mirror of https://github.com/AxioDL/metaforce.git
Implement CFishCloud
This commit is contained in:
parent
8e2db0795b
commit
b72cc490e8
|
@ -17,6 +17,9 @@
|
|||
<pair source="c" header="h" fileNamingConvention="NONE" />
|
||||
</extensions>
|
||||
</Objective-C-extensions>
|
||||
<clangFormatSettings>
|
||||
<option name="ENABLED" value="true" />
|
||||
</clangFormatSettings>
|
||||
<codeStyleSettings language="ObjectiveC">
|
||||
<option name="INDENT_CASE_FROM_SWITCH" value="false" />
|
||||
<indentOptions>
|
||||
|
|
|
@ -12,38 +12,38 @@ struct FishCloud : IScriptObject {
|
|||
Value<atVec3f> location;
|
||||
Value<atVec3f> orientation;
|
||||
Value<atVec3f> volume;
|
||||
Value<bool> unknown1;
|
||||
Value<bool> active;
|
||||
UniqueID32 model;
|
||||
AnimationParameters animationParameters;
|
||||
Value<float> unknown2;
|
||||
Value<float> unknown3;
|
||||
Value<float> unknown4;
|
||||
Value<float> unknown5;
|
||||
Value<float> unknown6;
|
||||
Value<float> unknown7;
|
||||
Value<float> unknown8;
|
||||
Value<float> unknown9;
|
||||
Value<float> unknown10;
|
||||
Value<float> unknown11;
|
||||
Value<float> unknown12;
|
||||
Value<float> unknown13;
|
||||
Value<float> unknown14;
|
||||
Value<float> unknown15;
|
||||
Value<atUint32> unknown16;
|
||||
Value<atVec4f> unknown17; // CColor
|
||||
Value<bool> unknown18;
|
||||
Value<float> unknown19;
|
||||
Value<atUint32> numBoids;
|
||||
Value<float> speed;
|
||||
Value<float> separationRadius;
|
||||
Value<float> cohesionMagnitude;
|
||||
Value<float> alignmentWeight;
|
||||
Value<float> separationMagnitude;
|
||||
Value<float> weaponRepelMagnitude;
|
||||
Value<float> playerRepelMagnitude;
|
||||
Value<float> containmentMagnitude;
|
||||
Value<float> scatterVel;
|
||||
Value<float> maxScatterAngle;
|
||||
Value<float> weaponRepelDampingSpeed;
|
||||
Value<float> playerRepelDampingSpeed;
|
||||
Value<float> containmentRadius;
|
||||
Value<atUint32> updateShift;
|
||||
Value<atVec4f> color; // CColor
|
||||
Value<bool> killable;
|
||||
Value<float> weaponKillRadius;
|
||||
UniqueID32 deathParticle1;
|
||||
Value<atUint32> deathParticle1Frames;
|
||||
Value<atUint32> deathParticle1Count;
|
||||
UniqueID32 deathParticle2;
|
||||
Value<atUint32> deathParticle2Frames;
|
||||
Value<atUint32> deathParticle2Count;
|
||||
UniqueID32 deathParticle3;
|
||||
Value<atUint32> deathParticle3Frames;
|
||||
Value<atUint32> deathParticle3Count;
|
||||
UniqueID32 deathParticle4;
|
||||
Value<atUint32> deathParticle4Frames;
|
||||
Value<atUint32> deathParticle4Count;
|
||||
Value<atUint32> deathSFX;
|
||||
Value<bool> unknown29;
|
||||
Value<bool> unknown30;
|
||||
Value<bool> repelFromThreats;
|
||||
Value<bool> hotInThermal;
|
||||
|
||||
void nameIDs(PAKRouter<PAKBridge>& pakRouter) const {
|
||||
if (model) {
|
||||
|
|
|
@ -10,10 +10,10 @@ struct FishCloudModifier : IScriptObject {
|
|||
AT_DECL_DNAV
|
||||
String<-1> name;
|
||||
Value<atVec3f> position;
|
||||
Value<bool> unknown1;
|
||||
Value<bool> unknown2;
|
||||
Value<bool> unknown3;
|
||||
Value<float> unknown4;
|
||||
Value<float> unknown5;
|
||||
Value<bool> active;
|
||||
Value<bool> repulsor;
|
||||
Value<bool> swirl;
|
||||
Value<float> radius;
|
||||
Value<float> priority;
|
||||
};
|
||||
} // namespace DataSpec::DNAMP1
|
||||
|
|
|
@ -1321,8 +1321,7 @@ void CStateManager::ApplyDamageToWorld(TUniqueId damager, const CActor& actor, c
|
|||
bool bomb = false;
|
||||
TCastToPtr<CWeapon> weapon = const_cast<CActor&>(actor);
|
||||
if (weapon)
|
||||
bomb = (weapon->GetAttribField() & (EProjectileAttrib::Bombs | EProjectileAttrib::PowerBombs)) !=
|
||||
EProjectileAttrib::None;
|
||||
bomb = True(weapon->GetAttribField() & (EProjectileAttrib::Bombs | EProjectileAttrib::PowerBombs));
|
||||
|
||||
rstl::reserved_vector<TUniqueId, 1024> nearList;
|
||||
BuildNearList(nearList, aabb, filter, &actor);
|
||||
|
@ -1508,8 +1507,7 @@ bool CStateManager::MultiRayCollideWorld(const zeus::CMRay& ray, const CMaterial
|
|||
|
||||
void CStateManager::TestBombHittingWater(const CActor& damager, const zeus::CVector3f& pos, CActor& damagee) {
|
||||
if (TCastToPtr<CWeapon> wpn = const_cast<CActor&>(damager)) {
|
||||
if ((wpn->GetAttribField() & (EProjectileAttrib::Bombs | EProjectileAttrib::PowerBombs)) !=
|
||||
EProjectileAttrib::None) {
|
||||
if (True(wpn->GetAttribField() & (EProjectileAttrib::Bombs | EProjectileAttrib::PowerBombs))) {
|
||||
bool powerBomb = (wpn->GetAttribField() & EProjectileAttrib::PowerBombs) == EProjectileAttrib::PowerBombs;
|
||||
if (TCastToPtr<CScriptWater> water = damagee) {
|
||||
zeus::CAABox bounds = water->GetTriggerBoundsWR();
|
||||
|
|
|
@ -76,7 +76,7 @@ void CCameraManager::EnterCinematic(CStateManager& mgr) {
|
|||
mgr.FreeScriptObject(explo->GetUniqueId());
|
||||
} else if (TCastToPtr<CWeapon> weap = ent) {
|
||||
if (weap->GetActive()) {
|
||||
if ((weap->GetAttribField() & EProjectileAttrib::KeepInCinematic) == EProjectileAttrib::None) {
|
||||
if (False(weap->GetAttribField() & EProjectileAttrib::KeepInCinematic)) {
|
||||
if (TCastToConstPtr<CAi>(mgr.GetObjectById(weap->GetOwnerId())) ||
|
||||
TCastToConstPtr<CPlayer>(mgr.GetObjectById(weap->GetOwnerId())))
|
||||
mgr.FreeScriptObject(weap->GetUniqueId());
|
||||
|
|
|
@ -10,14 +10,14 @@
|
|||
namespace urde {
|
||||
|
||||
CBoneTracking::CBoneTracking(const CAnimData& animData, std::string_view bone,
|
||||
float maxTrackingAngle, float angSpeed, bool parentIk)
|
||||
float maxTrackingAngle, float angSpeed, EBoneTrackingFlags flags)
|
||||
: x14_segId(animData.GetCharLayoutInfo().GetSegIdFromString(bone))
|
||||
, x1c_maxTrackingAngle(maxTrackingAngle)
|
||||
, x20_angSpeed(angSpeed)
|
||||
, x36_26_noParent(parentIk)
|
||||
, x36_27_noParentOrigin(parentIk)
|
||||
, x36_28_noHorizontalAim(parentIk)
|
||||
, x36_29_parentIk(parentIk) {}
|
||||
, x36_26_noParent(True(flags & EBoneTrackingFlags::NoParent))
|
||||
, x36_27_noParentOrigin(True(flags & EBoneTrackingFlags::NoParentOrigin))
|
||||
, x36_28_noHorizontalAim(True(flags & EBoneTrackingFlags::NoHorizontalAim))
|
||||
, x36_29_parentIk(True(flags & EBoneTrackingFlags::ParentIk)) {}
|
||||
|
||||
void CBoneTracking::Update(float dt) { x18_time += dt; }
|
||||
|
||||
|
|
|
@ -11,6 +11,16 @@ namespace urde {
|
|||
class CAnimData;
|
||||
class CStateManager;
|
||||
class CBodyController;
|
||||
|
||||
enum class EBoneTrackingFlags {
|
||||
None = 0,
|
||||
NoParent = 1,
|
||||
NoParentOrigin = 2,
|
||||
NoHorizontalAim = 4,
|
||||
ParentIk = 8
|
||||
};
|
||||
ENABLE_BITWISE_ENUM(EBoneTrackingFlags)
|
||||
|
||||
class CBoneTracking {
|
||||
zeus::CQuaternion x0_curRotation = zeus::CQuaternion();
|
||||
float x10_ = 0.f;
|
||||
|
@ -34,7 +44,7 @@ class CBoneTracking {
|
|||
|
||||
public:
|
||||
CBoneTracking(const CAnimData& animData, std::string_view bone,
|
||||
float maxTrackingAngle, float angSpeed, bool parentIk);
|
||||
float maxTrackingAngle, float angSpeed, EBoneTrackingFlags flags);
|
||||
void Update(float dt);
|
||||
void PreRender(const CStateManager& mgr, CAnimData& animData, const zeus::CTransform& xf,
|
||||
const zeus::CVector3f& vec, const CBodyController& bodyController);
|
||||
|
|
|
@ -59,7 +59,8 @@ CBabygoth::CBabygoth(TUniqueId uid, std::string_view name, const CEntityInfo& in
|
|||
, x6ec_(nullptr, 1, pInfo.GetPathfindingIndex(), 1.f, 1.f)
|
||||
, x7d0_(nullptr, 1, pInfo.GetPathfindingIndex(), 1.f, 1.f)
|
||||
, x8d0_(x3b4_speed)
|
||||
, x8f0_boneTracking(*ModelData()->AnimationData(), "Head_1"sv, zeus::degToRad(80.f), zeus::degToRad(180.f), false)
|
||||
, x8f0_boneTracking(*ModelData()->AnimationData(), "Head_1"sv, zeus::degToRad(80.f), zeus::degToRad(180.f),
|
||||
EBoneTrackingFlags::None)
|
||||
, x930_aabox(GetBoundingBox(), GetMaterialList())
|
||||
, x958_(babyData.x8_, babyData.xc_)
|
||||
, x984_flameThrowerDesc(babyData.x44_.IsValid() ? g_SimplePool->GetObj({SBIG('WPSC'), babyData.x44_})
|
||||
|
|
|
@ -17,7 +17,8 @@ CEyeball::CEyeball(TUniqueId uid, std::string_view name, CPatterned::EFlavorType
|
|||
EColliderType::Zero, EBodyType::Restricted, actParms, EKnockBackVariant::Medium)
|
||||
, x568_attackDelay(attackDelay)
|
||||
, x56c_attackStartTime(attackStartTime)
|
||||
, x570_boneTracking(*GetModelData()->GetAnimationData(), "Eye"sv, zeus::degToRad(45.f), zeus::degToRad(180.f), true)
|
||||
, x570_boneTracking(*GetModelData()->GetAnimationData(), "Eye"sv, zeus::degToRad(45.f), zeus::degToRad(180.f),
|
||||
EBoneTrackingFlags::NoParent)
|
||||
, x5b4_projectileInfo(wpscId, dInfo)
|
||||
, x5dc_beamContactFxId(beamContactFxId)
|
||||
, x5e0_beamPulseFxId(beamPulseFxId)
|
||||
|
|
|
@ -20,7 +20,8 @@ CNewIntroBoss::CNewIntroBoss(TUniqueId uid, std::string_view name, const CEntity
|
|||
: CPatterned(ECharacter::NewIntroBoss, uid, name, EFlavorType::Zero, info, xf, std::move(mData), pInfo,
|
||||
EMovementType::Flyer, EColliderType::One, EBodyType::Restricted, actParms, EKnockBackVariant::Medium)
|
||||
, x570_minTurnAngle(minTurnAngle)
|
||||
, x574_boneTracking(*GetModelData()->GetAnimationData(), "Head_1"sv, zeus::degToRad(80.f), zeus::degToRad(180.f), false)
|
||||
, x574_boneTracking(*GetModelData()->GetAnimationData(), "Head_1"sv, zeus::degToRad(80.f), zeus::degToRad(180.f),
|
||||
EBoneTrackingFlags::None)
|
||||
, x5ac_projectileInfo(projectile, dInfo)
|
||||
, x5f0_beamContactFxId(beamContactFxId)
|
||||
, x5f4_beamPulseFxId(beamPulseFxId)
|
||||
|
|
|
@ -341,7 +341,7 @@ CSpacePirate::CSpacePirate(TUniqueId uid, std::string_view name, const CEntityIn
|
|||
, x568_pirateData(in, propCount)
|
||||
, x660_pathFindSearch(nullptr, 0x1, pInfo.GetPathfindingIndex(), 1.f, 1.f)
|
||||
, x750_initialHP(pInfo.GetHealthInfo().GetHP())
|
||||
, x764_boneTracking(*x64_modelData->AnimationData(), "Head_1"sv, 1.22173f, 3.14159f, false)
|
||||
, x764_boneTracking(*x64_modelData->AnimationData(), "Head_1"sv, 1.22173f, 3.14159f, EBoneTrackingFlags::None)
|
||||
, x7c4_burstFire(skBursts, x568_pirateData.xac_firstBurstCount)
|
||||
, x8b8_minCloakAlpha(x568_pirateData.xb0_CloakOpacity)
|
||||
, x8bc_maxCloakAlpha(x568_pirateData.xb4_MaxCloakOpacity)
|
||||
|
@ -1005,7 +1005,7 @@ void CSpacePirate::Touch(CActor& other, CStateManager& mgr) {
|
|||
CPatterned::Touch(other, mgr);
|
||||
if (x85c_ragDoll && x85c_ragDoll->IsPrimed()) {
|
||||
if (TCastToPtr<CScriptTrigger> trig = other) {
|
||||
if (trig->GetActive() && (trig->GetTriggerFlags() & ETriggerFlags::DetectAI) != ETriggerFlags::None &&
|
||||
if (trig->GetActive() && True(trig->GetTriggerFlags() & ETriggerFlags::DetectAI) &&
|
||||
trig->GetForceMagnitude() > 0.f) {
|
||||
x85c_ragDoll->TorsoImpulse() += trig->GetForceVector();
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ CElementGen::CElementGen(const TToken<CGenDescription>& gen, EModelOrientationTy
|
|||
CGenDescription* desc = x1c_genDesc.GetObj();
|
||||
x28_loadedGenDesc = desc;
|
||||
|
||||
x26d_27_enableOPTS = (flags & EOptionalSystemFlags::Two) != EOptionalSystemFlags::None;
|
||||
x26d_27_enableOPTS = True(flags & EOptionalSystemFlags::Two);
|
||||
|
||||
if (desc->x54_x40_TEXR)
|
||||
desc->x54_x40_TEXR->GetValueTexture(0).GetObj();
|
||||
|
|
|
@ -10,7 +10,7 @@ CWeapon::CWeapon(TUniqueId uid, TAreaId aid, bool active, TUniqueId owner, EWeap
|
|||
const zeus::CTransform& xf, const CMaterialFilter& filter, const CMaterialList& mList,
|
||||
const CDamageInfo& dInfo, EProjectileAttrib attribs, CModelData&& mData)
|
||||
: CActor(uid, active, name, CEntityInfo(aid, CEntity::NullConnectionList), xf, std::move(mData), mList,
|
||||
CActorParameters::None(), kInvalidUniqueId)
|
||||
CActorParameters::None().HotInThermal(true), kInvalidUniqueId)
|
||||
, xe8_projectileAttribs(attribs)
|
||||
, xec_ownerId(owner)
|
||||
, xf0_weaponType(type)
|
||||
|
@ -70,10 +70,10 @@ void CWeapon::FluidFXThink(EFluidState state, CScriptWater& water, CStateManager
|
|||
break;
|
||||
}
|
||||
|
||||
if ((xe8_projectileAttribs & EProjectileAttrib::ComboShot) != EProjectileAttrib::None &&
|
||||
if (True(xe8_projectileAttribs & EProjectileAttrib::ComboShot) &&
|
||||
state != EFluidState::InFluid)
|
||||
mag += 0.5f;
|
||||
if ((xe8_projectileAttribs & EProjectileAttrib::Charged) != EProjectileAttrib::None)
|
||||
if (True(xe8_projectileAttribs & EProjectileAttrib::Charged))
|
||||
mag += 0.25f;
|
||||
if (mag > 1.f)
|
||||
mag = 1.f;
|
||||
|
@ -81,7 +81,7 @@ void CWeapon::FluidFXThink(EFluidState state, CScriptWater& water, CStateManager
|
|||
if (doRipple) {
|
||||
zeus::CVector3f pos = GetTranslation();
|
||||
pos.z() = float(water.GetTriggerBoundsWR().max.z());
|
||||
if ((xe8_projectileAttribs & EProjectileAttrib::ComboShot) != EProjectileAttrib::None) {
|
||||
if (True(xe8_projectileAttribs & EProjectileAttrib::ComboShot)) {
|
||||
if (!water.CanRippleAtPoint(pos))
|
||||
doRipple = false;
|
||||
} else if (state == EFluidState::InFluid) {
|
||||
|
|
|
@ -176,7 +176,7 @@ void CEnvFxManager::CalculateSnowForces(const CVectorFixed8_8& zVec,
|
|||
void CEnvFxManager::BuildBlockObjectList(rstl::reserved_vector<TUniqueId, 1024>& list, CStateManager& mgr) {
|
||||
for (CEntity* ent : mgr.GetAllObjectList()) {
|
||||
TCastToPtr<CScriptTrigger> trig = ent;
|
||||
if (trig && (trig->GetTriggerFlags() & ETriggerFlags::BlockEnvironmentalEffects) != ETriggerFlags::None) {
|
||||
if (trig && True(trig->GetTriggerFlags() & ETriggerFlags::BlockEnvironmentalEffects)) {
|
||||
list.push_back(ent->GetUniqueId());
|
||||
} else if (TCastToPtr<CScriptWater> water = ent) {
|
||||
list.push_back(ent->GetUniqueId());
|
||||
|
|
|
@ -98,7 +98,7 @@ class CEnvFxManager {
|
|||
// bool x3c_snowflakeTextureMipBlanked = false; /* Shader simulates this texture mod */
|
||||
TLockedToken<CTexture> x40_txtrEnvGradient;
|
||||
rstl::reserved_vector<CEnvFxManagerGrid, 64> x50_grids;
|
||||
float xb54_baseSplashRate;
|
||||
float xb54_baseSplashRate = 0.f;
|
||||
TLockedToken<CGenDescription> xb58_envRainSplash;
|
||||
bool xb64_ = true;
|
||||
TUniqueId xb68_envRainSplashId = kInvalidUniqueId;
|
||||
|
|
|
@ -1,26 +1,678 @@
|
|||
#include "CFishCloud.hpp"
|
||||
#include "CActorParameters.hpp"
|
||||
#include "TCastTo.hpp"
|
||||
#include "GameGlobalObjects.hpp"
|
||||
#include "CSimplePool.hpp"
|
||||
#include "Weapon/CWeapon.hpp"
|
||||
#include "CStateManager.hpp"
|
||||
#include "World/CWorld.hpp"
|
||||
#include "World/CPlayer.hpp"
|
||||
#include "Graphics/CVertexMorphEffect.hpp"
|
||||
#include "Graphics/CSkinnedModel.hpp"
|
||||
#include "Graphics/CBooRenderer.hpp"
|
||||
|
||||
namespace urde {
|
||||
|
||||
CFishCloud::CFishCloud(TUniqueId uid, bool active, std::string_view name, const CEntityInfo& info,
|
||||
const zeus::CVector3f& scale, const zeus::CTransform& xf, CModelData&& mData,
|
||||
const CAnimRes& aRes, u32 w1, float f1, float f2, float f3, float f4, float f5, float f6,
|
||||
float f7, float f8, float f9, float f10, float f11, float f12, float f13, u32 w2,
|
||||
const zeus::CColor& color, bool b1, float f14, CAssetId part1, u32 w3, CAssetId part2, u32 w4,
|
||||
CAssetId part3, u32 w5, CAssetId part4, u32 w6, u32 w7, bool b2, bool b3)
|
||||
: CActor(uid, active, name, info, xf, std::move(mData), {EMaterialTypes::NoStepLogic}, CActorParameters::None(),
|
||||
kInvalidUniqueId) {}
|
||||
const CAnimRes& aRes, u32 numBoids, float speed, float separationRadius, float cohesionMagnitude,
|
||||
float alignmentWeight, float separationMagnitude, float weaponRepelMagnitude,
|
||||
float playerRepelMagnitude, float containmentMagnitude, float scatterVel, float maxScatterAngle,
|
||||
float weaponRepelDampingSpeed, float playerRepelDampingSpeed, float containmentRadius,
|
||||
u32 updateShift, const zeus::CColor& color, bool killable, float weaponKillRadius,
|
||||
CAssetId part1, u32 partCount1, CAssetId part2, u32 partCount2, CAssetId part3, u32 partCount3,
|
||||
CAssetId part4, u32 partCount4, u32 deathSfx, bool repelFromThreats, bool hotInThermal)
|
||||
: CActor(uid, active, name, info, xf, std::move(mData), {EMaterialTypes::NoStepLogic},
|
||||
CActorParameters::None().HotInThermal(hotInThermal), kInvalidUniqueId)
|
||||
, x11c_updateMask(u32((1 << updateShift) - 1))
|
||||
, x120_scale(scale)
|
||||
, x130_speed(speed)
|
||||
, x134_numBoids(numBoids)
|
||||
, x138_separationRadius(separationRadius)
|
||||
, x13c_cohesionMagnitude(cohesionMagnitude)
|
||||
, x140_alignmentWeight(alignmentWeight)
|
||||
, x144_separationMagnitude(separationMagnitude)
|
||||
, x148_weaponRepelMagnitude(weaponRepelMagnitude)
|
||||
, x14c_playerRepelMagnitude(playerRepelMagnitude)
|
||||
, x150_scatterVel(scatterVel)
|
||||
, x154_maxScatterAngle(maxScatterAngle)
|
||||
, x158_containmentMagnitude(containmentMagnitude)
|
||||
, x15c_playerRepelDampingSpeed(playerRepelDampingSpeed)
|
||||
, x160_weaponRepelDampingSpeed(weaponRepelDampingSpeed)
|
||||
, x164_playerRepelDamping(playerRepelDampingSpeed)
|
||||
, x168_weaponRepelDamping(weaponRepelDampingSpeed)
|
||||
, x16c_color(color)
|
||||
, x170_weaponKillRadius(weaponKillRadius)
|
||||
, x174_containmentRadius(containmentRadius)
|
||||
, x234_deathSfx(deathSfx != 0xffffffff ? CSfxManager::TranslateSFXID(u16(deathSfx & 0xffff)) : u16(0xffff)) {
|
||||
x250_28_killable = killable;
|
||||
x250_29_repelFromThreats = repelFromThreats;
|
||||
x108_modifierSources.reserve(10);
|
||||
x250_25_worldSpace = true; // The result of a close_enough paradox (weird inlined test?)
|
||||
if (aRes.GetId().IsValid()) {
|
||||
x1b0_models.emplace_back(new CModelData(aRes));
|
||||
x1b0_models.emplace_back(new CModelData(aRes));
|
||||
x1b0_models.emplace_back(new CModelData(aRes));
|
||||
x1b0_models.emplace_back(new CModelData(aRes));
|
||||
x250_27_validModel = true;
|
||||
}
|
||||
if (part1.IsValid())
|
||||
x1c4_particleDescs.push_back(g_SimplePool->GetObj({FOURCC('PART'), part1}));
|
||||
if (part2.IsValid())
|
||||
x1c4_particleDescs.push_back(g_SimplePool->GetObj({FOURCC('PART'), part2}));
|
||||
if (part3.IsValid())
|
||||
x1c4_particleDescs.push_back(g_SimplePool->GetObj({FOURCC('PART'), part3}));
|
||||
if (part4.IsValid())
|
||||
x1c4_particleDescs.push_back(g_SimplePool->GetObj({FOURCC('PART'), part4}));
|
||||
for (const auto& p : x1c4_particleDescs) {
|
||||
x1f8_particleGens.emplace_back(new CElementGen(p));
|
||||
x1f8_particleGens.back()->SetParticleEmission(false);
|
||||
}
|
||||
x21c_deathParticleCounts.push_back(partCount1);
|
||||
x21c_deathParticleCounts.push_back(partCount2);
|
||||
x21c_deathParticleCounts.push_back(partCount3);
|
||||
x21c_deathParticleCounts.push_back(partCount4);
|
||||
zeus::CAABox aabb = GetBoundingBox();
|
||||
x238_partitionPitch = (aabb.max - aabb.min) / 7.f;
|
||||
x244_ooPartitionPitch = 1.f / x238_partitionPitch;
|
||||
}
|
||||
|
||||
void CFishCloud::Accept(IVisitor& visitor) { visitor.Visit(this); }
|
||||
|
||||
void CFishCloud::RemoveRepulsor(TUniqueId) {}
|
||||
void CFishCloud::UpdateParticles(float dt) {
|
||||
for (auto& p : x1f8_particleGens)
|
||||
p->Update(dt);
|
||||
}
|
||||
|
||||
void CFishCloud::RemoveAttractor(TUniqueId) {}
|
||||
void CFishCloud::UpdatePartitionList() {
|
||||
xf8_boidPartitionLists.clear();
|
||||
xf8_boidPartitionLists.resize(xf8_boidPartitionLists.capacity());
|
||||
auto aabb = GetBoundingBox();
|
||||
for (auto& b : xe8_boids) {
|
||||
zeus::CVector3f idxs = (b.x0_pos - aabb.min) * x244_ooPartitionPitch;
|
||||
int idx = int(idxs.x()) + int(idxs.y()) * 7 + int(idxs.z()) * 49;
|
||||
if (idx >= 0 && idx < 343) {
|
||||
b.x1c_next = xf8_boidPartitionLists[idx];
|
||||
xf8_boidPartitionLists[idx] = &b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CFishCloud::AddRepulsor(TUniqueId, float, float) {}
|
||||
bool CFishCloud::PointInBox(const zeus::CAABox& aabb, const zeus::CVector3f& point) const {
|
||||
if (!x250_25_worldSpace)
|
||||
return aabb.pointInside(point);
|
||||
return GetUntransformedBoundingBox().pointInside(GetTransform().transposeRotate(point - GetTranslation()));
|
||||
}
|
||||
|
||||
void CFishCloud::AddAttractor(TUniqueId, float, float) {}
|
||||
zeus::CPlane CFishCloud::FindClosestPlane(const zeus::CAABox& aabb, const zeus::CVector3f& point) const {
|
||||
if (!x250_25_worldSpace) {
|
||||
float minDist = FLT_MAX;
|
||||
zeus::CAABox::EBoxFaceId minFace = zeus::CAABox::EBoxFaceId::YMin;
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
auto tri = aabb.getTri(zeus::CAABox::EBoxFaceId(i), 0);
|
||||
float dist = zeus::CPlane(tri.x10_[0], tri.x10_[2], tri.x10_[1]).pointToPlaneDist(point);
|
||||
if (dist >= 0.f && dist < minDist) {
|
||||
minDist = dist;
|
||||
minFace = zeus::CAABox::EBoxFaceId(i);
|
||||
}
|
||||
}
|
||||
auto tri = aabb.getTri(minFace, 0);
|
||||
return zeus::CPlane(tri.x10_[0], tri.x10_[2], tri.x10_[1]);
|
||||
} else {
|
||||
auto unPoint = GetTransform().transposeRotate(point - GetTranslation());
|
||||
auto unAabb = GetUntransformedBoundingBox();
|
||||
float minDist = FLT_MAX;
|
||||
zeus::CAABox::EBoxFaceId minFace = zeus::CAABox::EBoxFaceId::YMin;
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
auto tri = unAabb.getTri(zeus::CAABox::EBoxFaceId(i), 0);
|
||||
float dist = zeus::CPlane(tri.x10_[0], tri.x10_[2], tri.x10_[1]).pointToPlaneDist(unPoint);
|
||||
if (dist >= 0.f && dist < minDist) {
|
||||
minDist = dist;
|
||||
minFace = zeus::CAABox::EBoxFaceId(i);
|
||||
}
|
||||
}
|
||||
auto tri = unAabb.getTri(minFace, 0);
|
||||
return zeus::CPlane(GetTransform() * tri.x10_[0], GetTransform() * tri.x10_[2], GetTransform() * tri.x10_[1]);
|
||||
}
|
||||
}
|
||||
|
||||
CFishCloud::CBoid* CFishCloud::GetListAt(const zeus::CVector3f& pos) {
|
||||
zeus::CAABox aabb = GetBoundingBox();
|
||||
zeus::CVector3f ints = (pos - aabb.min) * x244_ooPartitionPitch;
|
||||
int idx = int(ints.x()) + int(ints.y()) * 7 + int(ints.z()) * 49;
|
||||
if (idx < 0 || idx >= 343)
|
||||
return nullptr;
|
||||
return xf8_boidPartitionLists[idx];
|
||||
}
|
||||
|
||||
void CFishCloud::BuildBoidNearList(const zeus::CVector3f& pos, float radius,
|
||||
rstl::reserved_vector<CBoid*, 25>& nearList) {
|
||||
float radiusSq = radius * radius;
|
||||
CBoid* b = GetListAt(pos);
|
||||
while (b && nearList.size() < 25) {
|
||||
if (b->x20_active) {
|
||||
float distSq = (b->GetTranslation() - pos).magSquared();
|
||||
if (distSq != 0.f && distSq < radiusSq)
|
||||
nearList.push_back(b);
|
||||
}
|
||||
b = b->x1c_next;
|
||||
}
|
||||
}
|
||||
|
||||
void CFishCloud::BuildBoidNearPartitionList(const zeus::CVector3f& pos, float radius,
|
||||
rstl::reserved_vector<CBoid*, 25>& nearList) {
|
||||
float radiusSq = radius * radius;
|
||||
zeus::CAABox aabb = GetBoundingBox();
|
||||
float x = std::max(radius * x244_ooPartitionPitch.x(), float(x238_partitionPitch.x()));
|
||||
float y = std::max(radius * x244_ooPartitionPitch.y(), float(x238_partitionPitch.y()));
|
||||
float z = std::max(radius * x244_ooPartitionPitch.z(), float(x238_partitionPitch.z()));
|
||||
float nx = 0.01f - x;
|
||||
float ny = 0.01f - y;
|
||||
float nz = 0.01f - z;
|
||||
for (float lnx = nx; lnx < x; lnx += x238_partitionPitch.x()) {
|
||||
float cx = lnx + pos.x();
|
||||
if (cx < aabb.min.x())
|
||||
continue;
|
||||
if (cx >= aabb.max.x())
|
||||
break;
|
||||
for (float lny = ny; lny < y; lny += x238_partitionPitch.y()) {
|
||||
float cy = lny + pos.y();
|
||||
if (cy < aabb.min.y())
|
||||
continue;
|
||||
if (cy >= aabb.max.y())
|
||||
break;
|
||||
for (float lnz = nz; lnz < z; lnz += x238_partitionPitch.z()) {
|
||||
float cz = lnz + pos.z();
|
||||
if (cz < aabb.min.z())
|
||||
continue;
|
||||
if (cz >= aabb.max.z())
|
||||
break;
|
||||
zeus::CVector3f ints = (zeus::CVector3f(cx, cy, cz) - aabb.min) * x244_ooPartitionPitch;
|
||||
int idx = int(ints.x()) + int(ints.y()) * 7 + int(ints.z()) * 49;
|
||||
if (idx < 0)
|
||||
continue;
|
||||
if (idx < 343) {
|
||||
CBoid* boid = xf8_boidPartitionLists[idx];
|
||||
while (boid) {
|
||||
if (boid->x20_active) {
|
||||
float distSq = (boid->x0_pos - pos).magSquared();
|
||||
if (distSq != 0.f && distSq < radiusSq) {
|
||||
nearList.push_back(boid);
|
||||
if (nearList.size() == 25)
|
||||
return;
|
||||
}
|
||||
}
|
||||
boid = boid->x1c_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CFishCloud::PlaceBoid(CStateManager& mgr, CBoid& boid, const zeus::CAABox& aabb) {
|
||||
auto plane = FindClosestPlane(aabb, boid.x0_pos);
|
||||
boid.x0_pos -= plane.pointToPlaneDist(boid.x0_pos) * plane.normal() + 0.0001f * plane.normal();
|
||||
boid.xc_vel.y() = mgr.GetActiveRandom()->Float() - 0.5f;
|
||||
boid.xc_vel.x() = mgr.GetActiveRandom()->Float() - 0.5f;
|
||||
boid.xc_vel.z() = 0.f;
|
||||
if (!x250_25_worldSpace) {
|
||||
if (!aabb.pointInside(boid.x0_pos)) {
|
||||
boid.x0_pos.z() = mgr.GetActiveRandom()->Float() * (aabb.max.z() - aabb.min.z()) + aabb.min.z();
|
||||
boid.x0_pos.y() = mgr.GetActiveRandom()->Float() * (aabb.max.y() - aabb.min.y()) + aabb.min.y();
|
||||
boid.x0_pos.x() = mgr.GetActiveRandom()->Float() * (aabb.max.x() - aabb.min.x()) + aabb.min.x();
|
||||
}
|
||||
} else {
|
||||
if (!PointInBox(aabb, boid.x0_pos)) {
|
||||
auto unAabb = GetUntransformedBoundingBox();
|
||||
boid.x0_pos.z() = mgr.GetActiveRandom()->Float() * (unAabb.max.z() - unAabb.min.z()) + unAabb.min.z();
|
||||
boid.x0_pos.y() = mgr.GetActiveRandom()->Float() * (unAabb.max.y() - unAabb.min.y()) + unAabb.min.y();
|
||||
boid.x0_pos.x() = mgr.GetActiveRandom()->Float() * (unAabb.max.x() - unAabb.min.x()) + unAabb.min.x();
|
||||
boid.x0_pos = GetTransform() * boid.x0_pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CFishCloud::ApplySeparation(CBoid& boid, const rstl::reserved_vector<CBoid*, 25>& nearList) const {
|
||||
if (nearList.empty())
|
||||
return;
|
||||
float minDist = FLT_MAX;
|
||||
zeus::CVector3f pos;
|
||||
for (CBoid* b : nearList) {
|
||||
float dist = (boid.GetTranslation() - b->GetTranslation()).magSquared();
|
||||
if (dist < minDist) {
|
||||
minDist = dist;
|
||||
pos = b->GetTranslation();
|
||||
}
|
||||
}
|
||||
ApplySeparation(boid, pos, x138_separationRadius, x144_separationMagnitude);
|
||||
}
|
||||
|
||||
void CFishCloud::ApplySeparation(CBoid& boid, const zeus::CVector3f& separateFrom,
|
||||
float separationRadius, float separationMagnitude) const {
|
||||
zeus::CVector3f delta = boid.GetTranslation() - separateFrom;
|
||||
if (delta.canBeNormalized()) {
|
||||
float deltaDistSq = delta.magSquared();
|
||||
float capDeltaDistSq = separationRadius * separationRadius;
|
||||
if (deltaDistSq < capDeltaDistSq)
|
||||
boid.xc_vel += (1.f - deltaDistSq / capDeltaDistSq) * delta.normalized() * separationMagnitude;
|
||||
}
|
||||
}
|
||||
|
||||
void CFishCloud::ApplyCohesion(CBoid& boid, const rstl::reserved_vector<CBoid*, 25>& nearList) const {
|
||||
if (nearList.empty())
|
||||
return;
|
||||
zeus::CVector3f avg;
|
||||
for (CBoid* b : nearList)
|
||||
avg += b->GetTranslation();
|
||||
avg = avg / float(nearList.size());
|
||||
ApplyCohesion(boid, avg, x138_separationRadius, x13c_cohesionMagnitude);
|
||||
}
|
||||
|
||||
void CFishCloud::ApplyCohesion(CBoid& boid, const zeus::CVector3f& cohesionFrom,
|
||||
float cohesionRadius, float cohesionMagnitude) const {
|
||||
zeus::CVector3f delta = cohesionFrom - boid.GetTranslation();
|
||||
if (delta.canBeNormalized()) {
|
||||
float distSq = delta.magSquared();
|
||||
float capDistSq = cohesionRadius * cohesionRadius;
|
||||
boid.xc_vel += ((distSq > capDistSq) ? 1.f : distSq / capDistSq) * delta.normalized() * cohesionMagnitude;
|
||||
}
|
||||
}
|
||||
|
||||
void CFishCloud::ApplyAlignment(CBoid& boid, const rstl::reserved_vector<CBoid*, 25>& nearList) const {
|
||||
if (nearList.empty())
|
||||
return;
|
||||
zeus::CVector3f avg;
|
||||
for (CBoid* b : nearList)
|
||||
avg += b->xc_vel;
|
||||
avg = avg / float(nearList.size());
|
||||
boid.xc_vel += zeus::CVector3f::getAngleDiff(boid.xc_vel, avg) / M_PIF *
|
||||
(avg * x140_alignmentWeight);
|
||||
}
|
||||
|
||||
void CFishCloud::ApplyAttraction(CBoid& boid, const zeus::CVector3f& attractTo,
|
||||
float attractionRadius, float attractionMagnitude) const {
|
||||
zeus::CVector3f delta = attractTo - boid.GetTranslation();
|
||||
if (delta.canBeNormalized()) {
|
||||
float distSq = delta.magSquared();
|
||||
float capDistSq = attractionRadius * attractionRadius;
|
||||
boid.xc_vel += ((distSq > capDistSq) ? 0.f : (1.f - distSq / capDistSq)) * delta.normalized() * attractionMagnitude;
|
||||
}
|
||||
}
|
||||
|
||||
void CFishCloud::ApplyRepulsion(CBoid& boid, const zeus::CVector3f& attractTo,
|
||||
float repulsionRadius, float repulsionMagnitude) const {
|
||||
ApplySeparation(boid, attractTo, repulsionRadius, repulsionMagnitude);
|
||||
}
|
||||
|
||||
void CFishCloud::ApplySwirl(CBoid& boid, const zeus::CVector3f& swirlPoint, bool clockwise,
|
||||
float magnitude, float radius) const {
|
||||
zeus::CVector3f delta = boid.x0_pos - swirlPoint;
|
||||
float deltaMag = delta.magnitude();
|
||||
zeus::CVector3f alignVec;
|
||||
if (clockwise)
|
||||
alignVec = delta.normalized().cross(zeus::skUp);
|
||||
else
|
||||
alignVec = zeus::skUp.cross(delta / deltaMag);
|
||||
float weight = deltaMag > radius ? 0.f : 1.f - deltaMag / radius;
|
||||
boid.xc_vel += zeus::CVector3f::getAngleDiff(boid.xc_vel, alignVec) / M_PIF *
|
||||
weight * (magnitude * alignVec);
|
||||
}
|
||||
|
||||
void CFishCloud::ApplyContainment(CBoid& boid, const zeus::CAABox& aabb) const {
|
||||
if (boid.xc_vel.canBeNormalized()) {
|
||||
if (!PointInBox(aabb, boid.xc_vel.normalized() * x130_speed * x174_containmentRadius + boid.x0_pos)) {
|
||||
ApplyAttraction(boid, aabb.center(), 100000.f, x158_containmentMagnitude);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CFishCloud::ScatterBoid(CStateManager& mgr, CBoid& b) const {
|
||||
float angle = (mgr.GetActiveRandom()->Float() - 0.5f) * M_PIF * x154_maxScatterAngle;
|
||||
float cosAngle = std::cos(angle);
|
||||
float sinAngle = std::sin(angle);
|
||||
b.xc_vel.x() += x150_scatterVel * (b.xc_vel.y() * sinAngle + b.xc_vel.x() * cosAngle);
|
||||
b.xc_vel.y() += x150_scatterVel * (b.xc_vel.y() * cosAngle + b.xc_vel.x() * sinAngle);
|
||||
}
|
||||
|
||||
void CFishCloud::Think(float dt, CStateManager& mgr) {
|
||||
if (!GetActive())
|
||||
return;
|
||||
const CGameArea* area = mgr.GetWorld()->GetAreaAlways(x4_areaId);
|
||||
auto occState = area->IsPostConstructed() ? area->GetOcclusionState() : CGameArea::EOcclusionState::Occluded;
|
||||
if (occState == CGameArea::EOcclusionState::Visible) {
|
||||
x168_weaponRepelDamping = std::max(0.f, x168_weaponRepelDamping - x160_weaponRepelDampingSpeed * dt * 0.1f);
|
||||
if (x250_26_enableWeaponRepelDamping)
|
||||
x168_weaponRepelDamping = std::min(x160_weaponRepelDampingSpeed * dt + x168_weaponRepelDamping,
|
||||
x148_weaponRepelMagnitude);
|
||||
x164_playerRepelDamping = std::max(0.f, x164_playerRepelDamping - x15c_playerRepelDampingSpeed * dt * 0.1f);
|
||||
if (x250_30_enablePlayerRepelDamping)
|
||||
x164_playerRepelDamping = std::min(x15c_playerRepelDampingSpeed * dt + x164_playerRepelDamping,
|
||||
x14c_playerRepelMagnitude);
|
||||
x250_26_enableWeaponRepelDamping = false;
|
||||
x250_30_enablePlayerRepelDamping = false;
|
||||
++x118_thinkCounter;
|
||||
UpdateParticles(dt);
|
||||
UpdatePartitionList();
|
||||
zeus::CAABox aabb = GetBoundingBox();
|
||||
int idx = 0;
|
||||
for (auto& b : xe8_boids) {
|
||||
if (b.x20_active && (idx & x11c_updateMask) == (x118_thinkCounter & x11c_updateMask)) {
|
||||
rstl::reserved_vector<CBoid*, 25> nearList;
|
||||
if (x250_31_updateWithoutPartitions)
|
||||
BuildBoidNearList(b.x0_pos, x138_separationRadius, nearList);
|
||||
else
|
||||
BuildBoidNearPartitionList(b.x0_pos, x138_separationRadius, nearList);
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
switch (i) {
|
||||
case 1:
|
||||
ApplySeparation(b, nearList);
|
||||
break;
|
||||
case 2:
|
||||
if (!x250_24_randomMovement || mgr.GetActiveRandom()->Float() > x12c_randomMovementTimer)
|
||||
ApplyCohesion(b, nearList);
|
||||
break;
|
||||
case 3:
|
||||
if (!x250_24_randomMovement || mgr.GetActiveRandom()->Float() > x12c_randomMovementTimer)
|
||||
ApplyAlignment(b, nearList);
|
||||
break;
|
||||
case 4:
|
||||
ScatterBoid(mgr, b);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (b.xc_vel.magSquared() > 3.2f)
|
||||
break;
|
||||
}
|
||||
if (!x250_24_randomMovement && b.xc_vel.magSquared() < 3.2f) {
|
||||
for (auto& m : x108_modifierSources) {
|
||||
if (TCastToPtr<CActor> act = mgr.ObjectById(m.x0_source)) {
|
||||
if (m.xd_isSwirl) {
|
||||
ApplySwirl(b, act->GetTranslation(), m.xc_isRepulsor, m.x8_priority, m.x4_radius);
|
||||
} else if (m.xc_isRepulsor) {
|
||||
ApplyRepulsion(b, act->GetTranslation(), m.x4_radius, m.x8_priority);
|
||||
} else {
|
||||
ApplyAttraction(b, act->GetTranslation(), m.x4_radius, m.x8_priority);
|
||||
}
|
||||
} else {
|
||||
if (m.xc_isRepulsor)
|
||||
RemoveRepulsor(m.x0_source);
|
||||
else
|
||||
RemoveAttractor(m.x0_source);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
++idx;
|
||||
}
|
||||
for (auto& b : xe8_boids) {
|
||||
if (b.x20_active) {
|
||||
ApplyContainment(b, aabb);
|
||||
float velMag = b.xc_vel.magnitude();
|
||||
if (!zeus::close_enough(velMag, 0.f))
|
||||
b.xc_vel = b.xc_vel / velMag;
|
||||
b.xc_vel.z() *= 0.99f;
|
||||
}
|
||||
}
|
||||
if (x12c_randomMovementTimer > 0.f) {
|
||||
x12c_randomMovementTimer -= dt;
|
||||
} else {
|
||||
x12c_randomMovementTimer = 0.f;
|
||||
x250_24_randomMovement = false;
|
||||
}
|
||||
for (auto& b : xe8_boids) {
|
||||
if (b.x20_active) {
|
||||
b.x0_pos += b.xc_vel * dt * x130_speed;
|
||||
if (!PointInBox(aabb, b.x0_pos))
|
||||
PlaceBoid(mgr, b, aabb);
|
||||
}
|
||||
}
|
||||
if (x250_27_validModel) {
|
||||
for (auto& m : x1b0_models) {
|
||||
m->AnimationData()->SetPlaybackRate(1.f);
|
||||
m->AdvanceAnimation(dt, mgr, x4_areaId, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CFishCloud::CreatePartitionList() {
|
||||
xf8_boidPartitionLists.reserve(343);
|
||||
}
|
||||
|
||||
void CFishCloud::AllocateSkinnedModels(CStateManager& mgr, CModelData::EWhichModel which) {
|
||||
int idx = 0;
|
||||
for (auto& m : x1b0_models) {
|
||||
m->EnableLooping(true);
|
||||
m->AdvanceAnimation(
|
||||
m->AnimationData()->GetAnimTimeRemaining("Whole Body"sv) * 0.25f * idx, mgr, x4_areaId, true);
|
||||
++idx;
|
||||
}
|
||||
x230_whichModel = which;
|
||||
}
|
||||
|
||||
void CFishCloud::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr) {
|
||||
CActor::AcceptScriptMsg(msg, sender, mgr);
|
||||
switch (msg) {
|
||||
case EScriptObjectMessage::Registered: {
|
||||
xe8_boids.reserve(x134_numBoids);
|
||||
zeus::CAABox aabb = GetUntransformedBoundingBox();
|
||||
zeus::CVector3f extent = aabb.max - aabb.min;
|
||||
zeus::CVector3f randPoint;
|
||||
for (int i = 0; i < x134_numBoids; ++i) {
|
||||
randPoint.z() = mgr.GetActiveRandom()->Float() * extent.z() + aabb.min.z();
|
||||
randPoint.y() = mgr.GetActiveRandom()->Float() * extent.y() + aabb.min.y();
|
||||
randPoint.x() = mgr.GetActiveRandom()->Float() * extent.x() + aabb.min.x();
|
||||
zeus::CVector3f vel;
|
||||
vel.y() = mgr.GetActiveRandom()->Float() - 0.5f;
|
||||
vel.x() = mgr.GetActiveRandom()->Float() - 0.5f;
|
||||
xe8_boids.emplace_back(x34_transform * randPoint, vel,
|
||||
0.2f * std::pow(mgr.GetActiveRandom()->Float(), 7.f) + 0.9f);
|
||||
}
|
||||
CreatePartitionList();
|
||||
if (x250_27_validModel)
|
||||
AllocateSkinnedModels(mgr, CModelData::EWhichModel::Normal);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CFishCloud::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) {
|
||||
CActor::PreRender(mgr, frustum);
|
||||
if (x250_27_validModel) {
|
||||
for (auto& m : x1b0_models) {
|
||||
m->AnimationData()->PreRender();
|
||||
}
|
||||
}
|
||||
xe4_30_outOfFrustum = false;
|
||||
}
|
||||
|
||||
void CFishCloud::AddParticlesToRenderer() const {
|
||||
for (const auto& p : x1f8_particleGens)
|
||||
g_Renderer->AddParticleGen(*p);
|
||||
}
|
||||
|
||||
void CFishCloud::RenderBoid(int idx, const CBoid& boid, u32& drawMask,
|
||||
bool thermalHot, const CModelFlags& flags) const {
|
||||
u32 modelIndex = idx & 0x3;
|
||||
CModelData& mData = *x1b0_models[modelIndex];
|
||||
CSkinnedModel& model = mData.PickAnimatedModel(CModelData::EWhichModel::Normal);
|
||||
if (!model.GetModelInst()->TryLockTextures())
|
||||
return;
|
||||
u32 thisDrawMask = 1u << modelIndex;
|
||||
if (drawMask & thisDrawMask) {
|
||||
drawMask &= ~thisDrawMask;
|
||||
mData.AnimationData()->BuildPose();
|
||||
}
|
||||
model.GetModelInst()->SetAmbientColor(zeus::skWhite);
|
||||
CGraphics::SetModelMatrix(zeus::lookAt(boid.x0_pos, boid.x0_pos + boid.xc_vel));
|
||||
if (thermalHot) {
|
||||
CModelFlags thermFlags(0, 0, 3, zeus::skWhite);
|
||||
mData.RenderThermal(zeus::skWhite, zeus::CColor(0.f, 0.25f), thermFlags);
|
||||
} else {
|
||||
mData.AnimationData()->Render(model, flags, {}, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void CFishCloud::Render(const CStateManager& mgr) const {
|
||||
if (!GetActive())
|
||||
return;
|
||||
bool thermalHot = mgr.GetThermalDrawFlag() == EThermalDrawFlag::Hot;
|
||||
CModelFlags flags(0, 0, 3, zeus::skWhite);
|
||||
if (mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::XRay)
|
||||
flags = CModelFlags(5, 0, 3, x16c_color);
|
||||
else
|
||||
flags = CModelFlags(1, 0, 3, x16c_color);
|
||||
AddParticlesToRenderer();
|
||||
if (x250_27_validModel) {
|
||||
// Ambient white
|
||||
int idx = 0;
|
||||
u32 drawMask = 0xffffffff;
|
||||
for (const auto& b : xe8_boids) {
|
||||
if (b.x20_active)
|
||||
RenderBoid(idx, b, drawMask, thermalHot, flags);
|
||||
++idx;
|
||||
}
|
||||
} else {
|
||||
CGraphics::SetModelMatrix(zeus::CTransform());
|
||||
for (const auto& b : xe8_boids) {
|
||||
if (b.x20_active) {
|
||||
x64_modelData->SetScale(zeus::CVector3f(b.x18_scale));
|
||||
x64_modelData->Render(mgr, zeus::lookAt(b.x0_pos, b.x0_pos + b.xc_vel), nullptr, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CFishCloud::CalculateRenderBounds() {
|
||||
x9c_renderBounds = GetBoundingBox();
|
||||
}
|
||||
|
||||
rstl::optional<zeus::CAABox> CFishCloud::GetTouchBounds() const {
|
||||
return {GetBoundingBox()};
|
||||
}
|
||||
|
||||
void CFishCloud::CreateBoidDeathParticle(CBoid& b) const {
|
||||
auto it = x21c_deathParticleCounts.begin();
|
||||
for (auto& p : x1f8_particleGens) {
|
||||
p->SetParticleEmission(true);
|
||||
p->SetTranslation(b.x0_pos);
|
||||
p->ForceParticleCreation(*it);
|
||||
p->SetParticleEmission(false);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void CFishCloud::KillBoid(CBoid& b) const {
|
||||
b.x20_active = false;
|
||||
CreateBoidDeathParticle(b);
|
||||
CAudioSys::C3DEmitterParmData parmData = {};
|
||||
parmData.x0_pos = b.x0_pos;
|
||||
parmData.x18_maxDist = 250.f;
|
||||
parmData.x1c_distComp = 0.1f;
|
||||
parmData.x20_flags = 0x1;
|
||||
parmData.x24_sfxId = x234_deathSfx;
|
||||
parmData.x26_maxVol = 1.f;
|
||||
parmData.x27_minVol = 0.157f;
|
||||
parmData.x29_prio = 0x7f;
|
||||
CSfxManager::AddEmitter(parmData, true, 0x7f, false, x4_areaId);
|
||||
}
|
||||
|
||||
void CFishCloud::Touch(CActor& other, CStateManager& mgr) {
|
||||
CActor::Touch(other, mgr);
|
||||
if (TCastToPtr<CWeapon> weap = other) {
|
||||
if (!x250_26_enableWeaponRepelDamping && x250_29_repelFromThreats) {
|
||||
int idx = 0;
|
||||
for (auto& b : xe8_boids) {
|
||||
if ((idx & 0x3) == (x118_thinkCounter & 0x3))
|
||||
ApplyRepulsion(b, weap->GetTranslation(), 8.f, x148_weaponRepelMagnitude - x168_weaponRepelDamping);
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
x250_26_enableWeaponRepelDamping = true;
|
||||
if (x250_28_killable) {
|
||||
if (auto tb = weap->GetTouchBounds()) {
|
||||
for (auto& b : xe8_boids) {
|
||||
if (b.x20_active &&
|
||||
tb->intersects(zeus::CAABox(weap->GetTranslation() - x170_weaponKillRadius,
|
||||
weap->GetTranslation() + x170_weaponKillRadius)))
|
||||
KillBoid(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (x250_29_repelFromThreats) {
|
||||
if (TCastToPtr<CPlayer> player = other) {
|
||||
zeus::CVector3f playerPos = player->GetTranslation();
|
||||
for (auto& b : xe8_boids) {
|
||||
zeus::CVector3f adjPlayerPos = playerPos;
|
||||
float zDelta = b.x0_pos.z() - adjPlayerPos.z();
|
||||
if (zDelta > 0.f && zDelta < 2.3f)
|
||||
adjPlayerPos.z() = float(b.x0_pos.z());
|
||||
adjPlayerPos.x() += mgr.GetActiveRandom()->Float() * 0.2f - 0.1f;
|
||||
adjPlayerPos.y() += mgr.GetActiveRandom()->Float() * 0.2f - 0.1f;
|
||||
ApplyRepulsion(b, adjPlayerPos, 8.f, x14c_playerRepelMagnitude - x164_playerRepelDamping);
|
||||
}
|
||||
}
|
||||
x250_30_enablePlayerRepelDamping = true;
|
||||
}
|
||||
}
|
||||
|
||||
zeus::CAABox CFishCloud::GetUntransformedBoundingBox() const {
|
||||
zeus::CVector3f extent = x120_scale * 0.75f;
|
||||
return zeus::CAABox(-extent, extent);
|
||||
}
|
||||
|
||||
zeus::CAABox CFishCloud::GetBoundingBox() const {
|
||||
return GetUntransformedBoundingBox().getTransformedAABox(x34_transform);
|
||||
}
|
||||
|
||||
void CFishCloud::RemoveRepulsor(TUniqueId sourceId) {
|
||||
CModifierSource source(sourceId, true, false, 0.f, 0.f);
|
||||
auto it = rstl::binary_find(x108_modifierSources.begin(), x108_modifierSources.end(), source);
|
||||
if (it != x108_modifierSources.end())
|
||||
x108_modifierSources.erase(it);
|
||||
}
|
||||
|
||||
void CFishCloud::RemoveAttractor(TUniqueId sourceId) {
|
||||
CModifierSource source(sourceId, false, false, 0.f, 0.f);
|
||||
auto it = rstl::binary_find(x108_modifierSources.begin(), x108_modifierSources.end(), source);
|
||||
if (it != x108_modifierSources.end())
|
||||
x108_modifierSources.erase(it);
|
||||
}
|
||||
|
||||
bool CFishCloud::AddRepulsor(TUniqueId sourceId, bool swirl, float radius, float priority) {
|
||||
CModifierSource source(sourceId, true, swirl, radius, priority);
|
||||
auto it = rstl::binary_find(x108_modifierSources.begin(), x108_modifierSources.end(), source);
|
||||
if (it != x108_modifierSources.end()) {
|
||||
it->x4_radius = radius;
|
||||
it->x8_priority = priority;
|
||||
return true;
|
||||
} else if (x108_modifierSources.size() < x108_modifierSources.capacity()) {
|
||||
x108_modifierSources.insert(std::lower_bound(
|
||||
x108_modifierSources.begin(), x108_modifierSources.end(), source), source);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CFishCloud::AddAttractor(TUniqueId sourceId, bool swirl, float radius, float priority) {
|
||||
CModifierSource source(sourceId, false, swirl, radius, priority);
|
||||
auto it = rstl::binary_find(x108_modifierSources.begin(), x108_modifierSources.end(), source);
|
||||
if (it != x108_modifierSources.end()) {
|
||||
it->x4_radius = radius;
|
||||
it->x8_priority = priority;
|
||||
return true;
|
||||
} else if (x108_modifierSources.size() < x108_modifierSources.capacity()) {
|
||||
x108_modifierSources.insert(std::lower_bound(
|
||||
x108_modifierSources.begin(), x108_modifierSources.end(), source), source);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace urde
|
||||
|
|
|
@ -1,41 +1,152 @@
|
|||
#pragma once
|
||||
|
||||
#include "CActor.hpp"
|
||||
#include "Particle/CElementGen.hpp"
|
||||
|
||||
namespace urde {
|
||||
|
||||
class CFishCloud : public CActor {
|
||||
class CModifierSource {
|
||||
TUniqueId x0_source;
|
||||
float x4_;
|
||||
float x8_;
|
||||
bool xc_;
|
||||
bool xd_;
|
||||
|
||||
class CBoid {
|
||||
friend class CFishCloud;
|
||||
zeus::CVector3f x0_pos;
|
||||
zeus::CVector3f xc_vel;
|
||||
float x18_scale;
|
||||
CBoid* x1c_next = nullptr;
|
||||
bool x20_active = true;
|
||||
public:
|
||||
CModifierSource(TUniqueId, bool, float, float);
|
||||
void SetAffectPriority(float);
|
||||
void SetAffectRadius(float);
|
||||
float GetAffectPriority() const;
|
||||
float GetAffectRadius() const;
|
||||
bool IsRepulsor();
|
||||
TUniqueId GetSource() const;
|
||||
|
||||
bool operator<(const CModifierSource& other) const { return x0_source < other.x0_source; }
|
||||
CBoid(const zeus::CVector3f& pos, const zeus::CVector3f& vel, float scale)
|
||||
: x0_pos(pos), xc_vel(vel), x18_scale(scale) {}
|
||||
zeus::CVector3f& Translation() { return x0_pos; }
|
||||
const zeus::CVector3f& GetTranslation() const { return x0_pos; }
|
||||
};
|
||||
class CModifierSource {
|
||||
friend class CFishCloud;
|
||||
TUniqueId x0_source;
|
||||
float x4_radius;
|
||||
float x8_priority;
|
||||
bool xc_isRepulsor;
|
||||
bool xd_isSwirl;
|
||||
public:
|
||||
CModifierSource(TUniqueId source, bool repulsor, bool swirl, float radius, float priority)
|
||||
: x0_source(source), x4_radius(radius), x8_priority(priority), xc_isRepulsor(repulsor), xd_isSwirl(swirl) {}
|
||||
void SetAffectPriority(float p) { x8_priority = p; }
|
||||
void SetAffectRadius(float r) { x4_radius = r; }
|
||||
float GetAffectPriority() const { return x8_priority; }
|
||||
float GetAffectRadius() const { return x4_radius; }
|
||||
bool IsRepulsor() const { return xc_isRepulsor; }
|
||||
bool IsSwirl() const { return xd_isSwirl; }
|
||||
TUniqueId GetSource() const { return x0_source; }
|
||||
bool operator<(const CModifierSource& other) const {
|
||||
if (x0_source == other.x0_source)
|
||||
return xc_isRepulsor < other.xc_isRepulsor;
|
||||
return x0_source < other.x0_source;
|
||||
}
|
||||
};
|
||||
std::vector<CBoid> xe8_boids;
|
||||
std::vector<CBoid*> xf8_boidPartitionLists;
|
||||
std::vector<CModifierSource> x108_modifierSources;
|
||||
u32 x118_thinkCounter = 0;
|
||||
u32 x11c_updateMask;
|
||||
zeus::CVector3f x120_scale;
|
||||
float x12c_randomMovementTimer = 0.f;
|
||||
float x130_speed;
|
||||
u32 x134_numBoids;
|
||||
float x138_separationRadius;
|
||||
float x13c_cohesionMagnitude;
|
||||
float x140_alignmentWeight;
|
||||
float x144_separationMagnitude;
|
||||
float x148_weaponRepelMagnitude;
|
||||
float x14c_playerRepelMagnitude;
|
||||
float x150_scatterVel;
|
||||
float x154_maxScatterAngle;
|
||||
float x158_containmentMagnitude;
|
||||
float x15c_playerRepelDampingSpeed;
|
||||
float x160_weaponRepelDampingSpeed;
|
||||
float x164_playerRepelDamping;
|
||||
float x168_weaponRepelDamping;
|
||||
zeus::CColor x16c_color;
|
||||
float x170_weaponKillRadius;
|
||||
float x174_containmentRadius;
|
||||
/* Used to be position and normal arrays */
|
||||
//rstl::reserved_vector<std::unique_ptr<float[]>, 4> x178_;
|
||||
//rstl::reserved_vector<std::unique_ptr<float[]>, 4> x19c_;
|
||||
rstl::reserved_vector<std::shared_ptr<CModelData>, 4> x1b0_models;
|
||||
rstl::reserved_vector<TLockedToken<CGenDescription>, 4> x1c4_particleDescs;
|
||||
rstl::reserved_vector<std::unique_ptr<CElementGen>, 4> x1f8_particleGens;
|
||||
rstl::reserved_vector<u32, 4> x21c_deathParticleCounts;
|
||||
CModelData::EWhichModel x230_whichModel;
|
||||
u16 x234_deathSfx;
|
||||
zeus::CVector3f x238_partitionPitch;
|
||||
zeus::CVector3f x244_ooPartitionPitch;
|
||||
union {
|
||||
struct {
|
||||
bool x250_24_randomMovement : 1;
|
||||
bool x250_25_worldSpace : 1;
|
||||
bool x250_26_enableWeaponRepelDamping : 1;
|
||||
bool x250_27_validModel : 1;
|
||||
bool x250_28_killable : 1;
|
||||
bool x250_29_repelFromThreats : 1;
|
||||
bool x250_30_enablePlayerRepelDamping : 1;
|
||||
bool x250_31_updateWithoutPartitions : 1;
|
||||
};
|
||||
u32 _dummy = 0;
|
||||
};
|
||||
|
||||
void UpdateParticles(float dt);
|
||||
void UpdatePartitionList();
|
||||
bool PointInBox(const zeus::CAABox& aabb, const zeus::CVector3f& point) const;
|
||||
zeus::CPlane FindClosestPlane(const zeus::CAABox& aabb, const zeus::CVector3f& point) const;
|
||||
CBoid* GetListAt(const zeus::CVector3f& pos);
|
||||
void BuildBoidNearList(const zeus::CVector3f& pos, float radius, rstl::reserved_vector<CBoid*, 25>& nearList);
|
||||
void BuildBoidNearPartitionList(const zeus::CVector3f& pos, float radius,
|
||||
rstl::reserved_vector<CBoid*, 25>& nearList);
|
||||
void PlaceBoid(CStateManager& mgr, CBoid& boid, const zeus::CAABox& aabb);
|
||||
void ApplySeparation(CBoid& boid, const rstl::reserved_vector<CBoid*, 25>& nearList) const;
|
||||
void ApplySeparation(CBoid& boid, const zeus::CVector3f& separateFrom,
|
||||
float separationRadius, float separationMagnitude) const;
|
||||
void ApplyCohesion(CBoid& boid, const rstl::reserved_vector<CBoid*, 25>& nearList) const;
|
||||
void ApplyCohesion(CBoid& boid, const zeus::CVector3f& cohesionFrom,
|
||||
float cohesionRadius, float cohesionMagnitude) const;
|
||||
void ApplyAlignment(CBoid& boid, const rstl::reserved_vector<CBoid*, 25>& nearList) const;
|
||||
void ApplyAttraction(CBoid& boid, const zeus::CVector3f& attractTo,
|
||||
float attractionRadius, float attractionMagnitude) const;
|
||||
void ApplyRepulsion(CBoid& boid, const zeus::CVector3f& attractTo,
|
||||
float repulsionRadius, float repulsionMagnitude) const;
|
||||
void ApplySwirl(CBoid& boid, const zeus::CVector3f& swirlPoint, bool clockwise, float magnitude, float radius) const;
|
||||
void ApplyContainment(CBoid& boid, const zeus::CAABox& aabb) const;
|
||||
void ScatterBoid(CStateManager& mgr, CBoid& b) const;
|
||||
void CreateBoidDeathParticle(CBoid& b) const;
|
||||
void KillBoid(CBoid& b) const;
|
||||
zeus::CAABox GetUntransformedBoundingBox() const;
|
||||
zeus::CAABox GetBoundingBox() const;
|
||||
void CreatePartitionList();
|
||||
void AllocateSkinnedModels(CStateManager& mgr, CModelData::EWhichModel which);
|
||||
void AddParticlesToRenderer() const;
|
||||
void RenderBoid(int idx, const CBoid& boid, u32& drawMask, bool thermalHot, const CModelFlags& flags) const;
|
||||
|
||||
public:
|
||||
CFishCloud(TUniqueId uid, bool active, std::string_view name, const CEntityInfo& info, const zeus::CVector3f& scale,
|
||||
const zeus::CTransform& xf, CModelData&& mData, const CAnimRes& aRes, u32 w1, float f1, float f2, float f3,
|
||||
float f4, float f5, float f6, float f7, float f8, float f9, float f10, float f11, float f12, float f13,
|
||||
u32 w2, const zeus::CColor& color, bool b1, float f14, CAssetId part1, u32 w3, CAssetId part2, u32 w4,
|
||||
CAssetId part3, u32 w5, CAssetId part4, u32 w6, u32 w7, bool b2, bool b3);
|
||||
CFishCloud(TUniqueId uid, bool active, std::string_view name, const CEntityInfo& info,
|
||||
const zeus::CVector3f& scale, const zeus::CTransform& xf, CModelData&& mData,
|
||||
const CAnimRes& aRes, u32 numBoids, float speed, float separationRadius, float cohesionMagnitude,
|
||||
float alignmentWeight, float separationMagnitude, float weaponRepelMagnitude,
|
||||
float playerRepelMagnitude, float containmentMagnitude, float scatterVel, float maxScatterAngle,
|
||||
float weaponRepelDampingSpeed, float playerRepelDampingSpeed, float containmentRadius,
|
||||
u32 updateShift, const zeus::CColor& color, bool killable, float weaponKillRadius,
|
||||
CAssetId part1, u32 partCount1, CAssetId part2, u32 partCount2, CAssetId part3, u32 partCount3,
|
||||
CAssetId part4, u32 partCount4, u32 deathSfx, bool repelFromThreats, bool hotInThermal);
|
||||
|
||||
void Accept(IVisitor& visitor);
|
||||
void RemoveRepulsor(TUniqueId);
|
||||
void RemoveAttractor(TUniqueId);
|
||||
void AddRepulsor(TUniqueId, float, float);
|
||||
void AddAttractor(TUniqueId, float, float);
|
||||
void Think(float dt, CStateManager& mgr);
|
||||
void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr);
|
||||
void PreRender(CStateManager& mgr, const zeus::CFrustum& frustum);
|
||||
void Render(const CStateManager& mgr) const;
|
||||
void CalculateRenderBounds();
|
||||
rstl::optional<zeus::CAABox> GetTouchBounds() const;
|
||||
void Touch(CActor& other, CStateManager& mgr);
|
||||
void RemoveRepulsor(TUniqueId source);
|
||||
void RemoveAttractor(TUniqueId source);
|
||||
bool AddRepulsor(TUniqueId source, bool swirl, float radius, float priority);
|
||||
bool AddAttractor(TUniqueId source, bool swirl, float radius, float priority);
|
||||
};
|
||||
|
||||
} // namespace urde
|
||||
|
|
|
@ -6,13 +6,14 @@
|
|||
|
||||
namespace urde {
|
||||
CFishCloudModifier::CFishCloudModifier(TUniqueId uid, bool active, std::string_view name, const CEntityInfo& eInfo,
|
||||
const zeus::CVector3f& pos, bool b2, bool b3, float f1, float f2)
|
||||
const zeus::CVector3f& pos, bool isRepulsor, bool swirl, float radius,
|
||||
float priority)
|
||||
: CActor(uid, active, name, eInfo, zeus::CTransform::Translate(pos), CModelData::CModelDataNull(),
|
||||
{EMaterialTypes::NoStepLogic}, CActorParameters::None(), kInvalidUniqueId)
|
||||
, xe8_(f1)
|
||||
, xec_(f2)
|
||||
, xf0_isRepulsor(b2)
|
||||
, xf1_(b3) {}
|
||||
, xe8_radius(radius)
|
||||
, xec_priority(priority)
|
||||
, xf0_isRepulsor(isRepulsor)
|
||||
, xf1_swirl(swirl) {}
|
||||
|
||||
void CFishCloudModifier::Accept(IVisitor& visitor) { visitor.Visit(this); }
|
||||
|
||||
|
@ -32,9 +33,9 @@ void CFishCloudModifier::AddSelf(CStateManager& mgr) {
|
|||
|
||||
if (TCastToPtr<CFishCloud> fishCloud = mgr.ObjectById(mgr.GetIdForScript(conn.x8_objId))) {
|
||||
if (xf0_isRepulsor)
|
||||
fishCloud->AddRepulsor(GetUniqueId(), xe8_, xec_);
|
||||
fishCloud->AddRepulsor(GetUniqueId(), xf1_swirl, xe8_radius, xec_priority);
|
||||
else
|
||||
fishCloud->AddAttractor(GetUniqueId(), xe8_, xec_);
|
||||
fishCloud->AddAttractor(GetUniqueId(), xf1_swirl, xe8_radius, xec_priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,14 +4,15 @@
|
|||
|
||||
namespace urde {
|
||||
class CFishCloudModifier : public CActor {
|
||||
float xe8_;
|
||||
float xec_;
|
||||
float xe8_radius;
|
||||
float xec_priority;
|
||||
bool xf0_isRepulsor;
|
||||
bool xf1_;
|
||||
bool xf1_swirl;
|
||||
|
||||
public:
|
||||
CFishCloudModifier(TUniqueId, bool, std::string_view, const CEntityInfo&, const zeus::CVector3f&, bool, bool, float,
|
||||
float);
|
||||
CFishCloudModifier(TUniqueId uid, bool active, std::string_view name, const CEntityInfo& eInfo,
|
||||
const zeus::CVector3f& pos, bool isRepulsor, bool swirl, float radius,
|
||||
float priority);
|
||||
void Accept(IVisitor& visitor);
|
||||
void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&);
|
||||
|
||||
|
|
|
@ -2497,7 +2497,7 @@ void CPlayer::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CState
|
|||
break;
|
||||
case EScriptObjectMessage::Damage:
|
||||
if (TCastToPtr<CEnergyProjectile> energ = mgr.ObjectById(sender)) {
|
||||
if ((energ->GetAttribField() & EProjectileAttrib::StaticInterference) != EProjectileAttrib::None) {
|
||||
if (True(energ->GetAttribField() & EProjectileAttrib::StaticInterference)) {
|
||||
mgr.GetPlayerState()->GetStaticInterference().AddSource(GetUniqueId(), 0.3f, energ->GetInterferenceDuration());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,11 +76,11 @@ void CScriptTrigger::UpdateInhabitants(float dt, CStateManager& mgr) {
|
|||
if (TCastToPtr<CActor> act = mgr.ObjectById(it->GetObjectId())) {
|
||||
bool playerValid = true;
|
||||
if (it->GetObjectId() == mgr.GetPlayer().GetUniqueId()) {
|
||||
if ((x12c_flags & ETriggerFlags::DetectPlayer) == ETriggerFlags::None &&
|
||||
if (False(x12c_flags & ETriggerFlags::DetectPlayer) &&
|
||||
((mgr.GetPlayer().GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Morphed &&
|
||||
(x12c_flags & ETriggerFlags::DetectUnmorphedPlayer) != ETriggerFlags::None) ||
|
||||
True(x12c_flags & ETriggerFlags::DetectUnmorphedPlayer)) ||
|
||||
(mgr.GetPlayer().GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Unmorphed &&
|
||||
(x12c_flags & ETriggerFlags::DetectMorphedPlayer) != ETriggerFlags::None))) {
|
||||
True(x12c_flags & ETriggerFlags::DetectMorphedPlayer)))) {
|
||||
playerValid = false;
|
||||
}
|
||||
if (!playerValid) {
|
||||
|
@ -114,11 +114,11 @@ void CScriptTrigger::UpdateInhabitants(float dt, CStateManager& mgr) {
|
|||
if (x128_forceMagnitude > 0.f) {
|
||||
if (TCastToPtr<CPhysicsActor> pact = act.GetPtr()) {
|
||||
float forceMult = 1.f;
|
||||
if ((x12c_flags & ETriggerFlags::UseBooleanIntersection) != ETriggerFlags::None)
|
||||
if (True(x12c_flags & ETriggerFlags::UseBooleanIntersection))
|
||||
forceMult = touchBounds->booleanIntersection(*actTouchBounds).volume() / actTouchBounds->volume();
|
||||
|
||||
zeus::CVector3f force = forceMult * x11c_forceField;
|
||||
if ((x12c_flags & ETriggerFlags::UseCollisionImpulses) != ETriggerFlags::None) {
|
||||
if (True(x12c_flags & ETriggerFlags::UseCollisionImpulses)) {
|
||||
pact->ApplyImpulseWR(force, zeus::CAxisAngle());
|
||||
pact->UseCollisionImpulses();
|
||||
} else
|
||||
|
@ -158,18 +158,18 @@ void CScriptTrigger::UpdateInhabitants(float dt, CStateManager& mgr) {
|
|||
}
|
||||
}
|
||||
|
||||
if ((x12c_flags & ETriggerFlags::DetectCamera) != ETriggerFlags::None || x148_24_detectCamera) {
|
||||
if (True(x12c_flags & ETriggerFlags::DetectCamera) || x148_24_detectCamera) {
|
||||
CGameCamera* cam = mgr.GetCameraManager()->GetCurrentCamera(mgr);
|
||||
bool camInTrigger = GetTriggerBoundsWR().pointInside(cam->GetTranslation());
|
||||
if (x148_25_camSubmerged) {
|
||||
if (!camInTrigger) {
|
||||
x148_25_camSubmerged = false;
|
||||
if ((x12c_flags & ETriggerFlags::DetectCamera) != ETriggerFlags::None) {
|
||||
if (True(x12c_flags & ETriggerFlags::DetectCamera)) {
|
||||
sendExited = true;
|
||||
InhabitantExited(*cam, mgr);
|
||||
}
|
||||
} else {
|
||||
if ((x12c_flags & ETriggerFlags::DetectCamera) != ETriggerFlags::None) {
|
||||
if (True(x12c_flags & ETriggerFlags::DetectCamera)) {
|
||||
InhabitantIdle(*cam, mgr);
|
||||
sendInside = true;
|
||||
}
|
||||
|
@ -177,7 +177,7 @@ void CScriptTrigger::UpdateInhabitants(float dt, CStateManager& mgr) {
|
|||
} else {
|
||||
if (camInTrigger) {
|
||||
x148_25_camSubmerged = true;
|
||||
if ((x12c_flags & ETriggerFlags::DetectCamera) != ETriggerFlags::None) {
|
||||
if (True(x12c_flags & ETriggerFlags::DetectCamera)) {
|
||||
InhabitantAdded(*cam, mgr);
|
||||
SendScriptMsgs(EScriptObjectState::Entered, mgr, EScriptObjectMessage::Activate);
|
||||
}
|
||||
|
@ -215,7 +215,7 @@ void CScriptTrigger::Touch(CActor& act, CStateManager& mgr) {
|
|||
ETriggerFlags testFlags = ETriggerFlags::None;
|
||||
TCastToPtr<CPlayer> pl(act);
|
||||
if (pl) {
|
||||
if (x128_forceMagnitude > 0.f && (x12c_flags & ETriggerFlags::DetectPlayer) != ETriggerFlags::None &&
|
||||
if (x128_forceMagnitude > 0.f && True(x12c_flags & ETriggerFlags::DetectPlayer) &&
|
||||
mgr.GetLastTriggerId() == kInvalidUniqueId)
|
||||
mgr.SetLastTriggerId(x8_uid);
|
||||
|
||||
|
@ -238,7 +238,7 @@ void CScriptTrigger::Touch(CActor& act, CStateManager& mgr) {
|
|||
testFlags |= ETriggerFlags::DetectPowerBombs;
|
||||
}
|
||||
|
||||
if ((testFlags & x12c_flags) != ETriggerFlags::None) {
|
||||
if (True(testFlags & x12c_flags)) {
|
||||
xe8_inhabitants.push_back(act.GetUniqueId());
|
||||
InhabitantAdded(act, mgr);
|
||||
|
||||
|
@ -272,7 +272,7 @@ void CScriptTrigger::Touch(CActor& act, CStateManager& mgr) {
|
|||
}
|
||||
}
|
||||
|
||||
if ((x12c_flags & ETriggerFlags::KillOnEnter) != ETriggerFlags::None && act.HealthInfo(mgr)) {
|
||||
if (True(x12c_flags & ETriggerFlags::KillOnEnter) && act.HealthInfo(mgr)) {
|
||||
CHealthInfo* hInfo = act.HealthInfo(mgr);
|
||||
mgr.ApplyDamage(x8_uid, act.GetUniqueId(), x8_uid, {sktonOHurtWeaponMode, 10.f * hInfo->GetHP(), 0.f, 0.f},
|
||||
CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {0ull}), zeus::skZero3f);
|
||||
|
|
|
@ -2209,49 +2209,53 @@ CEntity* ScriptLoader::LoadFishCloud(CStateManager& mgr, CInputStream& in, int p
|
|||
if (!EnsurePropertyCount(propCount, 36, "FishCloud"))
|
||||
return nullptr;
|
||||
SScaledActorHead aHead = LoadScaledActorHead(in, mgr);
|
||||
bool b1 = in.readBool();
|
||||
CAssetId w1(in);
|
||||
bool active = in.readBool();
|
||||
CAssetId model(in);
|
||||
CAnimationParameters animParms(in);
|
||||
u32 w5 = u32(in.readFloatBig());
|
||||
float f1 = in.readFloatBig();
|
||||
float f2 = in.readFloatBig();
|
||||
float f3 = in.readFloatBig();
|
||||
float f4 = in.readFloatBig();
|
||||
float f5 = in.readFloatBig();
|
||||
float f6 = in.readFloatBig();
|
||||
float f7 = in.readFloatBig();
|
||||
float f8 = in.readFloatBig();
|
||||
float f9 = in.readFloatBig();
|
||||
float f10 = in.readFloatBig();
|
||||
float f11 = in.readFloatBig();
|
||||
float f12 = in.readFloatBig();
|
||||
float f13 = in.readFloatBig();
|
||||
u32 w6 = in.readUint32Big();
|
||||
u32 numBoids = u32(in.readFloatBig());
|
||||
float speed = in.readFloatBig();
|
||||
float separationRadius = in.readFloatBig();
|
||||
float cohesionMagnitude = in.readFloatBig();
|
||||
float alignmentWeight = in.readFloatBig();
|
||||
float separationMagnitude = in.readFloatBig();
|
||||
float weaponRepelMagnitude = in.readFloatBig();
|
||||
float playerRepelMagnitude = in.readFloatBig();
|
||||
float containmentMagnitude = in.readFloatBig();
|
||||
float scatterVel = in.readFloatBig();
|
||||
float maxScatterAngle = in.readFloatBig();
|
||||
float weaponRepelDampingSpeed = in.readFloatBig();
|
||||
float playerRepelDampingSpeed = in.readFloatBig();
|
||||
float containmentRadius = in.readFloatBig();
|
||||
u32 updateShift = in.readUint32Big();
|
||||
|
||||
if (!g_ResFactory->GetResourceTypeById(w1))
|
||||
if (!g_ResFactory->GetResourceTypeById(model))
|
||||
return nullptr;
|
||||
|
||||
zeus::CColor col = zeus::CColor::ReadRGBABig(in);
|
||||
bool b2 = in.readBool();
|
||||
float f14 = in.readFloatBig();
|
||||
CAssetId w7 = in.readUint32Big();
|
||||
u32 w8 = in.readUint32Big();
|
||||
CAssetId w9 = in.readUint32Big();
|
||||
u32 w10 = in.readUint32Big();
|
||||
CAssetId w11 = in.readUint32Big();
|
||||
u32 w12 = in.readUint32Big();
|
||||
CAssetId w13 = in.readUint32Big();
|
||||
u32 w14 = in.readUint32Big();
|
||||
u32 w15 = in.readUint32Big();
|
||||
bool b3 = in.readBool();
|
||||
bool b4 = in.readBool();
|
||||
zeus::CColor color = zeus::CColor::ReadRGBABig(in);
|
||||
bool killable = in.readBool();
|
||||
float weaponKillRadius = in.readFloatBig();
|
||||
CAssetId part1 = in.readUint32Big();
|
||||
u32 partCount1 = in.readUint32Big();
|
||||
CAssetId part2 = in.readUint32Big();
|
||||
u32 partCount2 = in.readUint32Big();
|
||||
CAssetId part3 = in.readUint32Big();
|
||||
u32 partCount3 = in.readUint32Big();
|
||||
CAssetId part4 = in.readUint32Big();
|
||||
u32 partCount4 = in.readUint32Big();
|
||||
u32 deathSfx = in.readUint32Big();
|
||||
bool repelFromThreats = in.readBool();
|
||||
bool hotInThermal = in.readBool();
|
||||
|
||||
CModelData mData(CStaticRes(w1, zeus::skOne3f));
|
||||
CModelData mData(CStaticRes(model, zeus::skOne3f));
|
||||
CAnimRes animRes(animParms.GetACSFile(), animParms.GetCharacter(), zeus::skOne3f,
|
||||
animParms.GetInitialAnimation(), true);
|
||||
return new CFishCloud(mgr.AllocateUniqueId(), b1, aHead.x0_name, info, aHead.x40_scale, aHead.x10_transform,
|
||||
std::move(mData), animRes, w5, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, w6, col,
|
||||
b2, f14, w7, w8, w9, w10, w11, w12, w13, w14, w15, b3, b4);
|
||||
return new CFishCloud(mgr.AllocateUniqueId(), active, aHead.x0_name, info, aHead.x40_scale, aHead.x10_transform,
|
||||
std::move(mData), animRes, numBoids, speed, separationRadius, cohesionMagnitude,
|
||||
alignmentWeight, separationMagnitude, weaponRepelMagnitude, playerRepelMagnitude,
|
||||
containmentMagnitude, scatterVel, maxScatterAngle, weaponRepelDampingSpeed,
|
||||
playerRepelDampingSpeed, containmentRadius, updateShift, color, killable, weaponKillRadius,
|
||||
part1, partCount1, part2, partCount2, part3, partCount3, part4, partCount4, deathSfx,
|
||||
repelFromThreats, hotInThermal);
|
||||
}
|
||||
|
||||
CEntity* ScriptLoader::LoadFishCloudModifier(CStateManager& mgr, CInputStream& in, int propCount,
|
||||
|
@ -2260,13 +2264,14 @@ CEntity* ScriptLoader::LoadFishCloudModifier(CStateManager& mgr, CInputStream& i
|
|||
return nullptr;
|
||||
|
||||
std::string name = mgr.HashInstanceName(in);
|
||||
zeus::CVector3f vec = zeus::CVector3f::ReadBig(in);
|
||||
bool b1 = in.readBool();
|
||||
bool b2 = in.readBool();
|
||||
bool b3 = propCount > 6 ? in.readBool() : false;
|
||||
float f1 = in.readFloatBig();
|
||||
float f2 = in.readFloatBig();
|
||||
return new CFishCloudModifier(mgr.AllocateUniqueId(), b1, name, info, vec, b2, b3, f1, f2);
|
||||
zeus::CVector3f pos = zeus::CVector3f::ReadBig(in);
|
||||
bool active = in.readBool();
|
||||
bool repulsor = in.readBool();
|
||||
bool swirl = propCount > 6 ? in.readBool() : false;
|
||||
float radius = in.readFloatBig();
|
||||
float priority = in.readFloatBig();
|
||||
|
||||
return new CFishCloudModifier(mgr.AllocateUniqueId(), active, name, info, pos, repulsor, swirl, radius, priority);
|
||||
}
|
||||
|
||||
CEntity* ScriptLoader::LoadVisorFlare(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) {
|
||||
|
|
2
hecl
2
hecl
|
@ -1 +1 @@
|
|||
Subproject commit 957a6c6851ee80c413cd1ba69795f92a8f336363
|
||||
Subproject commit 05e4c65848d6ff7a08bc7bcc4371369a6735446e
|
2
kabufuda
2
kabufuda
|
@ -1 +1 @@
|
|||
Subproject commit 3a6ee9a70cc7cd015a9dccef18852c434103988a
|
||||
Subproject commit 630119350bd083d7a63b8cfea6afc11e5b7fac76
|
2
specter
2
specter
|
@ -1 +1 @@
|
|||
Subproject commit 6d00c4007a9eb090b6b1e8525766cfd9c6732100
|
||||
Subproject commit ecea58334d51c163ec5d1a3ff26ba05f1deedbb9
|
Loading…
Reference in New Issue