metaforce/Runtime/World/CScriptTrigger.cpp

302 lines
12 KiB
C++
Raw Permalink Normal View History

#include "Runtime/World/CScriptTrigger.hpp"
#include "Runtime/CStateManager.hpp"
#include "Runtime/Camera/CGameCamera.hpp"
#include "Runtime/Weapon/CGameProjectile.hpp"
#include "Runtime/World/CActorParameters.hpp"
#include "Runtime/World/CPlayer.hpp"
#include "TCastTo.hpp" // Generated file, do not modify include path
2016-04-19 21:25:26 +00:00
2021-04-10 08:42:06 +00:00
namespace metaforce {
2016-04-19 21:25:26 +00:00
2017-11-13 06:19:18 +00:00
CScriptTrigger::CScriptTrigger(TUniqueId uid, std::string_view name, const CEntityInfo& info,
2017-01-15 03:59:37 +00:00
const zeus::CVector3f& pos, const zeus::CAABox& bounds, const CDamageInfo& dInfo,
2017-11-26 03:04:25 +00:00
const zeus::CVector3f& forceField, ETriggerFlags triggerFlags, bool active,
bool deactivateOnEntered, bool deactivateOnExited)
2016-04-19 21:25:26 +00:00
: CActor(uid, active, name, info, zeus::CTransform::Translate(pos), CModelData::CModelDataNull(),
2017-01-15 03:59:37 +00:00
CMaterialList(EMaterialTypes::Trigger), CActorParameters::None(), kInvalidUniqueId)
, x100_damageInfo(dInfo)
, x11c_forceField(forceField)
, x128_forceMagnitude(forceField.magnitude())
, x12c_flags(triggerFlags)
, x130_bounds(bounds)
, x148_26_deactivateOnEntered(deactivateOnEntered)
, x148_27_deactivateOnExited(deactivateOnExited) {
2018-12-08 05:30:43 +00:00
SetCallTouch(false);
2016-04-19 21:25:26 +00:00
}
2017-02-13 21:29:00 +00:00
void CScriptTrigger::Accept(IVisitor& visitor) { visitor.Visit(this); }
2017-01-15 03:07:01 +00:00
2018-12-08 05:30:43 +00:00
void CScriptTrigger::Think(float dt, CStateManager& mgr) {
if (GetActive()) {
2018-12-08 05:30:43 +00:00
UpdateInhabitants(dt, mgr);
}
2017-01-15 03:59:37 +00:00
}
2016-11-20 21:53:15 +00:00
2018-12-08 05:30:43 +00:00
void CScriptTrigger::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) {
if (GetActive() && (msg == EScriptObjectMessage::Deactivate || msg == EScriptObjectMessage::Deleted)) {
if (msg == EScriptObjectMessage::Deactivate) {
xe8_inhabitants.clear();
x148_25_camSubmerged = false;
}
2017-01-15 03:59:37 +00:00
2018-12-08 05:30:43 +00:00
if (x148_28_playerTriggerProc) {
x148_28_playerTriggerProc = false;
if (x148_29_didPhazonDamage) {
mgr.Player()->DecrementEnvironmentDamage();
2018-12-08 05:30:43 +00:00
x148_29_didPhazonDamage = false;
}
2017-01-15 03:59:37 +00:00
if (x8_uid == mgr.GetLastTriggerId()) {
2018-12-08 05:30:43 +00:00
mgr.SetLastTriggerId(kInvalidUniqueId);
}
2017-01-15 03:59:37 +00:00
}
2018-12-08 05:30:43 +00:00
}
2017-01-15 03:59:37 +00:00
2021-01-11 02:44:42 +00:00
CActor::AcceptScriptMsg(msg, uid, mgr);
2016-04-29 10:08:46 +00:00
}
2018-12-08 05:30:43 +00:00
CScriptTrigger::CObjectTracker* CScriptTrigger::FindObject(TUniqueId id) {
auto& inhabitants = GetInhabitants();
const auto iter = std::find(inhabitants.begin(), inhabitants.end(), CObjectTracker{id});
2017-01-15 03:59:37 +00:00
if (iter == inhabitants.end()) {
return nullptr;
}
return &*iter;
2016-04-29 10:08:46 +00:00
}
2018-12-08 05:30:43 +00:00
void CScriptTrigger::UpdateInhabitants(float dt, CStateManager& mgr) {
bool sendInside = false;
bool sendExited = false;
std::list<CObjectTracker>::iterator nextIt;
for (auto it = xe8_inhabitants.begin(); it != xe8_inhabitants.end(); it = nextIt) {
nextIt = it;
++nextIt;
if (const TCastToPtr<CActor> act = mgr.ObjectById(it->GetObjectId())) {
2018-12-08 05:30:43 +00:00
bool playerValid = true;
if (it->GetObjectId() == mgr.GetPlayer().GetUniqueId()) {
2019-04-03 04:32:31 +00:00
if (False(x12c_flags & ETriggerFlags::DetectPlayer) &&
2018-12-08 05:30:43 +00:00
((mgr.GetPlayer().GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Morphed &&
2019-04-03 04:32:31 +00:00
True(x12c_flags & ETriggerFlags::DetectUnmorphedPlayer)) ||
2018-12-08 05:30:43 +00:00
(mgr.GetPlayer().GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Unmorphed &&
2019-04-03 04:32:31 +00:00
True(x12c_flags & ETriggerFlags::DetectMorphedPlayer)))) {
2018-12-08 05:30:43 +00:00
playerValid = false;
}
if (!playerValid) {
xe8_inhabitants.erase(it);
sendExited = true;
if (x148_28_playerTriggerProc) {
x148_28_playerTriggerProc = false;
if (x148_29_didPhazonDamage) {
mgr.GetPlayer().DecrementEnvironmentDamage();
2018-12-08 05:30:43 +00:00
x148_29_didPhazonDamage = false;
2017-01-15 03:59:37 +00:00
}
if (mgr.GetLastTriggerId() == GetUniqueId()) {
2018-12-08 05:30:43 +00:00
mgr.SetLastTriggerId(kInvalidUniqueId);
}
2018-12-08 05:30:43 +00:00
}
InhabitantExited(*act, mgr);
continue;
}
2018-12-08 05:30:43 +00:00
}
const auto touchBounds = GetTouchBounds();
const auto actTouchBounds = act->GetTouchBounds();
2018-12-08 05:30:43 +00:00
if (touchBounds && actTouchBounds && touchBounds->intersects(*actTouchBounds)) {
sendInside = true;
InhabitantIdle(*act, mgr);
if (act->HealthInfo(mgr) && x100_damageInfo.GetDamage() > 0.f) {
2018-12-08 05:30:43 +00:00
mgr.ApplyDamage(GetUniqueId(), act->GetUniqueId(), GetUniqueId(), {x100_damageInfo, dt},
CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {}), zeus::skZero3f);
}
2018-12-08 05:30:43 +00:00
if (x128_forceMagnitude > 0.f) {
if (TCastToPtr<CPhysicsActor> pact = act.GetPtr()) {
float forceMult = 1.f;
if (True(x12c_flags & ETriggerFlags::UseBooleanIntersection)) {
2018-12-08 05:30:43 +00:00
forceMult = touchBounds->booleanIntersection(*actTouchBounds).volume() / actTouchBounds->volume();
}
2018-12-08 05:30:43 +00:00
const zeus::CVector3f force = forceMult * x11c_forceField;
2019-04-03 04:32:31 +00:00
if (True(x12c_flags & ETriggerFlags::UseCollisionImpulses)) {
pact->ApplyImpulseWR(force, zeus::CAxisAngle());
2018-12-08 05:30:43 +00:00
pact->UseCollisionImpulses();
} else {
pact->ApplyForceWR(force, zeus::CAxisAngle());
}
2018-12-08 05:30:43 +00:00
}
}
} else {
const TUniqueId tmpId = it->GetObjectId();
2018-12-08 05:30:43 +00:00
xe8_inhabitants.erase(it);
sendExited = true;
if (mgr.GetPlayer().GetUniqueId() == tmpId && x148_28_playerTriggerProc) {
x148_28_playerTriggerProc = false;
if (x148_29_didPhazonDamage) {
mgr.Player()->DecrementEnvironmentDamage();
2018-12-08 05:30:43 +00:00
x148_29_didPhazonDamage = false;
}
if (mgr.GetLastTriggerId() == GetUniqueId())
mgr.SetLastTriggerId(kInvalidUniqueId);
}
2017-01-15 03:59:37 +00:00
2018-12-08 05:30:43 +00:00
InhabitantExited(*act, mgr);
}
} else {
const TUniqueId tmpId = it->GetObjectId();
2018-12-08 05:30:43 +00:00
xe8_inhabitants.erase(it);
if (mgr.GetPlayer().GetUniqueId() == tmpId && x148_28_playerTriggerProc) {
x148_28_playerTriggerProc = false;
if (x148_29_didPhazonDamage) {
mgr.Player()->DecrementEnvironmentDamage();
2018-12-08 05:30:43 +00:00
x148_29_didPhazonDamage = false;
2017-01-15 03:59:37 +00:00
}
2018-12-08 05:30:43 +00:00
if (mgr.GetLastTriggerId() == GetUniqueId()) {
2018-12-08 05:30:43 +00:00
mgr.SetLastTriggerId(kInvalidUniqueId);
}
2018-12-08 05:30:43 +00:00
}
}
}
2019-04-03 04:32:31 +00:00
if (True(x12c_flags & ETriggerFlags::DetectCamera) || x148_24_detectCamera) {
2018-12-08 05:30:43 +00:00
CGameCamera* cam = mgr.GetCameraManager()->GetCurrentCamera(mgr);
const bool camInTrigger = GetTriggerBoundsWR().pointInside(cam->GetTranslation());
2018-12-08 05:30:43 +00:00
if (x148_25_camSubmerged) {
if (!camInTrigger) {
x148_25_camSubmerged = false;
2019-04-03 04:32:31 +00:00
if (True(x12c_flags & ETriggerFlags::DetectCamera)) {
2018-12-08 05:30:43 +00:00
sendExited = true;
InhabitantExited(*cam, mgr);
}
} else {
2019-04-03 04:32:31 +00:00
if (True(x12c_flags & ETriggerFlags::DetectCamera)) {
2018-12-08 05:30:43 +00:00
InhabitantIdle(*cam, mgr);
sendInside = true;
}
}
} else {
if (camInTrigger) {
x148_25_camSubmerged = true;
2019-04-03 04:32:31 +00:00
if (True(x12c_flags & ETriggerFlags::DetectCamera)) {
2018-12-08 05:30:43 +00:00
InhabitantAdded(*cam, mgr);
SendScriptMsgs(EScriptObjectState::Entered, mgr, EScriptObjectMessage::None);
2017-01-15 03:59:37 +00:00
}
2018-12-08 05:30:43 +00:00
}
2017-01-15 03:59:37 +00:00
}
2018-12-08 05:30:43 +00:00
}
2017-01-15 03:59:37 +00:00
2018-12-08 05:30:43 +00:00
if (sendInside) {
SendScriptMsgs(EScriptObjectState::Inside, mgr, EScriptObjectMessage::None);
2018-12-08 05:30:43 +00:00
}
2017-01-15 03:59:37 +00:00
2018-12-08 05:30:43 +00:00
if (sendExited) {
SendScriptMsgs(EScriptObjectState::Exited, mgr, EScriptObjectMessage::None);
2018-12-08 05:30:43 +00:00
if (x148_27_deactivateOnExited) {
mgr.SendScriptMsg(GetUniqueId(), mgr.GetEditorIdForUniqueId(GetUniqueId()), EScriptObjectMessage::Deactivate,
EScriptObjectState::Exited);
2017-01-15 03:59:37 +00:00
}
2018-12-08 05:30:43 +00:00
}
2016-04-29 10:08:46 +00:00
}
2017-01-15 03:59:37 +00:00
std::list<CScriptTrigger::CObjectTracker>& CScriptTrigger::GetInhabitants() { return xe8_inhabitants; }
std::optional<zeus::CAABox> CScriptTrigger::GetTouchBounds() const {
if (x30_24_active) {
return GetTriggerBoundsWR();
}
return std::nullopt;
2016-04-29 10:08:46 +00:00
}
constexpr auto sktonOHurtWeaponMode = CWeaponMode(EWeaponType::Power, false, false, true);
2017-01-15 03:59:37 +00:00
2018-12-08 05:30:43 +00:00
void CScriptTrigger::Touch(CActor& act, CStateManager& mgr) {
if (!act.GetActive() || act.GetMaterialList().HasMaterial(EMaterialTypes::Trigger)) {
2018-12-08 05:30:43 +00:00
return;
}
2018-12-08 05:30:43 +00:00
if (FindObject(act.GetUniqueId()) == nullptr) {
auto testFlags = ETriggerFlags::None;
const TCastToPtr<CPlayer> pl(act);
2018-12-08 05:30:43 +00:00
if (pl) {
2019-04-03 04:32:31 +00:00
if (x128_forceMagnitude > 0.f && True(x12c_flags & ETriggerFlags::DetectPlayer) &&
mgr.GetLastTriggerId() == kInvalidUniqueId) {
2018-12-08 05:30:43 +00:00
mgr.SetLastTriggerId(x8_uid);
}
2018-12-08 05:30:43 +00:00
testFlags |= ETriggerFlags::DetectPlayer;
if (pl->GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Unmorphed) {
2018-12-08 05:30:43 +00:00
testFlags |= ETriggerFlags::DetectUnmorphedPlayer;
} else if (pl->GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Morphed) {
2018-12-08 05:30:43 +00:00
testFlags |= ETriggerFlags::DetectMorphedPlayer;
}
2018-12-08 05:30:43 +00:00
} else if (TCastToPtr<CAi>(act)) {
testFlags |= ETriggerFlags::DetectAI;
} else if (TCastToPtr<CGameProjectile>(act)) {
testFlags |= ETriggerFlags::DetectProjectiles1 | ETriggerFlags::DetectProjectiles2 |
ETriggerFlags::DetectProjectiles3 | ETriggerFlags::DetectProjectiles4 |
ETriggerFlags::DetectProjectiles5 | ETriggerFlags::DetectProjectiles6 |
ETriggerFlags::DetectProjectiles7;
} else if (const TCastToConstPtr<CWeapon> weap = act) {
if ((weap->GetAttribField() & EProjectileAttrib::Bombs) == EProjectileAttrib::Bombs) {
2018-12-08 05:30:43 +00:00
testFlags |= ETriggerFlags::DetectBombs;
} else if ((weap->GetAttribField() & EProjectileAttrib::PowerBombs) == EProjectileAttrib::PowerBombs) {
2018-12-08 05:30:43 +00:00
testFlags |= ETriggerFlags::DetectPowerBombs;
}
2018-12-08 05:30:43 +00:00
}
2017-01-15 03:59:37 +00:00
2019-04-03 04:32:31 +00:00
if (True(testFlags & x12c_flags)) {
xe8_inhabitants.emplace_back(act.GetUniqueId());
2018-12-08 05:30:43 +00:00
InhabitantAdded(act, mgr);
if (pl) {
if (!x148_28_playerTriggerProc) {
x148_28_playerTriggerProc = true;
if (x148_29_didPhazonDamage) {
mgr.Player()->DecrementEnvironmentDamage();
2018-12-08 05:30:43 +00:00
x148_29_didPhazonDamage = false;
} else if (x100_damageInfo.GetDamage() > 0.f) {
const CDamageVulnerability* dVuln = mgr.Player()->GetDamageVulnerability();
if (dVuln->WeaponHurts(x100_damageInfo.GetWeaponMode(), false) &&
2018-12-08 05:30:43 +00:00
x100_damageInfo.GetWeaponMode().GetType() == EWeaponType::Phazon &&
!mgr.GetPlayerState()->HasPowerUp(CPlayerState::EItemType::PhazonSuit)) {
pl->IncrementEnvironmentDamage();
2018-12-08 05:30:43 +00:00
x148_29_didPhazonDamage = true;
2017-01-15 03:59:37 +00:00
}
2018-12-08 05:30:43 +00:00
}
}
}
2017-01-15 03:59:37 +00:00
2018-12-08 05:30:43 +00:00
SendScriptMsgs(EScriptObjectState::Entered, mgr, EScriptObjectMessage::None);
2017-01-15 03:59:37 +00:00
2018-12-08 05:30:43 +00:00
if (x148_26_deactivateOnEntered) {
mgr.SendScriptMsg(x8_uid, mgr.GetEditorIdForUniqueId(x8_uid), EScriptObjectMessage::Deactivate,
EScriptObjectState::Entered);
if (act.HealthInfo(mgr) && x100_damageInfo.GetDamage() > 0.f) {
mgr.ApplyDamage(x8_uid, act.GetUniqueId(), x8_uid, x100_damageInfo,
CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {0ull}),
zeus::skZero3f);
2017-01-15 03:59:37 +00:00
}
2018-12-08 05:30:43 +00:00
}
2019-04-03 04:32:31 +00:00
if (True(x12c_flags & ETriggerFlags::KillOnEnter) && act.HealthInfo(mgr)) {
2018-12-08 05:30:43 +00:00
CHealthInfo* hInfo = act.HealthInfo(mgr);
mgr.ApplyDamage(x8_uid, act.GetUniqueId(), x8_uid, {sktonOHurtWeaponMode, 10.f * hInfo->GetHP(), 0.f, 0.f},
CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {0ull}), zeus::skZero3f);
2018-12-08 05:30:43 +00:00
}
} else {
2018-12-08 05:30:43 +00:00
InhabitantRejected(act, mgr);
}
2018-12-08 05:30:43 +00:00
}
2017-01-15 03:59:37 +00:00
}
2016-04-29 10:08:46 +00:00
2018-12-08 05:30:43 +00:00
zeus::CAABox CScriptTrigger::GetTriggerBoundsWR() const {
return {x130_bounds.min + x34_transform.origin, x130_bounds.max + x34_transform.origin};
2016-04-19 21:25:26 +00:00
}
2021-04-10 08:42:06 +00:00
} // namespace metaforce