/**
 * d_a_obj_drift.cpp
 * Object - Floating tree platform
 */

#include "d/dolzel_rel.h" // IWYU pragma: keep
#include "d/actor/d_a_obj_drift.h"
#include "d/actor/d_a_player.h"
#include "res/Object/Kryu.h"
 
namespace daObjDrift {
    namespace {
        struct Attr_c {
            /* 0x00 */ f32 mWaveHeight;
            /* 0x04 */ f32 mWaveSpeed;
            /* 0x08 */ f32 mWavePhase;
            /* 0x0C */ f32 mWaveAmplitude;
            /* 0x10 */ f32 mRideYOff;
            /* 0x14 */ s16 mWavePhaseXStep;
            /* 0x16 */ s16 field_0x16;
            /* 0x18 */ f32 mWaveSinScale;
            /* 0x1C */ f32 field_0x1C;
            /* 0x20 */ f32 mTiltChaseWait;
            /* 0x24 */ f32 mTiltChaseRot;
            /* 0x28 */ f32 mPosMoveDamp;
            /* 0x2C */ s16 mWavePhaseYStep;
            /* 0x2E */ s16 mWavePhaseZStep;
            /* 0x30 */ f32 mTiltSinScale;
            /* 0x34 */ f32 field_0x34;
            /* 0x38 */ s16 field_0x38;
            /* 0x3A */ s16 field_0x3A;
            /* 0x3C */ s16 mRotTimerMax;
            /* 0x3E */ s16 field_0x3E;
        };

        static const Attr_c L_attr = {
            /* mWaveHeight     */ 500.0f,
            /* mWaveSpeed      */ 0.04f,
            /* mWavePhase      */ 0.01f,
            /* mWaveAmplitude  */ 0.02f,
            /* mRideYOff       */ -20.0f,
            /* mWavePhaseXStep */ 400,
            /* field_0x16      */ 0,
            /* mWaveSinScale   */ 0.3f,
            /* field_0x1C      */ 0.12f,
            /* mTiltChaseWait  */ 0.8f,
            /* mTiltChaseRot   */ 0.5f,
            /* mPosMoveDamp    */ 0.07f,
            /* mWavePhaseYStep */ 1000,
            /* mWavePhaseZStep */ 1111,
            /* mTiltSinScale   */ 0.01f,
            /* field_0x34      */ 0.5f,
            /* field_0x38      */ 30,
            /* field_0x3A      */ 30,
            /* mRotTimerMax    */ 10,
            /* field_0x3E      */ 0,
        };
        
        inline const Attr_c& attr() { return L_attr; }
    } // namespace
} // namespace daObjDrift

const char daObjDrift::Act_c::M_arcname[] = "Kryu";

const dCcD_SrcCyl daObjDrift::Act_c::M_cyl_src = {
    {
        /* Flags             */ 0,
        /* SrcObjAt  Type    */ 0,
        /* SrcObjAt  Atp     */ 0,
        /* SrcObjAt  SPrm    */ 0,
        /* SrcObjTg  Type    */ AT_TYPE_WIND,
        /* SrcObjTg  SPrm    */ cCcD_TgSPrm_Set_e | cCcD_TgSPrm_IsOther_e,
        /* SrcObjCo  SPrm    */ 0,
        /* SrcGObjAt Se      */ 0,
        /* SrcGObjAt HitMark */ 0,
        /* SrcGObjAt Spl     */ 0,
        /* SrcGObjAt Mtrl    */ 0,
        /* SrcGObjAt SPrm    */ 0,
        /* SrcGObjTg Se      */ 0,
        /* SrcGObjTg HitMark */ 0,
        /* SrcGObjTg Spl     */ 0,
        /* SrcGObjTg Mtrl    */ 0,
        /* SrcGObjTg SPrm    */ 0,
        /* SrcGObjCo SPrm    */ 0,
    },
    {{
        /* Center */ {0.0f, 0.0f, 0.0f},
        /* Radius */ 300.0f,
        /* Height */ 600.0f,
    }},
};

/* 000000EC-000001A0       .text CreateHeap__Q210daObjDrift5Act_cFv */
BOOL daObjDrift::Act_c::CreateHeap() {
    J3DModelData* model_data = (J3DModelData*)dComIfG_getObjectRes(M_arcname, dRes_INDEX_KRYU_BDL_RYU_00_e);
    JUT_ASSERT(314, model_data != NULL);
    mModel = mDoExt_J3DModel__create(model_data, 0x80000, 0x11000022);
    return mModel != NULL;
}

/* 000001A0-00000370       .text Create__Q210daObjDrift5Act_cFv */
BOOL daObjDrift::Act_c::Create() {
    fopAcM_SetMtx(this, mModel->getBaseTRMtx());
    init_mtx();

    fopAcM_setCullSizeBox(this, -550.0f, -180.0f, -550.0f, 550.0f, 605.0f, 550.0f);
    mStts.Init(0xFF, 0xFF, this);
    mCyl.Set(M_cyl_src);
    mCyl.SetStts(&mStts);
    mCyl.SetTgVec((cXyz&)cXyz::Zero);
    mCyl.OnTgNoHitMark();

    make_flower();
    mpBgW->SetRideCallback(rideCB);
    mode_wait_init();
    f32 waterY;
    if (fopAcM_getWaterY(&home.pos, &waterY)) {
        eyePos.y = waterY;
    }

    mRideYOff = 0.0f;
    mTiltTargetZ = 0.0f;
    mTiltTargetX = 0.0f;
    mTiltVelZ = 0.0f;
    mTiltVelX = 0.0f;
    mTiltZ = 0.0f;
    mTiltX = 0.0f;

    mWavePhaseX = cM_rndFX(0x8000);
    mWavePhaseY = cM_rndFX(0x8000);
    mWavePhaseZ = cM_rndFX(0x8000);
    mRideFlag = FALSE;

    mTargetAngleY = 0;
    mAngleChaseY = 0;

    mHitDir.set(cXyz::Zero);
    field_0x4B0.setall(5.0f);
    mPrevPos.set(current.pos);
    f32 prevY = mPrevPos.y;
    field_0x4C8 = prevY;
    field_0x4CC = prevY;

    field_0x4D0 = 0.0f;
    field_0x4D4 = 0.0f;

    return TRUE;
}

/* 00000370-0000050C       .text Mthd_Create__Q210daObjDrift5Act_cFv */
cPhs_State daObjDrift::Act_c::Mthd_Create() {
    fopAcM_ct(this, Act_c);

    cPhs_State phase_state = dComIfG_resLoad(&mPhase, M_arcname);
    if (phase_state == cPhs_COMPLEATE_e) {
        mType = prm_get_type();

        phase_state = MoveBGCreate(
            M_arcname,
            dRes_INDEX_KRYU_DZB_RYU_00_e,
            dBgS_MoveBGProc_TypicalRotY,
            DEMO_SELECT(0x8000, 0x1B80)
        );
        JUT_ASSERT(411, (phase_state == cPhs_COMPLEATE_e) || (phase_state == cPhs_ERROR_e));
    }
    return phase_state;
}

/* 0000075C-000007EC       .text make_flower__Q210daObjDrift5Act_cFv */
void daObjDrift::Act_c::make_flower() {
    if (mType >= 0 && mType <= 1) {
        cXyz pos;
        csXyz angle;
        calc_flower_param(&pos, &angle);
        static const s16 pf_name[2] = {fpcNm_JBO_e, fpcNm_BO_e};
        mFlowerPid = fopAcM_create(
            pf_name[mType],
            0,
            &pos,
            fopAcM_GetHomeRoomNo(this),
            &angle
        );
    } else {
        mFlowerPid = fpcM_ERROR_PROCESS_ID_e;
    }
}

/* 000007EC-00000890       .text calc_flower_param__Q210daObjDrift5Act_cFP4cXyzP5csXyz */
void daObjDrift::Act_c::calc_flower_param(cXyz* i_pos, csXyz* i_angle) {
    static cXyz offset_vec(-489.35f, 600.0f, 0.0f);

    mDoMtx_multVec(mMtx, &offset_vec, i_pos);
    mDoMtx_MtxToRot(mMtx, i_angle);
}

/* 00000890-00000954       .text set_flower_current__Q210daObjDrift5Act_cFv */
void daObjDrift::Act_c::set_flower_current() {
    if (mFlowerPid == fpcM_ERROR_PROCESS_ID_e) {
        return;
    }

    fopAc_ac_c* flower = fopAcM_SearchByID(mFlowerPid);
    if (flower != NULL) {
        cXyz pos;
        csXyz angle;
        calc_flower_param(&pos, &angle);
        flower->current.pos = pos;
        if (mType == 0) {
            flower->shape_angle = angle;
        } else {
            flower->current.angle = angle;
        }
    }
}

/* 00000954-0000095C       .text Delete__Q210daObjDrift5Act_cFv */
BOOL daObjDrift::Act_c::Delete() {
    return TRUE;
}

/* 0000095C-000009A8       .text Mthd_Delete__Q210daObjDrift5Act_cFv */
BOOL daObjDrift::Act_c::Mthd_Delete() {
    BOOL ret = MoveBGDelete();
    dComIfG_resDeleteDemo(&mPhase, M_arcname);
    return ret;
}

/* 000009A8-000009C0       .text mode_wait_init__Q210daObjDrift5Act_cFv */
void daObjDrift::Act_c::mode_wait_init() {
    fopAcM_OnStatus(this, fopAcStts_NOCULLEXEC_e);
    mMode = MODE_WAIT;
}

/* 000009C0-00000A80       .text mode_wait__Q210daObjDrift5Act_cFv */
void daObjDrift::Act_c::mode_wait() {
    if (mCyl.ChkTgHit()) {
        mCyl.ClrTgHit();
        if (fopAcM_searchPlayerDistanceXZ2(this) > 302500.0f) {
            cXyz* l_tgrVec = mCyl.GetTgRVecP();
            mHitDir.set(*l_tgrVec);
            mHitDir.normalizeZP();
            mode_rot_init();
        }
    } else {
        mCyl.MoveCAtTg(current.pos);
        dComIfG_Ccsp()->Set(&mCyl);
    }
}

/* 00000A80-00000B38       .text mode_rot_init__Q210daObjDrift5Act_cFv */
void daObjDrift::Act_c::mode_rot_init() {
    fopAcM_OffStatus(this, fopAcStts_NOCULLEXEC_e);
    mTargetAngleY = shape_angle.y + 0x8000;
    mAngleChaseY = 0;
    shape_angle.y += 10;
    mRotTimer = 0.0f;
    mMode = MODE_ROT;
    fopAcM_seStart(this, JA_SE_OBJ_RYUBOKU_MOVE, 0);
}

/* 00000B38-00000C3C       .text mode_rot__Q210daObjDrift5Act_cFv */
void daObjDrift::Act_c::mode_rot() {
    s16 yDiff = mTargetAngleY - shape_angle.y;
    if (yDiff <= 0) {
        shape_angle.y = mTargetAngleY;
        mHitDir.set(cXyz::Zero);
        mode_wait_init();
    } else {
        if (yDiff < 0x2000) {
            cLib_chaseS(&mAngleChaseY, 0x14, 0xA);
        } else {
            cLib_chaseS(&mAngleChaseY, 0x190, 0x14);
        }
        shape_angle.y += mAngleChaseY;
    }

    if (mRotTimer >= attr().mRotTimerMax) {
        mRotTimer = 0.0f;
        field_0x4D0 = 1.0f;
    } else {
        mRotTimer += 1.0f;
    }
}

/* 00000C3C-00000D18       .text set_mtx__Q210daObjDrift5Act_cFv */
void daObjDrift::Act_c::set_mtx() {
    mDoMtx_stack_c::transS(current.pos);
    Quaternion quat;
    cXyz axis(mTiltX, 1.0f, mTiltZ);
    daObj::quat_rotBaseY2(&quat, axis);
    mDoMtx_stack_c::quatM(&quat);
    mDoMtx_stack_c::ZXYrotM(shape_angle);
    mModel->setBaseTRMtx(mDoMtx_stack_c::get());
    cMtx_copy(mDoMtx_stack_c::get(), mMtx);
    field_0x4CC = field_0x4C8;
    field_0x4C8 = mPrevPos.y;
    mDoMtx_multVecZero(mDoMtx_stack_c::get(), &mPrevPos);
}

/* 00000D18-00000D54       .text init_mtx__Q210daObjDrift5Act_cFv */
void daObjDrift::Act_c::init_mtx() {
    mModel->setBaseScale(scale);
    set_mtx();
}

/* 00000D54-00000EC4       .text rideCB__Q210daObjDrift5Act_cFP4dBgWP10fopAc_ac_cP10fopAc_ac_c */
void daObjDrift::Act_c::rideCB(dBgW*, fopAc_ac_c* i_this, fopAc_ac_c* i_ride) {
    Act_c* drift = (Act_c*)i_this;
    if (fopAcM_GetProfName(i_ride) != fpcNm_PLAYER_e) {
        return;
    }
    daPy_py_c* player = (daPy_py_c*)i_ride;

    f32 ratio = 1.0f / attr().mWaveHeight;
    drift->mRideYOff = attr().mRideYOff;
    cXyz delta = player->current.pos - drift->current.pos;
    Mtx invMtx;
    if (MTXInverse(drift->mMtx, invMtx) && !dComIfGp_checkPlayerStatus0(0, daPyStts0_HANG_e)) {
        cXyz localDelta;
        mDoMtx_multVecSR(invMtx, &delta, &localDelta);
        f32 sqMag = localDelta.abs2XZ();
        if (localDelta.y < 400.0f) {
            if (sqMag < SQUARE(360.0f)) {
                drift->mRideFlag = TRUE;
            }
        } else if (localDelta.y < 550.0f) {
            if (sqMag < SQUARE(220.0f)) {
                drift->mRideFlag = TRUE;
            }
        }
    } else {
        drift->mRideFlag = TRUE;
    }
    if (drift->mRideFlag == FALSE) {
        drift->mTiltTargetZ = delta.z * (ratio * attr().field_0x1C);
        drift->mTiltTargetX = delta.x * (ratio * attr().field_0x1C);
    }
}

/* 00000EC4-00001104       .text set_current__Q210daObjDrift5Act_cFv */
void daObjDrift::Act_c::set_current() {
    f32 y = mRideYOff + home.pos.y;
    mWavePhaseX += attr().mWavePhaseXStep;
    f32 sinVal = cM_ssin(mWavePhaseX);
    f32 yDelta = y - current.pos.y;
    gravity = yDelta * attr().mWaveAmplitude
            + sinVal * attr().mWaveSinScale;
    daObj::posMoveF_stream(this, NULL, &cXyz::Zero, attr().mWaveSpeed, attr().mWavePhase);
    f32 rotFactor = mRideFlag != 0 ? 0.2f : 1.0f;
    f32 chaseFactor;
    if (mMode == MODE_ROT) {
        chaseFactor = attr().mTiltChaseRot;
    } else {
        chaseFactor = attr().mTiltChaseWait;
    }
    mHitDir *= 0.95f;
    mWavePhaseY += attr().mWavePhaseYStep;
    mWavePhaseZ += attr().mWavePhaseZStep;
    f32 diffZ = mTiltZ - mTiltTargetZ;
    f32 diffX = mTiltX - mTiltTargetX;
    f32 sinY = cM_ssin(mWavePhaseY);
    f32 z_val = mHitDir.z * attr().field_0x34
            + (rotFactor * (sinY * attr().mTiltSinScale)
            - diffZ * chaseFactor);
    f32 sinZ = cM_ssin(mWavePhaseZ);
    f32 x_val = mHitDir.x * attr().field_0x34
        + (rotFactor * (sinZ * attr().mTiltSinScale)
        - diffX * chaseFactor);
    mTiltVelZ += z_val;
    mTiltVelX += x_val;
    mTiltVelZ *= attr().mPosMoveDamp;
    mTiltVelX *= attr().mPosMoveDamp;
    mTiltZ += mTiltVelZ;
    mTiltX += mTiltVelX;
    mRideYOff = 0.0f;
    mTiltTargetZ = 0.0f;
    mTiltTargetX = 0.0f;
    mRideFlag = FALSE;
}

/* 00001104-000011D0       .text Execute__Q210daObjDrift5Act_cFPPA3_A4_f */
BOOL daObjDrift::Act_c::Execute(Mtx** mtx) {
    typedef void (daObjDrift::Act_c::*procFunc)();
    static procFunc mode_proc[] = {
        &daObjDrift::Act_c::mode_wait,
        &daObjDrift::Act_c::mode_rot,
    };
    (this->*mode_proc[mMode])();

    set_current();
    set_mtx();
    *mtx = &mMtx;
    set_flower_current();
    return TRUE;
}

/* 000011D0-00001270       .text Draw__Q210daObjDrift5Act_cFv */
BOOL daObjDrift::Act_c::Draw() {
    g_env_light.settingTevStruct(TEV_TYPE_BG0, &current.pos, &tevStr);
    g_env_light.setLightTevColorType(mModel, &tevStr);
    dComIfGd_setListBG();
    mDoExt_modelUpdateDL(mModel);
    dComIfGd_setList();
    return TRUE;
}

namespace daObjDrift {
namespace {
/* 00001270-00001290       .text Mthd_Create__Q210daObjDrift27@unnamed@d_a_obj_drift_cpp@FPv */
cPhs_State Mthd_Create(void* i_this) {
    return ((daObjDrift::Act_c*)i_this)->Mthd_Create();
}

/* 00001290-000012B0       .text Mthd_Delete__Q210daObjDrift27@unnamed@d_a_obj_drift_cpp@FPv */
BOOL Mthd_Delete(void* i_this) {
    return ((daObjDrift::Act_c*)i_this)->Mthd_Delete();
}

/* 000012B0-000012D0       .text Mthd_Execute__Q210daObjDrift27@unnamed@d_a_obj_drift_cpp@FPv */
BOOL Mthd_Execute(void* i_this) {
    return ((daObjDrift::Act_c*)i_this)->MoveBGExecute();
}

/* 000012D0-000012FC       .text Mthd_Draw__Q210daObjDrift27@unnamed@d_a_obj_drift_cpp@FPv */
BOOL Mthd_Draw(void* i_this) {
    return ((daObjDrift::Act_c*)i_this)->MoveBGDraw();
}

/* 000012FC-00001328       .text Mthd_IsDelete__Q210daObjDrift27@unnamed@d_a_obj_drift_cpp@FPv */
BOOL Mthd_IsDelete(void* i_this) {
    return ((daObjDrift::Act_c*)i_this)->MoveBGIsDelete();
}

static actor_method_class Mthd_Table = {
    (process_method_func)Mthd_Create,
    (process_method_func)Mthd_Delete,
    (process_method_func)Mthd_Execute,
    (process_method_func)Mthd_IsDelete,
    (process_method_func)Mthd_Draw,
};
}; // namespace
}; // namespace daObjDrift

actor_process_profile_definition g_profile_Obj_Drift = {
    /* Layer ID     */ fpcLy_CURRENT_e,
    /* List ID      */ 0x0002,
    /* List Prio    */ fpcPi_CURRENT_e,
    /* Proc Name    */ fpcNm_Obj_Drift_e,
    /* Proc SubMtd  */ &g_fpcLf_Method.base,
    /* Size         */ sizeof(daObjDrift::Act_c),
    /* Size Other   */ 0,
    /* Parameters   */ 0,
    /* Leaf SubMtd  */ &g_fopAc_Method.base,
    /* Draw Prio    */ fpcDwPi_Obj_Drift_e,
    /* Actor SubMtd */ &daObjDrift::Mthd_Table,
    /* Status       */ fopAcStts_NOCULLEXEC_e | fopAcStts_CULL_e | fopAcStts_UNK40000_e,
    /* Group        */ fopAc_ACTOR_e,
    /* Cull Type    */ fopAc_CULLBOX_CUSTOM_e,
};
