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

1840 lines
45 KiB
C++

//===========================================================================//
// File: AI.cpp //
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// 07/13/99 AHF Created file //
//---------------------------------------------------------------------------//
// Copyright (C) 1999, Microsoft //
// All Rights reserved worldwide //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
#include "MW4Headers.hpp"
//#include "windows.h"
#include "gameinfo.hpp"
#include "AI.hpp"
#include "AI_UserConstants.hpp"
#include "adept\Interface.hpp"
#include "adept\Application.hpp"
#include "adept\NameTable.hpp"
#include "adept\Map.hpp"
#include "adept\EntityManager.hpp"
#include "server\comline.hpp"
#include "mwobject.hpp"
#include "obstacle.hpp"
#include "adept\nametable.hpp"
#include "moverai.hpp"
#include "HeatManager.hpp"
#include "mech.hpp"
#include "mwmission.hpp"
#include <ElementRenderer\groupelement.hpp>
//#include "windows.h"
#include "data_client.hpp"
#include "lancemate.hpp"
#include "sensor.hpp"
#include "mwplayer.hpp"
#include "MWApplication.hpp"
#include "CameraShip.hpp"
#include "MWDebugHelper.hpp"
#include <mbstring.h>
#define __mbsrchr(s,c) (char*)_mbsrchr((const unsigned char*)(s),(c))
using namespace MW4AI;
using namespace MechWarrior4;
Graveyard* AI::m_Graveyard = 0;
int AI::m_AlwaysActiveCount = 0;
bool AI::m_GlobalTriggers[MW4AI::MAX_GLOBAL_TRIGGERS];
const MAXALWAYSACTIVE = 4;
namespace ABL
{
extern long execLineNumber;
};
//#############################################################################
//############################### AI ##############################
//#############################################################################
AI::ClassData* AI::DefaultData = NULL;
int AI::m_BoardGameMechAI=0,AI::m_LastBoardGameMechAI=0;
int AI::m_BoardGameVehicleAI=0,AI::m_LastBoardGameVehicleAI=0;
int AI::m_ActiveMechAI=0,AI::m_LastActiveMechAI=0;
int AI::m_ActiveVehicleAI=0,AI::m_LastActiveVehicleAI=0;
ElementRenderer::GroupElement *AI::m_GroupElement = NULL;
MemoryBlockOf<CommandEntry> *CommandEntry::m_EmptyCommand;
int MW4AI::g_AIExecutionNumber = 0;
DWORD MechWarrior4::Executed_AI_Count = 0;
DWORD MechWarrior4::Path_Calcs_Count = 0;
DWORD MechWarrior4::GridPath_Calcs_Count = 0;
DWORD MechWarrior4::QuickPath_Calcs_Count = 0;
DWORD MechWarrior4::QuickRail_Calcs_Count = 0;
DWORD MechWarrior4::FailedPath_Calcs_Count = 0;
namespace MW4AI
{
__int64 tABLTime;
HGOSHEAP g_AIHeap,g_MoverAIHeap,g_CombatAIHeap,g_RailHeap,g_RootAIHeap;
};
const Stuff::Scalar default_is_shot_radius = 80;
void MW4AI::SetupAIStagger (void)
{
int j,size,current;
NameTable *table = NameTable::GetInstance();
size = table->nameTableArray[NameTable::AIArray].GetLength ();
current = 0;
for (j=0;j<size;j++)
{
NameTableEntry *data;
AI* ai;
Entity *ent;
data = &table->nameTableArray [NameTable::AIArray][j];
ent = data->dataPointer->GetCurrent ();
if (!ent)
continue;
if ((ent->IsDerivedFrom (AI::DefaultData)) && (!ent->IsDerivedFrom (MoverAI::DefaultData)))
{
ai = Cast_Object (AI *,ent);
// if ((ai->aiBrain) || (ai->aiDLLBrain))
{
ai->ExecutionNumber (current);
current++;
}
}
current %= AIExecutionDelta;
}
for (j=0;j<size;j++)
{
NameTableEntry *data;
AI* ai;
Entity *ent;
data = &table->nameTableArray [NameTable::AIArray][j];
ent = data->dataPointer->GetCurrent ();
if (!ent)
continue;
if (ent->IsDerivedFrom (MoverAI::DefaultData))
{
ai = Cast_Object (AI *,ent);
ai->ExecutionNumber (current);
current++;
}
current %= AIExecutionDelta;
}
}
void MW4AI::ResetGlobalTriggers()
{
{for (int i = 0;
i < MAX_GLOBAL_TRIGGERS;
++i)
{
AI::SetGlobalTrigger(i,false);
}}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void AI::InitializeClass()
{
g_RootAIHeap = gos_CreateMemoryHeap ("Root AI");
g_AIHeap = gos_CreateMemoryHeap ("Misc AI",0,g_RootAIHeap);
g_MoverAIHeap = gos_CreateMemoryHeap ("Mover AI",0,g_RootAIHeap);
g_CombatAIHeap = gos_CreateMemoryHeap ("Combat AI",0,g_RootAIHeap);
g_RailHeap = gos_CreateMemoryHeap ("Movement System",0,g_RootAIHeap);
#if 0
// char user_name[200];
// DWORD username_size = 200;
// GetUserName((char*)&user_name,&username_size);
// if (!strcmp (user_name,"dabzug"))
// g_AbzugFlag = true;
// else
// g_AbzugFlag = false;
// if (s_NoAbzug)
// g_AbzugFlag = false;
#endif
Verify(!DefaultData);
DefaultData =
new ClassData(
AIClassID,
"Adept::AI",
Driver::DefaultData,
0, NULL,
(Entity::Factory)Make,
(Entity::CreateMessage::Factory)CreateMessage::ConstructCreateMessage,
ExecutionStateEngine::DefaultData,
(Entity::GameModel::Factory)GameModel::ConstructGameModel,
NULL,
(Entity::GameModel::ReadAndVerifier)GameModel::ReadAndVerify,
(Entity::GameModel::ModelWrite)GameModel::WriteToText,
(Entity::GameModel::ModelSave)GameModel::SaveGameModel
);
Register_Object(DefaultData);
CommandEntry::m_EmptyCommand = new MemoryBlockOf<CommandEntry> (100,10,"Command Entry Blocks");
InitObstacle ();
#if !defined(NO_TIMERS)
g_TimerStack = new std::stack<__int64*>;
StatisticFormat("");
StatisticFormat("AI Routines");
StatisticFormat("===========");
StatisticFormat("");
AddStatistic( "AI Script Time", "%", gos_timedata, (void*)&tABLTime, 0 );
#endif
Register_Object (CommandEntry::m_EmptyCommand);
m_GroupElement = new ElementRenderer::GroupElement ();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void AI::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
Unregister_Object (CommandEntry::m_EmptyCommand);
delete CommandEntry::m_EmptyCommand;
CommandEntry::m_EmptyCommand = NULL;
CleanObstacle ();
Check_Object(m_GroupElement);
delete m_GroupElement;
gos_DestroyMemoryHeap (g_CombatAIHeap);
gos_DestroyMemoryHeap (g_MoverAIHeap);
gos_DestroyMemoryHeap (g_AIHeap);
gos_DestroyMemoryHeap (g_RailHeap);
#if !defined(NO_TIMERS)
delete g_TimerStack;
#endif
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AI* AI::Make(CreateMessage *message,ReplicatorID *base_id)
{
AutoHeap local_heap (g_AIHeap);
AI *new_entity = new AI(DefaultData, message, base_id, NULL);
Check_Object(new_entity);
new_entity->SyncMatrices(true);
return new_entity;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void AI::Save (MemoryStream *stream)
{
*stream << m_GunnerySkill;
*stream << m_PilotSkill;
*stream << m_EliteSkill;
*stream << m_MinHeatSkill;
*stream << m_MaxHeatSkill;
*stream << m_SensorSkill;
*stream << m_BlindFightingSkill;
*stream << m_LongRangeGunnerySkill;
*stream << m_ShortRangeGunnerySkill;
*stream << m_TowardsPilotSkill;
*stream << m_TowardsGunnerySkill;
*stream << m_TowardsEliteSkill;
*stream << m_StartGunnerySkill;
*stream << m_StartPilotSkill;
*stream << m_StartEliteSkill;
*stream << m_EntropyMood;
*stream << m_CurrentMood;
*stream << m_LastMoodChange;
*stream << m_UsingCoolant;
*stream << m_IgnoringFriendlyFire;
*stream << m_ShotBy;
*stream << m_LastTimeShot;
*stream << m_RammedBy;
*stream << m_LastTimeRammed;
*stream << m_FirstFrame;
*stream << m_SecondFrame;
*stream << m_Active;
*stream << m_Debugging;
*stream << m_Dead;
*stream << m_ScriptRunning;
*stream << m_ExecutionNumber;
*stream << m_AlwaysActive;
*stream << m_IsShotRadius;
*stream << m_Deactive;
if (m_CurrentTarget.GetCurrent())
{
*stream << true;
*stream << m_CurrentTarget.GetCurrent()->objectID;
}
else
*stream << false;
int i;
for (i=0;i<MW4AI::NUM_MEMORY_CELLS;i++)
{
*stream << memory[i];
}
if (aiBrain)
{
aiBrain->write (stream);
}
// pass save up to driver
}
void AI::Load (MemoryStream *stream)
{
*stream >> m_GunnerySkill;
*stream >> m_PilotSkill;
*stream >> m_EliteSkill;
*stream >> m_MinHeatSkill;
*stream >> m_MaxHeatSkill;
*stream >> m_SensorSkill;
*stream >> m_BlindFightingSkill;
*stream >> m_LongRangeGunnerySkill;
*stream >> m_ShortRangeGunnerySkill;
*stream >> m_TowardsPilotSkill;
*stream >> m_TowardsGunnerySkill;
*stream >> m_TowardsEliteSkill;
*stream >> m_StartGunnerySkill;
*stream >> m_StartPilotSkill;
*stream >> m_StartEliteSkill;
*stream >> m_EntropyMood;
*stream >> m_CurrentMood;
*stream >> m_LastMoodChange;
*stream >> m_UsingCoolant;
*stream >> m_IgnoringFriendlyFire;
*stream >> m_ShotBy;
*stream >> m_LastTimeShot;
*stream >> m_RammedBy;
*stream >> m_LastTimeRammed;
*stream >> m_FirstFrame;
*stream >> m_SecondFrame;
*stream >> m_Active;
*stream >> m_Debugging;
*stream >> m_Dead;
*stream >> m_ScriptRunning;
*stream >> m_ExecutionNumber;
*stream >> m_AlwaysActive;
*stream >> m_IsShotRadius;
*stream >> m_Deactive;
bool flag;
*stream >> flag;
m_CurrentTarget.Remove();
if (flag)
{
ObjectID object_id;
*stream >> object_id;
m_CurrentTarget.Add(Cast_Object (MWObject *,NameTable::GetInstance()->FindData(object_id)));
}
int i;
for (i=0;i<MW4AI::NUM_MEMORY_CELLS;i++)
{
*stream >> memory[i];
}
if (aiBrain)
{
aiBrain->read (stream);
}
if (vehicle->IsDerivedFrom (MWObject::DefaultData))
{
MWObject *veh = Cast_Object (MWObject *,vehicle);
Sensor *sensor = veh->GetSensor ();
sensor->m_UpdateTime = (Scalar) SensorSkill ();
}
// pass load up to driver
}
Replicator::CreateMessage* AI::SaveMakeMessage(MemoryStream *stream, ResourceFile *res_file)
{
Check_Object(this);
Check_Object(stream);
stream->AllocateBytes(sizeof(CreateMessage));
Driver::SaveMakeMessage(stream, res_file);
CreateMessage *message = Cast_Pointer(CreateMessage*, stream->GetPointer());
message->messageLength = sizeof(*message);
message->entityID = NameTable::GetInstance()->FindID(vehicle->instanceName);
Str_Copy (message->scriptName,scriptName.c_str(),128);
return message;
}
bool AI::ShouldRun (bool execnumonly) const
{
if (m_Dead)
{
return false;
}
if ((!execnumonly) && (m_Deactive))
return false;
if (m_FirstFrame)
return false;
return m_ExecutionNumber == MW4AI::g_AIExecutionNumber;
}
bool AI::LoadScript (char *filename)
{
scriptName = filename;
return true;
}
void AI::UnloadScript (void)
{
if (aiBrain)
{
Check_Pointer (aiBrain);
delete aiBrain;
aiBrain = NULL;
}
}
bool AI::ReloadScript (ABL::ABLError *err)
{
m_FirstFrame = true;
UnloadScript ();
/* // TODO: use this implementation or remove it
if (m_ScriptParams.size() > 0)
{
aiScriptHandle = ABL::ABLi_preProcessFromParams(m_ScriptParams,(char*)instanceName);
aiBrain = new ABL::ABLModule;
long brainErr = aiBrain->init(aiScriptHandle);
gosASSERT(brainErr == 0);
if (brainErr)
STOP(("1???")); // todo fix this to proper exit.
// aiBrain->setName((char*)script_name.c_str()); // is this necessary?
}
else
{
*/
if (scriptName[0] != 0)
{
char name[128];
Str_Copy(name, scriptName.c_str(), sizeof(name));
AutoHeap local_heap (g_AIHeap);
aiScriptHandle = ABL::ABLi_preProcess(name, err,NULL,NULL);
if (aiScriptHandle <0)
return false;
aiBrain = new ABL::ABLModule;
gosASSERT(aiBrain != NULL);
long brainErr = aiBrain->init(aiScriptHandle);
gosASSERT(brainErr == 0);
if (brainErr)
STOP(("1???")); // todo fix this to proper exit.
aiBrain->setName(__mbsrchr (scriptName.c_str(),'\\'));
}
else
{
aiScriptHandle = 0;
aiBrain = NULL;
scriptName[0] = 0;
}
// }
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AI::AI(ClassData *class_data,CreateMessage *message,ReplicatorID *base_id,ElementRenderer::Element *element)
: Driver(class_data, message, base_id, element)
, m_ShotBy(0xFFFFFFFF)
, m_LastTimeShot(0)
, m_CurrentTarget(NULL)
, m_EntropyMood(5)
, m_CurrentMood(5)
, m_LastMoodChange(0)
, m_FirstFrame(true)
, m_SecondFrame(false)
, m_Active(true)
, m_DebugPrintCallback(NULL)
, m_Debugging(false)
, m_Dead(false)
, aiScriptHandle(0)
, aiBrain(NULL)
, m_IgnoringFriendlyFire(false)
, m_ScriptRunning(true)
, m_IsShotRadius(-1)
, m_RammedBy(0xFFFFFFFF)
, m_LastTimeRammed(0)
, m_UsingCoolant(false)
, m_Deactive (false)
, m_Lancemate (NULL)
, m_ExecutionNumber(0)
{
Check_Pointer(this);
Check_Object(message);
//
//----------------------------------------------
//Setup the script
//----------------------------------------------
//
MW4AI::UserConstants::IncrementRefCount();
AutoHeap local_heap (g_AIHeap);
AddCreationData ("AI", (const char *) instanceName,objectID);
aiDLLBrain = NULL;
memcpy (memory,message->cellValues,sizeof (Stuff::Scalar)*DEFAULT_MEMORYCELL_VALUES);
m_StartupRequest = false;
m_ShutdownRequest = false;
m_SelfDestructing = false;
m_GunnerySkill = message->gunnerySkill;
m_PilotSkill = message->pilotSkill;
m_EliteSkill = message->eliteSkill;
m_MinHeatSkill = message->minHeatSkill;
m_MaxHeatSkill = message->maxHeatSkill;
m_SensorSkill = message->sensorSkill;
m_BlindFightingSkill = message->blindFightingSkill;
m_LongRangeGunnerySkill = message->longRangeGunnerySkill;
m_ShortRangeGunnerySkill = message->shortRangeGunnerySkill;
m_TowardsGunnerySkill = message->towardsGunnerySkill;
m_TowardsPilotSkill = message->towardsPilotSkill;
m_TowardsEliteSkill = message->towardsEliteSkill;
// m_ScriptParams = message->scriptParams;
m_StartGunnerySkill = m_GunnerySkill;
m_StartPilotSkill = m_PilotSkill;
m_StartEliteSkill = m_EliteSkill;
// m_ScriptParams = "G_Ambush.abl,5,1.0,2.0,100,50,50,50,80,500,750"; // TEMPORARY FOR TESTING
if (message->scriptName[0] != 0)
{
scriptName = message->scriptName;
}
else
scriptName[0] = 0;
//
//----------------------------------------------
//Connect the AI Driver to the specified Vehicle
//----------------------------------------------
//
if (message->entityID != NameTable::NullObjectID)
{
Check_Object(NameTable::GetInstance());
vehicle = NameTable::GetInstance()->FindData(message->entityID);
Check_Object (vehicle);
Verify (vehicle->IsDerivedFrom (MWObject::DefaultData));
if (Network::GetInstance()->AmIServer())
{
ConnectEntity ((MWObject *) vehicle);
if (vehicle->IsDerivedFrom (MWObject::DefaultData))
{
MWObject *veh = Cast_Object (MWObject *,vehicle);
veh->HasAI(true);
Sensor *sensor = veh->GetSensor ();
if (sensor)
sensor->m_UpdateTime = (Scalar) SensorSkill ();
}
}
else
{
if (vehicle->IsDerivedFrom (MWObject::DefaultData))
{
MWObject *veh = Cast_Object (MWObject *,vehicle);
veh->HasAI(true);
}
executionState->RequestState(ExecutionStateEngine::NeverExecuteState);
}
}
if (!vehicle)
m_Deactive = false;
m_AlwaysActive = false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AI::~AI()
{
if (aiBrain)
{
Check_Pointer (aiBrain);
delete aiBrain;
aiBrain = NULL;
}
if (aiDLLBrain)
{
aiDLLExecute = NULL;
FreeLibrary ((HINSTANCE) aiDLLBrain);
aiDLLBrain = NULL;
}
MW4AI::UserConstants::DecrementRefCount();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
AI::Respawn(Entity::CreateMessage *message)
{
Check_Object(this);
Check_Object(message);
Driver::Respawn(message);
if (!Network::GetInstance()->AmIServer())
{
executionState->RequestState(ExecutionStateEngine::NeverExecuteState);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void AI::AlwayActive (bool p1)
{
if (!m_AlwaysActive && p1)
{
m_AlwaysActiveCount++;
#ifdef LAB_ONLY
if (m_AlwaysActiveCount > MAXALWAYSACTIVE)
{
int size;
NameTable *table = NameTable::GetInstance();
size = table->nameTableArray[NameTable::AIArray].GetLength ();
char test[255];
sprintf (test,"%d always active ai's of %d total ai's",m_AlwaysActiveCount,size);
SPEWALWAYS ((NULL,test));
AddMessageData (test);
}
#endif
}
m_AlwaysActive = p1;
}
void AI::SelfDestruct (void)
{
m_SelfDestructing = true;
}
void AI::Shutdown (void)
{
ablREPORT (vehicle->IsDerivedFrom (MWObject::DefaultData),"tried to shutdown a unit that is not an mwobject");
if (m_Active == false)
{
return;
}
MWObject *obj = Cast_Object (MWObject *,vehicle);
obj->vehicleShutDown = true;
obj->vehicleJustPoweredUp = false;
m_Active = false;
}
void AI::Startup (void)
{
ablREPORT (vehicle->IsDerivedFrom (Vehicle::DefaultData),"tried to startup a unit that is not a vehicle");
if (m_Active == true)
{
return;
}
MWObject *obj = Cast_Object (MWObject *,vehicle);
obj->vehicleShutDown = false;
obj->vehicleJustPoweredUp = true;
m_Active = true;
}
inline int GetDefaultedSkill(int skill_value, MW4AI::UserConstants::ID id)
{
Verify(MW4AI::UserConstants::Instance());
if (skill_value == -1)
{
return ((int)MW4AI::UserConstants::Instance ()->Get(id));
}
return skill_value;
}
int AI::GunnerySkill (void) const
{
float value;
int align;
value = (float) GetDefaultedSkill(m_GunnerySkill,MW4AI::UserConstants::default_gunnery);
align = Entity::DefaultAlignment;
if (vehicle)
align = vehicle->GetAlignment();
switch (align)
{
case Entity::Player:
switch (MWApplication::GetInstance()->GetDifficultyLevel())
{
case MWApplication::EASY_DIFFICULTY:
value *= MW4AI::UserConstants::Instance ()->Get(MW4AI::UserConstants::friend_easy_gunnery_mod);
break;
case MWApplication::MEDIUM_DIFFICULTY:
value *= MW4AI::UserConstants::Instance ()->Get(MW4AI::UserConstants::friend_medium_gunnery_mod);
break;
case MWApplication::HARD_DIFFICULTY:
value *= MW4AI::UserConstants::Instance ()->Get(MW4AI::UserConstants::friend_hard_gunnery_mod);
break;
case MWApplication::IMPOSSIBLE_DIFFICULTY:
value *= MW4AI::UserConstants::Instance ()->Get(MW4AI::UserConstants::friend_impossible_gunnery_mod);
break;
}
break;
case Entity::DefaultAlignment:
switch (MWApplication::GetInstance()->GetDifficultyLevel())
{
case MWApplication::EASY_DIFFICULTY:
value *= MW4AI::UserConstants::Instance ()->Get(MW4AI::UserConstants::neutral_easy_gunnery_mod);
break;
case MWApplication::MEDIUM_DIFFICULTY:
value *= MW4AI::UserConstants::Instance ()->Get(MW4AI::UserConstants::neutral_medium_gunnery_mod);
break;
case MWApplication::HARD_DIFFICULTY:
value *= MW4AI::UserConstants::Instance ()->Get(MW4AI::UserConstants::neutral_hard_gunnery_mod);
break;
case MWApplication::IMPOSSIBLE_DIFFICULTY:
value *= MW4AI::UserConstants::Instance ()->Get(MW4AI::UserConstants::neutral_impossible_gunnery_mod);
break;
}
break;
default:
switch (MWApplication::GetInstance()->GetDifficultyLevel())
{
case MWApplication::EASY_DIFFICULTY:
value *= MW4AI::UserConstants::Instance ()->Get(MW4AI::UserConstants::enemy_easy_gunnery_mod);
break;
case MWApplication::MEDIUM_DIFFICULTY:
value *= MW4AI::UserConstants::Instance ()->Get(MW4AI::UserConstants::enemy_medium_gunnery_mod);
break;
case MWApplication::HARD_DIFFICULTY:
value *= MW4AI::UserConstants::Instance ()->Get(MW4AI::UserConstants::enemy_hard_gunnery_mod);
break;
case MWApplication::IMPOSSIBLE_DIFFICULTY:
value *= MW4AI::UserConstants::Instance ()->Get(MW4AI::UserConstants::enemy_impossible_gunnery_mod);
break;
}
break;
}
return (int) value;
}
int AI::PilotSkill (void) const
{
return (GetDefaultedSkill(m_PilotSkill,MW4AI::UserConstants::default_pilot));
}
int AI::SensorSkill (void) const
{
return (GetDefaultedSkill(m_SensorSkill,MW4AI::UserConstants::default_sensor));
}
int AI::BlindFightingSkill (void) const
{
return (GetDefaultedSkill(m_BlindFightingSkill,MW4AI::UserConstants::default_blind));
}
int AI::LongRangeGunnerySkill (void) const
{
return (GetDefaultedSkill(m_LongRangeGunnerySkill,MW4AI::UserConstants::default_longrange));
}
int AI::ShortRangeGunnerySkill (void) const
{
return (GetDefaultedSkill(m_ShortRangeGunnerySkill,MW4AI::UserConstants::default_shortrange));
}
int AI::EliteSkill (void) const
{
return (GetDefaultedSkill(m_EliteSkill,MW4AI::UserConstants::default_elite));
}
int AI::MinHeatSkill (void) const
{
return (GetDefaultedSkill(m_MinHeatSkill,MW4AI::UserConstants::default_minheat));
}
int AI::MaxHeatSkill (void) const
{
return (GetDefaultedSkill(m_MaxHeatSkill,MW4AI::UserConstants::default_maxheat));
}
bool AI::PilotSkillCheck (Stuff::Scalar damage_amount,bool jump)
{
Scalar value,comp,mod;
Verify (MW4AI::UserConstants::Instance ());
Verify (getEntity ()->IsDerivedFrom (Mech::DefaultData));
Mech *mech = Cast_Object (Mech *, getEntity ());
MW4AI::UserConstants *data = MW4AI::UserConstants::Instance ();
mod = 1.0f;
if (damage_amount >= 0) // less than zero means ignore damage
{
if (damage_amount < data->Get (MW4AI::UserConstants::damage_amount))
return true; // did not take enough damage to cause check
else if (damage_amount > (2*data->Get (MW4AI::UserConstants::damage_amount)))
mod *= data->Get (MW4AI::UserConstants::double_damage_mod);
else
mod *= data->Get (MW4AI::UserConstants::damage_mod);
}
if (jump)
mod *= data->Get (MW4AI::UserConstants::jump_recover_mod);
Point3D loc(mech->GetLocalToWorld ());
unsigned short mapdata = g_MissionGraph->Passable (loc.x,loc.z);
mapdata &= WATER_MASK;
mapdata >>= WATER_SHIFT;
if (mapdata == SHALLOW_WATER)
mod *= data->Get (MW4AI::UserConstants::low_water_mod);
else if (mapdata == MEDIUM_WATER)
mod *= data->Get (MW4AI::UserConstants::mid_water_mod);
if (mech->gimpState != Mech::NotGimpedMode)
{
mod *= data->Get (MW4AI::UserConstants::gimped_mod);
}
Check_Object (mech->GetGameModel ());
const Mech__GameModel *model = static_cast<const Mech__GameModel *> (mech->GetGameModel ()) ;
if (mech->currentSpeedMPS > (model->maxSpeed / 2.0f))
{
mod *= data->Get (MW4AI::UserConstants::moving_fast_mod);
}
BYTE material;
GetMapY (loc.x,loc.z,mech,material,loc.y);
if ((material == ConcreteMaterial) || (material == DarkConcreteMaterial))
{
mod *= data->Get (MW4AI::UserConstants::concrete_mod);
}
value = Stuff::Random::GetFraction ();
comp = mod * PilotSkill ();
value *= SKILL_MULT;
if (comp < 5.0f)
comp = 5.0f;
else if (comp > 95.0f)
comp = 95.0f;
if (value >= comp)
{
NotifyFailedPilotingRoll();
}
return(value < comp);
}
void AI::AddTowardGunnery (int value)
{
Verify (UserConstants::Instance());
if (value == -1)
value = (int) UserConstants::Instance()->Get(UserConstants::default_addgunnery);
m_TowardsGunnerySkill += value;
if (m_TowardsGunnerySkill >= m_GunnerySkill)
{
if ((m_GunnerySkill - m_StartGunnerySkill) < UserConstants::Instance()->Get(UserConstants::max_skill_add))
{
m_GunnerySkill += 1;
DataClient::Add_AddSkill(1,objectID);
}
m_TowardsGunnerySkill -= (m_GunnerySkill-1);
}
}
void AI::AddTowardPilot (int value)
{
Verify (UserConstants::Instance());
if (value == -1)
value = (int) UserConstants::Instance()->Get(UserConstants::default_addpilot);
m_TowardsPilotSkill += value;
if (m_TowardsPilotSkill >= m_PilotSkill)
{
if ((m_PilotSkill - m_StartPilotSkill) < UserConstants::Instance()->Get(UserConstants::max_skill_add))
{
m_PilotSkill += 1;
DataClient::Add_AddSkill(0,objectID);
}
m_TowardsPilotSkill -= (m_PilotSkill-1);
}
}
void AI::AddTowardElite (int value)
{
Verify (UserConstants::Instance());
if (value == -1)
value = (int) UserConstants::Instance()->Get(UserConstants::default_addelite);
m_TowardsEliteSkill += value;
if (m_TowardsEliteSkill >= m_EliteSkill)
{
if ((m_EliteSkill - m_StartEliteSkill) < UserConstants::Instance()->Get(UserConstants::max_skill_add))
{
m_EliteSkill += 1;
DataClient::Add_AddSkill(2,objectID);
}
m_TowardsEliteSkill -= (m_EliteSkill-1);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void AI::TurnOn (void)
{
MWObject *obj;
Verify (!m_FirstFrame);
if (vehicle && !m_FirstFrame)
{
m_TurningOn = true;
obj = Cast_Object (MWObject *,vehicle);
obj->TurnOn ();
m_TurningOn = false;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void AI::TurnOff (void)
{
MWObject *obj;
if (vehicle && !m_FirstFrame)
{
obj = Cast_Object (MWObject *,vehicle);
obj->TurnOff ();
}
else if (vehicle && vehicle->IsDerivedFrom (Vehicle::DefaultData))
{
vehicle->executionState->RequestState(Vehicle::ExecutionStateEngine::AIMotionState);
}
else
{
obj = Cast_Object (MWObject *,vehicle);
obj->TurnOff ();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void AI::DetermineExecution(Stuff::Time till)
{
if (!m_FirstFrame && m_SecondFrame)
{
if ((m_AlwaysActive) || (MWApplication::GetInstance()->networkingFlag))
{
if (m_Deactive)
{
m_Deactive = false;
TurnOn ();
}
}
else
{
Scalar dist;
MWMission *inst;
Check_Object (MWMission::GetInstance());
inst = Cast_Object (MWMission *,MWMission::GetInstance());
dist = inst->m_DistanceCheck;
Point3D loc (vehicle->GetLocalToWorld ());
ChainIteratorOf<Entity *> iterator(&inst->m_CheckChain);
Entity *ent;
bool flag = false;
if (loc != Point3D::HellPoint)
{
while ((ent = iterator.ReadAndNext()) != NULL)
{
if (ent->IsWithin (vehicle,dist,true))
{
flag = true;
if (m_Deactive)
{
m_Deactive = false;
TurnOn ();
}
break;
}
}
}
if (!flag)
{
// if (!Target ())
{
if (!m_Deactive)
{
m_Deactive = true;
TurnOff ();
}
}
}
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
#pragma warning (disable : 4706)
void AI::PreCollisionExecute(Time till)
{
extern int g_nMR;
if (g_nMR == 2)
return;
AI_LOGIC("Pre-Collision::AI");
if (Application::GetInstance()->GetApplicationState() != ApplicationStateEngine::PreRenderState)
{
#if defined(LAB_ONLY)
if (!instanceName)
MWGameInfo::g_LastMWObject[0] = '\0';
else
{
strncpy(MWGameInfo::g_LastMWObject, instanceName, sizeof(MWGameInfo::g_LastMWObject)-1);
MWGameInfo::g_LastMWObject[sizeof(MWGameInfo::g_LastMWObject)-1] = '\0';
}
MWGameInfo::g_LastMWObjectPos = GetLocalToWorld();
#endif
Check_Object(this);
//
//---------------------------------
// Verify that this always executes
//---------------------------------
//
#ifdef LAB_ONLY
if (IsDerivedFrom(MechAI::DefaultData))
{
if ((!m_Dead) && (ShouldRun (true)))
{
if (m_Deactive)
m_BoardGameMechAI++;
else
m_ActiveMechAI++;
}
}
else
{
if ((!m_Dead) && (ShouldRun (true)))
{
if (m_Deactive)
m_BoardGameVehicleAI++;
else
m_ActiveVehicleAI++;
}
}
#endif
Check_Object(executionState);
if (executionState->GetState() == ExecutionStateEngine::NeverExecuteState)
return;
UpdateMood();
Check_Object (vehicle);
if (!m_FirstFrame && m_SecondFrame)
{
if (m_ExecutionNumber != MW4AI::g_AIExecutionNumber)
{
Driver::PreCollisionExecute (till);
return;
}
}
if (m_ScriptRunning && ((aiBrain || aiDLLExecute) && (!m_FirstFrame)))
{
if ((ShouldRunScript() == true) ||
(m_SecondFrame == false))
{
AutoHeap local_heap (g_AIHeap);
ABL::CurWarrior = this;
// aiBrain->setTrace (true);
PRECOLLISION_LOGIC("AI::Execute");
#if !defined(NO_TIMERS)
my_AutoTimer fred ((void *) &tABLTime);
#endif
#ifdef LAB_ONLY
if (aiDLLExecute)
{
try
{
aiDLLExecute (this,till,NameTable::GetInstance());
}
catch (...)
{
ablREPORT (false," Critical failure in ai dll, turning off dll. Continue at your own risk");
aiDLLExecute = NULL;
FreeLibrary ((HINSTANCE) aiDLLBrain);
}
}
else
{
try
{
aiBrain->execute ();
m_SecondFrame = true;
}
catch (...)
{
ablREPORT (false,ABL::ablERROR (" Critical failure in abl script, turning off script. Continue at your own risk"));
delete aiBrain;
aiBrain = NULL;
}
}
#else
if (aiDLLExecute)
{
aiDLLExecute (this,till,NameTable::GetInstance());
}
else
{
aiBrain->execute();
m_SecondFrame = true;
}
#endif
ABL::CurWarrior = NULL;
}
}
else if (m_FirstFrame)
{
AutoHeap local_heap (g_AIHeap);
aiDLLExecute = NULL;
aiBrain = NULL;
aiDLLBrain = NULL;
if (scriptName[0] != 0)
{
char *fred;
fred = strrchr (scriptName.c_str(),'.');
if (!stricmp (fred,".ai"))
{
aiDLLBrain = LoadLibrary (scriptName.c_str());
if (aiDLLBrain)
aiDLLExecute = (AIExecuteFunction) GetProcAddress ((HINSTANCE) aiDLLBrain,"aiexecute");
}
else
{
/* // TODO: use this implementation or remove it
if (m_ScriptParams.size() > 0)
{
aiScriptHandle = ABL::ABLi_preProcessFromParams(m_ScriptParams,(char*)instanceName);
aiBrain = new ABL::ABLModule;
long brainErr = aiBrain->init(aiScriptHandle);
gosASSERT(brainErr == 0);
if (brainErr)
STOP(("1???")); // todo fix this to proper exit.
// aiBrain->setName((char*)script_name.c_str()); // is this necessary?
}
else
{
*/
char name[128];
ABL::ABLError err;
Str_Copy(name, scriptName.c_str(), sizeof(name));
aiScriptHandle = ABL::ABLi_preProcess(name, &err,NULL,NULL);
if (aiScriptHandle < 0)
{
ablREPORT (false,err.Details ());
aiScriptHandle = 0;
aiBrain = NULL;
}
else
{
aiBrain = new ABL::ABLModule;
gosASSERT(aiBrain != NULL);
long brainErr = aiBrain->init(aiScriptHandle);
gosASSERT(brainErr == 0);
if (brainErr)
STOP(("1???")); // todo fix this to proper exit.
aiBrain->setName(__mbsrchr (scriptName.c_str(),'\\'));
}
// }
}
}
else
{
aiScriptHandle = 0;
aiBrain = NULL;
m_SecondFrame = true;
}
m_Deactive = true;
TurnOff ();
}
m_FirstFrame = false;
if (m_UsingCoolant == true)
{
if ((getEntity() != 0) &&
(getEntity()->IsDerivedFrom(MechWarrior4::MWObject::DefaultData) == true))
{
MechWarrior4::MWObject* mwobject = Cast_Object(MechWarrior4::MWObject*,getEntity());
if (mwobject->m_heatManager != 0)
{
if (mwobject->m_heatManager->GetHeatPercentage() < ((Stuff::Scalar)MinHeatSkill() / 100.0f) - 0.01f)
{
mwobject->SetCooling(0);
m_UsingCoolant = false;
}
}
else
{
mwobject->SetCooling(0);
m_UsingCoolant = false;
}
}
else
{
m_UsingCoolant = false;
}
}
}
Set_Statistic(Executed_AI_Count, Executed_AI_Count+1);
Driver::PreCollisionExecute(till);
if (!IsUsingPostCollision())
{
lastExecuted = till;
}
}
#pragma warning (default : 4706)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void AI::ConnectLancemate(LancematePlug *lancemate)
{
Check_Object(this);
Check_Object(lancemate);
m_Lancemate = lancemate;
m_GunnerySkill = m_Lancemate->m_GunnerySkill;
m_PilotSkill = m_Lancemate->m_PilotSkill;
m_EliteSkill = m_Lancemate->m_EliteSkill;
m_MinHeatSkill = m_Lancemate->m_MinHeatSkill;
m_MaxHeatSkill = m_Lancemate->m_MaxHeatSkill;
m_SensorSkill = m_Lancemate->m_SensorSkill;
m_BlindFightingSkill = m_Lancemate->m_BlindFightingSkill;
m_LongRangeGunnerySkill = m_Lancemate->m_LongRangeGunnerySkill;
m_ShortRangeGunnerySkill = m_Lancemate->m_ShortRangeGunnerySkill;
m_TowardsPilotSkill = m_Lancemate->m_TowardsPilotSkill;
m_TowardsGunnerySkill = m_Lancemate->m_TowardsGunnerySkill;
m_TowardsEliteSkill = m_Lancemate->m_TowardsEliteSkill;
m_StartGunnerySkill = m_GunnerySkill;
m_StartPilotSkill = m_PilotSkill;
m_StartEliteSkill = m_EliteSkill;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void AI::DisconnectLancemate(void)
{
Check_Object(this);
if (!m_Lancemate)
{
return;
}
m_PilotSkill += (int) ((Stuff::Random::GetFraction () * 3) + 3);
if (m_PilotSkill > 100)
{
m_PilotSkill = 100;
}
m_Lancemate->m_GunnerySkill = m_GunnerySkill;
m_Lancemate->m_PilotSkill = m_PilotSkill;
m_Lancemate->m_EliteSkill = m_EliteSkill;
m_Lancemate->m_MinHeatSkill = m_MinHeatSkill;
m_Lancemate->m_MaxHeatSkill = m_MaxHeatSkill;
m_Lancemate->m_SensorSkill = m_SensorSkill;
m_Lancemate->m_BlindFightingSkill = m_BlindFightingSkill;
m_Lancemate->m_LongRangeGunnerySkill = m_LongRangeGunnerySkill;
m_Lancemate->m_ShortRangeGunnerySkill = m_ShortRangeGunnerySkill;
m_Lancemate->m_TowardsPilotSkill = m_TowardsPilotSkill;
m_Lancemate->m_TowardsGunnerySkill = m_TowardsGunnerySkill;
m_Lancemate->m_TowardsEliteSkill = m_TowardsEliteSkill;
m_Lancemate->m_StartGunnerySkill = m_StartGunnerySkill;
m_Lancemate->m_StartPilotSkill = m_StartPilotSkill;
m_Lancemate->m_StartEliteSkill = m_StartEliteSkill;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void AI::ConnectEntity(MWObject *p1)
{
Check_Object(this);
Check_Object(p1);
Verify ((!vehicle->IsDerivedFrom (Vehicle::DefaultData )) || (!vehicle->IsTileBound ()));
vehicle = p1;
p1->AttachAI (this);
if (GetGraveyard() != 0)
{
GetGraveyard()->NotifyCreated(vehicle->objectID);
}
}
void AI::PostCollisionExecute(Time till)
{
extern int g_nMR;
if (g_nMR == 2)
return;
AI_LOGIC("Post-Collision::AI");
Check_Object(this);
lastExecuted = till;
if (m_SelfDestructing)
{
Entity *ent;
m_SelfDestructing = false;
ent = getEntity ();
if (ent)
{
Vehicle *veh;
if (ent->IsDerivedFrom (Vehicle::DefaultData))
{
veh = Cast_Object (Vehicle *,ent);
veh->ProcessSelfDestruct ();
}
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void AI::TestInstance()
{
Verify(IsDerivedFrom(DefaultData));
}
void AI::Die (void)
{
if (m_Dead)
{
return;
}
if (m_AlwaysActive)
{
m_AlwaysActiveCount--;
}
if (aiBrain)
aiBrain->SwitchStates ("deadstate");
m_Dead = true;
if (m_Lancemate != 0)
{
if (m_Lancemate->ShouldEjectSafely() == true)
{
Eject ();
}
}
else
{
Stuff::Scalar normalized_chance_to_eject = UserConstants::Instance()->Get(UserConstants::eject_chance_for_non_lancemate) * 0.01f;
if (Stuff::Random::GetFraction() < normalized_chance_to_eject)
{
Eject ();
}
}
if ((getEntity() != 0) &&
(GetGraveyard() != 0))
{
GetGraveyard()->NotifyDeceased(getEntity()->objectID,m_ShotBy,m_LastTimeShot);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Command Support
//
void AI::ExecuteHighCommand (CommandEntry *command)
{
Verify (command);
switch (command->Type ())
{
case ENDMISSION_HIGHID:
break;
case EJECT_HIGHID:
break;
case SETPROP_HIGHID:
break;
default:
break;
}
}
void AI::ExecuteLowCommand (CommandEntry *command)
{
Verify (command);
}
void AI::ExecuteCommand (CommandEntry *command)
{
if (!command)
return;
if (command->HighLevel ())
ExecuteHighCommand (command);
else
ExecuteLowCommand (command);
delete command;
}
void AI::Info (void (*printCallback)(char* s))
{
char text[100];
sprintf (text,"Script name %s",scriptName);
printCallback (text);
if (m_Dead)
printCallback ("Dead");
else
printCallback ("Alive");
}
void AI::UpdateMood()
{
if (CurrentMood() == EntropyMood())
{
return;
}
if ((gos_GetElapsedTime() - m_LastMoodChange) < 2.0f)
{
return;
}
Verify(UserConstants::Instance() != 0);
Stuff::Scalar mood = CurrentMood();
const Stuff::Scalar min_mood_change_per_2_seconds = UserConstants::Instance()->Get(UserConstants::entropy_regeneration_at_0);
const Stuff::Scalar max_mood_change_per_2_seconds = UserConstants::Instance()->Get(UserConstants::entropy_regeneration_at_100);
const Stuff::Scalar mood_change_delta(max_mood_change_per_2_seconds - min_mood_change_per_2_seconds);
const Stuff::Scalar normalized_elite_skill(((Stuff::Scalar)EliteSkill()) * 0.01f);
const Stuff::Scalar mood_change(min_mood_change_per_2_seconds + (mood_change_delta * normalized_elite_skill));
if (EntropyMood() > CurrentMood())
{
mood += mood_change;
if (mood > EntropyMood())
{
mood = EntropyMood();
}
}
else
{
mood -= mood_change;
if (mood < EntropyMood())
{
mood = EntropyMood();
}
}
CurrentMood(mood);
}
bool AI::ReactToCollision(Stuff::DynamicArrayOf<CollisionData> *collisions,bool& shoulddamage)
{
for (int i=0; i<collisions->GetLength(); ++i)
{
CollisionData *data = &(*collisions)[i];
if ((getEntity() != 0) &&
(data->m_otherEntity != 0) &&
(getEntity() != data->m_otherEntity))
{
if ((getEntity()->GetAlignment() != data->m_otherEntity->GetAlignment()) &&
(getEntity()->IsDerivedFrom(Vehicle::DefaultData) == true) &&
(data->m_otherEntity->IsDerivedFrom(Vehicle::DefaultData) == true))
{
Vehicle* us = Cast_Object(Vehicle*,getEntity());
Vehicle* them = Cast_Object(Vehicle*,data->m_otherEntity);
if (them->currentSpeedMPS > us->currentSpeedMPS)
{
m_RammedBy = them->objectID;
m_LastTimeRammed = (Stuff::Scalar)gos_GetElapsedTime();
}
}
if ((data->m_otherEntity->IsDerivedFrom(MWObject::DefaultData) == true) &&
(getEntity()->IsDerivedFrom(MWObject::DefaultData) == true))
{
MWObject* mwobject = Cast_Object(MWObject*,data->m_otherEntity);
MWObject* me = Cast_Object(MWObject*,getEntity());
if (mwobject->IsPlayerVehicle() == false)
{
if (me->GetTargetDesirability() == MWObject::desirability_never)
{
shoulddamage = false; // "ignore" units can't be damaged by collisions with anyone but the player
}
else
{
if ((mwobject->GetAI() != 0) ||
(mwobject->GetAlignment() == me->GetAlignment()))
{
shoulddamage = false; // friendly AI units don't damage each other
}
}
}
}
}
}
return true;
}
Entity* AI::RammedBy(Stuff::Time lastvalid) const
{
if ((lastvalid >= m_LastTimeRammed) ||
(NameTable::GetInstance() == 0) ||
(m_RammedBy == 0xFFFFFFFF))
{
return(0);
}
Entity* rv = NameTable::GetInstance()->FindData(m_RammedBy);
if ((rv == 0) ||
(rv->IsDestroyed() == true))
{
return(0);
}
return(rv);
}
void AI::NotifyShot(ObjectID who, bool fCanBeRecursive)
{
Verify(NameTable::GetInstance() != 0);
if ((getEntity() != 0) &&
(getEntity()->IsDestroyed() == true))
{
return;
}
if (who == -1)
{
return;
}
Adept::Entity* entity = NameTable::GetInstance()->FindData(who);
if ((entity == 0) ||
(entity->IsDestroyed() == true))
{
return;
}
if (entity == getEntity())
{
return;
}
if ((getEntity() != 0) &&
(entity->GetAlignment() == getEntity()->GetAlignment()) &&
(GetIgnoringFriendlyFire() == true))
{
NotifyFriendlyFire(*entity);
return;
}
m_LastTimeShot = (Stuff::Scalar)gos_GetElapsedTime();
m_ShotBy = who;
}
void AI::NotifyShotFired(const Adept::Entity::CollisionQuery& query, MWObject& shooter)
{
if ((vehicle != 0) &&
(vehicle != &shooter) &&
(shooter.GetAlignment() != vehicle->GetAlignment()) &&
(LinePenetrates(*(query.m_line),(Stuff::Point3D)vehicle->GetLocalToWorld(),GetIsShotRadius()) == true))
{
NotifyShot(shooter.objectID);
/* TODO -- comment this back in ... currently commented out awaiting Jerry's re-implementation of flinching that looks good from the outside
if (GetSelf().IsDerivedFrom(Mech::DefaultData) == true)
{
Mech* mech = Cast_Object(Mech*,&GetSelf());
Stuff::Sphere sphere(at_who,GetIsShotRadius());
Stuff::Scalar penetration;
query.line->GetDistanceTo(sphere,&penetration);
if ((GetIsShotRadius() - penetration) < 20.0f)
{
Stuff::Point3D closest_point;
query.line->GetClosestPointTo((Stuff::Point3D)GetSelf().GetLocalToWorld(),&closest_point);
mech->FlinchFromPoint(closest_point,25,25,25);
}
}
*/
}
}
void AI::SetIgnoringFriendlyFire(bool fIgnoreFriendlyFire)
{
m_IgnoringFriendlyFire = fIgnoreFriendlyFire;
}
Stuff::Scalar AI::GetIsShotRadius() const
{
if (m_IsShotRadius < 0)
{
return(default_is_shot_radius);
}
return(m_IsShotRadius);
}
void AI::SetIsShotRadius(Stuff::Scalar radius)
{
Verify(radius >= 0);
m_IsShotRadius = radius;
}
void AI::NotifyHeatShutdownImminent()
{
if (m_Active == false)
{
return;
}
if ((getEntity() != 0) && (getEntity()->IsDerivedFrom(MechWarrior4::Mech::DefaultData) == true))
{
MechWarrior4::MWObject* mwobject = Cast_Object(MechWarrior4::MWObject*,getEntity());
if ((m_UsingCoolant == false) &&
(mwobject->m_heatManager != 0))
{
m_UsingCoolant = true;
mwobject->SetCooling(1);
}
}
}
Graveyard* AI::GetGraveyard()
{
return(m_Graveyard);
}
void AI::CreateGraveyard()
{
DestroyGraveyard();
m_Graveyard = new Graveyard;
}
void AI::DestroyGraveyard()
{
if (m_Graveyard != 0)
{
delete m_Graveyard;
m_Graveyard = 0;
}
}
bool AI::GetIgnoringFriendlyFire() const
{
return(m_IgnoringFriendlyFire);
}
void AI::StartExecute (void)
{
AlwayActive (true);
}
void AI::StopExecute (void)
{
AlwayActive (false);
}
void AI::Eject (void)
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void AI::AddStatsToString(std::string& s)
{
if (m_Active == false)
{
s += "INACTIVE";
return;
}
if (m_Deactive == true)
{
s += "DEACTIVE";
}
s += "ABL State: ";
if ((aiBrain != 0) &&
(aiBrain->GetCurState() != 0) &&
(aiBrain->GetCurState()->name != 0))
{
s += aiBrain->GetCurState()->name;
}
else
{
s += "n/a";
}
s += "\nMood: ";
int mood = (int)CurrentMood();
Auto_Ptr<Moods::Mood> m = Moods::CreateMood((Moods::ID)mood);
s += m->GetName();
s += " (";
s += ScalarToString(CurrentMood());
s += "/";
s += ScalarToString(EntropyMood());
s += ")\n";
if (Target() != 0)
{
s += "TARGET: ";
s += Target()->instanceName;
s += "\n";
}
else
{
s += "NO TARGET";
}
}
void AI::NotifyRespawned()
{
if (aiBrain != 0)
{
delete aiBrain;
aiBrain = NULL;
#ifdef LAB_ONLY
if (MechWarrior4::DebugHelper::Checked_DisableAI() == false)
{
#endif
// aiBrain = new ABL::ABLModule;
// aiBrain->init(aiScriptHandle);
#ifdef LAB_ONLY
}
#endif
}
m_ShotBy = 0xFFFFFFFF;
m_LastTimeShot = 0;
m_CurrentTarget.Remove();
m_EntropyMood = 5;
m_CurrentMood = 5;
m_LastMoodChange = 0;
m_FirstFrame = true;
m_SecondFrame = false;
m_Active = true;
m_DebugPrintCallback = NULL;
m_Debugging = false;
m_Dead = false;
aiScriptHandle = 0;
aiBrain = NULL;
m_IgnoringFriendlyFire = false;
m_ScriptRunning = true;
m_IsShotRadius = -1;
m_RammedBy = 0xFFFFFFFF;
m_LastTimeRammed = 0;
m_UsingCoolant = false;
m_Deactive = false;
m_Lancemate = NULL;
m_ExecutionNumber = 0;
m_StartupRequest = false;
m_ShutdownRequest = false;
m_SelfDestructing = false;
if (!vehicle)
m_Deactive = false;
m_AlwaysActive = false;
#ifdef LAB_ONLY
if (MechWarrior4::DebugHelper::Checked_DisableAI() == true)
{
UnloadScript ();
m_Active = false;
}
#endif
}
Stuff::Scalar AI::GetLeastSquaredSensorDistance(const Stuff::Point3D& point) const
{
return (GetLengthSquared((Stuff::Point3D)vehicle->GetLocalToWorld(),point));
}
bool AI::GetLeaderAlignment(int& alignment)
{
return (false);
}
void AI::Target(Adept::Entity* newtarget)
{
#ifdef _ARMOR
if (newtarget != 0)
{
Verify(newtarget != getEntity());
}
#endif
m_CurrentTarget.Remove();
if (newtarget) // null is a valid value for this pointer
{
Check_Pointer (newtarget);
if ((newtarget->IsDestroyed() == true) ||
(newtarget == getEntity()) ||
(newtarget->IsDerivedFrom(CameraShip::DefaultData) == true))
{
return;
}
m_CurrentTarget.Add(newtarget);
}
}
Stuff::MString AI::GetTalkerSuffix() const
{
if (GetLancemate() != 0)
{
return (GetLancemate()->m_TalkerSuffix);
}
if (getEntity() == 0)
{
return ("");
}
switch (getEntity()->objectID % 5)
{
case 0: return ("_DAM");
case 1: return ("_CAS");
case 2: return ("_JEN");
case 3: return ("_GON");
}
return ("_TER");
}