#!/usr/bin/env python3 """ Flyff - Leveling Predictor Node: - Tracks the last N changes in EXP values. - Calculates the average change rate and time intervals. - Predicts the estimated time to reach level 100. """ import time import numpy as np from OdenGraphQt import BaseNode from PyQt5.QtCore import QTimer from Modules import data_manager class FlyffLevelingPredictorNode(BaseNode): __identifier__ = "bunny-lab.io.flyff_leveling_predictor_node" NODE_NAME = "Flyff - Leveling Predictor" def __init__(self): super(FlyffLevelingPredictorNode, self).__init__() # Input port for EXP values self.add_input("exp", "EXP") # User-defined number of changes to track self.add_text_input("exp_track_count", "# of EXP Changes to Track", text="7") # Output widgets self.add_text_input("time_to_level", "Time to Level", text="Calculating...") self.add_text_input("time_between_kills", "Time Between Kills", text="N/A") self.add_text_input("exp_per_kill", "EXP Per Kill", text="N/A") # Internal tracking lists self.exp_history = [] self.time_intervals = [] self.last_exp_value = None self.last_update_time = None # Timer to periodically process EXP changes self.timer = QTimer() self.timer.timeout.connect(self.process_exp_change) self.timer.start(1000) # Check for updates every second def reset_tracking_arrays(self): """ Resets the EXP history and time interval arrays when a level-up is detected. """ self.exp_history.clear() self.time_intervals.clear() self.last_exp_value = None self.last_update_time = None def process_exp_change(self): """ Monitors changes in EXP values and calculates various statistics. """ exp_value = data_manager.get_data().get("exp", None) if exp_value is None: return exp_track_count = self.get_property("exp_track_count") try: exp_track_count = int(exp_track_count) except ValueError: exp_track_count = 7 # Default to 7 if invalid input # Reset if EXP value decreases (indicating a level-up) if self.last_exp_value is not None and exp_value < self.last_exp_value: self.reset_tracking_arrays() if self.last_exp_value is not None and exp_value != self.last_exp_value: current_time = time.time() # Store EXP change history self.exp_history.append(exp_value) if len(self.exp_history) > exp_track_count: self.exp_history.pop(0) # Store time intervals if self.last_update_time is not None: interval = current_time - self.last_update_time self.time_intervals.append(interval) if len(self.time_intervals) > exp_track_count: self.time_intervals.pop(0) # Perform calculations self.calculate_time_to_level() self.calculate_additional_metrics() # Update last tracking values self.last_update_time = current_time self.last_exp_value = exp_value def calculate_time_to_level(self): """ Calculates the estimated time to reach level 100 based on EXP change history. """ if len(self.exp_history) < 2 or len(self.time_intervals) < 1: self.set_property("time_to_level", "Insufficient data") return exp_deltas = np.diff(self.exp_history) # Compute EXP change per interval avg_exp_change = np.mean(exp_deltas) if len(exp_deltas) > 0 else 0 avg_time_change = np.mean(self.time_intervals) if avg_exp_change <= 0: self.set_property("time_to_level", "Not gaining EXP") return current_exp = self.exp_history[-1] remaining_exp = 100.0 - current_exp # Distance to level 100 estimated_time = (remaining_exp / avg_exp_change) * avg_time_change # Convert estimated time into hours, minutes, and seconds hours = int(estimated_time // 3600) minutes = int((estimated_time % 3600) // 60) seconds = int(estimated_time % 60) time_str = f"{hours}h {minutes}m {seconds}s" self.set_property("time_to_level", time_str) def calculate_additional_metrics(self): """ Calculates and updates the "Time Between Kills" and "EXP Per Kill". """ if len(self.time_intervals) > 0: avg_time_between_kills = np.mean(self.time_intervals) minutes = int(avg_time_between_kills // 60) seconds = int(avg_time_between_kills % 60) self.set_property("time_between_kills", f"{minutes}m {seconds}s") else: self.set_property("time_between_kills", "N/A") if len(self.exp_history) > 1: exp_deltas = np.diff(self.exp_history) avg_exp_per_kill = np.mean(exp_deltas) if len(exp_deltas) > 0 else 0 self.set_property("exp_per_kill", f"{avg_exp_per_kill:.2f}%") else: self.set_property("exp_per_kill", "N/A")