mario_step.c (20919B)
1 #include <ultra64.h> 2 3 #include "sm64.h" 4 #include "engine/math_util.h" 5 #include "engine/surface_collision.h" 6 #include "mario.h" 7 #include "audio/external.h" 8 #include "game_init.h" 9 #include "interaction.h" 10 #include "mario_step.h" 11 12 static s16 sMovingSandSpeeds[] = { 12, 8, 4, 0 }; 13 14 struct Surface gWaterSurfacePseudoFloor = { 15 SURFACE_VERY_SLIPPERY, 0, 0, 0, 0, 0, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, 16 { 0.0f, 1.0f, 0.0f }, 0.0f, NULL, 17 }; 18 19 /** 20 * Always returns zero. This may have been intended 21 * to be used for the beta trampoline. Its return value 22 * is used by set_mario_y_vel_based_on_fspeed as a constant 23 * addition to Mario's Y velocity. Given the closeness of 24 * this function to stub_mario_step_2, it is probable that this 25 * was intended to check whether a trampoline had made itself 26 * known through stub_mario_step_2 and whether Mario was on it, 27 * and if so return a higher value than 0. 28 */ 29 f32 get_additive_y_vel_for_jumps(void) { 30 return 0.0f; 31 } 32 33 /** 34 * Does nothing, but takes in a MarioState. This is only ever 35 * called by update_mario_inputs, which is called as part of Mario's 36 * update routine. Due to its proximity to stub_mario_step_2, an 37 * incomplete trampoline function, and get_additive_y_vel_for_jumps, 38 * a potentially trampoline-related function, it is plausible that 39 * this could be used for checking if Mario was on the trampoline. 40 * It could, for example, make him bounce. 41 */ 42 void stub_mario_step_1(UNUSED struct MarioState *x) { 43 } 44 45 /** 46 * Does nothing. This is only called by the beta trampoline. 47 * Due to its proximity to get_additive_y_vel_for_jumps, another 48 * currently-pointless function, it is probable that this was used 49 * by the trampoline to make itself known to get_additive_y_vel_for_jumps, 50 * or to set a variable with its intended additive Y vel. 51 */ 52 void stub_mario_step_2(void) { 53 } 54 55 void transfer_bully_speed(struct BullyCollisionData *obj1, struct BullyCollisionData *obj2) { 56 f32 rx = obj2->posX - obj1->posX; 57 f32 rz = obj2->posZ - obj1->posZ; 58 59 //! Bully NaN crash 60 f32 projectedV1 = (rx * obj1->velX + rz * obj1->velZ) / (rx * rx + rz * rz); 61 f32 projectedV2 = (-rx * obj2->velX - rz * obj2->velZ) / (rx * rx + rz * rz); 62 63 // Kill speed along r. Convert one object's speed along r and transfer it to 64 // the other object. 65 obj2->velX += obj2->conversionRatio * projectedV1 * rx - projectedV2 * -rx; 66 obj2->velZ += obj2->conversionRatio * projectedV1 * rz - projectedV2 * -rz; 67 68 obj1->velX += -projectedV1 * rx + obj1->conversionRatio * projectedV2 * -rx; 69 obj1->velZ += -projectedV1 * rz + obj1->conversionRatio * projectedV2 * -rz; 70 71 //! Bully battery 72 } 73 74 BAD_RETURN(s32) init_bully_collision_data(struct BullyCollisionData *data, f32 posX, f32 posZ, 75 f32 forwardVel, s16 yaw, f32 conversionRatio, f32 radius) { 76 if (forwardVel < 0.0f) { 77 forwardVel *= -1.0f; 78 yaw += 0x8000; 79 } 80 81 data->radius = radius; 82 data->conversionRatio = conversionRatio; 83 data->posX = posX; 84 data->posZ = posZ; 85 data->velX = forwardVel * sins(yaw); 86 data->velZ = forwardVel * coss(yaw); 87 } 88 89 void mario_bonk_reflection(struct MarioState *m, u32 negateSpeed) { 90 if (m->wall != NULL) { 91 s16 wallAngle = atan2s(m->wall->normal.z, m->wall->normal.x); 92 m->faceAngle[1] = wallAngle - (s16)(m->faceAngle[1] - wallAngle); 93 94 play_sound((m->flags & MARIO_METAL_CAP) ? SOUND_ACTION_METAL_BONK : SOUND_ACTION_BONK, 95 m->marioObj->header.gfx.cameraToObject); 96 } else { 97 play_sound(SOUND_ACTION_HIT, m->marioObj->header.gfx.cameraToObject); 98 } 99 100 if (negateSpeed) { 101 mario_set_forward_vel(m, -m->forwardVel); 102 } else { 103 m->faceAngle[1] += 0x8000; 104 } 105 } 106 107 u32 mario_update_quicksand(struct MarioState *m, f32 sinkingSpeed) { 108 if (m->action & ACT_FLAG_RIDING_SHELL) { 109 m->quicksandDepth = 0.0f; 110 } else { 111 if (m->quicksandDepth < 1.1f) { 112 m->quicksandDepth = 1.1f; 113 } 114 115 switch (m->floor->type) { 116 case SURFACE_SHALLOW_QUICKSAND: 117 if ((m->quicksandDepth += sinkingSpeed) >= 10.0f) { 118 m->quicksandDepth = 10.0f; 119 } 120 break; 121 122 case SURFACE_SHALLOW_MOVING_QUICKSAND: 123 if ((m->quicksandDepth += sinkingSpeed) >= 25.0f) { 124 m->quicksandDepth = 25.0f; 125 } 126 break; 127 128 case SURFACE_QUICKSAND: 129 case SURFACE_MOVING_QUICKSAND: 130 if ((m->quicksandDepth += sinkingSpeed) >= 60.0f) { 131 m->quicksandDepth = 60.0f; 132 } 133 break; 134 135 case SURFACE_DEEP_QUICKSAND: 136 case SURFACE_DEEP_MOVING_QUICKSAND: 137 if ((m->quicksandDepth += sinkingSpeed) >= 160.0f) { 138 update_mario_sound_and_camera(m); 139 return drop_and_set_mario_action(m, ACT_QUICKSAND_DEATH, 0); 140 } 141 break; 142 143 case SURFACE_INSTANT_QUICKSAND: 144 case SURFACE_INSTANT_MOVING_QUICKSAND: 145 update_mario_sound_and_camera(m); 146 return drop_and_set_mario_action(m, ACT_QUICKSAND_DEATH, 0); 147 break; 148 149 default: 150 m->quicksandDepth = 0.0f; 151 break; 152 } 153 } 154 155 return FALSE; 156 } 157 158 u32 mario_push_off_steep_floor(struct MarioState *m, u32 action, u32 actionArg) { 159 s16 floorDYaw = m->floorAngle - m->faceAngle[1]; 160 161 if (floorDYaw > -0x4000 && floorDYaw < 0x4000) { 162 m->forwardVel = 16.0f; 163 m->faceAngle[1] = m->floorAngle; 164 } else { 165 m->forwardVel = -16.0f; 166 m->faceAngle[1] = m->floorAngle + 0x8000; 167 } 168 169 return set_mario_action(m, action, actionArg); 170 } 171 172 u32 mario_update_moving_sand(struct MarioState *m) { 173 struct Surface *floor = m->floor; 174 s32 floorType = floor->type; 175 176 if (floorType == SURFACE_DEEP_MOVING_QUICKSAND || floorType == SURFACE_SHALLOW_MOVING_QUICKSAND 177 || floorType == SURFACE_MOVING_QUICKSAND || floorType == SURFACE_INSTANT_MOVING_QUICKSAND) { 178 s16 pushAngle = floor->force << 8; 179 f32 pushSpeed = sMovingSandSpeeds[floor->force >> 8]; 180 181 m->vel[0] += pushSpeed * sins(pushAngle); 182 m->vel[2] += pushSpeed * coss(pushAngle); 183 184 return TRUE; 185 } 186 187 return FALSE; 188 } 189 190 u32 mario_update_windy_ground(struct MarioState *m) { 191 struct Surface *floor = m->floor; 192 193 if (floor->type == SURFACE_HORIZONTAL_WIND) { 194 f32 pushSpeed; 195 s16 pushAngle = floor->force << 8; 196 197 if (m->action & ACT_FLAG_MOVING) { 198 s16 pushDYaw = m->faceAngle[1] - pushAngle; 199 200 pushSpeed = m->forwardVel > 0.0f ? -m->forwardVel * 0.5f : -8.0f; 201 202 if (pushDYaw > -0x4000 && pushDYaw < 0x4000) { 203 pushSpeed *= -1.0f; 204 } 205 206 pushSpeed *= coss(pushDYaw); 207 } else { 208 pushSpeed = 3.2f + (gGlobalTimer % 4); 209 } 210 211 m->vel[0] += pushSpeed * sins(pushAngle); 212 m->vel[2] += pushSpeed * coss(pushAngle); 213 214 #ifdef VERSION_JP 215 play_sound(SOUND_ENV_WIND2, m->marioObj->header.gfx.cameraToObject); 216 #endif 217 return TRUE; 218 } 219 220 return FALSE; 221 } 222 223 void stop_and_set_height_to_floor(struct MarioState *m) { 224 struct Object *marioObj = m->marioObj; 225 226 mario_set_forward_vel(m, 0.0f); 227 m->vel[1] = 0.0f; 228 229 //! This is responsible for some downwarps. 230 m->pos[1] = m->floorHeight; 231 232 vec3f_copy(marioObj->header.gfx.pos, m->pos); 233 vec3s_set(marioObj->header.gfx.angle, 0, m->faceAngle[1], 0); 234 } 235 236 s32 stationary_ground_step(struct MarioState *m) { 237 u32 takeStep; 238 struct Object *marioObj = m->marioObj; 239 u32 stepResult = GROUND_STEP_NONE; 240 241 mario_set_forward_vel(m, 0.0f); 242 243 takeStep = mario_update_moving_sand(m); 244 takeStep |= mario_update_windy_ground(m); 245 if (takeStep) { 246 stepResult = perform_ground_step(m); 247 } else { 248 //! This is responsible for several stationary downwarps. 249 m->pos[1] = m->floorHeight; 250 251 vec3f_copy(marioObj->header.gfx.pos, m->pos); 252 vec3s_set(marioObj->header.gfx.angle, 0, m->faceAngle[1], 0); 253 } 254 255 return stepResult; 256 } 257 258 static s32 perform_ground_quarter_step(struct MarioState *m, Vec3f nextPos) { 259 UNUSED struct Surface *lowerWall; 260 struct Surface *upperWall; 261 struct Surface *ceil; 262 struct Surface *floor; 263 f32 ceilHeight; 264 f32 floorHeight; 265 f32 waterLevel; 266 267 lowerWall = resolve_and_return_wall_collisions(nextPos, 30.0f, 24.0f); 268 upperWall = resolve_and_return_wall_collisions(nextPos, 60.0f, 50.0f); 269 270 floorHeight = find_floor(nextPos[0], nextPos[1], nextPos[2], &floor); 271 ceilHeight = vec3f_find_ceil(nextPos, floorHeight, &ceil); 272 273 waterLevel = find_water_level(nextPos[0], nextPos[2]); 274 275 m->wall = upperWall; 276 277 if (floor == NULL) { 278 return GROUND_STEP_HIT_WALL_STOP_QSTEPS; 279 } 280 281 if ((m->action & ACT_FLAG_RIDING_SHELL) && floorHeight < waterLevel) { 282 floorHeight = waterLevel; 283 floor = &gWaterSurfacePseudoFloor; 284 floor->originOffset = floorHeight; //! Wrong origin offset (no effect) 285 } 286 287 if (nextPos[1] > floorHeight + 100.0f) { 288 if (nextPos[1] + 160.0f >= ceilHeight) { 289 return GROUND_STEP_HIT_WALL_STOP_QSTEPS; 290 } 291 292 vec3f_copy(m->pos, nextPos); 293 m->floor = floor; 294 m->floorHeight = floorHeight; 295 return GROUND_STEP_LEFT_GROUND; 296 } 297 298 if (floorHeight + 160.0f >= ceilHeight) { 299 return GROUND_STEP_HIT_WALL_STOP_QSTEPS; 300 } 301 302 vec3f_set(m->pos, nextPos[0], floorHeight, nextPos[2]); 303 m->floor = floor; 304 m->floorHeight = floorHeight; 305 306 if (upperWall != NULL) { 307 s16 wallDYaw = atan2s(upperWall->normal.z, upperWall->normal.x) - m->faceAngle[1]; 308 309 if (wallDYaw >= 0x2AAA && wallDYaw <= 0x5555) { 310 return GROUND_STEP_NONE; 311 } 312 if (wallDYaw <= -0x2AAA && wallDYaw >= -0x5555) { 313 return GROUND_STEP_NONE; 314 } 315 316 return GROUND_STEP_HIT_WALL_CONTINUE_QSTEPS; 317 } 318 319 return GROUND_STEP_NONE; 320 } 321 322 s32 perform_ground_step(struct MarioState *m) { 323 s32 i; 324 u32 stepResult; 325 Vec3f intendedPos; 326 327 for (i = 0; i < 4; i++) { 328 intendedPos[0] = m->pos[0] + m->floor->normal.y * (m->vel[0] / 4.0f); 329 intendedPos[2] = m->pos[2] + m->floor->normal.y * (m->vel[2] / 4.0f); 330 intendedPos[1] = m->pos[1]; 331 332 stepResult = perform_ground_quarter_step(m, intendedPos); 333 if (stepResult == GROUND_STEP_LEFT_GROUND || stepResult == GROUND_STEP_HIT_WALL_STOP_QSTEPS) { 334 break; 335 } 336 } 337 338 m->terrainSoundAddend = mario_get_terrain_sound_addend(m); 339 vec3f_copy(m->marioObj->header.gfx.pos, m->pos); 340 vec3s_set(m->marioObj->header.gfx.angle, 0, m->faceAngle[1], 0); 341 342 if (stepResult == GROUND_STEP_HIT_WALL_CONTINUE_QSTEPS) { 343 stepResult = GROUND_STEP_HIT_WALL; 344 } 345 return stepResult; 346 } 347 348 u32 check_ledge_grab(struct MarioState *m, struct Surface *wall, Vec3f intendedPos, Vec3f nextPos) { 349 struct Surface *ledgeFloor; 350 Vec3f ledgePos; 351 f32 displacementX; 352 f32 displacementZ; 353 354 if (m->vel[1] > 0) { 355 return FALSE; 356 } 357 358 displacementX = nextPos[0] - intendedPos[0]; 359 displacementZ = nextPos[2] - intendedPos[2]; 360 361 // Only ledge grab if the wall displaced Mario in the opposite direction of 362 // his velocity. 363 if (displacementX * m->vel[0] + displacementZ * m->vel[2] > 0.0f) { 364 return FALSE; 365 } 366 367 //! Since the search for floors starts at y + 160, we will sometimes grab 368 // a higher ledge than expected (glitchy ledge grab) 369 ledgePos[0] = nextPos[0] - wall->normal.x * 60.0f; 370 ledgePos[2] = nextPos[2] - wall->normal.z * 60.0f; 371 ledgePos[1] = find_floor(ledgePos[0], nextPos[1] + 160.0f, ledgePos[2], &ledgeFloor); 372 373 if (ledgePos[1] - nextPos[1] <= 100.0f) { 374 return FALSE; 375 } 376 377 vec3f_copy(m->pos, ledgePos); 378 m->floor = ledgeFloor; 379 m->floorHeight = ledgePos[1]; 380 381 m->floorAngle = atan2s(ledgeFloor->normal.z, ledgeFloor->normal.x); 382 383 m->faceAngle[0] = 0; 384 m->faceAngle[1] = atan2s(wall->normal.z, wall->normal.x) + 0x8000; 385 return TRUE; 386 } 387 388 s32 perform_air_quarter_step(struct MarioState *m, Vec3f intendedPos, u32 stepArg) { 389 s16 wallDYaw; 390 Vec3f nextPos; 391 struct Surface *upperWall; 392 struct Surface *lowerWall; 393 struct Surface *ceil; 394 struct Surface *floor; 395 f32 ceilHeight; 396 f32 floorHeight; 397 f32 waterLevel; 398 399 vec3f_copy(nextPos, intendedPos); 400 401 upperWall = resolve_and_return_wall_collisions(nextPos, 150.0f, 50.0f); 402 lowerWall = resolve_and_return_wall_collisions(nextPos, 30.0f, 50.0f); 403 404 floorHeight = find_floor(nextPos[0], nextPos[1], nextPos[2], &floor); 405 ceilHeight = vec3f_find_ceil(nextPos, floorHeight, &ceil); 406 407 waterLevel = find_water_level(nextPos[0], nextPos[2]); 408 409 m->wall = NULL; 410 411 //! The water pseudo floor is not referenced when your intended qstep is 412 // out of bounds, so it won't detect you as landing. 413 414 if (floor == NULL) { 415 if (nextPos[1] <= m->floorHeight) { 416 m->pos[1] = m->floorHeight; 417 return AIR_STEP_LANDED; 418 } 419 420 m->pos[1] = nextPos[1]; 421 return AIR_STEP_HIT_WALL; 422 } 423 424 if ((m->action & ACT_FLAG_RIDING_SHELL) && floorHeight < waterLevel) { 425 floorHeight = waterLevel; 426 floor = &gWaterSurfacePseudoFloor; 427 floor->originOffset = floorHeight; //! Incorrect origin offset (no effect) 428 } 429 430 //! This check uses f32, but findFloor uses short (overflow jumps) 431 if (nextPos[1] <= floorHeight) { 432 if (ceilHeight - floorHeight > 160.0f) { 433 m->pos[0] = nextPos[0]; 434 m->pos[2] = nextPos[2]; 435 m->floor = floor; 436 m->floorHeight = floorHeight; 437 } 438 439 //! When ceilHeight - floorHeight <= 160, the step result says that 440 // Mario landed, but his movement is cancelled and his referenced floor 441 // isn't updated (pedro spots) 442 m->pos[1] = floorHeight; 443 return AIR_STEP_LANDED; 444 } 445 446 if (nextPos[1] + 160.0f > ceilHeight) { 447 if (m->vel[1] >= 0.0f) { 448 m->vel[1] = 0.0f; 449 450 //! Uses referenced ceiling instead of ceil (ceiling hang upwarp) 451 if ((stepArg & AIR_STEP_CHECK_HANG) && m->ceil != NULL 452 && m->ceil->type == SURFACE_HANGABLE) { 453 return AIR_STEP_GRABBED_CEILING; 454 } 455 456 return AIR_STEP_NONE; 457 } 458 459 //! Potential subframe downwarp->upwarp? 460 if (nextPos[1] <= m->floorHeight) { 461 m->pos[1] = m->floorHeight; 462 return AIR_STEP_LANDED; 463 } 464 465 m->pos[1] = nextPos[1]; 466 return AIR_STEP_HIT_WALL; 467 } 468 469 //! When the wall is not completely vertical or there is a slight wall 470 // misalignment, you can activate these conditions in unexpected situations 471 if ((stepArg & AIR_STEP_CHECK_LEDGE_GRAB) && upperWall == NULL && lowerWall != NULL) { 472 if (check_ledge_grab(m, lowerWall, intendedPos, nextPos)) { 473 return AIR_STEP_GRABBED_LEDGE; 474 } 475 476 vec3f_copy(m->pos, nextPos); 477 m->floor = floor; 478 m->floorHeight = floorHeight; 479 return AIR_STEP_NONE; 480 } 481 482 vec3f_copy(m->pos, nextPos); 483 m->floor = floor; 484 m->floorHeight = floorHeight; 485 486 if (upperWall != NULL || lowerWall != NULL) { 487 m->wall = upperWall != NULL ? upperWall : lowerWall; 488 wallDYaw = atan2s(m->wall->normal.z, m->wall->normal.x) - m->faceAngle[1]; 489 490 if (m->wall->type == SURFACE_BURNING) { 491 return AIR_STEP_HIT_LAVA_WALL; 492 } 493 494 if (wallDYaw < -0x6000 || wallDYaw > 0x6000) { 495 m->flags |= MARIO_UNKNOWN_30; 496 return AIR_STEP_HIT_WALL; 497 } 498 } 499 500 return AIR_STEP_NONE; 501 } 502 503 void apply_twirl_gravity(struct MarioState *m) { 504 f32 terminalVelocity; 505 f32 heaviness = 1.0f; 506 507 if (m->angleVel[1] > 1024) { 508 heaviness = 1024.0f / m->angleVel[1]; 509 } 510 511 terminalVelocity = -75.0f * heaviness; 512 513 m->vel[1] -= 4.0f * heaviness; 514 if (m->vel[1] < terminalVelocity) { 515 m->vel[1] = terminalVelocity; 516 } 517 } 518 519 u32 should_strengthen_gravity_for_jump_ascent(struct MarioState *m) { 520 if (!(m->flags & MARIO_UNKNOWN_08)) { 521 return FALSE; 522 } 523 524 if (m->action & (ACT_FLAG_INTANGIBLE | ACT_FLAG_INVULNERABLE)) { 525 return FALSE; 526 } 527 528 if (!(m->input & INPUT_A_DOWN) && m->vel[1] > 20.0f) { 529 return (m->action & ACT_FLAG_CONTROL_JUMP_HEIGHT) != 0; 530 } 531 532 return FALSE; 533 } 534 535 void apply_gravity(struct MarioState *m) { 536 if (m->action == ACT_TWIRLING && m->vel[1] < 0.0f) { 537 apply_twirl_gravity(m); 538 } else if (m->action == ACT_SHOT_FROM_CANNON) { 539 m->vel[1] -= 1.0f; 540 if (m->vel[1] < -75.0f) { 541 m->vel[1] = -75.0f; 542 } 543 } else if (m->action == ACT_LONG_JUMP || m->action == ACT_SLIDE_KICK 544 || m->action == ACT_BBH_ENTER_SPIN) { 545 m->vel[1] -= 2.0f; 546 if (m->vel[1] < -75.0f) { 547 m->vel[1] = -75.0f; 548 } 549 } else if (m->action == ACT_LAVA_BOOST || m->action == ACT_FALL_AFTER_STAR_GRAB) { 550 m->vel[1] -= 3.2f; 551 if (m->vel[1] < -65.0f) { 552 m->vel[1] = -65.0f; 553 } 554 } else if (m->action == ACT_GETTING_BLOWN) { 555 m->vel[1] -= m->gettingBlownGravity; 556 if (m->vel[1] < -75.0f) { 557 m->vel[1] = -75.0f; 558 } 559 } else if (should_strengthen_gravity_for_jump_ascent(m)) { 560 m->vel[1] /= 4.0f; 561 } else if (m->action & ACT_FLAG_METAL_WATER) { 562 m->vel[1] -= 1.6f; 563 if (m->vel[1] < -16.0f) { 564 m->vel[1] = -16.0f; 565 } 566 } else if ((m->flags & MARIO_WING_CAP) && m->vel[1] < 0.0f && (m->input & INPUT_A_DOWN)) { 567 m->marioBodyState->wingFlutter = TRUE; 568 569 m->vel[1] -= 2.0f; 570 if (m->vel[1] < -37.5f) { 571 if ((m->vel[1] += 4.0f) > -37.5f) { 572 m->vel[1] = -37.5f; 573 } 574 } 575 } else { 576 m->vel[1] -= 4.0f; 577 if (m->vel[1] < -75.0f) { 578 m->vel[1] = -75.0f; 579 } 580 } 581 } 582 583 void apply_vertical_wind(struct MarioState *m) { 584 f32 maxVelY; 585 f32 offsetY; 586 587 if (m->action != ACT_GROUND_POUND) { 588 offsetY = m->pos[1] - -1500.0f; 589 590 if (m->floor->type == SURFACE_VERTICAL_WIND && -3000.0f < offsetY && offsetY < 2000.0f) { 591 if (offsetY >= 0.0f) { 592 maxVelY = 10000.0f / (offsetY + 200.0f); 593 } else { 594 maxVelY = 50.0f; 595 } 596 597 if (m->vel[1] < maxVelY) { 598 if ((m->vel[1] += maxVelY / 8.0f) > maxVelY) { 599 m->vel[1] = maxVelY; 600 } 601 } 602 603 #ifdef VERSION_JP 604 play_sound(SOUND_ENV_WIND2, m->marioObj->header.gfx.cameraToObject); 605 #endif 606 } 607 } 608 } 609 610 s32 perform_air_step(struct MarioState *m, u32 stepArg) { 611 Vec3f intendedPos; 612 s32 i; 613 s32 quarterStepResult; 614 s32 stepResult = AIR_STEP_NONE; 615 616 m->wall = NULL; 617 618 for (i = 0; i < 4; i++) { 619 intendedPos[0] = m->pos[0] + m->vel[0] / 4.0f; 620 intendedPos[1] = m->pos[1] + m->vel[1] / 4.0f; 621 intendedPos[2] = m->pos[2] + m->vel[2] / 4.0f; 622 623 quarterStepResult = perform_air_quarter_step(m, intendedPos, stepArg); 624 625 //! On one qf, hit OOB/ceil/wall to store the 2 return value, and continue 626 // getting 0s until your last qf. Graze a wall on your last qf, and it will 627 // return the stored 2 with a sharply angled reference wall. (some gwks) 628 629 if (quarterStepResult != AIR_STEP_NONE) { 630 stepResult = quarterStepResult; 631 } 632 633 if (quarterStepResult == AIR_STEP_LANDED || quarterStepResult == AIR_STEP_GRABBED_LEDGE 634 || quarterStepResult == AIR_STEP_GRABBED_CEILING 635 || quarterStepResult == AIR_STEP_HIT_LAVA_WALL) { 636 break; 637 } 638 } 639 640 if (m->vel[1] >= 0.0f) { 641 m->peakHeight = m->pos[1]; 642 } 643 644 m->terrainSoundAddend = mario_get_terrain_sound_addend(m); 645 646 if (m->action != ACT_FLYING) { 647 apply_gravity(m); 648 } 649 apply_vertical_wind(m); 650 651 vec3f_copy(m->marioObj->header.gfx.pos, m->pos); 652 vec3s_set(m->marioObj->header.gfx.angle, 0, m->faceAngle[1], 0); 653 654 return stepResult; 655 } 656 657 // They had these functions the whole time and never used them? Lol 658 659 void set_vel_from_pitch_and_yaw(struct MarioState *m) { 660 m->vel[0] = m->forwardVel * coss(m->faceAngle[0]) * sins(m->faceAngle[1]); 661 m->vel[1] = m->forwardVel * sins(m->faceAngle[0]); 662 m->vel[2] = m->forwardVel * coss(m->faceAngle[0]) * coss(m->faceAngle[1]); 663 } 664 665 void set_vel_from_yaw(struct MarioState *m) { 666 m->vel[0] = m->slideVelX = m->forwardVel * sins(m->faceAngle[1]); 667 m->vel[1] = 0.0f; 668 m->vel[2] = m->slideVelZ = m->forwardVel * coss(m->faceAngle[1]); 669 }