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)
222 if (weapon_prepareattack_check(1, cvar("g_balance_campingrifle_secondary_refire")))
223 if (time >= self.campingrifle_accumulator + cvar("g_balance_campingrifle_secondary_burstcost"))
225 weapon_prepareattack_do(1, cvar("g_balance_campingrifle_secondary_refire"));
226 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"));
227 self.campingrifle_accumulator += cvar("g_balance_campingrifle_secondary_burstcost");
231 else if (req == WR_PRECACHE)
233 precache_model ("models/weapons/g_campingrifle.md3");
234 precache_model ("models/weapons/v_campingrifle.md3");
235 precache_model ("models/weapons/h_campingrifle.iqm");
236 precache_sound ("weapons/campingrifle_reload.wav");
237 precache_sound ("weapons/campingrifle_fire.wav");
238 precache_sound ("weapons/campingrifle_fire2.wav");
240 else if (req == WR_SETUP)
242 weapon_setup(WEP_CAMPINGRIFLE);
244 full = W_CampingRifle_CheckMaxBullets(TRUE);
245 if(cvar("g_balance_campingrifle_auto_reload_after_changing_weapons"))
247 self.campingrifle_bulletcounter = -1;
249 else if (req == WR_CHECKAMMO1)
250 return self.ammo_nails >= cvar("g_balance_campingrifle_primary_ammo");
251 else if (req == WR_CHECKAMMO2)
252 return self.ammo_nails >= cvar("g_balance_campingrifle_secondary_ammo");
253 else if (req == WR_RELOAD)
255 W_CampingRifle_Reload();
257 else if (req == WR_RESETPLAYER)
259 self.campingrifle_accumulator = time - cvar("g_balance_campingrifle_bursttime");
260 self.campingrifle_bulletcounter = cvar("g_balance_campingrifle_magazinecapacity");
261 W_CampingRifle_CheckMaxBullets(FALSE);
267 float w_campingrifle(float req)
269 if(req == WR_IMPACTEFFECT)
272 org2 = w_org + w_backoff * 2;
273 pointparticles(particleeffectnum("machinegun_impact"), org2, w_backoff * 1000, 1);
277 sound(self, CHAN_PROJECTILE, "weapons/ric1.wav", VOL_BASE, ATTN_NORM);
278 else if(w_random < 0.4)
279 sound(self, CHAN_PROJECTILE, "weapons/ric2.wav", VOL_BASE, ATTN_NORM);
280 else if(w_random < 0.5)
281 sound(self, CHAN_PROJECTILE, "weapons/ric3.wav", VOL_BASE, ATTN_NORM);
284 else if(req == WR_PRECACHE)
286 precache_sound("weapons/ric1.wav");
287 precache_sound("weapons/ric2.wav");
288 precache_sound("weapons/ric3.wav");
290 else if (req == WR_SUICIDEMESSAGE)
292 if(w_deathtype & HITTYPE_SECONDARY)
293 w_deathtypestring = "shot themself automatically";
295 w_deathtypestring = "sniped themself somehow";
297 else if (req == WR_KILLMESSAGE)
299 if(w_deathtype & HITTYPE_SECONDARY)
301 if(w_deathtype & HITTYPE_BOUNCE)
302 w_deathtypestring = "failed to hide from #'s bullet hail";
304 w_deathtypestring = "died in #'s bullet hail";
308 if(w_deathtype & HITTYPE_BOUNCE)
310 // TODO special headshot message here too?
311 w_deathtypestring = "failed to hide from #'s rifle";
315 if(w_deathtype & HITTYPE_HEADSHOT)
316 w_deathtypestring = "got hit in the head by #";
318 w_deathtypestring = "was sniped by #";