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_DoReload()
14 if(W_SniperRifle_Reload(self.ammo_nails))
18 void W_SniperRifle_FireBullet(float pSpread, float pDamage, float pHeadshotAddedDamage, float pForce, float pSpeed, float pLifetime, float pAmmo, float deathtype, float pBulletConstant)
20 if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
21 self.ammo_nails -= pAmmo;
23 if(deathtype & HITTYPE_SECONDARY)
24 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);
26 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);
28 pointparticles(particleeffectnum("shotgun_muzzleflash"), w_shotorg, w_shotdir * 2000, 1);
30 if(self.BUTTON_ZOOM) // if zoomed, shoot from the eye
32 w_shotdir = v_forward;
33 w_shotorg = self.origin + self.view_ofs + ((w_shotorg - self.origin - self.view_ofs) * v_forward) * v_forward;
36 if(deathtype & HITTYPE_SECONDARY)
37 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);
39 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);
40 endFireBallisticBullet();
42 if (autocvar_g_casings >= 2)
43 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);
45 self.sniperrifle_bulletcounter = self.sniperrifle_bulletcounter - 1;
48 void W_SniperRifle_Attack()
50 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);
53 void W_SniperRifle_Attack2()
55 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);
58 void spawnfunc_weapon_sniperrifle (void)
60 weapon_defaultspawnfunc(WEP_SNIPERRIFLE);
63 // compatibility alias
64 void spawnfunc_weapon_campingrifle (void)
66 spawnfunc_weapon_sniperrifle();
69 .void(void) sniperrifle_bullethail_attackfunc;
70 .float sniperrifle_bullethail_frame;
71 .float sniperrifle_bullethail_animtime;
72 .float sniperrifle_bullethail_refire;
73 void W_SniperRifle_BulletHail_Continue()
76 if(self.sniperrifle_bulletcounter <= 0)
77 W_SniperRifle_DoReload();
78 if(self.sniperrifle_bulletcounter < 0)
79 return; // reloading, so we are done
80 sw = self.switchweapon; // make it not detect weapon changes as reason to abort firing
81 af = ATTACK_FINISHED(self);
82 self.switchweapon = self.weapon;
83 ATTACK_FINISHED(self) = time;
84 print(ftos(self.ammo_nails), "\n");
85 r = weapon_prepareattack(self.sniperrifle_bullethail_frame == WFRAME_FIRE2, self.sniperrifle_bullethail_refire);
86 if(self.switchweapon == self.weapon)
87 self.switchweapon = sw;
90 self.sniperrifle_bullethail_attackfunc();
91 weapon_thinkf(self.sniperrifle_bullethail_frame, self.sniperrifle_bullethail_animtime, W_SniperRifle_BulletHail_Continue);
92 print("thinkf set\n");
96 ATTACK_FINISHED(self) = af; // reset attack_finished if we didn't fire, so the last shot enforces the refire time
97 print("out of ammo... ", ftos(self.weaponentity.state), "\n");
101 void W_SniperRifle_BulletHail(float mode, void(void) AttackFunc, float fr, float animtime, float refire)
103 // if we get here, we have at least one bullet to fire
108 self.sniperrifle_bullethail_attackfunc = AttackFunc;
109 self.sniperrifle_bullethail_frame = fr;
110 self.sniperrifle_bullethail_animtime = animtime;
111 self.sniperrifle_bullethail_refire = refire;
112 weapon_thinkf(fr, animtime, W_SniperRifle_BulletHail_Continue);
117 weapon_thinkf(fr, animtime, w_ready);
121 .float bot_secondary_sniperriflemooth;
122 float w_sniperrifle(float req)
127 self.BUTTON_ATCK=FALSE;
128 self.BUTTON_ATCK2=FALSE;
129 if(vlen(self.origin-self.enemy.origin) > 1000)
130 self.bot_secondary_sniperriflemooth = 0;
131 if(self.bot_secondary_sniperriflemooth == 0)
133 if(bot_aim(autocvar_g_balance_sniperrifle_primary_speed, 0, autocvar_g_balance_sniperrifle_primary_lifetime, TRUE))
135 self.BUTTON_ATCK = TRUE;
136 if(random() < 0.01) self.bot_secondary_sniperriflemooth = 1;
141 if(bot_aim(autocvar_g_balance_sniperrifle_secondary_speed, 0, autocvar_g_balance_sniperrifle_secondary_lifetime, TRUE))
143 self.BUTTON_ATCK2 = TRUE;
144 if(random() < 0.03) self.bot_secondary_sniperriflemooth = 0;
148 else if (req == WR_THINK)
150 if(self.sniperrifle_bulletcounter < 0) // forced reload (e.g. because interrupted)
152 self.wish_reload = 1;
156 self.sniperrifle_accumulator = bound(time - autocvar_g_balance_sniperrifle_bursttime, self.sniperrifle_accumulator, time);
157 if (self.BUTTON_ATCK)
158 if (weapon_prepareattack_check(0, autocvar_g_balance_sniperrifle_primary_refire))
159 if (time >= self.sniperrifle_accumulator + autocvar_g_balance_sniperrifle_primary_burstcost)
161 weapon_prepareattack_do(0, autocvar_g_balance_sniperrifle_primary_refire);
162 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);
163 self.sniperrifle_accumulator += autocvar_g_balance_sniperrifle_primary_burstcost;
165 if (self.BUTTON_ATCK2)
167 if (autocvar_g_balance_sniperrifle_secondary)
169 if(autocvar_g_balance_sniperrifle_secondary_reload)
170 self.wish_reload = 1;
173 if (weapon_prepareattack_check(1, autocvar_g_balance_sniperrifle_secondary_refire))
174 if (time >= self.sniperrifle_accumulator + autocvar_g_balance_sniperrifle_secondary_burstcost)
176 weapon_prepareattack_do(1, autocvar_g_balance_sniperrifle_secondary_refire);
177 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);
178 self.sniperrifle_accumulator += autocvar_g_balance_sniperrifle_secondary_burstcost;
186 if(self.switchweapon == self.weapon)
188 if(self.weaponentity.state == WS_READY)
190 self.wish_reload = 0;
191 W_SniperRifle_Reload(self.ammo_nails);
196 else if (req == WR_PRECACHE)
198 precache_model ("models/weapons/g_campingrifle.md3");
199 precache_model ("models/weapons/v_campingrifle.md3");
200 precache_model ("models/weapons/h_campingrifle.iqm");
201 precache_sound ("weapons/campingrifle_reload.wav");
202 precache_sound ("weapons/campingrifle_fire.wav");
203 precache_sound ("weapons/campingrifle_fire2.wav");
205 else if (req == WR_SETUP)
207 weapon_setup(WEP_SNIPERRIFLE);
209 full = W_SniperRifle_CheckMaxBullets(TRUE);
210 if(autocvar_g_balance_sniperrifle_auto_reload_on_switch)
212 self.sniperrifle_bulletcounter = -1;
214 else if (req == WR_CHECKAMMO1)
215 return self.ammo_nails >= autocvar_g_balance_sniperrifle_primary_ammo;
216 else if (req == WR_CHECKAMMO2)
217 return self.ammo_nails >= autocvar_g_balance_sniperrifle_secondary_ammo;
218 else if (req == WR_RELOAD)
220 self.wish_reload = 1;
222 else if (req == WR_RESETPLAYER)
224 self.sniperrifle_accumulator = time - autocvar_g_balance_sniperrifle_bursttime;
225 self.sniperrifle_bulletcounter = autocvar_g_balance_sniperrifle_magazinecapacity;
226 W_SniperRifle_CheckMaxBullets(FALSE);
232 float w_sniperrifle(float req)
234 if(req == WR_IMPACTEFFECT)
237 org2 = w_org + w_backoff * 2;
238 pointparticles(particleeffectnum("machinegun_impact"), org2, w_backoff * 1000, 1);
242 sound(self, CHAN_PROJECTILE, "weapons/ric1.wav", VOL_BASE, ATTN_NORM);
243 else if(w_random < 0.4)
244 sound(self, CHAN_PROJECTILE, "weapons/ric2.wav", VOL_BASE, ATTN_NORM);
245 else if(w_random < 0.5)
246 sound(self, CHAN_PROJECTILE, "weapons/ric3.wav", VOL_BASE, ATTN_NORM);
249 else if(req == WR_PRECACHE)
251 precache_sound("weapons/ric1.wav");
252 precache_sound("weapons/ric2.wav");
253 precache_sound("weapons/ric3.wav");
255 else if (req == WR_SUICIDEMESSAGE)
257 if(w_deathtype & HITTYPE_SECONDARY)
258 w_deathtypestring = "%s shot themself automatically";
260 w_deathtypestring = "%s sniped themself somehow";
262 else if (req == WR_KILLMESSAGE)
264 if(w_deathtype & HITTYPE_SECONDARY)
266 if(w_deathtype & HITTYPE_BOUNCE)
267 w_deathtypestring = "%s failed to hide from %s's bullet hail";
269 w_deathtypestring = "%s died in %s's bullet hail";
273 if(w_deathtype & HITTYPE_BOUNCE)
275 // TODO special headshot message here too?
276 w_deathtypestring = "%s failed to hide from %s's rifle";
280 if(w_deathtype & HITTYPE_HEADSHOT)
281 w_deathtypestring = "%s got hit in the head by %s";
283 w_deathtypestring = "%s was sniped by %s";