Ver Fonte

- Fixed possible crash at invalid quest
- Fixed incorrect victory condition for AI (capture town/monster/hero)
- Possible fix for GET_OBJ not being completed (goal engine needs more work)
- So tweaks

DjWarmonger há 13 anos atrás
pai
commit
977acfafc8
2 ficheiros alterados com 71 adições e 48 exclusões
  1. 22 47
      AI/VCAI/VCAI.cpp
  2. 49 1
      AI/VCAI/VCAI.h

+ 22 - 47
AI/VCAI/VCAI.cpp

@@ -1717,41 +1717,6 @@ bool VCAI::isAccessibleForHero(const int3 & pos, HeroPtr h, bool includeAllies /
 	return cb->getPathInfo(pos)->reachable();
 }
 
-class cannotFulfillGoalException : public std::exception
-{
-	std::string msg;
-public:
-	explicit cannotFulfillGoalException(crstring _Message) : msg(_Message)
-	{
-	}
-
-	virtual ~cannotFulfillGoalException() throw ()
-	{
-	};
-
-	const char *what() const throw () OVERRIDE
-	{
-		return msg.c_str();
-	}
-};
-class goalFulfilledException : public std::exception
-{
-	std::string msg;
-public:
-	explicit goalFulfilledException(crstring _Message) : msg(_Message)
-	{
-	}
-
-	virtual ~goalFulfilledException() throw ()
-	{
-	};
-
-	const char *what() const throw () OVERRIDE
-	{
-		return msg.c_str();
-	}
-};
-
 bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
 {
 	visitedObject = NULL;
@@ -1815,6 +1780,8 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
 	if (visitedObject) //we step into something interesting
 	{
 		performObjectInteraction (visitedObject, h);
+		//BNLOG("Hero %s moved from %s to %s at %s", h->name % startHpos % visitedObject->hoverName % h->visitablePos());
+		//throw goalFulfilledException (CGoal(GET_OBJ).setobjid(visitedObject->id));
 	}
 
 	if(h) //we could have lost hero after last move
@@ -1918,7 +1885,7 @@ void VCAI::tryRealize(CGoal g)
 			//{
 				if (ai->moveHeroToTile(g.tile, g.hero.get()))
 				{
-					throw goalFulfilledException("");
+					throw goalFulfilledException (g);
 				}
 			//}
 			//else
@@ -1931,7 +1898,7 @@ void VCAI::tryRealize(CGoal g)
 				throw cannotFulfillGoalException("Cannot visit tile: hero is out of MPs!");
 			if (ai->moveHeroToTile(g.tile, g.hero.get()))
 			{
-				throw goalFulfilledException("");
+				throw goalFulfilledException (g);
 			}
 		}
 		break;
@@ -2081,6 +2048,16 @@ void VCAI::endTurn()
 	tlog4 << "Player " << playerID << " ended turn\n";
 }
 
+bool VCAI::fulfillsGoal (CGoal &goal, CGoal &mainGoal)
+{
+	if (mainGoal.goalType == GET_OBJ && goal.goalType == VISIT_TILE) //deduce that GET_OBJ was completed by visiting object's tile
+	{ //TODO: more universal mechanism
+		if (cb->getObj(mainGoal.objid)->visitablePos() == goal.tile)
+			return true;
+	}
+	return false;
+}
+
 void VCAI::striveToGoal(const CGoal &ultimateGoal)
 {
 	if (ultimateGoal.invalid())
@@ -2146,9 +2123,8 @@ void VCAI::striveToGoal(const CGoal &ultimateGoal)
 		catch(goalFulfilledException &e)
 		{
 			completeGoal (goal);
-			if (maxGoals > 98) //completed goal was main goal
-				//TODO: find better condition
-			return;
+			if (fulfillsGoal (goal, abstractGoal) || maxGoals > 98) //completed goal was main goal //TODO: find better condition
+				return; 
 		}
 		catch(std::exception &e)
 		{
@@ -2193,9 +2169,8 @@ void VCAI::striveToGoal(const CGoal &ultimateGoal)
 			}
 			catch(goalFulfilledException &e)
 			{
-				completeGoal (goal);
-				if (maxGoals > 98) //completed goal was main goal
-					//TODO: find better condition
+				completeGoal (goal); //FIXME: deduce that we have realized GET_OBJ goal
+				if (fulfillsGoal (goal, abstractGoal) || maxGoals > 98) //completed goal was main goal
 					return;
 			}
 			catch(std::exception &e)
@@ -2210,7 +2185,7 @@ void VCAI::striveToGoal(const CGoal &ultimateGoal)
 
 void VCAI::striveToQuest (const QuestInfo &q)
 {
-	if (q.quest.progress < CQuest::COMPLETE)
+	if (q.quest.missionType && q.quest.progress < CQuest::COMPLETE) //FIXME: quests are never synchronized. Pointer handling needed
 	{
 		MetaString ms;
 		q.quest.getRolloverText(ms, false);
@@ -2767,9 +2742,9 @@ TSubgoal CGoal::whatToDoToAchieve()
 			case EVictoryConditionType::ARTIFACT:
 				return CGoal(GET_ART_TYPE).setaid(vc.ID);
 			case EVictoryConditionType::BEATHERO:
-				return CGoal(GET_OBJ).setobjid(vc.ID);
+				return CGoal(GET_OBJ).setobjid(vc.obj->id);
 			case EVictoryConditionType::BEATMONSTER:
-				return CGoal(GET_OBJ).setobjid(vc.ID);
+				return CGoal(GET_OBJ).setobjid(vc.obj->id);
 			case EVictoryConditionType::BUILDCITY:
 				//TODO build castle/capitol
 				break;
@@ -2814,7 +2789,7 @@ TSubgoal CGoal::whatToDoToAchieve()
 				}
 				break;
 			case EVictoryConditionType::CAPTURECITY:
-				return CGoal(GET_OBJ).setobjid(vc.ID);
+				return CGoal(GET_OBJ).setobjid(vc.obj->id);
 			case EVictoryConditionType::GATHERRESOURCE:
 				return CGoal(COLLECT_RES).setresID(vc.ID).setvalue(vc.count);
 				//TODO mines? piles? marketplace?

+ 49 - 1
AI/VCAI/VCAI.h

@@ -158,6 +158,16 @@ struct CGoal
 	HeroPtr hero; SETTER(HeroPtr, hero)
 	const CGTownInstance *town; SETTER(CGTownInstance *, town)
 	int bid; SETTER(int, bid)
+
+	bool operator== (CGoal &g)
+	{
+		switch (goalType)
+		{
+			case EGoals::GET_OBJ:
+				return objid == g.objid;
+		}
+		return false;
+	}
 };
 
 enum {NOT_VISIBLE = 0, NOT_CHECKED = 1, NOT_AVAILABLE};
@@ -344,7 +354,8 @@ public:
 	void setGoal(HeroPtr h, const CGoal goal);
 	void setGoal(HeroPtr h, EGoals goalType = INVALID);
 	void completeGoal (const CGoal goal); //safely removes goal from reserved hero
-	void striveToQuest (const QuestInfo &q); 
+	void striveToQuest (const QuestInfo &q);
+	bool fulfillsGoal (CGoal &goal, CGoal &mainGoal);
 
 	void recruitHero(const CGTownInstance * t);
 	std::vector<const CGObjectInstance *> getPossibleDestinations(HeroPtr h);
@@ -391,6 +402,43 @@ public:
 	void requestActionASAP(boost::function<void()> whatToDo); 
 };
 
+std::string goalName(EGoals goalType); //TODO: move to CGoal class?
+
+class cannotFulfillGoalException : public std::exception
+{
+	std::string msg;
+public:
+	explicit cannotFulfillGoalException(crstring _Message) : msg(_Message)
+	{
+	}
+
+	virtual ~cannotFulfillGoalException() throw ()
+	{
+	};
+
+	const char *what() const throw () OVERRIDE
+	{
+		return msg.c_str();
+	}
+};
+class goalFulfilledException : public std::exception
+{
+public:
+	CGoal goal;
+
+	explicit goalFulfilledException(CGoal Goal) : goal(Goal)
+	{
+	}
+
+	virtual ~goalFulfilledException() throw ()
+	{
+	};
+
+	const char *what() const throw () OVERRIDE
+	{
+		return goalName(goal.goalType).c_str();
+	}
+};
 
 template<int id>
 bool objWithID(const CGObjectInstance *obj)