2021-05-15 19:22:44 +03: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
*
*/
2021-05-16 14:55:57 +03:00
# include "../StdInc.h"
2021-05-15 19:22:44 +03:00
# include "BuyArmy.h"
2021-05-15 21:57:44 +03:00
# include "../../../lib/mapObjects/CGTownInstance.h"
2021-05-16 15:39:38 +03:00
# include "../AIGateway.h"
2021-05-16 14:55:57 +03:00
# include "../Engine/Nullkiller.h"
2021-05-15 19:22:44 +03:00
2022-09-26 21:01:07 +03:00
namespace NKAI
{
2021-05-15 19:22:44 +03:00
using namespace Goals ;
bool BuyArmy : : operator = = ( const BuyArmy & other ) const
{
return town = = other . town & & objid = = other . objid ;
}
2021-05-16 14:38:26 +03:00
std : : string BuyArmy : : toString ( ) const
2021-05-15 19:22:44 +03:00
{
2023-01-04 15:17:50 +02:00
return " Buy army at " + town - > getNameTranslated ( ) ;
2021-05-16 14:38:53 +03:00
}
2021-05-16 15:39:38 +03:00
void BuyArmy : : accept ( AIGateway * ai )
2021-05-16 14:38:53 +03:00
{
ui64 valueBought = 0 ;
//buy the stacks with largest AI value
2024-06-24 03:23:26 +02:00
auto upgradeSuccessful = ai - > makePossibleUpgrades ( town ) ;
2021-05-16 14:38:53 +03:00
2020-05-04 18:58:43 +03:00
auto armyToBuy = ai - > nullkiller - > armyManager - > getArmyAvailableToBuy ( town - > getUpperArmy ( ) , town ) ;
2021-05-16 14:38:53 +03:00
if ( armyToBuy . empty ( ) )
{
2024-06-24 03:23:26 +02:00
if ( upgradeSuccessful )
2021-05-16 14:38:53 +03:00
return ;
throw cannotFulfillGoalException ( " No creatures to buy. " ) ;
}
for ( int i = 0 ; valueBought < value & & i < armyToBuy . size ( ) ; i + + )
{
auto res = cb - > getResourceAmount ( ) ;
auto & ci = armyToBuy [ i ] ;
2023-08-19 20:48:28 +03:00
if ( objid ! = CreatureID : : NONE & & ci . creID . getNum ( ) ! = objid )
2021-05-16 14:38:53 +03:00
continue ;
2023-12-31 23:43:35 +02:00
vstd : : amin ( ci . count , res / ci . creID . toCreature ( ) - > getFullRecruitCost ( ) ) ;
2021-05-16 14:38:53 +03:00
if ( ci . count )
{
2024-12-13 12:23:13 +01:00
if ( town - > getUpperArmy ( ) - > stacksCount ( ) = = GameConstants : : ARMY_SIZE )
2024-12-12 20:06:33 +01:00
{
SlotID lowestValueSlot ;
int lowestValue = std : : numeric_limits < int > : : max ( ) ;
for ( auto slot : town - > getUpperArmy ( ) - > Slots ( ) )
{
if ( slot . second - > getCreatureID ( ) ! = CreatureID : : NONE )
{
int currentStackMarketValue =
slot . second - > getCreatureID ( ) . toCreature ( ) - > getFullRecruitCost ( ) . marketValue ( ) * slot . second - > getCount ( ) ;
2024-12-13 00:09:10 +01:00
if ( slot . second - > getCreatureID ( ) . toCreature ( ) - > getFactionID ( ) = = town - > getFactionID ( ) )
continue ;
2024-12-12 20:06:33 +01:00
if ( currentStackMarketValue < lowestValue )
{
lowestValue = currentStackMarketValue ;
lowestValueSlot = slot . first ;
}
}
}
if ( lowestValueSlot . validSlot ( ) )
{
cb - > dismissCreature ( town - > getUpperArmy ( ) , lowestValueSlot ) ;
}
}
2024-12-13 12:23:13 +01: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
{
cb - > recruitCreatures ( town , town - > getUpperArmy ( ) , ci . creID , ci . count , ci . level ) ;
}
2023-12-31 23:43:35 +02:00
valueBought + = ci . count * ci . creID . toCreature ( ) - > getAIValue ( ) ;
2021-05-16 14:38:53 +03:00
}
}
if ( ! valueBought )
{
throw cannotFulfillGoalException ( " No creatures to buy. " ) ;
}
2023-06-04 16:02:02 +03:00
if ( town - > visitingHero & & ! town - > garrisonHero )
2021-05-16 14:38:53 +03:00
{
ai - > moveHeroToTile ( town - > visitablePos ( ) , town - > visitingHero . get ( ) ) ;
}
2022-09-26 21:01:07 +03:00
}
}