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 # If we chose to run, keep running if type(self.chain) == Chains.Run and self.keep_running: self.pickchain(Chains.Run, [opponent_state.position.x > smashbot_state.position.x]) return edge = melee.stages.EDGE_GROUND_POSITION[gamestate.stage] # Dash dance up to the correct spacing pivotpoint = opponent_state.position.x bufferzone = 30 if opponent_state.character == Character.CPTFALCON: bufferzone = 35 if opponent_state.character == Character.MARTH: bufferzone = 40 if opponent_state.character == Character.SHEIK: bufferzone = 38 if opponent_state.character == Character.MEWTWO: bufferzone = 32 if opponent_state.character == Character.DK: bufferzone = 40 if opponent_state.facing != (opponent_state.position.x < smashbot_state.position.x): bufferzone = 40 if opponent_state.position.x > smashbot_state.position.x: bufferzone *= -1 side_plat_height, side_plat_left, side_plat_right = melee.side_platform_position(opponent_state.position.x > 0, gamestate.stage) on_side_plat = False if side_plat_height is not None: on_side_plat = opponent_state.on_ground and abs(opponent_state.position.y - side_plat_height) < 5 if on_side_plat: bufferzone = 0 # Falling spacies falling_spacie = False if opponent_state.character in [Character.FOX, Character.FALCO]: if not opponent_state.on_ground and opponent_state.speed_y_self < 0: bufferzone = 0 falling_spacie = True pivotpoint += bufferzone # Don't run off the stage though, adjust this back inwards a little if it's off edgebuffer = 10 pivotpoint = min(pivotpoint, edge - edgebuffer) pivotpoint = max(pivotpoint, (-edge) + edgebuffer) if self.logger: self.logger.log("Notes", "pivotpoint: " + str(pivotpoint) + " ", concat=True) if on_side_plat and abs(smashbot_state.position.x - pivotpoint) < 2 and smashbot_state.action == Action.TURNING: if opponent_state.action_frame < 6: self.pickchain(Chains.Shffl, [SHFFL_DIRECTION.UP]) return smash_now = opponent_state.action_frame < 6 if opponent_state.character == Character.CPTFALCON: smash_now = opponent_state.action_frame in [4, 12, 20, 27] if opponent_state.character == Character.MARTH: smash_now = opponent_state.action_frame < 6 if opponent_state.character == Character.DK: smash_now = False shadowball = False if opponent_state.character == Character.MEWTWO: for projectile in gamestate.projectiles: if projectile.type in [ProjectileType.SHADOWBALL] and projectile.subtype == 0: shadowball = True smash_now = True spacing_grace_zone = 2 if falling_spacie: spacing_grace_zone = 8 # If spacing and timing is right, do an attack if abs(smashbot_state.position.x - pivotpoint) < spacing_grace_zone: if smashbot_state.action == Action.TURNING: if smash_now and not on_side_plat and not falling_spacie: # For marth, it's actually more reliable to run between slashes if opponent_state.character == Character.MARTH: self.keep_running = True self.pickchain(Chains.Run, [opponent_state.position.x > smashbot_state.position.x]) return self.chain = None if opponent_state.position.x < smashbot_state.position.x: self.pickchain(Chains.SmashAttack, [0, SMASH_DIRECTION.LEFT]) else: self.pickchain(Chains.SmashAttack, [0, SMASH_DIRECTION.RIGHT]) return if falling_spacie and abs(opponent_state.position.y - smashbot_state.position.y) < 36: self.chain = None self.pickchain(Chains.Tilt, [TILT_DIRECTION.UP]) return elif smashbot_state.action == Action.DASHING: # Ground pound if opponent_state.character == Character.DK and opponent_state.action in [Action.DK_GROUND_POUND]: if smashbot_state.facing == (smashbot_state.position.x < opponent_state.position.x): self.pickchain(Chains.Shffl, [SHFFL_DIRECTION.DOWN]) return self.pickchain(Chains.Run, [not smashbot_state.facing]) return # If we're stuck in shield, wavedash back if smashbot_state.action in [Action.SHIELD_RELEASE, Action.SHIELD]: self.pickchain(Chains.Wavedash, [1.0, False]) return # Otherwise dash dance to the pivot point self.pickchain(Chains.DashDance, [pivotpoint, 0, False])
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.side_platform_position(self.right_platform, gamestate) if position: platform_center = (position[1] + position[2]) / 2 platform_height = position[0] under_platform = abs(smashbot_state.position.x - platform_center) < 10 if smashbot_state.on_ground: self.interruptible = True # Are we in position to jump? if under_platform 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 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) 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 # 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 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()
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, [1, False]) return bufferzone = 30 if opponent_state.character == Character.SHEIK and opponent_state.action == Action.SWORD_DANCE_2_HIGH: bufferzone = 55 # Samus bomb? samus_bomb = False for projectile in gamestate.projectiles: if projectile.type in [ melee.ProjectileType.SAMUS_BOMB, melee.ProjectileType.PIKACHU_THUNDER ]: if smashbot_state.position.x < projectile.x < opponent_state.position.x or smashbot_state.position.x > projectile.x > opponent_state.position.x: samus_bomb = True if samus_bomb: bufferzone = 60 if opponent_state.action == Action.LOOPING_ATTACK_MIDDLE: bufferzone += 15 onright = opponent_state.position.x < smashbot_state.position.x if not onright: bufferzone *= -1 if Retreat.is_rapid_jab(opponent_state): bufferzone = 60 pivotpoint = opponent_state.position.x + bufferzone # Don't run off the stage though, adjust this back inwards a little if it's off edgebuffer = 10 edge = melee.stages.EDGE_GROUND_POSITION[gamestate.stage] - edgebuffer # If we are about to pivot near the edge, just grab the edge instead if abs(pivotpoint) > edge and opponent_state.position.y < 20: self.pickchain(Chains.Grabedge) return pivotpoint = min(pivotpoint, edge) pivotpoint = max(pivotpoint, -edge) # TODO make this a general function for all projectiles missle_approaching = False for projectile in gamestate.projectiles: if projectile.type in [ melee.ProjectileType.SAMUS_MISSLE, melee.ProjectileType.SAMUS_CHARGE_BEAM ]: missle_approaching = True # Only do this laser if we are on the same level as the opponent if abs(opponent_state.position.y - smashbot_state.position.y) < 5 and not missle_approaching: if samus_bomb and opponent_state.action == Action.SWORD_DANCE_4_MID and opponent_state.action_frame < 10: self.pickchain(Chains.Laser) return # If opponent is on a side platform, board the opposite platform and laser # They don't need to be standing on the plat, just sort of shortly above it side_plat_height, side_plat_left, side_plat_right = melee.side_platform_position( opponent_state.position.x > 0, gamestate.stage) other_side_plat_height, other_side_plat_left, other_side_plat_right = melee.side_platform_position( opponent_state.position.x < 0, gamestate.stage) if (side_plat_height is not None ) and (opponent_state.position.y + 1 > side_plat_height) and ( side_plat_left < opponent_state.position.x < side_plat_right): # If we're already on the platform if smashbot_state.position.y > 5 and smashbot_state.on_ground: # Make sure we're in the center-ish of the platform if (other_side_plat_left + 5 < smashbot_state.position.x < other_side_plat_right - 5) and not missle_approaching: self.pickchain(Chains.Laser) return else: self.chain = None self.pickchain(Chains.DashDance, [ other_side_plat_left + (other_side_plat_right - other_side_plat_left / 2) ]) return else: self.pickchain(Chains.BoardSidePlatform, [opponent_state.position.x < 0]) return self.chain = None self.pickchain(Chains.DashDance, [pivotpoint])
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()
def step(self, gamestate, smashbot_state, opponent_state): platform_center = 0 platform_height = 0 position = melee.side_platform_position(self.right_platform, gamestate) if position: platform_center = (position[1] + position[2]) / 2 platform_height = position[0] under_platform = abs(smashbot_state.x - platform_center) < 10 if smashbot_state.on_ground: self.interruptible = True # Are we in position to jump? if under_platform 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 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 if smashbot_state.ecb_bottom[1] + smashbot_state.y > platform_height: self.interruptible = True self.controller.press_button(melee.Button.BUTTON_L) self.controller.tilt_analog(melee.Button.BUTTON_MAIN, 0.5, 0) 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.x > platform_center + 2: self.controller.tilt_analog(melee.Button.BUTTON_MAIN, 0, .5) return if smashbot_state.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 else: self.controller.empty_input()