Module livemelee.bots
Collection of bot classes to extend.
Expand source code
'''Collection of bot classes to extend.'''
import melee
from melee import MenuHelper, Menu
import random
import time
from . import inputs as Inputs
from . import utils
import inspect
Buttons = melee.enums.Button
Actions = melee.enums.Action
DEFAULT_CHAR = melee.Character.FOX
DEFAULT_STAGE = melee.Stage.FINAL_DESTINATION
def _set_random_analogs(controller):
# preparing for port detection
x, y, L = ( round(random.random(), 2) for _ in range(3) )
# stick = (True, Buttons.BUTTON_MAIN, x, y)
# trigger = (True, Buttons.BUTTON_L, L)
# frame1_seq = [(stick, trigger,)]
print(x, y, L)
controller.tilt_analog(Buttons.BUTTON_MAIN, x, y)
controller.press_shoulder(Buttons.BUTTON_L, L)
return x, y, L
def _get_analogs(controller_state):
# during port detection
x, y = controller_state.main_stick
L = controller_state.l_shoulder
return x, y, L
class _PortBot:
def __init__(self):
self.controller = None
self.character = DEFAULT_CHAR
self.stage = DEFAULT_STAGE
self._finished_stage = False
self._last_gamestate = None
def act(self, gamestate):
self._last_gamestate = gamestate
if utils.in_game(gamestate):
# if gamestate.frame == -1: #-123: # first frame (i think)
# self._detect_ports(gamestate)
if gamestate.frame == -1: #-123: # first frame (i think)
self._vals = _set_random_analogs(self.controller)
elif gamestate.frame == 0:
self._detect_ports(gamestate)
else:
self.play_frame(gamestate)
else:
self._menu_nav(gamestate)
def _menu_nav(self, gamestate):
# normal menu helper except set rand inputs for frame 1 port detection after last step (selecting stage)
# copypasted from melee.menu_helper_simple
# If we're at the character select screen, choose our character
if gamestate.menu_state in (Menu.CHARACTER_SELECT, Menu.SLIPPI_ONLINE_CSS):
if gamestate.submenu == melee.SubMenu.NAME_ENTRY_SUBMENU:
MenuHelper.name_tag_index = MenuHelper.enter_direct_code(gamestate=gamestate,
controller=self.controller,
# connect_code=connect_code,
index=melee.MenuHelper.name_tag_index)
else:
MenuHelper.choose_character(character=self.character,
gamestate=gamestate,
controller=self.controller,
# cpu_level=cpu_level,
# costume=costume,
# swag=swag,
start=True)#autostart)
# If we're at the postgame scores screen, spam START
elif gamestate.menu_state == Menu.POSTGAME_SCORES:
MenuHelper.skip_postgame(controller=self.controller)
# If we're at the stage select screen, choose a stage
elif gamestate.menu_state == Menu.STAGE_SELECT and not self._finished_stage:
## new insert, not in libmelee
# listen for A press on controller, signaling about to start game
if self.controller.current.button[Buttons.BUTTON_A]:
# self._vals = _set_random_analogs(self.controller)
self._finished_stage = True
else:
# normal from libmelee
MenuHelper.choose_stage(stage=self.stage,
gamestate=gamestate,
controller=self.controller)
elif gamestate.menu_state == Menu.MAIN_MENU:
# if connect_code:
# MenuHelper.choose_direct_online(gamestate=gamestate, controller=self.controller)
# else:
# MenuHelper.choose_versus_mode(gamestate=gamestate, controller=self.controller)
MenuHelper.choose_versus_mode(gamestate=gamestate, controller=self.controller)
def _detect_ports(self, gamestate):
# returns port num for this bot and opponent, eg. (1,2).
# needs to be in game
# - set stick, L/R to random values
# - first frame of game, check gamestate controller states to find matching vals
# unlikely that the other player has the same analog vals.
# set controller after choosing stage? that way frame 1 of game is checking and releasing,
# as opposed to frame 1 setting and frame 2 checking + releasing, leaving f3 actionable.
# will this buffer any inputs?
# what's the float precision in controller state?
mine = -1
other = -1
print('detecting..')
# self._vals = _set_random_analogs(controller)
for port, pstate in gamestate.player.items():
these_vals = _get_analogs(pstate.controller_state)
print(these_vals) #
if self._vals == these_vals:
mine = port
else:
other = port
self.ports = (mine, other)
return mine, other
def get_controller_state(self):
return 'From controller: {}\nFrom gamestate: {}'.format(
utils.loggable_controller(self.controller.current),
utils.get_controller(self._last_gamestate, 1) )
def play_frame(self, gamestate):
pass
class Bot:
'''Framework for making controller inputs according to gamestate.
Offline only implementation currently.
Attributes:
controller: melee.Controller
character: melee.Character
stage: melee.Stage'''
def __init__(self, controller=None,
character=DEFAULT_CHAR,
stage=DEFAULT_STAGE):
self.controller = controller
self.character = character
self.stage = stage
def act(self, gamestate):
'''Main function called each frame of game loop with updated gamestate.'''
# if gamestate.menu_state in (melee.Menu.IN_GAME,
# melee.Menu.SUDDEN_DEATH):
if utils.in_game(gamestate):
self.play_frame(gamestate) # rand note, paused wont advance frame
else:
self.menu_nav(gamestate)
def menu_nav(self, gamestate):
'''Processes menus with given character, stage.'''
melee.MenuHelper.menu_helper_simple(gamestate,
self.controller,
self.character,
self.stage,
'', # connect code
0, # cpu_level (0 for N/A)
0, # costume
autostart=True)
def play_frame(self, gamestate):
'''Bot game logic implemented here.'''
pass
def always(gamestate):
return True
def never(gamestate):
return False
class InputsBot(Bot):
'''Adds inputs queue to Bot.
Inputs should be always put into queue,
never called directly/instantly with controller.
First queued input will happen same frame of queueing.
Attributes:
queue: list of inputs as outlined in inputs.py'''
def __init__(self, controller=None,
character=DEFAULT_CHAR,
stage=DEFAULT_STAGE):
super().__init__(controller, character, stage)
self.queue = []
def play_frame(self, gamestate):
self.check_frame(gamestate)
self.consume_next_inputs()
def consume_next_inputs(self):
'''Called each frame to press or release next buttons in queue.
See inputs.py for expected inputs format.'''
if self.queue:
inputs = self.queue.pop(0)
Inputs.make_inputs(inputs, self.controller)
def perform(self, input_sequence):
'''Set queue to a sequence of inputs.
Useful in lambdas where assignment is not allowed.'''
self.queue = list(input_sequence) # need a (deep) copy for modifiable lists/tuples
def check_frame(self, gamestate):
'''Override this (instead of overriding play_frame).
Decision making and input queueing happen here.'''
pass
class CheckBot(InputsBot):
'''Adds condition checker to main loop.
Attributes:
when: (ie trigger) a condition checked every frame (func taking gamestate)
do: (ie on_trigger) func called when condition returns True
By default, stops checking upon reaching condition.
`set_timer()` is an example of using `when` and `do`.
Eg.
`self.repeat(when=self.finished_inputs, do=some_func)`'''
def __init__(self, controller=None,
character=DEFAULT_CHAR,
stage=DEFAULT_STAGE):
super().__init__(controller, character, stage)
self.when = never
self.do = lambda:None
self._max_time = 30 # arbitrary init
self._timer = self._max_time
def check_frame(self, gamestate):
'''Called each frame to check gamestate (and/or possibly self?) for condition,
stopping check when True.'''
if self.when(gamestate):
self.when = never
self.do()
def set_timer(self, n, do, repeat=True):
'''Set all required timer functions:
n frames to wait, timer condition, callback.'''
self._max_time = n
self._timer = self._max_time
if repeat:
self.repeat(when=self._times_up,
do=do)
else:
self.when = self._times_up
self.do = do
def _times_up(self, gamestate):
'''A condition check that ticks timer, returning True on expire.'''
if self._timer > 0:
self._timer -= 1
return False
else:
self._timer = self._max_time
return True
def repeat(self, when, do):
'''Keeps checking when condition (as opposed to the default stop checking).'''
def do_and_wait_again():
do()
self.when = when
self.when = when
self.do = do_and_wait_again
def finished_inputs(self, gamestate):
'''A condition to loop inputs by returning True when queue is empty.
Eg.
```
self.when = self.finished_inputs
self.do = something
```'''
return len(self.queue) == 0
class ControllableBot(InputsBot):
'''Designed to easily control externally in real time,
eg. from live thread or perhaps something like a chat.
Attributes:
commands: dict of `{'cmd': (func, 'description')}`
See LiveInputsThread for details.'''
def __init__(self, controller=None,
character=melee.Character.FALCO,
stage=DEFAULT_STAGE):
super().__init__(controller, character, stage)
self.commands = self._init_commands()
self._curr_sequence = []
def _init_commands(self):
commands = {cmd: self._set_seq(make_seq) for cmd, make_seq in {
'laser': Inputs.laser,
'sh': Inputs.shorthop,
'shlaser': Inputs.jump_n_laser, #fastfall_laser_rand
'taunt': Inputs.taunt,
'shield': Inputs.shield,
'dd': Inputs.dashdance,
}.items()}
commands.update({cmd: self._set_seq(_make_seq(btn)) for cmd, btn in {
'release': Inputs.release,
'center': Inputs.center,
'down': Inputs.down,
'up': Inputs.up,
'left': Inputs.left,
'right': Inputs.right,
'A': Inputs.A,
'B': Inputs.B,
'Y': Inputs.Y,
'L': Inputs.L
}.items()})
# commands.update({
# 'undo': self.release_last,
# })
return commands
def _set_seq(self, make_seq):
# wrapper to set current sequence to result of sequence maker func
return lambda: self.set_curr_seq(make_seq())
def set_curr_seq(self, inputs):
self._curr_sequence = inputs# [(Inputs.release,), *inputs]
def add_to_queue(self, inputs):
# add to any existing inputs (usually would replace them)
self.queue.extend(inputs)
def check_frame(self, gamestate):
# keep doing current sequence, looping if finished
if len(self.queue) == 0:
self.perform(self._curr_sequence)
# if self.timer == 0:
# self.queue = Inputs.laser
def _make_seq(button):
# wrapper to put single button press into a sequence
return lambda: [(button,),]
class FalcoBot(CheckBot):
# working with previous features
def __init__(self):
super().__init__(character=melee.Character.FALCO)
# self.investigate_jumpframes()
self.jumped = False
self.set_shorthop_laser_strat()
def set_standing_laser_strat(self):
self.set_timer(2, lambda: self.perform(Inputs.laser()), repeat=True)
# self.repeat(when=self.finished_inputs,
# do=lambda: self.perform(laser))
def set_shorthop_laser_strat(self):
self.jumped = False
self.repeat(when=self.can_jump,
do=self.sh_laser)
def set_jump_strat(self):
self.jumped = False
self.repeat(when=self.can_jump,
do=self.jump)
def can_jump(self, gamestate):
if utils.grounded(gamestate):
if self.jumped:
return False
else:
return True
else:
self.jumped = False # safe to reset now
return False
def sh_laser(self):
self.perform([*Inputs.wait(3), *Inputs.fastfall_laser_rand()])
self.jumped = True
def jump(self):
self.perform([*Inputs.wait(3), *Inputs.shorthop()])
self.jumped = True
### example of finding out frame data
def investigate_jumpframes(self):
self.prepause = 0
self.jumped = False
self.max_time = 45
def timer_checking_jump(gamestate):
if self.timer < 0:
# print('timer up')
title = 'prepause {} f,'.format(self.prepause)
if self.jumped:
print(title, 'success')
# self.when = never
# return True
else:
print(title, 'fail')
# reset everything and inc pause frames
self.timer = self.max_time
self.prepause += 1
self.jumped = False
return True
else:
self.timer -= 1
if not utils.grounded(gamestate):
self.jumped = True # should be success but just let timer tick
return False
self.repeat(when=timer_checking_jump,
do=self.jump_with_wait)
def jump_with_wait(self):
self.perform([*Inputs.wait(self.prepause), *Inputs.shorthop()])
### toxic demos, use responsibly
def taunt(self):
# interrupt activities to taunt asap.
# keeps setting queue until taunting actually happens
# self.last_when = self.when
self.when = utils.not_taunting
self.do = lambda: self.perform([(Inputs.release,), *Inputs.taunt()])
def ragequit(self): #, angry_misinput=True):
# special pause case: frames not advanced in pause, so we have to
# independently execute multiple presses outside of main loop.
# generally poor use of inputs and lack of queue.
inputs = [
(True, Buttons.BUTTON_START),
(True, Buttons.BUTTON_L),
(True, Buttons.BUTTON_R),
(True, Buttons.BUTTON_A),
]
self.controller.release_all()
for press, *button_args in inputs:
self.controller.press_button(*button_args)
time.sleep(0.01) # could be needed if incosistent timing?
# under construction:
def _with_ports(self, func):
def stat_with_ports(gamestate):
return func(gamestate, self.my_port, self.opp_port)
return stat_with_ports
def _detect_ports(self, gamestate):
# melee.GameState.port_detector(gamestate, self.character, self.costume)
players = gamestate.player.items()
#
Functions
def always(gamestate)
-
Expand source code
def always(gamestate): return True
def never(gamestate)
-
Expand source code
def never(gamestate): return False
Classes
class Bot (controller=None, character=Character.FOX, stage=Stage.FINAL_DESTINATION)
-
Framework for making controller inputs according to gamestate. Offline only implementation currently.
Attributes
controller
- melee.Controller
character
- melee.Character
stage
- melee.Stage
Expand source code
class Bot: '''Framework for making controller inputs according to gamestate. Offline only implementation currently. Attributes: controller: melee.Controller character: melee.Character stage: melee.Stage''' def __init__(self, controller=None, character=DEFAULT_CHAR, stage=DEFAULT_STAGE): self.controller = controller self.character = character self.stage = stage def act(self, gamestate): '''Main function called each frame of game loop with updated gamestate.''' # if gamestate.menu_state in (melee.Menu.IN_GAME, # melee.Menu.SUDDEN_DEATH): if utils.in_game(gamestate): self.play_frame(gamestate) # rand note, paused wont advance frame else: self.menu_nav(gamestate) def menu_nav(self, gamestate): '''Processes menus with given character, stage.''' melee.MenuHelper.menu_helper_simple(gamestate, self.controller, self.character, self.stage, '', # connect code 0, # cpu_level (0 for N/A) 0, # costume autostart=True) def play_frame(self, gamestate): '''Bot game logic implemented here.''' pass
Subclasses
Methods
def act(self, gamestate)
-
Main function called each frame of game loop with updated gamestate.
Expand source code
def act(self, gamestate): '''Main function called each frame of game loop with updated gamestate.''' # if gamestate.menu_state in (melee.Menu.IN_GAME, # melee.Menu.SUDDEN_DEATH): if utils.in_game(gamestate): self.play_frame(gamestate) # rand note, paused wont advance frame else: self.menu_nav(gamestate)
-
Processes menus with given character, stage.
Expand source code
def menu_nav(self, gamestate): '''Processes menus with given character, stage.''' melee.MenuHelper.menu_helper_simple(gamestate, self.controller, self.character, self.stage, '', # connect code 0, # cpu_level (0 for N/A) 0, # costume autostart=True)
def play_frame(self, gamestate)
-
Bot game logic implemented here.
Expand source code
def play_frame(self, gamestate): '''Bot game logic implemented here.''' pass
class CheckBot (controller=None, character=Character.FOX, stage=Stage.FINAL_DESTINATION)
-
Adds condition checker to main loop.
Attributes
when
- (ie trigger) a condition checked every frame (func taking gamestate)
do
- (ie on_trigger) func called when condition returns True
By default, stops checking upon reaching condition.
set_timer()
is an example of usingwhen
anddo
.Eg.
self.repeat(when=self.finished_inputs, do=some_func)
Expand source code
class CheckBot(InputsBot): '''Adds condition checker to main loop. Attributes: when: (ie trigger) a condition checked every frame (func taking gamestate) do: (ie on_trigger) func called when condition returns True By default, stops checking upon reaching condition. `set_timer()` is an example of using `when` and `do`. Eg. `self.repeat(when=self.finished_inputs, do=some_func)`''' def __init__(self, controller=None, character=DEFAULT_CHAR, stage=DEFAULT_STAGE): super().__init__(controller, character, stage) self.when = never self.do = lambda:None self._max_time = 30 # arbitrary init self._timer = self._max_time def check_frame(self, gamestate): '''Called each frame to check gamestate (and/or possibly self?) for condition, stopping check when True.''' if self.when(gamestate): self.when = never self.do() def set_timer(self, n, do, repeat=True): '''Set all required timer functions: n frames to wait, timer condition, callback.''' self._max_time = n self._timer = self._max_time if repeat: self.repeat(when=self._times_up, do=do) else: self.when = self._times_up self.do = do def _times_up(self, gamestate): '''A condition check that ticks timer, returning True on expire.''' if self._timer > 0: self._timer -= 1 return False else: self._timer = self._max_time return True def repeat(self, when, do): '''Keeps checking when condition (as opposed to the default stop checking).''' def do_and_wait_again(): do() self.when = when self.when = when self.do = do_and_wait_again def finished_inputs(self, gamestate): '''A condition to loop inputs by returning True when queue is empty. Eg. ``` self.when = self.finished_inputs self.do = something ```''' return len(self.queue) == 0
Ancestors
Subclasses
Methods
def check_frame(self, gamestate)
-
Called each frame to check gamestate (and/or possibly self?) for condition, stopping check when True.
Expand source code
def check_frame(self, gamestate): '''Called each frame to check gamestate (and/or possibly self?) for condition, stopping check when True.''' if self.when(gamestate): self.when = never self.do()
def finished_inputs(self, gamestate)
-
A condition to loop inputs by returning True when queue is empty.
Eg.
self.when = self.finished_inputs self.do = something
Expand source code
def finished_inputs(self, gamestate): '''A condition to loop inputs by returning True when queue is empty. Eg. ``` self.when = self.finished_inputs self.do = something ```''' return len(self.queue) == 0
def repeat(self, when, do)
-
Keeps checking when condition (as opposed to the default stop checking).
Expand source code
def repeat(self, when, do): '''Keeps checking when condition (as opposed to the default stop checking).''' def do_and_wait_again(): do() self.when = when self.when = when self.do = do_and_wait_again
def set_timer(self, n, do, repeat=True)
-
Set all required timer functions: n frames to wait, timer condition, callback.
Expand source code
def set_timer(self, n, do, repeat=True): '''Set all required timer functions: n frames to wait, timer condition, callback.''' self._max_time = n self._timer = self._max_time if repeat: self.repeat(when=self._times_up, do=do) else: self.when = self._times_up self.do = do
Inherited members
class ControllableBot (controller=None, character=Character.FALCO, stage=Stage.FINAL_DESTINATION)
-
Designed to easily control externally in real time, eg. from live thread or perhaps something like a chat.
Attributes
commands
- dict of
{'cmd': (func, 'description')}
See LiveInputsThread for details.
Expand source code
class ControllableBot(InputsBot): '''Designed to easily control externally in real time, eg. from live thread or perhaps something like a chat. Attributes: commands: dict of `{'cmd': (func, 'description')}` See LiveInputsThread for details.''' def __init__(self, controller=None, character=melee.Character.FALCO, stage=DEFAULT_STAGE): super().__init__(controller, character, stage) self.commands = self._init_commands() self._curr_sequence = [] def _init_commands(self): commands = {cmd: self._set_seq(make_seq) for cmd, make_seq in { 'laser': Inputs.laser, 'sh': Inputs.shorthop, 'shlaser': Inputs.jump_n_laser, #fastfall_laser_rand 'taunt': Inputs.taunt, 'shield': Inputs.shield, 'dd': Inputs.dashdance, }.items()} commands.update({cmd: self._set_seq(_make_seq(btn)) for cmd, btn in { 'release': Inputs.release, 'center': Inputs.center, 'down': Inputs.down, 'up': Inputs.up, 'left': Inputs.left, 'right': Inputs.right, 'A': Inputs.A, 'B': Inputs.B, 'Y': Inputs.Y, 'L': Inputs.L }.items()}) # commands.update({ # 'undo': self.release_last, # }) return commands def _set_seq(self, make_seq): # wrapper to set current sequence to result of sequence maker func return lambda: self.set_curr_seq(make_seq()) def set_curr_seq(self, inputs): self._curr_sequence = inputs# [(Inputs.release,), *inputs] def add_to_queue(self, inputs): # add to any existing inputs (usually would replace them) self.queue.extend(inputs) def check_frame(self, gamestate): # keep doing current sequence, looping if finished if len(self.queue) == 0: self.perform(self._curr_sequence)
Ancestors
Methods
def add_to_queue(self, inputs)
-
Expand source code
def add_to_queue(self, inputs): # add to any existing inputs (usually would replace them) self.queue.extend(inputs)
def set_curr_seq(self, inputs)
-
Expand source code
def set_curr_seq(self, inputs): self._curr_sequence = inputs# [(Inputs.release,), *inputs]
Inherited members
class FalcoBot
-
Adds condition checker to main loop.
Attributes
when
- (ie trigger) a condition checked every frame (func taking gamestate)
do
- (ie on_trigger) func called when condition returns True
By default, stops checking upon reaching condition.
set_timer()
is an example of usingwhen
anddo
.Eg.
self.repeat(when=self.finished_inputs, do=some_func)
Expand source code
class FalcoBot(CheckBot): # working with previous features def __init__(self): super().__init__(character=melee.Character.FALCO) # self.investigate_jumpframes() self.jumped = False self.set_shorthop_laser_strat() def set_standing_laser_strat(self): self.set_timer(2, lambda: self.perform(Inputs.laser()), repeat=True) # self.repeat(when=self.finished_inputs, # do=lambda: self.perform(laser)) def set_shorthop_laser_strat(self): self.jumped = False self.repeat(when=self.can_jump, do=self.sh_laser) def set_jump_strat(self): self.jumped = False self.repeat(when=self.can_jump, do=self.jump) def can_jump(self, gamestate): if utils.grounded(gamestate): if self.jumped: return False else: return True else: self.jumped = False # safe to reset now return False def sh_laser(self): self.perform([*Inputs.wait(3), *Inputs.fastfall_laser_rand()]) self.jumped = True def jump(self): self.perform([*Inputs.wait(3), *Inputs.shorthop()]) self.jumped = True ### example of finding out frame data def investigate_jumpframes(self): self.prepause = 0 self.jumped = False self.max_time = 45 def timer_checking_jump(gamestate): if self.timer < 0: # print('timer up') title = 'prepause {} f,'.format(self.prepause) if self.jumped: print(title, 'success') # self.when = never # return True else: print(title, 'fail') # reset everything and inc pause frames self.timer = self.max_time self.prepause += 1 self.jumped = False return True else: self.timer -= 1 if not utils.grounded(gamestate): self.jumped = True # should be success but just let timer tick return False self.repeat(when=timer_checking_jump, do=self.jump_with_wait) def jump_with_wait(self): self.perform([*Inputs.wait(self.prepause), *Inputs.shorthop()]) ### toxic demos, use responsibly def taunt(self): # interrupt activities to taunt asap. # keeps setting queue until taunting actually happens # self.last_when = self.when self.when = utils.not_taunting self.do = lambda: self.perform([(Inputs.release,), *Inputs.taunt()]) def ragequit(self): #, angry_misinput=True): # special pause case: frames not advanced in pause, so we have to # independently execute multiple presses outside of main loop. # generally poor use of inputs and lack of queue. inputs = [ (True, Buttons.BUTTON_START), (True, Buttons.BUTTON_L), (True, Buttons.BUTTON_R), (True, Buttons.BUTTON_A), ] self.controller.release_all() for press, *button_args in inputs: self.controller.press_button(*button_args) time.sleep(0.01) # could be needed if incosistent timing?
Ancestors
Methods
def can_jump(self, gamestate)
-
Expand source code
def can_jump(self, gamestate): if utils.grounded(gamestate): if self.jumped: return False else: return True else: self.jumped = False # safe to reset now return False
def investigate_jumpframes(self)
-
Expand source code
def investigate_jumpframes(self): self.prepause = 0 self.jumped = False self.max_time = 45 def timer_checking_jump(gamestate): if self.timer < 0: # print('timer up') title = 'prepause {} f,'.format(self.prepause) if self.jumped: print(title, 'success') # self.when = never # return True else: print(title, 'fail') # reset everything and inc pause frames self.timer = self.max_time self.prepause += 1 self.jumped = False return True else: self.timer -= 1 if not utils.grounded(gamestate): self.jumped = True # should be success but just let timer tick return False self.repeat(when=timer_checking_jump, do=self.jump_with_wait)
def jump(self)
-
Expand source code
def jump(self): self.perform([*Inputs.wait(3), *Inputs.shorthop()]) self.jumped = True
def jump_with_wait(self)
-
Expand source code
def jump_with_wait(self): self.perform([*Inputs.wait(self.prepause), *Inputs.shorthop()])
def ragequit(self)
-
Expand source code
def ragequit(self): #, angry_misinput=True): # special pause case: frames not advanced in pause, so we have to # independently execute multiple presses outside of main loop. # generally poor use of inputs and lack of queue. inputs = [ (True, Buttons.BUTTON_START), (True, Buttons.BUTTON_L), (True, Buttons.BUTTON_R), (True, Buttons.BUTTON_A), ] self.controller.release_all() for press, *button_args in inputs: self.controller.press_button(*button_args) time.sleep(0.01) # could be needed if incosistent timing?
def set_jump_strat(self)
-
Expand source code
def set_jump_strat(self): self.jumped = False self.repeat(when=self.can_jump, do=self.jump)
def set_shorthop_laser_strat(self)
-
Expand source code
def set_shorthop_laser_strat(self): self.jumped = False self.repeat(when=self.can_jump, do=self.sh_laser)
def set_standing_laser_strat(self)
-
Expand source code
def set_standing_laser_strat(self): self.set_timer(2, lambda: self.perform(Inputs.laser()), repeat=True)
def sh_laser(self)
-
Expand source code
def sh_laser(self): self.perform([*Inputs.wait(3), *Inputs.fastfall_laser_rand()]) self.jumped = True
def taunt(self)
-
Expand source code
def taunt(self): # interrupt activities to taunt asap. # keeps setting queue until taunting actually happens # self.last_when = self.when self.when = utils.not_taunting self.do = lambda: self.perform([(Inputs.release,), *Inputs.taunt()])
Inherited members
class InputsBot (controller=None, character=Character.FOX, stage=Stage.FINAL_DESTINATION)
-
Adds inputs queue to Bot.
Inputs should be always put into queue, never called directly/instantly with controller. First queued input will happen same frame of queueing.
Attributes
queue
- list of inputs as outlined in inputs.py
Expand source code
class InputsBot(Bot): '''Adds inputs queue to Bot. Inputs should be always put into queue, never called directly/instantly with controller. First queued input will happen same frame of queueing. Attributes: queue: list of inputs as outlined in inputs.py''' def __init__(self, controller=None, character=DEFAULT_CHAR, stage=DEFAULT_STAGE): super().__init__(controller, character, stage) self.queue = [] def play_frame(self, gamestate): self.check_frame(gamestate) self.consume_next_inputs() def consume_next_inputs(self): '''Called each frame to press or release next buttons in queue. See inputs.py for expected inputs format.''' if self.queue: inputs = self.queue.pop(0) Inputs.make_inputs(inputs, self.controller) def perform(self, input_sequence): '''Set queue to a sequence of inputs. Useful in lambdas where assignment is not allowed.''' self.queue = list(input_sequence) # need a (deep) copy for modifiable lists/tuples def check_frame(self, gamestate): '''Override this (instead of overriding play_frame). Decision making and input queueing happen here.''' pass
Ancestors
Subclasses
Methods
def check_frame(self, gamestate)
-
Override this (instead of overriding play_frame). Decision making and input queueing happen here.
Expand source code
def check_frame(self, gamestate): '''Override this (instead of overriding play_frame). Decision making and input queueing happen here.''' pass
def consume_next_inputs(self)
-
Called each frame to press or release next buttons in queue. See inputs.py for expected inputs format.
Expand source code
def consume_next_inputs(self): '''Called each frame to press or release next buttons in queue. See inputs.py for expected inputs format.''' if self.queue: inputs = self.queue.pop(0) Inputs.make_inputs(inputs, self.controller)
def perform(self, input_sequence)
-
Set queue to a sequence of inputs. Useful in lambdas where assignment is not allowed.
Expand source code
def perform(self, input_sequence): '''Set queue to a sequence of inputs. Useful in lambdas where assignment is not allowed.''' self.queue = list(input_sequence) # need a (deep) copy for modifiable lists/tuples
Inherited members