On this page
  1. Related
  2. Mechanics
  3. References
  4. Sources

The atlas reads Paper Mario through the pmret team’s decompilation, C that builds the US ROM and three others from one tree. Names and comments quoted here are theirs, and the claims cite the code the US build compiles. Nothing has been measured in the game yet.

Mario’s attacks are action commands. The Jump takes one press of A in the last 4 updates1 of its count, and a press before then voids the window; a good press bounces Mario into a second stomp, and a Dodge Master badge widens the window1. The hammer is held left through its charge and let go inside a window of 11 updates2 at its end, which doubles the basic hammer’s damage from 1 to 22.

On defense, a fresh press of A in the last 3 updates3 before an enemy’s hit is a guard, unless A was pressed in the 10 updates before those; it takes 1 from Mario’s damage and stops a partner’s3. Mario’s own damage is a subtraction: the move’s damage with its badges and charges, capped at 994, less the target’s defense4.

Mechanics

MechanicKindHow
Action commandTimed pressthe Jump takes one press of A in the last 4 updates of its count, and a good press earns a second stomp; a press before the window voids it
Action commandHold and releasethe hammer is held left and let go in an 11-update window at the end of a 51-update charge; a good release doubles the basic hammer's damage
Timed guardReduce · Marioa fresh press of A in the 3 updates before a hit takes 1 off it, unless A was pressed in the 10 before those
Timed guardNegate · partnersa partner's guard, read the same way, stops the hit's damage
Damage formulaAttack minus defense, no rollMario's damage, after badges and charges and a cap of 99, less the target's defense, floored at 0
Every claim about this game, by concept (4)
Action commandIn the US version of Paper Mario, the jump action command (action_command_jump) is one press of A timed to the stomp, and runs only once Mario has learned action commands (not AC_MODE_NOT_LEARNED). The basic Jump (EVS_UseMove_Basic, the script for menu level 0) computes the jump's length as (distance - 20) / 10.588 + 15 from Mario to the target, gives that count to PlayerBasicJumpToGoal, and passes the same count to the command as prepareTime, at difficulty AC_DIFFICULTY_STANDARD (index 3 of 8). Each update the command counts prepareTime down until it is no more than the window size, actionCmdTableJump[difficulty], which is 4 at standard in a table running 7 down to 0; it then sets the window timer to that size and counts it down to 0. A press of A while prepareTime is still counting sets wrongButtonPressed, and the window then takes no press; the update in which the count reaches the window size runs that early-press test before falling through into the window, so a press there is early too, and a press counts only while the timer runs from 3 to 0, 4 updates at standard (computed), the last of the command's updates. When the partner isn't acting, adjust_action_command_difficulty lowers the difficulty index by 3 for each Dodge Master badge equipped, clamped at 0, so one badge widens the window to 7 updates (computed). A good press makes the basic Jump's first stomp a nice hit, and the script then bounces Mario into a second stomp; each stomp passes a damage of 1. A missed press ends the move after the first.Code
In the US version of Paper Mario, the hammer action command (action_command_hammer) is a hold and release of the stick to the left. When action commands are learned and the Berserker badge isn't equipped, the hammer script (outside the tutorial and auto-success) waits up to 45 updates for the stick to be held left, then starts the command with a duration of 51 (45 plus 6) at AC_DIFFICULTY_STANDARD, whose table value actionCmdTableHammer[3] is 8 without a Dodge Master badge. The command's timer counts up from 0 each update. Its look-back count is the table value minus the updates left (duration - stateTimer) plus 3, at least 0: while it is 0, a stick not held left fails the command at once (ACTION_RESULT_EARLY), and once it is above 0 the command succeeds if any of that many latest entries of the held-button buffer has the stick not held left. That opens the release window at timer 41 and keeps it through timer 51, 11 updates (computed); the command marks ready (HES_TimingReady and its sound) at timer 42, one update after the window opens (computed). A stick still held when the timer passes 51 fails. With the basic hammer, a success passes a damage of 2 and a failure 1 (comments in the script call them "good input dmg" and "bad input dmg").Code
Damage formulaIn the US version of Paper Mario, calc_player_damage_enemy works out Mario's damage to an enemy by subtraction. A forced immune hit (BS_FLAGS1_FORCE_IMMUNE_HIT) skips the calculation, and some hits return before it: an illusory, transparent, or buried target (buried unless the attack is a quake) is missed; a stone target takes nothing; a jump on a spiky top without Spike Shield, a contact attack on an explode-on-contact part, on a fiery part without Fire Shield or Ice Power, or on the alternate spiky flag without Spike Shield backfires; and a fire attack that sets off a part that explodes on fire returns before damage. Otherwise it starts from the move's damage (curAttackDamage, which the move script passes), adds Power Plus badges (count_power_plus), and adds or takes fixed amounts for Merlee, the jump and hammer charges, other badges, and statuses (L456-L535). A missed All or Nothing sets the damage to 0, and outside the Japanese build the defense too; a shrunk Mario's damage is halved, but stays at least 1; a blast on a part that explodes on ignition sets the damage to the target's HP and the defense to 0; and DAMAGE_TYPE_STATUS_ALWAYS_HITS sets both to 0. The total is capped at 99, and the target's defense is then subtracted: get_defense, plus the defense boost unless the attack ignores defense, plus 127 for a part flagged extreme defense, or 0 when the total is below 0. A result below 0 becomes 0, and a Power Bounce then adds its counter, keeping a hit above 0 at least 1. The function's one rand_int call, the DAMAGE_TYPE_FEAR scare-away test, runs after the damage is taken off the target's HP.Code
Timed guardIn the US version of Paper Mario, an enemy's hit on Mario is guarded when A was pressed shortly before it lands. calc_enemy_damage_target calls check_block_input(BUTTON_A) when Mario's debuff is none or one numbered at or after STATUS_KEY_POISON (so not dizzy, paralyzed, asleep, frozen, or stopped), he isn't stone, and the attack isn't DAMAGE_TYPE_UNBLOCKABLE; with the Berserker badge, rand_int(1) decides instead. The check returns false before action commands are learned and in demo battles, and returns a guard with no press in the tutorial battle while the mode is AC_MODE_TUTORIAL_BLOCK. It guards if a fresh press of A is in the last 3 entries of the battle's pressed-button buffer, which btl_update writes once per battle update (5 entries with a Dodge Master badge, when the partner isn't acting), unless A was also pressed in the 10 entries before those. A guard takes 1 from Mario's damage, plus 1 for each Damage Dodge badge equipped. A guard by the partner, checked the same way when the partner isn't stone or knocked out, sets the damage to 0.Code

References

  1. ^ abIn the US version of Paper Mario, the jump action command (action_command_jump) is one press of A timed to the stomp, and runs only once Mario has learned action commands (not AC_MODE_NOT_LEARNED). The basic Jump (EVS_UseMove_Basic, the script for menu level 0) computes the jump's length as (distance - 20) / 10.588 + 15 from Mario to the target, gives that count to PlayerBasicJumpToGoal, and passes the same count to the command as prepareTime, at difficulty AC_DIFFICULTY_STANDARD (index 3 of 8). Each update the command counts prepareTime down until it is no more than the window size, actionCmdTableJump[difficulty], which is 4 at standard in a table running 7 down to 0; it then sets the window timer to that size and counts it down to 0. A press of A while prepareTime is still counting sets wrongButtonPressed, and the window then takes no press; the update in which the count reaches the window size runs that early-press test before falling through into the window, so a press there is early too, and a press counts only while the timer runs from 3 to 0, 4 updates at standard (computed), the last of the command's updates. When the partner isn't acting, adjust_action_command_difficulty lowers the difficulty index by 3 for each Dodge Master badge equipped, clamped at 0, so one badge widens the window to 7 updates (computed). A good press makes the basic Jump's first stomp a nice hit, and the script then bounces Mario into a second stomp; each stomp passes a damage of 1. A missed press ends the move after the first.Codepmret/papermariorevised
    How we know
    28Difficulty1D actionCmdTableJump = { 7, 6, 5, 4, 3, 2, 1, 0 };
    
    src/battle/action_cmd.c line 28 at 1104f1f · upstream ↗
    41enum ActionCommandDifficulty {
    42    AC_DIFFICULTY_EASIEST,
    43    AC_DIFFICULTY_VERY_EASY,
    44    AC_DIFFICULTY_EASY,
    45    AC_DIFFICULTY_STANDARD,
    
    src/battle/action_cmd.h lines 41–45 at 1104f1f · upstream ↗
    101s32 adjust_action_command_difficulty(s32 difficultyLevel) {
    102    if (!(gBattleStatus.flags1 & BS_FLAGS1_PARTNER_ACTING)) {
    103        difficultyLevel -= is_ability_active(ABILITY_DODGE_MASTER) * 3;
    ⋮
    106    if (difficultyLevel < AC_DIFFICULTY_EASIEST) {
    107        difficultyLevel = AC_DIFFICULTY_EASIEST;
    
    src/battle/action_cmd.c lines 101–114 at 1104f1f · upstream ↗
    1578s32 is_ability_active(s32 ability) {
    ⋮
    1598    for (i = 0; i < ARRAY_COUNT(playerData->equippedBadges); i++) {
    ⋮
    1607            case ABILITY_DODGE_MASTER:
    1608                if (badgeMoveID == MOVE_DODGE_MASTER) {
    1609                    ret++;
    
    src/inventory.c lines 1578–1610 at 1104f1f · upstream ↗
    57    if (battleStatus->actionCommandMode == AC_MODE_NOT_LEARNED) {
    58        battleStatus->actionQuality = 0;
    59        return ApiStatus_DONE2;
    ⋮
    63    acs->prepareTime = evt_get_variable(script, *args++);
    64    acs->difficulty = evt_get_variable(script, *args++);
    65    acs->difficulty = adjust_action_command_difficulty(acs->difficulty);
    
    src/battle/action_cmd/jump.c lines 57–65 at 1104f1f · upstream ↗
    130            successWindow = battleStatus->actionCmdDifficultyTable[acs->difficulty];
    ⋮
    135            if ((battleStatus->curButtonsPressed & BUTTON_A) && !acs->autoSucceed) {
    136                acs->wrongButtonPressed = true;
    137                battleStatus->actionResult = ACTION_RESULT_EARLY;
    ⋮
    140            if ((acs->prepareTime - successWindow) > 0) {
    141                acs->prepareTime--;
    142                break;
    ⋮
    145            acs->stateTimer = battleStatus->actionCmdDifficultyTable[acs->difficulty];
    ⋮
    155                if (acs->stateTimer == 0) {
    156                    break;
    ⋮
    168            if (battleStatus->actionQuality < 0) {
    169                if (((battleStatus->curButtonsPressed & BUTTON_A) && !acs->wrongButtonPressed) || acs->autoSucceed) {
    ⋮
    
    src/battle/action_cmd/jump.c lines 130–188 at 1104f1f · upstream ↗
    75EvtScript N(EVS_JumpSupport_CalcJumpTime) = {
    ⋮
    85    Sub(LVar6, 20)
    86    DivF(LVar6, Float(10.588))
    87    AddF(LVar6, 15)
    88    Set(LVarA, LVar6)
    
    src/battle/common/move/JumpSupport.inc.c lines 75–88 at 1104f1f · upstream ↗
    309EvtScript N(EVS_JumpSupport_ApproachAndJump) = {
    ⋮
    313    ExecWait(N(EVS_JumpSupport_CalcJumpTime))
    314    Call(action_command_jump_start, LVarA, AC_DIFFICULTY_STANDARD)
    ⋮
    318    Call(PlayerBasicJumpToGoal, LVarA, PLAYER_BASIC_JUMP_0)
    
    src/battle/common/move/JumpSupport.inc.c lines 309–318 at 1104f1f · upstream ↗
    40    Call(GetMenuSelection, LVar0, LVar1, LVar2)
    41    Switch(LVar1)
    42        CaseEq(0)
    43            ExecWait(N(EVS_UseMove_Basic))
    
    src/battle/move/jump/attack.c lines 40–43 at 1104f1f · upstream ↗
    75    Call(GetPlayerActionQuality, LVar0)
    76    Switch(LVar0)
    77        CaseGt(false)
    ⋮
    79            Call(PlayerDamageEnemy, LVar0, DAMAGE_TYPE_JUMP, 0, 0, 1, BS_FLAGS1_INCLUDE_POWER_UPS | BS_FLAGS1_NICE_HIT)
    80        CaseDefault
    ⋮
    82            Call(PlayerDamageEnemy, LVar0, DAMAGE_TYPE_JUMP, 0, 0, 1, BS_FLAGS1_INCLUDE_POWER_UPS | BS_FLAGS1_TRIGGER_EVENTS)
    83    EndSwitch
    84    Switch(LVar0)
    85        CaseOrEq(HIT_RESULT_HIT)
    86        CaseOrEq(HIT_RESULT_NO_DAMAGE)
    87            // missed action command, end the script here
    88            ExecWait(N(EVS_JumpSupport_G))
    ⋮
    
    src/battle/move/jump/attack.c lines 75–95 at 1104f1f · upstream ↗
    107    Call(action_command_jump_start, 24, AC_DIFFICULTY_STANDARD)
    ⋮
    110    Call(PlayerBasicJumpToGoal, 24, PLAYER_BASIC_JUMP_3)
    111    Wait(1)
    ⋮
    113    Call(PlayerDamageEnemy, LVar0, DAMAGE_TYPE_JUMP, 0, 0, 1, BS_FLAGS1_TRIGGER_EVENTS | BS_FLAGS1_NICE_HIT | BS_FLAGS1_NO_RATING)
    
    src/battle/move/jump/attack.c lines 107–113 at 1104f1f · upstream ↗
    1545    battleStatus->curAttackElement = *args++;
    1546    battleStatus->curAttackEventSuppression = *args++;
    1547    battleStatus->curAttackStatus = *args++;
    1548    battleStatus->curAttackDamage = evt_get_variable(script, *args++);
    
    src/battle/dmg_player.c lines 1545–1548 at 1104f1f · upstream ↗
    1028    if (gBattleStatus.flags1 & (BS_FLAGS1_NICE_HIT | BS_FLAGS1_SUPER_HIT)) {
    1029        if (hitResult == HIT_RESULT_HIT) {
    1030            hitResult = HIT_RESULT_NICE;
    
    src/battle/dmg_player.c lines 1028–1031 at 1104f1f · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-22.

    Revised after a check by a second AI model, 2026-10-22.

    In the claim ledger

  2. ^ abIn the US version of Paper Mario, the hammer action command (action_command_hammer) is a hold and release of the stick to the left. When action commands are learned and the Berserker badge isn't equipped, the hammer script (outside the tutorial and auto-success) waits up to 45 updates for the stick to be held left, then starts the command with a duration of 51 (45 plus 6) at AC_DIFFICULTY_STANDARD, whose table value actionCmdTableHammer[3] is 8 without a Dodge Master badge. The command's timer counts up from 0 each update. Its look-back count is the table value minus the updates left (duration - stateTimer) plus 3, at least 0: while it is 0, a stick not held left fails the command at once (ACTION_RESULT_EARLY), and once it is above 0 the command succeeds if any of that many latest entries of the held-button buffer has the stick not held left. That opens the release window at timer 41 and keeps it through timer 51, 11 updates (computed); the command marks ready (HES_TimingReady and its sound) at timer 42, one update after the window opens (computed). A stick still held when the timer passes 51 fails. With the basic hammer, a success passes a damage of 2 and a failure 1 (comments in the script call them "good input dmg" and "bad input dmg").Codepmret/papermario
    How we know
    29Difficulty1D actionCmdTableHammer = { 11, 10, 9, 8, 7, 6, 5, 4 };
    
    src/battle/action_cmd.c line 29 at 1104f1f · upstream ↗
    13API_CALLABLE(N(IsBerserkerEquipped)) {
    14    script->varTable[0] = gBattleStatus.actionCommandMode;
    15    script->varTable[1] = 15;
    ⋮
    17    if (is_ability_active(ABILITY_BERSERKER)) {
    18        script->varTable[0] = AC_MODE_NOT_LEARNED;
    
    src/battle/common/move/HammerSupport.inc.c lines 13–23 at 1104f1f · upstream ↗
    257    Call(N(IsBerserkerEquipped))
    258    IfNe(LVar0, false)
    ⋮
    264                Loop(45)
    265                    Wait(1)
    266                    Call(CheckButtonDown, BUTTON_STICK_LEFT, LVar0)
    267                    IfNe(LVar0, false)
    268                        BreakLoop
    ⋮
    273        Add(LVarD, 6)
    274        Call(action_command_hammer_start, 0, LVarD, AC_DIFFICULTY_STANDARD)
    
    src/battle/common/move/HammerSupport.inc.c lines 257–274 at 1104f1f · upstream ↗
    17        CaseEq(0)
    18            Set(LVarD, 45)// action command duration
    19            Set(LVarE, 1) // bad input dmg
    20            Set(LVarF, 2) // good input dmg
    21            ExecWait(N(EVS_UseMove_Impl))
    
    src/battle/move/hammer/attack.c lines 17–21 at 1104f1f · upstream ↗
    95    Call(GetPlayerActionQuality, LVar0)
    96    Switch(LVar0)
    97        CaseGt(false)
    ⋮
    107            Call(PlayerDamageEnemy, LVar0, DAMAGE_TYPE_SMASH, SUPPRESS_EVENTS_HAMMER, 0, LVarF, BS_FLAGS1_INCLUDE_POWER_UPS | BS_FLAGS1_TRIGGER_EVENTS | BS_FLAGS1_NICE_HIT)
    108        CaseDefault
    ⋮
    118            Call(PlayerDamageEnemy, LVar0, DAMAGE_TYPE_SMASH, SUPPRESS_EVENTS_HAMMER, 0, LVarE, BS_FLAGS1_INCLUDE_POWER_UPS | BS_FLAGS1_TRIGGER_EVENTS)
    
    src/battle/move/hammer/attack.c lines 95–118 at 1104f1f · upstream ↗
    99    acs->prepareTime = evt_get_variable(script, *args++);
    100    acs->duration = evt_get_variable(script, *args++);
    101    acs->difficulty = evt_get_variable(script, *args++);
    102    acs->difficulty = adjust_action_command_difficulty(acs->difficulty);
    
    src/battle/action_cmd/hammer.c lines 99–102 at 1104f1f · upstream ↗
    207            if (acs->prepareTime != 0) {
    208                acs->prepareTime--;
    209                return;
    ⋮
    212            acs->stateTimer = 0;
    ⋮
    216            acs->state = AC_STATE_ACTIVE;
    
    src/battle/action_cmd/hammer.c lines 207–216 at 1104f1f · upstream ↗
    256            if (acs->stateTimer == (-(inputWindow + 1) + acs->duration)) {
    257                battleStatus->actionProgress = 3;
    258                hud_element_set_script(acs->hudElemIDs[HIDX_WAIT], &HES_TimingReady);
    
    src/battle/action_cmd/hammer.c lines 256–258 at 1104f1f · upstream ↗
    268            inputWindow = battleStatus->actionCmdDifficultyTable[acs->difficulty] - (acs->duration - acs->stateTimer) + 3;
    269            if (inputWindow < 0) {
    270                inputWindow = 0;
    ⋮
    273            // has the stick been release too early?
    274            if (!(battleStatus->curButtonsDown & BUTTON_STICK_LEFT)
    275                && inputWindow == 0
    276                && acs->autoSucceed == 0
    277                && battleStatus->actionCommandMode < AC_MODE_TUTORIAL
    278            ) {
    279                battleStatus->actionQuality = AC_QUALITY_FAILED;
    280                battleStatus->actionResult = ACTION_RESULT_EARLY;
    ⋮
    287            bufferPos -= inputWindow;
    ⋮
    
    src/battle/action_cmd/hammer.c lines 268–303 at 1104f1f · upstream ↗
    308            if (battleStatus->actionCommandMode < AC_MODE_TUTORIAL || acs->stateTimer != acs->duration) {
    309                acs->stateTimer++;
    310                if (acs->duration < acs->stateTimer) {
    311                    if (battleStatus->actionQuality == 0) {
    312                        battleStatus->actionQuality = AC_QUALITY_FAILED;
    
    src/battle/action_cmd/hammer.c lines 308–313 at 1104f1f · upstream ↗
    292    battleStatus->pushInputBuffer[battleStatus->inputBufferPos] = battleStatus->curButtonsPressed;
    293    battleStatus->holdInputBuffer[battleStatus->inputBufferPos] = battleStatus->curButtonsDown;
    ⋮
    295    battleStatus->inputBufferPos++;
    296    if (battleStatus->inputBufferPos >= ARRAY_COUNT(battleStatus->pushInputBuffer)) {
    297        battleStatus->inputBufferPos = 0;
    
    src/battle/16C8E0.c lines 292–298 at 1104f1f · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-22.

    Checked by a second AI model, 2026-10-22.

    In the claim ledger

  3. ^ abIn the US version of Paper Mario, an enemy's hit on Mario is guarded when A was pressed shortly before it lands. calc_enemy_damage_target calls check_block_input(BUTTON_A) when Mario's debuff is none or one numbered at or after STATUS_KEY_POISON (so not dizzy, paralyzed, asleep, frozen, or stopped), he isn't stone, and the attack isn't DAMAGE_TYPE_UNBLOCKABLE; with the Berserker badge, rand_int(1) decides instead. The check returns false before action commands are learned and in demo battles, and returns a guard with no press in the tutorial battle while the mode is AC_MODE_TUTORIAL_BLOCK. It guards if a fresh press of A is in the last 3 entries of the battle's pressed-button buffer, which btl_update writes once per battle update (5 entries with a Dodge Master badge, when the partner isn't acting), unless A was also pressed in the 10 entries before those. A guard takes 1 from Mario's damage, plus 1 for each Damage Dodge badge equipped. A guard by the partner, checked the same way when the partner isn't stone or knocked out, sets the damage to 0.Codepmret/papermariorevised
    How we know
    551    if (battleStatus->actionCommandMode == AC_MODE_TUTORIAL_BLOCK && (battleStatus->flags1 & BS_FLAGS1_TUTORIAL_BATTLE)) {
    552        battleStatus->blockResult = BLOCK_RESULT_SUCCESS;
    553        return true;
    
    src/battle/action_cmd.c lines 551–553 at 1104f1f · upstream ↗
    556    if (battleStatus->actionCommandMode == AC_MODE_NOT_LEARNED || (gGameStatusPtr->demoBattleFlags & DEMO_BTL_FLAG_ENABLED)) {
    557        return false;
    ⋮
    567    block = false;
    568    blockWindow = 3;
    569    mashWindow = 10;
    ⋮
    571    if (!(gBattleStatus.flags1 & BS_FLAGS1_PARTNER_ACTING) && is_ability_active(ABILITY_DODGE_MASTER)) {
    572        blockWindow = 5;
    ⋮
    575    // Pre-window mashing check
    576    bufferPos = battleStatus->inputBufferPos;
    577    bufferPos -= mashWindow + blockWindow;
    ⋮
    582    for (i = 0; i < mashWindow; i++) {
    ⋮
    587        if (battleStatus->pushInputBuffer[bufferPos] & buttonMask) {
    ⋮
    
    src/battle/action_cmd.c lines 556–616 at 1104f1f · upstream ↗
    292    battleStatus->pushInputBuffer[battleStatus->inputBufferPos] = battleStatus->curButtonsPressed;
    293    battleStatus->holdInputBuffer[battleStatus->inputBufferPos] = battleStatus->curButtonsDown;
    ⋮
    295    battleStatus->inputBufferPos++;
    
    src/battle/16C8E0.c lines 292–295 at 1104f1f · upstream ↗
    231HitResult calc_enemy_damage_target(Actor* attacker) {
    
    src/battle/1A5830.c line 231 at 1104f1f · upstream ↗
    430    // apply damage mitigation from blocking
    ⋮
    432    switch (actorClass) {
    433        case ACTOR_CLASS_PLAYER:
    ⋮
    435            if ((target->debuff == 0 || target->debuff >= STATUS_KEY_POISON)
    436                && (target->stoneStatus == 0)
    437                && !(battleStatus->curAttackElement & DAMAGE_TYPE_UNBLOCKABLE)
    438            ) {
    ⋮
    441                if (player_team_is_ability_active(target, ABILITY_BERSERKER)) {
    442                    blocked = rand_int(1);
    443                } else {
    444                    blocked = check_block_input(BUTTON_A);
    ⋮
    447                if (blocked) {
    ⋮
    
    src/battle/1A5830.c lines 430–466 at 1104f1f · upstream ↗
    2808    STATUS_KEY_DIZZY                = 0x00000004,
    2809    STATUS_KEY_PARALYZE             = 0x00000005,
    2810    STATUS_KEY_SLEEP                = 0x00000006,
    2811    STATUS_KEY_FROZEN               = 0x00000007,
    2812    STATUS_KEY_STOP                 = 0x00000008,
    2813    STATUS_KEY_POISON               = 0x00000009,
    
    include/enums.h lines 2808–2813 at 1104f1f · upstream ↗
    2870s32 player_team_is_ability_active(Actor* actor, s32 ability) {
    ⋮
    2875        case ACTOR_CLASS_PLAYER:
    2876            if (!(gBattleStatus.flags2 & BS_FLAGS2_PEACH_BATTLE)) {
    2877                hasAbility = is_ability_active(ability);
    
    src/battle/190B20.c lines 2870–2878 at 1104f1f · upstream ↗
    1881            case ABILITY_DAMAGE_DODGE:
    1882                if (badgeMoveID == MOVE_DAMAGE_DODGE) {
    1883                    ret++;
    
    src/inventory.c lines 1881–1883 at 1104f1f · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-22.

    Revised after a check by a second AI model, 2026-10-22.

    In the claim ledger

  4. ^ abIn the US version of Paper Mario, calc_player_damage_enemy works out Mario's damage to an enemy by subtraction. A forced immune hit (BS_FLAGS1_FORCE_IMMUNE_HIT) skips the calculation, and some hits return before it: an illusory, transparent, or buried target (buried unless the attack is a quake) is missed; a stone target takes nothing; a jump on a spiky top without Spike Shield, a contact attack on an explode-on-contact part, on a fiery part without Fire Shield or Ice Power, or on the alternate spiky flag without Spike Shield backfires; and a fire attack that sets off a part that explodes on fire returns before damage. Otherwise it starts from the move's damage (curAttackDamage, which the move script passes), adds Power Plus badges (count_power_plus), and adds or takes fixed amounts for Merlee, the jump and hammer charges, other badges, and statuses (L456-L535). A missed All or Nothing sets the damage to 0, and outside the Japanese build the defense too; a shrunk Mario's damage is halved, but stays at least 1; a blast on a part that explodes on ignition sets the damage to the target's HP and the defense to 0; and DAMAGE_TYPE_STATUS_ALWAYS_HITS sets both to 0. The total is capped at 99, and the target's defense is then subtracted: get_defense, plus the defense boost unless the attack ignores defense, plus 127 for a part flagged extreme defense, or 0 when the total is below 0. A result below 0 becomes 0, and a Power Bounce then adds its counter, keeping a hit above 0 at least 1. The function's one rand_int call, the DAMAGE_TYPE_FEAR scare-away test, runs after the damage is taken off the target's HP.Codepmret/papermariorevised
    How we know
    240HitResult calc_player_damage_enemy(void) {
    
    src/battle/dmg_player.c line 240 at 1104f1f · upstream ↗
    292    if (gBattleStatus.flags1 & BS_FLAGS1_FORCE_IMMUNE_HIT) {
    293        hitResult = HIT_RESULT_NO_DAMAGE;
    ⋮
    302        if (targetPart->eventFlags & ACTOR_EVENT_FLAG_ILLUSORY
    303            || target->transparentStatus == STATUS_KEY_TRANSPARENT
    304            || (targetPart->eventFlags & ACTOR_EVENT_FLAG_BURIED && !(battleStatus->curAttackElement & DAMAGE_TYPE_QUAKE))
    305        ) {
    306            return HIT_RESULT_MISS;
    ⋮
    309        if (target->stoneStatus == STATUS_KEY_STONE) {
    ⋮
    314                return HIT_RESULT_NICE;
    ⋮
    325        if ((battleStatus->curAttackElement & DAMAGE_TYPE_JUMP)
    326            && (targetPart->eventFlags & ACTOR_EVENT_FLAG_SPIKY_TOP)
    327            && !player_team_is_ability_active(player, ABILITY_SPIKE_SHIELD))
    ⋮
    
    src/battle/dmg_player.c lines 292–380 at 1104f1f · upstream ↗
    443        targetDefense = get_defense(target, targetPart->defenseTable, battleStatus->curAttackElement);
    ⋮
    445        if (!(battleStatus->curAttackElement & DAMAGE_TYPE_IGNORE_DEFENSE)) {
    446            targetDefense += target->defenseBoost;
    ⋮
    449        if (targetPart->eventFlags & ACTOR_EVENT_FLAG_EXTREME_DEFENSE) {
    450            targetDefense += 127;
    ⋮
    453        currentAttackDamage = battleStatus->curAttackDamage;
    454        currentAttackDamage += count_power_plus(battleStatus->curAttackElement);
    ⋮
    456        if (battleStatus->merleeAttackBoost > 0
    ⋮
    458        ) {
    459            currentAttackDamage += battleStatus->merleeAttackBoost;
    
    src/battle/dmg_player.c lines 443–459 at 1104f1f · upstream ↗
    462        if (battleStatus->jumpCharge && battleStatus->curAttackElement & DAMAGE_TYPE_JUMP) {
    463            currentAttackDamage += battleStatus->jumpCharge;
    ⋮
    467        if (battleStatus->hammerCharge && battleStatus->curAttackElement & (DAMAGE_TYPE_QUAKE_HAMMER | DAMAGE_TYPE_THROW | DAMAGE_TYPE_SMASH)) {
    468            currentAttackDamage += battleStatus->hammerCharge;
    ⋮
    473            currentAttackDamage += 2;
    ⋮
    476        if (player_team_is_ability_active(player, ABILITY_BERSERKER)) {
    477            currentAttackDamage += 2;
    ⋮
    480        if (player_team_is_ability_active(player, ABILITY_P_UP_D_DOWN)) {
    481            currentAttackDamage++;
    ⋮
    484        if (player_team_is_ability_active(player, ABILITY_P_DOWN_D_UP)) {
    485            currentAttackDamage--;
    ⋮
    488        if (battleStatus->turboChargeTurnsLeft != 0) {
    ⋮
    
    src/battle/dmg_player.c lines 462–492 at 1104f1f · upstream ↗
    537        if (!(gBattleStatus.flags2 & BS_FLAGS2_IS_FIRST_STRIKE)
    538            && player_team_is_ability_active(player, ABILITY_ALL_OR_NOTHING)
    539        ) {
    540            currentAttackDamage++;
    ⋮
    542            if (!(gBattleStatus.flags1 & (BS_FLAGS1_NICE_HIT | BS_FLAGS1_SUPER_HIT))) {
    543                missedAllOrNothing = true;
    544                currentAttackDamage = 0;
    545#if !VERSION_JP
    546                targetDefense = 0;
    547#endif
    ⋮
    555        if (player->debuff == STATUS_KEY_SHRINK) {
    556            if (currentAttackDamage > 0) {
    ⋮
    
    src/battle/dmg_player.c lines 536–576 at 1104f1f · upstream ↗
    578        if (currentAttackDamage > 99) {
    579            currentAttackDamage = 99;
    ⋮
    582        if (currentAttackDamage < 0) {
    583            targetDefense = 0;
    ⋮
    586        target->hpChangeCounter = 0;
    587        currentAttackDamage -= targetDefense;
    ⋮
    589        if (currentAttackDamage < 0) {
    590            currentAttackDamage = 0;
    ⋮
    593        if (battleStatus->curAttackElement & DAMAGE_TYPE_POWER_BOUNCE && currentAttackDamage > 0) {
    594            currentAttackDamage += battleStatus->powerBounceCounter;
    ⋮
    596            if (currentAttackDamage < 1) {
    597                currentAttackDamage = 1;
    
    src/battle/dmg_player.c lines 578–598 at 1104f1f · upstream ↗
    630                target->curHP -= currentAttackDamage;
    
    src/battle/dmg_player.c line 630 at 1104f1f · upstream ↗
    672        if (gBattleStatus.flags1 & BS_FLAGS1_TRIGGER_EVENTS) {
    673            if (battleStatus->curAttackElement & DAMAGE_TYPE_FEAR
    674                && rand_int(99) < (target->actorBlueprint->escapeChance * battleStatus->statusChance) / 100
    
    src/battle/dmg_player.c lines 672–674 at 1104f1f · upstream ↗
    1548    battleStatus->curAttackDamage = evt_get_variable(script, *args++);
    
    src/battle/dmg_player.c line 1548 at 1104f1f · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-22.

    Revised after a check by a second AI model, 2026-10-22.

    In the claim ledger

Sources

Code