Files
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

1089 lines
26 KiB
C++

#include "MW4Headers.hpp"
#include "AI_Weapons.hpp"
#include "BeamWeapon.hpp"
#include "ProjectileWeapon.hpp"
#include "MWObject.hpp"
#include "MWDamageObject.hpp"
#include <Adept\CollisionGrid.hpp>
#include "aiutils.hpp"
#include "bombastweapon.hpp"
#include <Adept\Site.hpp>
#include "SubsystemClassData.hpp"
#include <Adept\Map.hpp>
#include "Sensor.hpp"
#include <Adept\CollisionVolume.hpp>
using namespace MW4AI;
const Stuff::Scalar friendly_fire_stretch_distance = 10.0f;
inline bool WeaponReadyToFire(MechWarrior4::Weapon& weapon, Stuff::Time min_delay, Stuff::Time max_delay)
{
Verify(min_delay >= 0);
Verify(max_delay >= min_delay);
Stuff::Time delay = ((max_delay - min_delay) * weapon.GetAIWaitValue()) + min_delay;
return (gos_GetElapsedTime() >= weapon.GetLastTimeReadyToFire() + delay);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MW4AI::SetWeaponsToMaxWaitValue(MechWarrior4::MWObject& object)
{
Stuff::ChainIteratorOf<MechWarrior4::Weapon*> i(&(object.weaponChain));
MechWarrior4::Weapon* weapon = 0;
while ((weapon = i.ReadAndNext()) != 0)
{
weapon->SetMaxWaitValue();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// GetMaxWeaponDistance(): gets the maximum distance of a weapon
//
Stuff::Scalar MW4AI::GetMaxWeaponDistance(MechWarrior4::Weapon& weapon)
{
if (weapon.IsDerivedFrom(MechWarrior4::BeamWeapon::DefaultData) == true)
{
MechWarrior4::BeamWeapon* beam = Cast_Object(MechWarrior4::BeamWeapon*,&weapon);
return (beam->GetGameModel()->maxDistance);
}
if (weapon.IsDerivedFrom(MechWarrior4::ProjectileWeapon::DefaultData) == true)
{
MechWarrior4::ProjectileWeapon* projectile = Cast_Object(MechWarrior4::ProjectileWeapon*,&weapon);
return (projectile->GetGameModel()->maxDistance);
}
Verify(!"Cannot get max range: weapon type not found.");
return (0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// GetMaxWeaponDistance(): gets the maximum distance of any of an object's weapons
//
Stuff::Scalar MW4AI::GetMaxWeaponDistance(MechWarrior4::MWObject& object)
{
Stuff::ChainIteratorOf<MechWarrior4::Weapon*> i(&(object.weaponChain));
MechWarrior4::Weapon* weapon = 0;
Stuff::Scalar max = 0;
while ((weapon = i.ReadAndNext()) != 0)
{
Check_Object(weapon);
Stuff::Scalar this_range = GetMaxWeaponDistance(*weapon);
if (this_range > max)
{
max = this_range;
}
}
return (max);
}
// MSL 5.03 Min Distance (Disabled)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// GetMaxWeaponDistance(): gets the maximum distance of a weapon
//
//Stuff::Scalar MW4AI::GetMinWeaponDistance(MechWarrior4::Weapon& weapon)
//{
// if (weapon.IsDerivedFrom(MechWarrior4::BeamWeapon::DefaultData) == true)
// {
// MechWarrior4::BeamWeapon* beam = Cast_Object(MechWarrior4::BeamWeapon*,&weapon);
// return (beam->GetGameModel()->minDistance);
// }
// if (weapon.IsDerivedFrom(MechWarrior4::ProjectileWeapon::DefaultData) == true)
// {
// MechWarrior4::ProjectileWeapon* projectile = Cast_Object(MechWarrior4::ProjectileWeapon*,&weapon);
// return (projectile->GetGameModel()->minDistance);
// }
// Verify(!"Cannot get min range: weapon type not found.");
// return (0);
//}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// GetMaxWeaponDistance(): gets the maximum distance of any of an object's weapons
//
Stuff::Scalar MW4AI::GetMinWeaponDistance(MechWarrior4::MWObject& object)
{
Stuff::ChainIteratorOf<MechWarrior4::Weapon*> i(&(object.weaponChain));
MechWarrior4::Weapon* weapon = 0;
weapon = i.ReadAndNext();
if (weapon == 0)
{
return (0);
}
Check_Object(weapon);
Stuff::Scalar min = GetMaxWeaponDistance(*weapon);
while ((weapon = i.ReadAndNext()) != 0)
{
Check_Object(weapon);
Stuff::Scalar this_range = GetMaxWeaponDistance(*weapon);
if (this_range < min)
{
min = this_range;
}
}
return (min);
}
unsigned int MW4AI::NumWeaponsReady(MechWarrior4::MWObject& vehicle,
Stuff::Time min_delay,
Stuff::Time max_delay)
{
Stuff::ChainIteratorOf<MechWarrior4::Weapon*> i(&(vehicle.weaponChain));
MechWarrior4::Weapon* weapon = 0;
unsigned int rv = 0;
while ((weapon = i.ReadAndNext()) != 0)
{
Check_Object(weapon);
if (WeaponReadyToFire(*weapon,min_delay,max_delay) == true)
{
++rv;
}
}
return (rv);
}
unsigned int MW4AI::NumWeapons(MechWarrior4::MWObject& vehicle)
{
Stuff::ChainIteratorOf<MechWarrior4::Weapon*> i(&(vehicle.weaponChain));
unsigned int rv = 0;
while (i.ReadAndNext() != 0) // here's a place where the STL would have made this SO much easier ...
{
++rv;
}
return (rv);
}
bool MW4AI::AnyWeaponReady(MechWarrior4::MWObject& object, Stuff::Time min_delay, Stuff::Time max_delay)
{
Stuff::ChainIteratorOf<MechWarrior4::Weapon*> i(&(object.weaponChain));
MechWarrior4::Weapon* weapon = 0;
while ((weapon = i.ReadAndNext()) != 0)
{
if (WeaponReadyToFire(*weapon,min_delay,max_delay) == true)
{
return (true);
}
}
return (false);
}
bool MW4AI::AnyWeaponNotReady(MechWarrior4::MWObject& object, Stuff::Time min_delay, Stuff::Time max_delay)
{
return (NumWeaponsReady(object,min_delay,max_delay) < NumWeapons(object));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// WeaponCanFire(): indicates whether the given weapon can fire
//
bool MW4AI::WeaponCanFire(MechWarrior4::Weapon& weapon,
Stuff::Scalar line_length,
Stuff::Time min_delay,
Stuff::Time max_delay)
{
if ((weapon.executionState == 0) ||
(weapon.executionState->GetState() == MechWarrior4::Weapon::ExecutionStateEngine::DestroyedState))
{
return (false);
}
if (weapon.ReadyToFire() == false)
{
return (false);
}
if (WeaponReadyToFire(weapon,min_delay,max_delay) == false)
{
return (false);
}
if (line_length != 0)
{
// MSL 5.03 Min Distance
if (line_length > GetMaxWeaponDistance(weapon))
// if ((line_length > GetMaxWeaponDistance(weapon)) || (line_length < GetMinWeaponDistance(weapon)+1))
{
return (false);
}
}
if (weapon.IsDerivedFrom(BombastWeapon::DefaultData) == true)
{
BombastWeapon* bombast = Cast_Object(BombastWeapon*,&weapon);
if (bombast->ReadyToFire() == true)
{
return (true);
}
if ((bombast->executionState->GetState() == BombastWeapon::ExecutionStateEngine::ChargingState) &&
(bombast->percentCharged > 0.9f))
{
return (true);
}
return (false);
}
return (true);
}
bool MW4AI::GetWeaponsThatCanFire(std::vector<Weapon *>& weapons,
bool can_spend_ammo,
Stuff::Time min_delay,
Stuff::Time max_delay)
{
bool any_can_fire(false);
{for (std::vector<Weapon*>::iterator i = weapons.begin();
i != weapons.end();
++i)
{
if ((*i) == 0)
{
continue;
}
if ((*i)->ReadyToFire() == false)
{
*i = 0;
continue;
}
if (((*i)->executionState == 0) ||
((*i)->executionState->GetState() == MechWarrior4::Weapon::ExecutionStateEngine::DestroyedState))
{
*i = 0;
continue;
}
if (WeaponReadyToFire(**i,min_delay,max_delay) == false)
{
*i = 0;
continue;
}
if ((can_spend_ammo == false) &&
((*i)->GetAmmoCount() != -1))
{
*i = 0;
continue;
}
any_can_fire = true;
}}
return (any_can_fire);
}
bool MW4AI::GetWeaponsThatCanFireAt(std::vector<Weapon *>& weapons,
const Stuff::Point3D& aim)
{
bool any_can_fire(false);
{for (std::vector<Weapon*>::iterator i = weapons.begin();
i != weapons.end();
++i)
{
if ((*i) != 0)
{
if (((*i)->sitePointer != 0) &&
(GetApproximateLength(aim,(Stuff::Point3D)(*i)->sitePointer->GetLocalToWorld()) >
GetMaxWeaponDistance(**i)))
{
*i = 0;
continue;
}
if ((*i)->IsDerivedFrom(BombastWeapon::DefaultData) == true)
{
BombastWeapon* bombast = Cast_Object(BombastWeapon*,*i);
if (bombast->ReadyToFire() == true)
{
any_can_fire = true;
}
else
{
if ((bombast->executionState->GetState() == BombastWeapon::ExecutionStateEngine::ChargingState) &&
(bombast->percentCharged > 0.9f))
{
any_can_fire = true;
}
else
{
*i = 0;
}
}
continue;
}
any_can_fire = true;
}
}}
return (any_can_fire);
}
bool MW4AI::GetWeaponsThatCanFireFrom(std::vector<Weapon *>& weapons,
FireSource fire_source)
{
if (fire_source == FIRE_FROM_ANYWHERE)
{
return (true);
}
bool any_can_fire(false);
{for (std::vector<Weapon*>::iterator i = weapons.begin();
i != weapons.end();
++i)
{
if ((*i) != 0)
{
if (WeaponIsArmWeapon(**i,(fire_source == FIRE_FROM_LEFT_ARM)) == false)
{
*i = 0;
continue;
}
any_can_fire = true;
}
}}
return (any_can_fire);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool MW4AI::MightHitFriendlies(const Stuff::Line3D& line,
Stuff::Scalar line_length,
MechWarrior4::MWObject& shooter,
MechWarrior4::MWObject* ignore)
{
if (shooter.GetSensor() == 0)
{
return (false);
}
const MechWarrior4::Sensor::sensorDataArray& sensed_data = shooter.GetSensor()->RefreshAndGetSensorData();
{for (int i = 0;
i < shooter.GetSensor()->numberOfContacts;
++i)
{
MechWarrior4::SensorData* d = sensed_data[i];
if (d != 0)
{
Adept::Entity* current = d->object.GetCurrent();
if ((current != 0) &&
(current != ignore) &&
(current->objectID != shooter.objectID))
{
bool should_avoid_hitting = false;
if (current->GetAlignment() == shooter.GetAlignment())
{
should_avoid_hitting = true;
}
else
{
if (current->IsDerivedFrom(MWObject::DefaultData) == true)
{
MWObject* mwobject = Cast_Object(MWObject*,current);
if (mwobject->GetTargetDesirability() == MWObject::desirability_never)
{
should_avoid_hitting = true;
}
}
}
if (should_avoid_hitting == true)
{
MWObject* mwobject = Cast_Object(MWObject*,current);
Scalar radius = friendly_fire_stretch_distance;
CollisionVolume* cv = mwobject->GetSolidVolume();
if (cv != 0)
{
radius += cv->m_worldSpaceBounds.sphereRadius;
}
Stuff::Line3D line2(line);
if (line_length != line2.m_length)
{
line2.m_length = line_length;
}
if (LinePenetrates(line2,mwobject->GetLineOfSight(),radius) == true)
{
Stuff::LinearMatrix4D los;
shooter.GetLineOfSight(los);
if (MatrixFacesPoint(los,(Stuff::Point3D)mwobject->GetLineOfSight(),90.0f * Radians_Per_Degree) == true)
{
return (true);
}
}
}
}
}
}}
return (false);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// SortedChainOfComponentsToVector(): converts a component_chain to a valid component_vector
//
/*
void SortedChainOfComponentsToVector(component_chain& chain, component_vector& v)
{
const int first_component = Adept::DamageObject::LeftLegArmorZone;
const int last_component = Adept::DamageObject::HeadArmorZone;
{for (int i = first_component;
i <= last_component;
++i)
{
Adept::DamageObject* damage_object = chain.Find(i);
if ((damage_object != 0) &&
(damage_object->parentEntity != 0))
{
v.push_back(damage_object);
}
}}
}
*/
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NormalizedDamage(): returns a normalized current damage value for the given damage object, where 1=undamaged and 0=destroyed
//
inline Stuff::Scalar NormalizedDamage(const Adept::DamageObject& damage_object)
{
if (damage_object.baseArmorValue == 0)
{
return (0);
}
if (damage_object.currentArmorValue >= damage_object.baseArmorValue)
{
return (1);
}
return (damage_object.currentArmorValue / damage_object.baseArmorValue);
}
class DamageObjectEvaluator
{
public:
virtual Stuff::Scalar Evaluate(const Adept::DamageObject& damage_object) const = 0;
};
class DamageObjectEvaluator_MostDamaged
: public DamageObjectEvaluator
{
public:
Stuff::Scalar Evaluate(const Adept::DamageObject& damage_object) const
{
return (1 - NormalizedDamage(damage_object));
}
};
class DamageObjectEvaluator_LeastDamaged
: public DamageObjectEvaluator
{
public:
Stuff::Scalar Evaluate(const Adept::DamageObject& damage_object) const
{
return (NormalizedDamage(damage_object));
}
};
inline Adept::DamageObject* GetBestDamageObject(const component_vector& v, const DamageObjectEvaluator& evaluator)
{
if (v.size() == 0)
{
return (0);
}
component_vector best_fit_list;
{for (component_vector::const_iterator i = v.begin();
i != v.end();
++i)
{
if (best_fit_list.size() == 0)
{
best_fit_list.push_back(*i);
}
else
{
Stuff::Scalar my_score = evaluator.Evaluate(**i);
Stuff::Scalar best_fit_list_score = evaluator.Evaluate(**(best_fit_list.begin()));
if (my_score > best_fit_list_score)
{
best_fit_list.clear();
}
if (my_score >= best_fit_list_score)
{
best_fit_list.push_back(*i);
}
}
}}
if (best_fit_list.size() > 0)
{
return (best_fit_list[gos_rand() % best_fit_list.size()]);
}
return (0);
}
Adept::DamageObject* FindComponent(const component_vector& components, int zone)
{
{for (component_vector::const_iterator i = components.begin();
i != components.end();
++i)
{
if ((*i)->armorZone == zone)
{
return (*i);
}
}}
return (0);
}
Adept::DamageObject* FindMostArmedComponent(MechWarrior4::MWObject& who, const component_vector& components)
{
int battle_values[5];
{for (int i = 0; i < 5; ++i)
{
battle_values[i] = 0;
}}
{
Stuff::ChainIteratorOf<MechWarrior4::Weapon*> i(&(who.weaponChain));
MechWarrior4::Weapon* weapon = 0;
while ((weapon = i.ReadAndNext()) != 0)
{
if ((weapon->GetParentVehicle() != 0) &&
(weapon->IsDestroyed() == false) &&
(weapon->GetGameModel() != 0))
{
MWInternalDamageObject *zone = weapon->GetParentVehicle()->internalDamageObjects.Find(weapon->internalLocation);
if (zone != 0)
{
int bv = weapon->GetGameModel()->battleValue;
switch (zone->damageZone)
{
case MWInternalDamageObject::LeftArmZone:
{
battle_values[0] += bv;
break;
}
case MWInternalDamageObject::LeftTorsoZone:
{
battle_values[1] += bv;
break;
}
case MWInternalDamageObject::CenterTorsoZone:
{
battle_values[2] += bv;
break;
}
case MWInternalDamageObject::RightTorsoZone:
{
battle_values[3] += bv;
break;
}
case MWInternalDamageObject::RightArmZone:
{
battle_values[4] += bv;
break;
}
}
}
}
}
}
DamageObject* best_object = 0;
int iters = 0;
while ((best_object == 0) &&
(iters < 4))
{
int best_index = 0;
{for (int i = 1;
i < 5;
++i)
{
if (battle_values[i] > battle_values[best_index])
{
best_index = i;
}
}}
int best_zone = Adept::DamageObject::CenterTorsoArmorZone;
switch (best_index)
{
case 0:
{
best_zone = Adept::DamageObject::LeftArmArmorZone;
break;
}
case 1:
{
best_zone = Adept::DamageObject::LeftTorsoArmorZone;
break;
}
case 3:
{
best_zone = Adept::DamageObject::RightTorsoArmorZone;
break;
}
case 4:
{
best_zone = Adept::DamageObject::RightArmArmorZone;
break;
}
}
DamageObject* best_object = FindComponent(components,best_zone);
if (best_object != 0)
{
return (best_object);
}
battle_values[best_index] = -1;
++iters;
}
return (FindComponent(components,Adept::DamageObject::CenterTorsoArmorZone));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// GetComponent_MostDamaged(): gets the most damaged component of a given list
//
Adept::DamageObject* MW4AI::GetComponent_MostDamaged(MechWarrior4::MWObject& who, const component_vector& v)
{
Verify(v.size() > 0);
bool any_damaged(false);
{for (component_vector::const_iterator i = v.begin();
i != v.end();
++i)
{
if ((*i)->GetCurrentDamageLevel() == Adept::DamageObject::Damaged)
{
any_damaged = true;
}
switch ((*i)->armorZone)
{
case Adept::DamageObject::LeftLegArmorZone:
{
if ((*i)->GetCurrentDamageLevel() == Adept::DamageObject::Destroyed)
{
{for (component_vector::const_iterator j = v.begin();
j != v.end();
++j)
{
if ((*j)->armorZone == Adept::DamageObject::RightLegArmorZone)
{
return (*j);
}
}}
}
break;
}
case Adept::DamageObject::RightLegArmorZone:
{
if ((*i)->GetCurrentDamageLevel() == Adept::DamageObject::Destroyed)
{
{for (component_vector::const_iterator j = v.begin();
j != v.end();
++j)
{
if ((*j)->armorZone == Adept::DamageObject::LeftLegArmorZone)
{
return (*j);
}
}}
}
break;
}
case Adept::DamageObject::CenterTorsoArmorZone:
{
if (((*i)->GetCurrentDamageLevel() == Adept::DamageObject::Damaged) ||
((*i)->GetCurrentDamageLevel() == Adept::DamageObject::Destroyed))
{
if ((*i)->armorLevel < 0.7f)
{
return (*i);
}
}
break;
}
}
}}
if (any_damaged == false)
{
int best_zone;
switch (gos_rand() & 0x07)
{
case 0: { best_zone = Adept::DamageObject::LeftArmArmorZone; break; }
case 1: { best_zone = Adept::DamageObject::LeftTorsoArmorZone; break; }
case 2: { best_zone = Adept::DamageObject::RightTorsoArmorZone; break; }
case 3: { best_zone = Adept::DamageObject::RightArmArmorZone; break; }
default: { best_zone = Adept::DamageObject::CenterTorsoArmorZone; break; }
}
Adept::DamageObject* damage_object = FindComponent(v,best_zone);
if (damage_object != 0)
{
return (damage_object);
}
}
DamageObjectEvaluator_MostDamaged func;
return (GetBestDamageObject(v,func));
}
Adept::DamageObject* MW4AI::GetComponent_LeastDamaged(const component_vector& v)
{
Verify(v.size() > 0);
DamageObjectEvaluator_LeastDamaged func;
return (GetBestDamageObject(v,func));
}
Adept::DamageObject* MW4AI::GetComponent_Random(const component_vector& v)
{
Verify(v.size() > 0);
if (v.size () == 0)
{
return (0);
}
return (v[gos_rand() % v.size()]);
}
Adept::DamageObject* MW4AI::GetComponent_TorsoThenTopDown(const component_vector& v)
{
Verify(v.size() > 0);
Adept::DamageObject* torso = FindComponent(v,Adept::DamageObject::CenterTorsoArmorZone);
if (torso != 0)
{
return (torso);
}
Stuff::Point3D highest(0,-1000,0);
component_vector::const_iterator best = v.end();
{for (component_vector::const_iterator i = v.begin();
i != v.end();
++i)
{
if ((*i)->parentEntity != 0)
{
Stuff::Point3D pos = (Stuff::Point3D)(*i)->parentEntity->GetLocalToWorld();
if (pos.y > highest.y)
{
highest = pos;
best = i;
}
}
}}
if (best == v.end())
{
return (*v.begin());
}
return (*best);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool MW4AI::WeaponIsArmWeapon(const MechWarrior4::Weapon& weapon, bool left)
{
if ((weapon.sitePointer != 0) &&
(weapon.sitePointer->GetParent() != 0) &&
(weapon.sitePointer->GetParent()->damageObject != 0) &&
(weapon.sitePointer->GetParent()->damageObject->internalDamageObject != 0))
{
Adept::InternalDamageObject* ido = weapon.sitePointer->GetParent()->damageObject->internalDamageObject;
if (left == true)
{
if (ido->damageZone == Adept::InternalDamageObject::LeftArmZone)
{
return (true);
}
}
else
{
if (ido->damageZone == Adept::InternalDamageObject::RightArmZone)
{
return (true);
}
}
}
return (false);
}
Stuff::LinearMatrix4D MW4AI::WeaponSiteLocalToWorld(const MechWarrior4::Weapon& weapon)
{
Verify(weapon.sitePointer != 0);
Verify(weapon.sitePointer->GetParent() != 0);
Verify(weapon.sitePointer->GetParent()->damageObject != 0);
Verify(weapon.sitePointer->GetParent()->damageObject->internalDamageObject != 0);
Verify(weapon.sitePointer->GetParent()->damageObject->internalDamageObject->parentEntity != 0);
return (weapon.sitePointer->GetLocalToWorld());
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool MW4AI::HasAnyUnlimitedAmmoWeapons(MechWarrior4::MWObject& object)
{
Stuff::ChainIteratorOf<MechWarrior4::Weapon*> i(&(object.weaponChain));
MechWarrior4::Weapon* weapon = 0;
while ((weapon = i.ReadAndNext()) != 0)
{
if (weapon->GetAmmoCount() == -1)
{
return (true);
}
}
return (false);
}
bool MW4AI::HasAnyProjectileWeapons(MechWarrior4::MWObject& object)
{
Stuff::ChainIteratorOf<MechWarrior4::Weapon*> i(&(object.weaponChain));
MechWarrior4::Weapon* weapon = 0;
while ((weapon = i.ReadAndNext()) != 0)
{
if (weapon->IsDerivedFrom(MechWarrior4::ProjectileWeapon::DefaultData) == true)
{
return (true);
}
}
return (false);
}
Weapon* FindFarthestWeapon(const std::vector<MechWarrior4::Weapon*>& weapons, const Stuff::Point3D& point)
{
if (weapons.size() == 0)
{
return (0);
}
Stuff::Scalar best_distance = 0;
std::vector<MechWarrior4::Weapon*>::const_iterator best = weapons.end();
{for (std::vector<MechWarrior4::Weapon*>::const_iterator i = weapons.begin();
i != weapons.end();
++i)
{
const Stuff::Scalar distance = GetLengthSquared(point,(Stuff::Point3D)(*i)->sitePointer->GetLocalToWorld());
if (distance >= best_distance)
{
best_distance = distance;
best = i;
}
}}
Verify(best != weapons.end());
return (*best);
}
void MW4AI::GetLeftmostAndRightmostWeapons(MechWarrior4::MWObject& object,
std::vector<MechWarrior4::Weapon*>& weapons)
{
Stuff::ChainIteratorOf<MechWarrior4::Weapon*> i(&(object.weaponChain));
MechWarrior4::Weapon* weapon = 0;
std::vector<MechWarrior4::Weapon*> all_weapons;
while ((weapon = i.ReadAndNext()) != 0)
{
all_weapons.push_back(weapon);
}
if (all_weapons.size() < 2)
{
return;
}
weapons.push_back(FindFarthestWeapon(all_weapons,GetWeaponCenter(object)));
weapons.push_back(FindFarthestWeapon(all_weapons,(Stuff::Point3D)weapons.back()->sitePointer->GetLocalToWorld()));
}
Stuff::Point3D MW4AI::GetWeaponCenter(MechWarrior4::MWObject& object)
{
Stuff::ChainIteratorOf<MechWarrior4::Weapon*> i(&(object.weaponChain));
MechWarrior4::Weapon* weapon = 0;
Stuff::Point3D center(0,0,0);
Stuff::Scalar num_counted(0);
while ((weapon = i.ReadAndNext()) != 0)
{
center += (Stuff::Point3D)weapon->sitePointer->GetLocalToWorld();
num_counted += 1;
}
if (num_counted == 0)
{
return (Stuff::Point3D(0,0,0));
}
center.x /= num_counted;
center.y /= num_counted;
center.z /= num_counted;
return (center);
}
void MW4AI::DamageObjectChainToVector(Stuff::SortedChainOf<Adept::DamageObject*,int>& chain, component_vector& v)
{
AutoHeap local_heap (g_CombatAIHeap);
Stuff::SortedChainIteratorOf<Adept::DamageObject*,int> i(&chain);
Adept::DamageObject* damage_object = 0;
while ((damage_object = i.ReadAndNext()) != 0)
{
if ((damage_object->parentEntity != 0) &&
(damage_object->armorZone != Adept::DamageObject::HeadArmorZone))
{
if (damage_object->GetCurrentDamageLevel() == Adept::DamageObject::Destroyed)
{
switch (damage_object->armorZone)
{
case Adept::DamageObject::LeftArmArmorZone:
{
v.push_back(damage_object);
break;
}
case Adept::DamageObject::RightArmArmorZone:
case Adept::DamageObject::RightTorsoArmorZone:
case Adept::DamageObject::LeftTorsoArmorZone:
case Adept::DamageObject::CenterTorsoArmorZone:
case Adept::DamageObject::CenterRearTorsoArmorZone:
{
v.push_back(damage_object);
break;
}
}
}
else
{
v.push_back(damage_object);
}
}
}
}
void MW4AI::SetRaySourceToBestComponent(Adept::Entity__CollisionQuery& query)
{
if ((query.m_raySource != 0) &&
(query.m_raySource != Adept::Map::GetInstance()) &&
(query.m_line != 0) &&
(query.m_raySource->IsDerivedFrom(MWObject::DefaultData) == true))
{
MWObject* mwobject = Cast_Object(MWObject*,query.m_raySource);
component_vector components;
DamageObjectChainToVector(mwobject->damageObjects,components);
Adept::Entity* nearest = 0;
Stuff::Scalar least_distance = 100000.0f;
least_distance *= least_distance;
{for (component_vector::iterator i = components.begin();
i != components.end();
++i)
{
if ((*i)->parentEntity != 0)
{
Stuff::Point3D damage_object_point((*i)->parentEntity->GetLocalToWorld());
Stuff::Point3D closest_point;
query.m_line->GetClosestPointTo(damage_object_point,&closest_point);
Stuff::Scalar distance(GetLengthSquared(damage_object_point,closest_point));
if (distance < least_distance)
{
nearest = (*i)->parentEntity;
least_distance = distance;
}
}
}}
if (nearest != 0)
{
query.m_raySource = nearest;
}
}
}