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

415 lines
11 KiB
C++

//===========================================================================//
// File: Building.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 "Building.hpp"
#include "CombatAI.hpp"
#include "obstacle.hpp"
#include "Weapon.hpp"
#include <Adept\Site.hpp>
#include "MWMission.hpp"
#include "MWDamageObject.hpp"
//#############################################################################
//############################### Building ##############################
//#############################################################################
extern int g_nMR;
Building::ClassData*
Building::DefaultData = NULL;
DWORD MechWarrior4::Executed_Building_Count = 0;
bool MechWarrior4::Building::m_BuildingsAddedToCellMap = false;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Building::InitializeClass()
{
Verify(!DefaultData);
DefaultData =
new ClassData(
BuildingClassID,
"MechWarrior4::Building",
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);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Building::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Building*
Building::Make(
CreateMessage *message,
ReplicatorID *base_id
)
{
gos_PushCurrentHeap(Heap);
Building *new_entity =
new Building(DefaultData, message, base_id, NULL);
gos_PopCurrentHeap();
Check_Object(new_entity);
return new_entity;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Building::Building(
ClassData *class_data,
CreateMessage *message,
ReplicatorID *base_id,
ElementRenderer::Element *element
):
MWObject(class_data, message, base_id, element)
,
//the abl call markBuildingAsScorable is made in siege assault
//strong hold type maps.
//If set, when the building is destroyed points are awarded.
//Turrets will always be scored.
m_scoreThisBuilding (false)
{
Check_Pointer(this);
Check_Object(message);
CommonCreation(message);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Building::CommonCreation(CreateMessage *message)
{
Check_Object(this);
Check_Object(message);
m_AddedToSensorCellMap = false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Building::LoadAnimationScripts()
{
MWObject::LoadAnimationScripts();
if (!m_AI)
{
const GameModel *model = GetGameModel();
if(model->animScriptName[0] != NULL)
{
executionState->RequestState(ExecutionStateEngine::AlwaysExecuteState);
animStateEngine->RequestState(AnimationStateEngine::Test1State);
}
// if(!executingSubsystems.IsEmpty())
// executionState->RequestState(ExecutionStateEngine::AlwaysExecuteState);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Building::Respawn(Entity::CreateMessage *message)
{
Check_Object(this);
Check_Object(message);
MWObject::Respawn(message);
CreateMessage *building_message = Cast_Pointer(CreateMessage *, message);
CommonCreation(building_message);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Building::~Building()
{
DESTRUCTOR("Building");
}
void Building::TurnOn (void)
{
lastParameterization = gos_GetElapsedTime ();
const GameModel *model = GetGameModel();
if(model->animScriptName[0] != NULL)
{
executionState->RequestState(ExecutionStateEngine::AlwaysExecuteState);
animStateEngine->RequestState(AnimationStateEngine::Test1State);
}
if(!executingSubsystems.IsEmpty())
executionState->RequestState(ExecutionStateEngine::AlwaysExecuteState);
}
void Building::TurnOff (void)
{
executionState->RequestState(ExecutionStateEngine::NeverExecuteState);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Building::Reuse(
const CreateMessage *message,
ReplicatorID *base_id
)
{
Check_Object(this);
STOP(("Not implemented"));
MWObject::Reuse(message, base_id);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
Building::GetExecutionSlot()
{
Check_Object(this);
return BuildingExecutionSlot;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Building::PreCollisionExecute(Stuff::Time till)
{
Check_Object(this);
Check_Object(animStateEngine);
PRECOLLISION_LOGIC("Building");
Scalar time_slice = GetTimeSlice(till);
Verify(time_slice > 0.0f);
Verify(executionState->GetState() != ExecutionStateEngine::NeverExecuteState);
Check_Object(animStateEngine);
if(animStateEngine->GetState() != AnimationStateEngine::UninitializedState)
{
animStateEngine->RunStates(time_slice);
}
Set_Statistic(Executed_Building_Count, Executed_Building_Count+1);
MWObject::PreCollisionExecute(till);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
#if defined(LAB_ONLY)
void Building::SyncMatrices(bool update_matrix)
{
SYNC_LOGIC("Building");
BaseClass::SyncMatrices(update_matrix);
}
#endif
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Building::ReactToDestruction(int damage_mode, int damage_type)
{
Check_Object(this);
if(!IsDestroyed())
{
//added for scroing objective building in strong holds and siege assault
if (m_scoreThisBuilding)
{
Check_Object (Mission::GetInstance());
Mission::GetInstance()->ScoringReactToBuildingDeath (m_whoShotMeLast, GetReplicatorID());
}
if(m_AI)
{
Check_Object(m_AI);
m_AI->Die();
}
SetDestroyedFlag(damage_mode);
if (damage_type != SplashDamageType)
DealSplashDamage();
MW4AI::g_Rect4DHash->RemovePermRect (this);
const GameModel *model = GetGameModel();
Check_Object(model);
// CreateEffect(model->destroyedEffectResource, (Point3D)GetLocalToWorld());
CreateEffect(model->destroyedEffectResource, this);
Entity *death_entity = CreateStaticHermitEntity(model->deathEntityResource);
if((death_entity) && (!m_deathEntity.GetCurrent()))
{
m_deathEntity.Remove();
m_deathEntity.Add(death_entity);
}
RemoveFromExecution();
}
Entity::ReactToDestruction(damage_mode, damage_type);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Building::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Building::ReactToHit(const Entity__TakeDamageMessage *message,Adept::DamageObject *part_hit)
{
Check_Object(this);
Check_Object(message);
MWObject::ReactToHit(message,part_hit);
if (g_nMR == 2)
return;
// TODO: this should be more general and should take near
// misses into account as well as direct hits -- PAULT
if (GetAI() != 0)
{
NotifyAIShot(*(GetAI()),message->inflictingEntityID);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Stuff::Scalar
Building::FriendlyFireDamageMultiplier() const
{
if (MW4AI::UserConstants::Instance() != 0)
{
return (MW4AI::UserConstants::Instance()->Get(MW4AI::UserConstants::building_ff_multiplier));
}
return (1);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Building::GetLineOfSight(Stuff::LinearMatrix4D& line_of_sight)
{
Stuff::ChainIteratorOf<MechWarrior4::Weapon*> i(&weaponChain);
MechWarrior4::Weapon* weapon = i.ReadAndNext();
if ((weapon != 0) &&
(weapon->sitePointer != 0) &&
(weapon->sitePointer->GetParent() != 0))
{
line_of_sight = weapon->sitePointer->GetParent()->GetLocalToWorld();
return;
}
MWObject::GetLineOfSight(line_of_sight);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void AddOrRemoveFromMap(SensorCellMap& sensor_cell_map, int name_table_array, bool add)
{
NameTable *table = NameTable::GetInstance();
int size(table->nameTableArray[name_table_array].GetLength());
{for (int i = 0;
i < size;
++i)
{
NameTableEntry *data = &table->nameTableArray [name_table_array][i];
Adept::Entity* entity = data->dataPointer->GetCurrent ();
if ((entity != 0) &&
(entity->IsDerivedFrom(Building::DefaultData) == true))
{
Building* building = Cast_Object(Building*,entity);
if (building->m_AddedToSensorCellMap != add)
{
if (add == true)
{
sensor_cell_map.Add(building,building->GetLocalToWorld());
}
else
{
sensor_cell_map.Remove(building,building->GetLocalToWorld());
}
}
building->m_AddedToSensorCellMap = add;
}
}}
}
void
Building::AddAllBuildingsToSensorCellMap()
{
if ((NameTable::GetInstance() == 0) ||
(m_BuildingsAddedToCellMap == true) ||
(MWMission::GetInstance() == 0))
{
return;
}
MWMission* mwmission = Cast_Object(MWMission*,MWMission::GetInstance());
AddOrRemoveFromMap(mwmission->m_BuildingCellMap,NameTable::BuildingArray,true);
AddOrRemoveFromMap(mwmission->m_VehicleAndTurretCellMap,NameTable::TurretArray,true);
m_BuildingsAddedToCellMap = true;
}
void
Building::RemoveAllBuildingsFromSensorCellMap()
{
if ((NameTable::GetInstance() == 0) ||
(m_BuildingsAddedToCellMap == false) ||
(MWMission::GetInstance() == 0))
{
return;
}
MWMission* mwmission = Cast_Object(MWMission*,MWMission::GetInstance());
AddOrRemoveFromMap(mwmission->m_BuildingCellMap,NameTable::BuildingArray,false);
AddOrRemoveFromMap(mwmission->m_VehicleAndTurretCellMap,NameTable::TurretArray,false);
m_BuildingsAddedToCellMap = false;
}