From 5d51b18c3f0c3b1c68e0122163af1f95fc782870 Mon Sep 17 00:00:00 2001 From: Marisa Kirisame Date: Fri, 27 Nov 2020 17:18:05 +0100 Subject: [PATCH] Rewrite physics of lightweight actors. Now using Linetrace-based approach. Fix up: Moths shouldn't cast blob shadows, Lamp should cast them. --- language.version | 2 +- models/extra/BlobShadow.png | Bin 3710 -> 3858 bytes zscript/swwm_blod.zsc | 189 ++++++------- zscript/swwm_common.zsc | 532 +++++++++++++++--------------------- zscript/swwm_handler.zsc | 2 +- zscript/swwm_powerup.zsc | 36 ++- zscript/swwm_utility.zsc | 21 ++ 7 files changed, 345 insertions(+), 437 deletions(-) diff --git a/language.version b/language.version index 1acb9e9d9..e1013fd29 100644 --- a/language.version +++ b/language.version @@ -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)"; diff --git a/models/extra/BlobShadow.png b/models/extra/BlobShadow.png index f1fd7252092973fc9c08bb421c68fef5435f4299..586249d9937330020170f05517f8fb94f265641e 100644 GIT binary patch literal 3858 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 GgeCx91w*m` literal 3710 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 K=d#Wzp$PyarU_dB diff --git a/zscript/swwm_blod.zsc b/zscript/swwm_blod.zsc index ac865edf7..0784f555e 100644 --- a/zscript/swwm_blod.zsc +++ b/zscript/swwm_blod.zsc @@ -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= 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 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= 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. ) diff --git a/zscript/swwm_common.zsc b/zscript/swwm_common.zsc index 63f893974..ad8f7a7b6 100644 --- a/zscript/swwm_common.zsc +++ b/zscript/swwm_common.zsc @@ -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 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 ceilingz ) - { - // hit the ceiling, slide along it - SetZ(ceilingz-height); - F3DFloor ff; - for ( int i=0; i 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 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 ceilingz ) - { - // hit the ceiling, slide along it - SetZ(ceilingz-height); - F3DFloor ff; - for ( int i=0; i 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 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 ceilingz ) - { - // hit the ceiling, bounce on it - SetZ(ceilingz-height); - F3DFloor ff; - for ( int i=0; i 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 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 ceilingz ) - { - // hit the ceiling, bounce on it - SetZ(ceilingz-height); - F3DFloor ff; - for ( int i=0; i 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 diff --git a/zscript/swwm_handler.zsc b/zscript/swwm_handler.zsc index dfb8d831a..f03d884b1 100644 --- a/zscript/swwm_handler.zsc +++ b/zscript/swwm_handler.zsc @@ -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); diff --git a/zscript/swwm_powerup.zsc b/zscript/swwm_powerup.zsc index 9ea2d1746..5e129d509 100644 --- a/zscript/swwm_powerup.zsc +++ b/zscript/swwm_powerup.zsc @@ -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(); diff --git a/zscript/swwm_utility.zsc b/zscript/swwm_utility.zsc index 6bb074f0f..1866b430e 100644 --- a/zscript/swwm_utility.zsc +++ b/zscript/swwm_utility.zsc @@ -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