]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/weapons/w_machinegun.qc
Add the properties to all weapons now
[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 */ IT_NAILS,
6 /* impulse  */ 3,
7 /* flags    */ WEP_FLAG_NORMAL | 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) \
15         w_cvar(WEP_UZI, uzi, MO_NONE, speed) \
16         w_cvar(WEP_UZI, uzi, MO_NONE, spread_min) \
17         w_cvar(WEP_UZI, uzi, MO_NONE, spread_max) \
18         w_cvar(WEP_UZI, uzi, MO_NONE, spread_add) \
19         w_cvar(WEP_UZI, uzi, MO_NONE, mode) \
20         w_cvar(WEP_UZI, uzi, MO_NONE, bulletconstant) \
21         w_cvar(WEP_UZI, uzi, MO_NONE, first) \
22         w_cvar(WEP_UZI, uzi, MO_NONE, first_damage) \
23         w_cvar(WEP_UZI, uzi, MO_NONE, first_force) \
24         w_cvar(WEP_UZI, uzi, MO_NONE, first_refire) \
25         w_cvar(WEP_UZI, uzi, MO_NONE, first_spread) \
26         w_cvar(WEP_UZI, uzi, MO_NONE, first_ammo) \
27         w_cvar(WEP_UZI, uzi, MO_NONE, sustained_damage) \
28         w_cvar(WEP_UZI, uzi, MO_NONE, sustained_force) \
29         w_cvar(WEP_UZI, uzi, MO_NONE, sustained_refire) \
30         w_cvar(WEP_UZI, uzi, MO_NONE, sustained_spread) \
31         w_cvar(WEP_UZI, uzi, MO_NONE, sustained_ammo) \
32         w_cvar(WEP_UZI, uzi, MO_NONE, burst) \
33         w_cvar(WEP_UZI, uzi, MO_NONE, burst_refire) \
34         w_cvar(WEP_UZI, uzi, MO_NONE, burst_refire2) \
35         w_cvar(WEP_UZI, uzi, MO_NONE, burst_animtime) \
36         w_cvar(WEP_UZI, uzi, MO_NONE, burst_speed) \
37         w_cvar(WEP_UZI, uzi, MO_NONE, burst_ammo) \
38         w_prop(WEP_UZI, uzi, float,  reloading_ammo, reload_ammo) \
39         w_prop(WEP_UZI, uzi, float,  reloading_time, reload_time) \
40         w_prop(WEP_UZI, uzi, float,  switchdelay_raise, switchdelay_raise) \
41         w_prop(WEP_UZI, uzi, float,  switchdelay_drop, switchdelay_drop) \
42         w_prop(WEP_UZI, uzi, string, weaponreplace, weaponreplace) \
43         w_prop(WEP_UZI, uzi, float,  weaponstart, weaponstart)
44
45 #ifdef SVQC
46 UZI_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
47 #endif
48 #else
49 #ifdef SVQC
50
51 void spawnfunc_weapon_uzi()
52 {
53         if(autocvar_sv_q3acompat_machineshotgunswap)
54         if(self.classname != "droppedweapon")
55         {
56                 weapon_defaultspawnfunc(WEP_SHOCKWAVE);
57                 return;
58         }
59         weapon_defaultspawnfunc(WEP_UZI);
60 }
61
62 // leilei's fancy muzzleflash stuff
63 void UZI_Flash_Go()
64 {
65         self.frame = self.frame + 2;
66         self.scale = self.scale * 0.5;
67         self.alpha = self.alpha - 0.25;
68         self.nextthink = time + 0.05;
69
70         if (self.alpha <= 0)
71         {
72                 self.think = SUB_Remove;
73                 self.nextthink = time;
74                 self.realowner.muzzle_flash = world;
75                 return;
76         }
77
78 }
79
80 void UziFlash()
81 {
82         if (self.muzzle_flash == world)
83                 self.muzzle_flash = spawn();
84
85         // muzzle flash for 1st person view
86         setmodel(self.muzzle_flash, "models/uziflash.md3"); // precision set below
87
88         self.muzzle_flash.scale = 0.75;
89         self.muzzle_flash.think = UZI_Flash_Go;
90         self.muzzle_flash.nextthink = time + 0.02;
91         self.muzzle_flash.frame = 2;
92         self.muzzle_flash.alpha = 0.75;
93         self.muzzle_flash.angles_z = random() * 180;
94         self.muzzle_flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
95         self.muzzle_flash.owner = self.muzzle_flash.realowner = self;
96 }
97
98 void W_UZI_Attack (float deathtype)
99 {
100         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)));
101         if (!autocvar_g_norecoil)
102         {
103                 self.punchangle_x = random () - 0.5;
104                 self.punchangle_y = random () - 0.5;
105         }
106
107         // this attack_finished just enforces a cooldown at the end of a burst
108         ATTACK_FINISHED(self) = time + WEP_CVAR(uzi, first_refire) * W_WeaponRateFactor();
109
110         if (self.misc_bulletcounter == 1)
111                 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));
112         else
113                 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));
114         endFireBallisticBullet();
115
116         pointparticles(particleeffectnum("uzi_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
117
118         UziFlash();
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(ammo_nails, WEP_CVAR(uzi, first_ammo), autocvar_g_balance_uzi_reload_ammo);
127         else
128                 W_DecreaseAmmo(ammo_nails, WEP_CVAR(uzi, sustained_ammo), autocvar_g_balance_uzi_reload_ammo);
129 }
130
131 // weapon frames
132 void uzi_fire1_02()
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), uzi_fire1_02);
151         }
152         else
153                 weapon_thinkf(WFRAME_FIRE1, WEP_CVAR(uzi, sustained_refire), w_ready);
154 }
155
156
157 void uzi_mode1_fire_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(ammo_nails, WEP_CVAR(uzi, sustained_ammo), autocvar_g_balance_uzi_reload_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         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));
186         endFireBallisticBullet();
187
188         self.misc_bulletcounter = self.misc_bulletcounter + 1;
189
190         pointparticles(particleeffectnum("uzi_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
191
192         UziFlash();
193         W_AttachToShotorg(self.muzzle_flash, '5 0 0');
194
195         if (autocvar_g_casings >= 2) // casing code
196                 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);
197
198         ATTACK_FINISHED(self) = time + WEP_CVAR(uzi, first_refire) * W_WeaponRateFactor();
199         weapon_thinkf(WFRAME_FIRE1, WEP_CVAR(uzi, sustained_refire), uzi_mode1_fire_auto);
200 }
201
202 void uzi_mode1_fire_burst()
203 {
204         W_SetupShot (self, TRUE, 0, "weapons/uzi_fire.wav", CH_WEAPON_A, WEP_CVAR(uzi, sustained_damage));
205         if (!autocvar_g_norecoil)
206         {
207                 self.punchangle_x = random () - 0.5;
208                 self.punchangle_y = random () - 0.5;
209         }
210
211         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));
212         endFireBallisticBullet();
213
214
215         pointparticles(particleeffectnum("uzi_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
216
217         UziFlash();
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(uzi, burst_refire2) * W_WeaponRateFactor();
227                 weapon_thinkf(WFRAME_FIRE2, WEP_CVAR(uzi, burst_animtime), w_ready);
228         }
229         else
230         {
231                 weapon_thinkf(WFRAME_FIRE2, WEP_CVAR(uzi, burst_refire), uzi_mode1_fire_burst);
232         }
233
234 }
235
236 float w_uzi(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(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
253                                 WEP_ACTION(self.weapon, WR_RELOAD);
254                         else if(WEP_CVAR(uzi, mode) == 1)
255                         {
256                                 if (self.BUTTON_ATCK)
257                                 if (weapon_prepareattack(0, 0))
258                                 {
259                                         self.misc_bulletcounter = 0;
260                                         uzi_mode1_fire_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(ammo_nails, WEP_CVAR(uzi, burst_ammo), autocvar_g_balance_uzi_reload_ammo);
275
276                                         self.misc_bulletcounter = WEP_CVAR(uzi, burst) * -1;
277                                         uzi_mode1_fire_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_UZI_Attack(WEP_UZI); // sets attack_finished
288                                         weapon_thinkf(WFRAME_FIRE1, WEP_CVAR(uzi, sustained_refire), uzi_fire1_02);
289                                 }
290
291                                 if (self.BUTTON_ATCK2 && WEP_CVAR(uzi, first))
292                                 if (weapon_prepareattack(1, 0))
293                                 {
294                                         self.misc_bulletcounter = 1;
295                                         W_UZI_Attack(WEP_UZI | HITTYPE_SECONDARY); // sets attack_finished
296                                         weapon_thinkf(WFRAME_FIRE2, WEP_CVAR(uzi, 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                         UZI_SETTINGS(WEP_SKIPCVAR, WEP_SET_PROP)
310                         return TRUE;
311                 }
312                 case WR_SETUP:
313                 {
314                         self.current_ammo = ammo_nails;
315                         return TRUE;
316                 }
317                 case WR_CHECKAMMO1:
318                 {
319                         if(WEP_CVAR(uzi, mode) == 1)
320                                 ammo_amount = self.ammo_nails >= WEP_CVAR(uzi, sustained_ammo);
321                         else
322                                 ammo_amount = self.ammo_nails >= WEP_CVAR(uzi, first_ammo);
323
324                         if(autocvar_g_balance_uzi_reload_ammo)
325                         {
326                                 if(WEP_CVAR(uzi, mode) == 1)
327                                         ammo_amount += self.(weapon_load[WEP_UZI]) >= WEP_CVAR(uzi, sustained_ammo);
328                                 else
329                                         ammo_amount += self.(weapon_load[WEP_UZI]) >= WEP_CVAR(uzi, first_ammo);
330                         }
331                         return ammo_amount;
332                 }
333                 case WR_CHECKAMMO2:
334                 {
335                         if(WEP_CVAR(uzi, mode) == 1)
336                                 ammo_amount = self.ammo_nails >= WEP_CVAR(uzi, burst_ammo);
337                         else
338                                 ammo_amount = self.ammo_nails >= WEP_CVAR(uzi, first_ammo);
339
340                         if(autocvar_g_balance_uzi_reload_ammo)
341                         {
342                                 if(WEP_CVAR(uzi, mode) == 1)
343                                         ammo_amount += self.(weapon_load[WEP_UZI]) >= WEP_CVAR(uzi, burst_ammo);
344                                 else
345                                         ammo_amount += self.(weapon_load[WEP_UZI]) >= WEP_CVAR(uzi, first_ammo);
346                         }
347                         return ammo_amount;
348                 }
349                 case WR_CONFIG:
350                 {
351                         UZI_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS)
352                         return TRUE;
353                 }
354                 case WR_RELOAD:
355                 {
356                         W_Reload(min(max(WEP_CVAR(uzi, sustained_ammo), WEP_CVAR(uzi, first_ammo)), WEP_CVAR(uzi, burst_ammo)), "weapons/reload.wav");
357                         return TRUE;
358                 }
359                 case WR_SUICIDEMESSAGE:
360                 {
361                         return WEAPON_THINKING_WITH_PORTALS;
362                 }
363                 case WR_KILLMESSAGE:
364                 {
365                         if(w_deathtype & HITTYPE_SECONDARY)
366                                 return WEAPON_UZI_MURDER_SNIPE;
367                         else
368                                 return WEAPON_UZI_MURDER_SPRAY;
369                 }
370         }
371         return TRUE;
372 }
373 #endif
374 #ifdef CSQC
375 float w_uzi(float req)
376 {
377         switch(req)
378         {
379                 case WR_IMPACTEFFECT:
380                 {
381                         vector org2;
382                         org2 = w_org + w_backoff * 2;
383                         pointparticles(particleeffectnum("machinegun_impact"), org2, w_backoff * 1000, 1);
384                         if(!w_issilent)
385                                 if(w_random < 0.05)
386                                         sound(self, CH_SHOTS, "weapons/ric1.wav", VOL_BASE, ATTN_NORM);
387                                 else if(w_random < 0.1)
388                                         sound(self, CH_SHOTS, "weapons/ric2.wav", VOL_BASE, ATTN_NORM);
389                                 else if(w_random < 0.2)
390                                         sound(self, CH_SHOTS, "weapons/ric3.wav", VOL_BASE, ATTN_NORM);
391                                         
392                         return TRUE;
393                 }
394                 case WR_INIT:
395                 {
396                         precache_sound("weapons/ric1.wav");
397                         precache_sound("weapons/ric2.wav");
398                         precache_sound("weapons/ric3.wav");
399                         return TRUE;
400                 }
401         }
402         return TRUE;
403 }
404 #endif
405 #endif