Stuff ad things

This commit is contained in:
Kim Ravn Hansen
2026-02-12 16:54:27 +01:00
parent de96d45ade
commit 7ecb4f724b
5 changed files with 274 additions and 251 deletions

View File

@@ -60,8 +60,11 @@ export class Character {
/** @type {Set<string>} Things the character is particularly proficient at. */ /** @type {Set<string>} Things the character is particularly proficient at. */
proficiencies = new Set(); proficiencies = new Set();
/** @type {Map<Item,number} Things the character is particularly proficient at. */ /** @type {Set<Item} Things the character is particularly proficient at. */
items = new Map(); items = new Set();
/** @type {string[]} */
freeSlots = [];
/** /**
* @param {string} name The name of the character * @param {string} name The name of the character
@@ -72,44 +75,18 @@ export class Character {
/** Add an item to the equipment list /** Add an item to the equipment list
* @param {Item} item * @param {Item} item
* @param {number} count
* *
* Maybe return the accumulated ItemSlots used? * Maybe return the accumulated ItemSlots used?
*/ */
addItem(item, count = 1) { addItem(item) {
if (!Number.isInteger(count)) {
throw new Error("Number must be an integer");
}
if (!(item instanceof Item)) { if (!(item instanceof Item)) {
console.debug("bad item", item); console.debug("bad item", item);
throw new Error("item must be an instance of Item!"); throw new Error("item must be an instance of Item!");
} }
if (count <= 0) {
throw new Error("Number must be > 0");
}
const existingItemCount = this.items.get(item) || 0; this.items.add(item)
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)
} }

View File

@@ -41,6 +41,9 @@ export class ItemAttributes {
/** @constant @readonly @type {string[]} Type of ammo that this item is, or that this item uses */ /** @constant @readonly @type {string[]} Type of ammo that this item is, or that this item uses */
skills = []; skills = [];
/** @constant @readonly @type {boolean} Can a person wearing this armor be stealthy? */
sneak;
} }
/** /**
@@ -53,7 +56,7 @@ export class ItemBlueprint extends ItemAttributes {
/** /**
* Constructor * Constructor
* *
* @param {object} o Object whose attributes we copy * @param {ItemAttributes} o Object whose attributes we copy
*/ */
constructor(o) { constructor(o) {
super(); super();
@@ -106,4 +109,4 @@ export class ItemBlueprint extends ItemAttributes {
* arrows that are consumed. In this case, each individual arrow is not tracked * arrows that are consumed. In this case, each individual arrow is not tracked
* as its own entity, only the quiver is tracked. * as its own entity, only the quiver is tracked.
*/ */
export class Item extends ItemAttributes {} export class Item extends ItemAttributes { }

View File

@@ -239,8 +239,8 @@ export class CharacterSeeder {
c.itemSlots = 5; c.itemSlots = 5;
c.maxHitPoints = c.currentHitPoints = 15; c.maxHitPoints = c.currentHitPoints = 15;
c.clamp("magic", 1, 10) c.magic = Math.min(c.magic, 10)
c.clamp("meleeCombat", 10, undefined) c.meleeCombat = Math.max(c.meleeCombat, 10)
this.addProficienciesToCharacter( this.addProficienciesToCharacter(
c, // c, //
@@ -252,7 +252,7 @@ export class CharacterSeeder {
this.addItemsToCharacter( this.addItemsToCharacter(
c, // c, //
":armor.light.leather", ":armor.light.leather",
":weapon.light.dagger", ":weapon.basic.dagger",
":weapon.light.rapier", ":weapon.light.rapier",
); );
} }
@@ -265,9 +265,9 @@ export class CharacterSeeder {
c.itemSlots = 5; c.itemSlots = 5;
c.maxHitPoints = c.currentHitPoints = 10 c.maxHitPoints = c.currentHitPoints = 10
c.clamp("awareness", 10, undefined) c.awareness = Math.max(c.awareness, 10)
c.clamp("meleeCombat", 10, undefined) c.meleeCombat = Math.max(c.meleeCombat, 10)
c.clamp("skulduggery", 1, 10) c.skulduggery = Math.min(c.skulduggery, 10)
this.addProficienciesToCharacter( this.addProficienciesToCharacter(
c, // c, //
@@ -282,6 +282,7 @@ export class CharacterSeeder {
":armor.medium.breastplate", ":armor.medium.breastplate",
":lighting.bulls_eye_lantern", ":lighting.bulls_eye_lantern",
":map.city.hovedstad", ":map.city.hovedstad",
":misc.lamp_oil",
":misc.signal_whistle", ":misc.signal_whistle",
":weapon.specialist.halberd", ":weapon.specialist.halberd",
); );
@@ -296,18 +297,18 @@ export class CharacterSeeder {
c.itemSlots = 6 c.itemSlots = 6
c.maxHitPoints = c.currentHitPoints = 10 c.maxHitPoints = c.currentHitPoints = 10
c.clamp("grit", 0, 10) c.grit = Math.min(c.grit, 10)
c.clamp("magic", 10, undefined) c.magic = Math.max(c.magic, 10)
c.clamp("meleeCombat", 0, 10) c.meleeCombat = Math.min(c.meleeCombat, 10)
c.clamp("rangedCombat", 0, 5) c.rangedCombat = Math.min(c.rangedCombat, 10)
/* ---- NO PROFICIENCIES ---- */ /* ---- NO PROFICIENCIES ---- */
this.addItemsToCharacter( this.addItemsToCharacter(
c, // c, //
"TODO: [TEIR 2 WAND WITH RANDOM SPELL]", // "TODO: [TEIR 2 WAND WITH RANDOM SPELL]",
"TODO: [TEIR 1 WAND WITH RANDOM SPELL]", // "TODO: [TEIR 1 WAND WITH RANDOM SPELL]",
); );
return return
} }
@@ -320,6 +321,8 @@ export class CharacterSeeder {
c.itemSlots = 7; c.itemSlots = 7;
c.maxHitPoints = c.currentHitPoints = 10 c.maxHitPoints = c.currentHitPoints = 10
c.awareness = Math.max(10, c.awareness)
this.addProficienciesToCharacter( this.addProficienciesToCharacter(
c, // c, //
":armor.light", ":armor.light",
@@ -331,10 +334,8 @@ export class CharacterSeeder {
c, // c, //
":armor.light.studded_leather", ":armor.light.studded_leather",
":kit.healers_kit", ":kit.healers_kit",
":weapon.light.club", ":weapon.basic.club",
":weapon.light.dagger", ":weapon.basic.dagger",
":weapon.light.dagger",
":weapon.light.dagger",
":weapon.light.sling", ":weapon.light.sling",
); );
return return
@@ -348,14 +349,15 @@ export class CharacterSeeder {
c.itemSlots = 7; c.itemSlots = 7;
c.maxHitPoints = c.currentHitPoints = 20 c.maxHitPoints = c.currentHitPoints = 20
c.clamp("awareness", 10, undefined) c.awareness = Math.max(10, c.awareness);
c.clamp("grit", 10, undefined) c.grit = Math.max(10, c.grit);
c.clamp("magic", 1, 10) c.magic = Math.min(10, c.magic);
c.clamp("meleeCombat", 10, undefined) c.meleeCombat = Math.max(10, c.meleeCombat);
this.addProficienciesToCharacter( this.addProficienciesToCharacter(
c, // c, //
":wepaon.heavy", ":wepaon.heavy",
":wepaon.light",
); );
this.addItemsToCharacter( this.addItemsToCharacter(
@@ -373,14 +375,15 @@ export class CharacterSeeder {
c.itemSlots = 5; c.itemSlots = 5;
c.maxHitPoints = c.currentHitPoints = 10 c.maxHitPoints = c.currentHitPoints = 10
c.clamp("awareness", 10, undefined) c.awareness = Math.max(10, c.awareness)
c.clamp("magic", 1, 10) c.magic = Math.min(10, c.magic)
c.clamp("rangedCombat", 10, undefined) c.rangedCombat = Math.max(10, c.rangedCombat)
this.addProficienciesToCharacter( this.addProficienciesToCharacter(
c, // c, //
":armor.light", ":armor.light",
":weapon.light", ":weapon.light",
":weapon.heavy.longbow",
); );
this.addItemsToCharacter( this.addItemsToCharacter(
@@ -394,213 +397,177 @@ export class CharacterSeeder {
return return
} }
/* if (foundation === 9 || foundation === ":skrimisher") {
// c.foundation = "Skirmisher";
//---------------------------------------------------------------------------------------
//HEADLINE: ROVER
//---------------------------------------------------------------------------------------
| {counter:foundation}
| Rover c.silver = 15;
c.itemSlots = 6;
c.maxHitPoints = c.currentHitPoints = 15
|[unstyled] c.awareness = Math.max(10, c.awareness)
* Light Armor c.grit = Math.max(10, c.grit)
c.magic = Math.max(5, c.magic)
c.meleeCombat = Math.max(10, c.meleeCombat)
c.skulduggery = Math.max(10, c.skulduggery)
|[unstyled] this.addProficienciesToCharacter(
* Leather Armor c, //
* Short Sword ":armor.light",
* Longbow );
* Snare Maker's Kit
* 25 Silver Pieces
|[unstyled] this.addItemsToCharacter(
* 10 Hit Points c, //
* 5 Item Slots ":armor.light.small_shield",
* Magic Reduced to 10 ":weapon.light.spear",
* Awareness raised to 10 );
* Ranged Combat raised to 10 return
}
// if (foundation === 10 || foundation === ":sneak") {
//---------------------------------------------------------------------------------------
//HEADLINE: SKIRMISHER
//---------------------------------------------------------------------------------------
| {counter:foundation}
| Skirmisher c.foundation = "Sneak";
|[unstyled] c.silver = 30;
* Light Armor c.itemSlots = 6;
* Shields c.maxHitPoints = c.currentHitPoints = 10
|[unstyled] c.awareness = Math.max(10, c.awareness)
* Spear c.meleeCombat = Math.max(10, c.meleeCombat)
* Small Shield c.skulduggery = Math.max(10, c.skulduggery)
* 50 Silver Pieces
this.addProficienciesToCharacter(
c, //
":armor.light",
);
this.addItemsToCharacter(
c, //
":weapon.basic.dagger",
":weapon.light.small_crossbow",
":kit.poisoners_kit",
);
return
}
if (foundation === 11 || foundation === ":spellsword") {
c.foundation = "Spellsword";
c.silver = 30;
c.itemSlots = 5;
c.maxHitPoints = c.currentHitPoints = 12;
c.grit = Math.max(10, c.grit)
c.magic = Math.max(10, c.magic)
c.meleeCombat = Math.max(10, c.meleeCombat)
c.rangedCombat = Math.min(10, c.rangedCombat)
c.skulduggery = Math.min(10, c.skulduggery)
this.addProficienciesToCharacter(
c, //
":weapon.light",
);
this.addItemsToCharacter(
c, //
":weapon.light.rapier",
// "[TODO TIER 1 WAND WITH RANDOM SPELL]",
);
return
}
if (foundation === 12 || foundation === ":spelunker") {
c.foundation = "Spelunker";
c.silver = 5;
c.itemSlots = 4;
c.maxHitPoints = c.currentHitPoints = 10;
c.awareness = Math.max(10, c.awareness)
c.magic = Math.min(10, c.magic)
c.meleeCombat = Math.max(10, c.meleeCombat)
c.skulduggery = Math.max(10, c.skulduggery)
this.addProficienciesToCharacter(
c, //
":weapon.light",
);
this.addItemsToCharacter(
c, //
":kit.map_makers_kit",
":lighting.bulls_eye_lantern",
":misc.caltrops",
":misc.chalk",
":misc.lamp_oil",
":weapon.light.spear",
);
return
}
if (foundation === 13 || foundation === ":spit_n_polish") {
c.foundation = "Spit'n'Polish";
c.silver = 10;
c.itemSlots = 2;
c.maxHitPoints = c.currentHitPoints = 10;
c.magic = Math.min(6, c.magic)
c.meleeCombat = Math.max(10, c.meleeCombat)
this.addProficienciesToCharacter(
c, //
":weapon.light",
":weapon.heavy",
":armor.heavy",
":armor.light",
);
this.addItemsToCharacter(
c, //
":weapon.heavy.longsword",
":armor.heavy.half_plate",
":armor.heavy.large_shield",
);
return
}
if (foundation === 14 || foundation === ":stiletto") {
c.foundation = "Stiletto";
c.silver = 10;
c.itemSlots = 5;
c.maxHitPoints = c.currentHitPoints = 10;
|[unstyled] c.magic = Math.min(6, c.magic)
* 15 Hit Points c.meleeCombat = Math.max(10, c.meleeCombat)
* 6 Item Slots
* Melee Combat raised to 10
* Awareness raised to 10
* Skulduggery raised to 10
* Grit raised to 10
// this.addProficienciesToCharacter(
//--------------------------------------------------------------------------------------- c, //
//HEADLINE: SNEAK ":weapon.light",
//--------------------------------------------------------------------------------------- ":weapon.heavy",
| {counter:foundation} ":armor.heavy",
":armor.light",
);
| Sneak this.addItemsToCharacter(
c, //
":weapon.heavy.longsword",
":armor.heavy.half_plate",
":armor.heavy.large_shield",
);
|[unstyled] return
* Light Armor }
|[unstyled]
* 3 daggers
* Small Crossbow
* Poisoner's Kit
* 30 Silver Pieces
|[unstyled]
* 10 Hit Points
* 6 Item Slots
* Melee Combat raised to 10
* Awareness raised to 10
* Skulduggery raised to 10
* Grit raised to 10
//
//---------------------------------------------------------------------------------------
//HEADLINE: SPELLSWORD
//---------------------------------------------------------------------------------------
| {counter:foundation}
| Spellsword
|[unstyled]
|[unstyled]
* Tier 1 Wand with random spell.
* Longsword
* 30 Silver Pieces
|[unstyled]
* 12 Hit Points
* 5 Item Slots
* Melee Combat raised to 10
* Ranged Combat limited to 10
* Magic raised to 10
* Skulduggery limited to 10
* Grit raised to 10
//
//---------------------------------------------------------------------------------------
//HEADLINE: SPELUNKER
//---------------------------------------------------------------------------------------
| {counter:foundation}
| Spelunker
|[unstyled]
* None
|[unstyled]
* Spear
* Caltrops
* Bull's Eye Lantern
* Map Maker's Kit
* Chalk
* Caltrops
* 5 Silver Pieces
|[unstyled]
* 10 Hit Points
* 4 Item Slots
* Awareness raised to 10
* Melee Combat raised to 10
* Skulduggery raised to 10
* Magic limited to 10
//
//---------------------------------------------------------------------------------------
//HEADLINE: SPIT'N'POLISH
//---------------------------------------------------------------------------------------
| {counter:foundation}
| Spit'n' Polish
|[unstyled]
* Heavy Armor
* Shield
|[unstyled]
* Half-Plate
* Large Shield
* Long Sword
* 10 Silver Pieces
|[unstyled]
* 10 Hit Points
* 2 Item Slots
* Melee Combat raised to 10
* Magic Reduced to 6
* Awareness Reduced to 10
//
//---------------------------------------------------------------------------------------
//HEADLINE: STILETTO
//---------------------------------------------------------------------------------------
| {counter:foundation}
| Stiletto
|[unstyled]
* Light Armor
|[unstyled]
* Padded Armor
* 3 Daggers
* Small Crossbow
* Poisoner's Kit
* 20 Silver Pieces
|[unstyled]
* 10 Hit Points
* 5 Item Slots
* Melee Combat raised to 10
* Ranged Combat raised to 10
* Awareness raised to 10
* Magic limited to 6
* Knowledge limited to 10
//
//---------------------------------------------------------------------------------------
//HEADLINE: Tinkerer
//---------------------------------------------------------------------------------------
| {counter:foundation}
|Tinkerer
|[unstyled]
* Light Armor
|[unstyled]
* Studded Leather
* Wrench (club)
* Tinkerer's Kit
* 30 Silver Pieces
|[unstyled]
* 10 Hit Points
* 5 Item Slots
* Awareness raised to 10
* Knowledge raised to 10
*/
return this.applyFoundation(c, ":random") return this.applyFoundation(c, ":random")
} }
} }

View File

@@ -18,13 +18,23 @@ export class ItemSeeder {
// \_/\_/ \___|\__,_| .__/ \___/|_| |_|___/ // \_/\_/ \___|\__,_| .__/ \___/|_| |_|___/
// |_| // |_|
//------------------------------------------------------- //-------------------------------------------------------
gGame.addItemBlueprint(":weapon.light.dagger", { gGame.addItemBlueprint(":weapon.basic.club", {
name: "Club",
description: "A club, it's light, what's more to say?",
itemSlots: 1,
damage: 4,
specialEffect: "TBD",
});
gGame.addItemBlueprint(":weapon.basic.dagger", {
name: "Dagger", name: "Dagger",
description: "Small shady blady", description: "Basic small shady blady",
itemSlots: 0.5, itemSlots: 1,
damage: 3, damage: 3,
melee: true, melee: true,
ranged: true, ranged: true, //
count: 3, // basic daggers always come in a bundle of three
maxCount: 3,
specialEffect: ":effect.weapon.fast", specialEffect: ":effect.weapon.fast",
}); });
@@ -52,6 +62,31 @@ export class ItemSeeder {
specialEffect: "TBD", specialEffect: "TBD",
}); });
gGame.addItemBlueprint(":weapon.light.small_crossbow", {
name: "Rapier",
description: "Small Crossbow",
itemSlots: 2,
damage: 8,
specialEffect: "TBD",
ammoType: "bolt",
});
gGame.addItemBlueprint(":weapon.heavy.longsword", {
name: "Rapier",
description: "Long one-handed sword",
itemSlots: 2,
damage: 8,
specialEffect: "TBD",
});
gGame.addItemBlueprint(":weapon.heavy.longbow", {
name: "Rapier",
description: "Longbow",
itemSlots: 3,
damage: 8,
specialEffect: "TBD",
});
// _ // _
// / \ _ __ _ __ ___ ___ _ __ ___ // / \ _ __ _ __ ___ ___ _ __ ___
// / _ \ | '__| '_ ` _ \ / _ \| '__/ __| // / _ \ | '__| '_ ` _ \ / _ \| '__/ __|
@@ -63,8 +98,10 @@ export class ItemSeeder {
description: "Padded and hardened leather with metal stud reinforcement", description: "Padded and hardened leather with metal stud reinforcement",
itemSlots: 3, itemSlots: 3,
specialEffect: "TBD", specialEffect: "TBD",
sneak: false,
armorHitPoints: 10, armorHitPoints: 10,
}); });
gGame.addItemBlueprint(":armor.light.leather", { gGame.addItemBlueprint(":armor.light.leather", {
name: "Leather Armor", name: "Leather Armor",
description: "Padded and hardened leather", description: "Padded and hardened leather",
@@ -72,6 +109,29 @@ export class ItemSeeder {
specialEffect: "TBD", specialEffect: "TBD",
armorHitPoints: 6, armorHitPoints: 6,
}); });
gGame.addItemBlueprint(":armor.medium.breastplate", {
name: "Breastplate",
description: "Plate that covers chest, cloth and leather covers the rest",
itemSlots: 3,
specialEffect: "TBD",
armorHitPoints: 10,
})
gGame.addItemBlueprint(":armor.heavy.half_plate", {
name: "Half-Plate",
description: "Platemail with near-total coverage",
itemSlots: 4,
specialEffect: "TBD",
armorHitPoints: 6,
});
gGame.addItemBlueprint(":armor.heavy.large_shield", {
name: "Large Shield",
description: "Platemail with near-total coverage",
itemSlots: 4,
specialEffect: "TBD",
armorHitPoints: 6,
});
// _ ___ _ // _ ___ _
// | |/ (_) |_ ___ // | |/ (_) |_ ___
@@ -96,5 +156,21 @@ export class ItemSeeder {
count: 20, count: 20,
maxCount: 20, maxCount: 20,
}); });
gGame.addItemBlueprint(":kit.snare_makers_kit", {
name: "Healer's Kit",
description: "Allows you to create traps and snares",
itemSlots: 2,
specialEffect: "TBD",
count: 20,
maxCount: 20,
});
gGame.addItemBlueprint(":kit.map_makers_kit", {
name: "Healer's Kit",
description: "Allows you to create traps and snares",
itemSlots: 1,
specialEffect: "TBD",
})
} }
} }

0
test.js Normal file → Executable file
View File