]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/mutators/mutator_instagib.qc
Use SELFPARAM() in every function that uses self
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / mutators / mutator_instagib.qc
1 #include "../_all.qh"
2
3 #include "mutator.qh"
4
5 #include "../cl_client.qh"
6 #include "../../common/buffs.qh"
7
8 #include "../../common/items/all.qc"
9
10 void spawnfunc_item_minst_cells (void)
11 {SELFPARAM();
12         if (!g_instagib) { remove(self); return; }
13         if (!self.ammo_cells)
14                 self.ammo_cells = autocvar_g_instagib_ammo_drop;
15
16         StartItemA (ITEM_VaporizerCells);
17 }
18
19 void instagib_health_mega()
20 {SELFPARAM();
21         self.max_health = 1;
22         StartItemA (ITEM_ExtraLife);
23 }
24
25 .float instagib_nextthink;
26 .float instagib_needammo;
27 void instagib_stop_countdown(entity e)
28 {
29         if (!e.instagib_needammo)
30                 return;
31         Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER_CPID, CPID_INSTAGIB_FINDAMMO);
32         e.instagib_needammo = false;
33 }
34 void instagib_ammocheck()
35 {SELFPARAM();
36         if(time < self.instagib_nextthink)
37                 return;
38         if(!IS_PLAYER(self))
39                 return; // not a player
40
41         if(self.deadflag || gameover)
42                 instagib_stop_countdown(self);
43         else if (self.ammo_cells > 0 || (self.items & IT_UNLIMITED_WEAPON_AMMO) || (self.flags & FL_GODMODE))
44                 instagib_stop_countdown(self);
45         else if(autocvar_g_rm && autocvar_g_rm_laser)
46         {
47                 if(!self.instagib_needammo)
48                 {
49                         Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_INSTAGIB_DOWNGRADE);
50                         self.instagib_needammo = true;
51                 }
52         }
53         else
54         {
55                 self.instagib_needammo = true;
56                 if (self.health <= 5)
57                 {
58                         Damage(self, self, self, 5, DEATH_NOAMMO, self.origin, '0 0 0');
59                         Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_INSTAGIB_TERMINATED);
60                 }
61                 else if (self.health <= 10)
62                 {
63                         Damage(self, self, self, 5, DEATH_NOAMMO, self.origin, '0 0 0');
64                         Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_1);
65                 }
66                 else if (self.health <= 20)
67                 {
68                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
69                         Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_2);
70                 }
71                 else if (self.health <= 30)
72                 {
73                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
74                         Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_3);
75                 }
76                 else if (self.health <= 40)
77                 {
78                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
79                         Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_4);
80                 }
81                 else if (self.health <= 50)
82                 {
83                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
84                         Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_5);
85                 }
86                 else if (self.health <= 60)
87                 {
88                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
89                         Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_6);
90                 }
91                 else if (self.health <= 70)
92                 {
93                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
94                         Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_7);
95                 }
96                 else if (self.health <= 80)
97                 {
98                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
99                         Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_8);
100                 }
101                 else if (self.health <= 90)
102                 {
103                         Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_INSTAGIB_FINDAMMO);
104                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
105                         Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_9);
106                 }
107                 else
108                 {
109                         Send_Notification(NOTIF_ONE_ONLY, self, MSG_MULTI, MULTI_INSTAGIB_FINDAMMO);
110                         Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
111                 }
112         }
113         self.instagib_nextthink = time + 1;
114 }
115
116 MUTATOR_HOOKFUNCTION(instagib_MatchEnd)
117 {
118         entity head;
119         FOR_EACH_PLAYER(head)
120                 instagib_stop_countdown(head);
121
122         return false;
123 }
124
125 MUTATOR_HOOKFUNCTION(instagib_MonsterLoot)
126 {
127         other.monster_loot = spawnfunc_item_minst_cells;
128
129         return false;
130 }
131
132 MUTATOR_HOOKFUNCTION(instagib_MonsterSpawn)
133 {SELFPARAM();
134         // always refill ammo
135         if(self.monsterid == MON_MAGE.monsterid)
136                 self.skin = 1;
137
138         return false;
139 }
140
141 MUTATOR_HOOKFUNCTION(instagib_BotShouldAttack)
142 {
143         if(checkentity.items & ITEM_Strength.m_itemid)
144                 return true;
145
146         return false;
147 }
148
149 MUTATOR_HOOKFUNCTION(instagib_MakePlayerObserver)
150 {SELFPARAM();
151         instagib_stop_countdown(self);
152         return false;
153 }
154
155 MUTATOR_HOOKFUNCTION(instagib_PlayerSpawn)
156 {SELFPARAM();
157         self.effects |= EF_FULLBRIGHT;
158         return false;
159 }
160
161 MUTATOR_HOOKFUNCTION(instagib_PlayerPreThink)
162 {
163         instagib_ammocheck();
164         return false;
165 }
166
167 MUTATOR_HOOKFUNCTION(instagib_PlayerRegen)
168 {
169         // no regeneration in instagib
170         return true;
171 }
172
173 MUTATOR_HOOKFUNCTION(instagib_PlayerPowerups)
174 {SELFPARAM();
175         if (!(self.effects & EF_FULLBRIGHT))
176                 self.effects |= EF_FULLBRIGHT;
177
178         if (self.items & ITEM_Strength.m_itemid)
179         {
180                 play_countdown(self.strength_finished, "misc/poweroff.wav");
181                 if (time > self.strength_finished)
182                 {
183                         self.alpha = default_player_alpha;
184                         self.exteriorweaponentity.alpha = default_weapon_alpha;
185                         self.items &= ~ITEM_Strength.m_itemid;
186                         Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_INVISIBILITY);
187                 }
188         }
189         else
190         {
191                 if (time < self.strength_finished)
192                 {
193                         self.alpha = autocvar_g_instagib_invis_alpha;
194                         self.exteriorweaponentity.alpha = autocvar_g_instagib_invis_alpha;
195                         self.items |= ITEM_Strength.m_itemid;
196                         Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_INVISIBILITY, self.netname);
197                         Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_INVISIBILITY);
198                 }
199         }
200
201         if (self.items & ITEM_Shield.m_itemid)
202         {
203                 play_countdown(self.invincible_finished, "misc/poweroff.wav");
204                 if (time > self.invincible_finished)
205                 {
206                         self.items &= ~ITEM_Shield.m_itemid;
207                         Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_SPEED);
208                 }
209         }
210         else
211         {
212                 if (time < self.invincible_finished)
213                 {
214                         self.items |= ITEM_Shield.m_itemid;
215                         Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_SPEED, self.netname);
216                         Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_SPEED);
217                 }
218         }
219         return false;
220 }
221
222 MUTATOR_HOOKFUNCTION(instagib_PlayerPhysics)
223 {SELFPARAM();
224         if(self.items & ITEM_Shield.m_itemid)
225                 self.stat_sv_maxspeed = self.stat_sv_maxspeed * autocvar_g_instagib_speed_highspeed;
226
227         return false;
228 }
229
230 MUTATOR_HOOKFUNCTION(instagib_SplitHealthArmor)
231 {
232         damage_save = 0;
233         damage_take = frag_damage;
234
235         return false;
236 }
237
238 MUTATOR_HOOKFUNCTION(instagib_ForbidThrowing)
239 {
240         // weapon dropping on death handled by FilterItem
241
242         return true;
243 }
244
245 MUTATOR_HOOKFUNCTION(instagib_PlayerDamage)
246 {
247         if(autocvar_g_friendlyfire == 0 && SAME_TEAM(frag_target, frag_attacker) && IS_PLAYER(frag_target) && IS_PLAYER(frag_attacker))
248                 frag_damage = 0;
249
250         if(IS_PLAYER(frag_target))
251         {
252                 if ((frag_deathtype == DEATH_FALL)  ||
253                         (frag_deathtype == DEATH_DROWN) ||
254                         (frag_deathtype == DEATH_SLIME) ||
255                         (frag_deathtype == DEATH_LAVA))
256                 {
257                         frag_damage = 0;
258                 }
259
260                 if(IS_PLAYER(frag_attacker))
261                 if(DEATH_ISWEAPON(frag_deathtype, WEP_VAPORIZER.m_id))
262                 {
263                         if(frag_target.armorvalue)
264                         {
265                                 frag_target.armorvalue -= 1;
266                                 frag_damage = 0;
267                                 frag_target.damage_dealt += 1;
268                                 frag_attacker.damage_dealt += 1; // TODO: change this to a specific hitsound for armor hit
269                                 Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_INSTAGIB_LIVES_REMAINING, frag_target.armorvalue);
270                         }
271                 }
272
273                 if(IS_PLAYER(frag_attacker) && DEATH_ISWEAPON(frag_deathtype, WEP_BLASTER.m_id))
274                 {
275                         if(frag_deathtype & HITTYPE_SECONDARY)
276                         {
277                                 frag_damage = frag_mirrordamage = 0;
278
279                                 if(frag_target != frag_attacker)
280                                 {
281                                         if(frag_target.health > 0) { Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_SECONDARY_NODAMAGE); }
282                                         frag_force = '0 0 0';
283                                 }
284                         }
285                 }
286         }
287
288         if(IS_PLAYER(frag_attacker))
289         if(frag_mirrordamage > 0)
290         {
291                 // just lose extra LIVES, don't kill the player for mirror damage
292                 if(frag_attacker.armorvalue > 0)
293                 {
294                         frag_attacker.armorvalue -= 1;
295                         Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_INSTAGIB_LIVES_REMAINING, frag_attacker.armorvalue);
296                         frag_attacker.damage_dealt += 1;
297                 }
298                 frag_mirrordamage = 0;
299         }
300
301         if((frag_target.buffs & BUFF_INVISIBLE.m_itemid) || (frag_target.items & ITEM_Strength.m_itemid))
302                 yoda = 1;
303
304         return false;
305 }
306
307 MUTATOR_HOOKFUNCTION(instagib_SetStartItems)
308 {
309         start_health       = warmup_start_health       = 100;
310         start_armorvalue   = warmup_start_armorvalue   = 0;
311
312         start_ammo_shells  = warmup_start_ammo_shells  = 0;
313         start_ammo_nails   = warmup_start_ammo_nails   = 0;
314         start_ammo_cells   = warmup_start_ammo_cells   = cvar("g_instagib_ammo_start");
315         start_ammo_plasma  = warmup_start_ammo_plasma  = 0;
316         start_ammo_rockets = warmup_start_ammo_rockets = 0;
317         start_ammo_fuel    = warmup_start_ammo_fuel    = 0;
318
319         start_weapons = warmup_start_weapons = WEPSET_VAPORIZER;
320         start_items |= IT_UNLIMITED_SUPERWEAPONS;
321
322         return false;
323 }
324
325 MUTATOR_HOOKFUNCTION(instagib_FilterItem)
326 {SELFPARAM();
327         if(self.classname == "item_cells")
328                 return true; // no normal cells?
329
330         if(self.weapon == WEP_VAPORIZER.m_id && self.classname == "droppedweapon")
331         {
332                 self.ammo_cells = autocvar_g_instagib_ammo_drop;
333                 return false;
334         }
335
336         if(self.weapon == WEP_DEVASTATOR.m_id || self.weapon == WEP_VORTEX.m_id)
337         {
338                 entity e = spawn();
339                 setorigin(e, self.origin);
340                 entity oldself;
341                 oldself = self;
342                 self = e;
343                 spawnfunc_item_minst_cells();
344                 self = oldself;
345                 return true;
346         }
347
348         if(self.flags & FL_POWERUP)
349                 return false;
350
351         if(self.ammo_cells > autocvar_g_instagib_ammo_drop && self.classname != "item_minst_cells")
352                 self.ammo_cells = autocvar_g_instagib_ammo_drop;
353
354         if(self.ammo_cells && !self.weapon)
355                 return false;
356
357         return true;
358 }
359
360 MUTATOR_HOOKFUNCTION(instagib_CustomizeWaypoint)
361 {SELFPARAM();
362         entity e = WaypointSprite_getviewentity(other);
363
364         // if you have the invisibility powerup, sprites ALWAYS are restricted to your team
365         // but only apply this to real players, not to spectators
366         if((self.owner.flags & FL_CLIENT) && (self.owner.items & ITEM_Strength.m_itemid) && (e == other))
367         if(DIFF_TEAM(self.owner, e))
368                 return true;
369
370         return false;
371 }
372
373 MUTATOR_HOOKFUNCTION(instagib_ItemCountdown)
374 {SELFPARAM();
375         switch (self.items)
376         {
377                 case ITEM_Strength.m_itemid:  item_name = "item-invis";     item_color = '0 0 1'; break;
378                 case ITEM_ExtraLife.m_itemid: item_name = "item-extralife"; item_color = '1 0 0'; break;
379                 case ITEM_Shield.m_itemid:    item_name = "item-speed";     item_color = '1 0 1'; break;
380         }
381         return false;
382 }
383
384 MUTATOR_HOOKFUNCTION(instagib_ItemTouch)
385 {SELFPARAM();
386         if(self.ammo_cells)
387         {
388                 // play some cool sounds ;)
389                 if (IS_CLIENT(other))
390                 {
391                         if(other.health <= 5)
392                                 Send_Notification(NOTIF_ONE, other, MSG_ANNCE, ANNCE_INSTAGIB_LASTSECOND);
393                         else if(other.health < 50)
394                                 Send_Notification(NOTIF_ONE, other, MSG_ANNCE, ANNCE_INSTAGIB_NARROWLY);
395                 }
396
397                 if(other.health < 100)
398                         other.health = 100;
399
400                 return MUT_ITEMTOUCH_CONTINUE;
401         }
402
403         if(self.max_health)
404         {
405                 other.armorvalue = bound(other.armorvalue, 999, other.armorvalue + autocvar_g_instagib_extralives);
406                 Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_EXTRALIVES);
407                 return MUT_ITEMTOUCH_PICKUP;
408         }
409
410         return MUT_ITEMTOUCH_CONTINUE;
411 }
412
413 MUTATOR_HOOKFUNCTION(instagib_OnEntityPreSpawn)
414 {SELFPARAM();
415         if (!autocvar_g_powerups) { return false; }
416         if (!(self.classname == "item_strength" || self.classname == "item_invincible" || self.itemdef == ITEM_HealthMega))
417                 return false;
418
419         entity e = spawn();
420
421         if(random() < 0.3)
422                 e.think = spawnfunc_item_strength;
423         else if(random() < 0.6)
424                 e.think = instagib_health_mega;
425         else
426                 e.think = spawnfunc_item_invincible;
427
428         e.nextthink = time + 0.1;
429         e.spawnflags = self.spawnflags;
430         e.noalign = self.noalign;
431         setorigin(e, self.origin);
432
433         return true;
434 }
435
436 MUTATOR_HOOKFUNCTION(instagib_BuildMutatorsString)
437 {
438         ret_string = strcat(ret_string, ":instagib");
439         return false;
440 }
441
442 MUTATOR_HOOKFUNCTION(instagib_BuildMutatorsPrettyString)
443 {
444         ret_string = strcat(ret_string, ", instagib");
445         return false;
446 }
447
448 MUTATOR_HOOKFUNCTION(instagib_SetModname)
449 {
450         modname = "instagib";
451         return true;
452 }
453
454 MUTATOR_DEFINITION(mutator_instagib)
455 {
456         MUTATOR_HOOK(MatchEnd, instagib_MatchEnd, CBC_ORDER_ANY);
457         MUTATOR_HOOK(MonsterDropItem, instagib_MonsterLoot, CBC_ORDER_ANY);
458         MUTATOR_HOOK(MonsterSpawn, instagib_MonsterSpawn, CBC_ORDER_ANY);
459         MUTATOR_HOOK(BotShouldAttack, instagib_BotShouldAttack, CBC_ORDER_ANY);
460         MUTATOR_HOOK(PlayerPhysics, instagib_PlayerPhysics, CBC_ORDER_ANY);
461         MUTATOR_HOOK(PlayerSpawn, instagib_PlayerSpawn, CBC_ORDER_ANY);
462         MUTATOR_HOOK(PlayerDamage_Calculate, instagib_PlayerDamage, CBC_ORDER_ANY);
463         MUTATOR_HOOK(MakePlayerObserver, instagib_MakePlayerObserver, CBC_ORDER_ANY);
464         MUTATOR_HOOK(SetStartItems, instagib_SetStartItems, CBC_ORDER_ANY);
465         MUTATOR_HOOK(ItemTouch, instagib_ItemTouch, CBC_ORDER_ANY);
466         MUTATOR_HOOK(FilterItem, instagib_FilterItem, CBC_ORDER_ANY);
467         MUTATOR_HOOK(CustomizeWaypoint, instagib_CustomizeWaypoint, CBC_ORDER_ANY);
468         MUTATOR_HOOK(Item_RespawnCountdown, instagib_ItemCountdown, CBC_ORDER_ANY);
469         MUTATOR_HOOK(PlayerDamage_SplitHealthArmor, instagib_SplitHealthArmor, CBC_ORDER_ANY);
470         MUTATOR_HOOK(PlayerPowerups, instagib_PlayerPowerups, CBC_ORDER_ANY);
471         MUTATOR_HOOK(ForbidThrowCurrentWeapon, instagib_ForbidThrowing, CBC_ORDER_ANY);
472         MUTATOR_HOOK(PlayerPreThink, instagib_PlayerPreThink, CBC_ORDER_ANY);
473         MUTATOR_HOOK(PlayerRegen, instagib_PlayerRegen, CBC_ORDER_ANY);
474         MUTATOR_HOOK(OnEntityPreSpawn, instagib_OnEntityPreSpawn, CBC_ORDER_ANY);
475         MUTATOR_HOOK(BuildMutatorsString, instagib_BuildMutatorsString, CBC_ORDER_ANY);
476         MUTATOR_HOOK(BuildMutatorsPrettyString, instagib_BuildMutatorsPrettyString, CBC_ORDER_ANY);
477         MUTATOR_HOOK(SetModname, instagib_SetModname, CBC_ORDER_ANY);
478
479         return false;
480 }