From 2f027504b6716f35739038eb3073fedc9c1a86d1 Mon Sep 17 00:00:00 2001
From: Teemu Piippo <crimsondusk64@gmail.com>
Date: Sat, 12 Sep 2015 04:47:49 +0300
Subject: [PATCH 1/3] Show sector action boundaries on the automap like line
 specials are.

---
 src/am_map.cpp                  | 154 +++++++++++++++++++++++++-------
 src/g_shared/a_sectoraction.cpp |  23 ++++-
 src/r_defs.h                    |   5 ++
 3 files changed, 148 insertions(+), 34 deletions(-)

diff --git a/src/am_map.cpp b/src/am_map.cpp
index 045d48589..3430d3182 100644
--- a/src/am_map.cpp
+++ b/src/am_map.cpp
@@ -2224,6 +2224,124 @@ bool AM_Check3DFloors(line_t *line)
 	return false;
 }
 
+// [TP] Check whether a sector can trigger a special that satisfies the provided function.
+// If found, specialptr and argsptr will be filled by the special and the arguments
+// If needUseActivated is true, the special must be activated by use.
+bool AM_checkSectorActions (sector_t *sector, bool (*function)(int, int *), int *specialptr, int **argsptr, bool needUseActivated)
+{
+	for (ASectorAction* action = sector->SecActTarget; action; action = barrier_cast<ASectorAction *>(action->tracer))
+	{
+		if ((action->IsActivatedByUse() || false == needUseActivated)
+			&& (*function)(action->special, action->args)
+			&& action->CanTrigger (players[consoleplayer].mo))
+		{
+			*specialptr = action->special;
+			*argsptr = action->args;
+			return true;
+		}
+	}
+
+	return false;
+}
+
+// [TP] Check whether there's a boundary on the provided line for a special that satisfies the provided function.
+// It's a boundary if the line can activate the special or the line's bordering sectors can activate it.
+// If found, specialptr and argsptr will be filled with special and args if given.
+bool AM_checkSpecialBoundary (line_t &line, bool (*function)(int, int*), int *specialptr = NULL, int **argsptr = NULL)
+{
+	if (specialptr == NULL)
+	{
+		static int sink;
+		specialptr = &sink;
+	}
+
+	if (argsptr == NULL)
+	{
+		static int* sink;
+		argsptr = &sink;
+	}
+
+	// Check if the line special qualifies for this
+	if ((*function)(line.special, line.args) && (line.activation & SPAC_PlayerActivate))
+	{
+		*specialptr = line.special;
+		*argsptr = line.args;
+		return true;
+	}
+
+	// Check sector actions in the line's front sector -- the action has to be use-activated in order to
+	// show up if this is a one-sided line, because the player cannot trigger sector actions by crossing
+	// a one-sided line (since that's impossible, duh).
+	if (AM_checkSectorActions(line.frontsector, function, specialptr, argsptr, line.backsector == NULL))
+		return true;
+
+	// If it has a back sector, check sector actions in that.
+	return (line.backsector && AM_checkSectorActions(line.backsector, function, specialptr, argsptr, false));
+}
+
+bool AM_isTeleportSpecial (int special, int*)
+{
+	return (special == Teleport ||
+		special == Teleport_NoFog ||
+		special == Teleport_ZombieChanger ||
+		special == Teleport_Line);
+}
+
+bool AM_isTeleportBoundary (line_t& line)
+{
+	return AM_checkSpecialBoundary(line, &AM_isTeleportSpecial);
+}
+
+bool AM_isExitSpecial (int special, int*)
+{
+	return (special == Teleport_NewMap ||
+		 special == Teleport_EndGame ||
+		 special == Exit_Normal ||
+		 special == Exit_Secret);
+}
+
+bool AM_isExitBoundary (line_t& line)
+{
+	return AM_checkSpecialBoundary(line, &AM_isExitSpecial);
+}
+
+bool AM_isTriggerSpecial (int special, int*)
+{
+	return special != 0
+		&& special != Door_Open
+		&& special != Door_Close
+		&& special != Door_CloseWaitOpen
+		&& special != Door_Raise
+		&& special != Door_Animated
+		&& special != Generic_Door;
+}
+
+bool AM_isTriggerBoundary (line_t& line)
+{
+	return AM_checkSpecialBoundary(line, &AM_isTriggerSpecial);
+}
+
+bool AM_isLockSpecial (int special, int* args)
+{
+	return special == Door_LockedRaise ||
+		 special == ACS_LockedExecute ||
+		 special == ACS_LockedExecuteDoor ||
+		 (special == Door_Animated && args[3] != 0) ||
+		 (special == Generic_Door && args[4] != 0);
+}
+
+bool AM_isLockBoundary (line_t &line, int *lockptr = NULL)
+{
+	int special;
+	int *args;
+	bool result = AM_checkSpecialBoundary(line, &AM_isLockSpecial, &special, &args);
+
+	if (lockptr && result)
+		*lockptr = (special==Door_LockedRaise || special==Door_Animated) ? args[3] : args[4];
+
+	return result;
+}
+
 //=============================================================================
 //
 // Determines visible lines, draws them.
@@ -2283,37 +2401,18 @@ void AM_drawWalls (bool allmap)
 				
 				AM_drawMline (&l, c);
 			} 
-			else if ((lines[i].special == Teleport ||
-				lines[i].special == Teleport_NoFog ||
-				lines[i].special == Teleport_ZombieChanger ||
-				lines[i].special == Teleport_Line) &&
-				(lines[i].activation & SPAC_PlayerActivate) &&
-				AMColors.isValid(AMColors.IntraTeleportColor))
+			else if (AM_isTeleportBoundary(lines[i]) && AMColors.isValid(AMColors.IntraTeleportColor))
 			{ // intra-level teleporters
 				AM_drawMline(&l, AMColors.IntraTeleportColor);
 			}
-			else if ((lines[i].special == Teleport_NewMap ||
-					 lines[i].special == Teleport_EndGame ||
-					 lines[i].special == Exit_Normal ||
-					 lines[i].special == Exit_Secret) &&
-					 AMColors.isValid(AMColors.InterTeleportColor))
+			else if (AM_isExitBoundary(lines[i]) && AMColors.isValid(AMColors.InterTeleportColor))
 			{ // inter-level/game-ending teleporters
 				AM_drawMline(&l, AMColors.InterTeleportColor);
 			}
-			else if (lines[i].special == Door_LockedRaise ||
-					 lines[i].special == ACS_LockedExecute ||
-					 lines[i].special == ACS_LockedExecuteDoor ||
-					 (lines[i].special == Door_Animated && lines[i].args[3] != 0) ||
-					 (lines[i].special == Generic_Door && lines[i].args[4] != 0))
+			else if (AM_isLockBoundary(lines[i], &lock))
 			{
 				if (AMColors.displayLocks)
 				{
-					int P_GetMapColorForLock(int lock);
-
-					if (lines[i].special==Door_LockedRaise || lines[i].special==Door_Animated)
-						lock=lines[i].args[3];
-					else lock=lines[i].args[4];
-
 					color = P_GetMapColorForLock(lock);
 
 					AMColor c;
@@ -2328,14 +2427,9 @@ void AM_drawWalls (bool allmap)
 					AM_drawMline (&l, AMColors.LockedColor);  // locked special
 				}
 			}
-			else if (am_showtriggerlines && AMColors.isValid(AMColors.SpecialWallColor) && lines[i].special != 0
-				&& lines[i].special != Door_Open
-				&& lines[i].special != Door_Close
-				&& lines[i].special != Door_CloseWaitOpen
-				&& lines[i].special != Door_Raise
-				&& lines[i].special != Door_Animated
-				&& lines[i].special != Generic_Door
-				&& (lines[i].activation & SPAC_PlayerActivate))
+			else if (am_showtriggerlines
+				&& AMColors.isValid(AMColors.SpecialWallColor)
+				&& AM_isTriggerBoundary(lines[i]))
 			{
 				AM_drawMline(&l, AMColors.SpecialWallColor);	// wall with special non-door action the player can do
 			}
diff --git a/src/g_shared/a_sectoraction.cpp b/src/g_shared/a_sectoraction.cpp
index 570818e19..bb582dd28 100644
--- a/src/g_shared/a_sectoraction.cpp
+++ b/src/g_shared/a_sectoraction.cpp
@@ -39,6 +39,14 @@
 
 IMPLEMENT_CLASS (ASectorAction)
 
+ASectorAction::ASectorAction (bool activatedByUse) :
+	ActivatedByUse (activatedByUse) {}
+
+bool ASectorAction::IsActivatedByUse() const
+{
+	return ActivatedByUse;
+}
+
 void ASectorAction::Destroy ()
 {
 	// Remove ourself from this sector's list of actions
@@ -102,12 +110,17 @@ bool ASectorAction::DoTriggerAction (AActor *triggerer, int activationType)
 		return false;
 }
 
+bool ASectorAction::CanTrigger (AActor *triggerer) const
+{
+	return special &&
+		((triggerer->player && !(flags & MF_FRIENDLY)) ||
+		((flags & MF_AMBUSH) && (triggerer->flags2 & MF2_MCROSS)) ||
+		((flags2 & MF2_DORMANT) && (triggerer->flags2 & MF2_PCROSS)));
+}
+
 bool ASectorAction::CheckTrigger (AActor *triggerer) const
 {
-	if (special &&
-		((triggerer->player && !(flags & MF_FRIENDLY)) ||
-		 ((flags & MF_AMBUSH) && (triggerer->flags2 & MF2_MCROSS)) ||
-		 ((flags2 & MF2_DORMANT) && (triggerer->flags2 & MF2_PCROSS))))
+	if (CanTrigger(triggerer))
 	{
 		bool res = !!P_ExecuteSpecial(special, NULL, triggerer, false, args[0], args[1],
 			args[2], args[3], args[4]);
@@ -196,6 +209,7 @@ class ASecActUse : public ASectorAction
 {
 	DECLARE_CLASS (ASecActUse, ASectorAction)
 public:
+	ASecActUse() : ASectorAction (true) {}
 	bool DoTriggerAction (AActor *triggerer, int activationType);
 };
 
@@ -214,6 +228,7 @@ class ASecActUseWall : public ASectorAction
 {
 	DECLARE_CLASS (ASecActUseWall, ASectorAction)
 public:
+	ASecActUseWall() : ASectorAction (true) {}
 	bool DoTriggerAction (AActor *triggerer, int activationType);
 };
 
diff --git a/src/r_defs.h b/src/r_defs.h
index afda92089..ff6957783 100644
--- a/src/r_defs.h
+++ b/src/r_defs.h
@@ -194,14 +194,19 @@ class ASectorAction : public AActor
 {
 	DECLARE_CLASS (ASectorAction, AActor)
 public:
+	ASectorAction (bool activatedByUse = false);
 	void Destroy ();
 	void BeginPlay ();
 	void Activate (AActor *source);
 	void Deactivate (AActor *source);
 	bool TriggerAction(AActor *triggerer, int activationType);
+	bool CanTrigger (AActor *triggerer) const;
+	bool IsActivatedByUse() const;
 protected:
 	virtual bool DoTriggerAction(AActor *triggerer, int activationType);
 	bool CheckTrigger(AActor *triggerer) const;
+private:
+	bool ActivatedByUse;
 };
 
 class ASkyViewpoint;

From 67a7f48ca3cdd8c6e83a58c27dba6fd3f31fbbac Mon Sep 17 00:00:00 2001
From: Teemu Piippo <crimsondusk64@gmail.com>
Date: Sat, 12 Sep 2015 14:02:07 +0300
Subject: [PATCH 2/3] Handle locknumber in boundary checks, check for
 FS_Execute

---
 src/am_map.cpp | 56 +++++++++++++++++++++++++++++++++-----------------
 1 file changed, 37 insertions(+), 19 deletions(-)

diff --git a/src/am_map.cpp b/src/am_map.cpp
index 3430d3182..279deb8a4 100644
--- a/src/am_map.cpp
+++ b/src/am_map.cpp
@@ -2323,21 +2323,50 @@ bool AM_isTriggerBoundary (line_t& line)
 
 bool AM_isLockSpecial (int special, int* args)
 {
-	return special == Door_LockedRaise ||
-		 special == ACS_LockedExecute ||
-		 special == ACS_LockedExecuteDoor ||
-		 (special == Door_Animated && args[3] != 0) ||
-		 (special == Generic_Door && args[4] != 0);
+	return special == Door_LockedRaise
+		 || special == ACS_LockedExecute
+		 || special == ACS_LockedExecuteDoor
+		 || (special == Door_Animated && args[3] != 0)
+		 || (special == Generic_Door && args[4] != 0)
+		 || (special == FS_Execute && args[2] != 0);
 }
 
 bool AM_isLockBoundary (line_t &line, int *lockptr = NULL)
 {
+	if (lockptr == NULL)
+	{
+		static int sink;
+		lockptr = &sink;
+	}
+
+	if (line.locknumber)
+	{
+		*lockptr = line.locknumber;
+		return true;
+	}
+
 	int special;
 	int *args;
 	bool result = AM_checkSpecialBoundary(line, &AM_isLockSpecial, &special, &args);
 
-	if (lockptr && result)
-		*lockptr = (special==Door_LockedRaise || special==Door_Animated) ? args[3] : args[4];
+	if (result)
+	{
+		switch (special)
+		{
+		case FS_Execute:
+			*lockptr = args[2];
+			break;
+
+		case Door_Animated:
+		case Door_LockedRaise:
+			*lockptr = args[3];
+			break;
+
+		default:
+			*lockptr = args[4];
+			break;
+		}
+	}
 
 	return result;
 }
@@ -2389,18 +2418,7 @@ void AM_drawWalls (bool allmap)
 					AM_drawMline(&l, AMColors.SecretWallColor);
 			    else
 					AM_drawMline(&l, AMColors.WallColor);
-			} 
-			else if (lines[i].locknumber > 0 && AMColors.displayLocks) 
-			{ // [Dusk] specials w/ locknumbers
-				lock = lines[i].locknumber;
-				color = P_GetMapColorForLock(lock);
-				
-				AMColor c;
-				if (color >= 0)	c.FromRGB(RPART(color), GPART(color), BPART(color));
-				else c = AMColors[AMColors.LockedColor];
-				
-				AM_drawMline (&l, c);
-			} 
+			}
 			else if (AM_isTeleportBoundary(lines[i]) && AMColors.isValid(AMColors.IntraTeleportColor))
 			{ // intra-level teleporters
 				AM_drawMline(&l, AMColors.IntraTeleportColor);

From 69fd0e6eb484fddd4a55333b4fa74377c6e0e992 Mon Sep 17 00:00:00 2001
From: Teemu Piippo <crimsondusk64@gmail.com>
Date: Sat, 12 Sep 2015 14:07:40 +0300
Subject: [PATCH 3/3] Stylistical coherence..

---
 src/am_map.cpp | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/am_map.cpp b/src/am_map.cpp
index 279deb8a4..16fd67111 100644
--- a/src/am_map.cpp
+++ b/src/am_map.cpp
@@ -2247,7 +2247,7 @@ bool AM_checkSectorActions (sector_t *sector, bool (*function)(int, int *), int
 // [TP] Check whether there's a boundary on the provided line for a special that satisfies the provided function.
 // It's a boundary if the line can activate the special or the line's bordering sectors can activate it.
 // If found, specialptr and argsptr will be filled with special and args if given.
-bool AM_checkSpecialBoundary (line_t &line, bool (*function)(int, int*), int *specialptr = NULL, int **argsptr = NULL)
+bool AM_checkSpecialBoundary (line_t &line, bool (*function)(int, int *), int *specialptr = NULL, int **argsptr = NULL)
 {
 	if (specialptr == NULL)
 	{
@@ -2257,7 +2257,7 @@ bool AM_checkSpecialBoundary (line_t &line, bool (*function)(int, int*), int *sp
 
 	if (argsptr == NULL)
 	{
-		static int* sink;
+		static int *sink;
 		argsptr = &sink;
 	}
 
@@ -2279,7 +2279,7 @@ bool AM_checkSpecialBoundary (line_t &line, bool (*function)(int, int*), int *sp
 	return (line.backsector && AM_checkSectorActions(line.backsector, function, specialptr, argsptr, false));
 }
 
-bool AM_isTeleportSpecial (int special, int*)
+bool AM_isTeleportSpecial (int special, int *)
 {
 	return (special == Teleport ||
 		special == Teleport_NoFog ||
@@ -2287,12 +2287,12 @@ bool AM_isTeleportSpecial (int special, int*)
 		special == Teleport_Line);
 }
 
-bool AM_isTeleportBoundary (line_t& line)
+bool AM_isTeleportBoundary (line_t &line)
 {
 	return AM_checkSpecialBoundary(line, &AM_isTeleportSpecial);
 }
 
-bool AM_isExitSpecial (int special, int*)
+bool AM_isExitSpecial (int special, int *)
 {
 	return (special == Teleport_NewMap ||
 		 special == Teleport_EndGame ||
@@ -2305,7 +2305,7 @@ bool AM_isExitBoundary (line_t& line)
 	return AM_checkSpecialBoundary(line, &AM_isExitSpecial);
 }
 
-bool AM_isTriggerSpecial (int special, int*)
+bool AM_isTriggerSpecial (int special, int *)
 {
 	return special != 0
 		&& special != Door_Open
@@ -2316,7 +2316,7 @@ bool AM_isTriggerSpecial (int special, int*)
 		&& special != Generic_Door;
 }
 
-bool AM_isTriggerBoundary (line_t& line)
+bool AM_isTriggerBoundary (line_t &line)
 {
 	return AM_checkSpecialBoundary(line, &AM_isTriggerSpecial);
 }