From 28cf283d701767403d7c396e7a3bcedaffeae7eb Mon Sep 17 00:00:00 2001 From: Seil Weiss <32021834+pslehisl@users.noreply.github.com> Date: Sun, 11 Apr 2021 01:21:52 -0500 Subject: [PATCH] zEntPickup.cpp progress --- include/CodeWarrior/stdio.h | 1 + src/Core/p2/iAnim.h | 1 + src/Core/p2/iModel.h | 1 + src/Core/x/xEntDrive.h | 4 + src/Core/x/xFX.h | 2 + src/Core/x/xGrid.h | 4 + src/Core/x/xMath3.h | 1 + src/Core/x/xModelBucket.h | 1 + src/Core/x/xserializer.h | 2 + src/Game/zEntPickup.cpp | 1732 ++++++++++++++++++++++++++++-- src/Game/zEntPickup.h | 33 + src/Game/zEntPlayer.h | 13 + src/Game/zEntPlayerBungeeState.h | 2 + src/Game/zFX.h | 3 + src/Game/zLOD.h | 3 + src/Game/zNPCTypeBossSandy.cpp | 2 +- 16 files changed, 1740 insertions(+), 65 deletions(-) diff --git a/include/CodeWarrior/stdio.h b/include/CodeWarrior/stdio.h index 6306390..32578eb 100644 --- a/include/CodeWarrior/stdio.h +++ b/include/CodeWarrior/stdio.h @@ -6,6 +6,7 @@ extern "C" { #endif int sprintf(char* s, const char* format, ...); +void printf(const char* format, ...); #ifdef __cplusplus } diff --git a/src/Core/p2/iAnim.h b/src/Core/p2/iAnim.h index 0b7e1f7..481a6a5 100644 --- a/src/Core/p2/iAnim.h +++ b/src/Core/p2/iAnim.h @@ -6,6 +6,7 @@ extern uint8* giAnimScratch; void iAnimInit(); +uint32 iAnimBoneCount(void* RawData); void iAnimBlend(float32 BlendFactor, float32 BlendRecip, uint16* BlendTimeOffset, float32* BoneTable, uint32 BoneCount, xVec3* Tran1, xQuat* Quat1, xVec3* Tran2, xQuat* Quat2, xVec3* TranDest, xQuat* QuatDest); diff --git a/src/Core/p2/iModel.h b/src/Core/p2/iModel.h index 614f384..3ac9738 100644 --- a/src/Core/p2/iModel.h +++ b/src/Core/p2/iModel.h @@ -7,6 +7,7 @@ #include #include +uint32 iModelNumBones(RpAtomic* model); int32 iModelCull(RpAtomic* model, RwMatrixTag* mat); int32 iModelSphereCull(xSphere* sphere); RpAtomic* iModelFile_RWMultiAtomic(RpAtomic* model); diff --git a/src/Core/x/xEntDrive.h b/src/Core/x/xEntDrive.h index 73bf9c4..cbb6af3 100644 --- a/src/Core/x/xEntDrive.h +++ b/src/Core/x/xEntDrive.h @@ -35,4 +35,8 @@ struct xEntDrive ASSIGNMENT_OPERATOR(xEntDrive) }; +void xEntDriveInit(xEntDrive* drv, xEnt* driven); +void xEntDriveMount(xEntDrive* drv, xEnt* driver, float32 mt, const xCollis* coll); +void xEntDriveDismount(xEntDrive* drv, float32 dmt); + #endif \ No newline at end of file diff --git a/src/Core/x/xFX.h b/src/Core/x/xFX.h index 52f16c2..3eadea9 100644 --- a/src/Core/x/xFX.h +++ b/src/Core/x/xFX.h @@ -102,6 +102,7 @@ uint32 xFXanimUVCreate(); void xFXFireworksInit(const char* fireworksTrailEmitter, const char* fireworksEmitter1, const char* fireworksEmitter2, const char* fireworksSound, const char* fireworksLaunchSound); +void xFXFireworksLaunch(float32 countdownTime, const xVec3* pos, float32 fuelTime); void xFXFireworksUpdate(float32 dt); void xFXStreakInit(); void xFXStreakUpdate(float32 dt); @@ -109,6 +110,7 @@ void xFXStreakRender(); void xFXShineInit(); void xFXShineUpdate(float32 dt); void xFXShineRender(); +RpAtomic* xFXAtomicEnvMapSetup(RpAtomic* atomic, uint32 envmapID, float32 shininess); void xFXRibbonSceneEnter(); void xFXRibbonUpdate(float32 dt); void xFXRibbonRender(); diff --git a/src/Core/x/xGrid.h b/src/Core/x/xGrid.h index 8523739..9e57c8b 100644 --- a/src/Core/x/xGrid.h +++ b/src/Core/x/xGrid.h @@ -6,6 +6,7 @@ #include "xMath3.h" struct xEnt; +struct xQCData; struct xGridBound { @@ -56,6 +57,8 @@ struct xGridIterator uint32 delfound; }; +typedef int32 (*GridEntCallback)(xEnt*, void*); + extern volatile int32 gGridIterActive; void xGridBoundInit(xGridBound* gridb, void* data); @@ -69,5 +72,6 @@ xGridBound* xGridIterFirstCell(xGrid* grid, float32 posx, float32, float32 posz, xGridBound* xGridIterFirstCell(xGridBound** head, xGridIterator& it); xGridBound* xGridIterNextCell(xGridIterator& it); void xGridIterClose(xGridIterator& it); +void xGridCheckPosition(xGrid* grid, xVec3* pos, xQCData* qcd, GridEntCallback hitCB, void* cbdata); #endif \ No newline at end of file diff --git a/src/Core/x/xMath3.h b/src/Core/x/xMath3.h index fcf12d7..ad3d4eb 100644 --- a/src/Core/x/xMath3.h +++ b/src/Core/x/xMath3.h @@ -127,6 +127,7 @@ float32 xMat3x3LookVec(xMat3x3* m, const xVec3* at); void xBoxInitBoundOBB(xBox* o, const xBox* b, const xMat4x3* m); void xMat3x3Scale(xMat3x3* m, const xVec3* s); void xMat3x3ScaleC(xMat3x3* m, float32 x, float32 y, float32 z); +void xMat3x3RMulRotY(xMat3x3* o, const xMat3x3* m, float32 t); void xMat3x3Mul(xMat3x3* o, const xMat3x3* a, const xMat3x3* b); void xBoxFromLine(xBox& box, const xLine3& line); void xBoxFromRay(xBox& box, const xRay3& ray); diff --git a/src/Core/x/xModelBucket.h b/src/Core/x/xModelBucket.h index 25fd55c..f635e4f 100644 --- a/src/Core/x/xModelBucket.h +++ b/src/Core/x/xModelBucket.h @@ -22,6 +22,7 @@ void xModelBucket_Init(); void xModelBucket_Deinit(); xModelBucket** xModelBucket_GetBuckets(RpAtomic* data); void xModelBucket_Begin(); +void xModelBucket_Add(xModelInstance* minst); void xModelBucket_RenderOpaque(); void xModelBucket_RenderAlphaBegin(); void xModelBucket_RenderAlphaLayer(int32 maxLayer); diff --git a/src/Core/x/xserializer.h b/src/Core/x/xserializer.h index ce4f6e8..4940d14 100644 --- a/src/Core/x/xserializer.h +++ b/src/Core/x/xserializer.h @@ -28,12 +28,14 @@ struct xSerial void setClient(uint32 idtag); int32 Write_b1(int32 bits); + int32 Write_b7(uint32 bits); int32 Write(uint8 data); int32 Write(int16 data); int32 Write(int32 data); int32 Write(uint32 data); int32 Write(float32 data); int32 Read_b1(int32* bits); + int32 Read_b7(uint32* bits); int32 Read(uint8* buf); int32 Read(int16* buf); int32 Read(int32* buf); diff --git a/src/Game/zEntPickup.cpp b/src/Game/zEntPickup.cpp index 3704883..c25d9ef 100644 --- a/src/Game/zEntPickup.cpp +++ b/src/Game/zEntPickup.cpp @@ -1,124 +1,1728 @@ #include "zEntPickup.h" -#include +#include "zLOD.h" +#include "zGame.h" +#include "zGlobals.h" +#include "zEntPlayerBungeeState.h" +#include "zEntSimpleObj.h" +#include "zGrid.h" +#include "zFX.h" +#include "zUI.h" +#include "../Core/x/xMath.h" +#include "../Core/x/xFX.h" +#include "../Core/x/xstransvc.h" +#include "../Core/p2/iAnim.h" +#include "../Core/p2/iModel.h" + +#include +#include + +#define PICKUP_TYPE_SHINY 0 +#define PICKUP_TYPE_1 1 + +#define SHINY_PURPLE 0 +#define SHINY_BLUE 1 +#define SHINY_GREEN 2 +#define SHINY_YELLOW 3 +#define SHINY_RED 4 +#define SHINY_COUNT 5 + +#define PICKUP_SPATULA 0 +#define PICKUP_UNDERWEAR 1 +#define PICKUP_GOLDEN_UNDERWEAR 2 +#define PICKUP_4 4 +#define PICKUP_SUNDAE 5 +#define PICKUP_SOCK 6 +#define PICKUP_SPONGEBALL 7 +#define PICKUP_8 8 +#define PICKUP_9 9 +#define PICKUP_10 10 +#define PICKUP_11 11 +#define PICKUP_12 12 +#define PICKUP_13 13 +#define PICKUP_14 14 + +#define REWARD_TYPE_COUNT SHINY_COUNT +#define REWARD_COUNT 20 +#define REWARD_PICKUP_COUNT 10 + +struct ShinySparkly +{ + uint16 pickupType; + uint16 pickupIndex; + float32 radius; + float32 std_rate; + float32 fly_rate; + uint8 br; + uint8 bg; + uint8 bb; + uint8 ba; + uint8 dr; + uint8 dg; + uint8 db; + uint8 da; + uint32 envmapID; + float32 shininess; +}; + +struct _tagKeyShake +{ + xVec3 orig_pos; + float32 shake_timer; + float32 shake_it; + _zUI* ui; +}; + +struct RewardList +{ + bool active; + float32 timer; + xVec3* ppos; + xVec3 pos; + uint32 num; + uint32 currRequest; + uint32 pickups[REWARD_COUNT]; +}; + +zParEmitter* gEmitShinySparkles = NULL; + +static float32 SPARKLE_MAX_RATE = 30.0f; + +uint32 gEnableRewardsQueue = 1; + +static float32 sSpatulaGrabbedSpinMult = 0.0f; +static float32 sSpatulaGrabbedLife = 3.5f; +static float32 sUnderwearFade = 1.0f; + +#define bubble 0xB5126DFC // bubble RWTX in boot.HIP + +// clang-format off +static ShinySparkly ShinySparklyTable[] = +{ + { + PICKUP_TYPE_SHINY, SHINY_RED, + 0.15f, 50.0f, 25.0f, + 255, 255, 255, 255, + 255, 255, 255, 255, + bubble, + 0.5f + }, + { + PICKUP_TYPE_SHINY, SHINY_YELLOW, + 0.2f, 50.0f, 50.0f, + 255, 255, 255, 255, + 255, 255, 255, 255, + bubble, + 0.5f + }, + { + PICKUP_TYPE_SHINY, SHINY_GREEN, + 0.2f, 50.0f, 100.0f, + 255, 255, 255, 255, + 255, 255, 255, 255, + bubble, + 0.5f + }, + { + PICKUP_TYPE_SHINY, SHINY_BLUE, + 0.25f, 75.0f, 150.0f, + 255, 255, 255, 255, + 255, 255, 255, 255, + bubble, + 0.5f + }, + { + PICKUP_TYPE_SHINY, SHINY_PURPLE, + 0.4f, 110.0f, 200.0f, + 255, 255, 255, 255, + 255, 255, 255, 255, + bubble, + 0.5f + }, + { + PICKUP_TYPE_1, PICKUP_SPATULA, + 0.4f, 20.0f, 0.0f, + 255, 255, 224, 255, + 255, 255, 224, 255, + bubble, + 0.5f + }, + { + PICKUP_TYPE_1, PICKUP_GOLDEN_UNDERWEAR, + 0.15f, 10.0f, 0.0f, + 255, 255, 224, 255, + 255, 255, 224, 255, + bubble, + 0.5f + } +}; +// clang-format on + +// clang-format off +static RwMatrix sPickupOrientation = +{ + { 1.0f, 0.0f, 0.0f }, 0, + { 0.0f, 1.0f, 0.0f }, 0, + { 0.0f, 0.0f, 1.0f }, 0, + { 0.0f, 0.0f, 0.0f }, 0 +}; +// clang-format on + +static _tagKeyShake sKeyShake[4] = {}; + +static zEntPickup* rewardPickups[REWARD_TYPE_COUNT][REWARD_PICKUP_COUNT]; +static RewardList sRewards[REWARD_COUNT]; +static zLODTable sRewardLOD[REWARD_TYPE_COUNT]; +static xEntFrame gPickupFrame; +static xEntCollis gPickupCollis; +static zEntPickup* sSpatulaAlreadyGiven = NULL; +static zEntPickup* sSpatulaBungeeDeferred = NULL; + +extern float32 _864_0; // 0.8f +extern float32 _865_2; // 15.0f +extern float32 _866_1; // -20.0f +extern float32 _867_2; // 0.0f +extern float32 _964_2; // 1.0f +extern float32 _1050_1; // 0.5f +extern float32 _1051_0; // 0.00001f +extern float32 _1144; // 4.0f +extern float32 _1145; // 0.1f +extern float32 _1146; // 1.5f +extern float32 _1257_0; // 0.3f +extern float32 _1258; // 1.3f +extern float32 _1319; // 10.0f +extern float32 _1519; // PI +extern float32 _1526; // 1.2f +extern float32 _1609; // 75.0f +extern float32 _1610; // -7.5f +extern float32 _1611; // 0.0001f +extern float32 _2086; // 0.35f +extern float32 _2087; // 0.2f +extern float32 _2192; // 1.0e10f + +#ifndef NON_MATCHING +static void PickupFallPhysics(zEntPickup* ent, xScene* sc, float32 dt); // func_800627CC #pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "PickupFallPhysics__FP10zEntPickupP6xScenef") +#else +static void PickupFallPhysics(zEntPickup* ent, xScene* sc, float32 dt) +{ + // non-matching: scheduling, float regalloc -// func_80062980 -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "isRewardPickup__FP10zEntPickup") + gPickupFrame.mat = *(xMat4x3*)ent->model->Mat; + gPickupFrame.mat.pos.y -= _864_0; + gPickupFrame.oldmat = gPickupFrame.mat; -// func_80062A08 -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_Startup__Fv") + gPickupCollis.chk = 0x22; + gPickupCollis.pen = 0x22; -// func_80062A0C -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickupInit__FPvPv") + ent->vel.y -= _865_2 * dt; -// func_80062A2C -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickupInit__FP10zEntPickupP9xEntAsset") + if (ent->vel.y < _866_1) + { + ent->vel.y = _866_1; + } -// func_80062DD8 -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_Setup__FP10zEntPickup") + gPickupFrame.mat.pos.x += ent->vel.x * dt; + gPickupFrame.mat.pos.y += ent->vel.y * dt; + gPickupFrame.mat.pos.z += ent->vel.z * dt; -// func_80062DF8 -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_Setup__Fv") + if (!(ent->state & 0x80) || ent->vel.y < _867_2) + { + ent->frame = &gPickupFrame; + ent->collis = &gPickupCollis; -// func_80062F28 -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickupEventCB__FP5xBaseP5xBaseUiPCfP5xBase") + xEntCollide(ent, sc, dt); -// func_800631E8 -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_FlyToInterface__FP10zEntPickupf") + ent->frame = NULL; + ent->collis = NULL; + } -// func_800631EC -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_CheckAllPickupsAgainstPlayer__FP6xScenef") + gPickupFrame.mat.pos.y += _864_0; -// func_80063240 -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "CheckPickupAgainstPlayer__FP4xEntPv") + *(xMat4x3*)ent->model->Mat = gPickupFrame.mat; -// func_800635C8 -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_DoPickup__FP10zEntPickup") + if ((gPickupCollis.colls[0].flags & 0x1) && ent->vel.y < _867_2) + { + ent->vel.x = _867_2; + ent->vel.y = _867_2; + ent->vel.z = _867_2; + ent->state &= ~0x3f; + ent->state |= 0x1; + } +} +#endif -// func_80063690 -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_GivePickup__FP10zEntPickup") +uint32 isRewardPickup(zEntPickup* ent) +{ + char name[512]; -// func_80063914 -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "collectPickup__FP10zEntPickup") + for (int32 i = 0; i < 50; i++) + { + sprintf(name, "%s%02d", "boot_reward_pickup", i); -// func_80063AD4 -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_GiveAllRewardsNow__Fv") + if (ent->id == xStrHash(name)) + { + return 1; + } + } + + return 0; +} + +void zEntPickup_Startup() +{ +} + +void zEntPickupInit(void* ent, void* asset) +{ + zEntPickupInit((zEntPickup*)ent, (xEntAsset*)asset); +} + +void zEntPickupInit(zEntPickup* ent, xEntAsset* asset) +{ + xEntPickupAsset* pickupAsset = (xEntPickupAsset*)(asset + 1); + uint32 i, tmpsize; + + zEntInit(ent, asset, 'PKUP'); + + if (ent->linkCount) + { + ent->link = (xLinkAsset*)((xEntPickupAsset*)(ent->asset + 1) + 1); + } + else + { + ent->link = NULL; + } + + for (i = 0; i < ent->linkCount; i++) + { + if (ent->link[i].dstEvent == eEventDispatcher_SetSaveState_Saving) // ??????????? + { + ent->link[i].dstAssetID = ent->id; + } + } + + ent->pflags = 0; + ent->chkby = 0; + ent->penby = 0; + ent->update = (xEntUpdateCallback)zEntPickup_Update; + ent->render = NULL; + ent->move = NULL; + ent->eventFunc = zEntPickupEventCB; + ent->followTarget = NULL; + ent->followOffset.x = _867_2; + ent->followOffset.y = _867_2; + ent->followOffset.z = _867_2; + ent->shake_timer = _867_2; + ent->snackGateInfoDisplayed = 0; + ent->dropParent = NULL; + + zAssetPickup* ptbl = (zAssetPickup*)(globals.pickupTable + 1); + + for (i = 0; i < globals.pickupTable->Count; i++) + { + if (pickupAsset->pickupHash == ptbl[i].pickupHash) + { + ptbl += i; + break; + } + } + + RpAtomic* modelData = (RpAtomic*)xSTFindAsset(ptbl->modelID, &tmpsize); + void* animData = NULL; + + if (!modelData) + { + ptbl = (zAssetPickup*)(globals.pickupTable + 1); + modelData = (RpAtomic*)xSTFindAsset(ptbl->modelID, &tmpsize); + } + + if (ptbl->animID) + { + animData = xSTFindAsset(ptbl->animID, &tmpsize); + + if (iAnimBoneCount(animData) != iModelNumBones(modelData)) + { + animData = NULL; + } + } + + ent->model = xModelInstanceAlloc(modelData, ent, 0, 0, NULL); + ent->model->Flags &= (uint16)~0x2; + ent->model->modelID = ptbl->modelID; + ent->simpShadow = &ent->simpShadow_embedded; + + xShadowSimple_CacheInit(ent->simpShadow, ent, 80); + + ent->simpShadow->flags |= 0x8; + ent->state = 0x41; + ent->p = ptbl; + ent->pickupFlags = 0; + + if (pickupAsset->pickupFlags & 0x1) + { + ent->pickupFlags |= 0x1; + } + + if (pickupAsset->pickupFlags & 0x2) + { + ent->pickupFlags |= 0x2; + } + + ent->anim = animData; + ent->animTime = _867_2; + ent->timer = _867_2; + ent->fx_timer = _867_2; + ent->fx_par = NULL; + ent->fx_emit = NULL; + ent->fx_scale = _964_2; + ent->flyflags = 0; + + zEntReset(ent); + + ent->bound.type = XBOUND_TYPE_SPHERE; + ent->bound.sph.r = _964_2; + + xVec3Add(&ent->bound.sph.center, (xVec3*)&ent->model->Mat->pos, + (xVec3*)&ent->model->Data->boundingSphere.center); + + xEntDriveInit(&ent->drv, ent); + + ShinySparkly* sp = ShinySparklyTable; + + for (i = 0; i < sizeof(ShinySparklyTable) / sizeof(ShinySparkly); i++, sp++) + { + if (ent->p->pickupType == sp->pickupType && ent->p->pickupIndex == sp->pickupIndex) + { + xFXAtomicEnvMapSetup(ent->model->Data, sp->envmapID, sp->shininess); + } + } + + int32 found = 0; + + for (int32 i = 0; i < REWARD_TYPE_COUNT; i++) + { + char name[512]; + + for (int32 j = 0; j < REWARD_PICKUP_COUNT; j++) + { + sprintf(name, "%s%d%d", "boot_reward_pickup", i, j); + + if (ent->id == xStrHash(name)) + { + rewardPickups[i][j] = ent; + + ent->state = 0x48; + + xEntHide(ent); + + found = 1; + + break; + } + } + + if (found) + { + break; + } + } +} + +void zEntPickup_Setup(zEntPickup* p) +{ + zEntSetup(p); +} + +void zEntPickup_Setup() +{ + xBase* base; + zScene* zsc; + uint32 i, j; + zEntPickup* p; + xVec3* srcPos; + + zsc = globals.sceneCur; + + memset(sRewards, 0, sizeof(sRewards)); + + gEnableRewardsQueue = 1; + + for (i = 0; i < zsc->num_base; i++) + { + base = zsc->base[i]; + + if (base) + { + for (j = 0; j < base->linkCount; j++) + { + if (base->link[j].dstEvent == eEventDrop) + { + p = (zEntPickup*)zSceneFindObject(base->link[j].dstAssetID); + + if (p && p->baseType == eBaseTypePickup && p->state != 0x10) + { + srcPos = &p->asset->pos; + + switch (base->baseType) + { + case eBaseTypeVillain: + { + p->flg_opts |= 0x1; + p->flg_opts |= 0x2; + p->useThisEntPos = (xEnt*)base; + } + case eBaseTypeStatic: + case eBaseTypeDynamic: + case eBaseTypeButton: + case eBaseTypeDestructObj: + case eBaseTypeLobMaster: + { + srcPos = &((xEnt*)base)->asset->pos; + } + } + + zEntPickup_MakeDroppable(p, srcPos, NULL); + } + } + } + } + } +} + +int32 zEntPickupEventCB(xBase*, xBase* to, uint32 toEvent, const float32* toParam, + xBase* toParamWidget) +{ + zEntPickup* p = (zEntPickup*)to; + xEntFrame frame; + + switch (toEvent) + { + case eEventVisible: + { + if (!(p->state & 0x8)) + { + xEntShow(p); + + if (toParam && (int32)(_1050_1 + toParam[0]) == 77) + { + zFXPopOn(*p, toParam[1], toParam[2]); + } + } + + break; + } + case eEventInvisible: + { + xEntHide(p); + + if (toParam && (int32)(_1050_1 + toParam[0]) == 77) + { + zFXPopOff(*p, toParam[1], toParam[2]); + } + + break; + } + case eEventCollision_Visible_On: + { + if (!(p->state & 0x8)) + { + p->pickupFlags |= 0x2; + + xEntShow(p); + + if (toParam && toParam && (int32)(_1050_1 + toParam[0]) == 77) + { + zFXPopOn(*p, toParam[1], toParam[2]); + } + } + + break; + } + case eEventCollision_Visible_Off: + { + p->pickupFlags &= (uint8)~0x2; + + xEntHide(p); + + if (toParam && (int32)(_1050_1 + toParam[0]) == 77) + { + zFXPopOff(*p, toParam[1], toParam[2]); + } + + break; + } + case eEventReset: + { + zEntPickup_Reset(p); + break; + } + case eEventPickup: + { + if (p->state & 0x1) + { + zEntPickup_DoPickup(p); + } + + break; + } + case eEventDrop: + { + if (p->state == 0x10) + { + zEntPickup_Drop(p); + } + + break; + } + case eEventFollowTarget: + { + p->followTarget = toParamWidget; + p->followOffset.x = toParam[0]; + p->followOffset.y = toParam[1]; + p->followOffset.z = toParam[2]; + + break; + } + case eEventMount: + { + frame.mat = *(xMat4x3*)p->model->Mat; + + p->frame = &frame; + + xEntDriveMount(&p->drv, (xEnt*)toParamWidget, _1051_0, NULL); + + p->frame = NULL; + + break; + } + case eEventDismount: + { + frame.mat = *(xMat4x3*)p->model->Mat; + + p->frame = &frame; + + xEntDriveDismount(&p->drv, _1051_0); + + p->frame = NULL; + + break; + } + } + + return 1; +} + +void zEntPickup_FlyToInterface(zEntPickup*, float32) +{ +} + +struct zEntPickup_cbData +{ + xScene* sc; + float32 dt; +}; + +static int32 CheckPickupAgainstPlayer(xEnt* cbent, void*); + +void zEntPickup_CheckAllPickupsAgainstPlayer(xScene* sc, float32 dt) +{ + zEntPickup_cbData cbdata; + + cbdata.sc = sc; + cbdata.dt = dt; + + xGridCheckPosition(&colls_grid, (xVec3*)&globals.player.ent.model->Mat->pos, + &globals.player.ent.bound.qcd, CheckPickupAgainstPlayer, &cbdata); +} + +static int32 CheckPickupAgainstPlayer(xEnt* cbent, void*) +{ + if (cbent->baseType != eBaseTypePickup) + { + return 1; + } + + zEntPickup* ent = (zEntPickup*)cbent; + + if ((ent->state & 0x40) && _867_2 == ent->timer && !(ent->state & 0x8) && !(ent->state & 0x4) && + !(ent->state & 0x20) && globals.player.Health != 0) + { + ent->fx_scale = _964_2; + + if (ent->pickupFlags & 0x1) + { + ent->baseFlags &= 0x7f; + } + + float32 distance; + zEnt* plent = &globals.player.ent; + float32 distsqr; + float32 dx__ = plent->bound.sph.center.x - ent->model->Mat->pos.x; + float32 dy__ = plent->bound.sph.center.y - ent->model->Mat->pos.y; + float32 dz__ = plent->bound.sph.center.z - ent->model->Mat->pos.z; + float32 chkdist = _1144 * plent->bound.sph.r; + + distance = SQR(dx__) + SQR(dy__) + SQR(dz__); + + if (distance <= SQR(chkdist)) + { + if (ent->pickupFlags & 0x2) + { + if (ent->p->pickupType == PICKUP_TYPE_SHINY) + { + zEntPickup_DoPickup(ent); + } + + if (ent->p->pickupType == PICKUP_TYPE_1) + { + switch (ent->p->pickupIndex) + { + case PICKUP_UNDERWEAR: + { + if (globals.player.Health < globals.player.MaxHealth) + { + zEntPickup_DoPickup(ent); + } + + break; + } + case PICKUP_SOCK: + { + for (int32 i = 0; i < 5; i++) + { + xFXFireworksLaunch(_1050_1 + xurand(), (xVec3*)&ent->model->Mat->pos, + _1050_1 * xurand() + _1145); + } + + zEntPickup_DoPickup(ent); + + break; + } + case PICKUP_SPATULA: + { + if (bungee_state::active()) + { + chkdist = _1146 * plent->bound.sph.r; + distsqr = distance; + } + else + { + chkdist = _1146 * plent->bound.sph.r; + + xVec3 var_2C, var_38; + + xVec3Copy(&var_2C, (xVec3*)&ent->model->Mat->pos); + xVec3Copy(&var_38, (xVec3*)&ent->model->Mat->pos); + + var_2C.y += _1050_1 * chkdist; + var_38.y -= _1050_1 * chkdist; + + float32 dist2_1, dist2_2; + + { + float32 dx__ = plent->bound.sph.center.x - var_2C.x; + float32 dy__ = plent->bound.sph.center.y - var_2C.y; + float32 dz__ = plent->bound.sph.center.z - var_2C.z; + + dist2_1 = SQR(dx__) + SQR(dy__) + SQR(dz__); + } + + { + float32 dx__ = plent->bound.sph.center.x - var_38.x; + float32 dy__ = plent->bound.sph.center.y - var_38.y; + float32 dz__ = plent->bound.sph.center.z - var_38.z; + + dist2_2 = SQR(dx__) + SQR(dy__) + SQR(dz__); + } + + distsqr = MIN(dist2_1, dist2_2); + } + + if (distsqr <= SQR(chkdist)) + { + if (!bungee_state::active()) + { + zEntPlayerControlOff(CONTROL_OWNER_REWARDANIM); + } + + for (int32 i = 0; i < 10; i++) + { + xFXFireworksLaunch(xurand(), (xVec3*)&ent->model->Mat->pos, + _1050_1 * xurand() + _1145); + } + + zEntPlayer_SNDPlay(ePlayerSnd_PickupSpatula, _867_2); + zEntPickup_DoPickup(ent); + } + + break; + } + case PICKUP_SPONGEBALL: + { + if (distance <= SQR(_1146 * plent->bound.sph.r) && + gCurrentPlayer == eCurrentPlayerSpongeBob) + { + zEntPickup_DoPickup(ent); + } + + break; + } + case PICKUP_GOLDEN_UNDERWEAR: + case PICKUP_4: + case PICKUP_SUNDAE: + { + zEntPickup_DoPickup(ent); + break; + } + case PICKUP_8: + case PICKUP_9: + case PICKUP_11: + { + zEntPickup_DoPickup(ent); + break; + } + case PICKUP_10: + case PICKUP_12: + case PICKUP_13: + case PICKUP_14: + { + zEntPickup_DoPickup(ent); + break; + } + } + } + } + } + } + + return 1; +} + +void zEntPickup_DoPickup(zEntPickup* ent) +{ + ent->grab_pos = *xEntGetPos(ent); + ent->flyflags |= 0x1; + ent->state = (ent->state & ~0x3f) | 0x4; + + if (ent->p->pickupType == PICKUP_TYPE_1 && ent->p->pickupIndex == PICKUP_SPATULA) + { + zEntPlayer_SNDPlayStream(ePlayerStreamSnd_SpatulaComment1); + + if (!bungee_state::active()) + { + zEntPlayerControlOff(CONTROL_OWNER_REWARDANIM); + zEntPlayer_GiveSpatula(1); + + xMat4x3 mat; + + xMat4x3Copy(&mat, (xMat4x3*)&sPickupOrientation); + xVec3Copy(&mat.pos, (xVec3*)&ent->model->Mat->pos); + xMat4x3Copy((xMat4x3*)ent->model->Mat, &mat); + } + } +} + +void zEntPickup_GivePickup(zEntPickup* ent) +{ + if (ent->p->pickupType == PICKUP_TYPE_SHINY) + { + switch (ent->p->pickupIndex) + { + case SHINY_PURPLE: + { + globals.player.Inv_Shiny += globals.player.g.ShinyValuePurple; + break; + } + case SHINY_BLUE: + { + globals.player.Inv_Shiny += globals.player.g.ShinyValueBlue; + break; + } + case SHINY_GREEN: + { + globals.player.Inv_Shiny += globals.player.g.ShinyValueGreen; + break; + } + case SHINY_YELLOW: + { + globals.player.Inv_Shiny += globals.player.g.ShinyValueYellow; + break; + } + case SHINY_RED: + { + globals.player.Inv_Shiny += globals.player.g.ShinyValueRed; + break; + } + } + + if (globals.player.Inv_Shiny > 99999) + { + globals.player.Inv_Shiny = 99999; + } + } + else if (ent->p->pickupType == PICKUP_TYPE_1) + { + switch (ent->p->pickupIndex) + { + case PICKUP_SPATULA: + { + if (sSpatulaAlreadyGiven != ent) + { + globals.player.Inv_Spatula++; + } + + break; + } + case PICKUP_UNDERWEAR: + { + if (globals.player.Health != 0) + { + globals.player.Health++; + + if (globals.player.Health > globals.player.MaxHealth) + { + globals.player.Health = globals.player.MaxHealth; + } + } + + break; + } + case PICKUP_GOLDEN_UNDERWEAR: + { + globals.player.MaxHealth++; + + if (globals.player.MaxHealth > 6) + { + globals.player.MaxHealth = 6; + } + + globals.player.Health = globals.player.MaxHealth; + + if (globals.player.MaxHealth == 4) + { + zEntPlayer_SNDPlayStream(ePlayerStreamSnd_GoldenUnderwear4); + } + else if (globals.player.MaxHealth == 5) + { + zEntPlayer_SNDPlayStream(ePlayerStreamSnd_GoldenUnderwear5); + } + else if (globals.player.MaxHealth == 6) + { + zEntPlayer_SNDPlayStream(ePlayerStreamSnd_GoldenUnderwear6); + } + + break; + } + case PICKUP_SUNDAE: + { + globals.player.SundaeTimer = globals.player.g.SundaeTime; + globals.player.SpeedMult = globals.player.g.SundaeMult; + break; + } + case PICKUP_SOCK: + { + zEntPlayer_GivePatsSocksCurrentLevel(1); + break; + } + case PICKUP_SPONGEBALL: + { + zEntPlayer_setBoulderMode(1); + break; + } + case PICKUP_8: + case PICKUP_9: + case PICKUP_10: + case PICKUP_11: + case PICKUP_12: + case PICKUP_14: + { + globals.player.Inv_LevelPickups[zSceneGetLevelIndex()]++; + globals.player.Inv_LevelPickups_CurrentLevel = + globals.player.Inv_LevelPickups[zSceneGetLevelIndex()]; + break; + } + } + } + + zEntEvent(ent, eEventPickup); +} + +static void collectPickup(zEntPickup* ent) +{ + xEntHide(ent); + zEntPickup_GivePickup(ent); + + ent->state = (ent->state & ~0x3f) | 0x8; + + if (isRewardPickup(ent)) + { + ent->baseFlags &= 0x7f; + } + + ent->timer = _1050_1; + ent->model->Mat->pos.x = ent->asset->pos.x; + ent->model->Mat->pos.y = ent->asset->pos.y; + ent->model->Mat->pos.z = ent->asset->pos.z; + + if (!isRewardPickup(ent)) + { + if (ent->p->pickupType == PICKUP_TYPE_SHINY) + { + switch (ent->p->pickupIndex) + { + case SHINY_PURPLE: + { + zEntPlayer_SNDPlayStream(ePlayerStreamSnd_ShinyComment5); + break; + } + case SHINY_BLUE: + case SHINY_GREEN: + case SHINY_YELLOW: + case SHINY_RED: + { + if ((xrand() & 0x3) == 3) + { + zEntPlayer_SNDPlayStreamRandom(0, 1, ePlayerStreamSnd_ShinyComment1, + ePlayerStreamSnd_ShinyComment2, _1257_0); + zEntPlayer_SNDPlayStreamRandom(2, 25, ePlayerStreamSnd_ShinyComment1, + ePlayerStreamSnd_ShinyComment3, _1257_0); + zEntPlayer_SNDPlayStreamRandom(26, 100, ePlayerStreamSnd_ShinyComment1, + ePlayerStreamSnd_ShinyComment4, _1257_0); + } + + break; + } + } + } + else + { + switch (ent->p->pickupIndex) + { + case PICKUP_UNDERWEAR: + { + zEntPlayer_SNDPlay(ePlayerSnd_PickupUnderwear, _867_2); + zEntPlayer_SNDPlayStreamRandom(ePlayerStreamSnd_UnderwearComment1, + ePlayerStreamSnd_UnderwearComment3, _1258); + + break; + } + case PICKUP_SOCK: + { + if ((xrand() & 0x3) == 3) + { + zEntPlayer_SNDPlayStreamRandom(ePlayerStreamSnd_PickupSock1, + ePlayerStreamSnd_PickupSock3, _867_2); + } + + break; + } + case PICKUP_8: + case PICKUP_9: + case PICKUP_11: + { + zEntPlayer_SNDPlayStreamRandom(ePlayerStreamSnd_PickupSpecialGeneric1, + ePlayerStreamSnd_PickupSpecialGeneric1, _867_2); + + break; + } + } + } + } +} + +void zEntPickup_GiveAllRewardsNow() +{ + zEntPickup* ent; + uint32 i, j; + + for (i = 0; i < REWARD_TYPE_COUNT; i++) + { + for (j = 0; j < REWARD_PICKUP_COUNT; j++) + { + ent = rewardPickups[i][j]; + + if (ent) + { + xEntHide(ent); + + if (ent->state & 0x4) + { + zEntPickup_GivePickup(ent); + } + + ent->state = (ent->state & ~0x3f) | 0x8; + ent->timer = _1319; + ent->model->Mat->pos.x = ent->asset->pos.x; + ent->model->Mat->pos.y = ent->asset->pos.y; + ent->model->Mat->pos.z = ent->asset->pos.z; + } + } + } + + uint32 total = 0; + + for (i = 0; i < REWARD_COUNT; i++) + { + if (sRewards[i].active) + { + for (j = 0; j < sRewards[i].num; j++) + { + switch (sRewards[i].pickups[j]) + { + case SHINY_PURPLE: + { + total += globals.player.g.ShinyValuePurple; + break; + } + case SHINY_BLUE: + { + total += globals.player.g.ShinyValueBlue; + break; + } + case SHINY_GREEN: + { + total += globals.player.g.ShinyValueGreen; + break; + } + case SHINY_YELLOW: + { + total += globals.player.g.ShinyValueYellow; + break; + } + case SHINY_RED: + { + total += globals.player.g.ShinyValueRed; + break; + } + } + } + } + } + + globals.player.Inv_Shiny += total; + + if (globals.player.Inv_Shiny > 99999) + { + globals.player.Inv_Shiny = 99999; + } + + memset(sRewards, 0, sizeof(sRewards)); +} // func_80063C9C #pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_Update__FP10zEntPickupP6xScenef") -// func_80064464 -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_Reset__FP10zEntPickup") +void zEntPickup_Reset(zEntPickup* ent) +{ + zEntReset(ent); -// func_8006451C -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_Save__FP10zEntPickupP7xSerial") + ent->state = 0x41; + ent->animTime = _867_2; + ent->timer = _867_2; + ent->vel.x = ent->vel.y = ent->vel.z = _867_2; + ent->bound.type = XBOUND_TYPE_SPHERE; + ent->shake_timer = _867_2; + ent->fx_timer = _867_2; + ent->fx_par = NULL; + ent->fx_emit = NULL; + ent->fx_scale = _964_2; + ent->flyflags = 0; -// func_80064588 -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_Load__FP10zEntPickupP7xSerial") + if (isRewardPickup(ent)) + { + ent->state = 0x48; + ent->flyflags = 0x1; + } -// func_80064708 -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_FlushGrabbed__Fv") + // this is likely really slow, assuming zEntPickup_Reset runs for every single pickup in the level... + // might be faster to move this to zEntPickup_SceneReset + gEmitShinySparkles = zParEmitterFind("PAREMIT_SHINY_SPARKLES"); +} -// func_800647E0 -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", \ - "zEntPickup_MakeDroppable__FP10zEntPickupP5xVec3P5xBase") +void zEntPickup_Save(zEntPickup* ent, xSerial* s) +{ + zEntSave(ent, s); -// func_8006485C -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_Drop__FP10zEntPickup") + s->Write_b7(ent->state); -// func_800649A8 -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "ShowPickupFx__FP10zEntPickup") + if (ent->pickupFlags & 0x2) + { + s->Write_b1(1); + } + else + { + s->Write_b1(0); + } +} +void zEntPickup_Load(zEntPickup* ent, xSerial* s) +{ + int32 is_a_dropper = 0; + + zEntLoad(ent, s); + + if (ent->state & 0x10) + { + is_a_dropper = 1; + } + + uint32 state = 0; + int32 coll = 0; + + s->Read_b7(&state); + s->Read_b1(&coll); + + if (state & 0x4) + { + ent->state = (ent->state & ~0x3f) | 0x8; + + xEntHide(ent); + } + + ent->state = state; + + if (coll) + { + ent->pickupFlags |= 0x2; + } + else + { + ent->pickupFlags &= (uint8)~0x2; + } + + if (ent->pickupFlags & 0x1) + { + ent->timer = _964_2; + } + + if (is_a_dropper && (ent->state & 0x23)) + { + if (ent->dropParent && ent->dropParent->baseType == eBaseTypeStatic && + !(ent->dropParent->baseFlags & 0x2) && + (((zEntSimpleObj*)ent->dropParent)->sflags & 0x1)) + { + printf("Put back %f %f %f %f %f %f\n", // + ent->model->Mat->pos.x, ent->model->Mat->pos.y, ent->model->Mat->pos.z, + ent->droppos.x, ent->droppos.y, ent->droppos.z); + + ent->state = 0x10; + + xEntHide(ent); + } + else + { + xVec3Copy((xVec3*)&ent->model->Mat->pos, &ent->droppos); + } + } +} + +void zEntPickup_FlushGrabbed() +{ + zScene* s = globals.sceneCur; + zEntPickup* it = (zEntPickup*)s->baseList[eBaseTypePickup]; + zEntPickup* end = it + s->baseCount[eBaseTypePickup]; + + while (it != end) + { + if ((it->state & 0x4) && !isRewardPickup(it)) + { + xEntHide(it); + zEntPickup_GivePickup(it); + + it->state = (it->state & ~0x3f) | 0x8; + it->timer = _1050_1; + it->model->Mat->pos.x = it->asset->pos.x; + it->model->Mat->pos.y = it->asset->pos.y; + it->model->Mat->pos.z = it->asset->pos.z; + } + + it++; + } +} + +void zEntPickup_MakeDroppable(zEntPickup* ent, xVec3* pos, xBase* dropParent) +{ + ent->droppos = *(xVec3*)&ent->model->Mat->pos; + *(xVec3*)&ent->model->Mat->pos = *pos; + ent->state = 0x10; + + xEntHide(ent); + + ent->dropParent = dropParent; +} + +void zEntPickup_Drop(zEntPickup* ent) +{ + ent->state = 0xC2; + + xEntShow(ent); + + if ((ent->flg_opts & 0x2) && ent->useThisEntPos) + { + xVec3Copy(&ent->droppos, xEntGetPos(ent->useThisEntPos)); + xVec3Copy((xVec3*)&ent->model->Mat->pos, xEntGetPos(ent->useThisEntPos)); + } + + float32 b = xsqrt(_1609); + float32 c = ent->model->Mat->pos.y - ent->droppos.y; + + ent->vel.x = _867_2; + ent->vel.y = b; + ent->vel.z = _867_2; + + if (!(ent->flg_opts & 0x1)) + { + float32 sol[2]; + uint32 solcnt = xMathSolveQuadratic(_1610, b, c, &sol[0], &sol[1]); + + if (solcnt) + { + if (solcnt == 2 && sol[1] > sol[0]) + { + sol[0] = sol[1]; + } + + if (sol[0] > _1611) + { + sol[0] = _964_2 / sol[0]; + + ent->vel.x = sol[0] * (ent->droppos.x - ent->model->Mat->pos.x); + ent->vel.z = sol[0] * (ent->droppos.z - ent->model->Mat->pos.z); + } + } + } + + ent->timer = _1526; +} + +static uint32 ShowPickupFx(zEntPickup* ent) +{ + if (!globals.cmgr) + { + return 1; + } + + if ((ent->flyflags & 0x2) != 0x2) + { + return 1; + } + + return 0; +} + +// clang-format off +zPickupAuraInfo zPickupAuraTable[] = +{ + { 5.0f, 0.0f, { 240, 235, 224, 128 } }, + { 0.0f, 0.0f, { 128, 128, 128, 128 } }, + { 5.0f, 0.0f, { 240, 235, 224, 128 } }, + { 0.0f, 0.0f, { 128, 128, 128, 128 } }, + { 0.0f, 0.0f, { 128, 128, 128, 128 } }, + { 0.0f, 0.0f, { 128, 128, 128, 128 } }, + { 3.0f, 0.1f, { 240, 255, 240, 128 } }, + { 3.0f, 0.0f, { 128, 128, 128, 128 } }, + { 0.0f, 0.0f, { 128, 128, 128, 128 } }, + { 3.0f, 0.5f, { 192, 192, 192, 128 } }, + { 0.0f, 0.0f, { 128, 128, 128, 128 } }, + { 5.0f, 0.5f, { 192, 192, 192, 128 } }, + { 0.0f, 0.0f, { 128, 128, 128, 128 } }, + { 5.0f, 0.3f, { 192, 180, 240, 128 } }, + { 0.0f, 0.0f, { 128, 128, 128, 128 } } +}; +// clang-format on + +static void zEntPickup_UpdateFX(zEntPickup* ent, xScene*, float32 dt); +// Uses int-to-float conversion // func_800649D4 #pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_UpdateFX__FP10zEntPickupP6xScenef") -// func_80064FA0 -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "set_alpha_blend__FP14xModelInstance") +static void set_alpha_blend(xModelInstance* model) +{ + model->PipeFlags &= ~0xFF0C; + model->PipeFlags |= 0x6508; +} -// func_80064FC4 -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_Render__FP10zEntPickupUi") +void zEntPickup_Render(zEntPickup* plist, uint32 pcount) +{ + xLightKit_Enable(NULL, globals.currWorld); + for (uint32 i = 0; i < pcount; plist++, i++) + { + if (xEntIsVisible(plist) && !(plist->model->Flags & 0x400)) + { + RwMatrix* mat = plist->model->Mat; + + if (plist->p->pickupType == 1 && plist->p->pickupIndex == 1 && + globals.player.Health >= globals.player.MaxHealth) + { + set_alpha_blend(plist->model); + + plist->model->Alpha = sUnderwearFade; + + xModelBucket_Add(plist->model); + + *(xMat3x3*)mat = *(xMat3x3*)&sPickupOrientation; + } + } + } +} + +#ifndef NON_MATCHING // func_8006509C #pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_RenderOne__FP4xEnt") +#else +void zEntPickup_RenderOne(xEnt* ent) +{ + if (ent->baseType != eBaseTypePickup) + { + return; + } + + if (!xEntIsVisible(ent)) + { + return; + } + + if (ent->model->Flags & 0x400) + { + return; + } + + zEntPickup* pickup = (zEntPickup*)ent; + RpAtomic* imodel = pickup->model->Data; + RwMatrix* mat = ent->model->Mat; + int32 shadowResult; + xVec3 shadVec; + + // non-matching: scheduling + + shadVec.x = ent->model->Mat->pos.x; + shadVec.y = ent->model->Mat->pos.y - _1319; + shadVec.z = ent->model->Mat->pos.z; + + if (iModelCullPlusShadow(imodel, ent->model->Mat, &shadVec, &shadowResult)) + { + return; + } + + RwFrame* frame = RpAtomicGetFrame(imodel); + + if (!pickup->anim && (pickup->p->pickupType != PICKUP_TYPE_1 || !(pickup->state & 0x4))) + { + *(xMat3x3*)mat = *(xMat3x3*)&sPickupOrientation; + } + + frame->ltm = *mat; + + if (_964_2 != pickup->fx_scale) + { + RwV3d vec_scale; + + vec_scale.x = pickup->fx_scale; + vec_scale.y = pickup->fx_scale; + vec_scale.z = pickup->fx_scale; + + RwMatrixScale(&frame->ltm, &vec_scale, rwCOMBINEPRECONCAT); + } + + RpAtomicRender(imodel); +} +#endif // func_800651CC #pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_RenderList__FP10zEntPickupUi") +// Uses int-to-float conversion // func_8006541C #pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_UpdateFlyToInterface__FP10zEntPickupUif") -// func_800659D8 -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "rewardRequest__FUiP5xVec35xVec3") +static uint32 rewardRequest(uint32 shinyType, xVec3* ppos, xVec3 pos) +{ + for (int32 i = 0; i < REWARD_PICKUP_COUNT; i++) + { + zEntPickup* p = rewardPickups[shinyType][i]; -// func_80065AD0 -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_SceneEnter__Fv") + if (p && (p->state & 0x8)) + { + p->state = (p->state & ~0x3f) | 0x4; + xEntShow(p); + + p->baseFlags &= (uint8)~0x40; + p->baseFlags |= 0x80; + + if (ppos) + { + xVec3Copy((xVec3*)&p->model->Mat->pos, ppos); + + p->grab_pos = *ppos; + } + else + { + xVec3Copy((xVec3*)&p->model->Mat->pos, &pos); + + p->grab_pos = pos; + } + + return 1; + } + } + + return 0; +} + +void zEntPickup_SceneEnter() +{ + zEntPickup_SceneReset(); +} + +#ifndef NON_MATCHING // func_80065AF0 #pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_SceneReset__Fv") +#else +void zEntPickup_SceneReset() +{ + // non-matching: scheduling + gEnableRewardsQueue = 1; + sSpatulaAlreadyGiven = NULL; + sSpatulaBungeeDeferred = NULL; +} +#endif +#if 1 // func_80065B08 #pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_SceneUpdate__Ff") +#else +void zEntPickup_SceneUpdate(float32 dt) +{ + // wip + if (zGameIsPaused()) + { + return; + } + + xMat3x3RMulRotY((xMat3x3*)&sPickupOrientation, (xMat3x3*)&sPickupOrientation, _1519 * dt); + + sPickupOrientation.flags = rwMATRIXTYPEORTHONORMAL; + + if (globals.player.Health >= globals.player.MaxHealth) + { + if (sUnderwearFade > _2086) + { + sUnderwearFade -= _1050_1 * dt; + + if (sUnderwearFade < _2086) + { + sUnderwearFade = _2086; + } + } + } + else + { + if (sUnderwearFade < _964_2) + { + sUnderwearFade += _1050_1 * dt; + + if (sUnderwearFade > _964_2) + { + sUnderwearFade = _964_2; + } + } + } + + for (int32 i = 0; i < REWARD_COUNT; i++) + { + if (sRewards[i].active && (!sRewards[i].currRequest || _867_2 == sRewards[i].timer)) + { + sRewards[i].timer = _2087; + + uint32 ret = rewardRequest(sRewards[i].pickups[sRewards[i].currRequest], + sRewards[i].ppos, sRewards[i].pos); + + if (!ret) + { + switch (sRewards[i].pickups[sRewards[i].currRequest]) + { + case SHINY_PURPLE: + { + globals.player.Inv_Shiny += globals.player.g.ShinyValuePurple; + break; + } + case SHINY_BLUE: + { + globals.player.Inv_Shiny += globals.player.g.ShinyValueBlue; + break; + } + case SHINY_GREEN: + { + globals.player.Inv_Shiny += globals.player.g.ShinyValueGreen; + break; + } + case SHINY_YELLOW: + { + globals.player.Inv_Shiny += globals.player.g.ShinyValueYellow; + break; + } + case SHINY_RED: + { + globals.player.Inv_Shiny += globals.player.g.ShinyValueRed; + break; + } + } + } + + sRewards[i].currRequest++; + + if (sRewards[i].currRequest >= sRewards[i].num) + { + memset(&sRewards[i], 0, sizeof(RewardList)); + } + } + } + + if (globals.player.Inv_Shiny > 99999) + { + globals.player.Inv_Shiny = 99999; + } + + for (int32 i = 0; i < REWARD_COUNT; i++) + { + sRewards[i].timer -= dt; + + if (sRewards[i].timer < _867_2) + { + sRewards[i].timer = _867_2; + } + } + + if (sSpatulaBungeeDeferred && bungee_state::landed()) + { + xVec3* pos = xEntGetPos(sSpatulaBungeeDeferred); + + *pos = *(xVec3*)&globals.player.ent.model->Mat->pos; + pos->y += _964_2; + + xEntShow(sSpatulaBungeeDeferred); + zEntPickup_DoPickup(sSpatulaBungeeDeferred); + + sSpatulaAlreadyGiven = sSpatulaBungeeDeferred; + sSpatulaBungeeDeferred = NULL; + } +} +#endif + +#ifndef NON_MATCHING +static void spawnNRewards(uint32* pickups, uint32 num, xVec3* ppos, xVec3 pos); // func_80065E84 #pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "spawnNRewards__FPUiUiP5xVec35xVec3") +#else +static void spawnNRewards(uint32* pickups, uint32 num, xVec3* ppos, xVec3 pos) +{ + if (num >= 1 && gEnableRewardsQueue) + { + for (int32 i = 0; i < REWARD_COUNT; i++) + { + if (!sRewards[i].active) + { + // non-matching: scheduling + sRewards[i].active = true; + sRewards[i].num = num; + sRewards[i].timer = _2087; -// func_80066000 -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_SpawnNRewards__FPUiUiP5xVec3") + for (uint32 j = 0; j < num; j++) + { + sRewards[i].pickups[j] = pickups[j]; + } -// func_80066044 -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_SpawnNRewards__FPUiUi5xVec3") + if (ppos) + { + sRewards[i].ppos = ppos; + } + else + { + sRewards[i].pos = pos; + sRewards[i].ppos = NULL; + } -// func_8006608C -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "zEntPickup_RewardPostSetup__Fv") + break; + } + } + } +} +#endif -// func_80066128 -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "__as__9zLODTableFRC9zLODTable") +void zEntPickup_SpawnNRewards(uint32* pickups, uint32 num, xVec3* ppos) +{ + if (num >= 1) + { + xVec3 pos = *ppos; + spawnNRewards(pickups, num, ppos, pos); + } +} -// func_8006616C -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "xVec3DistFast__FPC5xVec3PC5xVec3") +void zEntPickup_SpawnNRewards(uint32* pickups, uint32 num, xVec3 pos) +{ + if (num >= 1) + { + spawnNRewards(pickups, num, NULL, pos); + } +} -// func_800661C4 -#pragma GLOBAL_ASM("asm/Game/zEntPickup.s", "xMat3x3MulRotC__FP7xMat3x3P7xMat3x3ffff") +void zEntPickup_RewardPostSetup() +{ + for (int32 i = 0; i < REWARD_TYPE_COUNT; i++) + { + for (int32 j = 0; j < REWARD_PICKUP_COUNT; j++) + { + if (rewardPickups[i][j]) + { + zLODTable* lod = zLOD_Get(rewardPickups[i][j]); + + if (lod) + { + sRewardLOD[i] = *lod; + sRewardLOD[i].noRenderDist = _2192; + + zLOD_UseCustomTable(rewardPickups[i][j], &sRewardLOD[i]); + } + } + } + } +} + +WEAK zLODTable& zLODTable::operator=(const zLODTable& other) +{ + this->baseBucket = other.baseBucket; + this->noRenderDist = other.noRenderDist; + this->lodBucket[0] = other.lodBucket[0]; + this->lodBucket[1] = other.lodBucket[1]; + this->lodBucket[2] = other.lodBucket[2]; + *(uint32*)&this->lodDist[0] = *(uint32*)&other.lodDist[0]; + *(uint32*)&this->lodDist[1] = *(uint32*)&other.lodDist[1]; + *(uint32*)&this->lodDist[2] = *(uint32*)&other.lodDist[2]; + return *this; +} + +WEAK float32 xVec3DistFast(const xVec3* a, const xVec3* b) +{ + float32 dx = a->x - b->x; + float32 dy = a->y - b->y; + float32 dz = a->z - b->z; + float32 dist2 = SQR(dx) + SQR(dy) + SQR(dz); + float32 dist; + + xsqrtfast(dist, dist2); + + return dist; +} + +WEAK void xMat3x3MulRotC(xMat3x3* o, xMat3x3* m, float32 _x, float32 _y, float32 _z, float32 t) +{ + xMat3x3 var_38; + xMat3x3RotC(&var_38, _x, _y, _z, t); + xMat3x3Mul(o, m, &var_38); +} diff --git a/src/Game/zEntPickup.h b/src/Game/zEntPickup.h index 5d7fb8b..42fc591 100644 --- a/src/Game/zEntPickup.h +++ b/src/Game/zEntPickup.h @@ -8,6 +8,7 @@ #include "../Core/x/xEntDrive.h" #include "../Core/x/xPar.h" #include "../Core/x/xShadowSimple.h" +#include "../Core/p2/iColor.h" struct zEntPickup : zEnt { @@ -37,20 +38,52 @@ struct zEntPickup : zEnt uint16 pickupFlags; // 0x264 }; +struct xEntPickupAsset +{ + uint32 pickupHash; + uint16 pickupFlags; + uint16 pickupValue; +}; + +struct zPickupAuraInfo +{ + float32 size; + float32 yoffset; + iColor_tag color; +}; + +extern zParEmitter* gEmitShinySparkles; +extern uint32 gEnableRewardsQueue; +extern zPickupAuraInfo zPickupAuraTable[]; + +void zEntPickup_Startup(); void zEntPickupInit(void* ent, void* asset); +void zEntPickupInit(zEntPickup* ent, xEntAsset* asset); void zEntPickup_Setup(zEntPickup* p); void zEntPickup_Setup(); +int32 zEntPickupEventCB(xBase*, xBase* to, uint32 toEvent, const float32* toParam, + xBase* toParamWidget); +void zEntPickup_FlyToInterface(zEntPickup*, float32); +void zEntPickup_CheckAllPickupsAgainstPlayer(xScene* sc, float32 dt); +void zEntPickup_DoPickup(zEntPickup* ent); +void zEntPickup_GivePickup(zEntPickup* ent); void zEntPickup_GiveAllRewardsNow(); +void zEntPickup_Update(zEntPickup* ent, xScene* sc, float32 dt); void zEntPickup_Reset(zEntPickup* ent); void zEntPickup_Save(zEntPickup* ent, xSerial* s); void zEntPickup_Load(zEntPickup* ent, xSerial* s); void zEntPickup_FlushGrabbed(); +void zEntPickup_MakeDroppable(zEntPickup* ent, xVec3* pos, xBase* dropParent); +void zEntPickup_Drop(zEntPickup* ent); void zEntPickup_Render(zEntPickup* plist, uint32 pcount); +void zEntPickup_RenderOne(xEnt* ent); void zEntPickup_RenderList(zEntPickup* plist, uint32 pcount); void zEntPickup_UpdateFlyToInterface(zEntPickup* ent, uint32 pcount, float32 dt); void zEntPickup_SceneEnter(); void zEntPickup_SceneReset(); void zEntPickup_SceneUpdate(float32 dt); +void zEntPickup_SpawnNRewards(uint32* pickups, uint32 num, xVec3* ppos); +void zEntPickup_SpawnNRewards(uint32* pickups, uint32 num, xVec3 pos); void zEntPickup_RewardPostSetup(); #endif \ No newline at end of file diff --git a/src/Game/zEntPlayer.h b/src/Game/zEntPlayer.h index 8fba4a1..fe84de6 100644 --- a/src/Game/zEntPlayer.h +++ b/src/Game/zEntPlayer.h @@ -398,6 +398,10 @@ void zEntPlayer_UnloadSounds(); void zEntPlayer_ShadowModelEnable(); void zEntPlayer_ShadowModelDisable(); +void zEntPlayer_setBoulderMode(uint32 mode); +void zEntPlayer_GiveSpatula(int32); +void zEntPlayer_GivePatsSocksCurrentLevel(int32 quantity); + void zEntPlayer_LoadCheckPoint(); void zEntPlayer_MinimalRender(zEnt* ent); @@ -405,6 +409,15 @@ uint8 zEntPlayer_MinimalUpdate(xEnt* ent, xScene* sc, float32 dt, xVec3& drive_m void zEntPlayer_SNDPlay(_tagePlayerSnd player_snd, float32 delay); void zEntPlayer_SNDPlayStream(_tagePlayerStreamSnd player_snd); + +void zEntPlayer_SNDPlayStreamRandom(_tagePlayerStreamSnd player_snd_start, + _tagePlayerStreamSnd player_snd_end, float32 delay); + +// Only plays sound if player's spatula count is between lower and upper +void zEntPlayer_SNDPlayStreamRandom(uint32 lower, uint32 upper, + _tagePlayerStreamSnd player_snd_start, + _tagePlayerStreamSnd player_snd_end, float32 delay); + void zEntPlayer_SNDSetVol(_tagePlayerSnd player_snd, float32 new_vol); void zEntPlayer_SNDSetPitch(_tagePlayerSnd player_snd, float32 new_pitch); void zEntPlayer_SNDStop(_tagePlayerSnd player_snd); diff --git a/src/Game/zEntPlayerBungeeState.h b/src/Game/zEntPlayerBungeeState.h index de40c11..bf10e94 100644 --- a/src/Game/zEntPlayerBungeeState.h +++ b/src/Game/zEntPlayerBungeeState.h @@ -65,6 +65,8 @@ namespace bungee_state }; void load(xBase& data, xDynAsset& asset, ulong32); + bool active(); + bool landed(); } // namespace bungee_state #endif \ No newline at end of file diff --git a/src/Game/zFX.h b/src/Game/zFX.h index a36d3a1..225dc22 100644 --- a/src/Game/zFX.h +++ b/src/Game/zFX.h @@ -167,4 +167,7 @@ void zFXMuscleArmWave(xVec3* pos); void zFX_SpawnBubbleMenuTrail(const xVec3* pos, uint32 num, const xVec3* pos_rnd, const xVec3* vel_rnd); +void zFXPopOn(xEnt& ent, float32 rate, float32 time); +void zFXPopOff(xEnt& ent, float32 rate, float32 time); + #endif \ No newline at end of file diff --git a/src/Game/zLOD.h b/src/Game/zLOD.h index 57f5bc1..37a42c9 100644 --- a/src/Game/zLOD.h +++ b/src/Game/zLOD.h @@ -9,6 +9,8 @@ struct zLODTable float32 noRenderDist; xModelBucket** lodBucket[3]; float32 lodDist[3]; + + ASSIGNMENT_OPERATOR(zLODTable) }; struct zLODManager @@ -24,5 +26,6 @@ void zLOD_Update(uint32 percent_update); zLODTable* zLOD_Get(xEnt* ent); void AddToLODList(xModelInstance* model); xEnt* AddToLODList(xEnt* ent); +void zLOD_UseCustomTable(xEnt* ent, zLODTable* lod); #endif \ No newline at end of file diff --git a/src/Game/zNPCTypeBossSandy.cpp b/src/Game/zNPCTypeBossSandy.cpp index 53623b1..add5f44 100644 --- a/src/Game/zNPCTypeBossSandy.cpp +++ b/src/Game/zNPCTypeBossSandy.cpp @@ -65,7 +65,7 @@ extern float32 _1522; // -0.800000011920929 bf4ccccd extern float32 _1523; // -2.0 c0000000 extern float32 _1524; // 66.0 42840000 extern float32 _1525; // -2500.0 c51c4000 -extern float32 _1526; // -1.5 bfc00000 +extern float32 _1526_0; // -1.5 bfc00000 extern float32 _1527; // 13.0 41500000 extern float32 _1528; // 3.5 40600000 extern float32 _1529; // -2.5 c0200000