1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
|
// _____________________________________________________
//
// RAI - Skirmish AI for Spring
// Author: Reth / Michael Vadovszki
// _____________________________________________________
#ifndef RAI_IGLOBALAI_H
#define RAI_IGLOBALAI_H
#if _MSC_VER > 1000
#pragma once
#endif
struct UnitInfo;
struct EnemyInfo;
class cRAI;
#include "LegacyCpp/IGlobalAI.h"
using std::map;
#include "BasicArray.h"
#include "UnitDefHandler.h"
#include "BuilderPlacement.h"
#include "Builder.h"
#include "UnitManager.h"
#include "SWeaponManager.h"
#include "PowerManager.h"
#include "CombatManager.h"
using std::set;
const char AI_NAME[]="RAI v0.601";
const bool RAIDEBUGGING = false;
// These are for anything that can occur in Update() but not on a regular basis
struct UpdateEvent
{
int type; // (1=unit-time-out,2=unit-monitoring,3=initialize), also used as a ranking of importance
int frame; // when the event will trigger
int index;
int unitID;
UnitInfo* unitI;
float3* lastPosition; // only used by unit-monitoring
};
struct UnitInfo
{
UnitInfo(sRAIUnitDef* rUnitDef);
const UnitDef* ud; // Always valid
sRAIUnitDef* udr; // Always valid
sRAIUnitDefBL* udrBL; // Valid if AIDisabled=false
TerrainMapArea* area; // Not always valid, but definitely = 0 if a unit flies
sBuildQuarry* BuildQ; // Valid if building something, otherwise = 0
UnitInfoPower* CloakUI; // I can not rely on cb->IsUnitCloaked(unit), since I need to keep track of power variables.
UnitInfoPower* OnOffUI; // I can not rely on cb->IsUnitActivated(unit), same reason
sSWeaponUnitInfo* SWeaponUI; // Valid if the unit has a stock weapon, otherwise = 0
sRAIGroup* group;
EnemyInfo* E; // valid if 'enemyID' & 'Group' are set, otherwise this must be updated before used
sWeaponEfficiency* enemyEff;
UpdateEvent* UE;
bool AIDisabled;
bool humanCommand; // Set true if a unit receives an order through HandleEvent(), set false on UnitIdle()
bool unitBeingBuilt;// Work Around: for cb->UnitBeingBuilt(), which will not work if UnitDestroyed() fails to trigger immediately after a unit's death Spring-Version(v0.74b3)
bool inCombat;
int lastUnitIdleFrame; // Guard: Prevent UnitIdle from executing too many times in rapid succession
int lastUnitDamagedFrame; // Guard: Prevent UnitDamaged from executing too many times in rapid succession
// Buildings Only
ResourceSiteExt* RS; // Extractor/Geo, otherwise = 0
map<int,UnitInfo*> UGuards; // Hubs/Nanos guarding this unit
map<int,UnitInfo*> UGuarding; // Hubs/Nanos only, Units being guarded
// map<int,UnitInfo*> UAssist; // Hubs/Nanos only, Units it will assist with building
map<int,UnitInfo*> URepair; // Hubs/Nanos only, Units that are in need of repairs
map<int,UnitInfo*> UDefences; // Defences build near this unit
map<int,UnitInfo*> UDefending; // Defences Only, buildings near this unit
// map<int,ResourceSiteExt*> Resources; // Hubs only, the only resources this unit can build at
// old
// int commandTimeOut; // Work Around: for the currently broken command.timeout Spring-Version(v0.72b1)
int enemyID;
};
struct EnemyInfo
{
EnemyInfo();
bool inLOS;
bool inRadar;
int baseThreatFrame;// last frame it attacked one of our immobile units
int baseThreatID; // what unit of ours did it last attack
const UnitDef* ud; // valid if the enemy was in LOS at least once, otherwise = 0
sRAIUnitDef* udr; // same as above
ResourceSiteExt* RS; // Enemy Extractor/Geo, otherwise = 0
set<sRAIGroup*> attackGroups;
float3 position; // last known position, used if not in LOS or Radar
bool posLocked; // This unit does not move and its 'position' was saved while in LOS
};
using namespace std;
#include "GTerrainMap.h"
#include "GResourceMap.h"
// how often lists are updated by frame interval. NOTE: this is different from in-game graphics frames and will always be trigger 30x per second (assuming the game speed is 1.00)
#define FUPDATE_MINIMAL 90 // 3 seconds, the minimal time for an update. NOTE: excluding FUPDATE_UNITS, this value needs to be 'a factor' of the other FUPDATE values
#define FUPDATE_UNITS 900 // 60 seconds, unit is checked for idleness - should never happen, but it does.
#define FUPDATE_POWER 450 // 15 seconds, all units are checked for on/off or cloak/uncloak tasks
#define FUPDATE_BUILDLIST 1800 // 600 seconds, redetermines the available build options - half unnecessary since this is also called by events, hence the longer delay
#define EVENT_LIST_SIZE 10000
class cRAI : public IGlobalAI
{
public:
cRAI();
virtual ~cRAI();
void InitAI(IGlobalAICallback* callback, int team);
void UnitCreated(int unit, int builder); // called when a new unit is created on an ai team
void UnitFinished(int unit); // called when a unit has finished being build
void UnitDestroyed(int unit,int attacker); // called when a unit is destroyed
void EnemyEnterLOS(int enemy); // called when an enemy unit enters the "line of sight" of you or your ally
void EnemyLeaveLOS(int enemy); // called when an enemy unit exits the "line of sight" of you and your ally
void EnemyEnterRadar(int enemy); // called when an enemy unit enters the radar of you or your ally
void EnemyLeaveRadar(int enemy); // called when an enemy unit exits the radar of you and your ally
void EnemyDestroyed(int enemy,int attacker); // called if an enemy inside los or radar dies
void EnemyRemove(int enemy, EnemyInfo* E);
void EnemyDamaged(int damaged,int attacker,float damage,float3 dir); // called when an enemy inside los or radar is damaged
void UnitIdle(int unit); // called when a unit go idle and is not assigned to any group
void RecvChatMessage(const char* msg,int player) {}; // called when someone writes a chat msg
void RecvLuaMessage(const char* inData, const char** outData) {}
void UnitDamaged(int damaged,int attacker,float damage,float3 dir); // called when one of your units are damaged
void UnitMoveFailed(int unit);
int HandleEvent(int msg,const void* data);
void Update(); // called every frame
void UpdateEventAdd(const int &eventType, const int &eventFrame, int uID=0, UnitInfo* uI=0);
void CorrectPosition(float3& position);
TerrainMapArea* GetCurrentMapArea(sRAIUnitDef* udr, float3& position); // returns MapB index if >=0, -1 = any mb, -2 = error(unit can not exist at this position)
float3 GetRandomPosition(TerrainMapArea* area);
bool IsHumanControled(const int& unit,UnitInfo* U); // this function will crash if the 'unit' id is invalid
// used to check if the UnitDestroyed() event failed to trigger properly for units, Work Around: Spring-Version(v0.74b3-0.75b2)
bool ValidateUnit(const int& unitID); // returns true if the unitID exists in-game, unitID is assumed to have been valid up to this point
bool ValidateUnitList(map<int,UnitInfo*>* UL); // returns true if at least one unit on the list is valid
void ValidateAllUnits();
static bool LocateFile(IAICallback* cb, const string& relFileName, string& absFileName, bool forWriting);
/// Converts a string to one that can be used in a file name (eg. "Abc.123 $%^*" -> "Abc.123_____")
static std::string MakeFileSystemCompatible(const std::string& str);
map<int,UnitInfo> Units; // Complete record of all owned units, key value = unit id
map<int,UnitInfo*> UImmobile;
map<int,UnitInfo*> UMobile;
map<int,EnemyInfo> Enemies;
map<int,EnemyInfo*> EThreat; // These enemies have attacked our immobile units
cLogFile* l;
cBuilder* B;
cCombatManager* CM;
cRAIUnitDefHandler* UDH;
cUnitManager* UM;
GlobalResourceMap* RM; // = static RM
GlobalTerrainMap* TM; // = static TM
void DebugDrawLine(float3 StartPos, float distance, int direction, float xposoffset=0, float zposoffset=0, float yposoffset=50, int lifetime=9000, int arrow=0, float width=5.0, int group=1); // direction 0-3, counter-clock wise, 0=right
void DebugDrawShape(float3 CenterPos, float linelength, float width=5.0, int arrow=0, float yposoffset=50, int lifetime=9000, int sides=4, int group=1); // incomplete, sides is always 4
typedef pair<int,UnitInfo*> iupPair; // used to access UImmobile,UMobile, also used by different classes
typedef pair<int,EnemyInfo*> iepPair;
private:
std::string GetLogFileSubPath(int teamId) const;
void RemoveLogFile(string relFileName) const;
void UpdateEventRemove(UpdateEvent* e);
void UpdateEventReorderFirst();
UpdateEvent* eventList[EVENT_LIST_SIZE];
int eventSize;
int DebugEnemyEnterLOS;
int DebugEnemyLeaveLOS;
int DebugEnemyEnterRadar;
int DebugEnemyLeaveRadar;
int DebugEnemyDestroyedLOS;
int DebugEnemyDestroyedRadar;
int DebugEnemyEnterLOSError;
int DebugEnemyLeaveLOSError;
int DebugEnemyEnterRadarError;
int DebugEnemyLeaveRadarError;
int frame;
typedef pair<int,UnitInfo> iuPair; // used to access Units
typedef pair<int,EnemyInfo> iePair;
void ClearLogFiles();
IAICallback* cb;
cSWeaponManager* SWM;
};
#endif
|