Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
sv_instagib.qc
Go to the documentation of this file.
1#include "sv_instagib.qh"
2
3#include <server/client.qh>
8
14//int autocvar_g_instagib_ammo_drop;
20
25{
28 {
29 string cvar_name = sprintf("g_%s_%s_probability", prefix,
30 it.m_canonical_spawnfunc);
31 if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
32 {
33 LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
34 continue;
35 }
36 RandomSelection_AddString(it.m_canonical_spawnfunc, cvar(cvar_name), 1);
37 });
39}
40
44{
45 if (!e.instagib_needammo)
46 return;
47 Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER, CPID_INSTAGIB_FINDAMMO);
48 e.instagib_needammo = false;
49}
50
52{
53 float hp = GetResource(this, RES_HEALTH);
54
55 float dmg = (hp <= 10) ? 5 : 10;
56 Damage(this, this, this, dmg, DEATH_NOAMMO.m_id, DMG_NOWEP, this.origin, '0 0 0');
57
58 entity annce = (hp <= 5) ? ANNCE_INSTAGIB_TERMINATED : Announcer_PickNumber(CNT_NORMAL, ceil(hp / 10));
59 Send_Notification(NOTIF_ONE, this, MSG_ANNCE, annce);
60
61 if (hp > 80)
62 {
63 if (hp <= 90)
64 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_INSTAGIB_FINDAMMO);
65 else
66 Send_Notification(NOTIF_ONE_ONLY, this, MSG_MULTI, MULTI_INSTAGIB_FINDAMMO);
67 }
68}
69
71{
72 if(time < this.instagib_nextthink)
73 return;
74 if(!IS_PLAYER(this))
75 return; // not a player
76
77 if(IS_DEAD(this) || game_stopped)
79 else if (GetResource(this, RES_CELLS) > 0 || (this.items & IT_UNLIMITED_AMMO) || (this.flags & FL_GODMODE))
82 {
83 if(!this.instagib_needammo)
84 {
85 Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_INSTAGIB_DOWNGRADE);
86 this.instagib_needammo = true;
87 }
88 }
89 else
90 {
91 this.instagib_needammo = true;
93 }
94 this.instagib_nextthink = time + 1;
95}
96
97MUTATOR_HOOKFUNCTION(mutator_instagib, MatchEnd)
98{
100}
101
103{
105 M_ARGV(0, string));
106 return true;
107}
108
109MUTATOR_HOOKFUNCTION(mutator_instagib, MonsterDropItem)
110{
111 M_ARGV(1, string) = "vaporizer_cells";
112}
113
114MUTATOR_HOOKFUNCTION(mutator_instagib, MonsterSpawn)
115{
116 entity mon = M_ARGV(0, entity);
117
118 // always refill ammo
119 if(mon.monsterdef == MON_MAGE)
120 mon.skin = 1;
121}
122
123MUTATOR_HOOKFUNCTION(mutator_instagib, MakePlayerObserver)
124{
125 entity player = M_ARGV(0, entity);
126
128}
129
130MUTATOR_HOOKFUNCTION(mutator_instagib, ForbidRandomStartWeapons)
131{
132 return true;
133}
134
135MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerSpawn)
136{
137 entity player = M_ARGV(0, entity);
138
139 player.effects |= EF_FULLBRIGHT;
140}
141
143{
144 entity player = M_ARGV(0, entity);
145
146 instagib_ammocheck(player);
147}
148
149MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerRegen)
150{
151 // no regeneration in instagib
152 return true;
153}
154
155MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerDamage_SplitHealthArmor)
156{
157 M_ARGV(4, float) = M_ARGV(7, float); // take = damage
158 M_ARGV(5, float) = 0; // save
159}
160
161MUTATOR_HOOKFUNCTION(mutator_instagib, ForbidThrowCurrentWeapon)
162{
163 // weapon dropping on death handled by FilterItem
164 return true;
165}
166
167MUTATOR_HOOKFUNCTION(mutator_instagib, Damage_Calculate)
168{
169 entity frag_attacker = M_ARGV(1, entity);
171 float frag_deathtype = M_ARGV(3, float);
172 float frag_damage = M_ARGV(4, float);
173 float frag_mirrordamage = M_ARGV(5, float);
175
176 if(autocvar_g_friendlyfire == 0 && SAME_TEAM(frag_target, frag_attacker) && IS_PLAYER(frag_target) && IS_PLAYER(frag_attacker))
177 frag_damage = 0;
178
180 {
181 if(frag_deathtype == DEATH_FALL.m_id)
182 frag_damage = 0; // never count fall damage
183
185 switch(DEATH_ENT(frag_deathtype))
186 {
187 case DEATH_DROWN:
188 case DEATH_SLIME:
189 case DEATH_LAVA:
190 frag_damage = 0;
191 break;
192 }
193
194 if(IS_PLAYER(frag_attacker))
195 if(DEATH_ISWEAPON(frag_deathtype, WEP_VAPORIZER))
196 {
198 frag_force = '0 0 0';
199
200 float armor = GetResource(frag_target, RES_ARMOR);
201 if(armor)
202 {
203 --armor;
205 frag_damage = 0;
206 ++frag_target.hitsound_damage_dealt;
207 ++frag_attacker.hitsound_damage_dealt;
208 Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_INSTAGIB_LIVES_REMAINING, armor);
209 }
210 }
211
212 if(IS_PLAYER(frag_attacker) && DEATH_ISWEAPON(frag_deathtype, WEP_BLASTER))
213 {
215 {
216 frag_damage = 0;
218 frag_mirrordamage = 0; // never do mirror damage on enemies
219 }
220
221 if(frag_target != frag_attacker)
222 {
224 frag_force = '0 0 0';
225 }
226 }
227 }
228
229 if(!autocvar_g_instagib_mirrordamage) // only apply the taking lives hack if we don't want to support real damage mirroring
230 if(IS_PLAYER(frag_attacker))
231 if(frag_mirrordamage > 0)
232 {
233 // just lose extra LIVES, don't kill the player for mirror damage
234 float armor = GetResource(frag_attacker, RES_ARMOR);
235 if(armor > 0)
236 {
237 --armor;
238 SetResource(frag_attacker, RES_ARMOR, armor);
239 Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_INSTAGIB_LIVES_REMAINING, armor);
240 frag_attacker.hitsound_damage_dealt += frag_mirrordamage;
241 }
242 frag_mirrordamage = 0;
243 }
244
245 if(frag_target.alpha && frag_target.alpha < 1)
247 yoda = 1;
248
249 M_ARGV(4, float) = frag_damage;
250 M_ARGV(5, float) = frag_mirrordamage;
252}
253
254MUTATOR_HOOKFUNCTION(mutator_instagib, SetStartItems, CBC_ORDER_LAST)
255{
258
261 start_ammo_cells = warmup_start_ammo_cells = cvar("g_instagib_ammo_start");
263 //start_ammo_fuel = warmup_start_ammo_fuel = 0;
264
267}
268
269MUTATOR_HOOKFUNCTION(mutator_instagib, SetWeaponArena)
270{
271 // turn weapon arena off
272 M_ARGV(0, string) = "off";
273}
274
275MUTATOR_HOOKFUNCTION(mutator_instagib, SetWeaponStay)
276{
277 // turn weapon stay off
278 M_ARGV(0, int) = 0;
279}
280
282{
283 entity new_item = spawn();
284 switch (def)
285 {
286 case ITEM_Invisibility:
287 new_item.invisibility_finished = autocvar_g_instagib_invisibility_time;
288 break;
289 case ITEM_Speed:
290 new_item.speed_finished = autocvar_g_instagib_speed_time;
291 break;
292 }
293 Item_CopyFields(this, new_item);
294 StartItem(new_item, def);
295}
296
299
300// replaces item with a random powerup selected among the less spawned ones
302{
303 static int remaining_powerups_count = INSTAGIB_POWERUP_COUNT;
304 if (remaining_powerups_count == 0)
305 remaining_powerups_count = INSTAGIB_POWERUP_COUNT;
306 if (remaining_powerups_count == INSTAGIB_POWERUP_COUNT)
307 {
308 instagib_remaining_powerups[0] = ITEM_Invisibility;
309 instagib_remaining_powerups[1] = ITEM_ExtraLife;
310 instagib_remaining_powerups[2] = ITEM_Speed;
311 }
312
313 float r = floor(random() * remaining_powerups_count);
315 for(int i = r; i < INSTAGIB_POWERUP_COUNT - 1; ++i)
317 --remaining_powerups_count;
318}
319
320MUTATOR_HOOKFUNCTION(mutator_instagib, FilterItem)
321{
322 entity item = M_ARGV(0, entity);
323
324 switch (item.itemdef)
325 {
326 case ITEM_Strength: case ITEM_Shield: case ITEM_HealthMega: case ITEM_ArmorMega:
329 return true;
330 case ITEM_Invisibility: case ITEM_ExtraLife: case ITEM_Speed:
331 return false;
332 case ITEM_Cells:
334 instagib_replace_item_with(item, ITEM_VaporizerCells);
335 return true;
336 case ITEM_Rockets:
338 instagib_replace_item_with(item, ITEM_VaporizerCells);
339 return true;
340 case ITEM_Shells:
342 instagib_replace_item_with(item, ITEM_VaporizerCells);
343 return true;
344 case ITEM_Bullets:
346 instagib_replace_item_with(item, ITEM_VaporizerCells);
347 return true;
348 case ITEM_Jetpack:
349 case ITEM_FuelRegen:
351 }
352
353 switch (item.weapon)
354 {
355 case WEP_VAPORIZER.m_id:
356 if (ITEM_IS_LOOT(item))
357 {
359 return false;
360 }
361 break;
362 case WEP_DEVASTATOR.m_id: case WEP_VORTEX.m_id:
363 instagib_replace_item_with(item, ITEM_VaporizerCells);
364 return true;
365 }
366
367 float cells = GetResource(item, RES_CELLS);
368 if(cells > autocvar_g_instagib_ammo_drop && item.classname != "item_vaporizer_cells")
370
371 if(cells && !item.weapon)
372 return false;
373
374 return true;
375}
376
377MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerDies)
378{
379 float frag_deathtype = M_ARGV(3, float);
380
381 if(DEATH_ISWEAPON(frag_deathtype, WEP_VAPORIZER))
382 M_ARGV(4, float) = 1000; // always gib if it was a vaporizer death
383}
384
385MUTATOR_HOOKFUNCTION(mutator_instagib, ItemTouch)
386{
387 if(MUTATOR_RETURNVALUE) return false;
388
389 entity item = M_ARGV(0, entity);
391
392 if(GetResource(item, RES_CELLS))
393 {
394 // play some cool sounds ;)
395 float hp = GetResource(toucher, RES_HEALTH);
396 if (IS_CLIENT(toucher))
397 {
398 if(hp <= 5)
399 Send_Notification(NOTIF_ONE, toucher, MSG_ANNCE, ANNCE_INSTAGIB_LASTSECOND);
400 else if(hp < 50)
401 Send_Notification(NOTIF_ONE, toucher, MSG_ANNCE, ANNCE_INSTAGIB_NARROWLY);
402 }
403
404 if(hp < 100)
405 SetResource(toucher, RES_HEALTH, 100);
406
408 }
409
410 if(item.itemdef == ITEM_ExtraLife)
411 {
413 Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_EXTRALIVES, autocvar_g_instagib_extralives);
414 Inventory_pickupitem(item.itemdef, toucher);
416 }
417
419}
420
421MUTATOR_HOOKFUNCTION(mutator_instagib, BuildMutatorsString)
422{
423 M_ARGV(0, string) = strcat(M_ARGV(0, string), ":instagib");
424}
425
426MUTATOR_HOOKFUNCTION(mutator_instagib, BuildMutatorsPrettyString)
427{
428 M_ARGV(0, string) = strcat(M_ARGV(0, string), ", InstaGib");
429}
430
431MUTATOR_HOOKFUNCTION(mutator_instagib, SetModname)
432{
433 M_ARGV(0, string) = "InstaGib";
434 return true;
435}
const int CBC_ORDER_LAST
Definition base.qh:11
#define MUTATOR_HOOKFUNCTION(...)
Definition base.qh:335
#define MUTATOR_RETURNVALUE
Definition base.qh:328
float dmg
Definition breakable.qc:12
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
void SetResource(entity e, Resource res_type, float amount)
Sets the current amount of resource the given entity will have.
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
const int IT_UNLIMITED_AMMO
Definition item.qh:23
const int IT_UNLIMITED_SUPERWEAPONS
Definition item.qh:24
#define M_ARGV(x, type)
Definition events.qh:17
int autocvar_g_instagib_ammo_drop
Definition items.qh:13
int items
Definition player.qh:226
#define IS_CLIENT(s)
Definition player.qh:241
#define IS_DEAD(s)
Definition player.qh:244
#define IS_PLAYER(s)
Definition player.qh:242
float game_stopped
Definition stats.qh:81
Notification Announcer_PickNumber(int type, int num)
Definition util.qc:1926
const int CNT_NORMAL
Definition util.qh:258
const int FL_GODMODE
Definition constants.qh:67
float flags
float CVAR_TYPEFLAG_EXISTS
const float EF_FULLBRIGHT
float time
#define spawn
void Damage(entity targ, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
Definition damage.qc:484
float yoda
Definition damage.qh:48
#define DMG_NOWEP
Definition damage.qh:104
float autocvar_g_friendlyfire
Definition damage.qh:26
#define DEATH_ENT(t)
Definition all.qh:43
#define DEATH_ISWEAPON(t, w)
Definition all.qh:48
RES_ARMOR
Definition ent_cs.qc:155
#define IL_EACH(this, cond, body)
void Inventory_pickupitem(Pickup this, entity player)
Definition inventory.qh:161
bool Item_IsDefinitionAllowed(entity definition)
Checks whether the items with the specified definition are allowed to spawn.
Definition spawning.qc:17
#define ITEM_IS_LOOT(item)
Returns whether the item is loot.
Definition spawning.qh:39
#define PlayerPreThink
Definition _all.inc:258
#define LOG_WARNF(...)
Definition log.qh:59
float ceil(float f)
float cvar(string name)
float random(void)
float floor(float f)
strcat(_("^F4Countdown stopped!"), "\n^BG", _("Teams are too unbalanced."))
void Send_Notification(NOTIF broadcast, entity client, MSG net_type, Notification net_name,...count)
Definition all.qc:1500
void Kill_Notification(NOTIF broadcast, entity client, MSG net_type, CPID net_cpid)
Definition all.qc:1464
ERASEABLE void RandomSelection_Init()
Definition random.qc:4
string RandomSelection_chosen_string
Definition random.qh:7
#define RandomSelection_AddString(s, weight, priority)
Definition random.qh:16
vector
Definition self.qh:96
entity entity toucher
Definition self.qh:76
void Item_CopyFields(entity this, entity to)
Definition items.qc:851
void StartItem(entity this, entity def)
Definition items.qc:1007
@ MUT_ITEMTOUCH_PICKUP
Definition events.qh:736
@ MUT_ITEMTOUCH_CONTINUE
Definition events.qh:734
float frag_damage
Definition sv_ctf.qc:2316
vector frag_force
Definition sv_ctf.qc:2317
entity frag_target
Definition sv_ctf.qc:2315
bool autocvar_g_instagib_ammo_convert_cells
bool autocvar_g_instagib_friendlypush
GameItem instagib_remaining_powerups[INSTAGIB_POWERUP_COUNT]
void instagib_countdown(entity this)
float instagib_needammo
const int INSTAGIB_POWERUP_COUNT
bool autocvar_g_instagib_damagedbycontents
Definition sv_instagib.qc:9
float instagib_nextthink
bool autocvar_g_instagib_ammo_convert_bullets
bool autocvar_g_instagib_mirrordamage
bool autocvar_g_instagib_blaster_keepdamage
bool autocvar_g_instagib_ammo_convert_shells
void instagib_stop_countdown(entity e)
bool autocvar_g_instagib_allow_jetpacks
bool autocvar_g_instagib_blaster_keepforce
void instagib_replace_item_with(entity this, GameItem def)
void instagib_ammocheck(entity this)
void instagib_replace_item_with_random_powerup(entity item)
string RandomItems_GetRandomInstagibItemClassName(string prefix)
Returns a random classname of the instagib item.
bool autocvar_g_instagib_ammo_convert_rockets
float autocvar_g_instagib_speed_time
float autocvar_g_rm
Definition sv_instagib.qh:8
int autocvar_g_instagib_extralives
float autocvar_g_instagib_invisibility_time
IntrusiveList g_instagib_items
float autocvar_g_rm_laser
int autocvar_g_powerups
Definition sv_powerups.qh:7
string RandomItems_GetRandomItemClassName(string prefix)
Returns a random classname of the item.
Header file that describes the random items mutator.
void GiveResource(entity receiver, Resource res_type, float amount)
Gives an entity some resource.
#define SAME_TEAM(a, b)
Definition teams.qh:241
#define FOREACH_CLIENT(cond, body)
Definition utils.qh:52
#define WEPSET(id)
Definition all.qh:47
WepSet start_weapons
Definition world.qh:79
float warmup_start_ammo_cells
Definition world.qh:104
float start_ammo_shells
Definition world.qh:83
float warmup_start_ammo_rockets
Definition world.qh:103
float warmup_start_ammo_shells
Definition world.qh:101
int start_items
Definition world.qh:82
float warmup_start_ammo_nails
Definition world.qh:102
float start_ammo_cells
Definition world.qh:86
float warmup_start_health
Definition world.qh:106
float start_ammo_rockets
Definition world.qh:85
float start_armorvalue
Definition world.qh:96
WepSet warmup_start_weapons
Definition world.qh:97
float start_health
Definition world.qh:95
float warmup_start_armorvalue
Definition world.qh:107
float start_ammo_nails
Definition world.qh:84