flak_m/zscript/utgore.zsc
Marisa Kirisame 96411592b3 Finally add player models (sorta rudimentary but they work).
Updated blood and gore code, it's less WIP now.
Updated readme with some additional notes.
Removed Heretic compat player classes as they are no longer needed.
2019-07-22 02:58:48 +02:00

605 lines
13 KiB
Text

// Blood
Class UTBlood : Actor
{
Default
{
RenderStyle "Add";
Scale 1.1;
+NOBLOCKMAP;
+NOGRAVITY;
+NOTELEPORT;
+DONTSPLASH;
+FORCEXYBILLBOARD;
+PUFFGETSOWNER;
}
void A_Bleed( int str = 1 )
{
Scale *= 0.7+0.3*str;
vel *= 0;
let b = Spawn("UTBloodSpurt",pos);
b.angle = angle+FRandom[Blud](-15,15);
b.pitch = pitch+FRandom[Blud](-15,15);
b.translation = translation;
b.args[0] = str;
// transfer blood color for decals
if ( target && target.bloodcolor ) b.SetShade(target.bloodcolor);
else b.SetShade(gameinfo.defaultbloodcolor);
}
States
{
Spawn:
TNT1 A 0 NoDelay A_Bleed(3);
Goto Puff;
TNT1 A 0 A_Bleed(2);
Goto Puff;
TNT1 A 0 A_Bleed(1);
Goto Puff;
Puff:
TNT1 A 0
{
int dec = Random[Blod](0,2);
if ( dec == 1 )
return ResolveState("Puff1");
if ( dec == 2 )
return ResolveState("Puff2");
return ResolveState("Puff3");
}
Puff1:
BPF1 ABCDEFGHIJK 1;
Stop;
Puff2:
BPF2 ABCDEFGH 1;
Stop;
Puff3:
BPF3 ABCDEFGHIJ 1;
Stop;
}
}
// single drop of blod
Class UTBloodDrop : Actor
{
Default
{
Scale 0.24;
Gravity 0.8;
Mass 1;
Radius 2;
Height 2;
RenderStyle "Translucent";
+MISSILE;
+NOTELEPORT;
+THRUACTORS;
+FORCEXYBILLBOARD;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
SetState(FindState("Spawn")+Random[Blod](0,4));
Scale *= FRandom[Blod](0.6,1.4);
}
void A_BloodDie()
{
// TODO leave decals
}
States
{
Spawn:
BDRP ABCDE -1;
Stop;
Death:
TNT1 A 0 A_BloodDie();
Stop;
}
}
// a burst of blod
Class UTBloodSpurt : Actor
{
double str;
Default
{
+NOBLOCKMAP;
+NOGRAVITY;
+DONTSPLASH;
+NOTELEPORT;
+THRUACTORS;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
str = FRandom[Blood](2.0,3.2)*args[0];
int sz = 7*args[0];
double ang, pt;
if ( !flak_blood ) sz /= 3;
for ( int i=0; i<sz; i++ )
{
Actor d;
if ( flak_blood ) d = Spawn("UTBloodDrop",pos);
else d = Spawn("Blood",pos,ALLOW_REPLACE);
d.translation = translation;
d.SetShade(fillcolor);
ang = angle+FRandom[Blood](-3,3)*str;
pt = pitch+FRandom[Blood](-3,3)*str;
Vector3 dir = (cos(pt)*cos(ang),cos(pt)*sin(ang),-sin(pt));
d.vel = dir*str*FRandom[Blood](0.4,0.8);
d.vel.z += str*0.5;
d.scale *= str*0.15*FRandom[Blood](0.6,1.4);
}
Destroy();
}
}
// for chunks
Class UTBloodTrail : Actor
{
double str;
Default
{
+NOBLOCKMAP;
+NOGRAVITY;
+NOTELEPORT;
+DONTSPLASH;
+THRUACTORS;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
if ( !target ) return;
str = FRandom[Blood](2.0,4.0);
}
private bool IsTargetFlying()
{
if ( !target ) return false;
if ( target.InStateSequence(target.CurState,target.FindState("Spawn")) ) return true;
return false;
}
override void Tick()
{
Super.Tick();
if ( isFrozen() ) return;
if ( !target ) return;
SetOrigin(target.pos,true);
double ang, pt;
int max = flak_blood?3:Random[Blood](-2,1);
for ( int i=0; i<max; i++ )
{
Actor d;
if ( flak_blood ) d = Spawn("UTBloodDrop",pos);
else d = Spawn("Blood",pos,ALLOW_REPLACE);
d.translation = translation;
d.SetShade(fillcolor);
ang = FRandom[Blood](0,360);
pt = FRandom[Blood](-90,90);
Vector3 dir = -target.vel*0.2;
dir += (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*0.8;
d.vel = dir*str*FRandom[Blood](0.8,1.2);
d.scale *= str*0.15*FRandom[Blood](0.6,1.4);
}
bool flying = IsTargetFlying();
if ( !flying ) Destroy();
}
}
// Poof
Class UTBloodPuff : Actor
{
Default
{
RenderStyle "Add";
Scale 1.1;
Alpha 0.4;
+NOBLOCKMAP;
+NOGRAVITY;
+NOTELEPORT;
+DONTSPLASH;
+FORCEXYBILLBOARD;
}
States
{
Spawn:
TNT1 A 0 NoDelay
{
int dec = Random[Blod](0,2);
if ( dec == 1 )
return ResolveState("Puff1");
if ( dec == 2 )
return ResolveState("Puff2");
return ResolveState("Puff3");
}
Puff1:
BPF1 ABCDEFGHIJK 2;
Stop;
Puff2:
BPF2 ABCDEFGH 2;
Stop;
Puff3:
BPF3 ABCDEFGHIJ 2;
Stop;
}
}
// Chunkers
Class UTGibber : Actor
{
Actor Gibbed;
int gibcount, gibsize;
color shadecol;
Vector3 rvel;
virtual void BurstGibs()
{
static const class<Actor> gibcls[] = {"UTGenericGib1","UTGenericGib2","UTGenericGib3","UTGenericGib4"};
Actor a;
double ang, pt;
Vector3 dir;
bool dummy;
for ( int i=0; i<gibsize; i++ )
{
let a = Spawn(gibcls[Random[Blod](0,3)],Vec3Offset(FRandom[Blod](-0.5,0.5)*radius,FRandom[Blod](-0.5,0.5)*radius,FRandom[Blod](0.2,0.8)*height));
a.translation = translation;
a.SetShade(fillcolor);
a.scale *= FRandom[Blod](1.7,2.3)*scale.x;
ang = FRandom[Blod](0,360);
pt = FRandom[Blod](-90,90);
dir = (cos(pt)*cos(ang),cos(pt)*sin(ang),sin(-pt));
a.vel = rvel*0.6+dir*FRandom[Blod](8.0,12.0);
}
for ( int i=0; i<gibsize; i++ )
{
let a = Spawn("UTBloodPuff",Vec3Offset(FRandom[Blod](-12,12),FRandom[Blod](-12,12),FRandom[Blod](0.1,0.9)*height));
a.translation = translation;
a.SetShade(fillcolor);
a.scale *= FRandom[Blod](1.8,2.3)*scale.x;
ang = FRandom[Blod](0,360);
pt = FRandom[Blod](-90,90);
dir = (cos(pt)*cos(ang),cos(pt)*sin(ang),sin(-pt));
a.vel = rvel*0.2+dir*FRandom[Blod](1.5,3.0);
}
A_CountDown();
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
gibsize = int(min(max(radius,height)/24,3));
reactiontime = int(min(max(radius,height)/10,4));
rvel = vel;
vel *= 0;
}
Default
{
+NOCLIP;
+NOGRAVITY;
+NOTELEPORT;
Radius 32;
Height 16;
}
States
{
Spawn:
TNT1 A 0 NoDelay A_PlaySound("misc/gibbed");
TNT1 A 1 BurstGibs();
Wait;
}
}
Class UTFemaleLegGibber : UTGibber
{
bool firstgib;
override void BurstGibs()
{
static const class<Actor> parts[] = {"UTFemaleFoot","UTThigh"};
static const double partofsy[] = {9,8};
static const double partofsz[] = {9,20};
Actor a;
double ang, pt;
Vector3 dir;
if ( !firstgib )
{
firstgib = true;
for ( int i=0; i<2; i++ )
{
Actor a = Spawn(parts[i],Vec3Offset(-partofsy[i]*sin(angle),partofsy[i]*cos(angle),partofsz[i]));
ang = FRandom[Blod](0,360);
pt = FRandom[Blod](-90,90);
dir = (cos(pt)*cos(ang),cos(pt)*sin(ang),sin(-pt));
a.vel = rvel*0.6+dir*FRandom[Blod](8.0,12.0);
}
}
for ( int i=0; i<gibsize; i++ )
{
Vector3 box = (FRandom[Blod](-8,8),FRandom[Blod](7,12),FRandom[Blod](5,18));
let a = Spawn("UTBloodPuff",Vec3Offset(box.x*cos(angle)-box.y*sin(angle),box.x*sin(angle)+box.y*cos(angle),box.z));
ang = FRandom[Blod](0,360);
pt = FRandom[Blod](-90,90);
dir = (cos(pt)*cos(ang),cos(pt)*sin(ang),sin(-pt));
a.vel = rvel*0.2+dir*FRandom[Blod](1.5,3.0);
}
A_CountDown();
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
gibsize = 3;
reactiontime = 5;
}
States
{
Spawn:
TNT1 A 0 NoDelay; // no sound, done by player
TNT1 A 1 BurstGibs();
Wait;
}
}
Class UTPlayerGibber : UTGibber
{
bool firstgib;
override void BurstGibs()
{
static const class<Actor> bossparts[] = {"UTBossArm","UTBossArm","UTBossFoot","UTBossFoot","UTMaleTorso","UTHeadBoss"};
static const class<Actor> maleparts[] = {"UTMaleArm","UTMaleArm","UTMaleFoot","UTMaleFoot","UTMaleTorso","UTHeadMale"};
static const class<Actor> femaleparts[] = {"UTFemaleArm","UTFemaleArm","UTFemaleFoot","UTFemaleFoot","UTFemaleTorso","UTHeadFemale"};
static const class<Actor> extraparts[] = {"UTThigh","UTThigh","UTHeart","UTLiver","UTStomach"};
static const double partofsy[] =
{
14,
-14,
9,
-9,
0,
0,
8,
-8,
-2,
5,
-3
};
static const double partofsz[] =
{
36,
36,
9,
9,
32,
48,
20,
20,
40,
32,
35
};
Actor a;
double ang, pt;
Vector3 dir;
if ( !firstgib )
{
firstgib = true;
for ( int i=0; i<11; i++ )
{
Actor a;
if ( i < 6 )
{
if ( UTPlayer(Gibbed).DollType == UTPlayer.DOLL_Boss )
a = Spawn(bossparts[i],Vec3Offset(-partofsy[i]*sin(angle),partofsy[i]*cos(angle),partofsz[i]));
else if ( UTPlayer(Gibbed).DollType == UTPlayer.DOLL_Female )
a = Spawn(femaleparts[i],Vec3Offset(-partofsy[i]*sin(angle),partofsy[i]*cos(angle),partofsz[i]));
else a = Spawn(maleparts[i],Vec3Offset(-partofsy[i]*sin(angle),partofsy[i]*cos(angle),partofsz[i]));
}
else a = Spawn(extraparts[i-6],Vec3Offset(-partofsy[i]*sin(angle),partofsy[i]*cos(angle),partofsz[i]));
ang = FRandom[Blod](0,360);
pt = FRandom[Blod](-90,90);
if ( a is 'UTHead' )
{
pt = FRandom[Blod](-90,-15);
if ( UTPlayer(Gibbed).player )
{
UTPlayer(Gibbed).player.Camera = a;
UTHead(a).headowner = UTPlayer(Gibbed).player;
}
}
dir = (cos(pt)*cos(ang),cos(pt)*sin(ang),sin(-pt));
a.vel = rvel*0.6+dir*FRandom[Blod](8.0,12.0);
}
}
for ( int i=0; i<gibsize; i++ )
{
let a = Spawn("UTBloodPuff",Vec3Offset(FRandom[Blod](-0.8,0.8)*radius,FRandom[Blod](-0.8,0.8)*radius,FRandom[Blod](0.1,0.9)*height));
ang = FRandom[Blod](0,360);
pt = FRandom[Blod](-90,90);
dir = (cos(pt)*cos(ang),cos(pt)*sin(ang),sin(-pt));
a.vel = rvel*0.2+dir*FRandom[Blod](1.5,3.0);
}
A_CountDown();
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
gibsize = 3;
reactiontime = 5;
}
States
{
Spawn:
TNT1 A 0 NoDelay; // no sound, done by player
TNT1 A 1 BurstGibs();
Wait;
}
}
// Chunks
Class UTGib : Actor
{
double rollvel, anglevel, pitchvel;
Default
{
Radius 4;
Height 4;
BounceType "Hexen";
BounceFactor 0.8;
WallBounceFactor 0.8;
Gravity 0.6;
+ROLLSPRITE;
+ROLLCENTER;
+INTERPOLATEANGLES;
+CANBOUNCEWATER;
+MISSILE;
+THRUACTORS;
+USEBOUNCESTATE;
+NOTELEPORT;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
tracer = Spawn("UTBloodTrail",pos);
tracer.target = self;
if ( bloodcolor ) tracer.SetShade(bloodcolor);
else tracer.SetShade(gameinfo.defaultbloodcolor);
tracer.translation = bloodtranslation;
rollvel = FRandom[Blod](3,6)*RandomPick[Blod](-1,1);
anglevel = FRandom[Blod](3,6)*RandomPick[Blod](-1,1);
pitchvel = FRandom[Blod](3,6)*RandomPick[Blod](-1,1);
}
void A_HandleBounce()
{
double spd = vel.length();
if ( spd > double.epsilon )
vel = (vel.unit()+(FRandom[Blod](-0.2,0.2),FRandom[Blod](-0.2,0.2),FRandom[Blod](-0.2,0.2))).unit()*spd;
if ( BlockingFloor && (vel.xy.length() < 1) )
{
ClearBounce();
ExplodeMissile();
}
if ( spd < 10 )
{
if ( tracer ) tracer.Destroy();
}
else if ( spd > 20 ) vel *= 0.8;
A_PlaySound("misc/gibp");
double ang, pt;
int max = flak_blood?6:2;
for ( int i=0; i<max; i++ )
{
Actor d;
if ( flak_blood ) d = Spawn("UTBloodDrop",pos);
else d = Spawn("Blood",pos,ALLOW_REPLACE);
d.translation = bloodtranslation;
if ( bloodcolor ) d.SetShade(bloodcolor);
else d.SetShade(gameinfo.defaultbloodcolor);
ang = FRandom[Blood](0,360);
pt = FRandom[Blood](-90,90);
Vector3 dir = -vel*0.4;
dir += (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*1.3;
d.vel = dir*FRandom[Blood](0.8,1.2);
d.scale *= 0.75*FRandom[Blood](0.6,1.4);
}
rollvel = FRandom[Blod](3,6)*RandomPick[Blod](-1,1);
anglevel = FRandom[Blod](3,6)*RandomPick[Blod](-1,1);
pitchvel = FRandom[Blod](3,6)*RandomPick[Blod](-1,1);
}
States
{
Spawn:
UGIB A 1
{
roll += rollvel;
angle += anglevel;
pitch += pitchvel;
}
Wait;
Bounce:
UGIB A 0 A_HandleBounce();
Goto Spawn;
Death:
UGIB A 1 A_SetTics(Random[Blod](12,18)*15);
UGIB A 1 A_FadeOut(0.05);
Wait;
}
}
Class UTGenericGib1 : UTGib {}
Class UTGenericGib2 : UTGib {}
Class UTGenericGib3 : UTGib {}
Class UTGenericGib4 : UTGib {}
Class UTThigh : UTGib {}
Class UTFemaleArm : UTGib {}
Class UTFemaleFoot : UTGib {}
Class UTFemaleTorso : UTGib {}
Class UTMaleArm : UTGib {}
Class UTMaleFoot : UTGib {}
Class UTMaleTorso : UTGib {}
Class UTBossArm : UTGib {}
Class UTBossFoot : UTGib {}
Class UTBossTorso : UTGib {}
Class UTHeart : UTGib
{
States
{
Spawn:
UGIB ABCDEF 1
{
roll += rollvel;
angle += anglevel;
pitch += pitchvel;
}
Loop;
Death:
UGIB ABCDEFABCDEFABCDEF 2;
UGIB ABCDEFABCDEF 4;
UGIB ABCDEF 8;
UGIB A 1 A_SetTics(Random[Blod](12,18)*15);
UGIB A 1 A_FadeOut(0.05);
Wait;
}
}
Class UTLiver : UTGib {}
Class UTStomach : UTGib {}
Class UTHead : UTGib
{
PlayerInfo headowner;
override void PostBeginPlay()
{
Super.PostBeginPlay();
UTMainHandler.DoFlash(self,Color(128,255,0,0),150);
UTMainHandler.DoFlash(self,Color(96,255,0,0),0);
}
override void Tick()
{
Super.Tick();
if ( headowner && headowner.mo && (headowner.mo.Health > 0) && (headowner.Camera == self) )
{
headowner.Camera = headowner.mo;
headowner = null;
}
}
override void OnDestroy()
{
if ( headowner && (headowner.Camera == self) && headowner.mo )
{
headowner.Camera = headowner.mo;
headowner = null;
}
Super.OnDestroy();
}
States
{
Death:
UGIB A 1 A_SetTics(Random[Blod](12,18)*15);
UGIB A 0 A_JumpIf(headowner,"Death");
UGIB A 1 A_FadeOut(0.05);
Wait;
}
}
Class UTHeadFemale : UTHead {}
Class UTHeadMale : UTHead {}
Class UTHeadBoss : UTHead {}