mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2024-08-13 17:03:47 -04:00
39cc86c260
subrepo: subdir: "soh" merged: "ba904bbd0" upstream: origin: "https://github.com/HarbourMasters/soh.git" branch: "master" commit: "ba904bbd0" git-subrepo: version: "0.4.1" origin: "???" commit: "???"
365 lines
14 KiB
C
365 lines
14 KiB
C
/*
|
||
* 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) "☆☆☆☆☆ You are Shock! ☆☆☆☆☆ %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);
|
||
}
|
||
}
|