swwmgz_m/zscript/swwm_common.zsc
Marisa Kirisame a8a74556a8 0.9.3b release:
- Add models for debris, akin to DT chunks.
 - Eviscerator chunks have a glow sprite like in DT.
 - Fix potential palette light crash under very special circumstances.
 - Double range of Ynykron altfire explosion.
 - Reduce Ynykron vortex lifetime (grows quicker), and reduce mass gain from kills by 40% (allows it to suck in a couple more enemies in hordes).
 - Adjust v-field compression formula for Ynykron vortex.
 - Reduce max blockmap iterator range of Ynykron vortex, should perform slightly better (maybe) on large maps.
 - Fix Ynykron altfire beam clipping through the world due to incorrect offsets.
 - Adjust Golden shell explosion propagation math.
 - Omnisight doesn't increase the item detection range (clutters screen too much).
 - The people have spoken, build only PK3 for releases from now on.
2020-09-20 15:05:43 +02:00

1167 lines
26 KiB
Text

// common code goes here
enum ESWWMGZChannels
{
CHAN_YOUDONEFUCKEDUP = 63200, // exception handler
CHAN_DEMOVOICE = 63201, // demolitionist voices
CHAN_FOOTSTEP = 63202, // footstep sounds and others
CHAN_WEAPONEXTRA = 63203, // additional weapon sounds (usually loops)
CHAN_POWERUP = 63204, // powerup sounds
CHAN_POWERUPEXTRA = 63205, // additional powerup sounds
CHAN_JETPACK = 63206, // jetpack sound
CHAN_ITEMEXTRA = 63207, // additional item sounds
CHAN_WEAPONEXTRA2 = 63208, // additional weapon sound slot
CHAN_WEAPONEXTRA3 = 63209, // additional weapon sound slot (again)
CHAN_DAMAGE = 63210, // used for impact/hit sounds
CHAN_AMBEXTRA = 63211 // player ambience when submerged
};
// Future planning, will be filled out with AI stuff and whatnot someday
Class SWWMMonster : Actor
{
virtual clearscope String GetFunTag( String defstr = "" )
{
return GetTag(defstr);
}
}
// imitates UE1 light type LT_TexturePaletteOnce/LT_TexturePaletteLoop
Class PaletteLight : DynamicLight
{
Color pal[256];
bool IsLooping;
Default
{
Tag "Explosion";
DynamicLight.Type "Point";
Args 0,0,0,80;
ReactionTime 15;
}
private void UpdateLight()
{
int index = clamp(255-((255*ReactionTime)/abs(default.ReactionTime)),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();
int lump = Wads.CheckNumForFullname(String.Format("palettes/%s.pal",GetTag()));
String paldat = Wads.ReadLump(lump);
for ( int i=0; i<256; i++ )
{
pal[i].r = paldat.ByteAt(i*3);
pal[i].g = paldat.ByteAt(i*3+1);
pal[i].b = paldat.ByteAt(i*3+2);
}
if ( ReactionTime < 0 )
{
ReactionTime = -ReactionTime;
IsLooping = true;
}
UpdateLight();
}
override void Tick()
{
Super.Tick();
if ( isFrozen() ) return;
ReactionTime--;
if ( ReactionTime < 0 )
{
if ( !IsLooping )
{
Destroy();
return;
}
else ReactionTime = abs(default.ReactionTime);
}
if ( target ) SetOrigin(target.pos,true);
UpdateLight();
}
}
// Generic smoke, lightweight tick
Class SWWMSmoke : Actor
{
Default
{
RenderStyle "Shaded";
StencilColor "FFFFFF";
Radius 2;
Height 2;
+NOBLOCKMAP;
+NOGRAVITY;
+DONTSPLASH;
+FORCEXYBILLBOARD;
+ROLLSPRITE;
+ROLLCENTER;
+THRUACTORS;
+NOTELEPORT;
+NOINTERACTION;
Scale .3;
}
override void PostBeginPlay()
{
double ang, pt;
scale *= FRandom[Puff](.5,1.5);
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);
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;
FCheckPosition tm;
// movement subdivision (these damn things are tiny)
int steps = 8;
while ( (abs(vel.x) >= radius*steps) || (abs(vel.y) >= radius*steps) || (abs(vel.z) >= height*steps) )
steps++;
bool domove = (vel!=(0,0,0));
if ( domove )
{
Vector3 steppy = vel/steps;
int changexy = steppy.X||steppy.Y;
bool readjust = false;
for ( int i=0; i<steps; i++ )
{
if ( changexy && !TryMove(Vec2Offset(steppy.x,steppy.y),1,false,tm) )
{
// hit wall, slide along it
if ( BlockingLine )
{
Vector3 normal = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit();
if ( !SWWMUtility.PointOnLineSide(pos.xy,BlockingLine) )
normal *= -1;
vel = vel-FRandom[Puff](1.,1.2)*normal*(vel dot normal);
}
readjust = true;
}
AddZ(steppy.z);
UpdateWaterLevel();
if ( pos.z <= floorz )
{
// landed on floor, slide along it
SetZ(floorz);
F3DFloor ff;
for ( int i=0; i<FloorSector.Get3DFloorCount(); i++ )
{
if ( !(FloorSector.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(FloorSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = FloorSector.Get3DFloor(i);
break;
}
Vector3 normal;
if ( ff ) normal = -ff.model.ceilingplane.Normal;
else normal = FloorSector.floorplane.Normal;
vel = vel-FRandom[Puff](1.,1.2)*normal*(vel dot normal);
readjust = true;
}
if ( pos.z+height > ceilingz )
{
// hit the ceiling, slide along it
SetZ(ceilingz-height);
F3DFloor ff;
for ( int i=0; i<CeilingSector.Get3DFloorCount(); i++ )
{
if ( !(CeilingSector.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(CeilingSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
ff = CeilingSector.Get3DFloor(i);
break;
}
Vector3 normal;
if ( ff ) normal = -ff.model.floorplane.Normal;
else normal = CeilingSector.ceilingplane.Normal;
vel = vel-FRandom[Puff](1.,1.2)*normal*(vel dot normal);
readjust = true;
}
CheckPortalTransition();
if ( readjust ) break; // movement changed, can't keep stepping
}
}
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 0.1;
Height 0;
+NOBLOCKMAP;
+NOGRAVITY;
+DONTSPLASH;
+FORCEXYBILLBOARD;
+ROLLSPRITE;
+ROLLCENTER;
+NOTELEPORT;
+NOINTERACTION;
Scale 0.3;
}
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);
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;
}
}
// visual smoke, very strictly non-interacting, updates even when game is frozen
Class SWWMViewSmoke : SWWMHalfSmoke
{
Vector3 ofs, vvel;
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);
vvel += (cos(pt)*cos(ang),cos(pt)*sin(ang),-sin(pt))*FRandom[Puff](0.04,0.16);
}
override void Tick()
{
prev = pos; // for interpolation
if ( !target || !target.player )
{
Destroy();
return;
}
Vector3 x, y, z;
[x, y, z] = swwm_CoordUtil.GetAxes(target.pitch,target.angle,target.roll);
Vector3 origin = level.Vec3Offset(target.Vec2OffsetZ(0,0,target.player.viewz),x*ofs.x+y*ofs.y+z*ofs.z);
SetOrigin(origin,true);
UpdateWaterLevel();
bInvisible = (players[consoleplayer].camera != target);
ofs += vvel;
vvel *= 0.96;
vvel.z += 0.01;
if ( (waterlevel > 0) && !bAMBUSH ) Destroy();
if ( tics > 0 ) tics--;
while ( !tics )
{
if ( !SetState(CurState.NextState) )
return;
}
}
}
Class SWWMBubble : Actor
{
Default
{
RenderStyle "Add";
Radius 2;
Height 2;
+NOBLOCKMAP;
+NOGRAVITY;
+DONTSPLASH;
+FORCEXYBILLBOARD;
+NOTELEPORT;
+THRUACTORS;
+NOINTERACTION;
Scale 0.5;
}
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;
FCheckPosition tm;
// movement subdivision (these damn things are tiny)
int steps = 8;
while ( (abs(vel.x) >= radius*steps) || (abs(vel.y) >= radius*steps) || (abs(vel.z) >= height*steps) )
steps++;
bool domove = (vel!=(0,0,0));
if ( domove )
{
Vector3 steppy = vel/steps;
int changexy = steppy.X||steppy.Y;
bool readjust = false;
for ( int i=0; i<steps; i++ )
{
if ( changexy && !TryMove(Vec2Offset(steppy.x,steppy.y),1,false,tm) )
{
// hit wall, slide along it
if ( BlockingLine )
{
Vector3 normal = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit();;
if ( !SWWMUtility.PointOnLineSide(pos.xy,BlockingLine) )
normal *= -1;
vel = vel-FRandom[Puff](1.,1.2)*normal*(vel dot normal);
}
readjust = true;
}
AddZ(steppy.z);
UpdateWaterLevel();
if ( pos.z <= floorz )
{
// landed on floor, slide along it
SetZ(floorz);
F3DFloor ff;
for ( int i=0; i<FloorSector.Get3DFloorCount(); i++ )
{
if ( !(FloorSector.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(FloorSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = FloorSector.Get3DFloor(i);
break;
}
Vector3 normal;
if ( ff ) normal = -ff.model.ceilingplane.Normal;
else normal = FloorSector.floorplane.Normal;
vel = vel-FRandom[Puff](1.,1.2)*normal*(vel dot normal);
readjust = true;
}
if ( pos.z+height > ceilingz )
{
// hit the ceiling, slide along it
SetZ(ceilingz-height);
F3DFloor ff;
for ( int i=0; i<CeilingSector.Get3DFloorCount(); i++ )
{
if ( !(CeilingSector.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(CeilingSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
ff = CeilingSector.Get3DFloor(i);
break;
}
Vector3 normal;
if ( ff ) normal = -ff.model.floorplane.Normal;
else normal = CeilingSector.ceilingplane.Normal;
vel = vel-FRandom[Puff](1.,1.2)*normal*(vel dot normal);
readjust = true;
}
CheckPortalTransition();
if ( readjust ) break; // movement changed, can't keep stepping
}
}
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 SWWMSpark : Actor
{
bool dead;
Sector tracksector;
int trackplane;
Default
{
RenderStyle "Add";
Radius 2;
Height 2;
+NOBLOCKMAP;
+FORCEXYBILLBOARD;
+THRUACTORS;
+NOTELEPORT;
+DONTSPLASH;
+NOINTERACTION;
Gravity 0.2;
Scale 0.05;
}
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);
UpdateWaterLevel(false);
}
}
}
else
{
vel.z -= GetGravity();
FCheckPosition tm;
// movement subdivision (these damn things are tiny)
int steps = 8;
while ( (abs(vel.x) >= radius*steps) || (abs(vel.y) >= radius*steps) || (abs(vel.z) >= height*steps) )
steps++;
bool domove = (vel!=(0,0,0));
if ( domove )
{
Vector3 steppy = vel/steps;
int changexy = steppy.X||steppy.Y;
bool readjust = false;
for ( int i=0; i<steps; i++ )
{
if ( changexy && !TryMove(Vec2Offset(steppy.x,steppy.y),1,false,tm) )
{
// hit wall, bounce on it
if ( BlockingLine )
{
Vector3 normal = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit();;
if ( !SWWMUtility.PointOnLineSide(pos.xy,BlockingLine) )
normal *= -1;
vel = .4*(vel-2.*normal*(vel dot normal));
}
readjust = true;
}
AddZ(steppy.z);
UpdateWaterLevel();
if ( pos.z <= floorz )
{
// landed on floor, bounce on it
SetZ(floorz);
F3DFloor ff;
for ( int i=0; i<FloorSector.Get3DFloorCount(); i++ )
{
if ( !(FloorSector.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(FloorSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = FloorSector.Get3DFloor(i);
break;
}
Vector3 normal;
if ( ff ) normal = -ff.model.ceilingplane.Normal;
else normal = FloorSector.floorplane.Normal;
vel = .4*(vel-2.*normal*(vel dot normal));
readjust = true;
}
if ( pos.z+height > ceilingz )
{
// hit the ceiling, bounce on it
SetZ(ceilingz-height);
F3DFloor ff;
for ( int i=0; i<CeilingSector.Get3DFloorCount(); i++ )
{
if ( !(CeilingSector.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(CeilingSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
ff = CeilingSector.Get3DFloor(i);
break;
}
Vector3 normal;
if ( ff ) normal = -ff.model.floorplane.Normal;
else normal = CeilingSector.ceilingplane.Normal;
vel = .4*(vel-2.*normal*(vel dot normal));
readjust = true;
}
CheckPortalTransition();
if ( readjust ) break; // movement changed, can't keep stepping
}
}
if ( (max(abs(vel.x),max(abs(vel.y),abs(vel.z))) < 1.) && (pos.z <= floorz) )
{
SetZ(floorz);
F3DFloor ff;
for ( int i=0; i<FloorSector.Get3DFloorCount(); i++ )
{
if ( !(FloorSector.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(FloorSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = FloorSector.Get3DFloor(i);
break;
}
if ( ff )
{
tracksector = ff.model;
trackplane = 1;
}
else
{
tracksector = FloorSector;
trackplane = 0;
}
vel = (0,0,0);
dead = true;
SetStateLabel("Death");
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 2;
Height 2;
+NOBLOCKMAP;
+THRUACTORS;
+NOTELEPORT;
+DONTSPLASH;
+INTERPOLATEANGLES;
+ROLLSPRITE;
+ROLLCENTER;
+FORCEXYBILLBOARD;
+NOINTERACTION;
Gravity 0.35;
Scale 0.2;
}
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
{
vel.z -= GetGravity();
FCheckPosition tm;
// movement subdivision (these damn things are tiny)
int steps = 8;
while ( (abs(vel.x) >= radius*steps) || (abs(vel.y) >= radius*steps) || (abs(vel.z) >= height*steps) )
steps++;
bool domove = (vel!=(0,0,0));
if ( domove )
{
Vector3 steppy = vel/steps;
int changexy = steppy.X||steppy.Y;
bool readjust = false;
for ( int i=0; i<steps; i++ )
{
if ( changexy && !TryMove(Vec2Offset(steppy.x,steppy.y),1,false,tm) )
{
// hit wall, bounce on it
if ( BlockingLine )
{
Vector3 normal = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit();;
if ( !SWWMUtility.PointOnLineSide(pos.xy,BlockingLine) )
normal *= -1;
vel = .3*(vel-2.*normal*(vel dot normal));
}
readjust = true;
}
AddZ(steppy.z);
UpdateWaterLevel();
if ( pos.z <= floorz )
{
// landed on floor, bounce on it
SetZ(floorz);
F3DFloor ff;
for ( int i=0; i<FloorSector.Get3DFloorCount(); i++ )
{
if ( !(FloorSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = FloorSector.Get3DFloor(i);
break;
}
Vector3 normal;
if ( ff ) normal = -ff.model.ceilingplane.Normal;
else normal = FloorSector.floorplane.Normal;
vel = .3*(vel-2.*normal*(vel dot normal));
readjust = true;
}
if ( pos.z+height > ceilingz )
{
// hit the ceiling, bounce on it
SetZ(ceilingz-height);
F3DFloor ff;
for ( int i=0; i<CeilingSector.Get3DFloorCount(); i++ )
{
if ( !(CeilingSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
ff = CeilingSector.Get3DFloor(i);
break;
}
Vector3 normal;
if ( ff ) normal = -ff.model.floorplane.Normal;
else normal = CeilingSector.ceilingplane.Normal;
vel = .3*(vel-2.*normal*(vel dot normal));
readjust = true;
}
CheckPortalTransition();
if ( readjust )
{
SetStateLabel("Bounce");
break; // movement changed, can't keep stepping
}
}
}
if ( (max(abs(vel.x),max(abs(vel.y),abs(vel.z))) < 1.) && (pos.z <= floorz) )
{
SetZ(floorz);
F3DFloor ff;
for ( int i=0; i<FloorSector.Get3DFloorCount(); i++ )
{
if ( !(FloorSector.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(FloorSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = FloorSector.Get3DFloor(i);
break;
}
if ( ff )
{
tracksector = ff.model;
trackplane = 1;
}
else
{
tracksector = FloorSector;
trackplane = 0;
}
vel = (0,0,0);
pitch = 0;
roll = 0;
dead = true;
SetStateLabel("Death");
return;
}
}
if ( killme ) A_FadeOut(.01);
if ( waterlevel > 0 )
{
vel *= .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 SWWMNothing : Actor
{
States
{
Spawn:
TNT1 A 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";
+NOGRAVITY;
+NOBLOCKMAP;
+DONTSPLASH;
+ROLLSPRITE;
+ROLLCENTER;
+NOINTERACTION;
}
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 0.1;
Height 0;
+NOGRAVITY;
+NOBLOCKMAP;
+DONTSPLASH;
+ROLLSPRITE;
+ROLLCENTER;
+FORCEXYBILLBOARD;
+NOINTERACTION;
}
override void Tick()
{
if ( isFrozen() ) return;
A_SetScale(scale.x*specialf1);
A_FadeOut(specialf2);
}
States
{
Spawn:
BLPF C -1 Bright;
Stop;
}
}
Class SWWMTeleportFog : Actor
{
Default
{
RenderStyle "Add";
+NOGRAVITY;
+NOBLOCKMAP;
+DONTSPLASH;
+NOINTERACTION;
+FORCEXYBILLBOARD;
Radius .1;
Height 0.;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
SetOrigin(Vec3Offset(0,0,28),false);
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;
}
}
// Bullet trails from DT
Class WaterHit
{
Sector sect;
Vector3 hitpos;
}
Class InvisibleSplasher : Actor
{
Default
{
Mass 100;
VSpeed -2;
Radius 2;
Radius 2;
+NOBLOCKMAP; // needed to prevent infinite loops with some 3D floor water (yes, you read that right)
}
States
{
Spawn:
TNT1 A 2;
Stop;
}
}
Class SmolInvisibleSplasher : InvisibleSplasher
{
Default
{
Mass 10;
}
}
Class SWWMBulletTrail : LineTracer
{
Array<WaterHit> WaterHitList;
Array<Line> ShootThroughList;
Actor ignoreme;
static play void DoTrail( Actor target, Vector3 pos, Vector3 dir, int 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++ )
{
t.ShootThroughList[i].Activate(target,0,SPAC_PCross);
if ( t.ShootThroughList[i].special == GlassBreak ) // fuck glass
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;
}
}
// Elastic recoil from DT (unused)
Enum ESwingMode
{
SWING_Straight, // constant increment
SWING_Spring, // bounces back after a delay
};
Class Swinger : Thinker
{
Actor target;
Vector2 dir;
double inc, rmul;
int steps, mode, delay;
double str, tstr;
int cnt, cstate;
Enum ESwingerState
{
STATE_Initial,
STATE_Wait,
STATE_Return,
};
override void Tick()
{
if ( !target ) cstate = -1;
switch ( cstate )
{
case STATE_Initial:
target.A_SetAngle(target.angle+dir.x*str,SPF_INTERPOLATE);
target.A_SetPitch(target.pitch+dir.y*str,SPF_INTERPOLATE);
str += inc;
if ( ++cnt >= steps )
{
cnt = 0;
str = tstr/steps;
cstate = (mode==SWING_Straight)?(-1):(delay>0)?STATE_Wait:STATE_Return;
}
else tstr += str;
break;
case STATE_Wait:
if ( ++cnt >= delay )
{
cnt = 0;
cstate = STATE_Return;
}
break;
case STATE_Return:
target.A_SetAngle(target.angle-dir.x*(str/rmul),SPF_INTERPOLATE);
target.A_SetPitch(target.pitch-dir.y*(str/rmul),SPF_INTERPOLATE);
if ( ++cnt >= steps*rmul )
{
cnt = 0;
cstate = -1;
}
break;
default:
Destroy();
return;
}
}
static void DoSwing( Actor target, Vector2 dir, double initial, double inc, int steps, int mode = 0, int delay = 0, double rmul = 1.0 )
{
let s = new("Swinger");
s.ChangeStatNum(Thinker.STAT_USER);
s.target = target;
s.dir = dir;
s.inc = inc;
s.rmul = rmul;
s.steps = steps;
s.mode = mode;
s.delay = delay;
s.cnt = 0;
s.cstate = 0;
s.str = initial;
s.tstr = initial;
}
}