Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MorsGames
GitHub Repository: MorsGames/sm64plus
Path: blob/master/src/game/mario_actions_automatic.c
7858 views
1
#include <PR/ultratypes.h>
2
3
#include "sm64.h"
4
#include "behavior_data.h"
5
#include "mario_actions_automatic.h"
6
#include "audio/external.h"
7
#include "area.h"
8
#include "mario.h"
9
#include "mario_step.h"
10
#include "engine/math_util.h"
11
#include "memory.h"
12
#include "engine/graph_node.h"
13
#include "save_file.h"
14
#include "engine/surface_collision.h"
15
#include "interaction.h"
16
#include "camera.h"
17
#include "level_table.h"
18
#include "rumble_init.h"
19
20
#include "settings.h"
21
22
#define POLE_NONE 0
23
#define POLE_TOUCHED_FLOOR 1
24
#define POLE_FELL_OFF 2
25
26
#define HANG_NONE 0
27
#define HANG_HIT_CEIL_OR_OOB 1
28
#define HANG_LEFT_CEIL 2
29
30
void add_tree_leaf_particles(struct MarioState *m) {
31
f32 leafHeight;
32
33
if (m->usedObj->behavior == segmented_to_virtual(bhvTree)) {
34
// make leaf effect spawn higher on the Shifting Sand Land palm tree
35
if (gCurrLevelNum == LEVEL_SSL) {
36
leafHeight = 250.0f;
37
} else {
38
leafHeight = 100.0f;
39
}
40
if (m->pos[1] - m->floorHeight > leafHeight) {
41
m->particleFlags |= PARTICLE_LEAF;
42
}
43
}
44
}
45
46
void play_climbing_sounds(struct MarioState *m, s32 b) {
47
s32 isOnTree = (m->usedObj->behavior == segmented_to_virtual(bhvTree));
48
49
if (b == 1) {
50
if (is_anim_past_frame(m, 1)) {
51
play_sound(isOnTree ? SOUND_ACTION_CLIMB_UP_TREE : SOUND_ACTION_CLIMB_UP_POLE,
52
m->marioObj->header.gfx.cameraToObject);
53
}
54
} else {
55
play_sound(isOnTree ? SOUND_MOVING_SLIDE_DOWN_TREE : SOUND_MOVING_SLIDE_DOWN_POLE,
56
m->marioObj->header.gfx.cameraToObject);
57
}
58
}
59
60
s32 set_pole_position(struct MarioState *m, f32 offsetY) {
61
UNUSED s32 unused1;
62
UNUSED s32 unused2;
63
UNUSED s32 unused3;
64
struct Surface *floor;
65
struct Surface *ceil;
66
f32 floorHeight;
67
f32 ceilHeight;
68
s32 collided;
69
s32 result = POLE_NONE;
70
f32 poleTop = m->usedObj->hitboxHeight - 100.0f;
71
struct Object *marioObj = m->marioObj;
72
73
if (marioObj->oMarioPolePos > poleTop) {
74
marioObj->oMarioPolePos = poleTop;
75
}
76
77
m->pos[0] = m->usedObj->oPosX;
78
m->pos[2] = m->usedObj->oPosZ;
79
m->pos[1] = m->usedObj->oPosY + marioObj->oMarioPolePos + offsetY;
80
81
collided = f32_find_wall_collision(&m->pos[0], &m->pos[1], &m->pos[2], 60.0f, 50.0f);
82
collided |= f32_find_wall_collision(&m->pos[0], &m->pos[1], &m->pos[2], 30.0f, 24.0f);
83
84
ceilHeight = vec3f_find_ceil(m->pos, m->pos[1], &ceil);
85
if (m->pos[1] > ceilHeight - 160.0f) {
86
m->pos[1] = ceilHeight - 160.0f;
87
marioObj->oMarioPolePos = m->pos[1] - m->usedObj->oPosY;
88
}
89
90
floorHeight = find_floor(m->pos[0], m->pos[1], m->pos[2], &floor);
91
if (m->pos[1] < floorHeight) {
92
m->pos[1] = floorHeight;
93
set_mario_action(m, ACT_IDLE, 0);
94
result = POLE_TOUCHED_FLOOR;
95
} else if (marioObj->oMarioPolePos < -m->usedObj->hitboxDownOffset) {
96
m->pos[1] = m->usedObj->oPosY - m->usedObj->hitboxDownOffset;
97
set_mario_action(m, ACT_FREEFALL, 0);
98
result = POLE_FELL_OFF;
99
} else if (collided) {
100
if (m->pos[1] > floorHeight + 20.0f) {
101
m->forwardVel = -2.0f;
102
set_mario_action(m, ACT_SOFT_BONK, 0);
103
result = POLE_FELL_OFF;
104
} else {
105
set_mario_action(m, ACT_IDLE, 0);
106
result = POLE_TOUCHED_FLOOR;
107
}
108
}
109
110
vec3f_copy(m->marioObj->header.gfx.pos, m->pos);
111
vec3s_set(m->marioObj->header.gfx.angle, m->usedObj->oMoveAnglePitch, m->faceAngle[1],
112
m->usedObj->oMoveAngleRoll);
113
114
return result;
115
}
116
117
s32 act_holding_pole(struct MarioState *m) {
118
struct Object *marioObj = m->marioObj;
119
120
#ifdef VERSION_JP
121
if (m->input & INPUT_A_PRESSED) {
122
add_tree_leaf_particles(m);
123
m->faceAngle[1] += 0x8000;
124
return set_mario_action(m, ACT_WALL_KICK_AIR, 0);
125
}
126
127
if (m->input & INPUT_Z_PRESSED) {
128
add_tree_leaf_particles(m);
129
m->forwardVel = -2.0f;
130
return set_mario_action(m, ACT_SOFT_BONK, 0);
131
}
132
#else
133
if ((m->input & INPUT_Z_PRESSED) || m->health < 0x100) {
134
add_tree_leaf_particles(m);
135
m->forwardVel = -2.0f;
136
return set_mario_action(m, ACT_SOFT_BONK, 0);
137
}
138
139
if (m->input & INPUT_A_PRESSED) {
140
add_tree_leaf_particles(m);
141
m->faceAngle[1] += 0x8000;
142
return set_mario_action(m, ACT_WALL_KICK_AIR, 0);
143
}
144
#endif
145
146
if (m->controller->stickY > 16.0f) {
147
f32 poleTop = m->usedObj->hitboxHeight - 100.0f;
148
const BehaviorScript *poleBehavior = virtual_to_segmented(0x13, m->usedObj->behavior);
149
150
if (marioObj->oMarioPolePos < poleTop - 0.4f) {
151
return set_mario_action(m, ACT_CLIMBING_POLE, 0);
152
}
153
154
if (poleBehavior != bhvGiantPole && m->controller->stickY > 50.0f) {
155
return set_mario_action(m, ACT_TOP_OF_POLE_TRANSITION, 0);
156
}
157
}
158
159
if (m->controller->stickY < -16.0f) {
160
marioObj->oMarioPoleYawVel -= m->controller->stickY * 2;
161
if (marioObj->oMarioPoleYawVel > 0x1000) {
162
marioObj->oMarioPoleYawVel = 0x1000;
163
}
164
165
m->faceAngle[1] += marioObj->oMarioPoleYawVel;
166
marioObj->oMarioPolePos -= marioObj->oMarioPoleYawVel / 0x100;
167
168
if (m->usedObj->behavior == segmented_to_virtual(bhvTree)) {
169
//! The Shifting Sand Land palm tree check is done climbing up in
170
// add_tree_leaf_particles, but not here, when climbing down.
171
if (m->pos[1] - m->floorHeight > 100.0f) {
172
m->particleFlags |= PARTICLE_LEAF;
173
}
174
}
175
play_climbing_sounds(m, 2);
176
#if ENABLE_RUMBLE
177
reset_rumble_timers();
178
#endif
179
set_sound_moving_speed(SOUND_BANK_MOVING, marioObj->oMarioPoleYawVel / 0x100 * 2);
180
} else {
181
marioObj->oMarioPoleYawVel = 0;
182
m->faceAngle[1] -= m->controller->stickX * 16.0f;
183
}
184
185
if (set_pole_position(m, 0.0f) == POLE_NONE) {
186
set_mario_animation(m, MARIO_ANIM_IDLE_ON_POLE);
187
}
188
189
return FALSE;
190
}
191
192
s32 act_climbing_pole(struct MarioState *m) {
193
s32 sp24;
194
struct Object *marioObj = m->marioObj;
195
s16 cameraAngle = m->area->camera->yaw;
196
197
#ifndef VERSION_JP
198
if (m->health < 0x100) {
199
add_tree_leaf_particles(m);
200
m->forwardVel = -2.0f;
201
return set_mario_action(m, ACT_SOFT_BONK, 0);
202
}
203
#endif
204
205
if (m->input & INPUT_A_PRESSED) {
206
add_tree_leaf_particles(m);
207
m->faceAngle[1] += 0x8000;
208
return set_mario_action(m, ACT_WALL_KICK_AIR, 0);
209
}
210
211
if (m->controller->stickY < 8.0f) {
212
return set_mario_action(m, ACT_HOLDING_POLE, 0);
213
}
214
215
marioObj->oMarioPolePos += m->controller->stickY / 8.0f;
216
marioObj->oMarioPoleYawVel = 0;
217
m->faceAngle[1] = cameraAngle - approach_s32((s16)(cameraAngle - m->faceAngle[1]), 0, 0x400, 0x400);
218
219
if (set_pole_position(m, 0.0f) == POLE_NONE) {
220
sp24 = m->controller->stickY / 4.0f * 0x10000;
221
set_mario_anim_with_accel(m, MARIO_ANIM_CLIMB_UP_POLE, sp24);
222
add_tree_leaf_particles(m);
223
play_climbing_sounds(m, 1);
224
}
225
226
return FALSE;
227
}
228
229
s32 act_grab_pole_slow(struct MarioState *m) {
230
play_sound_if_no_flag(m, SOUND_MARIO_WHOA, MARIO_MARIO_SOUND_PLAYED);
231
232
if (set_pole_position(m, 0.0f) == POLE_NONE) {
233
set_mario_animation(m, MARIO_ANIM_GRAB_POLE_SHORT);
234
if (is_anim_at_end(m)) {
235
set_mario_action(m, ACT_HOLDING_POLE, 0);
236
}
237
add_tree_leaf_particles(m);
238
}
239
240
return FALSE;
241
}
242
243
s32 act_grab_pole_fast(struct MarioState *m) {
244
struct Object *marioObj = m->marioObj;
245
246
play_sound_if_no_flag(m, SOUND_MARIO_WHOA, MARIO_MARIO_SOUND_PLAYED);
247
m->faceAngle[1] += marioObj->oMarioPoleYawVel;
248
marioObj->oMarioPoleYawVel = marioObj->oMarioPoleYawVel * 8 / 10;
249
250
if (set_pole_position(m, 0.0f) == POLE_NONE) {
251
if (marioObj->oMarioPoleYawVel > 0x800) {
252
set_mario_animation(m, MARIO_ANIM_GRAB_POLE_SWING_PART1);
253
} else {
254
set_mario_animation(m, MARIO_ANIM_GRAB_POLE_SWING_PART2);
255
if (is_anim_at_end(m)) {
256
marioObj->oMarioPoleYawVel = 0;
257
set_mario_action(m, ACT_HOLDING_POLE, 0);
258
}
259
}
260
add_tree_leaf_particles(m);
261
}
262
263
return FALSE;
264
}
265
266
s32 act_top_of_pole_transition(struct MarioState *m) {
267
struct Object *marioObj = m->marioObj;
268
269
marioObj->oMarioPoleYawVel = 0;
270
if (m->actionArg == 0) {
271
set_mario_animation(m, MARIO_ANIM_START_HANDSTAND);
272
if (is_anim_at_end(m)) {
273
return set_mario_action(m, ACT_TOP_OF_POLE, 0);
274
}
275
} else {
276
set_mario_animation(m, MARIO_ANIM_RETURN_FROM_HANDSTAND);
277
if (m->marioObj->header.gfx.animInfo.animFrame == 0) {
278
return set_mario_action(m, ACT_HOLDING_POLE, 0);
279
}
280
}
281
282
set_pole_position(m, return_mario_anim_y_translation(m));
283
return FALSE;
284
}
285
286
s32 act_top_of_pole(struct MarioState *m) {
287
UNUSED struct Object *marioObj = m->marioObj;
288
289
if (m->input & INPUT_A_PRESSED) {
290
return set_mario_action(m, ACT_TOP_OF_POLE_JUMP, 0);
291
}
292
if (m->controller->stickY < -16.0f) {
293
return set_mario_action(m, ACT_TOP_OF_POLE_TRANSITION, 1);
294
}
295
296
m->faceAngle[1] -= m->controller->stickX * 16.0f;
297
298
set_mario_animation(m, MARIO_ANIM_HANDSTAND_IDLE);
299
set_pole_position(m, return_mario_anim_y_translation(m));
300
return FALSE;
301
}
302
303
s32 perform_hanging_step(struct MarioState *m, Vec3f nextPos) {
304
UNUSED s32 unused;
305
struct Surface *ceil;
306
struct Surface *floor;
307
f32 ceilHeight;
308
f32 floorHeight;
309
f32 ceilOffset;
310
311
m->wall = resolve_and_return_wall_collisions(nextPos, 50.0f, 50.0f);
312
floorHeight = find_floor(nextPos[0], nextPos[1], nextPos[2], &floor);
313
if (configApplyBugFixes > 1)
314
ceilHeight = vec3f_find_ceil(nextPos, nextPos[1], &ceil);
315
else
316
ceilHeight = vec3f_find_ceil(nextPos, floorHeight, &ceil);
317
318
if (floor == NULL) {
319
return HANG_HIT_CEIL_OR_OOB;
320
}
321
if (ceil == NULL) {
322
return HANG_LEFT_CEIL;
323
}
324
if (ceilHeight - floorHeight <= 160.0f) {
325
return HANG_HIT_CEIL_OR_OOB;
326
}
327
if (ceil->type != SURFACE_HANGABLE) {
328
return HANG_LEFT_CEIL;
329
}
330
331
ceilOffset = ceilHeight - (nextPos[1] + 160.0f);
332
if (ceilOffset < -30.0f) {
333
return HANG_HIT_CEIL_OR_OOB;
334
}
335
if (ceilOffset > 30.0f) {
336
return HANG_LEFT_CEIL;
337
}
338
339
nextPos[1] = m->ceilHeight - 160.0f;
340
vec3f_copy(m->pos, nextPos);
341
342
m->floor = floor;
343
m->floorHeight = floorHeight;
344
m->ceil = ceil;
345
m->ceilHeight = ceilHeight;
346
347
return HANG_NONE;
348
}
349
350
s32 update_hang_moving(struct MarioState *m) {
351
s32 stepResult;
352
Vec3f nextPos;
353
f32 maxSpeed;
354
355
if (configImprovedHanging)
356
maxSpeed = 8.0f;
357
else
358
maxSpeed = 4.0f;
359
360
m->forwardVel += 1.0f;
361
if (m->forwardVel > maxSpeed) {
362
m->forwardVel = maxSpeed;
363
}
364
365
m->faceAngle[1] =
366
m->intendedYaw - approach_s32((s16)(m->intendedYaw - m->faceAngle[1]), 0, 0x800, 0x800);
367
368
m->slideYaw = m->faceAngle[1];
369
m->slideVelX = m->forwardVel * sins(m->faceAngle[1]);
370
m->slideVelZ = m->forwardVel * coss(m->faceAngle[1]);
371
372
m->vel[0] = m->slideVelX;
373
m->vel[1] = 0.0f;
374
m->vel[2] = m->slideVelZ;
375
376
nextPos[0] = m->pos[0] - m->ceil->normal.y * m->vel[0];
377
nextPos[2] = m->pos[2] - m->ceil->normal.y * m->vel[2];
378
nextPos[1] = m->pos[1];
379
380
stepResult = perform_hanging_step(m, nextPos);
381
382
vec3f_copy(m->marioObj->header.gfx.pos, m->pos);
383
vec3s_set(m->marioObj->header.gfx.angle, 0, m->faceAngle[1], 0);
384
return stepResult;
385
}
386
387
void update_hang_stationary(struct MarioState *m) {
388
m->forwardVel = 0.0f;
389
m->slideVelX = 0.0f;
390
m->slideVelZ = 0.0f;
391
392
m->pos[1] = m->ceilHeight - 160.0f;
393
vec3f_copy(m->vel, gVec3fZero);
394
vec3f_copy(m->marioObj->header.gfx.pos, m->pos);
395
}
396
397
s32 act_start_hanging(struct MarioState *m) {
398
#if ENABLE_RUMBLE
399
if (m->actionTimer++ == 0) {
400
queue_rumble_data(5, 80);
401
}
402
#else
403
m->actionTimer++;
404
#endif
405
406
if ((m->input & INPUT_NONZERO_ANALOG) && m->actionTimer >= 31) {
407
return set_mario_action(m, ACT_HANGING, 0);
408
}
409
410
if ((!(m->input & INPUT_A_DOWN) && !configImprovedHanging)
411
|| ((m->input & INPUT_A_PRESSED) && configImprovedHanging)) {
412
return set_mario_action(m, ACT_FREEFALL, 0);
413
}
414
415
if (m->input & INPUT_Z_PRESSED) {
416
return set_mario_action(m, ACT_GROUND_POUND, 0);
417
}
418
419
//! Crash if Mario's referenced ceiling is NULL (same for other hanging actions)
420
if (m->ceil->type != SURFACE_HANGABLE) {
421
return set_mario_action(m, ACT_FREEFALL, 0);
422
}
423
424
set_mario_animation(m, MARIO_ANIM_HANG_ON_CEILING);
425
play_sound_if_no_flag(m, SOUND_ACTION_HANGING_STEP, MARIO_ACTION_SOUND_PLAYED);
426
update_hang_stationary(m);
427
428
if (is_anim_at_end(m)) {
429
set_mario_action(m, ACT_HANGING, 0);
430
}
431
432
return FALSE;
433
}
434
435
s32 act_hanging(struct MarioState *m) {
436
if (m->input & INPUT_NONZERO_ANALOG) {
437
return set_mario_action(m, ACT_HANG_MOVING, m->actionArg);
438
}
439
440
if ((!(m->input & INPUT_A_DOWN) && !configImprovedHanging)
441
|| ((m->input & INPUT_A_PRESSED) && configImprovedHanging)) {
442
return set_mario_action(m, ACT_FREEFALL, 0);
443
}
444
445
if (m->input & INPUT_Z_PRESSED) {
446
return set_mario_action(m, ACT_GROUND_POUND, 0);
447
}
448
449
if (m->ceil->type != SURFACE_HANGABLE) {
450
return set_mario_action(m, ACT_FREEFALL, 0);
451
}
452
453
if (m->actionArg & 1) {
454
set_mario_animation(m, MARIO_ANIM_HANDSTAND_LEFT);
455
} else {
456
set_mario_animation(m, MARIO_ANIM_HANDSTAND_RIGHT);
457
}
458
459
update_hang_stationary(m);
460
461
return FALSE;
462
}
463
464
s32 act_hang_moving(struct MarioState *m) {
465
if ((!(m->input & INPUT_A_DOWN) && !configImprovedHanging)
466
|| ((m->input & INPUT_A_PRESSED) && configImprovedHanging)) {
467
return set_mario_action(m, ACT_FREEFALL, 0);
468
}
469
470
if (m->input & INPUT_Z_PRESSED) {
471
return set_mario_action(m, ACT_GROUND_POUND, 0);
472
}
473
474
if (m->ceil->type != SURFACE_HANGABLE) {
475
return set_mario_action(m, ACT_FREEFALL, 0);
476
}
477
478
if (m->actionArg & 1) {
479
set_mario_animation(m, MARIO_ANIM_MOVE_ON_WIRE_NET_RIGHT);
480
} else {
481
set_mario_animation(m, MARIO_ANIM_MOVE_ON_WIRE_NET_LEFT);
482
}
483
484
if (m->marioObj->header.gfx.animInfo.animFrame == 12) {
485
play_sound(SOUND_ACTION_HANGING_STEP, m->marioObj->header.gfx.cameraToObject);
486
#if ENABLE_RUMBLE
487
queue_rumble_data(1, 30);
488
#endif
489
}
490
491
if (is_anim_past_end(m)) {
492
m->actionArg ^= 1;
493
if (m->input & INPUT_UNKNOWN_5) {
494
return set_mario_action(m, ACT_HANGING, m->actionArg);
495
}
496
}
497
if (configImprovedHanging)
498
update_hang_moving(m);
499
else {
500
if (update_hang_moving(m) == HANG_LEFT_CEIL) {
501
set_mario_action(m, ACT_FREEFALL, 0);
502
}
503
}
504
505
return FALSE;
506
}
507
508
s32 let_go_of_ledge(struct MarioState *m) {
509
f32 floorHeight;
510
struct Surface *floor;
511
512
m->vel[1] = 0.0f;
513
m->forwardVel = -8.0f;
514
m->pos[0] -= 60.0f * sins(m->faceAngle[1]);
515
m->pos[2] -= 60.0f * coss(m->faceAngle[1]);
516
517
floorHeight = find_floor(m->pos[0], m->pos[1], m->pos[2], &floor);
518
if (floorHeight < m->pos[1] - 100.0f) {
519
m->pos[1] -= 100.0f;
520
} else {
521
m->pos[1] = floorHeight;
522
}
523
524
return set_mario_action(m, ACT_SOFT_BONK, 0);
525
}
526
527
void climb_up_ledge(struct MarioState *m) {
528
set_mario_animation(m, MARIO_ANIM_IDLE_HEAD_LEFT);
529
m->pos[0] += 14.0f * sins(m->faceAngle[1]);
530
m->pos[2] += 14.0f * coss(m->faceAngle[1]);
531
vec3f_copy(m->marioObj->header.gfx.pos, m->pos);
532
}
533
534
void update_ledge_climb_camera(struct MarioState *m) {
535
f32 sp4;
536
537
if (m->actionTimer < 14) {
538
sp4 = m->actionTimer;
539
} else {
540
sp4 = 14.0f;
541
}
542
m->statusForCamera->pos[0] = m->pos[0] + sp4 * sins(m->faceAngle[1]);
543
m->statusForCamera->pos[2] = m->pos[2] + sp4 * coss(m->faceAngle[1]);
544
m->statusForCamera->pos[1] = m->pos[1];
545
m->actionTimer++;
546
m->flags |= MARIO_UNKNOWN_25;
547
}
548
549
void update_ledge_climb(struct MarioState *m, s32 animation, u32 endAction) {
550
stop_and_set_height_to_floor(m);
551
552
set_mario_animation(m, animation);
553
if (is_anim_at_end(m)) {
554
set_mario_action(m, endAction, 0);
555
if (endAction == ACT_IDLE) {
556
climb_up_ledge(m);
557
}
558
}
559
}
560
561
s32 act_ledge_grab(struct MarioState *m) {
562
f32 heightAboveFloor;
563
s16 intendedDYaw = m->intendedYaw - m->faceAngle[1];
564
s32 hasSpaceForMario = (m->ceilHeight - m->floorHeight >= 160.0f);
565
566
if (m->actionTimer < 10) {
567
m->actionTimer++;
568
}
569
570
if (m->floor->normal.y < 0.9063078f) {
571
return let_go_of_ledge(m);
572
}
573
574
if (m->input & (INPUT_Z_PRESSED | INPUT_OFF_FLOOR)) {
575
return let_go_of_ledge(m);
576
}
577
578
if ((m->input & INPUT_A_PRESSED) && hasSpaceForMario) {
579
return set_mario_action(m, ACT_LEDGE_CLIMB_FAST, 0);
580
}
581
582
if (m->input & INPUT_STOMPED) {
583
if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_KNOCKBACK_DMG) {
584
m->hurtCounter += (m->flags & MARIO_CAP_ON_HEAD) ? 12 : 18;
585
}
586
return let_go_of_ledge(m);
587
}
588
#ifdef VERSION_EU
589
// On EU, you can't slow climb up ledges while holding A.
590
if (m->actionTimer == 10 && (m->input & INPUT_NONZERO_ANALOG) && !(m->input & INPUT_A_DOWN))
591
#else
592
if (m->actionTimer == 10 && (m->input & INPUT_NONZERO_ANALOG))
593
#endif
594
{
595
if (intendedDYaw >= -0x4000 && intendedDYaw <= 0x4000) {
596
if (hasSpaceForMario) {
597
return set_mario_action(m, ACT_LEDGE_CLIMB_SLOW_1, 0);
598
}
599
} else {
600
return let_go_of_ledge(m);
601
}
602
}
603
604
heightAboveFloor = m->pos[1] - find_floor_height_relative_polar(m, -0x8000, 30.0f);
605
if (hasSpaceForMario && heightAboveFloor < 100.0f) {
606
return set_mario_action(m, ACT_LEDGE_CLIMB_FAST, 0);
607
}
608
609
if (m->actionArg == 0) {
610
play_sound_if_no_flag(m, SOUND_MARIO_WHOA, MARIO_MARIO_SOUND_PLAYED);
611
}
612
613
stop_and_set_height_to_floor(m);
614
set_mario_animation(m, MARIO_ANIM_IDLE_ON_LEDGE);
615
616
return FALSE;
617
}
618
619
s32 act_ledge_climb_slow(struct MarioState *m) {
620
if (m->input & INPUT_OFF_FLOOR) {
621
return let_go_of_ledge(m);
622
}
623
624
if (m->actionTimer >= 28
625
&& (m->input
626
& (INPUT_NONZERO_ANALOG | INPUT_A_PRESSED | INPUT_OFF_FLOOR | INPUT_ABOVE_SLIDE))) {
627
climb_up_ledge(m);
628
return check_common_action_exits(m);
629
}
630
631
if (m->actionTimer == 10) {
632
play_sound_if_no_flag(m, SOUND_MARIO_EEUH, MARIO_MARIO_SOUND_PLAYED);
633
}
634
635
update_ledge_climb(m, MARIO_ANIM_SLOW_LEDGE_GRAB, ACT_IDLE);
636
637
update_ledge_climb_camera(m);
638
if (m->marioObj->header.gfx.animInfo.animFrame == 17) {
639
m->action = ACT_LEDGE_CLIMB_SLOW_2;
640
}
641
642
return FALSE;
643
}
644
645
s32 act_ledge_climb_down(struct MarioState *m) {
646
if (m->input & INPUT_OFF_FLOOR) {
647
return let_go_of_ledge(m);
648
}
649
650
play_sound_if_no_flag(m, SOUND_MARIO_WHOA, MARIO_MARIO_SOUND_PLAYED);
651
652
update_ledge_climb(m, MARIO_ANIM_CLIMB_DOWN_LEDGE, ACT_LEDGE_GRAB);
653
m->actionArg = 1;
654
655
return FALSE;
656
}
657
658
s32 act_ledge_climb_fast(struct MarioState *m) {
659
if (m->input & INPUT_OFF_FLOOR) {
660
return let_go_of_ledge(m);
661
}
662
663
play_sound_if_no_flag(m, SOUND_MARIO_UH2, MARIO_MARIO_SOUND_PLAYED);
664
665
update_ledge_climb(m, MARIO_ANIM_FAST_LEDGE_GRAB, ACT_IDLE);
666
667
if (m->marioObj->header.gfx.animInfo.animFrame == 8) {
668
play_mario_landing_sound(m, SOUND_ACTION_TERRAIN_LANDING);
669
}
670
update_ledge_climb_camera(m);
671
672
return FALSE;
673
}
674
675
s32 act_grabbed(struct MarioState *m) {
676
if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_UNK2) {
677
s32 thrown = (m->marioObj->oInteractStatus & INT_STATUS_MARIO_UNK6) == 0;
678
679
m->faceAngle[1] = m->usedObj->oMoveAngleYaw;
680
vec3f_copy(m->pos, m->marioObj->header.gfx.pos);
681
#if ENABLE_RUMBLE
682
queue_rumble_data(5, 60);
683
#endif
684
685
return set_mario_action(m, (m->forwardVel >= 0.0f) ? ACT_THROWN_FORWARD : ACT_THROWN_BACKWARD,
686
thrown);
687
}
688
689
set_mario_animation(m, MARIO_ANIM_BEING_GRABBED);
690
return FALSE;
691
}
692
693
s32 act_in_cannon(struct MarioState *m) {
694
struct Object *marioObj = m->marioObj;
695
s16 startFacePitch = m->faceAngle[0];
696
s16 startFaceYaw = m->faceAngle[1];
697
698
switch (m->actionState) {
699
case 0:
700
m->marioObj->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE;
701
m->usedObj->oInteractStatus = INT_STATUS_INTERACTED;
702
703
m->statusForCamera->cameraEvent = CAM_EVENT_CANNON;
704
m->statusForCamera->usedObj = m->usedObj;
705
706
vec3f_set(m->vel, 0.0f, 0.0f, 0.0f);
707
708
m->pos[0] = m->usedObj->oPosX;
709
m->pos[1] = m->usedObj->oPosY + 350.0f;
710
m->pos[2] = m->usedObj->oPosZ;
711
712
m->forwardVel = 0.0f;
713
714
m->actionState = 1;
715
break;
716
717
case 1:
718
if (m->usedObj->oAction == 1) {
719
m->faceAngle[0] = m->usedObj->oMoveAnglePitch;
720
m->faceAngle[1] = m->usedObj->oMoveAngleYaw;
721
722
marioObj->oMarioCannonObjectYaw = m->usedObj->oMoveAngleYaw;
723
marioObj->oMarioCannonInputYaw = 0;
724
725
m->actionState = 2;
726
}
727
break;
728
729
case 2:
730
if (configImprovedControls) {
731
m->faceAngle[0] -= (s16)((m->controller->stickY + m->controller->stick2Y) * 6.0f);
732
marioObj->oMarioCannonInputYaw -= (s16)((m->controller->stickX + m->controller->stick2X) * 6.0f);
733
}
734
else {
735
m->faceAngle[0] -= (s16)((m->controller->stickY + m->controller->stick2Y) * 10.0f);
736
marioObj->oMarioCannonInputYaw -= (s16)((m->controller->stickX + m->controller->stick2X) * 10.0f);
737
}
738
739
if (m->faceAngle[0] > 0x38E3) {
740
m->faceAngle[0] = 0x38E3;
741
}
742
if (m->faceAngle[0] < 0) {
743
m->faceAngle[0] = 0;
744
}
745
746
if (configFlexibleCannons) {
747
if (marioObj->oMarioCannonInputYaw > 0x10000) {
748
marioObj->oMarioCannonInputYaw = 0x10000;
749
}
750
if (marioObj->oMarioCannonInputYaw < -0x10000) {
751
marioObj->oMarioCannonInputYaw = -0x10000;
752
}
753
}
754
else {
755
if (marioObj->oMarioCannonInputYaw > 0x4000) {
756
marioObj->oMarioCannonInputYaw = 0x4000;
757
}
758
if (marioObj->oMarioCannonInputYaw < -0x4000) {
759
marioObj->oMarioCannonInputYaw = -0x4000;
760
}
761
}
762
763
m->faceAngle[1] = marioObj->oMarioCannonObjectYaw + marioObj->oMarioCannonInputYaw;
764
if (m->input & INPUT_A_PRESSED) {
765
m->forwardVel = 100.0f * coss(m->faceAngle[0]);
766
767
m->vel[1] = 100.0f * sins(m->faceAngle[0]);
768
769
m->pos[0] += 120.0f * coss(m->faceAngle[0]) * sins(m->faceAngle[1]);
770
m->pos[1] += 120.0f * sins(m->faceAngle[0]);
771
m->pos[2] += 120.0f * coss(m->faceAngle[0]) * coss(m->faceAngle[1]);
772
773
play_sound(SOUND_ACTION_FLYING_FAST, m->marioObj->header.gfx.cameraToObject);
774
play_sound(SOUND_OBJ_POUNDING_CANNON, m->marioObj->header.gfx.cameraToObject);
775
776
m->marioObj->header.gfx.node.flags |= GRAPH_RENDER_ACTIVE;
777
778
set_mario_action(m, ACT_SHOT_FROM_CANNON, 0);
779
#if ENABLE_RUMBLE
780
queue_rumble_data(60, 70);
781
#endif
782
m->usedObj->oAction = 2;
783
return FALSE;
784
} else if (m->faceAngle[0] != startFacePitch || m->faceAngle[1] != startFaceYaw) {
785
play_sound(SOUND_MOVING_AIM_CANNON, m->marioObj->header.gfx.cameraToObject);
786
#if ENABLE_RUMBLE
787
reset_rumble_timers_2(0);
788
#endif
789
}
790
}
791
792
vec3f_copy(m->marioObj->header.gfx.pos, m->pos);
793
vec3s_set(m->marioObj->header.gfx.angle, 0, m->faceAngle[1], 0);
794
set_mario_animation(m, MARIO_ANIM_DIVE);
795
796
return FALSE;
797
}
798
799
s32 act_tornado_twirling(struct MarioState *m) {
800
struct Surface *floor;
801
Vec3f nextPos;
802
f32 sinAngleVel;
803
f32 cosAngleVel;
804
f32 floorHeight;
805
struct Object *marioObj = m->marioObj;
806
struct Object *usedObj = m->usedObj;
807
s16 prevTwirlYaw = m->twirlYaw;
808
809
f32 dx = (m->pos[0] - usedObj->oPosX) * 0.95f;
810
f32 dz = (m->pos[2] - usedObj->oPosZ) * 0.95f;
811
812
if (m->vel[1] < 60.0f) {
813
m->vel[1] += 1.0f;
814
}
815
816
if ((marioObj->oMarioTornadoPosY += m->vel[1]) < 0.0f) {
817
marioObj->oMarioTornadoPosY = 0.0f;
818
}
819
if (marioObj->oMarioTornadoPosY > usedObj->hitboxHeight) {
820
if (m->vel[1] < 20.0f) {
821
m->vel[1] = 20.0f;
822
}
823
return set_mario_action(m, ACT_TWIRLING, 1);
824
}
825
826
if (m->angleVel[1] < 0x3000) {
827
m->angleVel[1] += 0x100;
828
}
829
830
if (marioObj->oMarioTornadoYawVel < 0x1000) {
831
marioObj->oMarioTornadoYawVel += 0x100;
832
}
833
834
m->twirlYaw += m->angleVel[1];
835
836
sinAngleVel = sins(marioObj->oMarioTornadoYawVel);
837
cosAngleVel = coss(marioObj->oMarioTornadoYawVel);
838
839
nextPos[0] = usedObj->oPosX + dx * cosAngleVel + dz * sinAngleVel;
840
nextPos[2] = usedObj->oPosZ - dx * sinAngleVel + dz * cosAngleVel;
841
nextPos[1] = usedObj->oPosY + marioObj->oMarioTornadoPosY;
842
843
f32_find_wall_collision(&nextPos[0], &nextPos[1], &nextPos[2], 60.0f, 50.0f);
844
845
floorHeight = find_floor(nextPos[0], nextPos[1], nextPos[2], &floor);
846
if (floor != NULL) {
847
m->floor = floor;
848
m->floorHeight = floorHeight;
849
vec3f_copy(m->pos, nextPos);
850
} else {
851
if (nextPos[1] >= m->floorHeight) {
852
m->pos[1] = nextPos[1];
853
} else {
854
m->pos[1] = m->floorHeight;
855
}
856
}
857
858
m->actionTimer++;
859
860
set_mario_animation(m, (m->actionArg == 0) ? MARIO_ANIM_START_TWIRL : MARIO_ANIM_TWIRL);
861
862
if (is_anim_past_end(m)) {
863
m->actionArg = 1;
864
}
865
866
// Play sound on angle overflow
867
if (prevTwirlYaw > m->twirlYaw) {
868
play_sound(SOUND_ACTION_TWIRL, m->marioObj->header.gfx.cameraToObject);
869
}
870
871
vec3f_copy(m->marioObj->header.gfx.pos, m->pos);
872
vec3s_set(m->marioObj->header.gfx.angle, 0, m->faceAngle[1] + m->twirlYaw, 0);
873
#if ENABLE_RUMBLE
874
reset_rumble_timers();
875
#endif
876
877
return FALSE;
878
}
879
880
s32 check_common_automatic_cancels(struct MarioState *m) {
881
if (m->pos[1] < m->waterLevel - 100) {
882
return set_water_plunge_action(m);
883
}
884
885
return FALSE;
886
}
887
888
s32 mario_execute_automatic_action(struct MarioState *m) {
889
s32 cancel;
890
891
if (check_common_automatic_cancels(m)) {
892
return TRUE;
893
}
894
895
m->quicksandDepth = 0.0f;
896
897
/* clang-format off */
898
switch (m->action) {
899
case ACT_HOLDING_POLE: cancel = act_holding_pole(m); break;
900
case ACT_GRAB_POLE_SLOW: cancel = act_grab_pole_slow(m); break;
901
case ACT_GRAB_POLE_FAST: cancel = act_grab_pole_fast(m); break;
902
case ACT_CLIMBING_POLE: cancel = act_climbing_pole(m); break;
903
case ACT_TOP_OF_POLE_TRANSITION: cancel = act_top_of_pole_transition(m); break;
904
case ACT_TOP_OF_POLE: cancel = act_top_of_pole(m); break;
905
case ACT_START_HANGING: cancel = act_start_hanging(m); break;
906
case ACT_HANGING: cancel = act_hanging(m); break;
907
case ACT_HANG_MOVING: cancel = act_hang_moving(m); break;
908
case ACT_LEDGE_GRAB: cancel = act_ledge_grab(m); break;
909
case ACT_LEDGE_CLIMB_SLOW_1: cancel = act_ledge_climb_slow(m); break;
910
case ACT_LEDGE_CLIMB_SLOW_2: cancel = act_ledge_climb_slow(m); break;
911
case ACT_LEDGE_CLIMB_DOWN: cancel = act_ledge_climb_down(m); break;
912
case ACT_LEDGE_CLIMB_FAST: cancel = act_ledge_climb_fast(m); break;
913
case ACT_GRABBED: cancel = act_grabbed(m); break;
914
case ACT_IN_CANNON: cancel = act_in_cannon(m); break;
915
case ACT_TORNADO_TWIRLING: cancel = act_tornado_twirling(m); break;
916
}
917
/* clang-format on */
918
919
return cancel;
920
}
921
922