Viewmodels: CSQC rendering
authorTimePath <andrew.hardaker1995@gmail.com>
Sat, 31 Oct 2015 09:06:06 +0000 (20:06 +1100)
committerTimePath <andrew.hardaker1995@gmail.com>
Sat, 31 Oct 2015 09:06:06 +0000 (20:06 +1100)
13 files changed:
qcsrc/client/progs.inc
qcsrc/client/view.qc
qcsrc/common/anim.qc [new file with mode: 0644]
qcsrc/common/anim.qh [new file with mode: 0644]
qcsrc/common/weapons/all.qc
qcsrc/common/weapons/all.qh
qcsrc/lib/net.qh
qcsrc/server/cl_player.qc
qcsrc/server/defs.qh
qcsrc/server/g_subs.qc
qcsrc/server/progs.inc
qcsrc/server/weapons/weaponsystem.qc
qcsrc/server/weapons/weaponsystem.qh

index 5c110e2..2b9c22a 100644 (file)
@@ -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"
index c714437..54fefa6 100644 (file)
@@ -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"
 #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 (file)
index 0000000..c2781c6
--- /dev/null
@@ -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 (file)
index 0000000..c1dee15
--- /dev/null
@@ -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
index f97ed6d..cb397e8 100644 (file)
        #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"
 
 // 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
index 2f974a4..ecfe581 100644 (file)
@@ -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
index c304380..9d0cb3a 100644 (file)
@@ -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)
index 205c2a0..b8b3618 100644 (file)
@@ -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)
index 88b98ad..45febdb 100644 (file)
@@ -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;
 
index 41bac7a..f3e8d4b 100644 (file)
@@ -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
index ab94c42..6ff405f 100644 (file)
@@ -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"
index 8c533de..0e8caae 100644 (file)
 #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;
index c5ee7ab..7c7459d 100644 (file)
@@ -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);