Integrated auto Reshoot on Kill
This commit is contained in:
parent
6e563162cf
commit
acf4e709b2
1 changed files with 434 additions and 0 deletions
|
@ -0,0 +1,434 @@
|
||||||
|
#include "sv_instagib.qh"
|
||||||
|
|
||||||
|
#include <server/client.qh>
|
||||||
|
#include <common/items/_mod.qh>
|
||||||
|
#include <common/mutators/mutator/powerups/_mod.qh>
|
||||||
|
#include <common/mutators/mutator/status_effects/_mod.qh>
|
||||||
|
#include "../random_items/sv_random_items.qh"
|
||||||
|
|
||||||
|
bool autocvar_g_instagib_damagedbycontents = true;
|
||||||
|
bool autocvar_g_instagib_blaster_keepdamage = false;
|
||||||
|
bool autocvar_g_instagib_blaster_keepforce = false;
|
||||||
|
bool autocvar_g_instagib_mirrordamage;
|
||||||
|
bool autocvar_g_instagib_friendlypush = true;
|
||||||
|
//int autocvar_g_instagib_ammo_drop;
|
||||||
|
bool autocvar_g_instagib_ammo_convert_cells;
|
||||||
|
bool autocvar_g_instagib_ammo_convert_rockets;
|
||||||
|
bool autocvar_g_instagib_ammo_convert_shells;
|
||||||
|
bool autocvar_g_instagib_ammo_convert_bullets;
|
||||||
|
|
||||||
|
/// \brief Returns a random classname of the instagib item.
|
||||||
|
/// \param[in] prefix Prefix of the cvars that hold probabilities.
|
||||||
|
/// \return Random classname of the instagib item.
|
||||||
|
string RandomItems_GetRandomInstagibItemClassName(string prefix)
|
||||||
|
{
|
||||||
|
RandomSelection_Init();
|
||||||
|
IL_EACH(g_instagib_items, Item_IsDefinitionAllowed(it),
|
||||||
|
{
|
||||||
|
string cvar_name = sprintf("g_%s_%s_probability", prefix,
|
||||||
|
it.m_canonical_spawnfunc);
|
||||||
|
if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
|
||||||
|
{
|
||||||
|
LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
RandomSelection_AddString(it.m_canonical_spawnfunc, cvar(cvar_name), 1);
|
||||||
|
});
|
||||||
|
return RandomSelection_chosen_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
.float instagib_nextthink;
|
||||||
|
.float instagib_needammo;
|
||||||
|
void instagib_stop_countdown(entity e)
|
||||||
|
{
|
||||||
|
if (!e.instagib_needammo)
|
||||||
|
return;
|
||||||
|
Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER, CPID_INSTAGIB_FINDAMMO);
|
||||||
|
e.instagib_needammo = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void instagib_countdown(entity this)
|
||||||
|
{
|
||||||
|
float hp = GetResource(this, RES_HEALTH);
|
||||||
|
|
||||||
|
float dmg = (hp <= 10) ? 5 : 10;
|
||||||
|
Damage(this, this, this, dmg, DEATH_NOAMMO.m_id, DMG_NOWEP, this.origin, '0 0 0');
|
||||||
|
|
||||||
|
entity annce = (hp <= 5) ? ANNCE_INSTAGIB_TERMINATED : Announcer_PickNumber(CNT_NORMAL, ceil(hp / 10));
|
||||||
|
Send_Notification(NOTIF_ONE, this, MSG_ANNCE, annce);
|
||||||
|
|
||||||
|
if (hp > 80)
|
||||||
|
{
|
||||||
|
if (hp <= 90)
|
||||||
|
Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_INSTAGIB_FINDAMMO);
|
||||||
|
else
|
||||||
|
Send_Notification(NOTIF_ONE_ONLY, this, MSG_MULTI, MULTI_INSTAGIB_FINDAMMO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void instagib_ammocheck(entity this)
|
||||||
|
{
|
||||||
|
if(time < this.instagib_nextthink)
|
||||||
|
return;
|
||||||
|
if(!IS_PLAYER(this))
|
||||||
|
return; // not a player
|
||||||
|
|
||||||
|
if(IS_DEAD(this) || game_stopped)
|
||||||
|
instagib_stop_countdown(this);
|
||||||
|
else if (GetResource(this, RES_CELLS) > 0 || (this.items & IT_UNLIMITED_AMMO) || (this.flags & FL_GODMODE))
|
||||||
|
instagib_stop_countdown(this);
|
||||||
|
else if(autocvar_g_rm && autocvar_g_rm_laser)
|
||||||
|
{
|
||||||
|
if(!this.instagib_needammo)
|
||||||
|
{
|
||||||
|
Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_INSTAGIB_DOWNGRADE);
|
||||||
|
this.instagib_needammo = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.instagib_needammo = true;
|
||||||
|
instagib_countdown(this);
|
||||||
|
}
|
||||||
|
this.instagib_nextthink = time + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
MUTATOR_HOOKFUNCTION(mutator_instagib, MatchEnd)
|
||||||
|
{
|
||||||
|
FOREACH_CLIENT(IS_PLAYER(it), { instagib_stop_countdown(it); });
|
||||||
|
}
|
||||||
|
|
||||||
|
MUTATOR_HOOKFUNCTION(mutator_instagib, RandomItems_GetRandomItemClassName)
|
||||||
|
{
|
||||||
|
M_ARGV(1, string) = RandomItems_GetRandomInstagibItemClassName(
|
||||||
|
M_ARGV(0, string));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MUTATOR_HOOKFUNCTION(mutator_instagib, MonsterDropItem)
|
||||||
|
{
|
||||||
|
entity item = M_ARGV(1, entity);
|
||||||
|
|
||||||
|
item.itemdef = ITEM_VaporizerCells;
|
||||||
|
}
|
||||||
|
|
||||||
|
MUTATOR_HOOKFUNCTION(mutator_instagib, MonsterSpawn)
|
||||||
|
{
|
||||||
|
entity mon = M_ARGV(0, entity);
|
||||||
|
|
||||||
|
// always refill ammo
|
||||||
|
if(mon.monsterdef == MON_MAGE)
|
||||||
|
mon.skin = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
MUTATOR_HOOKFUNCTION(mutator_instagib, MakePlayerObserver)
|
||||||
|
{
|
||||||
|
entity player = M_ARGV(0, entity);
|
||||||
|
|
||||||
|
instagib_stop_countdown(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
MUTATOR_HOOKFUNCTION(mutator_instagib, ForbidRandomStartWeapons)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerSpawn)
|
||||||
|
{
|
||||||
|
entity player = M_ARGV(0, entity);
|
||||||
|
|
||||||
|
player.effects |= EF_FULLBRIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerPreThink)
|
||||||
|
{
|
||||||
|
entity player = M_ARGV(0, entity);
|
||||||
|
|
||||||
|
instagib_ammocheck(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerRegen)
|
||||||
|
{
|
||||||
|
// no regeneration in instagib
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerDamage_SplitHealthArmor)
|
||||||
|
{
|
||||||
|
M_ARGV(4, float) = M_ARGV(7, float); // take = damage
|
||||||
|
M_ARGV(5, float) = 0; // save
|
||||||
|
}
|
||||||
|
|
||||||
|
MUTATOR_HOOKFUNCTION(mutator_instagib, ForbidThrowCurrentWeapon)
|
||||||
|
{
|
||||||
|
// weapon dropping on death handled by FilterItem
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MUTATOR_HOOKFUNCTION(mutator_instagib, Damage_Calculate)
|
||||||
|
{
|
||||||
|
entity frag_attacker = M_ARGV(1, entity);
|
||||||
|
entity frag_target = M_ARGV(2, entity);
|
||||||
|
float frag_deathtype = M_ARGV(3, float);
|
||||||
|
float frag_damage = M_ARGV(4, float);
|
||||||
|
float frag_mirrordamage = M_ARGV(5, float);
|
||||||
|
vector frag_force = M_ARGV(6, vector);
|
||||||
|
|
||||||
|
if(autocvar_g_friendlyfire == 0 && SAME_TEAM(frag_target, frag_attacker) && IS_PLAYER(frag_target) && IS_PLAYER(frag_attacker))
|
||||||
|
frag_damage = 0;
|
||||||
|
|
||||||
|
if(IS_PLAYER(frag_target))
|
||||||
|
{
|
||||||
|
if(frag_deathtype == DEATH_FALL.m_id)
|
||||||
|
frag_damage = 0; // never count fall damage
|
||||||
|
|
||||||
|
if(!autocvar_g_instagib_damagedbycontents)
|
||||||
|
switch(DEATH_ENT(frag_deathtype))
|
||||||
|
{
|
||||||
|
case DEATH_DROWN:
|
||||||
|
case DEATH_SLIME:
|
||||||
|
case DEATH_LAVA:
|
||||||
|
frag_damage = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(IS_PLAYER(frag_attacker))
|
||||||
|
if(DEATH_ISWEAPON(frag_deathtype, WEP_VAPORIZER))
|
||||||
|
{
|
||||||
|
if(!autocvar_g_instagib_friendlypush && SAME_TEAM(frag_target, frag_attacker))
|
||||||
|
frag_force = '0 0 0';
|
||||||
|
|
||||||
|
float armor = GetResource(frag_target, RES_ARMOR);
|
||||||
|
if(armor)
|
||||||
|
{
|
||||||
|
armor -= 1;
|
||||||
|
SetResource(frag_target, RES_ARMOR, armor);
|
||||||
|
frag_damage = 0;
|
||||||
|
frag_target.hitsound_damage_dealt += 1;
|
||||||
|
frag_attacker.hitsound_damage_dealt += 1;
|
||||||
|
Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_INSTAGIB_LIVES_REMAINING, armor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(IS_PLAYER(frag_attacker) && DEATH_ISWEAPON(frag_deathtype, WEP_BLASTER))
|
||||||
|
{
|
||||||
|
if(frag_deathtype & HITTYPE_SECONDARY)
|
||||||
|
{
|
||||||
|
if(!autocvar_g_instagib_blaster_keepdamage || frag_attacker == frag_target)
|
||||||
|
{
|
||||||
|
frag_damage = 0;
|
||||||
|
if(!autocvar_g_instagib_mirrordamage)
|
||||||
|
frag_mirrordamage = 0; // never do mirror damage on enemies
|
||||||
|
}
|
||||||
|
|
||||||
|
if(frag_target != frag_attacker)
|
||||||
|
{
|
||||||
|
if(!autocvar_g_instagib_blaster_keepforce)
|
||||||
|
frag_force = '0 0 0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!autocvar_g_instagib_mirrordamage) // only apply the taking lives hack if we don't want to support real damage mirroring
|
||||||
|
if(IS_PLAYER(frag_attacker))
|
||||||
|
if(frag_mirrordamage > 0)
|
||||||
|
{
|
||||||
|
// just lose extra LIVES, don't kill the player for mirror damage
|
||||||
|
float armor = GetResource(frag_attacker, RES_ARMOR);
|
||||||
|
if(armor > 0)
|
||||||
|
{
|
||||||
|
armor -= 1;
|
||||||
|
SetResource(frag_attacker, RES_ARMOR, armor);
|
||||||
|
Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_INSTAGIB_LIVES_REMAINING, armor);
|
||||||
|
frag_attacker.hitsound_damage_dealt += frag_mirrordamage;
|
||||||
|
}
|
||||||
|
frag_mirrordamage = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(frag_target.alpha && frag_target.alpha < 1)
|
||||||
|
if(IS_PLAYER(frag_target))
|
||||||
|
yoda = 1;
|
||||||
|
|
||||||
|
M_ARGV(4, float) = frag_damage;
|
||||||
|
M_ARGV(5, float) = frag_mirrordamage;
|
||||||
|
M_ARGV(6, vector) = frag_force;
|
||||||
|
}
|
||||||
|
|
||||||
|
MUTATOR_HOOKFUNCTION(mutator_instagib, SetStartItems, CBC_ORDER_LAST)
|
||||||
|
{
|
||||||
|
start_health = warmup_start_health = 100;
|
||||||
|
start_armorvalue = warmup_start_armorvalue = 0;
|
||||||
|
|
||||||
|
start_ammo_shells = warmup_start_ammo_shells = 0;
|
||||||
|
start_ammo_nails = warmup_start_ammo_nails = 0;
|
||||||
|
start_ammo_cells = warmup_start_ammo_cells = cvar("g_instagib_ammo_start");
|
||||||
|
start_ammo_plasma = warmup_start_ammo_plasma = 0;
|
||||||
|
start_ammo_rockets = warmup_start_ammo_rockets = 0;
|
||||||
|
//start_ammo_fuel = warmup_start_ammo_fuel = 0;
|
||||||
|
|
||||||
|
start_weapons = warmup_start_weapons = WEPSET(VAPORIZER);
|
||||||
|
start_items |= IT_UNLIMITED_SUPERWEAPONS;
|
||||||
|
}
|
||||||
|
|
||||||
|
MUTATOR_HOOKFUNCTION(mutator_instagib, SetWeaponArena)
|
||||||
|
{
|
||||||
|
// turn weapon arena off
|
||||||
|
M_ARGV(0, string) = "off";
|
||||||
|
}
|
||||||
|
|
||||||
|
void instagib_replace_item_with(entity this, GameItem def)
|
||||||
|
{
|
||||||
|
entity new_item = spawn();
|
||||||
|
switch (def)
|
||||||
|
{
|
||||||
|
case ITEM_Invisibility:
|
||||||
|
new_item.invisibility_finished = autocvar_g_instagib_invisibility_time;
|
||||||
|
break;
|
||||||
|
case ITEM_Speed:
|
||||||
|
new_item.speed_finished = autocvar_g_instagib_speed_time;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Item_CopyFields(this, new_item);
|
||||||
|
StartItem(new_item, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int INSTAGIB_POWERUP_COUNT = 3;
|
||||||
|
GameItem instagib_remaining_powerups[INSTAGIB_POWERUP_COUNT];
|
||||||
|
|
||||||
|
// replaces item with a random powerup selected among the less spawned ones
|
||||||
|
void instagib_replace_item_with_random_powerup(entity item)
|
||||||
|
{
|
||||||
|
static int remaining_powerups_count = INSTAGIB_POWERUP_COUNT;
|
||||||
|
if (remaining_powerups_count == 0)
|
||||||
|
remaining_powerups_count = INSTAGIB_POWERUP_COUNT;
|
||||||
|
if (remaining_powerups_count == INSTAGIB_POWERUP_COUNT)
|
||||||
|
{
|
||||||
|
instagib_remaining_powerups[0] = ITEM_Invisibility;
|
||||||
|
instagib_remaining_powerups[1] = ITEM_ExtraLife;
|
||||||
|
instagib_remaining_powerups[2] = ITEM_Speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
float r = floor(random() * remaining_powerups_count);
|
||||||
|
instagib_replace_item_with(item, instagib_remaining_powerups[r]);
|
||||||
|
for(int i = r; i < INSTAGIB_POWERUP_COUNT - 1; ++i)
|
||||||
|
instagib_remaining_powerups[i] = instagib_remaining_powerups[i + 1];
|
||||||
|
--remaining_powerups_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
MUTATOR_HOOKFUNCTION(mutator_instagib, FilterItem)
|
||||||
|
{
|
||||||
|
entity item = M_ARGV(0, entity);
|
||||||
|
|
||||||
|
switch (item.itemdef)
|
||||||
|
{
|
||||||
|
case ITEM_Strength: case ITEM_Shield: case ITEM_HealthMega: case ITEM_ArmorMega:
|
||||||
|
if(autocvar_g_powerups)
|
||||||
|
instagib_replace_item_with_random_powerup(item);
|
||||||
|
return true;
|
||||||
|
case ITEM_Cells:
|
||||||
|
if(autocvar_g_instagib_ammo_convert_cells)
|
||||||
|
instagib_replace_item_with(item, ITEM_VaporizerCells);
|
||||||
|
return true;
|
||||||
|
case ITEM_Rockets:
|
||||||
|
if(autocvar_g_instagib_ammo_convert_rockets)
|
||||||
|
instagib_replace_item_with(item, ITEM_VaporizerCells);
|
||||||
|
return true;
|
||||||
|
case ITEM_Shells:
|
||||||
|
if(autocvar_g_instagib_ammo_convert_shells)
|
||||||
|
instagib_replace_item_with(item, ITEM_VaporizerCells);
|
||||||
|
return true;
|
||||||
|
case ITEM_Bullets:
|
||||||
|
if(autocvar_g_instagib_ammo_convert_bullets)
|
||||||
|
instagib_replace_item_with(item, ITEM_VaporizerCells);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (item.weapon)
|
||||||
|
{
|
||||||
|
case WEP_VAPORIZER.m_id:
|
||||||
|
if (ITEM_IS_LOOT(item))
|
||||||
|
{
|
||||||
|
SetResource(item, RES_CELLS, autocvar_g_instagib_ammo_drop);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WEP_DEVASTATOR.m_id: case WEP_VORTEX.m_id:
|
||||||
|
instagib_replace_item_with(item, ITEM_VaporizerCells);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(item.itemdef.instanceOfPowerup)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
float cells = GetResource(item, RES_CELLS);
|
||||||
|
if(cells > autocvar_g_instagib_ammo_drop && item.classname != "item_vaporizer_cells")
|
||||||
|
SetResource(item, RES_CELLS, autocvar_g_instagib_ammo_drop);
|
||||||
|
|
||||||
|
if(cells && !item.weapon)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerDies)
|
||||||
|
{
|
||||||
|
float frag_deathtype = M_ARGV(3, float);
|
||||||
|
entity attacker = M_ARGV(1, entity);
|
||||||
|
if(DEATH_ISWEAPON(frag_deathtype, WEP_VAPORIZER))
|
||||||
|
M_ARGV(4, float) = 1000; // always gib if it was a vaporizer death
|
||||||
|
.entity weaponentity = weaponentities[0];
|
||||||
|
ATTACK_FINISHED(attacker, weaponentity) = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
MUTATOR_HOOKFUNCTION(mutator_instagib, ItemTouch)
|
||||||
|
{
|
||||||
|
if(MUTATOR_RETURNVALUE) return false;
|
||||||
|
|
||||||
|
entity item = M_ARGV(0, entity);
|
||||||
|
entity toucher = M_ARGV(1, entity);
|
||||||
|
|
||||||
|
if(GetResource(item, RES_CELLS))
|
||||||
|
{
|
||||||
|
// play some cool sounds ;)
|
||||||
|
float hp = GetResource(toucher, RES_HEALTH);
|
||||||
|
if (IS_CLIENT(toucher))
|
||||||
|
{
|
||||||
|
if(hp <= 5)
|
||||||
|
Send_Notification(NOTIF_ONE, toucher, MSG_ANNCE, ANNCE_INSTAGIB_LASTSECOND);
|
||||||
|
else if(hp < 50)
|
||||||
|
Send_Notification(NOTIF_ONE, toucher, MSG_ANNCE, ANNCE_INSTAGIB_NARROWLY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hp < 100)
|
||||||
|
SetResource(toucher, RES_HEALTH, 100);
|
||||||
|
|
||||||
|
return MUT_ITEMTOUCH_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(item.itemdef == ITEM_ExtraLife)
|
||||||
|
{
|
||||||
|
GiveResource(toucher, RES_ARMOR, autocvar_g_instagib_extralives);
|
||||||
|
Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_EXTRALIVES, autocvar_g_instagib_extralives);
|
||||||
|
Inventory_pickupitem(item.itemdef, toucher);
|
||||||
|
return MUT_ITEMTOUCH_PICKUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MUT_ITEMTOUCH_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
MUTATOR_HOOKFUNCTION(mutator_instagib, BuildMutatorsString)
|
||||||
|
{
|
||||||
|
M_ARGV(0, string) = strcat(M_ARGV(0, string), ":instagib");
|
||||||
|
}
|
||||||
|
|
||||||
|
MUTATOR_HOOKFUNCTION(mutator_instagib, BuildMutatorsPrettyString)
|
||||||
|
{
|
||||||
|
M_ARGV(0, string) = strcat(M_ARGV(0, string), ", InstaGib");
|
||||||
|
}
|
||||||
|
|
||||||
|
MUTATOR_HOOKFUNCTION(mutator_instagib, SetModname)
|
||||||
|
{
|
||||||
|
M_ARGV(0, string) = "InstaGib";
|
||||||
|
return true;
|
||||||
|
}
|
Loading…
Reference in a new issue