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.
1242 lines
34 KiB
C++
1242 lines
34 KiB
C++
//===========================================================================//
|
|
// File: WeaponMover.cpp
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// 09/09/98 JSE Inital base class based off of Shadowrun/Adept //
|
|
// 09/25/98 BDB WeaponMover based on Vehicle //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1998, Fasa Interactive //
|
|
// All Rights reserved worldwide //
|
|
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
|
//===========================================================================//
|
|
|
|
#include "MW4Headers.hpp"
|
|
|
|
#include "WeaponMover.hpp"
|
|
#include "Vehicle.hpp"
|
|
#include "DeathEntity.hpp"
|
|
#include "missile.hpp"
|
|
|
|
#include <Adept\Map.hpp>
|
|
#include <Adept\Effect.hpp>
|
|
#include <Adept\NameTable.hpp>
|
|
#include <Adept\EntityManager.hpp>
|
|
#include <Adept\Effect.hpp>
|
|
|
|
#include <gosFX\gosFX.hpp>
|
|
#include <ElementRenderer\Element.hpp>
|
|
|
|
#include "MWDamageObject.hpp"
|
|
#include <Adept\CollisionGrid.hpp>
|
|
#include <Adept\CollisionVolume.hpp>
|
|
#include "mwmission.hpp"
|
|
#include "bucket.hpp"
|
|
#include "MWApplication.hpp"
|
|
|
|
#include <Compost\CompostHeaders.hpp>
|
|
|
|
//#############################################################################
|
|
//############################### WeaponMover ###########################
|
|
//#############################################################################
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
WeaponMover::ClassData*
|
|
WeaponMover::DefaultData = NULL;
|
|
|
|
DWORD MechWarrior4::Executed_WeaponMover_Count = 0;
|
|
|
|
|
|
void MechWarrior4::WeaponMoverSecurityCheckStart()
|
|
{
|
|
_asm
|
|
{
|
|
nop
|
|
}
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
WeaponMover::InitializeClass()
|
|
{
|
|
Check_Object(BaseClass::DefaultData);
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
WeaponMoverClassID,
|
|
"MechWarrior4::WeaponMover",
|
|
BaseClass::DefaultData,
|
|
0, NULL,
|
|
(Entity::Factory)Make,
|
|
(Entity::CreateMessage::Factory)CreateMessage::ConstructCreateMessage,
|
|
ExecutionStateEngine::DefaultData,
|
|
(Entity::GameModel::Factory)GameModel::ConstructGameModel,
|
|
NULL,
|
|
(Entity::GameModel::ReadAndVerifier)GameModel::ReadAndVerify,
|
|
(Entity::GameModel::ModelWrite)GameModel::WriteToText,
|
|
(Entity::GameModel::ModelSave)GameModel::SaveGameModel
|
|
);
|
|
Register_Object(DefaultData);
|
|
|
|
INDIRECT_STATE_ATTRIBUTE(
|
|
WeaponMover,
|
|
ExecutionState,
|
|
executionState,
|
|
WeaponMover__ExecutionStateEngine
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
WeaponMover__GameModel,
|
|
MaxDistance,
|
|
maxDistance,
|
|
Scalar
|
|
);
|
|
|
|
// MSL 5.03 Min Distance
|
|
// DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
// WeaponMover__GameModel,
|
|
// MinDistance,
|
|
// minDistance,
|
|
// Scalar
|
|
// );
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
WeaponMover__GameModel,
|
|
TrailResource,
|
|
trailResource,
|
|
ResourceID
|
|
);
|
|
|
|
CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
WeaponMover__GameModel,
|
|
DoesPlaceCrater,
|
|
doesPlaceCrater,
|
|
bool,
|
|
BoolClassID
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
WeaponMover__GameModel,
|
|
HitEffectResource,
|
|
hitEffectResourceID,
|
|
ResourceID
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
WeaponMover__GameModel,
|
|
SecondaryHitEffectResource,
|
|
secondaryHitEffectResourceID,
|
|
ResourceID
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
WeaponMover__GameModel,
|
|
DamageDecalResource,
|
|
damageDecalResourceID,
|
|
ResourceID
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
WeaponMover__GameModel,
|
|
LightAmpFlareOut,
|
|
m_lightAmpFlareOut,
|
|
Scalar
|
|
);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
WeaponMover::TerminateClass()
|
|
{
|
|
Unregister_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
WeaponMover*
|
|
WeaponMover::Make(
|
|
CreateMessage *message,
|
|
ReplicatorID *base_id
|
|
)
|
|
{
|
|
Check_Object(message);
|
|
gos_PushCurrentHeap(Heap);
|
|
Check_Object(EntityManager::GetInstance());
|
|
WeaponMover *new_entity;
|
|
Entity *entity = EntityManager::GetInstance()->RequestFromArmory(message->dataListID);
|
|
if (entity)
|
|
{
|
|
new_entity = Cast_Object(WeaponMover*, entity);
|
|
new_entity->Reuse(message, base_id);
|
|
}
|
|
else
|
|
new_entity = new WeaponMover(DefaultData, message, base_id, NULL);
|
|
gos_PopCurrentHeap();
|
|
Check_Object(new_entity);
|
|
return new_entity;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
WeaponMover::WeaponMover(
|
|
ClassData *class_data,
|
|
CreateMessage *message,
|
|
ReplicatorID *base_id,
|
|
ElementRenderer::Element *element
|
|
):
|
|
Mover(class_data, message, base_id, element),
|
|
splashedEntities(NULL),
|
|
trailEffect(NULL)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(message);
|
|
|
|
damageAmount = message->damageAmount;
|
|
heatAmount = message->heatAmount;
|
|
maxDistance = message->maxDistance;
|
|
// MSL 5.03 Min Distance
|
|
// minDistance = message->minDistance;
|
|
|
|
itemID = message->itemID;
|
|
|
|
Check_Object(entityElement);
|
|
const LinearMatrix4D &local_to_parent = entityElement->GetNewLocalToParent();
|
|
Check_Object(&local_to_parent);
|
|
|
|
startPoint = local_to_parent;
|
|
|
|
inflictingEntityID = message->inflictingEntityID;
|
|
|
|
if (MWApplication::GetInstance()->networkingFlag == true)
|
|
{
|
|
MWMission *mission;
|
|
Check_Object (MWMission::GetInstance());
|
|
mission = Cast_Object (MWMission *,MWMission::GetInstance());
|
|
mission->m_BucketManager->NotifyAction (CBucketManager::SHOTS_FIRED,inflictingEntityID,1);
|
|
}
|
|
|
|
Check_Object(Network::GetInstance());
|
|
Connection *connection = Network::GetInstance()->GetConnection(message->inflictingEntityID.connectionID);
|
|
Check_Object(connection);
|
|
|
|
Replicator *replicator;
|
|
replicator = connection->FindReplicator(message->inflictingEntityID);
|
|
Verify(replicator->IsDerivedFrom(MWObject::DefaultData));
|
|
inflictingVehicle = Cast_Object(MWObject*, replicator);
|
|
dontHit = inflictingVehicle;
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
if(model->trailResource != ResourceID::Null)
|
|
{
|
|
CreateMissileTrail();
|
|
}
|
|
|
|
splashSize = 0;
|
|
|
|
|
|
|
|
splashRadius = message->splashRadius;
|
|
percentageOfDamageToDirectHit = message->percentageOfDamageToDirectHit;
|
|
minPercentageOfDamageToSphereHit = message->minPercentageOfDamageToSphereHit;
|
|
maxPercentageOfDamageToSphereHit = message->maxPercentageOfDamageToSphereHit;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
WeaponMover::~WeaponMover()
|
|
{
|
|
DESTRUCTOR("WeaponMover");
|
|
Check_Object(this);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
WeaponMover::Reuse(
|
|
const CreateMessage *message,
|
|
ReplicatorID *base_id
|
|
)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(message);
|
|
|
|
BaseClass::Reuse(message, base_id);
|
|
|
|
damageAmount = message->damageAmount;
|
|
maxDistance = message->maxDistance;
|
|
// MSL 5.03 Min Distance
|
|
// minDistance = message->minDistance;
|
|
|
|
Check_Object(entityElement);
|
|
const LinearMatrix4D &local_to_parent = entityElement->GetNewLocalToParent();
|
|
Check_Object(&local_to_parent);
|
|
|
|
startPoint = local_to_parent;
|
|
|
|
inflictingEntityID = message->inflictingEntityID;
|
|
|
|
Check_Object(Network::GetInstance());
|
|
Connection *connection = Network::GetInstance()->GetConnection(message->inflictingEntityID.connectionID);
|
|
Check_Object(connection);
|
|
|
|
Replicator *replicator;
|
|
replicator = connection->FindReplicator(message->inflictingEntityID);
|
|
Verify(replicator->IsDerivedFrom(MWObject::DefaultData));
|
|
inflictingVehicle = Cast_Object(MWObject*, replicator);
|
|
dontHit = inflictingVehicle;
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
if(model->trailResource != ResourceID::Null)
|
|
{
|
|
CreateMissileTrail();
|
|
}
|
|
|
|
splashSize = 0;
|
|
|
|
splashRadius = message->splashRadius;
|
|
percentageOfDamageToDirectHit = message->percentageOfDamageToDirectHit;
|
|
minPercentageOfDamageToSphereHit = message->minPercentageOfDamageToSphereHit;
|
|
maxPercentageOfDamageToSphereHit = message->maxPercentageOfDamageToSphereHit;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void WeaponMover::SentenceToDeathRow()
|
|
{
|
|
Check_Object(this);
|
|
|
|
if(trailEffect.GetCurrent())
|
|
trailEffect.GetCurrent()->executionState->RequestState(Effect::ExecutionStateEngine::StoppingState);
|
|
|
|
BaseClass::SentenceToDeathRow();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
WeaponMover::GetExecutionSlot()
|
|
{
|
|
Check_Object(this);
|
|
return BuildingExecutionSlot;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
WeaponMover::PreCollisionExecute(Time till)
|
|
{
|
|
Check_Object(this);
|
|
PRECOLLISION_LOGIC("WeaponMover");
|
|
|
|
if (oldCollisions)
|
|
{
|
|
worldSpaceVelocity = Motion3D::Identity;
|
|
localSpaceVelocity = Motion3D::Identity;
|
|
worldSpaceAcceleration = Motion3D::Identity;
|
|
localSpaceAcceleration = Motion3D::Identity;
|
|
SentenceToDeathRow();
|
|
UsePostCollision();
|
|
BaseClass::PreCollisionExecute(till);
|
|
return;
|
|
}
|
|
Vector3D distance;
|
|
Point3D initial_position;
|
|
initial_position = startPoint;
|
|
Point3D pointStartThisFrame;
|
|
pointStartThisFrame = GetLocalToParent();
|
|
|
|
distance.Subtract(pointStartThisFrame, initial_position);
|
|
Scalar maxDistanceSquared = maxDistance * maxDistance;
|
|
// MSL 5.03 Min Distance
|
|
// Scalar minDistanceSquared = minDistance * minDistance;
|
|
|
|
// if(distance.GetLengthSquared() >= maxDistanceSquared)
|
|
// {
|
|
// Set_Statistic(Executed_WeaponMover_Count, Executed_WeaponMover_Count+1);
|
|
// UsePostCollision();
|
|
// SentenceToDeathRow();
|
|
// return;
|
|
// }
|
|
//
|
|
//----------------------------------------
|
|
// Let our base class set up the variables
|
|
//----------------------------------------
|
|
//
|
|
Set_Statistic(Executed_WeaponMover_Count, Executed_WeaponMover_Count+1);
|
|
UsePostCollision();
|
|
BaseClass::PreCollisionExecute(till);
|
|
|
|
Check_Object(executionState);
|
|
int execution_state = executionState->GetState();
|
|
if(execution_state == ExecutionStateEngine::StraightLineMotionState)
|
|
{
|
|
Point3D current_position;
|
|
ElementRenderer::Element *element = GetElement();
|
|
current_position = element->GetNewLocalToParent();
|
|
distance.Subtract(current_position, initial_position);
|
|
//
|
|
// We still need to run post collision this frame on anything within our
|
|
// range, we can't just skip in the same frame as we went to far so clamp
|
|
// the far point.
|
|
//
|
|
if(distance.GetLengthSquared() >= maxDistanceSquared)
|
|
{
|
|
//
|
|
// Clamp the end point
|
|
//
|
|
Vector3D direction;
|
|
direction.Normalize(distance);
|
|
Line3D line;
|
|
line.m_origin = initial_position;
|
|
line.m_direction = direction;
|
|
line.m_length = maxDistance+1.0f;
|
|
line.FindEnd(&pointStartThisFrame); // reusing variable
|
|
LinearMatrix4D new_local_to_parent;
|
|
new_local_to_parent = element->GetNewLocalToParent();
|
|
new_local_to_parent.BuildTranslation(pointStartThisFrame);
|
|
SetNewLocalToParent(new_local_to_parent);
|
|
|
|
}
|
|
}
|
|
|
|
BlowUpIfOffMap();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
#if defined(LAB_ONLY)
|
|
void WeaponMover::SyncMatrices(bool update_matrix)
|
|
{
|
|
SYNC_LOGIC("WeaponMover");
|
|
BaseClass::SyncMatrices(update_matrix);
|
|
}
|
|
#endif
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
WeaponMover::CollisionHandler(
|
|
Stuff::LinearMatrix4D *new_position,
|
|
Stuff::DynamicArrayOf<CollisionData> *collisions
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(collisions);
|
|
Verify(collisions->GetLength() == 1);
|
|
|
|
Verify(EntityManager::GetInstance()->IsInPostCollisionExecution(this));
|
|
newCollisions = collisions;
|
|
Verify(GetInterestLevel() != DormantInterestLevel);
|
|
|
|
//
|
|
//-----------------------
|
|
// Time for us to blow up
|
|
//-----------------------
|
|
//
|
|
if (oldCollisions)
|
|
SentenceToDeathRow();
|
|
else
|
|
// make sure we're on the post collision chain
|
|
{
|
|
|
|
Verify(collisions->GetLength() == 1);
|
|
CollisionData *data = &(*collisions)[0];
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
//
|
|
// Make sure we're not past our effective range. This is most important for missiles because burn time
|
|
// makes their distance hard to judge,and we want them to not do damage once they run out of fuel.
|
|
//
|
|
//
|
|
Vector3D distance;
|
|
Point3D initial_position;
|
|
initial_position = startPoint;
|
|
Point3D pointStartThisFrame;
|
|
pointStartThisFrame = data->m_worldIntersectionPoint;
|
|
|
|
distance.Subtract(pointStartThisFrame, initial_position);
|
|
Scalar maxDistanceSquared = (maxDistance + 1.5f) * (maxDistance + 1.5f);
|
|
// MSL 5.03 Min Distance
|
|
// Scalar minDistanceSquared = (minDistance + 1.5f) * (minDistance + 1.5f);
|
|
//
|
|
//---------------------------------
|
|
// Create the hit and damage decals
|
|
// Do this here since it causes problems in post collision
|
|
//---------------------------------
|
|
//
|
|
|
|
//
|
|
// We are not going to do ground hit effects if they are under water, but we will if it hits anything else
|
|
//
|
|
Check_Object (Map::GetInstance());
|
|
const Adept::Map__GameModel *mapModel = Map::GetInstance()->GetGameModel();
|
|
Check_Object(mapModel);
|
|
|
|
if(distance.GetLengthSquared() <= maxDistanceSquared)
|
|
{
|
|
if (data->m_worldIntersectionPoint.y >= ((mapModel->m_waterLevel) -.001f) ||
|
|
!data->m_otherEntity ||
|
|
!data->m_otherEntity->IsDerivedFrom(Map::DefaultData))
|
|
|
|
{
|
|
|
|
CreateHitEffect(
|
|
data->m_normal,
|
|
data->m_worldIntersectionPoint,
|
|
data->m_material
|
|
);
|
|
|
|
if(data->m_otherEntity)
|
|
{
|
|
if(!(data->m_otherEntity->IsDerivedFrom(Map::DefaultData)))
|
|
{
|
|
CreateSecondaryHitEffect(
|
|
data->m_normal,
|
|
data->m_worldIntersectionPoint,
|
|
data->m_material,
|
|
data->m_otherEntity
|
|
);
|
|
}
|
|
|
|
if((data->m_otherEntity->IsDerivedFrom(Map::DefaultData)) &&
|
|
(model->doesPlaceCrater))
|
|
{
|
|
CreateDamageDecal(
|
|
data->m_otherEntity,
|
|
data->m_normal,
|
|
data->m_worldIntersectionPoint
|
|
);
|
|
if(Compost::TerrainTextureLogistic::Instance)
|
|
{
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
if(model->m_craterID >= 0)
|
|
{
|
|
Point3D local_to_world;
|
|
local_to_world = GetLocalToWorld();
|
|
Compost::TerrainTextureLogistic::Instance->AddFeature(
|
|
model->m_craterID, local_to_world.x, local_to_world.z);
|
|
}
|
|
}
|
|
} // if it's the map and we need a crater
|
|
else if(data->m_otherEntity->IsDerivedFrom(MWMover::DefaultData))
|
|
{
|
|
MWMover *hit_mover;
|
|
hit_mover = Cast_Object(MWMover *, data->m_otherEntity);
|
|
|
|
if(hit_mover->GetParentVehicle())
|
|
{
|
|
if(hit_mover->GetParentVehicle()->IsDerivedFrom(MWObject::DefaultData))
|
|
{
|
|
MWObject *hit_object;
|
|
hit_object = Cast_Object(MWObject *, hit_mover->GetParentVehicle());
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
|
|
if(hit_object->vehicleInterface)
|
|
{
|
|
hit_object->vehicleInterface->SetLightAmpFlareOut(model->m_lightAmpFlareOut);
|
|
}
|
|
}
|
|
} // if it's the player mech
|
|
} // else (it's an object)
|
|
} // if we hit an object (non-map)
|
|
} // if we hit nothing (just in case) an object (non-map), or we hit above water
|
|
}
|
|
//
|
|
// if we just hit water then splash and continue
|
|
//
|
|
initialLocalToParent = GetLocalToWorld();
|
|
initialLocalToParent.BuildTranslation(data->m_worldIntersectionPoint);
|
|
|
|
|
|
if (data->m_otherEntity && data->m_material == WaterMaterial)
|
|
{
|
|
Point3D pointIntersection;
|
|
pointIntersection = data->m_worldIntersectionPoint;
|
|
Vector3D normalIntersection;
|
|
normalIntersection.Multiply(data->m_normal, -.001f);
|
|
pointIntersection += normalIntersection;
|
|
initialLocalToParent.BuildTranslation(pointIntersection);
|
|
|
|
|
|
|
|
delete newCollisions;
|
|
newCollisions = NULL;
|
|
|
|
//
|
|
// Take water collision off since we are now done with it.
|
|
//
|
|
|
|
/*
|
|
CollisionMask currentMask;
|
|
|
|
currentMask = GetCollisionMask();
|
|
currentMask &= (~Entity::WaterSurfaceFlag);
|
|
SetCollisionMask(currentMask);
|
|
*/
|
|
}
|
|
|
|
*new_position = initialLocalToParent;
|
|
SetNewLocalToParent(*new_position);
|
|
lastParameterization = gos_GetElapsedTime();
|
|
return true;
|
|
|
|
}
|
|
|
|
//
|
|
// Moved to actual post collision processing as per JM's request to make sure splash damage works correctly.
|
|
//
|
|
// else
|
|
// PostCollision(collisions);
|
|
return false;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
WeaponMover::PostCollisionExecute(Stuff::Time till)
|
|
{
|
|
Check_Object(this);
|
|
POSTCOLLISION_LOGIC("WeaponMover");
|
|
|
|
Vector3D distance;
|
|
Point3D initial_position;
|
|
initial_position = startPoint;
|
|
Point3D pointStartThisFrame;
|
|
pointStartThisFrame = GetLocalToParent();
|
|
distance.Subtract(pointStartThisFrame, initial_position);
|
|
//
|
|
// Need to put on a slop factor of 1.5 just in case the last frame went past the max length
|
|
// and ended up clamping it to +1, we don't want to not apply damage under those circumstances.
|
|
//
|
|
Scalar maxDistanceSquared = (maxDistance) * (maxDistance);
|
|
Scalar maxDistanceSquaredForDamage = (maxDistance + 1.5f) * (maxDistance + 1.5f);
|
|
Scalar distanceSquared = distance.GetLengthSquared();
|
|
// MSL 5.03 Min Distance
|
|
// Scalar minDistanceSquared = (minDistance) * (minDistance);
|
|
// Scalar minDistanceSquaredForDamage = (minDistance + 1.5f) * (minDistance + 1.5f);
|
|
//
|
|
// [johnyo] According to JM we need to assign the splash damage during
|
|
// post collision, or else the splash search may not work.
|
|
//
|
|
// Don't apply damage if we are past our range.
|
|
//
|
|
if (distanceSquared >= maxDistanceSquared)
|
|
{
|
|
//
|
|
// There is a slop factor that needs to happen when we clamp the last frame of the motion to the
|
|
// max distance + 1.0
|
|
//
|
|
if (distanceSquared <= maxDistanceSquaredForDamage && newCollisions && !oldCollisions) // this would indicate we just hit things, and it's not time to die
|
|
{
|
|
|
|
PostCollision(newCollisions);
|
|
}
|
|
|
|
BaseClass::PostCollisionExecute(till);
|
|
//
|
|
// Missiles will continue their path and succomb to gravity and the ground eventually.
|
|
//
|
|
if (!this->IsDerivedFrom(Missile::DefaultData))
|
|
{
|
|
SentenceToDeathRow();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (newCollisions && !oldCollisions) // this would indicate we just hit things, and it's not time to die
|
|
{
|
|
|
|
PostCollision(newCollisions);
|
|
}
|
|
BaseClass::PostCollisionExecute(till);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
WeaponMover::PostCollision(Stuff::DynamicArrayOf<CollisionData> *collisions)
|
|
{
|
|
Check_Object(this);
|
|
POSTCOLLISION_LOGIC("WeaponMover::Explode");
|
|
|
|
#ifdef _ARMOR // otherwise, this doesn't compile -- PAULTOZ
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
#endif
|
|
|
|
Verify(collisions->GetLength() == 1);
|
|
CollisionData *data = &(*collisions)[0];
|
|
|
|
//This function should be called by all collision handlers that are derived
|
|
//From WeaponMover
|
|
//
|
|
//---------------------------------
|
|
// Apply damage to the thing we hit
|
|
//---------------------------------
|
|
//
|
|
|
|
if (splashRadius == 0.0f)
|
|
{
|
|
// MSL 5.06 Armor Mode
|
|
MWApplication *m_App;
|
|
m_App = MWApplication::GetInstance ();
|
|
m_ArmorMode = m_App->GetLocalNetParams()->m_armormodeOn;
|
|
|
|
Entity::TakeDamageMessage damage_message(
|
|
data->m_otherEntity->GetReplicatorID(),
|
|
inflictingEntityID,
|
|
damageAmount,
|
|
m_ArmorMode,
|
|
GetDamageType(), //Telling it that I am a projectile
|
|
data->m_normal,
|
|
data->m_worldIntersectionPoint,
|
|
heatAmount,
|
|
false,
|
|
itemID
|
|
);
|
|
|
|
data->m_otherEntity->Receive(&damage_message);
|
|
//data->m_otherEntity->Dispatch(&damage_message);
|
|
|
|
}
|
|
else
|
|
{
|
|
DealSplashDamage(data);
|
|
}
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void WeaponMover::DealSplashDamage(const CollisionData *data)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(CollisionGrid::Instance);
|
|
POSTCOLLISION_LOGIC("WeaponMover::Splash");
|
|
|
|
extern g_nMR;
|
|
if (g_nMR == 2)
|
|
return;
|
|
|
|
Stuff::Sphere sphere;
|
|
|
|
//
|
|
// We need to apply direct damage before checking for splash damage radius. Otherwise if the
|
|
// collision info is a little off, or the collision radius is too small, no damage is done
|
|
//
|
|
// MSL 5.04 Building Missile Damage
|
|
// if we hit something deal a set percentage to that part
|
|
if (data->m_otherEntity != NULL && data->m_otherEntity != Map::GetInstance())
|
|
{
|
|
if (data->m_otherEntity->IsDerivedFrom(Building::DefaultData))
|
|
{
|
|
// MSL 5.06 Armor Mode
|
|
MWApplication *m_App;
|
|
m_App = MWApplication::GetInstance ();
|
|
m_ArmorMode = m_App->GetLocalNetParams()->m_armormodeOn;
|
|
|
|
Entity::TakeDamageMessage damage_message(
|
|
data->m_otherEntity->GetReplicatorID(),
|
|
inflictingEntityID,
|
|
damageAmount, //Do full damage
|
|
m_ArmorMode,
|
|
GetDamageType(), //Telling it that I am a projectile
|
|
data->m_normal,
|
|
data->m_worldIntersectionPoint,
|
|
heatAmount,
|
|
false,
|
|
itemID
|
|
);
|
|
|
|
data->m_otherEntity->Receive(&damage_message);
|
|
}
|
|
else
|
|
{
|
|
// MSL 5.06 Armor Mode
|
|
MWApplication *m_App;
|
|
m_App = MWApplication::GetInstance ();
|
|
m_ArmorMode = m_App->GetLocalNetParams()->m_armormodeOn;
|
|
|
|
Entity::TakeDamageMessage damage_message(
|
|
data->m_otherEntity->GetReplicatorID(),
|
|
inflictingEntityID,
|
|
damageAmount * percentageOfDamageToDirectHit, // Do percentage of full damage
|
|
m_ArmorMode,
|
|
GetDamageType(), //Telling it that I am a projectile
|
|
data->m_normal,
|
|
data->m_worldIntersectionPoint,
|
|
heatAmount * percentageOfDamageToDirectHit,
|
|
false,
|
|
itemID
|
|
);
|
|
|
|
data->m_otherEntity->Receive(&damage_message);
|
|
}
|
|
}
|
|
|
|
//
|
|
// The splash damage has to be applied to the collision location, not the current entity location
|
|
// While this is especially true for proximity teleports it's true of slow frame rates as well.
|
|
//sphere.center = GetLocalToWorld();
|
|
sphere.center = data->m_worldIntersectionPoint;
|
|
sphere.radius = splashRadius;
|
|
|
|
CollisionGrid::Instance->FindEntitiesWithin(sphere, (Adept::CollisionGrid::WithinCallback)SplashCallBack, this);
|
|
|
|
|
|
if (splashSize == 0)
|
|
return;
|
|
|
|
// iterate the list
|
|
|
|
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();
|
|
}
|
|
// Set the damage object that received direct damage so it won't take more.
|
|
if (data->m_otherEntity && data->m_otherEntity->damageObject)
|
|
{
|
|
data->m_otherEntity->damageObject->SetTakenDamageFromThisEvent();
|
|
}
|
|
splashed_entities.First();
|
|
|
|
Scalar splash_damage = damageAmount * (1.0f - percentageOfDamageToDirectHit);
|
|
Scalar heat_damage = heatAmount * (1.0f - percentageOfDamageToDirectHit);
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
if (data->m_otherEntity != hit_entity) // don't double deal
|
|
{
|
|
// MSL 5.06 Armor Mode
|
|
MWApplication *m_App;
|
|
m_App = MWApplication::GetInstance ();
|
|
m_ArmorMode = m_App->GetLocalNetParams()->m_armormodeOn;
|
|
|
|
Verify(splashSize != 0);
|
|
Adept::Entity__TakeDamageMessage message(
|
|
hit_entity->GetReplicatorID(),
|
|
inflictingEntityID,
|
|
splash_damage,
|
|
m_ArmorMode,
|
|
SplashDamageType,
|
|
data->m_normal,
|
|
data->m_worldIntersectionPoint,
|
|
heat_damage,
|
|
false,
|
|
itemID
|
|
);
|
|
|
|
hit_entity->Receive(&message);
|
|
}
|
|
splashed_entities.Remove();
|
|
}
|
|
|
|
splashSize = 0;
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void WeaponMover::SplashCallBack(Entity *entity, Entity *original_caller, const Stuff::Sphere &sphere)
|
|
{
|
|
|
|
Check_Object(entity);
|
|
Check_Object(original_caller);
|
|
|
|
WeaponMover *weapon = Cast_Object( WeaponMover*, original_caller);
|
|
|
|
|
|
if (!entity->IsDestroyed())
|
|
{
|
|
|
|
CollisionVolume *volume = entity->GetHierarchicalVolume();
|
|
if (volume)
|
|
{
|
|
|
|
volume->FindSolidsWithin(
|
|
sphere,
|
|
(Adept::CollisionVolume::WithinCallback)SubSplashCallBack,
|
|
weapon,
|
|
entity,
|
|
entity->GetLocalToWorld()
|
|
);
|
|
}
|
|
else
|
|
{
|
|
weapon->splashedEntities.Add(entity);
|
|
++weapon->splashSize;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void WeaponMover::SubSplashCallBack(CollisionVolume *solid, Entity *original_caller, const Stuff::Sphere &sphere)
|
|
{
|
|
|
|
Check_Object(solid);
|
|
Check_Object(original_caller);
|
|
|
|
WeaponMover *weapon = Cast_Object( WeaponMover*, original_caller);
|
|
|
|
|
|
weapon->splashedEntities.Add(solid->m_entity);
|
|
|
|
++weapon->splashSize;
|
|
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void
|
|
WeaponMover::CreateHitEffect(
|
|
Normal3D normal,
|
|
Point3D target_point,
|
|
BYTE hit_material
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
|
|
ResourceID hit_effect_resource_id = ResourceID::Null;
|
|
|
|
if((model->hitEffectMaterialTable != ResourceID::Null) &&
|
|
(hit_material >= 0) && (hit_material < MaterialCount))
|
|
{
|
|
Entity__GameModel::GetEffectResourceID(&hit_effect_resource_id,
|
|
model->hitEffectMaterialTable, hit_material
|
|
);
|
|
}
|
|
else
|
|
{
|
|
hit_effect_resource_id = model->hitEffectResourceID;
|
|
}
|
|
|
|
if(hit_effect_resource_id != ResourceID::Null)
|
|
{
|
|
Resource hit_effect_resource(hit_effect_resource_id);
|
|
Verify(hit_effect_resource.DoesResourceExist());
|
|
|
|
ClassID class_ID;
|
|
class_ID = GetClassIDFromDataListID(hit_effect_resource_id);
|
|
Verify(class_ID != NullClassID);
|
|
|
|
LinearMatrix4D effect_position = LinearMatrix4D::Identity;
|
|
effect_position.AlignLocalAxisToWorldVector(normal, Y_Axis, X_Axis, Z_Axis);
|
|
effect_position.BuildTranslation(target_point);
|
|
|
|
Effect::CreateMessage effect_create_message(
|
|
sizeof(Effect::CreateMessage),
|
|
DefaultEventPriority,
|
|
CreateMessage::DefaultFlags,
|
|
class_ID,
|
|
Effect::DefaultFlags,
|
|
hit_effect_resource_id,
|
|
effect_position,
|
|
0.0f,
|
|
ExecutionStateEngine::AlwaysExecuteState,
|
|
NameTable::NullObjectID,
|
|
Entity::DefaultAlignment
|
|
);
|
|
MemoryStream stream(&effect_create_message, effect_create_message.messageLength);
|
|
|
|
Entity *entity;
|
|
ReplicatorID beam_id = Connection::Hermit->GetNextReplicatorID();
|
|
entity = CreateEntity(&stream, &beam_id, false);
|
|
Check_Object(entity);
|
|
Check_Object(Map::GetInstance());
|
|
Map::GetInstance()->AddChild(entity);
|
|
entity->SyncMatrices(true);
|
|
|
|
// Sound stuff here...
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void
|
|
WeaponMover::CreateSecondaryHitEffect(
|
|
Normal3D normal,
|
|
Point3D target_point,
|
|
BYTE hit_material,
|
|
Entity *entity_hit
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
|
|
ResourceID hit_effect_resource_id = ResourceID::Null;
|
|
|
|
if((model->secondaryHitEffectMaterialTable != ResourceID::Null) &&
|
|
(hit_material >= 0) && (hit_material < MaterialCount))
|
|
{
|
|
Entity__GameModel::GetEffectResourceID(&hit_effect_resource_id,
|
|
model->secondaryHitEffectMaterialTable, hit_material
|
|
);
|
|
}
|
|
else
|
|
{
|
|
hit_effect_resource_id = model->secondaryHitEffectResourceID;
|
|
}
|
|
|
|
if(hit_effect_resource_id != ResourceID::Null)
|
|
{
|
|
Resource hit_effect_resource(hit_effect_resource_id);
|
|
Verify(hit_effect_resource.DoesResourceExist());
|
|
|
|
ClassID class_ID;
|
|
class_ID = GetClassIDFromDataListID(hit_effect_resource_id);
|
|
Verify(class_ID != NullClassID);
|
|
|
|
LinearMatrix4D effect_position = LinearMatrix4D::Identity;
|
|
effect_position.AlignLocalAxisToWorldVector(normal, Y_Axis, X_Axis, Z_Axis);
|
|
effect_position.BuildTranslation(target_point);
|
|
|
|
Effect::CreateMessage effect_create_message(
|
|
sizeof(Effect::CreateMessage),
|
|
DefaultEventPriority,
|
|
CreateMessage::DefaultFlags,
|
|
class_ID,
|
|
Effect::DefaultFlags,
|
|
hit_effect_resource_id,
|
|
effect_position,
|
|
0.0f,
|
|
ExecutionStateEngine::AlwaysExecuteState,
|
|
NameTable::NullObjectID,
|
|
Entity::DefaultAlignment
|
|
);
|
|
MemoryStream stream(&effect_create_message, effect_create_message.messageLength);
|
|
|
|
Effect *entity;
|
|
ReplicatorID beam_id = Connection::Hermit->GetNextReplicatorID();
|
|
entity = Cast_Object(Effect *, CreateEntity(&stream, &beam_id, false));
|
|
Check_Object(entity);
|
|
Check_Object(Map::GetInstance());
|
|
Map::GetInstance()->AddChild(entity);
|
|
entity->SyncMatrices(true);
|
|
|
|
if(entity_hit)
|
|
{
|
|
// We need the local offset from the entity for where we hit.
|
|
LinearMatrix4D entity_hit_world_to_local;
|
|
entity_hit_world_to_local = entity_hit->GetLocalToWorld();
|
|
entity_hit_world_to_local.Invert();
|
|
LinearMatrix4D target_point_local_to_world(target_point);
|
|
LinearMatrix4D target_point_local_to_entity;
|
|
target_point_local_to_entity.Multiply(target_point_local_to_world, entity_hit_world_to_local);
|
|
|
|
entity->SetFollowEntity(entity_hit);
|
|
entity->PlaceOnEntity(target_point_local_to_entity);
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
WeaponMover::CreateDamageDecal(
|
|
Entity *hit_entity,
|
|
Normal3D normal,
|
|
Point3D target_point
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(Map::GetInstance());
|
|
|
|
const Map__GameModel *model = Map::GetInstance()->GetGameModel();
|
|
Check_Object(model);
|
|
if (model->m_damageCraterResourceID != ResourceID::Null)
|
|
{
|
|
Resource damage_effect_resource(model->m_damageCraterResourceID);
|
|
Verify(damage_effect_resource.DoesResourceExist());
|
|
ClassID class_ID;
|
|
class_ID = GetClassIDFromDataListID(model->m_damageCraterResourceID);
|
|
Verify(class_ID != NullClassID);
|
|
|
|
LinearMatrix4D effect_position = LinearMatrix4D::Identity;
|
|
effect_position.AlignLocalAxisToWorldVector(normal, Y_Axis, X_Axis, Z_Axis);
|
|
effect_position.BuildTranslation(target_point);
|
|
|
|
DeathEntity::CreateMessage decal_create_message(
|
|
sizeof(DeathEntity::CreateMessage),
|
|
DefaultEventPriority,
|
|
CreateMessage::DefaultFlags,
|
|
class_ID,
|
|
DeathEntity::DefaultFlags,
|
|
model->m_damageCraterResourceID,
|
|
effect_position,
|
|
0.0f,
|
|
ExecutionStateEngine::NeverExecuteState,
|
|
NameTable::NullObjectID,
|
|
Entity::DefaultAlignment
|
|
);
|
|
MemoryStream stream(&decal_create_message, decal_create_message.messageLength);
|
|
|
|
Entity *entity;
|
|
ReplicatorID beam_id = Connection::Hermit->GetNextReplicatorID();
|
|
entity = CreateEntity(&stream, &beam_id, false);
|
|
Check_Object(entity);
|
|
Check_Object(hit_entity);
|
|
hit_entity->AddChild(entity);
|
|
entity->SyncMatrices(true);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
WeaponMover::BlowUpIfOffMap()
|
|
{
|
|
Check_Object(this);
|
|
|
|
//
|
|
//--------------------------------------------------
|
|
//Need to check to see if we are moving off the edge
|
|
//--------------------------------------------------
|
|
//
|
|
ElementRenderer::Element *element = GetElement();
|
|
Check_Object(element);
|
|
|
|
Point3D new_translation;
|
|
new_translation = element->GetNewLocalToParent();
|
|
Check_Object(Map::GetInstance());
|
|
if(Map::GetInstance()->FindZone(new_translation) == -1 || HasTriedToMoveOffMapThisFrameFlag())
|
|
{
|
|
LinearMatrix4D current_local_to_world = LinearMatrix4D::Identity;
|
|
current_local_to_world = element->GetLocalToWorld();
|
|
SetNewLocalToParent(current_local_to_world);
|
|
SentenceToDeathRow();
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
WeaponMover::CreateMissileTrail()
|
|
{
|
|
Check_Pointer(this);
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
Resource trail_resource(model->trailResource);
|
|
if(trail_resource.DoesResourceExist())
|
|
{
|
|
ClassID class_ID;
|
|
class_ID = GetClassIDFromDataListID(model->trailResource);
|
|
Verify(class_ID != NullClassID);
|
|
|
|
LinearMatrix4D initial_position = LinearMatrix4D::Identity;
|
|
initial_position.Multiply(gosFX::Effect_Against_Motion, GetElement()->GetNewLocalToParent());
|
|
|
|
Effect::CreateMessage effect_create_message(
|
|
sizeof(Effect::CreateMessage),
|
|
DefaultEventPriority,
|
|
CreateMessage::DefaultFlags,
|
|
class_ID,
|
|
Effect::DefaultFlags|Effect::LoopFlag,
|
|
model->trailResource,
|
|
initial_position,
|
|
0.0f,
|
|
ExecutionStateEngine::AlwaysExecuteState,
|
|
NameTable::NullObjectID,
|
|
Entity::DefaultAlignment
|
|
);
|
|
MemoryStream stream(&effect_create_message, effect_create_message.messageLength);
|
|
|
|
Entity *entity;
|
|
ReplicatorID trail_id = Connection::Hermit->GetNextReplicatorID();
|
|
entity = CreateEntity(&stream, &trail_id, false);
|
|
Check_Object(entity);
|
|
Check_Object(Map::GetInstance());
|
|
Map::GetInstance()->AddChild(entity);
|
|
trailEffect.Remove();
|
|
trailEffect.Add(Cast_Object(Effect *, entity));
|
|
trailEffect.GetCurrent()->SetFollowEntity(this);
|
|
trailEffect.GetCurrent()->executionState->RequestState(Effect::ExecutionStateEngine::RunningState);
|
|
entity->SyncMatrices(true);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
char
|
|
WeaponMover::GetDamageType()
|
|
{
|
|
Check_Object(this);
|
|
|
|
if((itemID >= FirstBeamID) &&
|
|
(itemID <= LastBeamID))
|
|
return BeamDamageType;
|
|
|
|
if((itemID >= FirstMissileID) &&
|
|
(itemID <= LastMissileID))
|
|
return MissileDamageType;
|
|
|
|
|
|
return ProjectileDamageType;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
WeaponMover::TestInstance() const
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|
|
|
|
|
|
void MechWarrior4::WeaponMoverSecurityCheckStop()
|
|
{
|
|
_asm
|
|
{
|
|
nop
|
|
}
|
|
}
|