]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/w_minstanex.qc
b96d42f12163b63be2bf5bd470c31ed66ad47f59
[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 minstanex_ammo;
258 float w_minstanex(float req)
259 {
260         if (req == WR_AIM)
261         {
262                 if(self.ammo_cells > 0)
263                         self.BUTTON_ATCK = bot_aim(1000000, 0, 1, FALSE);
264                 else
265                         self.BUTTON_ATCK2 = bot_aim(autocvar_g_balance_laser_primary_speed, 0, autocvar_g_balance_laser_primary_lifetime, FALSE);
266         }
267         else if (req == WR_THINK)
268         {
269                 if(g_minstagib)
270                         minstanex_ammo = 1;
271                 else
272                         minstanex_ammo = autocvar_g_balance_minstanex_ammo;
273
274                 // if the laser uses load, we also consider its ammo for reloading
275                 if(autocvar_g_balance_minstanex_reload_ammo && W_Minstanex_LaserUsesLoad() && self.clip_load < min(minstanex_ammo, W_Minstanex_LaserUsesLoad())) // forced reload
276                         W_Minstanex_Reload();
277                 else if(autocvar_g_balance_minstanex_reload_ammo && self.clip_load < minstanex_ammo) // forced reload
278                         W_Minstanex_Reload();
279                 else if (self.BUTTON_ATCK)
280                 {
281                         if (weapon_prepareattack(0, autocvar_g_balance_minstanex_refire))
282                         {
283                                 W_MinstaNex_Attack();
284                                 weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_minstanex_animtime, w_ready);
285                         }
286                 }
287                 else if (self.BUTTON_ATCK2)
288                 {
289                         if (self.jump_interval <= time)
290                         {
291                                 self.jump_interval = time + autocvar_g_balance_laser_primary_refire * W_WeaponRateFactor();
292
293                                 // decrease clip load for the laser?
294                                 if(autocvar_g_balance_minstanex_reload_ammo && W_Minstanex_LaserUsesLoad())
295                                         self.clip_load -= W_Minstanex_LaserUsesLoad();
296
297                                 // ugly minstagib hack to reuse the fire mode of the laser
298                                 float w;
299                                 w = self.weapon;
300                                 self.weapon = WEP_LASER;
301                                 W_Laser_Attack(2);
302                                 self.weapon = w;
303                         }
304                 }
305         if(self.wish_reload)
306         {
307             if(self.switchweapon == self.weapon)
308             {
309                 if(self.weaponentity.state == WS_READY)
310                 {
311                     self.wish_reload = 0;
312                     W_Minstanex_Reload();
313                 }
314             }
315         }
316         }
317         else if (req == WR_PRECACHE)
318         {
319                 precache_model ("models/nexflash.md3");
320                 precache_model ("models/weapons/g_minstanex.md3");
321                 precache_model ("models/weapons/v_minstanex.md3");
322                 precache_model ("models/weapons/h_minstanex.iqm");
323                 precache_sound ("weapons/minstanexfire.wav");
324                 precache_sound ("weapons/nexwhoosh1.wav");
325                 precache_sound ("weapons/nexwhoosh2.wav");
326                 precache_sound ("weapons/nexwhoosh3.wav");
327                 w_laser(WR_PRECACHE);
328         }
329         else if (req == WR_SETUP)
330         {
331                 weapon_setup(WEP_MINSTANEX);
332                 W_Minstanex_SetAmmoCounter();
333                 self.minstanex_lasthit = 0;
334         }
335         else if (req == WR_CHECKAMMO1)
336         {
337                 if(autocvar_g_balance_minstanex_reload_ammo)
338                         return self.clip_load >= minstanex_ammo;
339                 else
340                         return self.ammo_cells >= minstanex_ammo;
341         }
342         else if (req == WR_CHECKAMMO2)
343         {
344                 if(W_Minstanex_LaserUsesLoad())
345                         return W_Minstanex_LaserUsesLoad();
346                 else
347                         return TRUE;
348         }
349         else if (req == WR_RESETPLAYER)
350         {
351                 self.minstanex_lasthit = 0;
352         }
353         else if (req == WR_RELOAD)
354         {
355                 W_Minstanex_Reload();
356         }
357         return TRUE;
358 };
359 #endif
360 #ifdef CSQC
361 float w_minstanex(float req)
362 {
363         if(req == WR_IMPACTEFFECT)
364         {
365                 vector org2;
366                 org2 = w_org + w_backoff * 6;
367                 pointparticles(particleeffectnum("nex_impact"), org2, '0 0 0', 1);
368                 if(!w_issilent)
369                         sound(self, CHAN_PROJECTILE, "weapons/neximpact.wav", VOL_BASE, ATTN_NORM);
370         }
371         else if(req == WR_PRECACHE)
372         {
373                 precache_sound("weapons/neximpact.wav");
374         }
375         else if (req == WR_SUICIDEMESSAGE)
376                 w_deathtypestring = "%s did the impossible";
377         else if (req == WR_KILLMESSAGE)
378                 w_deathtypestring = "%s has been vaporized by %s";
379         return TRUE;
380 }
381 #endif
382 #endif