mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-13 19:54:17 +02:00
Nullkiller: startup scripts
This commit is contained in:
committed by
Andrii Danylchenko
parent
5fe2630c64
commit
bcf8db3d05
@@ -216,3 +216,8 @@ float AIhelper::evaluateSecSkill(SecondarySkill skill, const CGHeroInstance * he
|
|||||||
{
|
{
|
||||||
return heroManager->evaluateSecSkill(skill, hero);
|
return heroManager->evaluateSecSkill(skill, hero);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float AIhelper::evaluateHero(const CGHeroInstance * hero) const
|
||||||
|
{
|
||||||
|
return heroManager->evaluateHero(hero);
|
||||||
|
}
|
@@ -85,6 +85,7 @@ public:
|
|||||||
int selectBestSkill(const HeroPtr & hero, const std::vector<SecondarySkill> & skills) const override;
|
int selectBestSkill(const HeroPtr & hero, const std::vector<SecondarySkill> & skills) const override;
|
||||||
void updateHeroRoles() override;
|
void updateHeroRoles() override;
|
||||||
float evaluateSecSkill(SecondarySkill skill, const CGHeroInstance * hero) const override;
|
float evaluateSecSkill(SecondarySkill skill, const CGHeroInstance * hero) const override;
|
||||||
|
float evaluateHero(const CGHeroInstance * hero) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool notifyGoalCompleted(Goals::TSubgoal goal) override;
|
bool notifyGoalCompleted(Goals::TSubgoal goal) override;
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
#include "../AIhelper.h"
|
#include "../AIhelper.h"
|
||||||
#include "../AIUtility.h"
|
#include "../AIUtility.h"
|
||||||
#include "../Goals/RecruitHero.h"
|
#include "../Goals/RecruitHero.h"
|
||||||
|
#include "../Goals/ExecuteHeroChain.h"
|
||||||
#include "lib/mapping/CMap.h" //for victory conditions
|
#include "lib/mapping/CMap.h" //for victory conditions
|
||||||
#include "lib/CPathfinder.h"
|
#include "lib/CPathfinder.h"
|
||||||
|
|
||||||
@@ -33,8 +34,7 @@ Goals::TGoalVec RecruitHeroBehavior::getTasks()
|
|||||||
|
|
||||||
if(ai->canRecruitAnyHero())
|
if(ai->canRecruitAnyHero())
|
||||||
{
|
{
|
||||||
if(cb->getDate(Date::DAY) == 1
|
if(cb->getHeroesInfo().size() < cb->getTownsInfo().size() + 1
|
||||||
|| cb->getHeroesInfo().size() < cb->getTownsInfo().size() + 1
|
|
||||||
|| cb->getResourceAmount(Res::GOLD) > 10000)
|
|| cb->getResourceAmount(Res::GOLD) > 10000)
|
||||||
{
|
{
|
||||||
tasks.push_back(Goals::sptr(Goals::RecruitHero()));
|
tasks.push_back(Goals::sptr(Goals::RecruitHero()));
|
||||||
@@ -43,3 +43,124 @@ Goals::TGoalVec RecruitHeroBehavior::getTasks()
|
|||||||
|
|
||||||
return tasks;
|
return tasks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string StartupBehavior::toString() const
|
||||||
|
{
|
||||||
|
return "Startup";
|
||||||
|
}
|
||||||
|
|
||||||
|
const AIPath getShortestPath(const CGTownInstance * town, const std::vector<AIPath> & paths)
|
||||||
|
{
|
||||||
|
auto shortestPath = *vstd::minElementByFun(paths, [town](const AIPath & path) -> float
|
||||||
|
{
|
||||||
|
if(town->garrisonHero && path.targetHero == town->garrisonHero.get())
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return path.movementCost();
|
||||||
|
});
|
||||||
|
|
||||||
|
return shortestPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CGHeroInstance * getNearestHero(const CGTownInstance * town)
|
||||||
|
{
|
||||||
|
auto paths = ai->ah->getPathsToTile(town->visitablePos());
|
||||||
|
|
||||||
|
if(paths.empty())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
auto shortestPath = getShortestPath(town, paths);
|
||||||
|
|
||||||
|
if(shortestPath.nodes.size() > 1
|
||||||
|
|| shortestPath.targetHero->visitablePos().dist2dSQ(town->visitablePos()) > 4
|
||||||
|
|| town->garrisonHero && shortestPath.targetHero == town->garrisonHero.get())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return shortestPath.targetHero;
|
||||||
|
}
|
||||||
|
|
||||||
|
Goals::TGoalVec StartupBehavior::getTasks()
|
||||||
|
{
|
||||||
|
Goals::TGoalVec tasks;
|
||||||
|
auto towns = cb->getTownsInfo();
|
||||||
|
|
||||||
|
if(!towns.size())
|
||||||
|
return tasks;
|
||||||
|
|
||||||
|
const CGTownInstance * startupTown = towns.front();
|
||||||
|
bool canRecruitHero = ai->canRecruitAnyHero(startupTown);
|
||||||
|
|
||||||
|
if(towns.size() > 1)
|
||||||
|
{
|
||||||
|
startupTown = *vstd::maxElementByFun(towns, [](const CGTownInstance * town) -> float
|
||||||
|
{
|
||||||
|
auto closestHero = getNearestHero(town);
|
||||||
|
|
||||||
|
if(!closestHero)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return ai->ah->evaluateHero(closestHero);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
auto closestHero = getNearestHero(startupTown);
|
||||||
|
|
||||||
|
if(closestHero)
|
||||||
|
{
|
||||||
|
if(!startupTown->visitingHero)
|
||||||
|
{
|
||||||
|
if(ai->ah->howManyReinforcementsCanGet(startupTown->getUpperArmy(), closestHero) > 200)
|
||||||
|
{
|
||||||
|
auto paths = ai->ah->getPathsToTile(startupTown->visitablePos());
|
||||||
|
|
||||||
|
if(paths.size())
|
||||||
|
{
|
||||||
|
auto path = getShortestPath(startupTown, paths);
|
||||||
|
|
||||||
|
tasks.push_back(Goals::sptr(Goals::ExecuteHeroChain(path, startupTown).setpriority(100)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto visitingHero = startupTown->visitingHero.get();
|
||||||
|
auto visitingHeroScore = ai->ah->evaluateHero(visitingHero);
|
||||||
|
|
||||||
|
if(startupTown->garrisonHero)
|
||||||
|
{
|
||||||
|
auto garrisonHero = startupTown->garrisonHero.get();
|
||||||
|
auto garrisonHeroScore = ai->ah->evaluateHero(garrisonHero);
|
||||||
|
|
||||||
|
if(garrisonHeroScore > visitingHeroScore)
|
||||||
|
{
|
||||||
|
if(ai->ah->howManyReinforcementsCanGet(garrisonHero, visitingHero) > 200)
|
||||||
|
tasks.push_back(Goals::sptr(ExchangeSwapTownHeroes(startupTown, garrisonHero).setpriority(100)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tasks.push_back(Goals::sptr(ExchangeSwapTownHeroes(startupTown, visitingHero).setpriority(100)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(canRecruitHero)
|
||||||
|
{
|
||||||
|
tasks.push_back(Goals::sptr(ExchangeSwapTownHeroes(startupTown, visitingHero).setpriority(100)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tasks.empty() && canRecruitHero && !startupTown->visitingHero)
|
||||||
|
{
|
||||||
|
tasks.push_back(Goals::sptr(Goals::RecruitHero()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tasks.empty() && towns.size())
|
||||||
|
{
|
||||||
|
for(const CGTownInstance * town : towns)
|
||||||
|
{
|
||||||
|
if(town->garrisonHero)
|
||||||
|
tasks.push_back(Goals::sptr(ExchangeSwapTownHeroes(town, nullptr).setpriority(0.0001f)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tasks;
|
||||||
|
}
|
@@ -24,3 +24,14 @@ public:
|
|||||||
virtual std::string toString() const override;
|
virtual std::string toString() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class StartupBehavior : public Behavior
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StartupBehavior()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Goals::TGoalVec getTasks() override;
|
||||||
|
virtual std::string toString() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -86,6 +86,11 @@ void Nullkiller::makeTurn()
|
|||||||
choseBestTask(std::make_shared<RecruitHeroBehavior>())
|
choseBestTask(std::make_shared<RecruitHeroBehavior>())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if(cb->getDate(Date::DAY) == 1)
|
||||||
|
{
|
||||||
|
bestTasks.push_back(choseBestTask(std::make_shared<StartupBehavior>()));
|
||||||
|
}
|
||||||
|
|
||||||
Goals::TSubgoal bestTask = choseBestTask(bestTasks);
|
Goals::TSubgoal bestTask = choseBestTask(bestTasks);
|
||||||
|
|
||||||
if(bestTask->invalid())
|
if(bestTask->invalid())
|
||||||
|
@@ -20,6 +20,7 @@ public:
|
|||||||
bool isActive(const CGHeroInstance * hero) const { return activeHero.h == hero; }
|
bool isActive(const CGHeroInstance * hero) const { return activeHero.h == hero; }
|
||||||
void setActive(const HeroPtr & hero) { activeHero = hero; }
|
void setActive(const HeroPtr & hero) { activeHero = hero; }
|
||||||
void lockHero(const HeroPtr & hero) { lockedHeroes.insert(hero); }
|
void lockHero(const HeroPtr & hero) { lockedHeroes.insert(hero); }
|
||||||
|
void unlockHero(const HeroPtr & hero) { lockedHeroes.erase(hero); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void resetAiState();
|
void resetAiState();
|
||||||
|
@@ -176,9 +176,9 @@ float getSkillReward(const CGObjectInstance * target, const CGHeroInstance * her
|
|||||||
case Obj::MARLETTO_TOWER:
|
case Obj::MARLETTO_TOWER:
|
||||||
case Obj::MERCENARY_CAMP:
|
case Obj::MERCENARY_CAMP:
|
||||||
case Obj::SHRINE_OF_MAGIC_GESTURE:
|
case Obj::SHRINE_OF_MAGIC_GESTURE:
|
||||||
|
case Obj::SHRINE_OF_MAGIC_INCANTATION:
|
||||||
return 1;
|
return 1;
|
||||||
case Obj::ARENA:
|
case Obj::ARENA:
|
||||||
case Obj::SHRINE_OF_MAGIC_INCANTATION:
|
|
||||||
case Obj::SHRINE_OF_MAGIC_THOUGHT:
|
case Obj::SHRINE_OF_MAGIC_THOUGHT:
|
||||||
return 2;
|
return 2;
|
||||||
case Obj::LIBRARY_OF_ENLIGHTENMENT:
|
case Obj::LIBRARY_OF_ENLIGHTENMENT:
|
||||||
@@ -240,6 +240,9 @@ int32_t getGoldReward(const CGObjectInstance * target, const CGHeroInstance * he
|
|||||||
/// importance
|
/// importance
|
||||||
float PriorityEvaluator::evaluate(Goals::TSubgoal task)
|
float PriorityEvaluator::evaluate(Goals::TSubgoal task)
|
||||||
{
|
{
|
||||||
|
if(task->priority > 0)
|
||||||
|
return task->priority;
|
||||||
|
|
||||||
auto heroPtr = task->hero;
|
auto heroPtr = task->hero;
|
||||||
|
|
||||||
if(!heroPtr.validAndSet())
|
if(!heroPtr.validAndSet())
|
||||||
@@ -264,9 +267,6 @@ float PriorityEvaluator::evaluate(Goals::TSubgoal task)
|
|||||||
double result = 0;
|
double result = 0;
|
||||||
int rewardType = (goldReward > 0 ? 1 : 0) + (armyReward > 0 ? 1 : 0) + (skillReward > 0 ? 1 : 0);
|
int rewardType = (goldReward > 0 ? 1 : 0) + (armyReward > 0 ? 1 : 0) + (skillReward > 0 ? 1 : 0);
|
||||||
|
|
||||||
if(day == 1)
|
|
||||||
goldReward *= 2;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
armyLossPersentageVariable->setValue(armyLossPersentage);
|
armyLossPersentageVariable->setValue(armyLossPersentage);
|
||||||
|
@@ -65,7 +65,8 @@ namespace Goals
|
|||||||
BUILD_BOAT,
|
BUILD_BOAT,
|
||||||
COMPLETE_QUEST,
|
COMPLETE_QUEST,
|
||||||
ADVENTURE_SPELL_CAST,
|
ADVENTURE_SPELL_CAST,
|
||||||
EXECUTE_HERO_CHAIN
|
EXECUTE_HERO_CHAIN,
|
||||||
|
EXCHANGE_SWAP_TOWN_HEROES
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT TSubgoal : public std::shared_ptr<AbstractGoal>
|
class DLL_EXPORT TSubgoal : public std::shared_ptr<AbstractGoal>
|
||||||
|
@@ -110,3 +110,59 @@ std::string ExecuteHeroChain::completeMessage() const
|
|||||||
{
|
{
|
||||||
return "Hero chain completed";
|
return "Hero chain completed";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExchangeSwapTownHeroes::ExchangeSwapTownHeroes(const CGTownInstance * town, const CGHeroInstance * garrisonHero)
|
||||||
|
:CGoal(Goals::EXCHANGE_SWAP_TOWN_HEROES), town(town), garrisonHero(garrisonHero)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ExchangeSwapTownHeroes::name() const
|
||||||
|
{
|
||||||
|
return "Exchange and swap heroes of " + town->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ExchangeSwapTownHeroes::completeMessage() const
|
||||||
|
{
|
||||||
|
return "Exchange and swap heroes of " + town->name + " compelete";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExchangeSwapTownHeroes::operator==(const ExchangeSwapTownHeroes & other) const
|
||||||
|
{
|
||||||
|
return town == other.town;
|
||||||
|
}
|
||||||
|
|
||||||
|
TSubgoal ExchangeSwapTownHeroes::whatToDoToAchieve()
|
||||||
|
{
|
||||||
|
return iAmElementar();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExchangeSwapTownHeroes::accept(VCAI * ai)
|
||||||
|
{
|
||||||
|
if(!garrisonHero && town->garrisonHero && town->visitingHero)
|
||||||
|
throw cannotFulfillGoalException("Invalid configuration. Garrison hero is null.");
|
||||||
|
|
||||||
|
if(!garrisonHero)
|
||||||
|
{
|
||||||
|
if(!town->garrisonHero)
|
||||||
|
throw cannotFulfillGoalException("Invalid configuration. There is no hero in town garrison.");
|
||||||
|
|
||||||
|
cb->swapGarrisonHero(town);
|
||||||
|
ai->nullkiller->unlockHero(town->visitingHero.get());
|
||||||
|
logAi->debug("Extracted hero %s from garrison of %s", town->visitingHero->name, town->name);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(town->visitingHero && town->visitingHero.get() != garrisonHero)
|
||||||
|
cb->swapGarrisonHero(town);
|
||||||
|
|
||||||
|
ai->moveHeroToTile(town->visitablePos(), garrisonHero);
|
||||||
|
|
||||||
|
cb->swapGarrisonHero(town); // selected hero left in garrison with strongest army
|
||||||
|
ai->nullkiller->lockHero(town->garrisonHero.get());
|
||||||
|
|
||||||
|
if(town->visitingHero)
|
||||||
|
ai->nullkiller->unlockHero(town->visitingHero.get());
|
||||||
|
|
||||||
|
logAi->debug("Put hero %s to garrison of %s", town->garrisonHero->name, town->name);
|
||||||
|
}
|
@@ -33,4 +33,25 @@ namespace Goals
|
|||||||
std::string completeMessage() const override;
|
std::string completeMessage() const override;
|
||||||
virtual bool operator==(const ExecuteHeroChain & other) const override;
|
virtual bool operator==(const ExecuteHeroChain & other) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DLL_EXPORT ExchangeSwapTownHeroes : public CGoal<ExchangeSwapTownHeroes>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
const CGTownInstance * town;
|
||||||
|
const CGHeroInstance * garrisonHero;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ExchangeSwapTownHeroes(const CGTownInstance * town, const CGHeroInstance * garrisonHero = nullptr);
|
||||||
|
|
||||||
|
TGoalVec getAllPossibleSubgoals() override
|
||||||
|
{
|
||||||
|
return TGoalVec();
|
||||||
|
}
|
||||||
|
|
||||||
|
TSubgoal whatToDoToAchieve() override;
|
||||||
|
void accept(VCAI * ai) override;
|
||||||
|
std::string name() const override;
|
||||||
|
std::string completeMessage() const override;
|
||||||
|
virtual bool operator==(const ExchangeSwapTownHeroes & other) const override;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@@ -163,6 +163,11 @@ int HeroManager::selectBestSkill(const HeroPtr & hero, const std::vector<Seconda
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float HeroManager::evaluateHero(const CGHeroInstance * hero) const
|
||||||
|
{
|
||||||
|
return evaluateFightingStrength(hero);
|
||||||
|
}
|
||||||
|
|
||||||
SecondarySkillScoreMap::SecondarySkillScoreMap(std::map<SecondarySkill, float> scoreMap)
|
SecondarySkillScoreMap::SecondarySkillScoreMap(std::map<SecondarySkill, float> scoreMap)
|
||||||
:scoreMap(scoreMap)
|
:scoreMap(scoreMap)
|
||||||
{
|
{
|
||||||
|
@@ -35,6 +35,7 @@ public:
|
|||||||
virtual HeroRole getHeroRole(const HeroPtr & hero) const = 0;
|
virtual HeroRole getHeroRole(const HeroPtr & hero) const = 0;
|
||||||
virtual void updateHeroRoles() = 0;
|
virtual void updateHeroRoles() = 0;
|
||||||
virtual float evaluateSecSkill(SecondarySkill skill, const CGHeroInstance * hero) const = 0;
|
virtual float evaluateSecSkill(SecondarySkill skill, const CGHeroInstance * hero) const = 0;
|
||||||
|
virtual float evaluateHero(const CGHeroInstance * hero) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT ISecondarySkillRule
|
class DLL_EXPORT ISecondarySkillRule
|
||||||
@@ -72,6 +73,7 @@ public:
|
|||||||
int selectBestSkill(const HeroPtr & hero, const std::vector<SecondarySkill> & skills) const override;
|
int selectBestSkill(const HeroPtr & hero, const std::vector<SecondarySkill> & skills) const override;
|
||||||
void updateHeroRoles() override;
|
void updateHeroRoles() override;
|
||||||
float evaluateSecSkill(SecondarySkill skill, const CGHeroInstance * hero) const override;
|
float evaluateSecSkill(SecondarySkill skill, const CGHeroInstance * hero) const override;
|
||||||
|
float evaluateHero(const CGHeroInstance * hero) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float evaluateFightingStrength(const CGHeroInstance * hero) const;
|
float evaluateFightingStrength(const CGHeroInstance * hero) const;
|
||||||
|
@@ -1077,7 +1077,7 @@ void VCAI::moveCreaturesToHero(const CGTownInstance * t)
|
|||||||
{
|
{
|
||||||
if(t->visitingHero && t->armedGarrison() && t->visitingHero->tempOwner == t->tempOwner)
|
if(t->visitingHero && t->armedGarrison() && t->visitingHero->tempOwner == t->tempOwner)
|
||||||
{
|
{
|
||||||
pickBestCreatures(t->visitingHero, t);
|
pickBestCreatures(t->visitingHero, t->getUpperArmy());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user