]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/gamec/cl_weapons.c
more elegant checking to see if stuffcmds are safe
[divverent/nexuiz.git] / data / qcsrc / gamec / cl_weapons.c
1 // generic weapons table
2 // add new weapons here
3 void(float wpn, float wrequest) weapon_action =
4 {
5         if (cvar("g_minstagib"))
6         {
7                 if (wpn == WEP_NEX)
8                         w_nex(wrequest);
9                 return;
10         }
11
12         if (wpn == WEP_LASER)
13                 w_laser(wrequest);
14         else if (wpn == WEP_SHOTGUN)
15                 w_shotgun(wrequest);
16         else if (wpn == WEP_UZI)
17                 w_uzi(wrequest);
18         else if (wpn == WEP_GRENADE_LAUNCHER)
19                 w_glauncher(wrequest);
20         else if (wpn == WEP_ELECTRO)
21                 w_electro(wrequest);
22         else if (wpn == WEP_CRYLINK)
23                 w_crylink(wrequest);
24         else if (wpn == WEP_NEX)
25                 w_nex(wrequest);
26         else if (wpn == WEP_HAGAR)
27                 w_hagar(wrequest);
28         else if (wpn == WEP_ROCKET_LAUNCHER)
29                 w_rlauncher(wrequest);
30 };
31
32 // think function for tossed weapons
33 void() thrown_wep_think =
34 {
35         self.solid = SOLID_TRIGGER;
36         SUB_SetFade(self, time + 20, 1);
37         setorigin(self, self.origin);
38 };
39
40 // toss current weapon
41 void() W_ThrowWeapon
42 {
43         local float w;
44         local entity wep, e;
45
46         e = self;
47         wep = spawn();
48         self = wep;
49         w = e.weapon;
50         setorigin(wep, e.origin);
51         makevectors(e.angles);
52         wep.classname = "droppedweapon";
53         wep.velocity = e.velocity * 0.5 + v_forward * 750;
54         SUB_SetFade(wep, time + 20, 1);
55
56         if(w == WEP_SHOTGUN)
57         {
58                 w = IT_SHOTGUN;
59                 if(!(e.items & w))
60                 {
61                         remove(wep);
62                         return;
63                 }
64                 weapon_shotgun();
65                 wep.ammo_shells = 1;
66                 e.ammo_shells -= 1;
67         }
68         else if(w == WEP_UZI)
69         {
70                 w = IT_UZI;
71                 if(!(e.items & w))
72                 {
73                         remove(wep);
74                         return;
75                 }
76                 weapon_uzi();
77                 wep.ammo_nails = 1;
78                 e.ammo_nails -= 1;
79         }
80         else if(w == WEP_GRENADE_LAUNCHER)
81         {
82                 w = IT_GRENADE_LAUNCHER;
83                 if(!(e.items & w))
84                 {
85                         remove(wep);
86                         return;
87                 }
88                 weapon_grenadelauncher();
89                 wep.ammo_rockets = 1;
90                 e.ammo_rockets -= 1;
91         }
92         else if(w == WEP_ELECTRO)
93         {
94                 w = IT_ELECTRO;
95                 if(!(e.items & w))
96                 {
97                         remove(wep);
98                         return;
99                 }
100                 weapon_electro();
101                 wep.ammo_cells = 1;
102                 e.ammo_cells -= 1;
103         }
104         else if(w == WEP_CRYLINK)
105         {
106                 w = IT_CRYLINK;
107                 if(!(e.items & w))
108                 {
109                         remove(wep);
110                         return;
111                 }
112                 weapon_crylink();
113                 wep.ammo_cells = 1;
114                 e.ammo_cells -= 1;
115         }
116         else if(w == WEP_NEX)
117         {
118                 w = IT_NEX;
119                 if(!(e.items & w))
120                 {
121                         remove(wep);
122                         return;
123                 }
124                 weapon_nex();
125                 wep.ammo_cells = 1;
126                 e.ammo_cells -= 1;
127         }
128         else if(w == WEP_HAGAR)
129         {
130                 w = IT_HAGAR;
131                 if(!(e.items & w))
132                 {
133                         remove(wep);
134                         return;
135                 }
136                 weapon_hagar();
137                 wep.ammo_rockets = 1;
138                 e.ammo_rockets -= 1;
139         }
140         else if(w == WEP_ROCKET_LAUNCHER)
141         {
142                 w = IT_ROCKET_LAUNCHER;
143                 if(!(e.items & w))
144                 {
145                         remove(wep);
146                         return;
147                 }
148                 weapon_rocketlauncher();
149                 wep.ammo_rockets = 1;
150                 e.ammo_rockets -= 1;
151         }
152
153         if(e.items & w)
154                 sprint(e, strcat("You dropped the ^2", wep.netname, "\n"));
155         wep.solid = SOLID_NOT;
156         setorigin(wep, wep.origin);
157         wep.nextthink = time + 0.25;
158         wep.think = thrown_wep_think;
159         wep.classname = "droppedweapon";
160         e.items = e.items - (e.items & w);
161         e.switchweapon = w_getbestweapon(e);
162         self = e;
163 };
164
165 // switch between weapons
166 void(float imp) W_SwitchWeapon
167 {
168         weapon_hasammo = TRUE;
169         if (!client_hasweapon(self, imp, TRUE))
170         {
171                 if (!weapon_hasammo)
172                         sprint(self, "You don't have any ammo for that weapon\n");
173                 else
174                         sprint(self, "You don't own that weapon\n");
175         }
176         else
177                 self.switchweapon = imp;
178 };
179
180 // next weapon
181 void() W_NextWeapon =
182 {
183         local float weaponwant;
184
185         weaponwant = self.switchweapon + 1;
186         if (weaponwant < WEP_FIRST)
187                 weaponwant = WEP_LAST;
188         if (weaponwant > WEP_LAST)
189                 weaponwant = WEP_FIRST;
190         weapon_hasammo = TRUE;
191         while(!client_hasweapon(self, weaponwant, TRUE))
192         {
193                 weaponwant = weaponwant + 1;
194                 if (weaponwant < WEP_FIRST)
195                         weaponwant = WEP_LAST;
196                 if (weaponwant > WEP_LAST)
197                         weaponwant = WEP_FIRST;
198         }
199         self.switchweapon = weaponwant;
200 };
201
202 // prev weapon
203 void() W_PreviousWeapon =
204 {
205         local float weaponwant;
206
207         weaponwant = self.switchweapon - 1;
208         if (weaponwant < WEP_FIRST)
209                 weaponwant = WEP_LAST;
210         if (weaponwant > WEP_LAST)
211                 weaponwant = WEP_FIRST;
212         weapon_hasammo = TRUE;
213         while(!client_hasweapon(self, weaponwant, TRUE))
214         {
215                 weaponwant = weaponwant - 1;
216                 if (weaponwant < WEP_FIRST)
217                         weaponwant = WEP_LAST;
218                 if (weaponwant > WEP_LAST)
219                         weaponwant = WEP_FIRST;
220         }
221         self.switchweapon = weaponwant;
222 };
223
224 // Bringed back weapon frame
225 void() W_WeaponFrame =
226 {
227         if (!self.weaponentity || self.health <= 0)
228                 return; // Dead player can't use weapons and injure impulse commands
229
230         if (cvar("g_antilag"))
231         {
232                 // if aiming at a player and the original trace won't hit that player
233                 // anymore, try aiming at the player's new position
234                 if (self.cursor_trace_ent)
235                 if (self.cursor_trace_ent.takedamage)
236                 if (self.weapon == WEP_NEX || self.weapon == WEP_SHOTGUN || self.weapon == WEP_UZI)
237                 {
238                         traceline(self.origin + self.view_ofs, self.cursor_trace_endpos, FALSE, self);
239                         if (trace_ent != self.cursor_trace_ent)
240                         {
241                                 traceline(self.origin + self.view_ofs, self.cursor_trace_ent.origin + (self.cursor_trace_ent.mins + self.cursor_trace_ent.maxs) * 0.5, FALSE, self);
242                                 if (trace_ent == self.cursor_trace_ent)
243                                         self.cursor_trace_endpos = trace_endpos;
244                         }
245                 }
246                 self.v_angle = vectoangles(self.cursor_trace_endpos - (self.origin + self.view_ofs));
247                 self.v_angle_x = 0 - self.v_angle_x;
248         }
249
250         makevectors(self.v_angle);
251
252         // Change weapon
253         if (self.weapon != self.switchweapon)
254         {
255                 if (self.weaponentity.state == WS_CLEAR)
256                 {
257                         self.weaponentity.state = WS_RAISE;
258                         weapon_action(self.switchweapon, WR_SETUP);
259                         // VorteX: add player model weapon select frame here
260                         // setcustomframe(PlayerWeaponRaise);
261                         weapon_action(self.weapon, WR_UPDATECOUNTS);
262                         weapon_action(self.weapon, WR_RAISE);
263                 }
264                 else if (self.weaponentity.state == WS_READY)
265                 {
266                         sound (self, CHAN_WEAPON, "weapons/weapon_switch.ogg", 1, ATTN_NORM);
267                         self.weaponentity.state = WS_DROP;
268                         // VorteX: add player model weapon deselect frame here
269                         // setcustomframe(PlayerWeaponDrop);
270                         weapon_action(self.weapon, WR_DROP);
271                 }
272         }
273
274         if (self.button0)
275                 weapon_action(self.weapon, WR_FIRE1);
276         if (self.button3)
277                 weapon_action(self.weapon, WR_FIRE2);
278
279         // do weapon think
280         if (time >= self.weapon_nextthink)
281                 if (self.weapon_nextthink > 0)
282                         self.weapon_think();
283
284         // weapon bobbing and script actions
285         local float bobintensity, q1pitching, framespeed, diff;
286         local vector vel, realorg, layer1, boblayer;
287
288         bobintensity = cvar("g_viewweapon_bobintensity"); // weapon bob intensity
289         q1pitching = fabs(cvar("g_viewweapon_q1pitching")); // q1 style of "bob" when looking up and down
290
291         realorg = self.weaponentity.origin + self.weaponentity.view_ofs;
292         realorg = realorg - self.weaponentity.finaldest; // finaldest is last bob position
293
294         // VorteX: actually this is needed for weapon screen offset
295         if (q1pitching)
296         {
297                 self.weaponentity.view_ofs_x = q1pitching*bound(-5.5, self.v_angle_x/45, 5.5);
298                 self.weaponentity.view_ofs_z = q1pitching*bound(-1.5, self.v_angle_x/60, 1.5);
299         }
300
301         // weapon origin interpolation, layer 1
302         if (realorg != self.weaponentity.pos1)
303         {
304                 framespeed = frametime*self.weaponentity.lip*10; // lip is speed of origin changing (of layer1)
305                 diff = vlen(realorg - self.weaponentity.pos1);
306                 // VorteX: add speed modifier (haste)?
307                 layer1 = frametime*10*self.weaponentity.lip*normalize(self.weaponentity.pos1 - realorg);
308                 if (diff <= vlen(layer1))
309                         layer1 = normalize(self.weaponentity.pos1 - realorg)*diff;
310         }
311
312         // weapon bobbing (q3-style)
313         if (self.flags & FL_ONGROUND && self.waterlevel < 2)
314         {
315                 // VorteX: only xy velocity matters
316                 vel_x = self.velocity_x;
317                 vel_y = self.velocity_y;
318                 framespeed = vlen(vel);
319                 // Y axis
320                 diff = bobintensity*framespeed/300;
321                 self.weaponentity.destvec_y = self.weaponentity.destvec_y + frametime*10;
322                 boblayer_y = diff*cos(self.weaponentity.destvec_y + 90);
323                 // Z axis
324                 diff = bobintensity*framespeed/540;
325                 self.weaponentity.destvec_z = self.weaponentity.destvec_z + frametime*20;
326                 boblayer_z = diff*cos(self.weaponentity.destvec_z);
327                 self.weaponentity.finaldest = boblayer;
328         }
329         else if (self.waterlevel > 0)
330         {// swim, all velocity matters
331                 // X axis
332                 framespeed = vlen(self.velocity);
333                 diff = bobintensity*framespeed/100;
334                 self.weaponentity.destvec_x = self.weaponentity.destvec_x + frametime*6;
335                 boblayer_x = diff*cos(self.weaponentity.destvec_x);
336                 self.weaponentity.finaldest = boblayer;
337         }
338         else
339                 self.weaponentity.finaldest = '0 0 0';
340         self.weaponentity.origin = realorg + boblayer + layer1 - self.weaponentity.view_ofs;
341 };