EU-Utility/plugins/codex_tracker/plugin.py

219 lines
7.7 KiB
Python

"""
EU-Utility - Codex Tracker Plugin
Track creature challenge progress from Codex.
"""
import json
from pathlib import Path
from datetime import datetime
from PyQt6.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QLabel,
QPushButton, QProgressBar, QTableWidget, QTableWidgetItem,
QComboBox, QFrame
)
from PyQt6.QtCore import Qt
from plugins.base_plugin import BasePlugin
class CodexTrackerPlugin(BasePlugin):
"""Track creature codex progress."""
name = "Codex Tracker"
version = "1.0.0"
author = "ImpulsiveFPS"
description = "Track creature challenges and codex progress"
hotkey = "ctrl+shift+x"
# Arkadia creatures from screenshot
CREATURES = [
{"name": "Bokol", "rank": 22, "progress": 49.5},
{"name": "Nusul", "rank": 15, "progress": 24.8},
{"name": "Wombana", "rank": 10, "progress": 45.2},
{"name": "Arkadian Hornet", "rank": 1, "progress": 15.0},
{"name": "Feran", "rank": 4, "progress": 86.0},
{"name": "Hadraada", "rank": 6, "progress": 0.4},
{"name": "Halix", "rank": 14, "progress": 0.2},
{"name": "Huon", "rank": 1, "progress": 45.8},
{"name": "Kadra", "rank": 2, "progress": 0.7},
{"name": "Magurg", "rank": 1, "progress": 8.7},
{"name": "Monura", "rank": 1, "progress": 5.2},
]
def initialize(self):
"""Setup codex tracker."""
self.data_file = Path("data/codex.json")
self.data_file.parent.mkdir(parents=True, exist_ok=True)
self.creatures = self.CREATURES.copy()
self.scanned_data = {}
self._load_data()
def _load_data(self):
"""Load codex data."""
if self.data_file.exists():
try:
with open(self.data_file, 'r') as f:
data = json.load(f)
self.creatures = data.get('creatures', self.CREATURES)
except:
pass
def _save_data(self):
"""Save codex data."""
with open(self.data_file, 'w') as f:
json.dump({'creatures': self.creatures}, f, indent=2)
def get_ui(self):
"""Create codex tracker UI."""
widget = QWidget()
widget.setStyleSheet("background: transparent;")
layout = QVBoxLayout(widget)
layout.setSpacing(15)
layout.setContentsMargins(0, 0, 0, 0)
# Title
title = QLabel("📖 Codex Tracker")
title.setStyleSheet("color: white; font-size: 16px; font-weight: bold;")
layout.addWidget(title)
# Summary
summary = QHBoxLayout()
total_creatures = len(self.creatures)
completed = sum(1 for c in self.creatures if c.get('progress', 0) >= 100)
self.total_label = QLabel(f"Creatures: {total_creatures}")
self.total_label.setStyleSheet("color: #4a9eff; font-size: 13px;")
summary.addWidget(self.total_label)
self.completed_label = QLabel(f"Completed: {completed}")
self.completed_label.setStyleSheet("color: #4caf50; font-size: 13px;")
summary.addWidget(self.completed_label)
summary.addStretch()
layout.addLayout(summary)
# Scan button
scan_btn = QPushButton("Scan Codex Window")
scan_btn.setStyleSheet("""
QPushButton {
background-color: #ff8c42;
color: white;
padding: 12px;
border: none;
border-radius: 4px;
font-weight: bold;
}
QPushButton:hover {
background-color: #ffa060;
}
""")
scan_btn.clicked.connect(self._scan_codex)
layout.addWidget(scan_btn)
# Creatures list
self.creatures_table = QTableWidget()
self.creatures_table.setColumnCount(4)
self.creatures_table.setHorizontalHeaderLabels(["Creature", "Rank", "Progress", "Next Rank"])
self.creatures_table.setStyleSheet("""
QTableWidget {
background-color: rgba(30, 35, 45, 200);
color: white;
border: 1px solid rgba(100, 110, 130, 80);
border-radius: 6px;
}
QHeaderView::section {
background-color: rgba(35, 40, 55, 200);
color: rgba(255,255,255,180);
padding: 8px;
border: none;
font-weight: bold;
font-size: 11px;
}
""")
self.creatures_table.horizontalHeader().setStretchLastSection(True)
layout.addWidget(self.creatures_table)
self._refresh_table()
layout.addStretch()
return widget
def _refresh_table(self):
"""Refresh creatures table."""
self.creatures_table.setRowCount(len(self.creatures))
for i, creature in enumerate(sorted(self.creatures, key=lambda x: -x.get('progress', 0))):
# Name
name_item = QTableWidgetItem(creature.get('name', 'Unknown'))
name_item.setFlags(name_item.flags() & ~Qt.ItemFlag.ItemIsEditable)
self.creatures_table.setItem(i, 0, name_item)
# Rank
rank = creature.get('rank', 0)
rank_item = QTableWidgetItem(str(rank))
rank_item.setFlags(rank_item.flags() & ~Qt.ItemFlag.ItemIsEditable)
rank_item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
self.creatures_table.setItem(i, 1, rank_item)
# Progress bar
progress = creature.get('progress', 0)
progress_widget = QWidget()
progress_layout = QHBoxLayout(progress_widget)
progress_layout.setContentsMargins(5, 2, 5, 2)
bar = QProgressBar()
bar.setValue(int(progress))
bar.setTextVisible(True)
bar.setFormat(f"{progress:.1f}%")
bar.setStyleSheet("""
QProgressBar {
background-color: rgba(60, 70, 90, 150);
border: none;
border-radius: 3px;
text-align: center;
color: white;
font-size: 10px;
}
QProgressBar::chunk {
background-color: #ff8c42;
border-radius: 3px;
}
""")
progress_layout.addWidget(bar)
self.creatures_table.setCellWidget(i, 2, progress_widget)
# Next rank (estimated kills needed)
progress_item = QTableWidgetItem(f"~{int((100-progress) * 120)} kills")
progress_item.setFlags(progress_item.flags() & ~Qt.ItemFlag.ItemIsEditable)
progress_item.setForeground(Qt.GlobalColor.gray)
self.creatures_table.setItem(i, 3, progress_item)
def _scan_codex(self):
"""Scan codex window with OCR."""
# TODO: Implement OCR scanning
# For now, simulate update
for creature in self.creatures:
creature['progress'] = min(100, creature.get('progress', 0) + 0.5)
self._save_data()
self._refresh_table()
def get_closest_to_rankup(self, count=3):
"""Get creatures closest to ranking up."""
sorted_creatures = sorted(
self.creatures,
key=lambda x: -(x.get('progress', 0))
)
return [c for c in sorted_creatures[:count] if c.get('progress', 0) < 100]
def get_recommended_hunt(self):
"""Get recommended creature to hunt."""
close = self.get_closest_to_rankup(1)
return close[0] if close else None