From 01bdd8a7da8e204fc6f2115071213ff446c893ae Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <coelckers@zdoom.fake>
Date: Wed, 24 Feb 2016 01:06:48 +0100
Subject: [PATCH] - actor transition through a sector portal is working.

---
 src/actor.h       |  1 +
 src/p_mobj.cpp    | 40 ++++++++++++++++++++++++++++++++++++++++
 src/r_utility.cpp | 27 +++++++++++++++++++++++++--
 3 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/src/actor.h b/src/actor.h
index 35afef397..47f6ef44b 100644
--- a/src/actor.h
+++ b/src/actor.h
@@ -742,6 +742,7 @@ public:
 	bool IsHostile (AActor *other);
 
 	inline bool IsNoClip2() const;
+	void CheckPortalTransition();
 
 	// What species am I?
 	virtual FName GetSpecies();
diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp
index 7228ffbff..73683824b 100644
--- a/src/p_mobj.cpp
+++ b/src/p_mobj.cpp
@@ -3288,6 +3288,43 @@ void AActor::SetRoll(angle_t r, bool interpolate)
 	}
 }
 
+
+void AActor::CheckPortalTransition()
+{
+	if (!Sector->PortalBlocksMovement(sector_t::ceiling))
+	{
+		AActor *port = Sector->SkyBoxes[sector_t::ceiling];
+		if (Z() > port->threshold)
+		{
+			fixedvec3 oldpos = Pos();
+			UnlinkFromWorld();
+			SetXYZ(PosRelative(port->Sector));
+			PrevX += X() - oldpos.x;
+			PrevY += Y() - oldpos.y;
+			PrevZ += Z() - oldpos.z;
+			LinkToWorld();
+			if (player) Printf("Transitioned upwards to sector %d\n", Sector->sectornum);
+			return;
+		}
+	}
+	if (!Sector->PortalBlocksMovement(sector_t::floor))
+	{
+		AActor *port = Sector->SkyBoxes[sector_t::floor];
+		if (Z() < port->threshold && floorz < port->threshold)
+		{
+			fixedvec3 oldpos = Pos();
+			UnlinkFromWorld();
+			SetXYZ(PosRelative(port->Sector));
+			PrevX += X() - oldpos.x;
+			PrevY += Y() - oldpos.y;
+			PrevZ += Z() - oldpos.z;
+			LinkToWorld();
+			if (player) Printf("Transitioned downwards to sector %d\n", Sector->sectornum);
+			return;
+		}
+	}
+}
+
 //
 // P_MobjThinker
 //
@@ -3355,6 +3392,7 @@ void AActor::Tick ()
 		UnlinkFromWorld ();
 		flags |= MF_NOBLOCKMAP;
 		SetXYZ(Vec3Offset(velx, vely, velz));
+		CheckPortalTransition();
 		SetMovement(velx, vely, velz);
 		LinkToWorld ();
 	}
@@ -3822,6 +3860,8 @@ void AActor::Tick ()
 			Crash();
 		}
 
+		CheckPortalTransition();
+
 		UpdateWaterLevel (oldz);
 
 		// [RH] Don't advance if predicting a player
diff --git a/src/r_utility.cpp b/src/r_utility.cpp
index 10a39ba57..60a415d80 100644
--- a/src/r_utility.cpp
+++ b/src/r_utility.cpp
@@ -581,8 +581,11 @@ void R_InterpolateView (player_t *player, fixed_t frac, InterpolationViewer *ivi
 		iview->oviewpitch = iview->nviewpitch;
 		iview->oviewangle = iview->nviewangle;
 	}
-	viewx = iview->oviewx + FixedMul (frac, iview->nviewx - iview->oviewx);
-	viewy = iview->oviewy + FixedMul (frac, iview->nviewy - iview->oviewy);
+	int oldgroup = R_PointInSubsector(iview->oviewx, iview->oviewy)->sector->PortalGroup;
+	int newgroup = R_PointInSubsector(iview->nviewx, iview->nviewy)->sector->PortalGroup;
+	fixedvec2 disp = Displacements(oldgroup, newgroup);
+	viewx = iview->oviewx + FixedMul (frac, iview->nviewx - iview->oviewx - disp.x);
+	viewy = iview->oviewy + FixedMul (frac, iview->nviewy - iview->oviewy - disp.y);
 	viewz = iview->oviewz + FixedMul (frac, iview->nviewz - iview->oviewz);
 	if (player != NULL &&
 		!(player->cheats & CF_INTERPVIEW) &&
@@ -637,6 +640,26 @@ void R_InterpolateView (player_t *player, fixed_t frac, InterpolationViewer *ivi
 	
 	// Due to interpolation this is not necessarily the same as the sector the camera is in.
 	viewsector = R_PointInSubsector(viewx, viewy)->sector;
+	if (!viewsector->PortalBlocksMovement(sector_t::ceiling))
+	{
+		AActor *point = viewsector->SkyBoxes[sector_t::ceiling];
+		if (viewz > point->threshold)
+		{
+			viewx += point->scaleX;
+			viewy += point->scaleY;
+			viewsector = R_PointInSubsector(viewx, viewy)->sector;
+		}
+	}
+	if (!viewsector->PortalBlocksMovement(sector_t::floor))
+	{
+		AActor *point = viewsector->SkyBoxes[sector_t::floor];
+		if (viewz < point->threshold)
+		{
+			viewx += point->scaleX;
+			viewy += point->scaleY;
+			viewsector = R_PointInSubsector(viewx, viewy)->sector;
+		}
+	}
 }
 
 //==========================================================================