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

157 lines
4.5 KiB
C

/**
* Behavior file for bhvTweester and bhvTweesterSandParticle
* Tweester swaps between twhree action- an idle action, a chasing
* Mario action, and an action that hides it. At certain times the
* Tweester spawns the sand particles also in this file.
*/
struct ObjectHitbox sTweesterHitbox = {
/* interactType: */ INTERACT_TORNADO,
/* downOffset: */ 0,
/* damageOrCoinValue: */ 0,
/* health: */ 0,
/* numLootCoins: */ 0,
/* radius: */ 1500,
/* height: */ 4000,
/* hurtboxRadius: */ 0,
/* hurtboxHeight: */ 0,
};
/**
* Controls the scaling of the tweester as well as
* its forward velocity.
*/
void tweester_scale_and_move(f32 preScale) {
s16 dYaw = 0x2C00;
f32 scale = preScale * 0.4;
o->header.gfx.scale[0]
= (( coss(o->oTweesterScaleTimer) + 1.0) * 0.5 * 0.3 + 1.0) * scale;
o->header.gfx.scale[1]
= ((-coss(o->oTweesterScaleTimer) + 1.0) * 0.5 * 0.5 + 0.5) * scale;
o->header.gfx.scale[2]
= (( coss(o->oTweesterScaleTimer) + 1.0) * 0.5 * 0.3 + 1.0) * scale;
o->oTweesterScaleTimer += 0x200;
o->oForwardVel = 14.0f;
o->oFaceAngleYaw += dYaw;
}
/**
* Tweester's idle action. Basically stays in active until Mario enters a 1500
* radius, at which point it appears and grows for 60 frames at which point it
* it enters the chasing action.
*/
void tweester_act_idle(void) {
if (o->oSubAction == TWEESTER_SUB_ACT_WAIT) {
cur_obj_become_tangible();
cur_obj_set_pos_to_home();
cur_obj_scale(0);
// Hard to have any idea of this purpose, only set here.
o->oTweesterUnused = 0;
// If Mario is within range, change to the growth sub-action.
if (o->oDistanceToMario < 1500.0f)
o->oSubAction++;
o->oTimer = 0;
} else {
cur_obj_play_sound_1(SOUND_ENV_WIND1);
tweester_scale_and_move(o->oTimer / 60.0f);
if (o->oTimer > 59)
o->oAction = TWEESTER_ACT_CHASE;
}
}
/**
* Action where the tweester "chases" Mario.
* After Mario is twirling, then return home.
*/
void tweester_act_chase(void) {
f32 activationRadius = o->oBehParams2ndByte * 100;
o->oAngleToHome = cur_obj_angle_to_home();
cur_obj_play_sound_1(SOUND_ENV_WIND1);
if (cur_obj_lateral_dist_from_mario_to_home() < activationRadius
&& o->oSubAction == TWEESTER_SUB_ACT_CHASE) {
o->oForwardVel = 20.0f;
cur_obj_rotate_yaw_toward(o->oAngleToMario, 0x200);
print_debug_top_down_objectinfo("off ", 0);
if (gMarioStates->action == ACT_TWIRLING)
o->oSubAction++;
} else {
o->oForwardVel = 20.0f;
cur_obj_rotate_yaw_toward(o->oAngleToHome, 0x200);
if (cur_obj_lateral_dist_to_home() < 200.0f)
o->oAction = TWEESTER_ACT_HIDE;
}
if (o->oDistanceToMario > 3000.0f)
o->oAction = TWEESTER_ACT_HIDE;
cur_obj_update_floor_and_walls();
if (o->oMoveFlags & OBJ_MOVE_HIT_WALL)
o->oMoveAngleYaw = o->oWallAngle;
cur_obj_move_standard(60);
tweester_scale_and_move(1.0f);
spawn_object(o, MODEL_SAND_DUST, bhvTweesterSandParticle);
}
/**
* Shrinks the tweester until it is invisible, then returns to the idle
* action if Mario is 2500 units away or 12 seconds passed.
*/
void tweester_act_hide(void) {
f32 shrinkTimer = 60.0f - o->oTimer;
if (shrinkTimer >= 0.0f)
tweester_scale_and_move(shrinkTimer / 60.0f);
else {
cur_obj_become_intangible();
if (cur_obj_lateral_dist_from_mario_to_home() > 2500.0f)
o->oAction = TWEESTER_ACT_IDLE;
if (o->oTimer > 360)
o->oAction = TWEESTER_ACT_IDLE;
}
}
// Array of Tweester action functions.
void (*sTweesterActions[])(void) = { tweester_act_idle, tweester_act_chase, tweester_act_hide };
/**
* Loop behavior for Tweester.
* Loads the hitbox and calls its relevant action.
*/
void bhv_tweester_loop(void) {
obj_set_hitbox(o, &sTweesterHitbox);
cur_obj_call_action_function(sTweesterActions);
o->oInteractStatus = 0;
}
/**
* Loop behavior for the particles Tweesters create.
* Floats upwards semi-randomly.
*/
void bhv_tweester_sand_particle_loop(void) {
o->oMoveAngleYaw += 0x3700;
o->oForwardVel += 15.0f;
o->oPosY += 22.0f;
cur_obj_scale(random_float() + 1.0);
if (o->oTimer == 0) {
obj_translate_xz_random(o, 100.0f);
o->oFaceAnglePitch = random_u16();
o->oFaceAngleYaw = random_u16();
}
if (o->oTimer > 15)
obj_mark_for_deletion(o);
}