Explorar o código

Nullkiller: fix/refactor temporary bonus nodes, fix gather army quest completion

Andrii Danylchenko %!s(int64=4) %!d(string=hai) anos
pai
achega
d47564955e

+ 0 - 1
AI/Nullkiller/AIUtility.cpp

@@ -407,7 +407,6 @@ bool shouldVisit(const Nullkiller * ai, const CGHeroInstance * h, const CGObject
 	case Obj::BORDERGUARD: //open borderguard if possible
 		return (dynamic_cast<const CGKeys *>(obj))->wasMyColorVisited(ai->playerID);
 	case Obj::SEER_HUT:
-	case Obj::QUEST_GUARD:
 	{
 		for(auto q : ai->cb->getMyQuests())
 		{

+ 1 - 1
AI/Nullkiller/Analyzers/ArmyManager.cpp

@@ -85,8 +85,8 @@ class TemporaryArmy : public CArmedInstance
 public:
 	void armyChanged() override {}
 	TemporaryArmy()
+		:CArmedInstance(true)
 	{
-		CBonusSystemNode::isHypotheticNode = true;
 	}
 };
 

+ 5 - 8
AI/Nullkiller/Goals/CompleteQuest.cpp

@@ -162,17 +162,14 @@ TGoalVec CompleteQuest::missionHero() const
 
 TGoalVec CompleteQuest::missionArmy() const
 {
-	TGoalVec solutions = tryCompleteQuest();
+	auto paths = ai->nullkiller->pathfinder->getPathInfo(q.obj->visitablePos());
 
-	if(!solutions.empty())
-		return solutions;
-	/*
-	for(auto creature : q.quest->m6creatures)
+	vstd::erase_if(paths, [&](const AIPath & path) -> bool
 	{
-		solutions.push_back(sptr(GatherTroops(creature.type->idNumber, creature.count)));
-	}*/
+		return !CQuest::checkMissionArmy(q.quest, path.heroArmy);
+	});
 
-	return solutions;
+	return CaptureObjectsBehavior::getVisitGoals(paths, q.obj);
 }
 
 TGoalVec CompleteQuest::missionIncreasePrimaryStat() const

+ 1 - 2
AI/Nullkiller/Pathfinding/Actors.h

@@ -29,9 +29,8 @@ public:
 	virtual bool needsLastStack() const override;
 	std::shared_ptr<SpecialAction> getActorAction() const;
 
-	HeroExchangeArmy() : CArmedInstance(), armyCost(), requireBuyArmy(false)
+	HeroExchangeArmy() : CArmedInstance(true), armyCost(), requireBuyArmy(false)
 	{
-		CBonusSystemNode::isHypotheticNode = true;
 	}
 };
 

+ 2 - 4
lib/CCreatureSet.cpp

@@ -536,21 +536,19 @@ CStackInstance::CStackInstance()
 }
 
 CStackInstance::CStackInstance(CreatureID id, TQuantity Count, bool isHypothetic)
-	: armyObj(_armyObj)
+	: CBonusSystemNode(isHypothetic), armyObj(_armyObj)
 {
 	init();
 	setType(id);
 	count = Count;
-	CBonusSystemNode::isHypotheticNode = isHypothetic;
 }
 
 CStackInstance::CStackInstance(const CCreature *cre, TQuantity Count, bool isHypothetic)
-	: armyObj(_armyObj)
+	: CBonusSystemNode(isHypothetic), armyObj(_armyObj)
 {
 	init();
 	setType(cre);
 	count = Count;
-	CBonusSystemNode::isHypotheticNode = isHypothetic;
 }
 
 void CStackInstance::init()

+ 13 - 5
lib/HeroBonus.cpp

@@ -989,12 +989,17 @@ std::shared_ptr<Bonus> CBonusSystemNode::update(const std::shared_ptr<Bonus> & b
 }
 
 CBonusSystemNode::CBonusSystemNode()
+	:CBonusSystemNode(false)
+{
+}
+
+CBonusSystemNode::CBonusSystemNode(bool isHypotetic)
 	: bonuses(true),
 	exportedBonuses(true),
 	nodeType(UNKNOWN),
 	cachedLast(0),
 	sync(),
-	isHypotheticNode(false)
+	isHypotheticNode(isHypotetic)
 {
 }
 
@@ -1015,17 +1020,20 @@ CBonusSystemNode::CBonusSystemNode(CBonusSystemNode && other):
 	description(other.description),
 	cachedLast(0),
 	sync(),
-	isHypotheticNode(false)
+	isHypotheticNode(other.isHypotheticNode)
 {
 	std::swap(parents, other.parents);
 	std::swap(children, other.children);
 
 	//fixing bonus tree without recalculation
 
-	for(CBonusSystemNode * n : parents)
+	if(!isHypothetic())
 	{
-		n->children -= &other;
-		n->children.push_back(this);
+		for(CBonusSystemNode * n : parents)
+		{
+			n->children -= &other;
+			n->children.push_back(this);
+		}
 	}
 
 	for(CBonusSystemNode * n : children)

+ 2 - 3
lib/HeroBonus.h

@@ -751,6 +751,7 @@ private:
 
 	ENodeTypes nodeType;
 	std::string description;
+	bool isHypotheticNode;
 
 	static const bool cachingEnabled;
 	mutable BonusList cachedBonuses;
@@ -768,11 +769,9 @@ private:
 	TConstBonusListPtr getAllBonusesWithoutCaching(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = nullptr) const;
 	std::shared_ptr<Bonus> update(const std::shared_ptr<Bonus> & b) const;
 
-protected:
-	bool isHypotheticNode;
-
 public:
 	explicit CBonusSystemNode();
+	explicit CBonusSystemNode(bool isHypotetic);
 	explicit CBonusSystemNode(ENodeTypes NodeType);
 	CBonusSystemNode(CBonusSystemNode && other);
 	virtual ~CBonusSystemNode();

+ 6 - 1
lib/mapObjects/CArmedInstance.cpp

@@ -40,7 +40,12 @@ void CArmedInstance::randomizeArmy(int type)
 CSelector CArmedInstance::nonEvilAlignmentMixSelector = Selector::type()(Bonus::NONEVIL_ALIGNMENT_MIX);
 
 CArmedInstance::CArmedInstance()
-	:nonEvilAlignmentMix(this, nonEvilAlignmentMixSelector)
+	:CArmedInstance(false)
+{
+}
+
+CArmedInstance::CArmedInstance(bool isHypotetic)
+	:CBonusSystemNode(isHypotetic), nonEvilAlignmentMix(this, nonEvilAlignmentMixSelector)
 {
 	battle = nullptr;
 }

+ 1 - 0
lib/mapObjects/CArmedInstance.h

@@ -36,6 +36,7 @@ public:
 	//////////////////////////////////////////////////////////////////////////
 
 	CArmedInstance();
+	CArmedInstance(bool isHypotetic);
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{

+ 28 - 23
lib/mapObjects/CQuest.cpp

@@ -60,6 +60,33 @@ static std::string & visitedTxt(const bool visited)
 	return VLC->generaltexth->allTexts[id];
 }
 
+bool CQuest::checkMissionArmy(const CQuest * q, const CCreatureSet * army)
+{
+	std::vector<CStackBasicDescriptor>::const_iterator cre;
+	TSlots::const_iterator it;
+	ui32 count;
+	ui32 slotsCount = 0;
+	bool hasExtraCreatures = false;
+	for(cre = q->m6creatures.begin(); cre != q->m6creatures.end(); ++cre)
+	{
+		for(count = 0, it = army->Slots().begin(); it != army->Slots().end(); ++it)
+		{
+			if(it->second->type == cre->type)
+			{
+				count += it->second->count;
+				slotsCount++;
+			}
+		}
+
+		if((TQuantity)count < cre->count) //not enough creatures of this kind
+			return false;
+
+		hasExtraCreatures |= (TQuantity)count > cre->count;
+	}
+
+	return hasExtraCreatures || slotsCount < army->Slots().size();
+}
+
 bool CQuest::checkQuest(const CGHeroInstance * h) const
 {
 	switch (missionType)
@@ -91,29 +118,7 @@ bool CQuest::checkQuest(const CGHeroInstance * h) const
 			}
 			return true;
 		case MISSION_ARMY:
-			{
-				std::vector<CStackBasicDescriptor>::const_iterator cre;
-				TSlots::const_iterator it;
-				ui32 count;
-				ui32 slotsCount = 0;
-				bool hasExtraCreatures = false;
-				for(cre = m6creatures.begin(); cre != m6creatures.end(); ++cre)
-				{
-					for(count = 0, it = h->Slots().begin(); it !=  h->Slots().end(); ++it)
-					{
-						if(it->second->type == cre->type)
-						{
-							count += it->second->count;
-							slotsCount++;
-						}
-					}
-					if((TQuantity)count < cre->count) //not enough creatures of this kind
-						return false;
-
-					hasExtraCreatures |= (TQuantity)count > cre->count;
-				}
-				return hasExtraCreatures || slotsCount < h->Slots().size();
-			}
+			return checkMissionArmy(this, h);
 		case MISSION_RESOURCES:
 			for(Res::ERes i = Res::WOOD; i <= Res::GOLD; vstd::advance(i, +1)) //including Mithril ?
 			{	//Quest has no direct access to callback

+ 1 - 0
lib/mapObjects/CQuest.h

@@ -52,6 +52,7 @@ public:
 	CQuest();
 	virtual ~CQuest(){};
 
+	static bool checkMissionArmy(const CQuest * q, const CCreatureSet * army);
 	virtual bool checkQuest (const CGHeroInstance * h) const; //determines whether the quest is complete or not
 	virtual void getVisitText (MetaString &text, std::vector<Component> &components, bool isCustom, bool FirstVisit, const CGHeroInstance * h = nullptr) const;
 	virtual void getCompletionText (MetaString &text, std::vector<Component> &components, bool isCustom, const CGHeroInstance * h = nullptr) const;