From 7359b66f99ff7f37df4db12fba4130d51eb71ed7 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 13 Feb 2024 23:42:05 +0200 Subject: [PATCH 1/5] Do not use floating point equality checks --- AI/BattleAI/AttackPossibility.cpp | 10 +++------ AI/BattleAI/BattleExchangeVariant.cpp | 2 +- AI/Nullkiller/AIGateway.cpp | 5 +++-- .../Analyzers/DangerHitMapAnalyzer.cpp | 2 +- Global.h | 13 ++++++++++++ client/mapView/MapViewCache.cpp | 4 ++-- client/render/ColorFilter.cpp | 8 +++---- client/widgets/Slider.cpp | 21 ++++++++++--------- lib/CCreatureHandler.cpp | 8 +++---- lib/rmg/float3.h | 17 --------------- 10 files changed, 42 insertions(+), 48 deletions(-) diff --git a/AI/BattleAI/AttackPossibility.cpp b/AI/BattleAI/AttackPossibility.cpp index af36ed07a..b2d4c769f 100644 --- a/AI/BattleAI/AttackPossibility.cpp +++ b/AI/BattleAI/AttackPossibility.cpp @@ -62,16 +62,12 @@ void DamageCache::buildDamageCache(std::shared_ptr hb, int sid int64_t DamageCache::getDamage(const battle::Unit * attacker, const battle::Unit * defender, std::shared_ptr hb) { - auto damage = damageCache[attacker->unitId()][defender->unitId()] * attacker->getCount(); + bool wasComputedBefore = damageCache[attacker->unitId()].count(defender->unitId()); - if(damage == 0) - { + if (!wasComputedBefore) cacheDamage(attacker, defender, hb); - damage = damageCache[attacker->unitId()][defender->unitId()] * attacker->getCount(); - } - - return static_cast(damage); + return damageCache[attacker->unitId()][defender->unitId()] * attacker->getCount(); } int64_t DamageCache::getOriginalDamage(const battle::Unit * attacker, const battle::Unit * defender, std::shared_ptr hb) diff --git a/AI/BattleAI/BattleExchangeVariant.cpp b/AI/BattleAI/BattleExchangeVariant.cpp index f0a29682b..d7902f878 100644 --- a/AI/BattleAI/BattleExchangeVariant.cpp +++ b/AI/BattleAI/BattleExchangeVariant.cpp @@ -270,7 +270,7 @@ EvaluationResult BattleExchangeEvaluator::findBestTarget( { float score = evaluateExchange(ap, 0, targets, damageCache, hb); - if(score > result.score || (score == result.score && result.wait)) + if(score > result.score || (vstd::isAlmostEqual(score, result.score) && result.wait)) { result.score = score; result.bestAttack = ap; diff --git a/AI/Nullkiller/AIGateway.cpp b/AI/Nullkiller/AIGateway.cpp index 9ed9fe77f..1fced0f95 100644 --- a/AI/Nullkiller/AIGateway.cpp +++ b/AI/Nullkiller/AIGateway.cpp @@ -632,7 +632,8 @@ void AIGateway::showBlockingDialog(const std::string & text, const std::vectorid == hero->id ? objects.back() : objects.front(); auto objType = topObj->ID; // top object should be our hero auto goalObjectID = nullkiller->getTargetObject(); - auto ratio = (float)nullkiller->dangerEvaluator->evaluateDanger(target, hero.get()) / (float)hero->getTotalStrength(); + auto danger = nullkiller->dangerEvaluator->evaluateDanger(target, hero.get()); + auto ratio = static_cast(danger) / hero->getTotalStrength(); answer = topObj->id == goalObjectID; // no if we do not aim to visit this object logAi->trace("Query hook: %s(%s) by %s danger ratio %f", target.toString(), topObj->getObjectName(), hero.name, ratio); @@ -648,7 +649,7 @@ void AIGateway::showBlockingDialog(const std::string & text, const std::vector (1 / SAFE_ATTACK_CONSTANT); answer = !dangerUnknown && !dangerTooHigh; diff --git a/AI/Nullkiller/Analyzers/DangerHitMapAnalyzer.cpp b/AI/Nullkiller/Analyzers/DangerHitMapAnalyzer.cpp index ccf6b7ecb..76ac640f7 100644 --- a/AI/Nullkiller/Analyzers/DangerHitMapAnalyzer.cpp +++ b/AI/Nullkiller/Analyzers/DangerHitMapAnalyzer.cpp @@ -226,7 +226,7 @@ void DangerHitMapAnalyzer::calculateTileOwners() } } - if(ourDistance == enemyDistance) + if(vstd::isAlmostEqual(ourDistance, enemyDistance)) { hitMap[pos.x][pos.y][pos.z].closestTown = nullptr; } diff --git a/Global.h b/Global.h index 7135412b1..43ee6d7ec 100644 --- a/Global.h +++ b/Global.h @@ -685,6 +685,19 @@ namespace vstd return a + (b - a) * f; } + template + bool isAlmostZero(const Floating & value) + { + constexpr Floating epsilon(0.00001); + return std::abs(value) < epsilon; + } + + template + bool isAlmostEqual(const Floating1 & left, const Floating2 & right) + { + return isAlmostZero(left - right); + } + ///compile-time version of std::abs for ints for int3, in clang++15 std::abs is constexpr static constexpr int abs(int i) { if(i < 0) return -i; diff --git a/client/mapView/MapViewCache.cpp b/client/mapView/MapViewCache.cpp index ad851ef11..2bd21ce8d 100644 --- a/client/mapView/MapViewCache.cpp +++ b/client/mapView/MapViewCache.cpp @@ -141,7 +141,7 @@ void MapViewCache::update(const std::shared_ptr & context) void MapViewCache::render(const std::shared_ptr & context, Canvas & target, bool fullRedraw) { bool mapMoved = (cachedPosition != model->getMapViewCenter()); - bool lazyUpdate = !mapMoved && !fullRedraw && context->viewTransitionProgress() == 0; + bool lazyUpdate = !mapMoved && !fullRedraw && vstd::isAlmostZero(context->viewTransitionProgress()); Rect dimensions = model->getTilesTotalRect(); @@ -184,7 +184,7 @@ void MapViewCache::render(const std::shared_ptr & context, } } - if(context->viewTransitionProgress() != 0) + if(!vstd::isAlmostZero(context->viewTransitionProgress())) target.drawTransparent(*terrainTransition, Point(0, 0), 1.0 - context->viewTransitionProgress()); cachedPosition = model->getMapViewCenter(); diff --git a/client/render/ColorFilter.cpp b/client/render/ColorFilter.cpp index d6234116f..4540c0557 100644 --- a/client/render/ColorFilter.cpp +++ b/client/render/ColorFilter.cpp @@ -41,10 +41,10 @@ bool ColorFilter::operator != (const ColorFilter & other) const bool ColorFilter::operator == (const ColorFilter & other) const { return - r.r == other.r.r && r.g && other.r.g && r.b == other.r.b && r.a == other.r.a && - g.r == other.g.r && g.g && other.g.g && g.b == other.g.b && g.a == other.g.a && - b.r == other.b.r && b.g && other.b.g && b.b == other.b.b && b.a == other.b.a && - a == other.a; + vstd::isAlmostEqual(r.r, other.r.r) && vstd::isAlmostEqual(r.g, other.r.g) && vstd::isAlmostEqual(r.b, other.r.b) && vstd::isAlmostEqual(r.a, other.r.a) && + vstd::isAlmostEqual(g.r, other.g.r) && vstd::isAlmostEqual(g.g, other.g.g) && vstd::isAlmostEqual(g.b, other.g.b) && vstd::isAlmostEqual(g.a, other.g.a) && + vstd::isAlmostEqual(b.r, other.b.r) && vstd::isAlmostEqual(b.g, other.b.g) && vstd::isAlmostEqual(b.b, other.b.b) && vstd::isAlmostEqual(b.a, other.b.a) && + vstd::isAlmostEqual(a, other.a); } ColorFilter ColorFilter::genEmptyShifter( ) diff --git a/client/widgets/Slider.cpp b/client/widgets/Slider.cpp index 8a37b6f46..dff5d3229 100644 --- a/client/widgets/Slider.cpp +++ b/client/widgets/Slider.cpp @@ -21,23 +21,24 @@ void CSlider::mouseDragged(const Point & cursorPosition, const Point & lastUpdateDistance) { - double v = 0; + double newPosition = 0; if(getOrientation() == Orientation::HORIZONTAL) { - v = cursorPosition.x - pos.x - 24; - v *= positions; - v /= (pos.w - 48); + newPosition = cursorPosition.x - pos.x - 24; + newPosition *= positions; + newPosition /= (pos.w - 48); } else { - v = cursorPosition.y - pos.y - 24; - v *= positions; - v /= (pos.h - 48); + newPosition = cursorPosition.y - pos.y - 24; + newPosition *= positions; + newPosition /= (pos.h - 48); } - v += 0.5; - if(v!=value) + + int positionInteger = std::round(newPosition); + if(positionInteger != value) { - scrollTo(static_cast(v)); + scrollTo(static_cast(newPosition)); } } diff --git a/lib/CCreatureHandler.cpp b/lib/CCreatureHandler.cpp index 87889fe1d..530c3c45b 100644 --- a/lib/CCreatureHandler.cpp +++ b/lib/CCreatureHandler.cpp @@ -844,8 +844,8 @@ void CCreatureHandler::loadUnitAnimInfo(JsonNode & graphics, CLegacyConfigParser missile["attackClimaxFrame"].Float() = parser.readNumber(); // assume that creature is not a shooter and should not have whole missile field - if (missile["frameAngles"].Vector()[0].Float() == 0 && - missile["attackClimaxFrame"].Float() == 0) + if (missile["frameAngles"].Vector()[0].Integer() == 0 && + missile["attackClimaxFrame"].Integer() == 0) graphics.Struct().erase("missile"); } @@ -987,10 +987,10 @@ void CCreatureHandler::loadStackExperience(CCreature * creature, const JsonNode int lastVal = 0; for (const JsonNode &val : values) { - if (val.Float() != lastVal) + if (val.Integer() != lastVal) { JsonNode bonusInput = exp["bonus"]; - bonusInput["val"].Float() = static_cast(val.Float()) - lastVal; + bonusInput["val"].Float() = val.Integer() - lastVal; auto bonus = JsonUtils::parseBonus (bonusInput); bonus->source = BonusSource::STACK_EXPERIENCE; diff --git a/lib/rmg/float3.h b/lib/rmg/float3.h index 97bbc95fc..ca8775c3a 100644 --- a/lib/rmg/float3.h +++ b/lib/rmg/float3.h @@ -113,23 +113,6 @@ public: return *this; } - bool operator==(const float3 & i) const { return (x == i.x) && (y == i.y) && (z == i.z); } - bool operator!=(const float3 & i) const { return (x != i.x) || (y != i.y) || (z != i.z); } - - bool operator<(const float3 & i) const - { - if (zi.z) - return false; - if (yi.y) - return false; - - return x Date: Tue, 13 Feb 2024 23:42:31 +0200 Subject: [PATCH 2/5] Replace throws() with nothrow --- AI/Nullkiller/Goals/AbstractGoal.h | 12 ++---------- AI/VCAI/VCAI.h | 12 ++---------- lib/rmg/Functions.h | 8 ++------ 3 files changed, 6 insertions(+), 26 deletions(-) diff --git a/AI/Nullkiller/Goals/AbstractGoal.h b/AI/Nullkiller/Goals/AbstractGoal.h index d089083bf..2579c1e12 100644 --- a/AI/Nullkiller/Goals/AbstractGoal.h +++ b/AI/Nullkiller/Goals/AbstractGoal.h @@ -180,11 +180,7 @@ public: { } - virtual ~cannotFulfillGoalException() throw () - { - }; - - const char * what() const throw () override + const char * what() const noexcept override { return msg.c_str(); } @@ -203,11 +199,7 @@ public: msg = goal->toString(); } - virtual ~goalFulfilledException() throw () - { - }; - - const char * what() const throw () override + const char * what() const noexcept override { return msg.c_str(); } diff --git a/AI/VCAI/VCAI.h b/AI/VCAI/VCAI.h index 0cc43db2c..4db3f89f0 100644 --- a/AI/VCAI/VCAI.h +++ b/AI/VCAI/VCAI.h @@ -371,11 +371,7 @@ public: { } - virtual ~cannotFulfillGoalException() throw () - { - }; - - const char * what() const throw () override + const char * what() const noexcept override { return msg.c_str(); } @@ -394,11 +390,7 @@ public: msg = goal->name(); } - virtual ~goalFulfilledException() throw () - { - }; - - const char * what() const throw () override + const char * what() const noexcept override { return msg.c_str(); } diff --git a/lib/rmg/Functions.h b/lib/rmg/Functions.h index 3a4885b5f..0bcaee0d7 100644 --- a/lib/rmg/Functions.h +++ b/lib/rmg/Functions.h @@ -28,12 +28,8 @@ public: explicit rmgException(const std::string& _Message) : msg(_Message) { } - - virtual ~rmgException() throw () - { - }; - - const char *what() const throw () override + + const char *what() const noexcept override { return msg.c_str(); } From 6d6137accc80532474db77e17dde6aabf4c3faf7 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 13 Feb 2024 23:49:00 +0200 Subject: [PATCH 3/5] Simplified code --- lib/gameState/CGameState.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/gameState/CGameState.cpp b/lib/gameState/CGameState.cpp index 9fa865db0..545c2b43c 100644 --- a/lib/gameState/CGameState.cpp +++ b/lib/gameState/CGameState.cpp @@ -1383,10 +1383,8 @@ bool CGameState::checkForVictory(const PlayerColor & player, const EventConditio int total = 0; //creature counter for(auto object : map->objects) { - const CArmedInstance *ai = nullptr; - if(object - && object->tempOwner == player //object controlled by player - && (ai = dynamic_cast(object.get()))) //contains army + const CArmedInstance *ai = dynamic_cast(object.get()); + if(ai && ai->getOwner() == player) { for(const auto & elem : ai->Slots()) //iterate through army if(elem.second->getId() == condition.objectType.as()) //it's searched creature From 0d74959a3320d805f0631b9c28f8410bf53643c3 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 14 Feb 2024 12:07:01 +0200 Subject: [PATCH 4/5] Better float comparison --- Global.h | 5 +++-- lib/gameState/CGameState.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Global.h b/Global.h index 43ee6d7ec..7834b9a76 100644 --- a/Global.h +++ b/Global.h @@ -689,13 +689,14 @@ namespace vstd bool isAlmostZero(const Floating & value) { constexpr Floating epsilon(0.00001); - return std::abs(value) < epsilon; + return std::abs(value) <= epsilon; } template bool isAlmostEqual(const Floating1 & left, const Floating2 & right) { - return isAlmostZero(left - right); + const auto relativeEpsilon = std::max(std::abs(left), std::abs(right)) * 0.00001; + return std::abs(left - right) <= relativeEpsilon; } ///compile-time version of std::abs for ints for int3, in clang++15 std::abs is constexpr diff --git a/lib/gameState/CGameState.cpp b/lib/gameState/CGameState.cpp index 545c2b43c..ebe7b6710 100644 --- a/lib/gameState/CGameState.cpp +++ b/lib/gameState/CGameState.cpp @@ -1383,7 +1383,7 @@ bool CGameState::checkForVictory(const PlayerColor & player, const EventConditio int total = 0; //creature counter for(auto object : map->objects) { - const CArmedInstance *ai = dynamic_cast(object.get()); + const auto * ai = dynamic_cast(object.get()); if(ai && ai->getOwner() == player) { for(const auto & elem : ai->Slots()) //iterate through army From c23953eac551919cb32a53881fe40354b3cdaad1 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 14 Feb 2024 12:56:37 +0200 Subject: [PATCH 5/5] Remove custom casts --- AI/Nullkiller/AIGateway.cpp | 2 +- .../Pathfinding/Rules/AILayerTransitionRule.cpp | 2 +- AI/VCAI/Goals/CollectRes.cpp | 4 +++- .../Pathfinding/Rules/AILayerTransitionRule.cpp | 2 +- AI/VCAI/VCAI.cpp | 2 +- Global.h | 7 +++++-- client/NetPacksClient.cpp | 6 +++--- client/adventureMap/AdventureMapInterface.cpp | 2 +- lib/mapObjects/IMarket.cpp | 14 -------------- lib/mapObjects/IMarket.h | 2 -- lib/mapObjects/IObjectInterface.cpp | 5 ----- lib/mapObjects/IObjectInterface.h | 2 -- server/CGameHandler.cpp | 2 +- server/NetPacksServer.cpp | 2 +- 14 files changed, 18 insertions(+), 36 deletions(-) diff --git a/AI/Nullkiller/AIGateway.cpp b/AI/Nullkiller/AIGateway.cpp index 1fced0f95..0015ed995 100644 --- a/AI/Nullkiller/AIGateway.cpp +++ b/AI/Nullkiller/AIGateway.cpp @@ -1407,7 +1407,7 @@ void AIGateway::tryRealize(Goals::Trade & g) //trade int accquiredResources = 0; if(const CGObjectInstance * obj = cb->getObj(ObjectInstanceID(g.objid), false)) { - if(const IMarket * m = IMarket::castFrom(obj, false)) + if(const auto * m = dynamic_cast(obj)) { auto freeRes = cb->getResourceAmount(); //trade only resources which are not reserved for(auto it = ResourceSet::nziterator(freeRes); it.valid(); it++) diff --git a/AI/Nullkiller/Pathfinding/Rules/AILayerTransitionRule.cpp b/AI/Nullkiller/Pathfinding/Rules/AILayerTransitionRule.cpp index a43f8f04e..d71aa9cb0 100644 --- a/AI/Nullkiller/Pathfinding/Rules/AILayerTransitionRule.cpp +++ b/AI/Nullkiller/Pathfinding/Rules/AILayerTransitionRule.cpp @@ -131,7 +131,7 @@ namespace AIPathfinding { if(obj->ID != Obj::TOWN) //towns were handled in the previous loop { - if(const IShipyard * shipyard = IShipyard::castFrom(obj)) + if(const auto * shipyard = dynamic_cast(obj)) shipyards.push_back(shipyard); } } diff --git a/AI/VCAI/Goals/CollectRes.cpp b/AI/VCAI/Goals/CollectRes.cpp index a5600d8df..cb780c5ac 100644 --- a/AI/VCAI/Goals/CollectRes.cpp +++ b/AI/VCAI/Goals/CollectRes.cpp @@ -124,7 +124,9 @@ TSubgoal CollectRes::whatToDoToTrade() ai->retrieveVisitableObjs(visObjs, true); for(const CGObjectInstance * obj : visObjs) { - if(const IMarket * m = IMarket::castFrom(obj, false); m && m->allowsTrade(EMarketMode::RESOURCE_RESOURCE)) + const auto * m = dynamic_cast(obj); + + if(m && m->allowsTrade(EMarketMode::RESOURCE_RESOURCE)) { if(obj->ID == Obj::TOWN) { diff --git a/AI/VCAI/Pathfinding/Rules/AILayerTransitionRule.cpp b/AI/VCAI/Pathfinding/Rules/AILayerTransitionRule.cpp index 9603189fc..4e857df98 100644 --- a/AI/VCAI/Pathfinding/Rules/AILayerTransitionRule.cpp +++ b/AI/VCAI/Pathfinding/Rules/AILayerTransitionRule.cpp @@ -58,7 +58,7 @@ namespace AIPathfinding { if(obj->ID != Obj::TOWN) //towns were handled in the previous loop { - if(const IShipyard * shipyard = IShipyard::castFrom(obj)) + if(const auto * shipyard = dynamic_cast(obj)) shipyards.push_back(shipyard); } } diff --git a/AI/VCAI/VCAI.cpp b/AI/VCAI/VCAI.cpp index 18d42a511..7ce4679dd 100644 --- a/AI/VCAI/VCAI.cpp +++ b/AI/VCAI/VCAI.cpp @@ -2134,7 +2134,7 @@ void VCAI::tryRealize(Goals::Trade & g) //trade int accquiredResources = 0; if(const CGObjectInstance * obj = cb->getObj(ObjectInstanceID(g.objid), false)) { - if(const IMarket * m = IMarket::castFrom(obj, false)) + if(const auto * m = dynamic_cast(obj)) { auto freeRes = ah->freeResources(); //trade only resources which are not reserved for(auto it = ResourceSet::nziterator(freeRes); it.valid(); it++) diff --git a/Global.h b/Global.h index 7834b9a76..3ef1a64e4 100644 --- a/Global.h +++ b/Global.h @@ -695,8 +695,11 @@ namespace vstd template bool isAlmostEqual(const Floating1 & left, const Floating2 & right) { - const auto relativeEpsilon = std::max(std::abs(left), std::abs(right)) * 0.00001; - return std::abs(left - right) <= relativeEpsilon; + using Floating = decltype(left + right); + constexpr Floating epsilon(0.00001); + const Floating relativeEpsilon = std::max(std::abs(left), std::abs(right)) * epsilon; + const Floating value = std::abs(left - right); + return value <= relativeEpsilon; } ///compile-time version of std::abs for ints for int3, in clang++15 std::abs is constexpr diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index d01890f37..ff6c037b1 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -958,7 +958,7 @@ void ApplyClientNetPackVisitor::visitOpenWindow(OpenWindow & pack) case EOpenWindowMode::SHIPYARD_WINDOW: { assert(pack.queryID == QueryID::NONE); - const IShipyard *sy = IShipyard::castFrom(cl.getObj(ObjectInstanceID(pack.object))); + const auto * sy = dynamic_cast(cl.getObj(ObjectInstanceID(pack.object))); callInterfaceIfPresent(cl, sy->getObject()->getOwner(), &IGameEventsReceiver::showShipyardDialog, sy); } break; @@ -974,7 +974,7 @@ void ApplyClientNetPackVisitor::visitOpenWindow(OpenWindow & pack) case EOpenWindowMode::UNIVERSITY_WINDOW: { //displays University window (when hero enters University on adventure map) - const IMarket *market = IMarket::castFrom(cl.getObj(ObjectInstanceID(pack.object))); + const auto * market = dynamic_cast(cl.getObj(ObjectInstanceID(pack.object))); const CGHeroInstance *hero = cl.getHero(ObjectInstanceID(pack.visitor)); callInterfaceIfPresent(cl, hero->tempOwner, &IGameEventsReceiver::showUniversityWindow, market, hero, pack.queryID); } @@ -984,7 +984,7 @@ void ApplyClientNetPackVisitor::visitOpenWindow(OpenWindow & pack) //displays Thieves' Guild window (when hero enters Den of Thieves) const CGObjectInstance *obj = cl.getObj(ObjectInstanceID(pack.object)); const CGHeroInstance *hero = cl.getHero(ObjectInstanceID(pack.visitor)); - const IMarket *market = IMarket::castFrom(obj); + const auto *market = dynamic_cast(obj); callInterfaceIfPresent(cl, cl.getTile(obj->visitablePos())->visitableObjects.back()->tempOwner, &IGameEventsReceiver::showMarketWindow, market, hero, pack.queryID); } break; diff --git a/client/adventureMap/AdventureMapInterface.cpp b/client/adventureMap/AdventureMapInterface.cpp index 4cb1ef6e6..7fd0528c7 100644 --- a/client/adventureMap/AdventureMapInterface.cpp +++ b/client/adventureMap/AdventureMapInterface.cpp @@ -852,7 +852,7 @@ Rect AdventureMapInterface::terrainAreaPixels() const const IShipyard * AdventureMapInterface::ourInaccessibleShipyard(const CGObjectInstance *obj) const { - const IShipyard *ret = IShipyard::castFrom(obj); + const auto *ret = dynamic_cast(obj); if(!ret || obj->tempOwner != currentPlayerID || diff --git a/lib/mapObjects/IMarket.cpp b/lib/mapObjects/IMarket.cpp index 02b6d4631..06fb94f1e 100644 --- a/lib/mapObjects/IMarket.cpp +++ b/lib/mapObjects/IMarket.cpp @@ -154,20 +154,6 @@ std::vector IMarket::availableItemsIds(EMarketMode mode) const return ret; } -const IMarket * IMarket::castFrom(const CGObjectInstance *obj, bool verbose) -{ - auto * imarket = dynamic_cast(obj); - if(verbose && !imarket) - { - logGlobal->error("Cannot cast to IMarket"); - if(obj) - { - logGlobal->error("Object type %s", obj->typeName); - } - } - return imarket; -} - IMarket::IMarket() { } diff --git a/lib/mapObjects/IMarket.h b/lib/mapObjects/IMarket.h index cc20300ab..caf3e4cb4 100644 --- a/lib/mapObjects/IMarket.h +++ b/lib/mapObjects/IMarket.h @@ -29,8 +29,6 @@ public: bool getOffer(int id1, int id2, int &val1, int &val2, EMarketMode mode) const; //val1 - how many units of id1 player has to give to receive val2 units std::vector availableModes() const; - - static const IMarket *castFrom(const CGObjectInstance *obj, bool verbose = true); }; VCMI_LIB_NAMESPACE_END diff --git a/lib/mapObjects/IObjectInterface.cpp b/lib/mapObjects/IObjectInterface.cpp index 1c2c15548..e7dac1ca0 100644 --- a/lib/mapObjects/IObjectInterface.cpp +++ b/lib/mapObjects/IObjectInterface.cpp @@ -156,9 +156,4 @@ void IShipyard::getBoatCost(TResources & cost) const cost[EGameResID::GOLD] = 1000; } -const IShipyard * IShipyard::castFrom( const CGObjectInstance *obj ) -{ - return dynamic_cast(obj); -} - VCMI_LIB_NAMESPACE_END diff --git a/lib/mapObjects/IObjectInterface.h b/lib/mapObjects/IObjectInterface.h index 8c5b94b8b..12d2baeb1 100644 --- a/lib/mapObjects/IObjectInterface.h +++ b/lib/mapObjects/IObjectInterface.h @@ -101,8 +101,6 @@ class DLL_LINKAGE IShipyard : public IBoatGenerator { public: virtual void getBoatCost(ResourceSet & cost) const; - - static const IShipyard *castFrom(const CGObjectInstance *obj); }; VCMI_LIB_NAMESPACE_END diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index aaa7793f1..7b7fca060 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -3528,7 +3528,7 @@ void CGameHandler::objectVisitEnded(const CObjectVisitQuery & query) bool CGameHandler::buildBoat(ObjectInstanceID objid, PlayerColor playerID) { - const IShipyard *obj = IShipyard::castFrom(getObj(objid)); + const auto *obj = dynamic_cast(getObj(objid)); if (obj->shipyardStatus() != IBoatGenerator::GOOD) { diff --git a/server/NetPacksServer.cpp b/server/NetPacksServer.cpp index fc5b297fb..6ad658784 100644 --- a/server/NetPacksServer.cpp +++ b/server/NetPacksServer.cpp @@ -170,7 +170,7 @@ void ApplyGhNetPackVisitor::visitTradeOnMarketplace(TradeOnMarketplace & pack) { const CGObjectInstance * object = gh.getObj(pack.marketId); const CGHeroInstance * hero = gh.getHero(pack.heroId); - const IMarket * market = IMarket::castFrom(object); + const auto * market = dynamic_cast(object); gh.throwIfWrongPlayer(&pack);