5 #include "../cl_client.qh"
6 #include "../../common/buffs.qh"
8 #include "../../common/items/item.qh"
10 #define WITH(it) this.m_##it;
11 #define CONFIGURE(...) MAP(WITH, __VA_ARGS__)
13 float instagib_respawntime_ammo = 45;
14 float instagib_respawntimejitter_ammo = 0;
15 GETTER(float, instagib_respawntime_ammo)
16 GETTER(float, instagib_respawntimejitter_ammo)
18 REGISTER_ITEM(VaporizerCells, Pickup, APPLY(UNWORDS
20 , model = "models/items/a_cells.md3"
21 , sound = "misc/itempickup.wav"
22 , name = "Vaporizer Ammo"
27 , respawntime = GET(instagib_respawntime_ammo)
28 , respawntimejitter = GET(instagib_respawntimejitter_ammo)
32 REGISTER_ITEM(ExtraLife, Pickup, APPLY(UNWORDS
34 , model = "models/items/g_h100.md3"
35 , sound = "misc/megahealth.wav"
39 , botvalue = BOT_PICKUP_RATING_HIGH
40 , itemflags = FL_POWERUP
42 , respawntime = GET(g_pickup_respawntime_powerup)
43 , respawntimejitter = GET(g_pickup_respawntimejitter_powerup)
50 void spawnfunc_item_minst_cells (void)
52 if (!g_instagib) { remove(self); return; }
54 self.ammo_cells = autocvar_g_instagib_ammo_drop;
56 StartItemA (ITEM_VaporizerCells);
59 void instagib_health_mega()
62 StartItemA (ITEM_ExtraLife);
65 .float instagib_nextthink;
66 .float instagib_needammo;
67 void instagib_stop_countdown(entity e)
69 if (!e.instagib_needammo)
71 Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER_CPID, CPID_INSTAGIB_FINDAMMO);
72 e.instagib_needammo = false;
74 void instagib_ammocheck()
76 if(time < self.instagib_nextthink)
79 return; // not a player
81 if(self.deadflag || gameover)
82 instagib_stop_countdown(self);
83 else if (self.ammo_cells > 0 || (self.items & IT_UNLIMITED_WEAPON_AMMO) || (self.flags & FL_GODMODE))
84 instagib_stop_countdown(self);
87 self.instagib_needammo = true;
90 Damage(self, self, self, 5, DEATH_NOAMMO, self.origin, '0 0 0');
91 Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_INSTAGIB_TERMINATED);
93 else if (self.health <= 10)
95 Damage(self, self, self, 5, DEATH_NOAMMO, self.origin, '0 0 0');
96 Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_1);
98 else if (self.health <= 20)
100 Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
101 Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_2);
103 else if (self.health <= 30)
105 Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
106 Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_3);
108 else if (self.health <= 40)
110 Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
111 Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_4);
113 else if (self.health <= 50)
115 Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
116 Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_5);
118 else if (self.health <= 60)
120 Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
121 Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_6);
123 else if (self.health <= 70)
125 Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
126 Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_7);
128 else if (self.health <= 80)
130 Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
131 Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_8);
133 else if (self.health <= 90)
135 Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_INSTAGIB_FINDAMMO);
136 Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
137 Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_9);
141 Send_Notification(NOTIF_ONE_ONLY, self, MSG_MULTI, MULTI_INSTAGIB_FINDAMMO);
142 Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
145 self.instagib_nextthink = time + 1;
148 MUTATOR_HOOKFUNCTION(instagib_MatchEnd)
151 FOR_EACH_PLAYER(head)
152 instagib_stop_countdown(head);
157 MUTATOR_HOOKFUNCTION(instagib_MonsterLoot)
159 other.monster_loot = spawnfunc_item_minst_cells;
164 MUTATOR_HOOKFUNCTION(instagib_MonsterSpawn)
166 // always refill ammo
167 if(self.monsterid == MON_MAGE)
173 MUTATOR_HOOKFUNCTION(instagib_BotShouldAttack)
175 if(checkentity.items & IT_STRENGTH)
181 MUTATOR_HOOKFUNCTION(instagib_MakePlayerObserver)
183 instagib_stop_countdown(self);
187 MUTATOR_HOOKFUNCTION(instagib_PlayerSpawn)
189 self.effects |= EF_FULLBRIGHT;
193 MUTATOR_HOOKFUNCTION(instagib_PlayerPreThink)
195 instagib_ammocheck();
199 MUTATOR_HOOKFUNCTION(instagib_PlayerRegen)
201 // no regeneration in instagib
205 MUTATOR_HOOKFUNCTION(instagib_PlayerPowerups)
207 if (!(self.effects & EF_FULLBRIGHT))
208 self.effects |= EF_FULLBRIGHT;
210 if (self.items & IT_STRENGTH)
212 play_countdown(self.strength_finished, "misc/poweroff.wav");
213 if (time > self.strength_finished)
215 self.alpha = default_player_alpha;
216 self.exteriorweaponentity.alpha = default_weapon_alpha;
217 self.items &= ~IT_STRENGTH;
218 Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_INVISIBILITY);
223 if (time < self.strength_finished)
225 self.alpha = autocvar_g_instagib_invis_alpha;
226 self.exteriorweaponentity.alpha = autocvar_g_instagib_invis_alpha;
227 self.items |= IT_STRENGTH;
228 Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_INVISIBILITY, self.netname);
229 Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_INVISIBILITY);
233 if (self.items & IT_INVINCIBLE)
235 play_countdown(self.invincible_finished, "misc/poweroff.wav");
236 if (time > self.invincible_finished)
238 self.items &= ~IT_INVINCIBLE;
239 Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_SPEED);
244 if (time < self.invincible_finished)
246 self.items |= IT_INVINCIBLE;
247 Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_SPEED, self.netname);
248 Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_SPEED);
254 MUTATOR_HOOKFUNCTION(instagib_PlayerPhysics)
256 if(self.items & IT_INVINCIBLE)
257 self.stat_sv_maxspeed = self.stat_sv_maxspeed * autocvar_g_instagib_speed_highspeed;
262 MUTATOR_HOOKFUNCTION(instagib_SplitHealthArmor)
265 damage_take = frag_damage;
270 MUTATOR_HOOKFUNCTION(instagib_ForbidThrowing)
272 // weapon dropping on death handled by FilterItem
277 MUTATOR_HOOKFUNCTION(instagib_PlayerDamage)
279 if(autocvar_g_friendlyfire == 0 && SAME_TEAM(frag_target, frag_attacker) && IS_PLAYER(frag_target) && IS_PLAYER(frag_attacker))
282 if(IS_PLAYER(frag_target))
284 if ((frag_deathtype == DEATH_FALL) ||
285 (frag_deathtype == DEATH_DROWN) ||
286 (frag_deathtype == DEATH_SLIME) ||
287 (frag_deathtype == DEATH_LAVA))
292 if(IS_PLAYER(frag_attacker))
293 if(DEATH_ISWEAPON(frag_deathtype, WEP_VAPORIZER))
295 if(frag_target.armorvalue)
297 frag_target.armorvalue -= 1;
299 frag_target.damage_dealt += 1;
300 frag_attacker.damage_dealt += 1; // TODO: change this to a specific hitsound for armor hit
301 Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_INSTAGIB_LIVES_REMAINING, frag_target.armorvalue);
305 if(IS_PLAYER(frag_attacker) && DEATH_ISWEAPON(frag_deathtype, WEP_BLASTER))
307 if(frag_deathtype & HITTYPE_SECONDARY)
309 frag_damage = frag_mirrordamage = 0;
311 if(frag_target != frag_attacker)
313 if(frag_target.health > 0) { Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_SECONDARY_NODAMAGE); }
314 frag_force = '0 0 0';
320 if(IS_PLAYER(frag_attacker))
321 if(frag_mirrordamage > 0)
323 // just lose extra LIVES, don't kill the player for mirror damage
324 if(frag_attacker.armorvalue > 0)
326 frag_attacker.armorvalue -= 1;
327 Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_INSTAGIB_LIVES_REMAINING, frag_attacker.armorvalue);
328 frag_attacker.damage_dealt += 1;
330 frag_mirrordamage = 0;
333 if((frag_target.buffs & BUFF_INVISIBLE) || (frag_target.items & IT_STRENGTH))
339 MUTATOR_HOOKFUNCTION(instagib_SetStartItems)
341 start_health = warmup_start_health = 100;
342 start_armorvalue = warmup_start_armorvalue = 0;
344 start_ammo_shells = warmup_start_ammo_shells = 0;
345 start_ammo_nails = warmup_start_ammo_nails = 0;
346 start_ammo_cells = warmup_start_ammo_cells = cvar("g_instagib_ammo_start");
347 start_ammo_plasma = warmup_start_ammo_plasma = 0;
348 start_ammo_rockets = warmup_start_ammo_rockets = 0;
349 start_ammo_fuel = warmup_start_ammo_fuel = 0;
351 start_weapons = warmup_start_weapons = WEPSET_VAPORIZER;
352 start_items |= IT_UNLIMITED_SUPERWEAPONS;
357 MUTATOR_HOOKFUNCTION(instagib_FilterItem)
359 if(self.classname == "item_cells")
360 return true; // no normal cells?
362 if(self.weapon == WEP_VAPORIZER && self.classname == "droppedweapon")
364 self.ammo_cells = autocvar_g_instagib_ammo_drop;
368 if(self.weapon == WEP_DEVASTATOR || self.weapon == WEP_VORTEX)
371 setorigin(e, self.origin);
375 spawnfunc_item_minst_cells();
380 if(self.flags & FL_POWERUP)
383 if(self.ammo_cells > autocvar_g_instagib_ammo_drop && self.classname != "item_minst_cells")
384 self.ammo_cells = autocvar_g_instagib_ammo_drop;
386 if(self.ammo_cells && !self.weapon)
392 MUTATOR_HOOKFUNCTION(instagib_CustomizeWaypoint)
394 entity e = WaypointSprite_getviewentity(other);
396 // if you have the invisibility powerup, sprites ALWAYS are restricted to your team
397 // but only apply this to real players, not to spectators
398 if((self.owner.flags & FL_CLIENT) && (self.owner.items & IT_STRENGTH) && (e == other))
399 if(DIFF_TEAM(self.owner, e))
405 MUTATOR_HOOKFUNCTION(instagib_ItemCountdown)
409 case IT_STRENGTH: item_name = "item-invis"; item_color = '0 0 1'; break;
410 case IT_NAILS: item_name = "item-extralife"; item_color = '1 0 0'; break;
411 case IT_INVINCIBLE: item_name = "item-speed"; item_color = '1 0 1'; break;
416 MUTATOR_HOOKFUNCTION(instagib_ItemTouch)
420 // play some cool sounds ;)
421 if (IS_CLIENT(other))
423 if(other.health <= 5)
424 Send_Notification(NOTIF_ONE, other, MSG_ANNCE, ANNCE_INSTAGIB_LASTSECOND);
425 else if(other.health < 50)
426 Send_Notification(NOTIF_ONE, other, MSG_ANNCE, ANNCE_INSTAGIB_NARROWLY);
429 if(other.health < 100)
432 return MUT_ITEMTOUCH_CONTINUE;
437 other.armorvalue = bound(other.armorvalue, 999, other.armorvalue + autocvar_g_instagib_extralives);
438 Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_EXTRALIVES);
439 return MUT_ITEMTOUCH_PICKUP;
442 return MUT_ITEMTOUCH_CONTINUE;
445 MUTATOR_HOOKFUNCTION(instagib_OnEntityPreSpawn)
447 if (!autocvar_g_powerups) { return false; }
448 if (!(self.classname == "item_strength" || self.classname == "item_invincible" || self.classname == "item_health_mega"))
454 e.think = spawnfunc_item_strength;
455 else if(random() < 0.6)
456 e.think = instagib_health_mega;
458 e.think = spawnfunc_item_invincible;
460 e.nextthink = time + 0.1;
461 e.spawnflags = self.spawnflags;
462 e.noalign = self.noalign;
463 setorigin(e, self.origin);
468 MUTATOR_HOOKFUNCTION(instagib_BuildMutatorsString)
470 ret_string = strcat(ret_string, ":instagib");
474 MUTATOR_HOOKFUNCTION(instagib_BuildMutatorsPrettyString)
476 ret_string = strcat(ret_string, ", instagib");
480 MUTATOR_HOOKFUNCTION(instagib_SetModname)
482 modname = "instagib";
486 MUTATOR_DEFINITION(mutator_instagib)
488 MUTATOR_HOOK(MatchEnd, instagib_MatchEnd, CBC_ORDER_ANY);
489 MUTATOR_HOOK(MonsterDropItem, instagib_MonsterLoot, CBC_ORDER_ANY);
490 MUTATOR_HOOK(MonsterSpawn, instagib_MonsterSpawn, CBC_ORDER_ANY);
491 MUTATOR_HOOK(BotShouldAttack, instagib_BotShouldAttack, CBC_ORDER_ANY);
492 MUTATOR_HOOK(PlayerPhysics, instagib_PlayerPhysics, CBC_ORDER_ANY);
493 MUTATOR_HOOK(PlayerSpawn, instagib_PlayerSpawn, CBC_ORDER_ANY);
494 MUTATOR_HOOK(PlayerDamage_Calculate, instagib_PlayerDamage, CBC_ORDER_ANY);
495 MUTATOR_HOOK(MakePlayerObserver, instagib_MakePlayerObserver, CBC_ORDER_ANY);
496 MUTATOR_HOOK(SetStartItems, instagib_SetStartItems, CBC_ORDER_ANY);
497 MUTATOR_HOOK(ItemTouch, instagib_ItemTouch, CBC_ORDER_ANY);
498 MUTATOR_HOOK(FilterItem, instagib_FilterItem, CBC_ORDER_ANY);
499 MUTATOR_HOOK(CustomizeWaypoint, instagib_CustomizeWaypoint, CBC_ORDER_ANY);
500 MUTATOR_HOOK(Item_RespawnCountdown, instagib_ItemCountdown, CBC_ORDER_ANY);
501 MUTATOR_HOOK(PlayerDamage_SplitHealthArmor, instagib_SplitHealthArmor, CBC_ORDER_ANY);
502 MUTATOR_HOOK(PlayerPowerups, instagib_PlayerPowerups, CBC_ORDER_ANY);
503 MUTATOR_HOOK(ForbidThrowCurrentWeapon, instagib_ForbidThrowing, CBC_ORDER_ANY);
504 MUTATOR_HOOK(PlayerPreThink, instagib_PlayerPreThink, CBC_ORDER_ANY);
505 MUTATOR_HOOK(PlayerRegen, instagib_PlayerRegen, CBC_ORDER_ANY);
506 MUTATOR_HOOK(OnEntityPreSpawn, instagib_OnEntityPreSpawn, CBC_ORDER_ANY);
507 MUTATOR_HOOK(BuildMutatorsString, instagib_BuildMutatorsString, CBC_ORDER_ANY);
508 MUTATOR_HOOK(BuildMutatorsPrettyString, instagib_BuildMutatorsPrettyString, CBC_ORDER_ANY);
509 MUTATOR_HOOK(SetModname, instagib_SetModname, CBC_ORDER_ANY);