mirror of
https://github.com/vcmi/vcmi.git
synced 2025-07-15 01:24:45 +02:00
Fix defence crashes and hangs
This commit is contained in:
committed by
Andrii Danylchenko
parent
3dc76cfe35
commit
3d91f2e988
@ -156,13 +156,13 @@ Goals::TGoalVec CaptureObjectsBehavior::decompose() const
|
|||||||
|
|
||||||
for(auto objToVisit : objs)
|
for(auto objToVisit : objs)
|
||||||
{
|
{
|
||||||
|
if(!objectMatchesFilter(objToVisit))
|
||||||
|
continue;
|
||||||
|
|
||||||
#if AI_TRACE_LEVEL >= 1
|
#if AI_TRACE_LEVEL >= 1
|
||||||
logAi->trace("Checking object %s, %s", objToVisit->getObjectName(), objToVisit->visitablePos().toString());
|
logAi->trace("Checking object %s, %s", objToVisit->getObjectName(), objToVisit->visitablePos().toString());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(!objectMatchesFilter(objToVisit))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const int3 pos = objToVisit->visitablePos();
|
const int3 pos = objToVisit->visitablePos();
|
||||||
|
|
||||||
auto paths = ai->nullkiller->pathfinder->getPathInfo(pos);
|
auto paths = ai->nullkiller->pathfinder->getPathInfo(pos);
|
||||||
|
@ -14,8 +14,11 @@
|
|||||||
#include "../AIUtility.h"
|
#include "../AIUtility.h"
|
||||||
#include "../Goals/BuyArmy.h"
|
#include "../Goals/BuyArmy.h"
|
||||||
#include "../Goals/ExecuteHeroChain.h"
|
#include "../Goals/ExecuteHeroChain.h"
|
||||||
|
#include "../Behaviors/CaptureObjectsBehavior.h"
|
||||||
#include "../Goals/RecruitHero.h"
|
#include "../Goals/RecruitHero.h"
|
||||||
#include "../Goals/DismissHero.h"
|
#include "../Goals/DismissHero.h"
|
||||||
|
#include "../Goals/Composition.h"
|
||||||
|
#include "../Markers/DefendTown.h"
|
||||||
#include "../Goals/ExchangeSwapTownHeroes.h"
|
#include "../Goals/ExchangeSwapTownHeroes.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"
|
||||||
@ -42,28 +45,9 @@ Goals::TGoalVec DefenceBehavior::decompose() const
|
|||||||
return tasks;
|
return tasks;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t townArmyIncome(const CGTownInstance * town)
|
|
||||||
{
|
|
||||||
uint64_t result = 0;
|
|
||||||
|
|
||||||
for(auto creatureInfo : town->creatures)
|
|
||||||
{
|
|
||||||
if(creatureInfo.second.empty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto creature = creatureInfo.second.back().toCreature();
|
|
||||||
result += creature->AIValue * town->getGrowthInfo(creature->level).totalGrowth();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInstance * town) const
|
void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInstance * town) const
|
||||||
{
|
{
|
||||||
auto basicPriority = 0.3f + std::sqrt(townArmyIncome(town) / 40000.0f)
|
logAi->debug("Evaluating defence for %s", town->name);
|
||||||
+ town->dailyIncome()[Res::GOLD] / 10000.0f;
|
|
||||||
|
|
||||||
logAi->debug("Evaluating defence for %s, basic priority %f", town->name, basicPriority);
|
|
||||||
|
|
||||||
auto treatNode = ai->nullkiller->dangerHitMap->getObjectTreat(town);
|
auto treatNode = ai->nullkiller->dangerHitMap->getObjectTreat(town);
|
||||||
auto treats = { treatNode.fastestDanger, treatNode.maximumDanger };
|
auto treats = { treatNode.fastestDanger, treatNode.maximumDanger };
|
||||||
@ -195,11 +179,13 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Goals::ExecuteHeroChain> pathsToDefend;
|
std::vector<int> pathsToDefend;
|
||||||
std::map<const CGHeroInstance *, std::vector<AIPath>> defferedPaths;
|
std::map<const CGHeroInstance *, std::vector<int>> defferedPaths;
|
||||||
|
|
||||||
for(AIPath & path : paths)
|
for(int i = 0; i < paths.size(); i++)
|
||||||
{
|
{
|
||||||
|
auto & path = paths[i];
|
||||||
|
|
||||||
#if AI_TRACE_LEVEL >= 1
|
#if AI_TRACE_LEVEL >= 1
|
||||||
logAi->trace(
|
logAi->trace(
|
||||||
"Hero %s can defend town with force %lld in %s turns, cost: %f, path: %s",
|
"Hero %s can defend town with force %lld in %s turns, cost: %f, path: %s",
|
||||||
@ -215,27 +201,29 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
|
|||||||
town->name,
|
town->name,
|
||||||
path.targetHero->name);
|
path.targetHero->name);
|
||||||
|
|
||||||
defferedPaths[path.targetHero].push_back(path);
|
defferedPaths[path.targetHero].push_back(i);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
float priority = basicPriority * std::min(SAFE_ATTACK_CONSTANT, (float)path.getHeroStrength() / treat.danger)
|
|
||||||
- treat.turn * 0.2f;
|
|
||||||
|
|
||||||
if(treat.turn < path.turn())
|
|
||||||
priority /= (path.turn() - treat.turn) * 2;
|
|
||||||
|
|
||||||
if(path.targetHero == town->visitingHero && path.exchangeCount == 1)
|
if(path.targetHero == town->visitingHero && path.exchangeCount == 1)
|
||||||
{
|
{
|
||||||
#if AI_TRACE_LEVEL >= 1
|
#if AI_TRACE_LEVEL >= 1
|
||||||
logAi->trace("Put %s to garrison of town %s with priority %f",
|
logAi->trace("Put %s to garrison of town %s",
|
||||||
path.targetHero->name,
|
path.targetHero->name,
|
||||||
town->name,
|
town->name);
|
||||||
priority);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
tasks.push_back(Goals::sptr(Goals::ExchangeSwapTownHeroes(town, town->visitingHero.get(), HeroLockedReason::DEFENCE).setpriority(priority)));
|
// dismiss creatures we are not able to pick to be able to hide in garrison
|
||||||
|
if(town->garrisonHero
|
||||||
|
|| town->getUpperArmy()->stacksCount() == 0
|
||||||
|
|| town->getUpperArmy()->getArmyStrength() < 500 && town->fortLevel() >= CGTownInstance::CITADEL)
|
||||||
|
{
|
||||||
|
tasks.push_back(
|
||||||
|
Goals::sptr(Composition()
|
||||||
|
.addNext(DefendTown(town, treat, path.targetHero))
|
||||||
|
.addNext(ExchangeSwapTownHeroes(town, town->visitingHero.get(), HeroLockedReason::DEFENCE))));
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -245,25 +233,26 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
|
|||||||
if(ai->nullkiller->arePathHeroesLocked(path))
|
if(ai->nullkiller->arePathHeroesLocked(path))
|
||||||
{
|
{
|
||||||
#if AI_TRACE_LEVEL >= 1
|
#if AI_TRACE_LEVEL >= 1
|
||||||
logAi->trace("Can not move %s to defend town %s with priority %f. Path is locked.",
|
logAi->trace("Can not move %s to defend town %s. Path is locked.",
|
||||||
path.targetHero->name,
|
path.targetHero->name,
|
||||||
town->name,
|
town->name);
|
||||||
priority);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
pathsToDefend.push_back(Goals::ExecuteHeroChain(path, town).setpriority(priority));
|
pathsToDefend.push_back(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(Goals::ExecuteHeroChain & chain : pathsToDefend)
|
for(int i : pathsToDefend)
|
||||||
{
|
{
|
||||||
auto path = chain.getPath();
|
AIPath & path = paths[i];
|
||||||
|
|
||||||
for(AIPath & defferedPath : defferedPaths[path.targetHero])
|
for(int j : defferedPaths[path.targetHero])
|
||||||
{
|
{
|
||||||
|
AIPath & defferedPath = paths[j];
|
||||||
|
|
||||||
if(defferedPath.getHeroStrength() >= path.getHeroStrength()
|
if(defferedPath.getHeroStrength() >= path.getHeroStrength()
|
||||||
&& defferedPath.turn() <= path.turn())
|
&& defferedPath.turn() <= path.turn())
|
||||||
{
|
{
|
||||||
@ -272,13 +261,35 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if AI_TRACE_LEVEL >= 1
|
#if AI_TRACE_LEVEL >= 1
|
||||||
logAi->trace("Move %s to defend town %s with priority %f",
|
logAi->trace("Move %s to defend town %s",
|
||||||
path.targetHero->name,
|
path.targetHero->name,
|
||||||
town->name,
|
town->name);
|
||||||
chain.priority);
|
#endif
|
||||||
|
Composition composition;
|
||||||
|
|
||||||
|
composition.addNext(DefendTown(town, treat, path)).addNext(ExecuteHeroChain(path, town));
|
||||||
|
|
||||||
|
auto firstBlockedAction = path.getFirstBlockedAction();
|
||||||
|
if(firstBlockedAction)
|
||||||
|
{
|
||||||
|
auto subGoal = firstBlockedAction->decompose(path.targetHero);
|
||||||
|
|
||||||
|
#if AI_TRACE_LEVEL >= 2
|
||||||
|
logAi->trace("Decomposing special action %s returns %s", firstBlockedAction->toString(), subGoal->toString());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
tasks.push_back(Goals::sptr(chain));
|
if(subGoal->invalid())
|
||||||
|
{
|
||||||
|
#if AI_TRACE_LEVEL >= 1
|
||||||
|
logAi->trace("Path is invalid. Skipping");
|
||||||
|
#endif
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
composition.addNext(subGoal);
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.push_back(Goals::sptr(composition));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,11 +175,17 @@ Goals::TGoalVec StartupBehavior::decompose() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(canRecruitHero)
|
else if(canRecruitHero)
|
||||||
|
{
|
||||||
|
auto canPickTownArmy = startupTown->stacksCount() == 0
|
||||||
|
|| ai->nullkiller->armyManager->howManyReinforcementsCanGet(startupTown->visitingHero, startupTown) > 0;
|
||||||
|
|
||||||
|
if(canPickTownArmy)
|
||||||
{
|
{
|
||||||
tasks.push_back(Goals::sptr(ExchangeSwapTownHeroes(startupTown, visitingHero, HeroLockedReason::STARTUP).setpriority(100)));
|
tasks.push_back(Goals::sptr(ExchangeSwapTownHeroes(startupTown, visitingHero, HeroLockedReason::STARTUP).setpriority(100)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(tasks.empty() && canRecruitHero && !startupTown->visitingHero)
|
if(tasks.empty() && canRecruitHero && !startupTown->visitingHero)
|
||||||
{
|
{
|
||||||
|
@ -37,6 +37,7 @@ set(VCAI_SRCS
|
|||||||
Markers/ArmyUpgrade.cpp
|
Markers/ArmyUpgrade.cpp
|
||||||
Markers/HeroExchange.cpp
|
Markers/HeroExchange.cpp
|
||||||
Markers/UnlockCluster.cpp
|
Markers/UnlockCluster.cpp
|
||||||
|
Markers/DefendTown.cpp
|
||||||
Engine/Nullkiller.cpp
|
Engine/Nullkiller.cpp
|
||||||
Engine/DeepDecomposer.cpp
|
Engine/DeepDecomposer.cpp
|
||||||
Engine/PriorityEvaluator.cpp
|
Engine/PriorityEvaluator.cpp
|
||||||
@ -97,6 +98,7 @@ set(VCAI_HEADERS
|
|||||||
Markers/ArmyUpgrade.h
|
Markers/ArmyUpgrade.h
|
||||||
Markers/HeroExchange.h
|
Markers/HeroExchange.h
|
||||||
Markers/UnlockCluster.h
|
Markers/UnlockCluster.h
|
||||||
|
Markers/DefendTown.h
|
||||||
Engine/Nullkiller.h
|
Engine/Nullkiller.h
|
||||||
Engine/DeepDecomposer.h
|
Engine/DeepDecomposer.h
|
||||||
Engine/PriorityEvaluator.h
|
Engine/PriorityEvaluator.h
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "../Goals/BuildThis.h"
|
#include "../Goals/BuildThis.h"
|
||||||
#include "../Markers/HeroExchange.h"
|
#include "../Markers/HeroExchange.h"
|
||||||
#include "../Markers/ArmyUpgrade.h"
|
#include "../Markers/ArmyUpgrade.h"
|
||||||
|
#include "../Markers/DefendTown.h"
|
||||||
|
|
||||||
#define MIN_AI_STRENGHT (0.5f) //lower when combat AI gets smarter
|
#define MIN_AI_STRENGHT (0.5f) //lower when combat AI gets smarter
|
||||||
#define UNGUARDED_OBJECT (100.0f) //we consider unguarded objects 100 times weaker than us
|
#define UNGUARDED_OBJECT (100.0f) //we consider unguarded objects 100 times weaker than us
|
||||||
@ -493,6 +494,51 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DefendTownEvaluator : public IEvaluationContextBuilder
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
uint64_t townArmyIncome(const CGTownInstance * town) const
|
||||||
|
{
|
||||||
|
uint64_t result = 0;
|
||||||
|
|
||||||
|
for(auto creatureInfo : town->creatures)
|
||||||
|
{
|
||||||
|
if(creatureInfo.second.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto creature = creatureInfo.second.back().toCreature();
|
||||||
|
result += creature->AIValue * town->getGrowthInfo(creature->level).totalGrowth();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void buildEvaluationContext(EvaluationContext & evaluationContext, Goals::TSubgoal task) const override
|
||||||
|
{
|
||||||
|
if(task->goalType != Goals::DEFEND_TOWN)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Goals::DefendTown & defendTown = dynamic_cast<Goals::DefendTown &>(*task);
|
||||||
|
const CGTownInstance * town = defendTown.town;
|
||||||
|
auto & treat = defendTown.getTreat();
|
||||||
|
|
||||||
|
auto armyIncome = townArmyIncome(town);
|
||||||
|
auto dailyIncome = town->dailyIncome()[Res::GOLD];
|
||||||
|
|
||||||
|
auto strategicalValue = std::sqrt(armyIncome / 20000.0f) + dailyIncome / 10000.0f;
|
||||||
|
|
||||||
|
float multiplier = 1;
|
||||||
|
|
||||||
|
if(treat.turn < defendTown.getTurn())
|
||||||
|
multiplier /= 1 + (defendTown.getTurn() - treat.turn);
|
||||||
|
|
||||||
|
evaluationContext.armyReward += armyIncome * multiplier;
|
||||||
|
evaluationContext.goldReward += dailyIncome * 5 * multiplier;
|
||||||
|
evaluationContext.strategicalValue += strategicalValue * multiplier;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class ExecuteHeroChainEvaluationContextBuilder : public IEvaluationContextBuilder
|
class ExecuteHeroChainEvaluationContextBuilder : public IEvaluationContextBuilder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -653,6 +699,8 @@ PriorityEvaluator::PriorityEvaluator(const Nullkiller * ai)
|
|||||||
evaluationContextBuilders.push_back(std::make_shared<BuildThisEvaluationContextBuilder>());
|
evaluationContextBuilders.push_back(std::make_shared<BuildThisEvaluationContextBuilder>());
|
||||||
evaluationContextBuilders.push_back(std::make_shared<ClusterEvaluationContextBuilder>());
|
evaluationContextBuilders.push_back(std::make_shared<ClusterEvaluationContextBuilder>());
|
||||||
evaluationContextBuilders.push_back(std::make_shared<HeroExchangeEvaluator>());
|
evaluationContextBuilders.push_back(std::make_shared<HeroExchangeEvaluator>());
|
||||||
|
evaluationContextBuilders.push_back(std::make_shared<ArmyUpgradeEvaluator>());
|
||||||
|
evaluationContextBuilders.push_back(std::make_shared<ArmyUpgradeEvaluator>());
|
||||||
}
|
}
|
||||||
|
|
||||||
EvaluationContext PriorityEvaluator::buildEvaluationContext(Goals::TSubgoal goal) const
|
EvaluationContext PriorityEvaluator::buildEvaluationContext(Goals::TSubgoal goal) const
|
||||||
|
@ -65,7 +65,8 @@ namespace Goals
|
|||||||
CLUSTER_BEHAVIOR,
|
CLUSTER_BEHAVIOR,
|
||||||
UNLOCK_CLUSTER,
|
UNLOCK_CLUSTER,
|
||||||
HERO_EXCHANGE,
|
HERO_EXCHANGE,
|
||||||
ARMY_UPGRADE
|
ARMY_UPGRADE,
|
||||||
|
DEFEND_TOWN
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT TSubgoal : public std::shared_ptr<AbstractGoal>
|
class DLL_EXPORT TSubgoal : public std::shared_ptr<AbstractGoal>
|
||||||
|
@ -199,7 +199,7 @@ TGoalVec CompleteQuest::missionKeymaster() const
|
|||||||
|
|
||||||
TGoalVec CompleteQuest::missionResources() const
|
TGoalVec CompleteQuest::missionResources() const
|
||||||
{
|
{
|
||||||
TGoalVec solutions;
|
TGoalVec solutions = tryCompleteQuest();
|
||||||
|
|
||||||
/*auto heroes = cb->getHeroesInfo(); //TODO: choose best / free hero from among many possibilities?
|
/*auto heroes = cb->getHeroesInfo(); //TODO: choose best / free hero from among many possibilities?
|
||||||
|
|
||||||
|
@ -61,24 +61,15 @@ void ExchangeSwapTownHeroes::accept(VCAI * ai)
|
|||||||
|
|
||||||
auto upperArmy = town->getUpperArmy();
|
auto upperArmy = town->getUpperArmy();
|
||||||
|
|
||||||
if(!town->garrisonHero && upperArmy->stacksCount() != 0)
|
if(!town->garrisonHero)
|
||||||
{
|
{
|
||||||
// dismiss creatures we are not able to pick to be able to hide in garrison
|
while(upperArmy->stacksCount() != 0)
|
||||||
if(upperArmy->getArmyStrength() < 500
|
|
||||||
&& town->fortLevel() >= CGTownInstance::CITADEL)
|
|
||||||
{
|
{
|
||||||
for(auto slot : upperArmy->Slots())
|
cb->dismissCreature(upperArmy, upperArmy->Slots().begin()->first);
|
||||||
{
|
}
|
||||||
cb->dismissCreature(upperArmy, slot.first);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cb->swapGarrisonHero(town);
|
cb->swapGarrisonHero(town);
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cb->swapGarrisonHero(town); // selected hero left in garrison with strongest army
|
|
||||||
}
|
|
||||||
|
|
||||||
ai->nullkiller->lockHero(garrisonHero, lockingReason);
|
ai->nullkiller->lockHero(garrisonHero, lockingReason);
|
||||||
|
|
||||||
|
40
AI/Nullkiller/Markers/DefendTown.cpp
Normal file
40
AI/Nullkiller/Markers/DefendTown.cpp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* ArmyUpgrade.cpp, part of VCMI engine
|
||||||
|
*
|
||||||
|
* Authors: listed in file AUTHORS in main folder
|
||||||
|
*
|
||||||
|
* License: GNU General Public License v2.0 or later
|
||||||
|
* Full text of license available in license.txt file, in main folder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "StdInc.h"
|
||||||
|
#include "DefendTown.h"
|
||||||
|
#include "../VCAI.h"
|
||||||
|
#include "../Engine/Nullkiller.h"
|
||||||
|
#include "../AIUtility.h"
|
||||||
|
|
||||||
|
using namespace Goals;
|
||||||
|
|
||||||
|
DefendTown::DefendTown(const CGTownInstance * town, const HitMapInfo & treat, const AIPath & defencePath)
|
||||||
|
: CGoal(Goals::DEFEND_TOWN), treat(treat), defenceArmyStrength(defencePath.getHeroStrength()), turn(defencePath.turn())
|
||||||
|
{
|
||||||
|
settown(town);
|
||||||
|
sethero(defencePath.targetHero);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefendTown::DefendTown(const CGTownInstance * town, const HitMapInfo & treat, const CGHeroInstance * defender)
|
||||||
|
: CGoal(Goals::DEFEND_TOWN), treat(treat), defenceArmyStrength(defender->getTotalStrength()), turn(0)
|
||||||
|
{
|
||||||
|
settown(town);
|
||||||
|
sethero(defender);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DefendTown::operator==(const DefendTown & other) const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string DefendTown::toString() const
|
||||||
|
{
|
||||||
|
return "Defend town " + town->getObjectName();
|
||||||
|
}
|
39
AI/Nullkiller/Markers/DefendTown.h
Normal file
39
AI/Nullkiller/Markers/DefendTown.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* ArmyUpgrade.h, part of VCMI engine
|
||||||
|
*
|
||||||
|
* Authors: listed in file AUTHORS in main folder
|
||||||
|
*
|
||||||
|
* License: GNU General Public License v2.0 or later
|
||||||
|
* Full text of license available in license.txt file, in main folder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../Goals/CGoal.h"
|
||||||
|
#include "../Pathfinding/AINodeStorage.h"
|
||||||
|
#include "../Analyzers/ArmyManager.h"
|
||||||
|
#include "../Analyzers/DangerHitMapAnalyzer.h"
|
||||||
|
|
||||||
|
namespace Goals
|
||||||
|
{
|
||||||
|
class DLL_EXPORT DefendTown : public CGoal<DefendTown>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
uint64_t defenceArmyStrength;
|
||||||
|
HitMapInfo treat;
|
||||||
|
uint8_t turn;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DefendTown(const CGTownInstance * town, const HitMapInfo & treat, const AIPath & defencePath);
|
||||||
|
DefendTown(const CGTownInstance * town, const HitMapInfo & treat, const CGHeroInstance * defender);
|
||||||
|
|
||||||
|
virtual bool operator==(const DefendTown & other) const override;
|
||||||
|
virtual std::string toString() const override;
|
||||||
|
|
||||||
|
const HitMapInfo & getTreat() const { return treat; }
|
||||||
|
|
||||||
|
uint64_t getDefenceStrength() const { return defenceArmyStrength; }
|
||||||
|
|
||||||
|
uint8_t getTurn() const { return turn; }
|
||||||
|
};
|
||||||
|
}
|
@ -11,7 +11,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define PATHFINDER_TRACE_LEVEL 0
|
#define PATHFINDER_TRACE_LEVEL 0
|
||||||
#define AI_TRACE_LEVEL 1
|
#define AI_TRACE_LEVEL 0
|
||||||
#define SCOUT_TURN_DISTANCE_LIMIT 3
|
#define SCOUT_TURN_DISTANCE_LIMIT 3
|
||||||
|
|
||||||
#include "../../../lib/CPathfinder.h"
|
#include "../../../lib/CPathfinder.h"
|
||||||
|
@ -283,6 +283,7 @@ HeroActor * HeroExchangeMap::exchange(const ChainActor * other)
|
|||||||
{
|
{
|
||||||
newArmy = pickBestCreatures(upgradedInitialArmy, other->creatureSet);
|
newArmy = pickBestCreatures(upgradedInitialArmy, other->creatureSet);
|
||||||
newArmy->armyCost = upgradedInitialArmy->armyCost;
|
newArmy->armyCost = upgradedInitialArmy->armyCost;
|
||||||
|
newArmy->requireBuyArmy = upgradedInitialArmy->requireBuyArmy;
|
||||||
|
|
||||||
delete upgradedInitialArmy;
|
delete upgradedInitialArmy;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user