feat(api): implement combat loot integration with hybrid static/procedural system
Add CombatLootService that orchestrates loot generation from combat, supporting both static item drops (consumables, materials) and procedural equipment generation (weapons, armor with affixes). Key changes: - Extend LootEntry model with LootType enum (STATIC/PROCEDURAL) - Create StaticItemLoader service for consumables/materials from YAML - Create CombatLootService with full rarity formula incorporating: - Party average level - Enemy difficulty tier (EASY: +0%, MEDIUM: +5%, HARD: +15%, BOSS: +30%) - Character luck stat - Per-entry rarity bonus - Integrate with CombatService._calculate_rewards() for automatic loot gen - Add boss guaranteed drops via generate_boss_loot() New enemy variants (goblin family proof-of-concept): - goblin_scout (Easy) - static drops only - goblin_warrior (Medium) - static + procedural weapon drops - goblin_chieftain (Hard) - static + procedural weapon/armor drops Static items added: - consumables.yaml: health/mana potions, elixirs, food - materials.yaml: trophy items, crafting materials Tests: 59 new tests across 3 test files (all passing)
This commit is contained in:
85
api/app/data/enemies/goblin_chieftain.yaml
Normal file
85
api/app/data/enemies/goblin_chieftain.yaml
Normal file
@@ -0,0 +1,85 @@
|
||||
# Goblin Chieftain - Hard variant, elite tribe leader
|
||||
# A cunning and powerful goblin leader, adorned with trophies.
|
||||
# Commands respect through fear and violence, drops quality loot.
|
||||
|
||||
enemy_id: goblin_chieftain
|
||||
name: Goblin Chieftain
|
||||
description: >
|
||||
A large, scarred goblin wearing a crown of teeth and bones.
|
||||
The chieftain has clawed its way to leadership through countless
|
||||
battles and betrayals. It wields a well-maintained weapon stolen
|
||||
from a fallen adventurer and commands its tribe with an iron fist.
|
||||
|
||||
base_stats:
|
||||
strength: 16
|
||||
dexterity: 12
|
||||
constitution: 14
|
||||
intelligence: 10
|
||||
wisdom: 10
|
||||
charisma: 12
|
||||
luck: 12
|
||||
|
||||
abilities:
|
||||
- basic_attack
|
||||
- shield_bash
|
||||
- intimidating_shout
|
||||
|
||||
loot_table:
|
||||
# Static drops - guaranteed materials
|
||||
- loot_type: static
|
||||
item_id: goblin_ear
|
||||
drop_chance: 1.0
|
||||
quantity_min: 2
|
||||
quantity_max: 3
|
||||
- loot_type: static
|
||||
item_id: goblin_chieftain_token
|
||||
drop_chance: 0.80
|
||||
quantity_min: 1
|
||||
quantity_max: 1
|
||||
- loot_type: static
|
||||
item_id: goblin_war_paint
|
||||
drop_chance: 0.50
|
||||
quantity_min: 1
|
||||
quantity_max: 2
|
||||
|
||||
# Consumable drops
|
||||
- loot_type: static
|
||||
item_id: health_potion_medium
|
||||
drop_chance: 0.40
|
||||
quantity_min: 1
|
||||
quantity_max: 1
|
||||
- loot_type: static
|
||||
item_id: elixir_of_strength
|
||||
drop_chance: 0.10
|
||||
quantity_min: 1
|
||||
quantity_max: 1
|
||||
|
||||
# Procedural equipment drops - higher chance and rarity bonus
|
||||
- loot_type: procedural
|
||||
item_type: weapon
|
||||
drop_chance: 0.25
|
||||
rarity_bonus: 0.10
|
||||
quantity_min: 1
|
||||
quantity_max: 1
|
||||
- loot_type: procedural
|
||||
item_type: armor
|
||||
drop_chance: 0.15
|
||||
rarity_bonus: 0.05
|
||||
quantity_min: 1
|
||||
quantity_max: 1
|
||||
|
||||
experience_reward: 75
|
||||
gold_reward_min: 20
|
||||
gold_reward_max: 50
|
||||
difficulty: hard
|
||||
|
||||
tags:
|
||||
- humanoid
|
||||
- goblinoid
|
||||
- leader
|
||||
- elite
|
||||
- armed
|
||||
|
||||
base_damage: 14
|
||||
crit_chance: 0.15
|
||||
flee_chance: 0.25
|
||||
56
api/app/data/enemies/goblin_scout.yaml
Normal file
56
api/app/data/enemies/goblin_scout.yaml
Normal file
@@ -0,0 +1,56 @@
|
||||
# Goblin Scout - Easy variant, agile but fragile
|
||||
# A fast, cowardly goblin that serves as a lookout for its tribe.
|
||||
# Quick to flee, drops minor loot and the occasional small potion.
|
||||
|
||||
enemy_id: goblin_scout
|
||||
name: Goblin Scout
|
||||
description: >
|
||||
A small, wiry goblin with oversized ears and beady yellow eyes.
|
||||
Goblin scouts are the first line of awareness for their tribes,
|
||||
often found lurking in shadows or perched in trees. They prefer
|
||||
to run rather than fight, but will attack if cornered.
|
||||
|
||||
base_stats:
|
||||
strength: 6
|
||||
dexterity: 14
|
||||
constitution: 5
|
||||
intelligence: 6
|
||||
wisdom: 10
|
||||
charisma: 4
|
||||
luck: 10
|
||||
|
||||
abilities:
|
||||
- basic_attack
|
||||
|
||||
loot_table:
|
||||
# Static drops - materials and consumables
|
||||
- loot_type: static
|
||||
item_id: goblin_ear
|
||||
drop_chance: 0.60
|
||||
quantity_min: 1
|
||||
quantity_max: 1
|
||||
- loot_type: static
|
||||
item_id: goblin_trinket
|
||||
drop_chance: 0.20
|
||||
quantity_min: 1
|
||||
quantity_max: 1
|
||||
- loot_type: static
|
||||
item_id: health_potion_small
|
||||
drop_chance: 0.08
|
||||
quantity_min: 1
|
||||
quantity_max: 1
|
||||
|
||||
experience_reward: 10
|
||||
gold_reward_min: 1
|
||||
gold_reward_max: 4
|
||||
difficulty: easy
|
||||
|
||||
tags:
|
||||
- humanoid
|
||||
- goblinoid
|
||||
- small
|
||||
- scout
|
||||
|
||||
base_damage: 3
|
||||
crit_chance: 0.08
|
||||
flee_chance: 0.70
|
||||
70
api/app/data/enemies/goblin_warrior.yaml
Normal file
70
api/app/data/enemies/goblin_warrior.yaml
Normal file
@@ -0,0 +1,70 @@
|
||||
# Goblin Warrior - Medium variant, trained fighter
|
||||
# A battle-hardened goblin wielding crude but effective weapons.
|
||||
# More dangerous than scouts, fights in organized groups.
|
||||
|
||||
enemy_id: goblin_warrior
|
||||
name: Goblin Warrior
|
||||
description: >
|
||||
A muscular goblin clad in scavenged armor and wielding a crude
|
||||
but deadly weapon. Goblin warriors are the backbone of any goblin
|
||||
warband, trained to fight rather than flee. They attack with
|
||||
surprising ferocity and coordination.
|
||||
|
||||
base_stats:
|
||||
strength: 12
|
||||
dexterity: 10
|
||||
constitution: 10
|
||||
intelligence: 6
|
||||
wisdom: 6
|
||||
charisma: 4
|
||||
luck: 8
|
||||
|
||||
abilities:
|
||||
- basic_attack
|
||||
- shield_bash
|
||||
|
||||
loot_table:
|
||||
# Static drops - materials and consumables
|
||||
- loot_type: static
|
||||
item_id: goblin_ear
|
||||
drop_chance: 0.80
|
||||
quantity_min: 1
|
||||
quantity_max: 1
|
||||
- loot_type: static
|
||||
item_id: goblin_war_paint
|
||||
drop_chance: 0.15
|
||||
quantity_min: 1
|
||||
quantity_max: 1
|
||||
- loot_type: static
|
||||
item_id: health_potion_small
|
||||
drop_chance: 0.15
|
||||
quantity_min: 1
|
||||
quantity_max: 1
|
||||
- loot_type: static
|
||||
item_id: iron_ore
|
||||
drop_chance: 0.10
|
||||
quantity_min: 1
|
||||
quantity_max: 2
|
||||
|
||||
# Procedural equipment drops
|
||||
- loot_type: procedural
|
||||
item_type: weapon
|
||||
drop_chance: 0.08
|
||||
rarity_bonus: 0.0
|
||||
quantity_min: 1
|
||||
quantity_max: 1
|
||||
|
||||
experience_reward: 25
|
||||
gold_reward_min: 5
|
||||
gold_reward_max: 15
|
||||
difficulty: medium
|
||||
|
||||
tags:
|
||||
- humanoid
|
||||
- goblinoid
|
||||
- warrior
|
||||
- armed
|
||||
|
||||
base_damage: 8
|
||||
crit_chance: 0.10
|
||||
flee_chance: 0.45
|
||||
161
api/app/data/static_items/consumables.yaml
Normal file
161
api/app/data/static_items/consumables.yaml
Normal file
@@ -0,0 +1,161 @@
|
||||
# Consumable items that drop from enemies or are purchased from vendors
|
||||
# These items have effects_on_use that trigger when consumed
|
||||
|
||||
items:
|
||||
# ==========================================================================
|
||||
# Health Potions
|
||||
# ==========================================================================
|
||||
|
||||
health_potion_small:
|
||||
name: "Small Health Potion"
|
||||
item_type: consumable
|
||||
rarity: common
|
||||
description: "A small vial of red liquid that restores a modest amount of health."
|
||||
value: 25
|
||||
is_tradeable: true
|
||||
effects_on_use:
|
||||
- effect_id: heal_small
|
||||
name: "Minor Healing"
|
||||
effect_type: hot
|
||||
power: 30
|
||||
duration: 1
|
||||
stacks: 1
|
||||
|
||||
health_potion_medium:
|
||||
name: "Health Potion"
|
||||
item_type: consumable
|
||||
rarity: uncommon
|
||||
description: "A standard healing potion used by adventurers across the realm."
|
||||
value: 75
|
||||
is_tradeable: true
|
||||
effects_on_use:
|
||||
- effect_id: heal_medium
|
||||
name: "Healing"
|
||||
effect_type: hot
|
||||
power: 75
|
||||
duration: 1
|
||||
stacks: 1
|
||||
|
||||
health_potion_large:
|
||||
name: "Large Health Potion"
|
||||
item_type: consumable
|
||||
rarity: rare
|
||||
description: "A potent healing draught that restores significant health."
|
||||
value: 150
|
||||
is_tradeable: true
|
||||
effects_on_use:
|
||||
- effect_id: heal_large
|
||||
name: "Major Healing"
|
||||
effect_type: hot
|
||||
power: 150
|
||||
duration: 1
|
||||
stacks: 1
|
||||
|
||||
# ==========================================================================
|
||||
# Mana Potions
|
||||
# ==========================================================================
|
||||
|
||||
mana_potion_small:
|
||||
name: "Small Mana Potion"
|
||||
item_type: consumable
|
||||
rarity: common
|
||||
description: "A small vial of blue liquid that restores mana."
|
||||
value: 25
|
||||
is_tradeable: true
|
||||
# Note: MP restoration would need custom effect type or game logic
|
||||
|
||||
mana_potion_medium:
|
||||
name: "Mana Potion"
|
||||
item_type: consumable
|
||||
rarity: uncommon
|
||||
description: "A standard mana potion favored by spellcasters."
|
||||
value: 75
|
||||
is_tradeable: true
|
||||
|
||||
# ==========================================================================
|
||||
# Status Effect Cures
|
||||
# ==========================================================================
|
||||
|
||||
antidote:
|
||||
name: "Antidote"
|
||||
item_type: consumable
|
||||
rarity: common
|
||||
description: "A bitter herbal remedy that cures poison effects."
|
||||
value: 30
|
||||
is_tradeable: true
|
||||
|
||||
smelling_salts:
|
||||
name: "Smelling Salts"
|
||||
item_type: consumable
|
||||
rarity: uncommon
|
||||
description: "Pungent salts that can revive unconscious allies or cure stun."
|
||||
value: 40
|
||||
is_tradeable: true
|
||||
|
||||
# ==========================================================================
|
||||
# Combat Buffs
|
||||
# ==========================================================================
|
||||
|
||||
elixir_of_strength:
|
||||
name: "Elixir of Strength"
|
||||
item_type: consumable
|
||||
rarity: rare
|
||||
description: "A powerful elixir that temporarily increases strength."
|
||||
value: 100
|
||||
is_tradeable: true
|
||||
effects_on_use:
|
||||
- effect_id: str_buff
|
||||
name: "Strength Boost"
|
||||
effect_type: buff
|
||||
power: 5
|
||||
duration: 5
|
||||
stacks: 1
|
||||
|
||||
elixir_of_agility:
|
||||
name: "Elixir of Agility"
|
||||
item_type: consumable
|
||||
rarity: rare
|
||||
description: "A shimmering elixir that enhances reflexes and speed."
|
||||
value: 100
|
||||
is_tradeable: true
|
||||
effects_on_use:
|
||||
- effect_id: dex_buff
|
||||
name: "Agility Boost"
|
||||
effect_type: buff
|
||||
power: 5
|
||||
duration: 5
|
||||
stacks: 1
|
||||
|
||||
# ==========================================================================
|
||||
# Food Items (simple healing, no combat use)
|
||||
# ==========================================================================
|
||||
|
||||
ration:
|
||||
name: "Trail Ration"
|
||||
item_type: consumable
|
||||
rarity: common
|
||||
description: "Dried meat, hardtack, and nuts. Sustains an adventurer on long journeys."
|
||||
value: 5
|
||||
is_tradeable: true
|
||||
effects_on_use:
|
||||
- effect_id: ration_heal
|
||||
name: "Nourishment"
|
||||
effect_type: hot
|
||||
power: 10
|
||||
duration: 1
|
||||
stacks: 1
|
||||
|
||||
cooked_meat:
|
||||
name: "Cooked Meat"
|
||||
item_type: consumable
|
||||
rarity: common
|
||||
description: "Freshly cooked meat that restores health."
|
||||
value: 15
|
||||
is_tradeable: true
|
||||
effects_on_use:
|
||||
- effect_id: meat_heal
|
||||
name: "Hearty Meal"
|
||||
effect_type: hot
|
||||
power: 20
|
||||
duration: 1
|
||||
stacks: 1
|
||||
207
api/app/data/static_items/materials.yaml
Normal file
207
api/app/data/static_items/materials.yaml
Normal file
@@ -0,0 +1,207 @@
|
||||
# Trophy items, crafting materials, and quest items dropped by enemies
|
||||
# These items don't have combat effects but are used for quests, crafting, or selling
|
||||
|
||||
items:
|
||||
# ==========================================================================
|
||||
# Goblin Drops
|
||||
# ==========================================================================
|
||||
|
||||
goblin_ear:
|
||||
name: "Goblin Ear"
|
||||
item_type: quest_item
|
||||
rarity: common
|
||||
description: "A severed goblin ear. Proof of a kill, sometimes collected for bounties."
|
||||
value: 2
|
||||
is_tradeable: true
|
||||
|
||||
goblin_trinket:
|
||||
name: "Goblin Trinket"
|
||||
item_type: quest_item
|
||||
rarity: common
|
||||
description: "A crude piece of jewelry stolen by a goblin. Worth a few coins."
|
||||
value: 8
|
||||
is_tradeable: true
|
||||
|
||||
goblin_war_paint:
|
||||
name: "Goblin War Paint"
|
||||
item_type: quest_item
|
||||
rarity: uncommon
|
||||
description: "Pungent red and black paint used by goblin warriors before battle."
|
||||
value: 15
|
||||
is_tradeable: true
|
||||
|
||||
goblin_chieftain_token:
|
||||
name: "Chieftain's Token"
|
||||
item_type: quest_item
|
||||
rarity: rare
|
||||
description: "A carved bone token marking the authority of a goblin chieftain."
|
||||
value: 50
|
||||
is_tradeable: true
|
||||
|
||||
# ==========================================================================
|
||||
# Wolf/Beast Drops
|
||||
# ==========================================================================
|
||||
|
||||
wolf_pelt:
|
||||
name: "Wolf Pelt"
|
||||
item_type: quest_item
|
||||
rarity: common
|
||||
description: "A fur pelt from a wolf. Useful for crafting or selling to tanners."
|
||||
value: 10
|
||||
is_tradeable: true
|
||||
|
||||
dire_wolf_fang:
|
||||
name: "Dire Wolf Fang"
|
||||
item_type: quest_item
|
||||
rarity: uncommon
|
||||
description: "A large fang from a dire wolf. Prized by craftsmen for weapon making."
|
||||
value: 25
|
||||
is_tradeable: true
|
||||
|
||||
beast_hide:
|
||||
name: "Beast Hide"
|
||||
item_type: quest_item
|
||||
rarity: common
|
||||
description: "Thick hide from a large beast. Can be tanned into leather."
|
||||
value: 12
|
||||
is_tradeable: true
|
||||
|
||||
# ==========================================================================
|
||||
# Undead Drops
|
||||
# ==========================================================================
|
||||
|
||||
skeleton_bone:
|
||||
name: "Skeleton Bone"
|
||||
item_type: quest_item
|
||||
rarity: common
|
||||
description: "A bone from an animated skeleton. Retains faint magical energy."
|
||||
value: 5
|
||||
is_tradeable: true
|
||||
|
||||
bone_dust:
|
||||
name: "Bone Dust"
|
||||
item_type: quest_item
|
||||
rarity: common
|
||||
description: "Powdered bone from undead remains. Used in alchemy and rituals."
|
||||
value: 8
|
||||
is_tradeable: true
|
||||
|
||||
skull_fragment:
|
||||
name: "Skull Fragment"
|
||||
item_type: quest_item
|
||||
rarity: uncommon
|
||||
description: "A piece of an undead skull, still crackling with dark energy."
|
||||
value: 20
|
||||
is_tradeable: true
|
||||
|
||||
# ==========================================================================
|
||||
# Orc Drops
|
||||
# ==========================================================================
|
||||
|
||||
orc_tusk:
|
||||
name: "Orc Tusk"
|
||||
item_type: quest_item
|
||||
rarity: uncommon
|
||||
description: "A large tusk from an orc warrior. A trophy prized by collectors."
|
||||
value: 25
|
||||
is_tradeable: true
|
||||
|
||||
orc_war_banner:
|
||||
name: "Orc War Banner"
|
||||
item_type: quest_item
|
||||
rarity: rare
|
||||
description: "A bloodstained banner torn from an orc warband. Proof of a hard fight."
|
||||
value: 45
|
||||
is_tradeable: true
|
||||
|
||||
berserker_charm:
|
||||
name: "Berserker Charm"
|
||||
item_type: quest_item
|
||||
rarity: rare
|
||||
description: "A crude charm worn by orc berserkers. Said to enhance rage."
|
||||
value: 60
|
||||
is_tradeable: true
|
||||
|
||||
# ==========================================================================
|
||||
# Bandit Drops
|
||||
# ==========================================================================
|
||||
|
||||
bandit_mask:
|
||||
name: "Bandit Mask"
|
||||
item_type: quest_item
|
||||
rarity: common
|
||||
description: "A cloth mask worn by bandits to conceal their identity."
|
||||
value: 8
|
||||
is_tradeable: true
|
||||
|
||||
stolen_coin_pouch:
|
||||
name: "Stolen Coin Pouch"
|
||||
item_type: quest_item
|
||||
rarity: common
|
||||
description: "A small pouch of coins stolen by bandits. Should be returned."
|
||||
value: 15
|
||||
is_tradeable: true
|
||||
|
||||
wanted_poster:
|
||||
name: "Wanted Poster"
|
||||
item_type: quest_item
|
||||
rarity: uncommon
|
||||
description: "A crumpled wanted poster. May lead to bounty opportunities."
|
||||
value: 5
|
||||
is_tradeable: true
|
||||
|
||||
# ==========================================================================
|
||||
# Generic/Currency Items
|
||||
# ==========================================================================
|
||||
|
||||
gold_coin:
|
||||
name: "Gold Coin"
|
||||
item_type: quest_item
|
||||
rarity: common
|
||||
description: "A single gold coin. Standard currency across the realm."
|
||||
value: 1
|
||||
is_tradeable: true
|
||||
|
||||
silver_coin:
|
||||
name: "Silver Coin"
|
||||
item_type: quest_item
|
||||
rarity: common
|
||||
description: "A silver coin worth less than gold but still useful."
|
||||
value: 1
|
||||
is_tradeable: true
|
||||
|
||||
# ==========================================================================
|
||||
# Crafting Materials (Generic)
|
||||
# ==========================================================================
|
||||
|
||||
iron_ore:
|
||||
name: "Iron Ore"
|
||||
item_type: quest_item
|
||||
rarity: common
|
||||
description: "Raw iron ore that can be smelted into ingots."
|
||||
value: 10
|
||||
is_tradeable: true
|
||||
|
||||
leather_scraps:
|
||||
name: "Leather Scraps"
|
||||
item_type: quest_item
|
||||
rarity: common
|
||||
description: "Scraps of leather useful for crafting and repairs."
|
||||
value: 5
|
||||
is_tradeable: true
|
||||
|
||||
cloth_scraps:
|
||||
name: "Cloth Scraps"
|
||||
item_type: quest_item
|
||||
rarity: common
|
||||
description: "Torn cloth that can be sewn into bandages or used for crafting."
|
||||
value: 3
|
||||
is_tradeable: true
|
||||
|
||||
magic_essence:
|
||||
name: "Magic Essence"
|
||||
item_type: quest_item
|
||||
rarity: uncommon
|
||||
description: "Crystallized magical energy. Used in enchanting and alchemy."
|
||||
value: 30
|
||||
is_tradeable: true
|
||||
Reference in New Issue
Block a user