mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-13 19:54:17 +02:00
Nullkiller: Try to join behavior and goal and see what come out of it.
This commit is contained in:
committed by
Andrii Danylchenko
parent
af0dcf97c4
commit
223a52b3d1
@@ -10,10 +10,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../VCAI.h"
|
#include "../VCAI.h"
|
||||||
|
#error REMOVE THIS FILE
|
||||||
|
|
||||||
class Behavior
|
class Behavior : public Goals::AbstractGoal
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual Goals::TGoalVec getTasks() = 0;
|
|
||||||
virtual std::string toString() const = 0;
|
virtual std::string toString() const = 0;
|
||||||
};
|
};
|
||||||
|
@@ -29,7 +29,7 @@ std::string BuildingBehavior::toString() const
|
|||||||
return "Build";
|
return "Build";
|
||||||
}
|
}
|
||||||
|
|
||||||
Goals::TGoalVec BuildingBehavior::getTasks()
|
Goals::TGoalVec BuildingBehavior::decompose() const
|
||||||
{
|
{
|
||||||
Goals::TGoalVec tasks;
|
Goals::TGoalVec tasks;
|
||||||
|
|
||||||
|
@@ -10,17 +10,24 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "lib/VCMI_Lib.h"
|
#include "lib/VCMI_Lib.h"
|
||||||
#include "Behavior.h"
|
|
||||||
#include "../AIUtility.h"
|
#include "../AIUtility.h"
|
||||||
|
#include "../Goals/CGoal.h"
|
||||||
|
|
||||||
class BuildingBehavior : public Behavior
|
namespace Goals
|
||||||
|
{
|
||||||
|
class BuildingBehavior : public CGoal<BuildingBehavior>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BuildingBehavior()
|
BuildingBehavior()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Goals::TGoalVec getTasks() override;
|
virtual Goals::TGoalVec decompose() const override;
|
||||||
virtual std::string toString() const override;
|
virtual std::string toString() const override;
|
||||||
|
virtual bool operator==(const BuildingBehavior & other) const override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -29,7 +29,7 @@ std::string BuyArmyBehavior::toString() const
|
|||||||
return "Buy army";
|
return "Buy army";
|
||||||
}
|
}
|
||||||
|
|
||||||
Goals::TGoalVec BuyArmyBehavior::getTasks()
|
Goals::TGoalVec BuyArmyBehavior::decompose() const
|
||||||
{
|
{
|
||||||
Goals::TGoalVec tasks;
|
Goals::TGoalVec tasks;
|
||||||
|
|
||||||
|
@@ -10,17 +10,23 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "lib/VCMI_Lib.h"
|
#include "lib/VCMI_Lib.h"
|
||||||
#include "Behavior.h"
|
|
||||||
#include "../AIUtility.h"
|
#include "../AIUtility.h"
|
||||||
|
#include "../Goals/CGoal.h"
|
||||||
|
|
||||||
class BuyArmyBehavior : public Behavior
|
namespace Goals
|
||||||
|
{
|
||||||
|
class BuyArmyBehavior : public CGoal<BuyArmyBehavior>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BuyArmyBehavior()
|
BuyArmyBehavior()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Goals::TGoalVec getTasks() override;
|
virtual Goals::TGoalVec decompose() const override;
|
||||||
virtual std::string toString() const override;
|
virtual std::string toString() const override;
|
||||||
|
virtual bool operator==(const BuyArmyBehavior & other) const override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
@@ -28,7 +28,7 @@ std::string CaptureObjectsBehavior::toString() const
|
|||||||
return "Capture objects";
|
return "Capture objects";
|
||||||
}
|
}
|
||||||
|
|
||||||
Goals::TGoalVec CaptureObjectsBehavior::getTasks()
|
Goals::TGoalVec CaptureObjectsBehavior::decompose() const
|
||||||
{
|
{
|
||||||
Goals::TGoalVec tasks;
|
Goals::TGoalVec tasks;
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ Goals::TGoalVec CaptureObjectsBehavior::getTasks()
|
|||||||
|
|
||||||
for(auto objToVisit : objs)
|
for(auto objToVisit : objs)
|
||||||
{
|
{
|
||||||
#ifdef 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
|
||||||
|
|
||||||
@@ -55,19 +55,19 @@ Goals::TGoalVec CaptureObjectsBehavior::getTasks()
|
|||||||
std::vector<std::shared_ptr<ExecuteHeroChain>> waysToVisitObj;
|
std::vector<std::shared_ptr<ExecuteHeroChain>> waysToVisitObj;
|
||||||
std::shared_ptr<ExecuteHeroChain> closestWay;
|
std::shared_ptr<ExecuteHeroChain> closestWay;
|
||||||
|
|
||||||
#ifdef AI_TRACE_LEVEL >= 1
|
#if AI_TRACE_LEVEL >= 1
|
||||||
logAi->trace("Found %d paths", paths.size());
|
logAi->trace("Found %d paths", paths.size());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for(auto & path : paths)
|
for(auto & path : paths)
|
||||||
{
|
{
|
||||||
#ifdef AI_TRACE_LEVEL >= 2
|
#if AI_TRACE_LEVEL >= 2
|
||||||
logAi->trace("Path found %s", path.toString());
|
logAi->trace("Path found %s", path.toString());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(path.getFirstBlockedAction())
|
if(path.getFirstBlockedAction())
|
||||||
{
|
{
|
||||||
#ifdef AI_TRACE_LEVEL >= 2
|
#if AI_TRACE_LEVEL >= 2
|
||||||
// TODO: decomposition?
|
// TODO: decomposition?
|
||||||
logAi->trace("Ignore path. Action is blocked.");
|
logAi->trace("Ignore path. Action is blocked.");
|
||||||
#endif
|
#endif
|
||||||
@@ -76,7 +76,7 @@ Goals::TGoalVec CaptureObjectsBehavior::getTasks()
|
|||||||
|
|
||||||
if(ai->nullkiller->dangerHitMap->enemyCanKillOurHeroesAlongThePath(path))
|
if(ai->nullkiller->dangerHitMap->enemyCanKillOurHeroesAlongThePath(path))
|
||||||
{
|
{
|
||||||
#ifdef AI_TRACE_LEVEL >= 2
|
#if AI_TRACE_LEVEL >= 2
|
||||||
logAi->trace("Ignore path. Target hero can be killed by enemy. Our power %lld", path.heroArmy->getArmyStrength());
|
logAi->trace("Ignore path. Target hero can be killed by enemy. Our power %lld", path.heroArmy->getArmyStrength());
|
||||||
#endif
|
#endif
|
||||||
continue;
|
continue;
|
||||||
@@ -98,7 +98,7 @@ Goals::TGoalVec CaptureObjectsBehavior::getTasks()
|
|||||||
|
|
||||||
auto isSafe = isSafeToVisit(hero, path.heroArmy, danger);
|
auto isSafe = isSafeToVisit(hero, path.heroArmy, danger);
|
||||||
|
|
||||||
#ifdef AI_TRACE_LEVEL >= 2
|
#if AI_TRACE_LEVEL >= 2
|
||||||
logAi->trace(
|
logAi->trace(
|
||||||
"It is %s to visit %s by %s with army %lld, danger %lld and army loss %lld",
|
"It is %s to visit %s by %s with army %lld, danger %lld and army loss %lld",
|
||||||
isSafe ? "safe" : "not safe",
|
isSafe ? "safe" : "not safe",
|
||||||
|
@@ -10,10 +10,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "lib/VCMI_Lib.h"
|
#include "lib/VCMI_Lib.h"
|
||||||
#include "Behavior.h"
|
|
||||||
#include "../AIUtility.h"
|
#include "../AIUtility.h"
|
||||||
|
#include "../Goals/CGoal.h"
|
||||||
|
|
||||||
class CaptureObjectsBehavior : public Behavior {
|
namespace Goals
|
||||||
|
{
|
||||||
|
class CaptureObjectsBehavior : public CGoal<CaptureObjectsBehavior>
|
||||||
|
{
|
||||||
private:
|
private:
|
||||||
std::vector<int> objectTypes;
|
std::vector<int> objectTypes;
|
||||||
std::vector<int> objectSubTypes;
|
std::vector<int> objectSubTypes;
|
||||||
@@ -39,22 +42,30 @@ public:
|
|||||||
specificObjects = true;
|
specificObjects = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Goals::TGoalVec getTasks() override;
|
virtual Goals::TGoalVec decompose() const override;
|
||||||
virtual std::string toString() const override;
|
virtual std::string toString() const override;
|
||||||
|
|
||||||
CaptureObjectsBehavior & ofType(int type) {
|
CaptureObjectsBehavior & ofType(int type)
|
||||||
|
{
|
||||||
objectTypes.push_back(type);
|
objectTypes.push_back(type);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
CaptureObjectsBehavior & ofType(int type, int subType) {
|
CaptureObjectsBehavior & ofType(int type, int subType)
|
||||||
|
{
|
||||||
objectTypes.push_back(type);
|
objectTypes.push_back(type);
|
||||||
objectSubTypes.push_back(subType);
|
objectSubTypes.push_back(subType);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool operator==(const CaptureObjectsBehavior & other) const override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool shouldVisitObject(ObjectIdRef obj) const;
|
bool shouldVisitObject(ObjectIdRef obj) const;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
237
AI/Nullkiller/Behaviors/CompleteQuestBehavior.cpp
Normal file
237
AI/Nullkiller/Behaviors/CompleteQuestBehavior.cpp
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
/*
|
||||||
|
* CompleteQuestBehavior.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 "CompleteQuestBehavior.h"
|
||||||
|
#include "CaptureObjectsBehavior.h"
|
||||||
|
#include "../VCAI.h"
|
||||||
|
#include "../AIhelper.h"
|
||||||
|
#include "../../../lib/mapping/CMap.h" //for victory conditions
|
||||||
|
#include "../../../lib/CPathfinder.h"
|
||||||
|
|
||||||
|
extern boost::thread_specific_ptr<CCallback> cb;
|
||||||
|
extern boost::thread_specific_ptr<VCAI> ai;
|
||||||
|
extern FuzzyHelper * fh;
|
||||||
|
|
||||||
|
using namespace Goals;
|
||||||
|
|
||||||
|
std::string CompleteQuestBehavior::toString() const
|
||||||
|
{
|
||||||
|
return "Complete Quests";
|
||||||
|
}
|
||||||
|
|
||||||
|
TGoalVec CompleteQuestBehavior::decompose() const
|
||||||
|
{
|
||||||
|
TGoalVec solutions;
|
||||||
|
|
||||||
|
auto quests = cb->getMyQuests();
|
||||||
|
|
||||||
|
for(auto & q : quests)
|
||||||
|
{
|
||||||
|
if(q.quest->missionType == CQuest::MISSION_NONE || q.quest->progress == CQuest::COMPLETE)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
vstd::concatenate(solutions, getQuestTasks(q));
|
||||||
|
}
|
||||||
|
|
||||||
|
return solutions;
|
||||||
|
}
|
||||||
|
|
||||||
|
TGoalVec CompleteQuestBehavior::getQuestTasks(const QuestInfo & q) const
|
||||||
|
{
|
||||||
|
logAi->debug("Trying to realize quest: %s", questToString(q));
|
||||||
|
|
||||||
|
switch(q.quest->missionType)
|
||||||
|
{
|
||||||
|
case CQuest::MISSION_ART:
|
||||||
|
return missionArt(q);
|
||||||
|
|
||||||
|
case CQuest::MISSION_HERO:
|
||||||
|
return missionHero(q);
|
||||||
|
|
||||||
|
case CQuest::MISSION_ARMY:
|
||||||
|
return missionArmy(q);
|
||||||
|
|
||||||
|
case CQuest::MISSION_RESOURCES:
|
||||||
|
return missionResources(q);
|
||||||
|
|
||||||
|
case CQuest::MISSION_KILL_HERO:
|
||||||
|
case CQuest::MISSION_KILL_CREATURE:
|
||||||
|
return missionDestroyObj(q);
|
||||||
|
|
||||||
|
case CQuest::MISSION_PRIMARY_STAT:
|
||||||
|
return missionIncreasePrimaryStat(q);
|
||||||
|
|
||||||
|
case CQuest::MISSION_LEVEL:
|
||||||
|
return missionLevel(q);
|
||||||
|
|
||||||
|
case CQuest::MISSION_PLAYER:
|
||||||
|
if(ai->playerID.getNum() != q.quest->m13489val)
|
||||||
|
logAi->debug("Can't be player of color %d", q.quest->m13489val);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CQuest::MISSION_KEYMASTER:
|
||||||
|
return missionKeymaster(q);
|
||||||
|
|
||||||
|
} //end of switch
|
||||||
|
|
||||||
|
return TGoalVec();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CompleteQuestBehavior::questToString(const QuestInfo & q) const
|
||||||
|
{
|
||||||
|
if(q.quest->missionType == CQuest::MISSION_NONE)
|
||||||
|
return "inactive quest";
|
||||||
|
|
||||||
|
MetaString ms;
|
||||||
|
q.quest->getRolloverText(ms, false);
|
||||||
|
|
||||||
|
return ms.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
TGoalVec CompleteQuestBehavior::tryCompleteQuest(const QuestInfo & q) const
|
||||||
|
{
|
||||||
|
TGoalVec solutions;
|
||||||
|
|
||||||
|
auto tasks = CaptureObjectsBehavior(q.obj).decompose(); //TODO: choose best / free hero from among many possibilities?
|
||||||
|
|
||||||
|
for(auto task : tasks)
|
||||||
|
{
|
||||||
|
if(task->hero && q.quest->checkQuest(task->hero.get()))
|
||||||
|
{
|
||||||
|
solutions.push_back(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return solutions;
|
||||||
|
}
|
||||||
|
|
||||||
|
TGoalVec CompleteQuestBehavior::missionArt(const QuestInfo & q) const
|
||||||
|
{
|
||||||
|
TGoalVec solutions = tryCompleteQuest(q);
|
||||||
|
|
||||||
|
if(!solutions.empty())
|
||||||
|
return solutions;
|
||||||
|
|
||||||
|
/*for(auto art : q.quest->m5arts)
|
||||||
|
{
|
||||||
|
solutions.push_back(sptr(GetArtOfType(art))); //TODO: transport?
|
||||||
|
}*/
|
||||||
|
|
||||||
|
return solutions;
|
||||||
|
}
|
||||||
|
|
||||||
|
TGoalVec CompleteQuestBehavior::missionHero(const QuestInfo & q) const
|
||||||
|
{
|
||||||
|
TGoalVec solutions = tryCompleteQuest(q);
|
||||||
|
|
||||||
|
if(solutions.empty())
|
||||||
|
{
|
||||||
|
//rule of a thumb - quest heroes usually are locked in prisons
|
||||||
|
return CaptureObjectsBehavior().ofType(Obj::PRISON).decompose();
|
||||||
|
}
|
||||||
|
|
||||||
|
return solutions;
|
||||||
|
}
|
||||||
|
|
||||||
|
TGoalVec CompleteQuestBehavior::missionArmy(const QuestInfo & q) const
|
||||||
|
{
|
||||||
|
TGoalVec solutions = tryCompleteQuest(q);
|
||||||
|
|
||||||
|
if(!solutions.empty())
|
||||||
|
return solutions;
|
||||||
|
/*
|
||||||
|
for(auto creature : q.quest->m6creatures)
|
||||||
|
{
|
||||||
|
solutions.push_back(sptr(GatherTroops(creature.type->idNumber, creature.count)));
|
||||||
|
}*/
|
||||||
|
|
||||||
|
return solutions;
|
||||||
|
}
|
||||||
|
|
||||||
|
TGoalVec CompleteQuestBehavior::missionIncreasePrimaryStat(const QuestInfo & q) const
|
||||||
|
{
|
||||||
|
return tryCompleteQuest(q);
|
||||||
|
}
|
||||||
|
|
||||||
|
TGoalVec CompleteQuestBehavior::missionLevel(const QuestInfo & q) const
|
||||||
|
{
|
||||||
|
return tryCompleteQuest(q);
|
||||||
|
}
|
||||||
|
|
||||||
|
TGoalVec CompleteQuestBehavior::missionKeymaster(const QuestInfo & q) const
|
||||||
|
{
|
||||||
|
TGoalVec solutions = tryCompleteQuest(q);
|
||||||
|
|
||||||
|
if(solutions.empty())
|
||||||
|
{
|
||||||
|
return CaptureObjectsBehavior().ofType(Obj::KEYMASTER, q.obj->subID).decompose();
|
||||||
|
}
|
||||||
|
|
||||||
|
return solutions;
|
||||||
|
}
|
||||||
|
|
||||||
|
TGoalVec CompleteQuestBehavior::missionResources(const QuestInfo & q) const
|
||||||
|
{
|
||||||
|
TGoalVec solutions;
|
||||||
|
|
||||||
|
/*auto heroes = cb->getHeroesInfo(); //TODO: choose best / free hero from among many possibilities?
|
||||||
|
|
||||||
|
if(heroes.size())
|
||||||
|
{
|
||||||
|
if(q.quest->checkQuest(heroes.front())) //it doesn't matter which hero it is
|
||||||
|
{
|
||||||
|
return solutions;// ai->ah->howToVisitObj(q.obj);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(int i = 0; i < q.quest->m7resources.size(); ++i)
|
||||||
|
{
|
||||||
|
if(q.quest->m7resources[i])
|
||||||
|
solutions.push_back(sptr(CollectRes(i, q.quest->m7resources[i])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
solutions.push_back(sptr(Goals::RecruitHero())); //FIXME: checkQuest requires any hero belonging to player :(
|
||||||
|
}*/
|
||||||
|
|
||||||
|
return solutions;
|
||||||
|
}
|
||||||
|
|
||||||
|
TGoalVec CompleteQuestBehavior::missionDestroyObj(const QuestInfo & q) const
|
||||||
|
{
|
||||||
|
auto obj = cb->getObjByQuestIdentifier(q.quest->m13489val);
|
||||||
|
|
||||||
|
if(!obj)
|
||||||
|
return CaptureObjectsBehavior(q.obj).decompose();
|
||||||
|
|
||||||
|
if(obj->ID == Obj::HERO)
|
||||||
|
{
|
||||||
|
auto relations = cb->getPlayerRelations(ai->playerID, obj->tempOwner);
|
||||||
|
|
||||||
|
//if(relations == PlayerRelations::SAME_PLAYER)
|
||||||
|
//{
|
||||||
|
// auto heroToProtect = cb->getHero(obj->id);
|
||||||
|
|
||||||
|
// //solutions.push_back(sptr(GatherArmy().sethero(heroToProtect)));
|
||||||
|
//}
|
||||||
|
//else
|
||||||
|
if(relations == PlayerRelations::ENEMIES)
|
||||||
|
{
|
||||||
|
return CaptureObjectsBehavior(obj).decompose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TGoalVec();
|
||||||
|
}
|
48
AI/Nullkiller/Behaviors/CompleteQuestBehavior.h
Normal file
48
AI/Nullkiller/Behaviors/CompleteQuestBehavior.h
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* CompleteQuestBehavior.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 "lib/VCMI_Lib.h"
|
||||||
|
#include "../AIUtility.h"
|
||||||
|
#include "../../../lib/VCMI_Lib.h"
|
||||||
|
#include "../../../CCallback.h"
|
||||||
|
#include "../Goals/CGoal.h"
|
||||||
|
|
||||||
|
namespace Goals
|
||||||
|
{
|
||||||
|
class CompleteQuestBehavior : public CGoal<CompleteQuestBehavior>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CompleteQuestBehavior()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Goals::TGoalVec decompose() const override;
|
||||||
|
virtual std::string toString() const override;
|
||||||
|
|
||||||
|
virtual bool operator==(const CompleteQuestBehavior & other) const override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TGoalVec getQuestTasks(const QuestInfo & q) const;
|
||||||
|
TGoalVec tryCompleteQuest(const QuestInfo & q) const;
|
||||||
|
TGoalVec missionArt(const QuestInfo & q) const;
|
||||||
|
TGoalVec missionHero(const QuestInfo & q) const;
|
||||||
|
TGoalVec missionArmy(const QuestInfo & q) const;
|
||||||
|
TGoalVec missionResources(const QuestInfo & q) const;
|
||||||
|
TGoalVec missionDestroyObj(const QuestInfo & q) const;
|
||||||
|
TGoalVec missionIncreasePrimaryStat(const QuestInfo & q) const;
|
||||||
|
TGoalVec missionLevel(const QuestInfo & q) const;
|
||||||
|
TGoalVec missionKeymaster(const QuestInfo & q) const;
|
||||||
|
std::string questToString(const QuestInfo & q) const;
|
||||||
|
};
|
||||||
|
}
|
@@ -14,7 +14,6 @@
|
|||||||
#include "../AIhelper.h"
|
#include "../AIhelper.h"
|
||||||
#include "../AIUtility.h"
|
#include "../AIUtility.h"
|
||||||
#include "../Goals/BuyArmy.h"
|
#include "../Goals/BuyArmy.h"
|
||||||
#include "../Goals/VisitTile.h"
|
|
||||||
#include "../Goals/ExecuteHeroChain.h"
|
#include "../Goals/ExecuteHeroChain.h"
|
||||||
#include "../Goals/DismissHero.h"
|
#include "../Goals/DismissHero.h"
|
||||||
#include "../Goals/ExchangeSwapTownHeroes.h"
|
#include "../Goals/ExchangeSwapTownHeroes.h"
|
||||||
@@ -32,7 +31,7 @@ std::string DefenceBehavior::toString() const
|
|||||||
return "Defend towns";
|
return "Defend towns";
|
||||||
}
|
}
|
||||||
|
|
||||||
Goals::TGoalVec DefenceBehavior::getTasks()
|
Goals::TGoalVec DefenceBehavior::decompose() const
|
||||||
{
|
{
|
||||||
Goals::TGoalVec tasks;
|
Goals::TGoalVec tasks;
|
||||||
|
|
||||||
@@ -65,7 +64,7 @@ uint64_t townArmyIncome(const CGTownInstance * town)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInstance * town)
|
void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInstance * town) const
|
||||||
{
|
{
|
||||||
auto basicPriority = 0.3f + std::sqrt(townArmyIncome(town) / 20000.0f)
|
auto basicPriority = 0.3f + std::sqrt(townArmyIncome(town) / 20000.0f)
|
||||||
+ town->dailyIncome()[Res::GOLD] / 10000.0f;
|
+ town->dailyIncome()[Res::GOLD] / 10000.0f;
|
||||||
@@ -163,7 +162,7 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
|
|||||||
if(cb->getHeroesInfo().size() < ALLOWED_ROAMING_HEROES)
|
if(cb->getHeroesInfo().size() < ALLOWED_ROAMING_HEROES)
|
||||||
{
|
{
|
||||||
logAi->debug("Hero %s can be recruited to defend %s", hero->name, town->name);
|
logAi->debug("Hero %s can be recruited to defend %s", hero->name, town->name);
|
||||||
tasks.push_back(Goals::sptr(Goals::RecruitHero().settown(town).setobjid(hero->id.getNum()).setpriority(1)));
|
tasks.push_back(Goals::sptr(Goals::RecruitHero(town, hero).setpriority(1)));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@@ -10,20 +10,28 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "lib/VCMI_Lib.h"
|
#include "lib/VCMI_Lib.h"
|
||||||
#include "Behavior.h"
|
#include "../Goals/CGoal.h"
|
||||||
#include "../AIUtility.h"
|
#include "../AIUtility.h"
|
||||||
|
|
||||||
class DefenceBehavior : public Behavior
|
namespace Goals
|
||||||
|
{
|
||||||
|
class DefenceBehavior : public CGoal<DefenceBehavior>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DefenceBehavior()
|
DefenceBehavior()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Goals::TGoalVec getTasks() override;
|
virtual Goals::TGoalVec decompose() const override;
|
||||||
virtual std::string toString() const override;
|
virtual std::string toString() const override;
|
||||||
|
|
||||||
private:
|
virtual bool operator==(const DefenceBehavior & other) const override
|
||||||
void evaluateDefence(Goals::TGoalVec & tasks, const CGTownInstance * town);
|
{
|
||||||
};
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void evaluateDefence(Goals::TGoalVec & tasks, const CGTownInstance * town) const;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -23,14 +23,12 @@ extern FuzzyHelper * fh;
|
|||||||
|
|
||||||
using namespace Goals;
|
using namespace Goals;
|
||||||
|
|
||||||
#define AI_TRACE_LEVEL 2
|
|
||||||
|
|
||||||
std::string GatherArmyBehavior::toString() const
|
std::string GatherArmyBehavior::toString() const
|
||||||
{
|
{
|
||||||
return "Gather army";
|
return "Gather army";
|
||||||
}
|
}
|
||||||
|
|
||||||
Goals::TGoalVec GatherArmyBehavior::getTasks()
|
Goals::TGoalVec GatherArmyBehavior::decompose() const
|
||||||
{
|
{
|
||||||
Goals::TGoalVec tasks;
|
Goals::TGoalVec tasks;
|
||||||
|
|
||||||
@@ -65,12 +63,12 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her
|
|||||||
Goals::TGoalVec tasks;
|
Goals::TGoalVec tasks;
|
||||||
const int3 pos = hero->visitablePos();
|
const int3 pos = hero->visitablePos();
|
||||||
|
|
||||||
#ifdef AI_TRACE_LEVEL >= 1
|
#if AI_TRACE_LEVEL >= 1
|
||||||
logAi->trace("Checking ways to gaher army for hero %s, %s", hero->getObjectName(), pos.toString());
|
logAi->trace("Checking ways to gaher army for hero %s, %s", hero->getObjectName(), pos.toString());
|
||||||
#endif
|
#endif
|
||||||
if(ai->nullkiller->isHeroLocked(hero))
|
if(ai->nullkiller->isHeroLocked(hero))
|
||||||
{
|
{
|
||||||
#ifdef AI_TRACE_LEVEL >= 1
|
#if AI_TRACE_LEVEL >= 1
|
||||||
logAi->trace("Skipping locked hero %s, %s", hero->getObjectName(), pos.toString());
|
logAi->trace("Skipping locked hero %s, %s", hero->getObjectName(), pos.toString());
|
||||||
#endif
|
#endif
|
||||||
return tasks;
|
return tasks;
|
||||||
@@ -79,13 +77,13 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her
|
|||||||
auto paths = ai->ah->getPathsToTile(pos);
|
auto paths = ai->ah->getPathsToTile(pos);
|
||||||
std::vector<std::shared_ptr<ExecuteHeroChain>> waysToVisitObj;
|
std::vector<std::shared_ptr<ExecuteHeroChain>> waysToVisitObj;
|
||||||
|
|
||||||
#ifdef AI_TRACE_LEVEL >= 1
|
#if AI_TRACE_LEVEL >= 1
|
||||||
logAi->trace("Found %d paths", paths.size());
|
logAi->trace("Found %d paths", paths.size());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for(const AIPath & path : paths)
|
for(const AIPath & path : paths)
|
||||||
{
|
{
|
||||||
#ifdef AI_TRACE_LEVEL >= 2
|
#if AI_TRACE_LEVEL >= 2
|
||||||
logAi->trace("Path found %s", path.toString());
|
logAi->trace("Path found %s", path.toString());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -93,7 +91,7 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her
|
|||||||
|
|
||||||
if(path.getFirstBlockedAction())
|
if(path.getFirstBlockedAction())
|
||||||
{
|
{
|
||||||
#ifdef AI_TRACE_LEVEL >= 2
|
#if AI_TRACE_LEVEL >= 2
|
||||||
// TODO: decomposition?
|
// TODO: decomposition?
|
||||||
logAi->trace("Ignore path. Action is blocked.");
|
logAi->trace("Ignore path. Action is blocked.");
|
||||||
#endif
|
#endif
|
||||||
@@ -102,7 +100,7 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her
|
|||||||
|
|
||||||
if(ai->nullkiller->dangerHitMap->enemyCanKillOurHeroesAlongThePath(path))
|
if(ai->nullkiller->dangerHitMap->enemyCanKillOurHeroesAlongThePath(path))
|
||||||
{
|
{
|
||||||
#ifdef AI_TRACE_LEVEL >= 2
|
#if AI_TRACE_LEVEL >= 2
|
||||||
logAi->trace("Ignore path. Target hero can be killed by enemy. Our power %lld", path.heroArmy->getArmyStrength());
|
logAi->trace("Ignore path. Target hero can be killed by enemy. Our power %lld", path.heroArmy->getArmyStrength());
|
||||||
#endif
|
#endif
|
||||||
continue;
|
continue;
|
||||||
@@ -122,7 +120,7 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her
|
|||||||
|
|
||||||
auto isSafe = isSafeToVisit(hero, path.heroArmy, danger);
|
auto isSafe = isSafeToVisit(hero, path.heroArmy, danger);
|
||||||
|
|
||||||
#ifdef AI_TRACE_LEVEL >= 2
|
#if AI_TRACE_LEVEL >= 2
|
||||||
logAi->trace(
|
logAi->trace(
|
||||||
"It is %s to visit %s by %s with army %lld, danger %lld and army loss %lld",
|
"It is %s to visit %s by %s with army %lld, danger %lld and army loss %lld",
|
||||||
isSafe ? "safe" : "not safe",
|
isSafe ? "safe" : "not safe",
|
||||||
@@ -164,25 +162,25 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const CGTownInstance * upgrader)
|
|||||||
const int3 pos = upgrader->visitablePos();
|
const int3 pos = upgrader->visitablePos();
|
||||||
TResources availableResources = cb->getResourceAmount();
|
TResources availableResources = cb->getResourceAmount();
|
||||||
|
|
||||||
#ifdef AI_TRACE_LEVEL >= 1
|
#if AI_TRACE_LEVEL >= 1
|
||||||
logAi->trace("Checking ways to upgrade army in town %s, %s", upgrader->getObjectName(), pos.toString());
|
logAi->trace("Checking ways to upgrade army in town %s, %s", upgrader->getObjectName(), pos.toString());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto paths = ai->ah->getPathsToTile(pos);
|
auto paths = ai->ah->getPathsToTile(pos);
|
||||||
std::vector<std::shared_ptr<ExecuteHeroChain>> waysToVisitObj;
|
std::vector<std::shared_ptr<ExecuteHeroChain>> waysToVisitObj;
|
||||||
|
|
||||||
#ifdef AI_TRACE_LEVEL >= 1
|
#if AI_TRACE_LEVEL >= 1
|
||||||
logAi->trace("Found %d paths", paths.size());
|
logAi->trace("Found %d paths", paths.size());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for(const AIPath & path : paths)
|
for(const AIPath & path : paths)
|
||||||
{
|
{
|
||||||
#ifdef AI_TRACE_LEVEL >= 2
|
#if AI_TRACE_LEVEL >= 2
|
||||||
logAi->trace("Path found %s", path.toString());
|
logAi->trace("Path found %s", path.toString());
|
||||||
#endif
|
#endif
|
||||||
if(upgrader->visitingHero != path.targetHero)
|
if(upgrader->visitingHero != path.targetHero)
|
||||||
{
|
{
|
||||||
#ifdef AI_TRACE_LEVEL >= 2
|
#if AI_TRACE_LEVEL >= 2
|
||||||
logAi->trace("Ignore path. Town has visiting hero.");
|
logAi->trace("Ignore path. Town has visiting hero.");
|
||||||
#endif
|
#endif
|
||||||
continue;
|
continue;
|
||||||
@@ -190,7 +188,7 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const CGTownInstance * upgrader)
|
|||||||
|
|
||||||
if(path.getFirstBlockedAction())
|
if(path.getFirstBlockedAction())
|
||||||
{
|
{
|
||||||
#ifdef AI_TRACE_LEVEL >= 2
|
#if AI_TRACE_LEVEL >= 2
|
||||||
// TODO: decomposition?
|
// TODO: decomposition?
|
||||||
logAi->trace("Ignore path. Action is blocked.");
|
logAi->trace("Ignore path. Action is blocked.");
|
||||||
#endif
|
#endif
|
||||||
@@ -199,7 +197,7 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const CGTownInstance * upgrader)
|
|||||||
|
|
||||||
if(ai->nullkiller->dangerHitMap->enemyCanKillOurHeroesAlongThePath(path))
|
if(ai->nullkiller->dangerHitMap->enemyCanKillOurHeroesAlongThePath(path))
|
||||||
{
|
{
|
||||||
#ifdef AI_TRACE_LEVEL >= 2
|
#if AI_TRACE_LEVEL >= 2
|
||||||
logAi->trace("Ignore path. Target hero can be killed by enemy. Our power %lld", path.heroArmy->getArmyStrength());
|
logAi->trace("Ignore path. Target hero can be killed by enemy. Our power %lld", path.heroArmy->getArmyStrength());
|
||||||
#endif
|
#endif
|
||||||
continue;
|
continue;
|
||||||
@@ -215,7 +213,7 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const CGTownInstance * upgrader)
|
|||||||
|
|
||||||
auto isSafe = isSafeToVisit(path.targetHero, path.heroArmy, danger);
|
auto isSafe = isSafeToVisit(path.targetHero, path.heroArmy, danger);
|
||||||
|
|
||||||
#ifdef AI_TRACE_LEVEL >= 2
|
#if AI_TRACE_LEVEL >= 2
|
||||||
logAi->trace(
|
logAi->trace(
|
||||||
"It is %s to visit %s by %s with army %lld, danger %lld and army loss %lld",
|
"It is %s to visit %s by %s with army %lld, danger %lld and army loss %lld",
|
||||||
isSafe ? "safe" : "not safe",
|
isSafe ? "safe" : "not safe",
|
||||||
|
@@ -10,27 +10,29 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "lib/VCMI_Lib.h"
|
#include "lib/VCMI_Lib.h"
|
||||||
#include "Behavior.h"
|
#include "../Goals/CGoal.h"
|
||||||
#include "../AIUtility.h"
|
#include "../AIUtility.h"
|
||||||
|
|
||||||
class GatherArmyBehavior : public Behavior {
|
namespace Goals
|
||||||
private:
|
{
|
||||||
std::vector<int> objectTypes;
|
class GatherArmyBehavior : public CGoal<GatherArmyBehavior>
|
||||||
std::vector<int> objectSubTypes;
|
{
|
||||||
std::vector<const CGObjectInstance *> objectsToCapture;
|
|
||||||
bool specificObjects;
|
|
||||||
public:
|
public:
|
||||||
GatherArmyBehavior()
|
GatherArmyBehavior()
|
||||||
{
|
{
|
||||||
objectTypes = std::vector<int>();
|
|
||||||
specificObjects = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Goals::TGoalVec getTasks() override;
|
virtual TGoalVec decompose() const override;
|
||||||
virtual std::string toString() const override;
|
virtual std::string toString() const override;
|
||||||
|
|
||||||
private:
|
virtual bool operator==(const GatherArmyBehavior & other) const override
|
||||||
Goals::TGoalVec deliverArmyToHero(const CGHeroInstance * hero) const;
|
{
|
||||||
Goals::TGoalVec upgradeArmy(const CGTownInstance * upgrader) const;
|
return true;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TGoalVec deliverArmyToHero(const CGHeroInstance * hero) const;
|
||||||
|
TGoalVec upgradeArmy(const CGTownInstance * upgrader) const;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -28,7 +28,7 @@ std::string RecruitHeroBehavior::toString() const
|
|||||||
return "Recruit hero";
|
return "Recruit hero";
|
||||||
}
|
}
|
||||||
|
|
||||||
Goals::TGoalVec RecruitHeroBehavior::getTasks()
|
Goals::TGoalVec RecruitHeroBehavior::decompose() const
|
||||||
{
|
{
|
||||||
Goals::TGoalVec tasks;
|
Goals::TGoalVec tasks;
|
||||||
auto towns = cb->getTownsInfo();
|
auto towns = cb->getTownsInfo();
|
||||||
@@ -40,7 +40,7 @@ Goals::TGoalVec RecruitHeroBehavior::getTasks()
|
|||||||
if(cb->getHeroesInfo().size() < cb->getTownsInfo().size() + 1
|
if(cb->getHeroesInfo().size() < cb->getTownsInfo().size() + 1
|
||||||
|| cb->getResourceAmount(Res::GOLD) > 10000)
|
|| cb->getResourceAmount(Res::GOLD) > 10000)
|
||||||
{
|
{
|
||||||
tasks.push_back(Goals::sptr(Goals::RecruitHero().settown(town).setpriority(3)));
|
tasks.push_back(Goals::sptr(Goals::RecruitHero(town).setpriority(3)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -10,16 +10,24 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "lib/VCMI_Lib.h"
|
#include "lib/VCMI_Lib.h"
|
||||||
#include "Behavior.h"
|
#include "../Goals/CGoal.h"
|
||||||
#include "../AIUtility.h"
|
#include "../AIUtility.h"
|
||||||
|
|
||||||
class RecruitHeroBehavior : public Behavior
|
namespace Goals
|
||||||
|
{
|
||||||
|
class RecruitHeroBehavior : public CGoal<RecruitHeroBehavior>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RecruitHeroBehavior()
|
RecruitHeroBehavior()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Goals::TGoalVec getTasks() override;
|
virtual TGoalVec decompose() const override;
|
||||||
virtual std::string toString() const override;
|
virtual std::string toString() const override;
|
||||||
|
|
||||||
|
virtual bool operator==(const RecruitHeroBehavior & other) const override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
}
|
@@ -92,7 +92,7 @@ bool needToRecruitHero(const CGTownInstance * startupTown)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Goals::TGoalVec StartupBehavior::getTasks()
|
Goals::TGoalVec StartupBehavior::decompose() const
|
||||||
{
|
{
|
||||||
Goals::TGoalVec tasks;
|
Goals::TGoalVec tasks;
|
||||||
auto towns = cb->getTownsInfo();
|
auto towns = cb->getTownsInfo();
|
||||||
@@ -166,7 +166,7 @@ Goals::TGoalVec StartupBehavior::getTasks()
|
|||||||
|
|
||||||
if(tasks.empty() && canRecruitHero && !startupTown->visitingHero)
|
if(tasks.empty() && canRecruitHero && !startupTown->visitingHero)
|
||||||
{
|
{
|
||||||
tasks.push_back(Goals::sptr(Goals::RecruitHero()));
|
tasks.push_back(Goals::sptr(Goals::RecruitHero(startupTown)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tasks.empty() && towns.size())
|
if(tasks.empty() && towns.size())
|
||||||
|
@@ -10,17 +10,25 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "lib/VCMI_Lib.h"
|
#include "lib/VCMI_Lib.h"
|
||||||
#include "Behavior.h"
|
#include "../Goals/CGoal.h"
|
||||||
#include "../AIUtility.h"
|
#include "../AIUtility.h"
|
||||||
|
|
||||||
class StartupBehavior : public Behavior
|
namespace Goals
|
||||||
|
{
|
||||||
|
class StartupBehavior : public CGoal<StartupBehavior>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
StartupBehavior()
|
StartupBehavior()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Goals::TGoalVec getTasks() override;
|
virtual TGoalVec decompose() const override;
|
||||||
virtual std::string toString() const override;
|
virtual std::string toString() const override;
|
||||||
};
|
|
||||||
|
virtual bool operator==(const StartupBehavior & other) const override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -27,24 +27,18 @@ set(VCAI_SRCS
|
|||||||
Goals/GatherTroops.cpp
|
Goals/GatherTroops.cpp
|
||||||
Goals/BuyArmy.cpp
|
Goals/BuyArmy.cpp
|
||||||
Goals/AdventureSpellCast.cpp
|
Goals/AdventureSpellCast.cpp
|
||||||
Goals/Win.cpp
|
|
||||||
Goals/VisitTile.cpp
|
|
||||||
Goals/VisitObj.cpp
|
|
||||||
Goals/VisitHero.cpp
|
|
||||||
Goals/CollectRes.cpp
|
Goals/CollectRes.cpp
|
||||||
Goals/Trade.cpp
|
Goals/Trade.cpp
|
||||||
Goals/RecruitHero.cpp
|
Goals/RecruitHero.cpp
|
||||||
Goals/DigAtTile.cpp
|
Goals/DigAtTile.cpp
|
||||||
Goals/GetArtOfType.cpp
|
Goals/GetArtOfType.cpp
|
||||||
Goals/FindObj.cpp
|
Goals/FindObj.cpp
|
||||||
Goals/CompleteQuest.cpp
|
|
||||||
Goals/ExecuteHeroChain.cpp
|
Goals/ExecuteHeroChain.cpp
|
||||||
Goals/ExchangeSwapTownHeroes.cpp
|
Goals/ExchangeSwapTownHeroes.cpp
|
||||||
Engine/Nullkiller.cpp
|
Engine/Nullkiller.cpp
|
||||||
Engine/PriorityEvaluator.cpp
|
Engine/PriorityEvaluator.cpp
|
||||||
Analyzers/DangerHitMapAnalyzer.cpp
|
Analyzers/DangerHitMapAnalyzer.cpp
|
||||||
Analyzers/BuildAnalyzer.cpp
|
Analyzers/BuildAnalyzer.cpp
|
||||||
Behaviors/Behavior.cpp
|
|
||||||
Behaviors/CaptureObjectsBehavior.cpp
|
Behaviors/CaptureObjectsBehavior.cpp
|
||||||
Behaviors/RecruitHeroBehavior.cpp
|
Behaviors/RecruitHeroBehavior.cpp
|
||||||
Behaviors/BuyArmyBehavior.cpp
|
Behaviors/BuyArmyBehavior.cpp
|
||||||
@@ -52,6 +46,7 @@ set(VCAI_SRCS
|
|||||||
Behaviors/StartupBehavior.cpp
|
Behaviors/StartupBehavior.cpp
|
||||||
Behaviors/BuildingBehavior.cpp
|
Behaviors/BuildingBehavior.cpp
|
||||||
Behaviors/GatherArmyBehavior.cpp
|
Behaviors/GatherArmyBehavior.cpp
|
||||||
|
Behaviors/CompleteQuestBehavior.cpp
|
||||||
main.cpp
|
main.cpp
|
||||||
VCAI.cpp
|
VCAI.cpp
|
||||||
)
|
)
|
||||||
@@ -88,17 +83,12 @@ set(VCAI_HEADERS
|
|||||||
Goals/GatherTroops.h
|
Goals/GatherTroops.h
|
||||||
Goals/BuyArmy.h
|
Goals/BuyArmy.h
|
||||||
Goals/AdventureSpellCast.h
|
Goals/AdventureSpellCast.h
|
||||||
Goals/Win.h
|
|
||||||
Goals/VisitTile.h
|
|
||||||
Goals/VisitObj.h
|
|
||||||
Goals/VisitHero.h
|
|
||||||
Goals/CollectRes.h
|
Goals/CollectRes.h
|
||||||
Goals/Trade.h
|
Goals/Trade.h
|
||||||
Goals/RecruitHero.h
|
Goals/RecruitHero.h
|
||||||
Goals/DigAtTile.h
|
Goals/DigAtTile.h
|
||||||
Goals/GetArtOfType.h
|
Goals/GetArtOfType.h
|
||||||
Goals/FindObj.h
|
Goals/FindObj.h
|
||||||
Goals/CompleteQuest.h
|
|
||||||
Goals/ExecuteHeroChain.h
|
Goals/ExecuteHeroChain.h
|
||||||
Goals/ExchangeSwapTownHeroes.h
|
Goals/ExchangeSwapTownHeroes.h
|
||||||
Goals/Goals.h
|
Goals/Goals.h
|
||||||
@@ -106,7 +96,6 @@ set(VCAI_HEADERS
|
|||||||
Engine/PriorityEvaluator.h
|
Engine/PriorityEvaluator.h
|
||||||
Analyzers/DangerHitMapAnalyzer.h
|
Analyzers/DangerHitMapAnalyzer.h
|
||||||
Analyzers/BuildAnalyzer.h
|
Analyzers/BuildAnalyzer.h
|
||||||
Behaviors/Behavior.h
|
|
||||||
Behaviors/CaptureObjectsBehavior.h
|
Behaviors/CaptureObjectsBehavior.h
|
||||||
Behaviors/RecruitHeroBehavior.h
|
Behaviors/RecruitHeroBehavior.h
|
||||||
Behaviors/BuyArmyBehavior.h
|
Behaviors/BuyArmyBehavior.h
|
||||||
@@ -114,6 +103,7 @@ set(VCAI_HEADERS
|
|||||||
Behaviors/StartupBehavior.h
|
Behaviors/StartupBehavior.h
|
||||||
Behaviors/BuildingBehavior.h
|
Behaviors/BuildingBehavior.h
|
||||||
Behaviors/GatherArmyBehavior.h
|
Behaviors/GatherArmyBehavior.h
|
||||||
|
Behaviors/CompleteQuestBehavior.h
|
||||||
VCAI.h
|
VCAI.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -23,6 +23,8 @@
|
|||||||
extern boost::thread_specific_ptr<CCallback> cb;
|
extern boost::thread_specific_ptr<CCallback> cb;
|
||||||
extern boost::thread_specific_ptr<VCAI> ai;
|
extern boost::thread_specific_ptr<VCAI> ai;
|
||||||
|
|
||||||
|
using namespace Goals;
|
||||||
|
|
||||||
Nullkiller::Nullkiller()
|
Nullkiller::Nullkiller()
|
||||||
{
|
{
|
||||||
priorityEvaluator.reset(new PriorityEvaluator());
|
priorityEvaluator.reset(new PriorityEvaluator());
|
||||||
@@ -30,38 +32,75 @@ Nullkiller::Nullkiller()
|
|||||||
buildAnalyzer.reset(new BuildAnalyzer());
|
buildAnalyzer.reset(new BuildAnalyzer());
|
||||||
}
|
}
|
||||||
|
|
||||||
Goals::TSubgoal Nullkiller::choseBestTask(Goals::TGoalVec & tasks) const
|
Goals::TTask Nullkiller::choseBestTask(Goals::TTaskVec & tasks) const
|
||||||
{
|
{
|
||||||
Goals::TSubgoal bestTask = *vstd::maxElementByFun(tasks, [](Goals::TSubgoal goal) -> float{
|
Goals::TTask bestTask = *vstd::maxElementByFun(tasks, [](Goals::TTask task) -> float{
|
||||||
return goal->priority;
|
return task->priority;
|
||||||
});
|
});
|
||||||
|
|
||||||
return bestTask;
|
return bestTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
Goals::TSubgoal Nullkiller::choseBestTask(std::shared_ptr<Behavior> behavior) const
|
Goals::TTask Nullkiller::choseBestTask(Goals::TSubgoal behavior) const
|
||||||
{
|
{
|
||||||
logAi->debug("Checking behavior %s", behavior->toString());
|
logAi->debug("Checking behavior %s", behavior->toString());
|
||||||
|
|
||||||
auto tasks = behavior->getTasks();
|
const int MAX_DEPTH = 10;
|
||||||
|
Goals::TGoalVec goals[MAX_DEPTH + 1];
|
||||||
|
Goals::TTaskVec tasks;
|
||||||
|
|
||||||
|
goals[0] = {behavior};
|
||||||
|
|
||||||
if(tasks.empty())
|
if(tasks.empty())
|
||||||
{
|
{
|
||||||
logAi->debug("Behavior %s found no tasks", behavior->toString());
|
logAi->debug("Behavior %s found no tasks", behavior->toString());
|
||||||
|
|
||||||
return Goals::sptr(Goals::Invalid());
|
return Goals::taskptr(Goals::Invalid());
|
||||||
}
|
}
|
||||||
|
|
||||||
logAi->trace("Evaluating priorities, tasks count %d", tasks.size());
|
logAi->trace("Evaluating priorities, tasks count %d", tasks.size());
|
||||||
|
|
||||||
for(auto task : tasks)
|
int depth = 0;
|
||||||
|
while(goals[0].size())
|
||||||
{
|
{
|
||||||
task->setpriority(priorityEvaluator->evaluate(task));
|
TSubgoal current = goals[depth].back();
|
||||||
|
TGoalVec subgoals = current->decompose();
|
||||||
|
|
||||||
|
goals[depth + 1].clear();
|
||||||
|
|
||||||
|
for(auto subgoal : subgoals)
|
||||||
|
{
|
||||||
|
if(subgoal->isElementar)
|
||||||
|
{
|
||||||
|
auto task = taskptr(*subgoal);
|
||||||
|
|
||||||
|
if(task->priority <= 0)
|
||||||
|
task->priority = priorityEvaluator->evaluate(subgoal);
|
||||||
|
|
||||||
|
tasks.push_back(task);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goals[depth + 1].push_back(subgoal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(goals[depth + 1].size() && depth < MAX_DEPTH)
|
||||||
|
{
|
||||||
|
depth++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while(depth > 0 && goals[depth].empty())
|
||||||
|
{
|
||||||
|
depth--;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto task = choseBestTask(tasks);
|
auto task = choseBestTask(tasks);
|
||||||
|
|
||||||
logAi->debug("Behavior %s returns %s(%s), priority %f", behavior->toString(), task->name(), task->tile.toString(), task->priority);
|
logAi->debug("Behavior %s returns %s, priority %f", behavior->toString(), task->toString(), task->priority);
|
||||||
|
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
@@ -141,54 +180,49 @@ void Nullkiller::makeTurn()
|
|||||||
{
|
{
|
||||||
updateAiState();
|
updateAiState();
|
||||||
|
|
||||||
Goals::TGoalVec bestTasks = {
|
Goals::TTaskVec bestTasks = {
|
||||||
choseBestTask(std::make_shared<BuyArmyBehavior>()),
|
choseBestTask(sptr(BuyArmyBehavior())),
|
||||||
choseBestTask(std::make_shared<CaptureObjectsBehavior>()),
|
choseBestTask(sptr(CaptureObjectsBehavior())),
|
||||||
choseBestTask(std::make_shared<RecruitHeroBehavior>()),
|
choseBestTask(sptr(RecruitHeroBehavior())),
|
||||||
choseBestTask(std::make_shared<DefenceBehavior>()),
|
choseBestTask(sptr(DefenceBehavior())),
|
||||||
choseBestTask(std::make_shared<BuildingBehavior>()),
|
choseBestTask(sptr(BuildingBehavior())),
|
||||||
choseBestTask(std::make_shared<GatherArmyBehavior>())
|
choseBestTask(sptr(GatherArmyBehavior()))
|
||||||
};
|
};
|
||||||
|
|
||||||
if(cb->getDate(Date::DAY) == 1)
|
if(cb->getDate(Date::DAY) == 1)
|
||||||
{
|
{
|
||||||
bestTasks.push_back(choseBestTask(std::make_shared<StartupBehavior>()));
|
bestTasks.push_back(choseBestTask(sptr(StartupBehavior())));
|
||||||
}
|
}
|
||||||
|
|
||||||
Goals::TSubgoal bestTask = choseBestTask(bestTasks);
|
Goals::TTask bestTask = choseBestTask(bestTasks);
|
||||||
|
|
||||||
if(bestTask->invalid())
|
/*if(bestTask->invalid())
|
||||||
{
|
{
|
||||||
logAi->trace("No goals found. Ending turn.");
|
logAi->trace("No goals found. Ending turn.");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
if(bestTask->priority < MIN_PRIORITY)
|
if(bestTask->priority < MIN_PRIORITY)
|
||||||
{
|
{
|
||||||
logAi->trace("Goal %s has too low priority. It is not worth doing it. Ending turn.", bestTask->name());
|
logAi->trace("Goal %s has too low priority. It is not worth doing it. Ending turn.", bestTask->toString());
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
logAi->debug("Trying to realize %s (value %2.3f)", bestTask->name(), bestTask->priority);
|
logAi->debug("Trying to realize %s (value %2.3f)", bestTask->toString(), bestTask->priority);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if(bestTask->hero)
|
|
||||||
{
|
|
||||||
setActive(bestTask->hero.get(), bestTask->tile);
|
|
||||||
}
|
|
||||||
|
|
||||||
bestTask->accept(ai.get());
|
bestTask->accept(ai.get());
|
||||||
}
|
}
|
||||||
catch(goalFulfilledException &)
|
catch(goalFulfilledException &)
|
||||||
{
|
{
|
||||||
logAi->trace("Task %s completed", bestTask->name());
|
logAi->trace("Task %s completed", bestTask->toString());
|
||||||
}
|
}
|
||||||
catch(std::exception & e)
|
catch(std::exception & e)
|
||||||
{
|
{
|
||||||
logAi->debug("Failed to realize subgoal of type %s, I will stop.", bestTask->name());
|
logAi->debug("Failed to realize subgoal of type %s, I will stop.", bestTask->toString());
|
||||||
logAi->debug("The error message was: %s", e.what());
|
logAi->debug("The error message was: %s", e.what());
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@@ -13,7 +13,6 @@
|
|||||||
#include "../Analyzers/DangerHitMapAnalyzer.h"
|
#include "../Analyzers/DangerHitMapAnalyzer.h"
|
||||||
#include "../Analyzers/BuildAnalyzer.h"
|
#include "../Analyzers/BuildAnalyzer.h"
|
||||||
#include "../Goals/AbstractGoal.h"
|
#include "../Goals/AbstractGoal.h"
|
||||||
#include "../Behaviors/Behavior.h"
|
|
||||||
|
|
||||||
const float MAX_GOLD_PEASURE = 0.3f;
|
const float MAX_GOLD_PEASURE = 0.3f;
|
||||||
const float MIN_PRIORITY = 0.01f;
|
const float MIN_PRIORITY = 0.01f;
|
||||||
@@ -56,6 +55,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
void resetAiState();
|
void resetAiState();
|
||||||
void updateAiState();
|
void updateAiState();
|
||||||
Goals::TSubgoal choseBestTask(std::shared_ptr<Behavior> behavior) const;
|
Goals::TTask choseBestTask(Goals::TSubgoal behavior) const;
|
||||||
Goals::TSubgoal choseBestTask(Goals::TGoalVec & tasks) const;
|
Goals::TTask choseBestTask(Goals::TTaskVec & tasks) const;
|
||||||
};
|
};
|
||||||
|
@@ -520,9 +520,6 @@ Goals::EvaluationContext PriorityEvaluator::buildEvaluationContext(Goals::TSubgo
|
|||||||
/// importance
|
/// importance
|
||||||
float PriorityEvaluator::evaluate(Goals::TSubgoal task)
|
float PriorityEvaluator::evaluate(Goals::TSubgoal task)
|
||||||
{
|
{
|
||||||
if(task->priority > 0)
|
|
||||||
return task->priority;
|
|
||||||
|
|
||||||
auto evaluationContext = buildEvaluationContext(task);
|
auto evaluationContext = buildEvaluationContext(task);
|
||||||
|
|
||||||
int rewardType = (evaluationContext.goldReward > 0 ? 1 : 0)
|
int rewardType = (evaluationContext.goldReward > 0 ? 1 : 0)
|
||||||
@@ -561,7 +558,7 @@ float PriorityEvaluator::evaluate(Goals::TSubgoal task)
|
|||||||
|
|
||||||
#ifdef VCMI_TRACE_PATHFINDER
|
#ifdef VCMI_TRACE_PATHFINDER
|
||||||
logAi->trace("Evaluated %s, loss: %f, turns main: %f, scout: %f, gold: %d, cost: %d, army gain: %d, danger: %d, role: %s, strategical value: %f, cwr: %f, result %f",
|
logAi->trace("Evaluated %s, loss: %f, turns main: %f, scout: %f, gold: %d, cost: %d, army gain: %d, danger: %d, role: %s, strategical value: %f, cwr: %f, result %f",
|
||||||
task->name(),
|
task->toString(),
|
||||||
evaluationContext.armyLossPersentage,
|
evaluationContext.armyLossPersentage,
|
||||||
evaluationContext.movementCostByRole[HeroRole::MAIN],
|
evaluationContext.movementCostByRole[HeroRole::MAIN],
|
||||||
evaluationContext.movementCostByRole[HeroRole::SCOUT],
|
evaluationContext.movementCostByRole[HeroRole::SCOUT],
|
||||||
|
@@ -89,19 +89,6 @@ armyStructure evaluateArmyStructure(const CArmedInstance * army)
|
|||||||
return as;
|
return as;
|
||||||
}
|
}
|
||||||
|
|
||||||
float HeroMovementGoalEngineBase::calculateTurnDistanceInputValue(const Goals::AbstractGoal & goal) const
|
|
||||||
{
|
|
||||||
if(goal.evaluationContext.movementCost > 0)
|
|
||||||
{
|
|
||||||
return goal.evaluationContext.movementCost;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto pathInfo = ai->myCb->getPathsInfo(goal.hero.h)->getPathInfo(goal.tile);
|
|
||||||
return pathInfo->cost;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TacticalAdvantageEngine::TacticalAdvantageEngine()
|
TacticalAdvantageEngine::TacticalAdvantageEngine()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -254,206 +241,3 @@ float TacticalAdvantageEngine::getTacticalAdvantage(const CArmedInstance * we, c
|
|||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
//std::shared_ptr<AbstractGoal> chooseSolution (std::vector<std::shared_ptr<AbstractGoal>> & vec)
|
|
||||||
|
|
||||||
HeroMovementGoalEngineBase::HeroMovementGoalEngineBase()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
strengthRatio = new fl::InputVariable("strengthRatio"); //hero must be strong enough to defeat guards
|
|
||||||
heroStrengthVariable = new fl::InputVariable("heroStrengthVariable"); //we want to use weakest possible hero
|
|
||||||
turnDistanceVariable = new fl::InputVariable("turnDistanceVariable"); //we want to use hero who is near
|
|
||||||
missionImportance = new fl::InputVariable("lockedMissionImportance"); //we may want to preempt hero with low-priority mission
|
|
||||||
value = new fl::OutputVariable("Value");
|
|
||||||
value->setMinimum(0);
|
|
||||||
value->setMaximum(5);
|
|
||||||
|
|
||||||
std::vector<fl::InputVariable *> helper = { strengthRatio, heroStrengthVariable, turnDistanceVariable, missionImportance };
|
|
||||||
for(auto val : helper)
|
|
||||||
{
|
|
||||||
engine.addInputVariable(val);
|
|
||||||
}
|
|
||||||
engine.addOutputVariable(value);
|
|
||||||
|
|
||||||
strengthRatio->addTerm(new fl::Ramp("LOW", SAFE_ATTACK_CONSTANT, 0));
|
|
||||||
strengthRatio->addTerm(new fl::Ramp("HIGH", SAFE_ATTACK_CONSTANT, SAFE_ATTACK_CONSTANT * 3));
|
|
||||||
strengthRatio->setRange(0, SAFE_ATTACK_CONSTANT * 3);
|
|
||||||
|
|
||||||
//strength compared to our main hero
|
|
||||||
heroStrengthVariable->addTerm(new fl::Ramp("LOW", 0.5, 0));
|
|
||||||
heroStrengthVariable->addTerm(new fl::Triangle("MEDIUM", 0.2, 0.8));
|
|
||||||
heroStrengthVariable->addTerm(new fl::Ramp("HIGH", 0.5, 1));
|
|
||||||
heroStrengthVariable->setRange(0.0, 1.0);
|
|
||||||
|
|
||||||
turnDistanceVariable->addTerm(new fl::Ramp("SHORT", 0.5, 0));
|
|
||||||
turnDistanceVariable->addTerm(new fl::Triangle("MEDIUM", 0.1, 0.8));
|
|
||||||
turnDistanceVariable->addTerm(new fl::Ramp("LONG", 0.5, 10));
|
|
||||||
turnDistanceVariable->setRange(0.0, 10.0);
|
|
||||||
|
|
||||||
missionImportance->addTerm(new fl::Ramp("LOW", 2.5, 0));
|
|
||||||
missionImportance->addTerm(new fl::Triangle("MEDIUM", 2, 3));
|
|
||||||
missionImportance->addTerm(new fl::Ramp("HIGH", 2.5, 5));
|
|
||||||
missionImportance->setRange(0.0, 5.0);
|
|
||||||
|
|
||||||
//an issue: in 99% cases this outputs center of mass (2.5) regardless of actual input :/
|
|
||||||
//should be same as "mission Importance" to keep consistency
|
|
||||||
value->addTerm(new fl::Ramp("LOW", 2.5, 0));
|
|
||||||
value->addTerm(new fl::Triangle("MEDIUM", 2, 3)); //can't be center of mass :/
|
|
||||||
value->addTerm(new fl::Ramp("HIGH", 2.5, 5));
|
|
||||||
value->setRange(0.0, 5.0);
|
|
||||||
|
|
||||||
//use unarmed scouts if possible
|
|
||||||
addRule("if strengthRatio is HIGH and heroStrengthVariable is LOW then Value is HIGH");
|
|
||||||
//we may want to use secondary hero(es) rather than main hero
|
|
||||||
addRule("if strengthRatio is HIGH and heroStrengthVariable is MEDIUM then Value is MEDIUM");
|
|
||||||
addRule("if strengthRatio is HIGH and heroStrengthVariable is HIGH then Value is LOW");
|
|
||||||
//don't assign targets to heroes who are too weak, but prefer targets of our main hero (in case we need to gather army)
|
|
||||||
addRule("if strengthRatio is LOW and heroStrengthVariable is LOW then Value is LOW");
|
|
||||||
//attempt to arm secondary heroes is not stupid
|
|
||||||
addRule("if strengthRatio is LOW and heroStrengthVariable is MEDIUM then Value is HIGH");
|
|
||||||
addRule("if strengthRatio is LOW and heroStrengthVariable is HIGH then Value is LOW");
|
|
||||||
|
|
||||||
//do not cancel important goals
|
|
||||||
addRule("if lockedMissionImportance is HIGH then Value is LOW");
|
|
||||||
addRule("if lockedMissionImportance is MEDIUM then Value is MEDIUM");
|
|
||||||
addRule("if lockedMissionImportance is LOW then Value is HIGH");
|
|
||||||
//pick nearby objects if it's easy, avoid long walks
|
|
||||||
addRule("if turnDistanceVariable is SHORT then Value is HIGH");
|
|
||||||
addRule("if turnDistanceVariable is MEDIUM then Value is MEDIUM");
|
|
||||||
addRule("if turnDistanceVariable is LONG then Value is LOW");
|
|
||||||
}
|
|
||||||
catch(fl::Exception & fe)
|
|
||||||
{
|
|
||||||
logAi->error("HeroMovementGoalEngineBase: %s", fe.getWhat());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HeroMovementGoalEngineBase::setSharedFuzzyVariables(Goals::AbstractGoal & goal)
|
|
||||||
{
|
|
||||||
float turns = calculateTurnDistanceInputValue(goal);
|
|
||||||
float missionImportanceData = 0;
|
|
||||||
|
|
||||||
if(vstd::contains(ai->lockedHeroes, goal.hero))
|
|
||||||
{
|
|
||||||
missionImportanceData = ai->lockedHeroes[goal.hero]->priority;
|
|
||||||
}
|
|
||||||
else if(goal.parent)
|
|
||||||
{
|
|
||||||
missionImportanceData = goal.parent->priority;
|
|
||||||
}
|
|
||||||
|
|
||||||
float strengthRatioData = 10.0f; //we are much stronger than enemy
|
|
||||||
ui64 danger = fh->evaluateDanger(goal.tile, goal.hero.h);
|
|
||||||
if(danger)
|
|
||||||
strengthRatioData = (fl::scalar)goal.hero.h->getTotalStrength() / danger;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
strengthRatio->setValue(strengthRatioData);
|
|
||||||
heroStrengthVariable->setValue((fl::scalar)goal.hero->getTotalStrength() / ai->primaryHero()->getTotalStrength());
|
|
||||||
turnDistanceVariable->setValue(turns);
|
|
||||||
missionImportance->setValue(missionImportanceData);
|
|
||||||
}
|
|
||||||
catch(fl::Exception & fe)
|
|
||||||
{
|
|
||||||
logAi->error("HeroMovementGoalEngineBase::setSharedFuzzyVariables: %s", fe.getWhat());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VisitObjEngine::VisitObjEngine()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
objectValue = new fl::InputVariable("objectValue"); //value of that object type known by AI
|
|
||||||
|
|
||||||
engine.addInputVariable(objectValue);
|
|
||||||
|
|
||||||
//objectValue ranges are based on checking RMG priorities of some objects and checking LOW/MID/HIGH proportions for various values in QtFuzzyLite
|
|
||||||
objectValue->addTerm(new fl::Ramp("LOW", 3500.0, 0.0));
|
|
||||||
objectValue->addTerm(new fl::Triangle("MEDIUM", 0.0, 8500.0));
|
|
||||||
std::vector<fl::Discrete::Pair> multiRamp = { fl::Discrete::Pair(5000.0, 0.0), fl::Discrete::Pair(10000.0, 0.75), fl::Discrete::Pair(20000.0, 1.0) };
|
|
||||||
objectValue->addTerm(new fl::Discrete("HIGH", multiRamp));
|
|
||||||
objectValue->setRange(0.0, 20000.0); //relic artifact value is border value by design, even better things are scaled down.
|
|
||||||
|
|
||||||
addRule("if objectValue is HIGH then Value is HIGH");
|
|
||||||
addRule("if objectValue is MEDIUM then Value is MEDIUM");
|
|
||||||
addRule("if objectValue is LOW then Value is LOW");
|
|
||||||
}
|
|
||||||
catch(fl::Exception & fe)
|
|
||||||
{
|
|
||||||
logAi->error("FindWanderTarget: %s", fe.getWhat());
|
|
||||||
}
|
|
||||||
configure();
|
|
||||||
}
|
|
||||||
|
|
||||||
float VisitObjEngine::evaluate(Goals::VisitObj & goal)
|
|
||||||
{
|
|
||||||
if(!goal.hero)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
auto obj = ai->myCb->getObj(ObjectInstanceID(goal.objid));
|
|
||||||
if(!obj)
|
|
||||||
{
|
|
||||||
logAi->error("Goals::VisitObj objid " + std::to_string(goal.objid) + " no longer visible, probably goal used for something it's not intended");
|
|
||||||
return -100; // FIXME: Added check when goal was used for hero instead of VisitHero, but crashes are bad anyway
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::optional<int> objValueKnownByAI = MapObjectsEvaluator::getInstance().getObjectValue(obj);
|
|
||||||
int objValue = 0;
|
|
||||||
|
|
||||||
if(objValueKnownByAI != boost::none) //consider adding value manipulation based on object instances on map
|
|
||||||
{
|
|
||||||
objValue = std::min(std::max(objValueKnownByAI.get(), 0), 20000);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MapObjectsEvaluator::getInstance().addObjectData(obj->ID, obj->subID, 0);
|
|
||||||
logGlobal->error("AI met object type it doesn't know - ID: " + std::to_string(obj->ID) + ", subID: " + std::to_string(obj->subID) + " - adding to database with value " + std::to_string(objValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
setSharedFuzzyVariables(goal);
|
|
||||||
|
|
||||||
float output = -1.0f;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
objectValue->setValue(objValue);
|
|
||||||
engine.process();
|
|
||||||
output = value->getValue();
|
|
||||||
}
|
|
||||||
catch(fl::Exception & fe)
|
|
||||||
{
|
|
||||||
logAi->error("evaluate getWanderTargetObjectValue: %s", fe.getWhat());
|
|
||||||
}
|
|
||||||
assert(output >= 0.0f);
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
VisitTileEngine::VisitTileEngine() //so far no VisitTile-specific variables that are not shared with HeroMovementGoalEngineBase
|
|
||||||
{
|
|
||||||
configure();
|
|
||||||
}
|
|
||||||
|
|
||||||
float VisitTileEngine::evaluate(Goals::VisitTile & goal)
|
|
||||||
{
|
|
||||||
//we assume that hero is already set and we want to choose most suitable one for the mission
|
|
||||||
if(!goal.hero)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
//assert(cb->isInTheMap(g.tile));
|
|
||||||
|
|
||||||
setSharedFuzzyVariables(goal);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
engine.process();
|
|
||||||
|
|
||||||
goal.priority = value->getValue();
|
|
||||||
}
|
|
||||||
catch(fl::Exception & fe)
|
|
||||||
{
|
|
||||||
logAi->error("evaluate VisitTile: %s", fe.getWhat());
|
|
||||||
}
|
|
||||||
assert(goal.priority >= 0);
|
|
||||||
return goal.priority;
|
|
||||||
}
|
|
||||||
|
@@ -36,37 +36,3 @@ private:
|
|||||||
fl::InputVariable * castleWalls;
|
fl::InputVariable * castleWalls;
|
||||||
fl::OutputVariable * threat;
|
fl::OutputVariable * threat;
|
||||||
};
|
};
|
||||||
|
|
||||||
class HeroMovementGoalEngineBase : public engineBase //in future - maybe derive from some (GoalEngineBase : public engineBase) class for handling non-movement goals with common utility for goal engines
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HeroMovementGoalEngineBase();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void setSharedFuzzyVariables(Goals::AbstractGoal & goal);
|
|
||||||
|
|
||||||
fl::InputVariable * strengthRatio;
|
|
||||||
fl::InputVariable * heroStrengthVariable;
|
|
||||||
fl::InputVariable * turnDistanceVariable;
|
|
||||||
fl::InputVariable * missionImportance;
|
|
||||||
fl::OutputVariable * value;
|
|
||||||
|
|
||||||
private:
|
|
||||||
float calculateTurnDistanceInputValue(const Goals::AbstractGoal & goal) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
class VisitTileEngine : public HeroMovementGoalEngineBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VisitTileEngine();
|
|
||||||
float evaluate(Goals::VisitTile & goal);
|
|
||||||
};
|
|
||||||
|
|
||||||
class VisitObjEngine : public HeroMovementGoalEngineBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VisitObjEngine();
|
|
||||||
float evaluate(Goals::VisitObj & goal);
|
|
||||||
protected:
|
|
||||||
fl::InputVariable * objectValue;
|
|
||||||
};
|
|
||||||
|
@@ -29,7 +29,19 @@ TSubgoal Goals::sptr(const AbstractGoal & tmp)
|
|||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AbstractGoal::name() const //TODO: virtualize
|
TTask Goals::taskptr(const AbstractGoal & tmp)
|
||||||
|
{
|
||||||
|
TTask ptr;
|
||||||
|
|
||||||
|
if(!tmp.isElementar)
|
||||||
|
throw cannotFulfillGoalException(tmp.toString() + " is not elementar");
|
||||||
|
|
||||||
|
ptr.reset(dynamic_cast<ITask *>(tmp.clone()));
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AbstractGoal::toString() const //TODO: virtualize
|
||||||
{
|
{
|
||||||
std::string desc;
|
std::string desc;
|
||||||
switch(goalType)
|
switch(goalType)
|
||||||
@@ -124,11 +136,6 @@ bool AbstractGoal::invalid() const
|
|||||||
return goalType == EGoals::INVALID;
|
return goalType == EGoals::INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractGoal::accept(VCAI * ai)
|
|
||||||
{
|
|
||||||
ai->tryRealize(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
EvaluationContext::EvaluationContext()
|
EvaluationContext::EvaluationContext()
|
||||||
: movementCost(0.0),
|
: movementCost(0.0),
|
||||||
manaCost(0),
|
manaCost(0),
|
||||||
|
@@ -22,21 +22,16 @@ class FuzzyHelper;
|
|||||||
namespace Goals
|
namespace Goals
|
||||||
{
|
{
|
||||||
class AbstractGoal;
|
class AbstractGoal;
|
||||||
class Explore;
|
class ITask;
|
||||||
class RecruitHero;
|
class RecruitHero;
|
||||||
class VisitTile;
|
|
||||||
class VisitObj;
|
|
||||||
class VisitHero;
|
|
||||||
class BuildThis;
|
class BuildThis;
|
||||||
class DigAtTile;
|
class DigAtTile;
|
||||||
class CollectRes;
|
class CollectRes;
|
||||||
class BuyArmy;
|
class BuyArmy;
|
||||||
class BuildBoat;
|
class BuildBoat;
|
||||||
class GatherArmy;
|
|
||||||
class ClearWayTo;
|
class ClearWayTo;
|
||||||
class Invalid;
|
class Invalid;
|
||||||
class Trade;
|
class Trade;
|
||||||
class CompleteQuest;
|
|
||||||
class AdventureSpellCast;
|
class AdventureSpellCast;
|
||||||
|
|
||||||
enum EGoals
|
enum EGoals
|
||||||
@@ -78,6 +73,8 @@ namespace Goals
|
|||||||
//TODO: serialize?
|
//TODO: serialize?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef std::shared_ptr<ITask> TTask;
|
||||||
|
typedef std::vector<TTask> TTaskVec;
|
||||||
typedef std::vector<TSubgoal> TGoalVec;
|
typedef std::vector<TSubgoal> TGoalVec;
|
||||||
|
|
||||||
//method chaining + clone pattern
|
//method chaining + clone pattern
|
||||||
@@ -91,6 +88,7 @@ namespace Goals
|
|||||||
enum { LOW_PR = -1 };
|
enum { LOW_PR = -1 };
|
||||||
|
|
||||||
DLL_EXPORT TSubgoal sptr(const AbstractGoal & tmp);
|
DLL_EXPORT TSubgoal sptr(const AbstractGoal & tmp);
|
||||||
|
DLL_EXPORT TTask taskptr(const AbstractGoal & tmp);
|
||||||
|
|
||||||
struct DLL_EXPORT EvaluationContext
|
struct DLL_EXPORT EvaluationContext
|
||||||
{
|
{
|
||||||
@@ -118,7 +116,6 @@ namespace Goals
|
|||||||
public:
|
public:
|
||||||
bool isElementar; VSETTER(bool, isElementar)
|
bool isElementar; VSETTER(bool, isElementar)
|
||||||
bool isAbstract; VSETTER(bool, isAbstract)
|
bool isAbstract; VSETTER(bool, isAbstract)
|
||||||
float priority; VSETTER(float, priority)
|
|
||||||
int value; VSETTER(int, value)
|
int value; VSETTER(int, value)
|
||||||
int resID; VSETTER(int, resID)
|
int resID; VSETTER(int, resID)
|
||||||
int objid; VSETTER(int, objid)
|
int objid; VSETTER(int, objid)
|
||||||
@@ -133,7 +130,6 @@ namespace Goals
|
|||||||
AbstractGoal(EGoals goal = EGoals::INVALID)
|
AbstractGoal(EGoals goal = EGoals::INVALID)
|
||||||
: goalType(goal), evaluationContext()
|
: goalType(goal), evaluationContext()
|
||||||
{
|
{
|
||||||
priority = 0;
|
|
||||||
isElementar = false;
|
isElementar = false;
|
||||||
isAbstract = false;
|
isAbstract = false;
|
||||||
value = 0;
|
value = 0;
|
||||||
@@ -150,25 +146,18 @@ namespace Goals
|
|||||||
{
|
{
|
||||||
return const_cast<AbstractGoal *>(this);
|
return const_cast<AbstractGoal *>(this);
|
||||||
}
|
}
|
||||||
virtual TGoalVec getAllPossibleSubgoals()
|
|
||||||
|
virtual TGoalVec decompose() const
|
||||||
{
|
{
|
||||||
return TGoalVec();
|
return TGoalVec();
|
||||||
}
|
}
|
||||||
virtual TSubgoal whatToDoToAchieve()
|
|
||||||
{
|
|
||||||
return sptr(AbstractGoal());
|
|
||||||
}
|
|
||||||
|
|
||||||
EGoals goalType;
|
EGoals goalType;
|
||||||
|
|
||||||
virtual std::string name() const;
|
virtual std::string toString() const;
|
||||||
|
|
||||||
bool invalid() const;
|
bool invalid() const;
|
||||||
|
|
||||||
///Visitor pattern
|
|
||||||
//TODO: make accept work for std::shared_ptr... somehow
|
|
||||||
virtual void accept(VCAI * ai); //unhandled goal will report standard error
|
|
||||||
|
|
||||||
virtual bool operator==(const AbstractGoal & g) const;
|
virtual bool operator==(const AbstractGoal & g) const;
|
||||||
|
|
||||||
bool operator!=(const AbstractGoal & g) const
|
bool operator!=(const AbstractGoal & g) const
|
||||||
@@ -192,4 +181,15 @@ namespace Goals
|
|||||||
h & bid;
|
h & bid;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DLL_EXPORT ITask
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
float priority;
|
||||||
|
|
||||||
|
///Visitor pattern
|
||||||
|
//TODO: make accept work for std::shared_ptr... somehow
|
||||||
|
virtual void accept(VCAI * ai) = 0; //unhandled goal will report standard error
|
||||||
|
virtual std::string toString() const = 0;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@@ -26,7 +26,7 @@ bool AdventureSpellCast::operator==(const AdventureSpellCast & other) const
|
|||||||
return hero.h == other.hero.h;
|
return hero.h == other.hero.h;
|
||||||
}
|
}
|
||||||
|
|
||||||
TSubgoal AdventureSpellCast::whatToDoToAchieve()
|
void AdventureSpellCast::accept(VCAI * ai)
|
||||||
{
|
{
|
||||||
if(!hero.validAndSet())
|
if(!hero.validAndSet())
|
||||||
throw cannotFulfillGoalException("Invalid hero!");
|
throw cannotFulfillGoalException("Invalid hero!");
|
||||||
@@ -47,11 +47,6 @@ TSubgoal AdventureSpellCast::whatToDoToAchieve()
|
|||||||
if(spellID == SpellID::TOWN_PORTAL && town && town->visitingHero)
|
if(spellID == SpellID::TOWN_PORTAL && town && town->visitingHero)
|
||||||
throw cannotFulfillGoalException("The town is already occupied by " + town->visitingHero->name);
|
throw cannotFulfillGoalException("The town is already occupied by " + town->visitingHero->name);
|
||||||
|
|
||||||
return iAmElementar();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdventureSpellCast::accept(VCAI * ai)
|
|
||||||
{
|
|
||||||
if(town && spellID == SpellID::TOWN_PORTAL)
|
if(town && spellID == SpellID::TOWN_PORTAL)
|
||||||
{
|
{
|
||||||
ai->selectedObject = town->id;
|
ai->selectedObject = town->id;
|
||||||
@@ -73,7 +68,7 @@ void AdventureSpellCast::accept(VCAI * ai)
|
|||||||
throw goalFulfilledException(sptr(*this));
|
throw goalFulfilledException(sptr(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AdventureSpellCast::name() const
|
std::string AdventureSpellCast::toString() const
|
||||||
{
|
{
|
||||||
return "AdventureSpellCast " + spellID.toSpell()->name;
|
return "AdventureSpellCast " + spellID.toSpell()->name;
|
||||||
}
|
}
|
||||||
|
@@ -13,31 +13,25 @@
|
|||||||
|
|
||||||
namespace Goals
|
namespace Goals
|
||||||
{
|
{
|
||||||
class DLL_EXPORT AdventureSpellCast : public CGoal<AdventureSpellCast>
|
class DLL_EXPORT AdventureSpellCast : public ElementarGoal<AdventureSpellCast>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SpellID spellID;
|
SpellID spellID;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AdventureSpellCast(HeroPtr hero, SpellID spellID)
|
AdventureSpellCast(HeroPtr hero, SpellID spellID)
|
||||||
: CGoal(Goals::ADVENTURE_SPELL_CAST), spellID(spellID)
|
: ElementarGoal(Goals::ADVENTURE_SPELL_CAST), spellID(spellID)
|
||||||
{
|
{
|
||||||
sethero(hero);
|
sethero(hero);
|
||||||
}
|
}
|
||||||
|
|
||||||
TGoalVec getAllPossibleSubgoals() override
|
|
||||||
{
|
|
||||||
return TGoalVec();
|
|
||||||
}
|
|
||||||
|
|
||||||
const CSpell * getSpell() const
|
const CSpell * getSpell() const
|
||||||
{
|
{
|
||||||
return spellID.toSpell();
|
return spellID.toSpell();
|
||||||
}
|
}
|
||||||
|
|
||||||
TSubgoal whatToDoToAchieve() override;
|
|
||||||
void accept(VCAI * ai) override;
|
void accept(VCAI * ai) override;
|
||||||
std::string name() const override;
|
std::string toString() const override;
|
||||||
virtual bool operator==(const AdventureSpellCast & other) const override;
|
virtual bool operator==(const AdventureSpellCast & other) const override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
#include "../AIhelper.h"
|
#include "../AIhelper.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 "../Behaviors/CaptureObjectsBehavior.h"
|
||||||
|
|
||||||
extern boost::thread_specific_ptr<CCallback> cb;
|
extern boost::thread_specific_ptr<CCallback> cb;
|
||||||
extern boost::thread_specific_ptr<VCAI> ai;
|
extern boost::thread_specific_ptr<VCAI> ai;
|
||||||
@@ -26,23 +27,23 @@ bool BuildBoat::operator==(const BuildBoat & other) const
|
|||||||
return shipyard->o->id == other.shipyard->o->id;
|
return shipyard->o->id == other.shipyard->o->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TSubgoal BuildBoat::whatToDoToAchieve()
|
TSubgoal BuildBoat::decomposeSingle() const
|
||||||
//{
|
{
|
||||||
// if(cb->getPlayerRelations(ai->playerID, shipyard->o->tempOwner) == PlayerRelations::ENEMIES)
|
if(cb->getPlayerRelations(ai->playerID, shipyard->o->tempOwner) == PlayerRelations::ENEMIES)
|
||||||
// {
|
{
|
||||||
// return fh->chooseSolution(ai->ah->howToVisitObj(shipyard->o));
|
return sptr(CaptureObjectsBehavior(shipyard->o));
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// if(shipyard->shipyardStatus() != IShipyard::GOOD)
|
if(shipyard->shipyardStatus() != IShipyard::GOOD)
|
||||||
// {
|
{
|
||||||
// throw cannotFulfillGoalException("Shipyard is busy.");
|
throw cannotFulfillGoalException("Shipyard is busy.");
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// TResources boatCost;
|
TResources boatCost;
|
||||||
// shipyard->getBoatCost(boatCost);
|
shipyard->getBoatCost(boatCost);
|
||||||
//
|
|
||||||
// return ai->ah->whatToDo(boatCost, this->iAmElementar());
|
return iAmElementar();
|
||||||
//}
|
}
|
||||||
|
|
||||||
void BuildBoat::accept(VCAI * ai)
|
void BuildBoat::accept(VCAI * ai)
|
||||||
{
|
{
|
||||||
@@ -75,7 +76,7 @@ void BuildBoat::accept(VCAI * ai)
|
|||||||
throw goalFulfilledException(sptr(*this));
|
throw goalFulfilledException(sptr(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string BuildBoat::name() const
|
std::string BuildBoat::toString() const
|
||||||
{
|
{
|
||||||
return "BuildBoat";
|
return "BuildBoat";
|
||||||
}
|
}
|
||||||
|
@@ -13,23 +13,20 @@
|
|||||||
|
|
||||||
namespace Goals
|
namespace Goals
|
||||||
{
|
{
|
||||||
class DLL_EXPORT BuildBoat : public CGoal<BuildBoat>
|
class DLL_EXPORT BuildBoat : public ElementarGoal<BuildBoat>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
const IShipyard * shipyard;
|
const IShipyard * shipyard;
|
||||||
|
TSubgoal decomposeSingle() const override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BuildBoat(const IShipyard * shipyard)
|
BuildBoat(const IShipyard * shipyard)
|
||||||
: CGoal(Goals::BUILD_BOAT), shipyard(shipyard)
|
: ElementarGoal(Goals::BUILD_BOAT), shipyard(shipyard)
|
||||||
{
|
{
|
||||||
priority = 0;
|
|
||||||
}
|
|
||||||
TGoalVec getAllPossibleSubgoals() override
|
|
||||||
{
|
|
||||||
return TGoalVec();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void accept(VCAI * ai) override;
|
void accept(VCAI * ai) override;
|
||||||
std::string name() const override;
|
std::string toString() const override;
|
||||||
virtual bool operator==(const BuildBoat & other) const override;
|
virtual bool operator==(const BuildBoat & other) const override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -29,7 +29,7 @@ bool BuildThis::operator==(const BuildThis & other) const
|
|||||||
return town == other.town && bid == other.bid;
|
return town == other.town && bid == other.bid;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string BuildThis::name() const
|
std::string BuildThis::toString() const
|
||||||
{
|
{
|
||||||
return "Build " + buildingInfo.name + "(" + std::to_string(bid) + ") in " + town->name;
|
return "Build " + buildingInfo.name + "(" + std::to_string(bid) + ") in " + town->name;
|
||||||
}
|
}
|
@@ -18,36 +18,36 @@ class FuzzyHelper;
|
|||||||
|
|
||||||
namespace Goals
|
namespace Goals
|
||||||
{
|
{
|
||||||
class DLL_EXPORT BuildThis : public CGoal<BuildThis>
|
class DLL_EXPORT BuildThis : public ElementarGoal<BuildThis>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BuildingInfo buildingInfo;
|
BuildingInfo buildingInfo;
|
||||||
TownDevelopmentInfo townInfo;
|
TownDevelopmentInfo townInfo;
|
||||||
|
|
||||||
BuildThis() //should be private, but unit test uses it
|
BuildThis() //should be private, but unit test uses it
|
||||||
: CGoal(Goals::BUILD_STRUCTURE)
|
: ElementarGoal(Goals::BUILD_STRUCTURE)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
BuildThis(const BuildingInfo & buildingInfo, const TownDevelopmentInfo & townInfo) //should be private, but unit test uses it
|
BuildThis(const BuildingInfo & buildingInfo, const TownDevelopmentInfo & townInfo) //should be private, but unit test uses it
|
||||||
: CGoal(Goals::BUILD_STRUCTURE), buildingInfo(buildingInfo), townInfo(townInfo)
|
: ElementarGoal(Goals::BUILD_STRUCTURE), buildingInfo(buildingInfo), townInfo(townInfo)
|
||||||
{
|
{
|
||||||
bid = buildingInfo.id;
|
bid = buildingInfo.id;
|
||||||
town = townInfo.town;
|
town = townInfo.town;
|
||||||
}
|
}
|
||||||
BuildThis(BuildingID Bid, const CGTownInstance * tid)
|
BuildThis(BuildingID Bid, const CGTownInstance * tid)
|
||||||
: CGoal(Goals::BUILD_STRUCTURE)
|
: ElementarGoal(Goals::BUILD_STRUCTURE)
|
||||||
{
|
{
|
||||||
bid = Bid;
|
bid = Bid;
|
||||||
town = tid;
|
town = tid;
|
||||||
priority = 1;
|
priority = 1;
|
||||||
}
|
}
|
||||||
BuildThis(BuildingID Bid)
|
BuildThis(BuildingID Bid)
|
||||||
: CGoal(Goals::BUILD_STRUCTURE)
|
: ElementarGoal(Goals::BUILD_STRUCTURE)
|
||||||
{
|
{
|
||||||
bid = Bid;
|
bid = Bid;
|
||||||
priority = 1;
|
priority = 1;
|
||||||
}
|
}
|
||||||
virtual bool operator==(const BuildThis & other) const override;
|
virtual bool operator==(const BuildThis & other) const override;
|
||||||
virtual std::string name() const override;
|
virtual std::string toString() const override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -25,7 +25,7 @@ bool BuyArmy::operator==(const BuyArmy & other) const
|
|||||||
return town == other.town && objid == other.objid;
|
return town == other.town && objid == other.objid;
|
||||||
}
|
}
|
||||||
|
|
||||||
TSubgoal BuyArmy::whatToDoToAchieve()
|
std::string BuyArmy::toString() const
|
||||||
{
|
{
|
||||||
return iAmElementar();
|
return "Buy army at " + town->name;
|
||||||
}
|
}
|
@@ -17,23 +17,24 @@ class FuzzyHelper;
|
|||||||
|
|
||||||
namespace Goals
|
namespace Goals
|
||||||
{
|
{
|
||||||
class DLL_EXPORT BuyArmy : public CGoal<BuyArmy>
|
class DLL_EXPORT BuyArmy : public ElementarGoal<BuyArmy>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
BuyArmy()
|
BuyArmy()
|
||||||
: CGoal(Goals::BUY_ARMY)
|
: ElementarGoal(Goals::BUY_ARMY)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
BuyArmy(const CGTownInstance * Town, int val)
|
BuyArmy(const CGTownInstance * Town, int val)
|
||||||
: CGoal(Goals::BUY_ARMY)
|
: ElementarGoal(Goals::BUY_ARMY)
|
||||||
{
|
{
|
||||||
town = Town; //where to buy this army
|
town = Town; //where to buy this army
|
||||||
value = val; //expressed in AI unit strength
|
value = val; //expressed in AI unit strength
|
||||||
priority = 3;//TODO: evaluate?
|
priority = 3;//TODO: evaluate?
|
||||||
}
|
}
|
||||||
|
|
||||||
TSubgoal whatToDoToAchieve() override;
|
|
||||||
virtual bool operator==(const BuyArmy & other) const override;
|
virtual bool operator==(const BuyArmy & other) const override;
|
||||||
|
|
||||||
|
virtual std::string toString() const override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -23,9 +23,8 @@ namespace Goals
|
|||||||
public:
|
public:
|
||||||
CGoal<T>(EGoals goal = INVALID) : AbstractGoal(goal)
|
CGoal<T>(EGoals goal = INVALID) : AbstractGoal(goal)
|
||||||
{
|
{
|
||||||
priority = 0;
|
|
||||||
isElementar = false;
|
isElementar = false;
|
||||||
isAbstract = false;
|
isAbstract = true;
|
||||||
value = 0;
|
value = 0;
|
||||||
aid = -1;
|
aid = -1;
|
||||||
objid = -1;
|
objid = -1;
|
||||||
@@ -36,7 +35,6 @@ namespace Goals
|
|||||||
|
|
||||||
OSETTER(bool, isElementar)
|
OSETTER(bool, isElementar)
|
||||||
OSETTER(bool, isAbstract)
|
OSETTER(bool, isAbstract)
|
||||||
OSETTER(float, priority)
|
|
||||||
OSETTER(int, value)
|
OSETTER(int, value)
|
||||||
OSETTER(int, resID)
|
OSETTER(int, resID)
|
||||||
OSETTER(int, objid)
|
OSETTER(int, objid)
|
||||||
@@ -46,11 +44,6 @@ namespace Goals
|
|||||||
OSETTER(CGTownInstance *, town)
|
OSETTER(CGTownInstance *, town)
|
||||||
OSETTER(int, bid)
|
OSETTER(int, bid)
|
||||||
|
|
||||||
void accept(VCAI * ai) override
|
|
||||||
{
|
|
||||||
ai->tryRealize(static_cast<T &>(*this)); //casting enforces template instantiation
|
|
||||||
}
|
|
||||||
|
|
||||||
CGoal<T> * clone() const override
|
CGoal<T> * clone() const override
|
||||||
{
|
{
|
||||||
return new T(static_cast<T const &>(*this)); //casting enforces template instantiation
|
return new T(static_cast<T const &>(*this)); //casting enforces template instantiation
|
||||||
@@ -80,5 +73,65 @@ namespace Goals
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual bool operator==(const T & other) const = 0;
|
virtual bool operator==(const T & other) const = 0;
|
||||||
|
|
||||||
|
virtual TGoalVec decompose() const override
|
||||||
|
{
|
||||||
|
return {decomposeSingle()};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual TSubgoal decomposeSingle() const
|
||||||
|
{
|
||||||
|
return sptr(Invalid());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T> class DLL_EXPORT ElementarGoal : public CGoal<T>, public ITask
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ElementarGoal<T>(EGoals goal = INVALID) : CGoal(goal)
|
||||||
|
{
|
||||||
|
priority = 0;
|
||||||
|
isElementar = true;
|
||||||
|
isAbstract = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
///Visitor pattern
|
||||||
|
//TODO: make accept work for std::shared_ptr... somehow
|
||||||
|
virtual void accept(VCAI * ai) override //unhandled goal will report standard error
|
||||||
|
{
|
||||||
|
ai->tryRealize(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
T & setpriority(float p)
|
||||||
|
{
|
||||||
|
priority = p;
|
||||||
|
|
||||||
|
return *((T *)this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class DLL_EXPORT Invalid : public ElementarGoal<Invalid>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Invalid()
|
||||||
|
: ElementarGoal(Goals::INVALID)
|
||||||
|
{
|
||||||
|
priority = -1;
|
||||||
|
}
|
||||||
|
TGoalVec decompose() const override
|
||||||
|
{
|
||||||
|
return TGoalVec();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool operator==(const Invalid & other) const override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string toString() const override
|
||||||
|
{
|
||||||
|
return "Invalid";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -29,10 +29,10 @@ bool CollectRes::operator==(const CollectRes & other) const
|
|||||||
return resID == other.resID;
|
return resID == other.resID;
|
||||||
}
|
}
|
||||||
|
|
||||||
TGoalVec CollectRes::getAllPossibleSubgoals()
|
//TGoalVec CollectRes::getAllPossibleSubgoals()
|
||||||
{
|
//{
|
||||||
TGoalVec ret;
|
// TGoalVec ret;
|
||||||
|
//
|
||||||
//auto givesResource = [this](const CGObjectInstance * obj) -> bool
|
//auto givesResource = [this](const CGObjectInstance * obj) -> bool
|
||||||
//{
|
//{
|
||||||
// //TODO: move this logic to object side
|
// //TODO: move this logic to object side
|
||||||
@@ -107,18 +107,18 @@ TGoalVec CollectRes::getAllPossibleSubgoals()
|
|||||||
// vstd::concatenate(ret, waysToGo);
|
// vstd::concatenate(ret, waysToGo);
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
return ret;
|
// return ret;
|
||||||
}
|
//}
|
||||||
|
|
||||||
TSubgoal CollectRes::whatToDoToAchieve()
|
//TSubgoal CollectRes::whatToDoToAchieve()
|
||||||
{
|
//{
|
||||||
auto goals = getAllPossibleSubgoals();
|
// auto goals = getAllPossibleSubgoals();
|
||||||
auto trade = whatToDoToTrade();
|
// auto trade = whatToDoToTrade();
|
||||||
if (!trade->invalid())
|
// if (!trade->invalid())
|
||||||
goals.push_back(trade);
|
// goals.push_back(trade);
|
||||||
|
//
|
||||||
return sptr(Invalid()); //we can always do that
|
// return sptr(Invalid()); //we can always do that
|
||||||
}
|
//}
|
||||||
|
|
||||||
TSubgoal CollectRes::whatToDoToTrade()
|
TSubgoal CollectRes::whatToDoToTrade()
|
||||||
{
|
{
|
||||||
|
@@ -29,10 +29,9 @@ namespace Goals
|
|||||||
{
|
{
|
||||||
resID = rid;
|
resID = rid;
|
||||||
value = val;
|
value = val;
|
||||||
priority = 2;
|
|
||||||
}
|
}
|
||||||
TGoalVec getAllPossibleSubgoals() override;
|
/*TGoalVec getAllPossibleSubgoals() override;
|
||||||
TSubgoal whatToDoToAchieve() override;
|
TSubgoal whatToDoToAchieve() override;*/
|
||||||
TSubgoal whatToDoToTrade();
|
TSubgoal whatToDoToTrade();
|
||||||
virtual bool operator==(const CollectRes & other) const override;
|
virtual bool operator==(const CollectRes & other) const override;
|
||||||
};
|
};
|
||||||
|
@@ -1,270 +0,0 @@
|
|||||||
/*
|
|
||||||
* CompleteQuest.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 "Goals.h"
|
|
||||||
#include "../VCAI.h"
|
|
||||||
#include "../FuzzyHelper.h"
|
|
||||||
#include "../AIhelper.h"
|
|
||||||
#include "../../../lib/mapping/CMap.h" //for victory conditions
|
|
||||||
#include "../../../lib/CPathfinder.h"
|
|
||||||
|
|
||||||
extern boost::thread_specific_ptr<CCallback> cb;
|
|
||||||
extern boost::thread_specific_ptr<VCAI> ai;
|
|
||||||
extern FuzzyHelper * fh;
|
|
||||||
|
|
||||||
using namespace Goals;
|
|
||||||
|
|
||||||
bool CompleteQuest::operator==(const CompleteQuest & other) const
|
|
||||||
{
|
|
||||||
return q.quest->qid == other.q.quest->qid;
|
|
||||||
}
|
|
||||||
|
|
||||||
TGoalVec CompleteQuest::getAllPossibleSubgoals()
|
|
||||||
{
|
|
||||||
TGoalVec solutions;
|
|
||||||
|
|
||||||
if(q.quest->missionType && q.quest->progress != CQuest::COMPLETE)
|
|
||||||
{
|
|
||||||
logAi->debug("Trying to realize quest: %s", questToString());
|
|
||||||
|
|
||||||
switch(q.quest->missionType)
|
|
||||||
{
|
|
||||||
case CQuest::MISSION_ART:
|
|
||||||
return missionArt();
|
|
||||||
|
|
||||||
case CQuest::MISSION_HERO:
|
|
||||||
return missionHero();
|
|
||||||
|
|
||||||
case CQuest::MISSION_ARMY:
|
|
||||||
return missionArmy();
|
|
||||||
|
|
||||||
case CQuest::MISSION_RESOURCES:
|
|
||||||
return missionResources();
|
|
||||||
|
|
||||||
case CQuest::MISSION_KILL_HERO:
|
|
||||||
case CQuest::MISSION_KILL_CREATURE:
|
|
||||||
return missionDestroyObj();
|
|
||||||
|
|
||||||
case CQuest::MISSION_PRIMARY_STAT:
|
|
||||||
return missionIncreasePrimaryStat();
|
|
||||||
|
|
||||||
case CQuest::MISSION_LEVEL:
|
|
||||||
return missionLevel();
|
|
||||||
|
|
||||||
case CQuest::MISSION_PLAYER:
|
|
||||||
if(ai->playerID.getNum() != q.quest->m13489val)
|
|
||||||
logAi->debug("Can't be player of color %d", q.quest->m13489val);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CQuest::MISSION_KEYMASTER:
|
|
||||||
return missionKeymaster();
|
|
||||||
|
|
||||||
} //end of switch
|
|
||||||
}
|
|
||||||
|
|
||||||
return TGoalVec();
|
|
||||||
}
|
|
||||||
|
|
||||||
TSubgoal CompleteQuest::whatToDoToAchieve()
|
|
||||||
{
|
|
||||||
if(q.quest->missionType == CQuest::MISSION_NONE)
|
|
||||||
{
|
|
||||||
throw cannotFulfillGoalException("Can not complete inactive quest");
|
|
||||||
}
|
|
||||||
|
|
||||||
TGoalVec solutions = getAllPossibleSubgoals();
|
|
||||||
|
|
||||||
throw cannotFulfillGoalException("Can not complete quest " + questToString());
|
|
||||||
/*
|
|
||||||
TSubgoal result = fh->chooseSolution(solutions);
|
|
||||||
|
|
||||||
logAi->trace(
|
|
||||||
"Returning %s, tile: %s, objid: %d, hero: %s",
|
|
||||||
result->name(),
|
|
||||||
result->tile.toString(),
|
|
||||||
result->objid,
|
|
||||||
result->hero.validAndSet() ? result->hero->name : "not specified");
|
|
||||||
|
|
||||||
return result;*/
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string CompleteQuest::name() const
|
|
||||||
{
|
|
||||||
return "CompleteQuest";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string CompleteQuest::questToString() const
|
|
||||||
{
|
|
||||||
if(q.quest->missionType == CQuest::MISSION_NONE)
|
|
||||||
return "inactive quest";
|
|
||||||
|
|
||||||
MetaString ms;
|
|
||||||
q.quest->getRolloverText(ms, false);
|
|
||||||
|
|
||||||
return ms.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
TGoalVec CompleteQuest::tryCompleteQuest() const
|
|
||||||
{
|
|
||||||
TGoalVec solutions;
|
|
||||||
|
|
||||||
auto heroes = cb->getHeroesInfo(); //TODO: choose best / free hero from among many possibilities?
|
|
||||||
|
|
||||||
for(auto hero : heroes)
|
|
||||||
{
|
|
||||||
if(q.quest->checkQuest(hero))
|
|
||||||
{
|
|
||||||
//vstd::concatenate(solutions, ai->ah->howToVisitObj(hero, ObjectIdRef(q.obj->id)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return solutions;
|
|
||||||
}
|
|
||||||
|
|
||||||
TGoalVec CompleteQuest::missionArt() const
|
|
||||||
{
|
|
||||||
TGoalVec solutions = tryCompleteQuest();
|
|
||||||
|
|
||||||
if(!solutions.empty())
|
|
||||||
return solutions;
|
|
||||||
|
|
||||||
for(auto art : q.quest->m5arts)
|
|
||||||
{
|
|
||||||
solutions.push_back(sptr(GetArtOfType(art))); //TODO: transport?
|
|
||||||
}
|
|
||||||
|
|
||||||
return solutions;
|
|
||||||
}
|
|
||||||
|
|
||||||
TGoalVec CompleteQuest::missionHero() const
|
|
||||||
{
|
|
||||||
TGoalVec solutions = tryCompleteQuest();
|
|
||||||
|
|
||||||
if(solutions.empty())
|
|
||||||
{
|
|
||||||
//rule of a thumb - quest heroes usually are locked in prisons
|
|
||||||
solutions.push_back(sptr(FindObj(Obj::PRISON)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return solutions;
|
|
||||||
}
|
|
||||||
|
|
||||||
TGoalVec CompleteQuest::missionArmy() const
|
|
||||||
{
|
|
||||||
TGoalVec solutions = tryCompleteQuest();
|
|
||||||
|
|
||||||
if(!solutions.empty())
|
|
||||||
return solutions;
|
|
||||||
|
|
||||||
for(auto creature : q.quest->m6creatures)
|
|
||||||
{
|
|
||||||
solutions.push_back(sptr(GatherTroops(creature.type->idNumber, creature.count)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return solutions;
|
|
||||||
}
|
|
||||||
|
|
||||||
TGoalVec CompleteQuest::missionIncreasePrimaryStat() const
|
|
||||||
{
|
|
||||||
TGoalVec solutions = tryCompleteQuest();
|
|
||||||
|
|
||||||
if(solutions.empty())
|
|
||||||
{
|
|
||||||
for(int i = 0; i < q.quest->m2stats.size(); ++i)
|
|
||||||
{
|
|
||||||
// TODO: library, school and other boost objects
|
|
||||||
logAi->debug("Don't know how to increase primary stat %d", i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return solutions;
|
|
||||||
}
|
|
||||||
|
|
||||||
TGoalVec CompleteQuest::missionLevel() const
|
|
||||||
{
|
|
||||||
TGoalVec solutions = tryCompleteQuest();
|
|
||||||
|
|
||||||
if(solutions.empty())
|
|
||||||
{
|
|
||||||
logAi->debug("Don't know how to reach hero level %d", q.quest->m13489val);
|
|
||||||
}
|
|
||||||
|
|
||||||
return solutions;
|
|
||||||
}
|
|
||||||
|
|
||||||
TGoalVec CompleteQuest::missionKeymaster() const
|
|
||||||
{
|
|
||||||
TGoalVec solutions = tryCompleteQuest();
|
|
||||||
|
|
||||||
if(solutions.empty())
|
|
||||||
{
|
|
||||||
solutions.push_back(sptr(Goals::FindObj(Obj::KEYMASTER, q.obj->subID)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return solutions;
|
|
||||||
}
|
|
||||||
|
|
||||||
TGoalVec CompleteQuest::missionResources() const
|
|
||||||
{
|
|
||||||
TGoalVec solutions;
|
|
||||||
|
|
||||||
auto heroes = cb->getHeroesInfo(); //TODO: choose best / free hero from among many possibilities?
|
|
||||||
|
|
||||||
if(heroes.size())
|
|
||||||
{
|
|
||||||
if(q.quest->checkQuest(heroes.front())) //it doesn't matter which hero it is
|
|
||||||
{
|
|
||||||
return solutions;// ai->ah->howToVisitObj(q.obj);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for(int i = 0; i < q.quest->m7resources.size(); ++i)
|
|
||||||
{
|
|
||||||
if(q.quest->m7resources[i])
|
|
||||||
solutions.push_back(sptr(CollectRes(i, q.quest->m7resources[i])));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
solutions.push_back(sptr(Goals::RecruitHero())); //FIXME: checkQuest requires any hero belonging to player :(
|
|
||||||
}
|
|
||||||
|
|
||||||
return solutions;
|
|
||||||
}
|
|
||||||
|
|
||||||
TGoalVec CompleteQuest::missionDestroyObj() const
|
|
||||||
{
|
|
||||||
TGoalVec solutions;
|
|
||||||
|
|
||||||
auto obj = cb->getObjByQuestIdentifier(q.quest->m13489val);
|
|
||||||
|
|
||||||
if(!obj)
|
|
||||||
return solutions;// ai->ah->howToVisitObj(q.obj);
|
|
||||||
|
|
||||||
if(obj->ID == Obj::HERO)
|
|
||||||
{
|
|
||||||
auto relations = cb->getPlayerRelations(ai->playerID, obj->tempOwner);
|
|
||||||
|
|
||||||
if(relations == PlayerRelations::SAME_PLAYER)
|
|
||||||
{
|
|
||||||
auto heroToProtect = cb->getHero(obj->id);
|
|
||||||
|
|
||||||
//solutions.push_back(sptr(GatherArmy().sethero(heroToProtect)));
|
|
||||||
}
|
|
||||||
else if(relations == PlayerRelations::ENEMIES)
|
|
||||||
{
|
|
||||||
//solutions = ai->ah->howToVisitObj(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return solutions;
|
|
||||||
}
|
|
@@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* CompleteQuest.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 "CGoal.h"
|
|
||||||
#include "../../../lib/VCMI_Lib.h"
|
|
||||||
|
|
||||||
namespace Goals
|
|
||||||
{
|
|
||||||
class DLL_EXPORT CompleteQuest : public CGoal<CompleteQuest>
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
const QuestInfo q;
|
|
||||||
|
|
||||||
public:
|
|
||||||
CompleteQuest(const QuestInfo quest)
|
|
||||||
: CGoal(Goals::COMPLETE_QUEST), q(quest)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
TGoalVec getAllPossibleSubgoals() override;
|
|
||||||
TSubgoal whatToDoToAchieve() override;
|
|
||||||
std::string name() const override;
|
|
||||||
virtual bool operator==(const CompleteQuest & other) const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
TGoalVec tryCompleteQuest() const;
|
|
||||||
TGoalVec missionArt() const;
|
|
||||||
TGoalVec missionHero() const;
|
|
||||||
TGoalVec missionArmy() const;
|
|
||||||
TGoalVec missionResources() const;
|
|
||||||
TGoalVec missionDestroyObj() const;
|
|
||||||
TGoalVec missionIncreasePrimaryStat() const;
|
|
||||||
TGoalVec missionLevel() const;
|
|
||||||
TGoalVec missionKeymaster() const;
|
|
||||||
std::string questToString() const;
|
|
||||||
};
|
|
||||||
}
|
|
@@ -24,16 +24,16 @@ bool DigAtTile::operator==(const DigAtTile & other) const
|
|||||||
{
|
{
|
||||||
return other.hero.h == hero.h && other.tile == tile;
|
return other.hero.h == hero.h && other.tile == tile;
|
||||||
}
|
}
|
||||||
|
//
|
||||||
TSubgoal DigAtTile::whatToDoToAchieve()
|
//TSubgoal DigAtTile::decomposeSingle() const
|
||||||
{
|
//{
|
||||||
const CGObjectInstance * firstObj = vstd::frontOrNull(cb->getVisitableObjs(tile));
|
// const CGObjectInstance * firstObj = vstd::frontOrNull(cb->getVisitableObjs(tile));
|
||||||
if(firstObj && firstObj->ID == Obj::HERO && firstObj->tempOwner == ai->playerID) //we have hero at dest
|
// if(firstObj && firstObj->ID == Obj::HERO && firstObj->tempOwner == ai->playerID) //we have hero at dest
|
||||||
{
|
// {
|
||||||
const CGHeroInstance * h = dynamic_cast<const CGHeroInstance *>(firstObj);
|
// const CGHeroInstance * h = dynamic_cast<const CGHeroInstance *>(firstObj);
|
||||||
sethero(h).setisElementar(true);
|
// sethero(h).setisElementar(true);
|
||||||
return sptr(*this);
|
// return sptr(*this);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
return sptr(VisitTile(tile));
|
// return sptr(VisitTile(tile));
|
||||||
}
|
//}
|
||||||
|
@@ -29,13 +29,10 @@ namespace Goals
|
|||||||
: CGoal(Goals::DIG_AT_TILE)
|
: CGoal(Goals::DIG_AT_TILE)
|
||||||
{
|
{
|
||||||
tile = Tile;
|
tile = Tile;
|
||||||
priority = 20;
|
|
||||||
}
|
}
|
||||||
TGoalVec getAllPossibleSubgoals() override
|
|
||||||
{
|
|
||||||
return TGoalVec();
|
|
||||||
}
|
|
||||||
TSubgoal whatToDoToAchieve() override;
|
|
||||||
virtual bool operator==(const DigAtTile & other) const override;
|
virtual bool operator==(const DigAtTile & other) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//TSubgoal decomposeSingle() const override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -26,14 +26,6 @@ bool DismissHero::operator==(const DismissHero & other) const
|
|||||||
return hero.h == other.hero.h;
|
return hero.h == other.hero.h;
|
||||||
}
|
}
|
||||||
|
|
||||||
TSubgoal DismissHero::whatToDoToAchieve()
|
|
||||||
{
|
|
||||||
if(!hero.validAndSet())
|
|
||||||
throw cannotFulfillGoalException("Invalid hero!");
|
|
||||||
|
|
||||||
return iAmElementar();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DismissHero::accept(VCAI * ai)
|
void DismissHero::accept(VCAI * ai)
|
||||||
{
|
{
|
||||||
if(!hero.validAndSet())
|
if(!hero.validAndSet())
|
||||||
@@ -44,7 +36,7 @@ void DismissHero::accept(VCAI * ai)
|
|||||||
throw goalFulfilledException(sptr(*this));
|
throw goalFulfilledException(sptr(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string DismissHero::name() const
|
std::string DismissHero::toString() const
|
||||||
{
|
{
|
||||||
return "DismissHero " + hero.name;
|
return "DismissHero " + hero.name;
|
||||||
}
|
}
|
||||||
|
@@ -13,23 +13,17 @@
|
|||||||
|
|
||||||
namespace Goals
|
namespace Goals
|
||||||
{
|
{
|
||||||
class DLL_EXPORT DismissHero : public CGoal<DismissHero>
|
class DLL_EXPORT DismissHero : public ElementarGoal<DismissHero>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DismissHero(HeroPtr hero)
|
DismissHero(HeroPtr hero)
|
||||||
: CGoal(Goals::DISMISS_HERO)
|
: ElementarGoal(Goals::DISMISS_HERO)
|
||||||
{
|
{
|
||||||
sethero(hero);
|
sethero(hero);
|
||||||
}
|
}
|
||||||
|
|
||||||
TGoalVec getAllPossibleSubgoals() override
|
|
||||||
{
|
|
||||||
return TGoalVec();
|
|
||||||
}
|
|
||||||
|
|
||||||
TSubgoal whatToDoToAchieve() override;
|
|
||||||
void accept(VCAI * ai) override;
|
void accept(VCAI * ai) override;
|
||||||
std::string name() const override;
|
std::string toString() const override;
|
||||||
virtual bool operator==(const DismissHero & other) const override;
|
virtual bool operator==(const DismissHero & other) const override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -27,11 +27,11 @@ ExchangeSwapTownHeroes::ExchangeSwapTownHeroes(
|
|||||||
const CGTownInstance * town,
|
const CGTownInstance * town,
|
||||||
const CGHeroInstance * garrisonHero,
|
const CGHeroInstance * garrisonHero,
|
||||||
HeroLockedReason lockingReason)
|
HeroLockedReason lockingReason)
|
||||||
:CGoal(Goals::EXCHANGE_SWAP_TOWN_HEROES), town(town), garrisonHero(garrisonHero), lockingReason(lockingReason)
|
:ElementarGoal(Goals::EXCHANGE_SWAP_TOWN_HEROES), town(town), garrisonHero(garrisonHero), lockingReason(lockingReason)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ExchangeSwapTownHeroes::name() const
|
std::string ExchangeSwapTownHeroes::toString() const
|
||||||
{
|
{
|
||||||
return "Exchange and swap heroes of " + town->name;
|
return "Exchange and swap heroes of " + town->name;
|
||||||
}
|
}
|
||||||
@@ -41,11 +41,6 @@ bool ExchangeSwapTownHeroes::operator==(const ExchangeSwapTownHeroes & other) co
|
|||||||
return town == other.town;
|
return town == other.town;
|
||||||
}
|
}
|
||||||
|
|
||||||
TSubgoal ExchangeSwapTownHeroes::whatToDoToAchieve()
|
|
||||||
{
|
|
||||||
return iAmElementar();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExchangeSwapTownHeroes::accept(VCAI * ai)
|
void ExchangeSwapTownHeroes::accept(VCAI * ai)
|
||||||
{
|
{
|
||||||
if(!garrisonHero)
|
if(!garrisonHero)
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
namespace Goals
|
namespace Goals
|
||||||
{
|
{
|
||||||
class DLL_EXPORT ExchangeSwapTownHeroes : public CGoal<ExchangeSwapTownHeroes>
|
class DLL_EXPORT ExchangeSwapTownHeroes : public ElementarGoal<ExchangeSwapTownHeroes>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
const CGTownInstance * town;
|
const CGTownInstance * town;
|
||||||
@@ -27,14 +27,8 @@ namespace Goals
|
|||||||
const CGHeroInstance * garrisonHero = nullptr,
|
const CGHeroInstance * garrisonHero = nullptr,
|
||||||
HeroLockedReason lockingReason = HeroLockedReason::NOT_LOCKED);
|
HeroLockedReason lockingReason = HeroLockedReason::NOT_LOCKED);
|
||||||
|
|
||||||
TGoalVec getAllPossibleSubgoals() override
|
|
||||||
{
|
|
||||||
return TGoalVec();
|
|
||||||
}
|
|
||||||
|
|
||||||
TSubgoal whatToDoToAchieve() override;
|
|
||||||
void accept(VCAI * ai) override;
|
void accept(VCAI * ai) override;
|
||||||
std::string name() const override;
|
std::string toString() const override;
|
||||||
virtual bool operator==(const ExchangeSwapTownHeroes & other) const override;
|
virtual bool operator==(const ExchangeSwapTownHeroes & other) const override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -24,23 +24,12 @@ extern FuzzyHelper * fh;
|
|||||||
using namespace Goals;
|
using namespace Goals;
|
||||||
|
|
||||||
ExecuteHeroChain::ExecuteHeroChain(const AIPath & path, const CGObjectInstance * obj)
|
ExecuteHeroChain::ExecuteHeroChain(const AIPath & path, const CGObjectInstance * obj)
|
||||||
:CGoal(Goals::EXECUTE_HERO_CHAIN), chainPath(path)
|
:ElementarGoal(Goals::EXECUTE_HERO_CHAIN), chainPath(path)
|
||||||
{
|
{
|
||||||
evaluationContext.danger = path.getTotalDanger();
|
|
||||||
evaluationContext.movementCost = path.movementCost();
|
|
||||||
evaluationContext.armyLoss = path.getTotalArmyLoss();
|
|
||||||
evaluationContext.heroStrength = path.getHeroStrength();
|
|
||||||
|
|
||||||
hero = path.targetHero;
|
hero = path.targetHero;
|
||||||
tile = path.targetTile();
|
tile = path.targetTile();
|
||||||
|
|
||||||
for(auto & node : path.nodes)
|
|
||||||
{
|
|
||||||
auto role = ai->ah->getHeroRole(node.targetHero);
|
|
||||||
|
|
||||||
evaluationContext.movementCostByRole[role] += node.cost;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(obj)
|
if(obj)
|
||||||
{
|
{
|
||||||
objid = obj->id.getNum();
|
objid = obj->id.getNum();
|
||||||
@@ -57,15 +46,12 @@ bool ExecuteHeroChain::operator==(const ExecuteHeroChain & other) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TSubgoal ExecuteHeroChain::whatToDoToAchieve()
|
|
||||||
{
|
|
||||||
return iAmElementar();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExecuteHeroChain::accept(VCAI * ai)
|
void ExecuteHeroChain::accept(VCAI * ai)
|
||||||
{
|
{
|
||||||
logAi->debug("Executing hero chain towards %s. Path %s", targetName, chainPath.toString());
|
logAi->debug("Executing hero chain towards %s. Path %s", targetName, chainPath.toString());
|
||||||
|
|
||||||
|
ai->nullkiller->setActive(chainPath.targetHero, tile);
|
||||||
|
|
||||||
std::set<int> blockedIndexes;
|
std::set<int> blockedIndexes;
|
||||||
|
|
||||||
for(int i = chainPath.nodes.size() - 1; i >= 0; i--)
|
for(int i = chainPath.nodes.size() - 1; i >= 0; i--)
|
||||||
@@ -89,7 +75,6 @@ void ExecuteHeroChain::accept(VCAI * ai)
|
|||||||
{
|
{
|
||||||
if(hero->movement)
|
if(hero->movement)
|
||||||
{
|
{
|
||||||
|
|
||||||
ai->nullkiller->setActive(hero, node.coord);
|
ai->nullkiller->setActive(hero, node.coord);
|
||||||
|
|
||||||
if(node.specialAction)
|
if(node.specialAction)
|
||||||
@@ -98,6 +83,8 @@ void ExecuteHeroChain::accept(VCAI * ai)
|
|||||||
{
|
{
|
||||||
auto specialGoal = node.specialAction->whatToDo(hero);
|
auto specialGoal = node.specialAction->whatToDo(hero);
|
||||||
|
|
||||||
|
if(!specialGoal->isElementar)
|
||||||
|
|
||||||
specialGoal->accept(ai);
|
specialGoal->accept(ai);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -135,7 +122,10 @@ void ExecuteHeroChain::accept(VCAI * ai)
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Goals::VisitTile(node.coord).sethero(hero).accept(ai);
|
if(moveHeroToTile(hero, node.coord))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch(cannotFulfillGoalException)
|
catch(cannotFulfillGoalException)
|
||||||
{
|
{
|
||||||
@@ -195,7 +185,19 @@ void ExecuteHeroChain::accept(VCAI * ai)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ExecuteHeroChain::name() const
|
std::string ExecuteHeroChain::toString() const
|
||||||
{
|
{
|
||||||
return "ExecuteHeroChain " + targetName + " by " + chainPath.targetHero->name;
|
return "ExecuteHeroChain " + targetName + " by " + chainPath.targetHero->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ExecuteHeroChain::moveHeroToTile(const CGHeroInstance * hero, const int3 & tile)
|
||||||
|
{
|
||||||
|
if(g.tile == g.hero->visitablePos() && cb->getVisitableObjs(g.hero->visitablePos()).size() < 2)
|
||||||
|
{
|
||||||
|
logAi->warn("Why do I want to move hero %s to tile %s? Already standing on that tile! ", g.hero->name, g.tile.toString());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ai->moveHeroToTile(tile, hero);
|
||||||
|
}
|
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
namespace Goals
|
namespace Goals
|
||||||
{
|
{
|
||||||
class DLL_EXPORT ExecuteHeroChain : public CGoal<ExecuteHeroChain>
|
class DLL_EXPORT ExecuteHeroChain : public ElementarGoal<ExecuteHeroChain>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
AIPath chainPath;
|
AIPath chainPath;
|
||||||
@@ -22,15 +22,13 @@ namespace Goals
|
|||||||
public:
|
public:
|
||||||
ExecuteHeroChain(const AIPath & path, const CGObjectInstance * obj = nullptr);
|
ExecuteHeroChain(const AIPath & path, const CGObjectInstance * obj = nullptr);
|
||||||
|
|
||||||
TGoalVec getAllPossibleSubgoals() override
|
|
||||||
{
|
|
||||||
return TGoalVec();
|
|
||||||
}
|
|
||||||
|
|
||||||
TSubgoal whatToDoToAchieve() override;
|
|
||||||
void accept(VCAI * ai) override;
|
void accept(VCAI * ai) override;
|
||||||
std::string name() const override;
|
std::string toString() const override;
|
||||||
virtual bool operator==(const ExecuteHeroChain & other) const override;
|
virtual bool operator==(const ExecuteHeroChain & other) const override;
|
||||||
const AIPath & getPath() const { return chainPath; }
|
const AIPath & getPath() const { return chainPath; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool moveHeroToTile(const CGHeroInstance * hero, const int3 & tile);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -23,32 +23,32 @@ bool FindObj::operator==(const FindObj & other) const
|
|||||||
{
|
{
|
||||||
return other.hero.h == hero.h && other.objid == objid;
|
return other.hero.h == hero.h && other.objid == objid;
|
||||||
}
|
}
|
||||||
|
//
|
||||||
TSubgoal FindObj::whatToDoToAchieve()
|
//TSubgoal FindObj::whatToDoToAchieve()
|
||||||
{
|
//{
|
||||||
const CGObjectInstance * o = nullptr;
|
// const CGObjectInstance * o = nullptr;
|
||||||
if(resID > -1) //specified
|
// if(resID > -1) //specified
|
||||||
{
|
// {
|
||||||
for(const CGObjectInstance * obj : ai->visitableObjs)
|
// for(const CGObjectInstance * obj : ai->visitableObjs)
|
||||||
{
|
// {
|
||||||
if(obj->ID == objid && obj->subID == resID)
|
// if(obj->ID == objid && obj->subID == resID)
|
||||||
{
|
// {
|
||||||
o = obj;
|
// o = obj;
|
||||||
break; //TODO: consider multiple objects and choose best
|
// break; //TODO: consider multiple objects and choose best
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
else
|
// else
|
||||||
{
|
// {
|
||||||
for(const CGObjectInstance * obj : ai->visitableObjs)
|
// for(const CGObjectInstance * obj : ai->visitableObjs)
|
||||||
{
|
// {
|
||||||
if(obj->ID == objid)
|
// if(obj->ID == objid)
|
||||||
{
|
// {
|
||||||
o = obj;
|
// o = obj;
|
||||||
break; //TODO: consider multiple objects and choose best
|
// break; //TODO: consider multiple objects and choose best
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
if(o && ai->isAccessible(o->pos)) //we don't use isAccessibleForHero as we don't know which hero it is
|
// if(o && ai->isAccessible(o->pos)) //we don't use isAccessibleForHero as we don't know which hero it is
|
||||||
return sptr(VisitObj(o->id.getNum()));
|
// return sptr(VisitObj(o->id.getNum()));
|
||||||
}
|
//}
|
@@ -27,20 +27,16 @@ namespace Goals
|
|||||||
{
|
{
|
||||||
objid = ID;
|
objid = ID;
|
||||||
resID = -1; //subid unspecified
|
resID = -1; //subid unspecified
|
||||||
priority = 1;
|
|
||||||
}
|
}
|
||||||
FindObj(int ID, int subID)
|
FindObj(int ID, int subID)
|
||||||
: CGoal(Goals::FIND_OBJ)
|
: CGoal(Goals::FIND_OBJ)
|
||||||
{
|
{
|
||||||
objid = ID;
|
objid = ID;
|
||||||
resID = subID;
|
resID = subID;
|
||||||
priority = 1;
|
|
||||||
}
|
}
|
||||||
TGoalVec getAllPossibleSubgoals() override
|
|
||||||
{
|
|
||||||
return TGoalVec();
|
|
||||||
}
|
|
||||||
TSubgoal whatToDoToAchieve() override;
|
|
||||||
virtual bool operator==(const FindObj & other) const override;
|
virtual bool operator==(const FindObj & other) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//TSubgoal decomposeSingle() const override;
|
||||||
};
|
};
|
||||||
}
|
}
|
@@ -43,30 +43,30 @@ int GatherTroops::getCreaturesCount(const CArmedInstance * army)
|
|||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
//TSubgoal GatherTroops::whatToDoToAchieve()
|
||||||
|
//{
|
||||||
|
// logAi->trace("Entering GatherTroops::whatToDoToAchieve");
|
||||||
|
//
|
||||||
|
// auto heroes = cb->getHeroesInfo(true);
|
||||||
|
//
|
||||||
|
// for(auto hero : heroes)
|
||||||
|
// {
|
||||||
|
// if(getCreaturesCount(hero) >= this->value)
|
||||||
|
// {
|
||||||
|
// logAi->trace("Completing GATHER_TROOPS by hero %s", hero->name);
|
||||||
|
//
|
||||||
|
// throw goalFulfilledException(sptr(*this));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return sptr(Invalid());
|
||||||
|
//}
|
||||||
|
|
||||||
TSubgoal GatherTroops::whatToDoToAchieve()
|
//
|
||||||
{
|
//TGoalVec GatherTroops::getAllPossibleSubgoals()
|
||||||
logAi->trace("Entering GatherTroops::whatToDoToAchieve");
|
//{
|
||||||
|
// TGoalVec solutions;
|
||||||
auto heroes = cb->getHeroesInfo(true);
|
|
||||||
|
|
||||||
for(auto hero : heroes)
|
|
||||||
{
|
|
||||||
if(getCreaturesCount(hero) >= this->value)
|
|
||||||
{
|
|
||||||
logAi->trace("Completing GATHER_TROOPS by hero %s", hero->name);
|
|
||||||
|
|
||||||
throw goalFulfilledException(sptr(*this));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sptr(Invalid());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TGoalVec GatherTroops::getAllPossibleSubgoals()
|
|
||||||
{
|
|
||||||
TGoalVec solutions;
|
|
||||||
|
|
||||||
//for(const CGTownInstance * t : cb->getTownsInfo())
|
//for(const CGTownInstance * t : cb->getTownsInfo())
|
||||||
//{
|
//{
|
||||||
@@ -136,6 +136,6 @@ TGoalVec GatherTroops::getAllPossibleSubgoals()
|
|||||||
// return goal->hero && !goal->hero->getSlotFor(creID).validSlot() && !goal->hero->getFreeSlot().validSlot();
|
// return goal->hero && !goal->hero->getSlotFor(creID).validSlot() && !goal->hero->getFreeSlot().validSlot();
|
||||||
//});
|
//});
|
||||||
|
|
||||||
return solutions;
|
// return solutions;
|
||||||
//TODO: exchange troops between heroes
|
// //TODO: exchange troops between heroes
|
||||||
}
|
//}
|
||||||
|
@@ -23,17 +23,13 @@ namespace Goals
|
|||||||
GatherTroops()
|
GatherTroops()
|
||||||
: CGoal(Goals::GATHER_TROOPS)
|
: CGoal(Goals::GATHER_TROOPS)
|
||||||
{
|
{
|
||||||
priority = 2;
|
|
||||||
}
|
}
|
||||||
GatherTroops(int type, int val)
|
GatherTroops(int type, int val)
|
||||||
: CGoal(Goals::GATHER_TROOPS)
|
: CGoal(Goals::GATHER_TROOPS)
|
||||||
{
|
{
|
||||||
objid = type;
|
objid = type;
|
||||||
value = val;
|
value = val;
|
||||||
priority = 2;
|
|
||||||
}
|
}
|
||||||
TGoalVec getAllPossibleSubgoals() override;
|
|
||||||
TSubgoal whatToDoToAchieve() override;
|
|
||||||
virtual bool operator==(const GatherTroops & other) const override;
|
virtual bool operator==(const GatherTroops & other) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -24,8 +24,8 @@ bool GetArtOfType::operator==(const GetArtOfType & other) const
|
|||||||
{
|
{
|
||||||
return other.hero.h == hero.h && other.objid == objid;
|
return other.hero.h == hero.h && other.objid == objid;
|
||||||
}
|
}
|
||||||
|
//
|
||||||
TSubgoal GetArtOfType::whatToDoToAchieve()
|
//TSubgoal GetArtOfType::whatToDoToAchieve()
|
||||||
{
|
//{
|
||||||
return sptr(FindObj(Obj::ARTIFACT, aid));
|
// return sptr(FindObj(Obj::ARTIFACT, aid));
|
||||||
}
|
//}
|
@@ -28,13 +28,7 @@ namespace Goals
|
|||||||
: CGoal(Goals::GET_ART_TYPE)
|
: CGoal(Goals::GET_ART_TYPE)
|
||||||
{
|
{
|
||||||
aid = type;
|
aid = type;
|
||||||
priority = 2;
|
|
||||||
}
|
}
|
||||||
TGoalVec getAllPossibleSubgoals() override
|
|
||||||
{
|
|
||||||
return TGoalVec();
|
|
||||||
}
|
|
||||||
TSubgoal whatToDoToAchieve() override;
|
|
||||||
virtual bool operator==(const GetArtOfType & other) const override;
|
virtual bool operator==(const GetArtOfType & other) const override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -13,10 +13,6 @@
|
|||||||
#include "Invalid.h"
|
#include "Invalid.h"
|
||||||
#include "BuildBoat.h"
|
#include "BuildBoat.h"
|
||||||
#include "BuildThis.h"
|
#include "BuildThis.h"
|
||||||
#include "Win.h"
|
|
||||||
#include "VisitObj.h"
|
|
||||||
#include "VisitTile.h"
|
|
||||||
#include "VisitHero.h"
|
|
||||||
#include "BuyArmy.h"
|
#include "BuyArmy.h"
|
||||||
#include "GatherTroops.h"
|
#include "GatherTroops.h"
|
||||||
#include "Trade.h"
|
#include "Trade.h"
|
||||||
@@ -25,5 +21,4 @@
|
|||||||
#include "GetArtOfType.h"
|
#include "GetArtOfType.h"
|
||||||
#include "DigAtTile.h"
|
#include "DigAtTile.h"
|
||||||
#include "FindObj.h"
|
#include "FindObj.h"
|
||||||
#include "CompleteQuest.h"
|
|
||||||
#include "AdventureSpellCast.h"
|
#include "AdventureSpellCast.h"
|
@@ -16,26 +16,4 @@ class VCAI;
|
|||||||
|
|
||||||
namespace Goals
|
namespace Goals
|
||||||
{
|
{
|
||||||
class DLL_EXPORT Invalid : public CGoal<Invalid>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Invalid()
|
|
||||||
: CGoal(Goals::INVALID)
|
|
||||||
{
|
|
||||||
priority = -1e10;
|
|
||||||
}
|
|
||||||
TGoalVec getAllPossibleSubgoals() override
|
|
||||||
{
|
|
||||||
return TGoalVec();
|
|
||||||
}
|
|
||||||
TSubgoal whatToDoToAchieve() override
|
|
||||||
{
|
|
||||||
return iAmElementar();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool operator==(const Invalid & other) const override
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
@@ -23,3 +23,8 @@ extern boost::thread_specific_ptr<VCAI> ai;
|
|||||||
extern FuzzyHelper * fh;
|
extern FuzzyHelper * fh;
|
||||||
|
|
||||||
using namespace Goals;
|
using namespace Goals;
|
||||||
|
|
||||||
|
std::string RecruitHero::toString() const
|
||||||
|
{
|
||||||
|
return "Recruit hero at " + town->name;
|
||||||
|
}
|
@@ -17,18 +17,27 @@ class FuzzyHelper;
|
|||||||
|
|
||||||
namespace Goals
|
namespace Goals
|
||||||
{
|
{
|
||||||
class DLL_EXPORT RecruitHero : public CGoal<RecruitHero>
|
class DLL_EXPORT RecruitHero : public ElementarGoal<RecruitHero>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RecruitHero()
|
RecruitHero(const CGTownInstance * townWithTavern, const CGHeroInstance * heroToBuy)
|
||||||
: CGoal(Goals::RECRUIT_HERO)
|
: RecruitHero(townWithTavern)
|
||||||
|
{
|
||||||
|
objid = heroToBuy->id.getNum();
|
||||||
|
}
|
||||||
|
|
||||||
|
RecruitHero(const CGTownInstance * townWithTavern)
|
||||||
|
: ElementarGoal(Goals::RECRUIT_HERO)
|
||||||
{
|
{
|
||||||
priority = 1;
|
priority = 1;
|
||||||
|
town = townWithTavern;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool operator==(const RecruitHero & other) const override
|
virtual bool operator==(const RecruitHero & other) const override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual std::string toString() const override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -16,8 +16,3 @@ bool Trade::operator==(const Trade & other) const
|
|||||||
{
|
{
|
||||||
return resID == other.resID;
|
return resID == other.resID;
|
||||||
}
|
}
|
||||||
|
|
||||||
TSubgoal Trade::whatToDoToAchieve()
|
|
||||||
{
|
|
||||||
return iAmElementar();
|
|
||||||
}
|
|
||||||
|
@@ -30,9 +30,7 @@ namespace Goals
|
|||||||
resID = rid;
|
resID = rid;
|
||||||
value = val;
|
value = val;
|
||||||
objid = Objid;
|
objid = Objid;
|
||||||
priority = 3; //trading is instant, but picking resources is free
|
|
||||||
}
|
}
|
||||||
TSubgoal whatToDoToAchieve() override;
|
|
||||||
virtual bool operator==(const Trade & other) const override;
|
virtual bool operator==(const Trade & other) const override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -9,6 +9,8 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#error not used
|
||||||
|
|
||||||
#include "CGoal.h"
|
#include "CGoal.h"
|
||||||
|
|
||||||
struct HeroPtr;
|
struct HeroPtr;
|
||||||
@@ -28,7 +30,6 @@ namespace Goals
|
|||||||
: CGoal(Goals::VISIT_HERO)
|
: CGoal(Goals::VISIT_HERO)
|
||||||
{
|
{
|
||||||
objid = hid;
|
objid = hid;
|
||||||
priority = 4;
|
|
||||||
}
|
}
|
||||||
virtual bool operator==(const VisitHero & other) const override;
|
virtual bool operator==(const VisitHero & other) const override;
|
||||||
};
|
};
|
||||||
|
@@ -38,6 +38,4 @@ VisitObj::VisitObj(int Objid)
|
|||||||
tile = obj->visitablePos();
|
tile = obj->visitablePos();
|
||||||
else
|
else
|
||||||
logAi->error("VisitObj constructed with invalid object instance %d", Objid);
|
logAi->error("VisitObj constructed with invalid object instance %d", Objid);
|
||||||
|
|
||||||
priority = 3;
|
|
||||||
}
|
}
|
@@ -9,6 +9,8 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#error not used
|
||||||
|
|
||||||
#include "CGoal.h"
|
#include "CGoal.h"
|
||||||
|
|
||||||
struct HeroPtr;
|
struct HeroPtr;
|
||||||
|
@@ -9,6 +9,8 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#error not used
|
||||||
|
|
||||||
#include "CGoal.h"
|
#include "CGoal.h"
|
||||||
|
|
||||||
struct HeroPtr;
|
struct HeroPtr;
|
||||||
@@ -27,7 +29,6 @@ namespace Goals
|
|||||||
: CGoal(Goals::VISIT_TILE)
|
: CGoal(Goals::VISIT_TILE)
|
||||||
{
|
{
|
||||||
tile = Tile;
|
tile = Tile;
|
||||||
priority = 5;
|
|
||||||
}
|
}
|
||||||
virtual bool operator==(const VisitTile & other) const override;
|
virtual bool operator==(const VisitTile & other) const override;
|
||||||
};
|
};
|
||||||
|
@@ -299,15 +299,6 @@ void VCAI::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, Q
|
|||||||
|
|
||||||
requestActionASAP([=]()
|
requestActionASAP([=]()
|
||||||
{
|
{
|
||||||
float goalpriority1 = 0, goalpriority2 = 0;
|
|
||||||
|
|
||||||
auto firstGoal = getGoal(firstHero);
|
|
||||||
if(firstGoal->goalType == Goals::GATHER_ARMY)
|
|
||||||
goalpriority1 = firstGoal->priority;
|
|
||||||
auto secondGoal = getGoal(secondHero);
|
|
||||||
if(secondGoal->goalType == Goals::GATHER_ARMY)
|
|
||||||
goalpriority2 = secondGoal->priority;
|
|
||||||
|
|
||||||
auto transferFrom2to1 = [this](const CGHeroInstance * h1, const CGHeroInstance * h2) -> void
|
auto transferFrom2to1 = [this](const CGHeroInstance * h1, const CGHeroInstance * h2) -> void
|
||||||
{
|
{
|
||||||
this->pickBestCreatures(h1, h2);
|
this->pickBestCreatures(h1, h2);
|
||||||
@@ -320,28 +311,13 @@ void VCAI::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, Q
|
|||||||
{
|
{
|
||||||
logAi->debug("Heroes owned by different players. Do not exchange army or artifacts.");
|
logAi->debug("Heroes owned by different players. Do not exchange army or artifacts.");
|
||||||
}
|
}
|
||||||
else if(nullkiller)
|
else
|
||||||
{
|
{
|
||||||
if(nullkiller->isActive(firstHero))
|
if(nullkiller->isActive(firstHero))
|
||||||
transferFrom2to1(secondHero, firstHero);
|
transferFrom2to1(secondHero, firstHero);
|
||||||
else
|
else
|
||||||
transferFrom2to1(firstHero, secondHero);
|
transferFrom2to1(firstHero, secondHero);
|
||||||
}
|
}
|
||||||
else if(goalpriority1 > goalpriority2)
|
|
||||||
{
|
|
||||||
transferFrom2to1(firstHero, secondHero);
|
|
||||||
}
|
|
||||||
else if(goalpriority1 < goalpriority2)
|
|
||||||
{
|
|
||||||
transferFrom2to1(secondHero, firstHero);
|
|
||||||
}
|
|
||||||
else //regular criteria
|
|
||||||
{
|
|
||||||
if(firstHero->getFightingStrength() > secondHero->getFightingStrength() && ah->canGetArmy(firstHero, secondHero))
|
|
||||||
transferFrom2to1(firstHero, secondHero);
|
|
||||||
else if(ah->canGetArmy(secondHero, firstHero))
|
|
||||||
transferFrom2to1(secondHero, firstHero);
|
|
||||||
}
|
|
||||||
|
|
||||||
answerQuery(query, 0);
|
answerQuery(query, 0);
|
||||||
});
|
});
|
||||||
@@ -1403,7 +1379,7 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
|
|||||||
if(path.nodes.empty())
|
if(path.nodes.empty())
|
||||||
{
|
{
|
||||||
logAi->error("Hero %s cannot reach %s.", h->name, dst.toString());
|
logAi->error("Hero %s cannot reach %s.", h->name, dst.toString());
|
||||||
throw goalFulfilledException(sptr(Goals::VisitTile(dst).sethero(h)));
|
return true;
|
||||||
}
|
}
|
||||||
int i = path.nodes.size() - 1;
|
int i = path.nodes.size() - 1;
|
||||||
|
|
||||||
@@ -1568,11 +1544,6 @@ void VCAI::buildStructure(const CGTownInstance * t, BuildingID building)
|
|||||||
cb->buildBuilding(t, building); //just do this;
|
cb->buildBuilding(t, building); //just do this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VCAI::tryRealize(Goals::Explore & g)
|
|
||||||
{
|
|
||||||
throw cannotFulfillGoalException("EXPLORE is not an elementar goal!");
|
|
||||||
}
|
|
||||||
|
|
||||||
void VCAI::tryRealize(Goals::RecruitHero & g)
|
void VCAI::tryRealize(Goals::RecruitHero & g)
|
||||||
{
|
{
|
||||||
const CGTownInstance * t = g.town;
|
const CGTownInstance * t = g.town;
|
||||||
@@ -1591,56 +1562,6 @@ void VCAI::tryRealize(Goals::RecruitHero & g)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VCAI::tryRealize(Goals::VisitTile & g)
|
|
||||||
{
|
|
||||||
if(!g.hero->movement)
|
|
||||||
throw cannotFulfillGoalException("Cannot visit tile: hero is out of MPs!");
|
|
||||||
if(g.tile == g.hero->visitablePos() && cb->getVisitableObjs(g.hero->visitablePos()).size() < 2)
|
|
||||||
{
|
|
||||||
logAi->warn("Why do I want to move hero %s to tile %s? Already standing on that tile! ", g.hero->name, g.tile.toString());
|
|
||||||
throw goalFulfilledException(sptr(g));
|
|
||||||
}
|
|
||||||
if(ai->moveHeroToTile(g.tile, g.hero.get()))
|
|
||||||
{
|
|
||||||
throw goalFulfilledException(sptr(g));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VCAI::tryRealize(Goals::VisitObj & g)
|
|
||||||
{
|
|
||||||
auto position = g.tile;
|
|
||||||
if(!g.hero->movement)
|
|
||||||
throw cannotFulfillGoalException("Cannot visit object: hero is out of MPs!");
|
|
||||||
if(position == g.hero->visitablePos() && cb->getVisitableObjs(g.hero->visitablePos()).size() < 2)
|
|
||||||
{
|
|
||||||
logAi->warn("Why do I want to move hero %s to tile %s? Already standing on that tile! ", g.hero->name, g.tile.toString());
|
|
||||||
throw goalFulfilledException(sptr(g));
|
|
||||||
}
|
|
||||||
if(ai->moveHeroToTile(position, g.hero.get()))
|
|
||||||
{
|
|
||||||
throw goalFulfilledException(sptr(g));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VCAI::tryRealize(Goals::VisitHero & g)
|
|
||||||
{
|
|
||||||
if(!g.hero->movement)
|
|
||||||
throw cannotFulfillGoalException("Cannot visit target hero: hero is out of MPs!");
|
|
||||||
|
|
||||||
const CGObjectInstance * obj = cb->getObj(ObjectInstanceID(g.objid));
|
|
||||||
if(obj)
|
|
||||||
{
|
|
||||||
if(ai->moveHeroToTile(obj->visitablePos(), g.hero.get()))
|
|
||||||
{
|
|
||||||
throw goalFulfilledException(sptr(g));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw cannotFulfillGoalException("Cannot visit hero: object not found!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VCAI::tryRealize(Goals::BuildThis & g)
|
void VCAI::tryRealize(Goals::BuildThis & g)
|
||||||
{
|
{
|
||||||
auto b = BuildingID(g.bid);
|
auto b = BuildingID(g.bid);
|
||||||
@@ -1773,7 +1694,7 @@ void VCAI::tryRealize(Goals::Invalid & g)
|
|||||||
|
|
||||||
void VCAI::tryRealize(Goals::AbstractGoal & g)
|
void VCAI::tryRealize(Goals::AbstractGoal & g)
|
||||||
{
|
{
|
||||||
logAi->debug("Attempting realizing goal with code %s", g.name());
|
logAi->debug("Attempting realizing goal with code %s", g.toString());
|
||||||
throw cannotFulfillGoalException("Unknown type of goal !");
|
throw cannotFulfillGoalException("Unknown type of goal !");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1786,42 +1707,6 @@ const CGTownInstance * VCAI::findTownWithTavern() const
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Goals::TSubgoal VCAI::getGoal(HeroPtr h) const
|
|
||||||
{
|
|
||||||
auto it = lockedHeroes.find(h);
|
|
||||||
if(it != lockedHeroes.end())
|
|
||||||
return it->second;
|
|
||||||
else
|
|
||||||
return sptr(Goals::Invalid());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<HeroPtr> VCAI::getUnblockedHeroes() const
|
|
||||||
{
|
|
||||||
std::vector<HeroPtr> ret;
|
|
||||||
for(auto h : cb->getHeroesInfo())
|
|
||||||
{
|
|
||||||
//&& !vstd::contains(lockedHeroes, h)
|
|
||||||
//at this point we assume heroes exhausted their locked goals
|
|
||||||
if(canAct(h))
|
|
||||||
ret.push_back(h);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VCAI::canAct(HeroPtr h) const
|
|
||||||
{
|
|
||||||
auto mission = lockedHeroes.find(h);
|
|
||||||
if(mission != lockedHeroes.end())
|
|
||||||
{
|
|
||||||
//FIXME: I'm afraid there can be other conditions when heroes can act but not move :?
|
|
||||||
if(mission->second->goalType == Goals::DIG_AT_TILE && !mission->second->isElementar)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return h->movement;
|
|
||||||
}
|
|
||||||
|
|
||||||
HeroPtr VCAI::primaryHero() const
|
HeroPtr VCAI::primaryHero() const
|
||||||
{
|
{
|
||||||
auto hs = cb->getHeroesInfo();
|
auto hs = cb->getHeroesInfo();
|
||||||
@@ -1876,7 +1761,7 @@ void VCAI::recruitHero(const CGTownInstance * t, bool throwing)
|
|||||||
if(t->visitingHero)
|
if(t->visitingHero)
|
||||||
moveHeroToTile(t->visitablePos(), t->visitingHero.get());
|
moveHeroToTile(t->visitablePos(), t->visitingHero.get());
|
||||||
|
|
||||||
throw goalFulfilledException(sptr(Goals::RecruitHero().settown(t)));
|
throw goalFulfilledException(sptr(Goals::RecruitHero(t)));
|
||||||
}
|
}
|
||||||
else if(throwing)
|
else if(throwing)
|
||||||
{
|
{
|
||||||
|
@@ -117,11 +117,7 @@ public:
|
|||||||
virtual ~VCAI();
|
virtual ~VCAI();
|
||||||
|
|
||||||
//TODO: use only smart pointers?
|
//TODO: use only smart pointers?
|
||||||
void tryRealize(Goals::Explore & g);
|
|
||||||
void tryRealize(Goals::RecruitHero & g);
|
void tryRealize(Goals::RecruitHero & g);
|
||||||
void tryRealize(Goals::VisitTile & g);
|
|
||||||
void tryRealize(Goals::VisitObj & g);
|
|
||||||
void tryRealize(Goals::VisitHero & g);
|
|
||||||
void tryRealize(Goals::BuildThis & g);
|
void tryRealize(Goals::BuildThis & g);
|
||||||
void tryRealize(Goals::DigAtTile & g);
|
void tryRealize(Goals::DigAtTile & g);
|
||||||
void tryRealize(Goals::Trade & g);
|
void tryRealize(Goals::Trade & g);
|
||||||
@@ -241,9 +237,6 @@ public:
|
|||||||
const CGTownInstance * findTownWithTavern() const;
|
const CGTownInstance * findTownWithTavern() const;
|
||||||
bool canRecruitAnyHero(const CGTownInstance * t = NULL) const;
|
bool canRecruitAnyHero(const CGTownInstance * t = NULL) const;
|
||||||
|
|
||||||
Goals::TSubgoal getGoal(HeroPtr h) const;
|
|
||||||
bool canAct(HeroPtr h) const;
|
|
||||||
std::vector<HeroPtr> getUnblockedHeroes() const;
|
|
||||||
std::vector<HeroPtr> getMyHeroes() const;
|
std::vector<HeroPtr> getMyHeroes() const;
|
||||||
HeroPtr primaryHero() const;
|
HeroPtr primaryHero() const;
|
||||||
|
|
||||||
@@ -374,7 +367,7 @@ public:
|
|||||||
explicit goalFulfilledException(Goals::TSubgoal Goal)
|
explicit goalFulfilledException(Goals::TSubgoal Goal)
|
||||||
: goal(Goal)
|
: goal(Goal)
|
||||||
{
|
{
|
||||||
msg = goal->name();
|
msg = goal->toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~goalFulfilledException() throw ()
|
virtual ~goalFulfilledException() throw ()
|
||||||
|
Reference in New Issue
Block a user