- Fuck it, Quadravol will be lever action. - Tiny cleanup. - Rewrite the weapon replacement system (less of a mess now maybe?). - Some menu fixes. - Minimap zoom increments like in the Common Library. - Add missing sound definition for Safety Tether. (This mostly went unnoticed because it's VERY rare to have it play) - Shift Sparkster x3 (DLC2) to slot 7. This way you can have both it and the Quadravol simultaneously. It would be unfair to not let you hold both "iconic" UnSX weapons at once. - Small lore tweak on Quadravol stance swap. - Fix off-by-one bug in looping palette lights. - Re-do logo shader. Use separate layer textures. - Fix Elemental Coating breaking "End Level" damage sectors. (This will be the last batch of changes before I continue working on menus)
1636 lines
36 KiB
Text
1636 lines
36 KiB
Text
// basic effects
|
|
|
|
// imitates UE1 light type LT_TexturePaletteOnce/LT_TexturePaletteLoop
|
|
Class PaletteLight : PointLight
|
|
{
|
|
Color pal[256];
|
|
bool IsLooping;
|
|
int InitialReactionTime;
|
|
|
|
Default
|
|
{
|
|
Tag "Explosion";
|
|
Args 0,0,0,80;
|
|
ReactionTime 15;
|
|
}
|
|
private void UpdateLight()
|
|
{
|
|
int index = clamp(255-((255*ReactionTime)/InitialReactionTime),0,255);
|
|
args[LIGHT_RED] = pal[index].r;
|
|
args[LIGHT_GREEN] = pal[index].g;
|
|
args[LIGHT_BLUE] = pal[index].b;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
String palname = GetTag();
|
|
int sep = palname.IndexOf(",");
|
|
int palnum = 0;
|
|
if ( sep != -1 )
|
|
{
|
|
String palnumstr = palname.Mid(sep+1);
|
|
palnum = palnumstr.ToInt()*768;
|
|
palname.Truncate(sep);
|
|
}
|
|
int lump = Wads.CheckNumForFullname(String.Format("palettes/%s.pal",palname));
|
|
String paldat = Wads.ReadLump(lump);
|
|
for ( int i=0; i<256; i++ )
|
|
{
|
|
pal[i].r = paldat.ByteAt(palnum++);
|
|
pal[i].g = paldat.ByteAt(palnum++);
|
|
pal[i].b = paldat.ByteAt(palnum++);
|
|
}
|
|
if ( ReactionTime < 0 )
|
|
{
|
|
ReactionTime = abs(ReactionTime)-1;
|
|
IsLooping = true;
|
|
}
|
|
InitialReactionTime = ReactionTime;
|
|
UpdateLight();
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( isFrozen() ) return;
|
|
ReactionTime--;
|
|
if ( ReactionTime < 0 )
|
|
{
|
|
if ( !IsLooping )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
else ReactionTime = abs(InitialReactionTime);
|
|
}
|
|
if ( target ) SetOrigin(target.pos,true);
|
|
UpdateLight();
|
|
}
|
|
}
|
|
|
|
// Generic smoke, lightweight tick
|
|
Class SWWMSmoke : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Shaded";
|
|
StencilColor "FFFFFF";
|
|
Radius .1;
|
|
Height 0;
|
|
Speed 1;
|
|
+NOBLOCKMAP;
|
|
+NOGRAVITY;
|
|
+DONTSPLASH;
|
|
+FORCEXYBILLBOARD;
|
|
+ROLLSPRITE;
|
|
+ROLLCENTER;
|
|
+THRUACTORS;
|
|
+NOTELEPORT;
|
|
+NOINTERACTION;
|
|
Scale .3;
|
|
FloatBobPhase 0;
|
|
}
|
|
|
|
override void PostBeginPlay()
|
|
{
|
|
double ang, pt;
|
|
scale *= FRandom[Puff](.5,1.5);
|
|
alpha = min(1.,alpha*FRandom[Puff](.5,1.5));
|
|
ang = FRandom[Puff](0,360);
|
|
pt = FRandom[Puff](-90,90);
|
|
vel += (cos(pt)*cos(ang),cos(pt)*sin(ang),-sin(pt))*FRandom[Puff](.2,.8)*speed;
|
|
roll = Frandom[Puff](0,360);
|
|
scale.x *= RandomPick[Puff](-1,1);
|
|
scale.y *= RandomPick[Puff](-1,1);
|
|
}
|
|
override void Tick()
|
|
{
|
|
prev = pos; // for interpolation
|
|
if ( isFrozen() ) return;
|
|
vel *= .96;
|
|
vel.z += .01;
|
|
// linetrace-based movement (hopefully more reliable than traditional methods)
|
|
Vector3 dir = vel;
|
|
double spd = vel.length();
|
|
dir /= spd;
|
|
double dist = spd;
|
|
FLineTraceData d;
|
|
Vector3 newpos = pos;
|
|
newpos.z = clamp(newpos.z,floorz,ceilingz);
|
|
int nstep = 0;
|
|
while ( dist > 0 )
|
|
{
|
|
// safeguard, too many bounces
|
|
if ( nstep > MAXBOUNCEPERTIC )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
double ang = atan2(dir.y,dir.x);
|
|
double pt = asin(-dir.z);
|
|
LineTrace(ang,dist,pt,TRF_THRUACTORS|TRF_THRUHITSCAN|TRF_ABSPOSITION,newpos.z,newpos.x,newpos.y,d);
|
|
Vector3 hitnormal = -d.HitDir;
|
|
if ( d.HitType == TRACE_HitFloor )
|
|
{
|
|
if ( d.Hit3DFloor ) hitnormal = -d.Hit3DFloor.top.Normal;
|
|
else hitnormal = d.HitSector.floorplane.Normal;
|
|
}
|
|
else if ( d.HitType == TRACE_HitCeiling )
|
|
{
|
|
if ( d.Hit3DFloor ) hitnormal = -d.Hit3DFloor.bottom.Normal;
|
|
else hitnormal = d.HitSector.ceilingplane.Normal;
|
|
}
|
|
else if ( d.HitType == TRACE_HitWall )
|
|
{
|
|
hitnormal = (-d.HitLine.delta.y,d.HitLine.delta.x,0).unit();
|
|
if ( !d.LineSide ) hitnormal *= -1;
|
|
}
|
|
if ( d.HitType != TRACE_HitNone )
|
|
{
|
|
dist -= d.Distance;
|
|
// should only happen if we bounced
|
|
dir = d.HitDir-(FRandom[Puff](1.,1.2)*hitnormal*(d.HitDir dot hitnormal));
|
|
vel = dir*spd;
|
|
newpos = d.HitLocation+dir;
|
|
}
|
|
else
|
|
{
|
|
dist = 0.;
|
|
newpos = level.Vec3Offset(newpos,dir*spd);
|
|
}
|
|
nstep++;
|
|
}
|
|
newpos.z = clamp(newpos.z,floorz,ceilingz);
|
|
SetOrigin(newpos,true);
|
|
UpdateWaterLevel();
|
|
if ( (waterlevel > 0) && !bAMBUSH )
|
|
{
|
|
let b = Spawn("SWWMBubble",pos);
|
|
b.scale *= abs(scale.x);
|
|
b.vel = vel;
|
|
Destroy();
|
|
return;
|
|
}
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
|
|
States
|
|
{
|
|
Spawn:
|
|
XSMK ABCDEFGHIJKLMNOPQRST 1 A_SetTics(1+special1);
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
// strictly non-interacting smoke, much lighter tick, used for heavier effects
|
|
Class SWWMHalfSmoke : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Shaded";
|
|
StencilColor "FFFFFF";
|
|
Radius .1;
|
|
Height 0;
|
|
Speed 1;
|
|
+NOBLOCKMAP;
|
|
+NOGRAVITY;
|
|
+DONTSPLASH;
|
|
+FORCEXYBILLBOARD;
|
|
+ROLLSPRITE;
|
|
+ROLLCENTER;
|
|
+NOTELEPORT;
|
|
+NOINTERACTION;
|
|
Scale 0.3;
|
|
FloatBobPhase 0;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
double ang, pt;
|
|
scale *= FRandom[Puff](0.5,1.5);
|
|
alpha *= FRandom[Puff](0.5,1.5);
|
|
ang = FRandom[Puff](0,360);
|
|
pt = FRandom[Puff](-90,90);
|
|
vel += (cos(pt)*cos(ang),cos(pt)*sin(ang),-sin(pt))*FRandom[Puff](0.2,0.8)*speed;
|
|
roll = Frandom[Puff](0,360);
|
|
scale.x *= RandomPick[Puff](-1,1);
|
|
scale.y *= RandomPick[Puff](-1,1);
|
|
}
|
|
override void Tick()
|
|
{
|
|
prev = pos; // for interpolation
|
|
if ( isFrozen() ) return;
|
|
vel *= 0.96;
|
|
vel.z += 0.01;
|
|
SetOrigin(level.Vec3Offset(pos,vel),true);
|
|
UpdateWaterLevel();
|
|
if ( (waterlevel > 0) && !bAMBUSH )
|
|
{
|
|
let b = Spawn("SWWMBubble",pos);
|
|
b.scale *= abs(scale.x);
|
|
b.vel = vel;
|
|
Destroy();
|
|
return;
|
|
}
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
|
|
States
|
|
{
|
|
Spawn:
|
|
XSMK ABCDEFGHIJKLMNOPQRST 1 A_SetTics(1+special1);
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class SWWMSmallSmoke : SWWMHalfSmoke
|
|
{
|
|
override void PostBeginPlay()
|
|
{
|
|
double ang, pt;
|
|
scale *= FRandom[Puff](0.1,0.3);
|
|
alpha *= FRandom[Puff](0.5,1.5);
|
|
ang = FRandom[Puff](0,360);
|
|
pt = FRandom[Puff](-90,90);
|
|
vel += (cos(pt)*cos(ang),cos(pt)*sin(ang),-sin(pt))*FRandom[Puff](0.04,0.16);
|
|
roll = Frandom[Puff](0,360);
|
|
scale.x *= RandomPick[Puff](-1,1);
|
|
scale.y *= RandomPick[Puff](-1,1);
|
|
}
|
|
|
|
States
|
|
{
|
|
Spawn:
|
|
QSM6 ABCDEFGHIJKLMNOPQR 1 A_SetTics(1+special1);
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class SWWMBubble : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Radius .1;
|
|
Height 0;
|
|
+NOBLOCKMAP;
|
|
+NOGRAVITY;
|
|
+DONTSPLASH;
|
|
+FORCEXYBILLBOARD;
|
|
+NOTELEPORT;
|
|
+THRUACTORS;
|
|
+NOINTERACTION;
|
|
Scale 0.5;
|
|
FloatBobPhase 0;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
double ang, pt;
|
|
scale *= FRandom[Puff](0.5,1.5);
|
|
ang = FRandom[Puff](0,360);
|
|
pt = FRandom[Puff](-90,90);
|
|
vel += (cos(pt)*cos(ang),cos(pt)*sin(ang),-sin(pt))*FRandom[Puff](0.2,0.8);
|
|
if ( waterlevel <= 0 ) Destroy();
|
|
SetState(ResolveState("Spawn")+Random[Puff](0,19));
|
|
}
|
|
override void Tick()
|
|
{
|
|
prev = pos;
|
|
if ( isFrozen() ) return;
|
|
vel *= 0.96;
|
|
vel.z += 0.05;
|
|
// linetrace-based movement (hopefully more reliable than traditional methods)
|
|
Vector3 dir = vel;
|
|
double spd = vel.length();
|
|
dir /= spd;
|
|
double dist = spd;
|
|
FLineTraceData d;
|
|
Vector3 newpos = pos;
|
|
newpos.z = clamp(newpos.z,floorz,ceilingz);
|
|
int nstep = 0;
|
|
while ( dist > 0 )
|
|
{
|
|
// safeguard, too many bounces
|
|
if ( nstep > MAXBOUNCEPERTIC )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
double ang = atan2(dir.y,dir.x);
|
|
double pt = asin(-dir.z);
|
|
LineTrace(ang,dist,pt,TRF_THRUACTORS|TRF_THRUHITSCAN|TRF_ABSPOSITION,newpos.z,newpos.x,newpos.y,d);
|
|
Vector3 hitnormal = -d.HitDir;
|
|
if ( d.HitType == TRACE_HitFloor )
|
|
{
|
|
if ( d.Hit3DFloor ) hitnormal = -d.Hit3DFloor.top.Normal;
|
|
else hitnormal = d.HitSector.floorplane.Normal;
|
|
}
|
|
else if ( d.HitType == TRACE_HitCeiling )
|
|
{
|
|
if ( d.Hit3DFloor ) hitnormal = -d.Hit3DFloor.bottom.Normal;
|
|
else hitnormal = d.HitSector.ceilingplane.Normal;
|
|
}
|
|
else if ( d.HitType == TRACE_HitWall )
|
|
{
|
|
hitnormal = (-d.HitLine.delta.y,d.HitLine.delta.x,0).unit();
|
|
if ( !d.LineSide ) hitnormal *= -1;
|
|
}
|
|
if ( d.HitType != TRACE_HitNone )
|
|
{
|
|
dist -= d.Distance;
|
|
// should only happen if we bounced
|
|
dir = d.HitDir-(FRandom[Puff](1.,1.2)*hitnormal*(d.HitDir dot hitnormal));
|
|
vel = dir*spd;
|
|
newpos = d.HitLocation+dir;
|
|
}
|
|
else
|
|
{
|
|
dist = 0.;
|
|
newpos = level.Vec3Offset(newpos,dir*spd);
|
|
}
|
|
nstep++;
|
|
}
|
|
newpos.z = clamp(newpos.z,floorz,ceilingz);
|
|
SetOrigin(newpos,true);
|
|
UpdateWaterLevel();
|
|
if ( (waterlevel <= 0) || !Random[Puff](0,100) ) Destroy();
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XBUB ABCDEFGHIJKLMNOPQRST 1;
|
|
Loop;
|
|
}
|
|
}
|
|
|
|
Class SWWMSparkTrail : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Radius .1;
|
|
Height 0.;
|
|
+FORCEXYBILLBOARD;
|
|
+NOGRAVITY;
|
|
+NOBLOCKMAP;
|
|
+NOINTERACTION;
|
|
+DONTSPLASH;
|
|
+NOTELEPORT;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
A_SetScale(scale.x*.9,scale.y);
|
|
A_FadeOut(.06);
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A -1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class SWWMSpark : Actor
|
|
{
|
|
bool dead;
|
|
Sector tracksector;
|
|
int trackplane;
|
|
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Radius .1;
|
|
Height 0;
|
|
+NOBLOCKMAP;
|
|
+FORCEXYBILLBOARD;
|
|
+THRUACTORS;
|
|
+NOTELEPORT;
|
|
+DONTSPLASH;
|
|
+NOINTERACTION;
|
|
Gravity 0.2;
|
|
Scale 0.05;
|
|
FloatBobPhase 0;
|
|
}
|
|
override void Tick()
|
|
{
|
|
prev = pos;
|
|
if ( isFrozen() ) return;
|
|
if ( dead )
|
|
{
|
|
// do nothing but follow floor movement
|
|
if ( tracksector )
|
|
{
|
|
double trackz;
|
|
if ( trackplane ) trackz = tracksector.ceilingplane.ZAtPoint(pos.xy);
|
|
else trackz = tracksector.floorplane.ZAtPoint(pos.xy);
|
|
if ( trackz != pos.z ) SetZ(trackz);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vel.z -= GetGravity();
|
|
// linetrace-based movement (hopefully more reliable than traditional methods)
|
|
Vector3 dir = vel;
|
|
double spd = vel.length();
|
|
dir /= spd;
|
|
double dist = spd;
|
|
FLineTraceData d;
|
|
Vector3 newpos = pos;
|
|
newpos.z = clamp(newpos.z,floorz,ceilingz);
|
|
int nstep = 0;
|
|
while ( dist > 0 )
|
|
{
|
|
Vector3 oldpos = newpos;
|
|
// safeguard, too many bounces
|
|
if ( nstep > MAXBOUNCEPERTIC )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
double ang = atan2(dir.y,dir.x);
|
|
double pt = asin(-dir.z);
|
|
LineTrace(ang,dist,pt,TRF_THRUACTORS|TRF_THRUHITSCAN|TRF_ABSPOSITION,newpos.z,newpos.x,newpos.y,d);
|
|
Vector3 hitnormal = -d.HitDir;
|
|
if ( d.HitType == TRACE_HitFloor )
|
|
{
|
|
if ( d.Hit3DFloor ) hitnormal = -d.Hit3DFloor.top.Normal;
|
|
else hitnormal = d.HitSector.floorplane.Normal;
|
|
}
|
|
else if ( d.HitType == TRACE_HitCeiling )
|
|
{
|
|
if ( d.Hit3DFloor ) hitnormal = -d.Hit3DFloor.bottom.Normal;
|
|
else hitnormal = d.HitSector.ceilingplane.Normal;
|
|
}
|
|
else if ( d.HitType == TRACE_HitWall )
|
|
{
|
|
hitnormal = (-d.HitLine.delta.y,d.HitLine.delta.x,0).unit();
|
|
if ( !d.LineSide ) hitnormal *= -1;
|
|
}
|
|
if ( d.HitType != TRACE_HitNone )
|
|
{
|
|
dist -= d.Distance;
|
|
// should only happen if we bounced
|
|
dir = d.HitDir-(2*hitnormal*(d.HitDir dot hitnormal));
|
|
spd *= .4;
|
|
dist *= .4;
|
|
vel = dir*spd;
|
|
newpos = d.HitLocation+dir;
|
|
}
|
|
else
|
|
{
|
|
dist = 0.;
|
|
newpos = level.Vec3Offset(newpos,dir*spd);
|
|
}
|
|
if ( ((spd < 1.) || (dir.z <= 0.)) && ((d.HitType == TRACE_HitFloor) || (newpos.z <= floorz)) )
|
|
{
|
|
// lose speed and die
|
|
if ( d.Hit3DFloor )
|
|
{
|
|
newpos.z = d.Hit3DFloor.top.ZAtPoint(newpos.xy);
|
|
tracksector = d.Hit3DFloor.model;
|
|
trackplane = 1;
|
|
}
|
|
else
|
|
{
|
|
// hacky workaround
|
|
if ( !d.HitSector ) d.HitSector = floorsector;
|
|
newpos.z = d.HitSector.floorplane.ZAtPoint(newpos.xy);
|
|
tracksector = d.HitSector;
|
|
trackplane = 0;
|
|
}
|
|
vel = (0,0,0);
|
|
pitch = 0;
|
|
roll = 0;
|
|
dead = true;
|
|
SetStateLabel("Death");
|
|
break;
|
|
}
|
|
nstep++;
|
|
}
|
|
newpos.z = clamp(newpos.z,floorz,ceilingz);
|
|
Vector3 taildir = level.Vec3Diff(newpos,pos);
|
|
double taillen = taildir.length();
|
|
if ( (taillen > 0.) && (alpha > .3) && (waterlevel <= 0) )
|
|
{
|
|
taildir /= taillen;
|
|
let t = Spawn("SWWMSparkTrail",newpos);
|
|
t.alpha = alpha*.3;
|
|
t.scale.y = taillen;
|
|
t.angle = atan2(taildir.y,taildir.x);
|
|
t.pitch = asin(-taildir.z)+90;
|
|
}
|
|
SetOrigin(newpos,true);
|
|
if ( (pos.z <= floorz) && GetFloorTerrain().IsLiquid )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
}
|
|
UpdateWaterLevel();
|
|
if ( waterlevel > 0 )
|
|
{
|
|
let b = Spawn("SWWMBubble",pos);
|
|
b.vel = vel;
|
|
b.scale *= 0.3;
|
|
Destroy();
|
|
return;
|
|
}
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
BLPF A 1 Bright A_FadeOut(0.01);
|
|
Wait;
|
|
Death:
|
|
BLPF A 1 Bright A_FadeOut(0.05);
|
|
Wait;
|
|
}
|
|
}
|
|
|
|
Class SWWMChip : Actor
|
|
{
|
|
SWWMChip prevchip, nextchip;
|
|
bool killme;
|
|
double anglevel, pitchvel, rollvel;
|
|
bool dead;
|
|
Sector tracksector;
|
|
int trackplane;
|
|
|
|
Default
|
|
{
|
|
Radius .1;
|
|
Height 0;
|
|
+NOBLOCKMAP;
|
|
+THRUACTORS;
|
|
+NOTELEPORT;
|
|
+DONTSPLASH;
|
|
+INTERPOLATEANGLES;
|
|
+ROLLSPRITE;
|
|
+ROLLCENTER;
|
|
+FORCEXYBILLBOARD;
|
|
+NOINTERACTION;
|
|
Gravity 0.35;
|
|
Scale 0.2;
|
|
FloatBobPhase 0;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
anglevel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1);
|
|
pitchvel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1);
|
|
rollvel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1);
|
|
frame = Random[Junk](0,7);
|
|
scale *= Frandom[Junk](0.8,1.2);
|
|
SWWMHandler.QueueChip(self);
|
|
}
|
|
override void OnDestroy()
|
|
{
|
|
SWWMHandler.DeQueueChip(self);
|
|
Super.OnDestroy();
|
|
}
|
|
override void Tick()
|
|
{
|
|
prev = pos; // for interpolation
|
|
if ( isFrozen() ) return;
|
|
if ( dead )
|
|
{
|
|
// do nothing but follow floor movement
|
|
if ( tracksector )
|
|
{
|
|
double trackz;
|
|
if ( trackplane ) trackz = tracksector.ceilingplane.ZAtPoint(pos.xy);
|
|
else trackz = tracksector.floorplane.ZAtPoint(pos.xy);
|
|
if ( trackz != pos.z )
|
|
{
|
|
SetZ(trackz);
|
|
UpdateWaterLevel(false);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( waterlevel <= 0 ) vel.z -= GetGravity();
|
|
// linetrace-based movement (hopefully more reliable than traditional methods)
|
|
Vector3 dir = vel;
|
|
double spd = vel.length();
|
|
dir /= spd;
|
|
double dist = spd;
|
|
FLineTraceData d;
|
|
Vector3 newpos = pos;
|
|
newpos.z = clamp(newpos.z,floorz,ceilingz);
|
|
int nstep = 0;
|
|
while ( dist > 0 )
|
|
{
|
|
// safeguard, too many bounces
|
|
if ( nstep > MAXBOUNCEPERTIC )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
double ang = atan2(dir.y,dir.x);
|
|
double pt = asin(-dir.z);
|
|
LineTrace(ang,dist,pt,TRF_THRUACTORS|TRF_THRUHITSCAN|TRF_ABSPOSITION,newpos.z,newpos.x,newpos.y,d);
|
|
Vector3 hitnormal = -d.HitDir;
|
|
if ( d.HitType == TRACE_HitFloor )
|
|
{
|
|
if ( d.Hit3DFloor ) hitnormal = -d.Hit3DFloor.top.Normal;
|
|
else hitnormal = d.HitSector.floorplane.Normal;
|
|
}
|
|
else if ( d.HitType == TRACE_HitCeiling )
|
|
{
|
|
if ( d.Hit3DFloor ) hitnormal = -d.Hit3DFloor.bottom.Normal;
|
|
else hitnormal = d.HitSector.ceilingplane.Normal;
|
|
}
|
|
else if ( d.HitType == TRACE_HitWall )
|
|
{
|
|
hitnormal = (-d.HitLine.delta.y,d.HitLine.delta.x,0).unit();
|
|
if ( !d.LineSide ) hitnormal *= -1;
|
|
}
|
|
if ( d.HitType != TRACE_HitNone )
|
|
{
|
|
dist -= d.Distance;
|
|
// should only happen if we bounced
|
|
dir = d.HitDir-(2*hitnormal*(d.HitDir dot hitnormal));
|
|
spd *= .3;
|
|
dist *= .3;
|
|
vel = dir*spd;
|
|
newpos = d.HitLocation+dir;
|
|
SetStateLabel("Bounce");
|
|
}
|
|
else
|
|
{
|
|
dist = 0.;
|
|
newpos = level.Vec3Offset(newpos,dir*spd);
|
|
}
|
|
newpos.z = clamp(newpos.z,floorz,ceilingz);
|
|
if ( ((spd < 1.) || (dir.z <= 0.)) && ((d.HitType == TRACE_HitFloor) || (newpos.z <= floorz)) )
|
|
{
|
|
// lose speed and die
|
|
if ( d.Hit3DFloor )
|
|
{
|
|
newpos.z = d.Hit3DFloor.top.ZAtPoint(newpos.xy);
|
|
tracksector = d.Hit3DFloor.model;
|
|
trackplane = 1;
|
|
}
|
|
else
|
|
{
|
|
// hacky workaround
|
|
if ( !d.HitSector ) d.HitSector = floorsector;
|
|
newpos.z = d.HitSector.floorplane.ZAtPoint(newpos.xy);
|
|
tracksector = d.HitSector;
|
|
trackplane = 0;
|
|
}
|
|
vel = (0,0,0);
|
|
pitch = 0;
|
|
roll = 0;
|
|
dead = true;
|
|
SetStateLabel("Death");
|
|
break;
|
|
}
|
|
nstep++;
|
|
}
|
|
SetOrigin(newpos,true);
|
|
UpdateWaterLevel();
|
|
if ( (pos.z <= floorz) && GetFloorTerrain().IsLiquid )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
}
|
|
if ( killme ) A_FadeOut(.01);
|
|
if ( waterlevel > 0 )
|
|
{
|
|
vel *= .98;
|
|
anglevel *= .98;
|
|
pitchvel *= .98;
|
|
rollvel *= .98;
|
|
}
|
|
if ( !CheckNoDelay() || (tics == -1) ) return;
|
|
if ( tics > 0 ) tics--;
|
|
while ( !tics )
|
|
{
|
|
if ( !SetState(CurState.NextState) )
|
|
return;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 # 1
|
|
{
|
|
angle += anglevel;
|
|
pitch += pitchvel;
|
|
roll += rollvel;
|
|
}
|
|
Loop;
|
|
Bounce:
|
|
XZW1 # 0
|
|
{
|
|
anglevel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1);
|
|
pitchvel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1);
|
|
rollvel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1);
|
|
}
|
|
Goto Spawn;
|
|
Death:
|
|
XZW2 # -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class PoofLight : PaletteLight
|
|
{
|
|
Default
|
|
{
|
|
Tag "Yellow";
|
|
ReactionTime 5;
|
|
Args 0,0,0,60;
|
|
}
|
|
}
|
|
Class PoofLight2 : PaletteLight
|
|
{
|
|
Default
|
|
{
|
|
Tag "Yellow";
|
|
ReactionTime 20;
|
|
Args 0,0,0,90;
|
|
}
|
|
}
|
|
|
|
Class SWWMItemFog : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Radius .1;
|
|
Height 0;
|
|
+NOGRAVITY;
|
|
+NOBLOCKMAP;
|
|
+DONTSPLASH;
|
|
+ROLLSPRITE;
|
|
+ROLLCENTER;
|
|
+NOINTERACTION;
|
|
+FORCEXYBILLBOARD;
|
|
FloatBobPhase 0;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
BLPF A 2 Bright NoDelay
|
|
{
|
|
// offset up
|
|
SetOrigin(Vec3Offset(0,0,16),false);
|
|
roll = FRandom[ExploS](0,360);
|
|
scale *= FRandom[ExploS](0.9,1.1);
|
|
scale.x *= RandomPick[ExploS](-1,1);
|
|
scale.y *= RandomPick[ExploS](-1,1);
|
|
int numpt = Random[ExploS](8,12);
|
|
if ( bAMBUSH ) numpt *= 2;
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](.3,8);
|
|
let s = Spawn(bAMBUSH?"SWWMSmoke":"SWWMSmallSmoke",pos);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(3,2,1)*Random[ExploS](64,85));
|
|
s.A_SetRenderStyle(s.alpha,STYLE_AddShaded);
|
|
s.scale *= 3.;
|
|
s.alpha *= bAMBUSH?.4:.2;
|
|
}
|
|
Spawn(bAMBUSH?"PoofLight2":"PoofLight",pos);
|
|
}
|
|
BLPF A 1 Bright A_FadeOut(.3);
|
|
Wait;
|
|
}
|
|
}
|
|
|
|
Class TeleLight : PaletteLight
|
|
{
|
|
Default
|
|
{
|
|
Tag "ImpactWav";
|
|
ReactionTime 10;
|
|
Args 0,0,0,150;
|
|
}
|
|
}
|
|
|
|
Class SWWMTeleportSparkle : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Scale 0.3;
|
|
Radius .1;
|
|
Height 0.;
|
|
+NOGRAVITY;
|
|
+NOBLOCKMAP;
|
|
+DONTSPLASH;
|
|
+ROLLSPRITE;
|
|
+ROLLCENTER;
|
|
+FORCEXYBILLBOARD;
|
|
+NOINTERACTION;
|
|
FloatBobPhase 0;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
A_SetScale(scale.x*specialf1);
|
|
A_FadeOut(specialf2);
|
|
if ( vel != (0,0,0) )
|
|
{
|
|
SetOrigin(level.Vec3Offset(pos,vel),true);
|
|
vel *= .98;
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
BLPF C -1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class SWWMTeleportDest : Actor
|
|
{
|
|
Default
|
|
{
|
|
+NOGRAVITY;
|
|
+NOBLOCKMAP;
|
|
+DONTSPLASH;
|
|
+NOINTERACTION;
|
|
Radius .1;
|
|
Height 0.;
|
|
}
|
|
|
|
override void PostBeginPlay()
|
|
{
|
|
special1 = Random[ExploS](0,10);
|
|
}
|
|
|
|
override void Tick()
|
|
{
|
|
if ( isFrozen() ) return;
|
|
if ( (level.maptime+special1)%10 ) return;
|
|
int numpt = Random[ExploS](0,2);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
A_SpawnParticle("88 AA FF",SPF_FULLBRIGHT,Random[ExploS](120,240),FRandom[ExploS](2.,4.),0,0,0,28,FRandom[ExploS](-.8,.8),FRandom[ExploS](-.8,.8),FRandom[ExploS](-.8,.8),0,0,0,FRandom[ExploS](.15,.3),-1,FRandom[ExploS](-.02,-.01));
|
|
}
|
|
}
|
|
}
|
|
|
|
Class SWWMTeleportLine : Actor
|
|
{
|
|
Line tline;
|
|
|
|
Default
|
|
{
|
|
+NOGRAVITY;
|
|
+NOBLOCKMAP;
|
|
+DONTSPLASH;
|
|
+NOINTERACTION;
|
|
Radius .1;
|
|
Height 0.;
|
|
}
|
|
|
|
override void PostBeginPlay()
|
|
{
|
|
special1 = Random[ExploS](0,5);
|
|
}
|
|
|
|
override void Tick()
|
|
{
|
|
if ( !tline )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
if ( isFrozen() ) return;
|
|
if ( (level.maptime+special1)%5 ) return;
|
|
Vector3 apos, bpos;
|
|
apos.xy = tline.v1.p;
|
|
bpos.xy = tline.v2.p;
|
|
apos.z = max(tline.frontsector.floorplane.ZAtPoint(apos.xy),tline.backsector.floorplane.ZAtPoint(apos.xy));
|
|
bpos.z = max(tline.frontsector.floorplane.ZAtPoint(bpos.xy),tline.backsector.floorplane.ZAtPoint(bpos.xy));
|
|
int numpt = Random[ExploS](0,2);
|
|
numpt *= int(clamp((apos-bpos).length()/32,1,8));
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
double d = FRandom[ExploS](0.,1.);
|
|
Vector3 ppos = bpos*d+apos*(1.-d)+(0,0,FRandom[ExploS](1,4));
|
|
Vector3 rpos = ppos-pos;
|
|
A_SpawnParticle("88 AA FF",SPF_FULLBRIGHT,Random[ExploS](120,240),FRandom[ExploS](2.,4.),0,rpos.x,rpos.y,rpos.z,FRandom[ExploS](-.3,.3),FRandom[ExploS](-.3,.3),FRandom[ExploS](-.3,.3),0,0,FRandom[ExploS](.05,.1),FRandom[ExploS](.15,.3),-1,FRandom[ExploS](-.02,-.01));
|
|
}
|
|
}
|
|
}
|
|
|
|
Class SWWMTeleportFog : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
+NOGRAVITY;
|
|
+NOBLOCKMAP;
|
|
+DONTSPLASH;
|
|
+NOINTERACTION;
|
|
+FORCEXYBILLBOARD;
|
|
Radius .1;
|
|
Height 0.;
|
|
FloatBobPhase 0;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
A_StartSound("misc/teleport",CHAN_VOICE);
|
|
Spawn("TeleLight",pos);
|
|
if ( swwm_simplefog ) SetStateLabel("Simple");
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
TNT1 A 1
|
|
{
|
|
int numpt = int(Random[ExploS](6,12)*alpha);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](.3,8)*alpha;
|
|
let s = Spawn("SWWMSmallSmoke",pos);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(1,2,3)*int(Random[ExploS](64,85)*alpha));
|
|
s.A_SetRenderStyle(s.alpha,STYLE_AddShaded);
|
|
s.scale *= 3.*alpha;
|
|
s.alpha *= alpha;
|
|
}
|
|
numpt = int(Random[ExploS](4,8));
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
double ang = FRandom[ExploS](0,360);
|
|
double pt = FRandom[ExploS](-90,90);
|
|
double dist = (FRandom[ExploS](5,10)+60*(1.-alpha));
|
|
if ( LineTrace(ang,dist,pt,TRF_THRUACTORS|TRF_THRUHITSCAN) ) continue;
|
|
Vector3 ofs = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*dist;
|
|
Vector3 spos = level.Vec3Offset(pos,ofs);
|
|
let s = Spawn("SWWMTeleportSparkle",spos);
|
|
s.scale *= FRandom[ExploS](.8,1.2);
|
|
s.specialf1 = FRandom[ExploS](.93,.97);
|
|
s.specialf2 = FRandom[ExploS](.02,.04);
|
|
s.roll = FRandom[ExploS](0,360);
|
|
}
|
|
A_FadeOut(.07);
|
|
}
|
|
Wait;
|
|
Simple:
|
|
SPEX ABCDEFGHIJKLMNOPQRSTUVWXYZ[\] 1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class SWWMPickupFlash : Actor
|
|
{
|
|
Vector3 lastitempos;
|
|
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Args 0,3,2,1;
|
|
Radius .1;
|
|
Height 0;
|
|
+NOGRAVITY;
|
|
+NOBLOCKMAP;
|
|
+DONTSPLASH;
|
|
+ROLLSPRITE;
|
|
+ROLLCENTER;
|
|
+NOINTERACTION;
|
|
+FORCEXYBILLBOARD;
|
|
FloatBobPhase 0;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
frame = Args[0];
|
|
}
|
|
action void A_Sparkle()
|
|
{
|
|
// offset up
|
|
SetOrigin(Vec3Offset(0,0,16),false);
|
|
roll = FRandom[ExploS](0,360);
|
|
scale *= FRandom[ExploS](.9,1.1);
|
|
scale.x *= RandomPick[ExploS](-1,1);
|
|
scale.y *= RandomPick[ExploS](-1,1);
|
|
int numpt = Random[ExploS](8,10);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](.3,8);
|
|
let s = Spawn("SWWMSmallSmoke",pos);
|
|
s.vel = pvel;
|
|
s.SetShade(Color(Args[1],Args[2],Args[3])*Random[ExploS](64,85));
|
|
s.A_SetRenderStyle(s.alpha,STYLE_AddShaded);
|
|
s.scale *= 3.;
|
|
s.alpha *= .5;
|
|
}
|
|
}
|
|
action void A_Shimmer()
|
|
{
|
|
if ( !target || Inventory(target).Owner )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
if ( target.bINVISIBLE )
|
|
{
|
|
bINVISIBLE = true;
|
|
return;
|
|
}
|
|
else if ( bINVISIBLE ) bINVISIBLE = false;
|
|
// try to reduce calls to SetOrigin as much as possible, for performance
|
|
if ( target.pos != invoker.lastitempos ) SetOrigin(target.Vec3Offset(0,0,16),true);
|
|
invoker.lastitempos = target.pos;
|
|
if ( target.bFLOATBOB && !bFLOATBOB )
|
|
{
|
|
bFLOATBOB = true;
|
|
FloatBobStrength = target.FloatBobStrength;
|
|
FloatBobPhase = target.FloatBobPhase;
|
|
}
|
|
else if ( !target.bFLOATBOB && bFLOATBOB ) bFLOATBOB = false;
|
|
A_SetScale(FRandom[ClientSparkles](.9,1.1)*(max(target.radius,target.height)/16.));
|
|
alpha = FRandom[ClientSparkles](.9,1.)*clamp((max(0,Distance3DSquared(players[consoleplayer].Camera)-40000.)/160000000.)**.25,0.,1.);
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
BLPF # 0 Bright;
|
|
BLPF # 1 Bright A_Sparkle();
|
|
BLPF # 1 Bright A_FadeOut(.2);
|
|
Wait;
|
|
Pickup:
|
|
BLPS # 1 Bright A_Shimmer();
|
|
Wait;
|
|
}
|
|
}
|
|
Class SWWMPinkPickupFlash : SWWMPickupFlash
|
|
{
|
|
Default
|
|
{
|
|
Args 1,3,1,2;
|
|
}
|
|
}
|
|
Class SWWMCyanPickupFlash : SWWMPickupFlash
|
|
{
|
|
Default
|
|
{
|
|
Args 2,1,2,3;
|
|
}
|
|
}
|
|
Class SWWMGreenPickupFlash : SWWMPickupFlash
|
|
{
|
|
Default
|
|
{
|
|
Args 3,1,3,1;
|
|
}
|
|
}
|
|
Class SWWMBluePickupFlash : SWWMPickupFlash
|
|
{
|
|
Default
|
|
{
|
|
Args 4,1,1,3;
|
|
}
|
|
}
|
|
Class SWWMPurplePickupFlash : SWWMPickupFlash
|
|
{
|
|
Default
|
|
{
|
|
Args 5,2,1,3;
|
|
}
|
|
}
|
|
Class SWWMRedPickupFlash : SWWMPickupFlash
|
|
{
|
|
Default
|
|
{
|
|
Args 6,3,1,1;
|
|
}
|
|
}
|
|
Class SWWMWhitePickupFlash : SWWMPickupFlash
|
|
{
|
|
Default
|
|
{
|
|
Args 7,3,3,3;
|
|
}
|
|
}
|
|
|
|
// TODO very precise tiny fast projectiles using hitscan-based stepping (e.g.: bullets)
|
|
Class SWWMLightProjectile : Actor abstract {}
|
|
|
|
// Bullet trails from DT
|
|
Class WaterHit
|
|
{
|
|
Sector sect;
|
|
Vector3 hitpos;
|
|
}
|
|
|
|
Class InvisibleSplasher : Actor
|
|
{
|
|
Default
|
|
{
|
|
Mass 100;
|
|
VSpeed -2;
|
|
Radius 2;
|
|
Height 4;
|
|
+NOBLOCKMAP; // needed to prevent infinite loops with some 3D floor water (yes, you read that right)
|
|
FloatBobPhase 0;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
TNT1 A 2;
|
|
Stop;
|
|
}
|
|
}
|
|
Class SmolInvisibleSplasher : InvisibleSplasher
|
|
{
|
|
Default
|
|
{
|
|
Mass 5;
|
|
}
|
|
}
|
|
|
|
Class SWWMBulletTrail : LineTracer
|
|
{
|
|
Array<WaterHit> WaterHitList;
|
|
Array<Line> ShootThroughList;
|
|
Actor ignoreme;
|
|
|
|
static play void DoTrail( Actor target, Vector3 pos, Vector3 dir, double dist, int bubblechance, bool smoky = false )
|
|
{
|
|
let t = new("SWWMBulletTrail");
|
|
t.ignoreme = target;
|
|
t.WaterHitList.Clear();
|
|
t.ShootThroughList.Clear();
|
|
t.Trace(pos,level.PointInSector(pos.xy),dir,dist,0);
|
|
for ( int i=0; i<t.ShootThroughList.Size(); i++ )
|
|
{
|
|
// have to do both because WOW, HOW THE FUCK IS THIS INTENTIONAL???
|
|
t.ShootThroughList[i].Activate(target,0,SPAC_PCross);
|
|
t.ShootThroughList[i].Activate(target,0,SPAC_Impact);
|
|
}
|
|
for ( int i=0; i<t.WaterHitList.Size(); i++ )
|
|
{
|
|
let b = Actor.Spawn("InvisibleSplasher",t.WaterHitList[i].hitpos);
|
|
b.A_CheckTerrain();
|
|
}
|
|
for ( int i=5; i<t.Results.Distance; i+=10 )
|
|
{
|
|
if ( !Random[Boolet](0,bubblechance) ) continue;
|
|
let b = Actor.Spawn(smoky?"SWWMSmallSmoke":"SWWMBubble",level.Vec3Offset(pos,dir*i));
|
|
b.Scale *= FRandom[Boolet](.4,.6);
|
|
}
|
|
t.Destroy();
|
|
}
|
|
|
|
override ETraceStatus TraceCallback()
|
|
{
|
|
// liquid splashes
|
|
if ( Results.CrossedWater )
|
|
{
|
|
let hl = new("WaterHit");
|
|
hl.sect = Results.CrossedWater;
|
|
hl.hitpos = Results.CrossedWaterPos;
|
|
WaterHitList.Push(hl);
|
|
}
|
|
else if ( Results.Crossed3DWater )
|
|
{
|
|
let hl = new("WaterHit");
|
|
hl.sect = Results.Crossed3DWater;
|
|
hl.hitpos = Results.Crossed3DWaterPos;
|
|
WaterHitList.Push(hl);
|
|
}
|
|
if ( Results.HitType == TRACE_HitActor )
|
|
{
|
|
if ( Results.HitActor == ignoreme ) return TRACE_Skip;
|
|
if ( Results.HitActor.bSHOOTABLE ) return TRACE_Stop;
|
|
return TRACE_Skip;
|
|
}
|
|
else if ( (Results.HitType == TRACE_HitWall) && (Results.Tier == TIER_Middle) )
|
|
{
|
|
if ( !Results.HitLine.sidedef[1] || (Results.HitLine.Flags&(Line.ML_BlockHitscan|Line.ML_BlockEverything)) )
|
|
return TRACE_Stop;
|
|
ShootThroughList.Push(Results.HitLine);
|
|
return TRACE_Skip;
|
|
}
|
|
return TRACE_Stop;
|
|
}
|
|
}
|
|
|
|
// finds the first pickup-able item
|
|
Class SWWMItemTracer : LineTracer
|
|
{
|
|
override ETraceStatus TraceCallback()
|
|
{
|
|
if ( Results.HitType == TRACE_HitActor )
|
|
{
|
|
if ( (Results.HitActor is 'Inventory') && Results.HitActor.bSPECIAL ) return TRACE_Stop;
|
|
return TRACE_Skip;
|
|
}
|
|
else if ( (Results.HitType == TRACE_HitWall) && (Results.Tier == TIER_Middle) )
|
|
{
|
|
if ( !Results.HitLine.sidedef[1] || (Results.HitLine.Flags&(Line.ML_BlockUse|Line.ML_BlockEverything)) )
|
|
return TRACE_Stop;
|
|
return TRACE_Skip;
|
|
}
|
|
return TRACE_Stop;
|
|
}
|
|
}
|
|
|
|
// Blob shadows
|
|
Class SWWMShadow : Actor
|
|
{
|
|
Sector oldfloor;
|
|
|
|
static void Track( Actor other )
|
|
{
|
|
// prevent infinite recursion
|
|
if ( other is 'SWWMShadow' ) return;
|
|
// no shadows for overlay actors
|
|
if ( other is 'GhostArtifactX' ) return;
|
|
// no shadows for things with zero radius
|
|
if ( other.radius <= 0. ) return;
|
|
let s = SWWMShadow(Spawn("SWWMShadow",other.pos));
|
|
s.target = other;
|
|
s.Update(true);
|
|
}
|
|
private void Update( bool nointerpolate = false )
|
|
{
|
|
// update scale / alpha
|
|
if ( ((target is 'Inventory') && Inventory(target).Owner) || target.bKILLED || target.bINVISIBLE || (target.sprite == target.GetSpriteIndex('TNT1')) || (target.sprite == target.GetSpriteIndex('ACLO')) || (target.CurSector.GetTexture(0) == skyflatnum) )
|
|
alpha = 0.;
|
|
else
|
|
{
|
|
alpha = 1.-min(1.,.006*abs(target.pos.z-pos.z));
|
|
alpha *= target.alpha;
|
|
double relz = target.pos.z-pos.z;
|
|
if ( target.bFLOATBOB ) relz += target.GetBobOffset();
|
|
double bscale = (target.radius/16.)*(1.-min(1.,.003*relz));
|
|
// hax
|
|
if ( target is 'CompanionLamp' ) bscale *= 2.;
|
|
A_SetScale(bscale);
|
|
}
|
|
// update position
|
|
double curz = target.CurSector.NextLowestFloorAt(target.pos.x,target.pos.y,target.pos.z);
|
|
if ( (target.pos.xy == pos.xy) && (pos.z == curz) ) return;
|
|
SetOrigin((target.pos.x,target.pos.y,curz),true);
|
|
if ( nointerpolate )
|
|
prev = pos;
|
|
else if ( oldfloor != target.CurSector )
|
|
prev.z = pos.z; // prevent interpolation of steep height changes
|
|
// update slope alignment
|
|
if ( !oldfloor || (oldfloor != target.CurSector) )
|
|
SWWMUtility.SetToSlope(self,0);
|
|
oldfloor = target.CurSector;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( !target )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
Update();
|
|
}
|
|
default
|
|
{
|
|
RenderStyle "Shaded";
|
|
StencilColor "000000";
|
|
DistanceCheck 'swwm_shadowdist';
|
|
Radius .1;
|
|
Height 0.;
|
|
+NOBLOCKMAP;
|
|
+NOINTERACTION;
|
|
+DONTSPLASH;
|
|
+NOTELEPORT;
|
|
FloatBobPhase 0;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
// Terrain FX (cheap)
|
|
Class SWWMBaseSplash : Actor
|
|
{
|
|
default
|
|
{
|
|
Radius .1;
|
|
Height 0.;
|
|
+NOBLOCKMAP;
|
|
+NOINTERACTION;
|
|
+DONTSPLASH;
|
|
+NOTELEPORT;
|
|
FloatBobPhase 0;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
TNT1 A 1;
|
|
Stop;
|
|
}
|
|
}
|
|
Class SWWMWaterSplash : SWWMBaseSplash
|
|
{
|
|
override void PostBeginPlay()
|
|
{
|
|
double ang, pt, str;
|
|
Vector3 dir;
|
|
for ( int i=0; i<60; i++ )
|
|
{
|
|
ang = FRandom[ExploS](0,360);
|
|
pt = FRandom[ExploS](-90,-60);
|
|
dir = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt));
|
|
str = FRandom[ExploS](2.,12.);
|
|
dir *= str*.25;
|
|
dir.z += 1.;
|
|
A_SpawnParticle(SWWMUtility.LerpColor("40 60 FF","A0 C0 FF",FRandom[ExploS](0.,1.)),0,60,str,0,0,0,0,dir.x,dir.y,dir.z,0,0,-.03*str,.5,-1,-.02*str);
|
|
}
|
|
}
|
|
}
|
|
Class SWWMWaterSplash2 : SWWMBaseSplash
|
|
{
|
|
override void PostBeginPlay()
|
|
{
|
|
double ang, pt, str;
|
|
Vector3 dir;
|
|
for ( int i=0; i<15; i++ )
|
|
{
|
|
ang = FRandom[ExploS](0,360);
|
|
pt = FRandom[ExploS](-90,-30);
|
|
dir = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt));
|
|
str = FRandom[ExploS](1.,6.);
|
|
dir *= str*.25;
|
|
dir.z += .35;
|
|
A_SpawnParticle(SWWMUtility.LerpColor("40 60 FF","A0 C0 FF",FRandom[ExploS](0.,1.)),0,50,str,0,0,0,0,dir.x,dir.y,dir.z,0,0,-.03*str,.5,-1,-.02*str);
|
|
}
|
|
}
|
|
}
|
|
Class SWWMBloodSplash : SWWMBaseSplash
|
|
{
|
|
override void PostBeginPlay()
|
|
{
|
|
double ang, pt, str;
|
|
Vector3 dir;
|
|
for ( int i=0; i<60; i++ )
|
|
{
|
|
ang = FRandom[ExploS](0,360);
|
|
pt = FRandom[ExploS](-90,-60);
|
|
dir = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt));
|
|
str = FRandom[ExploS](2.,12.);
|
|
dir *= str*.25;
|
|
dir.z += 1.;
|
|
A_SpawnParticle(SWWMUtility.LerpColor("80 00 00","60 00 00",FRandom[ExploS](0.,1.)),0,60,str+.5,0,0,0,0,dir.x,dir.y,dir.z,0,0,-.03*str,.5,-1,-.02*str);
|
|
}
|
|
}
|
|
}
|
|
Class SWWMBloodSplash2 : SWWMBaseSplash
|
|
{
|
|
override void PostBeginPlay()
|
|
{
|
|
double ang, pt, str;
|
|
Vector3 dir;
|
|
for ( int i=0; i<15; i++ )
|
|
{
|
|
ang = FRandom[ExploS](0,360);
|
|
pt = FRandom[ExploS](-90,-30);
|
|
dir = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt));
|
|
str = FRandom[ExploS](1.,6.);
|
|
dir *= str*.25;
|
|
dir.z += .35;
|
|
A_SpawnParticle(SWWMUtility.LerpColor("80 00 00","60 00 00",FRandom[ExploS](0.,1.)),0,50,str+.5,0,0,0,0,dir.x,dir.y,dir.z,0,0,-.03*str,.5,-1,-.02*str);
|
|
}
|
|
}
|
|
}
|
|
Class SWWMSludgeSplash : SWWMBaseSplash
|
|
{
|
|
override void PostBeginPlay()
|
|
{
|
|
double ang, pt, str;
|
|
Vector3 dir;
|
|
for ( int i=0; i<60; i++ )
|
|
{
|
|
ang = FRandom[ExploS](0,360);
|
|
pt = FRandom[ExploS](-90,-60);
|
|
dir = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt));
|
|
str = FRandom[ExploS](2.,8.);
|
|
dir *= str*.25;
|
|
dir.z += .4;
|
|
A_SpawnParticle(SWWMUtility.LerpColor("40 50 40","30 30 30",FRandom[ExploS](0.,1.)),0,40,str+2.,0,0,0,0,dir.x,dir.y,dir.z,0,0,-.03*str,.8,-1,-.02*str);
|
|
}
|
|
}
|
|
}
|
|
Class SWWMSludgeSplash2 : SWWMBaseSplash
|
|
{
|
|
override void PostBeginPlay()
|
|
{
|
|
double ang, pt, str;
|
|
Vector3 dir;
|
|
for ( int i=0; i<15; i++ )
|
|
{
|
|
ang = FRandom[ExploS](0,360);
|
|
pt = FRandom[ExploS](-90,-30);
|
|
dir = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt));
|
|
str = FRandom[ExploS](1.,4.);
|
|
dir *= str*.25;
|
|
dir.z += .15;
|
|
A_SpawnParticle(SWWMUtility.LerpColor("40 50 40","30 30 30",FRandom[ExploS](0.,1.)),0,30,str+2.,0,0,0,0,dir.x,dir.y,dir.z,0,0,-.03*str,.8,-1,-.02*str);
|
|
}
|
|
}
|
|
}
|
|
Class SWWMMudSplash : SWWMBaseSplash
|
|
{
|
|
override void PostBeginPlay()
|
|
{
|
|
double ang, pt, str;
|
|
Vector3 dir;
|
|
for ( int i=0; i<60; i++ )
|
|
{
|
|
ang = FRandom[ExploS](0,360);
|
|
pt = FRandom[ExploS](-90,-60);
|
|
dir = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt));
|
|
str = FRandom[ExploS](2.,8.);
|
|
dir *= str*.25;
|
|
dir.z += .4;
|
|
A_SpawnParticle(SWWMUtility.LerpColor("50 40 20","30 20 10",FRandom[ExploS](0.,1.)),0,40,str+2.,0,0,0,0,dir.x,dir.y,dir.z,0,0,-.03*str,.8,-1,-.02*str);
|
|
}
|
|
}
|
|
}
|
|
Class SWWMMudSplash2 : SWWMBaseSplash
|
|
{
|
|
override void PostBeginPlay()
|
|
{
|
|
double ang, pt, str;
|
|
Vector3 dir;
|
|
for ( int i=0; i<15; i++ )
|
|
{
|
|
ang = FRandom[ExploS](0,360);
|
|
pt = FRandom[ExploS](-90,-30);
|
|
dir = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt));
|
|
str = FRandom[ExploS](1.,4.);
|
|
dir *= str*.25;
|
|
dir.z += .15;
|
|
A_SpawnParticle(SWWMUtility.LerpColor("50 40 20","30 20 10",FRandom[ExploS](0.,1.)),0,30,str+2.,0,0,0,0,dir.x,dir.y,dir.z,0,0,-.03*str,.8,-1,-.02*str);
|
|
}
|
|
}
|
|
}
|
|
Class SWWMSlimeSplash : SWWMBaseSplash
|
|
{
|
|
override void PostBeginPlay()
|
|
{
|
|
double ang, pt, str;
|
|
Vector3 dir;
|
|
for ( int i=0; i<60; i++ )
|
|
{
|
|
ang = FRandom[ExploS](0,360);
|
|
pt = FRandom[ExploS](-90,-60);
|
|
dir = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt));
|
|
str = FRandom[ExploS](2.,8.);
|
|
dir *= str*.25;
|
|
dir.z += .4;
|
|
A_SpawnParticle(SWWMUtility.LerpColor("00 FF 00","00 80 00",FRandom[ExploS](0.,1.)),SPF_FULLBRIGHT,40,str+2.,0,0,0,0,dir.x,dir.y,dir.z,0,0,-.03*str,.8,-1,-.02*str);
|
|
}
|
|
}
|
|
}
|
|
Class SWWMSlimeSplash2 : SWWMBaseSplash
|
|
{
|
|
override void PostBeginPlay()
|
|
{
|
|
double ang, pt, str;
|
|
Vector3 dir;
|
|
for ( int i=0; i<15; i++ )
|
|
{
|
|
ang = FRandom[ExploS](0,360);
|
|
pt = FRandom[ExploS](-90,-30);
|
|
dir = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt));
|
|
str = FRandom[ExploS](1.,4.);
|
|
dir *= str*.25;
|
|
dir.z += .15;
|
|
A_SpawnParticle(SWWMUtility.LerpColor("00 FF 00","00 80 00",FRandom[ExploS](0.,1.)),SPF_FULLBRIGHT,30,str+2.,0,0,0,0,dir.x,dir.y,dir.z,0,0,-.03*str,.8,-1,-.02*str);
|
|
}
|
|
}
|
|
}
|
|
Class SWWMLavaSplash : SWWMBaseSplash
|
|
{
|
|
override void PostBeginPlay()
|
|
{
|
|
double ang, pt, str;
|
|
Vector3 dir;
|
|
for ( int i=0; i<60; i++ )
|
|
{
|
|
ang = FRandom[ExploS](0,360);
|
|
pt = FRandom[ExploS](-90,-60);
|
|
dir = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt));
|
|
str = FRandom[ExploS](2.,12.);
|
|
dir *= str*.35;
|
|
dir.z += .6;
|
|
A_SpawnParticle(SWWMUtility.LerpColor("FF C0 40","FF 40 20",FRandom[ExploS](0.,1.)),SPF_FULLBRIGHT,40,str+1.,0,0,0,0,dir.x,dir.y,dir.z,0,0,-.03*str,.8,-1,-.02*str);
|
|
}
|
|
Spawn("SWWMSizzleSmoke",pos);
|
|
}
|
|
}
|
|
Class SWWMLavaSplash2 : SWWMBaseSplash
|
|
{
|
|
override void PostBeginPlay()
|
|
{
|
|
double ang, pt, str;
|
|
Vector3 dir;
|
|
for ( int i=0; i<15; i++ )
|
|
{
|
|
ang = FRandom[ExploS](0,360);
|
|
pt = FRandom[ExploS](-90,-30);
|
|
dir = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt));
|
|
str = FRandom[ExploS](1.,6.);
|
|
dir *= str*.35;
|
|
dir.z += .2;
|
|
A_SpawnParticle(SWWMUtility.LerpColor("FF C0 40","FF 40 20",FRandom[ExploS](0.,1.)),SPF_FULLBRIGHT,30,str+1.,0,0,0,0,dir.x,dir.y,dir.z,0,0,-.03*str,.8,-1,-.02*str);
|
|
}
|
|
Spawn("SWWMSizzleSmoke2",pos);
|
|
}
|
|
}
|
|
Class SWWMSizzleSmoke : SWWMBaseSplash
|
|
{
|
|
override void PostBeginPlay()
|
|
{
|
|
double ang, pt, str;
|
|
Vector3 dir;
|
|
for ( int i=0; i<2; i++ )
|
|
{
|
|
ang = FRandom[ExploS](0,360);
|
|
pt = FRandom[ExploS](-90,-30);
|
|
dir = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt));
|
|
str = FRandom[ExploS](.5,2.);
|
|
let s = Spawn("SWWMSmallSmoke",pos);
|
|
s.vel = dir*str+(0,0,.4);
|
|
s.SetShade(Color(1,1,1)*Random[ExploS](192,224));
|
|
s.scale *= 40.;
|
|
s.A_SetRenderStyle(s.alpha*.4,STYLE_AddShaded);
|
|
s.special1 = Random[ExploS](0,2);
|
|
}
|
|
}
|
|
}
|
|
Class SWWMSizzleSmoke2 : SWWMBaseSplash
|
|
{
|
|
override void PostBeginPlay()
|
|
{
|
|
double ang, pt, str;
|
|
Vector3 dir;
|
|
ang = FRandom[ExploS](0,360);
|
|
pt = FRandom[ExploS](-90,-30);
|
|
dir = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt));
|
|
str = FRandom[ExploS](.25,1.);
|
|
let s = Spawn("SWWMSmallSmoke",pos);
|
|
s.vel = dir*str+(0,0,.15);
|
|
s.SetShade(Color(1,1,1)*Random[ExploS](192,224));
|
|
s.scale *= 20.;
|
|
s.A_SetRenderStyle(s.alpha*.3,STYLE_AddShaded);
|
|
s.special1 = Random[ExploS](0,1);
|
|
}
|
|
}
|
|
|
|
// Hexen thing
|
|
Class SWWMCrushedSpike : Actor
|
|
{
|
|
Default
|
|
{
|
|
Radius 20;
|
|
Height 16;
|
|
+SOLID;
|
|
+FLOORCLIP;
|
|
+NOTELEPORT;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
TSPK X -1;
|
|
Stop;
|
|
}
|
|
}
|