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.
3366 lines
82 KiB
C++
3366 lines
82 KiB
C++
#include "MW4Headers.hpp"
|
|
|
|
#include "MWObject.hpp"
|
|
#include "Subsystem.hpp"
|
|
#include "Torso.hpp"
|
|
#include "AnimationState.hpp"
|
|
#include "MWDamageObject.hpp"
|
|
#include "Weapon.hpp"
|
|
#include "Sensor.hpp"
|
|
#include "Beagle.hpp"
|
|
#include "HeatManager.hpp"
|
|
#include "AMS.hpp"
|
|
#include "SearchLight.hpp"
|
|
#include "Mech_AI.hpp"
|
|
#include "MWMission.hpp"
|
|
#include "gameinfo.hpp"
|
|
#include "AI_Statistics.hpp"
|
|
#include "obstacle.hpp"
|
|
#include "ECM.hpp"
|
|
#include "VehicleInterface.hpp"
|
|
#include "SubsystemClassData.hpp"
|
|
#include "MWApplication.hpp"
|
|
#include "DamageDispatch.hpp"
|
|
|
|
// MSL 5.02 SubSystems
|
|
//#include "EnhancedOptics.hpp"
|
|
#include "IFF_Jammer.hpp"
|
|
#include "AdvancedGyro.hpp"
|
|
|
|
#include <Adept\DamageObject.hpp>
|
|
#include <Adept\EntityManager.hpp>
|
|
#include <Adept\Effect.hpp>
|
|
#include <Adept\Map.hpp>
|
|
#include <Adept\Site.hpp>
|
|
#include <Adept\CollisionGrid.hpp>
|
|
#include <Adept\CollisionVolume.hpp>
|
|
#include <Adept\Renderer.hpp>
|
|
|
|
|
|
extern int g_nMR;
|
|
|
|
IdleEffectObject::IdleEffectObject() :
|
|
Plug(Plug::DefaultData),
|
|
idleEffect(NULL),
|
|
siteSlot(NULL)
|
|
{}
|
|
|
|
//#############################################################################
|
|
//############################### MWObject ##############################
|
|
//#############################################################################
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
MWObject::ClassData*
|
|
MWObject::DefaultData = NULL;
|
|
|
|
const Receiver::MessageEntry
|
|
MWObject::MessageEntries[]=
|
|
{
|
|
MESSAGE_ENTRY(MWObject, TakeDamage)
|
|
};
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::InitializeClass()
|
|
{
|
|
Check_Object(MWMover::ExecutionStateEngine::DefaultData);
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
MWObjectClassID,
|
|
"MechWarrior4::MWObject",
|
|
BaseClass::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,
|
|
AnimationStateEngine::Make
|
|
);
|
|
Register_Object(DefaultData);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
MWObject__GameModel,
|
|
DeathEntityResource,
|
|
deathEntityResource,
|
|
ResourceID
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
MWObject__GameModel,
|
|
DestroyedEffectResource,
|
|
destroyedEffectResource,
|
|
ResourceID
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
MWObject__GameModel,
|
|
SecondaryDeathEntityResource,
|
|
secondaryDeathEntityResource,
|
|
ResourceID
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
MWObject__GameModel,
|
|
SecondaryDestroyedEffectResource,
|
|
secondaryDestroyedEffectResource,
|
|
ResourceID
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
MWObject__GameModel,
|
|
VehicleTonnage,
|
|
vehicleTonnage,
|
|
Scalar
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
MWObject__GameModel,
|
|
MaxVehicleTonnage,
|
|
maxVehicleTonnage,
|
|
Scalar
|
|
);
|
|
|
|
CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
MWObject__GameModel,
|
|
EyeSiteName,
|
|
eyeSiteName,
|
|
const char *,
|
|
CharClassID
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
MWObject__GameModel,
|
|
PartDestructionEffectResource,
|
|
partDestructionEffectResource,
|
|
ResourceID
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
MWObject__GameModel,
|
|
SplashDamageRadius,
|
|
splashDamageRadius,
|
|
Scalar
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
MWObject__GameModel,
|
|
SplashDamageAmount,
|
|
splashDamageAmount,
|
|
Scalar
|
|
);
|
|
|
|
CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
MWObject__GameModel,
|
|
VehicleBattleValue,
|
|
vehicleBattleValue,
|
|
int,
|
|
IntClassID
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
MWObject__GameModel,
|
|
CoolantEffectResource,
|
|
coolantEffectResource,
|
|
ResourceID
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
MWObject__GameModel,
|
|
SplashHeatAmount,
|
|
splashHeatAmount,
|
|
Scalar
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
MWObject__GameModel,
|
|
EjectEffectResource,
|
|
ejectEffectResource,
|
|
ResourceID
|
|
);
|
|
|
|
CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
MWObject__GameModel,
|
|
NameIndex,
|
|
m_nameIndex,
|
|
int,
|
|
IntClassID
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
MWObject__GameModel,
|
|
OverHeatEffectResource,
|
|
overHeatEffectResource,
|
|
ResourceID
|
|
);
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::TerminateClass()
|
|
{
|
|
Unregister_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
MWObject*
|
|
MWObject::Make(
|
|
CreateMessage *message,
|
|
ReplicatorID *base_id
|
|
)
|
|
{
|
|
Check_Object(message);
|
|
gos_PushCurrentHeap(Heap);
|
|
MWObject *new_object = new
|
|
MWObject(DefaultData, message, base_id, NULL);
|
|
gos_PopCurrentHeap();
|
|
Check_Object(new_object);
|
|
|
|
return new_object;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Replicator::CreateMessage*
|
|
MWObject::SaveMakeMessage(MemoryStream *stream, ResourceFile *res_file)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(stream);
|
|
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// Make sure there is enough room for the factory request on the stream
|
|
//---------------------------------------------------------------------
|
|
//
|
|
stream->AllocateBytes(sizeof(CreateMessage));
|
|
BaseClass::SaveMakeMessage(stream, res_file);
|
|
CreateMessage *message =
|
|
Cast_Pointer(CreateMessage*, stream->GetPointer());
|
|
message->messageLength = sizeof(*message);
|
|
|
|
//
|
|
//--------------------------------------------
|
|
// Create the memory stream for the subsystems
|
|
//--------------------------------------------
|
|
//
|
|
DynamicMemoryStream subsystem_stream(sizeof(WORD));
|
|
subsystem_stream << static_cast<WORD>(0);
|
|
ReplicatorID span = ReplicatorID::Null;
|
|
ChainIteratorOf<Subsystem *> sub_iterator(&subsystemsInVehicle);
|
|
Subsystem *subsystem;
|
|
|
|
while((subsystem = sub_iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(subsystem);
|
|
Replicator::CreateMessage *create_message =
|
|
subsystem->SaveMakeMessage(&subsystem_stream, res_file);
|
|
if (create_message)
|
|
{
|
|
Check_Object(create_message);
|
|
span += create_message->replicatorID;
|
|
subsystem_stream.AdvancePointer(create_message->messageLength);
|
|
}
|
|
}
|
|
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
// If we actually wrote out some children, rewind the stream and save it to
|
|
// the resource. Otherwise, just set the resourceID to NULL
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
|
|
//This stream must be written out to the current res_file and not core.
|
|
if (subsystem_stream.GetBytesUsed() > sizeof(WORD))
|
|
{
|
|
subsystem_stream.Rewind();
|
|
Verify(span.localID > 0);
|
|
subsystem_stream << span.localID;
|
|
MString sub_resource_name = instanceName;
|
|
sub_resource_name += "{Subsystem}";
|
|
Resource subsystem_resource((const char *)sub_resource_name, res_file);
|
|
subsystem_resource.Save(&subsystem_stream, NULL);
|
|
Check_Object(&subsystem_resource);
|
|
message->subsystemStreamResourceID = subsystem_resource.GetResourceID();
|
|
message->replicatorID += span;
|
|
}
|
|
else
|
|
{
|
|
message->subsystemStreamResourceID = ResourceID::Null;
|
|
}
|
|
|
|
//
|
|
//------------------------------------------------------
|
|
//Need to save damage objects and Internal DamageObjects
|
|
//------------------------------------------------------
|
|
//
|
|
//We need to check if we have changed or not...if we have then save to the
|
|
//the res file given...if not then we need to just do nothing becuase we are already
|
|
//in the core file and just set the message
|
|
message->damageStreamResourceID = damageStreamResourceID;
|
|
if((m_hasExecuted) && (!m_markedForSalvage))
|
|
{
|
|
DynamicMemoryStream damage_stream;
|
|
DamageObject *damage_object;
|
|
SortedChainIteratorOf<DamageObject *, int> damage_iterator(&damageObjects);
|
|
damage_stream << damage_iterator.GetSize();
|
|
while((damage_object = damage_iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(damage_object);
|
|
damage_object->Save(&damage_stream);
|
|
}
|
|
|
|
MWInternalDamageObject *internal_damage_object;
|
|
SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&internalDamageObjects);
|
|
damage_stream << internal_iterator.GetSize();
|
|
while((internal_damage_object = internal_iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(internal_damage_object);
|
|
internal_damage_object->Save(&damage_stream);
|
|
}
|
|
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
// If we actually wrote out some children, rewind the stream and save it to
|
|
// the resource. Otherwise, just set the resourceID to NULL
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
|
|
if (damage_stream.GetBytesUsed())
|
|
{
|
|
Resource damage_resource(NULL, res_file);
|
|
damage_resource.Save(&damage_stream, NULL);
|
|
Check_Object(&damage_resource);
|
|
message->damageStreamResourceID = damage_resource.GetResourceID();
|
|
}
|
|
else
|
|
{
|
|
message->damageStreamResourceID = ResourceID::Null;
|
|
}
|
|
}
|
|
|
|
message->skinPrefix = m_skinPrefix;
|
|
message->teamDecal = m_teamDecal;
|
|
message->pilotDecal = m_pilotDecal;
|
|
|
|
message->nameIndex = m_localizeIndex;
|
|
message->doesHaveInstanceName = m_doesHaveInstanceName;
|
|
|
|
return message;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::LoadSubsystemsFromResource(
|
|
const ResourceID &subsystem_stream_id,
|
|
ReplicatorID *base_id
|
|
)
|
|
{
|
|
Resource stream(subsystem_stream_id);
|
|
Verify(stream.DoesResourceExist());
|
|
stream.AdvancePointer(sizeof(WORD));
|
|
|
|
while (stream.GetBytesRemaining() > 0)
|
|
{
|
|
Entity::CreateMessage *message =
|
|
Cast_Pointer(Entity::CreateMessage*, stream.GetPointer());
|
|
|
|
Entity *entity = CreateEntity(&stream, base_id);
|
|
Check_Object(entity);
|
|
|
|
AddChild(entity);
|
|
Subsystem *subsystem;
|
|
subsystem = Cast_Object(Subsystem *, entity);
|
|
|
|
//Dave here is where you want to do a apendparentname function
|
|
|
|
if (subsystem->IsDerivedFrom(Torso::DefaultData))
|
|
{
|
|
Torso* torso = Cast_Object(Torso*, subsystem);
|
|
if (std::find(m_Torsos.begin(),m_Torsos.end(),torso) == m_Torsos.end())
|
|
{
|
|
m_Torsos.push_back(torso);
|
|
}
|
|
}
|
|
if (subsystem->IsDerivedFrom(SearchLight::DefaultData))
|
|
{
|
|
searchLight = Cast_Object(SearchLight *, subsystem);
|
|
}
|
|
|
|
stream.AdvancePointer(message->messageLength);
|
|
}
|
|
|
|
//stream.UnloadData();
|
|
|
|
m_hasExecuted = false;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::LoadDamageObjectsFromResource(
|
|
const ResourceID &damage_stream_id
|
|
)
|
|
{
|
|
Resource stream(damage_stream_id);
|
|
Verify(stream.DoesResourceExist());
|
|
|
|
while (stream.GetBytesRemaining() > 0)
|
|
{
|
|
RegisteredClass::ClassID class_id;
|
|
stream >> class_id;
|
|
RegisteredClass::ClassData *class_data = NULL;
|
|
class_data = RegisteredClass::FindClassData(class_id);
|
|
if(class_data == DamageObject::DefaultData)
|
|
{
|
|
DamageObject *damage_object;
|
|
DamageObject::ClassData *damage_class_data =
|
|
Cast_Pointer(DamageObject::ClassData*, class_data);
|
|
|
|
gos_PushCurrentHeap(Heap);
|
|
damage_object = new DamageObject(
|
|
damage_class_data,
|
|
&stream
|
|
);
|
|
gos_PopCurrentHeap();
|
|
Check_Object(damage_object);
|
|
damageObjects.AddValue(damage_object, damage_object->armorZone);
|
|
}
|
|
else
|
|
{
|
|
MWInternalDamageObject *internal_damage_object;
|
|
MWInternalDamageObject::ClassData *damage_class_data =
|
|
Cast_Pointer(MWInternalDamageObject::ClassData*, class_data);
|
|
|
|
gos_PushCurrentHeap(Heap);
|
|
internal_damage_object = new MWInternalDamageObject(
|
|
damage_class_data,
|
|
&stream
|
|
);
|
|
gos_PopCurrentHeap();
|
|
Check_Object(internal_damage_object);
|
|
internalDamageObjects.AddValue(
|
|
internal_damage_object, internal_damage_object->damageZone);
|
|
}
|
|
}
|
|
|
|
stream.UnloadData();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::LoadIdleEffectsFromResource(const ResourceID &effects_stream_id)
|
|
{
|
|
Resource stream(effects_stream_id);
|
|
Verify(stream.DoesResourceExist());
|
|
|
|
while (stream.GetBytesRemaining() > 0)
|
|
{
|
|
|
|
IdleEffectObject *idle_effect_object;
|
|
idle_effect_object = new IdleEffectObject();
|
|
stream >> idle_effect_object->effectResourceID;
|
|
MString site_name;
|
|
stream >> site_name;
|
|
idle_effect_object->siteSlot.Remove();
|
|
Site *site_pointer = FindSite(site_name);
|
|
Check_Object(site_pointer);
|
|
idle_effect_object->siteSlot.Add(site_pointer);
|
|
idle_effect_object->idleEffect.Remove();
|
|
Effect *idle_effect = CreateIdleEffect(idle_effect_object);
|
|
Check_Object(idle_effect);
|
|
idle_effect_object->idleEffect.Add(idle_effect);
|
|
idleEffects.Add(idle_effect_object);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Effect*
|
|
MWObject::CreateIdleEffect(IdleEffectObject *effect_object)
|
|
{
|
|
Check_Object(effect_object);
|
|
|
|
if(effect_object->effectResourceID == ResourceID::Null)
|
|
return NULL;
|
|
|
|
Resource idle_resource(effect_object->effectResourceID);
|
|
if(idle_resource.DoesResourceExist())
|
|
{
|
|
ClassID class_ID;
|
|
class_ID = GetClassIDFromDataListID(effect_object->effectResourceID);
|
|
Verify(class_ID != NullClassID);
|
|
|
|
LinearMatrix4D effect_position = LinearMatrix4D::Identity;
|
|
UnitVector3D unit_forward;
|
|
Site *site_pointer = effect_object->siteSlot.GetCurrent();
|
|
Check_Object(site_pointer);
|
|
LinearMatrix4D site_position = site_pointer->GetLocalToWorld();
|
|
site_position.GetLocalForwardInWorld(&unit_forward);
|
|
effect_position.AlignLocalAxisToWorldVector(unit_forward, Y_Axis, X_Axis, Z_Axis);
|
|
Point3D effect_translation;
|
|
effect_translation = site_pointer->GetLocalToWorld();
|
|
effect_position.BuildTranslation(effect_translation);
|
|
|
|
Effect::CreateMessage effect_create_message(
|
|
sizeof(Effect::CreateMessage),
|
|
DefaultEventPriority,
|
|
CreateMessage::DefaultFlags,
|
|
class_ID,
|
|
Effect::DefaultFlags|Effect::LoopFlag,
|
|
effect_object->effectResourceID,
|
|
effect_position,
|
|
0.0f,
|
|
ExecutionStateEngine::AlwaysExecuteState,
|
|
NameTable::NullObjectID,
|
|
Entity::DefaultAlignment
|
|
);
|
|
MemoryStream stream(&effect_create_message, effect_create_message.messageLength);
|
|
|
|
Entity *entity;
|
|
ReplicatorID effect_id = Connection::Hermit->GetNextReplicatorID();
|
|
entity = CreateEntity(&stream, &effect_id, false);
|
|
Check_Object(Map::GetInstance());
|
|
Map::GetInstance()->AddChild(entity);
|
|
Effect *effect;
|
|
effect = Cast_Object(Effect *, entity);
|
|
effect->SetFollowEntity(site_pointer);
|
|
entity->SyncMatrices(true);
|
|
|
|
|
|
return effect;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
MWObject::MWObject(
|
|
ClassData *class_data,
|
|
CreateMessage *message,
|
|
ReplicatorID *base_id,
|
|
ElementRenderer::Element *element
|
|
):
|
|
MWMover(class_data, message, base_id, element),
|
|
armatureChain(NULL),
|
|
subsystemsInVehicle(NULL),
|
|
executingSubsystems(NULL),
|
|
damageObjects(NULL, false),
|
|
internalDamageObjects(NULL, true),
|
|
idleEffects(NULL),
|
|
weaponChain(NULL),
|
|
eyeSitePointer(NULL),
|
|
sensor(NULL),
|
|
beagle(NULL),
|
|
ams(NULL),
|
|
m_TargetDesirability(desirability_invalid),
|
|
entitiesToSync(NULL),
|
|
m_FindObjectCache(NULL),
|
|
m_FindObjectList(NULL),
|
|
m_VisibleOnSensors(true),
|
|
splashedEntities(NULL),
|
|
// MSL 5.02 SubSystems
|
|
// enhancedOptics(NULL),
|
|
advancedGyro(NULL),
|
|
iff_jammer(NULL)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(message);
|
|
|
|
CommonCreation(message);
|
|
|
|
m_AI = NULL;
|
|
m_bHasAI = false;
|
|
|
|
ecm = NULL;
|
|
beagle = NULL;
|
|
searchLight = NULL;
|
|
vehicleInterface = NULL;
|
|
invulnerable=false;
|
|
|
|
m_markedForSalvage = false;
|
|
|
|
m_localizeIndex = message->nameIndex;
|
|
m_doesHaveInstanceName = message->doesHaveInstanceName;
|
|
|
|
//
|
|
//----------------------
|
|
// Create the subsystems
|
|
//----------------------
|
|
//
|
|
subsystemStreamResourceID = message->subsystemStreamResourceID;
|
|
|
|
if(message->subsystemStreamResourceID != ResourceID::Null)
|
|
{
|
|
LoadSubsystemsFromResource(
|
|
message->subsystemStreamResourceID,
|
|
base_id
|
|
);
|
|
}
|
|
|
|
//
|
|
//--------------------------
|
|
// Create the damage Objects
|
|
//--------------------------
|
|
//
|
|
damageStreamResourceID = message->damageStreamResourceID;
|
|
|
|
if(message->damageStreamResourceID != ResourceID::Null)
|
|
{
|
|
LoadDamageObjectsFromResource(
|
|
message->damageStreamResourceID
|
|
);
|
|
}
|
|
|
|
const GameModel *game_model = GetGameModel();
|
|
Check_Object(game_model);
|
|
|
|
m_heatManager = NULL;
|
|
|
|
m_skinPrefix = message->skinPrefix;
|
|
m_pilotDecal = message->pilotDecal;
|
|
m_teamDecal = message->teamDecal;
|
|
|
|
|
|
MakeArmatureChain();
|
|
MakeAnimationArray();
|
|
ConnectDamageObjects();
|
|
HookUpSubsystems();
|
|
|
|
InitializeArmorArray ();
|
|
|
|
//
|
|
//------------------------
|
|
// Create the Idle Effects
|
|
//------------------------
|
|
//
|
|
if(game_model->idleEffectResourceID != ResourceID::Null)
|
|
{
|
|
LoadIdleEffectsFromResource(game_model->idleEffectResourceID);
|
|
}
|
|
|
|
//
|
|
//------------------------------
|
|
// Load up the animation engines
|
|
//------------------------------
|
|
//
|
|
AnimationStateEngine::FactoryRequest request;
|
|
request.currentState = AnimationStateEngine::UninitializedState;
|
|
animStateEngine = (*((MWObject::ClassData*)GetClassData())->animationStateFactory)(this, &request);
|
|
Register_Object(animStateEngine);
|
|
|
|
|
|
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
MWApplication *app = MWApplication::GetInstance();
|
|
|
|
if (game_model->animScriptName[0] != NULL)
|
|
{
|
|
app->AddToAnimationLoadQue(this);
|
|
}
|
|
|
|
MWMover* eye = FindChildMover(model->eyeSiteName);
|
|
if(eye)
|
|
eyeSitePointer.Add(eye);
|
|
|
|
originalCollisionMask = GetCollisionMask();
|
|
originalCullMode = GetElement()->GetCullMode();
|
|
jointRunningLight = NULL;
|
|
jointRunningLight = FindChildMover("joint_runninglights");
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
|
|
int temporaryQuickIDLookup[COMPRESS_JOINT_COUNT];
|
|
|
|
void
|
|
MWObject::LoadAnimationScripts()
|
|
{
|
|
|
|
|
|
for (int i = 0; i < COMPRESS_JOINT_COUNT; ++i)
|
|
{
|
|
temporaryQuickIDLookup[i] = -1;
|
|
}
|
|
|
|
Stuff::ChainIteratorOf<MWMover*> iterator(&armatureChain);
|
|
MWMover *mover;
|
|
|
|
i = 0;
|
|
while ((mover = iterator.ReadAndNext()) != NULL)
|
|
{
|
|
MString temp;
|
|
int index = MW4Animation::CompressName(mover->instanceName, temp);
|
|
if (index != -1)
|
|
{
|
|
Verify(index < COMPRESS_JOINT_COUNT);
|
|
Verify(index >= 0);
|
|
|
|
temporaryQuickIDLookup[index] = i;
|
|
}
|
|
|
|
++i;
|
|
}
|
|
|
|
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
if (model->animScriptName[0] != NULL && !animStateEngine->alreadyLoaded)
|
|
{
|
|
animStateEngine->LoadScript(model->animScriptName);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void MWObject::InitializeArmorArray()
|
|
{
|
|
Check_Object(this);
|
|
|
|
m_HitPoints = 0;
|
|
SortedChainIteratorOf<Adept::DamageObject*,int> iter(&damageObjects);
|
|
DamageObject *fred;
|
|
while ((fred = iter.ReadAndNext ()) != NULL)
|
|
{
|
|
m_HitPoints += fred->currentArmorValue;
|
|
if (fred->internalDamageObject)
|
|
{
|
|
m_HitPoints += fred->internalDamageObject->currentInternalDamage;
|
|
fred->internalDamageObject->SetHitPointPointer (&m_HitPoints);
|
|
}
|
|
fred->SetHitPointPointer (&m_HitPoints);
|
|
}
|
|
if (m_HitPoints == 0)
|
|
m_HitPoints = 1;
|
|
m_MaxHitPoints = m_HitPoints;
|
|
for(int i=0; i<12; i++)
|
|
{
|
|
armorArray[i] = -1.0f;
|
|
DamageObject *damage_object = damageObjects.Find(i);
|
|
if(damage_object)
|
|
{
|
|
armorArray[i] = damage_object->armorLevel;
|
|
damage_object->SetArmorArrayEntry(&armorArray[i]);
|
|
}
|
|
else
|
|
{
|
|
armorArray[i] = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void MWObject::CommonCreation(CreateMessage *message)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
|
|
for (int i=0;i<11;i++)
|
|
armorArray[i] = -1.0f;
|
|
|
|
const GameModel *game_model = GetGameModel();
|
|
Check_Object(game_model);
|
|
|
|
vehicleShutDown = false;
|
|
vehicleJustPoweredUp = false;
|
|
|
|
animationVelocity = Vector3D::Identity;
|
|
|
|
tonage = game_model->vehicleTonnage;
|
|
battleValue = game_model->vehicleBattleValue;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void MWObject::Respawn(Entity::CreateMessage *message)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
|
|
BaseClass::Respawn(message);
|
|
CreateMessage *object_message = Cast_Pointer(CreateMessage *, message);
|
|
CommonCreation(object_message);
|
|
|
|
animStateEngine->Reset();
|
|
|
|
//
|
|
//-----------------------------------------
|
|
//Load up the Damage Objects and Subsystems
|
|
//-----------------------------------------
|
|
//
|
|
ReuseDamageObjects();
|
|
|
|
if(object_message->subsystemStreamResourceID != ResourceID::Null)
|
|
{
|
|
Resource stream(object_message->subsystemStreamResourceID);
|
|
Verify(stream.DoesResourceExist());
|
|
ReuseSubsystems(&stream);
|
|
}
|
|
|
|
ReuseArmature();
|
|
|
|
|
|
|
|
//
|
|
// If you set to NeverCullMode, it screws up the sphere sync method.
|
|
// this results in splash damage not working after a respawn.
|
|
//
|
|
// entityElement->SetNeverCullMode();
|
|
GetElement()->SetCullMode(originalCullMode );
|
|
|
|
|
|
SetCollisionMask(originalCollisionMask);
|
|
|
|
if (GetAI() != 0)
|
|
{
|
|
if (MechWarrior4::AI::GetGraveyard() != 0)
|
|
{
|
|
MechWarrior4::AI::GetGraveyard()->NotifyCreated(objectID);
|
|
}
|
|
|
|
GetAI()->NotifyRespawned();
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
MWObject::~MWObject()
|
|
{
|
|
|
|
DESTRUCTOR("MWObject");
|
|
|
|
Unregister_Object(animStateEngine);
|
|
delete animStateEngine;
|
|
|
|
if (animationArray != NULL)
|
|
{
|
|
|
|
Unregister_Pointer(animationArray);
|
|
delete[] animationArray;
|
|
|
|
}
|
|
|
|
if (lastTriggerArray != NULL)
|
|
{
|
|
Unregister_Pointer(lastTriggerArray);
|
|
delete[] lastTriggerArray;
|
|
}
|
|
|
|
|
|
damageObjects.DeletePlugs();
|
|
internalDamageObjects.DeletePlugs();
|
|
idleEffects.DeletePlugs();
|
|
|
|
if(m_heatManager)
|
|
delete m_heatManager;
|
|
|
|
if (m_FindObjectCache)
|
|
delete m_FindObjectCache;
|
|
|
|
if (m_FindObjectList)
|
|
delete m_FindObjectList;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::MakeAnimationArray()
|
|
{
|
|
Stuff::ChainIteratorOf<MWMover*> iterator(&armatureChain);
|
|
MWMover *mover;
|
|
|
|
animationArrayCount = iterator.GetSize();
|
|
if (animationArrayCount == 0)
|
|
{
|
|
animationArray = NULL;
|
|
lastTriggerArray = NULL;
|
|
return;
|
|
}
|
|
animationArray = new MWMover *[animationArrayCount];
|
|
Register_Pointer(animationArray);
|
|
|
|
|
|
lastTriggerArray = new int [animationArrayCount];
|
|
Register_Pointer(lastTriggerArray);
|
|
|
|
for (int counter = 0; counter < animationArrayCount; counter++)
|
|
{
|
|
lastTriggerArray[counter] = 0;
|
|
}
|
|
|
|
|
|
|
|
int i = 0;
|
|
while ((mover = iterator.ReadAndNext()) != NULL)
|
|
{
|
|
animationArray[i] = mover;
|
|
i++;
|
|
}
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void
|
|
MWObject::ApplyChannel
|
|
(
|
|
MW4Animation::ChannelApplication &channel_data,
|
|
int joint_index,
|
|
void *user_data
|
|
)
|
|
{
|
|
|
|
MWObject *mw_object;
|
|
mw_object = Cast_Object(MWObject*, user_data);
|
|
|
|
Stuff::UnitQuaternion rotation;
|
|
Stuff::Point3D position;
|
|
|
|
LinearMatrix4D new_local_to_parent;
|
|
MWMover *mover = mw_object->animationArray[joint_index];
|
|
|
|
|
|
Check_Object(mover);
|
|
|
|
#if 0
|
|
const char *compare_name = mover->instanceName;
|
|
if((compare_name = strstr(compare_name, "::")) != NULL)
|
|
{
|
|
compare_name += 2;
|
|
}
|
|
else
|
|
{
|
|
compare_name = mover->instanceName;
|
|
}
|
|
if(!_stricmp(mover->instanceName, "site_eyepoint"))
|
|
{
|
|
SPEW(("jerryeds", "Animation trying to mess with the eye...bad bad bad!!!!"));
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
|
|
if (channel_data.hasTrigger)
|
|
{
|
|
if (channel_data.triggerValue != mw_object->lastTriggerArray[joint_index])
|
|
{
|
|
mw_object->animationTriggerManager.DispatchTriggerMessage(joint_index, channel_data.triggerValue, mw_object);
|
|
mw_object->lastTriggerArray[joint_index] = channel_data.triggerValue;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (channel_data.hasVelocity)
|
|
{
|
|
//channel_data.velocityValue.y = 0.0f;
|
|
//channel_data.velocityValue.x = 0.0f;
|
|
|
|
//position.y = channel_data.positionValue.y;
|
|
//position.x = channel_data.positionValue.x;
|
|
|
|
position = mover->GetLocalToParent();
|
|
mw_object->animationVelocity = channel_data.velocityValue;
|
|
|
|
//vehicle->animationVelocity;
|
|
|
|
}
|
|
else
|
|
{
|
|
if (channel_data.hasPosition)
|
|
{
|
|
position = channel_data.positionValue;
|
|
}
|
|
else
|
|
{
|
|
position = mover->GetLocalToParent();
|
|
}
|
|
}
|
|
|
|
|
|
if (channel_data.hasAngularVelocity)
|
|
{
|
|
mw_object->instantaniousAngularVelocity = channel_data.angularVelocityValue;
|
|
rotation = mover->GetLocalToParent();
|
|
}
|
|
else
|
|
{
|
|
if (channel_data.hasRotation)
|
|
{
|
|
rotation = channel_data.rotationValue;
|
|
}
|
|
else
|
|
{
|
|
rotation = mover->GetLocalToParent();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Stuff::Scalar small_backup = Stuff::SMALL;
|
|
Stuff::SMALL = 1e-3f;
|
|
|
|
rotation.Normalize();
|
|
new_local_to_parent.BuildTranslation(position);
|
|
new_local_to_parent.BuildRotation(rotation);
|
|
|
|
|
|
|
|
#if defined(_ARMOR)
|
|
new_local_to_parent.TestInstance();
|
|
#endif
|
|
|
|
|
|
mover->SetNewLocalToParent(new_local_to_parent);
|
|
|
|
|
|
Stuff::SMALL = small_backup;
|
|
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::MakeArmatureChain()
|
|
{
|
|
Check_Object(this);
|
|
|
|
ChainIteratorOf<Entity *> child_iterator(&childEntityChain);
|
|
Entity *entity;
|
|
|
|
//
|
|
//Step Through until we find a root mover object
|
|
//
|
|
|
|
while((entity = child_iterator.ReadAndNext()) != NULL)
|
|
{
|
|
if(entity->IsDerivedFrom(MWMover::DefaultData))
|
|
{
|
|
MWMover *mover;
|
|
mover = Cast_Object(MWMover *, entity);
|
|
ConnectMWMover(mover);
|
|
entitiesToSync.Add(mover);
|
|
}
|
|
}
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::ConnectMWMover(MWMover *mover)
|
|
{
|
|
Check_Object(this);
|
|
|
|
ChainIteratorOf<Entity *> child_iterator(mover->GetChildEntityChain());
|
|
Entity *entity;
|
|
|
|
while((entity = child_iterator.ReadAndNext()) != NULL)
|
|
{
|
|
if(entity->IsDerivedFrom(MWMover::DefaultData))
|
|
{
|
|
MWMover *child_mover;
|
|
child_mover = Cast_Object(MWMover *, entity);
|
|
ConnectMWMover(child_mover);
|
|
}
|
|
}
|
|
|
|
SortedChainIteratorOf<Site *, MString> site_iterator(&mover->m_sites);
|
|
Site *site;
|
|
while((site = site_iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(site);
|
|
m_sites.AddValue(site, site->GetName());
|
|
}
|
|
armatureChain.Add(mover);
|
|
mover->myParentVehicle = this;
|
|
mover->SetSkinPrefix(m_skinPrefix);
|
|
mover->SetTeamDecal(m_teamDecal);
|
|
mover->SetPilotDecal(m_pilotDecal);
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
MWObject::FindChildMoverIndexUserData(
|
|
const char *joint_name,
|
|
void *user_data
|
|
)
|
|
{
|
|
MWObject *mw_object = (MWObject *)user_data;
|
|
Verify(mw_object->IsDerivedFrom(MWObject::DefaultData));
|
|
|
|
|
|
return mw_object->FindChildMoverIndex(joint_name);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
MWObject::FindChildMoverIndex(
|
|
const char *temp_name
|
|
)
|
|
{
|
|
|
|
MString joint_name;
|
|
|
|
int index = MW4Animation::UncompressName(temp_name, joint_name);
|
|
|
|
if (index != -1)
|
|
{
|
|
if (temporaryQuickIDLookup[index] != -1)
|
|
{
|
|
return temporaryQuickIDLookup[index];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Stuff::ChainIteratorOf<MWMover*> iterator(&armatureChain);
|
|
MWMover *mover;
|
|
|
|
int i = 0;
|
|
while ((mover = iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(mover);
|
|
const char *compare_name = mover->instanceName;
|
|
|
|
if (!_stricmp(compare_name, joint_name))
|
|
{
|
|
Verify(mover == animationArray[i]);
|
|
return i;
|
|
}
|
|
|
|
++i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
MWMover*
|
|
MWObject::FindChildMover(
|
|
const char *joint_name
|
|
)
|
|
{
|
|
Stuff::ChainIteratorOf<MWMover*> iterator(&armatureChain);
|
|
MWMover *mover;
|
|
|
|
while ((mover = iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(mover);
|
|
const char *compare_name = mover->instanceName;
|
|
if((compare_name = strstr(compare_name, "::")) != NULL)
|
|
{
|
|
compare_name += 2;
|
|
}
|
|
else
|
|
{
|
|
compare_name = mover->instanceName;
|
|
}
|
|
if (!_stricmp(compare_name, joint_name))
|
|
{
|
|
return mover;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::ReuseDamageObjects()
|
|
{
|
|
Check_Pointer(this);
|
|
|
|
SortedChainIteratorOf<DamageObject *, int> iterator(&damageObjects);
|
|
SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&internalDamageObjects);
|
|
|
|
DamageObject *damage_object;
|
|
|
|
while((damage_object = iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(damage_object);
|
|
damage_object->Reuse();
|
|
}
|
|
|
|
InternalDamageObject *internal_object;
|
|
while((internal_object = internal_iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(internal_object);
|
|
internal_object->Reuse();
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::ConnectDamageObjects()
|
|
{
|
|
Check_Pointer(this);
|
|
|
|
SortedChainIteratorOf<DamageObject *, int> iterator(&damageObjects);
|
|
SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&internalDamageObjects);
|
|
|
|
DamageObject *damage_object;
|
|
|
|
|
|
while((damage_object = iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(damage_object);
|
|
|
|
MWMover *mover;
|
|
mover = FindChildMover(damage_object->damageObjectName);
|
|
if(mover)
|
|
{
|
|
Check_Object(mover);
|
|
//
|
|
//-----------------------------------------------
|
|
//Assign Damage Object its internal damage object
|
|
//-----------------------------------------------
|
|
//
|
|
damage_object->internalDamageObject =
|
|
internalDamageObjects.Find(damage_object->internalDamageObjectID);
|
|
|
|
Check_Object(damage_object->internalDamageObject);
|
|
|
|
damage_object->internalDamageObject->parentEntity =
|
|
FindChildMover(damage_object->internalDamageObject->parentEntityName);
|
|
damage_object->internalDamageObject->damagePropagationObject =
|
|
internalDamageObjects.Find(damage_object->internalDamageObject->damagePropagationZoneID);
|
|
|
|
mover->SetDamageObject(damage_object);
|
|
damage_object->Initialize(mover);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
//-------------------------------------------------------
|
|
//No Name means it is tied to us not part of the armature
|
|
//-------------------------------------------------------
|
|
//
|
|
damage_object->internalDamageObject =
|
|
internalDamageObjects.Find(damage_object->internalDamageObjectID);
|
|
|
|
Check_Object(damage_object->internalDamageObject);
|
|
damage_object->internalDamageObject->parentEntity = this;
|
|
damage_object->internalDamageObject->damagePropagationObject =
|
|
internalDamageObjects.Find(damage_object->internalDamageObject->damagePropagationZoneID);
|
|
SetDamageObject(damage_object);
|
|
damage_object->Initialize(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::AddChild(Entity *entity)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(entity);
|
|
|
|
Entity::AddChild(entity);
|
|
if (entity->IsDerivedFrom(MWMover::DefaultData))
|
|
{
|
|
//We must make sure that we are on the armature chain
|
|
if(!armatureChain.IsPlugMember(entity))
|
|
{
|
|
MWMover *mover;
|
|
mover = Cast_Object(MWMover *, entity);
|
|
armatureChain.Add(mover);
|
|
}
|
|
}
|
|
if(entity->IsDerivedFrom(Subsystem::DefaultData))
|
|
{
|
|
if(!subsystemsInVehicle.IsPlugMember(entity))
|
|
{
|
|
Subsystem *subsystem;
|
|
subsystem = Cast_Object(Subsystem *, entity);
|
|
subsystemsInVehicle.Add(subsystem);
|
|
|
|
if(subsystem->executionState->GetState() != ExecutionStateEngine::NeverExecuteState)
|
|
{
|
|
executingSubsystems.Add(subsystem);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::RemoveChild(Entity *entity)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(entity);
|
|
|
|
if(entity->IsDerivedFrom(Subsystem::DefaultData))
|
|
{
|
|
Subsystem *subsystem;
|
|
subsystem = Cast_Object(Subsystem *, entity);
|
|
|
|
subsystemsInVehicle.Remove(subsystem);
|
|
executingSubsystems.Remove(subsystem);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::ChildPreCollisionChanged(Entity *entity)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(entity);
|
|
if(entity->IsDerivedFrom(Subsystem::DefaultData))
|
|
{
|
|
Subsystem *subsystem;
|
|
subsystem = Cast_Object(Subsystem *, entity);
|
|
|
|
if((subsystem->executionState->GetOldState() == ExecutionStateEngine::NeverExecuteState)
|
|
&&(subsystem->executionState->GetState() != ExecutionStateEngine::NeverExecuteState))
|
|
{
|
|
executingSubsystems.Add(subsystem);
|
|
}
|
|
else if((subsystem->executionState->GetOldState() != ExecutionStateEngine::NeverExecuteState)
|
|
&&(subsystem->executionState->GetState() == ExecutionStateEngine::NeverExecuteState))
|
|
{
|
|
executingSubsystems.Remove(subsystem);
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
static Entity*
|
|
Find_Child(
|
|
Entity *parent,
|
|
const char* name
|
|
)
|
|
{
|
|
Check_Object(parent);
|
|
Check_Pointer(name);
|
|
return Cast_Object(MWObject*, parent)->FindChildMover(name);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::BecomeInteresting(bool render_me)
|
|
{
|
|
Check_Object(this);
|
|
LOAD_LOGIC("Become Interesting::MWObject");
|
|
|
|
//
|
|
//------------------------------------------------------------------------
|
|
// The entity version will just load the solid volumes. Go ahead and load
|
|
// the stream resource that should be indicated in the game model
|
|
//------------------------------------------------------------------------
|
|
//
|
|
if (!solidVolume && !hierarchicalVolume)
|
|
{
|
|
const GameModel *game_model = GetGameModel();
|
|
Check_Object(game_model);
|
|
|
|
//
|
|
//-------------------------------
|
|
// Load in the solid if it exists
|
|
//-------------------------------
|
|
//
|
|
#if defined(LAB_ONLY)
|
|
extern char g_LastEntity[255];
|
|
if (!instanceName)
|
|
g_LastEntity[0] = '\0';
|
|
else
|
|
{
|
|
strncpy(g_LastEntity, instanceName, sizeof(g_LastEntity)-1);
|
|
g_LastEntity[sizeof(g_LastEntity)-1] = '\0';
|
|
}
|
|
#endif
|
|
if (game_model->obbStreamResourceID != ResourceID::Null)
|
|
{
|
|
gos_PushCurrentHeap(Adept::Entity::s_CollisionHeap);
|
|
Resource obb_stream(game_model->obbStreamResourceID);
|
|
Verify(obb_stream.DoesResourceExist());
|
|
solidVolume =
|
|
new CollisionVolume(
|
|
this,
|
|
&obb_stream,
|
|
CollisionVolume::ReadOBBVersion(&obb_stream)
|
|
);
|
|
Check_Object(solidVolume);
|
|
gos_PopCurrentHeap();
|
|
}
|
|
|
|
if (game_model->hierarchicalOBBStreamResourceID != ResourceID::Null)
|
|
{
|
|
gos_PushCurrentHeap(Adept::Entity::s_CollisionHeap);
|
|
Resource obb_stream(game_model->hierarchicalOBBStreamResourceID);
|
|
Verify(obb_stream.DoesResourceExist());
|
|
if (!armatureChain.IsEmpty())
|
|
{
|
|
hierarchicalVolume =
|
|
new CollisionVolume(
|
|
this,
|
|
Find_Child,
|
|
this,
|
|
&obb_stream,
|
|
CollisionVolume::ReadOBBVersion(&obb_stream)
|
|
);
|
|
Check_Object(hierarchicalVolume);
|
|
}
|
|
else
|
|
{
|
|
#ifdef LAB_ONLY
|
|
PAUSE(("Error: %s is missing its armature!", (char*)instanceName));
|
|
#endif
|
|
if (!solidVolume)
|
|
{
|
|
solidVolume =
|
|
new CollisionVolume(
|
|
this,
|
|
&obb_stream,
|
|
CollisionVolume::ReadOBBVersion(&obb_stream)
|
|
);
|
|
Check_Object(solidVolume);
|
|
}
|
|
}
|
|
gos_PopCurrentHeap();
|
|
}
|
|
}
|
|
|
|
if(!Mission::GetInstance()->DoesAllowRunningLights())
|
|
{
|
|
DestroyRunningLight();
|
|
}
|
|
|
|
BaseClass::BecomeInteresting(render_me);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::CheckVideoStates(bool render_me)
|
|
{
|
|
if(render_me && IsDestroyed())
|
|
{
|
|
entityElement->SetAlwaysCullMode();
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::DestroyRunningLight()
|
|
{
|
|
Check_Object(this);
|
|
|
|
if(jointRunningLight)
|
|
{
|
|
Check_Object(jointRunningLight);
|
|
jointRunningLight->GetElement()->SetAlwaysCullMode();
|
|
if(jointRunningLight->GetSolidVolume() &&
|
|
!jointRunningLight->GetSolidVolume()->IsDestroyed())
|
|
jointRunningLight->GetSolidVolume()->Destroy();
|
|
if(jointRunningLight->GetHierarchicalVolume() &&
|
|
!jointRunningLight->GetHierarchicalVolume()->IsDestroyed())
|
|
jointRunningLight->GetHierarchicalVolume()->Destroy();
|
|
|
|
// jointRunningLight->GetElement()->SetAlwaysCullMode();
|
|
// jointRunningLight->SetDestroyedFlag(InternalDamageObject::DestructionDamageMode);
|
|
// jointRunningLight->SentenceToDeathRow();
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::ReuseSubsystems(MemoryStream *stream)
|
|
{
|
|
Check_Pointer(this);
|
|
|
|
Stuff::ChainIteratorOf<Subsystem*> iterator(&subsystemsInVehicle);
|
|
Subsystem *subsystem;
|
|
stream->AdvancePointer(sizeof(WORD));
|
|
while (((subsystem = iterator.ReadAndNext()) != NULL) &&
|
|
(stream->GetBytesRemaining() > 0))
|
|
{
|
|
Verify(subsystem->IsDerivedFrom(Subsystem::DefaultData));
|
|
Entity::CreateMessage *message =
|
|
Cast_Pointer(Entity::CreateMessage*, stream->GetPointer());
|
|
subsystem->Respawn(message);
|
|
// MSL 5.02 headshot
|
|
// bug fix: didn't re-hook these up - note we are explicitly calling the MWObject version
|
|
MWObject::AddSubsystem(subsystem);
|
|
stream->AdvancePointer(message->messageLength);
|
|
}
|
|
|
|
if(sensor)
|
|
{
|
|
sensor->SetSensorMode(Sensor::ActiveMode, DoesHaveBeagle());
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::HookUpSubsystems()
|
|
{
|
|
Stuff::ChainIteratorOf<Subsystem*> iterator(&subsystemsInVehicle);
|
|
Subsystem *subsystem;
|
|
int weapon_id = 0;
|
|
while ((subsystem = iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Verify(subsystem->IsDerivedFrom(Subsystem::DefaultData));
|
|
if(subsystem->ConnectSubsystem())
|
|
{
|
|
|
|
//
|
|
//-----------------------------------------------
|
|
//Connect the weapons to the correct weapon group
|
|
//-----------------------------------------------
|
|
//
|
|
if(subsystem->IsDerivedFrom(Weapon::DefaultData))
|
|
{
|
|
Weapon *weapon;
|
|
weapon = Cast_Object(Weapon *, subsystem);
|
|
weaponChain.Add(weapon);
|
|
weapon->SetWeaponID(weapon_id);
|
|
++weapon_id;
|
|
|
|
}
|
|
AddSubsystem(subsystem);
|
|
}
|
|
else
|
|
{
|
|
RemoveChild(subsystem);
|
|
}
|
|
}
|
|
if(sensor)
|
|
{
|
|
sensor->SetSensorMode(Sensor::ActiveMode, DoesHaveBeagle());
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::AddSubsystem(Subsystem *subsystem)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(subsystem);
|
|
|
|
|
|
if(subsystem->IsDerivedFrom(Sensor::DefaultData))
|
|
{
|
|
sensor = Cast_Object(Sensor *, subsystem);
|
|
}
|
|
else if (subsystem->IsDerivedFrom(Beagle::DefaultData))
|
|
{
|
|
beagle = Cast_Object(Beagle *, subsystem);
|
|
}
|
|
else if (subsystem->IsDerivedFrom(AMS::DefaultData))
|
|
{
|
|
ams = Cast_Object(AMS *, subsystem);
|
|
}
|
|
else if(subsystem->IsDerivedFrom(ECM::DefaultData))
|
|
{
|
|
ecm = Cast_Object(ECM *, subsystem);
|
|
}
|
|
// MSL 5.02 SubSystems
|
|
// else if(subsystem->IsDerivedFrom(EnhancedOptics::DefaultData))
|
|
// {
|
|
// enhancedOptics = Cast_Object(EnhancedOptics *, subsystem);
|
|
// }
|
|
else if(subsystem->IsDerivedFrom(IFF_Jammer::DefaultData))
|
|
{
|
|
iff_jammer = Cast_Object(IFF_Jammer *, subsystem);
|
|
}
|
|
else if(subsystem->IsDerivedFrom(AdvancedGyro::DefaultData))
|
|
{
|
|
advancedGyro = Cast_Object(AdvancedGyro *, subsystem);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::RemoveSubsystem(Subsystem *subsystem)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(subsystem);
|
|
|
|
if(subsystem->IsDerivedFrom(Weapon::DefaultData))
|
|
{
|
|
Weapon *weapon;
|
|
weapon = Cast_Object(Weapon *, subsystem);
|
|
weaponChain.Remove(weapon);
|
|
}
|
|
else if(subsystem->IsDerivedFrom(Sensor::DefaultData))
|
|
{
|
|
sensor = NULL;
|
|
}
|
|
else if (subsystem->IsDerivedFrom(Beagle::DefaultData))
|
|
{
|
|
beagle = NULL;
|
|
}
|
|
else if (subsystem->IsDerivedFrom(AMS::DefaultData))
|
|
{
|
|
ams = NULL;
|
|
}
|
|
else if(subsystem->IsDerivedFrom(ECM::DefaultData))
|
|
{
|
|
ecm = NULL;
|
|
}
|
|
// MSL 5.02 SubSystems
|
|
// else if(subsystem->IsDerivedFrom(EnhancedOptics::DefaultData))
|
|
// {
|
|
// enhancedOptics = NULL;
|
|
// }
|
|
else if(subsystem->IsDerivedFrom(IFF_Jammer::DefaultData))
|
|
{
|
|
iff_jammer = NULL;
|
|
}
|
|
else if(subsystem->IsDerivedFrom(AdvancedGyro::DefaultData))
|
|
{
|
|
advancedGyro = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::ReactToDestruction(int damage_mode, int damage_type)
|
|
{
|
|
Check_Object(this);
|
|
|
|
switch(damage_mode)
|
|
{
|
|
case InternalDamageObject::DestructionDamageMode:
|
|
{
|
|
|
|
if(!IsDestroyed())
|
|
{
|
|
Check_Object(executionState);
|
|
// executionState->RequestState(ExecutionStateEngine::DestroyedState);
|
|
if(m_AI)
|
|
{
|
|
Check_Object(m_AI);
|
|
m_AI->Die();
|
|
}
|
|
else
|
|
{
|
|
MW4AI::g_Rect4DHash->RemovePermRect (this);
|
|
}
|
|
|
|
SetDestroyedFlag(damage_mode);
|
|
|
|
if (damage_type != SplashDamageType)
|
|
DealSplashDamage();
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
|
|
CreateEffect(model->destroyedEffectResource, this, false);
|
|
if(!m_deathEntity.GetCurrent())
|
|
{
|
|
Entity *death_entity = CreateStaticHermitEntity(model->deathEntityResource);
|
|
if(death_entity)
|
|
{
|
|
m_deathEntity.Remove();
|
|
m_deathEntity.Add(death_entity);
|
|
}
|
|
}
|
|
|
|
|
|
RemoveFromExecution();
|
|
// SentenceToDeathRow();
|
|
DestroyChildren(damage_mode);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Entity::ReactToDestruction(damage_mode, damage_type);
|
|
|
|
#ifdef LAB_ONLY
|
|
if (MW4AI::Statistics::Enabled() == true)
|
|
{
|
|
MW4AI::Statistics::NotifyDestroyed(objectID);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
|
|
void MWObject::DestroyDamageObjects()
|
|
{
|
|
|
|
SortedChainIteratorOf<DamageObject *, int> iterator(&damageObjects);
|
|
SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&internalDamageObjects);
|
|
|
|
DamageObject *damage_object;
|
|
|
|
while((damage_object = iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(damage_object);
|
|
damage_object->SilentDestruction();
|
|
}
|
|
|
|
InternalDamageObject *internal_object;
|
|
while((internal_object = internal_iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(internal_object);
|
|
internal_object->SilentDestruction();
|
|
}
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void MWObject::DealSplashDamage()
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(CollisionGrid::Instance);
|
|
|
|
extern g_nMR;
|
|
if (g_nMR == 2)
|
|
return;
|
|
|
|
if (!Network::GetInstance()->AmIServer())
|
|
return;
|
|
|
|
NetMissionParameters::MWNetMissionParameters *params = MWApplication::GetInstance()->GetLocalNetParams();
|
|
if (!params->m_splashOn)
|
|
return;
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
Verify(splashedEntities.IsEmpty());
|
|
splashSize = 0;
|
|
if (model->splashDamageAmount > 0.0f)
|
|
{
|
|
|
|
//
|
|
// Need to see if the target has a solid volume and if so, use that for the positioning of the target
|
|
// bracket.
|
|
CollisionVolume * volume;
|
|
//
|
|
// This code was just getting the torso and using that local to world but the torso location
|
|
// was whacked. That should be fixed as a secondary issue, but for here the solid volume is
|
|
// good since that is what would be doing ramming damage, etc... anyway.
|
|
//
|
|
|
|
volume = GetSolidVolume();
|
|
if (!volume)
|
|
{
|
|
if (GetTorso())
|
|
volume = GetTorso()->GetHierarchicalVolume();
|
|
else
|
|
volume = GetHierarchicalVolume();
|
|
|
|
}
|
|
Stuff::Sphere sphere;
|
|
if (volume)
|
|
{
|
|
OBB world_bounds;
|
|
world_bounds.Multiply(volume->m_localSpaceBounds, GetLocalToWorld());
|
|
sphere.center = world_bounds.localToParent;
|
|
}
|
|
else
|
|
{
|
|
sphere.center = GetLocalToWorld();
|
|
}
|
|
sphere.radius = model->splashDamageRadius;
|
|
splashSize = 0;
|
|
|
|
CollisionGrid::Instance->FindEntitiesWithin(sphere, (Adept::CollisionGrid::WithinCallback)SplashCallBack, this);
|
|
|
|
if (splashSize == 0)
|
|
return;
|
|
ChainIteratorOf<Entity *> splashed_entities(&splashedEntities);
|
|
//
|
|
// First, iterate through the list once to clear the been hit flag so we don't do
|
|
// double/or more damage to multiple entities, connected to the same damage zones
|
|
//
|
|
Entity *hit_entity;
|
|
while((hit_entity = splashed_entities.ReadAndNext()) != NULL)
|
|
{
|
|
if (hit_entity->damageObject)
|
|
hit_entity->damageObject->ClearTakenDamageFromThisEvent();
|
|
}
|
|
splashed_entities.First();
|
|
|
|
NetMissionParameters::MWNetMissionParameters *params = MWApplication::GetInstance()->GetLocalNetParams();
|
|
|
|
while((hit_entity = splashed_entities.GetCurrent()) != NULL)
|
|
{
|
|
if (hit_entity->damageObject)
|
|
{
|
|
//
|
|
// If there is a damage object verify we aren't hitting it twice
|
|
//
|
|
if (!hit_entity->damageObject->GetTakenDamageFromThisEvent())
|
|
{
|
|
hit_entity->damageObject->SetTakenDamageFromThisEvent() ;
|
|
}
|
|
else
|
|
{
|
|
splashed_entities.Remove();
|
|
continue;
|
|
}
|
|
}
|
|
Stuff::Point3D ltwEntity;
|
|
ltwEntity = hit_entity->GetLocalToWorld();
|
|
|
|
// MSL 5.06 Armor Mode
|
|
MWApplication *m_App;
|
|
m_App = MWApplication::GetInstance ();
|
|
m_ArmorMode = m_App->GetLocalNetParams()->m_armormodeOn;
|
|
|
|
Adept::Entity__TakeDamageMessage message(
|
|
hit_entity->GetReplicatorID(),
|
|
this->GetReplicatorID(),
|
|
model->splashDamageAmount * ((Scalar)params->m_splashPercentage*0.01f),
|
|
m_ArmorMode,
|
|
SplashDamageType,
|
|
Normal3D(0.0f, 0.0f, 1.0f),
|
|
ltwEntity,
|
|
model->splashHeatAmount,
|
|
false,
|
|
TakeDamageMessage::DefaultWeaponType
|
|
);
|
|
hit_entity->Receive(&message);
|
|
splashed_entities.Remove();
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void MWObject::SplashCallBack(Adept::Entity *entity, Adept::Entity *original_caller, const Stuff::Sphere &sphere)
|
|
{
|
|
|
|
Check_Object(entity);
|
|
Check_Object(original_caller);
|
|
|
|
|
|
MWObject *mwobject = Cast_Object( MWObject*, original_caller);
|
|
|
|
|
|
if (!entity->IsDestroyed())
|
|
{
|
|
|
|
CollisionVolume *volume = entity->GetHierarchicalVolume();
|
|
if (volume)
|
|
{
|
|
|
|
volume->FindSolidsWithin(
|
|
sphere,
|
|
(Adept::CollisionVolume::WithinCallback)SubSplashCallBack,
|
|
mwobject,
|
|
entity,
|
|
entity->GetLocalToWorld()
|
|
);
|
|
}
|
|
else
|
|
{
|
|
mwobject->splashedEntities.Add(entity);
|
|
++mwobject->splashSize;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void MWObject::SubSplashCallBack(CollisionVolume *solid, Entity *original_caller, const Stuff::Sphere &sphere)
|
|
{
|
|
|
|
Check_Object(solid);
|
|
Check_Object(original_caller);
|
|
|
|
MWObject *mwobject = Cast_Object( MWObject*, original_caller);
|
|
|
|
if (solid->m_entity && !solid->m_entity->IsDestroyed())
|
|
{
|
|
|
|
|
|
mwobject->splashedEntities.Add(solid->m_entity);
|
|
|
|
++mwobject->splashSize;
|
|
}
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void MWObject::TakeSplashDamage(Adept::Entity__TakeDamageMessage *message)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(CollisionGrid::Instance);
|
|
|
|
// go thru my damage objects and deal the damage
|
|
|
|
SortedChainIteratorOf<DamageObject *, int> damage_iterator(&damageObjects);
|
|
DamageObject *damage_object;
|
|
while((damage_object = damage_iterator.ReadAndNext()) != NULL)
|
|
{
|
|
damage_object->TakeDamage(message, NULL);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::RemoveFromExecution()
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(entityElement);
|
|
Check_Object(executionState);
|
|
|
|
if (newCollisions)
|
|
{
|
|
delete newCollisions;
|
|
newCollisions = NULL;
|
|
}
|
|
executionState->RequestState(ExecutionStateEngine::NeverExecuteState);
|
|
entityElement->SetAlwaysCullMode();
|
|
EntityManager::GetInstance()->RemovePostCollisionExecution(this);
|
|
RemoveCollision();
|
|
|
|
SyncMatrices(true);
|
|
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::PreCollisionExecute(Stuff::Time till)
|
|
{
|
|
Check_Object(this);
|
|
|
|
PRECOLLISION_LOGIC("MWObject");
|
|
m_hasExecuted = true;
|
|
#if defined(LAB_ONLY)
|
|
if (!instanceName)
|
|
MWGameInfo::g_LastMWObject[0] = '\0';
|
|
else
|
|
{
|
|
strncpy(MWGameInfo::g_LastMWObject, instanceName, sizeof(MWGameInfo::g_LastMWObject)-1);
|
|
MWGameInfo::g_LastMWObject[sizeof(MWGameInfo::g_LastMWObject)-1] = '\0';
|
|
}
|
|
MWGameInfo::g_LastMWObjectPos = GetLocalToWorld();
|
|
#endif
|
|
|
|
//
|
|
//----------------------------------------------
|
|
// All MWObjects that execute use post collision
|
|
//----------------------------------------------
|
|
//
|
|
UsePostCollision();
|
|
BaseClass::PreCollisionExecute(till);
|
|
|
|
//
|
|
//-------------------------------------------------
|
|
// Run the ubsystems, then finally the heat manager
|
|
//-------------------------------------------------
|
|
//
|
|
{
|
|
ChainIteratorOf<Subsystem *> sub_iterator(&executingSubsystems);
|
|
Subsystem *subsystem;
|
|
while((subsystem = sub_iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(subsystem);
|
|
subsystem->PreCollisionExecute(till);
|
|
Verify(!subsystem->IsUsingPostCollision() || EntityManager::GetInstance()->IsInPostCollisionExecution(subsystem));
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::SyncMatrices(bool update_matrix)
|
|
{
|
|
Check_Object(this);
|
|
SYNC_LOGIC("MWObject");
|
|
|
|
#if defined(HUNT_BUG)
|
|
bool old_update=update_matrix;
|
|
if (update_matrix)
|
|
{
|
|
SPEW((0, "MWObject::SyncMatrices %s(+", GetClassString()));
|
|
Spew(0, GetReplicatorID());
|
|
SPEW((0, ")"));
|
|
}
|
|
#endif
|
|
Set_Statistic(s_EntitiesSynced, s_EntitiesSynced);
|
|
|
|
//
|
|
//-----------------------------------------
|
|
// If we have a dirty locator, sync with it
|
|
//-----------------------------------------
|
|
//
|
|
if (IsMatrixDirty())
|
|
{
|
|
if (update_matrix)
|
|
{
|
|
Check_Object(entityElement);
|
|
entityElement->Sync();
|
|
update_matrix = false;
|
|
}
|
|
ClearNeedMatrixSync();
|
|
}
|
|
|
|
//
|
|
//-----------------------------
|
|
// Sync our children's locators
|
|
//-----------------------------
|
|
//
|
|
if (!entitiesToSync.IsEmpty())
|
|
{
|
|
ChainIteratorOf<MWMover*> children(&entitiesToSync);
|
|
Entity *child;
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
child->SyncMatrices(update_matrix);
|
|
}
|
|
}
|
|
|
|
#if defined(HUNT_BUG)
|
|
if (old_update)
|
|
SPEW((0, ""));
|
|
#endif
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void MWObject::PostCollisionExecute(Time till)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(executionState);
|
|
|
|
POSTCOLLISION_LOGIC("MWObject");
|
|
|
|
{for (std::vector<Torso*>::iterator i = m_Torsos.begin();
|
|
i != m_Torsos.end();
|
|
++i)
|
|
{
|
|
if ((*i)->followTorsoRequest)
|
|
{
|
|
gosREPORT(*i,"somehow a mwobject got a follow torso request when it has no torso");
|
|
Check_Object(*i);
|
|
Point3D target_position = (*i)->torsoRequest;
|
|
|
|
Point3D distance_to_target;
|
|
distance_to_target.MultiplyByInverse(target_position,(*i)->GetTwistJointMatrix());
|
|
#if 0
|
|
MWMover *eye_site = eyeSitePointer.GetCurrent();
|
|
YawPitchRoll twist_offset = YawPitchRoll::Identity;
|
|
|
|
Point3D local_eye_site_offset_pitch = Point3D::Identity;
|
|
Point3D local_eye_site_offset_twist = Point3D::Identity;
|
|
if(eye_site)
|
|
{
|
|
Check_Object(eye_site);
|
|
Point3D world_eye_site = (Point3D) eye_site->GetLocalToWorld();
|
|
// LinearMatrix4D world_eye_site = eye_site->GetLocalToWorld();
|
|
// world_eye_site.Invert();
|
|
// LinearMatrix4D local_eye_site_offset = LinearMatrix4D::Identity;
|
|
local_eye_site_offset_twist.MultiplyByInverse(world_eye_site, (*i)->GetTwistJointMatrix());
|
|
local_eye_site_offset_pitch.MultiplyByInverse(world_eye_site, (*i)->GetPitchJointMatrix());
|
|
// twist_offset = (YawPitchRoll) local_eye_site_offset;
|
|
}
|
|
#endif
|
|
Scalar heading_adjustment;
|
|
Point3D distance_to_target_pitch;
|
|
distance_to_target_pitch.MultiplyByInverse(target_position,(*i)->GetPitchJointMatrix());
|
|
if(!Small_Enough(distance_to_target_pitch.z))
|
|
{
|
|
// heading_adjustment = Arctan(distance_to_target_pitch.y, distance_to_target_pitch.z) - (Arctan(local_eye_site_offset_pitch.y, local_eye_site_offset_pitch.z));;
|
|
heading_adjustment = Arctan(distance_to_target_pitch.y, distance_to_target_pitch.z);
|
|
if(!Small_Enough(heading_adjustment))
|
|
{
|
|
Scalar speed_demand;
|
|
if (heading_adjustment > (*i)->GetPitchSpeed())
|
|
{
|
|
speed_demand = 1.0;
|
|
}
|
|
else
|
|
{
|
|
speed_demand = heading_adjustment / (*i)->GetPitchSpeed();
|
|
speed_demand = Abs(speed_demand);
|
|
}
|
|
if(heading_adjustment > 0.02) // down
|
|
(*i)->pitchDemand = -speed_demand;
|
|
if(heading_adjustment < -0.02) // up
|
|
(*i)->pitchDemand = speed_demand;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
if(eye_site)
|
|
{
|
|
Check_Object(eye_site);
|
|
Point3D world_eye_site = (Point3D) eye_site->GetLocalToWorld();
|
|
// LinearMatrix4D world_eye_site = eye_site->GetLocalToWorld();
|
|
// world_eye_site.Invert();
|
|
// LinearMatrix4D local_eye_site_offset = LinearMatrix4D::Identity;
|
|
local_eye_site_offset_twist.MultiplyByInverse(world_eye_site, (*i)->GetTwistJointMatrix());
|
|
local_eye_site_offset_pitch.MultiplyByInverse(world_eye_site, (*i)->GetPitchJointMatrix());
|
|
// twist_offset = (YawPitchRoll) local_eye_site_offset;
|
|
}
|
|
#endif
|
|
|
|
if(!Small_Enough(distance_to_target.z))
|
|
{
|
|
// heading_adjustment = (Arctan(distance_to_target.x, distance_to_target.z)) + twist_offset.yaw;
|
|
// heading_adjustment = (Arctan(distance_to_target.x, distance_to_target.z)) - (Arctan(local_eye_site_offset_twist.x, local_eye_site_offset_twist.z));
|
|
heading_adjustment = (Arctan(distance_to_target.x, distance_to_target.z));
|
|
if(!Small_Enough(heading_adjustment))
|
|
{
|
|
Scalar speed_demand;
|
|
if (heading_adjustment > (*i)->GetTwistSpeed())
|
|
{
|
|
speed_demand = 1.0;
|
|
}
|
|
else
|
|
{
|
|
speed_demand = heading_adjustment / (*i)->GetTwistSpeed();
|
|
speed_demand = Abs(speed_demand);
|
|
}
|
|
|
|
if(heading_adjustment > 0.02) //left
|
|
(*i)->yawDemand = speed_demand;
|
|
|
|
if(heading_adjustment < -0.02) //right
|
|
(*i)->yawDemand = -speed_demand;
|
|
|
|
}
|
|
}
|
|
}
|
|
}}
|
|
BaseClass::PostCollisionExecute(till);
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
Effect*
|
|
MWObject::CreateEffect(const Adept::ResourceID& effect_id, MWMover *parent_part, bool follow_joint)
|
|
{
|
|
|
|
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 = GetLocalToWorld();
|
|
if(parent_part)
|
|
{
|
|
Check_Object(parent_part);
|
|
effect_location = parent_part->GetLocalToWorld();
|
|
}
|
|
|
|
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);
|
|
|
|
if (parent_part != NULL && follow_joint)
|
|
{
|
|
entity->SetFollowEntity(parent_part);
|
|
entity->PlaceOnEntity();
|
|
}
|
|
|
|
entity->SyncMatrices(true);
|
|
|
|
return entity;
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
Effect*
|
|
MWObject::CreateEffect(const Adept::ResourceID& effect_id, Site *parent_part, bool follow_joint)
|
|
{
|
|
|
|
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 = GetLocalToWorld();
|
|
if(parent_part)
|
|
{
|
|
Check_Object(parent_part);
|
|
effect_location = parent_part->GetLocalToWorld();
|
|
}
|
|
|
|
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);
|
|
|
|
if (parent_part != NULL && follow_joint)
|
|
{
|
|
entity->SetFollowEntity(parent_part);
|
|
entity->PlaceOnSite();
|
|
}
|
|
|
|
entity->SyncMatrices(true);
|
|
|
|
return entity;
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
Effect*
|
|
MWObject::CreateLoopingEffect(const Adept::ResourceID& effect_id, MWMover *parent_part, bool follow_joint)
|
|
{
|
|
|
|
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 = GetLocalToWorld();
|
|
if(parent_part)
|
|
{
|
|
Check_Object(parent_part);
|
|
effect_location = parent_part->GetLocalToWorld();
|
|
}
|
|
|
|
Effect::CreateMessage effect_create_message(
|
|
sizeof(Effect::CreateMessage),
|
|
DefaultEventPriority,
|
|
Entity::CreateMessage::DefaultFlags,
|
|
class_ID,
|
|
Effect::DefaultFlags|Effect::LoopFlag,
|
|
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);
|
|
|
|
if (parent_part != NULL && follow_joint)
|
|
{
|
|
entity->SetFollowEntity(parent_part);
|
|
entity->PlaceOnEntity();
|
|
}
|
|
|
|
entity->SyncMatrices(true);
|
|
|
|
return entity;
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
Effect*
|
|
MWObject::CreateLoopingEffect(const Adept::ResourceID& effect_id, const Point3D &location)
|
|
{
|
|
|
|
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::LoopFlag,
|
|
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;
|
|
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
Effect*
|
|
MWObject::CreateLoopingEffect(const Adept::ResourceID& effect_id, Site *parent_part, bool follow_joint)
|
|
{
|
|
|
|
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 = GetLocalToWorld();
|
|
if(parent_part)
|
|
{
|
|
Check_Object(parent_part);
|
|
effect_location = parent_part->GetLocalToWorld();
|
|
}
|
|
|
|
Effect::CreateMessage effect_create_message(
|
|
sizeof(Effect::CreateMessage),
|
|
DefaultEventPriority,
|
|
Entity::CreateMessage::DefaultFlags,
|
|
class_ID,
|
|
Effect::DefaultFlags|Effect::LoopFlag,
|
|
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);
|
|
|
|
if (parent_part != NULL && follow_joint)
|
|
{
|
|
entity->SetFollowEntity(parent_part);
|
|
entity->PlaceOnSite();
|
|
}
|
|
|
|
entity->SyncMatrices(true);
|
|
|
|
return entity;
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Effect*
|
|
MWObject::CreateEffect(const Adept::ResourceID& effect_id, const Point3D &location)
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
// MSL 5.03 Glass
|
|
Effect*
|
|
MWObject::CreateEffect(const Adept::ResourceID& effect_id, const Point3D &location, const Vector3D &vector)
|
|
{
|
|
|
|
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.AlignLocalAxisToWorldVector(vector, Y_Axis, X_Axis, Z_Axis);
|
|
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 *
|
|
MWObject::CreateStaticHermitEntity(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
|
|
MWObject::TestInstance() const
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|
|
|
|
void MWObject::AttachAI (AI *ai)
|
|
{
|
|
Check_Object (this);
|
|
|
|
if (ai != 0)
|
|
{
|
|
Check_Object (ai);
|
|
}
|
|
|
|
m_AI = ai;
|
|
}
|
|
|
|
void MWObject::SentenceToDeathRow()
|
|
{
|
|
Check_Object(this);
|
|
|
|
if (m_AI)
|
|
m_AI->SentenceToDeathRow ();
|
|
|
|
BaseClass::SentenceToDeathRow ();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const MWObject::GroupList&
|
|
MWObject::GetGroups() const
|
|
{
|
|
return m_groups;
|
|
}
|
|
|
|
MWObject::GroupList&
|
|
MWObject::GetGroups()
|
|
{
|
|
return m_groups;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
MWObject::GetSensorMode()
|
|
{
|
|
Check_Object(this);
|
|
if(sensor)
|
|
{
|
|
Check_Object(sensor);
|
|
return sensor->sensorMode;
|
|
}
|
|
return Sensor::ActiveMode;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
MWObject::DoesHaveBeagle()
|
|
{
|
|
Check_Object(this);
|
|
|
|
if(beagle)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::AddStatsToString(std::string& s)
|
|
{
|
|
s += instanceName;
|
|
|
|
if ((DamageDispatch::GetGlobalInvulnerability() == true) &&
|
|
(IsPlayerVehicle() == true))
|
|
{
|
|
s += " (INVULNERABLE)";
|
|
}
|
|
|
|
if (GetTargetDesirability() == desirability_never)
|
|
{
|
|
s += " (IGNORE)";
|
|
}
|
|
|
|
if (IsDestroyed() == true)
|
|
{
|
|
s += " (DEAD)";
|
|
}
|
|
|
|
char temp[80];
|
|
|
|
if(isPlayerVehicle)
|
|
{
|
|
if(VehicleInterface::GetInstance())
|
|
{
|
|
s += "\nTARGETMATERIAL: ";
|
|
int material_num = VehicleInterface::GetInstance()->targetQuery.m_material;
|
|
const char *material = MaterialTypeAsciiToText(material_num);
|
|
sprintf(temp,"%s\n",(char *)material);
|
|
s += temp;
|
|
}
|
|
}
|
|
|
|
s += "\nTONNAGE: ";
|
|
sprintf(temp,"%d",(int)GetTonage());
|
|
s += temp;
|
|
|
|
s += "\nBATTLEVALUE: ";
|
|
sprintf(temp,"%d",(int)GetBattleValue());
|
|
s += temp;
|
|
|
|
s += "\nHEAT: ";
|
|
if(m_heatManager)
|
|
sprintf(temp,"%f",m_heatManager->GetHeat());
|
|
else
|
|
sprintf(temp,"NA");
|
|
s += temp;
|
|
|
|
s += "\nCOOLANT: ";
|
|
if(m_heatManager)
|
|
sprintf(temp,"%f",m_heatManager->GetCoolant());
|
|
else
|
|
sprintf(temp, "NA");
|
|
s += temp;
|
|
|
|
s += "\nPOSITION: x=";
|
|
Point3D pos = (Point3D)GetLocalToWorld();
|
|
s += ScalarToString(pos.x);
|
|
s += ", z=";
|
|
s += ScalarToString(pos.z);
|
|
s += "\n";
|
|
|
|
if (GetTorso() != 0)
|
|
{
|
|
s += "Torso: y=";
|
|
sprintf(temp,"%.2f p=%.2f\n",GetTorso()->yawValue,GetTorso()->pitchValue);
|
|
s += temp;
|
|
}
|
|
|
|
if (GetTargetDesirability() >= 0)
|
|
{
|
|
sprintf(temp,"Target Desirability: %d\n",(int)(GetTargetDesirability() * 100));
|
|
s += temp;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::AddDamageInfoToString(std::string& s)
|
|
{
|
|
Check_Object(this);
|
|
|
|
char temp[80];
|
|
SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&internalDamageObjects);
|
|
SortedChainIteratorOf<DamageObject*, int> damage_iterator(&damageObjects);
|
|
|
|
s += "\nARMOR\n";
|
|
DamageObject *damage_object;
|
|
while((damage_object = damage_iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(damage_object);
|
|
s += damage_object->damageObjectName;
|
|
sprintf(temp, "base: %.2f current: %.2f\n", damage_object->baseArmorValue, damage_object->currentArmorValue);
|
|
s += temp;
|
|
}
|
|
|
|
s += "\nINTERNAL\n";
|
|
MWInternalDamageObject *internal_object;
|
|
while((internal_object = internal_iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(internal_object);
|
|
s += InternalDamageObject::InternalZoneAsciiToText(internal_object->damageZone);
|
|
sprintf(temp, "Mode: %s\n", InternalDamageObject::DamageModeAsciiToText(internal_object->damageMode));
|
|
s += temp;
|
|
sprintf(temp, "base: %.2f current: %.2f\n", internal_object->baseInternalDamage, internal_object->currentInternalDamage);
|
|
s += temp;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::NotifyProjectileApproaching(const Stuff::Point3D& origin)
|
|
{
|
|
BaseClass::NotifyProjectileApproaching(origin);
|
|
|
|
if (GetAI() != 0)
|
|
{
|
|
GetAI()->NotifyProjectileApproaching(origin);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::NotifyOfMissileLock()
|
|
{
|
|
Check_Object(this);
|
|
|
|
if(vehicleInterface)
|
|
vehicleInterface->ReactToEvent (VehicleInterface::MISSILE_LOCKED_ON_ME);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
ResourceID
|
|
MWObject::ReactToMissileApproach(Scalar distance, const Point3D& current_position)
|
|
{
|
|
Check_Object(this);
|
|
if(GetAMS())
|
|
{
|
|
const AMS__GameModel *model = GetAMS()->GetGameModel();
|
|
Check_Object(model);
|
|
if(GetAMS()->DoesHaveAmmo())
|
|
{
|
|
GetAMS()->SubtractAmmo(1);
|
|
return model->amsEffectResource;
|
|
}
|
|
}
|
|
|
|
return ResourceID::Null;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::SetTargetDesirability(Stuff::Scalar desirability)
|
|
{
|
|
if (desirability == desirability_never)
|
|
{
|
|
Verify(Adept::EntityManager::GetInstance() != 0);
|
|
|
|
NameTable *table = NameTable::GetInstance();
|
|
{
|
|
int size(table->nameTableArray[NameTable::VehicleArray].GetLength());
|
|
|
|
{for (int i = 0;
|
|
i < size;
|
|
++i)
|
|
{
|
|
NameTableEntry *data = &table->nameTableArray [NameTable::VehicleArray][i];
|
|
Adept::Entity* ent = data->dataPointer->GetCurrent ();
|
|
|
|
if ((ent != 0) &&
|
|
(ent->IsDerivedFrom(MWObject::DefaultData) == true))
|
|
{
|
|
MWObject* mwobject = Cast_Object(MWObject*,ent);
|
|
if (mwobject->GetAI() != 0)
|
|
{
|
|
mwobject->GetAI()->EnsureNotTargeting(objectID);
|
|
}
|
|
}
|
|
}}
|
|
}
|
|
|
|
{
|
|
int size(table->nameTableArray[NameTable::TurretArray].GetLength());
|
|
|
|
{for (int i = 0;
|
|
i < size;
|
|
++i)
|
|
{
|
|
NameTableEntry *data = &table->nameTableArray [NameTable::TurretArray][i];
|
|
Adept::Entity* ent = data->dataPointer->GetCurrent ();
|
|
|
|
if ((ent != 0) &&
|
|
(ent->IsDerivedFrom(MWObject::DefaultData) == true))
|
|
{
|
|
MWObject* mwobject = Cast_Object(MWObject*,ent);
|
|
if (mwobject->GetAI() != 0)
|
|
{
|
|
mwobject->GetAI()->EnsureNotTargeting(objectID);
|
|
}
|
|
}
|
|
}}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (desirability != desirability_invalid)
|
|
{
|
|
Verify(desirability >= 0);
|
|
Verify(desirability <= 1);
|
|
}
|
|
}
|
|
|
|
m_TargetDesirability = desirability;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Stuff::Scalar
|
|
MWObject::GetTargetDesirability() const
|
|
{
|
|
return (m_TargetDesirability);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::NotifyFired(const Adept::Entity::CollisionQuery& query)
|
|
{
|
|
if (GetAI() != 0)
|
|
{
|
|
GetAI()->NotifyShotFired(query,*this);
|
|
}
|
|
|
|
if ((GetSensor() == 0) ||
|
|
(query.m_line == 0))
|
|
{
|
|
return;
|
|
}
|
|
|
|
const MechWarrior4::Sensor::sensorDataArray& sensed_data = GetSensor()->GetSensorData();
|
|
{for (int i = 0;
|
|
i < sensed_data.GetLength();
|
|
++i)
|
|
{
|
|
MechWarrior4::SensorData* d = sensed_data[i];
|
|
if ((d != 0) &&
|
|
(d->object.GetCurrent() != 0) &&
|
|
(d->object.GetCurrent() != this) &&
|
|
(d->object.GetCurrent()->IsDerivedFrom(MWObject::DefaultData)))
|
|
{
|
|
MWObject* that = Cast_Object(MWObject*,d->object.GetCurrent());
|
|
Check_Object(that);
|
|
|
|
if (that->GetAI() != 0)
|
|
{
|
|
that->GetAI()->NotifyShotFired(query,*this);
|
|
}
|
|
}
|
|
}}
|
|
|
|
// special case for shutdown mechs since they don't appear on sensors
|
|
MechAI::NotifyShutDownMechsShotFired(query,*this);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::NotifyInTargetingReticule(MWObject& who)
|
|
{
|
|
if (GetAI() != 0)
|
|
{
|
|
GetAI()->NotifyInTargetingReticule(who);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
MWObject::CollisionHandler(
|
|
Stuff::LinearMatrix4D *new_position,
|
|
Stuff::DynamicArrayOf<CollisionData> *collisions
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Verify(GetInterestLevel() != DormantInterestLevel);
|
|
Verify(EntityManager::GetInstance()->IsInPostCollisionExecution(this));
|
|
|
|
STOP(("What are we doing here?!?!"));
|
|
return false;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::GetLineOfSight(Stuff::LinearMatrix4D& line_of_sight)
|
|
{
|
|
if ((GetTorso()) &&
|
|
(GetTorso()->twistJoint))
|
|
{
|
|
line_of_sight = GetTorso()->twistJoint->GetLocalToWorld();
|
|
}
|
|
else
|
|
{
|
|
if (eyeSitePointer.GetCurrent())
|
|
{
|
|
line_of_sight = eyeSitePointer.GetCurrent()->GetLocalToWorld();
|
|
}
|
|
else
|
|
{
|
|
line_of_sight = GetLocalToWorld();
|
|
}
|
|
}
|
|
|
|
Adept::InternalDamageObject* torso_zone = internalDamageObjects.Find(Adept::InternalDamageObject::CenterTorsoZone);
|
|
|
|
if ((torso_zone != 0) &&
|
|
(torso_zone->parentEntity != 0))
|
|
{
|
|
line_of_sight.BuildTranslation((Stuff::Point3D)torso_zone->parentEntity->GetLocalToWorld());
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Stuff::Point3D
|
|
MWObject::GetLineOfSight()
|
|
{
|
|
Adept::InternalDamageObject* torso_zone = internalDamageObjects.Find(Adept::InternalDamageObject::CenterTorsoZone);
|
|
|
|
if ((torso_zone != 0) &&
|
|
(torso_zone->parentEntity != 0))
|
|
{
|
|
return (torso_zone->parentEntity->GetLocalToWorld());
|
|
}
|
|
|
|
if ((GetTorso()) &&
|
|
(GetTorso()->twistJoint))
|
|
{
|
|
return (GetTorso()->twistJoint->GetLocalToWorld());
|
|
}
|
|
|
|
if (eyeSitePointer.GetCurrent())
|
|
{
|
|
return (eyeSitePointer.GetCurrent()->GetLocalToWorld());
|
|
}
|
|
|
|
Point3D p(GetLocalToWorld());
|
|
p.y += 1.0f;
|
|
|
|
return (p);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::ReactToHit(const Entity__TakeDamageMessage *message,Adept::DamageObject *part_hit)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
|
|
if (g_nMR == 2)
|
|
return;
|
|
|
|
if (IsDestroyed())
|
|
return;
|
|
|
|
#ifdef LAB_ONLY
|
|
if ((GetOwner() != 0) &&
|
|
(MW4AI::Statistics::Enabled() == true))
|
|
{
|
|
Connection *connection = Network::GetInstance()->GetConnection(message->inflictingEntityID.connectionID);
|
|
|
|
if (connection == NULL)
|
|
return;
|
|
|
|
Replicator* r = connection->FindReplicator(message->inflictingEntityID);
|
|
if (r != 0)
|
|
{
|
|
Verify(r->IsDerivedFrom(Entity::DefaultData));
|
|
Entity* e = Cast_Object(Entity*,r);
|
|
|
|
MW4AI::Statistics::NotifyDamageTaken(objectID,e->objectID,message->amountOfDamage,message->typeOfDamage);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Stuff::Point3D&
|
|
MWObject::EstimateFuturePosition(
|
|
Stuff::Point3D* new_position,
|
|
Stuff::Scalar seconds,
|
|
bool consider_terrain
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
return *new_position = GetLocalToWorld();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::Reuse(
|
|
const CreateMessage *message,
|
|
ReplicatorID *base_id
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
|
|
STOP(("Not implemented"));
|
|
BaseClass::Reuse(message, base_id);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::ToggleSearchLight()
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(Mission::GetInstance());
|
|
|
|
if(Mission::GetInstance()->DoesAllowSearchLights())
|
|
{
|
|
if(searchLight)
|
|
{
|
|
if(IsSearchLightOn())
|
|
{
|
|
//
|
|
// [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 (IsPlayerVehicle())
|
|
// Mission::GetInstance()->ResetMissionLights();
|
|
searchLight->HideBeam();
|
|
// SetSearchLightMode(true);
|
|
}
|
|
else
|
|
{
|
|
// if (IsPlayerVehicle())
|
|
// Mission::GetInstance()->SetSearchLightMissionLights();
|
|
searchLight->ShowBeam();
|
|
// SetSearchLightMode(false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::TurnOnSearchLight()
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(Mission::GetInstance());
|
|
|
|
// MSL 5.02 SearchLight
|
|
// if(Mission::GetInstance()->m_isNightMission)
|
|
if(Mission::GetInstance()->DoesAllowSearchLights())
|
|
{
|
|
// if (IsPlayerVehicle())
|
|
// Mission::GetInstance()->SetSearchLightMissionLights();
|
|
if(searchLight)
|
|
searchLight->ShowBeam();
|
|
// SetSearchLightMode(true);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::TurnOffSearchLight()
|
|
{
|
|
Check_Object(this);
|
|
// MWMission *mw_mission = Cast_Object(MWMission *, MWMission::GetInstance());
|
|
// mw_mission->ResetMissionLights();
|
|
if(searchLight)
|
|
searchLight->HideBeam();
|
|
// SetSearchLightMode(false);
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
MWObject::IsSearchLightOn()
|
|
{
|
|
Check_Object(this);
|
|
|
|
if(searchLight)
|
|
return searchLight->isLightOn;
|
|
|
|
return false;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Stuff::Scalar
|
|
MWObject::FriendlyFireDamageMultiplier() const
|
|
{
|
|
return (1);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::TakeDamageMessageHandler(const TakeDamageMessage *message)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
Verify(message->messageID == TakeDamageMessageID);
|
|
|
|
if(damageObject)
|
|
{
|
|
damageObject->TakeDamage((TakeDamageMessage *)message, this);
|
|
}
|
|
|
|
DamageObject *damage_object;
|
|
SortedChainIteratorOf<DamageObject *, int> iterator(&damageObjects);
|
|
|
|
while((damage_object = iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(damage_object);
|
|
if(damage_object != damageObject)
|
|
{
|
|
damage_object->TakeDamage((TakeDamageMessage *)message, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
char*
|
|
MWObject::GetObjectName()
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(MWApplication::GetInstance());
|
|
|
|
if(m_doesHaveInstanceName)
|
|
{
|
|
if((m_localizeIndex > -1) && (!isPlayerVehicle))
|
|
{
|
|
return MWApplication::GetInstance()->GetLocString(m_localizeIndex);
|
|
}
|
|
else
|
|
{
|
|
return (char *)instanceName;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(isPlayerVehicle)
|
|
return (char *)instanceName;
|
|
}
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
|
|
return MWApplication::GetInstance()->GetLocString(model->m_nameIndex);
|
|
}
|
|
|
|
char* MWObject::GetModelName()
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(MWApplication::GetInstance());
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
|
|
return MWApplication::GetInstance()->GetLocString(model->m_nameIndex);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
MWObject::GetVisibleOnSensors() const
|
|
{
|
|
return (m_VisibleOnSensors);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::SetVisibleOnSensors(bool visible)
|
|
{
|
|
m_VisibleOnSensors = visible;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
MWObject::DoesHaveAvailableTonage(Stuff::Scalar tons)
|
|
{
|
|
Check_Object(this);
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
|
|
return (tonage + tons) <= model->maxVehicleTonnage + 0.01f;
|
|
}
|
|
|
|
void MWObject::EngineDead (void)
|
|
{
|
|
STOP (("Only a drop ship should handle this function"));
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
Adept::Site* MWObject::FindSite(const char *site_name)
|
|
{
|
|
Check_Object(this);
|
|
Check_Pointer(site_name);
|
|
Adept::Site* pSite = m_sites.Find(site_name);
|
|
if (pSite) {
|
|
Check_Object(pSite->GetParent());
|
|
}
|
|
return pSite;
|
|
}
|
|
#endif // _DEBUG
|
|
void MWObject::SetDmgModifier (int nIdx, int nDmgFactor)
|
|
{
|
|
// nIdx : 0: default, 1: splash
|
|
gosASSERT((0 <= nIdx) && (nIdx < 2));
|
|
// nDmgFactor: < 0 - restore
|
|
// nDmgFactor: == 0 - store
|
|
// nDmgFactor: > 0 - set damage modifier as (nDmgFactor/10000.0)
|
|
Check_Pointer(this);
|
|
|
|
SortedChainIteratorOf<DamageObject *, int> iterator(&damageObjects);
|
|
|
|
DamageObject *damage_object;
|
|
|
|
nIdx *= 2;
|
|
if (nDmgFactor < 0) { // restore
|
|
while((damage_object = iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(damage_object);
|
|
damage_object->SetDamageModifier(nIdx, damage_object->GetDamageModifier(nIdx + 1));
|
|
}
|
|
} else if (nDmgFactor == 0) {
|
|
while((damage_object = iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(damage_object);
|
|
damage_object->SetDamageModifier(nIdx + 1, damage_object->GetDamageModifier(nIdx));
|
|
}
|
|
} else {
|
|
Stuff::Scalar f = static_cast<Stuff::Scalar>(nDmgFactor / 10000.0);
|
|
while((damage_object = iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(damage_object);
|
|
damage_object->SetDamageModifier(nIdx, f);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MWObject::RepairDamage (Stuff::Scalar fRepair)
|
|
{
|
|
// jcem
|
|
Check_Pointer(this);
|
|
if (fRepair <= 0.0f)
|
|
return;
|
|
if (1.0f < fRepair)
|
|
fRepair = 1.0f;
|
|
|
|
SortedChainIteratorOf<DamageObject *, int> iterator(&damageObjects);
|
|
|
|
DamageObject *damage_object;
|
|
|
|
while((damage_object = iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(damage_object);
|
|
damage_object->RepairDamage(fRepair);
|
|
}
|
|
}
|