-// switch between weapons
-void W_SwitchWeapon(float imp)
-{
- if (self.switchweapon != imp)
- {
- if (client_hasweapon(self, imp, TRUE, TRUE))
- W_SwitchWeapon_Force(self, imp);
- else
- self.selectweapon = imp; // update selectweapon ANYWAY
- }
- else
- {
- WEP_ACTION(self.weapon, WR_RELOAD);
- }
-}
-
-.float weaponcomplainindex;
-float W_GetCycleWeapon(entity pl, string weaponorder, float dir, float imp, float complain, float skipmissing)
-{
- // We cannot tokenize in this function, as GiveItems calls this
- // function. Thus we must use car/cdr.
- float weaponwant, first_valid, prev_valid, switchtonext, switchtolast, c;
- string rest;
- switchtonext = switchtolast = 0;
- first_valid = prev_valid = 0;
- float weaponcur;
-
- if(skipmissing || pl.selectweapon == 0)
- weaponcur = pl.switchweapon;
- else
- weaponcur = pl.selectweapon;
-
- if(dir == 0)
- switchtonext = 1;
-
- c = 0;
-
- rest = weaponorder;
- while(rest != "")
- {
- weaponwant = stof(car(rest)); rest = cdr(rest);
- if(imp >= 0)
- if((get_weaponinfo(weaponwant)).impulse != imp)
- continue;
-
- ++c;
-
- if(!skipmissing || client_hasweapon(pl, weaponwant, TRUE, FALSE))
- {
- if(switchtonext)
- return weaponwant;
- if(!first_valid)
- first_valid = weaponwant;
- if(weaponwant == weaponcur)
- {
- if(dir >= 0)
- switchtonext = 1;
- else if(prev_valid)
- return prev_valid;
- else
- switchtolast = 1;
- }
- prev_valid = weaponwant;
- }
- }
- if(first_valid)
- {
- if(switchtolast)
- return prev_valid;
- else
- return first_valid;
- }
- // complain (but only for one weapon on the button that has been pressed)
- if(complain)
- {
- self.weaponcomplainindex += 1;
- c = mod(self.weaponcomplainindex, c) + 1;
- rest = weaponorder;
- while(rest != "")
- {
- weaponwant = stof(car(rest)); rest = cdr(rest);
- if(imp >= 0)
- if((get_weaponinfo(weaponwant)).impulse != imp)
- continue;
-
- --c;
- if(c == 0)
- {
- client_hasweapon(pl, weaponwant, TRUE, TRUE);
- break;
- }
- }
- }
- return 0;
-}
-
-void W_CycleWeapon(string weaponorder, float dir)
-{
- float w;
- w = W_GetCycleWeapon(self, weaponorder, dir, -1, 1, TRUE);
- if(w > 0)
- W_SwitchWeapon(w);
-}
-
-void W_NextWeaponOnImpulse(float imp)
-{
- float w;
- w = W_GetCycleWeapon(self, self.cvar_cl_weaponpriority, +1, imp, 1, (self.cvar_cl_weaponimpulsemode == 0));
- if(w > 0)
- W_SwitchWeapon(w);
-}
-
-// next weapon
-void W_NextWeapon(float list)
-{
- if(list == 0)
- W_CycleWeapon(weaponorder_byid, -1);
- else if(list == 1)
- W_CycleWeapon(self.weaponorder_byimpulse, -1);
- else if(list == 2)
- W_CycleWeapon(self.cvar_cl_weaponpriority, -1);
-}
-
-// prev weapon
-void W_PreviousWeapon(float list)
-{
- if(list == 0)
- W_CycleWeapon(weaponorder_byid, +1);
- else if(list == 1)
- W_CycleWeapon(self.weaponorder_byimpulse, +1);
- else if(list == 2)
- W_CycleWeapon(self.cvar_cl_weaponpriority, +1);
-}
-
-// previously used if exists and has ammo, (second) best otherwise
-void W_LastWeapon()
-{
- if(client_hasweapon(self, self.cnt, TRUE, FALSE))
- W_SwitchWeapon(self.cnt);
- else
- W_SwitchToOtherWeapon(self);
-}
-
-float w_getbestweapon(entity e)
-{
- return W_GetCycleWeapon(e, e.cvar_cl_weaponpriority, 0, -1, FALSE, TRUE);
-}
-
-// generic weapons table
-// TODO should they be macros instead?
-//float WEP_ACTION(float wpn, float wrequest)
-//{
-// return (get_weaponinfo(wpn)).weapon_func(wrequest);
-//}
-
-.float savenextthink;
-void thrown_wep_think()
-{
- self.owner = world;
- float timeleft = self.savenextthink - time;
- if(timeleft > 1)
- SUB_SetFade(self, self.savenextthink - 1, 1);
- else if(timeleft > 0)
- SUB_SetFade(self, time, timeleft);
- else
- SUB_VanishOrRemove(self);
-}
-
-// returns amount of ammo used as string, or -1 for failure, or 0 for no ammo count
-string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vector velo)
-{
- entity oldself, wep;
- float wa, thisammo, i, j;
- string s;
- var .float ammofield;
-
- wep = spawn();
-
- setorigin(wep, org);
- wep.classname = "droppedweapon";
- wep.velocity = velo;
- wep.owner = wep.enemy = own;
- wep.flags |= FL_TOSSED;
- wep.colormap = own.colormap;
-
- if(WEPSET_CONTAINS_AW(WEPBIT_SUPERWEAPONS, wpn))
- {
- if(own.items & IT_UNLIMITED_SUPERWEAPONS)
- {
- wep.superweapons_finished = time + autocvar_g_balance_superweapons_time;
- }
- else
- {
- float superweapons = 1;
- for(i = WEP_FIRST; i <= WEP_LAST; ++i)
- if(WEPSET_CONTAINS_AW(WEPBIT_SUPERWEAPONS, i))
- if(WEPSET_CONTAINS_EW(own, i))
- ++superweapons;
- if(superweapons <= 1)
- {
- wep.superweapons_finished = own.superweapons_finished;
- own.superweapons_finished = 0;
- }
- else
- {
- float timeleft = own.superweapons_finished - time;
- float weptimeleft = timeleft / superweapons;
- wep.superweapons_finished = time + weptimeleft;
- own.superweapons_finished -= weptimeleft;
- }
- }
- }
-
- wa = W_AmmoItemCode(wpn);
- if(wa == 0)
- {
- oldself = self;
- self = wep;
- weapon_defaultspawnfunc(wpn);
- self = oldself;
- if(startitem_failed)
- return string_null;
- wep.glowmod = own.weaponentity_glowmod;
- wep.think = thrown_wep_think;
- wep.savenextthink = wep.nextthink;
- wep.nextthink = min(wep.nextthink, time + 0.5);
- wep.pickup_anyway = TRUE; // these are ALWAYS pickable
- return "";
- }
- else
- {
- s = "";
- oldself = self;
- self = wep;
- weapon_defaultspawnfunc(wpn);
- self = oldself;
- if(startitem_failed)
- return string_null;
- if(doreduce && g_weapon_stay == 2)
- {
- for(i = 0, j = 1; i < 24; ++i, j *= 2)
- {
- if(wa & j)
- {
- ammofield = Item_CounterField(j);
-
- // if our weapon is loaded, give its load back to the player
- if(self.(weapon_load[self.weapon]) > 0)
- {
- own.ammofield += self.(weapon_load[self.weapon]);
- self.(weapon_load[self.weapon]) = -1; // schedule the weapon for reloading
- }
-
- wep.ammofield = 0;
- }
- }
- }
- else if(doreduce)
- {
- for(i = 0, j = 1; i < 24; ++i, j *= 2)
- {
- if(wa & j)
- {
- ammofield = Item_CounterField(j);
-
- // if our weapon is loaded, give its load back to the player
- if(self.(weapon_load[self.weapon]) > 0)
- {
- own.ammofield += self.(weapon_load[self.weapon]);
- self.(weapon_load[self.weapon]) = -1; // schedule the weapon for reloading
- }
-
- thisammo = min(own.ammofield, wep.ammofield);
- wep.ammofield = thisammo;
- own.ammofield -= thisammo;
- s = strcat(s, " and ", ftos(thisammo), " ", Item_CounterFieldName(j));
- }
- }
- s = substring(s, 5, -1);
- }
- wep.glowmod = own.weaponentity_glowmod;
- wep.think = thrown_wep_think;
- wep.savenextthink = wep.nextthink;
- wep.nextthink = min(wep.nextthink, time + 0.5);
- wep.pickup_anyway = TRUE; // these are ALWAYS pickable
-
- return s;
- }
-}
-
-float W_IsWeaponThrowable(float w)
-{
- float wa;
-
- if (!autocvar_g_pickup_items)
- return 0;
- if (g_weaponarena)
- return 0;
- if (g_cts)
- return 0;
- if (g_nexball && w == WEP_GRENADE_LAUNCHER)
- return 0;
- if(w == 0)
- return 0;
-
- wa = W_AmmoItemCode(w);
- if(WEPSET_CONTAINS_AW(start_weapons, w))
- {
- // start weapons that take no ammo can't be dropped (this prevents dropping the laser, as long as it continues to use no ammo)
- if(start_items & IT_UNLIMITED_WEAPON_AMMO)
- return 0;
- if(wa == 0)
- return 0;
- }
-
- return 1;
-}
-
-// toss current weapon
-void W_ThrowWeapon(vector velo, vector delta, float doreduce)
-{
- float w;
- string a;
-
- w = self.weapon;
- if (w == 0)
- return; // just in case
- if(MUTATOR_CALLHOOK(ForbidThrowCurrentWeapon))
- return;
- if(!autocvar_g_weapon_throwable)
- return;
- if(self.weaponentity.state != WS_READY)
- return;
- if(!W_IsWeaponThrowable(w))
- return;
-
- if(!WEPSET_CONTAINS_EW(self, w))
- return;
- WEPSET_ANDNOT_EW(self, w);
-
- W_SwitchWeapon_Force(self, w_getbestweapon(self));
- a = W_ThrowNewWeapon(self, w, doreduce, self.origin + delta, velo);
-
- if not(a) return;
- Send_Notification(NOTIF_ONE, self, MSG_MULTI, ITEM_WEAPON_DROP, a, w);
-}
-
float forbidWeaponUse()
{
if(time < game_starttime && !autocvar_sv_ready_restart_after_countdown)
}
}
-void Send_WeaponComplain (entity e, float wpn, string wpnname, float type)
-{
- msg_entity = e;
- WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteByte(MSG_ONE, TE_CSQC_WEAPONCOMPLAIN);
- WriteByte(MSG_ONE, wpn);
- WriteString(MSG_ONE, wpnname);
- WriteByte(MSG_ONE, type);
-}
-
-.float hasweapon_complain_spam;
-
-float client_hasweapon(entity cl, float wpn, float andammo, float complain)
-{
- float f;
- entity oldself;
-
- if(time < self.hasweapon_complain_spam)
- complain = 0;
- if(complain)
- self.hasweapon_complain_spam = time + 0.2;
-
- if (wpn < WEP_FIRST || wpn > WEP_LAST)
- {
- if (complain)
- sprint(self, "Invalid weapon\n");
- return FALSE;
- }
- if (WEPSET_CONTAINS_EW(cl, wpn))
- {
- if (andammo)
- {
- if(cl.items & IT_UNLIMITED_WEAPON_AMMO)
- {
- f = 1;
- }
- else
- {
- oldself = self;
- self = cl;
- f = WEP_ACTION(wpn, WR_CHECKAMMO1);
- f = f + WEP_ACTION(wpn, WR_CHECKAMMO2);
-
- // always allow selecting the Mine Layer if we placed mines, so that we can detonate them
- entity mine;
- if(wpn == WEP_MINE_LAYER)
- for(mine = world; (mine = find(mine, classname, "mine")); ) if(mine.owner == self)
- f = 1;
-
- self = oldself;
- }
- if (!f)
- {
- if (complain)
- if(IS_REAL_CLIENT(cl))
- {
- play2(cl, "weapons/unavailable.wav");
- Send_WeaponComplain (cl, wpn, W_Name(wpn), 0);
- }
- return FALSE;
- }
- }
- return TRUE;
- }
- if (complain)
- {
- // DRESK - 3/16/07
- // Report Proper Weapon Status / Modified Weapon Ownership Message
- if (WEPSET_CONTAINS_AW(weaponsInMap, wpn))
- {
- Send_WeaponComplain(cl, wpn, W_Name(wpn), 1);
-
- if(autocvar_g_showweaponspawns)
- {
- entity e;
- string s;
-
- e = get_weaponinfo(wpn);
- s = e.model2;
-
- for(e = world; (e = findfloat(e, weapon, wpn)); )
- {
- if(e.classname == "droppedweapon")
- continue;
- if not(e.flags & FL_ITEM)
- continue;
- WaypointSprite_Spawn(
- s,
- 1, 0,
- world, e.origin,
- self, 0,
- world, enemy,
- 0,
- RADARICON_NONE, '0 0 0'
- );
- }
- }
- }
- else
- {
- Send_WeaponComplain (cl, wpn, W_Name(wpn), 2);
- }
-
- play2(cl, "weapons/unavailable.wav");
- }
- return FALSE;
-}
-
// Weapon subs
void w_clear()
{
weapon_thinkf(WFRAME_IDLE, 1000000, w_ready);
}
-// perform weapon to attack (weaponstate and attack_finished check is here)
-void W_SwitchToOtherWeapon(entity pl)
-{
- // hack to ensure it switches to an OTHER weapon (in case the other fire mode still has ammo, we want that anyway)
- float w, ww;
- w = pl.weapon;
- if(WEPSET_CONTAINS_EW(pl, w))
- {
- WEPSET_ANDNOT_EW(pl, w);
- ww = w_getbestweapon(pl);
- WEPSET_OR_EW(pl, w);
- }
- else
- ww = w_getbestweapon(pl);
- if(ww)
- W_SwitchWeapon_Force(pl, ww);
-}
-
.float prevdryfire;
.float prevwarntime;
float weapon_prepareattack_checkammo(float secondary)
--- /dev/null
+// switch between weapons
+void Send_WeaponComplain(entity e, float wpn, string wpnname, float type)
+{
+ msg_entity = e;
+ WriteByte(MSG_ONE, SVC_TEMPENTITY);
+ WriteByte(MSG_ONE, TE_CSQC_WEAPONCOMPLAIN);
+ WriteByte(MSG_ONE, wpn);
+ WriteString(MSG_ONE, wpnname);
+ WriteByte(MSG_ONE, type);
+}
+
+.float hasweapon_complain_spam;
+float client_hasweapon(entity cl, float wpn, float andammo, float complain)
+{
+ float f;
+ entity oldself;
+
+ if(time < self.hasweapon_complain_spam)
+ complain = 0;
+ if(complain)
+ self.hasweapon_complain_spam = time + 0.2;
+
+ if (wpn < WEP_FIRST || wpn > WEP_LAST)
+ {
+ if (complain)
+ sprint(self, "Invalid weapon\n");
+ return FALSE;
+ }
+ if (WEPSET_CONTAINS_EW(cl, wpn))
+ {
+ if (andammo)
+ {
+ if(cl.items & IT_UNLIMITED_WEAPON_AMMO)
+ {
+ f = 1;
+ }
+ else
+ {
+ oldself = self;
+ self = cl;
+ f = WEP_ACTION(wpn, WR_CHECKAMMO1);
+ f = f + WEP_ACTION(wpn, WR_CHECKAMMO2);
+
+ // always allow selecting the Mine Layer if we placed mines, so that we can detonate them
+ entity mine;
+ if(wpn == WEP_MINE_LAYER)
+ for(mine = world; (mine = find(mine, classname, "mine")); ) if(mine.owner == self)
+ f = 1;
+
+ self = oldself;
+ }
+ if (!f)
+ {
+ if (complain)
+ if(IS_REAL_CLIENT(cl))
+ {
+ play2(cl, "weapons/unavailable.wav");
+ Send_WeaponComplain (cl, wpn, W_Name(wpn), 0);
+ }
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+ if (complain)
+ {
+ // DRESK - 3/16/07
+ // Report Proper Weapon Status / Modified Weapon Ownership Message
+ if (WEPSET_CONTAINS_AW(weaponsInMap, wpn))
+ {
+ Send_WeaponComplain(cl, wpn, W_Name(wpn), 1);
+
+ if(autocvar_g_showweaponspawns)
+ {
+ entity e;
+ string s;
+
+ e = get_weaponinfo(wpn);
+ s = e.model2;
+
+ for(e = world; (e = findfloat(e, weapon, wpn)); )
+ {
+ if(e.classname == "droppedweapon")
+ continue;
+ if not(e.flags & FL_ITEM)
+ continue;
+ WaypointSprite_Spawn(
+ s,
+ 1, 0,
+ world, e.origin,
+ self, 0,
+ world, enemy,
+ 0,
+ RADARICON_NONE, '0 0 0'
+ );
+ }
+ }
+ }
+ else
+ {
+ Send_WeaponComplain (cl, wpn, W_Name(wpn), 2);
+ }
+
+ play2(cl, "weapons/unavailable.wav");
+ }
+ return FALSE;
+}
+
+.float weaponcomplainindex;
+float W_GetCycleWeapon(entity pl, string weaponorder, float dir, float imp, float complain, float skipmissing)
+{
+ // We cannot tokenize in this function, as GiveItems calls this
+ // function. Thus we must use car/cdr.
+ float weaponwant, first_valid, prev_valid, switchtonext, switchtolast, c;
+ string rest;
+ switchtonext = switchtolast = 0;
+ first_valid = prev_valid = 0;
+ float weaponcur;
+
+ if(skipmissing || pl.selectweapon == 0)
+ weaponcur = pl.switchweapon;
+ else
+ weaponcur = pl.selectweapon;
+
+ if(dir == 0)
+ switchtonext = 1;
+
+ c = 0;
+
+ rest = weaponorder;
+ while(rest != "")
+ {
+ weaponwant = stof(car(rest)); rest = cdr(rest);
+ if(imp >= 0)
+ if((get_weaponinfo(weaponwant)).impulse != imp)
+ continue;
+
+ ++c;
+
+ if(!skipmissing || client_hasweapon(pl, weaponwant, TRUE, FALSE))
+ {
+ if(switchtonext)
+ return weaponwant;
+ if(!first_valid)
+ first_valid = weaponwant;
+ if(weaponwant == weaponcur)
+ {
+ if(dir >= 0)
+ switchtonext = 1;
+ else if(prev_valid)
+ return prev_valid;
+ else
+ switchtolast = 1;
+ }
+ prev_valid = weaponwant;
+ }
+ }
+ if(first_valid)
+ {
+ if(switchtolast)
+ return prev_valid;
+ else
+ return first_valid;
+ }
+ // complain (but only for one weapon on the button that has been pressed)
+ if(complain)
+ {
+ self.weaponcomplainindex += 1;
+ c = mod(self.weaponcomplainindex, c) + 1;
+ rest = weaponorder;
+ while(rest != "")
+ {
+ weaponwant = stof(car(rest)); rest = cdr(rest);
+ if(imp >= 0)
+ if((get_weaponinfo(weaponwant)).impulse != imp)
+ continue;
+
+ --c;
+ if(c == 0)
+ {
+ client_hasweapon(pl, weaponwant, TRUE, TRUE);
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+#define w_getbestweapon(ent) W_GetCycleWeapon(ent, ent.cvar_cl_weaponpriority, 0, -1, FALSE, TRUE)
+
+// perform weapon to attack (weaponstate and attack_finished check is here)
+void W_SwitchToOtherWeapon(entity pl)
+{
+ // hack to ensure it switches to an OTHER weapon (in case the other fire mode still has ammo, we want that anyway)
+ float w, ww;
+ w = pl.weapon;
+ if(WEPSET_CONTAINS_EW(pl, w))
+ {
+ WEPSET_ANDNOT_EW(pl, w);
+ ww = w_getbestweapon(pl);
+ WEPSET_OR_EW(pl, w);
+ }
+ else
+ ww = w_getbestweapon(pl);
+ if(ww)
+ W_SwitchWeapon_Force(pl, ww);
+}
+
+void W_SwitchWeapon(float imp)
+{
+ if (self.switchweapon != imp)
+ {
+ if (client_hasweapon(self, imp, TRUE, TRUE))
+ W_SwitchWeapon_Force(self, imp);
+ else
+ self.selectweapon = imp; // update selectweapon ANYWAY
+ }
+ else { WEP_ACTION(self.weapon, WR_RELOAD); }
+}
+
+void W_CycleWeapon(string weaponorder, float dir)
+{
+ float w;
+ w = W_GetCycleWeapon(self, weaponorder, dir, -1, 1, TRUE);
+ if(w > 0)
+ W_SwitchWeapon(w);
+}
+
+void W_NextWeaponOnImpulse(float imp)
+{
+ float w;
+ w = W_GetCycleWeapon(self, self.cvar_cl_weaponpriority, +1, imp, 1, (self.cvar_cl_weaponimpulsemode == 0));
+ if(w > 0)
+ W_SwitchWeapon(w);
+}
+
+// next weapon
+void W_NextWeapon(float list)
+{
+ if(list == 0)
+ W_CycleWeapon(weaponorder_byid, -1);
+ else if(list == 1)
+ W_CycleWeapon(self.weaponorder_byimpulse, -1);
+ else if(list == 2)
+ W_CycleWeapon(self.cvar_cl_weaponpriority, -1);
+}
+
+// prev weapon
+void W_PreviousWeapon(float list)
+{
+ if(list == 0)
+ W_CycleWeapon(weaponorder_byid, +1);
+ else if(list == 1)
+ W_CycleWeapon(self.weaponorder_byimpulse, +1);
+ else if(list == 2)
+ W_CycleWeapon(self.cvar_cl_weaponpriority, +1);
+}
+
+// previously used if exists and has ammo, (second) best otherwise
+void W_LastWeapon(void)
+{
+ if(client_hasweapon(self, self.cnt, TRUE, FALSE))
+ W_SwitchWeapon(self.cnt);
+ else
+ W_SwitchToOtherWeapon(self);
+}
--- /dev/null
+.float savenextthink;
+void thrown_wep_think()
+{
+ self.owner = world;
+ float timeleft = self.savenextthink - time;
+ if(timeleft > 1)
+ SUB_SetFade(self, self.savenextthink - 1, 1);
+ else if(timeleft > 0)
+ SUB_SetFade(self, time, timeleft);
+ else
+ SUB_VanishOrRemove(self);
+}
+
+// returns amount of ammo used as string, or -1 for failure, or 0 for no ammo count
+string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vector velo)
+{
+ entity oldself, wep;
+ float wa, thisammo, i, j;
+ string s;
+ var .float ammofield;
+
+ wep = spawn();
+
+ setorigin(wep, org);
+ wep.classname = "droppedweapon";
+ wep.velocity = velo;
+ wep.owner = wep.enemy = own;
+ wep.flags |= FL_TOSSED;
+ wep.colormap = own.colormap;
+
+ if(WEPSET_CONTAINS_AW(WEPBIT_SUPERWEAPONS, wpn))
+ {
+ if(own.items & IT_UNLIMITED_SUPERWEAPONS)
+ {
+ wep.superweapons_finished = time + autocvar_g_balance_superweapons_time;
+ }
+ else
+ {
+ float superweapons = 1;
+ for(i = WEP_FIRST; i <= WEP_LAST; ++i)
+ if(WEPSET_CONTAINS_AW(WEPBIT_SUPERWEAPONS, i))
+ if(WEPSET_CONTAINS_EW(own, i))
+ ++superweapons;
+ if(superweapons <= 1)
+ {
+ wep.superweapons_finished = own.superweapons_finished;
+ own.superweapons_finished = 0;
+ }
+ else
+ {
+ float timeleft = own.superweapons_finished - time;
+ float weptimeleft = timeleft / superweapons;
+ wep.superweapons_finished = time + weptimeleft;
+ own.superweapons_finished -= weptimeleft;
+ }
+ }
+ }
+
+ wa = W_AmmoItemCode(wpn);
+ if(wa == 0)
+ {
+ oldself = self;
+ self = wep;
+ weapon_defaultspawnfunc(wpn);
+ self = oldself;
+ if(startitem_failed)
+ return string_null;
+ wep.glowmod = own.weaponentity_glowmod;
+ wep.think = thrown_wep_think;
+ wep.savenextthink = wep.nextthink;
+ wep.nextthink = min(wep.nextthink, time + 0.5);
+ wep.pickup_anyway = TRUE; // these are ALWAYS pickable
+ return "";
+ }
+ else
+ {
+ s = "";
+ oldself = self;
+ self = wep;
+ weapon_defaultspawnfunc(wpn);
+ self = oldself;
+ if(startitem_failed)
+ return string_null;
+ if(doreduce && g_weapon_stay == 2)
+ {
+ for(i = 0, j = 1; i < 24; ++i, j *= 2)
+ {
+ if(wa & j)
+ {
+ ammofield = Item_CounterField(j);
+
+ // if our weapon is loaded, give its load back to the player
+ if(self.(weapon_load[self.weapon]) > 0)
+ {
+ own.ammofield += self.(weapon_load[self.weapon]);
+ self.(weapon_load[self.weapon]) = -1; // schedule the weapon for reloading
+ }
+
+ wep.ammofield = 0;
+ }
+ }
+ }
+ else if(doreduce)
+ {
+ for(i = 0, j = 1; i < 24; ++i, j *= 2)
+ {
+ if(wa & j)
+ {
+ ammofield = Item_CounterField(j);
+
+ // if our weapon is loaded, give its load back to the player
+ if(self.(weapon_load[self.weapon]) > 0)
+ {
+ own.ammofield += self.(weapon_load[self.weapon]);
+ self.(weapon_load[self.weapon]) = -1; // schedule the weapon for reloading
+ }
+
+ thisammo = min(own.ammofield, wep.ammofield);
+ wep.ammofield = thisammo;
+ own.ammofield -= thisammo;
+ s = strcat(s, " and ", ftos(thisammo), " ", Item_CounterFieldName(j));
+ }
+ }
+ s = substring(s, 5, -1);
+ }
+ wep.glowmod = own.weaponentity_glowmod;
+ wep.think = thrown_wep_think;
+ wep.savenextthink = wep.nextthink;
+ wep.nextthink = min(wep.nextthink, time + 0.5);
+ wep.pickup_anyway = TRUE; // these are ALWAYS pickable
+
+ return s;
+ }
+}
+
+float W_IsWeaponThrowable(float w)
+{
+ float wa;
+
+ if (!autocvar_g_pickup_items)
+ return 0;
+ if (g_weaponarena)
+ return 0;
+ if (g_cts)
+ return 0;
+ if (g_nexball && w == WEP_GRENADE_LAUNCHER)
+ return 0;
+ if(w == 0)
+ return 0;
+
+ wa = W_AmmoItemCode(w);
+ if(WEPSET_CONTAINS_AW(start_weapons, w))
+ {
+ // start weapons that take no ammo can't be dropped (this prevents dropping the laser, as long as it continues to use no ammo)
+ if(start_items & IT_UNLIMITED_WEAPON_AMMO)
+ return 0;
+ if(wa == 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+// toss current weapon
+void W_ThrowWeapon(vector velo, vector delta, float doreduce)
+{
+ float w;
+ string a;
+
+ w = self.weapon;
+ if (w == 0)
+ return; // just in case
+ if(MUTATOR_CALLHOOK(ForbidThrowCurrentWeapon))
+ return;
+ if(!autocvar_g_weapon_throwable)
+ return;
+ if(self.weaponentity.state != WS_READY)
+ return;
+ if(!W_IsWeaponThrowable(w))
+ return;
+
+ if(!WEPSET_CONTAINS_EW(self, w))
+ return;
+ WEPSET_ANDNOT_EW(self, w);
+
+ W_SwitchWeapon_Force(self, w_getbestweapon(self));
+ a = W_ThrowNewWeapon(self, w, doreduce, self.origin + delta, velo);
+
+ if not(a) return;
+ Send_Notification(NOTIF_ONE, self, MSG_MULTI, ITEM_WEAPON_DROP, a, w);
+}