Merge pull request #121 from AnonymousRandomPerson/main
Some checks failed
build / build (push) Has been cancelled

Decomped GetAiUseItemProbability
This commit is contained in:
AnonymousRandomPerson 2025-04-30 00:23:59 -04:00 committed by GitHub
commit a37596a92b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 898 additions and 1078 deletions

View File

@ -1,69 +1,70 @@
#pragma once
.public _020A1894
.public AbilityIsActiveVeneer
.public ATK_STAT_IDX
.public AbilityIsActiveVeneer
.public BoostIQ
.public BoostOffensiveStat
.public CalcDamageFixedNoCategory
.public CanSeeInvisibleMonsters
.public CeilFixedPoint
.public ChangeDungeonMusic
.public ChangeShayminForme
.public CheckVariousStatuses2
.public ClearMonsterActionFields
.public DetermineAllMonsterShadow
.public DetermineTileWalkableNeighbors
.public DIRECTIONS_XY
.public DUNGEON_PTR
.public DirectoryFileMngr_OpenDirectoryFile
.public DisplayMessage2
.public DUNGEON_PTR
.public DungeonRandInt
.public DungeonRandOutcome__022EAB20
.public EAT_ITEM_EFFECT_IGNORE_LIST
.public EndBurnClassStatus
.public EndFrozenClassStatus
.public EnsureCanStandCurrentTile
.public EntityIsValid__0231CBC8
.public EntityIsValid__0231EDD8
.public FemaleToMaleForm
.public GetActiveTeamMember
.public GetApparentWeather
.public GetDoughSeedFlag
.public GetItemMoveId16
.public GetMaxPp
.public GetMobilityType
.public GetMoveBasePower
.public GetMoveCategory
.public GetMoveMaxGinsengBoost
.public GetPerformanceFlagWithChecks
.public GetTile
.public GetTileSafe
.public GetTreatmentBetweenMonsters
.public GetWeatherColorTable
.public GINSENG_CHANCE_3
.public GUMMI_BELLY_RESTORE_TABLE
.public GUMMI_IQ_STRING_IDS
.public GUMMI_LIKE_STRING_IDS
.public GetActiveTeamMember
.public GetApparentWeather
.public GetDoughSeedFlag
.public GetItemMoveId16
.public GetMoveBasePower
.public GetMoveMaxGinsengBoost
.public GetPerformanceFlagWithChecks
.public GetWeatherColorTable
.public HandleMovesMenuWrapper0
.public HandleMovesMenuWrapper1
.public HandleSir0Translation
.public InitMove
.public IQ_GUMMI_GAIN_TABLE
.public IqSkillIsEnabled
.public IsBlinded
.public IsCurrentFixedRoomBossFight
.public IsEdible
.public IsExperienceLocked
.public IsFullFloorFixedRoom
.public IsHM
.public IsItemValidVeneer
.public LogMessageByIdWithPopup
.public LogMessageByIdWithPopupCheckUser
.public LogMessageByIdWithPopupCheckUserTarget
.public LowerDefensiveStat
.public LowerOffensiveStat
.public MonsterHasNegativeStatus
.public MusicTableIdxToMusicId
.public RemoveUsedItem
.public RestoreAllMovePP
.public SPATK_STAT_IDX
.public SetDoughSeedFlag
.public SetMonsterActionFields
.public ShouldDisplayEntityWrapper
.public SubstitutePlaceholderStringTags
.public TryDecreaseBelly
.public TryIncreaseBelly
.public TryInflictBurnStatus
.public TryInflictEndureStatus
.public TryInflictParalysisStatus
.public TryInflictPoisonedStatus
.public TryInflictShadowHoldStatus
.public TryWarp
.public UnloadFile
.public UpdateMinimap
.public WONDER_GUMMI_IQ_GAIN
.public YesNoMenu
.public _020A1894
.public ov10_022C44CC
.public ov10_022C44E8
.public ov10_022C45D4
@ -76,7 +77,6 @@
.public ov29_022DD828
.public ov29_022DE47C
.public ov29_022DE608
.public ov29_022E0378
.public ov29_022E5AE4
.public ov29_022E5BD8
.public ov29_022EA370
@ -94,18 +94,13 @@
.public ov29_022F085C
.public ov29_022F8830
.public ov29_022F9C34
.public ov29_022F9C74
.public ov29_022FA02C
.public ov29_022FBA54
.public ov29_023008DC
.public ov29_023009A0
.public ov29_023021F0
.public ov29_023038D4
.public ov29_02305814
.public ov29_0233665C
.public ov29_0233785C
.public ov29_02339FF4
.public ov29_0233FB1C
.public ov29_02344B44
.public ov29_0234B084
.public ov29_0234B09C
@ -118,26 +113,5 @@
.public ov31_02386204
.public ov31_02386308
.public ov31_023877EC
.public RemoveUsedItem
.public RestoreAllMovePP
.public SetDoughSeedFlag
.public SetMonsterActionFields
.public ShouldDisplayEntityWrapper
.public SPATK_STAT_IDX
.public StairsAlwaysReachable
.public sub_02050FF8
.public sub_02053D1C
.public SubstitutePlaceholderStringTags
.public TryDecreaseBelly
.public TryIncreaseBelly
.public TryInflictBurnStatus
.public TryInflictEndureStatus
.public TryInflictParalysisStatus
.public TryInflictPoisonedStatus
.public TryInflictShadowHoldStatus
.public TryWarp
.public UnloadFile
.public UpdateMinimap
.public UpdateTrapsVisibility
.public WONDER_GUMMI_IQ_GAIN
.public YesNoMenu

View File

@ -0,0 +1,27 @@
#pragma once
.public DIRECTIONS_XY
.public DUNGEON_PTR
.public DetermineAllMonsterShadow
.public DetermineTileWalkableNeighbors
.public EAT_ITEM_EFFECT_IGNORE_LIST
.public EnsureCanStandCurrentTile
.public EntityIsValid__0231EDD8
.public GetMaxPp
.public GetMoveCategory
.public GetTile
.public GetTileSafe
.public GetTreatmentBetweenMonsters
.public InitMove
.public IsFullFloorFixedRoom
.public IsItemValidVeneer
.public LogMessageByIdWithPopupCheckUser
.public StairsAlwaysReachable
.public UpdateMinimap
.public UpdateTrapsVisibility
.public ov29_022E0378
.public ov29_022EA370
.public ov29_022F9C74
.public ov29_02305814
.public ov29_0233665C
.public ov29_0233785C
.public ov29_0233FB1C

File diff suppressed because it is too large Load Diff

392
asm/overlay_29_0231E8F0.s Normal file
View File

@ -0,0 +1,392 @@
.include "asm/macros.inc"
.include "overlay_29_0231E8F0.inc"
.text
arm_func_start IsAdjacentToEnemy
IsAdjacentToEnemy: ; 0x0231E8F0
stmdb sp!, {r4, r5, r6, r7, r8, sb, sl, lr}
mov r5, #0
mov sl, #1
mov r6, r0
mov sb, r5
mov r8, r5
mov r7, sl
ldr r4, _0231E98C ; =DIRECTIONS_XY
b _0231E97C
_0231E914:
mov r1, r5, lsl #2
add r0, r4, r5, lsl #2
ldrsh ip, [r6, #4]
ldrsh r3, [r4, r1]
ldrsh r2, [r6, #6]
ldrsh r1, [r0, #2]
add r0, ip, r3
add r1, r2, r1
bl GetTile
ldr r1, [r0, #0xc]
cmp r1, #0
beq _0231E978
ldr r0, [r1]
cmp r0, #0
moveq r0, sl
movne r0, sb
cmp r0, #1
beq _0231E978
mov r0, r6
mov r2, r8
mov r3, r7
bl GetTreatmentBetweenMonsters
cmp r0, #1
moveq r0, #1
ldmeqia sp!, {r4, r5, r6, r7, r8, sb, sl, pc}
_0231E978:
add r5, r5, #1
_0231E97C:
cmp r5, #8
blt _0231E914
mov r0, #0
ldmia sp!, {r4, r5, r6, r7, r8, sb, sl, pc}
.align 2, 0
_0231E98C: .word DIRECTIONS_XY
arm_func_end IsAdjacentToEnemy
arm_func_start ShouldTryEatItem
ShouldTryEatItem: ; 0x0231E990
stmdb sp!, {r4, lr}
mov r4, r0
cmp r4, #0x45
blt _0231E9A8
cmp r4, #0x8a
ble _0231E9B0
_0231E9A8:
mov r0, #0
ldmia sp!, {r4, pc}
_0231E9B0:
bl IsItemValidVeneer
cmp r0, #0
moveq r0, #0
ldmeqia sp!, {r4, pc}
ldr r0, _0231E9EC ; =EAT_ITEM_EFFECT_IGNORE_LIST
b _0231E9D8
_0231E9C8:
cmp r4, r1
moveq r0, #0
ldmeqia sp!, {r4, pc}
add r0, r0, #2
_0231E9D8:
ldrsh r1, [r0]
cmp r1, #0
bne _0231E9C8
mov r0, #1
ldmia sp!, {r4, pc}
.align 2, 0
_0231E9EC: .word EAT_ITEM_EFFECT_IGNORE_LIST
arm_func_end ShouldTryEatItem
arm_func_start GetMaxPpWrapper
GetMaxPpWrapper: ; 0x0231E9F0
stmdb sp!, {r3, lr}
bl GetMaxPp
mov r0, r0, lsl #0x10
mov r0, r0, asr #0x10
ldmia sp!, {r3, pc}
arm_func_end GetMaxPpWrapper
arm_func_start ov29_0231EA04
ov29_0231EA04: ; 0x0231EA04
ldr ip, _0231EA14 ; =InitMove
mov r0, r1
mov r1, r2
bx ip
.align 2, 0
_0231EA14: .word InitMove
arm_func_end ov29_0231EA04
arm_func_start MoveIsNotPhysical
MoveIsNotPhysical: ; 0x0231EA18
stmdb sp!, {r3, lr}
bl GetMoveCategory
cmp r0, #0
moveq r0, #0
movne r0, #1
ldmia sp!, {r3, pc}
arm_func_end MoveIsNotPhysical
arm_func_start CategoryIsNotPhysical
CategoryIsNotPhysical: ; 0x0231EA30
cmp r0, #0
moveq r0, #0
movne r0, #1
bx lr
arm_func_end CategoryIsNotPhysical
arm_func_start ov29_0231EA40
ov29_0231EA40: ; 0x0231EA40
#ifdef JAPAN
#define OV29_0231EA40_OFFSET -0xA4
#else
#define OV29_0231EA40_OFFSET 0
#endif
stmdb sp!, {r3, r4, r5, r6, r7, r8, sb, sl, fp, lr}
mov sl, r0
bl IsFullFloorFixedRoom
cmp r0, #0
bne _0231EA80
ldr r0, _0231EDC8 ; =DUNGEON_PTR
ldr r0, [r0]
add r1, r0, #0x4000
ldrsh r0, [r1, #0xd4 + OV29_0231EA40_OFFSET]
sub r2, r0, #0x1a
mov r2, r2, lsl #0x10
mov r2, r2, asr #0x10
mov r2, r2, lsl #0x10
mov r2, r2, lsr #0x10
cmp r2, #1
bhi _0231EA90
_0231EA80:
ldr r1, _0231EDCC ; =0x00000E01
mov r0, sl
bl LogMessageByIdWithPopupCheckUser
ldmia sp!, {r3, r4, r5, r6, r7, r8, sb, sl, fp, pc}
_0231EA90:
ldrb r2, [r1, #0xc4 + OV29_0231EA40_OFFSET]
cmp r2, #0
beq _0231EAAC
ldr r1, _0231EDD0 ; =0x00000DFF
mov r0, sl
bl LogMessageByIdWithPopupCheckUser
ldmia sp!, {r3, r4, r5, r6, r7, r8, sb, sl, fp, pc}
_0231EAAC:
ldrb r1, [r1, #0xc7 + OV29_0231EA40_OFFSET]
cmp r1, #0
beq _0231EAC8
mov r0, sl
#ifdef JAPAN
mov r1, #0xb40
#else
mov r1, #0xe00
#endif
bl LogMessageByIdWithPopupCheckUser
ldmia sp!, {r3, r4, r5, r6, r7, r8, sb, sl, fp, pc}
_0231EAC8:
bl ov29_022E0378
cmp r0, #0
movne r7, #3
moveq r7, #2
mov r6, #0
mov sb, #1
_0231EAE0:
ldr fp, _0231EDC8 ; =DUNGEON_PTR
mov r5, #1
mov r4, #0
_0231EAEC:
mov r0, sb
mov r1, r5
mov r8, #0
bl GetTileSafe
ldrh r1, [r0]
bic r1, r1, #0x400
strh r1, [r0]
strb r4, [r0, #7]
ldrh r1, [r0]
tst r1, #0x10
bne _0231EBCC
tst r1, #0x100
bne _0231EBCC
ldrh r1, [r0, #2]
orr r1, r1, #3
strh r1, [r0, #2]
ldrh r1, [r0]
bic r1, r1, #8
strh r1, [r0]
ldrh r1, [r0]
tst r1, #0x40
ldrh r1, [r0]
movne r6, #1
and r2, r1, #3
cmp r2, #2
cmpne r2, #3
beq _0231EBCC
cmp sb, #1
cmpne r5, #1
cmpne sb, #0x36
cmpne r5, #0x1e
bne _0231EB84
ldr r1, [r0, #0x10]
cmp r1, #0
ldreq r1, [fp]
ldreqb r1, [r1, #0x78f]
cmpeq r1, #0
moveq r8, #1
_0231EB84:
cmp r8, #0
beq _0231EBA8
ldrh r1, [r0]
bic r1, r1, #3
strh r1, [r0]
ldrh r1, [r0]
orr r1, r1, r7
strh r1, [r0]
b _0231EBCC
_0231EBA8:
cmp r2, #1
beq _0231EBCC
ldrh r1, [r0]
bic r1, r1, #3
strh r1, [r0]
ldrh r1, [r0]
orr r1, r1, #1
orr r1, r1, #0x400
strh r1, [r0]
_0231EBCC:
add r5, r5, #1
cmp r5, #0x1f
blt _0231EAEC
add sb, sb, #1
cmp sb, #0x37
blt _0231EAE0
ldr r0, _0231EDC8 ; =DUNGEON_PTR
mov r2, #1
ldr r0, [r0]
add r1, r0, #0xcc00
ldrsh r0, [r1, #0xe4 + OV29_0231EA40_OFFSET]
ldrsh r1, [r1, #0xe6 + OV29_0231EA40_OFFSET]
bl StairsAlwaysReachable
cmp r0, #0
beq _0231EC64
mov r5, #0
mov r4, r5
_0231EC10:
mov r8, r4
_0231EC14:
mov r0, r5
mov r1, r8
bl GetTileSafe
ldrh r1, [r0]
tst r1, #0x100
bne _0231EC4C
tst r1, #0x400
beq _0231EC4C
tst r1, #0x8000
bicne r1, r1, #3
strneh r1, [r0]
ldrneh r1, [r0]
orrne r1, r1, r7
strneh r1, [r0]
_0231EC4C:
add r8, r8, #1
cmp r8, #0x20
blt _0231EC14
add r5, r5, #1
cmp r5, #0x38
blt _0231EC10
_0231EC64:
cmp r6, #0
ldrne r0, _0231EDC8 ; =DUNGEON_PTR
mov r5, #0
ldrne r0, [r0]
movne r1, #0
addne r0, r0, #0x4000
strneb r1, [r0, #0xc9 + OV29_0231EA40_OFFSET]
mov r4, r5
_0231EC84:
mov r7, r4
_0231EC88:
cmp r6, #0
beq _0231ECA8
mov r0, r5
mov r1, r7
bl GetTileSafe
ldrh r1, [r0]
orr r1, r1, #0x40
strh r1, [r0]
_0231ECA8:
mov r0, r5
mov r1, r7
bl DetermineTileWalkableNeighbors
add r7, r7, #1
cmp r7, #0x20
blt _0231EC88
add r5, r5, #1
cmp r5, #0x38
blt _0231EC84
ldr r4, _0231EDC8 ; =DUNGEON_PTR
mov r5, #0
_0231ECD4:
ldr r0, [r4]
add r0, r0, r5, lsl #2
add r0, r0, #0x12000
ldr r6, [r0, #0xb78 + OV29_0231EA40_OFFSET]
mov r0, r6
bl EntityIsValid__0231EDD8
cmp r0, #0
beq _0231ED08
ldrsh r0, [r6, #4]
ldrsh r1, [r6, #6]
bl GetTile
ldrb r0, [r0, #7]
strb r0, [r6, #0x25]
_0231ED08:
add r5, r5, #1
cmp r5, #0x14
blt _0231ECD4
bl ov29_0233FB1C
bl ov29_0233785C
bl ov29_0233665C
bl DetermineAllMonsterShadow
bl UpdateMinimap
bl UpdateTrapsVisibility
ldr r1, _0231EDD4 ; =0x00000DFE
mov r0, sl
bl LogMessageByIdWithPopupCheckUser
mov r0, #0x28
mov r1, #0x2b
bl ov29_022EA370
mov r0, sl
mov r1, #1
bl ov29_02305814
ldr r4, _0231EDC8 ; =DUNGEON_PTR
mov r6, #0
_0231ED58:
ldr r0, [r4]
add r0, r0, r6, lsl #2
add r0, r0, #0x12000
ldr r5, [r0, #0xb78 + OV29_0231EA40_OFFSET]
mov r0, r5
bl EntityIsValid__0231EDD8
cmp r0, #0
beq _0231ED98
mov r0, r5
bl ov29_022F9C74
mov r0, r5
bl EntityIsValid__0231EDD8
cmp r0, #0
beq _0231ED98
mov r0, r5
bl EnsureCanStandCurrentTile
_0231ED98:
add r6, r6, #1
cmp r6, #0x14
blt _0231ED58
ldr r0, _0231EDC8 ; =DUNGEON_PTR
mov r3, #1
ldr r1, [r0]
mov r0, #0x14
add r2, r1, #0x4000
mov r1, #0x2b
strb r3, [r2, #0xc4 + OV29_0231EA40_OFFSET]
bl ov29_022EA370
ldmia sp!, {r3, r4, r5, r6, r7, r8, sb, sl, fp, pc}
.align 2, 0
_0231EDC8: .word DUNGEON_PTR
#ifdef JAPAN
_0231EDCC: .word 0x00000B41
_0231EDD0: .word 0x00000B3F
_0231EDD4: .word 0x00000B3E
#else
_0231EDCC: .word 0x00000E01
_0231EDD0: .word 0x00000DFF
_0231EDD4: .word 0x00000DFE
#endif
arm_func_end ov29_0231EA40

View File

@ -0,0 +1,8 @@
#ifndef PMDSKY_DUNGEON_AI_ITEM_WEIGHT_H
#define PMDSKY_DUNGEON_AI_ITEM_WEIGHT_H
#include "dungeon_mode.h"
u32 GetAiUseItemProbability(struct entity *item_consumer, struct item *item, u32 flags);
#endif //PMDSKY_DUNGEON_AI_ITEM_WEIGHT_H

View File

@ -9,6 +9,8 @@
#include "util.h"
#define NUM_PICKED_IQ_SKILLS 3
#define MAX_MON_MOVES 4
#define MAX_SPEED_STAGE 4
// Used in various contexts, like with entity positions in the dungeon
struct position {
@ -114,6 +116,19 @@ struct sleep_class_status {
u8 sleep_turns; // 0x1: Turns left for the status in statuses::sleep
};
struct burn_class_status
{
enum status_burn_id burn; // 0x0: STATUS_BURN if 1
u8 burn_turns; // 0x1: Turns left for the status in statuses::burn
// 0x2: Turns left until residual damage for the status in statuses::burn, if applicable
u8 burn_damage_countdown;
// 0x3: The number of times the statuses::burn_damage_countdown has reached 0. Only used
// when badly poisoned. Determines how much damage the badly poisoned status condition
// will deal. There is no noticable difference because the table this value is looked up
// on is filled with 0x6
u8 badly_poisoned_damage_count;
};
struct frozen_class_status {
// 0x0: If non-zero, the corresponding status in status_frozen_id is active.
enum status_frozen_id freeze;
@ -139,6 +154,13 @@ struct bide_class_status {
u8 bide_move_slot; // 0x2: Slot in the user's move list
};
struct reflect_class_status {
u8 reflect; // 0x0: STATUS_REFLECT if 1
u8 reflect_turns; // 0x1: Turns left for the status in statuses::reflect
// 0x2: Turns left until residual healing for the status in statuses::reflect, if applicable
u8 reflect_damage_countdown;
};
struct curse_class_status {
// 0x0: If non-zero, the corresponding status in status_curse_id is active.
enum status_curse_id curse;
@ -171,13 +193,19 @@ struct iq_skill_flags
u32 flags[NUM_PICKED_IQ_SKILLS]; /* 0x0 */
};
struct moves
{
struct move moves[MAX_MON_MOVES]; // 0x0
u8 struggle_move_flags; // 0x18
};
// Monster info
struct monster {
// 0x0: flags: 2-byte bitfield
u16 flags;
enum monster_id id; // 0x2:
enum monster_id apparent_id : 16; // 0x4: What's outwardly displayed if Transformed
s16 id; // 0x2:
s16 apparent_id; // 0x4: What's outwardly displayed if Transformed
bool8 is_not_team_member; // 0x6: true for enemies and allied NPCs that aren't on the team
bool8 is_team_leader; // 0x7
// 0x8: An ally is an NPC that isn't a normal team member, e.g. for story boss battles
@ -261,22 +289,11 @@ struct monster {
u32 bide_damage_tally;
enum monster_behavior monster_behavior : 8; // 0xBC
struct sleep_class_status sleep_class_status; // 0xBD
u8 burn; // 0xBF: STATUS_BURN if 1
u8 burn_turns; // 0xC0: Turns left for the status in statuses::burn
// 0xC1: Turns left until residual damage for the status in statuses::burn, if applicable
u8 burn_damage_countdown;
// 0xC2: The number of times the statuses::burn_damage_countdown has reached 0. Only used
// when badly poisoned. Determines how much damage the badly poisoned status condition
// will deal. There is no noticable difference because the table this value is looked up
// on is filled with 0x6
u8 badly_poisoned_damage_count;
struct burn_class_status burn_class_status; // 0xBF
struct frozen_class_status frozen_class_status; // 0xC4
struct cringe_class_status cringe_class_status; // 0xD0
struct bide_class_status bide_class_status; // 0xD2
u8 reflect; // 0xD5: STATUS_REFLECT if 1
u8 reflect_turns; // 0xD6: Turns left for the status in statuses::reflect
// 0xD7: Turns left until residual healing for the status in statuses::reflect, if applicable
u8 reflect_damage_countdown;
struct reflect_class_status reflect_class_status; // 0xD5
struct curse_class_status curse_class_status; // 0xD8
u8 leech_seed; // 0xE0: STATUS_LEECH_SEED if 1
u8 field_0xe1;
@ -371,9 +388,7 @@ struct monster {
// 0x120: If zero, when the monster is standing in a room, the AI will make it head towards a
// random exit. If nonzero, the monster will instead move in a random direction every turn.
s32 random_movement;
struct move moves[4]; // 0x124
u8 move_flags; // 0x144: 1-byte bitfield
u8 field_0x145;
struct moves moves; // 0x124
struct fixed_point belly; // 0x146
struct fixed_point max_belly; // 0x14A:
// 0x14E: If true and the monster is an ally, the AI will skip it. False for enemies.

View File

@ -6,7 +6,7 @@
// Monster move info
struct move {
// 0x0: flags: 1-byte bitfield
u8 flags;
u8 flags0;
// bool8 f_exists : 1; // This move will show up in the move list
// bool8 f_subsequent_in_link_chain : 1; // This move is in a link chain, but not the first move
// bool8 f_enabled_for_ai : 1; // AI can use this move

View File

@ -19,4 +19,6 @@ static inline bool8 ItemExists(u8 flags)
return !!(flags & ITEM_FLAG_EXISTS);
}
#define ENTITY_POISONED(entity_info)((entity_info->burn_class_status.burn == STATUS_BURN_POISONED || entity_info->burn_class_status.burn == STATUS_BURN_BADLY_POISONED))
#endif // PMDSKY_DUNGEON_UTIL_STATIC_H

View File

@ -2313,6 +2313,7 @@ enum status_invisible_id {
STATUS_INVISIBLE_INVISIBLE = 1,
STATUS_INVISIBLE_TRANSFORMED = 2,
STATUS_INVISIBLE_MOBILE = 3,
STATUS_INVISIBLE_SLIP = 4,
};
enum status_blinker_id {
@ -2899,4 +2900,28 @@ enum movement_flag
MOVEMENT_FLAG_SWAPPING_PLACES_PETRIFIED_ALLY = 1 << 15, // Set if the Pokémon is petrified and the leader cures them by swapping places.
};
enum move_flag
{
MOVE_FLAG_EXISTS = 1 << 0,
MOVE_FLAG_SUBSEQUENT_IN_LINK_CHAIN = 1 << 1, // This move is linked with the previous move in the Pokémon's moveset.
MOVE_FLAG_ENABLED_FOR_AI = 1 << 2, // Enabled for the AI to use.
MOVE_FLAG_SET = 1 << 3, // This move can be triggered by pressing L+A instead of having to go to the move menu.
MOVE_FLAG_LAST_USED = 1 << 4, // The most recent move used by the Pokémon.
MOVE_FLAG_DISABLED = 1 << 5, // Disabled by an effect like Taunt.
MOVE_FLAG_INTERNAL_MARKER = 1 << 7 // Possibly some kind of flag used internally to mark a move and find it again
};
// Mobility types for monsters
enum mobility_type {
MOBILITY_NORMAL = 0,
// This is unused within the monster data in monster.md, but is probably used in dungeons
// with a meaning that's dependent on what the secondary terrain type is
// (either MOBILITY_LAVA or MOBILITY_WATER).
MOBILITY_SECONDARY = 1,
MOBILITY_HOVERING = 2,
MOBILITY_INTANGIBLE = 3,
MOBILITY_LAVA = 4,
MOBILITY_WATER = 5,
};
#endif //PMDSKY_ENUMS_H

View File

@ -34,4 +34,10 @@ struct fixed_point {
// Compares two numbers and return the minimum
#define MIN(A, B) ((A > B) ? B : A)
// Same as MIN macro but as a static inline, since the macro doesn't match in some places.
static inline s32 Min(s32 a, s32 b)
{
return a < b ? a : b;
}
#endif //PMDSKY_UTIL_H

View File

@ -370,6 +370,8 @@ Overlay OVY_29
Object asm/overlay_29_0231B33C.o
Object src/overlay_29_0231CBC8.o
Object asm/overlay_29_0231CBEC.o
Object src/dungeon_ai_item_weight.o
Object asm/overlay_29_0231E8F0.o
Object src/overlay_29_0231EDD8.o
Object asm/overlay_29_0231EDFC.o
Object src/overlay_29_0231F570.o

View File

@ -0,0 +1,370 @@
#include "dungeon_ai_item_weight.h"
#include "dungeon_pokemon_attributes_1.h"
#include "dungeon_statuses.h"
#include "dungeon_util_static.h"
#include "main_02054BE0.h"
#include "util.h"
extern s32 CeilFixedPoint(struct fixed_point val_fp);
extern bool8 IsAdjacentToEnemy(struct entity *entity);
extern u8 GetMaxPpWrapper(struct move *move);
extern bool8 MonsterHasNegativeStatus(struct entity *monster, bool8 check_held_item);
extern enum mobility_type GetMobilityType(s16 monster_id);
u32 GetAiUseItemProbability(struct entity *item_consumer, struct item *item, u32 flags)
{
u32 item_weight = 0;
struct monster *pokemon_info = GetEntInfo(item_consumer);
bool8 target_other = (flags & 1) != 0;
bool8 target_ally = (flags & 2) != 0;
switch (item->id)
{
case ITEM_STICK:
case ITEM_IRON_THORN:
case ITEM_SILVER_SPIKE:
case ITEM_GOLD_FANG:
case ITEM_CACNEA_SPIKE:
case ITEM_CORSOLA_TWIG:
case ITEM_GRAVELEROCK:
case ITEM_GEO_PEBBLE:
case ITEM_GOLD_THORN:
case ITEM_RARE_FOSSIL:
if (target_other)
item_weight = 70;
break;
case ITEM_DIET_RIBBON:
if (target_other && CeilFixedPoint(pokemon_info->belly) > 0)
return 50;
item_weight = 0;
break;
case ITEM_WHIFF_SPECS:
case ITEM_NO_AIM_SCOPE:
if (target_other)
return 50;
item_weight = 0;
break;
case ITEM_PATSY_BAND:
item_weight = 40;
break;
case ITEM_ORAN_BERRY:
case ITEM_SITRUS_BERRY:
s32 pokemon_max_hp = pokemon_info->max_hp_stat + pokemon_info->max_hp_boost;
if (pokemon_info->hp < Min(999, pokemon_max_hp) && pokemon_info->hp <= Min(999, pokemon_max_hp) / 4)
{
if (!target_other)
if (IsAdjacentToEnemy(item_consumer))
item_weight = 100;
else
item_weight = 50;
else
item_weight = 50;
}
break;
case ITEM_MIX_ELIXIR:
case ITEM_MAX_ELIXIR:
bool8 can_use_elixir = TRUE;
if (item->id == ITEM_MIX_ELIXIR && pokemon_info->apparent_id != MONSTER_LINOONE && pokemon_info->apparent_id != MONSTER_LINOONE_SECONDARY)
can_use_elixir = FALSE;
if (can_use_elixir)
{
item_weight = 0;
for (s32 i = 0; i < MAX_MON_MOVES; i++)
{
bool8 move_exists;
struct move *move = &pokemon_info->moves.moves[i];
if (move->flags0 & MOVE_FLAG_EXISTS)
move_exists = TRUE;
else
move_exists = FALSE;
if (move_exists)
{
if (move->pp == 0)
item_weight += 30;
if (move->pp != GetMaxPpWrapper(move))
item_weight += 6;
}
}
item_weight = Min(item_weight, 99);
}
break;
case ITEM_HEAL_SEED:
case ITEM_GABITE_SCALE:
if (MonsterHasNegativeStatus(item_consumer, TRUE))
item_weight = 80;
else
item_weight = 0;
break;
case ITEM_PROTEIN:
if (pokemon_info->offensive_stats[0] >= 250)
item_weight = 0;
else
item_weight = 100;
break;
case ITEM_CALCIUM:
if (pokemon_info->offensive_stats[1] >= 250)
item_weight = 0;
else
item_weight = 100;
break;
case ITEM_IRON:
if (pokemon_info->defensive_stats[0] >= 250)
item_weight = 0;
else
item_weight = 100;
break;
case ITEM_ZINC:
if (pokemon_info->defensive_stats[1] >= 250)
item_weight = 0;
else
item_weight = 100;
break;
case ITEM_LIFE_SEED:
if (target_other)
item_weight = 0;
else if (IsAdjacentToEnemy(item_consumer))
item_weight = 10;
else
item_weight = 100;
break;
case ITEM_EYEDROP_SEED:
if (CanSeeInvisibleMonsters(item_consumer))
return 0;
if (IsAdjacentToEnemy(item_consumer))
item_weight = 80;
else
item_weight = 5;
break;
case ITEM_QUICK_SEED:
if (GetEntInfo(item_consumer)->speed_stage > MAX_SPEED_STAGE - 1)
return 0;
if (IsAdjacentToEnemy(item_consumer))
item_weight = 80;
else
item_weight = 5;
break;
case ITEM_X_EYE_SEED:
if (pokemon_info->blinker_class_status.blinded == STATUS_BLINKER_CROSS_EYED)
return 0;
if (IsAdjacentToEnemy(item_consumer))
item_weight = 80;
else
item_weight = 5;
break;
case ITEM_CHERI_BERRY:
if (pokemon_info->burn_class_status.burn != STATUS_BURN_PARALYSIS)
return 0;
if (IsAdjacentToEnemy(item_consumer))
item_weight = 80;
else
item_weight = 30;
break;
case ITEM_TOTTER_SEED:
if (pokemon_info->cringe_class_status.cringe == STATUS_CRINGE_CONFUSED)
return 0;
if (IsAdjacentToEnemy(item_consumer))
item_weight = 80;
else
item_weight = 15;
break;
case ITEM_PECHA_BERRY:
if (!ENTITY_POISONED(pokemon_info))
return 0;
else if (IsAdjacentToEnemy(item_consumer))
item_weight = 100;
else
item_weight = 50;
break;
case ITEM_BLINKER_SEED:
if (IsBlinded(item_consumer, TRUE))
return 0;
if (IsAdjacentToEnemy(item_consumer))
item_weight = 80;
else
item_weight = 5;
break;
case ITEM_WARP_SEED:
if (!target_ally)
{
if (IsAdjacentToEnemy(item_consumer))
item_weight = 40;
else
item_weight = 5;
}
else
{
s32 pokemon_max_hp = pokemon_info->max_hp_stat + pokemon_info->max_hp_boost;
if (pokemon_info->hp < Min(999, pokemon_max_hp) && pokemon_info->hp < 20)
{
if (!target_other)
if (IsAdjacentToEnemy(item_consumer))
item_weight = 100;
else
item_weight = 50;
else
item_weight = 50;
}
}
break;
case ITEM_SLEEP_SEED:
if (pokemon_info->sleep_class_status.sleep == STATUS_SLEEP_SLEEP)
return 0;
if (pokemon_info->sleep_class_status.sleep == STATUS_SLEEP_NAPPING)
return 0;
if (pokemon_info->sleep_class_status.sleep == STATUS_SLEEP_NIGHTMARE)
return 0;
if (IsAdjacentToEnemy(item_consumer))
item_weight = 80;
else
item_weight = 5;
break;
case ITEM_CHESTO_BERRY:
if (pokemon_info->sleep_class_status.sleep == STATUS_SLEEPLESS)
return 0;
item_weight = 5;
break;
case ITEM_JOY_SEED:
if (pokemon_info->level < 99)
item_weight = 80;
else
item_weight = 0;
break;
case ITEM_GINSENG:
item_weight = 80;
break;
case ITEM_RAWST_BERRY:
if (pokemon_info->burn_class_status.burn == STATUS_BURN_BURN)
return 50;
item_weight = 0;
break;
case ITEM_HUNGER_SEED:
if (CeilFixedPoint(pokemon_info->belly) > 0)
return 50;
item_weight = 0;
break;
case ITEM_DOOM_SEED:
if (pokemon_info->level > 1)
item_weight = 80;
else
item_weight = 0;
break;
case ITEM_STUN_SEED:
if (pokemon_info->frozen_class_status.freeze == STATUS_FROZEN_PETRIFIED)
return 0;
if (IsAdjacentToEnemy(item_consumer))
item_weight = 80;
else
item_weight = 5;
break;
case ITEM_BLAST_SEED:
if (IsAdjacentToEnemy(item_consumer))
item_weight = 80;
else
item_weight = 30;
break;
case ITEM_DOUGH_SEED:
if (pokemon_info->is_not_team_member)
item_weight = 0;
else
item_weight = 100;
break;
case ITEM_SLIP_SEED:
enum mobility_type mobility_type = GetMobilityType(pokemon_info->id);
bool8 can_use_slip_seed = mobility_type == MOBILITY_NORMAL || mobility_type == MOBILITY_LAVA;
if (!can_use_slip_seed || pokemon_info->invisible_class_status.status == STATUS_INVISIBLE_SLIP)
item_weight = 0;
else if (IsAdjacentToEnemy(item_consumer))
item_weight = 10;
else
item_weight = 100;
break;
case ITEM_GONE_PEBBLE:
if (pokemon_info->reflect_class_status.reflect == STATUS_REFLECT_ENDURING)
item_weight = 0;
else if (IsAdjacentToEnemy(item_consumer))
item_weight = 80;
else
item_weight = 0;
break;
case ITEM_VILE_SEED:
if (target_other)
item_weight = 70;
else
item_weight = 0;
break;
case ITEM_VIOLENT_SEED:
if (pokemon_info->stat_modifiers.offensive_stages[1] >= 20)
item_weight = 0;
else
item_weight = 80;
break;
case ITEM_VANISH_SEED:
if (pokemon_info->invisible_class_status.status != STATUS_INVISIBLE_INVISIBLE)
item_weight = 80;
else
item_weight = 0;
break;
case ITEM_GRAVELYROCK:
// BUG: FemaleToMaleForm is called, but the return value isn't used.
// This means the AI only uses Gravelyrocks on male Bonsly/Sudowoodo, ignoring female ones.
FemaleToMaleForm(pokemon_info->apparent_id);
if (pokemon_info->apparent_id == MONSTER_BONSLY || pokemon_info->apparent_id == MONSTER_SUDOWOODO)
{
if (target_other)
item_weight = 70;
else
item_weight = 100;
}
break;
case ITEM_APPLE:
case ITEM_BIG_APPLE:
case ITEM_HUGE_APPLE:
if (CeilFixedPoint(pokemon_info->belly) < 10)
return 100;
item_weight = 0;
break;
case ITEM_GRIMY_FOOD:
item_weight = 30;
break;
case ITEM_ROLLCALL_ORB:
if (target_other)
item_weight = 0;
else
item_weight = 20;
break;
case ITEM_Y_RAY_SPECS:
case ITEM_GAGGLE_SPECS:
case ITEM_VIA_SEED:
case ITEM_OREN_BERRY:
case ITEM_WANDER_GUMMI:
if (target_other)
item_weight = 80;
else
item_weight = 0;
break;
case ITEM_DROPEYE_SEED:
if (pokemon_info->blinker_class_status.blinded != STATUS_BLINKER_DROPEYE)
{
if (target_other)
item_weight = 80;
else
item_weight = 0;
}
break;
default:
item_weight = 0;
break;
}
return item_weight;
}

View File

@ -1,6 +1,7 @@
#include "dungeon_ai_items.h"
#include "dg_random.h"
#include "direction.h"
#include "dungeon_ai_item_weight.h"
#include "dungeon_ai_items_1.h"
#include "dungeon_capabilities_1.h"
#include "dungeon_map_access.h"
@ -24,7 +25,6 @@ extern bool8 TestItemAiFlag(s16 item_id, s32 flag);
extern void GetPossibleAiArcItemTargets(struct entity *user, struct item *item, struct position positions[], bool8 always_add_position);
extern s32 GetDirectionTowardsPosition(struct position *origin, struct position *target);
extern struct item *GetItemInfo(struct entity *item_entity);
extern u32 GetAiUseItemProbability(struct entity *item_consumer, struct item *item, u32 flags);
extern bool8 MonsterCanThrowItems(struct monster *monster);
bool8 EntityIsValid__0230E8F0(struct entity *entity)

View File

@ -2,6 +2,7 @@
#include "dungeon.h"
#include "dungeon_ai_attack.h"
#include "dungeon_ai_attack_1.h"
#include "dungeon_ai_item_weight.h"
#include "dungeon_ai_items.h"
#include "dungeon_ai_targeting_1.h"
#include "dungeon_util_static.h"
@ -16,8 +17,6 @@
extern s32 AI_THROWN_ITEM_ACTION_CHOICE_COUNT;
extern struct dungeon *DUNGEON_PTR[];
extern u32 GetAiUseItemProbability(struct entity *item_consumer, struct item *item, u32 flags);
void GetPossibleAiThrownItemDirections(struct entity *entity, s32 ally_or_enemy, struct item *item, bool8 always_add)
{
AI_THROWN_ITEM_ACTION_CHOICE_COUNT = 0;