The way this works is simple: everything that spawns is given a powerup that determines how a change in health affects the owner. Monster and player variables are controlled by different Cvars, so (for example) a negative "Speed" factor will make monsters move faster after they are hurt. Monsters can also regenerate health, as if you need motivation to kill them.
CVars:
Code: Select all
// monster speed abilities
user float mospeed_freq = 5;
user float mospeed_speed = 0;
user float mospeed_damagefactor = 0;
user float mospeed_damagemultiply = 0;
user float mospeed_health = 0;
// player speed abilities
user float plspeed_freq = 5;
user float plspeed_speed = 0;
user float plspeed_damagefactor = 0;
user float plspeed_damagemultiply = 0;
user float plspeed_health = 0;
user float plspeed_adrenaline = 1;
user float plspeed_armor = 0;
// debug
user bool speed_debug=false;
Code: Select all
class ArmorRegen : BasicArmorBonus
{
Default
{
Armor.SaveAmount 1;
Armor.MaxSaveAmount 0x7FFFFFFF;
}
}
class Speed : Powerup
{
Default
{
Powerup.Duration 0x7FFFFFFF;
+Inventory.Autoactivate;
}
// baseHealth baselines
int baseHealth;
int baseSpeed;
float baseDamageFactor;
float baseDamageMultiply;
// counters
int lasthealth;
int lastarmor;
int tCount;
// cvars
float cvar_freq;
float cvar_speed;
float cvar_damagefactor;
float cvar_damagemultiply;
float cvar_health;
float cvar_adrenaline;
float cvar_armor;
bool cvar_debug;
void setDefaults()
{
baseHealth = Owner.Health;
baseSpeed = Owner.Speed;
baseDamageFactor = Owner.DamageFactor;
baseDamageMultiply = Owner.DamageMultiply;
lasthealth = Owner.Health;
lastarmor = CountInv("BasicArmor");
tCount = 0;
if (Owner.bIsMonster)
{
cvar_freq = Cvar.FindCvar("mospeed_freq").GetFloat();
cvar_speed = Cvar.FindCvar("mospeed_speed").GetFloat();
cvar_damagefactor = Cvar.FindCvar("mospeed_damagefactor").GetFloat();
cvar_damagemultiply = Cvar.FindCvar("mospeed_damagemultiply").GetFloat();
cvar_health = Cvar.FindCvar("mospeed_health").GetFloat();
}
else
{
cvar_freq = Cvar.FindCvar("plspeed_freq").GetFloat();
cvar_speed = Cvar.FindCvar("plspeed_speed").GetFloat();
cvar_damagefactor = Cvar.FindCvar("plspeed_damagefactor").GetFloat();
cvar_damagemultiply = Cvar.FindCvar("plspeed_damagemultiply").GetFloat();
cvar_health = Cvar.FindCvar("plspeed_health").GetFloat();
cvar_adrenaline = Cvar.FindCvar("plspeed_adrenaline").GetFloat();
cvar_armor = Cvar.FindCvar("plspeed_armor").GetFloat();
}
cvar_debug = Cvar.FindCvar("speed_debug").GetBool();
}
override void DoEffect()
{
if (!lasthealth)
{
setDefaults();
}
tCount++;
if (tCount > 35 * cvar_freq)
{
tCount = 0;
if (Owner.Health < baseHealth)
{
if (lasthealth != Owner.Health)
{
Owner.Speed += (Owner.Health - lasthealth) * 0.01 * cvar_speed;
Owner.DamageFactor -= (Owner.Health - lasthealth) * 0.01 * cvar_damagefactor;
Owner.DamageMultiply += (Owner.Health - lasthealth) * 0.01 * cvar_damagemultiply;
Owner.Health += Random(0, baseHealth) + CountInv("BasicArmor") > lasthealth ? cvar_health : 0;
lasthealth = Owner.Health;
if (cvar_debug)
{
console.printf("%s: Speed: %f Dish: %f Take: %f Health: %d", Owner.GetSpecies(), Owner.Speed, Owner.DamageMultiply, Owner.DamageFactor, Owner.Health);
}
}
}
if (Owner.Health == baseHealth)
{
Owner.Speed = baseSpeed;
Owner.DamageFactor = baseDamageFactor;
Owner.DamageMultiply = baseDamageMultiply;
}
// these only apply to the player
if (Owner.Health > baseHealth)
{
Owner.Speed *= cvar_adrenaline;
}
if (CountInv("BasicArmor") < lastarmor)
{
Owner.GiveInventory("ArmorRegen", Random(0, 1) * cvar_armor);
}
}
}
}
class speed_EventHandler : EventHandler
{
int tidCounter;
override void WorldThingSpawned(WorldEvent e)
{
if (e.thing && e.thing.bIsMonster)
{
e.thing.GiveInventory("Speed", 1);
// give the monster a unique tid
if (tidCounter == 0)
{
tidCounter = 22000;
}
if (e.thing && e.thing.bIsMonster && !e.thing.tid)
{
e.thing.ChangeTid(tidCounter);
tidCounter++;
}
}
}
override void PlayerSpawned(PlayerEvent e)
{
PlayerInfo player = players[e.PlayerNumber];
if (player.mo.CountInv("Speed") == 0)
{
player.mo.GiveInventory("Speed", 1);
player.mo.GiveInventory("ArmorRegen", 100);
}
}
}
Small changes in the sliders greatly affect the game balance as you can imagine. Originally I put defaults that were minimal but thought better of it. This could be buggy, and I'm still testing it. But I think the basic idea works.
Update
Spoiler: