//===========================================================================// // 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 //#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 #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::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;jnameTableArray [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;jnameTableArray [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 (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;iwrite (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> 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 (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 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 *collisions,bool& shoulddamage) { for (int i=0; iGetLength(); ++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 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"); }