Files
tmc/src/enemy/businessScrub.c
T
notyourav 8dfc9f47f2 Merge pull request #330 from hatal175/playeractions
Use PlayerActions enum in several places
2022-01-29 22:43:26 -08:00

613 lines
16 KiB
C

/**
* @file businessScrub.c
* @ingroup Enemies
*
* @brief Business Scrub enemy
*/
#include "asm.h"
#include "enemy.h"
#include "message.h"
#include "save.h"
#include "npc.h"
#include "functions.h"
#include "game.h"
#include "item.h"
bool32 sub_0802915C(Entity*);
bool32 sub_080291DC(Entity*);
void sub_0802922C(Entity*);
void sub_08028E9C(Entity*);
void sub_08028FFC(Entity*);
void sub_0802925C(Entity*);
void sub_080290E0(Entity*, u32);
bool32 sub_08028F98(Entity*, u32);
void sub_08029078(Entity*);
bool32 sub_08028FDC(Entity*);
void sub_080290FC(Entity*);
void sub_08028EDC(Entity*);
extern const struct SalesOffering gUnk_080CC954[];
extern const u8 gUnk_080CC9C0[];
extern void (*const gUnk_080CC9C8[])(Entity*);
extern void (*const gUnk_080CC9E0[])(Entity*);
extern const u8 gUnk_080CCA04[];
struct SalesOffering {
u8 field_0x0;
u8 field_0x1;
u16 price;
u16 field_0x4;
u16 field_0x6;
u8 field_0x8;
u8 field_0x9;
u16 field_0xa;
};
void BusinessScrub(Entity* this) {
EnemyFunctionHandler(this, gUnk_080CC9C8);
}
void sub_0802891C(Entity* this) {
gUnk_080CC9E0[this->action](this);
}
void sub_08028934(Entity* this) {
Entity* pEVar1;
if (this->hitType == 1 && (this->bitfield & 0x7f) == 0x42) {
this->action = 3;
this->subAction = 0;
this->actionDelay = 0x28;
COLLISION_OFF(this);
sub_080290E0(this, 4);
pEVar1 = CreateFx(this, FX_BUSH, 0);
if (pEVar1 != NULL) {
pEVar1->z.HALF.HI -= 8;
}
EnqueueSFX(SFX_EM_DEKUSCRUB_HIT);
}
}
void nullsub_140(Entity* this) {
/* ... */
}
void sub_08028994(Entity* this) {
this->field_0xf = 0;
this->field_0x78.HWORD = this->x.HALF.HI;
this->field_0x7a.HWORD = this->y.HALF.HI;
this->animationState = 0;
this->direction = 0x10;
sub_08028E9C(this);
if ((*(u8*)this->field_0x7c.WORD & 1) || CheckFlags(this->field_0x86.HWORD)) {
this->action = 4;
this->actionDelay = 0x78;
this->spritePriority.b1 = 1;
sub_0802925C(this);
sub_080290E0(this, 0);
} else {
this->actionDelay = 0;
this->field_0x76.HWORD = COORD_TO_TILE(this);
this->field_0x74.HWORD = GetTileIndex(this->field_0x76.HWORD, this->collisionLayer);
this->hurtType = 0x41;
sub_08028FFC(this);
}
}
void sub_08028A48(Entity* this) {
if (this->actionDelay) {
this->actionDelay--;
} else if (sub_08028F98(this, 0)) {
sub_08029078(this);
this->subAction = 0;
this->field_0xf = 1;
}
}
void sub_08028A74(Entity* this) {
u32 unk;
GetNextFrame(this);
switch (this->subAction) {
case 0:
unk = 1;
if (this->frame & 0x80) {
this->subAction = 1;
this->actionDelay = 0x3c;
this->field_0xf = 0x10;
sub_08028FDC(this);
sub_080290E0(this, 1);
}
break;
case 1:
unk = 1;
if (--this->actionDelay == 0) {
this->subAction = 2;
this->actionDelay = 0x20;
this->field_0xf = 0;
sub_08028FDC(this);
sub_080290E0(this, 2);
} else if (--this->field_0xf == 0) {
if (sub_08028FDC(this)) {
sub_080290E0(this, 1);
}
this->field_0xf = 0x10;
}
break;
case 2:
unk = 1;
sub_080290FC(this);
if (this->frame & 1) {
Entity* ent = CreateProjectileWithParent(this, 4, 0);
if (ent != NULL) {
ent->parent = this;
ent->direction = this->direction;
this->frame &= ~1;
this->subAction = 3;
}
}
break;
case 3:
unk = 2;
if (this->frame & 0x80) {
this->subAction = 4;
this->actionDelay = 0x50;
sub_080290E0(this, 1);
}
break;
case 4:
unk = 2;
if (--this->actionDelay == 0) {
if (sub_08028F98(this, 0)) {
this->subAction = 1;
this->actionDelay = 0x3c;
this->field_0xf = 0x10;
sub_08028FDC(this);
} else {
sub_08028FFC(this);
this->subAction = 0;
this->actionDelay = 0x50;
this->field_0xf = 0;
}
return;
}
break;
}
if (!sub_08028F98(this, unk)) {
sub_08028FFC(this);
this->subAction = 0;
this->actionDelay = 0x50;
this->field_0xf = 0;
}
}
void sub_08028BC4(Entity* this) {
Entity* iVar1;
switch (this->subAction) {
case 0:
if (this->actionDelay == 0) {
if (this->frame & 0x80) {
this->subAction = 1;
sub_08028FDC(this);
sub_080290E0(this, 5);
this->spritePriority.b1 = 1;
}
} else {
this->actionDelay--;
}
break;
case 1:
if (this->frame & 0x80) {
this->action = 4;
this->subAction = 0;
this->actionDelay = 0x1e;
this->field_0xf = 5;
sub_080290E0(this, 0);
iVar1 = sub_0804A9FC(this, 0x1c);
if (iVar1 != NULL) {
iVar1->spritePriority.b0 = 3;
iVar1->z.HALF.HI -= 12;
SetDefaultPriority(iVar1, PRIO_MESSAGE);
}
SetFlag(this->field_0x86.HWORD);
sub_0802925C(this);
}
break;
}
GetNextFrame(this);
sub_0800445C(this);
}
extern void sub_0804AA1C(Entity*);
void sub_08028F0C(Entity*);
void sub_08028C84(Entity* this) {
if (--this->actionDelay == 0) {
this->actionDelay = 0x30;
if (this->field_0xf) {
if (--this->field_0xf == 0) {
sub_0804AA1C(this);
}
} else if (sub_08028FDC(this) || this->field_0x80.HALF.LO) {
this->field_0x80.HALF.LO = 0;
sub_080290E0(this, 0);
}
}
GetNextFrame(this);
sub_0800445C(this);
sub_08028F0C(this);
}
void sub_08028CE8(Entity* this) {
struct SalesOffering* offer = (struct SalesOffering*)this->field_0x7c.WORD;
u32 subtype;
if ((gMessage.doTextBox & 0x7f) == 0 && sub_0802915C(this) && !sub_08056338()) {
if (offer->price <= gSave.stats.rupees) {
if (sub_080291DC(this)) {
/* Bag full. */
MessageFromTarget(0x2904);
SetPlayerControl(0);
} else {
ModRupees(-offer->price);
switch (offer->field_0x0 >> 2) {
case 0:
subtype = offer->field_0x9;
if (subtype == 0xff) {
subtype = gUnk_080CC9C0[Random() & 7];
}
CreateItemEntity(offer->field_0x8, subtype, 0);
this->action = 6;
this->actionDelay = 4;
this->field_0x80.HALF.HI = 0;
sub_080290E0(this, 3);
#if defined(USA) || defined(DEMO_USA)
SetLocalFlag(KS_B06);
#endif
return;
case 1:
CreateItemEntity(offer->field_0x8, offer->field_0x9, 0);
this->actionDelay = 4;
sub_0802922C(this);
return;
case 2:
CreateItemEntity(offer->field_0x8, offer->field_0x9, 0);
this->actionDelay = 8;
sub_0802922C(this);
return;
}
}
} else {
/* Not enough money. */
MessageFromTarget(0x2903);
SetPlayerControl(0);
}
}
sub_0800445C(this);
this->action = 4;
this->actionDelay = 0x30;
sub_080290E0(this, 0);
}
void sub_08028DE8(Entity* this) {
if (gPlayerEntity.action == PLAYER_ITEMGET) {
if (this->field_0x80.HALF.HI == 0) {
SetPlayerControl(1);
this->field_0x80.HALF.HI = 1;
}
} else {
MessageFromTarget(0x2902);
this->action = 4;
this->field_0x80.HALF.HI = 0;
this->actionDelay = 1;
sub_08028EDC(this);
SetPlayerControl(0);
sub_0800445C(this);
GetNextFrame(this);
}
}
void sub_08028E40(Entity* this) {
if ((gMessage.doTextBox & 0x7f) == 0) {
struct SalesOffering* offer = (struct SalesOffering*)this->field_0x7c.WORD;
this->action = 4;
this->subAction = gMessage.doTextBox & 0x7f;
this->actionDelay = 1;
if (CheckLocalFlag(offer->field_0xa) == 0) {
SetLocalFlag(offer->field_0xa);
}
SetPlayerControl(0);
}
sub_0800445C(this);
GetNextFrame(this);
}
void sub_08028E84(Entity* this) {
if (UpdateFuseInteraction(this)) {
this->action = 4;
this->actionDelay = 1;
}
}
bool32 sub_08029198(const struct SalesOffering*);
void sub_08028E9C(Entity* this) {
const struct SalesOffering* offer = &gUnk_080CC954[this->type];
if (sub_08029198(offer) && (offer->field_0x0 & 2)) {
offer = &gUnk_080CC954[offer->field_0xa];
}
this->field_0x7c.WORD = (u32)offer;
this->field_0x80.HALF.LO = 0;
}
void sub_08028EDC(Entity* this) {
const struct SalesOffering* offer = (const struct SalesOffering*)this->field_0x7c.WORD;
if (sub_08029198(offer) && (offer->field_0x0 & 2)) {
offer = &gUnk_080CC954[offer->field_0xa];
this->field_0x7c.WORD = (u32)offer;
}
}
void sub_08028F0C(Entity* this) {
if (this->interactType == 2) {
this->action = 8;
this->interactType = 0;
sub_0806F118(this);
} else if (this->interactType != 0) {
u16 dialog;
const struct SalesOffering* offer = (const struct SalesOffering*)this->field_0x7c.WORD;
this->interactType = 0;
sub_0804AA1C(this);
this->direction = (GetAnimationState(this) << 3);
sub_080290E0(this, 3);
this->field_0x80.HALF.LO = 1;
this->actionDelay = 0x20;
this->field_0xf = 0;
if (sub_08029198(offer)) {
dialog = offer->field_0x6;
} else {
if ((offer->field_0x0 & 0xfc) != 0xc) {
this->action = 5;
} else {
this->action = 7;
}
dialog = offer->field_0x4;
SetPlayerControl(1);
}
MessageFromTarget(dialog);
gMessage.field_0x10 = offer->price;
}
}
bool32 sub_08028F98(Entity* this, u32 param_2) {
Entity* ent = sub_08049DF4(1);
if (ent == NULL || EntityInRectRadius(this, ent, 0x28, 0x28)) {
return FALSE;
}
if (param_2 != 2) {
u32 distance = param_2 ? 0x58 : 0x50;
if (!EntityInRectRadius(this, ent, distance, distance)) {
return FALSE;
}
}
return TRUE;
}
bool32 sub_08028FDC(Entity* this) {
u32 direction = DirectionRoundUp(sub_08049F84(this, 1));
if (direction == this->direction) {
return FALSE;
} else {
this->direction = direction;
return TRUE;
}
}
void sub_08028FFC(Entity* this) {
this->action = 1;
COLLISION_OFF(this);
this->spritePriority.b1 = 0;
sub_080AE068(this);
UnloadOBJPalette(this);
this->spriteVramOffset = 0xe8;
this->palette.b.b0 = 2;
this->palette.b.b4 = 2;
this->spriteIndex = 0xa7;
this->x.HALF.HI = this->field_0x78.HWORD;
this->y.HALF.HI = this->field_0x7a.HWORD;
InitializeAnimation(this, 0);
SetTile(0x4022, this->field_0x76.HWORD, this->collisionLayer);
}
void sub_08029078(Entity* this) {
this->action = 2;
COLLISION_ON(this);
this->spritePriority.b1 = 1;
if (LoadFixedGFX(this, 0x72) == 0) {
DeleteEntity(this);
} else {
LoadObjPalette(this, 0x6e);
this->spriteIndex = 0xd0;
sub_08028FDC(this);
sub_080290E0(this, 1);
SetTile(this->field_0x74.HWORD, this->field_0x76.HWORD, this->collisionLayer);
}
}
void sub_080290E0(Entity* this, u32 param_2) {
InitializeAnimation(this, this->direction >> 3 | gUnk_080CCA04[param_2]);
}
void sub_080290FC(Entity* this) {
if (this->actionDelay != 0) {
if (--this->actionDelay < 0x10 && (this->actionDelay & 1) == 0) {
s32 sVar3 = (this->direction & 0x10) ? -1 : 1;
if ((this->direction & 8)) {
this->x.HALF.HI += (this->actionDelay & 8) ? -sVar3 : sVar3;
} else {
this->y.HALF.HI += (this->actionDelay & 8) ? sVar3 : -sVar3;
}
}
}
}
bool32 sub_0802915C(Entity* this) {
const struct SalesOffering* offer = (const struct SalesOffering*)this->field_0x7c.WORD;
switch (offer->field_0x8) {
case 0x44:
if (GetInventoryValue(0x44) == 0)
return TRUE;
break;
case 0x1c:
if (CheckGlobalFlag(AKINDO_BOTTLE_SELL) == 0)
return TRUE;
break;
case 0x5c:
case 0x6c:
case 0x6f:
return TRUE;
}
return FALSE;
}
bool32 sub_08029198(const struct SalesOffering* offer) {
u32 tmp;
if ((offer->field_0x0 & 0xfc) != 0xc) {
switch (offer->field_0x8) {
case 0x1c:
tmp = CheckGlobalFlag(AKINDO_BOTTLE_SELL);
break;
case 0x9:
case 0x44:
tmp = GetInventoryValue(offer->field_0x8);
break;
default:
return 0;
}
} else {
tmp = CheckLocalFlag(offer->field_0xa);
}
if (tmp == 0) {
return FALSE;
}
return TRUE;
}
bool32 sub_080291DC(Entity* this) {
const struct SalesOffering* offer = (const struct SalesOffering*)this->field_0x7c.WORD;
switch (offer->field_0x8) {
case 0x6c:
if (gBombBagSizes[gSave.stats.bombBagType] <= gSave.stats.bombCount)
return TRUE;
break;
case 0x6f:
if (gQuiverSizes[gSave.stats.quiverType] <= gSave.stats.arrowCount)
return TRUE;
break;
}
return FALSE;
}
NONMATCH("asm/non_matching/businessScrub/sub_0802922C.inc", void sub_0802922C(Entity* this)) {
const struct SalesOffering* offer = (const struct SalesOffering*)this->field_0x7c.WORD;
this->action = 6;
this->field_0x80.HALF.HI = 0;
switch (offer->field_0x8) {
case 0x1c:
SetGlobalFlag(AKINDO_BOTTLE_SELL);
break;
}
sub_080290E0(this, 3);
}
END_NONMATCH
void sub_0802925C(Entity* this) {
sub_08078784(this, sub_0801E99C(this));
}
void sub_08029270(Entity* this) {
if (this->action == 0) {
this->action++;
this->spriteSettings.draw = 1;
InitializeAnimation(this, 0xe);
} else {
GetNextFrame(this);
}
}
// clang-format off
const struct SalesOffering gUnk_080CC954[] = {
{0x06, 0x00, 0xffff, 0x290f, 0x2902, 0x09, 0xff, 0x0001},
{0x04, 0x00, 0x001e, 0x290e, 0x2902, 0x6f, 0xff, 0xffff},
{0x04, 0x00, 0x001e, 0x290b, 0x2902, 0x6c, 0xff, 0xffff},
{0x08, 0x00, 0x0028, 0x290c, 0x2911, 0x44, 0xff, 0xffff},
{0x00, 0x00, 0x0064, 0x290d, 0x2902, 0x5c, 0xff, 0xffff},
{0x04, 0x00, 0x0014, 0x2910, 0x2911, 0x1c, 0xff, 0xffff},
{0x0c, 0x00, 0xffff, 0x2912, 0x2913, 0xff, 0xff, 0x0046},
{0x04, 0x00, 0x0064, 0x2913, 0x2902, 0x5c, 0x75, 0xffff},
#ifdef EU
{0x00, 0x00, 0x0064, 0x290d, 0x2902, 0x5c, 0xff, 0xffff},
#else
{0x00, 0x00, 0x00C8, 0x290d, 0x2902, 0x5c, 0xff, 0xffff},
#endif
};
const u8 gUnk_080CC9C0[] = {
0x6e,
0x6f,
0x70,
0x71,
0x72,
0x73,
0x74,
0x75,
};
void (*const gUnk_080CC9C8[])(Entity*) = {
sub_0802891C,
sub_08028934,
sub_08001324,
sub_0804A7D4,
sub_08001242,
nullsub_140,
};
void (*const gUnk_080CC9E0[])(Entity*) = {
sub_08028994,
sub_08028A48,
sub_08028A74,
sub_08028BC4,
sub_08028C84,
sub_08028CE8,
sub_08028DE8,
sub_08028E40,
sub_08028E84,
};
const u8 gUnk_080CCA04[] = {
0, 4, 8, 12, 16, 20,
};
// clang-format on