summaryrefslogtreecommitdiff
path: root/src/pokenav_match_call_ui.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pokenav_match_call_ui.c')
-rw-r--r--src/pokenav_match_call_ui.c1266
1 files changed, 1266 insertions, 0 deletions
diff --git a/src/pokenav_match_call_ui.c b/src/pokenav_match_call_ui.c
new file mode 100644
index 000000000..7443c0bdb
--- /dev/null
+++ b/src/pokenav_match_call_ui.c
@@ -0,0 +1,1266 @@
+#include "global.h"
+#include "pokenav.h"
+#include "window.h"
+#include "strings.h"
+#include "text.h"
+#include "bg.h"
+#include "menu.h"
+#include "decompress.h"
+
+struct UnknownSubSubStruct_0203CF40 {
+ u8 bg;
+ u8 unk1;
+ u8 unk2;
+ u8 unk3;
+ u8 unk4;
+ u8 fontId;
+ u16 unk6;
+ u16 windowId;
+ u16 unkA;
+ u16 unkC;
+ u16 unkE;
+};
+
+struct MatchCallWindowState {
+ // The index of the element at the top of the window.
+ u16 windowTopIndex;
+ u16 listLength;
+ u16 unk4;
+ // The index of the cursor, relative to the top of the window.
+ u16 selectedIndexOffset;
+ u16 visibleEntries;
+ u16 unkA;
+ u32 unkC;
+ u32 unk10;
+};
+
+struct UnknownInnerStruct_81C81D4
+{
+ struct UnknownSubSubStruct_0203CF40 unk0;
+ u32 unk10;
+ u32 unk14;
+ u32 unk18;
+ u32 unk1C;
+ s32 unk20;
+ s32 unk24;
+ u32 unk28;
+ s32 unk2C;
+ u32 unk30;
+ void (*unk34)(u32, u8*);
+ void (*unk38)(u16, u32, u32);
+ struct Sprite *rightArrow;
+ struct Sprite *upArrow;
+ struct Sprite *downArrow;
+ u8 unkTextBuffer[0x40];
+};
+
+// Generally at index 0x11 (17)
+struct UnknownSubStruct_81C81D4
+{
+ struct UnknownInnerStruct_81C81D4 unk0;
+ u8 tilemapBuffer[0x800];
+ struct MatchCallWindowState unk888;
+ u32 unk89C;
+ u32 unk8A0;
+};
+
+struct MatchCallListTemplate
+{
+ u32 unk0;
+ u16 unk4;
+ u16 unk6;
+ u8 unk8;
+ u8 unk9;
+ u8 unkA;
+ u8 unkB;
+ u8 unkC;
+ u8 unkD;
+ u8 unkE;
+ void (*unk10)(u32, u8 *a1);
+ void (*unk14)(u16 a0, u32 a1, u32 a2);
+};
+
+extern void sub_81CBD48(u16 windowId, u32 a1);
+extern void sub_81DB620(u32 windowId, u32 a1, u32 a2, u32 a3, u32 a4);
+extern u8 *sub_81CAFD8(u16 a0, u32 a1);
+
+void sub_81C82E4(struct UnknownSubStruct_81C81D4 *a0);
+u32 sub_81C91AC(struct UnknownInnerStruct_81C81D4 *a0, const struct BgTemplate *a1, struct MatchCallListTemplate *a2, s32 a3);
+void sub_81C9160(struct MatchCallWindowState *a0, struct MatchCallListTemplate *a1);
+void SpriteCB_MatchCallUpArrow(struct Sprite *sprite);
+void SpriteCB_MatchCallDownArrow(struct Sprite *sprite);
+void SpriteCB_MatchCallRightArrow(struct Sprite *sprite);
+void ToggleMatchCallArrows(struct UnknownInnerStruct_81C81D4 *a0, u32 a1);
+void sub_81C8FE0(struct UnknownInnerStruct_81C81D4 *a0);
+void sub_81C8EF8(struct MatchCallWindowState *a0, struct UnknownInnerStruct_81C81D4 *a1);
+void sub_81C8ED0(void);
+void sub_81C8E54(struct MatchCallWindowState *a0, struct UnknownInnerStruct_81C81D4 *a1, u32 a2);
+void PrintMatchCallFieldNames(struct UnknownInnerStruct_81C81D4 *a0, u32 a1);
+void sub_81C8D4C(struct MatchCallWindowState *a0, struct UnknownInnerStruct_81C81D4 *a1);
+void sub_81C8CB4(struct MatchCallWindowState *a0, struct UnknownInnerStruct_81C81D4 *a1);
+void sub_81C8B70(struct UnknownSubSubStruct_0203CF40 *a0, u32 a1, u32 a2);
+void sub_81C8568(s32 a0, struct UnknownInnerStruct_81C81D4 *a1);
+void sub_81C83AC(u32 a0, u32 a1, u32 a2, u32 a3, u32 a4, struct UnknownInnerStruct_81C81D4 *a5);
+void sub_81C837C(struct MatchCallWindowState *a0, struct UnknownInnerStruct_81C81D4 *a1);
+void sub_81C835C(struct UnknownSubSubStruct_0203CF40 *a0);
+u32 LoopedTask_sub_81C8254(s32 a0);
+bool32 sub_81C83E0(void);
+u32 LoopedTask_sub_81C83F0(s32 a0);
+u32 LoopedTask_sub_81C85A0(s32 a0);
+u32 LoopedTask_sub_81C8870(s32 a0);
+u32 LoopedTask_sub_81C8A28(s32 a0);
+u32 LoopedTask_sub_81C8958(s32 a0);
+
+static const u16 sMatchcallArrowPaletteData[] = INCBIN_U16("graphics/pokenav/arrows_matchcall.gbapal");
+static const u32 sMatchcallArrowSpriteSheetData[] = INCBIN_U32("graphics/pokenav/arrows_matchcall.4bpp.lz");
+
+static const u8 sPokenavColors_0861FBE4[] =
+{
+ 0, 2, 5
+};
+
+static const u8 *const sMatchCallFieldNames[] =
+{
+ gText_NavgearMatchCall_Strategy,
+ gText_NavgearMatchCall_TrainerPokemon,
+ gText_NavgearMatchCall_SelfIntroduction
+};
+
+static const u8 sMatchCallFieldColors[] =
+{
+ 1, 4, 5
+};
+
+static const u8 sUnknown_0861FBF7[] =
+{
+ 2, 4, 6, 7, 0
+};
+
+static const struct CompressedSpriteSheet sMatchcallArrowSpriteSheet[] =
+{
+ {
+ .data = sMatchcallArrowSpriteSheetData,
+ .size = 192,
+ .tag = 0xA
+ }
+};
+
+static const struct SpritePalette sMatchcallArrowPalette[] =
+{
+ {
+ .data = sMatchcallArrowPaletteData,
+ .tag = 0x14
+ },
+ {}
+};
+
+static const struct OamData sMatchCallRightArrowSpriteOam =
+{
+ .y = 0,
+ .affineMode = ST_OAM_AFFINE_OFF,
+ .objMode = ST_OAM_OBJ_NORMAL,
+ .bpp = ST_OAM_4BPP,
+ .shape = 2, //SPRITE_SHAPE(16x8),
+ .x = 0,
+ .size = 0, //SPRITE_SIZE(16x8),
+ .tileNum = 0,
+ .priority = 2,
+ .paletteNum = 0
+};
+
+static const struct SpriteTemplate sMatchCallRightArrowSprite =
+{
+ .tileTag = 0xA,
+ .paletteTag = 0x14,
+ .oam = &sMatchCallRightArrowSpriteOam,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCB_MatchCallRightArrow
+};
+
+static const struct OamData sMatchCallUpDownArrowSpriteOam =
+{
+ .y = 0,
+ .affineMode = ST_OAM_AFFINE_OFF,
+ .objMode = ST_OAM_OBJ_NORMAL,
+ .bpp = ST_OAM_4BPP,
+ .shape = 1, //SPRITE_SHAPE(8x16),
+ .x = 0,
+ .size = 0, //SPRITE_SIZE(8x16),
+ .tileNum = 0,
+ .priority = 2,
+ .paletteNum = 0
+};
+
+static const struct SpriteTemplate sMatchCallUpDownArrowSprite =
+{
+ .tileTag = 0xA,
+ .paletteTag = 0x14,
+ .oam = &sMatchCallUpDownArrowSpriteOam,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCallbackDummy
+};
+
+EWRAM_DATA u32 gUnknown_0203CF44 = 0;
+
+bool32 sub_81C81D4(const struct BgTemplate *arg0, struct MatchCallListTemplate *arg1, s32 arg2)
+{
+ u32 v1;
+ struct UnknownSubStruct_81C81D4 *structPtr;
+
+ structPtr = AllocSubstruct(0x11, sizeof(struct UnknownSubStruct_81C81D4));
+
+ if (structPtr == NULL)
+ return FALSE;
+
+ sub_81C9160(&structPtr->unk888, arg1);
+
+ v1 = sub_81C91AC(&structPtr->unk0, arg0, arg1, arg2);
+ if (v1 == 0)
+ return FALSE;
+
+ CreateLoopedTask(LoopedTask_sub_81C8254, 6);
+ return TRUE;
+}
+
+bool32 sub_81C8224(void)
+{
+ return FuncIsActiveLoopedTask(LoopedTask_sub_81C8254);
+}
+
+void sub_81C8234(void)
+{
+ struct UnknownSubStruct_81C81D4 *structPtr;
+
+ structPtr = GetSubstructPtr(0x11);
+ sub_81C8FE0(&structPtr->unk0);
+ RemoveWindow(structPtr->unk0.unk0.windowId);
+ FreePokenavSubstruct(0x11);
+}
+
+u32 LoopedTask_sub_81C8254(s32 a0)
+{
+ struct UnknownSubStruct_81C81D4 *structPtr;
+
+ if (IsDma3ManagerBusyWithBgCopy())
+ return 2;
+
+ structPtr = GetSubstructPtr(0x11);
+
+ switch (a0)
+ {
+ case 0:
+ sub_81C82E4(structPtr);
+ return 0;
+ case 1:
+ sub_81C835C(&structPtr->unk0.unk0);
+ return 0;
+ case 2:
+ sub_81C837C(&structPtr->unk888, &structPtr->unk0);
+ return 0;
+ case 3:
+ if (sub_81C83E0())
+ {
+ return 2;
+ }
+ else
+ {
+ sub_81C8ED0();
+ return 1;
+ }
+ case 4:
+ sub_81C8EF8(&structPtr->unk888, &structPtr->unk0);
+ return 4;
+ default:
+ return 4;
+ }
+}
+
+void sub_81C82E4(struct UnknownSubStruct_81C81D4 *a0)
+{
+ u16 v1 = (a0->unk0.unk0.unk1 << 12) | a0->unk0.unk0.unk6;
+ // TODO: When #553 is merged, use a PALETTE_NUM_TO_FILL_VALUE(1) macro here...
+ sub_8199DF0(a0->unk0.unk0.bg, 0x11, a0->unk0.unk0.unk6, 1);
+ // ...and PALETTE_NUM_TO_FILL_VALUE(4) here.
+ sub_8199DF0(a0->unk0.unk0.bg, 0x44, a0->unk0.unk0.unk6 + 1, 1);
+ SetBgTilemapBuffer(a0->unk0.unk0.bg, a0->tilemapBuffer);
+ FillBgTilemapBufferRect_Palette0(a0->unk0.unk0.bg, v1, 0, 0, 32, 32);
+ ChangeBgY(a0->unk0.unk0.bg, 0, 0);
+ ChangeBgX(a0->unk0.unk0.bg, 0, 0);
+ ChangeBgY(a0->unk0.unk0.bg, a0->unk0.unk0.unk3 << 11, 2);
+ CopyBgTilemapBufferToVram(a0->unk0.unk0.bg);
+}
+
+void sub_81C835C(struct UnknownSubSubStruct_0203CF40 *a0)
+{
+ FillWindowPixelBuffer(a0->windowId, PIXEL_FILL(1));
+ PutWindowTilemap(a0->windowId);
+ CopyWindowToVram(a0->windowId, 1);
+}
+
+void sub_81C837C(struct MatchCallWindowState *a0, struct UnknownInnerStruct_81C81D4 *a1)
+{
+ s32 v1;
+ s32 v2;
+
+ // TODO: Clean this up.
+ v1 = a0->listLength - a0->windowTopIndex;
+ v2 = a0->visibleEntries;
+ if (v1 > a0->visibleEntries)
+ v1 = v2;
+ sub_81C83AC(a0->unk10, a0->windowTopIndex, v1, a0->unkC, 0, a1);
+}
+
+void sub_81C83AC(u32 a0, u32 a1, u32 a2, u32 a3, u32 a4, struct UnknownInnerStruct_81C81D4 *a5)
+{
+ if (a2 == 0)
+ return;
+
+ a5->unk1C = a0 + a1 * a3;
+ a5->unk18 = a3;
+ a5->unk0.unkC = 0;
+ a5->unk0.unkE = a2;
+ a5->unk14 = a1;
+ a5->unk10 = a4;
+ CreateLoopedTask(LoopedTask_sub_81C83F0, 5);
+}
+
+bool32 sub_81C83E0(void)
+{
+ return FuncIsActiveLoopedTask(LoopedTask_sub_81C83F0);
+}
+
+u32 LoopedTask_sub_81C83F0(s32 a0)
+{
+ struct UnknownInnerStruct_81C81D4 *structPtr;
+ u32 v1;
+
+ structPtr = &((struct UnknownSubStruct_81C81D4*)GetSubstructPtr(0x11))->unk0;
+ switch (a0)
+ {
+ case 0:
+ v1 = (structPtr->unk0.unkA + structPtr->unk0.unkC + structPtr->unk10) & 0xF;
+ structPtr->unk34(structPtr->unk1C, structPtr->unkTextBuffer);
+ if (structPtr->unk38 != NULL)
+ // Accessing unk0.windowId as if it were a u16...?
+ // It's accessed as a u8 again in the very next line...
+ structPtr->unk38(*(u16*)(&structPtr->unk0.windowId), structPtr->unk14, v1);
+
+ AddTextPrinterParameterized(structPtr->unk0.windowId, structPtr->unk0.fontId, structPtr->unkTextBuffer, 8, (v1 << 4) + 1, 255, NULL);
+
+ if (++structPtr->unk0.unkC >= structPtr->unk0.unkE)
+ {
+ if (structPtr->unk38 != NULL)
+ CopyWindowToVram(structPtr->unk0.windowId, 3);
+ else
+ CopyWindowToVram(structPtr->unk0.windowId, 2);
+ return 0;
+ }
+ else
+ {
+ structPtr->unk1C += structPtr->unk18;
+ structPtr->unk14++;
+ return 3;
+ }
+ case 1:
+ if (IsDma3ManagerBusyWithBgCopy())
+ return 2;
+ else
+ return 4;
+ default:
+ return 4;
+ }
+}
+
+bool32 ShouldShowUpArrow(void)
+{
+ u16 v1;
+ s32 v2;
+ struct UnknownSubStruct_81C81D4 *structPtr;
+ structPtr = GetSubstructPtr(0x11);
+
+ return structPtr->unk888.windowTopIndex != 0;
+}
+
+bool32 ShouldShowDownArrow(void)
+{
+ struct MatchCallWindowState *subPtr;
+ struct UnknownSubStruct_81C81D4 *structPtr;
+ structPtr = GetSubstructPtr(0x11);
+ subPtr = &structPtr->unk888;
+
+ return subPtr->windowTopIndex + subPtr->visibleEntries < subPtr->listLength;
+}
+
+
+#ifdef NONMATCHING
+// This has some register renaming issues (r4, r5, and r6 are all switched around), and
+// for some reason it's creating two copies of subPtr->unk0.
+// TODO: Now I know why it's making two copies - one of them is UnknownInnerStruct_81C81D4.
+void MatchCall_MoveWindow(s32 a0, bool32 a1)
+{
+ s32 v1;
+ struct MatchCallWindowState *subPtr;
+ struct UnknownSubStruct_81C81D4 *structPtr;
+ structPtr = GetSubstructPtr(0x11);
+ subPtr = &structPtr->unk888;
+
+ if (a0 < 0)
+ {
+ // This is where the issue is. subPtr->windowTopIndex is being stored in r1 and then copied to
+ // r2... and then r2 is read for the if statement, r1 is read for the function call,
+ // and then both are clobbered as expected. Between those two uses, no writes to r1/r2
+ // happen; it doesn't need to be duplicated/moved at all.
+ if (subPtr->windowTopIndex + a0 < 0)
+ v1 = -1 * subPtr->windowTopIndex;
+ else
+ v1 = a0;
+ if (a1)
+ sub_81C83AC(subPtr->unk10, subPtr->windowTopIndex + v1, v1 * -1, subPtr->unkC, v1, structPtr);
+ }
+ else if (a1)
+ {
+
+ gUnknown_0203CF44 = subPtr->windowTopIndex + subPtr->visibleEntries;
+ if ((s32)(gUnknown_0203CF44) + a0 >= (s32)subPtr->listLength)
+ v1 = subPtr->listLength - gUnknown_0203CF44;
+ else
+ v1 = a0;
+
+ sub_81C83AC(subPtr->unk10, gUnknown_0203CF44, v1, subPtr->unkC, subPtr->visibleEntries, structPtr);
+ // Needed to prevent GCC from combining the two sub_81C83AC calls.
+ asm("");
+ }
+ else
+ {
+ v1 = a0;
+ }
+
+ sub_81C8568(v1, structPtr);
+ subPtr->windowTopIndex++;
+}
+#else
+NAKED
+void MatchCall_MoveWindow(s32 a0, bool32 a1)
+{
+ asm(".syntax unified\n\
+ push {r4-r7,lr}\n\
+ sub sp, 0x8\n\
+ adds r6, r0, 0\n\
+ adds r4, r1, 0\n\
+ movs r0, 0x11\n\
+ bl GetSubstructPtr\n\
+ adds r7, r0, 0\n\
+ ldr r0, =0x00000888\n\
+ adds r5, r7, r0\n\
+ cmp r6, 0\n\
+ bge _081C8524\n\
+ ldrh r1, [r5]\n\
+ adds r0, r1, r6\n\
+ cmp r0, 0\n\
+ bge _081C850A\n\
+ negs r6, r1\n\
+_081C850A:\n\
+ cmp r4, 0\n\
+ beq _081C854E\n\
+ ldr r0, [r5, 0x10]\n\
+ adds r1, r6\n\
+ negs r2, r6\n\
+ ldr r3, [r5, 0xC]\n\
+ str r6, [sp]\n\
+ str r7, [sp, 0x4]\n\
+ bl sub_81C83AC\n\
+ b _081C854E\n\
+ .pool\n\
+_081C8524:\n\
+ cmp r4, 0\n\
+ beq _081C854E\n\
+ ldr r2, =gUnknown_0203CF44\n\
+ ldrh r1, [r5]\n\
+ ldrh r0, [r5, 0x8]\n\
+ adds r4, r1, r0\n\
+ str r4, [r2]\n\
+ adds r0, r4, r6\n\
+ ldrh r1, [r5, 0x2]\n\
+ cmp r0, r1\n\
+ blt _081C853C\n\
+ subs r6, r1, r4\n\
+_081C853C:\n\
+ ldr r0, [r5, 0x10]\n\
+ ldr r3, [r5, 0xC]\n\
+ ldrh r1, [r5, 0x8]\n\
+ str r1, [sp]\n\
+ str r7, [sp, 0x4]\n\
+ adds r1, r4, 0\n\
+ adds r2, r6, 0\n\
+ bl sub_81C83AC\n\
+_081C854E:\n\
+ adds r0, r6, 0\n\
+ adds r1, r7, 0\n\
+ bl sub_81C8568\n\
+ ldrh r0, [r5]\n\
+ adds r0, r6\n\
+ strh r0, [r5]\n\
+ add sp, 0x8\n\
+ pop {r4-r7}\n\
+ pop {r0}\n\
+ bx r0\n\
+ .pool\n\
+ .syntax divided");
+}
+#endif
+
+void sub_81C8568(s32 a0, struct UnknownInnerStruct_81C81D4 *a1)
+{
+ a1->unk20 = GetBgY(a1->unk0.bg);
+ a1->unk24 = a1->unk20 + (a0 << 12);
+ if (a0 > 0)
+ a1->unk30 = 1;
+ else
+ a1->unk30 = 2;
+ a1->unk2C = a0;
+ a1->unk28 = CreateLoopedTask(LoopedTask_sub_81C85A0, 6);
+}
+
+u32 LoopedTask_sub_81C85A0(s32 a0)
+{
+ s32 y;
+ s32 v1;
+ bool32 flag;
+ struct UnknownInnerStruct_81C81D4 *structPtr;
+ structPtr = &((struct UnknownSubStruct_81C81D4 *)GetSubstructPtr(0x11))->unk0;
+
+ switch (a0)
+ {
+ case 0:
+ if (sub_81C83E0() == FALSE)
+ return 1;
+ else
+ return 2;
+ case 1:
+ flag = FALSE;
+ y = GetBgY(structPtr->unk0.bg);
+ v1 = ChangeBgY(structPtr->unk0.bg, 0x1000, structPtr->unk30);
+ if (structPtr->unk30 == 2)
+ {
+ if ((y > structPtr->unk24 || y <= structPtr->unk20) && v1 <= structPtr->unk24)
+ {
+ flag = TRUE;
+ }
+ }
+ else
+ {
+ if ((y < structPtr->unk24 || y >= structPtr->unk20) && v1 >= structPtr->unk24)
+ {
+ flag = TRUE;
+ }
+ }
+ if (flag)
+ {
+ structPtr->unk0.unkA = (structPtr->unk0.unkA + structPtr->unk2C) & 0xF;
+ ChangeBgY(structPtr->unk0.bg, structPtr->unk24, 0);
+ return 4;
+ }
+ else
+ {
+ return 2;
+ }
+ default:
+ return 4;
+ }
+}
+
+bool32 sub_81C8630(void)
+{
+ struct UnknownSubStruct_81C81D4 *structPtr;
+ structPtr = GetSubstructPtr(0x11);
+ return IsLoopedTaskActive(structPtr->unk0.unk28);
+}
+
+struct MatchCallWindowState *GetMatchCallWindowStruct(void)
+{
+ struct UnknownSubStruct_81C81D4 *structPtr;
+ structPtr = GetSubstructPtr(0x11);
+ return &structPtr->unk888;
+}
+
+u32 MatchCall_MoveCursorUp(void)
+{
+ struct MatchCallWindowState *structPtr;
+ structPtr = GetMatchCallWindowStruct();
+
+ if (structPtr->selectedIndexOffset != 0)
+ {
+ structPtr->selectedIndexOffset--;
+ return 1;
+ }
+ else
+ {
+ if (ShouldShowUpArrow())
+ {
+ MatchCall_MoveWindow(-1, TRUE);
+ return 2;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+}
+
+u32 MatchCall_MoveCursorDown(void)
+{
+ struct MatchCallWindowState *structPtr;
+ structPtr = GetMatchCallWindowStruct();
+
+ if (structPtr->windowTopIndex + structPtr->selectedIndexOffset < structPtr->listLength - 1)
+ {
+ if (structPtr->selectedIndexOffset < structPtr->visibleEntries - 1)
+ {
+ structPtr->selectedIndexOffset++;
+ return 1;
+ }
+ else if (!ShouldShowDownArrow())
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ return 0;
+ }
+ MatchCall_MoveWindow(1, TRUE);
+ return 2;
+}
+
+u32 MatchCall_PageUp(void)
+{
+ struct MatchCallWindowState *structPtr;
+ s32 scroll;
+
+ structPtr = GetMatchCallWindowStruct();
+ if (ShouldShowUpArrow())
+ {
+ if (structPtr->windowTopIndex >= structPtr->visibleEntries)
+ scroll = structPtr->visibleEntries;
+ else
+ scroll = structPtr->windowTopIndex;
+ MatchCall_MoveWindow(scroll * -1, TRUE);
+ return 2;
+ }
+ else if (structPtr->selectedIndexOffset != 0)
+ {
+ structPtr->selectedIndexOffset = 0;
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+u32 MatchCall_PageDown(void)
+{
+ struct MatchCallWindowState *structPtr;
+ structPtr = GetMatchCallWindowStruct();
+
+ if (ShouldShowDownArrow())
+ {
+ s32 scroll;
+ s32 windowBottomIndex;
+ s32 v3;
+ windowBottomIndex = structPtr->windowTopIndex + structPtr->visibleEntries;
+ scroll = structPtr->unk4 - structPtr->windowTopIndex;
+ if (windowBottomIndex <= structPtr->unk4)
+ scroll = structPtr->visibleEntries;
+ MatchCall_MoveWindow(scroll, TRUE);
+ return 2;
+ }
+ else
+ {
+ s32 cursor;
+ s32 lastVisibleIndex;
+ if (structPtr->listLength >= structPtr->visibleEntries)
+ {
+ cursor = structPtr->selectedIndexOffset;
+ lastVisibleIndex = structPtr->visibleEntries;
+ }
+ else
+ {
+ cursor = structPtr->selectedIndexOffset;
+ lastVisibleIndex = structPtr->listLength;
+ }
+ lastVisibleIndex -= 1;
+ if (cursor >= lastVisibleIndex)
+ {
+ return 0;
+ }
+ else
+ {
+ structPtr->selectedIndexOffset = lastVisibleIndex;
+ return 1;
+ }
+ }
+}
+
+u32 GetSelectedMatchCall(void)
+{
+ struct MatchCallWindowState *structPtr;
+ structPtr = GetMatchCallWindowStruct();
+
+ return structPtr->windowTopIndex + structPtr->selectedIndexOffset;
+}
+
+u32 GetMatchCallListTopIndex(void)
+{
+ struct MatchCallWindowState *structPtr;
+ structPtr = GetMatchCallWindowStruct();
+
+ return structPtr->windowTopIndex;
+}
+
+void sub_81C877C(void)
+{
+ struct UnknownSubStruct_81C81D4 *structPtr;
+ structPtr = GetSubstructPtr(0x11);
+ structPtr->unk89C = 0;
+ structPtr->unk8A0 = CreateLoopedTask(LoopedTask_sub_81C8870, 6);
+}
+
+void sub_81C87AC(u16 a0)
+{
+ u16 temp;
+ struct UnknownSubStruct_81C81D4 *structPtr;
+ structPtr = GetSubstructPtr(0x11);
+ temp = structPtr->unk888.windowTopIndex;
+ temp += a0;
+ structPtr->unk888.windowTopIndex = temp;
+ structPtr->unk89C = 0;
+ structPtr->unk8A0 = CreateLoopedTask(LoopedTask_sub_81C8958, 6);
+}
+
+void sub_81C87F0(void)
+{
+ struct UnknownSubStruct_81C81D4 *structPtr;
+ structPtr = GetSubstructPtr(0x11);
+ structPtr->unk89C = 0;
+ structPtr->unk8A0 = CreateLoopedTask(LoopedTask_sub_81C8A28, 6);
+}
+
+bool32 sub_81C8820(void)
+{
+ struct UnknownSubStruct_81C81D4 *structPtr;
+ structPtr = GetSubstructPtr(0x11);
+ return IsLoopedTaskActive(structPtr->unk8A0);
+}
+
+void sub_81C8838(void)
+{
+ struct UnknownSubStruct_81C81D4 *structPtr;
+ struct MatchCallWindowState *subStr;
+ structPtr = GetSubstructPtr(0x11);
+ subStr = &structPtr->unk888;
+ structPtr->unk0.unk38(structPtr->unk0.unk0.windowId, subStr->windowTopIndex + subStr->selectedIndexOffset, (structPtr->unk0.unk0.unkA + subStr->selectedIndexOffset) & 0xF);
+ CopyWindowToVram(structPtr->unk0.unk0.windowId, 1);
+}
+
+u32 LoopedTask_sub_81C8870(s32 a0)
+{
+ struct UnknownSubStruct_81C81D4 *structPtr;
+ u16 v1;
+ u32 v2;
+
+ // Needed to fix a register renaming issue.
+ register u16* temp asm("r1");
+ structPtr = GetSubstructPtr(0x11);
+
+ switch (a0)
+ {
+ case 0:
+ ToggleMatchCallArrows(&structPtr->unk0, 1);
+ // fall-through
+ case 1:
+ if (structPtr->unk89C != structPtr->unk888.selectedIndexOffset)
+ sub_81C8B70(&structPtr->unk0.unk0, structPtr->unk89C, 1);
+
+ structPtr->unk89C++;
+ return 0;
+ case 2:
+ if (IsDma3ManagerBusyWithBgCopy())
+ return 2;
+
+ if (structPtr->unk89C != structPtr->unk888.visibleEntries)
+ return 6;
+
+ if (structPtr->unk888.selectedIndexOffset != 0)
+ sub_81C8B70(&structPtr->unk0.unk0, structPtr->unk89C, structPtr->unk888.selectedIndexOffset);
+
+ return 0;
+ case 3:
+ if (IsDma3ManagerBusyWithBgCopy())
+ return 2;
+ temp = &structPtr->unk888.selectedIndexOffset;
+ v1 = *temp;
+ if (v1 == 0)
+ return 4;
+
+ MatchCall_MoveWindow(v1, FALSE);
+ return 0;
+ case 4:
+ v2 = sub_81C8630();
+ if (v2)
+ return 2;
+
+ structPtr->unk888.selectedIndexOffset = v2;
+ return 4;
+ default:
+ return 4;
+ }
+}
+
+u32 LoopedTask_sub_81C8958(s32 a0)
+{
+ struct UnknownSubStruct_81C81D4 *structPtr;
+ structPtr = GetSubstructPtr(0x11);
+ if (IsDma3ManagerBusyWithBgCopy())
+ return 2;
+
+ switch (a0)
+ {
+ case 0:
+ sub_81C8CB4(&structPtr->unk888, &structPtr->unk0);
+ break;
+ case 1:
+ PrintMatchCallFieldNames(&structPtr->unk0, 0);
+ break;
+ case 2:
+ sub_81C8E54(&structPtr->unk888, &structPtr->unk0, 0);
+ break;
+ case 3:
+ PrintMatchCallFieldNames(&structPtr->unk0, 1);
+ break;
+ case 4:
+ sub_81C8E54(&structPtr->unk888, &structPtr->unk0, 1);
+ break;
+ case 5:
+ PrintMatchCallFieldNames(&structPtr->unk0, 2);
+ break;
+ case 6:
+ sub_81C8E54(&structPtr->unk888, &structPtr->unk0, 2);
+ break;
+ case 7:
+ sub_81C8E54(&structPtr->unk888, &structPtr->unk0, 3);
+ break;
+ default:
+ return 4;
+ }
+ return 0;
+}
+
+u32 LoopedTask_sub_81C8A28(s32 a0)
+{
+ struct UnknownSubStruct_81C81D4 *structPtr;
+ struct MatchCallWindowState *subPtr888;
+ register struct UnknownInnerStruct_81C81D4 *subPtr0 asm("r2");
+ s32 v4;
+
+ if (IsDma3ManagerBusyWithBgCopy())
+ {
+ return 2;
+ }
+
+ structPtr = GetSubstructPtr(0x11);
+ subPtr888 = &structPtr->unk888;
+ subPtr0 = &structPtr->unk0;
+
+ switch (a0)
+ {
+ default:
+ return 4;
+ case 0:
+ sub_81C8D4C(subPtr888, subPtr0);
+ return 0;
+ case 1:
+ {
+ s32 v1;
+ s32 v2;
+ u32 *v3;
+ register s32 v4 asm("r5");
+
+ v3 = &structPtr->unk89C;
+ v1 = *v3 + 1;
+ *v3 = v1;
+ if (v1 < structPtr->unk888.visibleEntries)
+ {
+ sub_81C8B70(&subPtr0->unk0, v1, 1);
+ return 2;
+ }
+
+ *v3 = 0;
+ if (subPtr888->listLength <= subPtr888->visibleEntries)
+ {
+ register u32 temp asm("r0");
+ temp = subPtr888->windowTopIndex;
+ if (temp == 0)
+ return 9;
+ v2 = temp;
+ }
+ else
+ {
+ register s32 temp asm("r1");
+ v2 = subPtr888->windowTopIndex + subPtr888->visibleEntries;
+ temp = (s32)subPtr888->listLength;
+ if (v2 <= temp)
+ return 9;
+ v2 -= temp;
+ }
+ v4 = v2 * -1;
+ sub_81C8B70(&subPtr0->unk0, v4, v2);
+ subPtr888->selectedIndexOffset = v2;
+ *v3 = v4;
+ return 0;
+ }
+ case 2:
+ MatchCall_MoveWindow(structPtr->unk89C, FALSE);
+ return 0;
+ case 3:
+ if (sub_81C8630())
+ return 2;
+
+ structPtr->unk89C = 0;
+ return 1;
+ case 4:
+ sub_81C83AC(subPtr888->unk10, subPtr888->windowTopIndex + structPtr->unk89C, 1, subPtr888->unkC, structPtr->unk89C, &structPtr->unk0);
+ return 0;
+ case 5:
+ if (sub_81C83E0())
+ return 2;
+
+ v4 = ++structPtr->unk89C;
+ if (v4 >= subPtr888->listLength || v4 >= subPtr888->visibleEntries)
+ return 1;
+ return 9;
+ case 6:
+ ToggleMatchCallArrows(subPtr0, 0);
+ return 4;
+ }
+}
+
+void sub_81C8B70(struct UnknownSubSubStruct_0203CF40 *a0, u32 a1, u32 a2)
+{
+ u8 *v1;
+ u32 v2;
+
+ v1 = (u8*)GetWindowAttribute(a0->windowId, WINDOW_TILE_DATA);
+ v2 = a0->unk4 * 64;
+
+ a1 = (a0->unkA + a1) & 0xF;
+ if ((s32)(a1 + a2) <= 16)
+ {
+ CpuFastFill8(PIXEL_FILL(1), v1 + a1 * v2, a2 * v2);
+ CopyWindowToVram(a0->windowId, 2);
+ }
+ else
+ {
+ u32 v3;
+ u32 v4;
+
+ v3 = 16 - a1;
+ v4 = a2 - v3;
+
+ CpuFastFill8(PIXEL_FILL(1), v1 + a1 * v2, v3 * v2);
+ CpuFastFill8(PIXEL_FILL(1), v1, v4 * v2);
+ CopyWindowToVram(a0->windowId, 2);
+ }
+
+ a2 -= 1;
+ for (a2; a2 != -1; a1 = (a1 + 1) & 0xF, a2--)
+ {
+ sub_81CBD48(a0->windowId, a1);
+ }
+
+ CopyWindowToVram(a0->windowId, 1);
+}
+
+void sub_81C8C64(struct UnknownSubSubStruct_0203CF40 *a0, u32 a1)
+{
+ u16 *v1;
+ register u32 v2 asm("r0");
+ u32 v3;
+
+ v1 = (u16*)GetBgTilemapBuffer(GetWindowAttribute(a0->windowId, WINDOW_BG));
+
+ v1 = &v1[(a0->unkA << 6) + a0->unk2 - 1];
+
+ if (a1 != 0)
+ {
+ v2 = a0->unk1 << 12;
+ v3 = a0->unk6 + 1;
+ }
+ else
+ {
+ v2 = a0->unk1 << 12;
+ v3 = a0->unk6;
+ }
+ {
+ register u16 v5 asm("r1");
+ register u32 v6 asm("r0");
+ v6 = (v3 | v2);
+ v6 = v6 << 16;
+ v5 = v6 >> 16;
+ v1[0] = v5;
+ v1[0x20] = v5;
+ }
+}
+
+void sub_81C8CB4(struct MatchCallWindowState *a0, struct UnknownInnerStruct_81C81D4 *a1)
+{
+ u8 colors[3];
+
+
+ memcpy(colors, sPokenavColors_0861FBE4, ARRAY_COUNT(sPokenavColors_0861FBE4));
+
+ a1->unk34(a0->unk10 + a0->unkC * a0->windowTopIndex, a1->unkTextBuffer);
+ a1->unk38(a1->unk0.windowId, a0->windowTopIndex, a1->unk0.unkA);
+ FillWindowPixelRect(a1->unk0.windowId, PIXEL_FILL(4), 0, a1->unk0.unkA * 16, a1->unk0.unk4 * 8, 16);
+ AddTextPrinterParameterized3(a1->unk0.windowId, a1->unk0.fontId, 8, (a1->unk0.unkA * 16) + 1, colors, TEXT_SPEED_FF, a1->unkTextBuffer);
+ sub_81C8C64(&a1->unk0, 1);
+ CopyWindowRectToVram(a1->unk0.windowId, 3, 0, a1->unk0.unkA * 2, a1->unk0.unk4, 2);
+}
+
+void sub_81C8D4C(struct MatchCallWindowState *a0, struct UnknownInnerStruct_81C81D4 *a1)
+{
+ a1->unk34(a0->unk10 + a0->unkC * a0->windowTopIndex, a1->unkTextBuffer);
+ FillWindowPixelRect(a1->unk0.windowId, PIXEL_FILL(1), 0, a1->unk0.unkA * 16, a1->unk0.unk4 * 8, 16);
+ AddTextPrinterParameterized(a1->unk0.windowId, a1->unk0.fontId, a1->unkTextBuffer, 8, a1->unk0.unkA * 16 + 1, TEXT_SPEED_FF, NULL);
+ sub_81C8C64(&a1->unk0, 0);
+ CopyWindowToVram(a1->unk0.windowId, 3);
+}
+
+void PrintMatchCallFieldNames(struct UnknownInnerStruct_81C81D4 *a0, u32 fieldId)
+{
+ const u8 *fieldNames[3];
+ u8 colors[3];
+ u32 r4;
+ u32 r5;
+ u32 tmp;
+ u32 one;
+
+ memcpy(fieldNames, sMatchCallFieldNames, sizeof(sMatchCallFieldNames));
+ memcpy(colors, sMatchCallFieldColors, sizeof(sMatchCallFieldColors));
+
+ r4 = a0->unk0.unkA;
+ tmp = fieldId * 2 + 1;
+ r4 += tmp;
+ r4 &= 0xF;
+ FillWindowPixelRect(a0->unk0.windowId, PIXEL_FILL(1), 0, r4 << 4, a0->unk0.unk4, 16);
+
+ // This is a fake match. It should be this:
+ // AddTextPrinterParameterized3(a0->unk0.windowId, 7, 2, r4 << 4 + 1, colors, TEXT_SPEED_FF, fieldNames[fieldId]);
+ // But the original GCC does some clever reuse of the `1` constant that the current GCC doesn't.
+ one = 1;
+ AddTextPrinterParameterized3(a0->unk0.windowId, 7, 2, (r4 << 4) + one, colors, one - 2, fieldNames[fieldId]);
+ CopyWindowRectToVram(a0->unk0.windowId, 2, 0, r4 << 1, a0->unk0.unk4, 2);
+}
+
+void sub_81C8E54(struct MatchCallWindowState *a0, struct UnknownInnerStruct_81C81D4 *a1, u32 a2)
+{
+ const u8 *str;
+ u32 r6;
+
+ r6 = (a1->unk0.unkA + sUnknown_0861FBF7[a2]) & 0xF;
+
+ str = sub_81CAFD8(a0->windowTopIndex, a2);
+ if (str != NULL) {
+ sub_81DB620(a1->unk0.windowId, 1, r6 * 2, a1->unk0.unk4 - 1, 2);
+ AddTextPrinterParameterized(a1->unk0.windowId, 7, str, 2, (r6 << 4) + 1, TEXT_SPEED_FF, NULL);
+ CopyWindowRectToVram(a1->unk0.windowId, 2, 0, r6 * 2, a1->unk0.unk4, 2);
+ }
+}
+
+void sub_81C8ED0(void)
+{
+ u32 i;
+ const struct CompressedSpriteSheet *ptr;
+
+ for (i = 0, ptr = sMatchcallArrowSpriteSheet; i < ARRAY_COUNT(sMatchcallArrowSpriteSheet); ptr++, i++)
+ {
+ LoadCompressedSpriteSheet(ptr);
+ }
+ Pokenav_AllocAndLoadPalettes(sMatchcallArrowPalette);
+}
+
+void sub_81C8EF8(struct MatchCallWindowState *a0, struct UnknownInnerStruct_81C81D4 *a1)
+{
+ register u32 spriteId asm("r3");
+ s16 temp;
+
+ spriteId = (u8)CreateSprite(&sMatchCallRightArrowSprite, a1->unk0.unk2 * 8 + 3, (a1->unk0.unk3 + 1) * 8, 7);
+ a1->rightArrow = &gSprites[spriteId];
+
+ temp = a1->unk0.unk2 * 8 + (a1->unk0.unk4 - 1) * 4;
+ spriteId = (u8)CreateSprite(&sMatchCallUpDownArrowSprite, temp, a1->unk0.unk3 * 8 + a0->visibleEntries * 16, 7);
+ a1->downArrow = &gSprites[spriteId];
+ a1->downArrow->oam.tileNum += 2;
+ a1->downArrow->callback = SpriteCB_MatchCallDownArrow;
+
+ spriteId = (u8)CreateSprite(&sMatchCallUpDownArrowSprite, temp, a1->unk0.unk3 * 8, 7);
+ a1->upArrow = &gSprites[spriteId];
+ a1->upArrow->oam.tileNum += 4;
+ a1->upArrow->callback = SpriteCB_MatchCallUpArrow;
+}
+
+void sub_81C8FE0(struct UnknownInnerStruct_81C81D4 *a0)
+{
+ DestroySprite(a0->rightArrow);
+ DestroySprite(a0->upArrow);
+ DestroySprite(a0->downArrow);
+ FreeSpriteTilesByTag(0xA);
+ FreeSpritePaletteByTag(0x14);
+}
+
+void ToggleMatchCallArrows(struct UnknownInnerStruct_81C81D4 *a0, bool32 shouldHide)
+{
+ if (shouldHide)
+ {
+ a0->rightArrow->callback = SpriteCallbackDummy;
+ a0->upArrow->callback = SpriteCallbackDummy;
+ a0->downArrow->callback = SpriteCallbackDummy;
+ }
+ else
+ {
+ a0->rightArrow->callback = SpriteCB_MatchCallRightArrow;
+ a0->upArrow->callback = SpriteCB_MatchCallUpArrow;
+ a0->downArrow->callback = SpriteCB_MatchCallDownArrow;
+ }
+ a0->rightArrow->invisible = shouldHide;
+ a0->upArrow->invisible = shouldHide;
+ a0->downArrow->invisible = shouldHide;
+}
+
+void SpriteCB_MatchCallRightArrow(struct Sprite *sprite)
+{
+ struct UnknownSubStruct_81C81D4 *structPtr;
+ structPtr = GetSubstructPtr(0x11);
+ sprite->pos2.y = structPtr->unk888.selectedIndexOffset << 4;
+}
+
+void SpriteCB_MatchCallDownArrow(struct Sprite *sprite)
+{
+ if (sprite->data[7] == 0 && ShouldShowDownArrow())
+ sprite->invisible = FALSE;
+ else
+ sprite->invisible = TRUE;
+
+ if (++sprite->data[0] > 3)
+ {
+ s16 offset;
+
+ sprite->data[0] = 0;
+ offset = (sprite->data[1] + 1) & 7;
+ sprite->data[1] = offset;
+ sprite->pos2.y = offset;
+ }
+}
+
+void SpriteCB_MatchCallUpArrow(struct Sprite *sprite)
+{
+ if (sprite->data[7] == 0 && ShouldShowUpArrow())
+ sprite->invisible = FALSE;
+ else
+ sprite->invisible = TRUE;
+
+ if (++sprite->data[0] > 3)
+ {
+ s16 offset;
+
+ sprite->data[0] = 0;
+ offset = (sprite->data[1] + 1) & 7;
+ sprite->data[1] = offset;
+ sprite->pos2.y = -1 * offset;
+ }
+}
+
+void ToggleMatchCallVerticalArrows(bool32 shouldHide)
+{
+ struct UnknownSubStruct_81C81D4 *structPtr;
+ structPtr = GetSubstructPtr(0x11);
+ structPtr->unk0.upArrow->data[7] = shouldHide;
+ structPtr->unk0.downArrow->data[7] = shouldHide;
+}
+
+void sub_81C9160(struct MatchCallWindowState *a0, struct MatchCallListTemplate *a1)
+{
+ u32 unused1 = a0->unk10 = a1->unk0;
+ u32 v0 = a1->unk6;
+ u32 zero = 0;
+ u32 unused2 = a0->windowTopIndex = v0;
+ u32 v1 = a0->listLength = a1->unk4;
+
+ a0->unkC = a1->unk8;
+ a0->visibleEntries = a1->unkC;
+ if (a0->visibleEntries >= (u16)v1)
+ {
+ a0->windowTopIndex = 0;
+ a0->unk4 = 0;
+ a0->selectedIndexOffset = v0;
+ }
+ else
+ {
+ s32 v2;
+ a0->unk4 = a0->listLength - a0->visibleEntries;
+ v2 = a0->windowTopIndex + a0->visibleEntries;
+ if (v2 > a0->listLength) {
+ a0->selectedIndexOffset = v2 - a0->listLength;
+ a0->windowTopIndex = v0 - a0->selectedIndexOffset;
+ }
+ else
+ {
+ a0->selectedIndexOffset = 0;
+ }
+ }
+}
+
+u32 sub_81C91AC(struct UnknownInnerStruct_81C81D4 *a0, const struct BgTemplate *a1, struct MatchCallListTemplate *a2, s32 a3)
+{
+ register u32 raw_bg asm("r4") = ((a1->bg) << 30);
+ u8 bg = raw_bg >> 30;
+ u32 unknown = 0;
+ struct WindowTemplate window;
+ u8 bg_again;
+
+ a0->unk0.bg = bg;
+ a0->unk0.unk6 = a3;
+ a0->unk34 = a2->unk10;
+ a0->unk38 = a2->unk14;
+ a0->unk0.unk1 = a2->unkD;
+ a0->unk0.unk2 = a2->unk9;
+ a0->unk0.unk3 = a2->unkB;
+ a0->unk0.unk4 = a2->unkA;
+ a0->unk0.fontId = a2->unkE;
+
+ window.bg = raw_bg >> 30;
+ window.tilemapLeft = a2->unk9;
+ window.tilemapTop = 0;
+ window.width = a2->unkA;
+ window.height = 32;
+ window.paletteNum = a2->unkD;
+ window.baseBlock = a3 + 2;
+
+ a0->unk0.windowId = AddWindow(&window);
+ if (a0->unk0.windowId == 0xFF)
+ {
+ return 0;
+ }
+ else
+ {
+ a0->unk0.unkA = unknown;
+ a0->rightArrow = NULL;
+ a0->upArrow = NULL;
+ a0->downArrow = NULL;
+ return 1;
+ }
+} \ No newline at end of file