1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-08 00:39:47 +02:00

Fixed and improved disband-logic

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.
This commit is contained in:
Xilmi 2024-12-13 00:09:10 +01:00
parent 2ad9038709
commit fac18d953e
3 changed files with 39 additions and 12 deletions

View File

@ -309,9 +309,7 @@ std::vector<creInfo> ArmyManager::getArmyAvailableToBuy(
? dynamic_cast<const CGTownInstance *>(dwelling)
: nullptr;
// Keep track of the least valuable slot in the hero's army
SlotID leastValuableSlot;
int leastValuableStackMarketValue = std::numeric_limits<int>::max();
std::set<SlotID> alreadyDisbanded;
for(int i = dwelling->creatures.size() - 1; i >= 0; i--)
{
@ -327,9 +325,15 @@ std::vector<creInfo> ArmyManager::getArmyAvailableToBuy(
if(!ci.count) continue;
// Calculate the market value of the new stack
int newStackMarketValue = ci.creID.toCreature()->getFullRecruitCost().marketValue() * ci.count;
TResources newStackValue = ci.creID.toCreature()->getFullRecruitCost() * ci.count;
SlotID dst = hero->getSlotFor(ci.creID);
// Keep track of the least valuable slot in the hero's army
SlotID leastValuableSlot;
TResources leastValuableStackValue;
leastValuableStackValue[6] = std::numeric_limits<int>::max();
bool shouldDisband = false;
if(!hero->hasStackAtSlot(dst)) //need another new slot for this stack
{
if(!freeHeroSlots) // No free slots; consider replacing
@ -337,24 +341,33 @@ std::vector<creInfo> ArmyManager::getArmyAvailableToBuy(
// Check for the least valuable existing stack
for (auto& slot : hero->Slots())
{
if (alreadyDisbanded.find(slot.first) != alreadyDisbanded.end())
continue;
if(slot.second->getCreatureID() != CreatureID::NONE)
{
int currentStackMarketValue =
slot.second->getCreatureID().toCreature()->getFullRecruitCost().marketValue() * slot.second->getCount();
TResources currentStackValue = slot.second->getCreatureID().toCreature()->getFullRecruitCost() * slot.second->getCount();
if(currentStackMarketValue < leastValuableStackMarketValue)
if (town && slot.second->getCreatureID().toCreature()->getFactionID() == town->getFactionID())
continue;
if(currentStackValue.marketValue() < leastValuableStackValue.marketValue())
{
leastValuableStackMarketValue = currentStackMarketValue;
leastValuableStackValue = currentStackValue;
leastValuableSlot = slot.first;
}
}
}
// Decide whether to replace the least valuable stack
if(newStackMarketValue <= leastValuableStackMarketValue)
if(newStackValue.marketValue() <= leastValuableStackValue.marketValue())
{
continue; // Skip if the new stack isn't worth replacing
}
else
{
shouldDisband = true;
}
}
else
{
@ -364,7 +377,18 @@ std::vector<creInfo> ArmyManager::getArmyAvailableToBuy(
vstd::amin(ci.count, availableRes / ci.creID.toCreature()->getFullRecruitCost()); //max count we can afford
if(!ci.count) continue;
int disbandMalus = 0;
if (shouldDisband)
{
disbandMalus = leastValuableStackValue / ci.creID.toCreature()->getFullRecruitCost();
alreadyDisbanded.insert(leastValuableSlot);
}
ci.count -= disbandMalus;
if(ci.count <= 0)
continue;
ci.level = i; //this is important for Dungeon Summoning Portal
creaturesInDwellings.push_back(ci);

View File

@ -64,7 +64,7 @@ Goals::TGoalVec BuyArmyBehavior::decompose(const Nullkiller * ai) const
if(reinforcement)
{
tasks.push_back(Goals::sptr(Goals::BuyArmy(town, reinforcement).setpriority(5)));
tasks.push_back(Goals::sptr(Goals::BuyArmy(town, reinforcement).setpriority(reinforcement)));
}
}
}

View File

@ -58,7 +58,7 @@ void BuyArmy::accept(AIGateway * ai)
if(ci.count)
{
if (!town->getUpperArmy()->hasStackAtSlot(town->getUpperArmy()->getSlotFor(ci.creID)))
if (town->stacksCount() == GameConstants::ARMY_SIZE)
{
SlotID lowestValueSlot;
int lowestValue = std::numeric_limits<int>::max();
@ -69,6 +69,9 @@ void BuyArmy::accept(AIGateway * ai)
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;