示例#1
0
    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

        framesleft = Punish.framesleft(opponent_state, self.framedata, smashbot_state)
        # This is off by one for hitstun
        framesleft -= 1

        shinerange = 9.9
        if smashbot_state.action == Action.RUNNING:
            shinerange = 12.8
        if smashbot_state.action == Action.DASHING:
            shinerange = 9.5

        # If we shine too close to the edge while accelerating horizontally, we can slide offstage and get into trouble
        distance_from_edge = melee.stages.EDGE_GROUND_POSITION[gamestate.stage] - abs(smashbot_state.position.x)
        edgetooclose = smashbot_state.action == Action.EDGE_TEETERING_START or distance_from_edge < 5

        # Try to do the shine
        if gamestate.distance < shinerange and not edgetooclose:
            # Emergency backup shine. If we don't shine now, they'll get out of the combo
            if framesleft == 1:
                self.chain = None
                self.pickchain(Chains.Waveshine)
                return

            # Cut the run short and just shine now. Don't wait for the cross-up
            #   This is here to prevent running too close to the edge and sliding off
            if smashbot_state.action in [Action.RUNNING, Action.RUN_BRAKE, Action.CROUCH_START] and distance_from_edge < 16:
                self.chain = None
                self.pickchain(Chains.Waveshine)
                return

            # We always want to try to shine our opponent towards the center of the stage
            # If we are lined up right now, do the shine
            if (smashbot_state.position.x < opponent_state.position.x < 0) or (0 < opponent_state.position.x < smashbot_state.position.x):
                self.chain = None
                self.pickchain(Chains.Waveshine)
                return

            # If we are running away from our opponent, just shine now
            onright = opponent_state.position.x < smashbot_state.position.x
            if (smashbot_state.speed_ground_x_self > 0) == onright:
                self.chain = None
                self.pickchain(Chains.Waveshine)
                return

        if smashbot_state.action == Action.LANDING_SPECIAL and smashbot_state.action_frame < 28:
            self.pickchain(Chains.Nothing)
            return

        if not (smashbot_state.action == Action.DOWN_B_GROUND_START and smashbot_state.action_frame in [1,2]):
            self.pickchain(Chains.Run, [opponent_state.position.x > smashbot_state.position.x])
            return
        return
示例#2
0
 def shouldapproach(smashbot_state, opponent_state, gamestate, framedata, logger):
     if len(gamestate.projectiles) > 0:
         return False
     # Specify that this needs to be platform approach
     framesleft = Punish.framesleft(opponent_state, framedata, smashbot_state)
     if logger:
         logger.log("Notes", " framesleft: " + str(framesleft) + " ", concat=True)
     if framesleft >= 9:
         return True
     return False
示例#3
0
    def caninfinite(smashbot_state, opponent_state, gamestate, framedata,
                    difficulty):
        isroll = framedata.is_roll(opponent_state.character,
                                   opponent_state.action)

        if opponent_state.action in [Action.SHIELD_START, Action.SHIELD, \
                Action.SHIELD_STUN, Action.SHIELD_REFLECT]:
            return False

        # Don't try to infinite if we're on a platform
        if smashbot_state.position.y > 2 or opponent_state.position.y > 2:
            return False

        # Should we try a waveshine infinite?
        #   They need to have high friction and not fall down
        if opponent_state.action in [Action.STANDING, Action.TURNING, Action.DASHING, Action.RUNNING, \
                Action.WALK_SLOW, Action.WALK_MIDDLE, Action.WALK_FAST]:
            return False

        framesleft = Punish.framesleft(opponent_state, framedata,
                                       smashbot_state)
        # This is off by one for hitstun
        framesleft -= 1

        # Give up the infinite if we're in our last dashing frame, and are getting close to the edge
        #  We are at risk of running off the edge when this happens
        if (smashbot_state.action == Action.DASHING
                and smashbot_state.action_frame >= 11):
            if (smashbot_state.speed_ground_x_self >
                    0) == (smashbot_state.position.x > 0):
                edge_x = melee.stages.EDGE_GROUND_POSITION[gamestate.stage]
                if opponent_state.position.x < 0:
                    edge_x = -edge_x
                edgedistance = abs(edge_x - smashbot_state.position.x)
                if edgedistance < 16:
                    return False

        # If opponent is attacking, don't infinite
        if framedata.is_attack(opponent_state.character,
                               opponent_state.action):
            return False

        # If opponent is going to slide to the edge, then we have to stop
        endposition = opponent_state.position.x + framedata.slide_distance(
            opponent_state, opponent_state.speed_x_attack, framesleft)
        if abs(endposition) + 5 > melee.stages.EDGE_GROUND_POSITION[
                gamestate.stage]:
            return False

        if framedata.characterdata[opponent_state.character]["Friction"] >= 0.06 and \
                opponent_state.hitstun_frames_left > 1 and not isroll and opponent_state.on_ground \
                and opponent_state.percent < Infinite.killpercent(opponent_state):
            return True

        return False
示例#4
0
    def step(self, gamestate, smashbot_state, opponent_state):
        self._propagate = (gamestate, smashbot_state, opponent_state)

        # TODO Should this only be set once per instance?
        self.movingright = opponent_state.speed_x_attack + opponent_state.speed_ground_x_self > 0

        #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

        framesleft = Punish.framesleft(opponent_state, self.framedata)
        # This is off by one for hitstun
        framesleft -= 1

        shinerange = 11.8
        if smashbot_state.action == Action.DASHING:
            shinerange = 9

        # Try to do the shine
        if gamestate.distance < shinerange:
            # emergency backup shine
            if framesleft == 1:
                self.chain = None
                self.pickchain(Chains.Waveshine)
                return
            onright = opponent_state.x < smashbot_state.x
            opponentspeed = opponent_state.speed_x_attack + opponent_state.speed_ground_x_self
            # If opponent isn't moving, then just try to shine back towards the middle
            if abs(opponentspeed) > 0.01:
                self.movingright = opponentspeed > 0

            # We always want to try to shine our opponent towards the center of the stage
            # If we are lined up right now, do the shine
            if smashbot_state.x < opponent_state.x < 0 or \
                    0 < opponent_state.x < smashbot_state.x:
                self.chain = None
                self.pickchain(Chains.Waveshine)
                return

            # If we are running away from our opponent, just shine now
            if (smashbot_state.speed_ground_x_self > 0) == onright:
                self.chain = None
                self.pickchain(Chains.Waveshine)
                return

        if smashbot_state.action == Action.LANDING_SPECIAL and smashbot_state.action_frame < 28:
            self.pickchain(Chains.Nothing)
            return
        self.pickchain(Chains.Run, [opponent_state.speed_x_attack > 0])
        return
示例#5
0
文件: bait.py 项目: jinai/SmashBot
    def step(self, gamestate, smashbot_state, opponent_state):
        self._propagate = (gamestate, smashbot_state, opponent_state)

        # -1 means auto-adjust difficulty based on stocks remaining
        if self.set_difficulty == -1:
            self.difficulty = smashbot_state.stock
        else:
            self.difficulty = self.set_difficulty

        if SelfDestruct.shouldsd(gamestate, smashbot_state, opponent_state):
            self.picktactic(Tactics.SelfDestruct)
            return

        # Reset the approach state after 1 second
        #   Or if opponent becomes invulnerable
        if self.approach and ((abs(self.approach_frame - gamestate.frame) > 60)
                              or (opponent_state.invulnerability_left > 0)):
            self.approach_frame = -123
            self.approach = False

        # Randomly approach sometimes rather than keeping distance
        # Should happen on average once per 2 seconds
        # The effect will last for about 1 second
        # On the first two difficulties, just always approach
        if (random.randint(0, 120) == 0 or
            (self.difficulty >= 4 and opponent_state.action != Action.CROUCHING
             )) and (opponent_state.invulnerability_left == 0):
            self.approach = True
            self.approach_frame = gamestate.frame

        if self.logger:
            self.logger.log("Notes",
                            " approach: " + str(self.approach) + " ",
                            concat=True)

        if Mitigate.needsmitigation(smashbot_state):
            self.picktactic(Tactics.Mitigate)
            return

        if self.tactic and not self.tactic.isinteruptible():
            self.tactic.step(gamestate, smashbot_state, opponent_state)
            return

        # If we're stuck in a lag state, just do nothing. Trying an action might just
        #   buffer an input we don't want
        if Wait.shouldwait(gamestate, smashbot_state, opponent_state,
                           self.framedata):
            self.picktactic(Tactics.Wait)
            return

        if Recover.needsrecovery(smashbot_state, opponent_state, gamestate):
            self.picktactic(Tactics.Recover)
            return

        if Celebrate.deservescelebration(smashbot_state, opponent_state):
            self.picktactic(Tactics.Celebrate)
            return

        # Difficulty 5 is a debug / training mode
        #   Don't do any attacks, and don't do any shielding
        #   Take attacks, DI, and recover
        if self.difficulty == 5:
            self.picktactic(Tactics.KeepDistance)
            return

        if Defend.needsprojectiledefense(smashbot_state, opponent_state,
                                         gamestate, self.logger):
            self.picktactic(Tactics.Defend)
            return

        # If we can infinite our opponent, do that!
        if Infinite.caninfinite(smashbot_state, opponent_state, gamestate,
                                self.framedata, self.difficulty):
            self.picktactic(Tactics.Infinite)
            return

        # If we can juggle opponent in the air, do that
        if Juggle.canjuggle(smashbot_state, opponent_state, gamestate,
                            self.framedata, self.difficulty):
            self.picktactic(Tactics.Juggle)
            return

        # If we can punish our opponent for a laggy move, let's do that
        if Punish.canpunish(smashbot_state, opponent_state, gamestate,
                            self.framedata):
            self.picktactic(Tactics.Punish)
            return

        # Do we need to defend an attack?
        if Defend.needsdefense(smashbot_state, opponent_state, gamestate,
                               self.framedata):
            self.picktactic(Tactics.Defend)
            return

        # Can we edge guard them?
        if Edgeguard.canedgeguard(smashbot_state, opponent_state, gamestate):
            self.picktactic(Tactics.Edgeguard)
            return

        # Can we shield pressure them?
        if Pressure.canpressure(opponent_state, gamestate):
            self.picktactic(Tactics.Pressure)
            return

        if Retreat.shouldretreat(smashbot_state, opponent_state, gamestate,
                                 not self.approach):
            self.picktactic(Tactics.Retreat)
            return

        if Challenge.canchallenge(smashbot_state, opponent_state, gamestate,
                                  self.framedata, self.difficulty):
            self.picktactic(Tactics.Challenge)
            return

        if Approach.shouldapproach(smashbot_state, opponent_state, gamestate, self.framedata, self.logger) or \
                (self.approach and not Approach.approach_too_dangerous(smashbot_state, opponent_state, gamestate, self.framedata)):
            self.picktactic(Tactics.Approach)
            return

        self.picktactic(Tactics.KeepDistance)
示例#6
0
    def step(self):
        opponent_state = self.opponent_state
        smashbot_state = self.smashbot_state

        recoverhigh = self.canrecoverhigh()

        #If we can't interrupt the chain, just continue it
        if self.chain != None and not self.chain.interruptible:
            self.chain.step()
            return

        if Dropdownshine.inrange(self.smashbot_state, self.opponent_state,
                                 self.framedata):
            self.pickchain(Chains.Dropdownshine)
            return

        if smashbot_state.action == Action.EDGE_CATCHING:
            self.pickchain(Chains.Nothing)
            return

        # How many frames will it take to get to our opponent right now?
        onedge = smashbot_state.action in [
            Action.EDGE_HANGING, Action.EDGE_CATCHING
        ]
        opponentonedge = opponent_state.action in [
            Action.EDGE_HANGING, Action.EDGE_CATCHING
        ]

        # Stand up if opponent attacks us
        proj_incoming = Defend.needsprojectiledefense(
            self.smashbot_state, self.opponent_state,
            self.gamestate) and smashbot_state.invulnerability_left <= 2

        samusgrapple = opponent_state.character == Character.SAMUS and opponent_state.action == Action.SWORD_DANCE_4_LOW and \
            -25 < opponent_state.y < 0 and smashbot_state.invulnerability_left <= 2

        hitframe = self.framedata.inrange(opponent_state, smashbot_state,
                                          self.gamestate.stage)
        framesleft = hitframe - opponent_state.action_frame
        if proj_incoming or samusgrapple or (
                hitframe != 0 and onedge and framesleft < 5
                and smashbot_state.invulnerability_left < 2):
            # Unless the attack is a grab, then don't bother
            if not self.framedata.isgrab(opponent_state.character,
                                         opponent_state.action):
                if self.isupb():
                    #TODO: Make this a chain
                    self.chain = None
                    self.controller.press_button(Button.BUTTON_L)
                    return
                else:
                    self.chain = None
                    self.pickchain(Chains.DI, [0.5, 0.65])
                    return

        # Special exception for Fox/Falco illusion
        #   Since it is dumb and technically a projectile
        if opponent_state.character in [Character.FOX, Character.FALCO]:
            if opponent_state.action in [Action.SWORD_DANCE_2_MID]:
                self.chain = None
                self.pickchain(Chains.DI, [0.5, 0.65])
                return

        # What recovery options does opponent have?
        landonstage = False
        grabedge = False
        # they have to commit to an up-b to recover
        mustupb = False
        canrecover = True

        djheight = self.framedata.getdjheight(opponent_state)

        edgegrabframes = self.snaptoedgeframes()

        # How heigh can they go with a jump?
        potentialheight = djheight + opponent_state.y
        if potentialheight < -23:
            mustupb = True

        # Now consider UP-B
        #   Have they already UP-B'd?
        if self.isupb():
            if self.upbstart == 0:
                self.upbstart = opponent_state.y
            # If they are halfway through the up-b, then subtract out what they've alrady used
            potentialheight = self.upbheight() + self.upbstart
        elif opponent_state.action == Action.DEAD_FALL:
            potentialheight = opponent_state.y
        else:
            potentialheight += self.upbheight()

        # Cpt Falcon's up-b causes him to distort his model by a crazy amount. Giving him
        #   the ability to get on the stage easier. Adjust for this
        adjustedheight = potentialheight
        if opponent_state.character == Character.CPTFALCON and self.isupb():
            adjustedheight += 12

        # Adjust upwards a little to have some wiggle room
        if adjustedheight > -5:
            landonstage = True
        if potentialheight > -23:
            grabedge = True
        if potentialheight < -30:
            mustupb = True
            canrecover = False

        # Split the logic into two:
        #   A) We are on the edge
        #   B) We are on the stage
        if smashbot_state.action in [
                Action.EDGE_HANGING, Action.EDGE_CATCHING
        ]:
            # If opponent can't recover, then just get onto the stage!
            if not canrecover:
                #TODO: Make this a chain
                self.chain = None
                self.controller.press_button(Button.BUTTON_L)
                return

            # Don't roll up too early for Falcon
            falconupearly = opponent_state.character == Character.CPTFALCON and \
                opponent_state.action == Action.SWORD_DANCE_3_LOW and opponent_state.action_frame <= 12

            # Roll up to edgehog
            if self.isupb() and not landonstage and not falconupearly:
                #TODO: Make this a chain
                self.chain = None
                self.controller.press_button(Button.BUTTON_L)
                return

            # Edgestall
            # For Fox and Falco, we have a different edgestall strategy. Only edgestall if they start a FireFox
            if opponent_state.character in [Character.FOX, Character.FALCO]:
                # Are they in the start of a firefox?
                # But make sure they can't grab the edge in the middle of it
                edgedistance = abs(opponent_state.x) - (
                    melee.stages.edgegroundposition(self.gamestate.stage) + 15)
                inrange = (-5 > opponent_state.y > -23) and (edgedistance < 15)
                if opponent_state.action == Action.SWORD_DANCE_3_LOW and opponent_state.action_frame <= 5 and not inrange:
                    self.pickchain(Chains.Edgestall)
                    return
            # We must be on the first frame, or else it's dangerous
            elif smashbot_state.action == Action.EDGE_HANGING and smashbot_state.action_frame == 1:
                if edgegrabframes > 29 and smashbot_state.invulnerability_left >= 29:
                    self.pickchain(Chains.Edgestall)
                    return

            #  We are in danger of being attacked!
            #   It's unsafe to be in shine range of opponent. We can't react to the attack!
            if self.gamestate.distance < 11.8 and opponent_state.character in [Character.FOX, Character.FALCO, Character.JIGGLYPUFF] and \
                    smashbot_state.invulnerability_left <= 1:

                # If we can, challenge their shine at the edge
                if self.difficulty >= 3 and edgegrabframes > 2:
                    self.pickchain(Chains.Dropdownshine)
                    return

                self.chain = None
                self.pickchain(Chains.DI, [0.5, 0.65])
                return
            framesleft = Punish.framesleft(self.opponent_state, self.framedata)

            # Samus UP_B invulnerability
            samusupbinvuln = opponent_state.action in [Action.SWORD_DANCE_3_MID, Action.SWORD_DANCE_3_LOW] and \
                    opponent_state.character == Character.SAMUS and opponent_state.action_frame <= 5

            # Shine them, as long as they aren't attacking right now
            frameadvantage = framesleft > 2 or smashbot_state.invulnerability_left > 2
            if self.gamestate.distance < 11.8 and edgegrabframes > 2 and frameadvantage and not samusupbinvuln:
                self.pickchain(Chains.Dropdownshine)
                return

            # Illusion high
            if self.illusionhighframes() <= 5:
                if smashbot_state.invulnerability_left > 7:
                    self.pickchain(Chains.Edgebair)
                    return

            if self.firefoxhighframes() <= 5:
                self.pickchain(Chains.Edgebair)
                return

            # Do nothing
            self.chain = None
            self.pickchain(Chains.Nothing)
            return

        # We are on the stage
        else:
            edge_x = melee.stages.edgegroundposition(self.gamestate.stage)
            edgedistance = abs(edge_x - abs(self.smashbot_state.x))

            randomgrab = False
            if random.randint(0, 20) == 0:
                randomgrab = True
            if self.difficulty == 4:
                randomgrab = True

            # Can we challenge their ledge?
            framesleft = Punish.framesleft(self.opponent_state, self.framedata)
            if not recoverhigh and not onedge and opponent_state.invulnerability_left < 5 and edgedistance < 10:
                if randomgrab or framesleft > 10:
                    wavedash = True
                    if self.framedata.isattack(opponent_state.character,
                                               opponent_state.action):
                        wavedash = False
                    self.pickchain(Chains.Grabedge, [wavedash])
                    return

            # Dash dance near the edge
            pivotpoint = opponent_state.x
            # Don't run off the stage though, adjust this back inwards a little if it's off
            edgebuffer = 5
            pivotpoint = min(pivotpoint, edge_x - edgebuffer)
            pivotpoint = max(pivotpoint, (-edge_x) + edgebuffer)

            self.chain = None
            self.pickchain(Chains.DashDance, [pivotpoint])
示例#7
0
    def step(self, gamestate, smashbot_state, opponent_state):
        self._propagate = (gamestate, smashbot_state, opponent_state)

        recoverhigh = self.canrecoverhigh(gamestate, 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 Dropdownshine.inrange(smashbot_state, opponent_state,
                                 self.framedata):
            self.pickchain(Chains.Dropdownshine)
            return

        if smashbot_state.action == Action.EDGE_CATCHING:
            self.pickchain(Chains.Nothing)
            return

        # How many frames will it take to get to our opponent right now?
        onedge = smashbot_state.action in [
            Action.EDGE_HANGING, Action.EDGE_CATCHING
        ]

        # Stand up if opponent attacks us
        proj_incoming = Defend.needsprojectiledefense(
            smashbot_state, opponent_state,
            gamestate) and smashbot_state.invulnerability_left <= 2

        samusgrapple = opponent_state.character == Character.SAMUS and opponent_state.action == Action.SWORD_DANCE_4_LOW and \
            -25 < opponent_state.position.y < 0 and smashbot_state.invulnerability_left <= 2

        hitframe = self.framedata.in_range(opponent_state, smashbot_state,
                                           gamestate.stage)
        framesleft = hitframe - opponent_state.action_frame
        if proj_incoming or samusgrapple or (
                hitframe != 0 and onedge and framesleft < 5
                and smashbot_state.invulnerability_left < 2):
            # Unless the attack is a grab, then don't bother
            if not self.framedata.is_grab(opponent_state.character,
                                          opponent_state.action):
                if self.isupb(opponent_state):
                    #TODO: Make this a chain
                    self.chain = None
                    self.controller.press_button(Button.BUTTON_L)
                    return
                else:
                    self.chain = None
                    self.pickchain(Chains.DI, [0.5, 0.65])
                    return

        # For pikachu, we want to be up on the stage to edgeguard. Not on edge
        if opponent_state.character == Character.PIKACHU and smashbot_state.action == Action.EDGE_HANGING and smashbot_state.invulnerability_left == 0:
            if opponent_state.position.y < -20:
                self.chain = None
                self.pickchain(Chains.Edgedash, [False])
                return

        # Special exception for Fox/Falco illusion
        #   Since it is dumb and technically a projectile
        if opponent_state.character in [Character.FOX, Character.FALCO]:
            if opponent_state.action in [Action.SWORD_DANCE_2_MID]:
                self.chain = None
                self.pickchain(Chains.DI, [0.5, 0.65])
                return

        # What recovery options does opponent have?
        landonstage = False
        grabedge = False
        # they have to commit to an up-b to recover
        mustupb = False
        canrecover = True

        djheight = self.framedata.dj_height(opponent_state)

        edgegrabframes = self.snaptoedgeframes(gamestate, opponent_state)

        # How heigh can they go with a jump?
        potentialheight = djheight + opponent_state.position.y
        if potentialheight < -23:
            mustupb = True

        # Now consider UP-B
        #   Have they already UP-B'd?
        if self.isupb(opponent_state):
            if self.upbstart == 0:
                self.upbstart = opponent_state.position.y
            # If they are halfway through the up-b, then subtract out what they've alrady used
            potentialheight = self.upbheight(opponent_state) + self.upbstart
        elif opponent_state.action == Action.DEAD_FALL:
            potentialheight = opponent_state.position.y
        else:
            potentialheight += self.upbheight(opponent_state)

        # Cpt Falcon's up-b causes him to distort his model by a crazy amount. Giving him
        #   the ability to get on the stage easier. Adjust for this
        adjustedheight = potentialheight
        if opponent_state.character == Character.CPTFALCON and self.isupb(
                opponent_state):
            adjustedheight += 12

        # Adjust upwards a little to have some wiggle room
        if adjustedheight > -5:
            landonstage = True
        if potentialheight > -23:
            grabedge = True
        if potentialheight < -30:
            mustupb = True
            canrecover = False

        # Split the logic into two:
        #   A) We are on the edge
        #   B) We are on the stage
        if smashbot_state.action in [
                Action.EDGE_HANGING, Action.EDGE_CATCHING
        ]:
            # If opponent can't recover, then just get onto the stage!
            if not canrecover:
                #TODO: Make this a chain
                self.chain = None
                self.controller.press_button(Button.BUTTON_L)
                return

            # Don't roll up too early for Falcon
            falconupearly = opponent_state.character == Character.CPTFALCON and \
                opponent_state.action == Action.SWORD_DANCE_3_LOW and opponent_state.action_frame <= 12

            # Roll up to edgehog
            if self.isupb(
                    opponent_state) and not landonstage and not falconupearly:
                #TODO: Make this a chain
                self.chain = None
                self.controller.press_button(Button.BUTTON_L)
                return

            # Challenge rising UP-B's with a shine if we're in range
            #   except for pikachu and falcon/ganon
            if self.isupb(
                    opponent_state
            ) and opponent_state.speed_y_self >= 0 and gamestate.distance < 10:
                if opponent_state.character not in [
                        Character.PIKACHU, Character.GANONDORF,
                        Character.CPTFALCON
                ]:
                    self.pickchain(Chains.Dropdownshine)
                    return

            # Edgestall
            # For Fox and Falco, we have a different edgestall strategy. Only edgestall if they start a FireFox
            if opponent_state.character in [Character.FOX, Character.FALCO]:
                # Are they in the start of a firefox?
                # But make sure they can't grab the edge in the middle of it
                edgedistance = abs(opponent_state.position.x) - (
                    melee.stages.EDGE_GROUND_POSITION[gamestate.stage] + 15)
                in_immediate_range = (-5 > opponent_state.position.y >
                                      -23) and (edgedistance < 15)
                in_fly_range = opponent_state.action_frame > (
                    (edgedistance - 15) / 3)
                if opponent_state.action == Action.SWORD_DANCE_3_LOW and not in_fly_range and not in_immediate_range:
                    self.pickchain(Chains.Edgestall)
                    return
            # We must be on the first frame, or else it's dangerous
            elif smashbot_state.action == Action.EDGE_HANGING and smashbot_state.action_frame == 1:
                if edgegrabframes > 29 and smashbot_state.invulnerability_left >= 29:
                    self.pickchain(Chains.Edgestall)
                    return

            #  We are in danger of being attacked!
            #   It's unsafe to be in shine range of opponent. We can't react to the attack!
            if gamestate.distance < 11.8 and opponent_state.character in [Character.FOX, Character.FALCO, Character.JIGGLYPUFF] and \
                    smashbot_state.invulnerability_left <= 1:

                # If we can, challenge their shine at the edge
                if self.difficulty >= 3 and edgegrabframes > 2:
                    if Dropdownshine.inrange(smashbot_state, opponent_state,
                                             self.framedata):
                        self.pickchain(Chains.Dropdownshine)
                        return

                self.chain = None
                self.pickchain(Chains.DI, [0.5, 0.65])
                return
            framesleft = Punish.framesleft(opponent_state, self.framedata,
                                           smashbot_state)

            # Samus UP_B invulnerability
            samusupbinvuln = opponent_state.action in [Action.SWORD_DANCE_3_MID, Action.SWORD_DANCE_3_LOW] and \
                    opponent_state.character == Character.SAMUS and opponent_state.action_frame <= 5

            # Shine them, as long as they aren't attacking right now
            frameadvantage = framesleft > 2 or smashbot_state.invulnerability_left > 2
            if gamestate.distance < 11.8 and edgegrabframes > 2 and frameadvantage and not samusupbinvuln:
                if Dropdownshine.inrange(smashbot_state, opponent_state,
                                         self.framedata):
                    self.pickchain(Chains.Dropdownshine)
                    return

            # Illusion high
            if self.illusionhighframes(gamestate, opponent_state) <= 5:
                if smashbot_state.invulnerability_left > 7:
                    self.pickchain(Chains.Edgebair)
                    return

            # If opponent is recovering high with illusion, bair them at the right time
            if (opponent_state.character == Character.FOX
                    and opponent_state.action_frame
                    == 15) or (opponent_state.character == Character.FALCO
                               and opponent_state.action_frame == 10):
                if opponent_state.action == Action.SWORD_DANCE_2_HIGH and opponent_state.position.y > -4:
                    self.pickchain(Chains.Edgebair)
                    return

            if self.firefoxhighframes(gamestate, opponent_state) <= 5:
                self.pickchain(Chains.Edgebair)
                return

            # Do nothing
            self.chain = None
            self.pickchain(Chains.Nothing)
            return

        # We are on the stage
        else:
            edge_x = melee.stages.EDGE_GROUND_POSITION[gamestate.stage]
            edgedistance = abs(edge_x - abs(smashbot_state.position.x))

            randomgrab = False
            if random.randint(0, 20) == 0:
                randomgrab = True
            # Don't make this guaranteed, even on most aggressive mode. Make it common, but not predictable
            if self.difficulty == 4 and random.randint(0, 10) == 0:
                randomgrab = True

            # For pikachu and jiggs don't grab the edge unless they're sitting, camping
            if opponent_state.character in [
                    Character.PIKACHU, Character.JIGGLYPUFF
            ] and opponent_state.action != Action.EDGE_HANGING:
                randomgrab = False

            # TODO Don't grab the edge if opponent is

            # They're camping. Camp back
            if gamestate.custom["ledge_grab_count"] > 3:
                # Get into position away from the edge.
                pivotpoint = 0

                if abs(smashbot_state.position.x - pivotpoint) > 5:
                    self.chain = None
                    self.pickchain(Chains.DashDance, [pivotpoint])
                    return
                elif len(gamestate.projectiles) == 0:
                    # Laser
                    self.pickchain(Chains.Laser)
                    return

            # Can we challenge their ledge?
            framesleft = Punish.framesleft(opponent_state, self.framedata,
                                           smashbot_state)

            # Sheik shino stall is safe to grab edge from on these frames
            if opponent_state.character == Character.SHEIK and opponent_state.action == Action.SWORD_DANCE_1_AIR and opponent_state.action_frame < 5:
                self.pickchain(Chains.Grabedge, [True])
                return

            # Puff sing stall is safe to grab from
            if opponent_state.character == Character.JIGGLYPUFF and opponent_state.action in [
                    Action.DOWN_B_AIR, Action.SHINE_RELEASE_AIR
            ] and opponent_state.action_frame < 10:
                self.pickchain(Chains.Grabedge, [True])
                return

            # Grab edge out from under Pika quick-attack startup
            if opponent_state.character == Character.PIKACHU and opponent_state.action == Action.SWORD_DANCE_4_MID and opponent_state.action_frame < 7:
                self.pickchain(Chains.Grabedge, [True])
                return

            # Grab the edge when opponent starts a FireFox
            if opponent_state.character in [
                    Character.FOX, Character.FALCO
            ] and opponent_state.action == Action.SWORD_DANCE_3_LOW and (
                    opponent_state.action_frame < 22):
                # But not if they're in range to grab the edge themselves
                edgedistance = abs(opponent_state.position.x) - (
                    melee.stages.EDGE_GROUND_POSITION[gamestate.stage] + 15)
                in_immediate_range = (-5 > opponent_state.position.y >
                                      -28) and (edgedistance < 15)
                if not in_immediate_range:
                    self.pickchain(Chains.Grabedge, [True])
                    return

            if (
                    not recoverhigh or randomgrab
            ) and not onedge and opponent_state.invulnerability_left < 5 and edgedistance < 10 and smashbot_state.on_ground:
                if (randomgrab
                        or framesleft > 10) and opponent_state.action not in [
                            Action.EDGE_ROLL_SLOW, Action.EDGE_ROLL_QUICK,
                            Action.EDGE_GETUP_SLOW, Action.EDGE_GETUP_QUICK,
                            Action.EDGE_ATTACK_SLOW, Action.EDGE_ATTACK_QUICK
                        ]:
                    if not self.framedata.is_attack(opponent_state.character,
                                                    opponent_state.action):
                        ff_early = False
                        if opponent_state.character in [
                                Character.FOX, Character.FALCO
                        ] and opponent_state.action == Action.SWORD_DANCE_3_LOW:
                            if opponent_state.action_frame < 20:
                                ff_early = True

                        if not ff_early:
                            self.pickchain(Chains.Grabedge, [True])
                            return

            # Dash dance near the edge
            pivotpoint = opponent_state.position.x
            # Don't run off the stage though, adjust this back inwards a little if it's off
            edgebuffer = 2

            # Against Jigglypuff, we need to respect the ledge invulnerability. DD inwards more
            if opponent_state.character == Character.JIGGLYPUFF and opponent_state.invulnerability_left > 0:
                if self.logger:
                    self.logger.log("Notes",
                                    "staying safe: " +
                                    str(opponent_state.invulnerability_left) +
                                    " ",
                                    concat=True)
                if opponent_state.position.x > 0:
                    pivotpoint -= 10
                else:
                    pivotpoint += 10

            pivotpoint = min(pivotpoint, edge_x - edgebuffer)
            pivotpoint = max(pivotpoint, (-edge_x) + edgebuffer)

            self.chain = None
            self.pickchain(Chains.DashDance, [pivotpoint])
示例#8
0
    def step(self):
        # If we have stopped approaching, reset the state
        if type(self.tactic) != Tactics.Approach:
            self.approach = False

        if Mitigate.needsmitigation(self.smashbot_state):
            self.picktactic(Tactics.Mitigate)
            return

        if self.tactic and not self.tactic.isinteruptible():
            self.tactic.step()
            return

        # If we're stuck in a lag state, just do nothing. Trying an action might just
        #   buffer an input we don't want
        if Wait.shouldwait(self.smashbot_state, self.framedata):
            self.picktactic(Tactics.Wait)
            return

        if Recover.needsrecovery(self.smashbot_state, self.opponent_state,
                                 self.gamestate):
            self.picktactic(Tactics.Recover)
            return

        if Celebrate.deservescelebration(self.smashbot_state,
                                         self.opponent_state):
            self.picktactic(Tactics.Celebrate)
            return

        # Difficulty 5 is a debug / training mode
        #   Don't do any attacks, and don't do any shielding
        #   Take attacks, DI, and recover
        if self.difficulty == 5:
            self.picktactic(Tactics.KeepDistance)
            return

        if Defend.needsprojectiledefense(self.smashbot_state,
                                         self.opponent_state, self.gamestate):
            self.picktactic(Tactics.Defend)
            return

        # If we can infinite our opponent, do that!
        if Infinite.caninfinite(self.smashbot_state, self.opponent_state,
                                self.gamestate, self.framedata,
                                self.difficulty):
            self.picktactic(Tactics.Infinite)
            return

        # If we can punish our opponent for a laggy move, let's do that
        if Punish.canpunish(self.smashbot_state, self.opponent_state,
                            self.gamestate, self.framedata):
            self.picktactic(Tactics.Punish)
            return

        # Do we need to defend an attack?
        if Defend.needsdefense(self.smashbot_state, self.opponent_state,
                               self.gamestate, self.framedata):
            self.picktactic(Tactics.Defend)
            return

        # Can we edge guard them?
        if Edgeguard.canedgeguard(self.smashbot_state, self.opponent_state,
                                  self.gamestate):
            self.picktactic(Tactics.Edgeguard)
            return

        # Can we shield pressure them?
        if Pressure.canpressure(self.opponent_state, self.gamestate):
            self.picktactic(Tactics.Pressure)
            return

        if Retreat.shouldretreat(self.smashbot_state, self.opponent_state,
                                 self.gamestate):
            self.picktactic(Tactics.Retreat)
            return

        # Is opponent starting a jump?
        jumping = self.opponent_state.action == Action.KNEE_BEND
        if self.opponent_state.action in [Action.JUMPING_FORWARD, Action.JUMPING_BACKWARD] and \
                self.opponent_state.speed_y_self > 0:
            jumping = True

        # Randomly approach some times rather than keeping distance
        if self.smashbot_state.action == Action.TURNING and random.randint(
                0, 40) == 0:
            self.approach = True

        if (jumping and self.opponent_state.invulnerability_left <= 0
            ) or self.approach:
            self.picktactic(Tactics.Approach)
            return

        self.picktactic(Tactics.KeepDistance)
示例#9
0
    def step(self, gamestate, smashbot_state, opponent_state):
        self._propagate = (gamestate, smashbot_state, opponent_state)

        opponentonedge = opponent_state.action in [Action.EDGE_HANGING, Action.EDGE_CATCHING, Action.EDGE_GETUP_SLOW, \
        Action.EDGE_GETUP_QUICK, Action.EDGE_ATTACK_SLOW, Action.EDGE_ATTACK_QUICK, Action.EDGE_ROLL_SLOW, Action.EDGE_ROLL_QUICK]

        # 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

        # TODO: Determine whether we should refresh before the ledge dash
        # It takes 16 frames to go from frame 1 of hanging to standing.
        frames_left = Punish.framesleft(opponent_state, self.framedata,
                                        smashbot_state)
        refresh = False
        if smashbot_state.action in [
                Action.EDGE_HANGING, Action.EDGE_CATCHING
        ]:
            self.pickchain(Chains.Edgedash, [refresh])
            return

        # If we can't possibly illusion to recover, don't try
        if smashbot_state.position.y < -15 and smashbot_state.jumps_left == 0 and smashbot_state.speed_y_self < 0:
            self.useillusion = False

        diff_x = abs(melee.stages.EDGE_POSITION[gamestate.stage] -
                     abs(smashbot_state.position.x))

        # If we can just grab the edge with a firefox, do that
        facinginwards = smashbot_state.facing == (smashbot_state.position.x <
                                                  0)
        if not facinginwards and smashbot_state.action == Action.TURNING and smashbot_state.action_frame == 1:
            facinginwards = True

        if smashbot_state.action == Action.DEAD_FALL:
            x = 0
            if smashbot_state.position.x < 0:
                x = 1
            self.chain = None
            self.pickchain(Chains.DI, [x, 0.5])
            return

        # Are we facing the wrong way in shine? Turn around
        if smashbot_state.action == Action.DOWN_B_STUN and not facinginwards:
            x = 0
            if smashbot_state.position.x < 0:
                x = 1
            self.chain = None
            self.pickchain(Chains.DI, [x, 0.5])
            return

        # If we can just do nothing and grab the edge, do that
        # Action.SWORD_DANCE_1_AIR is Fox's initial freefall after his upB finishes launching.
        # Fox can ledgegrab from behind in this animation, but he oftentimes needs to fastfall to hit the window.
        if -12 < smashbot_state.position.y and (diff_x < 10) and (
                facinginwards
                or smashbot_state.action == Action.SWORD_DANCE_1_AIR
        ) and smashbot_state.speed_y_self < 0:
            # Do a Fastfall if we're not already
            if smashbot_state.action == Action.FALLING and smashbot_state.speed_y_self > -3.3:
                self.chain = None
                self.pickchain(Chains.DI, [0.5, 0])
                return

            # If we are currently moving away from the stage, DI in
            if (smashbot_state.speed_air_x_self >
                    0) == (smashbot_state.position.x > 0):
                x = 0
                if smashbot_state.position.x < 0:
                    x = 1
                self.chain = None
                self.pickchain(Chains.DI, [x, 0.5])
                return
            else:
                self.pickchain(Chains.Nothing)
                return

        # If we illusion at this range when the opponent is holding ledge, Smashbot dies.
        # Firefox instead if the opponent is grabbing edge. Opponent has to get up or get burned.
        if (-16.4 < smashbot_state.position.y <
                -5) and (diff_x < 10) and facinginwards and opponentonedge:
            if gamestate.stage == melee.enums.Stage.BATTLEFIELD:
                # If Smashbot does a random or horizontal sideB here, he pretty reliably SDs on Battlefield
                self.pickchain(Chains.Firefox, [FIREFOX.EDGE])
            else:
                self.pickchain(Chains.Firefox, [FIREFOX.RANDOM])
            return

        # If we're lined up, do the illusion
        #   88 is a little longer than the illusion max length
        if self.useillusion and (-16.4 < smashbot_state.position.y < -5) and (
                10 < diff_x < 88) and not opponentonedge:
            length = SHORTEN.LONG
            if diff_x < 50:
                length = SHORTEN.MID
            if diff_x < 40:
                length = SHORTEN.MID_SHORT
            if diff_x < 31:
                length = SHORTEN.SHORT

            self.pickchain(Chains.Illusion, [length])
            return

        # Is the opponent going offstage to edgeguard us?
        opponent_edgedistance = abs(opponent_state.position.x) - abs(
            melee.stages.EDGE_GROUND_POSITION[gamestate.stage])
        opponentxvelocity = opponent_state.speed_air_x_self + opponent_state.speed_ground_x_self
        opponentmovingtoedge = not opponent_state.off_stage and (
            opponent_edgedistance < 20) and (opponentxvelocity > 0 ==
                                             opponent_state.position.x > 0)
        opponentgoingoffstage = opponent_state.action in [Action.FALLING, Action.JUMPING_FORWARD, Action.JUMPING_BACKWARD, Action.LANDING_SPECIAL,\
            Action.DASHING, Action.WALK_MIDDLE, Action.WALK_FAST, Action.NAIR, Action.FAIR, Action.UAIR, Action.BAIR, Action.DAIR]

        # Don't airdodge recovery if we still have attack velocity. It just causes an SD
        hit_movement = abs(smashbot_state.speed_x_attack) > 0.2

        x_canairdodge = abs(smashbot_state.position.x) - 18 <= abs(
            melee.stages.EDGE_GROUND_POSITION[gamestate.stage])
        y_canairdodge = smashbot_state.position.y + 18 >= -6
        # airdodge_randomizer not currently in use
        airdodge_randomizer = random.randint(0, 4) == 1
        if x_canairdodge and y_canairdodge and (
                opponentgoingoffstage
                or opponentmovingtoedge) and not hit_movement:
            self.pickchain(Chains.Airdodge, [
                int(smashbot_state.position.x < 0),
                int(smashbot_state.position.y +
                    smashbot_state.ecb.bottom.y < 5)
            ])
            return

        # First jump back to the stage if we're low
        # Fox can at least DJ from y = -55.43 and still sweetspot grab the ledge.
        # For reference, if Fox inputs a DJ at y = -58.83, he will NOT sweetspot grab the ledge.
        jump_randomizer = random.randint(0, 5) == 1
        if smashbot_state.jumps_left > 0 and (smashbot_state.position.y < -52
                                              or opponentgoingoffstage
                                              or opponentmovingtoedge
                                              or jump_randomizer):
            self.pickchain(Chains.Jump)
            return

        # If we're high and doing an Illusion, just let ourselves fall into place
        if self.useillusion and smashbot_state.position.y > -5:
            # DI into the stage
            x = 0
            if smashbot_state.position.x < 0:
                x = 1
            self.chain = None
            self.pickchain(Chains.DI, [x, 0.5])
            return

        # Don't firefox if we're super high up, wait a little to come down
        if smashbot_state.speed_y_self < 0 and smashbot_state.position.y < -60:
            if gamestate.stage == melee.enums.Stage.BATTLEFIELD and diff_x < 30:
                self.pickchain(Chains.Firefox, [FIREFOX.HIGH])
            else:
                self.pickchain(Chains.Firefox, [FIREFOX.SAFERANDOM])
            return

        randomhighrecovery = smashbot_state.position.y > 0 and random.randint(
            0, 3) == 1
        if randomhighrecovery:
            if bool(random.randint(0, 1)):
                self.pickchain(Chains.Firefox, [FIREFOX.RANDOM])
            else:
                self.pickchain(Chains.Illusion, [SHORTEN.LONG])
            return

        # DI into the stage
        battlefielded = (
            smashbot_state.position.x <
            melee.stages.EDGE_POSITION[gamestate.stage] + 13
        ) and gamestate.stage == melee.enums.Stage.BATTLEFIELD and smashbot_state.position.y < 0
        if not battlefielded:
            x = 0
            if smashbot_state.position.x < 0:
                x = 1
            self.chain = None
            self.pickchain(Chains.DI, [x, 0.5])
示例#10
0
    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

        framesleft = Punish.framesleft(opponent_state, self.framedata)
        # This is off by one for hitstun
        framesleft -= 1

        shinerange = 9.9
        if smashbot_state.action == Action.RUNNING:
            shinerange = 12.8
        if smashbot_state.action == Action.DASHING:
            shinerange = 9.5

        # If we shine too close to the edge while accelerating horizontally, we can slide offstage and get into trouble
        distance_from_edge = melee.stages.EDGE_GROUND_POSITION[
            gamestate.stage] - abs(smashbot_state.x)
        edgetooclose = (smashbot_state.action == Action.EDGE_TEETERING_START or distance_from_edge < 5) \
            or (smashbot_state.action in [Action.RUNNING, Action.RUN_BRAKE, Action.CROUCH_START] and distance_from_edge < 10.5)

        # Try to do the shine
        if gamestate.distance < shinerange and not edgetooclose:
            # emergency backup shine
            if framesleft == 1:
                self.chain = None
                self.pickchain(Chains.Waveshine)
                return

            # We always want to try to shine our opponent towards the center of the stage
            # If we are lined up right now, do the shine
            if (smashbot_state.x < opponent_state.x <
                    0) or (0 < opponent_state.x < smashbot_state.x):
                self.chain = None
                self.pickchain(Chains.Waveshine)
                return

            # If we are running away from our opponent, just shine now
            onright = opponent_state.x < smashbot_state.x
            if (smashbot_state.speed_ground_x_self > 0) == onright:
                self.chain = None
                self.pickchain(Chains.Waveshine)
                return

        if smashbot_state.action == Action.LANDING_SPECIAL and smashbot_state.action_frame < 28:
            self.pickchain(Chains.Nothing)
            return

        if not smashbot_state.action == Action.DOWN_B_GROUND_START and smashbot_state.action_frame in [
                1, 2
        ]:
            # In general, we want to run the direction the opponent is moving
            #   Unless we're out of range and on the opposite side.
            if gamestate.distance > shinerange and (
                (smashbot_state.x < opponent_state.x < 0) or
                (0 < opponent_state.x < smashbot_state.x)):
                self.pickchain(Chains.Run,
                               [opponent_state.x > smashbot_state.x])
            else:
                self.pickchain(Chains.Run, [opponent_state.speed_x_attack > 0])
        return