8000 fix(inventory): align currency and carrying capacity by Mnehmos · Pull Request #80 · Mnehmos/mnehmos.rpg.mcp · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/schema/character.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ export const SkillProficiencySchema = z.enum([

export const SaveProficiencySchema = z.enum(['str', 'dex', 'con', 'int', 'wis', 'cha']);

export const CurrencySchema = z.object({
gold: z.number().int().min(0).default(0),
silver: z.number().int().min(0).default(0),
copper: z.number().int().min(0).default(0),
});

/**
* Bastion world-brief origin tracker.
*
Expand Down Expand Up @@ -138,6 +144,8 @@ export const CharacterSchema = z.object({
.describe('Tools the character is proficient with'),
languages: z.array(z.string()).optional().default([])
.describe('Languages the character can speak or understand'),
currency: CurrencySchema.optional().default({})
.describe('Character currency in gold, silver, and copper denominations'),

// Background and alignment — accepted previously but silently dropped on
// persistence (no migration column). See docs/bastion/05-world-brief-vs-tool-surface.md.
Expand Down
5 changes: 4 additions & 1 deletion src/server/consolidated/inventory-manage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,10 @@ const definitions: Record<InventoryAction, ActionDefinition> = {
inventory: inventory.items,
totalWeight: inventory.totalWeight,
capacity: inventory.capacity,
gold: (inventory as { gold?: number }).gold || 0,
currency: inventory.currency,
gold: inventory.currency.gold,
silver: inventory.currency.silver,
copper: inventory.currency.copper,
itemCount: inventory.items.length
};
},
Expand Down
1 change: 1 addition & 0 deletions src/server/consolidated/spawn-manage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ function buildCharacter(data: {
weaponProficiencies: [],
toolProficiencies: [],
languages: [],
currency: { gold: 0, silver: 0, copper: 0 },
origin: data.origin,
hasLairActions: false,
position: data.position,
Expand Down
27 changes: 17 additions & 10 deletions src/storage/repos/character.repo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,21 @@ export class CharacterRepository {

const stmt = this.db.prepare(`
INSERT INTO characters (id, name, stats, hp, max_hp, ac, level, faction_id, behavior, character_type,
character_class, race, spell_slots, pact_magic_slots, known_spells, prepared_spells,
cantrips_known, max_spell_level, concentrating_on, conditions,
legendary_actions, legendary_actions_remaining, legendary_resistances,
character_class, race, spell_slots, pact_magic_slots, known_spells, prepared_spells,
cantrips_known, max_spell_level, concentrating_on, conditions,
currency,
legendary_actions, legendary_actions_remaining, legendary_resistances,
legendary_resistances_remaining, has_lair_actions, resistances, vulnerabilities, immunities,
current_room_id, perception_bonus, stealth_bonus, resource_pools,
skill_proficiencies, save_proficiencies, expertise,
armor_proficiencies, weapon_proficiencies, tool_proficiencies, languages,
background, alignment, origin,
created_at, updated_at)
VALUES (@id, @name, @stats, @hp, @maxHp, @ac, @level, @factionId, @behavior, @characterType,
@characterClass, @race, @spellSlots, @pactMagicSlots, @knownSpells, @preparedSpells,
@cantripsKnown, @maxSpellLevel, @concentratingOn, @conditions,
@legendaryActions, @legendaryActionsRemaining, @legendaryResistances,
@characterClass, @race, @spellSlots, @pactMagicSlots, @knownSpells, @preparedSpells,
@cantripsKnown, @maxSpellLevel, @concentratingOn, @conditions,
@currency,
@legendaryActions, @legendaryActionsRemaining, @legendaryResistances,
@legendaryResistancesRemaining, @hasLairActions, @resistances, @vulnerabilities, @immunities,
@currentRoomId, @perceptionBonus, @stealthBonus, @resourcePools,
@skillProficiencies, @saveProficiencies, @expertise,
Expand Down Expand Up @@ -55,6 +57,7 @@ export class CharacterRepository {
maxSpellLevel: validChar.maxSpellLevel || 0,
concentratingOn: validChar.concentratingOn || null,
conditions: JSON.stringify(validChar.conditions || []),
currency: JSON.stringify(validChar.currency || { gold: 0, silver: 0, copper: 0 }),
// HIGH-007: Legendary creature fields
legendaryActions: validChar.legendaryActions ?? null,
legendaryActionsRemaining: validChar.legendaryActionsRemaining ?? null,
Expand Down Expand Up @@ -133,10 +136,11 @@ export class CharacterRepository {
UPDATE characters
SET name = ?, stats = ?, hp = ?, max_hp = ?, ac = ?, level = ?,
faction_id = ?, behavior = ?, character_type = ?,
character_class = ?, race = ?, spell_slots = ?, pact_magic_slots = ?,
known_spells = ?, prepared_spells = ?, cantrips_known = ?,
max_spell_level = ?, concentrating_on = ?, conditions = ?,
legendary_actions = ?, legendary_actions_remaining = ?,
character_class = ?, race = ?, spell_slots = ?, pact_magic_slots = ?,
known_spells = ?, prepared_spells = ?, cantrips_known = ?,
max_spell_level = ?, concentrating_on = ?, conditions = ?,
currency = ?,
legendary_actions = ?, legendary_actions_remaining = ?,
legendary_resistances = ?, legendary_resistances_remaining = ?,
has_lair_actions = ?, resistances = ?, vulnerabilities = ?, immunities = ?,
current_room_id = ?, perception_bonus = ?, stealth_bonus = ?,
Expand Down Expand Up @@ -169,6 +173,7 @@ export class CharacterRepository {
validChar.maxSpellLevel || 0,
validChar.concentratingOn || null,
JSON.stringify(validChar.conditions || []),
JSON.stringify(validChar.currency || { gold: 0, silver: 0, copper: 0 }),
// HIGH-007: Legendary creature fields
validChar.legendaryActions ?? null,
validChar.legendaryActionsRemaining ?? null,
Expand Down Expand Up @@ -230,6 +235,7 @@ export class CharacterRepository {
maxSpellLevel: row.max_spell_level || 0,
concentratingOn: row.concentrating_on || null,
conditions: row.conditions ? JSON.parse(row.conditions) : [],
currency: row.currency ? JSON.parse(row.currency) : { gold: 0, silver: 0, copper: 0 },
// HIGH-007: Legendary creature fields
legendaryActions: row.legendary_actions ?? undefined,
legendaryActionsRemaining: row.legendary_actions_remaining ?? undefined,
Expand Down Expand Up @@ -294,6 +300,7 @@ interface CharacterRow {
max_spell_level: number | null;
concentrating_on: string | null;
conditions: string | null;
currency: string | null;
// HIGH-007: Legendary creature columns
legendary_actions: number | null;
legendary_actions_remaining: number | null;
Expand Down
17 changes: 15 additions & 2 deletions src/storage/repos/inventory.repo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export class InventoryRepository {
return InventorySchema.parse({
characterId,
items,
capacity: 100, // Default
capacity: this.getCapacity(characterId),
currency
});
}
Expand Down Expand Up @@ -151,11 +151,24 @@ export class InventoryRepository {
characterId,
items,
totalWeight,
capacity: 100,
capacity: this.getCapacity(characterId),
currency
};
}

/** D&D 5e carrying capacity: Strength score multiplied by 15 pounds. */
private getCapacity(characterId: string): number {
const row = this.db.prepare('SELECT stats FROM characters WHERE id = ?').get(characterId) as { stats: string } | undefined;
if (!row?.stats) return 0;

try {
const stats = JSON.parse(row.stats) as { str?: number };
return Math.max(0, Math.trunc(stats.str ?? 0) * 15);
} catch {
return 0;
}
}

// ============================================================
// CURRENCY OPERATIONS
// ============================================================
Expand Down
10 changes: 6 additions & 4 deletions tests/server/consolidated/inventory-manage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,10 @@ describe('inventory_manage consolidated tool', () => {
race: 'human',
hp: 10,
maxHp: 10,
ac: 10,
stats: { str: 14, dex: 12, con: 13, int: 10, wis: 11, cha: 10 },
speed: 30,
ac: 10,
stats: { str: 14, dex: 12, con: 13, int: 10, wis: 11, cha: 10 },
currency: { gold: 5, silver: 0, copper: 0 },
speed: 30,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
});
Expand Down Expand Up @@ -482,7 +483,8 @@ describe('inventory_manage consolidated tool', () => {
expect(data.success).toBe(true);
expect(data.actionType).toBe('get_detailed');
expect(data.totalWeight).toBeDefined();
expect(data.capacity).toBeDefined();
expect(data.capacity).toBe(210);
expect(data.currency).toEqual({ gold: 5, silver: 0, copper: 0 });
});

it('should accept "detailed" alias', async () => {
Expand Down
Loading
0