2020-03-26 22:09:50 +00:00
|
|
|
#include "Runtime/MP1/World/CShockWave.hpp"
|
|
|
|
|
2020-03-31 07:29:00 +00:00
|
|
|
#include "Runtime/Collision/CCollisionActor.hpp"
|
2020-03-26 22:09:50 +00:00
|
|
|
#include "Runtime/CSimplePool.hpp"
|
|
|
|
#include "Runtime/CStateManager.hpp"
|
|
|
|
#include "Runtime/GameGlobalObjects.hpp"
|
2022-02-25 07:45:25 +00:00
|
|
|
#include "Runtime/Graphics/CCubeRenderer.hpp"
|
2020-03-26 22:09:50 +00:00
|
|
|
#include "Runtime/World/CActorParameters.hpp"
|
2020-03-31 07:29:00 +00:00
|
|
|
#include "Runtime/World/CGameLight.hpp"
|
2020-04-01 06:41:31 +00:00
|
|
|
#include "Runtime/World/CHUDBillboardEffect.hpp"
|
|
|
|
#include "Runtime/World/CPlayer.hpp"
|
2020-03-26 22:09:50 +00:00
|
|
|
|
|
|
|
#include "TCastTo.hpp" // Generated file, do not modify include path
|
|
|
|
|
2021-04-10 08:42:06 +00:00
|
|
|
namespace metaforce::MP1 {
|
2020-03-26 22:09:50 +00:00
|
|
|
CShockWave::CShockWave(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
|
2023-06-21 20:22:49 +00:00
|
|
|
TUniqueId parent, const CShockWaveInfo& data, float minActiveTime, float knockback)
|
2020-03-26 22:09:50 +00:00
|
|
|
: CActor(uid, true, name, info, xf, CModelData::CModelDataNull(), {EMaterialTypes::Projectile},
|
|
|
|
CActorParameters::None(), kInvalidUniqueId)
|
2020-05-07 23:13:43 +00:00
|
|
|
, xe8_parentId(parent)
|
2020-04-01 06:41:31 +00:00
|
|
|
, xec_damageInfo(data.GetDamageInfo())
|
|
|
|
, x108_elementGenDesc(g_SimplePool->GetObj({SBIG('PART'), data.GetParticleDescId()}))
|
2020-03-26 22:09:50 +00:00
|
|
|
, x110_elementGen(std::make_unique<CElementGen>(x108_elementGenDesc))
|
|
|
|
, x114_data(data)
|
2020-05-07 23:13:43 +00:00
|
|
|
, x150_radius(data.GetInitialRadius())
|
|
|
|
, x154_expansionSpeed(data.GetInitialExpansionSpeed())
|
2020-04-01 18:54:01 +00:00
|
|
|
, x15c_minActiveTime(minActiveTime)
|
|
|
|
, x160_knockback(knockback) {
|
2020-04-01 06:41:31 +00:00
|
|
|
if (data.GetWeaponDescId().IsValid()) {
|
|
|
|
x974_electricDesc = g_SimplePool->GetObj({SBIG('ELSC'), data.GetWeaponDescId()});
|
2020-03-26 22:09:50 +00:00
|
|
|
}
|
|
|
|
x110_elementGen->SetParticleEmission(true);
|
|
|
|
x110_elementGen->SetOrientation(GetTransform().getRotation());
|
|
|
|
x110_elementGen->SetGlobalTranslation(GetTranslation());
|
|
|
|
xe6_27_thermalVisorFlags = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CShockWave::Accept(IVisitor& visitor) { visitor.Visit(this); }
|
|
|
|
|
|
|
|
void CShockWave::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) {
|
2020-03-31 07:29:00 +00:00
|
|
|
if (msg == EScriptObjectMessage::Registered) {
|
|
|
|
if (x110_elementGen->SystemHasLight()) {
|
|
|
|
x980_id2 = mgr.AllocateUniqueId();
|
|
|
|
mgr.AddObject(new CGameLight(x980_id2, GetAreaIdAlways(), GetActive(), "ShockWaveLight_" + x10_name,
|
|
|
|
GetTransform(), GetUniqueId(), x110_elementGen->GetLight(),
|
2020-04-01 06:41:31 +00:00
|
|
|
x114_data.GetParticleDescId().Value(), 1, 0.f));
|
2020-03-31 07:29:00 +00:00
|
|
|
}
|
|
|
|
} else if (msg == EScriptObjectMessage::Deleted) {
|
|
|
|
mgr.FreeScriptObject(x980_id2);
|
|
|
|
x980_id2 = kInvalidUniqueId;
|
|
|
|
}
|
2020-03-26 22:09:50 +00:00
|
|
|
CActor::AcceptScriptMsg(msg, uid, mgr);
|
2020-03-31 07:29:00 +00:00
|
|
|
mgr.SendScriptMsgAlways(x980_id2, uid, msg);
|
2020-03-26 22:09:50 +00:00
|
|
|
}
|
|
|
|
|
2020-04-05 11:54:02 +00:00
|
|
|
void CShockWave::AddToRenderer(const zeus::CFrustum& frustum, CStateManager& mgr) {
|
2020-03-26 22:09:50 +00:00
|
|
|
CActor::AddToRenderer(frustum, mgr);
|
|
|
|
g_Renderer->AddParticleGen(*x110_elementGen);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::optional<zeus::CAABox> CShockWave::GetTouchBounds() const {
|
2020-05-07 23:13:43 +00:00
|
|
|
if (x150_radius <= 0.f) {
|
2020-03-31 07:29:00 +00:00
|
|
|
return std::nullopt;
|
|
|
|
}
|
2020-05-07 23:13:43 +00:00
|
|
|
return zeus::CAABox({-x150_radius, -x150_radius, 0.f}, {x150_radius, x150_radius, 1.f})
|
|
|
|
.getTransformedAABox(GetTransform());
|
2020-03-26 22:09:50 +00:00
|
|
|
}
|
|
|
|
|
2020-04-09 17:28:20 +00:00
|
|
|
void CShockWave::Render(CStateManager& mgr) {
|
2020-03-26 22:09:50 +00:00
|
|
|
CActor::Render(mgr);
|
|
|
|
x110_elementGen->Render();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CShockWave::Think(float dt, CStateManager& mgr) {
|
2020-03-31 07:29:00 +00:00
|
|
|
if (GetActive()) {
|
|
|
|
x110_elementGen->Update(dt);
|
2020-04-01 18:54:01 +00:00
|
|
|
x158_activeTime += dt;
|
2020-05-07 23:13:43 +00:00
|
|
|
x150_radius += x154_expansionSpeed * dt;
|
|
|
|
x154_expansionSpeed += dt * x114_data.GetSpeedIncrease();
|
|
|
|
x110_elementGen->SetExternalVar(0, x150_radius);
|
2020-04-06 17:25:28 +00:00
|
|
|
for (size_t i = 0; i < x110_elementGen->GetNumActiveChildParticles(); ++i) {
|
2020-03-31 07:29:00 +00:00
|
|
|
auto& particle = static_cast<CElementGen&>(x110_elementGen->GetActiveChildParticle(i));
|
|
|
|
if (particle.Get4CharId() == SBIG('PART')) {
|
2020-05-07 23:13:43 +00:00
|
|
|
particle.SetExternalVar(0, x150_radius);
|
2020-03-31 07:29:00 +00:00
|
|
|
}
|
|
|
|
}
|
2020-04-01 06:41:31 +00:00
|
|
|
if (x16c_hitPlayerInAir) {
|
|
|
|
x164_timeSinceHitPlayerInAir += dt;
|
|
|
|
x16c_hitPlayerInAir = false;
|
2020-03-31 07:29:00 +00:00
|
|
|
}
|
2020-04-01 06:41:31 +00:00
|
|
|
if (x16d_hitPlayer) {
|
|
|
|
x168_timeSinceHitPlayer += dt;
|
|
|
|
x16d_hitPlayer = false;
|
2020-03-31 07:29:00 +00:00
|
|
|
}
|
|
|
|
}
|
2020-04-01 18:54:01 +00:00
|
|
|
if (x110_elementGen->IsSystemDeletable() && x15c_minActiveTime > 0.f && x158_activeTime >= x15c_minActiveTime) {
|
2020-03-31 07:29:00 +00:00
|
|
|
mgr.FreeScriptObject(GetUniqueId());
|
|
|
|
} else if (x980_id2 != kInvalidUniqueId) {
|
|
|
|
if (TCastToPtr<CGameLight> light = mgr.ObjectById(x980_id2)) {
|
|
|
|
if (light->GetActive()) {
|
|
|
|
light->SetLight(x110_elementGen->GetLight());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-26 22:09:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CShockWave::Touch(CActor& actor, CStateManager& mgr) {
|
2020-04-01 18:54:01 +00:00
|
|
|
if (x158_activeTime >= x15c_minActiveTime) {
|
2020-03-31 07:29:00 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-05-07 23:13:43 +00:00
|
|
|
bool isParent = xe8_parentId == actor.GetUniqueId();
|
2020-03-31 07:29:00 +00:00
|
|
|
if (TCastToConstPtr<CCollisionActor> cactor = mgr.GetObjectById(actor.GetUniqueId())) {
|
2020-05-07 23:13:43 +00:00
|
|
|
isParent = xe8_parentId == cactor->GetOwnerId();
|
2020-03-31 07:29:00 +00:00
|
|
|
}
|
2020-04-01 06:41:31 +00:00
|
|
|
if (isParent) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-05-07 23:13:43 +00:00
|
|
|
float mmax = x150_radius * x150_radius;
|
|
|
|
float mmin = mmax * x114_data.GetWidthPercent() * x114_data.GetWidthPercent();
|
2020-04-01 06:41:31 +00:00
|
|
|
zeus::CVector3f dist = actor.GetTranslation() - GetTranslation();
|
|
|
|
CDamageInfo damageInfo = xec_damageInfo;
|
2020-04-01 18:54:01 +00:00
|
|
|
float knockBackScale = std::max(0.f, 1.f - x160_knockback * x158_activeTime);
|
2020-04-01 06:41:31 +00:00
|
|
|
bool isPlayer = mgr.GetPlayer().GetUniqueId() == actor.GetUniqueId();
|
|
|
|
bool isPlayerInAir = isPlayer && mgr.GetPlayer().GetPlayerMovementState() != CPlayer::EPlayerMovementState::OnGround;
|
|
|
|
float distXYMag = dist.toVec2f().magSquared();
|
|
|
|
if (distXYMag < mmin || distXYMag > mmax) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isPlayer) {
|
|
|
|
if (mgr.GetPlayer().GetPlayerMovementState() == CPlayer::EPlayerMovementState::OnGround) {
|
|
|
|
const zeus::CTransform& playerTransform = mgr.GetPlayer().GetTransform();
|
|
|
|
zeus::CVector3f playerDir = GetTranslation() - playerTransform.origin;
|
|
|
|
if (playerDir.canBeNormalized()) {
|
|
|
|
playerDir.normalize();
|
|
|
|
float dot = std::abs(playerDir.dot(playerTransform.frontVector()));
|
|
|
|
knockBackScale = std::max(0.12f, 0.88f * dot * dot);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (mgr.GetPlayer().GetVelocity().magnitude() > 40.f) {
|
|
|
|
x168_timeSinceHitPlayer = 0.2666f;
|
|
|
|
}
|
2020-03-31 07:29:00 +00:00
|
|
|
}
|
2020-04-01 06:41:31 +00:00
|
|
|
damageInfo.SetKnockBackPower(knockBackScale * damageInfo.GetKnockBackPower());
|
|
|
|
|
|
|
|
if (isPlayer && (x164_timeSinceHitPlayerInAir >= 0.1333f || x168_timeSinceHitPlayer >= 0.2666f)) {
|
|
|
|
return;
|
|
|
|
}
|
2023-06-21 20:22:49 +00:00
|
|
|
if (!WasAlreadyDamaged(actor.GetUniqueId())) {
|
2020-04-01 06:41:31 +00:00
|
|
|
mgr.ApplyDamage(GetUniqueId(), actor.GetUniqueId(), GetUniqueId(), damageInfo,
|
|
|
|
CMaterialFilter::MakeInclude({EMaterialTypes::Solid}), zeus::skZero3f);
|
|
|
|
if (isPlayer && x974_electricDesc) {
|
|
|
|
mgr.AddObject(new CHUDBillboardEffect(std::nullopt, x974_electricDesc, mgr.AllocateUniqueId(), true,
|
|
|
|
"VisorElectricFx", CHUDBillboardEffect::GetNearClipDistance(mgr),
|
|
|
|
CHUDBillboardEffect::GetScaleForPOV(mgr), zeus::skWhite, zeus::skOne3f,
|
|
|
|
zeus::skZero3f));
|
|
|
|
CSfxManager::SfxStart(x114_data.GetElectrocuteSfx(), 1.f, 1.f, false, 0x7f, false, kInvalidAreaId);
|
|
|
|
}
|
|
|
|
x170_hitIds.push_back(actor.GetUniqueId());
|
|
|
|
} else {
|
|
|
|
damageInfo.SetDamage(0.f);
|
|
|
|
mgr.ApplyDamage(GetUniqueId(), actor.GetUniqueId(), GetUniqueId(), damageInfo,
|
|
|
|
CMaterialFilter::MakeInclude({EMaterialTypes::Solid}), zeus::skZero3f);
|
|
|
|
}
|
|
|
|
if (isPlayerInAir) {
|
|
|
|
x16c_hitPlayerInAir = true;
|
|
|
|
}
|
|
|
|
if (isPlayer) {
|
|
|
|
x16d_hitPlayer = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-21 20:22:49 +00:00
|
|
|
bool CShockWave::WasAlreadyDamaged(TUniqueId id) const {
|
2020-04-01 06:41:31 +00:00
|
|
|
return std::find(x170_hitIds.begin(), x170_hitIds.end(), id) != x170_hitIds.end();
|
2020-03-26 22:09:50 +00:00
|
|
|
}
|
2021-04-10 08:42:06 +00:00
|
|
|
} // namespace metaforce::MP1
|