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