mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Nullkiller: rough implementation of capture objects and recruit hero behaviors
This commit is contained in:
parent
9c85e26d3c
commit
eee145c486
@ -123,14 +123,14 @@ TResource AIhelper::allGold() const
|
||||
return resourceManager->allGold();
|
||||
}
|
||||
|
||||
Goals::TGoalVec AIhelper::howToVisitTile(const int3 & tile) const
|
||||
Goals::TGoalVec AIhelper::howToVisitTile(const int3 & tile, bool allowGatherArmy) const
|
||||
{
|
||||
return pathfindingManager->howToVisitTile(tile);
|
||||
return pathfindingManager->howToVisitTile(tile, allowGatherArmy);
|
||||
}
|
||||
|
||||
Goals::TGoalVec AIhelper::howToVisitObj(ObjectIdRef obj) const
|
||||
Goals::TGoalVec AIhelper::howToVisitObj(ObjectIdRef obj, bool allowGatherArmy) const
|
||||
{
|
||||
return pathfindingManager->howToVisitObj(obj);
|
||||
return pathfindingManager->howToVisitObj(obj, allowGatherArmy);
|
||||
}
|
||||
|
||||
Goals::TGoalVec AIhelper::howToVisitTile(const HeroPtr & hero, const int3 & tile, bool allowGatherArmy) const
|
||||
|
@ -57,8 +57,8 @@ public:
|
||||
|
||||
Goals::TGoalVec howToVisitTile(const HeroPtr & hero, const int3 & tile, bool allowGatherArmy = true) const override;
|
||||
Goals::TGoalVec howToVisitObj(const HeroPtr & hero, ObjectIdRef obj, bool allowGatherArmy = true) const override;
|
||||
Goals::TGoalVec howToVisitTile(const int3 & tile) const override;
|
||||
Goals::TGoalVec howToVisitObj(ObjectIdRef obj) const override;
|
||||
Goals::TGoalVec howToVisitTile(const int3 & tile, bool allowGatherArmy = true) const override;
|
||||
Goals::TGoalVec howToVisitObj(ObjectIdRef obj, bool allowGatherArmy = true) const override;
|
||||
std::vector<AIPath> getPathsToTile(const HeroPtr & hero, const int3 & tile) const override;
|
||||
void updatePaths(std::vector<HeroPtr> heroes) override;
|
||||
void updatePaths(const HeroPtr & hero) override;
|
||||
|
@ -4,10 +4,7 @@
|
||||
|
||||
class Behavior
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
class CaptureObjectBehavior : public Behavior
|
||||
{
|
||||
|
||||
public:
|
||||
virtual Goals::TGoalVec getTasks() = 0;
|
||||
virtual std::string toString() const = 0;
|
||||
};
|
116
AI/Nullkiller/Behaviors/CaptureObjectsBehavior.cpp
Normal file
116
AI/Nullkiller/Behaviors/CaptureObjectsBehavior.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Goals.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 "../VCAI.h"
|
||||
#include "../AIhelper.h"
|
||||
#include "CaptureObjectsBehavior.h"
|
||||
#include "../AIUtility.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 CaptureObjectsBehavior::toString() const {
|
||||
return "Capture objects";
|
||||
}
|
||||
|
||||
Goals::TGoalVec CaptureObjectsBehavior::getTasks() {
|
||||
Goals::TGoalVec tasks;
|
||||
|
||||
auto captureObjects = [&](std::vector<const CGObjectInstance*> objs) -> void {
|
||||
if (objs.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto objToVisit : objs) {
|
||||
if(!shouldVisitObject(objToVisit))
|
||||
continue;
|
||||
|
||||
const int3 pos = objToVisit->visitablePos();
|
||||
logAi->trace("considering object %s %s", objToVisit->getObjectName(), pos.toString());
|
||||
|
||||
Goals::TGoalVec waysToVisitObj = ai->ah->howToVisitObj(objToVisit, false);
|
||||
|
||||
vstd::erase_if(waysToVisitObj, [objToVisit](Goals::TSubgoal goal) -> bool
|
||||
{
|
||||
return !goal->hero.validAndSet()
|
||||
|| !shouldVisit(goal->hero, objToVisit)
|
||||
|| goal->evaluationContext.danger * 1.5 > goal->hero->getTotalStrength();
|
||||
});
|
||||
|
||||
if(waysToVisitObj.empty())
|
||||
continue;
|
||||
|
||||
Goals::TSubgoal closestWay = *vstd::minElementByFun(waysToVisitObj, [](Goals::TSubgoal goal) -> float {
|
||||
return goal->evaluationContext.movementCost;
|
||||
});
|
||||
|
||||
for(Goals::TSubgoal way : waysToVisitObj)
|
||||
{
|
||||
if(!way->hero->movement)
|
||||
continue;
|
||||
|
||||
way->accept(fh);
|
||||
|
||||
auto closestWayRatio = way->evaluationContext.movementCost / closestWay->evaluationContext.movementCost;
|
||||
way->setpriority(way->priority / closestWayRatio);
|
||||
|
||||
tasks.push_back(way);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (specificObjects) {
|
||||
captureObjects(objectsToCapture);
|
||||
}
|
||||
else {
|
||||
captureObjects(std::vector<const CGObjectInstance*>(ai->visitableObjs.begin(), ai->visitableObjs.end()));
|
||||
}
|
||||
|
||||
return tasks;
|
||||
}
|
||||
|
||||
bool CaptureObjectsBehavior::shouldVisitObject(ObjectIdRef obj) const
|
||||
{
|
||||
const CGObjectInstance* objInstance = obj;
|
||||
|
||||
if (!objInstance || objectTypes.size() && !vstd::contains(objectTypes, objInstance->ID.num)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!objInstance || objectSubTypes.size() && !vstd::contains(objectSubTypes, objInstance->subID)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int3 pos = objInstance->visitablePos();
|
||||
|
||||
if (vstd::contains(ai->alreadyVisited, objInstance)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto playerRelations = cb->getPlayerRelations(ai->playerID, objInstance->tempOwner);
|
||||
if (playerRelations != PlayerRelations::ENEMIES && !isWeeklyRevisitable(objInstance)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//it may be hero visiting this obj
|
||||
//we don't try visiting object on which allied or owned hero stands
|
||||
// -> it will just trigger exchange windows and AI will be confused that obj behind doesn't get visited
|
||||
const CGObjectInstance * topObj = cb->getTopObj(obj->visitablePos());
|
||||
|
||||
if (topObj->ID == Obj::HERO && cb->getPlayerRelations(ai->playerID, topObj->tempOwner) != PlayerRelations::ENEMIES)
|
||||
return false;
|
||||
else
|
||||
return true; //all of the following is met
|
||||
}
|
60
AI/Nullkiller/Behaviors/CaptureObjectsBehavior.h
Normal file
60
AI/Nullkiller/Behaviors/CaptureObjectsBehavior.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Goals.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 "Behavior.h"
|
||||
#include "../AIUtility.h"
|
||||
|
||||
class CaptureObjectsBehavior : public Behavior {
|
||||
private:
|
||||
std::vector<int> objectTypes;
|
||||
std::vector<int> objectSubTypes;
|
||||
std::vector<const CGObjectInstance *> objectsToCapture;
|
||||
bool specificObjects;
|
||||
public:
|
||||
CaptureObjectsBehavior()
|
||||
{
|
||||
objectTypes = std::vector<int>();
|
||||
specificObjects = false;
|
||||
}
|
||||
|
||||
CaptureObjectsBehavior(std::vector<const CGObjectInstance *> objectsToCapture)
|
||||
{
|
||||
this->objectsToCapture = objectsToCapture;
|
||||
specificObjects = true;
|
||||
}
|
||||
|
||||
CaptureObjectsBehavior(const CGObjectInstance * objectToCapture)
|
||||
{
|
||||
objectsToCapture = std::vector<const CGObjectInstance *>();
|
||||
objectsToCapture.push_back(objectToCapture);
|
||||
specificObjects = true;
|
||||
}
|
||||
|
||||
virtual Goals::TGoalVec getTasks() override;
|
||||
virtual std::string toString() const override;
|
||||
|
||||
CaptureObjectsBehavior & ofType(int type) {
|
||||
objectTypes.push_back(type);
|
||||
|
||||
return *this;
|
||||
}
|
||||
CaptureObjectsBehavior & ofType(int type, int subType) {
|
||||
objectTypes.push_back(type);
|
||||
objectSubTypes.push_back(subType);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
bool shouldVisitObject(ObjectIdRef obj) const;
|
||||
};
|
||||
|
45
AI/Nullkiller/Behaviors/RecruitHeroBehavior.cpp
Normal file
45
AI/Nullkiller/Behaviors/RecruitHeroBehavior.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Goals.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 "RecruitHeroBehavior.h"
|
||||
#include "../VCAI.h"
|
||||
#include "../AIhelper.h"
|
||||
#include "../AIUtility.h"
|
||||
#include "../Goals/RecruitHero.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 RecruitHeroBehavior::toString() const
|
||||
{
|
||||
return "Recruit hero";
|
||||
}
|
||||
|
||||
Goals::TGoalVec RecruitHeroBehavior::getTasks()
|
||||
{
|
||||
Goals::TGoalVec tasks;
|
||||
|
||||
if(ai->canRecruitAnyHero())
|
||||
{
|
||||
if(cb->getDate(Date::DAY) == 1
|
||||
|| cb->getHeroesInfo().size() < cb->getTownsInfo().size() + 1
|
||||
|| cb->getResourceAmount(Res::GOLD) > 10000)
|
||||
{
|
||||
tasks.push_back(Goals::sptr(Goals::RecruitHero()));
|
||||
}
|
||||
}
|
||||
|
||||
return tasks;
|
||||
}
|
26
AI/Nullkiller/Behaviors/RecruitHeroBehavior.h
Normal file
26
AI/Nullkiller/Behaviors/RecruitHeroBehavior.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Goals.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 "Behavior.h"
|
||||
#include "../AIUtility.h"
|
||||
|
||||
class RecruitHeroBehavior : public Behavior
|
||||
{
|
||||
public:
|
||||
RecruitHeroBehavior()
|
||||
{
|
||||
}
|
||||
|
||||
virtual Goals::TGoalVec getTasks() override;
|
||||
virtual std::string toString() const override;
|
||||
};
|
||||
|
@ -54,6 +54,8 @@ set(VCAI_SRCS
|
||||
Goals/CompleteQuest.cpp
|
||||
Engine/Nullkiller.cpp
|
||||
Behaviors/Behavior.cpp
|
||||
Behaviors/CaptureObjectsBehavior.cpp
|
||||
Behaviors/RecruitHeroBehavior.cpp
|
||||
main.cpp
|
||||
VCAI.cpp
|
||||
)
|
||||
@ -111,6 +113,8 @@ set(VCAI_HEADERS
|
||||
Goals/Goals.h
|
||||
Engine/Nullkiller.h
|
||||
Behaviors/Behavior.h
|
||||
Behaviors/CaptureObjectsBehavior.h
|
||||
Behaviors/RecruitHeroBehavior.h
|
||||
VCAI.h
|
||||
)
|
||||
|
||||
|
@ -1,8 +1,71 @@
|
||||
#include "StdInc.h"
|
||||
#include "Nullkiller.h"
|
||||
#include "../VCAI.h"
|
||||
#include "../Behaviors/CaptureObjectsBehavior.h"
|
||||
#include "../Behaviors/RecruitHeroBehavior.h"
|
||||
#include "../Goals/Invalid.h"
|
||||
|
||||
extern boost::thread_specific_ptr<CCallback> cb;
|
||||
extern boost::thread_specific_ptr<VCAI> ai;
|
||||
|
||||
Goals::TSubgoal choseBestTask(Goals::TGoalVec tasks)
|
||||
{
|
||||
Goals::TSubgoal bestTask = *vstd::maxElementByFun(tasks, [](Goals::TSubgoal goal) -> float
|
||||
{
|
||||
return goal->priority;
|
||||
});
|
||||
|
||||
return bestTask;
|
||||
}
|
||||
|
||||
Goals::TSubgoal choseBestTask(Behavior & behavior)
|
||||
{
|
||||
auto tasks = behavior.getTasks();
|
||||
|
||||
if(tasks.empty())
|
||||
{
|
||||
logAi->trace("Behavior %s found no tasks", behavior.toString());
|
||||
|
||||
return Goals::sptr(Goals::Invalid());
|
||||
}
|
||||
|
||||
return choseBestTask(tasks);
|
||||
}
|
||||
|
||||
void Nullkiller::makeTurn()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
Goals::TGoalVec bestTasks = {
|
||||
choseBestTask(CaptureObjectsBehavior()),
|
||||
choseBestTask(RecruitHeroBehavior())
|
||||
};
|
||||
|
||||
Goals::TSubgoal bestTask = choseBestTask(bestTasks);
|
||||
|
||||
if(bestTask->invalid())
|
||||
{
|
||||
logAi->trace("No goals found. Ending turn.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
logAi->debug("Trying to realize %s (value %2.3f)", bestTask->name(), bestTask->priority);
|
||||
|
||||
try
|
||||
{
|
||||
bestTask->accept(ai.get());
|
||||
}
|
||||
catch(goalFulfilledException &)
|
||||
{
|
||||
logAi->trace(bestTask->completeMessage());
|
||||
}
|
||||
catch(std::exception & e)
|
||||
{
|
||||
logAi->debug("Failed to realize subgoal of type %s, I will stop.", bestTask->name());
|
||||
logAi->debug("The error message was: %s", e.what());
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
@ -32,7 +32,7 @@ void PathfindingManager::setAI(VCAI * AI)
|
||||
ai = AI;
|
||||
}
|
||||
|
||||
Goals::TGoalVec PathfindingManager::howToVisitTile(const int3 & tile) const
|
||||
Goals::TGoalVec PathfindingManager::howToVisitTile(const int3 & tile, bool allowGatherArmy) const
|
||||
{
|
||||
Goals::TGoalVec result;
|
||||
|
||||
@ -41,13 +41,13 @@ Goals::TGoalVec PathfindingManager::howToVisitTile(const int3 & tile) const
|
||||
|
||||
for(auto hero : heroes)
|
||||
{
|
||||
vstd::concatenate(result, howToVisitTile(hero, tile));
|
||||
vstd::concatenate(result, howToVisitTile(hero, tile, allowGatherArmy));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Goals::TGoalVec PathfindingManager::howToVisitObj(ObjectIdRef obj) const
|
||||
Goals::TGoalVec PathfindingManager::howToVisitObj(ObjectIdRef obj, bool allowGatherArmy) const
|
||||
{
|
||||
Goals::TGoalVec result;
|
||||
|
||||
@ -56,7 +56,7 @@ Goals::TGoalVec PathfindingManager::howToVisitObj(ObjectIdRef obj) const
|
||||
|
||||
for(auto hero : heroes)
|
||||
{
|
||||
vstd::concatenate(result, howToVisitObj(hero, obj));
|
||||
vstd::concatenate(result, howToVisitObj(hero, obj, allowGatherArmy));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -24,8 +24,8 @@ public:
|
||||
virtual void updatePaths(const HeroPtr & hero) = 0;
|
||||
virtual Goals::TGoalVec howToVisitTile(const HeroPtr & hero, const int3 & tile, bool allowGatherArmy = true) const = 0;
|
||||
virtual Goals::TGoalVec howToVisitObj(const HeroPtr & hero, ObjectIdRef obj, bool allowGatherArmy = true) const = 0;
|
||||
virtual Goals::TGoalVec howToVisitTile(const int3 & tile) const = 0;
|
||||
virtual Goals::TGoalVec howToVisitObj(ObjectIdRef obj) const = 0;
|
||||
virtual Goals::TGoalVec howToVisitTile(const int3 & tile, bool allowGatherArmy = true) const = 0;
|
||||
virtual Goals::TGoalVec howToVisitObj(ObjectIdRef obj, bool allowGatherArmy = true) const = 0;
|
||||
virtual std::vector<AIPath> getPathsToTile(const HeroPtr & hero, const int3 & tile) const = 0;
|
||||
};
|
||||
|
||||
@ -44,8 +44,8 @@ public:
|
||||
|
||||
Goals::TGoalVec howToVisitTile(const HeroPtr & hero, const int3 & tile, bool allowGatherArmy = true) const override;
|
||||
Goals::TGoalVec howToVisitObj(const HeroPtr & hero, ObjectIdRef obj, bool allowGatherArmy = true) const override;
|
||||
Goals::TGoalVec howToVisitTile(const int3 & tile) const override;
|
||||
Goals::TGoalVec howToVisitObj(ObjectIdRef obj) const override;
|
||||
Goals::TGoalVec howToVisitTile(const int3 & tile, bool allowGatherArmy = true) const override;
|
||||
Goals::TGoalVec howToVisitObj(ObjectIdRef obj, bool allowGatherArmy = true) const override;
|
||||
std::vector<AIPath> getPathsToTile(const HeroPtr & hero, const int3 & tile) const override;
|
||||
void updatePaths(std::vector<HeroPtr> heroes) override;
|
||||
void updatePaths(const HeroPtr & hero) override;
|
||||
|
Loading…
Reference in New Issue
Block a user