1
0
mirror of https://github.com/vcmi/vcmi.git synced 2026-05-22 09:55:17 +02:00

Fuzzy rework, added more defence and gather army routines

This commit is contained in:
Andrii Danylchenko
2023-06-04 16:02:02 +03:00
parent b1ca663eb6
commit b19ac01bf9
28 changed files with 710 additions and 195 deletions
+1 -1
View File
@@ -71,7 +71,7 @@ void BuyArmy::accept(AIGateway * ai)
throw cannotFulfillGoalException("No creatures to buy.");
}
if(town->visitingHero)
if(town->visitingHero && !town->garrisonHero)
{
ai->moveHeroToTile(town->visitablePos(), town->visitingHero.get());
}
+49 -9
View File
@@ -31,9 +31,17 @@ std::string Composition::toString() const
{
std::string result = "Composition";
for(auto goal : subtasks)
for(auto step : subtasks)
{
result += " " + goal->toString();
result += "[";
for(auto goal : step)
{
if(goal->isElementar())
result += goal->toString() + " => ";
else
result += goal->toString() + ", ";
}
result += "] ";
}
return result;
@@ -41,17 +49,34 @@ std::string Composition::toString() const
void Composition::accept(AIGateway * ai)
{
taskptr(*subtasks.back())->accept(ai);
for(auto task : subtasks.back())
{
if(task->isElementar())
{
taskptr(*task)->accept(ai);
}
else
{
break;
}
}
}
TGoalVec Composition::decompose() const
{
return subtasks;
TGoalVec result;
for(const TGoalVec & step : subtasks)
vstd::concatenate(result, step);
return result;
}
Composition & Composition::addNext(const AbstractGoal & goal)
Composition & Composition::addNextSequence(const TGoalVec & taskSequence)
{
return addNext(sptr(goal));
subtasks.push_back(taskSequence);
return *this;
}
Composition & Composition::addNext(TSubgoal goal)
@@ -64,20 +89,35 @@ Composition & Composition::addNext(TSubgoal goal)
}
else
{
subtasks.push_back(goal);
subtasks.push_back({goal});
}
return *this;
}
Composition & Composition::addNext(const AbstractGoal & goal)
{
return addNext(sptr(goal));
}
bool Composition::isElementar() const
{
return subtasks.back()->isElementar();
return subtasks.back().front()->isElementar();
}
int Composition::getHeroExchangeCount() const
{
return isElementar() ? taskptr(*subtasks.back())->getHeroExchangeCount() : 0;
auto result = 0;
for(auto task : subtasks.back())
{
if(task->isElementar())
{
result += taskptr(*task)->getHeroExchangeCount();
}
}
return result;
}
}
+2 -6
View File
@@ -18,7 +18,7 @@ namespace Goals
class DLL_EXPORT Composition : public ElementarGoal<Composition>
{
private:
TGoalVec subtasks;
std::vector<TGoalVec> subtasks; // things we want to do now
public:
Composition()
@@ -26,16 +26,12 @@ namespace Goals
{
}
Composition(TGoalVec subtasks)
: ElementarGoal(Goals::COMPOSITION), subtasks(subtasks)
{
}
virtual bool operator==(const Composition & other) const override;
virtual std::string toString() const override;
void accept(AIGateway * ai) override;
Composition & addNext(const AbstractGoal & goal);
Composition & addNext(TSubgoal goal);
Composition & addNextSequence(const TGoalVec & taskSequence);
virtual TGoalVec decompose() const override;
virtual bool isElementar() const override;
virtual int getHeroExchangeCount() const override;
+14
View File
@@ -52,6 +52,20 @@ void ExecuteHeroChain::accept(AIGateway * ai)
ai->nullkiller->setActive(chainPath.targetHero, tile);
ai->nullkiller->setTargetObject(objid);
auto targetObject = ai->myCb->getObj(static_cast<ObjectInstanceID>(objid), false);
if(chainPath.turn() == 0 && targetObject && targetObject->ID == Obj::TOWN)
{
auto relations = ai->myCb->getPlayerRelations(ai->playerID, targetObject->getOwner());
if(relations == PlayerRelations::ENEMIES)
{
ai->nullkiller->armyFormation->rearrangeArmyForSiege(
dynamic_cast<const CGTownInstance *>(targetObject),
chainPath.targetHero);
}
}
std::set<int> blockedIndexes;
for(int i = chainPath.nodes.size() - 1; i >= 0; i--)
+12 -9
View File
@@ -24,7 +24,10 @@ using namespace Goals;
std::string RecruitHero::toString() const
{
return "Recruit hero at " + town->getNameTranslated();
if(heroToBuy)
return "Recruit " + heroToBuy->getNameTranslated() + " at " + town->getNameTranslated();
else
return "Recruit hero at " + town->getNameTranslated();
}
void RecruitHero::accept(AIGateway * ai)
@@ -45,20 +48,20 @@ void RecruitHero::accept(AIGateway * ai)
throw cannotFulfillGoalException("No available heroes in tavern in " + t->nodeName());
}
auto heroToHire = heroes[0];
auto heroToHire = heroToBuy;
for(auto hero : heroes)
if(!heroToHire)
{
if(objid == hero->id.getNum())
for(auto hero : heroes)
{
heroToHire = hero;
break;
if(!heroToHire || hero->getTotalStrength() > heroToHire->getTotalStrength())
heroToHire = hero;
}
if(hero->getTotalStrength() > heroToHire->getTotalStrength())
heroToHire = hero;
}
if(!heroToHire)
throw cannotFulfillGoalException("No hero to hire!");
if(t->visitingHero)
{
cb->swapGarrisonHero(t);
+7 -5
View File
@@ -22,18 +22,20 @@ namespace Goals
{
class DLL_EXPORT RecruitHero : public ElementarGoal<RecruitHero>
{
private:
const CGHeroInstance * heroToBuy;
public:
RecruitHero(const CGTownInstance * townWithTavern, const CGHeroInstance * heroToBuy)
: RecruitHero(townWithTavern)
: ElementarGoal(Goals::RECRUIT_HERO), heroToBuy(heroToBuy)
{
objid = heroToBuy->id.getNum();
town = townWithTavern;
priority = 1;
}
RecruitHero(const CGTownInstance * townWithTavern)
: ElementarGoal(Goals::RECRUIT_HERO)
: RecruitHero(townWithTavern, nullptr)
{
priority = 1;
town = townWithTavern;
}
virtual bool operator==(const RecruitHero & other) const override