219 lines
7.7 KiB
Python
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
|