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_FireBullet(float pSpread, float pDamage, float pHeadshotAddedDamage, float pForce, float pSpeed, float pLifetime, float pAmmo, float deathtype, float pBulletConstant)
13 // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
14 if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
16 if(autocvar_g_balance_sniperrifle_reload_ammo)
18 self.clip_load -= pAmmo;
19 self.weapon_load[WEP_SNIPERRIFLE] = self.clip_load;
22 self.ammo_nails -= pAmmo;
25 if(deathtype & HITTYPE_SECONDARY)
26 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);
28 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);
30 pointparticles(particleeffectnum("sniperrifle_muzzleflash"), w_shotorg, w_shotdir * 2000, 1);
32 if(self.BUTTON_ZOOM) // if zoomed, shoot from the eye
34 w_shotdir = v_forward;
35 w_shotorg = self.origin + self.view_ofs + ((w_shotorg - self.origin - self.view_ofs) * v_forward) * v_forward;
38 if(deathtype & HITTYPE_SECONDARY)
39 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);
41 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);
42 endFireBallisticBullet();
44 if (autocvar_g_casings >= 2)
45 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);
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()
77 sw = self.switchweapon; // make it not detect weapon changes as reason to abort firing
78 af = ATTACK_FINISHED(self);
79 self.switchweapon = self.weapon;
80 ATTACK_FINISHED(self) = time;
81 print(ftos(self.ammo_nails), "\n");
82 r = weapon_prepareattack(self.sniperrifle_bullethail_frame == WFRAME_FIRE2, self.sniperrifle_bullethail_refire);
83 if(self.switchweapon == self.weapon)
84 self.switchweapon = sw;
87 self.sniperrifle_bullethail_attackfunc();
88 weapon_thinkf(self.sniperrifle_bullethail_frame, self.sniperrifle_bullethail_animtime, W_SniperRifle_BulletHail_Continue);
89 print("thinkf set\n");
93 ATTACK_FINISHED(self) = af; // reset attack_finished if we didn't fire, so the last shot enforces the refire time
94 print("out of ammo... ", ftos(self.weaponentity.state), "\n");
98 void W_SniperRifle_BulletHail(float mode, void(void) AttackFunc, float fr, float animtime, float refire)
100 // if we get here, we have at least one bullet to fire
105 self.sniperrifle_bullethail_attackfunc = AttackFunc;
106 self.sniperrifle_bullethail_frame = fr;
107 self.sniperrifle_bullethail_animtime = animtime;
108 self.sniperrifle_bullethail_refire = refire;
109 weapon_thinkf(fr, animtime, W_SniperRifle_BulletHail_Continue);
114 weapon_thinkf(fr, animtime, w_ready);
118 .float bot_secondary_sniperriflemooth;
119 float w_sniperrifle(float req)
125 self.BUTTON_ATCK=FALSE;
126 self.BUTTON_ATCK2=FALSE;
127 if(vlen(self.origin-self.enemy.origin) > 1000)
128 self.bot_secondary_sniperriflemooth = 0;
129 if(self.bot_secondary_sniperriflemooth == 0)
131 if(bot_aim(autocvar_g_balance_sniperrifle_primary_speed, 0, autocvar_g_balance_sniperrifle_primary_lifetime, TRUE))
133 self.BUTTON_ATCK = TRUE;
134 if(random() < 0.01) self.bot_secondary_sniperriflemooth = 1;
139 if(bot_aim(autocvar_g_balance_sniperrifle_secondary_speed, 0, autocvar_g_balance_sniperrifle_secondary_lifetime, TRUE))
141 self.BUTTON_ATCK2 = TRUE;
142 if(random() < 0.03) self.bot_secondary_sniperriflemooth = 0;
146 else if (req == WR_THINK)
148 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
149 weapon_action(self.weapon, WR_RELOAD);
152 self.sniperrifle_accumulator = bound(time - autocvar_g_balance_sniperrifle_bursttime, self.sniperrifle_accumulator, time);
153 if (self.BUTTON_ATCK)
154 if (weapon_prepareattack_check(0, autocvar_g_balance_sniperrifle_primary_refire))
155 if (time >= self.sniperrifle_accumulator + autocvar_g_balance_sniperrifle_primary_burstcost)
157 weapon_prepareattack_do(0, autocvar_g_balance_sniperrifle_primary_refire);
158 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);
159 self.sniperrifle_accumulator += autocvar_g_balance_sniperrifle_primary_burstcost;
161 if (self.BUTTON_ATCK2)
163 if (autocvar_g_balance_sniperrifle_secondary)
165 if(autocvar_g_balance_sniperrifle_secondary_reload)
166 weapon_action(self.weapon, WR_RELOAD);
169 if (weapon_prepareattack_check(1, autocvar_g_balance_sniperrifle_secondary_refire))
170 if (time >= self.sniperrifle_accumulator + autocvar_g_balance_sniperrifle_secondary_burstcost)
172 weapon_prepareattack_do(1, autocvar_g_balance_sniperrifle_secondary_refire);
173 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);
174 self.sniperrifle_accumulator += autocvar_g_balance_sniperrifle_secondary_burstcost;
181 else if (req == WR_PRECACHE)
183 precache_model ("models/weapons/g_campingrifle.md3");
184 precache_model ("models/weapons/v_campingrifle.md3");
185 precache_model ("models/weapons/h_campingrifle.iqm");
186 precache_sound ("weapons/campingrifle_fire.wav");
187 precache_sound ("weapons/campingrifle_fire2.wav");
188 precache_sound ("weapons/reload.wav");
190 else if (req == WR_SETUP)
192 weapon_setup(WEP_SNIPERRIFLE);
194 else if (req == WR_CHECKAMMO1)
196 ammo_amount = self.ammo_nails >= autocvar_g_balance_sniperrifle_primary_ammo;
197 ammo_amount += self.weapon_load[WEP_SNIPERRIFLE] >= autocvar_g_balance_sniperrifle_primary_ammo;
200 else if (req == WR_CHECKAMMO2)
202 ammo_amount = self.ammo_nails >= autocvar_g_balance_sniperrifle_secondary_ammo;
203 ammo_amount += self.weapon_load[WEP_SNIPERRIFLE] >= autocvar_g_balance_sniperrifle_secondary_ammo;
206 else if (req == WR_RESETPLAYER)
208 self.sniperrifle_accumulator = time - autocvar_g_balance_sniperrifle_bursttime;
210 else if (req == WR_RELOAD)
212 W_Reload(ammo_nails, min(autocvar_g_balance_sniperrifle_primary_ammo, autocvar_g_balance_sniperrifle_secondary_ammo), autocvar_g_balance_sniperrifle_reload_ammo, autocvar_g_balance_sniperrifle_reload_time, "weapons/reload.wav");
218 float w_sniperrifle(float req)
220 if(req == WR_IMPACTEFFECT)
223 org2 = w_org + w_backoff * 2;
224 pointparticles(particleeffectnum("machinegun_impact"), org2, w_backoff * 1000, 1);
228 sound(self, CHAN_PROJECTILE, "weapons/ric1.wav", VOL_BASE, ATTN_NORM);
229 else if(w_random < 0.4)
230 sound(self, CHAN_PROJECTILE, "weapons/ric2.wav", VOL_BASE, ATTN_NORM);
231 else if(w_random < 0.5)
232 sound(self, CHAN_PROJECTILE, "weapons/ric3.wav", VOL_BASE, ATTN_NORM);
235 else if(req == WR_PRECACHE)
237 precache_sound("weapons/ric1.wav");
238 precache_sound("weapons/ric2.wav");
239 precache_sound("weapons/ric3.wav");
241 else if (req == WR_SUICIDEMESSAGE)
243 if(w_deathtype & HITTYPE_SECONDARY)
244 w_deathtypestring = _("%s shot themself automatically");
246 w_deathtypestring = _("%s sniped themself somehow");
248 else if (req == WR_KILLMESSAGE)
250 if(w_deathtype & HITTYPE_SECONDARY)
252 if(w_deathtype & HITTYPE_BOUNCE)
253 w_deathtypestring = _("%s failed to hide from %s's bullet hail");
255 w_deathtypestring = _("%s died in %s's bullet hail");
259 if(w_deathtype & HITTYPE_BOUNCE)
261 // TODO special headshot message here too?
262 w_deathtypestring = _("%s failed to hide from %s's rifle");
266 if(w_deathtype & HITTYPE_HEADSHOT)
267 w_deathtypestring = _("%s got hit in the head by %s");
269 w_deathtypestring = _("%s was sniped by %s");