//===========================================================================// // File: MWPlayer.cpp // //---------------------------------------------------------------------------// // Date Who Modification // // -------- --- ---------------------------------------------------------- // // 09/09/98 JSE Inital base class based off of Shadowrun/Adept // //---------------------------------------------------------------------------// // Copyright (C) 1998, Fasa Interactive // // All Rights reserved worldwide // // This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL // //===========================================================================// #include "MW4Headers.hpp" #include "MWPlayer.hpp" #include "MWMover.hpp" #include "Vehicle.hpp" #include "VehicleInterface.hpp" #include "MWMission.hpp" #include "MWApplication.hpp" #include "playerai.hpp" #include "AI_Groups.hpp" #include "Team.hpp" #include #include #include #include #include #include #include #include using namespace MW4AI; //############################################################################# //############################### MWPlayer ############################## //############################################################################# MWPlayer::ClassData* MWPlayer::DefaultData = NULL; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MWPlayer::InitializeClass() { Verify(!DefaultData); DefaultData = new ClassData( MWPlayerClassID, "MechWarrior4::MWPlayer", Player::DefaultData, 0, NULL, (Entity::Factory)Make, (Entity::CreateMessage::Factory)CreateMessage::ConstructCreateMessage, ExecutionStateEngine::DefaultData, (Entity::GameModel::Factory)GameModel::ConstructGameModel, NULL, (Entity::GameModel::ReadAndVerifier)GameModel::ReadAndVerify, (Entity::GameModel::ModelWrite)GameModel::WriteToText, (Entity::GameModel::ModelSave)GameModel::SaveGameModel ); Register_Object(DefaultData); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MWPlayer::TerminateClass() { Unregister_Object(DefaultData); delete DefaultData; DefaultData = NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MWPlayer* MWPlayer::Make( CreateMessage *message, ReplicatorID *base_id ) { Check_Object(message); gos_PushCurrentHeap(Heap); MWPlayer *new_entity = new MWPlayer(DefaultData, message, base_id, NULL); gos_PopCurrentHeap(); Check_Object(new_entity); return new_entity; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ObjectID MWPlayer::FindDropZone(int team) { if (team != MWApplication::No_Team) { NameTable *table = NameTable::GetInstance(); int size(table->nameTableArray[NameTable::DropZoneArray].GetLength()); {for (int i = 0; i < size; ++i) { NameTableEntry *data; data = &table->nameTableArray [NameTable::DropZoneArray][i]; Adept::Entity* ent = data->dataPointer->GetCurrent (); if (ent != 0) { int team_number = MWApplication::NameToTeamNumber(ent->instanceName); if (team_number == team) { return (ent->objectID); } } }} } ObjectID obj_id = (NameTable::GetInstance()->FindID("PlayerStart")); if (obj_id == NameTable::NullObjectID) { STOP(("No valid dropzone")); } return obj_id; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MWPlayer::MWPlayer( ClassData *class_data, CreateMessage *message, ReplicatorID *base_id, ElementRenderer::Element *element ): Player(class_data, message, base_id, element), m_Team(MWApplication::No_Team) { Check_Pointer(this); Check_Object(message); isDropped = false; Mission::GetInstance()->AddChild(this); // //---------------------- // Create the interface //---------------------- // playerInterface = NULL; interfaceResourceID = ResourceID::Null; if (GetReplicatorMode() == Replicator::ClientMasterMode || GetReplicatorMode() == Replicator::MasterMode) { Resource stream(message->interfaceResourceID); Verify(stream.DoesResourceExist()); //ReplicatorID id = owningConnection->GetNextReplicatorID(); ReplicatorID interface_id = Connection::Hermit->GetNextReplicatorID(); playerInterface = Cast_Object(Interface *, CreateEntity(&stream, &interface_id)); Check_Object(playerInterface); interfaceResourceID = message->interfaceResourceID; } // //------------------- // Create the vehicle //------------------- // Resource mech_instance(message->vehicleResourceID); mech_instance.LoadData(); Verify(mech_instance.DoesResourceExist()); void *new_data = new BYTE[mech_instance.GetSize()]; Mem_Copy(new_data, mech_instance.GetPointer(), mech_instance.GetSize(), mech_instance.GetSize()); MWObject::CreateMessage *create_message = Cast_Pointer(MWObject::CreateMessage*, new_data); Check_Object(create_message); create_message->pilotDecal = message->pilotDecal; create_message->teamDecal = message->teamDecal; Team* team = 0; if (message->teamNumber != MWApplication::No_Team) { team = MWApplication::GetInstance()->teams[message->teamNumber]->GetCurrent(); if (team) { create_message->skinPrefix = team->GetTeamPrefix(); } } else if (MWApplication::GetInstance()->networkingFlag) { create_message->skinPrefix = message->skinPrefix; } // for campaign skin - jcem else { extern bool g_bCOOP; if (g_bCOOP) { // m_isCampaign == (serverFlag && !networkingFlag) create_message->skinPrefix = message->skinPrefix; } } // for campaign skin - jcem MemoryStream mech_stream(create_message, create_message->messageLength); //Insure that we start with a bad id and don't get our stuff set since we are going to do it later Mech::CreateMessage *mech_message = Cast_Pointer(Mech::CreateMessage *, mech_stream.GetPointer()); mech_message->nameID = NameTableEntry::BuildObjectID(NameTable::TableSize, 0); if(mech_message->initialAge == 0.0f) { Stuff::LinearMatrix4D drop_location = Stuff::LinearMatrix4D::Identity; drop_location.BuildTranslation(Point3D::HellPoint); mech_message->localToParent = drop_location; } vehicle = CreateEntity(&mech_stream, base_id); Check_Object(vehicle); //SPEW(("jerryeds","CREATE MECH %d:%d", vehicle->GetReplicatorID().connectionID, vehicle->GetReplicatorID().localID)); delete new_data; if (team) { ((Vehicle*)vehicle)->SetTeam(message->teamNumber); team->AddMemberToTeam((Vehicle*)vehicle); m_Team = message->teamNumber; } vehicle->SetPropType(PlayerPropType); Check_Object(Map::GetInstance()); Map::GetInstance()->AddChild(vehicle); EntityManager::GetInstance()->RemoveMover((Mover*)vehicle); ReplicatorID mech_id = vehicle->GetReplicatorID(); vehicle->instanceName = Network::GetInstance()->GetConnection(mech_id.connectionID)->GetConnectionName(); if(!vehicle->instanceName || !vehicle->instanceName.GetLength()) { char buffer[10]; sprintf(buffer, "%d::", owningConnection->GetID()); MString new_name; new_name = buffer + vehicle->instanceName; vehicle->instanceName = new_name; } Check_Object(NameTable::GetInstance()); vehicle->objectID = NameTable::GetInstance()->FindID(vehicle->instanceName); if(vehicle->objectID == NameTable::NullObjectID) NameTable::GetInstance()->AddEntry(vehicle, NameTable::VehicleArray); else NameTable::GetInstance()->SetData(vehicle); if (owningConnection != Connection::Local) { vehicle->SetAlignment(Entity::Enemy); } Check_Object(EntityManager::GetInstance()); EntityManager::GetInstance()->AddMover((Mover*)vehicle); // connect to the drop zone if (message->initialAge != 0.0f) { ElementRenderer::Element *element = vehicle->GetElement(); Check_Object(element); ReceiveDropZone(element->GetNewLocalToParent()); } else { dropZone = FindDropZone(m_Team); Stuff::LinearMatrix4D drop_location = Stuff::LinearMatrix4D::Identity; drop_location.BuildTranslation(Point3D::HellPoint); vehicle->SetNewLocalToParent(drop_location); vehicle->SyncMatrices(true); Map::GetInstance()->UpdateZone(vehicle); } // //---------------------------- //Store the Vehicle ResourceID //---------------------------- // vehicleResourceID = message->vehicleResourceID; m_LockedRects.reserve (50); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MWPlayer::Respawn(CreateMessage *message) { Check_Pointer(this); Check_Object(message); isDropped = false; // //---------------------- // Respawn the interface //---------------------- // Entity::CreateMessage *interface_respawn_message = NULL; interfaceResourceID = ResourceID::Null; if (GetReplicatorMode() == Replicator::ClientMasterMode || GetReplicatorMode() == Replicator::MasterMode) { Resource stream(message->interfaceResourceID); Verify(stream.DoesResourceExist()); //ReplicatorID id = owningConnection->GetNextReplicatorID(); //ReplicatorID interface_id = Connection::Hermit->GetNextReplicatorID(); interface_respawn_message = Cast_Pointer(Entity::CreateMessage*, stream.GetPointer()); //playerInterface->Respawn(new_message); //Check_Object(playerInterface); } // //------------------- // Create the vehicle //------------------- // Resource mech_instance(message->vehicleResourceID); Verify(mech_instance.DoesResourceExist()); void *new_data = new BYTE[mech_instance.GetSize()]; Mem_Copy(new_data, mech_instance.GetPointer(), mech_instance.GetSize(), mech_instance.GetSize()); MWObject::CreateMessage *create_message = Cast_Pointer(MWObject::CreateMessage*, new_data); Check_Object(create_message); create_message->pilotDecal = message->pilotDecal; create_message->teamDecal = message->teamDecal; //create_message->skinPrefix = message->skinPrefix; MemoryStream mech_stream(create_message, create_message->messageLength); vehicle->Respawn(create_message); Check_Object(vehicle); delete[] new_data; // we do this after the vehicle for a respawn since farther down // the stream there is no reconnect if (interface_respawn_message != NULL) { playerInterface->Respawn(interface_respawn_message); Check_Object(playerInterface); } // connect to the drop zone if (message->initialAge != 0.0f) { ElementRenderer::Element *element = vehicle->GetElement(); Check_Object(element); ReceiveDropZone(element->GetNewLocalToParent()); } else { dropZone = FindDropZone(m_Team); // Stuff::LinearMatrix4D drop_location = Stuff::LinearMatrix4D::Identity; // drop_location.BuildTranslation(Point3D::HellPoint); // vehicle->SetNewLocalToParent(drop_location); // vehicle->SyncMatrices(true); // Map::GetInstance()->UpdateZone(vehicle); } if (owningConnection != Connection::Local) { vehicle->SetAlignment(Entity::Enemy); } // //---------------------------- //Store the Vehicle ResourceID //---------------------------- // vehicleResourceID = message->vehicleResourceID; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MWPlayer::~MWPlayer() { ClearPathLock (true); #if 0 // happens automaticly with plugs. if ((vehicle != 0) && (m_Team != MWApplication::No_Team)) { Team* team = MWApplication::GetInstance()->teams[m_Team]->GetCurrent(); if (team != 0) { team->RemoveMemberFromTeam((Vehicle*)vehicle); } } #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MWPlayer::ConnectToVehicle(void) { Check_Object(vehicle); Check_Object(playerInterface); Player::ConnectToVehicle(); GetInterface()->ConnectVehicleToInterface(GetVehicle(),this); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MWPlayer::PreCollisionExecute(Time till) { Check_Object(this); PRECOLLISION_LOGIC("MWPlayer"); Player::PreCollisionExecute(till); ClearPathLock (false); PathLock (); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MWPlayer::LancemateCommandProxy::LancemateCommandProxy() : m_Mode(INVALID) { } bool MWPlayer::LancemateCommandProxy::SetMode(Mode mode) { Verify(mode != INVALID); stlport::vector lance; MW4AI::Groups::GetLancemates (lance); m_Mode = INVALID; switch (mode) { case LANCEMATE_1: if (lance.size () < 1) return false; break; case LANCEMATE_2: if (lance.size () < 2) return false; break; case LANCEMATE_3: if (lance.size () < 3) return false; break; case LANCEMATE_ALL: if (lance.size ()== 0) return false; break; } m_Mode = mode; return (true); } bool MWPlayer::LancemateCommandProxy::IssueCommand(Vehicle* v, MW4AI::LancemateCommands::ID command) { if ((v == 0) || (v->GetGroups().size() == 0)) { return (false); } Check_Object(v); Group::identifier group_id; if (MW4AI::Groups::GetLancemateGroup(v->GetGroups(),group_id) == false) { return (false); } std::vector indices_to_add; switch (m_Mode) { case LANCEMATE_1: { indices_to_add.push_back(1); break; } case LANCEMATE_2: { indices_to_add.push_back(2); break; } case LANCEMATE_3: { indices_to_add.push_back(3); break; } case LANCEMATE_ALL: { indices_to_add.push_back(1); indices_to_add.push_back(2); indices_to_add.push_back(3); break; } default: { return (false); } } MW4AI::LancemateCommands::lancemate_list lancemates; {for (std::vector::const_iterator i = indices_to_add.begin(); i != indices_to_add.end(); ++i) { Adept::ObjectID id; if (MW4AI::Groups::GetMember(group_id,*i,id) == true) { lancemates.push_back(id); } }} MW4AI::LancemateCommands::Execute(command,lancemates); m_Mode = INVALID; return (true); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // //void // MWPlayer::PostCollisionExecute(Time till) //{ // Check_Object(this); // Player::PostCollisionExecute(till); //} //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MWPlayer::PostCollisionExecute(Time till) { Check_Object(this); POSTCOLLISION_LOGIC("MWPlayer"); if (playerInterface) { VehicleInterface *veh_inf = Cast_Object(VehicleInterface *, playerInterface); if (veh_inf->IsObserving(true) && (veh_inf->observingEntity.GetCurrent() != NULL)) { SetNewLocalToParent(veh_inf->observingEntity.GetCurrent()->GetLocalToWorld()); } else { SetNewLocalToParent(vehicle->GetLocalToWorld()); } } else { SetNewLocalToParent(vehicle->GetLocalToWorld()); } if (m_ObjectsToDestroy.size() > 0) { {for (stlport::vector::iterator i = m_ObjectsToDestroy.begin(); i != m_ObjectsToDestroy.end(); ++i) { Entity* ent = NameTable::GetInstance()->FindData(*i); if (ent != 0) { Entity::TakeDamageMessage damage_message( ent->GetReplicatorID(), ent->GetReplicatorID(), // 100000, 0.0f, // MSL 5.05 Armor Mode 0, Adept::RammingDamageFromAboveType, Stuff::UnitVector3D(1,0,0), (Stuff::Point3D)ent->GetLocalToWorld(), 0, false, Entity::TakeDamageMessage::DefaultWeaponType ); ent->Receive(&damage_message); } }} m_ObjectsToDestroy.clear(); } SyncMatrices(true); //skip player & driver Entity::PostCollisionExecute(till); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MWPlayer::TestInstance() const { Verify(IsDerivedFrom(DefaultData)); } void MWPlayer::ClearPathLock (bool quitting) { stlport::vector::iterator iter; for (iter = m_PathLock.begin ();iter != m_PathLock.end ();iter++) { if (!quitting) { MW4AI::g_MissionGraph->PassableLocalOverride ((*iter)->locx,(*iter)->locz,(*iter)->olddata); MW4AI::RemoveBlockLocal ((*iter)->locx,(*iter)->locz,(MWObject *) this); } delete (*iter); } m_PathLock.clear (); Verify (m_LockedRects.size () == 0); stlport::vector::iterator iter2; for (iter2 = m_LockedRects.begin ();iter2 != m_LockedRects.end ();iter2++) { g_Rect4DHash->RemoveRect (*iter2); g_Rect4DHash->VerifyRectGone (*iter2); delete (*iter2); } m_LockedRects.clear (); } bool MWPlayer::AddLockCell (const Stuff::Point3D& loc) { unsigned short value; int locx,locz; Point3D pt; if (loc.x < MW4AI::MinX) return true; if (loc.z < MW4AI::MinX) return true; if (loc.x >= MW4AI::MaxX) return true; if (loc.z >= MW4AI::MaxZ) return true; locx = (int) (loc.x / BLOCK_GRID_RES); locz = (int) (loc.z / BLOCK_GRID_RES); MWObject *who; who = MW4AI::BlockerLocal (locx,locz); if (who == (MWObject *) this) return true; if (who) return false; value = MW4AI::g_MissionGraph->PassableLocal (locx,locz); if (value & (MOVEPASSNOW_FLAG)) return false; MW4AI::g_MissionGraph->PassableLocalOverride (locx,locz,(unsigned short)(value|MOVEPASSNOW_FLAG)); m_PathLock.push_back (new LockData (locx,locz,value)); MW4AI::AddBlockLocal (locx,locz,(MWObject *) this); return true; } bool MWPlayer::LockSquare (const Point3D& loc,Stuff::Scalar rad) { int sqrindex[8][2] = { {-1,-1}, {0,-1}, {1,-1}, {-1,0}, {1,0}, {-1,1}, {0,1}, {1,1} }; int i; Point3D pt (0,0,0); if (rad < 10.0f) rad = 10.0f; for (i=0;i<8;i++) { pt.x = loc.x+(sqrindex[i][0]*rad); pt.z = loc.z+(sqrindex[i][1]*rad); if (LockedByMe (pt)) continue; AddLockCell (pt); } return false; } bool MWPlayer::PathLock (bool secondpass) { Check_Object (GetVehicle ()); Check_Object (GetVehicle ()->GetGameModel ()); if (!GetVehicle()) return false; if (playerInterface) { Check_Object (playerInterface); if (playerInterface->executionState->GetState () == VehicleInterface::ExecutionStateEngine::AIRunningState) return false; } OBB *obb; CollisionVolume *col; col = vehicle->GetSolidVolume (); if (!col) return false; obb = &(col->m_localSpaceBounds); if (!obb) return false; Stuff::Scalar rad = obb->sphereRadius; rad *= 1.5f; Stuff::Scalar speed,movemps,slowtime; UnitVector3D forward; Point3D step,loc; int i,timelen; const Vehicle__GameModel *model = static_cast (vehicle->GetGameModel ()) ; loc = (Point3D) vehicle->GetLocalToWorld (); vehicle->GetLocalToWorld ().GetLocalForwardInWorld (&forward); step = forward; speed = GetVehicle ()->currentSpeedMPS; LockSquare (loc,rad); AddLockCell (loc); if (speed == 0) { return false; } movemps = speed; Max_Clamp(movemps, model->maxSpeed); Min_Clamp(movemps, model->minSpeed); slowtime = movemps / model->decceleration; Min_Clamp (movemps,1); step *= movemps; slowtime += 1.0f; //extra second of buffer timelen = (int) (slowtime); int maxi; Scalar delta; delta = 10.0f/movemps; step *= delta; maxi = (int) (timelen / delta); Min_Clamp (maxi,1); loc += step; for (i=0;i