Decomp CalcDamage; damage_calc_diag's move_category is 4 bytes, its modifiers unsigned

CalcDamage (0x0230BBAC, 1290 instructions) is the damage formula: stat
stages, item/ability/IQ-skill modifiers, the fixed-point base formula,
CalcTypeBasedDamageEffects, critical hits, Reflect/Light Screen and the
final multipliers, with its diagnostics in DUNGEON_PTR->last_damage_calc.
It is the first of 26 functions in asm/overlay_29_0230BBAC.s and a rodata
object precedes that object in main.lsf, so extract_function.py splits
rather than merges: the function lands in src/overlay_29_0230BBAC.c with
include/overlay_29_0230BBAC.h, the other 25 move to
asm/overlay_29_0230D088.{s,inc}, and main.lsf lists both objects where it
listed one.

struct damage_calc_diag modelled move_category as a 1-byte enum plus
field_0x5/0x6/0x7 padding (3fc6d8bd). Retail writes that field with a
4-byte str (0x0230BDC8) and reads the eight modifier bytes at 0x30..0x37
unsigned (ldrb at 24 sites), so move_category becomes s32 - the struct
stays 0x54 bytes - and the modifiers become u8 (they were s8). No other
source in the tree reads these members. Both deviate from pmdsky-debug's
declarations; the reasoning note linked from the PR has the evidence.

Region handling follows the neighbouring files: six
DefenderAbilityIsActive__0230A940 calls take three arguments under JAPAN,
and message ids C53/C54/C55/C57/C58 and DC1 are file-scope defines at
US - 0x2C1 under JAPAN. One difference is real source: the defense-side
apparent_id 0x211/0x218 checks compare the attacker's apparent_id under
JAPAN (the JP-only ldrsh r1, [r6, #4]). EU is identical to US.

The 17 callees that are still asm are declared extern in the .c with
prototypes read off their own asm, as the sibling files do. The spelling
of the ability-multiply block (an s32 calc[2] local, two temps and three
volatile s32 * pointers) is match-derived, each element removing one
measured compiler obstacle; the reasoning note explains it.

Authored by Claude (Fable 5.1) under human direction. Confirmed by
matching builds of all three regions: build/pmdsky.us/pmdsky.us.nds: OK,
build/pmdsky.eu/pmdsky.eu.nds: OK, build/pmdsky.jp/pmdsky.jp.nds: OK,
each also passing main.sha1, filesystem.sha1 and arm7.sha1.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
cecilarmitais
2026-09-05 23:53:28 -07:00
parent 38aa265d9d
commit 7653350896
8 changed files with 1639 additions and 2399 deletions

View File

@@ -1,100 +0,0 @@
#pragma once
.public _s32_div_f
.public AbilityIsActiveVeneer
.public AddFixedPoint64
.public AdvanceFrame
.public AIR_BLADE_DAMAGE_MULTIPLIER
.public ApplyDamageAndEffects
.public AURA_BOW_STAT_BOOST
.public AuraBowIsActive
.public CalcTypeBasedDamageEffects
.public CeilFixedPoint
.public ClampedLn
.public CreateTemporaryEntity
.public DAMAGE_FORMULA_AT_PREFACTOR
.public DAMAGE_FORMULA_CONSTANT_SHIFT
.public DAMAGE_FORMULA_DEF_PREFACTOR
.public DAMAGE_FORMULA_FLV_DEFICIT_DIVISOR
.public DAMAGE_FORMULA_FLV_SHIFT
.public DAMAGE_FORMULA_LN_ARG_PREFACTOR
.public DAMAGE_FORMULA_LN_PREFACTOR
.public DAMAGE_FORMULA_MAX_BASE
.public DAMAGE_FORMULA_MIN_BASE
.public DAMAGE_FORMULA_NON_TEAM_MEMBER_MODIFIER
.public DAMAGE_MULTIPLIER_0_5
.public DAMAGE_MULTIPLIER_1_5
.public DAMAGE_MULTIPLIER_2
.public Debug_Print0
.public DEF_SCARF_STAT_BOOST
.public DefenderAbilityIsActive__0230A940
.public DEFENSIVE_STAT_STAGE_MULTIPLIERS
.public DivideFixedPoint64
.public DUNGEON_PTR
.public DungeonRandInt
.public EntityIsValid__02308FBC
.public ExclusiveItemDefenseBoost
.public ExclusiveItemEffectIsActive__0230A9B8
.public ExclusiveItemEffectIsActiveWithLogging
.public ExclusiveItemOffenseBoost
.public FixedPoint32To64
.public FixedPoint64CmpLt
.public FixedPoint64ToInt
.public FixedRoomIsSubstituteRoom
.public FlashFireShouldActivate
.public GendersEqualNotGenderless
.public GendersNotEqualNotGenderless
.public GenerateStandardItem
.public GetApparentWeather
.public GetEquivItemIndex
.public GetItemAtIdx
.public GetMonsterGenderVeneer
.public GetMoveCategory
.public GetTypeMatchup
.public IntToFixedPoint64
.public IqSkillIsEnabled
.public IsMonster__0230A994
.public IsPunchMove
.public IsRecoilMove
.public IsRegularAttackOrProjectile
.public ItemIsActive__0230A9DC
.public LogMessageByIdWithPopupCheckUserTarget
.public ME_FIRST_MULTIPLIER
.public MemZero
.public MonsterHasNegativeStatus
.public MonsterIsType
.public MoveIsNotPhysical
.public MultiplyByFixedPoint
.public MultiplyFixedPoint64
.public MUNCH_BELT_STAT_BOOST
.public NearbyAllyIqSkillIsEnabled
.public OFFENSIVE_STAT_STAGE_MULTIPLIERS
.public OtherMonsterAbilityIsActive
.public ov10_022BF964
.public ov10_022C45B4
.public ov29_02352838
.public ov29_02352894
.public ov29_02352984
.public ov29_02352990
.public ov29_0235299C
.public ov29_023535D4
.public PlayEffectAnimation0x171
.public PlayEffectAnimation0x171Full
.public PlayEffectAnimation0x18E
.public PlayEffectAnimation0x1A9__022E6130
.public PlayEffectAnimation0x1A9__022E617C
.public PlayEffectAnimationEntity
.public PointCameraToMonster
.public POWER_BAND_STAT_BOOST
.public POWER_PITCHER_DAMAGE_MULTIPLIER
.public ResetDamageData
.public RoundUpDiv256
.public SCOPE_LENS_CRIT_RATE_BOOST
.public SetItemAcquired
.public SPECIAL_BAND_STAT_BOOST
.public SubstitutePlaceholderStringTags
.public SUPER_LUCK_CRIT_RATE_BOOST
.public TerminateEffectWrapper
.public TYPE_ADVANTAGE_MASTER_CRIT_RATE
.public TYPE_MATCHUP_COMBINATOR_TABLE
.public UpdateStateFlags
.public ZINC_BAND_STAT_BOOST

View File

@@ -0,0 +1,37 @@
#pragma once
.public AbilityIsActiveVeneer
.public AdvanceFrame
.public ApplyDamageAndEffects
.public CalcTypeBasedDamageEffects
.public CreateTemporaryEntity
.public DUNGEON_PTR
.public DefenderAbilityIsActive__0230A940
.public DungeonRandInt
.public EntityIsValid__02308FBC
.public FixedPoint64ToInt
.public GendersNotEqualNotGenderless
.public GenerateStandardItem
.public GetEquivItemIndex
.public GetItemAtIdx
.public GetTypeMatchup
.public IntToFixedPoint64
.public IqSkillIsEnabled
.public IsMonster__0230A994
.public LogMessageByIdWithPopupCheckUserTarget
.public MemZero
.public MonsterIsType
.public MultiplyByFixedPoint
.public MultiplyFixedPoint64
.public POWER_PITCHER_DAMAGE_MULTIPLIER
.public PlayEffectAnimationEntity
.public PointCameraToMonster
.public ResetDamageData
.public RoundUpDiv256
.public SetItemAcquired
.public SubstitutePlaceholderStringTags
.public TYPE_MATCHUP_COMBINATOR_TABLE
.public TerminateEffectWrapper
.public ov10_022BF964
.public ov10_022C45B4
.public ov29_02352894
.public ov29_023535D4

File diff suppressed because it is too large Load Diff

845
asm/overlay_29_0230D088.s Normal file
View File

@@ -0,0 +1,845 @@
.include "asm/macros.inc"
.include "overlay_29_0230D088.inc"
.text
arm_func_start ov29_0230D088
ov29_0230D088: ; 0x0230D088
stmdb sp!, {r4, r5, lr}
sub sp, sp, #0x1c
ldr r5, [sp, #0x2c]
ldr r4, [sp, #0x28]
mov lr, r0
strb r2, [r5, #0xc]
cmp r4, #1
strb r3, [r5, #0xd]
mov ip, r1
str r2, [sp]
mov r2, ip
ldr r0, _0230D118 ; =0x000003E7
movlt r4, #1
cmp r4, r0
movgt r4, r0
add r0, sp, #0x14
mov r1, lr
mov r3, r4
str r5, [sp, #4]
mov ip, #0
str ip, [sp, #8]
bl CalcTypeBasedDamageEffects
add r0, sp, #0xc
mov r1, r4
bl IntToFixedPoint64
add r0, sp, #0xc
add r2, sp, #0x14
mov r1, r0
bl MultiplyFixedPoint64
add r0, sp, #0xc
bl FixedPoint64ToInt
str r0, [r5]
mov r0, #0
str r0, [r5, #4]
add sp, sp, #0x1c
ldmia sp!, {r4, r5, pc}
.align 2, 0
_0230D118: .word 0x000003E7
arm_func_end ov29_0230D088
arm_func_start ApplyDamageAndEffectsWrapper
ApplyDamageAndEffectsWrapper: ; 0x0230D11C
stmdb sp!, {r4, r5, r6, r7, lr}
sub sp, sp, #0xdc
mov r7, r0
add r0, sp, #0x10
mov r6, r1
mov r5, r2
mov r4, r3
bl ResetDamageData
add r0, sp, #0x24
bl CreateTemporaryEntity
mov r3, #0
mov r0, #2
str r0, [sp, #0x18]
str r6, [sp, #0x10]
str r5, [sp, #0x14]
strb r3, [sp, #0x1c]
strb r3, [sp, #0x1e]
strb r3, [sp, #0x1f]
strb r3, [sp, #0x20]
stmia sp, {r3, r4}
str r3, [sp, #8]
mov r1, r7
add r0, sp, #0x24
add r2, sp, #0x10
str r3, [sp, #0xc]
bl ApplyDamageAndEffects
add sp, sp, #0xdc
ldmia sp!, {r4, r5, r6, r7, pc}
arm_func_end ApplyDamageAndEffectsWrapper
arm_func_start CalcRecoilDamageFixed
CalcRecoilDamageFixed: ; 0x0230D18C
stmdb sp!, {r4, r5, r6, r7, lr}
sub sp, sp, #0x1c
mov r7, r0
mov r6, r1
mov r5, r2
mov r4, r3
bl EntityIsValid__02308FBC
cmp r0, #0
beq _0230D238
ldr r0, [r7]
cmp r0, #1
bne _0230D1F0
ldr r0, [r7, #0xb4]
ldrsh r0, [r0, #0x10]
cmp r0, #0
beq _0230D238
mov r0, r7
mov r1, #0x5c
bl AbilityIsActiveVeneer
cmp r0, #0
beq _0230D1F0
mov r0, r6, lsl #8
mov r1, #0x180
bl MultiplyByFixedPoint
mov r6, r0, asr #8
_0230D1F0:
ldrb r1, [sp, #0x34]
str r4, [sp]
ldrsh r0, [sp, #0x38]
str r1, [sp, #4]
mov r1, #3
str r1, [sp, #8]
ldr r1, [sp, #0x3c]
str r0, [sp, #0xc]
ldr r0, [sp, #0x40]
str r1, [sp, #0x10]
ldr r4, [sp, #0x44]
str r0, [sp, #0x14]
mov r0, r7
mov r1, r7
mov r2, r6
mov r3, r5
str r4, [sp, #0x18]
bl CalcDamageFixed
_0230D238:
add sp, sp, #0x1c
ldmia sp!, {r4, r5, r6, r7, pc}
arm_func_end CalcRecoilDamageFixed
arm_func_start CalcDamageFixed
CalcDamageFixed: ; 0x0230D240
stmdb sp!, {r3, r4, r5, r6, r7, r8, sb, sl, lr}
sub sp, sp, #0x2c
mov sl, r0
add r0, sp, #0x18
mov sb, r1
mov r8, r2
mov r7, r3
ldr r6, [sp, #0x54]
bl ResetDamageData
mov r5, #0
ldrb r0, [sp, #0x58]
ldr r1, [sp, #0x60]
mov r2, #2
str r2, [sp, #0x20]
str r1, [sp, #0x1c]
strb r6, [sp, #0x24]
strb r5, [sp, #0x26]
strb r5, [sp, #0x27]
strb r0, [sp, #0x25]
cmp r6, #0
beq _0230D2F8
add r4, sp, #0x10
_0230D298:
mov r2, r5, lsl #0x10
mov r0, sl
mov r1, sb
mov r3, r6
mov r2, r2, asr #0x10
bl GetTypeMatchup
str r0, [r4, r5, lsl #2]
add r5, r5, #1
cmp r5, #2
blt _0230D298
mov r0, sl
mov r1, sb
mov r2, #0x35
#ifndef JAPAN
mov r3, #1
#endif
bl DefenderAbilityIsActive__0230A940
cmp r0, #0
beq _0230D2F8
ldr r2, [sp, #0x10]
ldr r0, _0230D39C ; =TYPE_MATCHUP_COMBINATOR_TABLE
ldr r1, [sp, #0x14]
add r0, r0, r2, lsl #4
ldr r0, [r0, r1, lsl #2]
cmp r0, #3
movne r8, #0
_0230D2F8:
ldrsh r1, [sp, #0x5c]
ldr r0, _0230D3A0 ; =0x00000256
mov r8, r8, lsl #8
cmp r1, r0
bne _0230D334
mov r0, sl
mov r1, #0x2f
bl IqSkillIsEnabled
cmp r0, #0
beq _0230D334
ldr r1, _0230D3A4 ; =POWER_PITCHER_DAMAGE_MULTIPLIER
mov r0, r8
ldr r1, [r1]
bl MultiplyByFixedPoint
mov r8, r0
_0230D334:
mov r0, r8
bl RoundUpDiv256
str r0, [sp, #0x18]
cmp r8, #0
moveq r0, #1
streqb r0, [sp, #0x28]
movne r0, #0
strneb r0, [sp, #0x28]
ldrsh r1, [sp, #0x5c]
str r7, [sp]
ldr r0, [sp, #0x64]
str r1, [sp, #4]
str r0, [sp, #8]
ldr r4, [sp, #0x68]
add r2, sp, #0x18
mov r0, sl
mov r1, sb
mov r3, #0
str r4, [sp, #0xc]
bl ApplyDamageAndEffects
ldr r1, [sp, #0x50]
cmp r1, #0
ldrneb r0, [sp, #0x28]
strneb r0, [r1]
add sp, sp, #0x2c
ldmia sp!, {r3, r4, r5, r6, r7, r8, sb, sl, pc}
.align 2, 0
_0230D39C: .word TYPE_MATCHUP_COMBINATOR_TABLE
_0230D3A0: .word 0x00000256
_0230D3A4: .word POWER_PITCHER_DAMAGE_MULTIPLIER
arm_func_end CalcDamageFixed
arm_func_start CalcDamageFixedNoCategory
CalcDamageFixedNoCategory: ; 0x0230D3A8
stmdb sp!, {lr}
sub sp, sp, #0x1c
ldr lr, [sp, #0x20]
ldrb ip, [sp, #0x24]
str lr, [sp]
ldrsh lr, [sp, #0x28]
str ip, [sp, #4]
mov ip, #3
str ip, [sp, #8]
ldr ip, [sp, #0x2c]
str lr, [sp, #0xc]
ldr lr, [sp, #0x30]
str ip, [sp, #0x10]
ldr ip, [sp, #0x34]
str lr, [sp, #0x14]
str ip, [sp, #0x18]
bl CalcDamageFixed
add sp, sp, #0x1c
ldmia sp!, {pc}
arm_func_end CalcDamageFixedNoCategory
arm_func_start CalcDamageFixedWrapper
CalcDamageFixedWrapper: ; 0x0230D3F4
stmdb sp!, {lr}
sub sp, sp, #0x1c
ldr ip, [sp, #0x20]
ldrb lr, [sp, #0x24]
str ip, [sp]
ldrb ip, [sp, #0x28]
str lr, [sp, #4]
ldrsh lr, [sp, #0x2c]
str ip, [sp, #8]
ldr ip, [sp, #0x30]
str lr, [sp, #0xc]
ldr lr, [sp, #0x34]
str ip, [sp, #0x10]
ldr ip, [sp, #0x38]
str lr, [sp, #0x14]
str ip, [sp, #0x18]
bl CalcDamageFixed
add sp, sp, #0x1c
ldmia sp!, {pc}
arm_func_end CalcDamageFixedWrapper
arm_func_start UpdateShopkeeperModeAfterAttack
UpdateShopkeeperModeAfterAttack: ; 0x0230D440
ldr r2, [r1, #0xb4]
ldrb r1, [r2, #9]
cmp r1, #0
bxeq lr
ldr r1, [r0]
cmp r1, #1
bxne lr
ldr r0, [r0, #0xb4]
ldrb r0, [r0, #6]
cmp r0, #0
movne r0, #2
strneb r0, [r2, #9]
moveq r0, #3
streqb r0, [r2, #9]
bx lr
arm_func_end UpdateShopkeeperModeAfterAttack
arm_func_start UpdateShopkeeperModeAfterTrap
UpdateShopkeeperModeAfterTrap: ; 0x0230D47C
ldr r2, [r0, #0xb4]
ldrb r0, [r2, #9]
cmp r0, #0
bxeq lr
cmp r1, #0
movne r0, #2
strneb r0, [r2, #9]
moveq r0, #3
streqb r0, [r2, #9]
bx lr
arm_func_end UpdateShopkeeperModeAfterTrap
arm_func_start ov29_0230D4A4
ov29_0230D4A4: ; 0x0230D4A4
stmdb sp!, {r3, r4, r5, r6, r7, lr}
mov r6, r1
mov r7, r0
mov r0, r6
mov r1, #0xe
mov r5, r2
ldr r4, [r6, #0xb4]
bl MonsterIsType
cmp r0, #0
beq _0230D4E8
cmp r5, #1
cmpne r5, #7
bne _0230D4E8
ldrb r0, [r4, #0xfe]
cmp r0, #0
moveq r0, #0
ldmeqia sp!, {r3, r4, r5, r6, r7, pc}
_0230D4E8:
mov r4, #0
b _0230D518
_0230D4F0:
mov r2, r4, lsl #0x10
mov r0, r7
mov r1, r6
mov r3, r5
mov r2, r2, asr #0x10
bl GetTypeMatchup
cmp r0, #0
moveq r0, #0
ldmeqia sp!, {r3, r4, r5, r6, r7, pc}
add r4, r4, #1
_0230D518:
cmp r4, #2
blt _0230D4F0
mov r0, #1
ldmia sp!, {r3, r4, r5, r6, r7, pc}
arm_func_end ov29_0230D4A4
arm_func_start ResetDamageCalcDiagnostics
ResetDamageCalcDiagnostics: ; 0x0230D528
stmdb sp!, {r3, r4, r5, lr}
ldr r0, _0230D614 ; =DUNGEON_PTR
mov r1, #0x54
ldr r4, [r0]
add r5, r4, #0x184
mov r0, r5
bl MemZero
mov r1, #0
strb r1, [r4, #0x184]
str r1, [r5, #4]
strb r1, [r5, #8]
strb r1, [r5, #9]
mov r0, #0xa
strb r0, [r5, #0xa]
strb r0, [r5, #0xb]
mov r0, #1
strh r0, [r5, #0xc]
strh r0, [r5, #0xe]
strh r1, [r5, #0x10]
strh r1, [r5, #0x14]
strh r1, [r5, #0x12]
strh r1, [r5, #0x16]
strh r1, [r5, #0x1c]
str r1, [r5, #0x20]
str r1, [r5, #0x28]
str r1, [r5, #0x2c]
strb r1, [r5, #0x30]
strb r1, [r5, #0x31]
strb r1, [r5, #0x36]
strb r1, [r5, #0x37]
strb r1, [r5, #0x34]
strb r1, [r5, #0x35]
strb r1, [r5, #0x38]
strb r1, [r5, #0x39]
strb r1, [r5, #0x3a]
strb r1, [r5, #0x3b]
strb r1, [r5, #0x3c]
strb r1, [r5, #0x3d]
strb r1, [r5, #0x3e]
strb r1, [r5, #0x40]
strb r1, [r5, #0x3f]
strb r1, [r5, #0x41]
strb r1, [r5, #0x42]
strb r1, [r5, #0x43]
strb r1, [r5, #0x44]
strb r1, [r5, #0x45]
strb r1, [r5, #0x46]
strb r1, [r5, #0x47]
strb r1, [r5, #0x48]
strb r1, [r5, #0x4b]
strb r1, [r5, #0x4c]
strb r1, [r5, #0x4d]
strb r1, [r5, #0x4e]
strb r1, [r5, #0x4f]
strb r1, [r5, #0x50]
strb r1, [r5, #0x51]
strb r1, [r5, #0x32]
strb r1, [r5, #0x33]
ldmia sp!, {r3, r4, r5, pc}
.align 2, 0
_0230D614: .word DUNGEON_PTR
arm_func_end ResetDamageCalcDiagnostics
arm_func_start ov29_0230D618
ov29_0230D618: ; 0x0230D618
ldr r1, _0230D624 ; =ov29_02352894
ldr r0, [r1, r0, lsl #2]
bx lr
.align 2, 0
_0230D624: .word ov29_02352894
arm_func_end ov29_0230D618
arm_func_start ov29_0230D628
ov29_0230D628: ; 0x0230D628
stmdb sp!, {r3, lr}
ldr r1, _0230D650 ; =DUNGEON_PTR
ldr r1, [r1]
add r1, r1, #0x1a000
#ifdef JAPAN
ldr r1, [r1, #0x188]
#else
ldr r1, [r1, #0x22c]
#endif
cmp r1, r0
ldmneia sp!, {r3, pc}
mov r1, #1
bl PointCameraToMonster
ldmia sp!, {r3, pc}
.align 2, 0
_0230D650: .word DUNGEON_PTR
arm_func_end ov29_0230D628
arm_func_start IsEitherMonsterInvalid
IsEitherMonsterInvalid: ; 0x0230D654
stmdb sp!, {r4, lr}
mov r4, r1
bl EntityIsValid__02308FBC
cmp r0, #0
beq _0230D678
mov r0, r4
bl EntityIsValid__02308FBC
cmp r0, #0
bne _0230D680
_0230D678:
mov r0, #1
ldmia sp!, {r4, pc}
_0230D680:
mov r0, #0
ldmia sp!, {r4, pc}
arm_func_end IsEitherMonsterInvalid
arm_func_start ov29_0230D688
ov29_0230D688: ; 0x0230D688
stmdb sp!, {r4, lr}
sub sp, sp, #8
mov r4, r0
ldrh r3, [r4]
mov r1, #0x55
mov r2, #2
strh r3, [sp]
ldrh r3, [r4, #2]
strh r3, [sp, #2]
ldrh r3, [r4, #4]
strh r3, [sp, #4]
bl GenerateStandardItem
mov r0, r4
bl SetItemAcquired
ldrb r0, [sp, #1]
strb r0, [r4, #1]
cmp r0, #0
beq _0230D6FC
add r0, sp, #0
bl GetEquivItemIndex
cmp r0, #0
blt _0230D6FC
bl GetItemAtIdx
ldrh r1, [r4]
strh r1, [r0]
ldrh r1, [r4, #2]
strh r1, [r0, #2]
ldrh r1, [r4, #4]
strh r1, [r0, #4]
_0230D6FC:
add sp, sp, #8
ldmia sp!, {r4, pc}
arm_func_end ov29_0230D688
arm_func_start ov29_0230D704
ov29_0230D704: ; 0x0230D704
mov r0, #0
bx lr
arm_func_end ov29_0230D704
arm_func_start ov29_0230D70C
ov29_0230D70C: ; 0x0230D70C
stmdb sp!, {r3, lr}
mov r0, #0x64
bl DungeonRandInt
ldr r1, _0230D734 ; =ov10_022C45B4
ldrsh r1, [r1]
cmp r0, r1
movlt r0, #1
movge r0, #0
and r0, r0, #0xff
ldmia sp!, {r3, pc}
.align 2, 0
_0230D734: .word ov10_022C45B4
arm_func_end ov29_0230D70C
arm_func_start ov29_0230D738
ov29_0230D738: ; 0x0230D738
stmdb sp!, {r3, lr}
cmp r2, #0
bne _0230D760
mov r0, #0x64
bl DungeonRandInt
ldr r1, _0230D768 ; =ov10_022C45B4
ldrsh r1, [r1]
cmp r0, r1
movlt r0, #1
ldmltia sp!, {r3, pc}
_0230D760:
mov r0, #0
ldmia sp!, {r3, pc}
.align 2, 0
_0230D768: .word ov10_022C45B4
arm_func_end ov29_0230D738
arm_func_start ov29_0230D76C
ov29_0230D76C: ; 0x0230D76C
stmdb sp!, {r4, r5, r6, lr}
mov r6, r0
mov r5, r1
mov r4, r2
bl IsMonster__0230A994
cmp r0, #0
beq _0230D798
mov r0, r5
bl IsMonster__0230A994
cmp r0, #0
bne _0230D7A0
_0230D798:
mov r0, #0
ldmia sp!, {r4, r5, r6, pc}
_0230D7A0:
ldr r0, [r6, #0xb4]
ldr r1, [r5, #0xb4]
ldrsh r0, [r0, #2]
ldrsh r1, [r1, #2]
bl GendersNotEqualNotGenderless
cmp r0, #0
moveq r0, #0
ldmeqia sp!, {r4, r5, r6, pc}
mov r0, r6
mov r1, r5
mov r2, r4
bl ov29_0230D738
ldmia sp!, {r4, r5, r6, pc}
arm_func_end ov29_0230D76C
arm_func_start ov29_0230D7D4
ov29_0230D7D4: ; 0x0230D7D4
stmdb sp!, {r3, r4, r5, lr}
sub sp, sp, #0x10
ldr r2, _0230D870 ; =ov29_023535D4
mvn r1, #0
ldrsh r3, [r2]
mov r4, r0
cmp r3, r1
beq _0230D808
ldrsh r0, [r2]
bl TerminateEffectWrapper
ldr r0, _0230D870 ; =ov29_023535D4
mvn r1, #0
strh r1, [r0]
_0230D808:
mov r2, #0
mov r1, #1
str r2, [sp]
stmib sp, {r1, r2}
mov r0, r4
rsb r1, r1, #0x2b8
mov r3, #3
str r2, [sp, #0xc]
bl PlayEffectAnimationEntity
mov r0, r0, lsl #0x10
mov r5, r0, asr #0x10
mvn r0, #0
cmp r5, r0
beq _0230D868
mov r4, #0x18
b _0230D850
_0230D848:
mov r0, r4
bl AdvanceFrame
_0230D850:
mov r0, r5
bl ov10_022BF964
cmp r0, #0
bne _0230D848
mov r0, r5
bl TerminateEffectWrapper
_0230D868:
add sp, sp, #0x10
ldmia sp!, {r3, r4, r5, pc}
.align 2, 0
_0230D870: .word ov29_023535D4
arm_func_end ov29_0230D7D4
arm_func_start SwapDefensiveStages
SwapDefensiveStages: ; 0x0230D874
stmdb sp!, {r3, r4, r5, lr}
mov r5, r0
mov r4, r1
ldr lr, [r5, #0xb4]
ldr ip, [r4, #0xb4]
ldrsh r3, [lr, #0x28]
ldrsh r1, [lr, #0x2a]
ldrsh r0, [ip, #0x28]
cmp r2, #0
strh r0, [lr, #0x28]
ldrsh r0, [ip, #0x2a]
strh r0, [lr, #0x2a]
strh r3, [ip, #0x28]
strh r1, [ip, #0x2a]
ldmeqia sp!, {r3, r4, r5, pc}
mov r0, #0
mov r1, r5
mov r2, r0
bl SubstitutePlaceholderStringTags
mov r1, r4
mov r0, #1
mov r2, #0
bl SubstitutePlaceholderStringTags
ldr r2, _0230D8E4 ; =0x00000F2D
mov r0, r5
mov r1, r4
bl LogMessageByIdWithPopupCheckUserTarget
ldmia sp!, {r3, r4, r5, pc}
.align 2, 0
#ifdef JAPAN
_0230D8E4: .word 0x00002494
#else
_0230D8E4: .word 0x00000F2D
#endif
arm_func_end SwapDefensiveStages
arm_func_start SwapDefensiveMultipliers
SwapDefensiveMultipliers: ; 0x0230D8E8
stmdb sp!, {r3, r4, r5, lr}
mov r5, r0
mov r4, r1
ldr lr, [r5, #0xb4]
ldr ip, [r4, #0xb4]
ldr r3, [lr, #0x3c]
ldr r1, [lr, #0x40]
ldr r0, [ip, #0x3c]
cmp r2, #0
str r0, [lr, #0x3c]
ldr r0, [ip, #0x40]
str r0, [lr, #0x40]
str r3, [ip, #0x3c]
str r1, [ip, #0x40]
ldmeqia sp!, {r3, r4, r5, pc}
mov r0, #0
mov r1, r5
mov r2, r0
bl SubstitutePlaceholderStringTags
mov r1, r4
mov r0, #1
mov r2, #0
bl SubstitutePlaceholderStringTags
ldr r2, _0230D958 ; =0x00000F2E
mov r0, r5
mov r1, r4
bl LogMessageByIdWithPopupCheckUserTarget
ldmia sp!, {r3, r4, r5, pc}
.align 2, 0
#ifdef JAPAN
_0230D958: .word 0x00002495
#else
_0230D958: .word 0x00000F2E
#endif
arm_func_end SwapDefensiveMultipliers
arm_func_start SwapOffensiveStages
SwapOffensiveStages: ; 0x0230D95C
stmdb sp!, {r3, r4, r5, lr}
mov r5, r0
mov r4, r1
ldr lr, [r5, #0xb4]
ldr ip, [r4, #0xb4]
ldrsh r3, [lr, #0x24]
ldrsh r1, [lr, #0x26]
ldrsh r0, [ip, #0x24]
cmp r2, #0
strh r0, [lr, #0x24]
ldrsh r0, [ip, #0x26]
strh r0, [lr, #0x26]
strh r3, [ip, #0x24]
strh r1, [ip, #0x26]
ldmeqia sp!, {r3, r4, r5, pc}
mov r0, #0
mov r1, r5
mov r2, r0
bl SubstitutePlaceholderStringTags
mov r1, r4
mov r0, #1
mov r2, #0
bl SubstitutePlaceholderStringTags
ldr r2, _0230D9CC ; =0x00000F2B
mov r0, r5
mov r1, r4
bl LogMessageByIdWithPopupCheckUserTarget
ldmia sp!, {r3, r4, r5, pc}
.align 2, 0
#ifdef JAPAN
_0230D9CC: .word 0x00002492
#else
_0230D9CC: .word 0x00000F2B
#endif
arm_func_end SwapOffensiveStages
arm_func_start SwapOffensiveMultipliers
SwapOffensiveMultipliers: ; 0x0230D9D0
stmdb sp!, {r3, r4, r5, lr}
mov r5, r0
mov r4, r1
ldr lr, [r5, #0xb4]
ldr ip, [r4, #0xb4]
ldr r3, [lr, #0x34]
ldr r1, [lr, #0x38]
ldr r0, [ip, #0x34]
cmp r2, #0
str r0, [lr, #0x34]
ldr r0, [ip, #0x38]
str r0, [lr, #0x38]
str r3, [ip, #0x34]
str r1, [ip, #0x38]
ldmeqia sp!, {r3, r4, r5, pc}
mov r0, #0
mov r1, r5
mov r2, r0
bl SubstitutePlaceholderStringTags
mov r1, r4
mov r0, #1
mov r2, #0
bl SubstitutePlaceholderStringTags
ldr r2, _0230DA40 ; =0x00000F2C
mov r0, r5
mov r1, r4
bl LogMessageByIdWithPopupCheckUserTarget
ldmia sp!, {r3, r4, r5, pc}
.align 2, 0
#ifdef JAPAN
_0230DA40: .word 0x00002493
#else
_0230DA40: .word 0x00000F2C
#endif
arm_func_end SwapOffensiveMultipliers
arm_func_start SwapHitChanceStages
SwapHitChanceStages: ; 0x0230DA44
stmdb sp!, {r3, r4, r5, lr}
mov r5, r0
mov r4, r1
ldr lr, [r5, #0xb4]
ldr ip, [r4, #0xb4]
ldrsh r3, [lr, #0x2c]
ldrsh r1, [lr, #0x2e]
ldrsh r0, [ip, #0x2c]
cmp r2, #0
strh r0, [lr, #0x2c]
ldrsh r0, [ip, #0x2e]
strh r0, [lr, #0x2e]
strh r3, [ip, #0x2c]
strh r1, [ip, #0x2e]
ldmeqia sp!, {r3, r4, r5, pc}
mov r0, #0
mov r1, r5
mov r2, r0
bl SubstitutePlaceholderStringTags
mov r1, r4
mov r0, #1
mov r2, #0
bl SubstitutePlaceholderStringTags
ldr r2, _0230DAB4 ; =0x00000F2F
mov r0, r5
mov r1, r4
bl LogMessageByIdWithPopupCheckUserTarget
ldmia sp!, {r3, r4, r5, pc}
.align 2, 0
#ifdef JAPAN
_0230DAB4: .word 0x00002496
#else
_0230DAB4: .word 0x00000F2F
#endif
arm_func_end SwapHitChanceStages
arm_func_start SwapUserAtkAndDefModifiers
SwapUserAtkAndDefModifiers: ; 0x0230DAB8
stmdb sp!, {r3, r4, r5, lr}
mov r5, r0
ldr ip, [r5, #0xb4]
mov r4, r1
ldrsh r1, [ip, #0x24]
ldr r3, [ip, #0x34]
ldr r0, [ip, #0x3c]
cmp r2, #0
str r0, [ip, #0x34]
ldrsh r0, [ip, #0x28]
strh r0, [ip, #0x24]
str r3, [ip, #0x3c]
strh r1, [ip, #0x28]
ldmeqia sp!, {r3, r4, r5, pc}
mov r0, #0
mov r1, r5
mov r2, r0
bl SubstitutePlaceholderStringTags
#ifdef JAPAN
ldr r2, _0230F050 ; =0x00002497
mov r0, r5
mov r1, r4
#else
mov r0, r5
mov r1, r4
mov r2, #0xf30
#endif
bl LogMessageByIdWithPopupCheckUserTarget
ldmia sp!, {r3, r4, r5, pc}
#ifdef JAPAN
_0230F050: .word 0x00002497
#endif
arm_func_end SwapUserAtkAndDefModifiers

View File

@@ -1165,10 +1165,7 @@ struct damage_calc_diag {
u8 field_0x1;
u8 field_0x2;
u8 field_0x3;
enum move_category move_category; // 0x4: The category of the last move used
u8 field_0x5;
u8 field_0x6;
u8 field_0x7;
s32 move_category;
// 0x8: The type matchup of the last move used against the individual types of the defender
enum type_matchup move_indiv_type_matchups[2];
// 0xA: The modified offensive stat stage of the attacker for the last move used
@@ -1222,29 +1219,29 @@ struct damage_calc_diag {
s32 static_damage_mult;
// 0x30: The net number of attack boosts to an attacker due to a Power Band or Munch Belt.
// It seems like there's a bug in the code; aura bows do not contribute to this field.
s8 item_atk_modifier;
u8 item_atk_modifier;
// 0x31: The net number of special attack boosts to an attacker due to a Special Band,
// Munch Belt, or aura bow. It seems like there's a bug in the code; physical attack boosts
// from aura bows also contribute to this field.
s8 item_sp_atk_modifier;
u8 item_sp_atk_modifier;
// 0x32: The net number of offense boosts to an attacker due to Download, Rivalry,
// Flower Gift, and Solar Power
s8 ability_offense_modifier;
u8 ability_offense_modifier;
// 0x33: The net number of defense boosts to a defender due to Flower Gift
s8 ability_defense_modifier;
u8 ability_defense_modifier;
// 0x34: The net number of offense boosts to an attacker due to Aggressor, Defender, and
// Practice Swinger
s8 iq_skill_offense_modifier;
u8 iq_skill_offense_modifier;
// 0x35: The net number of defense boosts to a defender due to Counter Basher, Aggressor, and
// Defender
s8 iq_skill_defense_modifier;
u8 iq_skill_defense_modifier;
// 0x36: The net number of defense boosts to a defender due to a Def Scarf or aura bow.
// It seems like there's a bug in the code; special defense boosts from aura bows also
// contribute to this field.
s8 item_def_modifier;
u8 item_def_modifier;
// 0x37: The net number of special defense boosts to a defender due to a Zinc Band.
// It seems like there's a bug in the code; aura bows do not contribute to this field.
s8 item_sp_def_modifier;
u8 item_sp_def_modifier;
// 0x38: Whether or not Scope Lens or Sharpshooter boosted the critical hit rate of a move
bool8 scope_lens_or_sharpshooter_activated;
// 0x39: Whether or not the Patsy Band boosted the critical hit rate of a move

View File

@@ -0,0 +1,12 @@
#ifndef PMDSKY_OVERLAY_29_0230BBAC_H
#define PMDSKY_OVERLAY_29_0230BBAC_H
#include "dungeon_mode.h"
#include "enums.h"
#include "overlay_29_02308FBC.h"
void CalcDamage(struct entity *attacker, struct entity *defender, enum type_id attack_type,
s32 power, s32 crit_chance, struct unk_02308FE0 *damage_out,
s32 damage_mult, enum move_id move_id, s32 a9);
#endif

View File

@@ -977,7 +977,8 @@ Overlay OVY_29
Object src/type_effectiveness.o
Object src/dungeon_damage.o
Object asm/overlay_29_rodata_02352894.o
Object asm/overlay_29_0230BBAC.o
Object src/overlay_29_0230BBAC.o
Object asm/overlay_29_0230D088.o
Object src/dungeon_recruitment.o
Object asm/overlay_29_0230E064.o
Object src/overlay_29_0230E578.o

734
src/overlay_29_0230BBAC.c Normal file
View File

@@ -0,0 +1,734 @@
#include "overlay_29_0230BBAC.h"
#include "debug.h"
#include "dg_random.h"
#include "dungeon.h"
#include "dungeon_logic.h"
#include "dungeon_pokemon_attributes.h"
#include "dungeon_pokemon_attributes_1.h"
#include "dungeon_util_static.h"
#include "enums.h"
#include "item.h"
#include "main_02001894.h"
#include "main_02001A54.h"
#include "main_02001BB4.h"
#include "main_02001CD4.h"
#include "main_02014CEC.h"
#include "main_0201514C.h"
#include "main_02054DC4.h"
#include "move_orb_effects.h"
#include "number_util.h"
#include "overlay_29_022E3F20.h"
#include "overlay_29_022E406C.h"
#include "overlay_29_0230A994.h"
#include "overlay_29_0230A9DC.h"
#include "run_dungeon_1.h"
#include "type_effectiveness.h"
#include "weather.h"
extern struct dungeon *DUNGEON_PTR;
extern u8 GetMonsterGenderVeneer(s16 monster_id);
extern u8 ExclusiveItemOffenseBoost(struct entity *entity, s32 idx);
extern u8 ExclusiveItemDefenseBoost(struct entity *entity, s32 idx);
extern int MoveIsNotPhysical(enum move_id move_id);
extern bool8 NearbyAllyIqSkillIsEnabled(struct entity *entity, enum iq_skill_id iq_skill);
extern s32 FixedPoint64ToInt(struct fixed_point_64 *x);
extern void AddFixedPoint64(struct fixed_point_64 *out, struct fixed_point_64 *a, struct fixed_point_64 *b);
extern void ClampedLn(struct fixed_point_64 *out, s32 x);
extern int IsRecoilMove(enum move_id move_id);
extern void PlayEffectAnimation0x1A9__022E6130(struct entity *entity);
extern void PlayEffectAnimation0x1A9__022E617C(struct entity *entity);
extern void PlayEffectAnimation0x18E(struct entity *entity);
extern bool8 AuraBowIsActive(struct entity *entity);
extern bool8 FixedPoint64CmpLt(const struct fixed_point_64 *a, const struct fixed_point_64 *b);
extern void DivideFixedPoint64(struct fixed_point_64 *out, struct fixed_point_64 *a, struct fixed_point_64 *b);
extern void ResetDamageCalcDiagnostics(void);
extern bool8 OtherMonsterAbilityIsActive(struct entity *entity, enum ability_id ability_id);
extern void MultiplyFixedPoint64(struct fixed_point_64 *out, const struct fixed_point_64 *a, const struct fixed_point_64 *b);
extern void LogMessageByIdWithPopupCheckUserTarget(struct entity *user, struct entity *target, u32 message_id);
extern bool8 UpdateStateFlags(struct monster *info, s32 flag, bool8 value);
extern void ResetDamageData(struct unk_02308FE0 *damage_data);
extern void SubstitutePlaceholderStringTags(s32 string_id, struct entity *entity, u32 param_3);
extern bool8 ExclusiveItemEffectIsActiveWithLogging(struct entity *user, struct entity *target, bool8 should_log, s32 message_id, enum exclusive_item_effect_id effect_id);
extern const u8 ov29_02352984[];
extern const u8 ov29_02352990[];
extern const u8 ov29_0235299C[];
extern const s32 ov29_02352838[];
extern const s16 AURA_BOW_STAT_BOOST;
extern const s16 DEF_SCARF_STAT_BOOST;
extern const s16 MUNCH_BELT_STAT_BOOST;
extern const s16 POWER_BAND_STAT_BOOST;
extern const s16 SPECIAL_BAND_STAT_BOOST;
extern const s16 ZINC_BAND_STAT_BOOST;
extern const s16 SCOPE_LENS_CRIT_RATE_BOOST;
extern const s16 SUPER_LUCK_CRIT_RATE_BOOST;
extern const s16 TYPE_ADVANTAGE_MASTER_CRIT_RATE;
extern const s32 AIR_BLADE_DAMAGE_MULTIPLIER;
extern const s32 ME_FIRST_MULTIPLIER;
extern const s32 POWER_PITCHER_DAMAGE_MULTIPLIER;
extern const s32 DAMAGE_FORMULA_AT_PREFACTOR;
extern const s32 DAMAGE_FORMULA_CONSTANT_SHIFT;
extern const s32 DAMAGE_FORMULA_DEF_PREFACTOR;
extern const s32 DAMAGE_FORMULA_FLV_DEFICIT_DIVISOR;
extern const s32 DAMAGE_FORMULA_FLV_SHIFT;
extern const s32 DAMAGE_FORMULA_LN_ARG_PREFACTOR;
extern const s32 DAMAGE_FORMULA_LN_PREFACTOR;
extern const s32 DAMAGE_FORMULA_NON_TEAM_MEMBER_MODIFIER;
extern const s32 OFFENSIVE_STAT_STAGE_MULTIPLIERS[21];
extern const s32 DEFENSIVE_STAT_STAGE_MULTIPLIERS[21];
extern const struct fixed_point_64 DAMAGE_FORMULA_MAX_BASE;
extern const struct fixed_point_64 DAMAGE_FORMULA_MIN_BASE;
extern const struct fixed_point_64 DAMAGE_MULTIPLIER_0_5;
extern const struct fixed_point_64 DAMAGE_MULTIPLIER_1_5;
extern const struct fixed_point_64 DAMAGE_MULTIPLIER_2;
#ifdef JAPAN
#define MESSAGE_C53 0x992
#define MESSAGE_C54 0x993
#define MESSAGE_C55 0x994
#define MESSAGE_C57 0x996
#define MESSAGE_C58 0x997
#define MESSAGE_DC1 0xB01
#else
#define MESSAGE_C53 0xC53
#define MESSAGE_C54 0xC54
#define MESSAGE_C55 0xC55
#define MESSAGE_C57 0xC57
#define MESSAGE_C58 0xC58
#define MESSAGE_DC1 0xDC1
#endif
void CalcDamage(struct entity *attacker, struct entity *defender, enum type_id attack_type,
s32 power, s32 crit_chance, struct unk_02308FE0 *damage_out,
s32 damage_mult, enum move_id move_id, s32 a9)
{
struct fixed_point_64 type_mult;
struct fixed_point_64 base;
struct fixed_point_64 flv_fp;
struct fixed_point_64 at_fp;
struct fixed_point_64 def_fp;
s32 calc[2];
struct fixed_point_64 tmp2;
struct fixed_point_64 tmp;
struct fixed_point_64 scratch;
struct fixed_point_64 tmp3;
struct fixed_point_64 mult_fp;
struct fixed_point_64 ln_fp;
struct fixed_point_64 mult32_fp;
struct fixed_point_64 hundred_fp;
struct monster *amon;
struct monster *dmon;
bool8 has_status;
s32 off_stage;
s32 ability_roll;
s32 off_mult;
s32 def_mult;
bool8 has_status2;
bool8 has_status3;
s32 not_physical2;
s32 def_ability_div;
s32 def_ability_mult;
s32 dv;
s32 p;
struct monster *info;
struct monster *info2;
int dmult;
s32 not_physical;
s32 is_team_member;
s32 def_stage;
s32 off_ability_mult;
s32 off_ability_div;
s32 off_mod;
s32 def_mod;
bool8 boosted;
s32 type_boosted;
s32 rate;
s32 flash;
volatile s32 *po;
volatile s32 *po2;
volatile s32 *pd;
struct damage_calc_diag *diag;
amon = GetEntInfo(attacker);
dmon = GetEntInfo(defender);
dmult = damage_mult;
diag = &DUNGEON_PTR->last_damage_calc;
ResetDamageData(damage_out);
if (amon->me_first_flag) {
dmult = MultiplyByFixedPoint(dmult, ME_FIRST_MULTIPLIER);
}
if (AbilityIsActiveVeneer(attacker, ABILITY_RECKLESS) && IsRecoilMove(move_id)) {
dmult = dmult * 3 / 2;
}
if (AbilityIsActiveVeneer(attacker, ABILITY_IRON_FIST) && IsPunchMove(move_id)) {
dmult = MultiplyByFixedPoint(dmult, 0x180);
}
if (AbilityIsActiveVeneer(attacker, ABILITY_NORMALIZE)) {
attack_type = TYPE_NORMAL;
}
if (move_id == 0x1D3) {
attack_type = amon->types[0];
}
not_physical = MoveIsNotPhysical(move_id);
ResetDamageCalcDiagnostics();
if (!amon->is_team_leader && CeilFixedPoint(amon->belly) == 0) {
damage_out->field_0x0 = 1;
damage_out->field_0x4 = 0;
damage_out->field_0x8 = MATCHUP_NEUTRAL;
damage_out->field_0xc = attack_type;
damage_out->field_0xd = GetMoveCategory(move_id);
damage_out->field_0xe = FALSE;
damage_out->field_0xf = FALSE;
damage_out->field_0x10 = FALSE;
return;
}
#ifdef JAPAN
if (move_id == 0x163
&& DefenderAbilityIsActive__0230A940(attacker, defender, ABILITY_WONDER_GUARD)) {
#else
if (move_id == 0x163
&& DefenderAbilityIsActive__0230A940(attacker, defender, ABILITY_WONDER_GUARD, TRUE)) {
#endif
damage_out->field_0x0 = 1;
damage_out->field_0x4 = 0;
damage_out->field_0x8 = MATCHUP_NEUTRAL;
damage_out->field_0xc = attack_type;
damage_out->field_0xd = GetMoveCategory(move_id);
damage_out->field_0xe = FALSE;
damage_out->field_0xf = FALSE;
damage_out->field_0x10 = FALSE;
return;
}
damage_out->field_0xc = attack_type;
damage_out->field_0xd = GetMoveCategory(move_id);
diag->move_type = attack_type;
off_mod = 0;
def_mod = 0;
diag->move_category = not_physical;
off_mult = amon->stat_modifiers.offensive_multipliers[not_physical];
def_mult = dmon->stat_modifiers.defensive_multipliers[not_physical];
if (AbilityIsActiveVeneer(attacker, ABILITY_DOWNLOAD)) {
if (dmon->defensive_stats[0] >= dmon->defensive_stats[1]) {
if (not_physical == 1) {
off_mod++;
diag->ability_offense_modifier++;
}
} else if (not_physical == 0) {
off_mod++;
diag->ability_offense_modifier++;
}
}
off_stage = amon->stat_modifiers.offensive_stages[not_physical];
if (a9) {
if (attack_type == TYPE_FIRE) {
s16 boost = amon->stat_modifiers.flash_fire_boost;
diag->flash_fire_boost = boost;
off_mod += boost;
}
}
if (IqSkillIsEnabled(attacker, IQ_AGGRESSOR)) {
off_mod++;
diag->iq_skill_offense_modifier++;
}
if (IqSkillIsEnabled(attacker, IQ_DEFENDER)) {
off_mod--;
diag->iq_skill_offense_modifier--;
}
if (IqSkillIsEnabled(attacker, IQ_PRACTICE_SWINGER) && amon->practice_swinger_flag) {
off_mod++;
diag->iq_skill_offense_modifier++;
}
if (NearbyAllyIqSkillIsEnabled(attacker, IQ_CHEERLEADER)) {
off_mod++;
}
if (not_physical == 0) {
if (AbilityIsActiveVeneer(attacker, ABILITY_RIVALRY)) {
if (GendersEqualNotGenderless(amon->apparent_id, dmon->apparent_id)) {
off_mod++;
diag->ability_offense_modifier++;
} else if (GetMonsterGenderVeneer(amon->apparent_id) != 3
&& GetMonsterGenderVeneer(dmon->apparent_id) != 3) {
off_mod--;
diag->ability_offense_modifier--;
}
}
if (GetApparentWeather(attacker) == WEATHER_SUNNY
&& (AbilityIsActiveVeneer(attacker, ABILITY_FLOWER_GIFT)
|| OtherMonsterAbilityIsActive(attacker, ABILITY_FLOWER_GIFT))) {
off_mod++;
diag->ability_offense_modifier++;
}
} else {
if (AbilityIsActiveVeneer(attacker, ABILITY_SOLAR_POWER)
&& GetApparentWeather(attacker) == WEATHER_SUNNY) {
off_mod += 2;
diag->ability_offense_modifier += 2;
}
if (GetApparentWeather(defender) == WEATHER_SUNNY
&& (AbilityIsActiveVeneer(defender, ABILITY_FLOWER_GIFT)
|| OtherMonsterAbilityIsActive(defender, ABILITY_FLOWER_GIFT))) {
def_mod++;
diag->ability_defense_modifier++;
}
if (GetApparentWeather(defender) == WEATHER_SANDSTORM
&& (dmon->types[0] == TYPE_ROCK || dmon->types[1] == TYPE_ROCK)) {
def_mod += 2;
}
}
if (amon->apparent_id == 0x1A3) {
off_mod += 2;
}
if (amon->apparent_id == 0x1A4) {
off_mod -= 2;
}
if (amon->apparent_id == 0x1A5) {
off_mod -= 2;
}
if (amon->apparent_id == 0x211) {
off_mod -= 2;
} else if (amon->apparent_id == 0x218) {
off_mod += 2;
}
off_stage += off_mod;
if (amon->anger_point_flag && AbilityIsActiveVeneer(attacker, ABILITY_ANGER_POINT)) {
off_stage = 20;
}
def_stage = dmon->stat_modifiers.defensive_stages[not_physical];
if (not_physical == 0) {
if (dmon->bide_class_status.bide == 6) {
diag->skull_bash_defense_boost_activated = TRUE;
def_mod++;
}
if (IqSkillIsEnabled(defender, IQ_COUNTER_BASHER)) {
def_mod--;
diag->iq_skill_defense_modifier--;
}
}
if (IqSkillIsEnabled(defender, IQ_AGGRESSOR)) {
def_mod--;
diag->iq_skill_defense_modifier--;
}
if (IqSkillIsEnabled(defender, IQ_DEFENDER)) {
def_mod++;
diag->iq_skill_defense_modifier++;
}
if (dmon->apparent_id == 0x1A3) {
def_mod -= 2;
}
if (dmon->apparent_id == 0x1A4) {
def_mod += 2;
}
if (dmon->apparent_id == 0x1A5) {
def_mod -= 2;
}
#ifdef JAPAN
if (amon->apparent_id == 0x211) {
def_mod += 2;
} else if (amon->apparent_id == 0x218) {
def_mod -= 2;
}
#else
if (dmon->apparent_id == 0x211) {
def_mod += 2;
} else if (dmon->apparent_id == 0x218) {
def_mod -= 2;
}
#endif
def_stage += def_mod;
if (move_id == 0x1BD) {
s16 sum = 0;
if (dmon->stat_modifiers.offensive_stages[0] > 10) {
sum += dmon->stat_modifiers.offensive_stages[0] - 10;
}
if (dmon->stat_modifiers.defensive_stages[0] > 10) {
sum += dmon->stat_modifiers.defensive_stages[0] - 10;
}
if (dmon->stat_modifiers.offensive_stages[1] > 10) {
sum += dmon->stat_modifiers.offensive_stages[1] - 10;
}
if (dmon->stat_modifiers.defensive_stages[1] > 10) {
sum += dmon->stat_modifiers.defensive_stages[1] - 10;
}
off_stage += sum;
}
if (AbilityIsActiveVeneer(attacker, ABILITY_UNAWARE)) {
def_stage = 10;
def_mult = 0x100;
#ifdef JAPAN
} else if (DefenderAbilityIsActive__0230A940(attacker, defender, ABILITY_UNAWARE)) {
#else
} else if (DefenderAbilityIsActive__0230A940(attacker, defender, ABILITY_UNAWARE, TRUE)) {
#endif
off_stage = 10;
off_mult = 0x100;
}
if (off_stage < 0) {
off_stage = 0;
}
if (off_stage > 20) {
off_stage = 20;
}
diag->offensive_stat_stage = off_stage;
diag->offensive_stat = amon->offensive_stats[not_physical];
calc[0] = MultiplyByFixedPoint(
MultiplyByFixedPoint(amon->offensive_stats[not_physical] << 8,
OFFENSIVE_STAT_STAGE_MULTIPLIERS[off_stage]),
off_mult) >> 8;
if (def_stage < 0) {
def_stage = 0;
}
if (def_stage > 20) {
def_stage = 20;
}
diag->defensive_stat_stage = def_stage;
diag->defensive_stat = dmon->defensive_stats[not_physical];
calc[1] = MultiplyByFixedPoint(
MultiplyByFixedPoint(dmon->defensive_stats[not_physical] << 8,
DEFENSIVE_STAT_STAGE_MULTIPLIERS[def_stage]),
def_mult) >> 8;
if (!amon->is_not_team_member) {
calc[0] += ExclusiveItemOffenseBoost(attacker, not_physical);
}
if (!dmon->is_not_team_member) {
calc[1] += ExclusiveItemDefenseBoost(defender, not_physical);
}
if (not_physical == 0) {
if (ItemIsActive__0230A9DC(attacker, ITEM_POWER_BAND)) {
calc[0] += POWER_BAND_STAT_BOOST;
diag->item_atk_modifier += POWER_BAND_STAT_BOOST;
}
if (ItemIsActive__0230A9DC(attacker, ITEM_MUNCH_BELT)) {
calc[0] += MUNCH_BELT_STAT_BOOST;
diag->item_atk_modifier += MUNCH_BELT_STAT_BOOST;
}
if (AuraBowIsActive(attacker)) {
calc[0] += AURA_BOW_STAT_BOOST;
diag->item_sp_atk_modifier += AURA_BOW_STAT_BOOST;
}
if (a9) {
if (ItemIsActive__0230A9DC(defender, ITEM_DEF_SCARF)) {
calc[1] += DEF_SCARF_STAT_BOOST;
diag->item_def_modifier += DEF_SCARF_STAT_BOOST;
}
if (AuraBowIsActive(defender)) {
calc[1] += AURA_BOW_STAT_BOOST;
diag->item_def_modifier += AURA_BOW_STAT_BOOST;
}
}
} else {
if (a9) {
if (ItemIsActive__0230A9DC(defender, ITEM_ZINC_BAND)) {
calc[1] += ZINC_BAND_STAT_BOOST;
diag->item_sp_def_modifier += ZINC_BAND_STAT_BOOST;
}
if (AuraBowIsActive(defender)) {
calc[1] += AURA_BOW_STAT_BOOST;
diag->item_def_modifier += AURA_BOW_STAT_BOOST;
}
}
if (ItemIsActive__0230A9DC(attacker, ITEM_SPECIAL_BAND)) {
calc[0] += SPECIAL_BAND_STAT_BOOST;
diag->item_sp_atk_modifier += SPECIAL_BAND_STAT_BOOST;
}
if (ItemIsActive__0230A9DC(attacker, ITEM_MUNCH_BELT)) {
calc[0] += MUNCH_BELT_STAT_BOOST;
diag->item_sp_atk_modifier += MUNCH_BELT_STAT_BOOST;
}
if (AuraBowIsActive(defender)) {
calc[0] += AURA_BOW_STAT_BOOST;
diag->item_sp_atk_modifier += AURA_BOW_STAT_BOOST;
}
}
po = &calc[0];
po2 = &calc[0];
FixedPoint32To64(&at_fp,
MultiplyByFixedPoint(MultiplyByFixedPoint(power << 8,
OFFENSIVE_STAT_STAGE_MULTIPLIERS[off_stage]),
off_mult));
ability_roll = DungeonRandInt(100);
amon->prev_state_flags &= ~0x100;
amon->state_flags &= ~0x100;
off_ability_mult = 1;
off_ability_div = 1;
def_ability_mult = 1;
def_ability_div = 1;
not_physical2 = MoveIsNotPhysical(move_id);
if (not_physical2 == 0 && AbilityIsActiveVeneer(attacker, ABILITY_GUTS)) {
info = attacker->info;
has_status = MonsterHasNegativeStatus(attacker, TRUE);
boosted = UpdateStateFlags(info, 1, has_status);
if (has_status) {
off_ability_mult <<= 1;
}
if (boosted) {
PlayEffectAnimation0x1A9__022E6130(attacker);
LogMessageByIdWithPopupCheckUserTarget(attacker, defender, MESSAGE_C53);
}
}
if (AbilityIsActiveVeneer(attacker, ABILITY_HUGE_POWER)
|| AbilityIsActiveVeneer(attacker, ABILITY_PURE_POWER)) {
info = attacker->info;
has_status2 = (ability_roll < 0x21 && not_physical2 == 0);
boosted = UpdateStateFlags(info, 0x100, has_status2);
if (has_status2) {
off_ability_mult += off_ability_mult * 2;
off_ability_div <<= 1;
}
if (boosted) {
PlayEffectAnimation0x1A9__022E617C(attacker);
LogMessageByIdWithPopupCheckUserTarget(attacker, defender, MESSAGE_C54);
}
}
if (AbilityIsActiveVeneer(attacker, ABILITY_HUSTLE) && not_physical2 == 0) {
off_ability_mult += off_ability_mult * 2;
off_ability_div <<= 1;
}
is_team_member = !((struct monster *)attacker->info)->is_not_team_member;
if (AbilityIsActiveVeneer(attacker, ABILITY_PLUS) && not_physical2 == 1
&& DUNGEON_PTR->minus_is_active[is_team_member]) {
off_ability_mult = off_ability_mult * 16 - off_ability_mult;
off_ability_div *= 10;
}
if (AbilityIsActiveVeneer(attacker, ABILITY_MINUS) && not_physical2 == 1
&& DUNGEON_PTR->plus_is_active[is_team_member]) {
off_ability_mult = off_ability_mult * 16 - off_ability_mult;
off_ability_div *= 10;
}
#ifdef JAPAN
if (DefenderAbilityIsActive__0230A940(attacker, defender, ABILITY_INTIMIDATE)
&& not_physical2 == 0) {
#else
if (DefenderAbilityIsActive__0230A940(attacker, defender, ABILITY_INTIMIDATE, TRUE)
&& not_physical2 == 0) {
#endif
off_ability_mult <<= 2;
off_ability_div += off_ability_div * 4;
}
#ifdef JAPAN
if (DefenderAbilityIsActive__0230A940(attacker, defender, ABILITY_MARVEL_SCALE)
&& not_physical2 == 0) {
#else
if (DefenderAbilityIsActive__0230A940(attacker, defender, ABILITY_MARVEL_SCALE, TRUE)
&& not_physical2 == 0) {
#endif
info2 = defender->info;
has_status3 = MonsterHasNegativeStatus(defender, TRUE);
boosted = UpdateStateFlags(info2, 8, has_status3);
if (has_status3) {
def_ability_mult = def_ability_mult * 3;
def_ability_div <<= 1;
}
if (boosted) {
PlayEffectAnimation0x18E(defender);
LogMessageByIdWithPopupCheckUserTarget(attacker, defender, MESSAGE_C55);
}
}
pd = &calc[1];
p = *po * off_ability_mult;
dv = *pd;
*pd = dv * def_ability_mult;
*po2 = p;
if (off_ability_div != 1) {
*po2 = p / off_ability_div;
}
if (def_ability_div != 1) {
pd = &calc[1];
*pd = *pd / def_ability_div;
}
diag->offense_calc = calc[0];
diag->defense_calc = calc[1];
if (calc[0] < 0) {
calc[0] = 0;
}
if (calc[0] >= 999) {
calc[0] = 999;
}
diag->damage_calc_def = calc[1];
IntToFixedPoint64(&def_fp, calc[1]);
IntToFixedPoint64(&tmp2, calc[0] - calc[1]);
FixedPoint32To64(&tmp, DAMAGE_FORMULA_FLV_DEFICIT_DIVISOR);
DivideFixedPoint64(&tmp2, &tmp2, &tmp);
IntToFixedPoint64(&tmp, amon->level);
AddFixedPoint64(&flv_fp, &tmp, &tmp2);
IntToFixedPoint64(&tmp, calc[0]);
AddFixedPoint64(&at_fp, &at_fp, &tmp);
diag->damage_calc_at = FixedPoint64ToInt(&at_fp);
diag->attacker_level = amon->level;
diag->damage_calc_flv = FixedPoint64ToInt(&flv_fp);
Debug_Print0(ov29_02352984, FixedPoint64ToInt(&flv_fp));
Debug_Print0(ov29_02352990, FixedPoint64ToInt(&at_fp));
Debug_Print0(ov29_0235299C, FixedPoint64ToInt(&def_fp));
FixedPoint32To64(&tmp3, DAMAGE_FORMULA_AT_PREFACTOR);
MultiplyFixedPoint64(&tmp3, &at_fp, &tmp3);
FixedPoint32To64(&mult_fp, DAMAGE_FORMULA_DEF_PREFACTOR);
MultiplyFixedPoint64(&mult_fp, &def_fp, &mult_fp);
FixedPoint32To64(&scratch, DAMAGE_FORMULA_FLV_SHIFT);
AddFixedPoint64(&ln_fp, &flv_fp, &scratch);
FixedPoint32To64(&scratch, DAMAGE_FORMULA_LN_ARG_PREFACTOR);
MultiplyFixedPoint64(&ln_fp, &ln_fp, &scratch);
ClampedLn(&ln_fp, FixedPoint64ToInt(&ln_fp));
FixedPoint32To64(&scratch, DAMAGE_FORMULA_LN_PREFACTOR);
MultiplyFixedPoint64(&ln_fp, &ln_fp, &scratch);
AddFixedPoint64(&base, &mult_fp, &tmp3);
AddFixedPoint64(&base, &base, &ln_fp);
FixedPoint32To64(&scratch, DAMAGE_FORMULA_CONSTANT_SHIFT);
AddFixedPoint64(&base, &base, &scratch);
if (!FixedRoomIsSubstituteRoom() && amon->is_not_team_member) {
FixedPoint32To64(&scratch, DAMAGE_FORMULA_NON_TEAM_MEMBER_MODIFIER);
DivideFixedPoint64(&base, &base, &scratch);
}
if (FixedPoint64CmpLt(&DAMAGE_FORMULA_MAX_BASE, &base)) {
base.lower = ((const struct fixed_point_64 *)&ov29_02352838[13])->lower;
base.upper = ((const struct fixed_point_64 *)&ov29_02352838[13])->upper;
}
if (FixedPoint64CmpLt(&base, &DAMAGE_FORMULA_MIN_BASE)) {
base.lower = ((const struct fixed_point_64 *)&ov29_02352838[17])->lower;
base.upper = ((const struct fixed_point_64 *)&ov29_02352838[17])->upper;
}
type_boosted = CalcTypeBasedDamageEffects(&type_mult, attacker, defender, power, attack_type,
damage_out, IsRegularAttackOrProjectile(move_id) != 0);
if (attack_type == TYPE_FIRE) {
flash = FlashFireShouldActivate(attacker, defender);
if (flash && !dmon->apply_flash_fire_boost && a9) {
dmon->apply_flash_fire_boost = TRUE;
SubstitutePlaceholderStringTags(1, defender, 0);
if (flash == 1) {
LogMessageByIdWithPopupCheckUserTarget(attacker, defender, MESSAGE_C58);
} else {
LogMessageByIdWithPopupCheckUserTarget(attacker, defender, MESSAGE_C57);
}
}
}
if (a9 && !ExclusiveItemEffectIsActive__0230A9B8(attacker, EXCLUSIVE_EFF_BYPASS_REFLECT_LIGHT_SCREEN)) {
if (not_physical == 0) {
if ((move_id != 0x48 && dmon->reflect_class_status.reflect == 1)
|| ExclusiveItemEffectIsActive__0230A9B8(defender, EXCLUSIVE_EFF_HALVED_PHYSICAL_DAMAGE)) {
PlayEffectAnimation0x171(defender);
MultiplyFixedPoint64(&type_mult, &type_mult, &DAMAGE_MULTIPLIER_0_5);
diag->half_physical_damage_activated = TRUE;
}
}
if (not_physical == 1
&& (dmon->reflect_class_status.reflect == 3
|| ExclusiveItemEffectIsActive__0230A9B8(defender, EXCLUSIVE_EFF_HALVED_SPECIAL_DAMAGE))) {
PlayEffectAnimation0x171Full(defender);
MultiplyFixedPoint64(&type_mult, &type_mult, &DAMAGE_MULTIPLIER_0_5);
diag->half_special_damage_activated = TRUE;
}
}
#ifdef JAPAN
if (dmon->reflect_class_status.reflect != 0x11
&& !DefenderAbilityIsActive__0230A940(attacker, defender, ABILITY_BATTLE_ARMOR)
&& !DefenderAbilityIsActive__0230A940(attacker, defender, ABILITY_SHELL_ARMOR)
&& !IqSkillIsEnabled(defender, IQ_CRITICAL_DODGER)) {
#else
if (dmon->reflect_class_status.reflect != 0x11
&& !DefenderAbilityIsActive__0230A940(attacker, defender, ABILITY_BATTLE_ARMOR, TRUE)
&& !DefenderAbilityIsActive__0230A940(attacker, defender, ABILITY_SHELL_ARMOR, TRUE)
&& !IqSkillIsEnabled(defender, IQ_CRITICAL_DODGER)) {
#endif
if (GetMonsterGenderVeneer(amon->id) == 2) {
rate = crit_chance;
} else {
rate = crit_chance + crit_chance / 2;
}
if (amon->sure_shot_class_status.sure_shot == 4) {
rate = 999;
diag->focus_energy_activated = TRUE;
} else {
if (ItemIsActive__0230A9DC(attacker, ITEM_SCOPE_LENS)
|| IqSkillIsEnabled(attacker, IQ_SHARPSHOOTER)) {
diag->scope_lens_or_sharpshooter_activated = TRUE;
rate += SCOPE_LENS_CRIT_RATE_BOOST;
}
if (AbilityIsActiveVeneer(attacker, ABILITY_SUPER_LUCK)) {
diag->super_luck_activated = TRUE;
rate += SUPER_LUCK_CRIT_RATE_BOOST;
}
if (ItemIsActive__0230A9DC(defender, ITEM_PATSY_BAND)) {
diag->patsy_band_activated = TRUE;
rate += SCOPE_LENS_CRIT_RATE_BOOST;
}
if (type_boosted && IqSkillIsEnabled(attacker, IQ_TYPE_ADVANTAGE_MASTER)) {
diag->type_advantage_master_activated = TRUE;
rate = TYPE_ADVANTAGE_MASTER_CRIT_RATE;
}
}
if (DungeonRandInt(100) < rate
&& !ExclusiveItemEffectIsActiveWithLogging(attacker, defender, TRUE, MESSAGE_DC1, EXCLUSIVE_EFF_NO_CRITICAL_HITS)) {
damage_out->field_0xe = TRUE;
if (AbilityIsActiveVeneer(attacker, ABILITY_SNIPER)) {
MultiplyFixedPoint64(&type_mult, &type_mult, &DAMAGE_MULTIPLIER_2);
diag->sniper_activated = TRUE;
} else {
MultiplyFixedPoint64(&type_mult, &type_mult, &DAMAGE_MULTIPLIER_1_5);
}
}
}
diag->damage_calc_base = FixedPoint64ToInt(&base);
MultiplyFixedPoint64(&base, &base, &type_mult);
diag->static_damage_mult = dmult;
FixedPoint32To64(&mult32_fp, dmult);
MultiplyFixedPoint64(&base, &base, &mult32_fp);
diag->damage_calc = FixedPoint64ToInt(&base);
type_mult.lower = DungeonRandInt(0x4000);
type_mult.upper = 0;
type_mult.lower += 0xE000;
MultiplyFixedPoint64(&base, &base, &type_mult);
IntToFixedPoint64(&hundred_fp, 100);
MultiplyFixedPoint64(&type_mult, &hundred_fp, &type_mult);
diag->damage_calc_random_mult_pct = FixedPoint64ToInt(&type_mult);
damage_out->field_0x0 = FixedPoint64ToInt(&base);
if (move_id == 0x195) {
damage_out->field_0x0 = RoundUpDiv256(MultiplyByFixedPoint(damage_out->field_0x0 << 8, 0x80));
}
if (move_id == 0x195 && IqSkillIsEnabled(attacker, IQ_POWER_PITCHER)) {
damage_out->field_0x0 = RoundUpDiv256(
MultiplyByFixedPoint(damage_out->field_0x0 << 8, POWER_PITCHER_DAMAGE_MULTIPLIER));
}
if (damage_out->field_0x0 > 0
&& ExclusiveItemEffectIsActive__0230A9B8(attacker, EXCLUSIVE_EFF_DAMAGE_BOOST_50_PCT)) {
damage_out->field_0x0 = RoundUpDiv256(
MultiplyByFixedPoint(damage_out->field_0x0 << 8, AIR_BLADE_DAMAGE_MULTIPLIER));
}
damage_out->field_0x4 = 0;
if (damage_out->field_0x0 == 0) {
damage_out->field_0xe = FALSE;
}
dmon->anger_point_flag = damage_out->field_0xe;
}