From: Mario Date: Mon, 3 Jul 2017 14:35:22 +0000 (+1000) Subject: Rough support for animated models as a separate optional model (and client side weapo... X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=03c71e7757306ebd839fc95b8dbcac84294de633;p=xonotic%2Fxonotic-data.pk3dir.git Rough support for animated models as a separate optional model (and client side weapon animation handling) --- diff --git a/defaultXonotic.cfg b/defaultXonotic.cfg index f2a6a2012..77f9f2fb1 100644 --- a/defaultXonotic.cfg +++ b/defaultXonotic.cfg @@ -1074,6 +1074,8 @@ seta cl_weaponpriority8 "" seta cl_weaponpriority9 "" "use weapon_priority_9_prev for prev gun from this list, weapon_priority_9_best for best gun, weapon_priority_9_next for next gun" seta cl_weaponimpulsemode 0 "0: only cycle between currently usable weapons in weapon priority order; 1: cycle between all possible weapons on a key in weapon priority order" +seta cl_weapons_animate 0 "Use animated weapon models" + set g_maplist_allow_hidden 0 "allow hidden maps to be, e.g., voted for and in the maplist" set g_maplist_allow_frustrating 0 "allow impossible maps to be, e.g., voted for and in the maplist (if set to 2, ONLY impossible maps are allowed)" diff --git a/models/weapons/h_gl_animated.iqm b/models/weapons/h_gl_animated.iqm new file mode 100644 index 000000000..63f514b44 Binary files /dev/null and b/models/weapons/h_gl_animated.iqm differ diff --git a/models/weapons/h_gl_animated.iqm.framegroups b/models/weapons/h_gl_animated.iqm.framegroups new file mode 100644 index 000000000..c7e79a91a --- /dev/null +++ b/models/weapons/h_gl_animated.iqm.framegroups @@ -0,0 +1,9 @@ +/* +Generated framegroups file for h_gl +Used by DarkPlaces to simulate frame groups in DPM models. +*/ + +1 25 30 0 // h_gl fire +26 25 30 0 // h_gl fire +51 101 3 1 // h_gl idle +152 101 3 1 // h_gl idle diff --git a/models/weapons/h_rl_animated.iqm b/models/weapons/h_rl_animated.iqm new file mode 100644 index 000000000..1868b2c02 Binary files /dev/null and b/models/weapons/h_rl_animated.iqm differ diff --git a/models/weapons/h_rl_animated.iqm.framegroups b/models/weapons/h_rl_animated.iqm.framegroups new file mode 100644 index 000000000..c4f4127e7 --- /dev/null +++ b/models/weapons/h_rl_animated.iqm.framegroups @@ -0,0 +1,9 @@ +/* +Generated framegroups file for h_rl +Used by DarkPlaces to simulate frame groups in DPM models. +*/ + +1 31 30 0 // h_rl fire +32 31 30 0 // h_rl fire +63 101 3 1 // h_rl idle +164 101 3 1 // h_rl idle diff --git a/models/weapons/v_gl_animated.md3 b/models/weapons/v_gl_animated.md3 new file mode 100644 index 000000000..970ca86ce Binary files /dev/null and b/models/weapons/v_gl_animated.md3 differ diff --git a/models/weapons/v_rl_animated.md3 b/models/weapons/v_rl_animated.md3 new file mode 100644 index 000000000..534e616ac Binary files /dev/null and b/models/weapons/v_rl_animated.md3 differ diff --git a/qcsrc/client/autocvars.qh b/qcsrc/client/autocvars.qh index d95958392..9af6f0e28 100644 --- a/qcsrc/client/autocvars.qh +++ b/qcsrc/client/autocvars.qh @@ -445,3 +445,4 @@ float autocvar_g_jetpack_attenuation; bool autocvar_cl_showspectators; int autocvar_cl_nade_timer; bool autocvar_r_drawviewmodel; +bool autocvar_cl_weapons_animate; diff --git a/qcsrc/common/models/all.inc b/qcsrc/common/models/all.inc index f47d8e7c5..dc2f94ea6 100644 --- a/qcsrc/common/models/all.inc +++ b/qcsrc/common/models/all.inc @@ -156,109 +156,157 @@ MODEL(CASING_BULLET, "models/casing_bronze.iqm"); MODEL(BUFF, "models/relics/relic.md3"); MODEL(BLASTER_VIEW, W_Model("h_laser.iqm")); +MODEL(BLASTER_VIEW_ANIMATED, W_Model("h_laser_animated.iqm")); MODEL(BLASTER_WORLD, W_Model("v_laser.md3")); +MODEL(BLASTER_WORLD_ANIMATED, W_Model("v_laser_animated.md3")); MODEL(BLASTER_ITEM, W_Model("g_laser.md3")); MODEL(SHOTGUN_MUZZLEFLASH, "models/uziflash.md3"); MODEL(SHOTGUN_VIEW, W_Model("h_shotgun.iqm")); +MODEL(SHOTGUN_VIEW_ANIMATED, W_Model("h_shotgun_animated.iqm")); MODEL(SHOTGUN_WORLD, W_Model("v_shotgun.md3")); +MODEL(SHOTGUN_WORLD_ANIMATED, W_Model("v_shotgun_animated.md3")); MODEL(SHOTGUN_ITEM, W_Model("g_shotgun.md3")); MODEL(MACHINEGUN_MUZZLEFLASH, "models/uziflash.md3"); MODEL(MACHINEGUN_VIEW, W_Model("h_uzi.iqm")); +MODEL(MACHINEGUN_VIEW_ANIMATED, W_Model("h_uzi_animated.iqm")); MODEL(MACHINEGUN_WORLD, W_Model("v_uzi.md3")); +MODEL(MACHINEGUN_WORLD_ANIMATED, W_Model("v_uzi_animated.md3")); MODEL(MACHINEGUN_ITEM, W_Model("g_uzi.md3")); MODEL(MORTAR_VIEW, W_Model("h_gl.iqm")); +MODEL(MORTAR_VIEW_ANIMATED, W_Model("h_gl_animated.iqm")); MODEL(MORTAR_WORLD, W_Model("v_gl.md3")); +MODEL(MORTAR_WORLD_ANIMATED, W_Model("v_gl_animated.md3")); MODEL(MORTAR_ITEM, W_Model("g_gl.md3")); MODEL(MINELAYER_MUZZLEFLASH, "models/flash.md3"); MODEL(MINELAYER_MINE, "models/mine.md3"); MODEL(MINELAYER_VIEW, W_Model("h_minelayer.iqm")); +MODEL(MINELAYER_VIEW_ANIMATED, W_Model("h_minelayer_animated.iqm")); MODEL(MINELAYER_WORLD, W_Model("v_minelayer.md3")); +MODEL(MINELAYER_WORLD_ANIMATED, W_Model("v_minelayer_animated.md3")); MODEL(MINELAYER_ITEM, W_Model("g_minelayer.md3")); MODEL(ELECTRO_VIEW, W_Model("h_electro.iqm")); +MODEL(ELECTRO_VIEW_ANIMATED, W_Model("h_electro_animated.iqm")); MODEL(ELECTRO_WORLD, W_Model("v_electro.md3")); +MODEL(ELECTRO_WORLD_ANIMATED, W_Model("v_electro_animated.md3")); MODEL(ELECTRO_ITEM, W_Model("g_electro.md3")); MODEL(CRYLINK_VIEW, W_Model("h_crylink.iqm")); +MODEL(CRYLINK_VIEW_ANIMATED, W_Model("h_crylink_animated.iqm")); MODEL(CRYLINK_WORLD, W_Model("v_crylink.md3")); +MODEL(CRYLINK_WORLD_ANIMATED, W_Model("v_crylink_animated.md3")); MODEL(CRYLINK_ITEM, W_Model("g_crylink.md3")); MODEL(VORTEX_MUZZLEFLASH, "models/nexflash.md3"); MODEL(VORTEX_VIEW, W_Model("h_nex.iqm")); +MODEL(VORTEX_VIEW_ANIMATED, W_Model("h_nex_animated.iqm")); MODEL(VORTEX_WORLD, W_Model("v_nex.md3")); +MODEL(VORTEX_WORLD_ANIMATED, W_Model("v_nex_animated.md3")); MODEL(VORTEX_ITEM, W_Model("g_nex.md3")); MODEL(HAGAR_VIEW, W_Model("h_hagar.iqm")); +MODEL(HAGAR_VIEW_ANIMATED, W_Model("h_hagar_animated.iqm")); MODEL(HAGAR_WORLD, W_Model("v_hagar.md3")); +MODEL(HAGAR_WORLD_ANIMATED, W_Model("v_hagar_animated.md3")); MODEL(HAGAR_ITEM, W_Model("g_hagar.md3")); MODEL(DEVASTATOR_MUZZLEFLASH, "models/flash.md3"); MODEL(DEVASTATOR_VIEW, W_Model("h_rl.iqm")); +MODEL(DEVASTATOR_VIEW_ANIMATED, W_Model("h_rl_animated.iqm")); MODEL(DEVASTATOR_WORLD, W_Model("v_rl.md3")); +MODEL(DEVASTATOR_WORLD_ANIMATED, W_Model("v_rl_animated.md3")); MODEL(DEVASTATOR_ITEM, W_Model("g_rl.md3")); MODEL(PORTAL, "models/portal.md3"); MODEL(PORTO_VIEW, W_Model("h_porto.iqm")); +MODEL(PORTO_VIEW_ANIMATED, W_Model("h_porto_animated.iqm")); MODEL(PORTO_WORLD, W_Model("v_porto.md3")); +MODEL(PORTO_WORLD_ANIMATED, W_Model("v_porto_animated.md3")); MODEL(PORTO_ITEM, W_Model("g_porto.md3")); MODEL(VAPORIZER_MUZZLEFLASH, "models/nexflash.md3"); MODEL(VAPORIZER_VIEW, W_Model("h_minstanex.iqm")); +MODEL(VAPORIZER_VIEW_ANIMATED, W_Model("h_minstanex_animated.iqm")); MODEL(VAPORIZER_WORLD, W_Model("v_minstanex.md3")); +MODEL(VAPORIZER_WORLD_ANIMATED, W_Model("v_minstanex_animated.md3")); MODEL(VAPORIZER_ITEM, W_Model("g_minstanex.md3")); MODEL(HOOK, "models/hook.md3"); MODEL(HOOK_VIEW, W_Model("h_hookgun.iqm")); +MODEL(HOOK_VIEW_ANIMATED, W_Model("h_hookgun_animated.iqm")); MODEL(HOOK_WORLD, W_Model("v_hookgun.md3")); +MODEL(HOOK_WORLD_ANIMATED, W_Model("v_hookgun_animated.md3")); MODEL(HOOK_ITEM, W_Model("g_hookgun.md3")); MODEL(HLAC_VIEW, W_Model("h_hlac.iqm")); +MODEL(HLAC_VIEW_ANIMATED, W_Model("h_hlac_animated.iqm")); MODEL(HLAC_WORLD, W_Model("v_hlac.md3")); +MODEL(HLAC_WORLD_ANIMATED, W_Model("v_hlac_animated.md3")); MODEL(HLAC_ITEM, W_Model("g_hlac.md3")); MODEL(TUBA_VIEW, W_Model("h_tuba.iqm")); +MODEL(TUBA_VIEW_ANIMATED, W_Model("h_tuba_animated.iqm")); MODEL(TUBA_WORLD, W_Model("v_tuba.md3")); +MODEL(TUBA_WORLD_ANIMATED, W_Model("v_tuba_animated.md3")); MODEL(TUBA_ITEM, W_Model("g_tuba.md3")); MODEL(ACCORDION_VIEW, W_Model("h_akordeon.iqm")); +MODEL(ACCORDION_VIEW_ANIMATED, W_Model("h_akordeon_animated.iqm")); MODEL(ACCORDION_WORLD, W_Model("v_akordeon.md3")); +MODEL(ACCORDION_WORLD_ANIMATED, W_Model("v_akordeon_animated.md3")); MODEL(KLEINBOTTLE_VIEW, W_Model("h_kleinbottle.iqm")); +MODEL(KLEINBOTTLE_VIEW_ANIMATED, W_Model("h_kleinbottle_animated.iqm")); MODEL(KLEINBOTTLE_WORLD, W_Model("v_kleinbottle.md3")); +MODEL(KLEINBOTTLE_WORLD_ANIMATED, W_Model("v_kleinbottle_animated.md3")); MODEL(RIFLE_VIEW, W_Model("h_campingrifle.iqm")); +MODEL(RIFLE_VIEW_ANIMATED, W_Model("h_campingrifle_animated.iqm")); MODEL(RIFLE_WORLD, W_Model("v_campingrifle.md3")); +MODEL(RIFLE_WORLD_ANIMATED, W_Model("v_campingrifle_animated.md3")); MODEL(RIFLE_ITEM, W_Model("g_campingrifle.md3")); MODEL(FIREBALL_SPHERE, "models/sphere/sphere.md3"); MODEL(FIREBALL_VIEW, W_Model("h_fireball.iqm")); +MODEL(FIREBALL_VIEW_ANIMATED, W_Model("h_fireball_animated.iqm")); MODEL(FIREBALL_WORLD, W_Model("v_fireball.md3")); +MODEL(FIREBALL_WORLD_ANIMATED, W_Model("v_fireball_animated.md3")); MODEL(FIREBALL_ITEM, W_Model("g_fireball.md3")); MODEL(SEEKER_VIEW, W_Model("h_seeker.iqm")); +MODEL(SEEKER_VIEW_ANIMATED, W_Model("h_seeker_animated.iqm")); MODEL(SEEKER_WORLD, W_Model("v_seeker.md3")); +MODEL(SEEKER_WORLD_ANIMATED, W_Model("v_seeker_animated.md3")); MODEL(SEEKER_ITEM, W_Model("g_seeker.md3")); MODEL(SHOCKWAVE_MUZZLEFLASH, "models/uziflash.md3"); MODEL(SHOCKWAVE_VIEW, W_Model("h_shotgun.iqm")); +MODEL(SHOCKWAVE_VIEW_ANIMATED, W_Model("h_shotgun_animated.iqm")); MODEL(SHOCKWAVE_WORLD, W_Model("v_shotgun.md3")); +MODEL(SHOCKWAVE_WORLD_ANIMATED, W_Model("v_shotgun_animated.md3")); MODEL(SHOCKWAVE_ITEM, W_Model("g_shotgun.md3")); MODEL(ARC_MUZZLEFLASH, "models/flash.md3"); MODEL(ARC_VIEW, W_Model("h_arc.iqm")); +MODEL(ARC_VIEW_ANIMATED, W_Model("h_arc_animated.iqm")); MODEL(ARC_WORLD, W_Model("v_arc.md3")); +MODEL(ARC_WORLD_ANIMATED, W_Model("v_arc_animated.md3")); MODEL(ARC_ITEM, W_Model("g_arc.md3")); MODEL(HMG_MUZZLEFLASH, "models/uziflash.md3"); MODEL(HMG_VIEW, W_Model("h_ok_hmg.iqm")); +MODEL(HMG_VIEW_ANIMATED, W_Model("h_ok_hmg_animated.iqm")); MODEL(HMG_WORLD, W_Model("v_ok_hmg.md3")); +MODEL(HMG_WORLD_ANIMATED, W_Model("v_ok_hmg_animated.md3")); MODEL(HMG_ITEM, W_Model("g_ok_hmg.md3")); MODEL(RPC_MUZZLEFLASH, "models/flash.md3"); MODEL(RPC_VIEW, W_Model("h_ok_rl.iqm")); +MODEL(RPC_VIEW_ANIMATED, W_Model("h_ok_rl_animated.iqm")); MODEL(RPC_WORLD, W_Model("v_ok_rl.md3")); +MODEL(RPC_WORLD_ANIMATED, W_Model("v_ok_rl_animated.md3")); MODEL(RPC_ITEM, W_Model("g_ok_rl.md3")); MODEL(TUR_GIB_BASE1, "models/turrets/base-gib1.md3"); diff --git a/qcsrc/common/models/model.qh b/qcsrc/common/models/model.qh index 7a1e7d73c..4eb01c31b 100644 --- a/qcsrc/common/models/model.qh +++ b/qcsrc/common/models/model.qh @@ -15,7 +15,8 @@ CLASS(Model, Object) TC(Model, this); string s = this.model_str(); if (s != "" && s != "null" && !fexists(s)) { - LOG_WARNF("Missing model: \"%s\"", s); + if(substring(s, 0, 14) != "models/weapons") + LOG_WARNF("Missing model: \"%s\"", s); return; } profile(sprintf("precache_model(\"%s\")", s)); diff --git a/qcsrc/common/weapons/all.qc b/qcsrc/common/weapons/all.qc index d8c76dbf3..37c6724dd 100644 --- a/qcsrc/common/weapons/all.qc +++ b/qcsrc/common/weapons/all.qc @@ -404,11 +404,26 @@ void CL_WeaponEntity_SetModel(entity this, string name, bool _anim) { // if there is a child entity, hide it until we're sure we use it if (this.weaponchild) this.weaponchild.model = ""; - _setmodel(this, W_Model(strcat("v_", name, ".md3"))); + bool use_animated = false; + string wmodel = W_Model(strcat("v_", name, ".md3")); + string hmodel = W_Model(strcat("h_", name, ".iqm")); + #ifdef CSQC + use_animated = autocvar_cl_weapons_animate; + #endif + if(use_animated) + { + string tmdl = W_Model(strcat("v_", name, "_animated.md3")); + string ymdl = W_Model(strcat("h_", name, "_animated.iqm")); + if(fexists(tmdl)) + wmodel = tmdl; + if(fexists(ymdl)) + hmodel = ymdl; + } + _setmodel(this, wmodel); int v_shot_idx; // used later (v_shot_idx = gettagindex(this, "shot")) || (v_shot_idx = gettagindex(this, "tag_shot")); - _setmodel(this, W_Model(strcat("h_", name, ".iqm"))); + _setmodel(this, hmodel); // preset some defaults that work great for renamed zym files (which don't need an animinfo) this.anim_fire1 = animfixfps(this, '0 1 0.01', '0 0 0'); this.anim_fire2 = animfixfps(this, '1 1 0.01', '0 0 0'); @@ -428,7 +443,7 @@ void CL_WeaponEntity_SetModel(entity this, string name, bool _anim) this.weaponchild.renderflags |= RF_VIEWMODEL; #endif } - _setmodel(this.weaponchild, W_Model(strcat("v_", name, ".md3"))); + _setmodel(this.weaponchild, wmodel); setsize(this.weaponchild, '0 0 0', '0 0 0'); setattachment(this.weaponchild, this, t); } @@ -555,14 +570,22 @@ REGISTER_NET_TEMP(wframe) #ifdef CSQC NET_HANDLE(wframe, bool isNew) { - vector a; - a.x = ReadCoord(); - a.y = ReadCoord(); - a.z = ReadCoord(); + int fr = ReadByte(); + float wrate = ReadCoord(); int slot = ReadByte(); bool restartanim = ReadByte(); entity wepent = viewmodels[slot]; - if(a.x == wepent.anim_idle_x) // we don't need to enforce idle animation + vector a = '0 0 0'; + if (fr == WFRAME_IDLE) a = wepent.anim_idle; + else if (fr == WFRAME_FIRE1) a = wepent.anim_fire1; + else if (fr == WFRAME_FIRE2) a = wepent.anim_fire2; + else // if (fr == WFRAME_RELOAD) + a = wepent.anim_reload; + a.z *= wrate; + + //LOG_INFO(vtos(a), " ", ftos(fr), " ", ftos(wrate), "\n"); + + if(fr == WFRAME_IDLE) // we don't need to enforce idle animation wepent.animstate_looping = false; else anim_set(wepent, a, !restartanim, restartanim, restartanim); @@ -585,15 +608,14 @@ NET_HANDLE(wframe, bool isNew) #endif #ifdef SVQC -void wframe_send(entity actor, entity weaponentity, vector a, bool restartanim) +void wframe_send(entity actor, entity weaponentity, int a, bool restartanim) { if (!IS_REAL_CLIENT(actor)) return; int channel = MSG_ONE; msg_entity = actor; WriteHeader(channel, wframe); - WriteCoord(channel, a.x); - WriteCoord(channel, a.y); - WriteCoord(channel, a.z); + WriteByte(channel, a); + WriteCoord(channel, W_WeaponRateFactor(actor)); WriteByte(channel, weaponslot(weaponentity.weaponentity_fld)); WriteByte(channel, restartanim); WriteByte(channel, weaponentity.state); diff --git a/qcsrc/server/weapons/weaponsystem.qc b/qcsrc/server/weapons/weaponsystem.qc index 2e4e160b3..a0cc62b2a 100644 --- a/qcsrc/server/weapons/weaponsystem.qc +++ b/qcsrc/server/weapons/weaponsystem.qc @@ -331,7 +331,7 @@ bool weapon_prepareattack(Weapon thiswep, entity actor, .entity weaponentity, bo return false; } -void wframe_send(entity actor, entity weaponentity, vector a, bool restartanim); +void wframe_send(entity actor, entity weaponentity, int a, bool restartanim); /** * @param t defer thinking until time + t @@ -357,15 +357,6 @@ void weapon_thinkf(entity actor, .entity weaponentity, WFRAME fr, float t, void( vector or = v_right; vector ou = v_up; - vector a = '0 0 0'; - this.wframe = fr; - if (fr == WFRAME_IDLE) a = this.anim_idle; - else if (fr == WFRAME_FIRE1) a = this.anim_fire1; - else if (fr == WFRAME_FIRE2) a = this.anim_fire2; - else // if (fr == WFRAME_RELOAD) - a = this.anim_reload; - a.z *= g_weaponratefactor; - v_forward = of; v_right = or; v_up = ou; @@ -395,7 +386,7 @@ void weapon_thinkf(entity actor, .entity weaponentity, WFRAME fr, float t, void( { FOREACH_CLIENT(true, LAMBDA( if(it == actor || (IS_SPEC(it) && it.enemy == actor)) - wframe_send(it, this, a, restartanim); + wframe_send(it, this, fr, restartanim); )); }