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.
1111 lines
26 KiB
C++
1111 lines
26 KiB
C++
//===========================================================================//
|
|
// File: Weapon.cpp
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// 09/09/98 JSE Inital base class based off of Shadowrun/Adept //
|
|
// 09/24/98 BDB Inital Weapon subsytem class based off of Subsystem //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1998, Fasa Interactive //
|
|
// All Rights reserved worldwide //
|
|
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
|
//===========================================================================//
|
|
|
|
#include "MW4Headers.hpp"
|
|
|
|
#include "Weapon.hpp"
|
|
#include "GUIWeaponManager.hpp"
|
|
#include "HeatManager.hpp"
|
|
#include "SubsystemClassData.hpp"
|
|
#include "MWApplication.hpp"
|
|
#include "Torso.hpp"
|
|
#include "MechLabHeaders.h"
|
|
|
|
#include <Adept\Map.hpp>
|
|
#include <Adept\Effect.hpp>
|
|
#include <Adept\Site.hpp>
|
|
#include <Adept\DamageObject.hpp>
|
|
|
|
//#############################################################################
|
|
//############################### Weapon ################################
|
|
//#############################################################################
|
|
|
|
Weapon::ClassData*
|
|
Weapon::DefaultData = NULL;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Weapon::InitializeClass()
|
|
{
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
WeaponClassID,
|
|
"MechWarrior4::Weapon",
|
|
Subsystem::DefaultData,
|
|
0, NULL,
|
|
(Entity::Factory)Make,
|
|
(Entity::CreateMessage::Factory)CreateMessage::ConstructCreateMessage,
|
|
ExecutionStateEngine::DefaultData,
|
|
(Entity::GameModel::Factory)GameModel::ConstructGameModel,
|
|
NULL,
|
|
(Entity::GameModel::ReadAndVerifier)GameModel::ReadAndVerify,
|
|
(Entity::GameModel::ModelWrite)GameModel::WriteToText,
|
|
(Entity::GameModel::ModelSave)GameModel::SaveGameModel,
|
|
(Subsystem::StreamCreate) CreateStream
|
|
);
|
|
Register_Object(DefaultData);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Weapon__GameModel,
|
|
MuzzleFlashResource,
|
|
muzzleFlashResource,
|
|
ResourceID
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Weapon__GameModel,
|
|
EjectEffectResource,
|
|
ejectEffectResource,
|
|
ResourceID
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Weapon__GameModel,
|
|
Heat,
|
|
heat,
|
|
Scalar
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Weapon__GameModel,
|
|
HeatSpreadTime,
|
|
heatSpreadTime,
|
|
Scalar
|
|
);
|
|
|
|
CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Weapon__GameModel,
|
|
MaxAmmo,
|
|
maxAmmoCount,
|
|
int,
|
|
IntClassID
|
|
);
|
|
|
|
CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Weapon__GameModel,
|
|
AmmoPerShot,
|
|
ammoPerShot,
|
|
int,
|
|
IntClassID
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Weapon__GameModel,
|
|
HeatToDeal,
|
|
heatToDeal,
|
|
Scalar
|
|
);
|
|
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Weapon__GameModel,
|
|
SplashRadius,
|
|
splashRadius,
|
|
Scalar
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Weapon__GameModel,
|
|
PercentageOfDamageToDirectHit,
|
|
percentageOfDamageToDirectHit,
|
|
Scalar
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Weapon__GameModel,
|
|
MinPercentageOfDamageToSphereHit,
|
|
minPercentageOfDamageToSphereHit,
|
|
Scalar
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Weapon__GameModel,
|
|
MaxPercentageOfDamageToSphereHit,
|
|
maxPercentageOfDamageToSphereHit,
|
|
Scalar
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Weapon__GameModel,
|
|
DamageAmount,
|
|
damageAmount,
|
|
Scalar
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Weapon__GameModel,
|
|
MaxDistance,
|
|
maxDistance,
|
|
Scalar
|
|
);
|
|
|
|
// MSL 5.03 Min Distance
|
|
// DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
// Weapon__GameModel,
|
|
// MinDistance,
|
|
// minDistance,
|
|
// Scalar
|
|
// );
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Weapon__GameModel,
|
|
ReloadTime,
|
|
reloadTime,
|
|
Scalar,
|
|
);
|
|
|
|
DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Weapon__GameModel,
|
|
LightAmpFlareOut,
|
|
m_lightAmpFlareOut,
|
|
Scalar
|
|
);
|
|
|
|
CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Weapon__GameModel,
|
|
NumFire,
|
|
numFire,
|
|
int,
|
|
IntClassID
|
|
);
|
|
|
|
CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
|
|
Weapon__GameModel,
|
|
HudEffect,
|
|
m_HudEffect,
|
|
Scalar,
|
|
ScalarClassID
|
|
); // jcem
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Weapon::TerminateClass()
|
|
{
|
|
Unregister_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Weapon*
|
|
Weapon::Make(
|
|
CreateMessage *message,
|
|
ReplicatorID *base_id
|
|
)
|
|
{
|
|
Check_Object(message);
|
|
gos_PushCurrentHeap(Heap);
|
|
Weapon *new_entity =
|
|
new Weapon(DefaultData, message, base_id, NULL);
|
|
gos_PopCurrentHeap();
|
|
Check_Object(new_entity);
|
|
return new_entity;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Replicator::CreateMessage*
|
|
Weapon::SaveMakeMessage(MemoryStream *stream, ResourceFile *res_file)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(stream);
|
|
|
|
stream->AllocateBytes(sizeof(CreateMessage));
|
|
Subsystem::SaveMakeMessage(stream, res_file);
|
|
CreateMessage *message =
|
|
Cast_Pointer(CreateMessage*, stream->GetPointer());
|
|
message->messageLength = sizeof(*message);
|
|
|
|
Str_Copy(message->siteName, (char *)siteName, sizeof(message->siteName));
|
|
Str_Copy(message->ejectSiteName, (char *)ejectSiteName, sizeof(message->ejectSiteName));
|
|
|
|
message->groupIndex = groupIndexFlags;
|
|
message->ammoCount = DECRYPT(encryptedAmmoCount);
|
|
message->initialAmmoCount = initialAmmoCount;
|
|
|
|
// MSL 5.04 Rear Firing Weapons
|
|
message->m_weaponFacing = m_weaponFacing;
|
|
|
|
return message;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Weapon::Weapon(
|
|
ClassData *class_data,
|
|
CreateMessage *message,
|
|
ReplicatorID *base_id,
|
|
ElementRenderer::Element *element
|
|
):
|
|
Subsystem(class_data, message, base_id, element),
|
|
guiWeapon(NULL),
|
|
m_AI_WaitValue(0),
|
|
m_AI_LastCountValue(0),
|
|
m_AI_NonrandomWaitTimes(false)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(message);
|
|
|
|
// MSL 5.04 Rear Firing Weapons
|
|
m_weaponFacing = message->m_weaponFacing;
|
|
|
|
siteName = message->siteName;
|
|
ejectSiteName = message->ejectSiteName;
|
|
groupIndexFlags = message->groupIndex;
|
|
|
|
sitePointer = NULL;
|
|
ejectSitePointer = NULL;
|
|
enginePointer = NULL;
|
|
weaponID = -1;
|
|
|
|
CommonCreation(message);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Weapon::CommonCreation(CreateMessage *message)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
|
|
m_AI_LastTimeReadyToFire = gos_GetElapsedTime();
|
|
encryptedAmmoCount = ENCRYPT(message->ammoCount);
|
|
initialAmmoCount = message->initialAmmoCount;
|
|
vehicleInterface = NULL;
|
|
m_PlayedRechargeSound = false;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Weapon::Respawn(Entity::CreateMessage *message)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
|
|
Subsystem::Respawn(message);
|
|
CreateMessage *weapon_message = Cast_Pointer(CreateMessage *, message);
|
|
CommonCreation(weapon_message);
|
|
if(guiWeapon.GetCurrent())
|
|
{
|
|
guiWeapon.GetCurrent()->SetStatus(GUIWeapon::ReadyStatus);
|
|
}
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Weapon::~Weapon()
|
|
{
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool Weapon::ConnectSubsystem()
|
|
{
|
|
MWObject *mw_object = GetParentVehicle();
|
|
Check_Object(mw_object);
|
|
|
|
enginePointer = NULL;
|
|
heatPointer = mw_object->m_heatManager;
|
|
|
|
sitePointer = mw_object->FindSite(siteName);
|
|
Check_Object(sitePointer);
|
|
|
|
ejectSitePointer = mw_object->FindSite(ejectSiteName);
|
|
|
|
//Must call the inherited virtual function!!!!
|
|
bool return_value = Subsystem::ConnectSubsystem();
|
|
|
|
//Only want to do this stuff if we did get connected.
|
|
if(return_value)
|
|
{
|
|
int ammo_tonnage = 0;
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
|
|
if((model->maxAmmoCount > 0) && (DECRYPT(encryptedAmmoCount) > 0))
|
|
ammo_tonnage = (DECRYPT(encryptedAmmoCount) / GetAmmoPerPack()) - 1; //subtract one because you get one free ton
|
|
|
|
mw_object->AddTonage((Scalar)ammo_tonnage);
|
|
}
|
|
|
|
return return_value;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
//
|
|
bool
|
|
Weapon::DisconnectSubsystem()
|
|
{
|
|
Check_Object(this);
|
|
|
|
MWObject *parent_vehicle;
|
|
parent_vehicle = GetParentVehicle();
|
|
Check_Object(parent_vehicle);
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
|
|
int ammo_tonnage = 0;
|
|
if((model->maxAmmoCount > 0) && (DECRYPT(encryptedAmmoCount) > 0))
|
|
ammo_tonnage = (DECRYPT(encryptedAmmoCount) / GetAmmoPerPack()) - 1;
|
|
|
|
parent_vehicle->SubtractTonage((Scalar) ammo_tonnage);
|
|
|
|
return Subsystem::DisconnectSubsystem();
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Weapon::CreateMuzzleFlash()
|
|
{
|
|
Check_Object(this);
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
|
|
if(model->muzzleFlashResource == ResourceID::Null)
|
|
return;
|
|
|
|
Resource muzzle_flash_resource(model->muzzleFlashResource);
|
|
if(muzzle_flash_resource.DoesResourceExist())
|
|
{
|
|
ClassID class_ID;
|
|
class_ID = GetClassIDFromDataListID(model->muzzleFlashResource);
|
|
Verify(class_ID != NullClassID);
|
|
|
|
LinearMatrix4D effect_position = LinearMatrix4D::Identity;
|
|
UnitVector3D unit_forward;
|
|
Check_Object(sitePointer);
|
|
LinearMatrix4D site_position = sitePointer->GetLocalToWorld();
|
|
site_position.GetLocalForwardInWorld(&unit_forward);
|
|
effect_position.AlignLocalAxisToWorldVector(unit_forward, Y_Axis, X_Axis, Z_Axis);
|
|
Point3D muzzle_translation;
|
|
muzzle_translation = sitePointer->GetLocalToWorld();
|
|
effect_position.BuildTranslation(muzzle_translation);
|
|
|
|
Effect::CreateMessage effect_create_message(
|
|
sizeof(Effect::CreateMessage),
|
|
DefaultEventPriority,
|
|
CreateMessage::DefaultFlags,
|
|
class_ID,
|
|
Effect::DefaultFlags,
|
|
model->muzzleFlashResource,
|
|
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(Map::GetInstance());
|
|
Map::GetInstance()->AddChild(entity);
|
|
Effect *effect;
|
|
effect = Cast_Object(Effect *, entity);
|
|
effect->SetFollowEntity(sitePointer);
|
|
entity->SyncMatrices(true);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Weapon::CreateEjectEffect()
|
|
{
|
|
Check_Object(this);
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
|
|
if(model->ejectEffectResource == ResourceID::Null)
|
|
return;
|
|
|
|
if(ejectSitePointer == NULL)
|
|
return;
|
|
|
|
Resource eject_effect_resource(model->ejectEffectResource);
|
|
if(eject_effect_resource.DoesResourceExist())
|
|
{
|
|
ClassID class_ID;
|
|
class_ID = GetClassIDFromDataListID(model->ejectEffectResource);
|
|
Verify(class_ID != NullClassID);
|
|
|
|
LinearMatrix4D effect_position = LinearMatrix4D::Identity;
|
|
UnitVector3D unit_forward;
|
|
Check_Object(ejectSitePointer);
|
|
LinearMatrix4D site_position = ejectSitePointer->GetLocalToWorld();
|
|
site_position.GetLocalForwardInWorld(&unit_forward);
|
|
effect_position.AlignLocalAxisToWorldVector(unit_forward, Y_Axis, X_Axis, Z_Axis);
|
|
Point3D muzzle_translation;
|
|
muzzle_translation = ejectSitePointer->GetLocalToWorld();
|
|
effect_position.BuildTranslation(muzzle_translation);
|
|
|
|
Effect::CreateMessage effect_create_message(
|
|
sizeof(Effect::CreateMessage),
|
|
DefaultEventPriority,
|
|
CreateMessage::DefaultFlags,
|
|
class_ID,
|
|
Effect::DefaultFlags,
|
|
model->ejectEffectResource,
|
|
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(Map::GetInstance());
|
|
Map::GetInstance()->AddChild(entity);
|
|
Effect *effect;
|
|
effect = Cast_Object(Effect *, entity);
|
|
effect->SetFollowEntity(ejectSitePointer);
|
|
entity->SyncMatrices(true);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Weapon::TestInstance() const
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void MechWarrior4::WeaponSecurityCheckStart()
|
|
{
|
|
_asm
|
|
{
|
|
nop
|
|
}
|
|
}
|
|
|
|
// MSL 5.04 Rear Firing Weapons
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
Weapon::CanFireForward()
|
|
{
|
|
Check_Object(this);
|
|
|
|
Torso* torso = parentAsVehicle->GetTorso();
|
|
|
|
if ((torso->eyeYaw < 15.0f * Stuff::Radians_Per_Degree) || (torso->eyeYaw > -15.0f * Stuff::Radians_Per_Degree))
|
|
{
|
|
if (m_weaponFacing != 1)
|
|
return (true);
|
|
}
|
|
|
|
return (false);
|
|
}
|
|
|
|
// MSL 5.04 Rear Firing Weapons
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
Weapon::CanFireRight()
|
|
{
|
|
Check_Object(this);
|
|
|
|
if ((parentAsVehicle != 0) &&
|
|
(parentAsVehicle->IsDestroyed() == false) &&
|
|
(sitePointer != 0) &&
|
|
(sitePointer->GetParent() != 0) &&
|
|
(sitePointer->GetParent()->damageObject != 0) &&
|
|
(sitePointer->GetParent()->damageObject->internalDamageObject != 0))
|
|
{
|
|
Torso* torso = parentAsVehicle->GetTorso();
|
|
|
|
if (torso != 0)
|
|
{
|
|
Adept::InternalDamageObject* ido = sitePointer->GetParent()->damageObject->internalDamageObject;
|
|
|
|
if ((torso->lookDirection == Torso::LookRightDirection) &&
|
|
(ido->damageZone == Adept::InternalDamageObject::RightArmZone))
|
|
{
|
|
return (true);
|
|
}
|
|
if (m_weaponFacing == 2)
|
|
{
|
|
return (true);
|
|
}
|
|
}
|
|
}
|
|
|
|
return (false);
|
|
}
|
|
// MSL 5.04 Rear Firing Weapons
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
Weapon::CanFireLeft()
|
|
{
|
|
Check_Object(this);
|
|
|
|
if ((parentAsVehicle != 0) &&
|
|
(parentAsVehicle->IsDestroyed() == false) &&
|
|
(sitePointer != 0) &&
|
|
(sitePointer->GetParent() != 0) &&
|
|
(sitePointer->GetParent()->damageObject != 0) &&
|
|
(sitePointer->GetParent()->damageObject->internalDamageObject != 0))
|
|
{
|
|
Torso* torso = parentAsVehicle->GetTorso();
|
|
|
|
if (torso != 0)
|
|
{
|
|
Adept::InternalDamageObject* ido = sitePointer->GetParent()->damageObject->internalDamageObject;
|
|
|
|
if ((torso->lookDirection == Torso::LookLeftDirection) &&
|
|
(ido->damageZone == Adept::InternalDamageObject::LeftArmZone))
|
|
{
|
|
return (true);
|
|
}
|
|
if (m_weaponFacing == 2)
|
|
{
|
|
return (true);
|
|
}
|
|
}
|
|
}
|
|
|
|
return (false);
|
|
}
|
|
// MSL 5.04 Rear Firing Weapons
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
Weapon::CanFireBackward()
|
|
{
|
|
Check_Object(this);
|
|
|
|
if (m_weaponFacing == 1)
|
|
return (true);
|
|
|
|
return (false);
|
|
}
|
|
// MSL 5.04 Rear Firing Weapons
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
Weapon::CanFireFromCurrentArm()
|
|
{
|
|
Check_Object(this);
|
|
|
|
if ((parentAsVehicle != 0) &&
|
|
(parentAsVehicle->IsDestroyed() == false))
|
|
{
|
|
Torso* torso = parentAsVehicle->GetTorso();
|
|
|
|
if (torso != 0)
|
|
{
|
|
switch (torso->lookDirection)
|
|
{
|
|
case Torso::LookBackDirection:
|
|
if (CanFireBackward() == false)
|
|
{
|
|
return (false);
|
|
}
|
|
break;
|
|
case Torso::LookLeftDirection:
|
|
if (CanFireLeft() == false)
|
|
{
|
|
return (false);
|
|
}
|
|
break;
|
|
case Torso::LookRightDirection:
|
|
if (CanFireRight() == false)
|
|
{
|
|
return (false);
|
|
}
|
|
break;
|
|
case Torso::LookForwardDirection:
|
|
if (CanFireForward() == false)
|
|
{
|
|
return (false);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (true);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Weapon::FireWeapon(Adept::Entity::CollisionQuery *query,
|
|
Stuff::Time time_locked,
|
|
const Stuff::Point3D& lockedTargetEntityPartOffset)
|
|
{
|
|
if (CanFireFromCurrentArm() == false)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ((query != 0) &&
|
|
(GetParentVehicle() != 0))
|
|
{
|
|
GetParentVehicle()->NotifyFired(*query);
|
|
}
|
|
|
|
Fire(query,time_locked, lockedTargetEntityPartOffset);
|
|
|
|
GenerateAIWaitValue();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Weapon::QuickFireWeapon (Adept::Entity *target)
|
|
{
|
|
Verify(!Application::GetInstance()->InPreCollisionPhase());
|
|
QuickFire(target);
|
|
|
|
GenerateAIWaitValue();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Stuff::Scalar
|
|
Weapon::GetAIWaitValue() const
|
|
{
|
|
return (m_AI_WaitValue);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Stuff::Time
|
|
Weapon::GetLastTimeReadyToFire() const
|
|
{
|
|
return (m_AI_LastTimeReadyToFire);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Weapon::SetCount(Stuff::Scalar count)
|
|
{
|
|
if ((count == 0) &&
|
|
(m_AI_LastCountValue != 0))
|
|
{
|
|
m_AI_LastTimeReadyToFire = gos_GetElapsedTime();
|
|
}
|
|
|
|
if (guiWeapon.GetCurrent())
|
|
{
|
|
Check_Object(guiWeapon.GetCurrent());
|
|
guiWeapon.GetCurrent()->SetCount(count);
|
|
}
|
|
|
|
m_AI_LastCountValue = count;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Weapon::ApplyHeat()
|
|
{
|
|
Check_Object(this);
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
|
|
if(heatPointer)
|
|
{
|
|
Check_Object(heatPointer);
|
|
heatPointer->AddHeat(model->heat);
|
|
heatPointer->AddHeatObject(model->heatSpreadTime, model->heat);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Stuff::Scalar
|
|
Weapon::GetTotalHeatGenerated()
|
|
{
|
|
Check_Object(this);
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
|
|
return (model->heat * 2);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
Weapon::DoesHaveAmmo()
|
|
{
|
|
Check_Object(this);
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
|
|
// MSL 5.03 Bug Fix
|
|
// -1 == Beam weapon...so should return a false unless it's a PPC
|
|
if((DECRYPT(encryptedAmmoCount) == -1) && ((model->itemID == W_ClanERPPC) || (model->itemID == W_PPC) || (model->itemID == W_ERPPC)))
|
|
return true;
|
|
|
|
if(DECRYPT(encryptedAmmoCount) >= model->ammoPerShot)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Weapon::UseAmmo()
|
|
{
|
|
Check_Object(this);
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
|
|
int ammo_count = DECRYPT(encryptedAmmoCount);
|
|
|
|
NetMissionParameters::MWNetMissionParameters *params = MWApplication::GetInstance()->GetLocalNetParams();
|
|
if(ammo_count >= 0 && !params->m_unlimitedAmmo)
|
|
{
|
|
ammo_count -= model->ammoPerShot;
|
|
|
|
if (ammo_count < model->ammoPerShot)
|
|
{
|
|
ammo_count = 0;
|
|
}
|
|
|
|
Min_Clamp(ammo_count, 0);
|
|
|
|
encryptedAmmoCount = ENCRYPT(ammo_count);
|
|
|
|
if (ammo_count == 0)
|
|
{
|
|
if (GetParentVehicle ()->vehicleInterface)
|
|
{
|
|
GetParentVehicle ()->vehicleInterface->ReactToEvent (VehicleInterface::OUT_OF_AMMO);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Weapon::SetMaxWaitValue()
|
|
{
|
|
m_AI_WaitValue = 1;
|
|
m_AI_LastTimeReadyToFire = gos_GetElapsedTime();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Weapon::DestroySubsystem()
|
|
{
|
|
Check_Object(this);
|
|
|
|
// MSL 5.02 Weapon Destroyed Betty
|
|
Check_Object(executionState);
|
|
if(GetParentVehicle()->vehicleInterface)
|
|
{
|
|
GetParentVehicle()->vehicleInterface->ReactToEvent (VehicleInterface::CRITICAL_HIT_WEAPON);
|
|
}
|
|
|
|
Subsystem::DestroySubsystem();
|
|
if(guiWeapon.GetCurrent())
|
|
{
|
|
guiWeapon.GetCurrent()->SetStatus(GUIWeapon::DestroyedStatus);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
Weapon::TakeCriticalHit()
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(executionState);
|
|
// MSL 5.02 Weapon Destroyed Betty
|
|
// if(GetParentVehicle()->vehicleInterface)
|
|
// {
|
|
// GetParentVehicle()->vehicleInterface->ReactToEvent (VehicleInterface::CRITICAL_HIT_WEAPON);
|
|
// }
|
|
return Subsystem::TakeCriticalHit();
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void MechWarrior4::WeaponSecurityCheckStop()
|
|
{
|
|
_asm
|
|
{
|
|
nop
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Weapon::CreateStream(ResourceID data_list, MemoryStream *stream)
|
|
{
|
|
Check_Pointer(stream);
|
|
|
|
stream->AllocateBytes(sizeof(Weapon__CreateMessage));
|
|
Subsystem::CreateStream(data_list, stream);
|
|
|
|
Weapon__CreateMessage *create_message = Cast_Pointer(
|
|
Weapon__CreateMessage *, stream->GetPointer());
|
|
|
|
Str_Copy(create_message->siteName, "site_", sizeof(create_message->siteName));
|
|
Str_Copy(create_message->ejectSiteName, " ", sizeof(create_message->ejectSiteName));
|
|
|
|
create_message->groupIndex = 1;
|
|
|
|
Resource model_resource;
|
|
Entity::GetGameModelResourceFromDataListID(&model_resource, data_list);
|
|
GameModel *model = Cast_Pointer(GameModel *, model_resource.GetPointer());
|
|
|
|
if((model->itemID >= FirstProjectileID) && (model->itemID <= LastProjectileID))
|
|
create_message->groupIndex = 2;
|
|
if((model->itemID >= FirstMissileID) && (model->itemID <= LastMissileID))
|
|
create_message->groupIndex = 4;
|
|
|
|
if(model->itemID == W_Flare)
|
|
create_message->groupIndex = 32;
|
|
|
|
if((model->itemID == W_NarcBeacon) || (model->itemID == W_ClanNarcBeacon))
|
|
create_message->groupIndex = 8;
|
|
|
|
if(model->maxAmmoCount > 0)
|
|
{
|
|
Verify(model->totalSlotsTaken != 0);
|
|
create_message->ammoCount = model->maxAmmoCount / (3 * model->totalSlotsTaken);
|
|
create_message->initialAmmoCount = model->maxAmmoCount / (3 * model->totalSlotsTaken);
|
|
}
|
|
else
|
|
{
|
|
create_message->ammoCount = -1;
|
|
create_message->initialAmmoCount = -1;
|
|
}
|
|
|
|
// MSL 5.04 Rear Firing Weapons
|
|
create_message->m_weaponFacing = 0;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Weapon::SetWeaponGroup(int group)
|
|
{
|
|
Check_Object(this);
|
|
|
|
switch(group)
|
|
{
|
|
case 1:
|
|
SetGroup1();
|
|
break;
|
|
case 2:
|
|
SetGroup2();
|
|
break;
|
|
case 3:
|
|
SetGroup3();
|
|
break;
|
|
case 4:
|
|
SetGroup4();
|
|
break;
|
|
case 5:
|
|
SetGroup5();
|
|
break;
|
|
case 6:
|
|
SetGroup6();
|
|
break;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Weapon::ClearWeaponGroup(int group)
|
|
{
|
|
Check_Object(this);
|
|
|
|
switch(group)
|
|
{
|
|
case 1:
|
|
ClearGroup1();
|
|
break;
|
|
case 2:
|
|
ClearGroup2();
|
|
break;
|
|
case 3:
|
|
ClearGroup3();
|
|
break;
|
|
case 4:
|
|
ClearGroup4();
|
|
break;
|
|
case 5:
|
|
ClearGroup5();
|
|
break;
|
|
case 6:
|
|
ClearGroup6();
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
Weapon::AddAmmoPack()
|
|
{
|
|
Check_Object(this);
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
|
|
if(DECRYPT(encryptedAmmoCount) < model->maxAmmoCount)
|
|
{
|
|
if(GetParentVehicle()->DoesHaveAvailableTonage(1.0f))
|
|
{
|
|
int ammo_count = DECRYPT(encryptedAmmoCount);
|
|
|
|
int added_ammo = GetAmmoPerPack();
|
|
ammo_count += added_ammo;
|
|
Max_Clamp(ammo_count, model->maxAmmoCount);
|
|
initialAmmoCount = ammo_count;
|
|
if(added_ammo > 0)
|
|
GetParentVehicle()->AddTonage(1.0f);
|
|
|
|
encryptedAmmoCount = ENCRYPT(ammo_count);
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
Weapon::RemoveAmmoPack()
|
|
{
|
|
Check_Object(this);
|
|
|
|
int ammo_count = DECRYPT(encryptedAmmoCount);
|
|
|
|
int sub_ammo = GetAmmoPerPack();
|
|
if(ammo_count > sub_ammo)
|
|
{
|
|
ammo_count -= sub_ammo;
|
|
Min_Clamp(ammo_count, sub_ammo);
|
|
initialAmmoCount = ammo_count;
|
|
|
|
encryptedAmmoCount = ENCRYPT(ammo_count);
|
|
|
|
if(sub_ammo > 0)
|
|
GetParentVehicle()->SubtractTonage(1.0f);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
Weapon::GetAmmoPacks()
|
|
{
|
|
Check_Object(this);
|
|
|
|
if(DECRYPT(encryptedAmmoCount) > 0)
|
|
return DECRYPT(encryptedAmmoCount) / GetAmmoPerPack();
|
|
|
|
return 0;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
Weapon::GetAmmoPerPack()
|
|
{
|
|
Check_Object(this);
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
Check_Object(model);
|
|
Verify(model->totalSlotsTaken != 0);
|
|
int value = model->maxAmmoCount / (3 * model->totalSlotsTaken);
|
|
|
|
Min_Clamp(value, 0);
|
|
|
|
return value;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Weapon::CreateLightAmpFlareOut()
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(GetParentVehicle());
|
|
|
|
if(GetParentVehicle()->vehicleInterface)
|
|
{
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
//Here is where we need to effect the Light Amp values
|
|
GetParentVehicle()->vehicleInterface->SetLightAmpFlareOut(model->m_lightAmpFlareOut);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Weapon::SetNonrandomWaitTimes(bool use_nonrandom)
|
|
{
|
|
m_AI_NonrandomWaitTimes = use_nonrandom;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Weapon::GenerateAIWaitValue()
|
|
{
|
|
if (m_AI_NonrandomWaitTimes == true)
|
|
{
|
|
m_AI_WaitValue = 0.5f;
|
|
}
|
|
else
|
|
{
|
|
m_AI_WaitValue = Stuff::Random::GetFraction();
|
|
}
|
|
|
|
} |