From c6b7568aac502d585cbb0fbc4c103d7371dfd4fd Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Wed, 25 May 2022 17:38:03 -0700 Subject: [PATCH 01/28] organized project structure into ./src --- command_books/blaster.py | 9 +++------ command_books/kanna.py | 8 +++----- gui_components/edit/commands.py | 4 ++-- gui_components/edit/components.py | 5 ++--- gui_components/edit/controls.py | 3 +-- gui_components/edit/main.py | 4 ++-- gui_components/edit/minimap.py | 7 ++----- gui_components/edit/record.py | 3 +-- gui_components/edit/routine.py | 1 - gui_components/edit/status.py | 3 +-- gui_components/menu/main.py | 4 +--- gui_components/settings/main.py | 3 +-- gui_components/view/main.py | 5 ++--- layouts/bd1 | Bin 63 -> 0 bytes layouts/cf1 | Bin 1717 -> 0 bytes layouts/dcsa | Bin 64 -> 0 bytes layouts/dcup2 | Bin 1044 -> 1248 bytes layouts/hft | Bin 1492 -> 0 bytes layouts/mts3 | Bin 2618 -> 0 bytes layouts/srs1 | Bin 64 -> 0 bytes main.py | 10 +++++----- routines/dcup2.csv | 11 ++++++----- config.py => src/common/config.py | 0 settings.py => src/common/settings.py | 0 utils.py => src/common/utils.py | 3 +-- vkeys.py => src/common/vkeys.py | 2 +- detection.py => src/detection/detection.py | 4 ++-- bot.py => src/modules/bot.py | 22 ++++++++++++--------- capture.py => src/modules/capture.py | 3 +-- gui.py => src/modules/gui.py | 5 ++--- listener.py => src/modules/listener.py | 3 +-- notifier.py => src/modules/notifier.py | 7 +++---- components.py => src/routine/components.py | 10 ++++++---- layout.py => src/routine/layout.py | 4 +--- routine.py => src/routine/routine.py | 8 +++----- 35 files changed, 66 insertions(+), 85 deletions(-) delete mode 100644 layouts/bd1 delete mode 100644 layouts/cf1 delete mode 100644 layouts/dcsa delete mode 100644 layouts/hft delete mode 100644 layouts/mts3 delete mode 100644 layouts/srs1 rename config.py => src/common/config.py (100%) rename settings.py => src/common/settings.py (100%) rename utils.py => src/common/utils.py (99%) rename vkeys.py => src/common/vkeys.py (99%) rename detection.py => src/detection/detection.py (98%) rename bot.py => src/modules/bot.py (92%) rename capture.py => src/modules/capture.py (99%) rename gui.py => src/modules/gui.py (94%) rename listener.py => src/modules/listener.py (98%) rename notifier.py => src/modules/notifier.py (98%) rename components.py => src/routine/components.py (97%) rename layout.py => src/routine/layout.py (99%) rename routine.py => src/routine/routine.py (98%) diff --git a/command_books/blaster.py b/command_books/blaster.py index fa7d48ae..482f71a1 100644 --- a/command_books/blaster.py +++ b/command_books/blaster.py @@ -1,12 +1,9 @@ """A collection of all commands that a Blaster can use to interact with the game.""" -import config import time -import math -import settings -import utils -from components import Command -from vkeys import press, key_down, key_up +from src.common import settings +from src.routine.components import Command +from src.common.vkeys import press, key_down, key_up # # class Move(Command): diff --git a/command_books/kanna.py b/command_books/kanna.py index cc0550e3..62e274f5 100644 --- a/command_books/kanna.py +++ b/command_books/kanna.py @@ -1,12 +1,10 @@ """A collection of all commands that a Kanna can use to interact with the game.""" -import config +from src.common import config, settings, utils import time import math -import settings -import utils -from components import Command -from vkeys import press, key_down, key_up +from src.routine.components import Command +from src.common.vkeys import press, key_down, key_up # List of key mappings diff --git a/gui_components/edit/commands.py b/gui_components/edit/commands.py index 1f241bbf..974ee9ba 100644 --- a/gui_components/edit/commands.py +++ b/gui_components/edit/commands.py @@ -1,7 +1,7 @@ import tkinter as tk -import config -from components import Point +from src.common import config +from src.routine.components import Point from gui_components.interfaces import Frame diff --git a/gui_components/edit/components.py b/gui_components/edit/components.py index 5196422b..5371a995 100644 --- a/gui_components/edit/components.py +++ b/gui_components/edit/components.py @@ -1,7 +1,6 @@ import tkinter as tk - -import config -from components import Point +from src.common import config +from src.routine.components import Point from gui_components.interfaces import Frame diff --git a/gui_components/edit/controls.py b/gui_components/edit/controls.py index c4ba47c7..5eff8fec 100644 --- a/gui_components/edit/controls.py +++ b/gui_components/edit/controls.py @@ -1,6 +1,5 @@ import tkinter as tk - -import config +from src.common import config from gui_components.interfaces import Frame diff --git a/gui_components/edit/main.py b/gui_components/edit/main.py index 5036a929..18441722 100644 --- a/gui_components/edit/main.py +++ b/gui_components/edit/main.py @@ -1,9 +1,9 @@ """Allows the user to edit routines while viewing each Point's location on the minimap.""" -import config +from src.common import config import inspect import tkinter as tk -from components import Point, Command +from src.routine.components import Point, Command from gui_components.edit.minimap import Minimap from gui_components.edit.record import Record from gui_components.edit.routine import Routine diff --git a/gui_components/edit/minimap.py b/gui_components/edit/minimap.py index 07522b05..54e7c931 100644 --- a/gui_components/edit/minimap.py +++ b/gui_components/edit/minimap.py @@ -1,11 +1,8 @@ import tkinter as tk - import cv2 from PIL import ImageTk, Image - -import config -import utils -from components import Point +from src.common import config, utils +from src.routine.components import Point from gui_components.interfaces import LabelFrame diff --git a/gui_components/edit/record.py b/gui_components/edit/record.py index a7b81dc9..5ebcd610 100644 --- a/gui_components/edit/record.py +++ b/gui_components/edit/record.py @@ -1,6 +1,5 @@ import tkinter as tk - -from components import Point +from src.routine.components import Point from gui_components.interfaces import LabelFrame diff --git a/gui_components/edit/routine.py b/gui_components/edit/routine.py index fe03f1b1..6bbbfac3 100644 --- a/gui_components/edit/routine.py +++ b/gui_components/edit/routine.py @@ -1,5 +1,4 @@ import tkinter as tk - from gui_components.edit.commands import Commands from gui_components.edit.components import Components from gui_components.edit.controls import Controls diff --git a/gui_components/edit/status.py b/gui_components/edit/status.py index 2871c3fa..7ec2994a 100644 --- a/gui_components/edit/status.py +++ b/gui_components/edit/status.py @@ -1,6 +1,5 @@ import tkinter as tk - -import config +from src.common import config from gui_components.interfaces import LabelFrame diff --git a/gui_components/menu/main.py b/gui_components/menu/main.py index 414a6db2..6a649ed9 100644 --- a/gui_components/menu/main.py +++ b/gui_components/menu/main.py @@ -1,12 +1,10 @@ """A menu for loading routines and command books.""" -import config -import utils +from src.common import config, utils import queue import tkinter as tk from tkinter.filedialog import askopenfilename, asksaveasfilename from tkinter.messagebox import askyesno -from bot import Bot class Menu(tk.Menu): diff --git a/gui_components/settings/main.py b/gui_components/settings/main.py index ba61adf8..328cd035 100644 --- a/gui_components/settings/main.py +++ b/gui_components/settings/main.py @@ -1,7 +1,6 @@ """Displays Auto Maple's current settings and allows the user to edit them.""" -import config -import utils +from src.common import config, utils import tkinter as tk import keyboard as kb from gui_components.interfaces import Tab, Frame, LabelFrame diff --git a/gui_components/view/main.py b/gui_components/view/main.py index dd41e751..28318fcf 100644 --- a/gui_components/view/main.py +++ b/gui_components/view/main.py @@ -1,11 +1,10 @@ """Displays the current minimap as well as various information regarding the current routine.""" -import config -import utils +from src.common import config, utils import cv2 import tkinter as tk from gui_components.interfaces import LabelFrame, Tab -from components import Point +from src.routine.components import Point from PIL import Image, ImageTk diff --git a/layouts/bd1 b/layouts/bd1 deleted file mode 100644 index 8540c47963e058727a68fd577dbe193ae0fe3fa4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63 zcmZo*PR>cJ%r7nB@_|r=44RFFjJ1VK8WAiE3=DaRxv7QB5zIhlQi@?A3s|ryKfk1q J)vq*34**4B5ZwR( diff --git a/layouts/cf1 b/layouts/cf1 deleted file mode 100644 index b95f8ecb3a31ab4863df1627a0f73438a4cade9a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1717 zcmai!IZRYh6ov;umO)$*P+SMm0Tl-~Tp2|Xm+_&}JZ+Tync$3v%&0_8qM@UsqqEXz z#8^m7#KNeFf`wp25~C(WiE#-Qb~MI&|F_Sg)w}QJ`_FdIIoHygI~uzpv8Xqsf5=mI zozj?Q`PB@M#}jV6&`RlQx;QqsRZ<2nJ0p=O%{GNfq@~qMnL?JulVngO z@Pny_EL?Pvw=Vd2U?%_R(5RXvh}gxm9j$Fq%GIQD4pW|A6Pj;Tr+=6AT+#$R>g$(3 znoi7Rng`-z@3~Ly!?zNN`AiEyycrtp3l-l>Bo;C)0`UZ<%M*!wro|xcBGfS#p{Ut< z;GO5&wI~%RYL57CiChlrsT3-z*Sye?A|=+O6(GYUOiN+;MYl{~#BJGtikX%HdO27+ zopZHDLgRmK2Jh7W&~g>6K+y^n4MyX?x|8KhE1-X;mp-YJl}xJuy_b*C7mA1e=VUdL z5Be#*W}i!sTuYeNfS8mGkonU^xY9_Hk)BB@(^{DLF4`e>qa?M7LbzPVn{c z`PVo#n3V%p##9b&Og2&8gyfz{559h*(bh9<0P#w8(ZEb1v5~0)#B-Tkb!{TCi75c$ zksZC;OC{505V!4yw}@0Fa#YKCL}FW*w!+{zVhXr|5(WWnW7-bL@$|{PI{ORKDyAKf zey}IQm}e9i&`zdZfIee%dt?w61Y$SS9uSkF_}#sYE+SRlMlfQQieO|fQ#FiywP(rg zCdjl8g#JRPhDDgw*w0iG4~-Zzk$l?hs#~!fU^)mRj?IK>w`!^SWiXHq~oww6V> sp9>c2nNEP8up`lDz-Nx3V}U_(lIavAj&*Y1T>VZLvgBf)#+oYr0cJ%r7nB@_|r=44RFFjJ1VK8WAiE3=DaRxv7QBU}j2kabh70m|2vcUsA~G ISDK^;0A0rsf&c&j diff --git a/layouts/dcup2 b/layouts/dcup2 index 96246c1f1ce032bdf8d9bc12a39f1f4fd198a184..a1fe8080323fe60f1ea97d2148707866335bb7da 100644 GIT binary patch literal 1248 zcmZo*PA)D=)+@>{Ey>JF)yqk&1hTk%AXFiPW@8~^Z6T9J1PcQLLtbKTY9Vt3E0CFz zTv}jM$O0BF%Fiz;WW{ETUw%p|S0NkF5cb+a4vh##pw5ayPIvoPh8qMu;`zV=m4#gH z_9v6P=ghyGAHfb(QCbk6lbTji$ejVw$x~a%tC0cJ^QXVe~Jst~9x6a=fdKg0Lv>ive8Duikag~2MWW!`o(W75P_AyQi?3RZFcZocE= zS813k#A*x0!7A2>&MLdu+Xzx|2IwiE>I`nb2o8wXiZatPN(v?XA~-?8m|va;@vNj@ z1Q$#IqC^Vped*dl8L*)zZg4EoZ)ZiZ)-OZCFGJEVL&~o-sWb_RlOX}tEL&SB2iAQ1 zLdCC{Nj^9=!wiAyldmmQ0PB0$+tB6oqksr~aCbnBP^>Lf0vqvS(sT9i(HDp?0_Uv;ymV4T|#eXDB+s4zR8*v;nJtmK-1zyBS4*PFM?e N0K#nK98sF22LL*axp4ph literal 1044 zcmZo*PR>cJ%r7nB@_|r=44RFFjJ1VK8WAiE3=DaRxv7QB5v)LFN^)s|Q6URhxF|or zq>vS+)h|CKm8*~qsFA(4kV7Ma5vaPNkkj4%_33v@9xmtx3se?zx!Z4$g7b7)brxg@0AuA${9e_Cu^?&)yHH&RPfan@`F`8&8Y-Q zV5$(PEffT+c*L=`Uw_vWOcg@4g~DJJcUi)YPrvJhsY0Z-P!z1P;$hfx91Z)vBD}pS7XDe(Ll_u!{03A_Y5dZ)H diff --git a/layouts/hft b/layouts/hft deleted file mode 100644 index d25c477a7daec73b258cf15646f44c843aec9ac6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1492 zcmaize`t(x9LH~N>~`ZeGxKX^hI40(VP-pXHk(uCk@(|Dip|DD=Wd^M#||HnBqYfn z{#eq|5-mxRBuSD+(yYd&ZMVZ*NAfG7mGAfSeeQ10bw~HdbI-Te`~Cg=ct1z)Bsrrw5Yhu*vQA!0510a@RK)VGNU{AQ&ui z5@VYo)nV^+T{yF$-$n;MFgoo1(DB?m8$)smBfO2!Z86q$oQ zB}yx4l57xyrro;~511r5mA%)y_q&8ex+ELJ2Lj2Eymg9+oW~<%l5@AQyzz3kQR}Qi z6A-cp>bZ1(-;-OVv5=&sOA47ro@71|A)9nB-fgcqSyIDwz4`p*6f0XXMRgg(PePbX zeAn=|+tsa4V|jw6AWS9bjpfI~vs5mTLskWbS0)vX;5j%8}hS>x2m zEQHwveaNU=-}&WQEEJuNcB*p_%%mF>0phv@Q{{WsisvF&Nc_@sZ_nXhy(6>#~B2yc}3W7pyflVyNu~3|Rgug=4mm{ns zz5nW;A?N8Tu8&zYadw1N#0}&=G@(XM4|$rlK8r#9K8p32P85aUiTEJ{TQf#8ESFHU8eZ@UQSM16UcI diff --git a/layouts/mts3 b/layouts/mts3 deleted file mode 100644 index 8dc44c8335cd7d10be26f4046241a1238ce94f59..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2618 zcmai$S#uOs7>0wO36mfMa7$1?6bDpXa8PjxI$%UYGhrRKU_uf)PLknGW`wcotJ0hJ z2mAx@2SQn1Myn{W)R9fYmXuV&l7dQw8~g*DeouFwKABFDT+B?@^S?qY zNoMCM-BB!TZaSTsT2xB6@j(fR=BDwXkz>Qj-fXoZiiZ#Mc6Ap}>w3yM!J?$AG{0r8 z{G?>ApZUrInnBZ{||D@Ygs+%f_Cj?KD_&dhKv0}~+|CFGC(rc=1 z%DvLOQLuu_JT+zM=)79+EQv`k z`p~ZyVb?}}jo>-*x94(vUa*$Lt+-{ix<$tq1WEEUs<2$S(aM0tI>CApcj6rhy(oBz z(6rZ}T-ma*3b9-CvS0&scRAXv57q_xIX{`tD}q<)`-|Q)p6{sNGd=&W30^1hv))7= zp$kmAwN}P@2sR4dAb--Uui<~o(c**5mNJu+U=ww>y?t0pTRIYN3f>|SBv_H_+k(v` z&YC$6U|r2Sf_F*$5fepa$3X81-X~Nxa~xlCP(sCqZW3&v#eZg8E^+BH{<-pj;6oCZ zyt68EHNLORCoR}YbjwawFc9l9b_g7bXM9D)itiL;NKBih3RgVZn&^(! znY9XbQ95M?RnP1_e~ESr_K>(`!k^;_Rp%3X1^Y-$m}Ai<_6xEk{5#0&vrT*^_?*P= zW)Lp;M~Jt<*v2meUlNKO|4}IBXf=QBjuo=lSHKAGyXmaEAA3>Ya5ep2rOSl@g{IRfn4@C+MXja=nELdiDwWNsO71`ina-6%0GMyx=go$fgLLqOqgz z2oMZV6uG4TWbPw@x&KZPEJ^SgdC?dY6lfB;71Bzvss_rKvjz4)TQ diff --git a/layouts/srs1 b/layouts/srs1 deleted file mode 100644 index 5aa43a88937aac39d08f9b1b25dea9580cea268f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 64 zcmZo*PR>cJ%r7nB@_|r=44RFFjJ1VK8WAiE3=DaRxv7QBU}kYqv0)(#m|2vcUsA~G ISDK^;09?)yZ~y=R diff --git a/main.py b/main.py index 0b41ffb5..a881093a 100644 --- a/main.py +++ b/main.py @@ -1,11 +1,11 @@ """The central program that ties all the modules together.""" import time -from bot import Bot -from capture import Capture -from notifier import Notifier -from listener import Listener -from gui import GUI +from src.modules.bot import Bot +from src.modules.capture import Capture +from src.modules.notifier import Notifier +from src.modules.listener import Listener +from src.modules.gui import GUI bot = Bot() diff --git a/routines/dcup2.csv b/routines/dcup2.csv index 58b076cf..780c2fb4 100644 --- a/routines/dcup2.csv +++ b/routines/dcup2.csv @@ -1,3 +1,4 @@ +$, target=record_layout, value=True $, target=move_tolerance, value=0.075 @, label=main @@ -8,7 +9,7 @@ $, target=move_tolerance, value=0.075 Shikigami, direction=right, attacks=2, repetitions=1 >, label=loot, frequency=4, skip=False *, x=0.873, y=0.200, frequency=1, skip=False, adjust=False - Fall, distance=0.05 + Fall, distance=0.02 @, label=afterboss *, x=0.055, y=0.125, frequency=1, skip=False, adjust=False @@ -37,7 +38,7 @@ $, target=move_tolerance, value=0.075 Walk, direction=left, duration=0.2 Shikigami, direction=left, attacks=2, repetitions=1 *, x=0.225, y=0.200, frequency=1, skip=False, adjust=False - Fall, distance=0.05 + Fall, distance=0.02 Walk, direction=left, duration=0.2 Tengu *, x=0.660, y=0.083, frequency=1, skip=False, adjust=False @@ -59,7 +60,7 @@ $, target=move_tolerance, value=0.075 Shikigami, direction=right, attacks=2, repetitions=1 >, label=boss2, frequency=5, skip=True *, x=0.873, y=0.200, frequency=1, skip=False, adjust=False - Fall, distance=0.05 + Fall, distance=0.02 Walk, direction=right, duration=0.2 @, label=afterboss2 @@ -76,8 +77,8 @@ $, target=move_tolerance, value=0.075 Teleport, direction=left, jump=False Yaksha, direction=left *, x=0.750, y=0.200, frequency=3, skip=True, adjust=False - Fall, distance=0.05 + Fall, distance=0.02 >, label=afterboss, frequency=3, skip=True *, x=0.750, y=0.200, frequency=1, skip=False, adjust=False - Fall, distance=0.05 + Fall, distance=0.02 >, label=afterboss2, frequency=1, skip=False diff --git a/config.py b/src/common/config.py similarity index 100% rename from config.py rename to src/common/config.py diff --git a/settings.py b/src/common/settings.py similarity index 100% rename from settings.py rename to src/common/settings.py diff --git a/utils.py b/src/common/utils.py similarity index 99% rename from utils.py rename to src/common/utils.py index 527bd753..71d9957a 100644 --- a/utils.py +++ b/src/common/utils.py @@ -1,12 +1,11 @@ """A collection of functions and classes used across multiple modules.""" -import config -import settings import math import queue import cv2 import threading import numpy as np +from src.common import config, settings from random import random diff --git a/vkeys.py b/src/common/vkeys.py similarity index 99% rename from vkeys.py rename to src/common/vkeys.py index b6fa51c7..33fccc2d 100644 --- a/vkeys.py +++ b/src/common/vkeys.py @@ -2,9 +2,9 @@ import ctypes import time -import utils import win32con import win32api +from src.common import utils from ctypes import wintypes from random import random diff --git a/detection.py b/src/detection/detection.py similarity index 98% rename from detection.py rename to src/detection/detection.py index 96a11f82..623b35d5 100644 --- a/detection.py +++ b/src/detection/detection.py @@ -1,9 +1,9 @@ """A module for classifying directional arrows using TensorFlow.""" -import utils import cv2 import tensorflow as tf import numpy as np +from src.common import utils ######################### @@ -178,7 +178,7 @@ def merge_detection(model, image): # Script for testing the detection module by itself if __name__ == '__main__': - import config + from src.common import config, utils import mss config.enabled = True monitor = {'top': 0, 'left': 0, 'width': 1366, 'height': 768} diff --git a/bot.py b/src/modules/bot.py similarity index 92% rename from bot.py rename to src/modules/bot.py index 042674c2..b63935a1 100644 --- a/bot.py +++ b/src/modules/bot.py @@ -1,19 +1,19 @@ """An interpreter that reads and executes user-created routines.""" -import config -import detection + import threading import time import cv2 -import utils import inspect -import components import numpy as np from PIL import ImageGrab from os.path import splitext, basename -from routine import Routine -from components import Point -from vkeys import press, click +from src.common import config, utils +from src.detection import detection +from src.routine import components +from src.routine.routine import Routine +from src.routine.components import Point +from src.common.vkeys import press, click # The rune's buff icon @@ -117,12 +117,16 @@ def _solve_rune(self, model): time.sleep(0.3) frame = np.array(ImageGrab.grab(config.capture.window)) frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) - rune_buff = utils.multi_match(frame[:frame.shape[0]//8, :], + rune_buff = utils.multi_match(frame[:frame.shape[0] // 8, :], RUNE_BUFF_TEMPLATE, threshold=0.9) if rune_buff: rune_buff_pos = min(rune_buff, key=lambda p: p[0]) - click(rune_buff_pos, button='right') + click( + (rune_buff_pos[0] + config.capture.window[0], + rune_buff_pos[1] + config.capture.window[0]), + button='right' + ) break elif len(solution) == 4: inferences.append(solution) diff --git a/capture.py b/src/modules/capture.py similarity index 99% rename from capture.py rename to src/modules/capture.py index 913f3185..3587ddbd 100644 --- a/capture.py +++ b/src/modules/capture.py @@ -1,12 +1,11 @@ """A module for tracking useful in-game information.""" -import config -import utils import time import cv2 import threading import ctypes import numpy as np +from src.common import config, utils from ctypes import wintypes from PIL import ImageGrab user32 = ctypes.windll.user32 diff --git a/gui.py b/src/modules/gui.py similarity index 94% rename from gui.py rename to src/modules/gui.py index 78ff30a4..f42a5615 100644 --- a/gui.py +++ b/src/modules/gui.py @@ -1,9 +1,8 @@ """User friendly GUI to interact with Auto Maple.""" -import config import tkinter as tk from tkinter import ttk -import settings +from src.common import config, settings from gui_components import Menu, View, Edit, Settings @@ -76,7 +75,7 @@ def start(self): self._save_layout() self.root.mainloop() - def _save_layout(self): + def _save_layout(self): # TODO: move to bot main loop, file I/O is costly, blocks gui main loop """Periodically saves the current Layout object.""" if config.layout is not None and settings.record_layout: diff --git a/listener.py b/src/modules/listener.py similarity index 98% rename from listener.py rename to src/modules/listener.py index af51b2b1..f27820ac 100644 --- a/listener.py +++ b/src/modules/listener.py @@ -1,12 +1,11 @@ """A keyboard listener to track user inputs.""" -import config import time -import utils import threading import winsound import pickle import keyboard as kb +from src.common import config, utils from os.path import isfile from datetime import datetime diff --git a/notifier.py b/src/modules/notifier.py similarity index 98% rename from notifier.py rename to src/modules/notifier.py index 89e3389f..dd7e7d67 100644 --- a/notifier.py +++ b/src/modules/notifier.py @@ -1,14 +1,13 @@ """A module for detecting and notifying the user of dangerous in-game events.""" -import config -import utils +from src.common import config, utils import time import cv2 import pygame import threading import numpy as np import keyboard as kb -from components import Point +from src.routine.components import Point # A rune's symbol on the minimap @@ -57,7 +56,7 @@ def _main(self): # Check for unexpected black screen gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) - if np.count_nonzero(gray < 15) / height / width > 0.75: + if np.count_nonzero(gray < 15) / height / width > 0.9: self._alert() # Check for elite warning diff --git a/components.py b/src/routine/components.py similarity index 97% rename from components.py rename to src/routine/components.py index 23df68ff..f55c9485 100644 --- a/components.py +++ b/src/routine/components.py @@ -1,11 +1,9 @@ """A collection of classes used to execute a Routine.""" -import config -import settings -import utils import math import time -from vkeys import key_down, key_up, press +from src.common import config, settings, utils +from src.common.vkeys import key_down, key_up, press ################################# @@ -263,6 +261,8 @@ def main(self): key = 'right' self._new_direction(key) step(key, point) + if settings.record_layout: + config.layout.add(*config.player_pos) counter -= 1 if i < len(path) - 1: time.sleep(0.15) @@ -275,6 +275,8 @@ def main(self): key = 'down' self._new_direction(key) step(key, point) + if settings.record_layout: + config.layout.add(*config.player_pos) counter -= 1 if i < len(path) - 1: time.sleep(0.05) diff --git a/layout.py b/src/routine/layout.py similarity index 99% rename from layout.py rename to src/routine/layout.py index 89359227..5a83d3f7 100644 --- a/layout.py +++ b/src/routine/layout.py @@ -1,11 +1,9 @@ """A module for saving map layouts and determining shortest paths.""" -import config -import settings -import utils import cv2 import math import pickle +from src.common import config, settings, utils from os.path import join, isfile, splitext, basename from heapq import heappush, heappop diff --git a/routine.py b/src/routine/routine.py similarity index 98% rename from routine.py rename to src/routine/routine.py index 7413d088..37ef5ff7 100644 --- a/routine.py +++ b/src/routine/routine.py @@ -1,12 +1,10 @@ """A collection of classes used in the 'machine code' generated by Auto Maple's compiler for each routine.""" -import config -import utils +from src.common import config, settings, utils import csv -import settings from os.path import splitext, basename -from components import Point, Label, Jump, Setting, Command, SYMBOLS -from layout import Layout +from src.routine.components import Point, Label, Jump, Setting, Command, SYMBOLS +from src.routine.layout import Layout def update(func): From a67d546207124fd48ae1751f99dc502217a8d65f Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Wed, 25 May 2022 19:40:01 -0700 Subject: [PATCH 02/28] added alerts for runes, fixed clicking after rune solved for windowed mode --- assets/{ => alerts}/alert.mp3 | Bin assets/{ => alerts}/ding.mp3 | Bin assets/alerts/rune_alert.mp3 | Bin 0 -> 28365 bytes layouts/dcup2 | Bin 1248 -> 1383 bytes src/modules/bot.py | 8 +++----- src/modules/capture.py | 2 ++ src/modules/notifier.py | 12 ++++++++++-- 7 files changed, 15 insertions(+), 7 deletions(-) rename assets/{ => alerts}/alert.mp3 (100%) rename assets/{ => alerts}/ding.mp3 (100%) create mode 100644 assets/alerts/rune_alert.mp3 diff --git a/assets/alert.mp3 b/assets/alerts/alert.mp3 similarity index 100% rename from assets/alert.mp3 rename to assets/alerts/alert.mp3 diff --git a/assets/ding.mp3 b/assets/alerts/ding.mp3 similarity index 100% rename from assets/ding.mp3 rename to assets/alerts/ding.mp3 diff --git a/assets/alerts/rune_alert.mp3 b/assets/alerts/rune_alert.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..a775d099289c94e3c10aad367ddf1c8023e1d9f0 GIT binary patch literal 28365 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 delta 145 zcmaFP^?-AOGc%80hC~LNW@DjlZK2-e8fMeUeoR~}`n81ylix6#uo%`B8ckMVQDiZ$ zEi{?z$zsl8T3cu~xdkXjH_!ooll@sG0Gfm`-2eap diff --git a/src/modules/bot.py b/src/modules/bot.py index b63935a1..37407de3 100644 --- a/src/modules/bot.py +++ b/src/modules/bot.py @@ -122,11 +122,9 @@ def _solve_rune(self, model): threshold=0.9) if rune_buff: rune_buff_pos = min(rune_buff, key=lambda p: p[0]) - click( - (rune_buff_pos[0] + config.capture.window[0], - rune_buff_pos[1] + config.capture.window[0]), - button='right' - ) + target = tuple(round(rune_buff_pos[i] + config.capture.window[i]) + for i in range(2)) + click(target, button='right') break elif len(solution) == 4: inferences.append(solution) diff --git a/src/modules/capture.py b/src/modules/capture.py index 3587ddbd..c330b493 100644 --- a/src/modules/capture.py +++ b/src/modules/capture.py @@ -51,6 +51,7 @@ def __init__(self): self.minimap_ratio = 1 self.minimap_sample = None self.window = (0, 0, 1366, 768) + self.scale = 1.0 self.ready = False self.calibrated = False @@ -75,6 +76,7 @@ def _main(self): rect = tuple(max(0, x) for x in rect) # Preliminary window to template match minimap + self.scale = ctypes.windll.shcore.GetScaleFactorForDevice(0) / 100 self.window = ( rect[0], rect[1], diff --git a/src/modules/notifier.py b/src/modules/notifier.py index dd7e7d67..9730ad58 100644 --- a/src/modules/notifier.py +++ b/src/modules/notifier.py @@ -85,6 +85,7 @@ def _main(self): index = np.argmin(distances) config.bot.rune_closest_pos = config.routine[index].location config.bot.rune_active = True + self._rune_alert() time.sleep(0.05) def _alert(self): @@ -95,7 +96,7 @@ def _alert(self): config.enabled = False config.listener.enabled = False - self.mixer.load('./assets/alert.mp3') + self.mixer.load('./assets/alerts/alert.mp3') self.mixer.set_volume(0.75) self.mixer.play(-1) while not kb.is_pressed(config.listener.key_binds['Start/stop']): @@ -107,10 +108,17 @@ def _alert(self): def _ding(self): """A quick notification for when another player enters the map.""" - self.mixer.load('./assets/ding.mp3') + self.mixer.load('./assets/alerts/ding.mp3') self.mixer.set_volume(0.50) self.mixer.play() + def _rune_alert(self): + """Notification for when a rune appears.""" + + self.mixer.load('./assets/alerts/rune_alert.mp3') + self.mixer.set_volume(0.75) + self.mixer.play() + ################################# # Helper Functions # From 9d172fe8e061c6571b277d760efe58f17d7a9c4e Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Wed, 25 May 2022 22:40:16 -0700 Subject: [PATCH 03/28] added keybind for pet food --- .gitignore | 2 +- gui_components/settings/keybindings.py | 129 ++++++++++++++++ gui_components/settings/main.py | 129 +--------------- gui_components/view/__init__.py | 0 gui_components/view/details.py | 60 ++++++++ gui_components/view/main.py | 198 +------------------------ gui_components/view/minimap.py | 83 +++++++++++ gui_components/view/routine.py | 30 ++++ gui_components/view/status.py | 29 ++++ layouts/dcup2 | Bin 1383 -> 1068 bytes src/modules/bot.py | 1 - src/modules/listener.py | 10 +- 12 files changed, 346 insertions(+), 325 deletions(-) create mode 100644 gui_components/settings/keybindings.py create mode 100644 gui_components/view/__init__.py create mode 100644 gui_components/view/details.py create mode 100644 gui_components/view/minimap.py create mode 100644 gui_components/view/routine.py create mode 100644 gui_components/view/status.py diff --git a/.gitignore b/.gitignore index c46954d9..885f5509 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ __pycache__/ assets/models/ .idea/ -.keybinds +.settings/ diff --git a/gui_components/settings/keybindings.py b/gui_components/settings/keybindings.py new file mode 100644 index 00000000..901fe3d9 --- /dev/null +++ b/gui_components/settings/keybindings.py @@ -0,0 +1,129 @@ +import tkinter as tk +import keyboard as kb +from gui_components.interfaces import LabelFrame, Frame +from src.common import config, utils + + +class KeyBindings(LabelFrame): + def __init__(self, parent, **kwargs): + super().__init__(parent, 'Key Bindings', **kwargs) + + self.columnconfigure(0, minsize=300) + + self.displays = {} # Holds each action's display variable + self.forward = {} # Maps actions to keys + self.backward = {} # Maps keys to actions + self.prev_a = '' + self.prev_k = '' + + self.contents = None + self.create_edit_ui() + + def create_edit_ui(self): + self.displays = {} + self.forward = {} + self.backward = {} + self.prev_a = '' + self.prev_k = '' + + self.contents = Frame(self) + self.contents.grid(row=0, column=0, sticky=tk.NSEW, padx=5, pady=5) + + if config.listener is not None: # For when running GUI only + for action, key in config.listener.key_binds.items(): + self.forward[action] = key + self.backward[key] = action + self.create_entry(action, key) + self.focus() + else: + self.create_disabled_entry() + + reset = tk.Button(self.contents, text='Reset', command=self.refresh_edit_ui, takefocus=False) + reset.pack(side=tk.LEFT, pady=5) + + save = tk.Button(self.contents, text='Save', command=self.save, takefocus=False) + save.pack(side=tk.RIGHT, pady=5) + + def refresh_edit_ui(self): + self.contents.destroy() + self.create_edit_ui() + + @utils.run_if_disabled('\n[!] Cannot save key bindings while Auto Maple is enabled.') + def save(self): + utils.print_separator() + print('[~] Saving key bindings...') + + failures = 0 + for action, key in self.forward.items(): + if key != '': + config.listener.key_binds[action] = key + else: + print(f" ! Action '{action}' was not bound to a key.") + failures += 1 + + config.listener.save_keybindings() + if failures == 0: + print('[~] Successfully saved all key bindings.') + else: + print(f'[~] Successfully saved all except for {failures} key bindings.') + self.create_edit_ui() + + def create_entry(self, action, key): + """ + Creates an input row for a single key bind. KEY is the name of its action + while VALUE is its currently assigned key. + """ + + display_var = tk.StringVar(value=key) + self.displays[action] = display_var + + row = Frame(self.contents, highlightthickness=0) + row.pack(expand=True, fill='x') + + label = tk.Entry(row) + label.grid(row=0, column=0, sticky=tk.EW) + label.insert(0, action) + label.config(state=tk.DISABLED) + + def on_key_press(_): + k = kb.read_key() + if action != self.prev_a: + self.prev_k = '' + self.prev_a = action + if k != self.prev_k: + prev_key = self.forward[action] + self.backward.pop(prev_key, None) + if k in self.backward: + prev_action = self.backward[k] + self.forward[prev_action] = '' + self.displays[prev_action].set('') + display_var.set(k) + self.forward[action] = k + self.backward[k] = action + self.prev_k = k + + def validate(d): + """Blocks user insertion, but allows StringVar set().""" + + if d == '-1': + return True + return False + + reg = (self.register(validate), '%d') + entry = tk.Entry(row, textvariable=display_var, + validate='key', validatecommand=reg, + takefocus=False) + entry.bind('', on_key_press) + entry.grid(row=0, column=1, sticky=tk.EW) + + def create_disabled_entry(self): + row = Frame(self.contents, highlightthickness=0) + row.pack(expand=True, fill='x') + + label = tk.Entry(row) + label.grid(row=0, column=0, sticky=tk.EW) + label.config(state=tk.DISABLED) + + entry = tk.Entry(row) + entry.grid(row=0, column=1, sticky=tk.EW) + entry.config(state=tk.DISABLED) diff --git a/gui_components/settings/main.py b/gui_components/settings/main.py index 328cd035..630ee1a9 100644 --- a/gui_components/settings/main.py +++ b/gui_components/settings/main.py @@ -1,9 +1,7 @@ """Displays Auto Maple's current settings and allows the user to edit them.""" - -from src.common import config, utils +from gui_components.settings.keybindings import KeyBindings import tkinter as tk -import keyboard as kb -from gui_components.interfaces import Tab, Frame, LabelFrame +from gui_components.interfaces import Tab class Settings(Tab): @@ -17,126 +15,3 @@ def __init__(self, parent, **kwargs): self.keybindings.grid(row=0, column=1, sticky=tk.NSEW) -class KeyBindings(LabelFrame): - def __init__(self, parent, **kwargs): - super().__init__(parent, 'Key Bindings', **kwargs) - - self.columnconfigure(0, minsize=300) - - self.displays = {} # Holds each action's display variable - self.forward = {} # Maps actions to keys - self.backward = {} # Maps keys to actions - self.prev_a = '' - self.prev_k = '' - - self.contents = None - self.create_edit_ui() - - def create_edit_ui(self): - self.displays = {} - self.forward = {} - self.backward = {} - self.prev_a = '' - self.prev_k = '' - - self.contents = Frame(self) - self.contents.grid(row=0, column=0, sticky=tk.NSEW, padx=5, pady=5) - - if config.listener is not None: # For when running GUI only - for action, key in config.listener.key_binds.items(): - self.forward[action] = key - self.backward[key] = action - self.create_entry(action, key) - self.focus() - else: - self.create_disabled_entry() - - reset = tk.Button(self.contents, text='Reset', command=self.refresh_edit_ui, takefocus=False) - reset.pack(side=tk.LEFT, pady=5) - - save = tk.Button(self.contents, text='Save', command=self.save, takefocus=False) - save.pack(side=tk.RIGHT, pady=5) - - def refresh_edit_ui(self): - self.contents.destroy() - self.create_edit_ui() - - @utils.run_if_disabled('\n[!] Cannot save key bindings while Auto Maple is enabled.') - def save(self): - utils.print_separator() - print('[~] Saving key bindings...') - - failures = 0 - for action, key in self.forward.items(): - if key != '': - config.listener.key_binds[action] = key - else: - print(f" ! Action '{action}' was not bound to a key.") - failures += 1 - - config.listener.save_keybindings() - if failures == 0: - print('[~] Successfully saved all key bindings.') - else: - print(f'[~] Successfully saved all except for {failures} key bindings.') - self.create_edit_ui() - - def create_entry(self, action, key): - """ - Creates an input row for a single key bind. KEY is the name of its action - while VALUE is its currently assigned key. - """ - - display_var = tk.StringVar(value=key) - self.displays[action] = display_var - - row = Frame(self.contents, highlightthickness=0) - row.pack(expand=True, fill='x') - - label = tk.Entry(row) - label.grid(row=0, column=0, sticky=tk.EW) - label.insert(0, action) - label.config(state=tk.DISABLED) - - def on_key_press(_): - k = kb.read_key() - if action != self.prev_a: - self.prev_k = '' - self.prev_a = action - if k != self.prev_k: - prev_key = self.forward[action] - self.backward.pop(prev_key, None) - if k in self.backward: - prev_action = self.backward[k] - self.forward[prev_action] = '' - self.displays[prev_action].set('') - display_var.set(k) - self.forward[action] = k - self.backward[k] = action - self.prev_k = k - - def validate(d): - """Blocks user insertion, but allows StringVar set().""" - - if d == '-1': - return True - return False - - reg = (self.register(validate), '%d') - entry = tk.Entry(row, textvariable=display_var, - validate='key', validatecommand=reg, - takefocus=False) - entry.bind('', on_key_press) - entry.grid(row=0, column=1, sticky=tk.EW) - - def create_disabled_entry(self): - row = Frame(self.contents, highlightthickness=0) - row.pack(expand=True, fill='x') - - label = tk.Entry(row) - label.grid(row=0, column=0, sticky=tk.EW) - label.config(state=tk.DISABLED) - - entry = tk.Entry(row) - entry.grid(row=0, column=1, sticky=tk.EW) - entry.config(state=tk.DISABLED) diff --git a/gui_components/view/__init__.py b/gui_components/view/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/gui_components/view/details.py b/gui_components/view/details.py new file mode 100644 index 00000000..5125e58d --- /dev/null +++ b/gui_components/view/details.py @@ -0,0 +1,60 @@ +import tkinter as tk +from gui_components.interfaces import LabelFrame +from src.common import config + + +class Details(LabelFrame): + def __init__(self, parent, **kwargs): + super().__init__(parent, 'Details', **kwargs) + self.name_var = tk.StringVar() + + self.name = tk.Entry(self, textvariable=self.name_var, justify=tk.CENTER, state=tk.DISABLED) + self.name.pack(pady=(5, 2)) + + self.scroll = tk.Scrollbar(self) + self.scroll.pack(side=tk.RIGHT, fill=tk.Y, pady=5) + + self.text = tk.Text(self, width=1, height=10, + yscrollcommand=self.scroll.set, + state=tk.DISABLED, wrap=tk.WORD) + self.text.pack(side=tk.LEFT, expand=True, fill='both', padx=(5, 0), pady=(0, 5)) + + self.scroll.config(command=self.text.yview) + + def show_details(self, e): + """Callback for updating the Details section everytime Listbox selection changes.""" + + selections = e.widget.curselection() + if len(selections) > 0: + index = int(selections[0]) + self.display_info(index) + + def update_details(self): + """Updates Details to show info about the current selection.""" + + selects = self.parent.routine.listbox.curselection() + if len(selects) > 0: + self.display_info(int(selects[0])) + else: + self.clear_info() + + def display_info(self, index): + """Updates the Details section to show info about the Component at position INDEX.""" + + self.text.config(state=tk.NORMAL) + + info = config.routine[index].info() + self.name_var.set(info['name']) + arr = [] + for key, value in info['vars'].items(): + arr.append(f'{key}: {value}') + self.text.delete(1.0, 'end') + self.text.insert(1.0, '\n'.join(arr)) + + self.text.config(state=tk.DISABLED) + + def clear_info(self): + self.name_var.set('') + self.text.config(state=tk.NORMAL) + self.text.delete(1.0, 'end') + self.text.config(state=tk.DISABLED) diff --git a/gui_components/view/main.py b/gui_components/view/main.py index 28318fcf..7ba8bc8a 100644 --- a/gui_components/view/main.py +++ b/gui_components/view/main.py @@ -1,11 +1,11 @@ """Displays the current minimap as well as various information regarding the current routine.""" -from src.common import config, utils -import cv2 import tkinter as tk -from gui_components.interfaces import LabelFrame, Tab -from src.routine.components import Point -from PIL import Image, ImageTk +from gui_components.view.details import Details +from gui_components.view.minimap import Minimap +from gui_components.view.routine import Routine +from gui_components.view.status import Status +from gui_components.interfaces import Tab class View(Tab): @@ -26,191 +26,3 @@ def __init__(self, parent, **kwargs): self.routine = Routine(self) self.routine.grid(row=0, column=1, rowspan=3, sticky=tk.NSEW, padx=10, pady=10) - - -class Minimap(LabelFrame): - def __init__(self, parent, **kwargs): - super().__init__(parent, 'Minimap', **kwargs) - - self.WIDTH = 400 - self.HEIGHT = 300 - self.canvas = tk.Canvas(self, bg='black', - width=self.WIDTH, height=self.HEIGHT, - borderwidth=0, highlightthickness=0) - self.canvas.pack(expand=True, fill='both', padx=5, pady=5) - self.container = None - - def display_minimap(self): - """Updates the Main page with the current minimap.""" - - minimap = config.capture.minimap - if minimap: - rune_active = minimap['rune_active'] - rune_pos = minimap['rune_pos'] - path = minimap['path'] - player_pos = minimap['player_pos'] - - img = cv2.cvtColor(minimap['minimap'], cv2.COLOR_BGR2RGB) - height, width, _ = img.shape - - # Resize minimap to fit the Canvas - ratio = min(self.WIDTH / width, self.HEIGHT / height) - new_width = int(width * ratio) - new_height = int(height * ratio) - if new_height * new_width > 0: - img = cv2.resize(img, (new_width, new_height), interpolation=cv2.INTER_AREA) - - # Mark the position of the active rune - if rune_active: - cv2.circle(img, - utils.convert_to_absolute(rune_pos, img), - 3, - (128, 0, 128), - -1) - - # Draw the current path that the program is taking - if config.enabled and len(path) > 1: - for i in range(len(path) - 1): - start = utils.convert_to_absolute(path[i], img) - end = utils.convert_to_absolute(path[i + 1], img) - cv2.line(img, start, end, (0, 255, 255), 1) - - # Draw each Point in the routine as a circle - for p in config.routine.sequence: - if isinstance(p, Point): - utils.draw_location(img, - p.location, - (0, 255, 0) if config.enabled else (255, 0, 0)) - - # Display the current Layout - if config.layout: - config.layout.draw(img) - - # Draw the player's position on top of everything - cv2.circle(img, - utils.convert_to_absolute(player_pos, img), - 3, - (0, 0, 255), - -1) - - # Display the minimap in the Canvas - img = ImageTk.PhotoImage(Image.fromarray(img)) - if self.container is None: - self.container = self.canvas.create_image(self.WIDTH // 2, - self.HEIGHT // 2, - image=img, anchor=tk.CENTER) - else: - self.canvas.itemconfig(self.container, image=img) - self._img = img # Prevent garbage collection - self.after(50, self.display_minimap) - - -class Status(LabelFrame): - def __init__(self, parent, **kwargs): - super().__init__(parent, 'Status', **kwargs) - - self.grid_columnconfigure(0, weight=1) - self.grid_columnconfigure(3, weight=1) - - self.curr_cb = tk.StringVar() - self.curr_routine = tk.StringVar() - - self.cb_label = tk.Label(self, text='Command Book:') - self.cb_label.grid(row=0, column=1, padx=5, pady=(5, 0), sticky=tk.E) - self.cb_entry = tk.Entry(self, textvariable=self.curr_cb, state=tk.DISABLED) - self.cb_entry.grid(row=0, column=2, padx=(0, 5), pady=(5, 0), sticky=tk.EW) - - self.r_label = tk.Label(self, text='Routine:') - self.r_label.grid(row=1, column=1, padx=5, pady=(0, 5), sticky=tk.E) - self.r_entry = tk.Entry(self, textvariable=self.curr_routine, state=tk.DISABLED) - self.r_entry.grid(row=1, column=2, padx=(0, 5), pady=(0, 5), sticky=tk.EW) - - def set_cb(self, string): - self.curr_cb.set(string) - - def set_routine(self, string): - self.curr_routine.set(string) - - -class Details(LabelFrame): - def __init__(self, parent, **kwargs): - super().__init__(parent, 'Details', **kwargs) - self.name_var = tk.StringVar() - - self.name = tk.Entry(self, textvariable=self.name_var, justify=tk.CENTER, state=tk.DISABLED) - self.name.pack(pady=(5, 2)) - - self.scroll = tk.Scrollbar(self) - self.scroll.pack(side=tk.RIGHT, fill=tk.Y, pady=5) - - self.text = tk.Text(self, width=1, height=10, - yscrollcommand=self.scroll.set, - state=tk.DISABLED, wrap=tk.WORD) - self.text.pack(side=tk.LEFT, expand=True, fill='both', padx=(5, 0), pady=(0, 5)) - - self.scroll.config(command=self.text.yview) - - def show_details(self, e): - """Callback for updating the Details section everytime Listbox selection changes.""" - - selections = e.widget.curselection() - if len(selections) > 0: - index = int(selections[0]) - self.display_info(index) - - def update_details(self): - """Updates Details to show info about the current selection.""" - - selects = self.parent.routine.listbox.curselection() - if len(selects) > 0: - self.display_info(int(selects[0])) - else: - self.clear_info() - - def display_info(self, index): - """Updates the Details section to show info about the Component at position INDEX.""" - - self.text.config(state=tk.NORMAL) - - info = config.routine[index].info() - self.name_var.set(info['name']) - arr = [] - for key, value in info['vars'].items(): - arr.append(f'{key}: {value}') - self.text.delete(1.0, 'end') - self.text.insert(1.0, '\n'.join(arr)) - - self.text.config(state=tk.DISABLED) - - def clear_info(self): - self.name_var.set('') - self.text.config(state=tk.NORMAL) - self.text.delete(1.0, 'end') - self.text.config(state=tk.DISABLED) - - -class Routine(LabelFrame): - def __init__(self, parent, **kwargs): - super().__init__(parent, 'Routine', **kwargs) - - self.scroll = tk.Scrollbar(self) - self.scroll.pack(side=tk.RIGHT, fill='both', pady=5) - - self.listbox = tk.Listbox(self, width=25, - listvariable=config.gui.routine_var, - exportselection=False, - activestyle='none', - yscrollcommand=self.scroll.set) - self.listbox.bind('', lambda e: 'break') - self.listbox.bind('', lambda e: 'break') - self.listbox.bind('', lambda e: 'break') - self.listbox.bind('', lambda e: 'break') - self.listbox.bind('<>', parent.details.show_details) - self.listbox.pack(side=tk.LEFT, expand=True, fill='both', padx=(5, 0), pady=5) - - self.scroll.config(command=self.listbox.yview) - - def select(self, i): - self.listbox.selection_clear(0, 'end') - self.listbox.selection_set(i) - self.listbox.see(i) diff --git a/gui_components/view/minimap.py b/gui_components/view/minimap.py new file mode 100644 index 00000000..9639712b --- /dev/null +++ b/gui_components/view/minimap.py @@ -0,0 +1,83 @@ +import cv2 +import tkinter as tk +from PIL import ImageTk, Image +from gui_components.interfaces import LabelFrame +from src.common import config, utils +from src.routine.components import Point + + +class Minimap(LabelFrame): + def __init__(self, parent, **kwargs): + super().__init__(parent, 'Minimap', **kwargs) + + self.WIDTH = 400 + self.HEIGHT = 300 + self.canvas = tk.Canvas(self, bg='black', + width=self.WIDTH, height=self.HEIGHT, + borderwidth=0, highlightthickness=0) + self.canvas.pack(expand=True, fill='both', padx=5, pady=5) + self.container = None + + def display_minimap(self): + """Updates the Main page with the current minimap.""" + + minimap = config.capture.minimap + if minimap: + rune_active = minimap['rune_active'] + rune_pos = minimap['rune_pos'] + path = minimap['path'] + player_pos = minimap['player_pos'] + + img = cv2.cvtColor(minimap['minimap'], cv2.COLOR_BGR2RGB) + height, width, _ = img.shape + + # Resize minimap to fit the Canvas + ratio = min(self.WIDTH / width, self.HEIGHT / height) + new_width = int(width * ratio) + new_height = int(height * ratio) + if new_height * new_width > 0: + img = cv2.resize(img, (new_width, new_height), interpolation=cv2.INTER_AREA) + + # Mark the position of the active rune + if rune_active: + cv2.circle(img, + utils.convert_to_absolute(rune_pos, img), + 3, + (128, 0, 128), + -1) + + # Draw the current path that the program is taking + if config.enabled and len(path) > 1: + for i in range(len(path) - 1): + start = utils.convert_to_absolute(path[i], img) + end = utils.convert_to_absolute(path[i + 1], img) + cv2.line(img, start, end, (0, 255, 255), 1) + + # Draw each Point in the routine as a circle + for p in config.routine.sequence: + if isinstance(p, Point): + utils.draw_location(img, + p.location, + (0, 255, 0) if config.enabled else (255, 0, 0)) + + # Display the current Layout + if config.layout: + config.layout.draw(img) + + # Draw the player's position on top of everything + cv2.circle(img, + utils.convert_to_absolute(player_pos, img), + 3, + (0, 0, 255), + -1) + + # Display the minimap in the Canvas + img = ImageTk.PhotoImage(Image.fromarray(img)) + if self.container is None: + self.container = self.canvas.create_image(self.WIDTH // 2, + self.HEIGHT // 2, + image=img, anchor=tk.CENTER) + else: + self.canvas.itemconfig(self.container, image=img) + self._img = img # Prevent garbage collection + self.after(50, self.display_minimap) diff --git a/gui_components/view/routine.py b/gui_components/view/routine.py new file mode 100644 index 00000000..8b71247e --- /dev/null +++ b/gui_components/view/routine.py @@ -0,0 +1,30 @@ +import tkinter as tk +from gui_components.interfaces import LabelFrame +from src.common import config + + +class Routine(LabelFrame): + def __init__(self, parent, **kwargs): + super().__init__(parent, 'Routine', **kwargs) + + self.scroll = tk.Scrollbar(self) + self.scroll.pack(side=tk.RIGHT, fill='both', pady=5) + + self.listbox = tk.Listbox(self, width=25, + listvariable=config.gui.routine_var, + exportselection=False, + activestyle='none', + yscrollcommand=self.scroll.set) + self.listbox.bind('', lambda e: 'break') + self.listbox.bind('', lambda e: 'break') + self.listbox.bind('', lambda e: 'break') + self.listbox.bind('', lambda e: 'break') + self.listbox.bind('<>', parent.details.show_details) + self.listbox.pack(side=tk.LEFT, expand=True, fill='both', padx=(5, 0), pady=5) + + self.scroll.config(command=self.listbox.yview) + + def select(self, i): + self.listbox.selection_clear(0, 'end') + self.listbox.selection_set(i) + self.listbox.see(i) diff --git a/gui_components/view/status.py b/gui_components/view/status.py new file mode 100644 index 00000000..ceab4f51 --- /dev/null +++ b/gui_components/view/status.py @@ -0,0 +1,29 @@ +import tkinter as tk +from gui_components.interfaces import LabelFrame + + +class Status(LabelFrame): + def __init__(self, parent, **kwargs): + super().__init__(parent, 'Status', **kwargs) + + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(3, weight=1) + + self.curr_cb = tk.StringVar() + self.curr_routine = tk.StringVar() + + self.cb_label = tk.Label(self, text='Command Book:') + self.cb_label.grid(row=0, column=1, padx=5, pady=(5, 0), sticky=tk.E) + self.cb_entry = tk.Entry(self, textvariable=self.curr_cb, state=tk.DISABLED) + self.cb_entry.grid(row=0, column=2, padx=(0, 5), pady=(5, 0), sticky=tk.EW) + + self.r_label = tk.Label(self, text='Routine:') + self.r_label.grid(row=1, column=1, padx=5, pady=(0, 5), sticky=tk.E) + self.r_entry = tk.Entry(self, textvariable=self.curr_routine, state=tk.DISABLED) + self.r_entry.grid(row=1, column=2, padx=(0, 5), pady=(0, 5), sticky=tk.EW) + + def set_cb(self, string): + self.curr_cb.set(string) + + def set_routine(self, string): + self.curr_routine.set(string) diff --git a/layouts/dcup2 b/layouts/dcup2 index f223e7ef311bd23a7aa761b7546610b3d8579b93..77aa4f4993e08f50ed97e4b2275f95f46ced3f8d 100644 GIT binary patch literal 1068 zcmZo*PA)D=)+@>{Ey>JF)yqk&1hTk%AXFiPW@8~^Z6T9J1PcQLLtbKTY9Vt3E0CFz zTv}jM$O0BF%Fiz;WW{ETUw%p|S0NkF5cb+a4vh##pw5ayPIvnk982`uS<}G+m4#gH z_9v6P=ghyGAHfb(QCbk6lbTji$ejVw$x~a%tC0cJ^K>tJ|H^5q83@%G5EXp2h5TR@ zj~202D=&4yR3T7XCPYx0K5Jn-H3NcN#wondi+UxG{ zxw*Z~L=JIxEyeQTdDuGoz{AzS$x}^h1#f}@Gm}i5k zP_8Xh0js$4x-#Ey|z#Ttm5RGzNrGnH$f`)2kUqi zPyPe7MYFb03#eu!^O#$}aXcbfKv5LyiIDV1ooEI52c;3-!PTT&Vap zGs$}{$bdbfAj29nxRDJ2MLPCKz$z*MHeJ8A&;V@uo2cENId^OYnT{INhP8!8U==SW xJy-u8eE~%U(0;Hn#t3e9r9xY@c4UK&mYt&Lf{?$( zaAJi`51~>>7(%#_*Ggs`L=>ARv+hN2EsLUsde9e}pIS;1y4sxE{ev3o;RfFo%dSIP|qIWlT-XMTjP1--+k@!&rm@yQ4&#J}-wdfVNp$M%deWjs<5j6@8yu?aG;#17ibP=!cCSV@F3g^cLh zoxZK6c}gKxA*2%_M;}lV83-mKu6c)WI>Yyzl>Ny>SWSHQtE-_$lWzDW`ti#7dQO+R z&O*p0o6fc5BC{VU8xZMhv#B6s4Z>P727e?L+~k{?F}(}EM!+bnL&za-H2L|CFYQ+X zJqpi7SWnQqp0j!8ha-WIcQ`!FuqUZ`2pdR!f2;9Q@5h}?y?^}M+tz`0>C!00=Ob(+ zXu`3F-OoTsl`pj|$8SO?AoCL&rrL2olL{~+Y$ihaCNZK@8zYr)$6G)lLXjMEYVWb~ Z+&BhxOCK=(vwVV71$a)2E~eXJ`U9<== Date: Wed, 25 May 2022 23:14:44 -0700 Subject: [PATCH 04/28] added Configurable class for storing keybinds for Listener and Bot --- gui_components/settings/keybindings.py | 6 ++-- gui_components/settings/pets.py | 9 ++++++ src/common/settings.py | 2 ++ src/modules/bot.py | 14 +++++++--- src/modules/interfaces.py | 31 +++++++++++++++++++++ src/modules/listener.py | 38 +++++++------------------- 6 files changed, 65 insertions(+), 35 deletions(-) create mode 100644 gui_components/settings/pets.py create mode 100644 src/modules/interfaces.py diff --git a/gui_components/settings/keybindings.py b/gui_components/settings/keybindings.py index 901fe3d9..6ebc84c3 100644 --- a/gui_components/settings/keybindings.py +++ b/gui_components/settings/keybindings.py @@ -30,7 +30,7 @@ def create_edit_ui(self): self.contents.grid(row=0, column=0, sticky=tk.NSEW, padx=5, pady=5) if config.listener is not None: # For when running GUI only - for action, key in config.listener.key_binds.items(): + for action, key in config.listener.config.items(): self.forward[action] = key self.backward[key] = action self.create_entry(action, key) @@ -56,12 +56,12 @@ def save(self): failures = 0 for action, key in self.forward.items(): if key != '': - config.listener.key_binds[action] = key + config.listener.config[action] = key else: print(f" ! Action '{action}' was not bound to a key.") failures += 1 - config.listener.save_keybindings() + config.listener.save_config() if failures == 0: print('[~] Successfully saved all key bindings.') else: diff --git a/gui_components/settings/pets.py b/gui_components/settings/pets.py new file mode 100644 index 00000000..70a3eb12 --- /dev/null +++ b/gui_components/settings/pets.py @@ -0,0 +1,9 @@ +from gui_components.interfaces import LabelFrame + + +class Pets(LabelFrame): + def __init__(self, parent, **kwargs): + super().__init__(parent, 'Pets', **kwargs) + + + diff --git a/src/common/settings.py b/src/common/settings.py index 7d496306..614363b2 100644 --- a/src/common/settings.py +++ b/src/common/settings.py @@ -95,3 +95,5 @@ def reset(): # The amount of time (in seconds) to wait between each call to the 'buff' command buff_cooldown = 180 + +reset() diff --git a/src/modules/bot.py b/src/modules/bot.py index c63210fd..0ef689a2 100644 --- a/src/modules/bot.py +++ b/src/modules/bot.py @@ -13,18 +13,26 @@ from src.routine.routine import Routine from src.routine.components import Point from src.common.vkeys import press, click +from src.modules.interfaces import Configurable # The rune's buff icon RUNE_BUFF_TEMPLATE = cv2.imread('assets/rune_buff_template.jpg', 0) -class Bot: +class Bot(Configurable): """A class that interprets and executes user-defined routines.""" + TARGET = 'controls' + DEFAULT_CONFIG = { + 'Interact': 'y', + 'Feed pet': '9' + } + def __init__(self): """Loads a user-defined routine on start up and initializes this Bot's main thread.""" + super().__init__() config.bot = self self.rune_active = False @@ -62,8 +70,6 @@ def _main(self): model = detection.load_model() print('\n[~] Initialized detection algorithm.') - # mss.windows.CAPTUREBLT = 0 - # with mss.mss() as sct: self.ready = True config.listener.enabled = True while True: @@ -98,7 +104,7 @@ def _solve_rune(self, model): adjust = self.command_book['adjust'] adjust(*self.rune_pos).execute() time.sleep(0.2) - press('y', 1, down_time=0.2) # Press 'y' to interact with rune in-game + press(self.config['Interact'], 1, down_time=0.2) # Inherited from Configurable print('\nSolving rune:') inferences = [] for _ in range(15): diff --git a/src/modules/interfaces.py b/src/modules/interfaces.py new file mode 100644 index 00000000..e2399938 --- /dev/null +++ b/src/modules/interfaces.py @@ -0,0 +1,31 @@ +import os +import pickle + +SETTINGS_DIR = '.settings' + + +class Configurable: + TARGET = 'default_configurable' + DEFAULT_CONFIG = { + 'Default configuration': 'None' + } + + def __init__(self): + self.config = self.DEFAULT_CONFIG.copy() + self.load_config() + + def load_config(self): + path = os.path.join(SETTINGS_DIR, self.TARGET) + if os.path.isfile(path): + with open(path, 'rb') as file: + self.config = pickle.load(file) + else: + self.save_config() + + def save_config(self): + path = os.path.join(SETTINGS_DIR, self.TARGET) + directory = os.path.dirname(path) + if not os.path.exists(directory): + os.makedirs(directory) + with open(path, 'wb') as file: + pickle.dump(self.config, file) diff --git a/src/modules/listener.py b/src/modules/listener.py index 584d61de..083b9c97 100644 --- a/src/modules/listener.py +++ b/src/modules/listener.py @@ -1,33 +1,29 @@ """A keyboard listener to track user inputs.""" -import os.path + import time import threading import winsound -import pickle import keyboard as kb +from src.modules.interfaces import Configurable from src.common import config, utils -from os.path import isfile from datetime import datetime -class Listener: - TARGET = '.settings/keybinds' - DEFAULT_KEYBINDS = { +class Listener(Configurable): + TARGET = 'keybinds' + DEFAULT_CONFIG = { 'Start/stop': 'insert', 'Reload routine': 'f6', - 'Record position': 'f7', - 'Feed pet': '9' + 'Record position': 'f7' } def __init__(self): """Initializes this Listener object's main thread.""" + super().__init__() config.listener = self self.enabled = False - self.key_binds = Listener.DEFAULT_KEYBINDS.copy() - self.load_keybindings() - self.ready = False self.thread = threading.Thread(target=self._main) self.thread.daemon = True @@ -50,11 +46,11 @@ def _main(self): self.ready = True while True: if self.enabled: - if kb.is_pressed(self.key_binds['Start/stop']): + if kb.is_pressed(self.config['Start/stop']): Listener.toggle_enabled() - elif kb.is_pressed(self.key_binds['Reload routine']): + elif kb.is_pressed(self.config['Reload routine']): Listener.reload_routine() - elif kb.is_pressed(self.key_binds['Record position']): + elif kb.is_pressed(self.config['Record position']): Listener.record_position() time.sleep(0.01) @@ -101,17 +97,3 @@ def record_position(): config.gui.edit.record.add_entry(now, pos) print(f'\n[~] Recorded position ({pos[0]}, {pos[1]}) at {now}.') time.sleep(0.6) - - def load_keybindings(self): - if isfile(Listener.TARGET): - with open(Listener.TARGET, 'rb') as file: - self.key_binds = pickle.load(file) - else: - self.save_keybindings() - - def save_keybindings(self): - directory = os.path.dirname(Listener.TARGET) - if not os.path.exists(directory): - os.makedirs(directory) - with open(Listener.TARGET, 'wb') as file: - pickle.dump(self.key_binds, file) From 591f69479307b43e11138d1f1fbe053bfd9a10a0 Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Wed, 25 May 2022 23:38:21 -0700 Subject: [PATCH 05/28] added keybindings for bot as well --- gui_components/settings/keybindings.py | 30 ++++++++++++++------------ gui_components/settings/main.py | 13 ++++++----- gui_components/settings/pets.py | 9 -------- gui_components/view/__init__.py | 0 main.py | 2 +- src/modules/bot.py | 8 +++---- src/modules/capture.py | 2 +- src/modules/listener.py | 4 ++-- src/modules/notifier.py | 2 +- 9 files changed, 33 insertions(+), 37 deletions(-) delete mode 100644 gui_components/settings/pets.py delete mode 100644 gui_components/view/__init__.py diff --git a/gui_components/settings/keybindings.py b/gui_components/settings/keybindings.py index 6ebc84c3..b1f9dc6b 100644 --- a/gui_components/settings/keybindings.py +++ b/gui_components/settings/keybindings.py @@ -1,12 +1,15 @@ import tkinter as tk import keyboard as kb from gui_components.interfaces import LabelFrame, Frame -from src.common import config, utils +from src.common import utils +from src.modules.interfaces import Configurable class KeyBindings(LabelFrame): - def __init__(self, parent, **kwargs): - super().__init__(parent, 'Key Bindings', **kwargs) + def __init__(self, parent, label, target, **kwargs): + super().__init__(parent, label, **kwargs) + assert isinstance(target, Configurable) + self.target = target self.columnconfigure(0, minsize=300) @@ -29,8 +32,8 @@ def create_edit_ui(self): self.contents = Frame(self) self.contents.grid(row=0, column=0, sticky=tk.NSEW, padx=5, pady=5) - if config.listener is not None: # For when running GUI only - for action, key in config.listener.config.items(): + if self.target is not None: # For when running GUI only + for action, key in self.target.config.items(): self.forward[action] = key self.backward[key] = action self.create_entry(action, key) @@ -48,30 +51,29 @@ def refresh_edit_ui(self): self.contents.destroy() self.create_edit_ui() - @utils.run_if_disabled('\n[!] Cannot save key bindings while Auto Maple is enabled.') + @utils.run_if_disabled('\n[!] Cannot save key bindings while Auto Maple is enabled') def save(self): utils.print_separator() - print('[~] Saving key bindings...') + print(f"[~] Saving key bindings to '{self.target.TARGET}':") failures = 0 for action, key in self.forward.items(): if key != '': - config.listener.config[action] = key + self.target.config[action] = key else: - print(f" ! Action '{action}' was not bound to a key.") + print(f" ! Action '{action}' was not bound to a key") failures += 1 - config.listener.save_config() + self.target.save_config() if failures == 0: - print('[~] Successfully saved all key bindings.') + print(' ~ Successfully saved all key bindings') else: - print(f'[~] Successfully saved all except for {failures} key bindings.') + print(f' ~ Successfully saved all except for {failures} key bindings') self.create_edit_ui() def create_entry(self, action, key): """ - Creates an input row for a single key bind. KEY is the name of its action - while VALUE is its currently assigned key. + Creates an input row for a single key bind. ACTION is assigned to KEY. """ display_var = tk.StringVar(value=key) diff --git a/gui_components/settings/main.py b/gui_components/settings/main.py index 630ee1a9..8b1aa736 100644 --- a/gui_components/settings/main.py +++ b/gui_components/settings/main.py @@ -1,7 +1,9 @@ """Displays Auto Maple's current settings and allows the user to edit them.""" -from gui_components.settings.keybindings import KeyBindings + import tkinter as tk +from gui_components.settings.keybindings import KeyBindings from gui_components.interfaces import Tab +from src.common import config class Settings(Tab): @@ -9,9 +11,10 @@ def __init__(self, parent, **kwargs): super().__init__(parent, 'Settings', **kwargs) self.columnconfigure(0, weight=1) - self.columnconfigure(2, weight=1) - - self.keybindings = KeyBindings(self) - self.keybindings.grid(row=0, column=1, sticky=tk.NSEW) + self.columnconfigure(3, weight=1) + self.controls = KeyBindings(self, 'Auto Maple Controls', config.listener) + self.controls.grid(row=0, column=1, sticky=tk.N, padx=10, pady=10) + self.key_bindings = KeyBindings(self, 'In-game Keybindings', config.bot) + self.key_bindings.grid(row=0, column=2, sticky=tk.N, padx=10, pady=10) diff --git a/gui_components/settings/pets.py b/gui_components/settings/pets.py deleted file mode 100644 index 70a3eb12..00000000 --- a/gui_components/settings/pets.py +++ /dev/null @@ -1,9 +0,0 @@ -from gui_components.interfaces import LabelFrame - - -class Pets(LabelFrame): - def __init__(self, parent, **kwargs): - super().__init__(parent, 'Pets', **kwargs) - - - diff --git a/gui_components/view/__init__.py b/gui_components/view/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/main.py b/main.py index a881093a..9f2a430b 100644 --- a/main.py +++ b/main.py @@ -29,7 +29,7 @@ while not listener.ready: time.sleep(0.01) -print('\n[~] Successfully initialized Auto Maple.') +print('\n[~] Successfully initialized Auto Maple') gui = GUI() gui.start() diff --git a/src/modules/bot.py b/src/modules/bot.py index 0ef689a2..adfcb255 100644 --- a/src/modules/bot.py +++ b/src/modules/bot.py @@ -23,7 +23,7 @@ class Bot(Configurable): """A class that interprets and executes user-defined routines.""" - TARGET = 'controls' + TARGET = 'keybindings' DEFAULT_CONFIG = { 'Interact': 'y', 'Feed pet': '9' @@ -57,7 +57,7 @@ def start(self): :return: None """ - print('\n[~] Started main bot loop.') + print('\n[~] Started main bot loop') self.thread.start() def _main(self): @@ -66,9 +66,9 @@ def _main(self): :return: None """ - print('\n[~] Initializing detection algorithm...\n') + print('\n[~] Initializing detection algorithm:\n') model = detection.load_model() - print('\n[~] Initialized detection algorithm.') + print('\n[~] Successfully initialized detection algorithm') self.ready = True config.listener.enabled = True diff --git a/src/modules/capture.py b/src/modules/capture.py index c330b493..71f0fa73 100644 --- a/src/modules/capture.py +++ b/src/modules/capture.py @@ -61,7 +61,7 @@ def __init__(self): def start(self): """Starts this Capture's thread.""" - print('\n[~] Started video capture.') + print('\n[~] Started video capture') self.thread.start() def _main(self): diff --git a/src/modules/listener.py b/src/modules/listener.py index 083b9c97..71312f3c 100644 --- a/src/modules/listener.py +++ b/src/modules/listener.py @@ -10,7 +10,7 @@ class Listener(Configurable): - TARGET = 'keybinds' + TARGET = 'controls' DEFAULT_CONFIG = { 'Start/stop': 'insert', 'Reload routine': 'f6', @@ -34,7 +34,7 @@ def start(self): :return: None """ - print('\n[~] Started keyboard listener.') + print('\n[~] Started keyboard listener') self.thread.start() def _main(self): diff --git a/src/modules/notifier.py b/src/modules/notifier.py index 9730ad58..11c2be75 100644 --- a/src/modules/notifier.py +++ b/src/modules/notifier.py @@ -42,7 +42,7 @@ def __init__(self): def start(self): """Starts this Notifier's thread.""" - print('\n[~] Started notifier.') + print('\n[~] Started notifier') self.thread.start() def _main(self): From a25576aded59ab0725708db7022a38f7530a9a10 Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Wed, 25 May 2022 23:40:48 -0700 Subject: [PATCH 06/28] removed all periods: : --- gui_components/menu/main.py | 8 ++++---- src/modules/bot.py | 2 +- src/modules/listener.py | 2 +- src/routine/components.py | 4 ++-- src/routine/routine.py | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/gui_components/menu/main.py b/gui_components/menu/main.py index 6a649ed9..302e4e00 100644 --- a/gui_components/menu/main.py +++ b/gui_components/menu/main.py @@ -24,7 +24,7 @@ def __init__(self, parent, **kwargs): self.add_cascade(label='File', menu=self.file) @staticmethod - @utils.run_if_disabled('\n[!] Cannot create a new routine while Auto Maple is enabled.') + @utils.run_if_disabled('\n[!] Cannot create a new routine while Auto Maple is enabled') def _new_routine(): if config.routine.dirty: if not askyesno(title='New Routine', @@ -36,7 +36,7 @@ def _new_routine(): config.routine.clear() @staticmethod - @utils.run_if_disabled('\n[!] Cannot save routines while Auto Maple is enabled.') + @utils.run_if_disabled('\n[!] Cannot save routines while Auto Maple is enabled') def _save_routine(): file_path = asksaveasfilename(initialdir='./routines/', title='Save routine', @@ -46,7 +46,7 @@ def _save_routine(): config.routine.save(file_path) @staticmethod - @utils.run_if_disabled('\n[!] Cannot load routines while Auto Maple is enabled.') + @utils.run_if_disabled('\n[!] Cannot load routines while Auto Maple is enabled') def _load_routine(): if config.routine.dirty: if not askyesno(title='Load Routine', @@ -62,7 +62,7 @@ def _load_routine(): config.routine.load(file_path) @staticmethod - @utils.run_if_disabled('\n[!] Cannot load command books while Auto Maple is enabled.') + @utils.run_if_disabled('\n[!] Cannot load command books while Auto Maple is enabled') def _load_commands(): if config.routine.dirty: if not askyesno(title='Load Command Book', diff --git a/src/modules/bot.py b/src/modules/bot.py index adfcb255..7b4db46f 100644 --- a/src/modules/bot.py +++ b/src/modules/bot.py @@ -114,7 +114,7 @@ def _solve_rune(self, model): if solution: print(', '.join(solution)) if solution in inferences: - print('Solution found, entering result.') + print('Solution found, entering result') for arrow in solution: press(arrow, 1, down_time=0.1) time.sleep(1) diff --git a/src/modules/listener.py b/src/modules/listener.py index 71312f3c..63b519ee 100644 --- a/src/modules/listener.py +++ b/src/modules/listener.py @@ -95,5 +95,5 @@ def record_position(): pos = tuple('{:.3f}'.format(round(i, 3)) for i in config.player_pos) now = datetime.now().strftime('%I:%M:%S %p') config.gui.edit.record.add_entry(now, pos) - print(f'\n[~] Recorded position ({pos[0]}, {pos[1]}) at {now}.') + print(f'\n[~] Recorded position ({pos[0]}, {pos[1]}) at {now}') time.sleep(0.6) diff --git a/src/routine/components.py b/src/routine/components.py index f55c9485..4b4d3456 100644 --- a/src/routine/components.py +++ b/src/routine/components.py @@ -15,9 +15,9 @@ class Component: def __init__(self, *args, **kwargs): if len(args) > 1: - raise TypeError('Component superclass __init__ only accepts 1 (optional) argument: LOCALS.') + raise TypeError('Component superclass __init__ only accepts 1 (optional) argument: LOCALS') if len(kwargs) != 0: - raise TypeError('Component superclass __init__ does not accept any keyword arguments.') + raise TypeError('Component superclass __init__ does not accept any keyword arguments') if len(args) == 0: self.kwargs = {} elif type(args[0]) != dict: diff --git a/src/routine/routine.py b/src/routine/routine.py index 37ef5ff7..9d330f81 100644 --- a/src/routine/routine.py +++ b/src/routine/routine.py @@ -203,9 +203,9 @@ def load(self, file=None): if not file: if self.path: file = self.path - print(' * File path not provided, using previously loaded routine.') + print(' * File path not provided, using previously loaded routine') else: - print('[!] File path not provided, no routine was previously loaded either.') + print('[!] File path not provided, no routine was previously loaded either') return False ext = splitext(file)[1] From aebe577625284898e17f3d8abc42d05eecbc90cd Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Thu, 26 May 2022 00:46:31 -0700 Subject: [PATCH 07/28] moved Configurable to common, added pet settings and auto-feed --- gui_components/settings/keybindings.py | 2 +- gui_components/settings/main.py | 17 +++++--- gui_components/settings/pets.py | 57 ++++++++++++++++++++++++++ src/{modules => common}/interfaces.py | 3 +- src/modules/bot.py | 14 +++++-- src/modules/listener.py | 5 +-- 6 files changed, 85 insertions(+), 13 deletions(-) create mode 100644 gui_components/settings/pets.py rename src/{modules => common}/interfaces.py (92%) diff --git a/gui_components/settings/keybindings.py b/gui_components/settings/keybindings.py index b1f9dc6b..9b5ba60a 100644 --- a/gui_components/settings/keybindings.py +++ b/gui_components/settings/keybindings.py @@ -2,7 +2,7 @@ import keyboard as kb from gui_components.interfaces import LabelFrame, Frame from src.common import utils -from src.modules.interfaces import Configurable +from src.common.interfaces import Configurable class KeyBindings(LabelFrame): diff --git a/gui_components/settings/main.py b/gui_components/settings/main.py index 8b1aa736..a586e1d2 100644 --- a/gui_components/settings/main.py +++ b/gui_components/settings/main.py @@ -2,7 +2,8 @@ import tkinter as tk from gui_components.settings.keybindings import KeyBindings -from gui_components.interfaces import Tab +from gui_components.settings.pets import Pets +from gui_components.interfaces import Tab, Frame from src.common import config @@ -13,8 +14,14 @@ def __init__(self, parent, **kwargs): self.columnconfigure(0, weight=1) self.columnconfigure(3, weight=1) - self.controls = KeyBindings(self, 'Auto Maple Controls', config.listener) - self.controls.grid(row=0, column=1, sticky=tk.N, padx=10, pady=10) + column1 = Frame(self) + column1.grid(row=0, column=1, sticky=tk.N, padx=10, pady=10) + self.controls = KeyBindings(column1, 'Auto Maple Controls', config.listener) + self.controls.pack(side=tk.TOP, fill='x', expand=True) - self.key_bindings = KeyBindings(self, 'In-game Keybindings', config.bot) - self.key_bindings.grid(row=0, column=2, sticky=tk.N, padx=10, pady=10) + column2 = Frame(self) + column2.grid(row=0, column=2, sticky=tk.N, padx=10, pady=10) + self.key_bindings = KeyBindings(column2, 'In-game Keybindings', config.bot) + self.key_bindings.pack(side=tk.TOP, fill='x', expand=True) + self.pets = Pets(column2) + self.pets.pack(side=tk.TOP, fill='x', expand=True, pady=(10, 0)) diff --git a/gui_components/settings/pets.py b/gui_components/settings/pets.py new file mode 100644 index 00000000..3091c045 --- /dev/null +++ b/gui_components/settings/pets.py @@ -0,0 +1,57 @@ +import tkinter as tk +from gui_components.interfaces import LabelFrame, Frame +from src.common.interfaces import Configurable + + +class Pets(LabelFrame): + def __init__(self, parent, **kwargs): + super().__init__(parent, 'Pets', **kwargs) + + self.pet_settings = PetSettings('pets') + self.auto_feed = tk.BooleanVar(value=self.pet_settings.get('Auto-feed')) + self.num_pets = tk.IntVar(value=self.pet_settings.get('Num pets')) + + feed_row = Frame(self) + feed_row.pack(side=tk.TOP, fill='x', expand=True, pady=5, padx=5) + check = tk.Checkbutton( + feed_row, + variable=self.auto_feed, + text='Auto-feed', + command=self._on_change + ) + check.pack() + + num_row = Frame(self) + num_row.pack(side=tk.TOP, fill='x', expand=True, pady=(0, 5), padx=5) + label = tk.Label(num_row, text='Number of pets to feed:') + label.pack(side=tk.LEFT, padx=(0, 15)) + radio_group = Frame(num_row) + radio_group.pack(side=tk.LEFT) + for i in range(1, 4): + radio = tk.Radiobutton( + radio_group, + text=str(i), + variable=self.num_pets, + value=i, + command=self._on_change + ) + radio.pack(side=tk.LEFT, padx=(0, 10)) + + def _on_change(self): + self.pet_settings.set('Auto-feed', self.auto_feed.get()) + self.pet_settings.set('Num pets', self.num_pets.get()) + self.pet_settings.save_config() + + +class PetSettings(Configurable): + DEFAULT_CONFIG = { + 'Auto-feed': False, + 'Num pets': 1 + } + + def get(self, key): + return self.config[key] + + def set(self, key, value): + assert key in self.config + self.config[key] = value diff --git a/src/modules/interfaces.py b/src/common/interfaces.py similarity index 92% rename from src/modules/interfaces.py rename to src/common/interfaces.py index e2399938..ba833aa9 100644 --- a/src/modules/interfaces.py +++ b/src/common/interfaces.py @@ -10,7 +10,8 @@ class Configurable: 'Default configuration': 'None' } - def __init__(self): + def __init__(self, target): + self.TARGET = target self.config = self.DEFAULT_CONFIG.copy() self.load_config() diff --git a/src/modules/bot.py b/src/modules/bot.py index 7b4db46f..5c96d262 100644 --- a/src/modules/bot.py +++ b/src/modules/bot.py @@ -13,7 +13,7 @@ from src.routine.routine import Routine from src.routine.components import Point from src.common.vkeys import press, click -from src.modules.interfaces import Configurable +from src.common.interfaces import Configurable # The rune's buff icon @@ -23,7 +23,6 @@ class Bot(Configurable): """A class that interprets and executes user-defined routines.""" - TARGET = 'keybindings' DEFAULT_CONFIG = { 'Interact': 'y', 'Feed pet': '9' @@ -32,7 +31,7 @@ class Bot(Configurable): def __init__(self): """Loads a user-defined routine on start up and initializes this Bot's main thread.""" - super().__init__() + super().__init__('keybindings') config.bot = self self.rune_active = False @@ -72,9 +71,18 @@ def _main(self): self.ready = True config.listener.enabled = True + last_fed = time.time() while True: if config.enabled and len(config.routine) > 0: + # Buff and feed pets self.buff.main() + pet_settings = config.gui.settings.pets + auto_feed = pet_settings.auto_feed.get() + num_pets = pet_settings.num_pets.get() + now = time.time() + if auto_feed and now - last_fed > 1200 / num_pets: + press(self.config['Feed pet'], 1) + last_fed = now # Highlight the current Point config.gui.view.routine.select(config.routine.index) diff --git a/src/modules/listener.py b/src/modules/listener.py index 63b519ee..4e54c847 100644 --- a/src/modules/listener.py +++ b/src/modules/listener.py @@ -4,13 +4,12 @@ import threading import winsound import keyboard as kb -from src.modules.interfaces import Configurable +from src.common.interfaces import Configurable from src.common import config, utils from datetime import datetime class Listener(Configurable): - TARGET = 'controls' DEFAULT_CONFIG = { 'Start/stop': 'insert', 'Reload routine': 'f6', @@ -20,7 +19,7 @@ class Listener(Configurable): def __init__(self): """Initializes this Listener object's main thread.""" - super().__init__() + super().__init__('controls') config.listener = self self.enabled = False From 27f72e37581a4b02f9a9e9d227647939dc65ae82 Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Thu, 26 May 2022 01:04:09 -0700 Subject: [PATCH 08/28] catching image grab error --- src/modules/bot.py | 10 ++++++---- src/modules/capture.py | 16 ++++++++++++++-- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/modules/bot.py b/src/modules/bot.py index 5c96d262..c24026a9 100644 --- a/src/modules/bot.py +++ b/src/modules/bot.py @@ -4,8 +4,6 @@ import time import cv2 import inspect -import numpy as np -from PIL import ImageGrab from os.path import splitext, basename from src.common import config, utils from src.detection import detection @@ -116,7 +114,9 @@ def _solve_rune(self, model): print('\nSolving rune:') inferences = [] for _ in range(15): - frame = np.array(ImageGrab.grab(config.capture.window)) + frame = config.capture.screenshot() + if frame is None: + continue frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) solution = detection.merge_detection(model, frame) if solution: @@ -128,7 +128,9 @@ def _solve_rune(self, model): time.sleep(1) for _ in range(3): time.sleep(0.3) - frame = np.array(ImageGrab.grab(config.capture.window)) + frame = config.capture.screenshot() + if frame is None: + continue frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) rune_buff = utils.multi_match(frame[:frame.shape[0] // 8, :], RUNE_BUFF_TEMPLATE, diff --git a/src/modules/capture.py b/src/modules/capture.py index 71f0fa73..21cf4016 100644 --- a/src/modules/capture.py +++ b/src/modules/capture.py @@ -85,7 +85,9 @@ def _main(self): ) # Calibrate by finding the bottom right corner of the minimap - self.frame = np.array(ImageGrab.grab(self.window)) + self.frame = self.screenshot() + if self.frame is None: + continue self.frame = cv2.cvtColor(self.frame, cv2.COLOR_RGB2BGR) tl, _ = utils.single_match(self.frame, MM_TL_TEMPLATE) _, br = utils.single_match(self.frame, MM_BR_TEMPLATE) @@ -110,7 +112,9 @@ def _main(self): self.calibrated = True # Take screenshot - self.frame = np.array(ImageGrab.grab(self.window)) + self.frame = self.screenshot() + if self.frame is None: + continue self.frame = cv2.cvtColor(self.frame, cv2.COLOR_RGB2BGR) # Crop the frame to only show the minimap @@ -133,3 +137,11 @@ def _main(self): if not self.ready: self.ready = True time.sleep(0.001) + + def screenshot(self, delay=1): + try: + return np.array(ImageGrab.grab(self.window)) + except OSError: + print(f'\n[!] Error while taking screenshot, retrying in {delay} second' + + ('s' if delay != 1 else '')) + time.sleep(delay) From aec267d162ac7e23ef6b61d5e2285c1b5be5543e Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Thu, 26 May 2022 01:19:50 -0700 Subject: [PATCH 09/28] fixed last of key_bind -> config conversion --- layouts/dcup2 | Bin 1068 -> 1248 bytes src/modules/notifier.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/layouts/dcup2 b/layouts/dcup2 index 77aa4f4993e08f50ed97e4b2275f95f46ced3f8d..d378f175c6dd0a8fd82134ee8b0eca188bd43caa 100644 GIT binary patch literal 1248 zcmZo*PA)D=)+@>{Ey>JF)yqk&1hTk%AXFiPW@8~^Z6T9J1PcQLLtbKTY9Vt3E0CFz zTv}jM$O0BF%Fiz;WW{ETUw%p|S0NkF5cb+a4vh##pw5ayPIvnk982`uS<}G+m4#gH z_9v6P=ghyGAHfb(QCbk6lbTji$ejVw$x~a%tC0cJ^K>tJ|H^5q83@%G5EXp2h5TR@ zj~202D=&4yR3T7XC9IWCP7Bl=JI3Qjt%1qBFDU|Sw-~D3iaAT4X}#Kzt_I7srAKFp;=p~1y*tLP2W@j zG%39$3ZFS!EY{8@f(M_g(hGf zHzqw-{~mn-qyrw3$T|=y3n_ZBGNr%sUxv6}23S3ehUk;7EtHx3 zhEduWn+k*`Bw2_)+1f(6$yQ9#qDV60V3)|(7Aj26Vv=J~tSwZU+yi7N*A}WwUI%2T z))uNwzQ80m`3w`M=E*mGQw5A~f*iU(SjV$?@}CTDumPI2g<4>*?6|?PM8BPN@;@f& z`lYkVF7`Hbp{Pdj7Lq%lOt4|PwS{_M!!A_(nwjK17i7R5QIKJcsNn(%N$mawiAqDl z4oQUs*m(WgLW9ZrEOIP{wS`8L16icqA;Du@TWA8d_VwBqHnlz*LDn8HzA3AvkdA6C OJX#P&mnM}a=>Y)98mXWF diff --git a/src/modules/notifier.py b/src/modules/notifier.py index 11c2be75..d064850b 100644 --- a/src/modules/notifier.py +++ b/src/modules/notifier.py @@ -99,7 +99,7 @@ def _alert(self): self.mixer.load('./assets/alerts/alert.mp3') self.mixer.set_volume(0.75) self.mixer.play(-1) - while not kb.is_pressed(config.listener.key_binds['Start/stop']): + while not kb.is_pressed(config.listener.config['Start/stop']): time.sleep(0.1) self.mixer.stop() time.sleep(2) From 48dedf5300814d7e87cddf7497492bca2c3b6653 Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Thu, 26 May 2022 01:22:58 -0700 Subject: [PATCH 10/28] updated dcup2 layout --- layouts/dcup2 | Bin 1248 -> 1293 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/layouts/dcup2 b/layouts/dcup2 index d378f175c6dd0a8fd82134ee8b0eca188bd43caa..cc5f04000a597175508c94609c8500cf2cfee65b 100644 GIT binary patch delta 195 zcmaFB*~_&dm`OB)O|!93v9?f2BZJf3{^gs#sRG6~Cm&#xnk>b{%_RwzR<12nnViKW z$D&$Ws5ZHWNpA8PCeF#5nItE_1JYNSBn7l<3w6K-oP-*nz$`7h;|9kP{dU$2E_eI= z!8)GBlmBFJgU!>gEi{;H#;n6)SX*c`IgQzh#kjW6WbzVbJr>j2LbJ)&m_u32YYQzV j>$AwQSk@L=O%7yHWU;O-w3%GSqQYWZTWB|V9*YwIfn7eX delta 141 zcmWN@I}QP17zNOn|3)$jOZa8H#vtC$LBSS8X93gR1$+_ Date: Thu, 26 May 2022 09:30:52 -0700 Subject: [PATCH 11/28] moved minimap display out of gui main loop, gui no longer stutters --- gui_components/view/minimap.py | 1 - src/modules/gui.py | 13 ++++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/gui_components/view/minimap.py b/gui_components/view/minimap.py index 9639712b..e359097b 100644 --- a/gui_components/view/minimap.py +++ b/gui_components/view/minimap.py @@ -80,4 +80,3 @@ def display_minimap(self): else: self.canvas.itemconfig(self.container, image=img) self._img = img # Prevent garbage collection - self.after(50, self.display_minimap) diff --git a/src/modules/gui.py b/src/modules/gui.py index f42a5615..8de05579 100644 --- a/src/modules/gui.py +++ b/src/modules/gui.py @@ -1,5 +1,7 @@ """User friendly GUI to interact with Auto Maple.""" +import time +import threading import tkinter as tk from tkinter import ttk from src.common import config, settings @@ -7,6 +9,7 @@ class GUI: + DISPLAY_FRAME_RATE = 30 RESOLUTIONS = { 'DEFAULT': '800x800', 'Edit': '1400x800' @@ -71,10 +74,18 @@ def _resize_window(self, e): def start(self): """Starts the GUI as well as any scheduled functions.""" - self.view.minimap.display_minimap() + self.display_thread = threading.Thread(target=self._display_minimap) + self.display_thread.daemon = True + self.display_thread.start() self._save_layout() self.root.mainloop() + def _display_minimap(self): + delay = 1 / GUI.DISPLAY_FRAME_RATE + while True: + self.view.minimap.display_minimap() + time.sleep(delay) + def _save_layout(self): # TODO: move to bot main loop, file I/O is costly, blocks gui main loop """Periodically saves the current Layout object.""" From eb8dc2f41c380d4a94e1d458c463c317d3e8548c Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Thu, 26 May 2022 09:36:44 -0700 Subject: [PATCH 12/28] moved save layout out of gui main loop as well --- src/modules/bot.py | 2 +- src/modules/gui.py | 21 +++++++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/modules/bot.py b/src/modules/bot.py index c24026a9..2fa4ff50 100644 --- a/src/modules/bot.py +++ b/src/modules/bot.py @@ -65,7 +65,7 @@ def _main(self): print('\n[~] Initializing detection algorithm:\n') model = detection.load_model() - print('\n[~] Successfully initialized detection algorithm') + print('\n[~] Initialized detection algorithm') self.ready = True config.listener.enabled = True diff --git a/src/modules/gui.py b/src/modules/gui.py index 8de05579..2cd93fbb 100644 --- a/src/modules/gui.py +++ b/src/modules/gui.py @@ -74,10 +74,14 @@ def _resize_window(self, e): def start(self): """Starts the GUI as well as any scheduled functions.""" - self.display_thread = threading.Thread(target=self._display_minimap) - self.display_thread.daemon = True - self.display_thread.start() - self._save_layout() + display_thread = threading.Thread(target=self._display_minimap) + display_thread.daemon = True + display_thread.start() + + layout_thread = threading.Thread(target=self._save_layout) + layout_thread.daemon = True + layout_thread.start() + self.root.mainloop() def _display_minimap(self): @@ -86,12 +90,13 @@ def _display_minimap(self): self.view.minimap.display_minimap() time.sleep(delay) - def _save_layout(self): # TODO: move to bot main loop, file I/O is costly, blocks gui main loop + def _save_layout(self): """Periodically saves the current Layout object.""" - if config.layout is not None and settings.record_layout: - config.layout.save() - self.root.after(5000, self._save_layout) + while True: + if config.layout is not None and settings.record_layout: + config.layout.save() + time.sleep(5) if __name__ == '__main__': From b5cd6981239c651d5aa04171678cf43730606e9c Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Thu, 26 May 2022 10:10:44 -0700 Subject: [PATCH 13/28] alerts if rune hasn't been solved in 2 minutes --- src/modules/notifier.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/modules/notifier.py b/src/modules/notifier.py index d064850b..a2efa1f4 100644 --- a/src/modules/notifier.py +++ b/src/modules/notifier.py @@ -39,6 +39,9 @@ def __init__(self): self.thread = threading.Thread(target=self._main) self.thread.daemon = True + self.room_change_threshold = 0.9 + self.rune_alert_delay = 120 + def start(self): """Starts this Notifier's thread.""" @@ -48,6 +51,7 @@ def start(self): def _main(self): self.ready = True prev_others = 0 + rune_start_time = time.time() while True: if config.enabled: frame = config.capture.frame @@ -56,7 +60,7 @@ def _main(self): # Check for unexpected black screen gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) - if np.count_nonzero(gray < 15) / height / width > 0.9: + if np.count_nonzero(gray < 15) / height / width > self.room_change_threshold: self._alert() # Check for elite warning @@ -75,9 +79,11 @@ def _main(self): prev_others = others # Check for rune + now = time.time() if not config.bot.rune_active: filtered = utils.filter_color(minimap, RUNE_RANGES) matches = utils.multi_match(filtered, RUNE_TEMPLATE, threshold=0.9) + rune_start_time = now if matches and config.routine.sequence: abs_rune_pos = (matches[0][0], matches[0][1]) config.bot.rune_pos = utils.convert_to_relative(abs_rune_pos, minimap) @@ -86,6 +92,9 @@ def _main(self): config.bot.rune_closest_pos = config.routine[index].location config.bot.rune_active = True self._rune_alert() + elif now - rune_start_time > self.rune_alert_delay: # Alert if rune hasn't been solved + config.bot.rune_active = False + self._alert() time.sleep(0.05) def _alert(self): From f3897399be2537343525c3891802385b578a5bc2 Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Thu, 26 May 2022 10:45:55 -0700 Subject: [PATCH 14/28] generalized alert and pings --- .../{rune_alert.mp3 => rune_appeared.mp3} | Bin assets/alerts/{alert.mp3 => siren.mp3} | Bin layouts/dcup2 | Bin 1293 -> 1383 bytes src/modules/notifier.py | 40 +++++++++--------- 4 files changed, 20 insertions(+), 20 deletions(-) rename assets/alerts/{rune_alert.mp3 => rune_appeared.mp3} (100%) rename assets/alerts/{alert.mp3 => siren.mp3} (100%) diff --git a/assets/alerts/rune_alert.mp3 b/assets/alerts/rune_appeared.mp3 similarity index 100% rename from assets/alerts/rune_alert.mp3 rename to assets/alerts/rune_appeared.mp3 diff --git a/assets/alerts/alert.mp3 b/assets/alerts/siren.mp3 similarity index 100% rename from assets/alerts/alert.mp3 rename to assets/alerts/siren.mp3 diff --git a/layouts/dcup2 b/layouts/dcup2 index cc5f04000a597175508c94609c8500cf2cfee65b..5d99054e94375d03f1f2201d5091240a63a48e4b 100644 GIT binary patch delta 219 zcmeC>dd{_>nMpK*O|!93xwcS6BZJf3{;khO)pP#uCm&!`;*tbQsn!;%O`gsq$D&?a zs4;mbkfB*ys5SXEliXx!X3oh>%#tj+wS{_<<(cIs#{&i2fC7fKg+`N;nRQr)Jw_$uTT)EVi|Uc9ZK^6j|(R3mqmeW>H~rtSxk!e451x E03FaqPyhe` delta 179 zcmaFP)yuV^nQ5{#6PJ!;2AgJMp>l1Zibe*fyZzHpFv#F?x8KtG;lY~A+cUVqDpYF= z)h0h;q)z))wkb&I2;^YYPn~Phi$zF{~{# zntXs+pWiP-(l0{_Y?5(pp~+-z7Cjcz+CsC*u`Ho1=Cy?ulee+Ru~^m?T1~#eqR3)h UTWB-+FN+F`ZEd05WK~ut0O?paM*si- diff --git a/src/modules/notifier.py b/src/modules/notifier.py index a2efa1f4..16a2e4e0 100644 --- a/src/modules/notifier.py +++ b/src/modules/notifier.py @@ -2,6 +2,7 @@ from src.common import config, utils import time +import os import cv2 import pygame import threading @@ -28,7 +29,13 @@ ELITE_TEMPLATE = cv2.imread('assets/elite_template.jpg', 0) +def get_alert_path(name): + return os.path.join(Notifier.ALERTS_DIR, f'{name}.mp3') + + class Notifier: + ALERTS_DIR = os.path.join('assets', 'alerts') + def __init__(self): """Initializes this Notifier object's main thread.""" @@ -40,7 +47,7 @@ def __init__(self): self.thread.daemon = True self.room_change_threshold = 0.9 - self.rune_alert_delay = 120 + self.rune_alert_delay = 270 # 4.5 minutes def start(self): """Starts this Notifier's thread.""" @@ -61,13 +68,13 @@ def _main(self): # Check for unexpected black screen gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) if np.count_nonzero(gray < 15) / height / width > self.room_change_threshold: - self._alert() + self._alert('siren') # Check for elite warning elite_frame = frame[height // 4:3 * height // 4, width // 4:3 * width // 4] elite = utils.multi_match(elite_frame, ELITE_TEMPLATE, threshold=0.9) if len(elite) > 0: - self._alert() + self._alert('siren') # Check for other players entering the map filtered = utils.filter_color(minimap, OTHER_RANGES) @@ -75,7 +82,7 @@ def _main(self): config.stage_fright = others > 0 if others != prev_others: if others > prev_others: - self._ding() + self._ping('ding') prev_others = others # Check for rune @@ -91,13 +98,13 @@ def _main(self): index = np.argmin(distances) config.bot.rune_closest_pos = config.routine[index].location config.bot.rune_active = True - self._rune_alert() + self._ping('rune_appeared', volume=0.75) elif now - rune_start_time > self.rune_alert_delay: # Alert if rune hasn't been solved config.bot.rune_active = False - self._alert() + self._alert('siren') time.sleep(0.05) - def _alert(self): + def _alert(self, name, volume=0.75): """ Plays an alert to notify user of a dangerous event. Stops the alert once the key bound to 'Start/stop' is pressed. @@ -105,8 +112,8 @@ def _alert(self): config.enabled = False config.listener.enabled = False - self.mixer.load('./assets/alerts/alert.mp3') - self.mixer.set_volume(0.75) + self.mixer.load(get_alert_path(name)) + self.mixer.set_volume(volume) self.mixer.play(-1) while not kb.is_pressed(config.listener.config['Start/stop']): time.sleep(0.1) @@ -114,18 +121,11 @@ def _alert(self): time.sleep(2) config.listener.enabled = True - def _ding(self): - """A quick notification for when another player enters the map.""" - - self.mixer.load('./assets/alerts/ding.mp3') - self.mixer.set_volume(0.50) - self.mixer.play() - - def _rune_alert(self): - """Notification for when a rune appears.""" + def _ping(self, name, volume=0.5): + """A quick notification for non-dangerous events.""" - self.mixer.load('./assets/alerts/rune_alert.mp3') - self.mixer.set_volume(0.75) + self.mixer.load(get_alert_path(name)) + self.mixer.set_volume(volume) self.mixer.play() From 58907414ccd2a43f850cd11f8d41fbd898eed53e Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Thu, 26 May 2022 11:38:23 -0700 Subject: [PATCH 15/28] updated layout for dcup2 --- layouts/dcup2 | Bin 1383 -> 1428 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/layouts/dcup2 b/layouts/dcup2 index 5d99054e94375d03f1f2201d5091240a63a48e4b..5625e31ce396536dffe691f60463a0c45ebc4d26 100644 GIT binary patch delta 74 zcmV-Q0JZ<;3X}`5j0BVK0|gK}eQ`V}XbDF@;1Nh)4hqeaX#_Y58fXS7fpI;3aXyo_ g1RexGeQ`jO*aRU2L49#Tll=rF1VepsM3W^2LXjUA%K!iX delta 76 zcmV-S0JHy;3+D>3j0BS#0v40c1P~@WeQ`V}XbDF@>{`3?3AnXr3P(S*h4A34)3;~~ iXa*^PaXo!;K9dCnAp}2taX^zQ1tbJPeQ`pQQUyX(2^(_& From 9a22b5e6e1ed606267c902a8581bcb77a9da8d7f Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Thu, 26 May 2022 13:18:46 -0700 Subject: [PATCH 16/28] updated layout for dcup2 --- layouts/dcup2 | Bin 1428 -> 1473 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/layouts/dcup2 b/layouts/dcup2 index 5625e31ce396536dffe691f60463a0c45ebc4d26..21833d4c5b1459883becc502b640ac645b695376 100644 GIT binary patch delta 114 zcmbQjeUN*@DHhQTHqFLD+uA}qjSNnA`^S@iuYF-tJ2{S3(yBBmL&7gZ(l0~G56F}P zE3~gIbO0-S6Sey@=Z>uzT<-Q;T0cBkb9s9PH&}&ZZK2a-R#rt8=h{M-$y%%`EUvYM JZj*ypodA`>DV_iT delta 81 zcmX@eJ%xM2DVE7%O#EC@8El%3g|@YYc9R8IVJ^Dfhm%IIz j)(;QXT;86+?Ux||R_$0@=rlQ;RfWa5w$NpAJ*yJ{j>#Q1 From 9b65db864291fa30cd1b8effceb68cc8f326cc17 Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Thu, 26 May 2022 14:14:00 -0700 Subject: [PATCH 17/28] moved gui_components into src --- gui_components/__init__.py | 9 --------- src/gui_components/__init__.py | 9 +++++++++ .../gui_components}/edit/commands.py | 2 +- .../gui_components}/edit/components.py | 2 +- .../gui_components}/edit/controls.py | 2 +- {gui_components => src/gui_components}/edit/main.py | 10 +++++----- {gui_components => src/gui_components}/edit/minimap.py | 2 +- {gui_components => src/gui_components}/edit/record.py | 2 +- {gui_components => src/gui_components}/edit/routine.py | 8 ++++---- {gui_components => src/gui_components}/edit/status.py | 2 +- {gui_components => src/gui_components}/interfaces.py | 0 {gui_components => src/gui_components}/menu/main.py | 0 .../gui_components}/settings/keybindings.py | 2 +- .../gui_components}/settings/main.py | 6 +++--- .../gui_components}/settings/pets.py | 2 +- {gui_components => src/gui_components}/view/details.py | 2 +- {gui_components => src/gui_components}/view/main.py | 10 +++++----- {gui_components => src/gui_components}/view/minimap.py | 2 +- {gui_components => src/gui_components}/view/routine.py | 2 +- {gui_components => src/gui_components}/view/status.py | 2 +- src/modules/gui.py | 2 +- 21 files changed, 39 insertions(+), 39 deletions(-) delete mode 100644 gui_components/__init__.py create mode 100644 src/gui_components/__init__.py rename {gui_components => src/gui_components}/edit/commands.py (98%) rename {gui_components => src/gui_components}/edit/components.py (98%) rename {gui_components => src/gui_components}/edit/controls.py (98%) rename {gui_components => src/gui_components}/edit/main.py (97%) rename {gui_components => src/gui_components}/edit/minimap.py (98%) rename {gui_components => src/gui_components}/edit/record.py (97%) rename {gui_components => src/gui_components}/edit/routine.py (76%) rename {gui_components => src/gui_components}/edit/status.py (91%) rename {gui_components => src/gui_components}/interfaces.py (100%) rename {gui_components => src/gui_components}/menu/main.py (100%) rename {gui_components => src/gui_components}/settings/keybindings.py (98%) rename {gui_components => src/gui_components}/settings/main.py (84%) rename {gui_components => src/gui_components}/settings/pets.py (96%) rename {gui_components => src/gui_components}/view/details.py (97%) rename {gui_components => src/gui_components}/view/main.py (75%) rename {gui_components => src/gui_components}/view/minimap.py (98%) rename {gui_components => src/gui_components}/view/routine.py (95%) rename {gui_components => src/gui_components}/view/status.py (95%) diff --git a/gui_components/__init__.py b/gui_components/__init__.py deleted file mode 100644 index 18ec8c72..00000000 --- a/gui_components/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -import gui_components.menu.main as menu -import gui_components.view.main as view -import gui_components.edit.main as edit -import gui_components.settings.main as settings - -Menu = menu.Menu -View = view.View -Edit = edit.Edit -Settings = settings.Settings diff --git a/src/gui_components/__init__.py b/src/gui_components/__init__.py new file mode 100644 index 00000000..417c0490 --- /dev/null +++ b/src/gui_components/__init__.py @@ -0,0 +1,9 @@ +import src.gui_components.menu.main as menu +import src.gui_components.view.main as view +import src.gui_components.edit.main as edit +import src.gui_components.settings.main as settings + +Menu = menu.Menu +View = view.View +Edit = edit.Edit +Settings = settings.Settings diff --git a/gui_components/edit/commands.py b/src/gui_components/edit/commands.py similarity index 98% rename from gui_components/edit/commands.py rename to src/gui_components/edit/commands.py index 974ee9ba..f4310f3c 100644 --- a/gui_components/edit/commands.py +++ b/src/gui_components/edit/commands.py @@ -2,7 +2,7 @@ from src.common import config from src.routine.components import Point -from gui_components.interfaces import Frame +from src.gui_components.interfaces import Frame class Commands(Frame): diff --git a/gui_components/edit/components.py b/src/gui_components/edit/components.py similarity index 98% rename from gui_components/edit/components.py rename to src/gui_components/edit/components.py index 5371a995..6537f56e 100644 --- a/gui_components/edit/components.py +++ b/src/gui_components/edit/components.py @@ -1,7 +1,7 @@ import tkinter as tk from src.common import config from src.routine.components import Point -from gui_components.interfaces import Frame +from src.gui_components.interfaces import Frame class Components(Frame): diff --git a/gui_components/edit/controls.py b/src/gui_components/edit/controls.py similarity index 98% rename from gui_components/edit/controls.py rename to src/gui_components/edit/controls.py index 5eff8fec..ad72af6b 100644 --- a/gui_components/edit/controls.py +++ b/src/gui_components/edit/controls.py @@ -1,6 +1,6 @@ import tkinter as tk from src.common import config -from gui_components.interfaces import Frame +from src.gui_components.interfaces import Frame class Controls(Frame): diff --git a/gui_components/edit/main.py b/src/gui_components/edit/main.py similarity index 97% rename from gui_components/edit/main.py rename to src/gui_components/edit/main.py index 18441722..c83684d1 100644 --- a/gui_components/edit/main.py +++ b/src/gui_components/edit/main.py @@ -4,11 +4,11 @@ import inspect import tkinter as tk from src.routine.components import Point, Command -from gui_components.edit.minimap import Minimap -from gui_components.edit.record import Record -from gui_components.edit.routine import Routine -from gui_components.edit.status import Status -from gui_components.interfaces import Tab, Frame, LabelFrame +from src.gui_components.edit.minimap import Minimap +from src.gui_components.edit.record import Record +from src.gui_components.edit.routine import Routine +from src.gui_components.edit.status import Status +from src.gui_components.interfaces import Tab, Frame, LabelFrame class Edit(Tab): diff --git a/gui_components/edit/minimap.py b/src/gui_components/edit/minimap.py similarity index 98% rename from gui_components/edit/minimap.py rename to src/gui_components/edit/minimap.py index 54e7c931..cb8a4e65 100644 --- a/gui_components/edit/minimap.py +++ b/src/gui_components/edit/minimap.py @@ -3,7 +3,7 @@ from PIL import ImageTk, Image from src.common import config, utils from src.routine.components import Point -from gui_components.interfaces import LabelFrame +from src.gui_components.interfaces import LabelFrame class Minimap(LabelFrame): diff --git a/gui_components/edit/record.py b/src/gui_components/edit/record.py similarity index 97% rename from gui_components/edit/record.py rename to src/gui_components/edit/record.py index 5ebcd610..a6b803c3 100644 --- a/gui_components/edit/record.py +++ b/src/gui_components/edit/record.py @@ -1,6 +1,6 @@ import tkinter as tk from src.routine.components import Point -from gui_components.interfaces import LabelFrame +from src.gui_components.interfaces import LabelFrame class Record(LabelFrame): diff --git a/gui_components/edit/routine.py b/src/gui_components/edit/routine.py similarity index 76% rename from gui_components/edit/routine.py rename to src/gui_components/edit/routine.py index 6bbbfac3..c2f99ca7 100644 --- a/gui_components/edit/routine.py +++ b/src/gui_components/edit/routine.py @@ -1,8 +1,8 @@ import tkinter as tk -from gui_components.edit.commands import Commands -from gui_components.edit.components import Components -from gui_components.edit.controls import Controls -from gui_components.interfaces import LabelFrame, Frame +from src.gui_components.edit.commands import Commands +from src.gui_components.edit.components import Components +from src.gui_components.edit.controls import Controls +from src.gui_components.interfaces import LabelFrame, Frame class Routine(LabelFrame): diff --git a/gui_components/edit/status.py b/src/gui_components/edit/status.py similarity index 91% rename from gui_components/edit/status.py rename to src/gui_components/edit/status.py index 7ec2994a..23e7ac85 100644 --- a/gui_components/edit/status.py +++ b/src/gui_components/edit/status.py @@ -1,6 +1,6 @@ import tkinter as tk from src.common import config -from gui_components.interfaces import LabelFrame +from src.gui_components.interfaces import LabelFrame class Status(LabelFrame): diff --git a/gui_components/interfaces.py b/src/gui_components/interfaces.py similarity index 100% rename from gui_components/interfaces.py rename to src/gui_components/interfaces.py diff --git a/gui_components/menu/main.py b/src/gui_components/menu/main.py similarity index 100% rename from gui_components/menu/main.py rename to src/gui_components/menu/main.py diff --git a/gui_components/settings/keybindings.py b/src/gui_components/settings/keybindings.py similarity index 98% rename from gui_components/settings/keybindings.py rename to src/gui_components/settings/keybindings.py index 9b5ba60a..e3039e57 100644 --- a/gui_components/settings/keybindings.py +++ b/src/gui_components/settings/keybindings.py @@ -1,6 +1,6 @@ import tkinter as tk import keyboard as kb -from gui_components.interfaces import LabelFrame, Frame +from src.gui_components.interfaces import LabelFrame, Frame from src.common import utils from src.common.interfaces import Configurable diff --git a/gui_components/settings/main.py b/src/gui_components/settings/main.py similarity index 84% rename from gui_components/settings/main.py rename to src/gui_components/settings/main.py index a586e1d2..d014e147 100644 --- a/gui_components/settings/main.py +++ b/src/gui_components/settings/main.py @@ -1,9 +1,9 @@ """Displays Auto Maple's current settings and allows the user to edit them.""" import tkinter as tk -from gui_components.settings.keybindings import KeyBindings -from gui_components.settings.pets import Pets -from gui_components.interfaces import Tab, Frame +from src.gui_components.settings.keybindings import KeyBindings +from src.gui_components.settings.pets import Pets +from src.gui_components.interfaces import Tab, Frame from src.common import config diff --git a/gui_components/settings/pets.py b/src/gui_components/settings/pets.py similarity index 96% rename from gui_components/settings/pets.py rename to src/gui_components/settings/pets.py index 3091c045..d9a3c276 100644 --- a/gui_components/settings/pets.py +++ b/src/gui_components/settings/pets.py @@ -1,5 +1,5 @@ import tkinter as tk -from gui_components.interfaces import LabelFrame, Frame +from src.gui_components.interfaces import LabelFrame, Frame from src.common.interfaces import Configurable diff --git a/gui_components/view/details.py b/src/gui_components/view/details.py similarity index 97% rename from gui_components/view/details.py rename to src/gui_components/view/details.py index 5125e58d..a9cdccfc 100644 --- a/gui_components/view/details.py +++ b/src/gui_components/view/details.py @@ -1,5 +1,5 @@ import tkinter as tk -from gui_components.interfaces import LabelFrame +from src.gui_components.interfaces import LabelFrame from src.common import config diff --git a/gui_components/view/main.py b/src/gui_components/view/main.py similarity index 75% rename from gui_components/view/main.py rename to src/gui_components/view/main.py index 7ba8bc8a..d96d0485 100644 --- a/gui_components/view/main.py +++ b/src/gui_components/view/main.py @@ -1,11 +1,11 @@ """Displays the current minimap as well as various information regarding the current routine.""" import tkinter as tk -from gui_components.view.details import Details -from gui_components.view.minimap import Minimap -from gui_components.view.routine import Routine -from gui_components.view.status import Status -from gui_components.interfaces import Tab +from src.gui_components.view.details import Details +from src.gui_components.view.minimap import Minimap +from src.gui_components.view.routine import Routine +from src.gui_components.view.status import Status +from src.gui_components.interfaces import Tab class View(Tab): diff --git a/gui_components/view/minimap.py b/src/gui_components/view/minimap.py similarity index 98% rename from gui_components/view/minimap.py rename to src/gui_components/view/minimap.py index e359097b..9b55557c 100644 --- a/gui_components/view/minimap.py +++ b/src/gui_components/view/minimap.py @@ -1,7 +1,7 @@ import cv2 import tkinter as tk from PIL import ImageTk, Image -from gui_components.interfaces import LabelFrame +from src.gui_components.interfaces import LabelFrame from src.common import config, utils from src.routine.components import Point diff --git a/gui_components/view/routine.py b/src/gui_components/view/routine.py similarity index 95% rename from gui_components/view/routine.py rename to src/gui_components/view/routine.py index 8b71247e..3c54a6f4 100644 --- a/gui_components/view/routine.py +++ b/src/gui_components/view/routine.py @@ -1,5 +1,5 @@ import tkinter as tk -from gui_components.interfaces import LabelFrame +from src.gui_components.interfaces import LabelFrame from src.common import config diff --git a/gui_components/view/status.py b/src/gui_components/view/status.py similarity index 95% rename from gui_components/view/status.py rename to src/gui_components/view/status.py index ceab4f51..30b22f8e 100644 --- a/gui_components/view/status.py +++ b/src/gui_components/view/status.py @@ -1,5 +1,5 @@ import tkinter as tk -from gui_components.interfaces import LabelFrame +from src.gui_components.interfaces import LabelFrame class Status(LabelFrame): diff --git a/src/modules/gui.py b/src/modules/gui.py index 2cd93fbb..90e7200f 100644 --- a/src/modules/gui.py +++ b/src/modules/gui.py @@ -5,7 +5,7 @@ import tkinter as tk from tkinter import ttk from src.common import config, settings -from gui_components import Menu, View, Edit, Settings +from src.gui_components import Menu, View, Edit, Settings class GUI: From e024e3a510923f8a8de5a1e90eb51f8da8b6eaaf Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Thu, 26 May 2022 17:09:20 -0700 Subject: [PATCH 18/28] moved command books and routines to community resources repo --- .gitignore | 2 + command_books/blaster.py | 170 ---------------------- command_books/kanna.py | 295 --------------------------------------- routines/cf1.csv | 62 -------- routines/dcup2.csv | 84 ----------- routines/mts3.csv | 217 ---------------------------- routines/os3.csv | 100 ------------- 7 files changed, 2 insertions(+), 928 deletions(-) delete mode 100644 command_books/blaster.py delete mode 100644 command_books/kanna.py delete mode 100644 routines/cf1.csv delete mode 100644 routines/dcup2.csv delete mode 100644 routines/mts3.csv delete mode 100644 routines/os3.csv diff --git a/.gitignore b/.gitignore index 885f5509..b8be820f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ __pycache__/ assets/models/ +command_books/* +routines/* .idea/ .settings/ diff --git a/command_books/blaster.py b/command_books/blaster.py deleted file mode 100644 index 482f71a1..00000000 --- a/command_books/blaster.py +++ /dev/null @@ -1,170 +0,0 @@ -"""A collection of all commands that a Blaster can use to interact with the game.""" - -import time -from src.common import settings -from src.routine.components import Command -from src.common.vkeys import press, key_down, key_up - -# -# class Move(Command): -# """Moves to a given position using the shortest path based on the current Layout.""" -# -# def __init__(self, x, y, max_steps=15): -# super().__init__(locals()) -# self.target = (float(x), float(y)) -# self.max_steps = settings.validate_nonnegative_int(max_steps) -# -# def main(self): -# counter = self.max_steps -# path = config.layout.shortest_path(config.player_pos, self.target) -# # config.path = path.copy() -# # config.path.insert(0, config.player_pos) -# for point in path: -# counter = self._step(point, counter) -# -# @utils.run_if_enabled -# def _step(self, target, counter): -# toggle = True -# local_error = utils.distance(config.player_pos, target) -# global_error = utils.distance(config.player_pos, self.target) -# while config.enabled and \ -# counter > 0 and \ -# local_error > settings.move_tolerance and \ -# global_error > settings.move_tolerance: -# if toggle: -# d_x = target[0] - config.player_pos[0] -# if abs(d_x) > settings.move_tolerance / math.sqrt(2): -# if d_x < 0: -# Jump('left').main() -# else: -# Jump('right').main() -# counter -= 1 -# else: -# d_y = target[1] - config.player_pos[1] -# if abs(d_y) > settings.move_tolerance / math.sqrt(2): -# if d_y < 0: -# Jump('up').main() -# else: -# Jump('down').main() -# counter -= 1 -# local_error = utils.distance(config.player_pos, target) -# global_error = utils.distance(config.player_pos, self.target) -# toggle = not toggle -# return counter -# -# -# class Adjust(Command): -# """Fine-tunes player position using small movements.""" -# -# def __init__(self, x, y, max_steps=5): -# super().__init__(locals()) -# self.target = (float(x), float(y)) -# self.max_steps = settings.validate_nonnegative_int(max_steps) -# -# def main(self): -# counter = self.max_steps -# toggle = True -# error = utils.distance(config.player_pos, self.target) -# while config.enabled and counter > 0 and error > settings.adjust_tolerance: -# if toggle: -# d_x = self.target[0] - config.player_pos[0] -# threshold = settings.adjust_tolerance / math.sqrt(2) -# if abs(d_x) > threshold: -# walk_counter = 0 -# if d_x < 0: -# key_down('left') -# while config.enabled and d_x < -1 * threshold and walk_counter < 60: -# time.sleep(0.05) -# walk_counter += 1 -# d_x = self.target[0] - config.player_pos[0] -# key_up('left') -# else: -# key_down('right') -# while config.enabled and d_x > threshold and walk_counter < 60: -# time.sleep(0.05) -# walk_counter += 1 -# d_x = self.target[0] - config.player_pos[0] -# key_up('right') -# counter -= 1 -# else: -# d_y = self.target[1] - config.player_pos[1] -# if abs(d_y) > settings.adjust_tolerance / math.sqrt(2): -# if d_y < 0: -# Jump('up').main() -# else: -# key_down('down') -# time.sleep(0.05) -# press('space', 3, down_time=0.1) -# key_up('down') -# time.sleep(0.05) -# counter -= 1 -# error = utils.distance(config.player_pos, self.target) -# toggle = not toggle -# -# -# def step(direction, target): -# print('blaster step test') - - -class Buff(Command): - """Uses each of Blaster's buffs once.""" - - def __init__(self): - super().__init__(locals()) - self.booster_time = 0 - self.warrior_time = 0 - - def main(self): - now = time.time() - if self.booster_time == 0 or now - self.booster_time > 190: - press('f1', 2) - self.booster_time = now - if self.warrior_time == 0 or now - self.warrior_time > 890: - press('f2', 2) - self.warrior_time = now - - -class Jump(Command): - """Performs a flash jump or 'Detonate' in the given direction.""" - - def __init__(self, direction): - super().__init__(locals()) - self.direction = settings.validate_arrows(direction) - - def main(self): - key_down(self.direction) - time.sleep(0.1) - press('space', 1) - if self.direction == 'up': - press('d', 1) - else: - press('space', 1) - key_up(self.direction) - time.sleep(0.5) - - -class MagnumPunch(Command): - """Performs a 'No-Reload Magnum Punch' combo once.""" - - def __init__(self, direction): - super().__init__(locals()) - self.direction = settings.validate_arrows(direction) - - def main(self): - key_down(self.direction) - time.sleep(0.05) - key_down('q') - time.sleep(0.1) - for _ in range(3): - key_down('r') - time.sleep(0.05) - key_down('e') - time.sleep(0.05) - key_up('r') - key_up('e') - time.sleep(0.05) - key_up('q') - time.sleep(0.025) - press('space', 1) - key_up(self.direction) - time.sleep(0.05) diff --git a/command_books/kanna.py b/command_books/kanna.py deleted file mode 100644 index 62e274f5..00000000 --- a/command_books/kanna.py +++ /dev/null @@ -1,295 +0,0 @@ -"""A collection of all commands that a Kanna can use to interact with the game.""" - -from src.common import config, settings, utils -import time -import math -from src.routine.components import Command -from src.common.vkeys import press, key_down, key_up - - -# List of key mappings -class Key: - # Movement - JUMP = 'space' - TELEPORT = 'e' - CHARM = 'd' - - # Buffs - HAKU = 'f4' - AKATSUKI_WARRIOR = 'f3' - HOLY_SYMBOL = 'f2' - SPEED_INFUSION = 'f1' - - # Skills - SHIKIGAMI = 'r' - TENGU = 'q' - YAKSHA = '2' - VANQUISHER = 'f' - KISHIN = 'ctrl' - NINE_TAILS = '3' - EXORCIST = 'w' - DOMAIN = 'z' - ONI_LEGION = '5' - BLOSSOM_BARRIER = 'g' - YUKIMUSUME = 'c' - MANA_BALANCE = 'lshift' - - -######################### -# Commands # -######################### -def step(direction, target): - """ - Performs one movement step in the given DIRECTION towards TARGET. - Should not press any arrow keys, as those are handled by Auto Maple. - """ - - num_presses = 2 - if direction == 'up' or direction == 'down': - num_presses = 1 - if config.stage_fright and direction != 'up' and utils.bernoulli(0.75): - time.sleep(utils.rand_float(0.1, 0.3)) - d_y = target[1] - config.player_pos[1] - if abs(d_y) > settings.move_tolerance * 1.5: - if direction == 'down': - press(Key.JUMP, 3) - elif direction == 'up': - press(Key.JUMP, 1) - press(Key.TELEPORT, num_presses) - - -class Adjust(Command): - """Fine-tunes player position using small movements.""" - - def __init__(self, x, y, max_steps=5): - super().__init__(locals()) - self.target = (float(x), float(y)) - self.max_steps = settings.validate_nonnegative_int(max_steps) - - def main(self): - counter = self.max_steps - toggle = True - error = utils.distance(config.player_pos, self.target) - while config.enabled and counter > 0 and error > settings.adjust_tolerance: - if toggle: - d_x = self.target[0] - config.player_pos[0] - threshold = settings.adjust_tolerance / math.sqrt(2) - if abs(d_x) > threshold: - walk_counter = 0 - if d_x < 0: - key_down('left') - while config.enabled and d_x < -1 * threshold and walk_counter < 60: - time.sleep(0.05) - walk_counter += 1 - d_x = self.target[0] - config.player_pos[0] - key_up('left') - else: - key_down('right') - while config.enabled and d_x > threshold and walk_counter < 60: - time.sleep(0.05) - walk_counter += 1 - d_x = self.target[0] - config.player_pos[0] - key_up('right') - counter -= 1 - else: - d_y = self.target[1] - config.player_pos[1] - if abs(d_y) > settings.adjust_tolerance / math.sqrt(2): - if d_y < 0: - Teleport('up').main() - else: - key_down('down') - time.sleep(0.05) - press(Key.JUMP, 3, down_time=0.1) - key_up('down') - time.sleep(0.05) - counter -= 1 - error = utils.distance(config.player_pos, self.target) - toggle = not toggle - - -class Buff(Command): - """Uses each of Kanna's buffs once. Uses 'Haku Reborn' whenever it is available.""" - - def __init__(self): - super().__init__(locals()) - self.haku_time = 0 - self.buff_time = 0 - - def main(self): - buffs = [Key.SPEED_INFUSION, Key.HOLY_SYMBOL] - now = time.time() - if self.haku_time == 0 or now - self.haku_time > 490: - press(Key.HAKU, 2) - press(Key.AKATSUKI_WARRIOR, 2) - self.haku_time = now - if self.buff_time == 0 or now - self.buff_time > settings.buff_cooldown: - for key in buffs: - press(key, 3, up_time=0.3) - self.buff_time = now - - -class Teleport(Command): - """ - Teleports in a given direction, jumping if specified. Adds the player's position - to the current Layout if necessary. - """ - - def __init__(self, direction, jump='False'): - super().__init__(locals()) - self.direction = settings.validate_arrows(direction) - self.jump = settings.validate_boolean(jump) - - def main(self): - num_presses = 3 - time.sleep(0.05) - if self.direction in ['up', 'down']: - num_presses = 2 - if self.direction != 'up': - key_down(self.direction) - time.sleep(0.05) - if self.jump: - if self.direction == 'down': - press(Key.JUMP, 3, down_time=0.1) - else: - press(Key.JUMP, 1) - if self.direction == 'up': - key_down(self.direction) - time.sleep(0.05) - press(Key.TELEPORT, num_presses) - key_up(self.direction) - if settings.record_layout: - config.layout.add(*config.player_pos) - - -class Shikigami(Command): - """Attacks using 'Shikigami Haunting' in a given direction.""" - - def __init__(self, direction, attacks=2, repetitions=1): - super().__init__(locals()) - self.direction = settings.validate_horizontal_arrows(direction) - self.attacks = int(attacks) - self.repetitions = int(repetitions) - - def main(self): - time.sleep(0.05) - key_down(self.direction) - time.sleep(0.05) - if config.stage_fright and utils.bernoulli(0.7): - time.sleep(utils.rand_float(0.1, 0.3)) - for _ in range(self.repetitions): - press(Key.SHIKIGAMI, self.attacks, up_time=0.05) - key_up(self.direction) - if self.attacks > 2: - time.sleep(0.3) - else: - time.sleep(0.2) - - -class Tengu(Command): - """Uses 'Tengu Strike' once.""" - - def main(self): - press(Key.TENGU, 1, up_time=0.05) - - -class Yaksha(Command): - """ - Places 'Ghost Yaksha Boss' in a given direction, or towards the center of the map if - no direction is specified. - """ - - def __init__(self, direction=None): - super().__init__(locals()) - if direction is None: - self.direction = direction - else: - self.direction = settings.validate_horizontal_arrows(direction) - - def main(self): - if self.direction: - press(self.direction, 1, down_time=0.1, up_time=0.05) - else: - if config.player_pos[0] > 0.5: - press('left', 1, down_time=0.1, up_time=0.05) - else: - press('right', 1, down_time=0.1, up_time=0.05) - press(Key.YAKSHA, 3) - - -class Vanquisher(Command): - """Holds down 'Vanquisher's Charm' until this command is called again.""" - - def main(self): - key_up(Key.VANQUISHER) - time.sleep(0.075) - key_down(Key.VANQUISHER) - time.sleep(0.15) - - -class Kishin(Command): - """Uses 'Kishin Shoukan' once.""" - - def main(self): - press(Key.KISHIN, 4, down_time=0.1, up_time=0.15) - - -class NineTails(Command): - """Uses 'Nine-Tailed Fury' once.""" - - def main(self): - press(Key.NINE_TAILS, 3) - - -class Exorcist(Command): - """Uses 'Exorcist's Charm' once.""" - - def __init__(self, jump='False'): - super().__init__(locals()) - self.jump = settings.validate_boolean(jump) - - def main(self): - if self.jump: - press(Key.JUMP, 1, down_time=0.1, up_time=0.15) - press(Key.EXORCIST, 2, up_time=0.05) - - -class Domain(Command): - """Uses 'Spirit's Domain' once.""" - - def main(self): - press(Key.DOMAIN, 3) - - -class Legion(Command): - """Uses 'Ghost Yaksha: Great Oni Lord's Legion' once.""" - - def main(self): - press(Key.ONI_LEGION, 2, down_time=0.1) - - -class BlossomBarrier(Command): - """Places a 'Blossom Barrier' on the ground once.""" - - def main(self): - press(Key.BLOSSOM_BARRIER, 2) - - -class Yukimusume(Command): - """Uses 'Yuki-musume Shoukan' once.""" - - def main(self): - press(Key.YUKIMUSUME, 2) - - -class Balance(Command): - """Restores mana using 'Mana Balance' once.""" - - def main(self): - press(Key.MANA_BALANCE, 2) - - -class Charm(Command): - """Jumps up using 'Shikigami Charm'.""" - - def main(self): - press(Key.CHARM, 2) diff --git a/routines/cf1.csv b/routines/cf1.csv deleted file mode 100644 index beac64a3..00000000 --- a/routines/cf1.csv +++ /dev/null @@ -1,62 +0,0 @@ -$, target=move_tolerance, value=0.09 -$, target=buff_cooldown, value=185 - -@, label=kish -*, x=0.811, y=0.243, frequency=1, skip=False, adjust=False - Kishin -*, x=0.640, y=0.243, frequency=1, skip=False, adjust=True -*, x=0.415, y=0.243, frequency=1, skip=False, adjust=False - Yaksha, direction=right -*, x=0.150, y=0.243, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=3, repetitions=1 - Shikigami, direction=left, attacks=2, repetitions=1 - Shikigami, direction=right, attacks=3, repetitions=1 - -@, label=main -*, x=0.275, y=0.142, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=3, repetitions=1 - Shikigami, direction=right, attacks=3, repetitions=1 - Wait, duration=0.05 -*, x=0.275, y=0.142, frequency=1, skip=False, adjust=True - Exorcist, jump=False - Wait, duration=0.3 - Teleport, direction=up, jump=False - Shikigami, direction=right, attacks=3, repetitions=1 - Shikigami, direction=right, attacks=2, repetitions=1 - Teleport, direction=down, jump=False - Wait, duration=0.05 ->, label=boss, frequency=7, skip=True ->, label=main, frequency=1, skip=False - -@, label=boss ->, label=loot, frequency=3, skip=True -*, x=0.415, y=0.243, frequency=1, skip=False, adjust=False - Yaksha, direction=right - Charm - Teleport, direction=left, jump=False ->, label=main, frequency=1, skip=False - -@, label=loot -*, x=0.125, y=0.142, frequency=1, skip=False, adjust=False - Yaksha, direction=right - Wait, duration=0.1 - Balance -*, x=0.257, y=0.142, frequency=1, skip=False, adjust=True - Exorcist, jump=False - Tengu - Teleport, direction=up, jump=False - Shikigami, direction=left, attacks=3, repetitions=1 - Teleport, direction=right, jump=False - Shikigami, direction=right, attacks=3, repetitions=1 - Shikigami, direction=right, attacks=2, repetitions=1 - Walk, direction=right, duration=0.4 - Teleport, direction=down, jump=False -*, x=0.640, y=0.108, frequency=1, skip=False, adjust=True - Shikigami, direction=left, attacks=2, repetitions=1 - Shikigami, direction=right, attacks=2, repetitions=1 -*, x=0.640, y=0.108, frequency=1, skip=False, adjust=False - NineTails - Tengu - Wait, duration=0.2 -*, x=0.640, y=0.243, frequency=1, skip=False, adjust=False ->, label=kish, frequency=1, skip=False diff --git a/routines/dcup2.csv b/routines/dcup2.csv deleted file mode 100644 index 780c2fb4..00000000 --- a/routines/dcup2.csv +++ /dev/null @@ -1,84 +0,0 @@ -$, target=record_layout, value=True -$, target=move_tolerance, value=0.075 - -@, label=main -*, x=0.873, y=0.083, frequency=1, skip=False, adjust=False - Tengu -*, x=0.873, y=0.200, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=2, repetitions=1 - Shikigami, direction=right, attacks=2, repetitions=1 ->, label=loot, frequency=4, skip=False -*, x=0.873, y=0.200, frequency=1, skip=False, adjust=False - Fall, distance=0.02 - -@, label=afterboss -*, x=0.055, y=0.125, frequency=1, skip=False, adjust=False - Shikigami, direction=right, attacks=2, repetitions=1 -*, x=0.055, y=0.125, frequency=1, skip=False, adjust=False - Fall, distance=0.005 - Shikigami, direction=right, attacks=2, repetitions=1 - Walk, direction=left, duration=0.2 ->, label=main, frequency=1, skip=False - -@, label=loot -*, x=0.873, y=0.200, frequency=1, skip=False, adjust=False - Teleport, direction=left, jump=False - Yaksha, direction=left -*, x=0.750, y=0.200, frequency=1, skip=False, adjust=False - Teleport, direction=left, jump=False - NineTails - Tengu -*, x=0.44, y=0.199, frequency=1, skip=False, adjust=True - Balance - Shikigami, direction=right, attacks=3, repetitions=1 -*, x=0.350, y=0.200, frequency=1, skip=False, adjust=True - Kishin - Wait, duration=0.15 -*, x=0.225, y=0.200, frequency=1, skip=False, adjust=True - Walk, direction=left, duration=0.2 - Shikigami, direction=left, attacks=2, repetitions=1 -*, x=0.225, y=0.200, frequency=1, skip=False, adjust=False - Fall, distance=0.02 - Walk, direction=left, duration=0.2 - Tengu -*, x=0.660, y=0.083, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=2, repetitions=1 - Tengu -*, x=0.394, y=0.100, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=2, repetitions=1 - Tengu - Walk, direction=left, duration=0.5 -*, x=0.394, y=0.100, frequency=1, skip=False, adjust=False - Walk, direction=left, duration=0.2 ->, label=afterboss2, frequency=1, skip=False - -@, label=main2 -*, x=0.873, y=0.083, frequency=1, skip=False, adjust=False - Tengu -*, x=0.873, y=0.200, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=2, repetitions=1 - Shikigami, direction=right, attacks=2, repetitions=1 ->, label=boss2, frequency=5, skip=True -*, x=0.873, y=0.200, frequency=1, skip=False, adjust=False - Fall, distance=0.02 - Walk, direction=right, duration=0.2 - -@, label=afterboss2 -*, x=0.055, y=0.125, frequency=1, skip=False, adjust=False - Shikigami, direction=right, attacks=2, repetitions=1 -*, x=0.055, y=0.125, frequency=1, skip=False, adjust=False - Fall, distance=0.005 - Shikigami, direction=right, attacks=2, repetitions=1 - Walk, direction=left, duration=0.2 ->, label=main2, frequency=1, skip=False - -@, label=boss2 -*, x=0.873, y=0.200, frequency=1, skip=False, adjust=False - Teleport, direction=left, jump=False - Yaksha, direction=left -*, x=0.750, y=0.200, frequency=3, skip=True, adjust=False - Fall, distance=0.02 ->, label=afterboss, frequency=3, skip=True -*, x=0.750, y=0.200, frequency=1, skip=False, adjust=False - Fall, distance=0.02 ->, label=afterboss2, frequency=1, skip=False diff --git a/routines/mts3.csv b/routines/mts3.csv deleted file mode 100644 index 5455821e..00000000 --- a/routines/mts3.csv +++ /dev/null @@ -1,217 +0,0 @@ -s, adjust_tolerance, 0.0125 - - - -@, loot_no_domain -*, 0.120, 0.303, adjust=True - shikigami, direction=right - yukimusume -*, 0.138, 0.414 - shikigami, direction=right -*, 0.336, 0.414 - legion -*, 0.461, 0.414 - ninetails -*, 0.737, 0.414 - kishin -*, 0.868, 0.414, adjust=True -*, 0.685, 0.414, adjust=True - teleport, direction=up -*, 0.750, 0.303 - walk, right, 0.15 -*, 0.865, 0.303, adjust=True - shikigami, direction=left, attacks=3 - wait, 0.1 -*, 0.865, 0.138 - shikigami, direction=left - walk, left, 0.3 -*, 0.645, 0.138, adjust=True - wait, 0.1 - teleport, direction=down -*, 0.539, 0.237 - yaksha, direction=right -*, 0.468, 0.237, adjust=True - exorcist - wait, 0.3 - teleport, direction=left -*, 0.315, 0.151, adjust=True - teleport, direction=down -*, 0.283, 0.303 - legion -*, 0.283, 0.303 - goto, main1 - -@, main1 -*, 0.283, 0.303, adjust=True - shikigami, direction=left - shikigami, direction=right, attacks=3 -*, 0.283, 0.303 - wait, 0.2 - exorcist - teleport, direction=up - wait, 0.3 - shikigami, direction=right, attacks=3 - teleport, direction=down -*, 0.460, 0.342, frequency=4, counter=1 - shikigami, direction=right -*, 0.500, 0.342, frequency=4, counter=1 - goto, boss1 -*, 0.283, 0.303 - teleport, direction=right - shikigami, direction=right -*, 0.283, 0.303 - goto, main1 - -@, main2 -*, 0.283, 0.303, adjust=True - shikigami, direction=left - shikigami, direction=right, attacks=3 -*, 0.283, 0.303 - wait, 0.2 - exorcist - teleport, direction=up - wait, 0.3 - shikigami, direction=right, attacks=3 - teleport, direction=down -*, 0.460, 0.342, frequency=5, counter=1 - shikigami, direction=right -*, 0.500, 0.342, frequency=5, counter=1 - goto, boss2 -*, 0.283, 0.303 - teleport, direction=right - shikigami, direction=right -*, 0.283, 0.303 - goto, main2 - -@, boss1 -*, 0.539, 0.237 - yaksha, direction=right -*, 0.510, 0.237 - teleport, direction=down -*, 0.530, 0.342 - shikigami, direction=left -*, 0.500, 0.342, frequency=3, counter=1 - goto, main2 -*, 0.500, 0.342 - goto, main1 - -@, boss2 -*, 0.539, 0.237 - yaksha, direction=right -*, 0.510, 0.237 - teleport, direction=down -*, 0.530, 0.342 - shikigami, direction=left -*, 0.500, 0.342 - goto, loot_with_domain - - - -@, loot_with_domain -*, 0.120, 0.303, adjust=True - shikigami, direction=right - yukimusume -*, 0.138, 0.414 - shikigami, direction=right -*, 0.336, 0.414, adjust=True - domain -*, 0.461, 0.414 - ninetails -*, 0.737, 0.414 - kishin -*, 0.868, 0.414, adjust=True -*, 0.685, 0.414, adjust=True - teleport, direction=up -*, 0.750, 0.303 - walk, right, 0.15 -*, 0.865, 0.303, adjust=True - shikigami, direction=left, attacks=3 - wait, 0.1 -*, 0.865, 0.138 - shikigami, direction=left - walk, left, 0.3 -*, 0.645, 0.138, adjust=True - wait, 0.1 - teleport, direction=down -*, 0.539, 0.237 - vanquisher -*, 0.480, 0.237, adjust=True -*, 0.580, 0.237, adjust=True - walk, left, 0.15 - walk, right, 0.1 - walk, left, 0.1 - walk, right, 0.1 - walk, left, 0.15 - walk, right, 0.1 - walk, left, 0.1 - walk, right, 0.1 - walk, left, 0.15 - walk, right, 0.1 - walk, left, 0.1 - walk, right, 0.1 - walk, left, 0.15 - walk, right, 0.1 - walk, left, 0.1 - walk, right, 0.1 -*, 0.600, 0.237, adjust=True - vanquisher - wait, 0.15 - exorcist - wait, 0.3 - teleport, direction=right -*, 0.715, 0.138 - goto, main3 - -@, main3 -*, 0.715, 0.138 - shikigami, direction=left, attacks=3 - wait, 0.15 - shikigami, direction=right, attacks=3 -*, 0.715, 0.138, adjust=True - teleport, direction=down -*, 0.715, 0.303 - shikigami, direction=left, attacks=3 - wait, 0.15 - shikigami, direction=right, attacks=3 - wait, 0.1 -*, 0.715, 0.303, frequency=3, adjust=True - exorcist - wait, 0.3 -*, 0.715, 0.303, frequency=12, counter=1 - teleport, direction=left, jump=True - goto, boss3 -*, 0.715, 0.303 - goto, main3 - -@, boss3 -*, 0.539, 0.237 - yaksha, direction=right -*, 0.510, 0.237 - teleport, direction=down -*, 0.530, 0.342 - shikigami, direction=left -*, 0.500, 0.342, frequency=2, counter=1 - goto, loot_no_domain -*, 0.500, 0.342 - goto, main4 - -@, main4 -*, 0.283, 0.303, adjust=True - shikigami, direction=left - shikigami, direction=right, attacks=3 -*, 0.283, 0.303 - wait, 0.2 - exorcist - teleport, direction=up - wait, 0.3 - shikigami, direction=right, attacks=3 - teleport, direction=down -*, 0.460, 0.342, frequency=5, counter=1 - shikigami, direction=right -*, 0.500, 0.342, frequency=5, counter=1 - goto, boss3 -*, 0.283, 0.303 - teleport, direction=right - shikigami, direction=right -*, 0.283, 0.303 - goto, main4 diff --git a/routines/os3.csv b/routines/os3.csv deleted file mode 100644 index 3d7340d9..00000000 --- a/routines/os3.csv +++ /dev/null @@ -1,100 +0,0 @@ -$, target=move_tolerance, value=0.075 -*, x=0.49, y=0.16, frequency=1, skip=False, adjust=True - Yaksha, direction=left - -@, label=kishin -*, x=0.360, y=0.257, frequency=1, skip=False, adjust=False - Kishin -*, x=0.543, y=0.257, frequency=1, skip=False, adjust=False - Shikigami, direction=right, attacks=2, repetitions=1 -*, x=0.754, y=0.257, frequency=1, skip=False, adjust=True - Shikigami, direction=right, attacks=2, repetitions=1 - -@, label=main1 -*, x=0.754, y=0.183, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=3, repetitions=1 - Shikigami, direction=right, attacks=3, repetitions=1 - Exorcist, jump=False - Wait, duration=0.4 - Teleport, direction=up, jump=False -*, x=0.754, y=0.097, frequency=2, skip=False, adjust=False - Shikigami, direction=left, attacks=3, repetitions=1 - Shikigami, direction=right, attacks=2, repetitions=1 -*, x=0.754, y=0.097, frequency=2, skip=False, adjust=True - Teleport, direction=down, jump=False -*, x=0.754, y=0.097, frequency=2, skip=True, adjust=False - Shikigami, direction=right, attacks=3, repetitions=1 - Shikigami, direction=left, attacks=2, repetitions=1 -*, x=0.754, y=0.097, frequency=2, skip=True, adjust=True - Teleport, direction=down, jump=False ->, label=boss1, frequency=5, skip=True ->, label=main1, frequency=1, skip=False - -@, label=boss1 -*, x=0.49, y=0.16, frequency=1, skip=False, adjust=True - Yaksha, direction=left ->, label=loot_domain, frequency=3, skip=True ->, label=main1, frequency=1, skip=False - -@, label=loot_domain -*, x=0.754, y=0.183, frequency=1, skip=False, adjust=False - Exorcist, jump=False - Wait, duration=0.6 -*, x=0.754, y=0.257, frequency=1, skip=False, adjust=True - Domain -*, x=0.846, y=0.257, frequency=1, skip=False, adjust=False - Shikigami, direction=right, attacks=3, repetitions=1 -*, x=0.869, y=0.177, frequency=1, skip=False, adjust=False - Shikigami, direction=right, attacks=3, repetitions=1 - Shikigami, direction=right, attacks=2, repetitions=1 -*, x=0.846, y=0.097, frequency=1, skip=False, adjust=False - Shikigami, direction=right, attacks=3, repetitions=1 - Shikigami, direction=left, attacks=2, repetitions=1 -*, x=0.650, y=0.097, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=3, repetitions=1 -*, x=0.474, y=0.063, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=3, repetitions=1 -*, x=0.280, y=0.080, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=3, repetitions=1 - Shikigami, direction=left, attacks=2, repetitions=1 - Teleport, direction=down, jump=False -*, x=0.28, y=0.16, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=2, repetitions=1 -*, x=0.46, y=0.16, frequency=1, skip=False, adjust=True - Yaksha, direction=right - Teleport, direction=down, jump=False -*, x=0.36, y=0.257, frequency=1, skip=False, adjust=False - Kishin -*, x=0.25, y=0.257, frequency=1, skip=False, adjust=True - Shikigami, direction=left, attacks=3, repetitions=1 - Teleport, direction=up, jump=False - -@, label=main2 -*, x=0.297, y=0.16, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=3, repetitions=1 - Shikigami, direction=right, attacks=3, repetitions=1 -*, x=0.297, y=0.16, frequency=1, skip=False, adjust=True - Teleport, direction=up, jump=False - Shikigami, direction=left, attacks=3, repetitions=1 - Shikigami, direction=left, attacks=2, repetitions=1 - Teleport, direction=down, jump=False ->, label=boss2, frequency=5, skip=True ->, label=main2, frequency=1, skip=False - -@, label=boss2 ->, label=loot_no_domain, frequency=2, skip=True -*, x=0.45, y=0.16, frequency=1, skip=False, adjust=False - Yaksha, direction=right ->, label=main2, frequency=1, skip=False - -@, label=loot_no_domain -*, x=0.49, y=0.160, frequency=1, skip=False, adjust=True - Yaksha, direction=left -*, x=0.486, y=0.063, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=2, repetitions=1 -*, x=0.280, y=0.080, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=2, repetitions=1 -*, x=0.28, y=0.257, frequency=1, skip=False, adjust=False -*, x=0.183, y=0.257, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=3, repetitions=1 ->, label=kishin, frequency=1, skip=False From 103306ec11b2d6791505400ce48a455845260357 Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Thu, 26 May 2022 17:16:22 -0700 Subject: [PATCH 19/28] moved resources into its own folder --- .gitignore | 3 +- command_books/blaster.py | 170 ++++++++++++++++++ command_books/kanna.py | 295 ++++++++++++++++++++++++++++++++ routines/cf1.csv | 62 +++++++ routines/dcup2.csv | 84 +++++++++ routines/mts3.csv | 217 +++++++++++++++++++++++ routines/os3.csv | 100 +++++++++++ src/gui_components/menu/main.py | 12 +- src/modules/bot.py | 2 +- 9 files changed, 938 insertions(+), 7 deletions(-) create mode 100644 command_books/blaster.py create mode 100644 command_books/kanna.py create mode 100644 routines/cf1.csv create mode 100644 routines/dcup2.csv create mode 100644 routines/mts3.csv create mode 100644 routines/os3.csv diff --git a/.gitignore b/.gitignore index b8be820f..050056e0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ __pycache__/ assets/models/ -command_books/* -routines/* +resources/ .idea/ .settings/ diff --git a/command_books/blaster.py b/command_books/blaster.py new file mode 100644 index 00000000..482f71a1 --- /dev/null +++ b/command_books/blaster.py @@ -0,0 +1,170 @@ +"""A collection of all commands that a Blaster can use to interact with the game.""" + +import time +from src.common import settings +from src.routine.components import Command +from src.common.vkeys import press, key_down, key_up + +# +# class Move(Command): +# """Moves to a given position using the shortest path based on the current Layout.""" +# +# def __init__(self, x, y, max_steps=15): +# super().__init__(locals()) +# self.target = (float(x), float(y)) +# self.max_steps = settings.validate_nonnegative_int(max_steps) +# +# def main(self): +# counter = self.max_steps +# path = config.layout.shortest_path(config.player_pos, self.target) +# # config.path = path.copy() +# # config.path.insert(0, config.player_pos) +# for point in path: +# counter = self._step(point, counter) +# +# @utils.run_if_enabled +# def _step(self, target, counter): +# toggle = True +# local_error = utils.distance(config.player_pos, target) +# global_error = utils.distance(config.player_pos, self.target) +# while config.enabled and \ +# counter > 0 and \ +# local_error > settings.move_tolerance and \ +# global_error > settings.move_tolerance: +# if toggle: +# d_x = target[0] - config.player_pos[0] +# if abs(d_x) > settings.move_tolerance / math.sqrt(2): +# if d_x < 0: +# Jump('left').main() +# else: +# Jump('right').main() +# counter -= 1 +# else: +# d_y = target[1] - config.player_pos[1] +# if abs(d_y) > settings.move_tolerance / math.sqrt(2): +# if d_y < 0: +# Jump('up').main() +# else: +# Jump('down').main() +# counter -= 1 +# local_error = utils.distance(config.player_pos, target) +# global_error = utils.distance(config.player_pos, self.target) +# toggle = not toggle +# return counter +# +# +# class Adjust(Command): +# """Fine-tunes player position using small movements.""" +# +# def __init__(self, x, y, max_steps=5): +# super().__init__(locals()) +# self.target = (float(x), float(y)) +# self.max_steps = settings.validate_nonnegative_int(max_steps) +# +# def main(self): +# counter = self.max_steps +# toggle = True +# error = utils.distance(config.player_pos, self.target) +# while config.enabled and counter > 0 and error > settings.adjust_tolerance: +# if toggle: +# d_x = self.target[0] - config.player_pos[0] +# threshold = settings.adjust_tolerance / math.sqrt(2) +# if abs(d_x) > threshold: +# walk_counter = 0 +# if d_x < 0: +# key_down('left') +# while config.enabled and d_x < -1 * threshold and walk_counter < 60: +# time.sleep(0.05) +# walk_counter += 1 +# d_x = self.target[0] - config.player_pos[0] +# key_up('left') +# else: +# key_down('right') +# while config.enabled and d_x > threshold and walk_counter < 60: +# time.sleep(0.05) +# walk_counter += 1 +# d_x = self.target[0] - config.player_pos[0] +# key_up('right') +# counter -= 1 +# else: +# d_y = self.target[1] - config.player_pos[1] +# if abs(d_y) > settings.adjust_tolerance / math.sqrt(2): +# if d_y < 0: +# Jump('up').main() +# else: +# key_down('down') +# time.sleep(0.05) +# press('space', 3, down_time=0.1) +# key_up('down') +# time.sleep(0.05) +# counter -= 1 +# error = utils.distance(config.player_pos, self.target) +# toggle = not toggle +# +# +# def step(direction, target): +# print('blaster step test') + + +class Buff(Command): + """Uses each of Blaster's buffs once.""" + + def __init__(self): + super().__init__(locals()) + self.booster_time = 0 + self.warrior_time = 0 + + def main(self): + now = time.time() + if self.booster_time == 0 or now - self.booster_time > 190: + press('f1', 2) + self.booster_time = now + if self.warrior_time == 0 or now - self.warrior_time > 890: + press('f2', 2) + self.warrior_time = now + + +class Jump(Command): + """Performs a flash jump or 'Detonate' in the given direction.""" + + def __init__(self, direction): + super().__init__(locals()) + self.direction = settings.validate_arrows(direction) + + def main(self): + key_down(self.direction) + time.sleep(0.1) + press('space', 1) + if self.direction == 'up': + press('d', 1) + else: + press('space', 1) + key_up(self.direction) + time.sleep(0.5) + + +class MagnumPunch(Command): + """Performs a 'No-Reload Magnum Punch' combo once.""" + + def __init__(self, direction): + super().__init__(locals()) + self.direction = settings.validate_arrows(direction) + + def main(self): + key_down(self.direction) + time.sleep(0.05) + key_down('q') + time.sleep(0.1) + for _ in range(3): + key_down('r') + time.sleep(0.05) + key_down('e') + time.sleep(0.05) + key_up('r') + key_up('e') + time.sleep(0.05) + key_up('q') + time.sleep(0.025) + press('space', 1) + key_up(self.direction) + time.sleep(0.05) diff --git a/command_books/kanna.py b/command_books/kanna.py new file mode 100644 index 00000000..62e274f5 --- /dev/null +++ b/command_books/kanna.py @@ -0,0 +1,295 @@ +"""A collection of all commands that a Kanna can use to interact with the game.""" + +from src.common import config, settings, utils +import time +import math +from src.routine.components import Command +from src.common.vkeys import press, key_down, key_up + + +# List of key mappings +class Key: + # Movement + JUMP = 'space' + TELEPORT = 'e' + CHARM = 'd' + + # Buffs + HAKU = 'f4' + AKATSUKI_WARRIOR = 'f3' + HOLY_SYMBOL = 'f2' + SPEED_INFUSION = 'f1' + + # Skills + SHIKIGAMI = 'r' + TENGU = 'q' + YAKSHA = '2' + VANQUISHER = 'f' + KISHIN = 'ctrl' + NINE_TAILS = '3' + EXORCIST = 'w' + DOMAIN = 'z' + ONI_LEGION = '5' + BLOSSOM_BARRIER = 'g' + YUKIMUSUME = 'c' + MANA_BALANCE = 'lshift' + + +######################### +# Commands # +######################### +def step(direction, target): + """ + Performs one movement step in the given DIRECTION towards TARGET. + Should not press any arrow keys, as those are handled by Auto Maple. + """ + + num_presses = 2 + if direction == 'up' or direction == 'down': + num_presses = 1 + if config.stage_fright and direction != 'up' and utils.bernoulli(0.75): + time.sleep(utils.rand_float(0.1, 0.3)) + d_y = target[1] - config.player_pos[1] + if abs(d_y) > settings.move_tolerance * 1.5: + if direction == 'down': + press(Key.JUMP, 3) + elif direction == 'up': + press(Key.JUMP, 1) + press(Key.TELEPORT, num_presses) + + +class Adjust(Command): + """Fine-tunes player position using small movements.""" + + def __init__(self, x, y, max_steps=5): + super().__init__(locals()) + self.target = (float(x), float(y)) + self.max_steps = settings.validate_nonnegative_int(max_steps) + + def main(self): + counter = self.max_steps + toggle = True + error = utils.distance(config.player_pos, self.target) + while config.enabled and counter > 0 and error > settings.adjust_tolerance: + if toggle: + d_x = self.target[0] - config.player_pos[0] + threshold = settings.adjust_tolerance / math.sqrt(2) + if abs(d_x) > threshold: + walk_counter = 0 + if d_x < 0: + key_down('left') + while config.enabled and d_x < -1 * threshold and walk_counter < 60: + time.sleep(0.05) + walk_counter += 1 + d_x = self.target[0] - config.player_pos[0] + key_up('left') + else: + key_down('right') + while config.enabled and d_x > threshold and walk_counter < 60: + time.sleep(0.05) + walk_counter += 1 + d_x = self.target[0] - config.player_pos[0] + key_up('right') + counter -= 1 + else: + d_y = self.target[1] - config.player_pos[1] + if abs(d_y) > settings.adjust_tolerance / math.sqrt(2): + if d_y < 0: + Teleport('up').main() + else: + key_down('down') + time.sleep(0.05) + press(Key.JUMP, 3, down_time=0.1) + key_up('down') + time.sleep(0.05) + counter -= 1 + error = utils.distance(config.player_pos, self.target) + toggle = not toggle + + +class Buff(Command): + """Uses each of Kanna's buffs once. Uses 'Haku Reborn' whenever it is available.""" + + def __init__(self): + super().__init__(locals()) + self.haku_time = 0 + self.buff_time = 0 + + def main(self): + buffs = [Key.SPEED_INFUSION, Key.HOLY_SYMBOL] + now = time.time() + if self.haku_time == 0 or now - self.haku_time > 490: + press(Key.HAKU, 2) + press(Key.AKATSUKI_WARRIOR, 2) + self.haku_time = now + if self.buff_time == 0 or now - self.buff_time > settings.buff_cooldown: + for key in buffs: + press(key, 3, up_time=0.3) + self.buff_time = now + + +class Teleport(Command): + """ + Teleports in a given direction, jumping if specified. Adds the player's position + to the current Layout if necessary. + """ + + def __init__(self, direction, jump='False'): + super().__init__(locals()) + self.direction = settings.validate_arrows(direction) + self.jump = settings.validate_boolean(jump) + + def main(self): + num_presses = 3 + time.sleep(0.05) + if self.direction in ['up', 'down']: + num_presses = 2 + if self.direction != 'up': + key_down(self.direction) + time.sleep(0.05) + if self.jump: + if self.direction == 'down': + press(Key.JUMP, 3, down_time=0.1) + else: + press(Key.JUMP, 1) + if self.direction == 'up': + key_down(self.direction) + time.sleep(0.05) + press(Key.TELEPORT, num_presses) + key_up(self.direction) + if settings.record_layout: + config.layout.add(*config.player_pos) + + +class Shikigami(Command): + """Attacks using 'Shikigami Haunting' in a given direction.""" + + def __init__(self, direction, attacks=2, repetitions=1): + super().__init__(locals()) + self.direction = settings.validate_horizontal_arrows(direction) + self.attacks = int(attacks) + self.repetitions = int(repetitions) + + def main(self): + time.sleep(0.05) + key_down(self.direction) + time.sleep(0.05) + if config.stage_fright and utils.bernoulli(0.7): + time.sleep(utils.rand_float(0.1, 0.3)) + for _ in range(self.repetitions): + press(Key.SHIKIGAMI, self.attacks, up_time=0.05) + key_up(self.direction) + if self.attacks > 2: + time.sleep(0.3) + else: + time.sleep(0.2) + + +class Tengu(Command): + """Uses 'Tengu Strike' once.""" + + def main(self): + press(Key.TENGU, 1, up_time=0.05) + + +class Yaksha(Command): + """ + Places 'Ghost Yaksha Boss' in a given direction, or towards the center of the map if + no direction is specified. + """ + + def __init__(self, direction=None): + super().__init__(locals()) + if direction is None: + self.direction = direction + else: + self.direction = settings.validate_horizontal_arrows(direction) + + def main(self): + if self.direction: + press(self.direction, 1, down_time=0.1, up_time=0.05) + else: + if config.player_pos[0] > 0.5: + press('left', 1, down_time=0.1, up_time=0.05) + else: + press('right', 1, down_time=0.1, up_time=0.05) + press(Key.YAKSHA, 3) + + +class Vanquisher(Command): + """Holds down 'Vanquisher's Charm' until this command is called again.""" + + def main(self): + key_up(Key.VANQUISHER) + time.sleep(0.075) + key_down(Key.VANQUISHER) + time.sleep(0.15) + + +class Kishin(Command): + """Uses 'Kishin Shoukan' once.""" + + def main(self): + press(Key.KISHIN, 4, down_time=0.1, up_time=0.15) + + +class NineTails(Command): + """Uses 'Nine-Tailed Fury' once.""" + + def main(self): + press(Key.NINE_TAILS, 3) + + +class Exorcist(Command): + """Uses 'Exorcist's Charm' once.""" + + def __init__(self, jump='False'): + super().__init__(locals()) + self.jump = settings.validate_boolean(jump) + + def main(self): + if self.jump: + press(Key.JUMP, 1, down_time=0.1, up_time=0.15) + press(Key.EXORCIST, 2, up_time=0.05) + + +class Domain(Command): + """Uses 'Spirit's Domain' once.""" + + def main(self): + press(Key.DOMAIN, 3) + + +class Legion(Command): + """Uses 'Ghost Yaksha: Great Oni Lord's Legion' once.""" + + def main(self): + press(Key.ONI_LEGION, 2, down_time=0.1) + + +class BlossomBarrier(Command): + """Places a 'Blossom Barrier' on the ground once.""" + + def main(self): + press(Key.BLOSSOM_BARRIER, 2) + + +class Yukimusume(Command): + """Uses 'Yuki-musume Shoukan' once.""" + + def main(self): + press(Key.YUKIMUSUME, 2) + + +class Balance(Command): + """Restores mana using 'Mana Balance' once.""" + + def main(self): + press(Key.MANA_BALANCE, 2) + + +class Charm(Command): + """Jumps up using 'Shikigami Charm'.""" + + def main(self): + press(Key.CHARM, 2) diff --git a/routines/cf1.csv b/routines/cf1.csv new file mode 100644 index 00000000..beac64a3 --- /dev/null +++ b/routines/cf1.csv @@ -0,0 +1,62 @@ +$, target=move_tolerance, value=0.09 +$, target=buff_cooldown, value=185 + +@, label=kish +*, x=0.811, y=0.243, frequency=1, skip=False, adjust=False + Kishin +*, x=0.640, y=0.243, frequency=1, skip=False, adjust=True +*, x=0.415, y=0.243, frequency=1, skip=False, adjust=False + Yaksha, direction=right +*, x=0.150, y=0.243, frequency=1, skip=False, adjust=False + Shikigami, direction=left, attacks=3, repetitions=1 + Shikigami, direction=left, attacks=2, repetitions=1 + Shikigami, direction=right, attacks=3, repetitions=1 + +@, label=main +*, x=0.275, y=0.142, frequency=1, skip=False, adjust=False + Shikigami, direction=left, attacks=3, repetitions=1 + Shikigami, direction=right, attacks=3, repetitions=1 + Wait, duration=0.05 +*, x=0.275, y=0.142, frequency=1, skip=False, adjust=True + Exorcist, jump=False + Wait, duration=0.3 + Teleport, direction=up, jump=False + Shikigami, direction=right, attacks=3, repetitions=1 + Shikigami, direction=right, attacks=2, repetitions=1 + Teleport, direction=down, jump=False + Wait, duration=0.05 +>, label=boss, frequency=7, skip=True +>, label=main, frequency=1, skip=False + +@, label=boss +>, label=loot, frequency=3, skip=True +*, x=0.415, y=0.243, frequency=1, skip=False, adjust=False + Yaksha, direction=right + Charm + Teleport, direction=left, jump=False +>, label=main, frequency=1, skip=False + +@, label=loot +*, x=0.125, y=0.142, frequency=1, skip=False, adjust=False + Yaksha, direction=right + Wait, duration=0.1 + Balance +*, x=0.257, y=0.142, frequency=1, skip=False, adjust=True + Exorcist, jump=False + Tengu + Teleport, direction=up, jump=False + Shikigami, direction=left, attacks=3, repetitions=1 + Teleport, direction=right, jump=False + Shikigami, direction=right, attacks=3, repetitions=1 + Shikigami, direction=right, attacks=2, repetitions=1 + Walk, direction=right, duration=0.4 + Teleport, direction=down, jump=False +*, x=0.640, y=0.108, frequency=1, skip=False, adjust=True + Shikigami, direction=left, attacks=2, repetitions=1 + Shikigami, direction=right, attacks=2, repetitions=1 +*, x=0.640, y=0.108, frequency=1, skip=False, adjust=False + NineTails + Tengu + Wait, duration=0.2 +*, x=0.640, y=0.243, frequency=1, skip=False, adjust=False +>, label=kish, frequency=1, skip=False diff --git a/routines/dcup2.csv b/routines/dcup2.csv new file mode 100644 index 00000000..780c2fb4 --- /dev/null +++ b/routines/dcup2.csv @@ -0,0 +1,84 @@ +$, target=record_layout, value=True +$, target=move_tolerance, value=0.075 + +@, label=main +*, x=0.873, y=0.083, frequency=1, skip=False, adjust=False + Tengu +*, x=0.873, y=0.200, frequency=1, skip=False, adjust=False + Shikigami, direction=left, attacks=2, repetitions=1 + Shikigami, direction=right, attacks=2, repetitions=1 +>, label=loot, frequency=4, skip=False +*, x=0.873, y=0.200, frequency=1, skip=False, adjust=False + Fall, distance=0.02 + +@, label=afterboss +*, x=0.055, y=0.125, frequency=1, skip=False, adjust=False + Shikigami, direction=right, attacks=2, repetitions=1 +*, x=0.055, y=0.125, frequency=1, skip=False, adjust=False + Fall, distance=0.005 + Shikigami, direction=right, attacks=2, repetitions=1 + Walk, direction=left, duration=0.2 +>, label=main, frequency=1, skip=False + +@, label=loot +*, x=0.873, y=0.200, frequency=1, skip=False, adjust=False + Teleport, direction=left, jump=False + Yaksha, direction=left +*, x=0.750, y=0.200, frequency=1, skip=False, adjust=False + Teleport, direction=left, jump=False + NineTails + Tengu +*, x=0.44, y=0.199, frequency=1, skip=False, adjust=True + Balance + Shikigami, direction=right, attacks=3, repetitions=1 +*, x=0.350, y=0.200, frequency=1, skip=False, adjust=True + Kishin + Wait, duration=0.15 +*, x=0.225, y=0.200, frequency=1, skip=False, adjust=True + Walk, direction=left, duration=0.2 + Shikigami, direction=left, attacks=2, repetitions=1 +*, x=0.225, y=0.200, frequency=1, skip=False, adjust=False + Fall, distance=0.02 + Walk, direction=left, duration=0.2 + Tengu +*, x=0.660, y=0.083, frequency=1, skip=False, adjust=False + Shikigami, direction=left, attacks=2, repetitions=1 + Tengu +*, x=0.394, y=0.100, frequency=1, skip=False, adjust=False + Shikigami, direction=left, attacks=2, repetitions=1 + Tengu + Walk, direction=left, duration=0.5 +*, x=0.394, y=0.100, frequency=1, skip=False, adjust=False + Walk, direction=left, duration=0.2 +>, label=afterboss2, frequency=1, skip=False + +@, label=main2 +*, x=0.873, y=0.083, frequency=1, skip=False, adjust=False + Tengu +*, x=0.873, y=0.200, frequency=1, skip=False, adjust=False + Shikigami, direction=left, attacks=2, repetitions=1 + Shikigami, direction=right, attacks=2, repetitions=1 +>, label=boss2, frequency=5, skip=True +*, x=0.873, y=0.200, frequency=1, skip=False, adjust=False + Fall, distance=0.02 + Walk, direction=right, duration=0.2 + +@, label=afterboss2 +*, x=0.055, y=0.125, frequency=1, skip=False, adjust=False + Shikigami, direction=right, attacks=2, repetitions=1 +*, x=0.055, y=0.125, frequency=1, skip=False, adjust=False + Fall, distance=0.005 + Shikigami, direction=right, attacks=2, repetitions=1 + Walk, direction=left, duration=0.2 +>, label=main2, frequency=1, skip=False + +@, label=boss2 +*, x=0.873, y=0.200, frequency=1, skip=False, adjust=False + Teleport, direction=left, jump=False + Yaksha, direction=left +*, x=0.750, y=0.200, frequency=3, skip=True, adjust=False + Fall, distance=0.02 +>, label=afterboss, frequency=3, skip=True +*, x=0.750, y=0.200, frequency=1, skip=False, adjust=False + Fall, distance=0.02 +>, label=afterboss2, frequency=1, skip=False diff --git a/routines/mts3.csv b/routines/mts3.csv new file mode 100644 index 00000000..5455821e --- /dev/null +++ b/routines/mts3.csv @@ -0,0 +1,217 @@ +s, adjust_tolerance, 0.0125 + + + +@, loot_no_domain +*, 0.120, 0.303, adjust=True + shikigami, direction=right + yukimusume +*, 0.138, 0.414 + shikigami, direction=right +*, 0.336, 0.414 + legion +*, 0.461, 0.414 + ninetails +*, 0.737, 0.414 + kishin +*, 0.868, 0.414, adjust=True +*, 0.685, 0.414, adjust=True + teleport, direction=up +*, 0.750, 0.303 + walk, right, 0.15 +*, 0.865, 0.303, adjust=True + shikigami, direction=left, attacks=3 + wait, 0.1 +*, 0.865, 0.138 + shikigami, direction=left + walk, left, 0.3 +*, 0.645, 0.138, adjust=True + wait, 0.1 + teleport, direction=down +*, 0.539, 0.237 + yaksha, direction=right +*, 0.468, 0.237, adjust=True + exorcist + wait, 0.3 + teleport, direction=left +*, 0.315, 0.151, adjust=True + teleport, direction=down +*, 0.283, 0.303 + legion +*, 0.283, 0.303 + goto, main1 + +@, main1 +*, 0.283, 0.303, adjust=True + shikigami, direction=left + shikigami, direction=right, attacks=3 +*, 0.283, 0.303 + wait, 0.2 + exorcist + teleport, direction=up + wait, 0.3 + shikigami, direction=right, attacks=3 + teleport, direction=down +*, 0.460, 0.342, frequency=4, counter=1 + shikigami, direction=right +*, 0.500, 0.342, frequency=4, counter=1 + goto, boss1 +*, 0.283, 0.303 + teleport, direction=right + shikigami, direction=right +*, 0.283, 0.303 + goto, main1 + +@, main2 +*, 0.283, 0.303, adjust=True + shikigami, direction=left + shikigami, direction=right, attacks=3 +*, 0.283, 0.303 + wait, 0.2 + exorcist + teleport, direction=up + wait, 0.3 + shikigami, direction=right, attacks=3 + teleport, direction=down +*, 0.460, 0.342, frequency=5, counter=1 + shikigami, direction=right +*, 0.500, 0.342, frequency=5, counter=1 + goto, boss2 +*, 0.283, 0.303 + teleport, direction=right + shikigami, direction=right +*, 0.283, 0.303 + goto, main2 + +@, boss1 +*, 0.539, 0.237 + yaksha, direction=right +*, 0.510, 0.237 + teleport, direction=down +*, 0.530, 0.342 + shikigami, direction=left +*, 0.500, 0.342, frequency=3, counter=1 + goto, main2 +*, 0.500, 0.342 + goto, main1 + +@, boss2 +*, 0.539, 0.237 + yaksha, direction=right +*, 0.510, 0.237 + teleport, direction=down +*, 0.530, 0.342 + shikigami, direction=left +*, 0.500, 0.342 + goto, loot_with_domain + + + +@, loot_with_domain +*, 0.120, 0.303, adjust=True + shikigami, direction=right + yukimusume +*, 0.138, 0.414 + shikigami, direction=right +*, 0.336, 0.414, adjust=True + domain +*, 0.461, 0.414 + ninetails +*, 0.737, 0.414 + kishin +*, 0.868, 0.414, adjust=True +*, 0.685, 0.414, adjust=True + teleport, direction=up +*, 0.750, 0.303 + walk, right, 0.15 +*, 0.865, 0.303, adjust=True + shikigami, direction=left, attacks=3 + wait, 0.1 +*, 0.865, 0.138 + shikigami, direction=left + walk, left, 0.3 +*, 0.645, 0.138, adjust=True + wait, 0.1 + teleport, direction=down +*, 0.539, 0.237 + vanquisher +*, 0.480, 0.237, adjust=True +*, 0.580, 0.237, adjust=True + walk, left, 0.15 + walk, right, 0.1 + walk, left, 0.1 + walk, right, 0.1 + walk, left, 0.15 + walk, right, 0.1 + walk, left, 0.1 + walk, right, 0.1 + walk, left, 0.15 + walk, right, 0.1 + walk, left, 0.1 + walk, right, 0.1 + walk, left, 0.15 + walk, right, 0.1 + walk, left, 0.1 + walk, right, 0.1 +*, 0.600, 0.237, adjust=True + vanquisher + wait, 0.15 + exorcist + wait, 0.3 + teleport, direction=right +*, 0.715, 0.138 + goto, main3 + +@, main3 +*, 0.715, 0.138 + shikigami, direction=left, attacks=3 + wait, 0.15 + shikigami, direction=right, attacks=3 +*, 0.715, 0.138, adjust=True + teleport, direction=down +*, 0.715, 0.303 + shikigami, direction=left, attacks=3 + wait, 0.15 + shikigami, direction=right, attacks=3 + wait, 0.1 +*, 0.715, 0.303, frequency=3, adjust=True + exorcist + wait, 0.3 +*, 0.715, 0.303, frequency=12, counter=1 + teleport, direction=left, jump=True + goto, boss3 +*, 0.715, 0.303 + goto, main3 + +@, boss3 +*, 0.539, 0.237 + yaksha, direction=right +*, 0.510, 0.237 + teleport, direction=down +*, 0.530, 0.342 + shikigami, direction=left +*, 0.500, 0.342, frequency=2, counter=1 + goto, loot_no_domain +*, 0.500, 0.342 + goto, main4 + +@, main4 +*, 0.283, 0.303, adjust=True + shikigami, direction=left + shikigami, direction=right, attacks=3 +*, 0.283, 0.303 + wait, 0.2 + exorcist + teleport, direction=up + wait, 0.3 + shikigami, direction=right, attacks=3 + teleport, direction=down +*, 0.460, 0.342, frequency=5, counter=1 + shikigami, direction=right +*, 0.500, 0.342, frequency=5, counter=1 + goto, boss3 +*, 0.283, 0.303 + teleport, direction=right + shikigami, direction=right +*, 0.283, 0.303 + goto, main4 diff --git a/routines/os3.csv b/routines/os3.csv new file mode 100644 index 00000000..3d7340d9 --- /dev/null +++ b/routines/os3.csv @@ -0,0 +1,100 @@ +$, target=move_tolerance, value=0.075 +*, x=0.49, y=0.16, frequency=1, skip=False, adjust=True + Yaksha, direction=left + +@, label=kishin +*, x=0.360, y=0.257, frequency=1, skip=False, adjust=False + Kishin +*, x=0.543, y=0.257, frequency=1, skip=False, adjust=False + Shikigami, direction=right, attacks=2, repetitions=1 +*, x=0.754, y=0.257, frequency=1, skip=False, adjust=True + Shikigami, direction=right, attacks=2, repetitions=1 + +@, label=main1 +*, x=0.754, y=0.183, frequency=1, skip=False, adjust=False + Shikigami, direction=left, attacks=3, repetitions=1 + Shikigami, direction=right, attacks=3, repetitions=1 + Exorcist, jump=False + Wait, duration=0.4 + Teleport, direction=up, jump=False +*, x=0.754, y=0.097, frequency=2, skip=False, adjust=False + Shikigami, direction=left, attacks=3, repetitions=1 + Shikigami, direction=right, attacks=2, repetitions=1 +*, x=0.754, y=0.097, frequency=2, skip=False, adjust=True + Teleport, direction=down, jump=False +*, x=0.754, y=0.097, frequency=2, skip=True, adjust=False + Shikigami, direction=right, attacks=3, repetitions=1 + Shikigami, direction=left, attacks=2, repetitions=1 +*, x=0.754, y=0.097, frequency=2, skip=True, adjust=True + Teleport, direction=down, jump=False +>, label=boss1, frequency=5, skip=True +>, label=main1, frequency=1, skip=False + +@, label=boss1 +*, x=0.49, y=0.16, frequency=1, skip=False, adjust=True + Yaksha, direction=left +>, label=loot_domain, frequency=3, skip=True +>, label=main1, frequency=1, skip=False + +@, label=loot_domain +*, x=0.754, y=0.183, frequency=1, skip=False, adjust=False + Exorcist, jump=False + Wait, duration=0.6 +*, x=0.754, y=0.257, frequency=1, skip=False, adjust=True + Domain +*, x=0.846, y=0.257, frequency=1, skip=False, adjust=False + Shikigami, direction=right, attacks=3, repetitions=1 +*, x=0.869, y=0.177, frequency=1, skip=False, adjust=False + Shikigami, direction=right, attacks=3, repetitions=1 + Shikigami, direction=right, attacks=2, repetitions=1 +*, x=0.846, y=0.097, frequency=1, skip=False, adjust=False + Shikigami, direction=right, attacks=3, repetitions=1 + Shikigami, direction=left, attacks=2, repetitions=1 +*, x=0.650, y=0.097, frequency=1, skip=False, adjust=False + Shikigami, direction=left, attacks=3, repetitions=1 +*, x=0.474, y=0.063, frequency=1, skip=False, adjust=False + Shikigami, direction=left, attacks=3, repetitions=1 +*, x=0.280, y=0.080, frequency=1, skip=False, adjust=False + Shikigami, direction=left, attacks=3, repetitions=1 + Shikigami, direction=left, attacks=2, repetitions=1 + Teleport, direction=down, jump=False +*, x=0.28, y=0.16, frequency=1, skip=False, adjust=False + Shikigami, direction=left, attacks=2, repetitions=1 +*, x=0.46, y=0.16, frequency=1, skip=False, adjust=True + Yaksha, direction=right + Teleport, direction=down, jump=False +*, x=0.36, y=0.257, frequency=1, skip=False, adjust=False + Kishin +*, x=0.25, y=0.257, frequency=1, skip=False, adjust=True + Shikigami, direction=left, attacks=3, repetitions=1 + Teleport, direction=up, jump=False + +@, label=main2 +*, x=0.297, y=0.16, frequency=1, skip=False, adjust=False + Shikigami, direction=left, attacks=3, repetitions=1 + Shikigami, direction=right, attacks=3, repetitions=1 +*, x=0.297, y=0.16, frequency=1, skip=False, adjust=True + Teleport, direction=up, jump=False + Shikigami, direction=left, attacks=3, repetitions=1 + Shikigami, direction=left, attacks=2, repetitions=1 + Teleport, direction=down, jump=False +>, label=boss2, frequency=5, skip=True +>, label=main2, frequency=1, skip=False + +@, label=boss2 +>, label=loot_no_domain, frequency=2, skip=True +*, x=0.45, y=0.16, frequency=1, skip=False, adjust=False + Yaksha, direction=right +>, label=main2, frequency=1, skip=False + +@, label=loot_no_domain +*, x=0.49, y=0.160, frequency=1, skip=False, adjust=True + Yaksha, direction=left +*, x=0.486, y=0.063, frequency=1, skip=False, adjust=False + Shikigami, direction=left, attacks=2, repetitions=1 +*, x=0.280, y=0.080, frequency=1, skip=False, adjust=False + Shikigami, direction=left, attacks=2, repetitions=1 +*, x=0.28, y=0.257, frequency=1, skip=False, adjust=False +*, x=0.183, y=0.257, frequency=1, skip=False, adjust=False + Shikigami, direction=left, attacks=3, repetitions=1 +>, label=kishin, frequency=1, skip=False diff --git a/src/gui_components/menu/main.py b/src/gui_components/menu/main.py index 302e4e00..a6e3d231 100644 --- a/src/gui_components/menu/main.py +++ b/src/gui_components/menu/main.py @@ -1,12 +1,16 @@ """A menu for loading routines and command books.""" -from src.common import config, utils +import os import queue import tkinter as tk +from src.common import config, utils from tkinter.filedialog import askopenfilename, asksaveasfilename from tkinter.messagebox import askyesno +RESOURCE_DIR = 'resources' + + class Menu(tk.Menu): def __init__(self, parent, **kwargs): super().__init__(parent, **kwargs) @@ -38,7 +42,7 @@ def _new_routine(): @staticmethod @utils.run_if_disabled('\n[!] Cannot save routines while Auto Maple is enabled') def _save_routine(): - file_path = asksaveasfilename(initialdir='./routines/', + file_path = asksaveasfilename(initialdir=os.path.join(RESOURCE_DIR, 'routines'), title='Save routine', filetypes=[('*.csv', '*.csv')], defaultextension='*.csv') @@ -55,7 +59,7 @@ def _load_routine(): icon='warning'): return - file_path = askopenfilename(initialdir='./routines/', + file_path = askopenfilename(initialdir=os.path.join(RESOURCE_DIR, 'routines'), title='Select a routine', filetypes=[('*.csv', '*.csv')]) if file_path: @@ -71,7 +75,7 @@ def _load_commands(): icon='warning'): return - file_path = askopenfilename(initialdir='./command_books/', + file_path = askopenfilename(initialdir=os.path.join(RESOURCE_DIR, 'command_books'), title='Select a command book', filetypes=[('*.py', '*.py')]) if file_path: diff --git a/src/modules/bot.py b/src/modules/bot.py index 2fa4ff50..e1087e01 100644 --- a/src/modules/bot.py +++ b/src/modules/bot.py @@ -163,7 +163,7 @@ def load_commands(self, file): # Import the desired command book file module_name = splitext(basename(file))[0] - module = __import__(f'command_books.{module_name}', fromlist=['']) + module = __import__(f'resources.command_books.{module_name}', fromlist=['']) # Check if the 'step' function has been implemented step_found = False From 9a68994e735bfab41d3b0cfec60d75847aad21d3 Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Thu, 26 May 2022 17:21:22 -0700 Subject: [PATCH 20/28] moved cbs and routines to resources --- command_books/blaster.py | 170 ---------------------- command_books/kanna.py | 295 --------------------------------------- routines/cf1.csv | 62 -------- routines/dcup2.csv | 84 ----------- routines/mts3.csv | 217 ---------------------------- routines/os3.csv | 100 ------------- 6 files changed, 928 deletions(-) delete mode 100644 command_books/blaster.py delete mode 100644 command_books/kanna.py delete mode 100644 routines/cf1.csv delete mode 100644 routines/dcup2.csv delete mode 100644 routines/mts3.csv delete mode 100644 routines/os3.csv diff --git a/command_books/blaster.py b/command_books/blaster.py deleted file mode 100644 index 482f71a1..00000000 --- a/command_books/blaster.py +++ /dev/null @@ -1,170 +0,0 @@ -"""A collection of all commands that a Blaster can use to interact with the game.""" - -import time -from src.common import settings -from src.routine.components import Command -from src.common.vkeys import press, key_down, key_up - -# -# class Move(Command): -# """Moves to a given position using the shortest path based on the current Layout.""" -# -# def __init__(self, x, y, max_steps=15): -# super().__init__(locals()) -# self.target = (float(x), float(y)) -# self.max_steps = settings.validate_nonnegative_int(max_steps) -# -# def main(self): -# counter = self.max_steps -# path = config.layout.shortest_path(config.player_pos, self.target) -# # config.path = path.copy() -# # config.path.insert(0, config.player_pos) -# for point in path: -# counter = self._step(point, counter) -# -# @utils.run_if_enabled -# def _step(self, target, counter): -# toggle = True -# local_error = utils.distance(config.player_pos, target) -# global_error = utils.distance(config.player_pos, self.target) -# while config.enabled and \ -# counter > 0 and \ -# local_error > settings.move_tolerance and \ -# global_error > settings.move_tolerance: -# if toggle: -# d_x = target[0] - config.player_pos[0] -# if abs(d_x) > settings.move_tolerance / math.sqrt(2): -# if d_x < 0: -# Jump('left').main() -# else: -# Jump('right').main() -# counter -= 1 -# else: -# d_y = target[1] - config.player_pos[1] -# if abs(d_y) > settings.move_tolerance / math.sqrt(2): -# if d_y < 0: -# Jump('up').main() -# else: -# Jump('down').main() -# counter -= 1 -# local_error = utils.distance(config.player_pos, target) -# global_error = utils.distance(config.player_pos, self.target) -# toggle = not toggle -# return counter -# -# -# class Adjust(Command): -# """Fine-tunes player position using small movements.""" -# -# def __init__(self, x, y, max_steps=5): -# super().__init__(locals()) -# self.target = (float(x), float(y)) -# self.max_steps = settings.validate_nonnegative_int(max_steps) -# -# def main(self): -# counter = self.max_steps -# toggle = True -# error = utils.distance(config.player_pos, self.target) -# while config.enabled and counter > 0 and error > settings.adjust_tolerance: -# if toggle: -# d_x = self.target[0] - config.player_pos[0] -# threshold = settings.adjust_tolerance / math.sqrt(2) -# if abs(d_x) > threshold: -# walk_counter = 0 -# if d_x < 0: -# key_down('left') -# while config.enabled and d_x < -1 * threshold and walk_counter < 60: -# time.sleep(0.05) -# walk_counter += 1 -# d_x = self.target[0] - config.player_pos[0] -# key_up('left') -# else: -# key_down('right') -# while config.enabled and d_x > threshold and walk_counter < 60: -# time.sleep(0.05) -# walk_counter += 1 -# d_x = self.target[0] - config.player_pos[0] -# key_up('right') -# counter -= 1 -# else: -# d_y = self.target[1] - config.player_pos[1] -# if abs(d_y) > settings.adjust_tolerance / math.sqrt(2): -# if d_y < 0: -# Jump('up').main() -# else: -# key_down('down') -# time.sleep(0.05) -# press('space', 3, down_time=0.1) -# key_up('down') -# time.sleep(0.05) -# counter -= 1 -# error = utils.distance(config.player_pos, self.target) -# toggle = not toggle -# -# -# def step(direction, target): -# print('blaster step test') - - -class Buff(Command): - """Uses each of Blaster's buffs once.""" - - def __init__(self): - super().__init__(locals()) - self.booster_time = 0 - self.warrior_time = 0 - - def main(self): - now = time.time() - if self.booster_time == 0 or now - self.booster_time > 190: - press('f1', 2) - self.booster_time = now - if self.warrior_time == 0 or now - self.warrior_time > 890: - press('f2', 2) - self.warrior_time = now - - -class Jump(Command): - """Performs a flash jump or 'Detonate' in the given direction.""" - - def __init__(self, direction): - super().__init__(locals()) - self.direction = settings.validate_arrows(direction) - - def main(self): - key_down(self.direction) - time.sleep(0.1) - press('space', 1) - if self.direction == 'up': - press('d', 1) - else: - press('space', 1) - key_up(self.direction) - time.sleep(0.5) - - -class MagnumPunch(Command): - """Performs a 'No-Reload Magnum Punch' combo once.""" - - def __init__(self, direction): - super().__init__(locals()) - self.direction = settings.validate_arrows(direction) - - def main(self): - key_down(self.direction) - time.sleep(0.05) - key_down('q') - time.sleep(0.1) - for _ in range(3): - key_down('r') - time.sleep(0.05) - key_down('e') - time.sleep(0.05) - key_up('r') - key_up('e') - time.sleep(0.05) - key_up('q') - time.sleep(0.025) - press('space', 1) - key_up(self.direction) - time.sleep(0.05) diff --git a/command_books/kanna.py b/command_books/kanna.py deleted file mode 100644 index 62e274f5..00000000 --- a/command_books/kanna.py +++ /dev/null @@ -1,295 +0,0 @@ -"""A collection of all commands that a Kanna can use to interact with the game.""" - -from src.common import config, settings, utils -import time -import math -from src.routine.components import Command -from src.common.vkeys import press, key_down, key_up - - -# List of key mappings -class Key: - # Movement - JUMP = 'space' - TELEPORT = 'e' - CHARM = 'd' - - # Buffs - HAKU = 'f4' - AKATSUKI_WARRIOR = 'f3' - HOLY_SYMBOL = 'f2' - SPEED_INFUSION = 'f1' - - # Skills - SHIKIGAMI = 'r' - TENGU = 'q' - YAKSHA = '2' - VANQUISHER = 'f' - KISHIN = 'ctrl' - NINE_TAILS = '3' - EXORCIST = 'w' - DOMAIN = 'z' - ONI_LEGION = '5' - BLOSSOM_BARRIER = 'g' - YUKIMUSUME = 'c' - MANA_BALANCE = 'lshift' - - -######################### -# Commands # -######################### -def step(direction, target): - """ - Performs one movement step in the given DIRECTION towards TARGET. - Should not press any arrow keys, as those are handled by Auto Maple. - """ - - num_presses = 2 - if direction == 'up' or direction == 'down': - num_presses = 1 - if config.stage_fright and direction != 'up' and utils.bernoulli(0.75): - time.sleep(utils.rand_float(0.1, 0.3)) - d_y = target[1] - config.player_pos[1] - if abs(d_y) > settings.move_tolerance * 1.5: - if direction == 'down': - press(Key.JUMP, 3) - elif direction == 'up': - press(Key.JUMP, 1) - press(Key.TELEPORT, num_presses) - - -class Adjust(Command): - """Fine-tunes player position using small movements.""" - - def __init__(self, x, y, max_steps=5): - super().__init__(locals()) - self.target = (float(x), float(y)) - self.max_steps = settings.validate_nonnegative_int(max_steps) - - def main(self): - counter = self.max_steps - toggle = True - error = utils.distance(config.player_pos, self.target) - while config.enabled and counter > 0 and error > settings.adjust_tolerance: - if toggle: - d_x = self.target[0] - config.player_pos[0] - threshold = settings.adjust_tolerance / math.sqrt(2) - if abs(d_x) > threshold: - walk_counter = 0 - if d_x < 0: - key_down('left') - while config.enabled and d_x < -1 * threshold and walk_counter < 60: - time.sleep(0.05) - walk_counter += 1 - d_x = self.target[0] - config.player_pos[0] - key_up('left') - else: - key_down('right') - while config.enabled and d_x > threshold and walk_counter < 60: - time.sleep(0.05) - walk_counter += 1 - d_x = self.target[0] - config.player_pos[0] - key_up('right') - counter -= 1 - else: - d_y = self.target[1] - config.player_pos[1] - if abs(d_y) > settings.adjust_tolerance / math.sqrt(2): - if d_y < 0: - Teleport('up').main() - else: - key_down('down') - time.sleep(0.05) - press(Key.JUMP, 3, down_time=0.1) - key_up('down') - time.sleep(0.05) - counter -= 1 - error = utils.distance(config.player_pos, self.target) - toggle = not toggle - - -class Buff(Command): - """Uses each of Kanna's buffs once. Uses 'Haku Reborn' whenever it is available.""" - - def __init__(self): - super().__init__(locals()) - self.haku_time = 0 - self.buff_time = 0 - - def main(self): - buffs = [Key.SPEED_INFUSION, Key.HOLY_SYMBOL] - now = time.time() - if self.haku_time == 0 or now - self.haku_time > 490: - press(Key.HAKU, 2) - press(Key.AKATSUKI_WARRIOR, 2) - self.haku_time = now - if self.buff_time == 0 or now - self.buff_time > settings.buff_cooldown: - for key in buffs: - press(key, 3, up_time=0.3) - self.buff_time = now - - -class Teleport(Command): - """ - Teleports in a given direction, jumping if specified. Adds the player's position - to the current Layout if necessary. - """ - - def __init__(self, direction, jump='False'): - super().__init__(locals()) - self.direction = settings.validate_arrows(direction) - self.jump = settings.validate_boolean(jump) - - def main(self): - num_presses = 3 - time.sleep(0.05) - if self.direction in ['up', 'down']: - num_presses = 2 - if self.direction != 'up': - key_down(self.direction) - time.sleep(0.05) - if self.jump: - if self.direction == 'down': - press(Key.JUMP, 3, down_time=0.1) - else: - press(Key.JUMP, 1) - if self.direction == 'up': - key_down(self.direction) - time.sleep(0.05) - press(Key.TELEPORT, num_presses) - key_up(self.direction) - if settings.record_layout: - config.layout.add(*config.player_pos) - - -class Shikigami(Command): - """Attacks using 'Shikigami Haunting' in a given direction.""" - - def __init__(self, direction, attacks=2, repetitions=1): - super().__init__(locals()) - self.direction = settings.validate_horizontal_arrows(direction) - self.attacks = int(attacks) - self.repetitions = int(repetitions) - - def main(self): - time.sleep(0.05) - key_down(self.direction) - time.sleep(0.05) - if config.stage_fright and utils.bernoulli(0.7): - time.sleep(utils.rand_float(0.1, 0.3)) - for _ in range(self.repetitions): - press(Key.SHIKIGAMI, self.attacks, up_time=0.05) - key_up(self.direction) - if self.attacks > 2: - time.sleep(0.3) - else: - time.sleep(0.2) - - -class Tengu(Command): - """Uses 'Tengu Strike' once.""" - - def main(self): - press(Key.TENGU, 1, up_time=0.05) - - -class Yaksha(Command): - """ - Places 'Ghost Yaksha Boss' in a given direction, or towards the center of the map if - no direction is specified. - """ - - def __init__(self, direction=None): - super().__init__(locals()) - if direction is None: - self.direction = direction - else: - self.direction = settings.validate_horizontal_arrows(direction) - - def main(self): - if self.direction: - press(self.direction, 1, down_time=0.1, up_time=0.05) - else: - if config.player_pos[0] > 0.5: - press('left', 1, down_time=0.1, up_time=0.05) - else: - press('right', 1, down_time=0.1, up_time=0.05) - press(Key.YAKSHA, 3) - - -class Vanquisher(Command): - """Holds down 'Vanquisher's Charm' until this command is called again.""" - - def main(self): - key_up(Key.VANQUISHER) - time.sleep(0.075) - key_down(Key.VANQUISHER) - time.sleep(0.15) - - -class Kishin(Command): - """Uses 'Kishin Shoukan' once.""" - - def main(self): - press(Key.KISHIN, 4, down_time=0.1, up_time=0.15) - - -class NineTails(Command): - """Uses 'Nine-Tailed Fury' once.""" - - def main(self): - press(Key.NINE_TAILS, 3) - - -class Exorcist(Command): - """Uses 'Exorcist's Charm' once.""" - - def __init__(self, jump='False'): - super().__init__(locals()) - self.jump = settings.validate_boolean(jump) - - def main(self): - if self.jump: - press(Key.JUMP, 1, down_time=0.1, up_time=0.15) - press(Key.EXORCIST, 2, up_time=0.05) - - -class Domain(Command): - """Uses 'Spirit's Domain' once.""" - - def main(self): - press(Key.DOMAIN, 3) - - -class Legion(Command): - """Uses 'Ghost Yaksha: Great Oni Lord's Legion' once.""" - - def main(self): - press(Key.ONI_LEGION, 2, down_time=0.1) - - -class BlossomBarrier(Command): - """Places a 'Blossom Barrier' on the ground once.""" - - def main(self): - press(Key.BLOSSOM_BARRIER, 2) - - -class Yukimusume(Command): - """Uses 'Yuki-musume Shoukan' once.""" - - def main(self): - press(Key.YUKIMUSUME, 2) - - -class Balance(Command): - """Restores mana using 'Mana Balance' once.""" - - def main(self): - press(Key.MANA_BALANCE, 2) - - -class Charm(Command): - """Jumps up using 'Shikigami Charm'.""" - - def main(self): - press(Key.CHARM, 2) diff --git a/routines/cf1.csv b/routines/cf1.csv deleted file mode 100644 index beac64a3..00000000 --- a/routines/cf1.csv +++ /dev/null @@ -1,62 +0,0 @@ -$, target=move_tolerance, value=0.09 -$, target=buff_cooldown, value=185 - -@, label=kish -*, x=0.811, y=0.243, frequency=1, skip=False, adjust=False - Kishin -*, x=0.640, y=0.243, frequency=1, skip=False, adjust=True -*, x=0.415, y=0.243, frequency=1, skip=False, adjust=False - Yaksha, direction=right -*, x=0.150, y=0.243, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=3, repetitions=1 - Shikigami, direction=left, attacks=2, repetitions=1 - Shikigami, direction=right, attacks=3, repetitions=1 - -@, label=main -*, x=0.275, y=0.142, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=3, repetitions=1 - Shikigami, direction=right, attacks=3, repetitions=1 - Wait, duration=0.05 -*, x=0.275, y=0.142, frequency=1, skip=False, adjust=True - Exorcist, jump=False - Wait, duration=0.3 - Teleport, direction=up, jump=False - Shikigami, direction=right, attacks=3, repetitions=1 - Shikigami, direction=right, attacks=2, repetitions=1 - Teleport, direction=down, jump=False - Wait, duration=0.05 ->, label=boss, frequency=7, skip=True ->, label=main, frequency=1, skip=False - -@, label=boss ->, label=loot, frequency=3, skip=True -*, x=0.415, y=0.243, frequency=1, skip=False, adjust=False - Yaksha, direction=right - Charm - Teleport, direction=left, jump=False ->, label=main, frequency=1, skip=False - -@, label=loot -*, x=0.125, y=0.142, frequency=1, skip=False, adjust=False - Yaksha, direction=right - Wait, duration=0.1 - Balance -*, x=0.257, y=0.142, frequency=1, skip=False, adjust=True - Exorcist, jump=False - Tengu - Teleport, direction=up, jump=False - Shikigami, direction=left, attacks=3, repetitions=1 - Teleport, direction=right, jump=False - Shikigami, direction=right, attacks=3, repetitions=1 - Shikigami, direction=right, attacks=2, repetitions=1 - Walk, direction=right, duration=0.4 - Teleport, direction=down, jump=False -*, x=0.640, y=0.108, frequency=1, skip=False, adjust=True - Shikigami, direction=left, attacks=2, repetitions=1 - Shikigami, direction=right, attacks=2, repetitions=1 -*, x=0.640, y=0.108, frequency=1, skip=False, adjust=False - NineTails - Tengu - Wait, duration=0.2 -*, x=0.640, y=0.243, frequency=1, skip=False, adjust=False ->, label=kish, frequency=1, skip=False diff --git a/routines/dcup2.csv b/routines/dcup2.csv deleted file mode 100644 index 780c2fb4..00000000 --- a/routines/dcup2.csv +++ /dev/null @@ -1,84 +0,0 @@ -$, target=record_layout, value=True -$, target=move_tolerance, value=0.075 - -@, label=main -*, x=0.873, y=0.083, frequency=1, skip=False, adjust=False - Tengu -*, x=0.873, y=0.200, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=2, repetitions=1 - Shikigami, direction=right, attacks=2, repetitions=1 ->, label=loot, frequency=4, skip=False -*, x=0.873, y=0.200, frequency=1, skip=False, adjust=False - Fall, distance=0.02 - -@, label=afterboss -*, x=0.055, y=0.125, frequency=1, skip=False, adjust=False - Shikigami, direction=right, attacks=2, repetitions=1 -*, x=0.055, y=0.125, frequency=1, skip=False, adjust=False - Fall, distance=0.005 - Shikigami, direction=right, attacks=2, repetitions=1 - Walk, direction=left, duration=0.2 ->, label=main, frequency=1, skip=False - -@, label=loot -*, x=0.873, y=0.200, frequency=1, skip=False, adjust=False - Teleport, direction=left, jump=False - Yaksha, direction=left -*, x=0.750, y=0.200, frequency=1, skip=False, adjust=False - Teleport, direction=left, jump=False - NineTails - Tengu -*, x=0.44, y=0.199, frequency=1, skip=False, adjust=True - Balance - Shikigami, direction=right, attacks=3, repetitions=1 -*, x=0.350, y=0.200, frequency=1, skip=False, adjust=True - Kishin - Wait, duration=0.15 -*, x=0.225, y=0.200, frequency=1, skip=False, adjust=True - Walk, direction=left, duration=0.2 - Shikigami, direction=left, attacks=2, repetitions=1 -*, x=0.225, y=0.200, frequency=1, skip=False, adjust=False - Fall, distance=0.02 - Walk, direction=left, duration=0.2 - Tengu -*, x=0.660, y=0.083, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=2, repetitions=1 - Tengu -*, x=0.394, y=0.100, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=2, repetitions=1 - Tengu - Walk, direction=left, duration=0.5 -*, x=0.394, y=0.100, frequency=1, skip=False, adjust=False - Walk, direction=left, duration=0.2 ->, label=afterboss2, frequency=1, skip=False - -@, label=main2 -*, x=0.873, y=0.083, frequency=1, skip=False, adjust=False - Tengu -*, x=0.873, y=0.200, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=2, repetitions=1 - Shikigami, direction=right, attacks=2, repetitions=1 ->, label=boss2, frequency=5, skip=True -*, x=0.873, y=0.200, frequency=1, skip=False, adjust=False - Fall, distance=0.02 - Walk, direction=right, duration=0.2 - -@, label=afterboss2 -*, x=0.055, y=0.125, frequency=1, skip=False, adjust=False - Shikigami, direction=right, attacks=2, repetitions=1 -*, x=0.055, y=0.125, frequency=1, skip=False, adjust=False - Fall, distance=0.005 - Shikigami, direction=right, attacks=2, repetitions=1 - Walk, direction=left, duration=0.2 ->, label=main2, frequency=1, skip=False - -@, label=boss2 -*, x=0.873, y=0.200, frequency=1, skip=False, adjust=False - Teleport, direction=left, jump=False - Yaksha, direction=left -*, x=0.750, y=0.200, frequency=3, skip=True, adjust=False - Fall, distance=0.02 ->, label=afterboss, frequency=3, skip=True -*, x=0.750, y=0.200, frequency=1, skip=False, adjust=False - Fall, distance=0.02 ->, label=afterboss2, frequency=1, skip=False diff --git a/routines/mts3.csv b/routines/mts3.csv deleted file mode 100644 index 5455821e..00000000 --- a/routines/mts3.csv +++ /dev/null @@ -1,217 +0,0 @@ -s, adjust_tolerance, 0.0125 - - - -@, loot_no_domain -*, 0.120, 0.303, adjust=True - shikigami, direction=right - yukimusume -*, 0.138, 0.414 - shikigami, direction=right -*, 0.336, 0.414 - legion -*, 0.461, 0.414 - ninetails -*, 0.737, 0.414 - kishin -*, 0.868, 0.414, adjust=True -*, 0.685, 0.414, adjust=True - teleport, direction=up -*, 0.750, 0.303 - walk, right, 0.15 -*, 0.865, 0.303, adjust=True - shikigami, direction=left, attacks=3 - wait, 0.1 -*, 0.865, 0.138 - shikigami, direction=left - walk, left, 0.3 -*, 0.645, 0.138, adjust=True - wait, 0.1 - teleport, direction=down -*, 0.539, 0.237 - yaksha, direction=right -*, 0.468, 0.237, adjust=True - exorcist - wait, 0.3 - teleport, direction=left -*, 0.315, 0.151, adjust=True - teleport, direction=down -*, 0.283, 0.303 - legion -*, 0.283, 0.303 - goto, main1 - -@, main1 -*, 0.283, 0.303, adjust=True - shikigami, direction=left - shikigami, direction=right, attacks=3 -*, 0.283, 0.303 - wait, 0.2 - exorcist - teleport, direction=up - wait, 0.3 - shikigami, direction=right, attacks=3 - teleport, direction=down -*, 0.460, 0.342, frequency=4, counter=1 - shikigami, direction=right -*, 0.500, 0.342, frequency=4, counter=1 - goto, boss1 -*, 0.283, 0.303 - teleport, direction=right - shikigami, direction=right -*, 0.283, 0.303 - goto, main1 - -@, main2 -*, 0.283, 0.303, adjust=True - shikigami, direction=left - shikigami, direction=right, attacks=3 -*, 0.283, 0.303 - wait, 0.2 - exorcist - teleport, direction=up - wait, 0.3 - shikigami, direction=right, attacks=3 - teleport, direction=down -*, 0.460, 0.342, frequency=5, counter=1 - shikigami, direction=right -*, 0.500, 0.342, frequency=5, counter=1 - goto, boss2 -*, 0.283, 0.303 - teleport, direction=right - shikigami, direction=right -*, 0.283, 0.303 - goto, main2 - -@, boss1 -*, 0.539, 0.237 - yaksha, direction=right -*, 0.510, 0.237 - teleport, direction=down -*, 0.530, 0.342 - shikigami, direction=left -*, 0.500, 0.342, frequency=3, counter=1 - goto, main2 -*, 0.500, 0.342 - goto, main1 - -@, boss2 -*, 0.539, 0.237 - yaksha, direction=right -*, 0.510, 0.237 - teleport, direction=down -*, 0.530, 0.342 - shikigami, direction=left -*, 0.500, 0.342 - goto, loot_with_domain - - - -@, loot_with_domain -*, 0.120, 0.303, adjust=True - shikigami, direction=right - yukimusume -*, 0.138, 0.414 - shikigami, direction=right -*, 0.336, 0.414, adjust=True - domain -*, 0.461, 0.414 - ninetails -*, 0.737, 0.414 - kishin -*, 0.868, 0.414, adjust=True -*, 0.685, 0.414, adjust=True - teleport, direction=up -*, 0.750, 0.303 - walk, right, 0.15 -*, 0.865, 0.303, adjust=True - shikigami, direction=left, attacks=3 - wait, 0.1 -*, 0.865, 0.138 - shikigami, direction=left - walk, left, 0.3 -*, 0.645, 0.138, adjust=True - wait, 0.1 - teleport, direction=down -*, 0.539, 0.237 - vanquisher -*, 0.480, 0.237, adjust=True -*, 0.580, 0.237, adjust=True - walk, left, 0.15 - walk, right, 0.1 - walk, left, 0.1 - walk, right, 0.1 - walk, left, 0.15 - walk, right, 0.1 - walk, left, 0.1 - walk, right, 0.1 - walk, left, 0.15 - walk, right, 0.1 - walk, left, 0.1 - walk, right, 0.1 - walk, left, 0.15 - walk, right, 0.1 - walk, left, 0.1 - walk, right, 0.1 -*, 0.600, 0.237, adjust=True - vanquisher - wait, 0.15 - exorcist - wait, 0.3 - teleport, direction=right -*, 0.715, 0.138 - goto, main3 - -@, main3 -*, 0.715, 0.138 - shikigami, direction=left, attacks=3 - wait, 0.15 - shikigami, direction=right, attacks=3 -*, 0.715, 0.138, adjust=True - teleport, direction=down -*, 0.715, 0.303 - shikigami, direction=left, attacks=3 - wait, 0.15 - shikigami, direction=right, attacks=3 - wait, 0.1 -*, 0.715, 0.303, frequency=3, adjust=True - exorcist - wait, 0.3 -*, 0.715, 0.303, frequency=12, counter=1 - teleport, direction=left, jump=True - goto, boss3 -*, 0.715, 0.303 - goto, main3 - -@, boss3 -*, 0.539, 0.237 - yaksha, direction=right -*, 0.510, 0.237 - teleport, direction=down -*, 0.530, 0.342 - shikigami, direction=left -*, 0.500, 0.342, frequency=2, counter=1 - goto, loot_no_domain -*, 0.500, 0.342 - goto, main4 - -@, main4 -*, 0.283, 0.303, adjust=True - shikigami, direction=left - shikigami, direction=right, attacks=3 -*, 0.283, 0.303 - wait, 0.2 - exorcist - teleport, direction=up - wait, 0.3 - shikigami, direction=right, attacks=3 - teleport, direction=down -*, 0.460, 0.342, frequency=5, counter=1 - shikigami, direction=right -*, 0.500, 0.342, frequency=5, counter=1 - goto, boss3 -*, 0.283, 0.303 - teleport, direction=right - shikigami, direction=right -*, 0.283, 0.303 - goto, main4 diff --git a/routines/os3.csv b/routines/os3.csv deleted file mode 100644 index 3d7340d9..00000000 --- a/routines/os3.csv +++ /dev/null @@ -1,100 +0,0 @@ -$, target=move_tolerance, value=0.075 -*, x=0.49, y=0.16, frequency=1, skip=False, adjust=True - Yaksha, direction=left - -@, label=kishin -*, x=0.360, y=0.257, frequency=1, skip=False, adjust=False - Kishin -*, x=0.543, y=0.257, frequency=1, skip=False, adjust=False - Shikigami, direction=right, attacks=2, repetitions=1 -*, x=0.754, y=0.257, frequency=1, skip=False, adjust=True - Shikigami, direction=right, attacks=2, repetitions=1 - -@, label=main1 -*, x=0.754, y=0.183, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=3, repetitions=1 - Shikigami, direction=right, attacks=3, repetitions=1 - Exorcist, jump=False - Wait, duration=0.4 - Teleport, direction=up, jump=False -*, x=0.754, y=0.097, frequency=2, skip=False, adjust=False - Shikigami, direction=left, attacks=3, repetitions=1 - Shikigami, direction=right, attacks=2, repetitions=1 -*, x=0.754, y=0.097, frequency=2, skip=False, adjust=True - Teleport, direction=down, jump=False -*, x=0.754, y=0.097, frequency=2, skip=True, adjust=False - Shikigami, direction=right, attacks=3, repetitions=1 - Shikigami, direction=left, attacks=2, repetitions=1 -*, x=0.754, y=0.097, frequency=2, skip=True, adjust=True - Teleport, direction=down, jump=False ->, label=boss1, frequency=5, skip=True ->, label=main1, frequency=1, skip=False - -@, label=boss1 -*, x=0.49, y=0.16, frequency=1, skip=False, adjust=True - Yaksha, direction=left ->, label=loot_domain, frequency=3, skip=True ->, label=main1, frequency=1, skip=False - -@, label=loot_domain -*, x=0.754, y=0.183, frequency=1, skip=False, adjust=False - Exorcist, jump=False - Wait, duration=0.6 -*, x=0.754, y=0.257, frequency=1, skip=False, adjust=True - Domain -*, x=0.846, y=0.257, frequency=1, skip=False, adjust=False - Shikigami, direction=right, attacks=3, repetitions=1 -*, x=0.869, y=0.177, frequency=1, skip=False, adjust=False - Shikigami, direction=right, attacks=3, repetitions=1 - Shikigami, direction=right, attacks=2, repetitions=1 -*, x=0.846, y=0.097, frequency=1, skip=False, adjust=False - Shikigami, direction=right, attacks=3, repetitions=1 - Shikigami, direction=left, attacks=2, repetitions=1 -*, x=0.650, y=0.097, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=3, repetitions=1 -*, x=0.474, y=0.063, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=3, repetitions=1 -*, x=0.280, y=0.080, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=3, repetitions=1 - Shikigami, direction=left, attacks=2, repetitions=1 - Teleport, direction=down, jump=False -*, x=0.28, y=0.16, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=2, repetitions=1 -*, x=0.46, y=0.16, frequency=1, skip=False, adjust=True - Yaksha, direction=right - Teleport, direction=down, jump=False -*, x=0.36, y=0.257, frequency=1, skip=False, adjust=False - Kishin -*, x=0.25, y=0.257, frequency=1, skip=False, adjust=True - Shikigami, direction=left, attacks=3, repetitions=1 - Teleport, direction=up, jump=False - -@, label=main2 -*, x=0.297, y=0.16, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=3, repetitions=1 - Shikigami, direction=right, attacks=3, repetitions=1 -*, x=0.297, y=0.16, frequency=1, skip=False, adjust=True - Teleport, direction=up, jump=False - Shikigami, direction=left, attacks=3, repetitions=1 - Shikigami, direction=left, attacks=2, repetitions=1 - Teleport, direction=down, jump=False ->, label=boss2, frequency=5, skip=True ->, label=main2, frequency=1, skip=False - -@, label=boss2 ->, label=loot_no_domain, frequency=2, skip=True -*, x=0.45, y=0.16, frequency=1, skip=False, adjust=False - Yaksha, direction=right ->, label=main2, frequency=1, skip=False - -@, label=loot_no_domain -*, x=0.49, y=0.160, frequency=1, skip=False, adjust=True - Yaksha, direction=left -*, x=0.486, y=0.063, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=2, repetitions=1 -*, x=0.280, y=0.080, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=2, repetitions=1 -*, x=0.28, y=0.257, frequency=1, skip=False, adjust=False -*, x=0.183, y=0.257, frequency=1, skip=False, adjust=False - Shikigami, direction=left, attacks=3, repetitions=1 ->, label=kishin, frequency=1, skip=False From 2d4948b4d85494e1c7910edf8720671a95a71ee9 Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Thu, 26 May 2022 17:25:00 -0700 Subject: [PATCH 21/28] moved layouts dir to resources as well --- layouts/dcup2 | Bin 1473 -> 0 bytes src/common/config.py | 6 ++++++ src/gui_components/menu/main.py | 9 +++------ src/routine/layout.py | 3 ++- 4 files changed, 11 insertions(+), 7 deletions(-) delete mode 100644 layouts/dcup2 diff --git a/layouts/dcup2 b/layouts/dcup2 deleted file mode 100644 index 21833d4c5b1459883becc502b640ac645b695376..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1473 zcma)*Ye*DP6oA)seXQjxO|4AJ*J`$=R%TghSr*##Bch=QadmYJb3E&AX>me}2zr82 zQ4~Ssk3b>mWmFU>h4iuv(aP8|$<#2Y2zt@nGwwRmD!704a{0dVnsaMh3oFfq2D50j zl$M(eWd+sJNtY-8fhMjNTo9({c{hzlQ(mys1g^YRIu;dLE0V#DuFaxo0quBUII+m2 z19vHi2ZE=bcah90@XE;;@Vu0GNLxY|)u7ACXgB7byU;809ui@#$S*S$Tfkdj=2V1f zdO>pf?|PiLd@5QPqXn7pLGUHw{YCe^kqz0-gdc)G5pNGXeEBF~yE74hFrA35s9WuS zy1qFRfe1lFJnI#+`UZ=gi5UpNL_8QL2FH8Kt(i+p1Pg?4ycZjzxVv0#Hk9La_6r%A z$ytp;2q%Pcf_$WL%tDw=NnX1I9{gf!QkB6ed9@dYFo!&wt+DgQ(XvT+iqwiDRS}L5 zLD7beY}r?k8mx* V}VM0^@Pe$p?cM@6XW3?V)eA&U6VdCk#JH;zoq+xrS7FB&0+ zy#CGfW8O7sFpZrzN7o}3K~KcH@5yba(=r*+(#;moeUykph$rIBhrdI6e8ZiI`3MO_ zbpC1@NXHG%!~z5Z5$$9B-rJP0zOw%JXqH5Tg+$27wJe63NJ2;^qT%eW=f`RetB7%C zmV&T|_*U34@;Ih%V%|P8dDe>&mXP-%xOM+k?iKUe>@!p4VIGY+6=5kU9aTTi7<11v zs6IbS*!g19pBLL7_COD(eMvuD-f#y diff --git a/src/common/config.py b/src/common/config.py index a21bddef..45487299 100644 --- a/src/common/config.py +++ b/src/common/config.py @@ -1,6 +1,12 @@ """A collection of variables shared across multiple modules.""" +######################### +# Constants # +######################### +RESOURCES_DIR = 'resources' + + ################################# # Global Variables # ################################# diff --git a/src/gui_components/menu/main.py b/src/gui_components/menu/main.py index a6e3d231..692364c6 100644 --- a/src/gui_components/menu/main.py +++ b/src/gui_components/menu/main.py @@ -8,9 +8,6 @@ from tkinter.messagebox import askyesno -RESOURCE_DIR = 'resources' - - class Menu(tk.Menu): def __init__(self, parent, **kwargs): super().__init__(parent, **kwargs) @@ -42,7 +39,7 @@ def _new_routine(): @staticmethod @utils.run_if_disabled('\n[!] Cannot save routines while Auto Maple is enabled') def _save_routine(): - file_path = asksaveasfilename(initialdir=os.path.join(RESOURCE_DIR, 'routines'), + file_path = asksaveasfilename(initialdir=os.path.join(config.RESOURCES_DIR, 'routines'), title='Save routine', filetypes=[('*.csv', '*.csv')], defaultextension='*.csv') @@ -59,7 +56,7 @@ def _load_routine(): icon='warning'): return - file_path = askopenfilename(initialdir=os.path.join(RESOURCE_DIR, 'routines'), + file_path = askopenfilename(initialdir=os.path.join(config.RESOURCES_DIR, 'routines'), title='Select a routine', filetypes=[('*.csv', '*.csv')]) if file_path: @@ -75,7 +72,7 @@ def _load_commands(): icon='warning'): return - file_path = askopenfilename(initialdir=os.path.join(RESOURCE_DIR, 'command_books'), + file_path = askopenfilename(initialdir=os.path.join(config.RESOURCES_DIR, 'command_books'), title='Select a command book', filetypes=[('*.py', '*.py')]) if file_path: diff --git a/src/routine/layout.py b/src/routine/layout.py index 5a83d3f7..8c77a14f 100644 --- a/src/routine/layout.py +++ b/src/routine/layout.py @@ -1,5 +1,6 @@ """A module for saving map layouts and determining shortest paths.""" +import os import cv2 import math import pickle @@ -63,7 +64,7 @@ def __iter__(self): class Layout: """Uses a quadtree to represent possible player positions in a map layout.""" - LAYOUTS_DIR = 'layouts' + LAYOUTS_DIR = os.path.join(config.RESOURCES_DIR, 'layouts') TOLERANCE = settings.move_tolerance / 2 def __init__(self, name): From 648a1844019a64ca243c86715785b56892734cc5 Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Thu, 26 May 2022 17:40:12 -0700 Subject: [PATCH 22/28] using git submodules for resources --- .gitignore | 1 - .gitmodules | 3 +++ resources | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 .gitmodules create mode 160000 resources diff --git a/.gitignore b/.gitignore index 050056e0..885f5509 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ __pycache__/ assets/models/ -resources/ .idea/ .settings/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..14bdb5c5 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "resources"] + path = resources + url = https://github.com/tanjeffreyz/auto-maple-resources.git diff --git a/resources b/resources new file mode 160000 index 00000000..ba5d2cbb --- /dev/null +++ b/resources @@ -0,0 +1 @@ +Subproject commit ba5d2cbb7094023c7007ec9686467bdda7c57961 From 56867915e0c27d0db42c29b495af6df060f1a03c Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Thu, 26 May 2022 17:45:07 -0700 Subject: [PATCH 23/28] changes to resources repo show up in main repo --- resources | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources b/resources index ba5d2cbb..6a80379d 160000 --- a/resources +++ b/resources @@ -1 +1 @@ -Subproject commit ba5d2cbb7094023c7007ec9686467bdda7c57961 +Subproject commit 6a80379d514f60ef03415e3020ce599f5b7e96cf From 48201f170f4cd316756a5437a0ec5acef691b6d6 Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Thu, 26 May 2022 17:49:17 -0700 Subject: [PATCH 24/28] submodule changes show up in main repo! --- resources | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources b/resources index 6a80379d..7a1c14a1 160000 --- a/resources +++ b/resources @@ -1 +1 @@ -Subproject commit 6a80379d514f60ef03415e3020ce599f5b7e96cf +Subproject commit 7a1c14a1298bf882bdb2508eeebef115b8179cac From bf7792abb0fc24f8fd2c0cfe2ca748d551174e47 Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Thu, 26 May 2022 18:07:34 -0700 Subject: [PATCH 25/28] added updating submodules to setup.py --- .idea/vcs.xml | 1 + setup.py | 65 ++++++++++++++++++++++++++++++--------------------- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 94a25f7f..b639d34d 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,5 +2,6 @@ + \ No newline at end of file diff --git a/setup.py b/setup.py index 27d70981..45eb61f8 100644 --- a/setup.py +++ b/setup.py @@ -1,39 +1,52 @@ """Creates a desktop shortcut that can run Auto Maple from anywhere.""" import os +import git import argparse import win32com.client as client -parser = argparse.ArgumentParser() -parser.add_argument('--stay', action='store_true') -args = parser.parse_args() +def create_desktop_shortcut(): + """Creates and saves a desktop shortcut using absolute paths""" + print('\n[~] Creating a desktop shortcut for Auto Maple:') + CWD = os.getcwd() + TARGET = os.path.join(os.environ['WINDIR'], 'System32', 'cmd.exe') + PATH = os.path.join(os.environ['USERPROFILE'], 'Desktop', 'Auto Maple.lnk') + flag = "/c" + if args.stay: + flag = "/k" + print(" - Leaving command prompt open after program finishes") -# Create and save the shortcut using absolute paths -print('[~] Creating a desktop shortcut for Auto Maple:') -CWD = os.getcwd() -TARGET = os.path.join(os.environ['WINDIR'], 'System32', 'cmd.exe') -PATH = os.path.join(os.environ['USERPROFILE'], 'Desktop', 'Auto Maple.lnk') -flag = "/c" -if args.stay: - flag = "/k" - print(" ~ Leaving command prompt open after program finishes") + shell = client.Dispatch('WScript.Shell') + shortcut = shell.CreateShortCut(PATH) + shortcut.Targetpath = TARGET + shortcut.Arguments = flag + f' \"cd {CWD} & python main.py\"' + shortcut.IconLocation = os.path.join(CWD, 'assets', 'icon.ico') + shortcut.save() -shell = client.Dispatch('WScript.Shell') -shortcut = shell.CreateShortCut(PATH) -shortcut.Targetpath = TARGET -shortcut.Arguments = flag + f' \"cd {CWD} & python main.py\"' -shortcut.IconLocation = os.path.join(CWD, 'assets', 'icon.ico') -shortcut.save() + # Enable "run as administrator" + with open(PATH, 'rb') as lnk: + arr = bytearray(lnk.read()) -# Enable "run as administrator" -with open(PATH, 'rb') as lnk: - arr = bytearray(lnk.read()) + arr[0x15] = arr[0x15] | 0x20 # Set the 6th bit of 21st byte to 1 -arr[0x15] = arr[0x15] | 0x20 # Set the 6th bit of 21st byte to 1 + with open(PATH, 'wb') as lnk: + lnk.write(arr) + print(' - Enabled the "Run as Administrator" option') + print(' ~ Successfully created Auto Maple shortcut') -with open(PATH, 'wb') as lnk: - lnk.write(arr) - print(' ~ Enabled the "Run as Administrator" option') -print('[~] Successfully created Auto Maple shortcut') +def update_submodules(): + print('\n[~] Updating submodules:') + repo = git.Repo() + repo.git.submodule('update', '--init', '--recursive') + print(' ~ Finished updating submodules') + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--stay', action='store_true') + args = parser.parse_args() + + create_desktop_shortcut() + update_submodules() From 3455a83f961f974be79ac96fc89dd52fd5dddd93 Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Thu, 26 May 2022 18:12:11 -0700 Subject: [PATCH 26/28] updated requirements.txt to include GitPython --- requirements.txt | 1 + setup.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 75b0d64a..44bf382a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +GitPython keyboard mss numpy diff --git a/setup.py b/setup.py index 45eb61f8..ede8a70d 100644 --- a/setup.py +++ b/setup.py @@ -39,7 +39,8 @@ def create_desktop_shortcut(): def update_submodules(): print('\n[~] Updating submodules:') repo = git.Repo() - repo.git.submodule('update', '--init', '--recursive') + output = repo.git.submodule('update', '--init', '--recursive') + print(output) print(' ~ Finished updating submodules') From d69a98ca2da87481e0460ad27efb3f4dcf39d89f Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Thu, 26 May 2022 18:21:09 -0700 Subject: [PATCH 27/28] printing out submodule update messages line-by-line --- setup.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index ede8a70d..e229f7b7 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,9 @@ def update_submodules(): print('\n[~] Updating submodules:') repo = git.Repo() output = repo.git.submodule('update', '--init', '--recursive') - print(output) + for line in output.split('\n'): + if line: + print(f' - {line}') print(' ~ Finished updating submodules') From 38f827e9ef8413a01a50f24851d5b7979e0a2e2b Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Thu, 26 May 2022 18:23:35 -0700 Subject: [PATCH 28/28] setup now says whether submodules changed --- setup.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index e229f7b7..65671a2a 100644 --- a/setup.py +++ b/setup.py @@ -40,10 +40,15 @@ def update_submodules(): print('\n[~] Updating submodules:') repo = git.Repo() output = repo.git.submodule('update', '--init', '--recursive') + changed = False for line in output.split('\n'): if line: print(f' - {line}') - print(' ~ Finished updating submodules') + changed = True + if changed: + print(' ~ Finished updating submodules') + else: + print(' ~ No changes found in submodules') if __name__ == '__main__':