def __init__(self, connectImmediately: bool = False): super(QObject, self).__init__() self.currentLevel = 0 self.currentDungeon = 6 self.statisctics_manager = StatisticsManager() self.start_date = datetime.now() self.stat_lvl_start = 0 self.screen_connector = GameScreenConnector() self.screen_connector.debug = False self.width, self.heigth = 1080, 2220 self.device_connector = UsbConnector() self.device_connector.setFunctionToCallOnConnectionStateChanged(self.onConnectionStateChanged) self.buttons = {} self.movements = {} self.stopRequested = False self.currentDataFolder = "" self.dataFolders = {} self.healingStrategy = HealingStrategy.AlwaysPowerUp self.centerAfterCrossingDungeon = False if connectImmediately: self.initDeviceConnector() self.check_seconds = 4
class CaveEngine(QObject): levelChanged = pyqtSignal(int) addLog = pyqtSignal(str) resolutionChanged = pyqtSignal(int, int) dataFolderChanged = pyqtSignal(str) noEnergyLeft = pyqtSignal() gameWon = pyqtSignal() healingStrategyChanged = pyqtSignal(bool) # onDictionaryTapsChanged = pyqtSignal(dict) # onButtonLocationChanged = pyqtSignal(str) # onImageSelected = pyqtSignal() MAX_LEVEL = 20 playtime = 70 # Set this to true if you want to use generated data with TouchManager. Uses below coordinates path UseGeneratedData = False # Set this to true if keep receiving "No energy, wqiting for one minute" UseManualStart = False # Set this to true if want to automatically check for energy SkipEnergyCheck = False data_pack = 'datas' coords_path = 'coords' buttons_filename = "buttons.json" movements_filename = "movements.json" print_names_movements = { "n": "up", "s": "down", "e": "right", "w": "left", "ne": "up-right", "nw": "up-left", "se": "down-right", "sw": "down-left", } t_intro = 'intro' t_normal = 'normal' t_heal = 'heal' t_boss = 'boss' t_final_boss = 'final_boss' levels_type = { 0: t_intro, 1: t_normal, 2: t_heal, 3: t_normal, 4: t_heal, 5: t_boss, 6: t_normal, 7: t_heal, 8: t_normal, 9: t_heal, 10: t_boss, 11: t_normal, 12: t_heal, 13: t_normal, 14: t_heal, 15: t_boss, 16: t_normal, 17: t_heal, 18: t_normal, 19: t_heal, 20: t_final_boss, } max_loops_game = 20 def __init__(self, connectImmediately: bool = False): super(QObject, self).__init__() self.currentLevel = 0 self.currentDungeon = 6 self.statisctics_manager = StatisticsManager() self.start_date = datetime.now() self.stat_lvl_start = 0 self.screen_connector = GameScreenConnector() self.screen_connector.debug = False self.width, self.heigth = 1080, 2220 self.device_connector = UsbConnector() self.device_connector.setFunctionToCallOnConnectionStateChanged(self.onConnectionStateChanged) self.buttons = {} self.movements = {} self.disableLogs = False self.stopRequested = False self.currentDataFolder = '' self.dataFolders = {} self.healingStrategy = HealingStrategy.AlwaysPowerUp self.centerAfterCrossingDungeon = False if connectImmediately: self.initDeviceConnector() self.check_seconds = 4 def initDataFolders(self): self.dataFolders = readAllSizesFolders() deviceFolder = buildDataFolder(self.width, self.heigth) first_folder = list(self.dataFolders.keys())[0] if deviceFolder not in self.dataFolders: print("Error: not having %s coordinates. Trying with %s" % (deviceFolder, first_folder)) deviceFolder = first_folder self.changeCurrentDataFolder(deviceFolder) def initdeviceconnector(self): self.device_connector.connect() def changeHealStrategy(self, always_heal: bool): self.healingStrategy = HealingStrategy.AlwaysHeal if always_heal else HealingStrategy.AlwaysPowerUp self.healingStrategyChanged.emit(always_heal) def changeChapter(self, new_chapter): self.currentDungeon = new_chapter def onConnectionStateChanged(self): if self.device_connector.connected: self.initDataFolders() self.screen_connector.changeDeviceConnector(self.device_connector) self.updateScreenSizeByPhone() def updateScreenSizeByPhone(self): if self.device_connector is not None: w, h = self.device_connector.adb_get_size() self.changeScreenSize(w, h) self.screen_connector.changeScreenSize(w, h) else: print("Device connector is none. initialize it before calling this method!") def changeCurrentDataFolder(self, new_folder): self.currentDataFolder = new_folder self.loadCoords() self.dataFolderChanged.emit(new_folder) def loadCoords(self): self.buttons = loadJsonData(getCoordFilePath(self.buttons_filename, sizePath=self.currentDataFolder)) self.movements = loadJsonData(getCoordFilePath(self.movements_filename, sizePath=self.currentDataFolder)) def setStopRequested(self): self.stopRequested = True self.screen_connector.stopRequested = True self.statisctics_manager.saveOneGame(self.start_date, self.stat_lvl_start, self.currentLevel) def changeScreenSize(self, w, h): self.width, self.heigth = w, h print("New resolution set: %dx%d" % (self.width, self.heigth)) self.resolutionChanged.emit(w, h) def __unused__initConnection(self): device = self.device_connector._get_device_id() if device is None: print("Error: no device discovered. Start adb server before executing this.") exit(1) print("Usb debugging device: %s" % device) def log(self, log: str): """ Logs an important move in the bot game """ if not self.disableLogs: self.addLog.emit(log) def swipe_points(self, start, stop, s): start = self.buttons[start] stop = self.buttons[stop] print("Swiping between %s and %s in %f" % (start, stop, s)) self.device_connector.adb_swipe( [start[0] * self.width, start[1] * self.heigth, stop[2] * self.width, stop[3] * self.heigth], s) def swipe(self, name, s): if self.stopRequested: exit() coord = self.movements[name] print("Swiping %s in %f" % (self.print_names_movements[name], s)) self.log("Swipe %s in %.2f" % (self.print_names_movements[name], s)) # convert back from normalized values self.device_connector.adb_swipe( [coord[0][0] * self.width, coord[0][1] * self.heigth, coord[1][0] * self.width, coord[1][1] * self.heigth], s) def tap(self, name): if self.stopRequested: exit() self.log("Tap %s" % name) # convert back from normalized values x, y = int(self.buttons[name][0] * self.width), int(self.buttons[name][1] * self.heigth) print("Tapping on %s at [%d, %d]" % (name, x, y)) self.device_connector.adb_tap((x, y)) def wait(self, s): decimal = s if int(s) > 0: decimal = s - int(s) for _ in range(int(s)): if self.stopRequested: exit() time.sleep(1) if self.stopRequested: exit() time.sleep(decimal) def exit_dungeon_uncentered(self): if self.currentDungeon == 3: self.exit_dungeon_uncentered_new() else: self.exit_dungeon_uncentered_new() def exit_dungeon_uncentered_new(self, second_check=True): # Center px, dir = self.screen_connector.getPlayerDecentering() self.wait(0.5) if dir == 'left': self.swipe('w', .7) self.swipe('ne', 4) elif dir == 'right': self.swipe('e', .7) self.swipe('nw', 4) elif dir == "center": self.swipe('n', 2) else: self.swipe('n', 2) if second_check: if self.screen_connector.getFrameState() != "in_game": self.reactGamePopups() self.exit_dungeon_uncentered_new(False) self.wait(1) # Safety wait for extra check def exit_dungeon_uncentered_old(self): self.wait(2) upper_line = self.screen_connector.getHorLine("hor_up_line") print("Going trough door to exit...") self.wait(1) self.swipe('n', 2) self.wait(2) if not self.screen_connector.checkUpperLineHasChanged(upper_line): print("Not exiting, trying right...") self.wait(1) self.swipe('ne', 3) self.wait(2) if not self.screen_connector.checkUpperLineHasChanged(upper_line): print("Not exiting, trying left...") self.wait(1) self.swipe('nw', 4) self.wait(2) if not self.screen_connector.checkUpperLineHasChanged(upper_line): raise Exception('unable_exit_dungeon') self.log("Exit level") def goTroughDungeon10(self): print("Going through dungeon (designed for #10)") self.log("Cross dungeon 10") self.disableLogs = True self.swipe('n', 0.5) self.swipe('nw', 4) self.swipe('ne', 4) self.swipe('nw', 2) self.swipe('e', .20) self.disableLogs = False def goTroughDungeon_old(self): print("Going through dungeon old design 'S')") self.log("Cross dungeon (old)") self.disableLogs = True self.swipe('n', 1.5) self.swipe('w', .32) self.swipe('n', .5) self.swipe('e', .32) self.swipe('e', .32) self.swipe('n', .5) self.swipe('w', .325) self.swipe('n', 1.5) self.disableLogs = False def goTroughDungeon6(self): print("Going through dungeon (designed for #6)") self.log("Cross dungeon 6") self.disableLogs = True self.swipe('n', 1.5) self.swipe('w', .32) self.swipe('n', .5) self.swipe('e', .32) self.swipe('e', .32) self.swipe('n', .7) self.swipe('w', .325) self.swipe('w', .3) self.swipe('n', 1.6) self.swipe('e', .28) self.swipe('n', 2.5) self.disableLogs = False def goTroughDungeon3(self): print("Going through dungeon (designed for #3)") self.log("Cross dungeon 3") self.disableLogs = True self.swipe('n', 1.5) self.swipe('w', .25) self.swipe('n', .5) self.swipe('e', .25) self.swipe('n', 2) # And now we need to go around possible obstacle self.swipe('w', 1) self.swipe('n', .5) self.swipe('e', 1) self.swipe('n', .3) self.disableLogs = False def goTroughDungeon(self): if self.currentDungeon == 3: self.goTroughDungeon3() elif self.currentDungeon == 6: self.goTroughDungeon6() elif self.currentDungeon == 10: self.goTroughDungeon10() else: self.goTroughDungeon_old() # Add movement if decentering is detected if self.centerAfterCrossingDungeon or self.currentLevel == 18: self.centerPlayer() def centerPlayer(self): px, dir = self.screen_connector.getPlayerDecentering() # Move in oppositye direction. Speed is made by y = mx + q duration = 0.019 * abs(px) - 4.8 if px < self.screen_connector.door_width / 2.0: pass if dir == 'left': self.log("Centering player <--") self.swipe('e', duration) elif dir == 'right': self.log("Centering player -->") self.swipe('w', duration) elif dir == "center": pass def letPlay(self, _time: int, is_boss=False): check_exp_bar = not is_boss self.wait(2) print("Auto attacking") self.log("Auto attacking") experience_bar_line = self.screen_connector.getLineExpBar() recheck = False for i in range(_time, 0, -1): if i % self.check_seconds == 0 or recheck: recheck = False print("Checking screen...") self.log("screen check") frame = self.screen_connector.getFrame() state = self.screen_connector.getFrameState(frame) if state == "unknown": print("Unknown screen situation detected. Checking again...") self.wait(2) if self.screen_connector.getFrameState() == "unknown": raise Exception('unknown_screen_state') else: recheck = True continue elif state == "endgame" or state == "repeat_endgame_question": if state == "repeat_endgame_question": self.wait(5) print("Game ended") self.log("Game over") self.wait(1) print("Going back to menu...") self.tap('close_end') self.wait(8) # Wait to go to the menu raise Exception('ended') elif state == "select_ability" or state == "fortune_wheel" or state == "devil_question" or state == "mistery_vendor" or state == "ad_ask": print("Level ended. Collecting results for leveling up.") self.wait(1) return elif check_exp_bar and self.screen_connector.checkExpBarHasChanged(experience_bar_line, frame): print("Experience gained!") self.log("Gained experience") self.wait(3) return elif state == "in_game": if self.screen_connector.checkDoorsOpen(frame): print("In game, door opened") self.wait(1) return else: print("In game. Playing but level not ended") self.wait(1) def _exitEngine(self): self.statisctics_manager.saveOneGame(self.start_date, self.stat_lvl_start, self.currentLevel) exit(1) def reactGamePopups(self) -> int: state = "" i = 0 while state != "in_game": if self.stopRequested: exit() if i > self.max_loops_game: print("Max loops reached") self.log("Max loops reached") self._exitEngine() self.log("screen check") state = self.screen_connector.getFrameState() print("state: %s" % state) if state == "select_ability": self.tap('ability_left') self.wait(3) elif state == "fortune_wheel": self.tap('lucky_wheel_start') self.wait(6) elif state == "repeat_endgame_question": self.tap('spin_wheel_back') self.wait(3) elif state == "devil_question": self.tap('ability_daemon_reject') self.wait(3) elif state == "ad_ask": self.tap('spin_wheel_back') self.wait(3) elif state == "mistery_vendor": self.tap('spin_wheel_back') self.wait(3) elif state == "special_gift_respin": self.tap('spin_wheel_back') self.wait(3) elif state == "angel_heal": self.tap('heal_right' if self.healingStrategy == HealingStrategy.AlwaysHeal else 'heal_left') self.wait(3) elif state == "on_pause": self.tap('resume') self.wait(3) elif state == "time_prize": print("Collecting time prize and ending game. Unexpected behaviour but managed") self.tap("collect_time_prize") self.wait(3) raise Exception('ended') elif state == "endgame": raise Exception('ended') i += 1 self.wait(.1) return i def normal_lvl(self): self.goTroughDungeon() self.letPlay(self.playtime) self.reactGamePopups() self.exit_dungeon_uncentered() def normal_lvl_manual(self): self.goTroughDungeon() self.letPlay(self.playtime) self.tap('spin_wheel_back') # guard not to click on mistery vendor self.wait(1) self.tap('ability_left') self.wait(1) self.tap('spin_wheel_back') # guard not to click on watch self.wait(3) self.tap('ability_left') self.wait(2) self.tap('spin_wheel_back') # guard not to click on watch or buy stuff (armor or others) self.wait(1) self.exit_dungeon_uncentered() def heal_lvl(self): self.swipe('n', 1.7) self.reactGamePopups() self.swipe('n', .8) self.reactGamePopups() self.swipe('n', 1) # self.exit_dungeon_uncentered() def heal_lvl_manual(self): self.swipe('n', 1.7) self.wait(1) self.tap('ability_daemon_reject') self.tap('ability_right') self.wait(1.5) self.tap('spin_wheel_back') self.wait(1) self.swipe('n', .8) self.wait(1.5) self.tap('spin_wheel_back') self.wait(1.5) self.exit_dungeon_uncentered() def boss_lvl(self): self.swipe('n', 2) self.swipe('w', .25) self.swipe('n', 2) self.letPlay(self.playtime, is_boss=True) self.reactGamePopups() self.exit_dungeon_uncentered() def boss_lvl_manual(self): self.swipe('n', 2) self.swipe('n', 1.2) if self.currentLevel != 15: self.swipe('n', 1) self.letPlay(self.playtime, is_boss=True) self.tap('lucky_wheel_start') self.wait(6) self.tap('spin_wheel_back') self.wait(1.5) self.tap('ability_daemon_reject') self.tap('ability_left') self.wait(1.5) self.tap('spin_wheel_back') # guard not to click on watch self.wait(1.5) self.tap('ability_left') # Extra guard for level up self.wait(1.5) self.exit_dungeon_uncentered() def intro_lvl(self): self.wait(3) self.tap('ability_daemon_reject') self.tap('ability_left') self.swipe('n', 3) self.wait(5) self.tap('lucky_wheel_start') self.wait(5) self.swipe('n', 2) def play_cave(self): self.levelChanged.emit(self.currentLevel) if self.currentLevel < 0 or self.currentLevel > 20: print("level out of range: %d" % self.currentLevel) self._exitEngine() while self.currentLevel <= self.MAX_LEVEL: print("Level %d: %s" % (self.currentLevel, str(self.levels_type[self.currentLevel]))) if self.levels_type[self.currentLevel] == self.t_intro: self.intro_lvl() elif self.levels_type[self.currentLevel] == self.t_normal: self.normal_lvl() elif self.levels_type[self.currentLevel] == self.t_heal: self.heal_lvl() elif self.levels_type[self.currentLevel] == self.t_final_boss: self.boss_final() elif self.levels_type[self.currentLevel] == self.t_boss: self.boss_lvl() self.changeCurrentLevel(self.currentLevel + 1) self.wait(5) if self.screen_connector.checkFrame('endgame'): self.tap('close_end') self.gameWon.emit() def changeCurrentLevel(self, new_lvl): self.currentLevel = new_lvl self.levelChanged.emit(self.currentLevel) def boss_final(self): self.wait(2) self.swipe('w', 3) self.wait(50) self.reactGamePopups() self.tap('start') self.wait(2) self.swipe('n', 5) self.wait(.5) self.swipe('ne', 3) self.wait(5) self.tap('close_end') # this is to wxit def chooseCave(self): print("Main menu") self.tap('start') self.wait(3) def quick_test_functions(self): pass def start_infinite_play(self): # Only for test purposes on pressing play # self.quick_test_functions() while True: self.start_one_game() self.currentLevel = 0 def start_one_game(self): self.start_date = datetime.now() self.stat_lvl_start = self.currentLevel self.stopRequested = False self.screen_connector.stopRequested = False self.log("New game started") print("New game. Starting from level %d" % self.currentLevel) self.wait(4) if self.screen_connector.checkFrame("time_prize"): print("Collecting time prize") self.tap("resume") self.wait(3) if self.currentLevel == 0: if self.UseManualStart: a = input("Press enter to start a game (your energy bar must be at least 5)") else: while (not self.SkipEnergyCheck) and not self.screen_connector.checkFrame("least_5_energy"): print("No energy, waiting for one minute") self.noEnergyLeft.emit() self.wait(60) self.chooseCave() try: self.play_cave() except Exception as exc: self.pressCloseEndIfEndedFrame() if exc.args[0] == 'ended': print("Game ended. Farmed a little bit...") elif exc.args[0] == 'unable_exit_dungeon': print("Unable to exit a room in a dungeon. Waiting instead of causing troubles") self._exitEngine() elif exc.args[0] == "unknown_screen_state": print("Unknows screen state. Exiting instead of doing trouble") self._exitEngine() else: print("Got an unknown exception: %s" % exc) self._exitEngine() self.pressCloseEndIfEndedFrame() self.statisctics_manager.saveOneGame(self.start_date, self.stat_lvl_start, self.currentLevel) def pressCloseEndIfEndedFrame(self): if self.screen_connector.checkFrame('endgame'): self.tap('close_end')
class CaveEngine(QObject): levelChanged = pyqtSignal(int) addLog = pyqtSignal(str) resolutionChanged = pyqtSignal(int, int) dataFolderChanged = pyqtSignal(str) noEnergyLeft = pyqtSignal() gameWon = pyqtSignal() healingStrategyChanged = pyqtSignal(bool) # onDictionaryTapsChanged = pyqtSignal(dict) # onButtonLocationChanged = pyqtSignal(str) # onImageSelected = pyqtSignal() MAX_LEVEL = 20 playtime = 70 # Set this to true if you want to use generated data with TouchManager. Uses below coordinates path UseGeneratedData = False # Set this to true if keep receiving "No energy, waiting for one minute" UseManualStart = False # Set this to true if want to automatically check for energy SkipEnergyCheck = False data_pack = "datas" coords_path = "coords" buttons_filename = "buttons.json" movements_filename = "movements.json" print_names_movements = { "n": "up", "s": "down", "e": "right", "w": "left", "ne": "up-right", "nw": "up-left", "se": "down-right", "sw": "down-left", } t_intro = "intro" t_normal = "normal" t_heal = "heal" t_boss = "boss" t_final_boss = "final_boss" levels_type = { 0: t_intro, 1: t_normal, 2: t_heal, 3: t_normal, 4: t_heal, 5: t_boss, 6: t_normal, 7: t_heal, 8: t_normal, 9: t_heal, 10: t_boss, 11: t_normal, 12: t_heal, 13: t_normal, 14: t_heal, 15: t_boss, 16: t_normal, 17: t_heal, 18: t_normal, 19: t_heal, 20: t_final_boss, } max_loops_game = 20 def __init__(self, connectImmediately: bool = False): super(QObject, self).__init__() self.currentLevel = 0 self.currentDungeon = 6 self.statisctics_manager = StatisticsManager() self.start_date = datetime.now() self.stat_lvl_start = 0 self.screen_connector = GameScreenConnector() self.screen_connector.debug = False self.width, self.heigth = 1080, 2220 self.device_connector = UsbConnector() self.device_connector.setFunctionToCallOnConnectionStateChanged(self.onConnectionStateChanged) self.buttons = {} self.movements = {} self.stopRequested = False self.currentDataFolder = "" self.dataFolders = {} self.healingStrategy = HealingStrategy.AlwaysPowerUp self.centerAfterCrossingDungeon = False if connectImmediately: self.initDeviceConnector() self.check_seconds = 4 def initDataFolders(self): self.dataFolders = readAllSizesFolders() deviceFolder = buildDataFolder(self.width, self.heigth) first_folder = list(self.dataFolders.keys())[0] if deviceFolder not in self.dataFolders: logger.info("Error: not having %s coordinates. Trying with %s" % (deviceFolder, first_folder)) deviceFolder = first_folder self.changeCurrentDataFolder(deviceFolder) def initdeviceconnector(self): self.device_connector.connect() def changeHealStrategy(self, always_heal: bool): self.healingStrategy = HealingStrategy.AlwaysHeal if always_heal else HealingStrategy.AlwaysPowerUp self.healingStrategyChanged.emit(always_heal) def changeChapter(self, new_chapter): self.currentDungeon = new_chapter def onConnectionStateChanged(self): if self.device_connector.connected: self.initDataFolders() self.screen_connector.change_device_connector(self.device_connector) self.updateScreenSizeByPhone() def updateScreenSizeByPhone(self): if self.device_connector is not None: w, h = self.device_connector.adb_get_size() self.change_screen_size(w, h) self.screen_connector.change_screen_size(w, h) else: logger.info("Device connector is none. initialize it before calling this method!") def changeCurrentDataFolder(self, new_folder): self.currentDataFolder = new_folder self.loadCoords() self.dataFolderChanged.emit(new_folder) def loadCoords(self): self.buttons = loadJsonData(getCoordFilePath(self.buttons_filename, sizePath=self.currentDataFolder)) self.movements = loadJsonData(getCoordFilePath(self.movements_filename, sizePath=self.currentDataFolder)) def setStopRequested(self): self.stopRequested = True self.screen_connector.stopRequested = True self.statisctics_manager.saveOneGame(self.start_date, self.stat_lvl_start, self.currentLevel) def change_screen_size(self, w, h): self.width, self.heigth = w, h logger.info("New resolution set: %dx%d" % (self.width, self.heigth)) self.resolutionChanged.emit(w, h) def swipe_points(self, start, stop, s): start = self.buttons[start] stop = self.buttons[stop] logger.info("Swiping between %s and %s in %f" % (start, stop, s)) self.device_connector.adb_swipe( [ start[0] * self.width, start[1] * self.heigth, stop[2] * self.width, stop[3] * self.heigth, ], s, ) def swipe(self, name, s): if self.stopRequested: exit() coord = self.movements[name] logger.debug("Swiping %s in %.2f" % (self.print_names_movements[name], s)) # convert back from normalized values self.device_connector.adb_swipe( [ coord[0][0] * self.width, coord[0][1] * self.heigth, coord[1][0] * self.width, coord[1][1] * self.heigth, ], s, ) def tap(self, name): if self.stopRequested: exit() # convert back from normalized values x, y = int(self.buttons[name][0] * self.width), int(self.buttons[name][1] * self.heigth) logger.debug("Tapping on %s at [%d, %d]" % (name, x, y)) self.device_connector.adb_tap((x, y)) def wait(self, s): decimal = s if int(s) > 0: decimal = s - int(s) for _ in range(int(s)): if self.stopRequested: exit() time.sleep(1) if self.stopRequested: exit() time.sleep(decimal) def exit_dungeon_uncentered(self, second_check=True): # Center _, direction = self.screen_connector.get_player_decentering() self.wait(0.5) if direction == "left": self.swipe("w", 0.7) self.swipe("ne", 4) elif direction == "right": self.swipe("e", 0.7) self.swipe("nw", 4) elif direction == "center": self.swipe("n", 2) else: self.swipe("n", 2) if second_check and self.screen_connector.get_frame_state() != "in_game": self.reactGamePopups() self.exit_dungeon_uncentered(False) self.wait(1) # Safety wait for extra check def goTroughDungeon10(self): logger.info("Going through dungeon (designed for #10)") self.swipe("n", 0.5) self.swipe("nw", 4) self.swipe("ne", 4) self.swipe("nw", 2) self.swipe("e", 0.20) def goTroughDungeon_old(self): logger.info("Going through dungeon old design 'S')") self.swipe("n", 1.5) self.swipe("w", 0.32) self.swipe("n", 0.5) self.swipe("e", 0.32) self.swipe("e", 0.32) self.swipe("n", 0.5) self.swipe("w", 0.325) self.swipe("n", 1.5) def goTroughDungeon6(self): logger.debug("Going through dungeon (designed for #6)") self.swipe("n", 1.5) self.swipe("w", 0.32) self.swipe("n", 0.5) self.swipe("e", 0.32) self.swipe("e", 0.32) self.swipe("n", 0.7) self.swipe("w", 0.325) self.swipe("w", 0.3) self.swipe("n", 1.6) self.swipe("e", 0.28) self.swipe("n", 2.5) def goTroughDungeon3(self): logger.info("Going through dungeon (designed for #3)") self.swipe("n", 1.5) self.swipe("w", 0.25) self.swipe("n", 0.5) self.swipe("e", 0.25) self.swipe("n", 2) # And now we need to go around possible obstacle self.swipe("w", 1) self.swipe("n", 0.5) self.swipe("e", 1) self.swipe("n", 0.3) def goTroughDungeon(self): if self.currentDungeon == 3: self.goTroughDungeon3() elif self.currentDungeon == 6: self.goTroughDungeon6() elif self.currentDungeon == 10: self.goTroughDungeon10() else: self.goTroughDungeon_old() # Add movement if decentering is detected if self.centerAfterCrossingDungeon: self.centerPlayer() def centerPlayer(self): px, dir = self.screen_connector.get_player_decentering() # Move in oppositye direction. Speed is made by y = mx + q duration = 0.019 * abs(px) - 4.8 if px < self.screen_connector.door_width / 2.0: pass if dir == "left": logger.info("Centering player <--") self.swipe("e", duration) elif dir == "right": logger.info("Centering player -->") self.swipe("w", duration) elif dir == "center": pass def letPlay(self, _time: int, is_boss=False): check_exp_bar = not is_boss # self.wait(2) logger.debug("Auto attacking") experience_bar_line = self.screen_connector.get_line_exp_bar() recheck = False for i in range(_time, 0, -1): if i % self.check_seconds == 0 or recheck: recheck = False logger.debug("Checking screen...") frame = self.screen_connector.get_frame() state = self.screen_connector.get_frame_state(frame) if state == "unknown": logger.info("Unknown screen situation detected. Checking again...") self.wait(2) if self.screen_connector.get_frame_state() == "unknown": raise Exception("unknown_screen_state") else: recheck = True continue elif state == "endgame" or state == "repeat_endgame_question": if state == "repeat_endgame_question": self.wait(5) logger.info("Game ended") self.wait(1) logger.info("Going back to menu...") self.tap("close_end") self.wait(8) # Wait to go to the menu raise Exception("ended") elif state in [ "select_ability", "fortune_wheel", "devil_question", "mistery_vendor", "ad_ask", ]: logger.debug("Level ended. Collecting results for leveling up.") self.wait(1) return elif check_exp_bar and self.screen_connector.check_exp_bar_has_changed(experience_bar_line, frame): logger.debug("Experience gained!") self.wait(3) return elif state == "in_game": if self.screen_connector.check_doors_open(frame): logger.info("In game, door opened") self.wait(1) return else: logger.debug("In game. Playing but level not ended") self.wait(1) def _exitEngine(self): self.statisctics_manager.saveOneGame(self.start_date, self.stat_lvl_start, self.currentLevel) exit(1) def reactGamePopups(self) -> None: state = "" i = 0 wait_time = 1 wait_time_wheel = 5 have_battle_pass = False while state != "in_game": if self.stopRequested: exit() if i > self.max_loops_game: logger.info("Max loops reached") self._exitEngine() logger.debug("Checking screen...") state = self.screen_connector.get_frame_state() logger.debug("state: %s" % state) if state == "select_ability": self.tap("ability_left") elif state == "fortune_wheel": self.tap("lucky_wheel_start") self.wait(wait_time_wheel) continue elif state == "ad_ask": if have_battle_pass: self.tap("lucky_wheel_start") else: self.tap("spin_wheel_back") elif state in [ "repeat_endgame_question", "mistery_vendor", "special_gift_respin", ]: self.tap("spin_wheel_back") elif state == "devil_question": self.tap("ability_daemon_reject") elif state == "angel_heal": self.tap("heal_right" if self.healingStrategy == HealingStrategy.AlwaysHeal else "heal_left") elif state == "on_pause": self.tap("resume") elif state == "time_prize": logger.info("Collecting time prize and ending game. Unexpected behaviour but managed") self.tap("collect_time_prize") self.wait(wait_time) raise Exception("ended") elif state == "endgame": raise Exception("ended") i += 1 self.wait(wait_time) def normal_lvl(self): self.goTroughDungeon() self.letPlay(self.playtime) self.reactGamePopups() self.exit_dungeon_uncentered() def normal_lvl_manual(self): self.goTroughDungeon() self.letPlay(self.playtime) self.tap("spin_wheel_back") # guard not to click on mistery vendor self.wait(1) self.tap("ability_left") self.wait(1) self.tap("spin_wheel_back") # guard not to click on watch self.wait(3) self.tap("ability_left") self.wait(2) self.tap("spin_wheel_back") # guard not to click on watch or buy stuff (armor or others) self.wait(1) self.exit_dungeon_uncentered() def heal_lvl(self): self.swipe("n", 1.7) self.reactGamePopups() self.swipe("n", 0.8) self.reactGamePopups() self.swipe("n", 1) # self.exit_dungeon_uncentered() def heal_lvl_manual(self): self.swipe("n", 1.7) self.wait(1) self.tap("ability_daemon_reject") self.tap("ability_right") self.wait(1.5) self.tap("spin_wheel_back") self.wait(1) self.swipe("n", 0.8) self.wait(1.5) self.tap("spin_wheel_back") self.wait(1.5) self.exit_dungeon_uncentered() def boss_lvl(self): self.swipe("n", 2) self.swipe("w", 0.25) self.swipe("n", 2) self.letPlay(self.playtime, is_boss=True) self.reactGamePopups() self.exit_dungeon_uncentered() def boss_lvl_manual(self): self.swipe("n", 2) self.swipe("n", 1.2) if self.currentLevel != 15: self.swipe("n", 1) self.letPlay(self.playtime, is_boss=True) self.tap("lucky_wheel_start") self.wait(6) self.tap("spin_wheel_back") self.wait(1.5) self.tap("ability_daemon_reject") self.tap("ability_left") self.wait(1.5) self.tap("spin_wheel_back") # guard not to click on watch self.wait(1.5) self.tap("ability_left") # Extra guard for level up self.wait(1.5) self.exit_dungeon_uncentered() def intro_lvl(self): self.wait(3) self.tap("ability_daemon_reject") self.tap("ability_left") self.swipe("n", 3) self.wait(5) self.tap("lucky_wheel_start") self.wait(5) self.swipe("n", 2) def play_cave(self): self.levelChanged.emit(self.currentLevel) if self.currentLevel < 0 or self.currentLevel > 20: logger.info("level out of range: %d" % self.currentLevel) self._exitEngine() while self.currentLevel <= self.MAX_LEVEL: logger.info("Level %d: %s" % (self.currentLevel, str(self.levels_type[self.currentLevel]))) if self.levels_type[self.currentLevel] == self.t_intro: self.intro_lvl() elif self.levels_type[self.currentLevel] == self.t_normal: self.normal_lvl() elif self.levels_type[self.currentLevel] == self.t_heal: self.heal_lvl() elif self.levels_type[self.currentLevel] == self.t_final_boss: self.boss_final() elif self.levels_type[self.currentLevel] == self.t_boss: self.boss_lvl() self.changeCurrentLevel(self.currentLevel + 1) self.wait(5) if self.screen_connector.check_frame("endgame"): self.tap("close_end") self.gameWon.emit() def changeCurrentLevel(self, new_lvl): self.currentLevel = new_lvl self.levelChanged.emit(self.currentLevel) def boss_final(self): self.wait(2) self.swipe("w", 2) start_time = time.perf_counter() self.wait(20) self.reactGamePopups() end_time = time.perf_counter() logger.debug(f"The final boss took {(end_time-start_time):0.1f} seconds") self.tap("start") self.wait(2) self.swipe("n", 5) self.wait(0.5) self.swipe("ne", 3) self.wait(5) self.tap("close_end") # this is to wxit def chooseCave(self): logger.info("Main menu") self.tap("start") self.wait(3) def start_infinite_play(self): while True: self.start_one_game() self.currentLevel = 0 def enough_energy(self, min_energy=5): result = self.device_connector.my_device.screencap() with open("screen.png", "wb") as fp: fp.write(result) image = cv2.imread("screen.png") energy = extract_energy(image) return True if energy >= min_energy else False def start_one_game(self): delay_energy_check = 30 self.start_date = datetime.now() self.stat_lvl_start = self.currentLevel self.stopRequested = False self.screen_connector.stopRequested = False logger.info("Received request to start new game from level %d" % self.currentLevel) # self.wait(5) if self.currentLevel == 0: if self.UseManualStart: input("Press any key to start a game (your energy bar must be at least 5)") else: logged_first = False while not self.SkipEnergyCheck and not self.screen_connector.check_frame( "least_5_energy_no_battlepass" ): if not logged_first: logger.info(f"Waiting for enough energy...") logged_first = True self.noEnergyLeft.emit() self.wait(delay_energy_check) self.chooseCave() start_time = time.perf_counter() try: self.play_cave() except Exception as exc: self.pressCloseEndIfEndedFrame() if exc.args[0] == "ended": logger.info("Game ended. Farmed a little bit...") elif exc.args[0] == "unable_exit_dungeon": logger.info("Unable to exit a room in a dungeon. Waiting instead of causing troubles") self._exitEngine() elif exc.args[0] == "unknown_screen_state": logger.info("Unknows screen state. Exiting instead of doing trouble") self._exitEngine() else: logger.exception("Got an unknown exception: %s" % exc) self._exitEngine() end_time = time.perf_counter() logger.info(f"This play took {(end_time-start_time)/60:0.1f} minutes") self.pressCloseEndIfEndedFrame() self.statisctics_manager.saveOneGame(self.start_date, self.stat_lvl_start, self.currentLevel) def pressCloseEndIfEndedFrame(self): if self.screen_connector.check_frame("endgame"): self.tap("close_end")
choosen = input("Select your number") folder = keys[int(choosen)] screens_path = os.path.join("datas", folder, "screens") print("Using %s" % screens_path) selected_debug = input( "Do you wish to debug? (set yes only if you did it already once and found some rows with NO_DETECTION): (y/n):" ) debug = False if selected_debug != None: if selected_debug == "y" or selected_debug == "yes": debug = True width, heigth = screens_data[folder] excluded = [] screen_conector = GameScreenConnector() screen_conector.change_screen_size(width, heigth) screen_conector.debug = debug static_coords = screen_conector.static_coords files = os.listdir(screens_path) files.sort() all_ok = True for file in files: if file not in excluded: full_path = os.path.join(screens_path, file) frame = getImageFrame(full_path) complete_frame = screen_conector.get_frame_state_complete(frame) computed = [k for k, v in complete_frame.items() if v] sum = len(computed) ok = False
choosen = input("Select your number") folder = keys[int(choosen)] screens_path = os.path.join("datas", folder, "screens") print("Using %s" % screens_path) selected_debug = input( "Do you wish to debug? (set yes only if you did it already once and found some rows with NO_DETECTION): (y/n):" ) debug = False if selected_debug != None: if selected_debug == 'y' or selected_debug == 'yes': debug = True width, heigth = screens_data[folder] excluded = [] screen_conector = GameScreenConnector() screen_conector.changeScreenSize(width, heigth) screen_conector.debug = debug static_coords = screen_conector.static_coords files = os.listdir(screens_path) files.sort() all_ok = True for file in files: if file not in excluded: full_path = os.path.join(screens_path, file) frame = getImageFrame(full_path) complete_frame = screen_conector.getFrameStateComplete(frame) computed = [k for k, v in complete_frame.items() if v] sum = len(computed) ok = False
UseGeneratedData = False # Set this to true if keep receiving "No energy, wqiting for one minute" UseManualStart = True # Set this to true if want to automatically check for energy SkipEnergyCheck = True data_pack = 'datas' buttons_corrdinates_filename = "data.py" device = get_device_id() if device is None: print("Error: no device discovered. Start adb server before executing this.") exit(1) print("Usb debugging device: %s" % device) width, heigth = adb_get_size() print("Your resolution is %dx%d" % (width, heigth)) screen_connector = GameScreenConnector(width, heigth) def pixel_equals(px1, px2): return px1[0] == px2[0] and px1[1] == px2[1] and px1[2] == px2[2] and px1[3] == px2[3] # Those are normalized coordinates of data to be taken and trained into a simple nn to predict game status (multiclass) def getAttributesArr(): calculus_width = 1080 calculus_heigth = 2220 attr = [ [1024 / calculus_width, 530 / calculus_heigth], # level up/initial ability choose (right up) [50 / calculus_width, 530 / calculus_heigth], # level up/initial ability choose (left up) [1010 / calculus_width, 370 / calculus_heigth], # blessing and devil (up right) [50 / calculus_width, 370 / calculus_heigth], # blessing and devil (up left)