diff --git a/raw/iw4/techniques/distortion_scale.tech.template b/raw/iw4/techniques/distortion_scale.tech.template index 0589dc763..9797b66cf 100644 --- a/raw/iw4/techniques/distortion_scale.tech.template +++ b/raw/iw4/techniques/distortion_scale.tech.template @@ -22,13 +22,13 @@ #filename "distortion_scale" + UV_ANIM_SUFFIX + ZFEATHER_SUFFIX + DTEX_SUFFIX + ".tech" -#set VERTEX_SHADER "distortion_scale" + UV_ANIM_SUFFIX + ZFEATHER_SUFFIX + DTEX_SUFFIX + ".hlsl" -#set PIXEL_SHADER "distortion" + ZFEATHER_SUFFIX + ".hlsl" +#set VERTEX_SHADER "\"" + "distortion_scale" + UV_ANIM_SUFFIX + ZFEATHER_SUFFIX + DTEX_SUFFIX + ".hlsl" + "\"" +#set PIXEL_SHADER "\"" + "distortion" + ZFEATHER_SUFFIX + ".hlsl" + "\"" { stateMap "default"; - vertexShader 3.0 "VERTEX_SHADER" + vertexShader 3.0 VERTEX_SHADER { worldViewProjectionMatrix = constant.transposeWorldViewProjectionMatrix; #ifdef UV_ANIM @@ -37,7 +37,7 @@ distortionScale = material.distortionScale; } - pixelShader 3.0 "PIXEL_SHADER" + pixelShader 3.0 PIXEL_SHADER { normalMapSampler = material.colorMap; colorMapSampler = sampler.resolvedPostSun; diff --git a/raw/iw4/techniques/particle_cloud.tech.template b/raw/iw4/techniques/particle_cloud.tech.template index 41e22e6ed..0b27dab10 100644 --- a/raw/iw4/techniques/particle_cloud.tech.template +++ b/raw/iw4/techniques/particle_cloud.tech.template @@ -40,13 +40,13 @@ #filename "particle_cloud" + SPARK_SUFFIX + OUTDOOR_SUFFIX + PREMUL_SUFFIX + SPOT_SUFFIX + SHADOW_SUFFIX + ".tech" -#set VERTEX_SHADER "particle_cloud" + SPARK_SUFFIX + OUTDOOR_SUFFIX + SPOT_SUFFIX + ".hlsl" -#set PIXEL_SHADER "particle_cloud" + SPARK_SUFFIX + OUTDOOR_SUFFIX + SPOT_SUFFIX + SHADOW_SUFFIX + PREMUL_SUFFIX + ".hlsl" +#set VERTEX_SHADER "\"" + "particle_cloud" + SPARK_SUFFIX + OUTDOOR_SUFFIX + SPOT_SUFFIX + ".hlsl" + "\"" +#set PIXEL_SHADER "\"" + "particle_cloud" + SPARK_SUFFIX + OUTDOOR_SUFFIX + SPOT_SUFFIX + SHADOW_SUFFIX + PREMUL_SUFFIX + ".hlsl" + "\"" { stateMap "default"; - vertexShader 3.0 "VERTEX_SHADER" + vertexShader 3.0 VERTEX_SHADER { worldViewMatrix = constant.transposeWorldViewMatrix; #if MODE == "spark" @@ -62,7 +62,7 @@ #endif } - pixelShader 3.0 "PIXEL_SHADER" + pixelShader 3.0 PIXEL_SHADER { colorMapSampler = material.colorMap; #ifdef OUTDOOR diff --git a/src/Common/Game/IW4/IW4.h b/src/Common/Game/IW4/IW4.h index 3e9130ef4..d8add5ca8 100644 --- a/src/Common/Game/IW4/IW4.h +++ b/src/Common/Game/IW4/IW4.h @@ -113,6 +113,9 @@ namespace IW4 WFT_NOTETRACKSOUNDMAP, WFT_NOTETRACKRUMBLEMAP, + // Custom + WFT_ANIM_NAME, + WFT_NUM_FIELD_TYPES, }; diff --git a/src/ObjCommon/Game/IW4/InfoString/EnumStrings.h b/src/ObjCommon/Game/IW4/InfoString/EnumStrings.h index 0b39203ad..2a062838f 100644 --- a/src/ObjCommon/Game/IW4/InfoString/EnumStrings.h +++ b/src/ObjCommon/Game/IW4/InfoString/EnumStrings.h @@ -173,4 +173,10 @@ namespace IW4 "rear", "all", }; + + 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", "_painted_metal", "_riot_shield", "_slush", + }; } // namespace IW4 diff --git a/src/ObjCommon/Game/IW4/InfoString/WeaponFields.h b/src/ObjCommon/Game/IW4/InfoString/WeaponFields.h index 0f979cbde..c1845ea6a 100644 --- a/src/ObjCommon/Game/IW4/InfoString/WeaponFields.h +++ b/src/ObjCommon/Game/IW4/InfoString/WeaponFields.h @@ -28,114 +28,114 @@ namespace IW4 {"hideTags", offsetof(WeaponFullDef, hideTags), WFT_HIDETAGS }, {"notetrackSoundMap", offsetof(WeaponFullDef, notetrackSoundMapKeys), WFT_NOTETRACKSOUNDMAP }, {"notetrackRumbleMap", offsetof(WeaponFullDef, notetrackRumbleMapKeys), WFT_NOTETRACKRUMBLEMAP }, - {"idleAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_IDLE]), CSPFT_STRING }, - {"emptyIdleAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_EMPTY_IDLE]), CSPFT_STRING }, - {"fireAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_FIRE]), CSPFT_STRING }, - {"holdFireAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_HOLD_FIRE]), CSPFT_STRING }, - {"lastShotAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_LASTSHOT]), CSPFT_STRING }, - {"detonateAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_DETONATE]), CSPFT_STRING }, - {"rechamberAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_RECHAMBER]), CSPFT_STRING }, - {"meleeAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_MELEE]), CSPFT_STRING }, - {"meleeChargeAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_MELEE_CHARGE]), CSPFT_STRING }, - {"reloadAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_RELOAD]), CSPFT_STRING }, - {"reloadEmptyAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_RELOAD_EMPTY]), CSPFT_STRING }, - {"reloadStartAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_RELOAD_START]), CSPFT_STRING }, - {"reloadEndAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_RELOAD_END]), CSPFT_STRING }, - {"raiseAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_RAISE]), CSPFT_STRING }, - {"dropAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_DROP]), CSPFT_STRING }, - {"firstRaiseAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_FIRST_RAISE]), CSPFT_STRING }, - {"breachRaiseAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_BREACH_RAISE]), CSPFT_STRING }, - {"altRaiseAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_ALT_RAISE]), CSPFT_STRING }, - {"altDropAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_ALT_DROP]), CSPFT_STRING }, - {"quickRaiseAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_QUICK_RAISE]), CSPFT_STRING }, - {"quickDropAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_QUICK_DROP]), CSPFT_STRING }, - {"emptyRaiseAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_EMPTY_RAISE]), CSPFT_STRING }, - {"emptyDropAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_EMPTY_DROP]), CSPFT_STRING }, - {"sprintInAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_SPRINT_IN]), CSPFT_STRING }, - {"sprintLoopAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_SPRINT_LOOP]), CSPFT_STRING }, - {"sprintOutAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_SPRINT_OUT]), CSPFT_STRING }, - {"stunnedAnimStart", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_STUNNED_START]), CSPFT_STRING }, - {"stunnedAnimLoop", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_STUNNED_LOOP]), CSPFT_STRING }, - {"stunnedAnimEnd", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_STUNNED_END]), CSPFT_STRING }, - {"nightVisionWearAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_NIGHTVISION_WEAR]), CSPFT_STRING }, - {"nightVisionRemoveAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_NIGHTVISION_REMOVE]), CSPFT_STRING }, - {"adsFireAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_ADS_FIRE]), CSPFT_STRING }, - {"adsLastShotAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_ADS_LASTSHOT]), CSPFT_STRING }, - {"adsRechamberAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_ADS_RECHAMBER]), CSPFT_STRING }, - {"adsUpAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_ADS_UP]), CSPFT_STRING }, - {"adsDownAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_ADS_DOWN]), CSPFT_STRING }, - {"idleAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_IDLE]), CSPFT_STRING }, - {"emptyIdleAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_EMPTY_IDLE]), CSPFT_STRING }, - {"fireAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_FIRE]), CSPFT_STRING }, - {"holdFireAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_HOLD_FIRE]), CSPFT_STRING }, - {"lastShotAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_LASTSHOT]), CSPFT_STRING }, - {"detonateAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_DETONATE]), CSPFT_STRING }, - {"rechamberAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_RECHAMBER]), CSPFT_STRING }, - {"meleeAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_MELEE]), CSPFT_STRING }, - {"meleeChargeAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_MELEE_CHARGE]), CSPFT_STRING }, - {"reloadAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_RELOAD]), CSPFT_STRING }, - {"reloadEmptyAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_RELOAD_EMPTY]), CSPFT_STRING }, - {"reloadStartAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_RELOAD_START]), CSPFT_STRING }, - {"reloadEndAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_RELOAD_END]), CSPFT_STRING }, - {"raiseAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_RAISE]), CSPFT_STRING }, - {"dropAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_DROP]), CSPFT_STRING }, - {"firstRaiseAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_FIRST_RAISE]), CSPFT_STRING }, - {"breachRaiseAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_BREACH_RAISE]), CSPFT_STRING }, - {"altRaiseAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_ALT_RAISE]), CSPFT_STRING }, - {"altDropAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_ALT_DROP]), CSPFT_STRING }, - {"quickRaiseAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_QUICK_RAISE]), CSPFT_STRING }, - {"quickDropAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_QUICK_DROP]), CSPFT_STRING }, - {"emptyRaiseAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_EMPTY_RAISE]), CSPFT_STRING }, - {"emptyDropAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_EMPTY_DROP]), CSPFT_STRING }, - {"sprintInAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_SPRINT_IN]), CSPFT_STRING }, - {"sprintLoopAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_SPRINT_LOOP]), CSPFT_STRING }, - {"sprintOutAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_SPRINT_OUT]), CSPFT_STRING }, - {"stunnedAnimStartR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_STUNNED_START]), CSPFT_STRING }, - {"stunnedAnimLoopR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_STUNNED_LOOP]), CSPFT_STRING }, - {"stunnedAnimEndR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_STUNNED_END]), CSPFT_STRING }, - {"nightVisionWearAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_NIGHTVISION_WEAR]), CSPFT_STRING }, - {"nightVisionRemoveAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_NIGHTVISION_REMOVE]), CSPFT_STRING }, - {"adsFireAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_ADS_FIRE]), CSPFT_STRING }, - {"adsLastShotAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_ADS_LASTSHOT]), CSPFT_STRING }, - {"adsRechamberAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_ADS_RECHAMBER]), CSPFT_STRING }, - {"adsUpAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_ADS_UP]), CSPFT_STRING }, - {"adsDownAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_ADS_DOWN]), CSPFT_STRING }, - {"idleAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_IDLE]), CSPFT_STRING }, - {"emptyIdleAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_EMPTY_IDLE]), CSPFT_STRING }, - {"fireAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_FIRE]), CSPFT_STRING }, - {"holdFireAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_HOLD_FIRE]), CSPFT_STRING }, - {"lastShotAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_LASTSHOT]), CSPFT_STRING }, - {"detonateAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_DETONATE]), CSPFT_STRING }, - {"rechamberAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_RECHAMBER]), CSPFT_STRING }, - {"meleeAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_MELEE]), CSPFT_STRING }, - {"meleeChargeAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_MELEE_CHARGE]), CSPFT_STRING }, - {"reloadAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_RELOAD]), CSPFT_STRING }, - {"reloadEmptyAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_RELOAD_EMPTY]), CSPFT_STRING }, - {"reloadStartAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_RELOAD_START]), CSPFT_STRING }, - {"reloadEndAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_RELOAD_END]), CSPFT_STRING }, - {"raiseAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_RAISE]), CSPFT_STRING }, - {"dropAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_DROP]), CSPFT_STRING }, - {"firstRaiseAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_FIRST_RAISE]), CSPFT_STRING }, - {"breachRaiseAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_BREACH_RAISE]), CSPFT_STRING }, - {"altRaiseAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_ALT_RAISE]), CSPFT_STRING }, - {"altDropAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_ALT_DROP]), CSPFT_STRING }, - {"quickRaiseAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_QUICK_RAISE]), CSPFT_STRING }, - {"quickDropAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_QUICK_DROP]), CSPFT_STRING }, - {"emptyRaiseAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_EMPTY_RAISE]), CSPFT_STRING }, - {"emptyDropAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_EMPTY_DROP]), CSPFT_STRING }, - {"sprintInAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_SPRINT_IN]), CSPFT_STRING }, - {"sprintLoopAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_SPRINT_LOOP]), CSPFT_STRING }, - {"sprintOutAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_SPRINT_OUT]), CSPFT_STRING }, - {"stunnedAnimStartL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_STUNNED_START]), CSPFT_STRING }, - {"stunnedAnimLoopL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_STUNNED_LOOP]), CSPFT_STRING }, - {"stunnedAnimEndL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_STUNNED_END]), CSPFT_STRING }, - {"nightVisionWearAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_NIGHTVISION_WEAR]), CSPFT_STRING }, - {"nightVisionRemoveAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_NIGHTVISION_REMOVE]), CSPFT_STRING }, - {"adsFireAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_ADS_FIRE]), CSPFT_STRING }, - {"adsLastShotAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_ADS_LASTSHOT]), CSPFT_STRING }, - {"adsRechamberAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_ADS_RECHAMBER]), CSPFT_STRING }, - {"adsUpAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_ADS_UP]), CSPFT_STRING }, - {"adsDownAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_ADS_DOWN]), CSPFT_STRING }, + {"idleAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_IDLE]), WFT_ANIM_NAME }, + {"emptyIdleAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_EMPTY_IDLE]), WFT_ANIM_NAME }, + {"fireAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_FIRE]), WFT_ANIM_NAME }, + {"holdFireAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_HOLD_FIRE]), WFT_ANIM_NAME }, + {"lastShotAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_LASTSHOT]), WFT_ANIM_NAME }, + {"detonateAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_DETONATE]), WFT_ANIM_NAME }, + {"rechamberAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_RECHAMBER]), WFT_ANIM_NAME }, + {"meleeAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_MELEE]), WFT_ANIM_NAME }, + {"meleeChargeAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_MELEE_CHARGE]), WFT_ANIM_NAME }, + {"reloadAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_RELOAD]), WFT_ANIM_NAME }, + {"reloadEmptyAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_RELOAD_EMPTY]), WFT_ANIM_NAME }, + {"reloadStartAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_RELOAD_START]), WFT_ANIM_NAME }, + {"reloadEndAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_RELOAD_END]), WFT_ANIM_NAME }, + {"raiseAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_RAISE]), WFT_ANIM_NAME }, + {"dropAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_DROP]), WFT_ANIM_NAME }, + {"firstRaiseAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_FIRST_RAISE]), WFT_ANIM_NAME }, + {"breachRaiseAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_BREACH_RAISE]), WFT_ANIM_NAME }, + {"altRaiseAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_ALT_RAISE]), WFT_ANIM_NAME }, + {"altDropAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_ALT_DROP]), WFT_ANIM_NAME }, + {"quickRaiseAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_QUICK_RAISE]), WFT_ANIM_NAME }, + {"quickDropAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_QUICK_DROP]), WFT_ANIM_NAME }, + {"emptyRaiseAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_EMPTY_RAISE]), WFT_ANIM_NAME }, + {"emptyDropAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_EMPTY_DROP]), WFT_ANIM_NAME }, + {"sprintInAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_SPRINT_IN]), WFT_ANIM_NAME }, + {"sprintLoopAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_SPRINT_LOOP]), WFT_ANIM_NAME }, + {"sprintOutAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_SPRINT_OUT]), WFT_ANIM_NAME }, + {"stunnedAnimStart", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_STUNNED_START]), WFT_ANIM_NAME }, + {"stunnedAnimLoop", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_STUNNED_LOOP]), WFT_ANIM_NAME }, + {"stunnedAnimEnd", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_STUNNED_END]), WFT_ANIM_NAME }, + {"nightVisionWearAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_NIGHTVISION_WEAR]), WFT_ANIM_NAME }, + {"nightVisionRemoveAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_NIGHTVISION_REMOVE]), WFT_ANIM_NAME }, + {"adsFireAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_ADS_FIRE]), WFT_ANIM_NAME }, + {"adsLastShotAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_ADS_LASTSHOT]), WFT_ANIM_NAME }, + {"adsRechamberAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_ADS_RECHAMBER]), WFT_ANIM_NAME }, + {"adsUpAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_ADS_UP]), WFT_ANIM_NAME }, + {"adsDownAnim", offsetof(WeaponFullDef, szXAnims[WEAP_ANIM_ADS_DOWN]), WFT_ANIM_NAME }, + {"idleAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_IDLE]), WFT_ANIM_NAME }, + {"emptyIdleAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_EMPTY_IDLE]), WFT_ANIM_NAME }, + {"fireAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_FIRE]), WFT_ANIM_NAME }, + {"holdFireAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_HOLD_FIRE]), WFT_ANIM_NAME }, + {"lastShotAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_LASTSHOT]), WFT_ANIM_NAME }, + {"detonateAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_DETONATE]), WFT_ANIM_NAME }, + {"rechamberAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_RECHAMBER]), WFT_ANIM_NAME }, + {"meleeAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_MELEE]), WFT_ANIM_NAME }, + {"meleeChargeAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_MELEE_CHARGE]), WFT_ANIM_NAME }, + {"reloadAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_RELOAD]), WFT_ANIM_NAME }, + {"reloadEmptyAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_RELOAD_EMPTY]), WFT_ANIM_NAME }, + {"reloadStartAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_RELOAD_START]), WFT_ANIM_NAME }, + {"reloadEndAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_RELOAD_END]), WFT_ANIM_NAME }, + {"raiseAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_RAISE]), WFT_ANIM_NAME }, + {"dropAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_DROP]), WFT_ANIM_NAME }, + {"firstRaiseAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_FIRST_RAISE]), WFT_ANIM_NAME }, + {"breachRaiseAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_BREACH_RAISE]), WFT_ANIM_NAME }, + {"altRaiseAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_ALT_RAISE]), WFT_ANIM_NAME }, + {"altDropAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_ALT_DROP]), WFT_ANIM_NAME }, + {"quickRaiseAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_QUICK_RAISE]), WFT_ANIM_NAME }, + {"quickDropAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_QUICK_DROP]), WFT_ANIM_NAME }, + {"emptyRaiseAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_EMPTY_RAISE]), WFT_ANIM_NAME }, + {"emptyDropAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_EMPTY_DROP]), WFT_ANIM_NAME }, + {"sprintInAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_SPRINT_IN]), WFT_ANIM_NAME }, + {"sprintLoopAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_SPRINT_LOOP]), WFT_ANIM_NAME }, + {"sprintOutAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_SPRINT_OUT]), WFT_ANIM_NAME }, + {"stunnedAnimStartR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_STUNNED_START]), WFT_ANIM_NAME }, + {"stunnedAnimLoopR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_STUNNED_LOOP]), WFT_ANIM_NAME }, + {"stunnedAnimEndR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_STUNNED_END]), WFT_ANIM_NAME }, + {"nightVisionWearAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_NIGHTVISION_WEAR]), WFT_ANIM_NAME }, + {"nightVisionRemoveAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_NIGHTVISION_REMOVE]), WFT_ANIM_NAME }, + {"adsFireAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_ADS_FIRE]), WFT_ANIM_NAME }, + {"adsLastShotAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_ADS_LASTSHOT]), WFT_ANIM_NAME }, + {"adsRechamberAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_ADS_RECHAMBER]), WFT_ANIM_NAME }, + {"adsUpAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_ADS_UP]), WFT_ANIM_NAME }, + {"adsDownAnimR", offsetof(WeaponFullDef, szXAnimsRightHanded[WEAP_ANIM_ADS_DOWN]), WFT_ANIM_NAME }, + {"idleAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_IDLE]), WFT_ANIM_NAME }, + {"emptyIdleAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_EMPTY_IDLE]), WFT_ANIM_NAME }, + {"fireAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_FIRE]), WFT_ANIM_NAME }, + {"holdFireAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_HOLD_FIRE]), WFT_ANIM_NAME }, + {"lastShotAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_LASTSHOT]), WFT_ANIM_NAME }, + {"detonateAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_DETONATE]), WFT_ANIM_NAME }, + {"rechamberAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_RECHAMBER]), WFT_ANIM_NAME }, + {"meleeAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_MELEE]), WFT_ANIM_NAME }, + {"meleeChargeAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_MELEE_CHARGE]), WFT_ANIM_NAME }, + {"reloadAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_RELOAD]), WFT_ANIM_NAME }, + {"reloadEmptyAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_RELOAD_EMPTY]), WFT_ANIM_NAME }, + {"reloadStartAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_RELOAD_START]), WFT_ANIM_NAME }, + {"reloadEndAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_RELOAD_END]), WFT_ANIM_NAME }, + {"raiseAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_RAISE]), WFT_ANIM_NAME }, + {"dropAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_DROP]), WFT_ANIM_NAME }, + {"firstRaiseAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_FIRST_RAISE]), WFT_ANIM_NAME }, + {"breachRaiseAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_BREACH_RAISE]), WFT_ANIM_NAME }, + {"altRaiseAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_ALT_RAISE]), WFT_ANIM_NAME }, + {"altDropAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_ALT_DROP]), WFT_ANIM_NAME }, + {"quickRaiseAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_QUICK_RAISE]), WFT_ANIM_NAME }, + {"quickDropAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_QUICK_DROP]), WFT_ANIM_NAME }, + {"emptyRaiseAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_EMPTY_RAISE]), WFT_ANIM_NAME }, + {"emptyDropAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_EMPTY_DROP]), WFT_ANIM_NAME }, + {"sprintInAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_SPRINT_IN]), WFT_ANIM_NAME }, + {"sprintLoopAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_SPRINT_LOOP]), WFT_ANIM_NAME }, + {"sprintOutAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_SPRINT_OUT]), WFT_ANIM_NAME }, + {"stunnedAnimStartL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_STUNNED_START]), WFT_ANIM_NAME }, + {"stunnedAnimLoopL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_STUNNED_LOOP]), WFT_ANIM_NAME }, + {"stunnedAnimEndL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_STUNNED_END]), WFT_ANIM_NAME }, + {"nightVisionWearAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_NIGHTVISION_WEAR]), WFT_ANIM_NAME }, + {"nightVisionRemoveAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_NIGHTVISION_REMOVE]), WFT_ANIM_NAME }, + {"adsFireAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_ADS_FIRE]), WFT_ANIM_NAME }, + {"adsLastShotAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_ADS_LASTSHOT]), WFT_ANIM_NAME }, + {"adsRechamberAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_ADS_RECHAMBER]), WFT_ANIM_NAME }, + {"adsUpAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_ADS_UP]), WFT_ANIM_NAME }, + {"adsDownAnimL", offsetof(WeaponFullDef, szXAnimsLeftHanded[WEAP_ANIM_ADS_DOWN]), WFT_ANIM_NAME }, {"script", offsetof(WeaponFullDef, weapDef.szScript), CSPFT_STRING }, {"weaponType", offsetof(WeaponFullDef, weapDef.weapType), WFT_WEAPONTYPE }, {"weaponClass", offsetof(WeaponFullDef, weapDef.weapClass), WFT_WEAPONCLASS }, diff --git a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderVertexDecl.cpp b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderVertexDecl.cpp index d86d02c60..65fff5cb2 100644 --- a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderVertexDecl.cpp +++ b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderVertexDecl.cpp @@ -48,6 +48,10 @@ bool AssetLoaderVertexDecl::LoadFromRaw( MaterialVertexDeclaration decl{}; size_t currentOffset = 0u; + + if (!assetName.empty() && assetName[0] == ',') + currentOffset = 1u; + std::string sourceAbbreviation; while (NextAbbreviation(assetName, sourceAbbreviation, currentOffset)) { diff --git a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderWeapon.cpp b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderWeapon.cpp index a46358758..e6fa3547e 100644 --- a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderWeapon.cpp +++ b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderWeapon.cpp @@ -1,13 +1,423 @@ #include "AssetLoaderWeapon.h" #include "Game/IW4/IW4.h" +#include "Game/IW4/InfoString/EnumStrings.h" +#include "Game/IW4/InfoString/InfoStringToStructConverter.h" +#include "Game/IW4/InfoString/WeaponFields.h" +#include "Game/IW4/ObjConstantsIW4.h" +#include "InfoString/InfoString.h" #include "ObjLoading.h" #include "Pool/GlobalAssetPool.h" +#include "Utils/StringUtils.h" #include +#include +#include using namespace IW4; +namespace +{ + class InfoStringToWeaponConverter final : public InfoStringToStructConverter + { + bool ConvertHideTags(const cspField_t& field, const std::string& value) + { + std::vector valueArray; + if (!ParseAsArray(value, valueArray)) + { + std::cerr << "Failed to parse hide tags as array\n"; + return false; + } + + if (valueArray.size() > std::extent_v) + { + std::cerr << "Cannot have more than " << std::extent_v << " hide tags!\n"; + return false; + } + + auto* hideTags = reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset); + + if (valueArray.size() < std::extent_v) + { + m_used_script_string_list.emplace(m_zone_script_strings.AddOrGetScriptString(nullptr)); + } + + auto currentHideTag = 0u; + for (; currentHideTag < valueArray.size(); currentHideTag++) + { + const auto& currentValue = valueArray[currentHideTag]; + const auto scrString = + !currentValue.empty() ? m_zone_script_strings.AddOrGetScriptString(currentValue) : m_zone_script_strings.AddOrGetScriptString(nullptr); + hideTags[currentHideTag] = scrString; + m_used_script_string_list.emplace(scrString); + } + + for (; currentHideTag < std::extent_v; currentHideTag++) + { + hideTags[currentHideTag] = m_zone_script_strings.GetScriptString(nullptr); + } + + return true; + } + + _NODISCARD bool ConvertBounceSounds(const cspField_t& field, const std::string& value) const + { + auto*** bounceSound = reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset); + if (value.empty()) + { + *bounceSound = nullptr; + return true; + } + + assert(std::extent_v == SURF_TYPE_NUM); + *bounceSound = static_cast(m_memory->Alloc(sizeof(const char*) * SURF_TYPE_NUM)); + for (auto i = 0u; i < SURF_TYPE_NUM; i++) + { + const auto currentBounceSound = value + bounceSoundSuffixes[i]; + (*bounceSound)[i] = m_memory->Dup(currentBounceSound.c_str()); + } + return true; + } + + _NODISCARD bool ConvertNotetrackMap(const cspField_t& field, const std::string& value, const char* mapName, const size_t keyAndValueCount) + { + std::vector> pairs; + if (!ParseAsPairs(value, pairs)) + { + std::cerr << "Failed to parse notetrack" << mapName << "map as pairs\n"; + return false; + } + + if (pairs.size() > std::extent_v) + { + std::cerr << "Cannot have more than " << std::extent_v << " notetrack" << mapName + << "map entries!\n"; + return false; + } + + auto* keys = reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset); + auto* values = &keys[keyAndValueCount]; + auto currentEntryNum = 0u; + + if (pairs.size() < keyAndValueCount) + { + m_used_script_string_list.emplace(m_zone_script_strings.AddOrGetScriptString(nullptr)); + } + + for (; currentEntryNum < pairs.size(); currentEntryNum++) + { + const auto& currentValue = pairs[currentEntryNum]; + const auto keyScriptString = !currentValue.first.empty() ? m_zone_script_strings.AddOrGetScriptString(currentValue.first) + : m_zone_script_strings.AddOrGetScriptString(nullptr); + const auto valueScriptString = !currentValue.second.empty() ? m_zone_script_strings.AddOrGetScriptString(currentValue.second) + : m_zone_script_strings.AddOrGetScriptString(nullptr); + + keys[currentEntryNum] = keyScriptString; + m_used_script_string_list.emplace(keyScriptString); + + values[currentEntryNum] = valueScriptString; + m_used_script_string_list.emplace(valueScriptString); + } + + for (; currentEntryNum < keyAndValueCount; 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()) + { + auto lowerValue = value; + utils::MakeStringLowerCase(lowerValue); + m_indirect_asset_references.emplace(m_loading_manager->LoadIndirectAssetReference(ASSET_TYPE_XANIMPARTS, lowerValue)); + } + return true; + } + + return false; + } + + protected: + bool ConvertExtensionField(const cspField_t& field, const std::string& value) override + { + switch (static_cast(field.iFieldType)) + { + case WFT_WEAPONTYPE: + return ConvertEnumInt(value, field.iOffset, szWeapTypeNames, std::extent_v); + + case WFT_WEAPONCLASS: + return ConvertEnumInt(value, field.iOffset, szWeapClassNames, std::extent_v); + + case WFT_OVERLAYRETICLE: + return ConvertEnumInt(value, field.iOffset, szWeapOverlayReticleNames, std::extent_v); + + case WFT_PENETRATE_TYPE: + return ConvertEnumInt(value, field.iOffset, penetrateTypeNames, std::extent_v); + + case WFT_IMPACT_TYPE: + return ConvertEnumInt(value, field.iOffset, impactTypeNames, std::extent_v); + + case WFT_STANCE: + return ConvertEnumInt(value, field.iOffset, szWeapStanceNames, std::extent_v); + + case WFT_PROJ_EXPLOSION: + return ConvertEnumInt(value, field.iOffset, szProjectileExplosionNames, std::extent_v); + + case WFT_OFFHAND_CLASS: + return ConvertEnumInt(value, field.iOffset, offhandClassNames, std::extent_v); + + case WFT_ANIMTYPE: + return ConvertEnumInt(value, field.iOffset, playerAnimTypeNames, std::extent_v); + + case WFT_ACTIVE_RETICLE_TYPE: + return ConvertEnumInt(value, field.iOffset, activeReticleNames, std::extent_v); + + case WFT_GUIDED_MISSILE_TYPE: + return ConvertEnumInt(value, field.iOffset, guidedMissileNames, std::extent_v); + + case WFT_BOUNCE_SOUND: + return ConvertBounceSounds(field, value); + + case WFT_STICKINESS: + return ConvertEnumInt(value, field.iOffset, stickinessNames, std::extent_v); + + case WFT_OVERLAYINTERFACE: + return ConvertEnumInt(value, field.iOffset, overlayInterfaceNames, std::extent_v); + + case WFT_INVENTORYTYPE: + return ConvertEnumInt(value, field.iOffset, szWeapInventoryTypeNames, std::extent_v); + + case WFT_FIRETYPE: + return ConvertEnumInt(value, field.iOffset, szWeapFireTypeNames, std::extent_v); + + case WFT_AMMOCOUNTER_CLIPTYPE: + return ConvertEnumInt(value, field.iOffset, ammoCounterClipNames, std::extent_v); + + case WFT_ICONRATIO_HUD: + case WFT_ICONRATIO_PICKUP: + case WFT_ICONRATIO_AMMOCOUNTER: + case WFT_ICONRATIO_KILL: + case WFT_ICONRATIO_DPAD: + return ConvertEnumInt(value, field.iOffset, weapIconRatioNames, std::extent_v); + + case WFT_HIDETAGS: + return ConvertHideTags(field, value); + + case WFT_NOTETRACKSOUNDMAP: + return ConvertNotetrackMap(field, value, "sound", std::extent_v); + + case WFT_NOTETRACKRUMBLEMAP: + return ConvertNotetrackMap(field, value, "rumble", std::extent_v); + + case WFT_ANIM_NAME: + return ConvertAnimName(field, value); + + default: + assert(false); + return false; + } + } + + public: + InfoStringToWeaponConverter(const InfoString& infoString, + WeaponFullDef* weaponFullDef, + ZoneScriptStrings& zoneScriptStrings, + MemoryManager* memory, + IAssetLoadingManager* manager, + const cspField_t* fields, + const size_t fieldCount) + : InfoStringToStructConverter(infoString, weaponFullDef, zoneScriptStrings, memory, manager, fields, fieldCount) + { + } + }; + + void InitWeaponFullDef(WeaponFullDef* weapon) + { + weapon->weapCompleteDef.weapDef = &weapon->weapDef; + weapon->weapCompleteDef.hideTags = weapon->hideTags; + weapon->weapCompleteDef.szXAnims = weapon->szXAnims; + weapon->weapDef.gunXModel = weapon->gunXModel; + weapon->weapDef.szXAnimsRightHanded = weapon->szXAnimsRightHanded; + weapon->weapDef.szXAnimsLeftHanded = weapon->szXAnimsLeftHanded; + weapon->weapDef.notetrackSoundMapKeys = weapon->notetrackSoundMapKeys; + weapon->weapDef.notetrackSoundMapValues = weapon->notetrackSoundMapValues; + weapon->weapDef.notetrackRumbleMapKeys = weapon->notetrackRumbleMapKeys; + weapon->weapDef.notetrackRumbleMapValues = weapon->notetrackRumbleMapValues; + weapon->weapDef.worldModel = weapon->worldModel; + weapon->weapDef.parallelBounce = weapon->parallelBounce; + weapon->weapDef.perpendicularBounce = weapon->perpendicularBounce; + weapon->weapDef.locationDamageMultipliers = weapon->locationDamageMultipliers; + weapon->weapCompleteDef.szInternalName = ""; + + for (const auto& field : weapon_fields) + { + if (field.iFieldType != CSPFT_STRING) + continue; + + *reinterpret_cast(reinterpret_cast(weapon) + field.iOffset) = ""; + } + } + + snd_alias_list_name* CreateSoundAliasListName(const char* value, MemoryManager* memory) + { + auto* name = static_cast(memory->Alloc(sizeof(snd_alias_list_name))); + name->soundName = memory->Dup(value); + return name; + } + + void CheckProjectileValues(const WeaponCompleteDef& weaponCompleteDef, const WeaponDef& weaponDef) + { + if (weaponDef.iProjectileSpeed <= 0) + std::cerr << std::format("Projectile speed for WeapType {} must be greater than 0.0", weaponCompleteDef.szDisplayName); + if (weaponDef.destabilizationCurvatureMax >= 1000000000.0f || weaponDef.destabilizationCurvatureMax < 0.0f) + std::cerr << std::format("Destabilization angle for for WeapType {} must be between 0 and 45 degrees", weaponCompleteDef.szDisplayName); + if (weaponDef.destabilizationRateTime < 0.0f) + std::cerr << std::format("Destabilization rate time for for WeapType {} must be non-negative", weaponCompleteDef.szDisplayName); + } + + void CheckTurretBarrelSpin(const WeaponCompleteDef& weaponCompleteDef, const WeaponDef& weaponDef) + { + if (weaponDef.weapClass != WEAPCLASS_TURRET) + std::cerr << std::format("Rotating barrel set for non-turret weapon {}.", weaponCompleteDef.szInternalName); + + if (0.0f == weaponDef.turretBarrelSpinSpeed) + { + std::cerr << std::format( + "Rotating barrel spin speed '{}' is invalid for weapon {}.", weaponDef.turretBarrelSpinSpeed, weaponCompleteDef.szInternalName); + } + if (0.0f < weaponDef.turretOverheatUpRate && 0.0f >= weaponDef.turretOverheatDownRate) + { + std::cerr << std::format("Turret overheat Up rate is set, but the down rate '{}' is invalid for weapon {}.", + weaponDef.turretOverheatDownRate, + weaponCompleteDef.szInternalName); + } + } + + void CheckThermalScope(const WeaponCompleteDef& weaponCompleteDef, const WeaponDef& weaponDef) + { + if (0.0f != weaponDef.fAdsZoomInFrac) + { + std::cerr << std::format("Weapon {} ({}) has thermal scope set. ADS Zoom In frac should be 0 to prevent zoom-in blur ({}).\n", + weaponCompleteDef.szInternalName, + weaponCompleteDef.szDisplayName, + weaponDef.fAdsZoomInFrac); + } + + if (0.0f != weaponDef.fAdsZoomOutFrac) + { + std::cerr << std::format("Weapon {} ({}) has thermal scope set. ADS Zoom Out frac should be 0 to prevent zoom-out blur ({}).\n", + weaponCompleteDef.szInternalName, + weaponCompleteDef.szDisplayName, + weaponDef.fAdsZoomOutFrac); + } + } + + void CalculateWeaponFields(WeaponFullDef* weapon, MemoryManager* memory) + { + auto& weaponCompleteDef = weapon->weapCompleteDef; + auto& weaponDef = weapon->weapDef; + + if (!weaponDef.viewLastShotEjectEffect) + weaponDef.viewLastShotEjectEffect = weaponDef.viewShellEjectEffect; + if (!weaponDef.worldLastShotEjectEffect) + weaponDef.worldLastShotEjectEffect = weaponDef.worldShellEjectEffect; + + if (!weaponDef.raiseSound.name) + weaponDef.raiseSound.name = CreateSoundAliasListName("weap_raise", memory); + if (!weaponDef.putawaySound.name) + weaponDef.putawaySound.name = CreateSoundAliasListName("weap_putaway", memory); + if (!weaponDef.pickupSound.name) + weaponDef.pickupSound.name = CreateSoundAliasListName("weap_pickup", memory); + if (!weaponDef.ammoPickupSound.name) + weaponDef.ammoPickupSound.name = CreateSoundAliasListName("weap_ammo_pickup", memory); + if (!weaponDef.emptyFireSound.name) + weaponDef.emptyFireSound.name = CreateSoundAliasListName("weap_dryfire_smg_npc", memory); + + if (weaponCompleteDef.iAdsTransInTime <= 0) + weaponDef.fOOPosAnimLength[0] = 0.0033333334f; + else + weaponDef.fOOPosAnimLength[0] = 1.0f / static_cast(weaponCompleteDef.iAdsTransInTime); + + if (weaponCompleteDef.iAdsTransOutTime <= 0) + weaponDef.fOOPosAnimLength[1] = 0.0020000001f; + else + weaponDef.fOOPosAnimLength[1] = 1.0f / static_cast(weaponCompleteDef.iAdsTransOutTime); + + if (weaponDef.fMaxDamageRange <= 0.0f) + weaponDef.fMaxDamageRange = 999999.0f; + if (weaponDef.fMinDamageRange <= 0.0f) + weaponDef.fMinDamageRange = 999999.12f; + + if (weaponDef.enemyCrosshairRange > 15000.0f) + std::cerr << std::format("Enemy crosshair ranges should be less than {}\n", 15000.0f); + + if (weaponDef.weapType == WEAPTYPE_PROJECTILE) + CheckProjectileValues(weaponCompleteDef, weaponDef); + + if (weaponDef.turretBarrelSpinEnabled) + CheckTurretBarrelSpin(weaponCompleteDef, weaponDef); + + if (weaponDef.thermalScope) + CheckThermalScope(weaponCompleteDef, weaponDef); + + if (weaponDef.offhandClass && !weaponDef.bClipOnly) + { + std::cerr << std::format( + "Weapon {} ({}) is an offhand weapon but is not set to clip only, which is not supported since we can't reload the offhand slot.\n", + weaponCompleteDef.szInternalName, + weaponCompleteDef.szDisplayName); + } + + if (weaponDef.weapType == WEAPTYPE_BULLET) + { + if (weaponDef.bulletExplDmgMult <= 0.0f) + std::cerr << std::format("Detected invalid bulletExplDmgMult of '{}' for weapon '{}'; please update weapon settings.\n", + weaponDef.bulletExplDmgMult, + weaponCompleteDef.szInternalName); + if (weaponDef.bulletExplRadiusMult <= 0.0f) + std::cerr << std::format("Detected invalid bulletExplRadiusMult of '{}' for weapon '{}'; please update weapon settings.\n", + weaponDef.bulletExplRadiusMult, + weaponCompleteDef.szInternalName); + } + } + + bool LoadFromInfoString(const InfoString& infoString, const std::string& assetName, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) + { + auto* weaponFullDef = memory->Create(); + memset(weaponFullDef, 0, sizeof(WeaponFullDef)); + InitWeaponFullDef(weaponFullDef); + + InfoStringToWeaponConverter converter( + infoString, weaponFullDef, zone->m_script_strings, memory, manager, weapon_fields, std::extent_v); + if (!converter.Convert()) + { + std::cerr << "Failed to parse weapon: \"" << assetName << "\"\n"; + return true; + } + + weaponFullDef->weapCompleteDef.szInternalName = memory->Dup(assetName.c_str()); + + CalculateWeaponFields(weaponFullDef, memory); + + manager->AddAsset(ASSET_TYPE_WEAPON, + assetName, + &weaponFullDef->weapCompleteDef, + converter.GetDependencies(), + converter.GetUsedScriptStrings(), + converter.GetIndirectAssetReferences()); + + return true; + } +} // namespace + void* AssetLoaderWeapon::CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) { auto* weapon = memory->Create(); @@ -15,3 +425,48 @@ void* AssetLoaderWeapon::CreateEmptyAsset(const std::string& assetName, MemoryMa weapon->szInternalName = memory->Dup(assetName.c_str()); return weapon; } + +bool AssetLoaderWeapon::CanLoadFromGdt() const +{ + return true; +} + +bool AssetLoaderWeapon::LoadFromGdt( + const std::string& assetName, IGdtQueryable* gdtQueryable, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const +{ + const auto* gdtEntry = gdtQueryable->GetGdtEntryByGdfAndName(ObjConstants::GDF_FILENAME_WEAPON, assetName); + if (gdtEntry == nullptr) + return false; + + InfoString infoString; + if (!infoString.FromGdtProperties(*gdtEntry)) + { + std::cerr << "Failed to read weapon gdt entry: \"" << assetName << "\"\n"; + return true; + } + + return LoadFromInfoString(infoString, assetName, memory, manager, zone); +} + +bool AssetLoaderWeapon::CanLoadFromRaw() const +{ + return true; +} + +bool AssetLoaderWeapon::LoadFromRaw( + const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const +{ + const auto fileName = "weapons/" + assetName; + const auto file = searchPath->Open(fileName); + if (!file.IsOpen()) + return false; + + InfoString infoString; + if (!infoString.FromStream(ObjConstants::INFO_STRING_PREFIX_WEAPON, *file.m_stream)) + { + std::cerr << "Failed to read weapon raw file: \"" << fileName << "\"\n"; + return true; + } + + return LoadFromInfoString(infoString, assetName, memory, manager, zone); +} diff --git a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderWeapon.h b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderWeapon.h index bbd5f5986..b176d8ee2 100644 --- a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderWeapon.h +++ b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderWeapon.h @@ -10,5 +10,11 @@ namespace IW4 { public: _NODISCARD void* CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) override; + _NODISCARD bool CanLoadFromGdt() const override; + bool LoadFromGdt( + const std::string& assetName, IGdtQueryable* gdtQueryable, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const override; + _NODISCARD bool CanLoadFromRaw() const override; + bool + LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const override; }; } // namespace IW4 diff --git a/src/ObjLoading/Game/IW4/InfoString/InfoStringToStructConverter.cpp b/src/ObjLoading/Game/IW4/InfoString/InfoStringToStructConverter.cpp index 1178c2db4..32ed60f9f 100644 --- a/src/ObjLoading/Game/IW4/InfoString/InfoStringToStructConverter.cpp +++ b/src/ObjLoading/Game/IW4/InfoString/InfoStringToStructConverter.cpp @@ -178,21 +178,16 @@ bool InfoStringToStructConverter::ConvertBaseField(const cspField_t& field, cons { if (value.empty()) { - *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = nullptr; + reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset)->name = nullptr; return true; } - auto* sound = m_loading_manager->LoadDependency(ASSET_TYPE_SOUND, value); - - if (sound == nullptr) - { - std::cout << "Failed to load sound asset \"" << value << "\"\n"; - return false; - } + auto* name = static_cast(m_memory->Alloc(sizeof(snd_alias_list_name))); + name->soundName = m_memory->Dup(value.c_str()); - m_dependencies.emplace(sound); - *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = sound->m_ptr; + reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset)->name = name; + m_indirect_asset_references.emplace(ASSET_TYPE_SOUND, value); return true; } diff --git a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderWeapon.cpp b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderWeapon.cpp index b52e375ff..4c0b4c4a1 100644 --- a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderWeapon.cpp +++ b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderWeapon.cpp @@ -8,6 +8,7 @@ #include "Game/T6/T6.h" #include "InfoString/InfoString.h" #include "Utils/ClassUtils.h" +#include "Utils/StringUtils.h" #include #include @@ -262,7 +263,11 @@ namespace T6 if (ConvertString(value, field.iOffset)) { if (!value.empty()) - m_indirect_asset_references.emplace(m_loading_manager->LoadIndirectAssetReference(ASSET_TYPE_XANIMPARTS, value)); + { + auto lowerValue = value; + utils::MakeStringLowerCase(lowerValue); + m_indirect_asset_references.emplace(m_loading_manager->LoadIndirectAssetReference(ASSET_TYPE_XANIMPARTS, lowerValue)); + } return true; } diff --git a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperWeapon.cpp b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperWeapon.cpp index ae5931446..c3b1dcc54 100644 --- a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperWeapon.cpp +++ b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperWeapon.cpp @@ -199,6 +199,10 @@ namespace IW4 break; } + case WFT_ANIM_NAME: + FillFromString(std::string(field.szName), field.iOffset); + break; + case WFT_NUM_FIELD_TYPES: default: assert(false);