]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/w_sniperrifle.qc
Proper names
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / w_sniperrifle.qc
1 #ifdef REGISTER_WEAPON
2 REGISTER_WEAPON(SNIPERRIFLE, w_sniperrifle, IT_NAILS, 7, WEP_FLAG_NORMAL | WEP_TYPE_HITSCAN, BOT_PICKUP_RATING_MID, "campingrifle", "sniperrifle", _("Sniper Rifle"))
3 #else
4 #ifdef SVQC
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.
8
9 .float sniperrifle_accumulator;
10
11 void W_SniperRifle_DoReload()
12 {
13         w_ready();
14         if(W_Reload(self.ammo_nails))
15                 return;
16 }
17
18 void W_SniperRifle_FireBullet(float pSpread, float pDamage, float pHeadshotAddedDamage, float pForce, float pSpeed, float pLifetime, float pAmmo, float deathtype, float pBulletConstant)
19 {
20         if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
21                 self.ammo_nails -= pAmmo;
22
23         if(deathtype & HITTYPE_SECONDARY)
24                 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);
25         else
26                 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);
27
28         pointparticles(particleeffectnum("shotgun_muzzleflash"), w_shotorg, w_shotdir * 2000, 1);
29
30         if(self.BUTTON_ZOOM) // if zoomed, shoot from the eye
31         {
32                 w_shotdir = v_forward;
33                 w_shotorg = self.origin + self.view_ofs + ((w_shotorg - self.origin - self.view_ofs) * v_forward) * v_forward;
34         }
35
36         if(deathtype & HITTYPE_SECONDARY)
37                 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);
38         else
39                 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);
40         endFireBallisticBullet();
41
42         if (autocvar_g_casings >= 2)
43                 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);
44         
45         self.ammo_counter = self.ammo_counter - 1;
46 }
47
48 void W_SniperRifle_Attack()
49 {
50         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);
51 }
52
53 void W_SniperRifle_Attack2()
54 {
55         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);
56 }
57
58 void spawnfunc_weapon_sniperrifle (void)
59 {
60         weapon_defaultspawnfunc(WEP_SNIPERRIFLE);
61 }
62
63 // compatibility alias
64 void spawnfunc_weapon_campingrifle (void)
65 {
66         spawnfunc_weapon_sniperrifle();
67 }
68
69 .void(void) sniperrifle_bullethail_attackfunc;
70 .float sniperrifle_bullethail_frame;
71 .float sniperrifle_bullethail_animtime;
72 .float sniperrifle_bullethail_refire;
73 void W_SniperRifle_BulletHail_Continue()
74 {
75         float r, sw, af;
76         if(self.ammo_counter <= 0)
77                 W_SniperRifle_DoReload();
78         if(self.ammo_counter < 0)
79                 return; // reloading, so we are done
80         sw = self.switchweapon; // make it not detect weapon changes as reason to abort firing
81         af = ATTACK_FINISHED(self);
82         self.switchweapon = self.weapon;
83         ATTACK_FINISHED(self) = time;
84         print(ftos(self.ammo_nails), "\n");
85         r = weapon_prepareattack(self.sniperrifle_bullethail_frame == WFRAME_FIRE2, self.sniperrifle_bullethail_refire);
86         if(self.switchweapon == self.weapon)
87                 self.switchweapon = sw;
88         if(r)
89         {
90                 self.sniperrifle_bullethail_attackfunc();
91                 weapon_thinkf(self.sniperrifle_bullethail_frame, self.sniperrifle_bullethail_animtime, W_SniperRifle_BulletHail_Continue);
92                 print("thinkf set\n");
93         }
94         else
95         {
96                 ATTACK_FINISHED(self) = af; // reset attack_finished if we didn't fire, so the last shot enforces the refire time
97                 print("out of ammo... ", ftos(self.weaponentity.state), "\n");
98         }
99 }
100
101 void W_SniperRifle_BulletHail(float mode, void(void) AttackFunc, float fr, float animtime, float refire)
102 {
103         // if we get here, we have at least one bullet to fire
104         AttackFunc();
105         if(mode)
106         {
107                 // continue hail
108                 self.sniperrifle_bullethail_attackfunc = AttackFunc;
109                 self.sniperrifle_bullethail_frame = fr;
110                 self.sniperrifle_bullethail_animtime = animtime;
111                 self.sniperrifle_bullethail_refire = refire;
112                 weapon_thinkf(fr, animtime, W_SniperRifle_BulletHail_Continue);
113         }
114         else
115         {
116                 // just one shot
117                 weapon_thinkf(fr, animtime, w_ready);
118         }
119 }
120
121 .float bot_secondary_sniperriflemooth;
122 float w_sniperrifle(float req)
123 {
124         float full;
125         if (req == WR_AIM)
126         {
127                 self.BUTTON_ATCK=FALSE;
128                 self.BUTTON_ATCK2=FALSE;
129                 if(vlen(self.origin-self.enemy.origin) > 1000)
130                         self.bot_secondary_sniperriflemooth = 0;
131                 if(self.bot_secondary_sniperriflemooth == 0)
132                 {
133                         if(bot_aim(autocvar_g_balance_sniperrifle_primary_speed, 0, autocvar_g_balance_sniperrifle_primary_lifetime, TRUE))
134                         {
135                                 self.BUTTON_ATCK = TRUE;
136                                 if(random() < 0.01) self.bot_secondary_sniperriflemooth = 1;
137                         }
138                 }
139                 else
140                 {
141                         if(bot_aim(autocvar_g_balance_sniperrifle_secondary_speed, 0, autocvar_g_balance_sniperrifle_secondary_lifetime, TRUE))
142                         {
143                                 self.BUTTON_ATCK2 = TRUE;
144                                 if(random() < 0.03) self.bot_secondary_sniperriflemooth = 0;
145                         }
146                 }
147         }
148         else if (req == WR_THINK)
149         {
150                 if(self.ammo_counter < 0) // forced reload (e.g. because interrupted)
151                 {
152             self.wish_reload = 1;
153                 }
154                 else
155                 {
156                         self.sniperrifle_accumulator = bound(time - autocvar_g_balance_sniperrifle_bursttime, self.sniperrifle_accumulator, time);
157                         if (self.BUTTON_ATCK)
158                         if (weapon_prepareattack_check(0, autocvar_g_balance_sniperrifle_primary_refire))
159                         if (time >= self.sniperrifle_accumulator + autocvar_g_balance_sniperrifle_primary_burstcost)
160                         {
161                                 weapon_prepareattack_do(0, autocvar_g_balance_sniperrifle_primary_refire);
162                                 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);
163                                 self.sniperrifle_accumulator += autocvar_g_balance_sniperrifle_primary_burstcost;
164                         }
165                         if (self.BUTTON_ATCK2)
166                         {       
167                                 if (autocvar_g_balance_sniperrifle_secondary)
168                                 {
169                     if(autocvar_g_balance_sniperrifle_secondary_reload)
170                         self.wish_reload = 1;
171                     else
172                     {
173                         if (weapon_prepareattack_check(1, autocvar_g_balance_sniperrifle_secondary_refire))
174                         if (time >= self.sniperrifle_accumulator + autocvar_g_balance_sniperrifle_secondary_burstcost)
175                         {
176                             weapon_prepareattack_do(1, autocvar_g_balance_sniperrifle_secondary_refire);
177                             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);
178                             self.sniperrifle_accumulator += autocvar_g_balance_sniperrifle_secondary_burstcost;
179                         }
180                     }
181                                 }
182                         }
183                 }
184         if(self.wish_reload)
185         {
186             if(self.switchweapon == self.weapon)
187             {
188                 if(self.weaponentity.state == WS_READY)
189                 {
190                     self.wish_reload = 0;
191                     W_Reload(self.ammo_nails);
192                 }
193             }
194         }
195         }
196         else if (req == WR_PRECACHE)
197         {
198                 precache_model ("models/weapons/g_campingrifle.md3");
199                 precache_model ("models/weapons/v_campingrifle.md3");
200                 precache_model ("models/weapons/h_campingrifle.iqm");
201                 precache_sound ("weapons/campingrifle_reload.wav");
202                 precache_sound ("weapons/campingrifle_fire.wav");
203                 precache_sound ("weapons/campingrifle_fire2.wav");
204         }
205         else if (req == WR_SETUP)
206         {
207                 weapon_setup(WEP_SNIPERRIFLE);
208
209                 full = W_CheckMaxBullets(TRUE);
210                 if(autocvar_g_balance_sniperrifle_auto_reload_on_switch)
211                         if(!full)
212                                 self.ammo_counter = -1;
213         }
214         else if (req == WR_CHECKAMMO1)
215                 return self.ammo_nails >= autocvar_g_balance_sniperrifle_primary_ammo;
216         else if (req == WR_CHECKAMMO2)
217                 return self.ammo_nails >= autocvar_g_balance_sniperrifle_secondary_ammo;
218         else if (req == WR_RELOAD)
219         {
220         self.wish_reload = 1;
221         }
222         else if (req == WR_RESETPLAYER)
223         {
224                 self.sniperrifle_accumulator = time - autocvar_g_balance_sniperrifle_bursttime;
225                 self.ammo_counter = autocvar_g_balance_sniperrifle_magazinecapacity;
226                 W_CheckMaxBullets(FALSE);
227         }
228         return TRUE;
229 };
230 #endif
231 #ifdef CSQC
232 float w_sniperrifle(float req)
233 {
234         if(req == WR_IMPACTEFFECT)
235         {
236                 vector org2;
237                 org2 = w_org + w_backoff * 2;
238                 pointparticles(particleeffectnum("machinegun_impact"), org2, w_backoff * 1000, 1);
239                 if(!w_issilent)
240                 {
241                         if(w_random < 0.2)
242                                 sound(self, CHAN_PROJECTILE, "weapons/ric1.wav", VOL_BASE, ATTN_NORM);
243                         else if(w_random < 0.4)
244                                 sound(self, CHAN_PROJECTILE, "weapons/ric2.wav", VOL_BASE, ATTN_NORM);
245                         else if(w_random < 0.5)
246                                 sound(self, CHAN_PROJECTILE, "weapons/ric3.wav", VOL_BASE, ATTN_NORM);
247                 }
248         }
249         else if(req == WR_PRECACHE)
250         {
251                 precache_sound("weapons/ric1.wav");
252                 precache_sound("weapons/ric2.wav");
253                 precache_sound("weapons/ric3.wav");
254         }
255         else if (req == WR_SUICIDEMESSAGE)
256         {
257                 if(w_deathtype & HITTYPE_SECONDARY)
258                         w_deathtypestring = "%s shot themself automatically";
259                 else
260                         w_deathtypestring = "%s sniped themself somehow";
261         }
262         else if (req == WR_KILLMESSAGE)
263         {
264                 if(w_deathtype & HITTYPE_SECONDARY)
265                 {
266                         if(w_deathtype & HITTYPE_BOUNCE)
267                                 w_deathtypestring = "%s failed to hide from %s's bullet hail";
268                         else
269                                 w_deathtypestring = "%s died in %s's bullet hail";
270                 }
271                 else
272                 {
273                         if(w_deathtype & HITTYPE_BOUNCE)
274                         {
275                                 // TODO special headshot message here too?
276                                 w_deathtypestring = "%s failed to hide from %s's rifle";
277                         }
278                         else
279                         {
280                                 if(w_deathtype & HITTYPE_HEADSHOT)
281                                         w_deathtypestring = "%s got hit in the head by %s";
282                                 else
283                                         w_deathtypestring = "%s was sniped by %s";
284                         }
285                 }
286         }
287         return TRUE;
288 }
289 #endif
290 #endif