#include "rp.h"
#pragma hdrstop

#include "runner.h"
#include "..\munga\dropzone.h"
#include "vtv.h"
#include "..\munga\hostmgr.h"
#include "..\munga\app.h"
#include "scorzone.h"
#include "..\munga\nttmgr.h"

//#############################################################################
//###############################    Runner      ##############################
//#############################################################################

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


Runner::SharedData
	Runner::DefaultData(
		Runner::GetClassDerivations(),
		Runner::MessageHandlers,
		Runner::GetAttributeIndex(),
		Runner::StateCount,
		(Runner::MakeHandler)Runner::Make
	);

const Receiver::HandlerEntry
	Runner::MessageHandlerEntries[]=
{
	MESSAGE_ENTRY(Runner, VehicleDead),
	MESSAGE_ENTRY(Runner, Score),
	MESSAGE_ENTRY(Runner, DropZoneReply),
	MESSAGE_ENTRY(Runner, ScoreZoneReply)
};

Receiver::MessageHandlerSet
	Runner::MessageHandlers(
		ELEMENTS(Runner::MessageHandlerEntries),
		Runner::MessageHandlerEntries,
		RPPlayer::GetMessageHandlers()
	);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Runner::Runner(
	MakeMessage *creation_message,
	SharedData &shared_data
)
: RPPlayer(creation_message, shared_data)
{
	StatusMessage
		*message = new StatusMessage(NULL,RPStatusMessage::RunnerMessage,1e10);
	Register_Object(message);
	AddStatusMessage(message);
	dropZonePenaltyOver.ticks = 0;
	scoreMultiplier = 1.0f;

	//----------------------------------------
	// Add to runner group
	//----------------------------------------
	EntityManager
		*entity_manager = application->GetEntityManager();
	Check(entity_manager);

	EntityGroup
		*runner_group = entity_manager->UseGroup("RunnerPlayers");
	Check(runner_group);

	runner_group->Add(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Runner*
	Runner::Make(MakeMessage *creation_message)
{
	return new Runner(creation_message);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Runner::AddOffensivePlayer(OffensivePlayer &offensive_player)
{
	Check(offensive_player.offensivePlayer);
	RPPlayer *rp_player = offensive_player.offensivePlayer;
	//
	//---------------------------------------------
	// Death Points awarded if ....
	//  This Runner gets hit by a crusher, blocker or runner
   // from the other team with collision Damage!
	//---------------------------------------------
	//
	if (
		 rp_player->playerType == CrusherPlayerType
		 && teamID != rp_player->teamID
		 && offensive_player.damageType == Damage::CollisionDamageType)
		{
			VTV *vtv = (VTV*)playerVehicle;
			Check(vtv);
			if (vtv->boosterOn)
				{
				dropZonePenaltyOver.ticks = 0;
				}
      	offensive_player.deathBonus = (Now() <= dropZonePenaltyOver) ? -5000.0f : 500.0f;
      }
   else
			if (
		 rp_player->playerType == BlockerPlayerType
		 && teamID != rp_player->teamID
		 && offensive_player.damageType == Damage::CollisionDamageType)
		{
			VTV *vtv = (VTV*)playerVehicle;
			Check(vtv);
			if (vtv->boosterOn)
				{
				dropZonePenaltyOver.ticks = 0;
				}
      	offensive_player.deathBonus = (Now() <= dropZonePenaltyOver) ? -6666.0f : 0.0f;
      }
   else
   		if (
		 rp_player->playerType == RunnerPlayerType
		 && teamID != rp_player->teamID
		 && offensive_player.damageType == Damage::CollisionDamageType)
		{
			VTV *vtv = (VTV*)playerVehicle;
			Check(vtv);
			if (vtv->boosterOn)
				{
				dropZonePenaltyOver.ticks = 0;
				}
      	offensive_player.deathBonus = (Now() <= dropZonePenaltyOver) ? -10000.0f : 0.0f;
      }
      else
   	{
   		offensive_player.deathBonus = 0.0f;
      }


   offensivePlayerList.AddValue(&offensive_player,offensive_player.damageType);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Runner::ScoreMessageHandler(ScoreMessage *message)
{
	RPPlayer::ScoreMessageHandler(message);
	switch (message->scoreType)
	{
	case ScoreZonePointType:
	case SpeedBonusPointType:
		currentScore += message->scoreAward * scoreMultiplier;
		break;

	case DamageScoreLossPointType:
		{
			if (Now() >= dropZonePenaltyOver)
			{
				goto Standard_Score;
			}
			VTV *vtv = (VTV*)playerVehicle;
			Check(vtv);
			if (vtv->boosterOn)
			{
				dropZonePenaltyOver.ticks = 0;
				goto Standard_Score;
			}
		}
		break;

	default:
Standard_Score:
		currentScore += message->scoreAward;
		break;
	}

	//
	// 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);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Runner::ScoreZoneReplyMessageHandler(
		ScoreZone::ReplyMessage *message
	)
{
	RPPlayer::ScoreZoneReplyMessageHandler(message);
		//
		//---------------------------------------------------------
		//  double the scoreMultiplier
		//---------------------------------------------------------
		//
	Check(playerVehicle);
	VTV *vtv = (VTV*)playerVehicle;
	if (vtv->GetSimulationState() != VTV::BurningState)
	{
	scoreMultiplier *= 2.0f;
	if (scoreMultiplier > 16.0f)
     	scoreMultiplier = 16.0f;
   if (scoreMultiplier == 2.0f)
   	{
     	RPStatusMessage *message = new RPStatusMessage(NULL, RPStatusMessage::Score2xMessage, 6.0f);
		Register_Object(message);
		AddStatusMessage((StatusMessage *) message);
      }
   if (scoreMultiplier == 4.0f)
   	{
     	RPStatusMessage *message = new RPStatusMessage(NULL, RPStatusMessage::Score4xMessage, 6.0f);
		Register_Object(message);
		AddStatusMessage((StatusMessage *) message);
      }
   if (scoreMultiplier == 8.0f)
   	{
     	RPStatusMessage *message = new RPStatusMessage(NULL, RPStatusMessage::Score8xMessage, 6.0f);
		Register_Object(message);
		AddStatusMessage((StatusMessage *) message);
      }
   if (scoreMultiplier == 16.0f)
   	{
     	RPStatusMessage *message = new RPStatusMessage(NULL, RPStatusMessage::Score16xMessage, 6.0f);
		Register_Object(message);
		AddStatusMessage((StatusMessage *) message);
      }
	}
}

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

	scoreMultiplier = 1.0f;
	RPPlayer::VehicleDeadMessageHandler(message);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Runner::DropZoneReplyMessageHandler(
		DropZone__ReplyMessage *message
	)
{
	Check(this);
	Check(message);

	if (
		playerVehicle
		 && deathCount == message->deathCount
		 && GetSimulationState() != DropZoneAcquiredState
	)
	{
		dropZonePenaltyOver = Now();
		dropZonePenaltyOver += 5.0f;
	}

	RPPlayer::DropZoneReplyMessageHandler(message);
	Check_Fpu();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
	Runner::TestInstance() const
{
	return IsDerivedFrom(*GetClassDerivations());
}
