From 580644e6465e927e151de16fe42d31c6f77f1ffa Mon Sep 17 00:00:00 2001 From: cecilarmitais Date: Wed, 22 Jul 2026 14:26:26 -0700 Subject: [PATCH] Decomp sub_02065050; make two script-entity fields signed Decompile sub_02065050 (0x02065050), the resolver that rewrites a script entity id in place and reports which storage it maps to. It redirects the four special ids 0x2E-0x31 through SPECIAL_ACTORS, then dispatches on the entity's kind field: kind 1 resolves the player slot from script variable 0x34, kind 2 resolves a team member from variables 0x35 and 0x36, kind 3 range-checks against the loaded unit or adventure NPC list, and anything else handles the appointed leader. It merges into src/main_02064FFC.c; asm/main_02065050.s splits, with sub_0206549C moving verbatim into asm/main_0206549C.s. Two type declarations are corrected, both diagnosed from the load instruction rather than assumed. Storing to a field cannot reveal its signedness -- strh is the same either way -- so neither error was observable until something read these fields, and this is the first decompiled function that does. enum script_entity_id gains ENTITY_NONE = -1. Under -enum min an enum with no negative enumerator is unsigned, so the SPECIAL_ACTORS redirect slots compiled to ldrh where the target has ldrsh. An explicit (s16) cast does not help: the destination store is 16-bit, so the compiler folds the conversion away. The name follows EPISODE_NONE = -1, already in this file. The sentinel was verified in isolation, with no other change in the tree, and the ROM still matches -- it is byte-neutral everywhere else and only affects code that reads such a field. struct unk_020A7FF0 field_0x0 becomes s16 for the same reason. It was declared u16 when the struct was introduced for sub_02065B14, which only reads field_0x8 -- genuinely unsigned, ldrh. Both resolvers read field_0x0 with ldrsh. sub_02055410 is declared as taking the member index rather than void. The argument is already in r0 from GetAppointedLeaderMemberIdx, so the call needs no register move, which is what leaves r0 occupied across the sentinel comparison. Declared void, the function is otherwise identical but allocates that constant to r0 instead of r1. The nine functions this calls that had no declaration are declared alongside; parameter names are positional where only the call site is understood. No comments are added to any pmd-sky file. Authored by Claude (Opus 4.8) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 4.8 --- .../{main_02065050.inc => main_0206549C.inc} | 7 +- asm/{main_02065050.s => main_0206549C.s} | 316 +----------------- include/enums.h | 1 + include/main_02064FFC.h | 12 + include/main_02065B3C.h | 2 +- main.lsf | 2 +- src/main_02064FFC.c | 192 +++++++++++ 7 files changed, 209 insertions(+), 323 deletions(-) rename asm/include/{main_02065050.inc => main_0206549C.inc} (70%) rename asm/{main_02065050.s => main_0206549C.s} (53%) diff --git a/asm/include/main_02065050.inc b/asm/include/main_0206549C.inc similarity index 70% rename from asm/include/main_02065050.inc rename to asm/include/main_0206549C.inc index 86502b51..7afbe2c0 100644 --- a/asm/include/main_02065050.inc +++ b/asm/include/main_0206549C.inc @@ -3,12 +3,9 @@ .public Debug_GetDebugFlag .public ENTITIES .public GetAdventureNpcIds -.public GetAppointedLeaderMemberIdx .public GetHero .public GetMainCharacter1 -.public GetMainCharacter1MemberIdx .public GetMainCharacter2 -.public GetMainCharacter2MemberIdx .public GetMainCharacter3 .public GetPartner .public GetUnitNpcIds @@ -17,7 +14,5 @@ .public SPECIAL_ACTORS .public TEAM_MEMBER_TABLE_PTR .public ov11_022E96E4 -.public sub_02055410 -.public sub_02055474 -.public sub_020554D8 .public sub_02056914 +.public sub_02065050 diff --git a/asm/main_02065050.s b/asm/main_0206549C.s similarity index 53% rename from asm/main_02065050.s rename to asm/main_0206549C.s index d212d7d6..63aacf89 100644 --- a/asm/main_02065050.s +++ b/asm/main_0206549C.s @@ -1,322 +1,8 @@ .include "asm/macros.inc" - .include "main_02065050.inc" + .include "main_0206549C.inc" .text - arm_func_start sub_02065050 -sub_02065050: ; 0x02065050 - stmdb sp!, {r4, r5, r6, lr} - sub sp, sp, #0x10 - mov r5, r0 - ldrsh r0, [r5] - mvn r4, #0 - cmp r0, #0x2e - ldreq r0, _02065494 ; =SPECIAL_ACTORS - ldreqsh r0, [r0, #0x18] - streqh r0, [r5] - beq _020650B0 - cmp r0, #0x2f - ldreq r0, _02065494 ; =SPECIAL_ACTORS - ldreqsh r0, [r0, #0x16] - streqh r0, [r5] - beq _020650B0 - cmp r0, #0x30 - ldreq r0, _02065494 ; =SPECIAL_ACTORS - ldreqsh r0, [r0, #0x14] - streqh r0, [r5] - beq _020650B0 - cmp r0, #0x31 - ldreq r0, _02065494 ; =SPECIAL_ACTORS - ldreqsh r0, [r0, #0x12] - streqh r0, [r5] -_020650B0: - ldrsh r2, [r5] - mvn r0, #0 - cmp r2, r0 - beq _0206548C - mov r0, #0xc - smulbb r1, r2, r0 - ldr r0, _02065498 ; =ENTITIES - ldrsh r0, [r0, r1] - cmp r0, #1 - bne _020651AC - cmp r2, #0 - bne _020651A4 - mov r0, #0 - mov r1, #0x34 - bl LoadScriptVariableValue - cmp r0, #8 - addls pc, pc, r0, lsl #2 - b _02065198 -_020650F8: ; jump table - b _0206511C ; case 0 - b _02065128 ; case 1 - b _02065198 ; case 2 - b _02065134 ; case 3 - b _02065180 ; case 4 - b _02065180 ; case 5 - b _02065180 ; case 6 - b _02065180 ; case 7 - b _02065180 ; case 8 -_0206511C: - mov r0, #1 - strh r0, [r5] - b _020651A4 -_02065128: - mov r0, #2 - strh r0, [r5] - b _020651A4 -_02065134: - bl GetAppointedLeaderMemberIdx - mov r4, r0 - mvn r0, #0 - cmp r4, r0 - moveq r0, #1 - streqh r0, [r5] - beq _020651A4 - bl GetMainCharacter1MemberIdx - cmp r4, r0 - moveq r0, #1 - streqh r0, [r5] - beq _020651A4 - bl GetMainCharacter2MemberIdx - cmp r4, r0 - moveq r0, #2 - streqh r0, [r5] - movne r0, #4 - strneh r0, [r5] - b _020651A4 -_02065180: - mov r0, #0 - mov r1, #0x34 - bl LoadScriptVariableValue - add r0, r0, #1 - strh r0, [r5] - b _020651A4 -_02065198: - mvn r0, #0 - strh r0, [r5] - b _0206548C -_020651A4: - mov r4, #0 - b _02065488 -_020651AC: - cmp r0, #2 - bne _02065330 - mov r0, #0 - mov r1, #0x35 - bl LoadScriptVariableValue - mov r4, r0 - mov r0, #0 - mov r1, #0x36 - bl LoadScriptVariableValue - ldrsh r2, [r5] - sub r1, r2, #0xa - mov r1, r1, lsl #0x10 - mov r1, r1, asr #0x10 - mov r1, r1, lsl #0x10 - mov r1, r1, lsr #0x10 - cmp r1, #1 - bhi _020652D0 - cmp r2, #0xa - bne _02065204 - cmp r4, #0 - moveq r4, r0 - b _02065210 -_02065204: - cmp r4, #0 - moveq r0, #0 - mov r4, r0 -_02065210: - cmp r4, #0xa - addls pc, pc, r4, lsl #2 - b _020652C4 -_0206521C: ; jump table - b _020652C4 ; case 0 - b _02065248 ; case 1 - b _02065254 ; case 2 - b _020652C4 ; case 3 - b _02065260 ; case 4 - b _020652AC ; case 5 - b _020652AC ; case 6 - b _020652AC ; case 7 - b _020652AC ; case 8 - b _020652AC ; case 9 - b _020652B8 ; case 10 -_02065248: - mov r0, #0xc - strh r0, [r5] - b _020652D0 -_02065254: - mov r0, #0xd - strh r0, [r5] - b _020652D0 -_02065260: - bl GetAppointedLeaderMemberIdx - mov r4, r0 - mvn r0, #0 - cmp r4, r0 - moveq r0, #0xc - streqh r0, [r5] - beq _020652D0 - bl GetMainCharacter1MemberIdx - cmp r4, r0 - moveq r0, #0xc - streqh r0, [r5] - beq _020652D0 - bl GetMainCharacter2MemberIdx - cmp r4, r0 - moveq r0, #0xd - streqh r0, [r5] - movne r0, #0xf - strneh r0, [r5] - b _020652D0 -_020652AC: - add r0, r4, #0xb - strh r0, [r5] - b _020652D0 -_020652B8: - mov r0, #0x15 - strh r0, [r5] - b _020652D0 -_020652C4: - mvn r0, #0 - strh r0, [r5] - b _0206548C -_020652D0: - ldrsh r0, [r5] - sub r0, r0, #0xc - cmp r0, #9 - addls pc, pc, r0, lsl #2 - b _02065324 -_020652E4: ; jump table - b _0206530C ; case 0 - b _02065314 ; case 1 - b _02065324 ; case 2 - b _0206531C ; case 3 - b _02065324 ; case 4 - b _02065324 ; case 5 - b _02065324 ; case 6 - b _02065324 ; case 7 - b _02065324 ; case 8 - b _0206531C ; case 9 -_0206530C: - mov r4, #2 - b _02065488 -_02065314: - mov r4, #1 - b _02065488 -_0206531C: - mov r4, #2 - b _02065488 -_02065324: - mvn r0, #0 - strh r0, [r5] - b _0206548C -_02065330: - cmp r0, #3 - bne _02065420 - cmp r2, #0x16 - blt _020653A8 - cmp r2, #0x19 - bgt _020653A8 - mov r0, #0xd - sub r4, r2, #0x16 - bl OverlayIsLoaded - cmp r0, #0 - beq _0206536C - bl ov11_022E96E4 - cmp r0, #0 - mvnne r0, #0 - bne _0206548C -_0206536C: - mov r0, #5 - bl Debug_GetDebugFlag - cmp r0, #0 - beq _02065390 - ldrsh r0, [r5] - cmp r0, #0x17 - bgt _02065414 - mvn r0, #0 - b _0206548C -_02065390: - add r0, sp, #8 - bl GetUnitNpcIds - cmp r4, r0 - bge _02065414 - mvn r0, #0 - b _0206548C -_020653A8: - cmp r2, #0x1a - blt _02065414 - cmp r2, #0x1d - bgt _02065414 - mov r0, #0xd - sub r4, r2, #0x1a - bl OverlayIsLoaded - cmp r0, #0 - beq _020653DC - bl ov11_022E96E4 - cmp r0, #0 - mvnne r0, #0 - bne _0206548C -_020653DC: - mov r0, #5 - bl Debug_GetDebugFlag - cmp r0, #0 - beq _02065400 - ldrsh r0, [r5] - cmp r0, #0x1c - bgt _02065414 - mvn r0, #0 - b _0206548C -_02065400: - add r0, sp, #0 - bl GetAdventureNpcIds - cmp r4, r0 - mvnlt r0, #0 - blt _0206548C -_02065414: - mvn r0, #0 - strh r0, [r5] - b _0206548C -_02065420: - bl GetAppointedLeaderMemberIdx - ldrsh r1, [r5] - mov r6, r0 - cmp r1, #0x3f - bne _02065488 - mvn r1, #0 - cmp r6, r1 - moveq r0, #0x3c - streqh r0, [r5] - beq _02065488 - bl sub_02055410 - cmp r0, #0 - movne r0, #0x3c - strneh r0, [r5] - bne _02065488 - mov r0, r6 - bl sub_02055474 - cmp r0, #0 - movne r0, #0x3d - strneh r0, [r5] - bne _02065488 - mov r0, r6 - bl sub_020554D8 - cmp r0, #0 - movne r0, #0x3e - strneh r0, [r5] -_02065488: - mov r0, r4 -_0206548C: - add sp, sp, #0x10 - ldmia sp!, {r4, r5, r6, pc} - .align 2, 0 -_02065494: .word SPECIAL_ACTORS -_02065498: .word ENTITIES - arm_func_end sub_02065050 - arm_func_start sub_0206549C sub_0206549C: ; 0x0206549C stmdb sp!, {r4, r5, r6, lr} diff --git a/include/enums.h b/include/enums.h index 117eb2e2..40e427c4 100644 --- a/include/enums.h +++ b/include/enums.h @@ -2017,6 +2017,7 @@ enum monster_id { // Script entity IDs. While a few script entities differ between versions, the IDs are the same. enum script_entity_id { + ENTITY_NONE = -1, ENTITY_PLAYER = 0, ENTITY_PLAYER_HERO = 1, ENTITY_PLAYER_PARTNER = 2, diff --git a/include/main_02064FFC.h b/include/main_02064FFC.h index 1959f51d..d3ede26a 100644 --- a/include/main_02064FFC.h +++ b/include/main_02064FFC.h @@ -25,9 +25,21 @@ extern u8 *_020AFC70; void sub_0201E380(u8* a, u32* b, s16 c, s16 d); +int GetAppointedLeaderMemberIdx(void); +int GetMainCharacter1MemberIdx(void); +int GetMainCharacter2MemberIdx(void); +int OverlayIsLoaded(s32 overlay_id); +int ov11_022E96E4(void); +int GetUnitNpcIds(void* buf); +int GetAdventureNpcIds(void* buf); +int sub_02055410(int a); +int sub_02055474(int a); +int sub_020554D8(int a); + void sub_02064F94(struct unk_02064F94* a, u32* data, int count); void sub_02064FE4(struct unk_02064F94* a, struct unk_02064FE4* b); char* sub_02064FFC(s16 id); int sub_02065014(s16 id); +int sub_02065050(s16* p); #endif diff --git a/include/main_02065B3C.h b/include/main_02065B3C.h index d4f0f430..473245a0 100644 --- a/include/main_02065B3C.h +++ b/include/main_02065B3C.h @@ -4,7 +4,7 @@ #include "enums.h" struct unk_020A7FF0 { - u16 field_0x0; + s16 field_0x0; u16 field_0x2; char *field_0x4; u16 field_0x8; diff --git a/main.lsf b/main.lsf index d0bee830..6193e7de 100644 --- a/main.lsf +++ b/main.lsf @@ -213,7 +213,7 @@ Static main Object src/main_0205ED84.o Object asm/main_0205EDA4.o Object src/main_02064FFC.o - Object asm/main_02065050.o + Object asm/main_0206549C.o Object src/main_02065974.o Object asm/main_02065998.o Object src/main_02065B3C.o diff --git a/src/main_02064FFC.c b/src/main_02064FFC.c index d803727e..ca2637dd 100644 --- a/src/main_02064FFC.c +++ b/src/main_02064FFC.c @@ -1,4 +1,7 @@ #include "main_02064FFC.h" +#include "main_02065B3C.h" +#include "script_variable.h" +#include "debug.h" void sub_02064F94(struct unk_02064F94* a, u32* data, int count) { @@ -30,3 +33,192 @@ int sub_02065014(s16 id) } return 1; } + +int sub_02065050(s16* p) +{ + s16 id; + int ret; + int a; + int b; + int member; + u8 unit_buf[8]; + u8 adv_buf[8]; + + id = *p; + ret = -1; + + if (id == 0x2e) { + *p = SPECIAL_ACTORS.talk_main; + } else if (id == 0x2f) { + *p = SPECIAL_ACTORS.talk_sub; + } else if (id == 0x30) { + *p = SPECIAL_ACTORS.event_npc_main; + } else if (id == 0x31) { + *p = SPECIAL_ACTORS.event_npc_sub; + } + + id = *p; + if (id == -1) { + return -1; + } + + if (ENTITIES[id].field_0x0 == 1) { + if (id == 0) { + switch (LoadScriptVariableValue(0, 0x34)) { + case 0: + *p = 1; + break; + case 1: + *p = 2; + break; + case 3: + member = GetAppointedLeaderMemberIdx(); + if (member == -1) { + *p = 1; + break; + } + if (member == GetMainCharacter1MemberIdx()) { + *p = 1; + break; + } + if (member == GetMainCharacter2MemberIdx()) { + *p = 2; + } else { + *p = 4; + } + break; + case 4: + case 5: + case 6: + case 7: + case 8: + *p = LoadScriptVariableValue(0, 0x34) + 1; + break; + default: + *p = -1; + return -1; + } + } + ret = 0; + } else if (ENTITIES[id].field_0x0 == 2) { + a = LoadScriptVariableValue(0, 0x35); + b = LoadScriptVariableValue(0, 0x36); + id = *p; + if ((u16)(s16)(id - 0xa) <= 1) { + if (id == 0xa) { + if (a == 0) { + a = b; + } + } else { + if (a == 0) { + b = 0; + } + a = b; + } + switch (a) { + case 1: + *p = 0xc; + break; + case 2: + *p = 0xd; + break; + case 4: + member = GetAppointedLeaderMemberIdx(); + if (member == -1) { + *p = 0xc; + break; + } + if (member == GetMainCharacter1MemberIdx()) { + *p = 0xc; + break; + } + if (member == GetMainCharacter2MemberIdx()) { + *p = 0xd; + } else { + *p = 0xf; + } + break; + case 5: + case 6: + case 7: + case 8: + case 9: + *p = a + 0xb; + break; + case 10: + *p = 0x15; + break; + default: + *p = -1; + return -1; + } + } + switch (*p - 0xc) { + case 0: + ret = 2; + break; + case 1: + ret = 1; + break; + case 3: + case 9: + ret = 2; + break; + case 2: + case 4: + case 5: + case 6: + case 7: + case 8: + default: + *p = -1; + return -1; + } + } else if (ENTITIES[id].field_0x0 == 3) { + if (id >= 0x16 && id <= 0x19) { + member = id - 0x16; + if (OverlayIsLoaded(0xd)) { + if (ov11_022E96E4()) { + return -1; + } + } + if (Debug_GetDebugFlag(DEBUG_FLAG_STAGE_NPC_DUMMY)) { + if (*p <= 0x17) { + return -1; + } + } else if (member < GetUnitNpcIds(unit_buf)) { + return -1; + } + } else if (id >= 0x1a && id <= 0x1d) { + member = id - 0x1a; + if (OverlayIsLoaded(0xd)) { + if (ov11_022E96E4()) { + return -1; + } + } + if (Debug_GetDebugFlag(DEBUG_FLAG_STAGE_NPC_DUMMY)) { + if (*p <= 0x1c) { + return -1; + } + } else if (member < GetAdventureNpcIds(adv_buf)) { + return -1; + } + } + *p = -1; + return -1; + } else { + member = GetAppointedLeaderMemberIdx(); + if (*p == 0x3f) { + if (member == -1) { + *p = 0x3c; + } else if (sub_02055410(member)) { + *p = 0x3c; + } else if (sub_02055474(member)) { + *p = 0x3d; + } else if (sub_020554D8(member)) { + *p = 0x3e; + } + } + } + return ret; +}