Shipwright/soh/src/overlays/actors/ovl_En_Wonder_Item/z_en_wonder_item.c

365 lines
14 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* File: z_en_wonder_item.c
* Overlay: ovl_En_Wonder_Item
* Description: Invisible Collectable; Used in MQ to create "Cow" switches
*/
#include "z_en_wonder_item.h"
#include "vt.h"
#define FLAGS 0
void EnWonderItem_Init(Actor* thisx, GlobalContext* globalCtx);
void EnWonderItem_Destroy(Actor* thisx, GlobalContext* globalCtx);
void EnWonderItem_Update(Actor* thisx, GlobalContext* globalCtx);
void EnWonderItem_MultitagFree(EnWonderItem* this, GlobalContext* globalCtx);
void EnWonderItem_ProximityDrop(EnWonderItem* this, GlobalContext* globalCtx);
void EnWonderItem_InteractSwitch(EnWonderItem* this, GlobalContext* globalCtx);
void EnWonderItem_ProximitySwitch(EnWonderItem* this, GlobalContext* globalCtx);
void EnWonderItem_MultitagOrdered(EnWonderItem* this, GlobalContext* globalCtx);
void EnWonderItem_BombSoldier(EnWonderItem* this, GlobalContext* globalCtx);
void EnWonderItem_RollDrop(EnWonderItem* this, GlobalContext* globalCtx);
static ColliderCylinderInit sCylinderInit = {
{
COLTYPE_NONE,
AT_NONE,
AC_ON | AC_TYPE_PLAYER,
OC1_NONE,
OC2_TYPE_2,
COLSHAPE_CYLINDER,
},
{
ELEMTYPE_UNK0,
{ 0x00000000, 0x00, 0x00 },
{ 0xFFCFFFFF, 0x00, 0x00 },
TOUCH_NONE,
BUMP_ON,
OCELEM_NONE,
},
{ 20, 30, 0, { 0, 0, 0 } },
};
const ActorInit En_Wonder_Item_InitVars = {
ACTOR_EN_WONDER_ITEM,
ACTORCAT_PROP,
FLAGS,
OBJECT_GAMEPLAY_KEEP,
sizeof(EnWonderItem),
(ActorFunc)EnWonderItem_Init,
(ActorFunc)EnWonderItem_Destroy,
(ActorFunc)EnWonderItem_Update,
NULL,
NULL,
};
static Vec3f sTagPointsFree[9];
static Vec3f sTagPointsOrdered[9];
void EnWonderItem_Destroy(Actor* thisx, GlobalContext* globalCtx) {
s32 pad;
EnWonderItem* this = (EnWonderItem*)thisx;
if ((this->collider.dim.radius != 0) || (this->collider.dim.height != 0)) {
Collider_DestroyCylinder(globalCtx, &this->collider);
}
}
void EnWonderItem_DropCollectible(EnWonderItem* this, GlobalContext* globalCtx, s32 autoCollect) {
static s16 dropTable[] = {
ITEM00_NUTS, ITEM00_HEART_PIECE, ITEM00_MAGIC_LARGE, ITEM00_MAGIC_SMALL,
ITEM00_HEART, ITEM00_ARROWS_SMALL, ITEM00_ARROWS_MEDIUM, ITEM00_ARROWS_LARGE,
ITEM00_RUPEE_GREEN, ITEM00_RUPEE_BLUE, ITEM00_RUPEE_RED, ITEM00_FLEXIBLE,
};
s32 i;
s32 randomDrop;
func_80078884(NA_SE_SY_GET_ITEM);
if (this->dropCount == 0) {
this->dropCount++;
}
for (i = this->dropCount; i > 0; i--) {
if (this->itemDrop < WONDERITEM_DROP_RANDOM) {
if ((this->itemDrop == WONDERITEM_DROP_FLEXIBLE) || !autoCollect) {
Item_DropCollectible(globalCtx, &this->actor.world.pos, dropTable[this->itemDrop]);
} else {
Item_DropCollectible(globalCtx, &this->actor.world.pos, dropTable[this->itemDrop] | 0x8000);
}
} else {
randomDrop = this->itemDrop - WONDERITEM_DROP_RANDOM;
if (!autoCollect) {
Item_DropCollectibleRandom(globalCtx, NULL, &this->actor.world.pos, randomDrop);
} else {
Item_DropCollectibleRandom(globalCtx, NULL, &this->actor.world.pos, randomDrop | 0x8000);
}
}
}
if (this->switchFlag >= 0) {
Flags_SetSwitch(globalCtx, this->switchFlag);
}
Actor_Kill(&this->actor);
}
void EnWonderItem_Init(Actor* thisx, GlobalContext* globalCtx) {
static u32 collisionTypes[] = {
0x00000702 /* sword slash */, 0x0001F820 /* arrow */, 0x00000040 /* hammer */, 0x00000008 /* bomb */,
0x00000004 /* slingshot */, 0x00000010 /* boomerang */, 0x00000080 /* hookshot */,
};
s32 pad;
s16 colTypeIndex;
EnWonderItem* this = (EnWonderItem*)thisx;
s16 rotZover10;
s16 tagIndex;
osSyncPrintf("\n\n");
// "Mysterious mystery, very mysterious"
osSyncPrintf(VT_FGCOL(GREEN) "☆☆☆☆☆ 不思議不思議まか不思議 \t ☆☆☆☆☆ %x\n" VT_RST, this->actor.params);
this->actor.flags &= ~ACTOR_FLAG_0;
this->wonderMode = (this->actor.params >> 0xB) & 0x1F;
this->itemDrop = (this->actor.params >> 6) & 0x1F;
this->switchFlag = this->actor.params & 0x3F;
if (this->switchFlag == 0x3F) {
this->switchFlag = -1;
}
this->actor.targetMode = 1;
if ((this->switchFlag >= 0) && Flags_GetSwitch(globalCtx, this->switchFlag)) {
osSyncPrintf(VT_FGCOL(GREEN) "☆☆☆☆☆ ☆☆☆☆☆ %d\n" VT_RST, this->switchFlag);
Actor_Kill(&this->actor);
return;
}
switch (this->wonderMode) {
case WONDERITEM_MULTITAG_FREE:
this->numTagPoints = this->actor.world.rot.z & 0xF;
rotZover10 = 0;
if (this->actor.world.rot.z >= 10) {
rotZover10 = this->actor.world.rot.z / 10;
this->timerMod = rotZover10 * 20;
}
this->numTagPoints = this->actor.world.rot.z - rotZover10 * 10;
// i.e timerMod = rot.z / 10 seconds, numTagPoints = rot.z % 10
this->updateFunc = EnWonderItem_MultitagFree;
break;
case WONDERITEM_TAG_POINT_FREE:
tagIndex = this->actor.world.rot.z & 0xFF;
sTagPointsFree[tagIndex] = this->actor.world.pos;
Actor_Kill(&this->actor);
break;
case WONDERITEM_PROXIMITY_DROP:
this->dropCount = this->actor.world.rot.z & 0xFF;
this->updateFunc = EnWonderItem_ProximityDrop;
break;
case WONDERITEM_INTERACT_SWITCH:
colTypeIndex = this->actor.world.rot.z & 0xFF;
Collider_InitCylinder(globalCtx, &this->collider);
Collider_SetCylinder(globalCtx, &this->collider, &this->actor, &sCylinderInit);
this->collider.info.bumper.dmgFlags = collisionTypes[colTypeIndex];
this->collider.dim.radius = 20;
this->collider.dim.height = 30;
this->updateFunc = EnWonderItem_InteractSwitch;
break;
case WONDERITEM_UNUSED:
break;
case WONDERITEM_MULTITAG_ORDERED:
this->numTagPoints = this->actor.world.rot.z & 0xF;
rotZover10 = 0;
if (this->actor.world.rot.z >= 10) {
rotZover10 = this->actor.world.rot.z / 10;
this->timerMod = rotZover10 * 20;
}
this->numTagPoints = this->actor.world.rot.z - rotZover10 * 10;
// i.e timerMod = rot.z / 10 seconds, numTagPoints = rot.z % 10
this->updateFunc = EnWonderItem_MultitagOrdered;
break;
case WONDERITEM_TAG_POINT_ORDERED:
tagIndex = this->actor.world.rot.z & 0xFF;
sTagPointsOrdered[tagIndex] = this->actor.world.pos;
Actor_Kill(&this->actor);
break;
case WONDERITEM_PROXIMITY_SWITCH:
this->updateFunc = EnWonderItem_ProximitySwitch;
break;
case WONDERITEM_BOMB_SOLDIER:
Collider_InitCylinder(globalCtx, &this->collider);
Collider_SetCylinder(globalCtx, &this->collider, &this->actor, &sCylinderInit);
this->collider.info.bumper.dmgFlags = 0x00000004; // slingshot
this->unkPos = this->actor.world.pos;
this->collider.dim.radius = 35;
this->collider.dim.height = 75;
this->updateFunc = EnWonderItem_BombSoldier;
break;
case WONDERITEM_ROLL_DROP:
this->dropCount = this->actor.world.rot.z & 0xFF;
this->updateFunc = EnWonderItem_RollDrop;
break;
default:
Actor_Kill(&this->actor);
break;
}
}
void EnWonderItem_MultitagFree(EnWonderItem* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
s32 prevTagFlags = this->tagFlags;
s32 i;
s32 mask;
for (i = 0, mask = 1; i < this->numTagPoints; i++, mask <<= 1) {
if (!(prevTagFlags & mask)) {
f32 dx = player->actor.world.pos.x - sTagPointsFree[i].x;
f32 dy = player->actor.world.pos.y - sTagPointsFree[i].y;
f32 dz = player->actor.world.pos.z - sTagPointsFree[i].z;
if (sqrtf(SQ(dx) + SQ(dy) + SQ(dz)) < 50.0f) {
this->tagFlags |= mask;
this->tagCount++;
this->timer = this->timerMod + 81;
return;
}
if (BREG(0) != 0) {
DebugDisplay_AddObject(sTagPointsFree[i].x, sTagPointsFree[i].y, sTagPointsFree[i].z,
this->actor.world.rot.x, this->actor.world.rot.y, this->actor.world.rot.z, 1.0f,
1.0f, 1.0f, 0, 255, 0, 255, 4, globalCtx->state.gfxCtx);
}
}
}
if (this->timer == 1) {
Actor_Kill(&this->actor);
return;
}
if (this->tagCount == this->numTagPoints) {
if (this->switchFlag >= 0) {
Flags_SetSwitch(globalCtx, this->switchFlag);
}
EnWonderItem_DropCollectible(this, globalCtx, true);
}
}
void EnWonderItem_ProximityDrop(EnWonderItem* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
if ((this->actor.xzDistToPlayer < 50.0f) && (fabsf(this->actor.world.pos.y - player->actor.world.pos.y) < 30.0f)) {
EnWonderItem_DropCollectible(this, globalCtx, true);
}
}
void EnWonderItem_InteractSwitch(EnWonderItem* this, GlobalContext* globalCtx) {
if (this->collider.base.acFlags & AC_HIT) {
this->collider.base.acFlags &= ~AC_HIT;
EnWonderItem_DropCollectible(this, globalCtx, false);
}
}
void EnWonderItem_ProximitySwitch(EnWonderItem* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
if ((this->actor.xzDistToPlayer < 50.0f) && (fabsf(this->actor.world.pos.y - player->actor.world.pos.y) < 30.0f)) {
if (this->switchFlag >= 0) {
Flags_SetSwitch(globalCtx, this->switchFlag);
}
Actor_Kill(&this->actor);
}
}
void EnWonderItem_MultitagOrdered(EnWonderItem* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
s32 prevTagFlags = this->tagFlags;
s32 i;
s32 mask;
for (i = 0, mask = 1; i < this->numTagPoints; i++, mask <<= 1) {
if (!(prevTagFlags & mask)) {
f32 dx = player->actor.world.pos.x - sTagPointsOrdered[i].x;
f32 dy = player->actor.world.pos.y - sTagPointsOrdered[i].y;
f32 dz = player->actor.world.pos.z - sTagPointsOrdered[i].z;
if (sqrtf(SQ(dx) + SQ(dy) + SQ(dz)) < 50.0f) {
if (prevTagFlags & mask) {
return;
} else if (i == this->nextTag) {
this->tagFlags |= mask;
this->tagCount++;
this->nextTag++;
this->timer = this->timerMod + 81;
return;
} else {
Actor_Kill(&this->actor);
return;
}
} else if (BREG(0) != 0) {
DebugDisplay_AddObject(sTagPointsOrdered[i].x, sTagPointsOrdered[i].y, sTagPointsOrdered[i].z,
this->actor.world.rot.x, this->actor.world.rot.y, this->actor.world.rot.z, 1.0f,
1.0f, 1.0f, 0, 0, 255, 255, 4, globalCtx->state.gfxCtx);
}
}
}
if (this->timer == 1) {
Actor_Kill(&this->actor);
return;
}
if (this->tagCount == this->numTagPoints) {
EnWonderItem_DropCollectible(this, globalCtx, true);
}
}
void EnWonderItem_BombSoldier(EnWonderItem* this, GlobalContext* globalCtx) {
if (this->collider.base.acFlags & AC_HIT) {
this->collider.base.acFlags &= ~AC_HIT;
if (Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_HEISHI2, this->actor.world.pos.x,
this->actor.world.pos.y, this->actor.world.pos.z, 0, this->actor.yawTowardsPlayer, 0,
9) != NULL) {
// "Careless soldier spawned"
osSyncPrintf(VT_FGCOL(YELLOW) "☆☆☆☆☆ うっかり兵セット完了 ☆☆☆☆☆ \n" VT_RST);
}
if (this->switchFlag >= 0) {
Flags_SetSwitch(globalCtx, this->switchFlag);
}
Actor_Kill(&this->actor);
}
}
void EnWonderItem_RollDrop(EnWonderItem* this, GlobalContext* globalCtx) {
Player* player = GET_PLAYER(globalCtx);
if ((this->actor.xzDistToPlayer < 50.0f) && (player->invincibilityTimer < 0) &&
(fabsf(this->actor.world.pos.y - player->actor.world.pos.y) < 30.0f)) {
EnWonderItem_DropCollectible(this, globalCtx, true);
}
}
void EnWonderItem_Update(Actor* thisx, GlobalContext* globalCtx) {
static s16 debugArrowColors[] = {
255, 255, 0, 255, 0, 255, 0, 255, 255, 255, 0, 0, 0, 255, 0, 0, 0, 255, 128, 128,
128, 128, 128, 0, 128, 0, 128, 0, 128, 0, 128, 0, 0, 0, 128, 0, 0, 0, 128,
}; // These seem to be mistyped. Logically they should be s16[13][3] and be indexed as [colorIndex][i]
s32 pad;
EnWonderItem* this = (EnWonderItem*)thisx;
s32 colorIndex;
if (this->timer != 0) {
this->timer--;
}
this->updateFunc(this, globalCtx);
if (this->wonderMode == WONDERITEM_UNUSED) {
Actor_SetFocus(&this->actor, this->unkHeight);
}
if ((this->wonderMode == WONDERITEM_INTERACT_SWITCH) || (this->wonderMode == WONDERITEM_BOMB_SOLDIER)) {
Collider_UpdateCylinder(&this->actor, &this->collider);
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->collider.base);
}
colorIndex = this->wonderMode;
if (this->wonderMode > 12) {
colorIndex = 0;
}
if (BREG(0) != 0) {
DebugDisplay_AddObject(this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z,
this->actor.world.rot.x, this->actor.world.rot.y, this->actor.world.rot.z, 1.0f, 1.0f,
1.0f, debugArrowColors[colorIndex], debugArrowColors[colorIndex + 1],
debugArrowColors[colorIndex + 2], 255, 4, globalCtx->state.gfxCtx);
}
}