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.
1718 lines
44 KiB
C++
1718 lines
44 KiB
C++
//===========================================================================//
|
|
// File: DamageObject.cpp //
|
|
// Project: Adept Brick: DamageObject //
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// 03/08/99 DPB Created File
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc. //
|
|
// PROPRIETARY AND CONFIDENTIAL //
|
|
//===========================================================================//
|
|
|
|
#include "AdeptHeaders.hpp"
|
|
|
|
#include "DamageObject.hpp"
|
|
#include "Entity.hpp"
|
|
#include "Tool.hpp"
|
|
#include "Effect.hpp"
|
|
#include "Map.hpp"
|
|
#include "NameTable.hpp"
|
|
#include "Site.hpp"
|
|
|
|
|
|
//#############################################################################
|
|
//########################### DamageObject ###############################
|
|
//#############################################################################
|
|
extern int g_nMR;
|
|
|
|
DamageObject::ClassData*
|
|
DamageObject::DefaultData = NULL;
|
|
|
|
HGOSHEAP
|
|
Adept::g_DamageObjectHeap = NULL;
|
|
|
|
void __cdecl Adept::AdeptDamageSecurityCheckStart(void)
|
|
{
|
|
_asm
|
|
{
|
|
nop
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
DamageObject::InitializeClass()
|
|
{
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
DamageObjectClassID,
|
|
"Adept::DamageObject",
|
|
Receiver::DefaultData,
|
|
0,
|
|
NULL
|
|
);
|
|
Check_Object(DefaultData);
|
|
|
|
|
|
Verify(!g_DamageObjectHeap);
|
|
g_DamageObjectHeap = gos_CreateMemoryHeap("DamageObject");
|
|
Check_Pointer(g_DamageObjectHeap);
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
DamageObject::TerminateClass()
|
|
{
|
|
Check_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
|
|
|
|
Check_Pointer(g_DamageObjectHeap);
|
|
gos_DestroyMemoryHeap(g_DamageObjectHeap);
|
|
g_DamageObjectHeap = NULL;
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
DamageObject::DamageObject(
|
|
ClassData *class_data,
|
|
MemoryStream *stream
|
|
):
|
|
Receiver(class_data)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(stream);
|
|
|
|
//Need to stream stuff in here
|
|
*stream >> baseArmorValue;
|
|
*stream >> currentArmorValue;
|
|
*stream >> scaleSplashDamage;
|
|
*stream >> damageObjectName;
|
|
*stream >> internalDamageObjectID;
|
|
*stream >> armorZone;
|
|
*stream >> damageLevel;
|
|
*stream >> m_armorType;
|
|
*stream >> maxArmorValue;
|
|
*stream >> m_specialConnectedToZone;
|
|
|
|
armorLevel = 1.0f;
|
|
damageArrayEntry = NULL;
|
|
armorArrayEntry = NULL;
|
|
internalDamageObject = NULL;
|
|
{for(int qqq = 0; qqq < DmgModifier_Count; qqq++)
|
|
{
|
|
m_aDamageModifier[qqq * 2] = 1.0f; // real value
|
|
m_aDamageModifier[qqq * 2 + 1] = 1.0f; // backup value
|
|
}}
|
|
m_HitPointPointer = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void*
|
|
DamageObject::operator new(size_t size)
|
|
{
|
|
/*
|
|
gos_PushCurrentHeap(g_DamageObjectHeap);
|
|
|
|
void *temp = ::new(size_t);
|
|
|
|
gos_PopCurrentHeap();
|
|
|
|
return temp;
|
|
*/
|
|
return gos_Malloc(size,g_DamageObjectHeap);
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void DamageObject::Reuse()
|
|
{
|
|
Check_Object(this);
|
|
|
|
m_HitPointPointer = NULL;
|
|
|
|
currentArmorValue = baseArmorValue;
|
|
damageLevel = NoArmorDamage;
|
|
if(damageArrayEntry)
|
|
*damageArrayEntry = damageLevel;
|
|
|
|
Scalar damage_percentage;
|
|
damage_percentage = 1.0f;
|
|
armorLevel = damage_percentage;
|
|
if (armorArrayEntry)
|
|
*armorArrayEntry = damage_percentage;
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
DamageObject::ConstructDamageObjectStream(
|
|
MemoryStream *stream,
|
|
Page *page
|
|
)
|
|
{
|
|
Check_Object(stream);
|
|
Check_Object(page);
|
|
|
|
int internal_damage_zone_id;
|
|
int armor_zone;
|
|
|
|
const char *armor_zone_text = "";
|
|
page->GetEntry("ArmorZone", &armor_zone_text);
|
|
|
|
armor_zone = ArmorZoneTextToAscii(armor_zone_text);
|
|
|
|
const char *zone_name;
|
|
page->GetEntry("InternalDamageZone", &zone_name, true);
|
|
|
|
internal_damage_zone_id = InternalDamageObject::InternalZoneTextToAscii(zone_name);
|
|
|
|
const char *attached_zone_string;
|
|
int attached_to_zone = NullArmorZone;
|
|
if(page->GetEntry("SpecialAttachedToZone", &attached_zone_string))
|
|
attached_to_zone = ArmorZoneTextToAscii(attached_zone_string);
|
|
|
|
Stuff::Scalar
|
|
base_armor_value,
|
|
current_armor_value,
|
|
scale_splash_damage,
|
|
max_armor_value;
|
|
|
|
base_armor_value = 0.0f;
|
|
page->GetEntry("BaseArmorValue", &base_armor_value);
|
|
Verify(base_armor_value >= 0.0f);
|
|
|
|
max_armor_value = base_armor_value;
|
|
page->GetEntry("MaxArmorValue", &max_armor_value);
|
|
Verify(max_armor_value > 0.0f);
|
|
|
|
|
|
if (!page->GetEntry("CurrentArmorValue", ¤t_armor_value))
|
|
{
|
|
current_armor_value = base_armor_value;
|
|
}
|
|
|
|
|
|
if (!page->GetEntry("ScaleSplashDamage", &scale_splash_damage))
|
|
{
|
|
scale_splash_damage = 1.0f;
|
|
}
|
|
|
|
int damage_level = NoArmorDamage;
|
|
|
|
RegisteredClass::ClassID class_id = DefaultData->GetClassID();
|
|
|
|
MString damage_object_name = page->GetName();
|
|
|
|
int armor_type = DefaultArmorType;
|
|
|
|
*stream << class_id;
|
|
*stream << base_armor_value;
|
|
*stream << current_armor_value;
|
|
*stream << scale_splash_damage;
|
|
*stream << damage_object_name;
|
|
*stream << internal_damage_zone_id;
|
|
*stream << armor_zone;
|
|
*stream << damage_level;
|
|
*stream << armor_type;
|
|
*stream << max_armor_value;
|
|
*stream << attached_to_zone;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
DamageObject::Save(MemoryStream *stream)
|
|
{
|
|
Check_Object(this);
|
|
|
|
RegisteredClass::ClassID class_id = DefaultData->GetClassID();
|
|
|
|
*stream << class_id;
|
|
*stream << baseArmorValue;
|
|
*stream << currentArmorValue;
|
|
*stream << damageObjectName;
|
|
*stream << internalDamageObjectID;
|
|
*stream << armorZone;
|
|
*stream << damageLevel;
|
|
*stream << m_armorType;
|
|
*stream << maxArmorValue;
|
|
*stream << m_specialConnectedToZone;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
DamageObject::~DamageObject()
|
|
{
|
|
}
|
|
// from here by jcem
|
|
Stuff::Scalar DamageObject::GetDamageModifier (int nIdx) const
|
|
{
|
|
gosASSERT((0 <= nIdx) && (nIdx < DmgModifier_Count * 2));
|
|
return m_aDamageModifier[nIdx];
|
|
}
|
|
|
|
void DamageObject::SetDamageModifier (int nIdx, Stuff::Scalar newvalue)
|
|
{
|
|
gosASSERT((0 <= nIdx) && (nIdx < DmgModifier_Count * 2));
|
|
m_aDamageModifier[nIdx] = newvalue;
|
|
}
|
|
// to here by jcem
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
DamageObject::Initialize(Entity *entity)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(entity);
|
|
|
|
parentEntity = entity;
|
|
|
|
DetermineDamageLevel();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
DamageObject::DetermineDamageLevel()
|
|
{
|
|
Check_Object(this);
|
|
int damage_level = NoArmorDamage;
|
|
Scalar damage_percentage;
|
|
if (baseArmorValue == 0)
|
|
damage_percentage = 0;
|
|
else
|
|
damage_percentage = currentArmorValue / baseArmorValue;
|
|
if(damage_percentage < 0.01f)
|
|
{
|
|
if(internalDamageObject)
|
|
{
|
|
if(internalDamageObject->currentInternalDamage <= 0.0f)
|
|
{
|
|
return InternalDestroyedDamage;
|
|
}
|
|
}
|
|
damage_level = ArmorDestroyedDamage;
|
|
}
|
|
else if(damage_percentage < 0.1f)
|
|
damage_level = BadArmorDamage;
|
|
else if(damage_percentage < 0.5f)
|
|
damage_level = MediumArmorDamage;
|
|
else if(damage_percentage < 0.75f)
|
|
damage_level = PartialArmorDamage;
|
|
|
|
return damage_level;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
DamageObject::TakeDamage(Entity__TakeDamageMessage *message, Entity *entity_hit)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(parentEntity);
|
|
|
|
Scalar internal_damage_taken = 0.0f;
|
|
|
|
// from here by jcem
|
|
if (message->typeOfDamage == SplashDamageType)
|
|
message->amountOfDamage *= m_aDamageModifier[DmgModifier_Splash * 2];
|
|
else
|
|
// to here by jcem
|
|
message->amountOfDamage *= m_aDamageModifier[DmgModifier_Default * 2];
|
|
|
|
// MSL 5.05 Advance Mode
|
|
if (message->amountOfModifier)
|
|
{
|
|
message->amountOfDamage *= 0.5f;
|
|
}
|
|
|
|
if (message->amountOfDamage < 0.1f)
|
|
message->amountOfDamage = 0.1f;
|
|
|
|
|
|
parentEntity->ReactToHit(message,this);
|
|
|
|
if (entity_hit != NULL)
|
|
{
|
|
entity_hit->ApplyVisualDamage(message, armorZone);
|
|
}
|
|
|
|
if (g_nMR == 2) {
|
|
Stuff::Scalar amount_of_damage = message->amountOfDamage;
|
|
|
|
if (message->typeOfDamage == SplashDamageType)
|
|
{
|
|
amount_of_damage *= scaleSplashDamage;
|
|
}
|
|
|
|
|
|
if (GetCurrentDamageLevel() == Destroyed)
|
|
{
|
|
//internal_damage_taken = amount_of_damage;
|
|
internalDamageObject->TakeDamage(amount_of_damage/*internal_damage_taken*/, message);
|
|
}
|
|
|
|
parentEntity->ReactToDamageTaken(amount_of_damage/*damage_actually_taken*/,message->inflictingEntityID,message->weaponID,(int)message->typeOfDamage);
|
|
return;
|
|
}
|
|
|
|
// if we are the server deal the damage...
|
|
|
|
// FUTURE UPGRADES!!!!!!
|
|
// If we are an instant weapon (beam) on the server take the damage
|
|
// Anything else gets the info stuck in a damage accumulator.
|
|
// That accumulator gets sent now and again.
|
|
|
|
|
|
if (Network::GetInstance()->AmIServer())
|
|
{
|
|
Stuff::Scalar amount_of_damage = message->amountOfDamage;
|
|
|
|
//only apply this if there is armor left
|
|
// MSL 5.03 Damage vs Armor Type Modified
|
|
// MSL 5.04 Penalty reduced from .667 to .333
|
|
// MSL 5.05 Corrected Formulas and changed to 40/40 reduction/penalty
|
|
if(currentArmorValue > 0)
|
|
{
|
|
if (m_armorType == ReflectiveArmor)
|
|
{
|
|
if(message->typeOfDamage == BeamDamageType)
|
|
{
|
|
amount_of_damage = amount_of_damage - (amount_of_damage * 0.4f);
|
|
}
|
|
if(message->typeOfDamage == ProjectileDamageType)
|
|
{
|
|
amount_of_damage = amount_of_damage + (amount_of_damage * 0.4f);
|
|
}
|
|
if(message->typeOfDamage == MissileDamageType)
|
|
{
|
|
amount_of_damage = amount_of_damage + (amount_of_damage * 0.4f);
|
|
}
|
|
}
|
|
|
|
if (m_armorType == ReactiveArmor)
|
|
{
|
|
if(message->typeOfDamage == ProjectileDamageType)
|
|
{
|
|
amount_of_damage = amount_of_damage - (amount_of_damage * 0.4f);
|
|
}
|
|
if(message->typeOfDamage == MissileDamageType)
|
|
{
|
|
amount_of_damage = amount_of_damage - (amount_of_damage * 0.4f);
|
|
}
|
|
if(message->typeOfDamage == BeamDamageType)
|
|
{
|
|
amount_of_damage = amount_of_damage + (amount_of_damage * 0.4f);
|
|
}
|
|
}
|
|
|
|
if (m_armorType == SolarianArmor)
|
|
{
|
|
if(message->typeOfDamage == ProjectileDamageType)
|
|
{
|
|
amount_of_damage = amount_of_damage - (amount_of_damage * 0.75f);
|
|
}
|
|
if(message->typeOfDamage == MissileDamageType)
|
|
{
|
|
amount_of_damage = amount_of_damage - (amount_of_damage * 0.75f);
|
|
}
|
|
if(message->typeOfDamage == BeamDamageType)
|
|
{
|
|
amount_of_damage = amount_of_damage - (amount_of_damage * 0.75f);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(currentArmorValue == baseArmorValue)
|
|
{
|
|
internalDamageObject->m_firstHitTime = gos_GetElapsedTime() + 1.0f;
|
|
}
|
|
|
|
if (message->typeOfDamage == SplashDamageType)
|
|
{
|
|
amount_of_damage *= scaleSplashDamage;
|
|
}
|
|
|
|
Stuff::Scalar damage_actually_taken = amount_of_damage;
|
|
|
|
if(currentArmorValue > 0.0f)
|
|
{
|
|
currentArmorValue -= amount_of_damage;
|
|
if (m_HitPointPointer)
|
|
{
|
|
*m_HitPointPointer -= amount_of_damage;
|
|
}
|
|
if(currentArmorValue < 0.0f)
|
|
{
|
|
damage_actually_taken += currentArmorValue;
|
|
|
|
internal_damage_taken = 0.0f - currentArmorValue;
|
|
if (m_HitPointPointer)
|
|
{
|
|
*m_HitPointPointer += internal_damage_taken; // will be removed in internal damage object
|
|
}
|
|
currentArmorValue = 0.0f;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
internal_damage_taken = amount_of_damage;
|
|
}
|
|
if (internal_damage_taken > 0.0f)
|
|
{
|
|
Check_Object(internalDamageObject);
|
|
damage_actually_taken += internalDamageObject->TakeDamage(internal_damage_taken, message);
|
|
}
|
|
|
|
parentEntity->ReactToDamageTaken(damage_actually_taken,message->inflictingEntityID,message->weaponID,(int)message->typeOfDamage);
|
|
}
|
|
else
|
|
{
|
|
Stuff::Scalar amount_of_damage = message->amountOfDamage;
|
|
|
|
if (message->typeOfDamage == SplashDamageType)
|
|
{
|
|
amount_of_damage *= scaleSplashDamage;
|
|
}
|
|
|
|
|
|
if (GetCurrentDamageLevel() == Destroyed)
|
|
{
|
|
internal_damage_taken = amount_of_damage;
|
|
internalDamageObject->TakeDamage(internal_damage_taken, message);
|
|
}
|
|
}
|
|
|
|
RefrehDamageState(); // jcem
|
|
}
|
|
|
|
void DamageObject::RefrehDamageState()
|
|
{
|
|
// jcem - Recalc/Refresh current DamageLevel/damageArrayEntry/armorLevel/armorArrayEntry
|
|
// this will be called after the modification of (currentArmorValue, internalDamageObject->currentInternalDamage...)
|
|
damageLevel = DetermineDamageLevel();
|
|
if(damageArrayEntry)
|
|
{
|
|
*damageArrayEntry = damageLevel;
|
|
}
|
|
|
|
|
|
Scalar damage_percentage;
|
|
if(internalDamageObject)
|
|
damage_percentage = (currentArmorValue+internalDamageObject->currentInternalDamage) / (baseArmorValue+internalDamageObject->baseInternalDamage);
|
|
else
|
|
damage_percentage = (currentArmorValue) / (baseArmorValue);
|
|
armorLevel = damage_percentage;
|
|
if (armorArrayEntry)
|
|
*armorArrayEntry = damage_percentage;
|
|
}
|
|
|
|
void DamageObject::RepairDamage(Scalar fRepair)
|
|
{
|
|
Stuff::Scalar fValue;
|
|
|
|
if (internalDamageObject)
|
|
{
|
|
fValue = internalDamageObject->baseInternalDamage * fRepair;
|
|
internalDamageObject->currentInternalDamage += fValue;
|
|
if (internalDamageObject->baseInternalDamage < internalDamageObject->currentInternalDamage)
|
|
{
|
|
fValue = internalDamageObject->currentInternalDamage - internalDamageObject->baseInternalDamage;
|
|
internalDamageObject->currentInternalDamage = internalDamageObject->baseInternalDamage;
|
|
}
|
|
else
|
|
{
|
|
fValue = 0.0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fValue = 0.0;
|
|
}
|
|
fValue += (baseArmorValue * fRepair);
|
|
currentArmorValue += fValue;
|
|
if (baseArmorValue < currentArmorValue)
|
|
currentArmorValue = baseArmorValue;
|
|
|
|
RefrehDamageState();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
DamageObject::ArmorZoneTextToAscii(const char *armor_name)
|
|
{
|
|
if(!_stricmp(armor_name, "NullZone"))
|
|
return NullArmorZone;
|
|
else if(!_stricmp(armor_name, "LeftLeg"))
|
|
return LeftLegArmorZone;
|
|
else if(!_stricmp(armor_name, "RightLeg"))
|
|
return RightLegArmorZone;
|
|
else if(!_stricmp(armor_name, "LeftArm"))
|
|
return LeftArmArmorZone;
|
|
else if(!_stricmp(armor_name, "RightArm"))
|
|
return RightArmArmorZone;
|
|
else if(!_stricmp(armor_name, "RightTorso"))
|
|
return RightTorsoArmorZone;
|
|
else if(!_stricmp(armor_name, "LeftTorso"))
|
|
return LeftTorsoArmorZone;
|
|
else if(!_stricmp(armor_name, "CenterTorso"))
|
|
return CenterTorsoArmorZone;
|
|
else if(!_stricmp(armor_name, "CenterRearTorso"))
|
|
return CenterRearTorsoArmorZone;
|
|
else if(!_stricmp(armor_name, "Head"))
|
|
return HeadArmorZone;
|
|
else if(!_stricmp(armor_name, "Special1"))
|
|
return SpecialArmorZone1;
|
|
else if(!_stricmp(armor_name, "Special2"))
|
|
return SpecialArmorZone2;
|
|
return DefaultArmorZone;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const char *
|
|
DamageObject::ArmorZoneAsciiToText(int armor_zone)
|
|
{
|
|
switch(armor_zone)
|
|
{
|
|
case NullArmorZone:
|
|
return "Null";
|
|
case LeftLegArmorZone:
|
|
return "LeftLeg";
|
|
case RightLegArmorZone:
|
|
return "RightLeg";
|
|
case LeftArmArmorZone:
|
|
return "LeftArm";
|
|
case RightArmArmorZone:
|
|
return "RightArm";
|
|
case RightTorsoArmorZone:
|
|
return "RightTorso";
|
|
case LeftTorsoArmorZone:
|
|
return "LeftTorso";
|
|
case CenterTorsoArmorZone:
|
|
return "CenterTorso";
|
|
case CenterRearTorsoArmorZone:
|
|
return "CenterRearTorso";
|
|
case HeadArmorZone:
|
|
return "Head";
|
|
case SpecialArmorZone1:
|
|
return "Special1";
|
|
case SpecialArmorZone2:
|
|
return "Special2";
|
|
}
|
|
|
|
return "Default";
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
DamageObject::SetType(int new_type)
|
|
{
|
|
Check_Object(this);
|
|
// MSL 5.0 Armor
|
|
// Verify(new_type >= FerroFiberusArmor);
|
|
Verify(new_type >= StandardArmor);
|
|
Verify(new_type < TypeCount);
|
|
|
|
m_armorType = new_type;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
DamageObject::AppendArmor(Scalar additive_armor)
|
|
{
|
|
Check_Object(this);
|
|
|
|
baseArmorValue += additive_armor;
|
|
currentArmorValue += additive_armor;
|
|
if (m_HitPointPointer)
|
|
{
|
|
*m_HitPointPointer += additive_armor;
|
|
}
|
|
|
|
Clamp(baseArmorValue, 1.0f, maxArmorValue);
|
|
if (currentArmorValue > maxArmorValue)
|
|
{
|
|
if (m_HitPointPointer)
|
|
{
|
|
*m_HitPointPointer -= (currentArmorValue - maxArmorValue);
|
|
}
|
|
}
|
|
Clamp(currentArmorValue, 1.0f, maxArmorValue);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
DamageObject::CanRepair()
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(internalDamageObject);
|
|
|
|
bool value = false;
|
|
if((internalDamageObject->GetCurrentDamageLevel() != InternalDamageObject::Destroyed) &&
|
|
(GetCurrentDamageLevel() != NoDamage))
|
|
{
|
|
value = true;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
DamageObject::TestInstance()
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|
|
|
|
//#############################################################################
|
|
//########################### InternalDamageObject #######################
|
|
//#############################################################################
|
|
|
|
InternalDamageObject::ClassData*
|
|
InternalDamageObject::DefaultData = NULL;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
InternalDamageObject::InitializeClass()
|
|
{
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
InternalDamageObjectClassID,
|
|
"Adept::InternalDamageObject",
|
|
Receiver::DefaultData,
|
|
0,
|
|
NULL
|
|
);
|
|
Check_Object(DefaultData);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
InternalDamageObject::TerminateClass()
|
|
{
|
|
Check_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
InternalDamageObject::InternalDamageObject(
|
|
ClassData *class_data,
|
|
MemoryStream *stream
|
|
):
|
|
Receiver(class_data),
|
|
m_sites(NULL, true),
|
|
// The same sites were being returned for each call. The iterators
|
|
// are now seperated into a weapon port iterator and and eject port
|
|
// iterator. Added this change to Vengeance, too --CBT 1/10/2002
|
|
m_weaponSiteIterator (&m_sites),
|
|
m_ejectionSiteIterator (&m_sites)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(stream);
|
|
|
|
//Need to stream stuff in here
|
|
*stream >> baseInternalDamage;
|
|
*stream >> currentInternalDamage;
|
|
*stream >> parentEntityName;
|
|
*stream >> damageMode;
|
|
*stream >> damageZone;
|
|
*stream >> damagePropagationZoneID;
|
|
*stream >> m_internalType;
|
|
*stream >> m_specialConnectedTo;
|
|
MemoryStreamIO_Read(stream, &damageEffects);
|
|
|
|
// MSL 5.02 headshot
|
|
if (damageMode == HeadShotDamageMode)
|
|
{
|
|
m_headShotFlag = true;
|
|
// MSL 5.05 Damage Mode
|
|
// damageMode = DestructionDamageMode;
|
|
}
|
|
else
|
|
m_headShotFlag = false;
|
|
|
|
|
|
// MSL 5.03 Gyro Hit
|
|
if (damageMode == GyroHitDamageMode)
|
|
{
|
|
m_gyrohitFlag = true;
|
|
// MSL 5.05 Damage Mode
|
|
damageMode = DestructionDamageMode;
|
|
}
|
|
else
|
|
m_gyrohitFlag = false;
|
|
|
|
currentDamageEffectResourceID = ResourceID::Null;
|
|
damagePropagationObject = NULL;
|
|
parentEntity = NULL;
|
|
currentDamageEffect = NULL;
|
|
m_HitPointPointer = NULL;
|
|
|
|
m_firstHitTime = gos_GetElapsedTime();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void*
|
|
InternalDamageObject::operator new(size_t size)
|
|
{
|
|
/*
|
|
gos_PushCurrentHeap(g_DamageObjectHeap);
|
|
|
|
void *temp = ::new(size_t);
|
|
|
|
gos_PopCurrentHeap();
|
|
|
|
return temp;
|
|
*/
|
|
return gos_Malloc(size,g_DamageObjectHeap);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
InternalDamageObject::Reuse()
|
|
{
|
|
Check_Object(this);
|
|
|
|
m_HitPointPointer = NULL;
|
|
currentInternalDamage = baseInternalDamage;
|
|
currentDamageEffectResourceID = ResourceID::Null;
|
|
currentDamageEffect = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
InternalDamageObject::ConstructInternalDamageObjectStream(
|
|
MemoryStream *stream,
|
|
Page *page,
|
|
RegisteredClass::ClassID class_id
|
|
)
|
|
{
|
|
Check_Object(stream);
|
|
Check_Object(page);
|
|
|
|
int
|
|
damage_zone;
|
|
int
|
|
damage_prop_zone = NullZone;
|
|
|
|
const char *internal_zone = "";
|
|
page->GetEntry("DamageZone", &internal_zone, true);
|
|
|
|
damage_zone = InternalZoneTextToAscii(internal_zone);
|
|
|
|
const char *zone_name;
|
|
if(page->GetEntry("DamagePropagationZone",&zone_name))
|
|
damage_prop_zone = InternalZoneTextToAscii(zone_name);
|
|
|
|
int attached_to = NullZone;
|
|
const char *attached_to_string;
|
|
if(page->GetEntry("SpecialAttachedToZone", &attached_to_string))
|
|
attached_to = InternalZoneTextToAscii(attached_to_string);
|
|
|
|
const char *parent_name = "NullParent";
|
|
page->GetEntry("ParentEntityName", &parent_name);
|
|
MString parent_entity_name = parent_name;
|
|
|
|
int
|
|
damage_mode;
|
|
|
|
const char *mode_name = "";
|
|
page->GetEntry("DamageMode", &mode_name);
|
|
|
|
damage_mode = DamageModeTextToAscii(mode_name);
|
|
|
|
Stuff::Scalar
|
|
base_internal_damage,
|
|
current_internal_damage,
|
|
base_armor_value,
|
|
current_armor_value;
|
|
|
|
page->GetEntry("BaseInternalDamage", &base_internal_damage, true);
|
|
Verify(base_internal_damage > 0);
|
|
|
|
if (!page->GetEntry("CurrentInternalDamage", ¤t_internal_damage))
|
|
{
|
|
current_internal_damage = base_internal_damage;
|
|
}
|
|
|
|
base_armor_value = 0.0f;
|
|
page->GetEntry("BaseArmorValue", &base_armor_value);
|
|
Verify(base_armor_value >= 0.0f);
|
|
|
|
if (!page->GetEntry("CurrentArmorValue", ¤t_armor_value))
|
|
{
|
|
current_armor_value = base_armor_value;
|
|
}
|
|
|
|
//
|
|
//---------------------------------------------
|
|
//Create the array of Damage Effect ResourceIDs
|
|
//---------------------------------------------
|
|
//
|
|
DynamicArrayOf<DamageEffectObject> damage_effects;
|
|
ChainOf<Note*> *list = page->MakeNoteChain("DamageEffect");
|
|
Check_Object(list);
|
|
Page::NoteIterator notes(list);
|
|
|
|
int entry_count = notes.GetSize();
|
|
Verify(entry_count >= 0);
|
|
|
|
damage_effects.SetLength(entry_count);
|
|
|
|
Note *note;
|
|
int i;
|
|
|
|
//
|
|
// For each entry, make entry in damage effect array
|
|
//
|
|
for (
|
|
i = 0;
|
|
(note = notes.ReadAndNext()) != NULL && i < entry_count;
|
|
i++
|
|
)
|
|
{
|
|
Check_Object(note);
|
|
const char *entry_data;
|
|
note->GetEntry(&entry_data);
|
|
Check_Pointer(entry_data);
|
|
|
|
MString entry_string;
|
|
MString effect_file_name;
|
|
|
|
entry_string = entry_data;
|
|
effect_file_name = entry_string.GetNthToken(0, ",");
|
|
|
|
Check_Object(Tool::Instance);
|
|
Check_Object(ResourceManager::Instance);
|
|
Resource effect_resource;
|
|
Tool::Instance->ConstructDataList(&effect_resource, effect_file_name);
|
|
Check_Object(&effect_resource);
|
|
Verify(effect_resource.DoesResourceExist());
|
|
MString percent_armor_string;
|
|
Scalar percent_armor;
|
|
|
|
percent_armor_string = entry_string.GetNthToken(1, ",");
|
|
sscanf(
|
|
percent_armor_string,
|
|
"%f ",
|
|
&percent_armor
|
|
);
|
|
|
|
damage_effects[i].resourceID = effect_resource.GetResourceID();
|
|
damage_effects[i].armorPercent = percent_armor;
|
|
}
|
|
Check_Object(list);
|
|
delete list;
|
|
|
|
int internal_type = DefaultInternalType;
|
|
*stream << class_id;
|
|
*stream << base_internal_damage;
|
|
*stream << current_internal_damage;
|
|
*stream << parent_entity_name;
|
|
*stream << damage_mode;
|
|
*stream << damage_zone;
|
|
*stream << damage_prop_zone;
|
|
*stream << internal_type;
|
|
*stream << attached_to;
|
|
MemoryStreamIO_Write(stream, &damage_effects);
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
InternalDamageObject::Save(MemoryStream *stream, RegisteredClass::ClassID class_id)
|
|
{
|
|
Check_Object(this);
|
|
|
|
*stream << class_id;
|
|
*stream << baseInternalDamage;
|
|
*stream << currentInternalDamage;
|
|
*stream << parentEntityName;
|
|
*stream << damageMode;
|
|
*stream << damageZone;
|
|
*stream << damagePropagationZoneID;
|
|
*stream << m_internalType;
|
|
*stream << m_specialConnectedTo;
|
|
MemoryStreamIO_Write(stream, &damageEffects);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
InternalDamageObject::~InternalDamageObject()
|
|
{
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
InternalDamageObject::Initialize(Entity *entity)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(entity);
|
|
|
|
parentEntity = entity;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Scalar
|
|
InternalDamageObject::TakeDamage(Scalar damage_taken, Entity__TakeDamageMessage *message)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(parentEntity);
|
|
Stuff::Scalar damage_already_distributed = 0.0f;
|
|
|
|
Scalar rv = 0;
|
|
|
|
if (g_nMR == 2) {
|
|
PlayDamageEffects(message);
|
|
//parentEntity->ReactToInternalDamage(damageMode);
|
|
return rv;
|
|
}
|
|
|
|
if (Network::GetInstance()->AmIServer())
|
|
{
|
|
if (currentInternalDamage > 0.0f)
|
|
{
|
|
rv = damage_taken;
|
|
|
|
if((damageMode == DestructionDamageMode) &&
|
|
(damageZone > NullZone) &&
|
|
(damageZone < VehicleHullZone) &&
|
|
(gos_GetElapsedTime() < m_firstHitTime) &&
|
|
(message->typeOfDamage != HighExplosiveDamageType))
|
|
{
|
|
if (m_HitPointPointer)
|
|
{
|
|
*m_HitPointPointer -= damage_taken;
|
|
}
|
|
currentInternalDamage -= damage_taken;
|
|
if (currentInternalDamage < 0.9f)
|
|
{
|
|
if (m_HitPointPointer)
|
|
{
|
|
*m_HitPointPointer += (0.9f - currentInternalDamage);
|
|
}
|
|
}
|
|
Min_Clamp(currentInternalDamage, 0.09f);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If we've already used up some of the damage here, we don't want to propagate it
|
|
// below. Note that since we check for currentInternalDamage being <= 0 below we know that
|
|
// we only get there if damage_take > currentInternalDamage so it is safe to assume
|
|
// currentInternalDamage is the amount of damage already taken.
|
|
//
|
|
damage_already_distributed = currentInternalDamage;
|
|
if (m_HitPointPointer)
|
|
{
|
|
*m_HitPointPointer -= damage_taken;
|
|
}
|
|
currentInternalDamage -= damage_taken;
|
|
}
|
|
|
|
PlayDamageEffects(message);
|
|
// MSL 5.02 Head Shot
|
|
// MSL 5.03 Gyro Hit
|
|
if (m_headShotFlag == true)
|
|
parentEntity->ReactToInternalDamage(HeadShotDamageMode);
|
|
else
|
|
if (m_gyrohitFlag == true)
|
|
parentEntity->ReactToInternalDamage(GyroHitDamageMode);
|
|
else
|
|
parentEntity->ReactToInternalDamage(damageMode);
|
|
InflictCriticalHit();
|
|
}
|
|
if(currentInternalDamage <= 0.0f)
|
|
{
|
|
if(damagePropagationObject)
|
|
{
|
|
Check_Object(damagePropagationObject);
|
|
Scalar prop_amount = 0.0f;
|
|
// MSL 5.05 Used to determine percentage of damage propagated.
|
|
switch(m_internalType)
|
|
{
|
|
case StandardInternal:
|
|
prop_amount = 0.85f;
|
|
break;
|
|
case EndoSteelInternal:
|
|
prop_amount = 1.0f;
|
|
break;
|
|
}
|
|
|
|
// MSL 5.05 If Advancemode then modify propagation damage
|
|
if (message->amountOfModifier)
|
|
{
|
|
prop_amount *= 0.5f;
|
|
}
|
|
//
|
|
// If two items point to each other they can cause recursion that we don't want
|
|
// when both become destroyed. The legs pointing at each other causes this
|
|
//
|
|
// This solution won't work if they ever put in second order propagation, ie...
|
|
// lleg -> rleg (if destroyed) -> centertorso, or lleg->ltorso->ctorso
|
|
// The first case isn't supported by the code, and the second won't work once the
|
|
// ltorso is destroyed. The damage won't get to the center torso
|
|
|
|
if (damagePropagationObject->currentInternalDamage > 0.0f)
|
|
{
|
|
rv += damagePropagationObject->TakeDamage((Scalar)((damage_taken - damage_already_distributed) * prop_amount), message);
|
|
}
|
|
}
|
|
if(!parentEntity->IsDestroyed())
|
|
parentEntity->ReactToDestruction(damageMode, message->typeOfDamage);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// create the effects
|
|
PlayDamageEffects(message);
|
|
// MSL 5.02 Head Shot
|
|
// MSL 5.03 Gyro Hit
|
|
if (m_headShotFlag == true)
|
|
parentEntity->ReactToInternalDamage(HeadShotDamageMode);
|
|
else
|
|
if (m_gyrohitFlag == true)
|
|
parentEntity->ReactToInternalDamage(GyroHitDamageMode);
|
|
else
|
|
parentEntity->ReactToInternalDamage(damageMode);
|
|
}
|
|
|
|
return (rv);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
InternalDamageObject::PlayDamageEffects(Entity__TakeDamageMessage *message)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
|
|
if (message->quickDamage) // boardgame mode hit
|
|
return;
|
|
|
|
ResourceID want_to_play_effect;
|
|
want_to_play_effect = GetDamageEffectID();
|
|
if((currentDamageEffectResourceID == want_to_play_effect) ||
|
|
(want_to_play_effect == ResourceID::Null))
|
|
{
|
|
return;
|
|
}
|
|
|
|
currentDamageEffectResourceID = want_to_play_effect;
|
|
|
|
ClassID class_ID;
|
|
class_ID = Entity::GetClassIDFromDataListID(currentDamageEffectResourceID);
|
|
Verify(class_ID != NullClassID);
|
|
|
|
Effect::CreateMessage effect_create_message(
|
|
sizeof(Effect::CreateMessage),
|
|
DefaultEventPriority,
|
|
Entity::CreateMessage::DefaultFlags,
|
|
class_ID,
|
|
Effect::DefaultFlags,
|
|
currentDamageEffectResourceID,
|
|
LinearMatrix4D::Identity,
|
|
0.0f,
|
|
Entity::ExecutionStateEngine::AlwaysExecuteState,
|
|
NameTable::NullObjectID,
|
|
Entity::DefaultAlignment
|
|
);
|
|
MemoryStream stream(&effect_create_message, effect_create_message.messageLength);
|
|
|
|
Entity *entity;
|
|
ReplicatorID effect_id = Connection::Hermit->GetNextReplicatorID();
|
|
entity = Entity::CreateEntity(&stream, &effect_id, false);
|
|
Check_Object(entity);
|
|
currentDamageEffect =
|
|
Cast_Object(Effect *, entity);
|
|
Check_Object(Map::GetInstance());
|
|
Map::GetInstance()->AddChild(entity);
|
|
LinearMatrix4D effect_position = LinearMatrix4D::Identity;
|
|
// effect_position.AlignAxis(message->normal, Y_Axis, X_Axis, Z_Axis);
|
|
effect_position.BuildTranslation(message->hitOffset);
|
|
LinearMatrix4D effect_offset = LinearMatrix4D::Identity;
|
|
Point3D effect_offset_position;
|
|
Check_Object(parentEntity);
|
|
effect_offset_position.MultiplyByInverse(message->hitOffset, parentEntity->GetLocalToWorld());
|
|
effect_offset.BuildTranslation(effect_offset_position);
|
|
currentDamageEffect->SetFollowEntity(parentEntity);
|
|
currentDamageEffect->effectOffset = effect_offset;
|
|
entity->SetNewLocalToParent(effect_position);
|
|
entity->SyncMatrices(true);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
ResourceID
|
|
InternalDamageObject::GetDamageEffectID()
|
|
{
|
|
Check_Object(this);
|
|
Scalar closest_armor = 1.0f;
|
|
ResourceID return_id;
|
|
|
|
return_id = ResourceID::Null;
|
|
|
|
for (int i = 0; i < damageEffects.GetLength(); i++)
|
|
{
|
|
Scalar damage_num = damageEffects[i].armorPercent;
|
|
if ((damage_num >= (currentInternalDamage / baseInternalDamage))
|
|
&& (damage_num <= closest_armor))
|
|
{
|
|
closest_armor = damage_num;
|
|
return_id = damageEffects[i].resourceID;
|
|
}
|
|
}
|
|
return return_id;
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
int InternalDamageObject::GetCurrentDamageLevel()
|
|
{
|
|
if (currentInternalDamage == baseInternalDamage)
|
|
{
|
|
return NoDamage;
|
|
}
|
|
if (currentInternalDamage <= 0.0f)
|
|
{
|
|
return Destroyed;
|
|
}
|
|
else
|
|
return Damaged;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void InternalDamageObject::SetCurrentDamageLevel(int level)
|
|
{
|
|
|
|
if (level != GetCurrentDamageLevel())
|
|
{
|
|
switch(level)
|
|
{
|
|
case NoDamage:
|
|
if (m_HitPointPointer)
|
|
{
|
|
*m_HitPointPointer += (baseInternalDamage - currentInternalDamage);
|
|
}
|
|
currentInternalDamage = baseInternalDamage;
|
|
break;
|
|
|
|
case Damaged:
|
|
if (m_HitPointPointer)
|
|
{
|
|
*m_HitPointPointer += ((baseInternalDamage*0.5f) - currentInternalDamage);
|
|
}
|
|
currentInternalDamage = baseInternalDamage*0.5f;
|
|
break;
|
|
|
|
case Destroyed:
|
|
if (m_HitPointPointer)
|
|
{
|
|
*m_HitPointPointer += (0-currentInternalDamage);
|
|
}
|
|
currentInternalDamage = 0.0f;
|
|
//parentEntity->ReactToDestruction(InternalDamageObject::DestructionDamageMode, 0);
|
|
parentEntity->ReactToDestruction(damageMode, 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
// The same sites were being returned for each call. The iterators
|
|
// are now seperated into a weapon port iterator and and eject port
|
|
// iterator. Added this change to Vengeance, too --CBT 1/10/2002
|
|
Site*
|
|
InternalDamageObject::GetNextWeaponSite()
|
|
{
|
|
Check_Object(this);
|
|
|
|
Site *site = m_weaponSiteIterator.GetCurrent();
|
|
if(!site)
|
|
{
|
|
m_weaponSiteIterator.First();
|
|
site = m_weaponSiteIterator.GetCurrent();
|
|
}
|
|
else
|
|
{ //you have previously retuned a site, begin on the next
|
|
m_weaponSiteIterator.Next();
|
|
if(!m_weaponSiteIterator.GetCurrent())
|
|
m_weaponSiteIterator.First();
|
|
site = m_weaponSiteIterator.GetCurrent();
|
|
}
|
|
|
|
bool found = false;
|
|
int num = 0;
|
|
int total = m_sites.GetSize();
|
|
|
|
while((site) && (!found) && (num < total))
|
|
{
|
|
Check_Object(site);
|
|
char *name_lower = _strlwr((char *)site->GetName());
|
|
// CBT 1/24/02 - the mispelled string "missle" is included due to historical reasons
|
|
if((strstr(name_lower, "gun")) || (strstr(name_lower, "missile"))
|
|
|| (strstr(name_lower, "missle")) || (strstr(name_lower, "torsoport")))
|
|
found = true;
|
|
else
|
|
{
|
|
m_weaponSiteIterator.Next();
|
|
if(!m_weaponSiteIterator.GetCurrent())
|
|
m_weaponSiteIterator.First();
|
|
site = m_weaponSiteIterator.GetCurrent();
|
|
num ++;
|
|
}
|
|
}
|
|
|
|
if(found)
|
|
return site;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Site*
|
|
InternalDamageObject::GetNextEjectSite()
|
|
{
|
|
Site *site = m_ejectionSiteIterator.GetCurrent();
|
|
if(!site)
|
|
{
|
|
m_ejectionSiteIterator.First();
|
|
site = m_ejectionSiteIterator.GetCurrent();
|
|
}
|
|
else
|
|
{ //you have previously returned a site, begin on the next
|
|
m_ejectionSiteIterator.Next();
|
|
if(!m_ejectionSiteIterator.GetCurrent())
|
|
m_ejectionSiteIterator.First();
|
|
site = m_ejectionSiteIterator.GetCurrent();
|
|
}
|
|
|
|
bool found = false;
|
|
int num = 0;
|
|
int total = m_sites.GetSize();
|
|
|
|
while((site) && (!found) && (num < total))
|
|
{
|
|
Check_Object(site);
|
|
char *name_lower = _strlwr((char *)site->GetName());
|
|
if(strstr(name_lower, "shellport"))
|
|
found = true;
|
|
else
|
|
{
|
|
m_ejectionSiteIterator.Next();
|
|
if(!m_ejectionSiteIterator.GetCurrent())
|
|
m_ejectionSiteIterator.First();
|
|
site = m_ejectionSiteIterator.GetCurrent();
|
|
num ++;
|
|
}
|
|
}
|
|
|
|
if(found)
|
|
return site;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void InternalDamageObject::SilentDestruction()
|
|
{
|
|
if (m_HitPointPointer)
|
|
{
|
|
*m_HitPointPointer += (0-currentInternalDamage);
|
|
}
|
|
currentInternalDamage = 0.0f;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
int DamageObject::GetCurrentDamageLevel()
|
|
{
|
|
if (currentArmorValue == baseArmorValue)
|
|
{
|
|
return NoDamage;
|
|
}
|
|
if (currentArmorValue <= 0.0f)
|
|
{
|
|
return Destroyed;
|
|
}
|
|
else
|
|
return Damaged;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void DamageObject::SetCurrentDamageLevel(int level)
|
|
{
|
|
if (level != GetCurrentDamageLevel())
|
|
{
|
|
switch(level)
|
|
{
|
|
case NoDamage:
|
|
if (m_HitPointPointer)
|
|
{
|
|
*m_HitPointPointer += (baseArmorValue - currentArmorValue);
|
|
}
|
|
currentArmorValue = baseArmorValue;
|
|
break;
|
|
|
|
case Damaged:
|
|
if (m_HitPointPointer)
|
|
{
|
|
*m_HitPointPointer += ((baseArmorValue*0.5f) - currentArmorValue);
|
|
}
|
|
currentArmorValue = baseArmorValue*0.5f;
|
|
break;
|
|
|
|
case Destroyed:
|
|
if (m_HitPointPointer)
|
|
{
|
|
*m_HitPointPointer += (0 - currentArmorValue);
|
|
}
|
|
currentArmorValue = 0.0f;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
damageLevel = DetermineDamageLevel();
|
|
if(damageArrayEntry)
|
|
{
|
|
*damageArrayEntry = damageLevel;
|
|
}
|
|
|
|
Scalar damage_percentage;
|
|
if(internalDamageObject)
|
|
damage_percentage = (currentArmorValue+internalDamageObject->currentInternalDamage) / (baseArmorValue+internalDamageObject->baseInternalDamage);
|
|
else
|
|
damage_percentage = (currentArmorValue) / (baseArmorValue);
|
|
armorLevel = damage_percentage;
|
|
if (armorArrayEntry)
|
|
*armorArrayEntry = damage_percentage;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
// Fix Bug #3100
|
|
// Damage Object are now refreshed when a mech sustains internal damage
|
|
|
|
void DamageObject::RefreshCurrentDamageLevel()
|
|
{
|
|
damageLevel = DetermineDamageLevel();
|
|
if(damageArrayEntry)
|
|
{
|
|
*damageArrayEntry = damageLevel;
|
|
}
|
|
|
|
Scalar damage_percentage;
|
|
if(internalDamageObject)
|
|
damage_percentage = (currentArmorValue+internalDamageObject->currentInternalDamage) / (baseArmorValue+internalDamageObject->baseInternalDamage);
|
|
else
|
|
damage_percentage = (currentArmorValue) / (baseArmorValue);
|
|
armorLevel = damage_percentage;
|
|
if (armorArrayEntry)
|
|
*armorArrayEntry = damage_percentage;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void DamageObject::SilentDestruction()
|
|
{
|
|
if (m_HitPointPointer)
|
|
{
|
|
*m_HitPointPointer += (0 - currentArmorValue);
|
|
}
|
|
currentArmorValue = 0.0f;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
Scalar DamageObject::GetHighResDamageLevel()
|
|
{
|
|
Scalar damage_level = currentArmorValue/baseArmorValue;
|
|
Clamp(damage_level, 0.0f, 1.0f);
|
|
return damage_level;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void DamageObject::SetHighResDamageLevel(Scalar damage_percentage)
|
|
{
|
|
if (m_HitPointPointer)
|
|
{
|
|
*m_HitPointPointer += ((baseArmorValue * damage_percentage) - currentArmorValue);
|
|
}
|
|
|
|
currentArmorValue = baseArmorValue * damage_percentage;
|
|
|
|
damageLevel = DetermineDamageLevel();
|
|
if(damageArrayEntry)
|
|
{
|
|
*damageArrayEntry = damageLevel;
|
|
}
|
|
|
|
Scalar fred;
|
|
if(internalDamageObject)
|
|
fred = (currentArmorValue+internalDamageObject->currentInternalDamage) / (baseArmorValue+internalDamageObject->baseInternalDamage);
|
|
else
|
|
fred = (currentArmorValue) / (baseArmorValue);
|
|
armorLevel = fred;
|
|
if (armorArrayEntry)
|
|
*armorArrayEntry = fred;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
Scalar InternalDamageObject::GetHighResDamageLevel()
|
|
{
|
|
Scalar damage_level = currentInternalDamage/baseInternalDamage;
|
|
Clamp(damage_level, 0.0f, 1.0f);
|
|
return damage_level;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void InternalDamageObject::SetHighResDamageLevel(Scalar damage_percentage)
|
|
{
|
|
|
|
if (GetCurrentDamageLevel() != Destroyed)
|
|
{
|
|
if (m_HitPointPointer)
|
|
{
|
|
*m_HitPointPointer += ((baseInternalDamage*damage_percentage)-currentInternalDamage);
|
|
}
|
|
currentInternalDamage = baseInternalDamage*damage_percentage;
|
|
|
|
if (damage_percentage == 0.0f)
|
|
{
|
|
if (m_HitPointPointer)
|
|
{
|
|
*m_HitPointPointer += (0-currentInternalDamage);
|
|
}
|
|
currentInternalDamage = 0.0f;
|
|
//parentEntity->ReactToDestruction(InternalDamageObject::DestructionDamageMode, 0);
|
|
parentEntity->ReactToDestruction(damageMode, 0);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
InternalDamageObject::DamageModeTextToAscii(const char *mode_name)
|
|
{
|
|
|
|
if(!_stricmp(mode_name, "GimpLeftDamageMode"))
|
|
return GimpLeftDamageMode;
|
|
else if(!_stricmp(mode_name, "GimpRightDamageMode"))
|
|
return GimpRightDamageMode;
|
|
else if(!_stricmp(mode_name, "DestructionDamageMode"))
|
|
return DestructionDamageMode;
|
|
// MSL 5.02 headshot
|
|
else if (!_stricmp(mode_name, "HeadShotDamageMode"))
|
|
return HeadShotDamageMode;
|
|
// MSL 5.03 Gyro Hit
|
|
else if (!_stricmp(mode_name, "GyroHitDamageMode"))
|
|
return GyroHitDamageMode;
|
|
else if(!_stricmp(mode_name, "DetachableDamageMode"))
|
|
return DetachableDamageMode;
|
|
// MSL 5.02 Engine
|
|
else if(!_stricmp(mode_name, "EngineDamageMode"))
|
|
return EngineDamageMode;
|
|
// MSL 5.05 Torso
|
|
else if(!_stricmp(mode_name, "TorsoLeftDamageMode"))
|
|
return TorsoLeftDamageMode;
|
|
else if(!_stricmp(mode_name, "TorsoRightDamageMode"))
|
|
return TorsoRightDamageMode;
|
|
else if(!_stricmp(mode_name, "ArmLeftDamageMode"))
|
|
return ArmLeftDamageMode;
|
|
else if(!_stricmp(mode_name, "ArmRightDamageMode"))
|
|
return ArmRightDamageMode;
|
|
|
|
return GeneralDamageMode;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const char *
|
|
InternalDamageObject::DamageModeAsciiToText(int damage_mode)
|
|
{
|
|
switch(damage_mode)
|
|
{
|
|
case GimpLeftDamageMode:
|
|
return "GimpLeftDamageMode";
|
|
case GimpRightDamageMode:
|
|
return "GimpRightDamageMode";
|
|
case DestructionDamageMode:
|
|
return "DestructionDamageMode";
|
|
// MSL 5.02 headshot
|
|
case HeadShotDamageMode:
|
|
return "HeadShotDamageMode";
|
|
// MSL 5.03 Gyro Hit
|
|
case GyroHitDamageMode:
|
|
return "GyroHitDamageMode";
|
|
case DetachableDamageMode:
|
|
return "DetachableDamageMode";
|
|
case EngineDamageMode:
|
|
return "EngineDamageMode";
|
|
// MSL 5.05 Torso
|
|
case TorsoLeftDamageMode:
|
|
return "TorsoLeftDamageMode";
|
|
case TorsoRightDamageMode:
|
|
return "TorsoRightDamageMode";
|
|
case ArmLeftDamageMode:
|
|
return "ArmLeftDamageMode";
|
|
case ArmRightDamageMode:
|
|
return "ArmRightDamageMode";
|
|
}
|
|
return "GeneralDamageMode";
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
InternalDamageObject::InternalZoneTextToAscii(const char *mode_name)
|
|
{
|
|
if(!_stricmp(mode_name, "NullZone"))
|
|
return NullZone;
|
|
else if(!_stricmp(mode_name, "LeftLeg"))
|
|
return LeftLegZone;
|
|
else if(!_stricmp(mode_name, "RightLeg"))
|
|
return RightLegZone;
|
|
else if(!_stricmp(mode_name, "LeftArm"))
|
|
return LeftArmZone;
|
|
else if(!_stricmp(mode_name, "RightArm"))
|
|
return RightArmZone;
|
|
else if(!_stricmp(mode_name, "RightTorso"))
|
|
return RightTorsoZone;
|
|
else if(!_stricmp(mode_name, "LeftTorso"))
|
|
return LeftTorsoZone;
|
|
else if(!_stricmp(mode_name, "CenterTorso"))
|
|
return CenterTorsoZone;
|
|
else if(!_stricmp(mode_name, "Head"))
|
|
return HeadZone;
|
|
else if(!_stricmp(mode_name, "Special1"))
|
|
return SpecialZone1;
|
|
else if(!_stricmp(mode_name, "Special2"))
|
|
return SpecialZone2;
|
|
else if(!_stricmp(mode_name, "VehicleHull"))
|
|
return VehicleHullZone;
|
|
else if(!_stricmp(mode_name, "VehicleWeapon"))
|
|
return VehicleWeaponZone;
|
|
else if(!_stricmp(mode_name, "VehicleSpecial"))
|
|
return VehicleSpecialZone;
|
|
|
|
return DefaultZone;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const char *
|
|
InternalDamageObject::InternalZoneAsciiToText(int internal_zone)
|
|
{
|
|
switch(internal_zone)
|
|
{
|
|
case NullZone:
|
|
return "Null";
|
|
case LeftLegZone:
|
|
return "LeftLeg";
|
|
case RightLegZone:
|
|
return "RightLeg";
|
|
case LeftArmZone:
|
|
return "LeftArm";
|
|
case RightArmZone:
|
|
return "RightArm";
|
|
case RightTorsoZone:
|
|
return "RightTorso";
|
|
case LeftTorsoZone:
|
|
return "LeftTorso";
|
|
case CenterTorsoZone:
|
|
return "CenterTorso";
|
|
case HeadZone:
|
|
return "Head";
|
|
case SpecialZone1:
|
|
return "Special1";
|
|
case SpecialZone2:
|
|
return "Special2";
|
|
case VehicleHullZone:
|
|
return "VehicleHull";
|
|
case VehicleWeaponZone:
|
|
return "VehicleWeapon";
|
|
case VehicleSpecialZone:
|
|
return "VehicleSpecial";
|
|
}
|
|
|
|
return "Default";
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
InternalDamageObject::SetType(int new_type)
|
|
{
|
|
Check_Object(this);
|
|
Verify(new_type >= StandardInternal);
|
|
Verify(new_type < TypeCount);
|
|
|
|
m_internalType = new_type;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
InternalDamageObject::TestInstance()
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|
|
|
|
void __cdecl Adept::AdeptDamageSecurityCheckStop(void)
|
|
{
|
|
_asm
|
|
{
|
|
nop
|
|
}
|
|
}
|