diff --git a/DataSpec/DNACommon/Tweaks/ITweakPlayer.hpp b/DataSpec/DNACommon/Tweaks/ITweakPlayer.hpp index d213d3ba8..461f71f13 100644 --- a/DataSpec/DNACommon/Tweaks/ITweakPlayer.hpp +++ b/DataSpec/DNACommon/Tweaks/ITweakPlayer.hpp @@ -17,6 +17,7 @@ struct ITweakPlayer : ITweak virtual float GetFluidGravAccel() const=0; virtual float GetHudLagAmount() const=0; virtual float GetOrbitNormalDistance() const=0; + virtual float GetOrbitDistanceCompareSignificance() const=0; virtual uint32_t GetOrbitScreenBoxHalfExtentX(int zone) const=0; virtual uint32_t GetOrbitScreenBoxHalfExtentY(int zone) const=0; virtual uint32_t GetOrbitScreenBoxCenterX(int zone) const=0; @@ -42,6 +43,7 @@ struct ITweakPlayer : ITweak virtual float GetX274() const=0; // x274 virtual float GetX278() const=0; // x278 virtual float GetPlayerBallHalfExtent() const=0; // x27c + virtual float GetOrbitDistanceThreshold() const=0; virtual float GetGrappleSwingLength() const=0; virtual float GetGrappleSwingPeriod() const=0; virtual float GetGrapplePullSpeedMin() const=0; diff --git a/DataSpec/DNAMP1/Tweaks/CTweakPlayer.cpp b/DataSpec/DNAMP1/Tweaks/CTweakPlayer.cpp index 8c0ab989b..dec8a1c1c 100644 --- a/DataSpec/DNAMP1/Tweaks/CTweakPlayer.cpp +++ b/DataSpec/DNAMP1/Tweaks/CTweakPlayer.cpp @@ -290,7 +290,7 @@ void CTweakPlayer::read(athena::io::IStreamReader& __dna_reader) /* x1a0_ */ x1a0_ = __dna_reader.readFloatBig(); /* x1a4_ */ - x1a4_ = __dna_reader.readFloatBig(); + x1a4_orbitDistanceCompareSignificance = __dna_reader.readFloatBig(); /* x1a8_orbitScreenBoxHalfExtentX[0] */ x1a8_orbitScreenBoxHalfExtentX[0] = __dna_reader.readUint32Big(); /* x1b0_orbitScreenBoxHalfExtentY[0] */ @@ -361,8 +361,8 @@ void CTweakPlayer::read(athena::io::IStreamReader& __dna_reader) x220_ = __dna_reader.readFloatBig(); /* x224_scanningFrameSenseRange */ x224_scanningFrameSenseRange = __dna_reader.readFloatBig(); - /* x2a0_ */ - x2a0_ = __dna_reader.readFloatBig(); + /* x2a0_orbitDistanceThreshold */ + x2a0_orbitDistanceThreshold = __dna_reader.readFloatBig(); /* x2a4_grappleSwingLength */ x2a4_grappleSwingLength = __dna_reader.readFloatBig(); /* x2a8_grappleSwingPeriod */ @@ -730,7 +730,7 @@ void CTweakPlayer::write(athena::io::IStreamWriter& __dna_writer) const /* x1a0_ */ __dna_writer.writeFloatBig(x1a0_); /* x1a4_ */ - __dna_writer.writeFloatBig(x1a4_); + __dna_writer.writeFloatBig(x1a4_orbitDistanceCompareSignificance); /* x1a8_orbitScreenBoxHalfExtentX[0] */ __dna_writer.writeUint32Big(x1a8_orbitScreenBoxHalfExtentX[0]); /* x1b0_orbitScreenBoxHalfExtentY[0] */ @@ -801,8 +801,8 @@ void CTweakPlayer::write(athena::io::IStreamWriter& __dna_writer) const __dna_writer.writeFloatBig(x220_); /* x224_scanningFrameSenseRange */ __dna_writer.writeFloatBig(x224_scanningFrameSenseRange); - /* x2a0_ */ - __dna_writer.writeFloatBig(x2a0_); + /* x2a0_orbitDistanceThreshold */ + __dna_writer.writeFloatBig(x2a0_orbitDistanceThreshold); /* x2a4_grappleSwingLength */ __dna_writer.writeFloatBig(x2a4_grappleSwingLength); /* x2a8_grappleSwingPeriod */ @@ -1215,7 +1215,7 @@ void CTweakPlayer::read(athena::io::YAMLDocReader& __dna_docin) /* x1a0_ */ x1a0_ = __dna_docin.readFloat("x1a0_"); /* x1a4_ */ - x1a4_ = __dna_docin.readFloat("x1a4_"); + x1a4_orbitDistanceCompareSignificance = __dna_docin.readFloat("x1a4_"); /* x1a8_orbitScreenBoxHalfExtentX */ size_t __x1a8_Count; if (auto v = __dna_docin.enterSubVector("x1a8_orbitScreenBoxHalfExtentX", __x1a8_Count)) @@ -1316,8 +1316,8 @@ void CTweakPlayer::read(athena::io::YAMLDocReader& __dna_docin) x220_ = __dna_docin.readFloat("x220_"); /* x224_scanningFrameSenseRange */ x224_scanningFrameSenseRange = __dna_docin.readFloat("x224_scanningFrameSenseRange"); - /* x2a0_ */ - x2a0_ = __dna_docin.readFloat("x2a0_"); + /* x2a0_orbitDistanceThreshold */ + x2a0_orbitDistanceThreshold = __dna_docin.readFloat("x2a0_orbitDistanceThreshold"); /* x2a4_grappleSwingLength */ x2a4_grappleSwingLength = __dna_docin.readFloat("x2a4_grappleSwingLength"); /* x2a8_grappleSwingPeriod */ @@ -1721,7 +1721,7 @@ void CTweakPlayer::write(athena::io::YAMLDocWriter& __dna_docout) const /* x1a0_ */ __dna_docout.writeFloat("x1a0_", x1a0_); /* x1a4_ */ - __dna_docout.writeFloat("x1a4_", x1a4_); + __dna_docout.writeFloat("x1a4_", x1a4_orbitDistanceCompareSignificance); /* x1a8_orbitScreenBoxHalfExtentX */ if (auto v = __dna_docout.enterSubVector("x1a8_orbitScreenBoxHalfExtentX")) { @@ -1816,8 +1816,8 @@ void CTweakPlayer::write(athena::io::YAMLDocWriter& __dna_docout) const __dna_docout.writeFloat("x220_", x220_); /* x224_scanningFrameSenseRange */ __dna_docout.writeFloat("x224_scanningFrameSenseRange", x224_scanningFrameSenseRange); - /* x2a0_ */ - __dna_docout.writeFloat("x2a0_", x2a0_); + /* x2a0_orbitDistanceThreshold */ + __dna_docout.writeFloat("x2a0_orbitDistanceThreshold", x2a0_orbitDistanceThreshold); /* x2a4_grappleSwingLength */ __dna_docout.writeFloat("x2a4_grappleSwingLength", x2a4_grappleSwingLength); /* x2a8_grappleSwingPeriod */ diff --git a/DataSpec/DNAMP1/Tweaks/CTweakPlayer.hpp b/DataSpec/DNAMP1/Tweaks/CTweakPlayer.hpp index ea582e0f9..84dd6edeb 100644 --- a/DataSpec/DNAMP1/Tweaks/CTweakPlayer.hpp +++ b/DataSpec/DNAMP1/Tweaks/CTweakPlayer.hpp @@ -67,7 +67,7 @@ struct CTweakPlayer : ITweakPlayer Value x198_; Value x19c_; Value x1a0_; - Value x1a4_; + Value x1a4_orbitDistanceCompareSignificance; Value x1a8_orbitScreenBoxHalfExtentX[2]; Value x1b0_orbitScreenBoxHalfExtentY[2]; Value x1b8_orbitScreenBoxCenterX[2]; @@ -147,7 +147,7 @@ struct CTweakPlayer : ITweakPlayer Value x294_; Value x298_; Value x29c_; - Value x2a0_; + Value x2a0_orbitDistanceThreshold; Value x2a4_grappleSwingLength; Value x2a8_grappleSwingPeriod; Value x2ac_grapplePullSpeedMin; @@ -183,6 +183,7 @@ struct CTweakPlayer : ITweakPlayer float GetFluidGravAccel() const { return xc8_fluidGravAccel; } float GetHudLagAmount() const { return x138_hudLagAmount; } float GetOrbitNormalDistance() const { return x180_orbitNormalDistance; } + float GetOrbitDistanceCompareSignificance() const { return x1a4_orbitDistanceCompareSignificance; } uint32_t GetOrbitScreenBoxHalfExtentX(int zone) const { return x1a8_orbitScreenBoxHalfExtentX[zone]; } uint32_t GetOrbitScreenBoxHalfExtentY(int zone) const { return x1b0_orbitScreenBoxHalfExtentY[zone]; } uint32_t GetOrbitScreenBoxCenterX(int zone) const { return x1b8_orbitScreenBoxCenterX[zone]; } @@ -207,6 +208,7 @@ struct CTweakPlayer : ITweakPlayer float GetX274() const { return x274_; } float GetX278() const { return x278_; } float GetPlayerBallHalfExtent() const { return x27c_playerBallHalfExtent; } + float GetOrbitDistanceThreshold() const { return x2a0_orbitDistanceThreshold; } float GetGrappleSwingLength() const { return x2a4_grappleSwingLength; } float GetGrappleSwingPeriod() const { return x2a8_grappleSwingPeriod; } float GetGrapplePullSpeedMin() const { return x2ac_grapplePullSpeedMin; } diff --git a/Runtime/CGameState.hpp b/Runtime/CGameState.hpp index 0b8517c1e..78da7e948 100644 --- a/Runtime/CGameState.hpp +++ b/Runtime/CGameState.hpp @@ -52,7 +52,7 @@ class CWorldState std::shared_ptr x14_layerState; public: - CWorldState(ResId id); + explicit CWorldState(ResId id); CWorldState(CBitStreamReader& reader, ResId mlvlId, const CSaveWorld& saveWorld); ResId GetWorldAssetId() const { return x0_mlvlId; } void SetAreaId(TAreaId aid) { x4_areaId = aid; } diff --git a/Runtime/World/CPlayer.cpp b/Runtime/World/CPlayer.cpp index a6f6da3ac..aef503f7c 100644 --- a/Runtime/World/CPlayer.cpp +++ b/Runtime/World/CPlayer.cpp @@ -31,12 +31,16 @@ namespace urde static const CMaterialFilter SolidMaterialFilter = CMaterialFilter::MakeInclude(CMaterialList(EMaterialTypes::Solid)); -static const CMaterialFilter TargetingFilter = +static const CMaterialFilter LineOfSightFilter = CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {EMaterialTypes::ProjectilePassthrough, EMaterialTypes::ScanPassthrough, EMaterialTypes::Player}); +static const CMaterialFilter OccluderFilter = + CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid, EMaterialTypes::Occluder}, + {EMaterialTypes::ProjectilePassthrough, EMaterialTypes::ScanPassthrough, EMaterialTypes::Player}); + static CModelData MakePlayerAnimRes(ResId resId, const zeus::CVector3f& scale) { return {CAnimRes(resId, 0, scale, 0, true), 1}; @@ -2037,7 +2041,7 @@ void CPlayer::UpdateGrappleState(const CFinalInput& input, CStateManager& mgr) { CRayCastResult result = mgr.RayStaticIntersection(eyePosition, playerToPoint.normalized(), playerToPoint.magnitude(), - TargetingFilter); + LineOfSightFilter); if (result.IsInvalid()) { HolsterGun(mgr); @@ -2170,7 +2174,7 @@ void CPlayer::UpdateGrappleState(const CFinalInput& input, CStateManager& mgr) { CRayCastResult result = mgr.RayStaticIntersection(eyePos, playerToPoint.normalized(), playerToPoint.magnitude(), - TargetingFilter); + LineOfSightFilter); if (result.IsValid()) { BreakGrapple(EPlayerOrbitRequest::Twelve, mgr); @@ -2442,12 +2446,189 @@ void CPlayer::UpdateOrbitableObjects(CStateManager& mgr) FindOrbitableObjects(nearList, x364_offScreenOrbitObjects, x330_orbitZone, x334_orbitType, mgr, false); } -TUniqueId CPlayer::FindBestOrbitableObject(const std::vector&, EPlayerZoneInfo, CStateManager& mgr) const +TUniqueId CPlayer::FindBestOrbitableObject(const std::vector& ids, + EPlayerZoneInfo info, CStateManager& mgr) const { zeus::CVector3f eyePos = GetEyePosition(); zeus::CVector3f lookDir = x34_transform.basis[1].normalized(); - /* TODO: Finish */ - return {}; + float minEyeToOrbitMag = 10000.f; + float minPosInBoxMagSq = 10000.f; + TUniqueId bestId = kInvalidUniqueId; + int vpWidthHalf = g_Viewport.x8_width / 2; + int vpHeightHalf = g_Viewport.xc_height / 2; + float boxLeft = (g_tweakPlayer->GetEnemyScreenBoxCenterX(int(info)) * + g_Viewport.x8_width / 640 - vpWidthHalf) / vpWidthHalf; + float boxTop = (g_tweakPlayer->GetEnemyScreenBoxCenterY(int(info)) * + g_Viewport.xc_height / 448 - vpHeightHalf) / vpHeightHalf; + + CFirstPersonCamera* fpCam = mgr.GetCameraManager()->GetFirstPersonCamera(); + + for (TUniqueId id : ids) + { + if (TCastToPtr act = mgr.ObjectById(id)) + { + zeus::CVector3f orbitPos = act->GetOrbitPosition(mgr); + zeus::CVector3f eyeToOrbit = orbitPos - eyePos; + float eyeToOrbitMag = eyeToOrbit.magnitude(); + zeus::CVector3f orbitPosScreen = fpCam->ConvertToScreenSpace(orbitPos); + if (orbitPosScreen.z >= 0.f) + { + if (x310_orbitTargetId != id) + { + if (TCastToPtr point = act.GetPtr()) + { + if (x310_orbitTargetId != point->GetUniqueId()) + { + if (mgr.GetPlayerState()->HasPowerUp(CPlayerState::EItemType::GrappleBeam) && + eyeToOrbitMag < minEyeToOrbitMag && + eyeToOrbitMag < g_tweakPlayer->GetOrbitDistanceThreshold()) + { + rstl::reserved_vector nearList; + TUniqueId intersectId = kInvalidUniqueId; + eyeToOrbit.normalize(); + mgr.BuildNearList(nearList, eyePos, eyeToOrbit, eyeToOrbitMag, + OccluderFilter, act.GetPtr()); + eyeToOrbit.normalize(); + CRayCastResult result = + mgr.RayWorldIntersection(intersectId, eyePos, eyeToOrbit, eyeToOrbitMag, + LineOfSightFilter, nearList); + if (result.IsInvalid()) + { + if (point->GetGrappleParameters().GetLockSwingTurn()) + { + zeus::CVector3f pointToPlayer = + GetTranslation() - point->GetTranslation(); + if (pointToPlayer.canBeNormalized()) + { + pointToPlayer.z = 0.f; + if (std::fabs(point->GetTransform().basis[1].normalized(). + dot(pointToPlayer.normalized())) <= M_SQRT1_2F) + continue; + } + } + + bestId = act->GetUniqueId(); + float posInBoxLeft = orbitPosScreen.x - boxLeft; + float posInBoxTop = orbitPosScreen.y - boxTop; + minEyeToOrbitMag = eyeToOrbitMag; + minPosInBoxMagSq = posInBoxLeft * posInBoxLeft + posInBoxTop * posInBoxTop; + } + } + continue; + } + } + + if (minEyeToOrbitMag - eyeToOrbitMag > g_tweakPlayer->GetOrbitDistanceCompareSignificance() && + mgr.GetPlayerState()->GetCurrentVisor() != CPlayerState::EPlayerVisor::Scan) + { + rstl::reserved_vector nearList; + TUniqueId bestId = kInvalidUniqueId; + eyeToOrbit.normalize(); + mgr.BuildNearList(nearList, eyePos, eyeToOrbit, eyeToOrbitMag, + OccluderFilter, act.GetPtr()); + for (auto it = nearList.begin() ; it != nearList.end() ;) + { + if (CEntity* obj = mgr.ObjectById(*it)) + { + if (obj->GetAreaIdAlways() != kInvalidAreaId) + { + if (mgr.GetNextAreaId() != obj->GetAreaIdAlways()) + { + const CGameArea* area = mgr.GetWorld()->GetAreaAlways(obj->GetAreaIdAlways()); + CGameArea::EOcclusionState state = + area->IsPostConstructed() ? area->GetOcclusionState() : + CGameArea::EOcclusionState::Occluded; + if (state == CGameArea::EOcclusionState::Occluded) + { + it = nearList.erase(it); + continue; + } + } + } + else + { + it = nearList.erase(it); + continue; + } + } + ++it; + } + + eyeToOrbit.normalize(); + CRayCastResult result = + mgr.RayWorldIntersection(bestId, eyePos, eyeToOrbit, eyeToOrbitMag, + LineOfSightFilter, nearList); + if (result.IsInvalid()) + { + bestId = act->GetUniqueId(); + float posInBoxLeft = orbitPosScreen.x - boxLeft; + float posInBoxTop = orbitPosScreen.y - boxTop; + minEyeToOrbitMag = eyeToOrbitMag; + minPosInBoxMagSq = posInBoxLeft * posInBoxLeft + posInBoxTop * posInBoxTop; + } + } + + if (std::fabs(eyeToOrbitMag - minEyeToOrbitMag) < + g_tweakPlayer->GetOrbitDistanceCompareSignificance() || + mgr.GetPlayerState()->GetCurrentVisor() == CPlayerState::EPlayerVisor::Scan) + { + float posInBoxLeft = orbitPosScreen.x - boxLeft; + float posInBoxTop = orbitPosScreen.y - boxTop; + float posInBoxMagSq = posInBoxLeft * posInBoxLeft + posInBoxTop * posInBoxTop; + if (posInBoxMagSq < minPosInBoxMagSq) + { + rstl::reserved_vector nearList; + TUniqueId bestId = kInvalidUniqueId; + eyeToOrbit.normalize(); + mgr.BuildNearList(nearList, eyePos, eyeToOrbit, eyeToOrbitMag, + OccluderFilter, act.GetPtr()); + for (auto it = nearList.begin() ; it != nearList.end() ;) + { + if (CEntity* obj = mgr.ObjectById(*it)) + { + if (obj->GetAreaIdAlways() != kInvalidAreaId) + { + if (mgr.GetNextAreaId() != obj->GetAreaIdAlways()) + { + const CGameArea* area = + mgr.GetWorld()->GetAreaAlways(obj->GetAreaIdAlways()); + CGameArea::EOcclusionState state = + area->IsPostConstructed() ? area->GetOcclusionState() : + CGameArea::EOcclusionState::Occluded; + if (state == CGameArea::EOcclusionState::Occluded) + { + it = nearList.erase(it); + continue; + } + } + } + else + { + it = nearList.erase(it); + continue; + } + } + ++it; + } + + eyeToOrbit.normalize(); + CRayCastResult result = + mgr.RayWorldIntersection(bestId, eyePos, eyeToOrbit, eyeToOrbitMag, + LineOfSightFilter, nearList); + if (result.IsInvalid()) + { + bestId = act->GetUniqueId(); + minPosInBoxMagSq = posInBoxMagSq; + minEyeToOrbitMag = eyeToOrbitMag; + } + } + } + } + } + } + } + + return bestId; } void CPlayer::FindOrbitableObjects(const rstl::reserved_vector& nearObjects, @@ -2482,13 +2663,15 @@ void CPlayer::FindOrbitableObjects(const rstl::reserved_vector& pass = true; } - if (pass && (!act->GetDoTargetDistanceTest() || (orbitPos - eyePos).magnitude() <= GetOrbitMaxTargetDistance(mgr))) + if (pass && (!act->GetDoTargetDistanceTest() || + (orbitPos - eyePos).magnitude() <= GetOrbitMaxTargetDistance(mgr))) listOut.push_back(id); } } } -bool CPlayer::WithinOrbitScreenBox(const zeus::CVector3f& screenCoords, EPlayerZoneInfo zone, EPlayerZoneType type) const +bool CPlayer::WithinOrbitScreenBox(const zeus::CVector3f& screenCoords, EPlayerZoneInfo zone, + EPlayerZoneType type) const { if (screenCoords.z >= 1.f) return false; diff --git a/nod b/nod index d597400f4..42ef3a795 160000 --- a/nod +++ b/nod @@ -1 +1 @@ -Subproject commit d597400f4a83f9bb759b1c1ce44517c2fe7f886d +Subproject commit 42ef3a7958b616eb606c43fbe0fc5fa443373358 diff --git a/specter b/specter index ea1f1f7b9..cd448ae32 160000 --- a/specter +++ b/specter @@ -1 +1 @@ -Subproject commit ea1f1f7b93352baf8b0142bc9458b6a0f512775e +Subproject commit cd448ae32819248448d04fa3ff050c2a82e1d190