""" 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