mirror of
https://github.com/pret/pmd-sky.git
synced 2026-09-29 05:41:47 -05:00
26611d6672cd104f3f1beb527b63231ae5ad150f
1471 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
26611d6672 |
Decomp seventeen storage-selection accessors
Decompile from asm, all reaching UNK_STORAGE_STRUCT_0X14: sub_02043148 sub_0204329C sub_020433E0 ClearStorageSelectedItemTable sub_0204316C sub_02043380 sub_02043400 CountSelectedStorageItems sub_02043218 sub_02043398 sub_02043434 GetFirstSelectedStorageItemIndex sub_0204322C sub_020433C0 sub_02043468 sub_0204323C sub_02043254 struct unk_020AFEE0 was introduced two dozen commits ago holding only the pointer at 0x8 and filler before it. Its first eight bytes are now split into what these functions read: halfwords at 0x0 and 0x2 and a pointer at 0x4, with a word at 0x10 added past the existing end. Nothing that already used field_0x8 moves. The object behind that pointer is new, and its size is derived rather than guessed. Its s16 array at 0x4 is bounded by 0x3e8 in three separate loops, which is 1000 entries and ends at 0x7D3; the signed byte the collection-menu wrappers read sits at 0x7D4, immediately after it. Two further fields at 0x910 and 0x18BC come from sub_020430F4. Filling the gaps brings the struct to exactly 0x18C0, which is the size in upstream's own name for its allocator, InitUnkStorageStruct0x18c0. That agreement is the reason the layout is worth trusting; the field names remain placeholders because nothing here establishes meaning. Fourteen of the seventeen matched on the first candidate. The other three are loops whose index and pointer landed in swapped registers, with every instruction otherwise correct, and all three were closed by reordering the local declarations -- the same effect recorded in the previous two commits. All orderings were enumerated rather than guessed: two locals for sub_02043254 and GetFirstSelectedStorageItemIndex, three for CountSelectedStorageItems. Eight callees remain asm and their prototypes are provisional, declared in the shared header rather than repeated per file. None of them was declared anywhere else in the tree. Two are typed from evidence rather than convention: IsCollectionMenuActive and IsCollectionMenuState3 return bool8 because both callers mask with and r0, r0, #0xff. sub_020430F4 was attempted and is not included. It reaches the same struct and its two extra fields are what sized it, but it stands at 495 after correcting sub_0202C654 to the four arguments the target passes -- the fourth is a zero in r3 that the first reading missed. Left in asm rather than landed as a near-match. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
72b366b366 |
Decomp SetPokemonBattled and GetNbItemAcquired
Decompile from asm: SetPokemonBattled 0x0204FE58 GetNbItemAcquired 0x020503CC SetPokemonBattled is the battled counterpart of SetPokemonJoined, already decompiled in src/main_0204FDFC.c, and merges into that file beside it. It differs only in which completion flag it sets and which flag array it indexes, so the existing function is the template rather than anything derived here. GetNbItemAcquired counts the set bits of items_acquired_flags across 0x580 entries. The pointer is hoisted to a local because the target loads it once before the loop, and the word and bit indices use signed division and remainder, which is what produces the asr/lsr/ror sequences the target has. Both matched on the first candidate. Seven adventure-log functions remain in asm. Four are large -- ComputeSpecialCounters at 144 instructions, CopyLogTo at 122, CopyLogFrom at 120 and ClearAdventureLogStruct at 74. The other three are not large but index the region at 0x260 as an array spanning special_challenge_flags and the five sentry_duty_game_points that follow it, mixing signed and unsigned division of the same index within one function; expressing that without either misdescribing the struct or writing something the compiler will not reproduce needs more care than this batch had left. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
4f46fed938 |
Decomp thirty adventure-log accessors
Decompile from asm, all of them accessors on ADVENTURE_LOG_PTR: SetAdventureLogStructLocation SetAdventureLogCompleted IncrementNbEvolutions SetAdventureLogDungeonFloor GetAdventureLogCompleted GetNbEvolutions GetAdventureLogDungeonFloor IsAdventureLogNotEmpty IncrementNbEggsHatched IncrementNbDungeonsCleared GetNbDungeonsCleared GetNbEggsHatched IncrementNbFriendRescues GetNbFriendRescues GetNbPokemonJoined GetNbMovesLearned SetVictoriesOnOneFloor GetVictoriesOnOneFloor GetNbPokemonBattled IncrementNbBigTreasureWins SetNbBigTreasureWins GetNbBigTreasureWins SetNbRecycled GetNbRecycled IncrementNbSkyGiftsSent SetNbSkyGiftsSent GetNbSkyGiftsSent IncrementNbFainted GetNbFainted GetSentryDutyGamePoints No new types. struct adventure_log already exists in include/adventure_log.h with every field these touch named and offset-commented, and struct dungeon_floor_pair in dungeon.h; every offset in the asm lands on a named field. That header is the reason a batch this size was tractable: the only modelling needed was reading which field each function touches. Two orderings decided four of the thirty, both instances of the rule added to MATCHING_TIPS in the previous commit. IsAdventureLogNotEmpty needed its loop index declared before the pointer local, not after -- with the pointer first the two land in swapped registers, at 35. The three Set functions needed the completion-flag write placed before the clamp rather than after: written in the obvious order the clamp is emitted ahead of the first pointer load and the two literal-pool words come out reversed, at 250 each. Reordering the statement fixed all three. The counters clamp at 0x000F423F, decimal 999999, and each function sets one bit of completion_flags[0]. The exact shape differs per function and is reproduced rather than normalised: three increment then clamp, two clamp then increment, and the three setters write the flag before storing the value. Those differences are what the target does. The clamp comparisons are signed even though the fields are u32, so each is written with an explicit (s32) cast rather than retyping a shared struct. ADVENTURE_LOG_PTR and _022AB69C move into adventure_log.h. src/main_0204FDFC.c declared the pointer itself, from before any of this was decompiled; that line is replaced by the header it already includes, and the object rebuilds unchanged. Nine adventure-log functions remain in asm and are not in this commit: ClearAdventureLogStruct, ComputeSpecialCounters, CopyLogTo, CopyLogFrom, SetItemAcquired, GetNbItemAcquired, SetChallengeLetterCleared, SetPokemonBattled and SetSentryDutyGamePoints. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
59c4a95e44 |
Decomp the volume and pan fade track events
Decompile from asm: DseTrackEvent_VolumeFade 0x020723C0 DseTrackEvent_PanFade 0x02072668 Both were deferred near-matches. Each reads a signed byte as the fade target and a little-endian pair as its duration in ticks, writes the target, and then either snaps current to it when the duration is zero, zeroes the duration when there is nothing to travel, or divides the distance by the duration to get the per-tick delta. The two differ only in which struct dse_fade they address -- volume at 0x2c, pan at 0x3c -- both of which already exist in dse.h. What closed them was declaration order, and in the opposite direction to the obvious one. The target loads ptr_next_byte[2] first, then [0] and [1]; writing the target expression first, so that its load comes first in the source, leaves the loads in ascending address order at score 620. Declaring ticks first and the target second emits them in the target's order and scores 0. So for this scheduler the later-declared expression's loads are issued first, and the fix is to write the declarations in the reverse of the order the asm reads them. Seven other spellings of the same two statements were tried -- explicit locals for each byte in the target's load order, s8/s16/s32 intermediates, an inline cast, and a pointer-cast subscript -- and every one of them stayed at 620. Only the declaration swap moves it. The lib/DSE headers extract_function.py generates do not include dse.h, so both were given it; every other header in that directory already does. Three deferred DSE functions remain, and this commit does not close them. DseTrackEvent_TuningFade is the same family with a bend fade plus the SetTuning tail; hoisting container out of channel before the flag test takes it from 935 to 760, which is progress and not a match. DseTrackEvent_SetupKeyBendLfo is unchanged in substance: its instructions have matched for some time and only register assignment differs. All 120 orderings of its five byte locals were tried this time, along with eleven structural variants, and the best is 55 rather than the 65 it sat at; the earlier note suggested exhaustive permutation as the untried move, and it has now been tried and does not close it. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
702c4c85fe |
Decomp DeleteWindow and seven window state helpers
Decompile from asm: sub_02027A08 0x02027A08 sub_0202811C 0x0202811C sub_02028080 0x02028080 sub_0202812C 0x0202812C sub_020280C0 0x020280C0 DeleteWindow 0x02028194 sub_0202810C 0x0202810C sub_0202822C 0x0202822C DeleteWindow explains _022A7A74, which the previous commit landed two accessors for without knowing what it held. On deleting a window it walks the other nineteen, and for every active one on the same background takes base_tile + width * height, keeping the largest and a floor of 1, then stores that at _022A7A74[bg_id]. So the pair is a next-free-tile watermark per background, which also explains NewWindowScreenCheck setting the entry to 1 when a background has no windows left: that resets the allocator. Four of the eight return their callee's result rather than void, and only one of them shows it. sub_020280C0 never touches r0 after calling sub_02027E30, which is only consistent with r0 staying live to the return; typed void it scored 90, typed s32 it scores 5, and the 5 is the literal-pool naming described below. sub_0202810C and sub_0202811C are tail calls that score 0 either way, so their own bytes settle nothing; they are typed s32 to match, and a reviewer should read those two as following the family rather than as read off the target. DeleteWindow needed two things past the obvious form. The background comparison is bg == p->template.bg_id, not the reverse, which is worth 5 on its own. And its four locals have to be declared i, top, p, bg: every one of the 24 orders was tried, they range from 0 to 140, and only that one reaches 0. The instructions were already identical at 35 -- the entire remaining difference was which register held bg and which held i. sub_0202812C and sub_02027A08 land at 10, and sub_020280C0 at 5, all of it the literal-pool symbol naming: the target writes _022A8990, _022A8992 and _022A88E4 where C indexing WINDOW_LIST emits WINDOW_LIST+0xb4, +0xb6 and +0x8. Same address, identical bytes once linked, at a flat 5 per word. The check for this is in MATCHING_TIPS; the build is what settles it. struct unk_020AFD4C is introduced for the 12-byte object at that address, sized by the gap to _020AFD58. Only its word at 0x8 is touched here, a bitmask that five of these functions set a bit in, indexed by bg_id. DeleteWindow had a provisional declaration in include/main_0202AAA8.h from the menu commits, with three decompiled callers. That is replaced by an include of the new header and all three objects rebuild. sub_0202836C now has a fifth declaration in the tree, and the existing four do not agree: overlay_15 says int, overlay_24_end says s32, and overlay_24_init and overlay_25_init say s8. It is declared s32 here, in the caller's own header rather than in window.h, so that no overlay including window.h sees a conflicting one. They should collapse into a single header when the callee lands. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build with the three DeleteWindow callers rebuilt: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
7f6977e268 |
Decomp ten window accessors, including UpdateWindow and ClearWindow
Decompile from asm: sub_02027624 0x02027624 ClearWindow 0x02027B58 UpdateWindow 0x02027AF0 sub_0202825C 0x0202825C sub_02027B1C 0x02027B1C sub_02028270 0x02028270 sub_020282C8 0x020282C8 sub_020282F4 0x020282F4 sub_0202830C 0x0202830C sub_02028324 0x02028324 Four bss symbols these functions index at stride 0xE0 are aliases into WINDOW_LIST[0], not separate objects: _022A88E4 is +0x8, _022A88F0 is +0x14, _022A88F8 is +0x1C and _022A8994 is +0xB8. The block from WINDOW_LIST to the end of _022A8994 measures 0xB8 + 0x10C8 = 0x1180 = 20 * 0xE0, and every one of those boundaries falls on a field boundary of the Window layout added earlier. That is independent corroboration of the layout, from the linker rather than from the struct definition. Five of the ten do not reach score 0 on a scratch, and are landed anyway. Their instructions all match; the only difference is the literal-pool word, which the target names _022A8994 where C indexing WINDOW_LIST emits WINDOW_LIST+0xb8. Same address, same relocation target, identical bytes once linked -- the scratch diff compares symbol names, at a flat 5 per word, so ClearWindow and sub_02027B1C report 10 and the three single-literal ones report 5. The matching build is what settles it. Which literal appears is decided by whether the index is constant. A constant offset keeps the base symbol in the pool and puts the offset in the instruction; a variable index folds the offset into the pool word because the index has to be scaled separately. That rule cost a build here: NewWindowScreenCheck stores to _022A7A6C at #8 and #0xa, and rewriting those two lines as _022A7A74[0] and [1] to remove an apparent duplicate changed the pool word and failed main.sbin, with no compile error and no overlay cascade. It is reverted, and both declarations are kept, because the target keeps both. sub_020282C8 writes width*8 and height*8 through an out parameter. It reuses Point rather than adding a second two-s32 struct; the layout is identical and the type already exists, but a size is not a coordinate, so read that as structural reuse and not as a claim about meaning. Two prototypes in the tree contradicted the ones landing here and are replaced with includes: overlay_31_02382820.c declared UpdateWindow itself, and overlay_31_02383880.c declared sub_020282F4 taking s8. Both objects are rebuilt to confirm the retyping is byte-neutral rather than assumed. Two more are left alone and are worth a later pass. overlay_13_0238BDA8.c declares UpdateWindow and sub_02027B1C taking s8, and overlay_25_init.c declares both taking char *; the second is a genuine mistyping, since the value it passes is a window id, but correcting it means retyping ov25_0238B414's own parameter and its callers, which is a larger change than this batch. The s8 declaration in overlay_13 carries an upstream annotation identifying sub_02027B1C, which is worth keeping in place rather than deleting to make a byte-neutral edit. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build with both overlay_31 objects rebuilt: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
b6faa49387 |
Decomp NewWindowScreenCheck, SetScreenWindowsColor and the palette getter
Decompile from asm: NewWindowScreenCheck 0x02027648 GetPaletteBaseAddress__020278A8 0x020278A8 SetScreenWindowsColor 0x02027A80 NewWindowScreenCheck counts the active windows on each background before delegating to NewWindow, and sets a flag when either screen has none. It reads is_active as a signed byte at 0xB6 and bg_id at 0x8, both named by the Window layout added in the previous commit, so the loop reads as what it does. It walks with a cursor rather than indexing. Indexing WINDOW_LIST[i] emits an mla per iteration; the target advances a pointer by 0xE0 at the bottom of the loop. Its two counters also have to be assigned in the order sub then main -- declaration order alone was not enough, and every permutation of the four locals left between 20 and 95. SetScreenWindowsColor's colour parameter is s32, not u8, and that distinction is not visible in its own bytes: both score 0 against it, because the store is a strb either way. It is visible one level up. SetBothScreensWindowsColor, landed matching in the previous commit, passes its argument straight through; a u8 parameter makes the compiler truncate at that call site, which changes an object that already matched, changes the size of main.sbin, and shifts every overlay after it. The first build of this batch failed 33 checksums for that reason, with no compile error and nothing wrong in the function being added. GetPaletteBaseAddress__020278A8 reads through _020AFC70, which include/ main_02064FFC.h already declares as u8 *. It is declared the same way here rather than being given a second, differently typed declaration. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
30ea1f34f0 |
Replace the Window placeholder with its real layout
struct Window was landed two commits ago as mostly filler: the fields those
functions happened to touch, and padding to reach the 0xE0 stride GetWindow
indexes by. This replaces it with the full 0xE0 layout, supplied by the project
maintainer, together with the four types it is built from -- WindowTemplate,
WindowBlock, WindowTile and CursorParams, plus Point.
Four things the layout has to satisfy, and does:
sizeof is 0xE0, the stride GetWindow multiplies by.
is_active is an s8 at 0xB6, which is where DeleteWindow does ldrnesb.
WindowTemplate.width is at 0x06, where the previous partial struct, inherited
from overlay_31_02382820.h, already had width.
x, y, width and height at 0x04 through 0x07 account for GetWindowRectangle
exactly: it writes y*8, y*8 + height*8, x*8 and x*8 + width*8, so its output
is top, bottom, left, right. That function is rewritten against the named
fields rather than shifting anonymous bytes.
Three choices worth noting for review. The struct keeps its tag, so both
struct Window and Window resolve and no existing use changes. GetWindowContents
still returns void * rather than the u32 the field is typed as, because all 22
of its callers assign the result to a pointer; the cast is a no-op and avoids 22
integer-to-pointer conversions. And width moving inside the template means
overlay_31_02382820.c reads window2->template.width, the one source change the
layout forces.
The field names here are the maintainer's, not derived in this commit. The
offsets and widths are checkable against the asm; the names are not, and should
be read as supplied rather than proven.
No comments are added to any pmd-sky file.
Authored by Claude (Opus 5) under human direction, from a struct definition
supplied by the maintainer. Confirmed by a matching build with
overlay_31_02382820.o rebuilt: build/pmdsky.us/pmdsky.us.nds: OK.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
643fd53bcf |
Decomp GetWindowContents, GetWindowRectangle and SetBothScreensWindowsColor
Decompile from asm: SetBothScreensWindowsColor 0x02027A80 GetWindowRectangle 0x02028284 GetWindowContents 0x0202833C GetWindowContents is the function the menu accessors landed over the last several commits all call. It reads the pointer at 0xC of a WINDOW_LIST entry, and its callers cast that to whichever menu layout they use. struct Window gains the fields these two touch: bytes at 0x4, 0x5, 0x7 and 0x8 around the existing width at 0x6, and the pointer at 0xC. The trailing padding shrinks to keep the entry at 0xE0, which is the stride GetWindow indexes by. GetWindowRectangle converts four of those bytes into a rectangle in pixels, multiplying each by 8, writing top and bottom from 0x5 and 0x7 and left and right from 0x4 and width. Its out parameter has no existing type and becomes struct unk_02028284. GetWindowContents needed the entry address bound to a pointer local. Returning WINDOW_LIST[window_id].field_0xC folds the field offset into the literal pool entry, giving a .word WINDOW_LIST+0xc and an indexed load; the target keeps WINDOW_LIST as the literal and reaches the field with mla plus ldr [r1, #0xc]. SetScreenWindowsColor is still asm and had no declaration in the tree, so its prototype is provisional. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
aade0cdfc8 |
Decomp GetWindow; retype overlay_31's window callbacks as ids
Decompile from asm: GetWindow 0x020275F8 It indexes WINDOW_LIST with a stride of 0xE0, so its argument is a window id rather than a pointer, and its result is the address of one entry. overlay_31_02382820.c declared it as taking a struct Window * and passed one, which cannot be what the target computes: multiplying a pointer by 0xE0 and adding it to WINDOW_LIST is meaningless. The value it passes is an id, and the same value goes to DrawTextInWindow and UpdateWindow, so those take ids too. This retypes the three window callbacks and both of those prototypes accordingly, along with the callback type CreateTextBox stores. That retyping is byte-neutral -- a pointer and an id both travel in r0 -- but overlay_31_02382820.o was already matching, so it is rebuilt here to confirm rather than assumed. struct Window keeps its existing return type and gains padding to its real 0xE0 size, which is what lets &WINDOW_LIST[id] stride correctly. Its first seven bytes are unchanged, so the width field overlay_31 reads is where it was. The struct moves from the overlay's header into include/window.h, which already exists and is where a main-binary function returning one can reach it; the overlay includes it rather than the main binary including an overlay header. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build with overlay_31_02382820.o rebuilt: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
2472ad54f7 |
Decomp four allocation, keyboard and area-name accessors
Decompile from asm: AllocUnkBagStruct 0x02042B98 FreeUnkBagStruct 0x02042BBC SetAreaNameBoxState3 0x0202FD3C GetKeyboardStringResult 0x0203755C AllocUnkBagStruct and FreeUnkBagStruct manage the pointer at offset 8 of UNK_STORAGE_STRUCT_0XC, the field the selection accessors in the previous commit read. The allocation is 0xC8 bytes, which is 0x32 words -- the same count ClearBagSelectedItemTable zeroes and the same inventory size the bag walkers use. MemAlloc is still asm and has no owning header, so its prototype is provisional and declared beside the caller, matching the signature overlay_31_02382820.c already uses. That is now a second declaration of it; both should collapse into one header when MemAlloc lands. SetAreaNameBoxState3 writes a word at 0xA0 of the window contents, so the filler before 0x198 in struct unk_0202AAA8 is split to expose it. Nothing after it moves. GetKeyboardStringResult reads through the unnamed pointer _020AFDF0, which keeps its placeholder name, into a word at 0xF8 of whatever it points at. GetWindow was looked at and deliberately left in asm. It indexes WINDOW_LIST with a stride of 0xE0, so its argument is an index, but overlay_31_02382820.c declares it as taking a struct Window * and passes one. Landing it correctly means retyping that caller, and struct Window there describes only its first 7 bytes, so the two disagree about more than this function. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
80c33c3540 |
Decomp six storage-selection and notify-note accessors
Decompile from asm: ClearBagSelectedItemTable 0x02042AF8 IsBagItemIndexSelected 0x02042B84 IsStorageItemIndexSelected 0x02043568 GetNotifyNote 0x020484A0 SetNotifyNote 0x020484B0 EventFlagBackupVeneer 0x02048758 UNK_STORAGE_STRUCT_0XC and UNK_STORAGE_STRUCT_0X14 already carry those names in asm. Only their field at offset 8 is touched here, a pointer to an array, so they are typed with placeholder structs holding that field and filler before it. The element widths come from the loads: words for the bag table, bytes for the storage one. Their struct names use the globals' own addresses, 0x020AFED4 and 0x020AFEE0, derived by walking back from UNK_STORAGE_STRUCT_0X8_PTR_1, which sits at the labelled address 0x020AFEF4, through the two definitions' byte counts. That is arithmetic on the data rather than a lookup, and a reviewer may want to confirm it; nothing in this commit depends on the names being right, only on the layout. ClearBagSelectedItemTable zeroes 0x32 entries, the same count the bag walkers in earlier commits use for an inventory. EventFlagBackup is still asm and had no declaration in the tree, so its prototype is provisional. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
f7fbcd80ba |
Decomp six collection-menu setters; add a second window-contents view
Decompile from asm: SetCollectionMenuField0x1BC 0x0202C5E0 SetCollectionMenuField0x1C8 0x0202C794 SetCollectionMenuField0x1A0 0x0202C7A8 SetCollectionMenuField0x1A4 0x0202C7BC SetCollectionMenuVoidFn 0x0202C7D0 SetCollectionMenuField0x1B2 0x0202D0D8 These reach the same buffer as the parent, simple and advanced menu accessors, through the same GetWindowContents, but they do not share its layout: this set writes a word at 0x1A0 where CheckParentMenuField0x1A0 reads a byte there, and a byte at 0x1B2 which falls inside the word the advanced text box uses at 0x1B0. So they are given their own view, struct unk_0202C5E0, named for the lowest-addressed function that takes it, rather than forcing one struct to describe both. GetWindowContents returns void *, so each menu type casting the buffer to its own layout is consistent with what the target does; a single merged struct would have to assert that the two layouts agree, which the stores show they do not. Two of the offsets are inferred from the store width alone and nothing else: 0x1A8 is written with a word and the function is named VoidFn, so it is typed void *, but the target would look the same for any pointer or 32-bit value. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
ec362491e1 |
Decomp six menu and text-box setters
Decompile from asm: SetSimpleMenuField0x1AC 0x0202BA0C CloseAdvancedMenu 0x0202BC44 IsAdvancedMenuActive2 0x0202BCBC SetAdvancedTextBoxField0x1C4 0x020307A4 SetAdvancedTextBoxField0x1C2 0x0203083C SetAdvancedTextBoxState5 0x0203088C struct unk_0202AAA8 gains fields at 0x1AC, 0x1BC, 0x1C2, 0x1C3 and 0x1C4. The filler that stood between 0x1A8 and 0x1B0 is split to expose 0x1AC; nothing after it moves. CloseAdvancedMenu differs from the simple- and parent-menu versions: it frees only the window contents, not the pointer at 0x198 those two free first. That is what the target does and is not an omission here. IsAdvancedMenuActive2 tests the same states as IsSimpleMenuActive, 7 and 8, and like it binds the state to a local so the field is loaded once. SetAdvancedTextBoxField0x1C2 stores a constant 1 rather than an argument, so it takes only the window id. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
363d3edb85 |
Decomp GetSelectedMenuItemIdx and five window-id wrappers
Decompile from asm: GetAdvancedMenuCurrentOption 0x0202BCFC GetWindowIdSelectedMenuItemIdx 0x0202C748 IsDialogueBoxActive 0x0202F180 GetWindowIdPageStart 0x02030A18 GetAdvancedTextBoxFlags2 0x02030A40 GetSelectedMenuItemIdx 0x02032578 GetSelectedMenuItemIdx computes the absolute item index from the paging struct added in the previous commit, current page times items per page plus the selection within the page, which the target folds into one mla. GetWindowIdPageStart, GetWindowIdSelectedMenuItemIdx and GetAdvancedMenuCurrentOption resolve a window and forward to the paging functions at offset 4 of its contents. The last two have identical bodies and are decompiled as written rather than one calling the other, since that is what the target does. struct unk_0202AAA8 gains two fields the other two functions read: a byte at 0x8 and a word at 0x1B0. The filler before 0x198 is split to expose the first without moving anything after it. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
75c76fa71f |
Decomp seven menu paging getters
Decompile from asm: GetSelectedItemOnPage 0x02032558 GetCurrentPage 0x02032560 GetPageStart 0x02032568 GetTotalNumMenuItems 0x0203258C GetNumItemsOnPage 0x02032594 GetMaxItemsOnPage 0x0203259C GetTotalNumPages 0x020325A4 Six read one word each from a struct with no existing type, introduced here as struct unk_02032558 with placeholder fields at 0xBC through 0xD0. GetPageStart multiplies two of them, current page by max items per page, which is consistent with the names but is an observation about the arithmetic rather than something the bytes label. GetSelectedItemOnPage was declared provisionally in include/main_0202AAA8.h last commit, taking void *, because it was still asm. That declaration is removed and its caller now includes the real header. The argument reaching it there is a void * offset by 4 from the window contents, which converts implicitly; the caller's object is rebuilt here and still matches. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
75f2f81394 |
Restore four literal-pool annotations stripped by earlier commits
Earlier commits on this branch stripped `; =VALUE` annotations off loads that survived a file split, because precommit.py discarded the removals rule 2 matches against. Four such lines remain in the tree; the rest were on code that has since been extracted to C, so they left legitimately with their functions. asm/main_020108B4.s ldr r5, _02010AC4 ; =0x0000270F asm/main_02010BC0.s ldr r5, _02010DC8 ; =0x0000270F lib/DSE/asm/main_02072054.s ldr r1, _02072140 ; =0x04000208 lib/DSE/asm/main_02072054.s ldr r2, _02072140 ; =0x04000208 These are regenerated from each file's own literal pool rather than recovered from history: the annotation is the `.word` of the label the instruction references, so it is derivable and exact. Two earlier attempts to restore comments by matching instruction text were discarded instead of committed -- repeated instructions made them paste annotations onto unrelated lines. The convention is unambiguous upstream: across the two files sampled, 263 of 263 pool-referencing loads carry an annotation and none lack one. No comments are added to any pmd-sky file beyond these, which are restorations of upstream's own annotations rather than anything authored here. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
fb757337d0 |
Decomp five simple-menu accessors
Decompile from asm: GetWindowIdSelectedItemOnPage 0x0202AB80 CloseSimpleMenu 0x0202B4C4 IsSimpleMenuActive 0x0202B520 CheckSimpleMenuField0x1A0 0x0202B540 GetSimpleMenuField0x1A4 0x0202B558 These are the simple-menu counterparts of the parent-menu accessors in the previous commit and reach the same window contents through GetWindowContents, so they reuse struct unk_0202AAA8, which gains a field at 0x1A4. IsSimpleMenuActive tests states 7 and 8 where the parent-menu version tests 8 and 9. As there, the state is bound to a local: comparing the field against two values inline emits two loads and the target loads it once. DeleteWindow moves into the shared header and MemFree is taken from main_02001188.h, rather than each source declaring them again. Two of these functions need both, and a second local copy of a prototype is the kind of disagreement no build can report. The asm files this split produces keep upstream's jump-table annotations. An earlier run of precommit.py stripped them, having discarded the removals that rule 2 matches against; that is fixed separately in the workspace repo, and the 158 comments in this split are intact here. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
3fc19ec702 |
Decomp IsEmptyString and four parent-menu accessors
Decompile from asm: IsEmptyString 0x0202A66C SetParentMenuState7 0x0202AAA8 CloseParentMenu 0x0202AABC IsParentMenuActive 0x0202AB40 CheckParentMenuField0x1A0 0x0202AB60 The four menu functions all resolve their window through GetWindowContents, which src/overlay_10_022BCC60.c already declares as returning void *. What it returns has fields at 0x198, 0x19C and 0x1A0 and no existing type, so it is introduced as struct unk_0202AAA8, named for the lowest-addressed function that uses it, with placeholder fields. The struct and the GetWindowContents prototype live in include/main_0202AAA8.h and are included by the second source rather than repeated in it. Two copies of a struct definition in two translation units is the same drift risk as two prototypes, and nothing in the build would report them disagreeing. Return widths differ across these and are read off the target. IsEmptyString and CheckParentMenuField0x1A0 end in and r0, r0, #0xff, so they return bool8; IsParentMenuActive does not, so it is word-sized despite reading like a predicate. IsParentMenuActive also needed its state field bound to a local. Comparing menu->field_0x19C against two values inline emits two loads; the target loads it once. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
6f907c680c |
Decomp eight veneers and wrappers
Decompile from asm: PlayBgmByIdVeneer 0x02017B58 PlayBgmByIdVolumeVeneer 0x02017B64 PlaySeByIdVolumeWrapper 0x02017C80 GroupOamAttributesWrapper 0x0201BA9C CopyAttributesToOamWrapper 0x0201BAAC CopyAndInterleaveWrapper 0x0201BFF0 SetAnimationControlPausedFlag 0x0201D198 DeleteWanTableEntryVeneer 0x0201D72C Most are tail calls the compiler reaches with bx rather than bl, either passing their arguments through unchanged or supplying one: PlaySeByIdVolumeWrapper fixes the volume at 0x100, the two Oam wrappers offset their argument by 0x20, and CopyAndInterleaveWrapper halves its length. That halving is a shift, not a division. Written as len / 2 the compiler adds the round-toward-zero correction a signed divide needs; the target has a bare asr #1, which is what len >> 1 produces. SetAnimationControlPausedFlag sets or clears bit 0x4000 of the bitfield at the start of struct animation_control, which already exists in graphics.h. Two cautions for a reviewer. The callees are all still asm and had no declarations in the tree, so every prototype here is provisional and declared beside its caller. And a veneer that only forwards constrains nothing about its own argument list -- the arguments are already in the right registers, so declaring none, one or several all produce the same bytes. The parameter lists are chosen to read sensibly against each callee's name, not read off the target. The exception is PlaySeByIdVolumeWrapper, whose signature is pinned by an existing C caller in overlay_25_init.c that passes a single s32. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
152f6c7ea6 |
Decomp six shop and item helpers; split bag_items' filler
Decompile from asm: SetMoneyStored 0x0201070C GetCurrentKecleonShop1ItemByIndex 0x02010898 GetCurrentKecleonShop2ItemByIndex 0x02010BA4 GetExclusiveItemOffset 0x02010E40 SwapShopFreeDoublePointer 0x020114F8 IsMonsterAffectedByGravelyrockGroundMode 0x02011830 The two Kecleon accessors index arrays hanging off pointers at 0x132C and 0x1370. Unlike the previous two extensions those offsets fall inside fill2[0x1009] rather than past the struct's end, so the filler is split into three runs with the two pointers between them. maybeMoney still lands at 0x1394 and nothing after it moves, which the rebuild of every struct bag_items user confirms. SetMoneyStored clamps to 0x0098967F, decimal 9999999, and to zero below. GetExclusiveItemOffset returns zero unless the item is in CATEGORY_EXCLUSIVE_ITEMS, which item.h already defines as 15, and otherwise the item's distance from 0x1bc, narrowed to 16 bits. IsMonsterAffectedByGravelyrockGroundMode normalises the species through FemaleToMaleForm and compares against two ids, left as raw values because naming them is not this commit's job. Its return is word-sized: bool8 appends and r0, r0, #0xff, which the target does not have. SwapShopFreeDoublePointer frees through two levels of indirection and clears the outer pointer, returning early when it is already null. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
35134eced4 |
Decomp twelve game-state and recycle-shop accessors
Decompile from asm: AddMoneyStored 0x02010758 SetEggSpecies 0x02010794 SetUnkGameState0x13a6 0x020107C4 SetEggHatchTimer 0x020107F4 DecrementEggHatchTimer 0x0201080C GetRecycleItemId 0x02011DF0 RecycleItemHasTradeTypePrizeTicket 0x02011DFC GetRecycleItemBonusOdds 0x02011E18 ClearRecycleShopOffer 0x02011F14 GetGameStateRecycleCount 0x02011F30 GetRankForRecycleShop 0x02011F48 GetRecycleOfferCooldown 0x0201227C Nine of these reach BAG_ITEMS_PTR_MIRROR. Five are the setters matching getters already landed; the other four use offsets past them, so struct bag_items gains four more fields, up to 0x13B4. As with the previous extension they are appended past the end, and the field at 0x13AC is left to align naturally rather than declaring a byte at 0x13AB that nothing reads. AddMoneyStored tail-calls SetMoneyStored, which is still asm; its prototype is provisional. DecrementEggHatchTimer only decrements a non-zero timer, which the target expresses with predicated subne/strneh rather than a branch. The remaining three take a pointer to a pointer to a small struct with fields at 0x0, 0x4 and 0x12. No existing type matches that layout, so it is introduced as struct unk_02011DF0, named for the lowest-addressed function that takes it, with placeholder fields. The bytes between 0x8 and 0x12 are unexamined and left as filler. Every one of the twelve matched on the first candidate. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
06c828e19b |
Decomp CountItemTypeInBag and GetEquippedThrowableItem
Decompile from asm: CountItemTypeInBag 0x0200EE88 GetEquippedThrowableItem 0x0200F208 CountItemTypeInBag totals matching slots, adding the stack size for thrown items and one for everything else, using IsThrownItem from item_util.c. GetEquippedThrowableItem returns the index of the first existing slot flagged usable by L+R, or -1. It reads item->flags through struct item_volatile. The target loads the flags byte twice, once for each test, where a plain struct item lets the compiler reuse the first load; item.h already carries item_volatile for exactly this purpose and says so. The cast is written at each access, following dungeon_ai_items.c and special_move_types.c rather than casting the cursor once, though both spellings score 0. Only the second flag test is left as a bare mask. The existence test goes through an explicit bool8 because the target boolifies it -- tst, movne, moveq, tst #0xff -- while the second test branches straight off tst, which is what a bare mask in an if produces. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
a49bcedffc |
Decomp CountNbItemsOfTypeInBag and HasStorableItems
Decompile from asm: CountNbItemsOfTypeInBag 0x0200EE4C HasStorableItems 0x0200F0FC CountNbItemsOfTypeInBag counts every slot whose id matches, without checking the existence flag, so empty slots are counted when the caller asks for whatever id they hold. That is what the target does; it is not an omission here. HasStorableItems checks the existence flag through the same explicit bool8 the other bag walkers use, then calls IsStorableItem, which is already decompiled in item_util_4.c, and returns on the first slot satisfying both. HasStorableItems sits at a lower address than GetItemIndex, so it is prepended to that file. The extern for BAG_ITEMS_PTR_MIRROR was below the existing function and is moved to the top, above both, since the new first function needs it too. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
3c5de72d23 |
Decomp IsItemWithFlagsInBag and GetItemIndex
Decompile from asm: IsItemWithFlagsInBag 0x0200EF20 GetItemIndex 0x0200F14C IsItemWithFlagsInBag matches an item by id and then by any of a flag mask, and returns on the first item satisfying both. The two conditions can be written as a single && or as nested ifs; both score 0, so the target does not distinguish them and the && form is used as the more direct reading. GetItemIndex takes a struct item pointer rather than an id. The target compares the walking cursor against the argument, not a field of it, so this returns the index of a bag slot the caller already holds a pointer to, and -1 when the pointer is not in the active inventory. The index is returned through a 16-bit narrowing, which is why the return type is s16 rather than the s32 the loop counter uses. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
fdbc544fcb |
Decomp GetNbItemsInBag and IsItemInBag
Decompile from asm: GetNbItemsInBag 0x0200EDFC IsItemInBag 0x0200EEE0 Both walk the active inventory with a cursor rather than indexing, with the index and the cursor both advanced in the for clause, which is what puts the two adds at the top of the loop body as the target has them. GetNbItemsInBag's existence test goes through an explicit boolean: (item->flags & ITEM_FLAG_EXISTS) != 0 assigned to a bool8 before the branch. That is what produces the target's tst / movne / moveq / tst #0xff sequence; testing the masked value directly collapses it. IsItemInBag returns early on the first match, which the target reaches with bxeq lr mid-loop, and falls through to a single return of zero. GetNbItemsInBag lands in the existing src/main_0200EDC0.c, which already includes item.h; IsItemInBag needs a new file and declares BAG_ITEMS_PTR_MIRROR alongside it, matching how the other bag sources in this tree declare it. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
399618a493 |
Decomp GetItemAtIdx and RemoveEmptyItemsInBag
Decompile from asm: GetItemAtIdx 0x0200F340 RemoveEmptyItemsInBag 0x0200F370 GetItemAtIdx returns a pointer into the active inventory, or null for a negative index. Its index parameter is s16, not s32: struct item is 6 bytes, and at 16-bit width the compiler folds the index scaling and the base into a single smlabb, which is what the target emits. An s32 index produces a separate multiply and add, at score 1100. RemoveEmptyItemsInBag tail-calls RemoveEmptyItems over the active inventory with INVENTORY_SIZE, which is already 50 in item.h and matches the 0x32 immediate. RemoveEmptyItems is still asm and was not declared anywhere in the tree, so its prototype is provisional and declared here. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
d4b2c2fc01 |
Decomp two bag helpers that forward to asm callees
Decompile from asm: RemoveFirstUnequippedItemOfType 0x0200F798 AddItemToBagNoHeld 0x0200F874 Both are thin forwarders. AddItemToBagNoHeld tail-calls AddItemToBag with a zero second argument, which the target reaches with bx rather than bl. RemoveFirstUnequippedItemOfType feeds GetFirstUnequippedItemOfType's result straight into RemoveItemNoHoleCheck. All three callees are still asm and had no declaration anywhere in the tree, so their prototypes are provisional and declared in the new headers with the loosest types that compile. They should collapse into the callees' own headers when those land. The return types are not determined by these functions' bytes. Both forward whatever the callee returns without touching it, so declaring them void scores 0 as well. They are written as returning u32 because that is what a pass-through of a word-sized result reads as, but a reviewer should treat the return type as a guess rather than something the target settles. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
27c9ec9af6 |
Decomp four bag accessors; extend struct bag_items past maybeMoney
Decompile from asm: GetMoneyStored 0x0201070C GetEggSpecies 0x0201077C GetUnkGameState0x13a6 0x020107AC GetEggHatchTimer 0x020107DC Each dereferences BAG_ITEMS_PTR_MIRROR and reads one field. struct bag_items in include/item.h ended at 0x13A0, immediately before every offset these four use, so it gains four fields: a word at 0x13A0, a signed halfword at 0x13A4 and halfwords at 0x13A6 and 0x13A8. The widths come from the loads -- GetEggSpecies uses ldrsh where the other two halfword readers use ldrh. The fields are placeholders rather than named after their accessors. The function names are suggestive, and a later pmdsky-debug sync can name them; the offsets and widths are facts read off the asm, which is all this commit claims. Extending a shared struct is the risk here, so it was checked rather than assumed. The four fields are appended past the end, after maybeMoney, so no existing member moves. All four translation units that use struct bag_items -- dungeon_ai_items.c, main_0200ECFC.c, main_0200EDC0.c and overlay_31_02383478.c -- are rebuilt by this commit's build and the ROM still matches. The two constants the target splits the offset into differ per function (0x1300 + 0xa8 against 0x1000 + 0x3a0) because each is a valid ARM immediate encoding of the same address; the compiler reproduces the choice from the field offset alone. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
0888986aaf |
Decomp the tempo and signal track events
Decompile from asm: DseTrackEvent_SetBpm 0x02071AE0 DseTrackEvent_SetBpm2 0x02071B20 DseTrackEvent_Signal 0x0207296C SetBpm and SetBpm2 have identical bodies. The two differ only in the label their literal pool uses, so they are the same routine reached from two opcodes rather than variants of one; both are decompiled as written rather than one calling the other, because that is what the target does. They scale the sequence's tempo fade by the new bpm and divide 0x03938700 -- sixty million microseconds, i.e. one minute -- by the result to get microseconds_per_beat, guarding a zero divisor by substituting 1. The shifts type the intermediate: the tempo is read with an arithmetic shift and the product with a logical one, so the value handed to _u32_div_f is unsigned. Signal writes the stream byte to the sequence and passes it to the sequence's signal_callback with code 8, following DseTrackEvent_SetInstrument in lib/DSE/src/main_02071BF4.c, which makes the same call with a different code. The callback's four arguments -- id, code, value, callback_arg -- come from the existing function-pointer type in dse.h, not from the call site. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
59fad373cc |
Decomp three LFO setup track events; complete struct dse_lfo_settings
Decompile from asm: DseTrackEvent_SetupVolumeLfo 0x020724A8 DseTrackEvent_SetupPanLfo 0x020726C4 DseTrackEvent_SetupLfo 0x02072770 Each reads five bytes and initialises one lfo_settings entry: waveform index, a signed 16-bit amplitude, a phase-change time, and zeroes for the envelope fields. The two fixed-slot handlers also set type and output_type, using the same slot-to-output_type mapping as the Use handlers -- 2 for volume, 3 for pan. SetupLfo is the indexed form and takes its slot from channel + 0x61. struct dse_lfo_settings gains field_0xE. All four of these handlers store a zero byte at that offset, which the struct previously described as trailing padding. The struct's size is unchanged: it already rounded to 0x10 for the s32 amplitude's alignment, and the 0x10 stride is confirmed by the shift-by-4 the asm uses to index the array. Adding the field is therefore byte-neutral to every existing user, which the build confirms. All five stream bytes are read into locals before the first store. Reading them inline instead interleaves the loads between stores, and the target issues all five ldrb up front. DseTrackEvent_SetupKeyBendLfo is deliberately not included. It is the same shape and reaches an instruction-for-instruction identical body -- every mnemonic, offset and immediate matches -- differing only in which registers the allocator picks, at score 65. Reordering the locals, introducing an explicit amplitude temporary, and dropping the pointer local were all tried and moved the score without closing it. It is left in asm rather than landed as a near-match. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
882d2edf64 |
Decomp the three tuning-delta track events
Decompile from asm: DseTrackEvent_TuningDeltaCoarse 0x02071EB4 DseTrackEvent_TuningDeltaFine 0x02071F3C DseTrackEvent_TuningDeltaFull 0x02071FC4 All three are DseTrackEvent_SetTuning with the new tuning derived from the old one instead of replacing it, and they share its tail verbatim: recompute bend_final from the tuning, the channel's bend fade and the synth's bend, then mask interrupts and set update_flags bit 0x10 on every voice in the channel. They differ only in how the delta is scaled. Coarse shifts the signed byte left 8, Fine shifts it left 2, and Full takes a little-endian pair of bytes and adds it whole. Coarse and Fine need the delta written before the existing tuning -- (delta << n) + channel->tuning, not channel->tuning + (delta << n). The target loads the stream byte first and folds the shift into the add's second operand; the other order reverses both the loads and the add, at score 215. Full is unaffected because its byte pair is assembled before the add either way. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
019b4543a2 |
Decomp the volume, expression and pan track events
Decompile from asm: DseTrackEvent_SetVolume 0x0207227C DseTrackEvent_VolumeDelta 0x02072310 DseTrackEvent_SetExpression 0x0207241C DseTrackEvent_SetPan 0x02072554 DseTrackEvent_PanDelta 0x020725D4 All five follow DseTrackEvent_SetTuning in lib/DSE/src/main_02071BF4.c, which was already landed and is a complete template for this shape: write the fade, recompute the final value, then mask interrupts through IME while walking channel->voice_list and setting an update_flags bit on every voice. The bit differs by what changed -- 0x20 for volume and expression, 0x40 for pan, where SetTuning uses 0x10. Offsets all resolve against existing dse.h types. struct dse_fade is 0x10, so the channel's bend, volume and pan fades sit at 0x1c, 0x2c and 0x3c, which is what the stores at 0x2c/0x34/0x38 and 0x3c/0x44/0x48 address. container is at 0xc4 and struct dse_synth puts pan at +7 and song_and_global_volume at +8, both of which the asm loads with ldrsb. The volume handlers scale by song_and_global_volume * volume * expression and divide by 127 * 127; the compiler reproduces the target's smull-based division by that constant, so the magic word 0x82061029 needs no special handling. Two details that were not obvious. The final pan is v + (container->pan - 0x40), not (v + container->pan) - 0x40: the target subtracts before adding, and the other grouping emits the two instructions in the opposite order. And the discarded read of IME before restoring it only survives if IME is declared through a volatile type; without volatile the compiler drops the load and the restore is all that remains. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
c356d53c74 |
Decomp the bank and key-bend track events; restore stripped label addresses
Decompile from asm:
DseTrackEvent_SetBank 0x02071B60
DseTrackEvent_SetBankMsb 0x02071B8C
DseTrackEvent_SetKeyBend 0x02072184
All three assemble a 16-bit value from the event stream and hand it to a
DseChannel_ setter, following DseTrackEvent_SetBankLsb in
lib/DSE/src/main_02071BF4.c. SetBankLsb replaces the low byte of swd_id;
SetBankMsb is its mirror and replaces the high byte, which is why its operands
read (*ptr_next_byte << 8) + (channel->swd_id & 0xFF). Written the other way
round the addition is emitted in the wrong order and scores 30.
SetBank and SetKeyBend take both bytes from the stream. They differ only in the
width cast the target applies before the call -- lsr for the unsigned bank,
asr for the signed bend -- which is what types each callee's second parameter.
DseChannel_SetBank and DseChannel_SetKeyBend are still asm. Their prototypes are
provisional and declared in the new headers. Note DseChannel_SetBank is now
declared in two places: here and in lib/DSE/src/main_02071BF4.c, which declared
it from its own call site earlier. They agree, but nothing in the build checks
that, and the duplicate should collapse into one header when the callee lands.
This commit also restores four `; 0xADDRESS` label comments in
lib/DSE/asm/main_02071AE0.s that a previous precommit run stripped. The addresses
came from the pre-split file at
|
||
|
|
acff5cf391 |
Decomp the generic-LFO and note-random-region track events
Decompile from asm: DseTrackEvent_SetNoteRandomRegion 0x02072144 DseTrackEvent_SetupLfoEnvelope 0x020727C8 DseTrackEvent_UseLfo 0x02072938 SetNoteRandomRegion reads two bytes and stores the smaller in note_random_region_begin and the larger in note_random_region_end, so the pair is sorted regardless of the order it was written in. SetupLfoEnvelope and UseLfo are the indexed forms of the per-slot handlers added in the previous commit: instead of a fixed lfo_settings entry they take the index from channel + 0x61, which UseLfo also writes. That byte falls inside dse.h's field_0x5A[10], so it is spelled field_0x5A[7]; a name for it would have to come from a real pmdsky-debug sync. UseLfo needed the sub-struct bound to a pointer local. Indexing channel->lfo_settings[idx] directly folds the array's 0x74 base into each store's offset, giving strb [r1, #0x75]; the target computes the element address once, add r1, r3, #0x74 then add r1, r1, idx lsl #4, and stores at [r1, #1] and [r1, #2]. Binding struct dse_lfo_settings *lfo also reproduces the frame push the target has, which no arrangement of the indexed form did. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
909484fb99 |
Decomp the six DSE LFO track-event handlers
Decompile from asm: DseTrackEvent_SetupKeyBendLfoEnvelope 0x0207222C DseTrackEvent_UseKeyBendLfo 0x0207225C DseTrackEvent_SetupVolumeLfoEnvelope 0x02072504 DseTrackEvent_UseVolumeLfo 0x02072534 DseTrackEvent_SetupPanLfoEnvelope 0x02072720 DseTrackEvent_UsePanLfo 0x02072750 All six index struct dse_channel's existing lfo_settings[4], which sits at offset 0x74 with a 0x10 stride -- the stride the asm computes as ip lsl #4, and the offset another handler in this family loads directly as channel + 0x74. The three pairs address entries 0, 1 and 2, so key bend, volume and pan each own one lfo_settings slot. Within an entry the setters write +0xa and +0xc, which are msec_until_lfo_started and lfo_envelope_len_msec, and the Use handlers write +1 and +2, which are type and output_type. output_type is set to 1, 2 and 3 for key bend, volume and pan respectively, which is consistent with the slot each one uses; that is an observation about the constants, not something the bytes label. The Use handlers needed an explicit if/else rather than a ternary. Every conditional-expression spelling tried -- v ? N : 0, v == 0 ? 0 : N, !v ? 0 : N, and (v != 0) -- emits movne before moveq, where the target emits moveq before movne. The statement form reverses the pair and matches. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
ed153d5fce |
Use the established parameter names for the arm9 DSE handlers
The eleven handlers decompiled in the two previous commits used (position, seq, track, channel). The handlers already landed in lib/DSE/src/main_02071A98.c, which are the same dispatch family reached from the same SMD_EVENTS_FUN_TABLE, use (ptr_next_byte, sequence, track, channel). This renames the arm9 ones to match so the family reads consistently, and follows the existing pointer spelling for the sub-loop local. Parameter names do not affect code generation; the rebuild below is to confirm that rather than to assume it. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
3046c8b010 |
Decomp six DSE track-event handlers in lib/DSE
Decompile from asm: DseTrackEvent_SetOctave 0x02071AC0 DseTrackEvent_OctaveDelta 0x02071ACC DseTrackEvent_SetTuningJitterAmplitude 0x0207216C DseTrackEvent_SetUnknown2 0x020721B0 DseTrackEvent_SetKeyBendRange 0x020721C8 DseTrackEvent_Dummy2Bytes2 0x0207299C These are the same handler family as the previous two commits, but they live in lib/DSE, which is compiled with different flags: -O4,p and -enum int, where the arm9 modules use -O4,s and -enum min. Signatures follow the parameter names already used by the landed handlers in lib/DSE/src/main_02071A98.c rather than the ones the previous two commits introduced. Field names come from struct dse_channel in lib/DSE/include/dse.h and match the offsets the asm uses: bend_jitter_amplitude at 0xa, field_0x56 at 0x56, and bend_sensitivity_override at 0x59, whose meaning agrees with SetKeyBendRange writing to it. SetTuningJitterAmplitude and SetUnknown2 read their two operand bytes in opposite orders -- little-endian for the first, big-endian for the second -- which the asm's shift operands show directly. Landing these needed two adjustments the arm9 path does not. extract_function.py hardcodes asm/, src/, include/ and main.lsf, so it was run with lib/DSE as the working directory; the object lines it then inserts into main.lsf carry no lib/DSE/ prefix and were corrected by hand. It also emits .include "main_XXXX.inc", which is right for arm9 where the search path is ./asm/include, but lib asm is built with -Ilib/DSE/asm/ and its existing files use .include "include/main_XXXX.inc"; the four split files were fixed to match. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
00d4d6428c |
Decomp the last four DSE track-event handlers in arm9
Decompile from asm: DseTrackEvent_WaitUntilFadeout 0x0207199C DseTrackEvent_EndTrack 0x020719C8 DseTrackEvent_SubLoopBegin 0x02071A1C DseTrackEvent_SubLoopEnd 0x02071A5C This empties asm/main_0207199C.s and asm/main_02071A1C.s, so both files and their .inc are removed rather than split, and the handlers merge into the adjacent sources added by the previous commit. EndTrack confirms the second parameter's type, which the previous commit could only infer from the dispatcher: it writes 1 to the byte at offset 3 of that argument, which is field_0x0.has_looped in struct dse_sequence. A track that reaches the end of its main loop setting has_looped is consistent, and no other struct in dse.h places a byte with that meaning at offset 3. SubLoopBegin and SubLoopEnd index track->loop_stack, the existing struct dse_sub_loop[4] at offset 0x24 with a 12-byte stride, which is what the asm's multiply by 0xc computes. SubLoopEnd needed two changes past the obvious form. Its index and count locals are int, not u8: at byte width the compiler inserts and rX, rX, #0xff after each decrement, which the target does not have. And the early return has to be the fall-through path -- written as an early return the compiler if-converts the tail into predicated stores, where the target branches with bxeq lr. Inverting the condition, so the longer body sits inside the if, produces the branch. DseVoice_CountNumActiveInChannel and DseChannel_DeallocateVoices are still asm; their prototypes are provisional and declared in this file's header. Neither was declared anywhere else in the tree. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
262177377d |
Decomp seven DSE track-event handlers
Decompile from asm: DseTrackEvent_Invalid 0x0207191C DseTrackEvent_WaitSame 0x02071928 DseTrackEvent_WaitDelta 0x02071934 DseTrackEvent_Wait8 0x0207194C DseTrackEvent_Wait16 0x0207195C DseTrackEvent_Wait24 0x02071978 DseTrackEvent_MainLoopBegin 0x02071A14 These are handlers in SMD_EVENTS_FUN_TABLE, dispatched by ParseDseEvent. No new types are introduced: struct dse_track and struct dse_sub_loop already exist in lib/DSE/include/dse.h, and every offset these functions touch lines up with a named field there -- is_playing at 2, wait_ticks_left at 0xc, previous_wait_ticks at 0x10, loop_start at 0x20. The shared four-argument signature is read off the dispatcher rather than guessed. ParseDseEvent loads the handler from SMD_EVENTS_FUN_TABLE and calls it with r0 already advanced past the opcode byte, r1 its own first argument, r2 the track, and r3 track->channel from offset 0x54; the returned r0 becomes the track's new position. Its caller passes a sequence and that sequence's track at offset 0xa8, which is what types the second parameter. The second parameter is unused by all seven bodies, so their own bytes do not constrain its type; it is typed from the dispatcher's call site, and the handlers that do use it are still asm. Six of these are contiguous and merge into one source file; MainLoopBegin sits after WaitUntilFadeout and EndTrack, which remain asm, so it splits separately. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
e6c5c87501 |
Decomp five leaf functions; replace four stale prototypes
Decompile from asm: IsMonsterIdInNormalRange 0x02056294 Rgb8ToRgb5 0x02004FCC Arm9LoadUnkFieldNa0x2029EC8 0x02029EC8 Arm9StoreUnkFieldNa0x2029ED8 0x02029ED8 CanMonsterBeUsedForMissionWrapper 0x02062A58 Each was extracted with extract_function.py, splitting its .s and adding the new objects to main.lsf. PREV_MENU_ITEMS is declared alongside the two accessors that use it, sized 0x18 from the .space in main_bss_020B3380.s. Four prototypes previously declared from call sites are replaced by includes of the new headers: IsMonsterIdInNormalRange in main_02056D70.c, Rgb8ToRgb5 in main_0201E380.c, and both Arm9 accessors in overlay_31_02382820.c. Arm9LoadUnkFieldNa0x2029EC8 keeps the two-parameter prototype that was already declared in overlay_31_02382820.c. Its body reads only the first argument -- the second register is overwritten with the table address before any use -- so the function's own bytes do not distinguish a one-parameter form from a two- parameter one, and both score 0 against the target. The call site does distinguish them: overlay_31_02382820.c passes two arguments and already matches, so the existing declaration is the load-bearing evidence. That object is rebuilt here and still matches. CanMonsterBeUsedForMission is still asm, so its prototype is provisional and declared in the caller's header. Its second parameter is byte-width: a caller in main_0205D1F4.s masks with and r1, r1, #0xff before the call. No comments are added to any pmd-sky file. Authored by Claude (Opus 5) under human direction. Confirmed by a matching build of all five together: build/pmdsky.us/pmdsky.us.nds: OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
0f2e0ea8c4 |
Decomp OverlayIsLoaded; migrate its prog_pos_info array to C
Decompile OverlayIsLoaded (0x02003ED0) from asm/main_02003DB8.s. It maps an overlay group id to whether that group is currently loaded, via a jump table over ids 0-0x24: group 0 is always loaded, and the other ranges check one of the three LOADED_OVERLAY_GROUP_0 slots, gated on the parent slot holding the expected group. Out-of-range ids fail an assert through Debug_FatalError with a prog_pos_info record for overlay.c line 177. That record is the reason this commit also moves data. The function copies _02092558[2] to the stack to pass its address, and the copy's two loads only schedule in the target's order when the compiler can see the array's initializers -- an extern declaration of the same array compiles to the loads transposed. So the five-record array moves into the C file as a const definition. The values are the ones decoded from the data: five entries sharing the overlay.c filename with lines 887, 534, 177, 269 and 626. The array's neighbours cannot move with it. The two strings that follow it in retail cannot be produced by this compiler in place: mwccarm 2.0/sp2p2 emits anonymous string literals into writable .data sections, which the link places in the far data region, and it has no -str readonly (only [no]reuse and [no]pool); a named const u8 string does land in .rodata but is emitted before the array regardless of definition order. The strings therefore stay as assembly, in a new asm/main_rodata_02092580.s holding exactly overlay.c and check group error. asm/main_rodata_020908D4.s is accordingly split: it now ends just before _02092558, and the remainder from _020925A0 onward becomes asm/main_rodata_020925A0.s. Both new rodata files include the original main_rodata_020908D4.inc, which other rodata files also include as a shared declaration header and which is left untouched. main.lsf orders the pieces src/main_02003ED0.o, asm/main_rodata_02092580.o, asm/main_rodata_020925A0.o, so the linker lays out the array, the strings and the remaining data at their retail addresses; the extraction also splits the text file, with the trailing functions moving verbatim into asm/main_020040AC.s. No new names are introduced: OverlayIsLoaded, struct prog_pos_info, Debug_FatalError, LOADED_OVERLAY_GROUP_0 and the three data placeholders all already exist in the tree. 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. Intermediate layouts were verified by binary-diffing the built main.sbin against a clean build, which is what located each divergence exactly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
4f33a43bf9 |
Decomp ov11_022E96E4
Decompile ov11_022E96E4 from asm/overlay_11.s. It returns the byte at offset 4 of ov11_02324FA0. This is overlay_11's first decompiled function, so it creates src/overlay_11_022E96E4.c rather than merging; the trailing functions move verbatim into asm/overlay_11_022E96F4.s, the .inc files are regenerated, and the two objects are added inside main.lsf's Overlay OVY_11 section. ov11_02324FA0 is declared as u8[0x20] rather than given a struct. The symbol is .space 0x20 in the data, so the size is a fact, and other functions in the overlay touch offsets 0x0, 0xc, 0x10, 0x14 and 0x1c -- none of which are decompiled, so a struct would have to invent a layout around the one field this function reads. The array asserts only the size. The return type is u8. The load is ldrb, so the width is known, but every candidate return type produces identical bytes here; bool8 would additionally assert that the value is a truth value, which is only an inference from the two callers testing it in a condition. u8 states what is known and nothing more. sub_02065050 and sub_0206549C call it and had a provisional int prototype in main_02064FFC.h while only the call site was understood. That is replaced by an include of the new header, and both were rebuilt to confirm they stay byte-identical. No new names are introduced: both ov11_022E96E4 and ov11_02324FA0 are pre-existing labels. 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 <noreply@anthropic.com> |
||
|
|
e1879864e2 |
Decomp sub_020564B0 and sub_0201E380
Decompile two more callees of the actor cluster, from asm/main_02055894.s and asm/main_020151E4.s. Each splits its file; the trailing functions move verbatim into asm/main_02056504.s and asm/main_0201E3AC.s, the affected .inc files are regenerated, and main.lsf gains the four objects. sub_020564B0 takes a member index and reports whether it is the appointed leader's. It repeats the roster read that GetAppointedLeaderMemberIdx performs -- active_team selects one of the number_active_team_members fields, and that value indexes active_roster_member_idxs -- and compares the result against its argument, returning false if either the argument or the intermediate is -1. With this, both NPC-collection filters are accounted for: GetAdventureNpcIds excludes the appointed leader, and GetUnitNpcIds excludes the three main characters. sub_0201E380 writes one palette entry. It converts an 8-bit RGB triple through Rgb8ToRgb5 into the halfword at index (c << 8) + d of the table its first argument points at, then sets a byte at index c in a second table, which reads as marking that palette dirty. That first argument is a struct with a halfword pointer at 0x18 and a byte pointer at 0x1c. No global has that type -- callers pass an interior offset of whatever _020AFC70 points at -- so it takes the address of the function that receives it, struct unk_0201E380, with fields named for their offsets. The parameter was previously declared u8* while only the call site was understood, so sub_02064F94 now casts at that call site; it was rebuilt to confirm it stays byte-identical. src/main_02056D70.c likewise drops its local extern for sub_020564B0 in favour of the new header. No other names are introduced. Rgb8ToRgb5, TEAM_MEMBER_TABLE_PTR, struct team_member_table and its fields all already exist, and both functions keep their sub_ names. 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 <noreply@anthropic.com> |
||
|
|
6371544da2 |
Decomp GetUnitNpcIds and GetAdventureNpcIds
Decompile both from asm/main_02056960.s. Each walks the four entries of TEAM_MEMBER_TABLE_PTR->active_roster and, for every entry with bit 1 of its flags byte set, takes member_index and keeps it if IsMonsterIdInNormalRange accepts it and a filter rejects it: GetUnitNpcIds excludes the three main characters via sub_02055410, sub_02055474 and sub_020554D8, and GetAdventureNpcIds excludes via sub_020564B0. Matching indices are appended to the caller's buffer and the count is returned. Both tolerate a null buffer. The target reserves eight bytes of stack and redirects the pointer there when the argument is null, which is why the frame reserves space nothing else uses. That is reproduced with a local s16 scratch[4]. They merge into a new src/main_02056D70.c; extracting them splits asm/main_02056960.s, the trailing functions move verbatim into asm/main_02056EB8.s, and main.lsf gains the two objects. The buffer parameter is s16*, which is what both call sites pass and what the stores write. Their prototypes move out of main_02064FFC.h, where they were declared as void* while their callers were decompiled, into the new header. That tightening also required sub_02065050's two scratch buffers to change from u8[8] to s16[4] -- the same eight bytes, and already how sub_0206549C declares its own. sub_02065050 was rebuilt to confirm it stays byte-identical. The flag test reads the first byte of struct team_member directly, as (*(u8 *)m & 2). common.h models that byte as a bitfield of f_is_valid:1 followed by flags_unk1:7, and no access through those members reproduces the target's single tst: reading flags_unk1 emits a shift pair to extract the field first, and splitting bit 1 into its own one-bit member is worse still. The raw byte read is the only form that matches, so it is used here rather than changing a struct shared with the rest of the tree. No new names are introduced. struct team_member, struct team_member_table, their fields and TEAM_MEMBER_TABLE_PTR already exist, and both function names were already labelled. 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 <noreply@anthropic.com> |
||
|
|
86d3db8f56 |
Decomp sub_02055410, sub_02055474 and sub_020554D8
Decompile the three member-index predicates from asm/main_02054E4C.s. Each takes a member index, checks that TEAM_MEMBER_TABLE_PTR->members[idx] is valid, and returns whether that index is the one a particular main character occupies for the current game mode: sub_02055410 tests index 2 during a special episode and 0 otherwise, sub_02055474 tests 3 and 1, and sub_020554D8 tests 4 and is false outside a special episode. Those are the same indices GetMainCharacter1, GetMainCharacter2 and GetMainCharacter3 select, so each predicate answers "is this index that main character" without going through the accessor. They merge into a new src/main_02055410.c; extracting them splits asm/main_02054E4C.s, the trailing functions move verbatim into asm/main_02055528.s, and main.lsf gains the two objects. The return type is bool8 rather than int, and the parameter is subscripted as members[(s16)idx] so the index multiply compiles to smulbb. Their prototypes move out of main_02064FFC.h, where they were declared while sub_02065050 was decompiled, into the new header, which main_02064FFC.h now includes; sub_02065050 was rebuilt to confirm the return-type change leaves it byte-identical. The new header includes util.h. Without it the header is not self-contained: bool8 is declared there, and a header that uses it before common.h is reached makes the compiler infer int and then conflict with the real typedef. No new names are introduced. struct team_member_table, its fields, TEAM_MEMBER_TABLE_PTR, GetGameMode and GAME_MODE_SPECIAL_EPISODE already exist in the tree, and all three functions keep their sub_ names. 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 <noreply@anthropic.com> |
||
|
|
3256b16116 |
Decomp GetAppointedLeaderMemberIdx and sub_02056914
Decompile the last two accessors of this cluster from asm/main_02055894.s. Both resolve the appointed leader through the roster region of team_member_table: they read the active team from active_team, index the three number_active_team_members fields by it, and use that value to index active_roster_member_idxs. GetAppointedLeaderMemberIdx returns the resulting member index, or -1 when the first read is -1. sub_02056914 is its pointer counterpart, returning &members[index] or NULL when either read is -1 -- the same index/pointer pairing as GetHeroMemberIdx and GetHero. Each sits in the middle of asm/main_02055894.s and is not adjacent to the other, so each extraction splits the file: the trailing functions move verbatim into asm/main_020568DC.s and asm/main_02056960.s, the affected .inc files are regenerated, and main.lsf gains the four objects. GetAppointedLeaderMemberIdx returns u32, consistent with the other MemberIdx functions in this cluster. Its prototype and sub_02056914's move out of main_02064FFC.h, where they were declared while their callers were decompiled, into the new headers; main_02064FFC.h now includes those. sub_02065050 and sub_0206549C call them and were rebuilt to confirm the u32 change leaves both byte-identical. The three number_active_team_members fields are separate scalars in common.h but are indexed here as an array, which is what the asm does; the expression relies on them being contiguous, which the struct layout guarantees. No new names are introduced. struct team_member_table, struct ground_monster, their fields and TEAM_MEMBER_TABLE_PTR all already exist in the tree, and both function labels were already present. 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 <noreply@anthropic.com> |
||
|
|
ac61cc341c |
Decomp five team-member index accessors
Decompile GetHeroMemberIdx, GetPartnerMemberIdx, GetMainCharacter1MemberIdx, GetMainCharacter2MemberIdx and GetMainCharacter3MemberIdx from asm/main_02054E4C.s. Each returns the index of a TEAM_MEMBER_TABLE_PTR->members entry when that entry's is_valid bit is set, or -1 otherwise: hero is index 0, partner index 1, and the GetMainCharacter functions choose the index by game mode -- 2/3/4 during a special episode, 0/1/none otherwise. They are the index returning counterparts of the pointer accessors in the previous commit and merge into a new src/main_0205567C.c. The return type is u32. This matters: with a signed int return, the compiler recognises `valid ? 0 : -1` as the idiom -(!valid) and emits an arithmetic negate, but the target uses a conditional-move select. Under u32, -1 is 0xFFFFFFFF, the negate idiom no longer applies, and the compiler emits the select the target has. The distinction is only observable for hero, whose index is the constant 0; for the others the index is non-zero or runtime, so both signednesses produce the select. The whole family is typed u32 for consistency, and sub_02065050, which calls two of these, was rebuilt to confirm the type change leaves it byte-identical. No new names are introduced. struct team_member_table, struct ground_monster and TEAM_MEMBER_TABLE_PTR already exist in the tree, and the five function names were already labelled; this commit only fills in bodies. 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 <noreply@anthropic.com> |
||
|
|
45761ded07 |
Decomp five team-member accessors
Decompile GetHero, GetPartner, GetMainCharacter1, GetMainCharacter2 and GetMainCharacter3 from asm/main_02054E4C.s. Each returns a pointer to a struct ground_monster in TEAM_MEMBER_TABLE_PTR->members, or NULL when that entry's is_valid bit is clear: GetHero returns members[0], GetPartner members[1], and the GetMainCharacter functions pick the index from the game mode -- members[2]/[3]/[4] during a special episode, members[0]/[1]/NULL otherwise. They merge into a new src/main_02055770.c; extracting them splits asm/main_02054E4C.s, the trailing functions move verbatim into asm/main_02055894.s, and main.lsf gains the two objects. Their prototypes were temporarily declared in main_02064FFC.h for the previous commits; they move to the new main_02055770.h, which main_02064FFC.h now includes. sub_02056914 keeps its prototype there since it is still asm. No new names are introduced. struct ground_monster and struct team_member_table already exist in common.h, and these six function names were already labelled in the tree; this commit only fills in bodies. Decompiling these confirms by construction what the previous commits declared: the accessors return struct ground_monster*, so the ->id reads that feed the monster-id output of sub_0206549C are reading struct ground_monster::id, the documented "Monster ID" field. 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 <noreply@anthropic.com> |
||
|
|
4032598287 |
Use canonical ground_monster / team_member_table in sub_0206549C
The previous commit declared struct unk_020B0A48 for the records that TEAM_MEMBER_TABLE_PTR points at. That global is already typed in the tree as struct team_member_table (common.h), whose members[] elements are struct ground_monster -- a 0x44-byte record whose field at 0x4 is the documented s16 Monster ID. The placeholder was a redundant reinvention of it, and it declared TEAM_MEMBER_TABLE_PTR a second time, conflicting with the extern that two other decompiled files already use. Replace it with the canonical types: TEAM_MEMBER_TABLE_PTR becomes struct team_member_table*, the six accessors return struct ground_monster*, and the nine reads that fed *out through ->field_0x4 now read ->id (or ->members[i].id for the table-indexed pair). struct unk_020B0A48 is removed and common.h is included for the definitions. members[] sits at offset 0 of team_member_table and ground_monster has the same 0x44 stride and 0x4 field as the placeholder, so the reads compute identical addresses. Confirmed unchanged by a matching build. Beyond removing a duplicate struct, this makes the output type legible from the decompilation itself: every value written to *out in sub_0206549C now reads, in-tree, as a monster id -- a ground_monster.id, a monster-valued script variable, or an entry of a table that decodes to species. 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 <noreply@anthropic.com> |