13
13
14
14
import pyautogui
15
15
16
- from lolbot .bot import game , launcher , logger , window
16
+ from lolbot .bot import game , launcher , logger , window , controller
17
17
from lolbot .common import accounts , config , proc
18
18
from lolbot .lcu .lcu_api import LCUApi , LCUError
19
19
31
31
32
32
class BotError (Exception ):
33
33
"""Indicates the League Client instance should be restarted."""
34
+
34
35
pass
35
36
36
37
37
38
class Bot :
38
39
"""Handles the League Client and all tasks needed to start a new game."""
40
+
39
41
def __init__ (self ) -> None :
40
42
self .api = LCUApi ()
41
43
self .config = config .load_config ()
42
- self .league_dir = self .config [' league_dir' ]
43
- self .max_level = self .config [' max_level' ]
44
- self .lobby = self .config [' lobby' ]
45
- self .champs = self .config [' champs' ]
46
- self .dialog = self .config [' dialog' ]
44
+ self .league_dir = self .config [" league_dir" ]
45
+ self .max_level = self .config [" max_level" ]
46
+ self .lobby = self .config [" lobby" ]
47
+ self .champs = self .config [" champs" ]
48
+ self .dialog = self .config [" dialog" ]
47
49
self .account = None
48
50
self .phase = None
49
51
self .prev_phase = None
@@ -62,7 +64,9 @@ def run(self, message_queue: mp.Queue, games: mp.Value, errors: mp.Value) -> Non
62
64
try :
63
65
errors .value = self .bot_errors
64
66
self .account = accounts .get_account (self .max_level )
65
- launcher .launch_league (self .account ['username' ], self .account ['password' ])
67
+ launcher .launch_league (
68
+ self .account ["username" ], self .account ["password" ]
69
+ )
66
70
self .leveling_loop (games )
67
71
proc .close_all_processes ()
68
72
self .bot_errors = 0
@@ -93,23 +97,23 @@ def leveling_loop(self, games: mp.Value) -> None:
93
97
"""Loop that takes action based on the phase of the League Client, continuously starts games."""
94
98
while not self .account_leveled ():
95
99
match self .get_phase ():
96
- case ' None' | ' Lobby' :
100
+ case " None" | " Lobby" :
97
101
self .start_matchmaking ()
98
- case ' Matchmaking' :
102
+ case " Matchmaking" :
99
103
self .queue ()
100
- case ' ReadyCheck' :
104
+ case " ReadyCheck" :
101
105
self .accept_match ()
102
- case ' ChampSelect' :
106
+ case " ChampSelect" :
103
107
self .champ_select ()
104
- case ' InProgress' :
108
+ case " InProgress" :
105
109
game .play_game ()
106
- case ' Reconnect' :
110
+ case " Reconnect" :
107
111
self .reconnect ()
108
- case ' WaitingForStats' :
112
+ case " WaitingForStats" :
109
113
self .wait_for_stats ()
110
- case ' PreEndOfGame' :
114
+ case " PreEndOfGame" :
111
115
self .pre_end_of_game ()
112
- case ' EndOfGame' :
116
+ case " EndOfGame" :
113
117
self .end_of_game ()
114
118
games .value += 1
115
119
case _:
@@ -122,7 +126,11 @@ def get_phase(self) -> str:
122
126
try :
123
127
self .prev_phase = self .phase
124
128
self .phase = self .api .get_phase ()
125
- if self .prev_phase == self .phase and self .phase != "Matchmaking" and self .phase != 'ReadyCheck' :
129
+ if (
130
+ self .prev_phase == self .phase
131
+ and self .phase != "Matchmaking"
132
+ and self .phase != "ReadyCheck"
133
+ ):
126
134
self .phase_errors += 1
127
135
if self .phase_errors == MAX_PHASE_ERRORS :
128
136
raise BotError ("Transition error. Phase will not change" )
@@ -173,7 +181,7 @@ def queue(self) -> None:
173
181
start = datetime .now ()
174
182
while True :
175
183
try :
176
- if self .api .get_phase () != ' Matchmaking' :
184
+ if self .api .get_phase () != " Matchmaking" :
177
185
return
178
186
elif datetime .now () - start > timedelta (minutes = 15 ):
179
187
raise BotError ("Queue Timeout" )
@@ -201,13 +209,21 @@ def champ_select(self) -> None:
201
209
except LCUError :
202
210
return
203
211
try :
204
- for action in data ['actions' ][0 ]:
205
- if action ['actorCellId' ] == data ['localPlayerCellId' ]:
206
- if action ['championId' ] == 0 : # No champ hovered. Hover a champion.
212
+ for action in data ["actions" ][0 ]:
213
+ if action ["actorCellId" ] == data ["localPlayerCellId" ]:
214
+ if (
215
+ action ["championId" ] == 0
216
+ ): # No champ hovered. Hover a champion.
207
217
champ_index += 1
208
- self .api .hover_champion (action ['id' ], champ_list [champ_index ])
209
- elif not action ['completed' ]: # Champ is hovered but not locked in.
210
- self .api .lock_in_champion (action ['id' ], action ['championId' ])
218
+ self .api .hover_champion (
219
+ action ["id" ], champ_list [champ_index ]
220
+ )
221
+ elif not action [
222
+ "completed"
223
+ ]: # Champ is hovered but not locked in.
224
+ self .api .lock_in_champion (
225
+ action ["id" ], action ["championId" ]
226
+ )
211
227
else : # Champ is locked in. Nothing left to do.
212
228
sleep (2 )
213
229
except LCUError :
@@ -223,15 +239,15 @@ def reconnect(self) -> None:
223
239
return
224
240
except LCUError :
225
241
sleep (2 )
226
- log .warning (' Could not reconnect to game' )
242
+ log .warning (" Could not reconnect to game" )
227
243
228
244
def wait_for_stats (self ) -> None :
229
245
"""Waits for the League Client Phase to change to something other than 'WaitingForStats'."""
230
246
log .info ("Waiting for stats" )
231
247
for i in range (60 ):
232
248
sleep (2 )
233
249
try :
234
- if self .api .get_phase () != ' WaitingForStats' :
250
+ if self .api .get_phase () != " WaitingForStats" :
235
251
return
236
252
except LCUError :
237
253
pass
@@ -242,14 +258,22 @@ def pre_end_of_game(self) -> None:
242
258
log .info ("Honoring teammates and accepting rewards" )
243
259
sleep (3 )
244
260
try :
245
- proc .click (POPUP_SEND_EMAIL_X_RATIO , proc .LEAGUE_CLIENT_WINNAME , 2 )
261
+ controller .left_click (
262
+ POPUP_SEND_EMAIL_X_RATIO , proc .LEAGUE_CLIENT_WINNAME , 2
263
+ )
246
264
if not self .honor_player ():
247
265
sleep (60 ) # Honor failed for some reason, wait out the honor screen
248
- proc .click (POPUP_SEND_EMAIL_X_RATIO , proc .LEAGUE_CLIENT_WINNAME , 2 )
266
+ controller .left_click (
267
+ POPUP_SEND_EMAIL_X_RATIO , proc .LEAGUE_CLIENT_WINNAME , 2
268
+ )
249
269
for i in range (3 ):
250
- proc .click (POST_GAME_SELECT_CHAMP_RATIO , proc .LEAGUE_CLIENT_WINNAME , 1 )
251
- proc .click (POST_GAME_OK_RATIO , proc .LEAGUE_CLIENT_WINNAME , 1 )
252
- proc .click (POPUP_SEND_EMAIL_X_RATIO , proc .LEAGUE_CLIENT_WINNAME , 1 )
270
+ controller .left_click (
271
+ POST_GAME_SELECT_CHAMP_RATIO , proc .LEAGUE_CLIENT_WINNAME , 1
272
+ )
273
+ controller .left_click (POST_GAME_OK_RATIO , proc .LEAGUE_CLIENT_WINNAME , 1 )
274
+ controller .left_click (
275
+ POPUP_SEND_EMAIL_X_RATIO , proc .LEAGUE_CLIENT_WINNAME , 1
276
+ )
253
277
except (window .WindowNotFound , pyautogui .FailSafeException ):
254
278
sleep (3 )
255
279
@@ -259,12 +283,12 @@ def honor_player(self) -> bool:
259
283
try :
260
284
players = self .api .get_players_to_honor ()
261
285
index = random .randint (0 , len (players ) - 1 )
262
- self .api .honor_player (players [index ][' summonerId' ])
286
+ self .api .honor_player (players [index ][" summonerId" ])
263
287
sleep (2 )
264
288
return True
265
289
except LCUError as e :
266
290
log .warning (e )
267
- log .warning (' Honor Failure' )
291
+ log .warning (" Honor Failure" )
268
292
return False
269
293
270
294
def end_of_game (self ) -> None :
@@ -273,7 +297,7 @@ def end_of_game(self) -> None:
273
297
posted = False
274
298
for i in range (15 ):
275
299
try :
276
- if self .api .get_phase () != ' EndOfGame' :
300
+ if self .api .get_phase () != " EndOfGame" :
277
301
return
278
302
if not posted :
279
303
self .api .play_again ()
@@ -289,8 +313,8 @@ def account_leveled(self) -> bool:
289
313
"""Checks if account has reached max level."""
290
314
try :
291
315
if self .api .get_summoner_level () >= self .max_level :
292
- if self .account [' username' ] == self .api .get_display_name ():
293
- self .account [' level' ] = self .max_level
316
+ if self .account [" username" ] == self .api .get_display_name ():
317
+ self .account [" level" ] = self .max_level
294
318
accounts .save_or_add (self .account )
295
319
log .info ("Account successfully leveled" )
296
320
return True
@@ -312,23 +336,25 @@ def wait_for_patching(self) -> None:
312
336
def set_game_config (self ) -> None :
313
337
"""Overwrites the League of Legends game config."""
314
338
log .info ("Overwriting game configs" )
315
- path = self .league_dir + ' /Config/game.cfg'
339
+ path = self .league_dir + " /Config/game.cfg"
316
340
folder = os .path .abspath (os .path .join (path , os .pardir ))
317
341
for filename in os .listdir (folder ):
318
342
file_path = os .path .join (folder , filename )
319
343
try :
320
344
if os .path .isfile (file_path ) or os .path .islink (file_path ):
321
345
os .unlink (file_path )
322
346
except Exception as e :
323
- log .error (' Failed to delete %s. Reason: %s' % (file_path , e ))
347
+ log .error (" Failed to delete %s. Reason: %s" % (file_path , e ))
324
348
shutil .copy (proc .resource_path (config .GAME_CFG ), path )
325
349
326
350
@staticmethod
327
351
def print_ascii () -> None :
328
352
"""Prints some League ascii art."""
329
- print ("""\n \n
353
+ print (
354
+ """\n \n
330
355
──────▄▌▐▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▌
331
356
───▄▄██▌█ BEEP BEEP
332
357
▄▄▄▌▐██▌█ -15 LP DELIVERY
333
358
███████▌█▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▌
334
- ▀(⊙)▀▀▀▀▀▀▀(⊙)(⊙)▀▀▀▀▀▀▀▀▀▀(⊙)\n \n \t \t \t \t LoL Bot\n \n """ )
359
+ ▀(⊙)▀▀▀▀▀▀▀(⊙)(⊙)▀▀▀▀▀▀▀▀▀▀(⊙)\n \n \t \t \t \t LoL Bot\n \n """
360
+ )
0 commit comments