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 // weapon load persistence, for weapons that support reloading
12 .float sniperrifle_load;
14 void W_SniperRifle_SetAmmoCounter()
16 // set clip_load to the weapon we have switched to, if the gun uses reloading
17 if(!autocvar_g_balance_sniperrifle_reload_ammo)
18 self.clip_load = 0; // also keeps crosshair ammo from displaying
21 self.clip_load = self.sniperrifle_load;
22 self.clip_size = autocvar_g_balance_sniperrifle_reload_ammo; // for the crosshair ammo display
26 void W_SniperRifle_ReloadedAndReady()
30 // now do the ammo transfer
31 self.clip_load = self.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading
32 while(self.clip_load < autocvar_g_balance_sniperrifle_reload_ammo && self.ammo_nails) // make sure we don't add more ammo than we have
37 self.sniperrifle_load = self.clip_load;
39 t = ATTACK_FINISHED(self) - autocvar_g_balance_sniperrifle_reload_time - 1;
40 ATTACK_FINISHED(self) = t;
44 void W_SniperRifle_Reload()
46 // return if reloading is disabled for this weapon
47 if(!autocvar_g_balance_sniperrifle_reload_ammo)
50 if(!W_ReloadCheck(self.ammo_nails, min(autocvar_g_balance_sniperrifle_primary_ammo, autocvar_g_balance_sniperrifle_secondary_ammo)))
55 sound (self, CHAN_WEAPON2, "weapons/reload.wav", VOL_BASE, ATTN_NORM);
57 t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_sniperrifle_reload_time + 1;
58 ATTACK_FINISHED(self) = t;
60 weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_sniperrifle_reload_time, W_SniperRifle_ReloadedAndReady);
62 self.old_clip_load = self.clip_load;
66 void W_SniperRifle_FireBullet(float pSpread, float pDamage, float pHeadshotAddedDamage, float pForce, float pSpeed, float pLifetime, float pAmmo, float deathtype, float pBulletConstant)
68 // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
69 if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
71 if(autocvar_g_balance_sniperrifle_reload_ammo)
73 self.clip_load -= pAmmo;
74 self.sniperrifle_load = self.clip_load;
77 self.ammo_nails -= pAmmo;
80 if(deathtype & HITTYPE_SECONDARY)
81 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);
83 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);
85 pointparticles(particleeffectnum("sniperrifle_muzzleflash"), w_shotorg, w_shotdir * 2000, 1);
87 if(self.BUTTON_ZOOM) // if zoomed, shoot from the eye
89 w_shotdir = v_forward;
90 w_shotorg = self.origin + self.view_ofs + ((w_shotorg - self.origin - self.view_ofs) * v_forward) * v_forward;
93 if(deathtype & HITTYPE_SECONDARY)
94 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);
96 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);
97 endFireBallisticBullet();
99 if (autocvar_g_casings >= 2)
100 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);
103 void W_SniperRifle_Attack()
105 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);
108 void W_SniperRifle_Attack2()
110 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);
113 void spawnfunc_weapon_sniperrifle (void)
115 weapon_defaultspawnfunc(WEP_SNIPERRIFLE);
118 // compatibility alias
119 void spawnfunc_weapon_campingrifle (void)
121 spawnfunc_weapon_sniperrifle();
124 .void(void) sniperrifle_bullethail_attackfunc;
125 .float sniperrifle_bullethail_frame;
126 .float sniperrifle_bullethail_animtime;
127 .float sniperrifle_bullethail_refire;
128 void W_SniperRifle_BulletHail_Continue()
132 sw = self.switchweapon; // make it not detect weapon changes as reason to abort firing
133 af = ATTACK_FINISHED(self);
134 self.switchweapon = self.weapon;
135 ATTACK_FINISHED(self) = time;
136 print(ftos(self.ammo_nails), "\n");
137 r = weapon_prepareattack(self.sniperrifle_bullethail_frame == WFRAME_FIRE2, self.sniperrifle_bullethail_refire);
138 if(self.switchweapon == self.weapon)
139 self.switchweapon = sw;
142 self.sniperrifle_bullethail_attackfunc();
143 weapon_thinkf(self.sniperrifle_bullethail_frame, self.sniperrifle_bullethail_animtime, W_SniperRifle_BulletHail_Continue);
144 print("thinkf set\n");
148 ATTACK_FINISHED(self) = af; // reset attack_finished if we didn't fire, so the last shot enforces the refire time
149 print("out of ammo... ", ftos(self.weaponentity.state), "\n");
153 void W_SniperRifle_BulletHail(float mode, void(void) AttackFunc, float fr, float animtime, float refire)
155 // if we get here, we have at least one bullet to fire
160 self.sniperrifle_bullethail_attackfunc = AttackFunc;
161 self.sniperrifle_bullethail_frame = fr;
162 self.sniperrifle_bullethail_animtime = animtime;
163 self.sniperrifle_bullethail_refire = refire;
164 weapon_thinkf(fr, animtime, W_SniperRifle_BulletHail_Continue);
169 weapon_thinkf(fr, animtime, w_ready);
173 .float bot_secondary_sniperriflemooth;
174 float w_sniperrifle(float req)
180 self.BUTTON_ATCK=FALSE;
181 self.BUTTON_ATCK2=FALSE;
182 if(vlen(self.origin-self.enemy.origin) > 1000)
183 self.bot_secondary_sniperriflemooth = 0;
184 if(self.bot_secondary_sniperriflemooth == 0)
186 if(bot_aim(autocvar_g_balance_sniperrifle_primary_speed, 0, autocvar_g_balance_sniperrifle_primary_lifetime, TRUE))
188 self.BUTTON_ATCK = TRUE;
189 if(random() < 0.01) self.bot_secondary_sniperriflemooth = 1;
194 if(bot_aim(autocvar_g_balance_sniperrifle_secondary_speed, 0, autocvar_g_balance_sniperrifle_secondary_lifetime, TRUE))
196 self.BUTTON_ATCK2 = TRUE;
197 if(random() < 0.03) self.bot_secondary_sniperriflemooth = 0;
201 else if (req == WR_THINK)
203 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
204 W_SniperRifle_Reload();
207 self.sniperrifle_accumulator = bound(time - autocvar_g_balance_sniperrifle_bursttime, self.sniperrifle_accumulator, time);
208 if (self.BUTTON_ATCK)
209 if (weapon_prepareattack_check(0, autocvar_g_balance_sniperrifle_primary_refire))
210 if (time >= self.sniperrifle_accumulator + autocvar_g_balance_sniperrifle_primary_burstcost)
212 weapon_prepareattack_do(0, autocvar_g_balance_sniperrifle_primary_refire);
213 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);
214 self.sniperrifle_accumulator += autocvar_g_balance_sniperrifle_primary_burstcost;
216 if (self.BUTTON_ATCK2)
218 if (autocvar_g_balance_sniperrifle_secondary)
220 if(autocvar_g_balance_sniperrifle_secondary_reload)
221 W_SniperRifle_Reload();
224 if (weapon_prepareattack_check(1, autocvar_g_balance_sniperrifle_secondary_refire))
225 if (time >= self.sniperrifle_accumulator + autocvar_g_balance_sniperrifle_secondary_burstcost)
227 weapon_prepareattack_do(1, autocvar_g_balance_sniperrifle_secondary_refire);
228 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);
229 self.sniperrifle_accumulator += autocvar_g_balance_sniperrifle_secondary_burstcost;
236 else if (req == WR_PRECACHE)
238 precache_model ("models/weapons/g_campingrifle.md3");
239 precache_model ("models/weapons/v_campingrifle.md3");
240 precache_model ("models/weapons/h_campingrifle.iqm");
241 precache_sound ("weapons/campingrifle_fire.wav");
242 precache_sound ("weapons/campingrifle_fire2.wav");
243 precache_sound ("weapons/reload.wav");
245 else if (req == WR_SETUP)
247 weapon_setup(WEP_SNIPERRIFLE);
248 W_SniperRifle_SetAmmoCounter();
250 else if (req == WR_CHECKAMMO1)
252 ammo_amount = self.ammo_cells >= autocvar_g_balance_sniperrifle_primary_ammo;
253 ammo_amount += (autocvar_g_balance_sniperrifle_reload_ammo && self.sniperrifle_load >= autocvar_g_balance_sniperrifle_primary_ammo);
256 else if (req == WR_CHECKAMMO2)
258 ammo_amount = self.ammo_cells >= autocvar_g_balance_sniperrifle_secondary_ammo;
259 ammo_amount += (autocvar_g_balance_sniperrifle_reload_ammo && self.sniperrifle_load >= autocvar_g_balance_sniperrifle_secondary_ammo);
262 else if (req == WR_RESETPLAYER)
264 self.sniperrifle_accumulator = time - autocvar_g_balance_sniperrifle_bursttime;
266 // all weapons must be fully loaded when we spawn
267 self.sniperrifle_load = autocvar_g_balance_sniperrifle_reload_ammo;
269 else if (req == WR_RELOAD)
271 W_SniperRifle_Reload();
277 float w_sniperrifle(float req)
279 if(req == WR_IMPACTEFFECT)
282 org2 = w_org + w_backoff * 2;
283 pointparticles(particleeffectnum("machinegun_impact"), org2, w_backoff * 1000, 1);
287 sound(self, CHAN_PROJECTILE, "weapons/ric1.wav", VOL_BASE, ATTN_NORM);
288 else if(w_random < 0.4)
289 sound(self, CHAN_PROJECTILE, "weapons/ric2.wav", VOL_BASE, ATTN_NORM);
290 else if(w_random < 0.5)
291 sound(self, CHAN_PROJECTILE, "weapons/ric3.wav", VOL_BASE, ATTN_NORM);
294 else if(req == WR_PRECACHE)
296 precache_sound("weapons/ric1.wav");
297 precache_sound("weapons/ric2.wav");
298 precache_sound("weapons/ric3.wav");
300 else if (req == WR_SUICIDEMESSAGE)
302 if(w_deathtype & HITTYPE_SECONDARY)
303 w_deathtypestring = _("%s shot themself automatically");
305 w_deathtypestring = _("%s sniped themself somehow");
307 else if (req == WR_KILLMESSAGE)
309 if(w_deathtype & HITTYPE_SECONDARY)
311 if(w_deathtype & HITTYPE_BOUNCE)
312 w_deathtypestring = _("%s failed to hide from %s's bullet hail");
314 w_deathtypestring = _("%s died in %s's bullet hail");
318 if(w_deathtype & HITTYPE_BOUNCE)
320 // TODO special headshot message here too?
321 w_deathtypestring = _("%s failed to hide from %s's rifle");
325 if(w_deathtype & HITTYPE_HEADSHOT)
326 w_deathtypestring = _("%s got hit in the head by %s");
328 w_deathtypestring = _("%s was sniped by %s");