#include "global.h"
#include "gflib.h"
#include "decompress.h"
#include "item.h"
#include "item_menu_icons.h"
#include "menu.h"
#include "new_menu_helpers.h"
#include "pokemon_storage_system_internal.h"
#include "trig.h"
#include "constants/items.h"

static u8 sub_80961D8(void);
static bool32 sub_8096210(u8 cursorArea, u8 cursorPos);
static u8 sub_8096258(u8 cursorArea, u8 cursorPos);
static void sub_80962F0(u8 id, u8 cursorArea, u8 cursorPos);
static void sub_8096408(u8 id, const u32 * tiles, const u32 * pal);
static void sub_80964B8(u8 id, u8 affineAnimNo);
static void sub_80964E8(u8 id, u8 command, u8 cursorArea, u8 cursorPos);
static void sub_8096624(u8 id, bool8 show);
static const u32 *GetItemIconPic(u16 itemId);
static const u32 *GetItemIconPalette(u16 itemId);
static void sub_8096898(u32 x);
static void sub_809692C(struct Sprite * sprite);
static void sub_8096958(struct Sprite * sprite);
static void sub_80969BC(struct Sprite * sprite);
static void sub_80969F4(struct Sprite * sprite);
static void sub_8096A74(struct Sprite * sprite);
static void sub_8096B10(struct Sprite * sprite);
static void sub_8096BAC(struct Sprite * sprite);

static const u32 gUnknown_83D35DC[] = INCBIN_U32("graphics/interface/pss_unk_83D35DC.4bpp");

static const struct OamData gUnknown_83D365C = {
    .y = 0,
    .affineMode = ST_OAM_AFFINE_NORMAL,
    .objMode = ST_OAM_OBJ_NORMAL,
    .mosaic = FALSE,
    .bpp = ST_OAM_4BPP,
    .shape = SPRITE_SHAPE(32x32),
    .x = 0,
    .matrixNum = 0,
    .size = SPRITE_SIZE(32x32),
    .tileNum = 0x000,
    .priority = 1,
    .paletteNum = 0,
    .affineParam = 0
};

static const union AffineAnimCmd gUnknown_83D3664[] = {
    AFFINEANIMCMD_FRAME(128, 128, 0, 0),
    AFFINEANIMCMD_END
};

static const union AffineAnimCmd gUnknown_83D3674[] = {
    AFFINEANIMCMD_FRAME(88, 88, 0, 0),
    AFFINEANIMCMD_FRAME(5, 5, 0, 8),
    AFFINEANIMCMD_END
};

static const union AffineAnimCmd gUnknown_83D368C[] = {
    AFFINEANIMCMD_FRAME(128, 128, 0, 0),
    AFFINEANIMCMD_FRAME(-5, -5, 0, 8),
    AFFINEANIMCMD_END
};

static const union AffineAnimCmd gUnknown_83D36A4[] = {
    AFFINEANIMCMD_FRAME(128, 128, 0, 0),
    AFFINEANIMCMD_FRAME(10, 10, 0, 12),
    AFFINEANIMCMD_FRAME(256, 256, 0, 0),
    AFFINEANIMCMD_END
};

static const union AffineAnimCmd gUnknown_83D36C4[] = {
    AFFINEANIMCMD_FRAME(256, 256, 0, 0),
    AFFINEANIMCMD_FRAME(-10, -10, 0, 12),
    AFFINEANIMCMD_FRAME(128, 128, 0, 0),
    AFFINEANIMCMD_END
};

static const union AffineAnimCmd gUnknown_83D36E4[] = {
    AFFINEANIMCMD_FRAME(256, 256, 0, 0),
    AFFINEANIMCMD_FRAME(-5, -5, 0, 16),
    AFFINEANIMCMD_END
};

static const union AffineAnimCmd gUnknown_83D36FC[] = {
    AFFINEANIMCMD_FRAME(256, 256, 0, 0),
    AFFINEANIMCMD_END
};

static const union AffineAnimCmd *const gUnknown_83D370C[] = {
    gUnknown_83D3664,
    gUnknown_83D3674,
    gUnknown_83D368C,
    gUnknown_83D36A4,
    gUnknown_83D36C4,
    gUnknown_83D36E4,
    gUnknown_83D36FC
};

static const struct SpriteTemplate gUnknown_83D3728 = {
    .tileTag = TAG_TILE_7,
    .paletteTag = TAG_PAL_DACB,
    .oam = &gUnknown_83D365C,
    .anims = gDummySpriteAnimTable,
    .images = NULL,
    .affineAnims = gUnknown_83D370C,
    .callback = SpriteCallbackDummy,
};

void sub_8095B5C(void)
{
    s32 i;
    u8 spriteId;
    struct CompressedSpriteSheet spriteSheet;
    struct SpriteTemplate spriteTemplate;
    static u32 gUnknown_3000FE8[0x61];

    if (gPSSData->boxOption == BOX_OPTION_MOVE_ITEMS)
    {
        spriteSheet.data = gUnknown_3000FE8;
        spriteSheet.size = 0x200;
        spriteTemplate = gUnknown_83D3728;

        for (i = 0; i < MAX_ITEM_ICONS; i++)
        {
            spriteSheet.tag = TAG_TILE_7 + i;
            LoadCompressedSpriteSheet(&spriteSheet);
            gPSSData->itemIconSprites[i].tiles = GetSpriteTileStartByTag(spriteSheet.tag) * 32 + (void*)(OBJ_VRAM0);
            gPSSData->itemIconSprites[i].palIndex = AllocSpritePalette(TAG_PAL_DACB + i);
            gPSSData->itemIconSprites[i].palIndex *= 16;
            gPSSData->itemIconSprites[i].palIndex += 0x100;
            spriteTemplate.tileTag = TAG_TILE_7 + i;
            spriteTemplate.paletteTag = TAG_PAL_DACB + i;
            spriteId = CreateSprite(&spriteTemplate, 0, 0, 11);
            gPSSData->itemIconSprites[i].sprite = &gSprites[spriteId];
            gPSSData->itemIconSprites[i].sprite->invisible = TRUE;
            gPSSData->itemIconSprites[i].active = 0;
        }
    }
    gPSSData->movingItem = ITEM_NONE;
}

void sub_8095C84(u8 cursorArea, u8 cursorPos)
{
    u16 heldItem;

    if (gPSSData->boxOption != BOX_OPTION_MOVE_ITEMS)
        return;
    if (sub_8096210(cursorArea, cursorPos))
        return;

    switch (cursorArea)
    {
    case CURSOR_AREA_IN_BOX:
        if (!GetCurrentBoxMonData(cursorPos, MON_DATA_SANITY_HAS_SPECIES))
            return;
        heldItem = GetCurrentBoxMonData(cursorPos, MON_DATA_HELD_ITEM);
        break;
    case CURSOR_AREA_IN_PARTY:
        if (!GetMonData(&gPlayerParty[cursorPos], MON_DATA_SANITY_HAS_SPECIES))
            return;
        heldItem = GetMonData(&gPlayerParty[cursorPos], MON_DATA_HELD_ITEM);
        break;
    default:
        return;
    }

    if (heldItem != ITEM_NONE)
    {
        const u32 *tiles = GetItemIconPic(heldItem);
        const u32 *pal = GetItemIconPalette(heldItem);
        u8 id = sub_80961D8();

        sub_80962F0(id, cursorArea, cursorPos);
        sub_8096408(id, tiles, pal);
        sub_80964B8(id, 1);
        sub_8096624(id, TRUE);
    }
}

void sub_8095D44(u8 cursorArea, u8 cursorPos)
{
    u8 id;

    if (gPSSData->boxOption != BOX_OPTION_MOVE_ITEMS)
        return;

    id = sub_8096258(cursorArea, cursorPos);
    sub_80964B8(id, 2);
    sub_80964E8(id, 0, cursorArea, cursorPos);
}

void Item_FromMonToMoving(u8 cursorArea, u8 cursorPos)
{
    u8 id;
    u16 item;

    if (gPSSData->boxOption != BOX_OPTION_MOVE_ITEMS)
        return;

    id = sub_8096258(cursorArea, cursorPos);
    item = 0;
    sub_80964B8(id, 3);
    sub_80964E8(id, 1, cursorArea, cursorPos);
    sub_80962F0(id, 2, 0);
    if (cursorArea  == CURSOR_AREA_IN_BOX)
    {
        SetCurrentBoxMonData(cursorPos, MON_DATA_HELD_ITEM, &item);
        SetBoxMonIconObjMode(cursorPos, ST_OAM_OBJ_BLEND);
    }
    else
    {
        SetMonData(&gPlayerParty[cursorPos], MON_DATA_HELD_ITEM, &item);
        SetPartyMonIconObjMode(cursorPos, ST_OAM_OBJ_BLEND);
    }

    gPSSData->movingItem = gPSSData->cursorMonItem;
}

void sub_8095E2C(u16 item)
{
    const u32 *tiles = GetItemIconPic(item);
    const u32 *pal = GetItemIconPalette(item);
    u8 id = sub_80961D8();

    sub_8096408(id, tiles, pal);
    sub_80964B8(id, 6);
    sub_80964E8(id, 1, CURSOR_AREA_IN_BOX, 0);
    sub_80962F0(id, CURSOR_AREA_BOX, 0);
    sub_8096624(id, TRUE);
    gPSSData->movingItem = item;
}

void Item_SwitchMonsWithMoving(u8 cursorArea, u8 cursorPos)
{
    u8 id;
    u16 item;

    if (gPSSData->boxOption != BOX_OPTION_MOVE_ITEMS)
        return;

    id = sub_8096258(cursorArea, cursorPos);
    sub_80964B8(id, 3);
    sub_80964E8(id, 3, CURSOR_AREA_BOX, 0);
    if (cursorArea == CURSOR_AREA_IN_BOX)
    {
        item = GetCurrentBoxMonData(cursorPos, MON_DATA_HELD_ITEM);
        SetCurrentBoxMonData(cursorPos, MON_DATA_HELD_ITEM, &gPSSData->movingItem);
        gPSSData->movingItem = item;
    }
    else
    {
        item = GetMonData(&gPlayerParty[cursorPos], MON_DATA_HELD_ITEM);
        SetMonData(&gPlayerParty[cursorPos], MON_DATA_HELD_ITEM, &gPSSData->movingItem);
        gPSSData->movingItem = item;
    }

    id = sub_8096258(2, 0);
    sub_80964B8(id, 4);
    sub_80964E8(id, 4, cursorArea, cursorPos);
}

void Item_GiveMovingToMon(u8 cursorArea, u8 cursorPos)
{
    u8 id;

    if (gPSSData->boxOption != BOX_OPTION_MOVE_ITEMS)
        return;

    id = sub_8096258(2, 0);
    sub_80964B8(id, 4);
    sub_80964E8(id, 2, cursorArea, cursorPos);
    if (cursorArea == CURSOR_AREA_IN_BOX)
    {
        SetCurrentBoxMonData(cursorPos, MON_DATA_HELD_ITEM, &gPSSData->movingItem);
        SetBoxMonIconObjMode(cursorPos, ST_OAM_OBJ_NORMAL);
    }
    else
    {
        SetMonData(&gPlayerParty[cursorPos], MON_DATA_HELD_ITEM, &gPSSData->movingItem);
        SetPartyMonIconObjMode(cursorPos, ST_OAM_OBJ_NORMAL);
    }
}

void Item_TakeMons(u8 cursorArea, u8 cursorPos)
{
    u8 id;
    u16 item;

    if (gPSSData->boxOption != BOX_OPTION_MOVE_ITEMS)
        return;

    item = 0;
    id = sub_8096258(cursorArea, cursorPos);
    sub_80964B8(id, 2);
    sub_80964E8(id, 0, cursorArea, cursorPos);
    if (cursorArea  == CURSOR_AREA_IN_BOX)
    {
        SetCurrentBoxMonData(cursorPos, MON_DATA_HELD_ITEM, &item);
        SetBoxMonIconObjMode(cursorPos, ST_OAM_OBJ_BLEND);
    }
    else
    {
        SetMonData(&gPlayerParty[cursorPos], MON_DATA_HELD_ITEM, &item);
        SetPartyMonIconObjMode(cursorPos, ST_OAM_OBJ_BLEND);
    }
}

void sub_8096088(void)
{
    if (gPSSData->boxOption == BOX_OPTION_MOVE_ITEMS)
    {
        u8 id = sub_8096258(2, 0);
        sub_80964B8(id, 5);
        sub_80964E8(id, 0, CURSOR_AREA_BOX, 0);
    }
}

void sub_80960C0(void)
{
    s32 i;

    if (gPSSData->boxOption != BOX_OPTION_MOVE_ITEMS)
        return;

    for (i = 0; i < MAX_ITEM_ICONS; i++)
    {
        if (gPSSData->itemIconSprites[i].active && gPSSData->itemIconSprites[i].cursorArea == CURSOR_AREA_IN_PARTY)
            sub_80964E8(i, 7, CURSOR_AREA_BOX, 0);
    }
}

bool8 sub_809610C(void)
{
    s32 i;

    for (i = 0; i < MAX_ITEM_ICONS; i++)
    {
        if (gPSSData->itemIconSprites[i].active)
        {
            if (!gPSSData->itemIconSprites[i].sprite->affineAnimEnded && gPSSData->itemIconSprites[i].sprite->affineAnimBeginning)
                return TRUE;
            if (gPSSData->itemIconSprites[i].sprite->callback != SpriteCallbackDummy && gPSSData->itemIconSprites[i].sprite->callback != sub_80969BC)
                return TRUE;
        }
    }

    return FALSE;
}

bool8 IsActiveItemMoving(void)
{
    s32 i;

    if (gPSSData->boxOption == BOX_OPTION_MOVE_ITEMS)
    {
        for (i = 0; i < MAX_ITEM_ICONS; i++)
        {
            if (gPSSData->itemIconSprites[i].active && gPSSData->itemIconSprites[i].cursorArea == CURSOR_AREA_BOX)
                return TRUE;
        }
    }

    return FALSE;
}

const u8 *GetMovingItemName(void)
{
    return ItemId_GetName(gPSSData->movingItem);
}

u16 GetMovingItem(void)
{
    return gPSSData->movingItem;
}

static u8 sub_80961D8(void)
{
    u8 i;

    for (i = 0; i < MAX_ITEM_ICONS; i++)
    {
        if (!gPSSData->itemIconSprites[i].active)
        {
            gPSSData->itemIconSprites[i].active = TRUE;
            return i;
        }
    }

    return MAX_ITEM_ICONS;
}

static bool32 sub_8096210(u8 cursorArea, u8 cursorPos)
{
    s32 i;

    for (i = 0; i < MAX_ITEM_ICONS; i++)
    {
        if (gPSSData->itemIconSprites[i].active
            && gPSSData->itemIconSprites[i].cursorArea == cursorArea
            && gPSSData->itemIconSprites[i].cursorPos == cursorPos)
            return TRUE;
    }

    return FALSE;
}

static u8 sub_8096258(u8 cursorArea, u8 cursorPos)
{
    u8 i;

    for (i = 0; i < MAX_ITEM_ICONS; i++)
    {
        if (gPSSData->itemIconSprites[i].active
            && gPSSData->itemIconSprites[i].cursorArea == cursorArea
            && gPSSData->itemIconSprites[i].cursorPos == cursorPos)
            return i;
    }

    return MAX_ITEM_ICONS;
}

static u8 sub_80962A8(struct Sprite *sprite)
{
    u8 i;

    for (i = 0; i < MAX_ITEM_ICONS; i++)
    {
        if (gPSSData->itemIconSprites[i].active
            && gPSSData->itemIconSprites[i].sprite == sprite)
            return i;
    }

    return MAX_ITEM_ICONS;
}

static void sub_80962F0(u8 id, u8 cursorArea, u8 cursorPos)
{
    u8 row, column;

    if (id >= MAX_ITEM_ICONS)
        return;

    switch (cursorArea)
    {
    case CURSOR_AREA_IN_BOX:
        row = cursorPos % IN_BOX_ROWS;
        column = cursorPos / IN_BOX_ROWS;
        gPSSData->itemIconSprites[id].sprite->x = (24 * row) + 112;
        gPSSData->itemIconSprites[id].sprite->y = (24 * column) + 56;
        gPSSData->itemIconSprites[id].sprite->oam.priority = 2;
        break;
    case CURSOR_AREA_IN_PARTY:
        if (cursorPos == 0)
        {
            gPSSData->itemIconSprites[id].sprite->x = 116;
            gPSSData->itemIconSprites[id].sprite->y = 76;
        }
        else
        {
            gPSSData->itemIconSprites[id].sprite->x = 164;
            gPSSData->itemIconSprites[id].sprite->y = 24 * (cursorPos - 1) + 28;
        }
        gPSSData->itemIconSprites[id].sprite->oam.priority = 1;
        break;
    }

    gPSSData->itemIconSprites[id].cursorArea = cursorArea;
    gPSSData->itemIconSprites[id].cursorPos = cursorPos;
}

static void sub_8096408(u8 id, const u32 *itemTiles, const u32 *itemPal)
{
    s32 i;

    if (id >= MAX_ITEM_ICONS)
        return;

    CpuFastFill(0, gPSSData->field_42C4, 0x200);
    LZ77UnCompWram(itemTiles, gPSSData->field_22C4);
    for (i = 0; i < 3; i++)
        CpuFastCopy(gPSSData->field_22C4 + (i * 0x60), gPSSData->field_42C4 + (i * 0x80), 0x60);

    CpuFastCopy(gPSSData->field_42C4, gPSSData->itemIconSprites[id].tiles, 0x200);
    LZ77UnCompWram(itemPal, gPSSData->field_42C4);
    LoadPalette(gPSSData->field_42C4, gPSSData->itemIconSprites[id].palIndex, 0x20);
}

static void sub_80964B8(u8 id, u8 animNum)
{
    if (id >= MAX_ITEM_ICONS)
        return;

    StartSpriteAffineAnim(gPSSData->itemIconSprites[id].sprite, animNum);
}

static void sub_80964E8(u8 id, u8 command, u8 cursorArea, u8 cursorPos)
{
    if (id >= MAX_ITEM_ICONS)
        return;

    switch (command)
    {
    case 0:
        gPSSData->itemIconSprites[id].sprite->data[0] = id;
        gPSSData->itemIconSprites[id].sprite->callback = sub_809692C;
        break;
    case 1:
        gPSSData->itemIconSprites[id].sprite->data[0] = 0;
        gPSSData->itemIconSprites[id].sprite->callback = sub_8096958;
        break;
    case 2:
        gPSSData->itemIconSprites[id].sprite->data[0] = 0;
        gPSSData->itemIconSprites[id].sprite->data[6] = cursorArea;
        gPSSData->itemIconSprites[id].sprite->data[7] = cursorPos;
        gPSSData->itemIconSprites[id].sprite->callback = sub_80969F4;
        break;
    case 3:
        gPSSData->itemIconSprites[id].sprite->data[0] = 0;
        gPSSData->itemIconSprites[id].sprite->callback = sub_8096A74;
        gPSSData->itemIconSprites[id].sprite->data[6] = cursorArea;
        gPSSData->itemIconSprites[id].sprite->data[7] = cursorPos;
        break;
    case 4:
        gPSSData->itemIconSprites[id].sprite->data[0] = 0;
        gPSSData->itemIconSprites[id].sprite->data[6] = cursorArea;
        gPSSData->itemIconSprites[id].sprite->data[7] = cursorPos;
        gPSSData->itemIconSprites[id].sprite->callback = sub_8096B10;
        break;
    case 7:
        gPSSData->itemIconSprites[id].sprite->callback = sub_8096BAC;
        break;
    }
}

static void sub_8096624(u8 id, bool8 show)
{
    if (id >= MAX_ITEM_ICONS)
        return;

    gPSSData->itemIconSprites[id].active = show;
    gPSSData->itemIconSprites[id].sprite->invisible = (show == FALSE);
}

static const u32 *GetItemIconPic(u16 itemId)
{
    return GetItemIconGfxPtr(itemId, 0);
}

static const u32 *GetItemIconPalette(u16 itemId)
{
    return GetItemIconGfxPtr(itemId, 1);
}

void PrintItemDescription(void)
{
    const u8 *description;

    if (IsActiveItemMoving())
        description = ItemId_GetDescription(gPSSData->movingItem);
    else
        description = ItemId_GetDescription(gPSSData->cursorMonItem);

    FillWindowPixelBuffer(2, PIXEL_FILL(1));
    AddTextPrinterParameterized5(2, 2, description, 2, 0, 0, NULL, 0, 0);
}

void sub_80966F4(void)
{
    gPSSData->field_2236 = 25;
    LoadBgTiles(0, gUnknown_83D35DC, 0x80, 0x1A4);
    sub_8096898(0);
}

bool8 sub_8096728(void)
{
    s32 i, var;

    if (gPSSData->field_2236 == 0)
        return FALSE;

    gPSSData->field_2236--;
    var = 25 - gPSSData->field_2236;
    for (i = 0; i < var; i++)
    {
        WriteSequenceToBgTilemapBuffer(0, GetBgAttribute(0, BG_ATTR_BASETILE) + 0x14 + gPSSData->field_2236 + i, i, 12, 1, 8, 15, 25);
    }

    sub_8096898(var);
    return (gPSSData->field_2236 != 0);
}

bool8 sub_80967C0(void)
{
    s32 i, var;

    if (gPSSData->field_2236 == 25)
        return FALSE;

    if (gPSSData->field_2236 == 0)
        FillBgTilemapBufferRect(0, 0, 25, 11, 1, 10, 17);

    gPSSData->field_2236++;
    var = 25 - gPSSData->field_2236;
    for (i = 0; i < var; i++)
    {
        WriteSequenceToBgTilemapBuffer(0, GetBgAttribute(0, BG_ATTR_BASETILE) + 0x14 + gPSSData->field_2236 + i, i, 12, 1, 8, 15, 25);
    }

    sub_8096898(var);

    FillBgTilemapBufferRect(0, 0, var, 11, 1, 10, 0x11);
    return (gPSSData->field_2236 != 25);
}

static void sub_8096898(u32 x)
{
    if (x != 0)
    {
        FillBgTilemapBufferRect(0, 0x1A4, 0, 0xB, x, 1, 0xFu);
        FillBgTilemapBufferRect(0, 0x9A4, 0, 0x14, x, 1, 0xFu);
    }
    FillBgTilemapBufferRect(0, 0x1A5, x, 0xC, 1, 8, 0xFu);
    FillBgTilemapBufferRect(0, 0x1A6, x, 0xB, 1, 1, 0xFu);
    FillBgTilemapBufferRect(0, 0x1A7, x, 0x14, 1, 1, 0xFu);
    ScheduleBgCopyTilemapToVram(0);
}

static void sub_809692C(struct Sprite *sprite)
{
    if (sprite->affineAnimEnded)
    {
        sub_8096624(sprite->data[0], FALSE);
        sprite->callback = SpriteCallbackDummy;
    }
}

static void sub_8096958(struct Sprite *sprite)
{
    switch (sprite->data[0])
    {
    case 0:
        sprite->data[1] = sprite->x << 4;
        sprite->data[2] = sprite->y << 4;
        sprite->data[3] = 10;
        sprite->data[4] = 21;
        sprite->data[5] = 0;
        sprite->data[0]++;
    case 1:
        sprite->data[1] -= sprite->data[3];
        sprite->data[2] -= sprite->data[4];
        sprite->x = sprite->data[1] >> 4;
        sprite->y = sprite->data[2] >> 4;
        if (++sprite->data[5] > 11)
            sprite->callback = sub_80969BC;
        break;
    }
}

static void sub_80969BC(struct Sprite *sprite)
{
    sprite->x = gPSSData->field_CB4->x + 4;
    sprite->y = gPSSData->field_CB4->y + gPSSData->field_CB4->y2 + 8;
    sprite->oam.priority = gPSSData->field_CB4->oam.priority;
}

static void sub_80969F4(struct Sprite *sprite)
{
    switch (sprite->data[0])
    {
    case 0:
        sprite->data[1] = sprite->x << 4;
        sprite->data[2] = sprite->y << 4;
        sprite->data[3] = 10;
        sprite->data[4] = 21;
        sprite->data[5] = 0;
        sprite->data[0]++;
    case 1:
        sprite->data[1] += sprite->data[3];
        sprite->data[2] += sprite->data[4];
        sprite->x = sprite->data[1] >> 4;
        sprite->y = sprite->data[2] >> 4;
        if (++sprite->data[5] > 11)
        {
            sub_80962F0(sub_80962A8(sprite), sprite->data[6], sprite->data[7]);
            sprite->callback = SpriteCallbackDummy;
        }
        break;
    }
}

static void sub_8096A74(struct Sprite *sprite)
{
    switch (sprite->data[0])
    {
    case 0:
        sprite->data[1] = sprite->x << 4;
        sprite->data[2] = sprite->y << 4;
        sprite->data[3] = 10;
        sprite->data[4] = 21;
        sprite->data[5] = 0;
        sprite->data[0]++;
    case 1:
        sprite->data[1] -= sprite->data[3];
        sprite->data[2] -= sprite->data[4];
        sprite->x = sprite->data[1] >> 4;
        sprite->y = sprite->data[2] >> 4;
        sprite->x2 = gSineTable[sprite->data[5] * 8] >> 4;
        if (++sprite->data[5] > 11)
        {
            sub_80962F0(sub_80962A8(sprite), sprite->data[6], sprite->data[7]);
            sprite->x2 = 0;
            sprite->callback = sub_80969BC;
        }
        break;
    }
}

static void sub_8096B10(struct Sprite *sprite)
{
    switch (sprite->data[0])
    {
    case 0:
        sprite->data[1] = sprite->x << 4;
        sprite->data[2] = sprite->y << 4;
        sprite->data[3] = 10;
        sprite->data[4] = 21;
        sprite->data[5] = 0;
        sprite->data[0]++;
    case 1:
        sprite->data[1] += sprite->data[3];
        sprite->data[2] += sprite->data[4];
        sprite->x = sprite->data[1] >> 4;
        sprite->y = sprite->data[2] >> 4;
        sprite->x2 = -(gSineTable[sprite->data[5] * 8] >> 4);
        if (++sprite->data[5] > 11)
        {
            sub_80962F0(sub_80962A8(sprite), sprite->data[6], sprite->data[7]);
            sprite->callback = SpriteCallbackDummy;
            sprite->x2 = 0;
        }
        break;
    }
}

static void sub_8096BAC(struct Sprite *sprite)
{
    sprite->y -= 8;
    if (sprite->y + sprite->y2 < -16)
    {
        sprite->callback = SpriteCallbackDummy;
        sub_8096624(sub_80962A8(sprite), FALSE);
    }
}
