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 void W_SniperRifle_SetAmmoCounter()
13 // set clip_load to the weapon we have switched to, if the gun uses reloading
14 if(!autocvar_g_balance_sniperrifle_reload_ammo)
15 self.clip_load = 0; // also keeps crosshair ammo from displaying
18 self.clip_load = self.weapon_load[WEP_SNIPERRIFLE];
19 self.clip_size = autocvar_g_balance_sniperrifle_reload_ammo; // for the crosshair ammo display
23 void W_SniperRifle_Reload()
25 self.reload_ammo_player = ammo_nails;
26 self.reload_ammo_min = min(autocvar_g_balance_sniperrifle_primary_ammo, autocvar_g_balance_sniperrifle_secondary_ammo);
27 self.reload_ammo_amount = autocvar_g_balance_sniperrifle_reload_ammo;
28 self.reload_time = autocvar_g_balance_sniperrifle_reload_time;
29 self.reload_sound = "weapons/reload.wav";
34 void W_SniperRifle_FireBullet(float pSpread, float pDamage, float pHeadshotAddedDamage, float pForce, float pSpeed, float pLifetime, float pAmmo, float deathtype, float pBulletConstant)
36 // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
37 if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
39 if(autocvar_g_balance_sniperrifle_reload_ammo)
41 self.clip_load -= pAmmo;
42 self.weapon_load[WEP_SNIPERRIFLE] = self.clip_load;
45 self.ammo_nails -= pAmmo;
48 if(deathtype & HITTYPE_SECONDARY)
49 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);
51 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);
53 pointparticles(particleeffectnum("sniperrifle_muzzleflash"), w_shotorg, w_shotdir * 2000, 1);
55 if(self.BUTTON_ZOOM) // if zoomed, shoot from the eye
57 w_shotdir = v_forward;
58 w_shotorg = self.origin + self.view_ofs + ((w_shotorg - self.origin - self.view_ofs) * v_forward) * v_forward;
61 if(deathtype & HITTYPE_SECONDARY)
62 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);
64 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);
65 endFireBallisticBullet();
67 if (autocvar_g_casings >= 2)
68 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);
71 void W_SniperRifle_Attack()
73 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);
76 void W_SniperRifle_Attack2()
78 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);
81 void spawnfunc_weapon_sniperrifle (void)
83 weapon_defaultspawnfunc(WEP_SNIPERRIFLE);
86 // compatibility alias
87 void spawnfunc_weapon_campingrifle (void)
89 spawnfunc_weapon_sniperrifle();
92 .void(void) sniperrifle_bullethail_attackfunc;
93 .float sniperrifle_bullethail_frame;
94 .float sniperrifle_bullethail_animtime;
95 .float sniperrifle_bullethail_refire;
96 void W_SniperRifle_BulletHail_Continue()
100 sw = self.switchweapon; // make it not detect weapon changes as reason to abort firing
101 af = ATTACK_FINISHED(self);
102 self.switchweapon = self.weapon;
103 ATTACK_FINISHED(self) = time;
104 print(ftos(self.ammo_nails), "\n");
105 r = weapon_prepareattack(self.sniperrifle_bullethail_frame == WFRAME_FIRE2, self.sniperrifle_bullethail_refire);
106 if(self.switchweapon == self.weapon)
107 self.switchweapon = sw;
110 self.sniperrifle_bullethail_attackfunc();
111 weapon_thinkf(self.sniperrifle_bullethail_frame, self.sniperrifle_bullethail_animtime, W_SniperRifle_BulletHail_Continue);
112 print("thinkf set\n");
116 ATTACK_FINISHED(self) = af; // reset attack_finished if we didn't fire, so the last shot enforces the refire time
117 print("out of ammo... ", ftos(self.weaponentity.state), "\n");
121 void W_SniperRifle_BulletHail(float mode, void(void) AttackFunc, float fr, float animtime, float refire)
123 // if we get here, we have at least one bullet to fire
128 self.sniperrifle_bullethail_attackfunc = AttackFunc;
129 self.sniperrifle_bullethail_frame = fr;
130 self.sniperrifle_bullethail_animtime = animtime;
131 self.sniperrifle_bullethail_refire = refire;
132 weapon_thinkf(fr, animtime, W_SniperRifle_BulletHail_Continue);
137 weapon_thinkf(fr, animtime, w_ready);
141 .float bot_secondary_sniperriflemooth;
142 float w_sniperrifle(float req)
148 self.BUTTON_ATCK=FALSE;
149 self.BUTTON_ATCK2=FALSE;
150 if(vlen(self.origin-self.enemy.origin) > 1000)
151 self.bot_secondary_sniperriflemooth = 0;
152 if(self.bot_secondary_sniperriflemooth == 0)
154 if(bot_aim(autocvar_g_balance_sniperrifle_primary_speed, 0, autocvar_g_balance_sniperrifle_primary_lifetime, TRUE))
156 self.BUTTON_ATCK = TRUE;
157 if(random() < 0.01) self.bot_secondary_sniperriflemooth = 1;
162 if(bot_aim(autocvar_g_balance_sniperrifle_secondary_speed, 0, autocvar_g_balance_sniperrifle_secondary_lifetime, TRUE))
164 self.BUTTON_ATCK2 = TRUE;
165 if(random() < 0.03) self.bot_secondary_sniperriflemooth = 0;
169 else if (req == WR_THINK)
171 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
172 W_SniperRifle_Reload();
175 self.sniperrifle_accumulator = bound(time - autocvar_g_balance_sniperrifle_bursttime, self.sniperrifle_accumulator, time);
176 if (self.BUTTON_ATCK)
177 if (weapon_prepareattack_check(0, autocvar_g_balance_sniperrifle_primary_refire))
178 if (time >= self.sniperrifle_accumulator + autocvar_g_balance_sniperrifle_primary_burstcost)
180 weapon_prepareattack_do(0, autocvar_g_balance_sniperrifle_primary_refire);
181 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);
182 self.sniperrifle_accumulator += autocvar_g_balance_sniperrifle_primary_burstcost;
184 if (self.BUTTON_ATCK2)
186 if (autocvar_g_balance_sniperrifle_secondary)
188 if(autocvar_g_balance_sniperrifle_secondary_reload)
189 W_SniperRifle_Reload();
192 if (weapon_prepareattack_check(1, autocvar_g_balance_sniperrifle_secondary_refire))
193 if (time >= self.sniperrifle_accumulator + autocvar_g_balance_sniperrifle_secondary_burstcost)
195 weapon_prepareattack_do(1, autocvar_g_balance_sniperrifle_secondary_refire);
196 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);
197 self.sniperrifle_accumulator += autocvar_g_balance_sniperrifle_secondary_burstcost;
204 else if (req == WR_PRECACHE)
206 precache_model ("models/weapons/g_campingrifle.md3");
207 precache_model ("models/weapons/v_campingrifle.md3");
208 precache_model ("models/weapons/h_campingrifle.iqm");
209 precache_sound ("weapons/campingrifle_fire.wav");
210 precache_sound ("weapons/campingrifle_fire2.wav");
211 precache_sound ("weapons/reload.wav");
213 else if (req == WR_SETUP)
215 weapon_setup(WEP_SNIPERRIFLE);
216 W_SniperRifle_SetAmmoCounter();
218 else if (req == WR_CHECKAMMO1)
220 ammo_amount = self.ammo_cells >= autocvar_g_balance_sniperrifle_primary_ammo;
221 ammo_amount += self.weapon_load[WEP_SNIPERRIFLE] >= autocvar_g_balance_sniperrifle_primary_ammo;
224 else if (req == WR_CHECKAMMO2)
226 ammo_amount = self.ammo_cells >= autocvar_g_balance_sniperrifle_secondary_ammo;
227 ammo_amount += self.weapon_load[WEP_SNIPERRIFLE] >= autocvar_g_balance_sniperrifle_secondary_ammo;
230 else if (req == WR_RESETPLAYER)
232 self.sniperrifle_accumulator = time - autocvar_g_balance_sniperrifle_bursttime;
234 // all weapons must be fully loaded when we spawn
235 self.weapon_load[WEP_SNIPERRIFLE] = autocvar_g_balance_sniperrifle_reload_ammo;
237 else if (req == WR_RELOAD)
239 W_SniperRifle_Reload();
245 float w_sniperrifle(float req)
247 if(req == WR_IMPACTEFFECT)
250 org2 = w_org + w_backoff * 2;
251 pointparticles(particleeffectnum("machinegun_impact"), org2, w_backoff * 1000, 1);
255 sound(self, CHAN_PROJECTILE, "weapons/ric1.wav", VOL_BASE, ATTN_NORM);
256 else if(w_random < 0.4)
257 sound(self, CHAN_PROJECTILE, "weapons/ric2.wav", VOL_BASE, ATTN_NORM);
258 else if(w_random < 0.5)
259 sound(self, CHAN_PROJECTILE, "weapons/ric3.wav", VOL_BASE, ATTN_NORM);
262 else if(req == WR_PRECACHE)
264 precache_sound("weapons/ric1.wav");
265 precache_sound("weapons/ric2.wav");
266 precache_sound("weapons/ric3.wav");
268 else if (req == WR_SUICIDEMESSAGE)
270 if(w_deathtype & HITTYPE_SECONDARY)
271 w_deathtypestring = _("%s shot themself automatically");
273 w_deathtypestring = _("%s sniped themself somehow");
275 else if (req == WR_KILLMESSAGE)
277 if(w_deathtype & HITTYPE_SECONDARY)
279 if(w_deathtype & HITTYPE_BOUNCE)
280 w_deathtypestring = _("%s failed to hide from %s's bullet hail");
282 w_deathtypestring = _("%s died in %s's bullet hail");
286 if(w_deathtype & HITTYPE_BOUNCE)
288 // TODO special headshot message here too?
289 w_deathtypestring = _("%s failed to hide from %s's rifle");
293 if(w_deathtype & HITTYPE_HEADSHOT)
294 w_deathtypestring = _("%s got hit in the head by %s");
296 w_deathtypestring = _("%s was sniped by %s");