From 1245fb3e998e9ace1b301dbe4bfb84b55f25bdf4 Mon Sep 17 00:00:00 2001 From: TimePath Date: Sat, 31 Oct 2015 20:06:06 +1100 Subject: [PATCH] Viewmodels: CSQC rendering --- qcsrc/client/progs.inc | 1 + qcsrc/client/view.qc | 30 ++ qcsrc/common/anim.qc | 42 +++ qcsrc/common/anim.qh | 7 + qcsrc/common/weapons/all.qc | 459 ++++++++++++++++----------- qcsrc/common/weapons/all.qh | 33 +- qcsrc/lib/net.qh | 2 +- qcsrc/server/cl_player.qc | 10 - qcsrc/server/defs.qh | 20 -- qcsrc/server/g_subs.qc | 44 --- qcsrc/server/progs.inc | 1 + qcsrc/server/weapons/weaponsystem.qc | 67 +--- qcsrc/server/weapons/weaponsystem.qh | 12 - 13 files changed, 402 insertions(+), 326 deletions(-) create mode 100644 qcsrc/common/anim.qc create mode 100644 qcsrc/common/anim.qh diff --git a/qcsrc/client/progs.inc b/qcsrc/client/progs.inc index 5c110e2b89..2b9c22a24f 100644 --- a/qcsrc/client/progs.inc +++ b/qcsrc/client/progs.inc @@ -32,6 +32,7 @@ #include "weapons/projectile.qc" // TODO +#include "../common/anim.qc" #include "../common/animdecide.qc" #include "../common/effects/effectinfo.qc" #include "../common/mapinfo.qc" diff --git a/qcsrc/client/view.qc b/qcsrc/client/view.qc index c7144372a3..54fefa68e2 100644 --- a/qcsrc/client/view.qc +++ b/qcsrc/client/view.qc @@ -10,6 +10,7 @@ #include "mutators/events.qh" +#include "../common/anim.qh" #include "../common/constants.qh" #include "../common/mapinfo.qh" #include "../common/gamemodes/all.qh" @@ -29,6 +30,24 @@ #include "../lib/warpzone/client.qh" #include "../lib/warpzone/common.qh" +void viewmodel_draw(entity this) +{ + int c = stof(getplayerkeyvalue(player_localnum, "colors")); + vector g = colormapPaletteColor(c & 0x0F, true) * 2; + for (entity e = this; e; e = e.weaponchild) + { + e.colormap = c; + e.glowmod = g; + } +} + +entity viewmodel; +STATIC_INIT(viewmodel) { + viewmodel = new(viewmodel); + viewmodel.drawmask = MASK_NORMAL; + viewmodel.draw = viewmodel_draw; +} + entity porto; vector polyline[16]; void Porto_Draw(entity this) @@ -1234,6 +1253,17 @@ void CSQC_UpdateView(float w, float h) WarpZone_FixView(); //WarpZone_FixPMove(); + { + static string name_last; + string name = get_weaponinfo(switchingweapon).mdl; + if (name != name_last) + { + CL_WeaponEntity_SetModel(viewmodel, name_last = name); + updateanim(viewmodel); + if (!viewmodel.animstate_override) + setanim(viewmodel, viewmodel.anim_idle, true, false, false); + } + } vector ov_org = '0 0 0'; vector ov_mid = '0 0 0'; diff --git a/qcsrc/common/anim.qc b/qcsrc/common/anim.qc new file mode 100644 index 0000000000..c2781c666e --- /dev/null +++ b/qcsrc/common/anim.qc @@ -0,0 +1,42 @@ +void setanim(entity e, vector anim, bool looping, bool override, int restart) +{ + if (!anim) return; // no animation was given to us! We can't use this. + + if (anim.x == e.animstate_startframe) + { + if (anim.y == e.animstate_numframes) + { + if (anim.z == e.animstate_framerate) + { + if (!restart) return; + if (restart > 0 && anim.y == 1) // ZYM animation + BITXOR_ASSIGN(e.effects, EF_RESTARTANIM_BIT); + } + } + } + e.animstate_startframe = anim.x; + e.animstate_numframes = anim.y; + e.animstate_framerate = anim.z; + e.animstate_starttime = servertime - 0.1 * frametime; // shift it a little bit into the past to prevent float inaccuracy hiccups + e.animstate_endtime = e.animstate_starttime + e.animstate_numframes / e.animstate_framerate; + e.animstate_looping = looping; + e.animstate_override = override; + e.frame = e.animstate_startframe; + e.frame1time = servertime; +} + +void updateanim(entity e) +{ + if (time >= e.animstate_endtime) + { + if (e.animstate_looping) + { + e.animstate_starttime = e.animstate_endtime; + e.animstate_endtime = e.animstate_starttime + e.animstate_numframes / e.animstate_framerate; + } + e.animstate_override = false; + } + e.frame = e.animstate_startframe + bound(0, (time - e.animstate_starttime) * e.animstate_framerate, + e.animstate_numframes - 1); + // print(ftos(time), " -> ", ftos(e.frame), "\n"); +} diff --git a/qcsrc/common/anim.qh b/qcsrc/common/anim.qh new file mode 100644 index 0000000000..c1dee151b6 --- /dev/null +++ b/qcsrc/common/anim.qh @@ -0,0 +1,7 @@ +#ifndef ANIM_H +#define ANIM_H + +void setanim(entity e, vector anim, float looping, float override, float restart); +void updateanim(entity e); + +#endif diff --git a/qcsrc/common/weapons/all.qc b/qcsrc/common/weapons/all.qc index f97ed6d893..cb397e8e5e 100644 --- a/qcsrc/common/weapons/all.qc +++ b/qcsrc/common/weapons/all.qc @@ -20,34 +20,34 @@ #include "../../lib/csqcmodel/cl_model.qh" #elif defined(MENUQC) #elif defined(SVQC) - #include "../../lib/warpzone/anglestransform.qh" - #include "../../lib/warpzone/common.qh" - #include "../../lib/warpzone/util_server.qh" - #include "../../lib/warpzone/server.qh" - #include "../constants.qh" - #include "../stats.qh" - #include "../teams.qh" - #include "../util.qh" - #include "../buffs/all.qh" - #include "../monsters/all.qh" - #include "config.qh" - #include "../../server/weapons/csqcprojectile.qh" - #include "../../server/weapons/tracing.qh" - #include "../../server/t_items.qh" - #include "../../server/autocvars.qh" - #include "../../server/constants.qh" - #include "../../server/defs.qh" - #include "../notifications.qh" - #include "../deathtypes/all.qh" - #include "../../server/mutators/all.qh" - #include "../mapinfo.qh" - #include "../../server/command/common.qh" - #include "../../lib/csqcmodel/sv_model.qh" - #include "../../server/portals.qh" - #include "../../server/g_hook.qh" + #include "../../lib/warpzone/anglestransform.qh" + #include "../../lib/warpzone/common.qh" + #include "../../lib/warpzone/util_server.qh" + #include "../../lib/warpzone/server.qh" + #include "../constants.qh" + #include "../stats.qh" + #include "../teams.qh" + #include "../util.qh" + #include "../buffs/all.qh" + #include "../monsters/all.qh" + #include "config.qh" + #include "../../server/weapons/csqcprojectile.qh" + #include "../../server/weapons/tracing.qh" + #include "../../server/t_items.qh" + #include "../../server/autocvars.qh" + #include "../../server/constants.qh" + #include "../../server/defs.qh" + #include "../notifications.qh" + #include "../deathtypes/all.qh" + #include "../../server/mutators/all.qh" + #include "../mapinfo.qh" + #include "../../server/command/common.qh" + #include "../../lib/csqcmodel/sv_model.qh" + #include "../../server/portals.qh" + #include "../../server/g_hook.qh" #endif #ifndef MENUQC -#include "calculations.qc" + #include "calculations.qc" #endif #define IMPLEMENTATION #include "all.inc" @@ -55,76 +55,66 @@ // WEAPON PLUGIN SYSTEM -WepSet WepSet_FromWeapon(int a) { +WepSet WepSet_FromWeapon(int a) +{ a -= WEP_FIRST; if (Weapons_MAX > 24) - if (a >= 24) { - a -= 24; - if (Weapons_MAX > 48) - if (a >= 24) { + if (a >= 24) + { a -= 24; - return '0 0 1' * power2of(a); + if (Weapons_MAX > 48) + if (a >= 24) + { + a -= 24; + return '0 0 1' * power2of(a); + } + return '0 1 0' * power2of(a); } - return '0 1 0' * power2of(a); - } return '1 0 0' * power2of(a); } #ifdef SVQC -void WepSet_AddStat() -{ - addstat(STAT_WEAPONS, AS_INT, weapons_x); - if (Weapons_MAX > 24) - addstat(STAT_WEAPONS2, AS_INT, weapons_y); - if (Weapons_MAX > 48) - addstat(STAT_WEAPONS3, AS_INT, weapons_z); -} -void WepSet_AddStat_InMap() -{ - addstat(STAT_WEAPONSINMAP, AS_INT, weaponsinmap_x); - if (Weapons_MAX > 24) - addstat(STAT_WEAPONSINMAP2, AS_INT, weaponsinmap_y); - if (Weapons_MAX > 48) - addstat(STAT_WEAPONSINMAP3, AS_INT, weaponsinmap_z); -} -void WriteWepSet(float dst, WepSet w) -{ - if (Weapons_MAX > 48) - WriteInt72_t(dst, w); - else if (Weapons_MAX > 24) - WriteInt48_t(dst, w); - else - WriteInt24_t(dst, w.x); -} + void WepSet_AddStat() + { + addstat(STAT_WEAPONS, AS_INT, weapons_x); + if (Weapons_MAX > 24) addstat(STAT_WEAPONS2, AS_INT, weapons_y); + if (Weapons_MAX > 48) addstat(STAT_WEAPONS3, AS_INT, weapons_z); + } + void WepSet_AddStat_InMap() + { + addstat(STAT_WEAPONSINMAP, AS_INT, weaponsinmap_x); + if (Weapons_MAX > 24) addstat(STAT_WEAPONSINMAP2, AS_INT, weaponsinmap_y); + if (Weapons_MAX > 48) addstat(STAT_WEAPONSINMAP3, AS_INT, weaponsinmap_z); + } + void WriteWepSet(float dst, WepSet w) + { + if (Weapons_MAX > 48) WriteInt72_t(dst, w); + else if (Weapons_MAX > 24) WriteInt48_t(dst, w); + else WriteInt24_t(dst, w.x); + } #endif #ifdef CSQC -WepSet WepSet_GetFromStat() -{ - WepSet w = '0 0 0'; - w.x = getstati(STAT_WEAPONS); - if (Weapons_MAX > 24) - w.y = getstati(STAT_WEAPONS2); - if (Weapons_MAX > 48) - w.z = getstati(STAT_WEAPONS3); - return w; -} -WepSet WepSet_GetFromStat_InMap() -{ - WepSet w = '0 0 0'; - w_x = getstati(STAT_WEAPONSINMAP); - if (Weapons_MAX > 24) - w_y = getstati(STAT_WEAPONSINMAP2); - if (Weapons_MAX > 48) - w_z = getstati(STAT_WEAPONSINMAP3); - return w; -} -WepSet ReadWepSet() -{ - if (Weapons_MAX > 48) - return ReadInt72_t(); - if (Weapons_MAX > 24) - return ReadInt48_t(); - return ReadInt24_t() * '1 0 0'; -} + WepSet WepSet_GetFromStat() + { + WepSet w = '0 0 0'; + w.x = getstati(STAT_WEAPONS); + if (Weapons_MAX > 24) w.y = getstati(STAT_WEAPONS2); + if (Weapons_MAX > 48) w.z = getstati(STAT_WEAPONS3); + return w; + } + WepSet WepSet_GetFromStat_InMap() + { + WepSet w = '0 0 0'; + w_x = getstati(STAT_WEAPONSINMAP); + if (Weapons_MAX > 24) w_y = getstati(STAT_WEAPONSINMAP2); + if (Weapons_MAX > 48) w_z = getstati(STAT_WEAPONSINMAP3); + return w; + } + WepSet ReadWepSet() + { + if (Weapons_MAX > 48) return ReadInt72_t(); + if (Weapons_MAX > 24) return ReadInt48_t(); + return ReadInt24_t() * '1 0 0'; + } #endif string W_FixWeaponOrder(string order, float complete) @@ -134,26 +124,25 @@ string W_FixWeaponOrder(string order, float complete) string W_NameWeaponOrder_MapFunc(string s) { entity wi; - if(s == "0" || stof(s)) + if (s == "0" || stof(s)) { wi = get_weaponinfo(stof(s)); - if(wi != WEP_Null) - return wi.netname; + if (wi != WEP_Null) return wi.netname; } return s; } string W_UndeprecateName(string s) { - switch ( s ) + switch (s) { - case "nex" : return "vortex"; - case "rocketlauncher" : return "devastator"; - case "laser" : return "blaster"; - case "minstanex" : return "vaporizer"; + case "nex": return "vortex"; + case "rocketlauncher": return "devastator"; + case "laser": return "blaster"; + case "minstanex": return "vaporizer"; case "grenadelauncher": return "mortar"; - case "uzi" : return "machinegun"; - default : return s; + case "uzi": return "machinegun"; + default: return s; } } string W_NameWeaponOrder(string order) @@ -163,12 +152,10 @@ string W_NameWeaponOrder(string order) string W_NumberWeaponOrder_MapFunc(string s) { int i; - if(s == "0" || stof(s)) - return s; + if (s == "0" || stof(s)) return s; s = W_UndeprecateName(s); - for(i = WEP_FIRST; i <= WEP_LAST; ++i) - if(s == get_weaponinfo(i).netname) - return ftos(i); + for (i = WEP_FIRST; i <= WEP_LAST; ++i) + if (s == get_weaponinfo(i).netname) return ftos(i); return s; } string W_NumberWeaponOrder(string order) @@ -192,23 +179,24 @@ float W_FixWeaponOrder_BuildImpulseList_cmp(int i, int j, entity pass) e1 = get_weaponinfo(W_FixWeaponOrder_BuildImpulseList_buf[i]); e2 = get_weaponinfo(W_FixWeaponOrder_BuildImpulseList_buf[j]); d = (e1.impulse + 9) % 10 - (e2.impulse + 9) % 10; - if(d != 0) - return -d; // high impulse first! - return - strstrofs(strcat(" ", W_FixWeaponOrder_BuildImpulseList_order, " "), sprintf(" %d ", W_FixWeaponOrder_BuildImpulseList_buf[i]), 0) - - - strstrofs(strcat(" ", W_FixWeaponOrder_BuildImpulseList_order, " "), sprintf(" %d ", W_FixWeaponOrder_BuildImpulseList_buf[j]), 0) - ; // low char index first! + if (d != 0) return -d; // high impulse first! + return strstrofs(strcat(" ", W_FixWeaponOrder_BuildImpulseList_order, " "), + sprintf(" %d ", W_FixWeaponOrder_BuildImpulseList_buf[i]), 0) + - + strstrofs(strcat(" ", W_FixWeaponOrder_BuildImpulseList_order, " "), + sprintf(" %d ", W_FixWeaponOrder_BuildImpulseList_buf[j]), 0) + ; // low char index first! } string W_FixWeaponOrder_BuildImpulseList(string o) { int i; W_FixWeaponOrder_BuildImpulseList_order = o; - for(i = WEP_FIRST; i <= WEP_LAST; ++i) + for (i = WEP_FIRST; i <= WEP_LAST; ++i) W_FixWeaponOrder_BuildImpulseList_buf[i - WEP_FIRST] = i; - heapsort(WEP_LAST - WEP_FIRST + 1, W_FixWeaponOrder_BuildImpulseList_swap, W_FixWeaponOrder_BuildImpulseList_cmp, world); + heapsort(WEP_LAST - WEP_FIRST + 1, W_FixWeaponOrder_BuildImpulseList_swap, W_FixWeaponOrder_BuildImpulseList_cmp, + world); o = ""; - for(i = WEP_FIRST; i <= WEP_LAST; ++i) + for (i = WEP_FIRST; i <= WEP_LAST; ++i) o = strcat(o, " ", ftos(W_FixWeaponOrder_BuildImpulseList_buf[i - WEP_FIRST])); W_FixWeaponOrder_BuildImpulseList_order = string_null; return substring(o, 1, -1); @@ -221,8 +209,7 @@ string W_FixWeaponOrder_AllowIncomplete(string order) string W_FixWeaponOrder_ForceComplete(string order) { - if(order == "") - order = W_NumberWeaponOrder(cvar_defstring("cl_weaponpriority")); + if (order == "") order = W_NumberWeaponOrder(cvar_defstring("cl_weaponpriority")); return W_FixWeaponOrder(order, 1); } @@ -233,12 +220,11 @@ void W_RandomWeapons(entity e, float n) WepSet result; remaining = e.weapons; result = '0 0 0'; - for(i = 0; i < n; ++i) + for (i = 0; i < n; ++i) { RandomSelection_Init(); - for(j = WEP_FIRST; j <= WEP_LAST; ++j) - if(remaining & WepSet_FromWeapon(j)) - RandomSelection_Add(world, j, string_null, 1, 1); + for (j = WEP_FIRST; j <= WEP_LAST; ++j) + if (remaining & WepSet_FromWeapon(j)) RandomSelection_Add(world, j, string_null, 1, 1); result |= WepSet_FromWeapon(RandomSelection_chosen_float); remaining &= ~WepSet_FromWeapon(RandomSelection_chosen_float); } @@ -255,57 +241,59 @@ string GetAmmoPicture(.int ammotype) case ammo_cells: return ITEM_Cells.m_icon; case ammo_plasma: return ITEM_Plasma.m_icon; case ammo_fuel: return ITEM_JetpackFuel.m_icon; - default: return ""; // wtf, no ammo type? + default: return ""; // wtf, no ammo type? } } #ifdef CSQC -.int GetAmmoFieldFromNum(int i) -{ - switch(i) + .int GetAmmoFieldFromNum(int i) { - case 0: return ammo_shells; - case 1: return ammo_nails; - case 2: return ammo_rockets; - case 3: return ammo_cells; - case 4: return ammo_plasma; - case 5: return ammo_fuel; - default: return ammo_none; + switch (i) + { + case 0: return ammo_shells; + case 1: return ammo_nails; + case 2: return ammo_rockets; + case 3: return ammo_cells; + case 4: return ammo_plasma; + case 5: return ammo_fuel; + default: return ammo_none; + } } -} -int GetAmmoStat(.int ammotype) -{ - switch(ammotype) + int GetAmmoStat(.int ammotype) { - case ammo_shells: return STAT_SHELLS; - case ammo_nails: return STAT_NAILS; - case ammo_rockets: return STAT_ROCKETS; - case ammo_cells: return STAT_CELLS; - case ammo_plasma: return STAT_PLASMA; - case ammo_fuel: return STAT_FUEL; - default: return -1; + switch (ammotype) + { + case ammo_shells: return STAT_SHELLS; + case ammo_nails: return STAT_NAILS; + case ammo_rockets: return STAT_ROCKETS; + case ammo_cells: return STAT_CELLS; + case ammo_plasma: return STAT_PLASMA; + case ammo_fuel: return STAT_FUEL; + default: return -1; + } } -} #endif string W_Sound(string w_snd) { #define extensions(X) X(wav) X(ogg) - #define tryext(ext) { if (fexists(strcat("sound/", output = strcat("weapons/", w_snd, "."#ext)))) break; } + #define tryext(ext) { if (fexists(strcat("sound/", output = strcat("weapons/", w_snd, "." #ext)))) break; } string output; - do { + do + { extensions(tryext); - #undef tryext - #undef extensions +#undef tryext +#undef extensions output = strcat("weapons/", w_snd); - } while (0); + } + while (0); #ifdef SVQC - MUTATOR_CALLHOOK(WeaponSound, w_snd, output); - return weapon_sound_output; + MUTATOR_CALLHOOK(WeaponSound, w_snd, output); + return weapon_sound_output; #else - return output; + return output; #endif } @@ -313,14 +301,74 @@ string W_Model(string w_mdl) { string output = strcat("models/weapons/", w_mdl); #ifdef SVQC - MUTATOR_CALLHOOK(WeaponModel, w_mdl, output); - return weapon_model_output; + MUTATOR_CALLHOOK(WeaponModel, w_mdl, output); + return weapon_model_output; #else - return output; + return output; #endif } +#ifndef MENUQC +vector shotorg_adjustfromclient(vector vecs, float y_is_right, float algn) +{ + switch (algn) + { + default: + case 3: + // right alignment + break; + case 4: + // left + vecs.y = -vecs.y; + break; + case 1: + case 2: + // center + vecs.y = 0; + vecs.z -= 2; + break; + } + return vecs; +} + +vector shotorg_adjust_values(vector vecs, bool y_is_right, bool visual, int algn) +{ #ifdef SVQC + string s; +#endif + if (visual) + { + vecs = shotorg_adjustfromclient(vecs, y_is_right, algn); + } +#ifdef SVQC + else if (autocvar_g_shootfromeye) + { + vecs.y = vecs.z = 0; + } + else if (autocvar_g_shootfromcenter) + { + vecs.y = 0; + vecs.z -= 2; + } + else if ((s = autocvar_g_shootfromfixedorigin) != "") + { + vector v = stov(s); + if (y_is_right) v.y = -v.y; + if (v.x != 0) vecs.x = v.x; + vecs.y = v.y; + vecs.z = v.z; + } +#endif + else // just do the same as top + { + vecs = shotorg_adjustfromclient(vecs, y_is_right, algn); + } + + return vecs; +} + +#define shotorg_adjust shotorg_adjust_values + /** * supported formats: * @@ -372,7 +420,7 @@ string W_Model(string w_mdl) * call again with "" * remove the ent */ -void CL_WeaponEntity_SetModel(entity this, int slot, string name) +void CL_WeaponEntity_SetModel(entity this, string name) { if (name == "") { @@ -392,7 +440,7 @@ void CL_WeaponEntity_SetModel(entity this, int slot, string name) // 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"))); - int v_shot_idx; // used later + 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"))); @@ -407,7 +455,13 @@ void CL_WeaponEntity_SetModel(entity this, int slot, string name) string t; if ((t = "weapon", gettagindex(this, t)) || (t = "tag_weapon", gettagindex(this, t))) { - if (!this.weaponchild) this.weaponchild = new(weaponchild); + if (!this.weaponchild) + { + this.weaponchild = new(weaponchild); +#ifdef CSQC + this.weaponchild.drawmask = MASK_NORMAL; +#endif + } _setmodel(this.weaponchild, W_Model(strcat("v_", name, ".md3"))); setattachment(this.weaponchild, this, t); } @@ -420,8 +474,11 @@ void CL_WeaponEntity_SetModel(entity this, int slot, string name) setorigin(this, '0 0 0'); this.angles = '0 0 0'; this.frame = 0; +#ifdef SVQC this.viewmodelforclient = NULL; - +#else + this.renderflags &= ~RF_VIEWMODEL; +#endif if (v_shot_idx) // v_ model attached to invisible h_ model { this.movedir = gettaginfo(this.weaponchild, v_shot_idx); @@ -440,24 +497,24 @@ void CL_WeaponEntity_SetModel(entity this, int slot, string name) this.movedir = '0 0 0'; } } - { - int idx = 0; - // v_ model attached to invisible h_ model - if (this.weaponchild - && ((idx = gettagindex(this.weaponchild, "shell")) || (idx = gettagindex(this.weaponchild, "tag_shell")))) - { - this.spawnorigin = gettaginfo(this.weaponchild, idx); - } - else if ((idx = gettagindex(this, "shell")) || (idx = gettagindex(this, "tag_shell"))) - { - this.spawnorigin = gettaginfo(this, idx); - } - else - { - LOG_WARNINGF("weapon model %s does not support the 'shell' tag, will display casings wrong\n", - this.model); - this.spawnorigin = this.movedir; - } + { + int idx = 0; + // v_ model attached to invisible h_ model + if (this.weaponchild + && ((idx = gettagindex(this.weaponchild, "shell")) || (idx = gettagindex(this.weaponchild, "tag_shell")))) + { + this.spawnorigin = gettaginfo(this.weaponchild, idx); + } + else if ((idx = gettagindex(this, "shell")) || (idx = gettagindex(this, "tag_shell"))) + { + this.spawnorigin = gettaginfo(this, idx); + } + else + { + LOG_WARNINGF("weapon model %s does not support the 'shell' tag, will display casings wrong\n", + this.model); + this.spawnorigin = this.movedir; + } } if (v_shot_idx) { @@ -485,21 +542,35 @@ void CL_WeaponEntity_SetModel(entity this, int slot, string name) } } +#ifdef SVQC this.viewmodelforclient = this.owner; +#else + this.renderflags |= RF_VIEWMODEL; +#endif } this.view_ofs = '0 0 0'; if (this.movedir.x >= 0) { +#ifdef SVQC + int algn = this.owner.cvar_cl_gunalign; +#else + int algn = autocvar_cl_gunalign; +#endif vector v = this.movedir; - this.movedir = shotorg_adjust(v, false, false, this.owner.cvar_cl_gunalign); - this.view_ofs = shotorg_adjust(v, false, true, this.owner.cvar_cl_gunalign) - v; + this.movedir = shotorg_adjust(v, false, false, algn); + this.view_ofs = shotorg_adjust(v, false, true, algn) - v; } - this.owner.stat_shotorg = compressShotOrigin(this.movedir); - this.movedir = decompressShotOrigin(this.owner.stat_shotorg); // make them match perfectly + int compressed_shotorg = compressShotOrigin(this.movedir); + // make them match perfectly +#ifdef SVQC + this.movedir = decompressShotOrigin(this.owner.stat_shotorg = compressed_shotorg); +#else + this.movedir = decompressShotOrigin(compressed_shotorg); +#endif - this.spawnorigin += this.view_ofs; // offset the casings origin by the same amount + this.spawnorigin += this.view_ofs; // offset the casings origin by the same amount // check if an instant weapon switch occurred setorigin(this, this.view_ofs); @@ -509,4 +580,34 @@ void CL_WeaponEntity_SetModel(entity this, int slot, string name) } #endif +#ifndef MENUQC + +REGISTER_NET_TEMP(wframe, bool isNew) +#ifdef CSQC +{ + vector a; + a.x = ReadCoord(); + a.y = ReadCoord(); + a.z = ReadCoord(); + bool restartanim = ReadByte(); + setanim(viewmodel, a, restartanim == false, restartanim, restartanim); +} +#endif + +#ifdef SVQC +void wframe_send(entity actor, vector 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, restartanim); +} +#endif + +#endif + #endif diff --git a/qcsrc/common/weapons/all.qh b/qcsrc/common/weapons/all.qh index 2f974a4f47..ecfe58199e 100644 --- a/qcsrc/common/weapons/all.qh +++ b/qcsrc/common/weapons/all.qh @@ -174,8 +174,37 @@ STATIC_INIT(register_weapons_done) weaponorder_byid = strzone(substring(weaponorder_byid, 1, strlen(weaponorder_byid) - 1)); } -#ifdef SVQC -void CL_WeaponEntity_SetModel(entity this, int slot, string name); +#ifndef MENUQC + +.entity weaponentity[MAX_WEAPONSLOTS]; +.entity weaponchild; +.entity exteriorweaponentity; +.vector weaponentity_glowmod; + +//.int weapon; // current weapon +.int switchweapon; // weapon requested to switch to +.int switchingweapon; // weapon currently being switched to (is copied from switchweapon once switch is possible) +.string weaponname; // name of .weapon + +.vector spawnorigin; // for casings + +// weapon animation vectors: +.vector anim_fire1; +.vector anim_fire2; +.vector anim_idle; +.vector anim_reload; + +// static frame globals +.int wframe; + +const float WFRAME_DONTCHANGE = -1; +const float WFRAME_FIRE1 = 0; +const float WFRAME_FIRE2 = 1; +const float WFRAME_IDLE = 2; +const float WFRAME_RELOAD = 3; + +vector shotorg_adjust_values(vector vecs, bool y_is_right, bool visual, int algn); +void CL_WeaponEntity_SetModel(entity this, string name); #endif #endif diff --git a/qcsrc/lib/net.qh b/qcsrc/lib/net.qh index c3043806a5..9d0cb3a5ff 100644 --- a/qcsrc/lib/net.qh +++ b/qcsrc/lib/net.qh @@ -130,7 +130,7 @@ STATIC_INIT(RegisterLinkedEntities_renumber) } #endif -REGISTRY(TempEntities, BIT(0)) +REGISTRY(TempEntities, BITS(3)) REGISTER_REGISTRY(RegisterTempEntities) REGISTRY_SORT(TempEntities, netname, 0) STATIC_INIT(RegisterTempEntities_renumber) diff --git a/qcsrc/server/cl_player.qc b/qcsrc/server/cl_player.qc index 205c2a0358..b8b3618de1 100644 --- a/qcsrc/server/cl_player.qc +++ b/qcsrc/server/cl_player.qc @@ -167,16 +167,6 @@ void player_anim (void) animbits |= ANIMSTATE_DUCK; animdecide_setstate(self, animbits, false); animdecide_setimplicitstate(self, (self.flags & FL_ONGROUND)); - - int slot = 0; // TODO: unhardcode - { - if (self.weaponentity[slot]) - { - updateanim(self.weaponentity[slot]); - if (!self.weaponentity[slot].animstate_override) - setanim(self.weaponentity[slot], self.weaponentity[slot].anim_idle, true, false, false); - } - } } void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force) diff --git a/qcsrc/server/defs.qh b/qcsrc/server/defs.qh index 88b98adac0..45febdbca7 100644 --- a/qcsrc/server/defs.qh +++ b/qcsrc/server/defs.qh @@ -92,12 +92,6 @@ float server_is_dedicated; .float fade_time; .float fade_rate; -// weapon animation vectors: -.vector anim_fire1; -.vector anim_fire2; -.vector anim_idle; -.vector anim_reload; - void() player_setupanimsformodel; void setanim(entity e, vector anim, float looping, float override, float restart); @@ -150,18 +144,6 @@ const float MAX_DAMAGEEXTRARADIUS = 16; .entity item_pickupsound_ent; .entity item_model_ent; -// definitions for weaponsystem -// more WEAPONTODO: move these to their proper files -.entity weaponentity[MAX_WEAPONSLOTS]; -.entity weaponchild; -.entity exteriorweaponentity; -.vector weaponentity_glowmod; - -//.int weapon; // current weapon -.int switchweapon; // weapon requested to switch to -.int switchingweapon; // weapon currently being switched to (is copied from switchweapon once switch is possible) -.string weaponname; // name of .weapon - // WEAPONTODO .float autoswitch; float client_hasweapon(entity cl, float wpn, float andammo, float complain); @@ -215,8 +197,6 @@ float nJoinAllowed(entity ignore); float playerid_last; .float noalign; // if set to 1, the item or spawnpoint won't be dropped to the floor -.vector spawnorigin; - .vector death_origin; .vector killer_origin; diff --git a/qcsrc/server/g_subs.qc b/qcsrc/server/g_subs.qc index 41bac7a43f..f3e8d4b1f8 100644 --- a/qcsrc/server/g_subs.qc +++ b/qcsrc/server/g_subs.qc @@ -11,50 +11,6 @@ spawnfunc(info_null) // if anything breaks, tell the mapper to fix his map! info_null is meant to remove itself immediately. } -void setanim(entity e, vector anim, float looping, float override, float restart) -{ - if (!anim) - return; // no animation was given to us! We can't use this. - - if (anim.x == e.animstate_startframe) - if (anim.y == e.animstate_numframes) - if (anim.z == e.animstate_framerate) - { - if(restart) - { - if(restart > 0) - if(anim.y == 1) // ZYM animation - BITXOR_ASSIGN(e.effects, EF_RESTARTANIM_BIT); - } - else - return; - } - e.animstate_startframe = anim.x; - e.animstate_numframes = anim.y; - e.animstate_framerate = anim.z; - e.animstate_starttime = servertime - 0.1 * serverframetime; // shift it a little bit into the past to prevent float inaccuracy hiccups - e.animstate_endtime = e.animstate_starttime + e.animstate_numframes / e.animstate_framerate; - e.animstate_looping = looping; - e.animstate_override = override; - e.frame = e.animstate_startframe; - e.frame1time = servertime; -} - -void updateanim(entity e) -{ - if (time >= e.animstate_endtime) - { - if (e.animstate_looping) - { - e.animstate_starttime = e.animstate_endtime; - e.animstate_endtime = e.animstate_starttime + e.animstate_numframes / e.animstate_framerate; - } - e.animstate_override = false; - } - e.frame = e.animstate_startframe + bound(0, (time - e.animstate_starttime) * e.animstate_framerate, e.animstate_numframes - 1); - //print(ftos(time), " -> ", ftos(e.frame), "\n"); -} - /* ================== main diff --git a/qcsrc/server/progs.inc b/qcsrc/server/progs.inc index ab94c42bdd..6ff405fabf 100644 --- a/qcsrc/server/progs.inc +++ b/qcsrc/server/progs.inc @@ -58,6 +58,7 @@ #include "weapons/weaponstats.qc" #include "weapons/weaponsystem.qc" +#include "../common/anim.qc" #include "../common/animdecide.qc" #include "../common/campaign_file.qc" #include "../common/campaign_setup.qc" diff --git a/qcsrc/server/weapons/weaponsystem.qc b/qcsrc/server/weapons/weaponsystem.qc index 8c533de169..0e8caae1f4 100644 --- a/qcsrc/server/weapons/weaponsystem.qc +++ b/qcsrc/server/weapons/weaponsystem.qc @@ -14,59 +14,6 @@ #include "../../common/weapons/all.qh" #include "../../lib/csqcmodel/sv_model.qh" -vector shotorg_adjustfromclient(vector vecs, float y_is_right, float algn) -{ - switch (algn) - { - default: case 3: break; // right alignment - case 4: vecs.y = -vecs.y; - break; // left - case 1: case 2: vecs.y = 0; - vecs.z -= 2; - break; // center - } - - return vecs; -} - -vector shotorg_adjust_values(vector vecs, bool y_is_right, bool visual, int algn) -{ - string s; - - if (visual) - { - vecs = shotorg_adjustfromclient(vecs, y_is_right, algn); - } - else if (autocvar_g_shootfromeye) - { - vecs.y = vecs.z = 0; - } - else if (autocvar_g_shootfromcenter) - { - vecs.y = 0; - vecs.z -= 2; - } - else if ((s = autocvar_g_shootfromfixedorigin) != "") - { - vector v = stov(s); - if (y_is_right) v.y = -v.y; - if (v.x != 0) vecs.x = v.x; - vecs.y = v.y; - vecs.z = v.z; - } - else // just do the same as top - { - vecs = shotorg_adjustfromclient(vecs, y_is_right, algn); - } - - return vecs; -} - -vector shotorg_adjust(vector vecs, bool y_is_right, bool visual, int algn) -{ - return shotorg_adjust_values(vecs, y_is_right, visual, algn); -} - .int state; .float weapon_frametime; @@ -107,9 +54,9 @@ vector CL_Weapon_GetShotOrg(int wpn) { entity wi = get_weaponinfo(wpn); entity e = spawn(); - CL_WeaponEntity_SetModel(e, 0, wi.mdl); + CL_WeaponEntity_SetModel(e, wi.mdl); vector ret = e.movedir; - CL_WeaponEntity_SetModel(e, 0, ""); + CL_WeaponEntity_SetModel(e, ""); remove(e); return ret; } @@ -143,7 +90,7 @@ void CL_Weaponentity_Think() this.dmg = this.owner.modelindex; this.deadflag = this.owner.deadflag; - CL_WeaponEntity_SetModel(this, slot, this.owner.weaponname); + CL_WeaponEntity_SetModel(this, this.owner.weaponname); } int tb = (this.effects & (EF_TELEPORT_BIT | EF_RESTARTANIM_BIT)); @@ -155,7 +102,9 @@ void CL_Weaponentity_Think() | EF_TELEPORT_BIT | EF_RESTARTANIM_BIT ) - | tb; + | tb + // TODO: don't render this entity at all + | EF_NODRAW; if (this.owner.alpha == default_player_alpha) this.alpha = default_weapon_alpha; else if (this.owner.alpha != 0) this.alpha = this.owner.alpha; @@ -393,6 +342,8 @@ bool weapon_prepareattack(Weapon thiswep, entity actor, int slot, bool secondary return false; } +void wframe_send(entity actor, vector a, bool restartanim); + void weapon_thinkf(entity actor, int slot, float fr, float t, void(Weapon thiswep, entity actor, int slot, int fire) func) { @@ -425,7 +376,7 @@ void weapon_thinkf(entity actor, int slot, float fr, float t, else // if (fr == WFRAME_RELOAD) a = actor.weaponentity[slot].anim_reload; a.z *= g_weaponratefactor; - setanim(actor.weaponentity[slot], a, restartanim == false, restartanim, restartanim); + wframe_send(actor, a, restartanim); } v_forward = of; diff --git a/qcsrc/server/weapons/weaponsystem.qh b/qcsrc/server/weapons/weaponsystem.qh index c5ee7abb6d..7c7459df2c 100644 --- a/qcsrc/server/weapons/weaponsystem.qh +++ b/qcsrc/server/weapons/weaponsystem.qh @@ -1,23 +1,11 @@ #ifndef WEAPONSYSTEM_H #define WEAPONSYSTEM_H -.float wframe; float internalteam; float weaponswapping; entity weapon_dropevent_item; -// VorteX: static frame globals -const float WFRAME_DONTCHANGE = -1; -const float WFRAME_FIRE1 = 0; -const float WFRAME_FIRE2 = 1; -const float WFRAME_IDLE = 2; -const float WFRAME_RELOAD = 3; - -vector shotorg_adjust(vector vecs, bool y_is_right, bool visual, int algn); - -vector shotorg_adjust_values(vector vecs, bool y_is_right, bool visual, int algn); - void CL_SpawnWeaponentity(entity e, int slot); vector CL_Weapon_GetShotOrg(float wpn); -- 2.39.2