Refactor: unified combat engine for PvE/PvP
- Create api/services/combat_engine.py with all shared combat logic - Rewrite combat.py from 2820 to ~600 lines (thin orchestration) - Fix buff consumption: fortify, berserker_rage, evade, foresight, iron_skin now actually work - Fix stun: PvE skills now write stun to npc_status_effects - Fix skill damage: now uses stats.attack_power consistently (includes perks) - Fix PvPCombatActionRequest: add skill_id field for proper PvP skill support - Remove dead code: PvP skill/item blocks copy-pasted into PvE endpoint - Update game_logic.npc_attack to check buff modifiers (dodge, damage reduction, etc.)
This commit is contained in:
@@ -810,17 +810,58 @@ async def npc_attack(player_id: int, combat: dict, npc_def, reduce_armor_func, p
|
||||
))
|
||||
# Remove defending effect after use
|
||||
await db.remove_effect(player_id, 'defending')
|
||||
|
||||
# ── Check buff-based damage reduction (fortify) ──
|
||||
buff_dmg_reduction = 0.0
|
||||
if player_stats:
|
||||
buff_dmg_reduction = player_stats.get('buff_damage_reduction', 0.0)
|
||||
if buff_dmg_reduction > 0:
|
||||
npc_damage = max(1, int(npc_damage * (1 - buff_dmg_reduction)))
|
||||
messages.append(create_combat_message(
|
||||
"damage_reduced",
|
||||
origin="player",
|
||||
reduction=int(buff_dmg_reduction * 100)
|
||||
))
|
||||
|
||||
# ── Check berserker rage increased damage taken ──
|
||||
buff_dmg_taken_increase = 0.0
|
||||
if player_stats:
|
||||
buff_dmg_taken_increase = player_stats.get('buff_damage_taken_increase', 0.0)
|
||||
if buff_dmg_taken_increase > 0:
|
||||
npc_damage = int(npc_damage * (1 + buff_dmg_taken_increase))
|
||||
|
||||
# Check for dodge
|
||||
# ── Check guaranteed dodge from Evade buff ──
|
||||
dodged = False
|
||||
if player_stats and 'dodge_chance' in player_stats:
|
||||
if player_stats and player_stats.get('buff_guaranteed_dodge', False):
|
||||
dodged = True
|
||||
messages.append(create_combat_message(
|
||||
"combat_dodge",
|
||||
origin="player"
|
||||
))
|
||||
actual_damage = 0
|
||||
new_player_hp = player['hp']
|
||||
# Consume the evade buff
|
||||
await db.remove_effect(player_id, 'evade')
|
||||
|
||||
# ── Check Foresight buff (enemy misses) ──
|
||||
if not dodged and player_stats and player_stats.get('buff_enemy_miss', False):
|
||||
dodged = True
|
||||
messages.append(create_combat_message(
|
||||
"combat_dodge",
|
||||
origin="player"
|
||||
))
|
||||
actual_damage = 0
|
||||
new_player_hp = player['hp']
|
||||
# Foresight ticks down naturally via db.tick_player_effects
|
||||
|
||||
# Check for regular dodge (stat-based)
|
||||
if not dodged and player_stats and 'dodge_chance' in player_stats:
|
||||
if random.random() < player_stats['dodge_chance']:
|
||||
dodged = True
|
||||
messages.append(create_combat_message(
|
||||
"combat_dodge",
|
||||
origin="player"
|
||||
))
|
||||
# Prevent damage calculation
|
||||
actual_damage = 0
|
||||
new_player_hp = player['hp']
|
||||
|
||||
@@ -833,7 +874,6 @@ async def npc_attack(player_id: int, combat: dict, npc_def, reduce_armor_func, p
|
||||
"combat_block",
|
||||
origin="player"
|
||||
))
|
||||
# Apply blocked effect (damage reduced significantly or nullified)
|
||||
npc_damage = max(1, int(npc_damage * 0.2)) # Block mitigates 80% damage
|
||||
|
||||
if not dodged:
|
||||
@@ -844,7 +884,6 @@ async def npc_attack(player_id: int, combat: dict, npc_def, reduce_armor_func, p
|
||||
if player_stats and player_stats.get('armor_reduction', 0) > 0:
|
||||
pct_reduction = player_stats['armor_reduction']
|
||||
actual_damage = max(1, int(npc_damage * (1 - pct_reduction)))
|
||||
# Still show "armor_absorbed" conceptually for UI logs, though it's % based now
|
||||
armor_absorbed_visual = npc_damage - actual_damage
|
||||
else:
|
||||
actual_damage = max(1, npc_damage - armor_absorbed)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1213
api/services/combat_engine.py
Normal file
1213
api/services/combat_engine.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -89,12 +89,13 @@ class PvPCombatInitiateRequest(BaseModel):
|
||||
|
||||
|
||||
class PvPAcknowledgeRequest(BaseModel):
|
||||
pass # No body needed
|
||||
combat_id: int
|
||||
|
||||
|
||||
class PvPCombatActionRequest(BaseModel):
|
||||
action: str # 'attack', 'defend', 'flee', 'use_item'
|
||||
action: str # 'attack', 'skill', 'flee', 'use_item'
|
||||
item_id: Optional[str] = None # For use_item action
|
||||
skill_id: Optional[str] = None # For skill action
|
||||
|
||||
|
||||
# ============================================================================
|
||||
|
||||
Reference in New Issue
Block a user