mirror of
https://github.com/vcmi/vcmi.git
synced 2025-04-23 12:08:45 +02:00
Nullkiller AI: new prioritization engine stabilization
This commit is contained in:
parent
b261734905
commit
6bebb766a6
@ -192,6 +192,11 @@ std::vector<SlotInfo> AIhelper::getSortedSlots(const CCreatureSet * target, cons
|
|||||||
return armyManager->getSortedSlots(target, source);
|
return armyManager->getSortedSlots(target, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<creInfo> AIhelper::getArmyAvailableToBuy(const CCreatureSet * hero, const CGDwelling * dwelling) const
|
||||||
|
{
|
||||||
|
return armyManager->getArmyAvailableToBuy(hero, dwelling);
|
||||||
|
}
|
||||||
|
|
||||||
int AIhelper::selectBestSkill(const HeroPtr & hero, const std::vector<SecondarySkill> & skills) const
|
int AIhelper::selectBestSkill(const HeroPtr & hero, const std::vector<SecondarySkill> & skills) const
|
||||||
{
|
{
|
||||||
return heroManager->selectBestSkill(hero, skills);
|
return heroManager->selectBestSkill(hero, skills);
|
||||||
|
@ -79,6 +79,7 @@ public:
|
|||||||
std::vector<SlotInfo> getBestArmy(const CCreatureSet * target, const CCreatureSet * source) const override;
|
std::vector<SlotInfo> getBestArmy(const CCreatureSet * target, const CCreatureSet * source) const override;
|
||||||
std::vector<SlotInfo>::iterator getWeakestCreature(std::vector<SlotInfo> & army) const override;
|
std::vector<SlotInfo>::iterator getWeakestCreature(std::vector<SlotInfo> & army) const override;
|
||||||
std::vector<SlotInfo> getSortedSlots(const CCreatureSet * target, const CCreatureSet * source) const override;
|
std::vector<SlotInfo> getSortedSlots(const CCreatureSet * target, const CCreatureSet * source) const override;
|
||||||
|
std::vector<creInfo> getArmyAvailableToBuy(const CCreatureSet * hero, const CGDwelling * dwelling) const override;
|
||||||
|
|
||||||
const std::map<HeroPtr, HeroRole> & getHeroRoles() const override;
|
const std::map<HeroPtr, HeroRole> & getHeroRoles() const override;
|
||||||
HeroRole getHeroRole(const HeroPtr & hero) const override;
|
HeroRole getHeroRole(const HeroPtr & hero) const override;
|
||||||
|
@ -110,23 +110,31 @@ bool ArmyManager::canGetArmy(const CArmedInstance * target, const CArmedInstance
|
|||||||
ui64 ArmyManager::howManyReinforcementsCanBuy(const CCreatureSet * h, const CGDwelling * t) const
|
ui64 ArmyManager::howManyReinforcementsCanBuy(const CCreatureSet * h, const CGDwelling * t) const
|
||||||
{
|
{
|
||||||
ui64 aivalue = 0;
|
ui64 aivalue = 0;
|
||||||
TResources availableRes = cb->getResourceAmount();
|
auto army = getArmyAvailableToBuy(h, t);
|
||||||
int freeHeroSlots = GameConstants::ARMY_SIZE - h->stacksCount();
|
|
||||||
|
|
||||||
for(auto const dc : t->creatures)
|
for(const creInfo & ci : army)
|
||||||
{
|
{
|
||||||
creInfo ci = infoFromDC(dc);
|
aivalue += ci.count * ci.cre->AIValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return aivalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<creInfo> ArmyManager::getArmyAvailableToBuy(const CCreatureSet * hero, const CGDwelling * dwelling) const
|
||||||
|
{
|
||||||
|
auto availableRes = cb->getResourceAmount();
|
||||||
|
std::vector<creInfo> creaturesInDwellings;
|
||||||
|
int freeHeroSlots = GameConstants::ARMY_SIZE - hero->stacksCount();
|
||||||
|
|
||||||
|
for(int i = dwelling->creatures.size() - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
auto ci = infoFromDC(dwelling->creatures[i]);
|
||||||
|
|
||||||
if(!ci.count || ci.creID == -1)
|
if(!ci.count || ci.creID == -1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
vstd::amin(ci.count, availableRes / ci.cre->cost); //max count we can afford
|
SlotID dst = hero->getSlotFor(ci.creID);
|
||||||
|
if(!hero->hasStackAtSlot(dst)) //need another new slot for this stack
|
||||||
if(ci.count && ci.creID != -1) //valid creature at this level
|
|
||||||
{
|
|
||||||
//can be merged with another stack?
|
|
||||||
SlotID dst = h->getSlotFor(ci.creID);
|
|
||||||
if(!h->hasStackAtSlot(dst)) //need another new slot for this stack
|
|
||||||
{
|
{
|
||||||
if(!freeHeroSlots) //no more place for stacks
|
if(!freeHeroSlots) //no more place for stacks
|
||||||
continue;
|
continue;
|
||||||
@ -134,13 +142,17 @@ ui64 ArmyManager::howManyReinforcementsCanBuy(const CCreatureSet * h, const CGDw
|
|||||||
freeHeroSlots--; //new slot will be occupied
|
freeHeroSlots--; //new slot will be occupied
|
||||||
}
|
}
|
||||||
|
|
||||||
//we found matching occupied or free slot
|
vstd::amin(ci.count, availableRes / ci.cre->cost); //max count we can afford
|
||||||
aivalue += ci.count * ci.cre->AIValue;
|
|
||||||
|
if(!ci.count)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ci.level = i; //this is important for Dungeon Summoning Portal
|
||||||
|
creaturesInDwellings.push_back(ci);
|
||||||
availableRes -= ci.cre->cost * ci.count;
|
availableRes -= ci.cre->cost * ci.count;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return aivalue;
|
return creaturesInDwellings;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui64 ArmyManager::howManyReinforcementsCanGet(const CCreatureSet * target, const CCreatureSet * source) const
|
ui64 ArmyManager::howManyReinforcementsCanGet(const CCreatureSet * target, const CCreatureSet * source) const
|
||||||
|
@ -36,6 +36,7 @@ public:
|
|||||||
virtual std::vector<SlotInfo> getBestArmy(const CCreatureSet * target, const CCreatureSet * source) const = 0;
|
virtual std::vector<SlotInfo> getBestArmy(const CCreatureSet * target, const CCreatureSet * source) const = 0;
|
||||||
virtual std::vector<SlotInfo>::iterator getWeakestCreature(std::vector<SlotInfo> & army) const = 0;
|
virtual std::vector<SlotInfo>::iterator getWeakestCreature(std::vector<SlotInfo> & army) const = 0;
|
||||||
virtual std::vector<SlotInfo> getSortedSlots(const CCreatureSet * target, const CCreatureSet * source) const = 0;
|
virtual std::vector<SlotInfo> getSortedSlots(const CCreatureSet * target, const CCreatureSet * source) const = 0;
|
||||||
|
virtual std::vector<creInfo> getArmyAvailableToBuy(const CCreatureSet * hero, const CGDwelling * dwelling) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT ArmyManager : public IArmyManager
|
class DLL_EXPORT ArmyManager : public IArmyManager
|
||||||
@ -54,4 +55,5 @@ public:
|
|||||||
std::vector<SlotInfo> getBestArmy(const CCreatureSet * target, const CCreatureSet * source) const override;
|
std::vector<SlotInfo> getBestArmy(const CCreatureSet * target, const CCreatureSet * source) const override;
|
||||||
std::vector<SlotInfo>::iterator getWeakestCreature(std::vector<SlotInfo> & army) const override;
|
std::vector<SlotInfo>::iterator getWeakestCreature(std::vector<SlotInfo> & army) const override;
|
||||||
std::vector<SlotInfo> getSortedSlots(const CCreatureSet * target, const CCreatureSet * source) const override;
|
std::vector<SlotInfo> getSortedSlots(const CCreatureSet * target, const CCreatureSet * source) const override;
|
||||||
|
std::vector<creInfo> getArmyAvailableToBuy(const CCreatureSet * hero, const CGDwelling * dwelling) const override;
|
||||||
};
|
};
|
||||||
|
@ -103,15 +103,16 @@ void ExecuteHeroChain::accept(VCAI * ai)
|
|||||||
if(!targetNode->accessible || targetNode->turns != 0)
|
if(!targetNode->accessible || targetNode->turns != 0)
|
||||||
{
|
{
|
||||||
logAi->error(
|
logAi->error(
|
||||||
"Enable to complete chain. Expected hero %s to arive to %s but he in 0 turns but he can not do this",
|
"Enable to complete chain. Expected hero %s to arive to %s in 0 turns but he can not do this",
|
||||||
hero.name,
|
hero.name,
|
||||||
node.coord.toString(),
|
node.coord.toString());
|
||||||
hero->visitablePos().toString());
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(hero->movement)
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Goals::VisitTile(node.coord).sethero(hero).accept(ai);
|
Goals::VisitTile(node.coord).sethero(hero).accept(ai);
|
||||||
@ -135,6 +136,7 @@ void ExecuteHeroChain::accept(VCAI * ai)
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(node.turns == 0)
|
if(node.turns == 0)
|
||||||
{
|
{
|
||||||
|
@ -201,11 +201,6 @@ void AINodeStorage::commit(
|
|||||||
int movementLeft,
|
int movementLeft,
|
||||||
float cost) const
|
float cost) const
|
||||||
{
|
{
|
||||||
if(destination->actor->chainMask == 195 && turn == 0)
|
|
||||||
{
|
|
||||||
throw std::exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
destination->action = action;
|
destination->action = action;
|
||||||
destination->cost = cost;
|
destination->cost = cost;
|
||||||
destination->moveRemains = movementLeft;
|
destination->moveRemains = movementLeft;
|
||||||
|
@ -1068,7 +1068,7 @@ void VCAI::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h)
|
|||||||
{
|
{
|
||||||
makePossibleUpgrades(h.get());
|
makePossibleUpgrades(h.get());
|
||||||
|
|
||||||
if(!h->visitedTown->garrisonHero)
|
if(!nullkiller || !h->visitedTown->garrisonHero || !nullkiller->isHeroLocked(h->visitedTown->garrisonHero))
|
||||||
moveCreaturesToHero(h->visitedTown);
|
moveCreaturesToHero(h->visitedTown);
|
||||||
|
|
||||||
townVisitsThisWeek[h].insert(h->visitedTown);
|
townVisitsThisWeek[h].insert(h->visitedTown);
|
||||||
@ -2192,47 +2192,34 @@ void VCAI::tryRealize(Goals::BuyArmy & g)
|
|||||||
|
|
||||||
makePossibleUpgrades(t);
|
makePossibleUpgrades(t);
|
||||||
|
|
||||||
while (valueBought < g.value)
|
auto armyToBuy = ah->getArmyAvailableToBuy(t->getUpperArmy(), t);
|
||||||
|
|
||||||
|
if(armyToBuy.empty())
|
||||||
{
|
{
|
||||||
auto res = ah->allResources();
|
throw cannotFulfillGoalException("No creatures to buy.");
|
||||||
std::vector<creInfo> creaturesInDwellings;
|
|
||||||
|
|
||||||
for (int i = t->creatures.size() - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
auto ci = infoFromDC(t->creatures[i]);
|
|
||||||
|
|
||||||
if(!ci.count
|
|
||||||
|| ci.creID == -1
|
|
||||||
|| (g.objid != -1 && ci.creID != g.objid)
|
|
||||||
|| t->getUpperArmy()->getSlotFor(ci.creID) == SlotID())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
vstd::amin(ci.count, res / ci.cre->cost); //max count we can afford
|
|
||||||
|
|
||||||
if(!ci.count)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ci.level = i; //this is important for Dungeon Summoning Portal
|
|
||||||
creaturesInDwellings.push_back(ci);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (creaturesInDwellings.empty())
|
for (int i = 0; valueBought < g.value && i < armyToBuy.size(); i++)
|
||||||
throw cannotFulfillGoalException("Can't buy any more creatures!");
|
|
||||||
|
|
||||||
creInfo ci =
|
|
||||||
*boost::max_element(creaturesInDwellings, [](const creInfo & lhs, const creInfo & rhs)
|
|
||||||
{
|
{
|
||||||
//max value of creatures we can buy with our res
|
auto res = ah->allResources();
|
||||||
int value1 = lhs.cre->AIValue * lhs.count,
|
auto & ci = armyToBuy[i];
|
||||||
value2 = rhs.cre->AIValue * rhs.count;
|
|
||||||
|
|
||||||
return value1 < value2;
|
if(g.objid != -1 && ci.creID != g.objid)
|
||||||
});
|
continue;
|
||||||
|
|
||||||
|
vstd::amin(ci.count, res / ci.cre->cost);
|
||||||
|
|
||||||
|
if(ci.count)
|
||||||
|
{
|
||||||
cb->recruitCreatures(t, t->getUpperArmy(), ci.creID, ci.count, ci.level);
|
cb->recruitCreatures(t, t->getUpperArmy(), ci.creID, ci.count, ci.level);
|
||||||
valueBought += ci.count * ci.cre->AIValue;
|
valueBought += ci.count * ci.cre->AIValue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!valueBought)
|
||||||
|
{
|
||||||
|
throw cannotFulfillGoalException("No creatures to buy.");
|
||||||
|
}
|
||||||
|
|
||||||
if(t->visitingHero)
|
if(t->visitingHero)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user