Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MorsGames
GitHub Repository: MorsGames/sm64plus
Path: blob/master/src/game/behaviors/bully.inc.c
7861 views
1
// bully.c.inc
2
3
static struct ObjectHitbox sSmallBullyHitbox = {
4
/* interactType: */ INTERACT_BULLY,
5
/* downOffset: */ 0,
6
/* damageOrCoinValue: */ 1,
7
/* health: */ 0,
8
/* numLootCoins: */ 0,
9
/* radius: */ 73,
10
/* height: */ 123,
11
/* hurtboxRadius: */ 63,
12
/* hurtboxHeight: */ 113,
13
};
14
15
static struct ObjectHitbox sBigBullyHitbox = {
16
/* interactType: */ INTERACT_BULLY,
17
/* downOffset: */ 0,
18
/* damageOrCoinValue: */ 1,
19
/* health: */ 0,
20
/* numLootCoins: */ 0,
21
/* radius: */ 115,
22
/* height: */ 235,
23
/* hurtboxRadius: */ 105,
24
/* hurtboxHeight: */ 225,
25
};
26
27
void bhv_small_bully_init(void) {
28
cur_obj_init_animation(0);
29
30
o->oHomeX = o->oPosX;
31
o->oHomeZ = o->oPosZ;
32
o->oBehParams2ndByte = BULLY_BP_SIZE_SMALL;
33
o->oGravity = 4.0;
34
o->oFriction = 0.91;
35
o->oBuoyancy = 1.3;
36
37
obj_set_hitbox(o, &sSmallBullyHitbox);
38
}
39
40
void bhv_big_bully_init(void) {
41
cur_obj_init_animation(0);
42
43
o->oHomeX = o->oPosX;
44
o->oHomeY = o->oPosY;
45
o->oHomeZ = o->oPosZ;
46
o->oBehParams2ndByte = BULLY_BP_SIZE_BIG;
47
o->oGravity = 5.0;
48
o->oFriction = 0.93;
49
o->oBuoyancy = 1.3;
50
51
obj_set_hitbox(o, &sBigBullyHitbox);
52
}
53
54
void bully_check_mario_collision(void) {
55
if (
56
#ifdef VERSION_SH
57
o->oAction != BULLY_ACT_LAVA_DEATH && o->oAction != BULLY_ACT_DEATH_PLANE_DEATH &&
58
#endif
59
o->oInteractStatus & INT_STATUS_INTERACTED) {
60
if (o->oBehParams2ndByte == BULLY_BP_SIZE_SMALL)
61
cur_obj_play_sound_2(SOUND_OBJ2_BULLY_ATTACKED);
62
else
63
cur_obj_play_sound_2(SOUND_OBJ2_LARGE_BULLY_ATTACKED);
64
65
o->oInteractStatus &= ~INT_STATUS_INTERACTED;
66
o->oAction = BULLY_ACT_KNOCKBACK;
67
o->oFlags &= ~0x8; /* bit 3 */
68
cur_obj_init_animation(3);
69
o->oBullyMarioCollisionAngle = o->oMoveAngleYaw;
70
}
71
}
72
73
void bully_act_chase_mario(void) {
74
f32 homeX = o->oHomeX;
75
f32 posY = o->oPosY;
76
f32 homeZ = o->oHomeZ;
77
78
if (o->oTimer < 10) {
79
o->oForwardVel = 3.0;
80
obj_turn_toward_object(o, gMarioObject, 16, 4096);
81
} else if (o->oBehParams2ndByte == BULLY_BP_SIZE_SMALL) {
82
o->oForwardVel = 20.0;
83
if (o->oTimer >= 31)
84
o->oTimer = 0;
85
} else {
86
o->oForwardVel = 30.0;
87
if (o->oTimer >= 36)
88
o->oTimer = 0;
89
}
90
91
if (!is_point_within_radius_of_mario(homeX, posY, homeZ, 1000)) {
92
o->oAction = BULLY_ACT_PATROL;
93
cur_obj_init_animation(0);
94
}
95
}
96
97
void bully_act_knockback(void) {
98
if (o->oForwardVel < 10.0 && (s32) o->oVelY == 0) {
99
o->oForwardVel = 1.0;
100
o->oBullyKBTimerAndMinionKOCounter++;
101
o->oFlags |= 0x8; /* bit 3 */
102
o->oMoveAngleYaw = o->oFaceAngleYaw;
103
obj_turn_toward_object(o, gMarioObject, 16, 1280);
104
} else
105
o->header.gfx.animInfo.animFrame = 0;
106
107
if (o->oBullyKBTimerAndMinionKOCounter == 18) {
108
o->oAction = BULLY_ACT_CHASE_MARIO;
109
o->oBullyKBTimerAndMinionKOCounter = 0;
110
cur_obj_init_animation(1);
111
}
112
}
113
114
void bully_act_back_up(void) {
115
if (o->oTimer == 0) {
116
o->oFlags &= ~0x8; /* bit 3 */
117
o->oMoveAngleYaw += 0x8000;
118
}
119
120
o->oForwardVel = 5.0;
121
122
//! bully_backup_check() happens after this function, and has the potential to reset
123
// the bully's action to BULLY_ACT_BACK_UP. Because the back up action is only
124
// set to end when the timer EQUALS 15, if this happens on that frame, the bully
125
// will be stuck in BULLY_ACT_BACK_UP forever until Mario hits it or its death
126
// conditions are activated. However because its angle is set to its facing angle,
127
// it will walk forward instead of backing up.
128
129
if (o->oTimer == 15) {
130
o->oMoveAngleYaw = o->oFaceAngleYaw;
131
o->oFlags |= 0x8; /* bit 3 */
132
o->oAction = BULLY_ACT_PATROL;
133
}
134
}
135
136
void bully_backup_check(s16 collisionFlags) {
137
if (!(collisionFlags & 0x8) && o->oAction != BULLY_ACT_KNOCKBACK) /* bit 3 */
138
{
139
o->oPosX = o->oBullyPrevX;
140
o->oPosZ = o->oBullyPrevZ;
141
o->oAction = BULLY_ACT_BACK_UP;
142
}
143
}
144
145
void bully_play_stomping_sound(void) {
146
s16 sp26 = o->header.gfx.animInfo.animFrame;
147
switch (o->oAction) {
148
case BULLY_ACT_PATROL:
149
if (sp26 == 0 || sp26 == 12) {
150
if (o->oBehParams2ndByte == BULLY_BP_SIZE_SMALL)
151
cur_obj_play_sound_2(SOUND_OBJ_BULLY_WALK);
152
else
153
cur_obj_play_sound_2(SOUND_OBJ_BULLY_WALKING);
154
}
155
break;
156
157
case BULLY_ACT_CHASE_MARIO:
158
case BULLY_ACT_BACK_UP:
159
if (sp26 == 0 || sp26 == 5) {
160
if (o->oBehParams2ndByte == BULLY_BP_SIZE_SMALL)
161
cur_obj_play_sound_2(SOUND_OBJ_BULLY_WALK);
162
else
163
cur_obj_play_sound_2(SOUND_OBJ_BULLY_WALKING);
164
}
165
break;
166
}
167
}
168
169
void bully_step(void) {
170
s16 collisionFlags = 0;
171
collisionFlags = object_step();
172
bully_backup_check(collisionFlags);
173
bully_play_stomping_sound();
174
obj_check_floor_death(collisionFlags, sObjFloor);
175
176
if (o->oBullySubtype & BULLY_STYPE_CHILL) {
177
if (o->oPosY < 1030.0f)
178
o->oAction = BULLY_ACT_LAVA_DEATH;
179
}
180
}
181
182
void bully_spawn_coin(void) {
183
struct Object *coin = spawn_object(o, MODEL_YELLOW_COIN, bhvMovingYellowCoin);
184
#ifdef VERSION_JP // TODO: maybe move this ifdef logic to the header?
185
cur_obj_play_sound_2(SOUND_GENERAL_COIN_SPURT);
186
#elif defined(VERSION_EU) || defined(VERSION_SH)
187
cur_obj_play_sound_2(SOUND_GENERAL_COIN_SPURT_EU);
188
#else
189
cur_obj_play_sound_2(SOUND_GENERAL_COIN_SPURT_2);
190
#endif
191
coin->oForwardVel = 10.0f;
192
coin->oVelY = 100.0f;
193
coin->oPosY = o->oPosY + 310.0f;
194
coin->oMoveAngleYaw = (f32)(o->oBullyMarioCollisionAngle + 0x8000) + random_float() * 1024.0f;
195
}
196
197
void bully_act_level_death(void) {
198
if (obj_lava_death() == 1) {
199
if (o->oBehParams2ndByte == BULLY_BP_SIZE_SMALL) {
200
if (o->oBullySubtype == BULLY_STYPE_MINION)
201
o->parentObj->oBullyKBTimerAndMinionKOCounter++;
202
bully_spawn_coin();
203
} else {
204
spawn_mist_particles();
205
206
if (o->oBullySubtype == BULLY_STYPE_CHILL)
207
spawn_default_star(130.0f, 1600.0f, -4335.0f);
208
else {
209
spawn_default_star(0, 950.0f, -6800.0f);
210
spawn_object_abs_with_rot(o, 0, MODEL_NONE, bhvLllTumblingBridge, 0, 154, -5631, 0, 0,
211
0);
212
}
213
}
214
}
215
}
216
217
void bhv_bully_loop(void) {
218
o->oBullyPrevX = o->oPosX;
219
o->oBullyPrevY = o->oPosY;
220
o->oBullyPrevZ = o->oPosZ;
221
222
//! Because this function runs no matter what, Mario is able to interrupt the bully's
223
// death action by colliding with it. Since the bully hitbox is tall enough to collide
224
// with Mario even when it is under a lava floor, this can get the bully stuck OOB
225
// if there is nothing under the lava floor.
226
bully_check_mario_collision();
227
228
switch (o->oAction) {
229
case BULLY_ACT_PATROL:
230
o->oForwardVel = 5.0;
231
232
if (obj_return_home_if_safe(o, o->oHomeX, o->oPosY, o->oHomeZ, 800) == 1) {
233
o->oAction = BULLY_ACT_CHASE_MARIO;
234
cur_obj_init_animation(1);
235
}
236
237
bully_step();
238
break;
239
240
case BULLY_ACT_CHASE_MARIO:
241
bully_act_chase_mario();
242
bully_step();
243
break;
244
245
case BULLY_ACT_KNOCKBACK:
246
bully_act_knockback();
247
bully_step();
248
break;
249
250
case BULLY_ACT_BACK_UP:
251
bully_act_back_up();
252
bully_step();
253
break;
254
255
case BULLY_ACT_LAVA_DEATH:
256
bully_act_level_death();
257
break;
258
259
case BULLY_ACT_DEATH_PLANE_DEATH:
260
o->activeFlags = ACTIVE_FLAG_DEACTIVATED;
261
break;
262
}
263
264
set_object_visibility(o, 3000);
265
}
266
267
// sp38 = arg0
268
// sp3c = arg1
269
// sp40 = arg2
270
// sp44 = arg3
271
272
void big_bully_spawn_minion(s32 arg0, s32 arg1, s32 arg2, s16 arg3) {
273
struct Object *bully =
274
spawn_object_abs_with_rot(o, 0, MODEL_BULLY, bhvSmallBully, arg0, arg1, arg2, 0, arg3, 00);
275
bully->oBullySubtype = BULLY_STYPE_MINION;
276
bully->oBehParams2ndByte = BULLY_BP_SIZE_SMALL;
277
}
278
279
void bhv_big_bully_with_minions_init(void) {
280
big_bully_spawn_minion(4454, 307, -5426, 0);
281
big_bully_spawn_minion(3840, 307, -6041, 0);
282
big_bully_spawn_minion(3226, 307, -5426, 0);
283
284
o->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE;
285
286
cur_obj_become_intangible();
287
288
o->oAction = BULLY_ACT_INACTIVE;
289
}
290
291
void big_bully_spawn_star(void) {
292
if (obj_lava_death() == 1) {
293
spawn_mist_particles();
294
spawn_default_star(3700.0f, 600.0f, -5500.0f);
295
}
296
}
297
298
void bhv_big_bully_with_minions_loop(void) {
299
s16 collisionFlags;
300
301
o->oBullyPrevX = o->oPosX;
302
o->oBullyPrevY = o->oPosY;
303
o->oBullyPrevZ = o->oPosZ;
304
305
bully_check_mario_collision();
306
307
switch (o->oAction) {
308
case BULLY_ACT_PATROL:
309
o->oForwardVel = 5.0;
310
311
if (obj_return_home_if_safe(o, o->oHomeX, o->oPosY, o->oHomeZ, 1000) == 1) {
312
o->oAction = BULLY_ACT_CHASE_MARIO;
313
cur_obj_init_animation(1);
314
}
315
316
bully_step();
317
break;
318
319
case BULLY_ACT_CHASE_MARIO:
320
bully_act_chase_mario();
321
bully_step();
322
break;
323
324
case BULLY_ACT_KNOCKBACK:
325
bully_act_knockback();
326
bully_step();
327
break;
328
329
case BULLY_ACT_BACK_UP:
330
bully_act_back_up();
331
bully_step();
332
break;
333
334
case BULLY_ACT_INACTIVE:
335
//! The Big Bully that spawns from killing its 3 minions uses the knockback timer
336
// for counting the number of dead minions. This means that when it activates,
337
// the knockback timer is at 3 instead of 0. So the bully knockback time will
338
// be reduced by 3 frames (16.67%) on the first hit.
339
if (o->oBullyKBTimerAndMinionKOCounter == 3) {
340
play_puzzle_jingle();
341
342
if (o->oTimer >= 91)
343
o->oAction = BULLY_ACT_ACTIVATE_AND_FALL;
344
}
345
break;
346
347
case BULLY_ACT_ACTIVATE_AND_FALL:
348
collisionFlags = object_step();
349
if ((collisionFlags & 0x9) == 0x9) /* bits 0 and 3 */
350
o->oAction = BULLY_ACT_PATROL;
351
352
if (collisionFlags == 1) {
353
cur_obj_play_sound_2(SOUND_OBJ_THWOMP);
354
set_camera_shake_from_point(SHAKE_POS_SMALL, o->oPosX, o->oPosY, o->oPosZ);
355
spawn_mist_particles();
356
}
357
358
o->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE;
359
cur_obj_become_tangible();
360
break;
361
362
case BULLY_ACT_LAVA_DEATH:
363
big_bully_spawn_star();
364
break;
365
366
case BULLY_ACT_DEATH_PLANE_DEATH:
367
o->activeFlags = ACTIVE_FLAG_DEACTIVATED;
368
break;
369
}
370
}
371
372