// ======================= ZoneTool ======================= // zonetool, a fastfile linker for various // Call of Duty titles. // // Project: https://github.com/ZoneTool/zonetool // Author: RektInator (https://github.com/RektInator) // License: GNU GPL v3.0 // ======================================================== #include "stdafx.hpp" #include "IW5/Assets/FxEffectDef.hpp" namespace ZoneTool { namespace IW4 { void IFxEffectDef::init(const std::string& name, ZoneMemory* mem) { this->name_ = name; this->asset_ = this->parse(name, mem); if (!this->asset_) { this->asset_ = DB_FindXAssetHeader(this->type(), this->name().data()).fx; } } void IFxEffectDef::prepare(ZoneBuffer* buf, ZoneMemory* mem) { } FxEffectDef* IFxEffectDef::parse(const std::string& name, ZoneMemory* mem) { const auto iw5_fx = IW5::IFxEffectDef::parse(name, mem); if (!iw5_fx) { return nullptr; } const auto fx = mem->Alloc(); memcpy(fx, iw5_fx, sizeof FxEffectDef); // transform elem defs const auto elem_count = fx->elemDefCountLooping + fx->elemDefCountEmission + fx->elemDefCountOneShot; fx->elemDefs = mem->Alloc(elem_count); for (auto i = 0; i < elem_count; i++) { memcpy(&fx->elemDefs[i], &iw5_fx->elemDefs[i], sizeof FxElemDef); if (fx->elemDefs[i].extended.trailDef) { // iw5 feature, unsupported on iw4 if (fx->elemDefs[i].elemType == 9) { fx->elemDefs[i].extended.trailDef = nullptr; } } } return fx; } void IFxEffectDef::load_depending(IZone* zone) { auto* data = this->asset_; auto load_fx_elem_visuals = [zone](FxElemDef* def, FxElemDefVisuals* vis) { if (def->elemType == 11) { for (auto i = 0; i < def->visualCount; i++) { if (vis->markArray[i]) { if (vis->markArray[i][0]) { zone->add_asset_of_type(material, vis->markArray[i][0]->name); } if (vis->markArray[i][1]) { zone->add_asset_of_type(material, vis->markArray[i][1]->name); } } } } else if (def->visualCount > 1) { for (auto i = 0; i < def->visualCount; i++) { if (def->elemType == 12 && vis->array[i].effectDef) { zone->add_asset_of_type(fx, vis->array[i].effectDef->name); } else if (def->elemType == 10 && vis->array[i].soundName) { zone->add_asset_of_type(sound, vis->array[i].soundName); } else if (def->elemType == 7 && vis->array[i].xmodel) { zone->add_asset_of_type(xmodel, vis->array[i].xmodel->name); } else { if (def->elemType != 8 && vis->array[i].material) { zone->add_asset_of_type(material, vis->array[i].material->name); } } } } else { if (def->elemType == 12 && vis->instance.effectDef) { zone->add_asset_of_type(fx, vis->instance.effectDef->name); } else if (def->elemType == 10 && vis->instance.soundName) { zone->add_asset_of_type(sound, vis->instance.soundName); } else if (def->elemType == 7 && vis->instance.xmodel) { zone->add_asset_of_type(xmodel, vis->instance.xmodel->name); } else { if (def->elemType != 8 && vis->instance.material) { zone->add_asset_of_type(material, vis->instance.material->name); } } } }; // Loop through frames for (auto i = 0; i < data->elemDefCountEmission + data->elemDefCountLooping + data->elemDefCountOneShot; i++) { auto* def = &data->elemDefs[i]; // Sub-FX effects if (def->effectEmitted) { zone->add_asset_of_type(fx, def->effectEmitted->name); } if (def->effectOnDeath) { zone->add_asset_of_type(fx, def->effectOnDeath->name); } if (def->effectOnImpact) { zone->add_asset_of_type(fx, def->effectOnImpact->name); } // Visuals load_fx_elem_visuals(def, &def->visuals); } } std::string IFxEffectDef::name() { return this->name_; } std::int32_t IFxEffectDef::type() { return fx; } void IFxEffectDef::write_fx_elem_visuals(IZone* zone, ZoneBuffer* buf, FxElemDef* def, FxElemVisuals* dest) { auto* data = dest; switch (def->elemType) { case FX_ELEM_TYPE_RUNNER: { buf->write_str(data->effectDef->name); ZoneBuffer::clear_pointer(&dest->effectDef); break; } case FX_ELEM_TYPE_SOUND: { if (data->soundName) { buf->write_str(data->soundName); ZoneBuffer::clear_pointer(&dest->soundName); } break; } case FX_ELEM_TYPE_SPOT_LIGHT: { dest->anonymous = (data->anonymous) ? zone->get_asset_pointer(lightdef, ((GfxLightDef*)data->anonymous)->name) : nullptr; break; } case FX_ELEM_TYPE_MODEL: { dest->xmodel = (data->xmodel) ? reinterpret_cast(zone->get_asset_pointer(xmodel, data->xmodel->name)) : nullptr; break; } default: { if (def->elemType != FX_ELEM_TYPE_OMNI_LIGHT) { dest->material = (data->material) ? reinterpret_cast(zone->get_asset_pointer( material, data->material->name)) : nullptr; } } } } void IFxEffectDef::write_fx_elem_def_visuals(IZone* zone, ZoneBuffer* buf, FxElemDef* def, FxElemDefVisuals* dest) { auto* data = dest; if (def->elemType == FX_ELEM_TYPE_DECAL) { if (data->markArray) { auto destvisuals = buf->write(data->markArray, def->visualCount); for (int i = 0; i < def->visualCount; i++) { destvisuals[i][0] = (data->markArray[i][0]) ? reinterpret_cast(zone->get_asset_pointer( material, data->markArray[i][0]->name)) : nullptr; destvisuals[i][1] = (data->markArray[i][1]) ? reinterpret_cast(zone->get_asset_pointer( material, data->markArray[i][1]->name)) : nullptr; } } } else if (def->visualCount > 1) { auto* vis = buf->write(data->array, def->visualCount); for (auto i = 0; i < def->visualCount; i++) { write_fx_elem_visuals(zone, buf, def, &vis[i]); } } else { write_fx_elem_visuals(zone, buf, def, &dest->instance); } } void IFxEffectDef::write_fx_elem_def(IZone* zone, ZoneBuffer* buf, FxElemDef* dest) { auto* data = dest; if (data->velSamples) { buf->align(3); buf->write(data->velSamples, data->velIntervalCount + 1); ZoneBuffer::clear_pointer(&dest->velSamples); } if (data->visSamples) { buf->align(3); buf->write(data->visSamples, data->visStateIntervalCount + 1); ZoneBuffer::clear_pointer(&dest->visSamples); } write_fx_elem_def_visuals(zone, buf, data, &dest->visuals); if (data->effectOnImpact) { buf->write_str_raw(data->effectOnImpact->name); ZoneBuffer::clear_pointer(&dest->effectOnImpact); } if (data->effectOnDeath) { buf->write_str_raw(data->effectOnDeath->name); ZoneBuffer::clear_pointer(&dest->effectOnDeath); } if (data->effectEmitted) { buf->write_str_raw(data->effectEmitted->name); ZoneBuffer::clear_pointer(&dest->effectEmitted); } if (data->extended.trailDef) { if (data->elemType == FX_ELEM_TYPE_TRAIL) { if (data->extended.trailDef) { buf->align(3); buf->write(data->extended.trailDef, sizeof(FxTrailDef)); if (data->extended.trailDef->verts) { buf->align(3); buf->write(data->extended.trailDef->verts, data->extended.trailDef->vertCount); } if (data->extended.trailDef->inds) { buf->align(1); buf->write(data->extended.trailDef->inds, data->extended.trailDef->indCount); } ZoneBuffer::clear_pointer(&dest->extended.trailDef); } } else if (data->elemType == FX_ELEM_TYPE_SPARKFOUNTAIN) { if (data->extended.sparkFountain) { buf->align(3); buf->write(data->extended.sparkFountain); ZoneBuffer::clear_pointer(&dest->extended.sparkFountain); } } else if (data->elemType == FX_ELEM_TYPE_SPOT_LIGHT) { if (data->extended.unknownDef) { buf->align(3); buf->write_stream(data->extended.unknownDef, 24); ZoneBuffer::clear_pointer(&dest->extended.unknownDef); } } else { if (data->extended.unknownDef) { buf->align(1); buf->write_stream(data->extended.unknownDef, sizeof(BYTE)); ZoneBuffer::clear_pointer(&dest->extended.unknownDef); } } } } void IFxEffectDef::write(IZone* zone, ZoneBuffer* buf) { auto* data = this->asset_; auto* dest = buf->write(data); buf->push_stream(3); START_LOG_STREAM; dest->name = buf->write_str(this->name()); if (data->elemDefs) { buf->align(3); auto* fx_elem_def = buf->write(data->elemDefs, data->elemDefCountEmission + data->elemDefCountLooping + data-> elemDefCountOneShot); for (std::int32_t i = 0; i < (data->elemDefCountEmission + data->elemDefCountLooping + data-> elemDefCountOneShot); i++) { write_fx_elem_def(zone, buf, &fx_elem_def[i]); } ZoneBuffer::clear_pointer(&dest->elemDefs); } END_LOG_STREAM; buf->pop_stream(); } void IFxEffectDef::dump(FxEffectDef* asset) { auto* iw5_fx = new IW5::FxEffectDef; memcpy(iw5_fx, asset, sizeof FxEffectDef); memset(iw5_fx->pad, 0, sizeof iw5_fx->pad); // alloc elemdefs const auto elem_def_count = iw5_fx->elemDefCountEmission + iw5_fx->elemDefCountLooping + iw5_fx->elemDefCountOneShot; iw5_fx->elemDefs = new IW5::FxElemDef[elem_def_count]; // transform elemdefs to iw5 format for (auto i = 0; i < elem_def_count; i++) { memcpy(&iw5_fx->elemDefs[i], &asset->elemDefs[i], sizeof IW4::FxElemDef); iw5_fx->elemDefs[i].pad = 0; } IW5::IFxEffectDef::dump(iw5_fx); delete[] iw5_fx->elemDefs; delete iw5_fx; } } }