//===========================================================================// // File: ai.hpp // //---------------------------------------------------------------------------// // Date Who Modification // // -------- --- ---------------------------------------------------------- // // 07/13/99 AHF Created File // //---------------------------------------------------------------------------// // Copyright (C) 1999, Microsoft // // All Rights reserved worldwide // // This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL // //===========================================================================// #pragma once #include "adept\Adept.hpp" #include "adept\Driver.hpp" #include "AI_Graveyard.hpp" namespace ElementRenderer { class GroupElement; }; namespace MechWarrior4 { class AI; class LancematePlug; }; #include "mwobject.hpp" #include "abl.h" class CCommandLineServer; namespace MW4AI { extern HGOSHEAP g_AIHeap,g_MoverAIHeap,g_CombatAIHeap,g_RailHeap; typedef void (* AIExecuteFunction) (AI *curunit,Stuff::Time till,NameTable *table); const int AIExecutionDelta = 4; // means once every fourth frame const int NUM_MEMORY_CELLS=60; const Stuff::Scalar MOODMIN = 1; // change the enums in MW4::AI_MOODS.HPP if you change this const Stuff::Scalar MOODMAX = 10; // change the enums in MW4::AI_MOODS.HPP if you change this const Stuff::Scalar SKILL_MULT = 100.0f; // mult for a normalized number to skill range enum { MAX_GLOBAL_TRIGGERS = 100 }; // maximum number of global triggers void ResetGlobalTriggers(); extern int g_AIExecutionNumber; void SetupAIStagger (void); const int SORT_DEPTH=4; #ifdef _ARMOR class CommandEntry : public Signature #else class CommandEntry #endif { friend class MechWarrior4::AI; protected: static Stuff::MemoryBlockOf *m_EmptyCommand; bool highlevel; int commandType; Stuff::Time startTime; int from; union { Stuff::Scalar dataScalar; int dataInt; void *dataPtr; }; Stuff::Point3D dataPoint; bool dataBoolean; public: CommandEntry (int type,bool high) { commandType = type; highlevel = high; } ~CommandEntry (void) {} bool HighLevel (void) const { return highlevel; } Stuff::Time StartTime (void) const { return startTime; } void StartTime (Stuff::Time time) { startTime = time; } int Type (void) const { return commandType; } void DataScalar (Stuff::Scalar value) { dataScalar = value; } Stuff::Scalar DataScalar (void) { return dataScalar; } void DataInt (int value) { dataInt = value; } int DataInt (void) const { return dataInt; } void DataBoolean (bool value) { dataBoolean = value; } bool DataBoolean (void) const { return dataBoolean; } void DataPtr (void *value) { dataPtr = value; } void *DataPtr (void) { return dataPtr; } void DataPoint3D (Stuff::Point3D value) { dataPoint = value; } Stuff::Point3D DataPoint3D (void) { return dataPoint; } void TestInstance() {} static CommandEntry *GetBlankCommand (void) { return (CommandEntry *) m_EmptyCommand->New (); } static void DoneCommand (CommandEntry *oldknow) { m_EmptyCommand->Delete (oldknow); } void *operator new (size_t size) {return GetBlankCommand (); } void operator delete (void *value,size_t size) { DoneCommand ((CommandEntry *) value); } }; #if 0 enum KNOWLEDGE_LEVEL {KNOW_LOCATION,KNOW_AFFILIATION,KNOW_CHASSIS,KNOW_TRUE}; enum THREAT_LEVEL {IMMEDIATE_THREAT,POTENTIAL_THREAT,WARNING_THREAT,OPPORTUNITY_THREAT,NON_THREAT}; #ifdef _ARMOR class AIKnowledge : public Signature #else class AIKnowledge #endif { friend class MechWarrior4::AI; private: static Stuff::MemoryBlockOf *m_EmptyKnowledge; protected: AI *unit; KNOWLEDGE_LEVEL knowledge; THREAT_LEVEL threat; unsigned int subthreat; float validCount; // decays over time AIKnowledge *next,*prev; AIKnowledge *sort_next,*sort_prev; public: AIKnowledge (void); ~AIKnowledge (void); static AIKnowledge *GetBlankKnowledge (void) { return (AIKnowledge *) m_EmptyKnowledge->New (); } static void DoneKnowledge (AIKnowledge *oldknow) { m_EmptyKnowledge->Delete (oldknow); } void *operator new (size_t size) {return GetBlankKnowledge (); } void operator delete (void *value,size_t size) { DoneKnowledge ((AIKnowledge *) value); } void TestInstance() {} }; #endif }; namespace MechWarrior4 { const int DEFAULT_MEMORYCELL_VALUES = 10; extern DWORD Executed_AI_Count; extern DWORD Path_Calcs_Count; extern DWORD GridPath_Calcs_Count; extern DWORD QuickPath_Calcs_Count; extern DWORD QuickRail_Calcs_Count; extern DWORD FailedPath_Calcs_Count; //########################################################################## //################## AIDriver::CreateMessage ######################### //########################################################################## class AI__CreateMessage:public Driver__CreateMessage { public: int entityID; char scriptName[128]; Stuff::Scalar cellValues[DEFAULT_MEMORYCELL_VALUES]; int gunnerySkill; int pilotSkill; int eliteSkill; int minHeatSkill; int maxHeatSkill; int sensorSkill; int blindFightingSkill; int longRangeGunnerySkill; int shortRangeGunnerySkill; int towardsGunnerySkill; int towardsPilotSkill; int towardsEliteSkill; // char scriptParams[2000]; AI__CreateMessage( size_t length, int priority, int message_flags, Stuff::RegisteredClass::ClassID class_id, int replicator_flags, const ResourceID& data_list_id, const Stuff::LinearMatrix4D &creation_matrix, Stuff::Scalar age, int execution_state, int name_id, int entity_alignment, int drop_zone, int entity_name_id, const char *script_name, Stuff::Scalar cell_values[DEFAULT_MEMORYCELL_VALUES], int gun, int pilot, int elite, int minheat, int maxheat, int sensor, int blind, int longrange, int shortrange, int tgun, int tpilot, int telite // / char* script_params ): Driver__CreateMessage( length, priority, message_flags, class_id, replicator_flags, data_list_id, creation_matrix, age, execution_state, name_id, entity_alignment, drop_zone ), entityID(entity_name_id) { Check_Pointer(script_name); Str_Copy(scriptName, script_name, sizeof(scriptName)); memcpy (cellValues,cell_values,sizeof (Stuff::Scalar)*DEFAULT_MEMORYCELL_VALUES); gunnerySkill = gun; pilotSkill = pilot; eliteSkill = elite; minHeatSkill = minheat; maxHeatSkill = maxheat; sensorSkill = sensor; blindFightingSkill = blind; longRangeGunnerySkill = longrange; shortRangeGunnerySkill = shortrange; towardsGunnerySkill = tgun; towardsPilotSkill = tpilot; towardsEliteSkill = telite; // strncpy(scriptParams,script_params,2000); } static void ConstructCreateMessage(Script *script); }; typedef Driver__ReceiveDropZoneMessage AI__ReceiveDropZoneMessage; //########################################################################## //########################### AI ###################################### //########################################################################## class AI: public Driver { friend class LancematePlug; friend void MW4AI::SetupAIStagger (void); public: static void InitializeClass(); static void TerminateClass(); static ClassData *DefaultData; static ElementRenderer::GroupElement *m_GroupElement; static int m_BoardGameMechAI,m_LastBoardGameMechAI; static int m_BoardGameVehicleAI,m_LastBoardGameVehicleAI; static int m_ActiveMechAI,m_LastActiveMechAI; static int m_ActiveVehicleAI,m_LastActiveVehicleAI; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Inheritance Support // public: typedef AI__CreateMessage CreateMessage; typedef AI__ReceiveDropZoneMessage DropZoneMessage; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Run-time Construction and Destruction Support // public: static AI* Make(CreateMessage *message,ReplicatorID *base_id); Replicator::CreateMessage* SaveMakeMessage(Stuff::MemoryStream *stream, Adept::ResourceFile *res_file); virtual void Save (MemoryStream *stream); virtual void Load (MemoryStream *stream); void Respawn(Entity::CreateMessage *message); protected: AI(ClassData *class_data,CreateMessage *message,ReplicatorID *base_id,ElementRenderer::Element *element); ~AI(); public: bool LoadScript (char *filename); void UnloadScript (void); bool ReloadScript (ABL::ABLError *err); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Command Support // protected: virtual void ExecuteHighCommand (MW4AI::CommandEntry *command); virtual void ExecuteLowCommand (MW4AI::CommandEntry *command); MW4AI::CommandEntry *CreateAdjustRatioCommand (Stuff::Time start=gos_GetElapsedTime ()) { return CreateBaseCommand (ADJUSTRATIO_LOWID,false,start); } public: enum { ENDMISSION_HIGHID, EJECT_HIGHID, SETPROP_HIGHID, NextHighCommandID }; enum { ADJUSTRATIO_LOWID, NextLowCommandID }; virtual void PostCollisionExecute(Time till); MW4AI::CommandEntry *CreateBaseCommand (int type,bool high,Stuff::Time start=gos_GetElapsedTime ()) { MW4AI::CommandEntry *toret; toret = new MW4AI::CommandEntry (type,high); Check_Object (toret); toret->StartTime (start); return toret; } MW4AI::CommandEntry *CreateEndMissionCommand (Stuff::Time start=gos_GetElapsedTime ()) { return CreateBaseCommand (ENDMISSION_HIGHID,true,start); } MW4AI::CommandEntry *CreateEjectCommand (Stuff::Time start=gos_GetElapsedTime ()) { return CreateBaseCommand (EJECT_HIGHID,true,start); } MW4AI::CommandEntry *CreateSetPropCommand (Stuff::Time start=gos_GetElapsedTime ()) { return CreateBaseCommand (SETPROP_HIGHID,true,start); } void ExecuteCommand (MW4AI::CommandEntry *command); Entity *getEntity (void) const { return vehicle; } virtual void EnsureNotTargeting(Adept::ObjectID object) {}; void SelfDestruct (void); bool m_SelfDestructing; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Skill Support // protected: int m_GunnerySkill; int m_PilotSkill; int m_EliteSkill; int m_MinHeatSkill; int m_MaxHeatSkill; int m_SensorSkill; int m_BlindFightingSkill; int m_LongRangeGunnerySkill; int m_ShortRangeGunnerySkill; int m_TowardsPilotSkill; int m_TowardsGunnerySkill; int m_TowardsEliteSkill; int m_StartGunnerySkill; int m_StartPilotSkill; int m_StartEliteSkill; public: int RootGunnerySkill (void) const { return m_GunnerySkill; } int RootPilotSkill (void) const { return m_PilotSkill; } int RootSensorSkill (void) const { return m_SensorSkill; } int RootBlindFightingSkill (void) const { return m_BlindFightingSkill; } int RootLongRangeGunnerySkill (void) const { return m_LongRangeGunnerySkill; } int RootShortRangeGunnerySkill (void) const { return m_ShortRangeGunnerySkill; } int RootEliteSkill (void) const { return m_EliteSkill; } int RootMinHeatSkill (void) const { return m_MinHeatSkill; } int RootMaxHeatSkill (void) const { return m_MaxHeatSkill; } int GunnerySkill (void) const; int PilotSkill (void) const; int SensorSkill (void) const; int BlindFightingSkill (void) const; int LongRangeGunnerySkill (void) const; int ShortRangeGunnerySkill (void) const; int EliteSkill (void) const; int MinHeatSkill (void) const; int MaxHeatSkill (void) const; void GunnerySkill (int newvalue) { m_GunnerySkill = newvalue; m_StartGunnerySkill = newvalue; } virtual void AddTowardGunnery (int value=-1); // -1 means default add value void PilotSkill (int newvalue) { m_PilotSkill = newvalue; m_StartPilotSkill = newvalue; } virtual bool PilotSkillCheck (Stuff::Scalar damage_amount,bool jump); // negative damage_amount means ignore damage for possible check virtual void AddTowardPilot (int value = -1); // -1 means default add value void SensorSkill (int newvalue) { m_SensorSkill = newvalue; } void BlindFightingSkill (int newvalue) { m_BlindFightingSkill = newvalue; } void LongRangeGunnerySkill (int newvalue) { m_LongRangeGunnerySkill = newvalue; } void ShortRangeGunnerySkill (int newvalue) { m_ShortRangeGunnerySkill = newvalue; } void EliteSkill (int newvalue) { m_EliteSkill = newvalue; m_StartEliteSkill = newvalue; } virtual void AddTowardElite (int value=-1); // -1 means default add value void MinHeatSkill (int newvalue) { m_MinHeatSkill = newvalue; } void MaxHeatSkill (int newvalue) { m_MaxHeatSkill = newvalue; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Mood Support // protected: Stuff::Scalar m_EntropyMood; Stuff::Scalar m_CurrentMood; Stuff::Scalar m_LastMoodChange; bool m_UsingCoolant; public: Stuff::Scalar EntropyMood () const { return m_EntropyMood; } Stuff::Scalar CurrentMood () const { return m_CurrentMood; } void EntropyMood (Stuff::Scalar newvalue) { Verify (newvalue>=MW4AI::MOODMIN); Verify (newvalue<=MW4AI::MOODMAX); m_EntropyMood = newvalue; } void CurrentMood (Stuff::Scalar newvalue) { Verify (newvalue>=MW4AI::MOODMIN); Verify (newvalue<=MW4AI::MOODMAX); m_CurrentMood = newvalue; m_LastMoodChange = (Stuff::Scalar)gos_GetElapsedTime (); } void UpdateMood(); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Combat Support // protected: Stuff::SlotOf m_CurrentTarget; bool m_IgnoringFriendlyFire; ObjectID m_ShotBy; Stuff::Scalar m_LastTimeShot; ObjectID m_RammedBy; Stuff::Scalar m_LastTimeRammed; public: Entity *Target (void) { return m_CurrentTarget.GetCurrent(); } void Target (Entity *newtarget); void SetIgnoringFriendlyFire(bool fIgnoreFriendlyFire); protected: virtual bool GetIgnoringFriendlyFire() const; public: Entity* ShotBy(Stuff::Time lastvalid) const { if (lastvalid < m_LastTimeShot) { if ((NameTable::GetInstance() == 0) || (m_ShotBy == 0xFFFFFFFF)) { return (0); } Entity* rv = NameTable::GetInstance()->FindData(m_ShotBy); if ((rv == 0) || (rv->IsDestroyed() == true) || (rv == getEntity())) { return (0); } if ((getEntity() != 0) && (rv->GetAlignment() == getEntity()->GetAlignment()) && (GetIgnoringFriendlyFire() == true)) { return (0); } return (rv); } return (0); } virtual bool GetLeaderAlignment(int& alignment); Entity* RammedBy(Stuff::Time lastvalid) const; virtual void NotifyShot(ObjectID who, bool fCanBeRecursive = true); virtual void NotifyShotFired(const Adept::Entity::CollisionQuery& query, MWObject& shooter); virtual void NotifyProjectileApproaching(const Stuff::Point3D& origin) {}; virtual void NotifyLastShotWasFriendlyFire(Adept::Entity& who_i_hit) {}; virtual void NotifyInternalHit() {}; virtual void NotifyComponentDestroyed(int zone) {}; virtual void NotifyShutdown() {}; virtual void NotifyAlignmentChanged() {}; virtual void NotifyInTargetingReticule(MWObject& who) {}; virtual void NotifyHeatShutdownImminent(); virtual void NotifyFailedPilotingRoll() {}; virtual void NotifyFriendlyFire(Adept::Entity& who_shot_me) {}; virtual void NotifyRespawned(); virtual bool Attacking() const { return (false); } virtual bool ReactToCollision(Stuff::DynamicArrayOf *collisions,bool& shoulddamage); Stuff::Scalar GetIsShotRadius() const; void SetIsShotRadius(Stuff::Scalar radius); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Execution Support // protected: int GetTableArray() {Check_Object(this); return NameTable::AIArray;} enum { Sensor_Area, Knowledge_Area, Communication_Area, NextAIAreaID }; Stuff::Scalar memory[MW4AI::NUM_MEMORY_CELLS]; std::string scriptName; long aiScriptHandle; ABL::ABLModulePtr aiBrain; void *aiDLLBrain; MW4AI::AIExecuteFunction aiDLLExecute; bool m_FirstFrame; bool m_SecondFrame; bool m_Active; // from shutdown and startup commands void (*m_DebugPrintCallback)(char* s); bool m_Debugging; bool m_Dead; bool m_ScriptRunning; int m_ExecutionNumber; bool m_AlwaysActive; // true if the this ai should always be active static int m_AlwaysActiveCount; Stuff::Scalar m_IsShotRadius; static MW4AI::Graveyard* m_Graveyard; bool m_StartupRequest; bool m_ShutdownRequest; static bool m_GlobalTriggers[MW4AI::MAX_GLOBAL_TRIGGERS]; public: bool m_Deactive; // from distance to player bool m_TurningOn; // true when the vehicle is being told to activate virtual void TurnOn (void); virtual void TurnOff (void); bool TurningOn (void) { return m_TurningOn; } static MW4AI::Graveyard* GetGraveyard(); static void CreateGraveyard(); static void DestroyGraveyard(); virtual bool ShouldRunScript() { return (true); } virtual void Shutdown (void); virtual void Startup (void); bool ShouldRun (bool execnumonly=false) const; void ExecutionNumber (int num) { m_ExecutionNumber = num; } void AlwayActive (bool p1); const char* GetScriptName() { return (scriptName.c_str()); } ABL::ABLModulePtr Brain (void) { return aiBrain; } void StopScript (void) { m_ScriptRunning = false; } void StartScript (void) { m_ScriptRunning = true; } void Debug (bool flag,void (*printCallback)(char* s)) { m_Debugging = flag; m_DebugPrintCallback = printCallback; } #ifdef LAB_ONLY void DebugMessage (char *s) { if (m_DebugPrintCallback) m_DebugPrintCallback (s); } #else void DebugMessage (char *s) { } #endif virtual void Info (void (*printCallback)(char* s)); void PreCollisionExecute(Stuff::Time till); void DetermineExecution(Stuff::Time till); virtual void StartExecute (void); virtual void StopExecute (void); virtual void Die (void); virtual void Eject (void); bool Dead (void) const { return m_Dead; } bool CanAct() const { if ((m_Active == true) && (m_Dead == false)) { return (true); } return (false); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Memory Support // public: void IntegerMemory (long index, long val) { Verify (index >=0); Verify (index =0); Verify (index =0); Verify (index =0); Verify (index = 0); Verify(index < MW4AI::MAX_GLOBAL_TRIGGERS); return (m_GlobalTriggers[index]); } static void SetGlobalTrigger(int index, bool value) { Verify(index >= 0); Verify(index < MW4AI::MAX_GLOBAL_TRIGGERS); m_GlobalTriggers[index] = value; } virtual void AddStatsToString(std::string& s); virtual bool GetExtendedSensorData(std::vector& sensor_data_list) { return (false); } virtual Stuff::Scalar GetLeastSquaredSensorDistance(const Stuff::Point3D& point) const; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Lancemate Support // protected: LancematePlug *m_Lancemate; public: void ConnectLancemate(LancematePlug *lancemate); void DisconnectLancemate(void); LancematePlug *GetLancemate (void) const { return m_Lancemate; } Stuff::MString GetTalkerSuffix() const; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Misc Support // public: void ConnectEntity(MWObject *entity); ResourceID interfaceResourceID; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // File Support // void SaveInstanceText(Stuff::Page *page); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Test Support // public: void TestInstance(); }; } #if 1 #define AI_LOGIC(string) PRECOLLISION_LOGIC("AI::" string) #else #define AI_LOGIC(string) #endif #if 1 #define MOVER_LOGIC(string) AI_LOGIC("Mover::" string) #else #define MOVER_LOGIC(string) #endif #if 1 #define COMBAT_LOGIC(string) AI_LOGIC("Combat::" string) #else #define COMBAT_LOGIC(string) #endif #if 1 #define ABL_LOGIC(string) AI_LOGIC("ABL::" string) #else #define ABL_LOGIC(string) #endif #if 1 #define PATH_LOGIC(string) AI_LOGIC("Path::" string) #else #define PATH_LOGIC(string) #endif