2 REGISTER_WEAPON(CAMPINGRIFLE, w_campingrifle, IT_NAILS, 3, WEP_FLAG_NORMAL | WEP_TYPE_HITSCAN, BOT_PICKUP_RATING_MID, "campingrifle", "campingrifle", "Rifle");
4 //Camping rifle Primary mode: manually operated bolt*, Secondary: full automatic**
5 //* 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.
6 //** In fully automatic mode some of the gas is used to extract and reload the next cartrige, thus there is less power and range.
8 .float campingrifle_accumulator;
10 float W_CampingRifle_CheckMaxBullets(float checkammo)
13 maxbulls = cvar("g_balance_campingrifle_magazinecapacity");
15 maxbulls = 8; // match HUD
17 if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
18 maxbulls = min(maxbulls, floor(self.ammo_nails / min(cvar("g_balance_campingrifle_primary_ammo"), cvar("g_balance_campingrifle_secondary_ammo"))));
19 if(self.campingrifle_bulletcounter > maxbulls || !cvar("g_balance_campingrifle_magazinecapacity"))
20 self.campingrifle_bulletcounter = maxbulls;
21 return (self.campingrifle_bulletcounter == maxbulls);
24 void W_CampingRifle_ReloadedAndReady()
27 self.campingrifle_bulletcounter = cvar("g_balance_campingrifle_magazinecapacity");
28 W_CampingRifle_CheckMaxBullets(TRUE);
29 t = ATTACK_FINISHED(self) - cvar("g_balance_campingrifle_reloadtime") - 1;
30 ATTACK_FINISHED(self) = t;
34 float W_CampingRifle_Reload()
38 W_CampingRifle_CheckMaxBullets(TRUE);
40 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
42 print("cannot reload... not enough bullets\n");
43 self.campingrifle_bulletcounter = -1; // reload later
44 W_SwitchToOtherWeapon(self);
48 if (self.campingrifle_bulletcounter >= cvar("g_balance_campingrifle_magazinecapacity"))
51 if (self.weaponentity)
53 if (self.weaponentity.wframe == WFRAME_RELOAD)
56 // allow to switch away while reloading, but this will cause a new reload!
57 self.weaponentity.state = WS_READY;
60 sound (self, CHAN_WEAPON2, "weapons/campingrifle_reload.wav", VOL_BASE, ATTN_NORM);
62 t = max(time, ATTACK_FINISHED(self)) + cvar("g_balance_campingrifle_reloadtime") + 1;
63 ATTACK_FINISHED(self) = t;
65 weapon_thinkf(WFRAME_RELOAD, cvar("g_balance_campingrifle_reloadtime"), W_CampingRifle_ReloadedAndReady);
67 self.campingrifle_bulletcounter = -1;
72 void W_CampingRifle_CheckReloadAndReady()
75 if(self.campingrifle_bulletcounter <= 0)
76 if(W_CampingRifle_Reload())
80 void W_CampingRifle_FireBullet(float pSpread, float pDamage, float pHeadshotAddedDamage, float pForce, float pSpeed, float pLifetime, float pAmmo, float deathtype, float pBulletConstant)
82 if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
83 self.ammo_nails -= pAmmo;
85 if(deathtype & HITTYPE_SECONDARY)
86 W_SetupShot (self, cvar("g_antilag_bullets") && pSpeed >= cvar("g_antilag_bullets"), 2, "weapons/campingrifle_fire2.wav", cvar("g_balance_campingrifle_secondary_damage"));
88 W_SetupShot (self, cvar("g_antilag_bullets") && pSpeed >= cvar("g_antilag_bullets"), 2, "weapons/campingrifle_fire.wav", cvar("g_balance_campingrifle_primary_damage"));
90 pointparticles(particleeffectnum("shotgun_muzzleflash"), w_shotorg, w_shotdir * 2000, 1);
92 if(self.BUTTON_ZOOM) // if zoomed, shoot from the eye
94 w_shotdir = v_forward;
95 w_shotorg = self.origin + self.view_ofs + ((w_shotorg - self.origin - self.view_ofs) * v_forward) * v_forward;
98 fireBallisticBullet(w_shotorg, w_shotdir, pSpread, pSpeed, pLifetime, pDamage, pHeadshotAddedDamage / pDamage, pForce, deathtype, (cvar("g_balance_campingrifle_tracer") ? EF_RED : EF_BLUE), 1, pBulletConstant);
99 endFireBallisticBullet();
101 if (cvar("g_casings") >= 2)
102 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);
104 self.campingrifle_bulletcounter = self.campingrifle_bulletcounter - 1;
105 W_CampingRifle_CheckMaxBullets(TRUE);
108 void W_CampingRifle_Attack()
110 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"));
113 void W_CampingRifle_Attack2()
115 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"));
118 void spawnfunc_weapon_campingrifle (void)
120 weapon_defaultspawnfunc(WEP_CAMPINGRIFLE);
123 .void(void) campingrifle_bullethail_attackfunc;
124 .float campingrifle_bullethail_frame;
125 .float campingrifle_bullethail_animtime;
126 .float campingrifle_bullethail_refire;
127 void W_CampingRifle_BulletHail_Continue()
130 W_CampingRifle_CheckReloadAndReady();
131 if(self.campingrifle_bulletcounter < 0)
132 return; // reloading, so we are done
133 sw = self.switchweapon; // make it not detect weapon changes as reason to abort firing
134 af = ATTACK_FINISHED(self);
135 self.switchweapon = self.weapon;
136 ATTACK_FINISHED(self) = time;
137 print(ftos(self.ammo_nails), "\n");
138 r = weapon_prepareattack(self.campingrifle_bullethail_frame == WFRAME_FIRE2, self.campingrifle_bullethail_refire);
139 if(self.switchweapon == self.weapon)
140 self.switchweapon = sw;
143 self.campingrifle_bullethail_attackfunc();
144 weapon_thinkf(self.campingrifle_bullethail_frame, self.campingrifle_bullethail_animtime, W_CampingRifle_BulletHail_Continue);
145 print("thinkf set\n");
149 ATTACK_FINISHED(self) = af; // reset attack_finished if we didn't fire, so the last shot enforces the refire time
150 print("out of ammo... ", ftos(self.weaponentity.state), "\n");
154 void W_CampingRifle_BulletHail(float mode, void(void) AttackFunc, float fr, float animtime, float refire)
156 // if we get here, we have at least one bullet to fire
161 self.campingrifle_bullethail_attackfunc = AttackFunc;
162 self.campingrifle_bullethail_frame = fr;
163 self.campingrifle_bullethail_animtime = animtime;
164 self.campingrifle_bullethail_refire = refire;
165 weapon_thinkf(fr, animtime, W_CampingRifle_BulletHail_Continue);
170 weapon_thinkf(fr, animtime, W_CampingRifle_CheckReloadAndReady);
174 .float bot_secondary_campingriflemooth;
175 float w_campingrifle(float req)
180 self.BUTTON_ATCK=FALSE;
181 self.BUTTON_ATCK2=FALSE;
182 if(vlen(self.origin-self.enemy.origin) > 1000)
183 self.bot_secondary_campingriflemooth = 0;
184 if(self.bot_secondary_campingriflemooth == 0)
186 if(bot_aim(cvar("g_balance_campingrifle_primary_speed"), 0, cvar("g_balance_campingrifle_primary_lifetime"), TRUE))
188 self.BUTTON_ATCK = TRUE;
189 if(random() < 0.01) self.bot_secondary_campingriflemooth = 1;
194 if(bot_aim(cvar("g_balance_campingrifle_secondary_speed"), 0, cvar("g_balance_campingrifle_secondary_lifetime"), TRUE))
196 self.BUTTON_ATCK2 = TRUE;
197 if(random() < 0.03) self.bot_secondary_campingriflemooth = 0;
201 else if (req == WR_THINK)
203 if(self.campingrifle_bulletcounter < 0) // forced reload (e.g. because interrupted)
205 if(self.switchweapon == self.weapon)
206 if(self.weaponentity.state == WS_READY)
207 W_CampingRifle_Reload();
211 self.campingrifle_accumulator = bound(time - cvar("g_balance_campingrifle_bursttime"), self.campingrifle_accumulator, time);
212 if (self.BUTTON_ATCK)
213 if (weapon_prepareattack_check(0, cvar("g_balance_campingrifle_primary_refire")))
214 if (time >= self.campingrifle_accumulator + cvar("g_balance_campingrifle_primary_burstcost"))
216 weapon_prepareattack_do(0, cvar("g_balance_campingrifle_primary_refire"));
217 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"));
218 self.campingrifle_accumulator += cvar("g_balance_campingrifle_primary_burstcost");
220 if (self.BUTTON_ATCK2)
221 if (weapon_prepareattack_check(1, cvar("g_balance_campingrifle_secondary_refire")))
222 if (time >= self.campingrifle_accumulator + cvar("g_balance_campingrifle_secondary_burstcost"))
224 weapon_prepareattack_do(1, cvar("g_balance_campingrifle_secondary_refire"));
225 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"));
226 self.campingrifle_accumulator += cvar("g_balance_campingrifle_secondary_burstcost");
230 else if (req == WR_PRECACHE)
232 precache_model ("models/weapons/g_campingrifle.md3");
233 precache_model ("models/weapons/v_campingrifle.md3");
234 precache_model ("models/weapons/h_campingrifle.iqm");
235 precache_sound ("weapons/campingrifle_reload.wav");
236 precache_sound ("weapons/campingrifle_fire.wav");
237 precache_sound ("weapons/campingrifle_fire2.wav");
239 else if (req == WR_SETUP)
241 weapon_setup(WEP_CAMPINGRIFLE);
243 full = W_CampingRifle_CheckMaxBullets(TRUE);
244 if(cvar("g_balance_campingrifle_auto_reload_after_changing_weapons"))
246 self.campingrifle_bulletcounter = -1;
248 else if (req == WR_CHECKAMMO1)
249 return self.ammo_nails >= cvar("g_balance_campingrifle_primary_ammo");
250 else if (req == WR_CHECKAMMO2)
251 return self.ammo_nails >= cvar("g_balance_campingrifle_secondary_ammo");
252 else if (req == WR_SUICIDEMESSAGE)
254 if(w_deathtype & HITTYPE_SECONDARY)
255 w_deathtypestring = "shot themself automatically";
257 w_deathtypestring = "sniped themself somehow";
259 else if (req == WR_KILLMESSAGE)
261 if(w_deathtype & HITTYPE_SECONDARY)
263 if(w_deathtype & HITTYPE_BOUNCE)
264 w_deathtypestring = "failed to hide from #'s bullet hail";
266 w_deathtypestring = "died in #'s bullet hail";
270 if(w_deathtype & HITTYPE_BOUNCE)
272 // TODO special headshot message here too?
273 w_deathtypestring = "failed to hide from #'s rifle";
277 if(w_deathtype & HITTYPE_HEADSHOT)
278 w_deathtypestring = "got hit in the head by #";
280 w_deathtypestring = "was sniped by #";
284 else if (req == WR_RELOAD)
286 W_CampingRifle_Reload();
288 else if (req == WR_RESETPLAYER)
290 self.campingrifle_accumulator = time - cvar("g_balance_campingrifle_bursttime");
291 self.campingrifle_bulletcounter = cvar("g_balance_campingrifle_magazinecapacity");
292 W_CampingRifle_CheckMaxBullets(FALSE);