Files
2026-08-09 04:29:27 -07:00

739 lines
25 KiB
C++

#include "gamelib/effects/fxmanager.h"
#include <algorithm>
#include <cmath>
#include <cstdint>
int GameLib_GetFXDeclActionCount(const idDeclFX* decl);
int GameLib_GetFXDeclChangeId(const idDeclFX* decl);
const char* GameLib_GetFXDeclName(const idDeclFX* decl);
bool GameLib_GetFXActionParameters(const idDeclFX* decl, int actionIndex,
idFXActionParameters& parameters);
void GameLib_CreateFXActionResource(idGameLibEffects* effects,
idRenderWorld* renderWorld, const idFXActionParameters& parameters,
idFXAction& action);
void GameLib_StartFXActionResource(idGameLibEffects* effects,
const idFXActionParameters& parameters, idFXAction& action,
const idVec3& origin, const idMat3& axis, int time);
void GameLib_UpdateFXActionResource(idGameLibEffects* effects,
const idFXActionParameters& parameters, idFXAction& action,
const idVec3& origin, const idMat3& axis, const idVec3& velocity,
const idVec4& color, int time, int frameNumber, float fovScale,
float depthHack);
void GameLib_StopFXActionResource(idGameLibEffects* effects,
const idFXActionParameters& parameters, idFXAction& action,
int time, bool immediate, bool recycleResources);
void GameLib_FreeFXActionResource(idGameLibEffects* effects,
const idFXActionParameters& parameters, idFXAction& action);
void GameLib_EnumerateFXActionTags(idTreeAnimator* animator,
const idDeclFX* decl, int actionIndex, idList<tagData_t, 109>& tags);
bool GameLib_GetFXTagVelocity(idTreeAnimator* animator, const tagData_t& tag,
int gameMsPerFrame, idVec3& velocity);
idVec4 GameLib_GetFXRenderParm(const idDeclRenderParm* parameter);
idVec4 GameLib_GetFXTableColor(const idFXSingleAction& action,
float fraction);
idList<idViewCallbacks*, 109>* GameLib_GetFXViewCallbacks();
int GameLib_StartFXSound(idSoundEmitter* emitter, soundChannel_t channel,
const idSoundShader* shader);
void GameLib_SerializeFXManager(idSerializer& serializer,
idFXManager& manager);
idRenderModelParticle* GameLib_AllocParticleFxModel(idRenderWorld* renderWorld,
const idDeclParticle* particleDecl);
void GameLib_FreeParticleFxModel(idRenderModelParticle* model);
idRenderModel* GameLib_AllocStaticFxModel(idRenderWorld* renderWorld,
const char* modelName);
void GameLib_FreeStaticFxModel(idRenderModel* model);
namespace {
int PointerKey(const void* pointer) {
return static_cast<int>(reinterpret_cast<std::uintptr_t>(pointer) >> 4);
}
float RandomRange(idRandom2& random, const idVec2& range) {
return range.x + (range.y - range.x) * random.RandomFloat();
}
float Clamp01(const float value) {
return (std::max)(0.0f, (std::min)(1.0f, value));
}
void ResetState(fxActionState_t& state) {
state.startDelay = 0;
state.startTime = -1;
state.stopTime = 0;
state.hidden = false;
state.started = false;
state.shouldTrigger = false;
state.forceStop = false;
state.fadeInStartTime = -1;
state.fadeInEndTime = 0;
state.fadeOutStartTime = 0;
}
} // namespace
idFXModelRecycler::idFXModelRecycler()
: fxPrtModels()
, activePrtModelHash(256, 256)
, inactivePrtModelHash(256, 256)
, fxStaticModels()
, activeStaticModelHash(64, 64)
, inactiveStaticModelHash(64, 64) {
}
idFXModelRecycler::~idFXModelRecycler() {
Shutdown();
}
void idFXModelRecycler::Init() {
Shutdown();
activePrtModelHash.Clear();
inactivePrtModelHash.Clear();
activeStaticModelHash.Clear();
inactiveStaticModelHash.Clear();
}
void idFXModelRecycler::Shutdown() {
for (int index = 0; index < fxPrtModels.Num(); ++index) {
if (fxPrtModels[index].pmodel != nullptr) {
GameLib_FreeParticleFxModel(fxPrtModels[index].pmodel);
}
}
for (int index = 0; index < fxStaticModels.Num(); ++index) {
if (fxStaticModels[index].rmodel != nullptr) {
GameLib_FreeStaticFxModel(fxStaticModels[index].rmodel);
}
}
fxPrtModels.Clear();
fxStaticModels.Clear();
activePrtModelHash.Clear();
inactivePrtModelHash.Clear();
activeStaticModelHash.Clear();
inactiveStaticModelHash.Clear();
}
idRenderModelParticle* idFXModelRecycler::GetParticleFxModel(
const idDeclParticle* const particleDecl,
idRenderWorld* const renderWorld) {
if (particleDecl == nullptr) {
return nullptr;
}
const int key = PointerKey(particleDecl);
for (int index = inactivePrtModelHash.First(key); index >= 0;
index = inactivePrtModelHash.Next(index)) {
if (index < fxPrtModels.Num() &&
fxPrtModels[index].pDecl == particleDecl) {
inactivePrtModelHash.Remove(key, index);
activePrtModelHash.Add(key, index);
return fxPrtModels[index].pmodel;
}
}
if (fxPrtModels.Num() >= fxPrtModels.Max()) {
return nullptr;
}
fxPrtModel_t item{};
item.pDecl = particleDecl;
item.pmodel = GameLib_AllocParticleFxModel(renderWorld, particleDecl);
if (item.pmodel == nullptr) {
return nullptr;
}
const int index = fxPrtModels.Append(item);
activePrtModelHash.Add(key, index);
return item.pmodel;
}
void idFXModelRecycler::RecycleParticleFxModel(
const idDeclParticle* const particleDecl,
idRenderModelParticle* const model) {
if (particleDecl == nullptr || model == nullptr) {
return;
}
const int key = PointerKey(particleDecl);
for (int index = activePrtModelHash.First(key); index >= 0;
index = activePrtModelHash.Next(index)) {
if (index < fxPrtModels.Num() &&
fxPrtModels[index].pmodel == model) {
activePrtModelHash.Remove(key, index);
inactivePrtModelHash.Add(key, index);
return;
}
}
}
idRenderModel* idFXModelRecycler::GetStaticFxModel(
const idAtomicString& modelName, idRenderWorld* const renderWorld) {
if (modelName.IsEmpty()) {
return nullptr;
}
const int key = inactiveStaticModelHash.GenerateKeyForString(
modelName.c_str(), false);
for (int index = inactiveStaticModelHash.First(key); index >= 0;
index = inactiveStaticModelHash.Next(index)) {
if (index < fxStaticModels.Num() &&
fxStaticModels[index].modelName == modelName) {
inactiveStaticModelHash.Remove(key, index);
activeStaticModelHash.Add(key, index);
return fxStaticModels[index].rmodel;
}
}
if (fxStaticModels.Num() >= fxStaticModels.Max()) {
return nullptr;
}
fxStaticModel_t item{};
item.modelName = modelName;
item.rmodel = GameLib_AllocStaticFxModel(renderWorld, modelName.c_str());
if (item.rmodel == nullptr) {
return nullptr;
}
const int index = fxStaticModels.Append(item);
activeStaticModelHash.Add(key, index);
return item.rmodel;
}
void idFXModelRecycler::RecycleStaticFxModel(
const idAtomicString& modelName, idRenderModel* const model) {
if (modelName.IsEmpty() || model == nullptr) {
return;
}
const int key = activeStaticModelHash.GenerateKeyForString(
modelName.c_str(), false);
for (int index = activeStaticModelHash.First(key); index >= 0;
index = activeStaticModelHash.Next(index)) {
if (index < fxStaticModels.Num() &&
fxStaticModels[index].rmodel == model) {
activeStaticModelHash.Remove(key, index);
inactiveStaticModelHash.Add(key, index);
return;
}
}
}
idFXAction::idFXAction()
: tagIndex(0)
, startOrg()
, startAxis(1.0f)
, rLight(nullptr)
, rModel(nullptr)
, rParticle(nullptr)
, screenPrtHandle(-1)
, flareManager()
, ribbonManager()
, tagData(4)
, lastParticleDropPos()
, renderParmStartValue(0.0f, 0.0f, 0.0f, 0.0f)
, randomAngles(0.0f, 0.0f, 0.0f)
, viewCallbacksID(-1) {
startOrg.Zero();
lastParticleDropPos.Zero();
}
idFXManager::idFXManager()
: initialized(false)
, fxDecl(nullptr)
, gameLibEffects(nullptr)
, ta(nullptr)
, rw(nullptr)
, systemColor(1.0f, 1.0f, 1.0f, 1.0f)
, random(0)
, soundInfo{nullptr, SND_CHANNEL_ANY}
, actions(4)
, actionState(4)
, remote(false)
, allowSurfaceOnlyInViewID(0)
, suppressSurfaceInViewID(0)
, viewCallbacksID(-1)
, declChangeId(-1)
, externalRotation(1.0f)
, externalPosition()
, hasExternalPositionAndRotation(false)
, actionBuffer{}
, actionBufferPos(0)
, serializeActionCount(0) {
externalPosition.Zero();
}
idFXManager::~idFXManager() {
Shutdown();
}
idVec4 idFXManager::GetVector(const idDeclRenderParm* const parameter) const {
return parameter != nullptr ? GameLib_GetFXRenderParm(parameter)
: idVec4(0.0f, 0.0f, 0.0f, 0.0f);
}
idVec4 idFXManager::GetTableColor(const idFXSingleAction& action,
const float fraction) const {
return GameLib_GetFXTableColor(action, fraction);
}
bool idFXManager::GetWorldSpaceTagVelocity(const tagData_t& tag,
const int gameMsPerFrame, idVec3& velocity) {
velocity.Zero();
return ta != nullptr && gameMsPerFrame > 0 &&
GameLib_GetFXTagVelocity(ta, tag, gameMsPerFrame, velocity);
}
int idFXManager::StartSound(const soundChannel_t channel,
const idSoundShader* const shader) {
if (soundInfo.emitter == nullptr || shader == nullptr) {
return 0;
}
const soundChannel_t resolved = channel == SND_CHANNEL_ANY
? soundInfo.channel : channel;
return GameLib_StartFXSound(soundInfo.emitter, resolved, shader);
}
idList<idViewCallbacks*, 109>& idFXManager::GetViewCallbacks() {
idList<idViewCallbacks*, 109>* callbacks = GameLib_GetFXViewCallbacks();
if (callbacks != nullptr) {
return *callbacks;
}
static idList<idViewCallbacks*, 109> empty;
return empty;
}
const char* idFXManager::GetName() const {
return fxDecl != nullptr ? GameLib_GetFXDeclName(fxDecl) : "";
}
bool idFXManager::IsStopped(const int time) const {
for (int index = 0; index < actionState.Num(); ++index) {
if (time < actionState[index].stopTime) {
return false;
}
}
return true;
}
void idFXManager::Init(const idDeclFX* const declFX,
idRenderWorld* const renderWorld,
const fxEmitterSound_t* const emitterSound,
idGameLibEffects* const effects, const float diversity,
idTreeAnimator* const treeAnimator) {
Shutdown();
if (declFX == nullptr) {
return;
}
fxDecl = declFX;
gameLibEffects = effects;
ta = treeAnimator;
rw = renderWorld;
random.SetSeed(static_cast<unsigned int>(diversity * 65535.0f));
if (emitterSound != nullptr) {
soundInfo = *emitterSound;
}
const int count = (std::max)(0, GameLib_GetFXDeclActionCount(fxDecl));
actions.SetNum(count);
actionState.SetNum(count);
declChangeId = GameLib_GetFXDeclChangeId(fxDecl);
for (int index = 0; index < count; ++index) {
CreateAction(index, rw);
}
EnumerateTags();
initialized = true;
}
void idFXManager::CreateAction(const int index,
idRenderWorld* const renderWorld) {
if (index < 0 || index >= actions.Num()) {
return;
}
ResetState(actionState[index]);
idFXActionParameters parameters{};
if (GameLib_GetFXActionParameters(fxDecl, index, parameters)) {
GameLib_CreateFXActionResource(gameLibEffects, renderWorld,
parameters, actions[index]);
}
}
void idFXManager::EnumerateTags() {
if (ta == nullptr) {
return;
}
for (int index = 0; index < actions.Num(); ++index) {
actions[index].tagData.Clear();
GameLib_EnumerateFXActionTags(ta, fxDecl, index,
actions[index].tagData);
}
}
void idFXManager::StartAction(const int index, const idVec3& origin,
const idMat3& axis, const int time, const int explicitTagIndex) {
if (index < 0 || index >= actions.Num()) {
return;
}
idFXActionParameters parameters{};
if (!GameLib_GetFXActionParameters(fxDecl, index, parameters)) {
return;
}
idFXAction& action = actions[index];
fxActionState_t& state = actionState[index];
action.startOrg = origin;
action.startAxis = axis;
action.tagIndex = explicitTagIndex >= 0 ? explicitTagIndex : 0;
if (explicitTagIndex < 0 && action.tagData.Num() > 1) {
action.tagIndex = random.RandomInt(action.tagData.Num());
}
action.randomAngles = idAngles(
RandomRange(random, parameters.randomRotationX),
RandomRange(random, parameters.randomRotationY),
RandomRange(random, parameters.randomRotationZ));
state.startDelay = static_cast<int>(RandomRange(random,
parameters.delay) * 1000.0f);
state.startTime = time;
state.stopTime = time + state.startDelay +
static_cast<int>(parameters.duration * 1000.0f);
state.fadeInStartTime = time + state.startDelay;
state.fadeInEndTime = state.fadeInStartTime +
static_cast<int>(parameters.fadeInTime * 1000.0f);
state.fadeOutStartTime = state.stopTime -
static_cast<int>(parameters.fadeOutTime * 1000.0f);
state.hidden = false;
state.started = false;
state.shouldTrigger = true;
state.forceStop = false;
}
int idFXManager::StartActions(const idVec3& origin, const idMat3& axis,
const int time, const fxCondition_t startCondition,
const fxExtraCondition_t extraCondition, const int explicitTagIndex) {
int startedCount = 0;
for (int index = 0; index < actions.Num(); ++index) {
idFXActionParameters parameters{};
if (!GameLib_GetFXActionParameters(fxDecl, index, parameters)) {
continue;
}
if (parameters.startCondition != startCondition) {
continue;
}
if (parameters.extraCondition != FX_EXTRA_COND_NONE &&
(static_cast<int>(parameters.extraCondition) &
static_cast<int>(extraCondition)) == 0) {
continue;
}
StartAction(index, origin, axis, time, explicitTagIndex);
++startedCount;
}
return startedCount;
}
int idFXManager::InternalStartFX(const fxActionCall_t& actionCall) {
if (!initialized) {
return 0;
}
const int result = StartActions(actionCall.org, actionCall.axis,
actionCall.time, actionCall.condition, actionCall.extraCondition,
actionCall.tagIdx);
++actionBufferPos;
return result;
}
int idFXManager::StartFX(const idVec3& origin, const idMat3& axis,
const int time, const fxCondition_t startCondition,
const int explicitTagIndex, const int delay) {
if (!initialized) {
return 0;
}
fxActionCall_t& call = actionBuffer[actionBufferPos % 8];
call.org = origin;
call.axis = axis;
call.condition = startCondition;
call.time = time + delay;
call.extraCondition = FX_EXTRA_COND_NONE;
call.tagIdx = explicitTagIndex;
call.actionType = FXACTION_START;
call.immediate = false;
call.viewCallbacksID = viewCallbacksID;
return InternalStartFX(call);
}
int idFXManager::StartFX(const idVec3& origin, const idMat3& axis,
const int time, const fxCondition_t startCondition,
const fxExtraCondition_t extraCondition) {
if (!initialized) {
return 0;
}
fxActionCall_t& call = actionBuffer[actionBufferPos % 8];
call.org = origin;
call.axis = axis;
call.condition = startCondition;
call.time = time;
call.extraCondition = extraCondition;
call.tagIdx = -1;
call.actionType = FXACTION_START;
call.immediate = false;
call.viewCallbacksID = viewCallbacksID;
return InternalStartFX(call);
}
int idFXManager::StartFX(const idVec3& origin, const idMat3& axis,
const int time, const fxCondition_t startCondition) {
return StartFX(origin, axis, time, startCondition, -1, 0);
}
void idFXManager::LocalStartFX(const idVec3& origin, const idMat3& axis,
const int time, const fxCondition_t startCondition) {
if (initialized) {
StartActions(origin, axis, time, startCondition,
FX_EXTRA_COND_NONE, -1);
}
}
void idFXManager::ApplyFade(const idFXActionParameters& parameters,
idFXAction& action, fxActionState_t& state, const int time,
const float fraction) {
float fade = 1.0f;
if (parameters.fadeInTime > 0.0f && time < state.fadeInEndTime) {
const int duration = state.fadeInEndTime - state.fadeInStartTime;
fade *= duration > 0 ? Clamp01(static_cast<float>(
time - state.fadeInStartTime) / duration) : 1.0f;
}
if (parameters.fadeOutTime > 0.0f && time >= state.fadeOutStartTime) {
const int duration = state.stopTime - state.fadeOutStartTime;
fade *= duration > 0 ? Clamp01(static_cast<float>(
state.stopTime - time) / duration) : 0.0f;
}
action.renderParmStartValue = idVec4(
systemColor.x * fade, systemColor.y * fade,
systemColor.z * fade, systemColor.w * fade * Clamp01(fraction));
}
void idFXManager::RestartAction(const int index, const int time) {
if (index < 0 || index >= actions.Num()) {
return;
}
const idVec3 origin = actions[index].startOrg;
const idMat3 axis = actions[index].startAxis;
StopAction(index, time, true, false);
StartAction(index, origin, axis, time, actions[index].tagIndex);
}
void idFXManager::StopAction(const int index, const int time,
const bool immediate, const bool recycleResources) {
if (index < 0 || index >= actions.Num()) {
return;
}
idFXActionParameters parameters{};
if (!GameLib_GetFXActionParameters(fxDecl, index, parameters)) {
return;
}
fxActionState_t& state = actionState[index];
if (state.startTime < 0) {
return;
}
if (!immediate && !state.forceStop && parameters.fadeOutTime > 0.0f &&
parameters.type != FX_SOUND) {
state.fadeOutStartTime = time;
state.stopTime = time + static_cast<int>(
parameters.fadeOutTime * 1000.0f);
state.forceStop = true;
return;
}
if (parameters.type == FX_FLARE) {
actions[index].flareManager.StopFlare();
} else if (parameters.type == FX_RIBBON) {
actions[index].ribbonManager.StopRibbon();
}
GameLib_StopFXActionResource(gameLibEffects, parameters, actions[index],
time, immediate, recycleResources);
const bool keepHidden = parameters.triggered;
ResetState(state);
state.hidden = keepHidden;
actions[index].lastParticleDropPos.Zero();
actions[index].randomAngles = idAngles(0.0f, 0.0f, 0.0f);
actions[index].startAxis = idMat3(1.0f);
actions[index].startOrg.Zero();
}
void idFXManager::StopActions(const int time,
const fxCondition_t stopCondition,
const fxExtraCondition_t extraCondition, const bool stopAll,
const bool immediate) {
for (int index = 0; index < actions.Num(); ++index) {
idFXActionParameters parameters{};
if (!GameLib_GetFXActionParameters(fxDecl, index, parameters)) {
continue;
}
if (!stopAll && parameters.stopCondition != stopCondition) {
continue;
}
if (!stopAll && parameters.extraCondition != FX_EXTRA_COND_NONE &&
(static_cast<int>(parameters.extraCondition) &
static_cast<int>(extraCondition)) == 0) {
continue;
}
StopAction(index, time, immediate, true);
}
}
void idFXManager::InternalStopFX(const fxActionCall_t& actionCall) {
if (!initialized) {
return;
}
StopActions(actionCall.time, actionCall.condition,
actionCall.extraCondition,
actionCall.actionType == FXACTION_STOP_ALL, actionCall.immediate);
++actionBufferPos;
}
void idFXManager::StopFX(const int time,
const fxCondition_t stopCondition, const bool immediate) {
StopFX(time, stopCondition, FX_EXTRA_COND_NONE, immediate);
}
void idFXManager::StopFX(const int time,
const fxCondition_t stopCondition,
const fxExtraCondition_t extraCondition, const bool immediate) {
if (!initialized) {
return;
}
fxActionCall_t& call = actionBuffer[actionBufferPos % 8];
call.condition = stopCondition;
call.time = time;
call.extraCondition = extraCondition;
call.actionType = FXACTION_STOP;
call.immediate = immediate;
call.viewCallbacksID = viewCallbacksID;
InternalStopFX(call);
}
void idFXManager::LocalStopFX(const int time,
const fxCondition_t stopCondition, const bool immediate) {
if (initialized) {
StopActions(time, stopCondition, FX_EXTRA_COND_NONE, false,
immediate);
}
}
void idFXManager::StopAllFX(const int time, const bool immediate) {
if (!initialized) {
return;
}
fxActionCall_t& call = actionBuffer[actionBufferPos % 8];
call.condition = FX_NONE;
call.time = time;
call.extraCondition = FX_EXTRA_COND_NONE;
call.actionType = FXACTION_STOP_ALL;
call.immediate = immediate;
call.viewCallbacksID = viewCallbacksID;
InternalStopFX(call);
}
void idFXManager::LocalStopAllFX(const int time, const bool immediate) {
if (initialized) {
StopActions(time, FX_NONE, FX_EXTRA_COND_NONE, true, immediate);
}
}
void idFXManager::UpdateActions(const idVec3& origin, const idMat3& axis,
const idVec3& velocity, const int time, const int gameMsPerFrame,
const int frameNumber, const float fovScale, const float depthHack) {
(void)gameMsPerFrame;
for (int index = 0; index < actions.Num(); ++index) {
idFXActionParameters parameters{};
if (!GameLib_GetFXActionParameters(fxDecl, index, parameters)) {
continue;
}
fxActionState_t& state = actionState[index];
idFXAction& action = actions[index];
if (state.startTime < 0 || state.hidden) {
continue;
}
const int actualStart = state.startTime + state.startDelay;
if (time < actualStart) {
continue;
}
if (!state.started) {
GameLib_StartFXActionResource(gameLibEffects, parameters, action,
action.startOrg, action.startAxis, actualStart);
if (parameters.type == FX_SOUND) {
StartSound(parameters.soundChannel, parameters.sound);
}
state.started = true;
}
if (time >= state.stopTime) {
if (parameters.looping && !state.forceStop) {
RestartAction(index, time + static_cast<int>(
parameters.restart * 1000.0f));
} else {
StopAction(index, time, true, true);
}
continue;
}
const int duration = (std::max)(1, state.stopTime - actualStart);
const float fraction = Clamp01(static_cast<float>(time - actualStart) /
static_cast<float>(duration));
ApplyFade(parameters, action, state, time, fraction);
const idVec3 updateOrigin = parameters.trackOrigin ? origin
: action.startOrg;
const idMat3 updateAxis = parameters.trackOrigin ? axis
: action.startAxis;
GameLib_UpdateFXActionResource(gameLibEffects, parameters, action,
updateOrigin, updateAxis, velocity, action.renderParmStartValue,
time, frameNumber, fovScale, depthHack);
}
}
void idFXManager::Update(const idVec3& parentOrigin,
const idMat3& parentAxis, const idVec3& parentVelocity, const int time,
const int gameMsPerFrame, const int frameNumber, const float fovScale,
const float depthHack) {
if (!initialized) {
return;
}
while (serializeActionCount > 0) {
--serializeActionCount;
fxActionCall_t& call = actionBuffer[actionBufferPos % 8];
call.time = time;
viewCallbacksID = call.viewCallbacksID;
if (call.actionType == FXACTION_START) {
InternalStartFX(call);
} else {
InternalStopFX(call);
}
}
UpdateActions(parentOrigin, parentAxis, parentVelocity, time,
gameMsPerFrame, frameNumber, fovScale, depthHack);
}
void idFXManager::ResetTreeAnimator(idTreeAnimator* const treeAnimator) {
ta = treeAnimator;
EnumerateTags();
}
void idFXManager::Serialize(idSerializer& serializer) {
GameLib_SerializeFXManager(serializer, *this);
}
void idFXManager::FreeActions() {
for (int index = 0; index < actions.Num(); ++index) {
idFXActionParameters parameters{};
if (GameLib_GetFXActionParameters(fxDecl, index, parameters)) {
GameLib_FreeFXActionResource(gameLibEffects, parameters,
actions[index]);
}
actions[index].tagData.Clear();
}
actions.Clear();
actionState.Clear();
}
void idFXManager::Shutdown() {
if (fxDecl != nullptr) {
StopActions(0, FX_NONE, FX_EXTRA_COND_NONE, true, true);
FreeActions();
}
initialized = false;
fxDecl = nullptr;
gameLibEffects = nullptr;
ta = nullptr;
rw = nullptr;
soundInfo.emitter = nullptr;
soundInfo.channel = SND_CHANNEL_ANY;
declChangeId = -1;
actionBufferPos = 0;
serializeActionCount = 0;
}