/**
 * @file cloudPiranha.c
 * @ingroup Enemies
 *
 * @brief Cloud Piranha enemy
 */

#define NENT_DEPRECATED
#include "global.h"
#include "enemy.h"
#include "functions.h"
#include "coord.h"

typedef struct {
    /*0x00*/ Entity base;
    /*0x68*/ u8 unk_68[0x18];
    /*0x80*/ u8 unk_80;
    /*0x81*/ u8 unk_81;
    /*0x82*/ u8 unk_82;
} CloudPiranhaEntity;

void sub_08038754(CloudPiranhaEntity*);
void sub_080387F0(CloudPiranhaEntity*);
bool32 sub_0803872C(CloudPiranhaEntity*, u32);
void CloudPiranha_OnTick(CloudPiranhaEntity*);
void CloudPiranha_OnCollision(CloudPiranhaEntity*);
void CloudPiranha_OnGrabbed(CloudPiranhaEntity*);
void CloudPiranha_Init(CloudPiranhaEntity*);
void CloudPiranha_Action1(CloudPiranhaEntity*);
void sub_080385CC(CloudPiranhaEntity*);
void CloudPiranha_Action3(CloudPiranhaEntity*);
void CloudPiranha_Action4(CloudPiranhaEntity*);
void CloudPiranha_Action5(CloudPiranhaEntity*);

void (*const gUnk_080CF4F0[])(CloudPiranhaEntity*) = {
    CloudPiranha_OnTick,
    CloudPiranha_OnCollision,
    (void (*)(CloudPiranhaEntity*))GenericKnockback,
    (void (*)(CloudPiranhaEntity*))GenericDeath,
    (void (*)(CloudPiranhaEntity*))GenericConfused,
    CloudPiranha_OnGrabbed,
};

void CloudPiranha(CloudPiranhaEntity* this) {
    EnemyFunctionHandler(super, (EntityActionArray)&gUnk_080CF4F0);
    SetChildOffset(super, 0, 1, -0x10);
}

void CloudPiranha_OnTick(CloudPiranhaEntity* this) {
    static void (*const CloudPiranha_Actions[])(CloudPiranhaEntity*) = {
        CloudPiranha_Init,    CloudPiranha_Action1, sub_080385CC,
        CloudPiranha_Action3, CloudPiranha_Action4, CloudPiranha_Action5,
    };

    CloudPiranha_Actions[super->action](this);
}

void CloudPiranha_OnCollision(CloudPiranhaEntity* this) {
    if (super->confusedTime != 0) {
        Create0x68FX(super, FX_STARS);
    }
    EnemyFunctionHandlerAfterCollision(super, gUnk_080CF4F0);
    if ((super->bitfield & 0x80) != 0) {
        if (super->hitType == 0x5a) {
            switch (super->bitfield & 0x3f) {
                case 0x14:
                    super->action = 5;
                    break;
                case 0x15:
                case 0xe:
                    super->health = 0;
                    break;
            }
#ifndef EU
        } else if ((super->bitfield & 0x3f) == 0x1d) {
            sub_08038754(this);
#endif
        }
    }
}

void CloudPiranha_OnGrabbed(CloudPiranhaEntity* this) {
}

void CloudPiranha_Init(CloudPiranhaEntity* this) {
    sub_0804A720(super);
    super->action = 1;
    super->direction = (Random() & 0x1c);
    super->animationState = super->direction >> 2;
    super->flags |= ENT_COLLIDE;
    super->actionDelay = 0;
    super->field_0xf = 0x20;
    this->unk_82 = 0;
    this->unk_80 = Random() & 1;
    this->unk_81 = 0;
    super->hitType = 0x72;
    InitializeAnimation(super, super->animationState);
}

void CloudPiranha_Action1(CloudPiranhaEntity* this) {
    u32 tmp;
    sub_080387F0(this);
    if (--super->field_0xf == 0) {
        super->actionDelay = 0;
        super->field_0xf = 0x20;
        if (sub_08049FA0(super)) {
            u32 tmp = super->animationState;
            if (this->unk_80 != 0) {
                tmp += 7;
            } else {
                tmp++;
            }
            super->animationState = tmp & 7;
            super->direction = super->animationState << 2;
        } else {
            super->direction = (sub_08049EE4(super) + 2) & 0x1c;
            super->animationState = super->direction >> 2;
        }
        InitializeAnimation(super, (u32)super->animationState);
    } else if ((super->actionDelay == 0) && sub_0803872C(this, 0x80)) {
        super->action = 2;
        super->field_0xf = 0x10;
        super->speed = 0x40;
        super->animationState = sub_0806FCAC(super, super->child);
        super->direction = super->animationState << 2;
        InitializeAnimation(super, super->animationState);
    }
}

NONMATCH("asm/non_matching/cloudPiranha/sub_080385CC.inc", void sub_080385CC(CloudPiranhaEntity* this)) {
    u32 tmp;
    sub_080387F0(this);
    if (sub_0803872C(this, 0x60)) {
        super->action = 3;
        super->field_0xf = 0xc;
        super->speed = 0x80;
        super->animationState = sub_0806FCAC(super, super->child);
        super->direction = super->animationState << 2;
        InitializeAnimation(super, super->animationState);
    } else {
        if (--super->field_0xf == 0) {
            super->field_0xf = 0x10;
            if (super->child != NULL) {
                super->animationState = sub_0806FCAC(super, super->child);
            } else {
                tmp = super->animationState;
                if ((Random() & 0x10) != 0) {
                    super->animationState = (tmp + 2) & 7;
                } else {
                    super->animationState = (tmp + 6) & 7;
                }
            }
            super->direction = super->animationState << 2;
            InitializeAnimation(super, super->animationState);
        }
    }
}
END_NONMATCH

void CloudPiranha_Action3(CloudPiranhaEntity* this) {
    s32 tmp;
    sub_080387F0(this);
    if (sub_0803872C(this, 0x14)) {
        sub_08038754(this);
    } else {
        if (--super->field_0xf == 0) {
            super->field_0xf = 0xa;
            if (this->unk_81 == 0) {
                tmp = super->speed += 0x40;
                if (0x2000000 < (tmp * 0x10000)) {
                    this->unk_81 = 1;
                }
            } else if (super->speed > 0x100) {
                super->speed -= 0x50;
            } else {
                sub_08038754(this);
            }
        }
    }
}

void CloudPiranha_Action4(CloudPiranhaEntity* this) {
    Entity* effect;
    sub_080387F0(this);
    if (sub_080044EC(super, 0x1800) == 1) {
        super->action = 1;
        super->hitType = 0x72;
        super->actionDelay = 1;
        super->field_0xf = 0x80;
        super->speed = 0x80;
        super->spritePriority.b1 = 2;
        EnqueueSFX(SFX_124);
        ChangeObjPalette(super, 0x70);
        InitializeAnimation(super, super->direction >> 2);
        effect = CreateFx(super, FX_DEATH, 0);
        if (effect != NULL) {
            SortEntityAbove(super, effect);
        }
    }
}

void CloudPiranha_Action5(CloudPiranhaEntity* this) {
    sub_08038754(this);
}

bool32 sub_0803872C(CloudPiranhaEntity* this, u32 param_2) {
    super->child = sub_08049DF4(1);
    if ((super->child != NULL) && sub_0806FC80(super, super->child, param_2)) {
        return TRUE;
    } else {
        return FALSE;
    }
}

void sub_08038754(CloudPiranhaEntity* this) {
    Entity* effect;
    super->action = 4;
    super->flags |= ENT_COLLIDE;
    super->hitType = 0x5a;
#ifdef EU
    super->speed = 0x100;
#else
    super->speed = 0xc0;
#endif
    super->zVelocity = 0x20000;
    this->unk_81 = 0;
    super->spritePriority.b1 = 3;
    EnqueueSFX(SFX_12B);
    ChangeObjPalette(super, 0x71);
    if ((super->direction & 0xf) != 0) {
        InitializeAnimation(super, ((super->direction & 0x10) >> 0x3) + 9);
    } else {
        InitializeAnimation(super, ((super->direction & 0x10) >> 0x3) + 8);
    }
    effect = CreateFx(super, FX_DEATH, 0);
    if (effect != NULL) {
        SortEntityAbove(super, effect);
    }
}

void sub_080387F0(CloudPiranhaEntity* this) {

    static const u8 gUnk_080CF520[] = {
        0, 244, 8, 248, 12, 0, 8, 8, 0, 12, 248, 8, 244, 0, 248, 248,
    };
    u8 bVar1;
    u8 bVar2;
    s32 iVar4;
    const s8* ptr;

    if ((super->action != 4) && (this->unk_82 == 0)) {
        iVar4 = sub_080B1B44(COORD_TO_TILE(super), super->collisionLayer);
        if ((iVar4 == 0xf) || (iVar4 == 0x2a)) {
            this->unk_82 = 0x20;
        }
        ptr = &gUnk_080CF520[super->direction >> 1];
        bVar1 = super->direction;
        iVar4 = sub_080B1AF0(super, ptr[0], ptr[1]);
        if ((iVar4 == 0xf) || (iVar4 == 0x2a)) {
            super->direction = (super->direction + 0x10) & 0x1f;
        } else {
            if (super->collisions != 0) {
                sub_0800417E(super, super->collisions);
            }
        }
        bVar2 = super->direction;
        if (bVar1 != bVar2) {
            super->animationState = bVar2 >> 2;
            InitializeAnimation(super, super->animationState);
        }
    }
    GetNextFrame(super);
    if (this->unk_82 == 0) {
        ProcessMovement0(super);
    } else {
        this->unk_82--;
        LinearMoveUpdate(super);
    }
}
