# HG changeset patch
# User Ru5tK1ng
# Date 1706218385 21600
#      Thu Jan 25 15:33:05 2024 -0600
# Branch sharekeyfixes
# Node ID d06fd92e796b36c72788b3d084154e4aba050995
# Parent  f46ab13b972a3a2ffbd7baf2e88c43a1828ce7af
Fixed: ShareKeys was not working properly with dehacked keys, with puzzle items, in hubs and would ignore losekeys when maps didn't reset in survival (addresses 4183).

diff -r f46ab13b972a -r d06fd92e796b docs/zandronum-history.txt
--- a/docs/zandronum-history.txt	Fri Sep 29 08:23:34 2023 -0400
+++ b/docs/zandronum-history.txt	Thu Jan 25 15:33:05 2024 -0600
@@ -114,6 +114,7 @@
 -	- Fixed: the coop info wasn't getting drawn in clientside demos. [Kaminsky]
 -	- Fixed: Floatbob items having incorrect z-height after a map reset and glitchy GL floor clipping (addresses 2361). [Ru5tK1ng]
 -	- Fixed: Monsters spawned by BossBrain cubes would move before being spawned on the clients therefore triggering warning messages (addresses 2655). [Ru5tK1ng]
+-   - Fixed: ShareKeys was not working properly with dehacked keys, with puzzle items, in hubs and would ignore losekeys when maps didn't reset in survival (addresses 4183). [Ru5tK1ng]
 !	- The result value of GAMEEVENT_MEDALS event scripts can now be used to determine whether or not the player receives the medal. [Kaminsky]
 !	- GAMEMODE flags are now validated after all GAMEMODE lumps have been parsed instead of after each one. The internal game mode name (e.g. "TeamLMS") is now printed with the error message instead of the actual name. [Kaminsky]
 !	- Added an extra check to ensure that game modes have a (short) name. [Kaminsky]
diff -r f46ab13b972a -r d06fd92e796b src/d_dehacked.cpp
--- a/src/d_dehacked.cpp	Fri Sep 29 08:23:34 2023 -0400
+++ b/src/d_dehacked.cpp	Thu Jan 25 15:33:05 2024 -0600
@@ -3197,3 +3197,8 @@
 	Super::Serialize(arc);
 	arc << droppedbymonster;
 }
+
+AInventory* ADehackedPickup::GetRealPickup()
+{
+		return RealPickup;
+}
\ No newline at end of file
diff -r f46ab13b972a -r d06fd92e796b src/d_dehacked.h
--- a/src/d_dehacked.h	Fri Sep 29 08:23:34 2023 -0400
+++ b/src/d_dehacked.h	Thu Jan 25 15:33:05 2024 -0600
@@ -54,6 +54,8 @@
 	AInventory *RealPickup;
 public:
 	bool droppedbymonster;
+// [RK] Accessor
+	AInventory* GetRealPickup();
 };
 
 int D_LoadDehLumps();
diff -r f46ab13b972a -r d06fd92e796b src/d_player.h
--- a/src/d_player.h	Fri Sep 29 08:23:34 2023 -0400
+++ b/src/d_player.h	Thu Jan 25 15:33:05 2024 -0600
@@ -679,6 +679,9 @@
 	// This player is currently spectating after dying in LMS or survival co-op.
 	bool		bDeadSpectator;
 
+	// [RK] This is set when a dead spectator is revived through SetDeadSpectator.
+	bool		bDeadSpectatorKeySync;
+
 	// [BB] Number of times the player may still respawn in LMS or survival co-op.
 	ULONG		ulLivesLeft;
 
diff -r f46ab13b972a -r d06fd92e796b src/g_level.cpp
--- a/src/g_level.cpp	Fri Sep 29 08:23:34 2023 -0400
+++ b/src/g_level.cpp	Thu Jan 25 15:33:05 2024 -0600
@@ -1306,7 +1306,9 @@
 		teamplay = false;
 
 	// [Dusk] Clear keys found
-	g_keysFound.Clear();
+	// [RK] Since PuzzleItems are tracked don't do this for hubs.
+	if( !( level.clusterflags & CLUSTER_HUB ) || autosave == false ) // Resets with map command
+		g_keysFound.Clear();
 
 	// [BC] In server mode, display the level name slightly differently.
 	if ( NETWORK_GetState( ) == NETSTATE_SERVER )
diff -r f46ab13b972a -r d06fd92e796b src/g_shared/a_pickups.cpp
--- a/src/g_shared/a_pickups.cpp	Fri Sep 29 08:23:34 2023 -0400
+++ b/src/g_shared/a_pickups.cpp	Thu Jan 25 15:33:05 2024 -0600
@@ -34,6 +34,7 @@
 #include "cooperative.h"
 #include "p_acs.h"
 #include "a_keys.h"
+#include "d_dehacked.h"
 
 static FRandom pr_restore ("RestorePos");
 
@@ -1088,6 +1089,7 @@
 void AInventory::Touch (AActor *toucher)
 {
 	AInventory	*pInventory;
+	ADehackedPickup *realitem = NULL;
 
 	// [BC] If this item was a bot's goal item, and it's reaching it, let the bot know that.
 	if ( toucher->player && toucher->player->pSkullBot )
@@ -1212,7 +1214,12 @@
 	}
 
 	// [RH] Execute an attached special (if any)
-	DoPickupSpecial (toucher);
+	// [RK] Do the special later for Dehacked pickups since it
+	// destorys the real pickup which we'll need for a bit more
+	if( GetClass()->IsDescendantOf( RUNTIME_CLASS( ADehackedPickup )))
+		realitem = static_cast< ADehackedPickup* >(this);
+	else
+		DoPickupSpecial (toucher);
 
 	// [BC] If this item was spawned from an invasion spot, tell the spot that the item
 	// it spawned has been picked up.
@@ -1268,16 +1275,22 @@
 	// we store the key as having been found even if shared keys is off. This
 	// way the server still remembers what keys were found and begins sharing
 	// them when sv_sharekeys is toggled on.
-	if (( NETWORK_GetState( ) == NETSTATE_SERVER ) &&
-		( IsKindOf( RUNTIME_CLASS( AKey ))) &&
-		( toucher->player != NULL ))
+	if (( NETWORK_GetState( ) == NETSTATE_SERVER ) && (toucher->player != NULL) &&
+		( IsKindOf( RUNTIME_CLASS( AKey )) ||
+		GetClass()->ActorInfo->GetReplacee()->Class->IsDescendantOf( RUNTIME_CLASS( AKey )) || // [RK] Dehacked item replaces this class
+		GetClass()->IsDescendantOf( RUNTIME_CLASS( APuzzleItem )))) // Hexen Puzzle items
 	{
 		// [Dusk] Check if the key has not been picked up yet.
 		bool pickedup = false;
 
 		for ( unsigned int i = 0; i < g_keysFound.Size(); ++i )
 		{
-			if ( g_keysFound[i] == GetClass()->getActorNetworkIndex() )
+			if( realitem != NULL && g_keysFound[i] == realitem->GetRealPickup()->GetClass()->getActorNetworkIndex() )
+			{
+					pickedup = true;
+					break;
+				}
+			else if ( g_keysFound[i] == GetClass()->getActorNetworkIndex() )
 			{
 				pickedup = true;
 				break;
@@ -1289,13 +1302,17 @@
 			// [Dusk] Store this key as having been found. For some reason
 			// storing the raw PClass pointer crashes Zandronum when sharing
 			// the keys later on so we store the actor network index instead.
-			g_keysFound.Push( GetClass()->getActorNetworkIndex() );
+			// [RK] For DEHACKED pickups we'll use the real pickup's index
+			if ( realitem != NULL)
+				g_keysFound.Push( realitem->GetRealPickup()->GetClass()->getActorNetworkIndex( ) );
+			else
+				g_keysFound.Push( GetClass()->getActorNetworkIndex() );
 
 			if ( zadmflags & ZADF_SHARE_KEYS )
 			{
 				// [Dusk] Announcement message
-				SERVER_Printf( TEXTCOLOR_GREEN "%s" TEXTCOLOR_NORMAL " has found the " TEXTCOLOR_GOLD "%s!\n",
-					toucher->player->userinfo.GetName(), GetTag() );
+				SERVER_Printf(TEXTCOLOR_GREEN "%s" TEXTCOLOR_NORMAL " has found the " TEXTCOLOR_GOLD "%s!\n",
+					toucher->player->userinfo.GetName(), (realitem ? realitem->GetRealPickup()->GetTag() : GetTag( )));
 
 				// [Dusk] Audio cue - skip the player picking the key because he
 				// hears the pickup sound from the original key. The little *bloop*
@@ -1311,6 +1328,8 @@
 			}
 		}
 	}
+	if (realitem != NULL)
+		DoPickupSpecial(toucher);
 }
 
 //===========================================================================
diff -r f46ab13b972a -r d06fd92e796b src/p_acs.cpp
--- a/src/p_acs.cpp	Fri Sep 29 08:23:34 2023 -0400
+++ b/src/p_acs.cpp	Thu Jan 25 15:33:05 2024 -0600
@@ -7310,6 +7310,7 @@
 					// [BB] Revive the player.
 					players[ulPlayer].bSpectating = false;
 					players[ulPlayer].bDeadSpectator = false;
+					players[ulPlayer].bDeadSpectatorKeySync = true; // [RK] Allow to sync the keys.
 					if ( GAMEMODE_GetCurrentFlags() & GMF_USEMAXLIVES )
 						PLAYER_SetLivesLeft ( &players[ulPlayer], GAMEMODE_GetMaxLives() - 1 );
 					players[ulPlayer].playerstate = ( zadmflags & ZADF_DEAD_PLAYERS_CAN_KEEP_INVENTORY ) ? PST_REBORN : PST_REBORNNOINVENTORY;
diff -r f46ab13b972a -r d06fd92e796b src/p_mobj.cpp
--- a/src/p_mobj.cpp	Fri Sep 29 08:23:34 2023 -0400
+++ b/src/p_mobj.cpp	Thu Jan 25 15:33:05 2024 -0600
@@ -5682,13 +5682,15 @@
 
 		// [Dusk] If we are sharing keys, give this player the keys that have been found.
 		// [AK] Make sure to give them the keys if they changed their class.
+		// [RK] Reviving dead spectators through ACS should sync keys if allowed. 
 		if (( flags & SPF_CLIENTUPDATE ) &&
 			( zadmflags & ZADF_SHARE_KEYS ) &&
 			( NETWORK_GetState( ) == NETSTATE_SERVER ) &&
-			( state == PST_ENTER || state == PST_ENTERNOINVENTORY || oldPlayerClass != p->CurrentPlayerClass ))
+			( state == PST_ENTER || state == PST_ENTERNOINVENTORY || ( !p->bDeadSpectator && state == PST_REBORNNOINVENTORY && p->bDeadSpectatorKeySync ) || oldPlayerClass != p->CurrentPlayerClass ))
 		{
 			SERVER_SyncSharedKeys( p - players, true );
 		}
+		p->bDeadSpectatorKeySync = false;
 	}
 
 	// setup gun psprite
diff -r f46ab13b972a -r d06fd92e796b src/survival.cpp
--- a/src/survival.cpp	Fri Sep 29 08:23:34 2023 -0400
+++ b/src/survival.cpp	Thu Jan 25 15:33:05 2024 -0600
@@ -274,7 +274,9 @@
 	SURVIVAL_SetState( SURVS_INPROGRESS );
 
 	// Share keys so that resurrected dead spectators can get them.
-	SERVER_SyncSharedKeys( MAXPLAYERS, false );
+	// [RK] Except if we're supposed to lose keys.
+	if( !( dmflags & DF_COOP_LOSE_INVENTORY) && !( dmflags & DF_COOP_LOSE_KEYS ))
+		SERVER_SyncSharedKeys( MAXPLAYERS, false );
 }
 
 void SURVIVAL_RestartMission( void )
