mirror of https://github.com/zeldaret/tmc.git
431 lines
11 KiB
C
431 lines
11 KiB
C
/**
|
|
* @file ghini.c
|
|
* @ingroup Enemies
|
|
*
|
|
* @brief Ghini enemy
|
|
*/
|
|
#include "area.h"
|
|
#include "enemy.h"
|
|
#include "functions.h"
|
|
#include "physics.h"
|
|
|
|
typedef struct {
|
|
/*0x00*/ Entity base;
|
|
/*0x68*/ u8 unk_68[0x10];
|
|
/*0x78*/ u16 unk_78;
|
|
/*0x7a*/ u8 unk_7a;
|
|
/*0x7b*/ u8 unk_7b;
|
|
/*0x7c*/ u16 unk_7c;
|
|
} GhiniEntity;
|
|
|
|
extern Entity* gUnk_020000B0;
|
|
|
|
extern void (*const Ghini_Functions[])(GhiniEntity*);
|
|
extern void (*const Ghini_Actions[])(GhiniEntity*);
|
|
extern void (*const Ghini_SubActions[])(GhiniEntity*);
|
|
extern const u8 gUnk_080D0970[];
|
|
extern const u8 gUnk_080D0974[];
|
|
extern const s8 gUnk_080D0978[];
|
|
extern const u8 gUnk_080D0980[];
|
|
extern const s8 gUnk_080D0984[];
|
|
|
|
void sub_0803F694(GhiniEntity*);
|
|
void sub_0803F630(GhiniEntity*);
|
|
void sub_0803F6EC(GhiniEntity*);
|
|
void sub_0803F51C(GhiniEntity*);
|
|
void sub_0803F50C(GhiniEntity*);
|
|
bool32 sub_0803F5A8(GhiniEntity*);
|
|
bool32 sub_0803F5D4(GhiniEntity*);
|
|
void sub_0803F58C(GhiniEntity*);
|
|
void sub_0803F66C(GhiniEntity*);
|
|
void sub_0803F738(GhiniEntity*);
|
|
void sub_0803F6C0(GhiniEntity*);
|
|
void sub_0803F528(GhiniEntity*);
|
|
|
|
void Ghini(GhiniEntity* this) {
|
|
Ghini_Functions[GetNextFunction(super)](this);
|
|
EnemySetFXOffset(super, 0, 1, -0x10);
|
|
}
|
|
|
|
void Ghini_OnTick(GhiniEntity* this) {
|
|
Ghini_Actions[super->action](this);
|
|
sub_0803F694(this);
|
|
}
|
|
|
|
void Ghini_OnCollision(GhiniEntity* this) {
|
|
if (super->action == 8 || super->action == 9) {
|
|
super->animationState = 0xff;
|
|
InitializeAnimation(super, (super->knockbackDirection >> 4 ^ 1) + 1);
|
|
sub_0803F630(this);
|
|
sub_0803F6EC(this);
|
|
}
|
|
if ((super->hitType == 0x25) && (super->contactFlags == 0x80)) {
|
|
super->action = 8;
|
|
InitializeAnimation(super, 3);
|
|
} else {
|
|
if (super->contactFlags == 0x9d) {
|
|
super->zVelocity = 0x18000;
|
|
}
|
|
if (super->confusedTime != 0) {
|
|
super->animationState = super->knockbackDirection >> 4;
|
|
InitializeAnimation(super, super->animationState + 7);
|
|
EnemyCreateFX(super, FX_STARS);
|
|
}
|
|
if (super->health != this->unk_7a) {
|
|
this->unk_7a = super->health;
|
|
if (super->action == 1 || super->action == 2) {
|
|
sub_0803F51C(this);
|
|
}
|
|
InitializeAnimation(super, (super->knockbackDirection >> 4) + 7);
|
|
}
|
|
}
|
|
EnemyFunctionHandlerAfterCollision(super, Ghini_Functions);
|
|
}
|
|
|
|
void Ghini_OnKnockback(GhiniEntity* this) {
|
|
GetNextFrame(super);
|
|
GenericKnockback2(super);
|
|
if (((super->knockbackDuration == 0) && (super->health != 0)) && (super->confusedTime == 0)) {
|
|
super->animationState = 0xff;
|
|
if (super->animIndex == 7 || super->animIndex == 8) {
|
|
InitializeAnimation(super, ((super->animIndex - 7) ^ 1) + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Ghini_OnConfused(GhiniEntity* this) {
|
|
if (super->animIndex != 7 && super->animIndex != 8) {
|
|
InitializeAnimation(super, super->animationState + 7);
|
|
}
|
|
GenericConfused(super);
|
|
if (super->z.HALF.HI == 0) {
|
|
super->z.HALF.HI = -1;
|
|
}
|
|
if (super->confusedTime == 0) {
|
|
InitializeAnimation(super, (super->animationState ^ 1) + 1);
|
|
super->direction = 0xff;
|
|
super->animationState = 0xff;
|
|
sub_0803F630(this);
|
|
}
|
|
}
|
|
|
|
void Ghini_OnGrabbed(GhiniEntity* this) {
|
|
if (sub_0806F520(super)) {
|
|
Ghini_SubActions[super->subAction](this);
|
|
} else {
|
|
sub_0803F51C(this);
|
|
InitializeAnimation(super, (super->direction >> 4) + 1);
|
|
}
|
|
}
|
|
|
|
void Ghini_SubAction0(GhiniEntity* this) {
|
|
super->subAction = 1;
|
|
super->gustJarTolerance = 0x3c;
|
|
InitializeAnimation(super, (gPlayerEntity.base.animationState >> 2) + 5);
|
|
}
|
|
|
|
void Ghini_SubAction1(GhiniEntity* this) {
|
|
GetNextFrame(super);
|
|
sub_0806F4E8(super);
|
|
}
|
|
|
|
void Ghini_SubAction2(GhiniEntity* this) {
|
|
GetNextFrame(super);
|
|
if (sub_0806F3E4(super)) {
|
|
Entity* effect = CreateFx(super, FX_DEATH, 0);
|
|
if (effect != NULL) {
|
|
effect->spritePriority.b0 = 3;
|
|
}
|
|
GenericDeath(super);
|
|
}
|
|
}
|
|
|
|
void Ghini_Init(GhiniEntity* this) {
|
|
u32 rand;
|
|
|
|
sub_0804A720(super);
|
|
rand = Random();
|
|
super->direction = rand & 0x1e;
|
|
super->animationState = 0xff;
|
|
super->gustJarFlags = 1;
|
|
this->unk_7a = super->health;
|
|
this->unk_7b = (rand >> 4);
|
|
this->unk_7c = 0;
|
|
if (super->type != 0) {
|
|
sub_0803F50C(this);
|
|
} else {
|
|
sub_0803F51C(this);
|
|
InitializeAnimation(super, (super->direction >> 4) + 1);
|
|
}
|
|
}
|
|
|
|
void Ghini_Action1(GhiniEntity* this) {
|
|
if (sub_0803F5A8(this)) {
|
|
super->action = 2;
|
|
super->timer = (Random() & 0x60) + 10;
|
|
}
|
|
}
|
|
|
|
void Ghini_Action2(GhiniEntity* this) {
|
|
if (sub_0803F5A8(this) == 0) {
|
|
sub_0803F50C(this);
|
|
} else if (--super->timer == 0) {
|
|
super->action = 3;
|
|
super->timer = 30;
|
|
if (sub_08049DF4(1) != NULL) {
|
|
super->direction = GetFacingDirection(super, gUnk_020000B0);
|
|
} else {
|
|
super->direction = Random() & 0x1f;
|
|
}
|
|
super->animationState = super->direction >> 4;
|
|
InitializeAnimation(super, super->animationState + 1);
|
|
}
|
|
}
|
|
|
|
void Ghini_Action3(GhiniEntity* this) {
|
|
GetNextFrame(super);
|
|
if (--super->timer == 0) {
|
|
sub_0803F51C(this);
|
|
}
|
|
}
|
|
|
|
void Ghini_Action4(GhiniEntity* this) {
|
|
if (sub_0803F5D4(this) == FALSE) {
|
|
sub_0803F58C(this);
|
|
GetNextFrame(super);
|
|
if (--super->timer == 0) {
|
|
sub_0803F51C(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Ghini_Action5(GhiniEntity* this) {
|
|
GetNextFrame(super);
|
|
super->direction = sub_08049F84(super, 1);
|
|
if ((super->direction) != 0xff) {
|
|
sub_0803F66C(this);
|
|
if (--this->unk_78 == 0) {
|
|
super->action = 6;
|
|
super->speed = 0x100;
|
|
}
|
|
} else {
|
|
sub_0803F51C(this);
|
|
}
|
|
}
|
|
|
|
void Ghini_Action6(GhiniEntity* this) {
|
|
u32 tmp;
|
|
|
|
if (sub_0803F5A8(this) == 0) {
|
|
sub_0803F51C(this);
|
|
} else if (sub_08049DF4(1) != NULL) {
|
|
tmp = super->timer + 1;
|
|
super->timer = tmp;
|
|
if ((tmp & gUnk_080D0970[tmp * 0x1000000 >> 0x1e]) == 0) {
|
|
sub_08004596(super, GetFacingDirection(super, gUnk_020000B0));
|
|
}
|
|
sub_0803F66C(this);
|
|
ProcessMovement1(super);
|
|
GetNextFrame(super);
|
|
} else {
|
|
super->action = 7;
|
|
super->timer = 30;
|
|
}
|
|
}
|
|
|
|
void Ghini_Action7(GhiniEntity* this) {
|
|
GetNextFrame(super);
|
|
if (--super->timer == 0) {
|
|
sub_0803F51C(this);
|
|
}
|
|
}
|
|
|
|
void Ghini_Action8(GhiniEntity* this) {
|
|
sub_0803F738(this);
|
|
GetNextFrame(super);
|
|
if ((super->frame & ANIM_DONE) != 0) {
|
|
super->action = 9;
|
|
super->flags |= 0x80;
|
|
this->unk_78 = 0;
|
|
InitializeAnimation(super, 4);
|
|
}
|
|
}
|
|
|
|
void Ghini_Action9(GhiniEntity* this) {
|
|
GetNextFrame(super);
|
|
if ((super->frame & 1) != 0) {
|
|
sub_0803F6C0(this);
|
|
}
|
|
if (sub_0807953C() != 0) {
|
|
this->unk_78 += 0xc;
|
|
}
|
|
if (gPlayerEntity.base.health == 0) {
|
|
this->unk_78 = 0xe0;
|
|
}
|
|
if (++this->unk_78 >= 0xe0) {
|
|
this->unk_7c = 0x78;
|
|
super->animationState = 0xff;
|
|
super->iframes = -0xc;
|
|
super->knockbackDuration = 0x14;
|
|
super->knockbackSpeed = 0x180;
|
|
super->knockbackDirection = gPlayerEntity.base.animationState << 2 ^ 0x10;
|
|
sub_0803F51C(this);
|
|
sub_0803F6EC(this);
|
|
} else {
|
|
sub_0803F738(this);
|
|
}
|
|
}
|
|
|
|
void sub_0803F50C(GhiniEntity* this) {
|
|
super->action = 1;
|
|
InitializeAnimation(super, 9);
|
|
}
|
|
|
|
void sub_0803F51C(GhiniEntity* this) {
|
|
super->action = 4;
|
|
sub_0803F528(this);
|
|
}
|
|
|
|
void sub_0803F528(GhiniEntity* this) {
|
|
u32 rand = Random();
|
|
super->timer = (rand & 8) + 8;
|
|
if (sub_08049FA0(super)) {
|
|
super->direction = (super->direction + gUnk_080D0978[rand & 7]) & 0x1e;
|
|
} else {
|
|
super->direction = sub_08049EE4(super) & 0x1e;
|
|
}
|
|
super->speed = gUnk_080D0974[rand >> 4 & 3];
|
|
super->hitType = 0x24;
|
|
sub_0803F66C(this);
|
|
}
|
|
|
|
void sub_0803F58C(GhiniEntity* this) {
|
|
s32 yAfter;
|
|
s32 yBefore;
|
|
|
|
yBefore = super->y.WORD;
|
|
ProcessMovement1(super);
|
|
yAfter = super->y.WORD;
|
|
super->y.WORD = yAfter - (yAfter - yBefore) / 2;
|
|
}
|
|
|
|
bool32 sub_0803F5A8(GhiniEntity* this) {
|
|
u32 result;
|
|
if (sub_08049FDC(super, 1) == 0) {
|
|
result = 0;
|
|
} else if ((s16)gArea.lightLevel < 0x10) {
|
|
result = sub_0806FD54(super);
|
|
} else {
|
|
result = 1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool32 sub_0803F5D4(GhiniEntity* this) {
|
|
if (this->unk_7c != 0) {
|
|
this->unk_7c--;
|
|
} else if ((sub_08049FDC(super, 1)) &&
|
|
((sub_0806FD54(super) ||
|
|
((0xf < (s16)gArea.lightLevel && (EntityInRectRadius(super, gUnk_020000B0, 0x70, 0x48))))))) {
|
|
sub_0803F630(this);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void sub_0803F630(GhiniEntity* this) {
|
|
s16 tmp;
|
|
|
|
super->action = 5;
|
|
super->hitType = 0x25;
|
|
tmp = 0;
|
|
if (gPlayerClones[0] != NULL) {
|
|
tmp = 0x3c;
|
|
}
|
|
this->unk_78 = gUnk_080D0980[Random() & 3] + tmp;
|
|
}
|
|
|
|
void sub_0803F66C(GhiniEntity* this) {
|
|
u8 tmp;
|
|
|
|
if (((super->direction & 0xf) != 0) || (super->animationState == 0xff)) {
|
|
if (super->direction >> 4 != super->animationState) {
|
|
tmp = super->direction >> 4;
|
|
super->animationState = tmp;
|
|
InitializeAnimation(super, tmp + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void sub_0803F694(GhiniEntity* this) {
|
|
super->z.HALF.HI = gUnk_080D0984[(this->unk_7b++ >> 3) & 3];
|
|
}
|
|
|
|
void sub_0803F6C0(GhiniEntity* this) {
|
|
super->frame &= ~1;
|
|
gPlayerEntity.base.iframes = 0xc;
|
|
ModHealth(-4);
|
|
SoundReqClipped(&gPlayerEntity.base, SFX_PLY_VO6);
|
|
}
|
|
|
|
void sub_0803F6EC(GhiniEntity* this) {
|
|
if (gPlayerEntity.base.health != 0) {
|
|
gPlayerEntity.base.flags |= ENT_COLLIDE;
|
|
gPlayerEntity.base.zVelocity = Q_16_16(1.5);
|
|
gPlayerEntity.base.z.HALF.HI = -2;
|
|
gPlayerEntity.base.direction = gPlayerEntity.base.animationState << 2;
|
|
gPlayerEntity.base.iframes = -0x3c;
|
|
gPlayerState.jump_status = 0x41;
|
|
}
|
|
gPlayerState.flags &= ~PL_CAPTURED;
|
|
}
|
|
|
|
void sub_0803F738(GhiniEntity* this) {
|
|
ResetActiveItems();
|
|
gPlayerState.mobility |= 0x80;
|
|
gPlayerState.field_0xa |= 0x80;
|
|
sub_0806FA90(&gPlayerEntity.base, super, 0, 1);
|
|
super->spriteOffsetY -= 2;
|
|
}
|
|
|
|
void (*const Ghini_Functions[])(GhiniEntity*) = {
|
|
Ghini_OnTick, Ghini_OnCollision, Ghini_OnKnockback, (void (*)(GhiniEntity*))GenericDeath,
|
|
Ghini_OnConfused, Ghini_OnGrabbed,
|
|
};
|
|
void (*const Ghini_Actions[])(GhiniEntity*) = {
|
|
Ghini_Init, Ghini_Action1, Ghini_Action2, Ghini_Action3, Ghini_Action4,
|
|
Ghini_Action5, Ghini_Action6, Ghini_Action7, Ghini_Action8, Ghini_Action9,
|
|
};
|
|
void (*const Ghini_SubActions[])(GhiniEntity*) = {
|
|
Ghini_SubAction0,
|
|
Ghini_SubAction1,
|
|
Ghini_SubAction2,
|
|
};
|
|
const u8 gUnk_080D0970[] = {
|
|
15,
|
|
7,
|
|
3,
|
|
1,
|
|
};
|
|
const u8 gUnk_080D0974[] = {
|
|
224,
|
|
192,
|
|
160,
|
|
128,
|
|
};
|
|
const s8 gUnk_080D0978[] = {
|
|
0, -2, 0, 2, 0, -4, 0, 4,
|
|
};
|
|
const u8 gUnk_080D0980[] = {
|
|
15,
|
|
25,
|
|
34,
|
|
45,
|
|
};
|
|
const s8 gUnk_080D0984[] = {
|
|
-1,
|
|
-2,
|
|
-3,
|
|
-2,
|
|
};
|