diff --git a/configure.py b/configure.py index c24f85221..7fac6562e 100644 --- a/configure.py +++ b/configure.py @@ -508,7 +508,7 @@ def MatchingFor(*versions): Object(Matching, "SB/Game/zParEmitter.cpp"), Object(Matching, "SB/Game/zPendulum.cpp"), Object(Matching, "SB/Game/zPickupTable.cpp"), - Object(NonMatching, "SB/Game/zPlatform.cpp"), + Object(NonMatching, "SB/Game/zPlatform.cpp", extra_cflags=["-sym on"]), Object(Matching, "SB/Game/zPortal.cpp"), Object(Matching, "SB/Game/zRenderState.cpp"), Object(Equivalent, "SB/Game/zRumble.cpp"), diff --git a/src/SB/Core/x/xAnim.h b/src/SB/Core/x/xAnim.h index 93d8a429c..6ce266d36 100644 --- a/src/SB/Core/x/xAnim.h +++ b/src/SB/Core/x/xAnim.h @@ -231,4 +231,7 @@ inline F32 xAnimFileRawTime(xAnimFile* data, float time) return data->TimeOffset + time; } +#define xAnimTableNewStateDefault(table, name, flags, userFlags) xAnimTableNewState((table), (name), (flags), (userFlags), 1.0f, NULL, NULL, 0.0f, NULL, NULL, xAnimDefaultBeforeEnter, NULL, NULL) +#define xAnimTableNewTransitionDefault(table, source, dest, priority, blendRecip) xAnimTableNewTransition((table), (source), (dest), NULL, NULL, 0x10, 0, 0.0f, 0.0f, (priority), 0, (blendRecip), NULL) + #endif diff --git a/src/SB/Core/x/xCollide.cpp b/src/SB/Core/x/xCollide.cpp index a14ea1f09..bc677ce8c 100644 --- a/src/SB/Core/x/xCollide.cpp +++ b/src/SB/Core/x/xCollide.cpp @@ -48,34 +48,6 @@ extern U8 xClumpColl_FilterFlags; #define RpGeometryGetMorphTargetMacro(_geometry, _index) \ (&((_geometry)->morphTarget[(_index)])) // bageomet.h -#define xVec3NormalizeMacro(o, v, len) \ - MACRO_START \ - { \ - F32 len2 = SQR((v)->x) + SQR((v)->y) + SQR((v)->z); \ - if (xeq(len2, 1.0f, 1e-5f)) \ - { \ - (o)->x = (v)->x; \ - (o)->y = (v)->y; \ - (o)->z = (v)->z; \ - *(len) = 1.0f; \ - } \ - else if (xeq(len2, 0.0f, 1e-5f)) \ - { \ - (o)->x = 0.0f; \ - (o)->y = 1.0f; \ - (o)->z = 0.0f; \ - *(len) = 0.0f; \ - } \ - else \ - { \ - *(len) = xsqrt(len2); \ - F32 len_inv = 1.0f / *(len); \ - (o)->x = (v)->x * len_inv; \ - (o)->y = (v)->y * len_inv; \ - (o)->z = (v)->z * len_inv; \ - } \ - } \ - MACRO_STOP _xCollsIdx xCollideGetCollsIdx(const xCollis* coll, const xVec3* tohit, const xMat3x3* mat) { diff --git a/src/SB/Core/x/xEnt.h b/src/SB/Core/x/xEnt.h index e0977846d..4e4bef392 100644 --- a/src/SB/Core/x/xEnt.h +++ b/src/SB/Core/x/xEnt.h @@ -184,13 +184,33 @@ struct xEnt : xBase void* user_data; // 0xCC }; -// collision types -#define XENT_COLLTYPE_NONE 0x0 -#define XENT_COLLTYPE_TRIG 0x1 // trigger (TRIG) -#define XENT_COLLTYPE_STAT 0x2 // static (SIMP) -#define XENT_COLLTYPE_DYN 0x4 // dynamic (PLAT) -#define XENT_COLLTYPE_NPC 0x8 // npc/enemy (VIL) -#define XENT_COLLTYPE_PLYR 0x10 // player (PLYR) +// Ent flags (xEnt::flags) +#define XENT_IS_VISIBLE ((U8)(1 << 0)) +#define XENT_IS_STACKED ((U8)(1 << 1)) +#define XENT_0x10 ((U8)(1 << 4)) +#define XENT_0x40 ((U8)(1 << 6)) +#define XENT_0x80 ((U8)(1 << 7)) + +// Physics flags (xEnt::pflags) +#define XENT_PFLAGS_IS_MOVING ((U8)(1 << 0)) +#define XENT_PFLAGS_HAS_VELOCITY ((U8)(1 << 1)) +#define XENT_PFLAGS_HAS_GRAVITY ((U8)(1 << 2)) +#define XENT_PFLAGS_HAS_DRAG ((U8)(1 << 3)) +#define XENT_PFLAGS_HAS_FRICTION ((U8)(1 << 4)) + +// More ent flags (xEnt::moreFlags) +#define XENT_MORE_FLAGS_0x8 ((U8)1<<3) +#define XENT_MORE_FLAGS_HITTABLE ((U8)1<<4) +#define XENT_MORE_FLAGS_ANIM_COLL ((U8)1<<5) + +// Collision types (xEnt::collType) +#define XENT_COLLTYPE_NONE (U8)0 +#define XENT_COLLTYPE_TRIG ((U8)(1 << (0))) +#define XENT_COLLTYPE_STAT ((U8)(1 << (1))) +#define XENT_COLLTYPE_DYN ((U8)(1 << (2))) +#define XENT_COLLTYPE_NPC ((U8)(1 << (3))) +#define XENT_COLLTYPE_PLYR ((U8)(1 << (4))) +#define XENT_COLLTYPE_ENV ((U8)(1 << (5))) // Size: 0x40 struct xEntShadow diff --git a/src/SB/Core/x/xEntDrive.h b/src/SB/Core/x/xEntDrive.h index b2a6f6b55..bd9c14663 100644 --- a/src/SB/Core/x/xEntDrive.h +++ b/src/SB/Core/x/xEntDrive.h @@ -36,6 +36,6 @@ struct xEntDrive void xEntDriveInit(xEntDrive* drv, xEnt* driven); void xEntDriveMount(xEntDrive* drv, xEnt* driver, F32 mt, const xCollis* coll); void xEntDriveDismount(xEntDrive* drv, F32 dmt); -void xEntDriveUpdate(xEntDrive* drv, xScene* s, F32 dt, xCollis* coll); +void xEntDriveUpdate(xEntDrive* drv, xScene* s, F32 dt, const xCollis* coll); #endif diff --git a/src/SB/Core/x/xEntMotion.cpp b/src/SB/Core/x/xEntMotion.cpp index ecd0cbe31..a7bada0b9 100644 --- a/src/SB/Core/x/xEntMotion.cpp +++ b/src/SB/Core/x/xEntMotion.cpp @@ -1307,46 +1307,6 @@ void xEntMotionDebugDraw(const xEntMotion*); _tagxPad* gDebugPad; -void xEntMotionRun(xEntMotion* motion) -{ - motion->flags &= 0xFFFB; -} - -void xEntMotionStop(xEntMotion* motion) -{ - motion->flags |= 0x4; -} - -U32 xEntMotionIsStopped(const xEntMotion* motion) -{ - return motion->flags & 0x4; -} - -U32 xEntERIsExtending(const xEntMotion* motion) -{ - return motion->t < motion->er.et; -} - -U32 xEntERIsExtended(const xEntMotion* motion) -{ - return motion->t >= motion->er.et && motion->t < motion->er.brt; -} - -U32 xEntERIsRetracted(const xEntMotion* motion) -{ - return motion->t >= motion->er.ert; -} - -U32 xEntERIsRetracting(const xEntMotion* motion) -{ - return motion->t >= motion->er.brt && motion->t < motion->er.ert; -} - -void xEntMPSetSpeed(xEntMotion* motion, F32 speed) -{ - motion->mp.speed = MAX(0.0f, speed); -} - void xQuatCopy(xQuat* a, const xQuat* b) { a->s = b->s; diff --git a/src/SB/Core/x/xEntMotion.h b/src/SB/Core/x/xEntMotion.h index c0ca73bad..d8371c887 100644 --- a/src/SB/Core/x/xEntMotion.h +++ b/src/SB/Core/x/xEntMotion.h @@ -2,6 +2,7 @@ #define XENTMOTION_H #include "xEnt.h" +#include "xEntMotionAsset.h" #include "xMovePoint.h" #include "xColor.h" @@ -186,5 +187,53 @@ void xEntMotionDebugExit(); void xEntMotionStop(xEntMotion* motion); void xEntMotionRun(xEntMotion* motion); U32 xEntMotionIsStopped(const xEntMotion* motion); +void xEntMechForward(xEntMotion* motion); +void xEntMechReverse(xEntMotion* motion); +void xEntMPSetSpeed(xEntMotion* motion, F32 speed); + +inline U32 xEntMotionIsStopped(const xEntMotion* motion) +{ + return motion->flags & k_XENTMOTION_STOPPED; +} + +inline void xEntMotionStop(xEntMotion* motion) +{ + motion->flags |= k_XENTMOTION_STOPPED; +} + +inline void xEntMotionRun(xEntMotion* motion) +{ + motion->flags &= (U16)~k_XENTMOTION_STOPPED; +} + +inline U32 xEntERIsExtending(const xEntMotion* motion) +{ + return motion->t < motion->er.et; +} + +inline U32 xEntERIsExtended(const xEntMotion* motion) +{ + return motion->t >= motion->er.et && motion->t < motion->er.brt; +} + +inline U32 xEntERIsRetracting(const xEntMotion* motion) +{ + return motion->t >= motion->er.brt && motion->t < motion->er.ert; +} + +inline U32 xEntERIsRetracted(const xEntMotion* motion) +{ + return motion->t >= motion->er.ert; +} + +inline void xEntMPSetSpeed(xEntMotion* motion, F32 speed) +{ + motion->mp.speed = MAX(0.0f, speed); +} + +inline void xEntMPAccelerate(xEntMotion* motion, F32 new_speed) +{ + motion->mp.speed = MAX(0.0f, motion->mp.speed + new_speed); +} #endif diff --git a/src/SB/Core/x/xVec3Inlines.h b/src/SB/Core/x/xVec3Inlines.h index b89883cae..8539fdac3 100644 --- a/src/SB/Core/x/xVec3Inlines.h +++ b/src/SB/Core/x/xVec3Inlines.h @@ -21,6 +21,35 @@ F32 xVec3LengthFast(F32 x, F32 y, F32 z); F32 xVec3LengthFast(const xVec3* vec); void xVec3AddScaled(xVec3* o, const xVec3* v, F32 s); +#define xVec3NormalizeMacro(o, v, len) \ + MACRO_START \ + { \ + F32 len2 = SQR((v)->x) + SQR((v)->y) + SQR((v)->z); \ + if (xeq(len2, 1.0f, 1e-5f)) \ + { \ + (o)->x = (v)->x; \ + (o)->y = (v)->y; \ + (o)->z = (v)->z; \ + *(len) = 1.0f; \ + } \ + else if (xeq(len2, 0.0f, 1e-5f)) \ + { \ + (o)->x = 0.0f; \ + (o)->y = 1.0f; \ + (o)->z = 0.0f; \ + *(len) = 0.0f; \ + } \ + else \ + { \ + *(len) = xsqrt(len2); \ + F32 len_inv = 1.0f / *(len); \ + (o)->x = (v)->x * len_inv; \ + (o)->y = (v)->y * len_inv; \ + (o)->z = (v)->z * len_inv; \ + } \ + } \ + MACRO_STOP + #define xVec3NormalizeDistXZMacro(o, a, b, dist) \ MACRO_START \ { \ diff --git a/src/SB/Game/zPlatform.cpp b/src/SB/Game/zPlatform.cpp index 4a14bc0e2..bd260178d 100644 --- a/src/SB/Game/zPlatform.cpp +++ b/src/SB/Game/zPlatform.cpp @@ -2,34 +2,36 @@ #include "zEnt.h" #include "zEntPlayer.h" #include "xEntDrive.h" +#include "xScrFx.h" #include "zParEmitter.h" +#include "zRumble.h" +#include "zFX.h" +#include "zCollGeom.h" +#include "zGoo.h" +#include "xSkyDome.h" +#include "zShrapnel.h" +#include "xEntMotionAsset.h" #include "xMath.h" #include "xMath3.h" +#include "xMathInlines.h" #include "xstransvc.h" #include "zGlobals.h" +#include "xCollide.h" #include zParEmitter* sEmitTremble; zParEmitter* sEmitBreakaway; -// Taken from zPlatform.s -// Defining these here makes the stringBase0 offsets match in the later functions. -char* str1 = ""; -char* str2 = "Idle"; -char* str3 = "Spring"; -char* str4 = "teeter_totter_pat"; -char* str5 = "teeter_totter_pat_bind"; -char* str6 = "PAREMIT_PLAT_TREMBLE"; -char* str7 = "PAREMIT_PLAT_BREAKAWAY"; -char* str8 = "skatepark_bumper"; -char* str9 = "skatepark_flipper"; -char* str10 = "Check1"; - -void zPlatformTranslate(xEnt* xent, xVec3* dpos, xMat4x3* dmat); -void zPlatform_Move(xEnt* entPlat, xScene* s, float dt, xEntFrame* frame); +static void zPlatformTranslate(xEnt* xent, xVec3* dpos, xMat4x3* dmat); +void zPlatform_Move(xEnt* entPlat, xScene* s, F32 dt, xEntFrame* frame); static void zPlatform_Tremble(zPlatform* plat, F32 ampl, F32 freq, F32 dur); +static void zPlatform_BreakawayFallFX(zPlatform* plat, F32); +static S32 zMechIsStartingForth(zPlatform* plat, U16 state); +static S32 zMechIsStartingBack(zPlatform* plat, U16 state); +static F32 SolvePaddleMotion(zPlatform* plat, F32* time, F32 tmr); +static void zPlatFM_Update(zPlatform* plat, xScene*, F32 dt); static void genericPlatRender(xEnt* ent) { @@ -46,25 +48,19 @@ void zPlatform_Init(void* plat, void* asset) zPlatform_Init((zPlatform*)plat, (xEntAsset*)asset); } -// FIXME: some asset pointer shenanigans plus a few other quirky spots void zPlatform_Init(zPlatform* plat, xEntAsset* asset) { - // asset pointer points to packed structure with more than just an xEntAsset inside! - xPlatformAsset* platAsset = (xPlatformAsset*)((char*)asset + sizeof(xEntAsset)); - xEntMotionAsset* entMotionAsset = (xEntMotionAsset*)((char*)platAsset + sizeof(xPlatformAsset)); - xLinkAsset* linkAsset = (xLinkAsset*)((char*)entMotionAsset + sizeof(xLinkAsset)); + xPlatformAsset* passet = (xPlatformAsset*)(asset + 1); + xEntMotionAsset* emasset = (xEntMotionAsset*)(passet + 1); zEntInit(plat, asset, 'PLAT'); - plat->passet = platAsset; - plat->subType = platAsset->type; + plat->passet = passet; + plat->subType = passet->type; - if (plat->linkCount != 0) - { - plat->link = linkAsset; - } - else - { + if (plat->linkCount) { + plat->link = (xLinkAsset*)(emasset + 1); + } else { plat->link = NULL; } @@ -73,124 +69,96 @@ void zPlatform_Init(zPlatform* plat, xEntAsset* asset) plat->eventFunc = zPlatformEventCB; plat->transl = zPlatformTranslate; plat->render = genericPlatRender; - plat->am = NULL; plat->bm = NULL; - plat->state = ZPLATFORM_STATE_INIT; - plat->plat_flags = 0x0; + plat->state = 0; + plat->plat_flags = 0; plat->fmrt = NULL; - plat->pauseMult = 1.0; + plat->pauseMult = 1.0f; plat->pauseDelta = 0.0f; - if (plat->subType == ZPLATFORM_SUBTYPE_BREAKAWAY) - { - plat->collis = (xEntCollis*)xMemAlloc(gActiveHeap, sizeof(xEntCollis), 0); - - xModelInstance* modelInst = NULL; - - plat->collis->chk = 0x0; - plat->collis->pen = 0x0; - - // TODO: does collis need to be null terminated??? - // this manual memory management is weird as heck but it matches the disassembly - *((U32*)&plat->collis->colls[18]) = NULL; - + if (plat->subType == ePlatformTypeBreakaway) { + plat->collis = (xEntCollis*)xMemAllocSize(sizeof(xEntCollis)); + plat->collis->chk = 0; + plat->collis->pen = 0; + plat->collis->post = NULL; plat->am = plat->model; - platAsset->ba.bustModelID = 0x0; - if (linkAsset->dstAssetID != NULL) - { - modelInst = (xModelInstance*)xSTFindAsset(linkAsset->dstAssetID, (U32*)&plat->flags); + void* buf = NULL; + U32 size = 0; + if (passet->ba.bustModelID) { + buf = xSTFindAsset(passet->ba.bustModelID, &size); } - - if (modelInst != NULL) - { - xEntLoadModel(plat, (RpAtomic*)modelInst); + if (buf) { + xEntLoadModel(plat, (RpAtomic*)buf); plat->bm = plat->model; - } - else - { + } else { plat->bm = NULL; } plat->model = plat->am; plat->collModel = NULL; - } - else if (plat->subType == ZPLATFORM_SUBTYPE_SPRINGBOARD) - { - xAnimFile* animFile = NULL; + } else if (plat->subType == ePlatformTypeSpringboard) { + void* spring_anim; + void* idle_anim; + xAnimFile* spring_file; + xAnimFile* idle_file; - xAnimFile* anim1File; - if (platAsset->sb.animID[0] != NULL) - { - anim1File = (xAnimFile*)xSTFindAsset(platAsset->sb.animID[0], NULL); - } - else - { - anim1File = NULL; - } + spring_file = NULL; + spring_anim = passet->sb.animID[0] ? xSTFindAsset(passet->sb.animID[0], NULL) : NULL; + idle_anim = passet->sb.animID[1] ? xSTFindAsset(passet->sb.animID[1], NULL) : NULL; - void* anim2File; - if (platAsset->sb.animID[1] != NULL) - { - anim2File = xSTFindAsset(platAsset->sb.animID[1], NULL); - } - else - { - anim2File = NULL; - } + if (spring_anim || idle_anim) { + gxAnimUseGrowAlloc = 1; - if (anim1File != NULL || anim2File != NULL) - { - gxAnimUseGrowAlloc = TRUE; + plat->atbl = xAnimTableNew("", NULL, 0); + xAnimTableNewStateDefault(plat->atbl, "Idle", 0x10, 0); - plat->atbl = xAnimTableNew("", NULL, 0x0); - xAnimTableNewState(plat->atbl, "Idle", 0x10, 0x0, 1.0f, NULL, NULL, 0.0f, NULL, NULL, - xAnimDefaultBeforeEnter, NULL, NULL); + if (spring_anim) { + xAnimTableNewStateDefault(plat->atbl, "Spring", 0x20, 0); + xAnimTableNewTransitionDefault(plat->atbl, "Spring", "Idle", 0, 0.1f); - if (anim1File != NULL) - { - xAnimTableNewState(plat->atbl, "Spring", 0x20, 0, 1.0f, NULL, NULL, 0.0f, NULL, - NULL, xAnimDefaultBeforeEnter, NULL, NULL); - xAnimTableNewTransition(plat->atbl, "Spring", "Idle", - (xAnimTransitionConditionalCallback)0x0, - (xAnimTransitionCallback)0x0, 0x10, 0, 0.0f, 0.0f, 0, 0, - 0.1f, NULL); - - animFile = xAnimFileNew(anim1File, "", 0, (xAnimFile**)0x0); - xAnimTableAddFile(plat->atbl, animFile, "Spring"); + spring_file = xAnimFileNew(spring_anim, "", 0, NULL); + xAnimTableAddFile(plat->atbl, spring_file, "Spring"); } - if (anim2File != NULL) - { - animFile = xAnimFileNew(anim2File, "", 0, NULL); - xAnimTableAddFile(plat->atbl, animFile, "Idle"); - } - else - { - xAnimTableAddFile(plat->atbl, animFile, "Idle"); - plat->atbl->StateList->Speed = 1.0f; + if (idle_anim) { + idle_file = xAnimFileNew(idle_anim, "", 0, NULL); + xAnimTableAddFile(plat->atbl, idle_file, "Idle"); + } else { + xAnimTableAddFile(plat->atbl, spring_file, "Idle"); + plat->atbl->StateList[0].Speed = 0.0f; } - // TODO: if this isn't matching, it's because the globals struct isn't defined correctly - // Figure out why that is - gxAnimUseGrowAlloc = FALSE; - xAnimPoolAlloc(&globals.scenePreload->mempool, plat, plat->atbl, plat->model); + gxAnimUseGrowAlloc = 0; + + xAnimPoolAlloc(&globals.sceneCur->mempool, plat, plat->atbl, plat->model); } - } - else if (plat->subType == ZPLATFORM_SUBTYPE_FM) - { - plat->fmrt = (zPlatFMRunTime*)xMemAlloc(gActiveHeap, sizeof(zPlatFMRunTime), 0); + } else if (plat->subType == ePlatformTypeFM) { + plat->fmrt = (zPlatFMRunTime*)xMemAllocSize(sizeof(zPlatFMRunTime)); } - xEntMotionInit(&plat->motion, plat, - (xEntMotionAsset*)((char*)asset + sizeof(xEntAsset) + sizeof(xPlatformAsset))); + xEntMotionInit(&plat->motion, plat, emasset); + xEntDriveInit(&plat->drv, plat); + plat->drv.flags = 0x1; if (plat->asset->modelInfoID == xStrHash("teeter_totter_pat") || - plat->asset->modelInfoID == xStrHash("teeter_totter_pat_bind")) + plat->asset->modelInfoID == xStrHash("teeter_totter_pat_bind")) { + plat->plat_flags |= 0x2; + } +} + +void zPlatform_Setup(zPlatform* ent, xScene* sc) +{ + zEntSetup((zEnt*)ent); + sEmitTremble = zParEmitterFind("PAREMIT_PLAT_TREMBLE"); + sEmitBreakaway = zParEmitterFind("PAREMIT_PLAT_BREAKAWAY"); + if (ent->subType == ZPLATFORM_SUBTYPE_PADDLE) { - plat->flags |= 0x2; + ent->tmr = 1e-9f; + ent->state = 2; + ent->ctr = ent->passet->paddle.startOrient; } } @@ -204,70 +172,854 @@ void zPlatform_Load(zPlatform* ent, xSerial* s) zEntLoad(ent, s); } -void zPlatform_Update(xEnt* ent, xScene* sc, float dt) +void zPlatform_Reset(zPlatform* plat, xScene* sc) +{ + if (plat->subType == ePlatformTypeBreakaway) { + plat->model = plat->am; + plat->collModel = NULL; + } + + zEntReset(plat); + + xEntMotionInit(&plat->motion, plat, (xEntMotionAsset*)(plat->passet + 1)); + xEntMotionReset(&plat->motion, sc); + + plat->plat_flags = 0x1; + + if (plat->subType == ePlatformTypeER) { + plat->state = 3; + } else if (plat->subType == ePlatformTypeBreakaway) { + plat->tmr = plat->passet->ba.ba_delay; + plat->state = 0; + plat->pflags &= (U8)~(XENT_PFLAGS_HAS_VELOCITY | XENT_PFLAGS_HAS_GRAVITY); + plat->collis->chk = 0; + + xVec3Copy(&plat->frame->vel, &g_O3); + + plat->bound.mat = (xMat4x3*)plat->model->Mat; + } else if (plat->subType == ePlatformTypeMech) { + plat->state = plat->motion.mech.state; + } else if (plat->subType == ePlatformTypeSpringboard) { + plat->tmr = -1.0f; + plat->ctr = 0; + } else if (plat->subType == ePlatformTypePaddle) { + plat->tmr = 1e-9f; + plat->state = 2; + plat->ctr = plat->passet->paddle.startOrient; + } else if (plat->subType == ePlatformTypeFM) { + for (S32 i = 0; i < 12; i++) { + plat->fmrt->flags = 0; + plat->fmrt->tmrs[i] = 0.0f; + plat->fmrt->ttms[i] = 0.0f; + plat->fmrt->atms[i] = 0.0f; + plat->fmrt->dtms[i] = 0.0f; + plat->fmrt->vms[i] = 0.0f; + plat->fmrt->dss[i] = 0.0f; + } + } + + if (plat->motion.type == k_XENTMOTIONTYPE_MP) { + plat->src = plat->motion.mp.src; + } + + plat->chkby &= (U8)~(XENT_COLLTYPE_PLYR | XENT_COLLTYPE_NPC | XENT_COLLTYPE_DYN); + + if (plat->passet->flags & 0x4) { + plat->chkby |= (XENT_COLLTYPE_PLYR | XENT_COLLTYPE_NPC); + } + + plat->bupdate(plat, (xVec3*)&plat->model->Mat->pos); + plat->moving = 0; + + if (plat->asset->modelInfoID == xStrHash("teeter_totter_pat") || + plat->asset->modelInfoID == xStrHash("teeter_totter_pat_bind")) { + plat->plat_flags |= 0x2; + } + + plat->pauseMult = 1.0f; + plat->pauseDelta = 0.0f; +} + +static S32 zMechIsStartingForth(zPlatform* plat, U16 state) { + if (plat->motion.asset->mech.type == k_XENTMOTIONMECH_ROT_THEN_SLIDE) { + return state == 1; + } else { + return state == 0; + } } -void zPlatform_Move(xEnt* entPlat, xScene* s, float dt, xEntFrame* frame) +static S32 zMechIsStartingBack(zPlatform* plat, U16 state) { - zPlatform* plat = (zPlatform*)entPlat; - xEntMotionMove(&plat->motion, s, dt, frame); - xEntDriveUpdate(&plat->drv, s, dt, NULL); + if (plat->motion.asset->mech.type == k_XENTMOTIONMECH_ROT_THEN_SLIDE) { + return state == 4; + } else { + return state == 3; + } } -void zPlatform_Tremble(zPlatform* plat, float ampl, float freq, float dur); +static F32 SolvePaddleMotion(zPlatform* plat, F32* time, F32 tmr) +{ + xPlatformPaddleData* paddle = &plat->passet->paddle; + + F32 destOrient = paddle->orient[plat->ctr]; + F32 srcOrient; + if (plat->state == 1 || plat->state == 3) { + if (plat->ctr + 1 == paddle->countOrient) { + srcOrient = paddle->orientLoop; + } else { + srcOrient = paddle->orient[plat->ctr + 1]; + } + } else if (plat->state == 2 || plat->state == 4) { + if (plat->ctr == 0) { + destOrient = paddle->orientLoop; + srcOrient = paddle->orient[paddle->countOrient - 1]; + } else { + srcOrient = paddle->orient[plat->ctr - 1]; + } + } else { + return destOrient; + } + + F32 absDelta = xabs(destOrient - srcOrient); + + if (plat->state == 3 || plat->state == 4) { + time[0] = 0.0f; + time[1] = 0.2f; + time[2] = 0.0f; -void zPlatform_Mount(zPlatform* ent) + if (tmr >= 0.0f) { + if (tmr > 0.1f) tmr = 0.2f - tmr; + + F32 stutterAmount = 100.0f * tmr; + if (destOrient < srcOrient) stutterAmount = -stutterAmount; + + return destOrient + stutterAmount; + } + + return destOrient; + } + + F32 A = 0.0f; + F32 D = 0.0f; + F32 distA, distC, distD; + + if (paddle->accelTime && paddle->decelTime) { + A = paddle->rotateSpeed / paddle->accelTime; + D = paddle->rotateSpeed / paddle->decelTime; + + time[0] = xsqrt(2.0f * D * absDelta / (A * D + A * A)); + if (time[0] < paddle->accelTime) { + time[1] = 0.0f; + time[2] = A * time[0] / D; + } else { + distA = 0.5f * paddle->rotateSpeed * paddle->accelTime; + distD = 0.5f * paddle->rotateSpeed * paddle->decelTime; + distC = absDelta - distA - distD; + + time[0] = paddle->accelTime; + time[1] = distC / paddle->rotateSpeed; + time[2] = paddle->decelTime; + } + } else if (paddle->accelTime) { + A = paddle->rotateSpeed / paddle->accelTime; + + time[0] = xsqrt(2.0f * absDelta / A); + time[2] = 0.0f; + if (time[0] < paddle->accelTime) { + time[1] = 0.0f; + } else { + distA = 0.5f * paddle->rotateSpeed * paddle->accelTime; + distC = absDelta - distA; + + time[0] = paddle->accelTime; + time[1] = distC / paddle->rotateSpeed; + } + } else if (paddle->decelTime) { + D = paddle->rotateSpeed / paddle->decelTime; + + time[0] = 0.0f; + time[2] = xsqrt(2.0f * absDelta / D); + if (time[2] < paddle->decelTime) { + time[1] = 0.0f; + } else { + distD = 0.5f * paddle->rotateSpeed * paddle->decelTime; + distC = absDelta - distD; + + time[1] = distC / paddle->rotateSpeed; + time[2] = paddle->decelTime; + } + } else { + time[0] = 0.0f; + time[1] = absDelta / paddle->rotateSpeed; + time[2] = 0.0f; + } + + if (tmr >= 0.0f) { + F32 lerp; + if (time[2] && tmr <= time[2]) { + lerp = 1.0f - 0.5f * D * tmr * tmr / absDelta; + } else { + F32 ttot = time[0] + time[1] + time[2]; + tmr = ttot - tmr; + if (tmr > ttot) tmr = ttot; + + if (time[0] && (!time[1] || tmr <= time[0])) { + lerp = 0.5f * A * tmr * tmr / absDelta; + } else { + tmr -= time[0]; + lerp = (0.5f * paddle->rotateSpeed * paddle->accelTime + tmr * paddle->rotateSpeed) / absDelta; + } + } + + return lerp * (destOrient - srcOrient) + srcOrient; + } + + return 0.0f; +} + +void zPlatform_PaddleStartRotate(xEnt* entplat, S32 direction, S32 stutter) { - if (ent->subType == ZPLATFORM_SUBTYPE_BREAKAWAY) + zPlatform* plat = (zPlatform*)entplat; + F32 time[3]; + + if (stutter != 0) { - if (ent->state == 0) + if (direction > 0) + { + plat->state = ZPLATFORM_STATE_UNK4; + } + else if (direction < 0) { - if ((ent->passet->ba.breakflags & 1) && zEntPlayer_IsSneaking()) + plat->state = ZPLATFORM_STATE_UNK1; + } + } + else + { + if (direction > 0) + { + plat->state = ZPLATFORM_STATE_UNK3; + plat->ctr += 1; + + if (plat->ctr >= plat->passet->paddle.countOrient) { - ent->state = 1; + plat->ctr = 0; } - else + } + else if (direction < 0) + { + plat->state = ZPLATFORM_STATE_UNK2; + plat->ctr -= 1; + + if (plat->ctr < 0) { - ent->state = 2; + plat->ctr = plat->passet->paddle.countOrient - 1; + } + } + } + + SolvePaddleMotion(plat, time, -1.0f); + plat->tmr = time[0] + time[1] + time[2]; +} + +U32 zPlatform_PaddleCollide(xCollis* coll, const xVec3* hitsource, const xVec3* hitvel, U32 worldSpaceNorm) +{ + zPlatform* plat = (zPlatform*)coll->optr; + if (plat->state != 0) { + return 0; + } + + xVec3 locnorm; + if (worldSpaceNorm) { + xMat3x3Tolocal(&locnorm, (xMat3x3*)plat->model->Mat, &coll->norm); + } else { + locnorm = coll->norm; + } + + xVec3 lochitsrc; + xMat4x3Tolocal(&lochitsrc, (xMat4x3*)plat->model->Mat, hitsource); + + xVec3 lochitvel; + xMat3x3Tolocal(&lochitvel, (xMat3x3*)plat->model->Mat, hitvel); + + if (xabs(locnorm.y) > xabs(locnorm.x) && xabs(locnorm.y) > xabs(locnorm.z)) { + return 0; + } + + if (xabs(lochitvel.y) > xabs(lochitvel.x) && xabs(lochitvel.y) > xabs(lochitvel.z)) { + return 0; + } + + xVec3Normalize(&locnorm, &locnorm); + xVec3Normalize(&lochitvel, &lochitvel); + + F32 hitdot = xVec3Dot(&locnorm, &lochitvel); + if (hitdot > -0.7071f) { + return 0; + } + + xVec3 hitsrcbot, hitsrctop; + hitsrcbot = lochitsrc; + hitsrctop = lochitsrc; + + hitsrcbot.y -= 5.0f; + hitsrctop.y += 5.0f; + + xMat4x3Toworld(&hitsrcbot, (xMat4x3*)plat->model->Mat, &hitsrcbot); + xMat4x3Toworld(&hitsrctop, (xMat4x3*)plat->model->Mat, &hitsrctop); + + xRay3 hitsrcray; + hitsrcray.origin.x = hitsrcbot.x; + hitsrcray.origin.y = hitsrcbot.y; + hitsrcray.origin.z = hitsrcbot.z; + hitsrcray.dir.x = hitsrctop.x - hitsrcbot.x; + hitsrcray.dir.y = hitsrctop.y - hitsrcbot.y; + hitsrcray.dir.z = hitsrctop.z - hitsrcbot.z; + hitsrcray.min_t = 0.0f; + hitsrcray.max_t = xVec3Normalize(&hitsrcray.dir, &hitsrcray.dir); + hitsrcray.flags = XRAY3_USE_MIN | XRAY3_USE_MAX; + + xCollis hitsrccoll; + xRayHitsBound(&hitsrcray, &plat->bound, &hitsrccoll); + + if (!(hitsrccoll.flags & k_HIT_IT)) { + return 0; + } + + S32 posX, posZ, direction; + if (xabs(lochitvel.x) < xabs(lochitvel.z)) { + posX = (lochitsrc.x > 0.0f); + posZ = (lochitsrc.z > 0.0f); + if ((posX ^ posZ) == 0) { + direction = 1; + } else { + direction = -1; + } + } else { + posX = (lochitsrc.x > 0.0f); + posZ = (lochitsrc.z > 0.0f); + if ((posX ^ posZ) == 0) { + direction = -1; + } else { + direction = 1; + } + } + + S32 stutter = 0; + if (direction == 1) { + if (!(plat->passet->paddle.paddleFlags & 0x1) || + (!(plat->passet->paddle.paddleFlags & 0x4) && plat->ctr + 1 == plat->passet->paddle.countOrient)) { + stutter = 1; + } + } + if (direction == -1) { + if (!(plat->passet->paddle.paddleFlags & 0x2) || + (!(plat->passet->paddle.paddleFlags & 0x4) && plat->ctr == 0)) { + stutter = 1; + } + } + + if (!stutter) { + if (direction > 0) { + zEntEvent(plat, eEventHit_PaddleLeft); + } else { + zEntEvent(plat, eEventHit_PaddleRight); + } + } + + zPlatform_PaddleStartRotate(plat, direction, stutter); - // Needs to be used or the comparison's operands will be swapped. - F32 restingSpeed = 0.0f; - if (ent->passet->fr.fspeed != restingSpeed) + return 1; +} + +static void zPlatFM_Update(zPlatform* plat, xScene*, F32 dt) +{ + for (S32 i = 0; i < 12; i++) { + zPlatFMRunTime* fmrt = plat->fmrt; + + F32 tm = fmrt->tmrs[i]; + if (tm > 0.0f) { + F32 ttm = fmrt->ttms[i]; + F32 atm = fmrt->atms[i]; + F32 dtm = fmrt->dtms[i]; + F32 vm = fmrt->vms[i]; + + F32 ds; + F32 etm = ttm - tm; + + if (tm > atm) { + if (atm > 0.0f) { + if (tm - dt < atm) { + if (dtm > 0.0f) { + if (tm - dt < dtm) { + if (tm - dt < 0.0f) { + F32 p = ttm - atm; + F32 cfacc = 0.5f * (p + etm) * (p - etm) / p; + F32 cfcs = atm - dtm; + F32 cfdec = 0.5f * dtm; + ds = cfacc + cfcs + cfdec; + } else { + F32 p = ttm - atm; + F32 cfacc = 0.5f * (p + etm) * (p - etm) / p; + F32 cfcs = atm - dtm; + F32 cfdec = 0.5f * (dtm + (tm - dt)) * (dtm - (tm - dt)) / dtm; + ds = cfacc + cfcs + cfdec; + } + } else { + F32 p = ttm - atm; + F32 cfacc = 0.5f * (p + etm) * (p - etm) / p; + F32 cfcs = atm - (tm - dt); + ds = cfacc + cfcs; + } + } else { + if (tm - dt < 0.0f) { + F32 p = ttm - atm; + F32 cfacc = 0.5f * (p + etm) * (p - etm) / p; + F32 cfcs = atm; + ds = cfacc + cfcs; + } else { + F32 p = ttm - atm; + F32 cfacc = 0.5f * (p + etm) * (p - etm) / p; + F32 cfcs = atm - (tm - dt); + ds = cfacc + cfcs; + } + } + } else { + F32 p = ttm - atm; + ds = (etm + 0.5f * dt) * dt / p; + } + } else { + if (tm - dt < 0.0f) { + ds = (etm + 0.5f * tm) * tm / ttm; + } else { + ds = (etm + 0.5f * dt) * dt / ttm; + } + } + } else { + if (tm < dtm) { + if (tm - dt < 0.0f) { + ds = 0.5f * tm * tm / dtm; + } else { + ds = (tm - 0.5f * dt) * dt / dtm; + } + } else { + if (dtm > 0.0f) { + if (tm - dt < dtm) { + if (tm - dt < 0.0f) { + F32 cfcs = tm - dtm; + F32 cfdec = 0.5f * dtm; + ds = cfcs + cfdec; + } else { + F32 cfcs = tm - dtm; + F32 cfdec = 0.5f * (dtm + (tm - dt)) * (dtm - (tm - dt)) / dtm; + ds = cfcs + cfdec; + } + } else { + ds = dt; + } + } else { + if (tm - dt < 0.0f) { + ds = tm; + } else { + ds = dt; + } + } + } + } + + ds *= vm; + fmrt->dss[i] -= ds; + + xMat4x3* pmat = (xMat4x3*)plat->model->Mat; + + if (i == 0) { + F32 translx = pmat->right.x * ds; + F32 transly = pmat->right.y * ds; + F32 translz = pmat->right.z * ds; + pmat->pos.x += translx; + pmat->pos.y += transly; + pmat->pos.z += translz; + } else if (i == 1) { + F32 translx = pmat->up.x * ds; + F32 transly = pmat->up.y * ds; + F32 translz = pmat->up.z * ds; + pmat->pos.x += translx; + pmat->pos.y += transly; + pmat->pos.z += translz; + } else if (i == 2) { + F32 translx = pmat->at.x * ds; + F32 transly = pmat->at.y * ds; + F32 translz = pmat->at.z * ds; + pmat->pos.x += translx; + pmat->pos.y += transly; + pmat->pos.z += translz; + } else if (i == 3) { + pmat->pos.x += ds; + } else if (i == 4) { + pmat->pos.y += ds; + } else if (i == 5) { + pmat->pos.z += ds; + } else if (i == 6) { + xMat3x3 preR; + xMat3x3RotX(&preR, ds); + xMat3x3Mul(pmat, &preR, pmat); + } else if (i == 7) { + xMat3x3 preR; + xMat3x3RotY(&preR, ds); + xMat3x3Mul(pmat, &preR, pmat); + } else if (i == 8) { + xMat3x3 preR; + xMat3x3RotZ(&preR, ds); + xMat3x3Mul(pmat, &preR, pmat); + } else if (i == 9) { + xMat3x3 postR; + xMat3x3RotX(&postR, ds); + xMat3x3Mul(pmat, pmat, &postR); + } else if (i == 10) { + xMat3x3 postR; + xMat3x3RotY(&postR, ds); + xMat3x3Mul(pmat, pmat, &postR); + } else if (i == 11) { + xMat3x3 postR; + xMat3x3RotZ(&postR, ds); + xMat3x3Mul(pmat, pmat, &postR); + } + + fmrt->tmrs[i] -= dt; + if (fmrt->tmrs[i] < 0.0f) { + F32 rts = xsqrt(SQR(pmat->right.x) + SQR(pmat->right.y) + SQR(pmat->right.z)); + F32 ups = xsqrt(SQR(pmat->up.x) + SQR(pmat->up.y) + SQR(pmat->up.z)); + F32 ats = xsqrt(SQR(pmat->at.x) + SQR(pmat->at.y) + SQR(pmat->at.z)); + + { + F32 inv_t = 100.0f; + if (pmat->pos.x < 0.0f) { + pmat->pos.x = 0.01f * (S32)(pmat->pos.x * inv_t - 0.5f); + } else { + pmat->pos.x = 0.01f * (S32)(pmat->pos.x * inv_t + 0.5f); + } + if (pmat->pos.y < 0.0f) { + pmat->pos.y = 0.01f * (S32)(pmat->pos.y * inv_t - 0.5f); + } else { + pmat->pos.y = 0.01f * (S32)(pmat->pos.y * inv_t + 0.5f); + } + if (pmat->pos.z < 0.0f) { + pmat->pos.z = 0.01f * (S32)(pmat->pos.z * inv_t - 0.5f); + } else { + pmat->pos.z = 0.01f * (S32)(pmat->pos.z * inv_t + 0.5f); + } + } + { - zPlatform_Tremble(ent, 0.06f, DEG2RAD(720), ent->passet->fr.fspeed + 1.0f); + F32 inv_t = 100.0f; + if (pmat->right.x < 0.0f) { + pmat->right.x = 0.01f * (S32)(pmat->right.x * inv_t - 0.5f); + } else { + pmat->right.x = 0.01f * (S32)(pmat->right.x * inv_t + 0.5f); + } + if (pmat->right.y < 0.0f) { + pmat->right.y = 0.01f * (S32)(pmat->right.y * inv_t - 0.5f); + } else { + pmat->right.y = 0.01f * (S32)(pmat->right.y * inv_t + 0.5f); + } + if (pmat->right.z < 0.0f) { + pmat->right.z = 0.01f * (S32)(pmat->right.z * inv_t - 0.5f); + } else { + pmat->right.z = 0.01f * (S32)(pmat->right.z * inv_t + 0.5f); + } } + + F32 len; + xVec3NormalizeMacro(&pmat->right, &pmat->right, &len); + + { + F32 inv_t = 100.0f; + if (pmat->up.x < 0.0f) { + pmat->up.x = 0.01f * (S32)(pmat->up.x * inv_t - 0.5f); + } else { + pmat->up.x = 0.01f * (S32)(pmat->up.x * inv_t + 0.5f); + } + if (pmat->up.y < 0.0f) { + pmat->up.y = 0.01f * (S32)(pmat->up.y * inv_t - 0.5f); + } else { + pmat->up.y = 0.01f * (S32)(pmat->up.y * inv_t + 0.5f); + } + if (pmat->up.z < 0.0f) { + pmat->up.z = 0.01f * (S32)(pmat->up.z * inv_t - 0.5f); + } else { + pmat->up.z = 0.01f * (S32)(pmat->up.z * inv_t + 0.5f); + } + } + + xVec3NormalizeMacro(&pmat->up, &pmat->up, &len); + + F32 rdotu = -(pmat->right.x * pmat->up.x + + pmat->right.y * pmat->up.y + + pmat->right.z * pmat->up.z); + + pmat->up.x += pmat->right.x * rdotu; + pmat->up.y += pmat->right.y * rdotu; + pmat->up.z += pmat->right.z * rdotu; + + xVec3NormalizeMacro(&pmat->up, &pmat->up, &len); + + pmat->at.x = pmat->right.y * pmat->up.z - pmat->up.y * pmat->right.z; + pmat->at.y = pmat->right.z * pmat->up.x - pmat->up.z * pmat->right.x; + pmat->at.z = pmat->right.x * pmat->up.y - pmat->up.x * pmat->right.y; + pmat->right.x *= rts; + pmat->right.y *= rts; + pmat->right.z *= rts; + pmat->up.x *= ups; + pmat->up.y *= ups; + pmat->up.z *= ups; + pmat->at.x *= ats; + pmat->at.y *= ats; + pmat->at.z *= ats; + + fmrt->flags &= ~(1 << i); + fmrt->tmrs[i] = 0.0f; + fmrt->ttms[i] = 0.0f; + fmrt->atms[i] = 0.0f; + fmrt->dtms[i] = 0.0f; + fmrt->vms[i] = 0.0f; + fmrt->dss[i] = 0.0f; + + zEntEvent(plat, plat, eEventTranslLocalXDone + i); } } } } -void zPlatform_Setup(zPlatform* ent, xScene* sc) +void zPlatform_Update(xEnt* entplat, xScene* sc, F32 dt) { - zEntSetup((zEnt*)ent); - sEmitTremble = zParEmitterFind("PAREMIT_PLAT_TREMBLE"); - sEmitBreakaway = zParEmitterFind("PAREMIT_PLAT_BREAKAWAY"); - if (ent->subType == ZPLATFORM_SUBTYPE_PADDLE) - { - ent->tmr = -1e38; - ent->state = 2; - ent->ctr = ent->passet->paddle.startOrient; + zPlatform* plat = (zPlatform*)entplat; + + if (plat->subType != ePlatformTypeBreakaway) { + plat->pauseMult = CLAMP(plat->pauseMult + plat->pauseDelta, 0.000001f, 1.0f); + dt *= plat->pauseMult; } -} -void zPlatform_Dismount(zPlatform* ent) -{ - if ((ent->subType == 9) && (ent->state == 1)) - { - ent->state = 0; + if (plat->subType == ePlatformTypeBreakaway) { + plat->model->Alpha += 4.0f * dt; + if (plat->model->Alpha > 1.0f) { + plat->model->Alpha = 1.0f; + } } + + xEntUpdate(plat, sc, dt); + + if (plat->subType == ePlatformTypeER) { + U16 state = plat->motion.er.state; + if (plat->state == state || + xEntERIsExtending(&plat->motion) || + xEntERIsExtended(&plat->motion) || + xEntERIsRetracting(&plat->motion) || + xEntERIsRetracted(&plat->motion)) { + // do nothing + } + plat->state = state; + } else if (plat->subType == ePlatformTypeBreakaway) { + if (plat->state == 1 && !zEntPlayer_IsSneaking()) { + plat->state = 2; + if (plat->passet->ba.ba_delay) { + zPlatform_Tremble(plat, 0.06f, 8*PI, 1.0f + plat->passet->ba.ba_delay); + } + } + if (plat->state == 2) { + plat->tmr -= dt; + if (plat->tmr <= 0.0f) { + zPlatform_BreakawayFallFX(plat, dt); + plat->state = 3; + plat->pflags |= 0x6; + plat->tmr = plat->passet->ba.reset_delay; + if (plat->bm) { + plat->model = plat->bm; + plat->collModel = plat->model; + xMat4x3Copy((xMat4x3*)plat->bm->Mat, (xMat4x3*)plat->am->Mat); + plat->bound.mat = (xMat4x3*)plat->model->Mat; + } + zEntEvent(plat, eEventBreak); + } + } else if (plat->state == 3) { + plat->tmr -= dt; + if (plat->collis->colls[0].flags & k_HIT_IT) { + plat->state = 4; + plat->pflags &= (U8)~(XENT_PFLAGS_HAS_VELOCITY | XENT_PFLAGS_HAS_GRAVITY); + plat->collis->chk = 0; + xVec3Copy(&plat->frame->vel, &g_O3); + } else if (plat->tmr <= 0.0f) { + if (xBaseIsEnabled(plat)) { + zEntEvent(plat, eEventReset); + } else { + zPlatform_Reset(plat, sc); + } + plat->model->Alpha = 0.0f; + plat->model->PipeFlags = (plat->model->PipeFlags & ~0xC) | 0x8; + } else if (plat->passet->ba.reset_delay - plat->tmr >= 25.0f) { + plat->state = 5; + plat->pflags &= (U8)~(XENT_PFLAGS_HAS_VELOCITY | XENT_PFLAGS_HAS_GRAVITY); + plat->collis->chk = 0; + xVec3Copy(&plat->frame->vel, &g_O3); + } + } else if (plat->state == 4) { + plat->tmr -= dt; + if (plat->tmr <= 0.0f) { + if (xBaseIsEnabled(plat)) { + zEntEvent(plat, eEventReset); + } else { + zPlatform_Reset(plat, sc); + } + plat->model->Alpha = 0.0f; + plat->model->PipeFlags = (plat->model->PipeFlags & ~0xC) | 0x8; + } + } + } else if (plat->subType == ePlatformTypeMech) { + U16 state = plat->motion.mech.state; + if (state != plat->state) { + xEntMotionMechData* mkasst = &plat->motion.asset->mech; + if (plat->state == 2) { + zEntEvent(plat, eEventArriveHalfway); + } else if (state == 6 || state == 7 || + (!(mkasst->flags & k_XENTMOTIONMECH_ONCE) && (state == 0 || state == 1))) { + zEntEvent(plat, eEventArrive); + } + if (zMechIsStartingForth(plat, state) || + zMechIsStartingBack(plat, state)) { + // do nothing + } + plat->state = state; + } + } else if (plat->subType == ePlatformTypeSpringboard) { + plat->tmr -= dt; + } else if (plat->subType == ePlatformTypeConvBelt) { + xEntDrive* drv = &globals.player.drv; + if (plat == drv->odriver || plat == drv->driver) { + F32 s = (plat == drv->driver) ? drv->s : drv->os; + xEnt* p = drv->driven; + xVec3SMul(&p->frame->dpos, &xModelGetFrame(plat->model)->right, s * plat->passet->cb.speed * dt); + xVec3AddTo((xVec3*)&p->model->Mat->pos, &p->frame->dpos); + } + } else if (plat->subType == ePlatformTypeTeeter) { + xEntDrive* drv = &globals.player.drv; + if (plat != drv->odriver && plat != drv->driver) { + F32 ctilt = plat->frame->rot.axis.z; + F32 itilt = plat->asset->ang.z; + F32 dtilt = xabs(DEG2RAD(plat->passet->teet.invmass) * dt); + if (ctilt != itilt) { + if (ctilt < itilt) { + dtilt = MIN(dtilt, itilt - ctilt); + } else if (ctilt > itilt) { + dtilt = MAX(-dtilt, itilt - ctilt); + } + plat->frame->rot.axis.z += dtilt; + xMat3x3Euler((xMat3x3*)plat->model->Mat, + plat->frame->rot.axis.x, + plat->frame->rot.axis.y, + plat->frame->rot.axis.z); + xVec3* scale = &plat->asset->scale; + xVec3SMulBy((xVec3*)&plat->model->Mat->right, scale->x); + xVec3SMulBy((xVec3*)&plat->model->Mat->up, scale->y); + xVec3SMulBy((xVec3*)&plat->model->Mat->at, scale->z); + } + } else { + F32 s = (plat == drv->driver) ? drv->s : drv->os; + xEnt* p = drv->driven; + xVec3 lpos; + xMat4x3Tolocal(&lpos, xModelGetFrame(plat->model), &p->frame->mat.pos); + F32 cangle = plat->frame->rot.axis.z; + F32 dangle = -s * DEG2RAD(plat->passet->teet.invmass) * lpos.x * dt; + F32 mangle = xabs(plat->passet->teet.maxtilt); + F32 eangle = dangle + cangle; + F32 tangle = xabs(eangle) - mangle; + if (tangle > 0.0f) { + if (dangle < 0.0f) dangle += tangle; + else if (dangle > 0.0f) dangle -= tangle; + } + plat->frame->rot.axis.z += dangle; + xMat3x3Euler((xMat3x3*)plat->model->Mat, + plat->frame->rot.axis.x, + plat->frame->rot.axis.y, + plat->frame->rot.axis.z); + xVec3* scale = &plat->asset->scale; + xVec3SMulBy((xVec3*)&plat->model->Mat->right, scale->x); + xVec3SMulBy((xVec3*)&plat->model->Mat->up, scale->y); + xVec3SMulBy((xVec3*)&plat->model->Mat->at, scale->z); + } + } else if (plat->subType == ePlatformTypePaddle) { + if (plat->tmr) { + plat->tmr -= dt; + if (plat->tmr < 0.0f) { + plat->tmr = 0.0f; + plat->state = 0; + } + F32 time[3]; + F32 orient = DEG2RAD(SolvePaddleMotion(plat, time, plat->tmr)); + xMat3x3 orientrot; + xMat3x3RotC(&orientrot, 0.0f, 1.0f, 0.0f, orient); + xMat3x3 origrot; + xMat3x3Euler(&origrot, plat->asset->ang.x, plat->asset->ang.y, plat->asset->ang.z); + xMat3x3Mul((xMat3x3*)plat->model->Mat, &orientrot, &origrot); + xVec3* scale = &plat->asset->scale; + xVec3SMulBy((xVec3*)&plat->model->Mat->right, scale->x); + xVec3SMulBy((xVec3*)&plat->model->Mat->up, scale->y); + xVec3SMulBy((xVec3*)&plat->model->Mat->at, scale->z); + } + } else if (plat->subType == ePlatformTypeFM) { + if (!(plat->plat_flags & 0x4)) { + zPlatFM_Update(plat, sc, dt); + } + } + + if (plat->motion.type == k_XENTMOTIONTYPE_MP) { + xMovePoint* src = plat->motion.mp.src; + if (src != plat->src) { + zEntEvent(plat, src, eEventArrive); + plat->src = src; + } + } + + S32 moving; + xVec3* opos = &plat->frame->oldmat.pos; + xVec3* pos = &plat->frame->mat.pos; + xVec3* orot = &plat->frame->oldrot.axis; + xVec3* rot = &plat->frame->rot.axis; + if (plat->subType == ePlatformTypeTeeter) { + if (orot->x != rot->x || orot->y != rot->y || orot->z != rot->z) { + moving = TRUE; + } else { + moving = FALSE; + } + } else if (plat->subType == ePlatformTypePaddle) { + if (plat->tmr != 0.0f) { + moving = TRUE; + } else { + moving = FALSE; + } + } else { + if (opos->x != pos->x || opos->y != pos->y || opos->z != pos->z || + orot->x != rot->x || orot->y != rot->y || orot->z != rot->z) { + moving = TRUE; + } else { + moving = FALSE; + } + } + + if (moving != plat->moving) { + if (moving) { + zEntEvent(plat, eEventStartMoving); + } else { + zEntEvent(plat, eEventStopMoving); + } + } + + plat->moving = moving; } -void zPlatformTranslate(xEnt* xent, xVec3* dpos, xMat4x3* dmat) +void zPlatform_Move(xEnt* entPlat, xScene* s, F32 dt, xEntFrame* frame) { - zPlatform* plat = (zPlatform*)xent; - xEntDefaultTranslate(xent, dpos, dmat); - xEntMotionTranslate(&plat->motion, dpos, dmat); + zPlatform* plat = (zPlatform*)entPlat; + xEntMotionMove(&plat->motion, s, dt, frame); + xEntDriveUpdate(&plat->drv, s, dt, NULL); } void zPlatform_Shake(zPlatform* plat, F32 _unused, F32 ampl, F32 freq) @@ -347,171 +1099,40 @@ void zPlatform_BreakawayFallFX(zPlatform* ent, F32 dt) info.custom_flags = 0x100; info.pos = *xEntGetCenter(ent); info.pos.y += 0.5f; - for (int iVar2 = 0; iVar2 < 25; iVar2++) + for (S32 iVar2 = 0; iVar2 < 25; iVar2++) { - xParEmitterEmitCustom(sEmitBreakaway, 0.03333333f, &info); + xParEmitterEmitCustom(sEmitBreakaway, 1/30.f, &info); } } } -void zPlatform_Reset(zPlatform* plat, xScene* sc) +void zPlatform_Mount(zPlatform* plat) { - if (plat->subType == ZPLATFORM_SUBTYPE_BREAKAWAY) - { - plat->model = plat->am; - plat->collModel = NULL; - } - - zEntReset(plat); - - // FIXME: One of the xPlatformAssetData structs is bigger than detected by DWARF data. - // Need to eventually figure out which one it is. - xEntMotionInit(&plat->motion, plat, (xEntMotionAsset*)((char*)plat->passet + 0x3C)); - xEntMotionReset(&plat->motion, sc); - - plat->plat_flags = 0x1; - if (plat->subType == ZPLATFORM_SUBTYPE_PLATFORM) - { - plat->state = ZPLATFORM_STATE_UNK1; - } - else if (plat->subType == ZPLATFORM_SUBTYPE_BREAKAWAY) - { - plat->tmr = plat->passet->ba.ba_delay; - plat->state = ZPLATFORM_STATE_INIT; - plat->pflags &= 0xF9; - plat->collis->chk = 0x0; - - xVec3Copy(&plat->frame->vel, (const xVec3*)&g_O3); - - plat->bound.mat = (xMat4x3*)plat->model->Mat; - } - else if (plat->subType == ZPLATFORM_SUBTYPE_MECH) - { - plat->state = (U16)plat->motion.mech.state; - } - else if (plat->subType == ZPLATFORM_SUBTYPE_SPRINGBOARD) - { - plat->tmr = -1.0f; - plat->ctr = 0; - } - else if (plat->subType == ZPLATFORM_SUBTYPE_PADDLE) - { - plat->tmr = 1e-9f; - plat->state = ZPLATFORM_STATE_UNK3; - plat->ctr = plat->passet->paddle.startOrient; - } - else if (plat->subType == ZPLATFORM_SUBTYPE_FM) - { - for (U32 i = 0; i < 12; i++) - { - plat->fmrt->flags = 0; - - plat->fmrt->tmrs[i] = 0.0f; - plat->fmrt->ttms[i] = 0.0f; - plat->fmrt->atms[i] = 0.0f; - plat->fmrt->dtms[i] = 0.0f; - plat->fmrt->vms[i] = 0.0f; - plat->fmrt->dss[i] = 0.0f; + if (plat->subType == ePlatformTypeBreakaway && plat->state == 0) { + if ((plat->passet->ba.breakflags & 0x1) && zEntPlayer_IsSneaking()) { + plat->state = 1; + } else { + plat->state = 2; + if (plat->passet->ba.ba_delay) { + zPlatform_Tremble(plat, 0.06f, 8*PI, 1.0f + plat->passet->ba.ba_delay); + } } } - - if (plat->motion.type == 0x3) - { - plat->src = plat->motion.mp.src; - } - - plat->chkby &= 0xE3; - - if (plat->passet->flags & 0x4) - { - plat->chkby |= 0x18; - } - - plat->bupdate(plat, (xVec3*)&plat->model->Mat->pos); - - plat->moving = FALSE; - - if (plat->asset->modelInfoID == xStrHash("teeter_totter_pat") || - plat->asset->modelInfoID == xStrHash("teeter_totter_pat_bind")) - { - plat->plat_flags |= 0x2; - } - - plat->pauseMult = 1.0f; - plat->pauseDelta = 0.0f; -} - -U32 zMechIsStartingForth(zPlatform* ent, U16 param_2) -{ - if (ent->motion.asset->mech.type == 4) - { - return param_2 == 1; - } - else - { - return param_2 == 0; - } } -U32 zMechIsStartingBack(zPlatform* ent, U16 param_2) +void zPlatform_Dismount(zPlatform* ent) { - if (ent->motion.asset->mech.type == 4) - { - return param_2 == 4; - } - else + if ((ent->subType == ePlatformTypeBreakaway) && (ent->state == 1)) { - return param_2 == 3; + ent->state = 0; } } -static F32 SolvePaddleMotion(zPlatform* plat, F32* time, F32 tmr) +static void zPlatformTranslate(xEnt* xent, xVec3* dpos, xMat4x3* dmat) { - return 0.0f; -} - -void zPlatform_PaddleStartRotate(xEnt* entplat, S32 direction, S32 stutter) -{ - zPlatform* plat = (zPlatform*)entplat; - F32 time[3]; - - if (stutter != 0) - { - if (direction > 0) - { - plat->state = ZPLATFORM_STATE_UNK4; - } - else if (direction < 0) - { - plat->state = ZPLATFORM_STATE_UNK1; - } - } - else - { - if (direction > 0) - { - plat->state = ZPLATFORM_STATE_UNK3; - plat->ctr += 1; - - if (plat->ctr >= plat->passet->paddle.countOrient) - { - plat->ctr = 0; - } - } - else if (direction < 0) - { - plat->state = ZPLATFORM_STATE_UNK2; - plat->ctr -= 1; - - if (plat->ctr < 0) - { - plat->ctr = plat->passet->paddle.countOrient - 1; - } - } - } - - SolvePaddleMotion(plat, time, -1.0f); - plat->tmr = time[0] + time[1] + time[2]; + zPlatform* plat = (zPlatform*)xent; + xEntDefaultTranslate(xent, dpos, dmat); + xEntMotionTranslate(&plat->motion, dpos, dmat); } static void zPlatFM_EventSetup(zPlatform* plat, const F32* toParam, S32 idx) @@ -562,7 +1183,328 @@ static void zPlatFM_EventSetup(zPlatform* plat, const F32* toParam, S32 idx) fmrt->flags |= (1 << idx); } -S32 zPlatformEventCB(xBase* from, xBase* to, U32 toEvent, const F32* toParam, xBase* base3) +S32 zPlatformEventCB(xBase* from, xBase* to, U32 toEvent, const F32* toParam, xBase* toParamWidget) { + zPlatform* plat = (zPlatform*)to; + + switch (toEvent) { + case eEventOn: + if (!(plat->plat_flags & 0x1)) { + plat->plat_flags |= 0x1; + } + break; + case eEventOff: + if (plat->plat_flags & 0x1) { + plat->plat_flags &= ~0x1; + } + break; + case eEventToggle: + if (plat->plat_flags & 0x1) { + plat->plat_flags &= ~0x1; + } else { + plat->plat_flags |= 0x1; + } + break; + case eEventRun: + if (plat->subType == ePlatformTypeBreakaway) { + if (plat->state == 0 || plat->state == 1) { + plat->state = 2; + if (plat->passet->ba.ba_delay) { + zPlatform_Tremble(plat, 0.06f, 8*PI, 1.0f + plat->passet->ba.ba_delay); + } + } + } else if (plat->subType == ePlatformTypeFM) { + plat->plat_flags &= (U16)~0x4; + } else if (plat->subType == ePlatformTypePaddle) { + S32 iParam0 = (S32)toParam[0]; + if (iParam0) { + if (plat->state == 0 && + ((plat->passet->paddle.paddleFlags & 0x4) || + !((iParam0 < 0) ? (plat->ctr == 0) : (plat->ctr + 1 == plat->passet->paddle.countOrient)))) { + zPlatform_PaddleStartRotate(plat, iParam0, (S32)toParam[1]); + } + } else { + S32 destctr = (S32)toParam[1]; + if (destctr >= 0 && destctr < plat->passet->paddle.countOrient) { + plat->tmr = 1e-9f; + plat->state = 2; + plat->ctr = destctr; + } + } + } else { + if (plat->subType == ePlatformTypeMech && + globals.sceneCur->sceneID == 'PG12' && + (plat->asset->modelInfoID == xStrHash("skatepark_bumper") || + plat->asset->modelInfoID == xStrHash("skatepark_flipper"))) { + if (plat->asset->modelInfoID != xStrHash("skatepark_flipper")) { + xScrFXGlareAdd((xVec3*)&plat->model->Mat->pos, + 0.5f * xurand() + 0.5f, + 0.5f * xurand() + 0.5f, + 4.0f * xurand() + 3.0f, + 1.0f, 0.7f, 0.5f, 1.0f, + NULL); + xScrFXGlareAdd((xVec3*)&plat->model->Mat->pos, + 0.5f * xurand(), + 0.8f * xurand(), + 3.0f + xurand(), + xurand(), xurand(), xurand(), 1.0f, + NULL); + } + xSndPlay3D(xStrHash("Check1"), 0.77f, 0.0f, 128, 0, + (xVec3*)&plat->model->Mat->pos, 0.0f, + SND_CAT_GAME, 0.0f); + zRumbleStartDistance(globals.currentActivePad, + 10.0f * xurand(), 48.0f, + eRumble_Medium, 0.35f); + } + if (plat->subType == ePlatformTypeMech && + (plat->motion.mech.state == 6 || plat->motion.mech.state == 7)) { + xEntMotionReset(&plat->motion, globals.sceneCur); + } + xEntMotionRun(&plat->motion); + } + break; + case eEventStop: + if (plat->subType == ePlatformTypeFM) { + plat->plat_flags |= 0x4; + } else { + xEntMotionStop(&plat->motion); + } + break; + case eEventTranslLocalX: + if (plat->subType == ePlatformTypeFM) { + zPlatFM_EventSetup(plat, toParam, 0); + } + break; + case eEventTranslLocalY: + if (plat->subType == ePlatformTypeFM) { + zPlatFM_EventSetup(plat, toParam, 1); + } + break; + case eEventTranslLocalZ: + if (plat->subType == ePlatformTypeFM) { + zPlatFM_EventSetup(plat, toParam, 2); + } + break; + case eEventTranslWorldX: + if (plat->subType == ePlatformTypeFM) { + zPlatFM_EventSetup(plat, toParam, 3); + } + break; + case eEventTranslWorldY: + if (plat->subType == ePlatformTypeFM) { + zPlatFM_EventSetup(plat, toParam, 4); + } + break; + case eEventTranslWorldZ: + if (plat->subType == ePlatformTypeFM) { + zPlatFM_EventSetup(plat, toParam, 5); + } + break; + case eEventRotLocalX: + if (plat->subType == ePlatformTypeFM) { + F32 tp[4]; + tp[0] = DEG2RAD(toParam[0]); + tp[1] = toParam[1]; + tp[2] = toParam[2]; + tp[3] = toParam[3]; + zPlatFM_EventSetup(plat, tp, 6); + } + break; + case eEventRotLocalY: + if (plat->subType == ePlatformTypeFM) { + F32 tp[4]; + tp[0] = DEG2RAD(toParam[0]); + tp[1] = toParam[1]; + tp[2] = toParam[2]; + tp[3] = toParam[3]; + zPlatFM_EventSetup(plat, tp, 7); + } + break; + case eEventRotLocalZ: + if (plat->subType == ePlatformTypeFM) { + F32 tp[4]; + tp[0] = DEG2RAD(toParam[0]); + tp[1] = toParam[1]; + tp[2] = toParam[2]; + tp[3] = toParam[3]; + zPlatFM_EventSetup(plat, tp, 8); + } + break; + case eEventRotWorldX: + if (plat->subType == ePlatformTypeFM) { + F32 tp[4]; + tp[0] = DEG2RAD(toParam[0]); + tp[1] = toParam[1]; + tp[2] = toParam[2]; + tp[3] = toParam[3]; + zPlatFM_EventSetup(plat, tp, 9); + } + break; + case eEventRotWorldY: + if (plat->subType == ePlatformTypeFM) { + F32 tp[4]; + tp[0] = DEG2RAD(toParam[0]); + tp[1] = toParam[1]; + tp[2] = toParam[2]; + tp[3] = toParam[3]; + zPlatFM_EventSetup(plat, tp, 10); + } + break; + case eEventRotWorldZ: + if (plat->subType == ePlatformTypeFM) { + F32 tp[4]; + tp[0] = DEG2RAD(toParam[0]); + tp[1] = toParam[1]; + tp[2] = toParam[2]; + tp[3] = toParam[3]; + zPlatFM_EventSetup(plat, tp, 11); + } + break; + case eEventForward: + if (plat->subType == ePlatformTypeMech) { + xEntMechForward(&plat->motion); + } + break; + case eEventReverse: + if (plat->subType == ePlatformTypeMech) { + xEntMechReverse(&plat->motion); + } + break; + case eEventReset: + zPlatform_Reset(plat, globals.sceneCur); + break; + case eEventVisible: + case eEventFastVisible: + xEntShow(plat); + if (toParam && (S32)(0.5f + toParam[0]) == 77) { + zFXPopOn(*plat, toParam[1], toParam[2]); + } + break; + case eEventInvisible: + case eEventFastInvisible: + xEntHide(plat); + if (toParam && (S32)(0.5f + toParam[0]) == 77) { + zFXPopOff(*plat, toParam[1], toParam[2]); + } + break; + case eEventCollision_Visible_On: + xEntShow(plat); + if (toParam && (S32)(0.5f + toParam[0]) == 77) { + zFXPopOn(*plat, toParam[1], toParam[2]); + } + // fallthrough + case eEventCollisionOn: + plat->chkby = (XENT_COLLTYPE_TRIG | XENT_COLLTYPE_STAT); + plat->bupdate(plat, (xVec3*)&plat->model->Mat->pos); + break; + case eEventCollision_Visible_Off: + xEntHide(plat); + if (toParam && (S32)(0.5f + toParam[0]) == 77) { + zFXPopOff(*plat, toParam[1], toParam[2]); + } + // fallthrough + case eEventCollisionOff: + plat->chkby = XENT_COLLTYPE_NONE; + break; + case eEventCameraCollideOn: + zCollGeom_CamEnable(plat); + break; + case eEventCameraCollideOff: + zCollGeom_CamDisable(plat); + break; + case eEventAnimPlay: + case eEventAnimPlayLoop: + case eEventAnimStop: + case eEventAnimPause: + case eEventAnimResume: + case eEventAnimTogglePause: + case eEventAnimPlayRandom: + case eEventAnimPlayMaybe: + zEntAnimEvent(plat, toEvent, toParam); + break; + case eEventSetSpeed: + if (plat->subType == ePlatformTypeMP) { + xEntMPSetSpeed(&plat->motion, toParam[0]); + } + break; + case eEventAccelerate: + if (plat->subType == ePlatformTypeMP) { + xEntMPAccelerate(&plat->motion, toParam[0]); + } + break; + case eEventSetSkyDome: + xSkyDome_AddEntity(plat, (S32)toParam[0], (S32)toParam[1]); + break; + case eEventSetGoo: + zGooAdd(plat, toParam[0], (S32)toParam[1]); + break; + case eEventGooSetWarb: + zFXGooEventSetWarb(plat, toParam); + break; + case eEventGooSetFreezeDuration: + zFXGooEventSetFreezeDuration(plat, toParam[0]); + break; + case eEventGooMelt: + zFXGooEventMelt(plat); + break; + case eEventMount: + if (toParamWidget) { + F32 mt = 0.00001f; + if (toParam[0]) mt = toParam[0]; + xEntDriveMount(&plat->drv, (xEnt*)toParamWidget, mt, NULL); + } + break; + case eEventDismount: + if (toParamWidget) { + F32 mt = 0.00001f; + if (toParam[0]) mt = toParam[0]; + xEntDriveDismount(&plat->drv, mt); + } + break; + case eEventSetUpdateDistance: + if (globals.updateMgr) { + if (toParam[0] <= 0.0f) { + xUpdateCull_SetCB(globals.updateMgr, plat, xUpdateCull_AlwaysTrueCB, NULL); + } else { + FloatAndVoid dist; + dist.f = SQR(toParam[0]); + xUpdateCull_SetCB(globals.updateMgr, plat, xUpdateCull_DistanceSquaredCB, dist.v); + } + } + break; + case eEventLaunchShrapnel: + { + zShrapnelAsset* shrap = (zShrapnelAsset*)toParamWidget; + if (shrap && shrap->initCB) { + xVec3 currVel; + xVec3Sub(&currVel, &plat->frame->mat.pos, &plat->frame->oldmat.pos); + xVec3SMulBy(&currVel, 1.0f / globals.update_dt); + shrap->initCB(shrap, plat->model, &currVel, NULL); + } + break; + } + case eEventPlatPause: + if (plat->subType != ePlatformTypeBreakaway) { + if (toParam[0] == 0.0f) { + plat->pauseMult = 0.000001f; + plat->pauseDelta = 0.0f; + } else { + plat->pauseDelta = -1.0f / toParam[0]; + } + } + break; + case eEventPlatUnpause: + if (plat->subType != ePlatformTypeBreakaway) { + if (toParam[0] == 0.0f) { + plat->pauseMult = 1.0f; + plat->pauseDelta = 0.0f; + } else { + plat->pauseDelta = 1.0f / toParam[0]; + } + } + break; + } + return 1; } diff --git a/src/SB/Game/zPlatform.h b/src/SB/Game/zPlatform.h index 3be6b6f2e..1c1fcb926 100644 --- a/src/SB/Game/zPlatform.h +++ b/src/SB/Game/zPlatform.h @@ -5,6 +5,24 @@ #include "xEntMotion.h" #include "xEntDrive.h" +enum en_ZPLATFORMTYPE +{ + ePlatformTypeER, + ePlatformTypeOrbit, + ePlatformTypeSpline, + ePlatformTypeMP, + ePlatformTypeMech, + ePlatformTypePen, + ePlatformTypeConvBelt, + ePlatformTypeFalling, + ePlatformTypeFR, + ePlatformTypeBreakaway, + ePlatformTypeSpringboard, + ePlatformTypeTeeter, + ePlatformTypePaddle, + ePlatformTypeFM +}; + struct xPlatformERData { S32 nodata; diff --git a/src/SB/Game/zSurface.cpp b/src/SB/Game/zSurface.cpp index 1c6ccbf40..10f29cf2b 100644 --- a/src/SB/Game/zSurface.cpp +++ b/src/SB/Game/zSurface.cpp @@ -3,41 +3,128 @@ #include "xstransvc.h" #include "xCollide.h" #include "xMathInlines.h" +#include "xGroup.h" +#include "xDebug.h" #include #include #include "xMath.h" -extern volatile S32 sMapperCount; -extern zMaterialMapAsset* sMapper[1]; +#define MAX_MAPPER 1 -extern xSurface sDef_surf; +static zSurfaceProps* zsps; +static S32 sMapperCount; +static zMaterialMapAsset* sMapper[MAX_MAPPER] = {}; +static xSurface sDef_surf; +static zSurfaceProps sDef_surf_props; +static zSurfAssetBase sDef_surf_asset; -extern F32 lbl_803CDEE8; // 0.34906587 // @798 -extern F32 lbl_803CDEE0; // 3.1415927 // pi // @796 -extern F32 lbl_803CDEF0; // 176.0 // @801 -extern F32 lbl_803CDEE4; // 180.0 // @797 +static void zSurfaceInitDefaultSurface(); +static S32 zSurfaceEventCB(xBase* from, xBase* to, U32 toEvent, const F32* toParam, + xBase* toParamWidget); -extern F32 lbl_803CDEDC; // -1.0 // @702 +void zSurfaceInit() +{ + U32 size; + U16 nsurfs; -extern F32 lbl_803CDED8; // 1.0 // @701 + nsurfs = xSTAssetCountByType('SURF'); -extern const char* zSurface_strings[]; + xSurfaceInit(nsurfs); -// TODO: Hacked to OK (with volatile sMapperCount and assignment in if), fix later -void zSurfaceRegisterMapper(U32 assetId) -{ - if (sMapperCount >= 1) + if (nsurfs) { - return; + zsps = (zSurfaceProps*)xMemAllocSize(nsurfs * sizeof(zSurfaceProps)); + + for (U16 i = 0; i < nsurfs; i++) + { + zSurfAssetBase* asset; + xSurface* surf; + zSurfaceProps* moprops; + + surf = xSurfaceGetByIdx(i); + moprops = &zsps[i]; + surf->moprops = moprops; + + asset = (zSurfAssetBase*)xSTFindAssetByType('SURF', i, &size); + moprops->asset = asset; + + xBaseInit(surf, asset); + + if (surf->linkCount) + { + surf->link = (xLinkAsset*)(asset + 1); + } + else + { + surf->link = NULL; + } + + surf->eventFunc = zSurfaceEventCB; + surf->friction = asset->friction; + surf->state = asset->on ? 0 : 1; + moprops->uvfx_flags = asset->uvfx_flags; + moprops->texanim_flags = asset->texture_anim_flags; + + for (S32 j = 0; j < 2; j++) + { + moprops->texanim[j].mode = asset->texture_anim[j].mode; + moprops->texanim[j].speed = asset->texture_anim[j].speed; + moprops->texanim[j].group = asset->texture_anim[j].group; + moprops->texanim[j].group_idx = 0; + moprops->uvfx[j].mode = asset->uvfx[j].mode; + if (moprops->uvfx[j].rot <= 360.0f) + moprops->uvfx[j].rot = 360.0f; + if (moprops->uvfx[j].rot >= 0.0f) + moprops->uvfx[j].rot = 0.0f; + moprops->uvfx[j].rot = asset->uvfx[j].rot; + moprops->uvfx[j].rot_spd = asset->uvfx[j].rot_spd; + moprops->uvfx[j].trans = asset->uvfx[j].trans; + moprops->uvfx[j].trans_spd = asset->uvfx[j].trans_spd; + moprops->uvfx[j].scale = asset->uvfx[j].scale; + moprops->uvfx[j].scale_spd = asset->uvfx[j].scale_spd; + moprops->uvfx[j].min = asset->uvfx[j].min; + moprops->uvfx[j].max = asset->uvfx[j].max; + moprops->uvfx[j].minmax_spd = asset->uvfx[j].minmax_spd; + moprops->uvfx[j].minmax_timer[0] = 0.0f; + moprops->uvfx[j].minmax_timer[1] = 0.0f; + } + } } - if (!assetId) + else { - return; + zsps = NULL; } - if (sMapper[sMapperCount] = (zMaterialMapAsset*)xSTFindAsset(assetId, 0)) - { + + zSurfaceInitDefaultSurface(); +} + +static void zSurfaceInitDefaultSurface() +{ + sDef_surf.friction = 1.0f; + sDef_surf.state = 0; + sDef_surf.moprops = &sDef_surf_props; + sDef_surf_props.asset = &sDef_surf_asset; + + + sDef_surf_asset.game_damage_type = 0; + sDef_surf_asset.game_sticky = 0; + sDef_surf_asset.game_damage_flags = 0; + sDef_surf_asset.sld_start = 20; + sDef_surf_asset.sld_stop = 10; + sDef_surf_asset.phys_flags = 0; + sDef_surf_asset.friction = 1.0f; + sDef_surf_asset.oob_delay = -1.0f; +} + +void zSurfaceRegisterMapper(U32 assetId) +{ + if (sMapperCount >= MAX_MAPPER) return; + if (!assetId) return; + + sMapper[sMapperCount] = (zMaterialMapAsset*)xSTFindAsset(assetId, NULL); + if (sMapper[sMapperCount]) { sMapperCount++; } } @@ -54,11 +141,39 @@ void zSurfaceResetSurface(xSurface* surf) surf->friction = ((zSurfaceProps*)(surf->moprops))->asset->friction; } +xSurface* zSurfaceGetSurface(U32 mat_id) +{ + for (S32 map = 0; map < sMapperCount; map++) + { + zMaterialMapAsset* mapper = sMapper[map]; + if (mapper) + { + for (U16 i = 0; i < mapper->count; i++) + { + zMaterialMapEntry* entry = (zMaterialMapEntry*)(mapper + 1) + i; + if (entry->materialIndex == (mat_id & 0xFFFF)) + { + U16 nsurfs = xSurfaceGetNumSurfaces(); + for (U16 j = 0; j < nsurfs; j++) + { + xSurface* surf = xSurfaceGetByIdx(j); + if (surf->id == entry->surfaceAssetID) + { + return surf; + } + } + } + } + } + } + return &sDef_surf; +} + xSurface* zSurfaceGetSurface(const xCollis* coll) { xSurface* surf = NULL; - if (coll->flags & 1) + if (coll->flags & k_HIT_IT) { if (coll->optr) { @@ -105,12 +220,22 @@ U8 zSurfaceOutOfBounds(const xSurface& s) } F32 zSurfaceGetSlideStartAngle(const xSurface* surf) +{ + if (surf->moprops) { + return DEG2RAD(((zSurfaceProps*)surf->moprops)->asset->sld_start); + } + + return DEG2RAD(20); +} + +F32 zSurfaceGetSlideStopAngle(const xSurface* surf) { if (surf->moprops) { - return ((((zSurfaceProps*)surf->moprops)->asset->sld_start) * PI) / 176.0f; + return DEG2RAD(((zSurfaceProps*)surf->moprops)->asset->sld_stop); } - return PI / 9; + + return DEG2RAD(10); } U32 zSurfaceGetMatchOrient(const xSurface* surf) @@ -163,18 +288,19 @@ F32 zSurfaceGetFriction(const xSurface* surf) return surf->friction; } -F32 zSurfaceGetOutOfBoundsDelay(xSurface& s) +F32 zSurfaceGetOutOfBoundsDelay(const xSurface& s) { if (s.moprops) { return ((zSurfaceProps*)s.moprops)->asset->oob_delay; } - return lbl_803CDEDC; + + return -1.0f; } S32 zSurfaceGetSlickness(const xSurface* surf) { - return (int)(lbl_803CDED8 / surf->friction); + return (S32)(1.0f / surf->friction); } F32 zSurfaceGetDamping(const xSurface* surf, F32 min_vel) @@ -195,21 +321,333 @@ void zSurfaceLoad(xSurface* ent, xSerial* s) void zSurfaceSetup(xSurface* s) { zSurfaceProps* pp = (zSurfaceProps*)s->moprops; + if (!pp) return; - if (!pp) + for (S32 i = 0; i < 2; i++) { + pp->texanim[i].group_ptr = NULL; + if (pp->texanim[i].group) { + pp->texanim[i].group_ptr = zSceneFindObject(pp->texanim[i].group); + } + } +} + +void zSurfaceUpdate(xBase* to, xScene* sc, F32 dt) +{ + F32 timestep_forUV = dt; + S32 j; + xSurface* t = (xSurface*)to; + zSurfaceProps* moprops = (zSurfaceProps*)t->moprops; + + for (j = 0; j < 2; j++) { - return; + if ((j == 0 && (moprops->uvfx_flags & UVANIM_FLAG_ON)) || + (j == 1 && (moprops->uvfx_flags & UVANIM_FLAG_ON2))) + { + switch (moprops->uvfx[j].mode) + { + case 0: + { + xVec3 d; + + moprops->uvfx[j].rot += moprops->uvfx[j].rot_spd * dt; + while (moprops->uvfx[j].rot >= 360.0f) + moprops->uvfx[j].rot -= 360.0f; + while (moprops->uvfx[j].rot < 0.0f) + moprops->uvfx[j].rot += 360.0f; + + xVec3SMul(&d, &moprops->uvfx[j].trans_spd, timestep_forUV); + xVec3Add(&moprops->uvfx[j].trans, &d, &moprops->uvfx[j].trans); + while (moprops->uvfx[j].trans.x >= 1.0f) + moprops->uvfx[j].trans.x -= 1.0f; + while (moprops->uvfx[j].trans.x < 0.0f) + moprops->uvfx[j].trans.x += 1.0f; + while (moprops->uvfx[j].trans.y >= 1.0f) + moprops->uvfx[j].trans.y -= 1.0f; + while (moprops->uvfx[j].trans.y < 0.0f) + moprops->uvfx[j].trans.y += 1.0f; + + xVec3SMul(&d, &moprops->uvfx[j].scale_spd, dt); + xVec3Add(&moprops->uvfx[j].scale, &d, &moprops->uvfx[j].scale); + while (moprops->uvfx[j].scale.x >= 8.0f) + moprops->uvfx[j].scale.x -= 8.0f; + while (moprops->uvfx[j].scale.x < 0.0f) + moprops->uvfx[j].scale.x += 8.0f; + while (moprops->uvfx[j].scale.y >= 8.0f) + moprops->uvfx[j].scale.y -= 8.0f; + while (moprops->uvfx[j].scale.y < 0.0f) + moprops->uvfx[j].scale.y += 8.0f; + + break; + } + case 1: + { + moprops->uvfx[j].trans.x = isin(2.0f * gFrameCount * (1.0f/60)); + moprops->uvfx[j].trans.y = isin(2.0f * gFrameCount * (1.0f/60)); + moprops->uvfx[j].scale.x = isin(2.0f * gFrameCount * (1.0f/60)); + moprops->uvfx[j].scale.y = isin(2.0f * gFrameCount * (1.0f/60)); + break; + } + case 2: + { + zSurfacePropUVFX& sfx = moprops->uvfx[j]; + + if (sfx.minmax_spd.x != 0.0f) + { + sfx.minmax_timer[0] += dt; + + F32 uTime = sfx.minmax_timer[0] * sfx.minmax_spd.x; + S32 uTimeInt = (S32)uTime; + if (uTimeInt > 1) + { + sfx.minmax_timer[0] -= 2.0f / sfx.minmax_spd.x; + } + uTime -= uTimeInt & ~1; + + sfx.trans.x = sfx.min.x + (sfx.max.x - sfx.min.x) * isin(HALF_PI * uTime); + } + else + { + sfx.trans.x = sfx.min.x; + } + + if (sfx.minmax_spd.y != 0.0f) + { + sfx.minmax_timer[1] += dt; + + F32 vTime = sfx.minmax_timer[1] * sfx.minmax_spd.y; + S32 vTimeInt = (S32)vTime; + if (vTimeInt > 1) + { + sfx.minmax_timer[1] -= 2.0f / sfx.minmax_spd.y; + } + vTime -= vTimeInt & ~1; + + sfx.trans.y = sfx.min.y + (sfx.max.y - sfx.min.y) * isin(HALF_PI * vTime); + } + else + { + sfx.trans.y = sfx.min.y; + } + + sfx.scale.x = 1.0f; + sfx.scale.y = 1.0f; + break; + } + } + } } - for (int i = 0; i < 2; i++) + for (j = 0; j < 2; j++) { - pp->texanim[i].group_ptr = 0; + if ((j == 0 && (moprops->texanim_flags & SURF_TEXANIM_ON)) || + (j == 1 && (moprops->texanim_flags & SURF_TEXANIM_ON2))) + { + xGroup* g = (xGroup*)moprops->texanim[j].group_ptr; + if (g) + { + S32 max = xGroupGetCount(g); + if (max > 0) + { + if (moprops->texanim[j].mode == 0) + { + moprops->texanim[j].frame += moprops->texanim[j].speed * dt; + if (moprops->texanim[j].frame >= 1.0f) + { + moprops->texanim[j].group_idx += (S32)moprops->texanim[j].frame; + moprops->texanim[j].frame -= (S32)moprops->texanim[j].frame; + } + } + else if (moprops->texanim[j].mode == 1) + { + moprops->texanim[j].frame += moprops->texanim[j].speed * dt; + if (moprops->texanim[j].frame >= 1.0f) + { + moprops->texanim[j].group_idx -= (S32)moprops->texanim[j].frame; + moprops->texanim[j].frame -= (S32)moprops->texanim[j].frame; + } + } + else if (moprops->texanim[j].mode == 2) + { + moprops->texanim[j].frame += moprops->texanim[j].speed * dt; + if (moprops->texanim[j].frame >= 1.0f) + { + moprops->texanim[j].group_idx = xrand() % max; + moprops->texanim[j].frame -= (S32)moprops->texanim[j].frame; + } + } + while (moprops->texanim[j].group_idx >= max) + moprops->texanim[j].group_idx -= max; + while (moprops->texanim[j].group_idx < 0) + moprops->texanim[j].group_idx += max; + } + } + } + } +} - if (pp->texanim[i].group != 0) +static S32 zSurfaceEventCB(xBase* from, xBase* to, U32 toEvent, const F32* toParam, + xBase* toParamWidget) +{ + xSurface* t = (xSurface*)to; + + switch (toEvent) + { + case eEventOn: + t->state = 0; + break; + case eEventOff: + t->state = 1; + break; + case eEventToggle: + if (t->state == 0) { - pp->texanim[i].group_ptr = zSceneFindObject(pp->texanim[i].group); + t->state = 1; + } + else + { + t->state = 0; + } + break; + case eEventReset: + zSurfaceResetSurface(t); + t->state = 0; + break; + case eEventTextureAnimateOn: + { + zSurfaceProps* p = (zSurfaceProps*)t->moprops; + if (p) + { + if (toParam[3] == 0.0f) + { + p->texanim_flags |= SURF_TEXANIM_ON; + } + else + { + p->texanim_flags |= SURF_TEXANIM_ON2; + } } + break; } + case eEventTextureAnimateStep: + { + zSurfaceProps* p = (zSurfaceProps*)t->moprops; + if (p && (p->texanim_flags & SURF_TEXANIM_ON)) + { + if (toParam[3] == 0.0f) + { + p->texanim[0].frame += toParam[0]; + } + else + { + p->texanim[1].frame += toParam[0]; + } + } + break; + } + case eEventTextureAnimateOff: + { + zSurfaceProps* p = (zSurfaceProps*)t->moprops; + if (p) + { + if (toParam[3] == 0.0f) + { + if (p->texanim_flags & SURF_TEXANIM_ON) + { + p->texanim_flags ^= SURF_TEXANIM_ON; + } + } + else + { + if (p->texanim_flags & SURF_TEXANIM_ON2) + { + p->texanim_flags ^= SURF_TEXANIM_ON2; + } + } + } + break; + } + case eEventTextureAnimateToggle: + { + zSurfaceProps* p = (zSurfaceProps*)t->moprops; + if (p) + { + if (toParam[3] == 0.0f) + { + if (p->texanim_flags & SURF_TEXANIM_ON) + { + if (p->texanim_flags & SURF_TEXANIM_ON) + { + p->texanim_flags ^= SURF_TEXANIM_ON; + } + } + else + { + p->texanim_flags |= SURF_TEXANIM_ON; + } + } + else + { + if (p->texanim_flags & SURF_TEXANIM_ON2) + { + if (p->texanim_flags & SURF_TEXANIM_ON2) + { + p->texanim_flags ^= SURF_TEXANIM_ON2; + } + } + else + { + p->texanim_flags |= SURF_TEXANIM_ON2; + } + } + } + break; + } + case eEventSetTextureAnimGroup: + { + zSurfaceProps* p = (zSurfaceProps*)t->moprops; + if (p) + { + if (toParamWidget) + { + S32 idx = (toParam[3] == 0.0f) ? 0 : 1; + p->texanim[idx].group = toParamWidget->id; + p->texanim[idx].group_ptr = toParamWidget; + } + else + { + if (toParam[3] == 0.0f) + { + p->texanim[0].group = 0; + p->texanim[0].group_ptr = NULL; + } + else + { + p->texanim[1].group = 0; + p->texanim[1].group_ptr = NULL; + } + } + } + break; + } + case eEventSetTextureAnimSpeed: + { + zSurfaceProps* p = (zSurfaceProps*)t->moprops; + if (p) + { + if (toParam[3] == 0.0f) + { + p->texanim[0].speed = toParam[0]; + } + else + { + p->texanim[1].speed = toParam[0]; + } + } + break; + } + } + + return 1; } void zSurfaceGetName(S32 type, char* buffer) diff --git a/src/SB/Game/zSurface.h b/src/SB/Game/zSurface.h index 68b118520..516fb7299 100644 --- a/src/SB/Game/zSurface.h +++ b/src/SB/Game/zSurface.h @@ -6,6 +6,13 @@ #include "xMath3.h" #include "xSurface.h" + +#define SURF_TEXANIM_ON (1<<0) +#define SURF_TEXANIM_ON2 (1<<1) + +#define UVANIM_FLAG_ON (1<<0) +#define UVANIM_FLAG_ON2 (1<<1) + struct zSurfMatFX { U32 flags;