mirror of
https://github.com/vcmi/vcmi.git
synced 2025-02-03 13:01:33 +02:00
commit
f2db64af94
@ -11,12 +11,15 @@
|
|||||||
|
|
||||||
#include "AIhelper.h"
|
#include "AIhelper.h"
|
||||||
#include "ResourceManager.h"
|
#include "ResourceManager.h"
|
||||||
|
#include "BuildingManager.h"
|
||||||
|
|
||||||
boost::thread_specific_ptr<AIhelper> ah;
|
boost::thread_specific_ptr<AIhelper> ah;
|
||||||
|
|
||||||
AIhelper::AIhelper()
|
AIhelper::AIhelper()
|
||||||
{
|
{
|
||||||
resourceManager.reset(new ResourceManager());
|
resourceManager.reset(new ResourceManager());
|
||||||
|
buildingManager.reset(new BuildingManager());
|
||||||
|
//TODO: push to vector
|
||||||
}
|
}
|
||||||
|
|
||||||
AIhelper::~AIhelper()
|
AIhelper::~AIhelper()
|
||||||
@ -30,12 +33,36 @@ bool AIhelper::notifyGoalCompleted(Goals::TSubgoal goal)
|
|||||||
|
|
||||||
void AIhelper::setCB(CPlayerSpecificInfoCallback * CB)
|
void AIhelper::setCB(CPlayerSpecificInfoCallback * CB)
|
||||||
{
|
{
|
||||||
|
//TODO: for
|
||||||
resourceManager->setCB(CB);
|
resourceManager->setCB(CB);
|
||||||
|
buildingManager->setCB(CB);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AIhelper::setAI(VCAI * AI)
|
void AIhelper::setAI(VCAI * AI)
|
||||||
{
|
{
|
||||||
|
//TODO: for loop
|
||||||
resourceManager->setAI(AI);
|
resourceManager->setAI(AI);
|
||||||
|
buildingManager->setAI(AI);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AIhelper::getBuildingOptions(const CGTownInstance * t)
|
||||||
|
{
|
||||||
|
return buildingManager->getBuildingOptions(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<PotentialBuilding> AIhelper::immediateBuilding() const
|
||||||
|
{
|
||||||
|
return buildingManager->immediateBuilding();
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<PotentialBuilding> AIhelper::expensiveBuilding() const
|
||||||
|
{
|
||||||
|
return buildingManager->expensiveBuilding();
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<BuildingID> AIhelper::canBuildAnyStructure(const CGTownInstance * t, const std::vector<BuildingID> & buildList, unsigned int maxDays) const
|
||||||
|
{
|
||||||
|
return buildingManager->canBuildAnyStructure(t, buildList, maxDays);
|
||||||
}
|
}
|
||||||
|
|
||||||
Goals::TSubgoal AIhelper::whatToDo(TResources & res, Goals::TSubgoal goal)
|
Goals::TSubgoal AIhelper::whatToDo(TResources & res, Goals::TSubgoal goal)
|
||||||
|
@ -15,23 +15,28 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ResourceManager.h"
|
#include "ResourceManager.h"
|
||||||
|
#include "BuildingManager.h"
|
||||||
|
|
||||||
class ResourceManager;
|
class ResourceManager;
|
||||||
|
class BuildingManager;
|
||||||
|
|
||||||
|
|
||||||
//indirection interface for various modules
|
//indirection interface for various modules
|
||||||
class DLL_EXPORT AIhelper : public IResourceManager
|
class DLL_EXPORT AIhelper : public IResourceManager, public IBuildingManager
|
||||||
{
|
{
|
||||||
friend class VCAI;
|
friend class VCAI;
|
||||||
friend struct SetGlobalState; //mess?
|
friend struct SetGlobalState; //mess?
|
||||||
|
|
||||||
//members are thread_specific. AIhelper is global
|
//members are thread_specific. AIhelper is global
|
||||||
std::shared_ptr<ResourceManager> resourceManager;
|
std::shared_ptr<ResourceManager> resourceManager;
|
||||||
|
std::shared_ptr<BuildingManager> buildingManager;
|
||||||
|
//TODO: vector<IAbstractManager>
|
||||||
std::shared_ptr<VCAI> ai;
|
std::shared_ptr<VCAI> ai;
|
||||||
public:
|
public:
|
||||||
AIhelper();
|
AIhelper();
|
||||||
~AIhelper();
|
~AIhelper();
|
||||||
|
|
||||||
//TODO: consider common interface with Resource Manager?
|
//from ResourceManager
|
||||||
bool canAfford(const TResources & cost) const;
|
bool canAfford(const TResources & cost) const;
|
||||||
TResources reservedResources() const override;
|
TResources reservedResources() const override;
|
||||||
TResources freeResources() const override;
|
TResources freeResources() const override;
|
||||||
@ -49,5 +54,12 @@ private:
|
|||||||
|
|
||||||
void setCB(CPlayerSpecificInfoCallback * CB) override;
|
void setCB(CPlayerSpecificInfoCallback * CB) override;
|
||||||
void setAI(VCAI * AI) override;
|
void setAI(VCAI * AI) override;
|
||||||
|
|
||||||
|
//from BuildingManager
|
||||||
|
public:
|
||||||
|
bool getBuildingOptions(const CGTownInstance * t) override;
|
||||||
|
boost::optional<PotentialBuilding> immediateBuilding() const override;
|
||||||
|
boost::optional<PotentialBuilding> expensiveBuilding() const override;
|
||||||
|
boost::optional<BuildingID> canBuildAnyStructure(const CGTownInstance * t, const std::vector<BuildingID> & buildList, unsigned int maxDays = 7) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
244
AI/VCAI/BuildingManager.cpp
Normal file
244
AI/VCAI/BuildingManager.cpp
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
/*
|
||||||
|
* BuildingManager.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 "BuildingManager.h"
|
||||||
|
|
||||||
|
#include "../../CCallback.h"
|
||||||
|
#include "../../lib/mapObjects/MapObjects.h"
|
||||||
|
|
||||||
|
bool BuildingManager::tryBuildThisStructure(const CGTownInstance * t, BuildingID building, unsigned int maxDays)
|
||||||
|
{
|
||||||
|
if (maxDays == 0)
|
||||||
|
{
|
||||||
|
logAi->warn("Request to build building %d in 0 days!", building.toEnum());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vstd::contains(t->town->buildings, building))
|
||||||
|
return false; // no such building in town
|
||||||
|
|
||||||
|
if (t->hasBuilt(building)) //Already built? Shouldn't happen in general
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const CBuilding * buildPtr = t->town->buildings.at(building);
|
||||||
|
|
||||||
|
auto toBuild = buildPtr->requirements.getFulfillmentCandidates([&](const BuildingID & buildID)
|
||||||
|
{
|
||||||
|
return t->hasBuilt(buildID);
|
||||||
|
});
|
||||||
|
toBuild.push_back(building);
|
||||||
|
|
||||||
|
for (BuildingID buildID : toBuild)
|
||||||
|
{
|
||||||
|
EBuildingState::EBuildingState canBuild = cb->canBuildStructure(t, buildID);
|
||||||
|
if (canBuild == EBuildingState::HAVE_CAPITAL || canBuild == EBuildingState::FORBIDDEN || canBuild == EBuildingState::NO_WATER)
|
||||||
|
return false; //we won't be able to build this
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxDays && toBuild.size() > maxDays)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//TODO: calculate if we have enough resources to build it in maxDays?
|
||||||
|
|
||||||
|
for (const auto & buildID : toBuild)
|
||||||
|
{
|
||||||
|
const CBuilding * b = t->town->buildings.at(buildID);
|
||||||
|
|
||||||
|
EBuildingState::EBuildingState canBuild = cb->canBuildStructure(t, buildID);
|
||||||
|
if (canBuild == EBuildingState::ALLOWED)
|
||||||
|
{
|
||||||
|
PotentialBuilding pb;
|
||||||
|
pb.bid = buildID;
|
||||||
|
pb.price = t->getBuildingCost(buildID);
|
||||||
|
immediateBuildings.push_back(pb); //these are checked again in try
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (canBuild == EBuildingState::PREREQUIRES)
|
||||||
|
{
|
||||||
|
// can happen when dependencies have their own missing dependencies
|
||||||
|
if (tryBuildThisStructure(t, buildID, maxDays - 1))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (canBuild == EBuildingState::MISSING_BASE)
|
||||||
|
{
|
||||||
|
if (tryBuildThisStructure(t, b->upgrade, maxDays - 1))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (canBuild == EBuildingState::NO_RESOURCES)
|
||||||
|
{
|
||||||
|
//we may need to gather resources for those
|
||||||
|
PotentialBuilding pb;
|
||||||
|
pb.bid = buildID;
|
||||||
|
pb.price = t->getBuildingCost(buildID);
|
||||||
|
expensiveBuildings.push_back(pb); //these are checked again in try
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BuildingManager::tryBuildAnyStructure(const CGTownInstance * t, std::vector<BuildingID> buildList, unsigned int maxDays)
|
||||||
|
{
|
||||||
|
for (const auto & building : buildList)
|
||||||
|
{
|
||||||
|
if (t->hasBuilt(building))
|
||||||
|
continue;
|
||||||
|
return tryBuildThisStructure(t, building, maxDays);
|
||||||
|
|
||||||
|
}
|
||||||
|
return false; //Can't build anything
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<BuildingID> BuildingManager::canBuildAnyStructure(const CGTownInstance * t, const std::vector<BuildingID> & buildList, unsigned int maxDays) const
|
||||||
|
{
|
||||||
|
for (const auto & building : buildList)
|
||||||
|
{
|
||||||
|
if (t->hasBuilt(building))
|
||||||
|
continue;
|
||||||
|
if (cb->canBuildStructure(t, building))
|
||||||
|
return boost::optional<BuildingID>(building);
|
||||||
|
}
|
||||||
|
return boost::optional<BuildingID>(); //Can't build anything
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BuildingManager::tryBuildNextStructure(const CGTownInstance * t, std::vector<BuildingID> buildList, unsigned int maxDays)
|
||||||
|
{
|
||||||
|
for (const auto & building : buildList)
|
||||||
|
{
|
||||||
|
if (t->hasBuilt(building))
|
||||||
|
continue;
|
||||||
|
return tryBuildThisStructure(t, building, maxDays);
|
||||||
|
}
|
||||||
|
return false; //Nothing to build
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildingManager::setCB(CPlayerSpecificInfoCallback * CB)
|
||||||
|
{
|
||||||
|
cb = CB;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildingManager::setAI(VCAI * AI)
|
||||||
|
{
|
||||||
|
ai = AI;
|
||||||
|
}
|
||||||
|
//Set of buildings for different goals. Does not include any prerequisites.
|
||||||
|
static const BuildingID essential[] = { BuildingID::TAVERN, BuildingID::TOWN_HALL };
|
||||||
|
static const BuildingID goldSource[] = { BuildingID::TOWN_HALL, BuildingID::CITY_HALL, BuildingID::CAPITOL };
|
||||||
|
static const BuildingID capitolRequirements[] = { BuildingID::FORT, BuildingID::CITADEL };
|
||||||
|
static const BuildingID unitsSource[] = { BuildingID::DWELL_LVL_1, BuildingID::DWELL_LVL_2, BuildingID::DWELL_LVL_3,
|
||||||
|
BuildingID::DWELL_LVL_4, BuildingID::DWELL_LVL_5, BuildingID::DWELL_LVL_6, BuildingID::DWELL_LVL_7 };
|
||||||
|
static const BuildingID unitsUpgrade[] = { BuildingID::DWELL_LVL_1_UP, BuildingID::DWELL_LVL_2_UP, BuildingID::DWELL_LVL_3_UP,
|
||||||
|
BuildingID::DWELL_LVL_4_UP, BuildingID::DWELL_LVL_5_UP, BuildingID::DWELL_LVL_6_UP, BuildingID::DWELL_LVL_7_UP };
|
||||||
|
static const BuildingID unitGrowth[] = { BuildingID::FORT, BuildingID::CITADEL, BuildingID::CASTLE, BuildingID::HORDE_1,
|
||||||
|
BuildingID::HORDE_1_UPGR, BuildingID::HORDE_2, BuildingID::HORDE_2_UPGR };
|
||||||
|
static const BuildingID _spells[] = { BuildingID::MAGES_GUILD_1, BuildingID::MAGES_GUILD_2, BuildingID::MAGES_GUILD_3,
|
||||||
|
BuildingID::MAGES_GUILD_4, BuildingID::MAGES_GUILD_5 };
|
||||||
|
static const BuildingID extra[] = { BuildingID::RESOURCE_SILO, BuildingID::SPECIAL_1, BuildingID::SPECIAL_2, BuildingID::SPECIAL_3,
|
||||||
|
BuildingID::SPECIAL_4, BuildingID::SHIPYARD }; // all remaining buildings
|
||||||
|
|
||||||
|
bool BuildingManager::getBuildingOptions(const CGTownInstance * t)
|
||||||
|
{
|
||||||
|
//TODO make *real* town development system
|
||||||
|
//TODO: faction-specific development: use special buildings, build dwellings in better order, etc
|
||||||
|
//TODO: build resource silo, defences when needed
|
||||||
|
//Possible - allow "locking" on specific building (build prerequisites and then building itself)
|
||||||
|
|
||||||
|
immediateBuildings.clear();
|
||||||
|
expensiveBuildings.clear();
|
||||||
|
|
||||||
|
//below algorithm focuses on economy growth at start of the game.
|
||||||
|
|
||||||
|
TResources currentRes = cb->getResourceAmount();
|
||||||
|
TResources currentIncome = t->dailyIncome();
|
||||||
|
|
||||||
|
if (tryBuildAnyStructure(t, std::vector<BuildingID>(essential, essential + ARRAY_COUNT(essential))))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
//the more gold the better and less problems later
|
||||||
|
if (tryBuildNextStructure(t, std::vector<BuildingID>(goldSource, goldSource + ARRAY_COUNT(goldSource))))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
//workaround for mantis #2696 - build fort and citadel - building castle will be handled without bug
|
||||||
|
if (vstd::contains(t->builtBuildings, BuildingID::CITY_HALL) &&
|
||||||
|
cb->canBuildStructure(t, BuildingID::CAPITOL) != EBuildingState::HAVE_CAPITAL)
|
||||||
|
{
|
||||||
|
if (cb->canBuildStructure(t, BuildingID::CAPITOL) != EBuildingState::FORBIDDEN)
|
||||||
|
{
|
||||||
|
if (tryBuildNextStructure(t, std::vector<BuildingID>(capitolRequirements,
|
||||||
|
capitolRequirements + ARRAY_COUNT(capitolRequirements))))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: save money for capitol or city hall if capitol unavailable
|
||||||
|
//do not build other things (unless gold source buildings are disabled in map editor)
|
||||||
|
|
||||||
|
|
||||||
|
if (cb->getDate(Date::DAY_OF_WEEK) > 6) // last 2 days of week - try to focus on growth
|
||||||
|
{
|
||||||
|
if (tryBuildNextStructure(t, std::vector<BuildingID>(unitGrowth, unitGrowth + ARRAY_COUNT(unitGrowth)), 2))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// first in-game week or second half of any week: try build dwellings
|
||||||
|
if (cb->getDate(Date::DAY) < 7 || cb->getDate(Date::DAY_OF_WEEK) > 3)
|
||||||
|
{
|
||||||
|
if (tryBuildAnyStructure(t, std::vector<BuildingID>(unitsSource,
|
||||||
|
unitsSource + ARRAY_COUNT(unitsSource)), 8 - cb->getDate(Date::DAY_OF_WEEK)))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//try to upgrade dwelling
|
||||||
|
for (int i = 0; i < ARRAY_COUNT(unitsUpgrade); i++)
|
||||||
|
{
|
||||||
|
if (t->hasBuilt(unitsSource[i]) && !t->hasBuilt(unitsUpgrade[i]))
|
||||||
|
{
|
||||||
|
if (tryBuildThisStructure(t, unitsUpgrade[i]))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//remaining tasks
|
||||||
|
if (tryBuildNextStructure(t, std::vector<BuildingID>(_spells, _spells + ARRAY_COUNT(_spells))))
|
||||||
|
return true;
|
||||||
|
if (tryBuildAnyStructure(t, std::vector<BuildingID>(extra, extra + ARRAY_COUNT(extra))))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
//at the end, try to get and build any extra buildings with nonstandard slots (for example HotA 3rd level dwelling)
|
||||||
|
std::vector<BuildingID> extraBuildings;
|
||||||
|
for (auto buildingInfo : t->town->buildings)
|
||||||
|
{
|
||||||
|
if (buildingInfo.first > 43)
|
||||||
|
extraBuildings.push_back(buildingInfo.first);
|
||||||
|
}
|
||||||
|
if (tryBuildAnyStructure(t, extraBuildings))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<PotentialBuilding> BuildingManager::immediateBuilding() const
|
||||||
|
{
|
||||||
|
if (immediateBuildings.size())
|
||||||
|
return boost::optional<PotentialBuilding>(immediateBuildings.front()); //back? whatever
|
||||||
|
else
|
||||||
|
return boost::optional<PotentialBuilding>();
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<PotentialBuilding> BuildingManager::expensiveBuilding() const
|
||||||
|
{
|
||||||
|
if (expensiveBuildings.size())
|
||||||
|
return boost::optional<PotentialBuilding>(expensiveBuildings.front());
|
||||||
|
else
|
||||||
|
return boost::optional<PotentialBuilding>();
|
||||||
|
}
|
74
AI/VCAI/BuildingManager.h
Normal file
74
AI/VCAI/BuildingManager.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* BuildingManager.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 "AIUtility.h"
|
||||||
|
|
||||||
|
#include "../../lib/GameConstants.h"
|
||||||
|
#include "../../lib/VCMI_Lib.h"
|
||||||
|
#include "../../lib/CTownHandler.h"
|
||||||
|
#include "../../lib/CBuildingHandler.h"
|
||||||
|
#include "VCAI.h"
|
||||||
|
|
||||||
|
struct DLL_EXPORT PotentialBuilding
|
||||||
|
{
|
||||||
|
BuildingID bid;
|
||||||
|
TResources price;
|
||||||
|
//days to build?
|
||||||
|
};
|
||||||
|
|
||||||
|
class DLL_EXPORT IBuildingManager //: public: IAbstractManager
|
||||||
|
{ //info about town development
|
||||||
|
public:
|
||||||
|
virtual ~IBuildingManager() = default;
|
||||||
|
virtual void setCB(CPlayerSpecificInfoCallback * CB) = 0;
|
||||||
|
virtual void setAI(VCAI * AI) = 0;
|
||||||
|
|
||||||
|
virtual bool getBuildingOptions(const CGTownInstance * t) = 0;
|
||||||
|
virtual boost::optional<PotentialBuilding> immediateBuilding() const = 0;
|
||||||
|
virtual boost::optional<PotentialBuilding> expensiveBuilding() const = 0;
|
||||||
|
virtual boost::optional<BuildingID> canBuildAnyStructure(const CGTownInstance * t, const std::vector<BuildingID> & buildList, unsigned int maxDays) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DLL_EXPORT BuildingManager : public IBuildingManager
|
||||||
|
{
|
||||||
|
friend class VCAI;
|
||||||
|
friend class AIhelper;
|
||||||
|
friend struct SetGlobalState;
|
||||||
|
|
||||||
|
CPlayerSpecificInfoCallback * cb; //this is enough, but we downcast from CCallback
|
||||||
|
VCAI * ai;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//try build anything in given town, and execute resulting Goal if any
|
||||||
|
bool getBuildingOptions(const CGTownInstance * t) override;
|
||||||
|
boost::optional<PotentialBuilding> immediateBuilding() const override;
|
||||||
|
boost::optional<PotentialBuilding> expensiveBuilding() const override;
|
||||||
|
boost::optional<BuildingID> canBuildAnyStructure(const CGTownInstance * t, const std::vector<BuildingID> & buildList, unsigned int maxDays = 7) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
bool tryBuildAnyStructure(const CGTownInstance * t, std::vector<BuildingID> buildList, unsigned int maxDays = 7);
|
||||||
|
//try build first unbuilt structure
|
||||||
|
bool tryBuildThisStructure(const CGTownInstance * t, BuildingID building, unsigned int maxDays = 7);
|
||||||
|
//try build ANY unbuilt structure
|
||||||
|
|
||||||
|
bool tryBuildNextStructure(const CGTownInstance * t, std::vector<BuildingID> buildList, unsigned int maxDays = 7);
|
||||||
|
|
||||||
|
private:
|
||||||
|
//TODO: remember current town?
|
||||||
|
std::vector<PotentialBuilding> immediateBuildings; //what we can build right now in current town
|
||||||
|
std::vector<PotentialBuilding> expensiveBuildings; //what we coudl build but can't afford
|
||||||
|
|
||||||
|
void setCB(CPlayerSpecificInfoCallback * CB) override;
|
||||||
|
void setAI(VCAI * AI) override;
|
||||||
|
};
|
@ -11,6 +11,9 @@ set(VCAI_SRCS
|
|||||||
AIUtility.cpp
|
AIUtility.cpp
|
||||||
AIhelper.cpp
|
AIhelper.cpp
|
||||||
ResourceManager.cpp
|
ResourceManager.cpp
|
||||||
|
BuildingManager.cpp
|
||||||
|
MapObjectsEvaluator.cpp
|
||||||
|
BuildingManager.cpp
|
||||||
MapObjectsEvaluator.cpp
|
MapObjectsEvaluator.cpp
|
||||||
Fuzzy.cpp
|
Fuzzy.cpp
|
||||||
Goals.cpp
|
Goals.cpp
|
||||||
@ -24,6 +27,9 @@ set(VCAI_HEADERS
|
|||||||
AIUtility.h
|
AIUtility.h
|
||||||
AIhelper.h
|
AIhelper.h
|
||||||
ResourceManager.h
|
ResourceManager.h
|
||||||
|
BuildingManager.h
|
||||||
|
MapObjectsEvaluator.h
|
||||||
|
BuildingManager.h
|
||||||
MapObjectsEvaluator.h
|
MapObjectsEvaluator.h
|
||||||
Fuzzy.h
|
Fuzzy.h
|
||||||
Goals.h
|
Goals.h
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "VCAI.h"
|
#include "VCAI.h"
|
||||||
#include "Fuzzy.h"
|
#include "Fuzzy.h"
|
||||||
#include "ResourceManager.h"
|
#include "ResourceManager.h"
|
||||||
|
#include "BuildingManager.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"
|
||||||
#include "../../lib/StringConstants.h"
|
#include "../../lib/StringConstants.h"
|
||||||
@ -1367,10 +1368,10 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//build dwelling
|
//build dwelling
|
||||||
auto bid = ai->canBuildAnyStructure(t, std::vector<BuildingID>(unitsSource, unitsSource + ARRAY_COUNT(unitsSource)), 8 - cb->getDate(Date::DAY_OF_WEEK));
|
auto bid = ah->canBuildAnyStructure(t, std::vector<BuildingID>(unitsSource, unitsSource + ARRAY_COUNT(unitsSource)), 8 - cb->getDate(Date::DAY_OF_WEEK));
|
||||||
if (bid != BuildingID::NONE)
|
if (bid.is_initialized())
|
||||||
{
|
{
|
||||||
auto goal = sptr(BuildThis(bid, t).setpriority(priority));
|
auto goal = sptr(BuildThis(bid.get(), t).setpriority(priority));
|
||||||
if (!ah->containsObjective(goal)) //avoid loops caused by reserving same objective twice
|
if (!ah->containsObjective(goal)) //avoid loops caused by reserving same objective twice
|
||||||
ret.push_back(goal);
|
ret.push_back(goal);
|
||||||
}
|
}
|
||||||
|
278
AI/VCAI/VCAI.cpp
278
AI/VCAI/VCAI.cpp
@ -11,6 +11,7 @@
|
|||||||
#include "VCAI.h"
|
#include "VCAI.h"
|
||||||
#include "Fuzzy.h"
|
#include "Fuzzy.h"
|
||||||
#include "ResourceManager.h"
|
#include "ResourceManager.h"
|
||||||
|
#include "BuildingManager.h"
|
||||||
|
|
||||||
#include "../../lib/UnlockGuard.h"
|
#include "../../lib/UnlockGuard.h"
|
||||||
#include "../../lib/mapObjects/MapObjects.h"
|
#include "../../lib/mapObjects/MapObjects.h"
|
||||||
@ -1181,241 +1182,35 @@ void VCAI::recruitCreatures(const CGDwelling * d, const CArmedInstance * recruit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VCAI::tryBuildThisStructure(const CGTownInstance * t, BuildingID building, unsigned int maxDays)
|
|
||||||
{
|
|
||||||
if(maxDays == 0)
|
|
||||||
{
|
|
||||||
logAi->warn("Request to build building %d in 0 days!", building.toEnum());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!vstd::contains(t->town->buildings, building))
|
|
||||||
return false; // no such building in town
|
|
||||||
|
|
||||||
if(t->hasBuilt(building)) //Already built? Shouldn't happen in general
|
|
||||||
return true;
|
|
||||||
|
|
||||||
const CBuilding * buildPtr = t->town->buildings.at(building);
|
|
||||||
|
|
||||||
auto toBuild = buildPtr->requirements.getFulfillmentCandidates([&](const BuildingID & buildID)
|
|
||||||
{
|
|
||||||
return t->hasBuilt(buildID);
|
|
||||||
});
|
|
||||||
toBuild.push_back(building);
|
|
||||||
|
|
||||||
for(BuildingID buildID : toBuild)
|
|
||||||
{
|
|
||||||
EBuildingState::EBuildingState canBuild = cb->canBuildStructure(t, buildID);
|
|
||||||
if(canBuild == EBuildingState::HAVE_CAPITAL || canBuild == EBuildingState::FORBIDDEN || canBuild == EBuildingState::NO_WATER)
|
|
||||||
return false; //we won't be able to build this
|
|
||||||
}
|
|
||||||
|
|
||||||
if(maxDays && toBuild.size() > maxDays)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
//TODO: calculate if we have enough resources to build it in maxDays?
|
|
||||||
|
|
||||||
for(const auto & buildID : toBuild)
|
|
||||||
{
|
|
||||||
const CBuilding * b = t->town->buildings.at(buildID);
|
|
||||||
|
|
||||||
EBuildingState::EBuildingState canBuild = cb->canBuildStructure(t, buildID);
|
|
||||||
if (canBuild == EBuildingState::ALLOWED)
|
|
||||||
{
|
|
||||||
buildStructure(t, buildID);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (canBuild == EBuildingState::PREREQUIRES)
|
|
||||||
{
|
|
||||||
// can happen when dependencies have their own missing dependencies
|
|
||||||
if (tryBuildThisStructure(t, buildID, maxDays - 1))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (canBuild == EBuildingState::MISSING_BASE)
|
|
||||||
{
|
|
||||||
if (tryBuildThisStructure(t, b->upgrade, maxDays - 1))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (canBuild == EBuildingState::NO_RESOURCES)
|
|
||||||
{
|
|
||||||
//we may need to gather resources for those
|
|
||||||
PotentialBuilding pb;
|
|
||||||
pb.bid = buildID;
|
|
||||||
pb.price = t->getBuildingCost(buildID);
|
|
||||||
potentialBuildings.push_back(pb); //these are checked again in try
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VCAI::tryBuildAnyStructure(const CGTownInstance * t, std::vector<BuildingID> buildList, unsigned int maxDays)
|
|
||||||
{
|
|
||||||
for(const auto & building : buildList)
|
|
||||||
{
|
|
||||||
if(t->hasBuilt(building))
|
|
||||||
continue;
|
|
||||||
return tryBuildThisStructure(t, building, maxDays);
|
|
||||||
|
|
||||||
}
|
|
||||||
return false; //Can't build anything
|
|
||||||
}
|
|
||||||
|
|
||||||
BuildingID VCAI::canBuildAnyStructure(const CGTownInstance * t, std::vector<BuildingID> buildList, unsigned int maxDays) const
|
|
||||||
{
|
|
||||||
for(const auto & building : buildList)
|
|
||||||
{
|
|
||||||
if(t->hasBuilt(building))
|
|
||||||
continue;
|
|
||||||
if(cb->canBuildStructure(t, building))
|
|
||||||
return building;
|
|
||||||
}
|
|
||||||
return BuildingID::NONE; //Can't build anything
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VCAI::tryBuildNextStructure(const CGTownInstance * t, std::vector<BuildingID> buildList, unsigned int maxDays)
|
|
||||||
{
|
|
||||||
for(const auto & building : buildList)
|
|
||||||
{
|
|
||||||
if(t->hasBuilt(building))
|
|
||||||
continue;
|
|
||||||
return tryBuildThisStructure(t, building, maxDays);
|
|
||||||
}
|
|
||||||
return false; //Nothing to build
|
|
||||||
}
|
|
||||||
|
|
||||||
void VCAI::buildStructure(const CGTownInstance * t, BuildingID building)
|
|
||||||
{
|
|
||||||
auto name = t->town->buildings.at(building)->Name();
|
|
||||||
logAi->debug("Player %d will build %s in town of %s at %s", playerID, name, t->name, t->pos.toString());
|
|
||||||
cb->buildBuilding(t, building); //just do this;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Set of buildings for different goals. Does not include any prerequisites.
|
|
||||||
static const BuildingID essential[] = {BuildingID::TAVERN, BuildingID::TOWN_HALL};
|
|
||||||
static const BuildingID goldSource[] = {BuildingID::TOWN_HALL, BuildingID::CITY_HALL, BuildingID::CAPITOL};
|
|
||||||
static const BuildingID capitolRequirements[] = { BuildingID::FORT, BuildingID::CITADEL };
|
|
||||||
static const BuildingID unitsSource[] = { BuildingID::DWELL_LVL_1, BuildingID::DWELL_LVL_2, BuildingID::DWELL_LVL_3,
|
|
||||||
BuildingID::DWELL_LVL_4, BuildingID::DWELL_LVL_5, BuildingID::DWELL_LVL_6, BuildingID::DWELL_LVL_7};
|
|
||||||
static const BuildingID unitsUpgrade[] = { BuildingID::DWELL_LVL_1_UP, BuildingID::DWELL_LVL_2_UP, BuildingID::DWELL_LVL_3_UP,
|
|
||||||
BuildingID::DWELL_LVL_4_UP, BuildingID::DWELL_LVL_5_UP, BuildingID::DWELL_LVL_6_UP, BuildingID::DWELL_LVL_7_UP};
|
|
||||||
static const BuildingID unitGrowth[] = { BuildingID::FORT, BuildingID::CITADEL, BuildingID::CASTLE, BuildingID::HORDE_1,
|
|
||||||
BuildingID::HORDE_1_UPGR, BuildingID::HORDE_2, BuildingID::HORDE_2_UPGR};
|
|
||||||
static const BuildingID _spells[] = {BuildingID::MAGES_GUILD_1, BuildingID::MAGES_GUILD_2, BuildingID::MAGES_GUILD_3,
|
|
||||||
BuildingID::MAGES_GUILD_4, BuildingID::MAGES_GUILD_5};
|
|
||||||
static const BuildingID extra[] = {BuildingID::RESOURCE_SILO, BuildingID::SPECIAL_1, BuildingID::SPECIAL_2, BuildingID::SPECIAL_3,
|
|
||||||
BuildingID::SPECIAL_4, BuildingID::SHIPYARD}; // all remaining buildings
|
|
||||||
|
|
||||||
bool VCAI::tryBuildStructure(const CGTownInstance * t)
|
|
||||||
{
|
|
||||||
//TODO make *real* town development system
|
|
||||||
//TODO: faction-specific development: use special buildings, build dwellings in better order, etc
|
|
||||||
//TODO: build resource silo, defences when needed
|
|
||||||
//Possible - allow "locking" on specific building (build prerequisites and then building itself)
|
|
||||||
|
|
||||||
//below algorithm focuses on economy growth at start of the game.
|
|
||||||
TResources currentRes = cb->getResourceAmount();
|
|
||||||
TResources currentIncome = t->dailyIncome();
|
|
||||||
|
|
||||||
if(tryBuildAnyStructure(t, std::vector<BuildingID>(essential, essential + ARRAY_COUNT(essential))))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
//the more gold the better and less problems later
|
|
||||||
if(tryBuildNextStructure(t, std::vector<BuildingID>(goldSource, goldSource + ARRAY_COUNT(goldSource))))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
//workaround for mantis #2696 - build fort and citadel - building castle will be handled without bug
|
|
||||||
if(vstd::contains(t->builtBuildings, BuildingID::CITY_HALL) &&
|
|
||||||
cb->canBuildStructure(t, BuildingID::CAPITOL) != EBuildingState::HAVE_CAPITAL)
|
|
||||||
{
|
|
||||||
if(cb->canBuildStructure(t, BuildingID::CAPITOL) != EBuildingState::FORBIDDEN)
|
|
||||||
{
|
|
||||||
if(tryBuildNextStructure(t, std::vector<BuildingID>(capitolRequirements,
|
|
||||||
capitolRequirements + ARRAY_COUNT(capitolRequirements))))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: save money for capitol or city hall if capitol unavailable
|
|
||||||
//do not build other things (unless gold source buildings are disabled in map editor)
|
|
||||||
|
|
||||||
|
|
||||||
if(cb->getDate(Date::DAY_OF_WEEK) > 6) // last 2 days of week - try to focus on growth
|
|
||||||
{
|
|
||||||
if(tryBuildNextStructure(t, std::vector<BuildingID>(unitGrowth, unitGrowth + ARRAY_COUNT(unitGrowth)), 2))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// first in-game week or second half of any week: try build dwellings
|
|
||||||
if(cb->getDate(Date::DAY) < 7 || cb->getDate(Date::DAY_OF_WEEK) > 3)
|
|
||||||
{
|
|
||||||
if(tryBuildAnyStructure(t, std::vector<BuildingID>(unitsSource,
|
|
||||||
unitsSource + ARRAY_COUNT(unitsSource)), 8 - cb->getDate(Date::DAY_OF_WEEK)))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//try to upgrade dwelling
|
|
||||||
for(int i = 0; i < ARRAY_COUNT(unitsUpgrade); i++)
|
|
||||||
{
|
|
||||||
if(t->hasBuilt(unitsSource[i]) && !t->hasBuilt(unitsUpgrade[i]))
|
|
||||||
{
|
|
||||||
if(tryBuildThisStructure(t, unitsUpgrade[i]))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//remaining tasks
|
|
||||||
if(tryBuildNextStructure(t, std::vector<BuildingID>(_spells, _spells + ARRAY_COUNT(_spells))))
|
|
||||||
return true;
|
|
||||||
if(tryBuildAnyStructure(t, std::vector<BuildingID>(extra, extra + ARRAY_COUNT(extra))))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
//at the end, try to get and build any extra buildings with nonstandard slots (for example HotA 3rd level dwelling)
|
|
||||||
std::vector<BuildingID> extraBuildings;
|
|
||||||
for(auto buildingInfo : t->town->buildings)
|
|
||||||
{
|
|
||||||
if(buildingInfo.first > 43)
|
|
||||||
extraBuildings.push_back(buildingInfo.first);
|
|
||||||
}
|
|
||||||
if(tryBuildAnyStructure(t, extraBuildings))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VCAI::isGoodForVisit(const CGObjectInstance * obj, HeroPtr h, SectorMap & sm)
|
bool VCAI::isGoodForVisit(const CGObjectInstance * obj, HeroPtr h, SectorMap & sm)
|
||||||
{
|
{
|
||||||
const int3 pos = obj->visitablePos();
|
const int3 pos = obj->visitablePos();
|
||||||
const int3 targetPos = sm.firstTileToGet(h, pos);
|
const int3 targetPos = sm.firstTileToGet(h, pos);
|
||||||
if(!targetPos.valid())
|
if (!targetPos.valid())
|
||||||
return false;
|
return false;
|
||||||
if(!isTileNotReserved(h.get(), targetPos))
|
if (!isTileNotReserved(h.get(), targetPos))
|
||||||
return false;
|
return false;
|
||||||
if(obj->wasVisited(playerID))
|
if (obj->wasVisited(playerID))
|
||||||
return false;
|
return false;
|
||||||
if(cb->getPlayerRelations(ai->playerID, obj->tempOwner) != PlayerRelations::ENEMIES && !isWeeklyRevisitable(obj))
|
if (cb->getPlayerRelations(ai->playerID, obj->tempOwner) != PlayerRelations::ENEMIES && !isWeeklyRevisitable(obj))
|
||||||
return false; // Otherwise we flag or get weekly resources / creatures
|
return false; // Otherwise we flag or get weekly resources / creatures
|
||||||
if(!isSafeToVisit(h, pos))
|
if (!isSafeToVisit(h, pos))
|
||||||
return false;
|
return false;
|
||||||
if(!shouldVisit(h, obj))
|
if (!shouldVisit(h, obj))
|
||||||
return false;
|
return false;
|
||||||
if(vstd::contains(alreadyVisited, obj))
|
if (vstd::contains(alreadyVisited, obj))
|
||||||
return false;
|
return false;
|
||||||
if(vstd::contains(reservedObjs, obj))
|
if (vstd::contains(reservedObjs, obj))
|
||||||
return false;
|
return false;
|
||||||
if(!isAccessibleForHero(targetPos, h))
|
if (!isAccessibleForHero(targetPos, h))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const CGObjectInstance * topObj = cb->getVisitableObjs(obj->visitablePos()).back(); //it may be hero visiting this obj
|
const CGObjectInstance * topObj = cb->getVisitableObjs(obj->visitablePos()).back(); //it may be hero visiting this obj
|
||||||
//we don't try visiting object on which allied or owned hero stands
|
//we don't try visiting object on which allied or owned hero stands
|
||||||
// -> it will just trigger exchange windows and AI will be confused that obj behind doesn't get visited
|
// -> it will just trigger exchange windows and AI will be confused that obj behind doesn't get visited
|
||||||
if(topObj->ID == Obj::HERO && cb->getPlayerRelations(h->tempOwner, topObj->tempOwner) != PlayerRelations::ENEMIES)
|
if (topObj->ID == Obj::HERO && cb->getPlayerRelations(h->tempOwner, topObj->tempOwner) != PlayerRelations::ENEMIES)
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
return true; //all of the following is met
|
return true; //all of the following is met
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VCAI::isTileNotReserved(const CGHeroInstance * h, int3 t)
|
bool VCAI::isTileNotReserved(const CGHeroInstance * h, int3 t)
|
||||||
@ -2084,6 +1879,14 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
|
|||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VCAI::buildStructure(const CGTownInstance * t, BuildingID building)
|
||||||
|
{
|
||||||
|
auto name = t->town->buildings.at(building)->Name();
|
||||||
|
logAi->debug("Player %d will build %s in town of %s at %s", ai->playerID, name, t->name, t->pos.toString());
|
||||||
|
cb->buildBuilding(t, building); //just do this;
|
||||||
|
}
|
||||||
|
|
||||||
void VCAI::tryRealize(Goals::Explore & g)
|
void VCAI::tryRealize(Goals::Explore & g)
|
||||||
{
|
{
|
||||||
throw cannotFulfillGoalException("EXPLORE is not an elementar goal!");
|
throw cannotFulfillGoalException("EXPLORE is not an elementar goal!");
|
||||||
@ -2216,23 +2019,32 @@ void VCAI::tryRealize(Goals::Build & g)
|
|||||||
for(const CGTownInstance * t : cb->getTownsInfo())
|
for(const CGTownInstance * t : cb->getTownsInfo())
|
||||||
{
|
{
|
||||||
logAi->debug("Looking into %s", t->name);
|
logAi->debug("Looking into %s", t->name);
|
||||||
potentialBuildings.clear(); //start fresh with every town
|
//start fresh with every town
|
||||||
if (tryBuildStructure(t))
|
ah->getBuildingOptions(t);
|
||||||
didWeBuildSomething = true;
|
auto ib = ah->immediateBuilding();
|
||||||
else if (potentialBuildings.size())
|
if (ib.is_initialized())
|
||||||
{
|
{
|
||||||
auto pb = potentialBuildings.front(); //gather resources for any we can't afford
|
buildStructure(t, ib.get().bid); //do it right now
|
||||||
auto goal = ah->whatToDo(pb.price, sptr(Goals::BuildThis(pb.bid, t)));
|
didWeBuildSomething = true;
|
||||||
if (goal->goalType == Goals::BUILD_STRUCTURE)
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto eb = ah->expensiveBuilding();
|
||||||
|
if (eb.is_initialized())
|
||||||
{
|
{
|
||||||
logAi->error("We were supposed to NOT afford any building");
|
auto pb = eb.get(); //gather resources for any we can't afford
|
||||||
buildStructure(t, pb.bid); //do it right now
|
auto goal = ah->whatToDo(pb.price, sptr(Goals::BuildThis(pb.bid, t)));
|
||||||
didWeBuildSomething = true;
|
if (goal->goalType == Goals::BUILD_STRUCTURE)
|
||||||
}
|
{
|
||||||
else
|
logAi->error("We were supposed to NOT afford any building");
|
||||||
{
|
buildStructure(t, pb.bid); //do it right now
|
||||||
//TODO: right now we do that for every town in order. Consider comparison of all potential goals.
|
didWeBuildSomething = true;
|
||||||
striveToGoal(goal); //gather resources, or something else?
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//TODO: right now we do that for every town in order. Consider comparison of all potential goals.
|
||||||
|
striveToGoal(goal); //gather resources, or something else?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,30 +129,10 @@ struct SectorMap
|
|||||||
class DLL_EXPORT VCAI : public CAdventureAI
|
class DLL_EXPORT VCAI : public CAdventureAI
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//internal methods for town development
|
|
||||||
//TODO: refactor to separate class BuildManager
|
|
||||||
|
|
||||||
//try build anything in given town, and execute resulting Goal if any
|
|
||||||
bool tryBuildStructure(const CGTownInstance * t);
|
|
||||||
bool tryBuildAnyStructure(const CGTownInstance * t, std::vector<BuildingID> buildList, unsigned int maxDays = 7);
|
|
||||||
//try build first unbuilt structure
|
|
||||||
|
|
||||||
bool tryBuildThisStructure(const CGTownInstance * t, BuildingID building, unsigned int maxDays = 7);
|
|
||||||
//try build ANY unbuilt structure
|
|
||||||
BuildingID canBuildAnyStructure(const CGTownInstance * t, std::vector<BuildingID> buildList, unsigned int maxDays = 7) const;
|
|
||||||
bool tryBuildNextStructure(const CGTownInstance * t, std::vector<BuildingID> buildList, unsigned int maxDays = 7);
|
|
||||||
void buildStructure(const CGTownInstance * t, BuildingID building); //actually execute build operation
|
|
||||||
|
|
||||||
struct PotentialBuilding
|
|
||||||
{
|
|
||||||
BuildingID bid;
|
|
||||||
TResources price;
|
|
||||||
//days to build?
|
|
||||||
};
|
|
||||||
std::vector<PotentialBuilding> potentialBuildings; //what we can build in current town
|
|
||||||
|
|
||||||
friend class FuzzyHelper;
|
friend class FuzzyHelper;
|
||||||
friend class ResourceManager;
|
friend class ResourceManager;
|
||||||
|
friend class BuildingManager;
|
||||||
|
|
||||||
std::map<TeleportChannelID, std::shared_ptr<TeleportChannel>> knownTeleportChannels;
|
std::map<TeleportChannelID, std::shared_ptr<TeleportChannel>> knownTeleportChannels;
|
||||||
std::map<const CGObjectInstance *, const CGObjectInstance *> knownSubterraneanGates;
|
std::map<const CGObjectInstance *, const CGObjectInstance *> knownSubterraneanGates;
|
||||||
@ -289,6 +269,7 @@ public:
|
|||||||
void performObjectInteraction(const CGObjectInstance * obj, HeroPtr h);
|
void performObjectInteraction(const CGObjectInstance * obj, HeroPtr h);
|
||||||
|
|
||||||
bool moveHeroToTile(int3 dst, HeroPtr h);
|
bool moveHeroToTile(int3 dst, HeroPtr h);
|
||||||
|
void buildStructure(const CGTownInstance * t, BuildingID building); //TODO: move to BuildingManager
|
||||||
|
|
||||||
void lostHero(HeroPtr h); //should remove all references to hero (assigned tasks and so on)
|
void lostHero(HeroPtr h); //should remove all references to hero (assigned tasks and so on)
|
||||||
void waitTillFree();
|
void waitTillFree();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user