mirror of
https://github.com/zeldaret/tmc
synced 2026-06-07 12:07:37 -04:00
399 lines
10 KiB
C
399 lines
10 KiB
C
/**
|
|
* @file spinyBeetle.c
|
|
* @ingroup Enemies
|
|
*
|
|
* @brief Spiny Beetle enemy
|
|
*/
|
|
#include "enemy.h"
|
|
#include "entity.h"
|
|
#include "functions.h"
|
|
#include "object.h"
|
|
|
|
typedef struct {
|
|
Entity base;
|
|
u8 filler[0xc];
|
|
u16 tile;
|
|
u16 tileIndex;
|
|
u8 unk_78;
|
|
u8 unk_79;
|
|
u8 unk_7a;
|
|
u8 unk_7b;
|
|
s32 unk_7c;
|
|
s32 unk_80;
|
|
u16 unk_84;
|
|
} SpinyBeetleEntity;
|
|
|
|
void (*const SpinyBeetle_Functions[])(Entity*);
|
|
void (*const gUnk_080CEC04[])(SpinyBeetleEntity*);
|
|
const s8 gUnk_080CEC1C[];
|
|
|
|
extern void sub_08033E1C(SpinyBeetleEntity*);
|
|
extern void sub_08033D78(SpinyBeetleEntity*);
|
|
extern u32 sub_08033DF0(SpinyBeetleEntity*);
|
|
extern void SpinyBeetle_SetHitType(SpinyBeetleEntity*);
|
|
extern void EnemyFunctionHandlerAfterCollision(Entity*, EntityActionArray);
|
|
extern u32 sub_0804A024(Entity*, u32, u32);
|
|
|
|
void SpinyBeetle(Entity* this) {
|
|
EnemyFunctionHandler(this, SpinyBeetle_Functions);
|
|
EnemySetFXOffset(this, 0, 1, -0x10);
|
|
}
|
|
|
|
void SpinyBeetle_OnTick(SpinyBeetleEntity* this) {
|
|
gUnk_080CEC04[super->action](this);
|
|
}
|
|
|
|
void SpinyBeetle_OnCollision(SpinyBeetleEntity* this) {
|
|
if (super->confusedTime) {
|
|
EnemyCreateFX(super, FX_STARS);
|
|
}
|
|
|
|
EnemyFunctionHandlerAfterCollision(super, SpinyBeetle_Functions);
|
|
if (super->contactFlags & 0x80) {
|
|
if (super->iframes > 0 && super->child) {
|
|
sub_08033E1C(this);
|
|
}
|
|
|
|
if ((super->contactFlags & 0x3f) == 0x14 && super->action != 5) {
|
|
super->action = 3;
|
|
super->timer = 90;
|
|
super->subtimer = 16;
|
|
super->spritePriority.b1 = 1;
|
|
super->direction = DirectionRoundUp(sub_08049F84(super, 1));
|
|
sub_08033D78(this);
|
|
InitializeAnimation(super, 3);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SpinyBeetle_OnGrabbed(SpinyBeetleEntity* this) {
|
|
}
|
|
|
|
void SpinyBeetle_OnConfused(SpinyBeetleEntity* this) {
|
|
GenericConfused(super);
|
|
|
|
if (super->action != 5) {
|
|
if (sub_08033DF0(this)) {
|
|
sub_08033E1C(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SpinyBeetle_Init(SpinyBeetleEntity* this) {
|
|
Entity* obj;
|
|
super->action = 1;
|
|
super->timer = 0;
|
|
super->subtimer = 0;
|
|
this->unk_7c = (super->x.WORD & 0xfff00000) | 0x80000;
|
|
this->unk_80 = (super->y.WORD & 0xfff00000) | 0x80000;
|
|
super->x.WORD = this->unk_7c;
|
|
super->y.WORD = this->unk_80;
|
|
this->unk_79 = 0;
|
|
this->unk_7a = 0;
|
|
this->unk_78 = 0;
|
|
this->unk_7b = 0;
|
|
this->tile = COORD_TO_TILE(super);
|
|
this->tileIndex = GetTileIndex(this->tile, super->collisionLayer);
|
|
SetTile(0x4022, this->tile, super->collisionLayer);
|
|
obj = CreateObject(OBJECT_ON_BEETLE, super->type, 0);
|
|
|
|
if (obj == NULL) {
|
|
DeleteThisEntity();
|
|
}
|
|
|
|
CopyPosition(super, obj);
|
|
super->child = obj;
|
|
obj->parent = super;
|
|
|
|
if (super->type == 1) {
|
|
SpinyBeetle_SetHitType(this);
|
|
}
|
|
|
|
InitializeAnimation(super, 0);
|
|
}
|
|
|
|
void sub_08033958(SpinyBeetleEntity* this) {
|
|
u32 direction;
|
|
if (sub_08033DF0(this)) {
|
|
sub_08033E1C(this);
|
|
sub_0807B9B8(this->tileIndex, this->tile, super->collisionLayer);
|
|
return;
|
|
}
|
|
|
|
if (this->unk_7b) {
|
|
this->unk_7b--;
|
|
return;
|
|
}
|
|
|
|
super->x.WORD = this->unk_7c;
|
|
super->y.WORD = this->unk_80;
|
|
direction = sub_0804A024(super, 1, 0x10);
|
|
switch (direction) {
|
|
case 0xff:
|
|
return;
|
|
case 0:
|
|
if (this->unk_78 == 0)
|
|
return;
|
|
if (super->y.HALF.HI - gPlayerEntity.base.y.HALF.HI > 0x30)
|
|
return;
|
|
break;
|
|
case 0x10:
|
|
if (gPlayerEntity.base.y.HALF.HI - super->y.HALF.HI > 0x30)
|
|
return;
|
|
break;
|
|
case 8:
|
|
if (gPlayerEntity.base.x.HALF.HI - super->x.HALF.HI > 0x30)
|
|
return;
|
|
break;
|
|
case 0x18:
|
|
if (super->x.HALF.HI - gPlayerEntity.base.x.HALF.HI > 0x30)
|
|
return;
|
|
break;
|
|
}
|
|
|
|
if (super->child && sub_0806F520(super->child)) {
|
|
return;
|
|
}
|
|
|
|
if (this->unk_78 == 0) {
|
|
this->unk_78 = 1;
|
|
}
|
|
|
|
super->action = 2;
|
|
super->direction = direction;
|
|
super->spriteSettings.draw = 1;
|
|
COLLISION_ON(super);
|
|
|
|
super->y.WORD = (super->y.WORD & 0xfff00000) | 0xC0000;
|
|
sub_0807B9B8(this->tileIndex, this->tile, super->collisionLayer);
|
|
InitializeAnimation(super, 2);
|
|
}
|
|
|
|
void sub_08033A7C(SpinyBeetleEntity* this) {
|
|
if (sub_08033DF0(this)) {
|
|
sub_08033E1C(this);
|
|
return;
|
|
}
|
|
|
|
GetNextFrame(super);
|
|
if ((super->frame & ANIM_DONE) == 0)
|
|
return;
|
|
|
|
super->action = 3;
|
|
super->timer = 120;
|
|
super->subtimer = 32;
|
|
super->spritePriority.b1 = 1;
|
|
InitializeAnimation(super, 3);
|
|
}
|
|
|
|
void sub_08033ACC(SpinyBeetleEntity* this) {
|
|
if (sub_08033DF0(this)) {
|
|
sub_08033E1C(this);
|
|
return;
|
|
}
|
|
|
|
GetNextFrame(super);
|
|
GetNextFrame(super);
|
|
|
|
if (super->subtimer) {
|
|
super->subtimer--;
|
|
return;
|
|
}
|
|
|
|
if (--super->timer == 0) {
|
|
super->action = 4;
|
|
super->timer = 120;
|
|
super->x.WORD = (super->x.WORD & 0xfff00000) | 0x80000;
|
|
super->y.WORD = (super->y.WORD & 0xfff00000) | 0xC0000;
|
|
this->unk_7c = super->x.WORD;
|
|
this->unk_80 = super->y.WORD;
|
|
InitializeAnimation(super, 4);
|
|
} else {
|
|
sub_08033D78(this);
|
|
}
|
|
}
|
|
|
|
void sub_08033B44(SpinyBeetleEntity* this) {
|
|
u32 stop;
|
|
if (sub_08033DF0(this)) {
|
|
sub_08033E1C(this);
|
|
return;
|
|
}
|
|
|
|
GetNextFrame(super);
|
|
if (--super->timer)
|
|
return;
|
|
|
|
super->action = 1;
|
|
super->spriteSettings.draw = 0;
|
|
COLLISION_OFF(super);
|
|
|
|
stop = 0;
|
|
while (!stop) {
|
|
super->x.WORD = (super->x.WORD & 0xfff00000) | 0x80000;
|
|
super->y.WORD = (super->y.WORD & 0xfff00000) | 0x80000;
|
|
this->unk_7c = super->x.WORD;
|
|
this->unk_80 = super->y.WORD;
|
|
super->spritePriority.b1 = 0;
|
|
this->unk_7b = 0x78;
|
|
this->tile = COORD_TO_TILE(super);
|
|
this->tileIndex = GetTileIndex(this->tile, super->collisionLayer);
|
|
|
|
if (this->tileIndex != 0x4022) {
|
|
stop++;
|
|
} else {
|
|
switch (DirectionRound(super->direction) >> 2) {
|
|
case 0:
|
|
super->y.HALF.HI += 0x10;
|
|
break;
|
|
case 2:
|
|
super->x.HALF.HI -= 0x10;
|
|
break;
|
|
case 4:
|
|
super->y.HALF.HI -= 0x10;
|
|
break;
|
|
case 6:
|
|
super->x.HALF.HI += 0x10;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
SetTile(0x4022, this->tile, super->collisionLayer);
|
|
InitializeAnimation(super, 0);
|
|
}
|
|
|
|
void sub_08033C94(SpinyBeetleEntity* this) {
|
|
UpdateAnimationVariableFrames(super, 3);
|
|
switch (this->unk_79) {
|
|
case 0:
|
|
this->unk_79 = 1;
|
|
if (super->spriteSettings.draw != 1) {
|
|
super->spriteSettings.draw = 1;
|
|
}
|
|
case 1:
|
|
if (--super->timer)
|
|
return;
|
|
this->unk_79 = 2;
|
|
super->timer = 120;
|
|
super->spriteOffsetY = 0;
|
|
super->direction = sub_08049F84(super, 1) + 0x14;
|
|
|
|
switch (Random() & 3) {
|
|
case 0:
|
|
super->direction += 8;
|
|
break;
|
|
case 2:
|
|
super->direction += 0x18;
|
|
break;
|
|
}
|
|
|
|
super->direction &= 0x18;
|
|
break;
|
|
case 2:
|
|
if (super->subtimer != 0) {
|
|
super->subtimer--;
|
|
} else {
|
|
sub_08033D78(this);
|
|
}
|
|
|
|
if (--super->timer)
|
|
return;
|
|
super->timer = (Random() & 0x1f) + 32;
|
|
super->direction = sub_08049F84(super, 1) + 0x14;
|
|
switch (Random() & 3) {
|
|
case 1:
|
|
super->direction += 8;
|
|
break;
|
|
case 3:
|
|
super->direction += 0x18;
|
|
break;
|
|
}
|
|
|
|
super->direction &= 0x18;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void sub_08033D78(SpinyBeetleEntity* this) {
|
|
u32 dir = DirectionRound(super->direction) >> 2;
|
|
const s8* ptr = gUnk_080CEC1C + dir;
|
|
s32 tile;
|
|
u32 type;
|
|
tile = COORD_TO_TILE_OFFSET(super, -ptr[0], -ptr[1]);
|
|
type = GetTileType(tile, super->collisionLayer);
|
|
|
|
switch (type) {
|
|
case 0x1c4:
|
|
case 0x1c5:
|
|
break;
|
|
default:
|
|
if (sub_080B1B44(tile, super->collisionLayer) - 1 > 0x3e)
|
|
ProcessMovement0(super);
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool32 sub_08033DF0(SpinyBeetleEntity* this) {
|
|
bool32 rv = 0;
|
|
if (super->child == NULL) {
|
|
rv = 1;
|
|
} else {
|
|
switch (super->child->action) {
|
|
case 4:
|
|
rv = 1;
|
|
break;
|
|
case 3:
|
|
if (super->child->subAction > 1) {
|
|
rv = 1;
|
|
}
|
|
break;
|
|
case 2:
|
|
rv = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
void sub_08033E1C(SpinyBeetleEntity* this) {
|
|
super->action = 5;
|
|
this->unk_79 = 0;
|
|
super->spriteSettings.draw = 1;
|
|
COLLISION_ON(super);
|
|
super->spritePriority.b0 = 5;
|
|
super->y.WORD = (super->y.WORD & 0xfff00000) | 0xC0000;
|
|
super->hitType = 0x19;
|
|
super->spritePriority.b1 = 1;
|
|
super->timer = 48;
|
|
super->subtimer = 0;
|
|
super->speed = 0x100;
|
|
super->child = NULL;
|
|
InitializeAnimation(super, 3);
|
|
CreateSpeechBubbleExclamationMark(super, 0xa, -12);
|
|
}
|
|
|
|
void SpinyBeetle_SetHitType(SpinyBeetleEntity* this) {
|
|
if ((gPlayerState.skills & SKILL_ROCK_BREAKER)) {
|
|
super->hitType = 0x95;
|
|
} else {
|
|
super->hitType = 0x63;
|
|
}
|
|
}
|
|
|
|
const u16 unusedLabel_0CEBDC[] = {
|
|
0x3F, 0x1C, 0x50, 0x2A, 0x55, 0x1D, 0x5C, 0x2B,
|
|
};
|
|
|
|
void (*const SpinyBeetle_Functions[])(Entity*) = {
|
|
(EntityActionPtr)SpinyBeetle_OnTick, (EntityActionPtr)SpinyBeetle_OnCollision, GenericKnockback, GenericDeath,
|
|
(EntityActionPtr)SpinyBeetle_OnConfused, (EntityActionPtr)SpinyBeetle_OnGrabbed,
|
|
};
|
|
|
|
void (*const gUnk_080CEC04[])(SpinyBeetleEntity*) = {
|
|
SpinyBeetle_Init, sub_08033958, sub_08033A7C, sub_08033ACC, sub_08033B44, sub_08033C94,
|
|
};
|
|
|
|
const s8 gUnk_080CEC1C[] = { 0, -8, 8, 0, 0, 8, -8, 0 };
|