2018-12-01 10:30:37 +02:00
/*
* GatherTroops . cpp , part of VCMI engine
*
* 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
*
*/
# include "StdInc.h"
# include "Goals.h"
# include "../VCAI.h"
# include "../AIUtility.h"
# include "../AIhelper.h"
# include "../FuzzyHelper.h"
# include "../ResourceManager.h"
# include "../BuildingManager.h"
2023-05-24 01:05:59 +02:00
# include "../../../lib/mapObjects/CGTownInstance.h"
2023-08-19 23:22:31 +02:00
# include "../../../lib/constants/StringConstants.h"
2018-12-01 10:30:37 +02:00
using namespace Goals ;
bool GatherTroops : : operator = = ( const GatherTroops & other ) const
{
return objid = = other . objid ;
}
int GatherTroops : : getCreaturesCount ( const CArmedInstance * army )
{
int count = 0 ;
for ( auto stack : army - > Slots ( ) )
{
if ( objid = = stack . second - > getCreatureID ( ) . num )
{
count + = stack . second - > count ;
}
}
return count ;
}
TSubgoal GatherTroops : : whatToDoToAchieve ( )
{
2018-12-09 15:20:46 +02:00
logAi - > trace ( " Entering GatherTroops::whatToDoToAchieve " ) ;
2018-12-01 10:30:37 +02:00
auto heroes = cb - > getHeroesInfo ( true ) ;
for ( auto hero : heroes )
{
if ( getCreaturesCount ( hero ) > = this - > value )
{
2023-01-02 13:27:03 +02:00
logAi - > trace ( " Completing GATHER_TROOPS by hero %s " , hero - > getNameTranslated ( ) ) ;
2018-12-01 10:30:37 +02:00
throw goalFulfilledException ( sptr ( * this ) ) ;
}
}
TGoalVec solutions = getAllPossibleSubgoals ( ) ;
if ( solutions . empty ( ) )
return sptr ( Explore ( ) ) ;
return fh - > chooseSolution ( solutions ) ;
}
TGoalVec GatherTroops : : getAllPossibleSubgoals ( )
{
TGoalVec solutions ;
for ( const CGTownInstance * t : cb - > getTownsInfo ( ) )
{
int count = getCreaturesCount ( t - > getUpperArmy ( ) ) ;
if ( count > = this - > value )
{
2019-01-06 22:36:46 +02:00
if ( t - > visitingHero )
{
solutions . push_back ( sptr ( VisitObj ( t - > id . getNum ( ) ) . sethero ( t - > visitingHero . get ( ) ) ) ) ;
}
else
{
vstd : : concatenate ( solutions , ai - > ah - > howToVisitObj ( t ) ) ;
}
2018-12-01 10:30:37 +02:00
continue ;
}
2023-04-05 02:26:29 +02:00
auto creature = VLC - > creatures ( ) - > getByIndex ( objid ) ;
2023-10-28 11:27:10 +02:00
if ( t - > getFaction ( ) = = creature - > getFaction ( ) ) //TODO: how to force AI to build unupgraded creatures? :O
2018-12-01 10:30:37 +02:00
{
2023-04-16 23:24:11 +02:00
auto tryFindCreature = [ & ] ( ) - > std : : optional < std : : vector < CreatureID > >
{
if ( vstd : : isValidIndex ( t - > town - > creatures , creature - > getLevel ( ) - 1 ) )
{
auto itr = t - > town - > creatures . begin ( ) ;
std : : advance ( itr , creature - > getLevel ( ) - 1 ) ;
return make_optional ( * itr ) ;
}
return std : : nullopt ;
} ;
auto creatures = tryFindCreature ( ) ;
2018-12-01 10:30:37 +02:00
if ( ! creatures )
continue ;
2023-04-05 02:26:29 +02:00
int upgradeNumber = vstd : : find_pos ( * creatures , creature - > getId ( ) ) ;
2018-12-01 10:30:37 +02:00
if ( upgradeNumber < 0 )
continue ;
2024-08-05 23:03:19 +02:00
BuildingID bid ( BuildingID : : DWELL_FIRST + creature - > getLevel ( ) - 1 + upgradeNumber * t - > town - > creatures . size ( ) ) ;
2023-04-05 02:26:29 +02:00
if ( t - > hasBuilt ( bid ) & & ai - > ah - > freeResources ( ) . canAfford ( creature - > getFullRecruitCost ( ) ) ) //this assumes only creatures with dwellings are assigned to faction
2018-12-01 10:30:37 +02:00
{
2023-04-05 02:26:29 +02:00
solutions . push_back ( sptr ( BuyArmy ( t , creature - > getAIValue ( ) * this - > value ) . setobjid ( objid ) ) ) ;
2018-12-01 10:30:37 +02:00
}
/*else //disable random building requests for now - this code needs to know a lot of town/resource context to do more good than harm
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
{
2018-12-01 10:30:37 +02:00
return sptr ( BuildThis ( bid , t ) . setpriority ( priority ) ) ;
} */
}
}
2019-05-28 08:04:31 +02:00
2018-12-01 10:30:37 +02:00
for ( auto obj : ai - > visitableObjs )
{
auto d = dynamic_cast < const CGDwelling * > ( obj ) ;
if ( ! d | | obj - > ID = = Obj : : TOWN )
continue ;
for ( auto creature : d - > creatures )
{
if ( creature . first ) //there are more than 0 creatures avaliabe
{
for ( auto type : creature . second )
{
2023-08-19 19:48:28 +02:00
if ( type . getNum ( ) = = objid & & ai - > ah - > freeResources ( ) . canAfford ( VLC - > creatures ( ) - > getById ( type ) - > getFullRecruitCost ( ) ) )
2018-12-01 10:30:37 +02:00
vstd : : concatenate ( solutions , ai - > ah - > howToVisitObj ( obj ) ) ;
}
}
}
}
2019-05-28 08:04:31 +02:00
CreatureID creID = CreatureID ( objid ) ;
2019-05-29 21:07:10 +02:00
vstd : : erase_if ( solutions , [ & ] ( TSubgoal goal ) - > bool
{
2019-05-28 08:04:31 +02:00
return goal - > hero & & ! goal - > hero - > getSlotFor ( creID ) . validSlot ( ) & & ! goal - > hero - > getFreeSlot ( ) . validSlot ( ) ;
} ) ;
2018-12-01 10:30:37 +02:00
return solutions ;
//TODO: exchange troops between heroes
}
bool GatherTroops : : fulfillsMe ( TSubgoal goal )
{
if ( ! hero | | hero = = goal - > hero ) //we got army for desired hero or any hero
if ( goal - > objid = = objid ) //same creature type //TODO: consider upgrades?
if ( goal - > value > = value ) //notify every time we get resources?
return true ;
return false ;
}