#include "all.qh"
#if defined(CSQC)
- #include "../../dpdefs/csprogsdefs.qh"
#include "../../client/defs.qh"
#include "../constants.qh"
#include "../stats.qh"
- #include "../../warpzonelib/anglestransform.qh"
- #include "../../warpzonelib/mathlib.qh"
- #include "../../warpzonelib/common.qh"
- #include "../../warpzonelib/client.qh"
+ #include "../../lib/warpzone/anglestransform.qh"
+ #include "../../lib/warpzone/common.qh"
+ #include "../../lib/warpzone/client.qh"
#include "../util.qh"
- #include "../buffs.qh"
#include "../../client/autocvars.qh"
- #include "../deathtypes.qh"
- #include "../../csqcmodellib/interpolate.qh"
+ #include "../deathtypes/all.qh"
+ #include "../../lib/csqcmodel/interpolate.qh"
#include "../movetypes/movetypes.qh"
#include "../../client/main.qh"
- #include "../../csqcmodellib/cl_model.qh"
+ #include "../../lib/csqcmodel/cl_model.qh"
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
- #include "../../dpdefs/dpextensions.qh"
- #include "../../warpzonelib/anglestransform.qh"
- #include "../../warpzonelib/mathlib.qh"
- #include "../../warpzonelib/common.qh"
- #include "../../warpzonelib/util_server.qh"
- #include "../../warpzonelib/server.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.qh"
#include "../monsters/all.qh"
#include "config.qh"
#include "../../server/weapons/csqcprojectile.qh"
#include "../../server/constants.qh"
#include "../../server/defs.qh"
#include "../notifications.qh"
- #include "../deathtypes.qh"
- #include "../../server/mutators/mutators_include.qh"
+ #include "../deathtypes/all.qh"
+ #include "../../server/mutators/all.qh"
#include "../mapinfo.qh"
#include "../../server/command/common.qh"
- #include "../../csqcmodellib/sv_model.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"
#undef IMPLEMENTATION
// WEAPON PLUGIN SYSTEM
-entity weapon_info[WEP_MAXCOUNT];
-entity dummy_weapon_info;
-#if WEP_MAXCOUNT > 72
-# error Kein Weltraum links auf dem Gerät
-#endif
-
-WepSet WepSet_FromWeapon(int a) {
+WepSet _WepSet_FromWeapon(int a)
+{
a -= WEP_FIRST;
-#if WEP_MAXCOUNT > 24
- if(a >= 24) {
- a -= 24;
-#if WEP_MAXCOUNT > 48
- if(a >= 24) {
+ if (Weapons_MAX > 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);
}
-#endif
- return '0 1 0' * power2of(a);
- }
-#endif
return '1 0 0' * power2of(a);
}
#ifdef SVQC
-void WepSet_AddStat()
-{
- addstat(STAT_WEAPONS, AS_INT, weapons_x);
-#if WEP_MAXCOUNT > 24
- addstat(STAT_WEAPONS2, AS_INT, weapons_y);
-#if WEP_MAXCOUNT > 48
- addstat(STAT_WEAPONS3, AS_INT, weapons_z);
-#endif
-#endif
-}
-void WepSet_AddStat_InMap()
-{
- addstat(STAT_WEAPONSINMAP, AS_INT, weaponsinmap_x);
-#if WEP_MAXCOUNT > 24
- addstat(STAT_WEAPONSINMAP2, AS_INT, weaponsinmap_y);
-#if WEP_MAXCOUNT > 48
- addstat(STAT_WEAPONSINMAP3, AS_INT, weaponsinmap_z);
-#endif
-#endif
-}
-void WriteWepSet(float dst, WepSet w)
-{
-#if WEP_MAXCOUNT > 48
- WriteInt72_t(dst, w);
-#elif WEP_MAXCOUNT > 24
- WriteInt48_t(dst, w);
-#else
- WriteInt24_t(dst, w.x);
-#endif
-}
+ 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 WEP_MAXCOUNT > 24
- w.y = getstati(STAT_WEAPONS2);
-#if WEP_MAXCOUNT > 48
- w.z = getstati(STAT_WEAPONS3);
-#endif
-#endif
- return w;
-}
-WepSet WepSet_GetFromStat_InMap()
-{
- WepSet w = '0 0 0';
- w_x = getstati(STAT_WEAPONSINMAP);
-#if WEP_MAXCOUNT > 24
- w_y = getstati(STAT_WEAPONSINMAP2);
-#if WEP_MAXCOUNT > 48
- w_z = getstati(STAT_WEAPONSINMAP3);
-#endif
-#endif
- return w;
-}
-WepSet ReadWepSet()
-{
-#if WEP_MAXCOUNT > 48
- return ReadInt72_t();
-#elif WEP_MAXCOUNT > 24
- return ReadInt48_t();
-#else
- return ReadInt24_t() * '1 0 0';
-#endif
-}
+ WepSet WepSet_GetFromStat()
+ {
+ return STAT(WEAPONS);
+ }
+ WepSet WepSet_GetFromStat_InMap()
+ {
+ return STAT(WEAPONSINMAP);
+ }
+ WepSet ReadWepSet()
+ {
+ if (Weapons_MAX > 48) return ReadInt72_t();
+ if (Weapons_MAX > 24) return ReadInt48_t();
+ return ReadInt24_t() * '1 0 0';
+ }
#endif
-void register_weapon(
- int id,
- WepSet bit,
- bool(int) func,
- .int ammotype,
- int i,
- int weapontype,
- float pickupbasevalue,
- vector clr,
- string modelname,
- string simplemdl,
- string crosshair,
- string wepimg,
- string refname,
- string wepname)
-{
- entity e;
- weapon_info[id - 1] = e = spawn();
- e.classname = "weapon_info";
- e.weapon = id;
- e.weapons = bit;
- e.weapon_func = func;
- e.ammo_field = ammotype;
- e.impulse = i;
- e.spawnflags = weapontype;
- e.bot_pickupbasevalue = pickupbasevalue;
- e.wpcolor = clr;
- e.wpmodel = strzone(strcat("wpn-", ftos(id)));
- e.mdl = modelname;
- e.model = strzone(strcat("models/weapons/g_", modelname, ".md3"));
- e.w_simplemdl = strzone(simplemdl); // simpleitems weapon model/image
- e.w_crosshair = strzone(car(crosshair));
- string s = cdr(crosshair);
- e.w_crosshair_size = ((s != "") ? stof(s) : 1); // so that we can scale the crosshair from code (for compat)
- e.model2 = strzone(wepimg);
- e.netname = refname;
- e.message = wepname;
-
- #ifdef CSQC
- func(WR_INIT);
- #endif
-}
-bool w_null(int dummy)
-{
- return 0;
-}
-void register_weapons_done()
-{
- dummy_weapon_info = spawn();
- dummy_weapon_info.classname = "weapon_info";
- dummy_weapon_info.weapon = 0; // you can recognize dummies by this
- dummy_weapon_info.weapons = '0 0 0';
- dummy_weapon_info.netname = "";
- dummy_weapon_info.message = "AOL CD Thrower";
- dummy_weapon_info.weapon_func = w_null;
- dummy_weapon_info.wpmodel = "";
- dummy_weapon_info.mdl = "";
- dummy_weapon_info.model = "";
- dummy_weapon_info.spawnflags = 0;
- dummy_weapon_info.impulse = -1;
- dummy_weapon_info.bot_pickupbasevalue = 0;
- dummy_weapon_info.ammo_field = ammo_none;
-
- dummy_weapon_info.w_crosshair = "gfx/crosshair1";
- dummy_weapon_info.w_crosshair_size = 1;
- dummy_weapon_info.model2 = "";
-
- int i;
- weaponorder_byid = "";
- for(i = WEP_MAXCOUNT; i >= 1; --i)
- if(weapon_info[i-1])
- weaponorder_byid = strcat(weaponorder_byid, " ", ftos(i));
- weaponorder_byid = strzone(substring(weaponorder_byid, 1, strlen(weaponorder_byid) - 1));
-}
-entity get_weaponinfo(int id)
-{
- entity w;
- if(id < WEP_FIRST || id > WEP_LAST)
- return dummy_weapon_info;
- w = weapon_info[id - 1];
- if(w)
- return w;
- return dummy_weapon_info;
-}
string W_FixWeaponOrder(string order, float complete)
{
- return fixPriorityList(order, WEP_FIRST, WEP_LAST, 230 - WEP_FIRST, complete);
+ return fixPriorityList(order, WEP_FIRST, WEP_LAST, WEP_IMPULSE_BEGIN - WEP_FIRST, 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 != dummy_weapon_info)
- 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)
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)
return mapPriorityList(order, W_NumberWeaponOrder_MapFunc);
}
-float W_FixWeaponOrder_BuildImpulseList_buf[WEP_MAXCOUNT];
+float W_FixWeaponOrder_BuildImpulseList_buf[Weapons_MAX];
string W_FixWeaponOrder_BuildImpulseList_order;
void W_FixWeaponOrder_BuildImpulseList_swap(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);
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);
}
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);
}
string GetAmmoPicture(.int ammotype)
{
- switch(ammotype)
+ switch (ammotype)
{
- case ammo_shells: return "ammo_shells";
- case ammo_nails: return "ammo_bullets";
- case ammo_rockets: return "ammo_rockets";
- case ammo_cells: return "ammo_cells";
- case ammo_plasma: return "ammo_cells";
- case ammo_fuel: return "ammo_fuel";
- default: return ""; // wtf, no ammo type?
+ case ammo_shells: return ITEM_Shells.m_icon;
+ case ammo_nails: return ITEM_Bullets.m_icon;
+ case ammo_rockets: return ITEM_Rockets.m_icon;
+ 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?
}
}
#ifdef CSQC
-.int GetAmmoFieldFromNum(int i)
+ .int GetAmmoFieldFromNum(int i)
+ {
+ 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)
+ {
+ 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.m_id;
+ case ammo_fuel: return STAT_FUEL.m_id;
+ default: return -1;
+ }
+ }
+#endif
+
+string W_Sound(string w_snd)
+{
+ string output = strcat("weapons/", w_snd);
+#ifdef SVQC
+ MUTATOR_CALLHOOK(WeaponSound, w_snd, output);
+ return weapon_sound_output;
+#else
+ return output;
+#endif
+}
+
+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;
+#else
+ return output;
+#endif
+}
+
+#ifndef MENUQC
+vector shotorg_adjustfromclient(vector vecs, float y_is_right, float algn)
{
- switch(i)
+ switch (algn)
{
- 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;
+ 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;
}
-int GetAmmoStat(.int ammotype)
+vector shotorg_adjust_values(vector vecs, bool y_is_right, bool visual, int algn)
{
- switch(ammotype)
+#ifdef SVQC
+ string s;
+#endif
+ if (visual)
{
- 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;
+ 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;
+ this.weaponchild.renderflags |= RF_VIEWMODEL;
#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
+ 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);
+}
+#endif
+
+#ifndef MENUQC
+
+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();
+ anim_set(viewmodel, a, !restartanim, 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