1 // switch between weapons
\r
2 void W_SwitchWeapon(float imp)
\r
4 if (self.switchweapon != imp)
\r
6 if (client_hasweapon(self, imp, TRUE, TRUE))
\r
7 W_SwitchWeapon_Force(self, imp);
\r
11 .float weaponcomplainindex;
\r
12 float W_GetCycleWeapon(entity pl, string weaponorder, float dir, float imp, float complain)
\r
14 // We cannot tokenize in this function, as GiveItems calls this
\r
15 // function. Thus we must use car/cdr.
\r
16 float weaponwant, first_valid, prev_valid, switchtonext, switchtolast, c;
\r
18 switchtonext = switchtolast = 0;
\r
19 first_valid = prev_valid = 0;
\r
29 weaponwant = stof(car(rest)); rest = cdr(rest);
\r
31 if((get_weaponinfo(weaponwant)).impulse != imp)
\r
36 if(client_hasweapon(pl, weaponwant, TRUE, FALSE))
\r
41 first_valid = weaponwant;
\r
42 if(weaponwant == pl.switchweapon)
\r
51 prev_valid = weaponwant;
\r
61 // complain (but only for one weapon on the button that has been pressed)
\r
64 self.weaponcomplainindex += 1;
\r
65 c = mod(self.weaponcomplainindex, c) + 1;
\r
69 weaponwant = stof(car(rest)); rest = cdr(rest);
\r
71 if((get_weaponinfo(weaponwant)).impulse != imp)
\r
77 client_hasweapon(pl, weaponwant, TRUE, TRUE);
\r
85 void W_CycleWeapon(string weaponorder, float dir)
\r
88 w = W_GetCycleWeapon(self, weaponorder, dir, -1, 1);
\r
93 void W_NextWeaponOnImpulse(float imp)
\r
96 w = W_GetCycleWeapon(self, self.cvar_cl_weaponpriority, +1, imp, 1);
\r
102 void W_NextWeapon(float list)
\r
105 W_CycleWeapon(weaponpriority_hudselector_0, -1);
\r
107 W_CycleWeapon(weaponpriority_hudselector_1, -1);
\r
109 W_CycleWeapon(self.cvar_cl_weaponpriority, -1);
\r
113 void W_PreviousWeapon(float list)
\r
116 W_CycleWeapon(weaponpriority_hudselector_0, +1);
\r
118 W_CycleWeapon(weaponpriority_hudselector_1, +1);
\r
120 W_CycleWeapon(self.cvar_cl_weaponpriority, +1);
\r
123 string W_FixWeaponOrder_AllowIncomplete(string order)
\r
125 return W_FixWeaponOrder(order, 0);
\r
128 string W_FixWeaponOrder_ForceComplete(string order)
\r
131 order = W_NumberWeaponOrder(cvar_string("cl_weaponpriority"));
\r
132 return W_FixWeaponOrder(order, 1);
\r
135 float w_getbestweapon(entity e)
\r
137 return W_GetCycleWeapon(e, e.cvar_cl_weaponpriority, 0, -1, 0);
\r
140 // generic weapons table
\r
141 // TODO should they be macros instead?
\r
142 float weapon_action(float wpn, float wrequest)
\r
144 return (get_weaponinfo(wpn)).weapon_func(wrequest);
\r
147 string W_Name(float weaponid)
\r
149 return (get_weaponinfo(weaponid)).message;
\r
152 float W_WeaponBit(float wpn)
\r
154 return (get_weaponinfo(wpn)).weapons;
\r
157 float W_AmmoItemCode(float wpn)
\r
159 return (get_weaponinfo(wpn)).items;
\r
162 void thrown_wep_think()
\r
164 self.solid = SOLID_TRIGGER;
\r
165 self.owner = world;
\r
166 SUB_SetFade(self, time + 20, 1);
\r
169 // returns amount of ammo used as string, or -1 for failure, or 0 for no ammo count
\r
170 string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vector velo)
\r
172 entity oldself, wep;
\r
173 float wa, thisammo, i, j;
\r
175 var .float ammofield;
\r
179 setorigin(wep, org);
\r
180 wep.classname = "droppedweapon";
\r
181 wep.velocity = velo;
\r
182 wep.owner = wep.enemy = own;
\r
183 wep.flags |= FL_TOSSED;
\r
184 wep.colormap = own.colormap;
\r
186 wa = W_AmmoItemCode(wpn);
\r
187 if(wa == IT_SUPERWEAPON || wa == 0)
\r
191 weapon_defaultspawnfunc(wpn);
\r
193 if(startitem_failed)
\r
194 return string_null;
\r
195 wep.colormod = wep.owner.colormod; // used by the regurgitating colors
\r
196 wep.think = thrown_wep_think;
\r
197 wep.nextthink = time + 0.5;
\r
205 weapon_defaultspawnfunc(wpn);
\r
207 if(startitem_failed)
\r
208 return string_null;
\r
211 for(i = 0, j = 1; i < 24; ++i, j *= 2)
\r
215 ammofield = Item_CounterField(j);
\r
216 thisammo = min(own.ammofield, wep.ammofield);
\r
217 wep.ammofield = thisammo;
\r
218 own.ammofield -= thisammo;
\r
219 s = strcat(s, " and ", ftos(thisammo), " ", Item_CounterFieldName(j));
\r
222 s = substring(s, 5, -1);
\r
224 wep.colormod = wep.owner.colormod; // used by the regurgitating colors
\r
225 wep.think = thrown_wep_think;
\r
226 wep.nextthink = time + 0.5;
\r
231 float W_IsWeaponThrowable(float w)
\r
234 wb = W_WeaponBit(w);
\r
237 wa = W_AmmoItemCode(w);
\r
238 if(start_weapons & wb)
\r
240 if(wa == IT_SUPERWEAPON && start_items & IT_UNLIMITED_SUPERWEAPONS)
\r
242 if(wa != IT_SUPERWEAPON && start_items & IT_UNLIMITED_WEAPON_AMMO)
\r
244 // start weapons that take no ammo can't be dropped (this prevents dropping the laser, as long as it continues to use no ammo)
\r
252 // toss current weapon
\r
253 void W_ThrowWeapon(vector velo, vector delta, float doreduce)
\r
260 return; // just in case
\r
263 if (!cvar("g_pickup_items"))
\r
265 if(!cvar("g_weapon_throwable"))
\r
267 if(cvar("g_weapon_stay") == 1)
\r
269 if(!W_IsWeaponThrowable(w))
\r
272 wb = W_WeaponBit(w);
\r
273 if(self.weapons & wb != wb)
\r
276 self.weapons &~= wb;
\r
277 W_SwitchWeapon_Force(self, w_getbestweapon(self));
\r
278 a = W_ThrowNewWeapon(self, w, doreduce, self.origin + delta, velo);
\r
281 if(self.health >= 1)
\r
284 sprint(self, strcat("You dropped the ^2", W_Name(w), "\n"));
\r
286 sprint(self, strcat("You dropped the ^2", W_Name(w), " with ", a, "\n"));
\r
290 // Bringed back weapon frame
\r
291 void W_WeaponFrame()
\r
296 self.weapon_frametime = frametime;
\r
298 if(((arena_roundbased || g_ca) && time < warmup) || ((time < game_starttime) && !cvar("sv_ready_restart_after_countdown")))
\r
301 if (!self.weaponentity || self.health < 1)
\r
302 return; // Dead player can't use weapons and injure impulse commands
\r
304 if(!self.switchweapon)
\r
307 self.weaponentity.state = WS_CLEAR;
\r
308 self.weaponname = "";
\r
309 self.items &~= IT_AMMO;
\r
313 makevectors(self.v_angle);
\r
314 fo = v_forward; // save them in case the weapon think functions change it
\r
319 if (self.weapon != self.switchweapon)
\r
321 if (self.weaponentity.state == WS_CLEAR)
\r
323 setanim(self, self.anim_draw, FALSE, TRUE, TRUE);
\r
324 self.weaponentity.state = WS_RAISE;
\r
325 weapon_action(self.switchweapon, WR_SETUP);
\r
326 // VorteX: add player model weapon select frame here
\r
327 // setcustomframe(PlayerWeaponRaise);
\r
328 weapon_thinkf(WFRAME_IDLE, cvar("g_balance_weaponswitchdelay"), w_ready);
\r
329 weapon_boblayer1(PLAYER_WEAPONSELECTION_SPEED, '0 0 0');
\r
331 else if (self.weaponentity.state == WS_READY)
\r
333 #ifndef INDEPENDENT_ATTACK_FINISHED
\r
334 if(ATTACK_FINISHED(self) <= time + self.weapon_frametime * 0.5)
\r
337 // UGLY WORKAROUND: play this on CHAN_WEAPON2 so it can't cut off fire sounds
\r
338 sound (self, CHAN_WEAPON2, "weapons/weapon_switch.wav", VOL_BASE, ATTN_NORM);
\r
339 self.weaponentity.state = WS_DROP;
\r
340 // set up weapon switch think in the future, and start drop anim
\r
341 weapon_thinkf(WFRAME_DONTCHANGE, cvar("g_balance_weaponswitchdelay"), w_clear);
\r
342 weapon_boblayer1(PLAYER_WEAPONSELECTION_SPEED, PLAYER_WEAPONSELECTION_RANGE);
\r
343 #ifndef INDEPENDENT_ATTACK_FINISHED
\r
349 // LordHavoc: network timing test code
\r
350 //if (self.button0)
\r
351 // print(ftos(frametime), " ", ftos(time), " >= ", ftos(ATTACK_FINISHED(self)), " >= ", ftos(self.weapon_nextthink), "\n");
\r
354 wb = W_WeaponBit(self.weapon);
\r
356 // call the think code which may fire the weapon
\r
357 // and do so multiple times to resolve framerate dependency issues if the
\r
358 // server framerate is very low and the weapon fire rate very high
\r
364 if(wb && ((self.weapons & wb) == 0))
\r
366 W_SwitchWeapon_Force(self, w_getbestweapon(self));
\r
374 weapon_action(self.weapon, WR_THINK);
\r
376 if (time + self.weapon_frametime * 0.5 >= self.weapon_nextthink)
\r
378 if(self.weapon_think)
\r
383 self.weapon_think();
\r
386 bprint("\{1}^1ERROR: undefined weapon think function for ", self.netname, "\n");
\r
390 // don't let attack_finished fall behind when not firing (must be after weapon_setup calls!)
\r
391 //if (ATTACK_FINISHED(self) < time)
\r
392 // ATTACK_FINISHED(self) = time;
\r
394 //if (self.weapon_nextthink < time)
\r
395 // self.weapon_nextthink = time;
\r