]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/w_minstanex.qc
An additional feature for the minstanex, allowing the alt fire (laser) to take weapon...
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / w_minstanex.qc
1 #ifdef REGISTER_WEAPON
2 REGISTER_WEAPON(MINSTANEX, w_minstanex, IT_CELLS, 7, WEP_FLAG_HIDDEN | WEP_FLAG_CANCLIMB | WEP_TYPE_HITSCAN, BOT_PICKUP_RATING_HIGH, "minstanex", "minstanex", _("MinstaNex"))
3 #else
4 #ifdef SVQC
5 .float minstanex_lasthit;
6
7 .float minstanex_load;
8
9 float W_Minstanex_LaserUsesLoad()
10 {
11         // if the minsta uses reloading, and consumption is enabled for the minsta laser, decrease clip load
12         if(!autocvar_g_balance_minstanex_reload_ammo) // reloading is disabled
13                 return FALSE;
14
15         if(autocvar_g_balance_minstanex_reload_laserload)
16                 return autocvar_g_balance_minstanex_reload_laserload;
17
18         return FALSE;
19 }
20
21 void W_Minstanex_SetAmmoCounter()
22 {
23         // set clip_load to the weapon we have switched to, if the gun uses reloading
24         if(!autocvar_g_balance_minstanex_reload_ammo)
25                 self.clip_load = 0; // also keeps crosshair ammo from displaying
26         else
27         {
28                 self.clip_load = self.minstanex_load;
29                 self.clip_size = autocvar_g_balance_minstanex_reload_ammo; // for the crosshair ammo display
30         }
31 }
32
33 void W_Minstanex_ReloadedAndReady()
34 {
35         float t;
36
37         // now do the ammo transfer
38         self.clip_load = self.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading
39         while(self.clip_load < autocvar_g_balance_minstanex_reload_ammo && self.ammo_cells) // make sure we don't add more ammo than we have
40         {
41                 self.clip_load += 1;
42                 self.ammo_cells -= 1;
43         }
44         self.minstanex_load = self.clip_load;
45
46         t = ATTACK_FINISHED(self) - autocvar_g_balance_minstanex_reload_time - 1;
47         ATTACK_FINISHED(self) = t;
48         w_ready();
49 }
50
51 void W_Minstanex_Reload()
52 {
53         // return if reloading is disabled for this weapon
54         if(!autocvar_g_balance_minstanex_reload_ammo)
55                 return;
56
57         if(W_Minstanex_LaserUsesLoad())
58         {
59                 if(!W_ReloadCheck(self.ammo_cells, min(autocvar_g_balance_minstanex_ammo, W_Minstanex_LaserUsesLoad())))
60                         return;
61         }
62         else if(!W_ReloadCheck(self.ammo_cells, autocvar_g_balance_minstanex_ammo))
63                 return;
64
65         float t;
66
67         sound (self, CHAN_WEAPON2, "weapons/reload.wav", VOL_BASE, ATTN_NORM);
68
69         t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_minstanex_reload_time + 1;
70         ATTACK_FINISHED(self) = t;
71
72         weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_minstanex_reload_time, W_Minstanex_ReloadedAndReady);
73
74         self.old_clip_load = self.clip_load;
75         self.clip_load = -1;
76 }
77
78 void W_MinstaNex_Attack (void)
79 {
80         float flying;
81         flying = IsFlying(self); // do this BEFORE to make the trace values from FireRailgunBullet last
82
83         W_SetupShot (self, TRUE, 0, "weapons/minstanexfire.wav", CHAN_WEAPON, 10000);
84
85         yoda = 0;
86         damage_goodhits = 0;
87         headshot = 0;
88         FireRailgunBullet (w_shotorg, w_shotorg + w_shotdir * MAX_SHOT_DISTANCE, 10000, 800, 0, 0, 0, 0, WEP_MINSTANEX);
89
90         if(g_minstagib)
91         {
92                 if(yoda)
93                         AnnounceTo(self, "yoda");
94         }
95         else
96         {
97                 if(yoda && flying)
98                         AnnounceTo(self, "yoda");
99                 if(headshot)
100                 {
101                         AnnounceTo(self, "headshot");
102                 }
103                 if(damage_goodhits && self.minstanex_lasthit)
104                 {
105                         if(AnnounceTo(self, "impressive"))
106                                 damage_goodhits = 0; // only every second time
107                 }
108         }
109
110         self.minstanex_lasthit = damage_goodhits;
111
112         pointparticles(particleeffectnum("nex_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
113
114         // teamcolor / hit beam effect
115         vector v;
116         v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos);
117         if(teams_matter)
118         {
119             switch(self.team)
120             {
121             case COLOR_TEAM1:   // Red
122                 if(damage_goodhits)
123                     WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3RED_HIT"), w_shotorg, v);
124                 else
125                     WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3RED"), w_shotorg, v);
126                 break;
127             case COLOR_TEAM2:   // Blue
128                 if(damage_goodhits)
129                     WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3BLUE_HIT"), w_shotorg, v);
130                 else
131                     WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3BLUE"), w_shotorg, v);
132                 break;
133             case COLOR_TEAM3:   // Yellow
134                 if(damage_goodhits)
135                     WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3YELLOW_HIT"), w_shotorg, v);
136                 else
137                     WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3YELLOW"), w_shotorg, v);
138                 break;
139             case COLOR_TEAM4:   // Pink
140                 if(damage_goodhits)
141                     WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3PINK_HIT"), w_shotorg, v);
142                 else
143                     WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3PINK"), w_shotorg, v);
144                 break;
145             }
146         }
147         else
148         WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3"), w_shotorg, v);
149
150         // flash and burn the wall
151         if (trace_ent.solid == SOLID_BSP && !(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT))
152                 Damage_DamageInfo(trace_endpos, 10000, 0, 0, 800 * w_shotdir, WEP_MINSTANEX, self);
153
154         // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
155         if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
156         {
157                 if(autocvar_g_balance_minstanex_reload_ammo)
158                 {
159                         if (g_minstagib)
160                                 self.clip_load -= - 1;
161                         else
162                                 self.clip_load -= autocvar_g_balance_minstanex_ammo;
163                         self.minstanex_load = self.clip_load;
164                 }
165                 else
166                 {
167                         if (g_minstagib)
168                                 self.ammo_cells -= - 1;
169                         else
170                                 self.ammo_cells -= autocvar_g_balance_minstanex_ammo;
171                 }
172         }
173 }
174
175
176 .float minstagib_nextthink;
177 void minstagib_ammocheck (void)
178 {
179         if (time < self.minstagib_nextthink || self.deadflag || gameover)
180                 return;
181
182         if (self.ammo_cells <= 0)
183         {
184                 if (self.health == 5)
185                 {
186                         centerprint(self, "you're dead now...\n");
187                         Damage(self, self, self, 5, DEATH_NOAMMO, self.origin, '0 0 0');
188                         AnnounceTo(self, "terminated");
189                 }
190                 else if (self.health == 10)
191                 {
192                         centerprint(self, "^11^7 second left to find some ammo\n");
193                         Damage(self, self, self, 5, DEATH_NOAMMO, self.origin, '0 0 0');
194                         AnnounceTo(self, "1");
195                 }
196                 else if (self.health == 20)
197                 {
198                         centerprint(self, "^12^7 seconds left to find some ammo\n");
199                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
200                         AnnounceTo(self, "2");
201                 }
202                 else if (self.health == 30)
203                 {
204                         centerprint(self, "^13^7 seconds left to find some ammo\n");
205                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
206                         AnnounceTo(self, "3");
207                 }
208                 else if (self.health == 40)
209                 {
210                         centerprint(self, "^14^7 seconds left to find some ammo\n");
211                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
212                         AnnounceTo(self, "4");
213                 }
214                 else if (self.health == 50)
215                 {
216                         centerprint(self, "^15^7 seconds left to find some ammo\n");
217                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
218                         AnnounceTo(self, "5");
219                 }
220                 else if (self.health == 60)
221                 {
222                         centerprint(self, "^36^7 seconds left to find some ammo\n");
223                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
224                         AnnounceTo(self, "6");
225                 }
226                 else if (self.health == 70)
227                 {
228                         centerprint(self, "^37^7 seconds left to find some ammo\n");
229                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
230                         AnnounceTo(self, "7");
231                 }
232                 else if (self.health == 80)
233                 {
234                         centerprint(self, "^38^7 seconds left to find some ammo\n");
235                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
236                         AnnounceTo(self, "8");
237                 }
238                 else if (self.health == 90)
239                 {
240                         centerprint(self, "^39^7 seconds left to find some ammo\n");
241                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
242                         AnnounceTo(self, "9");
243                 }
244                 else if (self.health == 100)
245                 {
246                         centerprint(self, "get some ammo or\nyou'll be dead in ^310^7 seconds...");
247                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
248                         if not(self.flags & FL_GODMODE)
249                                 AnnounceTo(self, "10");
250                 }
251         }
252         self.minstagib_nextthink = time + 1;
253 }
254
255 void spawnfunc_weapon_minstanex (void); // defined in t_items.qc
256
257 float w_minstanex(float req)
258 {
259         if (req == WR_AIM)
260         {
261                 if(self.ammo_cells>0)
262                         self.BUTTON_ATCK = bot_aim(1000000, 0, 1, FALSE);
263                 else
264                         self.BUTTON_ATCK2 = bot_aim(autocvar_g_balance_laser_primary_speed, 0, autocvar_g_balance_laser_primary_lifetime, FALSE);
265         }
266         else if (req == WR_THINK)
267         {
268                 // if the laser uses load, we also consider its ammo for reloading
269                 if(autocvar_g_balance_minstanex_reload_ammo && W_Minstanex_LaserUsesLoad() && ((g_minstagib && self.clip_load < min(1, W_Minstanex_LaserUsesLoad())) || (!g_minstagib && self.clip_load < min(autocvar_g_balance_minstanex_ammo, W_Minstanex_LaserUsesLoad())))) // forced reload
270                         W_Minstanex_Reload();
271                 else if(autocvar_g_balance_minstanex_reload_ammo && ((g_minstagib && self.clip_load < 1) || (!g_minstagib && self.clip_load < autocvar_g_balance_minstanex_ammo))) // forced reload
272                         W_Minstanex_Reload();
273                 else if (self.BUTTON_ATCK)
274                 {
275                         if (weapon_prepareattack(0, autocvar_g_balance_minstanex_refire))
276                         {
277                                 W_MinstaNex_Attack();
278                                 weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_minstanex_animtime, w_ready);
279                         }
280                 }
281                 else if (self.BUTTON_ATCK2)
282                 {
283                         if (self.jump_interval <= time)
284                         {
285                                 self.jump_interval = time + autocvar_g_balance_laser_primary_refire * W_WeaponRateFactor();
286
287                                 // decrease clip load for the laser?
288                                 if(autocvar_g_balance_minstanex_reload_ammo && W_Minstanex_LaserUsesLoad())
289                                         self.clip_load -= W_Minstanex_LaserUsesLoad();
290
291                                 // ugly minstagib hack to reuse the fire mode of the laser
292                                 float w;
293                                 w = self.weapon;
294                                 self.weapon = WEP_LASER;
295                                 W_Laser_Attack(2);
296                                 self.weapon = w;
297                         }
298                 }
299         if(self.wish_reload)
300         {
301             if(self.switchweapon == self.weapon)
302             {
303                 if(self.weaponentity.state == WS_READY)
304                 {
305                     self.wish_reload = 0;
306                     W_Minstanex_Reload();
307                 }
308             }
309         }
310         }
311         else if (req == WR_PRECACHE)
312         {
313                 precache_model ("models/nexflash.md3");
314                 precache_model ("models/weapons/g_minstanex.md3");
315                 precache_model ("models/weapons/v_minstanex.md3");
316                 precache_model ("models/weapons/h_minstanex.iqm");
317                 precache_sound ("weapons/minstanexfire.wav");
318                 precache_sound ("weapons/nexwhoosh1.wav");
319                 precache_sound ("weapons/nexwhoosh2.wav");
320                 precache_sound ("weapons/nexwhoosh3.wav");
321                 w_laser(WR_PRECACHE);
322         }
323         else if (req == WR_SETUP)
324         {
325                 weapon_setup(WEP_MINSTANEX);
326                 W_Minstanex_SetAmmoCounter();
327                 self.minstanex_lasthit = 0;
328         }
329         else if (req == WR_CHECKAMMO1)
330         {
331                 if(autocvar_g_balance_minstanex_reload_ammo)
332                 {
333                         if (g_minstagib)
334                                 return self.clip_load >= 1;
335                         else
336                                 return self.clip_load >= autocvar_g_balance_minstanex_ammo;
337                 }
338                 else
339                 {
340                         if (g_minstagib)
341                                 return self.ammo_cells >= 1;
342                         else
343                                 return self.ammo_cells >= autocvar_g_balance_minstanex_ammo;
344                 }
345         }
346         else if (req == WR_CHECKAMMO2)
347         {
348                 if(W_Minstanex_LaserUsesLoad())
349                         return W_Minstanex_LaserUsesLoad();
350                 else
351                         return TRUE;
352         }
353         else if (req == WR_RESETPLAYER)
354         {
355                 self.minstanex_lasthit = 0;
356         }
357         else if (req == WR_RELOAD)
358         {
359                 W_Minstanex_Reload();
360         }
361         return TRUE;
362 };
363 #endif
364 #ifdef CSQC
365 float w_minstanex(float req)
366 {
367         if(req == WR_IMPACTEFFECT)
368         {
369                 vector org2;
370                 org2 = w_org + w_backoff * 6;
371                 pointparticles(particleeffectnum("nex_impact"), org2, '0 0 0', 1);
372                 if(!w_issilent)
373                         sound(self, CHAN_PROJECTILE, "weapons/neximpact.wav", VOL_BASE, ATTN_NORM);
374         }
375         else if(req == WR_PRECACHE)
376         {
377                 precache_sound("weapons/neximpact.wav");
378         }
379         else if (req == WR_SUICIDEMESSAGE)
380                 w_deathtypestring = "%s did the impossible";
381         else if (req == WR_KILLMESSAGE)
382                 w_deathtypestring = "%s has been vaporized by %s";
383         return TRUE;
384 }
385 #endif
386 #endif