#include "d/a/obj/d_a_obj_rope_igaiga.h"

#include "c/c_lib.h"
#include "c/c_math.h"
#include "common.h"
#include "d/a/d_a_base.h"
#include "d/a/d_a_player.h"
#include "d/a/obj/d_a_obj_base.h"
#include "d/a/obj/d_a_obj_ivy_rope.h"
#include "d/col/bg/d_bg_s.h"
#include "d/col/bg/d_bg_s_wtr_chk.h"
#include "d/col/c/c_cc_d.h"
#include "d/col/cc/d_cc_s.h"
#include "d/d_vec.h"
#include "d/flag/sceneflag_manager.h"
#include "d/snd/d_snd_wzsound.h"
#include "f/f_base.h"
#include "f/f_profile_name.h"
#include "m/m_vec.h"
#include "nw4r/g3d/res/g3d_resfile.h"
#include "nw4r/g3d/res/g3d_resmdl.h"
#include "nw4r/math/math_arithmetic.h"
#include "nw4r/ut/ut_Color.h"
#include "rvl/GX/GXTypes.h"
#include "s/s_Math.h"
#include "toBeSorted/d_emitter.h"

SPECIAL_ACTOR_PROFILE(OBJ_ROPE_IGAIGA, dAcOropeIgaiga_c, fProfile::OBJ_ROPE_IGAIGA, 0x265, 0, 2);

STATE_DEFINE(dAcOropeIgaiga_c, Init);
STATE_DEFINE(dAcOropeIgaiga_c, Rope);
STATE_DEFINE(dAcOropeIgaiga_c, Ground);
STATE_DEFINE(dAcOropeIgaiga_c, Tree);
STATE_DEFINE(dAcOropeIgaiga_c, Stick);
STATE_DEFINE(dAcOropeIgaiga_c, Water);

dCcD_SrcSph dAcOropeIgaiga_c::sSphSrc = {
    /* mObjInf */
    {/* mObjAt */ {AT_TYPE_DAMAGE, 0x1F, {0, 0, 0}, 1, 0, 0, 0, 0, 0},
     /* mObjTg */
     {~(AT_TYPE_WIND | AT_TYPE_0x8000 | AT_TYPE_GLITTERING_SPORES | AT_TYPE_BEETLE | AT_TYPE_BUGNET), 0x311, {0, 0, 0x407}, 0, 0},
     /* mObjCo */ {0xA9}},
    /* mSphInf */
    {20.f},
};

const s16 dAcOropeIgaiga_c::sRopeTimerMin1 = 0x2D;
const s16 dAcOropeIgaiga_c::sRopeTimerMin2 = 0x3C;
const f32 dAcOropeIgaiga_c::lbl_257_rodata_4[3] = {500.f, 250.f, 50.f};
const s16 dAcOropeIgaiga_c::lbl_257_rodata_10 = 0x96;
const s16 dAcOropeIgaiga_c::lbl_257_rodata_12 = 0x64;
const s16 dAcOropeIgaiga_c::lbl_257_rodata_14 = 0x41;
const s16 dAcOropeIgaiga_c::lbl_257_rodata_16 = 0x41;
const s16 dAcOropeIgaiga_c::lbl_257_rodata_18 = 0x64;
const s16 dAcOropeIgaiga_c::lbl_257_rodata_1A = 0x64;
const s16 dAcOropeIgaiga_c::lbl_257_rodata_1C = 0x4;
const s16 dAcOropeIgaiga_c::lbl_257_rodata_1E = 0x41;
const s16 dAcOropeIgaiga_c::lbl_257_rodata_20 = 0x64;
const f32 dAcOropeIgaiga_c::lbl_257_rodata_28 = 20.f;

bool dAcOropeIgaiga_c::createHeap() {
    void *data = getOarcResFile("NeedleBall");
    if (data == nullptr) {
        return false;
    }
    mResFile = nw4r::g3d::ResFile(data);
    nw4r::g3d::ResMdl mdl = mResFile.GetResMdl("NeedleBall");
    TRY_CREATE(mMdl.create(mdl, &mAllocator, 0x120, 1, nullptr));
    return true;
}

int dAcOropeIgaiga_c::create() {
    mStartStateTree = getFromParams(0, 0xF);
    if (mStartStateTree >= 2) {
        mStartStateTree = 0;
    }
    mSceneflag = getFromParams(4, 0xFF);
    CREATE_ALLOCATOR(dAcOropeIgaiga_c);
    mObjAcch.Set(&mPosition, &mOldPosition, this, 1, &mAcchCir, &mVelocity, nullptr, nullptr);
    mAcchCir.SetWall(20.0f, 20.0f);
    mStts.mRank = 0;
    mCollider.Set(sSphSrc);
    mCollider.SetStts(mStts);
    mCollider.ClrAtSet();
    mAcceleration = 0.0f;
    mMaxSpeed = -100.0f;
    mInitTimer = 5;
    mPnts2Idx = 0xff;
    field_0x91E = -1;
    mYOffsetIdx = 0xff;
    if (mStartStateTree == 1) {
        mStateMgr.changeState(StateID_Tree);
    } else {
        mStateMgr.changeState(StateID_Init);
    }
    mBoundingBox.Set(mVec3_c(-50.0f, -50.0f, -50.0f), mVec3_c(50.0f, 50.0f, 50.0f));
    return SUCCEEDED;
}

int dAcOropeIgaiga_c::doDelete() {
    return SUCCEEDED;
}

int dAcOropeIgaiga_c::actorExecute() {
    mStateMgr.executeState();
    if (field_0x91E >= 0) {
        u8 red = 0;
        if (field_0x91E < 0x3C) {
            if ((field_0x91E / 3 & 1) == 0) {
                red = 0xff;
                if (!mSoundPlayed) {
                    startSound(SE_RopeIga_COUNT);
                    mSoundPlayed = true;
                }
            } else {
                mSoundPlayed = false;
            }
        } else if ((field_0x91E & 4) != 0) {
            red = 0xff;
            if (!mSoundPlayed) {
                startSound(SE_RopeIga_COUNT);
                mSoundPlayed = true;
            }
        } else {
            mSoundPlayed = false;
        }

        mMdl.setTevKColorAll(GX_KCOLOR3, mColor(red, 0, 0, 0xff), false);
    }
    f32 prevYPosition = mPosition.y;
    mPosition.y += 20.0f;
    mCollider.SetC(mPosition);
    dCcS::GetInstance()->Set(&mCollider);
    updateMatrix();
    mMdl.setLocalMtx(mWorldMtx);
    mPosition.y = prevYPosition;
    return SUCCEEDED;
}

int dAcOropeIgaiga_c::draw() {
    drawModelType1(&mMdl);
    return SUCCEEDED;
}

void dAcOropeIgaiga_c::initializeState_Init() {}

void dAcOropeIgaiga_c::executeState_Init() {
    if (mInitTimer != 0) {
        mInitTimer--;
        if (mCollider.ChkCoHit()) {
            dAcOivyRope_c *rope = (dAcOivyRope_c *)mCollider.GetCoActor();
            if (rope != NULL && (rope->mProfileName == fProfile::OBJ_IVY_ROPE) && rope->checkSubtype(1)) {
                mIvyRopeRef.link(rope);
                mInitTimer = 0;
                mPnts2Idx = 0.5f + mPosition.distance(rope->mPosition) * rope->lbl_256_rodata_40;
                mPosition = rope->getPnts2()[mPnts2Idx];
                f32 xzCirclePointFactor = cM::rndF(5.f) + 15.f;
                mPositionOffset.x = 0.f;
                mPositionOffset.y = 0.f;
                mPositionOffset.z = 0.f;
                s16 ang1 = cLib::targetAngleY(rope->getTightRopeEnd(), rope->getTightRopeStart());
                s16 ang2 = cM::rndInt(100) & 1 ? -1 : 1;
                getXZCirclePoint(mPositionOffset, ang1 + ang2 * 0x4000, xzCirclePointFactor);
                f32 positionYOffset = cM::rndFX(15.f);
                mPositionOffset.y += positionYOffset;
                mPosition += mPositionOffset;
                mPositionRelated = mPosition;
            }
        }
    } else if (mPnts2Idx == 255) {
        mStateMgr.changeState(StateID_Ground);
        mVelocityYRelated = 1;
    } else {
        mStateMgr.changeState(StateID_Rope);
    }
}

void dAcOropeIgaiga_c::finalizeState_Init() {
    mCollider.mCo.SetGrp(mCollider.mCo.mSrc.mSPrm & 0x160);
}

void dAcOropeIgaiga_c::initializeState_Rope() {
    mAcceleration = -3.0f;
}

void dAcOropeIgaiga_c::executeState_Rope() {
    if (mRopeTimer != 0) {
        mRopeTimer--;
    } else {
        field_0x922 = 0;
    }
    mVec3_c pos = mPosition;
    bool rope0x1087 = false;
    bool rope0x1002 = false;
    dAcOivyRope_c *rope = mIvyRopeRef.get();
    if (rope != nullptr) {
        rope0x1002 = rope->getField_0x1002();
        rope0x1087 = rope->getField_0x1087();
        if (rope0x1002) {
            pos.y = rope->getPnts2()[mPnts2Idx].y;
            pos.y += mPositionOffset.y;
        } else {
            pos = rope->getPnts2()[mPnts2Idx];
            pos += mPositionOffset;
        }
        pos.y -= 20.f;
    }
    if (rope0x1087) {
        s32 val = fn_257_1CA0();
        if (val > 0) {
            u32 ropeTimerMin = sRopeTimerMin1;
            field_0x922 += val;
            if (val == 2) {
                ropeTimerMin = sRopeTimerMin2;
            }
            if (ropeTimerMin > mRopeTimer) {
                mRopeTimer = ropeTimerMin;
            }

            if (mVelocityYRelated == 0) {
                mVelocityYRelated = val + 1;
                mVelocity.y = 5.f * mVelocityYRelated;
                fn_257_1F20();
            }
        }
    }
    if (mVelocityYRelated > 0) {
        mRotation.x += mRotationXOffset;
        calcVelocity();
        mPosition += mVelocity;
        if (mPosition.y < pos.y) {
            mPosition.y = pos.y;
            mVelocityYRelated -= 1;
            if (mVelocityYRelated != 0) {
                mVelocity.y = 7.f * mVelocityYRelated;
            }
        }
    }
    if (mVelocityYRelated == 0) {
        if (rope0x1002) {
            sLib::addCalc(&mPosition.y, pos.y, 0.5f, 20.f, 3.f);
        } else {
            cLib::addCalcPos(&mPosition, pos, 0.5f, 20.f, 3.f);
        }
    }
    s32 val = fn_257_1D20();
    fn_257_1DF0();
    if (val == 1) {
        mStateMgr.changeState(StateID_Stick);
    } else if (val == 3) {
        mStateMgr.changeState(StateID_Ground);
    } else if (field_0x922 >= 3) {
        mAngle.y = cM::rndInt(0xFFFF);
        mSpeed = 5.f;
        mVelocity.y = 20.f;
        mStateMgr.changeState(StateID_Ground);
    }
}

void dAcOropeIgaiga_c::finalizeState_Rope() {}

void dAcOropeIgaiga_c::initializeState_Ground() {
    mVelocityYRelated = -1;
    mAcceleration = -4.f;
    mStts.SetRank(0);
    fn_257_1F20();
    mGroundTimer = 0x1e;
}

void dAcOropeIgaiga_c::executeState_Ground() {
    if (mGroundTimer != 0) {
        mGroundTimer--;
    }
    s32 a = fn_257_1D20();
    fn_257_1DF0();
    calcVelocity();
    mPosition += mVelocity;
    if (a != 0) {
        if (mVelocityYRelated == 0) {
            fn_257_20F0(5.f, 10.f);
        }
    }
    if (mVelocityYRelated != 0) {
        mObjAcch.CrrPos(*dBgS::GetInstance());
        if (mObjAcch.ChkGndHit()) {
            if (mVelocityYRelated == -1) {
                mVelocityYRelated = 3;
                mSpeed = 3.f;
                s16 angleYOffset = cM::rndInt(0x2aab);
                if (angleYOffset & 1) {
                    angleYOffset = -angleYOffset;
                }
                mAngle.y += angleYOffset;
                if (field_0x922 >= 3 || *mStateMgr.getOldStateID() == StateID_Tree) {
                    fn_257_1FD0();
                }
                startSound(SE_RopeIga_GROUND);
            } else if (mVelocityYRelated > 0) {
                mVelocityYRelated--;
                sLib::chase(&mSpeed, 0.f, 1.f);
            }
            if (mVelocityYRelated > 0) {
                mVelocity.y = 7.f * mVelocityYRelated;
            } else if (mVelocityYRelated == 0) {
                mAcceleration = 0.f;
                mSpeed = 0.f;
            }
        }
    } else if (field_0x91E > 0) {
        mAcceleration = -4.f;
        mObjAcch.CrrPos(*dBgS::GetInstance());
    }
    if (mVelocityYRelated != 0 && !mObjAcch.ChkGndHit()) {
        mRotation.x += mRotationXOffset;
    }
    if (a == 1 && mGroundTimer == 0) {
        mStateMgr.changeState(StateID_Stick);
    }
    if (field_0x91E >= 0) {
        f32 posY = mPosition.y;
        if (fn_257_1FF0(&posY, false)) {
            mPositionRelated = mPosition;
            mPositionRelated.y = posY - 20.f;
            mStateMgr.changeState(StateID_Water);
        }
    }
}

void dAcOropeIgaiga_c::finalizeState_Ground() {}

void dAcOropeIgaiga_c::initializeState_Tree() {
    mAcceleration = 0.0f;
}

void dAcOropeIgaiga_c::executeState_Tree() {
    s32 tmp = fn_257_1D20();
    if (tmp == 1) {
        mStateMgr.changeState(StateID_Stick);
    } else if (tmp == 3 || SceneflagManager::sInstance->checkBoolFlag(mRoomID, mSceneflag)) {
        mStateMgr.changeState(StateID_Ground);
        f32 random = cM::rndF(2.f);
        mGroundTimer = 0;
        mAcceleration = -(3.f + random);
    }
    fn_257_1DF0();
}

void dAcOropeIgaiga_c::finalizeState_Tree() {}

void dAcOropeIgaiga_c::initializeState_Stick() {
    mStts.SetRank(0);
    mStickTimer = 10;
    mVelocity.y = 17.f;
    mAcceleration = -3.f;
    if (dAcPy_c::GetLink()->getCenterTranslation().y > mPosition.y) {
        mLinkHigher = true;
    } else {
        mLinkHigher = false;
    }
    u32 random;
    if (mLinkHigher) {
        random = cM::rndInt(400) + 200;
    } else {
        random = cM::rndInt(600);
    }
    mYOffsetIdx = random / 100;
    if (mYOffsetIdx > 5) {
        mYOffsetIdx = 5;
    }
    field_0x91A = 0;
    mCollider.ClrTgSet();
    f32 rnd = cM::rndF(10.f);
    mVelocity.y = rnd + 3.f;
    if (dAcPy_c::GetLink()->checkActionFlags(0x10000)) {
        s16 rotationYOffset = cM::rndInt(0x31C7) + 0x38E4;
        f32 f1 = (rotationYOffset - 0x38E4) / 12743.f;
        if (f1 > 1.f) {
            f1 = 1.f;
        } else if (f1 < 0.f) {
            f1 = 0.f;
        }
        f32 f2 = cM::rndF(3.f) + 15.f;
        mRadius = 15.f * f1 + f2;
        if ((mYOffsetIdx & 1) == 0) {
            rotationYOffset = -rotationYOffset;
        }
        mRotationYOffset = rotationYOffset;
    } else {
        if (mYOffsetIdx >= 4) {
            mRadius = cM::rndF(10.f);
        } else {
            mRadius = cM::rndF(35.f);
        }
        s16 rotationYOffset = cM::rndInt(0x1555) + 0x2aab;
        if ((mYOffsetIdx & 1) == 0) {
            rotationYOffset = -rotationYOffset;
        }
        if (mYOffsetIdx >= 4) {
            rotationYOffset += cM::rndInt(0x1555) + 0x2aab;
        }
        mRotationYOffset = rotationYOffset;
    }
    mLinkPosDiff = mPosition - dAcPy_c::GetLink()->getCenterTranslation();
    if (dAcPy_c::GetLink()->getCurrentAction() == 0x25) {
        field_0x93B = true;
    } else {
        field_0x93B = false;
    }
}

void dAcOropeIgaiga_c::executeState_Stick() {
    const dAcPy_c *link = dAcPy_c::GetLink();
    f32 posY = mPosition.y;
    if (fn_257_1FF0(&posY, false)) {
        mPositionRelated = mPosition;
        mPositionRelated.y = posY - 20.f;
        mStateMgr.changeState(StateID_Water);
    } else if (link->checkActionFlags(0x40000) || !link->checkFlags0x340(0x100)) {
        fn_257_1FF0(&posY, true);
        mPositionRelated = mPosition;
        mPositionRelated.y = posY - 20.f;
        mPosition.y = posY - 20.f;
        mStateMgr.changeState(StateID_Water);
        fn_257_21A0();
    } else if (fn_257_2310(mRotationYOffset)) {
        fn_257_1DF0();
        mVec3_c linkPos = dAcPy_c::GetLink()->getCenterTranslation();

        f32 linkPosDiffAbsXZ = mLinkPosDiff.absXZ();
        if (field_0x93B) {
            linkPosDiffAbsXZ *= 0.3f;
        }
        if (!dAcPy_c::GetLinkM()->isRoomID(mRoomID)) {
            mAngle.y = cM::rndInt(0x7fff);
            mSpeed = 13.f;
            mVelocity.y = 20.f;
            mStateMgr.changeState(StateID_Ground);
        } else {
            getXZCirclePoint(linkPos, dAcPy_c::GetLink()->mRotation.y + mRotationYOffset, linkPosDiffAbsXZ);
            linkPos.y += mLinkPosDiff.y;
            mRotation.y = cLib::targetAngleY(linkPos, dAcPy_c::GetLink()->mPosition);
            mPosition.x = linkPos.x;
            mPosition.z = linkPos.z;
            if (mVelocityYRelated > 0) {
                mAcceleration = -3.5f;
                mRotation.x += mRotationXOffset;
                calcVelocity();
                mPosition += mVelocity;
                if (mPosition.y < linkPos.y) {
                    mPosition.y = linkPos.y;
                    mVelocityYRelated--;
                    if (mVelocityYRelated != 0) {
                        mVelocity.y = 3.f * mLinkSpeedRelated * mVelocityYRelated;
                    }
                }
            } else {
                mPosition.y = linkPos.y;
                f32 linkSpeedRelated = dAcPy_c::GetLink()->mSpeed / 20.f;
                if (linkSpeedRelated > 1.f) {
                    linkSpeedRelated = 1.f;
                }
                if (dAcPy_c::GetLinkM()->checkActionFlags(0xc70852)) {
                    field_0x938 = true;
                } else if (field_0x938) {
                    field_0x938 = false;
                    linkSpeedRelated = 1.f;
                }
                mLinkSpeedRelated = linkSpeedRelated;
                if (linkSpeedRelated < 0.3f) {
                    mVelocityYRelated = 0;
                } else {
                    mVelocityYRelated = 3;
                    mLinkSpeedRelated += cM::rndFX(0.15f);
                }
                mRotationXOffset = mLinkSpeedRelated * 910.f;
            }
            if (fn_257_21D0()) {
                mAngle.y = cM::rndInt(0x7fff);
                mSpeed = 13.f;
                mVelocity.y = 20.f;
                mStateMgr.changeState(StateID_Ground);
            }
        }
    }
}

void dAcOropeIgaiga_c::finalizeState_Stick() {
    mYOffsetIdx = 0xff;
    mCollider.OnTgSet();
    mCollider.OnCoSet();
}

void dAcOropeIgaiga_c::initializeState_Water() {
    mStts.SetRank(5);
    mRotationXOffset = 100;
    mPositionYRelated = mPositionRelated.y - 2.0f;
    fn_257_20F0(3.f, 10.f);
}

const s16 dAcOropeIgaiga_c::lbl_257_rodata_90 = 0x2d8;

void dAcOropeIgaiga_c::executeState_Water() {
    fn_257_1D20();
    fn_257_1DF0();
    if (mVelocityYRelated != 0) {
        calcVelocity();
        mPosition += mVelocity;
        mPosition += mStts.mCcMove;
    }

    if (mVelocityYRelated != 0) {
        if (fn_257_1FF0(nullptr, 0) != 0) {
            mVelocityYRelated--;
            if (mVelocityYRelated > 0) {
                sLib::chase(&mSpeed, 0, 1.f);
                mVelocity.y = 7.f * mVelocityYRelated;
            } else {
                fn_257_21A0();
            }
        }
    } else {
        f32 f1 = 0.1f;
        if (fn_257_1D20() == 1) {
            mSpeed = 8.5f;
            mAngle.y = cLib::targetAngleY(dAcPy_c::GetLink()->mPosition, mPosition);
        }
        sLib::chase(&mSpeed, 0, 1.f);

        if (!cM::isZero(mSpeed)) {
            calcVelocity();
            mPosition += mVelocity;
            mPosition += mStts.mCcMove;
            mRotation.x += mAng(0x2d8);
            f1 = 2.f;
        }
        if (sLib::chase(&mPosition.y, mPositionYRelated, f1) != 0) {
            if (mPositionYRelated > mPositionRelated.y) {
                mPositionYRelated = mPositionRelated.y - 2.f;
            } else {
                mPositionYRelated = mPositionRelated.y + 1.f;
            }
        }
    }
    if (mObjAcch.ChkGndHit()) {
        mStateMgr.changeState(StateID_Ground);
        mVelocityYRelated = 0;
    }
    mObjAcch.CrrPos(*dBgS::GetInstance());
}

void dAcOropeIgaiga_c::finalizeState_Water() {
    mVelocityYRelated = 0;
    mStts.SetRank(0);
    fn_257_21A0();
}

u32 dAcOropeIgaiga_c::fn_257_1CA0() {
    f32 distThresh1 = 62500.0f;
    f32 distThresh2 = 250000.0f;
    f32 squareMagXZ = dAcPy_c::GetLink()->mPosition.squareDistanceToXZ(mPosition);
    if (squareMagXZ < distThresh1) {
        return 2;
    }
    return squareMagXZ < distThresh2;
}

s32 dAcOropeIgaiga_c::fn_257_1D20() {
    if (fn_257_2720()) {
        fn_257_1FD0();
        return 1;
    }
    if (mCollider.ChkTgHit()) {
        fn_257_1FD0();
        if (mCollider.ChkTgAtHitType(AT_TYPE_SWORD)) {
            startSound(SE_SW_HIT_RopeIga);
        }
        dAcObjBase_c *tgActor = mCollider.GetTgActor();
        if (tgActor != nullptr && tgActor->mProfileName == fProfile::OBJ_ROPE_IGAIGA) {
            return 2;
        }
        return 3;
    }
    return 0;
}

void dAcOropeIgaiga_c::fn_257_1DF0() {
    if (field_0x91E > 0) {
        field_0x91E--;
        if (field_0x91E == 3) {
            mCollider.OnAtSet();
            mCollider.SetR(50.f);
            mCollider.ClrCoSet();
            mVec3_c particlePosition = mPosition;
            particlePosition.y += 20.f;
            dJEffManager_c::spawnEffect(
                PARTICLE_RESOURCE_ID_MAPPING_498_, particlePosition, nullptr, nullptr, nullptr, nullptr, 0, 0
            );
            startSound(SE_RopeIga_EXPLODE);
        } else if (field_0x91E == 0) {
            deleteRequest();
        }
        if (field_0x91E > 0 && field_0x91E < 3) {
            if (mCollider.ChkAtHit()) {
                deleteRequest();
            }
        }
    }
}

void dAcOropeIgaiga_c::fn_257_1F20() {
    s16 ang = mStateMgr.isState(StateID_Rope) ? 0xb6 : 0x4fa;
    s16 random = cM::rndInt(0x222);
    s32 rotationXOffset = ang + random;
    if (rotationXOffset & 1) {
        rotationXOffset = (s16)-rotationXOffset;
    }
    mRotationXOffset = rotationXOffset;
}

void dAcOropeIgaiga_c::fn_257_1FD0() {
    if (field_0x91E != -1) {
        return;
    }
    field_0x91E = 0x99;
}

bool dAcOropeIgaiga_c::fn_257_1FF0(f32 *posY, bool p2) {
    if (p2 || mVelocity.y < 0.f) {
        mVec3_c _pos = mPosition;
        f32 f1 = p2 ? 200.f : 50.f;
        f32 f2 = p2 ? -200.f : -30.f;
        if (dBgS_WtrChk::CheckPos(&mPosition, true, f1, f2)) {
            f32 waterHeight = dBgS_WtrChk::GetWaterHeight();
            if (p2 || mPosition.y < waterHeight - 20.f) {
                if (posY != nullptr) {
                    *posY = waterHeight;
                }
                return true;
            }
        }
    }
    return false;
}

void dAcOropeIgaiga_c::fn_257_20F0(f32 speed, f32 velocityY) {
    fn_257_1F20();
    mVelocityYRelated = 3;
    mSpeed = speed;
    mAngle.y = cLib::targetAngleY(dAcPy_c::GetLink()->mPosition, mPosition);
    s16 angleOffset = cM::rndInt(0x2aab);
    if (angleOffset & 1) {
        angleOffset = -angleOffset;
    }
    mAngle.y += angleOffset;
    mVelocity.y = velocityY;
    mAcceleration = -4.f;
}

void dAcOropeIgaiga_c::fn_257_21A0() {
    mVelocityYRelated = 0;
    mVelocity.y = 0.f;
    mAcceleration = 0.f;
    mSpeed = 0.f;
    mRotationXOffset = 100;
}

bool dAcOropeIgaiga_c::fn_257_21D0() {
    if (field_0x91A != 0) {
        field_0x91A--;
    }
    dAcPy_c *link = dAcPy_c::GetLinkM();
    if (link->getCurrentAction() == 0x49) {
        if (!mLinkShieldBash) {
            field_0x91A += lbl_257_rodata_1E;
        }
        mLinkShieldBash = true;
    } else {
        mLinkShieldBash = false;
        if (link->checkFlags0x354(0x2000)) {
            field_0x91A += lbl_257_rodata_14;
        } else if (link->checkFlags0x354(0x4)) {
            field_0x91A += lbl_257_rodata_16;
        } else if (link->getCurrentAction() == 0xC) {
            field_0x91A += lbl_257_rodata_18;
        } else if (link->getCurrentAction() == 0x27) {
            field_0x91A += lbl_257_rodata_1A;
        } else if (link->checkSwordAndMoreStates(0x40)) {
            field_0x91A += lbl_257_rodata_1C;
        }
    }
    if (field_0x93B) {
        if (dAcPy_c::GetLink()->getCurrentAction() != 0x25) {
            field_0x91A += lbl_257_rodata_20;
        }
    } else if (dAcPy_c::GetLink()->getCurrentAction() == 0x25) {
        field_0x93B = true;
    }
    if ((s32)field_0x91A >= 100) {
        return true;
    }
    return false;
}

const f32 dAcOropeIgaiga_c::sLinkCenterTranslationYOffset[6] = {20.f, 30.f, -55.f, -65.f, -25.f, -35.f};

bool dAcOropeIgaiga_c::fn_257_2310(s16 rotationYOffset) {
    if (mStickTimer != 0) {
        mVec3_c linkCenterTranslation = dAcPy_c::GetLink()->getCenterTranslation();
        getXZCirclePoint(linkCenterTranslation, dAcPy_c::GetLink()->mRotation.y + rotationYOffset, mRadius);
        linkCenterTranslation.y += sLinkCenterTranslationYOffset[mYOffsetIdx];
        if (mStickTimer == 10 && mYOffsetIdx < 4) {
            mVec3_c linkPos = dAcPy_c::GetLink()->mPosition;
            s16 ang1 = cLib::targetAngleY(linkPos, mPosition);
            s16 ang2 = cLib::targetAngleY(linkPos, linkCenterTranslation);
            if (sLib::absDiff(ang1, ang2) > 0x471C) {
                if (mYOffsetIdx & 1) {
                    mYOffsetIdx--;
                } else {
                    mYOffsetIdx++;
                }
                if (mYOffsetIdx > 5) {
                    mYOffsetIdx = 5;
                }
            }
        }
        mStickTimer--;
        mRotation.y = cLib::targetAngleY(mPosition, dAcPy_c::GetLink()->mPosition);
        mRotation.x += mRotationXOffset;
        cLib::addCalcPosXZ(&mPosition, linkCenterTranslation, 0.3f, 10.f, 1.f);
        calcVelocity();
        if (mLinkHigher) {
            if (mVelocity.y < -5.f) {
                mVelocity.y = 10.f;
            }
            if (mPosition.y > linkCenterTranslation.y) {
                mVelocity.y = 0.f;
                if (mStickTimer > 10) {
                    mStickTimer = 0;
                }
            } else {
                mPosition.y += mVelocity.y;
            }
        } else {
            if (mVelocity.y < -15.f) {
                mVelocity.y = 0.f;
            }
            mPosition.y += mVelocity.y;
            if (mPosition.y < linkCenterTranslation.y) {
                mVelocity.y = 10.f;
                if (mStickTimer > 10) {
                    mStickTimer = 0;
                }
            }
        }
        if (fn_257_2720()) {
            mLinkPosDiff = mPosition - dAcPy_c::GetLink()->getCenterTranslation();
        } else {
            if (dAcPy_c::GetLinkM()->checkActionFlags(0xc70852) == 0) {
                linkCenterTranslation = (linkCenterTranslation + mPosition) * 0.5f;
            }
            mLinkPosDiff = linkCenterTranslation - dAcPy_c::GetLink()->getCenterTranslation();
            mStickTimer = 0;
        }
        return false;
    }
    mCollider.ClrCoSet();
    return true;
}

bool dAcOropeIgaiga_c::fn_257_2720() {
    if (mCollider.ChkCoHit()) {
        if (mCollider.GetCoActor()->isPlayer() &&
            dAcPy_c::GetLink()->getCenterTranslation().squareDistanceToXZ(mPosition) < 1600.f) {
            return true;
        }
    }
    return false;
}

const f32 dAcOropeIgaiga_c::sSquareXZDistanceThreshold = 1600.f;
