""" Hunting Session Tracker for Lemontropia Suite Complete session tracking with cost, loot, and profit/loss calculations. """ from decimal import Decimal from datetime import datetime, timedelta from dataclasses import dataclass, field from typing import Dict, List, Optional, Any import json import logging import sys from pathlib import Path # Add parent to path for standalone testing if __name__ == "__main__": sys.path.insert(0, str(Path(__file__).parent.parent)) try: from core.healing_tools import HealingTool, get_healing_tool from core.armor_decay import calculate_armor_decay, get_armor_durability except ImportError: # Fallback for standalone testing def calculate_armor_decay(damage, durability): durability_factor = Decimal(1) - Decimal(durability) / Decimal(100000) decay_pec = damage * Decimal("0.05") * durability_factor return decay_pec / Decimal(100) logger = logging.getLogger(__name__) @dataclass class HuntingSession: """Complete hunting session tracking.""" # Session identification session_id: str project_id: int start_time: datetime end_time: Optional[datetime] = None # Gear configuration weapon_name: str = "Unknown" weapon_damage: Decimal = Decimal('0') weapon_decay_pec: Decimal = Decimal('0') weapon_ammo_burn: Decimal = Decimal('0') armor_name: str = "Unknown" armor_durability: int = 2000 medical_tool_name: str = "None" medical_tool_decay_pec: Decimal = Decimal('0') # Combat statistics shots_fired: int = 0 damage_dealt: Decimal = Decimal('0') damage_taken: Decimal = Decimal('0') kills: int = 0 # Healing statistics heals_performed: int = 0 health_healed: Decimal = Decimal('0') # Loot tracking loot_events: List[Dict[str, Any]] = field(default_factory=list) total_loot_value: Decimal = Decimal('0') shrapnel_value: Decimal = Decimal('0') universal_ammo_value: Decimal = Decimal('0') other_loot_value: Decimal = Decimal('0') # Special events globals_count: int = 0 hofs_count: int = 0 personal_globals: List[Dict] = field(default_factory=list) # Cost tracking (calculated) _weapon_cost: Decimal = field(default=Decimal('0'), repr=False) _armor_cost: Decimal = field(default=Decimal('0'), repr=False) _healing_cost: Decimal = field(default=Decimal('0'), repr=False) _plate_cost: Decimal = field(default=Decimal('0'), repr=False) def add_shot(self): """Record a weapon shot.""" self.shots_fired += 1 self._recalculate_weapon_cost() def add_damage_dealt(self, damage: Decimal): """Record damage dealt to creatures.""" self.damage_dealt += damage def add_damage_taken(self, damage: Decimal): """Record damage taken from creatures.""" self.damage_taken += damage self._recalculate_armor_cost() def add_heal(self, amount: Decimal): """Record a healing action.""" self.heals_performed += 1 self.health_healed += amount self._recalculate_healing_cost() def add_kill(self): """Record a creature kill.""" self.kills += 1 def add_loot(self, item_name: str, quantity: int, value_ped: Decimal, is_shrapnel: bool = False, is_universal_ammo: bool = False): """Record loot received.""" loot_event = { 'timestamp': datetime.now().isoformat(), 'item': item_name, 'quantity': quantity, 'value': str(value_ped), 'is_shrapnel': is_shrapnel, 'is_universal_ammo': is_universal_ammo } self.loot_events.append(loot_event) if is_shrapnel: self.shrapnel_value += value_ped elif is_universal_ammo: self.universal_ammo_value += value_ped else: self.other_loot_value += value_ped self.total_loot_value += value_ped def add_global(self, is_hof: bool = False, value_ped: Decimal = Decimal('0')): """Record a global or HOF.""" if is_hof: self.hofs_count += 1 else: self.globals_count += 1 self.personal_globals.append({ 'timestamp': datetime.now().isoformat(), 'is_hof': is_hof, 'value': str(value_ped) }) def _recalculate_weapon_cost(self): """Calculate weapon cost based on shots fired.""" # Cost per shot = (decay + ammo_cost) / 100 (convert to PED) ammo_cost_pec = self.weapon_ammo_burn * Decimal('0.01') # 1 ammo = 0.01 PEC cost_per_shot = (self.weapon_decay_pec + ammo_cost_pec) / Decimal('100') self._weapon_cost = cost_per_shot * self.shots_fired def _recalculate_armor_cost(self): """Calculate armor cost based on damage taken.""" # Using official decay formula self._armor_cost = calculate_armor_decay(self.damage_taken, self.armor_durability) def _recalculate_healing_cost(self): """Calculate healing cost based on heals performed.""" self._healing_cost = (self.medical_tool_decay_pec * self.heals_performed) / Decimal('100') @property def total_cost(self) -> Decimal: """Get total hunting cost (PED).""" return self._weapon_cost + self._armor_cost + self._healing_cost + self._plate_cost @property def profit_loss(self) -> Decimal: """Calculate profit/loss (PED) - excludes shrapnel/UA.""" return self.total_loot_value - self.total_cost @property def return_percentage(self) -> Decimal: """Calculate return percentage (loot/cost * 100).""" if self.total_cost > 0: return (self.total_loot_value / self.total_cost) * Decimal('100') return Decimal('0') @property def cost_per_kill(self) -> Decimal: """Calculate cost per kill.""" if self.kills > 0: return self.total_cost / self.kills return Decimal('0') @property def session_duration(self) -> timedelta: """Get session duration.""" end = self.end_time or datetime.now() return end - self.start_time @property def cost_per_hour(self) -> Decimal: """Calculate cost per hour.""" hours = self.session_duration.total_seconds() / 3600 if hours > 0: return self.total_cost / Decimal(str(hours)) return Decimal('0') @property def loot_per_hour(self) -> Decimal: """Calculate loot value per hour.""" hours = self.session_duration.total_seconds() / 3600 if hours > 0: return self.total_loot_value / Decimal(str(hours)) return Decimal('0') def get_summary(self) -> Dict[str, Any]: """Get session summary as dictionary.""" return { 'session_id': self.session_id, 'duration_minutes': self.session_duration.total_seconds() / 60, 'weapon': self.weapon_name, 'armor': self.armor_name, 'medical_tool': self.medical_tool_name, 'combat': { 'shots_fired': self.shots_fired, 'damage_dealt': str(self.damage_dealt), 'damage_taken': str(self.damage_taken), 'kills': self.kills, }, 'healing': { 'heals_performed': self.heals_performed, 'health_healed': str(self.health_healed), }, 'loot': { 'total_value': str(self.total_loot_value), 'shrapnel': str(self.shrapnel_value), 'universal_ammo': str(self.universal_ammo_value), 'other': str(self.other_loot_value), 'events_count': len(self.loot_events), }, 'special_events': { 'globals': self.globals_count, 'hofs': self.hofs_count, }, 'costs': { 'weapon': str(self._weapon_cost), 'armor': str(self._armor_cost), 'healing': str(self._healing_cost), 'plates': str(self._plate_cost), 'total': str(self.total_cost), }, 'results': { 'profit_loss': str(self.profit_loss), 'return_percentage': float(self.return_percentage), 'cost_per_kill': str(self.cost_per_kill), 'cost_per_hour': str(self.cost_per_hour), 'loot_per_hour': str(self.loot_per_hour), } } def to_json(self) -> str: """Export session to JSON.""" return json.dumps(self.get_summary(), indent=2) class SessionManager: """Manages multiple hunting sessions.""" def __init__(self): self.active_session: Optional[HuntingSession] = None self.completed_sessions: List[HuntingSession] = [] def start_session(self, session_id: str, project_id: int, **gear_config) -> HuntingSession: """Start a new hunting session.""" session = HuntingSession( session_id=session_id, project_id=project_id, start_time=datetime.now(), **gear_config ) self.active_session = session logger.info(f"Started hunting session {session_id}") return session def end_session(self) -> Optional[HuntingSession]: """End the current session.""" if self.active_session: self.active_session.end_time = datetime.now() self.completed_sessions.append(self.active_session) session = self.active_session self.active_session = None logger.info(f"Ended hunting session {session.session_id}") return session return None def get_active_session(self) -> Optional[HuntingSession]: """Get currently active session.""" return self.active_session def get_session_history(self) -> List[HuntingSession]: """Get all completed sessions.""" return self.completed_sessions.copy() def get_totals(self) -> Dict[str, Decimal]: """Get totals across all sessions.""" totals = { 'total_loot': Decimal('0'), 'total_cost': Decimal('0'), 'total_profit': Decimal('0'), 'total_kills': Decimal('0'), } for session in self.completed_sessions: totals['total_loot'] += session.total_loot_value totals['total_cost'] += session.total_cost totals['total_profit'] += session.profit_loss totals['total_kills'] += Decimal(session.kills) return totals # Global session manager instance _session_manager = SessionManager() def get_session_manager() -> SessionManager: """Get the global session manager.""" return _session_manager if __name__ == "__main__": # Test the session tracking print("Testing Hunting Session Tracker") print("=" * 60) # Create a test session session = HuntingSession( session_id="test-001", project_id=1, start_time=datetime.now(), weapon_name="ArMatrix BP-25", weapon_damage=Decimal('39'), weapon_decay_pec=Decimal('0.688'), weapon_ammo_burn=Decimal('848'), armor_name="Ghost", armor_durability=2000, medical_tool_name="Vivo S10", medical_tool_decay_pec=Decimal('1.705') ) # Simulate a hunting session print("\nSimulating 10-minute hunt...") # Fire 100 shots for _ in range(100): session.add_shot() session.add_damage_dealt(Decimal('39')) # Take some damage session.add_damage_taken(Decimal('150')) # Heal twice session.add_heal(Decimal('21')) session.add_heal(Decimal('21')) # Kill 5 mobs for _ in range(5): session.add_kill() # Get some loot session.add_loot("Animal Hide", 5, Decimal('0.50')) session.add_loot("Animal Oil", 3, Decimal('0.30')) session.add_loot("Shrapnel", 100, Decimal('1.00'), is_shrapnel=True) # End session session.end_time = datetime.now() + timedelta(minutes=10) # Print summary print(f"\nSession Summary:") print(f" Duration: {session.session_duration}") print(f" Shots: {session.shots_fired}") print(f" Damage Dealt: {session.damage_dealt}") print(f" Damage Taken: {session.damage_taken}") print(f" Kills: {session.kills}") print(f" Heals: {session.heals_performed}") print(f"\nCosts:") print(f" Weapon: {session._weapon_cost:.4f} PED") print(f" Armor: {session._armor_cost:.4f} PED") print(f" Healing: {session._healing_cost:.4f} PED") print(f" Total: {session.total_cost:.4f} PED") print(f"\nLoot:") print(f" Total: {session.total_loot_value:.4f} PED") print(f" Shrapnel: {session.shrapnel_value:.4f} PED") print(f"\nResults:") print(f" Profit/Loss: {session.profit_loss:.4f} PED") print(f" Return: {session.return_percentage:.2f}%") print(f" Cost/Kill: {session.cost_per_kill:.4f} PED") print(f" Cost/Hour: {session.cost_per_hour:.2f} PED")