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

171 lines
5.0 KiB
C

/**
* Behavior for bhvTTCMovingBar.
*/
/**
* The delay before each cycle on each setting. On random setting, this is
* overwritten with one of the below delays after the first cycle.
*/
static s16 sTTCMovingBarDelays[] = {
/* TTC_SPEED_SLOW */ 55,
/* TTC_SPEED_FAST */ 30,
/* TTC_SPEED_RANDOM */ 55,
/* TTC_SPEED_STOPPED */ 0,
};
/**
* The possible delays before each cycle while on random setting.
*/
static s8 sTTCMovingBarRandomDelays[] = { 1, 12, 55, 100 };
/**
* Init function for bhvTTCMovingBar.
*/
void bhv_ttc_moving_bar_init(void) {
// If on still setting, then stick out
if ((o->oTTCMovingBarDelay = sTTCMovingBarDelays[gTTCSpeedSetting]) == 0) {
o->oTTCMovingBarOffset = 250.0f;
}
// This causes the first cycle to start at different times for different
// bars
o->oTTCMovingBarStoppedTimer = 10 * o->oBehParams2ndByte;
o->oMoveAngleYaw = 0x4000 - o->oMoveAngleYaw;
}
/**
* Wait a delay if necessary, then begin pulling back.
*/
static void ttc_moving_bar_act_wait(void) {
if (o->oTTCMovingBarDelay != 0 && o->oTimer > o->oTTCMovingBarDelay) {
// This is zero except on the first cycle, and is used to desync the
// bars from each other at the very beginning
if (o->oTTCMovingBarStoppedTimer != 0) {
o->oTTCMovingBarStoppedTimer -= 1;
} else {
if (gTTCSpeedSetting == TTC_SPEED_RANDOM) {
// Set the delay for the next cycle
o->oTTCMovingBarDelay = sTTCMovingBarRandomDelays[random_u16() & 0x3];
// With 50% probability, pause after pulling back
if (random_u16() % 2 == 0) {
o->oTTCMovingBarStoppedTimer = random_linear_offset(20, 100);
}
}
// Begin pulling back
o->oAction = TTC_MOVING_BAR_ACT_PULL_BACK;
o->oTTCMovingBarSpeed = -8.0f;
}
}
}
/**
* Pull back, possibly stop for a bit, then begin extending.
*/
static void ttc_moving_bar_act_pull_back(void) {
// Started with -8 speed, accelerate back to > 0
if ((o->oTTCMovingBarSpeed += 0.73f) > 0.0f) {
// Possibly pause after pulling back
if (o->oTTCMovingBarStoppedTimer != 0) {
o->oTTCMovingBarStoppedTimer -= 1;
o->oTTCMovingBarSpeed = 0.0f;
} else {
// Begin extending
o->oAction = TTC_MOVING_BAR_ACT_EXTEND;
o->oTTCMovingBarSpeed = 29.0f;
}
}
}
/**
* Reset and enter the wait action.
*/
static void ttc_moving_bar_reset(void) {
o->oTTCMovingBarOffset = o->oTTCMovingBarSpeed = 0.0f;
o->oAction = TTC_MOVING_BAR_ACT_WAIT;
}
/**
* With 25% probability on random setting, stop at 0 and reset.
* Otherwise, launch outward, oscillating and slowing down around 250, then
* begin retracting.
*/
static void ttc_moving_bar_act_extend(void) {
// If we passed the 250 threshold and we have decelerated enough
if ((o->oTTCMovingBarOffset == 250.0f
|| (250.0f - o->oTTCMovingBarOffset) * (250.0f - o->oTTCMovingBarStartOffset) < 0.0f)
&& o->oTTCMovingBarSpeed > -8.0f && o->oTTCMovingBarSpeed < 8.0f) {
// Begin retracting
o->oAction = TTC_MOVING_BAR_ACT_RETRACT;
o->oTTCMovingBarSpeed = 0.0f;
} else {
f32 accel;
// Accelerate before reaching 250, and decelerate after reaching it
if (o->oTTCMovingBarOffset < 250.0f) {
accel = 6.4f;
} else {
accel = -6.4f;
}
// Strengthen deceleration
if (o->oTTCMovingBarSpeed * accel < 0.0f) {
accel *= 2.35f;
}
o->oTTCMovingBarSpeed += accel;
// When we pass neutral on random setting, then stop immediately with
// 25% probability (fake out)
if (gTTCSpeedSetting == TTC_SPEED_RANDOM
&& o->oTTCMovingBarOffset * o->oTTCMovingBarStartOffset < 0.0f && random_u16() % 4 == 0) {
ttc_moving_bar_reset();
}
}
}
/**
* Wait a second, then retract back into the wall.
*/
static void ttc_moving_bar_act_retract(void) {
// Wait a second
if (o->oTimer > 30) {
// Retract
o->oTTCMovingBarSpeed = -5.0f;
if (o->oTTCMovingBarOffset < 0.0f) {
ttc_moving_bar_reset();
}
}
}
/**
* Update function for bhvTTCMovingBar.
*/
void bhv_ttc_moving_bar_update(void) {
o->oTTCMovingBarStartOffset = o->oTTCMovingBarOffset;
obj_perform_position_op(POS_OP_SAVE_POSITION);
o->oTTCMovingBarOffset += o->oTTCMovingBarSpeed;
switch (o->oAction) {
case TTC_MOVING_BAR_ACT_WAIT:
ttc_moving_bar_act_wait();
break;
case TTC_MOVING_BAR_ACT_PULL_BACK:
ttc_moving_bar_act_pull_back();
break;
case TTC_MOVING_BAR_ACT_EXTEND:
ttc_moving_bar_act_extend();
break;
case TTC_MOVING_BAR_ACT_RETRACT:
ttc_moving_bar_act_retract();
break;
}
obj_set_dist_from_home(o->oTTCMovingBarOffset);
obj_perform_position_op(POS_OP_COMPUTE_VELOCITY);
}