#include "munga.h"
#pragma hdrstop

#include "player.h"
#include "icom.h"
#include "camship.h"
#include "dropzone.h"
#include "mission.h"
#include "audio.h"
#include "director.h"
#include "app.h"
#include "hostmgr.h"
#include "nttmgr.h"
#include "console.h"
#include "appmsg.h"

//#############################################################################
//#######################    Player::StatusMessage    #########################
//#############################################################################

Player__StatusMessage::Player__StatusMessage(Player *player_involved, int message_type, Scalar display_time)
{
	playerInvolved = player_involved;
	messageType = message_type;
	displayTime = display_time;
}

//#############################################################################
//###############################    Player    ################################
//#############################################################################

//#############################################################################
// Shared Data Support
//
Derivation* Player::GetClassDerivations()
{
	static Derivation classDerivations(Entity::GetClassDerivations(), "Player");
	return &classDerivations;
}

Player::SharedData
	Player::DefaultData(
		Player::GetClassDerivations(),
		Player::GetMessageHandlers(),
		Player::GetAttributeIndex(),
		Player::StateCount,
		(Entity::MakeHandler)Player::Make
	);

//#############################################################################
// Attribute Support
//

const Player::IndexEntry
	Player::AttributePointers[]=
{
	ATTRIBUTE_ENTRY(Player, CurrentScore, currentScore),
	ATTRIBUTE_ENTRY(Player, PlayerRanking, playerRanking),
	ATTRIBUTE_ENTRY(Player, DropZoneLocation, dropZoneLocation),
	ATTRIBUTE_ENTRY(Player, StatusMessagePointer,statusMessagePointer),
	ATTRIBUTE_ENTRY(Player, PlayerBitmapIndex, playerBitmapIndex),
	ATTRIBUTE_ENTRY(Player, PlayerHighlighted, playerHighlighted)
};

Player::AttributeIndexSet& Player::GetAttributeIndex()
{
	static Player::AttributeIndexSet attributeIndex(ELEMENTS(Player::AttributePointers),
		Player::AttributePointers,
		Entity::GetAttributeIndex()
	);
	return attributeIndex;
}

//#############################################################################
// Message Support
//
const Receiver::HandlerEntry
	Player::MessageHandlerEntries[]=
{
	MESSAGE_ENTRY(Player, DropZoneReply),
	MESSAGE_ENTRY(Player, Score),
	MESSAGE_ENTRY(Player, VehicleDead),
	MESSAGE_ENTRY(Player, MissionStarting),
	MESSAGE_ENTRY(Player, MissionEnding)
};

Receiver::MessageHandlerSet& Player::GetMessageHandlers()
{
	static Receiver::MessageHandlerSet messageHandlers(ELEMENTS(Player::MessageHandlerEntries), Player::MessageHandlerEntries, Entity::GetMessageHandlers());
	return messageHandlers;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Player::MissionStartingMessageHandler(Message *)
{
	Check(this);
	Tell("Player::MissionStartingMessageHandler - starting fade in\n");
	fadeTimeRemaining = 3.0f;
	SetSimulationState(MissionStartingState);
	Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Player::MissionEndingMessageHandler(Message *)
{
	Check(this);
	fadeTimeRemaining = 3.0f;
	ForceUpdate();
	SetSimulationState(MissionEndingState);
	Check_Fpu();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Enumeration
	Player::GetAudioRepresentation(
#if DEBUG_LEVEL>0
		Entity *linked_entity
#else
		Entity *
#endif
	)
{
	Check(this);
	Check(linked_entity);
	Check_Fpu();

	return
		(GetInstance() == MasterInstance) ?
			InternalAudioRepresentation : ExternalAudioRepresentation;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Player::ScoreMessageHandler(ScoreMessage        *message)
{
	Check(this);
	Check(message);

	currentScore += message->scoreAward;

	//
	// HACK - ECH 7/6/95 - Allow the player vehicle to respond to score
	// messages, allows attribute system to be used for scoring
	//
	Check(playerVehicle);
	playerVehicle->RespondToScoreMessage(message);
	Check_Fpu();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Player::DropZoneReplyMessageHandler(
		DropZone::ReplyMessage *		//message
	)
{
	Check(this);
	Fail("Drop zone reply should not be handled by base player class!\n");
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Player::CreatePlayerVehicle(Origin camera_origin)
{
	Check(this);
	//
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Create any MUNGA level vehicles
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	if (IsCameraShipPlayer())
	{
		Check(application);
		ResourceFile *resources = application->GetResourceFile();
		Check(resources);
		Check_Pointer(playerMission->GetGameModel());

		HostManager *host_manager = application->GetHostManager();
		Check(host_manager);
		ResourceDescription *camera_res =
			resources->FindResourceDescription(
				playerMission->GetGameModel(),
				ResourceDescription::ModelListResourceType
		);
		Check(camera_res);
		CameraShip::MakeMessage
			create_camera(
				CameraShip::MakeMessageID,
				sizeof(CameraShip::MakeMessage),
				EntityID(host_manager->GetLocalHostID()),
				CameraShipClassID,
				EntityID::Null,
				camera_res->resourceID,
				CameraShip::DefaultFlags,
				camera_origin,
				Motion::Identity,
				Motion::Identity
			);
		CameraShip *camera =
			(CameraShip*)application->MakeAndLinkViewpointEntity(&create_camera);
		Register_Object(camera);
		playerVehicle = camera;
	}
	Check_Fpu();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Player::VehicleDeadMessageHandler(VehicleDeadMessage *message)
{
	Check(this);
	Check(message);
	Check(application);


	//DEBUG_STREAM << "VEHICLEDEAD : " << endl << std::flush;

	//
	//-------------------------------------------------------------------------
	// If we have let the player fry, send a message to the dropzone to give us
	// a new location to return to
	//-------------------------------------------------------------------------
	//
	if (
		message->deathCount == deathCount
		 && GetSimulationState() != DropZoneAcquiredState)
	{
		DropZone *dropzone;



		//
		//---------------------------------------------------------------------
		// If no dropzone has been assigned to this death, find the closest one
		//---------------------------------------------------------------------
		//
		if (message->dropZoneID == EntityID::Null)
		{

			//DEBUG_STREAM << "                     Find Closest" << endl << std::flush;

			EntityManager *entity_manager = application->GetEntityManager();
			Check(entity_manager);
			EntityGroup *dropzones = entity_manager->FindGroup("DropZones");
			Check(dropzones);
			ChainIteratorOf<Node*> iterator(dropzones->groupMembers);

			DropZone *closest_dropzone;
			Vector3D range;
			Scalar closest_range;

			while ((dropzone = (DropZone*)iterator.ReadAndNext()) != NULL)
			{
				Check(dropzone);

				if (!strnicmp(dropzone->GetDropZoneName(), "win", 3))
				{
					continue;
				}

				closest_dropzone = dropzone;
				range.Subtract(
					localOrigin.linearPosition,
					dropzone->localOrigin.linearPosition
				);
				closest_range = range.LengthSquared();
				break;
			}

			while ((dropzone = (DropZone*)iterator.ReadAndNext()) != NULL)
			{
				Check(dropzone);
				if (!strnicmp(dropzone->GetDropZoneName(), "win", 3))
				{
					continue;
				}
				range.Subtract(
					localOrigin.linearPosition,
					dropzone->localOrigin.linearPosition
				);
				Scalar len = range.LengthSquared();
				if (len < closest_range)
				{
					closest_dropzone = dropzone;
					closest_range = len;
				}
			}
			message->dropZoneID = closest_dropzone->GetEntityID();
			dropzone = closest_dropzone;
		}

		//
		//----------------------------------------------
		// Otherwise, get this one from the host manager
		//----------------------------------------------
		//
		else
		{
			//DEBUG_STREAM << "                        Use Assigned" << endl << std::flush;

			HostManager *host = application->GetHostManager();
			Check(host);
			dropzone =
				Cast_Object(
					DropZone*,
					host->GetEntityPointer(message->dropZoneID)
				);
		}

		Check(dropzone);
		DropZone::AssignDropZoneMessage
			request(
				DropZone::AssignDropZoneMessageID,
				sizeof(DropZone::AssignDropZoneMessage),
				GetEntityID(),
				DropZoneReplyMessageID,
				deathCount
			);
		dropzone->Dispatch(&request);
		Time when = Now();
		when += 2.0f;
		application->Post(HighEventPriority, this, message, when);
	}
	Check_Fpu();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Player::HuntForDropZone(Scalar)
{
	Check(this);
	Check(playerMission);

	//
	//----------------------------------------------------------------------
	// See if our designated drop zone is around yet.  If the dropzone group
	// does not exist, then no dropzones at all are available
	//----------------------------------------------------------------------
	//
	Check(application);
	EntityManager *entity_manager = application->GetEntityManager();
	Check(entity_manager);
	EntityGroup *dropzones = entity_manager->FindGroup("DropZones");
	if (!dropzones)
	{
		Check_Fpu();
		return;
	}

	Check(dropzones);
	ChainIteratorOf<Node*> iterator(dropzones->groupMembers);
	DropZone *dropzone;
	const char* zone_name = playerMission->GetDropZoneName();
	while ((dropzone = (DropZone*)iterator.ReadAndNext()) != NULL)
	{
		if (!strcmp(dropzone->GetDropZoneName(), zone_name))
		{
			break;
		}
	}

	//
	//------------------------------------------------------------------------
	// If it is, reset our performance, and send a message to the drop zone to
	// give us a location
	//------------------------------------------------------------------------
	//
	if (dropzone)
	{

		//DEBUG_STREAM << "FOUND DROPZONE" << endl << std::flush;

		Check(dropzone);
		SetPerformance(&Player::DoNothingOnce);
		VehicleDeadMessage
			dead(
				VehicleDeadMessageID,
				sizeof(VehicleDeadMessage),
				dropzone->GetEntityID()
			);
		dead.deathCount = -2;

		DropZone::AssignDropZoneMessage
			request(
				DropZone::AssignDropZoneMessageID,
				sizeof(DropZone::AssignDropZoneMessage),
				GetEntityID(),
				DropZoneReplyMessageID,
				deathCount
			);
		dropzone->Dispatch(&request);
		Time when = Now();
		when += 2.0f;
		application->Post(HighEventPriority, this, &dead, when);
	}
	Check_Fpu();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Player::ManageApplicationStatus(Scalar time_slice)
{
	//
	//--------------------------------------------------------------------------
	// If we are in the game start/stop phase, count the timer down and send the
	// appropriate message to the application when done
	//--------------------------------------------------------------------------
	//
	Check(this);
	Check(application);
	switch (GetSimulationState())
	{
	case MissionStartingState:
		Verify(fadeTimeRemaining <= 3.0f);
		fadeTimeRemaining -= time_slice;
		if (fadeTimeRemaining <= 0.0f)
		{
			SetSimulationState(VehicleTranslocatedState);
			Check(application);
			switch (application->GetApplicationState())
			{
			case Application::LaunchingMission:
				{
					Application::RunMissionMessage message;
					application->Dispatch(&message);
				}
				break;
			case Application::ResumingMission:
				{
					Application::ResumeMissionMessage message;
					application->Dispatch(&message);
				}
				break;
			}
		}
		break;
	case MissionEndingState:
		fadeTimeRemaining -= time_slice;
		if (fadeTimeRemaining <= 0.0f)
		{
			Check(application);
			switch (application->GetApplicationState())
			{
			case Application::EndingMission:
				{
					// Fill in appropriate exit code here. GAH
					Application::StopMissionMessage message(NullExitCodeID);
					application->Dispatch(&message);
				}
				break;
			case Application::AbortingMission:
				{
					// Fill in appropriate exit code here. GAH
					Application::AbortMissionMessage message(NullExitCodeID);
					application->Dispatch(&message);
				}
				break;
			case Application::SuspendingMission:
				{
					Application::SuspendMissionMessage message;
					application->Dispatch(&message);
				}
				break;
			}
		}
		break;
	}
	Check_Fpu();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Player::CameraShipSimulation(Scalar time_slice)
{
	Check(this);
	CalcRanking();

	ManageApplicationStatus(time_slice);
	Check_Fpu();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Player::PlayerSimulation(Scalar time_slice)
{
	Check(this);

	//-------------------------------
	// Calculate the player's ranking
	//-------------------------------
	CalcRanking();

	//----------------------------------
	// ...manage the application status?
	//----------------------------------
	ManageApplicationStatus(time_slice);

	//-------------------------------
	// Copy vehicle position
	//-------------------------------
	if (playerVehicle)
	{
		Check(playerVehicle);
		localOrigin = playerVehicle->localOrigin;
		localToWorld = playerVehicle->localToWorld;
	}

	//---------------------------------
	// Service the status message queue
	//---------------------------------
	StatusMessageUpdate(time_slice);

	Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Player::GoToVehicle(Scalar)
{
	Check(this);
	if (playerVehicle)
	{
		Check(playerVehicle);
		localOrigin = playerVehicle->localOrigin;
		localToWorld = playerVehicle->localToWorld;
	}
	Check_Fpu();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	Player::CalcRanking()
{

	//
	//---------------------------------------
	// Get all players from the entity group
	//---------------------------------------
	//
	EntityGroup *player_group =
		application->GetEntityManager()->FindGroup("Players");
	if(player_group)
	{
		int num_players = 0;
		Player *active_player;
		//
		//-----------------------------------------------------
		// Iterate through the players add to the sorted chain
		//-----------------------------------------------------
		//
		ChainIteratorOf<Node*> iterator(player_group->groupMembers);
		VChainOf<Player*, Scalar> player_rank(NULL, False);
		while ((active_player = (Player*) iterator.ReadAndNext()) != NULL)
		{
			if(active_player->IsScoringPlayer())
			{
				player_rank.AddValue(active_player, active_player->currentScore);
				++num_players;
				//
				//~~~~~~~~~~~~~~~~~~~~~~~~~
				// Reset Player Highlighted
				//~~~~~~~~~~~~~~~~~~~~~~~~~
				//
				active_player->playerHighlighted = False;
			}
			else
			{
				active_player->playerRanking = -1;
			}

		}
		--num_players;
		//
		//------------------------------------------------
		// Iterate through the chain assigning the rank
		//------------------------------------------------
		//
		VChainIteratorOf<Player*, Scalar> rank_iterator(player_rank);


		while ((active_player = rank_iterator.ReadAndNext()) != NULL)
		{
			active_player->playerRanking = num_players;
			//
			//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			// If player in first place turn on player highlighted
			//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			//
			if (!active_player->playerRanking)
			{
				active_player->playerHighlighted = True;
			}
			--num_players;
		}
		Check_Fpu();
	}
	return 1;
}
//#############################################################################
// Update Support
//
void
	Player::ReadUpdateRecord(Simulation::UpdateRecord *message)
{
	Check(this);
	Check_Pointer(message);
	Entity::ReadUpdateRecord(message);
	UpdateRecord* record = (UpdateRecord*) message;

	currentScore = record->currentScore;
	dropZoneLocation = record->dropZoneLocation;
	Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Player::WriteUpdateRecord(
		Simulation::UpdateRecord *record,
		int update_model
	)
{
	Check(this);
	Check_Pointer(record);

	Entity::WriteUpdateRecord(record, update_model);

	UpdateRecord* update = (UpdateRecord*) record;

	update->recordLength = sizeof(*update);
	update->currentScore = currentScore;
	update->dropZoneLocation = dropZoneLocation;
	Check_Fpu();
}


//#############################################################################
// Construction and Destruction
//

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Player::Player(
	Player::MakeMessage *creation_message,
	Player::SharedData &virtual_data
):
	Entity(creation_message, virtual_data),
	statusMessageQueue(NULL)
{
	Check_Pointer(this);
	Check_Pointer(creation_message);

	scenarioRole = NULL;
	//---------------------------------
	// Initialize data
	//---------------------------------
	statusMessagePointer = NULL;
	//
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Initialize the playerMission
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	playerMission = application->GetCurrentMission();
	Check(playerMission);
	//
	//---------------------------------
	// Set the resource ID for a player
	//---------------------------------
	//
	Check(application);
	Check(application->GetResourceFile());
	ResourceDescription *resource_description =
		application->GetResourceFile()->FindResourceDescription(
			"player",
			ResourceDescription::ModelListResourceType
		);
	if (resource_description != NULL)
	{
		Verify(resourceID == ResourceDescription::NullResourceID);
		resourceID = resource_description->resourceID;
	}
	//
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Get the host type associated with the entity ID
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//
	HostType host_type;

	HostID host_ID = entityID.GetHostID();
	Check(application);
	HostManager *host_mgr = application->GetHostManager();
	Check(host_mgr);
	Host *local_host = host_mgr->GetLocalHost();
	Check(local_host);
	if (host_ID == local_host->GetHostID())
	{
		host_type = local_host->GetHostType();
	}
	else
	{
		HostManager::RemoteHostIterator iterator(host_mgr);
		local_host = iterator.Find(host_ID);
		Check(local_host);
		host_type = local_host->GetHostType();
	}

	if (IsCameraShipPlayer())
	{
		//
		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// Make A CameraPlayers Entity Group
		// since cameras are not involved in
		// standard game play they need a
		// separate Entity Group!
		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		//
		playerBitmapIndex = -1;
	}
	else
	{
		//
		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// Make A Regular Players Entity Group
		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		//
		Check(application);
		EntityManager *entity_manager = application->GetEntityManager();
		Check(entity_manager);
		EntityGroup *players = entity_manager->UseGroup("Players");
		Check(players);
		players->Add(this);
		playerBitmapIndex = creation_message->playerBitmapIndex;
	}

	SetValidFlag();
	playerVehicle = NULL;
	if (GetInstance() != ReplicantInstance)
	{
		Check(application->GetCurrentMission());
		playerMission = application->GetCurrentMission();
		SetPerformance(&Player::HuntForDropZone);
	}
	else
	{
		SetPerformance(&Player::GoToVehicle);
		playerMission = NULL;
	}

	playerRanking = 0;
	deathCount = -2;

	//-------------------------------------
	// Clear score
	//-------------------------------------
	currentScore = 0.0f;
	//-------------------------------------
	// Create intercom object
	//-------------------------------------
	Check(application);
	IcomManager
		*intercom_manager = application->GetIntercomManager();
	Check(intercom_manager);

	intercomPointer = intercom_manager->MakeIcom(GetOwnerID());
	Check(intercomPointer);
	// registered in MakeIcom()

	playerHighlighted = False;
	fadeTimeRemaining = 0.0f;
	Check_Fpu();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Player* Player::Make(Player::MakeMessage *creation_message)
{
	Check_Fpu();
	return new Player(creation_message, DefaultData);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Player::~Player()
{
	Check(this);

	//--------------------------------------------
	// Delete intercom object
	//--------------------------------------------
	Check(intercomPointer);
	Unregister_Object(intercomPointer);
	delete intercomPointer;
	intercomPointer = NULL;

	Check_Fpu();
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Player::AddStatusMessage(StatusMessage *status_message)
{
	Check(this);
	Check_Pointer(status_message);
	statusMessageQueue.Add(status_message);
	Check_Fpu();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Player::StatusMessageUpdate(Scalar time_slice)
{
	Check(this);
	//-------------------------------------
	// We handle this queue as a STACK.
	// The most recent message is presented
	// first, causing older messages to
	// wait "below" them on the stack.
	// This allows a default message to
	// sit at the "bottom" of the stack
	// and allow others to override it
	// temporarily.
	//-------------------------------------
	//
	ChainIteratorOf<StatusMessage*>
		iterator(statusMessageQueue);
	//----------------------------------------
	// ...we really want iterator.GetLast(),
	// but since it doesn't exist we'll
	// do it directly.
	//----------------------------------------
	statusMessagePointer = NULL;
	{
		StatusMessage
			*the_message;

		while ((the_message = iterator.ReadAndNext()) != NULL)
		{
			statusMessagePointer = the_message;
		}
	}
	//----------------------------------------
	// If a message exists, decrement the
	// timer: discard it if timed out.
	//----------------------------------------
	if (statusMessagePointer != NULL)
	{
		Check_Pointer(statusMessagePointer);

		statusMessagePointer->displayTime -= time_slice;
		if (statusMessagePointer->displayTime <= (Scalar) 0.0f)
		{
			Unregister_Object(statusMessagePointer);
			delete statusMessagePointer;
			statusMessagePointer = NULL;
		}
	}
	Check_Fpu();
}

Logical
	Player::TestInstance() const
{
	return IsDerivedFrom(*GetClassDerivations());
}
