Implement CFishCloud

This commit is contained in:
Jack Andersen 2019-04-02 18:32:31 -10:00
parent 8e2db0795b
commit b72cc490e8
25 changed files with 943 additions and 159 deletions

View File

@ -17,6 +17,9 @@
<pair source="c" header="h" fileNamingConvention="NONE" /> <pair source="c" header="h" fileNamingConvention="NONE" />
</extensions> </extensions>
</Objective-C-extensions> </Objective-C-extensions>
<clangFormatSettings>
<option name="ENABLED" value="true" />
</clangFormatSettings>
<codeStyleSettings language="ObjectiveC"> <codeStyleSettings language="ObjectiveC">
<option name="INDENT_CASE_FROM_SWITCH" value="false" /> <option name="INDENT_CASE_FROM_SWITCH" value="false" />
<indentOptions> <indentOptions>

View File

@ -12,38 +12,38 @@ struct FishCloud : IScriptObject {
Value<atVec3f> location; Value<atVec3f> location;
Value<atVec3f> orientation; Value<atVec3f> orientation;
Value<atVec3f> volume; Value<atVec3f> volume;
Value<bool> unknown1; Value<bool> active;
UniqueID32 model; UniqueID32 model;
AnimationParameters animationParameters; AnimationParameters animationParameters;
Value<float> unknown2; Value<atUint32> numBoids;
Value<float> unknown3; Value<float> speed;
Value<float> unknown4; Value<float> separationRadius;
Value<float> unknown5; Value<float> cohesionMagnitude;
Value<float> unknown6; Value<float> alignmentWeight;
Value<float> unknown7; Value<float> separationMagnitude;
Value<float> unknown8; Value<float> weaponRepelMagnitude;
Value<float> unknown9; Value<float> playerRepelMagnitude;
Value<float> unknown10; Value<float> containmentMagnitude;
Value<float> unknown11; Value<float> scatterVel;
Value<float> unknown12; Value<float> maxScatterAngle;
Value<float> unknown13; Value<float> weaponRepelDampingSpeed;
Value<float> unknown14; Value<float> playerRepelDampingSpeed;
Value<float> unknown15; Value<float> containmentRadius;
Value<atUint32> unknown16; Value<atUint32> updateShift;
Value<atVec4f> unknown17; // CColor Value<atVec4f> color; // CColor
Value<bool> unknown18; Value<bool> killable;
Value<float> unknown19; Value<float> weaponKillRadius;
UniqueID32 deathParticle1; UniqueID32 deathParticle1;
Value<atUint32> deathParticle1Frames; Value<atUint32> deathParticle1Count;
UniqueID32 deathParticle2; UniqueID32 deathParticle2;
Value<atUint32> deathParticle2Frames; Value<atUint32> deathParticle2Count;
UniqueID32 deathParticle3; UniqueID32 deathParticle3;
Value<atUint32> deathParticle3Frames; Value<atUint32> deathParticle3Count;
UniqueID32 deathParticle4; UniqueID32 deathParticle4;
Value<atUint32> deathParticle4Frames; Value<atUint32> deathParticle4Count;
Value<atUint32> deathSFX; Value<atUint32> deathSFX;
Value<bool> unknown29; Value<bool> repelFromThreats;
Value<bool> unknown30; Value<bool> hotInThermal;
void nameIDs(PAKRouter<PAKBridge>& pakRouter) const { void nameIDs(PAKRouter<PAKBridge>& pakRouter) const {
if (model) { if (model) {

View File

@ -10,10 +10,10 @@ struct FishCloudModifier : IScriptObject {
AT_DECL_DNAV AT_DECL_DNAV
String<-1> name; String<-1> name;
Value<atVec3f> position; Value<atVec3f> position;
Value<bool> unknown1; Value<bool> active;
Value<bool> unknown2; Value<bool> repulsor;
Value<bool> unknown3; Value<bool> swirl;
Value<float> unknown4; Value<float> radius;
Value<float> unknown5; Value<float> priority;
}; };
} // namespace DataSpec::DNAMP1 } // namespace DataSpec::DNAMP1

View File

@ -1321,8 +1321,7 @@ void CStateManager::ApplyDamageToWorld(TUniqueId damager, const CActor& actor, c
bool bomb = false; bool bomb = false;
TCastToPtr<CWeapon> weapon = const_cast<CActor&>(actor); TCastToPtr<CWeapon> weapon = const_cast<CActor&>(actor);
if (weapon) if (weapon)
bomb = (weapon->GetAttribField() & (EProjectileAttrib::Bombs | EProjectileAttrib::PowerBombs)) != bomb = True(weapon->GetAttribField() & (EProjectileAttrib::Bombs | EProjectileAttrib::PowerBombs));
EProjectileAttrib::None;
rstl::reserved_vector<TUniqueId, 1024> nearList; rstl::reserved_vector<TUniqueId, 1024> nearList;
BuildNearList(nearList, aabb, filter, &actor); 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) { void CStateManager::TestBombHittingWater(const CActor& damager, const zeus::CVector3f& pos, CActor& damagee) {
if (TCastToPtr<CWeapon> wpn = const_cast<CActor&>(damager)) { if (TCastToPtr<CWeapon> wpn = const_cast<CActor&>(damager)) {
if ((wpn->GetAttribField() & (EProjectileAttrib::Bombs | EProjectileAttrib::PowerBombs)) != if (True(wpn->GetAttribField() & (EProjectileAttrib::Bombs | EProjectileAttrib::PowerBombs))) {
EProjectileAttrib::None) {
bool powerBomb = (wpn->GetAttribField() & EProjectileAttrib::PowerBombs) == EProjectileAttrib::PowerBombs; bool powerBomb = (wpn->GetAttribField() & EProjectileAttrib::PowerBombs) == EProjectileAttrib::PowerBombs;
if (TCastToPtr<CScriptWater> water = damagee) { if (TCastToPtr<CScriptWater> water = damagee) {
zeus::CAABox bounds = water->GetTriggerBoundsWR(); zeus::CAABox bounds = water->GetTriggerBoundsWR();

View File

@ -76,7 +76,7 @@ void CCameraManager::EnterCinematic(CStateManager& mgr) {
mgr.FreeScriptObject(explo->GetUniqueId()); mgr.FreeScriptObject(explo->GetUniqueId());
} else if (TCastToPtr<CWeapon> weap = ent) { } else if (TCastToPtr<CWeapon> weap = ent) {
if (weap->GetActive()) { if (weap->GetActive()) {
if ((weap->GetAttribField() & EProjectileAttrib::KeepInCinematic) == EProjectileAttrib::None) { if (False(weap->GetAttribField() & EProjectileAttrib::KeepInCinematic)) {
if (TCastToConstPtr<CAi>(mgr.GetObjectById(weap->GetOwnerId())) || if (TCastToConstPtr<CAi>(mgr.GetObjectById(weap->GetOwnerId())) ||
TCastToConstPtr<CPlayer>(mgr.GetObjectById(weap->GetOwnerId()))) TCastToConstPtr<CPlayer>(mgr.GetObjectById(weap->GetOwnerId())))
mgr.FreeScriptObject(weap->GetUniqueId()); mgr.FreeScriptObject(weap->GetUniqueId());

View File

@ -10,14 +10,14 @@
namespace urde { namespace urde {
CBoneTracking::CBoneTracking(const CAnimData& animData, std::string_view bone, 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)) : x14_segId(animData.GetCharLayoutInfo().GetSegIdFromString(bone))
, x1c_maxTrackingAngle(maxTrackingAngle) , x1c_maxTrackingAngle(maxTrackingAngle)
, x20_angSpeed(angSpeed) , x20_angSpeed(angSpeed)
, x36_26_noParent(parentIk) , x36_26_noParent(True(flags & EBoneTrackingFlags::NoParent))
, x36_27_noParentOrigin(parentIk) , x36_27_noParentOrigin(True(flags & EBoneTrackingFlags::NoParentOrigin))
, x36_28_noHorizontalAim(parentIk) , x36_28_noHorizontalAim(True(flags & EBoneTrackingFlags::NoHorizontalAim))
, x36_29_parentIk(parentIk) {} , x36_29_parentIk(True(flags & EBoneTrackingFlags::ParentIk)) {}
void CBoneTracking::Update(float dt) { x18_time += dt; } void CBoneTracking::Update(float dt) { x18_time += dt; }

View File

@ -11,6 +11,16 @@ namespace urde {
class CAnimData; class CAnimData;
class CStateManager; class CStateManager;
class CBodyController; class CBodyController;
enum class EBoneTrackingFlags {
None = 0,
NoParent = 1,
NoParentOrigin = 2,
NoHorizontalAim = 4,
ParentIk = 8
};
ENABLE_BITWISE_ENUM(EBoneTrackingFlags)
class CBoneTracking { class CBoneTracking {
zeus::CQuaternion x0_curRotation = zeus::CQuaternion(); zeus::CQuaternion x0_curRotation = zeus::CQuaternion();
float x10_ = 0.f; float x10_ = 0.f;
@ -34,7 +44,7 @@ class CBoneTracking {
public: public:
CBoneTracking(const CAnimData& animData, std::string_view bone, 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 Update(float dt);
void PreRender(const CStateManager& mgr, CAnimData& animData, const zeus::CTransform& xf, void PreRender(const CStateManager& mgr, CAnimData& animData, const zeus::CTransform& xf,
const zeus::CVector3f& vec, const CBodyController& bodyController); const zeus::CVector3f& vec, const CBodyController& bodyController);

View File

@ -59,7 +59,8 @@ CBabygoth::CBabygoth(TUniqueId uid, std::string_view name, const CEntityInfo& in
, x6ec_(nullptr, 1, pInfo.GetPathfindingIndex(), 1.f, 1.f) , x6ec_(nullptr, 1, pInfo.GetPathfindingIndex(), 1.f, 1.f)
, x7d0_(nullptr, 1, pInfo.GetPathfindingIndex(), 1.f, 1.f) , x7d0_(nullptr, 1, pInfo.GetPathfindingIndex(), 1.f, 1.f)
, x8d0_(x3b4_speed) , 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()) , x930_aabox(GetBoundingBox(), GetMaterialList())
, x958_(babyData.x8_, babyData.xc_) , x958_(babyData.x8_, babyData.xc_)
, x984_flameThrowerDesc(babyData.x44_.IsValid() ? g_SimplePool->GetObj({SBIG('WPSC'), babyData.x44_}) , x984_flameThrowerDesc(babyData.x44_.IsValid() ? g_SimplePool->GetObj({SBIG('WPSC'), babyData.x44_})

View File

@ -17,7 +17,8 @@ CEyeball::CEyeball(TUniqueId uid, std::string_view name, CPatterned::EFlavorType
EColliderType::Zero, EBodyType::Restricted, actParms, EKnockBackVariant::Medium) EColliderType::Zero, EBodyType::Restricted, actParms, EKnockBackVariant::Medium)
, x568_attackDelay(attackDelay) , x568_attackDelay(attackDelay)
, x56c_attackStartTime(attackStartTime) , 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) , x5b4_projectileInfo(wpscId, dInfo)
, x5dc_beamContactFxId(beamContactFxId) , x5dc_beamContactFxId(beamContactFxId)
, x5e0_beamPulseFxId(beamPulseFxId) , x5e0_beamPulseFxId(beamPulseFxId)

View File

@ -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, : CPatterned(ECharacter::NewIntroBoss, uid, name, EFlavorType::Zero, info, xf, std::move(mData), pInfo,
EMovementType::Flyer, EColliderType::One, EBodyType::Restricted, actParms, EKnockBackVariant::Medium) EMovementType::Flyer, EColliderType::One, EBodyType::Restricted, actParms, EKnockBackVariant::Medium)
, x570_minTurnAngle(minTurnAngle) , 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) , x5ac_projectileInfo(projectile, dInfo)
, x5f0_beamContactFxId(beamContactFxId) , x5f0_beamContactFxId(beamContactFxId)
, x5f4_beamPulseFxId(beamPulseFxId) , x5f4_beamPulseFxId(beamPulseFxId)

View File

@ -341,7 +341,7 @@ CSpacePirate::CSpacePirate(TUniqueId uid, std::string_view name, const CEntityIn
, x568_pirateData(in, propCount) , x568_pirateData(in, propCount)
, x660_pathFindSearch(nullptr, 0x1, pInfo.GetPathfindingIndex(), 1.f, 1.f) , x660_pathFindSearch(nullptr, 0x1, pInfo.GetPathfindingIndex(), 1.f, 1.f)
, x750_initialHP(pInfo.GetHealthInfo().GetHP()) , 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) , x7c4_burstFire(skBursts, x568_pirateData.xac_firstBurstCount)
, x8b8_minCloakAlpha(x568_pirateData.xb0_CloakOpacity) , x8b8_minCloakAlpha(x568_pirateData.xb0_CloakOpacity)
, x8bc_maxCloakAlpha(x568_pirateData.xb4_MaxCloakOpacity) , x8bc_maxCloakAlpha(x568_pirateData.xb4_MaxCloakOpacity)
@ -1005,7 +1005,7 @@ void CSpacePirate::Touch(CActor& other, CStateManager& mgr) {
CPatterned::Touch(other, mgr); CPatterned::Touch(other, mgr);
if (x85c_ragDoll && x85c_ragDoll->IsPrimed()) { if (x85c_ragDoll && x85c_ragDoll->IsPrimed()) {
if (TCastToPtr<CScriptTrigger> trig = other) { 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) { trig->GetForceMagnitude() > 0.f) {
x85c_ragDoll->TorsoImpulse() += trig->GetForceVector(); x85c_ragDoll->TorsoImpulse() += trig->GetForceVector();
} }

View File

@ -53,7 +53,7 @@ CElementGen::CElementGen(const TToken<CGenDescription>& gen, EModelOrientationTy
CGenDescription* desc = x1c_genDesc.GetObj(); CGenDescription* desc = x1c_genDesc.GetObj();
x28_loadedGenDesc = desc; x28_loadedGenDesc = desc;
x26d_27_enableOPTS = (flags & EOptionalSystemFlags::Two) != EOptionalSystemFlags::None; x26d_27_enableOPTS = True(flags & EOptionalSystemFlags::Two);
if (desc->x54_x40_TEXR) if (desc->x54_x40_TEXR)
desc->x54_x40_TEXR->GetValueTexture(0).GetObj(); desc->x54_x40_TEXR->GetValueTexture(0).GetObj();

View File

@ -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 zeus::CTransform& xf, const CMaterialFilter& filter, const CMaterialList& mList,
const CDamageInfo& dInfo, EProjectileAttrib attribs, CModelData&& mData) const CDamageInfo& dInfo, EProjectileAttrib attribs, CModelData&& mData)
: CActor(uid, active, name, CEntityInfo(aid, CEntity::NullConnectionList), xf, std::move(mData), mList, : CActor(uid, active, name, CEntityInfo(aid, CEntity::NullConnectionList), xf, std::move(mData), mList,
CActorParameters::None(), kInvalidUniqueId) CActorParameters::None().HotInThermal(true), kInvalidUniqueId)
, xe8_projectileAttribs(attribs) , xe8_projectileAttribs(attribs)
, xec_ownerId(owner) , xec_ownerId(owner)
, xf0_weaponType(type) , xf0_weaponType(type)
@ -70,10 +70,10 @@ void CWeapon::FluidFXThink(EFluidState state, CScriptWater& water, CStateManager
break; break;
} }
if ((xe8_projectileAttribs & EProjectileAttrib::ComboShot) != EProjectileAttrib::None && if (True(xe8_projectileAttribs & EProjectileAttrib::ComboShot) &&
state != EFluidState::InFluid) state != EFluidState::InFluid)
mag += 0.5f; mag += 0.5f;
if ((xe8_projectileAttribs & EProjectileAttrib::Charged) != EProjectileAttrib::None) if (True(xe8_projectileAttribs & EProjectileAttrib::Charged))
mag += 0.25f; mag += 0.25f;
if (mag > 1.f) if (mag > 1.f)
mag = 1.f; mag = 1.f;
@ -81,7 +81,7 @@ void CWeapon::FluidFXThink(EFluidState state, CScriptWater& water, CStateManager
if (doRipple) { if (doRipple) {
zeus::CVector3f pos = GetTranslation(); zeus::CVector3f pos = GetTranslation();
pos.z() = float(water.GetTriggerBoundsWR().max.z()); pos.z() = float(water.GetTriggerBoundsWR().max.z());
if ((xe8_projectileAttribs & EProjectileAttrib::ComboShot) != EProjectileAttrib::None) { if (True(xe8_projectileAttribs & EProjectileAttrib::ComboShot)) {
if (!water.CanRippleAtPoint(pos)) if (!water.CanRippleAtPoint(pos))
doRipple = false; doRipple = false;
} else if (state == EFluidState::InFluid) { } else if (state == EFluidState::InFluid) {

View File

@ -176,7 +176,7 @@ void CEnvFxManager::CalculateSnowForces(const CVectorFixed8_8& zVec,
void CEnvFxManager::BuildBlockObjectList(rstl::reserved_vector<TUniqueId, 1024>& list, CStateManager& mgr) { void CEnvFxManager::BuildBlockObjectList(rstl::reserved_vector<TUniqueId, 1024>& list, CStateManager& mgr) {
for (CEntity* ent : mgr.GetAllObjectList()) { for (CEntity* ent : mgr.GetAllObjectList()) {
TCastToPtr<CScriptTrigger> trig = ent; TCastToPtr<CScriptTrigger> trig = ent;
if (trig && (trig->GetTriggerFlags() & ETriggerFlags::BlockEnvironmentalEffects) != ETriggerFlags::None) { if (trig && True(trig->GetTriggerFlags() & ETriggerFlags::BlockEnvironmentalEffects)) {
list.push_back(ent->GetUniqueId()); list.push_back(ent->GetUniqueId());
} else if (TCastToPtr<CScriptWater> water = ent) { } else if (TCastToPtr<CScriptWater> water = ent) {
list.push_back(ent->GetUniqueId()); list.push_back(ent->GetUniqueId());

View File

@ -98,7 +98,7 @@ class CEnvFxManager {
// bool x3c_snowflakeTextureMipBlanked = false; /* Shader simulates this texture mod */ // bool x3c_snowflakeTextureMipBlanked = false; /* Shader simulates this texture mod */
TLockedToken<CTexture> x40_txtrEnvGradient; TLockedToken<CTexture> x40_txtrEnvGradient;
rstl::reserved_vector<CEnvFxManagerGrid, 64> x50_grids; rstl::reserved_vector<CEnvFxManagerGrid, 64> x50_grids;
float xb54_baseSplashRate; float xb54_baseSplashRate = 0.f;
TLockedToken<CGenDescription> xb58_envRainSplash; TLockedToken<CGenDescription> xb58_envRainSplash;
bool xb64_ = true; bool xb64_ = true;
TUniqueId xb68_envRainSplashId = kInvalidUniqueId; TUniqueId xb68_envRainSplashId = kInvalidUniqueId;

View File

@ -1,26 +1,678 @@
#include "CFishCloud.hpp" #include "CFishCloud.hpp"
#include "CActorParameters.hpp" #include "CActorParameters.hpp"
#include "TCastTo.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 { namespace urde {
CFishCloud::CFishCloud(TUniqueId uid, bool active, std::string_view name, const CEntityInfo& info, CFishCloud::CFishCloud(TUniqueId uid, bool active, std::string_view name, const CEntityInfo& info,
const zeus::CVector3f& scale, const zeus::CTransform& xf, CModelData&& mData, 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, const CAnimRes& aRes, u32 numBoids, float speed, float separationRadius, float cohesionMagnitude,
float f7, float f8, float f9, float f10, float f11, float f12, float f13, u32 w2, float alignmentWeight, float separationMagnitude, float weaponRepelMagnitude,
const zeus::CColor& color, bool b1, float f14, CAssetId part1, u32 w3, CAssetId part2, u32 w4, float playerRepelMagnitude, float containmentMagnitude, float scatterVel, float maxScatterAngle,
CAssetId part3, u32 w5, CAssetId part4, u32 w6, u32 w7, bool b2, bool b3) float weaponRepelDampingSpeed, float playerRepelDampingSpeed, float containmentRadius,
: CActor(uid, active, name, info, xf, std::move(mData), {EMaterialTypes::NoStepLogic}, CActorParameters::None(), u32 updateShift, const zeus::CColor& color, bool killable, float weaponKillRadius,
kInvalidUniqueId) {} 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::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 } // namespace urde

View File

@ -1,41 +1,152 @@
#pragma once #pragma once
#include "CActor.hpp" #include "CActor.hpp"
#include "Particle/CElementGen.hpp"
namespace urde { namespace urde {
class CFishCloud : public CActor { class CFishCloud : public CActor {
class CModifierSource { class CBoid {
TUniqueId x0_source; friend class CFishCloud;
float x4_; zeus::CVector3f x0_pos;
float x8_; zeus::CVector3f xc_vel;
bool xc_; float x18_scale;
bool xd_; CBoid* x1c_next = nullptr;
bool x20_active = true;
public: public:
CModifierSource(TUniqueId, bool, float, float); CBoid(const zeus::CVector3f& pos, const zeus::CVector3f& vel, float scale)
void SetAffectPriority(float); : x0_pos(pos), xc_vel(vel), x18_scale(scale) {}
void SetAffectRadius(float); zeus::CVector3f& Translation() { return x0_pos; }
float GetAffectPriority() const; const zeus::CVector3f& GetTranslation() const { return x0_pos; }
float GetAffectRadius() const; };
bool IsRepulsor(); class CModifierSource {
TUniqueId GetSource() const; friend class CFishCloud;
TUniqueId x0_source;
bool operator<(const CModifierSource& other) const { return x0_source < other.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: public:
CFishCloud(TUniqueId uid, bool active, std::string_view name, const CEntityInfo& info, const zeus::CVector3f& scale, CFishCloud(TUniqueId uid, bool active, std::string_view name, const CEntityInfo& info,
const zeus::CTransform& xf, CModelData&& mData, const CAnimRes& aRes, u32 w1, float f1, float f2, float f3, const zeus::CVector3f& scale, const zeus::CTransform& xf, CModelData&& mData,
float f4, float f5, float f6, float f7, float f8, float f9, float f10, float f11, float f12, float f13, const CAnimRes& aRes, u32 numBoids, float speed, float separationRadius, float cohesionMagnitude,
u32 w2, const zeus::CColor& color, bool b1, float f14, CAssetId part1, u32 w3, CAssetId part2, u32 w4, float alignmentWeight, float separationMagnitude, float weaponRepelMagnitude,
CAssetId part3, u32 w5, CAssetId part4, u32 w6, u32 w7, bool b2, bool b3); 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 Accept(IVisitor& visitor);
void RemoveRepulsor(TUniqueId); void Think(float dt, CStateManager& mgr);
void RemoveAttractor(TUniqueId); void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr);
void AddRepulsor(TUniqueId, float, float); void PreRender(CStateManager& mgr, const zeus::CFrustum& frustum);
void AddAttractor(TUniqueId, float, float); 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 } // namespace urde

View File

@ -6,13 +6,14 @@
namespace urde { namespace urde {
CFishCloudModifier::CFishCloudModifier(TUniqueId uid, bool active, std::string_view name, const CEntityInfo& eInfo, 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(), : CActor(uid, active, name, eInfo, zeus::CTransform::Translate(pos), CModelData::CModelDataNull(),
{EMaterialTypes::NoStepLogic}, CActorParameters::None(), kInvalidUniqueId) {EMaterialTypes::NoStepLogic}, CActorParameters::None(), kInvalidUniqueId)
, xe8_(f1) , xe8_radius(radius)
, xec_(f2) , xec_priority(priority)
, xf0_isRepulsor(b2) , xf0_isRepulsor(isRepulsor)
, xf1_(b3) {} , xf1_swirl(swirl) {}
void CFishCloudModifier::Accept(IVisitor& visitor) { visitor.Visit(this); } 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 (TCastToPtr<CFishCloud> fishCloud = mgr.ObjectById(mgr.GetIdForScript(conn.x8_objId))) {
if (xf0_isRepulsor) if (xf0_isRepulsor)
fishCloud->AddRepulsor(GetUniqueId(), xe8_, xec_); fishCloud->AddRepulsor(GetUniqueId(), xf1_swirl, xe8_radius, xec_priority);
else else
fishCloud->AddAttractor(GetUniqueId(), xe8_, xec_); fishCloud->AddAttractor(GetUniqueId(), xf1_swirl, xe8_radius, xec_priority);
} }
} }
} }

View File

@ -4,14 +4,15 @@
namespace urde { namespace urde {
class CFishCloudModifier : public CActor { class CFishCloudModifier : public CActor {
float xe8_; float xe8_radius;
float xec_; float xec_priority;
bool xf0_isRepulsor; bool xf0_isRepulsor;
bool xf1_; bool xf1_swirl;
public: public:
CFishCloudModifier(TUniqueId, bool, std::string_view, const CEntityInfo&, const zeus::CVector3f&, bool, bool, float, CFishCloudModifier(TUniqueId uid, bool active, std::string_view name, const CEntityInfo& eInfo,
float); const zeus::CVector3f& pos, bool isRepulsor, bool swirl, float radius,
float priority);
void Accept(IVisitor& visitor); void Accept(IVisitor& visitor);
void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&); void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&);

View File

@ -2497,7 +2497,7 @@ void CPlayer::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CState
break; break;
case EScriptObjectMessage::Damage: case EScriptObjectMessage::Damage:
if (TCastToPtr<CEnergyProjectile> energ = mgr.ObjectById(sender)) { 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()); mgr.GetPlayerState()->GetStaticInterference().AddSource(GetUniqueId(), 0.3f, energ->GetInterferenceDuration());
} }
} }

View File

@ -76,11 +76,11 @@ void CScriptTrigger::UpdateInhabitants(float dt, CStateManager& mgr) {
if (TCastToPtr<CActor> act = mgr.ObjectById(it->GetObjectId())) { if (TCastToPtr<CActor> act = mgr.ObjectById(it->GetObjectId())) {
bool playerValid = true; bool playerValid = true;
if (it->GetObjectId() == mgr.GetPlayer().GetUniqueId()) { 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 && ((mgr.GetPlayer().GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Morphed &&
(x12c_flags & ETriggerFlags::DetectUnmorphedPlayer) != ETriggerFlags::None) || True(x12c_flags & ETriggerFlags::DetectUnmorphedPlayer)) ||
(mgr.GetPlayer().GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Unmorphed && (mgr.GetPlayer().GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Unmorphed &&
(x12c_flags & ETriggerFlags::DetectMorphedPlayer) != ETriggerFlags::None))) { True(x12c_flags & ETriggerFlags::DetectMorphedPlayer)))) {
playerValid = false; playerValid = false;
} }
if (!playerValid) { if (!playerValid) {
@ -114,11 +114,11 @@ void CScriptTrigger::UpdateInhabitants(float dt, CStateManager& mgr) {
if (x128_forceMagnitude > 0.f) { if (x128_forceMagnitude > 0.f) {
if (TCastToPtr<CPhysicsActor> pact = act.GetPtr()) { if (TCastToPtr<CPhysicsActor> pact = act.GetPtr()) {
float forceMult = 1.f; float forceMult = 1.f;
if ((x12c_flags & ETriggerFlags::UseBooleanIntersection) != ETriggerFlags::None) if (True(x12c_flags & ETriggerFlags::UseBooleanIntersection))
forceMult = touchBounds->booleanIntersection(*actTouchBounds).volume() / actTouchBounds->volume(); forceMult = touchBounds->booleanIntersection(*actTouchBounds).volume() / actTouchBounds->volume();
zeus::CVector3f force = forceMult * x11c_forceField; 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->ApplyImpulseWR(force, zeus::CAxisAngle());
pact->UseCollisionImpulses(); pact->UseCollisionImpulses();
} else } 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); CGameCamera* cam = mgr.GetCameraManager()->GetCurrentCamera(mgr);
bool camInTrigger = GetTriggerBoundsWR().pointInside(cam->GetTranslation()); bool camInTrigger = GetTriggerBoundsWR().pointInside(cam->GetTranslation());
if (x148_25_camSubmerged) { if (x148_25_camSubmerged) {
if (!camInTrigger) { if (!camInTrigger) {
x148_25_camSubmerged = false; x148_25_camSubmerged = false;
if ((x12c_flags & ETriggerFlags::DetectCamera) != ETriggerFlags::None) { if (True(x12c_flags & ETriggerFlags::DetectCamera)) {
sendExited = true; sendExited = true;
InhabitantExited(*cam, mgr); InhabitantExited(*cam, mgr);
} }
} else { } else {
if ((x12c_flags & ETriggerFlags::DetectCamera) != ETriggerFlags::None) { if (True(x12c_flags & ETriggerFlags::DetectCamera)) {
InhabitantIdle(*cam, mgr); InhabitantIdle(*cam, mgr);
sendInside = true; sendInside = true;
} }
@ -177,7 +177,7 @@ void CScriptTrigger::UpdateInhabitants(float dt, CStateManager& mgr) {
} else { } else {
if (camInTrigger) { if (camInTrigger) {
x148_25_camSubmerged = true; x148_25_camSubmerged = true;
if ((x12c_flags & ETriggerFlags::DetectCamera) != ETriggerFlags::None) { if (True(x12c_flags & ETriggerFlags::DetectCamera)) {
InhabitantAdded(*cam, mgr); InhabitantAdded(*cam, mgr);
SendScriptMsgs(EScriptObjectState::Entered, mgr, EScriptObjectMessage::Activate); SendScriptMsgs(EScriptObjectState::Entered, mgr, EScriptObjectMessage::Activate);
} }
@ -215,7 +215,7 @@ void CScriptTrigger::Touch(CActor& act, CStateManager& mgr) {
ETriggerFlags testFlags = ETriggerFlags::None; ETriggerFlags testFlags = ETriggerFlags::None;
TCastToPtr<CPlayer> pl(act); TCastToPtr<CPlayer> pl(act);
if (pl) { 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.GetLastTriggerId() == kInvalidUniqueId)
mgr.SetLastTriggerId(x8_uid); mgr.SetLastTriggerId(x8_uid);
@ -238,7 +238,7 @@ void CScriptTrigger::Touch(CActor& act, CStateManager& mgr) {
testFlags |= ETriggerFlags::DetectPowerBombs; testFlags |= ETriggerFlags::DetectPowerBombs;
} }
if ((testFlags & x12c_flags) != ETriggerFlags::None) { if (True(testFlags & x12c_flags)) {
xe8_inhabitants.push_back(act.GetUniqueId()); xe8_inhabitants.push_back(act.GetUniqueId());
InhabitantAdded(act, mgr); 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); CHealthInfo* hInfo = act.HealthInfo(mgr);
mgr.ApplyDamage(x8_uid, act.GetUniqueId(), x8_uid, {sktonOHurtWeaponMode, 10.f * hInfo->GetHP(), 0.f, 0.f}, mgr.ApplyDamage(x8_uid, act.GetUniqueId(), x8_uid, {sktonOHurtWeaponMode, 10.f * hInfo->GetHP(), 0.f, 0.f},
CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {0ull}), zeus::skZero3f); CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {0ull}), zeus::skZero3f);

View File

@ -2209,49 +2209,53 @@ CEntity* ScriptLoader::LoadFishCloud(CStateManager& mgr, CInputStream& in, int p
if (!EnsurePropertyCount(propCount, 36, "FishCloud")) if (!EnsurePropertyCount(propCount, 36, "FishCloud"))
return nullptr; return nullptr;
SScaledActorHead aHead = LoadScaledActorHead(in, mgr); SScaledActorHead aHead = LoadScaledActorHead(in, mgr);
bool b1 = in.readBool(); bool active = in.readBool();
CAssetId w1(in); CAssetId model(in);
CAnimationParameters animParms(in); CAnimationParameters animParms(in);
u32 w5 = u32(in.readFloatBig()); u32 numBoids = u32(in.readFloatBig());
float f1 = in.readFloatBig(); float speed = in.readFloatBig();
float f2 = in.readFloatBig(); float separationRadius = in.readFloatBig();
float f3 = in.readFloatBig(); float cohesionMagnitude = in.readFloatBig();
float f4 = in.readFloatBig(); float alignmentWeight = in.readFloatBig();
float f5 = in.readFloatBig(); float separationMagnitude = in.readFloatBig();
float f6 = in.readFloatBig(); float weaponRepelMagnitude = in.readFloatBig();
float f7 = in.readFloatBig(); float playerRepelMagnitude = in.readFloatBig();
float f8 = in.readFloatBig(); float containmentMagnitude = in.readFloatBig();
float f9 = in.readFloatBig(); float scatterVel = in.readFloatBig();
float f10 = in.readFloatBig(); float maxScatterAngle = in.readFloatBig();
float f11 = in.readFloatBig(); float weaponRepelDampingSpeed = in.readFloatBig();
float f12 = in.readFloatBig(); float playerRepelDampingSpeed = in.readFloatBig();
float f13 = in.readFloatBig(); float containmentRadius = in.readFloatBig();
u32 w6 = in.readUint32Big(); u32 updateShift = in.readUint32Big();
if (!g_ResFactory->GetResourceTypeById(w1)) if (!g_ResFactory->GetResourceTypeById(model))
return nullptr; return nullptr;
zeus::CColor col = zeus::CColor::ReadRGBABig(in); zeus::CColor color = zeus::CColor::ReadRGBABig(in);
bool b2 = in.readBool(); bool killable = in.readBool();
float f14 = in.readFloatBig(); float weaponKillRadius = in.readFloatBig();
CAssetId w7 = in.readUint32Big(); CAssetId part1 = in.readUint32Big();
u32 w8 = in.readUint32Big(); u32 partCount1 = in.readUint32Big();
CAssetId w9 = in.readUint32Big(); CAssetId part2 = in.readUint32Big();
u32 w10 = in.readUint32Big(); u32 partCount2 = in.readUint32Big();
CAssetId w11 = in.readUint32Big(); CAssetId part3 = in.readUint32Big();
u32 w12 = in.readUint32Big(); u32 partCount3 = in.readUint32Big();
CAssetId w13 = in.readUint32Big(); CAssetId part4 = in.readUint32Big();
u32 w14 = in.readUint32Big(); u32 partCount4 = in.readUint32Big();
u32 w15 = in.readUint32Big(); u32 deathSfx = in.readUint32Big();
bool b3 = in.readBool(); bool repelFromThreats = in.readBool();
bool b4 = 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, CAnimRes animRes(animParms.GetACSFile(), animParms.GetCharacter(), zeus::skOne3f,
animParms.GetInitialAnimation(), true); animParms.GetInitialAnimation(), true);
return new CFishCloud(mgr.AllocateUniqueId(), b1, aHead.x0_name, info, aHead.x40_scale, aHead.x10_transform, return new CFishCloud(mgr.AllocateUniqueId(), active, 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, std::move(mData), animRes, numBoids, speed, separationRadius, cohesionMagnitude,
b2, f14, w7, w8, w9, w10, w11, w12, w13, w14, w15, b3, b4); 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, CEntity* ScriptLoader::LoadFishCloudModifier(CStateManager& mgr, CInputStream& in, int propCount,
@ -2260,13 +2264,14 @@ CEntity* ScriptLoader::LoadFishCloudModifier(CStateManager& mgr, CInputStream& i
return nullptr; return nullptr;
std::string name = mgr.HashInstanceName(in); std::string name = mgr.HashInstanceName(in);
zeus::CVector3f vec = zeus::CVector3f::ReadBig(in); zeus::CVector3f pos = zeus::CVector3f::ReadBig(in);
bool b1 = in.readBool(); bool active = in.readBool();
bool b2 = in.readBool(); bool repulsor = in.readBool();
bool b3 = propCount > 6 ? in.readBool() : false; bool swirl = propCount > 6 ? in.readBool() : false;
float f1 = in.readFloatBig(); float radius = in.readFloatBig();
float f2 = in.readFloatBig(); float priority = in.readFloatBig();
return new CFishCloudModifier(mgr.AllocateUniqueId(), b1, name, info, vec, b2, b3, f1, f2);
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) { CEntity* ScriptLoader::LoadVisorFlare(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) {

2
hecl

@ -1 +1 @@
Subproject commit 957a6c6851ee80c413cd1ba69795f92a8f336363 Subproject commit 05e4c65848d6ff7a08bc7bcc4371369a6735446e

@ -1 +1 @@
Subproject commit 3a6ee9a70cc7cd015a9dccef18852c434103988a Subproject commit 630119350bd083d7a63b8cfea6afc11e5b7fac76

@ -1 +1 @@
Subproject commit 6d00c4007a9eb090b6b1e8525766cfd9c6732100 Subproject commit ecea58334d51c163ec5d1a3ff26ba05f1deedbb9