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 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
19 self.clip_load = self.sniperrifle_load;
20 self.clip_size = autocvar_g_balance_sniperrifle_reload_ammo; // for the crosshair ammo display
24 void W_SniperRifle_ReloadedAndReady()
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
35 self.sniperrifle_load = self.clip_load;
37 t = ATTACK_FINISHED(self) - autocvar_g_balance_sniperrifle_reload_time - 1;
38 ATTACK_FINISHED(self) = t;
42 void W_SniperRifle_Reload()
44 // return if reloading is disabled for this weapon
45 if(!autocvar_g_balance_sniperrifle_reload_ammo)
48 if(!W_ReloadCheck(self.ammo_nails))
53 sound (self, CHAN_WEAPON2, "weapons/reload.wav", VOL_BASE, ATTN_NORM);
55 t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_sniperrifle_reload_time + 1;
56 ATTACK_FINISHED(self) = t;
58 weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_sniperrifle_reload_time, W_SniperRifle_ReloadedAndReady);
60 self.old_clip_load = self.clip_load;
64 void W_SniperRifle_FireBullet(float pSpread, float pDamage, float pHeadshotAddedDamage, float pForce, float pSpeed, float pLifetime, float pAmmo, float deathtype, float pBulletConstant)
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);
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);
71 pointparticles(particleeffectnum("sniperrifle_muzzleflash"), w_shotorg, w_shotdir * 2000, 1);
73 if(self.BUTTON_ZOOM) // if zoomed, shoot from the eye
75 w_shotdir = v_forward;
76 w_shotorg = self.origin + self.view_ofs + ((w_shotorg - self.origin - self.view_ofs) * v_forward) * v_forward;
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);
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();
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);
88 // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
89 if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
91 if(autocvar_g_balance_sniperrifle_reload_ammo)
93 self.clip_load -= pAmmo;
94 self.sniperrifle_load = self.clip_load;
97 self.ammo_nails -= pAmmo;
101 void W_SniperRifle_Attack()
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);
106 void W_SniperRifle_Attack2()
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);
111 void spawnfunc_weapon_sniperrifle (void)
113 weapon_defaultspawnfunc(WEP_SNIPERRIFLE);
116 // compatibility alias
117 void spawnfunc_weapon_campingrifle (void)
119 spawnfunc_weapon_sniperrifle();
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()
130 if(autocvar_g_balance_sniperrifle_reload_ammo && self.clip_load <= 0)
131 return; // reloading, so we are done
133 sw = self.switchweapon; // make it not detect weapon changes as reason to abort firing
134 af = ATTACK_FINISHED(self);
135 self.switchweapon = self.weapon;
136 ATTACK_FINISHED(self) = time;
137 print(ftos(self.ammo_nails), "\n");
138 r = weapon_prepareattack(self.sniperrifle_bullethail_frame == WFRAME_FIRE2, self.sniperrifle_bullethail_refire);
139 if(self.switchweapon == self.weapon)
140 self.switchweapon = sw;
143 self.sniperrifle_bullethail_attackfunc();
144 weapon_thinkf(self.sniperrifle_bullethail_frame, self.sniperrifle_bullethail_animtime, W_SniperRifle_BulletHail_Continue);
145 print("thinkf set\n");
149 ATTACK_FINISHED(self) = af; // reset attack_finished if we didn't fire, so the last shot enforces the refire time
150 print("out of ammo... ", ftos(self.weaponentity.state), "\n");
154 void W_SniperRifle_BulletHail(float mode, void(void) AttackFunc, float fr, float animtime, float refire)
156 // if we get here, we have at least one bullet to fire
161 self.sniperrifle_bullethail_attackfunc = AttackFunc;
162 self.sniperrifle_bullethail_frame = fr;
163 self.sniperrifle_bullethail_animtime = animtime;
164 self.sniperrifle_bullethail_refire = refire;
165 weapon_thinkf(fr, animtime, W_SniperRifle_BulletHail_Continue);
170 weapon_thinkf(fr, animtime, w_ready);
174 .float bot_secondary_sniperriflemooth;
175 float w_sniperrifle(float req)
179 self.BUTTON_ATCK=FALSE;
180 self.BUTTON_ATCK2=FALSE;
181 if(vlen(self.origin-self.enemy.origin) > 1000)
182 self.bot_secondary_sniperriflemooth = 0;
183 if(self.bot_secondary_sniperriflemooth == 0)
185 if(bot_aim(autocvar_g_balance_sniperrifle_primary_speed, 0, autocvar_g_balance_sniperrifle_primary_lifetime, TRUE))
187 self.BUTTON_ATCK = TRUE;
188 if(random() < 0.01) self.bot_secondary_sniperriflemooth = 1;
193 if(bot_aim(autocvar_g_balance_sniperrifle_secondary_speed, 0, autocvar_g_balance_sniperrifle_secondary_lifetime, TRUE))
195 self.BUTTON_ATCK2 = TRUE;
196 if(random() < 0.03) self.bot_secondary_sniperriflemooth = 0;
200 else if (req == WR_THINK)
202 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
203 W_SniperRifle_Reload();
206 self.sniperrifle_accumulator = bound(time - autocvar_g_balance_sniperrifle_bursttime, self.sniperrifle_accumulator, time);
207 if (self.BUTTON_ATCK)
208 if (weapon_prepareattack_check(0, autocvar_g_balance_sniperrifle_primary_refire))
209 if (time >= self.sniperrifle_accumulator + autocvar_g_balance_sniperrifle_primary_burstcost)
211 weapon_prepareattack_do(0, autocvar_g_balance_sniperrifle_primary_refire);
212 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);
213 self.sniperrifle_accumulator += autocvar_g_balance_sniperrifle_primary_burstcost;
215 if (self.BUTTON_ATCK2)
217 if (autocvar_g_balance_sniperrifle_secondary)
219 if(autocvar_g_balance_sniperrifle_secondary_reload)
220 W_SniperRifle_Reload();
223 if (weapon_prepareattack_check(1, autocvar_g_balance_sniperrifle_secondary_refire))
224 if (time >= self.sniperrifle_accumulator + autocvar_g_balance_sniperrifle_secondary_burstcost)
226 weapon_prepareattack_do(1, autocvar_g_balance_sniperrifle_secondary_refire);
227 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);
228 self.sniperrifle_accumulator += autocvar_g_balance_sniperrifle_secondary_burstcost;
236 if(self.switchweapon == self.weapon)
238 if(self.weaponentity.state == WS_READY)
240 self.wish_reload = 0;
241 W_SniperRifle_Reload();
246 else if (req == WR_PRECACHE)
248 precache_model ("models/weapons/g_campingrifle.md3");
249 precache_model ("models/weapons/v_campingrifle.md3");
250 precache_model ("models/weapons/h_campingrifle.iqm");
251 precache_sound ("weapons/campingrifle_fire.wav");
252 precache_sound ("weapons/campingrifle_fire2.wav");
253 precache_sound ("weapons/reload.wav");
255 else if (req == WR_SETUP)
257 weapon_setup(WEP_SNIPERRIFLE);
258 W_SniperRifle_SetAmmoCounter();
260 else if (req == WR_CHECKAMMO1)
262 if(autocvar_g_balance_sniperrifle_reload_ammo)
263 return self.sniperrifle_load >= autocvar_g_balance_sniperrifle_primary_ammo;
265 return self.ammo_nails >= autocvar_g_balance_sniperrifle_primary_ammo;
267 else if (req == WR_CHECKAMMO2)
269 if(autocvar_g_balance_sniperrifle_reload_ammo)
270 return self.sniperrifle_load >= autocvar_g_balance_sniperrifle_primary_ammo;
272 return self.ammo_nails >= autocvar_g_balance_sniperrifle_secondary_ammo;
274 else if (req == WR_RELOAD)
276 W_SniperRifle_Reload();
278 else if (req == WR_RESETPLAYER)
280 self.sniperrifle_accumulator = time - autocvar_g_balance_sniperrifle_bursttime;
281 self.clip_load = autocvar_g_balance_sniperrifle_reload_ammo;
287 float w_sniperrifle(float req)
289 if(req == WR_IMPACTEFFECT)
292 org2 = w_org + w_backoff * 2;
293 pointparticles(particleeffectnum("machinegun_impact"), org2, w_backoff * 1000, 1);
297 sound(self, CHAN_PROJECTILE, "weapons/ric1.wav", VOL_BASE, ATTN_NORM);
298 else if(w_random < 0.4)
299 sound(self, CHAN_PROJECTILE, "weapons/ric2.wav", VOL_BASE, ATTN_NORM);
300 else if(w_random < 0.5)
301 sound(self, CHAN_PROJECTILE, "weapons/ric3.wav", VOL_BASE, ATTN_NORM);
304 else if(req == WR_PRECACHE)
306 precache_sound("weapons/ric1.wav");
307 precache_sound("weapons/ric2.wav");
308 precache_sound("weapons/ric3.wav");
310 else if (req == WR_SUICIDEMESSAGE)
312 if(w_deathtype & HITTYPE_SECONDARY)
313 w_deathtypestring = "%s shot themself automatically";
315 w_deathtypestring = "%s sniped themself somehow";
317 else if (req == WR_KILLMESSAGE)
319 if(w_deathtype & HITTYPE_SECONDARY)
321 if(w_deathtype & HITTYPE_BOUNCE)
322 w_deathtypestring = "%s failed to hide from %s's bullet hail";
324 w_deathtypestring = "%s died in %s's bullet hail";
328 if(w_deathtype & HITTYPE_BOUNCE)
330 // TODO special headshot message here too?
331 w_deathtypestring = "%s failed to hide from %s's rifle";
335 if(w_deathtype & HITTYPE_HEADSHOT)
336 w_deathtypestring = "%s got hit in the head by %s";
338 w_deathtypestring = "%s was sniped by %s";