Files
echoes-of-the-ash/bot/status_utils.py
2025-11-07 15:27:13 +01:00

120 lines
3.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Status effect utilities for display and management.
"""
from collections import defaultdict
def stack_status_effects(effects: list) -> dict:
"""
Stack status effects by name, summing damage and counting stacks.
Args:
effects: List of dicts with keys: effect_name, effect_icon, damage_per_tick, ticks_remaining
Returns:
Dict with keys: effect_name -> {icon, total_damage, stacks, min_ticks, effects: [list of effect dicts]}
"""
stacked = defaultdict(lambda: {
'icon': '',
'total_damage': 0,
'stacks': 0,
'min_ticks': float('inf'),
'max_ticks': 0,
'effects': []
})
for effect in effects:
name = effect['effect_name']
stacked[name]['icon'] = effect['effect_icon']
stacked[name]['total_damage'] += effect.get('damage_per_tick', 0)
stacked[name]['stacks'] += 1
stacked[name]['min_ticks'] = min(stacked[name]['min_ticks'], effect['ticks_remaining'])
stacked[name]['max_ticks'] = max(stacked[name]['max_ticks'], effect['ticks_remaining'])
stacked[name]['effects'].append(effect)
return dict(stacked)
def get_status_summary(effects: list, in_combat: bool = False) -> str:
"""
Generate compact status summary for display in menus.
Args:
effects: List of status effect dicts
in_combat: If True, show "turns" instead of "cycles"
Returns:
String like "Statuses: 🩸 (-4), ☣️ (-3)" or empty string if no effects
"""
if not effects:
return ""
stacked = stack_status_effects(effects)
if not stacked:
return ""
parts = []
for name, data in stacked.items():
if data['total_damage'] > 0:
parts.append(f"{data['icon']} (-{data['total_damage']})")
else:
parts.append(f"{data['icon']}")
return "Statuses: " + ", ".join(parts)
def get_status_details(effects: list, in_combat: bool = False) -> str:
"""
Generate detailed status display for profile menu.
Args:
effects: List of status effect dicts
in_combat: If True, show "turns" instead of "cycles"
Returns:
Multi-line string with detailed effect info
"""
if not effects:
return "No active status effects."
stacked = stack_status_effects(effects)
lines = []
for name, data in stacked.items():
# Build effect line
effect_line = f"{data['icon']} {name.replace('_', ' ').title()}"
# Add damage info
if data['total_damage'] > 0:
effect_line += f": -{data['total_damage']} HP/{'turn' if in_combat else 'cycle'}"
# Add tick info
if data['stacks'] == 1:
tick_unit = 'turn' if in_combat else 'cycle'
tick_count = data['min_ticks']
effect_line += f" ({tick_count} {tick_unit}{'s' if tick_count != 1 else ''} left)"
else:
tick_unit = 'turns' if in_combat else 'cycles'
if data['min_ticks'] == data['max_ticks']:
effect_line += f" (×{data['stacks']}, {data['min_ticks']} {tick_unit} left)"
else:
effect_line += f" (×{data['stacks']}, {data['min_ticks']}-{data['max_ticks']} {tick_unit} left)"
lines.append(effect_line)
return "\n".join(lines)
def calculate_status_damage(effects: list) -> int:
"""
Calculate total damage from all status effects.
Args:
effects: List of status effect dicts
Returns:
Total damage per tick
"""
return sum(effect.get('damage_per_tick', 0) for effect in effects)