]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/weapons/w_machinegun.qc
Use .current_ammo instead of specific ammo fields
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / weapons / w_machinegun.qc
1 #ifdef REGISTER_WEAPON
2 REGISTER_WEAPON(
3 /* WEP_##id */ UZI,
4 /* function */ w_uzi,
5 /* ammotype */ ammo_nails,
6 /* impulse  */ 3,
7 /* flags    */ WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN,
8 /* rating   */ BOT_PICKUP_RATING_MID,
9 /* model    */ "uzi",
10 /* netname  */ "uzi",
11 /* fullname */ _("Machine Gun")
12 );
13
14 #define UZI_SETTINGS(w_cvar,w_prop) UZI_SETTINGS_LIST(w_cvar, w_prop, UZI, uzi)
15 #define UZI_SETTINGS_LIST(w_cvar,w_prop,id,sn) \
16         w_cvar(id, sn, NONE, speed) \
17         w_cvar(id, sn, NONE, spread_min) \
18         w_cvar(id, sn, NONE, spread_max) \
19         w_cvar(id, sn, NONE, spread_add) \
20         w_cvar(id, sn, NONE, mode) \
21         w_cvar(id, sn, NONE, bulletconstant) \
22         w_cvar(id, sn, NONE, first) \
23         w_cvar(id, sn, NONE, first_damage) \
24         w_cvar(id, sn, NONE, first_force) \
25         w_cvar(id, sn, NONE, first_refire) \
26         w_cvar(id, sn, NONE, first_spread) \
27         w_cvar(id, sn, NONE, first_ammo) \
28         w_cvar(id, sn, NONE, sustained_damage) \
29         w_cvar(id, sn, NONE, sustained_force) \
30         w_cvar(id, sn, NONE, sustained_refire) \
31         w_cvar(id, sn, NONE, sustained_spread) \
32         w_cvar(id, sn, NONE, sustained_ammo) \
33         w_cvar(id, sn, NONE, burst) \
34         w_cvar(id, sn, NONE, burst_refire) \
35         w_cvar(id, sn, NONE, burst_refire2) \
36         w_cvar(id, sn, NONE, burst_animtime) \
37         w_cvar(id, sn, NONE, burst_speed) \
38         w_cvar(id, sn, NONE, burst_ammo) \
39         w_prop(id, sn, float,  reloading_ammo, reload_ammo) \
40         w_prop(id, sn, float,  reloading_time, reload_time) \
41         w_prop(id, sn, float,  switchdelay_raise, switchdelay_raise) \
42         w_prop(id, sn, float,  switchdelay_drop, switchdelay_drop) \
43         w_prop(id, sn, string, weaponreplace, weaponreplace) \
44         w_prop(id, sn, float,  weaponstart, weaponstart) \
45         w_prop(id, sn, float,  weaponstartoverride, weaponstartoverride)
46
47 #ifdef SVQC
48 UZI_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
49 #endif
50 #else
51 #ifdef SVQC
52
53 void spawnfunc_weapon_uzi()
54 {
55         if(autocvar_sv_q3acompat_machineshotgunswap)
56         if(self.classname != "droppedweapon")
57         {
58                 weapon_defaultspawnfunc(WEP_SHOCKWAVE);
59                 return;
60         }
61         weapon_defaultspawnfunc(WEP_UZI);
62 }
63
64 // leilei's fancy muzzleflash stuff
65 void UZI_Flash_Go()
66 {
67         self.frame = self.frame + 2;
68         self.scale = self.scale * 0.5;
69         self.alpha = self.alpha - 0.25;
70         self.nextthink = time + 0.05;
71
72         if (self.alpha <= 0)
73         {
74                 self.think = SUB_Remove;
75                 self.nextthink = time;
76                 self.realowner.muzzle_flash = world;
77                 return;
78         }
79
80 }
81
82 void UziFlash()
83 {
84         if (self.muzzle_flash == world)
85                 self.muzzle_flash = spawn();
86
87         // muzzle flash for 1st person view
88         setmodel(self.muzzle_flash, "models/uziflash.md3"); // precision set below
89
90         self.muzzle_flash.scale = 0.75;
91         self.muzzle_flash.think = UZI_Flash_Go;
92         self.muzzle_flash.nextthink = time + 0.02;
93         self.muzzle_flash.frame = 2;
94         self.muzzle_flash.alpha = 0.75;
95         self.muzzle_flash.angles_z = random() * 180;
96         self.muzzle_flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
97         self.muzzle_flash.owner = self.muzzle_flash.realowner = self;
98 }
99
100 void W_UZI_Attack (float deathtype)
101 {
102         W_SetupShot (self, TRUE, 0, "weapons/uzi_fire.wav", CH_WEAPON_A, ((self.misc_bulletcounter == 1) ? WEP_CVAR(uzi, first_damage) : WEP_CVAR(uzi, sustained_damage)));
103         if (!autocvar_g_norecoil)
104         {
105                 self.punchangle_x = random () - 0.5;
106                 self.punchangle_y = random () - 0.5;
107         }
108
109         // this attack_finished just enforces a cooldown at the end of a burst
110         ATTACK_FINISHED(self) = time + WEP_CVAR(uzi, first_refire) * W_WeaponRateFactor();
111
112         if (self.misc_bulletcounter == 1)
113                 fireBallisticBullet(w_shotorg, w_shotdir, WEP_CVAR(uzi, first_spread), WEP_CVAR(uzi, speed), 5, WEP_CVAR(uzi, first_damage), WEP_CVAR(uzi, first_force), deathtype, 0, WEP_CVAR(uzi, bulletconstant));
114         else
115                 fireBallisticBullet(w_shotorg, w_shotdir, WEP_CVAR(uzi, sustained_spread), WEP_CVAR(uzi, speed), 5, WEP_CVAR(uzi, sustained_damage), WEP_CVAR(uzi, sustained_force), deathtype, 0, WEP_CVAR(uzi, bulletconstant));
116         endFireBallisticBullet();
117
118         pointparticles(particleeffectnum("uzi_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
119
120         UziFlash();
121         W_AttachToShotorg(self.muzzle_flash, '5 0 0');
122
123         // casing code
124         if (autocvar_g_casings >= 2)
125                 SpawnCasing (((random () * 50 + 50) * v_right) - (v_forward * (random () * 25 + 25)) - ((random () * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, self);
126
127         if (self.misc_bulletcounter == 1)
128                 W_DecreaseAmmo(WEP_CVAR(uzi, first_ammo));
129         else
130                 W_DecreaseAmmo(WEP_CVAR(uzi, sustained_ammo));
131 }
132
133 // weapon frames
134 void uzi_fire1_02()
135 {
136         if(self.weapon != self.switchweapon) // abort immediately if switching
137         {
138                 w_ready();
139                 return;
140         }
141         if (self.BUTTON_ATCK)
142         {
143                 if (!WEP_ACTION(self.weapon, WR_CHECKAMMO2))
144                 if (!(self.items & IT_UNLIMITED_WEAPON_AMMO))
145                 {
146                         W_SwitchWeapon_Force(self, w_getbestweapon(self));
147                         w_ready();
148                         return;
149                 }
150                 self.misc_bulletcounter = self.misc_bulletcounter + 1;
151                 W_UZI_Attack(WEP_UZI);
152                 weapon_thinkf(WFRAME_FIRE1, WEP_CVAR(uzi, sustained_refire), uzi_fire1_02);
153         }
154         else
155                 weapon_thinkf(WFRAME_FIRE1, WEP_CVAR(uzi, sustained_refire), w_ready);
156 }
157
158
159 void uzi_mode1_fire_auto()
160 {
161         float uzi_spread;
162
163         if (!self.BUTTON_ATCK)
164         {
165                 w_ready();
166                 return;
167         }
168
169         if (!WEP_ACTION(self.weapon, WR_CHECKAMMO1))
170         if (!(self.items & IT_UNLIMITED_WEAPON_AMMO))
171         {
172                 W_SwitchWeapon_Force(self, w_getbestweapon(self));
173                 w_ready();
174                 return;
175         }
176
177         W_DecreaseAmmo(WEP_CVAR(uzi, sustained_ammo));
178
179         W_SetupShot (self, TRUE, 0, "weapons/uzi_fire.wav", CH_WEAPON_A, WEP_CVAR(uzi, sustained_damage));
180         if (!autocvar_g_norecoil)
181         {
182                 self.punchangle_x = random () - 0.5;
183                 self.punchangle_y = random () - 0.5;
184         }
185
186         uzi_spread = bound(WEP_CVAR(uzi, spread_min), WEP_CVAR(uzi, spread_min) + (WEP_CVAR(uzi, spread_add) * self.misc_bulletcounter), WEP_CVAR(uzi, spread_max));
187         fireBallisticBullet(w_shotorg, w_shotdir, uzi_spread, WEP_CVAR(uzi, speed), 5, WEP_CVAR(uzi, sustained_damage), WEP_CVAR(uzi, sustained_force), WEP_UZI, 0, WEP_CVAR(uzi, bulletconstant));
188         endFireBallisticBullet();
189
190         self.misc_bulletcounter = self.misc_bulletcounter + 1;
191
192         pointparticles(particleeffectnum("uzi_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
193
194         UziFlash();
195         W_AttachToShotorg(self.muzzle_flash, '5 0 0');
196
197         if (autocvar_g_casings >= 2) // casing code
198                 SpawnCasing (((random () * 50 + 50) * v_right) - (v_forward * (random () * 25 + 25)) - ((random () * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, self);
199
200         ATTACK_FINISHED(self) = time + WEP_CVAR(uzi, first_refire) * W_WeaponRateFactor();
201         weapon_thinkf(WFRAME_FIRE1, WEP_CVAR(uzi, sustained_refire), uzi_mode1_fire_auto);
202 }
203
204 void uzi_mode1_fire_burst()
205 {
206         W_SetupShot (self, TRUE, 0, "weapons/uzi_fire.wav", CH_WEAPON_A, WEP_CVAR(uzi, sustained_damage));
207         if (!autocvar_g_norecoil)
208         {
209                 self.punchangle_x = random () - 0.5;
210                 self.punchangle_y = random () - 0.5;
211         }
212
213         fireBallisticBullet(w_shotorg, w_shotdir, WEP_CVAR(uzi, burst_speed), WEP_CVAR(uzi, speed), 5, WEP_CVAR(uzi, sustained_damage), WEP_CVAR(uzi, sustained_force), WEP_UZI, 0, WEP_CVAR(uzi, bulletconstant));
214         endFireBallisticBullet();
215
216
217         pointparticles(particleeffectnum("uzi_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
218
219         UziFlash();
220         W_AttachToShotorg(self.muzzle_flash, '5 0 0');
221
222         if (autocvar_g_casings >= 2) // casing code
223                 SpawnCasing (((random () * 50 + 50) * v_right) - (v_forward * (random () * 25 + 25)) - ((random () * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, self);
224
225         self.misc_bulletcounter = self.misc_bulletcounter + 1;
226         if (self.misc_bulletcounter == 0)
227         {
228                 ATTACK_FINISHED(self) = time + WEP_CVAR(uzi, burst_refire2) * W_WeaponRateFactor();
229                 weapon_thinkf(WFRAME_FIRE2, WEP_CVAR(uzi, burst_animtime), w_ready);
230         }
231         else
232         {
233                 weapon_thinkf(WFRAME_FIRE2, WEP_CVAR(uzi, burst_refire), uzi_mode1_fire_burst);
234         }
235
236 }
237
238 float w_uzi(float req)
239 {
240         float ammo_amount;
241         switch(req)
242         {
243                 case WR_AIM:
244                 {
245                         if(vlen(self.origin-self.enemy.origin) < 3000 - bound(0, skill, 10) * 200)
246                                 self.BUTTON_ATCK = bot_aim(1000000, 0, 0.001, FALSE);
247                         else
248                                 self.BUTTON_ATCK2 = bot_aim(1000000, 0, 0.001, FALSE);
249                         
250                         return TRUE;
251                 }
252                 case WR_THINK:
253                 {
254                         if(autocvar_g_balance_uzi_reload_ammo && self.clip_load < min(max(WEP_CVAR(uzi, sustained_ammo), WEP_CVAR(uzi, first_ammo)), WEP_CVAR(uzi, burst_ammo))) // forced reload
255                                 WEP_ACTION(self.weapon, WR_RELOAD);
256                         else if(WEP_CVAR(uzi, mode) == 1)
257                         {
258                                 if (self.BUTTON_ATCK)
259                                 if (weapon_prepareattack(0, 0))
260                                 {
261                                         self.misc_bulletcounter = 0;
262                                         uzi_mode1_fire_auto();
263                                 }
264
265                                 if(self.BUTTON_ATCK2)
266                                 if(weapon_prepareattack(1, 0))
267                                 {
268                                         if (!WEP_ACTION(self.weapon, WR_CHECKAMMO2))
269                                         if (!(self.items & IT_UNLIMITED_WEAPON_AMMO))
270                                         {
271                                                 W_SwitchWeapon_Force(self, w_getbestweapon(self));
272                                                 w_ready();
273                                                 return FALSE;
274                                         }
275
276                                         W_DecreaseAmmo(WEP_CVAR(uzi, burst_ammo));
277
278                                         self.misc_bulletcounter = WEP_CVAR(uzi, burst) * -1;
279                                         uzi_mode1_fire_burst();
280                                 }
281                         }
282                         else
283                         {
284
285                                 if (self.BUTTON_ATCK)
286                                 if (weapon_prepareattack(0, 0))
287                                 {
288                                         self.misc_bulletcounter = 1;
289                                         W_UZI_Attack(WEP_UZI); // sets attack_finished
290                                         weapon_thinkf(WFRAME_FIRE1, WEP_CVAR(uzi, sustained_refire), uzi_fire1_02);
291                                 }
292
293                                 if (self.BUTTON_ATCK2 && WEP_CVAR(uzi, first))
294                                 if (weapon_prepareattack(1, 0))
295                                 {
296                                         self.misc_bulletcounter = 1;
297                                         W_UZI_Attack(WEP_UZI | HITTYPE_SECONDARY); // sets attack_finished
298                                         weapon_thinkf(WFRAME_FIRE2, WEP_CVAR(uzi, first_refire), w_ready);
299                                 }
300                         }
301                         
302                         return TRUE;
303                 }
304                 case WR_INIT:
305                 {
306                         precache_model ("models/uziflash.md3");
307                         precache_model ("models/weapons/g_uzi.md3");
308                         precache_model ("models/weapons/v_uzi.md3");
309                         precache_model ("models/weapons/h_uzi.iqm");
310                         precache_sound ("weapons/uzi_fire.wav");
311                         UZI_SETTINGS(WEP_SKIPCVAR, WEP_SET_PROP)
312                         return TRUE;
313                 }
314                 case WR_CHECKAMMO1:
315                 {
316                         if(WEP_CVAR(uzi, mode) == 1)
317                                 ammo_amount = self.(self.current_ammo) >= WEP_CVAR(uzi, sustained_ammo);
318                         else
319                                 ammo_amount = self.(self.current_ammo) >= WEP_CVAR(uzi, first_ammo);
320
321                         if(autocvar_g_balance_uzi_reload_ammo)
322                         {
323                                 if(WEP_CVAR(uzi, mode) == 1)
324                                         ammo_amount += self.(weapon_load[WEP_UZI]) >= WEP_CVAR(uzi, sustained_ammo);
325                                 else
326                                         ammo_amount += self.(weapon_load[WEP_UZI]) >= WEP_CVAR(uzi, first_ammo);
327                         }
328                         return ammo_amount;
329                 }
330                 case WR_CHECKAMMO2:
331                 {
332                         if(WEP_CVAR(uzi, mode) == 1)
333                                 ammo_amount = self.(self.current_ammo) >= WEP_CVAR(uzi, burst_ammo);
334                         else
335                                 ammo_amount = self.(self.current_ammo) >= WEP_CVAR(uzi, first_ammo);
336
337                         if(autocvar_g_balance_uzi_reload_ammo)
338                         {
339                                 if(WEP_CVAR(uzi, mode) == 1)
340                                         ammo_amount += self.(weapon_load[WEP_UZI]) >= WEP_CVAR(uzi, burst_ammo);
341                                 else
342                                         ammo_amount += self.(weapon_load[WEP_UZI]) >= WEP_CVAR(uzi, first_ammo);
343                         }
344                         return ammo_amount;
345                 }
346                 case WR_CONFIG:
347                 {
348                         UZI_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS)
349                         return TRUE;
350                 }
351                 case WR_RELOAD:
352                 {
353                         W_Reload(min(max(WEP_CVAR(uzi, sustained_ammo), WEP_CVAR(uzi, first_ammo)), WEP_CVAR(uzi, burst_ammo)), "weapons/reload.wav");
354                         return TRUE;
355                 }
356                 case WR_SUICIDEMESSAGE:
357                 {
358                         return WEAPON_THINKING_WITH_PORTALS;
359                 }
360                 case WR_KILLMESSAGE:
361                 {
362                         if(w_deathtype & HITTYPE_SECONDARY)
363                                 return WEAPON_UZI_MURDER_SNIPE;
364                         else
365                                 return WEAPON_UZI_MURDER_SPRAY;
366                 }
367         }
368         return TRUE;
369 }
370 #endif
371 #ifdef CSQC
372 float w_uzi(float req)
373 {
374         switch(req)
375         {
376                 case WR_IMPACTEFFECT:
377                 {
378                         vector org2;
379                         org2 = w_org + w_backoff * 2;
380                         pointparticles(particleeffectnum("machinegun_impact"), org2, w_backoff * 1000, 1);
381                         if(!w_issilent)
382                                 if(w_random < 0.05)
383                                         sound(self, CH_SHOTS, "weapons/ric1.wav", VOL_BASE, ATTN_NORM);
384                                 else if(w_random < 0.1)
385                                         sound(self, CH_SHOTS, "weapons/ric2.wav", VOL_BASE, ATTN_NORM);
386                                 else if(w_random < 0.2)
387                                         sound(self, CH_SHOTS, "weapons/ric3.wav", VOL_BASE, ATTN_NORM);
388                                         
389                         return TRUE;
390                 }
391                 case WR_INIT:
392                 {
393                         precache_sound("weapons/ric1.wav");
394                         precache_sound("weapons/ric2.wav");
395                         precache_sound("weapons/ric3.wav");
396                         return TRUE;
397                 }
398         }
399         return TRUE;
400 }
401 #endif
402 #endif