]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/mutators/mutator_minstagib.qc
Initial commit
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / mutators / mutator_minstagib.qc
1 void spawnfunc_item_minst_cells (void) 
2 {
3         if not(g_minstagib)
4         {
5                 remove(self);
6                 return;
7         }
8 }
9
10 .float minstagib_nextthink;
11 .float minstagib_needammo;
12 void minstagib_stop_countdown(entity e)
13 {
14         if (!e.minstagib_needammo)
15                 return;
16         Send_CSQC_Centerprint_Generic_Expire(e, CPID_MINSTA_FINDAMMO);
17         e.minstagib_needammo = FALSE;
18 }
19 void minstagib_ammocheck(void)
20 {
21         if (time < self.minstagib_nextthink)
22                 return;
23
24         if (self.deadflag || gameover)
25                 minstagib_stop_countdown(self);
26         else if (self.ammo_cells > 0 || (self.items & IT_UNLIMITED_WEAPON_AMMO))
27         {
28                 minstagib_stop_countdown(self);
29                 if(self.health < 100)
30                         self.health = 100;
31         }
32         else
33         {
34                 self.minstagib_needammo = TRUE;
35                 if (self.health == 5)
36                 {
37                         Damage(self, self, self, 5, DEATH_NOAMMO, self.origin, '0 0 0');
38                         AnnounceTo(self, "terminated");
39                 }
40                 else if (self.health == 10)
41                 {
42                         Damage(self, self, self, 5, DEATH_NOAMMO, self.origin, '0 0 0');
43                         AnnounceTo(self, "1");
44                 }
45                 else if (self.health == 20)
46                 {
47                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
48                         AnnounceTo(self, "2");
49                 }
50                 else if (self.health == 30)
51                 {
52                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
53                         AnnounceTo(self, "3");
54                 }
55                 else if (self.health == 40)
56                 {
57                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
58                         AnnounceTo(self, "4");
59                 }
60                 else if (self.health == 50)
61                 {
62                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
63                         AnnounceTo(self, "5");
64                 }
65                 else if (self.health == 60)
66                 {
67                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
68                         AnnounceTo(self, "6");
69                 }
70                 else if (self.health == 70)
71                 {
72                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
73                         AnnounceTo(self, "7");
74                 }
75                 else if (self.health == 80)
76                 {
77                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
78                         AnnounceTo(self, "8");
79                 }
80                 else if (self.health == 90)
81                 {
82                         Send_CSQC_Centerprint_Generic(self, CPID_MINSTA_FINDAMMO, "^1%d^7 seconds left to find some ammo", 1, 9);
83                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
84                         AnnounceTo(self, "9");
85                 }
86                 else if (self.health == 100)
87                 {
88                         Send_CSQC_Centerprint_Generic(self, CPID_MINSTA_FINDAMMO, "get some ammo or\nyou'll be dead in ^3%d^7 seconds...", 1, 10);
89                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
90                         if not(self.flags & FL_GODMODE)
91                                 AnnounceTo(self, "10");
92                 }
93         }
94         self.minstagib_nextthink = time + 1;
95 }
96
97 MUTATOR_HOOKFUNCTION(minstagib_BotShouldAttack)
98 {
99         if(checkentity.items & IT_STRENGTH)
100                 return TRUE;
101                 
102         return FALSE;
103 }
104
105 MUTATOR_HOOKFUNCTION(minstagib_MakePlayerObserver)
106 {
107         minstagib_stop_countdown(self);
108         return FALSE;
109 }
110
111 MUTATOR_HOOKFUNCTION(minstagib_PlayerSpawn)
112 {
113         self.effects |= EF_FULLBRIGHT;
114         return FALSE;
115 }
116
117 MUTATOR_HOOKFUNCTION(minstagib_PlayerPreThink)
118 {
119         minstagib_ammocheck();
120         return FALSE;
121 }
122
123 MUTATOR_HOOKFUNCTION(minstagib_PlayerPowerups)
124 {
125         if not(self.effects & EF_FULLBRIGHT)
126                 self.effects |= EF_FULLBRIGHT;
127
128         if (self.items & IT_STRENGTH)
129         {
130                 play_countdown(self.strength_finished, "misc/poweroff.wav");
131                 if (time > self.strength_finished)
132                 {
133                         self.alpha = default_player_alpha;
134                         self.exteriorweaponentity.alpha = default_weapon_alpha;
135                         self.items &~= IT_STRENGTH;
136                         sprint(self, "^3Invisibility has worn off\n");
137                 }
138         }
139         else
140         {
141                 if (time < self.strength_finished)
142                 {
143                         self.alpha = g_minstagib_invis_alpha;
144                         self.exteriorweaponentity.alpha = g_minstagib_invis_alpha;
145                         self.items |= IT_STRENGTH;
146                         sprint(self, "^3You are invisible\n");
147                 }
148         }
149
150         if (self.items & IT_INVINCIBLE)
151         {
152                 play_countdown(self.invincible_finished, "misc/poweroff.wav");
153                 if (time > self.invincible_finished)
154                 {
155                         self.items &~= IT_INVINCIBLE;
156                         sprint(self, "^3Speed has worn off\n");
157                 }
158         }
159         else
160         {
161                 if (time < self.invincible_finished)
162                 {
163                         self.items |= IT_INVINCIBLE;
164                         sprint(self, "^3You are on speed\n");
165                 }
166         }
167         return FALSE;
168 }
169
170 MUTATOR_HOOKFUNCTION(minstagib_PlayerPhysics)
171 {
172         if(self.items & IT_INVINCIBLE)
173                 self.stat_sv_maxspeed = self.stat_sv_maxspeed * autocvar_g_minstagib_speed_highspeed;
174                 
175         return FALSE;
176 }
177
178 MUTATOR_HOOKFUNCTION(minstagib_SplitHealthArmor)
179 {
180         damage_save = 0;
181         damage_take = frag_damage;
182         
183         return FALSE;
184 }
185
186 MUTATOR_HOOKFUNCTION(minstagib_ForbidThrowing)
187 {
188         if (self.health < 1)
189                 return FALSE;
190                 
191         return TRUE;
192 }
193
194 MUTATOR_HOOKFUNCTION(minstagib_PlayStrengthSound)
195 {
196         // You shall not play!
197         return TRUE;
198 }
199
200 MUTATOR_HOOKFUNCTION(minstagib_PlayerDamage)
201 {
202         if(autocvar_g_friendlyfire == 0)
203                 frag_damage = 0;
204                 
205         if(frag_target.classname == "player")
206         {
207                 if ((frag_deathtype == DEATH_FALL)  ||
208                         (frag_deathtype == DEATH_DROWN) ||
209                         (frag_deathtype == DEATH_SLIME) ||
210                         (frag_deathtype == DEATH_LAVA))
211                 {
212                         frag_damage = 0;
213                 }
214                 
215                 if (frag_target.armorvalue && (frag_deathtype == WEP_MINSTANEX) && frag_damage)
216                 {
217                         frag_target.armorvalue -= 1;
218                         centerprint(frag_target, strcat("^3Remaining extra lives: ",ftos(frag_target.armorvalue)));
219                         frag_damage = 0;
220                         frag_target.hitsound += 1;
221                         frag_attacker.hitsound += 1; // TODO change this to a future specific hitsound for armor hit
222                 }
223                 if (DEATH_ISWEAPON(frag_deathtype, WEP_LASER))
224                 {
225                         frag_damage = 0;
226                         frag_mirrordamage = 0;
227                         if (frag_target != frag_attacker)
228                         {
229                                 if ((frag_target.health >= 1) && (frag_target.classname == "player"))
230                                         centerprint(frag_attacker, "Secondary fire inflicts no damage!");
231                                 frag_force = '0 0 0';
232                                 // keep mirrorfrag_force
233                                 frag_attacker = frag_target;
234                         }
235                 }
236         }
237         
238         if(frag_mirrordamage > 0)
239         {
240                 // just lose extra LIVES, don't kill the player for mirror damage
241                 if(frag_attacker.armorvalue > 0)
242                 {
243                         frag_attacker.armorvalue = frag_attacker.armorvalue - 1;
244                         centerprint(frag_attacker, strcat("^3Remaining extra lives: ", ftos(frag_attacker.armorvalue)));
245                         frag_attacker.hitsound += 1;
246                 }
247                 frag_mirrordamage = 0;
248         }
249         
250         if(frag_target.items & IT_STRENGTH)
251                 yoda = 1;
252                 
253         return FALSE;
254 }
255
256 MUTATOR_HOOKFUNCTION(minstagib_SetStartItems)
257 {
258         start_ammo_cells = cvar("g_minstagib_ammo_start");
259         
260         g_pinata = 0; // incompatible
261         g_weapon_stay = 0; // incompatible
262         g_bloodloss = 0; // incompatible
263         start_health = 100;
264         start_armorvalue = 0;
265         WEPSET_COPY_AW(start_weapons, WEP_MINSTANEX);
266         g_minstagib_invis_alpha = cvar("g_minstagib_invis_alpha");
267         start_items |= IT_UNLIMITED_SUPERWEAPONS;
268
269         if (g_minstagib_invis_alpha <= 0)
270                 g_minstagib_invis_alpha = -1;
271                 
272         return FALSE;
273 }
274
275 MUTATOR_HOOKFUNCTION(minstagib_FilterItem)
276 {
277         if(self.weapon == -2)
278                 return FALSE;
279                 
280         if(self.classname == "item_minst_cells" || self.weapon == WEP_ROCKET_LAUNCHER || self.weapon == WEP_NEX)
281         {
282                 self.ammo_cells = autocvar_g_minstagib_ammo_drop;
283                 StartItem ("models/items/a_cells.md3",
284                         "misc/itempickup.wav", 45, 0,
285                         "MinstaNex Ammo", IT_CELLS, -2, 0, generic_pickupevalfunc, 100);
286                 return FALSE;
287         }
288                 
289         if(self.flags & FL_POWERUP)
290         {
291                 // randomize
292                 float rnd = random() * 3;
293                 if (rnd <= 1)
294                         self.items = IT_STRENGTH;
295                 else if (rnd <= 2)
296                         self.items = IT_NAILS;
297                 else
298                         self.items = IT_INVINCIBLE;
299                 
300                 if (self.items == IT_STRENGTH)
301                 {
302                         if(!self.strength_finished)
303                                 self.strength_finished = autocvar_g_balance_powerup_strength_time;
304                         StartItem ("models/items/g_strength.md3",
305                                 "misc/powerup.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup,
306                                 "Invisibility", IT_STRENGTH, -2, FL_POWERUP, generic_pickupevalfunc, BOT_PICKUP_RATING_MID);
307                 }
308                 // replace with extra lives
309                 else if (self.items == IT_NAILS)
310                 {
311                         self.max_health = 1;
312                         StartItem ("models/items/g_h100.md3",
313                                 "misc/megahealth.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup,
314                                 "Extralife", IT_NAILS, -2, FL_POWERUP, generic_pickupevalfunc, BOT_PICKUP_RATING_HIGH);
315                 }
316                 // replace with speed
317                 else if (self.items == IT_INVINCIBLE)
318                 {
319                         if(!self.invincible_finished)
320                                 self.invincible_finished = autocvar_g_balance_powerup_invincible_time;
321                         StartItem ("models/items/g_invincible.md3",
322                                 "misc/powerup_shield.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup,
323                                 "Speed", IT_INVINCIBLE, -2, FL_POWERUP, generic_pickupevalfunc, BOT_PICKUP_RATING_MID);
324                 }
325                 return FALSE;
326         }
327                 
328         return TRUE;
329 }
330
331 MUTATOR_HOOKFUNCTION(minstagib_ItemCountdown)
332 {
333         switch(self.items)
334         {
335                 case IT_STRENGTH:   item_name = "item-invis"; item_color = '0 0 1'; break;
336                 case IT_NAILS:      item_name = "item-extralife"; item_color = '1 0 0'; break;
337                 case IT_INVINCIBLE: item_name = "item-speed"; item_color = '1 0 1'; break;
338         }
339         return FALSE;
340 }
341
342 MUTATOR_HOOKFUNCTION(minstagib_GiveItem)
343 {
344         float it;
345         float prevcells = giveplayer.ammo_cells;
346         
347         player_pickedup |= Item_GiveAmmoTo(giveitem, giveplayer, ammo_fuel, g_pickup_fuel_max, ITEM_MODE_FUEL);
348         player_pickedup |= Item_GiveAmmoTo(giveitem, giveplayer, ammo_cells, 999, ITEM_MODE_NONE);
349
350         if(giveplayer.ammo_cells > prevcells)
351         {
352                 player_wswitch = TRUE;
353                 // play some cool sounds ;)
354                 if (clienttype(giveplayer) == CLIENTTYPE_REAL)
355                 {
356                         if(giveplayer.health <= 5)
357                                 AnnounceTo(giveplayer, "lastsecond");
358                         else if(giveplayer.health < 50)
359                                 AnnounceTo(giveplayer, "narrowly");
360                 }
361
362                 if (WEPSET_CONTAINS_EW(giveitem, WEP_MINSTANEX))
363                         W_GiveWeapon (giveplayer, WEP_MINSTANEX, giveitem.netname);
364                 giveplayer.health = 100;
365         }
366
367         if((it = (giveitem.items - (giveitem.items & giveplayer.items)) & IT_PICKUPMASK))
368         {
369                 player_pickedup = TRUE;
370                 giveplayer.items |= it;
371                 sprint (giveplayer, strcat("You got the ^2", giveitem.netname, "\n"));
372         }
373
374         // extralife powerup
375         if (giveitem.max_health)
376         {
377                 player_pickedup = TRUE;
378                 // sound not available
379                 // AnnounceTo(giveplayer, "_lives");
380                 giveplayer.armorvalue = bound(giveplayer.armorvalue, 999, giveplayer.armorvalue + autocvar_g_minstagib_extralives);
381                 sprint(giveplayer, "^3You picked up some extra lives\n");
382         }
383
384         // invis powerup
385         if (giveitem.strength_finished)
386         {
387                 player_pickedup = TRUE;
388                 // sound not available
389                 // AnnounceTo(giveplayer, "invisible");
390                 giveplayer.strength_finished = max(giveplayer.strength_finished, time) + autocvar_g_balance_powerup_strength_time;
391         }
392
393         // speed powerup
394         if (giveitem.invincible_finished)
395         {
396                 player_pickedup = TRUE;
397                 // sound not available
398                 // AnnounceTo(giveplayer, "speed");
399                 giveplayer.invincible_finished = max(giveplayer.invincible_finished, time) + autocvar_g_balance_powerup_invincible_time;
400         }
401                 
402         return TRUE;
403 }
404
405 MUTATOR_HOOKFUNCTION(minstagib_BuildMutatorsString)
406 {
407         ret_string = strcat(ret_string, ":MinstaGib");
408         return FALSE;
409 }
410
411 MUTATOR_HOOKFUNCTION(minstagib_BuildMutatorsPrettyString)
412 {
413         ret_string = strcat(ret_string, ", MinstaGib");
414         return FALSE;
415 }
416
417 MUTATOR_DEFINITION(mutator_minstagib)
418 {
419         MUTATOR_HOOK(BotShouldAttack, minstagib_BotShouldAttack, CBC_ORDER_ANY);
420         MUTATOR_HOOK(PlayerPhysics, minstagib_PlayerPhysics, CBC_ORDER_ANY);
421         MUTATOR_HOOK(PlayerSpawn, minstagib_PlayerSpawn, CBC_ORDER_ANY);
422         MUTATOR_HOOK(PlayerDamage_Calculate, minstagib_PlayerDamage, CBC_ORDER_ANY);
423         MUTATOR_HOOK(PlayStrengthSound, minstagib_PlayStrengthSound, CBC_ORDER_ANY);
424         MUTATOR_HOOK(MakePlayerObserver, minstagib_MakePlayerObserver, CBC_ORDER_ANY);
425         MUTATOR_HOOK(SetStartItems, minstagib_SetStartItems, CBC_ORDER_ANY);
426         MUTATOR_HOOK(FilterItem, minstagib_FilterItem, CBC_ORDER_ANY);
427         MUTATOR_HOOK(Item_RespawnCountdown, minstagib_ItemCountdown, CBC_ORDER_ANY);
428         MUTATOR_HOOK(PlayerDamage_SplitHealthArmor, minstagib_SplitHealthArmor, CBC_ORDER_ANY);
429         MUTATOR_HOOK(PlayerPowerups, minstagib_PlayerPowerups, CBC_ORDER_ANY);
430         MUTATOR_HOOK(ForbidThrowCurrentWeapon, minstagib_ForbidThrowing, CBC_ORDER_ANY);
431         MUTATOR_HOOK(PlayerPreThink, minstagib_PlayerPreThink, CBC_ORDER_ANY);
432         MUTATOR_HOOK(BuildMutatorsString, minstagib_BuildMutatorsString, CBC_ORDER_ANY);
433         MUTATOR_HOOK(BuildMutatorsPrettyString, minstagib_BuildMutatorsPrettyString, CBC_ORDER_ANY);
434
435         return FALSE;
436 }