Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MorsGames
GitHub Repository: MorsGames/sm64plus
Path: blob/master/src/game/behaviors/bowser_puzzle_piece.inc.c
7861 views
1
/**
2
* Behavior for the sliding Bowser puzzle in Lethal Lava Land.
3
*/
4
5
/*
6
* The pieces move in this order:
7
*
8
* 1, 2, 5, 6, 10, 9, 13, 12, 8, 7, 3, 4
9
*
10
* Once they reach the end of the routine they follow it backwards until the
11
* puzzle is complete again.
12
*
13
* Note that pieces 11 and 14 do not move.
14
*/
15
static s8 sPieceActions01[] = { 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
16
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 2, -1 };
17
static s8 sPieceActions02[] = { 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
18
2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, -1 };
19
static s8 sPieceActions05[] = { 2, 2, 2, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
20
2, 2, 2, 2, 2, 2, 2, 2, 6, 2, 2, 2, -1 };
21
static s8 sPieceActions06[] = { 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2,
22
2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, -1 };
23
static s8 sPieceActions10[] = { 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 2, 2, 2, 2,
24
2, 2, 2, 2, 2, 2, 6, 2, 2, 2, 2, 2, -1 };
25
static s8 sPieceActions09[] = { 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2,
26
2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, -1 };
27
static s8 sPieceActions13[] = { 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 2, 2,
28
2, 2, 2, 2, 6, 2, 2, 2, 2, 2, 2, 2, -1 };
29
static s8 sPieceActions12[] = { 2, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2,
30
2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, -1 };
31
static s8 sPieceActions08[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 2, 2, 2, 2,
32
2, 2, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, -1 };
33
static s8 sPieceActions07[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2,
34
2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -1 };
35
static s8 sPieceActions03[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 2, 2,
36
5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -1 };
37
static s8 sPieceActions04[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4,
38
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -1 };
39
static s8 sPieceActions11[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
40
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -1 };
41
static s8 sPieceActions14[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
42
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -1 };
43
44
struct BowserPuzzlePiece {
45
u8 model;
46
s8 xOffset;
47
s8 zOffset;
48
s8 initialAction;
49
s8 *actionList;
50
};
51
52
/*
53
* The puzzle pieces are initially laid out in the following manner:
54
*
55
* +---+---+---+
56
* | 1 | 2 | * |
57
* +---+---+---+---+
58
* | 3 | 4 | 5 | 6 |
59
* +---+---+---+---+
60
* | 7 | 8 | 9 |10 |
61
* +---+---+---+---+
62
* |11 |12 |13 |14 |
63
* +---+---+---+---+
64
*
65
* (* = star platform)
66
*/
67
static struct BowserPuzzlePiece sBowserPuzzlePieces[] = {
68
{ MODEL_LLL_BOWSER_PIECE_1, -5, -15, 1, sPieceActions01 },
69
{ MODEL_LLL_BOWSER_PIECE_2, 5, -15, 0, sPieceActions02 },
70
{ MODEL_LLL_BOWSER_PIECE_3, -15, -5, 0, sPieceActions03 },
71
{ MODEL_LLL_BOWSER_PIECE_4, -5, -5, 0, sPieceActions04 },
72
{ MODEL_LLL_BOWSER_PIECE_5, 5, -5, 0, sPieceActions05 },
73
{ MODEL_LLL_BOWSER_PIECE_6, 15, -5, 0, sPieceActions06 },
74
{ MODEL_LLL_BOWSER_PIECE_7, -15, 5, 0, sPieceActions07 },
75
{ MODEL_LLL_BOWSER_PIECE_8, -5, 5, 0, sPieceActions08 },
76
{ MODEL_LLL_BOWSER_PIECE_9, 5, 5, 0, sPieceActions09 },
77
{ MODEL_LLL_BOWSER_PIECE_10, 15, 5, 0, sPieceActions10 },
78
{ MODEL_LLL_BOWSER_PIECE_11, -15, 15, 0, sPieceActions11 },
79
{ MODEL_LLL_BOWSER_PIECE_12, -5, 15, 0, sPieceActions12 },
80
{ MODEL_LLL_BOWSER_PIECE_13, 5, 15, 0, sPieceActions13 },
81
{ MODEL_LLL_BOWSER_PIECE_14, 15, 15, 0, sPieceActions14 }
82
};
83
84
/**
85
* Spawn a single puzzle piece.
86
*/
87
void bhv_lll_bowser_puzzle_spawn_piece(s16 model, const BehaviorScript *behavior,
88
f32 xOffset, f32 zOffset,
89
s8 initialAction, s8 *actionList) {
90
struct Object *puzzlePiece = spawn_object(o, model, behavior);
91
puzzlePiece->oPosX += xOffset;
92
puzzlePiece->oPosY += 50.0f;
93
puzzlePiece->oPosZ += zOffset;
94
puzzlePiece->oAction = initialAction; // This action never gets executed.
95
puzzlePiece->oBowserPuzzlePieceActionList = actionList;
96
puzzlePiece->oBowserPuzzlePieceNextAction = actionList;
97
}
98
99
/**
100
* Spawn the 14 puzzle pieces.
101
*/
102
void bhv_lll_bowser_puzzle_spawn_pieces(f32 pieceWidth) {
103
s32 i;
104
105
// Spawn all 14 puzzle pieces.
106
for (i = 0; i < 14; i++)
107
bhv_lll_bowser_puzzle_spawn_piece(sBowserPuzzlePieces[i].model, bhvLllBowserPuzzlePiece,
108
sBowserPuzzlePieces[i].xOffset * pieceWidth / 10.0f,
109
sBowserPuzzlePieces[i].zOffset * pieceWidth / 10.0f,
110
sBowserPuzzlePieces[i].initialAction,
111
sBowserPuzzlePieces[i].actionList);
112
113
// The pieces should only be spawned once so go to the next action.
114
o->oAction++;
115
}
116
117
/*
118
* Does the initial spawn of the puzzle pieces and then waits to spawn 5 coins.
119
*/
120
void bhv_lll_bowser_puzzle_loop(void) {
121
s32 i;
122
UNUSED struct Object *sp28;
123
switch (o->oAction) {
124
case BOWSER_PUZZLE_ACT_SPAWN_PIECES:
125
bhv_lll_bowser_puzzle_spawn_pieces(480.0f);
126
break;
127
case BOWSER_PUZZLE_ACT_WAIT_FOR_COMPLETE:
128
// If both completion flags are set and Mario is within 1000 units...
129
if (o->oBowserPuzzleCompletionFlags == 3 && o->oDistanceToMario < 1000.0f) {
130
// Spawn 5 coins.
131
for (i = 0; i < 5; i++)
132
sp28 = spawn_object(o, MODEL_YELLOW_COIN, bhvSingleCoinGetsSpawned);
133
134
// Reset completion flags (even though they never get checked again).
135
o->oBowserPuzzleCompletionFlags = 0;
136
137
// Go to next action so we don't spawn 5 coins ever again.
138
o->oAction++;
139
}
140
break;
141
case BOWSER_PUZZLE_ACT_DONE:
142
break;
143
}
144
}
145
146
/*
147
* Action 0 is never executed since it is not defined in any action lists.
148
*/
149
void bhv_lll_bowser_puzzle_piece_action_0(void) {
150
}
151
152
/*
153
* Action 1 is never executed since it is not defined in any action lists.
154
*/
155
void bhv_lll_bowser_puzzle_piece_action_1(void) {
156
o->oPosY += 50.0f;
157
o->oAction = 3;
158
}
159
160
/*
161
* Update the puzzle piece.
162
*/
163
void bhv_lll_bowser_puzzle_piece_update(void) {
164
s8 *nextAction = o->oBowserPuzzlePieceNextAction;
165
166
// If Mario is standing on this puzzle piece, set a flag in the parent.
167
if (gMarioObject->platform == o)
168
o->parentObj->oBowserPuzzleCompletionFlags = 1;
169
170
// If we should advance to the next action...
171
if (o->oBowserPuzzlePieceContinuePerformingAction == 0) {
172
// Start doing the next action.
173
cur_obj_change_action(*nextAction);
174
175
// Advance the pointer to the next action.
176
nextAction++;
177
o->oBowserPuzzlePieceNextAction = nextAction;
178
179
// If we're at the end of the list...
180
if (*nextAction == -1) {
181
// Set the other completion flag in the parent.
182
o->parentObj->oBowserPuzzleCompletionFlags |= 2;
183
184
// The next action is the first action in the list again.
185
o->oBowserPuzzlePieceNextAction = o->oBowserPuzzlePieceActionList;
186
}
187
188
// Keep doing this action until it's complete.
189
o->oBowserPuzzlePieceContinuePerformingAction = 1;
190
}
191
}
192
193
void bhv_lll_bowser_puzzle_piece_move(f32 xOffset, f32 zOffset, s32 duration, UNUSED s32 a3) {
194
// For the first 20 frames, shake the puzzle piece up and down.
195
if (o->oTimer < 20) {
196
if (o->oTimer % 2)
197
o->oBowserPuzzlePieceOffsetY = 0.0f;
198
else
199
o->oBowserPuzzlePieceOffsetY = -6.0f;
200
} else {
201
// On frame 20, play the shifting sound.
202
if (o->oTimer == 20)
203
cur_obj_play_sound_2(SOUND_OBJ2_BOWSER_PUZZLE_PIECE_MOVE);
204
205
// For the number of frames specified by duration, move the piece.
206
if (o->oTimer < duration + 20) {
207
o->oBowserPuzzlePieceOffsetX += xOffset;
208
o->oBowserPuzzlePieceOffsetZ += zOffset;
209
} else {
210
// This doesn't actually accomplish anything since
211
// cur_obj_change_action is going to be called before the
212
// next action is performed anyway.
213
o->oAction = 2;
214
215
// Advance to the next action.
216
o->oBowserPuzzlePieceContinuePerformingAction = 0;
217
}
218
}
219
}
220
221
void bhv_lll_bowser_puzzle_piece_idle(void) {
222
UNUSED s32 sp4;
223
224
// For the first 24 frames, do nothing.
225
if (o->oTimer < 24)
226
sp4 = 0;
227
else
228
// Then advance to the next action.
229
o->oBowserPuzzlePieceContinuePerformingAction = 0;
230
}
231
232
void bhv_lll_bowser_puzzle_piece_move_left(void) {
233
bhv_lll_bowser_puzzle_piece_move(-120.0f, 0.0f, 4, 4);
234
}
235
236
void bhv_lll_bowser_puzzle_piece_move_right(void) {
237
bhv_lll_bowser_puzzle_piece_move(120.0f, 0.0f, 4, 5);
238
}
239
240
void bhv_lll_bowser_puzzle_piece_move_up(void) {
241
bhv_lll_bowser_puzzle_piece_move(0.0f, -120.0f, 4, 6);
242
}
243
244
void bhv_lll_bowser_puzzle_piece_move_down(void) {
245
bhv_lll_bowser_puzzle_piece_move(0.0f, 120.0f, 4, 3);
246
}
247
248
void (*sBowserPuzzlePieceActions[])(void) = {
249
bhv_lll_bowser_puzzle_piece_action_0, bhv_lll_bowser_puzzle_piece_action_1,
250
bhv_lll_bowser_puzzle_piece_idle, bhv_lll_bowser_puzzle_piece_move_left,
251
bhv_lll_bowser_puzzle_piece_move_right, bhv_lll_bowser_puzzle_piece_move_up,
252
bhv_lll_bowser_puzzle_piece_move_down
253
};
254
255
void bhv_lll_bowser_puzzle_piece_loop(void) {
256
bhv_lll_bowser_puzzle_piece_update();
257
258
cur_obj_call_action_function(sBowserPuzzlePieceActions);
259
260
o->oPosX = o->oBowserPuzzlePieceOffsetX + o->oHomeX;
261
o->oPosY = o->oBowserPuzzlePieceOffsetY + o->oHomeY;
262
o->oPosZ = o->oBowserPuzzlePieceOffsetZ + o->oHomeZ;
263
}
264
265