2 REGISTER_WEAPON(SNIPERRIFLE, w_sniperrifle, IT_NAILS, 7, WEP_FLAG_NORMAL | WEP_TYPE_HITSCAN, BOT_PICKUP_RATING_MID, "campingrifle", "sniperrifle", _("Sniper Rifle"))
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.
9 .float sniperrifle_accumulator;
11 void W_SniperRifle_SetAmmoCounter()
13 // set clip_load to the weapon we have switched to, if the gun uses reloading
14 if(!autocvar_g_balance_sniperrifle_reload_ammo)
15 self.clip_load = 0; // also keeps crosshair ammo from displaying
18 self.clip_load = self.sniperrifle_load;
19 self.clip_size = autocvar_g_balance_sniperrifle_reload_ammo; // for the crosshair ammo display
23 void W_SniperRifle_ReloadedAndReady()
27 // now do the ammo transfer
28 self.clip_load = self.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading
29 while(self.clip_load < autocvar_g_balance_sniperrifle_reload_ammo && self.ammo_nails) // make sure we don't add more ammo than we have
34 self.sniperrifle_load = self.clip_load;
36 t = ATTACK_FINISHED(self) - autocvar_g_balance_sniperrifle_reload_time - 1;
37 ATTACK_FINISHED(self) = t;
41 void W_SniperRifle_Reload()
43 // return if reloading is disabled for this weapon
44 if(!autocvar_g_balance_sniperrifle_reload_ammo)
47 if(!W_ReloadCheck(self.ammo_nails, min(autocvar_g_balance_sniperrifle_primary_ammo, autocvar_g_balance_sniperrifle_secondary_ammo)))
52 sound (self, CHAN_WEAPON2, "weapons/reload.wav", VOL_BASE, ATTN_NORM);
54 t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_sniperrifle_reload_time + 1;
55 ATTACK_FINISHED(self) = t;
57 weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_sniperrifle_reload_time, W_SniperRifle_ReloadedAndReady);
59 self.old_clip_load = self.clip_load;
63 void W_SniperRifle_FireBullet(float pSpread, float pDamage, float pHeadshotAddedDamage, float pForce, float pSpeed, float pLifetime, float pAmmo, float deathtype, float pBulletConstant)
65 // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
66 if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
68 if(autocvar_g_balance_sniperrifle_reload_ammo)
70 self.clip_load -= pAmmo;
71 self.sniperrifle_load = self.clip_load;
74 self.ammo_nails -= pAmmo;
77 if(deathtype & HITTYPE_SECONDARY)
78 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);
80 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);
82 pointparticles(particleeffectnum("sniperrifle_muzzleflash"), w_shotorg, w_shotdir * 2000, 1);
84 if(self.BUTTON_ZOOM) // if zoomed, shoot from the eye
86 w_shotdir = v_forward;
87 w_shotorg = self.origin + self.view_ofs + ((w_shotorg - self.origin - self.view_ofs) * v_forward) * v_forward;
90 if(deathtype & HITTYPE_SECONDARY)
91 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);
93 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);
94 endFireBallisticBullet();
96 if (autocvar_g_casings >= 2)
97 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);
100 void W_SniperRifle_Attack()
102 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);
105 void W_SniperRifle_Attack2()
107 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);
110 void spawnfunc_weapon_sniperrifle (void)
112 weapon_defaultspawnfunc(WEP_SNIPERRIFLE);
115 // compatibility alias
116 void spawnfunc_weapon_campingrifle (void)
118 spawnfunc_weapon_sniperrifle();
121 .void(void) sniperrifle_bullethail_attackfunc;
122 .float sniperrifle_bullethail_frame;
123 .float sniperrifle_bullethail_animtime;
124 .float sniperrifle_bullethail_refire;
125 void W_SniperRifle_BulletHail_Continue()
129 sw = self.switchweapon; // make it not detect weapon changes as reason to abort firing
130 af = ATTACK_FINISHED(self);
131 self.switchweapon = self.weapon;
132 ATTACK_FINISHED(self) = time;
133 print(ftos(self.ammo_nails), "\n");
134 r = weapon_prepareattack(self.sniperrifle_bullethail_frame == WFRAME_FIRE2, self.sniperrifle_bullethail_refire);
135 if(self.switchweapon == self.weapon)
136 self.switchweapon = sw;
139 self.sniperrifle_bullethail_attackfunc();
140 weapon_thinkf(self.sniperrifle_bullethail_frame, self.sniperrifle_bullethail_animtime, W_SniperRifle_BulletHail_Continue);
141 print("thinkf set\n");
145 ATTACK_FINISHED(self) = af; // reset attack_finished if we didn't fire, so the last shot enforces the refire time
146 print("out of ammo... ", ftos(self.weaponentity.state), "\n");
150 void W_SniperRifle_BulletHail(float mode, void(void) AttackFunc, float fr, float animtime, float refire)
152 // if we get here, we have at least one bullet to fire
157 self.sniperrifle_bullethail_attackfunc = AttackFunc;
158 self.sniperrifle_bullethail_frame = fr;
159 self.sniperrifle_bullethail_animtime = animtime;
160 self.sniperrifle_bullethail_refire = refire;
161 weapon_thinkf(fr, animtime, W_SniperRifle_BulletHail_Continue);
166 weapon_thinkf(fr, animtime, w_ready);
170 .float bot_secondary_sniperriflemooth;
171 float w_sniperrifle(float req)
175 self.BUTTON_ATCK=FALSE;
176 self.BUTTON_ATCK2=FALSE;
177 if(vlen(self.origin-self.enemy.origin) > 1000)
178 self.bot_secondary_sniperriflemooth = 0;
179 if(self.bot_secondary_sniperriflemooth == 0)
181 if(bot_aim(autocvar_g_balance_sniperrifle_primary_speed, 0, autocvar_g_balance_sniperrifle_primary_lifetime, TRUE))
183 self.BUTTON_ATCK = TRUE;
184 if(random() < 0.01) self.bot_secondary_sniperriflemooth = 1;
189 if(bot_aim(autocvar_g_balance_sniperrifle_secondary_speed, 0, autocvar_g_balance_sniperrifle_secondary_lifetime, TRUE))
191 self.BUTTON_ATCK2 = TRUE;
192 if(random() < 0.03) self.bot_secondary_sniperriflemooth = 0;
196 else if (req == WR_THINK)
198 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
199 W_SniperRifle_Reload();
202 self.sniperrifle_accumulator = bound(time - autocvar_g_balance_sniperrifle_bursttime, self.sniperrifle_accumulator, time);
203 if (self.BUTTON_ATCK)
204 if (weapon_prepareattack_check(0, autocvar_g_balance_sniperrifle_primary_refire))
205 if (time >= self.sniperrifle_accumulator + autocvar_g_balance_sniperrifle_primary_burstcost)
207 weapon_prepareattack_do(0, autocvar_g_balance_sniperrifle_primary_refire);
208 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);
209 self.sniperrifle_accumulator += autocvar_g_balance_sniperrifle_primary_burstcost;
211 if (self.BUTTON_ATCK2)
213 if (autocvar_g_balance_sniperrifle_secondary)
215 if(autocvar_g_balance_sniperrifle_secondary_reload)
216 W_SniperRifle_Reload();
219 if (weapon_prepareattack_check(1, autocvar_g_balance_sniperrifle_secondary_refire))
220 if (time >= self.sniperrifle_accumulator + autocvar_g_balance_sniperrifle_secondary_burstcost)
222 weapon_prepareattack_do(1, autocvar_g_balance_sniperrifle_secondary_refire);
223 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);
224 self.sniperrifle_accumulator += autocvar_g_balance_sniperrifle_secondary_burstcost;
231 else if (req == WR_PRECACHE)
233 precache_model ("models/weapons/g_campingrifle.md3");
234 precache_model ("models/weapons/v_campingrifle.md3");
235 precache_model ("models/weapons/h_campingrifle.iqm");
236 precache_sound ("weapons/campingrifle_fire.wav");
237 precache_sound ("weapons/campingrifle_fire2.wav");
238 precache_sound ("weapons/reload.wav");
240 else if (req == WR_SETUP)
242 weapon_setup(WEP_SNIPERRIFLE);
243 W_SniperRifle_SetAmmoCounter();
245 else if (req == WR_CHECKAMMO1)
247 if(autocvar_g_balance_sniperrifle_reload_ammo)
248 return self.sniperrifle_load >= autocvar_g_balance_sniperrifle_primary_ammo;
250 return self.ammo_nails >= autocvar_g_balance_sniperrifle_primary_ammo;
252 else if (req == WR_CHECKAMMO2)
254 if(autocvar_g_balance_sniperrifle_reload_ammo)
255 return self.sniperrifle_load >= autocvar_g_balance_sniperrifle_secondary_ammo;
257 return self.ammo_nails >= autocvar_g_balance_sniperrifle_secondary_ammo;
259 else if (req == WR_RELOAD)
261 W_SniperRifle_Reload();
263 else if (req == WR_RESETPLAYER)
265 self.sniperrifle_accumulator = time - autocvar_g_balance_sniperrifle_bursttime;
266 self.clip_load = autocvar_g_balance_sniperrifle_reload_ammo;
268 else if (req == WR_SWITCHABLE)
270 // checks if this weapon can be switched to, when reloading is enabled
271 // returns true if there's either enough load in the weapon to use it,
272 // or we have enough ammo to reload the weapon to a usable point
274 ammo_amount = min(autocvar_g_balance_sniperrifle_primary_ammo, autocvar_g_balance_sniperrifle_secondary_ammo);
275 return (autocvar_g_balance_sniperrifle_reload_ammo && self.sniperrifle_load >= ammo_amount) || self.ammo_nails >= ammo_amount;
281 float w_sniperrifle(float req)
283 if(req == WR_IMPACTEFFECT)
286 org2 = w_org + w_backoff * 2;
287 pointparticles(particleeffectnum("machinegun_impact"), org2, w_backoff * 1000, 1);
291 sound(self, CHAN_PROJECTILE, "weapons/ric1.wav", VOL_BASE, ATTN_NORM);
292 else if(w_random < 0.4)
293 sound(self, CHAN_PROJECTILE, "weapons/ric2.wav", VOL_BASE, ATTN_NORM);
294 else if(w_random < 0.5)
295 sound(self, CHAN_PROJECTILE, "weapons/ric3.wav", VOL_BASE, ATTN_NORM);
298 else if(req == WR_PRECACHE)
300 precache_sound("weapons/ric1.wav");
301 precache_sound("weapons/ric2.wav");
302 precache_sound("weapons/ric3.wav");
304 else if (req == WR_SUICIDEMESSAGE)
306 if(w_deathtype & HITTYPE_SECONDARY)
307 w_deathtypestring = "%s shot themself automatically";
309 w_deathtypestring = "%s sniped themself somehow";
311 else if (req == WR_KILLMESSAGE)
313 if(w_deathtype & HITTYPE_SECONDARY)
315 if(w_deathtype & HITTYPE_BOUNCE)
316 w_deathtypestring = "%s failed to hide from %s's bullet hail";
318 w_deathtypestring = "%s died in %s's bullet hail";
322 if(w_deathtype & HITTYPE_BOUNCE)
324 // TODO special headshot message here too?
325 w_deathtypestring = "%s failed to hide from %s's rifle";
329 if(w_deathtype & HITTYPE_HEADSHOT)
330 w_deathtypestring = "%s got hit in the head by %s";
332 w_deathtypestring = "%s was sniped by %s";