/**
 * @file crenelBeanSprout.c
 * @ingroup Objects
 *
 * @brief Crenel Bean Sprout object
 */

#define NENT_DEPRECATED
#include "global.h"
#include "object.h"
#include "functions.h"
#include "hitbox.h"

typedef struct {
    /*0x00*/ Entity base;
    /*0x68*/ u8 unk_68[8];
    /*0x70*/ u16 unk_70;
    /*0x72*/ u16 unk_72;
} CrenelBeanSproutEntity;

extern u32 sub_080B1AB4(s32, s32, u32);

void sub_080969A4(CrenelBeanSproutEntity*);
void sub_08096A78(CrenelBeanSproutEntity*);
void CrenelBeanSprout_Init(CrenelBeanSproutEntity*);
void CrenelBeanSprout_Action1(CrenelBeanSproutEntity*);
void CrenelBeanSprout_Action2(CrenelBeanSproutEntity*);
void CrenelBeanSprout_Action3(CrenelBeanSproutEntity*);
void CrenelBeanSprout_Action4(CrenelBeanSproutEntity*);
void CrenelBeanSprout_Action5(CrenelBeanSproutEntity*);
void CrenelBeanSprout_Action6(CrenelBeanSproutEntity*);
void CrenelBeanSprout_Action2SubAction0(CrenelBeanSproutEntity*);
void CrenelBeanSprout_Action2SubAction1(CrenelBeanSproutEntity*);
void CrenelBeanSprout_Action2SubAction2(CrenelBeanSproutEntity*);
void CrenelBeanSprout_Action2SubAction3(CrenelBeanSproutEntity*);
void CrenelBeanSprout_Action6SubAction0(CrenelBeanSproutEntity*);
void CrenelBeanSprout_Action6SubAction1(CrenelBeanSproutEntity*);
void CrenelBeanSprout_Action6SubAction2(CrenelBeanSproutEntity*);

void CrenelBeanSprout(CrenelBeanSproutEntity* this) {
    static void (*const CrenelBeanSprout_Actions[])(CrenelBeanSproutEntity*) = {
        CrenelBeanSprout_Init,    CrenelBeanSprout_Action1, CrenelBeanSprout_Action2, CrenelBeanSprout_Action3,
        CrenelBeanSprout_Action4, CrenelBeanSprout_Action5, CrenelBeanSprout_Action6,
    };
    CrenelBeanSprout_Actions[super->action](this);
}

void CrenelBeanSprout_Init(CrenelBeanSproutEntity* this) {
    Entity* obj;
    u32 tmp;

    super->action = 1;
    tmp = super->speed = 0x80;
    super->hitbox = (Hitbox*)&gUnk_080FD2A8;
    switch (super->type) {
        case 0:
            if (CheckGlobalFlag(WATERBEAN_OUT)) {
                if (CheckGlobalFlag(WATERBEAN_PUT) == 0) {
                    PositionRelative(&gPlayerEntity, super, 0, 0x10000);
                    SetTile(0x4022, 0xdc, super->collisionLayer);
                } else {
                    if (CheckLocalFlag(super->type2) == 0) {
                        InitializeAnimation(super, 10);
                        super->y.HALF.HI += 4;
                        super->action = 4;
                        SetTile(0x403b, COORD_TO_TILE(super), super->collisionLayer);
                        return;
                    }
                    super->type2 = 0;
                    super->field_0xf = 2;
                    sub_080969A4(this);
                    DeleteThisEntity();
                }
            } else {
                super->x.HALF.HI = gRoomControls.origin_x + 0xd0;
                super->y.HALF.HI = gRoomControls.origin_y + 0x44;
                super->action = 4;
                InitializeAnimation(super, super->type + 3);
                return;
            }
            break;
        case 3:
            if (CheckGlobalFlag(WATERBEAN_OUT)) {
                if (CheckGlobalFlag(WATERBEAN_PUT) == 0) {
                    super->spritePriority.b0 = gPlayerEntity.spritePriority.b0 - 1;
                    *(((u8*)&gPlayerEntity) + 0x79) = tmp;
                    PositionRelative(&gPlayerEntity, super, 0, -0x180000);
                } else {
                    DeleteThisEntity();
                }
            }
            obj = CreateObjectWithParent(super, CRENEL_BEAN_SPROUT, 1, 0);
            super->child = obj;
            if (obj != NULL) {
                PositionRelative(super, obj, -0x1c0000, -0x280000);
            }
            super->field_0x16 = 0x10;
            super->spriteRendering.b0 = 3;
            InitializeAnimation(super, 0xc);
            CrenelBeanSprout_Action1(this);
            return;
            break;
        case 1:
            super->spriteRendering.b0 = 3;
            SetDefaultPriority(super, 6);
            break;
        case 2:
            if (CheckLocalFlag((u32)super->type2) == 0) {

                InitializeAnimation(super, 0xb);
                super->y.HALF.HI += 4;
                super->action = 4;
                SetTile(0x4032, COORD_TO_TILE(super), super->collisionLayer);
                return;
            } else {
                super->type2 = 0;
                super->field_0xf = 3;
                sub_080969A4(this);
                DeleteThisEntity();
                return;
            }
            break;
    }
    InitializeAnimation(super, super->type + 3);
    CrenelBeanSprout_Action1(this);
}

void CrenelBeanSprout_Action1(CrenelBeanSproutEntity* this) {
    static const u8 gUnk_08123184[] = {
        0, 240, 16, 0, 0, 16, 240, 0,
    };
    Entity* parent;
    u32 tmp;
    if ((super->type & 1) != 0) {
        if (super->type == 3) {
            sub_08078930(super);
            sub_0800445C(super);
        } else {
            PositionRelative(super->parent, super, -0x1c0000, -0x280000);
            if (super->parent->action == 2) {
                switch (super->parent->subAction) {
                    case 1:
                        if ((gPlayerState.field_0xd & 0x80) != 0) {
                            InitializeAnimation(super, 4);
                        } else {
                            GetNextFrame(super);
                        }
                        break;
                    case 2:
                        GetNextFrame(super);
                        break;
                    default:
                        InitializeAnimation(super, 4);
                        break;
                }
            }
            super->spritePriority.b0 = super->parent->spritePriority.b0 - 1;
            parent = super->parent;
            super->spriteRendering.b3 = parent->spriteRendering.b3;
            super->spriteOrientation.flipY = parent->spriteOrientation.flipY;
        }
        sub_0805EC9C(super, 0xcc, 0xcc, 0);
    } else {
        gPlayerState.mobility |= 0x80;
        gPlayerState.heldObject = 5;
        if ((gPlayerState.field_0xd & 0x80) != 0) {
            InitializeAnimation(super, (super->type >> 1) + 3);
        } else {
            GetNextFrame(super);
        }
        tmp = gPlayerEntity.animationState & 6;
        this->unk_70 = ((super->x.HALF.HI + (s8)gUnk_08123184[tmp]) & -0x10) | 8;
        this->unk_72 = ((super->y.HALF.HI + (s8)gUnk_08123184[(tmp) + 1]) & -0x10) | 8;
        if (sub_080B1AB4(this->unk_70, this->unk_72, super->collisionLayer) == 0x19) {
            gUnk_0200AF00.filler25[10] = 3;
        } else {
            gUnk_0200AF00.filler25[10] = 0;
        }
        PositionRelative(&gPlayerEntity, super, 0, 0x10000);
        if (sub_080B1AA8(super) == 0x19) {
            sub_0807BA8C(0xdc, super->collisionLayer);
            sub_08096A78(this);
        }
        if ((gPlayerState.field_0x92 & 0xc0) == 0) {
            return;
        }
        if (gUnk_0200AF00.filler25[10] != 3) {
            return;
        }
        gPlayerState.heldObject = 0;
        super->action = 5;
        super->speed = 0x100;
        super->zVelocity = 0x20000;
        super->spritePriority.b1 = 1;
        super->spriteSettings.shadow = 1;
        sub_0807BA8C(0xdc, super->collisionLayer);
        SoundReq(SFX_PLY_VO5);
    }
}

void CrenelBeanSprout_Action2(CrenelBeanSproutEntity* this) {
    static void (*const CrenelBeanSprout_Action2SubActions[])(CrenelBeanSproutEntity*) = {
        CrenelBeanSprout_Action2SubAction0,
        CrenelBeanSprout_Action2SubAction1,
        CrenelBeanSprout_Action2SubAction2,
        CrenelBeanSprout_Action2SubAction3,
    };
    CrenelBeanSprout_Action2SubActions[super->subAction](this);
}

void CrenelBeanSprout_Action2SubAction0(CrenelBeanSproutEntity* this) {
    SetGlobalFlag(WATERBEAN_OUT);
    super->subAction++;
}

void CrenelBeanSprout_Action2SubAction1(CrenelBeanSproutEntity* this) {
}

void CrenelBeanSprout_Action2SubAction2(CrenelBeanSproutEntity* this) {
    ClearGlobalFlag(WATERBEAN_OUT);
}

void CrenelBeanSprout_Action2SubAction3(CrenelBeanSproutEntity* this) {
    InitScreenShake(0x10, 0);
    super->action = 1;
    super->subAction = 0;
}

void CrenelBeanSprout_Action3(CrenelBeanSproutEntity* this) {
    UpdateAnimationSingleFrame(super);
    if ((super->frame & 0x80) != 0) {
        super->action++;
        InitializeAnimation(super, 10);
    }
}

void CrenelBeanSprout_Action4(CrenelBeanSproutEntity* this) {
    static const u16 gUnk_0812319C[] = { 0x403c, 0x4033 };
    if (gUnk_0812319C[super->type >> 1] == GetTileTypeByEntity(super)) {
        GetNextFrame(super);
        gPlayerState.keepFacing |= 0x80;
        gPlayerState.field_0xa |= 0x80;
        gPlayerState.field_0x7 |= 0x80;
        if (--super->actionDelay == 0) {
            super->action = 6;
            super->subAction = 0;
            CreateDust(super);
        }
    } else {
        super->actionDelay = 0xc0;
    }
}

void CrenelBeanSprout_Action5(CrenelBeanSproutEntity* this) {
    if ((this->unk_70 != super->x.HALF.HI) || (this->unk_72 != super->y.HALF.HI)) {
        super->direction = CalculateDirectionTo(super->x.HALF.HI, super->y.HALF.HI, this->unk_70, this->unk_72);
        LinearMoveUpdate(super);
    }
    if (GravityUpdate(super, 0x4000) == 0) {
        sub_08096A78(this);
    }
}

void CrenelBeanSprout_Action6(CrenelBeanSproutEntity* this) {
    static void (*const CrenelBeanSprout_Action6SubActions[])(CrenelBeanSproutEntity*) = {
        CrenelBeanSprout_Action6SubAction0,
        CrenelBeanSprout_Action6SubAction1,
        CrenelBeanSprout_Action6SubAction2,
    };
    if (super->subAction != 2) {
        sub_08078B48();
    }
    CrenelBeanSprout_Action6SubActions[super->subAction](this);
}

void CrenelBeanSprout_Action6SubAction0(CrenelBeanSproutEntity* this) {
    static const u8 gUnk_081231AC[] = {
        2,
        3,
    };
    SetLocalFlag(super->type2);
    super->actionDelay = 0x0f;
    super->field_0xf = gUnk_081231AC[super->type >> 1];
    super->type2 = 0;
    super->spriteSettings.draw = 0;
    super->subAction++;
    if (super->type == 0) {
        sub_0807B7D8(0x1ce, COORD_TO_TILE(super), super->collisionLayer);
    } else {
        sub_0807B7D8(0x1cd, COORD_TO_TILE(super), super->collisionLayer);
    }
    SoundReq(SFX_1DB);
}

void CrenelBeanSprout_Action6SubAction1(CrenelBeanSproutEntity* this) {
    static const u16 gUnk_081231AE[] = { 0x1cc, 0x1cb, 0x1c9 };
    if (--super->actionDelay == 0) {
        super->y.HALF.HI += -0x10;
        sub_0807B7D8(gUnk_081231AE[super->type2], COORD_TO_TILE(super), super->collisionLayer);
        super->type2++;
        if (super->type2 == super->field_0xf) {
            gPlayerState.keepFacing &= 0x7f;
            super->subAction++;
            super->actionDelay = 0x3c;
        } else {
            super->actionDelay = 0x0f;
        }
    }
}

void CrenelBeanSprout_Action6SubAction2(CrenelBeanSproutEntity* this) {
    if ((super->actionDelay != 0) && (--super->actionDelay == 0)) {
        SoundReq(SFX_SECRET);
    }
}

void sub_080969A4(CrenelBeanSproutEntity* this) {
    static const u16 gUnk_081231B4[] = { 0x1cc, 0x1cb, 0x1c9 };
    if (super->type == 0) {
        sub_0807B7D8(0x1ce, COORD_TO_TILE(super), super->collisionLayer);
    } else {
        sub_0807B7D8(0x1cd, COORD_TO_TILE(super), super->collisionLayer);
    }
    while (super->type2 != super->field_0xf) {
        super->y.HALF.HI -= 0x10;
        sub_0807B7D8(gUnk_081231B4[super->type2], COORD_TO_TILE(super), super->collisionLayer);
        super->type2++;
    }
}

void sub_08096A78(CrenelBeanSproutEntity* this) {
    SetGlobalFlag(WATERBEAN_PUT);
    InitAnimationForceUpdate(super, (super->type >> 1) + 8);
    sub_08004168(super);
    super->y.HALF.HI += 4;
    super->action = 3;
    SetTile(0x403b, COORD_TO_TILE(super), super->collisionLayer);
}
