├── .gitignore ├── Bot.py ├── Keys.py ├── README.md ├── Zero.py └── data ├── hp.png ├── mana.png └── osk.png /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /Bot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | """ 3 | This file contains the Bot class, which is initialize and used to complete 4 | sets of actions. 5 | 6 | NoKeyboardException is raised when we cannot find the On-Screen Keyboard. 7 | 8 | Author: Alvin Lin (alvin.lin.dev@gmail.com) 9 | """ 10 | 11 | import math 12 | import pyautogui 13 | import sys 14 | import time 15 | 16 | pyautogui.FAILSAFE = True 17 | 18 | class NoKeyboardException(Exception): 19 | def __init__(self): 20 | pass 21 | def __str__(self): 22 | return "No On-Screen Keyboard found. Try redo-ing your screenshot." 23 | 24 | class Bot(): 25 | def __init__(self): 26 | self.osk = pyautogui.locateOnScreen('data/osk.png') 27 | if self.osk is None: 28 | raise NoKeyboardException() 29 | self.time_created = time.time() 30 | self.hp_pots_used = 0 31 | self.mana_pots_used = 0 32 | 33 | def getDebugText(self): 34 | """ 35 | Returns debug text showing time running as well the amount of 36 | health/mana potions used and other statistical data. 37 | """ 38 | timeDifference = time.time() - self.time_created 39 | hours = math.floor(timeDifference / 3600) 40 | minutes = math.floor((timeDifference % 3600) / 60) 41 | seconds = math.floor(timeDifference % 3600 % 60) 42 | 43 | output = "\n" * 50 44 | output += "Time started: %s\n" % time.ctime(self.time_created) 45 | output += "Time now: %s\n" % time.ctime() 46 | output += "Time elapsed: %02d:%02d:%02d\n" % (hours, minutes, seconds) 47 | output += ("=" * 80) + "\n" 48 | output += "Health potions used: %d\n" % self.hp_pots_used 49 | output += "Health potions per hour: %d\n" % (self.hp_pots_used / ( 50 | timeDifference / 3600)) 51 | output += "Mana potions used: %d\n" % self.mana_pots_used 52 | output += "Mana potions per hour: %d\n" % (self.mana_pots_used / ( 53 | timeDifference / 3600)) 54 | return output 55 | 56 | def _moveTo(self, coord): 57 | """ 58 | Helper method that moves the mouse to a specified coordinate. 59 | """ 60 | pyautogui.moveTo(self.osk[0] + coord[0], self.osk[1] + coord[1]) 61 | 62 | def click(self, key, duration): 63 | """ 64 | Given a key to click and a duration to click it for, this method will 65 | click the key for the given duration. 66 | """ 67 | self._moveTo(key) 68 | pyautogui.mouseDown() 69 | time.sleep(duration) 70 | pyautogui.mouseUp() 71 | time.sleep(0.25) 72 | 73 | def checkHealth(self, pot_key): 74 | """ 75 | Given a key that is bound to a health potion, this method will check 76 | for a depleted health bar and use potions until it can no longer see a 77 | depleted health bar. 78 | """ 79 | while not pyautogui.locateOnScreen('data/hp.png'): 80 | self.click(pot_key, 0.25) 81 | self.hp_pots_used += 1 82 | 83 | def checkMana(self, pot_key): 84 | """ 85 | Given a key that is bound to a mana potion, this method will check for a 86 | depleted mana bar and use potions until it can no longer see a depleted 87 | mana bar. 88 | """ 89 | while not pyautogui.locateOnScreen('data/mana.png'): 90 | self.click(pot_key, 0.25) 91 | self.mana_pots_used += 1 92 | -------------------------------------------------------------------------------- /Keys.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | """ 3 | This is a class that stores the coordinates of the keys on osk.png. 4 | Author: Alvin Lin (alvin.lin.dev@gmail.com) 5 | Contributor: Jonathan Stoebe 6 | """ 7 | 8 | class Keys(): 9 | # Coordinates of the keys on osk.png 10 | key = { 11 | '1' : [190, 55], 12 | '2' : [260, 55], 13 | '3' : [330, 55], 14 | '4' : [400, 55], 15 | '5' : [470, 55], 16 | '6' : [545, 55], 17 | '7' : [625, 55], 18 | '8' : [700, 55], 19 | '9' : [770, 55], 20 | '0' : [845, 55], 21 | 22 | 23 | 24 | 'q' : [150, 85], 25 | 'w' : [225, 85], 26 | 'e' : [300, 85], 27 | 'r' : [360, 85], 28 | 't' : [445, 85], 29 | 'y' : [510, 85], 30 | 'u' : [585, 85], 31 | 'i' : [650, 85], 32 | 'o' : [730, 85], 33 | 'p' : [805, 85], 34 | 35 | 'a' : [190, 120], 36 | 's' : [260, 120], 37 | 'd' : [330, 120], 38 | 'f' : [400, 120], 39 | 'g' : [470, 120], 40 | 'h' : [545, 120], 41 | 'j' : [625, 120], 42 | 'k' : [700, 120], 43 | 'l' : [770, 120], 44 | 45 | 'z' : [225, 150], 46 | 'x' : [300, 150], 47 | 'c' : [360, 150], 48 | 'v' : [445, 150], 49 | 'b' : [510, 150], 50 | 'n' : [585, 150], 51 | 'm' : [650, 150], 52 | 53 | '.' : [805, 150], 54 | ' ' : [480, 185], 55 | 56 | 'BACKSP' : [1080, 55], 57 | 'ENTER' : [1050, 120], 58 | 'LSHIFT' : [90, 150], 59 | 'CTRL' : [115, 185], 60 | 'INS' : [1180, 125], 61 | 'DEL' : [1100, 85], 62 | 'END' : [1185, 85], 63 | 'RIGHT' : [1030, 185], 64 | 'LEFT' : [880, 185], 65 | 'UP' : [950, 150], 66 | 'DOWN' : [950, 185], 67 | 'PGUP' : [1250, 55], 68 | 'PGDN' : [1250, 90], 69 | 'HOME' : [1180, 55], 70 | 'END' : [1180, 90], 71 | 'ALT' : [260, 185], 72 | 'PRTSCN': [1180,150] 73 | } 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python bot for MapleStory 2 | 3 | Uses PyAutoGUI to spoof player actions. Since PyAutoGUI cannot send keyboard 4 | events directly to MapleStory, we use the On-Screen Keyboard built into 5 | Windows and set the mouse to click on the appropriate action keys. 6 | 7 | Bot.py is the main botting class that handles clicks and actions. Pass key 8 | coordinates to its methods (defined in Keys.py) to have it do an action. 9 | Remember to call checkHealth() and checkMana() frequently. It never hurts to 10 | have an extra call. 11 | 12 | Zero.py is an example program that shows the implementation of Bot.py 13 | 14 | # Setup 15 | ## Windows 16 | You will need to install Python 2 on Windows as well as pyautogui. 17 | The easiest way is probably by installing `pip` and using pip to 18 | install pyautogui. 19 | 20 | ## Linux setup for development: 21 | ``` 22 | sudo apt-get install python-pip python-dev python-tk python-xlib 23 | sudo pip install pillow pyautogui 24 | ``` 25 | 26 | # To use: 27 | - Open the On-Screen Keyboard and take a screenshot of it. Crop out the 28 | border so that you only have the keys and icon (copy the existing 29 | `osk.png` as a template). 30 | - Import Bot.py and write your own bot action sequence using it. 31 | - Run MapleStory. 32 | - Run your bot and switch to MapleStory. 33 | 34 | ## Creator 35 | - Alvin Lin (omgimanerd) 36 | ### Contributor 37 | - Jonathan Stoebe (jstoebe) 38 | -------------------------------------------------------------------------------- /Zero.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | """ 3 | Basic botting program for Zero. Works with my keybindings only. 4 | 5 | Premise: 6 | A - Giga Crash 7 | S - Flash Cut 8 | D - Rising Slash 9 | Del - Shadow Rain 10 | End - Rhinne's Protection 11 | 12 | Ctrl - Health pots 13 | 14 | Run while in Beta form standing on a platform with a wall to your right. 15 | This will bump the character against the wall and spam abilties in all 16 | directions. This bot is not smart responsive except for potting when your 17 | HP is low, so make sure you have thousands of health potions. If you get 18 | moved out of position, the bot will continue doing the same thing, so you 19 | need to find a place to stand where mobs do not or can not attack you. 20 | 21 | Author: Alvin Lin (alvin.lin.dev@gmail) 22 | """ 23 | 24 | from Bot import Bot 25 | from Keys import Keys 26 | 27 | import time 28 | 29 | def main(): 30 | bot = Bot() 31 | time.sleep(1) 32 | iterations_run = 0 33 | 34 | while True: 35 | print bot.getDebugText() 36 | bot.checkHealth(Keys.CTRL) 37 | bot.click(Keys.LEFT, 0.1) 38 | bot.click(Keys.D, 0.25) 39 | bot.click(Keys.D, 0.25) 40 | bot.checkHealth(Keys.CTRL) 41 | bot.click(Keys.S, 0.25) 42 | bot.click(Keys.S, 0.25) 43 | bot.checkHealth(Keys.CTRL) 44 | if iterations_run % 2 == 1: 45 | bot.click(Keys.A, 0.25) 46 | bot.click(Keys.A, 0.25) 47 | bot.click(Keys.A, 0.25) 48 | 49 | print bot.getDebugText() 50 | bot.checkHealth(Keys.CTRL) 51 | bot.click(Keys.RIGHT, 0.5) 52 | bot.click(Keys.D, 0.25) 53 | bot.click(Keys.D, 0.25) 54 | bot.checkHealth(Keys.CTRL) 55 | bot.click(Keys.S, 0.25) 56 | bot.click(Keys.S, 0.25) 57 | bot.checkHealth(Keys.CTRL) 58 | if iterations_run % 2 == 0: 59 | bot.click(Keys.A, 0.25) 60 | bot.click(Keys.A, 0.25) 61 | bot.click(Keys.A, 0.25) 62 | 63 | bot.checkHealth(Keys.CTRL) 64 | 65 | # Try to clear mobs every 2 iterations with ultimate ability 66 | if iterations_run % 2 == 0: 67 | bot.click(Keys.DEL, 0.25) 68 | 69 | # Buff self every 5 iterations 70 | if iterations_run % 5 == 0: 71 | bot.click(Keys.END, 0.25) 72 | print bot.getDebugText() 73 | 74 | iterations_run += 1 75 | 76 | if __name__ == "__main__": 77 | main() 78 | -------------------------------------------------------------------------------- /data/hp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jstoebe/python-maplestory-bot/0aeb0dc40bab84ae3819f43e468beded329dd4c2/data/hp.png -------------------------------------------------------------------------------- /data/mana.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jstoebe/python-maplestory-bot/0aeb0dc40bab84ae3819f43e468beded329dd4c2/data/mana.png -------------------------------------------------------------------------------- /data/osk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jstoebe/python-maplestory-bot/0aeb0dc40bab84ae3819f43e468beded329dd4c2/data/osk.png --------------------------------------------------------------------------------