]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/weapons/w_machinegun.qc
No need for that extra prefix
[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_SETUP:
315                 {
316                         self.current_ammo = ammo_nails;
317                         return TRUE;
318                 }
319                 case WR_CHECKAMMO1:
320                 {
321                         if(WEP_CVAR(uzi, mode) == 1)
322                                 ammo_amount = self.ammo_nails >= WEP_CVAR(uzi, sustained_ammo);
323                         else
324                                 ammo_amount = self.ammo_nails >= WEP_CVAR(uzi, first_ammo);
325
326                         if(autocvar_g_balance_uzi_reload_ammo)
327                         {
328                                 if(WEP_CVAR(uzi, mode) == 1)
329                                         ammo_amount += self.(weapon_load[WEP_UZI]) >= WEP_CVAR(uzi, sustained_ammo);
330                                 else
331                                         ammo_amount += self.(weapon_load[WEP_UZI]) >= WEP_CVAR(uzi, first_ammo);
332                         }
333                         return ammo_amount;
334                 }
335                 case WR_CHECKAMMO2:
336                 {
337                         if(WEP_CVAR(uzi, mode) == 1)
338                                 ammo_amount = self.ammo_nails >= WEP_CVAR(uzi, burst_ammo);
339                         else
340                                 ammo_amount = self.ammo_nails >= WEP_CVAR(uzi, first_ammo);
341
342                         if(autocvar_g_balance_uzi_reload_ammo)
343                         {
344                                 if(WEP_CVAR(uzi, mode) == 1)
345                                         ammo_amount += self.(weapon_load[WEP_UZI]) >= WEP_CVAR(uzi, burst_ammo);
346                                 else
347                                         ammo_amount += self.(weapon_load[WEP_UZI]) >= WEP_CVAR(uzi, first_ammo);
348                         }
349                         return ammo_amount;
350                 }
351                 case WR_CONFIG:
352                 {
353                         UZI_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS)
354                         return TRUE;
355                 }
356                 case WR_RELOAD:
357                 {
358                         W_Reload(min(max(WEP_CVAR(uzi, sustained_ammo), WEP_CVAR(uzi, first_ammo)), WEP_CVAR(uzi, burst_ammo)), "weapons/reload.wav");
359                         return TRUE;
360                 }
361                 case WR_SUICIDEMESSAGE:
362                 {
363                         return WEAPON_THINKING_WITH_PORTALS;
364                 }
365                 case WR_KILLMESSAGE:
366                 {
367                         if(w_deathtype & HITTYPE_SECONDARY)
368                                 return WEAPON_UZI_MURDER_SNIPE;
369                         else
370                                 return WEAPON_UZI_MURDER_SPRAY;
371                 }
372         }
373         return TRUE;
374 }
375 #endif
376 #ifdef CSQC
377 float w_uzi(float req)
378 {
379         switch(req)
380         {
381                 case WR_IMPACTEFFECT:
382                 {
383                         vector org2;
384                         org2 = w_org + w_backoff * 2;
385                         pointparticles(particleeffectnum("machinegun_impact"), org2, w_backoff * 1000, 1);
386                         if(!w_issilent)
387                                 if(w_random < 0.05)
388                                         sound(self, CH_SHOTS, "weapons/ric1.wav", VOL_BASE, ATTN_NORM);
389                                 else if(w_random < 0.1)
390                                         sound(self, CH_SHOTS, "weapons/ric2.wav", VOL_BASE, ATTN_NORM);
391                                 else if(w_random < 0.2)
392                                         sound(self, CH_SHOTS, "weapons/ric3.wav", VOL_BASE, ATTN_NORM);
393                                         
394                         return TRUE;
395                 }
396                 case WR_INIT:
397                 {
398                         precache_sound("weapons/ric1.wav");
399                         precache_sound("weapons/ric2.wav");
400                         precache_sound("weapons/ric3.wav");
401                         return TRUE;
402                 }
403         }
404         return TRUE;
405 }
406 #endif
407 #endif