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 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.clip_load < min(autocvar_g_balance_sniperrifle_primary_ammo, autocvar_g_balance_sniperrifle_secondary_ammo)) // 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_fire.wav");
249 precache_sound ("weapons/campingrifle_fire2.wav");
250 precache_sound ("weapons/reload.wav");
252 else if (req == WR_SETUP)
254 weapon_setup(WEP_SNIPERRIFLE);
255 W_SniperRifle_SetAmmoCounter();
257 else if (req == WR_CHECKAMMO1)
259 if(autocvar_g_balance_sniperrifle_reload_ammo)
260 return self.sniperrifle_load >= autocvar_g_balance_sniperrifle_primary_ammo;
262 return self.ammo_nails >= autocvar_g_balance_sniperrifle_primary_ammo;
264 else if (req == WR_CHECKAMMO2)
266 if(autocvar_g_balance_sniperrifle_reload_ammo)
267 return self.sniperrifle_load >= autocvar_g_balance_sniperrifle_primary_ammo;
269 return self.ammo_nails >= autocvar_g_balance_sniperrifle_secondary_ammo;
271 else if (req == WR_RELOAD)
273 W_SniperRifle_Reload();
275 else if (req == WR_RESETPLAYER)
277 self.sniperrifle_accumulator = time - autocvar_g_balance_sniperrifle_bursttime;
278 self.clip_load = autocvar_g_balance_sniperrifle_reload_ammo;
284 float w_sniperrifle(float req)
286 if(req == WR_IMPACTEFFECT)
289 org2 = w_org + w_backoff * 2;
290 pointparticles(particleeffectnum("machinegun_impact"), org2, w_backoff * 1000, 1);
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);
301 else if(req == WR_PRECACHE)
303 precache_sound("weapons/ric1.wav");
304 precache_sound("weapons/ric2.wav");
305 precache_sound("weapons/ric3.wav");
307 else if (req == WR_SUICIDEMESSAGE)
309 if(w_deathtype & HITTYPE_SECONDARY)
310 w_deathtypestring = "%s shot themself automatically";
312 w_deathtypestring = "%s sniped themself somehow";
314 else if (req == WR_KILLMESSAGE)
316 if(w_deathtype & HITTYPE_SECONDARY)
318 if(w_deathtype & HITTYPE_BOUNCE)
319 w_deathtypestring = "%s failed to hide from %s's bullet hail";
321 w_deathtypestring = "%s died in %s's bullet hail";
325 if(w_deathtype & HITTYPE_BOUNCE)
327 // TODO special headshot message here too?
328 w_deathtypestring = "%s failed to hide from %s's rifle";
332 if(w_deathtype & HITTYPE_HEADSHOT)
333 w_deathtypestring = "%s got hit in the head by %s";
335 w_deathtypestring = "%s was sniped by %s";