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