From 5b11848f4d5d7594481fc5915acee0af4c676e0b Mon Sep 17 00:00:00 2001 From: Paging Red Date: Sat, 20 Jun 2026 07:03:36 -0400 Subject: [PATCH] feat: T5 weapon dumping & loading (#792) * Update docs. * Add weapon constants. * Register asset dumper. * Add fields and strings for weapon parsing. * Add gdt and raw weapon loader. * Add weapon dumper. * Clang format. * Update T5 strings. * Fix forgotten rename. * Clang format. * fix: add missing t5 weapon fields * chore: properly sort,format and check size of t5 weapon enum strings * chore: remove unused functions * chore: add t5 weapon checks and defaults * format enum strings * chore: make FlameTable struct use pascal case name * feat: dump and load flametable * fix: make loaded weapons match vanilla data --------- Co-authored-by: njohnson Co-authored-by: Jan Laupetin --- docs/SupportedAssetTypes.md | 2 +- src/Common/Game/T4/T4_Assets.h | 6 +- src/Common/Game/T5/GameT5.cpp | 1 + src/Common/Game/T5/T5.h | 2 + src/Common/Game/T5/T5_Assets.h | 63 +- src/Common/Game/T6/T6_Assets.h | 8 +- src/ObjCommon/Game/T5/ObjConstantsT5.h | 3 + .../Game/T5/Weapon/FlameTableFields.h | 128 +++ src/ObjCommon/Game/T5/Weapon/WeaponFields.h | 756 ++++++++++++++++++ src/ObjCommon/Game/T5/Weapon/WeaponStrings.h | 211 +++++ src/ObjCommon/Weapon/WeaponCommon.cpp | 5 + src/ObjCommon/Weapon/WeaponCommon.h | 3 +- src/ObjLoading/Game/T5/ObjLoaderT5.cpp | 7 +- .../Game/T5/Weapon/FlameTableLoaderT5.cpp | 93 +++ .../Game/T5/Weapon/FlameTableLoaderT5.h | 13 + .../Game/T5/Weapon/WeaponGdtLoaderT5.cpp | 54 ++ .../Game/T5/Weapon/WeaponGdtLoaderT5.h | 14 + .../T5/Weapon/WeaponInfoStringLoaderT5.cpp | 457 +++++++++++ .../Game/T5/Weapon/WeaponInfoStringLoaderT5.h | 21 + .../Game/T5/Weapon/WeaponRawLoaderT5.cpp | 56 ++ .../Game/T5/Weapon/WeaponRawLoaderT5.h | 13 + .../SubAssetDeduplicationDumperState.h | 21 + src/ObjWriting/Game/T5/ObjWriterT5.cpp | 3 +- .../Game/T5/Weapon/WeaponDumperT5.cpp | 442 ++++++++++ .../Game/T5/Weapon/WeaponDumperT5.h | 13 + src/Utils/Utils/StringUtils.cpp | 12 + src/Utils/Utils/StringUtils.h | 2 + src/ZoneCode/Game/T4/XAssets/WeaponDef.txt | 4 +- .../Game/T5/XAssets/WeaponVariantDef.txt | 4 +- .../Game/T6/XAssets/WeaponVariantDef.txt | 4 +- 30 files changed, 2382 insertions(+), 39 deletions(-) create mode 100644 src/ObjCommon/Game/T5/Weapon/FlameTableFields.h create mode 100644 src/ObjCommon/Game/T5/Weapon/WeaponFields.h create mode 100644 src/ObjCommon/Game/T5/Weapon/WeaponStrings.h create mode 100644 src/ObjLoading/Game/T5/Weapon/FlameTableLoaderT5.cpp create mode 100644 src/ObjLoading/Game/T5/Weapon/FlameTableLoaderT5.h create mode 100644 src/ObjLoading/Game/T5/Weapon/WeaponGdtLoaderT5.cpp create mode 100644 src/ObjLoading/Game/T5/Weapon/WeaponGdtLoaderT5.h create mode 100644 src/ObjLoading/Game/T5/Weapon/WeaponInfoStringLoaderT5.cpp create mode 100644 src/ObjLoading/Game/T5/Weapon/WeaponInfoStringLoaderT5.h create mode 100644 src/ObjLoading/Game/T5/Weapon/WeaponRawLoaderT5.cpp create mode 100644 src/ObjLoading/Game/T5/Weapon/WeaponRawLoaderT5.h create mode 100644 src/ObjWriting/Dumping/SubAssetDeduplicationDumperState.h create mode 100644 src/ObjWriting/Game/T5/Weapon/WeaponDumperT5.cpp create mode 100644 src/ObjWriting/Game/T5/Weapon/WeaponDumperT5.h diff --git a/docs/SupportedAssetTypes.md b/docs/SupportedAssetTypes.md index 69f9024a..d12bfc55 100644 --- a/docs/SupportedAssetTypes.md +++ b/docs/SupportedAssetTypes.md @@ -180,7 +180,7 @@ The following section specify which assets are supported to be dumped to disk (u | MenuList | ❌ | ❌ | | | menuDef_t | ❌ | ❌ | | | LocalizeEntry | ✅ | ✅ | | -| WeaponVariantDef | ❌ | ❌ | | +| WeaponVariantDef | ✅ | ✅ | | | SndDriverGlobals | ❌ | ❌ | | | FxEffectDef | ❌ | ❌ | | | FxImpactTable | ❌ | ❌ | | diff --git a/src/Common/Game/T4/T4_Assets.h b/src/Common/Game/T4/T4_Assets.h index 4072e978..820bcd57 100644 --- a/src/Common/Game/T4/T4_Assets.h +++ b/src/Common/Game/T4/T4_Assets.h @@ -3242,7 +3242,7 @@ namespace T4 int clientOnly; }; - struct flameTable + struct FlameTable { float flameVar_streamChunkGravityStart; float flameVar_streamChunkGravityEnd; @@ -3788,8 +3788,8 @@ namespace T4 float hipDofEnd; const char* flameTableFirstPerson; const char* flameTableThirdPerson; - flameTable* flameTableFirstPersonPtr; - flameTable* flameTableThirdPersonPtr; + FlameTable* flameTableFirstPersonPtr; + FlameTable* flameTableThirdPersonPtr; FxEffectDef* tagFx_preparationEffect; FxEffectDef* tagFlash_preparationEffect; }; diff --git a/src/Common/Game/T5/GameT5.cpp b/src/Common/Game/T5/GameT5.cpp index 70c424cf..a128f3dc 100644 --- a/src/Common/Game/T5/GameT5.cpp +++ b/src/Common/Game/T5/GameT5.cpp @@ -24,6 +24,7 @@ namespace "vertexdecl", "vertexshader", "pixelshader", + "flametable", }; static_assert(std::extent_v == SUB_ASSET_TYPE_COUNT); } // namespace diff --git a/src/Common/Game/T5/T5.h b/src/Common/Game/T5/T5.h index 5b611c26..6a1460de 100644 --- a/src/Common/Game/T5/T5.h +++ b/src/Common/Game/T5/T5.h @@ -66,6 +66,7 @@ namespace T5 SUB_ASSET_TYPE_VERTEX_DECL, SUB_ASSET_TYPE_VERTEX_SHADER, SUB_ASSET_TYPE_PIXEL_SHADER, + SUB_ASSET_TYPE_FLAME_TABLE, SUB_ASSET_TYPE_COUNT }; @@ -212,6 +213,7 @@ namespace T5 using SubAssetVertexDecl = SubAsset; using SubAssetVertexShader = SubAsset; using SubAssetPixelShader = SubAsset; + using SubAssetFlameTable = SubAsset; } // namespace T5 DEFINE_ASSET_NAME_ACCESSOR(T5::AssetPhysPreset, name); diff --git a/src/Common/Game/T5/T5_Assets.h b/src/Common/Game/T5/T5_Assets.h index c8f9db37..3cc91b73 100644 --- a/src/Common/Game/T5/T5_Assets.h +++ b/src/Common/Game/T5/T5_Assets.h @@ -3778,7 +3778,8 @@ namespace T5 WEAPON_ICON_RATIO_1TO1 = 0x0, WEAPON_ICON_RATIO_2TO1 = 0x1, WEAPON_ICON_RATIO_4TO1 = 0x2, - WEAPON_ICON_RATIO_COUNT = 0x3, + + WEAPON_ICON_RATIO_NUM, }; enum weapType_t @@ -3791,7 +3792,8 @@ namespace T5 WEAPTYPE_BOMB = 0x5, WEAPTYPE_MINE = 0x6, WEAPTYPE_MELEE = 0x7, - WEAPTYPE_NUM = 0x8, + + WEAPTYPE_NUM, }; enum weapClass_t @@ -3809,7 +3811,8 @@ namespace T5 WEAPCLASS_ITEM = 0xA, WEAPCLASS_MELEE = 0xB, WEAPCLASS_KILLSTREAK_ALT_STORED_WEAPON = 0xC, - WEAPCLASS_NUM = 0xD, + + WEAPCLASS_NUM, }; enum PenetrateType @@ -3818,7 +3821,8 @@ namespace T5 PENETRATE_TYPE_SMALL = 0x1, PENETRATE_TYPE_MEDIUM = 0x2, PENETRATE_TYPE_LARGE = 0x3, - PENETRATE_TYPE_COUNT = 0x4, + + PENETRATE_TYPE_NUM, }; enum ImpactType @@ -3839,7 +3843,8 @@ namespace T5 IMPACT_TYPE_TANK_SHELL = 0xD, IMPACT_TYPE_BOLT = 0xE, IMPACT_TYPE_BLADE = 0xF, - IMPACT_TYPE_COUNT = 0x10, + + IMPACT_TYPE_NUM, }; enum weapInventoryType_t @@ -3849,7 +3854,8 @@ namespace T5 WEAPINVENTORY_ITEM = 0x2, WEAPINVENTORY_ALTMODE = 0x3, WEAPINVENTORY_MELEE = 0x4, - WEAPINVENTORYCOUNT = 0x5, + + WEAPINVENTORY_NUM, }; enum weapFireType_t @@ -3861,7 +3867,8 @@ namespace T5 WEAPON_FIRETYPE_BURSTFIRE4 = 0x4, WEAPON_FIRETYPE_STACKED = 0x5, WEAPON_FIRETYPE_MINIGUN = 0x6, - WEAPON_FIRETYPECOUNT = 0x7, + + WEAPON_FIRETYPE_NUM, }; enum weapClipType_t @@ -3872,7 +3879,8 @@ namespace T5 WEAPON_CLIPTYPE_DP28 = 0x3, WEAPON_CLIPTYPE_PTRS = 0x4, WEAPON_CLIPTYPE_LMG = 0x5, - WEAPON_CLIPTYPECOUNT = 0x6, + + WEAPON_CLIPTYPE_NUM, }; enum OffhandClass @@ -3882,7 +3890,8 @@ namespace T5 OFFHAND_CLASS_SMOKE_GRENADE = 0x2, OFFHAND_CLASS_FLASH_GRENADE = 0x3, OFFHAND_CLASS_GEAR = 0x4, - OFFHAND_CLASS_COUNT = 0x5, + + OFFHAND_CLASS_NUM, }; enum OffhandSlot @@ -3892,7 +3901,8 @@ namespace T5 OFFHAND_SLOT_TACTICAL_GRENADE = 0x2, OFFHAND_SLOT_EQUIPMENT = 0x3, OFFHAND_SLOT_SPECIFIC_USE = 0x4, - OFFHAND_SLOT_COUNT = 0x5, + + OFFHAND_SLOT_NUM, }; enum weapStance_t @@ -3900,7 +3910,8 @@ namespace T5 WEAPSTANCE_STAND = 0x0, WEAPSTANCE_DUCK = 0x1, WEAPSTANCE_PRONE = 0x2, - WEAPSTANCE_NUM = 0x3, + + WEAPSTANCE_NUM, }; enum activeReticleType_t @@ -3908,7 +3919,8 @@ namespace T5 VEH_ACTIVE_RETICLE_NONE = 0x0, VEH_ACTIVE_RETICLE_PIP_ON_A_STICK = 0x1, VEH_ACTIVE_RETICLE_BOUNCING_DIAMOND = 0x2, - VEH_ACTIVE_RETICLE_COUNT = 0x3, + + VEH_ACTIVE_RETICLE_NUM, }; enum ammoCounterClipType_t @@ -3920,14 +3932,16 @@ namespace T5 AMMO_COUNTER_CLIP_ROCKET = 0x4, AMMO_COUNTER_CLIP_BELTFED = 0x5, AMMO_COUNTER_CLIP_ALTWEAPON = 0x6, - AMMO_COUNTER_CLIP_COUNT = 0x7, + + AMMO_COUNTER_CLIP_NUM, }; enum weapOverlayReticle_t { WEAPOVERLAYRETICLE_NONE = 0x0, WEAPOVERLAYRETICLE_CROSSHAIR = 0x1, - WEAPOVERLAYRETICLE_NUM = 0x2, + + WEAPOVERLAYRETICLE_NUM, }; enum WeapOverlayInteface_t @@ -3935,7 +3949,8 @@ namespace T5 WEAPOVERLAYINTERFACE_NONE = 0x0, WEAPOVERLAYINTERFACE_JAVELIN = 0x1, WEAPOVERLAYINTERFACE_TURRETSCOPE = 0x2, - WEAPOVERLAYINTERFACECOUNT = 0x3, + + WEAPOVERLAYINTERFACE_NUM, }; enum weapProjExposion_t @@ -3950,7 +3965,8 @@ namespace T5 WEAPPROJEXP_FIRE = 0x7, WEAPPROJEXP_NAPALMBLOB = 0x8, WEAPPROJEXP_BOLT = 0x9, - WEAPPROJEXP_NUM = 0xA, + + WEAPPROJEXP_NUM, }; enum WeapStickinessType @@ -3961,7 +3977,8 @@ namespace T5 WEAPSTICKINESS_GROUND = 0x3, WEAPSTICKINESS_GROUND_WITH_YAW = 0x4, WEAPSTICKINESS_FLESH = 0x5, - WEAPSTICKINESS_COUNT = 0x6, + + WEAPSTICKINESS_NUM, }; enum WeapRotateType @@ -3969,7 +3986,8 @@ namespace T5 WEAPROTATE_GRENADE_ROTATE = 0x0, WEAPROTATE_BLADE_ROTATE = 0x1, WEAPROTATE_CYLINDER_ROTATE = 0x2, - WEAPROTATE_COUNT = 0x3, + + WEAPROTATE_NUM, }; enum guidedMissileType_t @@ -3981,7 +3999,8 @@ namespace T5 MISSILE_GUIDANCE_BALLISTIC = 0x4, MISSILE_GUIDANCE_WIREGUIDED = 0x5, MISSILE_GUIDANCE_TVGUIDED = 0x6, - MISSILE_GUIDANCE_COUNT = 0x7, + + MISSILE_GUIDANCE_NUM, }; enum weapAnimFiles_t @@ -4118,7 +4137,7 @@ namespace T5 HITLOC_COUNT }; - struct flameTable + struct FlameTable { float flameVar_streamChunkGravityStart; float flameVar_streamChunkGravityEnd; @@ -4741,8 +4760,8 @@ namespace T5 int scanPauseTime; const char* flameTableFirstPerson; const char* flameTableThirdPerson; - flameTable* flameTableFirstPersonPtr; - flameTable* flameTableThirdPersonPtr; + FlameTable* flameTableFirstPersonPtr; + FlameTable* flameTableThirdPersonPtr; FxEffectDef* tagFx_preparationEffect; FxEffectDef* tagFlash_preparationEffect; bool doGibbing; diff --git a/src/Common/Game/T6/T6_Assets.h b/src/Common/Game/T6/T6_Assets.h index a069ae35..5fb61668 100644 --- a/src/Common/Game/T6/T6_Assets.h +++ b/src/Common/Game/T6/T6_Assets.h @@ -88,7 +88,7 @@ namespace T6 struct XRigidVertList; struct XSurface; struct XModel; - struct flameTable; + struct FlameTable; struct cStaticModel_s; struct FxElemVelStateSample; struct FxElemVisStateSample; @@ -4944,8 +4944,8 @@ namespace T6 int scanPauseTime; const char* flameTableFirstPerson; const char* flameTableThirdPerson; - flameTable* flameTableFirstPersonPtr; - flameTable* flameTableThirdPersonPtr; + FlameTable* flameTableFirstPersonPtr; + FlameTable* flameTableThirdPersonPtr; FxEffectDef* tagFx_preparationEffect; FxEffectDef* tagFlash_preparationEffect; bool doGibbing; @@ -6681,7 +6681,7 @@ namespace T6 int animDuration; }; - struct flameTable + struct FlameTable { float flameVar_streamChunkGravityStart; float flameVar_streamChunkGravityEnd; diff --git a/src/ObjCommon/Game/T5/ObjConstantsT5.h b/src/ObjCommon/Game/T5/ObjConstantsT5.h index 0b073b48..870c4773 100644 --- a/src/ObjCommon/Game/T5/ObjConstantsT5.h +++ b/src/ObjCommon/Game/T5/ObjConstantsT5.h @@ -2,9 +2,12 @@ namespace T5 { + static constexpr auto INFO_STRING_PREFIX_FLAME_TABLE = "FLAMETABLEFILE"; static constexpr auto INFO_STRING_PREFIX_PHYS_PRESET = "PHYSIC"; + static constexpr auto INFO_STRING_PREFIX_WEAPON = "WEAPONFILE"; static constexpr auto GDF_FILENAME_PHYS_PRESET = "physpreset.gdf"; + static constexpr auto GDF_FILENAME_WEAPON = "weapon.gdf"; static constexpr float MAX_FRICTION = 1e+10; } // namespace T5 diff --git a/src/ObjCommon/Game/T5/Weapon/FlameTableFields.h b/src/ObjCommon/Game/T5/Weapon/FlameTableFields.h new file mode 100644 index 00000000..ada79694 --- /dev/null +++ b/src/ObjCommon/Game/T5/Weapon/FlameTableFields.h @@ -0,0 +1,128 @@ +#pragma once + +#include "Game/T5/T5.h" + +namespace T5 +{ + inline cspField_t flameTableFields[]{ + {"flameVar_streamChunkGravityStart", offsetof(FlameTable, flameVar_streamChunkGravityStart), CSPFT_FLOAT }, + {"flameVar_streamChunkGravityEnd", offsetof(FlameTable, flameVar_streamChunkGravityEnd), CSPFT_FLOAT }, + {"flameVar_streamChunkMaxSize", offsetof(FlameTable, flameVar_streamChunkMaxSize), CSPFT_FLOAT }, + {"flameVar_streamChunkStartSize", offsetof(FlameTable, flameVar_streamChunkStartSize), CSPFT_FLOAT }, + {"flameVar_streamChunkEndSize", offsetof(FlameTable, flameVar_streamChunkEndSize), CSPFT_FLOAT }, + {"flameVar_streamChunkStartSizeRand", offsetof(FlameTable, flameVar_streamChunkStartSizeRand), CSPFT_FLOAT }, + {"flameVar_streamChunkEndSizeRand", offsetof(FlameTable, flameVar_streamChunkEndSizeRand), CSPFT_FLOAT }, + {"flameVar_streamChunkDistScalar", offsetof(FlameTable, flameVar_streamChunkDistScalar), CSPFT_FLOAT }, + {"flameVar_streamChunkDistSwayScale", offsetof(FlameTable, flameVar_streamChunkDistSwayScale), CSPFT_FLOAT }, + {"flameVar_streamChunkDistSwayVelMax", offsetof(FlameTable, flameVar_streamChunkDistSwayVelMax), CSPFT_FLOAT }, + {"flameVar_streamChunkSpeed", offsetof(FlameTable, flameVar_streamChunkSpeed), CSPFT_FLOAT }, + {"flameVar_streamChunkDecel", offsetof(FlameTable, flameVar_streamChunkDecel), CSPFT_FLOAT }, + {"flameVar_streamChunkVelocityAddScale", offsetof(FlameTable, flameVar_streamChunkVelocityAddScale), CSPFT_FLOAT }, + {"flameVar_streamChunkDuration", offsetof(FlameTable, flameVar_streamChunkDuration), CSPFT_FLOAT }, + {"flameVar_streamChunkDurationScaleMaxVel", offsetof(FlameTable, flameVar_streamChunkDurationScaleMaxVel), CSPFT_FLOAT }, + {"flameVar_streamChunkDurationVelScalar", offsetof(FlameTable, flameVar_streamChunkDurationVelScalar), CSPFT_FLOAT }, + {"flameVar_streamChunkSizeSpeedScale", offsetof(FlameTable, flameVar_streamChunkSizeSpeedScale), CSPFT_FLOAT }, + {"flameVar_streamChunkSizeAgeScale", offsetof(FlameTable, flameVar_streamChunkSizeAgeScale), CSPFT_FLOAT }, + {"flameVar_streamChunkSpawnFireIntervalStart", offsetof(FlameTable, flameVar_streamChunkSpawnFireIntervalStart), CSPFT_FLOAT }, + {"flameVar_streamChunkSpawnFireIntervalEnd", offsetof(FlameTable, flameVar_streamChunkSpawnFireIntervalEnd), CSPFT_FLOAT }, + {"flameVar_streamChunkSpawnFireMinLifeFrac", offsetof(FlameTable, flameVar_streamChunkSpawnFireMinLifeFrac), CSPFT_FLOAT }, + {"flameVar_streamChunkSpawnFireMaxLifeFrac", offsetof(FlameTable, flameVar_streamChunkSpawnFireMaxLifeFrac), CSPFT_FLOAT }, + {"flameVar_streamChunkFireMinLifeFrac", offsetof(FlameTable, flameVar_streamChunkFireMinLifeFrac), CSPFT_FLOAT }, + {"flameVar_streamChunkFireMinLifeFracStart", offsetof(FlameTable, flameVar_streamChunkFireMinLifeFracStart), CSPFT_FLOAT }, + {"flameVar_streamChunkFireMinLifeFracEnd", offsetof(FlameTable, flameVar_streamChunkFireMinLifeFracEnd), CSPFT_FLOAT }, + {"flameVar_streamChunkDripsMinLifeFrac", offsetof(FlameTable, flameVar_streamChunkDripsMinLifeFrac), CSPFT_FLOAT }, + {"flameVar_streamChunkDripsMinLifeFracStart", offsetof(FlameTable, flameVar_streamChunkDripsMinLifeFracStart), CSPFT_FLOAT }, + {"flameVar_streamChunkDripsMinLifeFracEnd", offsetof(FlameTable, flameVar_streamChunkDripsMinLifeFracEnd), CSPFT_FLOAT }, + {"flameVar_streamChunkRotationRange", offsetof(FlameTable, flameVar_streamChunkRotationRange), CSPFT_FLOAT }, + {"flameVar_streamSizeRandSinWave", offsetof(FlameTable, flameVar_streamSizeRandSinWave), CSPFT_FLOAT }, + {"flameVar_streamSizeRandCosWave", offsetof(FlameTable, flameVar_streamSizeRandCosWave), CSPFT_FLOAT }, + {"flameVar_streamDripsChunkInterval", offsetof(FlameTable, flameVar_streamDripsChunkInterval), CSPFT_FLOAT }, + {"flameVar_streamDripsChunkMinFrac", offsetof(FlameTable, flameVar_streamDripsChunkMinFrac), CSPFT_FLOAT }, + {"flameVar_streamDripsChunkRandFrac", offsetof(FlameTable, flameVar_streamDripsChunkRandFrac), CSPFT_FLOAT }, + {"flameVar_streamSmokeChunkInterval", offsetof(FlameTable, flameVar_streamSmokeChunkInterval), CSPFT_FLOAT }, + {"flameVar_streamSmokeChunkMinFrac", offsetof(FlameTable, flameVar_streamSmokeChunkMinFrac), CSPFT_FLOAT }, + {"flameVar_streamSmokeChunkRandFrac", offsetof(FlameTable, flameVar_streamSmokeChunkRandFrac), CSPFT_FLOAT }, + {"flameVar_streamChunkCullDistSizeFrac", offsetof(FlameTable, flameVar_streamChunkCullDistSizeFrac), CSPFT_FLOAT }, + {"flameVar_streamChunkCullMinLife", offsetof(FlameTable, flameVar_streamChunkCullMinLife), CSPFT_FLOAT }, + {"flameVar_streamChunkCullMaxLife", offsetof(FlameTable, flameVar_streamChunkCullMaxLife), CSPFT_FLOAT }, + {"flameVar_streamFuelSizeStart", offsetof(FlameTable, flameVar_streamFuelSizeStart), CSPFT_FLOAT }, + {"flameVar_streamFuelSizeEnd", offsetof(FlameTable, flameVar_streamFuelSizeEnd), CSPFT_FLOAT }, + {"flameVar_streamFuelLength", offsetof(FlameTable, flameVar_streamFuelLength), CSPFT_FLOAT }, + {"flameVar_streamFuelNumSegments", offsetof(FlameTable, flameVar_streamFuelNumSegments), CSPFT_FLOAT }, + {"flameVar_streamFuelAnimLoopTime", offsetof(FlameTable, flameVar_streamFuelAnimLoopTime), CSPFT_FLOAT }, + {"flameVar_streamFlameSizeStart", offsetof(FlameTable, flameVar_streamFlameSizeStart), CSPFT_FLOAT }, + {"flameVar_streamFlameSizeEnd", offsetof(FlameTable, flameVar_streamFlameSizeEnd), CSPFT_FLOAT }, + {"flameVar_streamFlameLength", offsetof(FlameTable, flameVar_streamFlameLength), CSPFT_FLOAT }, + {"flameVar_streamFlameNumSegments", offsetof(FlameTable, flameVar_streamFlameNumSegments), CSPFT_FLOAT }, + {"flameVar_streamFlameAnimLoopTime", offsetof(FlameTable, flameVar_streamFlameAnimLoopTime), CSPFT_FLOAT }, + {"flameVar_streamPrimaryLightRadius", offsetof(FlameTable, flameVar_streamPrimaryLightRadius), CSPFT_FLOAT }, + {"flameVar_streamPrimaryLightRadiusFlutter", offsetof(FlameTable, flameVar_streamPrimaryLightRadiusFlutter), CSPFT_FLOAT }, + {"flameVar_streamPrimaryLightR", offsetof(FlameTable, flameVar_streamPrimaryLightR), CSPFT_FLOAT }, + {"flameVar_streamPrimaryLightG", offsetof(FlameTable, flameVar_streamPrimaryLightG), CSPFT_FLOAT }, + {"flameVar_streamPrimaryLightB", offsetof(FlameTable, flameVar_streamPrimaryLightB), CSPFT_FLOAT }, + {"flameVar_streamPrimaryLightFlutterR", offsetof(FlameTable, flameVar_streamPrimaryLightFlutterR), CSPFT_FLOAT }, + {"flameVar_streamPrimaryLightFlutterG", offsetof(FlameTable, flameVar_streamPrimaryLightFlutterG), CSPFT_FLOAT }, + {"flameVar_streamPrimaryLightFlutterB", offsetof(FlameTable, flameVar_streamPrimaryLightFlutterB), CSPFT_FLOAT }, + {"flameVar_fireLife", offsetof(FlameTable, flameVar_fireLife), CSPFT_FLOAT }, + {"flameVar_fireLifeRand", offsetof(FlameTable, flameVar_fireLifeRand), CSPFT_FLOAT }, + {"flameVar_fireSpeedScale", offsetof(FlameTable, flameVar_fireSpeedScale), CSPFT_FLOAT }, + {"flameVar_fireSpeedScaleRand", offsetof(FlameTable, flameVar_fireSpeedScaleRand), CSPFT_FLOAT }, + {"flameVar_fireVelocityAddZ", offsetof(FlameTable, flameVar_fireVelocityAddZ), CSPFT_FLOAT }, + {"flameVar_fireVelocityAddZRand", offsetof(FlameTable, flameVar_fireVelocityAddZRand), CSPFT_FLOAT }, + {"flameVar_fireVelocityAddSideways", offsetof(FlameTable, flameVar_fireVelocityAddSideways), CSPFT_FLOAT }, + {"flameVar_fireGravity", offsetof(FlameTable, flameVar_fireGravity), CSPFT_FLOAT }, + {"flameVar_fireGravityEnd", offsetof(FlameTable, flameVar_fireGravityEnd), CSPFT_FLOAT }, + {"flameVar_fireMaxRotVel", offsetof(FlameTable, flameVar_fireMaxRotVel), CSPFT_FLOAT }, + {"flameVar_fireFriction", offsetof(FlameTable, flameVar_fireFriction), CSPFT_FLOAT }, + {"flameVar_fireEndSizeAdd", offsetof(FlameTable, flameVar_fireEndSizeAdd), CSPFT_FLOAT }, + {"flameVar_fireStartSizeScale", offsetof(FlameTable, flameVar_fireStartSizeScale), CSPFT_FLOAT }, + {"flameVar_fireEndSizeScale", offsetof(FlameTable, flameVar_fireEndSizeScale), CSPFT_FLOAT }, + {"flameVar_dripsLife", offsetof(FlameTable, flameVar_dripsLife), CSPFT_FLOAT }, + {"flameVar_dripsLifeRand", offsetof(FlameTable, flameVar_dripsLifeRand), CSPFT_FLOAT }, + {"flameVar_dripsSpeedScale", offsetof(FlameTable, flameVar_dripsSpeedScale), CSPFT_FLOAT }, + {"flameVar_dripsSpeedScaleRand", offsetof(FlameTable, flameVar_dripsSpeedScaleRand), CSPFT_FLOAT }, + {"flameVar_dripsVelocityAddZ", offsetof(FlameTable, flameVar_dripsVelocityAddZ), CSPFT_FLOAT }, + {"flameVar_dripsVelocityAddZRand", offsetof(FlameTable, flameVar_dripsVelocityAddZRand), CSPFT_FLOAT }, + {"flameVar_dripsVelocityAddSideways", offsetof(FlameTable, flameVar_dripsVelocityAddSideways), CSPFT_FLOAT }, + {"flameVar_dripsGravity", offsetof(FlameTable, flameVar_dripsGravity), CSPFT_FLOAT }, + {"flameVar_dripsGravityEnd", offsetof(FlameTable, flameVar_dripsGravityEnd), CSPFT_FLOAT }, + {"flameVar_dripsMaxRotVel", offsetof(FlameTable, flameVar_dripsMaxRotVel), CSPFT_FLOAT }, + {"flameVar_dripsFriction", offsetof(FlameTable, flameVar_dripsFriction), CSPFT_FLOAT }, + {"flameVar_dripsEndSizeAdd", offsetof(FlameTable, flameVar_dripsEndSizeAdd), CSPFT_FLOAT }, + {"flameVar_dripsStartSizeScale", offsetof(FlameTable, flameVar_dripsStartSizeScale), CSPFT_FLOAT }, + {"flameVar_dripsEndSizeScale", offsetof(FlameTable, flameVar_dripsEndSizeScale), CSPFT_FLOAT }, + {"flameVar_smokeLife", offsetof(FlameTable, flameVar_smokeLife), CSPFT_FLOAT }, + {"flameVar_smokeLifeRand", offsetof(FlameTable, flameVar_smokeLifeRand), CSPFT_FLOAT }, + {"flameVar_smokeSpeedScale", offsetof(FlameTable, flameVar_smokeSpeedScale), CSPFT_FLOAT }, + {"flameVar_smokeVelocityAddZ", offsetof(FlameTable, flameVar_smokeVelocityAddZ), CSPFT_FLOAT }, + {"flameVar_smokeGravity", offsetof(FlameTable, flameVar_smokeGravity), CSPFT_FLOAT }, + {"flameVar_smokeGravityEnd", offsetof(FlameTable, flameVar_smokeGravityEnd), CSPFT_FLOAT }, + {"flameVar_smokeMaxRotation", offsetof(FlameTable, flameVar_smokeMaxRotation), CSPFT_FLOAT }, + {"flameVar_smokeMaxRotVel", offsetof(FlameTable, flameVar_smokeMaxRotVel), CSPFT_FLOAT }, + {"flameVar_smokeFriction", offsetof(FlameTable, flameVar_smokeFriction), CSPFT_FLOAT }, + {"flameVar_smokeEndSizeAdd", offsetof(FlameTable, flameVar_smokeEndSizeAdd), CSPFT_FLOAT }, + {"flameVar_smokeStartSizeAdd", offsetof(FlameTable, flameVar_smokeStartSizeAdd), CSPFT_FLOAT }, + {"flameVar_smokeOriginSizeOfsZScale", offsetof(FlameTable, flameVar_smokeOriginSizeOfsZScale), CSPFT_FLOAT }, + {"flameVar_smokeOriginOfsZ", offsetof(FlameTable, flameVar_smokeOriginOfsZ), CSPFT_FLOAT }, + {"flameVar_smokeFadein", offsetof(FlameTable, flameVar_smokeFadein), CSPFT_FLOAT }, + {"flameVar_smokeFadeout", offsetof(FlameTable, flameVar_smokeFadeout), CSPFT_FLOAT }, + {"flameVar_smokeMaxAlpha", offsetof(FlameTable, flameVar_smokeMaxAlpha), CSPFT_FLOAT }, + {"flameVar_smokeBrightness", offsetof(FlameTable, flameVar_smokeBrightness), CSPFT_FLOAT }, + {"flameVar_smokeOriginOffset", offsetof(FlameTable, flameVar_smokeOriginOffset), CSPFT_FLOAT }, + {"flameVar_collisionSpeedScale", offsetof(FlameTable, flameVar_collisionSpeedScale), CSPFT_FLOAT }, + {"flameVar_collisionVolumeScale", offsetof(FlameTable, flameVar_collisionVolumeScale), CSPFT_FLOAT }, + {"name", offsetof(FlameTable, name), CSPFT_STRING }, + {"fire", offsetof(FlameTable, fire), CSPFT_MATERIAL}, + {"smoke", offsetof(FlameTable, smoke), CSPFT_MATERIAL}, + {"heat", offsetof(FlameTable, heat), CSPFT_MATERIAL}, + {"drips", offsetof(FlameTable, drips), CSPFT_MATERIAL}, + {"streamFuel", offsetof(FlameTable, streamFuel), CSPFT_MATERIAL}, + {"streamFuel2", offsetof(FlameTable, streamFuel2), CSPFT_MATERIAL}, + {"streamFlame", offsetof(FlameTable, streamFlame), CSPFT_MATERIAL}, + {"streamFlame2", offsetof(FlameTable, streamFlame2), CSPFT_MATERIAL}, + {"flameOffLoopSound", offsetof(FlameTable, flameOffLoopSound), CSPFT_STRING }, + {"flameIgniteSound", offsetof(FlameTable, flameIgniteSound), CSPFT_STRING }, + {"flameOnLoopSound", offsetof(FlameTable, flameOnLoopSound), CSPFT_STRING }, + {"flameCooldownSound", offsetof(FlameTable, flameCooldownSound), CSPFT_STRING }, + }; +} diff --git a/src/ObjCommon/Game/T5/Weapon/WeaponFields.h b/src/ObjCommon/Game/T5/Weapon/WeaponFields.h new file mode 100644 index 00000000..39469207 --- /dev/null +++ b/src/ObjCommon/Game/T5/Weapon/WeaponFields.h @@ -0,0 +1,756 @@ +#pragma once +#include "Game/T5/T5.h" + +namespace T5 +{ + inline cspField_t weapon_fields[]{ + {"displayName", offsetof(WeaponFullDef, weapVariantDef.szDisplayName), CSPFT_STRING }, + {"AIOverlayDescription", offsetof(WeaponFullDef, weapDef.szOverlayName), CSPFT_STRING }, + {"modeName", offsetof(WeaponFullDef, weapDef.szModeName), CSPFT_STRING }, + {"playerAnimType", offsetof(WeaponFullDef, weapDef.playerAnimType), WFT_ANIMTYPE }, + {"gunModel", offsetof(WeaponFullDef, gunXModel[0]), CSPFT_XMODEL }, + {"gunModel2", offsetof(WeaponFullDef, gunXModel[1]), CSPFT_XMODEL }, + {"gunModel3", offsetof(WeaponFullDef, gunXModel[2]), CSPFT_XMODEL }, + {"gunModel4", offsetof(WeaponFullDef, gunXModel[3]), CSPFT_XMODEL }, + {"gunModel5", offsetof(WeaponFullDef, gunXModel[4]), CSPFT_XMODEL }, + {"gunModel6", offsetof(WeaponFullDef, gunXModel[5]), CSPFT_XMODEL }, + {"gunModel7", offsetof(WeaponFullDef, gunXModel[6]), CSPFT_XMODEL }, + {"gunModel8", offsetof(WeaponFullDef, gunXModel[7]), CSPFT_XMODEL }, + {"gunModel9", offsetof(WeaponFullDef, gunXModel[8]), CSPFT_XMODEL }, + {"gunModel10", offsetof(WeaponFullDef, gunXModel[9]), CSPFT_XMODEL }, + {"gunModel11", offsetof(WeaponFullDef, gunXModel[10]), CSPFT_XMODEL }, + {"gunModel12", offsetof(WeaponFullDef, gunXModel[11]), CSPFT_XMODEL }, + {"gunModel13", offsetof(WeaponFullDef, gunXModel[12]), CSPFT_XMODEL }, + {"gunModel14", offsetof(WeaponFullDef, gunXModel[13]), CSPFT_XMODEL }, + {"gunModel15", offsetof(WeaponFullDef, gunXModel[14]), CSPFT_XMODEL }, + {"gunModel16", offsetof(WeaponFullDef, gunXModel[15]), CSPFT_XMODEL }, + {"handModel", offsetof(WeaponFullDef, weapDef.handXModel), CSPFT_XMODEL }, + {"hideTags", offsetof(WeaponFullDef, hideTags), WFT_HIDETAGS }, + {"notetrackSoundMap", offsetof(WeaponFullDef, notetrackSoundMapKeys), WFT_NOTETRACKSOUNDMAP }, + {"idleAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_IDLE]), CSPFT_STRING }, + {"idleAnimLeft", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_IDLE_LEFT]), CSPFT_STRING }, + {"emptyIdleAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_EMPTY_IDLE]), CSPFT_STRING }, + {"emptyIdleAnimLeft", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_EMPTY_IDLE_LEFT]), CSPFT_STRING }, + {"fireAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_FIRE]), CSPFT_STRING }, + {"fireAnimLeft", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_FIRE_LEFT]), CSPFT_STRING }, + {"holdFireAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_HOLD_FIRE]), CSPFT_STRING }, + {"lastShotAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_LASTSHOT]), CSPFT_STRING }, + {"lastShotAnimLeft", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_LASTSHOT_LEFT]), CSPFT_STRING }, + {"detonateAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_DETONATE]), CSPFT_STRING }, + {"rechamberAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_RECHAMBER]), CSPFT_STRING }, + {"meleeAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_MELEE]), CSPFT_STRING }, + {"meleeChargeAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_MELEE_CHARGE]), CSPFT_STRING }, + {"reloadAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_RELOAD]), CSPFT_STRING }, + {"reloadAnimRight", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_RELOAD_RIGHT]), CSPFT_STRING }, + {"reloadAnimLeft", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_RELOAD_LEFT]), CSPFT_STRING }, + {"reloadEmptyAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_RELOAD_EMPTY]), CSPFT_STRING }, + {"reloadEmptyAnimLeft", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_RELOAD_EMPTY_LEFT]), CSPFT_STRING }, + {"reloadStartAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_RELOAD_START]), CSPFT_STRING }, + {"reloadEndAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_RELOAD_END]), CSPFT_STRING }, + {"reloadQuickAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_RELOAD_QUICK]), CSPFT_STRING }, + {"reloadQuickEmptyAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_RELOAD_QUICK_EMPTY]), CSPFT_STRING }, + {"raiseAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_RAISE]), CSPFT_STRING }, + {"dropAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_DROP]), CSPFT_STRING }, + {"firstRaiseAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_FIRST_RAISE]), CSPFT_STRING }, + {"altRaiseAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_ALT_RAISE]), CSPFT_STRING }, + {"altDropAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_ALT_DROP]), CSPFT_STRING }, + {"quickRaiseAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_QUICK_RAISE]), CSPFT_STRING }, + {"quickDropAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_QUICK_DROP]), CSPFT_STRING }, + {"emptyRaiseAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_EMPTY_RAISE]), CSPFT_STRING }, + {"emptyDropAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_EMPTY_DROP]), CSPFT_STRING }, + {"sprintInAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_SPRINT_IN]), CSPFT_STRING }, + {"sprintLoopAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_SPRINT_LOOP]), CSPFT_STRING }, + {"sprintOutAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_SPRINT_OUT]), CSPFT_STRING }, + {"sprintInEmptyAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_SPRINT_EMPTY_IN]), CSPFT_STRING }, + {"sprintLoopEmptyAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_SPRINT_EMPTY_LOOP]), CSPFT_STRING }, + {"sprintOutEmptyAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_SPRINT_EMPTY_OUT]), CSPFT_STRING }, + {"lowReadyInAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_LOWREADY_IN]), CSPFT_STRING }, + {"lowReadyLoopAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_LOWREADY_LOOP]), CSPFT_STRING }, + {"lowReadyOutAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_LOWREADY_OUT]), CSPFT_STRING }, + {"contFireInAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_CONT_FIRE_IN]), CSPFT_STRING }, + {"contFireLoopAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_CONT_FIRE_LOOP]), CSPFT_STRING }, + {"contFireOutAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_CONT_FIRE_OUT]), CSPFT_STRING }, + {"deployAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_DEPLOY]), CSPFT_STRING }, + {"breakdownAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_BREAKDOWN]), CSPFT_STRING }, + {"nightVisionWearAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_NIGHTVISION_WEAR]), CSPFT_STRING }, + {"nightVisionRemoveAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_NIGHTVISION_REMOVE]), CSPFT_STRING }, + {"adsFireAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_ADS_FIRE]), CSPFT_STRING }, + {"adsLastShotAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_ADS_LASTSHOT]), CSPFT_STRING }, + {"adsRechamberAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_ADS_RECHAMBER]), CSPFT_STRING }, + {"adsUpAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_ADS_UP]), CSPFT_STRING }, + {"adsDownAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_ADS_DOWN]), CSPFT_STRING }, + {"deployAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_DEPLOY]), CSPFT_STRING }, + {"breakdownAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_BREAKDOWN]), CSPFT_STRING }, + {"dtp_in", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_DTP_IN]), CSPFT_STRING }, + {"dtp_loop", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_DTP_LOOP]), CSPFT_STRING }, + {"dtp_out", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_DTP_OUT]), CSPFT_STRING }, + {"dtp_empty_in", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_DTP_EMPTY_IN]), CSPFT_STRING }, + {"dtp_empty_loop", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_DTP_EMPTY_LOOP]), CSPFT_STRING }, + {"dtp_empty_out", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_DTP_EMPTY_OUT]), CSPFT_STRING }, + {"slide_in", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_SLIDE_IN]), CSPFT_STRING }, + {"mantleAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_MANTLE]), CSPFT_STRING }, + {"sprintCameraAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_CAMERA_SPRINT_LOOP]), CSPFT_STRING }, + {"dtpInCameraAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_CAMERA_DTP_IN]), CSPFT_STRING }, + {"dtpLoopCameraAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_CAMERA_DTP_LOOP]), CSPFT_STRING }, + {"dtpOutCameraAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_CAMERA_DTP_OUT]), CSPFT_STRING }, + {"mantleCameraAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_CAMERA_MANTLE]), CSPFT_STRING }, + {"script", offsetof(WeaponFullDef, weapDef.szScript), CSPFT_STRING }, + {"weaponType", offsetof(WeaponFullDef, weapDef.weapType), WFT_WEAPONTYPE }, + {"weaponClass", offsetof(WeaponFullDef, weapDef.weapClass), WFT_WEAPONCLASS }, + {"penetrateType", offsetof(WeaponFullDef, weapDef.penetrateType), WFT_PENETRATE_TYPE }, + {"impactType", offsetof(WeaponFullDef, weapDef.impactType), WFT_IMPACT_TYPE }, + {"inventoryType", offsetof(WeaponFullDef, weapDef.inventoryType), WFT_INVENTORYTYPE }, + {"fireType", offsetof(WeaponFullDef, weapDef.fireType), WFT_FIRETYPE }, + {"clipType", offsetof(WeaponFullDef, weapDef.clipType), WFT_CLIPTYPE }, + {"offhandClass", offsetof(WeaponFullDef, weapDef.offhandClass), WFT_OFFHAND_CLASS }, + {"offhandSlot", offsetof(WeaponFullDef, weapDef.offhandSlot), WFT_OFFHAND_SLOT }, + {"viewFlashEffect", offsetof(WeaponFullDef, weapDef.viewFlashEffect), CSPFT_FX }, + {"worldFlashEffect", offsetof(WeaponFullDef, weapDef.worldFlashEffect), CSPFT_FX }, + {"pickupSound", offsetof(WeaponFullDef, weapDef.pickupSound), CSPFT_STRING }, + {"pickupSoundPlayer", offsetof(WeaponFullDef, weapDef.pickupSoundPlayer), CSPFT_STRING }, + {"ammoPickupSound", offsetof(WeaponFullDef, weapDef.ammoPickupSound), CSPFT_STRING }, + {"ammoPickupSoundPlayer", offsetof(WeaponFullDef, weapDef.ammoPickupSoundPlayer), CSPFT_STRING }, + {"projectileSound", offsetof(WeaponFullDef, weapDef.projectileSound), CSPFT_STRING }, + {"pullbackSound", offsetof(WeaponFullDef, weapDef.pullbackSound), CSPFT_STRING }, + {"pullbackSoundPlayer", offsetof(WeaponFullDef, weapDef.pullbackSoundPlayer), CSPFT_STRING }, + {"fireSound", offsetof(WeaponFullDef, weapDef.fireSound), CSPFT_STRING }, + {"crackSound", offsetof(WeaponFullDef, weapDef.crackSound), CSPFT_STRING }, + {"whizbySound", offsetof(WeaponFullDef, weapDef.whizbySound), CSPFT_STRING }, + {"fireSoundPlayer", offsetof(WeaponFullDef, weapDef.fireSoundPlayer), CSPFT_STRING }, + {"loopFireSound", offsetof(WeaponFullDef, weapDef.fireLoopSound), CSPFT_STRING }, + {"loopFireSoundPlayer", offsetof(WeaponFullDef, weapDef.fireLoopSoundPlayer), CSPFT_STRING }, + {"loopFireEndSound", offsetof(WeaponFullDef, weapDef.fireLoopEndSound), CSPFT_STRING }, + {"loopFireEndSoundPlayer", offsetof(WeaponFullDef, weapDef.fireLoopEndSoundPlayer), CSPFT_STRING }, + {"stopFireSound", offsetof(WeaponFullDef, weapDef.fireStopSound), CSPFT_STRING }, + {"stopFireSoundPlayer", offsetof(WeaponFullDef, weapDef.fireStopSoundPlayer), CSPFT_STRING }, + {"lastShotSound", offsetof(WeaponFullDef, weapDef.fireLastSound), CSPFT_STRING }, + {"lastShotSoundPlayer", offsetof(WeaponFullDef, weapDef.fireLastSoundPlayer), CSPFT_STRING }, + {"emptyFireSound", offsetof(WeaponFullDef, weapDef.emptyFireSound), CSPFT_STRING }, + {"emptyFireSoundPlayer", offsetof(WeaponFullDef, weapDef.emptyFireSoundPlayer), CSPFT_STRING }, + {"meleeSwipeSound", offsetof(WeaponFullDef, weapDef.meleeSwipeSound), CSPFT_STRING }, + {"meleeSwipeSoundPlayer", offsetof(WeaponFullDef, weapDef.meleeSwipeSoundPlayer), CSPFT_STRING }, + {"meleeHitSound", offsetof(WeaponFullDef, weapDef.meleeHitSound), CSPFT_STRING }, + {"meleeMissSound", offsetof(WeaponFullDef, weapDef.meleeMissSound), CSPFT_STRING }, + {"rechamberSound", offsetof(WeaponFullDef, weapDef.rechamberSound), CSPFT_STRING }, + {"rechamberSoundPlayer", offsetof(WeaponFullDef, weapDef.rechamberSoundPlayer), CSPFT_STRING }, + {"reloadSound", offsetof(WeaponFullDef, weapDef.reloadSound), CSPFT_STRING }, + {"reloadSoundPlayer", offsetof(WeaponFullDef, weapDef.reloadSoundPlayer), CSPFT_STRING }, + {"reloadEmptySound", offsetof(WeaponFullDef, weapDef.reloadEmptySound), CSPFT_STRING }, + {"reloadEmptySoundPlayer", offsetof(WeaponFullDef, weapDef.reloadEmptySoundPlayer), CSPFT_STRING }, + {"reloadStartSound", offsetof(WeaponFullDef, weapDef.reloadStartSound), CSPFT_STRING }, + {"reloadStartSoundPlayer", offsetof(WeaponFullDef, weapDef.reloadStartSoundPlayer), CSPFT_STRING }, + {"reloadEndSound", offsetof(WeaponFullDef, weapDef.reloadEndSound), CSPFT_STRING }, + {"reloadEndSoundPlayer", offsetof(WeaponFullDef, weapDef.reloadEndSoundPlayer), CSPFT_STRING }, + {"rotateLoopSound", offsetof(WeaponFullDef, weapDef.rotateLoopSound), CSPFT_STRING }, + {"rotateLoopSoundPlayer", offsetof(WeaponFullDef, weapDef.rotateLoopSoundPlayer), CSPFT_STRING }, + {"deploySound", offsetof(WeaponFullDef, weapDef.deploySound), CSPFT_STRING }, + {"deploySoundPlayer", offsetof(WeaponFullDef, weapDef.deploySoundPlayer), CSPFT_STRING }, + {"finishDeploySound", offsetof(WeaponFullDef, weapDef.finishDeploySound), CSPFT_STRING }, + {"finishDeploySoundPlayer", offsetof(WeaponFullDef, weapDef.finishDeploySoundPlayer), CSPFT_STRING }, + {"breakdownSound", offsetof(WeaponFullDef, weapDef.breakdownSound), CSPFT_STRING }, + {"breakdownSoundPlayer", offsetof(WeaponFullDef, weapDef.breakdownSoundPlayer), CSPFT_STRING }, + {"finishBreakdownSound", offsetof(WeaponFullDef, weapDef.finishBreakdownSound), CSPFT_STRING }, + {"finishBreakdownSoundPlayer", offsetof(WeaponFullDef, weapDef.finishBreakdownSoundPlayer), CSPFT_STRING }, + {"detonateSound", offsetof(WeaponFullDef, weapDef.detonateSound), CSPFT_STRING }, + {"detonateSoundPlayer", offsetof(WeaponFullDef, weapDef.detonateSoundPlayer), CSPFT_STRING }, + {"nightVisionWearSound", offsetof(WeaponFullDef, weapDef.nightVisionWearSound), CSPFT_STRING }, + {"nightVisionWearSoundPlayer", offsetof(WeaponFullDef, weapDef.nightVisionWearSoundPlayer), CSPFT_STRING }, + {"nightVisionRemoveSound", offsetof(WeaponFullDef, weapDef.nightVisionRemoveSound), CSPFT_STRING }, + {"nightVisionRemoveSoundPlayer", offsetof(WeaponFullDef, weapDef.nightVisionRemoveSoundPlayer), CSPFT_STRING }, + {"raiseSound", offsetof(WeaponFullDef, weapDef.raiseSound), CSPFT_STRING }, + {"raiseSoundPlayer", offsetof(WeaponFullDef, weapDef.raiseSoundPlayer), CSPFT_STRING }, + {"firstRaiseSound", offsetof(WeaponFullDef, weapDef.firstRaiseSound), CSPFT_STRING }, + {"firstRaiseSoundPlayer", offsetof(WeaponFullDef, weapDef.firstRaiseSoundPlayer), CSPFT_STRING }, + {"altSwitchSound", offsetof(WeaponFullDef, weapDef.altSwitchSound), CSPFT_STRING }, + {"altSwitchSoundPlayer", offsetof(WeaponFullDef, weapDef.altSwitchSoundPlayer), CSPFT_STRING }, + {"putawaySound", offsetof(WeaponFullDef, weapDef.putawaySound), CSPFT_STRING }, + {"putawaySoundPlayer", offsetof(WeaponFullDef, weapDef.putawaySoundPlayer), CSPFT_STRING }, + {"overheatSound", offsetof(WeaponFullDef, weapDef.overheatSound), CSPFT_STRING }, + {"overheatSoundPlayer", offsetof(WeaponFullDef, weapDef.overheatSoundPlayer), CSPFT_STRING }, + {"adsZoomSound", offsetof(WeaponFullDef, weapDef.adsZoomSound), CSPFT_STRING }, + {"bounceSound", offsetof(WeaponFullDef, weapDef.bounceSound), WFT_BOUNCE_SOUND }, + {"standMountedWeapdef", offsetof(WeaponFullDef, weapDef.standMountedWeapdef), CSPFT_STRING }, + {"crouchMountedWeapdef", offsetof(WeaponFullDef, weapDef.crouchMountedWeapdef), CSPFT_STRING }, + {"proneMountedWeapdef", offsetof(WeaponFullDef, weapDef.proneMountedWeapdef), CSPFT_STRING }, + {"viewShellEjectEffect", offsetof(WeaponFullDef, weapDef.viewShellEjectEffect), CSPFT_FX }, + {"worldShellEjectEffect", offsetof(WeaponFullDef, weapDef.worldShellEjectEffect), CSPFT_FX }, + {"viewLastShotEjectEffect", offsetof(WeaponFullDef, weapDef.viewLastShotEjectEffect), CSPFT_FX }, + {"worldLastShotEjectEffect", offsetof(WeaponFullDef, weapDef.worldLastShotEjectEffect), CSPFT_FX }, + {"reticleCenter", offsetof(WeaponFullDef, weapDef.reticleCenter), CSPFT_MATERIAL }, + {"reticleSide", offsetof(WeaponFullDef, weapDef.reticleSide), CSPFT_MATERIAL }, + {"reticleCenterSize", offsetof(WeaponFullDef, weapDef.iReticleCenterSize), CSPFT_INT }, + {"reticleSideSize", offsetof(WeaponFullDef, weapDef.iReticleSideSize), CSPFT_INT }, + {"reticleMinOfs", offsetof(WeaponFullDef, weapDef.iReticleMinOfs), CSPFT_INT }, + {"activeReticleType", offsetof(WeaponFullDef, weapDef.activeReticleType), WFT_ACTIVE_RETICLE_TYPE }, + {"standMoveF", offsetof(WeaponFullDef, weapDef.vStandMove[0]), CSPFT_FLOAT }, + {"standMoveR", offsetof(WeaponFullDef, weapDef.vStandMove[1]), CSPFT_FLOAT }, + {"standMoveU", offsetof(WeaponFullDef, weapDef.vStandMove[2]), CSPFT_FLOAT }, + {"standRotP", offsetof(WeaponFullDef, weapDef.vStandRot[0]), CSPFT_FLOAT }, + {"standRotY", offsetof(WeaponFullDef, weapDef.vStandRot[1]), CSPFT_FLOAT }, + {"standRotR", offsetof(WeaponFullDef, weapDef.vStandRot[2]), CSPFT_FLOAT }, + {"duckedOfsF", offsetof(WeaponFullDef, weapDef.vDuckedOfs[0]), CSPFT_FLOAT }, + {"duckedOfsR", offsetof(WeaponFullDef, weapDef.vDuckedOfs[1]), CSPFT_FLOAT }, + {"duckedOfsU", offsetof(WeaponFullDef, weapDef.vDuckedOfs[2]), CSPFT_FLOAT }, + {"duckedMoveF", offsetof(WeaponFullDef, weapDef.vDuckedMove[0]), CSPFT_FLOAT }, + {"duckedMoveR", offsetof(WeaponFullDef, weapDef.vDuckedMove[1]), CSPFT_FLOAT }, + {"duckedMoveU", offsetof(WeaponFullDef, weapDef.vDuckedMove[2]), CSPFT_FLOAT }, + {"duckedSprintOfsF", offsetof(WeaponFullDef, weapDef.vDuckedSprintOfs[0]), CSPFT_FLOAT }, + {"duckedSprintOfsR", offsetof(WeaponFullDef, weapDef.vDuckedSprintOfs[1]), CSPFT_FLOAT }, + {"duckedSprintOfsU", offsetof(WeaponFullDef, weapDef.vDuckedSprintOfs[2]), CSPFT_FLOAT }, + {"duckedSprintRotP", offsetof(WeaponFullDef, weapDef.vDuckedSprintRot[0]), CSPFT_FLOAT }, + {"duckedSprintRotY", offsetof(WeaponFullDef, weapDef.vDuckedSprintRot[1]), CSPFT_FLOAT }, + {"duckedSprintRotR", offsetof(WeaponFullDef, weapDef.vDuckedSprintRot[2]), CSPFT_FLOAT }, + {"duckedSprintBobH", offsetof(WeaponFullDef, weapDef.vDuckedSprintBob[0]), CSPFT_FLOAT }, + {"duckedSprintBobV", offsetof(WeaponFullDef, weapDef.vDuckedSprintBob[1]), CSPFT_FLOAT }, + {"duckedSprintScale", offsetof(WeaponFullDef, weapDef.fDuckedSprintCycleScale), CSPFT_FLOAT }, + {"sprintOfsF", offsetof(WeaponFullDef, weapDef.vSprintOfs[0]), CSPFT_FLOAT }, + {"sprintOfsR", offsetof(WeaponFullDef, weapDef.vSprintOfs[1]), CSPFT_FLOAT }, + {"sprintOfsU", offsetof(WeaponFullDef, weapDef.vSprintOfs[2]), CSPFT_FLOAT }, + {"sprintRotP", offsetof(WeaponFullDef, weapDef.vSprintRot[0]), CSPFT_FLOAT }, + {"sprintRotY", offsetof(WeaponFullDef, weapDef.vSprintRot[1]), CSPFT_FLOAT }, + {"sprintRotR", offsetof(WeaponFullDef, weapDef.vSprintRot[2]), CSPFT_FLOAT }, + {"sprintBobH", offsetof(WeaponFullDef, weapDef.vSprintBob[0]), CSPFT_FLOAT }, + {"sprintBobV", offsetof(WeaponFullDef, weapDef.vSprintBob[1]), CSPFT_FLOAT }, + {"sprintScale", offsetof(WeaponFullDef, weapDef.fSprintCycleScale), CSPFT_FLOAT }, + {"lowReadyOfsF", offsetof(WeaponFullDef, weapDef.vLowReadyOfs[0]), CSPFT_FLOAT }, + {"lowReadyOfsR", offsetof(WeaponFullDef, weapDef.vLowReadyOfs[1]), CSPFT_FLOAT }, + {"lowReadyOfsU", offsetof(WeaponFullDef, weapDef.vLowReadyOfs[2]), CSPFT_FLOAT }, + {"lowReadyRotP", offsetof(WeaponFullDef, weapDef.vLowReadyRot[0]), CSPFT_FLOAT }, + {"lowReadyRotY", offsetof(WeaponFullDef, weapDef.vLowReadyRot[1]), CSPFT_FLOAT }, + {"lowReadyRotR", offsetof(WeaponFullDef, weapDef.vLowReadyRot[2]), CSPFT_FLOAT }, + {"dtpOfsF", offsetof(WeaponFullDef, weapDef.vDtpOfs[0]), CSPFT_FLOAT }, + {"dtpOfsR", offsetof(WeaponFullDef, weapDef.vDtpOfs[1]), CSPFT_FLOAT }, + {"dtpOfsU", offsetof(WeaponFullDef, weapDef.vDtpOfs[2]), CSPFT_FLOAT }, + {"dtpRotP", offsetof(WeaponFullDef, weapDef.vDtpRot[0]), CSPFT_FLOAT }, + {"dtpRotY", offsetof(WeaponFullDef, weapDef.vDtpRot[1]), CSPFT_FLOAT }, + {"dtpRotR", offsetof(WeaponFullDef, weapDef.vDtpRot[2]), CSPFT_FLOAT }, + {"dtpBobH", offsetof(WeaponFullDef, weapDef.vDtpBob[0]), CSPFT_FLOAT }, + {"dtpBobV", offsetof(WeaponFullDef, weapDef.vDtpBob[1]), CSPFT_FLOAT }, + {"dtpScale", offsetof(WeaponFullDef, weapDef.fDtpCycleScale), CSPFT_FLOAT }, + {"mantleOfsF", offsetof(WeaponFullDef, weapDef.vMantleOfs[0]), CSPFT_FLOAT }, + {"mantleOfsR", offsetof(WeaponFullDef, weapDef.vMantleOfs[1]), CSPFT_FLOAT }, + {"mantleOfsU", offsetof(WeaponFullDef, weapDef.vMantleOfs[2]), CSPFT_FLOAT }, + {"mantleRotP", offsetof(WeaponFullDef, weapDef.vMantleRot[0]), CSPFT_FLOAT }, + {"mantleRotY", offsetof(WeaponFullDef, weapDef.vMantleRot[1]), CSPFT_FLOAT }, + {"mantleRotR", offsetof(WeaponFullDef, weapDef.vMantleRot[2]), CSPFT_FLOAT }, + {"slideOfsF", offsetof(WeaponFullDef, weapDef.vSlideOfs[0]), CSPFT_FLOAT }, + {"slideOfsR", offsetof(WeaponFullDef, weapDef.vSlideOfs[1]), CSPFT_FLOAT }, + {"slideOfsU", offsetof(WeaponFullDef, weapDef.vSlideOfs[2]), CSPFT_FLOAT }, + {"slideRotP", offsetof(WeaponFullDef, weapDef.vSlideRot[0]), CSPFT_FLOAT }, + {"slideRotY", offsetof(WeaponFullDef, weapDef.vSlideRot[1]), CSPFT_FLOAT }, + {"slideRotR", offsetof(WeaponFullDef, weapDef.vSlideRot[2]), CSPFT_FLOAT }, + {"duckedRotP", offsetof(WeaponFullDef, weapDef.vDuckedRot[0]), CSPFT_FLOAT }, + {"duckedRotY", offsetof(WeaponFullDef, weapDef.vDuckedRot[1]), CSPFT_FLOAT }, + {"duckedRotR", offsetof(WeaponFullDef, weapDef.vDuckedRot[2]), CSPFT_FLOAT }, + {"proneOfsF", offsetof(WeaponFullDef, weapDef.vProneOfs[0]), CSPFT_FLOAT }, + {"proneOfsR", offsetof(WeaponFullDef, weapDef.vProneOfs[1]), CSPFT_FLOAT }, + {"proneOfsU", offsetof(WeaponFullDef, weapDef.vProneOfs[2]), CSPFT_FLOAT }, + {"proneMoveF", offsetof(WeaponFullDef, weapDef.vProneMove[0]), CSPFT_FLOAT }, + {"proneMoveR", offsetof(WeaponFullDef, weapDef.vProneMove[1]), CSPFT_FLOAT }, + {"proneMoveU", offsetof(WeaponFullDef, weapDef.vProneMove[2]), CSPFT_FLOAT }, + {"proneRotP", offsetof(WeaponFullDef, weapDef.vProneRot[0]), CSPFT_FLOAT }, + {"proneRotY", offsetof(WeaponFullDef, weapDef.vProneRot[1]), CSPFT_FLOAT }, + {"proneRotR", offsetof(WeaponFullDef, weapDef.vProneRot[2]), CSPFT_FLOAT }, + {"strafeMoveF", offsetof(WeaponFullDef, weapDef.vStrafeMove[0]), CSPFT_FLOAT }, + {"strafeMoveR", offsetof(WeaponFullDef, weapDef.vStrafeMove[1]), CSPFT_FLOAT }, + {"strafeMoveU", offsetof(WeaponFullDef, weapDef.vStrafeMove[2]), CSPFT_FLOAT }, + {"strafeRotP", offsetof(WeaponFullDef, weapDef.vStrafeRot[0]), CSPFT_FLOAT }, + {"strafeRotY", offsetof(WeaponFullDef, weapDef.vStrafeRot[1]), CSPFT_FLOAT }, + {"strafeRotR", offsetof(WeaponFullDef, weapDef.vStrafeRot[2]), CSPFT_FLOAT }, + {"posMoveRate", offsetof(WeaponFullDef, weapDef.fPosMoveRate), CSPFT_FLOAT }, + {"posProneMoveRate", offsetof(WeaponFullDef, weapDef.fPosProneMoveRate), CSPFT_FLOAT }, + {"standMoveMinSpeed", offsetof(WeaponFullDef, weapDef.fStandMoveMinSpeed), CSPFT_FLOAT }, + {"duckedMoveMinSpeed", offsetof(WeaponFullDef, weapDef.fDuckedMoveMinSpeed), CSPFT_FLOAT }, + {"proneMoveMinSpeed", offsetof(WeaponFullDef, weapDef.fProneMoveMinSpeed), CSPFT_FLOAT }, + {"posRotRate", offsetof(WeaponFullDef, weapDef.fPosRotRate), CSPFT_FLOAT }, + {"posProneRotRate", offsetof(WeaponFullDef, weapDef.fPosProneRotRate), CSPFT_FLOAT }, + {"standRotMinSpeed", offsetof(WeaponFullDef, weapDef.fStandRotMinSpeed), CSPFT_FLOAT }, + {"duckedRotMinSpeed", offsetof(WeaponFullDef, weapDef.fDuckedRotMinSpeed), CSPFT_FLOAT }, + {"proneRotMinSpeed", offsetof(WeaponFullDef, weapDef.fProneRotMinSpeed), CSPFT_FLOAT }, + {"worldModel", offsetof(WeaponFullDef, worldModel[0]), CSPFT_XMODEL }, + {"worldModel2", offsetof(WeaponFullDef, worldModel[1]), CSPFT_XMODEL }, + {"worldModel3", offsetof(WeaponFullDef, worldModel[2]), CSPFT_XMODEL }, + {"worldModel4", offsetof(WeaponFullDef, worldModel[3]), CSPFT_XMODEL }, + {"worldModel5", offsetof(WeaponFullDef, worldModel[4]), CSPFT_XMODEL }, + {"worldModel6", offsetof(WeaponFullDef, worldModel[5]), CSPFT_XMODEL }, + {"worldModel7", offsetof(WeaponFullDef, worldModel[6]), CSPFT_XMODEL }, + {"worldModel8", offsetof(WeaponFullDef, worldModel[7]), CSPFT_XMODEL }, + {"worldModel9", offsetof(WeaponFullDef, worldModel[8]), CSPFT_XMODEL }, + {"worldModel10", offsetof(WeaponFullDef, worldModel[9]), CSPFT_XMODEL }, + {"worldModel11", offsetof(WeaponFullDef, worldModel[10]), CSPFT_XMODEL }, + {"worldModel12", offsetof(WeaponFullDef, worldModel[11]), CSPFT_XMODEL }, + {"worldModel13", offsetof(WeaponFullDef, worldModel[12]), CSPFT_XMODEL }, + {"worldModel14", offsetof(WeaponFullDef, worldModel[13]), CSPFT_XMODEL }, + {"worldModel15", offsetof(WeaponFullDef, worldModel[14]), CSPFT_XMODEL }, + {"worldModel16", offsetof(WeaponFullDef, worldModel[15]), CSPFT_XMODEL }, + {"worldClipModel", offsetof(WeaponFullDef, weapDef.worldClipModel), CSPFT_XMODEL }, + {"rocketModel", offsetof(WeaponFullDef, weapDef.rocketModel), CSPFT_XMODEL }, + {"mountedModel", offsetof(WeaponFullDef, weapDef.mountedModel), CSPFT_XMODEL }, + {"AdditionalMeleeModel", offsetof(WeaponFullDef, weapDef.additionalMeleeModel), CSPFT_XMODEL }, + {"hudIcon", offsetof(WeaponFullDef, weapDef.hudIcon), CSPFT_MATERIAL }, + {"hudIconRatio", offsetof(WeaponFullDef, weapDef.hudIconRatio), WFT_ICONRATIO_HUD }, + {"indicatorIcon", offsetof(WeaponFullDef, weapDef.indicatorIcon), CSPFT_MATERIAL }, + {"indicatorIconRatio", offsetof(WeaponFullDef, weapDef.indicatorIconRatio), WFT_ICONRATIO_INDICATOR }, + {"ammoCounterIcon", offsetof(WeaponFullDef, weapDef.ammoCounterIcon), CSPFT_MATERIAL }, + {"ammoCounterIconRatio", offsetof(WeaponFullDef, weapDef.ammoCounterIconRatio), WFT_ICONRATIO_AMMOCOUNTER}, + {"ammoCounterClip", offsetof(WeaponFullDef, weapDef.ammoCounterClip), WFT_AMMOCOUNTER_CLIPTYPE }, + {"startAmmo", offsetof(WeaponFullDef, weapDef.iStartAmmo), CSPFT_INT }, + {"ammoName", offsetof(WeaponFullDef, weapVariantDef.szAmmoName), CSPFT_STRING }, + {"clipName", offsetof(WeaponFullDef, weapVariantDef.szClipName), CSPFT_STRING }, + {"maxAmmo", offsetof(WeaponFullDef, weapDef.iMaxAmmo), CSPFT_INT }, + {"clipSize", offsetof(WeaponFullDef, weapVariantDef.iClipSize), CSPFT_INT }, + {"shotCount", offsetof(WeaponFullDef, weapDef.shotCount), CSPFT_INT }, + {"sharedAmmoCapName", offsetof(WeaponFullDef, weapDef.szSharedAmmoCapName), CSPFT_STRING }, + {"sharedAmmoCap", offsetof(WeaponFullDef, weapDef.iSharedAmmoCap), CSPFT_INT }, + {"unlimitedAmmo", offsetof(WeaponFullDef, weapDef.unlimitedAmmo), CSPFT_BOOL }, + {"ammoCountClipRelative", offsetof(WeaponFullDef, weapDef.ammoCountClipRelative), CSPFT_BOOL }, + {"sharedAmmo", offsetof(WeaponFullDef, weapDef.sharedAmmo), CSPFT_BOOL }, + {"jamFireTime", offsetof(WeaponFullDef, weapDef.iJamFireTime), CSPFT_MILLISECONDS }, + {"overheatWeapon", offsetof(WeaponFullDef, weapDef.overheatWeapon), CSPFT_INT }, + {"overheatRate", offsetof(WeaponFullDef, weapDef.overheatRate), CSPFT_FLOAT }, + {"cooldownRate", offsetof(WeaponFullDef, weapDef.cooldownRate), CSPFT_FLOAT }, + {"overheatEndVal", offsetof(WeaponFullDef, weapDef.overheatEndVal), CSPFT_FLOAT }, + {"coolWhileFiring", offsetof(WeaponFullDef, weapDef.coolWhileFiring), CSPFT_INT }, + {"fuelTankWeapon", offsetof(WeaponFullDef, weapDef.fuelTankWeapon), CSPFT_INT }, + {"tankLifeTime", offsetof(WeaponFullDef, weapDef.iTankLifeTime), CSPFT_MILLISECONDS }, + {"damage", offsetof(WeaponFullDef, weapDef.damage), CSPFT_INT }, + {"damageDuration", offsetof(WeaponFullDef, weapDef.damageDuration), CSPFT_FLOAT }, + {"damageInterval", offsetof(WeaponFullDef, weapDef.damageInterval), CSPFT_FLOAT }, + {"playerDamage", offsetof(WeaponFullDef, weapDef.playerDamage), CSPFT_INT }, + {"meleeDamage", offsetof(WeaponFullDef, weapDef.iMeleeDamage), CSPFT_INT }, + {"minDamage", offsetof(WeaponFullDef, weapDef.minDamage), CSPFT_INT }, + {"minPlayerDamage", offsetof(WeaponFullDef, weapDef.minPlayerDamage), CSPFT_INT }, + {"maxDamageRange", offsetof(WeaponFullDef, weapDef.fMaxDamageRange), CSPFT_FLOAT }, + {"minDamageRange", offsetof(WeaponFullDef, weapDef.fMinDamageRange), CSPFT_FLOAT }, + {"destabilizationRateTime", offsetof(WeaponFullDef, weapDef.destabilizationRateTime), CSPFT_FLOAT }, + {"destabilizationCurvatureMax", offsetof(WeaponFullDef, weapDef.destabilizationCurvatureMax), CSPFT_FLOAT }, + {"destabilizeDistance", offsetof(WeaponFullDef, weapDef.destabilizeDistance), CSPFT_INT }, + {"fireDelay", offsetof(WeaponFullDef, weapDef.iFireDelay), CSPFT_MILLISECONDS }, + {"meleeDelay", offsetof(WeaponFullDef, weapDef.iMeleeDelay), CSPFT_MILLISECONDS }, + {"meleeChargeDelay", offsetof(WeaponFullDef, weapDef.meleeChargeDelay), CSPFT_MILLISECONDS }, + {"spinUpTime", offsetof(WeaponFullDef, weapDef.iSpinUpTime), CSPFT_MILLISECONDS }, + {"spinDownTime", offsetof(WeaponFullDef, weapDef.iSpinDownTime), CSPFT_MILLISECONDS }, + {"spinRate", offsetof(WeaponFullDef, weapDef.spinRate), CSPFT_FLOAT }, + {"spinLoopSound", offsetof(WeaponFullDef, weapDef.spinLoopSound), CSPFT_STRING }, + {"spinLoopSoundPlayer", offsetof(WeaponFullDef, weapDef.spinLoopSoundPlayer), CSPFT_STRING }, + {"startSpinSound", offsetof(WeaponFullDef, weapDef.startSpinSound), CSPFT_STRING }, + {"startSpinSoundPlayer", offsetof(WeaponFullDef, weapDef.startSpinSoundPlayer), CSPFT_STRING }, + {"stopSpinSound", offsetof(WeaponFullDef, weapDef.stopSpinSound), CSPFT_STRING }, + {"stopSpinSoundPlayer", offsetof(WeaponFullDef, weapDef.stopSpinSoundPlayer), CSPFT_STRING }, + {"fireTime", offsetof(WeaponFullDef, weapDef.iFireTime), CSPFT_MILLISECONDS }, + {"lastFireTime", offsetof(WeaponFullDef, weapDef.iLastFireTime), CSPFT_MILLISECONDS }, + {"rechamberTime", offsetof(WeaponFullDef, weapDef.iRechamberTime), CSPFT_MILLISECONDS }, + {"rechamberBoltTime", offsetof(WeaponFullDef, weapDef.iRechamberBoltTime), CSPFT_MILLISECONDS }, + {"holdFireTime", offsetof(WeaponFullDef, weapDef.iHoldFireTime), CSPFT_MILLISECONDS }, + {"detonateTime", offsetof(WeaponFullDef, weapDef.iDetonateTime), CSPFT_MILLISECONDS }, + {"detonateDelay", offsetof(WeaponFullDef, weapDef.iDetonateDelay), CSPFT_MILLISECONDS }, + {"meleeTime", offsetof(WeaponFullDef, weapDef.iMeleeTime), CSPFT_MILLISECONDS }, + {"meleeChargeTime", offsetof(WeaponFullDef, weapDef.meleeChargeTime), CSPFT_MILLISECONDS }, + {"reloadTime", offsetof(WeaponFullDef, weapVariantDef.iReloadTime), CSPFT_MILLISECONDS }, + {"reloadShowRocketTime", offsetof(WeaponFullDef, weapDef.reloadShowRocketTime), CSPFT_MILLISECONDS }, + {"reloadEmptyTime", offsetof(WeaponFullDef, weapVariantDef.iReloadEmptyTime), CSPFT_MILLISECONDS }, + {"reloadAddTime", offsetof(WeaponFullDef, weapDef.iReloadAddTime), CSPFT_MILLISECONDS }, + {"reloadEmptyAddTime", offsetof(WeaponFullDef, weapDef.iReloadEmptyAddTime), CSPFT_MILLISECONDS }, + {"reloadQuickAddTime", offsetof(WeaponFullDef, weapDef.iReloadQuickAddTime), CSPFT_MILLISECONDS }, + {"reloadQuickEmptyAddTime", offsetof(WeaponFullDef, weapDef.iReloadQuickEmptyAddTime), CSPFT_MILLISECONDS }, + {"reloadStartTime", offsetof(WeaponFullDef, weapDef.iReloadStartTime), CSPFT_MILLISECONDS }, + {"reloadStartAddTime", offsetof(WeaponFullDef, weapDef.iReloadStartAddTime), CSPFT_MILLISECONDS }, + {"reloadEndTime", offsetof(WeaponFullDef, weapDef.iReloadEndTime), CSPFT_MILLISECONDS }, + {"reloadQuickTime", offsetof(WeaponFullDef, weapVariantDef.iReloadQuickTime), CSPFT_MILLISECONDS }, + {"reloadQuickEmptyTime", offsetof(WeaponFullDef, weapVariantDef.iReloadQuickEmptyTime), CSPFT_MILLISECONDS }, + {"dropTime", offsetof(WeaponFullDef, weapDef.iDropTime), CSPFT_MILLISECONDS }, + {"raiseTime", offsetof(WeaponFullDef, weapDef.iRaiseTime), CSPFT_MILLISECONDS }, + {"altDropTime", offsetof(WeaponFullDef, weapDef.iAltDropTime), CSPFT_MILLISECONDS }, + {"altRaiseTime", offsetof(WeaponFullDef, weapVariantDef.iAltRaiseTime), CSPFT_MILLISECONDS }, + {"quickDropTime", offsetof(WeaponFullDef, weapDef.quickDropTime), CSPFT_MILLISECONDS }, + {"quickRaiseTime", offsetof(WeaponFullDef, weapDef.quickRaiseTime), CSPFT_MILLISECONDS }, + {"firstRaiseTime", offsetof(WeaponFullDef, weapDef.iFirstRaiseTime), CSPFT_MILLISECONDS }, + {"emptyRaiseTime", offsetof(WeaponFullDef, weapDef.iEmptyRaiseTime), CSPFT_MILLISECONDS }, + {"emptyDropTime", offsetof(WeaponFullDef, weapDef.iEmptyDropTime), CSPFT_MILLISECONDS }, + {"sprintInTime", offsetof(WeaponFullDef, weapDef.sprintInTime), CSPFT_MILLISECONDS }, + {"sprintLoopTime", offsetof(WeaponFullDef, weapDef.sprintLoopTime), CSPFT_MILLISECONDS }, + {"sprintOutTime", offsetof(WeaponFullDef, weapDef.sprintOutTime), CSPFT_MILLISECONDS }, + {"lowReadyInTime", offsetof(WeaponFullDef, weapDef.lowReadyInTime), CSPFT_MILLISECONDS }, + {"lowReadyLoopTime", offsetof(WeaponFullDef, weapDef.lowReadyLoopTime), CSPFT_MILLISECONDS }, + {"lowReadyOutTime", offsetof(WeaponFullDef, weapDef.lowReadyOutTime), CSPFT_MILLISECONDS }, + {"contFireInTime", offsetof(WeaponFullDef, weapDef.contFireInTime), CSPFT_MILLISECONDS }, + {"contFireLoopTime", offsetof(WeaponFullDef, weapDef.contFireLoopTime), CSPFT_MILLISECONDS }, + {"contFireOutTime", offsetof(WeaponFullDef, weapDef.contFireOutTime), CSPFT_MILLISECONDS }, + {"dtpInTime", offsetof(WeaponFullDef, weapDef.dtpInTime), CSPFT_MILLISECONDS }, + {"dtpLoopTime", offsetof(WeaponFullDef, weapDef.dtpLoopTime), CSPFT_MILLISECONDS }, + {"dtpOutTime", offsetof(WeaponFullDef, weapDef.dtpOutTime), CSPFT_MILLISECONDS }, + {"slideInTime", offsetof(WeaponFullDef, weapDef.slideInTime), CSPFT_MILLISECONDS }, + {"deployTime", offsetof(WeaponFullDef, weapDef.deployTime), CSPFT_MILLISECONDS }, + {"breakdownTime", offsetof(WeaponFullDef, weapDef.breakdownTime), CSPFT_MILLISECONDS }, + {"tracerFrequency", offsetof(WeaponFullDef, weapDef.tracerFrequency), CSPFT_INT }, + {"tracerWidth", offsetof(WeaponFullDef, weapDef.tracerWidth), CSPFT_FLOAT }, + {"tracerLength", offsetof(WeaponFullDef, weapDef.tracerLength), CSPFT_FLOAT }, + {"nightVisionWearTime", offsetof(WeaponFullDef, weapDef.nightVisionWearTime), CSPFT_MILLISECONDS }, + {"nightVisionWearTimeFadeOutEnd", offsetof(WeaponFullDef, weapDef.nightVisionWearTimeFadeOutEnd), CSPFT_MILLISECONDS }, + {"nightVisionWearTimePowerUp", offsetof(WeaponFullDef, weapDef.nightVisionWearTimePowerUp), CSPFT_MILLISECONDS }, + {"nightVisionRemoveTime", offsetof(WeaponFullDef, weapDef.nightVisionRemoveTime), CSPFT_MILLISECONDS }, + {"nightVisionRemoveTimePowerDown", offsetof(WeaponFullDef, weapDef.nightVisionRemoveTimePowerDown), CSPFT_MILLISECONDS }, + {"nightVisionRemoveTimeFadeInStart", offsetof(WeaponFullDef, weapDef.nightVisionRemoveTimeFadeInStart), CSPFT_MILLISECONDS }, + {"fuseTime", offsetof(WeaponFullDef, weapDef.fuseTime), CSPFT_MILLISECONDS }, + {"aifuseTime", offsetof(WeaponFullDef, weapDef.aiFuseTime), CSPFT_MILLISECONDS }, + {"lockOnRadius", offsetof(WeaponFullDef, weapDef.lockOnRadius), CSPFT_INT }, + {"lockOnSpeed", offsetof(WeaponFullDef, weapDef.lockOnSpeed), CSPFT_INT }, + {"requireLockonToFire", offsetof(WeaponFullDef, weapDef.requireLockonToFire), CSPFT_BOOL }, + {"noAdsWhenMagEmpty", offsetof(WeaponFullDef, weapDef.noAdsWhenMagEmpty), CSPFT_BOOL }, + {"avoidDropCleanup", offsetof(WeaponFullDef, weapDef.avoidDropCleanup), CSPFT_BOOL }, + {"stackFire", offsetof(WeaponFullDef, weapDef.stackFire), CSPFT_INT }, + {"stackFireSpread", offsetof(WeaponFullDef, weapDef.stackFireSpread), CSPFT_FLOAT }, + {"stackFireAccuracyDecay", offsetof(WeaponFullDef, weapDef.stackFireAccuracyDecay), CSPFT_FLOAT }, + {"stackSound", offsetof(WeaponFullDef, weapDef.stackSound), CSPFT_STRING }, + {"autoAimRange", offsetof(WeaponFullDef, weapDef.autoAimRange), CSPFT_FLOAT }, + {"aimAssistRange", offsetof(WeaponFullDef, weapDef.aimAssistRange), CSPFT_FLOAT }, + {"aimAssistRangeAds", offsetof(WeaponFullDef, weapVariantDef.fAimAssistRangeAds), CSPFT_FLOAT }, + {"mountableWeapon", offsetof(WeaponFullDef, weapDef.mountableWeapon), CSPFT_BOOL }, + {"aimPadding", offsetof(WeaponFullDef, weapDef.aimPadding), CSPFT_FLOAT }, + {"enemyCrosshairRange", offsetof(WeaponFullDef, weapDef.enemyCrosshairRange), CSPFT_FLOAT }, + {"crosshairColorChange", offsetof(WeaponFullDef, weapDef.crosshairColorChange), CSPFT_BOOL }, + {"moveSpeedScale", offsetof(WeaponFullDef, weapDef.moveSpeedScale), CSPFT_FLOAT }, + {"adsMoveSpeedScale", offsetof(WeaponFullDef, weapDef.adsMoveSpeedScale), CSPFT_FLOAT }, + {"sprintDurationScale", offsetof(WeaponFullDef, weapDef.sprintDurationScale), CSPFT_FLOAT }, + {"idleCrouchFactor", offsetof(WeaponFullDef, weapDef.fIdleCrouchFactor), CSPFT_FLOAT }, + {"idleProneFactor", offsetof(WeaponFullDef, weapDef.fIdleProneFactor), CSPFT_FLOAT }, + {"gunMaxPitch", offsetof(WeaponFullDef, weapDef.fGunMaxPitch), CSPFT_FLOAT }, + {"gunMaxYaw", offsetof(WeaponFullDef, weapDef.fGunMaxYaw), CSPFT_FLOAT }, + {"swayMaxAngle", offsetof(WeaponFullDef, weapDef.swayMaxAngle), CSPFT_FLOAT }, + {"swayLerpSpeed", offsetof(WeaponFullDef, weapDef.swayLerpSpeed), CSPFT_FLOAT }, + {"swayPitchScale", offsetof(WeaponFullDef, weapDef.swayPitchScale), CSPFT_FLOAT }, + {"swayYawScale", offsetof(WeaponFullDef, weapDef.swayYawScale), CSPFT_FLOAT }, + {"swayHorizScale", offsetof(WeaponFullDef, weapDef.swayHorizScale), CSPFT_FLOAT }, + {"swayVertScale", offsetof(WeaponFullDef, weapDef.swayVertScale), CSPFT_FLOAT }, + {"swayShellShockScale", offsetof(WeaponFullDef, weapDef.swayShellShockScale), CSPFT_FLOAT }, + {"adsSwayMaxAngle", offsetof(WeaponFullDef, weapDef.adsSwayMaxAngle), CSPFT_FLOAT }, + {"adsSwayLerpSpeed", offsetof(WeaponFullDef, weapDef.adsSwayLerpSpeed), CSPFT_FLOAT }, + {"adsSwayPitchScale", offsetof(WeaponFullDef, weapDef.adsSwayPitchScale), CSPFT_FLOAT }, + {"adsSwayYawScale", offsetof(WeaponFullDef, weapDef.adsSwayYawScale), CSPFT_FLOAT }, + {"adsSwayHorizScale", offsetof(WeaponFullDef, weapVariantDef.fAdsSwayHorizScale), CSPFT_FLOAT }, + {"adsSwayVertScale", offsetof(WeaponFullDef, weapVariantDef.fAdsSwayVertScale), CSPFT_FLOAT }, + {"meleeChargeRange", offsetof(WeaponFullDef, weapDef.meleeChargeRange), CSPFT_FLOAT }, + {"rifleBullet", offsetof(WeaponFullDef, weapDef.bRifleBullet), CSPFT_BOOL }, + {"armorPiercing", offsetof(WeaponFullDef, weapDef.armorPiercing), CSPFT_BOOL }, + {"boltAction", offsetof(WeaponFullDef, weapDef.bBoltAction), CSPFT_BOOL }, + {"useAltTagFlash", offsetof(WeaponFullDef, weapDef.bUseAltTagFlash), CSPFT_BOOL }, + {"useAntiLagRewind", offsetof(WeaponFullDef, weapDef.bUseAntiLagRewind), CSPFT_BOOL }, + {"isCarriedKillstreakWeapon", offsetof(WeaponFullDef, weapDef.bIsCarriedKillstreakWeapon), CSPFT_BOOL }, + {"aimDownSight", offsetof(WeaponFullDef, weapDef.aimDownSight), CSPFT_BOOL }, + {"rechamberWhileAds", offsetof(WeaponFullDef, weapDef.bRechamberWhileAds), CSPFT_BOOL }, + {"reloadWhileAds", offsetof(WeaponFullDef, weapDef.bReloadWhileAds), CSPFT_BOOL }, + {"adsViewErrorMin", offsetof(WeaponFullDef, weapDef.adsViewErrorMin), CSPFT_FLOAT }, + {"adsViewErrorMax", offsetof(WeaponFullDef, weapDef.adsViewErrorMax), CSPFT_FLOAT }, + {"clipOnly", offsetof(WeaponFullDef, weapDef.bClipOnly), CSPFT_BOOL }, + {"canUseInVehicle", offsetof(WeaponFullDef, weapDef.bCanUseInVehicle), CSPFT_BOOL }, + {"noDropsOrRaises", offsetof(WeaponFullDef, weapDef.bNoDropsOrRaises), CSPFT_BOOL }, + {"cookOffHold", offsetof(WeaponFullDef, weapDef.bCookOffHold), CSPFT_BOOL }, + {"adsFire", offsetof(WeaponFullDef, weapDef.adsFireOnly), CSPFT_BOOL }, + {"cancelAutoHolsterWhenEmpty", offsetof(WeaponFullDef, weapDef.cancelAutoHolsterWhenEmpty), CSPFT_BOOL }, + {"suppressAmmoReserveDisplay", offsetof(WeaponFullDef, weapDef.suppressAmmoReserveDisplay), CSPFT_BOOL }, + {"laserSightDuringNightvision", offsetof(WeaponFullDef, weapDef.laserSightDuringNightvision), CSPFT_BOOL }, + {"bayonet", offsetof(WeaponFullDef, weapDef.bHasBayonet), CSPFT_BOOL }, + {"dualWield", offsetof(WeaponFullDef, weapDef.bDualWield), CSPFT_BOOL }, + {"hideThirdPerson", offsetof(WeaponFullDef, weapDef.bHideThirdPerson), CSPFT_BOOL }, + {"explodeOnGround", offsetof(WeaponFullDef, weapDef.bExplodeOnGround), CSPFT_BOOL }, + {"throwBack", offsetof(WeaponFullDef, weapDef.bThrowBack), CSPFT_BOOL }, + {"retrievable", offsetof(WeaponFullDef, weapDef.bRetrievable), CSPFT_BOOL }, + {"dieOnRespawn", offsetof(WeaponFullDef, weapDef.bDieOnRespawn), CSPFT_BOOL }, + {"noThirdPersonDropsOrRaises", offsetof(WeaponFullDef, weapDef.bNoThirdPersonDropsOrRaises), CSPFT_BOOL }, + {"continuousFire", offsetof(WeaponFullDef, weapDef.bContinuousFire), CSPFT_BOOL }, + {"fullMetalJacket", offsetof(WeaponFullDef, weapVariantDef.bFullMetalJacket), CSPFT_BOOL }, + {"hollowPoint", offsetof(WeaponFullDef, weapVariantDef.bHollowPoint), CSPFT_BOOL }, + {"useAsMelee", offsetof(WeaponFullDef, weapDef.bUseAsMelee), CSPFT_BOOL }, + {"rapidFire", offsetof(WeaponFullDef, weapVariantDef.bRapidFire), CSPFT_BOOL }, + {"noPing", offsetof(WeaponFullDef, weapDef.bNoPing), CSPFT_BOOL }, + {"forceBounce", offsetof(WeaponFullDef, weapDef.bForceBounce), CSPFT_BOOL }, + {"useDroppedModelAsStowed", offsetof(WeaponFullDef, weapDef.bUseDroppedModelAsStowed), CSPFT_BOOL }, + {"noQuickDropWhenEmpty", offsetof(WeaponFullDef, weapDef.bNoQuickDropWhenEmpty), CSPFT_BOOL }, + {"keepCrosshairWhenADS", offsetof(WeaponFullDef, weapDef.bKeepCrosshairWhenADS), CSPFT_BOOL }, + {"useOnlyAltWeaoponHideTagsInAltMode", offsetof(WeaponFullDef, weapDef.bUseOnlyAltWeaoponHideTagsInAltMode), CSPFT_BOOL }, + {"killIcon", offsetof(WeaponFullDef, weapDef.killIcon), CSPFT_MATERIAL }, + {"killIconRatio", offsetof(WeaponFullDef, weapDef.killIconRatio), WFT_ICONRATIO_KILL }, + {"flipKillIcon", offsetof(WeaponFullDef, weapDef.flipKillIcon), CSPFT_BOOL }, + {"dpadIcon", offsetof(WeaponFullDef, weapVariantDef.dpadIcon), CSPFT_MATERIAL }, + {"dpadIconRatio", offsetof(WeaponFullDef, weapVariantDef.dpadIconRatio), WFT_ICONRATIO_DPAD }, + {"noPartialReload", offsetof(WeaponFullDef, weapDef.bNoPartialReload), CSPFT_BOOL }, + {"segmentedReload", offsetof(WeaponFullDef, weapDef.bSegmentedReload), CSPFT_BOOL }, + {"noADSAutoReload", offsetof(WeaponFullDef, weapDef.bNoADSAutoReload), CSPFT_BOOL }, + {"reloadAmmoAdd", offsetof(WeaponFullDef, weapDef.iReloadAmmoAdd), CSPFT_INT }, + {"reloadStartAdd", offsetof(WeaponFullDef, weapDef.iReloadStartAdd), CSPFT_INT }, + {"altWeapon", offsetof(WeaponFullDef, weapVariantDef.szAltWeaponName), CSPFT_STRING }, + {"DualWieldWeapon", offsetof(WeaponFullDef, weapDef.szDualWieldWeaponName), CSPFT_STRING }, + {"grenadeWeapon", offsetof(WeaponFullDef, weapDef.szSpawnedGrenadeWeaponName), CSPFT_STRING }, + {"dropAmmoMin", offsetof(WeaponFullDef, weapDef.iDropAmmoMin), CSPFT_INT }, + {"dropAmmoMax", offsetof(WeaponFullDef, weapDef.iDropAmmoMax), CSPFT_INT }, + {"dropClipAmmoMin", offsetof(WeaponFullDef, weapDef.iDropClipAmmoMin), CSPFT_INT }, + {"dropClipAmmoMax", offsetof(WeaponFullDef, weapDef.iDropClipAmmoMax), CSPFT_INT }, + {"blocksProne", offsetof(WeaponFullDef, weapDef.blocksProne), CSPFT_BOOL }, + {"silenced", offsetof(WeaponFullDef, weapVariantDef.bSilenced), CSPFT_BOOL }, + {"dualMag", offsetof(WeaponFullDef, weapVariantDef.bDualMag), CSPFT_BOOL }, + {"isRollingGrenade", offsetof(WeaponFullDef, weapDef.isRollingGrenade), CSPFT_QBOOLEAN }, + {"showIndicator", offsetof(WeaponFullDef, weapDef.bShowIndicator), CSPFT_BOOL }, + {"explosionRadius", offsetof(WeaponFullDef, weapDef.iExplosionRadius), CSPFT_INT }, + {"explosionRadiusMin", offsetof(WeaponFullDef, weapDef.iExplosionRadiusMin), CSPFT_INT }, + {"indicatorRadius", offsetof(WeaponFullDef, weapDef.iIndicatorRadius), CSPFT_INT }, + {"explosionInnerDamage", offsetof(WeaponFullDef, weapDef.iExplosionInnerDamage), CSPFT_INT }, + {"explosionOuterDamage", offsetof(WeaponFullDef, weapDef.iExplosionOuterDamage), CSPFT_INT }, + {"damageConeAngle", offsetof(WeaponFullDef, weapDef.damageConeAngle), CSPFT_FLOAT }, + {"projectileSpeed", offsetof(WeaponFullDef, weapDef.iProjectileSpeed), CSPFT_INT }, + {"projectileSpeedRelativeUp", offsetof(WeaponFullDef, weapDef.iProjectileSpeedRelativeUp), CSPFT_INT }, + {"projectileSpeedUp", offsetof(WeaponFullDef, weapDef.iProjectileSpeedUp), CSPFT_INT }, + {"projectileSpeedForward", offsetof(WeaponFullDef, weapDef.iProjectileSpeedForward), CSPFT_INT }, + {"projectileActivateDist", offsetof(WeaponFullDef, weapDef.iProjectileActivateDist), CSPFT_INT }, + {"projectileLifetime", offsetof(WeaponFullDef, weapDef.projLifetime), CSPFT_FLOAT }, + {"timeToAccelerate", offsetof(WeaponFullDef, weapDef.timeToAccelerate), CSPFT_FLOAT }, + {"projectileCurvature", offsetof(WeaponFullDef, weapDef.projectileCurvature), CSPFT_FLOAT }, + {"projectileModel", offsetof(WeaponFullDef, weapDef.projectileModel), CSPFT_XMODEL }, + {"projExplosionType", offsetof(WeaponFullDef, weapDef.projExplosion), WFT_PROJ_EXPLOSION }, + {"projExplosionEffect", offsetof(WeaponFullDef, weapDef.projExplosionEffect), CSPFT_FX }, + {"projExplosionEffectForceNormalUp", offsetof(WeaponFullDef, weapDef.projExplosionEffectForceNormalUp), CSPFT_BOOL }, + {"projExplosionEffect2", offsetof(WeaponFullDef, weapDef.projExplosionEffect2), CSPFT_FX }, + {"projExplosionEffect2ForceNormalUp", offsetof(WeaponFullDef, weapDef.projExplosionEffect2ForceNormalUp), CSPFT_BOOL }, + {"projExplosionEffect3", offsetof(WeaponFullDef, weapDef.projExplosionEffect3), CSPFT_FX }, + {"projExplosionEffect3ForceNormalUp", offsetof(WeaponFullDef, weapDef.projExplosionEffect3ForceNormalUp), CSPFT_BOOL }, + {"projExplosionEffect4", offsetof(WeaponFullDef, weapDef.projExplosionEffect4), CSPFT_FX }, + {"projExplosionEffect4ForceNormalUp", offsetof(WeaponFullDef, weapDef.projExplosionEffect4ForceNormalUp), CSPFT_BOOL }, + {"projExplosionEffect5", offsetof(WeaponFullDef, weapDef.projExplosionEffect5), CSPFT_FX }, + {"projExplosionEffect5ForceNormalUp", offsetof(WeaponFullDef, weapDef.projExplosionEffect5ForceNormalUp), CSPFT_BOOL }, + {"projExplosionSound", offsetof(WeaponFullDef, weapDef.projExplosionSound), CSPFT_STRING }, + {"projDudEffect", offsetof(WeaponFullDef, weapDef.projDudEffect), CSPFT_FX }, + {"projDudSound", offsetof(WeaponFullDef, weapDef.projDudSound), CSPFT_STRING }, + {"projImpactExplode", offsetof(WeaponFullDef, weapDef.bProjImpactExplode), CSPFT_BOOL }, + {"bulletImpactExplode", offsetof(WeaponFullDef, weapDef.bBulletImpactExplode), CSPFT_BOOL }, + {"mortarShellSound", offsetof(WeaponFullDef, weapDef.mortarShellSound), CSPFT_STRING }, + {"tankShellSound", offsetof(WeaponFullDef, weapDef.tankShellSound), CSPFT_STRING }, + {"stickiness", offsetof(WeaponFullDef, weapDef.stickiness), WFT_STICKINESS }, + {"rotateType", offsetof(WeaponFullDef, weapDef.rotateType), WFT_ROTATETYPE }, + {"hasDetonator", offsetof(WeaponFullDef, weapDef.hasDetonator), CSPFT_BOOL }, + {"plantable", offsetof(WeaponFullDef, weapDef.plantable), CSPFT_BOOL }, + {"timedDetonation", offsetof(WeaponFullDef, weapDef.timedDetonation), CSPFT_BOOL }, + {"noCrumpleMissile", offsetof(WeaponFullDef, weapDef.bNoCrumpleMissile), CSPFT_BOOL }, + {"rotate", offsetof(WeaponFullDef, weapDef.rotate), CSPFT_BOOL }, + {"keepRolling", offsetof(WeaponFullDef, weapDef.bKeepRolling), CSPFT_BOOL }, + {"holdButtonToThrow", offsetof(WeaponFullDef, weapDef.holdButtonToThrow), CSPFT_BOOL }, + {"offhandHoldIsCancelable", offsetof(WeaponFullDef, weapDef.offhandHoldIsCancelable), CSPFT_BOOL }, + {"freezeMovementWhenFiring", offsetof(WeaponFullDef, weapDef.freezeMovementWhenFiring), CSPFT_BOOL }, + {"lowAmmoWarningThreshold", offsetof(WeaponFullDef, weapDef.lowAmmoWarningThreshold), CSPFT_FLOAT }, + {"explosionTag", offsetof(WeaponFullDef, weapDef.explosionTag), WFT_EXPLOSION_TAG }, + {"isCameraSensor", offsetof(WeaponFullDef, weapDef.isCameraSensor), CSPFT_BOOL }, + {"isAcousticSensor", offsetof(WeaponFullDef, weapDef.isAcousticSensor), CSPFT_BOOL }, + {"parallelDefaultBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_DEFAULT]), CSPFT_FLOAT }, + {"parallelAsphaltBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_ASPHALT]), CSPFT_FLOAT }, + {"parallelBarkBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_BARK]), CSPFT_FLOAT }, + {"parallelBrickBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_BRICK]), CSPFT_FLOAT }, + {"parallelCarpetBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_CARPET]), CSPFT_FLOAT }, + {"parallelCeramicBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_CERAMIC]), CSPFT_FLOAT }, + {"parallelClothBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_CLOTH]), CSPFT_FLOAT }, + {"parallelConcreteBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_CONCRETE]), CSPFT_FLOAT }, + {"parallelCushionBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_CUSHION]), CSPFT_FLOAT }, + {"parallelDirtBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_DIRT]), CSPFT_FLOAT }, + {"parallelFleshBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_FLESH]), CSPFT_FLOAT }, + {"parallelFoliageBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_FOLIAGE]), CSPFT_FLOAT }, + {"parallelFruitBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_FRUIT]), CSPFT_FLOAT }, + {"parallelGlassBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_GLASS]), CSPFT_FLOAT }, + {"parallelGrassBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_GRASS]), CSPFT_FLOAT }, + {"parallelGravelBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_GRAVEL]), CSPFT_FLOAT }, + {"parallelIceBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_ICE]), CSPFT_FLOAT }, + {"parallelMetalBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_METAL]), CSPFT_FLOAT }, + {"parallelMudBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_MUD]), CSPFT_FLOAT }, + {"parallelPaintedMetalBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_PAINTED_METAL]), CSPFT_FLOAT }, + {"parallelPaperBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_PAPER]), CSPFT_FLOAT }, + {"parallelPlasterBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_PLASTER]), CSPFT_FLOAT }, + {"parallelPlasticBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_PLASTIC]), CSPFT_FLOAT }, + {"parallelRockBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_ROCK]), CSPFT_FLOAT }, + {"parallelRubberBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_RUBBER]), CSPFT_FLOAT }, + {"parallelSandBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_SAND]), CSPFT_FLOAT }, + {"parallelSnowBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_SNOW]), CSPFT_FLOAT }, + {"parallelWaterBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_WATER]), CSPFT_FLOAT }, + {"parallelWoodBounce", offsetof(WeaponFullDef, parallelBounce[SURF_TYPE_WOOD]), CSPFT_FLOAT }, + {"perpendicularDefaultBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_DEFAULT]), CSPFT_FLOAT }, + {"perpendicularAsphaltBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_ASPHALT]), CSPFT_FLOAT }, + {"perpendicularBarkBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_BARK]), CSPFT_FLOAT }, + {"perpendicularBrickBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_BRICK]), CSPFT_FLOAT }, + {"perpendicularCarpetBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_CARPET]), CSPFT_FLOAT }, + {"perpendicularCeramicBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_CERAMIC]), CSPFT_FLOAT }, + {"perpendicularClothBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_CLOTH]), CSPFT_FLOAT }, + {"perpendicularConcreteBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_CONCRETE]), CSPFT_FLOAT }, + {"perpendicularCushionBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_CUSHION]), CSPFT_FLOAT }, + {"perpendicularDirtBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_DIRT]), CSPFT_FLOAT }, + {"perpendicularFleshBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_FLESH]), CSPFT_FLOAT }, + {"perpendicularFoliageBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_FOLIAGE]), CSPFT_FLOAT }, + {"perpendicularFruitBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_FRUIT]), CSPFT_FLOAT }, + {"perpendicularGlassBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_GLASS]), CSPFT_FLOAT }, + {"perpendicularGrassBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_GRASS]), CSPFT_FLOAT }, + {"perpendicularGravelBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_GRAVEL]), CSPFT_FLOAT }, + {"perpendicularIceBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_ICE]), CSPFT_FLOAT }, + {"perpendicularMetalBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_METAL]), CSPFT_FLOAT }, + {"perpendicularMudBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_MUD]), CSPFT_FLOAT }, + {"perpendicularPaintedMetalBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_PAINTED_METAL]), CSPFT_FLOAT }, + {"perpendicularPaperBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_PAPER]), CSPFT_FLOAT }, + {"perpendicularPlasterBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_PLASTER]), CSPFT_FLOAT }, + {"perpendicularPlasticBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_PLASTIC]), CSPFT_FLOAT }, + {"perpendicularRockBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_ROCK]), CSPFT_FLOAT }, + {"perpendicularRubberBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_RUBBER]), CSPFT_FLOAT }, + {"perpendicularSandBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_SAND]), CSPFT_FLOAT }, + {"perpendicularSnowBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_SNOW]), CSPFT_FLOAT }, + {"perpendicularWaterBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_WATER]), CSPFT_FLOAT }, + {"perpendicularWoodBounce", offsetof(WeaponFullDef, perpendicularBounce[SURF_TYPE_WOOD]), CSPFT_FLOAT }, + {"projTrailEffect", offsetof(WeaponFullDef, weapDef.projTrailEffect), CSPFT_FX }, + {"projectileRed", offsetof(WeaponFullDef, weapDef.vProjectileColor[0]), CSPFT_FLOAT }, + {"projectileGreen", offsetof(WeaponFullDef, weapDef.vProjectileColor[1]), CSPFT_FLOAT }, + {"projectileBlue", offsetof(WeaponFullDef, weapDef.vProjectileColor[2]), CSPFT_FLOAT }, + {"guidedMissileType", offsetof(WeaponFullDef, weapDef.guidedMissileType), WFT_GUIDED_MISSILE_TYPE }, + {"maxSteeringAccel", offsetof(WeaponFullDef, weapDef.maxSteeringAccel), CSPFT_FLOAT }, + {"projIgnitionDelay", offsetof(WeaponFullDef, weapDef.projIgnitionDelay), CSPFT_INT }, + {"projIgnitionEffect", offsetof(WeaponFullDef, weapDef.projIgnitionEffect), CSPFT_FX }, + {"projIgnitionSound", offsetof(WeaponFullDef, weapDef.projIgnitionSound), CSPFT_STRING }, + {"tagFx_preparationEffect", offsetof(WeaponFullDef, weapDef.tagFx_preparationEffect), CSPFT_FX }, + {"tagFlash_preparationEffect", offsetof(WeaponFullDef, weapDef.tagFlash_preparationEffect), CSPFT_FX }, + {"adsTransInTime", offsetof(WeaponFullDef, weapVariantDef.iAdsTransInTime), CSPFT_MILLISECONDS }, + {"adsTransOutTime", offsetof(WeaponFullDef, weapVariantDef.iAdsTransOutTime), CSPFT_MILLISECONDS }, + {"adsIdleAmount", offsetof(WeaponFullDef, weapDef.fAdsIdleAmount), CSPFT_FLOAT }, + {"adsIdleSpeed", offsetof(WeaponFullDef, weapDef.adsIdleSpeed), CSPFT_FLOAT }, + {"adsZoomFov1", offsetof(WeaponFullDef, weapVariantDef.fAdsZoomFov1), CSPFT_FLOAT }, + {"adsZoomFov2", offsetof(WeaponFullDef, weapVariantDef.fAdsZoomFov2), CSPFT_FLOAT }, + {"adsZoomFov3", offsetof(WeaponFullDef, weapVariantDef.fAdsZoomFov3), CSPFT_FLOAT }, + {"adsZoomInFrac", offsetof(WeaponFullDef, weapVariantDef.fAdsZoomInFrac), CSPFT_FLOAT }, + {"adsZoomOutFrac", offsetof(WeaponFullDef, weapVariantDef.fAdsZoomOutFrac), CSPFT_FLOAT }, + {"adsOverlayShader", offsetof(WeaponFullDef, weapVariantDef.overlayMaterial), CSPFT_MATERIAL_STREAM }, + {"adsOverlayShaderLowRes", offsetof(WeaponFullDef, weapVariantDef.overlayMaterialLowRes), CSPFT_MATERIAL_STREAM }, + {"adsOverlayReticle", offsetof(WeaponFullDef, weapDef.overlayReticle), WFT_OVERLAYRETICLE }, + {"adsOverlayInterface", offsetof(WeaponFullDef, weapDef.overlayInterface), WFT_OVERLAYINTERFACE }, + {"adsOverlayWidth", offsetof(WeaponFullDef, weapDef.overlayWidth), CSPFT_FLOAT }, + {"adsOverlayHeight", offsetof(WeaponFullDef, weapDef.overlayHeight), CSPFT_FLOAT }, + {"adsOverlayAlphaScale", offsetof(WeaponFullDef, weapVariantDef.fOverlayAlphaScale), CSPFT_FLOAT }, + {"adsBobFactor", offsetof(WeaponFullDef, weapDef.fAdsBobFactor), CSPFT_FLOAT }, + {"adsViewBobMult", offsetof(WeaponFullDef, weapDef.fAdsViewBobMult), CSPFT_FLOAT }, + {"adsAimPitch", offsetof(WeaponFullDef, weapDef.fAdsAimPitch), CSPFT_FLOAT }, + {"adsCrosshairInFrac", offsetof(WeaponFullDef, weapDef.fAdsCrosshairInFrac), CSPFT_FLOAT }, + {"adsCrosshairOutFrac", offsetof(WeaponFullDef, weapDef.fAdsCrosshairOutFrac), CSPFT_FLOAT }, + {"adsReloadTransTime", offsetof(WeaponFullDef, weapDef.iPositionReloadTransTime), CSPFT_MILLISECONDS }, + {"adsGunKickReducedKickBullets", offsetof(WeaponFullDef, weapDef.adsGunKickReducedKickBullets), CSPFT_INT }, + {"adsGunKickReducedKickPercent", offsetof(WeaponFullDef, weapDef.adsGunKickReducedKickPercent), CSPFT_FLOAT }, + {"adsGunKickPitchMin", offsetof(WeaponFullDef, weapDef.fAdsGunKickPitchMin), CSPFT_FLOAT }, + {"adsGunKickPitchMax", offsetof(WeaponFullDef, weapDef.fAdsGunKickPitchMax), CSPFT_FLOAT }, + {"adsGunKickYawMin", offsetof(WeaponFullDef, weapDef.fAdsGunKickYawMin), CSPFT_FLOAT }, + {"adsGunKickYawMax", offsetof(WeaponFullDef, weapDef.fAdsGunKickYawMax), CSPFT_FLOAT }, + {"adsGunKickAccel", offsetof(WeaponFullDef, weapDef.fAdsGunKickAccel), CSPFT_FLOAT }, + {"adsGunKickSpeedMax", offsetof(WeaponFullDef, weapDef.fAdsGunKickSpeedMax), CSPFT_FLOAT }, + {"adsGunKickSpeedDecay", offsetof(WeaponFullDef, weapDef.fAdsGunKickSpeedDecay), CSPFT_FLOAT }, + {"adsGunKickStaticDecay", offsetof(WeaponFullDef, weapDef.fAdsGunKickStaticDecay), CSPFT_FLOAT }, + {"adsViewKickPitchMin", offsetof(WeaponFullDef, weapDef.fAdsViewKickPitchMin), CSPFT_FLOAT }, + {"adsViewKickPitchMax", offsetof(WeaponFullDef, weapDef.fAdsViewKickPitchMax), CSPFT_FLOAT }, + {"adsViewKickYawMin", offsetof(WeaponFullDef, weapDef.fAdsViewKickYawMin), CSPFT_FLOAT }, + {"adsViewKickYawMax", offsetof(WeaponFullDef, weapDef.fAdsViewKickYawMax), CSPFT_FLOAT }, + {"adsViewKickCenterSpeed", offsetof(WeaponFullDef, weapVariantDef.fAdsViewKickCenterSpeed), CSPFT_FLOAT }, + {"adsSpread", offsetof(WeaponFullDef, weapDef.fAdsSpread), CSPFT_FLOAT }, + {"guidedMissileType", offsetof(WeaponFullDef, weapDef.guidedMissileType), WFT_GUIDED_MISSILE_TYPE }, + {"hipSpreadStandMin", offsetof(WeaponFullDef, weapDef.fHipSpreadStandMin), CSPFT_FLOAT }, + {"hipSpreadDuckedMin", offsetof(WeaponFullDef, weapDef.fHipSpreadDuckedMin), CSPFT_FLOAT }, + {"hipSpreadProneMin", offsetof(WeaponFullDef, weapDef.fHipSpreadProneMin), CSPFT_FLOAT }, + {"hipSpreadMax", offsetof(WeaponFullDef, weapDef.hipSpreadStandMax), CSPFT_FLOAT }, + {"hipSpreadDuckedMax", offsetof(WeaponFullDef, weapDef.hipSpreadDuckedMax), CSPFT_FLOAT }, + {"hipSpreadProneMax", offsetof(WeaponFullDef, weapDef.hipSpreadProneMax), CSPFT_FLOAT }, + {"hipSpreadDecayRate", offsetof(WeaponFullDef, weapDef.fHipSpreadDecayRate), CSPFT_FLOAT }, + {"hipSpreadFireAdd", offsetof(WeaponFullDef, weapDef.fHipSpreadFireAdd), CSPFT_FLOAT }, + {"hipSpreadTurnAdd", offsetof(WeaponFullDef, weapDef.fHipSpreadTurnAdd), CSPFT_FLOAT }, + {"hipSpreadMoveAdd", offsetof(WeaponFullDef, weapDef.fHipSpreadMoveAdd), CSPFT_FLOAT }, + {"hipSpreadDuckedDecay", offsetof(WeaponFullDef, weapDef.fHipSpreadDuckedDecay), CSPFT_FLOAT }, + {"hipSpreadProneDecay", offsetof(WeaponFullDef, weapDef.fHipSpreadProneDecay), CSPFT_FLOAT }, + {"hipReticleSidePos", offsetof(WeaponFullDef, weapDef.fHipReticleSidePos), CSPFT_FLOAT }, + {"hipIdleAmount", offsetof(WeaponFullDef, weapDef.fHipIdleAmount), CSPFT_FLOAT }, + {"hipIdleSpeed", offsetof(WeaponFullDef, weapDef.hipIdleSpeed), CSPFT_FLOAT }, + {"hipGunKickReducedKickBullets", offsetof(WeaponFullDef, weapDef.hipGunKickReducedKickBullets), CSPFT_INT }, + {"hipGunKickReducedKickPercent", offsetof(WeaponFullDef, weapDef.hipGunKickReducedKickPercent), CSPFT_FLOAT }, + {"hipGunKickPitchMin", offsetof(WeaponFullDef, weapDef.fHipGunKickPitchMin), CSPFT_FLOAT }, + {"hipGunKickPitchMax", offsetof(WeaponFullDef, weapDef.fHipGunKickPitchMax), CSPFT_FLOAT }, + {"hipGunKickYawMin", offsetof(WeaponFullDef, weapDef.fHipGunKickYawMin), CSPFT_FLOAT }, + {"hipGunKickYawMax", offsetof(WeaponFullDef, weapDef.fHipGunKickYawMax), CSPFT_FLOAT }, + {"hipGunKickAccel", offsetof(WeaponFullDef, weapDef.fHipGunKickAccel), CSPFT_FLOAT }, + {"hipGunKickSpeedMax", offsetof(WeaponFullDef, weapDef.fHipGunKickSpeedMax), CSPFT_FLOAT }, + {"hipGunKickSpeedDecay", offsetof(WeaponFullDef, weapDef.fHipGunKickSpeedDecay), CSPFT_FLOAT }, + {"hipGunKickStaticDecay", offsetof(WeaponFullDef, weapDef.fHipGunKickStaticDecay), CSPFT_FLOAT }, + {"hipViewKickPitchMin", offsetof(WeaponFullDef, weapDef.fHipViewKickPitchMin), CSPFT_FLOAT }, + {"hipViewKickPitchMax", offsetof(WeaponFullDef, weapDef.fHipViewKickPitchMax), CSPFT_FLOAT }, + {"hipViewKickYawMin", offsetof(WeaponFullDef, weapDef.fHipViewKickYawMin), CSPFT_FLOAT }, + {"hipViewKickYawMax", offsetof(WeaponFullDef, weapDef.fHipViewKickYawMax), CSPFT_FLOAT }, + {"hipViewKickCenterSpeed", offsetof(WeaponFullDef, weapVariantDef.fHipViewKickCenterSpeed), CSPFT_FLOAT }, + {"leftArc", offsetof(WeaponFullDef, weapDef.leftArc), CSPFT_FLOAT }, + {"rightArc", offsetof(WeaponFullDef, weapDef.rightArc), CSPFT_FLOAT }, + {"topArc", offsetof(WeaponFullDef, weapDef.topArc), CSPFT_FLOAT }, + {"bottomArc", offsetof(WeaponFullDef, weapDef.bottomArc), CSPFT_FLOAT }, + {"accuracy", offsetof(WeaponFullDef, weapDef.accuracy), CSPFT_FLOAT }, + {"aiSpread", offsetof(WeaponFullDef, weapDef.aiSpread), CSPFT_FLOAT }, + {"playerSpread", offsetof(WeaponFullDef, weapDef.playerSpread), CSPFT_FLOAT }, + {"maxVertTurnSpeed", offsetof(WeaponFullDef, weapDef.maxTurnSpeed[0]), CSPFT_FLOAT }, + {"maxHorTurnSpeed", offsetof(WeaponFullDef, weapDef.maxTurnSpeed[1]), CSPFT_FLOAT }, + {"minVertTurnSpeed", offsetof(WeaponFullDef, weapDef.minTurnSpeed[0]), CSPFT_FLOAT }, + {"minHorTurnSpeed", offsetof(WeaponFullDef, weapDef.minTurnSpeed[1]), CSPFT_FLOAT }, + {"pitchConvergenceTime", offsetof(WeaponFullDef, weapDef.pitchConvergenceTime), CSPFT_FLOAT }, + {"yawConvergenceTime", offsetof(WeaponFullDef, weapDef.yawConvergenceTime), CSPFT_FLOAT }, + {"suppressionTime", offsetof(WeaponFullDef, weapDef.suppressTime), CSPFT_FLOAT }, + {"maxRange", offsetof(WeaponFullDef, weapDef.maxRange), CSPFT_FLOAT }, + {"animHorRotateInc", offsetof(WeaponFullDef, weapDef.fAnimHorRotateInc), CSPFT_FLOAT }, + {"playerPositionDist", offsetof(WeaponFullDef, weapDef.fPlayerPositionDist), CSPFT_FLOAT }, + {"stance", offsetof(WeaponFullDef, weapDef.stance), WFT_STANCE }, + {"useHintString", offsetof(WeaponFullDef, weapDef.szUseHintString), CSPFT_STRING }, + {"dropHintString", offsetof(WeaponFullDef, weapDef.dropHintString), CSPFT_STRING }, + {"horizViewJitter", offsetof(WeaponFullDef, weapDef.horizViewJitter), CSPFT_FLOAT }, + {"vertViewJitter", offsetof(WeaponFullDef, weapDef.vertViewJitter), CSPFT_FLOAT }, + {"fightDist", offsetof(WeaponFullDef, weapDef.fightDist), CSPFT_FLOAT }, + {"maxDist", offsetof(WeaponFullDef, weapDef.maxDist), CSPFT_FLOAT }, + {"aiVsAiAccuracyGraph", offsetof(WeaponFullDef, weapDef.aiVsAiAccuracyGraphName), CSPFT_STRING }, + {"aiVsPlayerAccuracyGraph", offsetof(WeaponFullDef, weapDef.aiVsPlayerAccuracyGraphName), CSPFT_STRING }, + {"locNone", offsetof(WeaponFullDef, locationDamageMultipliers[HITLOC_NONE]), CSPFT_FLOAT }, + {"locHelmet", offsetof(WeaponFullDef, locationDamageMultipliers[HITLOC_HELMET]), CSPFT_FLOAT }, + {"locHead", offsetof(WeaponFullDef, locationDamageMultipliers[HITLOC_HEAD]), CSPFT_FLOAT }, + {"locNeck", offsetof(WeaponFullDef, locationDamageMultipliers[HITLOC_NECK]), CSPFT_FLOAT }, + {"locTorsoUpper", offsetof(WeaponFullDef, locationDamageMultipliers[HITLOC_TORSO_UPR]), CSPFT_FLOAT }, + {"locTorsoLower", offsetof(WeaponFullDef, locationDamageMultipliers[HITLOC_TORSO_LWR]), CSPFT_FLOAT }, + {"locRightArmUpper", offsetof(WeaponFullDef, locationDamageMultipliers[HITLOC_R_ARM_UPR]), CSPFT_FLOAT }, + {"locRightArmLower", offsetof(WeaponFullDef, locationDamageMultipliers[HITLOC_R_ARM_LWR]), CSPFT_FLOAT }, + {"locRightHand", offsetof(WeaponFullDef, locationDamageMultipliers[HITLOC_R_HAND]), CSPFT_FLOAT }, + {"locLeftArmUpper", offsetof(WeaponFullDef, locationDamageMultipliers[HITLOC_L_ARM_UPR]), CSPFT_FLOAT }, + {"locLeftArmLower", offsetof(WeaponFullDef, locationDamageMultipliers[HITLOC_L_ARM_LWR]), CSPFT_FLOAT }, + {"locLeftHand", offsetof(WeaponFullDef, locationDamageMultipliers[HITLOC_L_HAND]), CSPFT_FLOAT }, + {"locRightLegUpper", offsetof(WeaponFullDef, locationDamageMultipliers[HITLOC_R_LEG_UPR]), CSPFT_FLOAT }, + {"locRightLegLower", offsetof(WeaponFullDef, locationDamageMultipliers[HITLOC_R_LEG_LWR]), CSPFT_FLOAT }, + {"locRightFoot", offsetof(WeaponFullDef, locationDamageMultipliers[HITLOC_R_FOOT]), CSPFT_FLOAT }, + {"locLeftLegUpper", offsetof(WeaponFullDef, locationDamageMultipliers[HITLOC_L_LEG_UPR]), CSPFT_FLOAT }, + {"locLeftLegLower", offsetof(WeaponFullDef, locationDamageMultipliers[HITLOC_L_LEG_LWR]), CSPFT_FLOAT }, + {"locLeftFoot", offsetof(WeaponFullDef, locationDamageMultipliers[HITLOC_L_FOOT]), CSPFT_FLOAT }, + {"locGun", offsetof(WeaponFullDef, locationDamageMultipliers[HITLOC_GUN]), CSPFT_FLOAT }, + {"fireRumble", offsetof(WeaponFullDef, weapDef.fireRumble), CSPFT_STRING }, + {"meleeImpactRumble", offsetof(WeaponFullDef, weapDef.meleeImpactRumble), CSPFT_STRING }, + {"reloadRumble", offsetof(WeaponFullDef, weapDef.reloadRumble), CSPFT_STRING }, + {"adsDofStart", offsetof(WeaponFullDef, weapDef.adsDofStart), CSPFT_FLOAT }, + {"adsDofEnd", offsetof(WeaponFullDef, weapDef.adsDofEnd), CSPFT_FLOAT }, + {"scanSpeed", offsetof(WeaponFullDef, weapDef.scanSpeed), CSPFT_FLOAT }, + {"scanAccel", offsetof(WeaponFullDef, weapDef.scanAccel), CSPFT_FLOAT }, + {"scanPauseTime", offsetof(WeaponFullDef, weapDef.scanPauseTime), CSPFT_MILLISECONDS }, + {"flameTableFirstPerson", offsetof(WeaponFullDef, weapDef.flameTableFirstPerson), CSPFT_STRING }, + {"flameTableThirdPerson", offsetof(WeaponFullDef, weapDef.flameTableThirdPerson), CSPFT_STRING }, + {"ikLeftHandOffsetF", offsetof(WeaponFullDef, weapVariantDef.ikLeftHandOffset[0]), CSPFT_FLOAT }, + {"ikLeftHandOffsetR", offsetof(WeaponFullDef, weapVariantDef.ikLeftHandOffset[1]), CSPFT_FLOAT }, + {"ikLeftHandOffsetU", offsetof(WeaponFullDef, weapVariantDef.ikLeftHandOffset[2]), CSPFT_FLOAT }, + {"ikLeftHandRotationP", offsetof(WeaponFullDef, weapVariantDef.ikLeftHandRotation[0]), CSPFT_FLOAT }, + {"ikLeftHandRotationY", offsetof(WeaponFullDef, weapVariantDef.ikLeftHandRotation[1]), CSPFT_FLOAT }, + {"ikLeftHandRotationR", offsetof(WeaponFullDef, weapVariantDef.ikLeftHandRotation[2]), CSPFT_FLOAT }, + {"ikLeftHandProneOffsetF", offsetof(WeaponFullDef, weapVariantDef.ikLeftHandProneOffset[0]), CSPFT_FLOAT }, + {"ikLeftHandProneOffsetR", offsetof(WeaponFullDef, weapVariantDef.ikLeftHandProneOffset[1]), CSPFT_FLOAT }, + {"ikLeftHandProneOffsetU", offsetof(WeaponFullDef, weapVariantDef.ikLeftHandProneOffset[2]), CSPFT_FLOAT }, + {"ikLeftHandProneRotationP", offsetof(WeaponFullDef, weapVariantDef.ikLeftHandProneRotation[0]), CSPFT_FLOAT }, + {"ikLeftHandProneRotationY", offsetof(WeaponFullDef, weapVariantDef.ikLeftHandProneRotation[1]), CSPFT_FLOAT }, + {"ikLeftHandProneRotationR", offsetof(WeaponFullDef, weapVariantDef.ikLeftHandProneRotation[2]), CSPFT_FLOAT }, + {"ikLeftHandUiViewerOffsetF", offsetof(WeaponFullDef, weapVariantDef.ikLeftHandUiViewerOffset[0]), CSPFT_FLOAT }, + {"ikLeftHandUiViewerOffsetR", offsetof(WeaponFullDef, weapVariantDef.ikLeftHandUiViewerOffset[1]), CSPFT_FLOAT }, + {"ikLeftHandUiViewerOffsetU", offsetof(WeaponFullDef, weapVariantDef.ikLeftHandUiViewerOffset[2]), CSPFT_FLOAT }, + {"ikLeftHandUiViewerRotationP", offsetof(WeaponFullDef, weapVariantDef.ikLeftHandUiViewerRotation[0]), CSPFT_FLOAT }, + {"ikLeftHandUiViewerRotationY", offsetof(WeaponFullDef, weapVariantDef.ikLeftHandUiViewerRotation[1]), CSPFT_FLOAT }, + {"ikLeftHandUiViewerRotationR", offsetof(WeaponFullDef, weapVariantDef.ikLeftHandUiViewerRotation[2]), CSPFT_FLOAT }, + {"parentWeaponName", offsetof(WeaponFullDef, weapDef.parentWeaponName), CSPFT_STRING }, + {"doGibbing", offsetof(WeaponFullDef, weapDef.doGibbing), CSPFT_BOOL }, + {"maxGibDistance", offsetof(WeaponFullDef, weapDef.maxGibDistance), CSPFT_FLOAT }, + }; +} diff --git a/src/ObjCommon/Game/T5/Weapon/WeaponStrings.h b/src/ObjCommon/Game/T5/Weapon/WeaponStrings.h new file mode 100644 index 00000000..88d01dcb --- /dev/null +++ b/src/ObjCommon/Game/T5/Weapon/WeaponStrings.h @@ -0,0 +1,211 @@ +#pragma once + +#include "Game/T5/T5.h" + +namespace T5 +{ + inline const char* szWeapTypeNames[]{ + "bullet", + "grenade", + "projectile", + "binoculars", + "gas", + "bomb", + "mine", + "melee", + }; + static_assert(std::extent_v == WEAPTYPE_NUM); + + inline const char* szWeapClassNames[]{ + "rifle", + "mg", + "smg", + "spread", + "pistol", + "grenade", + "rocketlauncher", + "turret", + "non-player", + "gas", + "item", + "melee", + "Killstreak Alt Stored Weapon", + }; + static_assert(std::extent_v == WEAPCLASS_NUM); + + inline const char* szWeapOverlayReticleNames[]{ + "none", + "crosshair", + }; + static_assert(std::extent_v == WEAPOVERLAYRETICLE_NUM); + + inline const char* penetrateTypeNames[]{ + "none", + "small", + "medium", + "large", + }; + static_assert(std::extent_v == PENETRATE_TYPE_NUM); + + inline const char* impactTypeNames[]{ + "none", + "bullet_small", + "bullet_large", + "bullet_ap", + "bullet_xtreme", + "shotgun", + "grenade_bounce", + "grenade_explode", + "rifle_grenade", + "rocket_explode", + "rocket_explode_xtreme", + "projectile_dud", + "mortar_shell", + "tank_shell", + "bolt", + "blade", + }; + static_assert(std::extent_v == IMPACT_TYPE_NUM); + + inline const char* szWeapStanceNames[]{ + "stand", + "duck", + "prone", + }; + static_assert(std::extent_v == WEAPSTANCE_NUM); + + inline const char* szProjectileExplosionNames[]{ + "grenade", + "rocket", + "flashbang", + "none", + "dud", + "smoke", + "heavy explosive", + "fire", + "napalmblob", + "bolt", + }; + static_assert(std::extent_v == WEAPPROJEXP_NUM); + + inline const char* offhandClassNames[]{ + "None", + "Frag Grenade", + "Smoke Grenade", + "Flash Grenade", + "Gear", + }; + static_assert(std::extent_v == OFFHAND_CLASS_NUM); + + inline const char* offhandSlotNames[]{ + "None", + "Lethal grenade", + "Tactical grenade", + "Equipment", + "Specific use", + }; + static_assert(std::extent_v == OFFHAND_SLOT_NUM); + + // mp/playeranimtypes.txt + inline const char* playerAnimTypeNames[]{ + "none", "default", "other", "sniper", "m203", "hold", "briefcase", "reviver", "radio", "dualwield", "remotecontrol", + "crossbow", "minigun", "beltfed", "g11", "rearclip", "rearclipsniper", "ballisticknife", "nopump", "hatchet", "grimreaper", "zipline", + }; + + inline const char* activeReticleNames[]{ + "None", + "Pip-On-A-Stick", + "Bouncing diamond", + }; + static_assert(std::extent_v == VEH_ACTIVE_RETICLE_NUM); + + inline const char* guidedMissileNames[]{ + "None", + "Sidewinder", + "Hellfire", + "Javelin", + "Ballistic", + "WireGuided", + "TVGuided", + }; + static_assert(std::extent_v == MISSILE_GUIDANCE_NUM); + + inline const char* stickinessNames[]{ + "Don't stick", + "Stick to all", + "Stick to all, except ai and clients", + "Stick to ground", + "Stick to ground, maintain yaw", + "Stick to flesh", + }; + static_assert(std::extent_v == WEAPSTICKINESS_NUM); + + inline const char* rotateTypeNames[]{ + "Rotate both axis, grenade style", + "Rotate one axis, blade style", + "Rotate like a cylinder", + }; + static_assert(std::extent_v == WEAPROTATE_NUM); + + inline const char* overlayInterfaceNames[]{ + "None", + "Javelin", + "Turret Scope", + }; + static_assert(std::extent_v == WEAPOVERLAYINTERFACE_NUM); + + inline const char* szWeapInventoryTypeNames[]{ + "primary", + "offhand", + "item", + "altmode", + "melee", + }; + static_assert(std::extent_v == WEAPINVENTORY_NUM); + + inline const char* szWeapFireTypeNames[]{ + "Full Auto", + "Single Shot", + "2-Round Burst", + "3-Round Burst", + "4-Round Burst", + "Stacked Fire", + "Minigun", + }; + static_assert(std::extent_v == WEAPON_FIRETYPE_NUM); + + inline const char* szWeapClipTypeNames[]{ + "bottom", + "top", + "left", + "dp28", + "ptrs", + "lmg", + }; + static_assert(std::extent_v == WEAPON_CLIPTYPE_NUM); + + inline const char* ammoCounterClipNames[]{ + "None", + "Magazine", + "ShortMagazine", + "Shotgun", + "Rocket", + "Beltfed", + "AltWeapon", + }; + static_assert(std::extent_v == AMMO_COUNTER_CLIP_NUM); + + inline const char* weapIconRatioNames[]{ + "1:1", + "2:1", + "4:1", + }; + static_assert(std::extent_v == WEAPON_ICON_RATIO_NUM); + + inline const char* bounceSoundSuffixes[]{ + "_default", "_bark", "_brick", "_carpet", "_cloth", "_concrete", "_dirt", "_flesh", "_foliage", "_glass", "_grass", + "_gravel", "_ice", "_metal", "_mud", "_paper", "_plaster", "_rock", "_sand", "_snow", "_water", "_wood", + "_asphalt", "_ceramic", "_plastic", "_rubber", "_cushion", "_fruit", "_paintedmetal", "_player", "_tallgrass", + }; + static_assert(std::extent_v == SURF_TYPE_NUM); +} // namespace T5 diff --git a/src/ObjCommon/Weapon/WeaponCommon.cpp b/src/ObjCommon/Weapon/WeaponCommon.cpp index 704a388c..df2dc4d2 100644 --- a/src/ObjCommon/Weapon/WeaponCommon.cpp +++ b/src/ObjCommon/Weapon/WeaponCommon.cpp @@ -8,4 +8,9 @@ namespace weapon { return std::format("weapons/{}", assetName); } + + std::string GetFileNameForFlameTable(const std::string& flameTableName) + { + return std::format("weapons/{}", flameTableName); + } } // namespace weapon diff --git a/src/ObjCommon/Weapon/WeaponCommon.h b/src/ObjCommon/Weapon/WeaponCommon.h index 1d1a350a..1fd65457 100644 --- a/src/ObjCommon/Weapon/WeaponCommon.h +++ b/src/ObjCommon/Weapon/WeaponCommon.h @@ -5,4 +5,5 @@ namespace weapon { std::string GetFileNameForAssetName(const std::string& assetName); -} + std::string GetFileNameForFlameTable(const std::string& flameTableName); +} // namespace weapon diff --git a/src/ObjLoading/Game/T5/ObjLoaderT5.cpp b/src/ObjLoading/Game/T5/ObjLoaderT5.cpp index 31dbaec0..d25ac544 100644 --- a/src/ObjLoading/Game/T5/ObjLoaderT5.cpp +++ b/src/ObjLoading/Game/T5/ObjLoaderT5.cpp @@ -18,6 +18,9 @@ #include "PhysPreset/RawLoaderPhysPresetT5.h" #include "RawFile/LoaderRawFileT5.h" #include "StringTable/LoaderStringTableT5.h" +#include "Weapon/FlameTableLoaderT5.h" +#include "Weapon/WeaponGdtLoaderT5.h" +#include "Weapon/WeaponRawLoaderT5.h" #include @@ -132,7 +135,8 @@ namespace // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); collection.AddAssetCreator(localize::CreateLoaderT5(memory, searchPath, zone)); - // collection.AddAssetCreator(std::make_unique(memory)); + collection.AddAssetCreator(weapon::CreateRawLoaderT5(memory, searchPath, zone)); + collection.AddAssetCreator(weapon::CreateGdtLoaderT5(memory, searchPath, gdt, zone)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); @@ -146,6 +150,7 @@ namespace collection.AddSubAssetCreator(techset::CreateVertexShaderLoaderT5(memory, searchPath)); collection.AddSubAssetCreator(techset::CreatePixelShaderLoaderT5(memory, searchPath)); + collection.AddSubAssetCreator(weapon::CreateFlameTableLoaderT5(memory, searchPath, zone)); } } // namespace diff --git a/src/ObjLoading/Game/T5/Weapon/FlameTableLoaderT5.cpp b/src/ObjLoading/Game/T5/Weapon/FlameTableLoaderT5.cpp new file mode 100644 index 00000000..a9ddd47f --- /dev/null +++ b/src/ObjLoading/Game/T5/Weapon/FlameTableLoaderT5.cpp @@ -0,0 +1,93 @@ +#include "FlameTableLoaderT5.h" + +#include "Game/T5/InfoString/InfoStringToStructConverter.h" +#include "Game/T5/ObjConstantsT5.h" +#include "Game/T5/T5.h" +#include "Game/T5/Weapon/FlameTableFields.h" +#include "Weapon/WeaponCommon.h" + +#include +#include + +using namespace T5; + +namespace +{ + class InfoStringToFlameTableConverter final : public InfoStringToStructConverter + { + protected: + bool ConvertExtensionField(const cspField_t& field, const std::string& value) override + { + assert(false); + return false; + } + + public: + InfoStringToFlameTableConverter(const InfoString& infoString, + FlameTable& flameTable, + ZoneScriptStrings& zoneScriptStrings, + MemoryManager& memory, + AssetCreationContext& context, + AssetRegistration& registration, + const cspField_t* fields, + const size_t fieldCount) + : InfoStringToStructConverter(infoString, &flameTable, zoneScriptStrings, memory, context, registration, fields, fieldCount) + { + } + }; + + class FlameTableLoaderT5 final : public SubAssetCreator + { + public: + FlameTableLoaderT5(MemoryManager& memory, ISearchPath& searchPath, Zone& zone) + : m_memory(memory), + m_search_path(searchPath), + m_zone(zone) + { + } + + AssetCreationResult CreateSubAsset(const std::string& assetName, AssetCreationContext& context) override + { + const auto fileName = weapon::GetFileNameForFlameTable(assetName); + const auto file = m_search_path.Open(fileName); + if (!file.IsOpen()) + return AssetCreationResult::NoAction(); + + InfoString infoString; + if (!infoString.FromStream(INFO_STRING_PREFIX_FLAME_TABLE, *file.m_stream)) + { + con::error("Could not parse as info string file: \"{}\"", fileName); + return AssetCreationResult::Failure(); + } + + auto* flameTable = m_memory.Alloc(); + AssetRegistration registration(assetName, flameTable); + InfoStringToFlameTableConverter converter( + infoString, *flameTable, m_zone.m_script_strings, m_memory, context, registration, flameTableFields, std::extent_v); + if (!converter.Convert()) + { + con::error("Failed to parse flame table: \"{}\"", assetName); + return AssetCreationResult::Failure(); + } + + // The flametable infostring contains the name but we don't to use it from there + // It's kept to keep compatiblity with the official modtools and game + flameTable->name = m_memory.Dup(assetName.c_str()); + + return AssetCreationResult::Success(context.AddSubAsset(std::move(registration))); + } + + private: + MemoryManager& m_memory; + ISearchPath& m_search_path; + Zone& m_zone; + }; +} // namespace + +namespace weapon +{ + std::unique_ptr CreateFlameTableLoaderT5(MemoryManager& memory, ISearchPath& searchPath, Zone& zone) + { + return std::make_unique(memory, searchPath, zone); + } +} // namespace weapon diff --git a/src/ObjLoading/Game/T5/Weapon/FlameTableLoaderT5.h b/src/ObjLoading/Game/T5/Weapon/FlameTableLoaderT5.h new file mode 100644 index 00000000..35fed732 --- /dev/null +++ b/src/ObjLoading/Game/T5/Weapon/FlameTableLoaderT5.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Asset/IAssetCreator.h" +#include "SearchPath/ISearchPath.h" +#include "Utils/MemoryManager.h" +#include "Zone/Zone.h" + +#include + +namespace weapon +{ + std::unique_ptr CreateFlameTableLoaderT5(MemoryManager& memory, ISearchPath& searchPath, Zone& zone); +} // namespace weapon diff --git a/src/ObjLoading/Game/T5/Weapon/WeaponGdtLoaderT5.cpp b/src/ObjLoading/Game/T5/Weapon/WeaponGdtLoaderT5.cpp new file mode 100644 index 00000000..31c473fb --- /dev/null +++ b/src/ObjLoading/Game/T5/Weapon/WeaponGdtLoaderT5.cpp @@ -0,0 +1,54 @@ +#include "WeaponGdtLoaderT5.h" + +#include "Game/T5/ObjConstantsT5.h" +#include "Game/T5/T5.h" +#include "InfoString/InfoString.h" +#include "Utils/Logging/Log.h" +#include "WeaponInfoStringLoaderT5.h" + +#include +#include +#include + +using namespace T5; + +namespace +{ + class GdtLoaderWeapon final : public AssetCreator + { + public: + GdtLoaderWeapon(MemoryManager& memory, ISearchPath& searchPath, IGdtQueryable& gdt, Zone& zone) + : m_gdt(gdt), + m_info_string_loader(memory, searchPath, zone) + { + } + + AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override + { + const auto* gdtEntry = m_gdt.GetGdtEntryByGdfAndName(GDF_FILENAME_WEAPON, assetName); + if (gdtEntry == nullptr) + return AssetCreationResult::NoAction(); + + InfoString infoString; + if (!infoString.FromGdtProperties(*gdtEntry)) + { + con::error("Failed to read weapon gdt entry: \"{}\"", assetName); + return AssetCreationResult::Failure(); + } + + return m_info_string_loader.CreateAsset(assetName, infoString, context); + } + + private: + IGdtQueryable& m_gdt; + weapon::InfoStringLoaderT5 m_info_string_loader; + }; +} // namespace + +namespace weapon +{ + std::unique_ptr> CreateGdtLoaderT5(MemoryManager& memory, ISearchPath& searchPath, IGdtQueryable& gdt, Zone& zone) + { + return std::make_unique(memory, searchPath, gdt, zone); + } +} // namespace weapon diff --git a/src/ObjLoading/Game/T5/Weapon/WeaponGdtLoaderT5.h b/src/ObjLoading/Game/T5/Weapon/WeaponGdtLoaderT5.h new file mode 100644 index 00000000..9bd40a85 --- /dev/null +++ b/src/ObjLoading/Game/T5/Weapon/WeaponGdtLoaderT5.h @@ -0,0 +1,14 @@ +#pragma once + +#include "Asset/IAssetCreator.h" +#include "Game/T5/T5.h" +#include "Gdt/IGdtQueryable.h" +#include "SearchPath/ISearchPath.h" +#include "Utils/MemoryManager.h" + +#include + +namespace weapon +{ + std::unique_ptr> CreateGdtLoaderT5(MemoryManager& memory, ISearchPath& searchPath, IGdtQueryable& gdt, Zone& zone); +} // namespace weapon diff --git a/src/ObjLoading/Game/T5/Weapon/WeaponInfoStringLoaderT5.cpp b/src/ObjLoading/Game/T5/Weapon/WeaponInfoStringLoaderT5.cpp new file mode 100644 index 00000000..8d825a40 --- /dev/null +++ b/src/ObjLoading/Game/T5/Weapon/WeaponInfoStringLoaderT5.cpp @@ -0,0 +1,457 @@ +#include "WeaponInfoStringLoaderT5.h" + +#include "Game/T5/InfoString/InfoStringToStructConverter.h" +#include "Game/T5/T5.h" +#include "Game/T5/Weapon/WeaponFields.h" +#include "Game/T5/Weapon/WeaponStrings.h" +#include "Utils/Logging/Log.h" +#include "Utils/StringUtils.h" +#include "Weapon/AccuracyGraphLoader.h" + +#include +#include +#include +#include +#include + +using namespace T5; + +namespace +{ + class InfoStringToWeaponConverter final : public InfoStringToStructConverter + { + protected: + bool ConvertExtensionField(const cspField_t& field, const std::string& value) override + { + switch (static_cast(field.iFieldType)) + { + case WFT_WEAPONTYPE: + return ConvertEnumInt(field.szName, value, field.iOffset, szWeapTypeNames, std::extent_v); + + case WFT_WEAPONCLASS: + return ConvertEnumInt(field.szName, value, field.iOffset, szWeapClassNames, std::extent_v); + + case WFT_OVERLAYRETICLE: + return ConvertEnumInt(field.szName, value, field.iOffset, szWeapOverlayReticleNames, std::extent_v); + + case WFT_PENETRATE_TYPE: + return ConvertEnumInt(field.szName, value, field.iOffset, penetrateTypeNames, std::extent_v); + + case WFT_IMPACT_TYPE: + return ConvertEnumInt(field.szName, value, field.iOffset, impactTypeNames, std::extent_v); + + case WFT_STANCE: + return ConvertEnumInt(field.szName, value, field.iOffset, szWeapStanceNames, std::extent_v); + + case WFT_PROJ_EXPLOSION: + return ConvertEnumInt(field.szName, value, field.iOffset, szProjectileExplosionNames, std::extent_v); + + case WFT_OFFHAND_CLASS: + return ConvertEnumInt(field.szName, value, field.iOffset, offhandClassNames, std::extent_v); + + case WFT_OFFHAND_SLOT: + return ConvertEnumInt(field.szName, value, field.iOffset, offhandSlotNames, std::extent_v); + + case WFT_ANIMTYPE: + return ConvertEnumInt(field.szName, value, field.iOffset, playerAnimTypeNames, std::extent_v); + + case WFT_ACTIVE_RETICLE_TYPE: + return ConvertEnumInt(field.szName, value, field.iOffset, activeReticleNames, std::extent_v); + + case WFT_GUIDED_MISSILE_TYPE: + return ConvertEnumInt(field.szName, value, field.iOffset, guidedMissileNames, std::extent_v); + + case WFT_BOUNCE_SOUND: + return ConvertBounceSounds(field, value); + + case WFT_STICKINESS: + return ConvertEnumInt(field.szName, value, field.iOffset, stickinessNames, std::extent_v); + + case WFT_ROTATETYPE: + return ConvertEnumInt(field.szName, value, field.iOffset, rotateTypeNames, std::extent_v); + + case WFT_OVERLAYINTERFACE: + return ConvertEnumInt(field.szName, value, field.iOffset, overlayInterfaceNames, std::extent_v); + + case WFT_INVENTORYTYPE: + return ConvertEnumInt(field.szName, value, field.iOffset, szWeapInventoryTypeNames, std::extent_v); + + case WFT_FIRETYPE: + return ConvertEnumInt(field.szName, value, field.iOffset, szWeapFireTypeNames, std::extent_v); + + case WFT_CLIPTYPE: + return ConvertEnumInt(field.szName, value, field.iOffset, szWeapClipTypeNames, std::extent_v); + + case WFT_AMMOCOUNTER_CLIPTYPE: + return ConvertEnumInt(field.szName, value, field.iOffset, ammoCounterClipNames, std::extent_v); + + case WFT_ICONRATIO_HUD: + case WFT_ICONRATIO_AMMOCOUNTER: + case WFT_ICONRATIO_KILL: + case WFT_ICONRATIO_DPAD: + case WFT_ICONRATIO_INDICATOR: + return ConvertEnumInt(field.szName, value, field.iOffset, weapIconRatioNames, std::extent_v); + + case WFT_HIDETAGS: + return ConvertHideTags(field, value); + + case WFT_EXPLOSION_TAG: + return ConvertScriptString(value, field.iOffset); + + case WFT_NOTETRACKSOUNDMAP: + return ConvertNotetrackSoundMap(field, value); + + default: + assert(false); + return false; + } + } + + bool ConvertHideTags(const cspField_t& field, const std::string& value) + { + std::vector valueArray; + if (!ParseAsArray(value, valueArray)) + { + con::error("Failed to parse hide tags as array"); + return false; + } + + if (valueArray.size() > std::extent_v) + { + con::error("Cannot have more than {} hide tags!", std::extent_v); + return false; + } + + auto* hideTags = reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset); + + if (valueArray.size() < std::extent_v) + m_registration.AddScriptString(m_zone_script_strings.AddOrGetScriptString(nullptr)); + + auto currentHideTag = 0u; + for (; currentHideTag < valueArray.size(); currentHideTag++) + { + const auto& currentValue = valueArray[currentHideTag]; + const auto scrString = + !currentValue.empty() ? m_zone_script_strings.AddOrGetScriptString(currentValue) : m_zone_script_strings.AddOrGetScriptString(nullptr); + hideTags[currentHideTag] = scrString; + m_registration.AddScriptString(scrString); + } + + for (; currentHideTag < std::extent_v; currentHideTag++) + { + hideTags[currentHideTag] = m_zone_script_strings.GetScriptString(nullptr); + } + + return true; + } + + [[nodiscard]] bool ConvertBounceSounds(const cspField_t& field, const std::string& value) const + { + auto*** bounceSound = reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset); + if (value.empty()) + { + *bounceSound = nullptr; + return true; + } + + *bounceSound = m_memory.Alloc(SURF_TYPE_NUM); + for (auto i = 0u; i < SURF_TYPE_NUM; i++) + { + const auto currentBounceSound = value + bounceSoundSuffixes[i]; + (*bounceSound)[i] = m_memory.Dup(currentBounceSound.c_str()); + } + return true; + } + + [[nodiscard]] bool ConvertNotetrackSoundMap(const cspField_t& field, const std::string& value) + { + std::vector> pairs; + if (!ParseAsArray(value, pairs)) + { + con::error("Failed to parse notetracksoundmap as pairs"); + return false; + } + + if (pairs.size() > std::extent_v) + { + con::error("Cannot have more than {} notetracksoundmap entries!", std::extent_v); + return false; + } + + auto* keys = reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset); + auto* values = &keys[std::extent_v]; + auto currentEntryNum = 0u; + + if (pairs.size() < std::extent_v) + { + m_registration.AddScriptString(m_zone_script_strings.AddOrGetScriptString(nullptr)); + } + + for (; currentEntryNum < pairs.size(); currentEntryNum++) + { + const auto& currentValue = pairs[currentEntryNum]; + const auto keyScriptString = !currentValue[0].empty() ? m_zone_script_strings.AddOrGetScriptString(currentValue[0]) + : m_zone_script_strings.AddOrGetScriptString(nullptr); + const auto valueScriptString = !currentValue[1].empty() ? m_zone_script_strings.AddOrGetScriptString(currentValue[1]) + : m_zone_script_strings.AddOrGetScriptString(nullptr); + + keys[currentEntryNum] = keyScriptString; + m_registration.AddScriptString(keyScriptString); + + values[currentEntryNum] = valueScriptString; + m_registration.AddScriptString(valueScriptString); + } + + for (; currentEntryNum < std::extent_v; currentEntryNum++) + { + const auto emptyScr = m_zone_script_strings.GetScriptString(nullptr); + keys[currentEntryNum] = emptyScr; + values[currentEntryNum] = emptyScr; + } + + return true; + } + + public: + InfoStringToWeaponConverter(const InfoString& infoString, + WeaponFullDef& weaponFullDef, + ZoneScriptStrings& zoneScriptStrings, + MemoryManager& memory, + AssetCreationContext& context, + AssetRegistration& registration, + const cspField_t* fields, + const size_t fieldCount) + : InfoStringToStructConverter(infoString, &weaponFullDef, zoneScriptStrings, memory, context, registration, fields, fieldCount) + { + } + }; + + void ConvertAccuracyGraph( + const GenericGraph2D& graph, vec2_t*& originalGraphKnots, int& originalGraphKnotCount, vec2_t*& graphKnots, int& graphKnotCount, MemoryManager& memory) + { + originalGraphKnotCount = static_cast(graph.knots.size()); + originalGraphKnots = memory.Alloc(originalGraphKnotCount); + + for (auto i = 0; i < originalGraphKnotCount; i++) + { + const auto& commonKnot = graph.knots[i]; + originalGraphKnots[i].x = static_cast(commonKnot.x); + originalGraphKnots[i].y = static_cast(commonKnot.y); + } + + graphKnots = originalGraphKnots; + graphKnotCount = originalGraphKnotCount; + } + + bool LoadAccuracyGraphs(WeaponFullDef& weaponFullDef, MemoryManager& memory, ISearchPath& searchPath, AssetCreationContext& context) + { + auto& accuracyGraphLoader = context.GetZoneAssetCreationState(); + + if (weaponFullDef.weapDef.aiVsAiAccuracyGraphName && weaponFullDef.weapDef.aiVsAiAccuracyGraphName[0]) + { + const auto* graph = accuracyGraphLoader.LoadAiVsAiGraph(searchPath, weaponFullDef.weapDef.aiVsAiAccuracyGraphName); + if (!graph) + return false; + + ConvertAccuracyGraph(*graph, + weaponFullDef.weapDef.originalAiVsAiAccuracyGraphKnots, + weaponFullDef.weapDef.originalAiVsAiAccuracyGraphKnotCount, + weaponFullDef.weapDef.aiVsAiAccuracyGraphKnots, + weaponFullDef.weapDef.aiVsAiAccuracyGraphKnotCount, + memory); + } + + if (weaponFullDef.weapDef.aiVsPlayerAccuracyGraphName && weaponFullDef.weapDef.aiVsPlayerAccuracyGraphName[0]) + { + const auto* graph = accuracyGraphLoader.LoadAiVsPlayerGraph(searchPath, weaponFullDef.weapDef.aiVsPlayerAccuracyGraphName); + if (!graph) + return false; + + ConvertAccuracyGraph(*graph, + weaponFullDef.weapDef.originalAiVsPlayerAccuracyGraphKnots, + weaponFullDef.weapDef.originalAiVsPlayerAccuracyGraphKnotCount, + weaponFullDef.weapDef.aiVsPlayerAccuracyGraphKnots, + weaponFullDef.weapDef.aiVsPlayerAccuracyGraphKnotCount, + memory); + } + + return true; + } + + bool LoadFlameTable(const char* flameTableName, FlameTable*& flameTablePtr, AssetRegistration& registration, AssetCreationContext& context) + { + if (flameTableName && flameTableName[0] != '\0') + { + auto* flameTableAsset = context.LoadSubAsset(flameTableName); + if (!flameTableAsset) + return false; + + for (auto* dependency : flameTableAsset->m_dependencies) + registration.AddDependency(dependency); + + assert(flameTableAsset->m_used_script_strings.empty()); + assert(flameTableAsset->m_indirect_asset_references.empty()); + + flameTablePtr = flameTableAsset->Asset(); + } + + return true; + } + + bool LoadFlameTables(WeaponFullDef& weaponFullDef, AssetRegistration& registration, AssetCreationContext& context) + { + return LoadFlameTable(weaponFullDef.weapDef.flameTableFirstPerson, weaponFullDef.weapDef.flameTableFirstPersonPtr, registration, context) + && LoadFlameTable(weaponFullDef.weapDef.flameTableThirdPerson, weaponFullDef.weapDef.flameTableThirdPersonPtr, registration, context); + } + + void LinkWeaponFullDefSubStructs(WeaponFullDef& weapon) + { + weapon.weapVariantDef.weapDef = &weapon.weapDef; + weapon.weapDef.gunXModel = weapon.gunXModel; + weapon.weapVariantDef.szXAnims = weapon.szXAnims; + weapon.weapVariantDef.hideTags = weapon.hideTags; + weapon.weapDef.notetrackSoundMapKeys = weapon.notetrackSoundMapKeys; + weapon.weapDef.notetrackSoundMapValues = weapon.notetrackSoundMapValues; + weapon.weapDef.worldModel = weapon.worldModel; + weapon.weapDef.parallelBounce = weapon.parallelBounce; + weapon.weapDef.perpendicularBounce = weapon.perpendicularBounce; + weapon.weapDef.locationDamageMultipliers = weapon.locationDamageMultipliers; + } + + bool IsDefaultWeapon(const WeaponFullDef& weapon) + { + return strcmp(weapon.weapVariantDef.szInternalName, "defaultweapon") == 0 || strcmp(weapon.weapVariantDef.szInternalName, "defaultweapon_mp") == 0; + } + + void SetWeaponDefaults(WeaponFullDef& weapon) + { + if (IsDefaultWeapon(weapon)) + return; + + if (!weapon.weapDef.viewLastShotEjectEffect) + weapon.weapDef.viewLastShotEjectEffect = weapon.weapDef.viewShellEjectEffect; + if (!weapon.weapDef.worldLastShotEjectEffect) + weapon.weapDef.worldLastShotEjectEffect = weapon.weapDef.worldShellEjectEffect; + if (!weapon.weapDef.raiseSound) + weapon.weapDef.raiseSound = "wpn_default_raise"; + if (!weapon.weapDef.putawaySound) + weapon.weapDef.putawaySound = "wpn_default_putaway"; + if (!weapon.weapDef.pickupSound) + weapon.weapDef.pickupSound = "wpn_default_pickup"; + if (!weapon.weapDef.ammoPickupSound) + weapon.weapDef.ammoPickupSound = "wpn_default_ammo_pickup"; + if (!weapon.weapDef.emptyFireSound) + weapon.weapDef.emptyFireSound = "wpn_default_no_ammo"; + } + + void SetupTransitionTimes(WeaponFullDef& weapon) + { + if (weapon.weapVariantDef.iAdsTransInTime <= 0) + weapon.weapVariantDef.fOOPosAnimLength[0] = 1.0f / 300.0f; // 0.0033333334f; + else + weapon.weapVariantDef.fOOPosAnimLength[0] = 1.0f / static_cast(weapon.weapVariantDef.iAdsTransInTime); + + if (weapon.weapVariantDef.iAdsTransOutTime <= 0) + weapon.weapVariantDef.fOOPosAnimLength[1] = 1.0f / 500.0f; // 0.0020000001f + else + weapon.weapVariantDef.fOOPosAnimLength[1] = 1.0f / static_cast(weapon.weapVariantDef.iAdsTransOutTime); + } + + void CheckWeaponDamageRanges(WeaponFullDef& weapon) + { + if (strcmp(weapon.weapVariantDef.szInternalName, "none") == 0) + return; + + if (weapon.weapDef.fMaxDamageRange <= 0.0) + weapon.weapDef.fMaxDamageRange = 999999.0f; + if (weapon.weapDef.fMinDamageRange <= 0.0) + weapon.weapDef.fMinDamageRange = 999999.12f; // oddly specific number, no clue + } + + void CheckCrosshairValues(WeaponFullDef& weapon) + { + if (weapon.weapDef.enemyCrosshairRange > 15000.0f) + con::warn("Weapon {}: Enemy crosshair ranges should be less than 15000", weapon.weapVariantDef.szInternalName); + } + + void CheckProjectileValues(WeaponFullDef& weapon) + { + if (weapon.weapDef.weapType != WEAPTYPE_PROJECTILE) + return; + + if (weapon.weapDef.iProjectileSpeed <= 0) + con::warn("Weapon {}: Projectile speed must be greater than 0.0", weapon.weapVariantDef.szDisplayName); + + if (weapon.weapDef.destabilizationCurvatureMax >= 1000000000.0f || weapon.weapDef.destabilizationCurvatureMax < 0.0f) + con::warn("Weapon {}: Destabilization angle must be between 0 and 45 degrees", weapon.weapVariantDef.szDisplayName); + + if (weapon.weapDef.destabilizationRateTime < 0.0f) + con::warn("Weapon {}: Destabilization rate time must be non-negative", weapon.weapVariantDef.szDisplayName); + } + + void CheckSharedAmmoValues(WeaponFullDef& weapon) + { + if (weapon.weapDef.sharedAmmo) + { + if (weapon.weapVariantDef.szAmmoName) + utils::MakeStringLowerCase(const_cast(weapon.weapVariantDef.szAmmoName)); + + if (weapon.weapVariantDef.szClipName) + utils::MakeStringLowerCase(const_cast(weapon.weapVariantDef.szClipName)); + } + else + { + weapon.weapVariantDef.szAmmoName = ""; + weapon.weapVariantDef.szClipName = ""; + } + } +} // namespace + +namespace weapon +{ + InfoStringLoaderT5::InfoStringLoaderT5(MemoryManager& memory, ISearchPath& searchPath, Zone& zone) + : m_memory(memory), + m_search_path(searchPath), + m_zone(zone) + { + } + + AssetCreationResult InfoStringLoaderT5::CreateAsset(const std::string& assetName, const InfoString& infoString, AssetCreationContext& context) + { + auto* weaponFullDef = m_memory.Alloc(); + weaponFullDef->weapVariantDef.szInternalName = m_memory.Dup(assetName.c_str()); + + LinkWeaponFullDefSubStructs(*weaponFullDef); + + AssetRegistration registration(assetName, &weaponFullDef->weapVariantDef); + + InfoStringToWeaponConverter converter( + infoString, *weaponFullDef, m_zone.m_script_strings, m_memory, context, registration, weapon_fields, std::extent_v); + if (!converter.Convert()) + { + con::error("Failed to parse weapon: \"{}\"", assetName); + return AssetCreationResult::Failure(); + } + + if (!LoadAccuracyGraphs(*weaponFullDef, m_memory, m_search_path, context)) + { + con::error("Failed to load accuracy tables of weapon: \"{}\"", assetName); + return AssetCreationResult::Failure(); + } + + if (!LoadFlameTables(*weaponFullDef, registration, context)) + { + con::error("Failed to load flame tables of weapon: \"{}\"", assetName); + return AssetCreationResult::Failure(); + } + + SetWeaponDefaults(*weaponFullDef); + SetupTransitionTimes(*weaponFullDef); + CheckWeaponDamageRanges(*weaponFullDef); + CheckCrosshairValues(*weaponFullDef); + CheckProjectileValues(*weaponFullDef); + CheckSharedAmmoValues(*weaponFullDef); + + return AssetCreationResult::Success(context.AddAsset(std::move(registration))); + } +} // namespace weapon diff --git a/src/ObjLoading/Game/T5/Weapon/WeaponInfoStringLoaderT5.h b/src/ObjLoading/Game/T5/Weapon/WeaponInfoStringLoaderT5.h new file mode 100644 index 00000000..20a68fe4 --- /dev/null +++ b/src/ObjLoading/Game/T5/Weapon/WeaponInfoStringLoaderT5.h @@ -0,0 +1,21 @@ +#pragma once + +#include "Asset/AssetCreationContext.h" +#include "Asset/AssetCreationResult.h" +#include "InfoString/InfoString.h" + +namespace weapon +{ + class InfoStringLoaderT5 + { + public: + InfoStringLoaderT5(MemoryManager& memory, ISearchPath& searchPath, Zone& zone); + + AssetCreationResult CreateAsset(const std::string& assetName, const InfoString& infoString, AssetCreationContext& context); + + private: + MemoryManager& m_memory; + ISearchPath& m_search_path; + Zone& m_zone; + }; +} // namespace weapon diff --git a/src/ObjLoading/Game/T5/Weapon/WeaponRawLoaderT5.cpp b/src/ObjLoading/Game/T5/Weapon/WeaponRawLoaderT5.cpp new file mode 100644 index 00000000..c0d4d4af --- /dev/null +++ b/src/ObjLoading/Game/T5/Weapon/WeaponRawLoaderT5.cpp @@ -0,0 +1,56 @@ +#include "WeaponRawLoaderT5.h" + +#include "Game/T5/ObjConstantsT5.h" +#include "Game/T5/T5.h" +#include "InfoString/InfoString.h" +#include "Utils/Logging/Log.h" +#include "Weapon/WeaponCommon.h" +#include "WeaponInfoStringLoaderT5.h" + +#include +#include +#include + +using namespace T5; + +namespace +{ + class RawLoader final : public AssetCreator + { + public: + RawLoader(MemoryManager& memory, ISearchPath& searchPath, Zone& zone) + : m_search_path(searchPath), + m_info_string_loader(memory, searchPath, zone) + { + } + + AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override + { + const auto fileName = weapon::GetFileNameForAssetName(assetName); + const auto file = m_search_path.Open(fileName); + if (!file.IsOpen()) + return AssetCreationResult::NoAction(); + + InfoString infoString; + if (!infoString.FromStream(INFO_STRING_PREFIX_WEAPON, *file.m_stream)) + { + con::error("Could not parse as info string file: \"{}\"", fileName); + return AssetCreationResult::Failure(); + } + + return m_info_string_loader.CreateAsset(assetName, infoString, context); + } + + private: + ISearchPath& m_search_path; + weapon::InfoStringLoaderT5 m_info_string_loader; + }; +} // namespace + +namespace weapon +{ + std::unique_ptr> CreateRawLoaderT5(MemoryManager& memory, ISearchPath& searchPath, Zone& zone) + { + return std::make_unique(memory, searchPath, zone); + } +} // namespace weapon diff --git a/src/ObjLoading/Game/T5/Weapon/WeaponRawLoaderT5.h b/src/ObjLoading/Game/T5/Weapon/WeaponRawLoaderT5.h new file mode 100644 index 00000000..875746bd --- /dev/null +++ b/src/ObjLoading/Game/T5/Weapon/WeaponRawLoaderT5.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Asset/IAssetCreator.h" +#include "Game/T5/T5.h" +#include "SearchPath/ISearchPath.h" +#include "Utils/MemoryManager.h" + +#include + +namespace weapon +{ + std::unique_ptr> CreateRawLoaderT5(MemoryManager& memory, ISearchPath& searchPath, Zone& zone); +} // namespace weapon diff --git a/src/ObjWriting/Dumping/SubAssetDeduplicationDumperState.h b/src/ObjWriting/Dumping/SubAssetDeduplicationDumperState.h new file mode 100644 index 00000000..ce58886a --- /dev/null +++ b/src/ObjWriting/Dumping/SubAssetDeduplicationDumperState.h @@ -0,0 +1,21 @@ +#pragma once + +#include "Dumping/IZoneAssetDumperState.h" + +#include + +template class SubAssetDeduplicationDumperState final : public IZoneAssetDumperState +{ +public: + [[nodiscard]] bool ShouldDumpSubAsset(const T* subAsset) + { + if (m_dumped_sub_assets.contains(subAsset)) + return false; + + m_dumped_sub_assets.emplace(subAsset); + return true; + } + +private: + std::unordered_set m_dumped_sub_assets; +}; diff --git a/src/ObjWriting/Game/T5/ObjWriterT5.cpp b/src/ObjWriting/Game/T5/ObjWriterT5.cpp index 4a3be588..52fab971 100644 --- a/src/ObjWriting/Game/T5/ObjWriterT5.cpp +++ b/src/ObjWriting/Game/T5/ObjWriterT5.cpp @@ -10,6 +10,7 @@ #include "PhysPreset/PhysPresetInfoStringDumperT5.h" #include "RawFile/RawFileDumperT5.h" #include "StringTable/StringTableDumperT5.h" +#include "Weapon/WeaponDumperT5.h" using namespace T5; @@ -42,7 +43,7 @@ void ObjWriter::RegisterAssetDumpers(AssetDumpingContext& context) // REGISTER_DUMPER(AssetDumperMenuList, m_menu_list) // REGISTER_DUMPER(AssetDumperMenuDef, m_menu_def) RegisterAssetDumper(std::make_unique()); - // REGISTER_DUMPER(AssetDumperWeapon, m_weapon) + RegisterAssetDumper(std::make_unique()); // REGISTER_DUMPER(AssetDumperSndDriverGlobals, m_snd_driver_globals) // REGISTER_DUMPER(AssetDumperFxEffectDef, m_fx) // REGISTER_DUMPER(AssetDumperFxImpactTable, m_fx_impact_table) diff --git a/src/ObjWriting/Game/T5/Weapon/WeaponDumperT5.cpp b/src/ObjWriting/Game/T5/Weapon/WeaponDumperT5.cpp new file mode 100644 index 00000000..eb582a67 --- /dev/null +++ b/src/ObjWriting/Game/T5/Weapon/WeaponDumperT5.cpp @@ -0,0 +1,442 @@ +#include "WeaponDumperT5.h" + +#include "Dumping/SubAssetDeduplicationDumperState.h" +#include "Game/T5/InfoString/InfoStringFromStructConverter.h" +#include "Game/T5/ObjConstantsT5.h" +#include "Game/T5/Weapon/FlameTableFields.h" +#include "Game/T5/Weapon/WeaponFields.h" +#include "Game/T5/Weapon/WeaponStrings.h" +#include "InfoString/InfoString.h" +#include "Weapon/AccuracyGraphWriter.h" +#include "Weapon/WeaponCommon.h" + +#include +#include +#include +#include + +using namespace T5; + +namespace +{ + class InfoStringFromWeaponConverter final : public InfoStringFromStructConverter + { + protected: + void FillFromExtensionField(const cspField_t& field) override + { + switch (static_cast(field.iFieldType)) + { + case WFT_WEAPONTYPE: + FillFromEnumInt(std::string(field.szName), field.iOffset, szWeapTypeNames, std::extent_v); + break; + + case WFT_WEAPONCLASS: + FillFromEnumInt(std::string(field.szName), field.iOffset, szWeapClassNames, std::extent_v); + break; + + case WFT_OVERLAYRETICLE: + FillFromEnumInt(std::string(field.szName), field.iOffset, szWeapOverlayReticleNames, std::extent_v); + break; + + case WFT_PENETRATE_TYPE: + FillFromEnumInt(std::string(field.szName), field.iOffset, penetrateTypeNames, std::extent_v); + break; + + case WFT_IMPACT_TYPE: + FillFromEnumInt(std::string(field.szName), field.iOffset, impactTypeNames, std::extent_v); + break; + + case WFT_STANCE: + FillFromEnumInt(std::string(field.szName), field.iOffset, szWeapStanceNames, std::extent_v); + break; + + case WFT_PROJ_EXPLOSION: + FillFromEnumInt(std::string(field.szName), field.iOffset, szProjectileExplosionNames, std::extent_v); + break; + + case WFT_OFFHAND_CLASS: + FillFromEnumInt(std::string(field.szName), field.iOffset, offhandClassNames, std::extent_v); + break; + + case WFT_OFFHAND_SLOT: + FillFromEnumInt(std::string(field.szName), field.iOffset, offhandSlotNames, std::extent_v); + break; + + case WFT_ANIMTYPE: + FillFromEnumInt(std::string(field.szName), field.iOffset, playerAnimTypeNames, std::extent_v); + break; + + case WFT_ACTIVE_RETICLE_TYPE: + FillFromEnumInt(std::string(field.szName), field.iOffset, activeReticleNames, std::extent_v); + break; + + case WFT_GUIDED_MISSILE_TYPE: + FillFromEnumInt(std::string(field.szName), field.iOffset, guidedMissileNames, std::extent_v); + break; + + case WFT_BOUNCE_SOUND: + { + const auto* bounceSound = *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset); + + if (bounceSound && bounceSound[0]) + { + const std::string firstBounceSound(bounceSound[0]); + const auto endOfBouncePrefix = firstBounceSound.rfind("_default"); + assert(endOfBouncePrefix != std::string::npos); + + if (endOfBouncePrefix != std::string::npos) + { + m_info_string.SetValueForKey(std::string(field.szName), firstBounceSound.substr(0, endOfBouncePrefix)); + } + else + m_info_string.SetValueForKey(std::string(field.szName), ""); + } + else + m_info_string.SetValueForKey(std::string(field.szName), ""); + + break; + } + + case WFT_STICKINESS: + FillFromEnumInt(std::string(field.szName), field.iOffset, stickinessNames, std::extent_v); + break; + + case WFT_ROTATETYPE: + FillFromEnumInt(std::string(field.szName), field.iOffset, rotateTypeNames, std::extent_v); + break; + + case WFT_OVERLAYINTERFACE: + FillFromEnumInt(std::string(field.szName), field.iOffset, overlayInterfaceNames, std::extent_v); + break; + + case WFT_INVENTORYTYPE: + FillFromEnumInt(std::string(field.szName), field.iOffset, szWeapInventoryTypeNames, std::extent_v); + break; + + case WFT_FIRETYPE: + FillFromEnumInt(std::string(field.szName), field.iOffset, szWeapFireTypeNames, std::extent_v); + break; + + case WFT_CLIPTYPE: + FillFromEnumInt(std::string(field.szName), field.iOffset, szWeapClipTypeNames, std::extent_v); + break; + + case WFT_AMMOCOUNTER_CLIPTYPE: + FillFromEnumInt(std::string(field.szName), field.iOffset, ammoCounterClipNames, std::extent_v); + break; + + case WFT_ICONRATIO_HUD: + case WFT_ICONRATIO_AMMOCOUNTER: + case WFT_ICONRATIO_KILL: + case WFT_ICONRATIO_DPAD: + case WFT_ICONRATIO_INDICATOR: + FillFromEnumInt(std::string(field.szName), field.iOffset, weapIconRatioNames, std::extent_v); + break; + + case WFT_HIDETAGS: + { + const auto* hideTags = reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset); + std::stringstream ss; + bool first = true; + + for (auto i = 0u; i < std::extent_v; i++) + { + const auto& str = m_get_scr_string(hideTags[i]); + if (!str.empty()) + { + if (!first) + ss << "\n"; + else + first = false; + + ss << str; + } + } + + m_info_string.SetValueForKey(std::string(field.szName), ss.str()); + break; + } + + case WFT_EXPLOSION_TAG: + FillFromScriptString(std::string(field.szName), field.iOffset); + break; + + case WFT_NOTETRACKSOUNDMAP: + { + const auto* keys = reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset); + const auto* values = &keys[std::extent_v]; + std::stringstream ss; + bool first = true; + + for (auto i = 0u; i < std::extent_v; i++) + { + const auto& key = m_get_scr_string(keys[i]); + const auto& value = m_get_scr_string(values[i]); + if (!key.empty()) + { + if (!first) + ss << "\n"; + else + first = false; + + ss << key; + + if (!value.empty()) + ss << " " << value; + } + } + + m_info_string.SetValueForKey(std::string(field.szName), ss.str()); + break; + } + + case WFT_NUM_FIELD_TYPES: + default: + assert(false); + break; + } + } + + public: + InfoStringFromWeaponConverter(const WeaponFullDef* structure, + const cspField_t* fields, + const size_t fieldCount, + std::function scriptStringValueCallback) + : InfoStringFromStructConverter(structure, fields, fieldCount, std::move(scriptStringValueCallback)) + { + } + }; + + class InfoStringFromFlameTableConverter final : public InfoStringFromStructConverter + { + protected: + void FillFromExtensionField(const cspField_t& field) override + { + assert(false); + } + + public: + InfoStringFromFlameTableConverter(const FlameTable* structure, + const cspField_t* fields, + const size_t fieldCount, + std::function scriptStringValueCallback) + : InfoStringFromStructConverter(structure, fields, fieldCount, std::move(scriptStringValueCallback)) + { + } + }; + + GenericGraph2D ConvertAccuracyGraph(const char* graphName, const vec2_t* originalKnots, const unsigned originalKnotCount) + { + GenericGraph2D graph; + + graph.name = graphName; + graph.knots.resize(originalKnotCount); + + for (auto i = 0u; i < originalKnotCount; i++) + { + auto& knot = graph.knots[i]; + knot.x = originalKnots[i].x; + knot.y = originalKnots[i].y; + } + + return graph; + } + + void CopyToFullDef(const WeaponVariantDef* weapon, WeaponFullDef* fullDef) + { + fullDef->weapVariantDef = *weapon; + + if (weapon->weapDef) + { + fullDef->weapDef = *weapon->weapDef; + fullDef->weapVariantDef.weapDef = &fullDef->weapDef; + } + + if (fullDef->weapDef.gunXModel) + { + assert(sizeof(WeaponFullDef::gunXModel) >= sizeof(void*) * std::extent_v); + memcpy(fullDef->gunXModel, fullDef->weapDef.gunXModel, sizeof(void*) * std::extent_v); + fullDef->weapDef.gunXModel = fullDef->gunXModel; + } + + if (weapon->szXAnims) + { + assert(sizeof(WeaponFullDef::szXAnims) >= sizeof(void*) * NUM_WEAP_ANIMS); + memcpy(fullDef->szXAnims, weapon->szXAnims, sizeof(void*) * NUM_WEAP_ANIMS); + fullDef->weapVariantDef.szXAnims = fullDef->szXAnims; + } + + if (weapon->hideTags) + { + assert(sizeof(WeaponFullDef::hideTags) >= sizeof(scr_string_t) * std::extent_v); + memcpy(fullDef->hideTags, weapon->hideTags, sizeof(scr_string_t) * std::extent_v); + fullDef->weapVariantDef.hideTags = fullDef->hideTags; + } + + if (fullDef->weapDef.notetrackSoundMapKeys) + { + assert(sizeof(WeaponFullDef::notetrackSoundMapKeys) >= sizeof(scr_string_t) * std::extent_v); + memcpy(fullDef->notetrackSoundMapKeys, + fullDef->weapDef.notetrackSoundMapKeys, + sizeof(scr_string_t) * std::extent_v); + fullDef->weapDef.notetrackSoundMapKeys = fullDef->notetrackSoundMapKeys; + } + + if (fullDef->weapDef.notetrackSoundMapValues) + { + assert(sizeof(WeaponFullDef::notetrackSoundMapValues) >= sizeof(scr_string_t) * std::extent_v); + memcpy(fullDef->notetrackSoundMapValues, + fullDef->weapDef.notetrackSoundMapValues, + sizeof(scr_string_t) * std::extent_v); + fullDef->weapDef.notetrackSoundMapValues = fullDef->notetrackSoundMapValues; + } + + if (fullDef->weapDef.worldModel) + { + assert(sizeof(WeaponFullDef::worldModel) >= sizeof(void*) * std::extent_v); + memcpy(fullDef->worldModel, fullDef->weapDef.worldModel, sizeof(void*) * std::extent_v); + fullDef->weapDef.worldModel = fullDef->worldModel; + } + + if (fullDef->weapDef.parallelBounce) + { + assert(sizeof(WeaponFullDef::parallelBounce) >= sizeof(float) * SURF_TYPE_NUM); + memcpy(fullDef->parallelBounce, fullDef->weapDef.parallelBounce, sizeof(float) * SURF_TYPE_NUM); + fullDef->weapDef.parallelBounce = fullDef->parallelBounce; + } + + if (fullDef->weapDef.perpendicularBounce) + { + assert(sizeof(WeaponFullDef::perpendicularBounce) >= sizeof(float) * SURF_TYPE_NUM); + memcpy(fullDef->perpendicularBounce, fullDef->weapDef.perpendicularBounce, sizeof(float) * SURF_TYPE_NUM); + fullDef->weapDef.perpendicularBounce = fullDef->perpendicularBounce; + } + + if (fullDef->weapDef.locationDamageMultipliers) + { + assert(sizeof(WeaponFullDef::locationDamageMultipliers) >= sizeof(float) * HITLOC_COUNT); + memcpy(fullDef->locationDamageMultipliers, fullDef->weapDef.locationDamageMultipliers, sizeof(float) * HITLOC_COUNT); + fullDef->weapDef.locationDamageMultipliers = fullDef->locationDamageMultipliers; + } + } + + InfoString CreateInfoString(const XAssetInfo& asset) + { + const auto fullDef = std::make_unique(); + memset(fullDef.get(), 0, sizeof(WeaponFullDef)); + CopyToFullDef(asset.Asset(), fullDef.get()); + + InfoStringFromWeaponConverter converter(fullDef.get(), + weapon_fields, + std::extent_v, + [asset](const scr_string_t scrStr) -> std::string + { + assert(scrStr < asset.m_zone->m_script_strings.Count()); + if (scrStr >= asset.m_zone->m_script_strings.Count()) + return ""; + + return asset.m_zone->m_script_strings[scrStr]; + }); + + return converter.Convert(); + } + + void DumpAccuracyGraphs(AssetDumpingContext& context, const XAssetInfo& asset) + { + auto* accuracyGraphWriter = context.GetZoneAssetDumperState(); + const auto weapon = asset.Asset(); + const auto* weapDef = weapon->weapDef; + + if (!weapDef) + return; + + if (weapDef->aiVsAiAccuracyGraphName && weapDef->originalAiVsAiAccuracyGraphKnots + && accuracyGraphWriter->ShouldDumpAiVsAiGraph(weapDef->aiVsAiAccuracyGraphName)) + { + AccuracyGraphWriter::DumpAiVsAiGraph(context, + ConvertAccuracyGraph(weapDef->aiVsAiAccuracyGraphName, + weapDef->originalAiVsAiAccuracyGraphKnots, + weapDef->originalAiVsAiAccuracyGraphKnotCount)); + } + + if (weapDef->aiVsPlayerAccuracyGraphName && weapDef->originalAiVsPlayerAccuracyGraphKnots + && accuracyGraphWriter->ShouldDumpAiVsPlayerGraph(weapDef->aiVsPlayerAccuracyGraphName)) + { + AccuracyGraphWriter::DumpAiVsPlayerGraph(context, + ConvertAccuracyGraph(weapDef->aiVsPlayerAccuracyGraphName, + weapDef->originalAiVsPlayerAccuracyGraphKnots, + weapDef->originalAiVsPlayerAccuracyGraphKnotCount)); + } + } + + void DumpFlameTable(const AssetDumpingContext& context, + SubAssetDeduplicationDumperState& deduplicator, + const char* flameTableName, + const FlameTable* flameTable) + { + if (!flameTable || !flameTableName || flameTableName[0] == '\0') + return; + + if (!deduplicator.ShouldDumpSubAsset(flameTable)) + return; + + const auto assetFile = context.OpenAssetFile(weapon::GetFileNameForFlameTable(flameTableName)); + + if (!assetFile) + return; + + auto& stream = *assetFile; + InfoStringFromFlameTableConverter converter(flameTable, + flameTableFields, + std::extent_v, + [](const scr_string_t scrStr) -> std::string + { + assert(false); + return ""; + }); + + const auto infoString = converter.Convert(); + + const auto stringValue = infoString.ToString(INFO_STRING_PREFIX_FLAME_TABLE); + stream.write(stringValue.c_str(), stringValue.size()); + } + + void DumpFlameTables(AssetDumpingContext& context, const XAssetInfo& asset) + { + auto* deduplicator = context.GetZoneAssetDumperState>(); + const auto weapon = asset.Asset(); + + DumpFlameTable(context, *deduplicator, weapon->weapDef->flameTableFirstPerson, weapon->weapDef->flameTableFirstPersonPtr); + DumpFlameTable(context, *deduplicator, weapon->weapDef->flameTableThirdPerson, weapon->weapDef->flameTableThirdPersonPtr); + } +} // namespace + +namespace weapon +{ + void DumperT5::DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) + { + // Only dump raw when no gdt available + if (context.m_gdt) + { + const auto infoString = CreateInfoString(asset); + GdtEntry gdtEntry(asset.m_name, GDF_FILENAME_WEAPON); + infoString.ToGdtProperties(INFO_STRING_PREFIX_WEAPON, gdtEntry); + context.m_gdt->WriteEntry(gdtEntry); + } + else + { + const auto assetFile = context.OpenAssetFile(GetFileNameForAssetName(asset.m_name)); + + if (!assetFile) + return; + + auto& stream = *assetFile; + const auto infoString = CreateInfoString(asset); + const auto stringValue = infoString.ToString(INFO_STRING_PREFIX_WEAPON); + stream.write(stringValue.c_str(), stringValue.size()); + } + + DumpAccuracyGraphs(context, asset); + DumpFlameTables(context, asset); + } +} // namespace weapon diff --git a/src/ObjWriting/Game/T5/Weapon/WeaponDumperT5.h b/src/ObjWriting/Game/T5/Weapon/WeaponDumperT5.h new file mode 100644 index 00000000..236d60ba --- /dev/null +++ b/src/ObjWriting/Game/T5/Weapon/WeaponDumperT5.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/T5/T5.h" + +namespace weapon +{ + class DumperT5 final : public AbstractAssetDumper + { + protected: + void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; + }; +} // namespace weapon diff --git a/src/Utils/Utils/StringUtils.cpp b/src/Utils/Utils/StringUtils.cpp index 08e4f544..3f885a86 100644 --- a/src/Utils/Utils/StringUtils.cpp +++ b/src/Utils/Utils/StringUtils.cpp @@ -91,12 +91,24 @@ namespace utils } } + void MakeStringLowerCase(char* str) + { + for (auto* c = str; *c; c++) + *c = static_cast(tolower(static_cast(*c))); + } + void MakeStringLowerCase(std::string& str) { for (auto& c : str) c = static_cast(tolower(static_cast(c))); } + void MakeStringUpperCase(char* str) + { + for (auto* c = str; *c; c++) + *c = static_cast(toupper(static_cast(*c))); + } + void MakeStringUpperCase(std::string& str) { for (auto& c : str) diff --git a/src/Utils/Utils/StringUtils.h b/src/Utils/Utils/StringUtils.h index 38c7ba04..4c1efdf9 100644 --- a/src/Utils/Utils/StringUtils.h +++ b/src/Utils/Utils/StringUtils.h @@ -13,7 +13,9 @@ namespace utils std::string UnescapeStringFromQuotationMarks(const std::string_view& str); void UnescapeStringFromQuotationMarks(std::ostream& stream, const std::string_view& str); + void MakeStringLowerCase(char* str); void MakeStringLowerCase(std::string& str); + void MakeStringUpperCase(char* str); void MakeStringUpperCase(std::string& str); void StringTrimL(std::string& str); diff --git a/src/ZoneCode/Game/T4/XAssets/WeaponDef.txt b/src/ZoneCode/Game/T4/XAssets/WeaponDef.txt index fc8f1b12..caae269e 100644 --- a/src/ZoneCode/Game/T4/XAssets/WeaponDef.txt +++ b/src/ZoneCode/Game/T4/XAssets/WeaponDef.txt @@ -59,6 +59,6 @@ set condition sound never; // snd_alias_list_name set string snd_alias_list_name::soundName; -// flameTable -use flameTable; +// FlameTable +use FlameTable; set string name; diff --git a/src/ZoneCode/Game/T5/XAssets/WeaponVariantDef.txt b/src/ZoneCode/Game/T5/XAssets/WeaponVariantDef.txt index 488a69d9..112e8fa8 100644 --- a/src/ZoneCode/Game/T5/XAssets/WeaponVariantDef.txt +++ b/src/ZoneCode/Game/T5/XAssets/WeaponVariantDef.txt @@ -162,8 +162,8 @@ reorder: killIcon indicatorIcon; -// flameTable -use flameTable; +// FlameTable +use FlameTable; set string name; set string flameOffLoopSound; set string flameIgniteSound; diff --git a/src/ZoneCode/Game/T6/XAssets/WeaponVariantDef.txt b/src/ZoneCode/Game/T6/XAssets/WeaponVariantDef.txt index c39b148b..fa8133ad 100644 --- a/src/ZoneCode/Game/T6/XAssets/WeaponVariantDef.txt +++ b/src/ZoneCode/Game/T6/XAssets/WeaponVariantDef.txt @@ -185,8 +185,8 @@ reorder: killIcon indicatorIcon; -// flameTable -use flameTable; +// FlameTable +use FlameTable; set string name; set string flameOffLoopSound; set string flameIgniteSound;