316 lines
10 KiB
Python
316 lines
10 KiB
Python
"""
|
|
EU-Utility - Mission Tracker Plugin
|
|
|
|
Track active missions and progress.
|
|
"""
|
|
|
|
import json
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
|
|
from PyQt6.QtWidgets import (
|
|
QWidget, QVBoxLayout, QHBoxLayout, QLabel,
|
|
QPushButton, QProgressBar, QFrame, QScrollArea
|
|
)
|
|
from PyQt6.QtCore import Qt
|
|
|
|
from plugins.base_plugin import BasePlugin
|
|
from core.icon_manager import get_icon_manager
|
|
|
|
|
|
class MissionTrackerPlugin(BasePlugin):
|
|
"""Track active missions and daily challenges."""
|
|
|
|
name = "Mission Tracker"
|
|
version = "1.0.0"
|
|
author = "ImpulsiveFPS"
|
|
description = "Track missions, challenges, and objectives"
|
|
hotkey = "ctrl+shift+m"
|
|
|
|
def initialize(self):
|
|
"""Setup mission tracker."""
|
|
self.data_file = Path("data/missions.json")
|
|
self.data_file.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
self.missions = []
|
|
self.daily_challenges = []
|
|
|
|
self._load_data()
|
|
|
|
def _load_data(self):
|
|
"""Load mission data."""
|
|
if self.data_file.exists():
|
|
try:
|
|
with open(self.data_file, 'r') as f:
|
|
data = json.load(f)
|
|
self.missions = data.get('missions', [])
|
|
self.daily_challenges = data.get('daily', [])
|
|
except:
|
|
pass
|
|
|
|
def _save_data(self):
|
|
"""Save mission data."""
|
|
with open(self.data_file, 'w') as f:
|
|
json.dump({
|
|
'missions': self.missions,
|
|
'daily': self.daily_challenges
|
|
}, f, indent=2)
|
|
|
|
def get_ui(self):
|
|
"""Create mission tracker UI."""
|
|
widget = QWidget()
|
|
widget.setStyleSheet("background: transparent;")
|
|
layout = QVBoxLayout(widget)
|
|
layout.setSpacing(15)
|
|
layout.setContentsMargins(0, 0, 0, 0)
|
|
|
|
# Title
|
|
title = QLabel("📜 Mission Tracker")
|
|
title.setStyleSheet("""
|
|
color: white;
|
|
font-size: 16px;
|
|
font-weight: bold;
|
|
""")
|
|
layout.addWidget(title)
|
|
|
|
# Active missions section
|
|
active_label = QLabel("Active Missions")
|
|
active_label.setStyleSheet("color: rgba(255,255,255,200); font-size: 12px;")
|
|
layout.addWidget(active_label)
|
|
|
|
# Mission cards
|
|
self.missions_container = QWidget()
|
|
self.missions_layout = QVBoxLayout(self.missions_container)
|
|
self.missions_layout.setSpacing(10)
|
|
self.missions_layout.setContentsMargins(0, 0, 0, 0)
|
|
|
|
self._refresh_missions()
|
|
layout.addWidget(self.missions_container)
|
|
|
|
# Daily challenges
|
|
daily_label = QLabel("Daily Challenges")
|
|
daily_label.setStyleSheet("color: rgba(255,255,255,200); font-size: 12px; margin-top: 10px;")
|
|
layout.addWidget(daily_label)
|
|
|
|
self.daily_container = QWidget()
|
|
self.daily_layout = QVBoxLayout(self.daily_container)
|
|
self.daily_layout.setSpacing(8)
|
|
self.daily_layout.setContentsMargins(0, 0, 0, 0)
|
|
|
|
self._refresh_daily()
|
|
layout.addWidget(self.daily_container)
|
|
|
|
# Add mission button
|
|
add_btn = QPushButton("+ Add Mission")
|
|
add_btn.setStyleSheet("""
|
|
QPushButton {
|
|
background-color: rgba(255, 140, 66, 200);
|
|
color: white;
|
|
padding: 10px;
|
|
border: none;
|
|
border-radius: 4px;
|
|
font-weight: bold;
|
|
}
|
|
QPushButton:hover {
|
|
background-color: rgba(255, 160, 80, 230);
|
|
}
|
|
""")
|
|
add_btn.clicked.connect(self._add_mission)
|
|
layout.addWidget(add_btn)
|
|
|
|
layout.addStretch()
|
|
return widget
|
|
|
|
def _create_mission_card(self, mission):
|
|
"""Create a mission card widget."""
|
|
card = QFrame()
|
|
card.setStyleSheet("""
|
|
QFrame {
|
|
background-color: rgba(30, 35, 45, 200);
|
|
border: 1px solid rgba(100, 110, 130, 80);
|
|
border-radius: 6px;
|
|
}
|
|
""")
|
|
layout = QVBoxLayout(card)
|
|
layout.setContentsMargins(12, 10, 12, 10)
|
|
layout.setSpacing(8)
|
|
|
|
# Header
|
|
header = QHBoxLayout()
|
|
|
|
name = QLabel(mission.get('name', 'Unknown Mission'))
|
|
name.setStyleSheet("color: #ff8c42; font-weight: bold; font-size: 12px;")
|
|
header.addWidget(name)
|
|
|
|
header.addStretch()
|
|
|
|
# Complete button
|
|
complete_btn = QPushButton("✓")
|
|
complete_btn.setFixedSize(24, 24)
|
|
complete_btn.setStyleSheet("""
|
|
QPushButton {
|
|
background-color: rgba(76, 175, 80, 150);
|
|
color: white;
|
|
border: none;
|
|
border-radius: 3px;
|
|
font-weight: bold;
|
|
}
|
|
QPushButton:hover {
|
|
background-color: rgba(76, 175, 80, 200);
|
|
}
|
|
""")
|
|
complete_btn.clicked.connect(lambda: self._complete_mission(mission))
|
|
header.addWidget(complete_btn)
|
|
|
|
layout.addLayout(header)
|
|
|
|
# Progress
|
|
current = mission.get('current', 0)
|
|
total = mission.get('total', 1)
|
|
pct = min(100, int(current / total * 100))
|
|
|
|
progress_layout = QHBoxLayout()
|
|
|
|
progress = QProgressBar()
|
|
progress.setValue(pct)
|
|
progress.setTextVisible(False)
|
|
progress.setFixedHeight(6)
|
|
progress.setStyleSheet("""
|
|
QProgressBar {
|
|
background-color: rgba(60, 70, 90, 150);
|
|
border: none;
|
|
border-radius: 3px;
|
|
}
|
|
QProgressBar::chunk {
|
|
background-color: #ff8c42;
|
|
border-radius: 3px;
|
|
}
|
|
""")
|
|
progress_layout.addWidget(progress, 1)
|
|
|
|
progress_text = QLabel(f"{current}/{total}")
|
|
progress_text.setStyleSheet("color: rgba(255,255,255,150); font-size: 10px;")
|
|
progress_layout.addWidget(progress_text)
|
|
|
|
layout.addLayout(progress_layout)
|
|
|
|
return card
|
|
|
|
def _create_challenge_card(self, challenge):
|
|
"""Create a daily challenge card."""
|
|
card = QFrame()
|
|
card.setStyleSheet("""
|
|
QFrame {
|
|
background-color: rgba(25, 30, 40, 180);
|
|
border: 1px solid rgba(80, 90, 110, 60);
|
|
border-radius: 4px;
|
|
}
|
|
""")
|
|
layout = QHBoxLayout(card)
|
|
layout.setContentsMargins(10, 8, 10, 8)
|
|
layout.setSpacing(10)
|
|
|
|
# Icon based on type
|
|
icon_mgr = get_icon_manager()
|
|
icon_label = QLabel()
|
|
icon_pixmap = icon_mgr.get_pixmap('sword', size=16)
|
|
icon_label.setPixmap(icon_pixmap)
|
|
icon_label.setFixedSize(16, 16)
|
|
layout.addWidget(icon_label)
|
|
|
|
# Name
|
|
name = QLabel(challenge.get('name', 'Challenge'))
|
|
name.setStyleSheet("color: white; font-size: 11px;")
|
|
layout.addWidget(name)
|
|
|
|
layout.addStretch()
|
|
|
|
# Progress
|
|
current = challenge.get('current', 0)
|
|
total = challenge.get('total', 1)
|
|
pct = min(100, int(current / total * 100))
|
|
|
|
progress = QProgressBar()
|
|
progress.setValue(pct)
|
|
progress.setTextVisible(False)
|
|
progress.setFixedSize(60, 4)
|
|
progress.setStyleSheet("""
|
|
QProgressBar {
|
|
background-color: rgba(60, 70, 90, 150);
|
|
border: none;
|
|
border-radius: 2px;
|
|
}
|
|
QProgressBar::chunk {
|
|
background-color: #ffc107;
|
|
border-radius: 2px;
|
|
}
|
|
""")
|
|
layout.addWidget(progress)
|
|
|
|
text = QLabel(f"{current}/{total}")
|
|
text.setStyleSheet("color: rgba(255,255,255,120); font-size: 10px;")
|
|
layout.addWidget(text)
|
|
|
|
return card
|
|
|
|
def _refresh_missions(self):
|
|
"""Refresh mission display."""
|
|
# Clear existing
|
|
while self.missions_layout.count():
|
|
item = self.missions_layout.takeAt(0)
|
|
if item.widget():
|
|
item.widget().deleteLater()
|
|
|
|
# Add missions
|
|
for mission in self.missions:
|
|
card = self._create_mission_card(mission)
|
|
self.missions_layout.addWidget(card)
|
|
|
|
def _refresh_daily(self):
|
|
"""Refresh daily challenges."""
|
|
while self.daily_layout.count():
|
|
item = self.daily_layout.takeAt(0)
|
|
if item.widget():
|
|
item.widget().deleteLater()
|
|
|
|
for challenge in self.daily_challenges:
|
|
card = self._create_challenge_card(challenge)
|
|
self.daily_layout.addWidget(card)
|
|
|
|
def _add_mission(self):
|
|
"""Add a new mission."""
|
|
# Add sample mission
|
|
self.missions.append({
|
|
'name': 'Oratan Payback Mission III',
|
|
'current': 0,
|
|
'total': 100,
|
|
'type': 'kill',
|
|
'target': 'Oratan Prospector Bandits',
|
|
'added': datetime.now().isoformat()
|
|
})
|
|
self._save_data()
|
|
self._refresh_missions()
|
|
|
|
def _complete_mission(self, mission):
|
|
"""Mark mission as complete."""
|
|
if mission in self.missions:
|
|
self.missions.remove(mission)
|
|
self._save_data()
|
|
self._refresh_missions()
|
|
|
|
def parse_chat_message(self, message):
|
|
"""Parse mission progress from chat."""
|
|
# Look for mission progress
|
|
# Example: "Mission updated: 12/100 Oratan Prospector Bandits"
|
|
for mission in self.missions:
|
|
target = mission.get('target', '')
|
|
if target and target in message:
|
|
# Extract progress
|
|
import re
|
|
match = re.search(r'(\d+)/(\d+)', message)
|
|
if match:
|
|
mission['current'] = int(match.group(1))
|
|
mission['total'] = int(match.group(2))
|
|
self._save_data()
|
|
self._refresh_missions()
|