/**
 * @file rope.c
 * @ingroup Enemies
 *
 * @brief Rope enemy
 */

#include "enemy.h"
#include "physics.h"

void Rope_OnTick(Entity*);
void Rope_OnCollision(Entity*);
void Rope_OnGrabbed(Entity*);
void sub_08031434(Entity*);
void sub_08031480(Entity*);
void sub_080314FC(Entity*);
void sub_080315BC(Entity*);
void sub_0803140C(Entity*);
void sub_08031418(Entity*);
void sub_08031420(Entity*);

static void (*const Rope_Functions[6])(Entity*) = {
    Rope_OnTick, Rope_OnCollision, GenericKnockback, GenericDeath, GenericConfused, Rope_OnGrabbed,
};

extern Entity* gUnk_020000B0;

void sub_08031600(Entity*);
u32 sub_0803163C(Entity*);

void Rope(Entity* this) {
    EnemyFunctionHandler(this, Rope_Functions);
    SetChildOffset(this, 0, 1, -16);
}

void Rope_OnTick(Entity* this) {
    static void (*const actionFuncs[4])(Entity*) = {
        sub_08031434,
        sub_08031480,
        sub_080314FC,
        sub_080315BC,
    };
    actionFuncs[this->action](this);
}

void Rope_OnCollision(Entity* this) {
    if (this->action == 3) {
        this->subtimer = 30;
        this->field_0x78.HALF.LO = 0x3c;
        sub_08031600(this);
    }
    if (this->confusedTime) {
        Create0x68FX(this, FX_STARS);
    }
    EnemyFunctionHandlerAfterCollision(this, Rope_Functions);
}

void Rope_OnGrabbed(Entity* this) {
    static void (*const subActionFuncs[3])(Entity*) = {
        sub_0803140C,
        sub_08031418,
        sub_08031420,
    };
    if (sub_0806F520(this)) {
        subActionFuncs[this->subAction](this);
    }
}

void sub_0803140C(Entity* this) {
    this->subAction = 1;
    this->gustJarTolerance = 0x3c;
}

void sub_08031418(Entity* this) {
    sub_0806F4E8(this);
}

void sub_08031420(Entity* this) {
    if (sub_0806F3E4(this)) {
        GenericDeath(this);
    }
}

void sub_08031434(Entity* this) {

    sub_0804A720(this);
    this->animationState = 0xff;
    this->gustJarFlags = 1;
    this->field_0x7a.HWORD = this->speed;
    if (!(this->type)) {
        sub_08031600(this);
    } else {
        this->action = 1;
        this->subAction = 0;
        this->spriteSettings.draw = (this->spriteSettings.draw & 0xfc);
        this->z.HALF.HI = -0x80;
        this->frameIndex = 0xff;
    }
}

void sub_08031480(Entity* this) {
    if (this->subAction == 0) {
        if (this->timer != 0) {
            this->timer--;
        } else {
            sub_08031600(this);
            this->action = 1;
            this->subAction = 1;
            this->spriteSettings.draw = 3;
            this->spriteRendering.b3 = 1;
            this->spriteOrientation.flipY = 1;
            SoundReq(SFX_12D);
        }
    } else {
        if (GravityUpdate(this, Q_8_8(24.0)) == 0) {
            this->action = 2;
            this->subtimer = 15;
            this->spriteSettings.draw = 1;
            UpdateSpriteForCollisionLayer(this);
            EnqueueSFX(SFX_WATER_SPLASH);
        }
    }
}
void sub_080314FC(Entity* this) {
    u32 u;

    GetNextFrame(this);
    if (this->subtimer) {
        this->subtimer--;
    } else {
        if (this->field_0x78.HALF.LO) {
            this->field_0x78.HALF.LO--;
        }
        if (sub_08049FA0(this)) {
            if (!(this->field_0x78.HALF.LO)) {
                if (sub_08049FDC(this, 1)) {
                    u = sub_0804A044(this, gUnk_020000B0, 0xc);
                    if (u != 0xff) {
                        this->action = 3;
                        this->timer = 30;
                        this->field_0x7a.HWORD = this->speed = 0x1a0;
                        this->direction = u;
                        this->animationState = this->direction >> 3;
                        InitializeAnimation(this, this->animationState + 4);
                        return;
                    }
                }
            }
        } else {
            if ((Random() & 1)) {
                this->direction = DirectionRoundUp(sub_08049EE4(this));
                u = this->direction >> 3;
                if (u != this->animationState) {
                    this->animationState = u;
                    InitializeAnimation(this, u);
                }
            }
        }
        if (--this->timer == 0) {
            sub_08031600(this);
        }
        sub_0803163C(this);
    }
}

void sub_080315BC(Entity* this) {
    if (this->timer != 0) {
        this->timer--;
        UpdateAnimationVariableFrames(this, 2);
    } else {
        if (sub_08049FA0(this)) {
            GetNextFrame(this);
            if (sub_0803163C(this)) {
                return;
            }
        }
        this->field_0x78.HALF.LO = 0x1e;
        sub_08031600(this);
    }
}

void sub_08031600(Entity* this) {
    u32 r;
    this->action = 2;
    this->timer = (Random() & 0x30) + 60;
    this->speed = 0x80;
    this->field_0x7a.HWORD = 0x80;
    r = Random() & 0x18;
    this->direction = r;
    r = r / 8;
    if (r != this->animationState) {
        this->animationState = r;
        InitializeAnimation(this, r);
    }
}

u32 sub_0803163C(Entity* this) {
    u32 h;
    if (GetTileUnderEntity(this) == 0x13) {
        h = this->field_0x7a.HWORD / 2;
    } else {
        h = this->field_0x7a.HWORD;
    }
    this->speed = h;
    return ProcessMovement0(this);
}
