Work on CSpacePirate

This commit is contained in:
Jack Andersen 2018-11-25 16:15:44 -10:00
parent 9c88971df6
commit e1fa938127
29 changed files with 1787 additions and 290 deletions

View File

@ -11,15 +11,15 @@ struct TeamAIMgr : IScriptObject
AT_DECL_DNA_YAML
AT_DECL_DNAV
String<-1> name;
Value<atUint32> unknown1;
Value<atUint32> unknown2;
Value<atUint32> unknown3;
Value<atUint32> unknown4;
Value<atUint32> unknown5;
Value<atUint32> unknown6;
Value<atUint32> unknown7;
Value<float> unknown8;
Value<float> unknown9;
Value<atUint32> aiCount;
Value<atUint32> meleeCount;
Value<atUint32> projectileCount;
Value<atUint32> unknownCount;
Value<atUint32> maxMeleeAttackerCount;
Value<atUint32> maxProjectileAttackerCount;
Value<atUint32> positionMode;
Value<float> meleeTimeInterval;
Value<float> projectileTimeInterval;
};
}

View File

@ -561,7 +561,7 @@ void CActorLights::ActivateLights(CBooModel& model) const
if (x298_31_disableWorldLights)
{
zeus::CColor color(x2d4_worldLightingLevel);
g_Renderer->SetWorldLightMultiplyColor(color);
g_Renderer->SetGXRegister1Color(color);
}
}

View File

@ -25,6 +25,11 @@ void CIkChain::Activate(const CAnimData& animData, const CSegId& segId, const ze
//const TLockedToken<CCharLayoutInfo>& info = posBuilder.CharLayoutInfo();
}
void CIkChain::PreRender(CAnimData& animData, const zeus::CTransform& xf, const zeus::CVector3f& scale)
{
}
void CIkChain::Solve(zeus::CQuaternion& q1, zeus::CQuaternion& q2, const zeus::CVector3f& vec)
{
const float mag = vec.magnitude();

View File

@ -65,66 +65,68 @@ void CRagDoll::CRagDollPlaneConstraint::Update()
}
}
CRagDoll::CRagDoll(float f1, float f2, float f3, u32 flags)
: x44_f1(f1), x48_f2(f2), x50_f3(f3)
CRagDoll::CRagDoll(float normalGravity, float floatingGravity, float overTime, u32 flags)
: x44_normalGravity(normalGravity), x48_floatingGravity(floatingGravity), x50_overTimer(overTime)
{
x68_27_ = bool(flags & 0x1);
x68_28_ = bool(flags & 0x2);
x68_29_ = bool(flags & 0x4);
x68_27_continueSmallMovements = bool(flags & 0x1);
x68_28_noOverTimer = bool(flags & 0x2);
x68_29_noAiCollision = bool(flags & 0x4);
}
void CRagDoll::AccumulateForces(float dt, float f2)
void CRagDoll::AccumulateForces(float dt, float waterTop)
{
float fps = 1.f / dt;
x64_angTimer += dt;
if (x64_angTimer > 4.f)
x64_angTimer -= 4.f;
float f25 = std::sin(zeus::degToRad(90.f) * x64_angTimer) * 0.1f + (f2 - 0.2f);
zeus::CVector3f f29;
float f24 = 0.f;
float targetZ = std::sin(zeus::degToRad(90.f) * x64_angTimer) * 0.1f + (waterTop - 0.2f);
zeus::CVector3f centerOfVolume;
float totalVolume = 0.f;
for (auto& particle : x4_particles)
{
float cubed = particle.x10_radius * particle.x10_radius * particle.x10_radius;
f24 += cubed;
f29 += particle.x4_curPos * cubed;
float f7 = particle.x4_curPos.z - f25;
float f8 = x48_f2;
float f23 = 0.f;
if (std::fabs(f7) < 0.5f)
float volume = particle.x10_radius * particle.x10_radius * particle.x10_radius;
totalVolume += volume;
centerOfVolume += particle.x4_curPos * volume;
float fromTargetZ = particle.x4_curPos.z - targetZ;
float verticalAcc = x48_floatingGravity;
float termVelCoefficient = 0.f;
if (std::fabs(fromTargetZ) < 0.5f)
{
f23 = 0.5f * f7 / 0.5f + 0.5f;
f8 = x48_f2 * -f7 / 0.5f;
termVelCoefficient = 0.5f * fromTargetZ / 0.5f + 0.5f;
verticalAcc = x48_floatingGravity * -fromTargetZ / 0.5f;
}
else if (f7 > 0.f)
else if (fromTargetZ > 0.f)
{
f8 = x44_f1;
f23 = 1.f;
verticalAcc = x44_normalGravity;
termVelCoefficient = 1.f;
}
particle.x20_acceleration.z += f8;
particle.x20_velocity.z += verticalAcc;
zeus::CVector3f vel = (particle.x4_curPos - particle.x14_prevPos) * fps;
float velMag = vel.magnitude();
if (velMag > FLT_EPSILON)
{
particle.x20_acceleration -= vel * (1.f / velMag) *
((velMag * velMag * 0.75f * (1.2f * f23 + 1000.f * (1.f - f23))) / (8000.f * particle.x10_radius));
particle.x20_velocity -= vel * (1.f / velMag) *
((velMag * velMag * 0.75f * (1.2f * termVelCoefficient + 1000.f *
(1.f - termVelCoefficient))) / (8000.f * particle.x10_radius));
}
}
zeus::CVector3f _c8;
f29 = f29 / f24;
zeus::CVector3f averageTorque;
centerOfVolume = centerOfVolume / totalVolume;
for (const auto& particle : x4_particles)
{
float cubed = particle.x10_radius * particle.x10_radius * particle.x10_radius;
_c8 += (particle.x4_curPos - f29).cross(particle.x4_curPos) * cubed;
float volume = particle.x10_radius * particle.x10_radius * particle.x10_radius;
averageTorque += (particle.x4_curPos - centerOfVolume).
cross(particle.x4_curPos - particle.x14_prevPos) * volume;
}
_c8 = _c8 * (fps / f24);
if (_c8.canBeNormalized())
averageTorque = averageTorque * (fps / totalVolume);
if (averageTorque.canBeNormalized())
for (auto& particle : x4_particles)
particle.x20_acceleration -= _c8.cross(particle.x4_curPos - f29) * 25.f;
particle.x20_velocity -= averageTorque.cross(particle.x4_curPos - centerOfVolume) * 25.f;
}
void CRagDoll::AddParticle(CSegId id, const zeus::CVector3f& prevPos, const zeus::CVector3f& curPos, float f1)
void CRagDoll::AddParticle(CSegId id, const zeus::CVector3f& prevPos, const zeus::CVector3f& curPos, float radius)
{
x4_particles.emplace_back(id, curPos, f1, prevPos);
x4_particles.emplace_back(id, curPos, radius, prevPos);
}
void CRagDoll::AddLengthConstraint(int i1, int i2)
@ -173,42 +175,42 @@ zeus::CAABox CRagDoll::CalculateRenderBounds() const
void CRagDoll::CheckStatic(float dt)
{
x4c_ = 0;
x54_ = 0.f;
float f1 = 0.5f * dt;
float f31 = f1 * f1;
x58_ = zeus::CVector3f::skZero;
bool r31 = true;
x4c_impactCount = 0;
x54_impactVel = 0.f;
float halfDt = 0.5f * dt;
float halfDeltaUnitSq = halfDt * halfDt;
x58_averageVel = zeus::CVector3f::skZero;
bool movingSlowly = true;
for (auto& particle : x4_particles)
{
zeus::CVector3f delta = particle.x4_curPos - particle.x14_prevPos;
x58_ += delta;
if (delta.magSquared() > f31)
r31 = false;
if (particle.x3c_24_nextDampVel)
x58_averageVel += delta;
if (delta.magSquared() > halfDeltaUnitSq)
movingSlowly = false;
if (particle.x3c_24_impactPending)
{
x4c_ += 1;
x54_ = std::max(particle.x38_, x54_);
x4c_impactCount += 1;
x54_impactVel = std::max(particle.x38_impactFrameVel, x54_impactVel);
}
}
if (!x4_particles.empty())
x58_ = x58_ * (1.f / (dt * x4_particles.size()));
x54_ /= dt;
if (!x68_28_)
x58_averageVel = x58_averageVel * (1.f / (dt * x4_particles.size()));
x54_impactVel /= dt;
if (!x68_28_noOverTimer)
{
x50_f3 -= dt;
if (x50_f3 <= 0.f)
x68_25_ = true;
x50_overTimer -= dt;
if (x50_overTimer <= 0.f)
x68_25_over = true;
}
if (r31 && x68_24_)
x68_25_ = true;
x68_24_ = r31;
if (movingSlowly && x68_24_prevMovingSlowly)
x68_25_over = true;
x68_24_prevMovingSlowly = movingSlowly;
}
void CRagDoll::ClearForces()
{
for (auto& particle : x4_particles)
particle.x20_acceleration = zeus::CVector3f::skZero;
particle.x20_velocity = zeus::CVector3f::skZero;
}
void CRagDoll::SatisfyConstraints(CStateManager& mgr)
@ -223,12 +225,12 @@ void CRagDoll::SatisfyConstraints(CStateManager& mgr)
SatisfyWorldConstraints(mgr, 2);
}
bool CRagDoll::SatisfyWorldConstraints(CStateManager& mgr, int i1)
bool CRagDoll::SatisfyWorldConstraints(CStateManager& mgr, int pass)
{
zeus::CAABox aabb;
for (const auto& particle : x4_particles)
{
if (i1 == 1 || particle.x3c_24_nextDampVel)
if (pass == 1 || particle.x3c_24_impactPending)
{
aabb.accumulateBounds(particle.x14_prevPos - particle.x10_radius);
aabb.accumulateBounds(particle.x14_prevPos + particle.x10_radius);
@ -239,19 +241,19 @@ bool CRagDoll::SatisfyWorldConstraints(CStateManager& mgr, int i1)
CAreaCollisionCache ccache(aabb);
CGameCollision::BuildAreaCollisionCache(mgr, ccache);
bool ret = false;
bool needs2ndPass = false;
TUniqueId bestId = kInvalidUniqueId;
CMaterialList include;
if (x68_29_)
if (x68_29_noAiCollision)
include = CMaterialList(EMaterialTypes::Solid);
else
include = CMaterialList(EMaterialTypes::Solid, EMaterialTypes::AIBlock);
CMaterialList exclude;
if (x68_29_)
if (x68_29_noAiCollision)
exclude = CMaterialList(EMaterialTypes::Character, EMaterialTypes::Player,
EMaterialTypes::AIBlock, EMaterialTypes::Occluder);
EMaterialTypes::AIBlock, EMaterialTypes::Occluder);
else
exclude = CMaterialList(EMaterialTypes::Character, EMaterialTypes::Player);
@ -261,7 +263,7 @@ bool CRagDoll::SatisfyWorldConstraints(CStateManager& mgr, int i1)
for (auto& particle : x4_particles)
{
if (i1 == 1 || particle.x3c_24_nextDampVel)
if (pass == 1 || particle.x3c_24_impactPending)
{
zeus::CVector3f delta = particle.x4_curPos - particle.x14_prevPos;
float deltaMag = delta.magnitude();
@ -275,15 +277,15 @@ bool CRagDoll::SatisfyWorldConstraints(CStateManager& mgr, int i1)
nearList, delta, bestId, info, d);
if (info.IsValid())
{
ret = true;
switch (i1)
needs2ndPass = true;
switch (pass)
{
case 1:
{
particle.x3c_24_nextDampVel = true;
particle.x3c_24_impactPending = true;
float dot = delta.dot(info.GetNormalLeft());
particle.x2c_nextPosDelta = -0.125f * dot * deltaMag * info.GetNormalLeft();
particle.x38_ = -dot * deltaMag;
particle.x2c_impactResponseDelta = -0.125f * dot * deltaMag * info.GetNormalLeft();
particle.x38_impactFrameVel = -dot * deltaMag;
particle.x4_curPos += float(0.0001f - (deltaMag - d) * dot) * info.GetNormalLeft();
break;
}
@ -295,20 +297,20 @@ bool CRagDoll::SatisfyWorldConstraints(CStateManager& mgr, int i1)
}
}
}
else if (!x68_27_)
else if (!x68_27_continueSmallMovements)
{
particle.x4_curPos = particle.x14_prevPos;
}
}
}
return ret;
return needs2ndPass;
}
void CRagDoll::SatisfyWorldConstraintsOnConstruction(CStateManager& mgr)
{
for (auto& particle : x4_particles)
particle.x3c_24_nextDampVel = true;
particle.x3c_24_impactPending = true;
SatisfyWorldConstraints(mgr, 2);
for (auto& particle : x4_particles)
particle.x14_prevPos = particle.x4_curPos;
@ -320,15 +322,15 @@ void CRagDoll::Verlet(float dt)
{
zeus::CVector3f oldPos = particle.x4_curPos;
particle.x4_curPos += (particle.x4_curPos - particle.x14_prevPos) *
(particle.x3c_24_nextDampVel ? 0.9f : 1.f);
particle.x4_curPos += particle.x20_acceleration * (dt * dt);
particle.x4_curPos += particle.x2c_nextPosDelta;
(particle.x3c_24_impactPending ? 0.9f : 1.f);
particle.x4_curPos += particle.x20_velocity * (dt * dt);
particle.x4_curPos += particle.x2c_impactResponseDelta;
particle.x14_prevPos = oldPos;
zeus::CVector3f deltaPos = particle.x4_curPos - particle.x14_prevPos;
if (deltaPos.magSquared() > 4.f)
particle.x4_curPos = deltaPos.normalized() * 2.f + particle.x14_prevPos;
particle.x3c_24_nextDampVel = false;
particle.x2c_nextPosDelta = zeus::CVector3f::skZero;
particle.x3c_24_impactPending = false;
particle.x2c_impactResponseDelta = zeus::CVector3f::skZero;
}
}
@ -337,11 +339,11 @@ void CRagDoll::PreRender(const zeus::CVector3f& v, CModelData& mData)
// Empty
}
void CRagDoll::Update(CStateManager& mgr, float dt, float f2)
void CRagDoll::Update(CStateManager& mgr, float dt, float waterTop)
{
if (!x68_25_ || x68_27_)
if (!x68_25_over || x68_27_continueSmallMovements)
{
AccumulateForces(dt, f2);
AccumulateForces(dt, waterTop);
Verlet(dt);
SatisfyConstraints(mgr);
ClearForces();
@ -359,7 +361,7 @@ void CRagDoll::Prime(CStateManager& mgr, const zeus::CTransform& xf, CModelData&
particle.x4_curPos = xf * aData->GetPose().GetOffset(particle.x0_id) * scale;
SatisfyWorldConstraints(mgr, 2);
for (auto& particle : x4_particles)
particle.x3c_24_nextDampVel = false;
particle.x3c_24_impactPending = false;
x68_26_primed = true;
}

View File

@ -22,23 +22,23 @@ protected:
zeus::CVector3f x4_curPos;
float x10_radius;
zeus::CVector3f x14_prevPos;
zeus::CVector3f x20_acceleration;
zeus::CVector3f x2c_nextPosDelta;
float x38_ = 0.f;
bool x3c_24_nextDampVel : 1;
zeus::CVector3f x20_velocity;
zeus::CVector3f x2c_impactResponseDelta;
float x38_impactFrameVel = 0.f;
bool x3c_24_impactPending : 1;
bool x3c_25_ : 1;
public:
CRagDollParticle(CSegId id, const zeus::CVector3f& curPos, float f1, const zeus::CVector3f& prevPos)
: x0_id(id), x4_curPos(curPos), x10_radius(f1), x14_prevPos(prevPos)
CRagDollParticle(CSegId id, const zeus::CVector3f& curPos, float radius, const zeus::CVector3f& prevPos)
: x0_id(id), x4_curPos(curPos), x10_radius(radius), x14_prevPos(prevPos)
{
x3c_24_nextDampVel = false;
x3c_24_impactPending = false;
x3c_25_ = false;
}
CSegId GetBone() const { return x0_id; }
const zeus::CVector3f& GetPosition() const { return x4_curPos; }
zeus::CVector3f& Position() { return x4_curPos; }
const zeus::CVector3f& GetAcceleration() const { return x20_acceleration; }
zeus::CVector3f& Acceleration() { return x20_acceleration; }
const zeus::CVector3f& GetVelocity() const { return x20_velocity; }
zeus::CVector3f& Velocity() { return x20_velocity; }
float GetRadius() const { return x10_radius; }
};
class CRagDollLengthConstraint
@ -87,29 +87,29 @@ protected:
std::vector<CRagDollLengthConstraint> x14_lengthConstraints;
std::vector<CRagDollJointConstraint> x24_jointConstraints;
std::vector<CRagDollPlaneConstraint> x34_planeConstraints;
float x44_f1;
float x48_f2;
u32 x4c_ = 0;
float x50_f3;
float x54_ = 0.f;
zeus::CVector3f x58_;
float x44_normalGravity;
float x48_floatingGravity;
u32 x4c_impactCount = 0;
float x50_overTimer;
float x54_impactVel = 0.f;
zeus::CVector3f x58_averageVel;
float x64_angTimer = 0.f;
union
{
struct
{
bool x68_24_ : 1;
bool x68_25_ : 1;
bool x68_24_prevMovingSlowly : 1;
bool x68_25_over : 1;
bool x68_26_primed : 1;
bool x68_27_ : 1;
bool x68_28_ : 1;
bool x68_29_ : 1;
bool x68_27_continueSmallMovements : 1;
bool x68_28_noOverTimer : 1;
bool x68_29_noAiCollision : 1;
};
u32 _dummy = 0;
};
void AccumulateForces(float dt, float f2);
void AccumulateForces(float dt, float waterTop);
void SetNumParticles(int num) { x4_particles.reserve(num); }
void AddParticle(CSegId id, const zeus::CVector3f& prevPos, const zeus::CVector3f& curPos, float f1);
void AddParticle(CSegId id, const zeus::CVector3f& prevPos, const zeus::CVector3f& curPos, float radius);
void SetNumLengthConstraints(int num) { x14_lengthConstraints.reserve(num); }
void AddLengthConstraint(int i1, int i2);
void AddMaxLengthConstraint(int i1, int i2, float length);
@ -118,20 +118,24 @@ protected:
void AddJointConstraint(int i1, int i2, int i3, int i4, int i5, int i6);
zeus::CQuaternion BoneAlign(CHierarchyPoseBuilder& pb, const CCharLayoutInfo& charInfo,
int i1, int i2, const zeus::CQuaternion& q);
zeus::CAABox CalculateRenderBounds() const;
void CheckStatic(float dt);
void ClearForces();
void SatisfyConstraints(CStateManager& mgr);
bool SatisfyWorldConstraints(CStateManager& mgr, int i1);
bool SatisfyWorldConstraints(CStateManager& mgr, int pass);
void SatisfyWorldConstraintsOnConstruction(CStateManager& mgr);
void Verlet(float dt);
public:
virtual ~CRagDoll() = default;
CRagDoll(float f1, float f2, float f3, u32 flags);
CRagDoll(float normalGravity, float floatingGravity, float overTime, u32 flags);
virtual void PreRender(const zeus::CVector3f& v, CModelData& mData);
virtual void Update(CStateManager& mgr, float dt, float f2);
virtual void Update(CStateManager& mgr, float dt, float waterTop);
virtual void Prime(CStateManager& mgr, const zeus::CTransform& xf, CModelData& mData);
zeus::CAABox CalculateRenderBounds() const;
bool IsPrimed() const { return x68_26_primed; }
bool WillContinueSmallMovements() const { return x68_27_continueSmallMovements; }
bool IsOver() const { return x68_25_over; }
};
}

View File

@ -1347,7 +1347,7 @@ void CBooRenderer::PrepareDynamicLights(const std::vector<CLight>& lights)
}
}
void CBooRenderer::SetWorldLightMultiplyColor(const zeus::CColor& color)
void CBooRenderer::SetGXRegister1Color(const zeus::CColor& color)
{
CGraphics::g_ColorRegs[1] = color;
}

View File

@ -269,7 +269,7 @@ public:
void DoThermalBlendHot();
u32 GetStaticWorldDataSize();
void PrepareDynamicLights(const std::vector<CLight>& lights);
void SetWorldLightMultiplyColor(const zeus::CColor& color);
void SetGXRegister1Color(const zeus::CColor& color);
void SetWorldLightFadeLevel(float level);
void DrawPhazonSuitIndirectEffect(const zeus::CColor& nonIndirectMod, const TLockedToken<CTexture>& indTex,
const zeus::CColor& indirectMod, float blurRadius,

View File

@ -105,7 +105,7 @@ public:
virtual void DoThermalBlendHot()=0;
virtual u32 GetStaticWorldDataSize()=0;
virtual void PrepareDynamicLights(const std::vector<CLight>& lights)=0;
virtual void SetWorldLightMultiplyColor(const zeus::CColor& color)=0;
virtual void SetGXRegister1Color(const zeus::CColor& color)=0;
virtual void SetWorldLightFadeLevel(float level)=0;
};

View File

@ -63,7 +63,7 @@ void MP1::CActorContraption::ResetFlameThrowers(CStateManager& mgr)
}
}
void MP1::CActorContraption::DoUserAnimEvent(CStateManager& mgr, CInt32POINode& node, EUserEventType evType, float dt)
void MP1::CActorContraption::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType evType, float dt)
{
if (evType == EUserEventType::DamageOff)
{

View File

@ -23,7 +23,7 @@ public:
void Accept(IVisitor &visitor);
void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager &);
void Think(float, CStateManager &);
void DoUserAnimEvent(CStateManager &, CInt32POINode &, EUserEventType, float dt);
void DoUserAnimEvent(CStateManager&, const CInt32POINode&, EUserEventType, float dt);
CFlameThrower* CreateFlameThrower(std::string_view, CStateManager&);
void ResetFlameThrowers(CStateManager& mgr);
};

View File

@ -80,7 +80,7 @@ void CFlickerBat::Touch(CActor& act, CStateManager& mgr)
CPatterned::Touch(act, mgr);
}
void CFlickerBat::DoUserAnimEvent(CStateManager& mgr, CInt32POINode& node, EUserEventType type, float dt)
void CFlickerBat::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt)
{
CPatterned::DoUserAnimEvent(mgr, node, type, dt);
}

View File

@ -36,7 +36,7 @@ public:
void Think(float, CStateManager&);
void Render(const CStateManager&) const;
void Touch(CActor&, CStateManager&);
void DoUserAnimEvent(CStateManager&, CInt32POINode&, EUserEventType, float dt);
void DoUserAnimEvent(CStateManager&, const CInt32POINode&, EUserEventType, float dt);
void Death(CStateManager& mgr, const zeus::CVector3f& direction, EScriptObjectState state);
bool CanBeShot(CStateManager&, int);
void Patrol(CStateManager&, EStateMsg, float);

View File

@ -318,7 +318,7 @@ void CNewIntroBoss::Think(float dt, CStateManager& mgr)
}
}
void CNewIntroBoss::DoUserAnimEvent(CStateManager& mgr, CInt32POINode& node, EUserEventType event, float dt)
void CNewIntroBoss::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType event, float dt)
{
if (event == EUserEventType::DamageOn)
{

View File

@ -67,7 +67,7 @@ public:
}
std::experimental::optional<zeus::CAABox> GetTouchBounds() const { return {}; }
void DoUserAnimEvent(CStateManager&, CInt32POINode&, EUserEventType, float dt);
void DoUserAnimEvent(CStateManager&, const CInt32POINode&, EUserEventType, float dt);
void Generate(CStateManager&, EStateMsg, float);
void Attack(CStateManager&, EStateMsg, float);
void Patrol(CStateManager&, EStateMsg, float);

File diff suppressed because it is too large Load Diff

View File

@ -15,18 +15,18 @@ class CSpacePirate;
class CPirateRagDoll : public CRagDoll
{
CSpacePirate* x6c_spacePirate;
u16 x70_s1;
float x74_ = 0.f;
zeus::CVector3f x78_;
zeus::CVector3f x84_;
u16 x70_thudSfx;
float x74_sfxTimer = 0.f;
zeus::CVector3f x78_lastSFXPos;
zeus::CVector3f x84_torsoImpulse;
rstl::reserved_vector<TUniqueId, 4> x90_waypoints;
rstl::reserved_vector<u32, 4> x9c_wpParticleIdxs;
bool xb0_24_ : 1;
bool xb0_24_initSfx : 1;
public:
CPirateRagDoll(CStateManager& mgr, CSpacePirate* sp, u16 s1, u32 flags);
CPirateRagDoll(CStateManager& mgr, CSpacePirate* sp, u16 thudSfx, u32 flags);
void PreRender(const zeus::CVector3f& v, CModelData& mData);
void Update(CStateManager& mgr, float dt, float f2);
void Update(CStateManager& mgr, float dt, float waterTop);
void Prime(CStateManager& mgr, const zeus::CTransform& xf, CModelData& mData);
};
@ -44,23 +44,23 @@ private:
float x8_;
float xc_;
float x10_;
float x14_;
u32 x18_;
float x14_hearNoiseRange;
u32 x18_flags;
bool x1c_;
CProjectileInfo x20_;
CProjectileInfo x20_mainProjectileInfo;
u16 x48_;
CDamageInfo x4c_;
float x68_;
CProjectileInfo x6c_;
float x94_;
u16 x98_;
float x9c_;
float xa0_;
u16 x98_ragdollThudSfx;
float x9c_averageNextShotTime;
float xa0_nextShotTimeVariation;
u16 xa4_;
float xa8_;
float xa8_aimDelayTime;
u32 xac_firstBurstCount;
float xb0_;
float xb4_;
float xb0_minCloakAlpha;
float xb4_maxCloakAlpha;
float xb8_;
float xbc_;
u16 xc0_;
@ -76,24 +76,24 @@ private:
{
struct
{
bool x634_24_ : 1;
bool x634_25_ : 1;
bool x634_24_pendingAmbush : 1;
bool x634_25_ceilingAmbush : 1;
bool x634_26_ : 1;
bool x634_27_ : 1;
bool x634_27_melee : 1;
bool x634_28_ : 1;
bool x634_29_ : 1;
bool x634_29_onlyAttackInRange : 1;
bool x634_30_ : 1;
bool x634_31_ : 1;
bool x635_24_ : 1;
bool x635_25_ : 1;
bool x635_26_ : 1;
bool x635_27_ : 1;
bool x635_27_shadowPirate : 1;
bool x635_28_ : 1;
bool x635_29_ : 1;
bool x635_30_ : 1;
bool x635_31_ : 1;
bool x635_30_ragdollKeepAlive : 1;
bool x635_31_ragdollNoAiCollision : 1;
bool x636_24_trooper : 1;
bool x636_25_ : 1;
bool x636_25_hearNoise : 1;
bool x636_26_ : 1;
bool x636_27_ : 1;
bool x636_28_ : 1;
@ -102,19 +102,19 @@ private:
bool x636_31_ : 1;
bool x637_24_ : 1;
bool x637_25_ : 1;
bool x637_26_ : 1;
bool x637_27_ : 1;
bool x637_26_hearPlayerFire : 1;
bool x637_27_inProjectilePath : 1;
bool x637_28_ : 1;
bool x637_29_ : 1;
bool x637_30_ : 1;
bool x637_31_prevInCineCam : 1;
bool x638_24_ : 1;
bool x638_24_pendingFrenzyChance : 1;
bool x638_25_ : 1;
bool x638_26_ : 1;
bool x638_27_ : 1;
bool x638_28_ : 1;
bool x638_29_ : 1;
bool x638_30_ : 1;
bool x638_30_ragdollOver : 1;
bool x638_31_ : 1;
bool x639_24_ : 1;
bool x639_25_ : 1;
@ -130,22 +130,22 @@ private:
u64 _dummy = 0;
};
u32 x63c_ = 0;
s32 x63c_frenzyFrames = 0;
TUniqueId x640_ = kInvalidUniqueId;
TUniqueId x642_ = kInvalidUniqueId;
float x644_ = 1.f;
zeus::CVector3f x648_ = zeus::CVector3f::skForward;
zeus::CVector3f x654_;
CPathFindSearch x660_;
CPathFindSearch x660_pathFindSearch;
float x744_ = 0.f;
float x748_ = 0.f;
u32 x74c_ = 0;
float x750_;
float x750_initialHP;
float x754_ = 0.f;
CSegId x758_headSeg;
u32 x75c_ = 0;
s32 x760_ = -1;
CBoneTracking x764_;
CBoneTracking x764_boneTracking;
s32 x79c_ = -1;
float x7a4_intoJumpDist = 1.f;
float x7a8_ = 2.f;
@ -157,8 +157,8 @@ private:
CSegId x7b8_wristSeg;
CSegId x7b9_swooshSeg;
float x7bc_ = 1.f;
TUniqueId x7c0_ = kInvalidUniqueId;
CBurstFire x7c4_;
TUniqueId x7c0_targetId = kInvalidUniqueId;
CBurstFire x7c4_burstFire;
float x824_ = 3.f;
zeus::CVector3f x828_;
s32 x834_ = -1;
@ -168,20 +168,20 @@ private:
s32 x844_ = -1;
float x848_dodgeDist = 3.f;
float x84c_breakDodgeDist = 3.f;
float x850_ = FLT_MAX;
float x854_ = FLT_MAX;
float x858_ = 0.f;
float x850_timeSinceHitByPlayer = FLT_MAX;
float x854_lowHealthFrenzyTimer = FLT_MAX;
float x858_ragdollDelayTimer = 0.f;
std::unique_ptr<CPirateRagDoll> x85c_ragDoll;
CIkChain x860_ikChain;
float x8a8_ = 0.f;
float x8ac_ = 0.f;
float x8b0_ = 0.f;
float x8b4_ = 0.5f;
float x8b8_;
float x8bc_;
float x8a8_cloakDelayTimer = 0.f;
float x8ac_electricParticleTimer = 0.f;
float x8b0_cloakStepTime = 0.f;
float x8b4_shadowPirateAlpha = 0.5f;
float x8b8_minCloakAlpha;
float x8bc_maxCloakAlpha;
float x8c0_;
float x8c4_;
TUniqueId x8c8_ = kInvalidUniqueId;
float x8c4_aimDelayTimer;
TUniqueId x8c8_teamAiMgrId = kInvalidUniqueId;
zeus::CColor x8cc_trooperColor = zeus::CColor::skWhite;
zeus::CVector2f x8d0_;
float x8d8_ = 0.f;
@ -201,11 +201,111 @@ private:
static const SBurst skBurstsQuick[];
static const SBurst* skBursts[];
static std::list<TUniqueId> mChargePlayerList;
void UpdateCloak(float dt, CStateManager& mgr);
bool ShouldFrenzy(CStateManager& mgr);
void ResetTeamAiRole(CStateManager& mgr);
bool CheckTargetable(CStateManager& mgr);
void FireProjectile(float dt, CStateManager& mgr);
void UpdateAttacks(float dt, CStateManager& mgr);
zeus::CVector3f GetTargetPos(CStateManager& mgr);
void UpdateAimBodyState(float dt, CStateManager& mgr);
void SetCinematicCollision(CStateManager& mgr);
void SetNonCinematicCollision(CStateManager& mgr);
void CheckForProjectiles(CStateManager& mgr);
public:
CSpacePirate(TUniqueId, std::string_view, const CEntityInfo&, const zeus::CTransform&, CModelData&&,
const CActorParameters&, const CPatternedInfo&, CInputStream&, u32);
void Accept(IVisitor &visitor);
void Think(float dt, CStateManager&);
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();
void Touch(CActor& other, CStateManager& mgr);
zeus::CAABox GetSortingBounds(const CStateManager& mgr) const;
void DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt);
void Death(CStateManager& mgr, const zeus::CVector3f& direction, EScriptObjectState state);
void KnockBack(const zeus::CVector3f&, CStateManager&, const CDamageInfo& info,
EKnockBackType type, bool inDeferred, float magnitude);
bool IsListening() const;
bool Listen(const zeus::CVector3f&, EListenNoiseType);
zeus::CVector3f GetOrigin(const CStateManager& mgr, const CTeamAiRole& role) const;
void Patrol(CStateManager&, EStateMsg, float);
void Dead(CStateManager&, EStateMsg, float);
void PathFind(CStateManager&, EStateMsg, float);
void TargetPatrol(CStateManager&, EStateMsg, float);
void TargetCover(CStateManager&, EStateMsg, float);
void Halt(CStateManager&, EStateMsg, float);
void Run(CStateManager&, EStateMsg, float);
void Generate(CStateManager&, EStateMsg, float);
void Deactivate(CStateManager&, EStateMsg, float);
void Attack(CStateManager&, EStateMsg, float);
void JumpBack(CStateManager&, EStateMsg, float);
void DoubleSnap(CStateManager&, EStateMsg, float);
void Shuffle(CStateManager&, EStateMsg, float);
void TurnAround(CStateManager&, EStateMsg, float);
void Skid(CStateManager&, EStateMsg, float);
void CoverAttack(CStateManager&, EStateMsg, float);
void Crouch(CStateManager&, EStateMsg, float);
void GetUp(CStateManager&, EStateMsg, float);
void Taunt(CStateManager&, EStateMsg, float);
void Flee(CStateManager&, EStateMsg, float);
void Lurk(CStateManager&, EStateMsg, float);
void Jump(CStateManager&, EStateMsg, float);
void Dodge(CStateManager&, EStateMsg, float);
void Cover(CStateManager&, EStateMsg, float);
void Approach(CStateManager&, EStateMsg, float);
void WallHang(CStateManager&, EStateMsg, float);
void WallDetach(CStateManager&, EStateMsg, float);
void Enraged(CStateManager&, EStateMsg, float);
void SpecialAttack(CStateManager&, EStateMsg, float);
void Bounce(CStateManager&, EStateMsg, float);
void PathFindEx(CStateManager&, EStateMsg, float);
bool Leash(CStateManager&, float);
bool OffLine(CStateManager&, float);
bool Attacked(CStateManager&, float);
bool InRange(CStateManager&, float);
bool SpotPlayer(CStateManager&, float);
bool PatternOver(CStateManager&, float);
bool PatternShagged(CStateManager&, float);
bool AnimOver(CStateManager&, float);
bool ShouldAttack(CStateManager&, float);
bool ShouldJumpBack(CStateManager&, float);
bool Stuck(CStateManager&, float);
bool Landed(CStateManager&, float);
bool HearShot(CStateManager&, float);
bool HearPlayer(CStateManager&, float);
bool CoverCheck(CStateManager&, float);
bool CoverFind(CStateManager&, float);
bool CoverBlown(CStateManager&, float);
bool CoverNearlyBlown(CStateManager&, float);
bool CoveringFire(CStateManager&, float);
bool LineOfSight(CStateManager&, float);
bool AggressionCheck(CStateManager&, float);
bool ShouldDodge(CStateManager&, float);
bool ShouldRetreat(CStateManager&, float);
bool ShouldCrouch(CStateManager&, float);
bool ShouldMove(CStateManager&, float);
bool ShotAt(CStateManager&, float);
bool HasTargetingPoint(CStateManager&, float);
bool ShouldWallHang(CStateManager&, float);
bool StartAttack(CStateManager&, float);
bool BreakAttack(CStateManager&, float);
bool ShouldStrafe(CStateManager&, float);
bool ShouldSpecialAttack(CStateManager&, float);
bool LostInterest(CStateManager&, float);
bool BounceFind(CStateManager&, float);
CPathFindSearch* GetSearchPath();
u8 GetModelAlphau8(const CStateManager& mgr) const;
float GetGravityConstant() const;
CProjectileInfo* GetProjectileInfo();
};
}

View File

@ -51,7 +51,7 @@ void CBomb::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManag
mgr.AddObject(gameLight);
mgr.AddWeaponId(xec_ownerId, xf0_weaponType);
CSfxManager::AddEmitter(SFXwpn_bomb_drop, GetTranslation(), {}, true, false, 0x7f, -1);
mgr.InformListeners(GetTranslation(), EListenNoiseType::Bomb);
mgr.InformListeners(GetTranslation(), EListenNoiseType::BombExplode);
return;
}
else if (msg == EScriptObjectMessage::Deleted)
@ -166,7 +166,7 @@ void CBomb::Explode(const zeus::CVector3f& pos, CStateManager& mgr)
{
mgr.ApplyDamageToWorld(xec_ownerId, *this, pos, x12c_curDamageInfo, xf8_filter);
CSfxManager::AddEmitter(SFXwpn_bomb_explo, GetTranslation(), {}, true, false, 0x7f, -1);
mgr.InformListeners(pos, EListenNoiseType::Bomb);
mgr.InformListeners(pos, EListenNoiseType::BombExplode);
mgr.RemoveWeaponId(xec_ownerId, xf0_weaponType);
x190_24_isNotDetonated = false;

View File

@ -33,6 +33,7 @@ public:
void SetAvoidAccuracy(bool b) { x14_25_avoidAccuracy = b; }
void SetBurstType(s32 type) { x0_burstType = type; }
void SetTimeToNextShot(float t) { x8_timeToNextShot = t; }
float GetTimeToNextShot() const { return x8_timeToNextShot; }
s32 GetBurstType() const { return x0_burstType; }
void Start(CStateManager& mgr);
void Update(CStateManager& mgr, float dt);

View File

@ -334,7 +334,7 @@ bool CEnergyProjectile::Explode(const zeus::CVector3f& pos, const zeus::CVector3
}
PlayImpactSound(pos, type);
mgr.InformListeners(pos, EListenNoiseType::Projectile);
mgr.InformListeners(pos, EListenNoiseType::ProjectileExplode);
if (auto particle = x170_projectile.CollisionOccured(type, !done, retargetPlayer, offsetPos, normal, targetPos))
{
zeus::CTransform particleXf = zeus::lookAt(zeus::CVector3f::skZero, normal);

View File

@ -1533,7 +1533,7 @@ void CPlayerGun::FireSecondary(float dt, CStateManager& mgr)
fireXf.origin += mgr.GetCameraManager()->GetGlobalCameraTranslation(mgr);
x744_auxWeapon->Fire(dt, x834_27_underwater, x310_currentBeam, x330_chargeState, fireXf,
mgr, x72c_currentBeam->GetWeaponType(), targetId);
mgr.InformListeners(x4a8_gunWorldXf.origin, EListenNoiseType::Character);
mgr.InformListeners(x4a8_gunWorldXf.origin, EListenNoiseType::PlayerFire);
x3a0_missileExitTimer = 7.f;
if (!x832_26_comboFiring)
{
@ -1659,7 +1659,7 @@ void CPlayerGun::UpdateNormalShotCycle(float dt, CStateManager& mgr)
homingTarget = kInvalidUniqueId;
x72c_currentBeam->Fire(x834_27_underwater, dt, x330_chargeState, xf, mgr, homingTarget,
x340_chargeBeamFactor, x340_chargeBeamFactor);
mgr.InformListeners(x4a8_gunWorldXf.origin, EListenNoiseType::Character);
mgr.InformListeners(x4a8_gunWorldXf.origin, EListenNoiseType::PlayerFire);
}
void CPlayerGun::ProcessNormalState(u32 releasedStates, u32 pressedStates, CStateManager& mgr, float dt)

View File

@ -44,7 +44,7 @@ void CPowerBomb::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CState
if (mgr.GetPlayerState()->IsPlayerAlive())
{
CSfxManager::AddEmitter(SFXsfx0710, GetTranslation(), {}, true, false, 0x7f, -1);
mgr.InformListeners(GetTranslation(), EListenNoiseType::Bomb);
mgr.InformListeners(GetTranslation(), EListenNoiseType::BombExplode);
}
else
{

View File

@ -420,7 +420,7 @@ void CActor::OnScanStateChanged(EScanState state, CStateManager& mgr)
zeus::CAABox CActor::GetSortingBounds(const CStateManager&) const { return x9c_renderBounds; }
void CActor::DoUserAnimEvent(CStateManager&, CInt32POINode&, EUserEventType event, float)
void CActor::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType event, float dt)
{
if (event == EUserEventType::LoopedSoundStop)
RemoveEmitter();

View File

@ -132,7 +132,7 @@ public:
virtual void FluidFXThink(EFluidState, CScriptWater&, CStateManager&);
virtual void OnScanStateChanged(EScanState, CStateManager&);
virtual zeus::CAABox GetSortingBounds(const CStateManager&) const;
virtual void DoUserAnimEvent(CStateManager&, CInt32POINode&, EUserEventType, float dt);
virtual void DoUserAnimEvent(CStateManager&, const CInt32POINode&, EUserEventType, float dt);
void RemoveEmitter();
void SetVolume(float vol);

View File

@ -17,14 +17,16 @@ namespace urde
enum class EListenNoiseType
{
Character,
Bomb,
Projectile
PlayerFire,
BombExplode,
ProjectileExplode
};
class CAiFuncMap;
class CStateManager;
class CScriptWater;
class CTeamAiRole;
class CAi : public CPhysicsActor
{
static CAiFuncMap* m_FuncMap;
@ -52,12 +54,13 @@ public:
virtual void TakeDamage(const zeus::CVector3f& direction, float magnitude) {}
virtual bool CanBeShot(const CStateManager&, int) { return true; }
virtual bool IsListening() const { return false; }
virtual int Listen(const zeus::CVector3f&, EListenNoiseType) { return 0; }
virtual bool Listen(const zeus::CVector3f&, EListenNoiseType) { return 0; }
virtual EWeaponCollisionResponseTypes GetCollisionResponseType(const zeus::CVector3f&, const zeus::CVector3f&,
const CWeaponMode&, EProjectileAttrib) const;
void FluidFXThink(EFluidState, CScriptWater&, CStateManager&);
virtual zeus::CVector3f GetOrigin() const { return x34_transform.origin; }
virtual zeus::CVector3f GetOrigin(const CStateManager& mgr, const CTeamAiRole& role) const
{ return x34_transform.origin; }
virtual void Patrol(CStateManager&, EStateMsg, float) {}
virtual void FollowPattern(CStateManager&, EStateMsg, float) {}
virtual void Dead(CStateManager&, EStateMsg, float) {}
@ -116,7 +119,7 @@ public:
virtual bool InAttackPosition(CStateManager&, float) { return false; }
virtual bool Leash(CStateManager&, float) { return false; }
virtual bool OffLine(CStateManager&,float) { return false; }
virtual bool OffLine(CStateManager&, float) { return false; }
virtual bool Attacked(CStateManager&, float) { return false; }
virtual bool PathShagged(CStateManager&, float) { return false; }
virtual bool PathOver(CStateManager&, float) { return false; }
@ -146,20 +149,20 @@ public:
virtual bool Stuck(CStateManager&, float) { return false; }
virtual bool NoPathNodes(CStateManager&, float) { return false; }
virtual bool Landed(CStateManager&, float) { return false; }
virtual bool HearShot(CStateManager&,float) { return false; }
virtual bool HearPlayer(CStateManager&,float) { return false; }
virtual bool HearShot(CStateManager&, float) { return false; }
virtual bool HearPlayer(CStateManager&, float) { return false; }
virtual bool CoverCheck(CStateManager&, float) { return false; }
virtual bool CoverFind(CStateManager&, float) { return false; }
virtual bool CoverBlown(CStateManager&, float) { return false; }
virtual bool CoverNearlyBlown(CStateManager&, float) { return false; }
virtual bool CoveringFire(CStateManager&, float) { return false; }
virtual bool GotUp(CStateManager&, float) { return false; }
virtual bool LineOfSight(CStateManager&,float) { return false; }
virtual bool LineOfSight(CStateManager&, float) { return false; }
virtual bool AggressionCheck(CStateManager&, float) { return false; }
virtual bool AttackOver(CStateManager&, float) { return false; }
virtual bool ShouldTaunt(CStateManager&,float) { return false; }
virtual bool Inside(CStateManager&,float) { return false; }
virtual bool ShouldFire(CStateManager&,float) { return false; }
virtual bool Inside(CStateManager&, float) { return false; }
virtual bool ShouldFire(CStateManager&, float) { return false; }
virtual bool ShouldFlinch(CStateManager&, float) { return false; }
virtual bool PatrolPathOver(CStateManager&, float) { return false; }
virtual bool ShouldDodge(CStateManager&, float) { return false; }

View File

@ -19,6 +19,7 @@
#include "Camera/CFirstPersonCamera.hpp"
#include "World/CScriptWaypoint.hpp"
#include "World/CScriptActorKeyframe.hpp"
#include "Weapon/CEnergyProjectile.hpp"
namespace urde
{
@ -1171,10 +1172,9 @@ void CPatterned::Freeze(CStateManager& mgr, const zeus::CVector3f& pos,
zeus::CVector3f CPatterned::GetGunEyePos() const
{
zeus::CVector3f origin = GetOrigin();
zeus::CVector3f origin = GetTranslation();
zeus::CAABox baseBox = GetBaseBoundingBox();
origin.z = 0.6f * (baseBox.max.z - baseBox.min.z) + origin.z;
return origin;
}
@ -1187,6 +1187,98 @@ void CPatterned::SetupPlayerCollision(bool v)
SetMaterialFilter(CMaterialFilter::MakeIncludeExclude(include, exclude));
}
void CPatterned::LaunchProjectile(
const zeus::CTransform& gunXf, CStateManager& mgr, int maxAllowed, EProjectileAttrib attrib,
bool playerHoming, const std::experimental::optional<TLockedToken<CGenDescription>>& visorParticle,
u16 visorSfx, bool sendCollideMsg, const zeus::CVector3f& scale)
{
CProjectileInfo* pInfo = GetProjectileInfo();
if (pInfo->Token().IsLoaded())
{
if (mgr.CanCreateProjectile(GetUniqueId(), EWeaponType::AI, maxAllowed))
{
TUniqueId homingId = playerHoming ? mgr.GetPlayer().GetUniqueId() : kInvalidUniqueId;
CEnergyProjectile* newProjectile = new CEnergyProjectile(true, pInfo->Token(), EWeaponType::AI,
gunXf, EMaterialTypes::Character, pInfo->GetDamage(), mgr.AllocateUniqueId(), GetAreaIdAlways(),
GetUniqueId(), homingId, attrib, false, scale, visorParticle, visorSfx, sendCollideMsg);
mgr.AddObject(newProjectile);
}
}
}
void CPatterned::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt)
{
switch (type)
{
case EUserEventType::Projectile:
{
zeus::CTransform lctrXf = GetLctrTransform(node.GetLocatorName());
zeus::CVector3f aimPos = mgr.GetPlayer().GetAimPosition(mgr, 0.f);
if ((aimPos - lctrXf.origin).normalized().dot(lctrXf.basis[1]) > 0.f)
{
zeus::CTransform gunXf = zeus::lookAt(lctrXf.origin, aimPos);
LaunchProjectile(gunXf, mgr, 1, EProjectileAttrib::None, false, {}, 0xffff, false, zeus::CVector3f::skOne);
}
else
{
LaunchProjectile(lctrXf, mgr, 1, EProjectileAttrib::None, false, {}, 0xffff, false, zeus::CVector3f::skOne);
}
break;
}
case EUserEventType::DamageOn:
{
zeus::CTransform lctrXf = GetLctrTransform(node.GetLocatorName());
zeus::CVector3f xfOrigin = x34_transform * (x64_modelData->GetScale() * lctrXf.origin);
zeus::CVector3f margin = zeus::CVector3f(1.f, 1.f, 0.5f) * x64_modelData->GetScale();
if (zeus::CAABox(xfOrigin - margin, xfOrigin + margin).intersects(mgr.GetPlayer().GetBoundingBox()))
{
mgr.ApplyDamage(GetUniqueId(), mgr.GetPlayer().GetUniqueId(), GetUniqueId(),
GetContactDamage(), CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {}),
zeus::CVector3f::skZero);
}
break;
}
case EUserEventType::Delete:
{
if (!x400_25_alive)
{
if (!x400_27_fadeToDeath)
{
x3e8_alphaDelta = -0.333333f;
x400_27_fadeToDeath = true;
}
RemoveMaterial(EMaterialTypes::Character, EMaterialTypes::Solid,
EMaterialTypes::Target, EMaterialTypes::Orbit, mgr);
AddMaterial(EMaterialTypes::ProjectilePassthrough, mgr);
}
else
{
DeathDelete(mgr);
}
break;
}
case EUserEventType::BreakLockOn:
{
RemoveMaterial(EMaterialTypes::Character,
EMaterialTypes::Target, EMaterialTypes::Orbit, mgr);
break;
}
case EUserEventType::BecomeShootThrough:
{
AddMaterial(EMaterialTypes::ProjectilePassthrough, mgr);
break;
}
case EUserEventType::RemoveCollision:
{
RemoveMaterial(EMaterialTypes::Solid, mgr);
break;
}
default:
break;
}
CActor::DoUserAnimEvent(mgr, node, type, dt);
}
void CPatterned::UpdateAlphaDelta(float dt, CStateManager& mgr)
{
if (x3e8_alphaDelta == 0.f)

View File

@ -408,6 +408,10 @@ public:
CBodyController* BodyController() { return x450_bodyController.get(); }
const CKnockBackController& GetKnockBackController() const { return x460_knockBackController; }
void SetupPlayerCollision(bool);
void LaunchProjectile(const zeus::CTransform& gunXf, CStateManager& mgr, int maxAllowed, EProjectileAttrib attrib,
bool playerHoming, const std::experimental::optional<TLockedToken<CGenDescription>>& visorParticle,
u16 visorSfx, bool sendCollideMsg, const zeus::CVector3f& scale);
void DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt);
void SetDestPos(const zeus::CVector3f& pos) { x2e0_destPos = pos; }
void UpdateAlphaDelta(float dt, CStateManager& mgr);

View File

@ -688,6 +688,7 @@ public:
float GetMoveSpeed() const { return x4f8_moveSpeed; }
EPlayerOrbitRequest GetOrbitRequest() const { return x30c_orbitRequest; }
bool IsShowingCrosshairs() const { return x9c4_25_showCrosshairs; }
bool IsSidewaysDashing() const { return x37c_sidewaysDashing; }
};
}

View File

@ -1,28 +1,435 @@
#include "CTeamAiMgr.hpp"
#include "TCastTo.hpp"
#include "CStateManager.hpp"
#include "CPlayer.hpp"
namespace urde
{
struct TeamAiRoleSorter
{
zeus::CVector3f x0_pos;
s32 xc_type;
bool operator()(const CTeamAiRole& a, const CTeamAiRole& b) const
{
float aDist = (x0_pos - a.GetTeamPosition()).magSquared();
float bDist = (x0_pos - b.GetTeamPosition()).magSquared();
switch (xc_type)
{
case 0:
return a.GetOwnerId() < b.GetOwnerId();
case 1:
return aDist < bDist;
default:
if (a.GetTeamAiRole() == b.GetTeamAiRole())
return aDist < bDist;
else
return a.GetTeamAiRole() < b.GetTeamAiRole();
}
}
TeamAiRoleSorter(const zeus::CVector3f& pos, s32 type) : x0_pos(pos), xc_type(type) {}
};
CTeamAiData::CTeamAiData(CInputStream& in, s32 propCount)
: x0_(in.readUint32Big())
, x4_(in.readUint32Big())
, x8_(in.readUint32Big())
, xc_(in.readUint32Big())
, x10_(in.readUint32Big())
, x14_(in.readUint32Big())
, x18_(in.readUint32Big())
, x1c_(propCount > 8 ? in.readFloatBig() : 0.f)
, x20_(propCount > 8 ? in.readFloatBig() : 0.f)
: x0_aiCount(in.readUint32Big())
, x4_meleeCount(in.readUint32Big())
, x8_projectileCount(in.readUint32Big())
, xc_unknownCount(in.readUint32Big())
, x10_maxMeleeAttackerCount(in.readUint32Big())
, x14_maxProjectileAttackerCount(in.readUint32Big())
, x18_positionMode(in.readUint32Big())
, x1c_meleeTimeInterval(propCount > 8 ? in.readFloatBig() : 0.f)
, x20_projectileTimeInterval(propCount > 8 ? in.readFloatBig() : 0.f)
{
}
CTeamAiMgr::CTeamAiMgr(TUniqueId uid, std::string_view name, const CEntityInfo& info, const CTeamAiData& data)
: CEntity(uid, info, true, name)
: CEntity(uid, info, true, name), x34_data(data)
{
if (x34_data.x0_aiCount)
x58_roles.reserve(x34_data.x0_aiCount);
if (x34_data.x4_meleeCount)
x68_meleeAttackers.reserve(x34_data.x4_meleeCount);
if (x34_data.x8_projectileCount)
x78_projectileAttackers.reserve(x34_data.x8_projectileCount);
}
void CTeamAiMgr::Accept(IVisitor& visitor)
{
visitor.Visit(this);
}
void CTeamAiMgr::UpdateTeamCaptain()
{
int maxPriority = INT_MIN;
x8c_teamCaptainId = kInvalidUniqueId;
for (const auto& role : x58_roles)
{
if (role.x18_captainPriority > maxPriority)
{
maxPriority = role.x18_captainPriority;
x8c_teamCaptainId = role.GetOwnerId();
}
}
}
bool CTeamAiMgr::ShouldUpdateRoles(float dt)
{
if (x58_roles.empty())
return false;
x88_timeDirty += dt;
if (x88_timeDirty >= 1.5f)
return true;
for (const auto& role : x58_roles)
{
if (role.GetTeamAiRole() <= CTeamAiRole::ETeamAiRole::Initial ||
role.GetTeamAiRole() > CTeamAiRole::ETeamAiRole::Unassigned)
return true;
}
return false;
}
void CTeamAiMgr::ResetRoles(CStateManager& mgr)
{
for (auto& role : x58_roles)
{
role.x10_curRole = CTeamAiRole::ETeamAiRole::Initial;
role.x14_roleIndex = 0;
if (const CAi* ai = static_cast<const CAi*>(mgr.GetObjectById(role.GetOwnerId())))
role.x1c_position = ai->GetTranslation();
}
}
void CTeamAiMgr::SpacingSort(CStateManager& mgr, const zeus::CVector3f& pos)
{
TeamAiRoleSorter sorter(pos, 2);
std::sort(x58_roles.begin(), x58_roles.end(), sorter);
float tierStagger = 4.5f;
for (const auto& role : x58_roles)
{
if (TCastToPtr<CAi> ai = mgr.ObjectById(role.GetOwnerId()))
{
float length = (ai->GetBaseBoundingBox().max.y - ai->GetBaseBoundingBox().min.y) * 1.5f;
if (length > tierStagger)
tierStagger = length;
}
}
float curTierDist = tierStagger;
int tierTeamSize = 0;
int maxTierTeamSize = 3;
for (auto& role : x58_roles)
{
if (TCastToPtr<CAi> ai = mgr.ObjectById(role.GetOwnerId()))
{
zeus::CVector3f delta = ai->GetTranslation() - pos;
zeus::CVector3f newPos;
if (delta.canBeNormalized())
newPos = pos + delta.normalized() * curTierDist;
else
newPos = pos + ai->GetTransform().basis[1] * curTierDist;
role.x1c_position = newPos;
role.x1c_position.z = ai->GetTranslation().z;
tierTeamSize += 1;
if (tierTeamSize > maxTierTeamSize)
{
curTierDist += tierStagger;
tierTeamSize = 0;
maxTierTeamSize += 1;
}
}
}
TeamAiRoleSorter sorter2(pos, 0);
std::sort(x58_roles.begin(), x58_roles.end(), sorter2);
}
void CTeamAiMgr::PositionTeam(CStateManager& mgr)
{
zeus::CVector3f aimPos = mgr.GetPlayer().GetAimPosition(mgr, 0.f);
switch (x34_data.x18_positionMode)
{
case 1:
SpacingSort(mgr, aimPos);
break;
default:
for (auto& role : x58_roles)
if (TCastToPtr<CAi> ai = mgr.ObjectById(role.GetOwnerId()))
role.x1c_position = ai->GetOrigin(mgr, role);
break;
}
}
void CTeamAiMgr::AssignRoles(CTeamAiRole::ETeamAiRole assRole, s32 count)
{
if (count == 0)
return;
s32 lastIdx = 0;
for (auto& role : x58_roles)
{
if (role.GetTeamAiRole() == CTeamAiRole::ETeamAiRole::Initial)
{
if (role.x4_roleA == assRole || role.x8_roleB == assRole || role.xc_roleC == assRole)
{
role.x10_curRole = assRole;
role.x14_roleIndex = lastIdx++;
if (lastIdx == count)
return;
}
}
}
}
void CTeamAiMgr::UpdateRoles(CStateManager& mgr)
{
ResetRoles(mgr);
zeus::CVector3f aimPos = mgr.GetPlayer().GetAimPosition(mgr, 0.f);
TeamAiRoleSorter sorter(aimPos, 1);
std::sort(x58_roles.begin(), x58_roles.end(), sorter);
AssignRoles(CTeamAiRole::ETeamAiRole::Melee, x34_data.x4_meleeCount);
AssignRoles(CTeamAiRole::ETeamAiRole::Projectile, x34_data.x8_projectileCount);
AssignRoles(CTeamAiRole::ETeamAiRole::Unknown, x34_data.xc_unknownCount);
for (auto& role : x58_roles)
{
if (role.GetTeamAiRole() <= CTeamAiRole::ETeamAiRole::Initial ||
role.GetTeamAiRole() > CTeamAiRole::ETeamAiRole::Unassigned)
role.SetTeamAiRole(CTeamAiRole::ETeamAiRole::Unassigned);
}
TeamAiRoleSorter sorter2(aimPos, 0);
std::sort(x58_roles.begin(), x58_roles.end(), sorter2);
x88_timeDirty = 0.f;
}
void CTeamAiMgr::Think(float dt, CStateManager& mgr)
{
CEntity::Think(dt, mgr);
if (ShouldUpdateRoles(dt))
UpdateRoles(mgr);
PositionTeam(mgr);
x90_timeSinceMelee += dt;
x94_timeSinceProjectile += dt;
}
void CTeamAiMgr::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId objId, CStateManager& mgr)
{
CEntity::AcceptScriptMsg(msg, objId, mgr);
}
CTeamAiRole* CTeamAiMgr::GetTeamAiRole(TUniqueId aiId)
{
auto search = rstl::binary_find(x58_roles.begin(), x58_roles.end(), aiId,
[](const auto& obj) { return obj.GetOwnerId(); });
return search != x58_roles.end() ? &*search : nullptr;
}
bool CTeamAiMgr::IsPartOfTeam(TUniqueId aiId) const
{
auto search = rstl::binary_find(x58_roles.begin(), x58_roles.end(), aiId,
[](const auto& obj) { return obj.GetOwnerId(); });
return search != x58_roles.end();
}
bool CTeamAiMgr::HasTeamAiRole(TUniqueId aiId) const
{
auto search = rstl::binary_find(x58_roles.begin(), x58_roles.end(), aiId,
[](const auto& obj) { return obj.GetOwnerId(); });
return (search != x58_roles.end() &&
search->GetTeamAiRole() > CTeamAiRole::ETeamAiRole::Initial &&
search->GetTeamAiRole() <= CTeamAiRole::ETeamAiRole::Unassigned);
}
bool CTeamAiMgr::IsMeleeAttacker(TUniqueId aiId) const
{
auto search = rstl::binary_find(x68_meleeAttackers.begin(), x68_meleeAttackers.end(), aiId);
return search != x68_meleeAttackers.end();
}
bool CTeamAiMgr::CanAcceptMeleeAttacker(TUniqueId aiId) const
{
if (x90_timeSinceMelee >= x34_data.x1c_meleeTimeInterval &&
x68_meleeAttackers.size() < x34_data.x10_maxMeleeAttackerCount)
return true;
return IsMeleeAttacker(aiId);
}
bool CTeamAiMgr::AddMeleeAttacker(TUniqueId aiId)
{
if (x90_timeSinceMelee >= x34_data.x1c_meleeTimeInterval &&
x68_meleeAttackers.size() < x34_data.x10_maxMeleeAttackerCount && HasTeamAiRole(aiId))
{
auto search = rstl::binary_find(x68_meleeAttackers.begin(), x68_meleeAttackers.end(), aiId);
if (search == x68_meleeAttackers.end())
{
x68_meleeAttackers.insert(std::lower_bound(
x68_meleeAttackers.begin(), x68_meleeAttackers.end(), aiId), aiId);
x90_timeSinceMelee = 0.f;
}
return true;
}
return false;
}
void CTeamAiMgr::RemoveMeleeAttacker(TUniqueId aiId)
{
auto search = rstl::binary_find(x68_meleeAttackers.begin(), x68_meleeAttackers.end(), aiId);
if (search != x68_meleeAttackers.end())
x68_meleeAttackers.erase(search);
}
bool CTeamAiMgr::IsProjectileAttacker(TUniqueId aiId) const
{
auto search = rstl::binary_find(x78_projectileAttackers.begin(), x78_projectileAttackers.end(), aiId);
return search != x78_projectileAttackers.end();
}
bool CTeamAiMgr::CanAcceptProjectileAttacker(TUniqueId aiId) const
{
if (x94_timeSinceProjectile >= x34_data.x20_projectileTimeInterval &&
x78_projectileAttackers.size() < x34_data.x14_maxProjectileAttackerCount)
return true;
return IsProjectileAttacker(aiId);
}
bool CTeamAiMgr::AddProjectileAttacker(TUniqueId aiId)
{
if (x94_timeSinceProjectile >= x34_data.x20_projectileTimeInterval &&
x78_projectileAttackers.size() < x34_data.x14_maxProjectileAttackerCount && HasTeamAiRole(aiId))
{
auto search = rstl::binary_find(x78_projectileAttackers.begin(), x78_projectileAttackers.end(), aiId);
if (search == x78_projectileAttackers.end())
{
x78_projectileAttackers.insert(std::lower_bound(
x78_projectileAttackers.begin(), x78_projectileAttackers.end(), aiId), aiId);
x94_timeSinceProjectile = 0.f;
}
return true;
}
return false;
}
void CTeamAiMgr::RemoveProjectileAttacker(TUniqueId aiId)
{
auto search = rstl::binary_find(x78_projectileAttackers.begin(), x78_projectileAttackers.end(), aiId);
if (search != x78_projectileAttackers.end())
x78_projectileAttackers.erase(search);
}
bool CTeamAiMgr::AssignTeamAiRole(const CAi& ai, CTeamAiRole::ETeamAiRole roleA,
CTeamAiRole::ETeamAiRole roleB, CTeamAiRole::ETeamAiRole roleC)
{
CTeamAiRole newRole(ai.GetUniqueId(), roleA, roleB, roleC);
auto search = rstl::binary_find(x58_roles.begin(), x58_roles.end(), newRole);
if (search == x58_roles.end())
{
if (x58_roles.size() >= x58_roles.capacity())
return false;
x58_roles.insert(std::lower_bound(x58_roles.begin(), x58_roles.end(), newRole), newRole);
}
else
{
*search = newRole;
}
UpdateTeamCaptain();
return true;
}
void CTeamAiMgr::RemoveTeamAiRole(TUniqueId aiId)
{
if (IsMeleeAttacker(aiId))
RemoveMeleeAttacker(aiId);
if (IsProjectileAttacker(aiId))
RemoveProjectileAttacker(aiId);
auto search = rstl::binary_find(x58_roles.begin(), x58_roles.end(), aiId,
[](const auto& obj) { return obj.GetOwnerId(); });
x58_roles.erase(search);
UpdateTeamCaptain();
}
void CTeamAiMgr::ClearTeamAiRole(TUniqueId aiId)
{
auto search = rstl::binary_find(x58_roles.begin(), x58_roles.end(), aiId,
[](const auto& obj) { return obj.GetOwnerId(); });
if (search != x58_roles.end())
search->x10_curRole = CTeamAiRole::ETeamAiRole::Initial;
}
s32 CTeamAiMgr::GetNumAssignedOfRole(CTeamAiRole::ETeamAiRole testRole) const
{
s32 ret = 0;
for (const auto& role : x58_roles)
if (role.GetTeamAiRole() == testRole)
++ret;
return ret;
}
s32 CTeamAiMgr::GetNumAssignedAiRoles() const
{
s32 ret = 0;
for (const auto& role : x58_roles)
if (role.GetTeamAiRole() > CTeamAiRole::ETeamAiRole::Initial &&
role.GetTeamAiRole() <= CTeamAiRole::ETeamAiRole::Unassigned)
++ret;
return ret;
}
CTeamAiRole* CTeamAiMgr::GetTeamAiRole(CStateManager& mgr, TUniqueId mgrId, TUniqueId aiId)
{
if (TCastToPtr<CTeamAiMgr> aimgr = mgr.ObjectById(mgrId))
return aimgr->GetTeamAiRole(aiId);
return nullptr;
}
void CTeamAiMgr::ResetTeamAiRole(EAttackType type, CStateManager& mgr, TUniqueId mgrId, TUniqueId aiId, bool clearRole)
{
if (TCastToPtr<CTeamAiMgr> tmgr = mgr.ObjectById(mgrId))
{
if (tmgr->HasTeamAiRole(aiId))
{
if (type == EAttackType::Melee)
{
if (tmgr->IsMeleeAttacker(aiId))
tmgr->RemoveMeleeAttacker(aiId);
}
else if (type == EAttackType::Projectile)
{
if (tmgr->IsProjectileAttacker(aiId))
tmgr->RemoveProjectileAttacker(aiId);
}
if (clearRole)
tmgr->ClearTeamAiRole(aiId);
}
}
}
bool CTeamAiMgr::CanAcceptAttacker(EAttackType type, CStateManager& mgr, TUniqueId mgrId, TUniqueId aiId)
{
if (TCastToPtr<CTeamAiMgr> tmgr = mgr.ObjectById(mgrId))
{
if (tmgr->HasTeamAiRole(aiId))
{
if (type == EAttackType::Melee)
return tmgr->CanAcceptMeleeAttacker(aiId);
else if (type == EAttackType::Projectile)
return tmgr->CanAcceptProjectileAttacker(aiId);
}
}
return false;
}
bool CTeamAiMgr::AddAttacker(EAttackType type, CStateManager& mgr, TUniqueId mgrId, TUniqueId aiId)
{
if (TCastToPtr<CTeamAiMgr> tmgr = mgr.ObjectById(mgrId))
{
if (tmgr->HasTeamAiRole(aiId))
{
if (type == EAttackType::Melee)
return tmgr->AddMeleeAttacker(aiId);
else if (type == EAttackType::Projectile)
return tmgr->AddProjectileAttacker(aiId);
}
}
return false;
}
}

View File

@ -1,21 +1,61 @@
#pragma once
#include "CEntity.hpp"
#include "zeus/CVector3f.hpp"
namespace urde
{
class CStateManager;
class CAi;
class CTeamAiRole
{
friend class CTeamAiMgr;
public:
enum class ETeamAiRole
{
Invalid = -1,
Initial,
Melee,
Projectile,
Unknown,
Unassigned
};
private:
TUniqueId x0_ownerId;
ETeamAiRole x4_roleA = ETeamAiRole::Invalid;
ETeamAiRole x8_roleB = ETeamAiRole::Invalid;
ETeamAiRole xc_roleC = ETeamAiRole::Invalid;
ETeamAiRole x10_curRole = ETeamAiRole::Invalid;
s32 x14_roleIndex = -1;
s32 x18_captainPriority = 0;
zeus::CVector3f x1c_position;
public:
CTeamAiRole(TUniqueId ownerId, ETeamAiRole a, ETeamAiRole b, ETeamAiRole c)
: x0_ownerId(ownerId), x4_roleA(a), x8_roleB(b), xc_roleC(c) {}
TUniqueId GetOwnerId() const { return x0_ownerId; }
bool HasTeamAiRole() const { return false; }
ETeamAiRole GetTeamAiRole() const { return x10_curRole; }
void SetTeamAiRole(ETeamAiRole role) { x10_curRole = role; }
s32 GetRoleIndex() const { return x14_roleIndex; }
void SetRoleIndex(s32 idx) { x14_roleIndex = idx; }
const zeus::CVector3f& GetTeamPosition() const { return x1c_position; }
void SetTeamPosition(const zeus::CVector3f& pos) { x1c_position = pos; }
bool operator<(const CTeamAiRole& other) const { return x0_ownerId < other.x0_ownerId; }
};
class CTeamAiData
{
u32 x0_;
u32 x4_;
u32 x8_;
u32 xc_;
u32 x10_;
u32 x14_;
u32 x18_;
float x1c_;
float x20_;
friend class CTeamAiMgr;
u32 x0_aiCount;
u32 x4_meleeCount;
u32 x8_projectileCount;
u32 xc_unknownCount;
u32 x10_maxMeleeAttackerCount;
u32 x14_maxProjectileAttackerCount;
u32 x18_positionMode;
float x1c_meleeTimeInterval;
float x20_projectileTimeInterval;
public:
CTeamAiData(CInputStream& in, s32 propCount);
};
@ -23,9 +63,57 @@ public:
class CTeamAiMgr : public CEntity
{
public:
CTeamAiMgr(TUniqueId, std::string_view name, const CEntityInfo&, const CTeamAiData& data);
enum class EAttackType
{
Melee,
Projectile
};
private:
CTeamAiData x34_data;
std::vector<CTeamAiRole> x58_roles;
std::vector<TUniqueId> x68_meleeAttackers;
std::vector<TUniqueId> x78_projectileAttackers;
float x88_timeDirty = 0.f;
TUniqueId x8c_teamCaptainId = kInvalidUniqueId;
float x90_timeSinceMelee;
float x94_timeSinceProjectile;
void UpdateTeamCaptain();
bool ShouldUpdateRoles(float dt);
void ResetRoles(CStateManager& mgr);
void AssignRoles(CTeamAiRole::ETeamAiRole role, s32 count);
void UpdateRoles(CStateManager& mgr);
void SpacingSort(CStateManager& mgr, const zeus::CVector3f& pos);
void PositionTeam(CStateManager& mgr);
bool IsMeleeAttacker(TUniqueId aiId) const;
bool CanAcceptMeleeAttacker(TUniqueId aiId) const;
bool AddMeleeAttacker(TUniqueId aiId);
void RemoveMeleeAttacker(TUniqueId aiId);
bool IsProjectileAttacker(TUniqueId aiId) const;
bool CanAcceptProjectileAttacker(TUniqueId aiId) const;
bool AddProjectileAttacker(TUniqueId aiId);
void RemoveProjectileAttacker(TUniqueId aiId);
public:
CTeamAiMgr(TUniqueId uid, std::string_view name, const CEntityInfo& info, const CTeamAiData& data);
void Accept(IVisitor&);
void Think(float dt, CStateManager& mgr);
void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId objId, CStateManager& mgr);
CTeamAiRole* GetTeamAiRole(TUniqueId aiId);
bool IsPartOfTeam(TUniqueId aiId) const;
bool HasTeamAiRole(TUniqueId aiId) const;
bool AssignTeamAiRole(const CAi& ai, CTeamAiRole::ETeamAiRole roleA,
CTeamAiRole::ETeamAiRole roleB, CTeamAiRole::ETeamAiRole roleC);
void RemoveTeamAiRole(TUniqueId aiId);
void ClearTeamAiRole(TUniqueId aiId);
s32 GetNumAssignedOfRole(CTeamAiRole::ETeamAiRole role) const;
s32 GetNumAssignedAiRoles() const;
static CTeamAiRole* GetTeamAiRole(CStateManager& mgr, TUniqueId mgrId, TUniqueId aiId);
static void ResetTeamAiRole(EAttackType type, CStateManager& mgr, TUniqueId mgrId, TUniqueId aiId, bool clearRole);
static bool CanAcceptAttacker(EAttackType type, CStateManager& mgr, TUniqueId mgrId, TUniqueId aiId);
static bool AddAttacker(EAttackType type, CStateManager& mgr, TUniqueId mgrId, TUniqueId aiId);
};
}