#include "CCollisionResponseData.hpp" #include "Particle/CParticleDataFactory.hpp" #include "Particle/CDecalDescription.hpp" #include "Particle/CSwooshDescription.hpp" #include "Particle/CElectricDescription.hpp" #include "Particle/CGenDescription.hpp" #include "Graphics/CModel.hpp" #include "CSimplePool.hpp" #include "CRandom16.hpp" namespace urde { const EWeaponCollisionResponseTypes CCollisionResponseData::skWorldMaterialTable[32] = { EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Unknown2, EWeaponCollisionResponseTypes::Metal, EWeaponCollisionResponseTypes::Grass, EWeaponCollisionResponseTypes::Ice, EWeaponCollisionResponseTypes::Goo, EWeaponCollisionResponseTypes::Metal, EWeaponCollisionResponseTypes::Wood, EWeaponCollisionResponseTypes::Grass, EWeaponCollisionResponseTypes::Lava, EWeaponCollisionResponseTypes::Lava, EWeaponCollisionResponseTypes::Ice, EWeaponCollisionResponseTypes::Mud, EWeaponCollisionResponseTypes::Metal, EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Goo, EWeaponCollisionResponseTypes::Goo, EWeaponCollisionResponseTypes::Sand, EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Metal, EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Default, }; const s32 CCollisionResponseData::kInvalidSFX = -1; static const std::vector kWCRTSFXIDs = { SBIG('NSFX'), SBIG('DSFX'), SBIG('CSFX'), SBIG('MSFX'), SBIG('GRFX'), SBIG('ICFX'), SBIG('GOFX'), SBIG('WSFX'), SBIG('WTFX'), SBIG('2MUD'), SBIG('2LAV'), SBIG('2SAN'), SBIG('2PRJ'), SBIG('DCFX'), SBIG('DSFX'), SBIG('DSHX'), SBIG('DEFX'), SBIG('ESFX'), SBIG('SHFX'), SBIG('BEFX'), SBIG('WWFX'), SBIG('TAFX'), SBIG('GTFX'), SBIG('SPFX'), SBIG('FPFX'), SBIG('FFFX'), SBIG('PAFX'), SBIG('BMFX'), SBIG('BFFX'), SBIG('PBFX'), SBIG('IBFX'), SBIG('4SVA'), SBIG('4RPR'), SBIG('4MTR'), SBIG('4PDS'), SBIG('4FLB'), SBIG('4DRN'), SBIG('4MRE'), SBIG('CZFX'), SBIG('JZAS'), SBIG('2ISE'), SBIG('2BSE'), SBIG('2ATB'), SBIG('2ATA'), SBIG('BSFX'), SBIG('WSFX'), SBIG('TSFX'), SBIG('GSFX'), SBIG('SSFX'), SBIG('FSFX'), SBIG('SFFX'), SBIG('PSFX'), SBIG('MSFX'), SBIG('SBFX'), SBIG('PBSX'), SBIG('IBSX'), SBIG('5SVA'), SBIG('5RPR'), SBIG('5MTR'), SBIG('5PDS'), SBIG('5FLB'), SBIG('5DRN'), SBIG('5MRE'), SBIG('CSFX'), SBIG('JZPS'), SBIG('4ISE'), SBIG('4BSE'), SBIG('4ATB'), SBIG('4ATA'), SBIG('BHFX'), SBIG('WHFX'), SBIG('THFX'), SBIG('GHFX'), SBIG('SHFX'), SBIG('FHFX'), SBIG('HFFX'), SBIG('PHFX'), SBIG('MHFX'), SBIG('HBFX'), SBIG('PBHX'), SBIG('IBHX'), SBIG('6SVA'), SBIG('6RPR'), SBIG('6MTR'), SBIG('6PDS'), SBIG('6FLB'), SBIG('6DRN'), SBIG('6MRE'), SBIG('CHFX'), SBIG('JZHS'), SBIG('6ISE'), SBIG('6BSE'), SBIG('6ATB'), SBIG('6ATA'), }; static const std::vector kWCRTIDs = { SBIG('NODP'), SBIG('DEFS'), SBIG('CRTS'), SBIG('MTLS'), SBIG('GRAS'), SBIG('ICEE'), SBIG('GOOO'), SBIG('WODS'), SBIG('WATR'), SBIG('1MUD'), SBIG('1LAV'), SBIG('1SAN'), SBIG('1PRJ'), SBIG('DCHR'), SBIG('DCHS'), SBIG('DCSH'), SBIG('DENM'), SBIG('DESP'), SBIG('DESH'), SBIG('BTLE'), SBIG('WASP'), SBIG('TALP'), SBIG('PTGM'), SBIG('SPIR'), SBIG('FPIR'), SBIG('FFLE'), SBIG('PARA'), SBIG('BMON'), SBIG('BFLR'), SBIG('PBOS'), SBIG('IBOS'), SBIG('1SVA'), SBIG('1RPR'), SBIG('1MTR'), SBIG('1PDS'), SBIG('1FLB'), SBIG('1DRN'), SBIG('1MRE'), SBIG('CHOZ'), SBIG('JZAP'), SBIG('1ISE'), SBIG('1BSE'), SBIG('1ATB'), SBIG('1ATA'), SBIG('BTSP'), SBIG('WWSP'), SBIG('TASP'), SBIG('TGSP'), SBIG('SPSP'), SBIG('FPSP'), SBIG('FFSP'), SBIG('PSSP'), SBIG('BMSP'), SBIG('BFSP'), SBIG('PBSP'), SBIG('IBSP'), SBIG('2SVA'), SBIG('2RPR'), SBIG('2MTR'), SBIG('2PDS'), SBIG('2FLB'), SBIG('2DRN'), SBIG('2MRE'), SBIG('CHSP'), SBIG('JZSP'), SBIG('3ISE'), SBIG('3BSE'), SBIG('3ATB'), SBIG('3ATA'), SBIG('BTSH'), SBIG('WWSH'), SBIG('TASH'), SBIG('TGSH'), SBIG('SPSH'), SBIG('FPSH'), SBIG('FFSH'), SBIG('PSSH'), SBIG('BMSH'), SBIG('BFSH'), SBIG('PBSH'), SBIG('IBSH'), SBIG('3SVA'), SBIG('3RPR'), SBIG('3MTR'), SBIG('3PDS'), SBIG('3FLB'), SBIG('3DRN'), SBIG('3MRE'), SBIG('CHSH'), SBIG('JZSH'), SBIG('5ISE'), SBIG('5BSE'), SBIG('5ATB'), SBIG('5ATA')}; static const std::vector kWCRTDecalIDs = {SBIG('NCDL'), SBIG('DDCL'), SBIG('CODL'), SBIG('MEDL'), SBIG('GRDL'), SBIG('ICDL'), SBIG('GODL'), SBIG('WODL'), SBIG('WTDL'), SBIG('3MUD'), SBIG('3LAV'), SBIG('3SAN'), SBIG('CHDL'), SBIG('ENDL')}; using CPF = CParticleDataFactory; void CCollisionResponseData::AddParticleSystemToResponse(EWeaponCollisionResponseTypes type, CInputStream& in, CSimplePool* resPool) { int i = int(type); std::vector tracker; tracker.resize(8); x0_generators[i].emplace(CPF::GetChildGeneratorDesc(in, resPool, tracker).m_token); } bool CCollisionResponseData::CheckAndAddDecalToResponse(FourCC clsId, CInputStream& in, CSimplePool* resPool) { int i = 0; for (const FourCC& type : kWCRTDecalIDs) { if (type == clsId) { FourCC cls = CPF::GetClassID(in); if (cls == SBIG('NONE')) return true; CAssetId id = u64(in.readUint32Big()); if (!id.IsValid()) return true; x20_decals[i].emplace(resPool->GetObj({FOURCC('DPSC'), id})); return true; } i++; } return false; } bool CCollisionResponseData::CheckAndAddSoundFXToResponse(FourCC clsId, CInputStream& in) { int i = 0; for (const FourCC& type : kWCRTSFXIDs) { if (type == clsId) { FourCC cls = CPF::GetClassID(in); if (cls == SBIG('NONE')) return true; x10_sfx[i] = CPF::GetInt(in); return true; } i++; } return false; } bool CCollisionResponseData::CheckAndAddParticleSystemToResponse(FourCC clsId, CInputStream& in, CSimplePool* resPool) { int i = 0; for (const FourCC& type : kWCRTIDs) { if (type == clsId) { AddParticleSystemToResponse(EWeaponCollisionResponseTypes(i), in, resPool); return true; } i++; } return false; } bool CCollisionResponseData::CheckAndAddResourceToResponse(FourCC clsId, CInputStream& in, CSimplePool* resPool) { if (CheckAndAddParticleSystemToResponse(clsId, in, resPool)) return true; if (CheckAndAddSoundFXToResponse(clsId, in)) return true; if (CheckAndAddDecalToResponse(clsId, in, resPool)) return true; return false; } CCollisionResponseData::CCollisionResponseData(CInputStream& in, CSimplePool* resPool) : x30_RNGE(50.f), x34_FOFF(0.2f) { x0_generators.resize(94); x10_sfx.resize(94); x20_decals.resize(94); for (s32& id : x10_sfx) id = kInvalidSFX; FourCC clsId = CPF::GetClassID(in); if (clsId == UncookedResType()) { CRandom16 rand{99}; CGlobalRandom gr(rand); while (clsId != SBIG('_END')) { clsId = CPF::GetClassID(in); if (CheckAndAddResourceToResponse(clsId, in, resPool)) continue; if (clsId == SBIG('RNGE')) { CPF::GetClassID(in); x30_RNGE = CPF::GetReal(in); } else if (clsId == SBIG('FOFF')) { CPF::GetClassID(in); x34_FOFF = CPF::GetReal(in); } } } } const rstl::optional_object>& CCollisionResponseData::GetParticleDescription(EWeaponCollisionResponseTypes type) const { if (x0_generators[u32(type)]) return x0_generators[u32(type)]; bool foundType = false; if (ResponseTypeIsEnemyNormal(type)) { type = EWeaponCollisionResponseTypes::EnemyNormal; foundType = true; } else if (ResponseTypeIsEnemySpecial(type)) { type = EWeaponCollisionResponseTypes::EnemySpecial; foundType = true; } else if (ResponseTypeIsEnemyShielded(type)) { type = EWeaponCollisionResponseTypes::EnemyShielded; foundType = true; } if (foundType && !x0_generators[u32(type)]) type = EWeaponCollisionResponseTypes::EnemyNormal; if (!x0_generators[u32(type)] && type != EWeaponCollisionResponseTypes::None) type = EWeaponCollisionResponseTypes::Default; return x0_generators[u32(type)]; } const rstl::optional_object>& CCollisionResponseData::GetDecalDescription(EWeaponCollisionResponseTypes type) const { return x20_decals[u32(type)]; } s32 CCollisionResponseData::GetSoundEffectId(EWeaponCollisionResponseTypes type) const { if (x10_sfx[u32(type)] == kInvalidSFX) { if (ResponseTypeIsEnemyNormal(type)) type = EWeaponCollisionResponseTypes::EnemyNormal; else if (ResponseTypeIsEnemySpecial(type)) type = EWeaponCollisionResponseTypes::EnemySpecial; else if (ResponseTypeIsEnemyShielded(type)) type = EWeaponCollisionResponseTypes::EnemyShielded; else type = EWeaponCollisionResponseTypes::Default; } return x10_sfx[u32(type)]; } EWeaponCollisionResponseTypes CCollisionResponseData::GetWorldCollisionResponseType(s32 id) { if (id < 0 || id >= 32) return EWeaponCollisionResponseTypes::Default; return skWorldMaterialTable[id]; } bool CCollisionResponseData::ResponseTypeIsEnemyNormal(EWeaponCollisionResponseTypes type) { return (type >= EWeaponCollisionResponseTypes::Unknown19 && type <= EWeaponCollisionResponseTypes::Unknown43); } bool CCollisionResponseData::ResponseTypeIsEnemySpecial(EWeaponCollisionResponseTypes type) { return (type >= EWeaponCollisionResponseTypes::Unknown44 && type <= EWeaponCollisionResponseTypes::Unknown68); } bool CCollisionResponseData::ResponseTypeIsEnemyShielded(EWeaponCollisionResponseTypes type) { return (type >= EWeaponCollisionResponseTypes::Unknown69 && type <= EWeaponCollisionResponseTypes::Unknown93); } FourCC CCollisionResponseData::UncookedResType() { return SBIG('CRSM'); } CFactoryFnReturn FCollisionResponseDataFactory(const SObjectTag& tag, CInputStream& in, const CVParamTransfer& vparms, CObjectReference*) { CSimplePool* sp = vparms.GetOwnedObj(); return TToken::GetIObjObjectFor( std::unique_ptr(new CCollisionResponseData(in, sp))); } }