2 REGISTER_WEAPON(CAMPINGRIFLE, w_campingrifle, IT_NAILS, 3, WEP_FLAG_NORMAL | WEP_TYPE_HITSCAN, BOT_PICKUP_RATING_MID, "campingrifle", "campingrifle", "Rifle");
5 //Camping 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 campingrifle_accumulator;
11 float W_CampingRifle_CheckMaxBullets(float checkammo)
14 maxbulls = cvar("g_balance_campingrifle_magazinecapacity");
16 maxbulls = 8; // match HUD
18 if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
19 maxbulls = min(maxbulls, floor(self.ammo_nails / min(cvar("g_balance_campingrifle_primary_ammo"), cvar("g_balance_campingrifle_secondary_ammo"))));
20 if(self.campingrifle_bulletcounter > maxbulls || !cvar("g_balance_campingrifle_magazinecapacity"))
21 self.campingrifle_bulletcounter = maxbulls;
22 return (self.campingrifle_bulletcounter == maxbulls);
25 void W_CampingRifle_ReloadedAndReady()
28 self.campingrifle_bulletcounter = cvar("g_balance_campingrifle_magazinecapacity");
29 W_CampingRifle_CheckMaxBullets(TRUE);
30 t = ATTACK_FINISHED(self) - cvar("g_balance_campingrifle_reloadtime") - 1;
31 ATTACK_FINISHED(self) = t;
35 float W_CampingRifle_Reload()
39 W_CampingRifle_CheckMaxBullets(TRUE);
41 if(self.ammo_nails < min(cvar("g_balance_campingrifle_primary_ammo"), cvar("g_balance_campingrifle_secondary_ammo"))) // when we get here, bulletcounter must be 0 or -1
43 print("cannot reload... not enough bullets\n");
44 self.campingrifle_bulletcounter = -1; // reload later
45 W_SwitchToOtherWeapon(self);
49 if (self.campingrifle_bulletcounter >= cvar("g_balance_campingrifle_magazinecapacity"))
52 if (self.weaponentity)
54 if (self.weaponentity.wframe == WFRAME_RELOAD)
57 // allow to switch away while reloading, but this will cause a new reload!
58 self.weaponentity.state = WS_READY;
61 sound (self, CHAN_WEAPON2, "weapons/campingrifle_reload.wav", VOL_BASE, ATTN_NORM);
63 t = max(time, ATTACK_FINISHED(self)) + cvar("g_balance_campingrifle_reloadtime") + 1;
64 ATTACK_FINISHED(self) = t;
66 weapon_thinkf(WFRAME_RELOAD, cvar("g_balance_campingrifle_reloadtime"), W_CampingRifle_ReloadedAndReady);
68 self.campingrifle_bulletcounter = -1;
73 void W_CampingRifle_CheckReloadAndReady()
76 if(self.campingrifle_bulletcounter <= 0)
77 if(W_CampingRifle_Reload())
81 void W_CampingRifle_FireBullet(float pSpread, float pDamage, float pHeadshotAddedDamage, float pForce, float pSpeed, float pLifetime, float pAmmo, float deathtype, float pBulletConstant)
83 if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
84 self.ammo_nails -= pAmmo;
86 if(deathtype & HITTYPE_SECONDARY)
87 W_SetupShot (self, cvar("g_antilag_bullets") && pSpeed >= cvar("g_antilag_bullets"), 2, "weapons/campingrifle_fire2.wav", cvar("g_balance_campingrifle_secondary_damage"));
89 W_SetupShot (self, cvar("g_antilag_bullets") && pSpeed >= cvar("g_antilag_bullets"), 2, "weapons/campingrifle_fire.wav", cvar("g_balance_campingrifle_primary_damage"));
91 pointparticles(particleeffectnum("shotgun_muzzleflash"), w_shotorg, w_shotdir * 2000, 1);
93 if(self.BUTTON_ZOOM) // if zoomed, shoot from the eye
95 w_shotdir = v_forward;
96 w_shotorg = self.origin + self.view_ofs + ((w_shotorg - self.origin - self.view_ofs) * v_forward) * v_forward;
99 fireBallisticBullet(w_shotorg, w_shotdir, pSpread, pSpeed, pLifetime, pDamage, pHeadshotAddedDamage / pDamage, pForce, deathtype, (cvar("g_balance_campingrifle_tracer") ? EF_RED : EF_BLUE), 1, pBulletConstant);
100 endFireBallisticBullet();
102 if (cvar("g_casings") >= 2)
103 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);
105 self.campingrifle_bulletcounter = self.campingrifle_bulletcounter - 1;
106 W_CampingRifle_CheckMaxBullets(TRUE);
109 void W_CampingRifle_Attack()
111 W_CampingRifle_FireBullet(cvar("g_balance_campingrifle_primary_spread"), cvar("g_balance_campingrifle_primary_damage"), cvar("g_balance_campingrifle_primary_headshotaddeddamage"), cvar("g_balance_campingrifle_primary_force"), cvar("g_balance_campingrifle_primary_speed"), cvar("g_balance_campingrifle_primary_lifetime"), cvar("g_balance_campingrifle_primary_ammo"), WEP_CAMPINGRIFLE, cvar("g_balance_campingrifle_primary_bulletconstant"));
114 void W_CampingRifle_Attack2()
116 W_CampingRifle_FireBullet(cvar("g_balance_campingrifle_secondary_spread"), cvar("g_balance_campingrifle_secondary_damage"), cvar("g_balance_campingrifle_secondary_headshotaddeddamage"), cvar("g_balance_campingrifle_secondary_force"), cvar("g_balance_campingrifle_secondary_speed"), cvar("g_balance_campingrifle_secondary_lifetime"), cvar("g_balance_campingrifle_secondary_ammo"), WEP_CAMPINGRIFLE | HITTYPE_SECONDARY, cvar("g_balance_campingrifle_secondary_bulletconstant"));
119 void spawnfunc_weapon_campingrifle (void)
121 weapon_defaultspawnfunc(WEP_CAMPINGRIFLE);
124 .void(void) campingrifle_bullethail_attackfunc;
125 .float campingrifle_bullethail_frame;
126 .float campingrifle_bullethail_animtime;
127 .float campingrifle_bullethail_refire;
128 void W_CampingRifle_BulletHail_Continue()
131 W_CampingRifle_CheckReloadAndReady();
132 if(self.campingrifle_bulletcounter < 0)
133 return; // reloading, so we are done
134 sw = self.switchweapon; // make it not detect weapon changes as reason to abort firing
135 af = ATTACK_FINISHED(self);
136 self.switchweapon = self.weapon;
137 ATTACK_FINISHED(self) = time;
138 print(ftos(self.ammo_nails), "\n");
139 r = weapon_prepareattack(self.campingrifle_bullethail_frame == WFRAME_FIRE2, self.campingrifle_bullethail_refire);
140 if(self.switchweapon == self.weapon)
141 self.switchweapon = sw;
144 self.campingrifle_bullethail_attackfunc();
145 weapon_thinkf(self.campingrifle_bullethail_frame, self.campingrifle_bullethail_animtime, W_CampingRifle_BulletHail_Continue);
146 print("thinkf set\n");
150 ATTACK_FINISHED(self) = af; // reset attack_finished if we didn't fire, so the last shot enforces the refire time
151 print("out of ammo... ", ftos(self.weaponentity.state), "\n");
155 void W_CampingRifle_BulletHail(float mode, void(void) AttackFunc, float fr, float animtime, float refire)
157 // if we get here, we have at least one bullet to fire
162 self.campingrifle_bullethail_attackfunc = AttackFunc;
163 self.campingrifle_bullethail_frame = fr;
164 self.campingrifle_bullethail_animtime = animtime;
165 self.campingrifle_bullethail_refire = refire;
166 weapon_thinkf(fr, animtime, W_CampingRifle_BulletHail_Continue);
171 weapon_thinkf(fr, animtime, W_CampingRifle_CheckReloadAndReady);
175 .float bot_secondary_campingriflemooth;
176 float w_campingrifle(float req)
181 self.BUTTON_ATCK=FALSE;
182 self.BUTTON_ATCK2=FALSE;
183 if(vlen(self.origin-self.enemy.origin) > 1000)
184 self.bot_secondary_campingriflemooth = 0;
185 if(self.bot_secondary_campingriflemooth == 0)
187 if(bot_aim(cvar("g_balance_campingrifle_primary_speed"), 0, cvar("g_balance_campingrifle_primary_lifetime"), TRUE))
189 self.BUTTON_ATCK = TRUE;
190 if(random() < 0.01) self.bot_secondary_campingriflemooth = 1;
195 if(bot_aim(cvar("g_balance_campingrifle_secondary_speed"), 0, cvar("g_balance_campingrifle_secondary_lifetime"), TRUE))
197 self.BUTTON_ATCK2 = TRUE;
198 if(random() < 0.03) self.bot_secondary_campingriflemooth = 0;
202 else if (req == WR_THINK)
204 if(self.campingrifle_bulletcounter < 0) // forced reload (e.g. because interrupted)
206 if(self.switchweapon == self.weapon)
207 if(self.weaponentity.state == WS_READY)
208 W_CampingRifle_Reload();
212 self.campingrifle_accumulator = bound(time - cvar("g_balance_campingrifle_bursttime"), self.campingrifle_accumulator, time);
213 if (self.BUTTON_ATCK)
214 if (weapon_prepareattack_check(0, cvar("g_balance_campingrifle_primary_refire")))
215 if (time >= self.campingrifle_accumulator + cvar("g_balance_campingrifle_primary_burstcost"))
217 weapon_prepareattack_do(0, cvar("g_balance_campingrifle_primary_refire"));
218 W_CampingRifle_BulletHail(cvar("g_balance_campingrifle_primary_bullethail"), W_CampingRifle_Attack, WFRAME_FIRE1, cvar("g_balance_campingrifle_primary_animtime"), cvar("g_balance_campingrifle_primary_refire"));
219 self.campingrifle_accumulator += cvar("g_balance_campingrifle_primary_burstcost");
221 if (self.BUTTON_ATCK2)
223 if (cvar("g_balance_campingrifle_secondary"))
225 if (weapon_prepareattack_check(1, cvar("g_balance_campingrifle_secondary_refire")))
226 if (time >= self.campingrifle_accumulator + cvar("g_balance_campingrifle_secondary_burstcost"))
228 weapon_prepareattack_do(1, cvar("g_balance_campingrifle_secondary_refire"));
229 W_CampingRifle_BulletHail(cvar("g_balance_campingrifle_secondary_bullethail"), W_CampingRifle_Attack2, WFRAME_FIRE2, cvar("g_balance_campingrifle_secondary_animtime"), cvar("g_balance_campingrifle_primary_refire"));
230 self.campingrifle_accumulator += cvar("g_balance_campingrifle_secondary_burstcost");
236 else if (req == WR_PRECACHE)
238 precache_model ("models/weapons/g_campingrifle.md3");
239 precache_model ("models/weapons/v_campingrifle.md3");
240 precache_model ("models/weapons/h_campingrifle.iqm");
241 precache_sound ("weapons/campingrifle_reload.wav");
242 precache_sound ("weapons/campingrifle_fire.wav");
243 precache_sound ("weapons/campingrifle_fire2.wav");
245 else if (req == WR_SETUP)
247 weapon_setup(WEP_CAMPINGRIFLE);
249 full = W_CampingRifle_CheckMaxBullets(TRUE);
250 if(cvar("g_balance_campingrifle_auto_reload_after_changing_weapons"))
252 self.campingrifle_bulletcounter = -1;
254 else if (req == WR_CHECKAMMO1)
255 return self.ammo_nails >= cvar("g_balance_campingrifle_primary_ammo");
256 else if (req == WR_CHECKAMMO2)
257 return self.ammo_nails >= cvar("g_balance_campingrifle_secondary_ammo");
258 else if (req == WR_RELOAD)
260 W_CampingRifle_Reload();
262 else if (req == WR_RESETPLAYER)
264 self.campingrifle_accumulator = time - cvar("g_balance_campingrifle_bursttime");
265 self.campingrifle_bulletcounter = cvar("g_balance_campingrifle_magazinecapacity");
266 W_CampingRifle_CheckMaxBullets(FALSE);
272 float w_campingrifle(float req)
274 if(req == WR_IMPACTEFFECT)
277 org2 = w_org + w_backoff * 2;
278 pointparticles(particleeffectnum("machinegun_impact"), org2, w_backoff * 1000, 1);
282 sound(self, CHAN_PROJECTILE, "weapons/ric1.wav", VOL_BASE, ATTN_NORM);
283 else if(w_random < 0.4)
284 sound(self, CHAN_PROJECTILE, "weapons/ric2.wav", VOL_BASE, ATTN_NORM);
285 else if(w_random < 0.5)
286 sound(self, CHAN_PROJECTILE, "weapons/ric3.wav", VOL_BASE, ATTN_NORM);
289 else if(req == WR_PRECACHE)
291 precache_sound("weapons/ric1.wav");
292 precache_sound("weapons/ric2.wav");
293 precache_sound("weapons/ric3.wav");
295 else if (req == WR_SUICIDEMESSAGE)
297 if(w_deathtype & HITTYPE_SECONDARY)
298 w_deathtypestring = "%s shot themself automatically";
300 w_deathtypestring = "%s sniped themself somehow";
302 else if (req == WR_KILLMESSAGE)
304 if(w_deathtype & HITTYPE_SECONDARY)
306 if(w_deathtype & HITTYPE_BOUNCE)
307 w_deathtypestring = "%s failed to hide from %s's bullet hail";
309 w_deathtypestring = "%s died in %s's bullet hail";
313 if(w_deathtype & HITTYPE_BOUNCE)
315 // TODO special headshot message here too?
316 w_deathtypestring = "%s failed to hide from %s's rifle";
320 if(w_deathtype & HITTYPE_HEADSHOT)
321 w_deathtypestring = "%s got hit in the head by %s";
323 w_deathtypestring = "%s was sniped by %s";