Michał W. Urbańczyk 13 سال پیش
والد
کامیت
b5526f0f54
3فایلهای تغییر یافته به همراه60 افزوده شده و 45 حذف شده
  1. 51 39
      AI/VCAI/VCAI.cpp
  2. 8 5
      lib/IGameCallback.cpp
  3. 1 1
      lib/IGameCallback.h

+ 51 - 39
AI/VCAI/VCAI.cpp

@@ -41,6 +41,24 @@ struct SetGlobalState
 	}
 };
 
+template <typename Container>
+typename Container::value_type backOrNull(const Container &c) //returns last element of container or NULL if it is empty (to be used with containers of pointers)
+{
+	if(c.size())
+		return c.back();
+	else
+		return NULL;
+}
+
+template <typename Container>
+typename Container::value_type frontOrNull(const Container &c) //returns first element of container or NULL if it is empty (to be used with containers of pointers)
+{
+	if(c.size())
+		return c.front();
+	else
+		return NULL;
+}
+
 #define SET_GLOBAL_STATE(ai) SetGlobalState _hlpSetState(ai);
 
 #define NET_EVENT_HANDLER SET_GLOBAL_STATE(this)
@@ -294,8 +312,9 @@ ui64 evaluateDanger(crint3 tile)
 
 	ui64 objectDanger = 0, guardDanger = 0;
 
-	if(t->visitable)
-		objectDanger = evaluateDanger(t->visitableObjects.back());
+	auto visObjs = cb->getVisitableObjs(tile);
+	if(visObjs.size())
+		objectDanger = evaluateDanger(visObjs.back());
 
 	int3 guardPos = cb->guardingCreaturePosition(tile);
 	if(guardPos.x >= 0 && guardPos != tile)
@@ -314,15 +333,14 @@ ui64 evaluateDanger(crint3 tile, const CGHeroInstance *visitor)
 		return 190000000; //MUCH
 
 	ui64 objectDanger = 0, guardDanger = 0;
-	CArmedInstance * dangerousObject;
 
-	if(t->visitable)
+	if(const CGObjectInstance * dangerousObject = backOrNull(cb->getVisitableObjs(tile)))
 	{
-		dangerousObject = dynamic_cast<CArmedInstance*>(t->visitableObjects.back());
-		objectDanger = evaluateDanger(t->visitableObjects.back()); //unguarded objects can also be dangerous or unhandled
+		objectDanger = evaluateDanger(dangerousObject); //unguarded objects can also be dangerous or unhandled
 		if (dangerousObject)
 		{
-			objectDanger *= fh->getTacticalAdvantage (visitor, dangerousObject);
+			//TODO: don't downcast objects AI shouldnt know about!
+			objectDanger *= fh->getTacticalAdvantage(visitor, dynamic_cast<const CArmedInstance*>(dangerousObject));
 		}
 	}
 
@@ -410,22 +428,17 @@ void VCAI::heroMoved(const TryMoveHero & details)
 	LOG_ENTRY;
 	if(details.result == TryMoveHero::TELEPORTATION)
 	{
-		const TerrainTile *t1 = cb->getTile(CGHeroInstance::convertPosition(details.start, false), false),
-			*t2 = cb->getTile(CGHeroInstance::convertPosition(details.end, false), false);
-		if(!t1 || !t2) //enemy may have teleported to a tile we don't see
-			return;
-		if(t1->visitable && t2->visitable)
-		{
-			const CGObjectInstance *o1 = t1->visitableObjects.front(),
-				*o2 = t2->visitableObjects.front();
+		const int3 from = CGHeroInstance::convertPosition(details.start, false), 
+			to = CGHeroInstance::convertPosition(details.end, false);
+		const CGObjectInstance *o1 = frontOrNull(cb->getVisitableObjs(from)),
+			*o2 = frontOrNull(cb->getVisitableObjs(to));
 
-			if(o1->ID == Obj::SUBTERRANEAN_GATE && o2->ID == Obj::SUBTERRANEAN_GATE)
-			{
-				knownSubterraneanGates[o1] = o2;
-				knownSubterraneanGates[o2] = o1;
-			}
+		if(o1 && o2 && o1->ID == Obj::SUBTERRANEAN_GATE && o2->ID == Obj::SUBTERRANEAN_GATE)
+		{
+			knownSubterraneanGates[o1] = o2;
+			knownSubterraneanGates[o2] = o1;
+			BNLOG("Found a pair of subterranean gates between %s and %s!", from % to);
 		}
-
 	}
 }
 
@@ -1225,8 +1238,8 @@ void VCAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int
 {
 	assert(playerID > GameConstants::PLAYER_LIMIT || status.getBattle() == UPCOMING_BATTLE);
 	status.setBattle(ONGOING_BATTLE);
-	const TerrainTile *t = myCb->getTile(tile); //may be NULL in some very are cases -> eg. visited monolith and fighting with an enemy at the FoW covered exit
-	battlename = boost::str(boost::format("battle of %s attacking %s at %s") % (hero1 ? hero1->name : "a army") % (t ? t->visitableObjects.back()->hoverName : "unknown enemy") % tile);
+	const CGObjectInstance *presumedEnemy = backOrNull(cb->getVisitableObjs(tile)); //may be NULL in some very are cases -> eg. visited monolith and fighting with an enemy at the FoW covered exit
+	battlename = boost::str(boost::format("Starting battle of %s attacking %s at %s") % (hero1 ? hero1->name : "a army") % (presumedEnemy ? presumedEnemy->hoverName : "unknown enemy") % tile);
 	CAdventureAI::battleStart(army1, army2, tile, hero1, hero2, side);
 }
 
@@ -1278,17 +1291,14 @@ void VCAI::validateVisitableObjs()
 
 void VCAI::retreiveVisitableObjs(std::vector<const CGObjectInstance *> &out, bool includeOwned /*= false*/) const
 {
-	for(int i = 0; i < cb->getMapSize().x; i++)
-		for(int j = 0; j < cb->getMapSize().y; j++)
-			for(int k = 0; k < cb->getMapSize().z; k++)
-				if(const TerrainTile *t = cb->getTile(int3(i,j,k), false))
-				{
-					BOOST_FOREACH(const CGObjectInstance *obj, t->visitableObjects)
-					{
-						if(includeOwned || obj->tempOwner != playerID)
-							out.push_back(obj);
-					}
-				}
+	foreach_tile_pos([&](const int3 &pos)
+	{
+		BOOST_FOREACH(const CGObjectInstance *obj, cb->getVisitableObjs(pos, false))
+		{
+			if(includeOwned || obj->tempOwner != playerID)
+				out.push_back(obj);
+		}
+	});
 }
 
 std::vector<const CGObjectInstance *> VCAI::getFlaggedObjects() const
@@ -1384,7 +1394,7 @@ bool VCAI::moveHeroToTile(int3 dst, const CGHeroInstance * h)
 	bool ret = false;
 	if(startHpos == dst)
 	{
-		assert(cb->getTile(dst)->visitableObjects.size() > 1); //there's no point in revisiting tile where there is no visitable object
+		assert(cb->getVisitableObjs(dst).size() > 1); //there's no point in revisiting tile where there is no visitable object
 		cb->moveHero(h,CGHeroInstance::convertPosition(dst, true));
 		waitTillFree(); //movement may cause battle or blocking dialog
 		ret = true;
@@ -2263,10 +2273,10 @@ TSubgoal CGoal::whatToDoToAchieve()
 
 	case DIG_AT_TILE:
 		{
-			auto objs = cb->getTile(tile)->visitableObjects;
-			if(objs.size() && objs.front()->ID == GameConstants::HEROI_TYPE && objs.front()->tempOwner == ai->playerID) //we have hero at dest
+			const CGObjectInstance *firstObj = frontOrNull(cb->getVisitableObjs(tile));
+			if(firstObj && firstObj->ID == GameConstants::HEROI_TYPE && firstObj->tempOwner == ai->playerID) //we have hero at dest
 			{
-				const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(objs.front());
+				const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(firstObj);
 				return CGoal(*this).sethero(h).setisElementar(true);
 			}
 
@@ -2332,7 +2342,9 @@ TSubgoal CGoal::whatToDoToAchieve()
 
 				if(howManyCanWeBuy + cb->getResourceAmount(resID) >= value)
 				{
-					if(cb->getTile(m->o->visitablePos())->visitableObjects.back()->tempOwner != ai->playerID)
+					auto backObj = backOrNull(cb->getVisitableObjs(m->o->visitablePos())); //it'll be a hero if we have one there; otherwise marketplace
+					assert(backObj);
+					if(backObj->tempOwner != ai->playerID)
 						return CGoal(GET_OBJ).setobjid(m->o->id);
 					return setobjid(m->o->id).setisElementar(true);
 				}

+ 8 - 5
lib/IGameCallback.cpp

@@ -861,15 +861,18 @@ std::vector < const CGObjectInstance * > CGameInfoCallback::getBlockingObjs( int
 	return ret;
 }
 
-std::vector < const CGObjectInstance * > CGameInfoCallback::getVisitableObjs( int3 pos ) const
+std::vector <const CGObjectInstance * > CGameInfoCallback::getVisitableObjs(int3 pos, bool verbose /*= true*/) const
 {
 	std::vector<const CGObjectInstance *> ret;
-	const TerrainTile *t = getTile(pos);
-	ERROR_RET_VAL_IF(!t, "Not a valid tile requested!", ret);
-	//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
+	const TerrainTile *t = getTile(pos, verbose);
+	ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!t, verbose, pos << " is not visible!", ret);
 
 	BOOST_FOREACH(const CGObjectInstance * obj, t->visitableObjects)
-		ret.push_back(obj);
+	{
+		if(player < 0 || obj->ID != GameConstants::EVENTI_TYPE) //hide events from players
+			ret.push_back(obj);
+	}
+
 	return ret;
 }
 

+ 1 - 1
lib/IGameCallback.h

@@ -185,7 +185,7 @@ public:
 	//objects
 	const CGObjectInstance* getObj(int objid, bool verbose = true) const;
 	std::vector <const CGObjectInstance * > getBlockingObjs(int3 pos)const;
-	std::vector <const CGObjectInstance * > getVisitableObjs(int3 pos)const;
+	std::vector <const CGObjectInstance * > getVisitableObjs(int3 pos, bool verbose = true)const;
 	std::vector <const CGObjectInstance * > getFlaggableObjects(int3 pos) const;
 	std::vector <std::string > getObjDescriptions(int3 pos)const; //returns descriptions of objects at pos in order from the lowest to the highest
 	int getOwner(int heroID) const;