From b943da1fd12ad59c5f482defb50532595035998d Mon Sep 17 00:00:00 2001 From: AnonymousRandomPerson Date: Mon, 15 Sep 2025 22:00:19 -0400 Subject: [PATCH 1/2] Decomped GetMoveType --- .../{main_02013864.inc => main_02013884.inc} | 0 asm/{main_02013864.s => main_02013884.s} | 15 +-------------- include/move_data.h | 2 +- include/moves_2.h | 2 ++ main.lsf | 2 +- src/dungeon_logic_5.c | 3 +-- src/moves_2.c | 5 +++++ 7 files changed, 11 insertions(+), 18 deletions(-) rename asm/include/{main_02013864.inc => main_02013884.inc} (100%) rename asm/{main_02013864.s => main_02013884.s} (91%) diff --git a/asm/include/main_02013864.inc b/asm/include/main_02013884.inc similarity index 100% rename from asm/include/main_02013864.inc rename to asm/include/main_02013884.inc diff --git a/asm/main_02013864.s b/asm/main_02013884.s similarity index 91% rename from asm/main_02013864.s rename to asm/main_02013884.s index c5c2589c..e57c334d 100644 --- a/asm/main_02013864.s +++ b/asm/main_02013884.s @@ -1,21 +1,8 @@ .include "asm/macros.inc" - .include "main_02013864.inc" + .include "main_02013884.inc" .text - arm_func_start GetMoveType -GetMoveType: ; 0x02013864 - ldr r1, _02013880 ; =DUNGEON_MOVE_TABLES - ldrh r2, [r0, #4] - ldr r1, [r1, #8] - mov r0, #0x1a - mla r0, r2, r0, r1 - ldrb r0, [r0, #2] - bx lr - .align 2, 0 -_02013880: .word DUNGEON_MOVE_TABLES - arm_func_end GetMoveType - arm_func_start GetMovesetLevelUpPtr GetMovesetLevelUpPtr: ; 0x02013884 stmdb sp!, {r4, lr} diff --git a/include/move_data.h b/include/move_data.h index eaaae9ef..47c5530b 100644 --- a/include/move_data.h +++ b/include/move_data.h @@ -72,7 +72,7 @@ enum accuracy_type struct move_data { u16 base_power; // 0x0 - u8 type; // 0x2 + enum type_id type; // 0x2 u8 category; // 0x3 u16 target_range[2]; // 0x4 u8 pp; // 0x8 diff --git a/include/moves_2.h b/include/moves_2.h index 4d319c53..4d348057 100644 --- a/include/moves_2.h +++ b/include/moves_2.h @@ -6,5 +6,7 @@ // Gets the move target-and-range field. s16 GetMoveTargetAndRange(struct move *move, bool8 is_ai); +// Gets the type of a move +enum type_id GetMoveType(struct move* move); #endif //PMDSKY_MOVES_2_H diff --git a/main.lsf b/main.lsf index a44b19fa..3cd5afec 100644 --- a/main.lsf +++ b/main.lsf @@ -40,7 +40,7 @@ Static main Object src/moves_1.o Object asm/main_020137E8.o Object src/moves_2.o - Object asm/main_02013864.o + Object asm/main_02013884.o Object src/moves_4.o Object asm/main_02013A30.o Object src/moves.o diff --git a/src/dungeon_logic_5.c b/src/dungeon_logic_5.c index fd45f6ca..0cd0b12d 100644 --- a/src/dungeon_logic_5.c +++ b/src/dungeon_logic_5.c @@ -2,12 +2,11 @@ #include "dungeon_pokemon_attributes.h" #include "dungeon_util_static.h" #include "main_02014CEC.h" +#include "moves_2.h" #include "natural_gift_data.h" #include "overlay_29_023000E4.h" #include "special_move_types.h" -extern enum type_id GetMoveType(struct move* move); - enum type_id GetMoveTypeForMonster(struct entity *entity, struct move *move) { if (!IsRegularAttackOrProjectile(move->id) && EntityIsValid__023000E4(entity) && AbilityIsActive(entity, ABILITY_NORMALIZE)) diff --git a/src/moves_2.c b/src/moves_2.c index 6926ee2c..9d001189 100644 --- a/src/moves_2.c +++ b/src/moves_2.c @@ -7,3 +7,8 @@ s16 GetMoveTargetAndRange(struct move *move, bool8 is_ai) { return DUNGEON_MOVE_TABLES.moves->moves[move->id].target_range[is_ai]; } + +enum type_id GetMoveType(struct move* move) +{ + return DUNGEON_MOVE_TABLES.moves->moves[move->id].type; +} From 9d3691f857537877c11a91d2788b94abd2b2fb2f Mon Sep 17 00:00:00 2001 From: AnonymousRandomPerson Date: Tue, 16 Sep 2025 00:41:33 -0400 Subject: [PATCH 2/2] Decomped WeightWeakTypePicker --- ...9_0231A364.inc => overlay_29_0231A460.inc} | 6 +- asm/overlay_29_0230AA0C.s | 6 +- ...ay_29_0231A364.s => overlay_29_0231A460.s} | 78 +------------------ include/dungeon.h | 15 ++-- include/dungeon_ai_attack.h | 2 + include/enums.h | 3 +- main.lsf | 2 +- src/dungeon_ai_attack.c | 36 ++++++++- 8 files changed, 52 insertions(+), 96 deletions(-) rename asm/include/{overlay_29_0231A364.inc => overlay_29_0231A460.inc} (64%) rename asm/{overlay_29_0231A364.s => overlay_29_0231A460.s} (65%) diff --git a/asm/include/overlay_29_0231A364.inc b/asm/include/overlay_29_0231A460.inc similarity index 64% rename from asm/include/overlay_29_0231A364.inc rename to asm/include/overlay_29_0231A460.inc index d189f0b8..6971562e 100644 --- a/asm/include/overlay_29_0231A364.inc +++ b/asm/include/overlay_29_0231A460.inc @@ -1,14 +1,10 @@ #pragma once -.public _s32_div_f -.public AbilityIsActiveVeneer .public CanAttackInDirection .public DIRECTIONS_XY -.public DUNGEON_PTR .public DungeonRandInt .public GetTile .public GetTreatmentBetweenMonsters -.public HasHeldItem .public IqSkillIsEnabled .public IsBlinded -.public ov29_0230B7D4 +.public WeightMoveWithIqSkills .public ov29_0230F8D0 diff --git a/asm/overlay_29_0230AA0C.s b/asm/overlay_29_0230AA0C.s index 1de9a59a..123fce70 100644 --- a/asm/overlay_29_0230AA0C.s +++ b/asm/overlay_29_0230AA0C.s @@ -1022,8 +1022,8 @@ _0230B7CC: .word BURN_DAMAGE_MULTIPLIER _0230B7D0: .word CLOUDY_DAMAGE_MULTIPLIER arm_func_end CalcTypeBasedDamageEffects - arm_func_start ov29_0230B7D4 -ov29_0230B7D4: ; 0x0230B7D4 + arm_func_start WeightWeakTypePicker +WeightWeakTypePicker: ; 0x0230B7D4 stmdb sp!, {r4, r5, r6, r7, r8, sb, sl, fp, lr} sub sp, sp, #0x24 mov sb, r1 @@ -1305,7 +1305,7 @@ _0230BB98: _0230BBA0: .word ov29_02352884 _0230BBA4: .word DUNGEON_PTR _0230BBA8: .word 0x000003E7 - arm_func_end ov29_0230B7D4 + arm_func_end WeightWeakTypePicker arm_func_start CalcDamage CalcDamage: ; 0x0230BBAC diff --git a/asm/overlay_29_0231A364.s b/asm/overlay_29_0231A460.s similarity index 65% rename from asm/overlay_29_0231A364.s rename to asm/overlay_29_0231A460.s index d37d8bde..ab322aa7 100644 --- a/asm/overlay_29_0231A364.s +++ b/asm/overlay_29_0231A460.s @@ -1,84 +1,8 @@ .include "asm/macros.inc" - .include "overlay_29_0231A364.inc" + .include "overlay_29_0231A460.inc" .text - arm_func_start WeightMoveWithIqSkills -WeightMoveWithIqSkills: ; 0x0231A364 - stmdb sp!, {r3, r4, r5, r6, r7, r8, sb, lr} - mov r7, r2 - mov sb, r0 - mov r8, r1 - mov r0, r7 - mov r1, #0x6f - mov r6, r3 - ldr r5, [r7, #0xb4] - mov r4, #1 - bl AbilityIsActiveVeneer - cmp r0, #0 - movne r0, #0 - bne _0231A3A4 - mov r0, r7 - mov r1, #0xf - bl HasHeldItem -_0231A3A4: - cmp r0, #0 - movne r0, #0x1f4 - ldmneia sp!, {r3, r4, r5, r6, r7, r8, sb, pc} - ldrb r0, [r5, #6] - cmp r0, #0 - moveq r0, #1 - ldmeqia sp!, {r3, r4, r5, r6, r7, r8, sb, pc} - tst r8, #0xf - movne r0, #1 - ldmneia sp!, {r3, r4, r5, r6, r7, r8, sb, pc} - mov r0, sb - mov r1, #9 - bl IqSkillIsEnabled - cmp r0, #0 - beq _0231A404 - ldrsh r0, [r5, #2] - mov r1, #0x258 - bl _s32_div_f - ldr r0, _0231A45C ; =DUNGEON_PTR - ldr r0, [r0] - add r0, r0, r1 - add r0, r0, #0x3000 -#ifdef JAPAN - ldrb r4, [r0, #0xb24] -#else - ldrb r4, [r0, #0xb74] -#endif - b _0231A454 -_0231A404: - mov r0, sb - mov r1, #0xa - bl IqSkillIsEnabled - cmp r0, #0 - beq _0231A42C - ldrsh r0, [r5, #0x10] - rsb r4, r0, #0x1f4 - cmp r4, #1 - movlt r4, #1 - b _0231A454 -_0231A42C: - mov r0, sb - mov r1, #0xb - bl IqSkillIsEnabled - cmp r0, #0 - beq _0231A454 - mov r0, sb - mov r1, r7 - mov r2, r6 - bl ov29_0230B7D4 - add r4, r0, #1 -_0231A454: - mov r0, r4 - ldmia sp!, {r3, r4, r5, r6, r7, r8, sb, pc} - .align 2, 0 -_0231A45C: .word DUNGEON_PTR - arm_func_end WeightMoveWithIqSkills - arm_func_start TargetRegularAttack TargetRegularAttack: ; 0x0231A460 stmdb sp!, {r3, r4, r5, r6, r7, r8, sb, sl, fp, lr} diff --git a/include/dungeon.h b/include/dungeon.h index f676c46b..469f55a2 100644 --- a/include/dungeon.h +++ b/include/dungeon.h @@ -1069,10 +1069,6 @@ struct dungeon { u8 field_0x3b1c; u8 field_0x3b1d; u8 field_0x3b1e; - // TODO Something is omitted from the dungeon struct in JP, but it is not known what is missing. - // For the time being, take out these unknown fields from JP to allow JP usage of this struct to match. - // As more functions are decomped, move this conditional up the struct until we find where the actual difference is in the struct. -#ifndef JAPAN u8 field_0x3b1f; u8 field_0x3b20; u8 field_0x3b21; @@ -1158,16 +1154,19 @@ struct dungeon { u8 field_0x3b71; u8 field_0x3b72; u8 field_0x3b73; -#endif - // 0x3B74: Unknown array, likely one entry per monster species. This might be related to - // the IQ skill Exp. Go-Getter so the AI knows which monsters to prioritize. - u8 unknown_array_0x3B74[600]; + // 0x3B74: An array containing rankings of Pokémon species by their exp. yield, indexed by Pokémon species ID. + // This is used by the IQ skill Exp. Go-Getter so the AI knows which monsters to prioritize. + // The species with the highest exp. yield on the floor has the value 0xFF, second-highest has 0xFE, and so on. + // Species not on the floor have the value 1. + u8 exp_yield_rankings[NUM_SPECIES]; +#ifndef JAPAN // 0x3DCC: Appears to be a table that holds the statuses::statuses_unique_id value for // the monsters. Maybe just for convenience to avoid loading it from every monster? u32 monster_unique_id[20]; // 0x3E1C: Appears to be be an index inside or length for // dungeon::active_monsters_unique_statuses_ids. u32 unique_id_index; +#endif // 0x3E20: Number of valid monster spawn entries (see spawn_entries). int monster_spawn_entries_length; u8 field_0x3e24; diff --git a/include/dungeon_ai_attack.h b/include/dungeon_ai_attack.h index 64977477..5ec90007 100644 --- a/include/dungeon_ai_attack.h +++ b/include/dungeon_ai_attack.h @@ -42,5 +42,7 @@ s32 TryAddTargetToAiTargetList(s32 current_num_targets, s32 move_ai_range, struc // check_all_conditions True to check all the possible move_ai_condition values, false to only check for move_ai_condition::AI_CONDITION_RANDOM (if the move has a different ai condition, the result will be false). // return: True if the target is eligible, false otherwise bool8 IsAiTargetEligible(s32 move_ai_range, struct entity *user, struct entity *target, struct move *move, bool8 check_all_conditions); +// Calculates a move weight used for deciding which target the move should be used on. If the user is an ally, the target is an enemy Pokémon, and the user has Exp. Go-Getter, Efficiency Expert, or Weak-Type Picker enabled, this function calculates a move weight based on that IQ skill's functionality. Otherwise, this function returns a weight of 1. +s32 WeightMoveWithIqSkills(struct entity *user, s32 move_ai_range, struct entity *target, enum type_id move_type); #endif //PMDSKY_DUNGEON_AI_ATTACK_H diff --git a/include/enums.h b/include/enums.h index fba9444b..b73a5ee1 100644 --- a/include/enums.h +++ b/include/enums.h @@ -1172,7 +1172,8 @@ enum shopkeeper_mode { SHOPKEEPER_MODE_ATTACK_TEAM = 3, }; -#define MONSTER_GENDER_ID_OFFSET 600 +#define NUM_SPECIES 600 +#define MONSTER_GENDER_ID_OFFSET NUM_SPECIES // Some macro shenanigans to define the monster secondary gender labels neatly. #define _MONSTER_ID_GENDERED(name, base_value) \ diff --git a/main.lsf b/main.lsf index 3cd5afec..2aa55c9e 100644 --- a/main.lsf +++ b/main.lsf @@ -501,7 +501,7 @@ Overlay OVY_29 Object asm/overlay_29_02318E70.o Object src/inflict_status.o Object src/dungeon_ai_attack.o - Object asm/overlay_29_0231A364.o + Object asm/overlay_29_0231A460.o Object src/dungeon_ai_attack_1.o Object asm/overlay_29_0231A7A0.o Object src/overlay_29_0231A87C.o diff --git a/src/dungeon_ai_attack.c b/src/dungeon_ai_attack.c index cc00432c..6f5bbc89 100644 --- a/src/dungeon_ai_attack.c +++ b/src/dungeon_ai_attack.c @@ -4,10 +4,12 @@ #include "dungeon_ai_targeting_1.h" #include "dungeon_capabilities.h" #include "dungeon_capabilities_4.h" +#include "dungeon_items.h" #include "dungeon_logic.h" #include "dungeon_logic_4.h" #include "dungeon_logic_5.h" #include "dungeon_map_access.h" +#include "dungeon_pokemon_attributes.h" #include "dungeon_pokemon_attributes_1.h" #include "dungeon_statuses.h" #include "dungeon_util.h" @@ -27,7 +29,7 @@ extern u8 AI_POTENTIAL_ATTACK_TARGET_DIRECTIONS[NUM_DIRECTIONS]; extern s32 AI_POTENTIAL_ATTACK_TARGET_WEIGHTS[NUM_DIRECTIONS]; extern struct entity *AI_POTENTIAL_ATTACK_TARGETS[NUM_DIRECTIONS]; -extern s32 WeightMoveWithIqSkills(struct entity *user, s32 move_ai_range, struct entity *target, enum type_id move_type); +extern s32 WeightWeakTypePicker(struct entity *user, struct entity *target, enum type_id move_type); void ResetAiCanAttackInDirection() { @@ -895,3 +897,35 @@ bool8 IsAiTargetEligible(s32 move_ai_range, struct entity *user, struct entity * } return has_target; } + +s32 WeightMoveWithIqSkills(struct entity *user, s32 move_ai_range, struct entity *target, enum type_id move_type) +{ + struct monster *target_data = GetEntInfo(target); + s32 weight = 1; + bool8 has_gaggle_specs; + if (AbilityIsActiveVeneer(target, ABILITY_KLUTZ)) + has_gaggle_specs = FALSE; + else + has_gaggle_specs = HasHeldItem(target, ITEM_GAGGLE_SPECS); + + if (has_gaggle_specs) + return 500; + + if (!target_data->is_not_team_member) + return 1; + + if ((move_ai_range & 0xF) != RANGE_FRONT) + return 1; + + if (IqSkillIsEnabled(user, IQ_EXP_GO_GETTER)) + weight = DUNGEON_PTR[0]->exp_yield_rankings[target_data->id % NUM_SPECIES]; + else if (IqSkillIsEnabled(user, IQ_EFFICIENCY_EXPERT)) + { + weight = 500 - target_data->hp; + if (weight < 1) + weight = 1; + } else if (IqSkillIsEnabled(user, IQ_WEAK_TYPE_PICKER)) + weight = WeightWeakTypePicker(user, target, move_type) + 1; + + return weight; +}