Files
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2026-06-24 21:28:16 -05:00

847 lines
20 KiB
C++

//===========================================================================//
// 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 <Adept\EntityClassData.hpp>
#include <Adept\EntityManager.hpp>
#include <Adept\Interface.hpp>
#include <Adept\Application.hpp>
#include <Adept\Map.hpp>
#include <adept\collisionvolume.hpp>
#include <Adept\CollisionGrid.hpp>
#include <Adept\DamageObject.hpp>
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<MWObject *> 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<unsigned int> 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<unsigned int>::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<ObjectID>::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<LockData *>::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<Rect4D *>::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<const Vehicle__GameModel *> (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<maxi;i++)
{
LockSquare (loc,rad);
AddLockCell (loc);
loc += step;
}
return false;
}
void
MWPlayer::AddObjectToDestroy(ObjectID who)
{
m_ObjectsToDestroy.push_back(who);
}