diff --git a/api/app/data/abilities/absolute_zero.yaml b/api/app/data/abilities/absolute_zero.yaml new file mode 100644 index 0000000..601649a --- /dev/null +++ b/api/app/data/abilities/absolute_zero.yaml @@ -0,0 +1,34 @@ +# Absolute Zero - Arcanist Cryomancy ultimate +# Ultimate freeze all enemies + +ability_id: "absolute_zero" +name: "Absolute Zero" +description: "Lower the temperature to absolute zero, freezing all enemies solid and dealing massive ice damage" +ability_type: "spell" +base_power: 90 +damage_type: "ice" +scaling_stat: "intelligence" +scaling_factor: 0.7 +mana_cost: 70 +cooldown: 6 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "absolute_freeze" + name: "Absolute Zero" + effect_type: "stun" + duration: 2 + power: 0 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "absolute_zero" + - effect_id: "shattered" + name: "Shattered" + effect_type: "dot" + duration: 2 + power: 20 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "absolute_zero" diff --git a/api/app/data/abilities/aimed_shot.yaml b/api/app/data/abilities/aimed_shot.yaml new file mode 100644 index 0000000..49be97b --- /dev/null +++ b/api/app/data/abilities/aimed_shot.yaml @@ -0,0 +1,16 @@ +# Aimed Shot - Wildstrider Marksmanship ability +# High accuracy ranged attack + +ability_id: "aimed_shot" +name: "Aimed Shot" +description: "Take careful aim and fire a precise shot at your target" +ability_type: "attack" +base_power: 18 +damage_type: "physical" +scaling_stat: "dexterity" +scaling_factor: 0.6 +mana_cost: 8 +cooldown: 1 +is_aoe: false +target_count: 1 +effects_applied: [] diff --git a/api/app/data/abilities/arcane_brilliance.yaml b/api/app/data/abilities/arcane_brilliance.yaml new file mode 100644 index 0000000..f0a240e --- /dev/null +++ b/api/app/data/abilities/arcane_brilliance.yaml @@ -0,0 +1,25 @@ +# Arcane Brilliance - Lorekeeper Arcane Weaving ability +# Intelligence buff + +ability_id: "arcane_brilliance" +name: "Arcane Brilliance" +description: "Grant an ally increased intelligence and magical power" +ability_type: "spell" +base_power: 0 +damage_type: null +scaling_stat: "intelligence" +scaling_factor: 0.4 +mana_cost: 10 +cooldown: 0 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "arcane_brilliance_buff" + name: "Arcane Brilliance" + effect_type: "buff" + duration: 5 + power: 10 + stat_affected: "intelligence" + stacks: 1 + max_stacks: 1 + source: "arcane_brilliance" diff --git a/api/app/data/abilities/arcane_weakness.yaml b/api/app/data/abilities/arcane_weakness.yaml new file mode 100644 index 0000000..9b5d610 --- /dev/null +++ b/api/app/data/abilities/arcane_weakness.yaml @@ -0,0 +1,25 @@ +# Arcane Weakness - Lorekeeper Arcane Weaving ability +# Stat debuff on enemy + +ability_id: "arcane_weakness" +name: "Arcane Weakness" +description: "Expose the weaknesses in your enemy's defenses, reducing their resistances" +ability_type: "spell" +base_power: 0 +damage_type: "arcane" +scaling_stat: "intelligence" +scaling_factor: 0.5 +mana_cost: 25 +cooldown: 3 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "weakened_defenses" + name: "Weakened" + effect_type: "debuff" + duration: 4 + power: 25 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "arcane_weakness" diff --git a/api/app/data/abilities/army_of_the_dead.yaml b/api/app/data/abilities/army_of_the_dead.yaml new file mode 100644 index 0000000..c482639 --- /dev/null +++ b/api/app/data/abilities/army_of_the_dead.yaml @@ -0,0 +1,25 @@ +# Army of the Dead - Necromancer Raise Dead ultimate +# Summon undead army + +ability_id: "army_of_the_dead" +name: "Army of the Dead" +description: "Raise an entire army of undead to overwhelm your enemies" +ability_type: "spell" +base_power: 80 +damage_type: "shadow" +scaling_stat: "charisma" +scaling_factor: 0.7 +mana_cost: 70 +cooldown: 8 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "undead_army" + name: "Army of the Dead" + effect_type: "buff" + duration: 5 + power: 100 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "army_of_the_dead" diff --git a/api/app/data/abilities/bestial_wrath.yaml b/api/app/data/abilities/bestial_wrath.yaml new file mode 100644 index 0000000..07f82fc --- /dev/null +++ b/api/app/data/abilities/bestial_wrath.yaml @@ -0,0 +1,25 @@ +# Bestial Wrath - Wildstrider Beast Companion ability +# Pet damage buff + +ability_id: "bestial_wrath" +name: "Bestial Wrath" +description: "Enrage your companion, increasing their damage for 3 turns" +ability_type: "skill" +base_power: 0 +damage_type: null +scaling_stat: "wisdom" +scaling_factor: 0.4 +mana_cost: 25 +cooldown: 4 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "enraged_companion" + name: "Enraged Companion" + effect_type: "buff" + duration: 3 + power: 50 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "bestial_wrath" diff --git a/api/app/data/abilities/blessed_sacrifice.yaml b/api/app/data/abilities/blessed_sacrifice.yaml new file mode 100644 index 0000000..0cc9b82 --- /dev/null +++ b/api/app/data/abilities/blessed_sacrifice.yaml @@ -0,0 +1,16 @@ +# Blessed Sacrifice - Oathkeeper Redemption ability +# Transfer ally wounds to self + +ability_id: "blessed_sacrifice" +name: "Blessed Sacrifice" +description: "Take an ally's wounds upon yourself, healing them while damaging yourself" +ability_type: "spell" +base_power: 50 +damage_type: "holy" +scaling_stat: "wisdom" +scaling_factor: 0.5 +mana_cost: 25 +cooldown: 4 +is_aoe: false +target_count: 1 +effects_applied: [] diff --git a/api/app/data/abilities/blizzard.yaml b/api/app/data/abilities/blizzard.yaml new file mode 100644 index 0000000..2b88c06 --- /dev/null +++ b/api/app/data/abilities/blizzard.yaml @@ -0,0 +1,25 @@ +# Blizzard - Arcanist Cryomancy ability +# AoE ice damage with slow + +ability_id: "blizzard" +name: "Blizzard" +description: "Summon a devastating blizzard that damages and slows all enemies" +ability_type: "spell" +base_power: 40 +damage_type: "ice" +scaling_stat: "intelligence" +scaling_factor: 0.55 +mana_cost: 32 +cooldown: 3 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "frostbitten" + name: "Frostbitten" + effect_type: "debuff" + duration: 3 + power: 30 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "blizzard" diff --git a/api/app/data/abilities/cleanse.yaml b/api/app/data/abilities/cleanse.yaml new file mode 100644 index 0000000..ecfc082 --- /dev/null +++ b/api/app/data/abilities/cleanse.yaml @@ -0,0 +1,16 @@ +# Cleanse - Oathkeeper Redemption ability +# Remove all debuffs + +ability_id: "cleanse" +name: "Cleanse" +description: "Purify an ally, removing all negative effects" +ability_type: "spell" +base_power: 0 +damage_type: null +scaling_stat: "wisdom" +scaling_factor: 0.3 +mana_cost: 18 +cooldown: 3 +is_aoe: false +target_count: 1 +effects_applied: [] diff --git a/api/app/data/abilities/cleave.yaml b/api/app/data/abilities/cleave.yaml new file mode 100644 index 0000000..b18cdd3 --- /dev/null +++ b/api/app/data/abilities/cleave.yaml @@ -0,0 +1,16 @@ +# Cleave - Vanguard Weapon Master ability +# AoE attack hitting all enemies + +ability_id: "cleave" +name: "Cleave" +description: "Swing your weapon in a wide arc, hitting all enemies" +ability_type: "attack" +base_power: 20 +damage_type: "physical" +scaling_stat: "strength" +scaling_factor: 0.5 +mana_cost: 15 +cooldown: 2 +is_aoe: true +target_count: 0 +effects_applied: [] diff --git a/api/app/data/abilities/confuse.yaml b/api/app/data/abilities/confuse.yaml new file mode 100644 index 0000000..a67b227 --- /dev/null +++ b/api/app/data/abilities/confuse.yaml @@ -0,0 +1,25 @@ +# Confuse - Lorekeeper Illusionist ability +# Random target attacks + +ability_id: "confuse" +name: "Confuse" +description: "Confuse your enemy, causing them to attack random targets" +ability_type: "spell" +base_power: 0 +damage_type: "arcane" +scaling_stat: "charisma" +scaling_factor: 0.5 +mana_cost: 12 +cooldown: 2 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "confused" + name: "Confused" + effect_type: "debuff" + duration: 2 + power: 50 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "confuse" diff --git a/api/app/data/abilities/consecrated_ground.yaml b/api/app/data/abilities/consecrated_ground.yaml new file mode 100644 index 0000000..f33130d --- /dev/null +++ b/api/app/data/abilities/consecrated_ground.yaml @@ -0,0 +1,25 @@ +# Consecrated Ground - Oathkeeper Aegis of Light ability +# Ground buff with damage reduction zone + +ability_id: "consecrated_ground" +name: "Consecrated Ground" +description: "Consecrate the ground, creating a zone that reduces damage taken by all allies standing within" +ability_type: "spell" +base_power: 0 +damage_type: null +scaling_stat: "wisdom" +scaling_factor: 0.4 +mana_cost: 30 +cooldown: 4 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "consecrated_protection" + name: "Consecrated" + effect_type: "buff" + duration: 3 + power: 25 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "consecrated_ground" diff --git a/api/app/data/abilities/consecration.yaml b/api/app/data/abilities/consecration.yaml new file mode 100644 index 0000000..7923638 --- /dev/null +++ b/api/app/data/abilities/consecration.yaml @@ -0,0 +1,25 @@ +# Consecration - Luminary Radiant Judgment ability +# Ground AoE holy damage + +ability_id: "consecration" +name: "Consecration" +description: "Consecrate the ground beneath your feet, dealing holy damage to all nearby enemies" +ability_type: "spell" +base_power: 40 +damage_type: "holy" +scaling_stat: "wisdom" +scaling_factor: 0.55 +mana_cost: 28 +cooldown: 3 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "consecrated_ground" + name: "Consecrated" + effect_type: "dot" + duration: 3 + power: 10 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "consecration" diff --git a/api/app/data/abilities/coordinated_attack.yaml b/api/app/data/abilities/coordinated_attack.yaml new file mode 100644 index 0000000..ea62746 --- /dev/null +++ b/api/app/data/abilities/coordinated_attack.yaml @@ -0,0 +1,16 @@ +# Coordinated Attack - Wildstrider Beast Companion ability +# Attack with pet + +ability_id: "coordinated_attack" +name: "Coordinated Attack" +description: "Attack in perfect coordination with your companion for bonus damage" +ability_type: "skill" +base_power: 30 +damage_type: "physical" +scaling_stat: "wisdom" +scaling_factor: 0.5 +mana_cost: 18 +cooldown: 2 +is_aoe: false +target_count: 1 +effects_applied: [] diff --git a/api/app/data/abilities/corpse_explosion.yaml b/api/app/data/abilities/corpse_explosion.yaml new file mode 100644 index 0000000..c9fa05d --- /dev/null +++ b/api/app/data/abilities/corpse_explosion.yaml @@ -0,0 +1,16 @@ +# Corpse Explosion - Necromancer Raise Dead ability +# Detonate corpse/minion AoE + +ability_id: "corpse_explosion" +name: "Corpse Explosion" +description: "Detonate a corpse or minion, dealing AoE shadow damage to all nearby enemies" +ability_type: "spell" +base_power: 45 +damage_type: "shadow" +scaling_stat: "intelligence" +scaling_factor: 0.55 +mana_cost: 28 +cooldown: 3 +is_aoe: true +target_count: 0 +effects_applied: [] diff --git a/api/app/data/abilities/coup_de_grace.yaml b/api/app/data/abilities/coup_de_grace.yaml new file mode 100644 index 0000000..1ff1971 --- /dev/null +++ b/api/app/data/abilities/coup_de_grace.yaml @@ -0,0 +1,16 @@ +# Coup de Grace - Assassin Blade Specialist ability +# Execute low HP targets + +ability_id: "coup_de_grace" +name: "Coup de Grace" +description: "Deliver the killing blow. Instantly kills targets below 25% HP, otherwise deals massive damage" +ability_type: "attack" +base_power: 70 +damage_type: "physical" +scaling_stat: "dexterity" +scaling_factor: 0.6 +mana_cost: 40 +cooldown: 4 +is_aoe: false +target_count: 1 +effects_applied: [] diff --git a/api/app/data/abilities/curse_of_agony.yaml b/api/app/data/abilities/curse_of_agony.yaml new file mode 100644 index 0000000..d9f07d8 --- /dev/null +++ b/api/app/data/abilities/curse_of_agony.yaml @@ -0,0 +1,25 @@ +# Curse of Agony - Necromancer Dark Affliction ability +# Heavy shadow DoT + +ability_id: "curse_of_agony" +name: "Curse of Agony" +description: "Curse your target with unbearable agony, dealing increasing shadow damage over 5 turns" +ability_type: "spell" +base_power: 10 +damage_type: "shadow" +scaling_stat: "intelligence" +scaling_factor: 0.55 +mana_cost: 28 +cooldown: 4 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "agony" + name: "Curse of Agony" + effect_type: "dot" + duration: 5 + power: 12 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "curse_of_agony" diff --git a/api/app/data/abilities/death_mark.yaml b/api/app/data/abilities/death_mark.yaml new file mode 100644 index 0000000..195da58 --- /dev/null +++ b/api/app/data/abilities/death_mark.yaml @@ -0,0 +1,25 @@ +# Death Mark - Assassin Shadow Dancer ability +# Mark target for bonus damage + +ability_id: "death_mark" +name: "Death Mark" +description: "Mark your target for death. Your next attack deals 200% damage" +ability_type: "skill" +base_power: 0 +damage_type: null +scaling_stat: "dexterity" +scaling_factor: 0.0 +mana_cost: 30 +cooldown: 4 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "marked_for_death" + name: "Marked for Death" + effect_type: "debuff" + duration: 2 + power: 100 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "death_mark" diff --git a/api/app/data/abilities/death_pact.yaml b/api/app/data/abilities/death_pact.yaml new file mode 100644 index 0000000..e743ca7 --- /dev/null +++ b/api/app/data/abilities/death_pact.yaml @@ -0,0 +1,25 @@ +# Death Pact - Necromancer Raise Dead ability +# Sacrifice minion for HP/mana + +ability_id: "death_pact" +name: "Death Pact" +description: "Sacrifice one of your minions to restore your health and mana" +ability_type: "spell" +base_power: 50 +damage_type: null +scaling_stat: "charisma" +scaling_factor: 0.5 +mana_cost: 0 +cooldown: 5 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "death_pact_heal" + name: "Death Pact" + effect_type: "hot" + duration: 1 + power: 40 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "death_pact" diff --git a/api/app/data/abilities/divine_aegis.yaml b/api/app/data/abilities/divine_aegis.yaml new file mode 100644 index 0000000..6109cdb --- /dev/null +++ b/api/app/data/abilities/divine_aegis.yaml @@ -0,0 +1,25 @@ +# Divine Aegis - Oathkeeper Aegis of Light ability +# Massive party shield + +ability_id: "divine_aegis" +name: "Divine Aegis" +description: "Invoke divine protection to create a powerful shield around all allies" +ability_type: "spell" +base_power: 60 +damage_type: null +scaling_stat: "wisdom" +scaling_factor: 0.6 +mana_cost: 45 +cooldown: 5 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "divine_aegis_shield" + name: "Divine Aegis" + effect_type: "shield" + duration: 3 + power: 50 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "divine_aegis" diff --git a/api/app/data/abilities/divine_blessing.yaml b/api/app/data/abilities/divine_blessing.yaml new file mode 100644 index 0000000..03c1751 --- /dev/null +++ b/api/app/data/abilities/divine_blessing.yaml @@ -0,0 +1,34 @@ +# Divine Blessing - Oathkeeper Redemption ability +# Stat buff + HoT + +ability_id: "divine_blessing" +name: "Divine Blessing" +description: "Bless an ally with divine power, increasing their stats and healing over time" +ability_type: "spell" +base_power: 0 +damage_type: null +scaling_stat: "wisdom" +scaling_factor: 0.5 +mana_cost: 35 +cooldown: 4 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "blessed" + name: "Divine Blessing" + effect_type: "buff" + duration: 4 + power: 15 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "divine_blessing" + - effect_id: "blessed_healing" + name: "Blessed Healing" + effect_type: "hot" + duration: 4 + power: 10 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "divine_blessing" diff --git a/api/app/data/abilities/divine_intervention.yaml b/api/app/data/abilities/divine_intervention.yaml new file mode 100644 index 0000000..09d1071 --- /dev/null +++ b/api/app/data/abilities/divine_intervention.yaml @@ -0,0 +1,16 @@ +# Divine Intervention - Luminary Divine Protection ability +# Full heal + cleanse + +ability_id: "divine_intervention" +name: "Divine Intervention" +description: "Call upon divine power to fully heal and cleanse an ally of all negative effects" +ability_type: "spell" +base_power: 80 +damage_type: "holy" +scaling_stat: "wisdom" +scaling_factor: 0.6 +mana_cost: 45 +cooldown: 5 +is_aoe: false +target_count: 1 +effects_applied: [] diff --git a/api/app/data/abilities/divine_storm.yaml b/api/app/data/abilities/divine_storm.yaml new file mode 100644 index 0000000..0b7424c --- /dev/null +++ b/api/app/data/abilities/divine_storm.yaml @@ -0,0 +1,25 @@ +# Divine Storm - Luminary Radiant Judgment ultimate +# Ultimate AoE holy + stun all + +ability_id: "divine_storm" +name: "Divine Storm" +description: "Unleash the full fury of the divine, dealing massive holy damage to all enemies and stunning them" +ability_type: "spell" +base_power: 95 +damage_type: "holy" +scaling_stat: "wisdom" +scaling_factor: 0.7 +mana_cost: 60 +cooldown: 5 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "divine_judgment" + name: "Divine Judgment" + effect_type: "stun" + duration: 1 + power: 0 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "divine_storm" diff --git a/api/app/data/abilities/drain_life.yaml b/api/app/data/abilities/drain_life.yaml new file mode 100644 index 0000000..f44ad0b --- /dev/null +++ b/api/app/data/abilities/drain_life.yaml @@ -0,0 +1,25 @@ +# Drain Life - Necromancer Dark Affliction ability +# Shadow damage + self-heal + +ability_id: "drain_life" +name: "Drain Life" +description: "Drain the life force from your enemy, dealing shadow damage and healing yourself" +ability_type: "spell" +base_power: 18 +damage_type: "shadow" +scaling_stat: "intelligence" +scaling_factor: 0.5 +mana_cost: 12 +cooldown: 1 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "life_drain" + name: "Life Drained" + effect_type: "hot" + duration: 1 + power: 9 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "drain_life" diff --git a/api/app/data/abilities/epidemic.yaml b/api/app/data/abilities/epidemic.yaml new file mode 100644 index 0000000..af6d2af --- /dev/null +++ b/api/app/data/abilities/epidemic.yaml @@ -0,0 +1,34 @@ +# Epidemic - Necromancer Dark Affliction ultimate +# Ultimate multi-DoT all enemies + +ability_id: "epidemic" +name: "Epidemic" +description: "Unleash a devastating epidemic that afflicts all enemies with multiple diseases" +ability_type: "spell" +base_power: 60 +damage_type: "shadow" +scaling_stat: "intelligence" +scaling_factor: 0.7 +mana_cost: 60 +cooldown: 6 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "epidemic_plague" + name: "Epidemic" + effect_type: "dot" + duration: 5 + power: 20 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "epidemic" + - effect_id: "weakened" + name: "Weakened" + effect_type: "debuff" + duration: 5 + power: 25 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "epidemic" diff --git a/api/app/data/abilities/execute.yaml b/api/app/data/abilities/execute.yaml new file mode 100644 index 0000000..f132bac --- /dev/null +++ b/api/app/data/abilities/execute.yaml @@ -0,0 +1,16 @@ +# Execute - Vanguard Weapon Master ability +# Bonus damage to low HP targets + +ability_id: "execute" +name: "Execute" +description: "Finish off weakened enemies. Deals bonus damage to targets below 30% HP" +ability_type: "attack" +base_power: 60 +damage_type: "physical" +scaling_stat: "strength" +scaling_factor: 0.6 +mana_cost: 40 +cooldown: 3 +is_aoe: false +target_count: 1 +effects_applied: [] diff --git a/api/app/data/abilities/explosive_shot.yaml b/api/app/data/abilities/explosive_shot.yaml new file mode 100644 index 0000000..2e56517 --- /dev/null +++ b/api/app/data/abilities/explosive_shot.yaml @@ -0,0 +1,25 @@ +# Explosive Shot - Wildstrider Marksmanship ability +# Impact AoE damage + +ability_id: "explosive_shot" +name: "Explosive Shot" +description: "Fire an explosive arrow that detonates on impact, dealing AoE damage" +ability_type: "attack" +base_power: 55 +damage_type: "fire" +scaling_stat: "dexterity" +scaling_factor: 0.55 +mana_cost: 38 +cooldown: 3 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "burning_shrapnel" + name: "Burning Shrapnel" + effect_type: "dot" + duration: 2 + power: 8 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "explosive_shot" diff --git a/api/app/data/abilities/firestorm.yaml b/api/app/data/abilities/firestorm.yaml new file mode 100644 index 0000000..a9b7954 --- /dev/null +++ b/api/app/data/abilities/firestorm.yaml @@ -0,0 +1,25 @@ +# Firestorm - Arcanist Pyromancy ability +# Massive AoE fire damage + +ability_id: "firestorm" +name: "Firestorm" +description: "Call down a storm of fire from the heavens, devastating all enemies" +ability_type: "spell" +base_power: 55 +damage_type: "fire" +scaling_stat: "intelligence" +scaling_factor: 0.6 +mana_cost: 45 +cooldown: 4 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "scorched" + name: "Scorched" + effect_type: "dot" + duration: 2 + power: 12 + stat_affected: null + stacks: 1 + max_stacks: 3 + source: "firestorm" diff --git a/api/app/data/abilities/flame_burst.yaml b/api/app/data/abilities/flame_burst.yaml new file mode 100644 index 0000000..17b8bde --- /dev/null +++ b/api/app/data/abilities/flame_burst.yaml @@ -0,0 +1,16 @@ +# Flame Burst - Arcanist Pyromancy ability +# AoE fire burst centered on caster + +ability_id: "flame_burst" +name: "Flame Burst" +description: "Release a burst of flames around you, scorching all nearby enemies" +ability_type: "spell" +base_power: 25 +damage_type: "fire" +scaling_stat: "intelligence" +scaling_factor: 0.5 +mana_cost: 18 +cooldown: 2 +is_aoe: true +target_count: 0 +effects_applied: [] diff --git a/api/app/data/abilities/frozen_orb.yaml b/api/app/data/abilities/frozen_orb.yaml new file mode 100644 index 0000000..8c06cd8 --- /dev/null +++ b/api/app/data/abilities/frozen_orb.yaml @@ -0,0 +1,25 @@ +# Frozen Orb - Arcanist Cryomancy ability +# AoE freeze with damage + +ability_id: "frozen_orb" +name: "Frozen Orb" +description: "Launch a swirling orb of frost that freezes enemies in its path" +ability_type: "spell" +base_power: 28 +damage_type: "ice" +scaling_stat: "intelligence" +scaling_factor: 0.5 +mana_cost: 20 +cooldown: 3 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "frozen" + name: "Frozen" + effect_type: "stun" + duration: 1 + power: 0 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "frozen_orb" diff --git a/api/app/data/abilities/glacial_spike.yaml b/api/app/data/abilities/glacial_spike.yaml new file mode 100644 index 0000000..843cb90 --- /dev/null +++ b/api/app/data/abilities/glacial_spike.yaml @@ -0,0 +1,25 @@ +# Glacial Spike - Arcanist Cryomancy ability +# Heavy single target with freeze + +ability_id: "glacial_spike" +name: "Glacial Spike" +description: "Impale your target with a massive spike of ice, dealing heavy damage and freezing them" +ability_type: "spell" +base_power: 60 +damage_type: "ice" +scaling_stat: "intelligence" +scaling_factor: 0.6 +mana_cost: 40 +cooldown: 3 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "deep_freeze" + name: "Deep Freeze" + effect_type: "stun" + duration: 2 + power: 0 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "glacial_spike" diff --git a/api/app/data/abilities/guardian_angel.yaml b/api/app/data/abilities/guardian_angel.yaml new file mode 100644 index 0000000..9492366 --- /dev/null +++ b/api/app/data/abilities/guardian_angel.yaml @@ -0,0 +1,25 @@ +# Guardian Angel - Luminary Divine Protection ability +# Death prevention buff + +ability_id: "guardian_angel" +name: "Guardian Angel" +description: "Bless an ally with divine protection that prevents death once" +ability_type: "spell" +base_power: 0 +damage_type: null +scaling_stat: "wisdom" +scaling_factor: 0.4 +mana_cost: 35 +cooldown: 6 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "guardian_angel_buff" + name: "Guardian Angel" + effect_type: "buff" + duration: 5 + power: 1 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "guardian_angel" diff --git a/api/app/data/abilities/hammer_of_justice.yaml b/api/app/data/abilities/hammer_of_justice.yaml new file mode 100644 index 0000000..b455215 --- /dev/null +++ b/api/app/data/abilities/hammer_of_justice.yaml @@ -0,0 +1,25 @@ +# Hammer of Justice - Luminary Radiant Judgment ability +# Holy damage + stun + +ability_id: "hammer_of_justice" +name: "Hammer of Justice" +description: "Smash your enemy with a divine hammer, dealing holy damage and stunning them" +ability_type: "spell" +base_power: 55 +damage_type: "holy" +scaling_stat: "wisdom" +scaling_factor: 0.6 +mana_cost: 38 +cooldown: 4 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "justice_stun" + name: "Judged" + effect_type: "stun" + duration: 2 + power: 0 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "hammer_of_justice" diff --git a/api/app/data/abilities/haste.yaml b/api/app/data/abilities/haste.yaml new file mode 100644 index 0000000..d11a56f --- /dev/null +++ b/api/app/data/abilities/haste.yaml @@ -0,0 +1,25 @@ +# Haste - Lorekeeper Arcane Weaving ability +# Grant extra action + +ability_id: "haste" +name: "Haste" +description: "Speed up time around an ally, granting them an extra action" +ability_type: "spell" +base_power: 0 +damage_type: null +scaling_stat: "intelligence" +scaling_factor: 0.4 +mana_cost: 20 +cooldown: 4 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "hasted" + name: "Hasted" + effect_type: "buff" + duration: 2 + power: 50 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "haste" diff --git a/api/app/data/abilities/heal.yaml b/api/app/data/abilities/heal.yaml index 9b0c6b7..79025c4 100644 --- a/api/app/data/abilities/heal.yaml +++ b/api/app/data/abilities/heal.yaml @@ -7,7 +7,7 @@ description: "Channel divine energy to restore an ally's health" ability_type: "spell" base_power: 25 damage_type: "holy" -scaling_stat: "intelligence" +scaling_stat: "wisdom" scaling_factor: 0.5 mana_cost: 10 cooldown: 0 diff --git a/api/app/data/abilities/holy_fire.yaml b/api/app/data/abilities/holy_fire.yaml new file mode 100644 index 0000000..af35ffb --- /dev/null +++ b/api/app/data/abilities/holy_fire.yaml @@ -0,0 +1,25 @@ +# Holy Fire - Luminary Radiant Judgment ability +# Holy DoT with reduced healing + +ability_id: "holy_fire" +name: "Holy Fire" +description: "Engulf your enemy in holy flames that burn over time and reduce their healing" +ability_type: "spell" +base_power: 25 +damage_type: "holy" +scaling_stat: "wisdom" +scaling_factor: 0.5 +mana_cost: 18 +cooldown: 2 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "holy_burning" + name: "Holy Fire" + effect_type: "dot" + duration: 3 + power: 8 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "holy_fire" diff --git a/api/app/data/abilities/holy_shield.yaml b/api/app/data/abilities/holy_shield.yaml new file mode 100644 index 0000000..e24a8f2 --- /dev/null +++ b/api/app/data/abilities/holy_shield.yaml @@ -0,0 +1,25 @@ +# Holy Shield - Luminary Divine Protection ability +# Grant damage absorb shield + +ability_id: "holy_shield" +name: "Holy Shield" +description: "Grant an ally a protective barrier of holy light that absorbs damage" +ability_type: "spell" +base_power: 30 +damage_type: null +scaling_stat: "wisdom" +scaling_factor: 0.5 +mana_cost: 15 +cooldown: 2 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "holy_shield_barrier" + name: "Holy Shield" + effect_type: "shield" + duration: 3 + power: 30 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "holy_shield" diff --git a/api/app/data/abilities/ice_shard.yaml b/api/app/data/abilities/ice_shard.yaml new file mode 100644 index 0000000..fae900b --- /dev/null +++ b/api/app/data/abilities/ice_shard.yaml @@ -0,0 +1,25 @@ +# Ice Shard - Arcanist Cryomancy ability +# Single target ice damage with slow + +ability_id: "ice_shard" +name: "Ice Shard" +description: "Hurl a shard of ice at your enemy, dealing frost damage and slowing them" +ability_type: "spell" +base_power: 20 +damage_type: "ice" +scaling_stat: "intelligence" +scaling_factor: 0.5 +mana_cost: 10 +cooldown: 0 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "chilled" + name: "Chilled" + effect_type: "debuff" + duration: 2 + power: 20 + stat_affected: null + stacks: 1 + max_stacks: 3 + source: "ice_shard" diff --git a/api/app/data/abilities/inferno.yaml b/api/app/data/abilities/inferno.yaml new file mode 100644 index 0000000..117b70d --- /dev/null +++ b/api/app/data/abilities/inferno.yaml @@ -0,0 +1,25 @@ +# Inferno - Arcanist Pyromancy ability +# AoE fire DoT + +ability_id: "inferno" +name: "Inferno" +description: "Summon a raging inferno that burns all enemies for 3 turns" +ability_type: "spell" +base_power: 35 +damage_type: "fire" +scaling_stat: "intelligence" +scaling_factor: 0.55 +mana_cost: 30 +cooldown: 3 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "inferno_burn" + name: "Inferno Flames" + effect_type: "dot" + duration: 3 + power: 10 + stat_affected: null + stacks: 1 + max_stacks: 3 + source: "inferno" diff --git a/api/app/data/abilities/last_stand.yaml b/api/app/data/abilities/last_stand.yaml new file mode 100644 index 0000000..131255e --- /dev/null +++ b/api/app/data/abilities/last_stand.yaml @@ -0,0 +1,34 @@ +# Last Stand - Oathkeeper Aegis of Light ultimate +# Invulnerable + taunt all + +ability_id: "last_stand" +name: "Last Stand" +description: "Make your final stand, becoming invulnerable and forcing all enemies to attack you" +ability_type: "skill" +base_power: 0 +damage_type: null +scaling_stat: "constitution" +scaling_factor: 0.5 +mana_cost: 55 +cooldown: 8 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "invulnerable" + name: "Invulnerable" + effect_type: "buff" + duration: 3 + power: 100 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "last_stand" + - effect_id: "ultimate_taunt" + name: "Challenged" + effect_type: "debuff" + duration: 3 + power: 100 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "last_stand" diff --git a/api/app/data/abilities/lay_on_hands.yaml b/api/app/data/abilities/lay_on_hands.yaml new file mode 100644 index 0000000..28783a5 --- /dev/null +++ b/api/app/data/abilities/lay_on_hands.yaml @@ -0,0 +1,25 @@ +# Lay on Hands - Oathkeeper Redemption ability +# Touch heal + +ability_id: "lay_on_hands" +name: "Lay on Hands" +description: "Place your hands upon an ally to heal their wounds" +ability_type: "spell" +base_power: 25 +damage_type: "holy" +scaling_stat: "wisdom" +scaling_factor: 0.5 +mana_cost: 12 +cooldown: 0 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "gentle_healing" + name: "Soothed" + effect_type: "hot" + duration: 2 + power: 5 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "lay_on_hands" diff --git a/api/app/data/abilities/mass_confusion.yaml b/api/app/data/abilities/mass_confusion.yaml new file mode 100644 index 0000000..aecf29a --- /dev/null +++ b/api/app/data/abilities/mass_confusion.yaml @@ -0,0 +1,25 @@ +# Mass Confusion - Lorekeeper Illusionist ability +# AoE confusion + +ability_id: "mass_confusion" +name: "Mass Confusion" +description: "Unleash a wave of illusions that confuses all enemies" +ability_type: "spell" +base_power: 0 +damage_type: "arcane" +scaling_stat: "charisma" +scaling_factor: 0.55 +mana_cost: 35 +cooldown: 4 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "mass_confused" + name: "Bewildered" + effect_type: "debuff" + duration: 3 + power: 40 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "mass_confusion" diff --git a/api/app/data/abilities/mass_domination.yaml b/api/app/data/abilities/mass_domination.yaml new file mode 100644 index 0000000..442f9f2 --- /dev/null +++ b/api/app/data/abilities/mass_domination.yaml @@ -0,0 +1,25 @@ +# Mass Domination - Lorekeeper Illusionist ultimate +# Mind control all enemies + +ability_id: "mass_domination" +name: "Mass Domination" +description: "Dominate the minds of all enemies, forcing them to attack each other" +ability_type: "spell" +base_power: 0 +damage_type: "arcane" +scaling_stat: "charisma" +scaling_factor: 0.7 +mana_cost: 75 +cooldown: 8 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "dominated" + name: "Dominated" + effect_type: "debuff" + duration: 3 + power: 100 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "mass_domination" diff --git a/api/app/data/abilities/mass_enhancement.yaml b/api/app/data/abilities/mass_enhancement.yaml new file mode 100644 index 0000000..794320a --- /dev/null +++ b/api/app/data/abilities/mass_enhancement.yaml @@ -0,0 +1,25 @@ +# Mass Enhancement - Lorekeeper Arcane Weaving ability +# AoE stat buff + +ability_id: "mass_enhancement" +name: "Mass Enhancement" +description: "Enhance all allies with arcane power, increasing all their stats" +ability_type: "spell" +base_power: 0 +damage_type: null +scaling_stat: "intelligence" +scaling_factor: 0.5 +mana_cost: 32 +cooldown: 4 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "enhanced" + name: "Enhanced" + effect_type: "buff" + duration: 4 + power: 15 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "mass_enhancement" diff --git a/api/app/data/abilities/mass_heal.yaml b/api/app/data/abilities/mass_heal.yaml new file mode 100644 index 0000000..920fd27 --- /dev/null +++ b/api/app/data/abilities/mass_heal.yaml @@ -0,0 +1,25 @@ +# Mass Heal - Luminary Divine Protection ability +# AoE healing + +ability_id: "mass_heal" +name: "Mass Heal" +description: "Channel divine energy to heal all allies" +ability_type: "spell" +base_power: 35 +damage_type: "holy" +scaling_stat: "wisdom" +scaling_factor: 0.55 +mana_cost: 30 +cooldown: 3 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "mass_regen" + name: "Divine Healing" + effect_type: "hot" + duration: 2 + power: 8 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "mass_heal" diff --git a/api/app/data/abilities/mesmerize.yaml b/api/app/data/abilities/mesmerize.yaml new file mode 100644 index 0000000..cf7e89b --- /dev/null +++ b/api/app/data/abilities/mesmerize.yaml @@ -0,0 +1,25 @@ +# Mesmerize - Lorekeeper Illusionist ability +# Stun for 2 turns + +ability_id: "mesmerize" +name: "Mesmerize" +description: "Mesmerize your target with illusions, stunning them for 2 turns" +ability_type: "spell" +base_power: 0 +damage_type: "arcane" +scaling_stat: "charisma" +scaling_factor: 0.5 +mana_cost: 22 +cooldown: 4 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "mesmerized" + name: "Mesmerized" + effect_type: "stun" + duration: 2 + power: 0 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "mesmerize" diff --git a/api/app/data/abilities/miracle.yaml b/api/app/data/abilities/miracle.yaml new file mode 100644 index 0000000..d39e127 --- /dev/null +++ b/api/app/data/abilities/miracle.yaml @@ -0,0 +1,25 @@ +# Miracle - Oathkeeper Redemption ultimate +# Full party heal + cleanse all + +ability_id: "miracle" +name: "Miracle" +description: "Perform a divine miracle that fully heals all allies and cleanses all negative effects" +ability_type: "spell" +base_power: 100 +damage_type: "holy" +scaling_stat: "wisdom" +scaling_factor: 0.7 +mana_cost: 70 +cooldown: 8 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "miraculous_healing" + name: "Miraculous" + effect_type: "hot" + duration: 3 + power: 20 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "miracle" diff --git a/api/app/data/abilities/mirror_image.yaml b/api/app/data/abilities/mirror_image.yaml new file mode 100644 index 0000000..484ce2a --- /dev/null +++ b/api/app/data/abilities/mirror_image.yaml @@ -0,0 +1,25 @@ +# Mirror Image - Lorekeeper Illusionist ability +# Summon decoys + +ability_id: "mirror_image" +name: "Mirror Image" +description: "Create illusory copies of yourself that absorb enemy attacks" +ability_type: "spell" +base_power: 0 +damage_type: null +scaling_stat: "charisma" +scaling_factor: 0.5 +mana_cost: 28 +cooldown: 5 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "mirror_images" + name: "Mirror Images" + effect_type: "shield" + duration: 4 + power: 40 + stat_affected: null + stacks: 3 + max_stacks: 3 + source: "mirror_image" diff --git a/api/app/data/abilities/multishot.yaml b/api/app/data/abilities/multishot.yaml new file mode 100644 index 0000000..2b9d40a --- /dev/null +++ b/api/app/data/abilities/multishot.yaml @@ -0,0 +1,16 @@ +# Multishot - Wildstrider Marksmanship ability +# Hit multiple targets + +ability_id: "multishot" +name: "Multishot" +description: "Fire multiple arrows in quick succession, hitting up to 3 targets" +ability_type: "attack" +base_power: 22 +damage_type: "physical" +scaling_stat: "dexterity" +scaling_factor: 0.5 +mana_cost: 18 +cooldown: 2 +is_aoe: true +target_count: 3 +effects_applied: [] diff --git a/api/app/data/abilities/phantasmal_killer.yaml b/api/app/data/abilities/phantasmal_killer.yaml new file mode 100644 index 0000000..df2a80c --- /dev/null +++ b/api/app/data/abilities/phantasmal_killer.yaml @@ -0,0 +1,25 @@ +# Phantasmal Killer - Lorekeeper Illusionist ability +# Psychic damage + fear + +ability_id: "phantasmal_killer" +name: "Phantasmal Killer" +description: "Conjure a nightmarish illusion that terrifies and damages your target" +ability_type: "spell" +base_power: 55 +damage_type: "arcane" +scaling_stat: "charisma" +scaling_factor: 0.6 +mana_cost: 42 +cooldown: 4 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "terrified" + name: "Terrified" + effect_type: "debuff" + duration: 3 + power: 30 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "phantasmal_killer" diff --git a/api/app/data/abilities/piercing_shot.yaml b/api/app/data/abilities/piercing_shot.yaml new file mode 100644 index 0000000..7897f03 --- /dev/null +++ b/api/app/data/abilities/piercing_shot.yaml @@ -0,0 +1,25 @@ +# Piercing Shot - Wildstrider Marksmanship ability +# Line AoE that pierces through enemies + +ability_id: "piercing_shot" +name: "Piercing Shot" +description: "Fire a powerful arrow that pierces through all enemies in a line" +ability_type: "attack" +base_power: 40 +damage_type: "physical" +scaling_stat: "dexterity" +scaling_factor: 0.55 +mana_cost: 28 +cooldown: 3 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "armor_pierced" + name: "Armor Pierced" + effect_type: "debuff" + duration: 2 + power: 15 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "piercing_shot" diff --git a/api/app/data/abilities/plague.yaml b/api/app/data/abilities/plague.yaml new file mode 100644 index 0000000..a849a8d --- /dev/null +++ b/api/app/data/abilities/plague.yaml @@ -0,0 +1,25 @@ +# Plague - Necromancer Dark Affliction ability +# Spreading poison DoT + +ability_id: "plague" +name: "Plague" +description: "Infect your target with a virulent plague that spreads to nearby enemies" +ability_type: "spell" +base_power: 15 +damage_type: "poison" +scaling_stat: "intelligence" +scaling_factor: 0.5 +mana_cost: 20 +cooldown: 3 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "plagued" + name: "Plagued" + effect_type: "dot" + duration: 4 + power: 8 + stat_affected: null + stacks: 1 + max_stacks: 3 + source: "plague" diff --git a/api/app/data/abilities/power_strike.yaml b/api/app/data/abilities/power_strike.yaml new file mode 100644 index 0000000..c162987 --- /dev/null +++ b/api/app/data/abilities/power_strike.yaml @@ -0,0 +1,16 @@ +# Power Strike - Vanguard Weapon Master ability +# Heavy attack dealing 150% weapon damage + +ability_id: "power_strike" +name: "Power Strike" +description: "A heavy attack that deals 150% weapon damage" +ability_type: "attack" +base_power: 15 +damage_type: "physical" +scaling_stat: "strength" +scaling_factor: 0.6 +mana_cost: 8 +cooldown: 1 +is_aoe: false +target_count: 1 +effects_applied: [] diff --git a/api/app/data/abilities/precise_strike.yaml b/api/app/data/abilities/precise_strike.yaml new file mode 100644 index 0000000..54a391f --- /dev/null +++ b/api/app/data/abilities/precise_strike.yaml @@ -0,0 +1,16 @@ +# Precise Strike - Assassin Blade Specialist ability +# High crit chance attack + +ability_id: "precise_strike" +name: "Precise Strike" +description: "A calculated strike aimed at vital points with increased critical chance" +ability_type: "attack" +base_power: 15 +damage_type: "physical" +scaling_stat: "dexterity" +scaling_factor: 0.5 +mana_cost: 8 +cooldown: 1 +is_aoe: false +target_count: 1 +effects_applied: [] diff --git a/api/app/data/abilities/primal_fury.yaml b/api/app/data/abilities/primal_fury.yaml new file mode 100644 index 0000000..a3c93d9 --- /dev/null +++ b/api/app/data/abilities/primal_fury.yaml @@ -0,0 +1,16 @@ +# Primal Fury - Wildstrider Beast Companion ability +# Pet AoE attack + +ability_id: "primal_fury" +name: "Primal Fury" +description: "Command your companion to unleash a devastating attack on all enemies" +ability_type: "skill" +base_power: 50 +damage_type: "physical" +scaling_stat: "wisdom" +scaling_factor: 0.55 +mana_cost: 35 +cooldown: 4 +is_aoe: true +target_count: 0 +effects_applied: [] diff --git a/api/app/data/abilities/rain_of_arrows.yaml b/api/app/data/abilities/rain_of_arrows.yaml new file mode 100644 index 0000000..5c91837 --- /dev/null +++ b/api/app/data/abilities/rain_of_arrows.yaml @@ -0,0 +1,25 @@ +# Rain of Arrows - Wildstrider Marksmanship ultimate +# Ultimate AoE attack + +ability_id: "rain_of_arrows" +name: "Rain of Arrows" +description: "Call down a devastating rain of arrows upon all enemies" +ability_type: "attack" +base_power: 85 +damage_type: "physical" +scaling_stat: "dexterity" +scaling_factor: 0.7 +mana_cost: 55 +cooldown: 5 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "pinned" + name: "Pinned" + effect_type: "debuff" + duration: 1 + power: 50 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "rain_of_arrows" diff --git a/api/app/data/abilities/raise_ghoul.yaml b/api/app/data/abilities/raise_ghoul.yaml new file mode 100644 index 0000000..b5c2619 --- /dev/null +++ b/api/app/data/abilities/raise_ghoul.yaml @@ -0,0 +1,25 @@ +# Raise Ghoul - Necromancer Raise Dead ability +# Summon stronger ghoul + +ability_id: "raise_ghoul" +name: "Raise Ghoul" +description: "Raise a powerful ghoul from the dead to serve you" +ability_type: "spell" +base_power: 0 +damage_type: null +scaling_stat: "charisma" +scaling_factor: 0.55 +mana_cost: 22 +cooldown: 0 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "ghoul_minion" + name: "Ghoul" + effect_type: "buff" + duration: 99 + power: 35 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "raise_ghoul" diff --git a/api/app/data/abilities/reality_shift.yaml b/api/app/data/abilities/reality_shift.yaml new file mode 100644 index 0000000..08f8665 --- /dev/null +++ b/api/app/data/abilities/reality_shift.yaml @@ -0,0 +1,34 @@ +# Reality Shift - Lorekeeper Arcane Weaving ultimate +# Massive buff allies + debuff enemies + +ability_id: "reality_shift" +name: "Reality Shift" +description: "Alter reality itself, greatly empowering allies while weakening all enemies" +ability_type: "spell" +base_power: 0 +damage_type: "arcane" +scaling_stat: "intelligence" +scaling_factor: 0.7 +mana_cost: 70 +cooldown: 8 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "reality_empowered" + name: "Reality Empowered" + effect_type: "buff" + duration: 5 + power: 30 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "reality_shift" + - effect_id: "reality_weakened" + name: "Reality Distorted" + effect_type: "debuff" + duration: 5 + power: 30 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "reality_shift" diff --git a/api/app/data/abilities/rending_blow.yaml b/api/app/data/abilities/rending_blow.yaml new file mode 100644 index 0000000..2fc39af --- /dev/null +++ b/api/app/data/abilities/rending_blow.yaml @@ -0,0 +1,25 @@ +# Rending Blow - Vanguard Weapon Master ability +# Attack with bleed DoT + +ability_id: "rending_blow" +name: "Rending Blow" +description: "Strike with such force that your enemy bleeds for 3 turns" +ability_type: "attack" +base_power: 35 +damage_type: "physical" +scaling_stat: "strength" +scaling_factor: 0.5 +mana_cost: 25 +cooldown: 2 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "bleed" + name: "Bleeding" + effect_type: "dot" + duration: 3 + power: 8 + stat_affected: null + stacks: 1 + max_stacks: 3 + source: "rending_blow" diff --git a/api/app/data/abilities/resurrection.yaml b/api/app/data/abilities/resurrection.yaml new file mode 100644 index 0000000..0564a42 --- /dev/null +++ b/api/app/data/abilities/resurrection.yaml @@ -0,0 +1,16 @@ +# Resurrection - Luminary Divine Protection ultimate +# Revive fallen ally + +ability_id: "resurrection" +name: "Resurrection" +description: "Call upon the divine to bring a fallen ally back to life with 50% HP and mana" +ability_type: "spell" +base_power: 50 +damage_type: "holy" +scaling_stat: "wisdom" +scaling_factor: 0.5 +mana_cost: 60 +cooldown: 8 +is_aoe: false +target_count: 1 +effects_applied: [] diff --git a/api/app/data/abilities/riposte.yaml b/api/app/data/abilities/riposte.yaml new file mode 100644 index 0000000..c872090 --- /dev/null +++ b/api/app/data/abilities/riposte.yaml @@ -0,0 +1,16 @@ +# Riposte - Vanguard Shield Bearer ability +# Counter attack after blocking + +ability_id: "riposte" +name: "Riposte" +description: "After blocking an attack, counter with a swift strike" +ability_type: "skill" +base_power: 30 +damage_type: "physical" +scaling_stat: "strength" +scaling_factor: 0.5 +mana_cost: 20 +cooldown: 2 +is_aoe: false +target_count: 1 +effects_applied: [] diff --git a/api/app/data/abilities/shadow_assault.yaml b/api/app/data/abilities/shadow_assault.yaml new file mode 100644 index 0000000..9139089 --- /dev/null +++ b/api/app/data/abilities/shadow_assault.yaml @@ -0,0 +1,25 @@ +# Shadow Assault - Assassin Shadow Dancer ultimate +# AoE guaranteed crits + +ability_id: "shadow_assault" +name: "Shadow Assault" +description: "Become one with the shadows and strike all enemies with guaranteed critical hits" +ability_type: "skill" +base_power: 80 +damage_type: "physical" +scaling_stat: "dexterity" +scaling_factor: 0.7 +mana_cost: 55 +cooldown: 6 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "shadow_crit" + name: "Shadow Strike" + effect_type: "buff" + duration: 1 + power: 100 + stat_affected: "crit_chance" + stacks: 1 + max_stacks: 1 + source: "shadow_assault" diff --git a/api/app/data/abilities/shadowstep.yaml b/api/app/data/abilities/shadowstep.yaml new file mode 100644 index 0000000..8f90b82 --- /dev/null +++ b/api/app/data/abilities/shadowstep.yaml @@ -0,0 +1,16 @@ +# Shadowstep - Assassin Shadow Dancer ability +# Teleport and backstab + +ability_id: "shadowstep" +name: "Shadowstep" +description: "Vanish into the shadows and reappear behind your target, striking from behind" +ability_type: "skill" +base_power: 18 +damage_type: "physical" +scaling_stat: "dexterity" +scaling_factor: 0.6 +mana_cost: 10 +cooldown: 2 +is_aoe: false +target_count: 1 +effects_applied: [] diff --git a/api/app/data/abilities/shield_of_faith.yaml b/api/app/data/abilities/shield_of_faith.yaml new file mode 100644 index 0000000..55046cc --- /dev/null +++ b/api/app/data/abilities/shield_of_faith.yaml @@ -0,0 +1,25 @@ +# Shield of Faith - Oathkeeper Aegis of Light ability +# Shield for self and allies + +ability_id: "shield_of_faith" +name: "Shield of Faith" +description: "Create a shield of divine faith that protects you and nearby allies" +ability_type: "spell" +base_power: 35 +damage_type: null +scaling_stat: "wisdom" +scaling_factor: 0.5 +mana_cost: 20 +cooldown: 3 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "faith_shield" + name: "Shield of Faith" + effect_type: "shield" + duration: 3 + power: 25 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "shield_of_faith" diff --git a/api/app/data/abilities/shield_wall.yaml b/api/app/data/abilities/shield_wall.yaml new file mode 100644 index 0000000..4682191 --- /dev/null +++ b/api/app/data/abilities/shield_wall.yaml @@ -0,0 +1,25 @@ +# Shield Wall - Vanguard Shield Bearer ability +# Defensive buff reducing damage + +ability_id: "shield_wall" +name: "Shield Wall" +description: "Raise your shield to block incoming attacks, reducing damage by 50% for 3 turns" +ability_type: "defend" +base_power: 0 +damage_type: null +scaling_stat: "constitution" +scaling_factor: 0.3 +mana_cost: 12 +cooldown: 4 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "shield_wall_buff" + name: "Shield Wall" + effect_type: "buff" + duration: 3 + power: 50 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "shield_wall" diff --git a/api/app/data/abilities/smite.yaml b/api/app/data/abilities/smite.yaml new file mode 100644 index 0000000..6f439aa --- /dev/null +++ b/api/app/data/abilities/smite.yaml @@ -0,0 +1,16 @@ +# Smite - Luminary Radiant Judgment ability +# Holy damage attack + +ability_id: "smite" +name: "Smite" +description: "Call down holy light to smite your enemies" +ability_type: "spell" +base_power: 20 +damage_type: "holy" +scaling_stat: "wisdom" +scaling_factor: 0.5 +mana_cost: 10 +cooldown: 0 +is_aoe: false +target_count: 1 +effects_applied: [] diff --git a/api/app/data/abilities/smoke_bomb.yaml b/api/app/data/abilities/smoke_bomb.yaml new file mode 100644 index 0000000..256183c --- /dev/null +++ b/api/app/data/abilities/smoke_bomb.yaml @@ -0,0 +1,25 @@ +# Smoke Bomb - Assassin Shadow Dancer ability +# Evasion buff + +ability_id: "smoke_bomb" +name: "Smoke Bomb" +description: "Throw a smoke bomb, making yourself untargetable for 1 turn" +ability_type: "skill" +base_power: 0 +damage_type: null +scaling_stat: "dexterity" +scaling_factor: 0.3 +mana_cost: 15 +cooldown: 4 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "smoke_screen" + name: "Smoke Screen" + effect_type: "buff" + duration: 1 + power: 100 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "smoke_bomb" diff --git a/api/app/data/abilities/soul_rot.yaml b/api/app/data/abilities/soul_rot.yaml new file mode 100644 index 0000000..0c1a540 --- /dev/null +++ b/api/app/data/abilities/soul_rot.yaml @@ -0,0 +1,34 @@ +# Soul Rot - Necromancer Dark Affliction ability +# DoT + reduced healing on target + +ability_id: "soul_rot" +name: "Soul Rot" +description: "Rot your target's soul, dealing shadow damage over time and reducing their healing received" +ability_type: "spell" +base_power: 45 +damage_type: "shadow" +scaling_stat: "intelligence" +scaling_factor: 0.6 +mana_cost: 38 +cooldown: 4 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "rotting_soul" + name: "Soul Rot" + effect_type: "dot" + duration: 4 + power: 15 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "soul_rot" + - effect_id: "healing_reduction" + name: "Corrupted" + effect_type: "debuff" + duration: 4 + power: 50 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "soul_rot" diff --git a/api/app/data/abilities/stampede.yaml b/api/app/data/abilities/stampede.yaml new file mode 100644 index 0000000..d928841 --- /dev/null +++ b/api/app/data/abilities/stampede.yaml @@ -0,0 +1,25 @@ +# Stampede - Wildstrider Beast Companion ultimate +# Summon beast horde AoE + +ability_id: "stampede" +name: "Stampede" +description: "Call upon the spirits of the wild to summon a stampede of beasts that tramples all enemies" +ability_type: "skill" +base_power: 90 +damage_type: "physical" +scaling_stat: "wisdom" +scaling_factor: 0.7 +mana_cost: 60 +cooldown: 6 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "trampled" + name: "Trampled" + effect_type: "debuff" + duration: 2 + power: 30 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "stampede" diff --git a/api/app/data/abilities/summon_abomination.yaml b/api/app/data/abilities/summon_abomination.yaml new file mode 100644 index 0000000..047a444 --- /dev/null +++ b/api/app/data/abilities/summon_abomination.yaml @@ -0,0 +1,25 @@ +# Summon Abomination - Necromancer Raise Dead ability +# Summon powerful abomination + +ability_id: "summon_abomination" +name: "Summon Abomination" +description: "Stitch together corpses to create a powerful abomination" +ability_type: "spell" +base_power: 0 +damage_type: null +scaling_stat: "charisma" +scaling_factor: 0.6 +mana_cost: 45 +cooldown: 0 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "abomination_minion" + name: "Abomination" + effect_type: "buff" + duration: 99 + power: 60 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "summon_abomination" diff --git a/api/app/data/abilities/summon_companion.yaml b/api/app/data/abilities/summon_companion.yaml new file mode 100644 index 0000000..23cb15b --- /dev/null +++ b/api/app/data/abilities/summon_companion.yaml @@ -0,0 +1,25 @@ +# Summon Companion - Wildstrider Beast Companion ability +# Summon animal pet + +ability_id: "summon_companion" +name: "Summon Companion" +description: "Call your loyal animal companion to fight by your side" +ability_type: "skill" +base_power: 0 +damage_type: null +scaling_stat: "wisdom" +scaling_factor: 0.5 +mana_cost: 15 +cooldown: 0 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "companion_active" + name: "Animal Companion" + effect_type: "buff" + duration: 99 + power: 20 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "summon_companion" diff --git a/api/app/data/abilities/summon_skeleton.yaml b/api/app/data/abilities/summon_skeleton.yaml new file mode 100644 index 0000000..4b1868c --- /dev/null +++ b/api/app/data/abilities/summon_skeleton.yaml @@ -0,0 +1,25 @@ +# Summon Skeleton - Necromancer Raise Dead ability +# Summon skeleton warrior + +ability_id: "summon_skeleton" +name: "Summon Skeleton" +description: "Raise a skeleton warrior from the dead to fight for you" +ability_type: "spell" +base_power: 0 +damage_type: null +scaling_stat: "charisma" +scaling_factor: 0.5 +mana_cost: 15 +cooldown: 0 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "skeleton_minion" + name: "Skeleton Warrior" + effect_type: "buff" + duration: 99 + power: 20 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "summon_skeleton" diff --git a/api/app/data/abilities/sun_burst.yaml b/api/app/data/abilities/sun_burst.yaml new file mode 100644 index 0000000..cb2868b --- /dev/null +++ b/api/app/data/abilities/sun_burst.yaml @@ -0,0 +1,25 @@ +# Sun Burst - Arcanist Pyromancy ultimate +# Ultimate fire nuke + +ability_id: "sun_burst" +name: "Sun Burst" +description: "Channel the power of the sun to unleash a devastating explosion of fire on all enemies" +ability_type: "spell" +base_power: 100 +damage_type: "fire" +scaling_stat: "intelligence" +scaling_factor: 0.7 +mana_cost: 65 +cooldown: 5 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "incinerated" + name: "Incinerated" + effect_type: "dot" + duration: 3 + power: 15 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "sun_burst" diff --git a/api/app/data/abilities/taunt.yaml b/api/app/data/abilities/taunt.yaml new file mode 100644 index 0000000..7559e69 --- /dev/null +++ b/api/app/data/abilities/taunt.yaml @@ -0,0 +1,25 @@ +# Taunt - Oathkeeper Aegis of Light ability +# Force enemies to attack you + +ability_id: "taunt" +name: "Taunt" +description: "Force all enemies to focus their attacks on you" +ability_type: "skill" +base_power: 0 +damage_type: null +scaling_stat: "constitution" +scaling_factor: 0.3 +mana_cost: 8 +cooldown: 3 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "taunted" + name: "Taunted" + effect_type: "debuff" + duration: 2 + power: 100 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "taunt" diff --git a/api/app/data/abilities/thousand_cuts.yaml b/api/app/data/abilities/thousand_cuts.yaml new file mode 100644 index 0000000..d7b7f85 --- /dev/null +++ b/api/app/data/abilities/thousand_cuts.yaml @@ -0,0 +1,25 @@ +# Thousand Cuts - Assassin Blade Specialist ultimate +# Multi-hit flurry + +ability_id: "thousand_cuts" +name: "Thousand Cuts" +description: "Unleash a flurry of strikes, each with 50% crit chance" +ability_type: "attack" +base_power: 100 +damage_type: "physical" +scaling_stat: "dexterity" +scaling_factor: 0.7 +mana_cost: 60 +cooldown: 5 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "bleeding_wounds" + name: "Bleeding Wounds" + effect_type: "dot" + duration: 3 + power: 15 + stat_affected: null + stacks: 1 + max_stacks: 5 + source: "thousand_cuts" diff --git a/api/app/data/abilities/time_warp.yaml b/api/app/data/abilities/time_warp.yaml new file mode 100644 index 0000000..4f3c523 --- /dev/null +++ b/api/app/data/abilities/time_warp.yaml @@ -0,0 +1,25 @@ +# Time Warp - Lorekeeper Arcane Weaving ability +# AoE extra actions + +ability_id: "time_warp" +name: "Time Warp" +description: "Bend time itself, granting all allies increased speed" +ability_type: "spell" +base_power: 0 +damage_type: null +scaling_stat: "intelligence" +scaling_factor: 0.5 +mana_cost: 45 +cooldown: 5 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "time_warped" + name: "Time Warped" + effect_type: "buff" + duration: 3 + power: 75 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "time_warp" diff --git a/api/app/data/abilities/titans_wrath.yaml b/api/app/data/abilities/titans_wrath.yaml new file mode 100644 index 0000000..919ebad --- /dev/null +++ b/api/app/data/abilities/titans_wrath.yaml @@ -0,0 +1,25 @@ +# Titan's Wrath - Vanguard Weapon Master ultimate +# Devastating AoE attack with stun + +ability_id: "titans_wrath" +name: "Titan's Wrath" +description: "Unleash a devastating attack that deals 300% weapon damage and stuns all enemies" +ability_type: "attack" +base_power: 100 +damage_type: "physical" +scaling_stat: "strength" +scaling_factor: 0.7 +mana_cost: 60 +cooldown: 5 +is_aoe: true +target_count: 0 +effects_applied: + - effect_id: "titans_stun" + name: "Staggered" + effect_type: "stun" + duration: 1 + power: 0 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "titans_wrath" diff --git a/api/app/data/abilities/unbreakable.yaml b/api/app/data/abilities/unbreakable.yaml new file mode 100644 index 0000000..51f304e --- /dev/null +++ b/api/app/data/abilities/unbreakable.yaml @@ -0,0 +1,25 @@ +# Unbreakable - Vanguard Shield Bearer ultimate +# Massive damage reduction + +ability_id: "unbreakable" +name: "Unbreakable" +description: "Channel your inner strength to become nearly invulnerable, reducing all damage by 75% for 5 turns" +ability_type: "defend" +base_power: 0 +damage_type: null +scaling_stat: "constitution" +scaling_factor: 0.3 +mana_cost: 50 +cooldown: 6 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "unbreakable_buff" + name: "Unbreakable" + effect_type: "buff" + duration: 5 + power: 75 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "unbreakable" diff --git a/api/app/data/abilities/vanish.yaml b/api/app/data/abilities/vanish.yaml new file mode 100644 index 0000000..611dd63 --- /dev/null +++ b/api/app/data/abilities/vanish.yaml @@ -0,0 +1,25 @@ +# Vanish - Assassin Shadow Dancer ability +# Stealth for 2 turns + +ability_id: "vanish" +name: "Vanish" +description: "Disappear into the shadows, becoming invisible for 2 turns and dropping threat" +ability_type: "skill" +base_power: 0 +damage_type: null +scaling_stat: "dexterity" +scaling_factor: 0.3 +mana_cost: 25 +cooldown: 5 +is_aoe: false +target_count: 1 +effects_applied: + - effect_id: "stealth" + name: "Stealthed" + effect_type: "buff" + duration: 2 + power: 100 + stat_affected: null + stacks: 1 + max_stacks: 1 + source: "vanish" diff --git a/api/app/data/abilities/vital_strike.yaml b/api/app/data/abilities/vital_strike.yaml new file mode 100644 index 0000000..6d22d2b --- /dev/null +++ b/api/app/data/abilities/vital_strike.yaml @@ -0,0 +1,16 @@ +# Vital Strike - Assassin Blade Specialist ability +# Massive crit damage + +ability_id: "vital_strike" +name: "Vital Strike" +description: "Strike a vital organ for massive critical damage" +ability_type: "attack" +base_power: 30 +damage_type: "physical" +scaling_stat: "dexterity" +scaling_factor: 0.55 +mana_cost: 18 +cooldown: 2 +is_aoe: false +target_count: 1 +effects_applied: [] diff --git a/api/app/data/abilities/word_of_healing.yaml b/api/app/data/abilities/word_of_healing.yaml new file mode 100644 index 0000000..e50e7d6 --- /dev/null +++ b/api/app/data/abilities/word_of_healing.yaml @@ -0,0 +1,16 @@ +# Word of Healing - Oathkeeper Redemption ability +# AoE heal + +ability_id: "word_of_healing" +name: "Word of Healing" +description: "Speak a word of power that heals all nearby allies" +ability_type: "spell" +base_power: 40 +damage_type: "holy" +scaling_stat: "wisdom" +scaling_factor: 0.55 +mana_cost: 30 +cooldown: 3 +is_aoe: true +target_count: 0 +effects_applied: [] diff --git a/api/app/data/classes/arcanist.yaml b/api/app/data/classes/arcanist.yaml index 248e353..eb82c79 100644 --- a/api/app/data/classes/arcanist.yaml +++ b/api/app/data/classes/arcanist.yaml @@ -21,6 +21,7 @@ base_stats: starting_equipment: - worn_staff - cloth_armor + - health_potion_small starting_abilities: - basic_attack diff --git a/api/app/data/classes/assassin.yaml b/api/app/data/classes/assassin.yaml index f7e4c72..5c93abb 100644 --- a/api/app/data/classes/assassin.yaml +++ b/api/app/data/classes/assassin.yaml @@ -21,6 +21,7 @@ base_stats: starting_equipment: - rusty_dagger - cloth_armor + - health_potion_small starting_abilities: - basic_attack diff --git a/api/app/data/classes/lorekeeper.yaml b/api/app/data/classes/lorekeeper.yaml index 902db69..42647de 100644 --- a/api/app/data/classes/lorekeeper.yaml +++ b/api/app/data/classes/lorekeeper.yaml @@ -21,6 +21,7 @@ base_stats: starting_equipment: - tome - cloth_armor + - health_potion_small starting_abilities: - basic_attack diff --git a/api/app/data/classes/luminary.yaml b/api/app/data/classes/luminary.yaml index 9cabecb..e0ec10b 100644 --- a/api/app/data/classes/luminary.yaml +++ b/api/app/data/classes/luminary.yaml @@ -21,6 +21,7 @@ base_stats: starting_equipment: - rusty_mace - cloth_armor + - health_potion_small starting_abilities: - basic_attack diff --git a/api/app/data/classes/necromancer.yaml b/api/app/data/classes/necromancer.yaml index 1cd31b3..89180b9 100644 --- a/api/app/data/classes/necromancer.yaml +++ b/api/app/data/classes/necromancer.yaml @@ -21,6 +21,7 @@ base_stats: starting_equipment: - bone_wand - cloth_armor + - health_potion_small starting_abilities: - basic_attack diff --git a/api/app/data/classes/oathkeeper.yaml b/api/app/data/classes/oathkeeper.yaml index 5444cd9..ff9e7a9 100644 --- a/api/app/data/classes/oathkeeper.yaml +++ b/api/app/data/classes/oathkeeper.yaml @@ -22,6 +22,7 @@ starting_equipment: - rusty_sword - rusty_shield - cloth_armor + - health_potion_small starting_abilities: - basic_attack diff --git a/api/app/data/classes/vanguard.yaml b/api/app/data/classes/vanguard.yaml index ea84302..79c018b 100644 --- a/api/app/data/classes/vanguard.yaml +++ b/api/app/data/classes/vanguard.yaml @@ -22,6 +22,7 @@ base_stats: starting_equipment: - rusty_sword - cloth_armor + - health_potion_small # Starting abilities starting_abilities: diff --git a/api/app/data/classes/wildstrider.yaml b/api/app/data/classes/wildstrider.yaml index 989bb63..68ccb82 100644 --- a/api/app/data/classes/wildstrider.yaml +++ b/api/app/data/classes/wildstrider.yaml @@ -21,6 +21,7 @@ base_stats: starting_equipment: - rusty_bow - cloth_armor + - health_potion_small starting_abilities: - basic_attack diff --git a/api/docs/SKILLS_AND_ABILITIES.md b/api/docs/SKILLS_AND_ABILITIES.md new file mode 100644 index 0000000..3a47250 --- /dev/null +++ b/api/docs/SKILLS_AND_ABILITIES.md @@ -0,0 +1,479 @@ +# Skills and Abilities System + +## Overview + +The game uses two distinct but interconnected systems for character progression and combat: + +- **Skills**: Progression system that provides passive bonuses and unlocks abilities +- **Abilities**: Combat actions (attacks, spells, skills) that can be used in battle + +**Key Distinction**: Skills are *unlocked through leveling* and provide permanent benefits. Abilities are *combat actions* that characters can execute during battles. + +**⚠️ Terminology Note**: The word "skill" and "spell" have specific meanings in this system. See the [Terminology Clarification](#terminology-clarification) section below for important distinctions between Skills (progression nodes), Abilities (combat actions), Spells (a type of ability), and the confusing `AbilityType.SKILL` enum. + +--- + +## Terminology Clarification + +It's important to understand three distinct concepts that can be confusing due to overlapping names: + +### 1. Skills (Skill Tree Nodes) + +**What**: Nodes in the skill tree progression system that you unlock with skill points earned from leveling up. + +**Where**: Defined in class YAML files at `/api/app/data/classes/*.yaml` + +**Model**: `SkillNode` in [app/models/skills.py](../app/models/skills.py) + +**Purpose**: Provide passive stat bonuses and/or unlock combat abilities + +**Examples**: +- "Shield Bash" skill node (unlocks the Shield Bash ability) +- "Fortify" skill node (grants +5 defense bonus) +- "Fireball Mastery" skill node (unlocks the Fireball ability) + +### 2. Abilities (Combat Actions) + +**What**: Actions you can perform during combat - the umbrella term for all combat actions. + +**Where**: Defined in separate YAML files at `/api/app/data/abilities/*.yaml` + +**Model**: `Ability` in [app/models/abilities.py](../app/models/abilities.py) + +**Purpose**: Define combat mechanics - damage, effects, costs, targeting, etc. + +**Examples**: +- Fireball ability (deals fire damage) +- Shield Bash ability (stuns enemy) +- Heal ability (restores HP) +- Basic Attack ability (default physical attack) + +### 3. Spells (A Type of Ability) + +**What**: A **category** of ability that uses magic/arcane power (not a separate system). + +**Type Field**: `ability_type: "spell"` in the Ability YAML + +**Purpose**: Differentiate magical abilities from physical attacks or special skills + +**Examples**: +- Fireball (ability_type: spell) +- Lightning Bolt (ability_type: spell) +- Heal (ability_type: spell) + +### Ability Types (AbilityType Enum) + +All abilities have an `ability_type` field that categorizes them. From [app/models/enums.py](../app/models/enums.py): + +```python +class AbilityType(Enum): + """Categories of abilities that can be used in combat or exploration.""" + + ATTACK = "attack" # Basic physical attack + SPELL = "spell" # Magical spell (arcane/divine) + SKILL = "skill" # Special class ability (⚠️ different from skill tree!) + ITEM_USE = "item_use" # Using a consumable item + DEFEND = "defend" # Defensive action +``` + +**⚠️ Important Confusion to Avoid**: `AbilityType.SKILL` refers to special class abilities used in combat (like a Rogue's "Sneak Attack"). This is **completely different** from "Skills" in the skill tree progression system (`SkillNode`). + +### Complete Example: Fireball + +To illustrate how all three concepts work together: + +**1. Skill Tree Node** (what you unlock with a skill point): +```yaml +# In /api/app/data/classes/arcanist.yaml +- skill_id: fireball_mastery + name: Fireball Mastery + description: Learn to cast the devastating fireball spell + tier: 1 + prerequisites: [] + effects: + abilities: + - fireball # ← References the ability +``` + +**2. Ability Definition** (the combat action): +```yaml +# In /api/app/data/abilities/fireball.yaml +ability_id: "fireball" +name: "Fireball" +description: "Hurl a ball of fire at your enemies" +ability_type: "spell" # ← This makes it a SPELL-type ability +base_power: 30 +damage_type: "fire" +scaling_stat: "intelligence" +mana_cost: 15 +``` + +**3. The Flow**: +- Player unlocks "Fireball Mastery" **skill** (spends 1 skill point) +- This grants access to the "Fireball" **ability** +- Fireball is categorized as a **spell** (ability_type: spell) +- Player can now use Fireball in combat + +### Summary Table + +| Term | What It Is | Where Defined | Purpose | +|------|------------|---------------|---------| +| **Skill** (SkillNode) | Progression node | `/api/app/data/classes/*.yaml` | Unlock abilities, grant bonuses | +| **Ability** | Combat action | `/api/app/data/abilities/*.yaml` | Define what you can do in battle | +| **Spell** | Type of ability | `ability_type: "spell"` | Magical/arcane combat actions | +| **AbilityType.SKILL** | Type of ability | `ability_type: "skill"` | Special class abilities (⚠️ not skill tree) | + +--- + +## Architecture + +### Skills + +**Purpose**: Character progression and passive bonuses + +**Data Model**: [app/models/skills.py](../app/models/skills.py) +- `SkillNode`: Individual skill in a tree +- `SkillTree`: Collection of related skills +- `PlayerClass`: Character class with multiple skill trees + +**Data Location**: [app/data/classes/*.yaml](../app/data/classes/) +- Skills are embedded within class definitions +- Each class YAML contains 2+ skill trees +- Example: `vanguard.yaml`, `arcanist.yaml` + +**Loader**: [app/services/class_loader.py](../app/services/class_loader.py) +- `ClassLoader` reads class YAML files +- Parses skill trees and nodes during class loading +- Caches PlayerClass instances + +**Storage on Character**: [app/models/character.py](../app/models/character.py) +```python +unlocked_skills: List[str] = field(default_factory=list) # Just skill IDs +``` + +### Abilities + +**Purpose**: Combat actions and spells + +**Data Model**: [app/models/abilities.py](../app/models/abilities.py) +- `Ability`: Complete definition of a combat action +- Includes damage, effects, costs, targeting, etc. + +**Data Location**: [app/data/abilities/*.yaml](../app/data/abilities/) +- Each ability is a separate YAML file +- Example: `fireball.yaml`, `shield_bash.yaml`, `heal.yaml` + +**Loader**: [app/models/abilities.py](../app/models/abilities.py) +- `AbilityLoader` class (lines 164-238) +- Loads abilities on-demand or in bulk +- Caches Ability instances + +**Storage on Character**: Not stored directly +- Character has `player_class.starting_abilities` +- Abilities unlocked through skills are computed dynamically + +--- + +## How Skills Unlock Abilities + +### Skill Effects Dictionary + +Skills can provide multiple types of benefits through their `effects` dictionary: + +```yaml +# From vanguard.yaml +- skill_id: shield_bash + name: Shield Bash + description: Strike an enemy with your shield, dealing minor damage and stunning them + tier: 1 + prerequisites: [] + effects: + abilities: # Unlocks abilities for combat use + - shield_bash # References /app/data/abilities/shield_bash.yaml +``` + +```yaml +# Skills can also provide stat bonuses +- skill_id: fortify + name: Fortify + description: Your defensive training grants you enhanced protection + tier: 1 + prerequisites: [] + effects: + stat_bonuses: + defense: 5 # Passive stat increase +``` + +```yaml +# Or both at once +- skill_id: perfect_form + name: Perfect Form + description: Your combat technique reaches perfection + tier: 5 + prerequisites: + - weapon_mastery + effects: + stat_bonuses: + strength: 20 + dexterity: 10 + combat_bonuses: + crit_chance: 0.1 + crit_multiplier: 0.5 +``` + +### Effect Types + +Skills can define effects in several categories: + +1. **`abilities`**: List of ability IDs to unlock +2. **`stat_bonuses`**: Direct stat increases (strength, defense, etc.) +3. **`combat_bonuses`**: Combat modifiers (crit_chance, crit_multiplier) +4. **`passive_effects`**: Special passive effects (stun_resistance, etc.) +5. **`ability_enhancements`**: Modify existing abilities + +--- + +## Data Flow: Skill Unlock to Ability Usage + +### 1. Character Levels Up + +```python +# Character gains a level and skill point +character.level_up() +# character.level is now higher +# character.available_skill_points increases +``` + +### 2. Player Unlocks a Skill + +```python +# Service validates and unlocks the skill +skill_id = "shield_bash" +character.unlocked_skills.append(skill_id) +# Character saves to database +``` + +### 3. Getting Available Abilities + +```python +# Character.get_unlocked_abilities() - character.py:177-194 +def get_unlocked_abilities(self) -> List[str]: + # Start with class's built-in abilities + abilities = list(self.player_class.starting_abilities) + + # Get all skill nodes from all trees + all_skills = self.player_class.get_all_skills() + + # Collect abilities from unlocked skills + for skill in all_skills: + if skill.skill_id in self.unlocked_skills: + abilities.extend(skill.get_unlocked_abilities()) + + return abilities # Returns list of ability IDs +``` + +### 4. Extracting Abilities from Skills + +```python +# SkillNode.get_unlocked_abilities() - skills.py:73-87 +def get_unlocked_abilities(self) -> List[str]: + abilities = [] + if "abilities" in self.effects: + ability = self.effects["abilities"] + if isinstance(ability, list): + abilities.extend(ability) + else: + abilities.append(ability) + return abilities +``` + +### 5. Loading Ability Details for Combat + +```python +# During combat initialization +ability_loader = AbilityLoader() +ability_ids = character.get_unlocked_abilities() + +# Load full Ability objects +available_abilities = [] +for ability_id in ability_ids: + ability = ability_loader.load_ability(ability_id) + if ability: + available_abilities.append(ability) + +# Now character can use these abilities in combat +``` + +### 6. Using an Ability in Combat + +```python +# Player selects ability +ability = ability_loader.load_ability("fireball") + +# Calculate power with character's stats +effective_stats = character.get_effective_stats() +damage = ability.calculate_power(effective_stats) + +# Apply to target +target.current_hp -= damage + +# Apply effects (DoT, buffs, debuffs) +effects = ability.get_effects_to_apply() +for effect in effects: + target.active_effects.append(effect) +``` + +--- + +## Complete Example: Fireball (Step-by-Step Workflow) + +This example shows the complete journey from skill definition through combat usage. For the YAML definitions, see the [Terminology Clarification](#terminology-clarification) section above. + +### Step 1: Define the Skill (in class YAML) + +See the Fireball Mastery skill node example in the Terminology section. + +### Step 2: Define the Ability (separate YAML) + +See the Fireball ability YAML example in the Terminology section. + +**Key Point**: The skill's `effects.abilities` list contains `fireball`, which references `/api/app/data/abilities/fireball.yaml`. + +### Step 3: Character Progression + +```python +# Character is created as Arcanist +character = Character( + name="Merlin", + player_class=arcanist_class, + level=1, + unlocked_skills=[], # No skills yet +) + +# Starting abilities from class +character.get_unlocked_abilities() # Returns: ["basic_attack"] + +# Character reaches level 2, spends skill point +character.unlocked_skills.append("fireball_skill") + +# Now has fireball ability +character.get_unlocked_abilities() # Returns: ["basic_attack", "fireball"] +``` + +### Step 4: Combat Usage + +```python +# Combat begins +ability_loader = AbilityLoader() +fireball = ability_loader.load_ability("fireball") + +# Character's intelligence is 15 +# Effective stats calculation includes all bonuses +effective_stats = character.get_effective_stats() # intelligence = 15 + +# Calculate damage +damage = fireball.calculate_power(effective_stats) +# damage = 30 + (15 * 0.5) = 30 + 7.5 = 37 + +# Apply to enemy +enemy.current_hp -= 37 + +# Apply burning effect +burn_effect = fireball.get_effects_to_apply()[0] +enemy.active_effects.append(burn_effect) +# Enemy will take 5 fire damage per turn for 3 turns +``` + +--- + +## Skill Bonuses vs Abilities + +### Passive Bonuses + +Skills provide **permanent** stat increases calculated by `Character.get_effective_stats()`: + +```python +# Character._get_skill_bonuses() - character.py:156-175 +def _get_skill_bonuses(self) -> Dict[str, int]: + bonuses: Dict[str, int] = {} + + # Get all skill nodes from all trees + all_skills = self.player_class.get_all_skills() + + # Sum up bonuses from unlocked skills + for skill in all_skills: + if skill.skill_id in self.unlocked_skills: + skill_bonuses = skill.get_stat_bonuses() + for stat_name, bonus in skill_bonuses.items(): + bonuses[stat_name] = bonuses.get(stat_name, 0) + bonus + + return bonuses +``` + +### Extracting Stat Bonuses + +```python +# SkillNode.get_stat_bonuses() - skills.py:57-71 +def get_stat_bonuses(self) -> Dict[str, int]: + bonuses = {} + for key, value in self.effects.items(): + # Look for stat names in effects + if key in ["strength", "dexterity", "constitution", + "intelligence", "wisdom", "charisma"]: + bonuses[key] = value + elif key == "defense" or key == "resistance" or key == "hit_points": + bonuses[key] = value + return bonuses +``` + +**Note**: The current implementation looks for direct stat keys in `effects`. The newer YAML format uses nested `stat_bonuses` dictionaries. This may need updating. + +--- + +## Key Design Principles + +1. **Separation of Concerns** + - Skills = Progression system (what you unlock) + - Abilities = Combat system (what you can do) + +2. **Data-Driven Design** + - Both are defined in YAML files + - Game designers can modify without code changes + - Easy to balance and iterate + +3. **Loose Coupling** + - Skills reference abilities by ID only + - Abilities are loaded on-demand + - Changes to abilities don't affect skill definitions + +4. **Efficient Storage** + - Character only stores skill IDs (not full objects) + - Abilities computed dynamically when needed + - Reduces database payload + +5. **Flexible Effects System** + - Skills can unlock multiple abilities + - Skills can provide stat bonuses + - Skills can do both simultaneously + - Room for future effect types + +--- + +## Related Documentation + +- [DATA_MODELS.md](DATA_MODELS.md) - Character system and items +- [GAME_SYSTEMS.md](GAME_SYSTEMS.md) - Combat mechanics +- [API_REFERENCE.md](API_REFERENCE.md) - API endpoints for skills + +--- + +## Future Enhancements + +Potential improvements to the system: + +1. **Skill Levels**: Allow skills to be upgraded multiple times +2. **Ability Enhancements**: Skills that modify existing abilities +3. **Conditional Unlocks**: Require items, quests, or achievements +4. **Skill Synergies**: Bonuses for unlocking related skills +5. **Respec System**: Allow skill point redistribution +6. **Skill Prerequisites Validation**: Runtime validation of skill trees diff --git a/docs/PHASE4_COMBAT_IMPLEMENTATION.md b/docs/PHASE4_COMBAT_IMPLEMENTATION.md index a5db9ae..14767d3 100644 --- a/docs/PHASE4_COMBAT_IMPLEMENTATION.md +++ b/docs/PHASE4_COMBAT_IMPLEMENTATION.md @@ -729,8 +729,8 @@ app.register_blueprint(combat_bp, url_prefix='/combat') - ✅ Multiple enemies work - would like to update to allow the player to select which enemy to attack - ✅ Combat state persists (refresh page) -- [ ] Spells consume mana - unable to test -- [ ] Items can be used in combat - unable to test +- [ ] Spells consume mana - Need to test +- [ ] Items can be used in combat - Need to test **Bug Fixes & Polish:** - Fix any calculation errors diff --git a/public_web/app/views/character_views.py b/public_web/app/views/character_views.py index 913596e..8b5b63a 100644 --- a/public_web/app/views/character_views.py +++ b/public_web/app/views/character_views.py @@ -714,22 +714,18 @@ def view_skills(character_id: str): api_client = get_api_client() try: - # Get character data + # Get character data (includes full player_class with skill_trees) response = api_client.get(f"/api/v1/characters/{character_id}") character = response.get('result') - # Load class data to get skill trees - class_id = character.get('class_id') - player_class = None - - if class_id: - response = api_client.get(f"/api/v1/classes/{class_id}") - player_class = response.get('result') + # Player class is already embedded in character response + player_class = character.get('player_class') logger.info( "Skill tree viewed", user_id=user.get('id'), - character_id=character_id + character_id=character_id, + class_id=player_class.get('class_id') if player_class else None ) return render_template( @@ -752,3 +748,145 @@ def view_skills(character_id: str): ) flash('An error occurred while loading the skill tree.', 'error') return redirect(url_for('character_views.list_characters')) + + +@character_bp.route('//skills/unlock', methods=['POST']) +@require_auth_web +def unlock_skill(character_id: str): + """ + Unlock a skill for a character (HTMX endpoint). + + Args: + character_id: ID of the character + + Returns: + Re-rendered skills container partial + """ + user = get_current_user() + api_client = get_api_client() + skill_id = request.form.get('skill_id') + + if not skill_id: + return _render_skills_page( + api_client, character_id, user, + error="No skill specified" + ) + + try: + # Call API to unlock skill + api_client.post( + f"/api/v1/characters/{character_id}/skills/unlock", + data={'skill_id': skill_id} + ) + + logger.info( + "Skill unlocked", + user_id=user.get('id'), + character_id=character_id, + skill_id=skill_id + ) + + return _render_skills_page( + api_client, character_id, user, + message=f"Skill unlocked!" + ) + + except APIError as e: + logger.error( + "Failed to unlock skill", + user_id=user.get('id'), + character_id=character_id, + skill_id=skill_id, + error=str(e) + ) + return _render_skills_page( + api_client, character_id, user, + error=str(e.message) if hasattr(e, 'message') else "Failed to unlock skill" + ) + + +@character_bp.route('//skills/respec', methods=['POST']) +@require_auth_web +def respec_skills(character_id: str): + """ + Respec all skills for a character (HTMX endpoint). + + Args: + character_id: ID of the character + + Returns: + Re-rendered skills container partial + """ + user = get_current_user() + api_client = get_api_client() + + try: + # Call API to respec skills + response = api_client.post(f"/api/v1/characters/{character_id}/skills/respec") + result = response.get('result', {}) + + logger.info( + "Skills respec", + user_id=user.get('id'), + character_id=character_id, + cost=result.get('cost') + ) + + return _render_skills_page( + api_client, character_id, user, + message=f"Skills reset! {result.get('available_points', 0)} skill points refunded." + ) + + except APIError as e: + logger.error( + "Failed to respec skills", + user_id=user.get('id'), + character_id=character_id, + error=str(e) + ) + return _render_skills_page( + api_client, character_id, user, + error=str(e.message) if hasattr(e, 'message') else "Failed to respec skills" + ) + + +def _render_skills_page(api_client, character_id: str, user: dict, + message: str = None, error: str = None): + """ + Helper to render the skills container partial for HTMX updates. + + Args: + api_client: API client instance + character_id: Character ID + user: Current user dict + message: Optional success message + error: Optional error message + + Returns: + Rendered skills container HTML (partial, no base template) + """ + try: + # Get fresh character data (includes full player_class with skill_trees) + response = api_client.get(f"/api/v1/characters/{character_id}") + character = response.get('result') + + # Player class is already embedded in character response + player_class = character.get('player_class') + + # Use partial template for HTMX responses (no base.html wrapper) + return render_template( + 'character/partials/skills_container.html', + character=character, + player_class=player_class, + message=message, + error=error + ) + + except APIError as e: + logger.error("Failed to render skills page", error=str(e)) + return render_template( + 'character/partials/skills_container.html', + character={'character_id': character_id, 'name': 'Unknown', 'unlocked_skills': [], 'available_skill_points': 0, 'level': 1, 'gold': 0}, + player_class=None, + error="Failed to load character data" + ) diff --git a/public_web/static/css/skills.css b/public_web/static/css/skills.css new file mode 100644 index 0000000..a5098be --- /dev/null +++ b/public_web/static/css/skills.css @@ -0,0 +1,531 @@ +/** + * Code of Conquest - Skill Tree Stylesheet + * Visual skill tree UI with dual-column layout + */ + +/* ===== SKILL TREE CONTAINER ===== */ +.skills-container { + max-width: 1400px; + margin: 2rem auto; + padding: 2rem; +} + +/* ===== HEADER ===== */ +.skills-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 2rem; + flex-wrap: wrap; + gap: 1rem; +} + +.skills-header h1 { + font-family: var(--font-heading); + font-size: var(--text-3xl); + color: var(--accent-gold); + text-transform: uppercase; + letter-spacing: 2px; + margin: 0; +} + +.skills-info { + display: flex; + align-items: center; + gap: 1.5rem; +} + +.skill-points-display { + background: var(--bg-secondary); + border: 2px solid var(--border-primary); + border-radius: 8px; + padding: 0.75rem 1.5rem; + display: flex; + align-items: center; + gap: 0.5rem; +} + +.skill-points-label { + font-size: var(--text-sm); + color: var(--text-muted); + text-transform: uppercase; + font-weight: 600; +} + +.skill-points-value { + font-size: var(--text-2xl); + color: var(--accent-gold); + font-weight: 700; +} + +.btn-respec { + background: transparent; + border: 2px solid var(--accent-red); + color: var(--accent-red); + padding: 0.75rem 1.5rem; + border-radius: 4px; + cursor: pointer; + font-family: var(--font-body); + font-size: var(--text-sm); + font-weight: 600; + text-transform: uppercase; + transition: all 0.2s ease; +} + +.btn-respec:hover { + background: var(--accent-red); + color: var(--text-primary); +} + +.btn-respec:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +/* ===== BACK LINK ===== */ +.skills-back-link { + margin-bottom: 1rem; +} + +.skills-back-link a { + color: var(--text-secondary); + text-decoration: none; + font-size: var(--text-sm); + transition: color 0.2s ease; +} + +.skills-back-link a:hover { + color: var(--accent-gold); +} + +/* ===== DUAL TREE GRID ===== */ +.skill-trees-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 2rem; +} + +/* ===== INDIVIDUAL SKILL TREE ===== */ +.skill-tree { + background: var(--bg-secondary); + border: 2px solid var(--border-primary); + border-radius: 8px; + padding: 1.5rem; +} + +.tree-header { + margin-bottom: 1.5rem; + padding-bottom: 1rem; + border-bottom: 2px solid var(--border-primary); +} + +.tree-name { + font-family: var(--font-heading); + font-size: var(--text-xl); + color: var(--accent-gold); + text-transform: uppercase; + letter-spacing: 1px; + margin: 0 0 0.5rem 0; +} + +.tree-description { + font-size: var(--text-sm); + color: var(--text-secondary); + margin: 0; + line-height: 1.5; +} + +/* ===== TREE DIAGRAM (TIERS) ===== */ +.tree-diagram { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +/* ===== SKILL TIER ROW ===== */ +.skill-tier { + display: flex; + align-items: center; + gap: 1rem; + padding: 0.75rem 0; + position: relative; +} + +.tier-label { + font-size: var(--text-xs); + color: var(--text-muted); + text-transform: uppercase; + font-weight: 600; + min-width: 50px; + text-align: right; +} + +/* ===== SKILL NODES CONTAINER ===== */ +.skill-nodes { + display: flex; + gap: 1rem; + flex: 1; + justify-content: center; +} + +/* ===== INDIVIDUAL SKILL NODE ===== */ +.skill-node { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + gap: 0.5rem; + padding: 0.75rem; + min-width: 120px; + background: var(--bg-input); + border: 2px solid var(--border-primary); + border-radius: 8px; + cursor: pointer; + transition: all 0.2s ease; +} + +.skill-node:hover { + transform: translateY(-2px); + box-shadow: var(--shadow-md); +} + +/* ===== NODE STATES ===== */ +/* Locked (cannot unlock yet) */ +.skill-node--locked { + opacity: 0.5; + cursor: not-allowed; +} + +.skill-node--locked:hover { + transform: none; + box-shadow: none; +} + +.skill-node--locked .node-icon { + background: var(--bg-tertiary); + border-color: var(--border-primary); + color: var(--text-muted); +} + +/* Available (can unlock) */ +.skill-node--available { + border-color: var(--accent-blue); + box-shadow: 0 0 10px rgba(52, 152, 219, 0.3); +} + +.skill-node--available .node-icon { + background: var(--bg-input); + border-color: var(--accent-blue); + color: var(--accent-blue); +} + +.skill-node--available:hover { + border-color: var(--accent-gold); + box-shadow: 0 0 15px rgba(243, 156, 18, 0.4); +} + +/* Unlocked (already acquired) */ +.skill-node--unlocked { + border-color: var(--accent-green); +} + +.skill-node--unlocked .node-icon { + background: var(--accent-green); + border-color: var(--accent-green); + color: var(--text-primary); +} + +/* ===== NODE ICON ===== */ +.node-icon { + width: 40px; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + border: 2px solid var(--border-primary); + border-radius: 50%; + font-size: var(--text-lg); + font-weight: 700; + background: var(--bg-tertiary); + transition: all 0.2s ease; +} + +/* ===== NODE NAME ===== */ +.node-name { + font-size: var(--text-xs); + color: var(--text-primary); + text-align: center; + font-weight: 600; + line-height: 1.3; + max-width: 100px; +} + +/* ===== UNLOCK BUTTON ===== */ +.btn-unlock { + position: absolute; + bottom: -10px; + left: 50%; + transform: translateX(-50%); + background: var(--accent-gold); + border: none; + border-radius: 4px; + padding: 0.25rem 0.75rem; + font-size: var(--text-xs); + font-weight: 600; + color: var(--bg-tertiary); + cursor: pointer; + transition: all 0.2s ease; + white-space: nowrap; + z-index: 10; +} + +.btn-unlock:hover { + background: var(--accent-gold-hover); + transform: translateX(-50%) scale(1.05); +} + +/* ===== PREREQUISITE LINES ===== */ +/* Vertical line from node to previous tier */ +.skill-node--has-prereq::before { + content: ''; + position: absolute; + top: -20px; + left: 50%; + transform: translateX(-50%); + width: 2px; + height: 20px; + background: var(--border-primary); +} + +.skill-node--unlocked.skill-node--has-prereq::before, +.skill-node--available.skill-node--has-prereq::before { + background: var(--accent-green); +} + +/* ===== LEGEND ===== */ +.skills-legend { + display: flex; + justify-content: center; + gap: 2rem; + margin-top: 2rem; + padding: 1rem; + background: var(--bg-secondary); + border: 1px solid var(--border-primary); + border-radius: 4px; +} + +.legend-item { + display: flex; + align-items: center; + gap: 0.5rem; + font-size: var(--text-sm); + color: var(--text-secondary); +} + +.legend-icon { + width: 24px; + height: 24px; + display: flex; + align-items: center; + justify-content: center; + border: 2px solid var(--border-primary); + border-radius: 50%; + font-size: var(--text-xs); +} + +.legend-icon--unlocked { + background: var(--accent-green); + border-color: var(--accent-green); + color: var(--text-primary); +} + +.legend-icon--available { + border-color: var(--accent-blue); + color: var(--accent-blue); +} + +.legend-icon--locked { + background: var(--bg-tertiary); + color: var(--text-muted); + opacity: 0.5; +} + +/* ===== TOOLTIP ===== */ +.skill-tooltip { + position: fixed; + z-index: 1000; + background: var(--bg-tertiary); + border: 2px solid var(--border-ornate); + border-radius: 8px; + padding: 1rem; + max-width: 300px; + box-shadow: var(--shadow-lg); + pointer-events: none; + opacity: 0; + transition: opacity 0.2s ease; +} + +.skill-tooltip.visible { + opacity: 1; +} + +.tooltip-header { + margin-bottom: 0.75rem; + padding-bottom: 0.5rem; + border-bottom: 1px solid var(--border-primary); +} + +.tooltip-name { + font-family: var(--font-heading); + font-size: var(--text-lg); + color: var(--accent-gold); + margin: 0 0 0.25rem 0; +} + +.tooltip-tier { + font-size: var(--text-xs); + color: var(--text-muted); + text-transform: uppercase; +} + +.tooltip-description { + font-size: var(--text-sm); + color: var(--text-secondary); + line-height: 1.5; + margin-bottom: 0.75rem; +} + +.tooltip-section { + margin-bottom: 0.75rem; +} + +.tooltip-section:last-child { + margin-bottom: 0; +} + +.tooltip-section-title { + font-size: var(--text-xs); + color: var(--accent-gold); + text-transform: uppercase; + font-weight: 600; + margin-bottom: 0.25rem; +} + +.tooltip-bonuses { + list-style: none; + padding: 0; + margin: 0; +} + +.tooltip-bonuses li { + font-size: var(--text-sm); + color: var(--accent-green); + padding: 0.125rem 0; +} + +.tooltip-bonuses li::before { + content: '+ '; +} + +.tooltip-prerequisite { + font-size: var(--text-sm); + color: var(--accent-red-light); +} + +.tooltip-abilities { + list-style: none; + padding: 0; + margin: 0; +} + +.tooltip-abilities li { + font-size: var(--text-sm); + color: var(--accent-blue); + padding: 0.125rem 0; +} + +/* ===== MESSAGES ===== */ +.skills-message { + padding: 1rem; + border-radius: 4px; + margin-bottom: 1rem; + text-align: center; +} + +.skills-message--success { + background: rgba(39, 174, 96, 0.2); + border: 1px solid var(--accent-green); + color: var(--accent-green); +} + +.skills-message--error { + background: rgba(192, 57, 43, 0.2); + border: 1px solid var(--accent-red); + color: var(--accent-red-light); +} + +/* ===== RESPONSIVE ===== */ +@media (max-width: 1024px) { + .skill-trees-grid { + grid-template-columns: 1fr; + } + + .skills-header { + flex-direction: column; + align-items: flex-start; + } + + .skills-info { + width: 100%; + justify-content: space-between; + } +} + +@media (max-width: 768px) { + .skills-container { + padding: 1rem; + } + + .skill-tree { + padding: 1rem; + } + + .skill-nodes { + flex-direction: column; + align-items: center; + } + + .skill-node { + min-width: 100%; + max-width: 200px; + } + + .tier-label { + display: none; + } + + .skills-legend { + flex-wrap: wrap; + gap: 1rem; + } +} + +@media (max-width: 480px) { + .skills-header h1 { + font-size: var(--text-xl); + } + + .skills-info { + flex-direction: column; + gap: 0.75rem; + } + + .skill-points-display { + width: 100%; + justify-content: center; + } + + .btn-respec { + width: 100%; + } +} diff --git a/public_web/templates/character/partials/skills_container.html b/public_web/templates/character/partials/skills_container.html new file mode 100644 index 0000000..d6ab85f --- /dev/null +++ b/public_web/templates/character/partials/skills_container.html @@ -0,0 +1,127 @@ +{# Skills Container Partial - For HTMX updates #} +{# Calculate available skill points: level minus unlocked skills count #} +{% set skill_points = character.available_skill_points|default(character.level - (character.unlocked_skills|default([])|length), true) %} + +
+ {# Back Link #} + + + {# Header #} +
+

{{ character.name }}'s Skill Trees

+
+
+ Skill Points: + {{ skill_points }} +
+ {% set respec_cost = character.level * 100 %} + +
+
+ + {# Flash Messages #} + {% if message %} +
{{ message }}
+ {% endif %} + {% if error %} +
{{ error }}
+ {% endif %} + + {# Skill Trees Grid #} + {% if player_class and player_class.skill_trees %} +
+ {% for tree in player_class.skill_trees %} +
+ {# Tree Header #} +
+

{{ tree.name }}

+

{{ tree.description }}

+
+ + {# Tree Diagram (Tiers 5 to 1, top to bottom) #} +
+ {% for tier in range(5, 0, -1) %} +
+ Tier {{ tier }} +
+ {% for node in tree.nodes if node.tier == tier %} + {# Determine node state #} + {% set is_unlocked = node.skill_id in character.unlocked_skills %} + {% set prereqs_met = not node.prerequisites or (node.prerequisites | select('in', character.unlocked_skills) | list | length == node.prerequisites | length) %} + {% set has_lower_tier = tier == 1 or (tree.nodes | selectattr('tier', 'equalto', tier - 1) | selectattr('skill_id', 'in', character.unlocked_skills) | list | length > 0) %} + {% set can_unlock = not is_unlocked and prereqs_met and has_lower_tier and skill_points > 0 %} + {% set has_prereq = node.prerequisites | length > 0 %} + +
+ +
+ {% if is_unlocked %} + ✓ + {% elif can_unlock %} + ◇ + {% else %} + ◆ + {% endif %} +
+ + {{ node.name }} + + {% if can_unlock %} + + {% endif %} +
+ {% endfor %} +
+
+ {% endfor %} +
+
+ {% endfor %} +
+ + {# Legend #} +
+
+ + Unlocked +
+
+ + Available +
+
+ + Locked +
+
+ {% else %} +
+ Unable to load skill trees for this class. +
+ {% endif %} + + {# Tooltip Container #} +
+
diff --git a/public_web/templates/character/skills.html b/public_web/templates/character/skills.html new file mode 100644 index 0000000..1ae878b --- /dev/null +++ b/public_web/templates/character/skills.html @@ -0,0 +1,151 @@ +{% extends "base.html" %} + +{% block title %}Skill Trees - {{ character.name }} - Code of Conquest{% endblock %} + +{% block extra_head %} + +{% endblock %} + +{% block content %} +{% include "character/partials/skills_container.html" %} + +{# Embed skill data as JSON for tooltips #} + +{% endblock %} diff --git a/public_web/templates/game/partials/character_panel.html b/public_web/templates/game/partials/character_panel.html index 1564bea..d0fae69 100644 --- a/public_web/templates/game/partials/character_panel.html +++ b/public_web/templates/game/partials/character_panel.html @@ -82,7 +82,7 @@ Displays character stats, resource bars, and action buttons - {# Quick Actions (Inventory, Equipment, NPC, Travel) #} + {# Quick Actions (Inventory, Equipment, Skills, NPC, Travel) #}