mirror of
https://github.com/vcmi/vcmi.git
synced 2025-07-17 01:32:21 +02:00
NKAI: moddable configuration
This commit is contained in:
@ -677,9 +677,9 @@ void AIGateway::showBlockingDialog(const std::string & text, const std::vector<C
|
|||||||
&& components.size() == 2
|
&& components.size() == 2
|
||||||
&& components.front().type == ComponentType::RESOURCE
|
&& components.front().type == ComponentType::RESOURCE
|
||||||
&& (nullkiller->heroManager->getHeroRole(hero) != HeroRole::MAIN
|
&& (nullkiller->heroManager->getHeroRole(hero) != HeroRole::MAIN
|
||||||
|| nullkiller->buildAnalyzer->getGoldPreasure() > MAX_GOLD_PEASURE))
|
|| nullkiller->buildAnalyzer->isGoldPreasureHigh()))
|
||||||
{
|
{
|
||||||
sel = 1; // for now lets pick gold from a chest.
|
sel = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,7 +437,7 @@ bool shouldVisit(const Nullkiller * ai, const CGHeroInstance * h, const CGObject
|
|||||||
case Obj::MAGIC_WELL:
|
case Obj::MAGIC_WELL:
|
||||||
return h->mana < h->manaLimit();
|
return h->mana < h->manaLimit();
|
||||||
case Obj::PRISON:
|
case Obj::PRISON:
|
||||||
return ai->cb->getHeroesInfo().size() < VLC->settings()->getInteger(EGameSettings::HEROES_PER_PLAYER_ON_MAP_CAP);
|
return !ai->heroManager->heroCapReached();
|
||||||
case Obj::TAVERN:
|
case Obj::TAVERN:
|
||||||
case Obj::EYE_OF_MAGI:
|
case Obj::EYE_OF_MAGI:
|
||||||
case Obj::BOAT:
|
case Obj::BOAT:
|
||||||
|
@ -120,6 +120,11 @@ TResources BuildAnalyzer::getTotalResourcesRequired() const
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BuildAnalyzer::isGoldPreasureHigh() const
|
||||||
|
{
|
||||||
|
return goldPreasure > ai->settings->getMaxGoldPreasure();
|
||||||
|
}
|
||||||
|
|
||||||
void BuildAnalyzer::update()
|
void BuildAnalyzer::update()
|
||||||
{
|
{
|
||||||
logAi->trace("Start analysing build");
|
logAi->trace("Start analysing build");
|
||||||
|
@ -96,6 +96,7 @@ public:
|
|||||||
const std::vector<TownDevelopmentInfo> & getDevelopmentInfo() const { return developmentInfos; }
|
const std::vector<TownDevelopmentInfo> & getDevelopmentInfo() const { return developmentInfos; }
|
||||||
TResources getDailyIncome() const { return dailyIncome; }
|
TResources getDailyIncome() const { return dailyIncome; }
|
||||||
float getGoldPreasure() const { return goldPreasure; }
|
float getGoldPreasure() const { return goldPreasure; }
|
||||||
|
bool isGoldPreasureHigh() const;
|
||||||
bool hasAnyBuilding(int32_t alignment, BuildingID bid) const;
|
bool hasAnyBuilding(int32_t alignment, BuildingID bid) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -187,6 +187,7 @@ bool HeroManager::heroCapReached() const
|
|||||||
int heroCount = cb->getHeroCount(ai->playerID, includeGarnisoned);
|
int heroCount = cb->getHeroCount(ai->playerID, includeGarnisoned);
|
||||||
|
|
||||||
return heroCount >= ALLOWED_ROAMING_HEROES
|
return heroCount >= ALLOWED_ROAMING_HEROES
|
||||||
|
|| heroCount >= ai->settings->getMaxRoamingHeroes()
|
||||||
|| heroCount >= VLC->settings()->getInteger(EGameSettings::HEROES_PER_PLAYER_ON_MAP_CAP)
|
|| heroCount >= VLC->settings()->getInteger(EGameSettings::HEROES_PER_PLAYER_ON_MAP_CAP)
|
||||||
|| heroCount >= VLC->settings()->getInteger(EGameSettings::HEROES_PER_PLAYER_TOTAL_CAP);
|
|| heroCount >= VLC->settings()->getInteger(EGameSettings::HEROES_PER_PLAYER_TOTAL_CAP);
|
||||||
}
|
}
|
||||||
|
@ -47,13 +47,13 @@ Goals::TGoalVec BuildingBehavior::decompose() const
|
|||||||
totalDevelopmentCost.toString());
|
totalDevelopmentCost.toString());
|
||||||
|
|
||||||
auto & developmentInfos = ai->nullkiller->buildAnalyzer->getDevelopmentInfo();
|
auto & developmentInfos = ai->nullkiller->buildAnalyzer->getDevelopmentInfo();
|
||||||
auto goldPreasure = ai->nullkiller->buildAnalyzer->getGoldPreasure();
|
auto isGoldPreasureLow = !ai->nullkiller->buildAnalyzer->isGoldPreasureHigh();
|
||||||
|
|
||||||
for(auto & developmentInfo : developmentInfos)
|
for(auto & developmentInfo : developmentInfos)
|
||||||
{
|
{
|
||||||
for(auto & buildingInfo : developmentInfo.toBuild)
|
for(auto & buildingInfo : developmentInfo.toBuild)
|
||||||
{
|
{
|
||||||
if(goldPreasure < MAX_GOLD_PEASURE || buildingInfo.dailyIncome[EGameResID::GOLD] > 0)
|
if(isGoldPreasureLow || buildingInfo.dailyIncome[EGameResID::GOLD] > 0)
|
||||||
{
|
{
|
||||||
if(buildingInfo.notEnoughRes)
|
if(buildingInfo.notEnoughRes)
|
||||||
{
|
{
|
||||||
|
@ -46,8 +46,7 @@ Goals::TGoalVec BuyArmyBehavior::decompose() const
|
|||||||
|
|
||||||
for(const CGHeroInstance * targetHero : heroes)
|
for(const CGHeroInstance * targetHero : heroes)
|
||||||
{
|
{
|
||||||
if(ai->nullkiller->buildAnalyzer->getGoldPreasure() > MAX_GOLD_PEASURE
|
if(ai->nullkiller->buildAnalyzer->isGoldPreasureHigh() && !town->hasBuilt(BuildingID::CITY_HALL))
|
||||||
&& !town->hasBuilt(BuildingID::CITY_HALL))
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -246,7 +246,7 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const CGTownInstance * upgrader)
|
|||||||
{
|
{
|
||||||
auto heroRole = ai->nullkiller->heroManager->getHeroRole(path.targetHero);
|
auto heroRole = ai->nullkiller->heroManager->getHeroRole(path.targetHero);
|
||||||
|
|
||||||
if(heroRole == HeroRole::MAIN && path.turn() < SCOUT_TURN_DISTANCE_LIMIT)
|
if(heroRole == HeroRole::MAIN && path.turn() < ai->nullkiller->settings->getScoutHeroTurnDistanceLimit())
|
||||||
hasMainAround = true;
|
hasMainAround = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,7 +335,7 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const CGTownInstance * upgrader)
|
|||||||
if(!upgrade.upgradeValue
|
if(!upgrade.upgradeValue
|
||||||
&& armyToGetOrBuy.upgradeValue > 20000
|
&& armyToGetOrBuy.upgradeValue > 20000
|
||||||
&& ai->nullkiller->heroManager->canRecruitHero(town)
|
&& ai->nullkiller->heroManager->canRecruitHero(town)
|
||||||
&& path.turn() < SCOUT_TURN_DISTANCE_LIMIT)
|
&& path.turn() < ai->nullkiller->settings->getScoutHeroTurnDistanceLimit())
|
||||||
{
|
{
|
||||||
for(auto hero : cb->getAvailableHeroes(town))
|
for(auto hero : cb->getAvailableHeroes(town))
|
||||||
{
|
{
|
||||||
@ -344,7 +344,7 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const CGTownInstance * upgrader)
|
|||||||
|
|
||||||
if(scoutReinforcement >= armyToGetOrBuy.upgradeValue
|
if(scoutReinforcement >= armyToGetOrBuy.upgradeValue
|
||||||
&& ai->nullkiller->getFreeGold() >20000
|
&& ai->nullkiller->getFreeGold() >20000
|
||||||
&& ai->nullkiller->buildAnalyzer->getGoldPreasure() < MAX_GOLD_PEASURE)
|
&& !ai->nullkiller->buildAnalyzer->isGoldPreasureHigh())
|
||||||
{
|
{
|
||||||
Composition recruitHero;
|
Composition recruitHero;
|
||||||
|
|
||||||
|
@ -85,8 +85,7 @@ Goals::TGoalVec RecruitHeroBehavior::decompose() const
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(cb->getHeroesInfo().size() < cb->getTownsInfo().size() + 1
|
if(cb->getHeroesInfo().size() < cb->getTownsInfo().size() + 1
|
||||||
|| (ai->nullkiller->getFreeResources()[EGameResID::GOLD] > 10000
|
|| (ai->nullkiller->getFreeResources()[EGameResID::GOLD] > 10000 && !ai->nullkiller->buildAnalyzer->isGoldPreasureHigh()))
|
||||||
&& ai->nullkiller->buildAnalyzer->getGoldPreasure() < MAX_GOLD_PEASURE))
|
|
||||||
{
|
{
|
||||||
tasks.push_back(Goals::sptr(Goals::RecruitHero(town).setpriority(3)));
|
tasks.push_back(Goals::sptr(Goals::RecruitHero(town).setpriority(3)));
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ set(Nullkiller_SRCS
|
|||||||
AIUtility.cpp
|
AIUtility.cpp
|
||||||
Analyzers/ArmyManager.cpp
|
Analyzers/ArmyManager.cpp
|
||||||
Analyzers/HeroManager.cpp
|
Analyzers/HeroManager.cpp
|
||||||
|
Engine/Settings.cpp
|
||||||
Engine/FuzzyEngines.cpp
|
Engine/FuzzyEngines.cpp
|
||||||
Engine/FuzzyHelper.cpp
|
Engine/FuzzyHelper.cpp
|
||||||
Engine/AIMemory.cpp
|
Engine/AIMemory.cpp
|
||||||
@ -80,6 +81,7 @@ set(Nullkiller_HEADERS
|
|||||||
AIUtility.h
|
AIUtility.h
|
||||||
Analyzers/ArmyManager.h
|
Analyzers/ArmyManager.h
|
||||||
Analyzers/HeroManager.h
|
Analyzers/HeroManager.h
|
||||||
|
Engine/Settings.h
|
||||||
Engine/FuzzyEngines.h
|
Engine/FuzzyEngines.h
|
||||||
Engine/FuzzyHelper.h
|
Engine/FuzzyHelper.h
|
||||||
Engine/AIMemory.h
|
Engine/AIMemory.h
|
||||||
|
@ -27,15 +27,11 @@ namespace NKAI
|
|||||||
|
|
||||||
using namespace Goals;
|
using namespace Goals;
|
||||||
|
|
||||||
#if NKAI_TRACE_LEVEL >= 1
|
|
||||||
#define MAXPASS 1000000
|
|
||||||
#else
|
|
||||||
#define MAXPASS 30
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Nullkiller::Nullkiller()
|
Nullkiller::Nullkiller()
|
||||||
|
:activeHero(nullptr), scanDepth(ScanDepth::MAIN_FULL), useHeroChain(true)
|
||||||
{
|
{
|
||||||
memory.reset(new AIMemory());
|
memory = std::make_unique<AIMemory>();
|
||||||
|
settings = std::make_unique<Settings>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Nullkiller::init(std::shared_ptr<CCallback> cb, PlayerColor playerID)
|
void Nullkiller::init(std::shared_ptr<CCallback> cb, PlayerColor playerID)
|
||||||
@ -166,12 +162,12 @@ void Nullkiller::updateAiState(int pass, bool fast)
|
|||||||
|
|
||||||
if(scanDepth == ScanDepth::SMALL)
|
if(scanDepth == ScanDepth::SMALL)
|
||||||
{
|
{
|
||||||
cfg.mainTurnDistanceLimit = MAIN_TURN_DISTANCE_LIMIT;
|
cfg.mainTurnDistanceLimit = ai->nullkiller->settings->getMainHeroTurnDistanceLimit();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(scanDepth != ScanDepth::ALL_FULL)
|
if(scanDepth != ScanDepth::ALL_FULL)
|
||||||
{
|
{
|
||||||
cfg.scoutTurnDistanceLimit = SCOUT_TURN_DISTANCE_LIMIT;
|
cfg.scoutTurnDistanceLimit = ai->nullkiller->settings->getScoutHeroTurnDistanceLimit();
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::this_thread::interruption_point();
|
boost::this_thread::interruption_point();
|
||||||
@ -235,13 +231,13 @@ void Nullkiller::makeTurn()
|
|||||||
|
|
||||||
resetAiState();
|
resetAiState();
|
||||||
|
|
||||||
for(int i = 1; i <= MAXPASS; i++)
|
for(int i = 1; i <= settings->getMaxPass(); i++)
|
||||||
{
|
{
|
||||||
updateAiState(i);
|
updateAiState(i);
|
||||||
|
|
||||||
Goals::TTask bestTask = taskptr(Goals::Invalid());
|
Goals::TTask bestTask = taskptr(Goals::Invalid());
|
||||||
|
|
||||||
for(;i <= MAXPASS; i++)
|
for(;i <= settings->getMaxPass(); i++)
|
||||||
{
|
{
|
||||||
Goals::TTaskVec fastTasks = {
|
Goals::TTaskVec fastTasks = {
|
||||||
choseBestTask(sptr(BuyArmyBehavior()), 1),
|
choseBestTask(sptr(BuyArmyBehavior()), 1),
|
||||||
@ -328,9 +324,9 @@ void Nullkiller::makeTurn()
|
|||||||
|
|
||||||
executeTask(bestTask);
|
executeTask(bestTask);
|
||||||
|
|
||||||
if(i == MAXPASS)
|
if(i == settings->getMaxPass())
|
||||||
{
|
{
|
||||||
logAi->error("Goal %s exceeded maxpass. Terminating AI turn.", taskDescription);
|
logAi->warn("Goal %s exceeded maxpass. Terminating AI turn.", taskDescription);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include "PriorityEvaluator.h"
|
#include "PriorityEvaluator.h"
|
||||||
#include "FuzzyHelper.h"
|
#include "FuzzyHelper.h"
|
||||||
|
#include "Settings.h"
|
||||||
#include "AIMemory.h"
|
#include "AIMemory.h"
|
||||||
#include "DeepDecomposer.h"
|
#include "DeepDecomposer.h"
|
||||||
#include "../Analyzers/DangerHitMapAnalyzer.h"
|
#include "../Analyzers/DangerHitMapAnalyzer.h"
|
||||||
@ -23,7 +24,6 @@
|
|||||||
namespace NKAI
|
namespace NKAI
|
||||||
{
|
{
|
||||||
|
|
||||||
const float MAX_GOLD_PEASURE = 0.3f;
|
|
||||||
const float MIN_PRIORITY = 0.01f;
|
const float MIN_PRIORITY = 0.01f;
|
||||||
const float SMALL_SCAN_MIN_PRIORITY = 0.4f;
|
const float SMALL_SCAN_MIN_PRIORITY = 0.4f;
|
||||||
|
|
||||||
@ -71,6 +71,7 @@ public:
|
|||||||
std::unique_ptr<FuzzyHelper> dangerEvaluator;
|
std::unique_ptr<FuzzyHelper> dangerEvaluator;
|
||||||
std::unique_ptr<DeepDecomposer> decomposer;
|
std::unique_ptr<DeepDecomposer> decomposer;
|
||||||
std::unique_ptr<ArmyFormation> armyFormation;
|
std::unique_ptr<ArmyFormation> armyFormation;
|
||||||
|
std::unique_ptr<Settings> settings;
|
||||||
PlayerColor playerID;
|
PlayerColor playerID;
|
||||||
std::shared_ptr<CCallback> cb;
|
std::shared_ptr<CCallback> cb;
|
||||||
std::mutex aiStateMutex;
|
std::mutex aiStateMutex;
|
||||||
|
@ -69,7 +69,7 @@ PriorityEvaluator::~PriorityEvaluator()
|
|||||||
|
|
||||||
void PriorityEvaluator::initVisitTile()
|
void PriorityEvaluator::initVisitTile()
|
||||||
{
|
{
|
||||||
auto file = CResourceHandler::get()->load(ResourcePath("config/ai/object-priorities.txt"))->readAll();
|
auto file = CResourceHandler::get()->load(ResourcePath("config/ai/nkai/object-priorities.txt"))->readAll();
|
||||||
std::string str = std::string((char *)file.first.get(), file.second);
|
std::string str = std::string((char *)file.first.get(), file.second);
|
||||||
engine = fl::FllImporter().fromString(str);
|
engine = fl::FllImporter().fromString(str);
|
||||||
armyLossPersentageVariable = engine->getInputVariable("armyLoss");
|
armyLossPersentageVariable = engine->getInputVariable("armyLoss");
|
||||||
|
78
AI/Nullkiller/Engine/Settings.cpp
Normal file
78
AI/Nullkiller/Engine/Settings.cpp
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Settings.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 <limits>
|
||||||
|
|
||||||
|
#include "Settings.h"
|
||||||
|
#include "../../../lib/mapObjectConstructors/AObjectTypeHandler.h"
|
||||||
|
#include "../../../lib/mapObjectConstructors/CObjectClassesHandler.h"
|
||||||
|
#include "../../../lib/mapObjectConstructors/CBankInstanceConstructor.h"
|
||||||
|
#include "../../../lib/mapObjects/MapObjects.h"
|
||||||
|
#include "../../../lib/modding/CModHandler.h"
|
||||||
|
#include "../../../lib/VCMI_Lib.h"
|
||||||
|
#include "../../../lib/filesystem/Filesystem.h"
|
||||||
|
#include "../../../lib/json/JsonNode.h"
|
||||||
|
|
||||||
|
namespace NKAI
|
||||||
|
{
|
||||||
|
Settings::Settings()
|
||||||
|
: maxRoamingHeroes(8),
|
||||||
|
mainHeroTurnDistanceLimit(10),
|
||||||
|
scoutHeroTurnDistanceLimit(5),
|
||||||
|
maxGoldPreasure(0.3f),
|
||||||
|
maxpass(30)
|
||||||
|
{
|
||||||
|
ResourcePath resource("config/ai/nkai/nkai-settings", EResType::JSON);
|
||||||
|
|
||||||
|
loadFromMod("core", resource);
|
||||||
|
|
||||||
|
for(const auto & modName : VLC->modh->getActiveMods())
|
||||||
|
{
|
||||||
|
if(CResourceHandler::get(modName)->existsResource(resource))
|
||||||
|
loadFromMod(modName, resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::loadFromMod(const std::string & modName, const ResourcePath & resource)
|
||||||
|
{
|
||||||
|
if(!CResourceHandler::get(modName)->existsResource(resource))
|
||||||
|
{
|
||||||
|
logGlobal->error("Failed to load font %s from mod %s", resource.getName(), modName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonNode node(JsonPath::fromResource(resource), modName);
|
||||||
|
|
||||||
|
if(node.Struct()["maxRoamingHeroes"].isNumber())
|
||||||
|
{
|
||||||
|
maxRoamingHeroes = node.Struct()["maxRoamingHeroes"].Integer();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(node.Struct()["mainHeroTurnDistanceLimit"].isNumber())
|
||||||
|
{
|
||||||
|
mainHeroTurnDistanceLimit = node.Struct()["mainHeroTurnDistanceLimit"].Integer();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(node.Struct()["scoutHeroTurnDistanceLimit"].isNumber())
|
||||||
|
{
|
||||||
|
scoutHeroTurnDistanceLimit = node.Struct()["scoutHeroTurnDistanceLimit"].Integer();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(node.Struct()["maxpass"].isNumber())
|
||||||
|
{
|
||||||
|
maxpass = node.Struct()["maxpass"].Integer();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(node.Struct()["maxGoldPreasure"].isNumber())
|
||||||
|
{
|
||||||
|
maxGoldPreasure = node.Struct()["maxGoldPreasure"].Float();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
42
AI/Nullkiller/Engine/Settings.h
Normal file
42
AI/Nullkiller/Engine/Settings.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Settings.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
|
||||||
|
|
||||||
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
class JsonNode;
|
||||||
|
class ResourcePath;
|
||||||
|
|
||||||
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
|
||||||
|
namespace NKAI
|
||||||
|
{
|
||||||
|
class Settings
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
int maxRoamingHeroes;
|
||||||
|
int mainHeroTurnDistanceLimit;
|
||||||
|
int scoutHeroTurnDistanceLimit;
|
||||||
|
int maxpass;
|
||||||
|
float maxGoldPreasure;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Settings();
|
||||||
|
|
||||||
|
int getMaxPass() const { return maxpass; }
|
||||||
|
float getMaxGoldPreasure() const { return maxGoldPreasure; }
|
||||||
|
int getMaxRoamingHeroes() const { return maxRoamingHeroes; }
|
||||||
|
int getMainHeroTurnDistanceLimit() const { return mainHeroTurnDistanceLimit; }
|
||||||
|
int getScoutHeroTurnDistanceLimit() const { return scoutHeroTurnDistanceLimit; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void loadFromMod(const std::string & modName, const ResourcePath & resource);
|
||||||
|
};
|
||||||
|
}
|
@ -24,9 +24,6 @@
|
|||||||
|
|
||||||
namespace NKAI
|
namespace NKAI
|
||||||
{
|
{
|
||||||
const int SCOUT_TURN_DISTANCE_LIMIT = 5;
|
|
||||||
const int MAIN_TURN_DISTANCE_LIMIT = 10;
|
|
||||||
|
|
||||||
namespace AIPathfinding
|
namespace AIPathfinding
|
||||||
{
|
{
|
||||||
#ifdef ENVIRONMENT64
|
#ifdef ENVIRONMENT64
|
||||||
|
7
config/ai/nkai/nkai-settings.json
Normal file
7
config/ai/nkai/nkai-settings.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"maxRoamingHeroes" : 8,
|
||||||
|
"maxpass" : 30,
|
||||||
|
"mainHeroTurnDistanceLimit" : 10,
|
||||||
|
"scoutHeroTurnDistanceLimit" : 5,
|
||||||
|
"maxGoldPreasure" : 0.3
|
||||||
|
}
|
Reference in New Issue
Block a user