Merge branch 'master' into TimePath/csqc_viewmodels
authorTimePath <andrew.hardaker1995@gmail.com>
Fri, 6 Nov 2015 08:55:40 +0000 (19:55 +1100)
committerTimePath <andrew.hardaker1995@gmail.com>
Fri, 6 Nov 2015 08:59:26 +0000 (19:59 +1100)
# Conflicts:
# qcsrc/common/weapons/all.qc
# qcsrc/common/weapons/weapon/rifle.qc
# qcsrc/server/weapons/weaponsystem.qc

15 files changed:
1  2 
qcsrc/client/progs.inc
qcsrc/client/view.qc
qcsrc/client/weapons/projectile.qc
qcsrc/common/weapons/all.qc
qcsrc/common/weapons/all.qh
qcsrc/common/weapons/weapon/rifle.qc
qcsrc/lib/_all.inc
qcsrc/server/cl_client.qc
qcsrc/server/cl_player.qc
qcsrc/server/defs.qh
qcsrc/server/g_subs.qc
qcsrc/server/g_subs.qh
qcsrc/server/g_world.qc
qcsrc/server/progs.inc
qcsrc/server/weapons/weaponsystem.qc

Simple merge
@@@ -10,8 -9,8 +9,9 @@@
  
  #include "mutators/events.qh"
  
 +#include "../common/anim.qh"
  #include "../common/constants.qh"
+ #include "../common/debug.qh"
  #include "../common/mapinfo.qh"
  #include "../common/gamemodes/all.qh"
  #include "../common/nades/all.qh"
Simple merge
@@@ -277,23 -291,12 +277,12 @@@ string GetAmmoPicture(.int ammotype
  
  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; }
-       string output;
-       do
-       {
-               extensions(tryext);
- #undef tryext
- #undef extensions
-               output = strcat("weapons/", w_snd);
-       }
-       while (0);
+       string output = strcat("weapons/", w_snd);
  #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
  }
  
@@@ -301,341 -304,11 +290,345 @@@ 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;
 +#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:
 + *
 + * 1. simple animated model, muzzle flash handling on h_ model:
 + *    h_tuba.dpm, h_tuba.dpm.framegroups - invisible model controlling the animation
 + *      tags:
 + *        shot = muzzle end (shot origin, also used for muzzle flashes)
 + *        shell = casings ejection point (must be on the right hand side of the gun)
 + *        weapon = attachment for v_tuba.md3
 + *    v_tuba.md3 - first and third person model
 + *    g_tuba.md3 - pickup model
 + *
 + * 2. simple animated model, muzzle flash handling on v_ model:
 + *    h_tuba.dpm, h_tuba.dpm.framegroups - invisible model controlling the animation
 + *      tags:
 + *        weapon = attachment for v_tuba.md3
 + *    v_tuba.md3 - first and third person model
 + *      tags:
 + *        shot = muzzle end (shot origin, also used for muzzle flashes)
 + *        shell = casings ejection point (must be on the right hand side of the gun)
 + *    g_tuba.md3 - pickup model
 + *
 + * 3. fully animated model, muzzle flash handling on h_ model:
 + *    h_tuba.dpm, h_tuba.dpm.framegroups - animated first person model
 + *      tags:
 + *        shot = muzzle end (shot origin, also used for muzzle flashes)
 + *        shell = casings ejection point (must be on the right hand side of the gun)
 + *        handle = corresponding to the origin of v_tuba.md3 (used for muzzle flashes)
 + *    v_tuba.md3 - third person model
 + *    g_tuba.md3 - pickup model
 + *
 + * 4. fully animated model, muzzle flash handling on v_ model:
 + *    h_tuba.dpm, h_tuba.dpm.framegroups - animated first person model
 + *      tags:
 + *        shot = muzzle end (shot origin)
 + *        shell = casings ejection point (must be on the right hand side of the gun)
 + *    v_tuba.md3 - third person model
 + *      tags:
 + *        shot = muzzle end (for muzzle flashes)
 + *    g_tuba.md3 - pickup model
 + *
 + * writes:
 + *   this.origin, this.angles
 + *   this.weaponchild
 + *   this.movedir, this.view_ofs
 + *   attachment stuff
 + *   anim stuff
 + * to free:
 + *   call again with ""
 + *   remove the ent
 + */
 +void CL_WeaponEntity_SetModel(entity this, string name)
 +{
 +      if (name == "")
 +      {
 +              this.model = "";
 +              if (this.weaponchild) remove(this.weaponchild);
 +              this.weaponchild = NULL;
 +              this.movedir = '0 0 0';
 +              this.spawnorigin = '0 0 0';
 +              this.oldorigin = '0 0 0';
 +              this.anim_fire1  = '0 1 0.01';
 +              this.anim_fire2  = '0 1 0.01';
 +              this.anim_idle   = '0 1 0.01';
 +              this.anim_reload = '0 1 0.01';
 +      }
 +      else
 +      {
 +              // 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
 +              (v_shot_idx = gettagindex(this, "shot")) || (v_shot_idx = gettagindex(this, "tag_shot"));
 +
 +              _setmodel(this, W_Model(strcat("h_", name, ".iqm")));
 +              // 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');
 +              this.anim_idle   = animfixfps(this, '2 1 0.01', '0 0 0');
 +              this.anim_reload = animfixfps(this, '3 1 0.01', '0 0 0');
 +
 +              // if we have a "weapon" tag, let's attach the v_ model to it ("invisible hand" style model)
 +              // if we don't, this is a "real" animated model
 +              string t;
 +              if ((t = "weapon", gettagindex(this, t)) || (t = "tag_weapon", gettagindex(this, t)))
 +              {
 +                      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);
 +              }
 +              else
 +              {
 +                      if (this.weaponchild) remove(this.weaponchild);
 +                      this.weaponchild = NULL;
 +              }
 +
 +              setorigin(this, '0 0 0');
 +              this.angles = '0 0 0';
 +              this.frame = 0;
 +#ifdef SVQC
 +              this.viewmodelforclient = NULL;
  #else
 -      return output;
 +              this.renderflags &= ~RF_VIEWMODEL;
  #endif
 +              if (v_shot_idx)  // v_ model attached to invisible h_ model
 +              {
 +                      this.movedir = gettaginfo(this.weaponchild, v_shot_idx);
 +              }
 +              else
 +              {
 +                      int idx;
 +                      if ((idx = gettagindex(this, "shot")) || (idx = gettagindex(this, "tag_shot")))
 +                      {
 +                              this.movedir = gettaginfo(this, idx);
 +                      }
 +                      else
 +                      {
 +                              LOG_WARNINGF("weapon model %s does not support the 'shot' tag, will display shots TOTALLY wrong\n",
 +                                      this.model);
 +                              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;
 +                      }
 +              }
 +              if (v_shot_idx)
 +              {
 +                      this.oldorigin = '0 0 0';  // use regular attachment
 +              }
 +              else
 +              {
 +                      int idx;
 +                      if (this.weaponchild)
 +                              (idx = gettagindex(this, "weapon")) || (idx = gettagindex(this, "tag_weapon"));
 +                      else
 +                              (idx = gettagindex(this, "handle")) || (idx = gettagindex(this, "tag_handle"));
 +                      if (idx)
 +                      {
 +                              this.oldorigin = this.movedir - gettaginfo(this, idx);
 +                      }
 +                      else
 +                      {
 +                              LOG_WARNINGF(
 +                                      "weapon model %s does not support the 'handle' tag "
 +                                      "and neither does the v_ model support the 'shot' tag, "
 +                                      "will display muzzle flashes TOTALLY wrong\n",
 +                                      this.model);
 +                              this.oldorigin = '0 0 0';  // there is no way to recover from this
 +                      }
 +              }
 +
 +#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, algn);
 +              this.view_ofs = shotorg_adjust(v, false, true, algn) - v;
 +      }
 +      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
 +
 +      // check if an instant weapon switch occurred
 +      setorigin(this, this.view_ofs);
 +      // reset animstate now
 +      this.wframe = WFRAME_IDLE;
 +      setanim(this, this.anim_idle, true, false, true);
  }
- REGISTER_NET_TEMP(wframe, bool isNew)
 +#endif
 +
 +#ifndef MENUQC
 +
- REGISTER_NET_TEMP(wglow, bool isNew)
++REGISTER_NET_TEMP(wframe)
 +#ifdef CSQC
++NET_HANDLE(wframe, bool isNew)
 +{
 +      vector a;
 +      a.x = ReadCoord();
 +    a.y = ReadCoord();
 +    a.z = ReadCoord();
 +      bool restartanim = ReadByte();
 +      setanim(viewmodel, a, restartanim == false, restartanim, restartanim);
 +      viewmodel.state = ReadByte();
 +      viewmodel.alpha = ReadByte() / 255;
++      return true;
 +}
 +#endif
 +
 +#ifdef SVQC
 +void wframe_send(entity actor, entity weaponentity, 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);
 +      WriteByte(channel, weaponentity.state);
 +      WriteByte(channel, weaponentity.alpha * 255);
 +}
 +#endif
 +
++REGISTER_NET_TEMP(wglow)
 +#ifdef CSQC
++NET_HANDLE(wglow, bool isNew)
 +{
 +      vector g = '0 0 0';
 +      g.x = ReadCoord();
 +      g.y = ReadCoord();
 +      g.z = ReadCoord();
 +      viewmodel.glowmod = g;
++      return true;
 +}
 +#endif
 +
 +#ifdef SVQC
 +void wglow_send(entity actor, vector g)
 +{
 +      if (!IS_REAL_CLIENT(actor)) return;
 +      int channel = MSG_ONE;
 +      msg_entity = actor;
 +      WriteHeader(channel, wglow);
 +      WriteCoord(channel, g.x);
 +      WriteCoord(channel, g.y);
 +      WriteCoord(channel, g.z);
 +}
 +#endif
 +
 +#endif
  
  #endif
Simple merge
@@@ -86,8 -86,8 +86,8 @@@ void W_Rifle_Attack2(
        W_Rifle_FireBullet(WEP_RIFLE, WEP_CVAR_SEC(rifle, spread), WEP_CVAR_SEC(rifle, damage), WEP_CVAR_SEC(rifle, force), WEP_CVAR_SEC(rifle, solidpenetration), WEP_CVAR_SEC(rifle, ammo), WEP_RIFLE.m_id | HITTYPE_SECONDARY, WEP_CVAR_SEC(rifle, tracer), WEP_CVAR_SEC(rifle, shots), SND(CAMPINGRIFLE_FIRE2));
  }
  
- .void(void) rifle_bullethail_attackfunc;
+ .void() rifle_bullethail_attackfunc;
 -.float rifle_bullethail_frame;
 +.WFRAME rifle_bullethail_frame;
  .float rifle_bullethail_animtime;
  .float rifle_bullethail_refire;
  void W_Rifle_BulletHail_Continue(Weapon thiswep, entity actor, .entity weaponentity, int fire)
        }
  }
  
- void W_Rifle_BulletHail(.entity weaponentity, float mode, void(void) AttackFunc, WFRAME fr, float animtime, float refire)
 -void W_Rifle_BulletHail(.entity weaponentity, float mode, void() AttackFunc, float fr, float animtime, float refire)
++void W_Rifle_BulletHail(.entity weaponentity, float mode, void() AttackFunc, WFRAME fr, float animtime, float refire)
  {SELFPARAM();
        // if we get here, we have at least one bullet to fire
        AttackFunc();
Simple merge
@@@ -2138,35 -2143,7 +2144,9 @@@ void PlayerUseKey(
        MUTATOR_CALLHOOK(PlayerUseKey);
  }
  
- float isInvisibleString(string s)
- {
-       float i, n, c;
-       s = strdecolorize(s);
-       for((i = 0), (n = strlen(s)); i < n; ++i)
-       {
-               c = str2chr(s, i);
-               switch(c)
-               {
-                       case 0:
-                       case 32: // space
-                               break;
-                       case 192: // charmap space
-                               if (!autocvar_utf8_enable)
-                                       break;
-                               return false;
-                       case 160: // space in unicode fonts
-                       case 0xE000 + 192: // utf8 charmap space
-                               if (autocvar_utf8_enable)
-                                       break;
-                       default:
-                               return false;
-               }
-       }
-       return true;
- }
  
 +void wglow_send(entity actor, vector g);
 +
  /*
  =============
  PlayerPreThink
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -63,11 -327,10 +65,11 @@@ void CL_Weaponentity_Think(
        SELFPARAM();
        this.nextthink = time;
        if (intermission_running) this.frame = this.anim_idle.x;
-       .entity weaponentity = weaponentities[0];  // TODO: unhardcode
+       .entity weaponentity = this.weaponentity_fld;
        if (this.owner.(weaponentity) != this)
        {
 -              if (this.(weaponentity)) remove(this.(weaponentity));
 +              // owner has new gun; remove self
 +              if (this.weaponchild) remove(this.weaponchild);
                remove(this);
                return;
        }
@@@ -150,24 -443,31 +152,27 @@@ void CL_ExteriorWeaponentity_Think(
  }
  
  // spawning weaponentity for client
 -void CL_SpawnWeaponentity(entity e, .entity weaponentity)
 +void CL_SpawnWeaponentity(entity actor, .entity weaponentity)
  {
 -      entity view = e.(weaponentity) = new(weaponentity);
 +      entity view = actor.(weaponentity) = new(weaponentity);
+       make_pure(view);
        view.solid = SOLID_NOT;
 -      view.owner = e;
 +      view.owner = actor;
        setmodel(view, MDL_Null);  // precision set when changed
        setorigin(view, '0 0 0');
 -      view.angles = '0 0 0';
 -      view.viewmodelforclient = e;
 -      view.flags = 0;
+       view.weaponentity_fld = weaponentity;
        view.think = CL_Weaponentity_Think;
 -      view.customizeentityforclient = CL_Weaponentity_CustomizeEntityForClient;
        view.nextthink = time;
 +      view.viewmodelforclient = actor;
 +      view.customizeentityforclient = CL_Weaponentity_CustomizeEntityForClient;
  
        if (weaponentity == weaponentities[0])
        {
 -              entity exterior = e.exteriorweaponentity = new(exteriorweaponentity);
 +              entity exterior = actor.exteriorweaponentity = new(exteriorweaponentity);
+               make_pure(exterior);
                exterior.solid = SOLID_NOT;
 -              exterior.exteriorweaponentity = exterior;
 -              exterior.owner = e;
 +              exterior.owner = actor;
                setorigin(exterior, '0 0 0');
 -              exterior.angles = '0 0 0';
                exterior.think = CL_ExteriorWeaponentity_Think;
                exterior.nextthink = time;
  
@@@ -354,20 -654,20 +363,21 @@@ void weapon_thinkf(entity actor, .entit
        t *= W_WeaponRateFactor();
  
        // VorteX: haste can be added here
-       if (actor.weapon_think == w_ready)
+       if (this.weapon_think == w_ready)
        {
-               actor.weapon_nextthink = time;
+               this.weapon_nextthink = time;
                // dprint("started firing at ", ftos(time), "\n");
        }
-       if (actor.weapon_nextthink < time - actor.weapon_frametime * 1.5
-           || actor.weapon_nextthink > time + actor.weapon_frametime * 1.5)
+       if (this.weapon_nextthink < time - actor.weapon_frametime * 1.5
+           || this.weapon_nextthink > time + actor.weapon_frametime * 1.5)
        {
-               actor.weapon_nextthink = time;
+               this.weapon_nextthink = time;
                // dprint("reset weapon animation timer at ", ftos(time), "\n");
        }
-       actor.weapon_nextthink += t;
-       actor.weapon_think = func;
-       // dprint("next ", ftos(actor.weapon_nextthink), "\n");
 -      this.weapon_nextthink = this.weapon_nextthink + t;
++      this.weapon_nextthink += t;
++      if (weaponentity == weaponentities[0]) actor.weapon_nextthink = this.weapon_nextthink;
+       this.weapon_think = func;
+       // dprint("next ", ftos(this.weapon_nextthink), "\n");
  
        if ((fr == WFRAME_FIRE1 || fr == WFRAME_FIRE2) && t)
        {