]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/w_uzi.qc
Port reload code over to the UZI
[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         // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
127         if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
128         {
129                 if(autocvar_g_balance_uzi_reload_ammo)
130                 {
131                         if (self.misc_bulletcounter == 1)
132                                 self.clip_load -= autocvar_g_balance_uzi_first_ammo;
133                         else
134                                 self.clip_load -= autocvar_g_balance_uzi_sustained_ammo;
135                         self.uzi_load = self.clip_load;
136                 }
137                 else
138                 {
139                         if (self.misc_bulletcounter == 1)
140                                 self.ammo_nails -= autocvar_g_balance_uzi_first_ammo;
141                         else
142                                 self.ammo_nails -= autocvar_g_balance_uzi_sustained_ammo;
143                 }
144         }
145 }
146
147 // weapon frames
148 void uzi_fire1_02()
149 {
150         if(self.weapon != self.switchweapon) // abort immediately if switching
151         {
152                 w_ready();
153                 return;
154         }
155         if (self.BUTTON_ATCK)
156         {
157                 if (!weapon_action(self.weapon, WR_CHECKAMMO2))
158                 {
159                         W_SwitchWeapon_Force(self, w_getbestweapon(self));
160                         w_ready();
161                         return;
162                 }
163                 self.misc_bulletcounter = self.misc_bulletcounter + 1;
164                 W_Uzi_Attack(WEP_UZI);
165                 weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_uzi_sustained_refire, uzi_fire1_02);
166         }
167         else
168                 weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_uzi_sustained_refire, w_ready);
169 }
170
171
172 void uzi_mode1_fire_auto()
173 {
174         float uzi_spread;
175         
176         if (self.BUTTON_ATCK)
177                 weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_uzi_sustained_refire, uzi_mode1_fire_auto);
178         else
179         {
180                 ATTACK_FINISHED(self) = time + autocvar_g_balance_uzi_first_refire * W_WeaponRateFactor();
181                 weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_uzi_sustained_refire, w_ready);
182                 return;
183         }
184
185         if (!weapon_action(self.weapon, WR_CHECKAMMO1))
186         {
187                 W_SwitchWeapon_Force(self, w_getbestweapon(self));
188                 w_ready();
189                 return;
190         }
191         
192         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);
193         if (!g_norecoil)
194         {
195                 self.punchangle_x = random () - 0.5;
196                 self.punchangle_y = random () - 0.5;
197         }
198         
199         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);
200         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);
201         endFireBallisticBullet();
202         
203         self.misc_bulletcounter = self.misc_bulletcounter + 1;
204         
205         pointparticles(particleeffectnum("uzi_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
206
207         UziFlash();
208         W_AttachToShotorg(self.muzzle_flash, '5 0 0');
209         
210         if (autocvar_g_casings >= 2) // casing code
211                 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);
212
213         // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
214         if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
215         {
216                 if(autocvar_g_balance_uzi_reload_ammo)
217                 {
218                         self.clip_load -= autocvar_g_balance_uzi_sustained_ammo;
219                         self.uzi_load = self.clip_load;
220                 }
221                 else
222                         self.ammo_nails -= autocvar_g_balance_uzi_sustained_ammo;
223         }
224 }
225
226 void uzi_mode1_fire_burst()
227 {
228         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);
229         if (!g_norecoil)
230         {
231                 self.punchangle_x = random () - 0.5;
232                 self.punchangle_y = random () - 0.5;
233         }
234         
235         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);
236         endFireBallisticBullet();
237         
238         
239         pointparticles(particleeffectnum("uzi_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
240
241         UziFlash();
242         W_AttachToShotorg(self.muzzle_flash, '5 0 0');
243         
244         if (autocvar_g_casings >= 2) // casing code
245                 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);
246
247         self.misc_bulletcounter = self.misc_bulletcounter + 1;
248         if (self.misc_bulletcounter == 0)
249         {
250                 ATTACK_FINISHED(self) = time + autocvar_g_balance_uzi_burst_refire2 * W_WeaponRateFactor();
251                 weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_uzi_burst_animtime, w_ready);
252         }
253         else
254         {
255                 weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_uzi_burst_refire, uzi_mode1_fire_burst);
256         }
257                 
258 }
259
260 void spawnfunc_weapon_machinegun(); // defined in t_items.qc
261
262 float w_uzi(float req)
263 {
264         if (req == WR_AIM)
265                 if(vlen(self.origin-self.enemy.origin) < 3000 - bound(0, skill, 10) * 200)
266                         self.BUTTON_ATCK = bot_aim(1000000, 0, 0.001, FALSE);
267                 else
268                 {
269                         self.BUTTON_ATCK2 = bot_aim(1000000, 0, 0.001, FALSE);
270                 }
271         else if (req == WR_THINK)
272         {
273                 if(autocvar_g_balance_uzi_reload_ammo && self.clip_load <= 0) // forced reload
274                         W_Uzi_Reload();
275                 else if(autocvar_g_balance_uzi_mode == 1)
276                 {
277                         if (self.BUTTON_ATCK)
278                         if (weapon_prepareattack(0, 0))
279                         {                               
280                                 self.misc_bulletcounter = 0;
281                                 uzi_mode1_fire_auto();
282                         }
283                         
284                         if(self.BUTTON_ATCK2)
285                         if(weapon_prepareattack(1, 0))
286                         {
287                                 if (!weapon_action(self.weapon, WR_CHECKAMMO2))
288                                 {
289                                         W_SwitchWeapon_Force(self, w_getbestweapon(self));
290                                         w_ready();
291                                         return FALSE;
292                                 }
293
294                                 // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
295                                 if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
296                                 {
297                                         if(autocvar_g_balance_uzi_reload_ammo)
298                                         {
299                                                 self.clip_load -= autocvar_g_balance_uzi_burst_ammo;
300                                                 self.uzi_load = self.clip_load;
301                                         }
302                                         else
303                                                 self.ammo_nails -= autocvar_g_balance_uzi_burst_ammo;
304                                 }
305
306                                 self.misc_bulletcounter = autocvar_g_balance_uzi_burst * -1;
307                                 uzi_mode1_fire_burst();
308                         }
309                 }
310                 else
311                 {
312                         
313                         if (self.BUTTON_ATCK)
314                         if (weapon_prepareattack(0, 0))
315                         {
316                                 self.misc_bulletcounter = 1;
317                                 W_Uzi_Attack(WEP_UZI); // sets attack_finished
318                                 weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_uzi_sustained_refire, uzi_fire1_02);
319                         }
320
321                         if (self.BUTTON_ATCK2 && autocvar_g_balance_uzi_first)
322                         if (weapon_prepareattack(1, 0))
323                         {
324                                 self.misc_bulletcounter = 1;
325                                 W_Uzi_Attack(WEP_UZI | HITTYPE_SECONDARY); // sets attack_finished
326                                 weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_uzi_first_refire, w_ready);
327                         }
328                 }
329         if(self.wish_reload)
330         {
331             if(self.switchweapon == self.weapon)
332             {
333                 if(self.weaponentity.state == WS_READY)
334                 {
335                     self.wish_reload = 0;
336                     W_Uzi_Reload();
337                 }
338             }
339         }
340         }
341         else if (req == WR_PRECACHE)
342         {
343                 precache_model ("models/uziflash.md3");
344                 precache_model ("models/weapons/g_uzi.md3");
345                 precache_model ("models/weapons/v_uzi.md3");
346                 precache_model ("models/weapons/h_uzi.iqm");
347                 precache_sound ("weapons/uzi_fire.wav");
348         }
349         else if (req == WR_SETUP)
350         {
351                 weapon_setup(WEP_UZI);
352                 W_Uzi_SetAmmoCounter();
353         }
354         else if (req == WR_CHECKAMMO1)
355         {
356                 if(autocvar_g_balance_uzi_mode == 1)
357                         return self.ammo_nails >= autocvar_g_balance_uzi_sustained_ammo;
358                 else
359                         return self.ammo_nails >= autocvar_g_balance_uzi_first_ammo;
360         }
361         else if (req == WR_CHECKAMMO2)
362         {
363                 if(autocvar_g_balance_uzi_mode == 1)
364                         return self.ammo_nails >= autocvar_g_balance_uzi_burst_ammo;
365                 else
366                         return self.ammo_nails >= autocvar_g_balance_uzi_first_ammo;
367         }
368         else if (req == WR_RELOAD)
369         {
370                 W_Uzi_Reload();
371         }
372         return TRUE;
373 };
374 #endif
375 #ifdef CSQC
376 float w_uzi(float req)
377 {
378         if(req == WR_IMPACTEFFECT)
379         {
380                 vector org2;
381                 org2 = w_org + w_backoff * 2;
382                 pointparticles(particleeffectnum("machinegun_impact"), org2, w_backoff * 1000, 1);
383                 if(!w_issilent)
384                         if(w_random < 0.05)
385                                 sound(self, CHAN_PROJECTILE, "weapons/ric1.wav", VOL_BASE, ATTN_NORM);
386                         else if(w_random < 0.1)
387                                 sound(self, CHAN_PROJECTILE, "weapons/ric2.wav", VOL_BASE, ATTN_NORM);
388                         else if(w_random < 0.2)
389                                 sound(self, CHAN_PROJECTILE, "weapons/ric3.wav", VOL_BASE, ATTN_NORM);
390         }
391         else if(req == WR_PRECACHE)
392         {
393                 precache_sound("weapons/ric1.wav");
394                 precache_sound("weapons/ric2.wav");
395                 precache_sound("weapons/ric3.wav");
396         }
397         else if (req == WR_SUICIDEMESSAGE)
398                 w_deathtypestring = "%s did the impossible";
399         else if (req == WR_KILLMESSAGE)
400         {
401                 if(w_deathtype & HITTYPE_SECONDARY)
402                         w_deathtypestring = "%s was sniped by %s";
403                 else
404                         w_deathtypestring = "%s was riddled full of holes by %s";
405         }
406         return TRUE;
407 }
408 #endif
409 #endif