def step(self, gamestate, smashbot_state, opponent_state): self._propagate = (gamestate, smashbot_state, opponent_state) #If we can't interrupt the chain, just continue it if self.chain != None and not self.chain.interruptible: self.chain.step(gamestate, smashbot_state, opponent_state) return needswavedash = smashbot_state.action in [Action.DOWN_B_GROUND, Action.DOWN_B_STUN, \ Action.DOWN_B_GROUND_START, Action.LANDING_SPECIAL, Action.SHIELD, Action.SHIELD_START, \ Action.SHIELD_RELEASE, Action.SHIELD_STUN, Action.SHIELD_REFLECT] if needswavedash: self.pickchain(Chains.Wavedash) return # If opponent is on a side platform and we're not on_main_platform = smashbot_state.position.y < 1 and smashbot_state.on_ground if opponent_state.position.y > 1 and opponent_state.on_ground and on_main_platform and gamestate.stage != melee.enums.Stage.FOUNTAIN_OF_DREAMS: self.pickchain(Chains.BoardSidePlatform, [opponent_state.position.x > 0]) return # If opponent is on top platform on_side_platform = (5 < smashbot_state.position.y < 35) and smashbot_state.on_ground top_platform_height, top_platform_left, top_platform_right = melee.top_platform_position( gamestate.stage) opp_top_platform = False if top_platform_height is not None: opp_top_platform = ( opponent_state.position.y + 1 >= top_platform_height) and ( top_platform_left < opponent_state.position.x < top_platform_right) if on_side_platform and opp_top_platform: self.pickchain(Chains.BoardTopPlatform) return # Jump over Samus Bomb samus_bomb = opponent_state.character == Character.SAMUS and opponent_state.action == Action.SWORD_DANCE_4_MID # Falcon rapid jab falcon_rapid_jab = opponent_state.action == Action.LOOPING_ATTACK_MIDDLE # Are they facing the right way, though? facing_wrong_way = opponent_state.facing != ( opponent_state.position.x < smashbot_state.position.x) if (samus_bomb or falcon_rapid_jab) and opponent_state.position.y < 5: landing_spot = opponent_state.position.x if opponent_state.position.x < smashbot_state.position.x: landing_spot -= 10 else: landing_spot += 10 # Don't jump off the stage if abs(landing_spot) < melee.stages.EDGE_GROUND_POSITION[ gamestate.stage] and not facing_wrong_way: self.pickchain(Chains.JumpOver, [landing_spot]) return self.chain = None self.pickchain(Chains.DashDance, [opponent_state.position.x])
def step(self, gamestate, smashbot_state, opponent_state): platform_center = 0 platform_height = 0 plat_position = melee.top_platform_position(gamestate.stage) if plat_position: platform_center = (plat_position[1] + plat_position[2]) / 2 platform_height = plat_position[0] else: self.interruptible = True self.controller.empty_input() return on_side_platform = smashbot_state.on_ground and smashbot_state.position.y > 5 above_top_platform = (not smashbot_state.on_ground) and (smashbot_state.position.y + smashbot_state.ecb.bottom.y > platform_height) and \ plat_position[1] < smashbot_state.position.x < plat_position[2] if smashbot_state.on_ground and smashbot_state.action != Action.KNEE_BEND: self.interruptible = True if on_side_platform: self.interruptible = True self.controller.empty_input() return # If we're crouching, release holding Y if smashbot_state.action == Action.KNEE_BEND: self.controller.release_button(melee.Button.BUTTON_Y) self.interruptible = False return # Don't jump into Peach's dsmash or SH early dair spam dsmashactive = opponent_state.action == Action.DOWNSMASH and opponent_state.action_frame <= 22 if opponent_state.action == Action.DAIR or dsmashactive: self.interruptible = True self.controller.press_button(melee.Button.BUTTON_L) self.controller.tilt_analog(melee.Button.BUTTON_MAIN, 0.5, 0) return jump_frame = 30 if gamestate.stage == Stage.BATTLEFIELD: jump_frame = 14 if gamestate.stage == Stage.DREAMLAND: jump_frame = 16 if gamestate.stage == Stage.YOSHIS_STORY: jump_frame = 21 # Double jump if smashbot_state.action in [ Action.JUMPING_FORWARD, Action.JUMPING_BACKWARD ]: if smashbot_state.action_frame == jump_frame: if random.randint(0, 3) == 0: self.controller.press_button(melee.Button.BUTTON_Y) self.controller.tilt_analog(melee.Button.BUTTON_MAIN, 0.5, 0.5) self.interruptible = False return else: self.controller.tilt_analog(melee.Button.BUTTON_MAIN, 0.5, 0) return # Drift into opponent if smashbot_state.action in [ Action.JUMPING_ARIAL_FORWARD, Action.JUMPING_ARIAL_BACKWARD, Action.JUMPING_FORWARD, Action.JUMPING_BACKWARD ]: self.interruptible = False self.controller.release_button(melee.Button.BUTTON_Y) self.controller.tilt_analog( melee.Button.BUTTON_MAIN, int(smashbot_state.position.x < opponent_state.position.x), 0.5) return # Dash at the position of the opponent if smashbot_state.on_ground and smashbot_state.position.y < 10: self.interruptible = True pivotpoint = opponent_state.position.x pivotpoint = min(plat_position[2] - 7, pivotpoint) pivotpoint = max(plat_position[1] + 7, pivotpoint) if abs(smashbot_state.position.x - pivotpoint) < 5 and smashbot_state.action == Action.TURNING: self.interruptible = False self.controller.press_button(melee.Button.BUTTON_Y) return if smashbot_state.action == Action.TURNING and smashbot_state.action_frame == 1: return if smashbot_state.action == Action.DASHING and smashbot_state.action_frame >= 11: self.controller.tilt_analog(melee.Button.BUTTON_MAIN, int(not smashbot_state.facing), .5) return self.controller.tilt_analog( melee.Button.BUTTON_MAIN, int(smashbot_state.position.x < pivotpoint), 0.5) return self.controller.empty_input()
def step(self, gamestate, smashbot_state, opponent_state): self._propagate = (gamestate, smashbot_state, opponent_state) #If we can't interrupt the chain, just continue it if self.chain != None and not self.chain.interruptible: self.chain.step(gamestate, smashbot_state, opponent_state) return needswavedash = smashbot_state.action in [Action.DOWN_B_GROUND, Action.DOWN_B_STUN, \ Action.DOWN_B_GROUND_START, Action.LANDING_SPECIAL, Action.SHIELD, Action.SHIELD_START, \ Action.SHIELD_RELEASE, Action.SHIELD_STUN, Action.SHIELD_REFLECT] if needswavedash: self.pickchain(Chains.Wavedash, [True]) return # Are we behind in the game? losing = smashbot_state.stock < opponent_state.stock or ( smashbot_state.stock == opponent_state.stock and smashbot_state.percent > opponent_state.percent) opp_top_platform = False top_platform_height, top_platform_left, top_platform_right = melee.top_platform_position( gamestate.stage) if top_platform_height is not None: opp_top_platform = ( opponent_state.position.y + 1 >= top_platform_height) and ( top_platform_left - 1 < opponent_state.position.x < top_platform_right + 1) # If opponent is on a side platform and we're not on_main_platform = smashbot_state.position.y < 1 and smashbot_state.on_ground if not opp_top_platform: if opponent_state.position.y > 10 and opponent_state.on_ground and on_main_platform: self.pickchain(Chains.BoardSidePlatform, [opponent_state.position.x > 0]) return # If opponent is on top platform. Unless we're ahead. Then let them camp if opp_top_platform and losing and random.randint(0, 20) == 0: self.pickchain(Chains.BoardTopPlatform) return # Jump over Samus Bomb # TODO Don't jump on top of an existing bomb samus_bomb = opponent_state.character == Character.SAMUS and opponent_state.action == Action.SWORD_DANCE_4_MID if samus_bomb and opponent_state.position.y < 5: landing_spot = opponent_state.position.x if opponent_state.position.x < smashbot_state.position.x: landing_spot -= 10 else: landing_spot += 10 # Don't jump off the stage if abs(landing_spot) < melee.stages.EDGE_GROUND_POSITION[ gamestate.stage]: self.pickchain(Chains.JumpOver, [landing_spot]) return # SHFFL at opponent sometimes (33% chance per approach) if self.random_approach < 33: if not self.framedata.is_attack(opponent_state.character, opponent_state.action): # We need to be dashing towards our opponent. Not too close to the ledge vertical_distance = abs(smashbot_state.position.y - opponent_state.position.y) facing_opponent = smashbot_state.facing == ( smashbot_state.position.x < opponent_state.position.x) if smashbot_state.action == Action.DASHING and facing_opponent: if vertical_distance < 20 and gamestate.distance < 35 and abs( melee.stages.EDGE_GROUND_POSITION[gamestate.stage] - abs(smashbot_state.position.x)) > 35: self.pickchain(Chains.Shffl, [SHFFL_DIRECTION.NEUTRAL]) return self.chain = None self.pickchain(Chains.DashDance, [opponent_state.position.x])
def step(self, gamestate, smashbot_state, opponent_state): if self.logger: self.logger.log("Notes", " right side platform: " + str(self.right_platform) + " ", concat=True) platform_center = 0 platform_height, platform_left, platform_right = melee.side_platform_position( self.right_platform, gamestate.stage) if platform_height is not None: platform_center = (platform_left + platform_right) / 2 top_platform_height, _, _ = melee.top_platform_position( gamestate.stage) # Where to dash dance to pivot_point = platform_center # If opponent is on the platform, get right under them if platform_left < opponent_state.position.x < platform_right: pivot_point = opponent_state.position.x # Unless we don't need to attack them, then it's safe to just board asap if not self.attack and (platform_left < smashbot_state.position.x < platform_right): pivot_point = smashbot_state.position.x # If we're just using the side platform as a springboard, then go closer in than the middle if opponent_state.position.y >= top_platform_height: if smashbot_state.position.x > 0: pivot_point = platform_left + 8 else: pivot_point = platform_right - 8 if smashbot_state.on_ground: self.interruptible = True # If we're already on the platform, just do nothing. We shouldn't be here if smashbot_state.position.y > 5: self.controller.release_all() return # Are we in position to jump? if (abs(smashbot_state.position.x - pivot_point) < 5) and smashbot_state.action == Action.TURNING: self.interruptible = False self.controller.press_button(melee.Button.BUTTON_Y) return # If we're crouching, keep holding Y if smashbot_state.action == Action.KNEE_BEND: self.controller.press_button(melee.Button.BUTTON_Y) self.interruptible = False return # Jump out of shine if smashbot_state.action in [Action.DOWN_B_AIR]: self.controller.press_button(melee.Button.BUTTON_Y) return # Can we shine our opponent right now, while we're in the air? foxshinerange = 11.8 shineable = smashbot_state.action in [ Action.JUMPING_FORWARD, Action.JUMPING_BACKWARD ] if self.attack and shineable and gamestate.distance < foxshinerange: self.controller.press_button(melee.Button.BUTTON_B) self.controller.tilt_analog(melee.Button.BUTTON_MAIN, 0.5, 0) return # Waveland down aerials = [ Action.NAIR, Action.FAIR, Action.UAIR, Action.BAIR, Action.DAIR ] if smashbot_state.ecb.bottom.y + smashbot_state.position.y > platform_height and smashbot_state.action not in aerials: self.interruptible = True self.controller.press_button(melee.Button.BUTTON_L) # When we're choosing to not attack, just get close to the opponent if we're already x = int( smashbot_state.position.x < opponent_state.position.x) * 0.8 if not self.attack and abs(smashbot_state.position.x - opponent_state.position.x) < 5: x = 0.5 self.controller.tilt_analog(melee.Button.BUTTON_MAIN, x, 0) return # Don't jump into Peach's dsmash or SH early dair spam dsmashactive = opponent_state.action == Action.DOWNSMASH and opponent_state.action_frame <= 22 if shineable and (opponent_state.action == Action.DAIR or dsmashactive): self.interruptible = True self.controller.press_button(melee.Button.BUTTON_L) self.controller.tilt_analog(melee.Button.BUTTON_MAIN, 0.5, 0) return # If we see the opponent jump, they cannot protect themselves from uair. # Does not look for KNEE_BEND because Smashbot needs to discern between SH and FH y_afternineframes = opponent_state.position.y gravity = self.framedata.characterdata[ opponent_state.character]["Gravity"] y_speed = opponent_state.speed_y_self for i in range(1, 10): y_afternineframes += y_speed y_speed -= gravity aerialsminusdair = [Action.NAIR, Action.FAIR, Action.UAIR, Action.BAIR] if shineable and (opponent_state.action in [Action.JUMPING_FORWARD, Action.JUMPING_BACKWARD] or opponent_state.action in aerialsminusdair) and y_afternineframes < 50: self.controller.press_button(melee.Button.BUTTON_A) self.controller.tilt_analog(melee.Button.BUTTON_MAIN, 0.5, 1) return # Last resort, just dash at the center of the platform if smashbot_state.on_ground: self.interruptible = True #If we're starting the turn around animation, keep pressing that way or # else we'll get stuck in the slow turnaround if smashbot_state.action == Action.TURNING and smashbot_state.action_frame == 1: return #Dash back, since we're about to start running if smashbot_state.action == Action.DASHING and smashbot_state.action_frame >= 11: self.controller.tilt_analog(melee.Button.BUTTON_MAIN, int(not smashbot_state.facing), .5) return else: self.controller.tilt_analog( melee.Button.BUTTON_MAIN, int(smashbot_state.position.x < pivot_point), .5) return # Mash analog L presses to L-cancel if Smashbot is throwing out an aerial elif not smashbot_state.on_ground and smashbot_state.action in aerials: self.interruptible = False if gamestate.frame % 2 == 0: self.controller.press_shoulder(Button.BUTTON_L, 1) else: self.controller.press_shoulder(Button.BUTTON_L, 0) return else: self.controller.empty_input()
def step(self, gamestate, smashbot_state, opponent_state): self._propagate = (gamestate, smashbot_state, opponent_state) # If we can't interrupt the chain, just continue it if self.chain != None and not self.chain.interruptible: self.chain.step(gamestate, smashbot_state, opponent_state) return # Get over to where they will end up at the end of hitstun end_x, end_y = self.framedata.project_hit_location(opponent_state) frames_left = opponent_state.hitstun_frames_left if self.framedata.is_roll(opponent_state.character, opponent_state.action): end_x = self.framedata.roll_end_position(opponent_state, gamestate.stage) frames_left = self.framedata.last_roll_frame( opponent_state.character, opponent_state.action) - opponent_state.action_frame facing_away = (smashbot_state.position.x < end_x) != smashbot_state.facing if smashbot_state.action == Action.TURNING and smashbot_state.action_frame == 1: facing_away = not facing_away on_ground = opponent_state.on_ground or opponent_state.position.y < 1 or opponent_state.action in [ Action.TECH_MISS_UP, Action.TECH_MISS_DOWN ] # Make sure we don't dashdance off the platform during a juggle side_platform_height, side_platform_left, side_platform_right = melee.side_platform_position( smashbot_state.position.x > 0, gamestate.stage) top_platform_height, top_platform_left, top_platform_right = melee.top_platform_position( gamestate.stage) if smashbot_state.position.y < 5: end_x = min(end_x, melee.EDGE_GROUND_POSITION[gamestate.stage] - 5) end_x = max(end_x, -melee.EDGE_GROUND_POSITION[gamestate.stage] + 5) elif (side_platform_height is not None ) and abs(smashbot_state.position.y - side_platform_height) < 5: end_x = min(end_x, side_platform_right - 5) end_x = max(end_x, side_platform_left + 5) elif (top_platform_height is not None ) and abs(smashbot_state.position.y - top_platform_height) < 5: end_x = min(end_x, top_platform_right - 5) end_x = max(end_x, top_platform_left + 5) # TODO Slideoff detection if self.logger: self.logger.log("Notes", " Predicted End Position: " + str(end_x) + " " + str(end_y) + " ", concat=True) self.logger.log("Notes", " on_ground: " + str(on_ground), concat=True) self.logger.log("Notes", " frames left: " + str(frames_left) + " ", concat=True) # Need to pivot the uptilt # Uptilt's hitbox is pretty forgiving if we do it a few frames early, so no big deal there if not on_ground: # If we can just throw out an uptilt and hit now, do it. No need to wait for them to fall further end_early_x, end_early_y = self.framedata.project_hit_location( opponent_state, 7) if self.logger: self.logger.log("Notes", " uptilt early End Position: " + str(end_early_x) + " " + str(end_early_y) + " ", concat=True) in_range = (abs(end_early_x - smashbot_state.position.x) < 8) and ( abs(end_early_y - smashbot_state.position.y) < 12) if smashbot_state.action == Action.TURNING and in_range and ( 7 <= frames_left <= 9): self.pickchain(Chains.Tilt, [TILT_DIRECTION.UP]) return # Check each height level, can we do an up-air right now? for height_level in AirAttack.height_levels(): height = AirAttack.attack_height(height_level) commitment = AirAttack.frame_commitment(height) end_early_x, end_early_y = self.framedata.project_hit_location( opponent_state, commitment) if (commitment < frames_left) and ( abs(smashbot_state.position.x - end_early_x) < 20) and (abs(end_early_y - height) < 5): if self.logger: self.logger.log("Notes", " Early End Position: " + str(end_early_x) + " " + str(end_early_y) + " ", concat=True) self.logger.log("Notes", " height: " + str(height), concat=True) self.logger.log("Notes", " commitment: " + str(commitment), concat=True) self.chain = None self.pickchain( Chains.AirAttack, [end_early_x, end_early_y, AIR_ATTACK_DIRECTION.UP]) return # Just dash dance to where they will end up # TODO board platform to get closer? if frames_left > 9: self.chain = None self.pickchain(Chains.DashDance, [end_x]) return else: if self.framedata.is_roll(opponent_state.character, opponent_state.action): # We still have plenty of time, so just get closer to the DD spot # Even if we're already close if frames_left > 10: # Do we need to jump up to the side platform? side_plat_height, side_plat_left, side_plat_right = melee.side_platform_position( opponent_state.position.x > 0, gamestate.stage) # TODO 13 is the fastest getup attack of the legal character, do a lookup for the actual one if opponent_state.action in [ Action.TECH_MISS_UP, Action.TECH_MISS_DOWN ]: frames_left += 13 if side_plat_height is not None and ( frames_left > 25) and abs(side_plat_height - opponent_state.position.y) < 5: # But only if we're already mostly there smashbot_on_side_plat = smashbot_state.on_ground and abs( smashbot_state.position.y - side_plat_height) < 5 if side_plat_left < smashbot_state.position.x < side_plat_right: self.chain = None self.pickchain( Chains.BoardSidePlatform, [opponent_state.position.x > 0, False]) return if self.logger: self.logger.log("Notes", " DD at: " + str(end_x), concat=True) self.logger.log("Notes", " plat at: " + str(side_plat_left) + " " + str(side_plat_right), concat=True) self.chain = None self.pickchain(Chains.DashDance, [end_x]) return # We need to get to a position where our back is to the end position. We'll do a pivot stand to get there if (abs(smashbot_state.position.x - end_x) < 5): # Pivot if smashbot_state.action == Action.DASHING: self.chain = None self.pickchain(Chains.Run, [not smashbot_state.facing]) return if smashbot_state.action in [ Action.TURNING, Action.STANDING ]: if 7 <= frames_left <= 9: if facing_away and gamestate.distance < 20: self.pickchain(Chains.Tilt, [TILT_DIRECTION.UP]) return # Can't grab a tech miss. Don't try elif opponent_state.action not in [ Action.TECH_MISS_UP, Action.TECH_MISS_DOWN ] and gamestate.distance < 10: self.pickchain(Chains.GrabAndThrow, [THROW_DIRECTION.UP]) return if frames_left == 1 and gamestate.distance < 10: self.pickchain(Chains.Waveshine) return else: self.pickchain(Chains.Nothing) return # If we're a little further away than 5 units, but still in range elif (abs(smashbot_state.position.x - end_x) < 10): # Don't dashdance here. Just stand still if smashbot_state.action == Action.TURNING and smashbot_state.action_frame > 1: self.pickchain(Chains.Nothing) return self.chain = None self.pickchain(Chains.DashDance, [end_x]) return # We're further than 5 units away, so DD into their end position self.chain = None self.pickchain(Chains.DashDance, [end_x]) return self.chain = None self.pickchain(Chains.DashDance, [end_x])
def step(self, gamestate, smashbot_state, opponent_state): platform_center = 0 platform_height = 0 position = melee.top_platform_position(gamestate.stage) if position: platform_center = (position[1] + position[2]) / 2 platform_height = position[0] on_side_platform = smashbot_state.on_ground and smashbot_state.position.y > 5 above_top_platform = (not smashbot_state.on_ground) and (smashbot_state.position.y + smashbot_state.ecb.bottom.y > platform_height) and \ position[1] < smashbot_state.position.x < position[2] if smashbot_state.on_ground and smashbot_state.action != Action.KNEE_BEND: self.interruptible = True # Stage 1, get to the inside edge of the side platform # Are we in position to jump? We want to be dashing inwards on a side plat if on_side_platform: # Get the x coord of the inner edge of the plat right_edge = (melee.side_platform_position(True, gamestate.stage))[2] if right_edge - abs(smashbot_state.position.x) < 8: if smashbot_state.action in [ Action.DASHING, Action.RUNNING ] and (smashbot_state.facing == (smashbot_state.position.x < 0)): self.interruptible = False self.controller.press_button(melee.Button.BUTTON_Y) return else: # Dash inwards self.interruptible = False self.controller.tilt_analog( melee.Button.BUTTON_MAIN, int(smashbot_state.position.x < 0), 0.5) return else: # Dash inwards self.interruptible = False self.controller.tilt_analog(melee.Button.BUTTON_MAIN, int(smashbot_state.position.x < 0), 0.5) return # If we're crouching, keep holding Y if smashbot_state.action == Action.KNEE_BEND: self.controller.press_button(melee.Button.BUTTON_Y) self.interruptible = False return # Jump when falling if smashbot_state.action == Action.FALLING and smashbot_state.jumps_left > 0 and smashbot_state.action_frame > 6: self.interruptible = False self.controller.press_button(melee.Button.BUTTON_Y) self.controller.tilt_analog(melee.Button.BUTTON_MAIN, int(smashbot_state.position.x < 0), 0.5) return # Jump out of shine if smashbot_state.action in [Action.DOWN_B_AIR]: self.controller.press_button(melee.Button.BUTTON_Y) return # Can we shine our opponent right now, while we're in the air? foxshinerange = 11.8 shineable = smashbot_state.action in [ Action.JUMPING_FORWARD, Action.JUMPING_BACKWARD ] if shineable and gamestate.distance < foxshinerange: self.controller.press_button(melee.Button.BUTTON_B) self.controller.tilt_analog(melee.Button.BUTTON_MAIN, 0.5, 0) return # Waveland down aerials = [ Action.NAIR, Action.FAIR, Action.UAIR, Action.BAIR, Action.DAIR ] if above_top_platform and smashbot_state.action not in aerials: self.interruptible = True self.controller.press_button(melee.Button.BUTTON_L) # If opponent is in front of us, waveland towards them if smashbot_state.facing == (smashbot_state.position.x < opponent_state.position.x): self.controller.tilt_analog( melee.Button.BUTTON_MAIN, int(smashbot_state.position.x < opponent_state.position.x), 0.2) else: self.controller.tilt_analog(melee.Button.BUTTON_MAIN, 0.5, 0) return # Don't jump into Peach's dsmash or SH early dair spam dsmashactive = opponent_state.action == Action.DOWNSMASH and opponent_state.action_frame <= 22 if shineable and (opponent_state.action == Action.DAIR or dsmashactive): self.interruptible = True self.controller.press_button(melee.Button.BUTTON_L) self.controller.tilt_analog(melee.Button.BUTTON_MAIN, 0.5, 0) return # Hold inwards while we're jumping if shineable: self.controller.tilt_analog(melee.Button.BUTTON_MAIN, int(smashbot_state.position.x < 0), 0.5) return # Last resort, just dash at the center of the platform if smashbot_state.on_ground: self.interruptible = True #If we're starting the turn around animation, keep pressing that way or # else we'll get stuck in the slow turnaround if smashbot_state.action == Action.TURNING and smashbot_state.action_frame == 1: return #Dash back, since we're about to start running if smashbot_state.action == Action.DASHING and smashbot_state.action_frame >= 11: self.controller.tilt_analog(melee.Button.BUTTON_MAIN, int(not smashbot_state.facing), .5) return if smashbot_state.position.x > platform_center + 2: self.controller.tilt_analog(melee.Button.BUTTON_MAIN, 0, .5) return if smashbot_state.position.x < platform_center - 2: self.controller.tilt_analog(melee.Button.BUTTON_MAIN, 1, .5) return self.controller.tilt_analog(melee.Button.BUTTON_MAIN, int(smashbot_state.facing), .5) return # Mash analog L presses to L-cancel if Smashbot is throwing out an aerial elif not smashbot_state.on_ground and smashbot_state.action in aerials: self.interruptible = False if gamestate.frame % 2 == 0: self.controller.press_shoulder(Button.BUTTON_L, 1) else: self.controller.press_shoulder(Button.BUTTON_L, 0) return else: self.controller.empty_input()