From 2b9e074d54942cf54e880dbf5d862a9dbb760b1f Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Jan 2014 16:12:53 +0000 Subject: [PATCH] - implements level limit (Mantis #1620) - added workaround to weird bug where vcmi fails to find objects for win/loss conditions --- lib/mapping/CMap.cpp | 27 ++++++++++++++++++++++++--- server/CGameHandler.cpp | 22 ++++++++++++++++++++++ 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/lib/mapping/CMap.cpp b/lib/mapping/CMap.cpp index 664fea84a..d31ba57ea 100644 --- a/lib/mapping/CMap.cpp +++ b/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() diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index b0e072e25..9bc9c8486 100644 --- a/server/CGameHandler.cpp +++ b/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;