#include "CBomb.hpp" #include "Particle/CElementGen.hpp" #include "World/CPlayer.hpp" #include "World/CMorphBall.hpp" #include "GameGlobalObjects.hpp" #include "Graphics/CBooRenderer.hpp" #include "World/CGameLight.hpp" #include "TCastTo.hpp" #include "DataSpec/DNAMP1/SFX/Weapons.h" namespace urde { CBomb::CBomb(const TCachedToken& particle1, const TCachedToken& particle2, TUniqueId uid, TAreaId aid, TUniqueId playerId, float f1, const zeus::CTransform& xf, const CDamageInfo& dInfo) : CWeapon(uid, aid, true, playerId, EWeaponType::Bomb, "Bomb", xf, CMaterialFilter::MakeIncludeExclude( {EMaterialTypes::Solid, EMaterialTypes::Trigger, EMaterialTypes::NonSolidDamageable}, {EMaterialTypes::Projectile, EMaterialTypes::Bomb}), {EMaterialTypes::Projectile, EMaterialTypes::Bomb}, dInfo, EProjectileAttrib::Bombs, CModelData::CModelDataNull()) , x17c_fuseTime(f1) , x180_particle1( new CElementGen(particle1, CElementGen::EModelOrientationType::Normal, CElementGen::EOptionalSystemFlags::One)) , x184_particle2( new CElementGen(particle2, CElementGen::EModelOrientationType::Normal, CElementGen::EOptionalSystemFlags::One)) , x18c_(particle2.GetObj()) , x190_24_isNotDetonated(true) , x190_25_(false) , x190_26_disableFuse(false) { x180_particle1->SetGlobalTranslation(xf.origin); x184_particle2->SetGlobalTranslation(xf.origin); } void CBomb::Accept(urde::IVisitor& visitor) { visitor.Visit(this); } void CBomb::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) { if (msg == EScriptObjectMessage::Registered) { x188_lightId = mgr.AllocateUniqueId(); CGameLight* gameLight = new CGameLight(x188_lightId, GetAreaIdAlways(), false, std::string("Bomb_PLight") + GetName().data(), GetTransform(), GetUniqueId(), x184_particle2->GetLight(), reinterpret_cast(x18c_), 1, 0.f); mgr.AddObject(gameLight); mgr.AddWeaponId(xec_ownerId, xf0_weaponType); CSfxManager::AddEmitter(SFXwpn_bomb_drop, GetTranslation(), {}, true, false, 0x7f, -1); mgr.InformListeners(GetTranslation(), EListenNoiseType::BombExplode); return; } else if (msg == EScriptObjectMessage::Deleted) { if (x188_lightId != kInvalidUniqueId) mgr.FreeScriptObject(x188_lightId); if (x190_24_isNotDetonated) mgr.RemoveWeaponId(xec_ownerId, xf0_weaponType); return; } CActor::AcceptScriptMsg(msg, uid, mgr); } static CMaterialFilter kSolidFilter = CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {EMaterialTypes::Character, EMaterialTypes::Player, EMaterialTypes::ProjectilePassthrough}); void CBomb::Think(float dt, urde::CStateManager& mgr) { CWeapon::Think(dt, mgr); if (x190_24_isNotDetonated) { if (x17c_fuseTime <= 0.f) { Explode(GetTranslation(), mgr); if (TCastToPtr light = mgr.ObjectById(x188_lightId)) light->SetActive(true); } if (x17c_fuseTime > 0.5f) x180_particle1->Update(dt); else UpdateLight(dt, mgr); if (!x190_26_disableFuse) x17c_fuseTime -= dt; } else { UpdateLight(dt, mgr); if (x184_particle2->IsSystemDeletable()) mgr.FreeScriptObject(GetUniqueId()); } if (x190_24_isNotDetonated) { if (x164_.magSquared() > 0.f) x158_ += dt * x164_; if (x158_.magSquared() > 0.f) { x170_prevLocation = GetTranslation(); CActor::SetTranslation((dt * x158_) + GetTranslation()); zeus::CVector3f diffVec = (GetTranslation() - x170_prevLocation); float diffMag = diffVec.magnitude(); if (diffMag == 0.f) Explode(GetTranslation(), mgr); else { CRayCastResult res = mgr.RayStaticIntersection(x170_prevLocation, (1.f / diffMag) * diffVec, diffMag, kSolidFilter); if (res.IsValid()) Explode(GetTranslation(), mgr); } } } x180_particle1->SetGlobalTranslation(GetTranslation()); x184_particle2->SetGlobalTranslation(GetTranslation()); } void CBomb::AddToRenderer(const zeus::CFrustum& frustum, const urde::CStateManager& mgr) const { zeus::CVector3f origin = GetTranslation(); float ballRadius = mgr.GetPlayer().GetMorphBall()->GetBallRadius(); zeus::CAABox aabox(origin - (0.9f * ballRadius), origin + (0.9f * ballRadius)); zeus::CVector3f closestPoint = aabox.closestPointAlongVector(CGraphics::g_ViewMatrix.frontVector()); if (x190_24_isNotDetonated && x17c_fuseTime > 0.5f) g_Renderer->AddParticleGen(*x180_particle1, closestPoint, aabox); else g_Renderer->AddParticleGen(*x184_particle2, closestPoint, aabox); } void CBomb::Touch(CActor&, urde::CStateManager&) { #if 0 x190_24_isNotDetonated; /* wat? */ #endif } std::experimental::optional CBomb::GetTouchBounds() const { float radius = (x190_24_isNotDetonated ? 0.2f : x12c_curDamageInfo.GetRadius()); float minX = (x170_prevLocation.x() >= GetTranslation().x() ? x170_prevLocation.x() : GetTranslation().x()) - radius; float minY = (x170_prevLocation.y() >= GetTranslation().y() ? x170_prevLocation.y() : GetTranslation().y()) - radius; float minZ = (x170_prevLocation.z() >= GetTranslation().z() ? x170_prevLocation.z() : GetTranslation().z()) - radius; float maxX = (x170_prevLocation.x() >= GetTranslation().x() ? x170_prevLocation.x() : GetTranslation().x()) + radius; float maxY = (x170_prevLocation.y() >= GetTranslation().y() ? x170_prevLocation.y() : GetTranslation().y()) + radius; float maxZ = (x170_prevLocation.z() >= GetTranslation().z() ? x170_prevLocation.z() : GetTranslation().z()) + radius; return {{minX, minY, minZ, maxX, maxY, maxZ}}; } 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::BombExplode); mgr.RemoveWeaponId(xec_ownerId, xf0_weaponType); x190_24_isNotDetonated = false; } void CBomb::UpdateLight(float dt, CStateManager& mgr) { x184_particle2->Update(dt); if (x188_lightId == kInvalidUniqueId) return; if (TCastToPtr light = mgr.ObjectById(x188_lightId)) if (light->GetActive()) light->SetLight(x184_particle2->GetLight()); } } // namespace urde