mirror of
https://github.com/wesnoth/wesnoth
synced 2025-04-28 10:25:29 +00:00

(rounding of other attacks continue to be >0) This also fix round_damage() which was supposed to round towards base_damage, but was incorrect for 2 cases: when dividing by 1 (D/1 give D-1, but currently not used) and when base_damage was 0.
183 lines
4.5 KiB
C++
183 lines
4.5 KiB
C++
/* $Id$ */
|
|
/*
|
|
Copyright (C) 2003 - 2009 by David White <dave@whitevine.net>
|
|
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License version 2
|
|
or at your option any later version.
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY.
|
|
|
|
See the COPYING file for more details.
|
|
*/
|
|
|
|
/**
|
|
* @file util.hpp
|
|
* Templates and utility-routines for strings and numbers.
|
|
*/
|
|
|
|
#ifndef UTIL_H_INCLUDED
|
|
#define UTIL_H_INCLUDED
|
|
|
|
#include "global.hpp"
|
|
#include "wesconfig.h"
|
|
#include <cmath>
|
|
#include <vector>
|
|
#include <sstream>
|
|
|
|
template<typename T>
|
|
inline bool is_odd(T num) {
|
|
int n = static_cast< int >(num);
|
|
return static_cast< unsigned int >(n >= 0 ? n : -n) & 1;
|
|
}
|
|
|
|
template<typename T>
|
|
inline bool is_even(T num) { return !is_odd(num); }
|
|
|
|
/** Guarantees portable results for division by 100; round towards 0 */
|
|
inline int div100rounded(int num) {
|
|
return (num < 0) ? -(((-num) + 49) / 100) : (num + 49) / 100;
|
|
}
|
|
|
|
/**
|
|
* round (base_damage * bonus / divisor) to the closest integer,
|
|
* but up or down towards base_damage
|
|
*/
|
|
inline int round_damage(int base_damage, int bonus, int divisor) {
|
|
if (base_damage==0) return 0;
|
|
const int rounding = divisor / 2 - (bonus < divisor || divisor==1 ? 0 : 1);
|
|
return std::max<int>(1, (base_damage * bonus + rounding) / divisor);
|
|
}
|
|
|
|
// not guaranteed to have exactly the same result on different platforms
|
|
inline int round_double(double d) {
|
|
#ifdef HAVE_ROUND
|
|
return static_cast<int>(round(d)); //surprisingly, not implemented everywhere
|
|
#else
|
|
return static_cast<int>((d >= 0.0)? std::floor(d + 0.5) : std::ceil(d - 0.5));
|
|
#endif
|
|
}
|
|
|
|
// Guaranteed to have portable results across different platforms
|
|
inline double round_portable(double d) {
|
|
return (d >= 0.0) ? std::floor(d + 0.5) : std::ceil(d - 0.5);
|
|
}
|
|
|
|
struct bad_lexical_cast {};
|
|
|
|
template<typename To, typename From>
|
|
To lexical_cast(From a)
|
|
{
|
|
To res;
|
|
std::stringstream str;
|
|
|
|
if(!(str << a && str >> res)) {
|
|
throw bad_lexical_cast();
|
|
} else {
|
|
return res;
|
|
}
|
|
}
|
|
|
|
template<typename To, typename From>
|
|
To lexical_cast_default(From a, To def=To())
|
|
{
|
|
To res;
|
|
std::stringstream str;
|
|
|
|
if(!(str << a && str >> res)) {
|
|
return def;
|
|
} else {
|
|
return res;
|
|
}
|
|
}
|
|
|
|
template<>
|
|
int lexical_cast<int, const std::string&>(const std::string& a);
|
|
|
|
template<>
|
|
int lexical_cast<int, const char*>(const char* a);
|
|
|
|
template<>
|
|
int lexical_cast_default<int, const std::string&>(const std::string& a, int def);
|
|
|
|
template<>
|
|
int lexical_cast_default<int, const char*>(const char* a, int def);
|
|
|
|
template<typename From>
|
|
std::string str_cast(From a)
|
|
{
|
|
return lexical_cast<std::string,From>(a);
|
|
}
|
|
|
|
template<typename To, typename From>
|
|
To lexical_cast_in_range(From a, To def, To min, To max)
|
|
{
|
|
To res;
|
|
std::stringstream str;
|
|
|
|
if(!(str << a && str >> res)) {
|
|
return def;
|
|
} else {
|
|
if(res < min) {
|
|
return min;
|
|
}
|
|
if(res > max) {
|
|
return max;
|
|
}
|
|
return res;
|
|
}
|
|
}
|
|
|
|
template<typename Cmp>
|
|
bool in_ranges(const Cmp c, const std::vector<std::pair<Cmp, Cmp> >&ranges) {
|
|
typename std::vector<std::pair<Cmp,Cmp> >::const_iterator range,
|
|
range_end = ranges.end();
|
|
for (range = ranges.begin(); range != range_end; ++range) {
|
|
if(range->first <= c && c <= range->second) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
inline bool chars_equal_insensitive(char a, char b) { return tolower(a) == tolower(b); }
|
|
inline bool chars_less_insensitive(char a, char b) { return tolower(a) < tolower(b); }
|
|
|
|
#ifdef __GNUC__
|
|
#define LIKELY(a) __builtin_expect((a),1) // Tells GCC to optimize code so that if is likely to happen
|
|
#define UNLIKELY(a) __builtin_expect((a),0) // Tells GCC to optimize code so that if is unlikely to happen
|
|
#else
|
|
#define LIKELY(a) a
|
|
#define UNLIKELY(a) a
|
|
#endif
|
|
|
|
|
|
#if 1
|
|
# include <SDL_types.h>
|
|
typedef Sint32 fixed_t;
|
|
# define fxp_shift 8
|
|
# define fxp_base (1 << fxp_shift)
|
|
|
|
/** IN: float or int - OUT: fixed_t */
|
|
# define ftofxp(x) (fixed_t((x) * fxp_base))
|
|
|
|
/** IN: unsigned and fixed_t - OUT: unsigned */
|
|
# define fxpmult(x,y) (((x)*(y)) >> fxp_shift)
|
|
|
|
/** IN: unsigned and int - OUT: fixed_t */
|
|
# define fxpdiv(x,y) (((x) << fxp_shift) / (y))
|
|
|
|
/** IN: fixed_t - OUT: int */
|
|
# define fxptoi(x) ( ((x)>0) ? ((x) >> fxp_shift) : (-((-(x)) >> fxp_shift)) )
|
|
|
|
#else
|
|
typedef float fixed_t;
|
|
# define ftofxp(x) (x)
|
|
# define fxpmult(x,y) ((x)*(y))
|
|
# define fxpdiv(x,y) (static_cast<float>(x) / static_cast<float>(y))
|
|
# define fxptoi(x) ( static_cast<int>(x) )
|
|
#endif
|
|
|
|
#endif
|