mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
#2983б #2910 and a few other bugs fixed
This commit is contained in:
parent
49c872e4ec
commit
cf213a5acf
@ -523,7 +523,7 @@ creInfo infoFromDC(const dwellingContent & dc)
|
|||||||
return ci;
|
return ci;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui64 howManyReinforcementsCanBuy(HeroPtr h, const CGTownInstance * t)
|
ui64 howManyReinforcementsCanBuy(HeroPtr h, const CGDwelling * t)
|
||||||
{
|
{
|
||||||
ui64 aivalue = 0;
|
ui64 aivalue = 0;
|
||||||
|
|
||||||
|
@ -179,7 +179,7 @@ bool compareMovement(HeroPtr lhs, HeroPtr rhs);
|
|||||||
bool compareHeroStrength(HeroPtr h1, HeroPtr h2);
|
bool compareHeroStrength(HeroPtr h1, HeroPtr h2);
|
||||||
bool compareArmyStrength(const CArmedInstance * a1, const CArmedInstance * a2);
|
bool compareArmyStrength(const CArmedInstance * a1, const CArmedInstance * a2);
|
||||||
bool compareArtifacts(const CArtifactInstance * a1, const CArtifactInstance * a2);
|
bool compareArtifacts(const CArtifactInstance * a1, const CArtifactInstance * a2);
|
||||||
ui64 howManyReinforcementsCanBuy(HeroPtr h, const CGTownInstance * t);
|
ui64 howManyReinforcementsCanBuy(HeroPtr h, const CGDwelling * t);
|
||||||
ui64 howManyReinforcementsCanGet(HeroPtr h, const CGTownInstance * t);
|
ui64 howManyReinforcementsCanGet(HeroPtr h, const CGTownInstance * t);
|
||||||
int3 whereToExplore(HeroPtr h);
|
int3 whereToExplore(HeroPtr h);
|
||||||
uint32_t distanceToTile(const CGHeroInstance * hero, int3 pos);
|
uint32_t distanceToTile(const CGHeroInstance * hero, int3 pos);
|
||||||
|
@ -19,8 +19,13 @@ extern boost::thread_specific_ptr<VCAI> ai;
|
|||||||
|
|
||||||
Goals::TSubgoal FuzzyHelper::chooseSolution(Goals::TGoalVec vec)
|
Goals::TSubgoal FuzzyHelper::chooseSolution(Goals::TGoalVec vec)
|
||||||
{
|
{
|
||||||
if(vec.empty()) //no possibilities found
|
if(vec.empty())
|
||||||
|
{
|
||||||
|
logAi->debug("FuzzyHelper found no goals. Returning Goals::Invalid.");
|
||||||
|
|
||||||
|
//no possibilities found
|
||||||
return sptr(Goals::Invalid());
|
return sptr(Goals::Invalid());
|
||||||
|
}
|
||||||
|
|
||||||
//a trick to switch between heroes less often - calculatePaths is costly
|
//a trick to switch between heroes less often - calculatePaths is costly
|
||||||
auto sortByHeroes = [](const Goals::TSubgoal & lhs, const Goals::TSubgoal & rhs) -> bool
|
auto sortByHeroes = [](const Goals::TSubgoal & lhs, const Goals::TSubgoal & rhs) -> bool
|
||||||
@ -38,7 +43,17 @@ Goals::TSubgoal FuzzyHelper::chooseSolution(Goals::TGoalVec vec)
|
|||||||
{
|
{
|
||||||
return lhs->priority < rhs->priority;
|
return lhs->priority < rhs->priority;
|
||||||
};
|
};
|
||||||
return *boost::max_element(vec, compareGoals);
|
|
||||||
|
for(auto goal : vec)
|
||||||
|
{
|
||||||
|
logAi->debug("FuzzyHelper evaluated goal %s, priority=%i", goal->name(), goal->priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
Goals::TSubgoal result = *boost::max_element(vec, compareGoals);
|
||||||
|
|
||||||
|
logAi->debug("FuzzyHelper returned goal %s, priority=%i", result->name(), result->priority);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui64 FuzzyHelper::estimateBankDanger(const CBank * bank)
|
ui64 FuzzyHelper::estimateBankDanger(const CBank * bank)
|
||||||
|
@ -163,6 +163,9 @@ bool Goals::AbstractGoal::operator==(AbstractGoal & g)
|
|||||||
return (town == g.town && bid == g.bid); //build specific structure in specific town
|
return (town == g.town && bid == g.bid); //build specific structure in specific town
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case BUY_ARMY:
|
||||||
|
return town == g.town;
|
||||||
|
|
||||||
//no check atm
|
//no check atm
|
||||||
case COLLECT_RES:
|
case COLLECT_RES:
|
||||||
case TRADE: //TODO
|
case TRADE: //TODO
|
||||||
@ -1441,14 +1444,16 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
|
|||||||
ret.push_back(sptr(Goals::VisitTile(pos).sethero(hero)));
|
ret.push_back(sptr(Goals::VisitTile(pos).sethero(hero)));
|
||||||
}
|
}
|
||||||
//buy army in town
|
//buy army in town
|
||||||
if (!t->visitingHero || t->visitingHero != hero.get(true))
|
if (!t->visitingHero || t->visitingHero == hero.get(true))
|
||||||
{
|
{
|
||||||
ui32 val = std::min<ui32>(value, howManyReinforcementsCanBuy(hero, t));
|
ui32 val = std::min<ui32>(value, howManyReinforcementsCanBuy(hero, t));
|
||||||
if (val)
|
if (val)
|
||||||
{
|
{
|
||||||
auto goal = sptr(Goals::BuyArmy(t, val).sethero(hero));
|
auto goal = sptr(Goals::BuyArmy(t, val).sethero(hero));
|
||||||
if (!ai->ah->containsObjective(goal)) //avoid loops caused by reserving same objective twice
|
if(!ai->ah->containsObjective(goal)) //avoid loops caused by reserving same objective twice
|
||||||
ret.push_back(goal);
|
ret.push_back(goal);
|
||||||
|
else
|
||||||
|
logAi->debug("Can not buy army, because of ai->ah->containsObjective");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//build dwelling
|
//build dwelling
|
||||||
@ -1460,6 +1465,8 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
|
|||||||
auto goal = sptr(BuildThis(bid.get(), t).setpriority(priority));
|
auto goal = sptr(BuildThis(bid.get(), t).setpriority(priority));
|
||||||
if (!ai->ah->containsObjective(goal)) //avoid loops caused by reserving same objective twice
|
if (!ai->ah->containsObjective(goal)) //avoid loops caused by reserving same objective twice
|
||||||
ret.push_back(goal);
|
ret.push_back(goal);
|
||||||
|
else
|
||||||
|
logAi->debug("Can not build a structure, because of ai->ah->containsObjective");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1501,15 +1508,21 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
|
|||||||
if(relationToOwner == PlayerRelations::SAME_PLAYER)
|
if(relationToOwner == PlayerRelations::SAME_PLAYER)
|
||||||
{
|
{
|
||||||
auto dwelling = dynamic_cast<const CGDwelling *>(obj);
|
auto dwelling = dynamic_cast<const CGDwelling *>(obj);
|
||||||
for(auto & creLevel : dwelling->creatures)
|
|
||||||
|
ui32 val = std::min<ui32>(value, howManyReinforcementsCanBuy(hero, dwelling));
|
||||||
|
|
||||||
|
if(val)
|
||||||
{
|
{
|
||||||
if(creLevel.first)
|
for(auto & creLevel : dwelling->creatures)
|
||||||
{
|
{
|
||||||
for(auto & creatureID : creLevel.second)
|
if(creLevel.first)
|
||||||
{
|
{
|
||||||
auto creature = VLC->creh->creatures[creatureID];
|
for(auto & creatureID : creLevel.second)
|
||||||
if(ai->ah->freeResources().canAfford(creature->cost))
|
{
|
||||||
objs.push_back(obj); //TODO: reserve resources?
|
auto creature = VLC->creh->creatures[creatureID];
|
||||||
|
if(ai->ah->freeResources().canAfford(creature->cost))
|
||||||
|
objs.push_back(obj); //TODO: reserve resources?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,6 +172,8 @@ Goals::TSubgoal ResourceManager::whatToDo() const //suggest any goal
|
|||||||
|
|
||||||
Goals::TSubgoal ResourceManager::whatToDo(TResources &res, Goals::TSubgoal goal)
|
Goals::TSubgoal ResourceManager::whatToDo(TResources &res, Goals::TSubgoal goal)
|
||||||
{
|
{
|
||||||
|
logAi->trace("ResourceManager: checking goal %s which requires resources %s", goal->name(), res.toString());
|
||||||
|
|
||||||
TResources accumulatedResources;
|
TResources accumulatedResources;
|
||||||
auto allResources = cb->getResourceAmount();
|
auto allResources = cb->getResourceAmount();
|
||||||
|
|
||||||
@ -181,19 +183,38 @@ Goals::TSubgoal ResourceManager::whatToDo(TResources &res, Goals::TSubgoal goal)
|
|||||||
for (auto it = queue.ordered_begin(); it != queue.ordered_end(); it++)
|
for (auto it = queue.ordered_begin(); it != queue.ordered_end(); it++)
|
||||||
{
|
{
|
||||||
accumulatedResources += it->resources;
|
accumulatedResources += it->resources;
|
||||||
if (!accumulatedResources.canBeAfforded(allResources)) //can't afford
|
|
||||||
return collectResourcesForOurGoal(ro);
|
logAi->trace(
|
||||||
|
"ResourceManager: checking goal %s, accumulatedResources=%s, available=%s",
|
||||||
|
it->goal->name(),
|
||||||
|
accumulatedResources.toString(),
|
||||||
|
allResources.toString());
|
||||||
|
|
||||||
|
if(!accumulatedResources.canBeAfforded(allResources))
|
||||||
|
{
|
||||||
|
//can't afford
|
||||||
|
break;
|
||||||
|
}
|
||||||
else //can afford all goals up to this point
|
else //can afford all goals up to this point
|
||||||
{
|
{
|
||||||
if (it->goal == goal)
|
if(it->goal == goal)
|
||||||
|
{
|
||||||
|
logAi->debug("ResourceManager: can afford goal %s", goal->name());
|
||||||
return goal; //can afford immediately
|
return goal; //can afford immediately
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return collectResourcesForOurGoal(ro); //fallback, ever needed?
|
|
||||||
|
logAi->debug("ResourceManager: can not afford goal %s", goal->name());
|
||||||
|
|
||||||
|
return collectResourcesForOurGoal(ro);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ResourceManager::containsObjective(Goals::TSubgoal goal) const
|
bool ResourceManager::containsObjective(Goals::TSubgoal goal) const
|
||||||
{
|
{
|
||||||
|
logAi->trace("Entering ResourceManager.containsObjective goal=%s", goal->name());
|
||||||
|
dumpToLog();
|
||||||
|
|
||||||
//TODO: unit tests for once
|
//TODO: unit tests for once
|
||||||
for (auto objective : queue)
|
for (auto objective : queue)
|
||||||
{
|
{
|
||||||
@ -205,6 +226,8 @@ bool ResourceManager::containsObjective(Goals::TSubgoal goal) const
|
|||||||
|
|
||||||
bool ResourceManager::notifyGoalCompleted(Goals::TSubgoal goal)
|
bool ResourceManager::notifyGoalCompleted(Goals::TSubgoal goal)
|
||||||
{
|
{
|
||||||
|
logAi->trace("Entering ResourceManager.notifyGoalCompleted goal=%s", goal->name());
|
||||||
|
|
||||||
if (goal->invalid())
|
if (goal->invalid())
|
||||||
logAi->warn("Attempt to complete Invalid goal");
|
logAi->warn("Attempt to complete Invalid goal");
|
||||||
|
|
||||||
@ -215,15 +238,18 @@ bool ResourceManager::notifyGoalCompleted(Goals::TSubgoal goal)
|
|||||||
{
|
{
|
||||||
return ro.goal == goal || ro.goal->fulfillsMe (goal);
|
return ro.goal == goal || ro.goal->fulfillsMe (goal);
|
||||||
});
|
});
|
||||||
if (it != queue.end()) //removed at least one
|
if(it != queue.end()) //removed at least one
|
||||||
{
|
{
|
||||||
logAi->debug("Removing goal %s from ResourceManager.", it->goal->name());
|
logAi->debug("Removing goal %s from ResourceManager.", it->goal->name());
|
||||||
queue.erase(queue.s_handle_from_iterator(it));
|
queue.erase(queue.s_handle_from_iterator(it));
|
||||||
removedGoal = true;
|
removedGoal = true;
|
||||||
}
|
}
|
||||||
else //found nothing more to remove
|
else //found nothing more to remove
|
||||||
return removedGoal;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dumpToLog();
|
||||||
|
|
||||||
return removedGoal;
|
return removedGoal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,10 +274,21 @@ bool ResourceManager::updateGoal(Goals::TSubgoal goal)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ResourceManager::dumpToLog() const
|
||||||
|
{
|
||||||
|
for(auto it = queue.ordered_begin(); it != queue.ordered_end(); it++)
|
||||||
|
{
|
||||||
|
logAi->trace("ResourceManager contains goal %s which requires resources %s", it->goal->name(), it->resources.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool ResourceManager::tryPush(const ResourceObjective & o)
|
bool ResourceManager::tryPush(const ResourceObjective & o)
|
||||||
{
|
{
|
||||||
auto goal = o.goal;
|
auto goal = o.goal;
|
||||||
|
|
||||||
|
logAi->trace("ResourceManager: Trying to add goal %s which requires resources %s", goal->name(), o.resources.toString());
|
||||||
|
dumpToLog();
|
||||||
|
|
||||||
auto it = boost::find_if(queue, [goal](const ResourceObjective & ro) -> bool
|
auto it = boost::find_if(queue, [goal](const ResourceObjective & ro) -> bool
|
||||||
{
|
{
|
||||||
return ro.goal == goal;
|
return ro.goal == goal;
|
||||||
|
@ -102,6 +102,8 @@ private:
|
|||||||
|
|
||||||
boost::heap::binomial_heap<ResourceObjective> queue;
|
boost::heap::binomial_heap<ResourceObjective> queue;
|
||||||
|
|
||||||
|
void dumpToLog() const;
|
||||||
|
|
||||||
//TODO: register?
|
//TODO: register?
|
||||||
template<typename Handler> void serializeInternal(Handler & h, const int version)
|
template<typename Handler> void serializeInternal(Handler & h, const int version)
|
||||||
{
|
{
|
||||||
|
@ -933,6 +933,8 @@ void VCAI::mainLoop()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logAi->trace("Main loop: selecting best elementar goal");
|
||||||
|
|
||||||
//now choose one elementar goal to realize
|
//now choose one elementar goal to realize
|
||||||
Goals::TGoalVec possibleGoals(elementarGoals.begin(), elementarGoals.end()); //copy to vector
|
Goals::TGoalVec possibleGoals(elementarGoals.begin(), elementarGoals.end()); //copy to vector
|
||||||
Goals::TSubgoal goalToRealize = sptr(Goals::Invalid());
|
Goals::TSubgoal goalToRealize = sptr(Goals::Invalid());
|
||||||
@ -2205,7 +2207,7 @@ void VCAI::tryRealize(Goals::BuyArmy & g)
|
|||||||
});
|
});
|
||||||
|
|
||||||
vstd::amin(ci.count, res / ci.cre->cost); //max count we can afford
|
vstd::amin(ci.count, res / ci.cre->cost); //max count we can afford
|
||||||
if (ci.count > 0)
|
if (ci.count > 0 && t->getUpperArmy()->getSlotFor(ci.creID) != SlotID())
|
||||||
{
|
{
|
||||||
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;
|
||||||
@ -2379,6 +2381,13 @@ void VCAI::striveToGoal(Goals::TSubgoal basicGoal)
|
|||||||
|
|
||||||
Goals::TSubgoal VCAI::decomposeGoal(Goals::TSubgoal ultimateGoal)
|
Goals::TSubgoal VCAI::decomposeGoal(Goals::TSubgoal ultimateGoal)
|
||||||
{
|
{
|
||||||
|
if(ultimateGoal->isElementar)
|
||||||
|
{
|
||||||
|
logAi->warn("Trying to decompose elementar goal %s", ultimateGoal->name());
|
||||||
|
|
||||||
|
return ultimateGoal;
|
||||||
|
}
|
||||||
|
|
||||||
const int searchDepth = 30;
|
const int searchDepth = 30;
|
||||||
const int searchDepth2 = searchDepth - 2;
|
const int searchDepth2 = searchDepth - 2;
|
||||||
Goals::TSubgoal abstractGoal = sptr(Goals::Invalid());
|
Goals::TSubgoal abstractGoal = sptr(Goals::Invalid());
|
||||||
|
Loading…
Reference in New Issue
Block a user