]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/mutators/mutator/overkill/okmachinegun.qc
Added weapon code
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / mutators / mutator / overkill / okmachinegun.qc
1 #include "okmachinegun.qh"
2
3 #ifdef SVQC
4
5 spawnfunc(weapon_okmachinegun)
6 {
7         if(autocvar_sv_q3acompat_machineshotgunswap)
8         if(this.classname != "droppedweapon")
9         {
10                 weapon_defaultspawnfunc(this, WEP_SHOCKWAVE);
11                 return;
12         }
13         weapon_defaultspawnfunc(this, WEP_OVERKILL_MACHINEGUN);
14 }
15
16 void W_OverkillMachineGun_MuzzleFlash_Think(entity this)
17 {
18         this.frame += 2;
19         this.scale *= 0.5;
20         this.alpha -= 0.25;
21         this.nextthink = time + 0.05;
22
23         if(this.alpha <= 0)
24         {
25                 setthink(this, SUB_Remove);
26                 this.nextthink = time;
27                 this.realowner.muzzle_flash = NULL;
28                 return;
29         }
30
31 }
32
33 void W_OverkillMachineGun_MuzzleFlash(entity actor, .entity weaponentity)
34 {
35         entity wepent = actor.(weaponentity);
36
37         if(wepent.muzzle_flash == NULL)
38                 wepent.muzzle_flash = spawn();
39
40         // muzzle flash for 1st person view
41         setmodel(wepent.muzzle_flash, MDL_MACHINEGUN_MUZZLEFLASH); // precision set below
42
43         wepent.muzzle_flash.scale = 0.75;
44         setthink(wepent.muzzle_flash, W_OverkillMachineGun_MuzzleFlash_Think);
45         wepent.muzzle_flash.nextthink = time + 0.02;
46         wepent.muzzle_flash.frame = 2;
47         wepent.muzzle_flash.alpha = 0.75;
48         wepent.muzzle_flash.angles_z = random() * 180;
49         wepent.muzzle_flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
50         wepent.muzzle_flash.owner = wepent.muzzle_flash.realowner = wepent;
51 }
52
53 void W_OverkillMachineGun_Attack(Weapon thiswep, int deathtype, entity actor, .entity weaponentity)
54 {
55         W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, ((actor.(weaponentity).misc_bulletcounter == 1) ? WEP_CVAR(okmachinegun, first_damage) : WEP_CVAR(okmachinegun, sustained_damage)));
56         if(!autocvar_g_norecoil)
57         {
58                 actor.punchangle_x = random() - 0.5;
59                 actor.punchangle_y = random() - 0.5;
60         }
61         int slot = weaponslot(weaponentity);
62         // this attack_finished just enforces a cooldown at the end of a burst
63         ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(okmachinegun, first_refire) * W_WeaponRateFactor(actor);
64
65         if(actor.(weaponentity).misc_bulletcounter == 1)
66                 fireBullet(actor, weaponentity, w_shotorg, w_shotdir, WEP_CVAR(okmachinegun, first_spread), WEP_CVAR(okmachinegun, solidpenetration), WEP_CVAR(okmachinegun, first_damage), WEP_CVAR(okmachinegun, first_force), deathtype, 0);
67         else
68                 fireBullet(actor, weaponentity, w_shotorg, w_shotdir, WEP_CVAR(okmachinegun, sustained_spread), WEP_CVAR(okmachinegun, solidpenetration), WEP_CVAR(okmachinegun, sustained_damage), WEP_CVAR(okmachinegun, sustained_force), deathtype, 0);
69
70         Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
71
72         W_OverkillMachineGun_MuzzleFlash(actor, weaponentity);
73         W_AttachToShotorg(actor, weaponentity, actor.(weaponentity).muzzle_flash, '5 0 0');
74
75         // casing code
76         if(autocvar_g_casings >= 2)
77         {
78                 makevectors(actor.v_angle); // for some reason, this is lost
79                 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, actor, weaponentity);
80         }
81
82         if(actor.(weaponentity).misc_bulletcounter == 1)
83                 W_DecreaseAmmo(thiswep, actor, WEP_CVAR(okmachinegun, first_ammo), weaponentity);
84         else
85                 W_DecreaseAmmo(thiswep, actor, WEP_CVAR(okmachinegun, sustained_ammo), weaponentity);
86 }
87
88 // weapon frames
89 void W_OverkillMachineGun_Attack_Frame(Weapon thiswep, entity actor, .entity weaponentity, int fire)
90 {
91         if(actor.(weaponentity).m_weapon != actor.(weaponentity).m_switchweapon) // abort immediately if switching
92         {
93                 w_ready(thiswep, actor, weaponentity, fire);
94                 return;
95         }
96         if(PHYS_INPUT_BUTTON_ATCK(actor))
97         {
98                 if(!thiswep.wr_checkammo2(thiswep, actor, weaponentity))
99                 if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
100                 {
101                         W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity);
102                         w_ready(thiswep, actor, weaponentity, fire);
103                         return;
104                 }
105                 actor.(weaponentity).misc_bulletcounter = actor.(weaponentity).misc_bulletcounter + 1;
106                 W_OverkillMachineGun_Attack(WEP_OVERKILL_MACHINEGUN, WEP_OVERKILL_MACHINEGUN.m_id, actor, weaponentity);
107                 weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(okmachinegun, sustained_refire), W_OverkillMachineGun_Attack_Frame);
108         }
109         else
110                 weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(okmachinegun, sustained_refire), w_ready);
111 }
112
113 void W_OverkillMachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity, int fire)
114 {
115         float okmachinegun_spread;
116
117         if(!(fire & 1))
118         {
119                 w_ready(thiswep, actor, weaponentity, fire);
120                 return;
121         }
122
123         if(!thiswep.wr_checkammo1(thiswep, actor, weaponentity))
124         if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
125         {
126                 W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity);
127                 w_ready(thiswep, actor, weaponentity, fire);
128                 return;
129         }
130
131         W_DecreaseAmmo(WEP_OVERKILL_MACHINEGUN, actor, WEP_CVAR(okmachinegun, sustained_ammo), weaponentity);
132
133         W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, WEP_CVAR(okmachinegun, sustained_damage));
134         if(!autocvar_g_norecoil)
135         {
136                 actor.punchangle_x = random() - 0.5;
137                 actor.punchangle_y = random() - 0.5;
138         }
139
140         okmachinegun_spread = bound(WEP_CVAR(okmachinegun, spread_min), WEP_CVAR(okmachinegun, spread_min) + (WEP_CVAR(okmachinegun, spread_add) * actor.(weaponentity).misc_bulletcounter), WEP_CVAR(okmachinegun, spread_max));
141         fireBullet(actor, weaponentity, w_shotorg, w_shotdir, okmachinegun_spread, WEP_CVAR(okmachinegun, solidpenetration), WEP_CVAR(okmachinegun, sustained_damage), WEP_CVAR(okmachinegun, sustained_force), WEP_OVERKILL_MACHINEGUN.m_id, 0);
142
143         actor.(weaponentity).misc_bulletcounter = actor.(weaponentity).misc_bulletcounter + 1;
144
145         Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
146
147         W_OverkillMachineGun_MuzzleFlash(actor, weaponentity);
148         W_AttachToShotorg(actor, weaponentity, actor.(weaponentity).muzzle_flash, '5 0 0');
149
150         if(autocvar_g_casings >= 2) // casing code
151         {
152                 makevectors(actor.v_angle); // for some reason, this is lost
153                 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, actor, weaponentity);
154         }
155
156         int slot = weaponslot(weaponentity);
157         ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(okmachinegun, first_refire) * W_WeaponRateFactor(actor);
158         weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(okmachinegun, sustained_refire), W_OverkillMachineGun_Attack_Auto);
159 }
160
161 void W_OverkillMachineGun_Attack_Burst(Weapon thiswep, entity actor, .entity weaponentity, int fire)
162 {
163         W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, WEP_CVAR(okmachinegun, sustained_damage));
164         if(!autocvar_g_norecoil)
165         {
166                 actor.punchangle_x = random() - 0.5;
167                 actor.punchangle_y = random() - 0.5;
168         }
169
170         fireBullet(actor, weaponentity, w_shotorg, w_shotdir, WEP_CVAR(okmachinegun, burst_speed), WEP_CVAR(okmachinegun, solidpenetration), WEP_CVAR(okmachinegun, sustained_damage), WEP_CVAR(okmachinegun, sustained_force), WEP_OVERKILL_MACHINEGUN.m_id, 0);
171
172         Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
173
174         W_OverkillMachineGun_MuzzleFlash(actor, weaponentity);
175         W_AttachToShotorg(actor, weaponentity, actor.(weaponentity).muzzle_flash, '5 0 0');
176
177         if(autocvar_g_casings >= 2) // casing code
178         {
179                 makevectors(actor.v_angle); // for some reason, this is lost
180                 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, actor, weaponentity);
181         }
182
183         actor.(weaponentity).misc_bulletcounter = actor.(weaponentity).misc_bulletcounter + 1;
184         if(actor.(weaponentity).misc_bulletcounter == 0)
185         {
186                 int slot = weaponslot(weaponentity);
187                 ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(okmachinegun, burst_refire2) * W_WeaponRateFactor(actor);
188                 weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(okmachinegun, burst_animtime), w_ready);
189         }
190         else
191         {
192                 weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(okmachinegun, burst_refire), W_OverkillMachineGun_Attack_Burst);
193         }
194
195 }
196
197 METHOD(OverkillMachineGun, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
198 {
199         if(vdist(actor.origin - actor.enemy.origin, <, 3000 - bound(0, skill, 10) * 200))
200                 PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
201         else
202                 PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
203 }
204
205 METHOD(OverkillMachineGun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
206 {
207         if (WEP_CVAR(okmachinegun, reload_ammo) && actor.(weaponentity).clip_load < min(max(WEP_CVAR(okmachinegun, sustained_ammo), WEP_CVAR(okmachinegun, first_ammo)), WEP_CVAR(okmachinegun, burst_ammo)))
208         { // forced reload
209                 thiswep.wr_reload(thiswep, actor, weaponentity);
210         }
211         else if (WEP_CVAR(okmachinegun, mode) == 1)
212         {
213                 if(fire & 1)
214                 if(weapon_prepareattack(thiswep, actor, weaponentity, false, 0))
215                 {
216                         actor.(weaponentity).misc_bulletcounter = 0;
217                         W_OverkillMachineGun_Attack_Auto(thiswep, actor, weaponentity, fire);
218                 }
219
220                 if (fire & 2)
221                 {
222                         if (WEP_CVAR_SEC(okmachinegun, type) == 1)
223                         {
224                                 if (weapon_prepareattack(thiswep, actor, weaponentity, true, 0))
225                                 {
226                                         if (!thiswep.wr_checkammo2(thiswep, actor, weaponentity))
227                                         if (!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
228                                         {
229                                                 W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity);
230                                                 w_ready(thiswep, actor, weaponentity, fire);
231                                                 return;
232                                         }
233
234                                         W_DecreaseAmmo(thiswep, actor, WEP_CVAR(okmachinegun, burst_ammo), weaponentity);
235
236                                         actor.(weaponentity).misc_bulletcounter = WEP_CVAR(okmachinegun, burst) * -1;
237                                         W_OverkillMachineGun_Attack_Burst(thiswep, actor, weaponentity, fire);
238                                 }
239                         }
240                         else
241                         {
242                                 if (!weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_SEC(okmachinegun, refire)))
243                                 {
244                                         return;
245                                 }
246                                 // ugly instagib hack to reuse the fire mode of the laser
247                                 makevectors(actor.v_angle);
248                                 Weapon oldwep = actor.(weaponentity).m_weapon; // we can't avoid this hack
249                                 actor.(weaponentity).m_weapon = WEP_BLASTER;
250                                 W_Blaster_Attack(
251                                         actor,
252                                         weaponentity,
253                                         WEP_BLASTER.m_id | HITTYPE_SECONDARY,
254                                         WEP_CVAR_SEC(okmachinegun, shotangle),
255                                         WEP_CVAR_SEC(okmachinegun, damage),
256                                         WEP_CVAR_SEC(okmachinegun, edgedamage),
257                                         WEP_CVAR_SEC(okmachinegun, radius),
258                                         WEP_CVAR_SEC(okmachinegun, force),
259                                         WEP_CVAR_SEC(okmachinegun, speed),
260                                         WEP_CVAR_SEC(okmachinegun, spread),
261                                         WEP_CVAR_SEC(okmachinegun, delay),
262                                         WEP_CVAR_SEC(okmachinegun, lifetime)
263                                 );
264                                 actor.(weaponentity).m_weapon = oldwep;
265                                 weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(okmachinegun, animtime), w_ready);
266                         }
267                 }
268         }
269         else
270         {
271                 if(fire & 1)
272                 if(weapon_prepareattack(thiswep, actor, weaponentity, false, 0))
273                 {
274                         actor.(weaponentity).misc_bulletcounter = 1;
275                         W_OverkillMachineGun_Attack(WEP_OVERKILL_MACHINEGUN, WEP_OVERKILL_MACHINEGUN.m_id, actor, weaponentity); // sets attack_finished
276                         weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(okmachinegun, sustained_refire), W_OverkillMachineGun_Attack_Frame);
277                 }
278
279                 if (fire & 2)
280                 {
281                         if (WEP_CVAR_SEC(okmachinegun, type) == 1)
282                         {
283                                 if (WEP_CVAR(okmachinegun, first))
284                                 {
285                                         if (weapon_prepareattack(thiswep, actor, weaponentity, true, 0))
286                                         {
287                                                 actor.(weaponentity).misc_bulletcounter = 1;
288                                                 W_OverkillMachineGun_Attack(WEP_OVERKILL_MACHINEGUN, WEP_OVERKILL_MACHINEGUN.m_id | HITTYPE_SECONDARY, actor, weaponentity); // sets attack_finished
289                                                 weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(okmachinegun, first_refire), w_ready);
290                                         }
291                                 }
292                         }
293                         else
294                         {
295                                 if (!weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_SEC(okmachinegun, refire)))
296                                 {
297                                         return;
298                                 }
299                                 // ugly instagib hack to reuse the fire mode of the laser
300                                 makevectors(actor.v_angle);
301                                 Weapon oldwep = actor.(weaponentity).m_weapon; // we can't avoid this hack
302                                 actor.(weaponentity).m_weapon = WEP_BLASTER;
303                                 W_Blaster_Attack(
304                                         actor,
305                                         weaponentity,
306                                         WEP_BLASTER.m_id | HITTYPE_SECONDARY,
307                                         WEP_CVAR_SEC(okmachinegun, shotangle),
308                                         WEP_CVAR_SEC(okmachinegun, damage),
309                                         WEP_CVAR_SEC(okmachinegun, edgedamage),
310                                         WEP_CVAR_SEC(okmachinegun, radius),
311                                         WEP_CVAR_SEC(okmachinegun, force),
312                                         WEP_CVAR_SEC(okmachinegun, speed),
313                                         WEP_CVAR_SEC(okmachinegun, spread),
314                                         WEP_CVAR_SEC(okmachinegun, delay),
315                                         WEP_CVAR_SEC(okmachinegun, lifetime)
316                                 );
317                                 actor.(weaponentity).m_weapon = oldwep;
318                                 weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(okmachinegun, animtime), w_ready);
319                         }
320                 }
321         }
322 }
323
324 METHOD(OverkillMachineGun, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
325 {
326         float ammo_amount;
327         if(WEP_CVAR(okmachinegun, mode) == 1)
328                 ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(okmachinegun, sustained_ammo);
329         else
330                 ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(okmachinegun, first_ammo);
331
332         if(WEP_CVAR(okmachinegun, reload_ammo))
333         {
334                 if(WEP_CVAR(okmachinegun, mode) == 1)
335                         ammo_amount += actor.(weaponentity).(weapon_load[WEP_OVERKILL_MACHINEGUN.m_id]) >= WEP_CVAR(okmachinegun, sustained_ammo);
336                 else
337                         ammo_amount += actor.(weaponentity).(weapon_load[WEP_OVERKILL_MACHINEGUN.m_id]) >= WEP_CVAR(okmachinegun, first_ammo);
338         }
339         return ammo_amount;
340 }
341
342 METHOD(OverkillMachineGun, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
343 {
344         float ammo_amount;
345         if(WEP_CVAR(okmachinegun, mode) == 1)
346                 ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(okmachinegun, burst_ammo);
347         else
348                 ammo_amount = actor.(thiswep.ammo_field) >= WEP_CVAR(okmachinegun, first_ammo);
349
350         if(WEP_CVAR(okmachinegun, reload_ammo))
351         {
352                 if(WEP_CVAR(okmachinegun, mode) == 1)
353                         ammo_amount += actor.(weaponentity).(weapon_load[WEP_OVERKILL_MACHINEGUN.m_id]) >= WEP_CVAR(okmachinegun, burst_ammo);
354                 else
355                         ammo_amount += actor.(weaponentity).(weapon_load[WEP_OVERKILL_MACHINEGUN.m_id]) >= WEP_CVAR(okmachinegun, first_ammo);
356         }
357         return ammo_amount;
358 }
359
360 METHOD(OverkillMachineGun, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
361 {
362         W_Reload(actor, weaponentity, min(max(WEP_CVAR(okmachinegun, sustained_ammo), WEP_CVAR(okmachinegun, first_ammo)), WEP_CVAR(okmachinegun, burst_ammo)), SND_RELOAD);
363 }
364
365 METHOD(OverkillMachineGun, wr_suicidemessage, Notification(entity thiswep))
366 {
367         return WEAPON_THINKING_WITH_PORTALS;
368 }
369
370 METHOD(OverkillMachineGun, wr_killmessage, Notification(entity thiswep))
371 {
372         if(w_deathtype & HITTYPE_SECONDARY)
373                 return WEAPON_MACHINEGUN_MURDER_SNIPE;
374         else
375                 return WEAPON_MACHINEGUN_MURDER_SPRAY;
376 }
377
378 #endif
379 #ifdef CSQC
380
381 METHOD(OverkillMachineGun, wr_impacteffect, void(entity thiswep, entity actor))
382 {
383         vector org2;
384         org2 = w_org + w_backoff * 2;
385         pointparticles(EFFECT_MACHINEGUN_IMPACT, org2, w_backoff * 1000, 1);
386         if(!w_issilent)
387                 sound(actor, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTN_NORM);
388 }
389
390 #endif
391