Rewrite physics of lightweight actors. Now using Linetrace-based approach.

Fix up: Moths shouldn't cast blob shadows, Lamp should cast them.
This commit is contained in:
Mari the Deer 2020-11-27 17:18:05 +01:00
commit 5d51b18c3f
7 changed files with 339 additions and 431 deletions

View file

@ -1,2 +1,2 @@
[default]
SWWM_MODVER="\chSWWM \czGZ\c- \cw0.9.11b-pre r644 \cu(Fri 27 Nov 14:23:13 CET 2020)";
SWWM_MODVER="\chSWWM \czGZ\c- \cw0.9.11b-pre r645 \cu(Fri 27 Nov 17:18:05 CET 2020)";

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Before After
Before After

View file

@ -122,7 +122,6 @@ Class mkBloodDrop : Actor
bool dead, onceiling;
mkBloodDrop prevblod, nextblod;
Sector tracksector;
Sector trackffloor; // can't use F3DFloor, blocks saving
int trackplane;
Default
@ -154,16 +153,8 @@ Class mkBloodDrop : Actor
if ( tracksector )
{
double trackz;
if ( trackffloor )
{
if ( trackplane ) trackz = trackffloor.floorplane.ZAtPoint(pos.xy)-.1;
else trackz = trackffloor.ceilingplane.ZAtPoint(pos.xy);
}
else
{
if ( trackplane ) trackz = tracksector.ceilingplane.ZAtPoint(pos.xy)-.1;
else trackz = tracksector.floorplane.ZAtPoint(pos.xy);
}
if ( trackplane ) trackz = tracksector.ceilingplane.ZAtPoint(pos.xy)-.1;
else trackz = tracksector.floorplane.ZAtPoint(pos.xy);
if ( trackz != pos.z )
{
SetZ(trackz);
@ -190,110 +181,96 @@ Class mkBloodDrop : Actor
}
else
{
FCheckPosition tm;
// gravitational pull
vel.z -= GetGravity();
// 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))||((pos.z!=floorz)&&(pos.z!=ceilingz-height));
if ( domove )
if ( waterlevel <= 0 ) vel.z -= GetGravity();
// linetrace-based movement (hopefully more reliable than traditional methods)
Vector3 dir = vel;
double spd = vel.length();
dir /= spd;
FLineTraceData d;
double ang = atan2(dir.y,dir.x);
double pt = asin(-dir.z);
LineTrace(ang,spd,pt,TRF_THRUACTORS|TRF_THRUHITSCAN,data:d);
if ( d.HitType == TRACE_HitFloor )
{
Vector3 steppy = vel/steps;
int changexy = steppy.X||steppy.Y;
for ( int i=0; i<steps; i++ )
if ( d.HitTexture == skyflatnum )
{
if ( changexy && !TryMove(Vec2Offset(steppy.x,steppy.y),1,false,tm) )
Destroy();
return;
}
// landed on floor
SetOrigin(d.HitLocation,true);
HitFloor();
A_StartSound("misc/blooddrop",volume:.1);
if ( master )
{
// assume we dropped onto the previous spot
if ( master.tracer )
{
let l = tm.CeilingLine;
if ( l && l.backsector && l.backsector.GetTexture(1) == skyflatnum )
{
let posr = PosRelative(l.backsector);
if ( pos.z >= l.backsector.ceilingplane.ZAtPoint(posr.xy) )
{
Destroy();
return;
}
}
// hit wall
Vector3 dir = vel.unit();
TraceBleedAngle(20,atan2(dir.y,dir.x),asin(-dir.z));
A_StartSound("misc/blooddrop",volume:.1);
Destroy();
return;
}
AddZ(steppy.z);
UpdateWaterLevel();
if ( pos.z <= floorz )
{
if ( floorpic == skyflatnum )
{
Destroy();
return;
}
// landed on floor
SetZ(floorz);
HitFloor();
A_StartSound("misc/blooddrop",volume:.1);
if ( master )
{
// assume we dropped onto the previous spot
if ( master.tracer )
{
Destroy();
return;
}
master.tracer = self;
}
dead = true;
SWWMUtility.SetToSlope(self,FRandom[Blood](0,360));
tracksector = FloorSector;
trackplane = 0;
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 ) trackffloor = ff.model;
frame = Random[Blood](5,8);
return;
}
if ( pos.z+height > ceilingz )
{
if ( (ceilingpic == skyflatnum) || master )
{
Destroy();
return;
}
// hit the ceiling
SetZ(ceilingz-.1);
A_StartSound("misc/blooddrop",volume:.1);
dead = true;
onceiling = true;
SWWMUtility.SetToSlope(self,FRandom[Blood](0,360),true);
tracksector = CeilingSector;
trackplane = 1;
F3DFloor ff;
for ( int i=0; i<CeilingSector.Get3DFloorCount(); i++ )
{
if ( !(CeilingSector.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(CeilingSector.Get3DFloor(i).bottom.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
ff = CeilingSector.Get3DFloor(i);
break;
}
if ( ff ) trackffloor = ff.model;
frame = Random[Blood](5,8);
special1 = Random[Blood](15,25);
special2 = 0;
return;
}
CheckPortalTransition();
master.tracer = self;
}
dead = true;
if ( d.Hit3DFloor )
{
tracksector = d.Hit3DFloor.model;
trackplane = 1;
}
else
{
tracksector = d.HitSector;
trackplane = 0;
}
SWWMUtility.SetToSlope(self,FRandom[Blood](0,360));
frame = Random[Blood](5,8);
return;
}
if ( d.HitType == TRACE_HitCeiling )
{
if ( (d.HitTexture == skyflatnum) || master )
{
Destroy();
return;
}
// hit the ceiling
SetOrigin(d.HitLocation-(0,0,1),true);
A_StartSound("misc/blooddrop",volume:.1);
dead = true;
onceiling = true;
if ( d.Hit3DFloor )
{
tracksector = d.Hit3DFloor.model;
trackplane = 0;
}
else
{
tracksector = d.HitSector;
trackplane = 1;
}
SWWMUtility.SetToSlope(self,FRandom[Blood](0,360),true);
frame = Random[Blood](5,8);
return;
}
if ( d.HitType == TRACE_HitWall )
{
if ( d.HitLine.backsector && (d.HitLine.backsector.GetTexture(1) == skyflatnum) && (d.HitLocation.z >= d.HitLine.backsector.ceilingplane.ZAtPoint(d.HitLocation.xy)) )
{
Destroy();
return;
}
// hit wall
Vector2 walldir = (-d.HitLine.delta.y,d.HitLine.delta.x).unit();
if ( d.LineSide ) walldir *= -1;
SetOrigin(d.HitLocation-walldir*8,true);
TraceBleedAngle(20,atan2(walldir.y,walldir.x),0);
A_StartSound("misc/blooddrop",volume:.1);
Destroy();
return;
}
SetOrigin(level.Vec3Offset(pos,vel),true);
UpdateWaterLevel();
if ( waterlevel > 0 ) A_FadeOut();
scale *= .99;
if ( scale.x <= 0. )

View file

@ -16,7 +16,7 @@ enum ESWWMGZChannels
};
// Future planning, will be filled out with AI stuff and whatnot someday
Class SWWMMonster : Actor
Class SWWMMonster : Actor abstract
{
// integrated fun tags
virtual clearscope String GetFunTag( String defstr = "" )
@ -239,73 +239,54 @@ Class SWWMSmoke : Actor
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 )
// 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;
int nstep = 0;
while ( dist > 0 )
{
Vector3 steppy = vel/steps;
int changexy = steppy.X||steppy.Y;
bool readjust = false;
for ( int i=0; i<steps; i++ )
// safeguard, too many bounces
if ( nstep > MAXBOUNCEPERTIC )
{
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
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;
}
dist -= d.Distance;
if ( d.HitType != TRACE_HitNone )
{
// 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+hitnormal;
}
else newpos = level.Vec3Offset(newpos,dir*spd);
nstep++;
}
SetOrigin(newpos,true);
UpdateWaterLevel();
if ( (waterlevel > 0) && !bAMBUSH )
{
let b = Spawn("SWWMBubble",pos);
@ -490,73 +471,53 @@ Class SWWMBubble : Actor
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 )
// 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;
int nstep = 0;
while ( dist > 0 )
{
Vector3 steppy = vel/steps;
int changexy = steppy.X||steppy.Y;
bool readjust = false;
for ( int i=0; i<steps; i++ )
// safeguard, too many bounces
if ( nstep > MAXBOUNCEPERTIC )
{
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
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;
}
dist -= d.Distance;
if ( d.HitType != TRACE_HitNone )
{
// 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+hitnormal;
}
else newpos = level.Vec3Offset(newpos,dir*spd);
nstep++;
}
SetOrigin(newpos,true);
UpdateWaterLevel();
if ( (waterlevel <= 0) || !Random[Puff](0,100) ) Destroy();
if ( tics > 0 ) tics--;
@ -606,109 +567,83 @@ Class SWWMSpark : Actor
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);
}
if ( trackz != pos.z ) SetZ(trackz);
}
}
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 )
// 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;
int nstep = 0;
while ( dist > 0 )
{
Vector3 steppy = vel/steps;
int changexy = steppy.X||steppy.Y;
bool readjust = false;
for ( int i=0; i<steps; i++ )
// safeguard, too many bounces
if ( nstep > MAXBOUNCEPERTIC )
{
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
Destroy();
return;
}
}
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++ )
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 ( !(FloorSector.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(FloorSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = FloorSector.Get3DFloor(i);
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;
}
dist -= d.Distance;
if ( d.HitType != TRACE_HitNone )
{
// 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+hitnormal;
}
else newpos = level.Vec3Offset(newpos,dir*spd);
if ( (spd < 1.) && (d.HitType == TRACE_HitFloor) )
{
// lose speed and die
if ( d.Hit3DFloor )
{
newpos.z = d.Hit3DFloor.top.ZAtPoint(newpos.xy);
tracksector = d.Hit3DFloor.model;
trackplane = 1;
}
else
{
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;
}
if ( ff )
{
tracksector = ff.model;
trackplane = 1;
}
else
{
tracksector = FloorSector;
trackplane = 0;
}
vel = (0,0,0);
dead = true;
SetStateLabel("Death");
return;
nstep++;
}
SetOrigin(newpos,true);
}
UpdateWaterLevel();
if ( waterlevel > 0 )
@ -797,109 +732,86 @@ Class SWWMChip : Actor
}
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 )
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;
int nstep = 0;
while ( dist > 0 )
{
Vector3 steppy = vel/steps;
int changexy = steppy.X||steppy.Y;
bool readjust = false;
for ( int i=0; i<steps; i++ )
// safeguard, too many bounces
if ( nstep > MAXBOUNCEPERTIC )
{
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
}
Destroy();
return;
}
}
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++ )
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 ( !(FloorSector.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(FloorSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = FloorSector.Get3DFloor(i);
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;
}
dist -= d.Distance;
if ( d.HitType != TRACE_HitNone )
{
// 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+hitnormal;
}
else newpos = level.Vec3Offset(newpos,dir*spd);
if ( (spd < 1.) && (d.HitType == TRACE_HitFloor) )
{
// lose speed and die
if ( d.Hit3DFloor )
{
newpos.z = d.Hit3DFloor.top.ZAtPoint(newpos.xy);
tracksector = d.Hit3DFloor.model;
trackplane = 1;
}
else
{
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;
}
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;
nstep++;
}
SetOrigin(newpos,true);
UpdateWaterLevel();
}
if ( killme ) A_FadeOut(.01);
if ( waterlevel > 0 )
{
vel *= .98;
anglevel *= .98;
pitchvel *= .98;
rollvel *= .98;
}
if ( !CheckNoDelay() || (tics == -1) ) return;
@ -1326,6 +1238,8 @@ Class SWWMShadow : Actor
double relz = target.pos.z-pos.z;
if ( target.bFLOATBOB ) relz += BobSin(target.FloatBobPhase)*target.FloatBobStrength;
double bscale = (target.radius/16.)*(1.-min(1.,.003*relz));
// hax
if ( target is 'CompanionLamp' ) bscale *= 2.;
A_SetScale(bscale);
}
// update position

View file

@ -1531,7 +1531,7 @@ Class SWWMHandler : EventHandler
}
if ( !swwm_notrack && (e.Thing.bSHOOTABLE || e.Thing.bISMONSTER) && !(e.Thing is 'LampMoth') && !(e.Thing is 'CompanionLamp') )
SWWMCombatTracker.Spawn(e.Thing);
if ( e.Thing.bSHOOTABLE || e.Thing.bISMONSTER || e.Thing.bCORPSE || (e.Thing is 'Inventory') )
if ( !(e.Thing is 'LampMoth') && (e.Thing.bSHOOTABLE || e.Thing.bISMONSTER || e.Thing.bCORPSE || (e.Thing is 'Inventory') || (e.Thing is 'CompanionLamp')) )
{
if ( (swwm_shadows == 2) || ((swwm_shadows == 1) && ((e.Thing is 'Demolitionist') || (e.Thing.SpawnState.sprite == e.Thing.GetSpriteIndex('XZW1')))) )
SWWMShadow.Track(e.Thing);

View file

@ -1183,13 +1183,16 @@ Class LampMoth : Actor
}
Vector3 dest = target.Vec3Offset(0,0,target.height*.75);
Vector3 dir = level.Vec3Diff(pos,dest);
Vector3 dirunit = dir.unit();
FLineTraceData d;
LineTrace(atan2(dirunit.y,dirunit.x),dir.length(),asin(-dirunit.z),data:d);
if ( (d.HitType != TRACE_HitActor) && (d.HitActor != target) )
if ( dir.length() > 0 )
{
A_Chase();
return;
Vector3 dirunit = dir.unit();
FLineTraceData d;
LineTrace(atan2(dirunit.y,dirunit.x),dir.length(),asin(-dirunit.z),data:d);
if ( (d.HitType != TRACE_HitActor) && (d.HitActor != target) )
{
A_Chase();
return;
}
}
if ( vel.length() > 0 )
{
@ -1327,7 +1330,7 @@ Class LampMoth2 : LampMoth
}
}
Class LampMashiro : Actor abstract
Class LampMashiro : SWWMMonster abstract
{
//
// ~nothing here yet, but she will make an appearance someday~
@ -1414,7 +1417,9 @@ Class CompanionLamp : Actor
Vector3 ofs = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*dist;
Vector3 spawnpos = level.Vec3Offset(Vec3Offset(0,0,height/2),ofs);
if ( !level.IsPointInLevel(spawnpos) ) return;
let m = LampMoth(Spawn(Random[Moth](0,9)?"LampMoth":"LampMoth2",spawnpos));
// higher chance of white moths if carrying the Mashiro plush
int mchance = parent.FindInventory("MothPlushy")?3:9;
let m = LampMoth(Spawn(Random[Moth](0,mchance)?"LampMoth":"LampMoth2",spawnpos));
if ( !m.TestMobjLocation() )
{
m.Destroy();
@ -1438,16 +1443,7 @@ Class CompanionLamp : Actor
Spawn("SWWMItemFog",pos);
Trail = pos;
}
// the stupidest thing ever, it's called BlockingLine but it's not always blocking us
private bool BlockingLineIsBlocking()
{
if ( !BlockingLine ) return false;
// one-sided
if ( !BlockingLine.sidedef[1] ) return true;
// blocks us
if ( BlockingLine.flags&(Line.ML_BLOCKING|Line.ML_BLOCKEVERYTHING) ) return true;
return false;
}
override void Tick()
{
Super.Tick();
@ -1472,7 +1468,7 @@ Class CompanionLamp : Actor
Line oldblockingline = blockingline;
Sector oldblockingfloor = blockingfloor, oldblockingceiling = blockingceiling;
SetOrigin(testpos,false);
if ( !TestMobjLocation() || BlockingLineIsBlocking() || BlockingFloor || BlockingCeiling )
if ( !TestMobjLocation() || SWWMUtility.BlockingLineIsBlocking(self,Line.ML_BLOCKING|Line.ML_BLOCKEVERYTHING) || BlockingFloor || BlockingCeiling )
{
SetOrigin(oldpos,false);
prev = oldprev;
@ -1523,7 +1519,7 @@ Class CompanionLamp : Actor
angle += Clamp(deltaangle(angle,AngleTo(parent)),-5.,5.);
vel *= .8;
bool blocked = false;
if ( BlockingLine && BlockingLineIsBlocking() )
if ( SWWMUtility.BlockingLineIsBlocking(self,Line.ML_BLOCKING|Line.ML_BLOCKEVERYTHING) )
{
// push away from wall
Vector3 normal = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit();

View file

@ -12,6 +12,7 @@ enum EDoExplosionFlags
};
const FallbackTag = "AWESOME IT'S PENIS"; // used on tag processing, please don't mind the actual string used)
const MaxBouncePerTic = 40; // maximum simultaneous bounces in one tic for a lightweight actor before we consider it's stuck
Class SWWMUtility
{
@ -892,6 +893,26 @@ Class SWWMUtility
if ( a is 'Ettin' ) return true;
return false;
}
// the stupidest thing ever, it's called BlockingLine but it's not always blocking us
static bool BlockingLineIsBlocking( Actor a, int blockflags = Line.ML_BLOCKEVERYTHING )
{
Line l = a.BlockingLine;
// not blocked
if ( !l ) return false;
// one-sided always blocking
if ( !l.sidedef[1] ) return true;
// same for block everything lines
if ( l.flags&blockflags ) return true;
// lower and upper bounds hit?
double afloor = l.frontsector.floorplane.ZAtPoint(a.pos.xy),
bfloor = l.backsector.floorplane.ZAtPoint(a.pos.xy),
aceil = l.frontsector.ceilingplane.ZAtPoint(a.pos.xy),
bceil = l.backsector.ceilingplane.ZAtPoint(a.pos.xy);
if ( (a.pos.z >= min(aceil,bceil)) || (a.pos.z <= max(afloor,bfloor)) )
return true;
return false;
}
}
Class RadiusDebugSphere : Actor