2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-12-08 22:27:43 +00:00

Implement CScriptSound and bug fixes

This commit is contained in:
Jack Andersen
2017-11-26 19:06:53 -10:00
parent 11d17d0fe5
commit f60097b7e3
26 changed files with 369 additions and 143 deletions

View File

@@ -11,31 +11,32 @@ namespace urde
bool CScriptSound::sFirstInFrame = false;
CScriptSound::CScriptSound(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
s16 soundId, bool active, float f1, float f2, float f3, u32 w1, u32 w2, u32 w3, u32 w4,
u32 w5, u32 w6, bool b1, bool b2, bool autoStart, bool b4, bool b5, bool b6, bool b7, u32 w7)
u16 soundId, bool active, float maxDist, float distComp, float startDelay, u32 minVol,
u32 vol, u32 w3, u32 prio, u32 pan, u32 w6, bool looped, bool nonEmitter, bool autoStart,
bool occlusionTest, bool acoustics, bool worldSfx, bool allowDuplicates, s32 pitch)
: CActor(uid, active, name, info, xf, CModelData::CModelDataNull(), CMaterialList(EMaterialTypes::Unknown),
CActorParameters::None(), kInvalidUniqueId)
, xfc_(f3)
, xfc_startDelay(startDelay)
, x100_soundId(CSfxManager::TranslateSFXID(soundId))
, x104_(f1)
, x108_(f2)
, x10c_(w1)
, x10e_(w2)
, x104_maxDist(maxDist)
, x108_distComp(distComp)
, x10c_minVol(minVol / 127.f)
, x10e_vol(vol / 127.f)
, x110_(w3)
, x112_(w4)
, x114_(w5)
, x112_prio(s16(prio))
, x114_pan(pan / 64.f - 1.f)
, x116_(w6)
, x118_(w7 + 8192)
, x118_pitch(pitch / 8192.f)
{
x11c_25_ = b1;
x11c_26_ = b2;
x11c_25_looped = looped;
x11c_26_nonEmitter = nonEmitter;
x11c_27_autoStart = autoStart;
x11c_28_ = b4;
x11c_29_ = b5;
x11c_30_ = b6;
x11d_24_ = b7;
if (x11c_30_ && (!x11c_26_ || !x11c_25_))
x11c_30_ = false;
x11c_28_occlusionTest = occlusionTest;
x11c_29_acoustics = acoustics;
x11c_30_worldSfx = worldSfx;
x11d_24_allowDuplicates = allowDuplicates;
if (x11c_30_worldSfx && (!x11c_26_nonEmitter || !x11c_25_looped))
x11c_30_worldSfx = false;
}
void CScriptSound::Accept(IVisitor& visitor) { visitor.Visit(this); }
@@ -44,11 +45,120 @@ void CScriptSound::PreThink(float dt, CStateManager& mgr)
{
CEntity::PreThink(dt, mgr);
sFirstInFrame = true;
x11d_25_ = false;
x11d_25_processedThisFrame = false;
}
static const CMaterialFilter kSolidFilter =
CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {EMaterialTypes::ProjectilePassthrough});
float CScriptSound::GetOccludedVolumeAmount(const zeus::CVector3f& pos, const CStateManager& mgr)
{
zeus::CTransform camXf = mgr.GetCameraManager()->GetCurrentCameraTransform(mgr);
zeus::CVector3f soundToCam = camXf.origin - pos;
float soundToCamMag = soundToCam.magnitude();
zeus::CVector3f soundToCamNorm = soundToCam * (1.f / soundToCamMag);
zeus::CVector3f thirdEdge = zeus::CVector3f::skUp - soundToCamNorm * soundToCamNorm.dot(zeus::CVector3f::skUp);
zeus::CVector3f cross = soundToCamNorm.cross(thirdEdge);
static float kInfluenceAmount = 3.f / soundToCamMag;
static float kInfluenceIncrement = kInfluenceAmount;
int totalCount = 0;
int invalCount = 0;
float f17 = -kInfluenceAmount;
while (f17 <= kInfluenceAmount)
{
zeus::CVector3f angledDir = thirdEdge * f17 + soundToCamNorm;
float f16 = -kInfluenceAmount;
while (f16 <= kInfluenceAmount)
{
if (mgr.RayStaticIntersection(pos, (cross * f16 + angledDir).normalized(),
soundToCamMag, kSolidFilter).IsInvalid())
++invalCount;
++totalCount;
f16 += kInfluenceIncrement;
}
f17 += kInfluenceIncrement;
}
return invalCount / float(totalCount) * 0.42f + 0.58f;
}
void CScriptSound::Think(float dt, CStateManager& mgr)
{
if (x11c_31_selfFree && (!GetActive() || x11c_25_looped || !x11c_27_autoStart))
{
mgr.FreeScriptObject(GetUniqueId());
}
else if (GetActive())
{
if (!x11c_25_looped && x11c_27_autoStart && !x11c_24_playRequested &&
xec_sfxHandle && !CSfxManager::IsPlaying(xec_sfxHandle))
mgr.FreeScriptObject(GetUniqueId());
if (!x11c_26_nonEmitter && xec_sfxHandle)
{
if (xf8_updateTimer <= 0.f)
{
xf8_updateTimer = 0.25f;
CSfxManager::UpdateEmitter(xec_sfxHandle, GetTranslation(), zeus::CVector3f::skZero, xf2_maxVolUpd);
}
else
{
xf8_updateTimer -= dt;
}
}
if (xec_sfxHandle && !x11c_26_nonEmitter && x11c_28_occlusionTest)
{
if (xe8_occUpdateTimer <= 0.f && sFirstInFrame)
{
sFirstInFrame = false;
float occVol = GetOccludedVolumeAmount(GetTranslation(), mgr);
float newMaxVol = std::max(occVol * x10e_vol, x10c_minVol);
if (newMaxVol != xf0_maxVol)
{
xf0_maxVol = newMaxVol;
float delta = xf0_maxVol - xf2_maxVolUpd;
xf4_maxVolUpdDelta = delta / 10.5f;
if (xf4_maxVolUpdDelta == 0.f)
{
if (xf2_maxVolUpd < xf0_maxVol)
xf4_maxVolUpdDelta = 1.f / 127.f;
else
xf4_maxVolUpdDelta = -1.f / 127.f;
}
}
xe8_occUpdateTimer = 0.5f;
}
else
{
xe8_occUpdateTimer -= dt;
}
if (xf2_maxVolUpd != xf0_maxVol)
{
xf2_maxVolUpd += xf4_maxVolUpdDelta;
if (xf4_maxVolUpdDelta > 0.f && xf2_maxVolUpd > xf0_maxVol)
xf2_maxVolUpd = xf0_maxVol;
if (xf4_maxVolUpdDelta < 0.f && xf2_maxVolUpd < xf0_maxVol)
xf2_maxVolUpd = xf0_maxVol;
CSfxManager::UpdateEmitter(xec_sfxHandle, GetTranslation(), zeus::CVector3f::skZero, xf2_maxVolUpd);
}
}
if (x11c_24_playRequested)
{
xfc_startDelay -= dt;
if (xfc_startDelay <= 0.f)
{
x11c_24_playRequested = false;
PlaySound(mgr);
}
}
if (x118_pitch != 0.f && xec_sfxHandle)
CSfxManager::PitchBend(xec_sfxHandle, x118_pitch);
}
}
void CScriptSound::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr)
@@ -60,8 +170,8 @@ void CScriptSound::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CSta
case EScriptObjectMessage::Registered:
{
if (GetActive() && x11c_27_autoStart)
x11c_24_ = true;
x11c_31_ = mgr.GetIsGeneratingObject();
x11c_24_playRequested = true;
x11c_31_selfFree = mgr.GetIsGeneratingObject();
}
break;
case EScriptObjectMessage::Play:
@@ -85,12 +195,12 @@ void CScriptSound::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CSta
case EScriptObjectMessage::Activate:
{
if(GetActive())
x11c_24_ = true;
x11c_24_playRequested = true;
}
break;
case EScriptObjectMessage::Deleted:
{
if (!x11c_30_)
if (!x11c_30_worldSfx)
StopSound(mgr);
}
break;
@@ -98,21 +208,52 @@ void CScriptSound::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CSta
}
}
void CScriptSound::PlaySound(CStateManager&)
void CScriptSound::PlaySound(CStateManager& mgr)
{
if ((x11d_24_allowDuplicates || !xec_sfxHandle) && !x11d_25_processedThisFrame)
{
x11d_25_processedThisFrame = true;
if (x11c_26_nonEmitter)
{
if (!x11c_30_worldSfx || !mgr.GetWorld()->HasGlobalSound(x100_soundId))
{
xec_sfxHandle = CSfxManager::SfxStart(x100_soundId, x10e_vol, x114_pan,
x11c_29_acoustics, x112_prio, x11c_25_looped,
x11c_30_worldSfx ? kInvalidAreaId : GetAreaIdAlways());
if (x11c_30_worldSfx)
mgr.WorldNC()->AddGlobalSound(xec_sfxHandle);
}
}
else
{
float occVol = x11c_28_occlusionTest ? GetOccludedVolumeAmount(GetTranslation(), mgr) : 1.f;
xf0_maxVol = xf2_maxVolUpd = x10e_vol * occVol;
CAudioSys::C3DEmitterParmData data = {};
data.x0_pos = GetTranslation();
data.x18_maxDist = x104_maxDist;
data.x1c_distComp = x108_distComp;
data.x20_flags = 1; // Continuous parameter update
data.x24_sfxId = x100_soundId;
data.x26_maxVol = xf0_maxVol;
data.x27_minVol = x10c_minVol;
data.x29_prio = 0x7f;
xec_sfxHandle = CSfxManager::AddEmitter(data, x11c_29_acoustics, x112_prio,
x11c_25_looped, GetAreaIdAlways());
}
}
}
void CScriptSound::StopSound(CStateManager& mgr)
{
x11c_24_ = false;
if (x11c_30_ && x11c_26_)
x11c_24_playRequested = false;
if (x11c_30_worldSfx && x11c_26_nonEmitter)
{
mgr.WorldNC()->StopSound(x100_soundId);
mgr.WorldNC()->StopGlobalSound(x100_soundId);
xec_sfxHandle.reset();
}
else if (xec_sfxHandle)
{
CSfxManager::RemoveEmitter(*xec_sfxHandle.get());
CSfxManager::RemoveEmitter(xec_sfxHandle);
xec_sfxHandle.reset();
}
}