mirror of
https://github.com/vcmi/vcmi.git
synced 2025-04-11 11:31:52 +02:00
Nullkiller: startup scripts
This commit is contained in:
parent
5fe2630c64
commit
bcf8db3d05
@ -215,4 +215,9 @@ void AIhelper::updateHeroRoles()
|
||||
float AIhelper::evaluateSecSkill(SecondarySkill skill, const CGHeroInstance * hero) const
|
||||
{
|
||||
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;
|
||||
void updateHeroRoles() override;
|
||||
float evaluateSecSkill(SecondarySkill skill, const CGHeroInstance * hero) const override;
|
||||
float evaluateHero(const CGHeroInstance * hero) const override;
|
||||
|
||||
private:
|
||||
bool notifyGoalCompleted(Goals::TSubgoal goal) override;
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "../AIhelper.h"
|
||||
#include "../AIUtility.h"
|
||||
#include "../Goals/RecruitHero.h"
|
||||
#include "../Goals/ExecuteHeroChain.h"
|
||||
#include "lib/mapping/CMap.h" //for victory conditions
|
||||
#include "lib/CPathfinder.h"
|
||||
|
||||
@ -33,13 +34,133 @@ Goals::TGoalVec RecruitHeroBehavior::getTasks()
|
||||
|
||||
if(ai->canRecruitAnyHero())
|
||||
{
|
||||
if(cb->getDate(Date::DAY) == 1
|
||||
|| cb->getHeroesInfo().size() < cb->getTownsInfo().size() + 1
|
||||
if(cb->getHeroesInfo().size() < cb->getTownsInfo().size() + 1
|
||||
|| cb->getResourceAmount(Res::GOLD) > 10000)
|
||||
{
|
||||
tasks.push_back(Goals::sptr(Goals::RecruitHero()));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
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>())
|
||||
};
|
||||
|
||||
if(cb->getDate(Date::DAY) == 1)
|
||||
{
|
||||
bestTasks.push_back(choseBestTask(std::make_shared<StartupBehavior>()));
|
||||
}
|
||||
|
||||
Goals::TSubgoal bestTask = choseBestTask(bestTasks);
|
||||
|
||||
if(bestTask->invalid())
|
||||
|
@ -20,6 +20,7 @@ public:
|
||||
bool isActive(const CGHeroInstance * hero) const { return activeHero.h == hero; }
|
||||
void setActive(const HeroPtr & hero) { activeHero = hero; }
|
||||
void lockHero(const HeroPtr & hero) { lockedHeroes.insert(hero); }
|
||||
void unlockHero(const HeroPtr & hero) { lockedHeroes.erase(hero); }
|
||||
|
||||
private:
|
||||
void resetAiState();
|
||||
|
@ -176,9 +176,9 @@ float getSkillReward(const CGObjectInstance * target, const CGHeroInstance * her
|
||||
case Obj::MARLETTO_TOWER:
|
||||
case Obj::MERCENARY_CAMP:
|
||||
case Obj::SHRINE_OF_MAGIC_GESTURE:
|
||||
case Obj::SHRINE_OF_MAGIC_INCANTATION:
|
||||
return 1;
|
||||
case Obj::ARENA:
|
||||
case Obj::SHRINE_OF_MAGIC_INCANTATION:
|
||||
case Obj::SHRINE_OF_MAGIC_THOUGHT:
|
||||
return 2;
|
||||
case Obj::LIBRARY_OF_ENLIGHTENMENT:
|
||||
@ -240,6 +240,9 @@ int32_t getGoldReward(const CGObjectInstance * target, const CGHeroInstance * he
|
||||
/// importance
|
||||
float PriorityEvaluator::evaluate(Goals::TSubgoal task)
|
||||
{
|
||||
if(task->priority > 0)
|
||||
return task->priority;
|
||||
|
||||
auto heroPtr = task->hero;
|
||||
|
||||
if(!heroPtr.validAndSet())
|
||||
@ -263,10 +266,7 @@ float PriorityEvaluator::evaluate(Goals::TSubgoal task)
|
||||
uint64_t danger = task->evaluationContext.danger;
|
||||
double result = 0;
|
||||
int rewardType = (goldReward > 0 ? 1 : 0) + (armyReward > 0 ? 1 : 0) + (skillReward > 0 ? 1 : 0);
|
||||
|
||||
if(day == 1)
|
||||
goldReward *= 2;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
armyLossPersentageVariable->setValue(armyLossPersentage);
|
||||
|
@ -65,7 +65,8 @@ namespace Goals
|
||||
BUILD_BOAT,
|
||||
COMPLETE_QUEST,
|
||||
ADVENTURE_SPELL_CAST,
|
||||
EXECUTE_HERO_CHAIN
|
||||
EXECUTE_HERO_CHAIN,
|
||||
EXCHANGE_SWAP_TOWN_HEROES
|
||||
};
|
||||
|
||||
class DLL_EXPORT TSubgoal : public std::shared_ptr<AbstractGoal>
|
||||
|
@ -110,3 +110,59 @@ std::string ExecuteHeroChain::completeMessage() const
|
||||
{
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
float HeroManager::evaluateHero(const CGHeroInstance * hero) const
|
||||
{
|
||||
return evaluateFightingStrength(hero);
|
||||
}
|
||||
|
||||
SecondarySkillScoreMap::SecondarySkillScoreMap(std::map<SecondarySkill, float> scoreMap)
|
||||
:scoreMap(scoreMap)
|
||||
{
|
||||
|
@ -35,6 +35,7 @@ public:
|
||||
virtual HeroRole getHeroRole(const HeroPtr & hero) const = 0;
|
||||
virtual void updateHeroRoles() = 0;
|
||||
virtual float evaluateSecSkill(SecondarySkill skill, const CGHeroInstance * hero) const = 0;
|
||||
virtual float evaluateHero(const CGHeroInstance * hero) const = 0;
|
||||
};
|
||||
|
||||
class DLL_EXPORT ISecondarySkillRule
|
||||
@ -72,6 +73,7 @@ public:
|
||||
int selectBestSkill(const HeroPtr & hero, const std::vector<SecondarySkill> & skills) const override;
|
||||
void updateHeroRoles() override;
|
||||
float evaluateSecSkill(SecondarySkill skill, const CGHeroInstance * hero) const override;
|
||||
float evaluateHero(const CGHeroInstance * hero) const override;
|
||||
|
||||
private:
|
||||
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)
|
||||
{
|
||||
pickBestCreatures(t->visitingHero, t);
|
||||
pickBestCreatures(t->visitingHero, t->getUpperArmy());
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user