2012-02-14 21:04:45 +03:00
# pragma once
2012-09-06 13:39:48 +03:00
# include "../../lib/AI_Base.h"
# include "../../CCallback.h"
# include "../../lib/CObjectHandler.h"
# include "../../lib/CThreadHelper.h"
# include "../../lib/VCMI_Lib.h"
# include "../../lib/CBuildingHandler.h"
# include "../../lib/CCreatureHandler.h"
# include "../../lib/CTownHandler.h"
# include "../../lib/CSpellHandler.h"
# include "../../lib/CObjectHandler.h"
# include "../../lib/Connection.h"
# include "../../lib/CGameState.h"
# include "../../lib/map.h"
# include "../../lib/NetPacks.h"
# include "../../lib/CondSh.h"
# include "../../lib/CStopWatch.h"
struct QuestInfo ;
2012-02-14 21:04:45 +03:00
typedef const int3 & crint3 ;
typedef const std : : string & crstring ;
2012-07-01 02:48:40 +03:00
//provisional class for AI to store a reference to an owned hero object
//checks if it's valid on access, should be used in place of const CGHeroInstance*
struct HeroPtr
{
const CGHeroInstance * h ;
int hid ; //hero id (object subID or type ID)
public :
std : : string name ;
HeroPtr ( ) ;
HeroPtr ( const CGHeroInstance * H ) ;
~ HeroPtr ( ) ;
operator bool ( ) const
{
return validAndSet ( ) ;
}
bool operator < ( const HeroPtr & rhs ) const ;
const CGHeroInstance * operator - > ( ) const ;
const CGHeroInstance * operator * ( ) const ; //not that consistent with -> but all interfaces use CGHeroInstance*, so it's convenient
const CGHeroInstance * get ( bool doWeExpectNull = false ) const ;
bool validAndSet ( ) const ;
} ;
2012-02-14 21:04:45 +03:00
enum BattleState
{
NO_BATTLE ,
UPCOMING_BATTLE ,
ONGOING_BATTLE ,
ENDING_BATTLE
} ;
class AIStatus
{
boost : : mutex mx ;
boost : : condition_variable cv ;
BattleState battle ;
2012-07-15 18:34:00 +03:00
std : : map < int , std : : string > remainingQueries ;
std : : map < int , int > requestToQueryID ; //IDs of answer-requests sent to server => query ids (so we can match answer confirmation from server to the query)
2012-02-14 21:04:45 +03:00
bool havingTurn ;
public :
AIStatus ( ) ;
~ AIStatus ( ) ;
void setBattle ( BattleState BS ) ;
BattleState getBattle ( ) ;
2012-07-15 18:34:00 +03:00
void addQuery ( int ID , std : : string description ) ;
void removeQuery ( int ID ) ;
2012-02-14 21:04:45 +03:00
int getQueriesCount ( ) ;
void startedTurn ( ) ;
void madeTurn ( ) ;
void waitTillFree ( ) ;
bool haveTurn ( ) ;
2012-07-15 18:34:00 +03:00
void attemptedAnsweringQuery ( int queryID , int answerRequestID ) ;
void receivedAnswerConfirmation ( int answerRequestID , int result ) ;
2012-02-14 21:04:45 +03:00
} ;
enum EGoals
{
INVALID = - 1 ,
2012-04-16 20:12:39 +03:00
WIN , DO_NOT_LOSE , CONQUER , BUILD , //build needs to get a real reasoning
EXPLORE , GATHER_ARMY , BOOST_HERO ,
2012-02-16 20:10:58 +03:00
RECRUIT_HERO ,
2012-02-14 21:04:45 +03:00
BUILD_STRUCTURE , //if hero set, then in visited town
COLLECT_RES ,
2012-07-21 10:15:53 +03:00
GATHER_TROOPS , // val of creatures with objid
2012-02-14 21:04:45 +03:00
OBJECT_GOALS_BEGIN ,
GET_OBJ , //visit or defeat or collect the object
2012-07-18 13:10:14 +03:00
FIND_OBJ , //find and visit any obj with objid + resid //TODO: consider universal subid for various types (aid, bid)
2012-08-28 18:04:05 +03:00
VISIT_HERO , //heroes can move around - set goal abstract and track hero every turn
2012-02-16 20:10:58 +03:00
2012-02-14 21:04:45 +03:00
GET_ART_TYPE ,
//BUILD_STRUCTURE,
ISSUE_COMMAND ,
VISIT_TILE , //tile, in conjunction with hero elementar; assumes tile is reachable
2012-02-16 20:10:58 +03:00
CLEAR_WAY_TO ,
2012-02-14 21:04:45 +03:00
DIG_AT_TILE //elementar with hero on tile
} ;
struct CGoal ;
typedef CGoal TSubgoal ;
# define SETTER(type, field) CGoal &set ## field(const type &rhs) { field = rhs; return *this; }
#if 0
# define SETTER
# endif // _DEBUG
enum { LOW_PR = - 1 } ;
struct CGoal
{
EGoals goalType ;
bool isElementar ; SETTER ( bool , isElementar )
2012-05-08 11:10:40 +03:00
bool isAbstract ; SETTER ( bool , isAbstract ) //allows to remember abstract goals
2012-02-14 21:04:45 +03:00
int priority ; SETTER ( bool , priority )
virtual TSubgoal whatToDoToAchieve ( ) ;
2012-02-16 20:10:58 +03:00
CGoal ( EGoals goal = INVALID ) : goalType ( goal )
2012-02-14 21:04:45 +03:00
{
priority = 0 ;
isElementar = false ;
2012-05-08 11:10:40 +03:00
isAbstract = false ;
2012-07-18 13:10:14 +03:00
value = 0 ;
2012-02-14 21:04:45 +03:00
objid = - 1 ;
aid = - 1 ;
2012-07-18 13:10:14 +03:00
resID = - 1 ;
2012-02-14 21:04:45 +03:00
tile = int3 ( - 1 , - 1 , - 1 ) ;
town = NULL ;
}
bool invalid ( ) const ;
static TSubgoal goVisitOrLookFor ( const CGObjectInstance * obj ) ; //if obj is NULL, then we'll explore
static TSubgoal lookForArtSmart ( int aid ) ; //checks non-standard ways of obtaining art (merchants, quests, etc.)
2012-05-07 15:54:22 +03:00
static TSubgoal tryRecruitHero ( ) ;
2012-02-14 21:04:45 +03:00
int value ; SETTER ( int , value )
int resID ; SETTER ( int , resID )
int objid ; SETTER ( int , objid )
int aid ; SETTER ( int , aid )
int3 tile ; SETTER ( int3 , tile )
2012-07-01 02:48:40 +03:00
HeroPtr hero ; SETTER ( HeroPtr , hero )
2012-02-16 20:10:58 +03:00
const CGTownInstance * town ; SETTER ( CGTownInstance * , town )
2012-02-14 21:04:45 +03:00
int bid ; SETTER ( int , bid )
} ;
enum { NOT_VISIBLE = 0 , NOT_CHECKED = 1 , NOT_AVAILABLE } ;
struct SectorMap
{
//a sector is set of tiles that would be mutually reachable if all visitable objs would be passable (incl monsters)
struct Sector
{
int id ;
std : : vector < int3 > tiles ;
std : : vector < int3 > embarkmentPoints ; //tiles of other sectors onto which we can (dis)embark
bool water ; //all tiles of sector are land or water
2012-02-16 20:10:58 +03:00
Sector ( )
{
2012-02-14 21:04:45 +03:00
id = - 1 ;
}
} ;
bool valid ; //some kind of lazy eval
std : : map < int3 , int3 > parent ;
2012-02-16 20:10:58 +03:00
std : : vector < std : : vector < std : : vector < unsigned char > > > sector ;
//std::vector<std::vector<std::vector<unsigned char>>> pathfinderSector;
2012-02-14 21:04:45 +03:00
std : : map < int , Sector > infoOnSectors ;
SectorMap ( ) ;
void update ( ) ;
void clear ( ) ;
void exploreNewSector ( crint3 pos , int num ) ;
void write ( crstring fname ) ;
unsigned char & retreiveTile ( crint3 pos ) ;
void makeParentBFS ( crint3 source ) ;
2012-07-01 02:48:40 +03:00
int3 firstTileToGet ( HeroPtr h , crint3 dst ) ; //if h wants to reach tile dst, which tile he should visit to clear the way?
2012-02-14 21:04:45 +03:00
} ;
struct CIssueCommand : CGoal
{
boost : : function < bool ( ) > command ;
2012-02-16 20:10:58 +03:00
CIssueCommand ( boost : : function < bool ( ) > _command ) : CGoal ( ISSUE_COMMAND ) , command ( _command ) { }
2012-02-14 21:04:45 +03:00
} ;
2012-04-17 15:46:21 +03:00
// AI lives in a dangerous world. CGObjectInstances under pointer may got deleted/hidden.
// This class stores object id, so we can detect when we lose access to the underlying object.
struct ObjectIdRef
{
int id ;
const CGObjectInstance * operator - > ( ) const ;
operator const CGObjectInstance * ( ) const ;
ObjectIdRef ( int _id ) ;
ObjectIdRef ( const CGObjectInstance * obj ) ;
bool operator < ( const ObjectIdRef & rhs ) const ;
} ;
class ObjsVector : public std : : vector < ObjectIdRef >
{
private :
} ;
2012-02-14 21:04:45 +03:00
class VCAI : public CAdventureAI
{
2012-05-19 19:22:34 +03:00
//internal methods for town development
//try build an unbuilt structure in maxDays at most (0 = indefinite)
bool tryBuildStructure ( const CGTownInstance * t , int building , unsigned int maxDays = 0 ) ;
//try build ANY unbuilt structure
bool tryBuildAnyStructure ( const CGTownInstance * t , std : : vector < int > buildList , unsigned int maxDays = 0 ) ;
//try build first unbuilt structure
bool tryBuildNextStructure ( const CGTownInstance * t , std : : vector < int > buildList , unsigned int maxDays = 0 ) ;
2012-02-14 21:04:45 +03:00
public :
2012-03-03 13:08:01 +03:00
friend class FuzzyHelper ;
2012-02-14 21:04:45 +03:00
std : : map < const CGObjectInstance * , const CGObjectInstance * > knownSubterraneanGates ;
std : : vector < const CGObjectInstance * > visitedThisWeek ; //only OPWs
2012-07-01 02:48:40 +03:00
std : : map < HeroPtr , std : : vector < const CGTownInstance * > > townVisitsThisWeek ;
2012-02-14 21:04:45 +03:00
2012-07-01 02:48:40 +03:00
std : : map < HeroPtr , CGoal > lockedHeroes ; //TODO: allow non-elementar objectives
std : : map < HeroPtr , std : : vector < const CGObjectInstance * > > reservedHeroesMap ; //objects reserved by specific heroes
2012-02-14 21:04:45 +03:00
std : : vector < const CGObjectInstance * > visitableObjs ;
std : : vector < const CGObjectInstance * > alreadyVisited ;
2012-03-29 21:26:06 +03:00
std : : vector < const CGObjectInstance * > reservedObjs ; //to be visited by specific hero
2012-02-14 21:04:45 +03:00
TResources saving ;
AIStatus status ;
std : : string battlename ;
CCallback * myCb ;
VCAI ( void ) ;
~ VCAI ( void ) ;
2012-03-05 22:11:28 +03:00
CGObjectInstance * visitedObject ; //remember currently viisted object
2012-02-14 21:04:45 +03:00
boost : : thread * makingTurn ;
void tryRealize ( CGoal g ) ;
2012-07-01 02:48:40 +03:00
int3 explorationBestNeighbour ( int3 hpos , int radius , HeroPtr h ) ;
int3 explorationNewPoint ( int radius , HeroPtr h , std : : vector < std : : vector < int3 > > & tiles ) ;
2012-02-14 21:04:45 +03:00
void recruitHero ( ) ;
2012-09-29 13:59:43 +03:00
virtual std : : string getBattleAIName ( ) const OVERRIDE ;
virtual void init ( CCallback * CB ) OVERRIDE ;
virtual void yourTurn ( ) OVERRIDE ;
2012-07-15 18:34:00 +03:00
virtual void heroGotLevel ( const CGHeroInstance * hero , int pskill , std : : vector < ui16 > & skills , int queryID ) OVERRIDE ; //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id
virtual void commanderGotLevel ( const CCommanderInstance * commander , std : : vector < ui32 > skills , int queryID ) OVERRIDE ; //TODO
2012-02-14 21:04:45 +03:00
virtual void showBlockingDialog ( const std : : string & text , const std : : vector < Component > & components , ui32 askID , const int soundID , bool selection , bool cancel ) OVERRIDE ; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
2012-07-15 18:34:00 +03:00
virtual void showGarrisonDialog ( const CArmedInstance * up , const CGHeroInstance * down , bool removableUnits , int queryID ) OVERRIDE ; //all stacks operations between these objects become allowed, interface has to call onEnd when done
2012-02-14 21:04:45 +03:00
virtual void serialize ( COSer < CSaveFile > & h , const int version ) OVERRIDE ; //saving
virtual void serialize ( CISer < CLoadFile > & h , const int version ) OVERRIDE ; //loading
2012-02-22 16:41:27 +03:00
virtual void finish ( ) OVERRIDE ;
2012-02-14 21:04:45 +03:00
virtual void availableCreaturesChanged ( const CGDwelling * town ) OVERRIDE ;
virtual void heroMoved ( const TryMoveHero & details ) OVERRIDE ;
virtual void stackChagedCount ( const StackLocation & location , const TQuantity & change , bool isAbsolute ) OVERRIDE ;
virtual void heroInGarrisonChange ( const CGTownInstance * town ) OVERRIDE ;
virtual void centerView ( int3 pos , int focusTime ) OVERRIDE ;
virtual void tileHidden ( const boost : : unordered_set < int3 , ShashInt3 > & pos ) OVERRIDE ;
virtual void artifactMoved ( const ArtifactLocation & src , const ArtifactLocation & dst ) OVERRIDE ;
virtual void artifactAssembled ( const ArtifactLocation & al ) OVERRIDE ;
virtual void showTavernWindow ( const CGObjectInstance * townOrTavern ) OVERRIDE ;
2012-03-07 17:05:54 +03:00
virtual void showThievesGuildWindow ( const CGObjectInstance * obj ) OVERRIDE ;
2012-02-14 21:04:45 +03:00
virtual void playerBlocked ( int reason ) OVERRIDE ;
virtual void showPuzzleMap ( ) OVERRIDE ;
virtual void showShipyardDialog ( const IShipyard * obj ) OVERRIDE ;
virtual void gameOver ( ui8 player , bool victory ) OVERRIDE ;
virtual void artifactPut ( const ArtifactLocation & al ) OVERRIDE ;
virtual void artifactRemoved ( const ArtifactLocation & al ) OVERRIDE ;
virtual void stacksErased ( const StackLocation & location ) OVERRIDE ;
virtual void artifactDisassembled ( const ArtifactLocation & al ) OVERRIDE ;
virtual void heroVisit ( const CGHeroInstance * visitor , const CGObjectInstance * visitedObj , bool start ) OVERRIDE ;
virtual void availableArtifactsChanged ( const CGBlackMarket * bm = NULL ) OVERRIDE ;
virtual void heroVisitsTown ( const CGHeroInstance * hero , const CGTownInstance * town ) OVERRIDE ;
virtual void tileRevealed ( const boost : : unordered_set < int3 , ShashInt3 > & pos ) OVERRIDE ;
virtual void heroExchangeStarted ( si32 hero1 , si32 hero2 ) OVERRIDE ;
virtual void heroPrimarySkillChanged ( const CGHeroInstance * hero , int which , si64 val ) OVERRIDE ;
virtual void showRecruitmentDialog ( const CGDwelling * dwelling , const CArmedInstance * dst , int level ) OVERRIDE ;
virtual void heroMovePointsChanged ( const CGHeroInstance * hero ) OVERRIDE ;
virtual void stackChangedType ( const StackLocation & location , const CCreature & newType ) OVERRIDE ;
virtual void stacksRebalanced ( const StackLocation & src , const StackLocation & dst , TQuantity count ) OVERRIDE ;
virtual void newObject ( const CGObjectInstance * obj ) OVERRIDE ;
virtual void showHillFortWindow ( const CGObjectInstance * object , const CGHeroInstance * visitor ) OVERRIDE ;
virtual void playerBonusChanged ( const Bonus & bonus , bool gain ) OVERRIDE ;
virtual void newStackInserted ( const StackLocation & location , const CStackInstance & stack ) OVERRIDE ;
virtual void heroCreated ( const CGHeroInstance * ) OVERRIDE ;
virtual void advmapSpellCast ( const CGHeroInstance * caster , int spellID ) OVERRIDE ;
virtual void showInfoDialog ( const std : : string & text , const std : : vector < Component * > & components , int soundID ) OVERRIDE ;
virtual void requestRealized ( PackageApplied * pa ) OVERRIDE ;
virtual void receivedResource ( int type , int val ) OVERRIDE ;
virtual void stacksSwapped ( const StackLocation & loc1 , const StackLocation & loc2 ) OVERRIDE ;
virtual void objectRemoved ( const CGObjectInstance * obj ) OVERRIDE ;
virtual void showUniversityWindow ( const IMarket * market , const CGHeroInstance * visitor ) OVERRIDE ;
virtual void heroManaPointsChanged ( const CGHeroInstance * hero ) OVERRIDE ;
virtual void heroSecondarySkillChanged ( const CGHeroInstance * hero , int which , int val ) OVERRIDE ;
virtual void battleResultsApplied ( ) OVERRIDE ;
virtual void objectPropertyChanged ( const SetObjectProperty * sop ) OVERRIDE ;
virtual void buildChanged ( const CGTownInstance * town , int buildingID , int what ) OVERRIDE ;
virtual void heroBonusChanged ( const CGHeroInstance * hero , const Bonus & bonus , bool gain ) OVERRIDE ;
virtual void showMarketWindow ( const IMarket * market , const CGHeroInstance * visitor ) OVERRIDE ;
virtual void battleStart ( const CCreatureSet * army1 , const CCreatureSet * army2 , int3 tile , const CGHeroInstance * hero1 , const CGHeroInstance * hero2 , bool side ) OVERRIDE ;
virtual void battleEnd ( const BattleResult * br ) OVERRIDE ;
void makeTurn ( ) ;
void makeTurnInternal ( ) ;
void performTypicalActions ( ) ;
void buildArmyIn ( const CGTownInstance * t ) ;
void striveToGoal ( const CGoal & ultimateGoal ) ;
void endTurn ( ) ;
2012-07-01 02:48:40 +03:00
void wander ( HeroPtr h ) ;
void setGoal ( HeroPtr h , const CGoal goal ) ;
void setGoal ( HeroPtr h , EGoals goalType = INVALID ) ;
2012-05-08 11:10:40 +03:00
void completeGoal ( const CGoal goal ) ; //safely removes goal from reserved hero
2012-07-18 13:10:14 +03:00
void striveToQuest ( const QuestInfo & q ) ;
2012-02-14 21:04:45 +03:00
void recruitHero ( const CGTownInstance * t ) ;
2012-07-01 02:48:40 +03:00
std : : vector < const CGObjectInstance * > getPossibleDestinations ( HeroPtr h ) ;
2012-02-14 21:04:45 +03:00
void buildStructure ( const CGTownInstance * t ) ;
2012-03-05 22:11:28 +03:00
//void recruitCreatures(const CGTownInstance * t);
void recruitCreatures ( const CGDwelling * d ) ;
2012-08-29 12:19:20 +03:00
bool canGetArmy ( const CGHeroInstance * h , const CGHeroInstance * source ) ; //can we get any better stacks from other hero?
2012-03-06 21:49:23 +03:00
void pickBestCreatures ( const CArmedInstance * army , const CArmedInstance * source ) ; //called when we can't find a slot for new stack
2012-02-14 21:04:45 +03:00
void moveCreaturesToHero ( const CGTownInstance * t ) ;
2012-07-01 02:48:40 +03:00
bool goVisitObj ( const CGObjectInstance * obj , HeroPtr h ) ;
void performObjectInteraction ( const CGObjectInstance * obj , HeroPtr h ) ;
bool moveHeroToTile ( int3 dst , HeroPtr h ) ;
2012-02-14 21:04:45 +03:00
2012-07-01 02:48:40 +03:00
void lostHero ( HeroPtr h ) ; //should remove all references to hero (assigned tasks and so on)
2012-02-14 21:04:45 +03:00
void waitTillFree ( ) ;
void addVisitableObj ( const CGObjectInstance * obj ) ;
2012-03-14 16:02:38 +03:00
void markObjectVisited ( const CGObjectInstance * obj ) ;
2012-07-01 02:48:40 +03:00
void reserveObject ( HeroPtr h , const CGObjectInstance * obj ) ;
2012-02-14 21:04:45 +03:00
//void removeVisitableObj(const CGObjectInstance *obj);
void validateVisitableObjs ( ) ;
void retreiveVisitableObjs ( std : : vector < const CGObjectInstance * > & out , bool includeOwned = false ) const ;
std : : vector < const CGObjectInstance * > getFlaggedObjects ( ) const ;
const CGObjectInstance * lookForArt ( int aid ) const ;
bool isAccessible ( const int3 & pos ) ;
2012-07-01 02:48:40 +03:00
HeroPtr getHeroWithGrail ( ) const ;
2012-02-16 20:10:58 +03:00
2012-02-14 21:04:45 +03:00
const CGObjectInstance * getUnvisitedObj ( const boost : : function < bool ( const CGObjectInstance * ) > & predicate ) ;
2012-07-01 02:48:40 +03:00
bool isAccessibleForHero ( const int3 & pos , HeroPtr h , bool includeAllies = false ) const ;
2012-02-14 21:04:45 +03:00
const CGTownInstance * findTownWithTavern ( ) const ;
2012-07-01 02:48:40 +03:00
std : : vector < HeroPtr > getUnblockedHeroes ( ) const ;
HeroPtr primaryHero ( ) const ;
2012-02-14 21:04:45 +03:00
TResources estimateIncome ( ) const ;
bool containsSavedRes ( const TResources & cost ) const ;
2012-07-18 13:10:14 +03:00
void checkHeroArmy ( HeroPtr h ) ;
2012-03-26 01:46:14 +03:00
2012-07-15 18:34:00 +03:00
void requestSent ( const CPackForServer * pack , int requestID ) OVERRIDE ;
void answerQuery ( int queryID , int selection ) ;
2012-03-26 01:46:14 +03:00
//special function that can be called ONLY from game events handling thread and will send request ASAP
void requestActionASAP ( boost : : function < void ( ) > whatToDo ) ;
2012-02-14 21:04:45 +03:00
} ;
2012-02-16 20:10:58 +03:00
template < int id >
2012-02-14 21:04:45 +03:00
bool objWithID ( const CGObjectInstance * obj )
{
return obj - > ID = = id ;
2012-03-05 22:11:28 +03:00
}
2012-07-19 12:10:55 +03:00
bool isBlockedBorderGate ( int3 tileToHit ) ;
2012-03-05 22:11:28 +03:00
2012-03-14 16:02:38 +03:00
bool isWeeklyRevisitable ( const CGObjectInstance * obj ) ;
2012-08-29 12:19:20 +03:00
bool shouldVisit ( HeroPtr h , const CGObjectInstance * obj ) ;
void makePossibleUpgrades ( const CArmedInstance * obj ) ;