-
Notifications
You must be signed in to change notification settings - Fork 10
Feature/bugs and extra modules #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
b644627
006a887
2e336c8
259c985
6d57dd0
16390d6
8394527
a1f4f20
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,3 @@ | ||
| DQconfig.ini | ||
| PARconfig.ini | ||
| PyAutoRaid.log |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,10 +12,15 @@ | |
| import threading | ||
| from screeninfo import get_monitors | ||
| from tkinter import messagebox | ||
| from tkinter import scrolledtext | ||
| from tkinter import ttk | ||
| from tkinter import * | ||
| from ttkthemes import ThemedTk | ||
| import pyscreeze | ||
| from faction_wars.FactionWars import FactionWarsCommand | ||
| from dungeons.IronTwins import IronTwinsCommand | ||
| from doom_tower.DoomTower import DoomTowerCommand | ||
|
|
||
| pyscreeze.USE_IMAGE_NOT_FOUND_EXCEPTION = False | ||
| # Configure logging | ||
| logging.basicConfig( | ||
|
|
@@ -773,11 +778,14 @@ def __init__(self, master): | |
| self.AS_bought = 0 | ||
| self.MS_bought = 0 | ||
| self.manual_run_triggered = False | ||
|
|
||
| self.command_registry = { | ||
| 'rewards': RewardsCommand(self), | ||
| 'daily_ten_classic_arena': DailyTenClassicArenaCommand(self), | ||
| 'clanboss': ClanBossCommand(self), | ||
| 'faction_wars': FactionWarsCommand(self, logger), | ||
| 'iron_twins': IronTwinsCommand(self, logger), | ||
| 'doom_tower': DoomTowerCommand(self, logger) | ||
| # Add other commands as needed | ||
| } | ||
|
|
||
|
|
@@ -865,20 +873,43 @@ def Check_os(self): | |
|
|
||
| def find_raid_path(self): | ||
| try: | ||
| logger.info("Starting focused search for Raid.exe...") | ||
| appdata_local = os.path.join(os.environ['LOCALAPPDATA']) | ||
| raid_feature = "Raid.exe" | ||
| for root, dirs, files in os.walk(appdata_local): | ||
| if raid_feature in dirs or raid_feature in files: | ||
|
|
||
| # Most specific likely path | ||
| current_path = os.path.join(appdata_local, "PlariumPlay", "StandAloneApps", "raid-shadow-legends") | ||
|
|
||
| # Step 1: Check if the likely path exists; move backward if it doesn't | ||
| while not os.path.exists(current_path) and current_path != appdata_local: | ||
| logger.debug(f"Path not found: {current_path}. Moving to parent directory.") | ||
| current_path = os.path.dirname(current_path) | ||
|
|
||
| if not os.path.exists(current_path): | ||
| logger.error("No valid path found starting from likely paths.") | ||
| self.steps["Raid_path"] = "False" | ||
| sys.exit(1) | ||
|
|
||
| logger.debug(f"Valid path found: {current_path}. Starting recursive search here.") | ||
|
|
||
| # Step 2: Perform a recursive search starting from the valid path | ||
| for root, dirs, files in os.walk(current_path, topdown=True): | ||
| # Check for the target file | ||
| if raid_feature in files: | ||
| raidloc = os.path.join(root, raid_feature) | ||
| logging.debug(f"Found Raid.exe installed at {raidloc}") | ||
| logger.debug(f"Found Raid.exe at {raidloc}") | ||
| self.steps["Raid_path"] = "True" | ||
| return raidloc | ||
|
|
||
| # Step 3: If not found, log an error | ||
| self.steps["Raid_path"] = "False" | ||
| logging.error("Raid.exe was not found.") | ||
| logger.error("Raid.exe was not found after recursive search.") | ||
| sys.exit(1) | ||
|
|
||
| except Exception as e: | ||
| logger.error(f"Error in find_raid_path: {e}") | ||
|
|
||
|
|
||
| def get_asset_path(self): | ||
| try: | ||
| # Start with the directory of the current script | ||
|
|
@@ -1009,19 +1040,33 @@ def get_screen_info(self): | |
| self.width = m.width | ||
| self.height = m.height | ||
| main = m.is_primary | ||
| if self.width != 1920 or self.height != 1080: | ||
| tkinter.messagebox.showerror( | ||
| "Warning", | ||
| "Your Screen pixel is not 1920 by 1080. This may cause issues", | ||
| ) | ||
| logger.warning("Screen resolution is not 1920x1080.") | ||
| if main == True: | ||
|
|
||
| # Log screen resolution | ||
| logger.info(f"Detected screen resolution: width={self.width}, height={self.height}, primary={main}") | ||
|
|
||
| if main: # Only consider the primary monitor | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have two different sized monitors and this error kept kicking off for me even though my main is set to 1920x1080. |
||
| if self.width != 1920 or self.height != 1080: | ||
| logger.warning("Screen resolution is not 1920x1080. This may cause issues.") | ||
| tkinter.messagebox.showerror( | ||
| "Warning", | ||
| "Your screen resolution is not 1920x1080. This may cause issues.", | ||
| ) | ||
| else: | ||
| logger.info("Screen resolution is 1920x1080.") | ||
|
|
||
| center_width = int((self.width / 2) - 450) | ||
| center_height = int((self.height / 2) - 300) | ||
| logger.info(f"Screen info obtained: width={self.width}, height={self.height}") | ||
| logger.info(f"Screen info obtained: center_width={center_width}, center_height={center_height}") | ||
| return (center_width, center_height) | ||
|
|
||
| # If no primary monitor was detected | ||
| logger.error("No primary monitor detected.") | ||
| raise RuntimeError("No primary monitor detected.") | ||
|
|
||
| except Exception as e: | ||
| logger.error(f"Error in get_screen_info: {e}") | ||
| raise | ||
|
|
||
|
|
||
| def window_sizing_centering(self): | ||
| try: | ||
|
|
@@ -1044,10 +1089,12 @@ def initiate_raid(self, not_open): | |
| try: | ||
| self.window_sizing_centering() | ||
| exit_add_image = os.path.join(self.asset_path, "exitAdd.png") | ||
| home_battle_button = os.path.join(self.asset_path, "battleBTN.png") | ||
|
|
||
| while True: | ||
| try: | ||
| # Attempt to locate the image | ||
| if pyautogui.locateOnScreen(exit_add_image, confidence=0.7) is not None: | ||
| if pyautogui.locateOnScreen(exit_add_image, confidence=0.7) is not None or pyautogui.locateOnScreen(home_battle_button, confidence=0.7): | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If exit image wasn't on the screen it would loop here without the tk ui popping up. Now I also check for being on the bastion without a pop up by looking for the battle button
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've realised this one might not be the intention you had. Is it supposed to attempt to escape so the exit button comes up and then close to make sure we are in the bastion without popups? |
||
| logger.info("Image found. Breaking the loop.") | ||
| break | ||
| else: | ||
|
|
@@ -1137,7 +1184,6 @@ def run(self): | |
| os.system("taskkill /f /im Raid.exe") | ||
| break | ||
|
|
||
| # GUI class with error handling and logging | ||
| class GUI: | ||
| def __init__(self, master): | ||
| try: | ||
|
|
@@ -1156,7 +1202,7 @@ def __init__(self, master): | |
| # Creating a ttk Frame which will contain all other widgets | ||
| main_frame = ttk.Frame(master) | ||
| main_frame.pack(fill=tkinter.BOTH, expand=True) | ||
| config_keys = ['rewards', 'daily_ten_classic_arena', 'clanboss'] | ||
| config_keys = ['rewards', 'daily_ten_classic_arena', 'clanboss', 'faction_wars', 'iron_twins', 'doom_tower'] | ||
| # Automated Mode Checkbox | ||
| self.automated_mode = tkinter.IntVar() | ||
| if settings_config.get("automated_mode") == 'True': | ||
|
|
@@ -1177,7 +1223,7 @@ def checkbox_callback(var_name, index, mode, config_key, var): | |
|
|
||
| # Other Checkboxes | ||
| self.checkbox_texts = [ | ||
| "Collect Rewards", "Ten Classic Arena Battles", "Clan Boss", | ||
| "Collect Rewards", "Ten Classic Arena Battles", "Clan Boss", "Faction Wars", "Iron Twins", "Doom Tower" | ||
| ] | ||
| self.checkboxes = [] | ||
| self.vars = [] | ||
|
|
@@ -1200,6 +1246,18 @@ def checkbox_callback(var_name, index, mode, config_key, var): | |
|
|
||
| self.btn_quit_all = ttk.Button(main_frame, text="Quit All", command=self.quit_all) | ||
| self.btn_quit_all.grid(row=len(self.checkbox_texts) + 3, column=1, padx=10, pady=(5, 5), sticky="E") | ||
|
|
||
| # Separator above the log box | ||
| self.separator2 = ttk.Separator(main_frame, orient='horizontal') | ||
| self.separator2.grid(row=len(self.checkbox_texts) + 4, column=0, columnspan=2, padx=10, pady=5, sticky="EW") | ||
|
|
||
| # Log Text Box | ||
| self.log_text = scrolledtext.ScrolledText(main_frame, wrap=tkinter.WORD, height=10, state="disabled") | ||
| self.log_text.grid(row=len(self.checkbox_texts) + 5, column=0, columnspan=2, padx=10, pady=(5, 10), sticky="EW") | ||
|
|
||
| # Redirect logs to the text box | ||
| self.redirect_logs() | ||
|
|
||
| logger.info("GUI initialized successfully.") | ||
| except Exception as e: | ||
| logger.error(f"Error initializing GUI: {e}") | ||
|
|
@@ -1237,6 +1295,24 @@ def timer_thread(self): | |
| logger.info("Timer thread started.") | ||
| except Exception as e: | ||
| logger.error(f"Error in timer_thread: {e}") | ||
|
|
||
| def redirect_logs(self): | ||
| """Redirect log output to the text box.""" | ||
| class TextHandler(logging.Handler): | ||
| def __init__(self, widget): | ||
| super().__init__() | ||
| self.widget = widget | ||
|
|
||
| def emit(self, record): | ||
| msg = self.format(record) | ||
| self.widget.config(state="normal") | ||
| self.widget.insert(tkinter.END, msg + "\n") | ||
| self.widget.config(state="disabled") | ||
| self.widget.see(tkinter.END) | ||
|
|
||
| handler = TextHandler(self.log_text) | ||
| handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")) | ||
| logger.addHandler(handler) | ||
|
|
||
| def on_closing(): | ||
| try: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| import os | ||
| import time | ||
| import pyautogui | ||
|
|
||
| class Command: | ||
| def execute(self): | ||
| pass | ||
|
|
||
| class DoomTowerCommand(Command): | ||
| def __init__(self, app, logger): | ||
| self.app = app | ||
| self.logger = logger | ||
|
|
||
| def execute(self): | ||
| try: | ||
| self.logger.info("Starting Doom Tower task.") | ||
|
|
||
| # Define image paths | ||
| battle_btn_image = os.path.join(self.app.asset_path, "battleBTN.png") | ||
| doom_tower_image = os.path.join(self.app.asset_path, "doomTower.png") | ||
| doom_tower_next_stage = os.path.join(self.app.asset_path, "doomTowerNextStage.png") | ||
| doom_tower_start_battle = os.path.join(self.app.asset_path, "doomTowerStartBattle.png") | ||
| doom_tower_stages_screen = os.path.join(self.app.asset_path, "doomTowerScreen.png") | ||
| in_battle_image = os.path.join(self.app.asset_path, "inBattle.png") | ||
| in_mutli_battle_image = os.path.join(self.app.asset_path, "turnOffMultiBattle.png") | ||
| mutli_battle_complete_image = os.path.join(self.app.asset_path, "mutliBattleComplete.png") | ||
|
|
||
| self.logger.info("Attempting to close any existing pop-ups.") | ||
| self.app.delete_popup() | ||
|
|
||
| # Navigate to battle screen | ||
| time.sleep(2) | ||
| self.click_image(battle_btn_image, "Battle button") | ||
|
|
||
| # Navigate to Doom Tower | ||
| pyautogui.moveTo(960, 540) | ||
| pyautogui.dragRel(-600, 0, duration=0.5) | ||
| time.sleep(2) | ||
| self.click_image(doom_tower_image, "Doom Tower button") | ||
| time.sleep(2) | ||
|
|
||
| # Loop through this to complete Auto Climb and then Tower - Or replay failed stages | ||
| while pyautogui.locateOnScreen(doom_tower_next_stage, confidence=0.8): | ||
| self.click_image(doom_tower_next_stage, "Doom Tower Next Stage") | ||
|
|
||
| # If Wave stage Start Multi Battle | ||
| x, y = pyautogui.locateCenterOnScreen(doom_tower_start_battle, confidence=0.8) | ||
| pyautogui.click(x, y) | ||
| self.logger.info(f"Clicked on Doom Tower Start Battle at coordinates ({x}, {y}).") | ||
| time.sleep(2) | ||
|
|
||
| if pyautogui.locateOnScreen(doom_tower_start_battle, confidence=0.8): | ||
| self.logger.info("Must not have enough keys. Doom Tower Comlete") | ||
| pyautogui.press("esc") | ||
| time.sleep(1) | ||
| pyautogui.press("esc") | ||
| time.sleep(1) | ||
|
|
||
|
|
||
| # Wait for battle to complete | ||
| while pyautogui.locateOnScreen(in_battle_image, confidence=0.8) or pyautogui.locateOnScreen(in_mutli_battle_image, confidence=0.8): | ||
| self.logger.info("Waiting for the battle results.") | ||
| time.sleep(10) | ||
| while pyautogui.locateOnScreen(mutli_battle_complete_image, confidence=0.8): | ||
| # Back to doom tower to check if the boss is ready or failed run | ||
| pyautogui.press("esc") | ||
| time.sleep(1) | ||
| pyautogui.press("esc") | ||
| time.sleep(1) | ||
|
|
||
| if not pyautogui.locateOnScreen(doom_tower_stages_screen, confidence=0.7): | ||
| self.logger.info("Can't find doom tower stages screen.") | ||
|
|
||
| # If Boss Stage Click Boss Right Hand Side | ||
| if pyautogui.locateOnScreen(doom_tower_stages_screen, confidence=0.7): | ||
| self.logger.info("Found doom tower stages screen. Clicking Right Side") | ||
| pyautogui.click(1250, 500) | ||
| time.sleep(2) | ||
|
|
||
| # Click on boss that is stage 120 | ||
| if pyautogui.locateOnScreen(doom_tower_stages_screen, confidence=0.7): | ||
| self.logger.info("Found doom tower stages screen. Clicking Middle (for stage 120)") | ||
| pyautogui.click(950, 500) | ||
| time.sleep(2) | ||
|
|
||
| self.click_image(doom_tower_start_battle, "Doom Tower Start Battle") | ||
| time.sleep(5) | ||
| # Wait for battle to complete | ||
| while pyautogui.locateOnScreen(in_battle_image, confidence=0.8): | ||
| self.logger.info("Waiting for the battle results.") | ||
| time.sleep(10) | ||
|
|
||
| pyautogui.press("esc") | ||
| self.app.back_to_bastion() | ||
| self.logger.info("Doom Tower task completed successfully.") | ||
| except Exception as e: | ||
| self.logger.error(f"Error in DoomTowerCommand: {e}", exc_info=True) | ||
| self.app.back_to_bastion() | ||
|
|
||
| def click_image(self, imagePath, description, retry=True): | ||
| """Helper to click an image on screen.""" | ||
| if retry: | ||
| # Retry until the image is found and clicked | ||
| while pyautogui.locateOnScreen(imagePath, confidence=0.8): | ||
| x, y = pyautogui.locateCenterOnScreen(imagePath, confidence=0.8) | ||
| pyautogui.click(x, y) | ||
| self.logger.info(f"Clicked on {description} at coordinates ({x}, {y}).") | ||
| time.sleep(2) | ||
| else: | ||
| # Single attempt to click the image | ||
| location = pyautogui.locateOnScreen(imagePath, confidence=0.8) | ||
| if location: | ||
| x, y = pyautogui.locateCenterOnScreen(imagePath, confidence=0.8) | ||
| pyautogui.click(x, y) | ||
| time.sleep(2) | ||
| self.logger.info(f"Clicked on {description} at coordinates ({x}, {y}).") | ||
| else: | ||
| self.logger.warning(f"{description} not found for a single click attempt.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Making this change made my start up time go from 1min to 2s