Convert Quadravol fire debuff to inventory item.

Copy over spread code from black shell debuff (lower hard lock risk).
This commit is contained in:
Mari the Deer 2022-09-03 18:28:13 +02:00
commit 78dc1bb453
4 changed files with 92 additions and 85 deletions

View file

@ -1,3 +1,3 @@
[default]
SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r398 \cu(Sat 3 Sep 09:33:23 CEST 2022)\c-";
SWWM_SHORTVER="\cw1.3pre r398 \cu(2022-09-03 09:33:23)\c-";
SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r399 \cu(Sat 3 Sep 18:28:13 CEST 2022)\c-";
SWWM_SHORTVER="\cw1.3pre r399 \cu(2022-09-03 18:28:13)\c-";

View file

@ -929,7 +929,7 @@ Class OnFireLight : PointLightFlickerRandomAttenuated
override void Tick()
{
Super.Tick();
if ( !of || !of.victim )
if ( !of || !of.Owner )
{
A_StopSound(CHAN_VOICE);
Destroy();
@ -938,32 +938,78 @@ Class OnFireLight : PointLightFlickerRandomAttenuated
Args[0] = clamp(of.Amount*4,0,255);
Args[1] = clamp(of.Amount*2,0,160);
Args[2] = clamp(of.Amount/2,0,24);
Args[3] = int(max(of.victim.radius,of.victim.height)*2.5+40+clamp(of.amount/4,0,120));
Args[3] = int(max(of.Owner.radius,of.Owner.height)*2.5+40+clamp(of.Amount/4,0,120));
Args[4] = args[3]+8;
SetOrigin(of.Victim.Vec3Offset(0,0,of.Victim.Height/2),true);
SetOrigin(of.Owner.Vec3Offset(0,0,of.Owner.Height/2),true);
}
}
Class OnFire : Thinker
Class OnFire : Inventory
{
Actor victim, instigator, lite;
int amount, cnt;
Actor instigator, lite;
int cnt;
double oangle;
override void Tick()
Default
{
if ( level.isFrozen() ) return;
if ( !victim )
Obituary "$O_QUADRAVOL";
Inventory.Amount 1;
Inventory.MaxAmount 500;
+INVENTORY.KEEPDEPLETED; // since our amount can go below 0, we need special cleanup
+INVENTORY.UNDROPPABLE;
+INVENTORY.UNTOSSABLE;
}
override void AttachToOwner( Actor other )
{
Super.AttachToOwner(other);
cnt = 1;
lite = Spawn("OnFireLight",other.pos);
lite.specialf1 = 3;
OnFireLight(lite).of = self;
}
override void OwnerDied()
{
Super.OwnerDied();
amount = min(amount,100);
}
override void PreTravelled()
{
Super.PreTravelled();
// debuff disappears between levels
Destroy();
}
override int DoSpecialDamage( Actor target, int Damage, Name DamageType )
{
if ( target == Owner ) return Damage;
// spread ourselves
let t = OnFire(target.FindInventory("OnFire"));
if ( !t )
{
t = Apply(target,instigator,min(Damage,int(Amount*.6))); // prevent "escalating" spread
t.cnt = 15; // long delay
}
else if ( t.Amount < int(Amount*.6) ) t.Amount = min(t.Amount+Damage,int(Amount*.6)); // prevent "escalating" spread
t.instigator = instigator;
return clamp(int(Damage*.15),1,50); // reduced direct damage
}
override void DoEffect()
{
Super.DoEffect();
if ( !Owner )
{
Destroy();
return;
}
if ( victim is 'Demolitionist' ) amount = min(amount-1,200); // Demo's body puts out fire faster
if ( victim.Health <= 0 ) amount = min(amount,100);
if ( Owner is 'Demolitionist' ) amount = min(amount-1,200); // Demo's body puts out fire faster
if ( !(level.maptime%3) )
amount--;
if ( victim.player ) amount -= int(abs(actor.deltaangle(victim.angle,oangle))/30);
oangle = victim.angle;
if ( Owner.player ) amount -= int(abs(actor.deltaangle(Owner.angle,oangle))/30);
oangle = Owner.angle;
if ( amount < -30 )
{
Destroy();
@ -973,101 +1019,62 @@ Class OnFire : Thinker
else
{
cnt = 10;
if ( victim.bSHOOTABLE && (victim.Health > 0) && (amount > 0) )
if ( Owner.bSHOOTABLE && (Owner.Health > 0) && (amount > 0) )
{
int flg = DMG_THRUSTLESS;
if ( victim is 'Centaur' ) flg |= DMG_FOILINVUL; // you're on fire, that shield is worthless
Actor inflictor = instigator;
if ( instigator )
{
let q = instigator.FindInventory("Quadravol");
if ( q ) inflictor = q;
}
victim.DamageMobj(inflictor,instigator,clamp(int(amount*.15),1,50),'Fire',flg);
if ( victim.bISMONSTER && !Random[FlameT](0,3) )
victim.Howl();
if ( Owner is 'Centaur' ) flg |= DMG_FOILINVUL; // you're on fire, that shield is worthless
Owner.DamageMobj(self,instigator,clamp(int(amount*.15),1,50),'Fire',flg);
if ( Owner.bISMONSTER && !Random[FlameT](0,3) )
Owner.Howl();
}
if ( !victim )
if ( !Owner )
{
Destroy();
return;
}
// damage nearby actors
SWWMUtility.DoExplosion(Owner,amount,0,Owner.radius+40+amount/5,0,DE_NOBLEED|DE_NOSPLASH|DE_HOWL|DE_CENTERHEIGHT|DE_NONEXPLOSIVE,'Fire',null,DMG_THRUSTLESS,instigator,self);
}
double mult = max(victim.radius,victim.height)/30.;
double mult = max(Owner.radius,Owner.height)/30.;
if ( lite ) lite.A_SoundVolume(CHAN_VOICE,min(1.,mult*amount/80.));
if ( level.maptime%5 ) return;
int numpt = clamp(int(Random[FlameT](2,4)*amount*.02),1,4);
numpt = int(clamp(numpt*mult**.5,1,5));
for ( int i=0; i<numpt; i++ )
{
Vector3 pos = victim.Vec3Offset(FRandom[FlameT](-victim.radius,victim.radius)*.8,FRandom[FlameT](-victim.radius,victim.radius)*.8,FRandom[FlameT](victim.height*.2,victim.height*.8));
Vector3 tpos = Owner.Vec3Offset(FRandom[FlameT](-Owner.radius,Owner.radius)*.8,FRandom[FlameT](-Owner.radius,Owner.radius)*.8,FRandom[FlameT](Owner.height*.2,Owner.height*.8));
double ang = FRandom[FlameT](0,360);
double pt = FRandom[FlameT](-90,90);
if ( amount > 0 )
{
let c = victim.Spawn("OnFireTrail",pos);
let c = Spawn("OnFireTrail",tpos);
c.scale *= max(.35,mult*.6);
c.vel = victim.vel*.5+SWWMUtility.Vec3FromAngles(ang,pt)*FRandom[FlameT](.5,2.)*c.scale.x;
c.vel = Owner.vel*.5+SWWMUtility.Vec3FromAngles(ang,pt)*FRandom[FlameT](.5,2.)*c.scale.x;
}
if ( Random[FlameT](0,2) ) continue;
let s = victim.Spawn("SWWMHalfSmoke",pos);
let s = Spawn("SWWMHalfSmoke",tpos);
s.scale *= max(.5,mult*.75);
s.alpha *= min(amount+30,100)*.005;
s.vel = victim.vel*.5+SWWMUtility.Vec3FromAngles(ang,pt)*FRandom[FlameT](.2,.6)*s.scale.x;
s.vel = Owner.vel*.5+SWWMUtility.Vec3FromAngles(ang,pt)*FRandom[FlameT](.2,.6)*s.scale.x;
}
// this is too expensive, it has to go
/*let bt = BlockThingsIterator.Create(victim);
while ( bt.Next() )
{
let t = bt.Thing;
if ( !t || !t.bSHOOTABLE || (t.Health <= 0) || (t == victim) )
continue;
double maxdist = (victim.radius+t.radius+20);
if ( (victim.Distance3DSquared(t) > maxdist*maxdist) || !victim.CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) )
continue;
int amt = max(1,amount/10);
let of = IsOnFire(t);
if ( of )
{
amt = min(5,amt);
of.amount = min(500,of.amount+amt);
of.cnt = min(of.cnt,5);
}
else Apply(t,instigator,amt);
}
bt.Destroy();*/
// damage nearby actors instead
Actor inflictor = instigator;
if ( instigator )
{
let q = instigator.FindInventory("Quadravol");
if ( q ) inflictor = q;
}
SWWMUtility.DoExplosion(victim,clamp(int(amount*.15),1,50),0,victim.radius+40+amount/5,0,DE_NOBLEED|DE_NOSPLASH|DE_HOWL|DE_CENTERHEIGHT|DE_NONEXPLOSIVE,'Fire',null,DMG_THRUSTLESS,instigator,inflictor);
}
static OnFire Apply( Actor victim, Actor instigator, int amount )
{
if ( amount <= 0 ) return null;
let ti = ThinkerIterator.Create("OnFire",STAT_USER);
OnFire t;
while ( t = OnFire(ti.Next()) )
let t = OnFire(victim.FindInventory("OnFire"));
if ( t )
{
if ( t.victim != victim ) continue;
if ( instigator ) t.instigator = instigator;
t.amount = min(500,t.amount+amount);
t.instigator = instigator;
t.amount = min(t.maxamount,t.amount+amount);
t.cnt = min(t.cnt,5);
return t;
}
t = new("ONFire");
t.ChangeStatNum(STAT_USER);
t.victim = victim;
t = OnFire(Spawn("ONFire"));
t.AttachToOwner(victim);
t.instigator = instigator;
t.amount = min(500,amount);
t.amount = min(t.maxamount,amount);
t.cnt = 1;
t.lite = Actor.Spawn("OnFireLight",victim.pos);
t.lite.specialf1 = 3;
OnFireLight(t.lite).of = t;
t.oangle = victim.angle;
double mult = max(victim.radius,victim.height)/30.;
t.lite.A_StartSound("misc/flame",CHAN_VOICE,CHANF_LOOP);
@ -1075,15 +1082,10 @@ Class OnFire : Thinker
return t;
}
static OnFire IsOnFire( Actor victim )
static clearscope OnFire IsOnFire( Actor victim )
{
let ti = ThinkerIterator.Create("OnFire",STAT_USER);
OnFire t;
while ( t = OnFire(ti.Next()) )
{
if ( (t.victim != victim) || (t.amount <= 0) ) continue;
return t;
}
let t = OnFire(victim.FindInventory("OnFire"));
if ( t && (t.amount > 0) ) return t;
return null;
}
}

View file

@ -173,7 +173,7 @@ Class SWWMStats : SWWMStaticThinker
else if ( (inflictor is 'EvisceratorChunk') || (inflictor is 'EvisceratorProj') ) which = 'Eviscerator';
else if ( inflictor is 'SheenTrail' ) which = 'HeavyMahSheenGun';
else if ( (inflictor is 'HellblazerMissile') || (inflictor is 'HellblazerRavagerArm') || (inflictor is 'HellblazerWarheadArm') ) which = 'Hellblazer';
else if ( (inflictor is 'QuadProj') || (inflictor is 'QuadExplArm') || ((inflictor is 'Demolitionist') && (DamageType == 'Fire')) ) which = 'Quadravol'; // last one is a hack for fire effects
else if ( (inflictor is 'QuadProj') || (inflictor is 'QuadExplArm') || (inflictor is 'OnFire') ) which = 'Quadravol';
else if ( (inflictor is 'BigBiospark') || (inflictor is 'BiosparkBall') || (inflictor is 'BiosparkBeamImpact') || (inflictor is 'BiosparkComboImpact') || (inflictor is 'BiosparkComboImpactSub') || (inflictor is 'BiosparkBeam') || (inflictor is 'BiosparkArc') || (inflictor is 'BiosparkCore') ) which = 'Sparkster';
else if ( (inflictor is 'SilverAirRip') || (inflictor is 'SilverAirRip2') || (inflictor is 'SilverImpact') || (inflictor is 'FatChodeImpact') || (inflictor is 'FatChodeExplosionArm') ) which = 'SilverBullet';
else if ( (inflictor is 'CandyBeam') || (inflictor is 'CandyPop') || (inflictor is 'CandyMagArm') || (inflictor is 'CandyGunProj') || (inflictor is 'CandyMagProj') || (inflictor is 'CandyBulletImpact') ) which = 'CandyGun';

View file

@ -571,7 +571,6 @@ Class CorrodeDebuff : Inventory
Obituary "$O_SPREADGUN_BLACK_DEBUFF";
Inventory.Amount 1;
Inventory.MaxAmount 1000;
Inventory.InterHubAmount 0;
+INVENTORY.UNDROPPABLE;
+INVENTORY.UNTOSSABLE;
}
@ -605,6 +604,12 @@ Class CorrodeDebuff : Inventory
cnt = -1;
if ( instigator ) SWWMUtility.AchievementProgressInc("acid",1,instigator.player);
}
override void PreTravelled()
{
Super.PreTravelled();
// debuff disappears between levels
Destroy();
}
override void DoEffect()
{
Super.DoEffect();