mirror of
https://github.com/vcmi/vcmi.git
synced 2025-04-17 11:56:46 +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:
parent
2ad9038709
commit
fac18d953e
@ -309,9 +309,7 @@ std::vector<creInfo> ArmyManager::getArmyAvailableToBuy(
|
|||||||
? dynamic_cast<const CGTownInstance *>(dwelling)
|
? dynamic_cast<const CGTownInstance *>(dwelling)
|
||||||
: nullptr;
|
: nullptr;
|
||||||
|
|
||||||
// Keep track of the least valuable slot in the hero's army
|
std::set<SlotID> alreadyDisbanded;
|
||||||
SlotID leastValuableSlot;
|
|
||||||
int leastValuableStackMarketValue = std::numeric_limits<int>::max();
|
|
||||||
|
|
||||||
for(int i = dwelling->creatures.size() - 1; i >= 0; i--)
|
for(int i = dwelling->creatures.size() - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
@ -327,9 +325,15 @@ std::vector<creInfo> ArmyManager::getArmyAvailableToBuy(
|
|||||||
if(!ci.count) continue;
|
if(!ci.count) continue;
|
||||||
|
|
||||||
// Calculate the market value of the new stack
|
// 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);
|
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(!hero->hasStackAtSlot(dst)) //need another new slot for this stack
|
||||||
{
|
{
|
||||||
if(!freeHeroSlots) // No free slots; consider replacing
|
if(!freeHeroSlots) // No free slots; consider replacing
|
||||||
@ -337,24 +341,33 @@ std::vector<creInfo> ArmyManager::getArmyAvailableToBuy(
|
|||||||
// Check for the least valuable existing stack
|
// Check for the least valuable existing stack
|
||||||
for (auto& slot : hero->Slots())
|
for (auto& slot : hero->Slots())
|
||||||
{
|
{
|
||||||
|
if (alreadyDisbanded.find(slot.first) != alreadyDisbanded.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
if(slot.second->getCreatureID() != CreatureID::NONE)
|
if(slot.second->getCreatureID() != CreatureID::NONE)
|
||||||
{
|
{
|
||||||
int currentStackMarketValue =
|
TResources currentStackValue = slot.second->getCreatureID().toCreature()->getFullRecruitCost() * slot.second->getCount();
|
||||||
slot.second->getCreatureID().toCreature()->getFullRecruitCost().marketValue() * 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;
|
leastValuableSlot = slot.first;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decide whether to replace the least valuable stack
|
// 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
|
continue; // Skip if the new stack isn't worth replacing
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shouldDisband = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -364,7 +377,18 @@ std::vector<creInfo> ArmyManager::getArmyAvailableToBuy(
|
|||||||
|
|
||||||
vstd::amin(ci.count, availableRes / ci.creID.toCreature()->getFullRecruitCost()); //max count we can afford
|
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
|
ci.level = i; //this is important for Dungeon Summoning Portal
|
||||||
creaturesInDwellings.push_back(ci);
|
creaturesInDwellings.push_back(ci);
|
||||||
|
@ -64,7 +64,7 @@ Goals::TGoalVec BuyArmyBehavior::decompose(const Nullkiller * ai) const
|
|||||||
|
|
||||||
if(reinforcement)
|
if(reinforcement)
|
||||||
{
|
{
|
||||||
tasks.push_back(Goals::sptr(Goals::BuyArmy(town, reinforcement).setpriority(5)));
|
tasks.push_back(Goals::sptr(Goals::BuyArmy(town, reinforcement).setpriority(reinforcement)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ void BuyArmy::accept(AIGateway * ai)
|
|||||||
|
|
||||||
if(ci.count)
|
if(ci.count)
|
||||||
{
|
{
|
||||||
if (!town->getUpperArmy()->hasStackAtSlot(town->getUpperArmy()->getSlotFor(ci.creID)))
|
if (town->stacksCount() == GameConstants::ARMY_SIZE)
|
||||||
{
|
{
|
||||||
SlotID lowestValueSlot;
|
SlotID lowestValueSlot;
|
||||||
int lowestValue = std::numeric_limits<int>::max();
|
int lowestValue = std::numeric_limits<int>::max();
|
||||||
@ -69,6 +69,9 @@ void BuyArmy::accept(AIGateway * ai)
|
|||||||
int currentStackMarketValue =
|
int currentStackMarketValue =
|
||||||
slot.second->getCreatureID().toCreature()->getFullRecruitCost().marketValue() * slot.second->getCount();
|
slot.second->getCreatureID().toCreature()->getFullRecruitCost().marketValue() * slot.second->getCount();
|
||||||
|
|
||||||
|
if (slot.second->getCreatureID().toCreature()->getFactionID() == town->getFactionID())
|
||||||
|
continue;
|
||||||
|
|
||||||
if (currentStackMarketValue < lowestValue)
|
if (currentStackMarketValue < lowestValue)
|
||||||
{
|
{
|
||||||
lowestValue = currentStackMarketValue;
|
lowestValue = currentStackMarketValue;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user