import { EquipmentSlot } from '../../items/equipment-slot.enum'; import { ItemRarity } from '../../items/item-rarity.enum'; import { ItemType } from '../../items/item-type.enum'; import { ASH_RAT_LOOT_TABLE_ID, ITEM_IDS, ItemKey, ROAD_BANDIT_LOOT_TABLE_ID, } from './item.constants'; export interface SeedItemDefinition { id: string; key: ItemKey; name: string; description: string; type: ItemType; equipmentSlot: EquipmentSlot | null; rarity: ItemRarity; tier: number; weaponDamage: number; bonusHp: number; bonusAttack: number; bonusArmor: number; sellPrice: number; iconPath: string; } function item( key: ItemKey, name: string, description: string, type: ItemType, equipmentSlot: EquipmentSlot | null, rarity: ItemRarity, stats: Partial< Pick< SeedItemDefinition, 'weaponDamage' | 'bonusHp' | 'bonusAttack' | 'bonusArmor' > > = {}, ): SeedItemDefinition { return { id: ITEM_IDS[key], key, name, description, type, equipmentSlot, rarity, tier: 1, weaponDamage: stats.weaponDamage ?? 0, bonusHp: stats.bonusHp ?? 0, bonusAttack: stats.bonusAttack ?? 0, bonusArmor: stats.bonusArmor ?? 0, // Always 0: no merchants exist in Slice 0.4, and the balancing doc's // Grenzmarken table lists purchase prices, not sell prices. sellPrice: 0, iconPath: `/images/items/${key}.png`, }; } // Stats from docs/Ashen_Realms_Balancing_Items_Loot_Design_V1.md §19. export const ITEM_DEFINITIONS: SeedItemDefinition[] = [ item( 'worn-short-sword', 'Worn Shortsword', "A recruit's blade, sharpened more often than it's been swung.", ItemType.EQUIPMENT, EquipmentSlot.WEAPON, ItemRarity.COMMON, { weaponDamage: 8 }, ), item( 'bandit-blade', 'Bandit Blade', 'A roughly serrated blade, forged for quick raids.', ItemType.EQUIPMENT, EquipmentSlot.WEAPON, ItemRarity.COMMON, { weaponDamage: 11, bonusAttack: 1 }, ), item( 'ash-blade', 'Ashen Blade', 'Tempered in the embers of the Ashen Fields; the edge still glows faintly.', ItemType.EQUIPMENT, EquipmentSlot.WEAPON, ItemRarity.RARE, { weaponDamage: 15, bonusAttack: 2 }, ), item( 'bandit-hood', 'Bandit Hood', "Scarred leather that hides both the wearer's face and their intent.", ItemType.EQUIPMENT, EquipmentSlot.HEAD, ItemRarity.COMMON, { bonusArmor: 3, bonusHp: 5 }, ), item( 'reinforced-leather-jacket', 'Reinforced Leather Jacket', 'Leather sewn with iron plates, heavy and dependable.', ItemType.EQUIPMENT, EquipmentSlot.CHEST, ItemRarity.RARE, { bonusArmor: 7, bonusHp: 10 }, ), item( 'raider-gloves', 'Plunderer Gloves', "Studded gloves, worn smooth from handling other people's belongings.", ItemType.EQUIPMENT, EquipmentSlot.HANDS, ItemRarity.COMMON, { bonusArmor: 3, bonusAttack: 1 }, ), item( 'guardsman-legs', "Watchman's Leggings", 'Leg armor of the Border Watch, patched at the knees.', ItemType.EQUIPMENT, EquipmentSlot.LEGS, ItemRarity.RARE, { bonusArmor: 5, bonusHp: 5 }, ), item( 'ash-boots', 'Ashen Boots', 'Boots that walked through smoldering fields and never quite left them behind.', ItemType.EQUIPMENT, EquipmentSlot.FEET, ItemRarity.RARE, { bonusArmor: 4, bonusHp: 5 }, ), item( 'borderwatch-sigil', 'Mark of the Border Watch', 'The crest of a watchtower that no longer stands.', ItemType.EQUIPMENT, EquipmentSlot.AMULET, ItemRarity.RARE, { bonusAttack: 3, bonusHp: 10 }, ), item( 'burned-captain-pendant', "Charred Captain's Pendant", 'A skull cast in slag, its embers never quite gone out.', ItemType.EQUIPMENT, EquipmentSlot.AMULET, ItemRarity.EPIC, { bonusAttack: 3, bonusHp: 15, bonusArmor: 2 }, ), // Seeded as content only. Slice 0.4 implements no consumable use, and the // Road Bandit loot entry for it is deliberately deferred (spec §16). item( 'small-healing-potion', 'Small Healing Potion', 'A bitter draught that makes wounds forgettable, if only for a breath.', ItemType.CONSUMABLE, null, ItemRarity.COMMON, ), // A Trade Good (spec §17): turned in to the Border Watch for Silver and // reputation rather than crafted with. item( 'ash-pelt', 'Ash Pelt', 'Singed pelt, tough as leather and grey with drifting ash.', ItemType.TRADE_GOOD, null, ItemRarity.COMMON, ), item( 'bandit-insignia', 'Bandit Insignia', 'A roughly stamped token marking a road bandit as one of their band.', ItemType.TROPHY, null, ItemRarity.COMMON, ), ]; export const LOOT_TABLES = [ { id: ASH_RAT_LOOT_TABLE_ID, key: 'ash-rat-loot', name: 'Ash Rat Loot' }, { id: ROAD_BANDIT_LOOT_TABLE_ID, key: 'road-bandit-loot', name: 'Road Bandit Loot', }, ]; export interface SeedLootTableEntry { lootTableId: string; itemDefinitionId: string; position: number; dropChance: string; minQuantity: number; maxQuantity: number; enabled: boolean; } function entry( lootTableId: string, key: ItemKey, position: number, dropChance: string, ): SeedLootTableEntry { return { lootTableId, itemDefinitionId: ITEM_IDS[key], position, dropChance, minQuantity: 1, maxQuantity: 1, enabled: true, }; } /** * Drop chances from docs/Ashen_Realms_Balancing_Items_Loot_Design_V1.md §27–28. * Every entry is an independent roll (spec §17), rolled in `position` order. * * DEFERRED: the Straßenräuber table also lists 10 % Kleiner Heiltrank. It is * omitted here because Slice 0.4 implements no consumables (spec §16). */ export const LOOT_TABLE_ENTRIES: SeedLootTableEntry[] = [ entry(ASH_RAT_LOOT_TABLE_ID, 'ash-pelt', 1, '0.6000'), entry(ASH_RAT_LOOT_TABLE_ID, 'worn-short-sword', 2, '0.0800'), entry(ROAD_BANDIT_LOOT_TABLE_ID, 'bandit-blade', 1, '0.1800'), entry(ROAD_BANDIT_LOOT_TABLE_ID, 'bandit-hood', 2, '0.1200'), entry(ROAD_BANDIT_LOOT_TABLE_ID, 'raider-gloves', 3, '0.0800'), entry(ROAD_BANDIT_LOOT_TABLE_ID, 'bandit-insignia', 4, '0.4000'), ];