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.
416 lines
10 KiB
C++
416 lines
10 KiB
C++
//===========================================================================//
|
|
// File: bridge.cpp
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// 01/12/2000 AHF Inital base class
|
|
//===========================================================================//
|
|
|
|
#include "MW4Headers.hpp"
|
|
|
|
#include "cultural.hpp"
|
|
#include <adept\EntityManager.hpp>
|
|
#include "obstacle.hpp"
|
|
#include <adept\effect.hpp>
|
|
#include <adept\map.hpp>
|
|
#include <adept\damageobject.hpp>
|
|
#include "MWDamageObject.hpp"
|
|
#include <adept\application.hpp>
|
|
//#############################################################################
|
|
//############################### Cultural ############################
|
|
//#############################################################################
|
|
|
|
extern int g_nMR;
|
|
|
|
Cultural::ClassData* Cultural::DefaultData = NULL;
|
|
|
|
const Receiver::MessageEntry
|
|
Cultural::MessageEntries[]=
|
|
{
|
|
MESSAGE_ENTRY(Cultural, TakeDamage)
|
|
};
|
|
|
|
DWORD Cultural_Count = 0;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Cultural::InitializeClass()
|
|
{
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
CulturalClassID,
|
|
"MechWarrior4::Cultural",
|
|
Entity::DefaultData,
|
|
ELEMENTS(MessageEntries), MessageEntries,
|
|
(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
|
|
);
|
|
Register_Object(DefaultData);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Cultural__GameModel,
|
|
DeathEntityResource,
|
|
deathEntityResource,
|
|
ResourceID
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Cultural__GameModel,
|
|
DestroyedEffectResource,
|
|
destroyedEffectResource,
|
|
ResourceID
|
|
);
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Cultural__GameModel,
|
|
RammingDestroyedEffectResource,
|
|
rammingDestroyedEffectResource,
|
|
ResourceID
|
|
);
|
|
|
|
Cultural_Count = 0;
|
|
AddStatistic("Culturals", "culturals", gos_DWORD, &Cultural_Count, 0);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Cultural::TerminateClass()
|
|
{
|
|
Unregister_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Cultural* Cultural::Make(CreateMessage *message,ReplicatorID *base_id)
|
|
{
|
|
Cultural *new_entity = new Cultural(DefaultData, message, base_id, NULL);
|
|
Check_Object(new_entity);
|
|
return new_entity;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Cultural::Cultural(ClassData *class_data,CreateMessage *message,ReplicatorID *base_id,ElementRenderer::Element *element):
|
|
Entity(class_data, message, base_id, element)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(message);
|
|
Set_Statistic(Cultural_Count, Cultural_Count+1);
|
|
|
|
//
|
|
//--------------------------
|
|
// Create the damage Objects
|
|
//--------------------------
|
|
//
|
|
destroyableFlag = message->destroyableFlag;
|
|
|
|
//remove when content fixed
|
|
destroyableFlag = true;
|
|
|
|
lastHitType = RammingDamageFromAheadType;
|
|
|
|
|
|
delete executionState;
|
|
executionState = NULL;
|
|
|
|
|
|
if (Application::GetInstance()->applicationMode != Application::EditorMode)
|
|
{
|
|
|
|
NameTable *table = NameTable::GetInstance();
|
|
|
|
ObjectID id = table->FindID(instanceName);
|
|
|
|
table->SetName(id, NULL);
|
|
|
|
|
|
instanceName = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Cultural::~Cultural()
|
|
{
|
|
DESTRUCTOR("Cultural");
|
|
|
|
--Cultural_Count;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Cultural::TestInstance()
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|
|
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Cultural::Respawn(Entity::CreateMessage *message)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
|
|
Entity::Respawn(message);
|
|
destroyableFlag = true;
|
|
lastHitType = RammingDamageFromAheadType;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Cultural::ReactToHit(const Entity__TakeDamageMessage *message,Adept::DamageObject *part_hit)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
|
|
if (IsDestroyed())
|
|
return;
|
|
|
|
if (g_nMR == 2)
|
|
return;
|
|
//
|
|
// Save off the direction we were hit from as we have to initiate some destruction phases (trees) with knowledge of where
|
|
// we either were hit from, or run into from.
|
|
//
|
|
//
|
|
//
|
|
last_hit_normal = message->normal;
|
|
|
|
lastHitType = message->typeOfDamage;
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Cultural::ReactToDestruction(int damage_mode, int damage_type)
|
|
{
|
|
Check_Object(this);
|
|
|
|
|
|
if(!IsDestroyed())
|
|
{
|
|
|
|
SetDestroyedFlag(damage_mode);
|
|
|
|
|
|
MW4AI::g_Rect4DHash->RemovePermRect (this);
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
|
|
//
|
|
// Due to the network not being able to specify how something died, the trees need to do their differing
|
|
// reactions by whether they received a reactotohit message.
|
|
//
|
|
//
|
|
// Here we need to kick off the destruction effect with a normal from the direction of the damage
|
|
//
|
|
switch (lastHitType)
|
|
{
|
|
case BeamDamageType:
|
|
case MissileDamageType:
|
|
case ProjectileDamageType:
|
|
case SplashDamageType:
|
|
case HeatDamageType:
|
|
//
|
|
// don't use default here or it will always play the hit effect which we only want
|
|
// when shot.
|
|
//
|
|
// default:
|
|
CreateEffect(model->destroyedEffectResource, (Point3D)GetLocalToWorld(), last_hit_normal);
|
|
break;
|
|
/*
|
|
case RammingDamageFromAboveType:
|
|
case RammingDamageFromBelowType:
|
|
case RammingDamageFromLeftType:
|
|
case RammingDamageFromRightType:
|
|
case RammingDamageFromAheadType:
|
|
case RammingDamageFromBehindType:
|
|
case LavaDamageType;
|
|
case AmmoFireDamageType:
|
|
*/
|
|
}
|
|
|
|
CreateEffect(model->rammingDestroyedEffectResource, (Point3D)GetLocalToWorld(), last_hit_normal);
|
|
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);
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Effect*
|
|
Cultural::CreateEffect(const Adept::ResourceID& effect_id, const Point3D &location, const Normal3D &normal)
|
|
{
|
|
|
|
if (effect_id == ResourceID::Null)
|
|
return NULL;
|
|
|
|
Resource resource(effect_id);
|
|
Verify(resource.DoesResourceExist());
|
|
|
|
ClassID class_ID;
|
|
class_ID = Entity::GetClassIDFromDataListID(effect_id);
|
|
Verify(class_ID != NullClassID);
|
|
|
|
LinearMatrix4D effect_location = LinearMatrix4D::Identity;
|
|
effect_location.BuildTranslation(location);
|
|
|
|
|
|
|
|
Effect::CreateMessage effect_create_message(
|
|
sizeof(Effect::CreateMessage),
|
|
DefaultEventPriority,
|
|
Entity::CreateMessage::DefaultFlags,
|
|
class_ID,
|
|
Effect::DefaultFlags,
|
|
effect_id,
|
|
effect_location,
|
|
0.0f,
|
|
Entity::ExecutionStateEngine::AlwaysExecuteState,
|
|
NameTable::NullObjectID,
|
|
Entity::DefaultAlignment
|
|
);
|
|
MemoryStream stream(&effect_create_message, effect_create_message.messageLength);
|
|
|
|
Effect *entity;
|
|
ReplicatorID effect_rep_id = Connection::Hermit->GetNextReplicatorID();
|
|
entity = Cast_Object(Effect *,Entity::CreateEntity(&stream, &effect_rep_id, false));
|
|
Check_Object(entity);
|
|
Check_Object(Map::GetInstance());
|
|
Map::GetInstance()->AddChild(entity);
|
|
|
|
|
|
|
|
entity->SyncMatrices(true);
|
|
|
|
return entity;
|
|
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
Entity *
|
|
Cultural::CreateStaticHermitEntity(const Adept::ResourceID& entity_id)
|
|
{
|
|
|
|
if(entity_id == ResourceID::Null)
|
|
return false;
|
|
|
|
|
|
ClassID class_ID;
|
|
class_ID = GetClassIDFromDataListID(entity_id);
|
|
Verify(class_ID != NullClassID);
|
|
|
|
unsigned flags = HermitMode;
|
|
|
|
Entity::CreateMessage entity_create_message(
|
|
sizeof(Entity::CreateMessage),
|
|
DefaultEventPriority,
|
|
CreateMessage::DefaultFlags,
|
|
class_ID,
|
|
flags,
|
|
entity_id,
|
|
GetLocalToWorld(),
|
|
0.0f,
|
|
ExecutionStateEngine::NeverExecuteState,
|
|
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);
|
|
entity->SetPropType(MissionPropType);
|
|
Map::GetInstance()->AddChild(entity);
|
|
entity->SyncMatrices(true);
|
|
|
|
|
|
|
|
return entity;
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Cultural::RemoveFromExecution()
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(entityElement);
|
|
//Check_Object(executionState);
|
|
|
|
//executionState->RequestState(ExecutionStateEngine::NeverExecuteState);
|
|
entityElement->SetAlwaysCullMode();
|
|
EntityManager::GetInstance()->RemovePostCollisionExecution(this);
|
|
RemoveCollision();
|
|
|
|
SyncMatrices(true);
|
|
|
|
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Cultural::ReactToInternalDamage(int damage_mode)
|
|
{
|
|
_asm nop;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Cultural::TakeDamageMessageHandler(const TakeDamageMessage *message)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
Verify(message->messageID == TakeDamageMessageID);
|
|
|
|
if (IsDestroyable() && !IsDestroyed())
|
|
{
|
|
ReactToHit(message,NULL);
|
|
if (g_nMR != 2)
|
|
ReactToDestruction( InternalDamageObject::DestructionDamageMode, message->typeOfDamage);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
bool
|
|
Cultural::IsNeverExecuteState()
|
|
{
|
|
return true;
|
|
} |