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.
543 lines
12 KiB
C++
543 lines
12 KiB
C++
//===========================================================================//
|
|
// File: NonCom.cpp
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// 05/06/99 DPB Inital base class
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1998, Fasa Interactive //
|
|
// All Rights reserved worldwide //
|
|
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
|
//===========================================================================//
|
|
|
|
#include "MW4Headers.hpp"
|
|
|
|
#include "NonCom.hpp"
|
|
#include "ai.hpp"
|
|
|
|
#include "MWDamageObject.hpp"
|
|
#include "adept\CameraComponent.hpp"
|
|
|
|
//#############################################################################
|
|
//############################### NonCom ################################
|
|
//#############################################################################
|
|
|
|
NonCom::ClassData* NonCom::DefaultData = NULL;
|
|
|
|
|
|
DWORD MechWarrior4::Executed_NonCom_Count = 0;
|
|
const int MAX_NONCOM_FRAME = 8;
|
|
const Stuff::Scalar NONCOM_FRAME_WIDTH = 256/16;
|
|
const Stuff::Scalar NONCOM_ANIMAL_FRAME_WIDTH = 256/8;
|
|
const Stuff::Scalar NONCOM_FRAME_HEIGHT = 256/8;
|
|
const Stuff::Scalar RUN_FRAME_RATE = 15.0f; // frames per second
|
|
const Stuff::Scalar WALK_FRAME_RATE = 8.0f; // frames per second
|
|
const Stuff::Scalar ANIMAL_FRAME_RATE = 15.0f; // frames per second
|
|
const Stuff::Scalar RUN_SPEED = 5.99f; // meters per second to use run frame
|
|
const Stuff::Scalar min_index_change_duration = 1.5f;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void NonCom::InitializeClass()
|
|
{
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
NonComClassID,
|
|
"MechWarrior4::NonCom",
|
|
MWObject::DefaultData,
|
|
0, NULL,
|
|
(Entity::Factory)Make,
|
|
(Entity::CreateMessage::Factory)CreateMessage::ConstructCreateMessage,
|
|
ExecutionStateEngine::DefaultData,
|
|
(Entity::GameModel::Factory)GameModel::ConstructGameModel,
|
|
(Entity::GameModel::Factory)GameModel::ConstructOBBStream,
|
|
(Entity::GameModel::ReadAndVerifier)GameModel::ReadAndVerify,
|
|
(Entity::GameModel::ModelWrite)GameModel::WriteToText,
|
|
(Entity::GameModel::ModelSave)GameModel::SaveGameModel,
|
|
AnimationStateEngine::Make
|
|
);
|
|
Register_Object(DefaultData);
|
|
|
|
CUSTOM_DIRECT_ATTRIBUTE(
|
|
NonCom,
|
|
UVMatrix,
|
|
UVMatrix,
|
|
AffineMatrix4D,
|
|
AffineMatrix4DClassID
|
|
);
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void NonCom::TerminateClass()
|
|
{
|
|
Unregister_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
NonCom* NonCom::Make(CreateMessage *message,ReplicatorID *base_id)
|
|
{
|
|
gos_PushCurrentHeap(Heap);
|
|
NonCom *new_entity = new NonCom(DefaultData, message, base_id, NULL);
|
|
gos_PopCurrentHeap();
|
|
Check_Object(new_entity);
|
|
return new_entity;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
NonCom::NonCom(ClassData *class_data,CreateMessage *message,ReplicatorID *base_id,ElementRenderer::Element *element):
|
|
MWObject(class_data, message, base_id, element)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(message);
|
|
|
|
CommonCreation(message);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void NonCom::CommonCreation(CreateMessage *message)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
|
|
m_UVs[0] = Point3D (0,0,0);
|
|
m_UVs[1] = Point3D (0,0,0);
|
|
m_UVs[2] = Point3D (0,0,0);
|
|
m_UVs[3] = Point3D (0,0,0);
|
|
m_TextureID = 0;
|
|
UVMatrix = AffineMatrix4D::Identity;
|
|
m_AnimFrame = (objectID & 0x07);
|
|
m_FrameTime = 0;
|
|
m_Speed = 0;
|
|
m_IsAnimal = false;
|
|
m_LastPos = Point3D::Identity;
|
|
m_LastFacing = 0;
|
|
|
|
// executionState->RequestState(ExecutionStateEngine::NeverExecuteState);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void NonCom::Respawn(Entity::CreateMessage *message)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
|
|
MWObject::Respawn(message);
|
|
CreateMessage *NonCom_message = Cast_Pointer(CreateMessage *, message);
|
|
CommonCreation(NonCom_message);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
NonCom::~NonCom()
|
|
{
|
|
}
|
|
|
|
void NonCom::TurnOn (void)
|
|
{
|
|
lastParameterization = gos_GetElapsedTime ();
|
|
executionState->RequestState(ExecutionStateEngine::AlwaysExecuteState);
|
|
}
|
|
|
|
void NonCom::TurnOff (void)
|
|
{
|
|
executionState->RequestState(ExecutionStateEngine::NeverExecuteState);
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void NonCom::Reuse(const CreateMessage *message,ReplicatorID *base_id)
|
|
{
|
|
Check_Object(this);
|
|
STOP(("Not implemented"));
|
|
MWObject::Reuse(message, base_id);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void NonCom::PreCollisionExecute(Stuff::Time till)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(animStateEngine);
|
|
PRECOLLISION_LOGIC("NonCom");
|
|
|
|
Verify(executionState->GetState() != ExecutionStateEngine::NeverExecuteState);
|
|
|
|
Set_Statistic(Executed_NonCom_Count, Executed_NonCom_Count+1);
|
|
DetermineUV (GetTimeSlice (till));
|
|
|
|
MWObject::PreCollisionExecute(till);
|
|
}
|
|
|
|
void NonCom::DetermineUV (Stuff::Time slice)
|
|
{
|
|
Check_Object (this);
|
|
|
|
bool flip,run=false;
|
|
Scalar gridx,gridy; // index into grid
|
|
|
|
int index;
|
|
|
|
Point3D distance_to_target;
|
|
Point3D loc (GetLocalToWorld ());
|
|
LinearMatrix4D tempmat (GetLocalToWorld ());
|
|
|
|
tempmat.AlignLocalAxisToWorldVector (Vector3D::Up,Y_Axis,X_Axis,Z_Axis);
|
|
|
|
CameraComponent *camera = VideoRenderer::Instance->GetSceneCamera();
|
|
|
|
// camera can be null on dedicated servers and in prerender.
|
|
if (camera == NULL)
|
|
return;
|
|
|
|
Check_Object(camera);
|
|
|
|
Stuff::Vector2DOf<Stuff::Scalar> lastPos2D;
|
|
camera->ComputeCursor(&lastPos2D,m_LastPos);
|
|
|
|
Stuff::Vector2DOf<Stuff::Scalar> curPos2D;
|
|
camera->ComputeCursor(&curPos2D,loc);
|
|
|
|
if (lastPos2D.x < curPos2D.x)
|
|
{
|
|
if (lastPos2D.y < curPos2D.y)
|
|
{
|
|
index = 2;
|
|
}
|
|
else
|
|
{
|
|
index = 3;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (lastPos2D.y < curPos2D.y)
|
|
{
|
|
index = 0;
|
|
}
|
|
else
|
|
{
|
|
index = 1;
|
|
}
|
|
}
|
|
|
|
/*
|
|
ElementRenderer::CameraElement* camelement = camera->GetElement();
|
|
|
|
Point3D camera_pos(camelement->GetLocalToWorld());
|
|
|
|
if (m_LastPos == Point3D::Identity)
|
|
{
|
|
m_LastPos = camelement->GetLocalToWorld();
|
|
}
|
|
|
|
Stuff::UnitVector3D forward_vector;
|
|
camelement->GetLocalToWorld().GetLocalForwardInWorld(&forward_vector);
|
|
|
|
Point3D delta;
|
|
delta.Subtract(m_LastPos,loc);
|
|
|
|
if (!Small_Enough(delta.GetLengthSquared()))
|
|
{
|
|
delta.Normalize(delta);
|
|
}
|
|
|
|
Scalar angle = delta * forward_vector;
|
|
|
|
bool left = (angle < 0);
|
|
|
|
if (GetLengthSquared(camera_pos,loc) > GetLengthSquared(camera_pos,m_LastPos))
|
|
{
|
|
if (left == true)
|
|
{
|
|
index = 1;
|
|
}
|
|
else
|
|
{
|
|
index = 3;
|
|
}
|
|
// 1 or 3
|
|
}
|
|
else
|
|
{
|
|
if (left == true)
|
|
{
|
|
index = 0;
|
|
}
|
|
else
|
|
{
|
|
index = 2;
|
|
}
|
|
// 0 or 2
|
|
}
|
|
*/
|
|
|
|
/*
|
|
Stuff::UnitVector3D forward_vector;
|
|
camelement->GetLocalToWorld().GetLocalForwardInWorld(&forward_vector);
|
|
|
|
if (m_LastPos == Point3D::Identity)
|
|
{
|
|
m_LastPos = camelement->GetLocalToWorld();
|
|
}
|
|
|
|
Point3D delta;
|
|
delta.Subtract(m_LastPos,loc);
|
|
|
|
if (!Small_Enough(delta.GetLengthSquared()))
|
|
{
|
|
delta.Normalize(delta);
|
|
}
|
|
|
|
Scalar angle = delta * forward_vector;
|
|
|
|
if ((angle <= -1) ||
|
|
(angle >= 1))
|
|
{
|
|
angle = 0;
|
|
}
|
|
else
|
|
{
|
|
angle = Arccos(angle);
|
|
}
|
|
|
|
if (angle < 0)
|
|
{
|
|
angle = Two_Pi + angle;
|
|
}
|
|
|
|
m_LastFacing = angle;
|
|
|
|
if (angle < Pi_Over_4)
|
|
{
|
|
index = 0;
|
|
}
|
|
else
|
|
{
|
|
if (angle < Pi_Over_2)
|
|
{
|
|
index = 1;
|
|
}
|
|
else
|
|
{
|
|
if (angle < Pi_Over_4 + Pi_Over_2)
|
|
{
|
|
index = 2;
|
|
}
|
|
else
|
|
{
|
|
index = 3;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
m_LastIndex = index;
|
|
if ((m_Speed >= RUN_SPEED) &&
|
|
(m_IsAnimal == false))
|
|
{
|
|
index += 4;
|
|
run = true;
|
|
}
|
|
flip = false;
|
|
Verify (index >=0);
|
|
Verify (index <= 7);
|
|
gridx = gridy = 0;
|
|
|
|
if (m_IsAnimal == true)
|
|
{
|
|
switch (index)
|
|
{
|
|
case 0:
|
|
gridx = 0; gridy = 0;
|
|
break;
|
|
case 1:
|
|
gridx = 0; gridy = 1;
|
|
break;
|
|
case 2:
|
|
gridx = 0; gridy = 0;
|
|
flip = true;
|
|
break;
|
|
case 3:
|
|
gridx = 0; gridy = 1;
|
|
flip = true;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (index)
|
|
{
|
|
case 0:
|
|
gridx = 0; gridy = 0;
|
|
break;
|
|
case 1:
|
|
gridx = 8; gridy = 0;
|
|
break;
|
|
case 2:
|
|
gridx = 0; gridy = 0;
|
|
flip = true;
|
|
break;
|
|
case 3:
|
|
gridx = 8; gridy = 0;
|
|
flip = true;
|
|
break;
|
|
|
|
case 4:
|
|
gridx = 0; gridy = 1;
|
|
break;
|
|
case 5:
|
|
gridx = 8; gridy = 1;
|
|
break;
|
|
case 6:
|
|
gridx = 0; gridy = 1;
|
|
flip = true;
|
|
break;
|
|
case 7:
|
|
gridx = 8; gridy = 1;
|
|
flip = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (m_Speed == 0)
|
|
m_AnimFrame = (objectID & 0x07);
|
|
else
|
|
{
|
|
m_FrameTime += slice;
|
|
Scalar frame_rate;
|
|
|
|
if (m_IsAnimal == true)
|
|
{
|
|
frame_rate = ANIMAL_FRAME_RATE;
|
|
}
|
|
else
|
|
{
|
|
frame_rate = run ? RUN_FRAME_RATE : WALK_FRAME_RATE;
|
|
}
|
|
|
|
while (m_FrameTime >= (1.0/frame_rate))
|
|
{
|
|
m_FrameTime -= (1.0/frame_rate);
|
|
m_AnimFrame++;
|
|
}
|
|
}
|
|
|
|
if ((m_IsAnimal == true) &&
|
|
(m_TextureID == 0))
|
|
{
|
|
flip = (flip == true) ? false : true;
|
|
}
|
|
|
|
Verify (m_TextureID >=0);
|
|
Verify (m_TextureID <= 3);
|
|
gridy += (m_TextureID * 2);
|
|
m_AnimFrame = m_AnimFrame & 0x07;
|
|
|
|
UVMatrix = AffineMatrix4D::Identity;
|
|
if (flip)
|
|
UVMatrix(0,0) = -1.0f;
|
|
else
|
|
UVMatrix(0,0) = 1.0f;
|
|
UVMatrix(1,1) = 1.0f;
|
|
|
|
UVMatrix(3,0) = (FrameWidth() / 256.0f) * (m_AnimFrame + gridx);
|
|
if (flip)
|
|
UVMatrix(3,0) += (FrameWidth() / 256.0f);
|
|
UVMatrix(3,1) = (FrameHeight() / 256.0f) * gridy;
|
|
// UVMatrix(3,0) = m_UVs[2].x / 256.0f;
|
|
// UVMatrix(3,1) = m_UVs[2].y / 256.0f;
|
|
|
|
#if 0
|
|
for (i=0;i<4;i++) // normalize values
|
|
{
|
|
m_UVs[i].x /= 256.0f;
|
|
m_UVs[i].y /= 256.0f;
|
|
}
|
|
#endif
|
|
|
|
m_LastPos = loc;
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void NonCom::ReactToDestruction(int damage_mode, int damage_type)
|
|
{
|
|
Check_Object(this);
|
|
|
|
if (!IsDestroyed())
|
|
{
|
|
if (m_AI)
|
|
{
|
|
Check_Object(m_AI);
|
|
m_AI->Die();
|
|
}
|
|
|
|
SetDestroyedFlag(damage_mode);
|
|
|
|
if (damage_type != SplashDamageType)
|
|
DealSplashDamage();
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
|
|
CreateEffect(model->destroyedEffectResource, (Point3D)GetLocalToWorld());
|
|
if(!m_deathEntity.GetCurrent())
|
|
{
|
|
Entity *death_entity = CreateStaticHermitEntity(model->deathEntityResource);
|
|
if(death_entity)
|
|
{
|
|
m_deathEntity.Remove();
|
|
m_deathEntity.Add(death_entity);
|
|
}
|
|
}
|
|
|
|
RemoveFromExecution();
|
|
}
|
|
|
|
Entity::ReactToDestruction(damage_mode, damage_type);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void NonCom::TestInstance() const
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void NonCom::ReactToHit(const Entity__TakeDamageMessage *message,Adept::DamageObject *part_hit)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
|
|
MWObject::ReactToHit(message,part_hit);
|
|
|
|
}
|
|
|
|
void NonCom::SetAsAnimal()
|
|
{
|
|
m_IsAnimal = true;
|
|
}
|
|
|
|
Scalar NonCom::FrameWidth() const
|
|
{
|
|
if (m_IsAnimal == true)
|
|
{
|
|
return (NONCOM_ANIMAL_FRAME_WIDTH);
|
|
}
|
|
|
|
return (NONCOM_FRAME_WIDTH);
|
|
}
|
|
|
|
Scalar NonCom::FrameHeight() const
|
|
{
|
|
return (NONCOM_FRAME_HEIGHT);
|
|
}
|