-
Black/White
- Home
- Sword/Shield
- Sun/Moon
- X/Y
- Black/White
- Diamond/Pearl
- Ruby/Sapphire
- Gold/Silver
- Red/Blue
| The Complete Damage Formula for Black & White
- Introduction
-
Main concepts
- General flow of damage calculation
- How to apply a modifier
- How to chain modifiers
- The multi-target modifier
- The weather modifier
- Critical hits
- The random factor
- STAB
- Type effectiveness
- Effect of a burn
- Final modifier
-
The base power
- Triggers for variable base power
- Modifiers for the base power
-
User attack stat
- Base value
- Boost level
- Attack modifiers
-
Target defense stat
- Base value
- Boost level
- Sandstorm modifier
- Defense modifiers
- Special cases
In Generation IV, the damage formula was derived empirically by X-Act from running it countless times, an approach that is both tedious and prone to errors. The good understanding of the ARM code for Black & White allows us to document the damage formula based on the actual source code of the game. It doesn't guarantee that we didn't make any mistake (interpreting assembly language is in itself a tricky task) but having the documented source along with the formula backs up our claims and allows anyone who spots any error to fix it by themselves.
MEMORY:021C1E94 @ int __fastcall DamageCalc(void *trigger_table, void **attacking_bpkm, void **defending_bpkm, unsigned __int16 *move_id)
MEMORY:021C1E94 DamageCalc: @ CODE XREF: MEMORY:021C0B28p
MEMORY:021C1E94
MEMORY:021C1E94 double_damage= -0x30
MEMORY:021C1E94 p_attacking= -0x2C
MEMORY:021C1E94 current_damage= -0x28
MEMORY:021C1E94 static_damage= -0x24
MEMORY:021C1E94 move_cat= -0x20
MEMORY:021C1E94 base_power= -0x1C
MEMORY:021C1E94 attack_stat= -0x18
MEMORY:021C1E94 effectiveness_factor= 0
MEMORY:021C1E94 field_mod= 4
MEMORY:021C1E94 is_critical= 8
MEMORY:021C1E94 rig_mindamage= 0xC
MEMORY:021C1E94 p_store_result= 0x10
MEMORY:021C1E94
MEMORY:021C1E94 PUSH {R4-R7,LR}
MEMORY:021C1E96 SUB SP, SP, #0x1C
MEMORY:021C1E98 MOVS R4, R3
MEMORY:021C1E9A MOVS R5, R0
MEMORY:021C1E9C LDRH R0, [R4]
MEMORY:021C1E9E STR R1, [SP,#0x30+p_attacking]
MEMORY:021C1EA0 MOVS R7, R2
MEMORY:021C1EA2 LDR R6, [SP,#0x30+is_critical]
MEMORY:021C1EA4 BL GetMoveCategory
MEMORY:021C1EA8 STR R0, [SP,#0x30+move_cat]
MEMORY:021C1EAA MOVS R0, #0
MEMORY:021C1EAC STR R0, [SP,#0x30+static_damage]
MEMORY:021C1EAE LDR R0, =0x1C21
MEMORY:021C1EB0 BL AllocateVolatileVariables
MEMORY:021C1EB4 LDR R1, [SP,#0x30+effectiveness_factor]
MEMORY:021C1EB6 MOVS R0, #0x38 @ '8'
MEMORY:021C1EB8 BL StoreVolatileVariableFlag3e4
MEMORY:021C1EBC LDR R0, [SP,#0x30+p_attacking]
MEMORY:021C1EBE BL Dereference25
MEMORY:021C1EC2 MOVS R1, R0
MEMORY:021C1EC4 MOVS R0, #3
MEMORY:021C1EC6 BL StoreVolatileVariableFlag3e4
MEMORY:021C1ECA MOVS R0, R7
MEMORY:021C1ECC BL Dereference25
MEMORY:021C1ED0 MOVS R1, R0
MEMORY:021C1ED2 MOVS R0, #4
MEMORY:021C1ED4 BL StoreVolatileVariableFlag3e4
MEMORY:021C1ED8 MOVS R0, #0x45 @ 'E'
MEMORY:021C1EDA MOVS R1, R6
MEMORY:021C1EDC BL StoreVolatileVariableFlag3e4
MEMORY:021C1EE0 LDRB R1, [R4,#6]
MEMORY:021C1EE2 MOVS R0, #0x16
MEMORY:021C1EE4 BL StoreVolatileVariableFlag3e4
MEMORY:021C1EE8 LDRH R1, [R4]
MEMORY:021C1EEA MOVS R0, #0x12
MEMORY:021C1EEC BL StoreVolatileVariableFlag3e4
MEMORY:021C1EF0 LDR R1, [SP,#0x30+move_cat]
MEMORY:021C1EF2 MOVS R0, #0x1A
MEMORY:021C1EF4 BL StoreVolatileVariableFlag3e4
MEMORY:021C1EF8 MOVS R0, #0x37 @ '7'
MEMORY:021C1EFA MOVS R1, #0
MEMORY:021C1EFC BL InitVolatileVariable
MEMORY:021C1F00 MOVS R0, R5
MEMORY:021C1F02 MOVS R1, #0x46 @ 'F'
MEMORY:021C1F04 BL ApplyTriggers
MEMORY:021C1F08 MOVS R0, #0x37 @ '7'
MEMORY:021C1F0A BL ReadVolatileVariable
MEMORY:021C1F0E STR R0, [SP,#0x30+current_damage]
MEMORY:021C1F10 CMP R0, #0
MEMORY:021C1F12 BEQ Bank0
MEMORY:021C1F14 MOVS R0, #1
MEMORY:021C1F16 STR R0, [SP,#0x30+static_damage]
MEMORY:021C1F18 B Bank9
MEMORY:021C1F1A @ ---------------------------------------------------------------------------
MEMORY:021C1F1A
MEMORY:021C1F1A Bank0: @ CODE XREF: DamageCalc+7Ej
MEMORY:021C1F1A LDR R1, [SP,#0x30+p_attacking]
MEMORY:021C1F1C MOVS R0, R5
MEMORY:021C1F1E MOVS R2, R7
MEMORY:021C1F20 MOVS R3, R4
MEMORY:021C1F22 BL BasePowerMods
MEMORY:021C1F26 STR R0, [SP,#0x30+base_power]
MEMORY:021C1F28 LDR R1, [SP,#0x30+p_attacking]
MEMORY:021C1F2A MOVS R0, R5
MEMORY:021C1F2C MOVS R2, R7
MEMORY:021C1F2E MOVS R3, R4
MEMORY:021C1F30 STR R6, [SP,#0x30+double_damage]
MEMORY:021C1F32 BL BaseAttackMods
MEMORY:021C1F36 STR R0, [SP,#0x30+attack_stat]
MEMORY:021C1F38 LDR R1, [SP,#0x30+p_attacking]
MEMORY:021C1F3A MOVS R0, R5
MEMORY:021C1F3C MOVS R2, R7
MEMORY:021C1F3E MOVS R3, R4
MEMORY:021C1F40 STR R6, [SP,#0x30+double_damage]
MEMORY:021C1F42 BL BaseDefenseMods
MEMORY:021C1F46 MOVS R7, R0
MEMORY:021C1F48 LDR R0, [SP,#0x30+p_attacking]
MEMORY:021C1F4A MOVS R1, #0xF
MEMORY:021C1F4C BL GetBpkmStat
MEMORY:021C1F50 LSLS R0, R0, #0x18
MEMORY:021C1F52 LSRS R2, R0, #0x18
MEMORY:021C1F54 LDR R0, [SP,#0x30+base_power]
MEMORY:021C1F56 LDR R1, [SP,#0x30+attack_stat]
MEMORY:021C1F58 MOVS R3, R7
MEMORY:021C1F5A BL BaseDamageFormula
MEMORY:021C1F5E MOVS R2, #4
MEMORY:021C1F60 LDR R1, [SP,#0x30+field_mod]
MEMORY:021C1F62 LSLS R2, R2, #0xA
MEMORY:021C1F64 MOVS R7, R0
MEMORY:021C1F66 CMP R1, R2
MEMORY:021C1F68 BEQ Bank1
MEMORY:021C1F6A BL ApplyMod
MEMORY:021C1F6E ADDS R7, R0, #0
MEMORY:021C1F70
MEMORY:021C1F70 Bank1: @ CODE XREF: DamageCalc+D4j
MEMORY:021C1F70 MOVS R0, R5
MEMORY:021C1F72 BL WeatherTriggers
MEMORY:021C1F76 LDRB R1, [R4,#6]
MEMORY:021C1F78 BL WeatherMod
MEMORY:021C1F7C MOVS R1, R0
MEMORY:021C1F7E MOVS R0, 0x1000
MEMORY:021C1F82 CMP R1, R0
MEMORY:021C1F84 BEQ Bank2
MEMORY:021C1F86 MOVS R0, R7
MEMORY:021C1F88 BL ApplyMod
MEMORY:021C1F8C ADDS R7, R0, #0
MEMORY:021C1F8E
MEMORY:021C1F8E Bank2: @ CODE XREF: DamageCalc+F0j
MEMORY:021C1F8E CMP R6, #0
MEMORY:021C1F90 BEQ Bank3
MEMORY:021C1F92 LSLS R7, R7, #1
MEMORY:021C1F94
MEMORY:021C1F94 Bank3: @ CODE XREF: DamageCalc+FCj
MEMORY:021C1F94 LDR R0, [R5,#4]
MEMORY:021C1F96 MOVS R1, #7
MEMORY:021C1F98 BL sub_21B913C
MEMORY:021C1F9C CMP R0, #0
MEMORY:021C1F9E BNE Bank6
MEMORY:021C1FA0 LDR R0, [SP,#0x30+rig_mindamage]
MEMORY:021C1FA2 CMP R0, #0
MEMORY:021C1FA4 BEQ Bank4
MEMORY:021C1FA6 MOVS R0, #0x55 @ 'U'
MEMORY:021C1FA8 B Bank5
MEMORY:021C1FAA @ ---------------------------------------------------------------------------
MEMORY:021C1FAA
MEMORY:021C1FAA Bank4: @ CODE XREF: DamageCalc+110j
MEMORY:021C1FAA MOVS R0, #0x10
MEMORY:021C1FAC BL BRand
MEMORY:021C1FB0 MOVS R1, #0x64 @ 'd'
MEMORY:021C1FB2 SUBS R0, R1, R0
MEMORY:021C1FB4 LSLS R0, R0, #0x10
MEMORY:021C1FB6 LSRS R0, R0, #0x10
MEMORY:021C1FB8
MEMORY:021C1FB8 Bank5: @ CODE XREF: DamageCalc+114j
MEMORY:021C1FB8 MULS R0, R7
MEMORY:021C1FBA MOVS R1, #0x64 @ 'd' @ divisor
MEMORY:021C1FBC BLX divmodUnsigned__
MEMORY:021C1FC0 ADDS R7, R0, #0
MEMORY:021C1FC2
MEMORY:021C1FC2 Bank6: @ CODE XREF: DamageCalc+10Aj
MEMORY:021C1FC2 LDRB R2, [R4,#6]
MEMORY:021C1FC4 CMP R2, #0x11
MEMORY:021C1FC6 BEQ Bank7
MEMORY:021C1FC8 LDR R1, [SP,#0x30+p_attacking]
MEMORY:021C1FCA ADDS R0, R5, #0
MEMORY:021C1FCC
MEMORY:021C1FCC Bank_STAB: @ CODE XREF: MEMORY:021C1D6Aj
MEMORY:021C1FCC BL STAB
MEMORY:021C1FD0 MOVS R1, R0
MEMORY:021C1FD2 MOVS R0, R7
MEMORY:021C1FD4 BL ApplyMod
MEMORY:021C1FD8 ADDS R7, R0, #0
MEMORY:021C1FDA
MEMORY:021C1FDA Bank7: @ CODE XREF: DamageCalc+132j
MEMORY:021C1FDA LDR R1, [SP,#0x30+effectiveness_factor]
MEMORY:021C1FDC
MEMORY:021C1FDC loc_21C1FDC: @ CODE XREF: MEMORY:021C1D7Aj
MEMORY:021C1FDC MOVS R0, R7
MEMORY:021C1FDE BL TypeEffectiveness
MEMORY:021C1FE2 MOVS R4, R0
MEMORY:021C1FE4 LDR R0, [SP,#0x30+move_cat]
MEMORY:021C1FE6 CMP R0, #1
MEMORY:021C1FE8 BNE Bank_notnull
MEMORY:021C1FEA LDR R0, [SP,#0x30+p_attacking]
MEMORY:021C1FEC BL GetBpkmStatus
MEMORY:021C1FF0 CMP R0, #4
MEMORY:021C1FF2 BNE Bank_notnull
MEMORY:021C1FF4 LDR R0, [SP,#0x30+p_attacking]
MEMORY:021C1FF6 MOVS R1, #0x11
MEMORY:021C1FF8 BL GetBpkmStat
MEMORY:021C1FFC CMP R0, #0x3E @ '>'
MEMORY:021C1FFE BEQ Bank_notnull
MEMORY:021C2000 MOVS R0, #0x32 @ '2'
MEMORY:021C2002 MULS R0, R4
MEMORY:021C2004 MOVS R1, #0x64 @ 'd' @ divisor
MEMORY:021C2006 BLX divmodUnsigned__
MEMORY:021C200A ADDS R4, R0, #0
MEMORY:021C200C
MEMORY:021C200C Bank_notnull: @ CODE XREF: DamageCalc+154j
MEMORY:021C200C @ DamageCalc+15Ej ...
MEMORY:021C200C CMP R4, #0
MEMORY:021C200E BNE Bank8
MEMORY:021C2010 MOVS R4, #1
MEMORY:021C2012
MEMORY:021C2012 Bank8: @ CODE XREF: DamageCalc+17Aj
MEMORY:021C2012 MOVS R1, 0x1000
MEMORY:021C2016 MOVS R0, #0x35 @ '5'
MEMORY:021C2018 MOVS R2, #0x29 @ ')'
MEMORY:021C201A LSLS R3, R1, #5
MEMORY:021C201C BL StoreVolatileVariableFlag3e3
MEMORY:021C2020 MOVS R0, #0x32 @ '2'
MEMORY:021C2022 MOVS R1, R4
MEMORY:021C2024 BL InitVolatileVariable
MEMORY:021C2028 MOVS R0, R5
MEMORY:021C202A MOVS R1, #0x47 @ 'G'
MEMORY:021C202C BL ApplyTriggers
MEMORY:021C2030 MOVS R0, #0x35 @ '5'
MEMORY:021C2032 BL ReadVolatileVariable
MEMORY:021C2036 MOVS R4, R0
MEMORY:021C2038 MOVS R0, #0x32 @ '2'
MEMORY:021C203A BL ReadVolatileVariable
MEMORY:021C203E MOVS R1, R4
MEMORY:021C2040 BL ApplyMod
MEMORY:021C2044 STR R0, [SP,#0x30+current_damage]
MEMORY:021C2046
MEMORY:021C2046 Bank9: @ CODE XREF: DamageCalc+84j
MEMORY:021C2046 MOVS R0, R5
MEMORY:021C2048 MOVS R1, #0x48 @ 'H'
MEMORY:021C204A BL ApplyTriggers
MEMORY:021C204E LDR R0, =0x1C8D
MEMORY:021C2050 BL FreeVolatileVariable
MEMORY:021C2054 LDR R1, [SP,#0x30+p_store_result]
MEMORY:021C2056 LDR R0, [SP,#0x30+current_damage]
MEMORY:021C2058 STRH R0, [R1]
MEMORY:021C205A LDR R0, [SP,#0x30+static_damage]
MEMORY:021C205C ADD SP, SP, #0x1C
MEMORY:021C205E POP {R4-R7,PC}
MEMORY:021C205E @ End of function DamageCalc
Roughly speaking, the damage formula in Pokémon is a big multiplication, each factor representing the user's level and attack
stat, the foe's defense stat, and a bunch of factors for STAB, held items, abilities and other field effects.
In a perfect world where ARM CPUs could work on real numbers, it would be possible to multiply each factor in any order
and get the same result, but in practice the game will round some multiplications and truncate others, meaning that
in order to get accurate damage results, it is of utmost importance to perform the multiplication in the same order
as the game and using the same rounding methods. Even though rounding errors might not sound like a big problem, they
will be amplified at each step, and a few factors such as Reflect and Life Orb in a double battle can cause a significant
difference between an unrounded and a properly rounded calculation.
There are three main parameters for damage calculation: the user's attack stat, the target's defense stat and the move's
base power. To compute these stats, the game starts from a base value and apply a modifier to reflect the various
effects that can alter the base value. This modifier is obtained by running through a list of short functions called triggers
that are called based on the current active effects on field. Different triggers can modify the same modifier before it is
applied, this operation is called chaining and is explained below.
Once the main parameters are set, the general steps of the calculation are as follows:
BaseDamage = ((((2 × Level) ÷ 5 + 2) * BasePower * [Sp]Atk) ÷ [Sp]Def) ÷ 50 + 2
- Apply the multi-target modifier
- Apply the weather modifier
- In case of a critical hit, double the value
- Alter with a random factor
- Apply STAB modifier
- Alter with type effectiveness
- Alter with user's burn
- Make sure damage is at least 1
- Apply the final modifier
In this article, ÷ always denotes the in-game unsigned divmod function, i.e. the unrounded/truncated integer division.
By contrast, "apply a modifier" is a rounded operation explained in the next subsection.
There are some exceptions to the formula above that correspond to the set of triggers at the very top of the damage function;
they are detailed in a separate section.
MEMORY:021D7B30 @ int __fastcall ApplyMod(int base_value, int modifier)
MEMORY:021D7B30 ApplyMod: @ CODE XREF: sub_21BC968+68p
MEMORY:021D7B30 MULS R1, R0
MEMORY:021D7B32 LDR R0, =0xFFF
MEMORY:021D7B34 MOVS R2, R1
MEMORY:021D7B36 ANDS R2, R0
MEMORY:021D7B38 LSRS R0, R1, #0xC
MEMORY:021D7B3A MOVS R1, 0x800
MEMORY:021D7B3E CMP R2, R1
MEMORY:021D7B40 BLS locret_21D7B44
MEMORY:021D7B42 ADDS R0, R0, #1
A modifier is a 16 bit fixed point factor, i.e. a fraction whose divisor is always 0x1000 (4096). For instance, 0x14cc is the modifier for Life Orb (0x14cc/0x1000 is about 1.3). Applying the modifier
M to the damage value D means multiplying D by M and dividing the result by 0x1000; then if the decimal part is ≤0.5, round the result down, otherwise round it up.
Simply put: D' = round(D * M / 0x1000)
MEMORY:021D7724 @ void __fastcall ChainMod(__int16 Volatile_index, int mod)
MEMORY:021D7724 ChainMod: @ CODE XREF: AccuracyCheck+FAp
MEMORY:021D7724 @ MEMORY:021D8B5Ep ...
MEMORY:021D7724 PUSH {R3-R7,LR}
MEMORY:021D7726 MOVS R2, R0
MEMORY:021D7728 MOVS R7, R1
MEMORY:021D772A LDR R0, =VolatileStore
MEMORY:021D772C MOVS R1, R2
MEMORY:021D772E BL sub_21D7808
MEMORY:021D7732 MOVS R5, R0
MEMORY:021D7734 BMI locret_21D7772
MEMORY:021D7736 LDR R0, =VolatileStore
MEMORY:021D7738 ADDS R1, R0, R5
MEMORY:021D773A LDR R0, =0x544
MEMORY:021D773C LDRB R0, [R1,R0]
MEMORY:021D773E CMP R0, #3
MEMORY:021D7740 BNE locret_21D7772
MEMORY:021D7742 LDR R4, =VolatileStore
MEMORY:021D7744 LSLS R6, R5, #2
MEMORY:021D7746 ADDS R4, #0xC4 @ '-'
MEMORY:021D7748 LDR R0, [R4,R6] @ num1
MEMORY:021D774A ASRS R3, R7, #0x1F
MEMORY:021D774C ASRS R1, R0, #0x1F
MEMORY:021D774E MOVS R2, R7 @ num2
MEMORY:021D7750 BLX mul64Unsigned__
MEMORY:021D7754 MOVS R3, R1
MEMORY:021D7756 MOVS R1, R5
MEMORY:021D7758 MOVS R5, #2
MEMORY:021D775A MOVS R2, R0
MEMORY:021D775C MOVS R7, #0
MEMORY:021D775E LSLS R5, R5, #0xA
MEMORY:021D7760 ADDS R2, R2, R5
MEMORY:021D7762 ADCS R3, R7
MEMORY:021D7764 LDR R0, =VolatileStore
MEMORY:021D7766 LSLS R3, R3, #0x14
MEMORY:021D7768 LSRS R2, R2, #0xC
MEMORY:021D776A ORRS R2, R3
MEMORY:021D776C BL sub_21D782C
MEMORY:021D7770 STR R0, [R4,R6]
Recall that modifiers for a given parameters are computed by the triggers for that parameter. This means that when multiple triggers apply, you have to chain the modifier for the parameter, starting from 0x1000.
If the current modifier is M and you want to chain with another modifier M', the resulting modifier would be: M'' = ((M * M') + 0x800) >> 12
MEMORY:021C0DCC @ ---------------------------------------------------------------------------
MEMORY:021C0DBE BL sub_21C0EE4
MEMORY:021C0DC2 CMP R0, #1
MEMORY:021C0DC4 BNE loc_21C0DCC
MEMORY:021C0DC6 MOVS R4, 0x1000
MEMORY:021C0DCA B loc_21C0DD0
MEMORY:021C0DCC @ ---------------------------------------------------------------------------
MEMORY:021C0DCC loc_21C0DCC:
MEMORY:021C0DCC MOVS R4, 0xC00
This modifier doesn't have any trigger and is set to 0xC00 if the move has more than one target and 0x1000 otherwise.
Being a target is independent of all accuracy and effectiveness checks, but a fainted Pokémon on the field will not count
as a target.
MEMORY:021D7C58 @ int __fastcall WeatherMod(__int16 active_weather)
MEMORY:021D7C58 WeatherMod: @ CODE XREF: DamageCalc+E4p
MEMORY:021D7C58 CMP R0, #1
MEMORY:021D7C5A BEQ loc_21D7C62
MEMORY:021D7C5C CMP R0, #2
MEMORY:021D7C5E BEQ loc_21D7C76
MEMORY:021D7C60 B loc_21D7C8A
MEMORY:021D7C62 @ ---------------------------------------------------------------------------
MEMORY:021D7C62
MEMORY:021D7C62 loc_21D7C62: @ CODE XREF: WeatherMod+2j
MEMORY:021D7C62 CMP R1, #9
MEMORY:021D7C64 BNE loc_21D7C6C
MEMORY:021D7C66 MOVS R0, 0x1800
MEMORY:021D7C6A BX LR
MEMORY:021D7C6C @ ---------------------------------------------------------------------------
MEMORY:021D7C6C
MEMORY:021D7C6C loc_21D7C6C: @ CODE XREF: WeatherMod+Cj
MEMORY:021D7C6C CMP R1, #0xA
MEMORY:021D7C6E BNE loc_21D7C8A
MEMORY:021D7C70 MOVS R0, 0x800
MEMORY:021D7C74 BX LR
MEMORY:021D7C76 @ ---------------------------------------------------------------------------
MEMORY:021D7C76
MEMORY:021D7C76 loc_21D7C76: @ CODE XREF: WeatherMod+6j
MEMORY:021D7C76 CMP R1, #9
MEMORY:021D7C78 BNE loc_21D7C80
MEMORY:021D7C7A MOVS R0, 0x800
MEMORY:021D7C7E BX LR
MEMORY:021D7C80 @ ---------------------------------------------------------------------------
MEMORY:021D7C80
MEMORY:021D7C80 loc_21D7C80: @ CODE XREF: WeatherMod+20j
MEMORY:021D7C80 CMP R1, #0xA
MEMORY:021D7C82 BNE loc_21D7C8A
MEMORY:021D7C84 MOVS R0, 0x1800
MEMORY:021D7C88 BX LR
MEMORY:021D7C8A @ ---------------------------------------------------------------------------
MEMORY:021D7C8A
MEMORY:021D7C8A loc_21D7C8A: @ CODE XREF: WeatherMod+8j
MEMORY:021D7C8A @ WeatherMod+16j ...
MEMORY:021D7C8A MOVS R0, 0x1000
MEMORY:021D7C8E BX LR
Even though the weather modifier has its own set of triggers listed below, they never affect the actual value of the
modifier: a water move used during rain or a fire move used during intense sunlight will use 0x1800 as modifier, while a
fire move used during rain or a water move during intense sunlight will use 0x800.
Trigger address |
Trigger description |
21d9850 |
Cancel weather if any Pokémon on field has Air Lock or Cloud Nine. |
21d9084 |
Internal. |
Trigger address |
Trigger description |
21d9be8 |
Super Luck: increase user's critical hit level by 1. |
21d9bc4 |
Battle Armor / Shell Armor: if the target has either of these abilities, bypass critical hit checks. |
21dae18 |
Internal. |
21de5fc |
Stick: if user is Farfetch'd and holds Stick, increase critical hit level by 2. |
21de5b8 |
Lucky Punch: if user is Chansey and holds Lucky Punch, increase critical hit level by 2. |
21de584 |
Razor Claw: increase holder's critical hit level by 1. |
21e53b4 |
Internal. |
6899210 |
Lucky Chant: if the user's party is protected by Lucky Chant, bypass critical hit checks. |
Provided the battle isn't rigged to always use minimum damage, the current damage value D is altered using a random number 0 ≤ R ≤ 15:
D' = (D * (100-R)) ÷ 100
MEMORY:021C760C STAB: @ CODE XREF: DamageCalc:Bank_STABp
MEMORY:021C760C PUSH {R3-R7,LR}
MEMORY:021C760E MOVS R7, R1
MEMORY:021C7610 MOVS R5, R0
MEMORY:021C7612 MOVS R0, R7
MEMORY:021C7614 MOVS R1, R2
MEMORY:021C7616 BL IsMoveOfUserType
MEMORY:021C761A MOVS R6, R0
MEMORY:021C761C MOVS R4, #1
MEMORY:021C761E LDR R0, =0x3178
MEMORY:021C7620 LSLS R4, R4, #0xC
MEMORY:021C7622 BL AllocateVolatileVariables
MEMORY:021C7626 MOVS R0, R7
MEMORY:021C7628 BL Dereference25
MEMORY:021C762C MOVS R1, R0
MEMORY:021C762E MOVS R0, #2
MEMORY:021C7630 BL StoreVolatileVariableFlag3e4
MEMORY:021C7634 MOVS R0, #0x51 @ 'Q'
MEMORY:021C7636 MOVS R1, R6
MEMORY:021C7638 BL StoreVolatileVariableFlag3e1
MEMORY:021C763C MOVS R0, R5
MEMORY:021C763E MOVS R1, #0x40 @ '@'
MEMORY:021C7640 BL ApplyTriggers
MEMORY:021C7644 MOVS R0, #0x51 @ 'Q'
MEMORY:021C7646 BL ReadVolatileVariable
MEMORY:021C764A MOVS R1, R0
MEMORY:021C764C BEQ loc_21C7652
MEMORY:021C764E MOVS R4, 0x1800
MEMORY:021C7652
MEMORY:021C7652 loc_21C7652: @ CODE XREF: STAB+40j
MEMORY:021C7652 MOVS R0, #0x44 @ 'D'
MEMORY:021C7654 BL StoreVolatileVariableFlag3e4
MEMORY:021C7658 MOVS R0, #0x35 @ '5'
MEMORY:021C765A MOVS R1, R4
MEMORY:021C765C BL InitVolatileVariable
MEMORY:021C7660 MOVS R0, R5
MEMORY:021C7662 MOVS R1, #0x41 @ 'A'
MEMORY:021C7664 BL ApplyTriggers
MEMORY:021C7668 MOVS R0, #0x35 @ '5'
MEMORY:021C766A BL ReadVolatileVariable
MEMORY:021C766E MOVS R4, R0
MEMORY:021C7670 LDR R0, =0x3189
MEMORY:021C7672 BL FreeVolatileVariable
MEMORY:021C7676 MOVS R0, R4
MEMORY:021C7678 POP {R3-R7,PC}
MEMORY:021C7678 @ End of function STAB
If the type of the move match one of its users', the STAB modifier is set to 0x1800. The only trigger for this modifier is listed below.
Trigger address |
Trigger description |
21D8C2D |
Adaptability: if the user has this ability and move matches one of the user's types, the initial value for the final modifier is set to 0x2000. |
MEMORY:021D7A8C TypeEffectiveness: @ CODE XREF: DamageCalc+14Ap
MEMORY:021D7A8C CMP R1, #5
MEMORY:021D7A8E BHI locret_21D7ABA
MEMORY:021D7A90 ADDS R1, R1, R1
MEMORY:021D7A92 ADD R1, PC
MEMORY:021D7A94 LDRH R1, [R1,#6]
MEMORY:021D7A96 LSLS R1, R1, #0x10
MEMORY:021D7A98 ASRS R1, R1, #0x10
MEMORY:021D7A9A ADD PC, R1
MEMORY:021D7A9A @ ---------------------------------------------------------------------------
MEMORY:021D7A9C .byte 0xA
MEMORY:021D7A9D .byte 0
MEMORY:021D7A9E .byte 0xE
MEMORY:021D7A9F .byte 0
MEMORY:021D7AA0 .byte 0x12
MEMORY:021D7AA1 .byte 0
MEMORY:021D7AA2 .byte 0x14
MEMORY:021D7AA3 .byte 0
MEMORY:021D7AA4 .byte 0x16
MEMORY:021D7AA5 .byte 0
MEMORY:021D7AA6 .byte 0x1A
MEMORY:021D7AA7 .byte 0
MEMORY:021D7AA8 @ ---------------------------------------------------------------------------
MEMORY:021D7AA8 MOVS R0, #0
MEMORY:021D7AAA BX LR
MEMORY:021D7AAC @ ---------------------------------------------------------------------------
MEMORY:021D7AAC LSRS R0, R0, #2
MEMORY:021D7AAE BX LR
MEMORY:021D7AB0 @ ---------------------------------------------------------------------------
MEMORY:021D7AB0 LSRS R0, R0, #1
MEMORY:021D7AB2 BX LR
MEMORY:021D7AB4 @ ---------------------------------------------------------------------------
MEMORY:021D7AB4 LSLS R0, R0, #1
MEMORY:021D7AB6 BX LR
MEMORY:021D7AB8 @ ---------------------------------------------------------------------------
MEMORY:021D7AB8 LSLS R0, R0, #2
MEMORY:021D7ABA
MEMORY:021D7ABA locret_21D7ABA: @ CODE XREF: TypeEffectiveness+2j
MEMORY:021D7ABA BX LR
Type effectiveness doesn't use a modifier but a simple left (respectively right) shift of one for a simple and two
for a double weakness (respectively resistance), in other words an unrounded division or multiplication by 2 or 4.
The effect of a burn is directly taken into account in the damage formula. First, the game checks if the attack is
physical, then if the user is burned, and finally if its ability is different than Guts. If all conditions are satisfied,
the current damage is divided by 2 with no rounding.
The final modifier is decided by calling the appropriate triggers, which are listed below. Be sure to chain the modifiers in the order they are listed in.
Trigger address |
Modifier |
Trigger description |
6898E29 |
Variable |
If the target's side is affected by Reflect, the move used was physical, the user's ability isn't Infiltrator and the critical hit flag isn't set.
The value of the modificator is 0xA8F if there is more than one Pokémon per side of the field and 0x800 otherwise. |
6898E45 |
Variable |
Same as above with Light Screen and special moves. |
21DC125 |
0x800 |
If the target's ability is Multiscale and the target is at full health. |
21D8B3D |
0x2000 |
If the user's ability is Tinted Lens and the move wasn't very effective. |
21DC15D |
0xC00 |
If one of the target's allies' ability is Friend Guard. |
21D8BA5 |
0x1800 |
If user has ability Sniper and move was a critical hit. |
21D8B71 |
0xC00 |
If the target's ability is Solid Rock or Filter and the move was super effective. |
21DBA95 |
|
Internal. |
21DEC91 |
Variable |
If the user is holding the item Metronome. If n is the number of time the current move was used
successfully and successively, the value of the modifier is 0x1000+n*0x333 if n≤4 and 0x2000 otherwise. |
21DEBD5 |
0x1333 |
If the user is holding an expert belt and the move was super effective. |
21DEC65 |
0x14CC |
If the user is holding a Life Orb. |
21DDB85 |
0x800 |
If the target is holding a damage lowering berry of the attack's type. There is one trigger for each type of berry, the others are at:
21DDC05, 21DDAE5, 21DDB05, 21DDB25, 21DDB45, 21DDB65, 21DDBA5, 21DDBC5, 21DDBE5, 21DDC25, 21DDC45, 21DDC65, 21DDC85, 21DDCA5, 21DDCC5 and 21DDCE5. |
21E3A25 |
0x2000 |
If move is Stomp and target has used Minimize. |
21E316D |
0x2000 |
If move is Earthquake and target is in the charging turn of Dig. |
21E39E1 |
0x2000 |
If move is Surf and target is in the charging turn of Dive. |
21E1455 |
0x2000 |
If move is Steamroller and target has used Minimize. |
There are two separate sets of triggers for the base power of moves. The first is mainly used for moves
with a variable base power, while the second contains the various modifiers for base power.
Trigger address |
Summary of BP formula |
Move and remarks. |
21d88cc |
|
Internal. |
21e2aec |
((255 - Happiness) * 10) ÷ 25 |
Frustration: if result is 0 add 1. |
21e2968 |
50, 100 |
Payback: BP is doubled to 100 if target has moved this turn, 50 otherwise. |
21e2aa0 |
(Happiness * 10) ÷ 25 |
Return: if result is 0 add 1. |
21e7184 |
150, 120, 80, 60, 40 |
Electro Ball: Let S = UserModSpeed ÷ TargetModSpeed. BP = {150: S ≥ 4, 120: 3 ≤ S < 4, 80: 2 ≤ S < 3, 60: 1 ≤ S < 2, 40: otherwise}; |
21e283c |
60, 120 |
Avalanche: BP is doubled to 120 if the target has inflicted non-effect damage to the user this turn. |
21e27d0 |
min(150, 25 * TargetSpd ÷ UserSpd) |
Gyro Ball. |
21e29a8 |
(150 * CurrentHP) ÷ MaxHP |
Eruption, Water Spout: if result is 0 set BP to 1. |
21e2de0 |
min(120, 60 + 20 * statup_total) |
Punishment: statup_total is the sum of the target's stat levels that are ≥ 0, including accuracy and evasion. |
21e2e48 |
20 * 2^(use_counter) |
Fury Cutter: use_counter counts successive and successful previous uses up to a maximum of 3. |
21e2ef4 |
20, 40, 60, 80, 100, 120 |
Low Kick, Grass Knot: let W be the final weight after modifiers. If W ≥ 200, BP is 120, else if W ≥ 100, BP is 100, else if W ≥ 50, BP is 80, else if W ≥ 25, BP is 60, else if W ≥ 10, BP is 40, else BP is 20. |
21e7204 |
40, 80, 120, 160, 200 |
Echoed Voice: BP increases in the listed order every turn this move is used successively on the user's side of the field. |
21e702c |
50, 100 |
Hex: BP is doubled to 100 if target has a status problem. |
21e2a08 |
round(120 * TargetHP%) ÷ 100 |
Wring Out, Crush Grip: TargetHP% is computed by a fixed point division using 0x1000 as the scaling factor. |
21e2eb0 |
50, 100 |
Assurance: BP is doubled to 100 if target has already been inflicted non-effect damage this turn. |
21e7104 |
120, 100, 80, 60, 40 |
Heavy Slam, Heat Crash: let W = UserModWeight ÷ TargetModWeight. BP = {120: W ≥ 5, 100: 4 ≤ W < 5, 80: 3 ≤ W < 4, 60: 2 ≤ W < 3, 40: W < 2}. |
21e70a0 |
20 + 20 * statups |
Stored Power: statups is the sum of all positive stat increases, including accuracy and evasion. |
21e706c |
55, 110 |
Acrobatics: BP is doubled to 110 if user has no held item. |
21e28b8 |
P = (48 * CurrentHP) ÷ MaxHP |
Flail, Reversal: 200 if P ≤ 1, 150 if 2 ≤ P ≤ 4, 100 if 5 ≤ P ≤ 9, 80 if 10 ≤ P ≤ 16, 40 if 17 ≤ P ≤ 32, 20 otherwise. |
21e2d7c |
40, 50, 60, 80, 200 |
Trump Card: listed BP correspond to decreasing PP (if PP is ≥ 5 or this move was called by another move BP is 40). |
21e7dd0 |
60, 120 |
Round: BP is doubled to 120 if used in direct succession of an ally. |
21e2788 |
10, 20, 30 |
Triple Kick: BP is listed for the successive hits. |
21e2b38 |
60, 120 |
Wake-Up Slap: BP is doubled to 120 if target is asleep. |
21e2bd4 |
60, 120 |
SmellingSalt: BP is doubled to 120 is target is paralyzed. |
21e2fd0 |
50, 100 |
Weather Ball: BP is doubled to 100 in any non-default weather. |
21e302c |
40, 80 |
Gust, Twister: BP is doubled to 80 is target is in the charging turn of Bounce, Fly or Sky Drop. |
21e6074 |
CurrentPartyMemberAttack ÷ 10 + 5 |
Beat Up: this move attacks once for every non fainted member in the user's party, including the user. |
21e3318 |
30 + (40 * sum(((IV[i]>>1)&1)<<i)) ÷ 63 |
Hidden Power: IV are indexed from 0 and listed as HP, At, Df, Sp, SA, SD. |
21e17d0 |
100 * stockpile |
Spit Up: stockpile is the stockpile counter ranging from 0 to 3. |
21e1dbc |
40, 80 |
Pursuit: BP is doubled to 80 if target is switching out. |
21e2d40 |
40, 80 or 120 |
Present: let 0 ≤ r < 80 be a random number. If r < 40, BP is 40, else if r < 70, BP is 80, otherwise BP is 120. |
21e33dc |
Variable |
Natural Gift: base power and type depend on held berry. See 2021030 and 20210E4 for corresponding tables. |
21e398c |
10 + 20 * factor |
Magnitude: let R = rand(100), factor = {0: R < 5, 1: 5 ≤ R < 15, 2: 15 ≤ R < 35, 3: 35 ≤ R < 65, 4: 65 ≤ R < 85, 5: 85 ≤ R < 95, 7: R ≥ 95}. |
21e2720 |
30 * 2 ^ (use_counter + defense_curl) |
Rollout: use_counter counts successive and successful previous uses up to a maximum of 5, defense_curl is 1 if user used Defense Curl previously on field, 0 otherwise. |
21e5d44 |
Variable |
Fling: base power depends on the held item. See 21D807C for table of items. |
21e84b8 |
150 |
Grass/Fire/Water Pledge: if a slower ally used a different Pledge move this turn, it will skip its turn and this move's base power will be set to 150. |
Trigger address |
Modifier |
Trigger description |
21d9108 |
0x1800 |
If user has ability Technician and move's base power is ≤60. |
21dc27c |
0x1800 |
If user has ability Flare Boost, is burned and uses a special move. |
21dc6c0 |
0x14CD |
If user has ability Analytic, move isn't Future Sight or Doom Desire and target has already moved this turn. |
21d9174 |
0x1333 |
If user has ability Reckless and move has recoil or is either Jump Kick or Hi Jump Kick. |
21d9138 |
0x1333 |
If the user has ability Iron Fist and move has the "Punching move" (0x7) flag set. |
21dc238 |
0x1800 |
If user has ability Toxic Boost, is poisoned and move is physical. |
21d9090 |
Variable |
If user has ability Rivalry. The value of the modifier is 0x1000 if either the user or target is genderless,
0x1400 if the user and target are of the same gender and 0xC00 otherwise. |
21dc718 |
0x14CD |
If user has ability Sand Force and move is Rock, Ground or Steel type. |
21da864 |
0x800 |
If target has ability Heatproof and move is Fire type. |
21daa90 |
0x1400 |
If target has ability Dry Skin and move is Fire type. |
21dbf48 |
0x14CD |
If the user has ability Sheer Force and move has a flag (0xA) set. |
21d9dc4 |
|
Internal. |
Multiple |
0x1333 |
Type boosting items, plates, incenses. All are wrappers for the 21DF95C trigger. List of locations:
21df7a8, 21df878, 21df760, 21df748, 21df778, 21df7c0, 21df860, 21df890, 21df730, 21df908, 21df950, 21df790,
21df7d8, 21df7f0, 21df808, 21df718, 21df8c0, 21df938, 21df920, 21df8d8, 21df8a8.
|
21de6ec |
0x1199 |
If user holds a Muscle Band and move is physical. |
21df994 |
0x1333 |
If user is Palkia, holds the Lustrous Orb and move is Water or Dragon type. |
21de72c |
0x1199 |
If user holds Wise Glasses and move is special. |
21df458 |
0x1333 |
If user is Giratina, holds the Griseous Orb and move is Dragon or Ghost type. |
21df8f0 |
0x1333 |
If user holds Odd Incense and move is Psychic type. |
21df9e8 |
0x1333 |
If user is Dialga, holds the Adamant Orb and move is Steel or Dragon type. |
21e01e4 |
0x1800 |
If user holds a Normal Gem and move is normal type. Similar triggers for the other types are at:
21DFF14, 21DFF40, 21DFF6C, 21DFF98, 21DFFC4, 21DFFF0, 21E001C, 21E0048, 21E0074, 21E00A0, 21E00CC, 21E00F8, 21E0124, 21E0150, 21E017C, 21E01A8 |
21e2928 |
0x2000 |
If move is Facade and user is either paralyzed, poisoned or burned. |
21e2a58 |
0x2000 |
If move is Brine and target's HP is ≤ 50%. |
21e6fe8 |
0x2000 |
If move is Venoshock and target is poisoned. |
21e729c |
0x2000 |
If move is Retaliate and a Pokémon from the target's party fainted on the previous turn. |
21e8330 |
0x2000 |
If move is either Fusion Bolt or Fusion Flare and the previously used move was respectively Fusion Flare or Fusion Bolt. |
21e6f34 |
0x1800 |
If move was called using Me First. |
21e64a0 |
0x800 |
If move is SolarBeam in non-sunny, non-default weather. |
21e1f38 |
0x2000 |
If user used Charge the previous turn and move is Electric type. |
21e5ff0 |
0x1800 |
If user has been the target of Helping Hand this turn. |
6898158 |
0x548 |
If Water Sport was used by any Pokémon still on the field and move is Fire type. |
6898110 |
0x548 |
If Mud Sport was used by any Pokémon still on the field and move is Electric type. |
MEMORY:021C7394 BaseAttackMods: @ CODE XREF: DamageCalc+9Ep
MEMORY:021C7394 PUSH {R3-R7,LR}
MEMORY:021C7396 MOVS R5, R3
MEMORY:021C7398 MOVS R7, R0
MEMORY:021C739A LDRH R0, [R5]
MEMORY:021C739C MOVS R6, R1
MEMORY:021C739E STR R2, [SP]
MEMORY:021C73A0 BL GetMoveCategory
MEMORY:021C73A4 MOVS R4, #0xA
MEMORY:021C73A6 CMP R0, #2
MEMORY:021C73A8 BEQ loc_21C73AC
MEMORY:021C73AA MOVS R4, #8
MEMORY:021C73AC
MEMORY:021C73AC loc_21C73AC: @ CODE XREF: BaseAttackMods+14j
MEMORY:021C73AC LDR R0, =0x30FE
MEMORY:021C73AE BL AllocateVolatileVariables
MEMORY:021C73B2 MOVS R0, R6
MEMORY:021C73B4 BL GetPkmId
MEMORY:021C73B8 MOVS R1, R0
MEMORY:021C73BA MOVS R0, #3
MEMORY:021C73BC BL StoreVolatileVariableFlag3e4
MEMORY:021C73C0 LDR R0, [SP]
MEMORY:021C73C2 BL GetPkmId
MEMORY:021C73C6 MOVS R1, R0
MEMORY:021C73C8 MOVS R0, #4
MEMORY:021C73CA BL StoreVolatileVariableFlag3e4
MEMORY:021C73CE MOVS R0, #0x3B @ ';'
MEMORY:021C73D0 MOVS R1, #0x1F
MEMORY:021C73D2 BL InitVolatileVariable
MEMORY:021C73D6 MOVS R0, #0x51 @ 'Q'
MEMORY:021C73D8 MOVS R1, #0
MEMORY:021C73DA BL InitVolatileVariable
MEMORY:021C73DE MOVS R0, R7
MEMORY:021C73E0 MOVS R1, #0x39 @ '9'
MEMORY:021C73E2 BL ApplyTriggers
MEMORY:021C73E6 MOVS R0, #0x3B @ ';'
MEMORY:021C73E8 BL ReadVolatileVariable
MEMORY:021C73EC LSLS R0, R0, #0x18
MEMORY:021C73EE LSRS R1, R0, #0x18
MEMORY:021C73F0 CMP R1, #0x1F
MEMORY:021C73F2 BEQ loc_21C73FC
MEMORY:021C73F4 LDR R0, [R7,#8]
MEMORY:021C73F6 BL GetPartyPkm
MEMORY:021C73FA ADDS R6, R0, #0
MEMORY:021C73FC
MEMORY:021C73FC loc_21C73FC: @ CODE XREF: BaseAttackMods+5Ej
MEMORY:021C73FC MOVS R0, #0x51 @ 'Q'
MEMORY:021C73FE BL ReadVolatileVariable
MEMORY:021C7402 CMP R0, #0
MEMORY:021C7404 BEQ loc_21C7410
MEMORY:021C7406 MOVS R0, R6
MEMORY:021C7408 MOVS R1, R4
MEMORY:021C740A BL RawBpkmStat
MEMORY:021C740E B loc_21C7428
MEMORY:021C7410 @ ---------------------------------------------------------------------------
MEMORY:021C7410
MEMORY:021C7410 loc_21C7410: @ CODE XREF: BaseAttackMods+70j
MEMORY:021C7410 LDR R0, [SP,#0x18]
MEMORY:021C7412 CMP R0, #0
MEMORY:021C7414 BEQ loc_21C7420
MEMORY:021C7416 MOVS R0, R6
MEMORY:021C7418 MOVS R1, R4
MEMORY:021C741A BL CritAtkDefLevel
MEMORY:021C741E B loc_21C7428
MEMORY:021C7420 @ ---------------------------------------------------------------------------
MEMORY:021C7420
MEMORY:021C7420 loc_21C7420: @ CODE XREF: BaseAttackMods+80j
MEMORY:021C7420 MOVS R0, R6
MEMORY:021C7422 MOVS R1, R4
MEMORY:021C7424 BL GetBpkmStat
MEMORY:021C7428
MEMORY:021C7428 loc_21C7428: @ CODE XREF: BaseAttackMods+7Aj
MEMORY:021C7428 @ BaseAttackMods+8Aj
MEMORY:021C7428 LSLS R0, R0, #0x10
MEMORY:021C742A LSRS R4, R0, #0x10
MEMORY:021C742C LDRH R1, [R5]
MEMORY:021C742E MOVS R0, #0x12
MEMORY:021C7430 BL StoreVolatileVariableFlag3e4
MEMORY:021C7434 LDRB R1, [R5,#6]
MEMORY:021C7436 MOVS R0, #0x16
MEMORY:021C7438 BL StoreVolatileVariableFlag3e4
MEMORY:021C743C LDR R1, [R5,#8]
MEMORY:021C743E MOVS R0, #0x1A
MEMORY:021C7440 BL StoreVolatileVariableFlag3e4
MEMORY:021C7444 MOVS R0, #0x33 @ '3'
MEMORY:021C7446 MOVS R1, R4
MEMORY:021C7448 BL InitVolatileVariable
MEMORY:021C744C MOVS R1, 0x1000
MEMORY:021C7450 LDR R2, =0x19A
MEMORY:021C7452 MOVS R0, #0x35 @ '5'
MEMORY:021C7454 LSLS R3, R1, #5
MEMORY:021C7456 BL StoreVolatileVariableFlag3e3
MEMORY:021C745A MOVS R0, R7
MEMORY:021C745C MOVS R1, #0x3B @ ';'
MEMORY:021C745E BL ApplyTriggers
MEMORY:021C7462 MOVS R0, #0x33 @ '3'
MEMORY:021C7464 BL ReadVolatileVariable
MEMORY:021C7468 LSLS R0, R0, #0x10
MEMORY:021C746A LSRS R4, R0, #0x10
MEMORY:021C746C MOVS R0, #0x35 @ '5'
MEMORY:021C746E BL ReadVolatileVariable
MEMORY:021C7472 MOVS R1, R0
MEMORY:021C7474 MOVS R0, R4
MEMORY:021C7476 BL ApplyMod
MEMORY:021C747A LSLS R0, R0, #0x10
MEMORY:021C747C LSRS R4, R0, #0x10
MEMORY:021C747E LDR R0, =0x3123
MEMORY:021C7480 BL FreeVolatileVariable
MEMORY:021C7484 MOVS R0, R4
MEMORY:021C7486 POP {R3-R7,PC}
MEMORY:021C7486 @ End of function BaseAttackMods
The first step of computing the attack stat is to decide whether the attack or special attack stat should be used, and
on which Pokémon. By default, the user's attack is used if the move is physical and the special attack otherwise but
this behavior can be altered by the following triggers:
Trigger address |
Trigger description |
21da828 |
Unaware: if target has ability Unaware do not apply any attack level boosts. |
21d8db0 |
Internal. |
21e7320 |
Foul Play: use the target's base attack stat instead of the user's. |
21e39b0 |
Internal. |
Once the base stat is decided, the stat boost level is applied:
- If a trigger decided to skip stat boosts, use the base stat.
- If the hit was critical and the boost level is negative, use the base stat.
- Otherwise, apply the factor corresponding to the boost level according to the table below
(multiply stat by the dividend first then use unrounded division on divisor).
Stat boost level |
Multiplier |
Decimal Approximate |
-6 | 2/8 | 0.25 |
-5 | 2/7 | 0.2857 |
-4 | 2/6 | 0.3333 |
-3 | 2/5 | 0.4 |
-2 | 2/4 | 0.5 |
-1 | 2/3 | 0.6667 |
0 | 2/2 | 1 |
+1 | 3/2 | 1.5 |
+2 | 4/2 | 2 |
+3 | 5/2 | 2.5 |
+4 | 6/2 | 3 |
+5 | 7/2 | 3.5 |
+6 | 8/2 | 4 |
The final attack stat is altered using the following modifiers:
Trigger address |
Modifier |
Trigger description |
21d871c |
0x800 |
If target has ability Thick Fat and move is Ice or Fire type. |
21d8c78 |
0x1800 |
If user has ability Torrent, has MaxHP ÷ 3 or less HP and move is water type. |
21d8d14 |
0x1800 |
If user has ability Guts, has a status problem and move is physical. |
21d8cb0 |
0x1800 |
If user has ability Swarm, has MaxHP ÷ 3 or less HP and move is bug type. |
21d8c94 |
0x1800 |
If user has ability Overgrow, has MaxHP ÷ 3 or less HP and move is grass type. |
21d8d60 |
0x1800 |
If user has ability Plus or Minus and an ally has ability Plus or Minus and move is special. |
21d8c5c |
0x1800 |
If user has ability Blaze, has MaxHP ÷ 3 or less HP and move is fire type. |
21dc0dc |
0x800 |
If user has ability Defeatist and CurrentHP ≤ MaxHP ÷ 2. |
21d8754 |
0x2000 |
If user has ability Pure Power or Huge Power and move is physical. |
21d9954 |
0x1800 |
If user has ability Solar Power and weather is intense sunlight and move is special. |
21d8894 |
0x1800 |
If user has ability Hustle and move is physical. This is a special trigger in the sense that instead of chaining it will directly apply the 0x1800 on the current attack stat instead of being chained with others. |
21daf04 |
0x1800 |
If user has ability Flash Fire activated and move is Fire type. |
21d892c |
0x800 |
If user has ability Slow Start, has been on field for less than 5 turns and move is physical. |
21d8fec |
0x1800 |
If ally is Cherrim and has ability Flower Gift, weather is intense sunlight and move is physical. |
21db424 |
|
Internal. |
21de91c |
0x2000 |
If user is Cubone or Marowak, holds a Thick Club and move is physical. |
21de76c |
0x2000 |
If user is Clamperl, holds a DeepSeaTooth and move is special. |
21df53c |
0x2000 |
If user is Pikachu and holds a Light Ball. |
21de898 |
0x1800 |
If user is Latios or Latias, holds a Soul Dew and move is special. |
21de968 |
0x1800 |
If user is holding Choice Band and move is physical. |
21de9a0 |
0x1800 |
If user is holding Choice Specs and move is special. |
21e310c |
|
Internal. |
MEMORY:021C7494 BaseDefenseMods: @ CODE XREF: DamageCalc+AEp
MEMORY:021C7494 PUSH {R4-R7,LR}
MEMORY:021C7496 SUB SP, SP, #0xC
MEMORY:021C7498 MOVS R6, R3
MEMORY:021C749A STR R0, [SP]
MEMORY:021C749C LDRH R0, [R6]
MEMORY:021C749E STR R1, [SP,#4]
MEMORY:021C74A0 MOVS R5, R2
MEMORY:021C74A2 BL GetMoveCategory
MEMORY:021C74A6 MOVS R4, #0xB
MEMORY:021C74A8 CMP R0, #2
MEMORY:021C74AA BEQ loc_21C74AE
MEMORY:021C74AC MOVS R4, #9
MEMORY:021C74AE
MEMORY:021C74AE loc_21C74AE: @ CODE XREF: BaseDefenseMods+16j
MEMORY:021C74AE LDR R0, [R6,#8]
MEMORY:021C74B0 STR R0, [SP,#8]
MEMORY:021C74B2 LDR R0, =0x3133
MEMORY:021C74B4 BL AllocateVolatileVariables
MEMORY:021C74B8 LDR R0, [SP,#4]
MEMORY:021C74BA BL GetPkmId
MEMORY:021C74BE MOVS R1, R0
MEMORY:021C74C0 MOVS R0, #3
MEMORY:021C74C2 BL StoreVolatileVariableFlag3e4
MEMORY:021C74C6 MOVS R0, R5
MEMORY:021C74C8 BL GetPkmId
MEMORY:021C74CC MOVS R1, R0
MEMORY:021C74CE MOVS R0, #4
MEMORY:021C74D0 BL StoreVolatileVariableFlag3e4
MEMORY:021C74D4 MOVS R0, #0x3C @ '<'
MEMORY:021C74D6 MOVS R1, R4
MEMORY:021C74D8 BL StoreVolatileVariableFlag3e4
MEMORY:021C74DC MOVS R0, #0x3D @ '='
MEMORY:021C74DE MOVS R1, #0
MEMORY:021C74E0 BL InitVolatileVariable
MEMORY:021C74E4 MOVS R0, #0x51 @ 'Q'
MEMORY:021C74E6 MOVS R1, #0
MEMORY:021C74E8 BL StoreVolatileVariableFlag3e1
MEMORY:021C74EC LDR R0, [SP]
MEMORY:021C74EE MOVS R1, #0x3A @ ':'
MEMORY:021C74F0 BL ApplyTriggers
MEMORY:021C74F4 MOVS R0, #0x3D @ '='
MEMORY:021C74F6 BL ReadVolatileVariable
MEMORY:021C74FA MOVS R1, #1
MEMORY:021C74FC TST R0, R1
MEMORY:021C74FE BEQ loc_21C7516
MEMORY:021C7500 CMP R4, #9
MEMORY:021C7502 BNE loc_21C7508
MEMORY:021C7504 MOVS R4, #0xB
MEMORY:021C7506 B loc_21C750A
MEMORY:021C7508 @ ---------------------------------------------------------------------------
MEMORY:021C7508
MEMORY:021C7508 loc_21C7508: @ CODE XREF: BaseDefenseMods+6Ej
MEMORY:021C7508 MOVS R4, #9
MEMORY:021C750A
MEMORY:021C750A loc_21C750A: @ CODE XREF: BaseDefenseMods+72j
MEMORY:021C750A CMP R4, #9
MEMORY:021C750C BNE loc_21C7512
MEMORY:021C750E MOVS R0, #1
MEMORY:021C7510 B loc_21C7514
MEMORY:021C7512 @ ---------------------------------------------------------------------------
MEMORY:021C7512
MEMORY:021C7512 loc_21C7512: @ CODE XREF: BaseDefenseMods+78j
MEMORY:021C7512 MOVS R0, #2
MEMORY:021C7514
MEMORY:021C7514 loc_21C7514: @ CODE XREF: BaseDefenseMods+7Cj
MEMORY:021C7514 STR R0, [SP,#8]
MEMORY:021C7516
MEMORY:021C7516 loc_21C7516: @ CODE XREF: BaseDefenseMods+6Aj
MEMORY:021C7516 MOVS R0, #0x51 @ 'Q'
MEMORY:021C7518 BL ReadVolatileVariable
MEMORY:021C751C LSLS R0, R0, #0x18
MEMORY:021C751E LSRS R7, R0, #0x18
MEMORY:021C7520 LDR R0, =0x3142
MEMORY:021C7522 BL FreeVolatileVariable
MEMORY:021C7526 CMP R7, #0
MEMORY:021C7528 BEQ loc_21C7534
MEMORY:021C752A MOVS R0, R5
MEMORY:021C752C MOVS R1, R4
MEMORY:021C752E BL RawBpkmStat
MEMORY:021C7532 B loc_21C754C
MEMORY:021C7534 @ ---------------------------------------------------------------------------
MEMORY:021C7534
MEMORY:021C7534 loc_21C7534: @ CODE XREF: BaseDefenseMods+94j
MEMORY:021C7534 LDR R0, [SP,#0x20]
MEMORY:021C7536 CMP R0, #0
MEMORY:021C7538 BEQ loc_21C7544
MEMORY:021C753A MOVS R0, R5
MEMORY:021C753C MOVS R1, R4
MEMORY:021C753E BL CritAtkDefLevel
MEMORY:021C7542 B loc_21C754C
MEMORY:021C7544 @ ---------------------------------------------------------------------------
MEMORY:021C7544
MEMORY:021C7544 loc_21C7544: @ CODE XREF: BaseDefenseMods+A4j
MEMORY:021C7544 MOVS R0, R5
MEMORY:021C7546 MOVS R1, R4
MEMORY:021C7548 BL GetBpkmStat
MEMORY:021C754C
MEMORY:021C754C loc_21C754C: @ CODE XREF: BaseDefenseMods+9Ej
MEMORY:021C754C @ BaseDefenseMods+AEj
MEMORY:021C754C LSLS R0, R0, #0x10
MEMORY:021C754E LSRS R7, R0, #0x10
MEMORY:021C7550 LDR R0, [SP]
MEMORY:021C7552 BL GetActiveWeather
MEMORY:021C7556 CMP R0, #4
MEMORY:021C7558 BNE loc_21C7578
MEMORY:021C755A MOVS R0, R5
MEMORY:021C755C MOVS R1, #5
MEMORY:021C755E BL IsMoveOfUserType
MEMORY:021C7562 CMP R0, #0
MEMORY:021C7564 BEQ loc_21C7578
MEMORY:021C7566 CMP R4, #0xB
MEMORY:021C7568 BNE loc_21C7578
MEMORY:021C756A MOVS R1, #6
MEMORY:021C756C MOVS R0, R7
MEMORY:021C756E LSLS R1, R1, #0xA
MEMORY:021C7570 BL ApplyMod
MEMORY:021C7574 LSLS R0, R0, #0x10
MEMORY:021C7576 LSRS R7, R0, #0x10
MEMORY:021C7578
MEMORY:021C7578 loc_21C7578: @ CODE XREF: BaseDefenseMods+C4j
MEMORY:021C7578 @ BaseDefenseMods+D0j ...
MEMORY:021C7578 LDR R4, =0x3157
MEMORY:021C757A MOVS R0, R4
MEMORY:021C757C BL AllocateVolatileVariables
MEMORY:021C7580 LDR R0, [SP,#4]
MEMORY:021C7582 BL GetPkmId
MEMORY:021C7586 MOVS R1, R0
MEMORY:021C7588 MOVS R0, #3
MEMORY:021C758A BL StoreVolatileVariableFlag3e4
MEMORY:021C758E MOVS R0, R5
MEMORY:021C7590 BL GetPkmId
MEMORY:021C7594 MOVS R1, R0
MEMORY:021C7596 MOVS R0, #4
MEMORY:021C7598 MOVS R5, #4
MEMORY:021C759A BL StoreVolatileVariableFlag3e4
MEMORY:021C759E LDRH R1, [R6]
MEMORY:021C75A0 MOVS R0, #0x12
MEMORY:021C75A2 BL StoreVolatileVariableFlag3e4
MEMORY:021C75A6 LDRB R1, [R6,#6]
MEMORY:021C75A8 MOVS R0, #0x16
MEMORY:021C75AA BL StoreVolatileVariableFlag3e4
MEMORY:021C75AE LDR R1, [SP,#8]
MEMORY:021C75B0 MOVS R0, #0x1A
MEMORY:021C75B2 BL StoreVolatileVariableFlag3e4
MEMORY:021C75B6 MOVS R0, #0x34 @ '4'
MEMORY:021C75B8 MOVS R1, R7
MEMORY:021C75BA BL InitVolatileVariable
MEMORY:021C75BE LDR R2, =0x19A
MEMORY:021C75C0 MOVS R0, #0x35 @ '5'
MEMORY:021C75C2 LSLS R1, R5, #0xA
MEMORY:021C75C4 LSLS R3, R5, #0xF
MEMORY:021C75C6 BL StoreVolatileVariableFlag3e3
MEMORY:021C75CA LDR R0, [SP]
MEMORY:021C75CC MOVS R1, #0x3C @ '<'
MEMORY:021C75CE BL ApplyTriggers
MEMORY:021C75D2 MOVS R0, #0x34 @ '4'
MEMORY:021C75D4 BL ReadVolatileVariable
MEMORY:021C75D8 LSLS R0, R0, #0x10
MEMORY:021C75DA LSRS R5, R0, #0x10
MEMORY:021C75DC MOVS R0, #0x35 @ '5'
MEMORY:021C75DE BL ReadVolatileVariable
MEMORY:021C75E2 ADDS R4, #0xB
MEMORY:021C75E4 MOVS R6, R0
MEMORY:021C75E6 MOVS R0, R4
MEMORY:021C75E8 BL FreeVolatileVariable
MEMORY:021C75EC MOVS R0, R5
MEMORY:021C75EE MOVS R1, R6
MEMORY:021C75F0 BL ApplyMod
MEMORY:021C75F4 LSLS R0, R0, #0x10
MEMORY:021C75F6 LSRS R0, R0, #0x10
MEMORY:021C75F8 ADD SP, SP, #0xC
MEMORY:021C75FA POP {R4-R7,PC}
MEMORY:021C75FA @ End of function BaseDefenseMods
Just like for the attack stat, the first step is to decide which defense stat to use and whether to apply the
active boost level. This is done by the following triggers:
Trigger address |
Trigger description |
21da840 |
Unaware: if foe has ability Unaware do not apply any Defense level boosts. |
21d8db0 |
Internal. |
21e7944 |
This triggers is used for special moves that deal physical damage. It replaces the identifier of the base special defense stat with the one for defense. |
21e797c |
Chip Away: ignore defense level boosts if foe has it. |
68981a0 |
Wonder Room: has the same effect as 21e7944 but for all Pokémon on field. Will also cancel the effect of 21e7944. |
This works like attack boosts except the base defense stat is used on critical hits if the boost level is positive.
At this point, if the current weather (after triggers) is Sandstorm, the user is Rock type and the
base stat was special attack, apply a 0x1800 modifier to the current defense stat. This is done regardless
of critical hits and before any other modifier.
The final defense stat is altered using the following modifiers:
Trigger address |
Modifier |
Trigger description |
21d91bc |
0x1800 |
If target has ability Marvel Scale, has a status problem and move is physical. |
21d903c |
0x1800 |
If ally is Cherrim and has ability Flower Gift, weather is intense sunlight and move is special. |
21db8f0 |
|
Internal. |
21de7bc |
0x1800 |
Is target is Clamperl, holds a DeepSeaScale and move is special. |
21de804 |
0x2000 |
Is target is (untransformed) Ditto, holds Metal Powder and move is physical. |
21dfaa8 |
0x1800 |
If target is holding Eviolite and is not fully evolved. |
21de8d4 |
0x1800 |
If target is Latios or Latias holding a Soul Dew and move is special. |
The following moves do not depend on the user's attack or the target's defense and are handled by specific triggers:
Trigger address |
Trigger description |
21e1608 |
Psywave: damage is always max(1, ((rand(101) + 50) * UserLevel) ÷ 100) |
21e15d0 |
Night Shade: damage is always UserLevel. |
21e1504 |
SonicBoom: damage is always 20. |
21e1498 |
Super Fang: damage is always max(1, TargetHP ÷ 2). |
21e14e0 |
Dragon Rage: damage is always 40. |
21e1578 |
Endeavor: damage is always max(0, TargetHP-UserHP). |
21e7c98 |
Final Gambit: damage is always UserHP. |
21e0838 |
Brick Break: cancels the effect of Reflect / Light Screen. |
21e1978 |
Counter: if last Pokémon to hit the user was a foe using a physical move, use double the set damage. |
21e19bc |
Mirror Coat: same as Counter for special moves. |
21e1a00 |
Metal Burst: if the user was hit by an attack earlier this turn, use 1.5 times the set damage. |
21e3e50 |
Bide: store energy for 2 turns, then set damage to twice the total damage dealt to user during the charging turns. |
|