Files
tmc/src/enemy/pesto.c
T
2023-12-31 02:12:41 +01:00

929 lines
26 KiB
C

/**
* @file pesto.c
* @ingroup Enemies
*
* @brief Pesto enemy
*/
#include "collision.h"
#include "enemy.h"
#include "game.h"
#include "object.h"
#include "playeritem.h"
#include "save.h"
typedef struct {
/*0x00*/ Entity base;
/*0x68*/ u8 unused1[8];
/*0x70*/ u16 unk_70;
/*0x72*/ u8 unused2[6];
/*0x78*/ u16 unk_78;
/*0x7a*/ u8 unused3[6];
/*0x80*/ u8 unk_80;
/*0x81*/ u8 unk_81;
/*0x82*/ u8 unk_82;
/*0x83*/ u8 unk_83;
/*0x84*/ u8 unk_84;
/*0x85*/ u8 unk_85;
/*0x86*/ u8 unk_86;
/*0x87*/ u8 unk_87;
} PestoEntity;
void sub_080249F4(PestoEntity*);
void sub_08024940(PestoEntity*);
void sub_080249DC(PestoEntity*);
void sub_08024A14(PestoEntity*, u32, u32);
bool32 sub_08024AD8(PestoEntity*);
bool32 sub_08024B38(PestoEntity*);
bool32 sub_08024C48(PestoEntity*, bool32);
void sub_08024C7C(PestoEntity*);
void sub_08024C94(PestoEntity*);
bool32 sub_08024CC0(PestoEntity*);
void sub_08024D00(PestoEntity*);
void sub_08024E00(PestoEntity*, u32);
void sub_08024E1C(PestoEntity*);
u32 sub_08024E34(void);
void sub_08024E4C(PestoEntity*);
void sub_08024F50(PestoEntity*);
extern Entity* gUnk_020000B0;
extern void (*const Pesto_Functions[])(PestoEntity*);
extern void (*const gUnk_080CBEDC[])(PestoEntity*);
extern void (*const gUnk_080CBEF8[])(PestoEntity*);
extern const u8 gUnk_080CBF10[];
extern const u16 gUnk_080CBF18[];
extern const u8 gUnk_080CBF20[];
void Pesto(PestoEntity* this) {
Pesto_Functions[GetNextFunction(super)](this);
}
void Pesto_OnTick(PestoEntity* this) {
gUnk_080CBEDC[super->action](this);
}
void Pesto_OnCollision(PestoEntity* this) {
if (super->hitType != 0x6e) {
if (super->contactFlags == 0x80) {
this->unk_86 = 0x30;
if ((this->unk_83 & 0xf) == 3 && super->action == 6) {
switch (this->unk_80) {
case 1:
super->z.HALF.HI = -0x10;
this->unk_82 = 0;
this->unk_78 = -0x10;
this->unk_80++;
/* fallthrough */
case 2:
this->unk_83 &= ~0x80;
break;
}
}
}
} else {
super->health = 0;
}
EnemyFunctionHandlerAfterCollision(super, Pesto_Functions);
}
void Pesto_OnKnockback(PestoEntity* this) {
GenericKnockback(super);
GetNextFrame(super);
}
void Pesto_OnGrabbed(PestoEntity* this) {
if (super->subAction < 3 && !sub_0806F520(super)) {
super->action = 1;
super->subAction = 0;
COLLISION_ON(super);
super->hitType = 0x77;
super->timer = 1;
super->speed = 0x40;
} else {
gUnk_080CBEF8[super->subAction](this);
}
}
void sub_08024038(PestoEntity* this) {
super->subAction = 1;
super->gustJarTolerance = 60;
GetNextFrame(super);
}
void sub_08024048(PestoEntity* this) {
sub_0806F4E8(super);
GetNextFrame(super);
}
void sub_08024058(PestoEntity* this) {
sub_0806F3E4(super);
}
void sub_08024060(PestoEntity* this) {
if (super->hitType != 0x6e) {
COLLISION_OFF(super);
super->hitType = 0x6e;
super->spriteRendering.b3 = gPlayerEntity.base.spriteRendering.b3;
}
GetNextFrame(super);
}
void nullsub_138(PestoEntity* this) {
/* ... */
}
void sub_0802409C(PestoEntity* this) {
super->health = 0;
InitializeAnimation(super, super->animationState);
CreateDust(super);
}
void sub_080240B8(PestoEntity* this) {
u32 direction = (Random() & 0xc0) >> 3;
sub_0804A720(super);
super->action = 1;
super->subAction = 0;
this->unk_80 = 0;
if (direction & 8) {
super->y.HALF.HI += (direction & 0x10) ? -0x20 : 0x20;
} else {
super->x.HALF.HI += (direction & 0x10) ? -0x20 : 0x20;
}
switch (super->type) {
case 0:
this->unk_78 = -0x10;
super->z.HALF.HI = -0x10;
break;
case 1:
this->unk_78 = -0x30;
super->z.HALF.HI = -0x30;
break;
}
UpdateSpriteForCollisionLayer(super);
if (AreaIsDungeon())
super->spriteOrientation.flipY = 1;
this->unk_81 = Random() & 0x40;
this->unk_82 = 0;
this->unk_83 = 0x80;
this->unk_86 = 0;
this->unk_87 = 0;
super->timer = 0;
super->subtimer = 32;
super->collisionFlags |= 0x10;
super->gustJarFlags = 2;
super->direction = direction;
sub_080249DC(this);
if (super->type == 1) {
Entity* entity;
this->unk_83 = 0;
entity = CreateProjectileWithParent(super, DIRT_BALL_PROJECTILE, this->unk_83);
if (entity != NULL) {
super->child = entity;
entity->parent = super;
entity->y.HALF.HI += 0x10;
}
}
}
void sub_080241C0(PestoEntity* this) {
sub_08024940(this);
switch (this->unk_80) {
case 0:
if (PlayerInRange(super, 3, (gPlayerState.hurtBlinkSpeed != 0) ? 0xa0 : 0x40) && sub_08049FDC(super, 3) &&
gPlayerEntity.base.action != PLAYER_USEENTRANCE) {
this->unk_80++;
super->speed = 0;
sub_08024A14(this, 3, 10);
} else if (--super->subtimer == 0) {
sub_08024A14(this, 0, 0x20);
}
break;
case 1:
if (--super->subtimer == 0) {
if (super->type != 0) {
u8 tmp = this->unk_83 & 0x80;
if (tmp) {
sub_08024C94(this);
this->unk_83 |= 0x40;
} else {
super->action = 3;
this->unk_80 = tmp;
super->subtimer = 10;
sub_08024E00(this, 0);
sub_08024E1C(this);
sub_08024A14(this, 3, super->subtimer);
}
} else {
sub_08024C94(this);
}
}
break;
}
}
void sub_08024298(PestoEntity* this) {
sub_08024D00(this);
}
void sub_080242A0(PestoEntity* this) {
sub_08024940(this);
if (sub_08024CC0(this)) {
if (--super->timer == 0) {
super->direction = GetFacingDirection(super, gUnk_020000B0);
sub_08024E00(this, 1);
if (super->speed != 0) {
super->speed = 0;
} else {
sub_08024E1C(this);
}
} else if (--super->subtimer == 0) {
sub_08024A14(this, 3, 10);
}
if (sub_08049F1C(super, gUnk_020000B0, 0x20) && sub_08049FDC(super, 3)) {
super->action = 4;
this->unk_80 = 0;
super->timer = 16;
super->speed = 0;
}
}
}
void sub_0802433C(PestoEntity* this) {
sub_08024940(this);
switch (this->unk_80) {
case 0:
if (--super->timer == 0) {
this->unk_80++;
super->speed = 0x100;
super->subtimer = 8;
sub_08024E00(this, 1);
}
break;
case 1:
if (--super->timer == 0) {
super->action = 5;
this->unk_80 = 0;
super->speed = 0x140;
super->timer = 192;
super->subtimer = 8;
} else {
if (--super->subtimer == 0)
sub_08024A14(this, 2, 4);
}
break;
}
}
void sub_080243B8(PestoEntity* this) {
sub_08024940(this);
switch (this->unk_80) {
case 0:
if (sub_08024C48(this, TRUE)) {
if (super->child == NULL || super->child->next == NULL) {
this->unk_80 = 2;
super->timer = 32;
super->speed = 0x80;
this->unk_83 = 0x80;
} else if (sub_08049F1C(super, gUnk_020000B0, 0xe)) {
this->unk_80++;
super->timer = 30;
super->speed = 0x100;
this->unk_83 = 0x80;
super->child->action = 2;
} else if (--super->timer != 0) {
if (--super->subtimer == 0) {
sub_08024A14(this, 2, (super->timer >> 6) + 1);
}
} else {
sub_08024C7C(this);
}
} else {
sub_08024C7C(this);
}
break;
case 1:
if (--super->timer == 0) {
this->unk_80++;
super->timer = 32;
super->speed = 0x80;
}
break;
case 2:
if (--super->timer == 0) {
super->action = 6;
this->unk_80 = 0;
super->speed = 0x80;
sub_08024B38(this);
if ((this->unk_83 & 0x40) == 0) {
switch (this->unk_83 & 0x3f) {
case 3:
super->timer = 4;
break;
case 1:
super->timer = 20;
break;
default:
super->timer = 48;
break;
}
sub_08024A14(this, 2, 8);
} else {
super->timer = 64;
sub_08024A14(this, 0, 8);
}
}
break;
}
}
void sub_080244E8(PestoEntity* this) {
sub_08024940(this);
switch (this->unk_80) {
case 0:
if (--super->timer == 0) {
if (GetCollisionDataAtMetaTilePos(COORD_TO_TILE(super), 1) == 0) {
this->unk_80++;
this->unk_82++;
super->subtimer = 0;
super->speed = 0;
} else {
super->timer = 48;
super->subtimer = 4;
}
break;
} else {
if (--super->subtimer == 0) {
sub_08024A14(this, 1, 8);
}
}
break;
case 1:
if (++super->z.HALF.HI >= -0x10) {
this->unk_82 = 0;
this->unk_78 = -16;
if (sub_08024AD8(this)) {
this->unk_80++;
} else {
sub_08024C94(this);
this->unk_83 |= 0x40;
}
}
break;
case 2:
if (sub_08024AD8(this)) {
u32 tmp;
if (--super->timer == 0) {
if (super->speed) {
super->speed = 0;
} else {
sub_08024E1C(this);
}
super->direction = GetFacingDirection(super, super->child);
sub_08024E00(this, 0);
sub_080249DC(this);
} else if (--super->subtimer == 0) {
sub_08024A14(this, 1, 8);
}
switch (this->unk_83 & 0x3f) {
case 3:
tmp = this->unk_83 & 0x80;
if (tmp == 0) {
this->unk_80++;
super->timer = 12;
super->direction = DirectionSouth;
super->speed = tmp;
this->unk_84 = 0;
super->flags2 &= 0xfc;
sub_080249DC(this);
this->unk_85 = gPlayerEntity.base.spritePriority.b1;
gPlayerEntity.base.flags &= ~ENT_COLLIDE;
gPlayerState.flags |= PL_DISABLE_ITEMS;
gPlayerState.field_0xa |= 0x80;
if (gPlayerState.swim_state != 0) {
gPlayerState.swim_state = 0;
}
}
break;
case 1:
if (EntityInRectRadius(super, super->child, 6, 6)) {
Entity* entity;
this->unk_80++;
super->timer = 12;
this->unk_83 &= ~0x80;
CopyPosition(super->child, super);
super->z.HALF.HI -= 0xe;
this->unk_78 -= 0xe;
entity = CreateProjectileWithParent(super, DIRT_BALL_PROJECTILE, this->unk_83);
if (entity != NULL) {
entity->parent = super;
entity->z.HALF.HI += 0xe;
entity->child = super->child;
CopyPosition(entity, entity->child);
super->child = entity;
}
}
break;
case 2:
if (EntityInRectRadius(super, super->child, 6, 6)) {
Entity* entity;
this->unk_80++;
super->timer = 12;
this->unk_83 &= ~0x80;
entity = super->child;
SetMetaTile(((PestoEntity*)entity)->unk_70, COORD_TO_TILE(entity), entity->collisionLayer);
DeleteEntity(entity);
super->z.HALF.HI -= 0xe;
this->unk_78 -= 0xe;
entity = CreateProjectileWithParent(super, DIRT_BALL_PROJECTILE, this->unk_83);
if (entity != NULL) {
entity->parent = super;
entity->z.HALF.HI += 0xe;
super->child = entity;
}
}
break;
}
break;
} else {
sub_08024C94(this);
this->unk_83 |= 0x40;
}
break;
case 3:
if (--super->timer == 0) {
this->unk_80++;
super->subtimer = 0;
super->speed = 0;
this->unk_82++;
}
break;
case 4:
super->z.HALF.HI -= 2;
if (-60 > super->z.HALF.HI) {
this->unk_80++;
}
break;
case 5:
if (super->z.HALF.HI < -0x30) {
super->z.HALF.HI++;
} else {
if (this->unk_82 != 0) {
this->unk_82 = 0;
this->unk_78 = -0x30;
}
switch (this->unk_83) {
case 3:
if (0x2f < this->unk_84) {
sub_08024F50(this);
}
break;
case 1 ... 2:
this->unk_80++;
super->timer = 192;
super->subtimer = 8;
super->speed = 0x80;
sub_080249DC(this);
break;
default:
sub_08024C7C(this);
break;
}
}
break;
case 6:
if (--super->timer == 0) {
if (this->unk_83 & 0x80) {
this->unk_83 = 0xc0;
this->unk_80 = 0;
super->speed = 0x40;
super->timer = 64;
super->subtimer = 8;
sub_08024A14(this, 0, 8);
} else {
super->timer = 64;
super->subtimer = 8;
}
} else if (--super->subtimer == 0) {
sub_08024A14(this, 2, 8);
}
break;
case 7:
if (gPlayerEntity.base.z.HALF.HI == 0) {
this->unk_80 = 0;
super->speed = 0x80;
sub_08024B38(this);
}
}
if (this->unk_83 == 3) {
sub_08024E4C(this);
}
}
void sub_08024940(PestoEntity* this) {
u32 random = Random() & 0x70;
if (super->collisions != COL_NONE) {
sub_0800417E(super, super->collisions);
sub_080249F4(this);
}
if (this->unk_82 == 0) {
super->z.HALF.HI = this->unk_78;
if (random)
super->z.HALF.HI += 2;
}
if (super->type2 != 0 || AreaIsDungeon()) {
if (!sub_08049FA0(super)) {
super->direction = sub_08049EE4(super);
sub_080249F4(this);
}
if (super->z.HALF.HI < -0x20) {
super->spritePriority.b0 = 0;
} else {
super->spritePriority.b0 = 1;
}
}
ProcessMovement1(super);
GetNextFrame(super);
}
void sub_080249DC(PestoEntity* this) {
u8 direction = ((super->direction + 2) & DirectionNorthWest) >> 2;
super->animationState = direction;
InitializeAnimation(super, super->animationState);
}
void sub_080249F4(PestoEntity* this) {
u32 direction = ((super->direction + 2) & (0x3 | DirectionNorthWest));
direction >>= 2;
if (direction != super->animationState) {
super->animationState = direction;
InitializeAnimation(super, super->animationState);
}
}
void sub_08024A14(PestoEntity* this, u32 param_2, u32 param_3) {
u8 unk = FALSE;
switch (param_2) {
case 0:
sub_08004596(super, sub_08049EE4(super));
unk = TRUE;
break;
case 1:
if (sub_08024C48(this, FALSE)) {
sub_08004596(super, GetFacingDirection(super, super->child));
unk = TRUE;
}
break;
case 2:
if (sub_08024C48(this, TRUE)) {
sub_08004596(super, GetFacingDirection(super, gUnk_020000B0));
unk = TRUE;
}
break;
case 3:
if (sub_08024C48(this, TRUE)) {
super->direction = GetFacingDirection(super, gUnk_020000B0);
unk = TRUE;
}
break;
}
if (param_2 != 0 && !sub_08049FA0(super) && (Random() & 3)) {
unk = FALSE;
}
if (!unk) {
sub_08024A14(this, 0, param_3);
}
sub_080249DC(this);
super->subtimer = param_3;
}
bool32 sub_08024AD8(PestoEntity* this) {
if ((this->unk_83 & 0x40) == 0) {
u8 unk = FALSE;
if ((this->unk_83 & 0x3f) == 3) {
if (gPlayerState.hurtBlinkSpeed == 0) {
super->child->parent = NULL;
super->child = NULL;
this->unk_83 = 0xc0;
return FALSE;
}
unk = TRUE;
}
if (sub_08024C48(this, unk) == 0) {
super->child = NULL;
this->unk_83 = 0xc0;
return FALSE;
}
} else {
return sub_08024B38(this);
}
return TRUE;
}
bool32 sub_08024B38(PestoEntity* this) {
int iVar4 = 0;
Entity* entity;
if (gPlayerState.hurtBlinkSpeed != 0) {
if (gPlayerState.swim_state == 1) {
if (gPlayerState.hurtBlinkSpeed > 3) {
gPlayerState.hurtBlinkSpeed -= 3;
} else {
gPlayerState.hurtBlinkSpeed = 0;
}
}
if (gPlayerState.hurtBlinkSpeed != 0) {
if (sub_08024C48(this, 1) && sub_08049F1C(super, gUnk_020000B0, 0xa0)) {
iVar4 = 1;
super->child = gUnk_020000B0;
this->unk_83 |= 3;
this->unk_83 &= ~0x40;
}
if (iVar4 == 0) {
super->child = NULL;
}
return iVar4;
}
}
entity = FindEntityByID(PLAYER_ITEM, PLAYER_ITEM_BOMB, 2);
if (entity != NULL) {
do {
if (entity->action != 2 && entity->z.HALF.HI == 0 && sub_08049F1C(super, entity, 0xa0)) {
iVar4 = 1;
super->child = entity;
this->unk_83 |= 1;
this->unk_83 &= ~0x40;
break;
}
} while (entity = FindNextDuplicateID(entity, 2), entity != NULL);
}
if (iVar4 != 0) {
return iVar4;
}
entity = FindEntityByID(OBJECT, POT, 6);
if (entity != NULL) {
do {
if (entity->action == 1 && sub_08049F1C(super, entity, 0xa0)) {
iVar4 = 1;
super->child = entity;
this->unk_83 |= 2;
this->unk_83 &= ~0x40;
break;
}
} while (entity = FindNextDuplicateID(entity, 6), entity != NULL);
}
if (iVar4 == 0) {
super->child = NULL;
}
return iVar4;
}
bool32 sub_08024C48(PestoEntity* this, bool32 unk) {
bool32 rv = TRUE;
u32 val;
if (unk) {
if (sub_08049DF4(3)) {
rv = TRUE;
} else {
rv = FALSE;
}
} else {
if (super->child == NULL) {
super->child = NULL;
rv = FALSE;
} else if (super->child->next == NULL) {
super->child = NULL;
rv = FALSE;
} else if (super->child->z.HALF.HI < 0) {
super->child = NULL;
rv = FALSE;
}
}
return rv;
}
void sub_08024C7C(PestoEntity* this) {
super->action = 1;
super->speed = 0x40;
super->timer = 0;
sub_08024A14(this, 0, 0x20);
}
void sub_08024C94(PestoEntity* this) {
super->action = 2;
this->unk_80 = 0;
super->timer = 64;
super->subtimer = 0;
super->speed = 0xc0;
this->unk_83 = 0x80;
sub_08024A14(this, 3, super->subtimer);
}
bool32 sub_08024CC0(PestoEntity* this) {
bool32 uVar2;
uVar2 = TRUE;
if (!sub_08024C48(this, 1)) {
uVar2 = FALSE;
} else if (!sub_08049F1C(super, gUnk_020000B0, 0x50) || !sub_08049FDC(super, 3)) {
uVar2 = FALSE;
sub_08024C7C(this);
}
return uVar2;
}
void sub_08024D00(PestoEntity* this) {
if (this->unk_86) {
this->unk_86--;
GetNextFrame(super);
} else {
sub_08024940(this);
}
if ((this->unk_83 & 0x40) && sub_08024B38(this)) {
super->action = 6;
this->unk_80 = 2;
} else if (sub_08024CC0(this)) {
switch (this->unk_80) {
case 0:
if (--super->timer == 0) {
this->unk_80++;
super->timer = (Random() & 0xf) + 32;
super->direction += this->unk_81 ? DirectionNorthEast : DirectionNorthWest;
super->direction &= 0x3 | DirectionNorthWest;
this->unk_81 ^= 0x40;
sub_08024A14(this, 3, 0x10);
}
break;
case 1:
if (--super->timer == 0) {
this->unk_80 = 0;
super->timer = (Random() & 0x1f) + 32;
} else {
if (--super->subtimer == 0) {
super->direction += this->unk_81 ? 1 : (0x3 | DirectionNorthWest);
super->direction &= 0x3 | DirectionNorthWest;
super->subtimer = 16;
sub_080249DC(this);
}
}
break;
}
}
}
void sub_08024E00(PestoEntity* this, u32 unk) {
super->timer = gUnk_080CBF10[sub_08024E34() * 2 | unk];
}
void sub_08024E1C(PestoEntity* this) {
super->speed = gUnk_080CBF18[sub_08024E34()];
}
u32 sub_08024E34(void) {
u32 idx = (Random() & 0x3c) >> 2;
return gUnk_080CBF20[idx];
}
void sub_08024E4C(PestoEntity* this) {
if (this->unk_83 == 3) {
super->subtimer = ++super->subtimer & 0x1f;
if (sub_0807953C()) {
u32 r = Random();
this->unk_84++;
r &= 1;
this->unk_84 += r;
}
if (gSave.stats.health == 0 || this->unk_87 == 4) {
this->unk_84 = 0x30;
this->unk_87 = 0;
sub_08024F50(this);
this->unk_80 = 0;
super->speed = 0x40;
super->timer = 64;
super->subtimer = 8;
sub_08024A14(this, 0, 8);
} else {
Entity* player = &gPlayerEntity.base;
ResetActiveItems();
gPlayerState.flags |= PL_DISABLE_ITEMS;
gPlayerState.field_0xa |= 0x80;
gPlayerState.queued_action = PLAYER_0807204C;
gPlayerState.field_0x38 = 0x14;
gPlayerState.field_0x39 = 1;
*(u8*)&gPlayerState.field_0x3a = 0;
PositionRelative(super, player, 0, Q_16_16(1.0));
player->spriteOffsetY = 0x1a;
player->animationState = 4;
player->spritePriority.b1 = 0;
if (super->subtimer == 0) {
this->unk_87++;
player->iframes = 8;
ModHealth(-2);
SoundReqClipped(player, SFX_PLY_VO6);
}
}
}
}
void sub_08024F50(PestoEntity* this) {
gPlayerState.field_0xa = 0;
gPlayerState.flags &= ~PL_DISABLE_ITEMS;
CopyPosition(super, &gPlayerEntity.base);
gPlayerEntity.base.action = PLAYER_NORMAL;
COLLISION_ON(&gPlayerEntity.base);
gPlayerEntity.base.iframes = -0x3c;
gPlayerEntity.base.direction = gPlayerEntity.base.animationState << 2;
gPlayerEntity.base.speed = 0;
gPlayerEntity.base.spritePriority.b1 = this->unk_85;
gPlayerEntity.base.z.HALF.HI = gPlayerEntity.base.spriteOffsetY;
gPlayerEntity.base.spriteOffsetY = 0;
super->flags2 |= 3;
this->unk_83 = 0xc0;
this->unk_80 += 2;
this->unk_84 = 0;
super->speed = 0x80;
}
// clang-format off
void (*const Pesto_Functions[])(PestoEntity*) = {
Pesto_OnTick,
Pesto_OnCollision,
Pesto_OnKnockback,
(void (*)(PestoEntity*))GenericDeath,
(void (*)(PestoEntity*))GenericConfused,
Pesto_OnGrabbed,
};
void (*const gUnk_080CBEDC[])(PestoEntity*) = {
sub_080240B8,
sub_080241C0,
sub_08024298,
sub_080242A0,
sub_0802433C,
sub_080243B8,
sub_080244E8,
};
void (*const gUnk_080CBEF8[])(PestoEntity*) = {
sub_08024038,
sub_08024048,
sub_08024058,
sub_08024060,
nullsub_138,
sub_0802409C,
};
const u8 gUnk_080CBF10[] = {
30, 60, 50, 90, 70, 100, 90, 120,
};
const u16 gUnk_080CBF18[] = {
0x80, 0xC0, 0x100, 0x140,
};
const u8 gUnk_080CBF20[] = {
0, 2, 1, 1, 3, 1, 2, 0,
1, 1, 2, 3, 2, 2, 1, 2,
};
// clang-format on