fae0beef创建于 7月26日历史提交
#include <ultra64.h>
#include "functions.h"
#include "variables.h"

#include "port/Patches/Patches.h"

extern void particleEmitter_func_802EFA20(ParticleEmitter *, f32, f32);
extern void subaddie_set_state_with_direction(Actor *, s32, f32, s32);
extern void subaddie_turnToYaw(Actor *, f32);


typedef struct {
    ActorMarker *unk0;
    f32 unk4;
    u8 pad8[0x1];
    u8 unk9;
    u8 unkA;
    u8 unkB;
} ActorLocal_chSirSlush;

Actor *chSnowman_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx); //chSirSlush_draw
void chSnowman_update(Actor *this); //chSirSlush_update

/* .data */
ActorAnimationInfo chSnowmanAnimations[] = {
    {0, 0.0f},
    {ASSET_108_ANIM_SIR_SLUSH_IDLE,   0.8f},
    {ASSET_109_ANIM_SIR_SLUSH_ATTACK, 4.0f},
    {ASSET_220_ANIM_SIR_SLUSH_DIE,    1.6f}
};

enum chsnowman_state_e{
    CHSNOWMAN_STATE_1_IDLE = 1,
    CHSNOWMAN_STATE_2_ATTACK,
    CHSNOWMAN_STATE_3_DIE
};

ActorInfo chSnowman = { 
    MARKER_B1_SIR_SLUSH, ACTOR_124_SIR_SLUSH, ASSET_377_MODEL_SIR_SLUSH,
    CHSNOWMAN_STATE_1_IDLE, chSnowmanAnimations,
    chSnowman_update, actor_update_func_80326224, chSnowman_draw,
    0, 0x199, 0.0f, 0
};

/* .code */
Actor *chSnowman_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx){
    Actor *actor;
    ActorLocal_chSirSlush *local;

    actor = marker_getActor(marker);
    local = (ActorLocal_chSirSlush *)&actor->local;
    modelRender_setAppendageVisibility(1, local->unk9);
    modelRender_setAppendageVisibility(2, local->unkA);
    return actor_draw(marker, gfx, mtx, vtx);
}

void __chSnowman_spawnSnowball(ActorMarker *marker){
    Actor *actor;
    Actor *other;
    f32 player_position[3];
    ActorMarker *m = *(ActorMarker **)&marker;

    actor = marker_getActor(m);
    other = spawn_child_actor(ACTOR_125_SNOWBALL, &actor);
    if(m->unk14_21){
        vec3fArray_get_vec3f(m->unk44, 5, player_position);
    }
    else{
        player_position[0] = actor->position[0];
        player_position[1] = actor->position[1];
        player_position[2] = actor->position[2];
        player_position[1] += 150.0f;
    }
    other->position[0] = player_position[0];
    other->position[1] = player_position[1];
    other->position[2] = player_position[2];
}

void __chSnowman_spawnHat(ActorMarker *marker){
    Actor *actor;
    Actor *other;
    f32 sp2C[3];
    s32 sp28;
    ActorMarker *m = *(ActorMarker **)&marker;

    actor = marker_getActor(m);
    other = spawn_child_actor(ACTOR_126_SIR_SLUSH_HAT, &actor);

    vec3fArray_get_vec3f(m->unk44, 6, sp2C);

    other->position[0] = sp2C[0];
    other->position[1] = sp2C[1];
    other->position[2] = sp2C[2];
    

    other->yaw = actor->yaw + 180.0f;
    other->velocity[0] = other->velocity[1] = other->velocity[2] = 0.0f;

    other->velocity[0] = 34.0f;

    sp28 = (globalTimer_getTime() & 1)? 0x3C : 0x78;
    ml_vec3f_yaw_rotate_copy(other->velocity, other->velocity, other->yaw - sp28);
    other->velocity[1] = 30.0f;
}

void __chSnowman_spawnSnowballParticles(f32 position[3], s32 count){
    static ParticleScaleAndLifetimeRanges D_80368694 = {
        {0.4f, 1.55f},
        {0.0f, 0.0f},
        {0.0f, 0.01f},
        {4.0f, 4.0f},
        0.0f, 0.3f
    };
    static ParticleSettingsVelocityAccelerationPosition D_803686BC = {
        {{-250.0f, 600.0f, -250.0f}, {350.0f, 960.0f, 350.0f}},
        {{0.0f, -1200.0f, 0.0f}, {0.0f, -1200.0f, 0.0f}},
        {{-80.0f, 0.0f, -80.0f}, {80.0f, 200.0f, 80.0f}}
    };

    ParticleEmitter *particleSpawner = partEmitMgr_newEmitter(count);

    particleEmitter_setModel(particleSpawner, ASSET_378_MODEL_SNOWBALL);
    particleEmitter_setPosition(particleSpawner, position);
    particleEmitter_setVelocityAccelerationAndPositionRanges(particleSpawner, &D_803686BC);
    particleEmitter_setAngularVelocityRange(particleSpawner, -600.0f, -600.0f, -600.0f, 600.0f, 600.0f, 600.0f);
    particleEmitter_func_802EF9F8(particleSpawner, 0.01f);
    particleEmitter_func_802EFA18(particleSpawner, 3);
    particleEmitter_func_802EFA20(particleSpawner, 1.0f, 1.3f);
    particleEmitter_setSfx(particleSpawner, SFX_2F_ORANGE_SPLAT, 16000);
    particleEmitter_setScaleAndLifetimeRanges(particleSpawner, &D_80368694);
    particleEmitter_emitN(particleSpawner, count);
}

void __chSnowman_enterIdle(Actor *this){
    ActorLocal_chSirSlush *local = (ActorLocal_chSirSlush *) &this->local;
    subaddie_set_state_with_direction(this, CHSNOWMAN_STATE_1_IDLE, 0.01f, 1);
    actor_loopAnimation(this);
    local->unk4 = 0.4f;
}

void __chSnowman_enterDeath(Actor *this){
    subaddie_set_state_with_direction(this, CHSNOWMAN_STATE_3_DIE, 0.01f, 1);
    actor_playAnimationOnce(this);
}

void __chSnowman_setYawTarget(Actor *this, f32 max_rotation){
    this->yaw_ideal = subaddie_getYawToPlayer(this);
    subaddie_turnToYaw(this, 6.0f);
}

bool __chSnowman_isYawNearYawTarget(Actor *this, s32 max_angle_degree){
    f32 dYaw;
    dYaw = this->yaw - this->yaw_ideal;
    if((dYaw < max_angle_degree) && (-max_angle_degree < dYaw)){
        return true;
    }
    return false;
}

int __chSnowman_isPlayerInAttackRange(Actor *this, s32 min_distance, s32 max_distance){
    f32 player_position[3];
    if(this->actorTypeSpecificField == 0x33){
        player_getPosition(player_position);
        if( (this->position[1] + 500.0f < player_position[1]) || (player_position[1] < this->position[1] - 500.0f))
            return 0;
    }//L802E1F28
    if(subaddie_playerIsWithinSphereAndActive(this, max_distance) && !subaddie_playerIsWithinSphereAndActive(this, min_distance)){
        return 1;
    }
    return 0;
}

int __chSnowman_func_802E1F70(ActorMarker *marker, s32 arg1){
    if(marker->unk40_31 == 0xB){
        marker->id = 0x287;
    }
    else{
        marker->id = MARKER_B1_SIR_SLUSH;
    }
    return true;
}

void __chSnowman_deathCallback(ActorMarker *marker, ActorMarker *other_marker){
    Actor *actor = marker_getActor(marker);
    sfx_playFadeShorthandDefault(SFX_15_METALLIC_HIT_2, 1.0f, 30000, actor->position, 1500, 4500);
    sfx_playFadeShorthandDefault(SFX_3EA_BANJO_GUH_HUH, 1.0f, 30000, actor->position, 1500, 4500);
    sfx_playFadeShorthandDefault(SFX_2F_ORANGE_SPLAT, 1.0f, 30000, actor->position, 1500, 4500);

    __spawnQueue_add_1((GenFunction_1)__chSnowman_spawnHat, (uintptr_t)actor->marker);
    if(gsworld_getMap() == MAP_27_FP_FREEZEEZY_PEAK){
        maSnowy_decRemaining();
        port_puzzlePos_mark(ANCHOR_PUZZLE_FP_SLUSHES, (s32)actor->position[0], (s32)actor->position[1],
                            (s32)actor->position[2]);
    }
    __chSnowman_spawnSnowballParticles(actor->position, 0xC);
    marker_despawn(actor->marker);
}

int __chSnowman_CCW_playerInProtectedZone(void){
    static f32 ccw_no_attack_zone[3] = {350.0f, 600.0f, 65.0f};
    f32 player_position[3];
    if(gsworld_getMap() == MAP_46_CCW_WINTER){
        player_getPosition(player_position);
        if(ml_vec3f_within_horizontal_distance(player_position, ccw_no_attack_zone, 900.0f))
            return 1;
    }
    return 0;
}

void chSnowman_update(Actor *this){
    ActorLocal_chSirSlush *local = (ActorLocal_chSirSlush *) &this->local;
    f32 dt;


    dt = time_getDelta();
    if(!this->volatile_initialized){
        this->volatile_initialized = true;
        this->marker->propPtr->unk8_3 = 0;
        actor_collisionOn(this);
        marker_setCollisionScripts(this->marker, NULL, NULL, __chSnowman_deathCallback);
        func_803300C0(this->marker, (s32 (*)(ActorMarker *, ActorMarker *))__chSnowman_func_802E1F70);
        local->unk9 = 0;
        local->unkA = 1;
        local->unkB = 0;
        local->unk4 = 0.0f;
        anctrl_setTransitionDuration(this->anctrl, 0.8f);
        anctrl_setAnimTimer(this->anctrl, randf());
        func_8032BC18(this);
        if(gsworld_getMap() == MAP_27_FP_FREEZEEZY_PEAK){
            local->unk0 = actorArray_findActorFromActorId(0x336)->marker;
            maSnowy_incTotal();
            if(port_puzzlePos_isMarked(ANCHOR_PUZZLE_FP_SLUSHES, (s32)this->position[0],
                                       (s32)this->position[1], (s32)this->position[2])){
                maSnowy_decRemaining();
                marker_despawn(this->marker);
                return;
            }
        }
    }//L802E21D8
    if(gsworld_getMap() == MAP_27_FP_FREEZEEZY_PEAK && !this->despawn_flag
       && port_puzzlePos_isMarked(ANCHOR_PUZZLE_FP_SLUSHES, (s32)this->position[0],
                                  (s32)this->position[1], (s32)this->position[2])){
        __chSnowman_deathCallback(this->marker, NULL);
        return;
    }
    if(gsworld_getMap() == MAP_27_FP_FREEZEEZY_PEAK){
        if(maSlalom_isActive() || func_8038DD14()){
            actor_collisionOff(this);
            this->unk58_0 = 0;
            return;
        }
        else{//L802E2224
            actor_collisionOn(this);
            this->unk58_0 = 1;

        }
    }//L802E223C
    if(!subaddie_playerIsWithinSphere(this, 4000))
        return;

    if(!local->unkB && this->marker->unk14_21){
        local->unkB = 1;
    }//L802E2280
    switch(this->state){
        case CHSNOWMAN_STATE_1_IDLE://L802E22B0
            local->unk9 = false;
            local->unkA = 1;
            __chSnowman_setYawTarget(this, 6.0f);
            if(!subaddie_playerIsWithinSphereAndActive(this, 3150)){
                __chSnowman_enterDeath(this);
            }
            else if( 
                gsworld_getMap() != MAP_27_FP_FREEZEEZY_PEAK
                || preventSnowmanAttack(local->unk0) == 0
                || fileProgressFlag_get(FILEPROG_13_COMPLETED_TWINKLIES_MINIGAME)
            ){//L802E2318
                if(0.0 < local->unk4){
                    if( (globalTimer_getTime() & 1)
                        || player_movementGroup() == BSGROUP_A_FLYING
                    ){//L802E236C
                        local->unk4 -= dt;
                    }
                }
                else{//L802E2380
                    if( __chSnowman_isPlayerInAttackRange(this, 500, 2750)
                        && __chSnowman_isYawNearYawTarget(this, 3)
                        && player_getWaterState() != BSWATERGROUP_2_UNDERWATER
                        && !__chSnowman_CCW_playerInProtectedZone()
                    ){
                        subaddie_set_state_with_direction(this, CHSNOWMAN_STATE_2_ATTACK, 0.01f, 1);
                        actor_playAnimationOnce(this);
                    }
                }
            }
            break;
        case CHSNOWMAN_STATE_2_ATTACK://L802E23E8
            if(!subaddie_playerIsWithinSphereAndActive(this, 3150)){
                __chSnowman_enterDeath(this);
            }//L802E240C
            else if( 
                0.98 < anctrl_getAnimTimer(this->anctrl)
                || !__chSnowman_isPlayerInAttackRange(this, 500, 2750)
                || player_getWaterState() == BSWATERGROUP_2_UNDERWATER
                || __chSnowman_CCW_playerInProtectedZone()
            ){
                __chSnowman_enterIdle(this);
            }
            else{
                if(anctrl_getAnimTimer(this->anctrl) < 0.45){
                    __chSnowman_setYawTarget(this, 6.0f);
                }
                if( actor_animationIsAt(this, 0.19f)
                    || actor_animationIsAt(this, 0.28f)
                    || actor_animationIsAt(this, 0.37f)
                ){
                    sfx_playFadeShorthandDefault(SFX_A7_WOODEN_SWOSH, 1.3f, 18000, this->position, 800, 3050);
                }//L802E24FC
                if(actor_animationIsAt(this, 0.15f)){
                    func_8030E878(SFX_3F5_UNKNOWN, randf2(1.35f, 1.5f),32000, this->position, 800.0f, 3050.0f);
                }//L802E2558

                if(actor_animationIsAt(this, 0.45f)){
                    local->unk9 = true;
                }
                else if(
                    actor_animationIsAt(this, 0.58f)
                    && local->unkB
                ){
                    func_8030E878(SFX_8F_SNOWBALL_FLYING, randf2(0.95f, 1.05f), 30000, this->position, 800.0f, 3050.0f);
                    __spawnQueue_add_1((GenFunction_1)__chSnowman_spawnSnowball, (uintptr_t)this->marker);
                    local->unk9 = false;
                }
                
            }
            break;
        case CHSNOWMAN_STATE_3_DIE://L802E2604
            if(subaddie_playerIsWithinSphereAndActive(this, 3150)){
                __chSnowman_enterIdle(this);
            }
            break;
    }
}