Merge branch 'master' into terencehill/music_player
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / w_uzi.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 /* shortname */ "uzi",
11 /* fullname  */ _("Machine Gun")
12 );
13 #else
14 #ifdef SVQC
15
16 // leilei's fancy muzzleflash stuff
17 void UZI_Flash_Go()
18 {
19         self.frame = self.frame + 2;
20         self.scale = self.scale * 0.5;
21         self.alpha = self.alpha - 0.25;
22         self.nextthink = time + 0.05;
23
24         if (self.alpha <= 0)
25         {
26                 self.think = SUB_Remove;
27                 self.nextthink = time;
28                 self.realowner.muzzle_flash = world;
29                 return;
30         }
31
32 }
33
34 void UziFlash()
35 {
36         if (self.muzzle_flash == world)
37                 self.muzzle_flash = spawn();
38
39         // muzzle flash for 1st person view
40         setmodel(self.muzzle_flash, "models/uziflash.md3"); // precision set below
41
42         self.muzzle_flash.scale = 0.75;
43         self.muzzle_flash.think = UZI_Flash_Go;
44         self.muzzle_flash.nextthink = time + 0.02;
45         self.muzzle_flash.frame = 2;
46         self.muzzle_flash.alpha = 0.75;
47         self.muzzle_flash.angles_z = random() * 180;
48         self.muzzle_flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
49         self.muzzle_flash.owner = self.muzzle_flash.realowner = self;
50 }
51
52 void W_UZI_Attack (float deathtype)
53 {
54         W_SetupShot (self, TRUE, 0, "weapons/uzi_fire.wav", CH_WEAPON_A, ((self.misc_bulletcounter == 1) ? autocvar_g_balance_uzi_first_damage : autocvar_g_balance_uzi_sustained_damage));
55         if (!autocvar_g_norecoil)
56         {
57                 self.punchangle_x = random () - 0.5;
58                 self.punchangle_y = random () - 0.5;
59         }
60
61         // this attack_finished just enforces a cooldown at the end of a burst
62         ATTACK_FINISHED(self) = time + autocvar_g_balance_uzi_first_refire * W_WeaponRateFactor();
63
64         if (self.misc_bulletcounter == 1)
65                 fireBallisticBullet(w_shotorg, w_shotdir, autocvar_g_balance_uzi_first_spread, autocvar_g_balance_uzi_speed, 5, autocvar_g_balance_uzi_first_damage, autocvar_g_balance_uzi_first_force, deathtype, 0, autocvar_g_balance_uzi_bulletconstant);
66         else
67                 fireBallisticBullet(w_shotorg, w_shotdir, autocvar_g_balance_uzi_sustained_spread, autocvar_g_balance_uzi_speed, 5, autocvar_g_balance_uzi_sustained_damage, autocvar_g_balance_uzi_sustained_force, deathtype, 0, autocvar_g_balance_uzi_bulletconstant);
68         endFireBallisticBullet();
69
70         pointparticles(particleeffectnum("uzi_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
71
72         UziFlash();
73         W_AttachToShotorg(self.muzzle_flash, '5 0 0');
74
75         // casing code
76         if (autocvar_g_casings >= 2)
77                 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);
78
79         if (self.misc_bulletcounter == 1)
80                 W_DecreaseAmmo(ammo_nails, autocvar_g_balance_uzi_first_ammo, autocvar_g_balance_uzi_reload_ammo);
81         else
82                 W_DecreaseAmmo(ammo_nails, autocvar_g_balance_uzi_sustained_ammo, autocvar_g_balance_uzi_reload_ammo);
83 }
84
85 // weapon frames
86 void uzi_fire1_02()
87 {
88         if(self.weapon != self.switchweapon) // abort immediately if switching
89         {
90                 w_ready();
91                 return;
92         }
93         if (self.BUTTON_ATCK)
94         {
95                 if (!weapon_action(self.weapon, WR_CHECKAMMO2))
96                 if (!(self.items & IT_UNLIMITED_WEAPON_AMMO))
97                 {
98                         W_SwitchWeapon_Force(self, w_getbestweapon(self));
99                         w_ready();
100                         return;
101                 }
102                 self.misc_bulletcounter = self.misc_bulletcounter + 1;
103                 W_UZI_Attack(WEP_UZI);
104                 weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_uzi_sustained_refire, uzi_fire1_02);
105         }
106         else
107                 weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_uzi_sustained_refire, w_ready);
108 }
109
110
111 void uzi_mode1_fire_auto()
112 {
113         float uzi_spread;
114
115         if (!self.BUTTON_ATCK)
116         {
117                 w_ready();
118                 return;
119         }
120
121         if (!weapon_action(self.weapon, WR_CHECKAMMO1))
122         if (!(self.items & IT_UNLIMITED_WEAPON_AMMO))
123         {
124                 W_SwitchWeapon_Force(self, w_getbestweapon(self));
125                 w_ready();
126                 return;
127         }
128
129         W_DecreaseAmmo(ammo_nails, autocvar_g_balance_uzi_sustained_ammo, autocvar_g_balance_uzi_reload_ammo);
130
131         W_SetupShot (self, TRUE, 0, "weapons/uzi_fire.wav", CH_WEAPON_A, autocvar_g_balance_uzi_sustained_damage);
132         if (!autocvar_g_norecoil)
133         {
134                 self.punchangle_x = random () - 0.5;
135                 self.punchangle_y = random () - 0.5;
136         }
137
138         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);
139         fireBallisticBullet(w_shotorg, w_shotdir, uzi_spread, autocvar_g_balance_uzi_speed, 5, autocvar_g_balance_uzi_sustained_damage, autocvar_g_balance_uzi_sustained_force, WEP_UZI, 0, autocvar_g_balance_uzi_bulletconstant);
140         endFireBallisticBullet();
141
142         self.misc_bulletcounter = self.misc_bulletcounter + 1;
143
144         pointparticles(particleeffectnum("uzi_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
145
146         UziFlash();
147         W_AttachToShotorg(self.muzzle_flash, '5 0 0');
148
149         if (autocvar_g_casings >= 2) // casing code
150                 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);
151
152         ATTACK_FINISHED(self) = time + autocvar_g_balance_uzi_first_refire * W_WeaponRateFactor();
153         weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_uzi_sustained_refire, uzi_mode1_fire_auto);
154 }
155
156 void uzi_mode1_fire_burst()
157 {
158         W_SetupShot (self, TRUE, 0, "weapons/uzi_fire.wav", CH_WEAPON_A, autocvar_g_balance_uzi_sustained_damage);
159         if (!autocvar_g_norecoil)
160         {
161                 self.punchangle_x = random () - 0.5;
162                 self.punchangle_y = random () - 0.5;
163         }
164
165         fireBallisticBullet(w_shotorg, w_shotdir, autocvar_g_balance_uzi_burst_spread, autocvar_g_balance_uzi_speed, 5, autocvar_g_balance_uzi_sustained_damage, autocvar_g_balance_uzi_sustained_force, WEP_UZI, 0, autocvar_g_balance_uzi_bulletconstant);
166         endFireBallisticBullet();
167
168
169         pointparticles(particleeffectnum("uzi_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
170
171         UziFlash();
172         W_AttachToShotorg(self.muzzle_flash, '5 0 0');
173
174         if (autocvar_g_casings >= 2) // casing code
175                 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);
176
177         self.misc_bulletcounter = self.misc_bulletcounter + 1;
178         if (self.misc_bulletcounter == 0)
179         {
180                 ATTACK_FINISHED(self) = time + autocvar_g_balance_uzi_burst_refire2 * W_WeaponRateFactor();
181                 weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_uzi_burst_animtime, w_ready);
182         }
183         else
184         {
185                 weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_uzi_burst_refire, uzi_mode1_fire_burst);
186         }
187
188 }
189
190 void spawnfunc_weapon_machinegun(); // defined in t_items.qc
191
192 float w_uzi(float req)
193 {
194         float ammo_amount;
195         if (req == WR_AIM)
196                 if(vlen(self.origin-self.enemy.origin) < 3000 - bound(0, skill, 10) * 200)
197                         self.BUTTON_ATCK = bot_aim(1000000, 0, 0.001, FALSE);
198                 else
199                 {
200                         self.BUTTON_ATCK2 = bot_aim(1000000, 0, 0.001, FALSE);
201                 }
202         else if (req == WR_THINK)
203         {
204                 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
205                         weapon_action(self.weapon, WR_RELOAD);
206                 else if(autocvar_g_balance_uzi_mode == 1)
207                 {
208                         if (self.BUTTON_ATCK)
209                         if (weapon_prepareattack(0, 0))
210                         {
211                                 self.misc_bulletcounter = 0;
212                                 uzi_mode1_fire_auto();
213                         }
214
215                         if(self.BUTTON_ATCK2)
216                         if(weapon_prepareattack(1, 0))
217                         {
218                                 if (!weapon_action(self.weapon, WR_CHECKAMMO2))
219                                 if (!(self.items & IT_UNLIMITED_WEAPON_AMMO))
220                                 {
221                                         W_SwitchWeapon_Force(self, w_getbestweapon(self));
222                                         w_ready();
223                                         return FALSE;
224                                 }
225
226                                 W_DecreaseAmmo(ammo_nails, autocvar_g_balance_uzi_burst_ammo, autocvar_g_balance_uzi_reload_ammo);
227
228                                 self.misc_bulletcounter = autocvar_g_balance_uzi_burst * -1;
229                                 uzi_mode1_fire_burst();
230                         }
231                 }
232                 else
233                 {
234
235                         if (self.BUTTON_ATCK)
236                         if (weapon_prepareattack(0, 0))
237                         {
238                                 self.misc_bulletcounter = 1;
239                                 W_UZI_Attack(WEP_UZI); // sets attack_finished
240                                 weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_uzi_sustained_refire, uzi_fire1_02);
241                         }
242
243                         if (self.BUTTON_ATCK2 && autocvar_g_balance_uzi_first)
244                         if (weapon_prepareattack(1, 0))
245                         {
246                                 self.misc_bulletcounter = 1;
247                                 W_UZI_Attack(WEP_UZI | HITTYPE_SECONDARY); // sets attack_finished
248                                 weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_uzi_first_refire, w_ready);
249                         }
250                 }
251         }
252         else if (req == WR_PRECACHE)
253         {
254                 precache_model ("models/uziflash.md3");
255                 precache_model ("models/weapons/g_uzi.md3");
256                 precache_model ("models/weapons/v_uzi.md3");
257                 precache_model ("models/weapons/h_uzi.iqm");
258                 precache_sound ("weapons/uzi_fire.wav");
259                 //precache_sound ("weapons/reload.wav"); // until weapons have individual reload sounds, precache the reload sound somewhere else
260         }
261         else if (req == WR_SETUP)
262         {
263                 weapon_setup(WEP_UZI);
264                 self.current_ammo = ammo_nails;
265         }
266         else if (req == WR_CHECKAMMO1)
267         {
268                 if(autocvar_g_balance_uzi_mode == 1)
269                         ammo_amount = self.ammo_nails >= autocvar_g_balance_uzi_sustained_ammo;
270                 else
271                         ammo_amount = self.ammo_nails >= autocvar_g_balance_uzi_first_ammo;
272
273                 if(autocvar_g_balance_uzi_reload_ammo)
274                 {
275                         if(autocvar_g_balance_uzi_mode == 1)
276                                 ammo_amount += self.(weapon_load[WEP_UZI]) >= autocvar_g_balance_uzi_sustained_ammo;
277                         else
278                                 ammo_amount += self.(weapon_load[WEP_UZI]) >= autocvar_g_balance_uzi_first_ammo;
279                 }
280                 return ammo_amount;
281         }
282         else if (req == WR_CHECKAMMO2)
283         {
284                 if(autocvar_g_balance_uzi_mode == 1)
285                         ammo_amount = self.ammo_nails >= autocvar_g_balance_uzi_burst_ammo;
286                 else
287                         ammo_amount = self.ammo_nails >= autocvar_g_balance_uzi_first_ammo;
288
289                 if(autocvar_g_balance_uzi_reload_ammo)
290                 {
291                         if(autocvar_g_balance_uzi_mode == 1)
292                                 ammo_amount += self.(weapon_load[WEP_UZI]) >= autocvar_g_balance_uzi_burst_ammo;
293                         else
294                                 ammo_amount += self.(weapon_load[WEP_UZI]) >= autocvar_g_balance_uzi_first_ammo;
295                 }
296                 return ammo_amount;
297         }
298         else if (req == WR_RELOAD)
299         {
300                 W_Reload(min(max(autocvar_g_balance_uzi_sustained_ammo, autocvar_g_balance_uzi_first_ammo), autocvar_g_balance_uzi_burst_ammo), autocvar_g_balance_uzi_reload_ammo, autocvar_g_balance_uzi_reload_time, "weapons/reload.wav");
301         }
302         else if (req == WR_SUICIDEMESSAGE)
303         {
304                 return WEAPON_THINKING_WITH_PORTALS;
305         }
306         else if (req == WR_KILLMESSAGE)
307         {
308                 if(w_deathtype & HITTYPE_SECONDARY)
309                         return WEAPON_UZI_MURDER_SNIPE;
310                 else
311                         return WEAPON_UZI_MURDER_SPRAY;
312         }
313         return TRUE;
314 }
315 #endif
316 #ifdef CSQC
317 float w_uzi(float req)
318 {
319         if(req == WR_IMPACTEFFECT)
320         {
321                 vector org2;
322                 org2 = w_org + w_backoff * 2;
323                 pointparticles(particleeffectnum("machinegun_impact"), org2, w_backoff * 1000, 1);
324                 if(!w_issilent)
325                         if(w_random < 0.05)
326                                 sound(self, CH_SHOTS, "weapons/ric1.wav", VOL_BASE, ATTEN_NORM);
327                         else if(w_random < 0.1)
328                                 sound(self, CH_SHOTS, "weapons/ric2.wav", VOL_BASE, ATTEN_NORM);
329                         else if(w_random < 0.2)
330                                 sound(self, CH_SHOTS, "weapons/ric3.wav", VOL_BASE, ATTEN_NORM);
331         }
332         else if(req == WR_PRECACHE)
333         {
334                 precache_sound("weapons/ric1.wav");
335                 precache_sound("weapons/ric2.wav");
336                 precache_sound("weapons/ric3.wav");
337         }
338         return TRUE;
339 }
340 #endif
341 #endif