Ver código fonte

- implements level limit (Mantis #1620)
- added workaround to weird bug where vcmi fails to find objects for
win/loss conditions

Ivan Savenko 12 anos atrás
pai
commit
2b9e074d54
2 arquivos alterados com 46 adições e 3 exclusões
  1. 24 3
      lib/mapping/CMap.cpp
  2. 22 0
      server/CGameHandler.cpp

+ 24 - 3
lib/mapping/CMap.cpp

@@ -312,9 +312,30 @@ const CGObjectInstance * CMap::getObjectiveObjectFrom(int3 pos, Obj::EObj type)
 		if (object->ID == type)
 			return object;
 	}
-	// possibly may trigger for empty placeholders in campaigns
-	logGlobal->warnStream() << "Failed to find object of type " << int(type) << " at " << pos;
-	return nullptr;
+	// There is weird bug because of which sometimes heroes will not be found properly despite having correct position
+	// Try to workaround that and find closest object that we can use
+
+	logGlobal->errorStream() << "Failed to find object of type " << int(type) << " at " << pos;
+	logGlobal->errorStream() << "Will try to find closest matching object";
+
+	CGObjectInstance * bestMatch = nullptr;
+	for (CGObjectInstance * object : objects)
+	{
+		if (object->ID == type)
+		{
+			if (bestMatch == nullptr)
+				bestMatch = object;
+			else
+			{
+				if (object->pos.dist2d(pos) < bestMatch->pos.dist2d(pos))
+					bestMatch = object;// closer than one we already found
+			}
+		}
+	}
+	assert(bestMatch != nullptr); // if this happens - victory conditions or map itself is very, very broken
+
+	logGlobal->errorStream() << "Will use " << bestMatch->getHoverText() << " from " << bestMatch->pos;
+	return bestMatch;
 }
 
 void CMap::checkForObjectives()

+ 22 - 0
server/CGameHandler.cpp

@@ -373,6 +373,27 @@ void CGameHandler::expGiven(const CGHeroInstance *hero)
 
 void CGameHandler::changePrimSkill(const CGHeroInstance * hero, PrimarySkill::PrimarySkill which, si64 val, bool abs)
 {
+	if (which == PrimarySkill::EXPERIENCE) // Check if scenario limit reached
+	{
+		if (gs->map->levelLimit != 0)
+		{
+			TExpType expLimit = VLC->heroh->reqExp(gs->map->levelLimit);
+			TExpType resultingExp = abs ? val : hero->exp + val;
+			if (resultingExp > expLimit)
+			{
+				// set given experience to max possible, but don't decrease if hero already over top
+				abs = true;
+				val = std::max(expLimit, hero->exp);
+
+				InfoWindow iw;
+				iw.player = hero->tempOwner;
+				iw.text.addTxt(MetaString::GENERAL_TXT, 1); //can gain no more XP
+				iw.text.addReplacement(hero->name);
+				sendAndApply(&iw);
+			}
+		}
+	}
+
 	SetPrimSkill sps;
 	sps.id = hero->id;
 	sps.which = which;
@@ -385,6 +406,7 @@ void CGameHandler::changePrimSkill(const CGHeroInstance * hero, PrimarySkill::Pr
 	{
 		if(hero->commander && hero->commander->alive)
 		{
+			//FIXME: trim experience according to map limit?
 			SetCommanderProperty scp;
 			scp.heroid = hero->id;
 			scp.which = SetCommanderProperty::EXPERIENCE;