2 REGISTER_WEAPON(SNIPERRIFLE, w_sniperrifle, IT_NAILS, 7, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | 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_Reload()
13 self.reload_ammo_player = ammo_nails;
14 self.reload_ammo_min = min(autocvar_g_balance_sniperrifle_primary_ammo, autocvar_g_balance_sniperrifle_secondary_ammo);
15 self.reload_ammo_amount = autocvar_g_balance_sniperrifle_reload_ammo;
16 self.reload_time = autocvar_g_balance_sniperrifle_reload_time;
17 self.reload_sound = "weapons/reload.wav";
22 void W_SniperRifle_FireBullet(float pSpread, float pDamage, float pHeadshotAddedDamage, float pForce, float pSpeed, float pLifetime, float pAmmo, float deathtype, float pBulletConstant)
24 // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
25 if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
27 if(autocvar_g_balance_sniperrifle_reload_ammo)
29 self.clip_load -= pAmmo;
30 self.weapon_load[WEP_SNIPERRIFLE] = self.clip_load;
33 self.ammo_nails -= pAmmo;
36 if(deathtype & HITTYPE_SECONDARY)
37 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);
39 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);
41 pointparticles(particleeffectnum("sniperrifle_muzzleflash"), w_shotorg, w_shotdir * 2000, 1);
43 if(self.BUTTON_ZOOM) // if zoomed, shoot from the eye
45 w_shotdir = v_forward;
46 w_shotorg = self.origin + self.view_ofs + ((w_shotorg - self.origin - self.view_ofs) * v_forward) * v_forward;
49 if(deathtype & HITTYPE_SECONDARY)
50 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);
52 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);
53 endFireBallisticBullet();
55 if (autocvar_g_casings >= 2)
56 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);
59 void W_SniperRifle_Attack()
61 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);
64 void W_SniperRifle_Attack2()
66 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);
69 void spawnfunc_weapon_sniperrifle (void)
71 weapon_defaultspawnfunc(WEP_SNIPERRIFLE);
74 // compatibility alias
75 void spawnfunc_weapon_campingrifle (void)
77 spawnfunc_weapon_sniperrifle();
80 .void(void) sniperrifle_bullethail_attackfunc;
81 .float sniperrifle_bullethail_frame;
82 .float sniperrifle_bullethail_animtime;
83 .float sniperrifle_bullethail_refire;
84 void W_SniperRifle_BulletHail_Continue()
88 sw = self.switchweapon; // make it not detect weapon changes as reason to abort firing
89 af = ATTACK_FINISHED(self);
90 self.switchweapon = self.weapon;
91 ATTACK_FINISHED(self) = time;
92 print(ftos(self.ammo_nails), "\n");
93 r = weapon_prepareattack(self.sniperrifle_bullethail_frame == WFRAME_FIRE2, self.sniperrifle_bullethail_refire);
94 if(self.switchweapon == self.weapon)
95 self.switchweapon = sw;
98 self.sniperrifle_bullethail_attackfunc();
99 weapon_thinkf(self.sniperrifle_bullethail_frame, self.sniperrifle_bullethail_animtime, W_SniperRifle_BulletHail_Continue);
100 print("thinkf set\n");
104 ATTACK_FINISHED(self) = af; // reset attack_finished if we didn't fire, so the last shot enforces the refire time
105 print("out of ammo... ", ftos(self.weaponentity.state), "\n");
109 void W_SniperRifle_BulletHail(float mode, void(void) AttackFunc, float fr, float animtime, float refire)
111 // if we get here, we have at least one bullet to fire
116 self.sniperrifle_bullethail_attackfunc = AttackFunc;
117 self.sniperrifle_bullethail_frame = fr;
118 self.sniperrifle_bullethail_animtime = animtime;
119 self.sniperrifle_bullethail_refire = refire;
120 weapon_thinkf(fr, animtime, W_SniperRifle_BulletHail_Continue);
125 weapon_thinkf(fr, animtime, w_ready);
129 .float bot_secondary_sniperriflemooth;
130 float w_sniperrifle(float req)
136 self.BUTTON_ATCK=FALSE;
137 self.BUTTON_ATCK2=FALSE;
138 if(vlen(self.origin-self.enemy.origin) > 1000)
139 self.bot_secondary_sniperriflemooth = 0;
140 if(self.bot_secondary_sniperriflemooth == 0)
142 if(bot_aim(autocvar_g_balance_sniperrifle_primary_speed, 0, autocvar_g_balance_sniperrifle_primary_lifetime, TRUE))
144 self.BUTTON_ATCK = TRUE;
145 if(random() < 0.01) self.bot_secondary_sniperriflemooth = 1;
150 if(bot_aim(autocvar_g_balance_sniperrifle_secondary_speed, 0, autocvar_g_balance_sniperrifle_secondary_lifetime, TRUE))
152 self.BUTTON_ATCK2 = TRUE;
153 if(random() < 0.03) self.bot_secondary_sniperriflemooth = 0;
157 else if (req == WR_THINK)
159 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
160 W_SniperRifle_Reload();
163 self.sniperrifle_accumulator = bound(time - autocvar_g_balance_sniperrifle_bursttime, self.sniperrifle_accumulator, time);
164 if (self.BUTTON_ATCK)
165 if (weapon_prepareattack_check(0, autocvar_g_balance_sniperrifle_primary_refire))
166 if (time >= self.sniperrifle_accumulator + autocvar_g_balance_sniperrifle_primary_burstcost)
168 weapon_prepareattack_do(0, autocvar_g_balance_sniperrifle_primary_refire);
169 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);
170 self.sniperrifle_accumulator += autocvar_g_balance_sniperrifle_primary_burstcost;
172 if (self.BUTTON_ATCK2)
174 if (autocvar_g_balance_sniperrifle_secondary)
176 if(autocvar_g_balance_sniperrifle_secondary_reload)
177 W_SniperRifle_Reload();
180 if (weapon_prepareattack_check(1, autocvar_g_balance_sniperrifle_secondary_refire))
181 if (time >= self.sniperrifle_accumulator + autocvar_g_balance_sniperrifle_secondary_burstcost)
183 weapon_prepareattack_do(1, autocvar_g_balance_sniperrifle_secondary_refire);
184 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);
185 self.sniperrifle_accumulator += autocvar_g_balance_sniperrifle_secondary_burstcost;
192 else if (req == WR_PRECACHE)
194 precache_model ("models/weapons/g_campingrifle.md3");
195 precache_model ("models/weapons/v_campingrifle.md3");
196 precache_model ("models/weapons/h_campingrifle.iqm");
197 precache_sound ("weapons/campingrifle_fire.wav");
198 precache_sound ("weapons/campingrifle_fire2.wav");
199 precache_sound ("weapons/reload.wav");
201 else if (req == WR_SETUP)
203 weapon_setup(WEP_SNIPERRIFLE);
205 else if (req == WR_CHECKAMMO1)
207 ammo_amount = self.ammo_cells >= autocvar_g_balance_sniperrifle_primary_ammo;
208 ammo_amount += self.weapon_load[WEP_SNIPERRIFLE] >= autocvar_g_balance_sniperrifle_primary_ammo;
211 else if (req == WR_CHECKAMMO2)
213 ammo_amount = self.ammo_cells >= autocvar_g_balance_sniperrifle_secondary_ammo;
214 ammo_amount += self.weapon_load[WEP_SNIPERRIFLE] >= autocvar_g_balance_sniperrifle_secondary_ammo;
217 else if (req == WR_RESETPLAYER)
219 self.sniperrifle_accumulator = time - autocvar_g_balance_sniperrifle_bursttime;
221 else if (req == WR_RELOAD)
223 W_SniperRifle_Reload();
229 float w_sniperrifle(float req)
231 if(req == WR_IMPACTEFFECT)
234 org2 = w_org + w_backoff * 2;
235 pointparticles(particleeffectnum("machinegun_impact"), org2, w_backoff * 1000, 1);
239 sound(self, CHAN_PROJECTILE, "weapons/ric1.wav", VOL_BASE, ATTN_NORM);
240 else if(w_random < 0.4)
241 sound(self, CHAN_PROJECTILE, "weapons/ric2.wav", VOL_BASE, ATTN_NORM);
242 else if(w_random < 0.5)
243 sound(self, CHAN_PROJECTILE, "weapons/ric3.wav", VOL_BASE, ATTN_NORM);
246 else if(req == WR_PRECACHE)
248 precache_sound("weapons/ric1.wav");
249 precache_sound("weapons/ric2.wav");
250 precache_sound("weapons/ric3.wav");
252 else if (req == WR_SUICIDEMESSAGE)
254 if(w_deathtype & HITTYPE_SECONDARY)
255 w_deathtypestring = _("%s shot themself automatically");
257 w_deathtypestring = _("%s sniped themself somehow");
259 else if (req == WR_KILLMESSAGE)
261 if(w_deathtype & HITTYPE_SECONDARY)
263 if(w_deathtype & HITTYPE_BOUNCE)
264 w_deathtypestring = _("%s failed to hide from %s's bullet hail");
266 w_deathtypestring = _("%s died in %s's bullet hail");
270 if(w_deathtype & HITTYPE_BOUNCE)
272 // TODO special headshot message here too?
273 w_deathtypestring = _("%s failed to hide from %s's rifle");
277 if(w_deathtype & HITTYPE_HEADSHOT)
278 w_deathtypestring = _("%s got hit in the head by %s");
280 w_deathtypestring = _("%s was sniped by %s");