├── .gitignore ├── .idea ├── .gitignore ├── Maple Controller.iml ├── inspectionProfiles │ └── profiles_settings.xml ├── misc.xml ├── modules.xml ├── other.xml ├── runConfigurations │ └── _template__of_Python.xml ├── vcs.xml └── webResources.xml ├── Bot ├── .gitignore ├── Bot.py └── compile.py ├── Controller ├── Controllers │ ├── BaseController.py │ ├── GameController.py │ ├── MovementController.py │ ├── PlayerController.py │ ├── PotionsController.py │ └── SettingsController.py ├── Elite boss.png ├── MapleMoveMode.py ├── MapleState.py ├── docs │ ├── Controller Settings.md │ └── images │ │ ├── Download folder.png │ │ ├── Json selection.png │ │ ├── Resolution.png │ │ ├── Smart direction example.png │ │ ├── UAC1.png │ │ └── UAC2.png ├── funcs.py └── refs │ ├── EXP digits │ ├── 0.png │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ ├── 5.png │ ├── 6.png │ ├── 7.png │ ├── 8.png │ ├── 9.png │ ├── bracket.png │ ├── exp.png │ └── slash.png │ ├── PIC keys │ ├── 0.png │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ ├── 5.png │ ├── 6.png │ ├── 7.png │ ├── 8.png │ ├── 9.png │ ├── a.png │ ├── b.png │ ├── c.png │ ├── d.png │ ├── e.png │ ├── f.png │ ├── g.png │ ├── h.png │ ├── i.png │ ├── j.png │ ├── k.png │ ├── l.png │ ├── m.png │ ├── n.png │ ├── o.png │ ├── p.png │ ├── q.png │ ├── r.png │ ├── s.png │ ├── t.png │ ├── u.png │ ├── v.png │ ├── w.png │ ├── x.png │ ├── y.png │ └── z.png │ ├── bars │ ├── EXP bar.png │ └── World map.png │ ├── buttons │ ├── Cash shop button.png │ ├── Change channel button.png │ ├── Close button.png │ ├── Create character button.png │ ├── Login news buttons.png │ ├── Ok.png │ └── World menu channels button.png │ ├── curses │ ├── No potions curse.png │ └── Rune cooldown.png │ ├── map │ └── Location mark.png │ ├── menus │ └── Settings menu E.png │ ├── messages │ ├── Death message.png │ ├── Missing hyper rock.png │ ├── Rune cooldown.png │ ├── Rune message 1.png │ ├── Select a world.png │ ├── Unable to change channel dialog.png │ └── World map teleport message.png │ ├── mini map │ ├── Left edge.png │ ├── Npc.png │ ├── Other player.png │ ├── Player.png │ ├── Portal.png │ ├── Right edge.png │ ├── Rune.png │ └── World.png │ ├── rune keys │ ├── Down.png │ ├── Left.png │ ├── Right.png │ └── Up.png │ └── worlds │ ├── aurora.png │ ├── bera.png │ ├── burning.png │ ├── elysium.png │ ├── reboot.png │ └── scania.png ├── Dependencies ├── __pycache__ │ ├── NotebookLoader.cpython-39.pyc │ └── admin.cpython-39.pyc └── admin.py └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | compile 2 | compile/* 3 | deaths 4 | deaths/* 5 | log.txt 6 | *.json 7 | __pycache__ 8 | __pycache__/* 9 | .ipynb_checkpoints 10 | .ipynb_checkpoints/* 11 | overlay 12 | overlay/* 13 | bot.exe 14 | *.exe -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /../../../../../../../../../../:\Users\Tomer\Desktop\Projects\Practice\Python\Maplestory\Maple Controller\.idea/dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /.idea/Maple Controller.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 13 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/other.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /.idea/runConfigurations/_template__of_Python.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 24 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/webResources.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Bot/.gitignore: -------------------------------------------------------------------------------- 1 | compile 2 | compile/* 3 | deaths 4 | deaths/* 5 | log.txt 6 | *.json 7 | __pycache__ 8 | __pycache__/* 9 | .ipynb_checkpoints 10 | .ipynb_checkpoints/* 11 | overlay 12 | overlay/* 13 | -------------------------------------------------------------------------------- /Bot/Bot.py: -------------------------------------------------------------------------------- 1 | import collections 2 | import sys 3 | 4 | from Controller.MapleMoveMode import MapleMoveMode 5 | 6 | sys.path.append('..') 7 | sys.path.append('..\\Dependencies') 8 | sys.path.append('..\\Controller') 9 | 10 | from Dependencies import admin 11 | from Controller.Controllers.PlayerController import PlayerController 12 | from Controller.funcs import * 13 | 14 | print("Created by tomergt45 (Tomergt89@gmail.com or github.com/tomergt45) ") 15 | 16 | if not admin.isUserAdmin(): 17 | print("Note: You must run this application as administrator") 18 | admin.runAsAdmin(wait=False) 19 | sys.exit() 20 | 21 | print("Note: You must play on windowed 800x600 (4:3)") 22 | print( 23 | "Note: You must change your windows UAC settings to 'Never Notify' (don't forget to turn it back after using the bot!)") 24 | 25 | 26 | def get_json_files(path='.'): 27 | return [f for f in os.listdir(".") if f.endswith(".json")] 28 | 29 | 30 | files = get_json_files() 31 | 32 | if len(files) == 0: 33 | raise Exception('No settings.json file was found.') 34 | elif len(files) == 1: 35 | settingsPath = files[0] 36 | else: 37 | print('Found multiple .json files, please select the one you want to use:') 38 | for i, file in enumerate(files): 39 | print(str(i + 1) + ')', file) 40 | selection = int(input("I select: ")) 41 | settingsPath = files[selection - 1] 42 | 43 | if os.path.isdir("refs"): 44 | resources_path = "refs" 45 | elif os.path.isdir("../Controller/refs"): 46 | resources_path = "../Controller/refs" 47 | else: 48 | raise Exception("Unable to locate the refs directory.") 49 | 50 | controller = PlayerController(settingsPath, resources_path=resources_path) 51 | 52 | start_time = datetime.datetime.now() 53 | maxlen = 10 54 | history = { 55 | 'last_verbose': time.time(), 56 | 'exp_per_minute_history': collections.deque(maxlen=maxlen), 57 | } 58 | controller.restart_cooldown('change_channel') 59 | 60 | def clear(): 61 | os.system("cls") 62 | 63 | def refresh_exp_history(current_exp, t_diff): 64 | if current_exp < history.get('last_exp', current_exp): 65 | history['last_exp'] = 0 66 | history['exp_per_minute_history'] = collections.deque(maxlen=maxlen) 67 | current_exp_diff = current_exp - history.get('last_exp', current_exp) # Gained EXP 68 | current_exp_per_minute = current_exp_diff * (1 / t_diff) * 60 69 | current_exp_per_hour = current_exp_per_minute * 60 70 | history['exp_per_minute_history'].append(current_exp_per_minute) 71 | history['last_exp'] = current_exp 72 | 73 | def verbose(): 74 | if controller.check_black_screen(): 75 | sleep(1) 76 | return False 77 | 78 | t_diff = time.time() - history['last_verbose'] 79 | 80 | # Calculate EXP 81 | if not controller.pause_state: 82 | current_exp = controller.get_exp_precent() 83 | refresh_exp_history(current_exp, t_diff) 84 | exp_per_minute = np.mean(history['exp_per_minute_history']) 85 | exp_per_hour = exp_per_minute * 60 86 | exp_diff = exp_per_minute / 60 * t_diff 87 | estimated_time_rankup = pretty_delta(datetime.timedelta( 88 | minutes=(100 - current_exp) / exp_per_minute)) if exp_per_minute != 0 else "Gain more EXP for estimation" 89 | else: 90 | current_exp = history['last_exp'] 91 | exp_diff = exp_per_minute = exp_per_hour = 0 92 | estimated_time_rankup = 'Unable to estimate while paused' 93 | 94 | clear() 95 | print(f""" 96 | Elapsed time:\t\t {str((datetime.datetime.now() - start_time))} 97 | Paused:\t\t\t {controller.pause_state} 98 | Deaths:\t\t\t {controller.deaths} 99 | HP Potions used:\t\t {controller.hp_potions_used} 100 | MP Potions used:\t\t {controller.mp_potions_used} 101 | EXP per {round(t_diff, 1)}s/1m/1h: \t {str(round(exp_diff, 2))}% / {str(round(exp_per_minute, 2))}% / {str(round(exp_per_hour, 2))}% 102 | Estimated time till rankup:\t {estimated_time_rankup} 103 | """) 104 | history['last_verbose'] = time.time() 105 | 106 | def login_bot(): 107 | close_news = select_character = select_world = False 108 | controller.restart_cooldown('wait_for_ingame_view') 109 | 110 | if controller.get_status() != MapleState.ACTIVE: 111 | log('Launching maplestory', console=True) 112 | controller.launch_maple() 113 | sleep(30) # Give at least 30 seconds for maple to launch 114 | while 1: 115 | if controller.pause_state: 116 | continue 117 | try: 118 | if controller.check_world_menu_open() or controller.check_cooldown('wait_for_ingame_view', 180): 119 | break 120 | except Exception as e: 121 | log(str(e), console=True) 122 | sleep(5) 123 | 124 | while not controller.check_cooldown('wait_for_ingame_view', 60 * 5): 125 | if controller.pause_state: 126 | continue 127 | if controller.get_status() == MapleState.ACTIVE: 128 | if controller.check_world_menu_open() and not select_world: 129 | log('Maplestory launched and detected', console=True) 130 | select_world = True 131 | controller.select_world(controller.world) 132 | sleep(3) 133 | 134 | elif controller.check_characters_menu_open() and not select_character: 135 | log('Entered characters menu', console=True) 136 | select_character = True 137 | press_and_release('enter') 138 | controller.enter_PIC(controller.PIC) 139 | sleep(3) 140 | 141 | elif controller.check_news_window_open() and not close_news: 142 | sleep(1) 143 | log('Closing annoying news window', console=True) 144 | close_news = True 145 | press_and_release('esc') 146 | sleep(2) 147 | 148 | elif controller.check_exp_bar_inview(): 149 | log('Player spawned', console=True) 150 | if not close_news: 151 | log('Pressing safeguard ESC', console=True) 152 | press_and_release('esc') 153 | sleep(.5) 154 | if controller.check_settings_menu_open(): 155 | press_and_release('esc') 156 | sleep(1) 157 | if select_world or select_character: 158 | sleep(1) 159 | controller.use_spawn_skills() 160 | return True 161 | return False 162 | 163 | def afk_bot(): 164 | if controller.hold_up_state: 165 | controller.press_up() 166 | if controller.move_mode == MapleMoveMode.HOLD: 167 | controller.press_move() 168 | 169 | # Check that maplestory is running and that the cashshop button is in view (indicating that you are in game) 170 | while controller.get_status() == 1: 171 | try: # Sanity check: Failing to grab frame means app is not running properly 172 | verbose() 173 | 174 | if controller.pause_state: 175 | continue 176 | if controller.check_unable_change_channel_dialog_open(): 177 | press_and_release('enter') 178 | if controller.check_dead(): 179 | controller.on_death() 180 | sleep(1) 181 | break 182 | 183 | controller.check_health_and_heal() 184 | controller.close_tabs() 185 | 186 | if controller.check_mana(): 187 | controller.fill_mana() 188 | sleep(.15) 189 | controller.check_direction_and_change() 190 | 191 | if controller.check_cooldown("pet_food", controller.pet_food_period): 192 | controller.feed_pet() 193 | controller.restart_cooldown('pet_food') 194 | 195 | if controller.pause_state: 196 | continue 197 | controller.check_health_and_heal() 198 | 199 | # Attempt to activate rune only if not on cooldown 200 | if not controller.check_rune_cooldown_buff() and controller.attempt_rune(): 201 | pass 202 | 203 | # Change channel if: 204 | # Faild to activate rune / Rune is blocking EXP / Another player in map / Channel timeout exceeded 205 | elif controller.check_channel(): 206 | # Release move / up keys if on hold 207 | if controller.hold_up_state: 208 | controller.release_up() 209 | if controller.move_mode == MapleMoveMode.HOLD: 210 | controller.release_move() 211 | 212 | status = controller.move_channel() 213 | if not status: # Exit bot if faild to change channel 214 | break 215 | 216 | sleep(2) 217 | controller.restart_cooldown('change_channel') 218 | 219 | # Press move / up keys if on hold 220 | if controller.hold_up_state: 221 | controller.press_up() 222 | if controller.move_mode == MapleMoveMode.HOLD: 223 | controller.press_move() 224 | 225 | while controller.check_no_potion_curse(): 226 | controller.check_direction_and_change() 227 | controller.jump_or_doublejump() 228 | controller.attack() 229 | controller.check_direction_and_change() 230 | sleep(.5) 231 | 232 | if controller.pause_state: 233 | continue 234 | controller.check_health_and_heal() 235 | 236 | if controller.check_cooldown('buffs', controller.buffs_period): 237 | controller.attack() 238 | controller.use_buffs() 239 | controller.restart_cooldown('buffs') 240 | # Periodical HP check 241 | if controller.check_cooldown('period hp', 30): 242 | controller.heal() 243 | controller.restart_cooldown('period hp') 244 | if controller.pause_state: 245 | continue 246 | 247 | if controller.ascend_key and controller.check_cooldown("ascend", controller.ascend_period): 248 | controller.restart_cooldown("ascend") 249 | controller.ascend() 250 | 251 | if controller.move_mode == MapleMoveMode.TELEPORT: 252 | controller.grab_frame() 253 | if controller.check_cooldown('teleport down', controller.teleport_down_period): 254 | controller.restart_cooldown('teleport down') 255 | controller.teleport_down() 256 | sleep(.25) 257 | elif controller.check_cooldown('teleport up', controller.teleport_up_period): 258 | controller.restart_cooldown('teleport up') 259 | controller.teleport_up() 260 | sleep(.25) 261 | controller.move() 262 | 263 | controller.check_direction_and_change() 264 | controller.jump_or_doublejump() 265 | controller.check_health_and_heal() 266 | controller.use_uncooldowned_skills() 267 | controller.check_health_and_heal() 268 | controller.check_direction_and_change() 269 | controller.attack() 270 | except: 271 | import traceback 272 | log('AFK Bot crashed attempting restart') 273 | log(''.join(traceback.format_exception(*sys.exc_info())), console=True) 274 | break 275 | 276 | # Release keys left pressed 277 | if controller.hold_up_state: 278 | controller.release_up() 279 | if controller.move_mode == MapleMoveMode.HOLD: 280 | controller.release_move() 281 | 282 | while 1: 283 | if controller.pause_state: 284 | continue 285 | if controller.get_status() == MapleState.CRASHED: # Check if maple crashed 286 | if controller.attempt_restart_after_crash_state: # Close crashed maple 287 | clear() 288 | log('Maplestory has crashed... closing program', console=True) 289 | controller.close_maple() 290 | log('Maplestory closed, waiting 10 seconds and then launching back', console=True) 291 | sleep(10) # Wait a bit for maplestory to close properly 292 | else: 293 | log( 294 | 'Maplestory has crashed, exiting program... (If you want to auto restart maple in future crashes, set "attempt_restart_after_crash=true" in the settings.json file)', 295 | console=True) 296 | 297 | # launch the game, select world, enter PIC and conddddinue fighting 298 | status = login_bot() 299 | try: 300 | if status: 301 | afk_bot() 302 | clear() 303 | else: 304 | log( 305 | 'Maplestory attempt to launch and login has faild after 5 minutes of wait time (this includes attempting to launch the game, select a world, channel, character and enter PIC).', 306 | console=True) 307 | break 308 | except: 309 | import traceback 310 | log(''.join(traceback.format_exception(*sys.exc_info())), console=True) 311 | -------------------------------------------------------------------------------- /Bot/compile.py: -------------------------------------------------------------------------------- 1 | import os, shutil 2 | import sys 3 | 4 | sys.path.append('..') 5 | sys.path.append('..\\Dependencies') 6 | from Dependencies import admin 7 | 8 | if not admin.isUserAdmin(): 9 | admin.runAsAdmin(wait=False) 10 | sys.exit() 11 | 12 | hiddenimports = [ 13 | 'numpy', 14 | 'os', 15 | 'subprocess', 16 | 'itertools', 17 | 'ctypes', 18 | 'win32gui', 19 | 'win32com', 20 | 'pyautogui', 21 | 'keyboard', 22 | 'json', 23 | 'datetime', 24 | 'psutil', 25 | 'time', 26 | 'PIL', 27 | "mss", 28 | "cv2", 29 | "shutil", 30 | "re" 31 | ] 32 | 33 | 34 | 35 | 36 | os.makedirs('../compile', exist_ok=True) 37 | with open('../compile/controller imports.py', 'w') as fd: 38 | fd.write('hiddenimports = ' + str(hiddenimports)) 39 | 40 | shutil.copyfile("../Dependencies/admin.py", '../compile/admin.py') 41 | shutil.copyfile("Bot.py", '../compile/Bot.py') 42 | 43 | os.system('pyinstaller "../compile/bot.py" --onefile --specpath="../compile/" --distpath="../compile/" --workpath="../compile/" --additional-hooks-dir="../compile/hook-data.py"') 44 | 45 | shutil.copyfile('../compile/bot.exe', 'bot.exe') 46 | shutil.rmtree('../compile') 47 | # -------------------------------------------------------------------------------- /Controller/Controllers/BaseController.py: -------------------------------------------------------------------------------- 1 | import collections 2 | import subprocess 3 | 4 | from Controller.Controllers.SettingsController import SettingsController 5 | from Controller.funcs import * 6 | 7 | pyautogui.FAILSAFE = False 8 | 9 | nexon_launch_target = "nxl://launch/10100" 10 | steam_launch_target = "steam://rungameid/216150" 11 | 12 | class BaseController(SettingsController): 13 | def __init__(self, settings_path, log_path='log.txt'): 14 | super().__init__(settings_path) 15 | clearlog(path=log_path) 16 | 17 | # Settings variables 18 | self.pause_key = self.get('pause', 'f5') 19 | self.install_origin = self.get('install_origin') 20 | 21 | # Default variables 22 | self.log_path = log_path 23 | self.frames = collections.deque(maxlen=600) 24 | self.cooldowns = {} 25 | 26 | # Keyboard events 27 | self.pause_state = False 28 | 29 | def onpause(e): 30 | self.pause_state = not self.pause_state 31 | log('Paused' if self.pause_state else 'Unpaused') 32 | print('Paused' if self.pause_state else 'Unpaused') 33 | 34 | keyboard.unhook_all() 35 | keyboard.on_release_key(self.pause_key, onpause) 36 | 37 | def grab_frame(self, focus=True): 38 | if self.get_status() == MapleState.ACTIVE: 39 | self.frame_pil, self.box = grab_maple(focus=(focus and not self.pause_state)) 40 | self.frame_arr = np.asarray(self.frame_pil) 41 | self.frames.append(self.frame_arr) 42 | return self.frame_pil, self.frame_arr, self.box 43 | else: 44 | raise Exception('Unable to grab a screenshot from maplestory because maplestory isn\'t running.') 45 | 46 | def get_status(self): 47 | return get_maple_status() 48 | 49 | def launch_maple(self): 50 | launch_target = steam_launch_target if self.install_origin == 'steam' else nexon_launch_target 51 | subprocess.run("start {}".format(launch_target), shell=True) 52 | 53 | def close_maple(self): 54 | for process in psutil.process_iter(): 55 | name = process.name().lower() 56 | if 'werfault' in name.lower() or 'maplestory' in name.lower(): 57 | process.kill() 58 | 59 | def toggle_fullscreen(self): 60 | focus_maple() 61 | press_and_release('alt+enter') 62 | 63 | def focus_maple(self): 64 | focus_maple() 65 | 66 | def restart_cooldown(self, key): 67 | self.cooldowns[key] = time.time() 68 | 69 | def check_cooldown(self, key, cooldown): 70 | if cooldown == -1 or cooldown is None: 71 | return False 72 | if key in self.cooldowns: 73 | return True if time.time() - self.cooldowns[key] > cooldown else False 74 | else: 75 | return True 76 | -------------------------------------------------------------------------------- /Controller/Controllers/GameController.py: -------------------------------------------------------------------------------- 1 | import pathlib 2 | 3 | from Controller.Controllers.BaseController import BaseController 4 | from Controller.funcs import * 5 | 6 | 7 | class GameController(BaseController): 8 | def __init__(self, settings_path, log_path='log.txt', resources_path="refs"): 9 | super().__init__(settings_path, log_path) 10 | 11 | self.world = self.get('world') 12 | self.PIC = self.get('PIC') 13 | self.world_map_key = self.get('world_map', 'w') 14 | self.channel_period = self.get('change_channel_period', 600) 15 | 16 | # Default variables 17 | self.resources_path = pathlib.Path(resources_path) 18 | if not self.resources_path.exists(): 19 | raise Exception("Unable to locate the refs folder at '" + resources_path + "'") 20 | 21 | def select_world(self, world, channel=1): 22 | self.grab_frame() 23 | if self.check_world_menu_open(): 24 | if not locate_on_screen(self.get_resource_path("worlds/{}.png".format(world))): 25 | self.grab_frame() 26 | press_and_release('up') 27 | sleep(.25) 28 | press_and_release('up') 29 | sleep(.25) 30 | if locate_on_screen_and_click(self.get_resource_path("worlds/{}.png".format(world)), duration=1): 31 | sleep(.5) 32 | if self.check_world_menu_channels_menu_open(): 33 | for i in range(channel - 1): 34 | press_and_release('right') 35 | sleep(.3) 36 | press_and_release('enter') 37 | sleep(1) 38 | else: 39 | raise Exception('Faild selecting world {}, channels menu was not detected.'.format(world)) 40 | else: 41 | raise Exception('Faild selecting world {}, world button was not detected.'.format(world)) 42 | 43 | def enter_PIC(self, PIC): 44 | self.grab_frame() 45 | for key in PIC: 46 | if not locate_on_screen_and_click(self.get_resource_path('PIC keys/{}.png'.format(key)), duration=.5): 47 | raise Exception('Faild entering PIC, unable to find the key for `{}`.'.format(key)) 48 | press_and_release('enter') 49 | 50 | def get_player_position(self, confidence=.9, minimap=None): 51 | if not minimap: 52 | minimap = self.get_mini_map() 53 | return locate(self.get_resource_path('mini map/Player.png'), minimap, confidence=confidence) 54 | 55 | def get_rune_position(self, confidence=.9, minimap=None): 56 | if not minimap: 57 | minimap = self.get_mini_map() 58 | return locate(self.get_resource_path('mini map/Rune.png'), minimap, confidence=confidence) 59 | 60 | def get_mini_map(self, padding=5, confidence=.98): 61 | self.grab_frame() 62 | 63 | left_edge = locate(self.get_resource_path("mini map/Left edge.png"), self.frame_pil, confidence=confidence) 64 | right_edge = locate(self.get_resource_path("mini map/Right edge.png"), self.frame_pil, confidence=confidence) 65 | 66 | try: 67 | return self.frame_pil.crop((left_edge.left, left_edge.top, right_edge.left + padding, right_edge.top + padding)) 68 | except: 69 | print("Faild to find minimap") 70 | button = self.get_npc_button() 71 | if not button: 72 | button = self.get_world_button() 73 | if button: 74 | width, height = self.frame_pil.size 75 | return self.frame_pil.crop((0, 0, button.left + button.width + 10, height)) 76 | else: 77 | return self.frame_pil 78 | 79 | def get_world_button(self): 80 | self.grab_frame() 81 | return locate(self.get_resource_path("mini map/World.png"), self.frame_pil) 82 | 83 | def get_npc_button(self): 84 | self.grab_frame() 85 | return locate(self.get_resource_path("mini map/Npc.png"), self.frame_pil) 86 | 87 | def click_ok_button(self, duration=1): 88 | self.grab_frame() 89 | button = locate_on_screen(self.get_resource_path('buttons/Ok.png'), confidence=.95) 90 | if button: 91 | pyautogui.click(button, duration=duration) 92 | 93 | def close_tabs(self): 94 | self.grab_frame() 95 | i = 1 96 | while locate_and_click(self.get_resource_path('buttons/Close button.png'), self.frame_pil, self.box, duration=.5, 97 | confidence=.8) and not self.pause_state: 98 | self.grab_frame() 99 | log('Closed tab num. ' + str(i)) 100 | press_and_release('enter') 101 | sleep(.25) 102 | i += 1 103 | 104 | def open_world_map(self): 105 | press_and_release(self.world_map_key) 106 | 107 | def get_resource_path(self, resource): 108 | path = self.resources_path / resource 109 | if not path.exists(): 110 | raise Exception("Unable to locate resource at " + str(path)) 111 | return str(path) 112 | 113 | def check_frame_for_resource(self, resource, confidence=.99): 114 | path = self.get_resource_path(resource) 115 | return True if locate(path, self.frame_pil, confidence=confidence) else False 116 | 117 | def check_world_menu_open(self): 118 | self.grab_frame() 119 | return self.check_frame_for_resource("messages/Select a world.png") 120 | 121 | def check_rune_message_open(self): 122 | self.grab_frame() 123 | return self.check_frame_for_resource("messages/Rune message 1.png") 124 | 125 | def check_settings_menu_open(self): 126 | self.grab_frame() 127 | return self.check_frame_for_resource("menus/Settings menu E.png") 128 | 129 | def check_ingame_channel_menu_open(self): 130 | self.grab_frame() 131 | return self.check_frame_for_resource("buttons/Change channel button.png") 132 | 133 | def check_unable_change_channel_dialog_open(self): 134 | self.grab_frame() 135 | return self.check_frame_for_resource("messages/Unable to change channel dialog.png") 136 | 137 | def check_news_window_open(self): 138 | self.grab_frame() 139 | return self.check_frame_for_resource("buttons/Login news buttons.png") 140 | 141 | def check_world_menu_channels_menu_open(self): 142 | self.grab_frame() 143 | return self.check_frame_for_resource("buttons/World menu channels button.png") 144 | 145 | def check_characters_menu_open(self): 146 | self.grab_frame() 147 | return self.check_frame_for_resource("buttons/Create character button.png") 148 | 149 | def check_cashshop_button_inview(self): 150 | self.grab_frame() 151 | return self.check_frame_for_resource("buttons/Cash shop button.png") 152 | 153 | def check_black_screen(self): 154 | self.grab_frame() 155 | return np.all(self.frame_arr[100:500, 100:500] == 0) 156 | 157 | def check_dead(self): 158 | self.grab_frame() 159 | return self.check_frame_for_resource("messages/Death message.png") 160 | 161 | def check_exp_bar_inview(self): 162 | self.grab_frame() 163 | return self.check_frame_for_resource("bars/EXP bar.png") 164 | 165 | def check_other_player_in_map(self, minimap=None): 166 | if not minimap: 167 | minimap = self.get_mini_map() 168 | return locate(self.get_resource_path("mini map/Other player.png"), minimap) 169 | 170 | def check_no_potion_curse(self): 171 | self.grab_frame() 172 | return self.check_frame_for_resource("curses/No potions curse.png") 173 | 174 | def check_rune_cooldown_message(self): 175 | self.grab_frame() 176 | return self.check_frame_for_resource("messages/Rune cooldown.png", confidence=.5) 177 | 178 | def check_rune_cooldown_buff(self): 179 | self.grab_frame() 180 | return self.check_frame_for_resource("curses/Rune cooldown.png", confidence=.75) 181 | 182 | def check_world_map_open(self): 183 | self.grab_frame() 184 | return self.check_frame_for_resource('bars/World map.png', confidence=.9) 185 | 186 | def check_world_map_teleport_message(self): 187 | self.grab_frame() 188 | return self.check_frame_for_resource('messages/World map teleport message.png', confidence=.75) 189 | 190 | def check_missing_hyper_message(self): 191 | self.grab_frame() 192 | return self.check_frame_for_resource('messages/Missing hyper rock.png', confidence=.75) 193 | 194 | def check_channel(self): 195 | return self.check_rune_message_open() \ 196 | or self.check_other_player_in_map() \ 197 | or self.check_cooldown('change_channel', self.channel_period) 198 | 199 | -------------------------------------------------------------------------------- /Controller/Controllers/MovementController.py: -------------------------------------------------------------------------------- 1 | from Controller.Controllers.GameController import GameController 2 | from Controller.MapleMoveMode import MapleMoveMode 3 | from Controller.funcs import * 4 | 5 | 6 | class MovementController(GameController): 7 | def __init__(self, settings_path, log_path='log.txt', resources_path="refs"): 8 | super().__init__(settings_path, log_path=log_path, resources_path=resources_path) 9 | 10 | self.move_mode = self.get('move_mode', 'hold') 11 | self.right_key = self.get('right') 12 | self.left_key = self.get('left') 13 | self.up_key = self.get('up') 14 | self.down_key = self.get('down') 15 | self.jump_key = self.get('jump', None) 16 | self.doublejump_state = self.get('doublejump', True) 17 | self.ascend_key = self.get('ascend', None) 18 | self.ascend_period = self.get('ascend_period', -1) 19 | self.hold_up_state = self.get('hold_up', True) 20 | self.direction_period = self.get('change_direction_period', 10) 21 | self.smart_direction_state = self.get('smart_direction', True) 22 | 23 | # Load TELEPORT settings 24 | if self.move_mode == MapleMoveMode.TELEPORT: 25 | self.teleport_up_period = self.get('teleport_up_period', 10) 26 | self.teleport_down_period = self.get('teleport_down_period', 30) 27 | self.teleport_up_key = self.get('teleport_up') 28 | self.teleport_down_key = self.get('teleport_down') 29 | self.teleport_right_key = self.get('teleport_right') 30 | self.teleport_left_key = self.get('teleport_left') 31 | self.hold_up_state = False 32 | 33 | if self.smart_direction_state: 34 | self.direction_period = 0 35 | 36 | # Default variables 37 | self.move_key = self.teleport_right_key if self.move_mode == MapleMoveMode.TELEPORT else self.right_key 38 | self.move_locked = False 39 | self.moving = False 40 | self.last_smart_direction = None 41 | 42 | def jump(self): 43 | press_and_release(self.jump_key) 44 | 45 | def doublejump(self): 46 | press_and_release(self.jump_key, repeat=2) 47 | 48 | def press_right(self): 49 | press(self.right_key) 50 | 51 | def release_right(self): 52 | release(self.right_key) 53 | 54 | def right(self): 55 | press_and_release(self.right_key) 56 | 57 | def press_left(self): 58 | press(self.left_key) 59 | 60 | def release_left(self): 61 | release(self.left_key) 62 | 63 | def left(self): 64 | press_and_release(self.left_key) 65 | 66 | def press_up(self): 67 | press(self.up_key) 68 | 69 | def release_up(self): 70 | release(self.up_key) 71 | 72 | def up(self): 73 | press_and_release(self.up_key) 74 | 75 | def press_down(self): 76 | press(self.down_key) 77 | 78 | def release_down(self): 79 | release(self.down_key) 80 | 81 | def down(self): 82 | press_and_release(self.down_key) 83 | 84 | def teleport_right(self): 85 | press_and_release(self.teleport_right_key) 86 | 87 | def teleport_left(self): 88 | press_and_release(self.teleport_left_key) 89 | 90 | def teleport_up(self): 91 | press_and_release(self.teleport_up_key) 92 | 93 | def teleport_down(self): 94 | press_and_release(self.teleport_down_key) 95 | 96 | def press_move(self): 97 | press(self.move_key) 98 | self.moving = True 99 | 100 | def release_move(self): 101 | self.focus_maple() 102 | release(self.move_key) 103 | self.moving = False 104 | 105 | def move(self): 106 | self.moving = True 107 | press_and_release(self.move_key) 108 | self.moving = False 109 | 110 | def toggle_move_direction(self): 111 | if self.move_mode == MapleMoveMode.HOLD: 112 | self.move_key = self.left_key if self.move_key == self.right_key else self.right_key 113 | elif self.move_mode == MapleMoveMode.TELEPORT: 114 | self.move_key = self.teleport_left_key if self.move_key == self.teleport_right_key else self.teleport_right_key 115 | 116 | def set_move_direction(self, direction_num, force_mode=None): 117 | if abs(direction_num) != 1: 118 | return 119 | elif self.move_mode == MapleMoveMode.HOLD or force_mode == MapleMoveMode.HOLD: 120 | self.move_key = self.left_key if direction_num == -1 else self.right_key 121 | elif self.move_mode == MapleMoveMode.TELEPORT or force_mode == MapleMoveMode.TELEPORT: 122 | self.move_key = self.teleport_left_key if direction_num == -1 else self.teleport_right_key 123 | log("Move direction key changed to: " + self.move_key) 124 | 125 | def change_move_direction(self): 126 | if self.smart_direction_state: 127 | direction = self.get_smart_direction() 128 | self.set_move_direction(direction) 129 | else: 130 | self.toggle_move_direction() 131 | 132 | def lock_move(self): 133 | self.move_locked = True 134 | 135 | def unlock_move(self): 136 | self.move_locked = False 137 | 138 | def is_move_locked(self): 139 | return self.move_locked 140 | 141 | def check_direction_and_change(self): 142 | log("Checking direction") 143 | if self.check_cooldown("change_direction", self.direction_period) and not self.is_move_locked(): 144 | self.change_direction() 145 | self.restart_cooldown("change_direction") 146 | 147 | def change_direction(self): 148 | moving = self.moving 149 | if moving and self.move_mode == MapleMoveMode.HOLD: 150 | self.release_move() 151 | self.change_move_direction() 152 | if moving and self.move_mode == MapleMoveMode.HOLD: 153 | self.press_move() 154 | 155 | def get_smart_direction(self, winPrecent=.5): 156 | minimap = self.get_mini_map() 157 | 158 | max_left = minimap.size[0] 159 | center_left = max_left // 2 160 | win_size = round(center_left * winPrecent) 161 | xMin, xMax = center_left - win_size, center_left + win_size 162 | 163 | try: 164 | player_left = self.get_player_position(minimap=minimap).left 165 | 166 | if player_left < xMin: 167 | direction = 1 168 | elif player_left > xMax: 169 | direction = -1 170 | else: 171 | return 0 172 | except: 173 | print("Couldn't find player") 174 | return np.random.choice([-1, 1]) 175 | 176 | self.last_smart_direction = direction 177 | return direction 178 | 179 | def ascend(self): 180 | press_and_release(self.ascend_key) 181 | 182 | def jump_or_doublejump(self): 183 | if self.doublejump_state: 184 | self.doublejump() 185 | else: 186 | self.jump() 187 | 188 | -------------------------------------------------------------------------------- /Controller/Controllers/PlayerController.py: -------------------------------------------------------------------------------- 1 | import re 2 | import sys 3 | 4 | import cv2 5 | 6 | from Controller.MapleMoveMode import MapleMoveMode 7 | from Controller.funcs import * 8 | from Controller.Controllers.PotionsController import PotionsController 9 | from Controller.Controllers.MovementController import MovementController 10 | 11 | 12 | class PlayerController(MovementController, PotionsController): 13 | def __init__(self, settings_path, log_path='log.txt', resources_path="refs", deathsfolder='deaths'): 14 | PotionsController.__init__(self, settings_path, log_path=log_path) 15 | MovementController.__init__(self, settings_path, log_path=log_path, resources_path=resources_path) 16 | 17 | # Settings variables 18 | self.attack_key = self.get('attack') 19 | self.attack_interval = self.get('attack_interval', .25) 20 | self.attack_repeat = self.get('attack_repeat', 5) 21 | self.buffs_key = self.get('buffs', []) 22 | self.buffs_period = self.get('buffs_period', 50) 23 | self.buffs_interval = self.get('buffs_interval', .5) 24 | self.skills = self.get('skills', []) 25 | self.skills_interval = self.get('skills_interval', .25) 26 | self.spawn_skills = self.get('spawn_skills', []) 27 | self.spawn_skills_interval = self.get('spawn_skills_interval', .25) 28 | self.interact_key = self.get('interact', 'space') 29 | self.hyper_teleport_state = self.get('hyper_teleport', True) 30 | self.attempt_restart_after_crash_state = self.get('attempt_restart_after_crash', True) 31 | self.console_update_period = self.get('console_update_period', 60) 32 | 33 | # Default variables 34 | self.deaths = 0 35 | self.deathsfolder = deathsfolder 36 | 37 | def get_exp_precent(self): 38 | try: 39 | box = get_maple_windows()[0].box 40 | images = ["slash.png", "bracket.png"] + [str(i) + '.png' for i in range(10)] 41 | pyautogui.moveTo(box.left + 5, box.top + box.height - 5, _pause=False) 42 | self.grab_frame() 43 | img = Image.fromarray(self.frame_arr[-30:-5, 5:500]) 44 | 45 | if locate(self.get_resource_path('EXP digits/exp.png'), img, confidence=.85): 46 | results = locate_all_multiple_images(img, 47 | self.get_resource_path('EXP digits/'), 48 | images, 49 | confidence=.85, 50 | key=lambda x: x[1].left) 51 | results = re.split('slash|bracket', ''.join(results[:, 0]))[:2] 52 | results = np.asarray(results, dtype=np.int64) 53 | exp, max_exp = results 54 | return exp / max_exp * 100 55 | else: 56 | return 0 57 | except: 58 | return 0 59 | 60 | def attack(self): 61 | log('Attacking') 62 | for i in range(self.attack_repeat): 63 | if self.pause_state or self.check_channel(): 64 | break 65 | press_and_release(self.attack_key) 66 | self.check_direction_and_change() 67 | sleep(self.attack_interval) 68 | 69 | def interact(self): 70 | press_and_release(self.interact_key) 71 | 72 | def use_buffs(self): 73 | self.release_move() 74 | 75 | for key in self.buffs_key: 76 | if self.pause_state or self.check_channel(): 77 | break 78 | self.check_health_and_heal() 79 | self.check_direction_and_change() 80 | sleep(self.buffs_interval) 81 | press_and_release(key) 82 | 83 | if self.move_mode == MapleMoveMode.HOLD: 84 | self.press_move() 85 | 86 | def use_skill(self, skill_settings): 87 | log('Using skill:' + str(skill_settings)) 88 | for i in range(5): 89 | if self.pause_state: 90 | break 91 | press(skill_settings['key']) 92 | sleep(skill_settings.get('hold', .1) / 5) 93 | release(skill_settings['key']) 94 | 95 | def use_uncooldowned_skills(self): 96 | if any(self.check_cooldown(skill['key'], skill['period']) for skill in self.skills): 97 | sleep(0.75) # Wait for any active animations to end 98 | for skill in self.skills: 99 | if self.pause_state or self.check_channel(): 100 | break 101 | if self.check_cooldown(skill['key'], skill['period']): 102 | self.check_health_and_heal() 103 | self.check_direction_and_change() 104 | self.use_skill(skill) 105 | self.restart_cooldown(skill['key']) 106 | sleep(self.skills_interval) 107 | 108 | def use_spawn_skills(self): 109 | for skill in self.spawn_skills: 110 | self.use_skill(skill) 111 | sleep(self.spawn_skills_interval) 112 | 113 | def save_last_frames(self, path, fps=10, fourcc='H264'): 114 | fourcc = cv2.VideoWriter_fourcc(*fourcc) 115 | writer = cv2.VideoWriter(path, fourcc, fps, self.frames[0].shape[1::-1]) 116 | 117 | for frame in self.frames: 118 | frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) 119 | writer.write(frame) 120 | 121 | writer.release() 122 | 123 | def move_channel(self): 124 | while self.get_status() == MapleState.ACTIVE and not self.pause_state: 125 | # Make sure player wont die during channel change 126 | self.check_health_and_heal() 127 | 128 | if self.check_dead(): 129 | log('Player died while trying to change channel') 130 | self.on_death() 131 | return False 132 | 133 | while self.check_no_potion_curse(): 134 | if self.pause_state: 135 | break 136 | self.check_direction_and_change() 137 | self.attack() 138 | sleep(.5) 139 | 140 | press_and_release('esc') 141 | sleep(.15) 142 | 143 | if self.check_settings_menu_open(): 144 | log('Change channel - Settings menu opened') 145 | press_and_release('enter') 146 | sleep(.15) 147 | 148 | if self.check_ingame_channel_menu_open(): 149 | log('Change channel - Channel menu opened') 150 | press_and_release('right') 151 | sleep(.15) 152 | 153 | # Make sure player wont die during channel change 154 | if self.check_health(): 155 | log('Change channel - Heal') 156 | press_and_release('esc') 157 | self.attack() 158 | self.heal() 159 | sleep(.15) 160 | continue 161 | 162 | press_and_release('enter') 163 | sleep(1) 164 | 165 | if self.check_unable_change_channel_dialog_open(): 166 | log('Change channel - Unable to change channel dialog') 167 | press_and_release('enter') 168 | continue 169 | 170 | # Random pixel turns black must mean success 171 | # Or if all screen turned black 172 | if self.check_black_screen(): 173 | log('Change channel - Successfully changed channel') 174 | if self.move_mode == MapleMoveMode.HOLD: 175 | self.check_direction_and_change() 176 | self.press_move() 177 | 178 | return True 179 | 180 | def attempt_rune(self): 181 | minimap = self.get_mini_map() 182 | player = self.get_player_position(.8, minimap=minimap) 183 | rune = self.get_rune_position(minimap=minimap) 184 | 185 | if player and rune: # If player and rune are visible in the minimap 186 | reached_rune = self.reach_rune() 187 | 188 | if reached_rune: 189 | # Maximum of 10 seconds to attempt activating the rune 190 | self.restart_cooldown('attempt rune') 191 | while not self.check_cooldown('attempt rune', 30) and not self.pause_state: 192 | log('Moving towards rune - ' + str(abs(player.left - rune.left)) + 'px left') 193 | self.check_health_and_heal() 194 | self.release_move() 195 | self.move() # Move towards rune 196 | 197 | activated = self.activate_rune(rune) 198 | if activated: 199 | log('Activated rune') 200 | break 201 | 202 | self.unlock_move() 203 | return False 204 | 205 | def reach_rune(self): 206 | log('Attempting to reach rune') 207 | 208 | minimap = self.get_mini_map() 209 | player = self.get_player_position(minimap=minimap) 210 | if not player: 211 | return False 212 | rune = self.get_rune_position(minimap=minimap) 213 | direction = -1 if player.left - rune.left > 0 else 1 214 | 215 | self.release_move() 216 | self.lock_move() 217 | self.set_move_direction(direction, force_mode=MapleMoveMode.HOLD) 218 | 219 | # Maximum of 10 seconds to reach rune x axis 220 | self.restart_cooldown('reach rune x axis') 221 | 222 | while not self.check_cooldown('reach rune x axis', 15) and not self.pause_state: 223 | self.check_health_and_heal() 224 | 225 | player = self.get_player_position() 226 | 227 | if not player: 228 | continue 229 | 230 | currentDirection = -1 if player.left - rune.left > 0 else 1 231 | 232 | if currentDirection == direction: 233 | self.press_move() 234 | if self.doublejump_state: 235 | self.doublejump() 236 | continue 237 | else: 238 | self.unlock_move() 239 | self.release_move() 240 | self.set_move_direction(currentDirection, force_mode=MapleMoveMode.HOLD) 241 | self.press_move() 242 | 243 | while not self.check_cooldown('reach rune x axis', 15) and not self.pause_state: 244 | self.check_health_and_heal() 245 | player = self.get_player_position() 246 | 247 | if abs(player.left - rune.left) <= 3: 248 | self.release_move() 249 | break 250 | 251 | player = self.get_player_position() 252 | 253 | if player.top > rune.top: # Player below rune 254 | while not self.check_cooldown('reach rune x axis', 15) and not self.pause_state: 255 | self.check_health_and_heal() 256 | player = self.get_player_position() 257 | 258 | if not player: 259 | continue 260 | 261 | if rune.top - 3 <= player.top <= rune.top + 3: # Check if player reached rune 262 | return True 263 | 264 | self.ascend() 265 | sleep(.5) 266 | else: # Player above rune 267 | while not self.check_cooldown('reach rune x axis', 15) and not self.pause_state: 268 | self.check_health_and_heal() 269 | player = self.get_player_position() 270 | 271 | if not player: 272 | continue 273 | 274 | if rune.top - 3 <= player.top <= rune.top + 3: # Check if player reached rune 275 | return True 276 | 277 | press_and_release(self.down_key + "+" + self.jump_key) 278 | sleep(.5) 279 | 280 | return False 281 | 282 | def activate_rune(self, rune): 283 | log('Attempting to activate rune') 284 | 285 | # Help function 286 | def filter_rune_results(results): 287 | results = list(results) 288 | if len(results) == 0: return [] 289 | current_result = results[0] 290 | yield (current_result[0], current_result[1].left) 291 | for result in results: 292 | if not (current_result[1].left - 10 <= result[1].left <= current_result[1].left + 10): 293 | current_result = result 294 | yield (current_result[0], current_result[1].left) 295 | 296 | player = self.get_player_position() 297 | 298 | if not player: 299 | return False 300 | elif rune.left - 3 <= player.left <= rune.left + 3: # Check if player reached rune 301 | self.restart_cooldown('activate rune') 302 | while not self.check_cooldown('activate rune', 15) and not self.pause_state: 303 | sleep(1.5) 304 | self.interact() 305 | 306 | sleep(.5) 307 | self.grab_frame(focus=False) 308 | 309 | rune_keys_pil = self.frame_pil.crop((150, 150, 650, 400)) 310 | keys = locate_all_multiple_images(rune_keys_pil, 311 | self.get_resource_path('rune keys/'), 312 | ["Up.png", "Down.png", "Right.png", "Left.png"], 313 | confidence=.7, 314 | key=lambda x: x[1].left) 315 | 316 | keys = list(filter_rune_results(keys)) 317 | 318 | if len(keys) == 0: 319 | return True 320 | 321 | for key, x in keys: 322 | press_and_release(key) 323 | sleep(.25) 324 | 325 | return False 326 | 327 | def mark_world_map_location(self): 328 | self.focus_maple() 329 | if not self.check_world_map_open(): 330 | self.open_world_map() 331 | sleep(.5) 332 | self.grab_frame(focus=False) 333 | if self.check_world_map_open(): 334 | mark = locate(self.get_resource_path('map/Location mark.png'), self.frame_pil, confidence=.85) 335 | self.open_world_map() # Press world map key to close it 336 | sleep(.5) 337 | return mark 338 | 339 | def teleport_to_mark(self, mark): 340 | if mark: 341 | self.focus_maple() 342 | self.open_world_map() 343 | sleep(.5) 344 | for i in range(10): 345 | pyautogui.doubleClick(self.box.left + mark.left + mark.width // 2, 346 | self.box.top + mark.top + mark.height + i, duration=1 / 3) 347 | if self.check_world_map_teleport_message(): 348 | press_and_release('enter') 349 | return True 350 | elif self.check_missing_hyper_message(): 351 | return False 352 | return False 353 | 354 | def on_death(self, save_vid=True): 355 | log('Player died, saving death video') 356 | if save_vid: 357 | if not os.path.exists(self.deathsfolder): 358 | os.makedirs(self.deathsfolder) 359 | self.save_last_frames( 360 | self.deathsfolder + '\\' + datetime.datetime.now().strftime("%m-%d-%Y %H-%M-%S") + '.mp4') 361 | self.deaths += 1 362 | if self.hyper_teleport_state: 363 | sleep(2) 364 | mark = self.mark_world_map_location() 365 | sleep(1) 366 | self.click_ok_button() 367 | sleep(5) 368 | self.check_health_and_heal() 369 | if mark: 370 | if self.teleport_to_mark(mark): 371 | sleep(3) 372 | self.use_spawn_skills() 373 | else: 374 | raise Exception('Faild respawning after death') 375 | else: 376 | sys.exit() 377 | 378 | controller = PlayerController("Shade Settings.json", resources_path="../Controller/refs") -------------------------------------------------------------------------------- /Controller/Controllers/PotionsController.py: -------------------------------------------------------------------------------- 1 | from Controller.Controllers.BaseController import BaseController 2 | from Controller.funcs import * 3 | 4 | 5 | class PotionsController(BaseController): 6 | def __init__(self, settings_path, log_path='log.txt'): 7 | super().__init__(settings_path, log_path) 8 | 9 | self.hp_potion_key = self.get('hp_potion', None) 10 | self.min_potion_hp = self.get('min_potion_hp', 50) 11 | self.mana_potion_key = self.get('mana_potion', None) 12 | self.min_potion_mp = self.get('min_potion_mp', 50) 13 | self.potions_per_use = self.get('potions_per_use', 1) 14 | self.delay_per_potion = self.get('delay_per_potion', 0) 15 | self.pet_food_key = self.get('pet_food', None) 16 | self.pet_food_period = self.get('pet_food_period', 100) 17 | 18 | self.hp_potions_used = 0 19 | self.mp_potions_used = 0 20 | 21 | def get_hp_precent(self): 22 | try: 23 | self.grab_frame() 24 | img = self.frame_arr[575:586, 441:571] 25 | img = img.copy() 26 | img[np.where(img < 200)] = 0 27 | imax = 0 28 | for row in img: 29 | r, g, b = row.T 30 | cond = (r > 240) & (g == 0) & (b == 0) 31 | i = np.where(cond)[0].max() 32 | if i > imax: 33 | imax = i 34 | return imax / img.shape[1] * 100 35 | except: 36 | return 0 37 | 38 | def get_mp_precent(self): 39 | self.grab_frame() 40 | img = self.frame_arr[591:602, 441:578] 41 | img = img.copy() 42 | r, g, b = img.T 43 | cond = (r < 200) & (g > 200) & (b > 200) 44 | try: 45 | mp = np.where(cond)[0].max() 46 | except: 47 | mp = 0 48 | return mp / img.shape[1] * 100 49 | 50 | def check_health(self): 51 | return self.get_hp_precent() < self.min_potion_hp 52 | 53 | def check_health_and_heal(self, after_delay=0): 54 | if self.check_health(): 55 | self.heal() 56 | sleep(after_delay) 57 | 58 | def check_mana(self): 59 | return self.get_mp_precent() < self.min_potion_mp 60 | 61 | def heal(self): 62 | self.grab_frame() 63 | for i in range(self.potions_per_use): 64 | press_and_release(self.hp_potion_key) 65 | self.hp_potions_used += 1 66 | log('Healing') 67 | if i > 0: sleep(self.delay_per_potion) 68 | 69 | def fill_mana(self, delay_per_fill=.25): 70 | self.grab_frame() 71 | for i in range(self.potions_per_use): 72 | press_and_release(self.mana_potion_key) 73 | self.mp_potions_used += 1 74 | log('Filling mana') 75 | if i > 0: sleep(self.delay_per_potion) 76 | 77 | def feed_pet(self): 78 | press_and_release(self.pet_food_key) 79 | -------------------------------------------------------------------------------- /Controller/Controllers/SettingsController.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | 4 | class SettingsController: 5 | DEFAULT_VAL = "~SETTINGS_CONTROLLER_DEFAULT_VALUE~" 6 | 7 | def __init__(self, settings_path): 8 | self.settings = SettingsController.load_settings(settings_path) 9 | 10 | @staticmethod 11 | def load_settings(path): 12 | with open(path) as fd: 13 | return json.load(fd) 14 | 15 | def get(self, key, default_value=DEFAULT_VAL): 16 | if key not in self.settings: 17 | if default_value == SettingsController.DEFAULT_VAL: 18 | raise ValueError("The .json file does not contain the key '" + key + "'") 19 | else: 20 | return default_value 21 | else: 22 | return self.settings[key] 23 | -------------------------------------------------------------------------------- /Controller/Elite boss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/Elite boss.png -------------------------------------------------------------------------------- /Controller/MapleMoveMode.py: -------------------------------------------------------------------------------- 1 | class MapleMoveMode: 2 | HOLD = 'hold' 3 | TELEPORT = 'teleport' 4 | -------------------------------------------------------------------------------- /Controller/MapleState.py: -------------------------------------------------------------------------------- 1 | class MapleState: 2 | CLOSED = 0 3 | ACTIVE = 1 4 | CRASHED = 2 5 | -------------------------------------------------------------------------------- /Controller/docs/Controller Settings.md: -------------------------------------------------------------------------------- 1 | # Settings.json 2 | The `settings.json` file is used to contain the settings of the `MapleController` class, below you can find all the optional parameters that can be used within it. 3 | 4 | Notes: 5 | 1. The names are case sensitive. 6 | 2. An empty default cell means required. 7 | 8 | ### General 9 | Name | Type | Description | Default 10 | ---- | ---- | ---- | ---- 11 | `install_origin` | String | The source of your installation, can be either `steam` or `nexon` | 12 | `world` | String | The world your character is in (use this only if you want to use the auto restart system) | 13 | `PIC` | String | Your character's PIC (use this only if you want to use the auto restart system) | 14 | `toggle_pause` | Boolean | The key used to toggle in and out of pause mode | `f5` 15 | `attempt_restart_after_crash` | Boolean | Indication if to attempt restart when the game crashes | `true` 16 | `hyper_teleport` | Boolean | Indication if to attempt to teleport back to the training region after death (using an hyper teleport rock) | `true` 17 | 18 | ### Movement 19 | Name | Type | Description | Default 20 | ---- | ---- | ---- | ---- 21 | `move_mode` | String | The mode of the movement, can be either `hold` or `teleport` | `hold` 22 | `smart_direction` | Boolean | Indicates if the direction of the player is smartly decided (more info below) or is constantly switching between right and left | `true` 23 | `right` | String | The key of your right movement | 24 | `left` | String | The key of your left movement | 25 | `up` | String | The key of your up movement | 26 | `down` | String | The key of your down movement | 27 | `teleport_right` | String | The key (or key combination, i.e. `right+shift`) used to teleport right (use this only when `move_mode=teleport`) | `None` 28 | `teleport_left` | String | The key (or key combination, i.e. `right+shift`) used to teleport left (use this only when `move_mode=teleport`) | `None` 29 | `teleport_up` | String | The key (or key combination, i.e. `right+shift`) used to teleport up (use this only when `move_mode=teleport`) | `None` 30 | `teleport_down` | String | The key (or key combination, i.e. `right+shift`) used to teleport down (use this only when `move_mode=teleport`) | `None` 31 | `teleport_up_period` | Number | The period of which to teleport up (use this only when `move_mode=teleport`) | 10 32 | `teleport_down_period` | Number | The period of which to teleport down (use this only when `move_mode=teleport`) | 30 33 | `hold_up` | Boolean | Indication if to keep the up key pressed the entire time | `true` 34 | `jump` | String | The key of your character's jump | 35 | `doublejump` | Boolean | Indication if to double jump (press the jump key twice) everytime you jump | `true` 36 | `change_direction_period` | Number | The period of which to change direction | 10 (seconds) 37 | 38 | ### Attack 39 | Name | Type | Description | Default 40 | ---- | ---- | ---- | ---- 41 | `attack` | String | The key of your main attack | 42 | `attack_repeat` | Number | The number of attacks (key presses) to perform each time you attack | 5 43 | `attack_interval` | Number | The delay (in seconds) between each of the key presses | 0.25 44 | 45 | ### Misc 46 | Name | Type | Description | Default 47 | ---- | ---- | ---- | ---- 48 | `interact` | String | The key used to activate runes / interact with stuff | `space` 49 | `world_map` | String | The key used to open the world map | `w` 50 | 51 | ### Potions 52 | Name | Type | Description | Default 53 | ---- | ---- | ---- | ---- 54 | `hp_potion` | String | The key of your HP potion | `None` 55 | `min_potion_hp` | Number | Minimum HP required to take a potion in precent | 50 56 | `mana_potion` | String | The key of your MP potion | `None` 57 | `min_potion_mp` | Number | Minimum MP required to take a potion in precent | 50 58 | `potions_per_use` | Number | The number of potions to take each time (this applies to both HP and MP) | 1 59 | `delay_per_potion` | Number | Delay (in seconds) per potion take | 0 60 | `pet_food` | String | The key of your pet food | `None` 61 | `pet_food_period` | Number | The period of which to take the pet food | 100 (1.4 minutes) 62 | 63 | ### Channel 64 | Name | Type | Description | Default 65 | ---- | ---- | ---- | ---- 66 | `change_channel_period` | Number | The period of which to change channel | 600 (10 minutes) 67 | 68 | ### Buffs 69 | Name | Type | Description | Default 70 | ---- | ---- | ---- | ---- 71 | `buffs` | List\ | A list of strings where each string is a key for a buff | `[]` (empty list) 72 | `buffs_interval` | Number | The delay (in seconds) between each buff's keypress | 0.5 73 | `buffs_period` | Number | The period of which to activate the buffs | 50 (seconds) 74 | 75 | ### Skills 76 | Name | Type | Description | Default 77 | ---- | ---- | ---- | ---- 78 | `skills` | List<{}> | A list of dicts where each dict is a skills containing `key`, `period` and (optional) `hold` | `[]` 79 | `skills_interval` | Number | The delay between skill keypress | 0.25 80 | `spawn_skills` | List<{}> | A list of skills to activate on spawn (death respawn or crash) | `[]` 81 | `spawn_skills_interval` | Number | The delay between skill keypresses | 0.25 82 | 83 | ### Misc skills 84 | Name | Type | Description | Default 85 | ---- | ---- | ---- | ---- 86 | `ascend` | String | Key used to quickly ascend to the platform above you (For example the skill `Rope Lift`) | `None` 87 | `ascend_period` | Number | The period of which to ascend upwards | -1 (seconds) 88 | 89 | # Move mode 90 | Move mode dictates the mode of which to move the player, currently the available modes are: 91 | - `hold`: Leaving the direction key pressed until direction change to keep the player constantly moving. 92 | - `teleport`: Constantly teleports the player, make sure to set all teleportation keys (i.e. if `up+shift` teleport you up than set this as your `teleport_up` key). this would also overwrite `hold_up` to `false`. 93 | 94 | # Smart direction 95 | When smart direction is enabled the player will be constantly guided into the center of the map, this feature will overwrite `change_direction_period` to 0. 96 | 97 | ![alt text](https://raw.githubusercontent.com/tomergt45/MapleController/main/Controller/docs/images/Smart%20direction%20example.png) 98 | -------------------------------------------------------------------------------- /Controller/docs/images/Download folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/docs/images/Download folder.png -------------------------------------------------------------------------------- /Controller/docs/images/Json selection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/docs/images/Json selection.png -------------------------------------------------------------------------------- /Controller/docs/images/Resolution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/docs/images/Resolution.png -------------------------------------------------------------------------------- /Controller/docs/images/Smart direction example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/docs/images/Smart direction example.png -------------------------------------------------------------------------------- /Controller/docs/images/UAC1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/docs/images/UAC1.png -------------------------------------------------------------------------------- /Controller/docs/images/UAC2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/docs/images/UAC2.png -------------------------------------------------------------------------------- /Controller/funcs.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import os 3 | import time 4 | 5 | import keyboard 6 | import mss 7 | import numpy as np 8 | import psutil 9 | import pyautogui 10 | import win32gui 11 | from PIL import Image 12 | from win32com.client import Dispatch 13 | from Controller.MapleState import MapleState 14 | 15 | 16 | def get_maple_hwnd(): 17 | return win32gui.FindWindowEx(None, None, None, 'MapleStory') 18 | 19 | 20 | def get_maple_processes(): 21 | for proc in psutil.process_iter(): 22 | if 'maplestory' in proc.name().lower(): 23 | yield proc 24 | 25 | 26 | def convert_psutil_status(status): 27 | if status == psutil.STATUS_RUNNING: 28 | return MapleState.ACTIVE 29 | else: 30 | return MapleState.CRASHED 31 | 32 | 33 | def get_maple_status(): 34 | mprocesses = list(get_maple_processes()) 35 | if len(mprocesses) == 0: 36 | return MapleState.CLOSED 37 | else: 38 | for mproc in mprocesses: 39 | status = convert_psutil_status(mproc.status()) 40 | if status != MapleState.ACTIVE: 41 | return status 42 | return MapleState.ACTIVE 43 | 44 | 45 | def focus_maple(): 46 | hwnd = get_maple_hwnd() 47 | shell = Dispatch("WScript.Shell") 48 | shell.SendKeys('%') 49 | try: 50 | win32gui.SetForegroundWindow(hwnd) 51 | except: 52 | pass 53 | 54 | 55 | def get_maple_windows(): 56 | wins = pyautogui.getWindowsWithTitle("MapleStory") 57 | if get_maple_status() == MapleState.ACTIVE and len(wins) > 0: 58 | return list(filter(lambda x: x.title == 'MapleStory', wins)) 59 | else: 60 | raise Exception("Unable to get maplestory, maplestory is not running") 61 | 62 | 63 | def grab_maple(focus=True): 64 | wins = get_maple_windows() 65 | box = wins[0].box 66 | if len(wins) == 0: 67 | return None 68 | 69 | if focus: 70 | focus_maple() 71 | 72 | with mss.mss() as sct: 73 | mon = sct.monitors[1] 74 | monitor = { 75 | "top": mon["top"] + box.top, # 100px from the top 76 | "left": mon["left"] + box.left, # 100px from the left 77 | "width": box.width, 78 | "height": box.height, 79 | "mon": 1, 80 | } 81 | img = sct.grab(monitor) 82 | img = Image.frombytes("RGB", img.size, img.bgra, "raw", "BGRX") 83 | 84 | return img, box 85 | 86 | 87 | def press_and_release(key, release_delay=.1, repeat=1): 88 | if key: 89 | for i in range(repeat): 90 | press(key) 91 | sleep(release_delay) 92 | release(key) 93 | 94 | 95 | def press(key): 96 | if key: 97 | keyboard.press(key) 98 | 99 | 100 | def release(key): 101 | if key: 102 | keyboard.release(key) 103 | 104 | 105 | def click(x=None, y=None, duration=0, clicks=1, interval=0): 106 | pyautogui.click(x, y, duration=duration, interval=interval, clicks=clicks) 107 | 108 | 109 | def locate(img_path, source, confidence=.999): 110 | return pyautogui.locate(img_path, source, confidence=confidence) 111 | 112 | 113 | def locate_all(img_path, source, confidence=.999): 114 | return pyautogui.locateAll(img_path, source, confidence=confidence) 115 | 116 | 117 | def locate_all_multiple_images(source, path, imgnames, confidence=.99, key=None): 118 | results = [] 119 | for img in imgnames: 120 | img_path = os.path.join(path, img) 121 | img = img.split('.')[0] 122 | for result in locate_all(img_path, source, confidence): 123 | results.append((img, result)) 124 | results = sorted(results, key=key) if key else results 125 | return np.asarray(results, dtype=tuple) 126 | 127 | 128 | def locate_on_screen(img_path, confidence=.999): 129 | return pyautogui.locateOnScreen(img_path, confidence=confidence) 130 | 131 | 132 | def locate_all_on_screen(img_path, confidence=.999): 133 | return pyautogui.locateAllOnScreen(img_path, confidence=confidence) 134 | 135 | 136 | def locate_on_screen_and_click(img_path, clicks=1, clicks_interval=0, duration=0, confidence=.999): 137 | box = locate_on_screen(img_path, confidence=confidence) 138 | if box: 139 | click(box, duration=duration, clicks=clicks, interval=clicks_interval) 140 | return True 141 | return False 142 | 143 | 144 | def locate_and_click(img_path, source, source_box, clicks=1, clicks_interval=0, duration=0, confidence=.999): 145 | box = locate(img_path, source, confidence=confidence) 146 | if box: 147 | click(source_box.left + box.left, source_box.top + box.top, duration=duration, clicks=clicks, 148 | interval=clicks_interval) 149 | return True 150 | return False 151 | 152 | 153 | def sleep(seconds): 154 | time.sleep(seconds) 155 | 156 | 157 | def log(message, path='log.txt', console=False): 158 | with open(path, 'a') as fd: 159 | message = '[{}] {}\n'.format(str(datetime.datetime.now()), message) 160 | fd.write(message) 161 | if console: 162 | print(message) 163 | 164 | 165 | def clearlog(path='log.txt'): 166 | with open(path, 'w') as fd: 167 | fd.seek(0) 168 | fd.truncate() 169 | 170 | def pretty_delta(delta, granularity=2): 171 | result = [] 172 | intervals = (('weeks', 604800), ('days', 86400), ('hours', 3600), ('minutes', 60), ('seconds', 1)) 173 | seconds = delta.seconds 174 | for name, count in intervals: 175 | value = seconds // count 176 | if value: 177 | seconds -= value * count 178 | if value == 1: 179 | name = name.rstrip('s') 180 | result.append("{} {}".format(value, name)) 181 | return ', '.join(result[:granularity]) 182 | -------------------------------------------------------------------------------- /Controller/refs/EXP digits/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/EXP digits/0.png -------------------------------------------------------------------------------- /Controller/refs/EXP digits/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/EXP digits/1.png -------------------------------------------------------------------------------- /Controller/refs/EXP digits/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/EXP digits/2.png -------------------------------------------------------------------------------- /Controller/refs/EXP digits/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/EXP digits/3.png -------------------------------------------------------------------------------- /Controller/refs/EXP digits/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/EXP digits/4.png -------------------------------------------------------------------------------- /Controller/refs/EXP digits/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/EXP digits/5.png -------------------------------------------------------------------------------- /Controller/refs/EXP digits/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/EXP digits/6.png -------------------------------------------------------------------------------- /Controller/refs/EXP digits/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/EXP digits/7.png -------------------------------------------------------------------------------- /Controller/refs/EXP digits/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/EXP digits/8.png -------------------------------------------------------------------------------- /Controller/refs/EXP digits/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/EXP digits/9.png -------------------------------------------------------------------------------- /Controller/refs/EXP digits/bracket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/EXP digits/bracket.png -------------------------------------------------------------------------------- /Controller/refs/EXP digits/exp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/EXP digits/exp.png -------------------------------------------------------------------------------- /Controller/refs/EXP digits/slash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/EXP digits/slash.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/0.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/1.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/2.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/3.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/4.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/5.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/6.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/7.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/8.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/9.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/a.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/b.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/c.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/d.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/e.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/f.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/g.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/g.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/h.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/i.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/i.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/j.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/j.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/k.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/k.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/l.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/l.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/m.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/m.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/n.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/o.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/o.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/p.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/p.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/q.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/q.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/r.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/r.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/s.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/t.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/t.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/u.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/u.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/v.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/v.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/w.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/x.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/y.png -------------------------------------------------------------------------------- /Controller/refs/PIC keys/z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/PIC keys/z.png -------------------------------------------------------------------------------- /Controller/refs/bars/EXP bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/bars/EXP bar.png -------------------------------------------------------------------------------- /Controller/refs/bars/World map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/bars/World map.png -------------------------------------------------------------------------------- /Controller/refs/buttons/Cash shop button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/buttons/Cash shop button.png -------------------------------------------------------------------------------- /Controller/refs/buttons/Change channel button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/buttons/Change channel button.png -------------------------------------------------------------------------------- /Controller/refs/buttons/Close button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/buttons/Close button.png -------------------------------------------------------------------------------- /Controller/refs/buttons/Create character button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/buttons/Create character button.png -------------------------------------------------------------------------------- /Controller/refs/buttons/Login news buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/buttons/Login news buttons.png -------------------------------------------------------------------------------- /Controller/refs/buttons/Ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/buttons/Ok.png -------------------------------------------------------------------------------- /Controller/refs/buttons/World menu channels button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/buttons/World menu channels button.png -------------------------------------------------------------------------------- /Controller/refs/curses/No potions curse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/curses/No potions curse.png -------------------------------------------------------------------------------- /Controller/refs/curses/Rune cooldown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/curses/Rune cooldown.png -------------------------------------------------------------------------------- /Controller/refs/map/Location mark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/map/Location mark.png -------------------------------------------------------------------------------- /Controller/refs/menus/Settings menu E.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/menus/Settings menu E.png -------------------------------------------------------------------------------- /Controller/refs/messages/Death message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/messages/Death message.png -------------------------------------------------------------------------------- /Controller/refs/messages/Missing hyper rock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/messages/Missing hyper rock.png -------------------------------------------------------------------------------- /Controller/refs/messages/Rune cooldown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/messages/Rune cooldown.png -------------------------------------------------------------------------------- /Controller/refs/messages/Rune message 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/messages/Rune message 1.png -------------------------------------------------------------------------------- /Controller/refs/messages/Select a world.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/messages/Select a world.png -------------------------------------------------------------------------------- /Controller/refs/messages/Unable to change channel dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/messages/Unable to change channel dialog.png -------------------------------------------------------------------------------- /Controller/refs/messages/World map teleport message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/messages/World map teleport message.png -------------------------------------------------------------------------------- /Controller/refs/mini map/Left edge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/mini map/Left edge.png -------------------------------------------------------------------------------- /Controller/refs/mini map/Npc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/mini map/Npc.png -------------------------------------------------------------------------------- /Controller/refs/mini map/Other player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/mini map/Other player.png -------------------------------------------------------------------------------- /Controller/refs/mini map/Player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/mini map/Player.png -------------------------------------------------------------------------------- /Controller/refs/mini map/Portal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/mini map/Portal.png -------------------------------------------------------------------------------- /Controller/refs/mini map/Right edge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/mini map/Right edge.png -------------------------------------------------------------------------------- /Controller/refs/mini map/Rune.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/mini map/Rune.png -------------------------------------------------------------------------------- /Controller/refs/mini map/World.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/mini map/World.png -------------------------------------------------------------------------------- /Controller/refs/rune keys/Down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/rune keys/Down.png -------------------------------------------------------------------------------- /Controller/refs/rune keys/Left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/rune keys/Left.png -------------------------------------------------------------------------------- /Controller/refs/rune keys/Right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/rune keys/Right.png -------------------------------------------------------------------------------- /Controller/refs/rune keys/Up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/rune keys/Up.png -------------------------------------------------------------------------------- /Controller/refs/worlds/aurora.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/worlds/aurora.png -------------------------------------------------------------------------------- /Controller/refs/worlds/bera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/worlds/bera.png -------------------------------------------------------------------------------- /Controller/refs/worlds/burning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/worlds/burning.png -------------------------------------------------------------------------------- /Controller/refs/worlds/elysium.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/worlds/elysium.png -------------------------------------------------------------------------------- /Controller/refs/worlds/reboot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/worlds/reboot.png -------------------------------------------------------------------------------- /Controller/refs/worlds/scania.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Controller/refs/worlds/scania.png -------------------------------------------------------------------------------- /Dependencies/__pycache__/NotebookLoader.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Dependencies/__pycache__/NotebookLoader.cpython-39.pyc -------------------------------------------------------------------------------- /Dependencies/__pycache__/admin.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerh2001/MapleController/e0dbdca616cd56fcf242bcd1f6390b77de1f45e5/Dependencies/__pycache__/admin.cpython-39.pyc -------------------------------------------------------------------------------- /Dependencies/admin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8; mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- 3 | # vim: fileencoding=utf-8 tabstop=4 expandtab shiftwidth=4 4 | 5 | # (C) COPYRIGHT © Preston Landers 2010 6 | # Released under the same license as Python 2.6.5 7 | 8 | 9 | import sys, os, traceback, types 10 | 11 | def isUserAdmin(): 12 | 13 | if os.name == 'nt': 14 | import ctypes 15 | # WARNING: requires Windows XP SP2 or higher! 16 | try: 17 | return ctypes.windll.shell32.IsUserAnAdmin() 18 | except: 19 | traceback.print_exc() 20 | print("Admin check failed, assuming not an admin.") 21 | return False 22 | elif os.name == 'posix': 23 | # Check for root on Posix 24 | return os.getuid() == 0 25 | else: 26 | raise( RuntimeError, "Unsupported operating system for this module: %s" % (os.name,)) 27 | 28 | def runAsAdmin(cmdLine=None, wait=True): 29 | 30 | if os.name != 'nt': 31 | raise( RuntimeError, "This function is only implemented on Windows.") 32 | 33 | import win32api, win32con, win32event, win32process 34 | from win32com.shell.shell import ShellExecuteEx 35 | from win32com.shell import shellcon 36 | 37 | python_exe = sys.executable 38 | 39 | if cmdLine is None: 40 | cmdLine = [python_exe] + sys.argv 41 | elif type(cmdLine) not in (types.TupleType,types.ListType): 42 | raise( ValueError, "cmdLine is not a sequence.") 43 | cmd = '"%s"' % (cmdLine[0],) 44 | # XXX TODO: isn't there a function or something we can call to massage command line params? 45 | params = " ".join(['"%s"' % (x,) for x in cmdLine[1:]]) 46 | cmdDir = '' 47 | showCmd = win32con.SW_SHOWNORMAL 48 | #showCmd = win32con.SW_HIDE 49 | lpVerb = 'runas' # causes UAC elevation prompt. 50 | 51 | # print("Running", cmd, params 52 | 53 | # ShellExecute() doesn't seem to allow us to fetch the PID or handle 54 | # of the process, so we can't get anything useful from it. Therefore 55 | # the more complex ShellExecuteEx() must be used. 56 | 57 | # procHandle = win32api.ShellExecute(0, lpVerb, cmd, params, cmdDir, showCmd) 58 | 59 | procInfo = ShellExecuteEx(nShow=showCmd, 60 | fMask=shellcon.SEE_MASK_NOCLOSEPROCESS, 61 | lpVerb=lpVerb, 62 | lpFile=cmd, 63 | lpParameters=params) 64 | 65 | if wait: 66 | procHandle = procInfo['hProcess'] 67 | obj = win32event.WaitForSingleObject(procHandle, win32event.INFINITE) 68 | rc = win32process.GetExitCodeProcess(procHandle) 69 | #print("Process handle %s returned code %s" % (procHandle, rc) 70 | else: 71 | rc = None 72 | 73 | return rc 74 | 75 | def test(): 76 | rc = 0 77 | if not isUserAdmin(): 78 | print("You're not an admin.", os.getpid(), "params: ", sys.argv) 79 | #rc = runAsAdmin(["c:\\Windows\\notepad.exe"]) 80 | rc = runAsAdmin() 81 | else: 82 | print("You are an admin!", os.getpid(), "params: ", sys.argv) 83 | rc = 0 84 | x = raw_input('Press Enter to exit.') 85 | return rc 86 | 87 | 88 | if __name__ == "__main__": 89 | sys.exit(test()) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AFK Bot 2 | A less-detectable, easy to use MapleStory bot using fancy computer vision and clever coding. Train while you're AFK, farm mesos, boost main/secondary characters and more! 3 | 4 | **Note: this is not cheats by any means, this bot does not access the game's memory data or files.** 5 | 6 | ## Download 7 | https://mega.nz/file/c4lSRTxJ#YZZcqvFK_nOaXrVCdNz0AQaoHrQtv1slaSwNbFNYLY8 8 | 9 | ## Features 10 | - Auto crash detection, restart & login 11 | - Move & attack 12 | - Use skills 13 | - Predict time to rankup 14 | - Activate buffs periodically 15 | - Take potions (HP, MP & Pet) 16 | - Change channels 17 | - Avoid players (by changing channel, to ensure not getting reported) 18 | - Activate ruins 19 | - Teleport back after death (using hyper teleport rock) 20 | - Settings per character 21 | 22 | ### Upcoming features 23 | - Kanna follower 24 | - In-game overlay 25 | - Email notifications 26 | - And much, much more! 27 | 28 | ## Setup 29 | 1. Download the files using the download link above and extract all of them into the same folder 30 | 31 | alt text 32 | 33 | - Open the `settings.json` file, this file will contain all the insutrctions for the bot, make sure to adjust everything according to your character, if you plan on using the bot with multiple characters then create a `.json` file for each character and name it accordingly, for example `Kanna Settings.json`, `Shade Settings.json`, etc... 34 | 35 | - By default the `settings.json` that you download will contain only the default parameters and would look something like that: 36 | 37 | ``` 38 | { 39 | "install_origin": "steam", 40 | "world": "bera", 41 | "PIC": "password", 42 | "hold_up": false, 43 | "right": "right", 44 | "left": "left", 45 | "up": "up", 46 | "down": "down", 47 | "jump": "alt", 48 | "hp_potion": "delete", 49 | "mana_potion": "insert", 50 | "pet_food": "end", 51 | "attack": "d", 52 | "buffs": [], 53 | "skills": [] 54 | } 55 | ``` 56 | 57 | - You can add more parameters to customize the bot's behavior, for example add periodic skills, spawn skills, interval between attacks, num. of attacks, and MUCH MORE. 58 | You can find all the other parameters here: https://github.com/tomergt45/MapleController/blob/main/docs/Controller%20Settings.md 59 | 60 | - Make sure to edit all the parameters according to your character keys and behavior (i.e. animation time, etc...) 61 | 62 | 2. While using the bot, maplestory MUST be on 800x600 (4:3) windowed 63 | alt text 64 | 65 | 3. Disable UAC (only if you use the auto restart feature). 66 | This is because when maplestory is launched, you are prompted with an admin privileges dialog, this dialog cannot be accepeted via code so in order to automate the process you'll need to disable it while using the bot. 67 | 68 | - Search "UAC" in the windows search 69 | 70 | alt text 71 | 72 | - Set it to "Never notify me ..." 73 | 74 | alt text 75 | 76 | 4. After you finish with your `.json` files and steps 2 & 3, launch the `bot.exe` file as administrator and wait for it to load 77 | 78 | - If you have have mutliple `.json` files, you'll be prompted to select which file you wanna use 79 | 80 | alt text 81 | 82 | - Otherwise, if you only have one `.json` file in that folder then this file will automatically be selected 83 | 84 | - After selecting the `.json` file the bot will take control over your PC and start playing MapleStory 85 | 86 | - You can now go to sleep, good night :) 87 | "# MapleAfkBot" 88 | --------------------------------------------------------------------------------