#include <ultra64.h>
#include "functions.h"
#include "variables.h"
#include "port/Patches/Patches.h"
static void __chNipper_updateFunc(Actor *this);
static Actor *__chNipper_animFunc(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx);
enum ch_nipper_states_e {
CH_NIPPER_STATE_1_UNKNOWN = 1,
CH_NIPPER_STATE_2_UNKNOWN,
CH_NIPPER_STATE_3_UNKNOWN,
CH_NIPPER_STATE_4_DIEING,
CH_NIPPER_STATE_5_SPAWNED,
CH_NIPPER_STATE_6_DEAD,
CH_NIPPER_STATE_7_UNKNOWN
};
static s32 __chNipper_sharedHits(void) {
s32 bits = port_puzzleStep_get(ANCHOR_PUZZLE_TTC_NIPPER) & 0x7;
return (bits & 1) + ((bits >> 1) & 1) + ((bits >> 2) & 1);
}
static s32 __chNipper_localHits(Actor *this) {
if (this->state == CH_NIPPER_STATE_6_DEAD || this->state == CH_NIPPER_STATE_7_UNKNOWN) {
return 3;
}
if (this->lifetime_value == 80.0f) {
return 1;
}
if (this->lifetime_value == 40.0f) {
return 2;
}
return 0;
}
ActorAnimationInfo gChNipperAnimations[8] = {
{0, 0.0},
{ASSET_C0_ANIM_NIPPER_IDLE, 2.0f},
{ASSET_BD_ANIM_NIPPER_VULNERABLE, 1.5f},
{ASSET_BF_ANIM_NIPPER_ATTACK, 1.2f},
{ASSET_BE_ANIM_NIPPER_OW, 1.3f},
{ASSET_C0_ANIM_NIPPER_IDLE, 2.0f},
{ASSET_133_ANIM_NIPPER_DIE, 3.0f},
{0, 0.0}
};
ActorInfo gChNipper = {
MARKER_A5_NIPPER, ACTOR_117_NIPPER, ASSET_3D5_MODEL_NIPPER,
0x1, gChNipperAnimations,
__chNipper_updateFunc, actor_update_func_80326224, __chNipper_animFunc,
0, 0x299, 10.0f, 0
};
static void __chNipper_drawParticlesAtPosition(f32 *position, s32 count) {
static s32 D_8038C5A4[3] = {180, 180, 180};
static ParticleScaleAndLifetimeRanges D_8038C5B0 = {
{0.1f, 0.5f},
{1.4f, 2.8f},
{0.0f, 0.01f},
{0.5f, 1.4f},
0.0f, 0.01f
};
ParticleEmitter *pCtrl;
pCtrl = partEmitMgr_newEmitter(count);
pCtrl = pCtrl;
particleEmitter_setSprite(pCtrl, ASSET_700_SPRITE_DUST);
particleEmitter_setRGB(pCtrl, D_8038C5A4);
particleEmitter_setStartingFrameRange(pCtrl, 0, 7);
particleEmitter_setPosition(pCtrl, position);
particleEmitter_setSpawnPositionRange(pCtrl,
-10.0f, -5.0f, -10.0f,
10.0f, 10.0f, 10.0f
);
particleEmitter_setParticleVelocityRange(pCtrl,
-40.0f, 10.0f, -40.0f,
40.0f, 40.0f, 40.0f
);
particleEmitter_setScaleAndLifetimeRanges(pCtrl, &D_8038C5B0);
particleEmitter_emitN(pCtrl, count);
}
static Actor *__chNipper_animFunc(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) {
Actor *this;
this = marker_getActor(marker);
modelRender_setAppendageVisibility(3, (this->state == 7)? 0 : 1);
return actor_draw(marker, gfx, mtx, vtx);
}
static void __chNipper_setAnimationDuration(Actor *this) {
subaddie_set_state_looped(this, CH_NIPPER_STATE_3_UNKNOWN);
this->unk1C[0] = 0.0f;
switch((s32)this->lifetime_value){
case 120:
anctrl_setDuration(this->anctrl, 1.2f);
break;
case 80:
anctrl_setDuration(this->anctrl, 1.05f);
break;
case 40:
anctrl_setDuration(this->anctrl, 0.9f);
break;
}
}
static void __chNipper_spawnedShowTextCallback(ActorMarker *caller, enum asset_e text_id, s32 arg2){
Actor *this;
this = marker_getActor(caller);
__chNipper_setAnimationDuration(this);
ncStaticCamera_exit();
comusic_8025AB44(COMUSIC_12_TTC_NIPPER, -1, 300);
}
static void __chNipper_playDeathAnimation(Actor *this) {
s32 i;
subaddie_set_state_with_direction(this, CH_NIPPER_STATE_4_DIEING, 0.01f, 1);
actor_playAnimationOnce(this);
for(i = 0; i < 3; i ++){
sfx_playFadeShorthandDefault(SFX_79_TICKER_DEATH, 0.5f, 17000, this->position, 1500, 3000);
};
}
static bool __func_80388088(Actor *this){
f32 sp2C;
f32 sp20[3];
bool out;
sp2C = this->yaw - subaddie_getYawToPlayer(this);
player_getPosition(sp20);
if(sp20[0] < -5680.0f){
return false;
}
return BOOL(-35.0f < sp2C && sp2C < 35.0f);
}
static bool __chNipper_shouldShowActor(Actor *this){
return BOOL(subaddie_playerIsWithinSphereAndActive(this, 1300) && __func_80388088(this));
}
static void __chNipper_dieFunc(ActorMarker *this_marker, ActorMarker *other_marker) {
Actor *this;
s32 i;
this = marker_getActor(this_marker);
func_8032B4DC(this, other_marker, 7);
if (this->lifetime_value == 40.0f) {
port_puzzleStep_orBits(ANCHOR_PUZZLE_TTC_NIPPER, 0x7);
subaddie_set_state_with_direction(this, CH_NIPPER_STATE_6_DEAD, 0.01f, 1);
actor_playAnimationOnce(this);
for(i = 0; i < 3; i++){
sfx_playFadeShorthandDefault(SFX_78_EAGLECRY, 0.7f, 20000, this->position, 1500, 3000);
};
comusic_8025AB44(COMUSIC_12_TTC_NIPPER, 0, 300);
func_8025AABC(COMUSIC_12_TTC_NIPPER);
func_8032BB88(this, -1, 300);
gcStaticCamera_activate(0x1C);
return;
}
if (this->lifetime_value == 80.0f) {
port_puzzleStep_orBits(ANCHOR_PUZZLE_TTC_NIPPER, 0x3);
__chNipper_playDeathAnimation(this);
this->lifetime_value = 40.0f;
return;
}
port_puzzleStep_orBits(ANCHOR_PUZZLE_TTC_NIPPER, 0x1);
__chNipper_playDeathAnimation(this);
this->lifetime_value = 80.0f;
gcdialog_showDialog(VER_SELECT(ASSET_A10_DIALOG_NIPPER_HURT, 0x910, 0, 0), 4, NULL, NULL, NULL, NULL);
return;
}
static s32 __chNipper_determineMarkerId(ActorMarker * this_marker, ActorMarker * other_marker){
if(this_marker->unk40_31 == 1){
this_marker->id = MARKER_16C_NIPPER;
}
else{
this_marker->id = MARKER_A5_NIPPER;
}
return true;
}
static void __chNipper_ow2Func(ActorMarker * this_marker, ActorMarker *other_marker){
Actor *this;
if(other_marker->id == 1){
this = marker_getActor(this_marker);
if( !mapSpecificFlags_get(TTC_SPECIFIC_FLAG_7_NIPPER_FIRST_MEET_TEXT_SHOWN)
&& this->has_met_before
&& gcdialog_showDialog(VER_SELECT(ASSET_A0F_DIALOG_NIPPER_HIT_BY_EGG, 0x90F, 0, 0), 0, NULL, NULL, NULL, NULL)
){
mapSpecificFlags_set(TTC_SPECIFIC_FLAG_7_NIPPER_FIRST_MEET_TEXT_SHOWN, true);
}
}
}
static void __chNipper_owFunc(ActorMarker * this_marker, ActorMarker *other_marker){
Actor *this = marker_getActor(this_marker);
if( !this->unk138_23
&& this->has_met_before
&& gcdialog_showDialog(VER_SELECT(ASSET_A11_DIALOG_NIPPER_ATTACK, 0x911, 0, 0), 0, NULL, NULL, NULL, NULL)
){
this->unk138_23 = true;
}
}
static void __chNipper_updateFunc(Actor *this){
f32 particlePosition[3];
s32 sp48;
s32 xVelocity;
f32 playerPosition[3];
enum bsgroup_e player_movement_group;
s32 sharedHits;
player_getPosition(playerPosition);
xVelocity = func_80309D58(playerPosition, 1);
if(!this->volatile_initialized){
this->volatile_initialized = true;
this->velocity_x = xVelocity;
func_8032BC18(this);
}
if(this->state != CH_NIPPER_STATE_7_UNKNOWN){
if(0.0f == this->velocity_x && xVelocity){
comusic_8025AB44(COMUSIC_12_TTC_NIPPER, -1, 5000);
func_8032BB88(this, 0, 4000);
midichannel_incOrDecCounter(false);
}
else if(!xVelocity && 0.0f != this->velocity_x){
comusic_8025AB44(COMUSIC_12_TTC_NIPPER, 0, 300);
func_8025AABC(COMUSIC_12_TTC_NIPPER);
func_8032BB88(this, -1, 300);
midichannel_incOrDecCounter(true);
}
this->velocity_x = xVelocity;
}
if (this->initialized && this->state != CH_NIPPER_STATE_4_DIEING && this->state != CH_NIPPER_STATE_6_DEAD &&
this->state != CH_NIPPER_STATE_7_UNKNOWN) {
sharedHits = __chNipper_sharedHits();
if (__chNipper_localHits(this) < sharedHits) {
if (sharedHits >= 3) {
this->lifetime_value = 40.0f;
subaddie_set_state_with_direction(this, CH_NIPPER_STATE_6_DEAD, 0.01f, 1);
actor_playAnimationOnce(this);
sfx_playFadeShorthandDefault(SFX_78_EAGLECRY, 0.7f, 20000, this->position, 1500, 3000);
comusic_8025AB44(COMUSIC_12_TTC_NIPPER, 0, 300);
func_8025AABC(COMUSIC_12_TTC_NIPPER);
func_8032BB88(this, -1, 300);
} else {
this->lifetime_value = (sharedHits == 1) ? 80.0f : 40.0f;
}
}
}
switch(this->state){
case CH_NIPPER_STATE_1_UNKNOWN:
if(!this->initialized){
anctrl_setTransitionDuration(this->anctrl, 0.35f);
subaddie_set_state_with_direction(this, CH_NIPPER_STATE_1_UNKNOWN, 0.01f, 1);
this->lifetime_value = 120.0f;
this->marker->propPtr->unk8_3 = true;
marker_setCollisionScripts(this->marker, __chNipper_owFunc, __chNipper_ow2Func, __chNipper_dieFunc);
func_803300C0(this->marker, __chNipper_determineMarkerId);
this->initialized = true;
}
if(__chNipper_shouldShowActor(this)){
player_movement_group = player_movementGroup();
if( !this->has_met_before
&& player_movement_group != BSGROUP_1_INTR
&& player_movement_group != BSGROUP_A_FLYING
){
subaddie_set_state_with_direction(this, CH_NIPPER_STATE_5_SPAWNED, 0.01f, 1);
if(gcdialog_showDialog(VER_SELECT(ASSET_A0E_DIALOG_NIPPER_SPAWNED, 0x90E, 0, 0), 0xf, this->position, this->marker, __chNipper_spawnedShowTextCallback, NULL)){
this->has_met_before = TRUE;
}
comusic_8025AB44(COMUSIC_12_TTC_NIPPER, 5000, 300);
ncStaticCamera_setToNode(11);
}
else{
__chNipper_setAnimationDuration(this);
}
break;
}
if( actor_animationIsAt(this, 0.2f)
|| actor_animationIsAt(this, 0.2f)
|| actor_animationIsAt(this, 0.6f)
|| actor_animationIsAt(this, 0.7f)
){
sfx_playFadeShorthandDefault(SFX_3D_TICKER_WALKING, 0.75f, 12000, this->position, 0x5dc, 0xbb8);
}
break;
case CH_NIPPER_STATE_2_UNKNOWN:
if(!__chNipper_shouldShowActor(this)){
subaddie_set_state_looped(this, CH_NIPPER_STATE_1_UNKNOWN);
break;
}
if(this->lifetime_value <= this->unk38_31){
__chNipper_setAnimationDuration(this);
break;
}
this->unk38_31++;
break;
case CH_NIPPER_STATE_3_UNKNOWN:
if(actor_animationIsAt(this, 0.5f) && this->marker->unk14_21){
vec3fArray_get_vec3f(this->marker->unk44, 6, particlePosition);
__chNipper_drawParticlesAtPosition(particlePosition, 2);
}
else if(actor_animationIsAt(this, 0.95f) && this->marker->unk14_21){
vec3fArray_get_vec3f(this->marker->unk44, 5, particlePosition);
__chNipper_drawParticlesAtPosition(particlePosition, 2);
}
if(actor_animationIsAt(this, 0.99f)){
this->unk1C[0] += 1.0f;
}
if(2.0f <= this->unk1C[0]){
subaddie_set_state_looped(this, CH_NIPPER_STATE_2_UNKNOWN);
this->unk38_31 = 0;
break;
}
if( actor_animationIsAt(this, 0.5f)
|| actor_animationIsAt(this, 0.95f)
){
for(sp48 = 0; sp48 < 3; sp48++){
sfx_playFadeShorthandDefault(SFX_3D_TICKER_WALKING, 0.75f, 12000, this->position, 1500, 3000);
}
}
break;
case CH_NIPPER_STATE_4_DIEING:
if(actor_animationIsAt(this, 0.99f)){
__chNipper_setAnimationDuration(this);
}
break;
case CH_NIPPER_STATE_5_SPAWNED:
if( actor_animationIsAt(this, 0.2f)
|| actor_animationIsAt(this, 0.2f)
|| actor_animationIsAt(this, 0.6f)
|| actor_animationIsAt(this, 0.7f)
){
sfx_playFadeShorthandDefault(SFX_3D_TICKER_WALKING, 0.75f, 12000, this->position, 0x5dc, 0xbb8);
}
break;
case CH_NIPPER_STATE_6_DEAD:
this->marker->collidable = false;
if(actor_animationIsAt(this, 0.6f)){
sfx_playFadeShorthandDefault(SFX_7C_CHEBOOF, 0.9f, 20000, this->position, 1500, 3000);
break;
}
if(actor_animationIsAt(this, 0.99f)){
subaddie_set_state_with_direction(this, CH_NIPPER_STATE_7_UNKNOWN, 0.01f, 1);
}
break;
case CH_NIPPER_STATE_7_UNKNOWN:
this->marker->collidable = false;
break;
}
}
bool chNipper_isInState7(s16 arg0[3]){
f32 sp1C[3];
Actor *nipper;
sp1C[0] = (f32) arg0[0];
sp1C[1] = (f32) arg0[1];
sp1C[2] = (f32) arg0[2];
nipper = actorArray_findClosestActorFromActorId(sp1C, ACTOR_117_NIPPER, -1, NULL);
return nipper->state == CH_NIPPER_STATE_7_UNKNOWN;
}