Xonotic
sv_instagib.qc
Go to the documentation of this file.
1 #include "sv_instagib.qh"
2 
3 #include <server/client.qh>
4 #include <common/items/_mod.qh>
7 #include "../random_items/sv_random_items.qh"
8 
14 //int autocvar_g_instagib_ammo_drop;
19 
21 {
22  this.invisibility_finished = autocvar_g_instagib_invisibility_time;
23  StartItem(this, ITEM_Invisibility);
24 }
25 
27 {
28  StartItem(this, ITEM_ExtraLife);
29 }
30 
32 {
33  this.speed_finished = autocvar_g_instagib_speed_time;
34  StartItem(this, ITEM_Speed);
35 }
36 
41 {
44  {
45  string cvar_name = sprintf("g_%s_%s_probability", prefix,
46  it.m_canonical_spawnfunc);
47  if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
48  {
49  LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
50  continue;
51  }
52  RandomSelection_AddString(it.m_canonical_spawnfunc, cvar(cvar_name), 1);
53  });
55 }
56 
60 {
61  if (!e.instagib_needammo)
62  return;
63  Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER, CPID_INSTAGIB_FINDAMMO);
64  e.instagib_needammo = false;
65 }
66 
68 {
69  float hp = GetResource(this, RES_HEALTH);
70 
71  float dmg = (hp <= 10) ? 5 : 10;
72  Damage(this, this, this, dmg, DEATH_NOAMMO.m_id, DMG_NOWEP, this.origin, '0 0 0');
73 
74  entity annce = (hp <= 5) ? ANNCE_INSTAGIB_TERMINATED : Announcer_PickNumber(CNT_NORMAL, ceil(hp / 10));
75  Send_Notification(NOTIF_ONE, this, MSG_ANNCE, annce);
76 
77  if (hp > 80)
78  {
79  if (hp <= 90)
80  Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_INSTAGIB_FINDAMMO);
81  else
82  Send_Notification(NOTIF_ONE_ONLY, this, MSG_MULTI, MULTI_INSTAGIB_FINDAMMO);
83  }
84 }
85 
87 {
88  if(time < this.instagib_nextthink)
89  return;
90  if(!IS_PLAYER(this))
91  return; // not a player
92 
93  if(IS_DEAD(this) || game_stopped)
95  else if (GetResource(this, RES_CELLS) > 0 || (this.items & IT_UNLIMITED_AMMO) || (this.flags & FL_GODMODE))
98  {
99  if(!this.instagib_needammo)
100  {
101  Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_INSTAGIB_DOWNGRADE);
102  this.instagib_needammo = true;
103  }
104  }
105  else
106  {
107  this.instagib_needammo = true;
108  instagib_countdown(this);
109  }
110  this.instagib_nextthink = time + 1;
111 }
112 
113 MUTATOR_HOOKFUNCTION(mutator_instagib, MatchEnd)
114 {
116 }
117 
119 {
121  M_ARGV(0, string));
122  return true;
123 }
124 
125 MUTATOR_HOOKFUNCTION(mutator_instagib, MonsterDropItem)
126 {
127  entity item = M_ARGV(1, entity);
128 
129  item.monster_loot = ITEM_VaporizerCells;
130 }
131 
132 MUTATOR_HOOKFUNCTION(mutator_instagib, MonsterSpawn)
133 {
134  entity mon = M_ARGV(0, entity);
135 
136  // always refill ammo
137  if(mon.monsterdef == MON_MAGE)
138  mon.skin = 1;
139 }
140 
141 MUTATOR_HOOKFUNCTION(mutator_instagib, MakePlayerObserver)
142 {
143  entity player = M_ARGV(0, entity);
144 
145  instagib_stop_countdown(player);
146 }
147 
148 MUTATOR_HOOKFUNCTION(mutator_instagib, ForbidRandomStartWeapons)
149 {
150  return true;
151 }
152 
153 MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerSpawn)
154 {
155  entity player = M_ARGV(0, entity);
156 
157  player.effects |= EF_FULLBRIGHT;
158 }
159 
161 {
162  entity player = M_ARGV(0, entity);
163 
164  instagib_ammocheck(player);
165 }
166 
167 MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerRegen)
168 {
169  // no regeneration in instagib
170  return true;
171 }
172 
173 MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerDamage_SplitHealthArmor)
174 {
175  M_ARGV(4, float) = M_ARGV(7, float); // take = damage
176  M_ARGV(5, float) = 0; // save
177 }
178 
179 MUTATOR_HOOKFUNCTION(mutator_instagib, ForbidThrowCurrentWeapon)
180 {
181  // weapon dropping on death handled by FilterItem
182  return true;
183 }
184 
185 MUTATOR_HOOKFUNCTION(mutator_instagib, Damage_Calculate)
186 {
187  entity frag_attacker = M_ARGV(1, entity);
188  entity frag_target = M_ARGV(2, entity);
189  float frag_deathtype = M_ARGV(3, float);
190  float frag_damage = M_ARGV(4, float);
191  float frag_mirrordamage = M_ARGV(5, float);
192  vector frag_force = M_ARGV(6, vector);
193 
194  if(autocvar_g_friendlyfire == 0 && SAME_TEAM(frag_target, frag_attacker) && IS_PLAYER(frag_target) && IS_PLAYER(frag_attacker))
195  frag_damage = 0;
196 
197  if(IS_PLAYER(frag_target))
198  {
199  if(frag_deathtype == DEATH_FALL.m_id)
200  frag_damage = 0; // never count fall damage
201 
203  switch(DEATH_ENT(frag_deathtype))
204  {
205  case DEATH_DROWN:
206  case DEATH_SLIME:
207  case DEATH_LAVA:
208  frag_damage = 0;
209  break;
210  }
211 
212  if(IS_PLAYER(frag_attacker))
213  if(DEATH_ISWEAPON(frag_deathtype, WEP_VAPORIZER))
214  {
215  if(!autocvar_g_instagib_friendlypush && SAME_TEAM(frag_target, frag_attacker))
216  frag_force = '0 0 0';
217 
218  float armor = GetResource(frag_target, RES_ARMOR);
219  if(armor)
220  {
221  armor -= 1;
222  SetResource(frag_target, RES_ARMOR, armor);
223  frag_damage = 0;
224  frag_target.hitsound_damage_dealt += 1;
225  frag_attacker.hitsound_damage_dealt += 1;
226  Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_INSTAGIB_LIVES_REMAINING, armor);
227  }
228  }
229 
230  if(IS_PLAYER(frag_attacker) && DEATH_ISWEAPON(frag_deathtype, WEP_BLASTER))
231  {
232  if(frag_deathtype & HITTYPE_SECONDARY)
233  {
234  if(!autocvar_g_instagib_blaster_keepdamage || frag_attacker == frag_target)
235  {
236  frag_damage = 0;
238  frag_mirrordamage = 0; // never do mirror damage on enemies
239  }
240 
241  if(frag_target != frag_attacker)
242  {
244  frag_force = '0 0 0';
245  }
246  }
247  }
248  }
249 
250  if(!autocvar_g_instagib_mirrordamage) // only apply the taking lives hack if we don't want to support real damage mirroring
251  if(IS_PLAYER(frag_attacker))
252  if(frag_mirrordamage > 0)
253  {
254  // just lose extra LIVES, don't kill the player for mirror damage
255  float armor = GetResource(frag_attacker, RES_ARMOR);
256  if(armor > 0)
257  {
258  armor -= 1;
259  SetResource(frag_attacker, RES_ARMOR, armor);
260  Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_INSTAGIB_LIVES_REMAINING, armor);
261  frag_attacker.hitsound_damage_dealt += frag_mirrordamage;
262  }
263  frag_mirrordamage = 0;
264  }
265 
266  if(frag_target.alpha && frag_target.alpha < 1)
267  if(IS_PLAYER(frag_target))
268  yoda = 1;
269 
270  M_ARGV(4, float) = frag_damage;
271  M_ARGV(5, float) = frag_mirrordamage;
272  M_ARGV(6, vector) = frag_force;
273 }
274 
275 MUTATOR_HOOKFUNCTION(mutator_instagib, SetStartItems, CBC_ORDER_LAST)
276 {
279 
282  start_ammo_cells = warmup_start_ammo_cells = cvar("g_instagib_ammo_start");
285  //start_ammo_fuel = warmup_start_ammo_fuel = 0;
286 
288  start_items |= IT_UNLIMITED_SUPERWEAPONS;
289 }
290 
291 MUTATOR_HOOKFUNCTION(mutator_instagib, SetWeaponArena)
292 {
293  // turn weapon arena off
294  M_ARGV(0, string) = "off";
295 }
296 
298 {
299  entity e = new(item_vaporizer_cells);
300  setorigin(e, item.origin);
301  e.noalign = Item_ShouldKeepPosition(item);
302  e.cnt = item.cnt;
303  e.team = item.team;
304  e.spawnfunc_checked = true;
305  spawnfunc_item_vaporizer_cells(e);
306 }
307 
308 MUTATOR_HOOKFUNCTION(mutator_instagib, FilterItem)
309 {
310  entity item = M_ARGV(0, entity);
311 
312  if(item.classname == "item_cells")
313  {
315  {
317  }
318  return true;
319  }
320  else if(item.classname == "item_rockets")
321  {
323  {
325  }
326  return true;
327  }
328  else if(item.classname == "item_shells")
329  {
331  {
333  }
334  return true;
335  }
336  else if(item.classname == "item_bullets")
337  {
339  {
341  }
342  return true;
343  }
344 
345  if(item.weapon == WEP_VAPORIZER.m_id && Item_IsLoot(item))
346  {
347  SetResource(item, RES_CELLS, autocvar_g_instagib_ammo_drop);
348  return false;
349  }
350 
351  if(item.weapon == WEP_DEVASTATOR.m_id || item.weapon == WEP_VORTEX.m_id)
352  {
354  return true;
355  }
356 
357  if(item.itemdef.instanceOfPowerup)
358  return false;
359 
360  float cells = GetResource(item, RES_CELLS);
361  if(cells > autocvar_g_instagib_ammo_drop && item.classname != "item_vaporizer_cells")
362  SetResource(item, RES_CELLS, autocvar_g_instagib_ammo_drop);
363 
364  if(cells && !item.weapon)
365  return false;
366 
367  return true;
368 }
369 
370 MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerDies)
371 {
372  float frag_deathtype = M_ARGV(3, float);
373 
374  if(DEATH_ISWEAPON(frag_deathtype, WEP_VAPORIZER))
375  M_ARGV(4, float) = 1000; // always gib if it was a vaporizer death
376 }
377 
378 MUTATOR_HOOKFUNCTION(mutator_instagib, ItemTouch)
379 {
380  if(MUTATOR_RETURNVALUE) return false;
381 
382  entity item = M_ARGV(0, entity);
383  entity toucher = M_ARGV(1, entity);
384 
385  if(GetResource(item, RES_CELLS))
386  {
387  // play some cool sounds ;)
388  float hp = GetResource(toucher, RES_HEALTH);
389  if (IS_CLIENT(toucher))
390  {
391  if(hp <= 5)
392  Send_Notification(NOTIF_ONE, toucher, MSG_ANNCE, ANNCE_INSTAGIB_LASTSECOND);
393  else if(hp < 50)
394  Send_Notification(NOTIF_ONE, toucher, MSG_ANNCE, ANNCE_INSTAGIB_NARROWLY);
395  }
396 
397  if(hp < 100)
398  SetResource(toucher, RES_HEALTH, 100);
399 
400  return MUT_ITEMTOUCH_CONTINUE;
401  }
402 
403  if(item.itemdef == ITEM_ExtraLife)
404  {
405  GiveResource(toucher, RES_ARMOR, autocvar_g_instagib_extralives);
406  Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_EXTRALIVES, autocvar_g_instagib_extralives);
407  return MUT_ITEMTOUCH_PICKUP;
408  }
409 
410  return MUT_ITEMTOUCH_CONTINUE;
411 }
412 
413 MUTATOR_HOOKFUNCTION(mutator_instagib, OnEntityPreSpawn)
414 {
415  if (MUTATOR_RETURNVALUE) return false;
416  if (!autocvar_g_powerups) { return; }
417  entity ent = M_ARGV(0, entity);
418  // Can't use .itemdef here
419  if (!(ent.classname == "item_strength" || ent.classname == "item_shield" || ent.classname == "item_invincible" || ent.classname == "item_health_mega"))
420  return;
421 
422  entity e = spawn();
423 
424  float r = random();
425  if (r < 0.3)
426  {
427  e.classname = "item_invisibility";
429  }
430  else if (r < 0.6)
431  {
432  e.classname = "item_extralife";
434  }
435  else
436  {
437  e.classname = "item_speed";
439  }
440 
441  e.nextthink = time + 0.1;
442  e.spawnflags = ent.spawnflags;
443  e.noalign = ent.noalign;
444  setorigin(e, ent.origin);
445 
446  return true;
447 }
448 
449 MUTATOR_HOOKFUNCTION(mutator_instagib, BuildMutatorsString)
450 {
451  M_ARGV(0, string) = strcat(M_ARGV(0, string), ":instagib");
452 }
453 
454 MUTATOR_HOOKFUNCTION(mutator_instagib, BuildMutatorsPrettyString)
455 {
456  M_ARGV(0, string) = strcat(M_ARGV(0, string), ", instagib");
457 }
458 
459 MUTATOR_HOOKFUNCTION(mutator_instagib, SetModname)
460 {
461  M_ARGV(0, string) = "InstaGib";
462  return true;
463 }
#define WEPSET(id)
Definition: all.qh:37
#define IL_EACH(this, cond, body)
float start_ammo_rockets
Definition: world.qh:87
string RandomSelection_chosen_string
Definition: random.qh:7
void instagib_speed(entity this)
Definition: sv_instagib.qc:31
bool Item_IsDefinitionAllowed(entity definition)
Checks whether the items with the specified definition are allowed to spawn.
Definition: spawning.qc:55
float warmup_start_ammo_shells
Definition: world.qh:104
WepSet warmup_start_weapons
Definition: world.qh:100
WepSet start_weapons
Definition: world.qh:81
bool autocvar_g_instagib_ammo_convert_bullets
Definition: sv_instagib.qc:18
#define IS_CLIENT(v)
Definition: utils.qh:13
ERASEABLE void RandomSelection_Init()
Definition: random.qc:4
float CVAR_TYPEFLAG_EXISTS
entity() spawn
bool autocvar_g_instagib_friendlypush
Definition: sv_instagib.qc:13
#define FOREACH_CLIENT(cond, body)
Definition: utils.qh:49
void instagib_invisibility(entity this)
Definition: sv_instagib.qc:20
void instagib_stop_countdown(entity e)
Definition: sv_instagib.qc:59
bool autocvar_g_instagib_ammo_convert_shells
Definition: sv_instagib.qc:17
int start_items
Definition: world.qh:84
#define RandomSelection_AddString(s, weight, priority)
Definition: random.qh:16
float dmg
Definition: platforms.qh:6
float start_ammo_shells
Definition: world.qh:85
int autocvar_g_powerups
Definition: sv_powerups.qh:7
float FL_GODMODE
Definition: progsdefs.qc:237
#define DEATH_ENT(t)
Definition: all.qh:37
bool autocvar_g_instagib_ammo_convert_cells
Definition: sv_instagib.qc:15
void PlayerPreThink(entity this)
Definition: client.qc:2402
#define DMG_NOWEP
Definition: damage.qh:126
float warmup_start_ammo_plasma
Definition: world.qh:108
MUTATOR_HOOKFUNCTION(mutator_instagib, MatchEnd)
Definition: sv_instagib.qc:113
float instagib_nextthink
Definition: sv_instagib.qc:57
#define LOG_WARNF(...)
Definition: log.qh:67
RES_HEALTH
Definition: ent_cs.qc:126
const int CBC_ORDER_LAST
Definition: base.qh:8
const float EF_FULLBRIGHT
Definition: csprogsdefs.qc:303
string RandomItems_GetRandomInstagibItemClassName(string prefix)
Returns a random classname of the instagib item.
Definition: sv_instagib.qc:40
void replace_with_insta_cells(entity item)
Definition: sv_instagib.qc:297
bool autocvar_g_instagib_blaster_keepdamage
Definition: sv_instagib.qc:10
float autocvar_g_instagib_speed_time
Time of speed powerup in seconds.
Definition: sv_instagib.qh:33
float warmup_start_ammo_cells
Definition: world.qh:107
bool autocvar_g_instagib_damagedbycontents
Definition: sv_instagib.qc:9
void SetResource(entity e, Resource res_type, float amount)
Sets the current amount of resource the given entity will have.
Definition: cl_resources.qc:26
spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 f1 s1 strcat(_("Level %s: "), "^BG%s\3\, _("^BGPress ^F2%s^BG to enter the game"))
string RandomItems_GetRandomItemClassName(string prefix)
Returns a random classname of the item.
void StartItem(entity this, GameItem def)
Definition: items.qc:1148
float start_ammo_cells
Definition: world.qh:88
float instagib_needammo
Definition: sv_instagib.qc:58
float autocvar_g_rm
Definition: sv_instagib.qh:8
float autocvar_g_friendlyfire
Definition: damage.qh:25
void Damage(entity targ, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
Definition: damage.qc:583
#define MUTATOR_RETURNVALUE
Definition: base.qh:303
#define SAME_TEAM(a, b)
Definition: teams.qh:239
const int HITTYPE_SECONDARY
Definition: all.qh:25
#define M_ARGV(x, type)
Definition: events.qh:17
#define IS_DEAD(s)
Definition: utils.qh:26
IntrusiveList g_instagib_items
Definition: sv_instagib.qh:38
float warmup_start_armorvalue
Definition: world.qh:111
vector(float skel, float bonenum) _skel_get_boneabs_hidden
void GiveResource(entity receiver, Resource res_type, float amount)
Gives an entity some resource.
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
Definition: cl_resources.qc:10
bool autocvar_g_instagib_mirrordamage
Definition: sv_instagib.qc:12
float start_health
Definition: world.qh:98
float flags
Definition: csprogsdefs.qc:129
float warmup_start_ammo_rockets
Definition: world.qh:106
bool Item_ShouldKeepPosition(entity item)
Returns whether item should keep its position or be dropped to the ground.
Definition: spawning.qc:131
int autocvar_g_instagib_extralives
Definition: sv_instagib.qh:28
float items
Definition: progsdefs.qc:145
float start_ammo_nails
Definition: world.qh:86
bool autocvar_g_instagib_blaster_keepforce
Definition: sv_instagib.qc:11
float warmup_start_health
Definition: world.qh:110
float autocvar_g_instagib_invisibility_time
Time of invisibility powerup in seconds.
Definition: sv_instagib.qh:31
setorigin(ent, v)
bool Item_IsLoot(entity item)
Returns whether the item is loot.
Definition: spawning.qc:121
#define setthink(e, f)
bool autocvar_g_instagib_ammo_convert_rockets
Definition: sv_instagib.qc:16
#define DEATH_ISWEAPON(t, w)
Definition: all.qh:42
float time
Definition: csprogsdefs.qc:16
float start_armorvalue
Definition: world.qh:99
float start_ammo_plasma
Definition: world.qh:89
void instagib_extralife(entity this)
Definition: sv_instagib.qc:26
#define IS_PLAYER(v)
Definition: utils.qh:9
float yoda
Definition: damage.qh:51
void instagib_ammocheck(entity this)
Definition: sv_instagib.qc:86
float autocvar_g_rm_laser
Definition: sv_instagib.qh:13
void instagib_countdown(entity this)
Definition: sv_instagib.qc:67
float warmup_start_ammo_nails
Definition: world.qh:105