mirror of
https://github.com/vcmi/vcmi.git
synced 2025-06-12 23:57:33 +02:00
Do not use floating point equality checks
This commit is contained in:
parent
9ebd194ab1
commit
7359b66f99
@ -62,16 +62,12 @@ void DamageCache::buildDamageCache(std::shared_ptr<HypotheticBattle> hb, int sid
|
|||||||
|
|
||||||
int64_t DamageCache::getDamage(const battle::Unit * attacker, const battle::Unit * defender, std::shared_ptr<CBattleInfoCallback> hb)
|
int64_t DamageCache::getDamage(const battle::Unit * attacker, const battle::Unit * defender, std::shared_ptr<CBattleInfoCallback> 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);
|
cacheDamage(attacker, defender, hb);
|
||||||
|
|
||||||
damage = damageCache[attacker->unitId()][defender->unitId()] * attacker->getCount();
|
return damageCache[attacker->unitId()][defender->unitId()] * attacker->getCount();
|
||||||
}
|
|
||||||
|
|
||||||
return static_cast<int64_t>(damage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t DamageCache::getOriginalDamage(const battle::Unit * attacker, const battle::Unit * defender, std::shared_ptr<CBattleInfoCallback> hb)
|
int64_t DamageCache::getOriginalDamage(const battle::Unit * attacker, const battle::Unit * defender, std::shared_ptr<CBattleInfoCallback> hb)
|
||||||
|
@ -270,7 +270,7 @@ EvaluationResult BattleExchangeEvaluator::findBestTarget(
|
|||||||
{
|
{
|
||||||
float score = evaluateExchange(ap, 0, targets, damageCache, hb);
|
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.score = score;
|
||||||
result.bestAttack = ap;
|
result.bestAttack = ap;
|
||||||
|
@ -632,7 +632,8 @@ void AIGateway::showBlockingDialog(const std::string & text, const std::vector<C
|
|||||||
auto topObj = objects.front()->id == hero->id ? objects.back() : objects.front();
|
auto topObj = objects.front()->id == hero->id ? objects.back() : objects.front();
|
||||||
auto objType = topObj->ID; // top object should be our hero
|
auto objType = topObj->ID; // top object should be our hero
|
||||||
auto goalObjectID = nullkiller->getTargetObject();
|
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<float>(danger) / hero->getTotalStrength();
|
||||||
|
|
||||||
answer = topObj->id == goalObjectID; // no if we do not aim to visit this object
|
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);
|
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<C
|
|||||||
}
|
}
|
||||||
else if(objType == Obj::ARTIFACT || objType == Obj::RESOURCE)
|
else if(objType == Obj::ARTIFACT || objType == Obj::RESOURCE)
|
||||||
{
|
{
|
||||||
bool dangerUnknown = ratio == 0;
|
bool dangerUnknown = danger == 0;
|
||||||
bool dangerTooHigh = ratio > (1 / SAFE_ATTACK_CONSTANT);
|
bool dangerTooHigh = ratio > (1 / SAFE_ATTACK_CONSTANT);
|
||||||
|
|
||||||
answer = !dangerUnknown && !dangerTooHigh;
|
answer = !dangerUnknown && !dangerTooHigh;
|
||||||
|
@ -226,7 +226,7 @@ void DangerHitMapAnalyzer::calculateTileOwners()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ourDistance == enemyDistance)
|
if(vstd::isAlmostEqual(ourDistance, enemyDistance))
|
||||||
{
|
{
|
||||||
hitMap[pos.x][pos.y][pos.z].closestTown = nullptr;
|
hitMap[pos.x][pos.y][pos.z].closestTown = nullptr;
|
||||||
}
|
}
|
||||||
|
13
Global.h
13
Global.h
@ -685,6 +685,19 @@ namespace vstd
|
|||||||
return a + (b - a) * f;
|
return a + (b - a) * f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Floating>
|
||||||
|
bool isAlmostZero(const Floating & value)
|
||||||
|
{
|
||||||
|
constexpr Floating epsilon(0.00001);
|
||||||
|
return std::abs(value) < epsilon;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Floating1, typename Floating2>
|
||||||
|
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
|
///compile-time version of std::abs for ints for int3, in clang++15 std::abs is constexpr
|
||||||
static constexpr int abs(int i) {
|
static constexpr int abs(int i) {
|
||||||
if(i < 0) return -i;
|
if(i < 0) return -i;
|
||||||
|
@ -141,7 +141,7 @@ void MapViewCache::update(const std::shared_ptr<IMapRendererContext> & context)
|
|||||||
void MapViewCache::render(const std::shared_ptr<IMapRendererContext> & context, Canvas & target, bool fullRedraw)
|
void MapViewCache::render(const std::shared_ptr<IMapRendererContext> & context, Canvas & target, bool fullRedraw)
|
||||||
{
|
{
|
||||||
bool mapMoved = (cachedPosition != model->getMapViewCenter());
|
bool mapMoved = (cachedPosition != model->getMapViewCenter());
|
||||||
bool lazyUpdate = !mapMoved && !fullRedraw && context->viewTransitionProgress() == 0;
|
bool lazyUpdate = !mapMoved && !fullRedraw && vstd::isAlmostZero(context->viewTransitionProgress());
|
||||||
|
|
||||||
Rect dimensions = model->getTilesTotalRect();
|
Rect dimensions = model->getTilesTotalRect();
|
||||||
|
|
||||||
@ -184,7 +184,7 @@ void MapViewCache::render(const std::shared_ptr<IMapRendererContext> & context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(context->viewTransitionProgress() != 0)
|
if(!vstd::isAlmostZero(context->viewTransitionProgress()))
|
||||||
target.drawTransparent(*terrainTransition, Point(0, 0), 1.0 - context->viewTransitionProgress());
|
target.drawTransparent(*terrainTransition, Point(0, 0), 1.0 - context->viewTransitionProgress());
|
||||||
|
|
||||||
cachedPosition = model->getMapViewCenter();
|
cachedPosition = model->getMapViewCenter();
|
||||||
|
@ -41,10 +41,10 @@ bool ColorFilter::operator != (const ColorFilter & other) const
|
|||||||
bool ColorFilter::operator == (const ColorFilter & other) const
|
bool ColorFilter::operator == (const ColorFilter & other) const
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
r.r == other.r.r && r.g && other.r.g && r.b == other.r.b && r.a == other.r.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) &&
|
||||||
g.r == other.g.r && g.g && other.g.g && g.b == other.g.b && g.a == other.g.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) &&
|
||||||
b.r == other.b.r && b.g && other.b.g && b.b == other.b.b && b.a == other.b.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) &&
|
||||||
a == other.a;
|
vstd::isAlmostEqual(a, other.a);
|
||||||
}
|
}
|
||||||
|
|
||||||
ColorFilter ColorFilter::genEmptyShifter( )
|
ColorFilter ColorFilter::genEmptyShifter( )
|
||||||
|
@ -21,23 +21,24 @@
|
|||||||
|
|
||||||
void CSlider::mouseDragged(const Point & cursorPosition, const Point & lastUpdateDistance)
|
void CSlider::mouseDragged(const Point & cursorPosition, const Point & lastUpdateDistance)
|
||||||
{
|
{
|
||||||
double v = 0;
|
double newPosition = 0;
|
||||||
if(getOrientation() == Orientation::HORIZONTAL)
|
if(getOrientation() == Orientation::HORIZONTAL)
|
||||||
{
|
{
|
||||||
v = cursorPosition.x - pos.x - 24;
|
newPosition = cursorPosition.x - pos.x - 24;
|
||||||
v *= positions;
|
newPosition *= positions;
|
||||||
v /= (pos.w - 48);
|
newPosition /= (pos.w - 48);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
v = cursorPosition.y - pos.y - 24;
|
newPosition = cursorPosition.y - pos.y - 24;
|
||||||
v *= positions;
|
newPosition *= positions;
|
||||||
v /= (pos.h - 48);
|
newPosition /= (pos.h - 48);
|
||||||
}
|
}
|
||||||
v += 0.5;
|
|
||||||
if(v!=value)
|
int positionInteger = std::round(newPosition);
|
||||||
|
if(positionInteger != value)
|
||||||
{
|
{
|
||||||
scrollTo(static_cast<int>(v));
|
scrollTo(static_cast<int>(newPosition));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -844,8 +844,8 @@ void CCreatureHandler::loadUnitAnimInfo(JsonNode & graphics, CLegacyConfigParser
|
|||||||
missile["attackClimaxFrame"].Float() = parser.readNumber();
|
missile["attackClimaxFrame"].Float() = parser.readNumber();
|
||||||
|
|
||||||
// assume that creature is not a shooter and should not have whole missile field
|
// assume that creature is not a shooter and should not have whole missile field
|
||||||
if (missile["frameAngles"].Vector()[0].Float() == 0 &&
|
if (missile["frameAngles"].Vector()[0].Integer() == 0 &&
|
||||||
missile["attackClimaxFrame"].Float() == 0)
|
missile["attackClimaxFrame"].Integer() == 0)
|
||||||
graphics.Struct().erase("missile");
|
graphics.Struct().erase("missile");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -987,10 +987,10 @@ void CCreatureHandler::loadStackExperience(CCreature * creature, const JsonNode
|
|||||||
int lastVal = 0;
|
int lastVal = 0;
|
||||||
for (const JsonNode &val : values)
|
for (const JsonNode &val : values)
|
||||||
{
|
{
|
||||||
if (val.Float() != lastVal)
|
if (val.Integer() != lastVal)
|
||||||
{
|
{
|
||||||
JsonNode bonusInput = exp["bonus"];
|
JsonNode bonusInput = exp["bonus"];
|
||||||
bonusInput["val"].Float() = static_cast<int>(val.Float()) - lastVal;
|
bonusInput["val"].Float() = val.Integer() - lastVal;
|
||||||
|
|
||||||
auto bonus = JsonUtils::parseBonus (bonusInput);
|
auto bonus = JsonUtils::parseBonus (bonusInput);
|
||||||
bonus->source = BonusSource::STACK_EXPERIENCE;
|
bonus->source = BonusSource::STACK_EXPERIENCE;
|
||||||
|
@ -113,23 +113,6 @@ public:
|
|||||||
return *this;
|
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 (z<i.z)
|
|
||||||
return true;
|
|
||||||
if (z>i.z)
|
|
||||||
return false;
|
|
||||||
if (y<i.y)
|
|
||||||
return true;
|
|
||||||
if (y>i.y)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return x<i.x;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toString() const
|
std::string toString() const
|
||||||
{
|
{
|
||||||
return "(" + std::to_string(x) +
|
return "(" + std::to_string(x) +
|
||||||
|
Loading…
x
Reference in New Issue
Block a user