|
|
|
|
@@ -5,15 +5,366 @@
|
|
|
|
|
#include "sound.h"
|
|
|
|
|
#include "task.h"
|
|
|
|
|
#include "trig.h"
|
|
|
|
|
#include "minigame_countdown.h"
|
|
|
|
|
#include "constants/songs.h"
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
This file contains two types of '3-2-1 Start' countdowns intended for use by the wireless minigames.
|
|
|
|
|
|
|
|
|
|
One is static, where the numbers simply appear and disappear without moving. This version is unused.
|
|
|
|
|
The other (used) version has the numbers squish and bounce up as they appear.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define TAG_STATIC_COUNTDOWN 0x2000
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
STATE_IDLE = 1,
|
|
|
|
|
STATE_START,
|
|
|
|
|
STATE_RUN,
|
|
|
|
|
STATE_END,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
FUNC_INIT,
|
|
|
|
|
FUNC_FREE,
|
|
|
|
|
FUNC_START,
|
|
|
|
|
FUNC_RUN,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
ANIM_THREE,
|
|
|
|
|
ANIM_TWO,
|
|
|
|
|
ANIM_ONE,
|
|
|
|
|
ANIM_START_LEFT,
|
|
|
|
|
ANIM_START_MID,
|
|
|
|
|
ANIM_START_RIGHT,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
extern const struct OamData gOamData_AffineOff_ObjNormal_32x32;
|
|
|
|
|
|
|
|
|
|
static void sub_802E6D0(u8 taskId);
|
|
|
|
|
static void sub_802E83C(u8 taskId);
|
|
|
|
|
static void sub_802E8C8(u8 taskId);
|
|
|
|
|
static void sub_802EA50(u8 taskId);
|
|
|
|
|
static void sub_802EAB0(u8 taskId);
|
|
|
|
|
static void Task_StaticCountdown(u8 taskId);
|
|
|
|
|
static void Task_StaticCountdown_Init(u8 taskId);
|
|
|
|
|
static void Task_StaticCountdown_Free(u8 taskId);
|
|
|
|
|
static void Task_StaticCountdown_Start(u8 taskId);
|
|
|
|
|
static void Task_StaticCountdown_Run(u8 taskId);
|
|
|
|
|
|
|
|
|
|
static const u16 s321Start_Static_Pal[] = INCBIN_U16("graphics/link_games/321start_static.gbapal");
|
|
|
|
|
static const u32 s321Start_Static_Gfx[] = INCBIN_U32("graphics/link_games/321start_static.4bpp.lz");
|
|
|
|
|
|
|
|
|
|
static const struct CompressedSpriteSheet sSpriteSheet_321Start_Static[] =
|
|
|
|
|
{
|
|
|
|
|
{s321Start_Static_Gfx, 0xC00, TAG_STATIC_COUNTDOWN},
|
|
|
|
|
{},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct SpritePalette sSpritePalette_321Start_Static[] =
|
|
|
|
|
{
|
|
|
|
|
{s321Start_Static_Pal, TAG_STATIC_COUNTDOWN},
|
|
|
|
|
{},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const union AnimCmd sAnim_StaticCountdown_Three[] =
|
|
|
|
|
{
|
|
|
|
|
ANIMCMD_FRAME(0, 0),
|
|
|
|
|
ANIMCMD_END
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const union AnimCmd sAnim_StaticCountdown_Two[] =
|
|
|
|
|
{
|
|
|
|
|
ANIMCMD_FRAME(16, 0),
|
|
|
|
|
ANIMCMD_END
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const union AnimCmd sAnim_StaticCountdown_One[] =
|
|
|
|
|
{
|
|
|
|
|
ANIMCMD_FRAME(32, 0),
|
|
|
|
|
ANIMCMD_END
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const union AnimCmd sAnim_StaticCountdown_StartLeft[] =
|
|
|
|
|
{
|
|
|
|
|
ANIMCMD_FRAME(64, 0),
|
|
|
|
|
ANIMCMD_END
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const union AnimCmd sAnim_StaticCountdown_StartMid[] =
|
|
|
|
|
{
|
|
|
|
|
ANIMCMD_FRAME(48, 0),
|
|
|
|
|
ANIMCMD_END
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const union AnimCmd sAnim_StaticCountdown_StartRight[] =
|
|
|
|
|
{
|
|
|
|
|
ANIMCMD_FRAME(80, 0),
|
|
|
|
|
ANIMCMD_END
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const union AnimCmd *const sAnims_StaticCountdown[] =
|
|
|
|
|
{
|
|
|
|
|
[ANIM_THREE] = sAnim_StaticCountdown_Three,
|
|
|
|
|
[ANIM_TWO] = sAnim_StaticCountdown_Two,
|
|
|
|
|
[ANIM_ONE] = sAnim_StaticCountdown_One,
|
|
|
|
|
[ANIM_START_LEFT] = sAnim_StaticCountdown_StartLeft,
|
|
|
|
|
[ANIM_START_MID] = sAnim_StaticCountdown_StartMid,
|
|
|
|
|
[ANIM_START_RIGHT] = sAnim_StaticCountdown_StartRight
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_StaticCountdown[] =
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
.tileTag = TAG_STATIC_COUNTDOWN,
|
|
|
|
|
.paletteTag = TAG_STATIC_COUNTDOWN,
|
|
|
|
|
.oam = &gOamData_AffineOff_ObjNormal_32x32,
|
|
|
|
|
.anims = sAnims_StaticCountdown,
|
|
|
|
|
.images = NULL,
|
|
|
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
|
|
|
.callback = SpriteCallbackDummy,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const TaskFunc sStaticCountdownFuncs[][4] =
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
[FUNC_INIT] = Task_StaticCountdown_Init,
|
|
|
|
|
[FUNC_FREE] = Task_StaticCountdown_Free,
|
|
|
|
|
[FUNC_START] = Task_StaticCountdown_Start,
|
|
|
|
|
[FUNC_RUN] = Task_StaticCountdown_Run
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#define tState data[0]
|
|
|
|
|
#define tFuncSetId data[1] // These 4 data elements are indexes into
|
|
|
|
|
#define tSpriteTemplateId data[2] // arrays that only have 1 element with
|
|
|
|
|
#define tSpriteSheetId data[3] // data. As such their only legal value
|
|
|
|
|
#define tSpritePalId data[4] // is 0. Unclear why they were used.
|
|
|
|
|
#define tInterval data[5]
|
|
|
|
|
#define tPriority data[6]
|
|
|
|
|
#define tSubpriority data[7]
|
|
|
|
|
#define tNumSprites data[8]
|
|
|
|
|
#define tX data[9]
|
|
|
|
|
#define tY data[10]
|
|
|
|
|
#define tPrevTime data[10] // Re-used
|
|
|
|
|
#define tTimer data[11]
|
|
|
|
|
#define tLinkTimer data[12]
|
|
|
|
|
// 13-15 hold sprite ids
|
|
|
|
|
// tSpriteIds(0) is used for the number sprites, and the leftmost part of 'Start'
|
|
|
|
|
// tSpriteIds(1) is used for the middle part of 'Start'
|
|
|
|
|
// tSpriteIds(2) is used for for the rightmost part of 'Start'
|
|
|
|
|
#define tSpriteIds(i) data[13 + i]
|
|
|
|
|
|
|
|
|
|
#define sInterval data[1] // Never read
|
|
|
|
|
#define sAnimNum data[2]
|
|
|
|
|
#define sTaskId data[3]
|
|
|
|
|
#define sId data[4] // Never read
|
|
|
|
|
#define sNumberSpriteId data[5] // Never read
|
|
|
|
|
|
|
|
|
|
// Unused
|
|
|
|
|
static u32 CreateStaticCountdownTask(u8 funcSetId, u8 taskPriority)
|
|
|
|
|
{
|
|
|
|
|
u8 taskId = CreateTask(Task_StaticCountdown, taskPriority);
|
|
|
|
|
struct Task *task = &gTasks[taskId];
|
|
|
|
|
|
|
|
|
|
task->tState = STATE_IDLE;
|
|
|
|
|
task->tFuncSetId = funcSetId;
|
|
|
|
|
sStaticCountdownFuncs[funcSetId][FUNC_INIT](taskId);
|
|
|
|
|
return taskId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool32 StartStaticCountdown(void)
|
|
|
|
|
{
|
|
|
|
|
u8 taskId = FindTaskIdByFunc(Task_StaticCountdown);
|
|
|
|
|
if (taskId == TASK_NONE)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
gTasks[taskId].tState = STATE_START;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool32 IsStaticCountdownRunning(void)
|
|
|
|
|
{
|
|
|
|
|
return FuncIsActiveTask(Task_StaticCountdown);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void Task_StaticCountdown(u8 taskId)
|
|
|
|
|
{
|
|
|
|
|
s16 *data = gTasks[taskId].data;
|
|
|
|
|
|
|
|
|
|
switch (tState)
|
|
|
|
|
{
|
|
|
|
|
// STATE_IDLE does nothing; wait until started
|
|
|
|
|
case STATE_START:
|
|
|
|
|
sStaticCountdownFuncs[tFuncSetId][FUNC_START](taskId);
|
|
|
|
|
tState = STATE_RUN;
|
|
|
|
|
break;
|
|
|
|
|
case STATE_RUN:
|
|
|
|
|
sStaticCountdownFuncs[tFuncSetId][FUNC_RUN](taskId);
|
|
|
|
|
break;
|
|
|
|
|
case STATE_END:
|
|
|
|
|
sStaticCountdownFuncs[tFuncSetId][FUNC_FREE](taskId);
|
|
|
|
|
DestroyTask(taskId);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void StaticCountdown_CreateSprites(u8 taskId, s16 *data)
|
|
|
|
|
{
|
|
|
|
|
u8 i;
|
|
|
|
|
struct Sprite *sprite;
|
|
|
|
|
|
|
|
|
|
LoadCompressedSpriteSheet(&sSpriteSheet_321Start_Static[tSpriteSheetId]);
|
|
|
|
|
LoadSpritePalette(&sSpritePalette_321Start_Static[tSpritePalId]);
|
|
|
|
|
for (i = 0; i < tNumSprites; i++)
|
|
|
|
|
tSpriteIds(i) = CreateSprite(&sSpriteTemplate_StaticCountdown[tSpriteTemplateId], tX, tY, tSubpriority);
|
|
|
|
|
for (i = 0; i < tNumSprites; i++)
|
|
|
|
|
{
|
|
|
|
|
sprite = &gSprites[tSpriteIds(i)];
|
|
|
|
|
sprite->oam.priority = tPriority;
|
|
|
|
|
sprite->invisible = TRUE;
|
|
|
|
|
sprite->sInterval = tInterval;
|
|
|
|
|
sprite->sTaskId = taskId;
|
|
|
|
|
sprite->sId = i;
|
|
|
|
|
sprite->sNumberSpriteId = tSpriteIds(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void Task_StaticCountdown_Init(u8 taskId)
|
|
|
|
|
{
|
|
|
|
|
s16 *data = gTasks[taskId].data;
|
|
|
|
|
tSpriteTemplateId = 0;
|
|
|
|
|
tSpriteSheetId = 0;
|
|
|
|
|
tSpritePalId = 0;
|
|
|
|
|
tInterval = 60;
|
|
|
|
|
tPriority = 0;
|
|
|
|
|
tSubpriority = 0;
|
|
|
|
|
tNumSprites = 3;
|
|
|
|
|
tX = 120;
|
|
|
|
|
tY = 88;
|
|
|
|
|
StaticCountdown_CreateSprites(taskId, data);
|
|
|
|
|
|
|
|
|
|
StartSpriteAnim(&gSprites[tSpriteIds(1)], ANIM_START_MID);
|
|
|
|
|
gSprites[tSpriteIds(1)].pos2.x = -32;
|
|
|
|
|
|
|
|
|
|
StartSpriteAnim(&gSprites[tSpriteIds(2)], ANIM_START_RIGHT);
|
|
|
|
|
gSprites[tSpriteIds(2)].pos2.x = 32;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void Task_StaticCountdown_Free(u8 taskId)
|
|
|
|
|
{
|
|
|
|
|
u8 i = 0;
|
|
|
|
|
s16 *data = gTasks[taskId].data;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < tNumSprites; i++)
|
|
|
|
|
DestroySprite(&gSprites[tSpriteIds(i)]);
|
|
|
|
|
FreeSpriteTilesByTag(sSpriteSheet_321Start_Static[tSpriteSheetId].tag);
|
|
|
|
|
FreeSpritePaletteByTag(sSpritePalette_321Start_Static[tSpritePalId].tag);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void SpriteCB_StaticCountdown(struct Sprite *sprite)
|
|
|
|
|
{
|
|
|
|
|
s16 *data = gTasks[sprite->sTaskId].data;
|
|
|
|
|
|
|
|
|
|
if (tTimer % tInterval != 0)
|
|
|
|
|
return;
|
|
|
|
|
if (tTimer == tPrevTime)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
tPrevTime = tTimer;
|
|
|
|
|
switch (sprite->sAnimNum)
|
|
|
|
|
{
|
|
|
|
|
case ANIM_THREE:
|
|
|
|
|
sprite->invisible = FALSE;
|
|
|
|
|
case ANIM_TWO:
|
|
|
|
|
case ANIM_ONE:
|
|
|
|
|
// Set sprite to a number
|
|
|
|
|
PlaySE(SE_BALL_BOUNCE_1);
|
|
|
|
|
StartSpriteAnim(sprite, sprite->sAnimNum);
|
|
|
|
|
break;
|
|
|
|
|
case ANIM_START_LEFT:
|
|
|
|
|
// Set sprite to 'Start'
|
|
|
|
|
PlaySE(SE_PIN);
|
|
|
|
|
StartSpriteAnim(sprite, sprite->sAnimNum);
|
|
|
|
|
gSprites[tSpriteIds(1)].invisible = FALSE;
|
|
|
|
|
gSprites[tSpriteIds(2)].invisible = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
case ANIM_START_LEFT + 1: // End
|
|
|
|
|
// Hide countdown
|
|
|
|
|
sprite->invisible = TRUE;
|
|
|
|
|
gSprites[tSpriteIds(1)].invisible = TRUE;
|
|
|
|
|
gSprites[tSpriteIds(2)].invisible = TRUE;
|
|
|
|
|
tState = STATE_END;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
sprite->sAnimNum++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void Task_StaticCountdown_Start(u8 taskId)
|
|
|
|
|
{
|
|
|
|
|
s16 *data = gTasks[taskId].data;
|
|
|
|
|
PlaySE(SE_BALL_BOUNCE_1);
|
|
|
|
|
gSprites[tSpriteIds(0)].callback = SpriteCB_StaticCountdown;
|
|
|
|
|
gSprites[tSpriteIds(0)].invisible = FALSE;
|
|
|
|
|
gTasks[taskId].tState = STATE_RUN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Increment timer for progressing the countdown.
|
|
|
|
|
// If the player is the link leader, increment a
|
|
|
|
|
// separate timer and send it to group members for
|
|
|
|
|
// them to read and use.
|
|
|
|
|
static void Task_StaticCountdown_Run(u8 taskId)
|
|
|
|
|
{
|
|
|
|
|
u16 packet[RFU_PACKET_SIZE];
|
|
|
|
|
s16 *data = gTasks[taskId].data;
|
|
|
|
|
|
|
|
|
|
if (gReceivedRemoteLinkPlayers != 0)
|
|
|
|
|
{
|
|
|
|
|
// Read link timer
|
|
|
|
|
if (gRecvCmds[0][1] == LINKCMD_COUNTDOWN)
|
|
|
|
|
tTimer = gRecvCmds[0][2];
|
|
|
|
|
|
|
|
|
|
if (GetMultiplayerId() == 0)
|
|
|
|
|
{
|
|
|
|
|
// Player is link leader.
|
|
|
|
|
// Send timer to group members
|
|
|
|
|
tLinkTimer++;
|
|
|
|
|
memset(packet, 0, sizeof(packet));
|
|
|
|
|
packet[0] = LINKCMD_COUNTDOWN;
|
|
|
|
|
packet[1] = tLinkTimer;
|
|
|
|
|
Rfu_SendPacket(packet);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Local, just increment own timer
|
|
|
|
|
tTimer++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef tState
|
|
|
|
|
#undef tFuncSetId
|
|
|
|
|
#undef tSpriteTemplateId
|
|
|
|
|
#undef tSpriteSheetId
|
|
|
|
|
#undef tSpritePalId
|
|
|
|
|
#undef tInterval
|
|
|
|
|
#undef tPriority
|
|
|
|
|
#undef tSubpriority
|
|
|
|
|
#undef tNumSprites
|
|
|
|
|
#undef tX
|
|
|
|
|
#undef tY
|
|
|
|
|
#undef tPrevTime
|
|
|
|
|
#undef tTimer
|
|
|
|
|
#undef tLinkTimer
|
|
|
|
|
#undef tSpriteIds
|
|
|
|
|
#undef sInterval
|
|
|
|
|
#undef sAnimNum
|
|
|
|
|
#undef sTaskId
|
|
|
|
|
#undef sId
|
|
|
|
|
#undef sNumberSpriteId
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
The countdown that actually gets used by
|
|
|
|
|
the wireless minigames starts here
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static void Task_MinigameCountdown(u8 taskId);
|
|
|
|
|
static bool32 RunMinigameCountdownDigitsAnim(u8 spriteId);
|
|
|
|
|
static bool32 IsStartGraphicAnimRunning(u8 spriteId);
|
|
|
|
|
@@ -23,260 +374,8 @@ static void CreateStartSprite(u16 tileTag, u16 palTag, s16 x, s16 y, u8 subprior
|
|
|
|
|
static void InitStartGraphic(u8 spriteId1, u8 spriteId2, u8 spriteId3);
|
|
|
|
|
static void SpriteCB_Start(struct Sprite *sprite);
|
|
|
|
|
|
|
|
|
|
static const u16 sSpritePal_321Start_2[] = INCBIN_U16("graphics/link_games/321start_2.gbapal");
|
|
|
|
|
static const u32 sSpriteSheet_321Start_2[] = INCBIN_U32("graphics/link_games/321start_2.4bpp.lz");
|
|
|
|
|
|
|
|
|
|
static const struct CompressedSpriteSheet gUnknown_082FE6C8[] =
|
|
|
|
|
{
|
|
|
|
|
{sSpriteSheet_321Start_2, 0xC00, 0x2000},
|
|
|
|
|
{},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct SpritePalette gUnknown_082FE6D8[] =
|
|
|
|
|
{
|
|
|
|
|
{sSpritePal_321Start_2, 0x2000},
|
|
|
|
|
{},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const union AnimCmd sSpriteAnim_82FE6E8[] =
|
|
|
|
|
{
|
|
|
|
|
ANIMCMD_FRAME(0, 0),
|
|
|
|
|
ANIMCMD_END
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const union AnimCmd sSpriteAnim_82FE6F0[] =
|
|
|
|
|
{
|
|
|
|
|
ANIMCMD_FRAME(16, 0),
|
|
|
|
|
ANIMCMD_END
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const union AnimCmd sSpriteAnim_82FE6F8[] =
|
|
|
|
|
{
|
|
|
|
|
ANIMCMD_FRAME(32, 0),
|
|
|
|
|
ANIMCMD_END
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const union AnimCmd sSpriteAnim_82FE700[] =
|
|
|
|
|
{
|
|
|
|
|
ANIMCMD_FRAME(64, 0),
|
|
|
|
|
ANIMCMD_END
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const union AnimCmd sSpriteAnim_82FE708[] =
|
|
|
|
|
{
|
|
|
|
|
ANIMCMD_FRAME(48, 0),
|
|
|
|
|
ANIMCMD_END
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const union AnimCmd sSpriteAnim_82FE710[] =
|
|
|
|
|
{
|
|
|
|
|
ANIMCMD_FRAME(80, 0),
|
|
|
|
|
ANIMCMD_END
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const union AnimCmd *const sSpriteAnimTable_82FE718[] =
|
|
|
|
|
{
|
|
|
|
|
sSpriteAnim_82FE6E8,
|
|
|
|
|
sSpriteAnim_82FE6F0,
|
|
|
|
|
sSpriteAnim_82FE6F8,
|
|
|
|
|
sSpriteAnim_82FE700,
|
|
|
|
|
sSpriteAnim_82FE708,
|
|
|
|
|
sSpriteAnim_82FE710
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct SpriteTemplate gUnknown_082FE730[] =
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
.tileTag = 0x2000,
|
|
|
|
|
.paletteTag = 0x2000,
|
|
|
|
|
.oam = &gOamData_AffineOff_ObjNormal_32x32,
|
|
|
|
|
.anims = sSpriteAnimTable_82FE718,
|
|
|
|
|
.images = NULL,
|
|
|
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
|
|
|
.callback = SpriteCallbackDummy,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const TaskFunc gUnknown_082FE748[][4] =
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
sub_802E83C,
|
|
|
|
|
sub_802E8C8,
|
|
|
|
|
sub_802EA50,
|
|
|
|
|
sub_802EAB0
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const u16 sSpritePal_321Start[] = INCBIN_U16("graphics/link_games/321start.gbapal");
|
|
|
|
|
static const u32 sSpriteSheet_321Start[] = INCBIN_U32("graphics/link_games/321start.4bpp.lz");
|
|
|
|
|
|
|
|
|
|
// Unused
|
|
|
|
|
static u32 sub_802E63C(u8 funcSetId, u8 taskPriority)
|
|
|
|
|
{
|
|
|
|
|
u8 taskId = CreateTask(sub_802E6D0, taskPriority);
|
|
|
|
|
struct Task *task = &gTasks[taskId];
|
|
|
|
|
|
|
|
|
|
task->data[0] = 1;
|
|
|
|
|
task->data[1] = funcSetId;
|
|
|
|
|
gUnknown_082FE748[funcSetId][0](taskId);
|
|
|
|
|
return taskId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool32 sub_802E688(void)
|
|
|
|
|
{
|
|
|
|
|
u8 taskId = FindTaskIdByFunc(sub_802E6D0);
|
|
|
|
|
if (taskId == TASK_NONE)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
gTasks[taskId].data[0] = 2;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool32 sub_802E6BC(void)
|
|
|
|
|
{
|
|
|
|
|
return FuncIsActiveTask(sub_802E6D0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void sub_802E6D0(u8 taskId)
|
|
|
|
|
{
|
|
|
|
|
s16 *data = gTasks[taskId].data;
|
|
|
|
|
|
|
|
|
|
switch (data[0])
|
|
|
|
|
{
|
|
|
|
|
case 2:
|
|
|
|
|
gUnknown_082FE748[data[1]][2](taskId);
|
|
|
|
|
data[0] = 3;
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
gUnknown_082FE748[data[1]][3](taskId);
|
|
|
|
|
break;
|
|
|
|
|
case 4:
|
|
|
|
|
gUnknown_082FE748[data[1]][1](taskId);
|
|
|
|
|
DestroyTask(taskId);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void sub_802E75C(u8 taskId, s16 *data)
|
|
|
|
|
{
|
|
|
|
|
u8 i;
|
|
|
|
|
struct Sprite *sprite;
|
|
|
|
|
|
|
|
|
|
LoadCompressedSpriteSheet(&gUnknown_082FE6C8[data[3]]);
|
|
|
|
|
LoadSpritePalette(&gUnknown_082FE6D8[data[4]]);
|
|
|
|
|
for (i = 0; i < data[8]; i++)
|
|
|
|
|
data[13 + i] = CreateSprite(&gUnknown_082FE730[data[2]], data[9], data[10], data[7]);
|
|
|
|
|
for (i = 0; i < data[8]; i++)
|
|
|
|
|
{
|
|
|
|
|
sprite = &gSprites[data[13 + i]];
|
|
|
|
|
sprite->oam.priority = data[6];
|
|
|
|
|
sprite->invisible = TRUE;
|
|
|
|
|
sprite->data[1] = data[5];
|
|
|
|
|
sprite->data[3] = taskId;
|
|
|
|
|
sprite->data[4] = i;
|
|
|
|
|
sprite->data[5] = data[13];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void sub_802E83C(u8 taskId)
|
|
|
|
|
{
|
|
|
|
|
s16 *data = gTasks[taskId].data;
|
|
|
|
|
data[2] = 0;
|
|
|
|
|
data[3] = 0;
|
|
|
|
|
data[4] = 0;
|
|
|
|
|
data[5] = 60;
|
|
|
|
|
data[6] = 0;
|
|
|
|
|
data[7] = 0;
|
|
|
|
|
data[8] = 3;
|
|
|
|
|
data[9] = 120;
|
|
|
|
|
data[10] = 88;
|
|
|
|
|
sub_802E75C(taskId, data);
|
|
|
|
|
|
|
|
|
|
StartSpriteAnim(&gSprites[data[14]], 4);
|
|
|
|
|
gSprites[data[14]].pos2.x = -32;
|
|
|
|
|
|
|
|
|
|
StartSpriteAnim(&gSprites[data[15]], 5);
|
|
|
|
|
gSprites[data[15]].pos2.x = 32;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void sub_802E8C8(u8 taskId)
|
|
|
|
|
{
|
|
|
|
|
u8 i = 0;
|
|
|
|
|
s16 *data = gTasks[taskId].data;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < data[8]; i++)
|
|
|
|
|
DestroySprite(&gSprites[data[13 + i]]);
|
|
|
|
|
FreeSpriteTilesByTag(gUnknown_082FE6C8[data[3]].tag);
|
|
|
|
|
FreeSpritePaletteByTag(gUnknown_082FE6D8[data[4]].tag);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void sub_802E938(struct Sprite *sprite)
|
|
|
|
|
{
|
|
|
|
|
s16 *data = gTasks[sprite->data[3]].data;
|
|
|
|
|
|
|
|
|
|
if (data[11] % data[5] != 0)
|
|
|
|
|
return;
|
|
|
|
|
if (data[11] == data[10])
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
data[10] = data[11];
|
|
|
|
|
switch (sprite->data[2])
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
sprite->invisible = FALSE;
|
|
|
|
|
case 1:
|
|
|
|
|
case 2:
|
|
|
|
|
PlaySE(SE_BALL_BOUNCE_1);
|
|
|
|
|
StartSpriteAnim(sprite, sprite->data[2]);
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
PlaySE(SE_PIN);
|
|
|
|
|
StartSpriteAnim(sprite, sprite->data[2]);
|
|
|
|
|
gSprites[data[14]].invisible = FALSE;
|
|
|
|
|
gSprites[data[15]].invisible = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
case 4:
|
|
|
|
|
sprite->invisible = TRUE;
|
|
|
|
|
gSprites[data[14]].invisible = TRUE;
|
|
|
|
|
gSprites[data[15]].invisible = TRUE;
|
|
|
|
|
data[0] = 4;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
sprite->data[2]++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void sub_802EA50(u8 taskId)
|
|
|
|
|
{
|
|
|
|
|
s16 *data = gTasks[taskId].data;
|
|
|
|
|
PlaySE(SE_BALL_BOUNCE_1);
|
|
|
|
|
gSprites[data[13]].callback = sub_802E938;
|
|
|
|
|
gSprites[data[13]].invisible = FALSE;
|
|
|
|
|
gTasks[taskId].data[0] = 3;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void sub_802EAB0(u8 taskId)
|
|
|
|
|
{
|
|
|
|
|
u16 packet[6];
|
|
|
|
|
s16 *data = gTasks[taskId].data;
|
|
|
|
|
|
|
|
|
|
if (gReceivedRemoteLinkPlayers != 0)
|
|
|
|
|
{
|
|
|
|
|
if (gRecvCmds[0][1] == LINKCMD_0x7FFF)
|
|
|
|
|
data[11] = gRecvCmds[0][2];
|
|
|
|
|
if (GetMultiplayerId() == 0)
|
|
|
|
|
{
|
|
|
|
|
data[12]++;
|
|
|
|
|
memset(packet, 0, sizeof(packet));
|
|
|
|
|
packet[0] = LINKCMD_0x7FFF;
|
|
|
|
|
packet[1] = data[12];
|
|
|
|
|
Rfu_SendPacket(packet);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
data[11]++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
static const u16 s321Start_Pal[] = INCBIN_U16("graphics/link_games/321start.gbapal");
|
|
|
|
|
static const u32 s321Start_Gfx[] = INCBIN_U32("graphics/link_games/321start.4bpp.lz");
|
|
|
|
|
|
|
|
|
|
#define tState data[0]
|
|
|
|
|
#define tTilesTag data[2]
|
|
|
|
|
@@ -288,7 +387,7 @@ static void sub_802EAB0(u8 taskId)
|
|
|
|
|
#define tSpriteId2 data[8]
|
|
|
|
|
#define tSpriteId3 data[9]
|
|
|
|
|
|
|
|
|
|
void StartMinigameCountdown(s16 tilesTag, s16 palTag, s16 x, s16 y, u8 subpriority)
|
|
|
|
|
void StartMinigameCountdown(u16 tilesTag, u16 palTag, s16 x, s16 y, u8 subpriority)
|
|
|
|
|
{
|
|
|
|
|
u8 taskId = CreateTask(Task_MinigameCountdown, 80);
|
|
|
|
|
gTasks[taskId].tTilesTag = tilesTag;
|
|
|
|
|
@@ -337,69 +436,82 @@ static void Task_MinigameCountdown(u8 taskId)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define sState data[0]
|
|
|
|
|
#define sTimer data[2]
|
|
|
|
|
#define sAnimNum data[4]
|
|
|
|
|
|
|
|
|
|
static bool32 RunMinigameCountdownDigitsAnim(u8 spriteId)
|
|
|
|
|
{
|
|
|
|
|
struct Sprite *sprite = &gSprites[spriteId];
|
|
|
|
|
|
|
|
|
|
switch (sprite->data[0])
|
|
|
|
|
switch (sprite->sState)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
sub_8007E18(sprite, 0x800, 0x1A);
|
|
|
|
|
sprite->data[0]++;
|
|
|
|
|
sprite->sState++;
|
|
|
|
|
// fallthrough
|
|
|
|
|
case 1:
|
|
|
|
|
if (sprite->data[2] == 0)
|
|
|
|
|
if (sprite->sTimer == 0)
|
|
|
|
|
PlaySE(SE_BALL_BOUNCE_2);
|
|
|
|
|
if (++sprite->data[2] >= 20)
|
|
|
|
|
|
|
|
|
|
if (++sprite->sTimer >= 20)
|
|
|
|
|
{
|
|
|
|
|
sprite->data[2] = 0;
|
|
|
|
|
// Ready for jump
|
|
|
|
|
sprite->sTimer = 0;
|
|
|
|
|
StartSpriteAffineAnim(sprite, 1);
|
|
|
|
|
sprite->data[0]++;
|
|
|
|
|
sprite->sState++;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
if (sprite->affineAnimEnded)
|
|
|
|
|
sprite->data[0]++;
|
|
|
|
|
sprite->sState++;
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
if (++sprite->data[2] >= 4)
|
|
|
|
|
if (++sprite->sTimer >= 4)
|
|
|
|
|
{
|
|
|
|
|
sprite->data[2] = 0;
|
|
|
|
|
sprite->data[0]++;
|
|
|
|
|
// Start jump
|
|
|
|
|
sprite->sTimer = 0;
|
|
|
|
|
sprite->sState++;
|
|
|
|
|
StartSpriteAffineAnim(sprite, 2);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 4:
|
|
|
|
|
// Moving up from jump
|
|
|
|
|
sprite->pos1.y -= 4;
|
|
|
|
|
if (++sprite->data[2] >= 8)
|
|
|
|
|
if (++sprite->sTimer >= 8)
|
|
|
|
|
{
|
|
|
|
|
if (sprite->data[4] <= 1)
|
|
|
|
|
if (sprite->sAnimNum < 2)
|
|
|
|
|
{
|
|
|
|
|
StartSpriteAnim(sprite, sprite->data[4] + 1);
|
|
|
|
|
sprite->data[2] = 0;
|
|
|
|
|
sprite->data[0]++;
|
|
|
|
|
// Swap to the next number
|
|
|
|
|
StartSpriteAnim(sprite, sprite->sAnimNum + 1);
|
|
|
|
|
sprite->sTimer = 0;
|
|
|
|
|
sprite->sState++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sprite->data[0] = 7;
|
|
|
|
|
// End
|
|
|
|
|
sprite->sState = 7;
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 5:
|
|
|
|
|
// Falling after jump
|
|
|
|
|
sprite->pos1.y += 4;
|
|
|
|
|
if (++sprite->data[2] >= 8)
|
|
|
|
|
if (++sprite->sTimer >= 8)
|
|
|
|
|
{
|
|
|
|
|
sprite->data[2] = 0;
|
|
|
|
|
// Land from jump
|
|
|
|
|
sprite->sTimer = 0;
|
|
|
|
|
StartSpriteAffineAnim(sprite, 3);
|
|
|
|
|
sprite->data[0]++;
|
|
|
|
|
sprite->sState++;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 6:
|
|
|
|
|
if (sprite->affineAnimEnded)
|
|
|
|
|
{
|
|
|
|
|
sprite->data[4]++;
|
|
|
|
|
sprite->data[0] = 1;
|
|
|
|
|
// Restart for next number
|
|
|
|
|
sprite->sAnimNum++;
|
|
|
|
|
sprite->sState = 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 7:
|
|
|
|
|
@@ -409,6 +521,10 @@ static bool32 RunMinigameCountdownDigitsAnim(u8 spriteId)
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef sState
|
|
|
|
|
#undef sTimer
|
|
|
|
|
#undef sAnimNum
|
|
|
|
|
|
|
|
|
|
// First argument is unused.
|
|
|
|
|
static void InitStartGraphic(u8 spriteId1, u8 spriteId2, u8 spriteId3)
|
|
|
|
|
{
|
|
|
|
|
@@ -425,60 +541,70 @@ static bool32 IsStartGraphicAnimRunning(u8 spriteId)
|
|
|
|
|
return gSprites[spriteId].callback == SpriteCB_Start;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define sState data[0]
|
|
|
|
|
#define sTimer data[1]
|
|
|
|
|
#define sYSpeed data[4]
|
|
|
|
|
#define sY data[5]
|
|
|
|
|
|
|
|
|
|
static void SpriteCB_Start(struct Sprite *sprite)
|
|
|
|
|
{
|
|
|
|
|
int y;
|
|
|
|
|
s16 *data = sprite->data;
|
|
|
|
|
|
|
|
|
|
switch (data[0])
|
|
|
|
|
switch (sState)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
data[4] = 64;
|
|
|
|
|
data[5] = sprite->pos2.y << 4;
|
|
|
|
|
data[0]++;
|
|
|
|
|
sYSpeed = 64;
|
|
|
|
|
sY = sprite->pos2.y << 4;
|
|
|
|
|
sState++;
|
|
|
|
|
case 1:
|
|
|
|
|
data[5] += data[4];
|
|
|
|
|
data[4]++;
|
|
|
|
|
sprite->pos2.y = data[5] >> 4;
|
|
|
|
|
sY += sYSpeed;
|
|
|
|
|
sYSpeed++;
|
|
|
|
|
sprite->pos2.y = sY >> 4;
|
|
|
|
|
if (sprite->pos2.y >= 0)
|
|
|
|
|
{
|
|
|
|
|
PlaySE(SE_BALL_BOUNCE_2);
|
|
|
|
|
sprite->pos2.y = 0;
|
|
|
|
|
data[0]++;
|
|
|
|
|
sState++;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
data[1] += 12;
|
|
|
|
|
if (data[1] >= 128)
|
|
|
|
|
sTimer += 12;
|
|
|
|
|
if (sTimer >= 128)
|
|
|
|
|
{
|
|
|
|
|
PlaySE(SE_BALL_BOUNCE_2);
|
|
|
|
|
data[1] = 0;
|
|
|
|
|
data[0]++;
|
|
|
|
|
sTimer = 0;
|
|
|
|
|
sState++;
|
|
|
|
|
}
|
|
|
|
|
y = gSineTable[data[1]];
|
|
|
|
|
y = gSineTable[sTimer];
|
|
|
|
|
sprite->pos2.y = -(y >> 4);
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
data[1] += 16;
|
|
|
|
|
if (data[1] >= 128)
|
|
|
|
|
sTimer += 16;
|
|
|
|
|
if (sTimer >= 128)
|
|
|
|
|
{
|
|
|
|
|
PlaySE(SE_BALL_BOUNCE_2);
|
|
|
|
|
data[1] = 0;
|
|
|
|
|
data[0]++;
|
|
|
|
|
sTimer = 0;
|
|
|
|
|
sState++;
|
|
|
|
|
}
|
|
|
|
|
sprite->pos2.y = -(gSineTable[data[1]] >> 5);
|
|
|
|
|
sprite->pos2.y = -(gSineTable[sTimer] >> 5);
|
|
|
|
|
break;
|
|
|
|
|
case 4:
|
|
|
|
|
if (++data[1] > 40)
|
|
|
|
|
if (++sTimer > 40)
|
|
|
|
|
sprite->callback = SpriteCallbackDummy;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef sState
|
|
|
|
|
#undef sTimer
|
|
|
|
|
#undef sYSpeed
|
|
|
|
|
#undef sY
|
|
|
|
|
|
|
|
|
|
static void Load321StartGfx(u16 tileTag, u16 palTag)
|
|
|
|
|
{
|
|
|
|
|
struct CompressedSpriteSheet spriteSheet = {sSpriteSheet_321Start, 0xE00, 0};
|
|
|
|
|
struct SpritePalette spritePalette = {sSpritePal_321Start, 0};
|
|
|
|
|
struct CompressedSpriteSheet spriteSheet = {s321Start_Gfx, 0xE00, 0};
|
|
|
|
|
struct SpritePalette spritePalette = {s321Start_Pal, 0};
|
|
|
|
|
|
|
|
|
|
spriteSheet.tag = tileTag;
|
|
|
|
|
spritePalette.tag = palTag;
|
|
|
|
|
@@ -564,26 +690,26 @@ static const union AnimCmd *const sAnimTable_Start[] =
|
|
|
|
|
sAnim_StartRight
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const union AffineAnimCmd sAffineAnim_Numbers_0[] =
|
|
|
|
|
static const union AffineAnimCmd sAffineAnim_Numbers_Normal[] =
|
|
|
|
|
{
|
|
|
|
|
AFFINEANIMCMD_FRAME(256, 256, 0, 0),
|
|
|
|
|
AFFINEANIMCMD_END
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const union AffineAnimCmd sAffineAnim_Numbers_1[] =
|
|
|
|
|
static const union AffineAnimCmd sAffineAnim_Numbers_Squash[] =
|
|
|
|
|
{
|
|
|
|
|
AFFINEANIMCMD_FRAME(256, 256, 0, 0),
|
|
|
|
|
AFFINEANIMCMD_FRAME(16, -16, 0, 8),
|
|
|
|
|
AFFINEANIMCMD_END
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const union AffineAnimCmd sAffineAnim_Numbers_2[] =
|
|
|
|
|
static const union AffineAnimCmd sAffineAnim_Numbers_Stretch[] =
|
|
|
|
|
{
|
|
|
|
|
AFFINEANIMCMD_FRAME(-18, 18, 0, 8),
|
|
|
|
|
AFFINEANIMCMD_END
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const union AffineAnimCmd sAffineAnim_Numbers_3[] =
|
|
|
|
|
static const union AffineAnimCmd sAffineAnim_Numbers_Land[] =
|
|
|
|
|
{
|
|
|
|
|
AFFINEANIMCMD_FRAME( 6, -6, 0, 8),
|
|
|
|
|
AFFINEANIMCMD_FRAME( -4, 4, 0, 8),
|
|
|
|
|
@@ -593,10 +719,10 @@ static const union AffineAnimCmd sAffineAnim_Numbers_3[] =
|
|
|
|
|
|
|
|
|
|
static const union AffineAnimCmd *const sAffineAnimTable_Numbers[] =
|
|
|
|
|
{
|
|
|
|
|
sAffineAnim_Numbers_0,
|
|
|
|
|
sAffineAnim_Numbers_1,
|
|
|
|
|
sAffineAnim_Numbers_2,
|
|
|
|
|
sAffineAnim_Numbers_3
|
|
|
|
|
sAffineAnim_Numbers_Normal,
|
|
|
|
|
sAffineAnim_Numbers_Squash, // Push down before the jump
|
|
|
|
|
sAffineAnim_Numbers_Stretch, // Stretch up for the jump
|
|
|
|
|
sAffineAnim_Numbers_Land // Land after the jump
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static u8 CreateNumberSprite(u16 tileTag, u16 palTag, s16 x, s16 y, u8 subpriority)
|
|
|
|
|
|