diff --git a/Runtime/Graphics/CGraphics.cpp b/Runtime/Graphics/CGraphics.cpp index 92279b5ff..579701410 100644 --- a/Runtime/Graphics/CGraphics.cpp +++ b/Runtime/Graphics/CGraphics.cpp @@ -507,8 +507,8 @@ float CGraphics::GetSecondsMod900() void CGraphics::TickRenderTimings() { - g_RenderTimings++; - g_DefaultSeconds = float(g_RenderTimings) / 60.f; + g_RenderTimings = (g_RenderTimings + 1) % u32(900*60); + g_DefaultSeconds = g_RenderTimings / 60.f; } boo::IGraphicsDataFactory::Platform CGraphics::g_BooPlatform = boo::IGraphicsDataFactory::Platform::Null; diff --git a/Runtime/World/CGameArea.cpp b/Runtime/World/CGameArea.cpp index 4062f73a6..1e7e6ef69 100644 --- a/Runtime/World/CGameArea.cpp +++ b/Runtime/World/CGameArea.cpp @@ -416,7 +416,11 @@ const zeus::CTransform& CDummyGameArea::IGetTM() const CGameArea::CGameArea(CInputStream& in, int idx, int mlvlVersion) : x4_selfIdx(idx) { + xf0_24_postConstructed = false; xf0_25_active = true; + xf0_26_tokensReady = false; + xf0_27_paused = false; + xf0_28_validated = false; x8_nameSTRG = in.readUint32Big(); xc_transform.read34RowMajor(in); x3c_invTransform = xc_transform.inverse(); @@ -463,6 +467,12 @@ CGameArea::CGameArea(CInputStream& in, int idx, int mlvlVersion) CGameArea::CGameArea(CAssetId mreaId) : x84_mrea(mreaId) { + xf0_24_postConstructed = false; + xf0_25_active = false; + xf0_26_tokensReady = false; + xf0_27_paused = false; + xf0_28_validated = false; + while (StartStreamingMainArea()) for (auto& req : xf8_loadTransactions) req->WaitUntilComplete(); @@ -905,7 +915,7 @@ void CGameArea::AllocNewAreaData(int offset, int size) bool CGameArea::Invalidate(CStateManager* mgr) { - if (xf0_24_postConstructed) + if (!xf0_24_postConstructed) { ClearTokenList(); diff --git a/Runtime/World/CGameArea.hpp b/Runtime/World/CGameArea.hpp index ac94310c3..79b5f72e4 100644 --- a/Runtime/World/CGameArea.hpp +++ b/Runtime/World/CGameArea.hpp @@ -117,18 +117,11 @@ class CGameArea : public IGameArea u32 xec_totalResourcesSize = 0; - union - { - struct - { - bool xf0_24_postConstructed : 1; - bool xf0_25_active : 1; - bool xf0_26_tokensReady : 1; - bool xf0_27_paused : 1; - bool xf0_28_validated : 1; - }; - u32 _dummy = 0; - }; + bool xf0_24_postConstructed : 1; + bool xf0_25_active : 1; + bool xf0_26_tokensReady : 1; + bool xf0_27_paused : 1; + bool xf0_28_validated : 1; enum class EPhase { @@ -361,7 +354,7 @@ public: s32 GetDockCount() const { return xcc_docks.size(); } Dock* DockNC(s32 dock) { return &xcc_docks[dock]; } - bool IsPostConstructed() const { return xf0_24_postConstructed && x12c_postConstructed; } + bool IsPostConstructed() const { return xf0_24_postConstructed; } const CPostConstructed* GetPostConstructed() const { if (!x12c_postConstructed) diff --git a/Runtime/World/CMakeLists.txt b/Runtime/World/CMakeLists.txt index 7edd6617a..8c4d75954 100644 --- a/Runtime/World/CMakeLists.txt +++ b/Runtime/World/CMakeLists.txt @@ -37,6 +37,8 @@ set(WORLD_SOURCES CScriptCounter.hpp CScriptCounter.cpp CScriptEffect.hpp CScriptEffect.cpp CScriptSteam.hpp CScriptSteam.cpp + CScriptRipple.hpp CScriptRipple.cpp + CScriptBallTrigger.hpp CScriptBallTrigger.cpp CScriptPlatform.hpp CScriptPlatform.cpp CScriptSound.hpp CScriptSound.cpp CScriptGenerator.hpp CScriptGenerator.cpp diff --git a/Runtime/World/CScriptBallTrigger.cpp b/Runtime/World/CScriptBallTrigger.cpp new file mode 100644 index 000000000..0ad49e00d --- /dev/null +++ b/Runtime/World/CScriptBallTrigger.cpp @@ -0,0 +1,107 @@ +#include "CScriptBallTrigger.hpp" +#include "CStateManager.hpp" +#include "CPlayer.hpp" +#include "CMorphBall.hpp" +#include "GameGlobalObjects.hpp" +#include "DNAMP1/Tweaks/CTweakPlayer.hpp" +#include "TCastTo.hpp" + +namespace urde +{ + +static zeus::CAABox calculate_ball_aabox() +{ + float extent = 0.33f * g_tweakPlayer->GetPlayerBallHalfExtent(); + return {-extent, extent}; +} + +CScriptBallTrigger::CScriptBallTrigger(TUniqueId uid, std::string_view name, const CEntityInfo& info, + const zeus::CVector3f& pos, const zeus::CVector3f& scale, + bool active, float f1, float f2, float f3, const zeus::CVector3f& vec, bool b2) + : CScriptTrigger(uid, name, info, pos, calculate_ball_aabox(), CDamageInfo(CWeaponMode::Power(), 0.f, 0.f, 0.f), zeus::CVector3f::skZero, ETriggerFlags::DetectMorphedPlayer, active, false, false) + , x150_force(f1) + , x154_minAngle(f2) + , x158_maxDistance(f3) + , x168_24_canApplyForce(false) + , x168_25_stopPlayer(b2) +{ + + if (vec.canBeNormalized()) + x15c_forceAngle = vec.normalized(); +} + +void CScriptBallTrigger::Accept(IVisitor& visitor) +{ + visitor.Visit(this); +} + +void CScriptBallTrigger::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager & mgr) +{ + if (msg == EScriptObjectMessage::Deactivate && GetActive()) + { + mgr.GetPlayer().GetMorphBall()->SetBallBoostState(CMorphBall::EBallBoostState::BoostAvailable); + x168_24_canApplyForce = false; + } + + CScriptTrigger::AcceptScriptMsg(msg, uid, mgr); +} + +void CScriptBallTrigger::Think(float dt, CStateManager& mgr) +{ + if (!GetActive()) + return; + CScriptTrigger::Think(dt, mgr); + CPlayer& player = mgr.GetPlayer(); + + if (player.GetMorphballTransitionState() != CPlayer::EPlayerMorphBallState::Morphed) + { + x168_24_canApplyForce = false; + return; + } + + const float ballRadius = player.GetMorphBall()->GetBallRadius(); + const zeus::CVector3f radiusPosDif = (player.GetTranslation() - (player.GetTranslation() + zeus::CVector3f{0.f, 0.f, ballRadius})); + const float distance = radiusPosDif.magnitude(); + + if (!x168_24_canApplyForce) + { + if (distance < ballRadius) + x168_24_canApplyForce = true; + else + { + zeus::CVector3f offset = radiusPosDif.normalized(); + if (std::cos(zeus::degToRad(x154_minAngle)) < (-offset).dot(x15c_forceAngle) && distance < x158_maxDistance) + { + float force = zeus::min((1.f / dt * distance), x150_force * (distance * distance)); + player.ApplyForceWR(force * (player.GetMass() * offset), zeus::CAxisAngle::sIdentity); + } + } + } + + if (x148_28_playerTriggerProc) + { + zeus::CVector3f offset = GetTranslation() - zeus::CVector3f(0.f, 0.f, ballRadius); + if (x168_25_stopPlayer) + player.Stop(); + player.MoveToWR(offset, dt); + } + else + x168_24_canApplyForce = false; +} + +void CScriptBallTrigger::InhabitantAdded(CActor& act, CStateManager& /*mgr*/) +{ + if (TCastToPtr player = act) + player->GetMorphBall()->SetBallBoostState(CMorphBall::EBallBoostState::BoostDisabled); +} + +void CScriptBallTrigger::InhabitantExited(CActor& act, CStateManager &) +{ + if (TCastToPtr player = act) + { + player->GetMorphBall()->SetBallBoostState(CMorphBall::EBallBoostState::BoostAvailable); + x168_24_canApplyForce = false; + } +} + +} diff --git a/Runtime/World/CScriptBallTrigger.hpp b/Runtime/World/CScriptBallTrigger.hpp new file mode 100644 index 000000000..934b0c879 --- /dev/null +++ b/Runtime/World/CScriptBallTrigger.hpp @@ -0,0 +1,27 @@ +#ifndef __URDE_CSCRIPTBALLTRIGGER_HPP__ +#define __URDE_CSCRIPTBALLTRIGGER_HPP__ + +#include "CScriptTrigger.hpp" + +namespace urde +{ +class CScriptBallTrigger : public CScriptTrigger +{ + float x150_force; + float x154_minAngle; + float x158_maxDistance; + zeus::CVector3f x15c_forceAngle = zeus::CVector3f::skZero; + bool x168_24_canApplyForce : 1; + bool x168_25_stopPlayer : 1; +public: + CScriptBallTrigger(TUniqueId, std::string_view, const CEntityInfo&, const zeus::CVector3f&, + const zeus::CVector3f&, bool, float, float, float, const zeus::CVector3f&, bool); + + void Accept(IVisitor&); + void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&); + void Think(float, CStateManager& mgr); + void InhabitantAdded(CActor&, CStateManager&); + void InhabitantExited(CActor&, CStateManager&); +}; +} +#endif // __URDE_CSCRIPTBALLTRIGGER_HPP diff --git a/Runtime/World/CScriptGunTurret.cpp b/Runtime/World/CScriptGunTurret.cpp index 838a3c4cb..10d560bd2 100644 --- a/Runtime/World/CScriptGunTurret.cpp +++ b/Runtime/World/CScriptGunTurret.cpp @@ -1,4 +1,5 @@ #include "CScriptGunTurret.hpp" +#include "TCastTo.hpp" namespace urde { @@ -7,6 +8,47 @@ static const CMaterialList skGunMaterialList = { EMaterialTypes::Solid, EMateria EMaterialTypes::Orbit, EMaterialTypes::Target }; static const CMaterialList skTurretMaterialList = { EMaterialTypes::Character }; +CScriptGunTurretData::CScriptGunTurretData(CInputStream& in, s32 propCount) +: x0_(in.readFloatBig()), + x4_(in.readFloatBig()), + x8_(in.readFloatBig()), + xc_(in.readFloatBig()), + x10_(in.readFloatBig()), + x14_(in.readFloatBig()), + x1c_(zeus::degToRad(in.readFloatBig())), + x20_(zeus::degToRad(in.readFloatBig())), + x24_(zeus::degToRad(in.readFloatBig())), + x28_(zeus::degToRad(in.readFloatBig())), + x2c_(in.readFloatBig()), + x30_(in.readFloatBig()), + x34_(in.readFloatBig()), + x38_(in.readFloatBig()), + x3c_(propCount >= 48 ? in.readBool() : false), + x40_(in.readUint32Big()), + x44_(in), + x60_(in.readUint32Big()), + x64_(in.readUint32Big()), + x68_(in.readUint32Big()), + x6c_(in.readUint32Big()), + x70_(in.readUint32Big()), + x74_(in.readUint32Big()), + x78_(propCount >= 44 ? in.readUint32Big() : -1), + x7c_(CSfxManager::TranslateSFXID(in.readUint32Big() & 0xFFFF)), + x7e_(CSfxManager::TranslateSFXID(in.readUint32Big() & 0xFFFF)), + x80_(CSfxManager::TranslateSFXID(in.readUint32Big() & 0xFFFF)), + x82_(CSfxManager::TranslateSFXID(in.readUint32Big() & 0xFFFF)), + x84_(CSfxManager::TranslateSFXID(in.readUint32Big() & 0xFFFF)), + x86_(propCount >= 45 ? CSfxManager::TranslateSFXID(in.readUint32Big() & 0xFFFF) : -1), + x88_(in.readUint32Big()), + x8c_(in.readUint32Big()), + x90_(in.readUint32Big()), + x94_(in.readUint32Big()), + x98_(in.readUint32Big()), + x9c_(propCount >= 47 ? in.readFloatBig() : 3.f), + xa0_(propCount >= 46 ? in.readBool() : false) +{ +} + CScriptGunTurret::CScriptGunTurret(TUniqueId uid, std::string_view name, ETurretComponent comp, const CEntityInfo& info, const zeus::CTransform& xf, CModelData&& mData, const zeus::CAABox& aabb, const CHealthInfo& hInfo, const CDamageVulnerability& dVuln, @@ -18,4 +60,9 @@ CScriptGunTurret::CScriptGunTurret(TUniqueId uid, std::string_view name, ETurret } +void CScriptGunTurret::Accept(IVisitor& visitor) +{ + visitor.Visit(this); +} + } diff --git a/Runtime/World/CScriptGunTurret.hpp b/Runtime/World/CScriptGunTurret.hpp index 072e3c8cb..d467dbe33 100644 --- a/Runtime/World/CScriptGunTurret.hpp +++ b/Runtime/World/CScriptGunTurret.hpp @@ -2,13 +2,64 @@ #define __URDE_CSCRIPTGUNTURRET_HPP__ #include "CPhysicsActor.hpp" - +#include "CDamageInfo.hpp" namespace urde { class CScriptGunTurretData { - + float x0_; + float x4_; + float x8_; + float xc_; + float x10_; + float x14_; + float x18_ = 30.f; + float x1c_; + float x20_; + float x24_; + float x28_; + float x2c_; + float x30_; + float x34_; + float x38_; + bool x3c_; + u32 x40_; + CDamageInfo x44_; + u32 x60_; + u32 x64_; + u32 x68_; + u32 x6c_; + u32 x70_; + u32 x74_; + u32 x78_; + u16 x7c_; + u16 x7e_; + u16 x80_; + u16 x82_; + u16 x84_; + u16 x86_; + u32 x88_; + float x8c_; + u32 x90_; + u32 x94_; + u32 x98_; + float x9c_; + bool xa0_; + static constexpr s32 skMinProperties = 43; +public: + CScriptGunTurretData(CInputStream&, s32); + const CAssetId& GetPanningEffectRes() const; + const CAssetId& GetChargingEffectRes() const; + const CAssetId& GetFrozenEffectRes() const; + const CAssetId& GetTargettingLightRes() const; + const CAssetId& GetDeactivateLightRes() const; + const CAssetId& GetIdleLightRes() const; + const CDamageInfo& GetProjectileDamage() const; + const CAssetId& GetProjectileRes() const; + u16 GetUnFreezeSoundId() const; + void GetIntoDeactivateDelay() const; + static s32 GetMinProperties() { return skMinProperties; } }; class CScriptGunTurret : public CPhysicsActor @@ -25,6 +76,9 @@ public: const zeus::CTransform& xf, CModelData&& mData, const zeus::CAABox& aabb, const CHealthInfo& hInfo, const CDamageVulnerability& dVuln, const CActorParameters& aParms, const CScriptGunTurretData& turretData); + + void Accept(IVisitor&); + }; } diff --git a/Runtime/World/CScriptRipple.cpp b/Runtime/World/CScriptRipple.cpp new file mode 100644 index 000000000..83ae7fe06 --- /dev/null +++ b/Runtime/World/CScriptRipple.cpp @@ -0,0 +1,46 @@ +#include "CScriptRipple.hpp" +#include "CStateManager.hpp" +#include "CScriptWater.hpp" +#include "TCastTo.hpp" + +namespace urde +{ + +CScriptRipple::CScriptRipple(TUniqueId uid, std::string_view name, const CEntityInfo& info, + const zeus::CVector3f& vec, bool active, float f1) +: CEntity(uid, info, active, name) +, x34_magnitude(f1 >= 0.f ? f1 : 0.5f) +, x38_center(vec) +{ +} + +void CScriptRipple::Accept(IVisitor& visitor) +{ + visitor.Visit(this); +} + +void CScriptRipple::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) +{ + if (msg == EScriptObjectMessage::Play) + { + if (!GetActive()) + return; + + for (const SConnection& conn : x20_conns) + { + if (conn.x0_state != EScriptObjectState::Active || conn.x4_msg != EScriptObjectMessage::Next) + continue; + + auto search = mgr.GetIdListForScript(conn.x8_objId); + for (auto it = search.first; it != search.second; ++it) + { + if (TCastToPtr water = mgr.ObjectById(it->second)) + water->GetFluidPlane().AddRipple(x34_magnitude, GetUniqueId(), x38_center, *water, mgr); + } + } + + return; + } + CEntity::AcceptScriptMsg(msg, uid, mgr); +} +} diff --git a/Runtime/World/CScriptRipple.hpp b/Runtime/World/CScriptRipple.hpp new file mode 100644 index 000000000..1670b8fc0 --- /dev/null +++ b/Runtime/World/CScriptRipple.hpp @@ -0,0 +1,21 @@ +#ifndef __URDE_CSCRIPTRIPPLE_HPP__ +#define __URDE_CSCRIPTRIPPLE_HPP__ + +#include "CEntity.hpp" +#include "zeus/CVector3f.hpp" + +namespace urde +{ +class CScriptRipple : public CEntity +{ + float x34_magnitude; + zeus::CVector3f x38_center; +public: + CScriptRipple(TUniqueId, std::string_view, const CEntityInfo&, const zeus::CVector3f&, bool, float); + + void Accept(IVisitor&); + void Think(float, CStateManager&) {} + void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&); +}; +} +#endif // __URDE_CSCRIPTRIPPLE_HPP__ diff --git a/Runtime/World/CWorld.cpp b/Runtime/World/CWorld.cpp index dec625953..c0cdad81d 100644 --- a/Runtime/World/CWorld.cpp +++ b/Runtime/World/CWorld.cpp @@ -449,7 +449,7 @@ bool CWorld::CheckWorldComplete(CStateManager* mgr, TAreaId id, CAssetId mreaId) bool CWorld::ScheduleAreaToLoad(CGameArea* area, CStateManager& mgr) { - if (!area->xf0_24_postConstructed) + if (!area->IsPostConstructed()) { MoveToChain(area, EChain::Loading); return true; diff --git a/Runtime/World/ScriptLoader.cpp b/Runtime/World/ScriptLoader.cpp index 1510d1cdd..1b7796810 100644 --- a/Runtime/World/ScriptLoader.cpp +++ b/Runtime/World/ScriptLoader.cpp @@ -53,7 +53,11 @@ #include "CScriptSpawnPoint.hpp" #include "CScriptSpecialFunction.hpp" #include "CScriptSteam.hpp" +#include "CScriptRipple.hpp" +#include "CScriptBallTrigger.hpp" +#include "CScriptTargetingPoint.hpp" #include "CScriptStreamedMusic.hpp" +#include "CScriptGunTurret.hpp" #include "CScriptSwitch.hpp" #include "CScriptTimer.hpp" #include "CScriptVisorFlare.hpp" @@ -1789,17 +1793,43 @@ CEntity* ScriptLoader::LoadSteam(CStateManager& mgr, CInputStream& in, int propC CEntity* ScriptLoader::LoadRipple(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) { - return nullptr; + if (!EnsurePropertyCount(propCount, 4, "Ripple")) + return nullptr; + std::string_view name = mgr.HashInstanceName(in); + zeus::CVector3f center = zeus::CVector3f::ReadBig(in); + bool active = in.readBool(); + float mag = in.readFloatBig(); + return new CScriptRipple(mgr.AllocateUniqueId(), name, info, center, active, mag); } CEntity* ScriptLoader::LoadBallTrigger(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) { - return nullptr; + if (!EnsurePropertyCount(propCount, 9, "BallTrigger")) + return nullptr; + + std::string_view name = in.readString(); + zeus::CVector3f pos = zeus::CVector3f::ReadBig(in); + zeus::CVector3f scale = zeus::CVector3f::ReadBig(in); + + bool b1 = in.readBool(); + float f1 = in.readFloatBig(); + float f2 = in.readFloatBig(); + float f3 = in.readFloatBig(); + zeus::CVector3f vec = zeus::CVector3f::ReadBig(in); + bool b2 = in.readBool(); + return new CScriptBallTrigger(mgr.AllocateUniqueId(), name, info, pos, scale, b1, f1, f2, f3, vec, b2); } CEntity* ScriptLoader::LoadTargetingPoint(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) { - return nullptr; + if (!EnsurePropertyCount(propCount, 4, "TargetingPoint")) + return nullptr; + + + SActorHead aHead = LoadActorHead(in, mgr); + bool active = in.readBool(); + + return new CScriptTargetingPoint(mgr.AllocateUniqueId(), aHead.x0_name, info, aHead.x10_transform, active); } CEntity* ScriptLoader::LoadEMPulse(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) @@ -2293,7 +2323,31 @@ CEntity* ScriptLoader::LoadRepulsor(CStateManager& mgr, CInputStream& in, int pr CEntity* ScriptLoader::LoadGunTurret(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) { - return nullptr; + if (!EnsurePropertyCount(propCount, CScriptGunTurretData::GetMinProperties(), "GunTurret")) + return nullptr; + + std::string_view name = mgr.HashInstanceName(in); + CScriptGunTurret::ETurretComponent component = CScriptGunTurret::ETurretComponent(in.readUint32Big()); + zeus::CTransform xf = LoadEditorTransform(in); + zeus::CVector3f scale = zeus::CVector3f::ReadBig(in); + zeus::CVector3f collisionExtent = zeus::CVector3f::ReadBig(in); + zeus::CVector3f collisionOffset = zeus::CVector3f::ReadBig(in); + CAnimationParameters animParms = LoadAnimationParameters(in); + CActorParameters actParms = LoadActorParameters(in); + CHealthInfo hInfo(in); + CDamageVulnerability dVuln(in); + CScriptGunTurretData turretData(in, propCount); + + if (!g_ResFactory->GetResourceTypeById(animParms.GetACSFile())) + return nullptr; + + CModelData mData(CAnimRes(animParms.GetACSFile(), animParms.GetCharacter(), scale, animParms.GetInitialAnimation(), true)); + zeus::CAABox aabb = GetCollisionBox(mgr, info.GetAreaId(), collisionExtent, collisionOffset); + + if ((collisionExtent.x < 0.f || collisionExtent.y < 0.f || collisionExtent.z < 0.f) || collisionExtent.isZero()) + aabb = mData.GetBounds(xf.getRotation()); + + return new CScriptGunTurret(mgr.AllocateUniqueId(), name, component, info, xf, std::move(mData), aabb, hInfo, dVuln, actParms, turretData); } CEntity* ScriptLoader::LoadFogVolume(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info)