Skip to content

Actor Attacks

The EVS_TakeTurn script runs when it's the actor's turn to attack. A typical attack follows this pattern: approach the target, check if the attack hits, deal damage, then return home.

Testing the target

Before dealing damage, use EnemyTestTarget to check if the attack will hit. This accounts for evasion badges and abilities.

Call(SetTargetActor, ACTOR_SELF, ACTOR_PLAYER)
Call(EnemyTestTarget,
    ACTOR_SELF, LVar0, 0, 0,
    1, BS_FLAGS1_INCLUDE_POWER_UPS)
Switch(LVar0)
    CaseOrEq(HIT_RESULT_MISS)
    CaseOrEq(HIT_RESULT_LUCKY)
        // play miss animation, then return home
        Call(YieldTurn)
        Return
    EndCaseGroup
EndSwitch

The fifth argument (1 in this example) is the damage amount for display purposes.

Dealing damage

If the test passes, use EnemyDamageTarget to actually apply damage:

Call(SetGoalToTarget, ACTOR_SELF)
Call(EnemyDamageTarget,
    ACTOR_SELF, LVar0, 0, 0,
    0, 2, BS_FLAGS1_TRIGGER_EVENTS)

The third argument is the damage type flags — use 0 for a normal attack, or combine flags for elemental and special behavior (see below). The sixth argument (2 here) is the actual damage dealt. The result in LVar0 tells you what happened:

ResultMeaning
HIT_RESULT_HITNormal hit
HIT_RESULT_NO_DAMAGEHit but dealt 0 damage (e.g. high defense)

Simple melee attack

Here's a basic melee attack that runs up to the player, hits, and retreats:

EvtScript EVS_TakeTurn = {
    Call(UseIdleAnimation, ACTOR_SELF, false)
    Call(EnableIdleScript, ACTOR_SELF, IDLE_SCRIPT_DISABLE)
    Call(SetTargetActor, ACTOR_SELF, ACTOR_PLAYER)
    Call(UseBattleCamPreset, BTL_CAM_ENEMY_APPROACH)
    Call(BattleCamTargetActor, ACTOR_SELF)
    // run towards the player
    Call(SetAnimation,
        ACTOR_SELF, PRT_MAIN, ANIM_Goomba_Run)
    Call(SetGoalToTarget, ACTOR_SELF)
    Call(AddGoalPos, ACTOR_SELF, 50, 0, 0)
    Call(SetActorSpeed, ACTOR_SELF, Float(6.0))
    Call(RunToGoal, ACTOR_SELF, 0, false)
    // test if the attack hits
    Call(EnemyTestTarget,
        ACTOR_SELF, LVar0, 0, 0,
        2, BS_FLAGS1_INCLUDE_POWER_UPS)
    Switch(LVar0)
        CaseOrEq(HIT_RESULT_MISS)
        CaseOrEq(HIT_RESULT_LUCKY)
            // missed — return home
            Call(UseBattleCamPreset, BTL_CAM_DEFAULT)
            Call(YieldTurn)
            Call(SetAnimation,
                ACTOR_SELF, PRT_MAIN, ANIM_Goomba_Run)
            Call(SetGoalToHome, ACTOR_SELF)
            Call(SetActorSpeed, ACTOR_SELF, Float(8.0))
            Call(RunToGoal,
                ACTOR_SELF, 0, false)
            Call(EnableIdleScript, ACTOR_SELF, IDLE_SCRIPT_ENABLE)
            Call(UseIdleAnimation, ACTOR_SELF, true)
            Return
        EndCaseGroup
    EndSwitch
    // attack connects
    Call(SetGoalToTarget, ACTOR_SELF)
    Call(EnemyDamageTarget,
        ACTOR_SELF, LVar0, 0, 0,
        0, 2, BS_FLAGS1_TRIGGER_EVENTS)
    // return home
    Call(UseBattleCamPreset, BTL_CAM_DEFAULT)
    Wait(5)
    Call(YieldTurn)
    Call(SetAnimation,
        ACTOR_SELF, PRT_MAIN, ANIM_Goomba_Run)
    Call(SetGoalToHome, ACTOR_SELF)
    Call(SetActorSpeed, ACTOR_SELF, Float(8.0))
    Call(RunToGoal, ACTOR_SELF, 0, false)
    Call(EnableIdleScript, ACTOR_SELF, IDLE_SCRIPT_ENABLE)
    Call(UseIdleAnimation, ACTOR_SELF, true)
    Return
    End
};

For a jump attack with arc rotation, see src/battle/actor/gloomba.c. For a dive attack pattern, see src/battle/actor/paragoomba.c.

Damage type flags

The third argument to EnemyDamageTarget is a bitmask of DAMAGE_TYPE_ flags. Use exactly one elemental flag to set the attack's element, and optionally combine it with modifier flags:

FlagEffect
DAMAGE_TYPE_NO_CONTACTRanged/projectile attack — won't trigger contact hazards like spikes or Zap Tap.
DAMAGE_TYPE_IGNORE_DEFENSEBypasses the target's defense stat.
DAMAGE_TYPE_UNBLOCKABLECannot be blocked by the player.
DAMAGE_TYPE_STATUS_ALWAYS_HITSStatus effects bypass immunity checks.

Pass 0 for a normal contact attack with no special properties.