Files
muuhd/server/seeders/characerSeeder.js
Kim Ravn Hansen 8c196bb6a1 thinstuff
2025-09-10 22:37:54 +02:00

575 lines
13 KiB
JavaScript
Executable File

// ____ _ _
// / ___| |__ __ _ _ __ __ _ ___| |_ ___ _ __
// | | | '_ \ / _` | '__/ _` |/ __| __/ _ \ '__|
// | |___| | | | (_| | | | (_| | (__| || __/ |
// \____|_| |_|\__,_|_| \__,_|\___|\__\___|_|
// ____ _
// / ___| ___ ___ __| | ___ _ __
// \___ \ / _ \/ _ \/ _` |/ _ \ '__|
// ___) | __/ __/ (_| | __/ |
// |____/ \___|\___|\__,_|\___|_|
// ------------------------------------------------
import { Character } from "../models/character.js";
import { Game } from "../models/game.js";
import { Player } from "../models/player.js";
import * as roll from "../utils/dice.js";
import { isIdSane } from "../utils/id.js";
export class CharacterSeeder {
/** @type {Game} */
constructor(game) {
/** @type {Game} */
this.game = game;
}
/**
* Create an item, using an item blueprint with the given name
*
* @param {string} itemBlueprintId id of the item blueprint
* @returns {Item|undefined}
*/
item(itemBlueprintId) {}
/**
* @param {Character} character
* @param {...string} itemBlueprintIds
*/
addItemsToCharacter(character, ...itemBlueprintIds) {
for (const id of itemBlueprintIds) {
const blueprint = this.game.getItemBlueprint(id);
if (!blueprint) {
throw new Error(`No blueprint found for id: ${id}`);
}
const item = blueprint.createItem();
character.addItem(item);
}
}
/**
* @param {Character} character
* @param {...string} skills
*/
addSkillsToCharacter(character, ...skills) {
for (const skill of skills) {
if (!isIdSane(skill)) {
throw new Error(`Skill id >>${skill}<< is insane!`);
}
character.skills.add(skill);
}
}
/**
* Foundation function
* @name FoundationFunction
* @function
* @param {Character} The character to which we apply this foundation.
*/
createCharacter() {
const c = new Character();
//
// Initializing
//
// Rolling skills
c.name =
this.game.rng.oneOf("sir", "madam", "mister", "miss", "", "", "") +
" random " +
this.game.rng.get().toString();
c.awareness = roll.d6() + 2;
c.grit = roll.d6() + 2;
c.knowledge = roll.d6() + 2;
c.magic = roll.d6() + 2;
c.meleeCombat = roll.d6() + 2;
c.rangedCombat = roll.d6() + 2;
c.skulduggery = roll.d6() + 2;
switch (roll.d8()) {
case 1:
c.ancestry = "human";
// Humans get +1 to all skills
c.awareness++;
c.grit++;
c.knowledge++;
c.magic++;
c.meleeCombat++;
c.rangedCombat++;
c.skulduggery++;
break;
case 2:
c.ancestry = "dwarven";
c.meleeCombat = Math.max(c.meleeCombat, 10);
break;
case 3:
c.ancestry = "elven";
c.rangedCombat = Math.max(c.rangedCombat, 10);
break;
case 4:
c.ancestry = "giant";
c.meleeCombat = Math.max(c.grit, 10);
break;
case 5:
c.ancestry = "Gnomish";
c.meleeCombat = Math.max(c.awareness, 10);
break;
case 6:
c.ancestry = "primordial";
c.meleeCombat = Math.max(c.magic, 10);
break;
case 7:
c.ancestry = "draconic";
c.meleeCombat = Math.max(c.knowledge, 10);
break;
case 8:
c.ancestry = "demonic";
c.meleeCombat = Math.max(c.skulduggery, 10);
break;
default:
throw new Error("Logic error, ancestry d8() roll was out of scope");
}
this.applyFoundation(c);
console.log(c);
return c;
}
/**
* Create characters for the given player
*
* The characters are automatically added to the player's party
*
* @param {Player} player
* @param {number} partySize
*
* @return {Character[]}
*/
createParty(player, partySize) {
//
for (let i = 0; i < partySize; i++) {
player.addCharacter(
this.createCharacter(player), //
);
}
}
/**
* @param {Character} c
* @param {string|number} Foundation to add to character
*/
applyFoundation(c, foundation = ":random") {
switch (foundation) {
case ":random":
return this.applyFoundation(c, roll.dice(3));
break;
//
// Brawler
// ------
case 1:
case ":brawler":
c.foundation = "Brawler";
c.skills.add(":armor.light");
c.silver = 40;
c.maxHitPoints = c.currentHitPoints = 15;
c.itemSlots = 7;
c.meleeCombat = Math.max(c.meleeCombat, 10);
c.knowledge = Math.min(c.knowledge, 10);
this.addItemsToCharacter(
c, //
":armor.light.studded_leather",
":weapon.weird.spiked_gauntlets",
);
this.addSkillsToCharacter(c, ":weapon.weird.spiked_gauntlets");
break;
//
// DRUID
// ------
case 2:
case ":druid":
c.foundation = "Druid";
c.silver = 40;
c.maxHitPoints = this.currentHitPoints = 15;
c.itemSlots = 7;
c.meleeCombat = Math.max(this.meleeCombat, 10);
c.knowledge = Math.min(this.knowledge, 10);
this.addItemsToCharacter(
c, //
":armor.light.leather",
":weapon.light.sickle",
":kit.poisoners_kit",
":kit.healers_kit",
);
this.addSkillsToCharacter(
c, //
":armor.light.sleather",
":armor.light.hide",
":weapon.light.sickle",
);
break;
case 3:
case ":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, //
":perk.two_weapons", // TODO: perks should be their own thing, and not a part of the skill system?
":armor.light",
);
//
// Gear
c.silver = 40;
c.itemSlots = 5;
this.addItemsToCharacter(
c, //
":armor.light.leather",
":weapon.light.rapier",
":weapon.light.dagger",
);
break;
/*
//
//---------------------------------------------------------------------------------------
//HEADLINE: Fencer
//---------------------------------------------------------------------------------------
| {counter:foundation}
|Fencer
|[unstyled]
* Light Armor
|[unstyled]
* Leather
* Rapier
* Dagger
* 40 Silver Pieces
|[unstyled]
//
//---------------------------------------------------------------------------------------
//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
//---------------------------------------------------------------------------------------
| {counter:foundation}
| Rover
|[unstyled]
* Light Armor
|[unstyled]
* Leather Armor
* Short Sword
* Longbow
* Snare Maker's Kit
* 25 Silver Pieces
|[unstyled]
* 10 Hit Points
* 5 Item Slots
* Magic Reduced to 10
* Awareness raised to 10
* Ranged Combat raised to 10
//
//---------------------------------------------------------------------------------------
//HEADLINE: SKIRMISHER
//---------------------------------------------------------------------------------------
| {counter:foundation}
| Skirmisher
|[unstyled]
* Light Armor
* Shields
|[unstyled]
* Spear
* Small Shield
* 50 Silver Pieces
|[unstyled]
* 15 Hit Points
* 6 Item Slots
* Melee Combat raised to 10
* Awareness raised to 10
* Skulduggery raised to 10
* Grit raised to 10
//
//---------------------------------------------------------------------------------------
//HEADLINE: SNEAK
//---------------------------------------------------------------------------------------
| {counter:foundation}
| Sneak
|[unstyled]
* 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
*/
//
// WTF ?!
// ------
default:
throw new Error(`Invalid foundation id ${foundation}`);
}
}
}