]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/w_sniperrifle.qc
Remove useless returns on attack and attack2. There are several other checks that...
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / w_sniperrifle.qc
1 #ifdef REGISTER_WEAPON
2 REGISTER_WEAPON(SNIPERRIFLE, w_sniperrifle, IT_NAILS, 7, WEP_FLAG_NORMAL | WEP_TYPE_HITSCAN, BOT_PICKUP_RATING_MID, "campingrifle", "sniperrifle", _("Sniper Rifle"))
3 #else
4 #ifdef SVQC
5 //Sniper rifle Primary mode: manually operated bolt*, Secondary: full automatic**
6 //* Manually operating the bolt means that all the power of the gas is used to propell the bullet. In this mode the bolt is prevented from moving backwards in response to the firing of the bullet.
7 //** In fully automatic mode some of the gas is used to extract and reload the next cartrige, thus there is less power and range.
8
9 .float sniperrifle_accumulator;
10 .float sniperrifle_load;
11
12 void W_SniperRifle_SetAmmoCounter()
13 {
14         // set clip_load to the weapon we have switched to, if the gun uses reloading
15         if(!autocvar_g_balance_sniperrifle_reload_ammo)
16                 self.clip_load = 0; // also keeps crosshair ammo from displaying
17         else
18         {
19                 self.clip_load = self.sniperrifle_load;
20                 self.clip_size = autocvar_g_balance_sniperrifle_reload_ammo; // for the crosshair ammo display
21         }
22 }
23
24 void W_SniperRifle_ReloadedAndReady()
25 {
26         float t;
27
28         // now do the ammo transfer
29         self.clip_load = self.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading
30         while(self.clip_load < autocvar_g_balance_sniperrifle_reload_ammo && self.ammo_nails) // make sure we don't add more ammo than we have
31         {
32                 self.clip_load += 1;
33                 self.ammo_nails -= 1;
34         }
35         self.sniperrifle_load = self.clip_load;
36
37         t = ATTACK_FINISHED(self) - autocvar_g_balance_sniperrifle_reload_time - 1;
38         ATTACK_FINISHED(self) = t;
39         w_ready();
40 }
41
42 void W_SniperRifle_Reload()
43 {
44         // return if reloading is disabled for this weapon
45         if(!autocvar_g_balance_sniperrifle_reload_ammo)
46                 return;
47
48         if(!W_ReloadCheck(self.ammo_nails))
49                 return;
50
51         float t;
52
53         sound (self, CHAN_WEAPON2, "weapons/reload.wav", VOL_BASE, ATTN_NORM);
54
55         t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_sniperrifle_reload_time + 1;
56         ATTACK_FINISHED(self) = t;
57
58         weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_sniperrifle_reload_time, W_SniperRifle_ReloadedAndReady);
59
60         self.old_clip_load = self.clip_load;
61         self.clip_load = -1;
62 }
63
64 void W_SniperRifle_FireBullet(float pSpread, float pDamage, float pHeadshotAddedDamage, float pForce, float pSpeed, float pLifetime, float pAmmo, float deathtype, float pBulletConstant)
65 {
66         if(deathtype & HITTYPE_SECONDARY)
67                 W_SetupShot (self, autocvar_g_antilag_bullets && pSpeed >= autocvar_g_antilag_bullets, 2, "weapons/campingrifle_fire2.wav", CHAN_WEAPON, autocvar_g_balance_sniperrifle_secondary_damage + autocvar_g_balance_sniperrifle_secondary_headshotaddeddamage);
68         else
69                 W_SetupShot (self, autocvar_g_antilag_bullets && pSpeed >= autocvar_g_antilag_bullets, 2, "weapons/campingrifle_fire.wav", CHAN_WEAPON, autocvar_g_balance_sniperrifle_primary_damage + autocvar_g_balance_sniperrifle_primary_headshotaddeddamage);
70
71         pointparticles(particleeffectnum("sniperrifle_muzzleflash"), w_shotorg, w_shotdir * 2000, 1);
72
73         if(self.BUTTON_ZOOM) // if zoomed, shoot from the eye
74         {
75                 w_shotdir = v_forward;
76                 w_shotorg = self.origin + self.view_ofs + ((w_shotorg - self.origin - self.view_ofs) * v_forward) * v_forward;
77         }
78
79         if(deathtype & HITTYPE_SECONDARY)
80                 fireBallisticBullet(w_shotorg, w_shotdir, pSpread, pSpeed, pLifetime, pDamage, pHeadshotAddedDamage / pDamage, pForce, deathtype, (autocvar_g_balance_sniperrifle_secondary_tracer ? EF_RED : EF_BLUE), 1, pBulletConstant);
81         else
82                 fireBallisticBullet(w_shotorg, w_shotdir, pSpread, pSpeed, pLifetime, pDamage, pHeadshotAddedDamage / pDamage, pForce, deathtype, (autocvar_g_balance_sniperrifle_primary_tracer ? EF_RED : EF_BLUE), 1, pBulletConstant);
83         endFireBallisticBullet();
84
85         if (autocvar_g_casings >= 2)
86                 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);
87
88         // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
89         if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
90         {
91                 if(autocvar_g_balance_sniperrifle_reload_ammo)
92                 {
93                         self.clip_load -= pAmmo;
94                         self.sniperrifle_load = self.clip_load;
95                 }
96                 else
97                         self.ammo_nails -= pAmmo;
98         }
99 }
100
101 void W_SniperRifle_Attack()
102 {
103         W_SniperRifle_FireBullet(autocvar_g_balance_sniperrifle_primary_spread, autocvar_g_balance_sniperrifle_primary_damage, autocvar_g_balance_sniperrifle_primary_headshotaddeddamage, autocvar_g_balance_sniperrifle_primary_force, autocvar_g_balance_sniperrifle_primary_speed, autocvar_g_balance_sniperrifle_primary_lifetime, autocvar_g_balance_sniperrifle_primary_ammo, WEP_SNIPERRIFLE, autocvar_g_balance_sniperrifle_primary_bulletconstant);
104 }
105
106 void W_SniperRifle_Attack2()
107 {
108         W_SniperRifle_FireBullet(autocvar_g_balance_sniperrifle_secondary_spread, autocvar_g_balance_sniperrifle_secondary_damage, autocvar_g_balance_sniperrifle_secondary_headshotaddeddamage, autocvar_g_balance_sniperrifle_secondary_force, autocvar_g_balance_sniperrifle_secondary_speed, autocvar_g_balance_sniperrifle_secondary_lifetime, autocvar_g_balance_sniperrifle_secondary_ammo, WEP_SNIPERRIFLE | HITTYPE_SECONDARY, autocvar_g_balance_sniperrifle_secondary_bulletconstant);
109 }
110
111 void spawnfunc_weapon_sniperrifle (void)
112 {
113         weapon_defaultspawnfunc(WEP_SNIPERRIFLE);
114 }
115
116 // compatibility alias
117 void spawnfunc_weapon_campingrifle (void)
118 {
119         spawnfunc_weapon_sniperrifle();
120 }
121
122 .void(void) sniperrifle_bullethail_attackfunc;
123 .float sniperrifle_bullethail_frame;
124 .float sniperrifle_bullethail_animtime;
125 .float sniperrifle_bullethail_refire;
126 void W_SniperRifle_BulletHail_Continue()
127 {
128         float r, sw, af;
129
130         sw = self.switchweapon; // make it not detect weapon changes as reason to abort firing
131         af = ATTACK_FINISHED(self);
132         self.switchweapon = self.weapon;
133         ATTACK_FINISHED(self) = time;
134         print(ftos(self.ammo_nails), "\n");
135         r = weapon_prepareattack(self.sniperrifle_bullethail_frame == WFRAME_FIRE2, self.sniperrifle_bullethail_refire);
136         if(self.switchweapon == self.weapon)
137                 self.switchweapon = sw;
138         if(r)
139         {
140                 self.sniperrifle_bullethail_attackfunc();
141                 weapon_thinkf(self.sniperrifle_bullethail_frame, self.sniperrifle_bullethail_animtime, W_SniperRifle_BulletHail_Continue);
142                 print("thinkf set\n");
143         }
144         else
145         {
146                 ATTACK_FINISHED(self) = af; // reset attack_finished if we didn't fire, so the last shot enforces the refire time
147                 print("out of ammo... ", ftos(self.weaponentity.state), "\n");
148         }
149 }
150
151 void W_SniperRifle_BulletHail(float mode, void(void) AttackFunc, float fr, float animtime, float refire)
152 {
153         // if we get here, we have at least one bullet to fire
154         AttackFunc();
155         if(mode)
156         {
157                 // continue hail
158                 self.sniperrifle_bullethail_attackfunc = AttackFunc;
159                 self.sniperrifle_bullethail_frame = fr;
160                 self.sniperrifle_bullethail_animtime = animtime;
161                 self.sniperrifle_bullethail_refire = refire;
162                 weapon_thinkf(fr, animtime, W_SniperRifle_BulletHail_Continue);
163         }
164         else
165         {
166                 // just one shot
167                 weapon_thinkf(fr, animtime, w_ready);
168         }
169 }
170
171 .float bot_secondary_sniperriflemooth;
172 float w_sniperrifle(float req)
173 {
174         if (req == WR_AIM)
175         {
176                 self.BUTTON_ATCK=FALSE;
177                 self.BUTTON_ATCK2=FALSE;
178                 if(vlen(self.origin-self.enemy.origin) > 1000)
179                         self.bot_secondary_sniperriflemooth = 0;
180                 if(self.bot_secondary_sniperriflemooth == 0)
181                 {
182                         if(bot_aim(autocvar_g_balance_sniperrifle_primary_speed, 0, autocvar_g_balance_sniperrifle_primary_lifetime, TRUE))
183                         {
184                                 self.BUTTON_ATCK = TRUE;
185                                 if(random() < 0.01) self.bot_secondary_sniperriflemooth = 1;
186                         }
187                 }
188                 else
189                 {
190                         if(bot_aim(autocvar_g_balance_sniperrifle_secondary_speed, 0, autocvar_g_balance_sniperrifle_secondary_lifetime, TRUE))
191                         {
192                                 self.BUTTON_ATCK2 = TRUE;
193                                 if(random() < 0.03) self.bot_secondary_sniperriflemooth = 0;
194                         }
195                 }
196         }
197         else if (req == WR_THINK)
198         {
199                 if(autocvar_g_balance_sniperrifle_reload_ammo && self.clip_load < min(autocvar_g_balance_sniperrifle_primary_ammo, autocvar_g_balance_sniperrifle_secondary_ammo)) // forced reload
200             W_SniperRifle_Reload();
201                 else
202                 {
203                         self.sniperrifle_accumulator = bound(time - autocvar_g_balance_sniperrifle_bursttime, self.sniperrifle_accumulator, time);
204                         if (self.BUTTON_ATCK)
205                         if (weapon_prepareattack_check(0, autocvar_g_balance_sniperrifle_primary_refire))
206                         if (time >= self.sniperrifle_accumulator + autocvar_g_balance_sniperrifle_primary_burstcost)
207                         {
208                                 weapon_prepareattack_do(0, autocvar_g_balance_sniperrifle_primary_refire);
209                                 W_SniperRifle_BulletHail(autocvar_g_balance_sniperrifle_primary_bullethail, W_SniperRifle_Attack, WFRAME_FIRE1, autocvar_g_balance_sniperrifle_primary_animtime, autocvar_g_balance_sniperrifle_primary_refire);
210                                 self.sniperrifle_accumulator += autocvar_g_balance_sniperrifle_primary_burstcost;
211                         }
212                         if (self.BUTTON_ATCK2)
213                         {       
214                                 if (autocvar_g_balance_sniperrifle_secondary)
215                                 {
216                     if(autocvar_g_balance_sniperrifle_secondary_reload)
217                         W_SniperRifle_Reload();
218                     else
219                     {
220                         if (weapon_prepareattack_check(1, autocvar_g_balance_sniperrifle_secondary_refire))
221                         if (time >= self.sniperrifle_accumulator + autocvar_g_balance_sniperrifle_secondary_burstcost)
222                         {
223                             weapon_prepareattack_do(1, autocvar_g_balance_sniperrifle_secondary_refire);
224                             W_SniperRifle_BulletHail(autocvar_g_balance_sniperrifle_secondary_bullethail, W_SniperRifle_Attack2, WFRAME_FIRE2, autocvar_g_balance_sniperrifle_secondary_animtime, autocvar_g_balance_sniperrifle_primary_refire);
225                             self.sniperrifle_accumulator += autocvar_g_balance_sniperrifle_secondary_burstcost;
226                         }
227                     }
228                                 }
229                         }
230                 }
231         if(self.wish_reload)
232         {
233             if(self.switchweapon == self.weapon)
234             {
235                 if(self.weaponentity.state == WS_READY)
236                 {
237                     self.wish_reload = 0;
238                     W_SniperRifle_Reload();
239                 }
240             }
241         }
242         }
243         else if (req == WR_PRECACHE)
244         {
245                 precache_model ("models/weapons/g_campingrifle.md3");
246                 precache_model ("models/weapons/v_campingrifle.md3");
247                 precache_model ("models/weapons/h_campingrifle.iqm");
248                 precache_sound ("weapons/campingrifle_fire.wav");
249                 precache_sound ("weapons/campingrifle_fire2.wav");
250                 precache_sound ("weapons/reload.wav");
251         }
252         else if (req == WR_SETUP)
253         {
254                 weapon_setup(WEP_SNIPERRIFLE);
255                 W_SniperRifle_SetAmmoCounter();
256         }
257         else if (req == WR_CHECKAMMO1)
258         {
259                 if(autocvar_g_balance_sniperrifle_reload_ammo)
260                         return self.sniperrifle_load >= autocvar_g_balance_sniperrifle_primary_ammo;
261                 else
262                         return self.ammo_nails >= autocvar_g_balance_sniperrifle_primary_ammo;
263         }
264         else if (req == WR_CHECKAMMO2)
265         {
266                 if(autocvar_g_balance_sniperrifle_reload_ammo)
267                         return self.sniperrifle_load >= autocvar_g_balance_sniperrifle_primary_ammo;
268                 else
269                         return self.ammo_nails >= autocvar_g_balance_sniperrifle_secondary_ammo;
270         }
271         else if (req == WR_RELOAD)
272         {
273                 W_SniperRifle_Reload();
274         }
275         else if (req == WR_RESETPLAYER)
276         {
277                 self.sniperrifle_accumulator = time - autocvar_g_balance_sniperrifle_bursttime;
278                 self.clip_load = autocvar_g_balance_sniperrifle_reload_ammo;
279         }
280         return TRUE;
281 };
282 #endif
283 #ifdef CSQC
284 float w_sniperrifle(float req)
285 {
286         if(req == WR_IMPACTEFFECT)
287         {
288                 vector org2;
289                 org2 = w_org + w_backoff * 2;
290                 pointparticles(particleeffectnum("machinegun_impact"), org2, w_backoff * 1000, 1);
291                 if(!w_issilent)
292                 {
293                         if(w_random < 0.2)
294                                 sound(self, CHAN_PROJECTILE, "weapons/ric1.wav", VOL_BASE, ATTN_NORM);
295                         else if(w_random < 0.4)
296                                 sound(self, CHAN_PROJECTILE, "weapons/ric2.wav", VOL_BASE, ATTN_NORM);
297                         else if(w_random < 0.5)
298                                 sound(self, CHAN_PROJECTILE, "weapons/ric3.wav", VOL_BASE, ATTN_NORM);
299                 }
300         }
301         else if(req == WR_PRECACHE)
302         {
303                 precache_sound("weapons/ric1.wav");
304                 precache_sound("weapons/ric2.wav");
305                 precache_sound("weapons/ric3.wav");
306         }
307         else if (req == WR_SUICIDEMESSAGE)
308         {
309                 if(w_deathtype & HITTYPE_SECONDARY)
310                         w_deathtypestring = "%s shot themself automatically";
311                 else
312                         w_deathtypestring = "%s sniped themself somehow";
313         }
314         else if (req == WR_KILLMESSAGE)
315         {
316                 if(w_deathtype & HITTYPE_SECONDARY)
317                 {
318                         if(w_deathtype & HITTYPE_BOUNCE)
319                                 w_deathtypestring = "%s failed to hide from %s's bullet hail";
320                         else
321                                 w_deathtypestring = "%s died in %s's bullet hail";
322                 }
323                 else
324                 {
325                         if(w_deathtype & HITTYPE_BOUNCE)
326                         {
327                                 // TODO special headshot message here too?
328                                 w_deathtypestring = "%s failed to hide from %s's rifle";
329                         }
330                         else
331                         {
332                                 if(w_deathtype & HITTYPE_HEADSHOT)
333                                         w_deathtypestring = "%s got hit in the head by %s";
334                                 else
335                                         w_deathtypestring = "%s was sniped by %s";
336                         }
337                 }
338         }
339         return TRUE;
340 }
341 #endif
342 #endif