feat(db): add database migration script for loadout support
- migrate_db.py adds loadout_id, mindforce_cost_ped, hits_taken, heals_used columns - Creates loadouts table if not exists - Updates schema version to 3
This commit is contained in:
parent
1b176b96a8
commit
1ba8acb7e2
|
|
@ -1,7 +1,7 @@
|
||||||
# 2026-02-09 - Lemontropia Suite Development
|
# 2026-02-09 - Lemontropia Suite Development
|
||||||
|
|
||||||
## Session Summary
|
## Session Summary
|
||||||
Completed the TODO list for Loadout Manager improvements. Multiple bug fixes and new features implemented.
|
Completed full integration between Loadout Manager and Hunting Sessions. Users can now configure complete loadouts and use them to track costs during actual hunting.
|
||||||
|
|
||||||
## Bug Fixes
|
## Bug Fixes
|
||||||
|
|
||||||
|
|
@ -48,11 +48,94 @@ Completed the TODO list for Loadout Manager improvements. Multiple bug fixes and
|
||||||
- **Decay**: All equipped enhancers contribute to total decay per shot
|
- **Decay**: All equipped enhancers contribute to total decay per shot
|
||||||
- **Commit**: `b58af87`
|
- **Commit**: `b58af87`
|
||||||
|
|
||||||
|
## Loadout-Session Integration (NEW)
|
||||||
|
|
||||||
|
### Database Schema Updates
|
||||||
|
- **New table**: `loadouts` - stores complete gear configurations
|
||||||
|
- Weapon with attachments (amp, scope, absorber)
|
||||||
|
- Armor with plates (JSON)
|
||||||
|
- Healing tool
|
||||||
|
- Mindforce implant
|
||||||
|
- Accessories (rings, pet, clothing)
|
||||||
|
- Enhancers (JSON with tier mapping)
|
||||||
|
- Pre-calculated per-action costs
|
||||||
|
- **Updated table**: `hunting_sessions` - added `loadout_id` foreign key
|
||||||
|
- **File**: `core/schema.sql`
|
||||||
|
|
||||||
|
### Core Modules
|
||||||
|
|
||||||
|
#### LoadoutDatabase (`core/loadout_db.py`)
|
||||||
|
- CRUD operations for loadouts
|
||||||
|
- `save_loadout()` - Save complete configuration
|
||||||
|
- `get_loadout()` - Retrieve by name
|
||||||
|
- `list_loadouts()` - List all saved
|
||||||
|
- `set_active_loadout()` - Mark as default
|
||||||
|
- `link_loadout_to_session()` - Associate with hunting session
|
||||||
|
- `update_session_costs()` - Calculate costs based on loadout
|
||||||
|
|
||||||
|
#### SessionCostTracker (`core/session_cost_tracker.py`)
|
||||||
|
- Real-time cost tracking during hunting
|
||||||
|
- Tracks per-action costs:
|
||||||
|
- Cost per shot (weapon + ammo + enhancers + amp)
|
||||||
|
- Cost per hit (armor decay)
|
||||||
|
- Cost per heal (FAP/chip decay)
|
||||||
|
- Mindforce decay (if using implants)
|
||||||
|
- Callback system for live HUD updates
|
||||||
|
- Automatic database persistence
|
||||||
|
|
||||||
|
### UI Components
|
||||||
|
|
||||||
|
#### LoadoutSelectionDialog (`ui/loadout_selection_dialog.py`)
|
||||||
|
- Shown when starting a hunting session
|
||||||
|
- Lists all saved loadouts with preview
|
||||||
|
- Shows per-action costs for comparison
|
||||||
|
- Option to skip (no cost tracking)
|
||||||
|
|
||||||
|
#### HUDOverlay Updates
|
||||||
|
- New display row for loadout metrics:
|
||||||
|
- $/shot - Cost per weapon shot
|
||||||
|
- $/hit - Cost per armor hit taken
|
||||||
|
- $/heal - Cost per heal used
|
||||||
|
- Hits - Number of hits taken
|
||||||
|
- Heals - Number of heals used
|
||||||
|
- `set_cost_tracker()` method for live updates
|
||||||
|
- Mindforce cost tracking support
|
||||||
|
|
||||||
|
### Usage Flow
|
||||||
|
```
|
||||||
|
1. User creates loadout in Loadout Manager
|
||||||
|
→ Saved to database with per-action costs calculated
|
||||||
|
|
||||||
|
2. User starts hunting session
|
||||||
|
→ LoadoutSelectionDialog appears
|
||||||
|
→ User selects loadout (or skips)
|
||||||
|
→ Session linked to loadout_id
|
||||||
|
|
||||||
|
3. During hunting
|
||||||
|
→ LogWatcher detects events
|
||||||
|
→ SessionCostTracker calculates costs
|
||||||
|
→ HUD updates in real-time with loadout-based costs
|
||||||
|
|
||||||
|
4. After session
|
||||||
|
→ Complete cost breakdown stored in database
|
||||||
|
→ Can compare against loot for true P/L
|
||||||
|
```
|
||||||
|
|
||||||
## Data Model Updates
|
## Data Model Updates
|
||||||
Added to `LoadoutConfig`:
|
|
||||||
- `mindforce_implant: Optional[str]` - Selected MF chip name
|
### LoadoutConfig additions:
|
||||||
- `mindforce_decay_pec: Decimal` - Decay cost per use
|
- `mindforce_implant: Optional[str]` - Selected MF chip
|
||||||
- `enhancers: Dict[int, NexusEnhancer]` - Tier-based enhancer slots
|
- `mindforce_decay_pec: Decimal` - Decay per use
|
||||||
|
- `enhancers: Dict[int, NexusEnhancer]` - Tier-based slots
|
||||||
|
|
||||||
|
### HUDStats additions:
|
||||||
|
- `mindforce_cost_total: Decimal` - Accumulated MF costs
|
||||||
|
- `hits_taken: int` - Number of armor hits
|
||||||
|
- `heals_used: int` - Number of heals
|
||||||
|
- `cost_per_shot: Decimal` - From loadout
|
||||||
|
- `cost_per_hit: Decimal` - From loadout
|
||||||
|
- `cost_per_heal: Decimal` - From loadout
|
||||||
|
- `loadout_id: Optional[int]` - Linked loadout
|
||||||
|
|
||||||
## Git Commits
|
## Git Commits
|
||||||
- `b8fc0a8` - fix(api): fix NexusPlate dataclass
|
- `b8fc0a8` - fix(api): fix NexusPlate dataclass
|
||||||
|
|
@ -60,6 +143,15 @@ Added to `LoadoutConfig`:
|
||||||
- `6bcd0ca` - feat(api): add armor sets and mindforce implants endpoints
|
- `6bcd0ca` - feat(api): add armor sets and mindforce implants endpoints
|
||||||
- `1e115db` - feat(ui): add armor set and mindforce implant selectors
|
- `1e115db` - feat(ui): add armor set and mindforce implant selectors
|
||||||
- `b58af87` - feat(loadout): add mindforce implant field and tier-based enhancers
|
- `b58af87` - feat(loadout): add mindforce implant field and tier-based enhancers
|
||||||
|
- `af624b2` - feat(core): add loadout-session integration and cost tracking
|
||||||
|
- `1b176b9` - feat(hud): integrate loadout-based cost tracking in HUD
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
All Loadout Manager TODO items completed. Ready for integration testing.
|
✅ Complete loadout-to-session integration ready for testing
|
||||||
|
|
||||||
|
### Next Steps:
|
||||||
|
1. Test loadout selection dialog when starting hunt
|
||||||
|
2. Verify cost tracking accuracy during live session
|
||||||
|
3. Add "Loadout" button to main window toolbar
|
||||||
|
4. Implement actual log parsing to trigger cost updates
|
||||||
|
5. Add session summary view showing loadout vs actual costs
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,139 @@
|
||||||
|
"""
|
||||||
|
Database migration script for Lemontropia Suite
|
||||||
|
Adds loadout support to existing database
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sqlite3
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
def migrate_database(db_path: str):
|
||||||
|
"""Migrate database to latest schema."""
|
||||||
|
print(f"Migrating database: {db_path}")
|
||||||
|
|
||||||
|
conn = sqlite3.connect(db_path)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
# Check if loadout_id column exists
|
||||||
|
cursor.execute("PRAGMA table_info(hunting_sessions)")
|
||||||
|
columns = [col[1] for col in cursor.fetchall()]
|
||||||
|
|
||||||
|
if 'loadout_id' not in columns:
|
||||||
|
print("Adding loadout_id column to hunting_sessions...")
|
||||||
|
cursor.execute("""
|
||||||
|
ALTER TABLE hunting_sessions
|
||||||
|
ADD COLUMN loadout_id INTEGER
|
||||||
|
REFERENCES loadouts(id) ON DELETE SET NULL
|
||||||
|
""")
|
||||||
|
else:
|
||||||
|
print("loadout_id column already exists")
|
||||||
|
|
||||||
|
# Check if mindforce_cost_ped column exists
|
||||||
|
if 'mindforce_cost_ped' not in columns:
|
||||||
|
print("Adding mindforce_cost_ped column...")
|
||||||
|
cursor.execute("""
|
||||||
|
ALTER TABLE hunting_sessions
|
||||||
|
ADD COLUMN mindforce_cost_ped REAL DEFAULT 0.0
|
||||||
|
""")
|
||||||
|
else:
|
||||||
|
print("mindforce_cost_ped column already exists")
|
||||||
|
|
||||||
|
# Check if hits_taken column exists
|
||||||
|
if 'hits_taken' not in columns:
|
||||||
|
print("Adding hits_taken column...")
|
||||||
|
cursor.execute("""
|
||||||
|
ALTER TABLE hunting_sessions
|
||||||
|
ADD COLUMN hits_taken INTEGER DEFAULT 0
|
||||||
|
""")
|
||||||
|
else:
|
||||||
|
print("hits_taken column already exists")
|
||||||
|
|
||||||
|
# Check if heals_used column exists
|
||||||
|
if 'heals_used' not in columns:
|
||||||
|
print("Adding heals_used column...")
|
||||||
|
cursor.execute("""
|
||||||
|
ALTER TABLE hunting_sessions
|
||||||
|
ADD COLUMN heals_used INTEGER DEFAULT 0
|
||||||
|
""")
|
||||||
|
else:
|
||||||
|
print("heals_used column already exists")
|
||||||
|
|
||||||
|
# Create loadouts table if not exists
|
||||||
|
cursor.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS loadouts (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
name TEXT NOT NULL UNIQUE,
|
||||||
|
description TEXT,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
weapon_name TEXT,
|
||||||
|
weapon_damage REAL DEFAULT 0.0,
|
||||||
|
weapon_decay_pec REAL DEFAULT 0.0,
|
||||||
|
weapon_ammo_pec REAL DEFAULT 0.0,
|
||||||
|
weapon_dpp REAL DEFAULT 0.0,
|
||||||
|
weapon_efficiency REAL DEFAULT 0.0,
|
||||||
|
amplifier_name TEXT,
|
||||||
|
amplifier_decay_pec REAL DEFAULT 0.0,
|
||||||
|
scope_name TEXT,
|
||||||
|
scope_decay_pec REAL DEFAULT 0.0,
|
||||||
|
absorber_name TEXT,
|
||||||
|
absorber_decay_pec REAL DEFAULT 0.0,
|
||||||
|
armor_name TEXT,
|
||||||
|
armor_decay_per_hp REAL DEFAULT 0.05,
|
||||||
|
plates_json TEXT,
|
||||||
|
healing_tool_name TEXT,
|
||||||
|
healing_decay_pec REAL DEFAULT 0.0,
|
||||||
|
healing_amount REAL DEFAULT 0.0,
|
||||||
|
mindforce_implant_name TEXT,
|
||||||
|
mindforce_decay_pec REAL DEFAULT 0.0,
|
||||||
|
left_ring TEXT,
|
||||||
|
right_ring TEXT,
|
||||||
|
pet_name TEXT,
|
||||||
|
accessories_json TEXT,
|
||||||
|
enhancers_json TEXT,
|
||||||
|
cost_per_shot_ped REAL DEFAULT 0.0,
|
||||||
|
cost_per_hit_ped REAL DEFAULT 0.0,
|
||||||
|
cost_per_heal_ped REAL DEFAULT 0.0,
|
||||||
|
is_active BOOLEAN DEFAULT 0,
|
||||||
|
metadata TEXT
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
print("Created loadouts table (if not exists)")
|
||||||
|
|
||||||
|
# Create indexes
|
||||||
|
cursor.execute("CREATE INDEX IF NOT EXISTS idx_loadouts_name ON loadouts(name)")
|
||||||
|
cursor.execute("CREATE INDEX IF NOT EXISTS idx_loadouts_active ON loadouts(is_active)")
|
||||||
|
cursor.execute("CREATE INDEX IF NOT EXISTS idx_hunting_sessions_loadout ON hunting_sessions(loadout_id)")
|
||||||
|
print("Created indexes")
|
||||||
|
|
||||||
|
# Update schema version
|
||||||
|
cursor.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS schema_version (
|
||||||
|
version INTEGER PRIMARY KEY,
|
||||||
|
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
description TEXT
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
cursor.execute("""
|
||||||
|
INSERT OR REPLACE INTO schema_version (version, description)
|
||||||
|
VALUES (3, 'Added loadout support with loadout_id, mindforce costs, hits/heals tracking')
|
||||||
|
""")
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
print("✅ Migration complete!")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# Default path
|
||||||
|
db_path = Path.home() / "Documents" / "AA2-Repositories" / "Lemontropia-Tool-Alpha" / "Lemontropia-Suite" / "data" / "lemontropia.db"
|
||||||
|
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
db_path = sys.argv[1]
|
||||||
|
|
||||||
|
if not Path(db_path).exists():
|
||||||
|
print(f"Database not found: {db_path}")
|
||||||
|
print("Run gui_main.py to create a new database")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
migrate_database(str(db_path))
|
||||||
Loading…
Reference in New Issue