From d4a02e06778ec4a28dd3825d786448e1b20174b9 Mon Sep 17 00:00:00 2001 From: Samual Lenks Date: Mon, 1 Jul 2013 02:53:14 -0400 Subject: [PATCH] Split throwing and selection into their own files --- qcsrc/server/weapons/cl_weapons.qc | 347 ----------------------------- qcsrc/server/weapons/main.qc | 126 ----------- qcsrc/server/weapons/selection.qc | 266 ++++++++++++++++++++++ qcsrc/server/weapons/throwing.qc | 191 ++++++++++++++++ 4 files changed, 457 insertions(+), 473 deletions(-) create mode 100644 qcsrc/server/weapons/selection.qc create mode 100644 qcsrc/server/weapons/throwing.qc diff --git a/qcsrc/server/weapons/cl_weapons.qc b/qcsrc/server/weapons/cl_weapons.qc index bf72ae15a..1091853af 100644 --- a/qcsrc/server/weapons/cl_weapons.qc +++ b/qcsrc/server/weapons/cl_weapons.qc @@ -1,350 +1,3 @@ -// 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) diff --git a/qcsrc/server/weapons/main.qc b/qcsrc/server/weapons/main.qc index c6e9e30a9..be5eca13b 100644 --- a/qcsrc/server/weapons/main.qc +++ b/qcsrc/server/weapons/main.qc @@ -573,114 +573,6 @@ void CL_SpawnWeaponentity() } } -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() { @@ -703,24 +595,6 @@ void w_ready() 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) diff --git a/qcsrc/server/weapons/selection.qc b/qcsrc/server/weapons/selection.qc new file mode 100644 index 000000000..95a145e69 --- /dev/null +++ b/qcsrc/server/weapons/selection.qc @@ -0,0 +1,266 @@ +// 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); +} diff --git a/qcsrc/server/weapons/throwing.qc b/qcsrc/server/weapons/throwing.qc new file mode 100644 index 000000000..c5e21f2f4 --- /dev/null +++ b/qcsrc/server/weapons/throwing.qc @@ -0,0 +1,191 @@ +.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); +} -- 2.39.2