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_SUICIDEMESSAGE)
255 if(w_deathtype & HITTYPE_SECONDARY)
256 w_deathtypestring = "shot themself automatically";
258 w_deathtypestring = "sniped themself somehow";
260 else if (req == WR_KILLMESSAGE)
262 if(w_deathtype & HITTYPE_SECONDARY)
264 if(w_deathtype & HITTYPE_BOUNCE)
265 w_deathtypestring = "failed to hide from #'s bullet hail";
267 w_deathtypestring = "died in #'s bullet hail";
271 if(w_deathtype & HITTYPE_BOUNCE)
273 // TODO special headshot message here too?
274 w_deathtypestring = "failed to hide from #'s rifle";
278 if(w_deathtype & HITTYPE_HEADSHOT)
279 w_deathtypestring = "got hit in the head by #";
281 w_deathtypestring = "was sniped by #";
285 else if (req == WR_RELOAD)
287 W_CampingRifle_Reload();
289 else if (req == WR_RESETPLAYER)
291 self.campingrifle_accumulator = time - cvar("g_balance_campingrifle_bursttime");
292 self.campingrifle_bulletcounter = cvar("g_balance_campingrifle_magazinecapacity");
293 W_CampingRifle_CheckMaxBullets(FALSE);
299 float w_campingrifle(float req)
301 if(req == WR_IMPACTEFFECT)
304 org2 = w_org + w_backoff * 2;
305 pointparticles(particleeffectnum("machinegun_impact"), org2, w_backoff * 1000, 1);
309 sound(self, CHAN_PROJECTILE, "weapons/ric1.wav", VOL_BASE, ATTN_NORM);
310 else if(w_random < 0.4)
311 sound(self, CHAN_PROJECTILE, "weapons/ric2.wav", VOL_BASE, ATTN_NORM);
312 else if(w_random < 0.5)
313 sound(self, CHAN_PROJECTILE, "weapons/ric3.wav", VOL_BASE, ATTN_NORM);
316 else if(req == WR_PRECACHE)
318 precache_sound("weapons/ric1.wav");
319 precache_sound("weapons/ric2.wav");
320 precache_sound("weapons/ric3.wav");