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 W_DecreaseAmmo(ammo_nails, pAmmo, autocvar_g_balance_sniperrifle_reload_ammo);
15 if(deathtype & HITTYPE_SECONDARY)
16 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);
18 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);
20 pointparticles(particleeffectnum("sniperrifle_muzzleflash"), w_shotorg, w_shotdir * 2000, 1);
22 if(self.BUTTON_ZOOM) // if zoomed, shoot from the eye
24 w_shotdir = v_forward;
25 w_shotorg = self.origin + self.view_ofs + ((w_shotorg - self.origin - self.view_ofs) * v_forward) * v_forward;
28 if(deathtype & HITTYPE_SECONDARY)
29 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);
31 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);
32 endFireBallisticBullet();
34 if (autocvar_g_casings >= 2)
35 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);
38 void W_SniperRifle_Attack()
40 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);
43 void W_SniperRifle_Attack2()
45 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);
48 void spawnfunc_weapon_sniperrifle (void)
50 weapon_defaultspawnfunc(WEP_SNIPERRIFLE);
53 // compatibility alias
54 void spawnfunc_weapon_campingrifle (void)
56 spawnfunc_weapon_sniperrifle();
59 .void(void) sniperrifle_bullethail_attackfunc;
60 .float sniperrifle_bullethail_frame;
61 .float sniperrifle_bullethail_animtime;
62 .float sniperrifle_bullethail_refire;
63 void W_SniperRifle_BulletHail_Continue()
67 sw = self.switchweapon; // make it not detect weapon changes as reason to abort firing
68 af = ATTACK_FINISHED(self);
69 self.switchweapon = self.weapon;
70 ATTACK_FINISHED(self) = time;
71 print(ftos(self.ammo_nails), "\n");
72 r = weapon_prepareattack(self.sniperrifle_bullethail_frame == WFRAME_FIRE2, self.sniperrifle_bullethail_refire);
73 if(self.switchweapon == self.weapon)
74 self.switchweapon = sw;
77 self.sniperrifle_bullethail_attackfunc();
78 weapon_thinkf(self.sniperrifle_bullethail_frame, self.sniperrifle_bullethail_animtime, W_SniperRifle_BulletHail_Continue);
79 print("thinkf set\n");
83 ATTACK_FINISHED(self) = af; // reset attack_finished if we didn't fire, so the last shot enforces the refire time
84 print("out of ammo... ", ftos(self.weaponentity.state), "\n");
88 void W_SniperRifle_BulletHail(float mode, void(void) AttackFunc, float fr, float animtime, float refire)
90 // if we get here, we have at least one bullet to fire
95 self.sniperrifle_bullethail_attackfunc = AttackFunc;
96 self.sniperrifle_bullethail_frame = fr;
97 self.sniperrifle_bullethail_animtime = animtime;
98 self.sniperrifle_bullethail_refire = refire;
99 weapon_thinkf(fr, animtime, W_SniperRifle_BulletHail_Continue);
104 weapon_thinkf(fr, animtime, w_ready);
108 .float bot_secondary_sniperriflemooth;
109 float w_sniperrifle(float req)
115 self.BUTTON_ATCK=FALSE;
116 self.BUTTON_ATCK2=FALSE;
117 if(vlen(self.origin-self.enemy.origin) > 1000)
118 self.bot_secondary_sniperriflemooth = 0;
119 if(self.bot_secondary_sniperriflemooth == 0)
121 if(bot_aim(autocvar_g_balance_sniperrifle_primary_speed, 0, autocvar_g_balance_sniperrifle_primary_lifetime, TRUE))
123 self.BUTTON_ATCK = TRUE;
124 if(random() < 0.01) self.bot_secondary_sniperriflemooth = 1;
129 if(bot_aim(autocvar_g_balance_sniperrifle_secondary_speed, 0, autocvar_g_balance_sniperrifle_secondary_lifetime, TRUE))
131 self.BUTTON_ATCK2 = TRUE;
132 if(random() < 0.03) self.bot_secondary_sniperriflemooth = 0;
136 else if (req == WR_THINK)
138 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
139 weapon_action(self.weapon, WR_RELOAD);
142 self.sniperrifle_accumulator = bound(time - autocvar_g_balance_sniperrifle_bursttime, self.sniperrifle_accumulator, time);
143 if (self.BUTTON_ATCK)
144 if (weapon_prepareattack_check(0, autocvar_g_balance_sniperrifle_primary_refire))
145 if (time >= self.sniperrifle_accumulator + autocvar_g_balance_sniperrifle_primary_burstcost)
147 weapon_prepareattack_do(0, autocvar_g_balance_sniperrifle_primary_refire);
148 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);
149 self.sniperrifle_accumulator += autocvar_g_balance_sniperrifle_primary_burstcost;
151 if (self.BUTTON_ATCK2)
153 if (autocvar_g_balance_sniperrifle_secondary)
155 if(autocvar_g_balance_sniperrifle_secondary_reload)
156 weapon_action(self.weapon, WR_RELOAD);
159 if (weapon_prepareattack_check(1, autocvar_g_balance_sniperrifle_secondary_refire))
160 if (time >= self.sniperrifle_accumulator + autocvar_g_balance_sniperrifle_secondary_burstcost)
162 weapon_prepareattack_do(1, autocvar_g_balance_sniperrifle_secondary_refire);
163 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);
164 self.sniperrifle_accumulator += autocvar_g_balance_sniperrifle_secondary_burstcost;
171 else if (req == WR_PRECACHE)
173 precache_model ("models/weapons/g_campingrifle.md3");
174 precache_model ("models/weapons/v_campingrifle.md3");
175 precache_model ("models/weapons/h_campingrifle.iqm");
176 precache_sound ("weapons/campingrifle_fire.wav");
177 precache_sound ("weapons/campingrifle_fire2.wav");
178 //precache_sound ("weapons/reload.wav"); // until weapons have individual reload sounds, precache the reload sound somewhere else
180 else if (req == WR_SETUP)
182 weapon_setup(WEP_SNIPERRIFLE);
183 self.current_ammo = ammo_nails;
185 else if (req == WR_CHECKAMMO1)
187 ammo_amount = self.ammo_nails >= autocvar_g_balance_sniperrifle_primary_ammo;
188 ammo_amount += self.weapon_load[WEP_SNIPERRIFLE] >= autocvar_g_balance_sniperrifle_primary_ammo;
191 else if (req == WR_CHECKAMMO2)
193 ammo_amount = self.ammo_nails >= autocvar_g_balance_sniperrifle_secondary_ammo;
194 ammo_amount += self.weapon_load[WEP_SNIPERRIFLE] >= autocvar_g_balance_sniperrifle_secondary_ammo;
197 else if (req == WR_RESETPLAYER)
199 self.sniperrifle_accumulator = time - autocvar_g_balance_sniperrifle_bursttime;
201 else if (req == WR_RELOAD)
203 W_Reload(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");
209 float w_sniperrifle(float req)
211 if(req == WR_IMPACTEFFECT)
214 org2 = w_org + w_backoff * 2;
215 pointparticles(particleeffectnum("machinegun_impact"), org2, w_backoff * 1000, 1);
219 sound(self, CHAN_PROJECTILE, "weapons/ric1.wav", VOL_BASE, ATTN_NORM);
220 else if(w_random < 0.4)
221 sound(self, CHAN_PROJECTILE, "weapons/ric2.wav", VOL_BASE, ATTN_NORM);
222 else if(w_random < 0.5)
223 sound(self, CHAN_PROJECTILE, "weapons/ric3.wav", VOL_BASE, ATTN_NORM);
226 else if(req == WR_PRECACHE)
228 precache_sound("weapons/ric1.wav");
229 precache_sound("weapons/ric2.wav");
230 precache_sound("weapons/ric3.wav");
232 else if (req == WR_SUICIDEMESSAGE)
234 if(w_deathtype & HITTYPE_SECONDARY)
235 w_deathtypestring = _("%s shot themself automatically");
237 w_deathtypestring = _("%s sniped themself somehow");
239 else if (req == WR_KILLMESSAGE)
241 if(w_deathtype & HITTYPE_SECONDARY)
243 if(w_deathtype & HITTYPE_BOUNCE)
244 w_deathtypestring = _("%s failed to hide from %s's bullet hail");
246 w_deathtypestring = _("%s died in %s's bullet hail");
250 if(w_deathtype & HITTYPE_BOUNCE)
252 // TODO special headshot message here too?
253 w_deathtypestring = _("%s failed to hide from %s's rifle");
257 if(w_deathtype & HITTYPE_HEADSHOT)
258 w_deathtypestring = _("%s got hit in the head by %s");
260 w_deathtypestring = _("%s was sniped by %s");