progress
This commit is contained in:
@@ -58,7 +58,7 @@ export class Character {
|
|||||||
itemSlots;
|
itemSlots;
|
||||||
|
|
||||||
/** @type {Set<string>} Things the character is particularly proficient at. */
|
/** @type {Set<string>} Things the character is particularly proficient at. */
|
||||||
skills = new Set();
|
proficiencies = new Set();
|
||||||
|
|
||||||
/** @type {Map<Item,number} Things the character is particularly proficient at. */
|
/** @type {Map<Item,number} Things the character is particularly proficient at. */
|
||||||
items = new Map();
|
items = new Map();
|
||||||
@@ -93,5 +93,23 @@ export class Character {
|
|||||||
this.items.set(item, count + existingItemCount);
|
this.items.set(item, count + existingItemCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clamp(skill, min, max) {
|
||||||
|
const val = this[skill];
|
||||||
|
|
||||||
|
if (val === undefined) {
|
||||||
|
throw new Error(`Invalid skill >>>${skill}<<<`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val < min) {
|
||||||
|
this[skill] = min
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val > max) {
|
||||||
|
this.skill = max;
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// todo removeItem(item, count)
|
// todo removeItem(item, count)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,19 +20,11 @@ let roll = {};
|
|||||||
|
|
||||||
export class CharacterSeeder {
|
export class CharacterSeeder {
|
||||||
constructor() {
|
constructor() {
|
||||||
// stupid convenience hack that only works if we only have a single Game in the system.
|
// stupid hack that ensures we populate roll AFTER gGame is available
|
||||||
// Which we easily could have.!!
|
// Which we easily could have.!!
|
||||||
roll = {
|
roll.d = (max, min = 1) => gGame.random.within(min, max)
|
||||||
d: (max, min = 1) => {
|
roll.d6 = () => roll.d(6)
|
||||||
return gGame.random.within(min, max);
|
roll.d8 = () => roll.d(8)
|
||||||
},
|
|
||||||
d6: () => {
|
|
||||||
return gGame.random.within(1, 6);
|
|
||||||
},
|
|
||||||
d8: () => {
|
|
||||||
return gGame.random.within(1, 8);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,14 +44,14 @@ export class CharacterSeeder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Character} character
|
* @param {Character} character
|
||||||
* @param {...string} skills
|
* @param {...string} proficiencies
|
||||||
*/
|
*/
|
||||||
addSkillsToCharacter(character, ...skills) {
|
addProficienciesToCharacter(character, ...proficiencies) {
|
||||||
for (const skill of skills) {
|
for (const prof of proficiencies) {
|
||||||
if (!isIdSane(skill)) {
|
if (!isIdSane(prof)) {
|
||||||
throw new Error(`Skill id >>${skill}<< is insane!`);
|
throw new Error(`Proficiency id >>${prof}<< is insane!`);
|
||||||
}
|
}
|
||||||
character.skills.add(skill);
|
character.proficiencies.add(prof);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,17 +64,24 @@ export class CharacterSeeder {
|
|||||||
|
|
||||||
createCharacter() {
|
createCharacter() {
|
||||||
const c = new Character();
|
const c = new Character();
|
||||||
//
|
|
||||||
// Initializing
|
|
||||||
//
|
|
||||||
|
|
||||||
// Rolling skills
|
this.generateName(c);
|
||||||
|
this.rollSkills(c);
|
||||||
|
this.applyAncestry(c);
|
||||||
|
this.applyFoundation(c);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
generateName(c) {
|
||||||
|
/** @todo use actual random name generator */
|
||||||
c.name =
|
c.name =
|
||||||
gGame.random.oneOf("sir ", "madam ", "mister ", "miss ", "", "", "") + // prefix
|
gGame.random.oneOf("sir ", "madam ", "mister ", "miss ", "", "", "") +
|
||||||
"random " + // name
|
"random " + // name
|
||||||
gGame.random.next().toString(); // suffix
|
gGame.random.next().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
rollSkills(c) {
|
||||||
c.awareness = roll.d6() + 2;
|
c.awareness = roll.d6() + 2;
|
||||||
c.grit = roll.d6() + 2;
|
c.grit = roll.d6() + 2;
|
||||||
c.knowledge = roll.d6() + 2;
|
c.knowledge = roll.d6() + 2;
|
||||||
@@ -90,11 +89,6 @@ export class CharacterSeeder {
|
|||||||
c.meleeCombat = roll.d6() + 2;
|
c.meleeCombat = roll.d6() + 2;
|
||||||
c.rangedCombat = roll.d6() + 2;
|
c.rangedCombat = roll.d6() + 2;
|
||||||
c.skulduggery = roll.d6() + 2;
|
c.skulduggery = roll.d6() + 2;
|
||||||
|
|
||||||
this.applyAncestry(c);
|
|
||||||
this.applyFoundation(c);
|
|
||||||
|
|
||||||
return c;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
applyAncestry(c) {
|
applyAncestry(c) {
|
||||||
@@ -168,44 +162,61 @@ export class CharacterSeeder {
|
|||||||
* @param {string|number} Foundation to add to character
|
* @param {string|number} Foundation to add to character
|
||||||
*/
|
*/
|
||||||
applyFoundation(c, foundation = ":random") {
|
applyFoundation(c, foundation = ":random") {
|
||||||
switch (foundation) {
|
if (foundation == ":random") {
|
||||||
case ":random":
|
return this.applyFoundation(c, roll.d(20)); // according to the rulebook, roll a d20 and reroll any invalid results.
|
||||||
return this.applyFoundation(c, roll.d(3));
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Brawler
|
// Brawler
|
||||||
// ------
|
// ------
|
||||||
case 1:
|
if (foundation === 1 || foundation === ":brawler") {
|
||||||
case ":brawler":
|
|
||||||
c.foundation = "Brawler";
|
c.foundation = "Brawler";
|
||||||
c.skills.add(":armor.light");
|
|
||||||
c.silver = 40;
|
|
||||||
c.maxHitPoints = c.currentHitPoints = 15;
|
c.maxHitPoints = c.currentHitPoints = 15;
|
||||||
c.itemSlots = 7;
|
c.itemSlots = 7;
|
||||||
|
c.silver = 40;
|
||||||
|
|
||||||
c.meleeCombat = Math.max(c.meleeCombat, 10);
|
c.meleeCombat = Math.max(c.meleeCombat, 10);
|
||||||
c.knowledge = Math.min(c.knowledge, 10);
|
c.knowledge = Math.min(c.knowledge, 10);
|
||||||
|
|
||||||
|
this.addProficienciesToCharacter(
|
||||||
|
c,
|
||||||
|
":armor.light",
|
||||||
|
":weapon.weird.spiked_gauntlets"
|
||||||
|
);
|
||||||
|
|
||||||
this.addItemsToCharacter(
|
this.addItemsToCharacter(
|
||||||
c, //
|
c, //
|
||||||
":armor.light.studded_leather",
|
":armor.light.studded_leather",
|
||||||
":weapon.weird.spiked_gauntlets",
|
":weapon.weird.spiked_gauntlets",
|
||||||
);
|
);
|
||||||
|
|
||||||
this.addSkillsToCharacter(c, ":weapon.weird.spiked_gauntlets");
|
return;
|
||||||
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// DRUID
|
// DRUID
|
||||||
// ------
|
// ------
|
||||||
case 2:
|
if (foundation === 2 || foundation === ":druid") {
|
||||||
case ":druid":
|
|
||||||
c.foundation = "Druid";
|
c.foundation = "Druid";
|
||||||
c.silver = 40;
|
|
||||||
c.maxHitPoints = this.currentHitPoints = 15;
|
c.silver = 10;
|
||||||
c.itemSlots = 7;
|
c.itemSlots = 5;
|
||||||
c.meleeCombat = Math.max(this.meleeCombat, 10);
|
c.maxHitPoints = this.currentHitPoints = 10;
|
||||||
c.knowledge = Math.min(this.knowledge, 10);
|
|
||||||
|
this.addProficienciesToCharacter(
|
||||||
|
c, //
|
||||||
|
":armor.light.cloth",
|
||||||
|
":armor.light.hide",
|
||||||
|
":armor.light.leather",
|
||||||
|
":kit.healers_kit",
|
||||||
|
":kit.poisoners_kit",
|
||||||
|
":weapon.light.sickle",
|
||||||
|
":weapon.light.quarterstaff",
|
||||||
|
":weapon.light.sling",
|
||||||
|
);
|
||||||
|
|
||||||
this.addItemsToCharacter(
|
this.addItemsToCharacter(
|
||||||
c, //
|
c, //
|
||||||
":armor.light.leather",
|
":armor.light.leather",
|
||||||
@@ -213,173 +224,178 @@ export class CharacterSeeder {
|
|||||||
":kit.poisoners_kit",
|
":kit.poisoners_kit",
|
||||||
":kit.healers_kit",
|
":kit.healers_kit",
|
||||||
);
|
);
|
||||||
this.addSkillsToCharacter(
|
|
||||||
c, //
|
return;
|
||||||
":armor.light.sleather",
|
}
|
||||||
":armor.light.hide",
|
|
||||||
":weapon.light.sickle",
|
//
|
||||||
);
|
// FENCER
|
||||||
break;
|
// -------
|
||||||
case 3:
|
if (foundation === 3 || foundation === ":fencer") {
|
||||||
case ":fencer":
|
|
||||||
c.foundation = "Fencer";
|
c.foundation = "Fencer";
|
||||||
|
|
||||||
//
|
|
||||||
// Stats
|
|
||||||
c.maxHitPoints = c.currentHitPoints = 15;
|
|
||||||
c.meleeCombat = Math.max(c.meleeCombat, 10);
|
|
||||||
c.magic = Math.min(c.magic, 10);
|
|
||||||
|
|
||||||
//
|
|
||||||
// Skills
|
|
||||||
this.addSkillsToCharacter(
|
|
||||||
c, //
|
|
||||||
":weapon.style.two_weapons",
|
|
||||||
":armor.light",
|
|
||||||
);
|
|
||||||
|
|
||||||
//
|
|
||||||
// Gear
|
|
||||||
c.silver = 40;
|
c.silver = 40;
|
||||||
c.itemSlots = 5;
|
c.itemSlots = 5;
|
||||||
|
c.maxHitPoints = c.currentHitPoints = 15;
|
||||||
|
|
||||||
|
c.clamp("magic", 1, 10)
|
||||||
|
c.clamp("meleeCombat", 10, undefined)
|
||||||
|
|
||||||
|
this.addProficienciesToCharacter(
|
||||||
|
c, //
|
||||||
|
":perk.riposte",
|
||||||
|
":armor.light",
|
||||||
|
":weapon.light",
|
||||||
|
);
|
||||||
|
|
||||||
this.addItemsToCharacter(
|
this.addItemsToCharacter(
|
||||||
c, //
|
c, //
|
||||||
":armor.light.leather",
|
":armor.light.leather",
|
||||||
":weapon.light.rapier",
|
|
||||||
":weapon.light.dagger",
|
":weapon.light.dagger",
|
||||||
|
":weapon.light.rapier",
|
||||||
);
|
);
|
||||||
break;
|
}
|
||||||
case 4:
|
|
||||||
case ":guard":
|
if (foundation === 4 || foundation === ":guard") {
|
||||||
|
|
||||||
c.foundation = "Guard";
|
c.foundation = "Guard";
|
||||||
|
|
||||||
//
|
|
||||||
// Stats
|
|
||||||
c.maxHitPoints = c.currentHitPoints = 15;
|
|
||||||
|
|
||||||
c.meleeCombat = Math.max(c.meleeCombat, 10);
|
|
||||||
c.awareness = Math.max(c.awareness, 10)
|
|
||||||
c.skulduggery = Math.min(c.skulduggery, 10);
|
|
||||||
|
|
||||||
//
|
|
||||||
// Skills
|
|
||||||
this.addSkillsToCharacter(
|
|
||||||
c, //
|
|
||||||
":armor.medium",
|
|
||||||
":weapon.weird.halberd",
|
|
||||||
);
|
|
||||||
|
|
||||||
//
|
|
||||||
// Gear
|
|
||||||
c.silver = 50;
|
c.silver = 50;
|
||||||
c.itemSlots = 5;
|
c.itemSlots = 5;
|
||||||
|
c.maxHitPoints = c.currentHitPoints = 10
|
||||||
|
|
||||||
|
c.clamp("awareness", 10, undefined)
|
||||||
|
c.clamp("meleeCombat", 10, undefined)
|
||||||
|
c.clamp("skulduggery", 1, 10)
|
||||||
|
|
||||||
|
this.addProficienciesToCharacter(
|
||||||
|
c, //
|
||||||
|
":armor.medium",
|
||||||
|
":weapon.heavy",
|
||||||
|
":weapon.specialist.halberd",
|
||||||
|
":wepaon.light",
|
||||||
|
);
|
||||||
|
|
||||||
this.addItemsToCharacter(
|
this.addItemsToCharacter(
|
||||||
c, //
|
c, //
|
||||||
":armor.medium.breastplate",
|
":armor.medium.breastplate",
|
||||||
":weapon.weird.halberd",
|
|
||||||
":lighting.bulls_eye_lantern",
|
":lighting.bulls_eye_lantern",
|
||||||
|
":map.city.hovedstad",
|
||||||
":misc.signal_whistle",
|
":misc.signal_whistle",
|
||||||
":maps.area.hvedstad",
|
":weapon.specialist.halberd",
|
||||||
);
|
);
|
||||||
break;
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundation === 5 || foundation === ":magician") {
|
||||||
|
|
||||||
|
c.foundation = "Magician"
|
||||||
|
|
||||||
|
c.silver = 10;
|
||||||
|
c.itemSlots = 6
|
||||||
|
c.maxHitPoints = c.currentHitPoints = 10
|
||||||
|
|
||||||
|
c.clamp("grit", 0, 10)
|
||||||
|
c.clamp("magic", 10, undefined)
|
||||||
|
c.clamp("meleeCombat", 0, 10)
|
||||||
|
c.clamp("rangedCombat", 0, 5)
|
||||||
|
|
||||||
|
/* ---- NO PROFICIENCIES ---- */
|
||||||
|
|
||||||
|
|
||||||
|
this.addItemsToCharacter(
|
||||||
|
c, //
|
||||||
|
"TODO: [TEIR 2 WAND WITH RANDOM SPELL]",
|
||||||
|
"TODO: [TEIR 1 WAND WITH RANDOM SPELL]",
|
||||||
|
);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundation === 6 || foundation === ":medic") {
|
||||||
|
|
||||||
|
c.foundation = "Medic";
|
||||||
|
|
||||||
|
c.silver = 40;
|
||||||
|
c.itemSlots = 7;
|
||||||
|
c.maxHitPoints = c.currentHitPoints = 10
|
||||||
|
|
||||||
|
this.addProficienciesToCharacter(
|
||||||
|
c, //
|
||||||
|
":armor.light",
|
||||||
|
":armor.medium",
|
||||||
|
":weapon.light",
|
||||||
|
);
|
||||||
|
|
||||||
|
this.addItemsToCharacter(
|
||||||
|
c, //
|
||||||
|
":armor.light.studded_leather",
|
||||||
|
":kit.healers_kit",
|
||||||
|
":weapon.light.club",
|
||||||
|
":weapon.light.dagger",
|
||||||
|
":weapon.light.dagger",
|
||||||
|
":weapon.light.dagger",
|
||||||
|
":weapon.light.sling",
|
||||||
|
);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundation === 7 || foundation === ":reckless") {
|
||||||
|
|
||||||
|
c.foundation = "Reckless";
|
||||||
|
|
||||||
|
c.silver = 50;
|
||||||
|
c.itemSlots = 7;
|
||||||
|
c.maxHitPoints = c.currentHitPoints = 20
|
||||||
|
|
||||||
|
c.clamp("awareness", 10, undefined)
|
||||||
|
c.clamp("grit", 10, undefined)
|
||||||
|
c.clamp("magic", 1, 10)
|
||||||
|
c.clamp("meleeCombat", 10, undefined)
|
||||||
|
|
||||||
|
this.addProficienciesToCharacter(
|
||||||
|
c, //
|
||||||
|
":wepaon.heavy",
|
||||||
|
);
|
||||||
|
|
||||||
|
this.addItemsToCharacter(
|
||||||
|
c, //
|
||||||
|
":weapon.heavy.great_axe",
|
||||||
|
);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundation === 8 || foundation === ":rover") {
|
||||||
|
|
||||||
|
c.foundation = "Rover";
|
||||||
|
|
||||||
|
c.silver = 25;
|
||||||
|
c.itemSlots = 5;
|
||||||
|
c.maxHitPoints = c.currentHitPoints = 10
|
||||||
|
|
||||||
|
c.clamp("awareness", 10, undefined)
|
||||||
|
c.clamp("magic", 1, 10)
|
||||||
|
c.clamp("rangedCombat", 10, undefined)
|
||||||
|
|
||||||
|
this.addProficienciesToCharacter(
|
||||||
|
c, //
|
||||||
|
":armor.light",
|
||||||
|
":weapon.light",
|
||||||
|
);
|
||||||
|
|
||||||
|
this.addItemsToCharacter(
|
||||||
|
c, //
|
||||||
|
":armor.light.leather",
|
||||||
|
":kit.snare_makers_kit",
|
||||||
|
":weapon.heavy.longbow",
|
||||||
|
":weapon.light.short_sword",
|
||||||
|
":map.shayland", // Shayland is the region around Hovedstad
|
||||||
|
);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
//---------------------------------------------------------------------------------------
|
|
||||||
//HEADLINE: GUARD
|
|
||||||
//---------------------------------------------------------------------------------------
|
|
||||||
| {counter:foundation}
|
|
||||||
|
|
||||||
| Guard
|
|
||||||
|
|
||||||
|[unstyled]
|
|
||||||
* Medium Armor
|
|
||||||
|
|
||||||
|[unstyled]
|
|
||||||
* Halberd
|
|
||||||
* Bull's Eye Lantern
|
|
||||||
* Signal Whistle
|
|
||||||
* Map of Local Area
|
|
||||||
* 50 Silver Pieces
|
|
||||||
|
|
||||||
|[unstyled]
|
|
||||||
* 10 Hit Points
|
|
||||||
* 5 Item Slots
|
|
||||||
* Awareness raised to 10
|
|
||||||
* Melee Combat raised to 10
|
|
||||||
* Skulduggery limited to 10
|
|
||||||
|
|
||||||
//
|
|
||||||
//---------------------------------------------------------------------------------------
|
|
||||||
//HEADLINE: MAGICIAN
|
|
||||||
//---------------------------------------------------------------------------------------
|
|
||||||
| {counter:foundation}
|
|
||||||
|
|
||||||
| Magician
|
|
||||||
|
|
||||||
|[unstyled]
|
|
||||||
* None
|
|
||||||
|
|
||||||
|[unstyled]
|
|
||||||
* Tier 2 Wand with random spell.
|
|
||||||
* Tier 1 Wand with random spell.
|
|
||||||
* 10 Silver Pieces
|
|
||||||
|
|
||||||
|[unstyled]
|
|
||||||
* 10 Hit Points
|
|
||||||
* 6 Item Slots
|
|
||||||
* Melee Combat limited to 10
|
|
||||||
* Ranged Combat limited to 5
|
|
||||||
* Magic raised to 10
|
|
||||||
* Grit limited to 10
|
|
||||||
|
|
||||||
//
|
|
||||||
//---------------------------------------------------------------------------------------
|
|
||||||
//HEADLINE: MEDIC
|
|
||||||
//---------------------------------------------------------------------------------------
|
|
||||||
| {counter:foundation}
|
|
||||||
|
|
||||||
|Medic
|
|
||||||
|
|
||||||
|[unstyled]
|
|
||||||
* Light Armor
|
|
||||||
* Medium Armor
|
|
||||||
|
|
||||||
|[unstyled]
|
|
||||||
* Club
|
|
||||||
* Sling
|
|
||||||
* 3 Daggers
|
|
||||||
* Healer's Kit
|
|
||||||
* 40 Silver Pieces
|
|
||||||
|
|
||||||
|[unstyled]
|
|
||||||
* 10 Hit Points
|
|
||||||
* 6 Item Slots
|
|
||||||
|
|
||||||
//
|
|
||||||
//---------------------------------------------------------------------------------------
|
|
||||||
//HEADLINE: RECKLESS
|
|
||||||
//---------------------------------------------------------------------------------------
|
|
||||||
| {counter:foundation}
|
|
||||||
|
|
||||||
| Reckless
|
|
||||||
|
|
||||||
|[unstyled]
|
|
||||||
|
|
||||||
|[unstyled]
|
|
||||||
* Great Axe
|
|
||||||
* 50 Silver Pieces
|
|
||||||
|
|
||||||
|[unstyled]
|
|
||||||
* 20 Hit Points
|
|
||||||
* 7 Item Slots
|
|
||||||
* Melee Combat raised to 10
|
|
||||||
* Awareness raised to 10
|
|
||||||
* Grit raised to 10
|
|
||||||
* Magic limited to 10
|
|
||||||
|
|
||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------
|
||||||
//HEADLINE: ROVER
|
//HEADLINE: ROVER
|
||||||
@@ -585,15 +601,6 @@ export class CharacterSeeder {
|
|||||||
* Knowledge raised to 10
|
* Knowledge raised to 10
|
||||||
|
|
||||||
*/
|
*/
|
||||||
//
|
return this.applyFoundation(c, ":random")
|
||||||
// WTF ?!
|
|
||||||
// ------
|
|
||||||
default:
|
|
||||||
throw new Error(`Invalid foundation id ${foundation}`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (Math.PI < 0 && Player) {
|
|
||||||
("STFU Linda");
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -76,13 +76,13 @@ export class Xorshift32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {...<T>} ... pick random function argument
|
* @method
|
||||||
* @returns {<T>}
|
* @template T
|
||||||
|
* @param {...T} args pick random function argument
|
||||||
|
* @returns {T}
|
||||||
*/
|
*/
|
||||||
oneOf(...args) {
|
oneOf(...args) {
|
||||||
const idx = this.lowerThan(args.length);
|
return this.randomElement(args)
|
||||||
|
|
||||||
return args[idx];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user