2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2026-07-02 22:08:11 +00:00

feat: T4 weapon loading and dumping (#869)

* feat: T4 weapon loading and dumping

* chore: adjust naming of weapon enum values

* chore: fix typo in type names

* chore: rename t4 weapon loader files

* feat: dump and load gdt weapons for t4

* chore: weapon loaders to use similar logic

---------

Co-authored-by: Jan Laupetin <jan@laupetin.net>
This commit is contained in:
mo
2026-07-02 06:10:24 +01:00
committed by GitHub
parent ee63355fd2
commit fb4b00398c
32 changed files with 2536 additions and 46 deletions
+1 -1
View File
@@ -149,7 +149,7 @@ using `Linker`):
| MenuList | ❌ | ❌ | | | MenuList | ❌ | ❌ | |
| menuDef_t | ❌ | ❌ | | | menuDef_t | ❌ | ❌ | |
| LocalizeEntry | ✅ | ✅ | | | LocalizeEntry | ✅ | ✅ | |
| WeaponDef | | | | | WeaponDef | | | |
| FxEffectDef | ❌ | ❌ | | | FxEffectDef | ❌ | ❌ | |
| FxImpactTable | ❌ | ❌ | | | FxImpactTable | ❌ | ❌ | |
| RawFile | ✅ | ✅ | | | RawFile | ✅ | ✅ | |
+2 -2
View File
@@ -2855,7 +2855,7 @@ namespace IW3
WEAPOVERLAYRETICLE_NUM, WEAPOVERLAYRETICLE_NUM,
}; };
enum WeapOverlayInteface_t enum WeapOverlayInterface_t
{ {
WEAPOVERLAYINTERFACE_NONE = 0x0, WEAPOVERLAYINTERFACE_NONE = 0x0,
WEAPOVERLAYINTERFACE_JAVELIN = 0x1, WEAPOVERLAYINTERFACE_JAVELIN = 0x1,
@@ -3150,7 +3150,7 @@ namespace IW3
Material* overlayMaterial; Material* overlayMaterial;
Material* overlayMaterialLowRes; Material* overlayMaterialLowRes;
weapOverlayReticle_t overlayReticle; weapOverlayReticle_t overlayReticle;
WeapOverlayInteface_t overlayInterface; WeapOverlayInterface_t overlayInterface;
float overlayWidth; float overlayWidth;
float overlayHeight; float overlayHeight;
float fAdsBobFactor; float fAdsBobFactor;
+2
View File
@@ -52,6 +52,8 @@ namespace
"vertexdecl", "vertexdecl",
"vertexshader", "vertexshader",
"pixelshader", "pixelshader",
"accuracygraph",
"flametable",
}; };
static_assert(std::extent_v<decltype(SUB_ASSET_TYPE_NAMES)> == SUB_ASSET_TYPE_COUNT); static_assert(std::extent_v<decltype(SUB_ASSET_TYPE_NAMES)> == SUB_ASSET_TYPE_COUNT);
} // namespace } // namespace
+67
View File
@@ -60,6 +60,8 @@ namespace T4
SUB_ASSET_TYPE_VERTEX_DECL, SUB_ASSET_TYPE_VERTEX_DECL,
SUB_ASSET_TYPE_VERTEX_SHADER, SUB_ASSET_TYPE_VERTEX_SHADER,
SUB_ASSET_TYPE_PIXEL_SHADER, SUB_ASSET_TYPE_PIXEL_SHADER,
SUB_ASSET_TYPE_ACCURACY_GRAPH,
SUB_ASSET_TYPE_FLAME_TABLE,
SUB_ASSET_TYPE_COUNT SUB_ASSET_TYPE_COUNT
}; };
@@ -83,6 +85,69 @@ namespace T4
XAsset* assets; 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<ASSET_TYPE_PHYSPRESET, PhysPreset>; using AssetPhysPreset = Asset<ASSET_TYPE_PHYSPRESET, PhysPreset>;
using AssetPhysConstraints = Asset<ASSET_TYPE_PHYSCONSTRAINTS, PhysConstraints>; using AssetPhysConstraints = Asset<ASSET_TYPE_PHYSCONSTRAINTS, PhysConstraints>;
using AssetDestructibleDef = Asset<ASSET_TYPE_DESTRUCTIBLEDEF, DestructibleDef>; using AssetDestructibleDef = Asset<ASSET_TYPE_DESTRUCTIBLEDEF, DestructibleDef>;
@@ -117,6 +182,8 @@ namespace T4
using SubAssetVertexDecl = SubAsset<SUB_ASSET_TYPE_VERTEX_DECL, MaterialVertexDeclaration>; using SubAssetVertexDecl = SubAsset<SUB_ASSET_TYPE_VERTEX_DECL, MaterialVertexDeclaration>;
using SubAssetVertexShader = SubAsset<SUB_ASSET_TYPE_VERTEX_SHADER, MaterialVertexShader>; using SubAssetVertexShader = SubAsset<SUB_ASSET_TYPE_VERTEX_SHADER, MaterialVertexShader>;
using SubAssetPixelShader = SubAsset<SUB_ASSET_TYPE_PIXEL_SHADER, MaterialPixelShader>; using SubAssetPixelShader = SubAsset<SUB_ASSET_TYPE_PIXEL_SHADER, MaterialPixelShader>;
using SubAssetAccuracyGraph = SubAsset<SUB_ASSET_TYPE_ACCURACY_GRAPH, AccuracyGraph>;
using SubAssetFlameTable = SubAsset<SUB_ASSET_TYPE_FLAME_TABLE, FlameTable>;
} // namespace T4 } // namespace T4
DEFINE_ASSET_NAME_ACCESSOR(T4::AssetPhysPreset, name); DEFINE_ASSET_NAME_ACCESSOR(T4::AssetPhysPreset, name);
+91 -22
View File
@@ -1013,6 +1013,8 @@ namespace T4
SURF_TYPE_CUSHION, SURF_TYPE_CUSHION,
SURF_TYPE_FRUIT, SURF_TYPE_FRUIT,
SURF_TYPE_PAINTED_METAL, SURF_TYPE_PAINTED_METAL,
SURF_TYPE_PLAYER,
SURF_TYPE_TALL_GRASS,
SURF_TYPE_NUM SURF_TYPE_NUM
}; };
@@ -2999,7 +3001,11 @@ namespace T4
WEAPTYPE_GRENADE = 0x1, WEAPTYPE_GRENADE = 0x1,
WEAPTYPE_PROJECTILE = 0x2, WEAPTYPE_PROJECTILE = 0x2,
WEAPTYPE_BINOCULARS = 0x3, WEAPTYPE_BINOCULARS = 0x3,
WEAPTYPE_NUM = 0x4, WEAPTYPE_GAS = 0x4,
WEAPTYPE_BOMB = 0x5,
WEAPTYPE_MINE = 0x6,
WEAPTYPE_NUM,
}; };
enum weapClass_t enum weapClass_t
@@ -3013,8 +3019,10 @@ namespace T4
WEAPCLASS_ROCKETLAUNCHER = 0x6, WEAPCLASS_ROCKETLAUNCHER = 0x6,
WEAPCLASS_TURRET = 0x7, WEAPCLASS_TURRET = 0x7,
WEAPCLASS_NON_PLAYER = 0x8, WEAPCLASS_NON_PLAYER = 0x8,
WEAPCLASS_ITEM = 0x9, WEAPCLASS_GAS = 0x9,
WEAPCLASS_NUM = 0xA, WEAPCLASS_ITEM = 0xA,
WEAPCLASS_NUM,
}; };
enum PenetrateType enum PenetrateType
@@ -3023,7 +3031,8 @@ namespace T4
PENETRATE_TYPE_SMALL = 0x1, PENETRATE_TYPE_SMALL = 0x1,
PENETRATE_TYPE_MEDIUM = 0x2, PENETRATE_TYPE_MEDIUM = 0x2,
PENETRATE_TYPE_LARGE = 0x3, PENETRATE_TYPE_LARGE = 0x3,
PENETRATE_TYPE_COUNT = 0x4,
PENETRATE_TYPE_NUM,
}; };
enum ImpactType enum ImpactType
@@ -3035,9 +3044,13 @@ namespace T4
IMPACT_TYPE_SHOTGUN = 0x4, IMPACT_TYPE_SHOTGUN = 0x4,
IMPACT_TYPE_GRENADE_BOUNCE = 0x5, IMPACT_TYPE_GRENADE_BOUNCE = 0x5,
IMPACT_TYPE_GRENADE_EXPLODE = 0x6, IMPACT_TYPE_GRENADE_EXPLODE = 0x6,
IMPACT_TYPE_ROCKET_EXPLODE = 0x7, IMPACT_TYPE_RIFLE_GRENADE = 0x7,
IMPACT_TYPE_PROJECTILE_DUD = 0x8, IMPACT_TYPE_ROCKET_EXPLODE = 0x8,
IMPACT_TYPE_COUNT = 0x9, IMPACT_TYPE_PROJECTILE_DUD = 0x9,
IMPACT_TYPE_MORTAR_SHELL = 0xA,
IMPACT_TYPE_TANK_SHELL = 0xB,
IMPACT_TYPE_NUM,
}; };
enum weapInventoryType_t enum weapInventoryType_t
@@ -3046,7 +3059,8 @@ namespace T4
WEAPINVENTORY_OFFHAND = 0x1, WEAPINVENTORY_OFFHAND = 0x1,
WEAPINVENTORY_ITEM = 0x2, WEAPINVENTORY_ITEM = 0x2,
WEAPINVENTORY_ALTMODE = 0x3, WEAPINVENTORY_ALTMODE = 0x3,
WEAPINVENTORYCOUNT = 0x4,
WEAPINVENTORY_NUM,
}; };
enum weapFireType_t enum weapFireType_t
@@ -3056,7 +3070,8 @@ namespace T4
WEAPON_FIRETYPE_BURSTFIRE2 = 0x2, WEAPON_FIRETYPE_BURSTFIRE2 = 0x2,
WEAPON_FIRETYPE_BURSTFIRE3 = 0x3, WEAPON_FIRETYPE_BURSTFIRE3 = 0x3,
WEAPON_FIRETYPE_BURSTFIRE4 = 0x4, WEAPON_FIRETYPE_BURSTFIRE4 = 0x4,
WEAPON_FIRETYPECOUNT = 0x5,
WEAPON_FIRETYPE_NUM,
}; };
enum OffhandClass enum OffhandClass
@@ -3065,7 +3080,8 @@ namespace T4
OFFHAND_CLASS_FRAG_GRENADE = 0x1, OFFHAND_CLASS_FRAG_GRENADE = 0x1,
OFFHAND_CLASS_SMOKE_GRENADE = 0x2, OFFHAND_CLASS_SMOKE_GRENADE = 0x2,
OFFHAND_CLASS_FLASH_GRENADE = 0x3, OFFHAND_CLASS_FLASH_GRENADE = 0x3,
OFFHAND_CLASS_COUNT = 0x4,
OFFHAND_CLASS_NUM,
}; };
enum weapStance_t enum weapStance_t
@@ -3073,7 +3089,8 @@ namespace T4
WEAPSTANCE_STAND = 0x0, WEAPSTANCE_STAND = 0x0,
WEAPSTANCE_DUCK = 0x1, WEAPSTANCE_DUCK = 0x1,
WEAPSTANCE_PRONE = 0x2, WEAPSTANCE_PRONE = 0x2,
WEAPSTANCE_NUM = 0x3,
WEAPSTANCE_NUM,
}; };
enum activeReticleType_t enum activeReticleType_t
@@ -3081,7 +3098,8 @@ namespace T4
VEH_ACTIVE_RETICLE_NONE = 0x0, VEH_ACTIVE_RETICLE_NONE = 0x0,
VEH_ACTIVE_RETICLE_PIP_ON_A_STICK = 0x1, VEH_ACTIVE_RETICLE_PIP_ON_A_STICK = 0x1,
VEH_ACTIVE_RETICLE_BOUNCING_DIAMOND = 0x2, VEH_ACTIVE_RETICLE_BOUNCING_DIAMOND = 0x2,
VEH_ACTIVE_RETICLE_COUNT = 0x3,
VEH_ACTIVE_RETICLE_NUM,
}; };
enum weaponIconRatioType_t enum weaponIconRatioType_t
@@ -3089,7 +3107,8 @@ namespace T4
WEAPON_ICON_RATIO_1TO1 = 0x0, WEAPON_ICON_RATIO_1TO1 = 0x0,
WEAPON_ICON_RATIO_2TO1 = 0x1, WEAPON_ICON_RATIO_2TO1 = 0x1,
WEAPON_ICON_RATIO_4TO1 = 0x2, WEAPON_ICON_RATIO_4TO1 = 0x2,
WEAPON_ICON_RATIO_COUNT = 0x3,
WEAPON_ICON_RATIO_NUM,
}; };
enum weapClipType_t enum weapClipType_t
@@ -3100,7 +3119,8 @@ namespace T4
WEAPON_CLIPTYPE_DP28 = 0x3, WEAPON_CLIPTYPE_DP28 = 0x3,
WEAPON_CLIPTYPE_PTRS = 0x4, WEAPON_CLIPTYPE_PTRS = 0x4,
WEAPON_CLIPTYPE_LMG = 0x5, WEAPON_CLIPTYPE_LMG = 0x5,
WEAPON_CLIPTYPECOUNT = 0x6,
WEAPON_CLIPTYPE_NUM,
}; };
enum ammoCounterClipType_t enum ammoCounterClipType_t
@@ -3112,22 +3132,25 @@ namespace T4
AMMO_COUNTER_CLIP_ROCKET = 0x4, AMMO_COUNTER_CLIP_ROCKET = 0x4,
AMMO_COUNTER_CLIP_BELTFED = 0x5, AMMO_COUNTER_CLIP_BELTFED = 0x5,
AMMO_COUNTER_CLIP_ALTWEAPON = 0x6, AMMO_COUNTER_CLIP_ALTWEAPON = 0x6,
AMMO_COUNTER_CLIP_COUNT = 0x7,
AMMO_COUNTER_CLIP_NUM,
}; };
enum weapOverlayReticle_t enum weapOverlayReticle_t
{ {
WEAPOVERLAYRETICLE_NONE = 0x0, WEAPOVERLAYRETICLE_NONE = 0x0,
WEAPOVERLAYRETICLE_CROSSHAIR = 0x1, WEAPOVERLAYRETICLE_CROSSHAIR = 0x1,
WEAPOVERLAYRETICLE_NUM = 0x2,
WEAPOVERLAYRETICLE_NUM,
}; };
enum WeapOverlayInteface_t enum WeapOverlayInterface_t
{ {
WEAPOVERLAYINTERFACE_NONE = 0x0, WEAPOVERLAYINTERFACE_NONE = 0x0,
WEAPOVERLAYINTERFACE_JAVELIN = 0x1, WEAPOVERLAYINTERFACE_JAVELIN = 0x1,
WEAPOVERLAYINTERFACE_TURRETSCOPE = 0x2, WEAPOVERLAYINTERFACE_TURRETSCOPE = 0x2,
WEAPOVERLAYINTERFACECOUNT = 0x3,
WEAPOVERLAYINTERFACE_NUM,
}; };
enum weapProjExposion_t enum weapProjExposion_t
@@ -3139,7 +3162,10 @@ namespace T4
WEAPPROJEXP_DUD = 0x4, WEAPPROJEXP_DUD = 0x4,
WEAPPROJEXP_SMOKE = 0x5, WEAPPROJEXP_SMOKE = 0x5,
WEAPPROJEXP_HEAVY = 0x6, WEAPPROJEXP_HEAVY = 0x6,
WEAPPROJEXP_NUM = 0x7, WEAPPROJEXP_FIRE = 0x7,
WEAPPROJEXP_NAPALMBLOB = 0x8,
WEAPPROJEXP_NUM,
}; };
enum WeapStickinessType enum WeapStickinessType
@@ -3148,7 +3174,8 @@ namespace T4
WEAPSTICKINESS_ALL = 0x1, WEAPSTICKINESS_ALL = 0x1,
WEAPSTICKINESS_GROUND = 0x2, WEAPSTICKINESS_GROUND = 0x2,
WEAPSTICKINESS_GROUND_WITH_YAW = 0x3, WEAPSTICKINESS_GROUND_WITH_YAW = 0x3,
WEAPSTICKINESS_COUNT = 0x4,
WEAPSTICKINESS_NUM,
}; };
enum guidedMissileType_t enum guidedMissileType_t
@@ -3158,7 +3185,49 @@ namespace T4
MISSILE_GUIDANCE_HELLFIRE = 0x2, MISSILE_GUIDANCE_HELLFIRE = 0x2,
MISSILE_GUIDANCE_JAVELIN = 0x3, MISSILE_GUIDANCE_JAVELIN = 0x3,
MISSILE_GUIDANCE_BALLISTIC = 0x4, 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 enum hitLocation_t
@@ -3586,7 +3655,7 @@ namespace T4
Material* overlayMaterial; Material* overlayMaterial;
Material* overlayMaterialLowRes; Material* overlayMaterialLowRes;
weapOverlayReticle_t overlayReticle; weapOverlayReticle_t overlayReticle;
WeapOverlayInteface_t overlayInterface; WeapOverlayInterface_t overlayInterface;
float overlayWidth; float overlayWidth;
float overlayHeight; float overlayHeight;
float fAdsBobFactor; float fAdsBobFactor;
+2 -2
View File
@@ -4295,7 +4295,7 @@ namespace T6
AMMO_COUNTER_CLIP_COUNT = 0x7, AMMO_COUNTER_CLIP_COUNT = 0x7,
}; };
enum WeapOverlayInteface_t enum WeapOverlayInterface_t
{ {
WEAPOVERLAYINTERFACE_NONE = 0x0, WEAPOVERLAYINTERFACE_NONE = 0x0,
WEAPOVERLAYINTERFACE_JAVELIN = 0x1, WEAPOVERLAYINTERFACE_JAVELIN = 0x1,
@@ -4671,7 +4671,7 @@ namespace T6
float adsMoveSpeedScale; float adsMoveSpeedScale;
float sprintDurationScale; float sprintDurationScale;
weapOverlayReticle_t overlayReticle; weapOverlayReticle_t overlayReticle;
WeapOverlayInteface_t overlayInterface; WeapOverlayInterface_t overlayInterface;
float overlayWidth; float overlayWidth;
float overlayHeight; float overlayHeight;
float fAdsBobFactor; float fAdsBobFactor;
+9
View File
@@ -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
@@ -0,0 +1,130 @@
#pragma once
#include "Game/T4/T4.h"
#include <cstddef>
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
+573
View File
@@ -0,0 +1,573 @@
#pragma once
#include "Game/T4/T4.h"
#include <cstddef>
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
@@ -0,0 +1,181 @@
#pragma once
#include "Game/T4/T4.h"
#include <type_traits>
namespace T4
{
inline const char* szWeapTypeNames[]{
"bullet",
"grenade",
"projectile",
"binoculars",
"gas",
"bomb",
"mine",
};
static_assert(std::extent_v<decltype(szWeapTypeNames)> == WEAPTYPE_NUM);
inline const char* szWeapClassNames[]{
"rifle",
"mg",
"smg",
"spread",
"pistol",
"grenade",
"rocketlauncher",
"turret",
"non-player",
"gas",
"item",
};
static_assert(std::extent_v<decltype(szWeapClassNames)> == WEAPCLASS_NUM);
inline const char* szWeapOverlayReticleNames[]{
"none",
"crosshair",
};
static_assert(std::extent_v<decltype(szWeapOverlayReticleNames)> == WEAPOVERLAYRETICLE_NUM);
inline const char* penetrateTypeNames[]{
"none",
"small",
"medium",
"large",
};
static_assert(std::extent_v<decltype(penetrateTypeNames)> == 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<decltype(impactTypeNames)> == IMPACT_TYPE_NUM);
inline const char* szWeapStanceNames[]{
"stand",
"duck",
"prone",
};
static_assert(std::extent_v<decltype(szWeapStanceNames)> == WEAPSTANCE_NUM);
inline const char* szProjectileExplosionNames[]{
"grenade",
"rocket",
"flashbang",
"none",
"dud",
"smoke",
"heavy explosive",
"fire",
"napalmblob",
};
static_assert(std::extent_v<decltype(szProjectileExplosionNames)> == WEAPPROJEXP_NUM);
inline const char* offhandClassNames[]{
"None",
"Frag Grenade",
"Smoke Grenade",
"Flash Grenade",
};
static_assert(std::extent_v<decltype(offhandClassNames)> == 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<decltype(activeReticleNames)> == VEH_ACTIVE_RETICLE_NUM);
inline const char* guidedMissileNames[]{
"None",
"Sidewinder",
"Hellfire",
"Javelin",
"Ballistic",
};
static_assert(std::extent_v<decltype(guidedMissileNames)> == 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<decltype(stickinessNames)> == WEAPSTICKINESS_NUM);
inline const char* overlayInterfaceNames[]{
"None",
"Javelin",
"Turret Scope",
};
static_assert(std::extent_v<decltype(overlayInterfaceNames)> == WEAPOVERLAYINTERFACE_NUM);
inline const char* szWeapInventoryTypeNames[]{
"primary",
"offhand",
"item",
"altmode",
};
static_assert(std::extent_v<decltype(szWeapInventoryTypeNames)> == WEAPINVENTORY_NUM);
inline const char* szWeapFireTypeNames[]{
"Full Auto",
"Single Shot",
"2-Round Burst",
"3-Round Burst",
"4-Round Burst",
};
static_assert(std::extent_v<decltype(szWeapFireTypeNames)> == WEAPON_FIRETYPE_NUM);
inline const char* szWeapClipTypeNames[]{
"bottom",
"top",
"left",
"dp28",
"ptrs",
"lmg",
};
static_assert(std::extent_v<decltype(szWeapClipTypeNames)> == WEAPON_CLIPTYPE_NUM);
inline const char* ammoCounterClipNames[]{
"None",
"Magazine",
"ShortMagazine",
"Shotgun",
"Rocket",
"Beltfed",
"AltWeapon",
};
static_assert(std::extent_v<decltype(ammoCounterClipNames)> == AMMO_COUNTER_CLIP_NUM);
inline const char* weapIconRatioNames[]{
"1:1",
"2:1",
"4:1",
};
static_assert(std::extent_v<decltype(weapIconRatioNames)> == 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<decltype(bounceSoundSuffixes)> == SURF_TYPE_NUM);
} // namespace T4
@@ -303,15 +303,16 @@ namespace
return strcmp(weapon.szInternalName, "defaultweapon") == 0 || strcmp(weapon.szInternalName, "defaultweapon_mp") == 0; 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<AssetWeapon>& registration)
{ {
auto* aliasListName = memory.Alloc<snd_alias_list_name>(); auto* aliasListName = memory.Alloc<snd_alias_list_name>();
aliasListName->soundName = name; aliasListName->soundName = name;
registration.AddIndirectAssetReference(context.LoadIndirectAssetReference<AssetSound>(name));
return aliasListName; return aliasListName;
} }
void SetWeaponDefaults(WeaponDef& weapon, MemoryManager& memory) void SetWeaponDefaults(WeaponDef& weapon, MemoryManager& memory, AssetCreationContext& context, AssetRegistration<AssetWeapon>& registration)
{ {
if (IsDefaultWeapon(weapon)) if (IsDefaultWeapon(weapon))
return; return;
@@ -321,15 +322,15 @@ namespace
if (!weapon.worldLastShotEjectEffect) if (!weapon.worldLastShotEjectEffect)
weapon.worldLastShotEjectEffect = weapon.worldShellEjectEffect; weapon.worldLastShotEjectEffect = weapon.worldShellEjectEffect;
if (!weapon.raiseSound.name) if (!weapon.raiseSound.name)
SetDefaultSound("weap_raise", memory); SetDefaultSound("weap_raise", memory, context, registration);
if (!weapon.putawaySound.name) if (!weapon.putawaySound.name)
SetDefaultSound("weap_putaway", memory); SetDefaultSound("weap_putaway", memory, context, registration);
if (!weapon.pickupSound.name) if (!weapon.pickupSound.name)
SetDefaultSound("weap_pickup", memory); SetDefaultSound("weap_pickup", memory, context, registration);
if (!weapon.ammoPickupSound.name) if (!weapon.ammoPickupSound.name)
SetDefaultSound("weap_ammo_pickup", memory); SetDefaultSound("weap_ammo_pickup", memory, context, registration);
if (!weapon.emptyFireSound.name) if (!weapon.emptyFireSound.name)
SetDefaultSound("weap_dryfire_smg_npc", memory); SetDefaultSound("weap_dryfire_smg_npc", memory, context, registration);
} }
void SetupTransitionTimes(WeaponDef& weapon) void SetupTransitionTimes(WeaponDef& weapon)
@@ -356,13 +357,13 @@ namespace
weapon.fMinDamageRange = 999999.12f; // oddly specific number, no clue weapon.fMinDamageRange = 999999.12f; // oddly specific number, no clue
} }
void CheckCrosshairValues(WeaponDef& weapon) void CheckCrosshairValues(const WeaponDef& weapon)
{ {
if (weapon.enemyCrosshairRange > 15000.0f) if (weapon.enemyCrosshairRange > 15000.0f)
con::warn("Weapon {}: Enemy crosshair ranges should be less than 15000", weapon.szInternalName); 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) if (weapon.weapType != WEAPTYPE_PROJECTILE)
return; return;
@@ -399,8 +400,6 @@ namespace weapon
AssetCreationResult InfoStringLoaderIW3::CreateAsset(const std::string& assetName, const InfoString& infoString, AssetCreationContext& context) const AssetCreationResult InfoStringLoaderIW3::CreateAsset(const std::string& assetName, const InfoString& infoString, AssetCreationContext& context) const
{ {
auto* weaponDef = m_memory.Alloc<WeaponDef>(); auto* weaponDef = m_memory.Alloc<WeaponDef>();
memset(weaponDef, 0, sizeof(WeaponDef));
InitWeaponDef(*weaponDef); InitWeaponDef(*weaponDef);
weaponDef->szInternalName = m_memory.Dup(assetName.c_str()); weaponDef->szInternalName = m_memory.Dup(assetName.c_str());
@@ -420,7 +419,7 @@ namespace weapon
return AssetCreationResult::Failure(); return AssetCreationResult::Failure();
} }
SetWeaponDefaults(*weaponDef, m_memory); SetWeaponDefaults(*weaponDef, m_memory, context, registration);
SetupTransitionTimes(*weaponDef); SetupTransitionTimes(*weaponDef);
CheckWeaponDamageRanges(*weaponDef); CheckWeaponDamageRanges(*weaponDef);
CheckCrosshairValues(*weaponDef); CheckCrosshairValues(*weaponDef);
@@ -0,0 +1,164 @@
#include "InfoStringToStructConverter.h"
#include "Utils/Logging/Log.h"
#include <cassert>
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<csParseFieldType_t>(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<FxEffectDef**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset) = nullptr;
return true;
}
auto* fx = m_context.LoadDependency<AssetFx>(value);
if (fx == nullptr)
{
con::error("Failed to load fx asset \"{}\"", value);
return false;
}
m_registration.AddDependency(fx);
*reinterpret_cast<FxEffectDef**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset) = fx->Asset();
return true;
}
case CSPFT_XMODEL:
{
if (value.empty())
{
*reinterpret_cast<XModel**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset) = nullptr;
return true;
}
auto* xmodel = m_context.LoadDependency<AssetXModel>(value);
if (xmodel == nullptr)
{
con::error("Failed to load xmodel asset \"{}\"", value);
return false;
}
m_registration.AddDependency(xmodel);
*reinterpret_cast<XModel**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset) = xmodel->Asset();
return true;
}
case CSPFT_MATERIAL:
{
if (value.empty())
{
*reinterpret_cast<Material**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset) = nullptr;
return true;
}
auto* material = m_context.LoadDependency<AssetMaterial>(value);
if (material == nullptr)
{
con::error("Failed to load material asset \"{}\"", value);
return false;
}
m_registration.AddDependency(material);
*reinterpret_cast<Material**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset) = material->Asset();
return true;
}
case CSPFT_SOUND:
{
auto* sound = reinterpret_cast<SndAliasCustom*>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset);
if (value.empty())
{
sound->name = nullptr;
return true;
}
auto* name = m_memory.Alloc<snd_alias_list_name>();
name->soundName = m_memory.Dup(value.c_str());
sound->name = name;
m_registration.AddIndirectAssetReference(m_context.LoadIndirectAssetReference<AssetSound>(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;
}
@@ -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
+9
View File
@@ -3,10 +3,14 @@
#include "Asset/GlobalAssetPoolsLoader.h" #include "Asset/GlobalAssetPoolsLoader.h"
#include "Game/T4/AssetMarkerT4.h" #include "Game/T4/AssetMarkerT4.h"
#include "Game/T4/T4.h" #include "Game/T4/T4.h"
#include "Game/T4/Weapon/AccuracyGraphLoaderT4.h"
#include "Game/T4/XAnim/XAnimLoaderT4.h" #include "Game/T4/XAnim/XAnimLoaderT4.h"
#include "Localize/AssetLoaderLocalizeT4.h" #include "Localize/AssetLoaderLocalizeT4.h"
#include "Maps/MapEntsLoaderT4.h" #include "Maps/MapEntsLoaderT4.h"
#include "RawFile/AssetLoaderRawFileT4.h" #include "RawFile/AssetLoaderRawFileT4.h"
#include "Weapon/FlameTableLoaderT4.h"
#include "Weapon/WeaponGdtLoaderT4.h"
#include "Weapon/WeaponRawLoaderT4.h"
using namespace T4; using namespace T4;
@@ -92,6 +96,11 @@ namespace
collection.AddAssetCreator(localize::CreateLoaderT4(memory, searchPath, zone)); collection.AddAssetCreator(localize::CreateLoaderT4(memory, searchPath, zone));
collection.AddAssetCreator(map_ents::CreateLoaderT4(memory, searchPath)); collection.AddAssetCreator(map_ents::CreateLoaderT4(memory, searchPath));
collection.AddAssetCreator(raw_file::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 } // namespace
@@ -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 <cassert>
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<SubAssetFlameTable>& registration,
const cspField_t* fields,
const size_t fieldCount)
: InfoStringToStructConverter(infoString, &flameTable, zoneScriptStrings, memory, context, registration, fields, fieldCount)
{
}
};
class FlameTableLoaderT4 final : public SubAssetCreator<SubAssetFlameTable>
{
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<FlameTable>();
AssetRegistration<SubAssetFlameTable> registration(assetName, flameTable);
InfoStringToFlameTableConverter converter(
infoString, *flameTable, m_zone.m_script_strings, m_memory, context, registration, flameTableFields, std::extent_v<decltype(flameTableFields)>);
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<ISubAssetCreator> CreateFlameTableLoaderT4(MemoryManager& memory, ISearchPath& searchPath, Zone& zone)
{
return std::make_unique<FlameTableLoaderT4>(memory, searchPath, zone);
}
} // namespace weapon
@@ -0,0 +1,13 @@
#pragma once
#include "Asset/IAssetCreator.h"
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"
#include "Zone/Zone.h"
#include <memory>
namespace weapon
{
std::unique_ptr<ISubAssetCreator> CreateFlameTableLoaderT4(MemoryManager& memory, ISearchPath& searchPath, Zone& zone);
} // namespace weapon
@@ -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 <format>
using namespace T4;
namespace
{
class GdtLoaderWeapon final : public AssetCreator<AssetWeapon>
{
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<AssetCreator<AssetWeapon>> CreateGdtLoaderT4(MemoryManager& memory, ISearchPath& searchPath, IGdtQueryable& gdt, Zone& zone)
{
return std::make_unique<GdtLoaderWeapon>(memory, searchPath, gdt, zone);
}
} // namespace weapon
@@ -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 <memory>
namespace weapon
{
std::unique_ptr<AssetCreator<T4::AssetWeapon>> CreateGdtLoaderT4(MemoryManager& memory, ISearchPath& searchPath, IGdtQueryable& gdt, Zone& zone);
} // namespace weapon
@@ -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 <cassert>
#include <cstring>
#include <sstream>
#include <type_traits>
#include <vector>
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<std::string> tags;
std::string tag;
while (ss >> tag)
tags.emplace_back(std::move(tag));
if (tags.size() > std::extent_v<decltype(WeaponDef::hideTags)>)
{
con::error("Cannot have more than {} hide tags!", std::extent_v<decltype(WeaponDef::hideTags)>);
return false;
}
auto* hideTags = reinterpret_cast<scr_string_t*>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset);
if (tags.size() < std::extent_v<decltype(WeaponDef::hideTags)>)
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<decltype(WeaponDef::hideTags)>; 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<SndAliasCustom**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset);
if (value.empty())
{
*bounceSound = nullptr;
return true;
}
static_assert(std::extent_v<decltype(bounceSoundSuffixes)> == std::extent_v<decltype(WeaponDef::parallelBounce)>);
*bounceSound = m_memory.Alloc<SndAliasCustom>(std::extent_v<decltype(bounceSoundSuffixes)>);
for (auto i = 0u; i < std::extent_v<decltype(bounceSoundSuffixes)>; i++)
{
const auto currentBounceSound = value + bounceSoundSuffixes[i];
(*bounceSound)[i].name = m_memory.Alloc<snd_alias_list_name>();
(*bounceSound)[i].name->soundName = m_memory.Dup(currentBounceSound.c_str());
m_registration.AddIndirectAssetReference(m_context.LoadIndirectAssetReference<AssetSound>(currentBounceSound));
}
return true;
}
[[nodiscard]] bool ConvertNotetrackSoundMap(const cspField_t& field, const std::string& value)
{
std::istringstream ss(value);
std::vector<std::string> 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<const char**>(m_structure),
tokens.back());
tokens.pop_back();
}
const auto pairCount = tokens.size() / 2;
if (pairCount > std::extent_v<decltype(WeaponDef::notetrackSoundMapKeys)>)
{
con::error("Cannot have more than {} notetracksoundmap entries!", std::extent_v<decltype(WeaponDef::notetrackSoundMapKeys)>);
return false;
}
auto* keys = reinterpret_cast<scr_string_t*>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset);
auto* values = &keys[std::extent_v<decltype(WeaponDef::notetrackSoundMapKeys)>];
auto currentEntryNum = 0u;
if (pairCount < std::extent_v<decltype(WeaponDef::notetrackSoundMapKeys)>)
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<decltype(WeaponDef::notetrackSoundMapKeys)>; 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<AssetXAnim>(value));
return true;
}
return false;
}
protected:
bool ConvertExtensionField(const cspField_t& field, const std::string& value) override
{
switch (static_cast<weapFieldType_t>(field.iFieldType))
{
case WFT_WEAPONTYPE:
return ConvertEnumInt(field.szName, value, field.iOffset, szWeapTypeNames, std::extent_v<decltype(szWeapTypeNames)>);
case WFT_WEAPONCLASS:
return ConvertEnumInt(field.szName, value, field.iOffset, szWeapClassNames, std::extent_v<decltype(szWeapClassNames)>);
case WFT_OVERLAYRETICLE:
return ConvertEnumInt(field.szName, value, field.iOffset, szWeapOverlayReticleNames, std::extent_v<decltype(szWeapOverlayReticleNames)>);
case WFT_PENETRATE_TYPE:
return ConvertEnumInt(field.szName, value, field.iOffset, penetrateTypeNames, std::extent_v<decltype(penetrateTypeNames)>);
case WFT_IMPACT_TYPE:
return ConvertEnumInt(field.szName, value, field.iOffset, impactTypeNames, std::extent_v<decltype(impactTypeNames)>);
case WFT_STANCE:
return ConvertEnumInt(field.szName, value, field.iOffset, szWeapStanceNames, std::extent_v<decltype(szWeapStanceNames)>);
case WFT_PROJ_EXPLOSION:
return ConvertEnumInt(field.szName, value, field.iOffset, szProjectileExplosionNames, std::extent_v<decltype(szProjectileExplosionNames)>);
case WFT_OFFHAND_CLASS:
return ConvertEnumInt(field.szName, value, field.iOffset, offhandClassNames, std::extent_v<decltype(offhandClassNames)>);
case WFT_ANIMTYPE:
return ConvertEnumInt(field.szName, value, field.iOffset, playerAnimTypeNames, std::extent_v<decltype(playerAnimTypeNames)>);
case WFT_ACTIVE_RETICLE_TYPE:
return ConvertEnumInt(field.szName, value, field.iOffset, activeReticleNames, std::extent_v<decltype(activeReticleNames)>);
case WFT_GUIDED_MISSILE_TYPE:
return ConvertEnumInt(field.szName, value, field.iOffset, guidedMissileNames, std::extent_v<decltype(guidedMissileNames)>);
case WFT_BOUNCE_SOUND:
return ConvertBounceSounds(field, value);
case WFT_STICKINESS:
return ConvertEnumInt(field.szName, value, field.iOffset, stickinessNames, std::extent_v<decltype(stickinessNames)>);
case WFT_OVERLAYINTERFACE:
return ConvertEnumInt(field.szName, value, field.iOffset, overlayInterfaceNames, std::extent_v<decltype(overlayInterfaceNames)>);
case WFT_INVENTORYTYPE:
return ConvertEnumInt(field.szName, value, field.iOffset, szWeapInventoryTypeNames, std::extent_v<decltype(szWeapInventoryTypeNames)>);
case WFT_FIRETYPE:
return ConvertEnumInt(field.szName, value, field.iOffset, szWeapFireTypeNames, std::extent_v<decltype(szWeapFireTypeNames)>);
case WFT_CLIPTYPE:
return ConvertEnumInt(field.szName, value, field.iOffset, szWeapClipTypeNames, std::extent_v<decltype(szWeapClipTypeNames)>);
case WFT_AMMOCOUNTER_CLIPTYPE:
return ConvertEnumInt(field.szName, value, field.iOffset, ammoCounterClipNames, std::extent_v<decltype(ammoCounterClipNames)>);
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<decltype(weapIconRatioNames)>);
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<AssetWeapon>& 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<const char**>(reinterpret_cast<char*>(&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<SubAssetAccuracyGraph>(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<AssetWeapon>& registration, AssetCreationContext& context)
{
flameTablePtr = nullptr;
if (!flameTableName || flameTableName[0] == '\0')
return true;
auto* flameTableAsset = context.LoadSubAsset<SubAssetFlameTable>(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<AssetWeapon>& 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<AssetWeapon>& registration)
{
auto* aliasListName = memory.Alloc<snd_alias_list_name>();
aliasListName->soundName = name;
registration.AddIndirectAssetReference(context.LoadIndirectAssetReference<AssetSound>(name));
return aliasListName;
}
void SetWeaponDefaults(WeaponDef& weapon, MemoryManager& memory, AssetCreationContext& context, AssetRegistration<AssetWeapon>& 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<float>(weapon.iAdsTransInTime);
if (weapon.iAdsTransOutTime <= 0)
weapon.fOOPosAnimLength[1] = 1.0f / 500.0f;
else
weapon.fOOPosAnimLength[1] = 1.0f / static_cast<float>(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<char*>(weapon.szAmmoName));
if (weapon.szClipName)
utils::MakeStringLowerCase(const_cast<char*>(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<WeaponDef>();
InitWeaponDef(*weaponDef);
weaponDef->szInternalName = m_memory.Dup(assetName.c_str());
AssetRegistration<AssetWeapon> registration(assetName, weaponDef);
InfoStringToWeaponConverter converter(
infoString, *weaponDef, m_zone.m_script_strings, m_memory, context, registration, weapon_fields, std::extent_v<decltype(weapon_fields)>);
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
@@ -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
@@ -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<AssetWeapon>
{
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<AssetCreator<AssetWeapon>> CreateRawLoaderT4(MemoryManager& memory, ISearchPath& searchPath, Zone& zone)
{
return std::make_unique<RawLoaderWeapon>(memory, searchPath, zone);
}
} // namespace weapon
@@ -0,0 +1,13 @@
#pragma once
#include "Asset/IAssetCreator.h"
#include "Game/T4/T4.h"
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"
#include <memory>
namespace weapon
{
std::unique_ptr<AssetCreator<T4::AssetWeapon>> CreateRawLoaderT4(MemoryManager& memory, ISearchPath& searchPath, Zone& zone);
} // namespace weapon
@@ -395,7 +395,7 @@ namespace
con::warn("Weapon {}: Enemy crosshair ranges should be less than 15000", weapon.weapVariantDef.szInternalName); 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) if (weapon.weapDef.weapType != WEAPTYPE_PROJECTILE)
return; return;
@@ -544,13 +544,13 @@ namespace
weapon.weapDef.damageRange[5] = 999999.12f; // oddly specific number, no clue 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) if (weapon.weapDef.enemyCrosshairRange > 15000.0f)
con::warn("Weapon {}: Enemy crosshair ranges should be less than 15000", weapon.weapVariantDef.szInternalName); 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) if (weapon.weapDef.weapType != WEAPTYPE_PROJECTILE)
return; 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>(); auto* weaponFullDef = m_memory.Alloc<WeaponFullDef>();
weaponFullDef->weapVariantDef.szInternalName = m_memory.Dup(assetName.c_str()); weaponFullDef->weapVariantDef.szInternalName = m_memory.Dup(assetName.c_str());
@@ -11,7 +11,7 @@ namespace weapon
public: public:
InfoStringLoaderT6(MemoryManager& memory, ISearchPath& searchPath, Zone& zone); 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: private:
MemoryManager& m_memory; MemoryManager& m_memory;
@@ -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" #filename "Game/" + GAME + "/Weapon/AccuracyGraphLoader" + GAME + ".cpp"
@@ -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" #filename "Game/" + GAME + "/Weapon/AccuracyGraphLoader" + GAME + ".h"
@@ -0,0 +1,123 @@
#include "InfoStringFromStructConverter.h"
#include <cassert>
using namespace T4;
void InfoStringFromStructConverter::FillFromBaseField(const cspField_t& field)
{
switch (static_cast<csParseFieldType_t>(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<FxEffectDef**>(reinterpret_cast<uintptr_t>(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<XModel**>(reinterpret_cast<uintptr_t>(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<Material**>(reinterpret_cast<uintptr_t>(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<SndAliasCustom*>(reinterpret_cast<uintptr_t>(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<std::string(scr_string_t)> scriptStringValueCallback)
: InfoStringFromStructConverterBase(structure, std::move(scriptStringValueCallback)),
m_fields(fields),
m_field_count(fieldCount)
{
}
@@ -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<std::string(scr_string_t)> scriptStringValueCallback);
};
} // namespace T4
+2
View File
@@ -8,6 +8,7 @@
#include "RawFile/RawFileDumperT4.h" #include "RawFile/RawFileDumperT4.h"
#include "Sound/LoadedSoundDumperT4.h" #include "Sound/LoadedSoundDumperT4.h"
#include "StringTable/StringTableDumperT4.h" #include "StringTable/StringTableDumperT4.h"
#include "Weapon/WeaponDumperT4.h"
using namespace T4; using namespace T4;
@@ -19,6 +20,7 @@ void ObjWriter::RegisterAssetDumpers(AssetDumpingContext& context)
RegisterAssetDumper(std::make_unique<sound::LoadedSoundDumperT4>()); RegisterAssetDumper(std::make_unique<sound::LoadedSoundDumperT4>());
RegisterAssetDumper(std::make_unique<map_ents::DumperT4>()); RegisterAssetDumper(std::make_unique<map_ents::DumperT4>());
RegisterAssetDumper(std::make_unique<localize::DumperT4>()); RegisterAssetDumper(std::make_unique<localize::DumperT4>());
RegisterAssetDumper(std::make_unique<weapon::DumperT4>());
RegisterAssetDumper(std::make_unique<raw_file::DumperT4>()); RegisterAssetDumper(std::make_unique<raw_file::DumperT4>());
RegisterAssetDumper(std::make_unique<string_table::DumperT4>()); RegisterAssetDumper(std::make_unique<string_table::DumperT4>());
} }
@@ -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 <cassert>
#include <sstream>
#include <type_traits>
using namespace T4;
namespace
{
class InfoStringFromWeaponConverter final : public InfoStringFromStructConverter
{
protected:
void FillFromExtensionField(const cspField_t& field) override
{
switch (static_cast<weapFieldType_t>(field.iFieldType))
{
case WFT_WEAPONTYPE:
FillFromEnumInt(std::string(field.szName), field.iOffset, szWeapTypeNames, std::extent_v<decltype(szWeapTypeNames)>);
break;
case WFT_WEAPONCLASS:
FillFromEnumInt(std::string(field.szName), field.iOffset, szWeapClassNames, std::extent_v<decltype(szWeapClassNames)>);
break;
case WFT_OVERLAYRETICLE:
FillFromEnumInt(std::string(field.szName), field.iOffset, szWeapOverlayReticleNames, std::extent_v<decltype(szWeapOverlayReticleNames)>);
break;
case WFT_PENETRATE_TYPE:
FillFromEnumInt(std::string(field.szName), field.iOffset, penetrateTypeNames, std::extent_v<decltype(penetrateTypeNames)>);
break;
case WFT_IMPACT_TYPE:
FillFromEnumInt(std::string(field.szName), field.iOffset, impactTypeNames, std::extent_v<decltype(impactTypeNames)>);
break;
case WFT_STANCE:
FillFromEnumInt(std::string(field.szName), field.iOffset, szWeapStanceNames, std::extent_v<decltype(szWeapStanceNames)>);
break;
case WFT_PROJ_EXPLOSION:
FillFromEnumInt(std::string(field.szName), field.iOffset, szProjectileExplosionNames, std::extent_v<decltype(szProjectileExplosionNames)>);
break;
case WFT_OFFHAND_CLASS:
FillFromEnumInt(std::string(field.szName), field.iOffset, offhandClassNames, std::extent_v<decltype(offhandClassNames)>);
break;
case WFT_ANIMTYPE:
FillFromEnumInt(std::string(field.szName), field.iOffset, playerAnimTypeNames, std::extent_v<decltype(playerAnimTypeNames)>);
break;
case WFT_ACTIVE_RETICLE_TYPE:
FillFromEnumInt(std::string(field.szName), field.iOffset, activeReticleNames, std::extent_v<decltype(activeReticleNames)>);
break;
case WFT_GUIDED_MISSILE_TYPE:
FillFromEnumInt(std::string(field.szName), field.iOffset, guidedMissileNames, std::extent_v<decltype(guidedMissileNames)>);
break;
case WFT_BOUNCE_SOUND:
{
const auto* bounceSound = *reinterpret_cast<SndAliasCustom**>(reinterpret_cast<uintptr_t>(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<decltype(stickinessNames)>);
break;
case WFT_OVERLAYINTERFACE:
FillFromEnumInt(std::string(field.szName), field.iOffset, overlayInterfaceNames, std::extent_v<decltype(overlayInterfaceNames)>);
break;
case WFT_INVENTORYTYPE:
FillFromEnumInt(std::string(field.szName), field.iOffset, szWeapInventoryTypeNames, std::extent_v<decltype(szWeapInventoryTypeNames)>);
break;
case WFT_FIRETYPE:
FillFromEnumInt(std::string(field.szName), field.iOffset, szWeapFireTypeNames, std::extent_v<decltype(szWeapFireTypeNames)>);
break;
case WFT_CLIPTYPE:
FillFromEnumInt(std::string(field.szName), field.iOffset, szWeapClipTypeNames, std::extent_v<decltype(szWeapClipTypeNames)>);
break;
case WFT_AMMOCOUNTER_CLIPTYPE:
FillFromEnumInt(std::string(field.szName), field.iOffset, ammoCounterClipNames, std::extent_v<decltype(ammoCounterClipNames)>);
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<decltype(weapIconRatioNames)>);
break;
case WFT_HIDETAGS:
{
const auto* hideTags = reinterpret_cast<scr_string_t*>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset);
std::stringstream ss;
bool first = true;
for (auto i = 0u; i < std::extent_v<decltype(WeaponDef::hideTags)>; 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<scr_string_t*>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset);
const auto* values = &keys[std::extent_v<decltype(WeaponDef::notetrackSoundMapKeys)>];
std::stringstream ss;
bool first = true;
for (auto i = 0u; i < std::extent_v<decltype(WeaponDef::notetrackSoundMapKeys)>; 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<std::string(scr_string_t)> 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<std::string(scr_string_t)> scriptStringValueCallback)
: InfoStringFromStructConverter(structure, fields, fieldCount, std::move(scriptStringValueCallback))
{
}
};
InfoString CreateInfoString(const XAssetInfo<WeaponDef>& asset)
{
InfoStringFromWeaponConverter converter(asset.Asset(),
weapon_fields,
std::extent_v<decltype(weapon_fields)>,
[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<WeaponDef>& asset)
{
auto* accuracyGraphWriter = context.GetZoneAssetDumperState<AccuracyGraphWriter>();
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<FlameTable>& 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<decltype(flameTableFields)>,
[](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<WeaponDef>& asset)
{
auto* deduplicator = context.GetZoneAssetDumperState<SubAssetDeduplicationDumperState<FlameTable>>();
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<AssetWeapon::Type>& 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
@@ -0,0 +1,13 @@
#pragma once
#include "Dumping/AbstractAssetDumper.h"
#include "Game/T4/T4.h"
namespace weapon
{
class DumperT4 final : public AbstractAssetDumper<T4::AssetWeapon>
{
protected:
void DumpAsset(AssetDumpingContext& context, const XAssetInfo<T4::AssetWeapon::Type>& asset) override;
};
} // namespace weapon