2008-11-25 20:51:44 +02:00
# include "CGeniusAI.h"
2009-08-18 10:37:45 +03:00
# include "AIPriorities.h"
2008-11-25 20:51:44 +02:00
# include <iostream>
2009-08-04 11:56:38 +03:00
# include "../../hch/CBuildingHandler.h"
2009-08-06 12:52:07 +03:00
# include "../../hch/CHeroHandler.h"
2009-08-05 12:46:55 +03:00
# include "../../lib/VCMI_Lib.h"
2009-08-06 12:52:07 +03:00
# include "../../lib/NetPacks.h"
2009-08-18 10:37:45 +03:00
2009-02-07 20:52:55 +02:00
using namespace std ;
2008-11-25 20:51:44 +02:00
using namespace GeniusAI ;
2009-02-08 18:36:53 +02:00
# if defined (_MSC_VER) && (_MSC_VER >= 1020) || (__MINGW32__)
2009-08-17 16:08:05 +03:00
# define WIN32_LEAN_AND_MEAN //excludes rarely used stuff from windows headers - delete this line if something is missing
2008-11-25 20:51:44 +02:00
# include <windows.h>
# endif
2009-08-04 01:15:13 +03:00
void DbgBox ( const char * msg , bool messageBox )
2008-11-25 20:51:44 +02:00
{
2009-08-04 01:15:13 +03:00
# if defined PRINT_DEBUG
2008-11-25 20:51:44 +02:00
# if defined _DEBUG
2009-08-04 01:15:13 +03:00
//#if 0
2008-11-25 20:51:44 +02:00
# if defined (_MSC_VER) && (_MSC_VER >= 1020)
if ( messageBox )
{
MessageBoxA ( NULL , msg , " Debug message " , MB_OK | MB_ICONASTERISK ) ;
}
# endif
std : : cout < < msg < < std : : endl ;
# endif
2009-08-04 01:15:13 +03:00
# endif
2008-11-25 20:51:44 +02:00
}
2009-08-06 12:52:07 +03:00
bool CGeniusAI : : AIObjectContainer : : operator < ( const AIObjectContainer & b ) const
{
if ( o - > pos ! = b . o - > pos )
return o - > pos < b . o - > pos ;
return o - > id < b . o - > id ;
}
CGeniusAI : : HypotheticalGameState : : HeroModel : : HeroModel ( const CGHeroInstance * h )
: h ( h ) , finished ( false )
{
pos = h - > getPosition ( false ) ; remainingMovement = h - > movement ;
}
CGeniusAI : : HypotheticalGameState : : TownModel : : TownModel ( const CGTownInstance * t ) : t ( t )
{
hasBuilt = t - > builded ;
creaturesToRecruit = t - > creatures ;
creaturesInGarrison = t - > army ;
}
2009-08-18 10:37:45 +03:00
CGeniusAI : : HypotheticalGameState : : HypotheticalGameState ( CGeniusAI & ai )
: knownVisitableObjects ( ai . knownVisitableObjects )
2009-08-06 12:52:07 +03:00
{
2009-08-18 10:37:45 +03:00
AI = & ai ;
std : : vector < const CGHeroInstance * > heroes = ai . m_cb - > getHeroesInfo ( ) ;
2009-08-06 12:52:07 +03:00
for ( std : : vector < const CGHeroInstance * > : : iterator i = heroes . begin ( ) ; i ! = heroes . end ( ) ; i + + )
heroModels . push_back ( HeroModel ( * i ) ) ;
2009-08-18 10:37:45 +03:00
std : : vector < const CGTownInstance * > towns = ai . m_cb - > getTownsInfo ( ) ;
2009-08-06 12:52:07 +03:00
for ( std : : vector < const CGTownInstance * > : : iterator i = towns . begin ( ) ; i ! = towns . end ( ) ; i + + )
2009-08-18 10:37:45 +03:00
if ( ( * i ) - > tempOwner = = ai . m_cb - > getMyColor ( ) )
2009-08-06 12:52:07 +03:00
townModels . push_back ( TownModel ( * i ) ) ;
2009-08-18 10:37:45 +03:00
if ( ai . m_cb - > howManyTowns ( ) ! = 0 )
AvailableHeroesToBuy = ai . m_cb - > getAvailableHeroes ( ai . m_cb - > getTownInfo ( 0 , 0 ) ) ;
2009-08-06 12:52:07 +03:00
2009-08-18 10:37:45 +03:00
for ( int i = 0 ; i < 8 ; i + + ) resourceAmounts . push_back ( ai . m_cb - > getResourceAmount ( i ) ) ;
2009-08-06 12:52:07 +03:00
}
2009-08-18 10:37:45 +03:00
void CGeniusAI : : HypotheticalGameState : : update ( CGeniusAI & ai )
2009-08-06 12:52:07 +03:00
{
2009-08-18 10:37:45 +03:00
AI = & ai ;
2009-08-21 21:18:52 +03:00
knownVisitableObjects = ai . knownVisitableObjects ;
2009-08-06 12:52:07 +03:00
std : : vector < HeroModel > oldModels = heroModels ;
heroModels . clear ( ) ;
2009-08-18 10:37:45 +03:00
std : : vector < const CGHeroInstance * > heroes = ai . m_cb - > getHeroesInfo ( ) ;
2009-08-06 12:52:07 +03:00
for ( std : : vector < const CGHeroInstance * > : : iterator i = heroes . begin ( ) ; i ! = heroes . end ( ) ; i + + )
heroModels . push_back ( HeroModel ( * i ) ) ;
for ( int i = 0 ; i < oldModels . size ( ) ; i + + )
for ( int ii = 0 ; ii < heroModels . size ( ) ; ii + + )
2009-08-19 13:18:14 +03:00
if ( oldModels [ i ] . h - > subID = = heroModels [ ii ] . h - > subID )
{
heroModels [ ii ] . finished = oldModels [ i ] . finished ;
heroModels [ ii ] . previouslyVisited_pos = oldModels [ i ] . previouslyVisited_pos ;
}
2009-08-06 12:52:07 +03:00
townModels . clear ( ) ;
2009-08-18 10:37:45 +03:00
std : : vector < const CGTownInstance * > towns = ai . m_cb - > getTownsInfo ( ) ;
2009-08-06 12:52:07 +03:00
for ( std : : vector < const CGTownInstance * > : : iterator i = towns . begin ( ) ; i ! = towns . end ( ) ; i + + )
2009-08-18 10:37:45 +03:00
if ( ( * i ) - > tempOwner = = ai . m_cb - > getMyColor ( ) )
2009-08-06 12:52:07 +03:00
townModels . push_back ( TownModel ( * i ) ) ;
2009-08-18 10:37:45 +03:00
if ( ai . m_cb - > howManyTowns ( ) ! = 0 )
AvailableHeroesToBuy = ai . m_cb - > getAvailableHeroes ( ai . m_cb - > getTownInfo ( 0 , 0 ) ) ;
2009-08-06 12:52:07 +03:00
resourceAmounts . clear ( ) ;
2009-08-18 10:37:45 +03:00
for ( int i = 0 ; i < 8 ; i + + ) resourceAmounts . push_back ( ai . m_cb - > getResourceAmount ( i ) ) ;
2009-08-06 12:52:07 +03:00
}
2009-08-18 10:37:45 +03:00
CGeniusAI : : HeroObjective : : HeroObjective ( const HypotheticalGameState & hgs , Type t , const CGObjectInstance * object , HypotheticalGameState : : HeroModel * h , CGeniusAI * ai ) : object ( object ) , hgs ( hgs )
2009-08-06 12:52:07 +03:00
{
2009-08-07 11:41:40 +03:00
AI = ai ;
2009-08-06 12:52:07 +03:00
pos = object - > pos ;
type = t ;
whoCanAchieve . push_back ( h ) ;
2009-08-07 11:41:40 +03:00
_value = - 1 ;
2009-08-06 12:52:07 +03:00
}
2009-08-07 11:41:40 +03:00
float CGeniusAI : : HeroObjective : : getValue ( ) const
{
2009-08-18 10:37:45 +03:00
if ( _value > = 0 )
return _value - _cost ;
2009-08-07 11:41:40 +03:00
2009-08-18 10:37:45 +03:00
vector < int > resourceCosts ; //TODO: each object should have an associated cost to visit IE (tree of knowledge 1000 gold/10 gems)
2009-08-07 11:41:40 +03:00
for ( int i = 0 ; i < 8 ; i + + )
resourceCosts . push_back ( 0 ) ;
2009-08-18 10:37:45 +03:00
if ( object - > ID = = 47 ) //school of magic
resourceCosts [ 6 ] + = 1000 ;
2009-08-07 11:41:40 +03:00
float bestCost = 9e9 ;
2009-08-21 21:18:52 +03:00
HypotheticalGameState : : HeroModel * bestHero = NULL ;
2009-08-07 11:41:40 +03:00
if ( type ! = AIObjective : : finishTurn )
2009-08-18 10:37:45 +03:00
{
2009-08-07 11:41:40 +03:00
for ( int i = 0 ; i < whoCanAchieve . size ( ) ; i + + )
{
int distOutOfTheWay = 0 ;
2009-08-21 21:18:52 +03:00
CPath path3 ;
2009-08-07 11:41:40 +03:00
//from hero to object
2009-08-21 21:18:52 +03:00
if ( AI - > m_cb - > getPath ( whoCanAchieve [ i ] - > pos , pos , whoCanAchieve [ i ] - > h , path3 ) )
distOutOfTheWay + = path3 . nodes [ 0 ] . dist ;
2009-08-07 11:41:40 +03:00
//from object to goal
2009-08-21 21:18:52 +03:00
if ( AI - > m_cb - > getPath ( pos , whoCanAchieve [ i ] - > interestingPos , whoCanAchieve [ i ] - > h , path3 ) )
2009-08-07 11:41:40 +03:00
{
2009-08-21 21:18:52 +03:00
distOutOfTheWay + = path3 . nodes [ 0 ] . dist ;
2009-08-07 11:41:40 +03:00
//from hero directly to goal
2009-08-21 21:18:52 +03:00
if ( AI - > m_cb - > getPath ( whoCanAchieve [ i ] - > pos , whoCanAchieve [ i ] - > interestingPos , whoCanAchieve [ i ] - > h , path3 ) )
distOutOfTheWay - = path3 . nodes [ 0 ] . dist ;
2009-08-07 11:41:40 +03:00
}
2009-08-18 10:37:45 +03:00
float cost = AI - > m_priorities - > getCost ( resourceCosts , whoCanAchieve [ i ] - > h , distOutOfTheWay ) ;
2009-08-07 11:41:40 +03:00
if ( cost < bestCost )
2009-08-21 21:18:52 +03:00
{
2009-08-07 11:41:40 +03:00
bestCost = cost ;
2009-08-21 21:18:52 +03:00
bestHero = whoCanAchieve [ i ] ;
}
2009-08-07 11:41:40 +03:00
}
2009-08-18 10:37:45 +03:00
}
else bestCost = 0 ;
2009-08-21 21:18:52 +03:00
if ( bestHero )
{
whoCanAchieve . clear ( ) ;
whoCanAchieve . push_back ( bestHero ) ;
}
2009-08-18 10:37:45 +03:00
_value = AI - > m_priorities - > getValue ( * this ) ;
_cost = bestCost ;
return _value - _cost ;
2009-08-07 11:41:40 +03:00
}
2009-08-06 12:52:07 +03:00
bool CGeniusAI : : HeroObjective : : operator < ( const HeroObjective & other ) const
{
if ( type ! = other . type )
return type < other . type ;
if ( pos ! = other . pos )
return pos < other . pos ;
if ( object - > id ! = other . object - > id )
return object - > id < other . object - > id ;
2009-08-07 11:41:40 +03:00
if ( dynamic_cast < const CGVisitableOPH * > ( object ) )
if ( whoCanAchieve . front ( ) - > h - > id ! = other . whoCanAchieve . front ( ) - > h - > id )
return whoCanAchieve . front ( ) - > h - > id < other . whoCanAchieve . front ( ) - > h - > id ;
2009-08-06 12:52:07 +03:00
return false ;
}
2009-08-07 11:41:40 +03:00
void CGeniusAI : : HeroObjective : : print ( ) const
{
switch ( type )
{
case visit :
2009-08-18 10:37:45 +03:00
cout < < " visit " < < object - > hoverName < < " at ( " < < object - > pos . x < < " , " < < object - > pos . y < < " ) " ;
2009-08-07 11:41:40 +03:00
break ;
case attack :
cout < < " attack " < < object - > hoverName ;
2009-08-21 21:18:52 +03:00
break ;
2009-08-07 11:41:40 +03:00
case finishTurn :
cout < < " finish turn " ;
}
2009-08-18 10:37:45 +03:00
if ( whoCanAchieve . size ( ) = = 1 )
cout < < " with " < < whoCanAchieve . front ( ) - > h - > hoverName ;
2009-08-07 11:41:40 +03:00
}
2009-08-18 10:37:45 +03:00
CGeniusAI : : TownObjective : : TownObjective ( const HypotheticalGameState & hgs , Type t , HypotheticalGameState : : TownModel * tn , int Which , CGeniusAI * ai )
: whichTown ( tn ) , which ( Which ) , hgs ( hgs )
2009-08-06 12:52:07 +03:00
{
2009-08-07 11:41:40 +03:00
AI = ai ;
2009-08-06 12:52:07 +03:00
type = t ;
2009-08-07 11:41:40 +03:00
_value = - 1 ;
2009-08-06 12:52:07 +03:00
}
2009-08-07 11:41:40 +03:00
float CGeniusAI : : TownObjective : : getValue ( ) const
{
2009-08-18 10:37:45 +03:00
if ( _value > = 0 )
return _value - _cost ;
float cost ;
2009-08-07 11:41:40 +03:00
2009-08-18 10:37:45 +03:00
vector < int > resourceCosts ( 8 , 0 ) ;
CBuilding * b ;
CCreature * creature ;
int ID , newID , howMany ;
switch ( type )
{
case recruitHero :
resourceCosts [ 6 ] = 2500 ;
break ;
case buildBuilding :
b = VLC - > buildh - > buildings [ whichTown - > t - > subID ] [ which ] ;
for ( int i = 0 ; b & & i < b - > resources . size ( ) ; i + + )
resourceCosts [ i ] = b - > resources [ i ] ;
break ;
2009-08-07 11:41:40 +03:00
2009-08-18 10:37:45 +03:00
case recruitCreatures :
ID = whichTown - > creaturesToRecruit [ which ] . second . back ( ) ; //buy upgraded if possible
creature = & VLC - > creh - > creatures [ ID ] ;
howMany = whichTown - > creaturesToRecruit [ which ] . first ;
for ( int i = 0 ; i < creature - > cost . size ( ) ; i + + )
amin ( howMany , creature - > cost [ i ] ? hgs . resourceAmounts [ i ] / creature - > cost [ i ] : INT_MAX ) ;
for ( int i = 0 ; creature & & i < creature - > cost . size ( ) ; i + + )
resourceCosts [ i ] = creature - > cost [ i ] * howMany ;
2009-08-07 11:41:40 +03:00
2009-08-18 10:37:45 +03:00
break ;
case upgradeCreatures :
UpgradeInfo ui = AI - > m_cb - > getUpgradeInfo ( whichTown - > t , which ) ;
ID = whichTown - > creaturesInGarrison . slots [ which ] . first ;
howMany = whichTown - > creaturesInGarrison . slots [ which ] . second ;
newID = ui . newID . back ( ) ;
2009-08-21 21:18:52 +03:00
int upgrade_serial = ui . newID . size ( ) - 1 ;
for ( std : : set < std : : pair < int , int > > : : iterator j = ui . cost [ upgrade_serial ] . begin ( ) ; j ! = ui . cost [ upgrade_serial ] . end ( ) ; j + + )
resourceCosts [ j - > first ] = j - > second * howMany ;
2009-08-18 10:37:45 +03:00
break ;
}
_cost = AI - > m_priorities - > getCost ( resourceCosts , NULL , 0 ) ;
_value = AI - > m_priorities - > getValue ( * this ) ;
return _value - _cost ;
2009-08-07 11:41:40 +03:00
}
2009-08-06 12:52:07 +03:00
bool CGeniusAI : : TownObjective : : operator < ( const TownObjective & other ) const
{
if ( type ! = other . type )
return type < other . type ;
if ( which ! = other . which )
return which < other . which ;
if ( whichTown - > t - > id ! = other . whichTown - > t - > id )
return whichTown - > t - > id < other . whichTown - > t - > id ;
return false ;
}
2009-08-07 11:41:40 +03:00
void CGeniusAI : : TownObjective : : print ( ) const
{
CBuilding * b ;
const CCreature * creature ;
HypotheticalGameState : : HeroModel hm ;
int ID , howMany , newID , hSlot ;
switch ( type )
{
case recruitHero :
cout < < " recruit hero. " ; break ;
case buildBuilding :
b = VLC - > buildh - > buildings [ whichTown - > t - > subID ] [ which ] ;
cout < < " build " < < b - > Name ( ) < < " cost = " ;
if ( b - > resources . size ( ) ! = 0 )
{
if ( b - > resources [ 0 ] ! = 0 ) cout < < b - > resources [ 0 ] < < " wood. " ;
if ( b - > resources [ 1 ] ! = 0 ) cout < < b - > resources [ 1 ] < < " mercury. " ;
if ( b - > resources [ 2 ] ! = 0 ) cout < < b - > resources [ 2 ] < < " ore. " ;
if ( b - > resources [ 3 ] ! = 0 ) cout < < b - > resources [ 3 ] < < " sulfer. " ;
if ( b - > resources [ 4 ] ! = 0 ) cout < < b - > resources [ 4 ] < < " cristal. " ;
if ( b - > resources [ 5 ] ! = 0 ) cout < < b - > resources [ 5 ] < < " gems. " ;
if ( b - > resources [ 6 ] ! = 0 ) cout < < b - > resources [ 6 ] < < " gold. " ;
}
break ;
case recruitCreatures :
ID = whichTown - > creaturesToRecruit [ which ] . second . back ( ) ; //buy upgraded if possible
creature = & VLC - > creh - > creatures [ ID ] ;
howMany = whichTown - > creaturesToRecruit [ which ] . first ;
for ( int i = 0 ; i < creature - > cost . size ( ) ; i + + )
2009-08-08 09:13:56 +03:00
amin ( howMany , creature - > cost [ i ] ? AI - > m_cb - > getResourceAmount ( i ) / creature - > cost [ i ] : INT_MAX ) ;
2009-08-07 11:41:40 +03:00
cout < < " recruit " < < howMany < < " " < < creature - > namePl < < " (Total AI Strength " < < creature - > AIValue * howMany < < " ). cost = " ;
if ( creature - > cost . size ( ) ! = 0 )
{
if ( creature - > cost [ 0 ] ! = 0 ) cout < < creature - > cost [ 0 ] * howMany < < " wood. " ;
if ( creature - > cost [ 1 ] ! = 0 ) cout < < creature - > cost [ 1 ] * howMany < < " mercury. " ;
if ( creature - > cost [ 2 ] ! = 0 ) cout < < creature - > cost [ 2 ] * howMany < < " ore. " ;
if ( creature - > cost [ 3 ] ! = 0 ) cout < < creature - > cost [ 3 ] * howMany < < " sulfer. " ;
if ( creature - > cost [ 4 ] ! = 0 ) cout < < creature - > cost [ 4 ] * howMany < < " cristal. " ;
if ( creature - > cost [ 5 ] ! = 0 ) cout < < creature - > cost [ 5 ] * howMany < < " gems. " ;
if ( creature - > cost [ 6 ] ! = 0 ) cout < < creature - > cost [ 6 ] * howMany < < " gold. " ;
}
break ;
case upgradeCreatures :
UpgradeInfo ui = AI - > m_cb - > getUpgradeInfo ( whichTown - > t , which ) ;
ID = whichTown - > creaturesInGarrison . slots [ which ] . first ;
2009-08-18 10:37:45 +03:00
cout < < " upgrade " < < VLC - > creh - > creatures [ ID ] . namePl ;
2009-08-07 11:41:40 +03:00
//ui.cost
break ;
}
}
2009-05-10 11:15:30 +03:00
CGeniusAI : : CGeniusAI ( )
2009-08-06 12:52:07 +03:00
: m_generalAI ( ) , m_state ( NO_BATTLE )
2009-05-10 11:15:30 +03:00
{
2009-08-18 10:37:45 +03:00
m_priorities = new Priorities ( " AI/GeniusAI.brain " ) ;
2009-05-10 11:15:30 +03:00
}
CGeniusAI : : ~ CGeniusAI ( )
{
2009-08-18 10:37:45 +03:00
delete m_priorities ;
2009-05-10 11:15:30 +03:00
}
2008-11-25 20:51:44 +02:00
void CGeniusAI : : init ( ICallback * CB )
{
m_cb = CB ;
2009-05-10 11:15:30 +03:00
m_generalAI . init ( CB ) ;
2008-11-25 20:51:44 +02:00
human = false ;
playerID = m_cb - > getMyColor ( ) ;
serialID = m_cb - > getMySerial ( ) ;
std : : string info = std : : string ( " GeniusAI initialized for player " ) + boost : : lexical_cast < std : : string > ( playerID ) ;
m_battleLogic = NULL ;
2009-08-04 01:15:13 +03:00
DbgBox ( info . c_str ( ) ) ;
2008-11-25 20:51:44 +02:00
}
2009-08-01 05:57:50 +03:00
2009-08-04 01:15:13 +03:00
void CGeniusAI : : reportResources ( )
{
2009-08-06 12:52:07 +03:00
cout < < " Day " < < m_cb - > getDate ( ) < < " : " ;
cout < < " AI Player " < < m_cb - > getMySerial ( ) < < " with " < < m_cb - > howManyHeroes ( true ) < < " heroes. " < < endl ;
2009-08-01 05:57:50 +03:00
2009-08-06 12:52:07 +03:00
cout < < m_cb - > getResourceAmount ( 0 ) < < " wood. " ;
cout < < m_cb - > getResourceAmount ( 1 ) < < " mercury. " ;
cout < < m_cb - > getResourceAmount ( 2 ) < < " ore. " ;
cout < < m_cb - > getResourceAmount ( 3 ) < < " sulfer. " ;
cout < < m_cb - > getResourceAmount ( 4 ) < < " cristal. " ;
cout < < m_cb - > getResourceAmount ( 5 ) < < " gems. " ;
cout < < m_cb - > getResourceAmount ( 6 ) < < " gold. " ;
cout < < endl ;
2009-08-04 01:15:13 +03:00
}
void CGeniusAI : : addHeroObjectives ( CGeniusAI : : HypotheticalGameState : : HeroModel & h , CGeniusAI : : HypotheticalGameState & hgs )
{
int3 hpos , destination ;
CPath path ;
hpos = h . pos ;
int movement = h . remainingMovement ;
2009-08-05 12:46:55 +03:00
int3 interestingPos ;
int maxInteresting = 0 ;
2009-08-06 12:52:07 +03:00
AIObjective : : Type tp = AIObjective : : visit ;
if ( h . finished ) return ;
2009-08-04 01:15:13 +03:00
for ( std : : set < AIObjectContainer > : : const_iterator i = hgs . knownVisitableObjects . begin ( ) ; i ! = hgs . knownVisitableObjects . end ( ) ; i + + )
2009-08-01 05:57:50 +03:00
{
2009-08-21 21:18:52 +03:00
tp = AIObjective : : visit ;
2009-08-19 13:18:14 +03:00
if ( h . previouslyVisited_pos = = i - > o - > getSightCenter ( ) )
continue ;
2009-08-06 12:52:07 +03:00
//TODO: what would the hero actually visit if he went to that spot
2009-08-19 13:18:14 +03:00
// maybe the hero wants to visit a seemingly unguarded enemy town, but there is a hero on top of it.
2009-08-07 11:41:40 +03:00
//if(i->o->)
2009-08-17 16:08:05 +03:00
if ( i - > o - > ID ! = HEROI_TYPE ) //unless you are trying to visit a hero
2009-08-06 12:52:07 +03:00
{
bool heroThere = false ;
for ( int ii = 0 ; ii < hgs . heroModels . size ( ) ; ii + + )
if ( hgs . heroModels [ ii ] . pos = = i - > o - > getSightCenter ( ) )
heroThere = true ;
if ( heroThere ) //it won't work if there is already someone visiting that spot.
continue ;
}
2009-08-21 21:18:52 +03:00
if ( i - > o - > ID = = HEROI_TYPE & & i - > o - > getOwner ( ) = = m_cb - > getMyColor ( ) ) //visiting friendly heroes not yet supported
continue ;
2009-08-19 13:18:14 +03:00
if ( i - > o - > id = = h . h - > id ) //don't visit yourself (should be caught by above)
continue ;
2009-08-21 21:18:52 +03:00
if ( i - > o - > ID = = 53 & & i - > o - > getOwner ( ) = = m_cb - > getMyColor ( ) ) //don't visit a mine if you own, there's almost no point(maybe to leave guards or because the hero's trapped).
continue ;
2009-08-06 12:52:07 +03:00
if ( i - > o - > getOwner ( ) ! = m_cb - > getMyColor ( ) )
{
int enemyStrength = 0 ; //TODO: I feel like the AI shouldn't have access to this information.
// We must get an approximation based on few, many, ... zounds etc.
if ( dynamic_cast < const CArmedInstance * > ( i - > o ) )
enemyStrength = ( dynamic_cast < const CArmedInstance * > ( i - > o ) ) - > getArmyStrength ( ) ; //TODO: should be virtual maybe, Army strength should be comparable across objects
if ( dynamic_cast < const CGHeroInstance * > ( i - > o ) )
2009-08-21 21:18:52 +03:00
enemyStrength = ( dynamic_cast < const CGHeroInstance * > ( i - > o ) ) - > getTotalStrength ( ) ;
2009-08-06 12:52:07 +03:00
if ( dynamic_cast < const CGTownInstance * > ( i - > o ) )
2009-08-18 10:37:45 +03:00
enemyStrength = ( dynamic_cast < const CGTownInstance * > ( i - > o ) ) - > getArmyStrength ( ) * 1.2 ;
2009-08-21 21:18:52 +03:00
float heroStrength = h . h - > getTotalStrength ( ) ;
if ( enemyStrength * 2.5 > heroStrength ) //TODO: ballence these numbers using objective cost formula.
2009-08-19 13:18:14 +03:00
continue ; // it would be nice to do a battle sim
2009-08-21 21:18:52 +03:00
if ( enemyStrength > 0 ) tp = AIObjective : : attack ;
2009-08-06 12:52:07 +03:00
}
2009-08-21 21:18:52 +03:00
2009-08-07 11:41:40 +03:00
if ( dynamic_cast < const CGVisitableOPW * > ( i - > o ) & & dynamic_cast < const CGVisitableOPW * > ( i - > o ) - > visited ) //don't visit things that have already been visited this week.
continue ;
if ( dynamic_cast < const CGVisitableOPH * > ( i - > o ) & & vstd : : contains ( dynamic_cast < const CGVisitableOPH * > ( i - > o ) - > visitors , h . h - > id ) ) //don't visit things that you have already visited OPH
continue ;
2009-08-19 13:18:14 +03:00
2009-08-07 11:41:40 +03:00
2009-08-18 10:37:45 +03:00
if ( i - > o - > ID = = 88 | | i - > o - > ID = = 89 | | i - > o - > ID = = 90 )
{
//TODO: if no spell book continue
//TODO: if the shrine's spell is identified, and the hero already has it, continue
}
2009-08-04 01:15:13 +03:00
destination = i - > o - > getSightCenter ( ) ;
2009-08-05 12:46:55 +03:00
if ( hpos . z = = destination . z ) //don't try to take a path from the underworld to the top or vice versa
2009-08-21 21:18:52 +03:00
{ //TODO: fix get path so that it doesn't return a path unless z's are the same, or path goes through sub gate
2009-08-05 12:46:55 +03:00
if ( m_cb - > getPath ( hpos , destination , h . h , path ) )
2009-08-01 05:57:50 +03:00
{
2009-08-05 12:46:55 +03:00
path . convert ( 0 ) ;
if ( path . nodes [ 0 ] . dist < movement )
{
2009-08-18 10:37:45 +03:00
HeroObjective ho ( hgs , tp , i - > o , & h , this ) ;
2009-08-05 12:46:55 +03:00
std : : set < HeroObjective > : : iterator found = currentHeroObjectives . find ( ho ) ;
if ( found = = currentHeroObjectives . end ( ) )
currentHeroObjectives . insert ( ho ) ;
2009-08-12 05:08:59 +03:00
else {
HeroObjective * objective = ( HeroObjective * ) & ( * found ) ;
objective - > whoCanAchieve . push_back ( & h ) ;
}
2009-08-05 12:46:55 +03:00
}
2009-08-06 12:52:07 +03:00
// find the most interesting object that is eventually reachable, and set that position to the ultimate goal position
2009-08-05 12:46:55 +03:00
int hi = rand ( ) ; //TODO: replace random numbers with some sort of ranking system
if ( hi > maxInteresting )
{
maxInteresting = hi ;
interestingPos = destination ;
}
}
}
}
2009-08-06 12:52:07 +03:00
h . interestingPos = interestingPos ;
2009-08-21 21:18:52 +03:00
// if(h.remainingMovement>0&&m_cb->getPath(hpos,interestingPos,h.h,path)) // there ought to be a path
2009-08-18 10:37:45 +03:00
currentHeroObjectives . insert ( HeroObjective ( hgs , HeroObjective : : finishTurn , h . h , & h , this ) ) ;
2009-08-06 12:52:07 +03:00
2009-08-05 12:46:55 +03:00
}
void CGeniusAI : : HeroObjective : : fulfill ( CGeniusAI & cg , HypotheticalGameState & hgs )
{
2009-08-06 12:52:07 +03:00
cg . m_cb - > waitTillRealize = true ;
2009-08-05 12:46:55 +03:00
HypotheticalGameState : : HeroModel * h ;
int3 hpos , destination ;
CPath path ;
CPath path2 ;
2009-08-06 12:52:07 +03:00
int3 bestPos , currentPos , checkPos ;
int howGood ;
2009-08-05 12:46:55 +03:00
switch ( type )
{
case finishTurn :
h = whoCanAchieve . front ( ) ;
2009-08-18 10:37:45 +03:00
h - > finished = true ;
2009-08-05 12:46:55 +03:00
hpos = h - > pos ;
destination = h - > interestingPos ;
if ( ! cg . m_cb - > getPath ( hpos , destination , h - > h , path ) ) { cout < < " AI error: invalid destination " < < endl ; return ; }
2009-08-21 21:18:52 +03:00
2009-08-05 12:46:55 +03:00
destination = h - > pos ;
for ( int i = path . nodes . size ( ) - 2 ; i > = 0 ; i - - ) //find closest coord that we can get to
if ( cg . m_cb - > getPath ( hpos , path . nodes [ i ] . coord , h - > h , path2 ) & & path2 . nodes [ 0 ] . dist < = h - > remainingMovement )
destination = path . nodes [ i ] . coord ;
2009-08-06 12:52:07 +03:00
if ( destination = = h - > interestingPos ) break ;
///////// Find close pos with the most neighboring empty squares. We don't want to get in the way. ///////////////////
bestPos = destination ;
howGood = 0 ;
for ( int x = - 3 ; x < = 3 ; x + + )
for ( int y = - 3 ; y < = 3 ; y + + )
{
currentPos = destination + int3 ( x , y , 0 ) ;
if ( cg . m_cb - > getVisitableObjs ( currentPos ) . size ( ) ! = 0 ) //there better not be anything there
continue ;
if ( ! cg . m_cb - > getPath ( hpos , currentPos , h - > h , path ) | | path . nodes [ 0 ] . dist > h - > remainingMovement ) //it better be reachable from the hero
continue ;
int count = 0 ;
for ( int xx = - 1 ; xx < = 1 ; xx + + )
for ( int yy = - 1 ; yy < = 1 ; yy + + )
{
checkPos = currentPos + int3 ( xx , yy , 0 ) ;
if ( cg . m_cb - > getPath ( currentPos , checkPos , h - > h , path ) )
count + + ;
}
if ( count > howGood )
{
howGood = count ;
bestPos = currentPos ;
}
}
destination = bestPos ;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2009-08-21 21:18:52 +03:00
cg . m_cb - > getPath ( hpos , destination , h - > h , path ) ;
path . convert ( 0 ) ;
2009-08-05 12:46:55 +03:00
break ;
2009-08-06 12:52:07 +03:00
case visit : case attack :
2009-08-07 11:41:40 +03:00
2009-08-21 21:18:52 +03:00
h = whoCanAchieve . front ( ) ; //lowest cost hero
2009-08-19 13:18:14 +03:00
h - > previouslyVisited_pos = object - > getSightCenter ( ) ;
2009-08-05 12:46:55 +03:00
hpos = h - > pos ;
destination = object - > getSightCenter ( ) ;
break ;
}
2009-08-19 13:18:14 +03:00
if ( type = = visit | | type = = finishTurn | | type = = attack )
2009-08-05 12:46:55 +03:00
if ( cg . m_cb - > getPath ( hpos , destination , h - > h , path ) )
{
path . convert ( 0 ) ;
if ( cg . m_state . get ( ) ! = NO_BATTLE )
cg . m_state . waitUntil ( NO_BATTLE ) ; //wait for battle end
//wait over, battle over too. hero might be killed. check.
for ( int i = path . nodes . size ( ) - 2 ; i > = 0 & & ( cg . m_cb - > getHeroSerial ( h - > h ) > = 0 ) ; i - - )
{
cg . m_cb - > moveHero ( h - > h , path . nodes [ i ] . coord ) ;
if ( cg . m_state . get ( ) ! = NO_BATTLE )
cg . m_state . waitUntil ( NO_BATTLE ) ; //wait for battle end
2009-08-04 01:15:13 +03:00
}
2009-08-05 12:46:55 +03:00
h - > remainingMovement - = path . nodes [ 0 ] . dist ;
if ( object - > blockVisit )
h - > pos = path . nodes [ 1 ] . coord ;
else
h - > pos = destination ;
std : : set < AIObjectContainer > : : iterator i = hgs . knownVisitableObjects . find ( AIObjectContainer ( object ) ) ;
if ( i ! = hgs . knownVisitableObjects . end ( ) )
hgs . knownVisitableObjects . erase ( i ) ;
2009-08-04 01:15:13 +03:00
}
2009-08-06 12:52:07 +03:00
const CGTownInstance * town = dynamic_cast < const CGTownInstance * > ( object ) ;
if ( town & & object - > getOwner ( ) = = cg . m_cb - > getMyColor ( ) )
{
//upgrade hero's units
cout < < " visiting town " < < endl ;
CCreatureSet hcreatures = h - > h - > army ;
for ( std : : map < si32 , std : : pair < ui32 , si32 > > : : const_iterator i = hcreatures . slots . begin ( ) ; i ! = hcreatures . slots . end ( ) ; i + + ) // for each hero slot
{
UpgradeInfo ui = cg . m_cb - > getUpgradeInfo ( h - > h , i - > first ) ;
bool canUpgrade = false ;
if ( ui . newID . size ( ) ! = 0 ) //does this stack need upgrading?
{
canUpgrade = true ;
for ( int ii = 0 ; ii < ui . cost . size ( ) ; ii + + ) //can afford the upgrade?
for ( std : : set < std : : pair < int , int > > : : iterator j = ui . cost [ ii ] . begin ( ) ; j ! = ui . cost [ ii ] . end ( ) ; j + + )
if ( hgs . resourceAmounts [ j - > first ] < j - > second * i - > second . second )
canUpgrade = false ;
}
if ( canUpgrade )
{
cg . m_cb - > upgradeCreature ( h - > h , i - > first , ui . newID . back ( ) ) ;
cout < < " upgrading hero's " < < VLC - > creh - > creatures [ i - > second . first ] . namePl < < endl ;
}
}
//give town's units to hero
CCreatureSet tcreatures = town - > army ;
2009-08-07 11:41:40 +03:00
int weakestCreatureStack ;
int weakestCreatureAIValue = 99999 ;
for ( std : : map < si32 , std : : pair < ui32 , si32 > > : : const_iterator i = tcreatures . slots . begin ( ) ; i ! = tcreatures . slots . end ( ) ; i + + )
if ( VLC - > creh - > creatures [ i - > second . first ] . AIValue < weakestCreatureAIValue )
{
weakestCreatureAIValue = VLC - > creh - > creatures [ i - > second . first ] . AIValue ;
weakestCreatureStack = i - > first ;
}
2009-08-06 12:52:07 +03:00
for ( std : : map < si32 , std : : pair < ui32 , si32 > > : : const_iterator i = tcreatures . slots . begin ( ) ; i ! = tcreatures . slots . end ( ) ; i + + ) // for each town slot
{
hcreatures = h - > h - > army ;
int hSlot = hcreatures . getSlotFor ( i - > second . first ) ;
if ( hSlot = = - 1 ) continue ;
cout < < " giving hero " < < VLC - > creh - > creatures [ i - > second . first ] . namePl < < endl ;
if ( hcreatures . slots . find ( hSlot ) ! = hcreatures . slots . end ( ) )
{
2009-08-07 11:41:40 +03:00
if ( i - > first = = weakestCreatureStack & & town - > garrisonHero ! = NULL ) //can't take garrisonHero's last unit
cg . m_cb - > splitStack ( town , h - > h , i - > first , hSlot , i - > second . second - 1 ) ;
else
cg . m_cb - > mergeStacks ( town , h - > h , i - > first , hSlot ) ; //TODO: the comment says that this code is not safe for the AI.
2009-08-06 12:52:07 +03:00
}
else
{
cg . m_cb - > swapCreatures ( town , h - > h , i - > first , hSlot ) ;
}
}
}
2009-08-05 12:46:55 +03:00
2009-08-04 01:15:13 +03:00
}
2009-08-05 12:46:55 +03:00
2009-08-04 01:15:13 +03:00
void CGeniusAI : : addTownObjectives ( HypotheticalGameState : : TownModel & t , HypotheticalGameState & hgs )
{
//recruitHero
2009-08-05 12:46:55 +03:00
//buildBuilding
2009-08-04 01:15:13 +03:00
//recruitCreatures
//upgradeCreatures
2009-08-04 11:56:38 +03:00
if ( hgs . heroModels . size ( ) < 3 & & hgs . resourceAmounts [ 6 ] > = 2500 ) //recruitHero
2009-08-04 01:15:13 +03:00
{
2009-08-05 12:46:55 +03:00
bool heroAtTown = false ;
for ( int i = 0 ; i < hgs . heroModels . size ( ) ; i + + )
if ( hgs . heroModels [ i ] . pos = = t . t - > getSightCenter ( ) )
heroAtTown = true ;
if ( ! heroAtTown & & vstd : : contains ( t . t - > builtBuildings , 5 ) ) //no visiting hero and built tavern
2009-08-01 05:57:50 +03:00
{
2009-08-04 01:15:13 +03:00
for ( int i = 0 ; i < hgs . AvailableHeroesToBuy . size ( ) ; i + + )
2009-08-06 12:52:07 +03:00
if ( hgs . AvailableHeroesToBuy [ i ] ! = NULL & & ( t . t - > subID = = ( hgs . AvailableHeroesToBuy [ i ] - > type - > heroType / 2 ) ) )
{
2009-08-18 10:37:45 +03:00
TownObjective to ( hgs , AIObjective : : recruitHero , & t , 0 , this ) ;
2009-08-04 01:15:13 +03:00
currentTownObjectives . insert ( to ) ;
}
2009-08-05 12:46:55 +03:00
}
}
//buildBuilding
if ( ! t . hasBuilt )
{
std : : map < int , CBuilding * > thisTownsBuildings = VLC - > buildh - > buildings [ t . t - > subID ] ; // m_cb->getCBuildingsByID(t.t);
for ( std : : map < int , CBuilding * > : : iterator i = thisTownsBuildings . begin ( ) ; i ! = thisTownsBuildings . end ( ) ; i + + )
{
if ( m_cb - > canBuildStructure ( t . t , i - > first ) = = 7 )
{
2009-08-18 10:37:45 +03:00
TownObjective to ( hgs , AIObjective : : buildBuilding , & t , i - > first , this ) ;
2009-08-05 12:46:55 +03:00
currentTownObjectives . insert ( to ) ;
}
2009-08-01 05:57:50 +03:00
}
2009-08-04 01:15:13 +03:00
}
2009-08-05 12:46:55 +03:00
//recruitCreatures
for ( int i = 0 ; i < t . creaturesToRecruit . size ( ) ; i + + )
2009-08-04 11:56:38 +03:00
{
2009-08-07 11:41:40 +03:00
if ( t . creaturesToRecruit [ i ] . first = = 0 | | t . creaturesToRecruit [ i ] . second . empty ( ) ) continue ;
2009-08-05 12:46:55 +03:00
int ID = t . creaturesToRecruit [ i ] . second . back ( ) ;
const CCreature * creature = & VLC - > creh - > creatures [ ID ] ; //m_cb->getCCreatureByID(ID);
bool canAfford = true ;
for ( int ii = 0 ; ii < creature - > cost . size ( ) ; ii + + )
if ( creature - > cost [ ii ] > hgs . resourceAmounts [ ii ] )
2009-08-06 12:52:07 +03:00
canAfford = false ; // can we afford at least one creature?
2009-08-05 12:46:55 +03:00
if ( ! canAfford ) continue ;
//cout << "town has " << t.t->creatures[i].first << " "<< creature->namePl << " (AI Strength " << creature->AIValue << ")." << endl;
2009-08-18 10:37:45 +03:00
TownObjective to ( hgs , AIObjective : : recruitCreatures , & t , i , this ) ;
2009-08-05 12:46:55 +03:00
currentTownObjectives . insert ( to ) ;
2009-08-01 05:57:50 +03:00
2009-08-05 12:46:55 +03:00
}
2009-08-21 21:18:52 +03:00
//upgradeCreatures
2009-08-06 12:52:07 +03:00
for ( std : : map < si32 , std : : pair < ui32 , si32 > > : : iterator i = t . creaturesInGarrison . slots . begin ( ) ; i ! = t . creaturesInGarrison . slots . end ( ) ; i + + )
{
UpgradeInfo ui = m_cb - > getUpgradeInfo ( t . t , i - > first ) ;
if ( ui . newID . size ( ) ! = 0 )
{
bool canAfford = true ;
2009-08-21 21:18:52 +03:00
int upgrade_serial = ui . newID . size ( ) - 1 ;
for ( std : : set < std : : pair < int , int > > : : iterator j = ui . cost [ upgrade_serial ] . begin ( ) ; j ! = ui . cost [ upgrade_serial ] . end ( ) ; j + + )
if ( hgs . resourceAmounts [ j - > first ] < j - > second * i - > second . second )
canAfford = false ;
2009-08-06 12:52:07 +03:00
if ( canAfford )
{
2009-08-18 10:37:45 +03:00
TownObjective to ( hgs , AIObjective : : upgradeCreatures , & t , i - > first , this ) ;
2009-08-06 12:52:07 +03:00
currentTownObjectives . insert ( to ) ;
}
}
}
2009-08-04 01:15:13 +03:00
}
2009-08-04 11:56:38 +03:00
void CGeniusAI : : TownObjective : : fulfill ( CGeniusAI & cg , HypotheticalGameState & hgs )
2009-08-04 01:15:13 +03:00
{
2009-08-06 12:52:07 +03:00
cg . m_cb - > waitTillRealize = true ;
2009-08-05 12:46:55 +03:00
CBuilding * b ;
const CCreature * creature ;
HypotheticalGameState : : HeroModel hm ;
2009-08-06 12:52:07 +03:00
int ID , howMany , newID , hSlot ;
2009-08-04 01:15:13 +03:00
switch ( type )
{
case recruitHero :
cg . m_cb - > recruitHero ( whichTown - > t , hgs . AvailableHeroesToBuy [ which ] ) ;
2009-08-05 12:46:55 +03:00
hm = HypotheticalGameState : : HeroModel ( hgs . AvailableHeroesToBuy [ which ] ) ;
hm . pos = whichTown - > t - > getSightCenter ( ) ;
hm . remainingMovement = hm . h - > maxMovePoints ( true ) ;
hgs . heroModels . push_back ( hm ) ;
hgs . resourceAmounts [ 6 ] - = 2500 ;
break ;
case buildBuilding :
2009-08-06 12:52:07 +03:00
b = VLC - > buildh - > buildings [ whichTown - > t - > subID ] [ which ] ;
2009-08-05 12:46:55 +03:00
if ( cg . m_cb - > canBuildStructure ( whichTown - > t , which ) = = 7 )
2009-08-01 05:57:50 +03:00
{
2009-08-05 12:46:55 +03:00
cout < < " built " < < b - > Name ( ) < < " . " < < endl ;
2009-08-06 12:52:07 +03:00
if ( ! cg . m_cb - > buildBuilding ( whichTown - > t , which ) ) cout < < " really tried to build unbuildable building " < < endl ;
2009-08-05 12:46:55 +03:00
for ( int i = 0 ; b & & i < b - > resources . size ( ) ; i + + )
hgs . resourceAmounts [ i ] - = b - > resources [ i ] ;
2009-08-01 05:57:50 +03:00
}
2009-08-06 12:52:07 +03:00
else cout < < " trying to build a structure we cannot build " < < endl ;
whichTown - > hasBuilt = true ;
2009-08-05 12:46:55 +03:00
break ;
2009-08-06 12:59:33 +03:00
2009-08-05 12:46:55 +03:00
case recruitCreatures :
2009-08-06 12:52:07 +03:00
ID = whichTown - > creaturesToRecruit [ which ] . second . back ( ) ; //buy upgraded if possible
creature = & VLC - > creh - > creatures [ ID ] ;
howMany = whichTown - > creaturesToRecruit [ which ] . first ;
2009-08-05 12:46:55 +03:00
for ( int i = 0 ; i < creature - > cost . size ( ) ; i + + )
2009-08-08 09:13:56 +03:00
amin ( howMany , creature - > cost [ i ] ? hgs . resourceAmounts [ i ] / creature - > cost [ i ] : INT_MAX ) ;
2009-08-05 12:46:55 +03:00
if ( howMany = = 0 ) cout < < " tried to recruit without enough money. " ;
cout < < " recruiting " < < howMany < < " " < < creature - > namePl < < " (Total AI Strength " < < creature - > AIValue * howMany < < " ). " < < endl ;
cg . m_cb - > recruitCreatures ( whichTown - > t , ID , howMany ) ;
break ;
2009-08-06 12:52:07 +03:00
case upgradeCreatures :
UpgradeInfo ui = cg . m_cb - > getUpgradeInfo ( whichTown - > t , which ) ;
ID = whichTown - > creaturesInGarrison . slots [ which ] . first ;
newID = ui . newID . back ( ) ;
cg . m_cb - > upgradeCreature ( whichTown - > t , which , newID ) ; //TODO: reduce resources in hgs
cout < < " upgrading " < < VLC - > creh - > creatures [ ID ] . namePl < < endl ;
break ;
2009-08-05 12:46:55 +03:00
2009-08-01 05:57:50 +03:00
2009-08-04 01:15:13 +03:00
}
2009-08-05 12:46:55 +03:00
2009-08-01 05:57:50 +03:00
}
2009-08-04 11:56:38 +03:00
void CGeniusAI : : fillObjectiveQueue ( HypotheticalGameState & hgs )
{
objectiveQueue . clear ( ) ;
currentHeroObjectives . clear ( ) ;
currentTownObjectives . clear ( ) ;
for ( std : : vector < CGeniusAI : : HypotheticalGameState : : HeroModel > : : iterator i = hgs . heroModels . begin ( ) ; i ! = hgs . heroModels . end ( ) ; i + + )
addHeroObjectives ( * i , hgs ) ;
for ( std : : vector < CGeniusAI : : HypotheticalGameState : : TownModel > : : iterator i = hgs . townModels . begin ( ) ; i ! = hgs . townModels . end ( ) ; i + + )
addTownObjectives ( * i , hgs ) ;
2009-08-18 10:37:45 +03:00
2009-08-04 11:56:38 +03:00
for ( std : : set < CGeniusAI : : HeroObjective > : : iterator i = currentHeroObjectives . begin ( ) ; i ! = currentHeroObjectives . end ( ) ; i + + )
2009-08-12 05:08:59 +03:00
objectiveQueue . push_back ( AIObjectivePtrCont ( ( CGeniusAI : : HeroObjective * ) & ( * i ) ) ) ;
2009-08-04 11:56:38 +03:00
for ( std : : set < CGeniusAI : : TownObjective > : : iterator i = currentTownObjectives . begin ( ) ; i ! = currentTownObjectives . end ( ) ; i + + )
2009-08-12 05:08:59 +03:00
objectiveQueue . push_back ( AIObjectivePtrCont ( ( CGeniusAI : : TownObjective * ) & ( * i ) ) ) ;
2009-08-04 11:56:38 +03:00
}
2009-08-18 10:37:45 +03:00
2009-08-04 11:56:38 +03:00
CGeniusAI : : AIObjective * CGeniusAI : : getBestObjective ( )
{
2009-08-06 12:52:07 +03:00
trueGameState . update ( * this ) ;
2009-08-04 11:56:38 +03:00
fillObjectiveQueue ( trueGameState ) ;
2009-08-07 11:41:40 +03:00
// if(!objectiveQueue.empty())
// return max_element(objectiveQueue.begin(),objectiveQueue.end())->obj;
2009-08-18 10:37:45 +03:00
m_priorities - > fillFeatures ( trueGameState ) ;
2009-08-07 11:41:40 +03:00
if ( objectiveQueue . empty ( ) ) return NULL ;
2009-08-19 13:18:14 +03:00
// sort(objectiveQueue.begin(),objectiveQueue.end());
// reverse(objectiveQueue.begin(),objectiveQueue.end());
2009-08-07 11:41:40 +03:00
int num = 1 ;
2009-08-18 10:37:45 +03:00
// for(std::vector<AIObjectivePtrCont> ::iterator i = objectiveQueue.begin(); i < objectiveQueue.end();i++)
// {
// if(!dynamic_cast<HeroObjective*>(i->obj))continue;
// cout << num++ << ": ";
// i->obj->print();
// cout << " value: " << i->obj->getValue();
// cout << endl;
// }
// int choice = 0;
// cout << "which would you do? (enter 0 for none): ";
// cin >> choice;
cout < < " doing best of " < < objectiveQueue . size ( ) < < " " ;
2009-08-19 13:18:14 +03:00
CGeniusAI : : AIObjective * best = max_element ( objectiveQueue . begin ( ) , objectiveQueue . end ( ) ) - > obj ;
best - > print ( ) ;
cout < < " value = " < < best - > getValue ( ) < < endl ;
if ( ! objectiveQueue . empty ( ) )
return best ;
2009-08-07 11:41:40 +03:00
return objectiveQueue . front ( ) . obj ;
2009-08-04 11:56:38 +03:00
}
2008-11-25 20:51:44 +02:00
void CGeniusAI : : yourTurn ( )
{
2009-08-06 12:52:07 +03:00
static boost : : mutex mutex ;
boost : : mutex : : scoped_lock lock ( mutex ) ;
2009-08-05 12:46:55 +03:00
m_cb - > waitTillRealize = true ;
2009-08-04 01:15:13 +03:00
static int seed = rand ( ) ;
srand ( seed ) ;
2009-08-06 12:52:07 +03:00
if ( m_cb - > getDate ( ) = = 1 )
2009-08-04 01:15:13 +03:00
{
2009-08-07 11:41:40 +03:00
// startFirstTurn();
2009-08-06 12:52:07 +03:00
2009-08-07 11:41:40 +03:00
// m_cb->endTurn();
// return;
2009-08-04 01:15:13 +03:00
}
2009-08-04 11:56:38 +03:00
//////////////TODO: replace with updates. Also add suspected objects list./////////
2009-08-04 01:15:13 +03:00
knownVisitableObjects . clear ( ) ;
int3 pos = m_cb - > getMapSize ( ) ;
for ( int x = 0 ; x < pos . x ; x + + )
for ( int y = 0 ; y < pos . y ; y + + )
for ( int z = 0 ; z < pos . z ; z + + )
tileRevealed ( int3 ( x , y , z ) ) ;
2009-08-04 11:56:38 +03:00
///////////////////////////////////////////////////////////////////////////////////
2009-08-04 01:15:13 +03:00
2009-08-04 12:40:57 +03:00
reportResources ( ) ;
2009-08-06 12:52:07 +03:00
trueGameState = HypotheticalGameState ( * this ) ;
2009-08-01 05:57:50 +03:00
2009-08-04 11:56:38 +03:00
AIObjective * objective ;
while ( ( objective = getBestObjective ( ) ) ! = NULL )
objective - > fulfill ( * this , trueGameState ) ;
2009-08-01 05:57:50 +03:00
2009-08-04 01:15:13 +03:00
seed = rand ( ) ;
2008-11-25 20:51:44 +02:00
m_cb - > endTurn ( ) ;
2009-08-05 12:46:55 +03:00
m_cb - > waitTillRealize = false ;
2008-11-25 20:51:44 +02:00
}
2009-08-18 10:37:45 +03:00
/*
2009-08-06 12:52:07 +03:00
void CGeniusAI : : startFirstTurn ( )
{
2009-08-07 11:41:40 +03:00
2009-08-06 12:52:07 +03:00
HypotheticalGameState hgs ( * this ) ;
const CGTownInstance * town = m_cb - > getTownInfo ( 0 , 0 ) ;
const CGHeroInstance * heroInst = m_cb - > getHeroInfo ( 0 , 0 ) ;
2009-08-18 10:37:45 +03:00
TownObjective ( hgs , AIObjective : : recruitHero , & hgs . townModels . front ( ) , 0 , this ) . fulfill ( * this , hgs ) ;
2009-08-06 12:52:07 +03:00
m_cb - > swapGarrisonHero ( town ) ;
hgs . update ( * this ) ;
for ( int i = 0 ; i < hgs . townModels . front ( ) . creaturesToRecruit . size ( ) ; i + + )
{
if ( hgs . townModels . front ( ) . creaturesToRecruit [ i ] . first = = 0 ) continue ;
int ID = hgs . townModels . front ( ) . creaturesToRecruit [ i ] . second . back ( ) ;
const CCreature * creature = & VLC - > creh - > creatures [ ID ] ;
bool canAfford = true ;
for ( int ii = 0 ; ii < creature - > cost . size ( ) ; ii + + )
if ( creature - > cost [ ii ] > hgs . resourceAmounts [ ii ] )
canAfford = false ; // can we afford at least one creature?
if ( ! canAfford ) continue ;
2009-08-18 10:37:45 +03:00
TownObjective ( hgs , AIObjective : : recruitCreatures , & hgs . townModels . front ( ) , i , this ) . fulfill ( * this , hgs ) ;
2009-08-06 12:52:07 +03:00
}
hgs . update ( * this ) ;
HypotheticalGameState : : HeroModel * hero ;
for ( int i = 0 ; i < hgs . heroModels . size ( ) ; i + + )
if ( hgs . heroModels [ i ] . h - > id = = heroInst - > id )
2009-08-18 10:37:45 +03:00
HeroObjective ( hgs , AIObjective : : visit , town , hero = & hgs . heroModels [ i ] , this ) . fulfill ( * this , hgs ) ;
2009-08-06 12:52:07 +03:00
hgs . update ( * this ) ;
2009-08-07 11:41:40 +03:00
// m_cb->swapGarrisonHero(town);
2009-08-06 12:52:07 +03:00
//TODO: choose the strongest hero.
2009-08-07 11:41:40 +03:00
2009-08-06 12:52:07 +03:00
}
2009-08-18 10:37:45 +03:00
*/
2009-08-01 05:57:50 +03:00
void CGeniusAI : : heroKilled ( const CGHeroInstance * hero )
2008-11-25 20:51:44 +02:00
{
2009-08-01 05:57:50 +03:00
2008-11-25 20:51:44 +02:00
}
2009-08-01 05:57:50 +03:00
void CGeniusAI : : heroCreated ( const CGHeroInstance * hero )
2008-11-25 20:51:44 +02:00
{
2009-08-01 05:57:50 +03:00
2008-11-25 20:51:44 +02:00
}
2009-08-04 01:15:13 +03:00
void CGeniusAI : : tileRevealed ( int3 pos )
2008-11-25 20:51:44 +02:00
{
2009-08-04 01:15:13 +03:00
std : : vector < const CGObjectInstance * > objects = m_cb - > getVisitableObjs ( pos ) ;
for ( std : : vector < const CGObjectInstance * > : : iterator o = objects . begin ( ) ; o ! = objects . end ( ) ; o + + )
2009-08-07 11:41:40 +03:00
if ( ( * o ) - > id ! = - 1 )
knownVisitableObjects . insert ( * o ) ;
2009-08-04 01:15:13 +03:00
objects = m_cb - > getFlaggableObjects ( pos ) ;
for ( std : : vector < const CGObjectInstance * > : : iterator o = objects . begin ( ) ; o ! = objects . end ( ) ; o + + )
2009-08-07 11:41:40 +03:00
if ( ( * o ) - > id ! = - 1 )
knownVisitableObjects . insert ( * o ) ;
2009-08-04 01:15:13 +03:00
}
2009-08-01 05:57:50 +03:00
2009-08-04 11:56:38 +03:00
void CGeniusAI : : newObject ( const CGObjectInstance * obj ) //eg. ship built in shipyard
2009-08-04 01:15:13 +03:00
{
2009-08-04 11:56:38 +03:00
knownVisitableObjects . insert ( obj ) ;
}
2009-08-01 05:57:50 +03:00
2009-08-04 11:56:38 +03:00
void CGeniusAI : : objectRemoved ( const CGObjectInstance * obj ) //eg. collected resource, picked artifact, beaten hero
{
std : : set < AIObjectContainer > : : iterator o = knownVisitableObjects . find ( obj ) ;
if ( o ! = knownVisitableObjects . end ( ) )
knownVisitableObjects . erase ( o ) ;
}
void CGeniusAI : : tileHidden ( int3 pos )
{
2008-11-25 20:51:44 +02:00
}
2009-08-04 01:15:13 +03:00
void CGeniusAI : : heroMoved ( const TryMoveHero & TMH )
{
2009-08-04 11:56:38 +03:00
//DbgBox("** CGeniusAI::heroMoved **");
2009-08-04 01:15:13 +03:00
}
2008-11-25 20:51:44 +02:00
void CGeniusAI : : heroGotLevel ( const CGHeroInstance * hero , int pskill , std : : vector < ui16 > & skills , boost : : function < void ( ui32 ) > & callback )
{
callback ( rand ( ) % skills . size ( ) ) ;
}
2009-04-11 04:32:50 +03:00
2009-04-12 03:58:41 +03:00
void GeniusAI : : CGeniusAI : : showGarrisonDialog ( const CArmedInstance * up , const CGHeroInstance * down , boost : : function < void ( ) > & onEnd )
{
onEnd ( ) ;
}
2009-08-04 02:53:18 +03:00
void GeniusAI : : CGeniusAI : : playerBlocked ( int reason )
{
if ( reason = = 0 ) //battle is coming...
{
m_state . setn ( UPCOMING_BATTLE ) ;
}
}
void GeniusAI : : CGeniusAI : : battleResultsApplied ( )
{
assert ( m_state . get ( ) = = ENDING_BATTLE ) ;
m_state . setn ( NO_BATTLE ) ;
}
2009-05-10 11:15:30 +03:00
void CGeniusAI : : showBlockingDialog ( const std : : string & text , const std : : vector < Component > & components , ui32 askID , const int soundID , bool selection , bool cancel )
2009-04-11 04:32:50 +03:00
{
m_cb - > selectionMade ( cancel ? 0 : 1 , askID ) ;
}
2008-11-25 20:51:44 +02:00
/**
* occurs AFTER every action taken by any stack or by the hero
*/
void CGeniusAI : : actionFinished ( const BattleAction * action )
{
std : : string message ( " \t \t CGeniusAI::actionFinished - type( " ) ;
message + = boost : : lexical_cast < std : : string > ( ( unsigned ) action - > actionType ) ;
message + = " ), side( " ;
message + = boost : : lexical_cast < std : : string > ( ( unsigned ) action - > side ) ;
message + = " ) " ;
2009-08-04 01:15:13 +03:00
DbgBox ( message . c_str ( ) ) ;
2008-11-25 20:51:44 +02:00
}
/**
* occurs BEFORE every action taken by any stack or by the hero
*/
void CGeniusAI : : actionStarted ( const BattleAction * action )
{
std : : string message ( " \t \t CGeniusAI::actionStarted - type( " ) ;
message + = boost : : lexical_cast < std : : string > ( ( unsigned ) action - > actionType ) ;
message + = " ), side( " ;
message + = boost : : lexical_cast < std : : string > ( ( unsigned ) action - > side ) ;
message + = " ) " ;
2009-08-04 01:15:13 +03:00
DbgBox ( message . c_str ( ) ) ;
2008-11-25 20:51:44 +02:00
}
/**
* called when stack is performing attack
*/
void CGeniusAI : : battleAttack ( BattleAttack * ba )
{
2009-08-04 01:15:13 +03:00
DbgBox ( " \t \t \t CGeniusAI::battleAttack " ) ;
2008-11-25 20:51:44 +02:00
}
/**
* called when stack receives damage ( after battleAttack ( ) )
*/
2009-03-21 14:49:58 +02:00
void CGeniusAI : : battleStacksAttacked ( std : : set < BattleStackAttacked > & bsa )
2008-11-25 20:51:44 +02:00
{
2009-08-04 01:15:13 +03:00
DbgBox ( " \t \t \t CGeniusAI::battleStacksAttacked " ) ;
2008-11-25 20:51:44 +02:00
}
/**
* called by engine when battle starts ; side = 0 - left , side = 1 - right
*/
2009-08-01 05:57:50 +03:00
2008-11-25 20:51:44 +02:00
void CGeniusAI : : battleStart ( CCreatureSet * army1 , CCreatureSet * army2 , int3 tile , CGHeroInstance * hero1 , CGHeroInstance * hero2 , bool side )
{
2009-08-04 02:53:18 +03:00
assert ( ! m_battleLogic ) ;
assert ( playerID > PLAYER_LIMIT | | m_state . get ( ) = = UPCOMING_BATTLE ) ; //we have been informed that battle will start (or we are neutral AI)
m_state . setn ( ONGOING_BATTLE ) ;
2009-05-10 11:15:30 +03:00
m_battleLogic = new BattleAI : : CBattleLogic ( m_cb , army1 , army2 , tile , hero1 , hero2 , side ) ;
2008-11-25 20:51:44 +02:00
2009-08-04 01:15:13 +03:00
DbgBox ( " ** CGeniusAI::battleStart ** " ) ;
2008-11-25 20:51:44 +02:00
}
/**
*
*/
void CGeniusAI : : battleEnd ( BattleResult * br )
{
2009-08-21 21:18:52 +03:00
2009-08-06 12:52:07 +03:00
switch ( br - > winner )
2009-08-01 05:57:50 +03:00
{
case 0 : std : : cout < < " The winner is the attacker. " < < std : : endl ; break ;
case 1 : std : : cout < < " The winner is the defender. " < < std : : endl ; break ;
case 2 : std : : cout < < " It's a draw. " < < std : : endl ; break ;
2009-08-06 12:52:07 +03:00
} ;
2009-08-21 21:18:52 +03:00
cout < < " lost " ;
for ( std : : set < std : : pair < ui32 , si32 > > : : iterator i = br - > casualties [ 0 ] . begin ( ) ; i ! = br - > casualties [ 0 ] . end ( ) ; i + + )
cout < < i - > second < < " " < < VLC - > creh - > creatures [ i - > first ] . namePl < < endl ;
2008-11-25 20:51:44 +02:00
delete m_battleLogic ;
m_battleLogic = NULL ;
2009-08-04 02:53:18 +03:00
assert ( m_state . get ( ) = = ONGOING_BATTLE ) ;
m_state . setn ( ENDING_BATTLE ) ;
2009-08-04 01:15:13 +03:00
DbgBox ( " ** CGeniusAI::battleEnd ** " ) ;
2008-11-25 20:51:44 +02:00
}
/**
* called at the beggining of each turn , round = - 1 is the tactic phase , round = 0 is the first " normal " turn
*/
void CGeniusAI : : battleNewRound ( int round )
{
std : : string message ( " \t CGeniusAI::battleNewRound - " ) ;
message + = boost : : lexical_cast < std : : string > ( round ) ;
2009-08-04 01:15:13 +03:00
DbgBox ( message . c_str ( ) ) ;
2008-11-25 20:51:44 +02:00
m_battleLogic - > SetCurrentTurn ( round ) ;
}
/**
*
*/
2009-03-31 23:47:53 +03:00
void CGeniusAI : : battleStackMoved ( int ID , int dest , int distance , bool end )
2008-11-25 20:51:44 +02:00
{
std : : string message ( " \t \t \t CGeniusAI::battleStackMoved ID( " ) ;
message + = boost : : lexical_cast < std : : string > ( ID ) ;
message + = " ), dest( " ;
message + = boost : : lexical_cast < std : : string > ( dest ) ;
message + = " ) " ;
2009-08-04 01:15:13 +03:00
DbgBox ( message . c_str ( ) ) ;
2008-11-25 20:51:44 +02:00
}
/**
*
*/
2009-05-12 06:35:51 +03:00
void CGeniusAI : : battleSpellCast ( SpellCast * sc )
2008-11-25 20:51:44 +02:00
{
2009-08-04 01:15:13 +03:00
DbgBox ( " \t \t \t CGeniusAI::battleSpellCast " ) ;
2008-11-25 20:51:44 +02:00
}
/**
* called when battlefield is prepared , prior the battle beginning
*/
void CGeniusAI : : battlefieldPrepared ( int battlefieldType , std : : vector < CObstacle * > obstacles )
{
2009-08-04 01:15:13 +03:00
DbgBox ( " CGeniusAI::battlefieldPrepared " ) ;
2008-11-25 20:51:44 +02:00
}
/**
*
*/
void CGeniusAI : : battleStackMoved ( int ID , int dest , bool startMoving , bool endMoving )
{
2009-08-04 01:15:13 +03:00
DbgBox ( " \t \t \t CGeniusAI::battleStackMoved " ) ;
2008-11-25 20:51:44 +02:00
}
/**
*
*/
void CGeniusAI : : battleStackAttacking ( int ID , int dest )
{
2009-08-04 01:15:13 +03:00
DbgBox ( " \t \t \t CGeniusAI::battleStackAttacking " ) ;
2008-11-25 20:51:44 +02:00
}
/**
*
*/
void CGeniusAI : : battleStackIsAttacked ( int ID , int dmg , int killed , int IDby , bool byShooting )
{
2009-08-04 01:15:13 +03:00
DbgBox ( " \t \t \t CGeniusAI::battleStackIsAttacked " ) ;
2008-11-25 20:51:44 +02:00
}
/**
* called when it ' s turn of that stack
*/
2009-02-08 17:39:26 +02:00
BattleAction CGeniusAI : : activeStack ( int stackID )
2008-11-25 20:51:44 +02:00
{
std : : string message ( " \t \t \t CGeniusAI::activeStack stackID( " ) ;
2009-02-08 17:39:26 +02:00
2008-11-25 20:51:44 +02:00
message + = boost : : lexical_cast < std : : string > ( stackID ) ;
message + = " ) " ;
2009-08-04 01:15:13 +03:00
DbgBox ( message . c_str ( ) ) ;
2008-11-25 20:51:44 +02:00
return m_battleLogic - > MakeDecision ( stackID ) ;
} ;