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:
parent
4acd02d7b5
commit
5d51b18c3f
7 changed files with 339 additions and 431 deletions
|
|
@ -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 |
|
|
@ -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. )
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue