2025-08-13 14:41:15 +02:00
/*
* BuyArmy . 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 "BuyArmy.h"
# include "../../../lib/mapObjects/CGTownInstance.h"
# include "../AIGateway.h"
2025-08-13 17:05:30 +02:00
# include "../Engine/Nullkiller.h"
2025-08-13 14:41:15 +02:00
2025-08-13 17:16:27 +02:00
namespace NK2AI
2025-08-13 14:41:15 +02:00
{
using namespace Goals ;
bool BuyArmy : : operator = = ( const BuyArmy & other ) const
{
return town = = other . town & & objid = = other . objid ;
}
std : : string BuyArmy : : toString ( ) const
{
return " Buy army at " + town - > getNameTranslated ( ) ;
}
2025-08-15 18:30:28 +02:00
void BuyArmy : : accept ( AIGateway * aiGw )
2025-08-13 14:41:15 +02:00
{
ui64 valueBought = 0 ;
//buy the stacks with largest AI value
2025-08-15 18:30:28 +02:00
auto upgradeSuccessful = aiGw - > makePossibleUpgrades ( town ) ;
2025-08-13 14:41:15 +02:00
2025-08-15 18:30:28 +02:00
auto armyToBuy = aiGw - > nullkiller - > armyManager - > getArmyAvailableToBuy ( town - > getUpperArmy ( ) , town ) ;
2025-08-13 14:41:15 +02:00
if ( armyToBuy . empty ( ) )
{
if ( upgradeSuccessful )
return ;
throw cannotFulfillGoalException ( " No creatures to buy. " ) ;
}
for ( int i = 0 ; valueBought < value & & i < armyToBuy . size ( ) ; i + + )
{
2025-09-05 18:10:14 +02:00
auto res = aiGw - > cc - > getResourceAmount ( ) ;
2025-08-13 14:41:15 +02:00
auto & ci = armyToBuy [ i ] ;
if ( objid ! = CreatureID : : NONE & & ci . creID . getNum ( ) ! = objid )
continue ;
vstd : : amin ( ci . count , res / ci . creID . toCreature ( ) - > getFullRecruitCost ( ) ) ;
if ( ci . count )
{
if ( town - > getUpperArmy ( ) - > stacksCount ( ) = = GameConstants : : ARMY_SIZE )
{
SlotID lowestValueSlot ;
int lowestValue = std : : numeric_limits < int > : : max ( ) ;
for ( const auto & slot : town - > getUpperArmy ( ) - > Slots ( ) )
{
if ( slot . second - > getCreatureID ( ) ! = CreatureID : : NONE )
{
int currentStackMarketValue =
slot . second - > getCreatureID ( ) . toCreature ( ) - > getFullRecruitCost ( ) . marketValue ( ) * slot . second - > getCount ( ) ;
if ( slot . second - > getCreatureID ( ) . toCreature ( ) - > getFactionID ( ) = = town - > getFactionID ( ) )
continue ;
if ( currentStackMarketValue < lowestValue )
{
lowestValue = currentStackMarketValue ;
lowestValueSlot = slot . first ;
}
}
}
if ( lowestValueSlot . validSlot ( ) )
{
2025-09-05 18:10:14 +02:00
aiGw - > cc - > dismissCreature ( town - > getUpperArmy ( ) , lowestValueSlot ) ;
2025-08-13 14:41:15 +02:00
}
}
if ( town - > getUpperArmy ( ) - > stacksCount ( ) < GameConstants : : ARMY_SIZE | | town - > getUpperArmy ( ) - > getSlotFor ( ci . creID ) . validSlot ( ) ) //It is possible we don't scrap despite we wanted to due to not scrapping stacks that fit our faction
{
2025-09-05 18:10:14 +02:00
aiGw - > cc - > recruitCreatures ( town , town - > getUpperArmy ( ) , ci . creID , ci . count , ci . level ) ;
2025-08-13 14:41:15 +02:00
}
valueBought + = ci . count * ci . creID . toCreature ( ) - > getAIValue ( ) ;
}
}
if ( ! valueBought )
{
throw cannotFulfillGoalException ( " No creatures to buy. " ) ;
}
if ( town - > getVisitingHero ( ) & & ! town - > getGarrisonHero ( ) )
{
2025-09-12 19:25:56 +02:00
aiGw - > moveHeroToTile ( town - > visitablePos ( ) , HeroPtr ( town - > getVisitingHero ( ) , aiGw - > cc . get ( ) ) ) ;
2025-08-13 14:41:15 +02:00
}
}
}