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