264 lines
9.8 KiB
C
264 lines
9.8 KiB
C
/**
|
|
* Behavior for the sliding Bowser puzzle in Lethal Lava Land.
|
|
*/
|
|
|
|
/*
|
|
* The pieces move in this order:
|
|
*
|
|
* 1, 2, 5, 6, 10, 9, 13, 12, 8, 7, 3, 4
|
|
*
|
|
* Once they reach the end of the routine they follow it backwards until the
|
|
* puzzle is complete again.
|
|
*
|
|
* Note that pieces 11 and 14 do not move.
|
|
*/
|
|
static s8 sPieceActions01[] = { 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 2, -1 };
|
|
static s8 sPieceActions02[] = { 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, -1 };
|
|
static s8 sPieceActions05[] = { 2, 2, 2, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
2, 2, 2, 2, 2, 2, 2, 2, 6, 2, 2, 2, -1 };
|
|
static s8 sPieceActions06[] = { 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, -1 };
|
|
static s8 sPieceActions10[] = { 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
2, 2, 2, 2, 2, 2, 6, 2, 2, 2, 2, 2, -1 };
|
|
static s8 sPieceActions09[] = { 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2,
|
|
2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, -1 };
|
|
static s8 sPieceActions13[] = { 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 2, 2,
|
|
2, 2, 2, 2, 6, 2, 2, 2, 2, 2, 2, 2, -1 };
|
|
static s8 sPieceActions12[] = { 2, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2,
|
|
2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, -1 };
|
|
static s8 sPieceActions08[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 2, 2, 2, 2,
|
|
2, 2, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, -1 };
|
|
static s8 sPieceActions07[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2,
|
|
2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -1 };
|
|
static s8 sPieceActions03[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 2, 2,
|
|
5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -1 };
|
|
static s8 sPieceActions04[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4,
|
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -1 };
|
|
static s8 sPieceActions11[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -1 };
|
|
static s8 sPieceActions14[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -1 };
|
|
|
|
struct BowserPuzzlePiece {
|
|
u8 model;
|
|
s8 xOffset;
|
|
s8 zOffset;
|
|
s8 initialAction;
|
|
s8 *actionList;
|
|
};
|
|
|
|
/*
|
|
* The puzzle pieces are initially laid out in the following manner:
|
|
*
|
|
* +---+---+---+
|
|
* | 1 | 2 | * |
|
|
* +---+---+---+---+
|
|
* | 3 | 4 | 5 | 6 |
|
|
* +---+---+---+---+
|
|
* | 7 | 8 | 9 |10 |
|
|
* +---+---+---+---+
|
|
* |11 |12 |13 |14 |
|
|
* +---+---+---+---+
|
|
*
|
|
* (* = star platform)
|
|
*/
|
|
static struct BowserPuzzlePiece sBowserPuzzlePieces[] = {
|
|
{ MODEL_LLL_BOWSER_PIECE_1, -5, -15, 1, sPieceActions01 },
|
|
{ MODEL_LLL_BOWSER_PIECE_2, 5, -15, 0, sPieceActions02 },
|
|
{ MODEL_LLL_BOWSER_PIECE_3, -15, -5, 0, sPieceActions03 },
|
|
{ MODEL_LLL_BOWSER_PIECE_4, -5, -5, 0, sPieceActions04 },
|
|
{ MODEL_LLL_BOWSER_PIECE_5, 5, -5, 0, sPieceActions05 },
|
|
{ MODEL_LLL_BOWSER_PIECE_6, 15, -5, 0, sPieceActions06 },
|
|
{ MODEL_LLL_BOWSER_PIECE_7, -15, 5, 0, sPieceActions07 },
|
|
{ MODEL_LLL_BOWSER_PIECE_8, -5, 5, 0, sPieceActions08 },
|
|
{ MODEL_LLL_BOWSER_PIECE_9, 5, 5, 0, sPieceActions09 },
|
|
{ MODEL_LLL_BOWSER_PIECE_10, 15, 5, 0, sPieceActions10 },
|
|
{ MODEL_LLL_BOWSER_PIECE_11, -15, 15, 0, sPieceActions11 },
|
|
{ MODEL_LLL_BOWSER_PIECE_12, -5, 15, 0, sPieceActions12 },
|
|
{ MODEL_LLL_BOWSER_PIECE_13, 5, 15, 0, sPieceActions13 },
|
|
{ MODEL_LLL_BOWSER_PIECE_14, 15, 15, 0, sPieceActions14 }
|
|
};
|
|
|
|
/**
|
|
* Spawn a single puzzle piece.
|
|
*/
|
|
void bhv_lll_bowser_puzzle_spawn_piece(s16 model, const BehaviorScript *behavior,
|
|
f32 xOffset, f32 zOffset,
|
|
s8 initialAction, s8 *actionList) {
|
|
struct Object *puzzlePiece = spawn_object(o, model, behavior);
|
|
puzzlePiece->oPosX += xOffset;
|
|
puzzlePiece->oPosY += 50.0f;
|
|
puzzlePiece->oPosZ += zOffset;
|
|
puzzlePiece->oAction = initialAction; // This action never gets executed.
|
|
puzzlePiece->oBowserPuzzlePieceActionList = actionList;
|
|
puzzlePiece->oBowserPuzzlePieceNextAction = actionList;
|
|
}
|
|
|
|
/**
|
|
* Spawn the 14 puzzle pieces.
|
|
*/
|
|
void bhv_lll_bowser_puzzle_spawn_pieces(f32 pieceWidth) {
|
|
s32 i;
|
|
|
|
// Spawn all 14 puzzle pieces.
|
|
for (i = 0; i < 14; i++)
|
|
bhv_lll_bowser_puzzle_spawn_piece(sBowserPuzzlePieces[i].model, bhvLllBowserPuzzlePiece,
|
|
sBowserPuzzlePieces[i].xOffset * pieceWidth / 10.0f,
|
|
sBowserPuzzlePieces[i].zOffset * pieceWidth / 10.0f,
|
|
sBowserPuzzlePieces[i].initialAction,
|
|
sBowserPuzzlePieces[i].actionList);
|
|
|
|
// The pieces should only be spawned once so go to the next action.
|
|
o->oAction++;
|
|
}
|
|
|
|
/*
|
|
* Does the initial spawn of the puzzle pieces and then waits to spawn 5 coins.
|
|
*/
|
|
void bhv_lll_bowser_puzzle_loop(void) {
|
|
s32 i;
|
|
UNUSED struct Object *sp28;
|
|
switch (o->oAction) {
|
|
case BOWSER_PUZZLE_ACT_SPAWN_PIECES:
|
|
bhv_lll_bowser_puzzle_spawn_pieces(480.0f);
|
|
break;
|
|
case BOWSER_PUZZLE_ACT_WAIT_FOR_COMPLETE:
|
|
// If both completion flags are set and Mario is within 1000 units...
|
|
if (o->oBowserPuzzleCompletionFlags == 3 && o->oDistanceToMario < 1000.0f) {
|
|
// Spawn 5 coins.
|
|
for (i = 0; i < 5; i++)
|
|
sp28 = spawn_object(o, MODEL_YELLOW_COIN, bhvSingleCoinGetsSpawned);
|
|
|
|
// Reset completion flags (even though they never get checked again).
|
|
o->oBowserPuzzleCompletionFlags = 0;
|
|
|
|
// Go to next action so we don't spawn 5 coins ever again.
|
|
o->oAction++;
|
|
}
|
|
break;
|
|
case BOWSER_PUZZLE_ACT_DONE:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Action 0 is never executed since it is not defined in any action lists.
|
|
*/
|
|
void bhv_lll_bowser_puzzle_piece_action_0(void) {
|
|
}
|
|
|
|
/*
|
|
* Action 1 is never executed since it is not defined in any action lists.
|
|
*/
|
|
void bhv_lll_bowser_puzzle_piece_action_1(void) {
|
|
o->oPosY += 50.0f;
|
|
o->oAction = 3;
|
|
}
|
|
|
|
/*
|
|
* Update the puzzle piece.
|
|
*/
|
|
void bhv_lll_bowser_puzzle_piece_update(void) {
|
|
s8 *nextAction = o->oBowserPuzzlePieceNextAction;
|
|
|
|
// If Mario is standing on this puzzle piece, set a flag in the parent.
|
|
if (gMarioObject->platform == o)
|
|
o->parentObj->oBowserPuzzleCompletionFlags = 1;
|
|
|
|
// If we should advance to the next action...
|
|
if (o->oBowserPuzzlePieceContinuePerformingAction == 0) {
|
|
// Start doing the next action.
|
|
cur_obj_change_action(*nextAction);
|
|
|
|
// Advance the pointer to the next action.
|
|
nextAction++;
|
|
o->oBowserPuzzlePieceNextAction = nextAction;
|
|
|
|
// If we're at the end of the list...
|
|
if (*nextAction == -1) {
|
|
// Set the other completion flag in the parent.
|
|
o->parentObj->oBowserPuzzleCompletionFlags |= 2;
|
|
|
|
// The next action is the first action in the list again.
|
|
o->oBowserPuzzlePieceNextAction = o->oBowserPuzzlePieceActionList;
|
|
}
|
|
|
|
// Keep doing this action until it's complete.
|
|
o->oBowserPuzzlePieceContinuePerformingAction = 1;
|
|
}
|
|
}
|
|
|
|
void bhv_lll_bowser_puzzle_piece_move(f32 xOffset, f32 zOffset, s32 duration, UNUSED s32 a3) {
|
|
// For the first 20 frames, shake the puzzle piece up and down.
|
|
if (o->oTimer < 20) {
|
|
if (o->oTimer % 2)
|
|
o->oBowserPuzzlePieceOffsetY = 0.0f;
|
|
else
|
|
o->oBowserPuzzlePieceOffsetY = -6.0f;
|
|
} else {
|
|
// On frame 20, play the shifting sound.
|
|
if (o->oTimer == 20)
|
|
cur_obj_play_sound_2(SOUND_OBJ2_BOWSER_PUZZLE_PIECE_MOVE);
|
|
|
|
// For the number of frames specified by duration, move the piece.
|
|
if (o->oTimer < duration + 20) {
|
|
o->oBowserPuzzlePieceOffsetX += xOffset;
|
|
o->oBowserPuzzlePieceOffsetZ += zOffset;
|
|
} else {
|
|
// This doesn't actually accomplish anything since
|
|
// cur_obj_change_action is going to be called before the
|
|
// next action is performed anyway.
|
|
o->oAction = 2;
|
|
|
|
// Advance to the next action.
|
|
o->oBowserPuzzlePieceContinuePerformingAction = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void bhv_lll_bowser_puzzle_piece_idle(void) {
|
|
UNUSED s32 sp4;
|
|
|
|
// For the first 24 frames, do nothing.
|
|
if (o->oTimer < 24)
|
|
sp4 = 0;
|
|
else
|
|
// Then advance to the next action.
|
|
o->oBowserPuzzlePieceContinuePerformingAction = 0;
|
|
}
|
|
|
|
void bhv_lll_bowser_puzzle_piece_move_left(void) {
|
|
bhv_lll_bowser_puzzle_piece_move(-120.0f, 0.0f, 4, 4);
|
|
}
|
|
|
|
void bhv_lll_bowser_puzzle_piece_move_right(void) {
|
|
bhv_lll_bowser_puzzle_piece_move(120.0f, 0.0f, 4, 5);
|
|
}
|
|
|
|
void bhv_lll_bowser_puzzle_piece_move_up(void) {
|
|
bhv_lll_bowser_puzzle_piece_move(0.0f, -120.0f, 4, 6);
|
|
}
|
|
|
|
void bhv_lll_bowser_puzzle_piece_move_down(void) {
|
|
bhv_lll_bowser_puzzle_piece_move(0.0f, 120.0f, 4, 3);
|
|
}
|
|
|
|
void (*sBowserPuzzlePieceActions[])(void) = {
|
|
bhv_lll_bowser_puzzle_piece_action_0, bhv_lll_bowser_puzzle_piece_action_1,
|
|
bhv_lll_bowser_puzzle_piece_idle, bhv_lll_bowser_puzzle_piece_move_left,
|
|
bhv_lll_bowser_puzzle_piece_move_right, bhv_lll_bowser_puzzle_piece_move_up,
|
|
bhv_lll_bowser_puzzle_piece_move_down
|
|
};
|
|
|
|
void bhv_lll_bowser_puzzle_piece_loop(void) {
|
|
bhv_lll_bowser_puzzle_piece_update();
|
|
|
|
cur_obj_call_action_function(sBowserPuzzlePieceActions);
|
|
|
|
o->oPosX = o->oBowserPuzzlePieceOffsetX + o->oHomeX;
|
|
o->oPosY = o->oBowserPuzzlePieceOffsetY + o->oHomeY;
|
|
o->oPosZ = o->oBowserPuzzlePieceOffsetZ + o->oHomeZ;
|
|
}
|