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_Reload()
28 self.reload_ammo_player = ammo_fuel;
29 self.reload_ammo_min = min(autocvar_g_balance_sniperrifle_primary_ammo, autocvar_g_balance_sniperrifle_secondary_ammo);
30 self.reload_ammo_amount = autocvar_g_balance_sniperrifle_reload_ammo;
31 self.reload_time = autocvar_g_balance_sniperrifle_reload_time;
32 self.reload_sound = "weapons/reload.wav";
37 void W_SniperRifle_FireBullet(float pSpread, float pDamage, float pHeadshotAddedDamage, float pForce, float pSpeed, float pLifetime, float pAmmo, float deathtype, float pBulletConstant)
39 // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
40 if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
42 if(autocvar_g_balance_sniperrifle_reload_ammo)
44 self.clip_load -= pAmmo;
45 self.sniperrifle_load = self.clip_load;
48 self.ammo_nails -= pAmmo;
51 if(deathtype & HITTYPE_SECONDARY)
52 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);
54 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);
56 pointparticles(particleeffectnum("sniperrifle_muzzleflash"), w_shotorg, w_shotdir * 2000, 1);
58 if(self.BUTTON_ZOOM) // if zoomed, shoot from the eye
60 w_shotdir = v_forward;
61 w_shotorg = self.origin + self.view_ofs + ((w_shotorg - self.origin - self.view_ofs) * v_forward) * v_forward;
64 if(deathtype & HITTYPE_SECONDARY)
65 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);
67 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);
68 endFireBallisticBullet();
70 if (autocvar_g_casings >= 2)
71 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);
74 void W_SniperRifle_Attack()
76 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);
79 void W_SniperRifle_Attack2()
81 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);
84 void spawnfunc_weapon_sniperrifle (void)
86 weapon_defaultspawnfunc(WEP_SNIPERRIFLE);
89 // compatibility alias
90 void spawnfunc_weapon_campingrifle (void)
92 spawnfunc_weapon_sniperrifle();
95 .void(void) sniperrifle_bullethail_attackfunc;
96 .float sniperrifle_bullethail_frame;
97 .float sniperrifle_bullethail_animtime;
98 .float sniperrifle_bullethail_refire;
99 void W_SniperRifle_BulletHail_Continue()
103 sw = self.switchweapon; // make it not detect weapon changes as reason to abort firing
104 af = ATTACK_FINISHED(self);
105 self.switchweapon = self.weapon;
106 ATTACK_FINISHED(self) = time;
107 print(ftos(self.ammo_nails), "\n");
108 r = weapon_prepareattack(self.sniperrifle_bullethail_frame == WFRAME_FIRE2, self.sniperrifle_bullethail_refire);
109 if(self.switchweapon == self.weapon)
110 self.switchweapon = sw;
113 self.sniperrifle_bullethail_attackfunc();
114 weapon_thinkf(self.sniperrifle_bullethail_frame, self.sniperrifle_bullethail_animtime, W_SniperRifle_BulletHail_Continue);
115 print("thinkf set\n");
119 ATTACK_FINISHED(self) = af; // reset attack_finished if we didn't fire, so the last shot enforces the refire time
120 print("out of ammo... ", ftos(self.weaponentity.state), "\n");
124 void W_SniperRifle_BulletHail(float mode, void(void) AttackFunc, float fr, float animtime, float refire)
126 // if we get here, we have at least one bullet to fire
131 self.sniperrifle_bullethail_attackfunc = AttackFunc;
132 self.sniperrifle_bullethail_frame = fr;
133 self.sniperrifle_bullethail_animtime = animtime;
134 self.sniperrifle_bullethail_refire = refire;
135 weapon_thinkf(fr, animtime, W_SniperRifle_BulletHail_Continue);
140 weapon_thinkf(fr, animtime, w_ready);
144 .float bot_secondary_sniperriflemooth;
145 float w_sniperrifle(float req)
151 self.BUTTON_ATCK=FALSE;
152 self.BUTTON_ATCK2=FALSE;
153 if(vlen(self.origin-self.enemy.origin) > 1000)
154 self.bot_secondary_sniperriflemooth = 0;
155 if(self.bot_secondary_sniperriflemooth == 0)
157 if(bot_aim(autocvar_g_balance_sniperrifle_primary_speed, 0, autocvar_g_balance_sniperrifle_primary_lifetime, TRUE))
159 self.BUTTON_ATCK = TRUE;
160 if(random() < 0.01) self.bot_secondary_sniperriflemooth = 1;
165 if(bot_aim(autocvar_g_balance_sniperrifle_secondary_speed, 0, autocvar_g_balance_sniperrifle_secondary_lifetime, TRUE))
167 self.BUTTON_ATCK2 = TRUE;
168 if(random() < 0.03) self.bot_secondary_sniperriflemooth = 0;
172 else if (req == WR_THINK)
174 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
175 W_SniperRifle_Reload();
178 self.sniperrifle_accumulator = bound(time - autocvar_g_balance_sniperrifle_bursttime, self.sniperrifle_accumulator, time);
179 if (self.BUTTON_ATCK)
180 if (weapon_prepareattack_check(0, autocvar_g_balance_sniperrifle_primary_refire))
181 if (time >= self.sniperrifle_accumulator + autocvar_g_balance_sniperrifle_primary_burstcost)
183 weapon_prepareattack_do(0, autocvar_g_balance_sniperrifle_primary_refire);
184 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);
185 self.sniperrifle_accumulator += autocvar_g_balance_sniperrifle_primary_burstcost;
187 if (self.BUTTON_ATCK2)
189 if (autocvar_g_balance_sniperrifle_secondary)
191 if(autocvar_g_balance_sniperrifle_secondary_reload)
192 W_SniperRifle_Reload();
195 if (weapon_prepareattack_check(1, autocvar_g_balance_sniperrifle_secondary_refire))
196 if (time >= self.sniperrifle_accumulator + autocvar_g_balance_sniperrifle_secondary_burstcost)
198 weapon_prepareattack_do(1, autocvar_g_balance_sniperrifle_secondary_refire);
199 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);
200 self.sniperrifle_accumulator += autocvar_g_balance_sniperrifle_secondary_burstcost;
207 else if (req == WR_PRECACHE)
209 precache_model ("models/weapons/g_campingrifle.md3");
210 precache_model ("models/weapons/v_campingrifle.md3");
211 precache_model ("models/weapons/h_campingrifle.iqm");
212 precache_sound ("weapons/campingrifle_fire.wav");
213 precache_sound ("weapons/campingrifle_fire2.wav");
214 precache_sound ("weapons/reload.wav");
216 else if (req == WR_SETUP)
218 weapon_setup(WEP_SNIPERRIFLE);
219 W_SniperRifle_SetAmmoCounter();
221 else if (req == WR_CHECKAMMO1)
223 ammo_amount = self.ammo_cells >= autocvar_g_balance_sniperrifle_primary_ammo;
224 ammo_amount += self.sniperrifle_load >= autocvar_g_balance_sniperrifle_primary_ammo;
227 else if (req == WR_CHECKAMMO2)
229 ammo_amount = self.ammo_cells >= autocvar_g_balance_sniperrifle_secondary_ammo;
230 ammo_amount += self.sniperrifle_load >= autocvar_g_balance_sniperrifle_secondary_ammo;
233 else if (req == WR_RESETPLAYER)
235 self.sniperrifle_accumulator = time - autocvar_g_balance_sniperrifle_bursttime;
237 // all weapons must be fully loaded when we spawn
238 self.sniperrifle_load = autocvar_g_balance_sniperrifle_reload_ammo;
240 else if (req == WR_RELOAD)
242 W_SniperRifle_Reload();
248 float w_sniperrifle(float req)
250 if(req == WR_IMPACTEFFECT)
253 org2 = w_org + w_backoff * 2;
254 pointparticles(particleeffectnum("machinegun_impact"), org2, w_backoff * 1000, 1);
258 sound(self, CHAN_PROJECTILE, "weapons/ric1.wav", VOL_BASE, ATTN_NORM);
259 else if(w_random < 0.4)
260 sound(self, CHAN_PROJECTILE, "weapons/ric2.wav", VOL_BASE, ATTN_NORM);
261 else if(w_random < 0.5)
262 sound(self, CHAN_PROJECTILE, "weapons/ric3.wav", VOL_BASE, ATTN_NORM);
265 else if(req == WR_PRECACHE)
267 precache_sound("weapons/ric1.wav");
268 precache_sound("weapons/ric2.wav");
269 precache_sound("weapons/ric3.wav");
271 else if (req == WR_SUICIDEMESSAGE)
273 if(w_deathtype & HITTYPE_SECONDARY)
274 w_deathtypestring = _("%s shot themself automatically");
276 w_deathtypestring = _("%s sniped themself somehow");
278 else if (req == WR_KILLMESSAGE)
280 if(w_deathtype & HITTYPE_SECONDARY)
282 if(w_deathtype & HITTYPE_BOUNCE)
283 w_deathtypestring = _("%s failed to hide from %s's bullet hail");
285 w_deathtypestring = _("%s died in %s's bullet hail");
289 if(w_deathtype & HITTYPE_BOUNCE)
291 // TODO special headshot message here too?
292 w_deathtypestring = _("%s failed to hide from %s's rifle");
296 if(w_deathtype & HITTYPE_HEADSHOT)
297 w_deathtypestring = _("%s got hit in the head by %s");
299 w_deathtypestring = _("%s was sniped by %s");