示例#1
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)
示例#2
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])
示例#3
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])
示例#4
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)