]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/w_uzi.qc
8681c204cdd5009f9bff4ed89c96d177de7d4e1b
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / w_uzi.qc
1 #ifdef REGISTER_WEAPON
2 REGISTER_WEAPON(UZI, w_uzi, IT_NAILS, 3, WEP_FLAG_NORMAL | WEP_TYPE_HITSCAN, BOT_PICKUP_RATING_MID, "uzi", "uzi", _("Machine Gun"))
3 #else
4 #ifdef SVQC
5
6 .float uzi_load;
7
8 void W_Uzi_SetAmmoCounter()
9 {
10         // set clip_load to the weapon we have switched to, if the gun uses reloading
11         if(!autocvar_g_balance_uzi_reload_ammo)
12                 self.clip_load = 0; // also keeps crosshair ammo from displaying
13         else
14         {
15                 self.clip_load = self.uzi_load;
16                 self.clip_size = autocvar_g_balance_uzi_reload_ammo; // for the crosshair ammo display
17         }
18 }
19
20 void W_Uzi_ReloadedAndReady()
21 {
22         float t;
23
24         // now do the ammo transfer
25         self.clip_load = self.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading
26         while(self.clip_load < autocvar_g_balance_uzi_reload_ammo && self.ammo_nails) // make sure we don't add more ammo than we have
27         {
28                 self.clip_load += 1;
29                 self.ammo_nails -= 1;
30         }
31         self.uzi_load = self.clip_load;
32
33         t = ATTACK_FINISHED(self) - autocvar_g_balance_uzi_reload_time - 1;
34         ATTACK_FINISHED(self) = t;
35         w_ready();
36 }
37
38 void W_Uzi_Reload()
39 {
40         // return if reloading is disabled for this weapon
41         if(!autocvar_g_balance_uzi_reload_ammo)
42                 return;
43
44         if(!W_ReloadCheck(self.ammo_nails))
45                 return;
46
47         float t;
48
49         sound (self, CHAN_WEAPON2, "weapons/reload.wav", VOL_BASE, ATTN_NORM);
50
51         t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_uzi_reload_time + 1;
52         ATTACK_FINISHED(self) = t;
53
54         weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_uzi_reload_time, W_Uzi_ReloadedAndReady);
55
56         self.old_clip_load = self.clip_load;
57         self.clip_load = -1;
58 }
59
60 // leilei's fancy muzzleflash stuff
61 void Uzi_Flash_Go() 
62 {       
63         self.frame = self.frame + 2;
64         self.scale = self.scale * 0.5;
65         self.alpha = self.alpha - 0.25;
66         self.nextthink = time + 0.05;
67
68         if (self.alpha <= 0)
69         {
70                 self.think = SUB_Remove;
71                 self.nextthink = time;
72                 self.owner.muzzle_flash = world;
73                 return;
74         }
75         
76 }
77
78 void UziFlash()
79 {       
80         if (self.muzzle_flash == world)
81                 self.muzzle_flash = spawn();    
82         
83         // muzzle flash for 1st person view
84         setmodel(self.muzzle_flash, "models/uziflash.md3"); // precision set below
85         
86         self.muzzle_flash.scale = 0.75;
87         self.muzzle_flash.think = Uzi_Flash_Go;
88         self.muzzle_flash.nextthink = time + 0.02;
89         self.muzzle_flash.frame = 2;
90         self.muzzle_flash.alpha = 0.75;
91         self.muzzle_flash.angles_z = random() * 180;
92         self.muzzle_flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
93         self.muzzle_flash.owner = self;
94 }
95
96 void W_Uzi_Attack (float deathtype)
97 {
98         if(autocvar_g_balance_uzi_reload_ammo && self.clip_load <= 0)
99                 return; // reloading, so we are done
100
101         W_SetupShot (self, autocvar_g_antilag_bullets && autocvar_g_balance_uzi_speed >= autocvar_g_antilag_bullets, 0, "weapons/uzi_fire.wav", CHAN_WEAPON, ((self.misc_bulletcounter == 1) ? autocvar_g_balance_uzi_first_damage : autocvar_g_balance_uzi_sustained_damage));
102         if (!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 + autocvar_g_balance_uzi_first_refire * W_WeaponRateFactor();
110
111         if (self.misc_bulletcounter == 1)
112                 fireBallisticBullet(w_shotorg, w_shotdir, autocvar_g_balance_uzi_first_spread, autocvar_g_balance_uzi_speed, 5, autocvar_g_balance_uzi_first_damage, 0, autocvar_g_balance_uzi_first_force, deathtype, 0, 1, autocvar_g_balance_uzi_bulletconstant);
113         else
114                 fireBallisticBullet(w_shotorg, w_shotdir, autocvar_g_balance_uzi_sustained_spread, autocvar_g_balance_uzi_speed, 5, autocvar_g_balance_uzi_sustained_damage, 0, autocvar_g_balance_uzi_sustained_force, deathtype, 0, 1, autocvar_g_balance_uzi_bulletconstant);
115         endFireBallisticBullet();
116
117         pointparticles(particleeffectnum("uzi_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
118
119         UziFlash();
120         W_AttachToShotorg(self.muzzle_flash, '5 0 0');
121
122         // casing code
123         if (autocvar_g_casings >= 2)
124                 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);
125 }
126
127 // weapon frames
128 void uzi_fire1_02()
129 {
130         if(self.weapon != self.switchweapon) // abort immediately if switching
131         {
132                 w_ready();
133                 return;
134         }
135         if (self.BUTTON_ATCK)
136         {
137                 if (!weapon_action(self.weapon, WR_CHECKAMMO2))
138                 {
139                         W_SwitchWeapon_Force(self, w_getbestweapon(self));
140                         w_ready();
141                         return;
142                 }
143                 self.misc_bulletcounter = self.misc_bulletcounter + 1;
144                 W_Uzi_Attack(WEP_UZI);
145                 weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_uzi_sustained_refire, uzi_fire1_02);
146         }
147         else
148                 weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_uzi_sustained_refire, w_ready);
149 }
150
151
152 void uzi_mode1_fire_auto()
153 {
154         float uzi_spread;
155         
156         if (self.BUTTON_ATCK)
157                 weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_uzi_sustained_refire, uzi_mode1_fire_auto);
158         else
159         {
160                 ATTACK_FINISHED(self) = time + autocvar_g_balance_uzi_first_refire * W_WeaponRateFactor();
161                 weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_uzi_sustained_refire, w_ready);
162                 return;
163         }
164
165         if (!weapon_action(self.weapon, WR_CHECKAMMO1))
166         {
167                 W_SwitchWeapon_Force(self, w_getbestweapon(self));
168                 w_ready();
169                 return;
170         }
171         
172         W_SetupShot (self, autocvar_g_antilag_bullets && autocvar_g_balance_uzi_speed >= autocvar_g_antilag_bullets, 0, "weapons/uzi_fire.wav", CHAN_WEAPON, autocvar_g_balance_uzi_sustained_damage);
173         if (!g_norecoil)
174         {
175                 self.punchangle_x = random () - 0.5;
176                 self.punchangle_y = random () - 0.5;
177         }
178         
179         uzi_spread = bound(autocvar_g_balance_uzi_spread_min, autocvar_g_balance_uzi_spread_min + (autocvar_g_balance_uzi_spread_add * self.misc_bulletcounter), autocvar_g_balance_uzi_spread_max);
180         fireBallisticBullet(w_shotorg, w_shotdir, uzi_spread, autocvar_g_balance_uzi_speed, 5, autocvar_g_balance_uzi_sustained_damage, 0, autocvar_g_balance_uzi_sustained_force, WEP_UZI, 0, 1, autocvar_g_balance_uzi_bulletconstant);
181         endFireBallisticBullet();
182         
183         self.misc_bulletcounter = self.misc_bulletcounter + 1;
184         
185         pointparticles(particleeffectnum("uzi_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
186
187         UziFlash();
188         W_AttachToShotorg(self.muzzle_flash, '5 0 0');
189         
190         if (autocvar_g_casings >= 2) // casing code
191                 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);
192
193         // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
194         if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
195         {
196                 if(autocvar_g_balance_uzi_reload_ammo)
197                 {
198                         self.clip_load -= autocvar_g_balance_uzi_sustained_ammo;
199                         self.uzi_load = self.clip_load;
200                 }
201                 else
202                         self.ammo_nails -= autocvar_g_balance_uzi_sustained_ammo;
203         }
204 }
205
206 void uzi_mode1_fire_burst()
207 {
208         W_SetupShot (self, autocvar_g_antilag_bullets && autocvar_g_balance_uzi_speed >= autocvar_g_antilag_bullets, 0, "weapons/uzi_fire.wav", CHAN_WEAPON, autocvar_g_balance_uzi_sustained_damage);
209         if (!g_norecoil)
210         {
211                 self.punchangle_x = random () - 0.5;
212                 self.punchangle_y = random () - 0.5;
213         }
214         
215         fireBallisticBullet(w_shotorg, w_shotdir, autocvar_g_balance_uzi_burst_spread, autocvar_g_balance_uzi_speed, 5, autocvar_g_balance_uzi_sustained_damage, 0, autocvar_g_balance_uzi_sustained_force, WEP_UZI, 0, 1, autocvar_g_balance_uzi_bulletconstant);
216         endFireBallisticBullet();
217         
218         
219         pointparticles(particleeffectnum("uzi_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
220
221         UziFlash();
222         W_AttachToShotorg(self.muzzle_flash, '5 0 0');
223         
224         if (autocvar_g_casings >= 2) // casing code
225                 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);
226
227         self.misc_bulletcounter = self.misc_bulletcounter + 1;
228         if (self.misc_bulletcounter == 0)
229         {
230                 ATTACK_FINISHED(self) = time + autocvar_g_balance_uzi_burst_refire2 * W_WeaponRateFactor();
231                 weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_uzi_burst_animtime, w_ready);
232         }
233         else
234         {
235                 weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_uzi_burst_refire, uzi_mode1_fire_burst);
236         }
237                 
238 }
239
240 void spawnfunc_weapon_machinegun(); // defined in t_items.qc
241
242 float w_uzi(float req)
243 {
244         if (req == WR_AIM)
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                 {
249                         self.BUTTON_ATCK2 = bot_aim(1000000, 0, 0.001, FALSE);
250                 }
251         else if (req == WR_THINK)
252         {
253                 if(autocvar_g_balance_uzi_reload_ammo && self.clip_load < min(max(autocvar_g_balance_uzi_sustained_ammo, autocvar_g_balance_uzi_first_ammo), autocvar_g_balance_uzi_burst_ammo)) // forced reload
254                         W_Uzi_Reload();
255                 else if(autocvar_g_balance_uzi_mode == 1)
256                 {
257                         if (self.BUTTON_ATCK)
258                         if (weapon_prepareattack(0, 0))
259                         {                               
260                                 self.misc_bulletcounter = 0;
261                                 uzi_mode1_fire_auto();
262                         }
263                         
264                         if(self.BUTTON_ATCK2)
265                         if(weapon_prepareattack(1, 0))
266                         {
267                                 if (!weapon_action(self.weapon, WR_CHECKAMMO2))
268                                 {
269                                         W_SwitchWeapon_Force(self, w_getbestweapon(self));
270                                         w_ready();
271                                         return FALSE;
272                                 }
273
274                                 // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
275                                 if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
276                                 {
277                                         if(autocvar_g_balance_uzi_reload_ammo)
278                                         {
279                                                 self.clip_load -= autocvar_g_balance_uzi_burst_ammo;
280                                                 self.uzi_load = self.clip_load;
281                                         }
282                                         else
283                                                 self.ammo_nails -= autocvar_g_balance_uzi_burst_ammo;
284                                 }
285
286                                 self.misc_bulletcounter = autocvar_g_balance_uzi_burst * -1;
287                                 uzi_mode1_fire_burst();
288                         }
289                 }
290                 else
291                 {
292                         
293                         if (self.BUTTON_ATCK)
294                         if (weapon_prepareattack(0, 0))
295                         {
296                                 self.misc_bulletcounter = 1;
297                                 W_Uzi_Attack(WEP_UZI); // sets attack_finished
298                                 weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_uzi_sustained_refire, uzi_fire1_02);
299                         }
300
301                         if (self.BUTTON_ATCK2 && autocvar_g_balance_uzi_first)
302                         if (weapon_prepareattack(1, 0))
303                         {
304                                 self.misc_bulletcounter = 1;
305                                 W_Uzi_Attack(WEP_UZI | HITTYPE_SECONDARY); // sets attack_finished
306                                 weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_uzi_first_refire, w_ready);
307                         }
308                 }
309         if(self.wish_reload)
310         {
311             if(self.switchweapon == self.weapon)
312             {
313                 if(self.weaponentity.state == WS_READY)
314                 {
315                     self.wish_reload = 0;
316                     W_Uzi_Reload();
317                 }
318             }
319         }
320         }
321         else if (req == WR_PRECACHE)
322         {
323                 precache_model ("models/uziflash.md3");
324                 precache_model ("models/weapons/g_uzi.md3");
325                 precache_model ("models/weapons/v_uzi.md3");
326                 precache_model ("models/weapons/h_uzi.iqm");
327                 precache_sound ("weapons/uzi_fire.wav");
328         }
329         else if (req == WR_SETUP)
330         {
331                 weapon_setup(WEP_UZI);
332                 W_Uzi_SetAmmoCounter();
333         }
334         else if (req == WR_CHECKAMMO1)
335         {
336                 if(autocvar_g_balance_uzi_mode == 1)
337                         return self.ammo_nails >= autocvar_g_balance_uzi_sustained_ammo;
338                 else
339                         return self.ammo_nails >= autocvar_g_balance_uzi_first_ammo;
340         }
341         else if (req == WR_CHECKAMMO2)
342         {
343                 if(autocvar_g_balance_uzi_mode == 1)
344                         return self.ammo_nails >= autocvar_g_balance_uzi_burst_ammo;
345                 else
346                         return self.ammo_nails >= autocvar_g_balance_uzi_first_ammo;
347         }
348         else if (req == WR_RELOAD)
349         {
350                 W_Uzi_Reload();
351         }
352         return TRUE;
353 };
354 #endif
355 #ifdef CSQC
356 float w_uzi(float req)
357 {
358         if(req == WR_IMPACTEFFECT)
359         {
360                 vector org2;
361                 org2 = w_org + w_backoff * 2;
362                 pointparticles(particleeffectnum("machinegun_impact"), org2, w_backoff * 1000, 1);
363                 if(!w_issilent)
364                         if(w_random < 0.05)
365                                 sound(self, CHAN_PROJECTILE, "weapons/ric1.wav", VOL_BASE, ATTN_NORM);
366                         else if(w_random < 0.1)
367                                 sound(self, CHAN_PROJECTILE, "weapons/ric2.wav", VOL_BASE, ATTN_NORM);
368                         else if(w_random < 0.2)
369                                 sound(self, CHAN_PROJECTILE, "weapons/ric3.wav", VOL_BASE, ATTN_NORM);
370         }
371         else if(req == WR_PRECACHE)
372         {
373                 precache_sound("weapons/ric1.wav");
374                 precache_sound("weapons/ric2.wav");
375                 precache_sound("weapons/ric3.wav");
376         }
377         else if (req == WR_SUICIDEMESSAGE)
378                 w_deathtypestring = "%s did the impossible";
379         else if (req == WR_KILLMESSAGE)
380         {
381                 if(w_deathtype & HITTYPE_SECONDARY)
382                         w_deathtypestring = "%s was sniped by %s";
383                 else
384                         w_deathtypestring = "%s was riddled full of holes by %s";
385         }
386         return TRUE;
387 }
388 #endif
389 #endif