mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-27 21:49:10 +02:00
The score for buying army now scales with the cost of that army. The cost of the units that need to be disbanded in order to hire the new units is subtracted from the army-hiring-score so the AI will prefer hiring armies where the amount of troops to disband is low or non-existent. Fixed a bug that also disbanded troops when there still were free slots available.
104 lines
2.4 KiB
C++
104 lines
2.4 KiB
C++
/*
|
|
* 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"
|
|
#include "../Engine/Nullkiller.h"
|
|
|
|
|
|
namespace NKAI
|
|
{
|
|
|
|
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();
|
|
}
|
|
|
|
void BuyArmy::accept(AIGateway * ai)
|
|
{
|
|
ui64 valueBought = 0;
|
|
//buy the stacks with largest AI value
|
|
|
|
auto upgradeSuccessful = ai->makePossibleUpgrades(town);
|
|
|
|
auto armyToBuy = ai->nullkiller->armyManager->getArmyAvailableToBuy(town->getUpperArmy(), town);
|
|
|
|
if(armyToBuy.empty())
|
|
{
|
|
if(upgradeSuccessful)
|
|
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];
|
|
|
|
if(objid != CreatureID::NONE && ci.creID.getNum() != objid)
|
|
continue;
|
|
|
|
vstd::amin(ci.count, res / ci.creID.toCreature()->getFullRecruitCost());
|
|
|
|
if(ci.count)
|
|
{
|
|
if (town->stacksCount() == GameConstants::ARMY_SIZE)
|
|
{
|
|
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();
|
|
|
|
if (slot.second->getCreatureID().toCreature()->getFactionID() == town->getFactionID())
|
|
continue;
|
|
|
|
if (currentStackMarketValue < lowestValue)
|
|
{
|
|
lowestValue = currentStackMarketValue;
|
|
lowestValueSlot = slot.first;
|
|
}
|
|
}
|
|
}
|
|
if (lowestValueSlot.validSlot())
|
|
{
|
|
cb->dismissCreature(town->getUpperArmy(), lowestValueSlot);
|
|
}
|
|
}
|
|
cb->recruitCreatures(town, town->getUpperArmy(), ci.creID, ci.count, ci.level);
|
|
valueBought += ci.count * ci.creID.toCreature()->getAIValue();
|
|
}
|
|
}
|
|
|
|
if(!valueBought)
|
|
{
|
|
throw cannotFulfillGoalException("No creatures to buy.");
|
|
}
|
|
|
|
if(town->visitingHero && !town->garrisonHero)
|
|
{
|
|
ai->moveHeroToTile(town->visitablePos(), town->visitingHero.get());
|
|
}
|
|
}
|
|
|
|
}
|