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 f1fd72520..586249d99 100644 Binary files a/models/extra/BlobShadow.png and b/models/extra/BlobShadow.png differ 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