Unconditional blood replacement, new blood decals, corpse blood pools.

TODO: bloodied footsteps, can still re-use code from Soundless Mound there.
This commit is contained in:
Mari the Deer 2025-03-07 17:27:59 +01:00
commit f89393ca81
62 changed files with 540 additions and 22 deletions

View file

@ -53,6 +53,9 @@ Class SWWMHandler : EventHandler
transient ui Vector2 oldplayerpos;
transient ui bool do_trace_steps;
// for bloody footsteps
mkBloodPool bloodpools;
enum EProfileTimer
{
PT_WORLDTICK,

View file

@ -32,6 +32,7 @@ extend Class SWWMHandler
if ( !b ) return;
mkGibber(a).gibbed = e.Thing;
mkGibber(a).delay = 40;
mkGibber(a).mksplat = true;
a.special1 = 1;
a.A_SetSize(e.Thing.default.radius,e.Thing.default.height);
return;
@ -42,6 +43,7 @@ extend Class SWWMHandler
if ( !b ) return;
mkGibber(a).gibbed = e.Thing;
mkGibber(a).delay = 60;
mkGibber(a).mksplat = true;
a.special1 = 1;
a.A_SetSize(e.Thing.default.radius,e.Thing.default.height);
}

View file

@ -196,8 +196,5 @@ extend Class SWWMHandler
oldmaxdebris = swwm_maxdebris;
oldmaxblood = swwm_maxblood;
oldmaxgibs = swwm_maxgibs;
if ( swwm_blood ) return;
while ( blods ) DeQueueBlod(blods);
while ( meats ) DeQueueMeat(meats);
}
}

View file

@ -675,8 +675,7 @@ extend Class SWWMHandler
return;
}
}
// only replace vanilla blood if no other gore mod is doing it (unless swwm_blood is set to 2)
if ( (((e.Replacee == "Blood") && (!e.Replacement || (e.Replacement == "Blood") || (swwm_blood >= 2))) || (bludtypes.Find(e.Replacee.GetClassName()) < bludtypes.Size())) && swwm_blood ) e.Replacement = "mkBlood";
if ( (e.Replacee is 'Blood') || (bludtypes.Find(e.Replacee.GetClassName()) < bludtypes.Size()) ) e.Replacement = 'mkBlood';
else if ( e.Replacee is 'ItemFog' ) e.Replacement = 'SWWMItemFog';
else if ( e.Replacee is 'TeleportFog' ) e.Replacement = 'SWWMTeleportFog';
else if ( (e.Replacee is 'CommanderKeen') && (!e.Replacement || (e.Replacement == 'CommanderKeen')) )

View file

@ -302,7 +302,7 @@ Class mkBloodDrop : SWWMNonInteractiveActor
}
SWWMUtility.SetToSlope(self,FRandom[Blood](0,360));
A_SetRenderStyle(1.,STYLE_Shaded);
frame = Random[Blood](5,8);
frame = Random[Blood](5,12);
int numpt = Random[Blood](4,8);
puff.lifetime = 20;
puff.startalpha = .5*alpha;
@ -357,7 +357,7 @@ Class mkBloodDrop : SWWMNonInteractiveActor
}
SWWMUtility.SetToSlope(self,FRandom[Blood](0,360),true);
A_SetRenderStyle(1.,STYLE_Shaded);
frame = Random[Blood](9,12);
frame = Random[Blood](13,20);
int numpt = Random[Blood](4,8);
puff.lifetime = 20;
puff.startalpha = .5*alpha;
@ -456,7 +456,7 @@ Class mkBloodSmoke : SWWMStaticSprite
override void SetupSprite()
{
texture = TexMan.CheckForTexture(String.Format("BSMK%c0",0x41+Random[Blood](0,19)));
texture = TexMan.CheckForTexture(String.Format("MSMK%c0",0x41+Random[Blood](0,7)));
Scale = (.5,.5);
Alpha = .35;
SetRenderStyle(STYLE_Shaded);
@ -653,6 +653,7 @@ Class mkGibber : SWWMNonInteractiveActor
color shadecol;
meta Class<Actor> gibtype; // allow custom gib types (will be used for monster pack)
bool psnd;
bool mksplat;
Property GibType: gibtype;
@ -754,6 +755,14 @@ Class mkGibber : SWWMNonInteractiveActor
A_StartSound("misc/gibber",CHAN_VOICE,CHANF_OVERLAP);
psnd = true;
}
if ( mksplat )
{
let s = Spawn("mkBloodBlast",pos);
s.SetShade(shadecol);
s.scale *= radius/4.;
s.master = gibbed;
mksplat = false;
}
BurstGibs();
if ( reactiontime <= 0 )
Destroy();
@ -767,6 +776,44 @@ Class mkGibber : SWWMNonInteractiveActor
}
}
// for exploding Cyberdemon/Spider
Class mkBloodBlast : SWWMNonInteractiveActor
{
override void Tick()
{
if ( freezetics > 0 )
{
freezetics--;
return;
}
if ( isFrozen() ) return;
double fz = CurSector.floorplane.ZAtPoint(pos.xy);
if ( fz != pos.z ) SetOrigin((pos.x,pos.y,fz),true);
if ( (waterlevel > 0) || GetFloorTerrain().isliquid )
A_FadeOut();
if ( !master ) A_FadeOut(.01);
}
override void PostBeginPlay()
{
double fz = CurSector.floorplane.ZAtPoint(pos.xy);
SetZ(fz);
prev.z = fz;
A_QueueCorpse();
SWWMUtility.SetToSlope(self,FRandom[Blood](0,360));
}
default
{
RenderStyle "Shaded";
StencilColor "Red";
}
States
{
Spawn:
XZW1 A -1;
Stop;
}
}
// bare actors used for copying blood color to vanilla monsters
Class GreenBloodReference : Actor
{
@ -822,6 +869,93 @@ Class CorpseFallTracker : Thinker
// wait until body is dead on floor and at the last state of animation
if ( (mybody.Health > 0) || isflying || (mybody.tics != -1) || (mybody.vel.length() > 0) )
return;
let b = mybody.Spawn("mkBloodPool",mybody.pos);
Color shadecol;
if ( mybody.bloodcolor ) shadecol = Color(mybody.bloodcolor.r/2,mybody.bloodcolor.g/2,mybody.bloodcolor.b/2);
else shadecol = Color(80,0,0);
mkBloodPool(b).stepcol = shadecol;
b.master = mybody;
b.A_SetScale(mybody.default.radius/16.);
// futureproofing hack (heh)
let mtype = SWWMUtility.GetParentClassBefore(mybody.GetClass(),'Actor');
if ( mtype.GetClassName() == 'SWWMMonster' )
{
b.A_SetRenderStyle(1.,STYLE_Shaded);
b.SetShade(shadecol);
}
else b.translation = mybody.bloodtranslation;
Destroy();
}
}
// Blood pool
Class mkBloodPool : SWWMNonInteractiveActor
{
double basesz, sz, accel;
Color stepcol;
mkBloodPool prevpool, nextpool;
override void OnDestroy()
{
Super.OnDestroy();
if ( prevpool )
{
prevpool.nextpool = nextpool;
if ( nextpool ) nextpool.prevpool = prevpool;
}
let hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
if ( !hnd ) return;
hnd.bloodpools = nextpool;
}
override void PostBeginPlay()
{
double fz = CurSector.floorplane.ZAtPoint(pos.xy);
SetZ(fz);
prev.z = fz;
accel = .0012;
basesz = scale.x;
sz = .01;
A_SetScale(sz);
A_QueueCorpse();
SWWMUtility.SetToSlope(self,FRandom[Blood](0,360));
let hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
if ( !hnd ) return;
nextpool = hnd.bloodpools;
hnd.bloodpools = self;
if ( nextpool ) nextpool.prevpool = self;
}
override void Tick()
{
if ( freezetics > 0 )
{
freezetics--;
return;
}
if ( isFrozen() ) return;
double fz = CurSector.floorplane.ZAtPoint(pos.xy);
if ( fz != pos.z ) SetOrigin((pos.x,pos.y,fz),true);
if ( (waterlevel > 0) || GetFloorTerrain().isliquid )
A_FadeOut();
if ( !master ) A_FadeOut(.01);
if ( accel <= double.epsilon ) return;
sz += accel;
accel *= .997;
A_SetScale(basesz*sz);
A_SetSize(50.*basesz*sz);
}
Default
{
Radius 1;
Height 1;
StencilColor "Red";
}
States
{
Spawn:
XZW1 A -1;
Stop;
}
}

View file

@ -495,4 +495,14 @@ extend Class SWWMUtility
return true;
return target.bCOUNTITEM;
}
// return the highest parent class in hierarchy before a specific "highest class"
// useful to check stuff such as monster subtypes and the like
static Class<Object> GetParentClassBefore( Class<Object> baseclass, Class<Object> highestclass )
{
Class<Object> step = baseclass;
while ( (step.GetParentClass() != highestclass) && step.GetParentClass() )
step = step.GetParentClass();
return step;
}
}