#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 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 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 iterator(player_group->groupMembers); VChainOf 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 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 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()); }