Files
firestorm/Gameleap/code/mw4/Code/MW4/Weapon.cpp
T
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2026-06-24 21:28:16 -05:00

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();
}
}