feat: add total skill gained tracking to HUD

- Add show_skills config option to HUDConfig
- Add total_skill_gained and skill_gains fields to HUDStats
- Add skills display section in HUD UI (purple box)
- Add update_skill() method to track skill gains
- Update on_skill handler in main_window.py to call update_skill()
- Add skills checkbox to HUD settings dialog
- Fix duplicate code in _refresh_display method
- Update to_dict/from_dict for skills config persistence
This commit is contained in:
LemonNexus 2026-02-10 14:19:56 +00:00
parent ecf27a504c
commit b14888dc97
2 changed files with 52 additions and 23 deletions

View File

@ -48,6 +48,7 @@ class HUDConfig:
show_cost_metrics: bool = True # Cost per shot/hit/heal show_cost_metrics: bool = True # Cost per shot/hit/heal
show_shrapnel: bool = False # Deprecated - now integrated in loot summary show_shrapnel: bool = False # Deprecated - now integrated in loot summary
show_gear_info: bool = True show_gear_info: bool = True
show_skills: bool = False # NEW: Total skill gained
compact_mode: bool = False compact_mode: bool = False
@ -62,6 +63,7 @@ class HUDConfig:
'show_damage_stats': self.show_damage_stats, 'show_damage_stats': self.show_damage_stats,
'show_cost_metrics': self.show_cost_metrics, 'show_cost_metrics': self.show_cost_metrics,
'show_gear_info': self.show_gear_info, 'show_gear_info': self.show_gear_info,
'show_skills': self.show_skills,
'compact_mode': self.compact_mode, 'compact_mode': self.compact_mode,
} }
@ -77,6 +79,7 @@ class HUDConfig:
show_damage_stats=data.get('show_damage_stats', False), show_damage_stats=data.get('show_damage_stats', False),
show_cost_metrics=data.get('show_cost_metrics', True), show_cost_metrics=data.get('show_cost_metrics', True),
show_gear_info=data.get('show_gear_info', True), show_gear_info=data.get('show_gear_info', True),
show_skills=data.get('show_skills', False),
compact_mode=data.get('compact_mode', False), compact_mode=data.get('compact_mode', False),
) )
@ -129,6 +132,10 @@ class HUDStats:
current_fap: str = "None" current_fap: str = "None"
current_loadout: str = "None" current_loadout: str = "None"
# Skills (NEW)
total_skill_gained: Decimal = Decimal('0.0') # Total of all skill gains
skill_gains: Dict[str, Decimal] = field(default_factory=dict) # Per-skill tracking
def recalculate(self): def recalculate(self):
"""Recalculate derived values.""" """Recalculate derived values."""
# Total loot is shrapnel + other loot # Total loot is shrapnel + other loot
@ -229,6 +236,10 @@ class HUDSettingsDialog(QDialog):
self.cb_damage.setChecked(self.config.show_damage_stats) self.cb_damage.setChecked(self.config.show_damage_stats)
form.addRow(self.cb_damage) form.addRow(self.cb_damage)
self.cb_skills = QCheckBox("Total Skills Gained")
self.cb_skills.setChecked(self.config.show_skills)
form.addRow(self.cb_skills)
# Display mode # Display mode
form.addRow(QLabel("<b>Display Mode</b>")) form.addRow(QLabel("<b>Display Mode</b>"))
@ -263,6 +274,7 @@ class HUDSettingsDialog(QDialog):
self.config.show_cost_breakdown = self.cb_cost_breakdown.isChecked() self.config.show_cost_breakdown = self.cb_cost_breakdown.isChecked()
self.config.show_combat_stats = self.cb_combat.isChecked() self.config.show_combat_stats = self.cb_combat.isChecked()
self.config.show_damage_stats = self.cb_damage.isChecked() self.config.show_damage_stats = self.cb_damage.isChecked()
self.config.show_skills = self.cb_skills.isChecked()
self.config.compact_mode = self.cb_compact.isChecked() self.config.compact_mode = self.cb_compact.isChecked()
self.accept() self.accept()
@ -578,6 +590,20 @@ class HUDOverlay(QWidget):
layout.addWidget(damage_box) layout.addWidget(damage_box)
# === SKILLS (if enabled) ===
if self.hud_config.show_skills:
skills_box = QFrame()
skills_box.setStyleSheet("background-color: rgba(100, 50, 150, 80); border: 1px solid rgba(200, 150, 255, 50); border-radius: 4px;")
skills_layout = QHBoxLayout(skills_box)
skills_layout.setContentsMargins(8, 4, 8, 4)
self.skills_label = QLabel("Skills: 0.00")
self.skills_label.setStyleSheet("font-size: 11px; color: #DDA0DD;")
skills_layout.addWidget(self.skills_label)
skills_layout.addStretch()
layout.addWidget(skills_box)
# Separator before footer # Separator before footer
sep_footer = QFrame() sep_footer = QFrame()
sep_footer.setFrameShape(QFrame.Shape.HLine) sep_footer.setFrameShape(QFrame.Shape.HLine)
@ -641,6 +667,8 @@ class HUDOverlay(QWidget):
height += 25 height += 25
if self.hud_config.show_damage_stats: if self.hud_config.show_damage_stats:
height += 25 height += 25
if self.hud_config.show_skills:
height += 25
if self.hud_config.show_session_time: if self.hud_config.show_session_time:
height += 20 height += 20
@ -809,31 +837,12 @@ class HUDOverlay(QWidget):
# Damage stats # Damage stats
self._safe_set_text('damage_dealt_label', f"Dealt: {int(self._stats.damage_dealt)}") self._safe_set_text('damage_dealt_label', f"Dealt: {int(self._stats.damage_dealt)}")
self._safe_set_text('damage_taken_label', f"Taken: {int(self._stats.damage_taken)}") self._safe_set_text('damage_taken_label', f"Taken: {int(self._stats.damage_taken)}")
# Skills
if hasattr(self, 'skills_label'):
self._safe_set_text('skills_label', f"Skills: {self._stats.total_skill_gained:.2f}")
except Exception as e: except Exception as e:
logger.error(f"Error in _refresh_display: {e}") logger.error(f"Error in _refresh_display: {e}")
self._safe_set_text('cps_label', f"Shot: {self._stats.cost_per_shot:.4f}")
self._safe_set_text('cph_label', f"Hit: {self._stats.cost_per_hit:.4f}")
self._safe_set_text('cphl_label', f"Heal: {self._stats.cost_per_heal:.4f}")
# Gear
self._safe_set_text('weapon_label', f"W: {self._stats.current_weapon[:20]}")
self._safe_set_text('armor_label', f"A: {self._stats.current_armor[:20]}")
self._safe_set_text('loadout_label', f"L: {self._stats.current_loadout[:20]}")
# Cost breakdown
self._safe_set_text('wep_cost_label', f"{self._stats.weapon_cost_total:.2f}")
self._safe_set_text('arm_cost_label', f"{self._stats.armor_cost_total:.2f}")
self._safe_set_text('heal_cost_label', f"{self._stats.healing_cost_total:.2f}")
# Combat
self._safe_set_text('kills_label', f"Kills: {self._stats.kills}")
self._safe_set_text('globals_label', f"Globals: {self._stats.globals_count}")
# Damage stats
self._safe_set_text('damage_dealt_label', f"Dealt: {int(self._stats.damage_dealt)}")
self._safe_set_text('damage_taken_label', f"Taken: {int(self._stats.damage_taken)}")
# Shrapnel (in summary section now - already updated above)
# === Public Update Methods === # === Public Update Methods ===
@ -909,6 +918,18 @@ class HUDOverlay(QWidget):
self._stats.kills += count self._stats.kills += count
self._refresh_display() self._refresh_display()
def update_skill(self, skill_name: str, amount: Decimal):
"""Update skill gain tracking."""
logger.debug(f"[HUD] update_skill called: skill={skill_name}, amount={amount}")
if self.session_active:
# Track per-skill gains
if skill_name not in self._stats.skill_gains:
self._stats.skill_gains[skill_name] = Decimal('0.0')
self._stats.skill_gains[skill_name] += amount
# Update total
self._stats.total_skill_gained += amount
self._refresh_display()
def update_globals(self): def update_globals(self):
"""Update global count.""" """Update global count."""
if self.session_active: if self.session_active:

View File

@ -1137,10 +1137,18 @@ class MainWindow(QMainWindow):
def on_skill(event): def on_skill(event):
"""Handle skill events.""" """Handle skill events."""
from decimal import Decimal
skill_name = event.data.get('skill_name', 'Unknown') skill_name = event.data.get('skill_name', 'Unknown')
gained = event.data.get('gained', 0) gained = event.data.get('gained', 0)
self.log_info("Skill", f"{skill_name} +{gained}") self.log_info("Skill", f"{skill_name} +{gained}")
# Update HUD skill tracking
try:
gained_decimal = Decimal(str(gained))
self.hud.update_skill(skill_name, gained_decimal)
except Exception as e:
logger.error(f"[ERROR] Error updating HUD skill: {e}")
def on_damage_dealt(event): def on_damage_dealt(event):
"""Handle damage dealt - track damage stats and weapon cost.""" """Handle damage dealt - track damage stats and weapon cost."""
from decimal import Decimal from decimal import Decimal