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;
10 .float sniperrifle_load;
12 void W_SniperRifle_SetAmmoCounter()
14 // set ammo_counter to the weapon we have switched to, if the gun uses reloading
15 if(!autocvar_g_balance_sniperrifle_reload_ammo)
16 self.ammo_counter = 0; // also keeps crosshair ammo from displaying
18 self.ammo_counter = self.sniperrifle_load;
21 void W_SniperRifle_ReloadedAndReady()
25 // now do the ammo transfer
26 self.ammo_counter = self.old_ammo_counter; // restore the ammo counter, in case we still had ammo in the weapon before reloading
27 while(self.ammo_counter < autocvar_g_balance_sniperrifle_reload_ammo && self.ammo_nails) // make sure we don't add more ammo than we have
29 self.ammo_counter += 1;
32 self.sniperrifle_load = self.ammo_counter;
34 t = ATTACK_FINISHED(self) - autocvar_g_balance_sniperrifle_reload_time - 1;
35 ATTACK_FINISHED(self) = t;
39 void W_SniperRifle_Reload()
41 // return if reloading is disabled for this weapon
42 if(!autocvar_g_balance_sniperrifle_reload_ammo)
45 if(!W_ReloadCheck(self.ammo_nails))
50 sound (self, CHAN_WEAPON2, "weapons/campingrifle_reload.wav", VOL_BASE, ATTN_NORM);
52 t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_sniperrifle_reload_time + 1;
53 ATTACK_FINISHED(self) = t;
55 weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_sniperrifle_reload_time, W_SniperRifle_ReloadedAndReady);
57 self.old_ammo_counter = self.ammo_counter;
58 self.ammo_counter = -1;
61 void W_SniperRifle_FireBullet(float pSpread, float pDamage, float pHeadshotAddedDamage, float pForce, float pSpeed, float pLifetime, float pAmmo, float deathtype, float pBulletConstant)
63 if(deathtype & HITTYPE_SECONDARY)
64 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);
66 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);
68 pointparticles(particleeffectnum("sniperrifle_muzzleflash"), w_shotorg, w_shotdir * 2000, 1);
70 if(self.BUTTON_ZOOM) // if zoomed, shoot from the eye
72 w_shotdir = v_forward;
73 w_shotorg = self.origin + self.view_ofs + ((w_shotorg - self.origin - self.view_ofs) * v_forward) * v_forward;
76 if(deathtype & HITTYPE_SECONDARY)
77 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);
79 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);
80 endFireBallisticBullet();
82 if (autocvar_g_casings >= 2)
83 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);
85 // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
86 if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
88 if(!autocvar_g_balance_sniperrifle_reload_ammo)
89 self.ammo_nails -= pAmmo;
92 self.ammo_counter -= pAmmo;
93 self.sniperrifle_load = self.ammo_counter;
98 void W_SniperRifle_Attack()
100 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);
103 void W_SniperRifle_Attack2()
105 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);
108 void spawnfunc_weapon_sniperrifle (void)
110 weapon_defaultspawnfunc(WEP_SNIPERRIFLE);
113 // compatibility alias
114 void spawnfunc_weapon_campingrifle (void)
116 spawnfunc_weapon_sniperrifle();
119 .void(void) sniperrifle_bullethail_attackfunc;
120 .float sniperrifle_bullethail_frame;
121 .float sniperrifle_bullethail_animtime;
122 .float sniperrifle_bullethail_refire;
123 void W_SniperRifle_BulletHail_Continue()
127 if(autocvar_g_balance_sniperrifle_reload_ammo && self.ammo_counter <= 0)
128 return; // reloading, so we are done
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;
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");
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");
151 void W_SniperRifle_BulletHail(float mode, void(void) AttackFunc, float fr, float animtime, float refire)
153 // if we get here, we have at least one bullet to fire
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);
167 weapon_thinkf(fr, animtime, w_ready);
171 .float bot_secondary_sniperriflemooth;
172 float w_sniperrifle(float req)
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)
182 if(bot_aim(autocvar_g_balance_sniperrifle_primary_speed, 0, autocvar_g_balance_sniperrifle_primary_lifetime, TRUE))
184 self.BUTTON_ATCK = TRUE;
185 if(random() < 0.01) self.bot_secondary_sniperriflemooth = 1;
190 if(bot_aim(autocvar_g_balance_sniperrifle_secondary_speed, 0, autocvar_g_balance_sniperrifle_secondary_lifetime, TRUE))
192 self.BUTTON_ATCK2 = TRUE;
193 if(random() < 0.03) self.bot_secondary_sniperriflemooth = 0;
197 else if (req == WR_THINK)
199 if(autocvar_g_balance_sniperrifle_reload_ammo && self.ammo_counter <= 0) // forced reload
200 W_SniperRifle_Reload();
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)
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;
212 if (self.BUTTON_ATCK2)
214 if (autocvar_g_balance_sniperrifle_secondary)
216 if(autocvar_g_balance_sniperrifle_secondary_reload)
217 W_SniperRifle_Reload();
220 if (weapon_prepareattack_check(1, autocvar_g_balance_sniperrifle_secondary_refire))
221 if (time >= self.sniperrifle_accumulator + autocvar_g_balance_sniperrifle_secondary_burstcost)
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;
233 if(self.switchweapon == self.weapon)
235 if(self.weaponentity.state == WS_READY)
237 self.wish_reload = 0;
238 W_SniperRifle_Reload();
243 else if (req == WR_PRECACHE)
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_reload.wav");
249 precache_sound ("weapons/campingrifle_fire.wav");
250 precache_sound ("weapons/campingrifle_fire2.wav");
252 else if (req == WR_SETUP)
254 weapon_setup(WEP_SNIPERRIFLE);
255 W_SniperRifle_SetAmmoCounter();
257 else if (req == WR_CHECKAMMO1)
259 return self.ammo_nails >= autocvar_g_balance_sniperrifle_primary_ammo;
261 else if (req == WR_CHECKAMMO2)
263 return self.ammo_nails >= autocvar_g_balance_sniperrifle_secondary_ammo;
265 else if (req == WR_RELOAD)
267 W_SniperRifle_Reload();
269 else if (req == WR_RESETPLAYER)
271 self.sniperrifle_accumulator = time - autocvar_g_balance_sniperrifle_bursttime;
272 self.ammo_counter = autocvar_g_balance_sniperrifle_reload_ammo;
278 float w_sniperrifle(float req)
280 if(req == WR_IMPACTEFFECT)
283 org2 = w_org + w_backoff * 2;
284 pointparticles(particleeffectnum("machinegun_impact"), org2, w_backoff * 1000, 1);
288 sound(self, CHAN_PROJECTILE, "weapons/ric1.wav", VOL_BASE, ATTN_NORM);
289 else if(w_random < 0.4)
290 sound(self, CHAN_PROJECTILE, "weapons/ric2.wav", VOL_BASE, ATTN_NORM);
291 else if(w_random < 0.5)
292 sound(self, CHAN_PROJECTILE, "weapons/ric3.wav", VOL_BASE, ATTN_NORM);
295 else if(req == WR_PRECACHE)
297 precache_sound("weapons/ric1.wav");
298 precache_sound("weapons/ric2.wav");
299 precache_sound("weapons/ric3.wav");
301 else if (req == WR_SUICIDEMESSAGE)
303 if(w_deathtype & HITTYPE_SECONDARY)
304 w_deathtypestring = "%s shot themself automatically";
306 w_deathtypestring = "%s sniped themself somehow";
308 else if (req == WR_KILLMESSAGE)
310 if(w_deathtype & HITTYPE_SECONDARY)
312 if(w_deathtype & HITTYPE_BOUNCE)
313 w_deathtypestring = "%s failed to hide from %s's bullet hail";
315 w_deathtypestring = "%s died in %s's bullet hail";
319 if(w_deathtype & HITTYPE_BOUNCE)
321 // TODO special headshot message here too?
322 w_deathtypestring = "%s failed to hide from %s's rifle";
326 if(w_deathtype & HITTYPE_HEADSHOT)
327 w_deathtypestring = "%s got hit in the head by %s";
329 w_deathtypestring = "%s was sniped by %s";