sm64pc/src/game/behaviors/mr_blizzard.inc.c

483 lines
16 KiB
C
Raw Normal View History

2020-07-04 17:18:55 +02:00
// Mr. Blizzard hitbox
2019-08-25 06:46:40 +02:00
struct ObjectHitbox sMrBlizzardHitbox = {
/* interactType: */ INTERACT_MR_BLIZZARD,
/* downOffset: */ 24,
/* damageOrCoinValue: */ 2,
/* health: */ 99,
/* numLootCoins: */ 3,
/* radius: */ 65,
/* height: */ 170,
/* hurtboxRadius: */ 65,
/* hurtboxHeight: */ 170,
};
2020-07-04 17:18:55 +02:00
// Mr. Blizzard particle spawner.
void mr_blizzard_spawn_white_particles(s8 count, s8 offsetY, s8 forwardVelBase, s8 velYBase,
s8 sizeBase) {
2020-04-03 20:57:26 +02:00
static struct SpawnParticlesInfo D_80331A00 = {
/* behParam: */ 0,
/* count: */ 6,
/* model: */ MODEL_WHITE_PARTICLE,
/* offsetY: */ 0,
/* forwardVelBase: */ 5,
/* forwardVelRange: */ 5,
/* velYBase: */ 10,
/* velYRange: */ 10,
/* gravity: */ -3,
/* dragStrength: */ 0,
/* sizeBase: */ 3.0f,
/* sizeRange: */ 5.0f,
};
2019-08-25 06:46:40 +02:00
2020-02-03 06:51:26 +01:00
D_80331A00.count = count;
D_80331A00.offsetY = offsetY;
D_80331A00.forwardVelBase = forwardVelBase;
D_80331A00.velYBase = velYBase;
D_80331A00.sizeBase = sizeBase;
2020-03-02 04:42:52 +01:00
cur_obj_spawn_particles(&D_80331A00);
2019-08-25 06:46:40 +02:00
}
2020-07-04 17:18:55 +02:00
/**
* Mr. Blizzard initialization function.
*/
2019-08-25 06:46:40 +02:00
void bhv_mr_blizzard_init(void) {
2020-07-04 17:18:55 +02:00
if (o->oBehParams2ndByte == MR_BLIZZARD_STYPE_JUMPING) {
// Jumping Mr. Blizzard.
o->oAction = MR_BLIZZARD_ACT_JUMP;
2020-06-02 18:44:34 +02:00
o->oMrBlizzardGraphYOffset = 24.0f;
o->oMrBlizzardTargetMoveYaw = o->oMoveAngleYaw;
2019-08-25 06:46:40 +02:00
} else {
2020-07-04 17:18:55 +02:00
if (o->oBehParams2ndByte != MR_BLIZZARD_STYPE_NO_CAP) {
// Cap wearing Mr. Blizzard from SL.
2019-08-25 06:46:40 +02:00
if (save_file_get_flags() & SAVE_FLAG_CAP_ON_MR_BLIZZARD) {
o->oAnimState = 1;
}
}
2020-07-04 17:18:55 +02:00
// Mr. Blizzard starts under the floor holding nothing.
2020-06-02 18:44:34 +02:00
o->oMrBlizzardGraphYOffset = -200.0f;
o->oMrBlizzardHeldObj = NULL;
2019-08-25 06:46:40 +02:00
}
}
2020-07-04 17:18:55 +02:00
/**
* Handler for spawning Mr. Blizzard's snowball.
*/
static void mr_blizzard_act_spawn_snowball(void) {
// If Mr. Blizzard is not holding a snowball, and the animation reaches 5 frames
// spawn the Mr. Blizzard snowball.
2020-06-02 18:44:34 +02:00
if (o->oMrBlizzardHeldObj == NULL && cur_obj_init_anim_check_frame(0, 5)) {
2020-07-04 17:18:55 +02:00
o->oMrBlizzardHeldObj =
spawn_object_relative(0, -70, (s32)(o->oMrBlizzardGraphYOffset + 153.0f), 0, o,
MODEL_WHITE_PARTICLE, bhvMrBlizzardSnowball);
2020-03-02 04:42:52 +01:00
} else if (cur_obj_check_anim_frame(10)) {
2020-06-02 18:44:34 +02:00
o->prevObj = o->oMrBlizzardHeldObj;
2020-03-02 04:42:52 +01:00
} else if (cur_obj_check_if_near_animation_end()) {
2020-07-04 17:18:55 +02:00
// If Mr. Blizzard's graphical position is below the ground, move to hide and unhide action.
// Otherwise, move to rotate action.
2020-06-02 18:44:34 +02:00
if (o->oMrBlizzardGraphYOffset < 0.0f) {
2020-07-04 17:18:55 +02:00
o->oAction = MR_BLIZZARD_ACT_HIDE_UNHIDE;
2019-08-25 06:46:40 +02:00
} else {
2020-07-04 17:18:55 +02:00
o->oAction = MR_BLIZZARD_ACT_ROTATE;
2019-08-25 06:46:40 +02:00
}
}
}
2020-07-04 17:18:55 +02:00
/**
* Handler for Mario entering or exiting Mr. Blizzard's range.
*/
static void mr_blizzard_act_hide_unhide(void) {
2019-08-25 06:46:40 +02:00
if (o->oDistanceToMario < 1000.0f) {
2020-07-04 17:18:55 +02:00
// If Mario is in range, move to rising action, make Mr. Blizzard visible,
// make Mr. Blizzard tangible, and initialize GraphYVel.
2020-03-02 04:42:52 +01:00
cur_obj_play_sound_2(SOUND_OBJ_SNOW_SAND2);
2020-07-04 17:18:55 +02:00
o->oAction = MR_BLIZZARD_ACT_RISE_FROM_GROUND;
2019-08-25 06:46:40 +02:00
o->oMoveAngleYaw = o->oAngleToMario;
2020-06-02 18:44:34 +02:00
o->oMrBlizzardGraphYVel = 42.0f;
2019-08-25 06:46:40 +02:00
2020-04-03 20:57:26 +02:00
mr_blizzard_spawn_white_particles(8, -10, 15, 20, 10);
2020-03-02 04:42:52 +01:00
cur_obj_unhide();
cur_obj_become_tangible();
2019-08-25 06:46:40 +02:00
} else {
2020-07-04 17:18:55 +02:00
// If Mario is not in range, make Mr. Blizzard invisible.
2020-03-02 04:42:52 +01:00
cur_obj_hide();
2019-08-25 06:46:40 +02:00
}
}
2020-07-04 17:18:55 +02:00
/**
* Handler for Mr. Blizzard popping up out of the ground.
*/
static void mr_blizzard_act_rise_from_ground(void) {
// If the timer is not 0, decrement by 1 until it reaches 0.
2020-06-02 18:44:34 +02:00
if (o->oMrBlizzardTimer != 0) {
o->oMrBlizzardTimer -= 1;
} else if ((o->oMrBlizzardGraphYOffset += o->oMrBlizzardGraphYVel) > 24.0f) {
2020-07-04 17:18:55 +02:00
// Increments GraphYOffset by GraphYVel until it is greater than 24,
// moving Mr. Blizzard's graphical position upward each frame.
// Then, Mr. Blizzard's Y-position is increased by the value of
// GraphYOffset minus 24, GraphYOffset is
// set to 24, VelY is set to GraphYVel and action is moved to rotate.
2020-06-02 18:44:34 +02:00
o->oPosY += o->oMrBlizzardGraphYOffset - 24.0f;
o->oMrBlizzardGraphYOffset = 24.0f;
2019-08-25 06:46:40 +02:00
2020-04-03 20:57:26 +02:00
mr_blizzard_spawn_white_particles(8, -20, 20, 15, 10);
2019-08-25 06:46:40 +02:00
2020-07-04 17:18:55 +02:00
o->oAction = MR_BLIZZARD_ACT_ROTATE;
2020-06-02 18:44:34 +02:00
o->oVelY = o->oMrBlizzardGraphYVel;
} else if ((o->oMrBlizzardGraphYVel -= 10.0f) < 0.0f) {
2020-07-04 17:18:55 +02:00
// Decrement GraphYOffset until it is less than 0.
// When it is less than 0, set it to 47 and set timer to 5.
2020-06-02 18:44:34 +02:00
o->oMrBlizzardGraphYVel = 47.0f;
o->oMrBlizzardTimer = 5;
2019-08-25 06:46:40 +02:00
}
}
2020-07-04 17:18:55 +02:00
/**
* Handler for Mr. Blizzard's rotation.
*/
static void mr_blizzard_act_rotate(void) {
2019-08-25 06:46:40 +02:00
2020-07-04 17:18:55 +02:00
s16 angleDiff;
f32 prevDizziness;
// While Mr. Blizzard is on the ground, rotate toward Mario at
// 8.4375 degrees/frame.
if (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND) {
2020-03-02 04:42:52 +01:00
cur_obj_rotate_yaw_toward(o->oAngleToMario, 0x600);
2019-08-25 06:46:40 +02:00
2020-07-04 17:18:55 +02:00
// Modify the ChangeInDizziness based on Mario's angle to Mr. Blizzard.
angleDiff = o->oAngleToMario - o->oMoveAngleYaw;
if (angleDiff != 0) {
if (angleDiff < 0) {
2020-06-02 18:44:34 +02:00
o->oMrBlizzardChangeInDizziness -= 8.0f;
2019-08-25 06:46:40 +02:00
} else {
2020-06-02 18:44:34 +02:00
o->oMrBlizzardChangeInDizziness += 8.0f;
2019-08-25 06:46:40 +02:00
}
2020-07-04 17:18:55 +02:00
// Incremement Dizziness by value of ChangeInDizziness
2020-06-02 18:44:34 +02:00
o->oMrBlizzardDizziness += o->oMrBlizzardChangeInDizziness;
} else if (o->oMrBlizzardDizziness != 0.0f) {
2020-07-04 17:18:55 +02:00
prevDizziness = o->oMrBlizzardDizziness;
// Slowly move Dizziness back to 0 by making ChangeInDizziness positive if Dizziness
// is negative, and making ChangeInDizziness negative if Dizziness is positive.
2020-06-02 18:44:34 +02:00
if (o->oMrBlizzardDizziness < 0.0f) {
approach_f32_ptr(&o->oMrBlizzardChangeInDizziness, 1000.0f, 80.0f);
2019-08-25 06:46:40 +02:00
} else {
2020-06-02 18:44:34 +02:00
approach_f32_ptr(&o->oMrBlizzardChangeInDizziness, -1000.0f, 80.0f);
2019-08-25 06:46:40 +02:00
}
2020-06-02 18:44:34 +02:00
o->oMrBlizzardDizziness += o->oMrBlizzardChangeInDizziness;
2020-07-04 17:18:55 +02:00
// If prevDizziness has a different sign than Dizziness,
// set Dizziness and ChangeInDizziness to 0.
if (prevDizziness * o->oMrBlizzardDizziness < 0.0f) {
2020-06-02 18:44:34 +02:00
o->oMrBlizzardDizziness = o->oMrBlizzardChangeInDizziness = 0.0f;
2019-08-25 06:46:40 +02:00
}
}
2020-07-04 17:18:55 +02:00
// If Dizziness is not 0 and Mr. Blizzard's FaceRollAngle has a magnitude greater than
// 67.5 degrees move to death action, delete the snowball, and make Mr. Blizzard intangible.
2020-06-02 18:44:34 +02:00
if (o->oMrBlizzardDizziness != 0.0f) {
2019-08-25 06:46:40 +02:00
if (absi(o->oFaceAngleRoll) > 0x3000) {
2020-07-04 17:18:55 +02:00
o->oAction = MR_BLIZZARD_ACT_DEATH;
2020-06-02 18:44:34 +02:00
o->prevObj = o->oMrBlizzardHeldObj = NULL;
2020-03-02 04:42:52 +01:00
cur_obj_become_intangible();
2019-08-25 06:46:40 +02:00
}
2020-07-04 17:18:55 +02:00
// If Mario gets too far away, move to burrow action and delete the snowball.
2019-08-25 06:46:40 +02:00
} else if (o->oDistanceToMario > 1500.0f) {
2020-07-04 17:18:55 +02:00
o->oAction = MR_BLIZZARD_ACT_BURROW;
2020-06-02 18:44:34 +02:00
o->oMrBlizzardChangeInDizziness = 300.0f;
o->prevObj = o->oMrBlizzardHeldObj = NULL;
2020-07-04 17:18:55 +02:00
// After 60 frames, if Mario is within 11.25 degrees of Mr. Blizzard, throw snowball action.
2019-08-25 06:46:40 +02:00
} else if (o->oTimer > 60 && abs_angle_diff(o->oAngleToMario, o->oMoveAngleYaw) < 0x800) {
2020-07-04 17:18:55 +02:00
o->oAction = MR_BLIZZARD_ACT_THROW_SNOWBALL;
2019-08-25 06:46:40 +02:00
}
}
}
2020-07-04 17:18:55 +02:00
/**
* Handler for Mr. Blizzard's death.
*/
static void mr_blizzard_act_death(void) {
struct Object *cap;
2019-08-25 06:46:40 +02:00
2020-06-02 18:44:34 +02:00
if (clamp_f32(&o->oMrBlizzardDizziness, -0x4000, 0x4000)) {
if (o->oMrBlizzardChangeInDizziness != 0.0f) {
2020-03-02 04:42:52 +01:00
cur_obj_play_sound_2(SOUND_OBJ_SNOW_SAND1);
2020-07-04 17:18:55 +02:00
// If Mr. Blizzard is wearing Mario's cap, clear
// the save flag and spawn Mario's cap.
2019-08-25 06:46:40 +02:00
if (o->oAnimState) {
save_file_clear_flags(SAVE_FLAG_CAP_ON_MR_BLIZZARD);
2020-07-04 17:18:55 +02:00
cap = spawn_object_relative(0, 5, 105, 0, o, MODEL_MARIOS_CAP, bhvNormalCap);
if (cap != NULL) {
cap->oMoveAngleYaw = o->oFaceAngleYaw + (o->oFaceAngleRoll < 0 ? 0x4000 : -0x4000);
cap->oForwardVel = 10.0f;
2019-08-25 06:46:40 +02:00
}
2020-07-04 17:18:55 +02:00
// Mr. Blizzard no longer spawns with Mario's cap on.
2019-08-25 06:46:40 +02:00
o->oAnimState = 0;
}
2020-06-02 18:44:34 +02:00
o->oMrBlizzardChangeInDizziness = 0.0f;
2019-08-25 06:46:40 +02:00
}
} else {
2020-06-02 18:44:34 +02:00
if (o->oMrBlizzardDizziness < 0) {
o->oMrBlizzardChangeInDizziness -= 40.0f;
2019-08-25 06:46:40 +02:00
} else {
2020-06-02 18:44:34 +02:00
o->oMrBlizzardChangeInDizziness += 40.0f;
2019-08-25 06:46:40 +02:00
}
2020-06-02 18:44:34 +02:00
o->oMrBlizzardDizziness += o->oMrBlizzardChangeInDizziness;
2019-08-25 06:46:40 +02:00
}
2020-07-04 17:18:55 +02:00
// After 30 frames, play the defeat sound once and scale Mr. Blizzard down to 0
// at .03 units per frame. Spawn coins and set the coins to not respawn.
2019-08-25 06:46:40 +02:00
if (o->oTimer >= 30) {
if (o->oTimer == 30) {
2020-03-02 04:42:52 +01:00
cur_obj_play_sound_2(SOUND_OBJ_ENEMY_DEFEAT_SHRINK);
2019-08-25 06:46:40 +02:00
}
2020-06-02 18:44:34 +02:00
if (o->oMrBlizzardScale != 0.0f) {
if ((o->oMrBlizzardScale -= 0.03f) <= 0.0f) {
o->oMrBlizzardScale = 0.0f;
2019-08-25 06:46:40 +02:00
if (!(o->oBehParams & 0x0000FF00)) {
2020-03-02 04:42:52 +01:00
obj_spawn_loot_yellow_coins(o, o->oNumLootCoins, 20.0f);
2019-08-25 06:46:40 +02:00
set_object_respawn_info_bits(o, 1);
}
}
2020-07-04 17:18:55 +02:00
// Reset Mr. Blizzard if Mario leaves its radius.
2019-08-25 06:46:40 +02:00
} else if (o->oDistanceToMario > 1000.0f) {
2020-03-02 04:42:52 +01:00
cur_obj_init_animation_with_sound(1);
2019-08-25 06:46:40 +02:00
2020-07-04 17:18:55 +02:00
o->oAction = MR_BLIZZARD_ACT_SPAWN_SNOWBALL;
2020-06-02 18:44:34 +02:00
o->oMrBlizzardScale = 1.0f;
o->oMrBlizzardGraphYOffset = -200.0f;
2019-08-25 06:46:40 +02:00
o->oFaceAngleRoll = 0;
2020-06-02 18:44:34 +02:00
o->oMrBlizzardDizziness = o->oMrBlizzardChangeInDizziness = 0.0f;
2019-08-25 06:46:40 +02:00
}
}
}
2020-07-04 17:18:55 +02:00
/**
* Handler for snowball throw.
*/
static void mr_blizzard_act_throw_snowball(void) {
// Play a sound and set HeldObj to NULL. Then set action to 0.
2020-04-03 20:57:26 +02:00
if (cur_obj_init_anim_check_frame(1, 7)) {
2020-03-02 04:42:52 +01:00
cur_obj_play_sound_2(SOUND_OBJ2_SCUTTLEBUG_ALERT);
2020-06-02 18:44:34 +02:00
o->prevObj = o->oMrBlizzardHeldObj = NULL;
2020-03-02 04:42:52 +01:00
} else if (cur_obj_check_if_near_animation_end()) {
2020-07-04 17:18:55 +02:00
o->oAction = MR_BLIZZARD_ACT_SPAWN_SNOWBALL;
2019-08-25 06:46:40 +02:00
}
}
2020-07-04 17:18:55 +02:00
/**
* Mr. Blizzard's going back into the ground function.
*/
static void mr_blizzard_act_burrow(void) {
// Reset Dizziness by increasing ChangeInDizziness if
// dizziness is negative and decreasing it if Dizziness
2020-06-02 18:44:34 +02:00
o->oMrBlizzardDizziness += o->oMrBlizzardChangeInDizziness;
2019-08-25 06:46:40 +02:00
2020-06-02 18:44:34 +02:00
if (o->oMrBlizzardDizziness < 0.0f) {
o->oMrBlizzardChangeInDizziness += 150.0f;
2019-08-25 06:46:40 +02:00
} else {
2020-06-02 18:44:34 +02:00
o->oMrBlizzardChangeInDizziness -= 150.0f;
2019-08-25 06:46:40 +02:00
}
2020-07-04 17:18:55 +02:00
// Put Mr. Blizzard's graphical position back below ground
// then move to action 0.
2020-06-02 18:44:34 +02:00
if (approach_f32_ptr(&o->oMrBlizzardGraphYOffset, -200.0f, 4.0f)) {
2020-07-04 17:18:55 +02:00
o->oAction = MR_BLIZZARD_ACT_SPAWN_SNOWBALL;
2020-03-02 04:42:52 +01:00
cur_obj_init_animation_with_sound(1);
2019-08-25 06:46:40 +02:00
}
}
2020-07-04 17:18:55 +02:00
/**
* Jumping Mr. Blizzard handler function.
*/
static void mr_blizzard_act_jump(void) {
2020-06-02 18:44:34 +02:00
if (o->oMrBlizzardTimer != 0) {
cur_obj_rotate_yaw_toward(o->oMrBlizzardTargetMoveYaw, 3400);
2019-08-25 06:46:40 +02:00
2020-06-02 18:44:34 +02:00
if (--o->oMrBlizzardTimer == 0) {
2020-03-02 04:42:52 +01:00
cur_obj_play_sound_2(SOUND_OBJ_MR_BLIZZARD_ALERT);
2019-08-25 06:46:40 +02:00
2020-07-04 17:18:55 +02:00
// If Mr. Blizzard is more than 700 units from its home, change its target yaw
// by 180 degrees, jump in the air, set distance from home to 0.
2020-06-02 18:44:34 +02:00
if (o->oMrBlizzardDistFromHome > 700) {
o->oMrBlizzardTargetMoveYaw += 0x8000;
2019-08-25 06:46:40 +02:00
o->oVelY = 25.0f;
2020-06-02 18:44:34 +02:00
o->oMrBlizzardTimer = 30;
o->oMrBlizzardDistFromHome = 0;
2020-07-04 17:18:55 +02:00
// Jump forward.
2019-08-25 06:46:40 +02:00
} else {
o->oForwardVel = 10.0f;
o->oVelY = 50.0f;
o->oMoveFlags = 0;
}
}
2020-07-04 17:18:55 +02:00
} else if (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND) {
// When Mr. Blizzard lands, play the landing sound, stop Mr. Blizzard, and
// set its timer to 15. If Mr. Blizzard's DistFromHome is not 0,
// set DistFromHome to its current distance from its home.
// Otherwise, set DistFromHome to 700.
2020-03-02 04:42:52 +01:00
cur_obj_play_sound_2(SOUND_OBJ_SNOW_SAND1);
2020-06-02 18:44:34 +02:00
if (o->oMrBlizzardDistFromHome != 0) {
o->oMrBlizzardDistFromHome = (s32) cur_obj_lateral_dist_to_home();
2019-08-25 06:46:40 +02:00
} else {
2020-06-02 18:44:34 +02:00
o->oMrBlizzardDistFromHome = 700;
2019-08-25 06:46:40 +02:00
}
o->oForwardVel = 0.0f;
2020-06-02 18:44:34 +02:00
o->oMrBlizzardTimer = 15;
2019-08-25 06:46:40 +02:00
}
}
2020-07-04 17:18:55 +02:00
/**
* Mr. Blizzard update function.
*/
2019-08-25 06:46:40 +02:00
void bhv_mr_blizzard_update(void) {
2020-03-02 04:42:52 +01:00
cur_obj_update_floor_and_walls();
2019-08-25 06:46:40 +02:00
2020-07-04 17:18:55 +02:00
// Behavior loop
2019-08-25 06:46:40 +02:00
switch (o->oAction) {
2020-07-04 17:18:55 +02:00
case MR_BLIZZARD_ACT_SPAWN_SNOWBALL:
mr_blizzard_act_spawn_snowball();
2019-08-25 06:46:40 +02:00
break;
2020-07-04 17:18:55 +02:00
case MR_BLIZZARD_ACT_HIDE_UNHIDE:
mr_blizzard_act_hide_unhide();
2019-08-25 06:46:40 +02:00
break;
2020-07-04 17:18:55 +02:00
case MR_BLIZZARD_ACT_RISE_FROM_GROUND:
mr_blizzard_act_rise_from_ground();
2019-08-25 06:46:40 +02:00
break;
2020-07-04 17:18:55 +02:00
case MR_BLIZZARD_ACT_ROTATE:
mr_blizzard_act_rotate();
2019-08-25 06:46:40 +02:00
break;
2020-07-04 17:18:55 +02:00
case MR_BLIZZARD_ACT_THROW_SNOWBALL:
mr_blizzard_act_throw_snowball();
2019-08-25 06:46:40 +02:00
break;
2020-07-04 17:18:55 +02:00
case MR_BLIZZARD_ACT_BURROW:
mr_blizzard_act_burrow();
2019-08-25 06:46:40 +02:00
break;
2020-07-04 17:18:55 +02:00
case MR_BLIZZARD_ACT_DEATH:
mr_blizzard_act_death();
2019-08-25 06:46:40 +02:00
break;
2020-07-04 17:18:55 +02:00
case MR_BLIZZARD_ACT_JUMP:
mr_blizzard_act_jump();
2019-08-25 06:46:40 +02:00
break;
}
2020-07-04 17:18:55 +02:00
// Set roll angle equal to dizziness, making Mr. Blizzard
// slowly fall over.
2020-06-02 18:44:34 +02:00
o->oFaceAngleRoll = o->oMrBlizzardDizziness;
2020-07-04 17:18:55 +02:00
// Mr. Blizzard's graphical position changes by changing the Y offset.
2020-06-02 18:44:34 +02:00
o->oGraphYOffset = o->oMrBlizzardGraphYOffset + absf(20.0f * sins(o->oFaceAngleRoll))
- 40.0f * (1.0f - o->oMrBlizzardScale);
2019-08-25 06:46:40 +02:00
2020-06-02 18:44:34 +02:00
cur_obj_scale(o->oMrBlizzardScale);
2020-03-02 04:42:52 +01:00
cur_obj_move_standard(78);
2019-08-25 06:46:40 +02:00
obj_check_attacks(&sMrBlizzardHitbox, o->oAction);
}
2020-07-04 17:18:55 +02:00
/**
* Snowball initial takeoff position handler.
*/
2020-04-03 20:57:26 +02:00
static void mr_blizzard_snowball_act_0(void) {
2020-03-02 04:42:52 +01:00
cur_obj_move_using_fvel_and_gravity();
2019-08-25 06:46:40 +02:00
if (o->parentObj->prevObj == o) {
o->oAction = 1;
o->oParentRelativePosX = 190.0f;
o->oParentRelativePosY = o->oParentRelativePosZ = -38.0f;
}
}
2020-07-04 17:18:55 +02:00
/**
* Snowball launching action.
*/
2020-04-03 20:57:26 +02:00
static void mr_blizzard_snowball_act_1(void) {
2020-07-04 17:18:55 +02:00
f32 marioDist;
2019-08-25 06:46:40 +02:00
if (o->parentObj->prevObj == NULL) {
2020-07-04 17:18:55 +02:00
if (o->parentObj->oAction == MR_BLIZZARD_ACT_THROW_SNOWBALL) {
marioDist = o->oDistanceToMario;
if (marioDist > 800.0f) {
marioDist = 800.0f;
2019-08-25 06:46:40 +02:00
}
2020-07-04 17:18:55 +02:00
// Launch the snowball relative to Mario's distance from the snowball.
o->oMoveAngleYaw = (s32)(o->parentObj->oMoveAngleYaw + 4000 - marioDist * 4.0f);
2019-08-25 06:46:40 +02:00
o->oForwardVel = 40.0f;
2020-07-04 17:18:55 +02:00
o->oVelY = -20.0f + marioDist * 0.075f;
2019-08-25 06:46:40 +02:00
}
o->oAction = 2;
o->oMoveFlags = 0;
}
}
2020-07-04 17:18:55 +02:00
// Snowball hitbox.
2020-04-03 20:57:26 +02:00
struct ObjectHitbox sMrBlizzardSnowballHitbox = {
/* interactType: */ INTERACT_MR_BLIZZARD,
/* downOffset: */ 12,
/* damageOrCoinValue: */ 1,
/* health: */ 99,
/* numLootCoins: */ 0,
/* radius: */ 30,
/* height: */ 30,
/* hurtboxRadius: */ 25,
/* hurtboxHeight: */ 25,
};
2020-07-04 17:18:55 +02:00
/**
* Snowball collision function.
*/
2020-04-03 20:57:26 +02:00
static void mr_blizzard_snowball_act_2(void) {
2020-07-04 17:18:55 +02:00
// Set snowball to interact with walls, floors, and Mario.
2020-03-02 04:42:52 +01:00
cur_obj_update_floor_and_walls();
2019-08-25 06:46:40 +02:00
obj_check_attacks(&sMrBlizzardSnowballHitbox, -1);
2020-07-04 17:18:55 +02:00
// If snowball collides with the ground, delete snowball.
if (o->oAction == -1 || o->oMoveFlags & (OBJ_MOVE_MASK_ON_GROUND | OBJ_MOVE_ENTERED_WATER)) {
2020-04-03 20:57:26 +02:00
mr_blizzard_spawn_white_particles(6, 0, 5, 10, 3);
2019-10-05 21:08:05 +02:00
create_sound_spawner(SOUND_GENERAL_MOVING_IN_SAND);
2020-03-02 04:42:52 +01:00
obj_mark_for_deletion(o);
2019-08-25 06:46:40 +02:00
}
2020-03-02 04:42:52 +01:00
cur_obj_move_standard(78);
2019-08-25 06:46:40 +02:00
}
2020-07-04 17:18:55 +02:00
/**
* Snowball behavior loop.
*/
2019-08-25 06:46:40 +02:00
void bhv_mr_blizzard_snowball(void) {
switch (o->oAction) {
case 0:
2020-04-03 20:57:26 +02:00
mr_blizzard_snowball_act_0();
2019-08-25 06:46:40 +02:00
break;
case 1:
2020-04-03 20:57:26 +02:00
mr_blizzard_snowball_act_1();
2019-08-25 06:46:40 +02:00
break;
case 2:
2020-04-03 20:57:26 +02:00
mr_blizzard_snowball_act_2();
2019-08-25 06:46:40 +02:00
break;
}
}