2021-05-15 18:22:44 +02:00
/*
2021-05-16 14:39:38 +02:00
* AIGateway . h , part of VCMI engine
2021-05-15 18:22:44 +02:00
*
* Authors : listed in file AUTHORS in main folder
*
* License : GNU General Public License v2 .0 or later
* Full text of license available in license . txt file , in main folder
*
*/
# pragma once
# include "AIUtility.h"
# include "Goals/AbstractGoal.h"
# include "../../lib/AI_Base.h"
# include "../../CCallback.h"
# include "../../lib/CThreadHelper.h"
# include "../../lib/GameConstants.h"
# include "../../lib/VCMI_Lib.h"
# include "../../lib/CBuildingHandler.h"
# include "../../lib/CCreatureHandler.h"
# include "../../lib/CTownHandler.h"
# include "../../lib/mapObjects/MiscObjects.h"
# include "../../lib/spells/CSpellHandler.h"
# include "../../lib/CondSh.h"
# include "Pathfinding/AIPathfinder.h"
2021-05-16 13:55:47 +02:00
# include "Engine/Nullkiller.h"
2021-05-15 18:22:44 +02:00
2022-09-26 20:01:07 +02:00
namespace NKAI
{
2022-07-26 15:07:42 +02:00
2021-05-15 18:22:44 +02:00
class AIStatus
{
boost : : mutex mx ;
boost : : condition_variable cv ;
BattleState battle ;
std : : map < QueryID , std : : string > remainingQueries ;
std : : map < int , QueryID > requestToQueryID ; //IDs of answer-requests sent to server => query ids (so we can match answer confirmation from server to the query)
std : : vector < const CGObjectInstance * > objectsBeingVisited ;
bool ongoingHeroMovement ;
bool ongoingChannelProbing ; // true if AI currently explore bidirectional teleport channel exits
bool havingTurn ;
public :
AIStatus ( ) ;
~ AIStatus ( ) ;
void setBattle ( BattleState BS ) ;
void setMove ( bool ongoing ) ;
void setChannelProbing ( bool ongoing ) ;
bool channelProbing ( ) ;
BattleState getBattle ( ) ;
void addQuery ( QueryID ID , std : : string description ) ;
void removeQuery ( QueryID ID ) ;
int getQueriesCount ( ) ;
void startedTurn ( ) ;
void madeTurn ( ) ;
void waitTillFree ( ) ;
bool haveTurn ( ) ;
void attemptedAnsweringQuery ( QueryID queryID , int answerRequestID ) ;
void receivedAnswerConfirmation ( int answerRequestID , int result ) ;
void heroVisit ( const CGObjectInstance * obj , bool started ) ;
template < typename Handler > void serialize ( Handler & h , const int version )
{
h & battle ;
h & remainingQueries ;
h & requestToQueryID ;
h & havingTurn ;
}
} ;
2021-05-16 14:39:38 +02:00
// The gateway is responsible for AI events handling. Copied from VCAI.h and refined a bit
// Probably we can use concept of hooks to handle event in their related goals
class DLL_EXPORT AIGateway : public CAdventureAI
2021-05-15 18:22:44 +02:00
{
public :
ObjectInstanceID destinationTeleport ;
int3 destinationTeleportPos ;
std : : vector < ObjectInstanceID > teleportChannelProbingList ; //list of teleport channel exits that not visible and need to be (re-)explored
//std::vector<const CGObjectInstance *> visitedThisWeek; //only OPWs
2021-05-16 14:39:38 +02:00
//std::set<HeroPtr> invalidPathHeroes; //FIXME, just a workaround
//std::map<HeroPtr, Goals::TSubgoal> lockedHeroes; //TODO: allow non-elementar objectives
//std::map<HeroPtr, std::set<const CGObjectInstance *>> reservedHeroesMap; //objects reserved by specific heroes
//std::set<HeroPtr> heroesUnableToExplore; //these heroes will not be polled for exploration in current state of game
2021-05-15 18:22:44 +02:00
//sets are faster to search, also do not contain duplicates
2021-05-16 14:39:38 +02:00
//std::set<const CGObjectInstance *> reservedObjs; //to be visited by specific hero
//std::map<HeroPtr, std::set<HeroPtr>> visitedHeroes; //visited this turn //FIXME: this is just bug workaround
2021-05-15 18:22:44 +02:00
AIStatus status ;
std : : string battlename ;
std : : shared_ptr < CCallback > myCb ;
std : : unique_ptr < boost : : thread > makingTurn ;
2019-12-15 15:47:21 +02:00
private :
boost : : mutex turnInterruptionMutex ;
public :
2021-05-15 18:22:44 +02:00
ObjectInstanceID selectedObject ;
2021-05-15 18:23:05 +02:00
std : : unique_ptr < Nullkiller > nullkiller ;
2021-05-15 18:22:44 +02:00
2021-05-16 14:39:38 +02:00
AIGateway ( ) ;
virtual ~ AIGateway ( ) ;
2021-05-15 18:22:44 +02:00
2021-05-16 14:39:38 +02:00
//TODO: extract to apropriate goals
2021-05-15 18:22:44 +02:00
void tryRealize ( Goals : : DigAtTile & g ) ;
void tryRealize ( Goals : : Trade & g ) ;
std : : string getBattleAIName ( ) const override ;
2022-12-07 21:50:45 +02:00
void initGameInterface ( std : : shared_ptr < Environment > env , std : : shared_ptr < CCallback > CB ) override ;
2023-08-28 02:42:05 +02:00
void yourTurn ( QueryID queryID ) override ;
2021-05-15 18:22:44 +02:00
2023-08-19 20:43:50 +02:00
void heroGotLevel ( const CGHeroInstance * hero , PrimarySkill pskill , std : : vector < SecondarySkill > & skills , QueryID queryID ) override ; //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id
2021-05-15 18:22:44 +02:00
void commanderGotLevel ( const CCommanderInstance * commander , std : : vector < ui32 > skills , QueryID queryID ) override ; //TODO
void showBlockingDialog ( const std : : string & text , const std : : vector < Component > & components , QueryID 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.
void showGarrisonDialog ( const CArmedInstance * up , const CGHeroInstance * down , bool removableUnits , QueryID queryID ) override ; //all stacks operations between these objects become allowed, interface has to call onEnd when done
2023-09-15 21:18:36 +02:00
void showTeleportDialog ( const CGHeroInstance * hero , TeleportChannelID channel , TTeleportExitsList exits , bool impassable , QueryID askID ) override ;
2021-05-15 18:22:44 +02:00
void showMapObjectSelectDialog ( QueryID askID , const Component & icon , const MetaString & title , const MetaString & description , const std : : vector < ObjectInstanceID > & objects ) override ;
void saveGame ( BinarySerializer & h , const int version ) override ; //saving
void loadGame ( BinaryDeserializer & h , const int version ) override ; //loading
void finish ( ) override ;
void availableCreaturesChanged ( const CGDwelling * town ) override ;
2022-01-25 13:19:48 +02:00
void heroMoved ( const TryMoveHero & details , bool verbose = true ) override ;
2021-05-15 18:22:44 +02:00
void heroInGarrisonChange ( const CGTownInstance * town ) override ;
void centerView ( int3 pos , int focusTime ) override ;
2023-04-16 00:48:49 +02:00
void tileHidden ( const std : : unordered_set < int3 > & pos ) override ;
2021-05-15 18:22:44 +02:00
void artifactMoved ( const ArtifactLocation & src , const ArtifactLocation & dst ) override ;
void artifactAssembled ( const ArtifactLocation & al ) override ;
2023-09-28 00:17:05 +02:00
void showTavernWindow ( const CGObjectInstance * object , const CGHeroInstance * visitor , QueryID queryID ) override ;
2021-05-15 18:22:44 +02:00
void showThievesGuildWindow ( const CGObjectInstance * obj ) override ;
void playerBlocked ( int reason , bool start ) override ;
void showPuzzleMap ( ) override ;
void showShipyardDialog ( const IShipyard * obj ) override ;
void gameOver ( PlayerColor player , const EVictoryLossCheckResult & victoryLossCheckResult ) override ;
void artifactPut ( const ArtifactLocation & al ) override ;
void artifactRemoved ( const ArtifactLocation & al ) override ;
void artifactDisassembled ( const ArtifactLocation & al ) override ;
void heroVisit ( const CGHeroInstance * visitor , const CGObjectInstance * visitedObj , bool start ) override ;
void availableArtifactsChanged ( const CGBlackMarket * bm = nullptr ) override ;
void heroVisitsTown ( const CGHeroInstance * hero , const CGTownInstance * town ) override ;
2023-04-16 00:48:49 +02:00
void tileRevealed ( const std : : unordered_set < int3 > & pos ) override ;
2021-05-15 18:22:44 +02:00
void heroExchangeStarted ( ObjectInstanceID hero1 , ObjectInstanceID hero2 , QueryID query ) override ;
2023-08-19 20:43:50 +02:00
void heroPrimarySkillChanged ( const CGHeroInstance * hero , PrimarySkill which , si64 val ) override ;
2023-10-04 16:24:19 +02:00
void showRecruitmentDialog ( const CGDwelling * dwelling , const CArmedInstance * dst , int level , QueryID queryID ) override ;
2021-05-15 18:22:44 +02:00
void heroMovePointsChanged ( const CGHeroInstance * hero ) override ;
void garrisonsChanged ( ObjectInstanceID id1 , ObjectInstanceID id2 ) override ;
void newObject ( const CGObjectInstance * obj ) override ;
void showHillFortWindow ( const CGObjectInstance * object , const CGHeroInstance * visitor ) override ;
void playerBonusChanged ( const Bonus & bonus , bool gain ) override ;
void heroCreated ( const CGHeroInstance * ) override ;
2023-09-04 12:03:15 +02:00
void advmapSpellCast ( const CGHeroInstance * caster , SpellID spellID ) override ;
2023-03-06 01:30:21 +02:00
void showInfoDialog ( EInfoWindowMode type , const std : : string & text , const std : : vector < Component > & components , int soundID ) override ;
2021-05-15 18:22:44 +02:00
void requestRealized ( PackageApplied * pa ) override ;
void receivedResource ( ) override ;
2023-09-18 21:09:55 +02:00
void objectRemoved ( const CGObjectInstance * obj , const PlayerColor & initiator ) override ;
2023-09-28 00:17:05 +02:00
void showUniversityWindow ( const IMarket * market , const CGHeroInstance * visitor , QueryID queryID ) override ;
2021-05-15 18:22:44 +02:00
void heroManaPointsChanged ( const CGHeroInstance * hero ) override ;
void heroSecondarySkillChanged ( const CGHeroInstance * hero , int which , int val ) override ;
void battleResultsApplied ( ) override ;
2023-07-04 19:02:41 +02:00
void beforeObjectPropertyChanged ( const SetObjectProperty * sop ) override ;
2021-05-15 18:22:44 +02:00
void objectPropertyChanged ( const SetObjectProperty * sop ) override ;
void buildChanged ( const CGTownInstance * town , BuildingID buildingID , int what ) override ;
void heroBonusChanged ( const CGHeroInstance * hero , const Bonus & bonus , bool gain ) override ;
2023-09-28 00:17:05 +02:00
void showMarketWindow ( const IMarket * market , const CGHeroInstance * visitor , QueryID queryID ) override ;
2023-02-21 14:38:08 +02:00
void showWorldViewEx ( const std : : vector < ObjectPosInfo > & objectPositions , bool showTerrain ) override ;
2023-08-28 17:59:12 +02:00
std : : optional < BattleAction > makeSurrenderRetreatDecision ( const BattleID & battleID , const BattleStateInfoForRetreat & battleState ) override ;
2021-05-15 18:22:44 +02:00
2023-08-28 17:59:12 +02:00
void battleStart ( const BattleID & battleID , const CCreatureSet * army1 , const CCreatureSet * army2 , int3 tile , const CGHeroInstance * hero1 , const CGHeroInstance * hero2 , bool side , bool replayAllowed ) override ;
void battleEnd ( const BattleID & battleID , const BattleResult * br , QueryID queryID ) override ;
2021-05-15 18:22:44 +02:00
void makeTurn ( ) ;
void buildArmyIn ( const CGTownInstance * t ) ;
void endTurn ( ) ;
2021-05-16 14:39:38 +02:00
// TODO: all the routines like recruiting hero or building army should be removed from here and extracted to elementar goals or whatever
2021-05-15 18:22:44 +02:00
void recruitCreatures ( const CGDwelling * d , const CArmedInstance * recruiter ) ;
void pickBestCreatures ( const CArmedInstance * army , const CArmedInstance * source ) ; //called when we can't find a slot for new stack
void pickBestArtifacts ( const CGHeroInstance * h , const CGHeroInstance * other = nullptr ) ;
void moveCreaturesToHero ( const CGTownInstance * t ) ;
void performObjectInteraction ( const CGObjectInstance * obj , HeroPtr h ) ;
2021-05-16 13:19:00 +02:00
bool makePossibleUpgrades ( const CArmedInstance * obj ) ;
2021-05-15 18:22:44 +02:00
bool moveHeroToTile ( int3 dst , HeroPtr h ) ;
2021-05-16 14:39:38 +02:00
void buildStructure ( const CGTownInstance * t , BuildingID building ) ;
2021-05-15 18:22:44 +02:00
void lostHero ( HeroPtr h ) ; //should remove all references to hero (assigned tasks and so on)
void waitTillFree ( ) ;
void addVisitableObj ( const CGObjectInstance * obj ) ;
void validateObject ( const CGObjectInstance * obj ) ; //checks if object is still visible and if not, removes references to it
void validateObject ( ObjectIdRef obj ) ; //checks if object is still visible and if not, removes references to it
void retrieveVisitableObjs ( ) ;
virtual std : : vector < const CGObjectInstance * > getFlaggedObjects ( ) const ;
void requestSent ( const CPackForServer * pack , int requestID ) override ;
void answerQuery ( QueryID queryID , int selection ) ;
//special function that can be called ONLY from game events handling thread and will send request ASAP
void requestActionASAP ( std : : function < void ( ) > whatToDo ) ;
template < typename Handler > void serializeInternal ( Handler & h , const int version )
{
2020-05-04 17:58:43 +02:00
h & nullkiller - > memory - > knownTeleportChannels ;
h & nullkiller - > memory - > knownSubterraneanGates ;
2021-05-15 18:22:44 +02:00
h & destinationTeleport ;
2020-05-04 17:58:43 +02:00
h & nullkiller - > memory - > visitableObjs ;
h & nullkiller - > memory - > alreadyVisited ;
2021-05-15 18:22:44 +02:00
h & status ;
h & battlename ;
}
} ;
2022-09-26 20:01:07 +02:00
}