diff --git a/docs/SupportedAssetTypes.md b/docs/SupportedAssetTypes.md index c22cdca8..ba43a9f8 100644 --- a/docs/SupportedAssetTypes.md +++ b/docs/SupportedAssetTypes.md @@ -149,7 +149,7 @@ using `Linker`): | MenuList | ❌ | ❌ | | | menuDef_t | ❌ | ❌ | | | LocalizeEntry | ✅ | ✅ | | -| WeaponDef | ❌ | ❌ | | +| WeaponDef | ✅ | ✅ | | | FxEffectDef | ❌ | ❌ | | | FxImpactTable | ❌ | ❌ | | | RawFile | ✅ | ✅ | | diff --git a/src/Common/Game/IW3/IW3_Assets.h b/src/Common/Game/IW3/IW3_Assets.h index 96e09676..18c76c08 100644 --- a/src/Common/Game/IW3/IW3_Assets.h +++ b/src/Common/Game/IW3/IW3_Assets.h @@ -2855,7 +2855,7 @@ namespace IW3 WEAPOVERLAYRETICLE_NUM, }; - enum WeapOverlayInteface_t + enum WeapOverlayInterface_t { WEAPOVERLAYINTERFACE_NONE = 0x0, WEAPOVERLAYINTERFACE_JAVELIN = 0x1, @@ -3150,7 +3150,7 @@ namespace IW3 Material* overlayMaterial; Material* overlayMaterialLowRes; weapOverlayReticle_t overlayReticle; - WeapOverlayInteface_t overlayInterface; + WeapOverlayInterface_t overlayInterface; float overlayWidth; float overlayHeight; float fAdsBobFactor; diff --git a/src/Common/Game/T4/GameT4.cpp b/src/Common/Game/T4/GameT4.cpp index ed9252b6..8066cb09 100644 --- a/src/Common/Game/T4/GameT4.cpp +++ b/src/Common/Game/T4/GameT4.cpp @@ -52,6 +52,8 @@ namespace "vertexdecl", "vertexshader", "pixelshader", + "accuracygraph", + "flametable", }; static_assert(std::extent_v == SUB_ASSET_TYPE_COUNT); } // namespace diff --git a/src/Common/Game/T4/T4.h b/src/Common/Game/T4/T4.h index 09ec32d0..48d117e2 100644 --- a/src/Common/Game/T4/T4.h +++ b/src/Common/Game/T4/T4.h @@ -60,6 +60,8 @@ namespace T4 SUB_ASSET_TYPE_VERTEX_DECL, SUB_ASSET_TYPE_VERTEX_SHADER, SUB_ASSET_TYPE_PIXEL_SHADER, + SUB_ASSET_TYPE_ACCURACY_GRAPH, + SUB_ASSET_TYPE_FLAME_TABLE, SUB_ASSET_TYPE_COUNT }; @@ -83,6 +85,69 @@ namespace T4 XAsset* assets; }; + struct cspField_t + { + const char* szName; + int iOffset; + int iFieldType; + }; + + enum csParseFieldType_t + { + CSPFT_STRING, + CSPFT_STRING_MAX_STRING_CHARS, + CSPFT_STRING_MAX_QPATH, + CSPFT_STRING_MAX_OSPATH, + CSPFT_INT, + CSPFT_BOOL, + CSPFT_FLOAT, + CSPFT_MILLISECONDS, + CSPFT_FX, + CSPFT_XMODEL, + CSPFT_MATERIAL, + CSPFT_SOUND, + + CSPFT_NUM_BASE_FIELD_TYPES + }; + + enum weapFieldType_t + { + WFT_WEAPONTYPE = CSPFT_NUM_BASE_FIELD_TYPES, + WFT_WEAPONCLASS, + WFT_OVERLAYRETICLE, + WFT_PENETRATE_TYPE, + WFT_IMPACT_TYPE, + WFT_STANCE, + WFT_PROJ_EXPLOSION, + WFT_OFFHAND_CLASS, + WFT_ANIMTYPE, + WFT_ACTIVE_RETICLE_TYPE, + WFT_GUIDED_MISSILE_TYPE, + WFT_BOUNCE_SOUND, + WFT_STICKINESS, + WFT_OVERLAYINTERFACE, + WFT_INVENTORYTYPE, + WFT_FIRETYPE, + WFT_CLIPTYPE, + WFT_AMMOCOUNTER_CLIPTYPE, + WFT_ICONRATIO_HUD, + WFT_ICONRATIO_AMMOCOUNTER, + WFT_ICONRATIO_KILL, + WFT_ICONRATIO_DPAD, + WFT_HIDETAGS, + WFT_NOTETRACKSOUNDMAP, + + WFT_ANIM_NAME, + + WFT_NUM_FIELD_TYPES, + }; + + struct AccuracyGraph + { + vec2_t* graphKnots; + int graphKnotCount; + }; + using AssetPhysPreset = Asset; using AssetPhysConstraints = Asset; using AssetDestructibleDef = Asset; @@ -117,6 +182,8 @@ namespace T4 using SubAssetVertexDecl = SubAsset; using SubAssetVertexShader = SubAsset; using SubAssetPixelShader = SubAsset; + using SubAssetAccuracyGraph = SubAsset; + using SubAssetFlameTable = SubAsset; } // namespace T4 DEFINE_ASSET_NAME_ACCESSOR(T4::AssetPhysPreset, name); diff --git a/src/Common/Game/T4/T4_Assets.h b/src/Common/Game/T4/T4_Assets.h index 21e75c91..2de77160 100644 --- a/src/Common/Game/T4/T4_Assets.h +++ b/src/Common/Game/T4/T4_Assets.h @@ -1013,6 +1013,8 @@ namespace T4 SURF_TYPE_CUSHION, SURF_TYPE_FRUIT, SURF_TYPE_PAINTED_METAL, + SURF_TYPE_PLAYER, + SURF_TYPE_TALL_GRASS, SURF_TYPE_NUM }; @@ -2999,7 +3001,11 @@ namespace T4 WEAPTYPE_GRENADE = 0x1, WEAPTYPE_PROJECTILE = 0x2, WEAPTYPE_BINOCULARS = 0x3, - WEAPTYPE_NUM = 0x4, + WEAPTYPE_GAS = 0x4, + WEAPTYPE_BOMB = 0x5, + WEAPTYPE_MINE = 0x6, + + WEAPTYPE_NUM, }; enum weapClass_t @@ -3013,8 +3019,10 @@ namespace T4 WEAPCLASS_ROCKETLAUNCHER = 0x6, WEAPCLASS_TURRET = 0x7, WEAPCLASS_NON_PLAYER = 0x8, - WEAPCLASS_ITEM = 0x9, - WEAPCLASS_NUM = 0xA, + WEAPCLASS_GAS = 0x9, + WEAPCLASS_ITEM = 0xA, + + WEAPCLASS_NUM, }; enum PenetrateType @@ -3023,7 +3031,8 @@ namespace T4 PENETRATE_TYPE_SMALL = 0x1, PENETRATE_TYPE_MEDIUM = 0x2, PENETRATE_TYPE_LARGE = 0x3, - PENETRATE_TYPE_COUNT = 0x4, + + PENETRATE_TYPE_NUM, }; enum ImpactType @@ -3035,9 +3044,13 @@ namespace T4 IMPACT_TYPE_SHOTGUN = 0x4, IMPACT_TYPE_GRENADE_BOUNCE = 0x5, IMPACT_TYPE_GRENADE_EXPLODE = 0x6, - IMPACT_TYPE_ROCKET_EXPLODE = 0x7, - IMPACT_TYPE_PROJECTILE_DUD = 0x8, - IMPACT_TYPE_COUNT = 0x9, + IMPACT_TYPE_RIFLE_GRENADE = 0x7, + IMPACT_TYPE_ROCKET_EXPLODE = 0x8, + IMPACT_TYPE_PROJECTILE_DUD = 0x9, + IMPACT_TYPE_MORTAR_SHELL = 0xA, + IMPACT_TYPE_TANK_SHELL = 0xB, + + IMPACT_TYPE_NUM, }; enum weapInventoryType_t @@ -3046,7 +3059,8 @@ namespace T4 WEAPINVENTORY_OFFHAND = 0x1, WEAPINVENTORY_ITEM = 0x2, WEAPINVENTORY_ALTMODE = 0x3, - WEAPINVENTORYCOUNT = 0x4, + + WEAPINVENTORY_NUM, }; enum weapFireType_t @@ -3056,7 +3070,8 @@ namespace T4 WEAPON_FIRETYPE_BURSTFIRE2 = 0x2, WEAPON_FIRETYPE_BURSTFIRE3 = 0x3, WEAPON_FIRETYPE_BURSTFIRE4 = 0x4, - WEAPON_FIRETYPECOUNT = 0x5, + + WEAPON_FIRETYPE_NUM, }; enum OffhandClass @@ -3065,7 +3080,8 @@ namespace T4 OFFHAND_CLASS_FRAG_GRENADE = 0x1, OFFHAND_CLASS_SMOKE_GRENADE = 0x2, OFFHAND_CLASS_FLASH_GRENADE = 0x3, - OFFHAND_CLASS_COUNT = 0x4, + + OFFHAND_CLASS_NUM, }; enum weapStance_t @@ -3073,7 +3089,8 @@ namespace T4 WEAPSTANCE_STAND = 0x0, WEAPSTANCE_DUCK = 0x1, WEAPSTANCE_PRONE = 0x2, - WEAPSTANCE_NUM = 0x3, + + WEAPSTANCE_NUM, }; enum activeReticleType_t @@ -3081,7 +3098,8 @@ namespace T4 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 weaponIconRatioType_t @@ -3089,7 +3107,8 @@ namespace T4 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 weapClipType_t @@ -3100,7 +3119,8 @@ namespace T4 WEAPON_CLIPTYPE_DP28 = 0x3, WEAPON_CLIPTYPE_PTRS = 0x4, WEAPON_CLIPTYPE_LMG = 0x5, - WEAPON_CLIPTYPECOUNT = 0x6, + + WEAPON_CLIPTYPE_NUM, }; enum ammoCounterClipType_t @@ -3112,22 +3132,25 @@ namespace T4 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 + enum WeapOverlayInterface_t { WEAPOVERLAYINTERFACE_NONE = 0x0, WEAPOVERLAYINTERFACE_JAVELIN = 0x1, WEAPOVERLAYINTERFACE_TURRETSCOPE = 0x2, - WEAPOVERLAYINTERFACECOUNT = 0x3, + + WEAPOVERLAYINTERFACE_NUM, }; enum weapProjExposion_t @@ -3139,7 +3162,10 @@ namespace T4 WEAPPROJEXP_DUD = 0x4, WEAPPROJEXP_SMOKE = 0x5, WEAPPROJEXP_HEAVY = 0x6, - WEAPPROJEXP_NUM = 0x7, + WEAPPROJEXP_FIRE = 0x7, + WEAPPROJEXP_NAPALMBLOB = 0x8, + + WEAPPROJEXP_NUM, }; enum WeapStickinessType @@ -3148,7 +3174,8 @@ namespace T4 WEAPSTICKINESS_ALL = 0x1, WEAPSTICKINESS_GROUND = 0x2, WEAPSTICKINESS_GROUND_WITH_YAW = 0x3, - WEAPSTICKINESS_COUNT = 0x4, + + WEAPSTICKINESS_NUM, }; enum guidedMissileType_t @@ -3158,7 +3185,49 @@ namespace T4 MISSILE_GUIDANCE_HELLFIRE = 0x2, MISSILE_GUIDANCE_JAVELIN = 0x3, MISSILE_GUIDANCE_BALLISTIC = 0x4, - MISSILE_GUIDANCE_COUNT = 0x5, + + MISSILE_GUIDANCE_NUM, + }; + + enum WeaponAnimSlot + { + WEAP_ANIM_ROOT = 0x0, + WEAP_ANIM_IDLE = 0x1, + WEAP_ANIM_EMPTY_IDLE = 0x2, + WEAP_ANIM_FIRE = 0x3, + WEAP_ANIM_HOLD_FIRE = 0x4, + WEAP_ANIM_LASTSHOT = 0x5, + WEAP_ANIM_RECHAMBER = 0x6, + WEAP_ANIM_MELEE = 0x7, + WEAP_ANIM_MELEE_CHARGE = 0x8, + WEAP_ANIM_RELOAD = 0x9, + WEAP_ANIM_RELOAD_EMPTY = 0xA, + WEAP_ANIM_RELOAD_START = 0xB, + WEAP_ANIM_RELOAD_END = 0xC, + WEAP_ANIM_RAISE = 0xD, + WEAP_ANIM_FIRST_RAISE = 0xE, + WEAP_ANIM_DROP = 0xF, + WEAP_ANIM_ALT_RAISE = 0x10, + WEAP_ANIM_ALT_DROP = 0x11, + WEAP_ANIM_QUICK_RAISE = 0x12, + WEAP_ANIM_QUICK_DROP = 0x13, + WEAP_ANIM_EMPTY_RAISE = 0x14, + WEAP_ANIM_EMPTY_DROP = 0x15, + WEAP_ANIM_SPRINT_IN = 0x16, + WEAP_ANIM_SPRINT_LOOP = 0x17, + WEAP_ANIM_SPRINT_OUT = 0x18, + WEAP_ANIM_DEPLOY = 0x19, + WEAP_ANIM_BREAKDOWN = 0x1A, + WEAP_ANIM_DETONATE = 0x1B, + WEAP_ANIM_NIGHTVISION_WEAR = 0x1C, + WEAP_ANIM_NIGHTVISION_REMOVE = 0x1D, + WEAP_ANIM_ADS_FIRE = 0x1E, + WEAP_ANIM_ADS_LASTSHOT = 0x1F, + WEAP_ANIM_ADS_RECHAMBER = 0x20, + WEAP_ANIM_ADS_UP = 0x21, + WEAP_ANIM_ADS_DOWN = 0x22, + + NUM_WEAP_ANIMS, }; enum hitLocation_t @@ -3586,7 +3655,7 @@ namespace T4 Material* overlayMaterial; Material* overlayMaterialLowRes; weapOverlayReticle_t overlayReticle; - WeapOverlayInteface_t overlayInterface; + WeapOverlayInterface_t overlayInterface; float overlayWidth; float overlayHeight; float fAdsBobFactor; diff --git a/src/Common/Game/T6/T6_Assets.h b/src/Common/Game/T6/T6_Assets.h index 5fb61668..1bcfc35b 100644 --- a/src/Common/Game/T6/T6_Assets.h +++ b/src/Common/Game/T6/T6_Assets.h @@ -4295,7 +4295,7 @@ namespace T6 AMMO_COUNTER_CLIP_COUNT = 0x7, }; - enum WeapOverlayInteface_t + enum WeapOverlayInterface_t { WEAPOVERLAYINTERFACE_NONE = 0x0, WEAPOVERLAYINTERFACE_JAVELIN = 0x1, @@ -4671,7 +4671,7 @@ namespace T6 float adsMoveSpeedScale; float sprintDurationScale; weapOverlayReticle_t overlayReticle; - WeapOverlayInteface_t overlayInterface; + WeapOverlayInterface_t overlayInterface; float overlayWidth; float overlayHeight; float fAdsBobFactor; diff --git a/src/ObjCommon/Game/T4/ObjConstantsT4.h b/src/ObjCommon/Game/T4/ObjConstantsT4.h new file mode 100644 index 00000000..ec1436be --- /dev/null +++ b/src/ObjCommon/Game/T4/ObjConstantsT4.h @@ -0,0 +1,9 @@ +#pragma once + +namespace T4 +{ + static constexpr auto INFO_STRING_PREFIX_FLAME_TABLE = "FLAMETABLEFILE"; + static constexpr auto INFO_STRING_PREFIX_WEAPON = "WEAPONFILE"; + + static constexpr auto GDF_FILENAME_WEAPON = "weapon.gdf"; +} // namespace T4 diff --git a/src/ObjCommon/Game/T4/Weapon/FlameTableFields.h b/src/ObjCommon/Game/T4/Weapon/FlameTableFields.h new file mode 100644 index 00000000..4f1ef8b2 --- /dev/null +++ b/src/ObjCommon/Game/T4/Weapon/FlameTableFields.h @@ -0,0 +1,130 @@ +#pragma once + +#include "Game/T4/T4.h" + +#include + +namespace T4 +{ + 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_SOUND }, + {"flameIgniteSound", offsetof(FlameTable, flameIgniteSound), CSPFT_SOUND }, + {"flameOnLoopSound", offsetof(FlameTable, flameOnLoopSound), CSPFT_SOUND }, + {"flameCooldownSound", offsetof(FlameTable, flameCooldownSound), CSPFT_SOUND }, + }; +} // namespace T4 diff --git a/src/ObjCommon/Game/T4/Weapon/WeaponFields.h b/src/ObjCommon/Game/T4/Weapon/WeaponFields.h new file mode 100644 index 00000000..c3da94c5 --- /dev/null +++ b/src/ObjCommon/Game/T4/Weapon/WeaponFields.h @@ -0,0 +1,573 @@ +#pragma once + +#include "Game/T4/T4.h" + +#include + +namespace T4 +{ + inline cspField_t weapon_fields[]{ + {"displayName", offsetof(WeaponDef, szDisplayName), CSPFT_STRING }, + {"AIOverlayDescription", offsetof(WeaponDef, szOverlayName), CSPFT_STRING }, + {"modeName", offsetof(WeaponDef, szModeName), CSPFT_STRING }, + {"playerAnimType", offsetof(WeaponDef, playerAnimType), WFT_ANIMTYPE }, + {"gunModel", offsetof(WeaponDef, gunXModel[0]), CSPFT_XMODEL }, + {"gunModel2", offsetof(WeaponDef, gunXModel[1]), CSPFT_XMODEL }, + {"gunModel3", offsetof(WeaponDef, gunXModel[2]), CSPFT_XMODEL }, + {"gunModel4", offsetof(WeaponDef, gunXModel[3]), CSPFT_XMODEL }, + {"gunModel5", offsetof(WeaponDef, gunXModel[4]), CSPFT_XMODEL }, + {"gunModel6", offsetof(WeaponDef, gunXModel[5]), CSPFT_XMODEL }, + {"gunModel7", offsetof(WeaponDef, gunXModel[6]), CSPFT_XMODEL }, + {"gunModel8", offsetof(WeaponDef, gunXModel[7]), CSPFT_XMODEL }, + {"gunModel9", offsetof(WeaponDef, gunXModel[8]), CSPFT_XMODEL }, + {"gunModel10", offsetof(WeaponDef, gunXModel[9]), CSPFT_XMODEL }, + {"gunModel11", offsetof(WeaponDef, gunXModel[10]), CSPFT_XMODEL }, + {"gunModel12", offsetof(WeaponDef, gunXModel[11]), CSPFT_XMODEL }, + {"gunModel13", offsetof(WeaponDef, gunXModel[12]), CSPFT_XMODEL }, + {"gunModel14", offsetof(WeaponDef, gunXModel[13]), CSPFT_XMODEL }, + {"gunModel15", offsetof(WeaponDef, gunXModel[14]), CSPFT_XMODEL }, + {"gunModel16", offsetof(WeaponDef, gunXModel[15]), CSPFT_XMODEL }, + {"handModel", offsetof(WeaponDef, handXModel), CSPFT_XMODEL }, + {"hideTags", offsetof(WeaponDef, hideTags), WFT_HIDETAGS }, + {"notetrackSoundMap", offsetof(WeaponDef, notetrackSoundMapKeys), WFT_NOTETRACKSOUNDMAP }, + {"idleAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_IDLE]), WFT_ANIM_NAME }, + {"emptyIdleAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_EMPTY_IDLE]), WFT_ANIM_NAME }, + {"fireAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_FIRE]), WFT_ANIM_NAME }, + {"holdFireAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_HOLD_FIRE]), WFT_ANIM_NAME }, + {"lastShotAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_LASTSHOT]), WFT_ANIM_NAME }, + {"detonateAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_DETONATE]), WFT_ANIM_NAME }, + {"rechamberAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_RECHAMBER]), WFT_ANIM_NAME }, + {"meleeAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_MELEE]), WFT_ANIM_NAME }, + {"meleeChargeAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_MELEE_CHARGE]), WFT_ANIM_NAME }, + {"reloadAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_RELOAD]), WFT_ANIM_NAME }, + {"reloadEmptyAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_RELOAD_EMPTY]), WFT_ANIM_NAME }, + {"reloadStartAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_RELOAD_START]), WFT_ANIM_NAME }, + {"reloadEndAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_RELOAD_END]), WFT_ANIM_NAME }, + {"raiseAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_RAISE]), WFT_ANIM_NAME }, + {"dropAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_DROP]), WFT_ANIM_NAME }, + {"firstRaiseAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_FIRST_RAISE]), WFT_ANIM_NAME }, + {"altRaiseAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_ALT_RAISE]), WFT_ANIM_NAME }, + {"altDropAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_ALT_DROP]), WFT_ANIM_NAME }, + {"quickRaiseAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_QUICK_RAISE]), WFT_ANIM_NAME }, + {"quickDropAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_QUICK_DROP]), WFT_ANIM_NAME }, + {"emptyRaiseAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_EMPTY_RAISE]), WFT_ANIM_NAME }, + {"emptyDropAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_EMPTY_DROP]), WFT_ANIM_NAME }, + {"sprintInAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_SPRINT_IN]), WFT_ANIM_NAME }, + {"sprintLoopAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_SPRINT_LOOP]), WFT_ANIM_NAME }, + {"sprintOutAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_SPRINT_OUT]), WFT_ANIM_NAME }, + {"deployAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_DEPLOY]), WFT_ANIM_NAME }, + {"breakdownAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_BREAKDOWN]), WFT_ANIM_NAME }, + {"nightVisionWearAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_NIGHTVISION_WEAR]), WFT_ANIM_NAME }, + {"nightVisionRemoveAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_NIGHTVISION_REMOVE]), WFT_ANIM_NAME }, + {"adsFireAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_ADS_FIRE]), WFT_ANIM_NAME }, + {"adsLastShotAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_ADS_LASTSHOT]), WFT_ANIM_NAME }, + {"adsRechamberAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_ADS_RECHAMBER]), WFT_ANIM_NAME }, + {"adsUpAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_ADS_UP]), WFT_ANIM_NAME }, + {"adsDownAnim", offsetof(WeaponDef, szXAnims[WEAP_ANIM_ADS_DOWN]), WFT_ANIM_NAME }, + {"script", offsetof(WeaponDef, szScript), CSPFT_STRING }, + {"weaponType", offsetof(WeaponDef, weapType), WFT_WEAPONTYPE }, + {"weaponClass", offsetof(WeaponDef, weapClass), WFT_WEAPONCLASS }, + {"penetrateType", offsetof(WeaponDef, penetrateType), WFT_PENETRATE_TYPE }, + {"impactType", offsetof(WeaponDef, impactType), WFT_IMPACT_TYPE }, + {"inventoryType", offsetof(WeaponDef, inventoryType), WFT_INVENTORYTYPE }, + {"fireType", offsetof(WeaponDef, fireType), WFT_FIRETYPE }, + {"clipType", offsetof(WeaponDef, clipType), WFT_CLIPTYPE }, + {"offhandClass", offsetof(WeaponDef, offhandClass), WFT_OFFHAND_CLASS }, + {"viewFlashEffect", offsetof(WeaponDef, viewFlashEffect), CSPFT_FX }, + {"worldFlashEffect", offsetof(WeaponDef, worldFlashEffect), CSPFT_FX }, + {"pickupSound", offsetof(WeaponDef, pickupSound), CSPFT_SOUND }, + {"pickupSoundPlayer", offsetof(WeaponDef, pickupSoundPlayer), CSPFT_SOUND }, + {"ammoPickupSound", offsetof(WeaponDef, ammoPickupSound), CSPFT_SOUND }, + {"ammoPickupSoundPlayer", offsetof(WeaponDef, ammoPickupSoundPlayer), CSPFT_SOUND }, + {"projectileSound", offsetof(WeaponDef, projectileSound), CSPFT_SOUND }, + {"pullbackSound", offsetof(WeaponDef, pullbackSound), CSPFT_SOUND }, + {"pullbackSoundPlayer", offsetof(WeaponDef, pullbackSoundPlayer), CSPFT_SOUND }, + {"fireSound", offsetof(WeaponDef, fireSound), CSPFT_SOUND }, + {"crackSound", offsetof(WeaponDef, crackSound), CSPFT_SOUND }, + {"whizbySound", offsetof(WeaponDef, whizbySound), CSPFT_SOUND }, + {"fireSoundPlayer", offsetof(WeaponDef, fireSoundPlayer), CSPFT_SOUND }, + {"loopFireSound", offsetof(WeaponDef, fireLoopSound), CSPFT_SOUND }, + {"loopFireSoundPlayer", offsetof(WeaponDef, fireLoopSoundPlayer), CSPFT_SOUND }, + {"stopFireSound", offsetof(WeaponDef, fireStopSound), CSPFT_SOUND }, + {"stopFireSoundPlayer", offsetof(WeaponDef, fireStopSoundPlayer), CSPFT_SOUND }, + {"lastShotSound", offsetof(WeaponDef, fireLastSound), CSPFT_SOUND }, + {"lastShotSoundPlayer", offsetof(WeaponDef, fireLastSoundPlayer), CSPFT_SOUND }, + {"emptyFireSound", offsetof(WeaponDef, emptyFireSound), CSPFT_SOUND }, + {"emptyFireSoundPlayer", offsetof(WeaponDef, emptyFireSoundPlayer), CSPFT_SOUND }, + {"meleeSwipeSound", offsetof(WeaponDef, meleeSwipeSound), CSPFT_SOUND }, + {"meleeSwipeSoundPlayer", offsetof(WeaponDef, meleeSwipeSoundPlayer), CSPFT_SOUND }, + {"meleeHitSound", offsetof(WeaponDef, meleeHitSound), CSPFT_SOUND }, + {"meleeMissSound", offsetof(WeaponDef, meleeMissSound), CSPFT_SOUND }, + {"rechamberSound", offsetof(WeaponDef, rechamberSound), CSPFT_SOUND }, + {"rechamberSoundPlayer", offsetof(WeaponDef, rechamberSoundPlayer), CSPFT_SOUND }, + {"reloadSound", offsetof(WeaponDef, reloadSound), CSPFT_SOUND }, + {"reloadSoundPlayer", offsetof(WeaponDef, reloadSoundPlayer), CSPFT_SOUND }, + {"reloadEmptySound", offsetof(WeaponDef, reloadEmptySound), CSPFT_SOUND }, + {"reloadEmptySoundPlayer", offsetof(WeaponDef, reloadEmptySoundPlayer), CSPFT_SOUND }, + {"reloadStartSound", offsetof(WeaponDef, reloadStartSound), CSPFT_SOUND }, + {"reloadStartSoundPlayer", offsetof(WeaponDef, reloadStartSoundPlayer), CSPFT_SOUND }, + {"reloadEndSound", offsetof(WeaponDef, reloadEndSound), CSPFT_SOUND }, + {"reloadEndSoundPlayer", offsetof(WeaponDef, reloadEndSoundPlayer), CSPFT_SOUND }, + {"rotateLoopSound", offsetof(WeaponDef, rotateLoopSound), CSPFT_SOUND }, + {"rotateLoopSoundPlayer", offsetof(WeaponDef, rotateLoopSoundPlayer), CSPFT_SOUND }, + {"deploySound", offsetof(WeaponDef, deploySound), CSPFT_SOUND }, + {"deploySoundPlayer", offsetof(WeaponDef, deploySoundPlayer), CSPFT_SOUND }, + {"finishDeploySound", offsetof(WeaponDef, finishDeploySound), CSPFT_SOUND }, + {"finishDeploySoundPlayer", offsetof(WeaponDef, finishDeploySoundPlayer), CSPFT_SOUND }, + {"breakdownSound", offsetof(WeaponDef, breakdownSound), CSPFT_SOUND }, + {"breakdownSoundPlayer", offsetof(WeaponDef, breakdownSoundPlayer), CSPFT_SOUND }, + {"finishBreakdownSound", offsetof(WeaponDef, finishBreakdownSound), CSPFT_SOUND }, + {"finishBreakdownSoundPlayer", offsetof(WeaponDef, finishBreakdownSoundPlayer), CSPFT_SOUND }, + {"detonateSound", offsetof(WeaponDef, detonateSound), CSPFT_SOUND }, + {"detonateSoundPlayer", offsetof(WeaponDef, detonateSoundPlayer), CSPFT_SOUND }, + {"nightVisionWearSound", offsetof(WeaponDef, nightVisionWearSound), CSPFT_SOUND }, + {"nightVisionWearSoundPlayer", offsetof(WeaponDef, nightVisionWearSoundPlayer), CSPFT_SOUND }, + {"nightVisionRemoveSound", offsetof(WeaponDef, nightVisionRemoveSound), CSPFT_SOUND }, + {"nightVisionRemoveSoundPlayer", offsetof(WeaponDef, nightVisionRemoveSoundPlayer), CSPFT_SOUND }, + {"raiseSound", offsetof(WeaponDef, raiseSound), CSPFT_SOUND }, + {"raiseSoundPlayer", offsetof(WeaponDef, raiseSoundPlayer), CSPFT_SOUND }, + {"firstRaiseSound", offsetof(WeaponDef, firstRaiseSound), CSPFT_SOUND }, + {"firstRaiseSoundPlayer", offsetof(WeaponDef, firstRaiseSoundPlayer), CSPFT_SOUND }, + {"altSwitchSound", offsetof(WeaponDef, altSwitchSound), CSPFT_SOUND }, + {"altSwitchSoundPlayer", offsetof(WeaponDef, altSwitchSoundPlayer), CSPFT_SOUND }, + {"putawaySound", offsetof(WeaponDef, putawaySound), CSPFT_SOUND }, + {"putawaySoundPlayer", offsetof(WeaponDef, putawaySoundPlayer), CSPFT_SOUND }, + {"overheatSound", offsetof(WeaponDef, overheatSound), CSPFT_SOUND }, + {"overheatSoundPlayer", offsetof(WeaponDef, overheatSoundPlayer), CSPFT_SOUND }, + {"bounceSound", offsetof(WeaponDef, bounceSound), WFT_BOUNCE_SOUND }, + {"standMountedWeapdef", offsetof(WeaponDef, standMountedWeapdef), CSPFT_STRING }, + {"crouchMountedWeapdef", offsetof(WeaponDef, crouchMountedWeapdef), CSPFT_STRING }, + {"proneMountedWeapdef", offsetof(WeaponDef, proneMountedWeapdef), CSPFT_STRING }, + {"viewShellEjectEffect", offsetof(WeaponDef, viewShellEjectEffect), CSPFT_FX }, + {"worldShellEjectEffect", offsetof(WeaponDef, worldShellEjectEffect), CSPFT_FX }, + {"viewLastShotEjectEffect", offsetof(WeaponDef, viewLastShotEjectEffect), CSPFT_FX }, + {"worldLastShotEjectEffect", offsetof(WeaponDef, worldLastShotEjectEffect), CSPFT_FX }, + {"reticleCenter", offsetof(WeaponDef, reticleCenter), CSPFT_MATERIAL }, + {"reticleSide", offsetof(WeaponDef, reticleSide), CSPFT_MATERIAL }, + {"reticleCenterSize", offsetof(WeaponDef, iReticleCenterSize), CSPFT_INT }, + {"reticleSideSize", offsetof(WeaponDef, iReticleSideSize), CSPFT_INT }, + {"reticleMinOfs", offsetof(WeaponDef, iReticleMinOfs), CSPFT_INT }, + {"activeReticleType", offsetof(WeaponDef, activeReticleType), WFT_ACTIVE_RETICLE_TYPE }, + {"standMoveF", offsetof(WeaponDef, vStandMove[0]), CSPFT_FLOAT }, + {"standMoveR", offsetof(WeaponDef, vStandMove[1]), CSPFT_FLOAT }, + {"standMoveU", offsetof(WeaponDef, vStandMove[2]), CSPFT_FLOAT }, + {"standRotP", offsetof(WeaponDef, vStandRot[0]), CSPFT_FLOAT }, + {"standRotY", offsetof(WeaponDef, vStandRot[1]), CSPFT_FLOAT }, + {"standRotR", offsetof(WeaponDef, vStandRot[2]), CSPFT_FLOAT }, + {"duckedOfsF", offsetof(WeaponDef, vDuckedOfs[0]), CSPFT_FLOAT }, + {"duckedOfsR", offsetof(WeaponDef, vDuckedOfs[1]), CSPFT_FLOAT }, + {"duckedOfsU", offsetof(WeaponDef, vDuckedOfs[2]), CSPFT_FLOAT }, + {"duckedMoveF", offsetof(WeaponDef, vDuckedMove[0]), CSPFT_FLOAT }, + {"duckedMoveR", offsetof(WeaponDef, vDuckedMove[1]), CSPFT_FLOAT }, + {"duckedMoveU", offsetof(WeaponDef, vDuckedMove[2]), CSPFT_FLOAT }, + {"duckedSprintOfsF", offsetof(WeaponDef, duckedSprintOfs[0]), CSPFT_FLOAT }, + {"duckedSprintOfsR", offsetof(WeaponDef, duckedSprintOfs[1]), CSPFT_FLOAT }, + {"duckedSprintOfsU", offsetof(WeaponDef, duckedSprintOfs[2]), CSPFT_FLOAT }, + {"duckedSprintRotP", offsetof(WeaponDef, duckedSprintRot[0]), CSPFT_FLOAT }, + {"duckedSprintRotY", offsetof(WeaponDef, duckedSprintRot[1]), CSPFT_FLOAT }, + {"duckedSprintRotR", offsetof(WeaponDef, duckedSprintRot[2]), CSPFT_FLOAT }, + {"duckedSprintBobH", offsetof(WeaponDef, duckedSprintBob[0]), CSPFT_FLOAT }, + {"duckedSprintBobV", offsetof(WeaponDef, duckedSprintBob[1]), CSPFT_FLOAT }, + {"duckedSprintScale", offsetof(WeaponDef, duckedSprintScale), CSPFT_FLOAT }, + {"sprintOfsF", offsetof(WeaponDef, sprintOfs[0]), CSPFT_FLOAT }, + {"sprintOfsR", offsetof(WeaponDef, sprintOfs[1]), CSPFT_FLOAT }, + {"sprintOfsU", offsetof(WeaponDef, sprintOfs[2]), CSPFT_FLOAT }, + {"sprintRotP", offsetof(WeaponDef, sprintRot[0]), CSPFT_FLOAT }, + {"sprintRotY", offsetof(WeaponDef, sprintRot[1]), CSPFT_FLOAT }, + {"sprintRotR", offsetof(WeaponDef, sprintRot[2]), CSPFT_FLOAT }, + {"sprintBobH", offsetof(WeaponDef, sprintBob[0]), CSPFT_FLOAT }, + {"sprintBobV", offsetof(WeaponDef, sprintBob[1]), CSPFT_FLOAT }, + {"sprintScale", offsetof(WeaponDef, sprintScale), CSPFT_FLOAT }, + {"duckedRotP", offsetof(WeaponDef, vDuckedRot[0]), CSPFT_FLOAT }, + {"duckedRotY", offsetof(WeaponDef, vDuckedRot[1]), CSPFT_FLOAT }, + {"duckedRotR", offsetof(WeaponDef, vDuckedRot[2]), CSPFT_FLOAT }, + {"proneOfsF", offsetof(WeaponDef, vProneOfs[0]), CSPFT_FLOAT }, + {"proneOfsR", offsetof(WeaponDef, vProneOfs[1]), CSPFT_FLOAT }, + {"proneOfsU", offsetof(WeaponDef, vProneOfs[2]), CSPFT_FLOAT }, + {"proneMoveF", offsetof(WeaponDef, vProneMove[0]), CSPFT_FLOAT }, + {"proneMoveR", offsetof(WeaponDef, vProneMove[1]), CSPFT_FLOAT }, + {"proneMoveU", offsetof(WeaponDef, vProneMove[2]), CSPFT_FLOAT }, + {"proneRotP", offsetof(WeaponDef, vProneRot[0]), CSPFT_FLOAT }, + {"proneRotY", offsetof(WeaponDef, vProneRot[1]), CSPFT_FLOAT }, + {"proneRotR", offsetof(WeaponDef, vProneRot[2]), CSPFT_FLOAT }, + {"posMoveRate", offsetof(WeaponDef, fPosMoveRate), CSPFT_FLOAT }, + {"posProneMoveRate", offsetof(WeaponDef, fPosProneMoveRate), CSPFT_FLOAT }, + {"standMoveMinSpeed", offsetof(WeaponDef, fStandMoveMinSpeed), CSPFT_FLOAT }, + {"duckedMoveMinSpeed", offsetof(WeaponDef, fDuckedMoveMinSpeed), CSPFT_FLOAT }, + {"proneMoveMinSpeed", offsetof(WeaponDef, fProneMoveMinSpeed), CSPFT_FLOAT }, + {"posRotRate", offsetof(WeaponDef, fPosRotRate), CSPFT_FLOAT }, + {"posProneRotRate", offsetof(WeaponDef, fPosProneRotRate), CSPFT_FLOAT }, + {"standRotMinSpeed", offsetof(WeaponDef, fStandRotMinSpeed), CSPFT_FLOAT }, + {"duckedRotMinSpeed", offsetof(WeaponDef, fDuckedRotMinSpeed), CSPFT_FLOAT }, + {"proneRotMinSpeed", offsetof(WeaponDef, fProneRotMinSpeed), CSPFT_FLOAT }, + {"worldModel", offsetof(WeaponDef, worldModel[0]), CSPFT_XMODEL }, + {"worldModel2", offsetof(WeaponDef, worldModel[1]), CSPFT_XMODEL }, + {"worldModel3", offsetof(WeaponDef, worldModel[2]), CSPFT_XMODEL }, + {"worldModel4", offsetof(WeaponDef, worldModel[3]), CSPFT_XMODEL }, + {"worldModel5", offsetof(WeaponDef, worldModel[4]), CSPFT_XMODEL }, + {"worldModel6", offsetof(WeaponDef, worldModel[5]), CSPFT_XMODEL }, + {"worldModel7", offsetof(WeaponDef, worldModel[6]), CSPFT_XMODEL }, + {"worldModel8", offsetof(WeaponDef, worldModel[7]), CSPFT_XMODEL }, + {"worldModel9", offsetof(WeaponDef, worldModel[8]), CSPFT_XMODEL }, + {"worldModel10", offsetof(WeaponDef, worldModel[9]), CSPFT_XMODEL }, + {"worldModel11", offsetof(WeaponDef, worldModel[10]), CSPFT_XMODEL }, + {"worldModel12", offsetof(WeaponDef, worldModel[11]), CSPFT_XMODEL }, + {"worldModel13", offsetof(WeaponDef, worldModel[12]), CSPFT_XMODEL }, + {"worldModel14", offsetof(WeaponDef, worldModel[13]), CSPFT_XMODEL }, + {"worldModel15", offsetof(WeaponDef, worldModel[14]), CSPFT_XMODEL }, + {"worldModel16", offsetof(WeaponDef, worldModel[15]), CSPFT_XMODEL }, + {"worldClipModel", offsetof(WeaponDef, worldClipModel), CSPFT_XMODEL }, + {"rocketModel", offsetof(WeaponDef, rocketModel), CSPFT_XMODEL }, + {"knifeModel", offsetof(WeaponDef, knifeModel), CSPFT_XMODEL }, + {"worldKnifeModel", offsetof(WeaponDef, worldKnifeModel), CSPFT_XMODEL }, + {"mountedModel", offsetof(WeaponDef, mountedModel), CSPFT_XMODEL }, + {"hudIcon", offsetof(WeaponDef, hudIcon), CSPFT_MATERIAL }, + {"hudIconRatio", offsetof(WeaponDef, hudIconRatio), WFT_ICONRATIO_HUD }, + {"ammoCounterIcon", offsetof(WeaponDef, ammoCounterIcon), CSPFT_MATERIAL }, + {"ammoCounterIconRatio", offsetof(WeaponDef, ammoCounterIconRatio), WFT_ICONRATIO_AMMOCOUNTER}, + {"ammoCounterClip", offsetof(WeaponDef, ammoCounterClip), WFT_AMMOCOUNTER_CLIPTYPE }, + {"startAmmo", offsetof(WeaponDef, iStartAmmo), CSPFT_INT }, + {"ammoName", offsetof(WeaponDef, szAmmoName), CSPFT_STRING }, + {"clipName", offsetof(WeaponDef, szClipName), CSPFT_STRING }, + {"maxAmmo", offsetof(WeaponDef, iMaxAmmo), CSPFT_INT }, + {"clipSize", offsetof(WeaponDef, iClipSize), CSPFT_INT }, + {"shotCount", offsetof(WeaponDef, shotCount), CSPFT_INT }, + {"sharedAmmoCapName", offsetof(WeaponDef, szSharedAmmoCapName), CSPFT_STRING }, + {"sharedAmmoCap", offsetof(WeaponDef, iSharedAmmoCap), CSPFT_INT }, + {"unlimitedAmmo", offsetof(WeaponDef, unlimitedAmmo), CSPFT_INT }, + {"overheatWeapon", offsetof(WeaponDef, overheatWeapon), CSPFT_INT }, + {"overheatRate", offsetof(WeaponDef, overheatRate), CSPFT_FLOAT }, + {"cooldownRate", offsetof(WeaponDef, cooldownRate), CSPFT_FLOAT }, + {"overheatEndVal", offsetof(WeaponDef, overheatEndVal), CSPFT_FLOAT }, + {"coolWhileFiring", offsetof(WeaponDef, coolWhileFiring), CSPFT_INT }, + {"damage", offsetof(WeaponDef, damage), CSPFT_INT }, + {"damageDuration", offsetof(WeaponDef, damageDuration), CSPFT_FLOAT }, + {"damageInterval", offsetof(WeaponDef, damageInterval), CSPFT_FLOAT }, + {"playerDamage", offsetof(WeaponDef, playerDamage), CSPFT_INT }, + {"meleeDamage", offsetof(WeaponDef, iMeleeDamage), CSPFT_INT }, + {"minDamage", offsetof(WeaponDef, minDamage), CSPFT_INT }, + {"minPlayerDamage", offsetof(WeaponDef, minPlayerDamage), CSPFT_INT }, + {"maxDamageRange", offsetof(WeaponDef, fMaxDamageRange), CSPFT_FLOAT }, + {"minDamageRange", offsetof(WeaponDef, fMinDamageRange), CSPFT_FLOAT }, + {"destabilizationRateTime", offsetof(WeaponDef, destabilizationRateTime), CSPFT_FLOAT }, + {"destabilizationCurvatureMax", offsetof(WeaponDef, destabilizationCurvatureMax), CSPFT_FLOAT }, + {"destabilizeDistance", offsetof(WeaponDef, destabilizeDistance), CSPFT_INT }, + {"fireDelay", offsetof(WeaponDef, iFireDelay), CSPFT_MILLISECONDS }, + {"meleeDelay", offsetof(WeaponDef, iMeleeDelay), CSPFT_MILLISECONDS }, + {"meleeChargeDelay", offsetof(WeaponDef, meleeChargeDelay), CSPFT_MILLISECONDS }, + {"fireTime", offsetof(WeaponDef, iFireTime), CSPFT_MILLISECONDS }, + {"rechamberTime", offsetof(WeaponDef, iRechamberTime), CSPFT_MILLISECONDS }, + {"rechamberBoltTime", offsetof(WeaponDef, iRechamberBoltTime), CSPFT_MILLISECONDS }, + {"holdFireTime", offsetof(WeaponDef, iHoldFireTime), CSPFT_MILLISECONDS }, + {"detonateTime", offsetof(WeaponDef, iDetonateTime), CSPFT_MILLISECONDS }, + {"detonateDelay", offsetof(WeaponDef, iDetonateDelay), CSPFT_MILLISECONDS }, + {"meleeTime", offsetof(WeaponDef, iMeleeTime), CSPFT_MILLISECONDS }, + {"meleeChargeTime", offsetof(WeaponDef, meleeChargeTime), CSPFT_MILLISECONDS }, + {"reloadTime", offsetof(WeaponDef, iReloadTime), CSPFT_MILLISECONDS }, + {"reloadShowRocketTime", offsetof(WeaponDef, reloadShowRocketTime), CSPFT_MILLISECONDS }, + {"reloadEmptyTime", offsetof(WeaponDef, iReloadEmptyTime), CSPFT_MILLISECONDS }, + {"reloadAddTime", offsetof(WeaponDef, iReloadAddTime), CSPFT_MILLISECONDS }, + {"reloadEmptyAddTime", offsetof(WeaponDef, reloadEmptyAddTime), CSPFT_MILLISECONDS }, + {"reloadStartTime", offsetof(WeaponDef, iReloadStartTime), CSPFT_MILLISECONDS }, + {"reloadStartAddTime", offsetof(WeaponDef, iReloadStartAddTime), CSPFT_MILLISECONDS }, + {"reloadEndTime", offsetof(WeaponDef, iReloadEndTime), CSPFT_MILLISECONDS }, + {"dropTime", offsetof(WeaponDef, iDropTime), CSPFT_MILLISECONDS }, + {"raiseTime", offsetof(WeaponDef, iRaiseTime), CSPFT_MILLISECONDS }, + {"altDropTime", offsetof(WeaponDef, iAltDropTime), CSPFT_MILLISECONDS }, + {"altRaiseTime", offsetof(WeaponDef, iAltRaiseTime), CSPFT_MILLISECONDS }, + {"quickDropTime", offsetof(WeaponDef, quickDropTime), CSPFT_MILLISECONDS }, + {"quickRaiseTime", offsetof(WeaponDef, quickRaiseTime), CSPFT_MILLISECONDS }, + {"firstRaiseTime", offsetof(WeaponDef, iFirstRaiseTime), CSPFT_MILLISECONDS }, + {"emptyRaiseTime", offsetof(WeaponDef, iEmptyRaiseTime), CSPFT_MILLISECONDS }, + {"emptyDropTime", offsetof(WeaponDef, iEmptyDropTime), CSPFT_MILLISECONDS }, + {"sprintInTime", offsetof(WeaponDef, sprintInTime), CSPFT_MILLISECONDS }, + {"sprintLoopTime", offsetof(WeaponDef, sprintLoopTime), CSPFT_MILLISECONDS }, + {"sprintOutTime", offsetof(WeaponDef, sprintOutTime), CSPFT_MILLISECONDS }, + {"deployTime", offsetof(WeaponDef, deployTime), CSPFT_MILLISECONDS }, + {"breakdownTime", offsetof(WeaponDef, breakdownTime), CSPFT_MILLISECONDS }, + {"nightVisionWearTime", offsetof(WeaponDef, nightVisionWearTime), CSPFT_MILLISECONDS }, + {"nightVisionWearTimeFadeOutEnd", offsetof(WeaponDef, nightVisionWearTimeFadeOutEnd), CSPFT_MILLISECONDS }, + {"nightVisionWearTimePowerUp", offsetof(WeaponDef, nightVisionWearTimePowerUp), CSPFT_MILLISECONDS }, + {"nightVisionRemoveTime", offsetof(WeaponDef, nightVisionRemoveTime), CSPFT_MILLISECONDS }, + {"nightVisionRemoveTimePowerDown", offsetof(WeaponDef, nightVisionRemoveTimePowerDown), CSPFT_MILLISECONDS }, + {"nightVisionRemoveTimeFadeInStart", offsetof(WeaponDef, nightVisionRemoveTimeFadeInStart), CSPFT_MILLISECONDS }, + {"fuseTime", offsetof(WeaponDef, fuseTime), CSPFT_MILLISECONDS }, + {"aifuseTime", offsetof(WeaponDef, aiFuseTime), CSPFT_MILLISECONDS }, + {"requireLockonToFire", offsetof(WeaponDef, requireLockonToFire), CSPFT_BOOL }, + {"noAdsWhenMagEmpty", offsetof(WeaponDef, noAdsWhenMagEmpty), CSPFT_BOOL }, + {"avoidDropCleanup", offsetof(WeaponDef, avoidDropCleanup), CSPFT_BOOL }, + {"autoAimRange", offsetof(WeaponDef, autoAimRange), CSPFT_FLOAT }, + {"aimAssistRange", offsetof(WeaponDef, aimAssistRange), CSPFT_FLOAT }, + {"aimAssistRangeAds", offsetof(WeaponDef, aimAssistRangeAds), CSPFT_FLOAT }, + {"mountableWeapon", offsetof(WeaponDef, mountableWeapon), CSPFT_BOOL }, + {"aimPadding", offsetof(WeaponDef, aimPadding), CSPFT_FLOAT }, + {"enemyCrosshairRange", offsetof(WeaponDef, enemyCrosshairRange), CSPFT_FLOAT }, + {"crosshairColorChange", offsetof(WeaponDef, crosshairColorChange), CSPFT_BOOL }, + {"moveSpeedScale", offsetof(WeaponDef, moveSpeedScale), CSPFT_FLOAT }, + {"adsMoveSpeedScale", offsetof(WeaponDef, adsMoveSpeedScale), CSPFT_FLOAT }, + {"sprintDurationScale", offsetof(WeaponDef, sprintDurationScale), CSPFT_FLOAT }, + {"idleCrouchFactor", offsetof(WeaponDef, fIdleCrouchFactor), CSPFT_FLOAT }, + {"idleProneFactor", offsetof(WeaponDef, fIdleProneFactor), CSPFT_FLOAT }, + {"gunMaxPitch", offsetof(WeaponDef, fGunMaxPitch), CSPFT_FLOAT }, + {"gunMaxYaw", offsetof(WeaponDef, fGunMaxYaw), CSPFT_FLOAT }, + {"swayMaxAngle", offsetof(WeaponDef, swayMaxAngle), CSPFT_FLOAT }, + {"swayLerpSpeed", offsetof(WeaponDef, swayLerpSpeed), CSPFT_FLOAT }, + {"swayPitchScale", offsetof(WeaponDef, swayPitchScale), CSPFT_FLOAT }, + {"swayYawScale", offsetof(WeaponDef, swayYawScale), CSPFT_FLOAT }, + {"swayHorizScale", offsetof(WeaponDef, swayHorizScale), CSPFT_FLOAT }, + {"swayVertScale", offsetof(WeaponDef, swayVertScale), CSPFT_FLOAT }, + {"swayShellShockScale", offsetof(WeaponDef, swayShellShockScale), CSPFT_FLOAT }, + {"adsSwayMaxAngle", offsetof(WeaponDef, adsSwayMaxAngle), CSPFT_FLOAT }, + {"adsSwayLerpSpeed", offsetof(WeaponDef, adsSwayLerpSpeed), CSPFT_FLOAT }, + {"adsSwayPitchScale", offsetof(WeaponDef, adsSwayPitchScale), CSPFT_FLOAT }, + {"adsSwayYawScale", offsetof(WeaponDef, adsSwayYawScale), CSPFT_FLOAT }, + {"adsSwayHorizScale", offsetof(WeaponDef, adsSwayHorizScale), CSPFT_FLOAT }, + {"adsSwayVertScale", offsetof(WeaponDef, adsSwayVertScale), CSPFT_FLOAT }, + {"rifleBullet", offsetof(WeaponDef, bRifleBullet), CSPFT_BOOL }, + {"armorPiercing", offsetof(WeaponDef, armorPiercing), CSPFT_BOOL }, + {"boltAction", offsetof(WeaponDef, bBoltAction), CSPFT_BOOL }, + {"aimDownSight", offsetof(WeaponDef, aimDownSight), CSPFT_BOOL }, + {"rechamberWhileAds", offsetof(WeaponDef, bRechamberWhileAds), CSPFT_BOOL }, + {"adsViewErrorMin", offsetof(WeaponDef, adsViewErrorMin), CSPFT_FLOAT }, + {"adsViewErrorMax", offsetof(WeaponDef, adsViewErrorMax), CSPFT_FLOAT }, + {"clipOnly", offsetof(WeaponDef, bClipOnly), CSPFT_BOOL }, + {"canUseInVehicle", offsetof(WeaponDef, canUseInVehicle), CSPFT_BOOL }, + {"noDropsOrRaises", offsetof(WeaponDef, noDropsOrRaises), CSPFT_BOOL }, + {"cookOffHold", offsetof(WeaponDef, bCookOffHold), CSPFT_BOOL }, + {"adsFire", offsetof(WeaponDef, adsFireOnly), CSPFT_BOOL }, + {"cancelAutoHolsterWhenEmpty", offsetof(WeaponDef, cancelAutoHolsterWhenEmpty), CSPFT_BOOL }, + {"suppressAmmoReserveDisplay", offsetof(WeaponDef, suppressAmmoReserveDisplay), CSPFT_BOOL }, + {"enhanced", offsetof(WeaponDef, enhanced), CSPFT_BOOL }, + {"laserSightDuringNightvision", offsetof(WeaponDef, laserSightDuringNightvision), CSPFT_BOOL }, + {"bayonet", offsetof(WeaponDef, bayonet), CSPFT_BOOL }, + {"killIcon", offsetof(WeaponDef, killIcon), CSPFT_MATERIAL }, + {"killIconRatio", offsetof(WeaponDef, killIconRatio), WFT_ICONRATIO_KILL }, + {"flipKillIcon", offsetof(WeaponDef, flipKillIcon), CSPFT_BOOL }, + {"dpadIcon", offsetof(WeaponDef, dpadIcon), CSPFT_MATERIAL }, + {"dpadIconRatio", offsetof(WeaponDef, dpadIconRatio), WFT_ICONRATIO_DPAD }, + {"noPartialReload", offsetof(WeaponDef, bNoPartialReload), CSPFT_BOOL }, + {"segmentedReload", offsetof(WeaponDef, bSegmentedReload), CSPFT_BOOL }, + {"noADSAutoReload", offsetof(WeaponDef, noADSAutoReload), CSPFT_BOOL }, + {"reloadAmmoAdd", offsetof(WeaponDef, iReloadAmmoAdd), CSPFT_INT }, + {"reloadStartAdd", offsetof(WeaponDef, iReloadStartAdd), CSPFT_INT }, + {"altWeapon", offsetof(WeaponDef, szAltWeaponName), CSPFT_STRING }, + {"dropAmmoMin", offsetof(WeaponDef, iDropAmmoMin), CSPFT_INT }, + {"dropAmmoMax", offsetof(WeaponDef, iDropAmmoMax), CSPFT_INT }, + {"blocksProne", offsetof(WeaponDef, blocksProne), CSPFT_BOOL }, + {"silenced", offsetof(WeaponDef, silenced), CSPFT_BOOL }, + {"explosionRadius", offsetof(WeaponDef, iExplosionRadius), CSPFT_INT }, + {"explosionRadiusMin", offsetof(WeaponDef, iExplosionRadiusMin), CSPFT_INT }, + {"explosionInnerDamage", offsetof(WeaponDef, iExplosionInnerDamage), CSPFT_INT }, + {"explosionOuterDamage", offsetof(WeaponDef, iExplosionOuterDamage), CSPFT_INT }, + {"damageConeAngle", offsetof(WeaponDef, damageConeAngle), CSPFT_FLOAT }, + {"projectileSpeed", offsetof(WeaponDef, iProjectileSpeed), CSPFT_INT }, + {"projectileSpeedUp", offsetof(WeaponDef, iProjectileSpeedUp), CSPFT_INT }, + {"projectileSpeedForward", offsetof(WeaponDef, iProjectileSpeedForward), CSPFT_INT }, + {"projectileActivateDist", offsetof(WeaponDef, iProjectileActivateDist), CSPFT_INT }, + {"projectileLifetime", offsetof(WeaponDef, projLifetime), CSPFT_FLOAT }, + {"timeToAccelerate", offsetof(WeaponDef, timeToAccelerate), CSPFT_FLOAT }, + {"projectileCurvature", offsetof(WeaponDef, projectileCurvature), CSPFT_FLOAT }, + {"projectileModel", offsetof(WeaponDef, projectileModel), CSPFT_XMODEL }, + {"projExplosionType", offsetof(WeaponDef, projExplosion), WFT_PROJ_EXPLOSION }, + {"projExplosionEffect", offsetof(WeaponDef, projExplosionEffect), CSPFT_FX }, + {"projExplosionEffectForceNormalUp", offsetof(WeaponDef, projExplosionEffectForceNormalUp), CSPFT_BOOL }, + {"projExplosionSound", offsetof(WeaponDef, projExplosionSound), CSPFT_SOUND }, + {"projDudEffect", offsetof(WeaponDef, projDudEffect), CSPFT_FX }, + {"projDudSound", offsetof(WeaponDef, projDudSound), CSPFT_SOUND }, + {"projImpactExplode", offsetof(WeaponDef, bProjImpactExplode), CSPFT_BOOL }, + {"mortarShellSound", offsetof(WeaponDef, mortarShellSound), CSPFT_SOUND }, + {"tankShellSound", offsetof(WeaponDef, tankShellSound), CSPFT_SOUND }, + {"stickiness", offsetof(WeaponDef, stickiness), WFT_STICKINESS }, + {"hasDetonator", offsetof(WeaponDef, hasDetonator), CSPFT_BOOL }, + {"timedDetonation", offsetof(WeaponDef, timedDetonation), CSPFT_BOOL }, + {"rotate", offsetof(WeaponDef, rotate), CSPFT_BOOL }, + {"holdButtonToThrow", offsetof(WeaponDef, holdButtonToThrow), CSPFT_BOOL }, + {"freezeMovementWhenFiring", offsetof(WeaponDef, freezeMovementWhenFiring), CSPFT_BOOL }, + {"lowAmmoWarningThreshold", offsetof(WeaponDef, lowAmmoWarningThreshold), CSPFT_FLOAT }, + {"parallelDefaultBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_DEFAULT]), CSPFT_FLOAT }, + {"parallelBarkBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_BARK]), CSPFT_FLOAT }, + {"parallelBrickBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_BRICK]), CSPFT_FLOAT }, + {"parallelCarpetBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_CARPET]), CSPFT_FLOAT }, + {"parallelClothBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_CLOTH]), CSPFT_FLOAT }, + {"parallelConcreteBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_CONCRETE]), CSPFT_FLOAT }, + {"parallelDirtBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_DIRT]), CSPFT_FLOAT }, + {"parallelFleshBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_FLESH]), CSPFT_FLOAT }, + {"parallelFoliageBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_FOLIAGE]), CSPFT_FLOAT }, + {"parallelGlassBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_GLASS]), CSPFT_FLOAT }, + {"parallelGrassBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_GRASS]), CSPFT_FLOAT }, + {"parallelGravelBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_GRAVEL]), CSPFT_FLOAT }, + {"parallelIceBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_ICE]), CSPFT_FLOAT }, + {"parallelMetalBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_METAL]), CSPFT_FLOAT }, + {"parallelMudBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_MUD]), CSPFT_FLOAT }, + {"parallelPaperBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_PAPER]), CSPFT_FLOAT }, + {"parallelPlasterBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_PLASTER]), CSPFT_FLOAT }, + {"parallelRockBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_ROCK]), CSPFT_FLOAT }, + {"parallelSandBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_SAND]), CSPFT_FLOAT }, + {"parallelSnowBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_SNOW]), CSPFT_FLOAT }, + {"parallelWaterBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_WATER]), CSPFT_FLOAT }, + {"parallelWoodBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_WOOD]), CSPFT_FLOAT }, + {"parallelAsphaltBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_ASPHALT]), CSPFT_FLOAT }, + {"parallelCeramicBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_CERAMIC]), CSPFT_FLOAT }, + {"parallelPlasticBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_PLASTIC]), CSPFT_FLOAT }, + {"parallelRubberBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_RUBBER]), CSPFT_FLOAT }, + {"parallelCushionBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_CUSHION]), CSPFT_FLOAT }, + {"parallelFruitBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_FRUIT]), CSPFT_FLOAT }, + {"parallelPaintedMetalBounce", offsetof(WeaponDef, parallelBounce[SURF_TYPE_PAINTED_METAL]), CSPFT_FLOAT }, + {"perpendicularDefaultBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_DEFAULT]), CSPFT_FLOAT }, + {"perpendicularBarkBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_BARK]), CSPFT_FLOAT }, + {"perpendicularBrickBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_BRICK]), CSPFT_FLOAT }, + {"perpendicularCarpetBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_CARPET]), CSPFT_FLOAT }, + {"perpendicularClothBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_CLOTH]), CSPFT_FLOAT }, + {"perpendicularConcreteBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_CONCRETE]), CSPFT_FLOAT }, + {"perpendicularDirtBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_DIRT]), CSPFT_FLOAT }, + {"perpendicularFleshBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_FLESH]), CSPFT_FLOAT }, + {"perpendicularFoliageBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_FOLIAGE]), CSPFT_FLOAT }, + {"perpendicularGlassBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_GLASS]), CSPFT_FLOAT }, + {"perpendicularGrassBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_GRASS]), CSPFT_FLOAT }, + {"perpendicularGravelBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_GRAVEL]), CSPFT_FLOAT }, + {"perpendicularIceBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_ICE]), CSPFT_FLOAT }, + {"perpendicularMetalBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_METAL]), CSPFT_FLOAT }, + {"perpendicularMudBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_MUD]), CSPFT_FLOAT }, + {"perpendicularPaperBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_PAPER]), CSPFT_FLOAT }, + {"perpendicularPlasterBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_PLASTER]), CSPFT_FLOAT }, + {"perpendicularRockBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_ROCK]), CSPFT_FLOAT }, + {"perpendicularSandBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_SAND]), CSPFT_FLOAT }, + {"perpendicularSnowBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_SNOW]), CSPFT_FLOAT }, + {"perpendicularWaterBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_WATER]), CSPFT_FLOAT }, + {"perpendicularWoodBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_WOOD]), CSPFT_FLOAT }, + {"perpendicularAsphaltBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_ASPHALT]), CSPFT_FLOAT }, + {"perpendicularCeramicBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_CERAMIC]), CSPFT_FLOAT }, + {"perpendicularPlasticBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_PLASTIC]), CSPFT_FLOAT }, + {"perpendicularRubberBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_RUBBER]), CSPFT_FLOAT }, + {"perpendicularCushionBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_CUSHION]), CSPFT_FLOAT }, + {"perpendicularFruitBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_FRUIT]), CSPFT_FLOAT }, + {"perpendicularPaintedMetalBounce", offsetof(WeaponDef, perpendicularBounce[SURF_TYPE_PAINTED_METAL]), CSPFT_FLOAT }, + {"projTrailEffect", offsetof(WeaponDef, projTrailEffect), CSPFT_FX }, + {"projectileRed", offsetof(WeaponDef, vProjectileColor[0]), CSPFT_FLOAT }, + {"projectileGreen", offsetof(WeaponDef, vProjectileColor[1]), CSPFT_FLOAT }, + {"projectileBlue", offsetof(WeaponDef, vProjectileColor[2]), CSPFT_FLOAT }, + {"guidedMissileType", offsetof(WeaponDef, guidedMissileType), WFT_GUIDED_MISSILE_TYPE }, + {"maxSteeringAccel", offsetof(WeaponDef, maxSteeringAccel), CSPFT_FLOAT }, + {"projIgnitionDelay", offsetof(WeaponDef, projIgnitionDelay), CSPFT_INT }, + {"projIgnitionEffect", offsetof(WeaponDef, projIgnitionEffect), CSPFT_FX }, + {"projIgnitionSound", offsetof(WeaponDef, projIgnitionSound), CSPFT_SOUND }, + {"tagFx_preparationEffect", offsetof(WeaponDef, tagFx_preparationEffect), CSPFT_FX }, + {"tagFlash_preparationEffect", offsetof(WeaponDef, tagFlash_preparationEffect), CSPFT_FX }, + {"adsTransInTime", offsetof(WeaponDef, iAdsTransInTime), CSPFT_MILLISECONDS }, + {"adsTransOutTime", offsetof(WeaponDef, iAdsTransOutTime), CSPFT_MILLISECONDS }, + {"adsIdleAmount", offsetof(WeaponDef, fAdsIdleAmount), CSPFT_FLOAT }, + {"adsIdleSpeed", offsetof(WeaponDef, adsIdleSpeed), CSPFT_FLOAT }, + {"adsZoomFov", offsetof(WeaponDef, fAdsZoomFov), CSPFT_FLOAT }, + {"adsZoomInFrac", offsetof(WeaponDef, fAdsZoomInFrac), CSPFT_FLOAT }, + {"adsZoomOutFrac", offsetof(WeaponDef, fAdsZoomOutFrac), CSPFT_FLOAT }, + {"adsOverlayShader", offsetof(WeaponDef, overlayMaterial), CSPFT_MATERIAL }, + {"adsOverlayShaderLowRes", offsetof(WeaponDef, overlayMaterialLowRes), CSPFT_MATERIAL }, + {"adsOverlayReticle", offsetof(WeaponDef, overlayReticle), WFT_OVERLAYRETICLE }, + {"adsOverlayInterface", offsetof(WeaponDef, overlayInterface), WFT_OVERLAYINTERFACE }, + {"adsOverlayWidth", offsetof(WeaponDef, overlayWidth), CSPFT_FLOAT }, + {"adsOverlayHeight", offsetof(WeaponDef, overlayHeight), CSPFT_FLOAT }, + {"adsBobFactor", offsetof(WeaponDef, fAdsBobFactor), CSPFT_FLOAT }, + {"adsViewBobMult", offsetof(WeaponDef, fAdsViewBobMult), CSPFT_FLOAT }, + {"adsAimPitch", offsetof(WeaponDef, fAdsAimPitch), CSPFT_FLOAT }, + {"adsCrosshairInFrac", offsetof(WeaponDef, fAdsCrosshairInFrac), CSPFT_FLOAT }, + {"adsCrosshairOutFrac", offsetof(WeaponDef, fAdsCrosshairOutFrac), CSPFT_FLOAT }, + {"adsReloadTransTime", offsetof(WeaponDef, iPositionReloadTransTime), CSPFT_MILLISECONDS }, + {"adsGunKickReducedKickBullets", offsetof(WeaponDef, adsGunKickReducedKickBullets), CSPFT_INT }, + {"adsGunKickReducedKickPercent", offsetof(WeaponDef, adsGunKickReducedKickPercent), CSPFT_FLOAT }, + {"adsGunKickPitchMin", offsetof(WeaponDef, fAdsGunKickPitchMin), CSPFT_FLOAT }, + {"adsGunKickPitchMax", offsetof(WeaponDef, fAdsGunKickPitchMax), CSPFT_FLOAT }, + {"adsGunKickYawMin", offsetof(WeaponDef, fAdsGunKickYawMin), CSPFT_FLOAT }, + {"adsGunKickYawMax", offsetof(WeaponDef, fAdsGunKickYawMax), CSPFT_FLOAT }, + {"adsGunKickAccel", offsetof(WeaponDef, fAdsGunKickAccel), CSPFT_FLOAT }, + {"adsGunKickSpeedMax", offsetof(WeaponDef, fAdsGunKickSpeedMax), CSPFT_FLOAT }, + {"adsGunKickSpeedDecay", offsetof(WeaponDef, fAdsGunKickSpeedDecay), CSPFT_FLOAT }, + {"adsGunKickStaticDecay", offsetof(WeaponDef, fAdsGunKickStaticDecay), CSPFT_FLOAT }, + {"adsViewKickPitchMin", offsetof(WeaponDef, fAdsViewKickPitchMin), CSPFT_FLOAT }, + {"adsViewKickPitchMax", offsetof(WeaponDef, fAdsViewKickPitchMax), CSPFT_FLOAT }, + {"adsViewKickYawMin", offsetof(WeaponDef, fAdsViewKickYawMin), CSPFT_FLOAT }, + {"adsViewKickYawMax", offsetof(WeaponDef, fAdsViewKickYawMax), CSPFT_FLOAT }, + {"adsViewKickCenterSpeed", offsetof(WeaponDef, fAdsViewKickCenterSpeed), CSPFT_FLOAT }, + {"adsSpread", offsetof(WeaponDef, fAdsSpread), CSPFT_FLOAT }, + {"hipSpreadStandMin", offsetof(WeaponDef, fHipSpreadStandMin), CSPFT_FLOAT }, + {"hipSpreadDuckedMin", offsetof(WeaponDef, fHipSpreadDuckedMin), CSPFT_FLOAT }, + {"hipSpreadProneMin", offsetof(WeaponDef, fHipSpreadProneMin), CSPFT_FLOAT }, + {"hipSpreadMax", offsetof(WeaponDef, hipSpreadStandMax), CSPFT_FLOAT }, + {"hipSpreadDuckedMax", offsetof(WeaponDef, hipSpreadDuckedMax), CSPFT_FLOAT }, + {"hipSpreadProneMax", offsetof(WeaponDef, hipSpreadProneMax), CSPFT_FLOAT }, + {"hipSpreadDecayRate", offsetof(WeaponDef, fHipSpreadDecayRate), CSPFT_FLOAT }, + {"hipSpreadFireAdd", offsetof(WeaponDef, fHipSpreadFireAdd), CSPFT_FLOAT }, + {"hipSpreadTurnAdd", offsetof(WeaponDef, fHipSpreadTurnAdd), CSPFT_FLOAT }, + {"hipSpreadMoveAdd", offsetof(WeaponDef, fHipSpreadMoveAdd), CSPFT_FLOAT }, + {"hipSpreadDuckedDecay", offsetof(WeaponDef, fHipSpreadDuckedDecay), CSPFT_FLOAT }, + {"hipSpreadProneDecay", offsetof(WeaponDef, fHipSpreadProneDecay), CSPFT_FLOAT }, + {"hipReticleSidePos", offsetof(WeaponDef, fHipReticleSidePos), CSPFT_FLOAT }, + {"hipIdleAmount", offsetof(WeaponDef, fHipIdleAmount), CSPFT_FLOAT }, + {"hipIdleSpeed", offsetof(WeaponDef, hipIdleSpeed), CSPFT_FLOAT }, + {"hipGunKickReducedKickBullets", offsetof(WeaponDef, hipGunKickReducedKickBullets), CSPFT_INT }, + {"hipGunKickReducedKickPercent", offsetof(WeaponDef, hipGunKickReducedKickPercent), CSPFT_FLOAT }, + {"hipGunKickPitchMin", offsetof(WeaponDef, fHipGunKickPitchMin), CSPFT_FLOAT }, + {"hipGunKickPitchMax", offsetof(WeaponDef, fHipGunKickPitchMax), CSPFT_FLOAT }, + {"hipGunKickYawMin", offsetof(WeaponDef, fHipGunKickYawMin), CSPFT_FLOAT }, + {"hipGunKickYawMax", offsetof(WeaponDef, fHipGunKickYawMax), CSPFT_FLOAT }, + {"hipGunKickAccel", offsetof(WeaponDef, fHipGunKickAccel), CSPFT_FLOAT }, + {"hipGunKickSpeedMax", offsetof(WeaponDef, fHipGunKickSpeedMax), CSPFT_FLOAT }, + {"hipGunKickSpeedDecay", offsetof(WeaponDef, fHipGunKickSpeedDecay), CSPFT_FLOAT }, + {"hipGunKickStaticDecay", offsetof(WeaponDef, fHipGunKickStaticDecay), CSPFT_FLOAT }, + {"hipViewKickPitchMin", offsetof(WeaponDef, fHipViewKickPitchMin), CSPFT_FLOAT }, + {"hipViewKickPitchMax", offsetof(WeaponDef, fHipViewKickPitchMax), CSPFT_FLOAT }, + {"hipViewKickYawMin", offsetof(WeaponDef, fHipViewKickYawMin), CSPFT_FLOAT }, + {"hipViewKickYawMax", offsetof(WeaponDef, fHipViewKickYawMax), CSPFT_FLOAT }, + {"hipViewKickCenterSpeed", offsetof(WeaponDef, fHipViewKickCenterSpeed), CSPFT_FLOAT }, + {"leftArc", offsetof(WeaponDef, leftArc), CSPFT_FLOAT }, + {"rightArc", offsetof(WeaponDef, rightArc), CSPFT_FLOAT }, + {"topArc", offsetof(WeaponDef, topArc), CSPFT_FLOAT }, + {"bottomArc", offsetof(WeaponDef, bottomArc), CSPFT_FLOAT }, + {"accuracy", offsetof(WeaponDef, accuracy), CSPFT_FLOAT }, + {"aiSpread", offsetof(WeaponDef, aiSpread), CSPFT_FLOAT }, + {"playerSpread", offsetof(WeaponDef, playerSpread), CSPFT_FLOAT }, + {"maxVertTurnSpeed", offsetof(WeaponDef, maxTurnSpeed[0]), CSPFT_FLOAT }, + {"maxHorTurnSpeed", offsetof(WeaponDef, maxTurnSpeed[1]), CSPFT_FLOAT }, + {"minVertTurnSpeed", offsetof(WeaponDef, minTurnSpeed[0]), CSPFT_FLOAT }, + {"minHorTurnSpeed", offsetof(WeaponDef, minTurnSpeed[1]), CSPFT_FLOAT }, + {"pitchConvergenceTime", offsetof(WeaponDef, pitchConvergenceTime), CSPFT_FLOAT }, + {"yawConvergenceTime", offsetof(WeaponDef, yawConvergenceTime), CSPFT_FLOAT }, + {"suppressionTime", offsetof(WeaponDef, suppressTime), CSPFT_FLOAT }, + {"maxRange", offsetof(WeaponDef, maxRange), CSPFT_FLOAT }, + {"animHorRotateInc", offsetof(WeaponDef, fAnimHorRotateInc), CSPFT_FLOAT }, + {"playerPositionDist", offsetof(WeaponDef, fPlayerPositionDist), CSPFT_FLOAT }, + {"stance", offsetof(WeaponDef, stance), WFT_STANCE }, + {"useHintString", offsetof(WeaponDef, szUseHintString), CSPFT_STRING }, + {"dropHintString", offsetof(WeaponDef, dropHintString), CSPFT_STRING }, + {"horizViewJitter", offsetof(WeaponDef, horizViewJitter), CSPFT_FLOAT }, + {"vertViewJitter", offsetof(WeaponDef, vertViewJitter), CSPFT_FLOAT }, + {"fightDist", offsetof(WeaponDef, fightDist), CSPFT_FLOAT }, + {"maxDist", offsetof(WeaponDef, maxDist), CSPFT_FLOAT }, + {"aiVsAiAccuracyGraph", offsetof(WeaponDef, aiVsAiAccuracyGraphName), CSPFT_STRING }, + {"aiVsPlayerAccuracyGraph", offsetof(WeaponDef, aiVsPlayerAccuracyGraphName), CSPFT_STRING }, + {"locNone", offsetof(WeaponDef, locationDamageMultipliers[HITLOC_NONE]), CSPFT_FLOAT }, + {"locHelmet", offsetof(WeaponDef, locationDamageMultipliers[HITLOC_HELMET]), CSPFT_FLOAT }, + {"locHead", offsetof(WeaponDef, locationDamageMultipliers[HITLOC_HEAD]), CSPFT_FLOAT }, + {"locNeck", offsetof(WeaponDef, locationDamageMultipliers[HITLOC_NECK]), CSPFT_FLOAT }, + {"locTorsoUpper", offsetof(WeaponDef, locationDamageMultipliers[HITLOC_TORSO_UPR]), CSPFT_FLOAT }, + {"locTorsoLower", offsetof(WeaponDef, locationDamageMultipliers[HITLOC_TORSO_LWR]), CSPFT_FLOAT }, + {"locRightArmUpper", offsetof(WeaponDef, locationDamageMultipliers[HITLOC_R_ARM_UPR]), CSPFT_FLOAT }, + {"locRightArmLower", offsetof(WeaponDef, locationDamageMultipliers[HITLOC_R_ARM_LWR]), CSPFT_FLOAT }, + {"locRightHand", offsetof(WeaponDef, locationDamageMultipliers[HITLOC_R_HAND]), CSPFT_FLOAT }, + {"locLeftArmUpper", offsetof(WeaponDef, locationDamageMultipliers[HITLOC_L_ARM_UPR]), CSPFT_FLOAT }, + {"locLeftArmLower", offsetof(WeaponDef, locationDamageMultipliers[HITLOC_L_ARM_LWR]), CSPFT_FLOAT }, + {"locLeftHand", offsetof(WeaponDef, locationDamageMultipliers[HITLOC_L_HAND]), CSPFT_FLOAT }, + {"locRightLegUpper", offsetof(WeaponDef, locationDamageMultipliers[HITLOC_R_LEG_UPR]), CSPFT_FLOAT }, + {"locRightLegLower", offsetof(WeaponDef, locationDamageMultipliers[HITLOC_R_LEG_LWR]), CSPFT_FLOAT }, + {"locRightFoot", offsetof(WeaponDef, locationDamageMultipliers[HITLOC_R_FOOT]), CSPFT_FLOAT }, + {"locLeftLegUpper", offsetof(WeaponDef, locationDamageMultipliers[HITLOC_L_LEG_UPR]), CSPFT_FLOAT }, + {"locLeftLegLower", offsetof(WeaponDef, locationDamageMultipliers[HITLOC_L_LEG_LWR]), CSPFT_FLOAT }, + {"locLeftFoot", offsetof(WeaponDef, locationDamageMultipliers[HITLOC_L_FOOT]), CSPFT_FLOAT }, + {"locGun", offsetof(WeaponDef, locationDamageMultipliers[HITLOC_GUN]), CSPFT_FLOAT }, + {"fireRumble", offsetof(WeaponDef, fireRumble), CSPFT_STRING }, + {"meleeImpactRumble", offsetof(WeaponDef, meleeImpactRumble), CSPFT_STRING }, + {"adsDofStart", offsetof(WeaponDef, adsDofStart), CSPFT_FLOAT }, + {"adsDofEnd", offsetof(WeaponDef, adsDofEnd), CSPFT_FLOAT }, + {"flameTableFirstPerson", offsetof(WeaponDef, flameTableFirstPerson), CSPFT_STRING }, + {"flameTableThirdPerson", offsetof(WeaponDef, flameTableThirdPerson), CSPFT_STRING }, + }; +} // namespace T4 diff --git a/src/ObjCommon/Game/T4/Weapon/WeaponStrings.h b/src/ObjCommon/Game/T4/Weapon/WeaponStrings.h new file mode 100644 index 00000000..0e9f3822 --- /dev/null +++ b/src/ObjCommon/Game/T4/Weapon/WeaponStrings.h @@ -0,0 +1,181 @@ +#pragma once + +#include "Game/T4/T4.h" + +#include + +namespace T4 +{ + inline const char* szWeapTypeNames[]{ + "bullet", + "grenade", + "projectile", + "binoculars", + "gas", + "bomb", + "mine", + }; + static_assert(std::extent_v == WEAPTYPE_NUM); + + inline const char* szWeapClassNames[]{ + "rifle", + "mg", + "smg", + "spread", + "pistol", + "grenade", + "rocketlauncher", + "turret", + "non-player", + "gas", + "item", + }; + 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", + "shotgun", + "grenade_bounce", + "grenade_explode", + "rifle_grenade", + "rocket_explode", + "projectile_dud", + "mortar_shell", + "tank_shell", + }; + 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", + }; + static_assert(std::extent_v == WEAPPROJEXP_NUM); + + inline const char* offhandClassNames[]{ + "None", + "Frag Grenade", + "Smoke Grenade", + "Flash Grenade", + }; + static_assert(std::extent_v == OFFHAND_CLASS_NUM); + + // mp/playeranimtypes.txt + inline const char* playerAnimTypeNames[]{ + "none", "other", "pistol", "smg", "autorifle", "mg", "sniper", "rocketlauncher", "explosive", "grenade", + "turret", "c4", "m203", "hold", "briefcase", "gas", "revivee", "reviver", "radio", + }; + + 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", + }; + static_assert(std::extent_v == MISSILE_GUIDANCE_NUM); + + inline const char* stickinessNames[]{ + "Don't stick", + "Stick to all", + "Stick to ground", + "Stick to ground, maintain yaw", + }; + static_assert(std::extent_v == WEAPSTICKINESS_NUM); + + inline const char* overlayInterfaceNames[]{ + "None", + "Javelin", + "Turret Scope", + }; + static_assert(std::extent_v == WEAPOVERLAYINTERFACE_NUM); + + inline const char* szWeapInventoryTypeNames[]{ + "primary", + "offhand", + "item", + "altmode", + }; + static_assert(std::extent_v == WEAPINVENTORY_NUM); + + inline const char* szWeapFireTypeNames[]{ + "Full Auto", + "Single Shot", + "2-Round Burst", + "3-Round Burst", + "4-Round Burst", + }; + 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 T4 diff --git a/src/ObjLoading/Game/IW3/Weapon/WeaponInfoStringLoaderIW3.cpp b/src/ObjLoading/Game/IW3/Weapon/WeaponInfoStringLoaderIW3.cpp index fcd7a856..a556c01d 100644 --- a/src/ObjLoading/Game/IW3/Weapon/WeaponInfoStringLoaderIW3.cpp +++ b/src/ObjLoading/Game/IW3/Weapon/WeaponInfoStringLoaderIW3.cpp @@ -303,15 +303,16 @@ namespace return strcmp(weapon.szInternalName, "defaultweapon") == 0 || strcmp(weapon.szInternalName, "defaultweapon_mp") == 0; } - snd_alias_list_name* SetDefaultSound(const char* name, MemoryManager& memory) + snd_alias_list_name* SetDefaultSound(const char* name, MemoryManager& memory, AssetCreationContext& context, AssetRegistration& registration) { auto* aliasListName = memory.Alloc(); aliasListName->soundName = name; + registration.AddIndirectAssetReference(context.LoadIndirectAssetReference(name)); return aliasListName; } - void SetWeaponDefaults(WeaponDef& weapon, MemoryManager& memory) + void SetWeaponDefaults(WeaponDef& weapon, MemoryManager& memory, AssetCreationContext& context, AssetRegistration& registration) { if (IsDefaultWeapon(weapon)) return; @@ -321,15 +322,15 @@ namespace if (!weapon.worldLastShotEjectEffect) weapon.worldLastShotEjectEffect = weapon.worldShellEjectEffect; if (!weapon.raiseSound.name) - SetDefaultSound("weap_raise", memory); + SetDefaultSound("weap_raise", memory, context, registration); if (!weapon.putawaySound.name) - SetDefaultSound("weap_putaway", memory); + SetDefaultSound("weap_putaway", memory, context, registration); if (!weapon.pickupSound.name) - SetDefaultSound("weap_pickup", memory); + SetDefaultSound("weap_pickup", memory, context, registration); if (!weapon.ammoPickupSound.name) - SetDefaultSound("weap_ammo_pickup", memory); + SetDefaultSound("weap_ammo_pickup", memory, context, registration); if (!weapon.emptyFireSound.name) - SetDefaultSound("weap_dryfire_smg_npc", memory); + SetDefaultSound("weap_dryfire_smg_npc", memory, context, registration); } void SetupTransitionTimes(WeaponDef& weapon) @@ -356,13 +357,13 @@ namespace weapon.fMinDamageRange = 999999.12f; // oddly specific number, no clue } - void CheckCrosshairValues(WeaponDef& weapon) + void CheckCrosshairValues(const WeaponDef& weapon) { if (weapon.enemyCrosshairRange > 15000.0f) con::warn("Weapon {}: Enemy crosshair ranges should be less than 15000", weapon.szInternalName); } - void CheckProjectileValues(WeaponDef& weapon) + void CheckProjectileValues(const WeaponDef& weapon) { if (weapon.weapType != WEAPTYPE_PROJECTILE) return; @@ -399,8 +400,6 @@ namespace weapon AssetCreationResult InfoStringLoaderIW3::CreateAsset(const std::string& assetName, const InfoString& infoString, AssetCreationContext& context) const { auto* weaponDef = m_memory.Alloc(); - memset(weaponDef, 0, sizeof(WeaponDef)); - InitWeaponDef(*weaponDef); weaponDef->szInternalName = m_memory.Dup(assetName.c_str()); @@ -420,7 +419,7 @@ namespace weapon return AssetCreationResult::Failure(); } - SetWeaponDefaults(*weaponDef, m_memory); + SetWeaponDefaults(*weaponDef, m_memory, context, registration); SetupTransitionTimes(*weaponDef); CheckWeaponDamageRanges(*weaponDef); CheckCrosshairValues(*weaponDef); diff --git a/src/ObjLoading/Game/T4/InfoString/InfoStringToStructConverter.cpp b/src/ObjLoading/Game/T4/InfoString/InfoStringToStructConverter.cpp new file mode 100644 index 00000000..166c6a38 --- /dev/null +++ b/src/ObjLoading/Game/T4/InfoString/InfoStringToStructConverter.cpp @@ -0,0 +1,164 @@ +#include "InfoStringToStructConverter.h" + +#include "Utils/Logging/Log.h" + +#include + +using namespace T4; + +InfoStringToStructConverter::InfoStringToStructConverter(const InfoString& infoString, + void* structure, + ZoneScriptStrings& zoneScriptStrings, + MemoryManager& memory, + AssetCreationContext& context, + GenericAssetRegistration& registration, + const cspField_t* fields, + const size_t fieldCount) + : InfoStringToStructConverterBase(infoString, structure, zoneScriptStrings, memory, context, registration), + m_fields(fields), + m_field_count(fieldCount) +{ +} + +bool InfoStringToStructConverter::ConvertBaseField(const cspField_t& field, const std::string& value) +{ + switch (static_cast(field.iFieldType)) + { + case CSPFT_STRING: + return ConvertString(value, field.iOffset); + + case CSPFT_STRING_MAX_STRING_CHARS: + return ConvertStringBuffer(value, field.iOffset, 1024); + + case CSPFT_STRING_MAX_QPATH: + return ConvertStringBuffer(value, field.iOffset, 64); + + case CSPFT_STRING_MAX_OSPATH: + return ConvertStringBuffer(value, field.iOffset, 256); + + case CSPFT_INT: + return ConvertInt(value, field.iOffset); + + case CSPFT_BOOL: + return ConvertQBoolean(value, field.iOffset); + + case CSPFT_FLOAT: + return ConvertFloat(value, field.iOffset); + + case CSPFT_MILLISECONDS: + return ConvertMilliseconds(value, field.iOffset); + + case CSPFT_FX: + { + if (value.empty()) + { + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = nullptr; + return true; + } + + auto* fx = m_context.LoadDependency(value); + if (fx == nullptr) + { + con::error("Failed to load fx asset \"{}\"", value); + return false; + } + + m_registration.AddDependency(fx); + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = fx->Asset(); + + return true; + } + + case CSPFT_XMODEL: + { + if (value.empty()) + { + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = nullptr; + return true; + } + + auto* xmodel = m_context.LoadDependency(value); + if (xmodel == nullptr) + { + con::error("Failed to load xmodel asset \"{}\"", value); + return false; + } + + m_registration.AddDependency(xmodel); + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = xmodel->Asset(); + + return true; + } + + case CSPFT_MATERIAL: + { + if (value.empty()) + { + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = nullptr; + return true; + } + + auto* material = m_context.LoadDependency(value); + if (material == nullptr) + { + con::error("Failed to load material asset \"{}\"", value); + return false; + } + + m_registration.AddDependency(material); + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = material->Asset(); + + return true; + } + + case CSPFT_SOUND: + { + auto* sound = reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset); + if (value.empty()) + { + sound->name = nullptr; + return true; + } + + auto* name = m_memory.Alloc(); + name->soundName = m_memory.Dup(value.c_str()); + sound->name = name; + + m_registration.AddIndirectAssetReference(m_context.LoadIndirectAssetReference(value)); + return true; + } + + case CSPFT_NUM_BASE_FIELD_TYPES: + default: + assert(false); + return false; + } +} + +bool InfoStringToStructConverter::Convert() +{ + for (auto fieldIndex = 0u; fieldIndex < m_field_count; fieldIndex++) + { + const auto& field = m_fields[fieldIndex]; + assert(field.iFieldType >= 0); + + auto foundValue = false; + const auto& value = m_info_string.GetValueForKey(std::string(field.szName), &foundValue); + + if (foundValue) + { + if (field.iFieldType < CSPFT_NUM_BASE_FIELD_TYPES) + { + if (!ConvertBaseField(field, value)) + return false; + } + else + { + if (!ConvertExtensionField(field, value)) + return false; + } + } + } + + return true; +} diff --git a/src/ObjLoading/Game/T4/InfoString/InfoStringToStructConverter.h b/src/ObjLoading/Game/T4/InfoString/InfoStringToStructConverter.h new file mode 100644 index 00000000..a2fead61 --- /dev/null +++ b/src/ObjLoading/Game/T4/InfoString/InfoStringToStructConverter.h @@ -0,0 +1,28 @@ +#pragma once + +#include "Game/T4/T4.h" +#include "InfoString/InfoStringToStructConverterBase.h" + +namespace T4 +{ + class InfoStringToStructConverter : public InfoStringToStructConverterBase + { + public: + InfoStringToStructConverter(const InfoString& infoString, + void* structure, + ZoneScriptStrings& zoneScriptStrings, + MemoryManager& memory, + AssetCreationContext& context, + GenericAssetRegistration& registration, + const cspField_t* fields, + size_t fieldCount); + bool Convert() override; + + protected: + virtual bool ConvertExtensionField(const cspField_t& field, const std::string& value) = 0; + bool ConvertBaseField(const cspField_t& field, const std::string& value); + + const cspField_t* m_fields; + size_t m_field_count; + }; +} // namespace T4 diff --git a/src/ObjLoading/Game/T4/ObjLoaderT4.cpp b/src/ObjLoading/Game/T4/ObjLoaderT4.cpp index 9c52ddf8..6a037de2 100644 --- a/src/ObjLoading/Game/T4/ObjLoaderT4.cpp +++ b/src/ObjLoading/Game/T4/ObjLoaderT4.cpp @@ -3,10 +3,14 @@ #include "Asset/GlobalAssetPoolsLoader.h" #include "Game/T4/AssetMarkerT4.h" #include "Game/T4/T4.h" +#include "Game/T4/Weapon/AccuracyGraphLoaderT4.h" #include "Game/T4/XAnim/XAnimLoaderT4.h" #include "Localize/AssetLoaderLocalizeT4.h" #include "Maps/MapEntsLoaderT4.h" #include "RawFile/AssetLoaderRawFileT4.h" +#include "Weapon/FlameTableLoaderT4.h" +#include "Weapon/WeaponGdtLoaderT4.h" +#include "Weapon/WeaponRawLoaderT4.h" using namespace T4; @@ -92,6 +96,11 @@ namespace collection.AddAssetCreator(localize::CreateLoaderT4(memory, searchPath, zone)); collection.AddAssetCreator(map_ents::CreateLoaderT4(memory, searchPath)); collection.AddAssetCreator(raw_file::CreateLoaderT4(memory, searchPath)); + collection.AddAssetCreator(weapon::CreateRawLoaderT4(memory, searchPath, zone)); + collection.AddAssetCreator(weapon::CreateGdtLoaderT4(memory, searchPath, gdt, zone)); + + collection.AddSubAssetCreator(weapon::CreateAccuracyGraphLoaderT4(memory, searchPath)); + collection.AddSubAssetCreator(weapon::CreateFlameTableLoaderT4(memory, searchPath, zone)); } } // namespace diff --git a/src/ObjLoading/Game/T4/Weapon/FlameTableLoaderT4.cpp b/src/ObjLoading/Game/T4/Weapon/FlameTableLoaderT4.cpp new file mode 100644 index 00000000..fe34c124 --- /dev/null +++ b/src/ObjLoading/Game/T4/Weapon/FlameTableLoaderT4.cpp @@ -0,0 +1,90 @@ +#include "FlameTableLoaderT4.h" + +#include "Game/T4/InfoString/InfoStringToStructConverter.h" +#include "Game/T4/ObjConstantsT4.h" +#include "Game/T4/T4.h" +#include "Game/T4/Weapon/FlameTableFields.h" +#include "Weapon/WeaponCommon.h" + +#include + +using namespace T4; + +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 FlameTableLoaderT4 final : public SubAssetCreator + { + public: + FlameTableLoaderT4(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(); + } + + 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 CreateFlameTableLoaderT4(MemoryManager& memory, ISearchPath& searchPath, Zone& zone) + { + return std::make_unique(memory, searchPath, zone); + } +} // namespace weapon diff --git a/src/ObjLoading/Game/T4/Weapon/FlameTableLoaderT4.h b/src/ObjLoading/Game/T4/Weapon/FlameTableLoaderT4.h new file mode 100644 index 00000000..6ac0f749 --- /dev/null +++ b/src/ObjLoading/Game/T4/Weapon/FlameTableLoaderT4.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 CreateFlameTableLoaderT4(MemoryManager& memory, ISearchPath& searchPath, Zone& zone); +} // namespace weapon diff --git a/src/ObjLoading/Game/T4/Weapon/WeaponGdtLoaderT4.cpp b/src/ObjLoading/Game/T4/Weapon/WeaponGdtLoaderT4.cpp new file mode 100644 index 00000000..a194e6f6 --- /dev/null +++ b/src/ObjLoading/Game/T4/Weapon/WeaponGdtLoaderT4.cpp @@ -0,0 +1,52 @@ +#include "WeaponGdtLoaderT4.h" + +#include "Game/T4/ObjConstantsT4.h" +#include "Game/T4/T4.h" +#include "InfoString/InfoString.h" +#include "Utils/Logging/Log.h" +#include "WeaponInfoStringLoaderT4.h" + +#include + +using namespace T4; + +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::InfoStringLoaderT4 m_info_string_loader; + }; +} // namespace + +namespace weapon +{ + std::unique_ptr> CreateGdtLoaderT4(MemoryManager& memory, ISearchPath& searchPath, IGdtQueryable& gdt, Zone& zone) + { + return std::make_unique(memory, searchPath, gdt, zone); + } +} // namespace weapon diff --git a/src/ObjLoading/Game/T4/Weapon/WeaponGdtLoaderT4.h b/src/ObjLoading/Game/T4/Weapon/WeaponGdtLoaderT4.h new file mode 100644 index 00000000..63769cb1 --- /dev/null +++ b/src/ObjLoading/Game/T4/Weapon/WeaponGdtLoaderT4.h @@ -0,0 +1,14 @@ +#pragma once + +#include "Asset/IAssetCreator.h" +#include "Game/T4/T4.h" +#include "Gdt/IGdtQueryable.h" +#include "SearchPath/ISearchPath.h" +#include "Utils/MemoryManager.h" + +#include + +namespace weapon +{ + std::unique_ptr> CreateGdtLoaderT4(MemoryManager& memory, ISearchPath& searchPath, IGdtQueryable& gdt, Zone& zone); +} // namespace weapon diff --git a/src/ObjLoading/Game/T4/Weapon/WeaponInfoStringLoaderT4.cpp b/src/ObjLoading/Game/T4/Weapon/WeaponInfoStringLoaderT4.cpp new file mode 100644 index 00000000..0a5c3d90 --- /dev/null +++ b/src/ObjLoading/Game/T4/Weapon/WeaponInfoStringLoaderT4.cpp @@ -0,0 +1,491 @@ +#include "WeaponInfoStringLoaderT4.h" + +#include "Game/T4/InfoString/InfoStringToStructConverter.h" +#include "Game/T4/T4.h" +#include "Game/T4/Weapon/WeaponFields.h" +#include "Game/T4/Weapon/WeaponStrings.h" +#include "Utils/Logging/Log.h" +#include "Utils/StringUtils.h" +#include "Weapon/WeaponCommon.h" + +#include +#include +#include +#include +#include + +using namespace T4; + +namespace +{ + class InfoStringToWeaponConverter final : public InfoStringToStructConverter + { + bool ConvertHideTags(const cspField_t& field, const std::string& value) + { + std::istringstream ss(value); + std::vector tags; + + std::string tag; + while (ss >> tag) + tags.emplace_back(std::move(tag)); + + if (tags.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 (tags.size() < std::extent_v) + m_registration.AddScriptString(m_zone_script_strings.AddOrGetScriptString(nullptr)); + + auto currentHideTag = 0u; + for (; currentHideTag < tags.size(); currentHideTag++) + { + auto currentValue = tags[currentHideTag]; + utils::MakeStringLowerCase(currentValue); + + 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; + } + + static_assert(std::extent_v == std::extent_v); + *bounceSound = m_memory.Alloc(std::extent_v); + for (auto i = 0u; i < std::extent_v; i++) + { + const auto currentBounceSound = value + bounceSoundSuffixes[i]; + + (*bounceSound)[i].name = m_memory.Alloc(); + (*bounceSound)[i].name->soundName = m_memory.Dup(currentBounceSound.c_str()); + m_registration.AddIndirectAssetReference(m_context.LoadIndirectAssetReference(currentBounceSound)); + } + + return true; + } + + [[nodiscard]] bool ConvertNotetrackSoundMap(const cspField_t& field, const std::string& value) + { + std::istringstream ss(value); + std::vector tokens; + + std::string token; + while (ss >> token) + tokens.emplace_back(std::move(token)); + + if (tokens.size() % 2 != 0) + { + con::warn("Notetrack-to-Sound: Weapon '{}' has bad entry; notetrack '{}' doesn't have a corresponding sound.", + *reinterpret_cast(m_structure), + tokens.back()); + tokens.pop_back(); + } + + const auto pairCount = tokens.size() / 2; + if (pairCount > 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 (pairCount < std::extent_v) + m_registration.AddScriptString(m_zone_script_strings.AddOrGetScriptString(nullptr)); + + for (; currentEntryNum < pairCount; currentEntryNum++) + { + auto key = tokens[currentEntryNum * 2]; + auto sound = tokens[currentEntryNum * 2 + 1]; + + if (key.size() >= 63) + { + con::error("Notetrack-to-sound: keyname \"{}\" is too long (length {}/{}).", key, key.size(), 63); + return false; + } + + utils::MakeStringLowerCase(key); + utils::MakeStringLowerCase(sound); + + const auto keyScriptString = + !key.empty() ? m_zone_script_strings.AddOrGetScriptString(key) : m_zone_script_strings.AddOrGetScriptString(nullptr); + const auto valueScriptString = + !sound.empty() ? m_zone_script_strings.AddOrGetScriptString(sound) : 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; + } + + bool ConvertAnimName(const cspField_t& field, const std::string& value) + { + if (ConvertString(value, field.iOffset)) + { + if (!value.empty()) + m_registration.AddIndirectAssetReference(m_context.LoadIndirectAssetReference(value)); + + return true; + } + + return false; + } + + 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_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_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: + return ConvertEnumInt(field.szName, value, field.iOffset, weapIconRatioNames, std::extent_v); + + case WFT_HIDETAGS: + return ConvertHideTags(field, value); + + case WFT_NOTETRACKSOUNDMAP: + return ConvertNotetrackSoundMap(field, value); + + case WFT_ANIM_NAME: + return ConvertAnimName(field, value); + + default: + assert(false); + return false; + } + } + + public: + InfoStringToWeaponConverter(const InfoString& infoString, + WeaponDef& weaponDef, + ZoneScriptStrings& zoneScriptStrings, + MemoryManager& memory, + AssetCreationContext& context, + AssetRegistration& registration, + const cspField_t* fields, + const size_t fieldCount) + : InfoStringToStructConverter(infoString, &weaponDef, zoneScriptStrings, memory, context, registration, fields, fieldCount) + { + } + }; + + void InitWeaponDef(WeaponDef& weapon) + { + for (const auto& field : weapon_fields) + { + if (field.iFieldType != CSPFT_STRING && field.iFieldType != WFT_ANIM_NAME) + continue; + + *reinterpret_cast(reinterpret_cast(&weapon) + field.iOffset) = ""; + } + + weapon.szXAnims[WEAP_ANIM_ROOT] = ""; + } + + bool LoadAccuracyGraph(const std::string& graphName, + vec2_t*& originalGraphKnots, + int& originalGraphKnotCount, + vec2_t*& graphKnots, + int& graphKnotCount, + AssetCreationContext& context) + { + auto* accuracyGraphAsset = context.LoadSubAsset(graphName); + if (!accuracyGraphAsset) + return false; + + const auto* accuracyGraph = accuracyGraphAsset->Asset(); + + assert(accuracyGraphAsset->m_dependencies.empty()); + assert(accuracyGraphAsset->m_used_script_strings.empty()); + assert(accuracyGraphAsset->m_indirect_asset_references.empty()); + + originalGraphKnots = accuracyGraph->graphKnots; + originalGraphKnotCount = accuracyGraph->graphKnotCount; + + graphKnots = accuracyGraph->graphKnots; + graphKnotCount = accuracyGraph->graphKnotCount; + + return true; + } + + bool LoadAccuracyGraphs(WeaponDef& weapon, AssetCreationContext& context) + { + if (weapon.aiVsAiAccuracyGraphName && weapon.aiVsAiAccuracyGraphName[0]) + { + if (!LoadAccuracyGraph(weapon::GetAssetNameForAiVsAiAccuracyGraph(weapon.aiVsAiAccuracyGraphName), + weapon.originalAiVsAiAccuracyGraphKnots, + weapon.originalAiVsAiAccuracyGraphKnotCount, + weapon.aiVsAiAccuracyGraphKnots, + weapon.aiVsAiAccuracyGraphKnotCount, + context)) + { + return false; + } + } + + if (weapon.aiVsPlayerAccuracyGraphName && weapon.aiVsPlayerAccuracyGraphName[0]) + { + if (!LoadAccuracyGraph(weapon::GetAssetNameForAiVsPlayerAccuracyGraph(weapon.aiVsPlayerAccuracyGraphName), + weapon.originalAiVsPlayerAccuracyGraphKnots, + weapon.originalAiVsPlayerAccuracyGraphKnotCount, + weapon.aiVsPlayerAccuracyGraphKnots, + weapon.aiVsPlayerAccuracyGraphKnotCount, + context)) + { + return false; + } + } + + return true; + } + + bool LoadFlameTable(const char* flameTableName, FlameTable*& flameTablePtr, AssetRegistration& registration, AssetCreationContext& context) + { + flameTablePtr = nullptr; + if (!flameTableName || flameTableName[0] == '\0') + return true; + + 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()); + for (const auto& indirectReference : flameTableAsset->m_indirect_asset_references) + registration.AddIndirectAssetReference(indirectReference); + + flameTablePtr = flameTableAsset->Asset(); + return true; + } + + bool LoadFlameTables(WeaponDef& weapon, AssetRegistration& registration, AssetCreationContext& context) + { + return LoadFlameTable(weapon.flameTableFirstPerson, weapon.flameTableFirstPersonPtr, registration, context) + && LoadFlameTable(weapon.flameTableThirdPerson, weapon.flameTableThirdPersonPtr, registration, context); + } + + bool IsDefaultWeapon(const WeaponDef& weapon) + { + return strcmp(weapon.szInternalName, "defaultweapon") == 0 || strcmp(weapon.szInternalName, "defaultweapon_mp") == 0; + } + + snd_alias_list_name* SetDefaultSound(const char* name, MemoryManager& memory, AssetCreationContext& context, AssetRegistration& registration) + { + auto* aliasListName = memory.Alloc(); + aliasListName->soundName = name; + registration.AddIndirectAssetReference(context.LoadIndirectAssetReference(name)); + + return aliasListName; + } + + void SetWeaponDefaults(WeaponDef& weapon, MemoryManager& memory, AssetCreationContext& context, AssetRegistration& registration) + { + if (IsDefaultWeapon(weapon)) + return; + + if (!weapon.viewLastShotEjectEffect) + weapon.viewLastShotEjectEffect = weapon.viewShellEjectEffect; + if (!weapon.worldLastShotEjectEffect) + weapon.worldLastShotEjectEffect = weapon.worldShellEjectEffect; + if (!weapon.raiseSound.name) + SetDefaultSound("weap_raise", memory, context, registration); + if (!weapon.putawaySound.name) + SetDefaultSound("weap_putaway", memory, context, registration); + if (!weapon.pickupSound.name) + SetDefaultSound("weap_pickup", memory, context, registration); + if (!weapon.ammoPickupSound.name) + SetDefaultSound("weap_ammo_pickup", memory, context, registration); + if (!weapon.emptyFireSound.name) + SetDefaultSound("player_out_of_ammo", memory, context, registration); + } + + void SetupTransitionTimes(WeaponDef& weapon) + { + if (weapon.iAdsTransInTime <= 0) + weapon.fOOPosAnimLength[0] = 1.0f / 300.0f; + else + weapon.fOOPosAnimLength[0] = 1.0f / static_cast(weapon.iAdsTransInTime); + + if (weapon.iAdsTransOutTime <= 0) + weapon.fOOPosAnimLength[1] = 1.0f / 500.0f; + else + weapon.fOOPosAnimLength[1] = 1.0f / static_cast(weapon.iAdsTransOutTime); + } + + void CheckWeaponDamageRanges(WeaponDef& weapon) + { + if (strcmp(weapon.szInternalName, "none") == 0) + return; + + if (weapon.fMaxDamageRange <= 0.0f) + weapon.fMaxDamageRange = 999999.0f; + if (weapon.fMinDamageRange <= 0.0f) + weapon.fMinDamageRange = 999999.12f; + } + + void CheckCrosshairValues(const WeaponDef& weapon) + { + if (weapon.enemyCrosshairRange > 15000.0f) + con::warn("Weapon {}: Enemy crosshair ranges should be less than 15000", weapon.szInternalName); + } + + void CheckProjectileValues(const WeaponDef& weapon) + { + if (weapon.weapType != WEAPTYPE_PROJECTILE) + return; + + if (weapon.iProjectileSpeed <= 0) + con::warn("Weapon {}: Projectile speed must be greater than 0.0", weapon.szDisplayName); + + if (weapon.destabilizationCurvatureMax >= 1000000000.0f || weapon.destabilizationCurvatureMax < 0.0f) + con::warn("Weapon {}: Destabilization angle must be between 0 and 45 degrees", weapon.szDisplayName); + + if (weapon.destabilizationRateTime < 0.0f) + con::warn("Weapon {}: Destabilization rate time must be non-negative", weapon.szDisplayName); + } + + void CheckSharedAmmoValues(const WeaponDef& weapon) + { + if (weapon.szAmmoName) + utils::MakeStringLowerCase(const_cast(weapon.szAmmoName)); + + if (weapon.szClipName) + utils::MakeStringLowerCase(const_cast(weapon.szClipName)); + } +} // namespace + +namespace weapon +{ + InfoStringLoaderT4::InfoStringLoaderT4(MemoryManager& memory, ISearchPath& searchPath, Zone& zone) + : m_memory(memory), + m_search_path(searchPath), + m_zone(zone) + { + } + + AssetCreationResult InfoStringLoaderT4::CreateAsset(const std::string& assetName, const InfoString& infoString, AssetCreationContext& context) const + { + auto* weaponDef = m_memory.Alloc(); + InitWeaponDef(*weaponDef); + weaponDef->szInternalName = m_memory.Dup(assetName.c_str()); + + AssetRegistration registration(assetName, weaponDef); + + InfoStringToWeaponConverter converter( + infoString, *weaponDef, 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(*weaponDef, context)) + { + con::error("Failed to load accuracy tables of weapon: \"{}\"", assetName); + return AssetCreationResult::Failure(); + } + + if (!LoadFlameTables(*weaponDef, registration, context)) + { + con::error("Failed to load flame tables of weapon: \"{}\"", assetName); + return AssetCreationResult::Failure(); + } + + SetWeaponDefaults(*weaponDef, m_memory, context, registration); + SetupTransitionTimes(*weaponDef); + CheckWeaponDamageRanges(*weaponDef); + CheckCrosshairValues(*weaponDef); + CheckProjectileValues(*weaponDef); + CheckSharedAmmoValues(*weaponDef); + + return AssetCreationResult::Success(context.AddAsset(std::move(registration))); + } +} // namespace weapon diff --git a/src/ObjLoading/Game/T4/Weapon/WeaponInfoStringLoaderT4.h b/src/ObjLoading/Game/T4/Weapon/WeaponInfoStringLoaderT4.h new file mode 100644 index 00000000..b89aca53 --- /dev/null +++ b/src/ObjLoading/Game/T4/Weapon/WeaponInfoStringLoaderT4.h @@ -0,0 +1,24 @@ +#pragma once + +#include "Asset/AssetCreationContext.h" +#include "Asset/AssetCreationResult.h" +#include "InfoString/InfoString.h" +#include "SearchPath/ISearchPath.h" +#include "Utils/MemoryManager.h" +#include "Zone/Zone.h" + +namespace weapon +{ + class InfoStringLoaderT4 + { + public: + InfoStringLoaderT4(MemoryManager& memory, ISearchPath& searchPath, Zone& zone); + + AssetCreationResult CreateAsset(const std::string& assetName, const InfoString& infoString, AssetCreationContext& context) const; + + private: + MemoryManager& m_memory; + ISearchPath& m_search_path; + Zone& m_zone; + }; +} // namespace weapon diff --git a/src/ObjLoading/Game/T4/Weapon/WeaponRawLoaderT4.cpp b/src/ObjLoading/Game/T4/Weapon/WeaponRawLoaderT4.cpp new file mode 100644 index 00000000..b54a34c1 --- /dev/null +++ b/src/ObjLoading/Game/T4/Weapon/WeaponRawLoaderT4.cpp @@ -0,0 +1,52 @@ +#include "WeaponRawLoaderT4.h" + +#include "Game/T4/ObjConstantsT4.h" +#include "Game/T4/T4.h" +#include "InfoString/InfoString.h" +#include "Utils/Logging/Log.h" +#include "Weapon/WeaponCommon.h" +#include "WeaponInfoStringLoaderT4.h" + +using namespace T4; + +namespace +{ + class RawLoaderWeapon final : public AssetCreator + { + public: + RawLoaderWeapon(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::InfoStringLoaderT4 m_info_string_loader; + }; +} // namespace + +namespace weapon +{ + std::unique_ptr> CreateRawLoaderT4(MemoryManager& memory, ISearchPath& searchPath, Zone& zone) + { + return std::make_unique(memory, searchPath, zone); + } +} // namespace weapon diff --git a/src/ObjLoading/Game/T4/Weapon/WeaponRawLoaderT4.h b/src/ObjLoading/Game/T4/Weapon/WeaponRawLoaderT4.h new file mode 100644 index 00000000..ac947d1a --- /dev/null +++ b/src/ObjLoading/Game/T4/Weapon/WeaponRawLoaderT4.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Asset/IAssetCreator.h" +#include "Game/T4/T4.h" +#include "SearchPath/ISearchPath.h" +#include "Utils/MemoryManager.h" + +#include + +namespace weapon +{ + std::unique_ptr> CreateRawLoaderT4(MemoryManager& memory, ISearchPath& searchPath, Zone& zone); +} // namespace weapon diff --git a/src/ObjLoading/Game/T5/Weapon/WeaponInfoStringLoaderT5.cpp b/src/ObjLoading/Game/T5/Weapon/WeaponInfoStringLoaderT5.cpp index 582ec695..f2e0a154 100644 --- a/src/ObjLoading/Game/T5/Weapon/WeaponInfoStringLoaderT5.cpp +++ b/src/ObjLoading/Game/T5/Weapon/WeaponInfoStringLoaderT5.cpp @@ -395,7 +395,7 @@ namespace con::warn("Weapon {}: Enemy crosshair ranges should be less than 15000", weapon.weapVariantDef.szInternalName); } - void CheckProjectileValues(WeaponFullDef& weapon) + void CheckProjectileValues(const WeaponFullDef& weapon) { if (weapon.weapDef.weapType != WEAPTYPE_PROJECTILE) return; diff --git a/src/ObjLoading/Game/T6/Weapon/WeaponInfoStringLoaderT6.cpp b/src/ObjLoading/Game/T6/Weapon/WeaponInfoStringLoaderT6.cpp index 8913af24..1ab025ce 100644 --- a/src/ObjLoading/Game/T6/Weapon/WeaponInfoStringLoaderT6.cpp +++ b/src/ObjLoading/Game/T6/Weapon/WeaponInfoStringLoaderT6.cpp @@ -544,13 +544,13 @@ namespace weapon.weapDef.damageRange[5] = 999999.12f; // oddly specific number, no clue } - void CheckCrosshairValues(WeaponFullDef& weapon) + void CheckCrosshairValues(const 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) + void CheckProjectileValues(const WeaponFullDef& weapon) { if (weapon.weapDef.weapType != WEAPTYPE_PROJECTILE) return; @@ -724,7 +724,7 @@ namespace weapon { } - AssetCreationResult InfoStringLoaderT6::CreateAsset(const std::string& assetName, const InfoString& infoString, AssetCreationContext& context) + AssetCreationResult InfoStringLoaderT6::CreateAsset(const std::string& assetName, const InfoString& infoString, AssetCreationContext& context) const { auto* weaponFullDef = m_memory.Alloc(); weaponFullDef->weapVariantDef.szInternalName = m_memory.Dup(assetName.c_str()); diff --git a/src/ObjLoading/Game/T6/Weapon/WeaponInfoStringLoaderT6.h b/src/ObjLoading/Game/T6/Weapon/WeaponInfoStringLoaderT6.h index a4d146cb..c8170563 100644 --- a/src/ObjLoading/Game/T6/Weapon/WeaponInfoStringLoaderT6.h +++ b/src/ObjLoading/Game/T6/Weapon/WeaponInfoStringLoaderT6.h @@ -11,7 +11,7 @@ namespace weapon public: InfoStringLoaderT6(MemoryManager& memory, ISearchPath& searchPath, Zone& zone); - AssetCreationResult CreateAsset(const std::string& assetName, const InfoString& infoString, AssetCreationContext& context); + AssetCreationResult CreateAsset(const std::string& assetName, const InfoString& infoString, AssetCreationContext& context) const; private: MemoryManager& m_memory; diff --git a/src/ObjLoading/Weapon/AccuracyGraphLoader.cpp.template b/src/ObjLoading/Weapon/AccuracyGraphLoader.cpp.template index 9baee78f..5b2e6ada 100644 --- a/src/ObjLoading/Weapon/AccuracyGraphLoader.cpp.template +++ b/src/ObjLoading/Weapon/AccuracyGraphLoader.cpp.template @@ -1,4 +1,4 @@ -#options GAME(IW3, IW4, IW5, T5, T6) +#options GAME(IW3, IW4, IW5, T4, T5, T6) #filename "Game/" + GAME + "/Weapon/AccuracyGraphLoader" + GAME + ".cpp" diff --git a/src/ObjLoading/Weapon/AccuracyGraphLoader.h.template b/src/ObjLoading/Weapon/AccuracyGraphLoader.h.template index 89e2d295..7961cf8a 100644 --- a/src/ObjLoading/Weapon/AccuracyGraphLoader.h.template +++ b/src/ObjLoading/Weapon/AccuracyGraphLoader.h.template @@ -1,4 +1,4 @@ -#options GAME (IW3, IW4, IW5, T5, T6) +#options GAME(IW3, IW4, IW5, T4, T5, T6) #filename "Game/" + GAME + "/Weapon/AccuracyGraphLoader" + GAME + ".h" diff --git a/src/ObjWriting/Game/T4/InfoString/InfoStringFromStructConverter.cpp b/src/ObjWriting/Game/T4/InfoString/InfoStringFromStructConverter.cpp new file mode 100644 index 00000000..83a57dd1 --- /dev/null +++ b/src/ObjWriting/Game/T4/InfoString/InfoStringFromStructConverter.cpp @@ -0,0 +1,123 @@ +#include "InfoStringFromStructConverter.h" + +#include + +using namespace T4; + +void InfoStringFromStructConverter::FillFromBaseField(const cspField_t& field) +{ + switch (static_cast(field.iFieldType)) + { + case CSPFT_STRING: + FillFromString(std::string(field.szName), field.iOffset); + break; + + case CSPFT_STRING_MAX_STRING_CHARS: + FillFromStringBuffer(std::string(field.szName), field.iOffset, 1024); + break; + + case CSPFT_STRING_MAX_QPATH: + FillFromStringBuffer(std::string(field.szName), field.iOffset, 64); + break; + + case CSPFT_STRING_MAX_OSPATH: + FillFromStringBuffer(std::string(field.szName), field.iOffset, 256); + break; + + case CSPFT_INT: + FillFromInt(std::string(field.szName), field.iOffset); + break; + + case CSPFT_BOOL: + FillFromQBoolean(std::string(field.szName), field.iOffset); + break; + + case CSPFT_FLOAT: + FillFromFloat(std::string(field.szName), field.iOffset); + break; + + case CSPFT_MILLISECONDS: + FillFromMilliseconds(std::string(field.szName), field.iOffset); + break; + + case CSPFT_FX: + { + const auto* fx = *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset); + + if (fx) + m_info_string.SetValueForKey(std::string(field.szName), std::string(AssetName(fx->name))); + else + m_info_string.SetValueForKey(std::string(field.szName), ""); + break; + } + + case CSPFT_XMODEL: + { + const auto* model = *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset); + + if (model) + m_info_string.SetValueForKey(std::string(field.szName), std::string(AssetName(model->name))); + else + m_info_string.SetValueForKey(std::string(field.szName), ""); + break; + } + + case CSPFT_MATERIAL: + { + const auto* material = *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset); + + if (material) + m_info_string.SetValueForKey(std::string(field.szName), std::string(AssetName(material->info.name))); + else + m_info_string.SetValueForKey(std::string(field.szName), ""); + break; + } + + case CSPFT_SOUND: + { + const auto* sndAlias = reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset); + + if (sndAlias->name) + m_info_string.SetValueForKey(std::string(field.szName), std::string(sndAlias->name->soundName)); + else + m_info_string.SetValueForKey(std::string(field.szName), ""); + break; + } + + case CSPFT_NUM_BASE_FIELD_TYPES: + default: + assert(false); + break; + } +} + +void InfoStringFromStructConverter::FillInfoString() +{ + for (auto fieldIndex = 0u; fieldIndex < m_field_count; fieldIndex++) + { + const auto& field = m_fields[fieldIndex]; + assert(field.iFieldType >= 0); + + if (field.iFieldType < CSPFT_NUM_BASE_FIELD_TYPES) + FillFromBaseField(field); + else + FillFromExtensionField(field); + } +} + +InfoStringFromStructConverter::InfoStringFromStructConverter(const void* structure, const cspField_t* fields, const size_t fieldCount) + : InfoStringFromStructConverterBase(structure), + m_fields(fields), + m_field_count(fieldCount) +{ +} + +InfoStringFromStructConverter::InfoStringFromStructConverter(const void* structure, + const cspField_t* fields, + const size_t fieldCount, + std::function scriptStringValueCallback) + : InfoStringFromStructConverterBase(structure, std::move(scriptStringValueCallback)), + m_fields(fields), + m_field_count(fieldCount) +{ +} diff --git a/src/ObjWriting/Game/T4/InfoString/InfoStringFromStructConverter.h b/src/ObjWriting/Game/T4/InfoString/InfoStringFromStructConverter.h new file mode 100644 index 00000000..2f27957c --- /dev/null +++ b/src/ObjWriting/Game/T4/InfoString/InfoStringFromStructConverter.h @@ -0,0 +1,25 @@ +#pragma once + +#include "Game/T4/T4.h" +#include "InfoString/InfoStringFromStructConverterBase.h" + +namespace T4 +{ + class InfoStringFromStructConverter : public InfoStringFromStructConverterBase + { + protected: + const cspField_t* m_fields; + size_t m_field_count; + + virtual void FillFromExtensionField(const cspField_t& field) = 0; + void FillFromBaseField(const cspField_t& field); + void FillInfoString() override; + + public: + InfoStringFromStructConverter(const void* structure, const cspField_t* fields, size_t fieldCount); + InfoStringFromStructConverter(const void* structure, + const cspField_t* fields, + size_t fieldCount, + std::function scriptStringValueCallback); + }; +} // namespace T4 diff --git a/src/ObjWriting/Game/T4/ObjWriterT4.cpp b/src/ObjWriting/Game/T4/ObjWriterT4.cpp index 7e95b891..d38f0a7d 100644 --- a/src/ObjWriting/Game/T4/ObjWriterT4.cpp +++ b/src/ObjWriting/Game/T4/ObjWriterT4.cpp @@ -8,6 +8,7 @@ #include "RawFile/RawFileDumperT4.h" #include "Sound/LoadedSoundDumperT4.h" #include "StringTable/StringTableDumperT4.h" +#include "Weapon/WeaponDumperT4.h" using namespace T4; @@ -19,6 +20,7 @@ void ObjWriter::RegisterAssetDumpers(AssetDumpingContext& context) RegisterAssetDumper(std::make_unique()); RegisterAssetDumper(std::make_unique()); RegisterAssetDumper(std::make_unique()); + RegisterAssetDumper(std::make_unique()); RegisterAssetDumper(std::make_unique()); RegisterAssetDumper(std::make_unique()); } diff --git a/src/ObjWriting/Game/T4/Weapon/WeaponDumperT4.cpp b/src/ObjWriting/Game/T4/Weapon/WeaponDumperT4.cpp new file mode 100644 index 00000000..9636ee34 --- /dev/null +++ b/src/ObjWriting/Game/T4/Weapon/WeaponDumperT4.cpp @@ -0,0 +1,347 @@ +#include "WeaponDumperT4.h" + +#include "Dumping/SubAssetDeduplicationDumperState.h" +#include "Game/T4/InfoString/InfoStringFromStructConverter.h" +#include "Game/T4/ObjConstantsT4.h" +#include "Game/T4/Weapon/FlameTableFields.h" +#include "Game/T4/Weapon/WeaponFields.h" +#include "Game/T4/Weapon/WeaponStrings.h" +#include "InfoString/InfoString.h" +#include "Weapon/AccuracyGraphWriter.h" +#include "Weapon/WeaponCommon.h" + +#include +#include +#include + +using namespace T4; + +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_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->name) + { + const std::string firstBounceSound(bounceSound->name->soundName); + 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_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: + 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_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_ANIM_NAME: + FillFromString(std::string(field.szName), field.iOffset); + break; + + case WFT_NUM_FIELD_TYPES: + default: + assert(false); + break; + } + } + + public: + InfoStringFromWeaponConverter(const WeaponDef* 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)) + { + } + }; + + InfoString CreateInfoString(const XAssetInfo& asset) + { + InfoStringFromWeaponConverter converter(asset.Asset(), + 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(); + } + + GenericGraph2D ConvertAccuracyGraph(std::string graphName, const vec2_t* originalKnots, const unsigned originalKnotCount) + { + GenericGraph2D graph; + + graph.name = std::move(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 DumpAccuracyGraphs(AssetDumpingContext& context, const XAssetInfo& asset) + { + auto* accuracyGraphWriter = context.GetZoneAssetDumperState(); + const auto* weapon = asset.Asset(); + + if (weapon->aiVsAiAccuracyGraphName && weapon->originalAiVsAiAccuracyGraphKnots) + { + auto graphName = weapon::GetAssetNameForAiVsAiAccuracyGraph(weapon->aiVsAiAccuracyGraphName); + if (accuracyGraphWriter->ShouldDumpGraph(graphName)) + { + const auto graph = + ConvertAccuracyGraph(std::move(graphName), weapon->originalAiVsAiAccuracyGraphKnots, weapon->originalAiVsAiAccuracyGraphKnotCount); + AccuracyGraphWriter::DumpGraph(context, graph); + } + } + + if (weapon->aiVsPlayerAccuracyGraphName && weapon->originalAiVsPlayerAccuracyGraphKnots) + { + auto graphName = weapon::GetAssetNameForAiVsPlayerAccuracyGraph(weapon->aiVsPlayerAccuracyGraphName); + if (accuracyGraphWriter->ShouldDumpGraph(graphName)) + { + const auto graph = + ConvertAccuracyGraph(std::move(graphName), weapon->originalAiVsPlayerAccuracyGraphKnots, weapon->originalAiVsPlayerAccuracyGraphKnotCount); + AccuracyGraphWriter::DumpGraph(context, graph); + } + } + } + + 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; + + 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); + assetFile->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->flameTableFirstPerson, weapon->flameTableFirstPersonPtr); + DumpFlameTable(context, *deduplicator, weapon->flameTableThirdPerson, weapon->flameTableThirdPersonPtr); + } +} // namespace + +namespace weapon +{ + void DumperT4::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/T4/Weapon/WeaponDumperT4.h b/src/ObjWriting/Game/T4/Weapon/WeaponDumperT4.h new file mode 100644 index 00000000..7680e3b8 --- /dev/null +++ b/src/ObjWriting/Game/T4/Weapon/WeaponDumperT4.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/T4/T4.h" + +namespace weapon +{ + class DumperT4 final : public AbstractAssetDumper + { + protected: + void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; + }; +} // namespace weapon