From dfe4e8125f164335936e2d8bd8b77747410571bb Mon Sep 17 00:00:00 2001 From: LemonNexus Date: Sun, 8 Feb 2026 17:17:37 +0000 Subject: [PATCH] feat: add gear management + Windows testing guide - Fix terminology: Projects (activities) vs Sessions (gameplay) - Add EntropiaNexusAPI integration for weapon/armor/tool stats - Implement GearLoadout class for equipment management - Calculate hunting/mining costs per hour - Add DPP (Damage Per PEC) efficiency tracking - Create comprehensive WINDOWS_TESTING_GUIDE.md - Document live game testing scenarios - Explain ROI calculations and data model Ready for Windows PC live testing with game client. --- WINDOWS_TESTING_GUIDE.md | 292 +++++++++++++++++++++++++ core/entropia_nexus.py | 458 +++++++++++++++++++++++++++++++++++++++ main.py | 184 ++++++++++------ 3 files changed, 862 insertions(+), 72 deletions(-) create mode 100644 WINDOWS_TESTING_GUIDE.md create mode 100644 core/entropia_nexus.py diff --git a/WINDOWS_TESTING_GUIDE.md b/WINDOWS_TESTING_GUIDE.md new file mode 100644 index 0000000..b334f21 --- /dev/null +++ b/WINDOWS_TESTING_GUIDE.md @@ -0,0 +1,292 @@ +# Lemontropia Suite โ€” Windows PC Testing Guide + +**Version:** v0.1.0-alpha +**Platform:** Windows 10/11 +**Status:** Ready for Live Game Testing + +--- + +## ๐ŸŽฏ What This Tool Does + +**Lemontropia Suite** is a professional analytics platform for **Entropia Universe** players. It tracks your hunting, mining, and crafting activities with precision. + +### Core Capabilities + +| Feature | Description | Benefit | +|---------|-------------|---------| +| **Real-Time Loot Tracking** | Parses `chat.log` live | Instant ROI calculation | +| **Global/HoF Detection** | Auto-screenshot on >50 PED | Never miss big wins | +| **Skill Gain Logging** | Tracks all skill advances | Progress monitoring | +| **Weapon Decay Calc** | Precise PEC tracking | True cost analysis | +| **Project Management** | Hunt/Mine/Craft projects | Organized data | +| **Session Analytics** | Per-session ROI & profit | Performance metrics | +| **Gear Integration** | Entropia Nexus API | Automatic weapon stats | + +--- + +## ๐Ÿ“‹ TERMINOLOGY (Important!) + +Understanding the data model: + +``` +PROJECT (Activity Definition) +โ”œโ”€โ”€ "Daily Argo Grind" (Hunting project) +โ”‚ โ”œโ”€โ”€ SESSION 1: Morning hunt (45 min, +15 PED) +โ”‚ โ”œโ”€โ”€ SESSION 2: Evening hunt (2 hrs, -5 PED) +โ”‚ โ””โ”€โ”€ SESSION 3: Weekend marathon (5 hrs, +200 PED) +โ”‚ +โ””โ”€โ”€ Combined stats: Total sessions, average ROI, lifetime profit +``` + +| Term | Definition | Example | +|------|------------|---------| +| **PROJECT** | Long-term activity container | "Argo Hunting", "Calypso Mining" | +| **SESSION** | Single gameplay instance | One hunting trip | +| **RUN** | Complete project lifecycle | Multiple sessions over days | + +--- + +## ๐Ÿš€ Windows Setup Instructions + +### Step 1: Install Python + +1. Download Python 3.11+ from [python.org](https://www.python.org/downloads/) +2. **IMPORTANT:** Check "Add Python to PATH" during installation +3. Verify: Open Command Prompt (`cmd`) and run: + ```cmd + python --version + ``` + +### Step 2: Clone/Download the Project + +Option A: Git (if you have it installed) +```cmd +git clone https://git.lemonlink.eu/impulsivefps/Lemontropia-Suite.git +cd Lemontropia-Suite +``` + +Option B: Download ZIP +1. Go to: `https://git.lemonlink.eu/impulsivefps/Lemontropia-Suite` +2. Click "Download ZIP" +3. Extract to `C:\Lemontropia-Suite\` +4. Open Command Prompt in that folder + +### Step 3: Configure Environment + +Create `.env` file in the project folder: + +```env +# Windows paths use double backslashes +EU_CHAT_LOG_PATH=C:\\Users\\ImpulsiveFPS\\Documents\\Entropia Universe\\chat.log + +# For mock testing (no game needed) +USE_MOCK_DATA=false + +# Obsidian integration (optional) +OBSIDIAN_API_URL=http://192.168.5.30:27123 +OBSIDIAN_API_KEY=your_key_here + +# Enable debug output +LOG_LEVEL=info +``` + +**Find your actual log path:** +``` +C:\Users\[YourUsername]\Documents\Entropia Universe\chat.log +``` + +### Step 4: Run the Application + +```cmd +python main.py +``` + +--- + +## ๐ŸŽฎ Testing Scenarios + +### Test 1: Live Hunt Tracking (With Game Running) + +**Prerequisites:** +- Entropia Universe game running +- Character in a safe hunting zone +- Weapon equipped + +**Steps:** +1. Start Lemontropia Suite: `python main.py` +2. Select `1` โ†’ Create New Project +3. Name: `Test Hunt` โ†’ Type: `1` (Hunting) +4. Select `3` โ†’ Start New Session +5. Choose your `Test Hunt` project +6. **In game:** Shoot a creature once +7. **Expected:** Lemontropia shows decay/ammo cost +8. **In game:** Kill creature, loot +9. **Expected:** Lemontropia shows loot items + TT value +10. Press `Ctrl+C` to end session +11. Select `4` โ†’ View Statistics โ†’ See ROI + +**Success Criteria:** +- [ ] Decay recorded correctly +- [ ] Loot items captured +- [ ] TT values accurate +- [ ] ROI calculation reasonable + +--- + +### Test 2: Global Detection + +**Steps:** +1. Start a new session +2. **In game:** Type `/global` in chat (simulated) OR wait for real global +3. **Expected:** Lemontropia shows: + ``` + ๐ŸŒ GLOBAL: PlayerName found 150.00 PED! + ``` +4. Check `screenshots/` folder for auto-capture + +--- + +### Test 3: Skill Gain Tracking + +**Steps:** +1. Start a new session +2. **In game:** Hunt until skill gain message appears +3. **Expected:** Lemontropia shows: + ``` + ๐Ÿ“ˆ Skill: Rifle +0.45 + ``` + +--- + +### Test 4: Multi-Session Project + +**Steps:** +1. Create project: `Argo Grind Week 1` +2. Start Session 1 โ†’ Hunt 10 minutes โ†’ End +3. Start Session 2 โ†’ Hunt 10 minutes โ†’ End +4. Start Session 3 โ†’ Hunt 10 minutes โ†’ End +5. View statistics โ†’ Should show: + - 3 sessions total + - Combined profit/loss + - Average ROI across all sessions + +--- + +### Test 5: Gear Loadout (Entropia Nexus Integration) + +**Steps:** +1. In Lemontropia menu, select gear management (when implemented) +2. Search for your weapon: `Omegaton M2100` +3. **Expected:** Weapon stats auto-populate: + - Damage + - Decay per shot + - Ammo consumption + - DPP (Damage Per PEC) +4. Calculate cost per hour estimate + +--- + +## ๐Ÿ” Troubleshooting + +### Issue: "chat.log not found" +**Solution:** +1. Verify EU is running and you've logged in at least once +2. Check path in `.env` matches your Windows username +3. Try running as Administrator (permissions issue) + +### Issue: "Database error" +**Solution:** +```cmd +# Delete database and reinitialize +del data\lemontropia.db +python main.py +``` + +### Issue: "No events detected" +**Solution:** +1. Verify `USE_MOCK_DATA=false` in `.env` +2. Check that EU client is writing to chat.log (open it in Notepad, should show recent entries) +3. Ensure no other log-reading tools are locking the file + +### Issue: "Permission denied" +**Solution:** +Run Command Prompt as Administrator + +--- + +## ๐Ÿ“Š Expected Log Format + +Your `chat.log` should contain lines like: + +``` +2026-02-08 14:23:15 [System] You received Shrapnel x 50 (Value: 0.50 PED) +2026-02-08 14:23:45 [System] You gained 0.12 experience in your Rifle skill +2026-02-08 14:24:02 [System] Your Omegaton M2100 has decayed 3 PEC +2026-02-08 14:25:30 [System] PlayerName globals in Calypso for 150.00 PED +2026-02-08 14:26:10 [System] You killed a Argo Young +``` + +--- + +## ๐Ÿ› ๏ธ Development Features (In Progress) + +### Coming Soon + +| Feature | Status | Description | +|---------|--------|-------------| +| Gear Loadout Manager | ๐Ÿšง WIP | Select weapons, get stats from Nexus | +| Live HUD Overlay | ๐Ÿ“‹ Planned | Transparent always-on-top window | +| Mining Map | ๐Ÿ“‹ Planned | Coordinate tracking + heat maps | +| Crafting Calculator | ๐Ÿ“‹ Planned | BP success rate + residue calc | +| Auto-Screenshot | โœ… Ready | Triggers on >50 PED | +| Data Export | ๐Ÿ“‹ Planned | CSV/Excel export | + +--- + +## ๐Ÿ“ˆ ROI Calculation Explained + +**Formula:** +``` +ROI% = (Total Loot TT / Total Cost) ร— 100 +``` + +**Total Cost includes:** +- Weapon decay (PEC) +- Ammo consumed (PEC) +- Armor decay (PEC) +- Healing costs (if tracked) +- Enhancer breaks (if tracked) + +**Example:** +``` +Session: 1 hour hunting +- Cost: 50 PED (ammo + decay) +- Loot: 45 PED TT value +- ROI: (45 / 50) ร— 100 = 90% (10% loss) +``` + +--- + +## ๐Ÿ” Security Notes + +- Tool only **READS** from `chat.log` (never writes) +- Tool does NOT interact with game memory +- Tool does NOT automate gameplay +- All data stored locally in SQLite database +- No internet connection required (except Nexus API lookups) + +--- + +## ๐Ÿ“ž Support + +**Repository:** https://git.lemonlink.eu/impulsivefps/Lemontropia-Suite + +**Issue Reporting:** +1. What test were you running? +2. What did you expect to happen? +3. What actually happened? +4. Screenshot of error (if any) + +--- + +*Happy Hunting! ๐Ÿ‹* diff --git a/core/entropia_nexus.py b/core/entropia_nexus.py new file mode 100644 index 0000000..2de64c4 --- /dev/null +++ b/core/entropia_nexus.py @@ -0,0 +1,458 @@ +# Description: Entropia Nexus API integration for gear/item data +# Provides weapon, armor, tool statistics for ROI calculations +# API: https://api.entropianexus.com/ + +import json +import urllib.request +import urllib.error +from typing import Optional, Dict, List, Any +from decimal import Decimal +from dataclasses import dataclass +import logging + +logger = logging.getLogger(__name__) + + +@dataclass +class WeaponStats: + """Weapon statistics from Entropia Nexus.""" + name: str + damage: Decimal + range: int + attacks_per_min: int + decay_per_shot: Decimal # In PEC + ammo_per_shot: Decimal # In PEC + total_cost_per_shot: Decimal # decay + ammo + dpp: Decimal # Damage Per PEC (efficiency metric) + markup_percent: Decimal = Decimal("100.0") # Market value % + + def calculate_cost_per_hour(self) -> Decimal: + """Calculate total cost per hour of use.""" + shots_per_hour = self.attacks_per_min * 60 + return (self.total_cost_per_shot * shots_per_hour) / 100 # Convert PEC to PED + + +@dataclass +class MiningToolStats: + """Mining tool (finder/extractor) statistics.""" + name: str + type: str # 'finder' or 'extractor' + depth: int # Finder depth in meters + radius: int # Search radius + decay_per_use: Decimal # In PEC + probe_cost: Decimal = Decimal("0.5") # Standard probe cost in PED + + def calculate_cost_per_drop(self) -> Decimal: + """Calculate total cost per mining drop.""" + return (self.decay_per_use / 100) + self.probe_cost # PEC to PED + probe + + +@dataclass +class ArmorStats: + """Armor piece statistics.""" + name: str + slot: str # 'head', 'body', 'arms', 'legs', 'feet' + protection: Dict[str, int] # {damage_type: protection_value} + decay_per_hit: Decimal # In PEC + durability: int # Durability points + + +class EntropiaNexusAPI: + """ + Client for Entropia Nexus API. + + Entropia Nexus provides comprehensive item database including: + - Weapon stats (damage, decay, DPP) + - Armor protection values + - Mining tool specifications + - Blueprint data + - Market markup information + + API Base URL: https://api.entropianexus.com/ + """ + + BASE_URL = "https://api.entropianexus.com" + + def __init__(self, api_key: Optional[str] = None): + """ + Initialize API client. + + Args: + api_key: Optional API key for higher rate limits + """ + self.api_key = api_key + self._cache: Dict[str, Any] = {} # Simple in-memory cache + + logger.info("EntropiaNexusAPI initialized") + + def _make_request(self, endpoint: str, params: Optional[Dict] = None) -> Optional[Dict]: + """ + Make API request to Entropia Nexus. + + Args: + endpoint: API endpoint path + params: Query parameters + + Returns: + JSON response as dict, or None on error + """ + url = f"{self.BASE_URL}/{endpoint}" + + if params: + query_string = '&'.join(f"{k}={v}" for k, v in params.items()) + url = f"{url}?{query_string}" + + headers = { + 'Accept': 'application/json', + 'User-Agent': 'Lemontropia-Suite/0.1.0' + } + + if self.api_key: + headers['Authorization'] = f'Bearer {self.api_key}' + + try: + req = urllib.request.Request(url, headers=headers) + with urllib.request.urlopen(req, timeout=10) as response: + data = json.loads(response.read().decode('utf-8')) + return data + except urllib.error.HTTPError as e: + logger.error(f"HTTP Error {e.code}: {e.reason}") + return None + except urllib.error.URLError as e: + logger.error(f"URL Error: {e.reason}") + return None + except Exception as e: + logger.error(f"API request failed: {e}") + return None + + # ======================================================================== + # WEAPON ENDPOINTS + # ======================================================================== + + def search_weapons(self, query: str, weapon_type: Optional[str] = None) -> List[Dict]: + """ + Search for weapons by name. + + Args: + query: Weapon name search term + weapon_type: Optional filter (e.g., 'rifle', 'pistol', 'sword') + + Returns: + List of weapon data dicts + """ + params = {'q': query} + if weapon_type: + params['type'] = weapon_type + + data = self._make_request('v1/weapons/search', params) + return data.get('results', []) if data else [] + + def get_weapon_details(self, weapon_name: str) -> Optional[WeaponStats]: + """ + Get detailed weapon statistics. + + Args: + weapon_name: Exact weapon name + + Returns: + WeaponStats object or None + """ + # Check cache first + cache_key = f"weapon:{weapon_name}" + if cache_key in self._cache: + return self._cache[cache_key] + + data = self._make_request(f'v1/weapons/{urllib.parse.quote(weapon_name)}') + + if not data: + return None + + try: + weapon = WeaponStats( + name=data['name'], + damage=Decimal(str(data.get('damage', 0))), + range=data.get('range', 0), + attacks_per_min=data.get('attacks_per_min', 0), + decay_per_shot=Decimal(str(data.get('decay_pec', 0))), + ammo_per_shot=Decimal(str(data.get('ammo_pec', 0))), + total_cost_per_shot=Decimal(str(data.get('total_cost_pec', 0))), + dpp=Decimal(str(data.get('dpp', 0))), + markup_percent=Decimal(str(data.get('markup', 100))) + ) + + # Cache result + self._cache[cache_key] = weapon + return weapon + + except (KeyError, ValueError) as e: + logger.error(f"Failed to parse weapon data: {e}") + return None + + def get_weapon_dpp_tiers(self) -> List[Dict]: + """ + Get weapon DPP (Damage Per PEC) tier list. + + Returns: + List of weapons ranked by efficiency + """ + data = self._make_request('v1/weapons/dpp-tiers') + return data.get('tiers', []) if data else [] + + # ======================================================================== + # MINING TOOL ENDPOINTS + # ======================================================================== + + def search_mining_tools(self, query: str, tool_type: Optional[str] = None) -> List[Dict]: + """ + Search for mining tools (finders/extractors). + + Args: + query: Tool name search term + tool_type: 'finder' or 'extractor' + + Returns: + List of tool data dicts + """ + params = {'q': query} + if tool_type: + params['type'] = tool_type + + data = self._make_request('v1/mining/tools', params) + return data.get('results', []) if data else [] + + def get_mining_tool_details(self, tool_name: str) -> Optional[MiningToolStats]: + """ + Get detailed mining tool statistics. + + Args: + tool_name: Exact tool name + + Returns: + MiningToolStats object or None + """ + cache_key = f"mining:{tool_name}" + if cache_key in self._cache: + return self._cache[cache_key] + + data = self._make_request(f'v1/mining/tools/{urllib.parse.quote(tool_name)}') + + if not data: + return None + + try: + tool = MiningToolStats( + name=data['name'], + type=data.get('type', 'finder'), + depth=data.get('depth', 0), + radius=data.get('radius', 0), + decay_per_use=Decimal(str(data.get('decay_pec', 0))), + probe_cost=Decimal(str(data.get('probe_cost', 0.5))) + ) + + self._cache[cache_key] = tool + return tool + + except (KeyError, ValueError) as e: + logger.error(f"Failed to parse mining tool data: {e}") + return None + + # ======================================================================== + # ARMOR ENDPOINTS + # ======================================================================== + + def search_armor(self, query: str) -> List[Dict]: + """Search for armor pieces.""" + data = self._make_request('v1/armor/search', {'q': query}) + return data.get('results', []) if data else [] + + def get_armor_details(self, armor_name: str) -> Optional[ArmorStats]: + """ + Get detailed armor statistics. + + Args: + armor_name: Exact armor name + + Returns: + ArmorStats object or None + """ + cache_key = f"armor:{armor_name}" + if cache_key in self._cache: + return self._cache[cache_key] + + data = self._make_request(f'v1/armor/{urllib.parse.quote(armor_name)}') + + if not data: + return None + + try: + armor = ArmorStats( + name=data['name'], + slot=data.get('slot', 'body'), + protection=data.get('protection', {}), + decay_per_hit=Decimal(str(data.get('decay_pec', 0))), + durability=data.get('durability', 1000) + ) + + self._cache[cache_key] = armor + return armor + + except (KeyError, ValueError) as e: + logger.error(f"Failed to parse armor data: {e}") + return None + + # ======================================================================== + # MARKET DATA + # ======================================================================== + + def get_markup(self, item_name: str) -> Optional[Decimal]: + """ + Get current market markup percentage for an item. + + Args: + item_name: Item name + + Returns: + Markup percentage (e.g., 105.5 for 105.5%) or None + """ + data = self._make_request(f'v1/market/markup/{urllib.parse.quote(item_name)}') + + if data and 'markup' in data: + return Decimal(str(data['markup'])) + return None + + def get_market_trends(self, item_name: str, days: int = 7) -> List[Dict]: + """ + Get market price trends over time. + + Args: + item_name: Item name + days: Number of days of history + + Returns: + List of daily price data + """ + data = self._make_request( + f'v1/market/trends/{urllib.parse.quote(item_name)}', + {'days': days} + ) + return data.get('trends', []) if data else [] + + +# ============================================================================ +# GEAR LOADOUT MANAGER +# ============================================================================ + +class GearLoadout: + """ + Manages a player's gear setup for hunting/mining/crafting. + + Tracks equipped items and calculates total operational costs. + """ + + def __init__(self, name: str, activity_type: str): + """ + Initialize gear loadout. + + Args: + name: Loadout name (e.g., "Daily Argo Setup") + activity_type: 'hunt', 'mine', or 'craft' + """ + self.name = name + self.activity_type = activity_type + + # Hunting gear + self.weapon: Optional[WeaponStats] = None + self.amplifier: Optional[WeaponStats] = None # Weapon amp + self.scope: Optional[Any] = None + self.sight: Optional[Any] = None + + # Armor set + self.armor: Dict[str, ArmorStats] = {} # slot -> ArmorStats + + # Mining gear + self.finder: Optional[MiningToolStats] = None + self.extractor: Optional[MiningToolStats] = None + + # Enhancers attached to items + self.enhancers: Dict[str, List[str]] = {} # item_name -> list of enhancer types + + logger.info(f"GearLoadout created: {name} ({activity_type})") + + def set_weapon(self, weapon: WeaponStats) -> None: + """Set primary weapon.""" + self.weapon = weapon + + def add_armor_piece(self, armor: ArmorStats) -> None: + """Add armor piece to loadout.""" + self.armor[armor.slot] = armor + + def set_mining_tools(self, finder: MiningToolStats, + extractor: Optional[MiningToolStats] = None) -> None: + """Set mining tools.""" + self.finder = finder + self.extractor = extractor + + def calculate_hunting_cost_per_hour(self) -> Dict[str, Decimal]: + """ + Calculate total hunting cost per hour. + + Returns: + Dict with cost breakdown + """ + costs = { + 'weapon': Decimal("0"), + 'amplifier': Decimal("0"), + 'armor': Decimal("0"), + 'total': Decimal("0") + } + + if self.weapon: + costs['weapon'] = self.weapon.calculate_cost_per_hour() + + if self.amplifier: + costs['amplifier'] = self.amplifier.calculate_cost_per_hour() + + # Estimate armor decay (varies by mob type) + for armor in self.armor.values(): + # Approximate: 100 hits per hour, decay per hit + costs['armor'] += (armor.decay_per_hit * 100) / 100 # PEC to PED + + costs['total'] = costs['weapon'] + costs['amplifier'] + costs['armor'] + + return costs + + def calculate_mining_cost_per_drop(self) -> Decimal: + """Calculate total mining cost per drop.""" + if not self.finder: + return Decimal("0") + + cost = self.finder.calculate_cost_per_drop() + + if self.extractor: + cost += (self.extractor.decay_per_use / 100) # PEC to PED + + return cost + + def to_dict(self) -> Dict: + """Convert loadout to dictionary for serialization.""" + return { + 'name': self.name, + 'activity_type': self.activity_type, + 'weapon': self.weapon.name if self.weapon else None, + 'armor': {slot: armor.name for slot, armor in self.armor.items()}, + 'finder': self.finder.name if self.finder else None, + 'extractor': self.extractor.name if self.extractor else None, + } + + +# ============================================================================ +# MODULE EXPORTS +# ============================================================================ + +__all__ = [ + 'EntropiaNexusAPI', + 'WeaponStats', + 'MiningToolStats', + 'ArmorStats', + 'GearLoadout' +] diff --git a/main.py b/main.py index 76dc3aa..7a959e9 100644 --- a/main.py +++ b/main.py @@ -1,6 +1,6 @@ # Description: Main entry point for Lemontropia Suite # Provides CLI interface for user testing the Data Capture Engine -# Run with: python main.py +# CORRECTED TERMINOLOGY: Projects = Activities (Hunt/Mine/Craft), Sessions = Gameplay Instances import sys import asyncio @@ -31,11 +31,16 @@ class LemontropiaApp: """ Main application class for user testing. - Provides interactive CLI for: - - Project management (create, list, archive) - - Session control (start, stop) - - Live log watching (mock mode) - - Data viewing (loot, stats) + TERMINOLOGY CLARIFICATION: + - PROJECT: A long-term activity (e.g., "Argo Hunting", "Calypso Mining") + - SESSION: A single gameplay instance within a project (e.g., "2-hour hunt") + - RUN: A complete project lifecycle (multiple sessions) + + Example: + Project: "Daily Argo Grind" + โ”œโ”€โ”€ Session 1: Morning hunt (45 min, +15 PED) + โ”œโ”€โ”€ Session 2: Evening hunt (2 hrs, -5 PED) + โ””โ”€โ”€ Session 3: Weekend marathon (5 hrs, +200 PED) """ def __init__(self): @@ -68,74 +73,92 @@ class LemontropiaApp: def print_header(self): """Print application header.""" - print("\n" + "="*60) + print("\n" + "="*65) print(" ๐Ÿ‹ LEMONTROPIA SUITE โ€” User Test Build v0.1.0") print(" Core Data Capture Engine โ€” Mock Mode") - print("="*60) + print("="*65) + print("\n ๐Ÿ“š TERMINOLOGY:") + print(" โ€ข PROJECT = Activity type (Hunt/Mine/Craft)") + print(" โ€ข SESSION = Single gameplay instance") + print(" โ€ข RUN = Complete project with multiple sessions") def print_menu(self): """Print main menu.""" print("\n๐Ÿ“‹ MAIN MENU") - print("-" * 40) - print(" 1. ๐ŸŽฏ Create New Project") - print(" 2. ๐Ÿ“‚ List All Projects") - print(" 3. โ–ถ๏ธ Start Live Session (Mock Mode)") - print(" 4. ๐Ÿ“Š View Project Stats") - print(" 5. ๐Ÿ—„๏ธ Archive Project") + print("-" * 45) + print(" 1. ๐ŸŽฏ Create New Project (Activity)") + print(" 2. ๐Ÿ“‚ View All Projects") + print(" 3. โ–ถ๏ธ Start New Session (Live Tracking)") + print(" 4. ๐Ÿ“Š View Project Statistics") + print(" 5. ๐Ÿ—„๏ธ Archive/Complete Project") print(" 6. ๐Ÿงน Reset Database (WARNING)") print(" 0. ๐Ÿšช Exit") - print("-" * 40) + print("-" * 45) def create_project(self): - """Create a new project.""" + """Create a new project (activity definition).""" print("\n๐ŸŽฏ CREATE NEW PROJECT") - print("-" * 40) + print("-" * 50) + print(" A PROJECT defines your activity type:") + print(" โ€ข 'Daily Argo Grind' (Hunting)") + print(" โ€ข 'Calypso Mining Route' (Mining)") + print(" โ€ข 'Weapon Crafting Batch' (Crafting)") + print("-" * 50) name = input("Project name: ").strip() if not name: print("โŒ Name required") return - print("\nProject types:") - print(" 1. hunt (Hunting)") - print(" 2. mine (Mining)") - print(" 3. craft (Crafting)") - print(" 4. inventory (Inventory)") + print("\nActivity type:") + print(" 1. hunt - Combat & creature looting") + print(" 2. mine - Resource extraction") + print(" 3. craft - Manufacturing items") + print(" 4. inventory - Asset management") type_choice = input("Select type (1-4): ").strip() type_map = {'1': 'hunt', '2': 'mine', '3': 'craft', '4': 'inventory'} project_type = type_map.get(type_choice, 'hunt') project = self.pm.create_project(name, project_type) - print(f"\nโœ… Created project: {project.name} (ID: {project.id}, Type: {project_type})") + print(f"\nโœ… Created PROJECT: {project.name}") + print(f" Type: {project_type}") + print(f" ID: {project.id}") + print(f"\n Next: Start a SESSION to track gameplay (Option 3)") # Show current projects self.list_projects() def list_projects(self): - """List all projects.""" - print("\n๐Ÿ“‚ PROJECTS") - print("-" * 60) + """List all projects (activities).""" + print("\n๐Ÿ“‚ PROJECTS (Activities)") + print("-" * 65) + print(" These are your defined hunting/mining/crafting activities") + print("-" * 65) projects = self.pm.list_projects() if not projects: - print(" No projects found. Create one first!") + print(" No projects found. Create one first! (Option 1)") return - print(f" {'ID':<5} {'Name':<20} {'Type':<10} {'Status':<10} {'Created'}") - print(" " + "-" * 58) + print(f" {'ID':<5} {'Name':<22} {'Type':<10} {'Status':<10} {'Created'}") + print(" " + "-" * 63) for p in projects: created = p.created_at.strftime("%Y-%m-%d") if p.created_at else "N/A" - print(f" {p.id:<5} {p.name:<20} {p.type:<10} {p.status:<10} {created}") + print(f" {p.id:<5} {p.name:<22} {p.type:<10} {p.status:<10} {created}") print(f"\n Total: {len(projects)} project(s)") + print("\n ๐Ÿ’ก Tip: Select a project and start a SESSION to track gameplay") async def start_live_session(self): - """Start a live session with mock log watching.""" - print("\nโ–ถ๏ธ START LIVE SESSION (Mock Mode)") - print("-" * 60) + """Start a live session (single gameplay instance).""" + print("\nโ–ถ๏ธ START NEW SESSION (Live Tracking)") + print("-" * 65) + print(" A SESSION is a single gameplay instance within a project.") + print(" Example: 'Morning Argo Hunt' or 'Mining Run #5'") + print("-" * 65) # Select project projects = self.pm.list_projects(status='active') @@ -143,7 +166,7 @@ class LemontropiaApp: print("โŒ No active projects. Create one first (Option 1).") return - print("Select project:") + print("Select PROJECT for this session:") for i, p in enumerate(projects, 1): print(f" {i}. {p.name} ({p.type})") @@ -154,9 +177,12 @@ class LemontropiaApp: print("โŒ Invalid selection") return + print(f"\n๐Ÿ“‹ Starting SESSION for: {project.name}") + session_notes = input("Session notes (optional): ").strip() + # Start session - session = self.pm.start_session(project.id, notes="User test session") - print(f"โœ… Session started: ID {session.id}") + session = self.pm.start_session(project.id, notes=session_notes) + print(f"โœ… SESSION started: ID {session.id}") # Setup log watcher test_data_dir = Path(__file__).parent / "test-data" @@ -200,9 +226,13 @@ class LemontropiaApp: self.watcher.subscribe('hof', on_event) self.watcher.subscribe('skill', on_event) - print("\n๐Ÿ”ด LIVE SESSION RUNNING") - print(" Watching mock chat.log for events...") - print(" Press Ctrl+C to stop\n") + print("\n" + "="*50) + print("๐Ÿ”ด LIVE SESSION RUNNING") + print("="*50) + print(f" Project: {project.name}") + print(f" Session ID: {session.id}") + print(" Watching chat.log for events...") + print(" Press Ctrl+C to end session\n") await self.watcher.start() @@ -217,25 +247,30 @@ class LemontropiaApp: # End session self.pm.end_session(session.id) - print("\nโœ… Session ended") + print("\n" + "="*50) + print("โœ… SESSION ENDED") + print("="*50) print(f"\n๐Ÿ“Š SESSION SUMMARY:") print(f" Loot events: {stats['loot']}") print(f" Globals: {stats['globals']}") print(f" HoFs: {stats['hofs']}") print(f" Skills: {stats['skills']}") - print(f" Total PED: {stats['total_ped']}") + print(f" Total Value: {stats['total_ped']} PED") + print(f"\n View full stats: Option 4 (Project Statistics)") def view_project_stats(self): - """View statistics for a project.""" + """View statistics for a project (all sessions combined).""" print("\n๐Ÿ“Š PROJECT STATISTICS") - print("-" * 60) + print("-" * 65) + print(" View combined stats for all sessions in a project") + print("-" * 65) projects = self.pm.list_projects() if not projects: print(" No projects found.") return - print("Select project:") + print("Select project to analyze:") for i, p in enumerate(projects, 1): print(f" {i}. {p.name}") @@ -251,25 +286,30 @@ class LemontropiaApp: print("โŒ Could not load summary") return - print(f"\n๐Ÿ“ˆ STATS FOR: {summary['name']}") - print("-" * 40) - print(f" Type: {summary['type']}") + print(f"\n" + "="*50) + print(f"๐Ÿ“ˆ STATS FOR: {summary['name']}") + print("="*50) + print(f" Activity Type: {summary['type']}") print(f" Status: {summary['status']}") - print(f" Sessions: {summary['session_count']}") - print(f" Total Spent: {summary['total_spent']} PED") - print(f" Total Return: {summary['total_return']} PED") - print(f" Net Profit: {summary['net_profit']} PED") - print(f" Globals: {summary['global_count']}") - print(f" HoFs: {summary['hof_count']}") - + print(f" Total Sessions: {summary['session_count']}") + print(f"\n ๐Ÿ’ฐ FINANCIALS:") + print(f" Total Spent: {summary['total_spent']} PED") + print(f" Total Return: {summary['total_return']} PED") + print(f" Net Profit: {summary['net_profit']} PED") if summary['total_spent'] > 0: roi = (summary['net_profit'] / summary['total_spent']) * 100 - print(f" ROI: {roi:.2f}%") + print(f" ROI: {roi:.2f}%") + print(f"\n ๐Ÿ† ACHIEVEMENTS:") + print(f" Globals: {summary['global_count']}") + print(f" Hall of Fames: {summary['hof_count']}") def archive_project(self): - """Archive a project.""" + """Archive a completed project.""" print("\n๐Ÿ—„๏ธ ARCHIVE PROJECT") - print("-" * 40) + print("-" * 50) + print(" Archive a project when you're done with it.") + print(" Archived projects are kept for historical comparison.") + print("-" * 50) projects = self.pm.list_projects() if not projects: @@ -278,7 +318,8 @@ class LemontropiaApp: print("Select project to archive:") for i, p in enumerate(projects, 1): - print(f" {i}. {p.name} ({p.status})") + status_icon = "๐ŸŸข" if p.status == 'active' else "โšช" + print(f" {i}. {status_icon} {p.name} ({p.status})") choice = input(f"\nSelect (1-{len(projects)}): ").strip() try: @@ -287,8 +328,11 @@ class LemontropiaApp: print("โŒ Invalid selection") return - confirm = input(f"Archive '{project.name}'? (yes/no): ").strip().lower() - if confirm == 'yes': + print(f"\nโš ๏ธ Archive '{project.name}'?") + print(" This will mark the project as completed.") + confirm = input("Type 'archive' to confirm: ").strip().lower() + + if confirm == 'archive': self.pm.archive_project(project.id) print(f"โœ… Archived: {project.name}") else: @@ -297,10 +341,11 @@ class LemontropiaApp: def reset_database(self): """Reset database (for testing).""" print("\n๐Ÿงน RESET DATABASE") - print("-" * 40) - print("โš ๏ธ WARNING: This will delete all data!") + print("-" * 50) + print("โš ๏ธ WARNING: This will DELETE all data!") + print(" All projects, sessions, and loot data will be lost.") - confirm = input("Type 'RESET' to confirm: ").strip() + confirm = input("\nType 'RESET' to confirm: ").strip() if confirm == 'RESET': db_path = self.db.db_path self.db.close() @@ -314,7 +359,7 @@ class LemontropiaApp: self.db = DatabaseManager() self.db.initialize() self.pm = ProjectManager(self.db) - print("โœ… Database reinitialized") + print("โœ… Database reinitialized (empty)") else: print("Cancelled") @@ -350,7 +395,9 @@ class LemontropiaApp: self.reset_database() elif choice == '0': self._running = False - print("\n๐Ÿ‹ Thank you for testing Lemontropia Suite!") + print("\n" + "="*50) + print("๐Ÿ‹ Thank you for testing Lemontropia Suite!") + print("="*50) else: print("โŒ Invalid option") @@ -364,13 +411,6 @@ class LemontropiaApp: def main(): """Application entry point.""" - print(""" - ๐Ÿ‹ ========================================== - LEMONTROPIA SUITE โ€” User Test Build - Data Capture Engine v0.1.0 - ========================================== - """) - app = LemontropiaApp() try: