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.
449 lines
12 KiB
C++
449 lines
12 KiB
C++
//===========================================================================//
|
|
// File: Weapon.cpp
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// 09/09/98 JSE Inital base class based off of Shadowrun/Adept //
|
|
// 09/24/98 BDB Inital Weapon subsytem class based off of Subsystem //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1998, Fasa Interactive //
|
|
// All Rights reserved worldwide //
|
|
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
|
//===========================================================================//
|
|
|
|
#include "MW4Headers.hpp"
|
|
|
|
#include "SearchLight.hpp"
|
|
#include "MWObject.hpp"
|
|
#include "LightEntity.hpp"
|
|
#include "SubsystemClassData.hpp"
|
|
//#include "torso.hpp"
|
|
#include <Adept\Mission.hpp>
|
|
#include <Adept\Map.hpp>
|
|
#include <Adept\Effect.hpp>
|
|
#include <Adept\CollisionGrid.hpp>
|
|
#include <Adept\Site.hpp>
|
|
|
|
//#############################################################################
|
|
//############################### SearchLight ###########################
|
|
//#############################################################################
|
|
|
|
SearchLight::ClassData*
|
|
SearchLight::DefaultData = NULL;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
SearchLight::InitializeClass()
|
|
{
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
SearchLightClassID,
|
|
"MechWarrior4::SearchLight",
|
|
Subsystem::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,
|
|
(Subsystem::StreamCreate) CreateStream
|
|
);
|
|
Register_Object(DefaultData);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
SearchLight__GameModel,
|
|
LightEntityResource,
|
|
lightEntityResource,
|
|
ResourceID
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
SearchLight__GameModel,
|
|
LightConeResource,
|
|
lightConeResource,
|
|
ResourceID
|
|
);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
SearchLight::TerminateClass()
|
|
{
|
|
Unregister_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
SearchLight*
|
|
SearchLight::Make(
|
|
CreateMessage *message,
|
|
ReplicatorID *base_id
|
|
)
|
|
{
|
|
Check_Object(message);
|
|
gos_PushCurrentHeap(Heap);
|
|
SearchLight *new_entity =
|
|
new SearchLight(DefaultData, message, base_id, NULL);
|
|
gos_PopCurrentHeap();
|
|
Check_Object(new_entity);
|
|
return new_entity;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Replicator::CreateMessage*
|
|
SearchLight::SaveMakeMessage(MemoryStream *stream, ResourceFile *res_file)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(stream);
|
|
|
|
stream->AllocateBytes(sizeof(CreateMessage));
|
|
Subsystem::SaveMakeMessage(stream, res_file);
|
|
CreateMessage *message =
|
|
Cast_Pointer(CreateMessage*, stream->GetPointer());
|
|
message->messageLength = sizeof(*message);
|
|
|
|
Str_Copy(message->siteName, (char *)siteName, sizeof(message->siteName));
|
|
return message;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
SearchLight::SearchLight(
|
|
ClassData *class_data,
|
|
CreateMessage *message,
|
|
ReplicatorID *base_id,
|
|
ElementRenderer::Element *element
|
|
):
|
|
Subsystem(class_data, message, base_id, element),
|
|
lightEntity(NULL),
|
|
lightConeEntity(NULL)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(message);
|
|
|
|
siteName = message->siteName;
|
|
sitePointer = NULL;
|
|
|
|
CommonCreation(message);
|
|
UsePostCollision();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
SearchLight::CommonCreation(CreateMessage *message)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
|
|
if(!lightEntity.GetCurrent())
|
|
{
|
|
CreateSearchLight();
|
|
}
|
|
UsePostCollision();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
SearchLight::Respawn(Entity::CreateMessage *message)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
|
|
Subsystem::Respawn(message);
|
|
CreateMessage *SearchLight_message = Cast_Pointer(CreateMessage *, message);
|
|
CommonCreation(SearchLight_message);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
SearchLight::~SearchLight()
|
|
{
|
|
HideBeam();
|
|
if(lightEntity.GetCurrent())
|
|
{
|
|
lightEntity.GetCurrent()->SentenceToDeathRow();
|
|
}
|
|
if(lightConeEntity.GetCurrent())
|
|
{
|
|
lightConeEntity.GetCurrent()->SentenceToDeathRow();
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
SearchLight::PostCollisionExecute(Time till)
|
|
{
|
|
Check_Object(this);
|
|
POSTCOLLISION_LOGIC("Subsystem::Searchlight");
|
|
//
|
|
// [johnyo] 08/27/00 PreviousSearchLight code is experimental code that I have checked in to keep a backup
|
|
// of only. It may be ripped out shortly if the effect that it was intended to have isn't
|
|
// put into the game
|
|
//
|
|
|
|
// if(Mission::GetInstance()->DoesAllowSearchLights() && isLightOn == true)
|
|
if(Mission::GetInstance()->DoesAllowSearchLights())
|
|
{
|
|
if(lightConeEntity.GetCurrent() == NULL)
|
|
{
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
MWObject *parent = GetParentVehicle();
|
|
Check_Object(parent);
|
|
Check_Object(sitePointer);
|
|
|
|
lightConeEntity.Remove();
|
|
lightConeEntity.Add(
|
|
parent->CreateEffect(model->lightConeResource, sitePointer, true));
|
|
HideBeam();
|
|
}
|
|
|
|
if (
|
|
(lightEntity.GetCurrent()) &&
|
|
(lightEntity.GetCurrent()->lightIntensity > MidLevelRenderer::Limits::LightThreshold) &&
|
|
(sitePointer != 0)
|
|
)
|
|
{
|
|
Check_Object(sitePointer);
|
|
Point3D new_translation;
|
|
new_translation = sitePointer->GetLocalToWorld();
|
|
UnitVector3D direction_vector;
|
|
if(lightConeEntity.GetCurrent())
|
|
{
|
|
LinearMatrix4D new_position;
|
|
/*
|
|
YawPitchRoll angle;
|
|
// if (GetParentVehicle() && GetParentVehicle()->GetTorso())
|
|
// {
|
|
angle = lightConeEntity.GetCurrent()->effectOffset;
|
|
angle.yaw = 0.0f;
|
|
angle.roll = 0.0f;
|
|
|
|
// }
|
|
// else
|
|
// {
|
|
// angle = lightConeEntity.GetCurrent()->effectOffset;
|
|
// angle.yaw = 0.0f;
|
|
// angle.roll = 0.0f;
|
|
// angle.pitch += GetParentVehicle()->GetTorso()->eyePitch;
|
|
// }
|
|
|
|
LinearMatrix4D offset = lightConeEntity.GetCurrent()->effectOffset;
|
|
// offset.BuildRotation(angle);
|
|
new_position.Multiply(
|
|
offset,
|
|
sitePointer->GetLocalToWorld()
|
|
);
|
|
*/
|
|
new_position = lightConeEntity.GetCurrent()->GetLocalToWorld();
|
|
new_translation = lightConeEntity.GetCurrent()->GetLocalToWorld();
|
|
|
|
new_position.GetLocalLeftInWorld(&direction_vector);
|
|
}
|
|
else
|
|
{
|
|
sitePointer->GetLocalToWorld().GetLocalForwardInWorld(&direction_vector);
|
|
direction_vector.y -= 0.2f;
|
|
}
|
|
|
|
Line3D target_line;
|
|
Normal3D target_normal;
|
|
|
|
target_line.SetOrigin(new_translation);
|
|
target_line.SetDirection(direction_vector);
|
|
target_line.m_length = 500;
|
|
|
|
Entity::CollisionQuery target_query(&target_line, &target_normal, Entity::AlwaysCollidesMask, GetParentVehicle());
|
|
Adept::Entity *entity_hit;
|
|
Check_Object(CollisionGrid::Instance);
|
|
entity_hit = CollisionGrid::Instance->ProjectLine(&target_query);
|
|
Point3D light_point;
|
|
target_query.m_line->FindEnd(&light_point);
|
|
|
|
lightEntity.GetCurrent()->lightIntensity = target_query.m_line->m_length;
|
|
|
|
|
|
light_point.y = target_query.m_line->m_length/* - 0.01f*/;
|
|
// LinearMatrix4D new_local_to_world = sitePointer->GetLocalToWorld();
|
|
|
|
LinearMatrix4D new_local_to_world = lightConeEntity.GetCurrent()->GetLocalToWorld();
|
|
|
|
new_local_to_world.AlignLocalAxisToWorldVector(
|
|
direction_vector,
|
|
Stuff::Z_Axis,
|
|
Stuff::Y_Axis,
|
|
Stuff::X_Axis
|
|
);
|
|
|
|
// new_local_to_world.BuildTranslation(light_point);
|
|
|
|
lightEntity.GetCurrent()->SetNewLocalToParent(new_local_to_world);
|
|
lightEntity.GetCurrent()->SyncMatrices(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool SearchLight::ConnectSubsystem()
|
|
{
|
|
MWObject *mw_object = GetParentVehicle();
|
|
Check_Object(mw_object);
|
|
|
|
sitePointer = mw_object->FindSite(siteName);
|
|
HideBeam();
|
|
|
|
//Must call the inherited virtual function!!!!
|
|
return Subsystem::ConnectSubsystem();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void SearchLight::CreateSearchLight()
|
|
{
|
|
Check_Object(this);
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
|
|
if(model->lightEntityResource != ResourceID::Null)
|
|
{
|
|
ClassID class_ID;
|
|
class_ID = GetClassIDFromDataListID(model->lightEntityResource);
|
|
Verify(class_ID != NullClassID);
|
|
|
|
LightEntity::CreateMessage entity_create_message(
|
|
sizeof(Entity::CreateMessage),
|
|
DefaultEventPriority,
|
|
CreateMessage::DefaultFlags,
|
|
class_ID,
|
|
LightEntity::DefaultFlags,
|
|
model->lightEntityResource,
|
|
GetLocalToWorld(),
|
|
0.0f,
|
|
ExecutionStateEngine::AlwaysExecuteState,
|
|
NameTable::NullObjectID,
|
|
Entity::DefaultAlignment
|
|
);
|
|
MemoryStream stream(&entity_create_message, entity_create_message.messageLength);
|
|
|
|
Entity *entity;
|
|
ReplicatorID beam_id = Connection::Hermit->GetNextReplicatorID();
|
|
entity = CreateEntity(&stream, &beam_id, false);
|
|
Check_Object(entity);
|
|
if(Map::GetInstance())
|
|
Map::GetInstance()->AddChild(entity);
|
|
lightEntity.Remove();
|
|
lightEntity.Add(Cast_Object(LightEntity *, entity));
|
|
entity->SyncMatrices(true);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
SearchLight::TakeCriticalHit()
|
|
{
|
|
Check_Object(this);
|
|
|
|
//Don't do anything here
|
|
return false;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void SearchLight::DestroySubsystem()
|
|
{
|
|
Check_Object(this);
|
|
|
|
Subsystem::DestroySubsystem();
|
|
HideBeam();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void SearchLight::HideBeam()
|
|
{
|
|
Check_Object(this);
|
|
|
|
if(lightEntity.GetCurrent())
|
|
{
|
|
// ElementRenderer::Element *element;
|
|
// element = lightEntity.GetCurrent()->GetElement();
|
|
// Check_Object(element);
|
|
// element->SetAlwaysCullMode();
|
|
lightEntity.GetCurrent()->lightIntensity = 0.0f;
|
|
}
|
|
if(lightConeEntity.GetCurrent())
|
|
{
|
|
ElementRenderer::Element *element;
|
|
element = lightConeEntity.GetCurrent()->GetElement();
|
|
Check_Object(element);
|
|
element->SetAlwaysCullMode();
|
|
}
|
|
|
|
isLightOn = false;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void SearchLight::ShowBeam()
|
|
{
|
|
Check_Object(this);
|
|
|
|
Check_Pointer(Mission::GetInstance());
|
|
|
|
if(Mission::GetInstance()->DoesAllowSearchLights())
|
|
{
|
|
if(lightEntity.GetCurrent())
|
|
{
|
|
lightEntity.GetCurrent()->lightIntensity = 1.0f;
|
|
}
|
|
if(lightConeEntity.GetCurrent())
|
|
{
|
|
ElementRenderer::Element *element;
|
|
element = lightConeEntity.GetCurrent()->GetElement();
|
|
Check_Object(element);
|
|
element->SetNeverCullMode();
|
|
|
|
}
|
|
|
|
isLightOn = true;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
SearchLight::TestInstance() const
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
SearchLight::CreateStream(ResourceID data_list, MemoryStream *stream)
|
|
{
|
|
Check_Pointer(stream);
|
|
|
|
stream->AllocateBytes(sizeof(SearchLight__CreateMessage));
|
|
Subsystem::CreateStream(data_list, stream);
|
|
|
|
SearchLight__CreateMessage *create_message = Cast_Pointer(
|
|
SearchLight__CreateMessage *, stream->GetPointer());
|
|
|
|
Str_Copy(create_message->siteName, _strlwr("site_light"), sizeof(create_message->siteName));
|
|
}
|