#include "global.h"
#include "palette.h"
#include "constants/songs.h"
#include "sound.h"
#include "field_weather.h"
#include "overworld.h"
#include "field_fadetransition.h"
#include "menu.h"
#include "main.h"
#include "strings.h"
#include "string_util.h"
#include "event_data.h"
#include "script.h"
#include "pokemon_storage_system.h"

void StorageSystemCreatePrimaryMenu(u8 whichMenu);
void sub_80963D0(u8 curBox);
void sub_809658C(void);
void sub_80965F8(void);
void sub_809662C(void);
void sub_809665C(void);
void sub_80966F4(const u8 *sourceString, u16 x, u16 y);
void sub_8096784(struct Sprite *sprite);

EWRAM_DATA u8 gUnknown_02038474 = 0;
EWRAM_DATA struct UnkPSSStruct_2002370 *gUnknown_02038478 = NULL;

const struct PSS_MenuStringPtrs gUnknown_083B600C[] = {
    {PCText_WithdrawPoke, PCText_MovePokeToParty},
    {PCText_DepositPoke,  PCText_StorePokeInBox},
    {PCText_MovePoke,     PCText_OrganizeBoxesParty},
    {PCText_SeeYa,        PCText_ReturnToPrevMenu}
};

#if DEBUG
const u16 gUnknown_Debug_083E05F0[2] = {0};
#endif

const union AnimCmd gSpriteAnim_83B602C[] = {
    ANIMCMD_FRAME( 0, 5),
    ANIMCMD_END
};

const union AnimCmd gSpriteAnim_83B6034[] = {
    ANIMCMD_FRAME( 4, 5),
    ANIMCMD_END
};

const union AnimCmd gSpriteAnim_83B603C[] = {
    ANIMCMD_FRAME( 6, 5),
    ANIMCMD_END
};

const union AnimCmd gSpriteAnim_83B6044[] = {
    ANIMCMD_FRAME(10, 5),
    ANIMCMD_END
};

const union AnimCmd *const gSpriteAnimTable_83B604C[] = {
    gSpriteAnim_83B602C,
    gSpriteAnim_83B6034,
    gSpriteAnim_83B603C,
    gSpriteAnim_83B6044
};

const union AffineAnimCmd gSpriteAffineAnim_83B605C[] = {
    AFFINEANIMCMD_FRAME(0xe0, 0xe0, 0, 0),
    AFFINEANIMCMD_END
};

const union AffineAnimCmd *const gSpriteAffineAnimTable_83B606C[] = {
    gSpriteAffineAnim_83B605C
};

const u16 gBoxSelectionPopupPalette[] = INCBIN_U16("graphics/pokemon_storage/box_selection_popup.gbapal");

const u8 gBoxSelectionPopupCenterTiles[] = INCBIN_U8("graphics/pokemon_storage/box_selection_popup_center.4bpp");

const u8 gBoxSelectionPopupSidesTiles[] = INCBIN_U8("graphics/pokemon_storage/box_selection_popup_sides.4bpp");

u8 CountPokemonInBoxN(u8 boxId)
{
    u16 i;
    u16 count;

    for (i = 0, count = 0; i < 30; i++)
    {
        if (GetBoxMonData(gPokemonStorage.boxes[boxId] + i, MON_DATA_SPECIES) != 0)
            count++;
    }
    return count;
}

s16 GetIndexOfFirstEmptySpaceInBoxN(u8 boxId)
{
    u16 i;

    for (i = 0; i < 30; i++)
    {
        if (GetBoxMonData(gPokemonStorage.boxes[boxId] + i, MON_DATA_SPECIES) == 0)
            return i;
    }
    return -1;
}

u8 GetNumValidDaycarePartyMons(void)
{
    u16 i;
    u16 count;

    for (i = 0, count = 0; i < PARTY_SIZE; i++)
    {
        struct Pokemon *pokemon = gPlayerParty + i;
        if (GetMonData(pokemon, MON_DATA_SPECIES) != 0 && !GetMonData(pokemon, MON_DATA_IS_EGG))
            count++;
    }
    return count;
}

u8 CountAlivePartyMonsExceptOne(u8 toSkip)
{
    u16 i;
    u16 count;

    for (i = 0, count = 0; i < PARTY_SIZE; i++)
    {
        if (i != toSkip)
        {
            struct Pokemon *pokemon = gPlayerParty + i;
            if (GetMonData(pokemon, MON_DATA_SPECIES) != 0 && !GetMonData(pokemon, MON_DATA_IS_EGG) && GetMonData(pokemon, MON_DATA_HP) != 0)
                count++;
        }
    }
    return count;
}

u8 CountAlivePartyMonsExceptSelectedOne(void)
{
    return CountAlivePartyMonsExceptOne(gSpecialVar_0x8004);
}

u8 StorageSystemGetPartySize(void)
{
    u16 i;
    u16 count;

    for (i = 0, count = 0; i < PARTY_SIZE; i++)
    {
        if (GetMonData(gPlayerParty + i, MON_DATA_SPECIES) != 0)
            count++;
    }
    return count;
}

u8 *unref_sub_8095C60(u8 *dest, const u8 *src, u16 pad)
{
    u8 *_dest = StringCopy(dest, src);
    while (_dest < dest + pad)
    {
        *_dest++ = CHAR_SPACE;
    }
    *_dest = EOS;
    return _dest;
}

void sub_8095C8C(u16 *dest, u16 dest_left, u16 dest_top, const u16 *src, u16 src_left, u16 src_top, u16 dest_width, u16 dest_height, u16 src_width)
{
    u16 i;

    dest_width *= 2;
    dest += dest_top * 0x20 + dest_left;
    src += src_top * src_width + src_left;
    for (i = 0; i < dest_height; i++)
    {
        CpuCopy16(src, dest, dest_width);
        dest += 0x20;
        src += src_width;
    }
}

#define MAX_DMA_BLOCK_SIZE 0x1000
#define Dma3FillLarge_(value, dest, size, bit)             \
{                                                          \
    void *_dest = dest;                                    \
    u32 _size = size;                                      \
    while (1)                                              \
    {                                                      \
        if (_size <= MAX_DMA_BLOCK_SIZE)                   \
        {                                                  \
            DmaFill##bit(3, value, _dest, _size);          \
            break;                                         \
        }                                                  \
        DmaFill##bit(3, value, _dest, MAX_DMA_BLOCK_SIZE); \
        _dest += MAX_DMA_BLOCK_SIZE;                       \
        _size -= MAX_DMA_BLOCK_SIZE;                       \
    }                                                      \
}

#define Dma3FillLarge16_(value, dest, size) Dma3FillLarge_(value, dest, size, 16)
#define Dma3FillLarge32_(value, dest, size) Dma3FillLarge_(value, dest, size, 32)

void unref_sub_8095D08(u16 *dest, u16 dest_left, u16 dest_top, u16 width, u16 height)
{
    u16 i;

    dest += dest_top * 0x20 + dest_left;
    width *= 2;
    for (i = 0; i < height; dest += 0x20, i++)
        Dma3FillLarge16_(0, dest, width);
}

s16 StorageSystemGetNextMonIndex(struct BoxPokemon *box, s8 startIdx, u8 stopIdx, u8 mode)
{
    s16 i;
    s16 direction;
    if (mode == 0 || mode == 2)
    {
        direction = 1;
    }
    else
    {
        direction = -1;
    }
    if (mode == 2 || mode == 3)
    {
        for (i = startIdx + direction; i >= 0 && i <= stopIdx; i += direction)
        {
            if (GetBoxMonData(box + i, MON_DATA_SPECIES) != 0)
                return i;
        }
    }
    else
    {
        for (i = startIdx + direction; i >= 0 && i <= stopIdx; i += direction)
        {
            if (GetBoxMonData(box + i, MON_DATA_SPECIES) != 0 && !GetBoxMonData(box + i, MON_DATA_IS_EGG))
                return i;
        }
    }
    return -1;
}

void StorageSystemClearMessageWindow(void)
{
    Menu_BlankWindowRect(2, 15, 27, 18);
}

void Task_PokemonStorageSystem(u8 taskId)
{
    struct Task *task = gTasks + taskId;
    switch (task->data[0])
    {
        case 0:
            StorageSystemCreatePrimaryMenu(task->data[1]);
            Menu_DisplayDialogueFrame();
            Menu_PrintText(gUnknown_083B600C[task->data[1]].desc, 2, 15);
            task->data[0]++;
            break;
        case 1:
            if (IsWeatherNotFadingIn())
            {
                task->data[0]++;
            }
            break;
        case 2:
            task->data[2] = Menu_ProcessInput();
            switch(task->data[2])
            {
                case -2:
                    task->data[3] = task->data[1];
                    if (gMain.newKeys & DPAD_UP && --task->data[3] < 0)
                        task->data[3] = 3;

                    if (gMain.newKeys & DPAD_DOWN && ++task->data[3] > 3)
                        task->data[3] = 0;
                    if (task->data[1] != task->data[3])
                    {
                        task->data[1] = task->data[3];
                        StorageSystemClearMessageWindow();
                        Menu_PrintText(gUnknown_083B600C[task->data[1]].desc, 2, 15);
                    }
                    break;
                case -1:
                case  3:
                    Menu_DestroyCursor();
                    Menu_EraseWindowRect(0, 0, 13, 9);
                    ScriptContext2_Disable();
                    EnableBothScriptContexts();
                    DestroyTask(taskId);
                    break;
                default:
                    if (task->data[2] == 0 && StorageSystemGetPartySize() == PARTY_SIZE)
                    {
                        StorageSystemClearMessageWindow();
                        Menu_PrintText(gPCText_PartyFull2, 2, 15);
                        task->data[0] = 3;
                    }
                    else if (task->data[2] == 1 && StorageSystemGetPartySize() == 1)
                    {
                        StorageSystemClearMessageWindow();
                        Menu_PrintText(gPCText_OnlyOne, 2, 15);
                        task->data[0] = 3;
                    }
                    else
                    {
                        FadeScreen(1, 0);
                        task->data[0] = 4;
                    }
                    break;
            }
            break;
        case 3:
            if (gMain.newKeys & (A_BUTTON | B_BUTTON))
            {
                StorageSystemClearMessageWindow();
                Menu_PrintText(gUnknown_083B600C[task->data[1]].desc, 2, 15);
                task->data[0] = 2;
            }
            else if (gMain.newKeys & DPAD_UP)
            {
                if (--task->data[1] < 0)
                    task->data[1] = 3;
                Menu_MoveCursor(-1);
                task->data[1] = Menu_GetCursorPos();
                StorageSystemClearMessageWindow();
                Menu_PrintText(gUnknown_083B600C[task->data[1]].desc, 2, 15);
                task->data[0] = 2;
            }
            else if (gMain.newKeys & DPAD_DOWN)
            {
                if (++task->data[1] > 3)
                    task->data[1] = 0;
                Menu_MoveCursor(1);
                task->data[1] = Menu_GetCursorPos();
                StorageSystemClearMessageWindow();
                Menu_PrintText(gUnknown_083B600C[task->data[1]].desc, 2, 15);
                task->data[0] = 2;
            }
            break;
        case 4:
            if (!gPaletteFade.active)
            {
                task_intro_29(task->data[2]);
                DestroyTask(taskId);
            }
            break;
    }
}

void ShowPokemonStorageSystem(void)
{
    u8 taskId = CreateTask(Task_PokemonStorageSystem, 80);
    gTasks[taskId].data[0] = 0;
    gTasks[taskId].data[1] = 0;
    ScriptContext2_Enable();
}

void FieldCB_ReturnToOverworld(void)
{
    u8 taskId = CreateTask(Task_PokemonStorageSystem, 80);
    gTasks[taskId].data[0] = 0;
    gTasks[taskId].data[1] = gUnknown_02038474;
    pal_fill_black();
}

void StorageSystemCreatePrimaryMenu(u8 whichMenu)
{
    Menu_DrawStdWindowFrame(0, 0, 13, 9);
    Menu_PrintItems(1, 1, 4, (const struct MenuAction *)gUnknown_083B600C);
    InitMenu(0, 1, 1, 4, whichMenu, 12);
}

void sub_80961A8(void)
{
    gUnknown_02038474 = gPokemonStorageSystemPtr->unk_0005;
    gFieldCallback = FieldCB_ReturnToOverworld;
    SetMainCallback2(CB2_ReturnToField);
}

void ResetPokemonStorageSystem(void)
{
    u16 boxId;
    u16 boxMon;

    gPokemonStorage.currentBox = 0;
    for (boxId = 0; boxId < 14; boxId++)
    {
        for (boxMon = 0; boxMon < 30; boxMon++)
        {
            ZeroBoxMonData(gPokemonStorage.boxes[boxId] + boxMon);
        }
    }
    for (boxId = 0; boxId < 14; boxId++)
    {
        u8 *dest = StringCopy(gPokemonStorage.boxNames[boxId], gPCText_BOX);
        ConvertIntToDecimalStringN(dest, boxId + 1, STR_CONV_MODE_LEFT_ALIGN, 2);
    }
    for (boxId = 0; boxId < 14; boxId++)
    {
        gPokemonStorage.wallpaper[boxId] = boxId & 0x03;
    }
}

#if DEBUG
NAKED
void debug_sub_80A3904(void)
{
	asm("\
	push	{r4, r5, r6, r7, lr}\n\
	mov	r7, sl\n\
	mov	r6, r9\n\
	mov	r5, r8\n\
	push	{r5, r6, r7}\n\
	add	sp, sp, #0xffffffe4\n\
	mov	r0, #0x0\n\
	mov	r8, r0\n\
	mov	r7, r8\n\
	mov	r1, #0x14\n\
	str	r1, [sp, #0x18]\n\
	mov	r2, #0xff\n\
	mov	r9, r2\n\
._162:\n\
	mov	r5, #0x0\n\
	cmp	r7, #0\n\
	beq	._160	@cond_branch\n\
	mov	r0, #0xe\n\
	mov	r8, r0\n\
	b	._158\n\
._160:\n\
	bl	Random\n\
	lsl	r0, r0, #0x10\n\
	lsr	r0, r0, #0x10\n\
	str	r0, [sp, #0x14]\n\
	mov	r2, r8\n\
	lsl	r1, r2, #0x2\n\
	add r1, r1, r8\n\
	lsl	r3, r1, #0x4\n\
	sub	r3, r3, r1\n\
	lsl	r3, r3, #0x5\n\
	lsl	r1, r5, #0x2\n\
	add	r1, r1, r5\n\
	lsl	r1, r1, #0x4\n\
	ldr	r2, ._163       @ gPokemonStorage\n\
	add	r1, r1, r2\n\
	add	r6, r3, r1\n\
	ldr	r2, ._163 + 4   @ gUnknown_Debug_083E05F0\n\
	lsl	r1, r7, #0x1\n\
	add	r1, r1, r2\n\
	ldrh	r4, [r1]\n\
	add	r5, r5, #0x1\n\
	lsl	r2, r5, #0x18\n\
	lsr	r2, r2, #0x18\n\
	mov	r1, #0x0\n\
	str	r1, [sp]\n\
	str	r1, [sp, #0x4]\n\
	mov	r1, #0x1\n\
	mov	sl, r1\n\
	str	r1, [sp, #0x8]\n\
	str	r0, [sp, #0xc]\n\
	add	r0, r6, #0\n\
	add	r1, r4, #0\n\
	mov	r3, #0x20\n\
	bl	CreateBoxMon\n\
	cmp	r4, #0\n\
	beq	._157	@cond_branch\n\
	cmp	r4, #0xac\n\
	bne	._156	@cond_branch\n\
	add	r0, sp, #0x10\n\
	mov	r2, sl\n\
	strb	r2, [r0]\n\
	add	r0, r6, #0\n\
	mov	r1, #0x2d\n\
	add	r2, sp, #0x10\n\
	bl	SetBoxMonData\n\
._156:\n\
	bl	Random\n\
	mov	r1, r9\n\
	and	r1, r1, r0\n\
	str	r1, [sp, #0x14]\n\
	add	r4, sp, #0x14\n\
	add	r0, r6, #0\n\
	mov	r1, #0x16\n\
	add	r2, r4, #0\n\
	bl	SetBoxMonData\n\
	bl	Random\n\
	mov	r1, r9\n\
	and	r1, r1, r0\n\
	str	r1, [sp, #0x14]\n\
	add	r0, r6, #0\n\
	mov	r1, #0x17\n\
	add	r2, r4, #0\n\
	bl	SetBoxMonData\n\
	bl	Random\n\
	mov	r1, r9\n\
	and	r1, r1, r0\n\
	str	r1, [sp, #0x14]\n\
	add	r0, r6, #0\n\
	mov	r1, #0x18\n\
	add	r2, r4, #0\n\
	bl	SetBoxMonData\n\
	bl	Random\n\
	mov	r1, r9\n\
	and	r1, r1, r0\n\
	str	r1, [sp, #0x14]\n\
	add	r0, r6, #0\n\
	mov	r1, #0x21\n\
	add	r2, r4, #0\n\
	bl	SetBoxMonData\n\
	bl	Random\n\
	mov	r1, r9\n\
	and	r1, r1, r0\n\
	str	r1, [sp, #0x14]\n\
	add	r0, r6, #0\n\
	mov	r1, #0x2f\n\
	add	r2, r4, #0\n\
	bl	SetBoxMonData\n\
	bl	Random\n\
	mov	r1, r9\n\
	and	r1, r1, r0\n\
	str	r1, [sp, #0x14]\n\
	add	r0, r6, #0\n\
	mov	r1, #0x30\n\
	add	r2, r4, #0\n\
	bl	SetBoxMonData\n\
	ldr	r0, [sp, #0x18]\n\
	cmp	r0, #0\n\
	beq	._157	@cond_branch\n\
	sub	r0, r0, #0x1\n\
	lsl	r0, r0, #0x10\n\
	lsr	r0, r0, #0x10\n\
	str	r0, [sp, #0x18]\n\
	mov	r1, sl\n\
	str	r1, [sp, #0x14]\n\
	add	r0, r6, #0\n\
	mov	r1, #0x32\n\
	add	r2, r4, #0\n\
	bl	SetBoxMonData\n\
._157:\n\
	add	r0, r7, #1\n\
	lsl	r0, r0, #0x10\n\
	lsr	r7, r0, #0x10\n\
	lsl	r0, r5, #0x10\n\
	lsr	r5, r0, #0x10\n\
	cmp	r5, #0x1d\n\
	bhi	._158	@cond_branch\n\
	cmp	r7, #0\n\
	bne	._159	@cond_branch\n\
	b	._160\n\
._159:\n\
	mov	r2, #0xe\n\
	mov	r8, r2\n\
._158:\n\
	mov	r0, r8\n\
	add	r0, r0, #0x1\n\
	lsl	r0, r0, #0x10\n\
	lsr	r0, r0, #0x10\n\
	mov	r8, r0\n\
	cmp	r0, #0xd\n\
	bhi	._161	@cond_branch\n\
	b	._162\n\
._161:\n\
	add	sp, sp, #0x1c\n\
	pop	{r3, r4, r5}\n\
	mov	r8, r3\n\
	mov	r9, r4\n\
	mov	sl, r5\n\
	pop	{r4, r5, r6, r7}\n\
	pop	{r0}\n\
	bx	r0\n\
._164:\n\
	.align	2, 0\n\
._163:\n\
	.word	gPokemonStorage+0x4\n\
	.word	gUnknown_Debug_083E05F0");
}
#endif

void sub_8096264(struct UnkPSSStruct_2002370 *a0, u16 tileTag, u16 palTag, u8 a3)
{
    struct SpritePalette palette = {
        gBoxSelectionPopupPalette, palTag
    };
    struct SpriteSheet sheets[] = {
        {gBoxSelectionPopupCenterTiles, 0x800, tileTag},
        {gBoxSelectionPopupSidesTiles,  0x180, tileTag + 1},
        {}
    };
    LoadSpritePalette(&palette);
    LoadSpriteSheets(sheets);
    gUnknown_02038478 = a0;
    a0->unk_0240 = tileTag;
    a0->unk_0242 = palTag;
    a0->unk_023e = a3;
}

void sub_8096310(void)
{
    FreeSpritePaletteByTag(gUnknown_02038478->unk_0242);
    FreeSpriteTilesByTag(gUnknown_02038478->unk_0240);
    FreeSpriteTilesByTag(gUnknown_02038478->unk_0240 + 1);
}

void sub_809634C(u8 curBox)
{
    sub_80963D0(curBox);
}

void sub_809635C(void)
{
    sub_809658C();
}

u8 sub_8096368(void)
{
    if (gMain.newKeys & B_BUTTON)
    {
        PlaySE(SE_SELECT);
        return 201;
    }
    if (gMain.newKeys & A_BUTTON)
    {
        PlaySE(SE_SELECT);
        return gUnknown_02038478->curBox;
    }
    if (gMain.newKeys & DPAD_LEFT)
    {
        PlaySE(SE_SELECT);
        sub_809662C();
    }
    else if (gMain.newKeys & DPAD_RIGHT)
    {
        PlaySE(SE_SELECT);
        sub_80965F8();
    }
    return 200;
}

void sub_80963D0(u8 curBox)
{
    u16 i;
    u8 spriteId;
    struct SpriteTemplate template;
    struct OamData oamData = {};
    oamData.size = 3;
    oamData.paletteNum = 1;
    template = (struct SpriteTemplate){
        0, 0, &oamData, gDummySpriteAnimTable, NULL, gDummySpriteAffineAnimTable, SpriteCallbackDummy
    };

    gUnknown_02038478->curBox = curBox;
    template.tileTag = gUnknown_02038478->unk_0240;
    template.paletteTag = gUnknown_02038478->unk_0242;

    spriteId = CreateSprite(&template, 0xA0, 0x60, 0);
    gUnknown_02038478->unk_0000 = gSprites + spriteId;

    oamData.shape = ST_OAM_V_RECTANGLE;
    oamData.size = 1;
    template.tileTag = gUnknown_02038478->unk_0240 + 1;
    template.anims = gSpriteAnimTable_83B604C;
    for (i = 0; i < 4; i++)
    {
        u16 r5;
        spriteId = CreateSprite(&template, 0x7c, 0x50, gUnknown_02038478->unk_023e);
        gUnknown_02038478->unk_0004[i] = gSprites + spriteId;
        r5 = 0;
        if (i & 2)
        {
            gUnknown_02038478->unk_0004[i]->x = 0xc4;
            r5 = 2;
        }
        if (i & 1)
        {
            gUnknown_02038478->unk_0004[i]->y = 0x70;
            gUnknown_02038478->unk_0004[i]->oam.size = 0;
            r5++;
        }
        StartSpriteAnim(gUnknown_02038478->unk_0004[i], r5);
    }
    for (i = 0; i < 2; i++)
    {
        gUnknown_02038478->unk_0020[i] = sub_809A9A0(72 * i + 0x7c, 0x58, i, 0, gUnknown_02038478->unk_023e);
        if (gUnknown_02038478->unk_0020[i])
        {
            gUnknown_02038478->unk_0020[i]->data[0] = (i == 0 ? -1 : 1);
            gUnknown_02038478->unk_0020[i]->callback = sub_8096784;
        }
    }
    sub_809665C();
}

void sub_809658C(void)
{
    u16 i;
    if (gUnknown_02038478->unk_0000)
    {
        DestroySprite(gUnknown_02038478->unk_0000);
        gUnknown_02038478->unk_0000 = NULL;
    }
    for (i = 0; i < 4; i++)
    {
        if (gUnknown_02038478->unk_0004[i])
        {
            DestroySprite(gUnknown_02038478->unk_0004[i]);
            gUnknown_02038478->unk_0004[i] = NULL;
        }
    }
    for (i = 0; i < 2; i++)
    {
        if (gUnknown_02038478->unk_0020[i])
            DestroySprite(gUnknown_02038478->unk_0020[i]);
    }
}

void sub_80965F8(void)
{
    if (++gUnknown_02038478->curBox > 13)
        gUnknown_02038478->curBox = 0;
    sub_809665C();
}

void sub_809662C(void)
{
    gUnknown_02038478->curBox = (gUnknown_02038478->curBox == 0 ? 13 : gUnknown_02038478->curBox - 1);
    sub_809665C();
}

void sub_809665C(void)
{
    u8 nPokemonInBox = CountPokemonInBoxN(gUnknown_02038478->curBox);
    u8 *stringVar = gStringVar1;

    stringVar[0] = EXT_CTRL_CODE_BEGIN;
    stringVar[1] = EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW;
    stringVar[2] = 0x0F; // TEXT_COLOR_WHITE2
    stringVar[3] = 0x01; // TEXT_COLOR_DARK_GREY
    stringVar[4] = 0x0E; // TEXT_COLOR_LIGHT_BLUE
    stringVar += 5;

    stringVar = StringCopy(stringVar, gPokemonStorage.boxNames[gUnknown_02038478->curBox]);

    stringVar[0] = CHAR_NEWLINE;
    stringVar[1] = EXT_CTRL_CODE_BEGIN;
    stringVar[2] = EXT_CTRL_CODE_CLEAR;
    if (nPokemonInBox < 10)
        stringVar[3] = 0x28;
    else
        stringVar[3] = 0x22;
    stringVar += 4;

    stringVar = ConvertIntToDecimalString(stringVar, nPokemonInBox);

    stringVar[0] = CHAR_SLASH;
    stringVar[1] = CHAR_0 + 3;
    stringVar[2] = CHAR_0 + 0;
    stringVar[3] = EOS;
    sub_80966F4(gStringVar1, 0, 1);
}

void sub_80966F4(const u8 *sourceString, u16 x, u16 y)
{
    u16 *vdest = (u16 *)(BG_CHAR_ADDR(4) + (GetSpriteTileStartByTag(gUnknown_02038478->unk_0240) * 32) + y * 256 + x * 32);
    u8 *tileBuff = gUnknown_083B6DB8;
    DmaFill16(3, 0x1111, tileBuff, 0x400);
    Text_InitWindow8004E3C(&gWindowTemplate_81E6D38, tileBuff, sourceString);
    DmaCopy16(3, tileBuff, vdest, 0x400);
}

void sub_8096784(struct Sprite *sprite)
{
    if (++sprite->data[1] > 3)
    {
        sprite->data[1] = 0;
        sprite->x2 += sprite->data[0];
        if (++sprite->data[2] > 5)
        {
            sprite->data[2] = 0;
            sprite->x2 = 0;
        }
    }
}
