summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFedja Beader <fedja@protonmail.ch>2025-01-23 01:39:08 +0100
committerFedja Beader <fedja@protonmail.ch>2025-01-24 01:14:30 +0100
commit1ba5b02cb9ffa83a0e8ff283f4d01d0044eb533e (patch)
tree24df2acf4790d8b1ece6e32886db653650149da3
parentd8782a82fc0cbc6b52d2f7385229cbe832562b95 (diff)
downloadtmwa-1ba5b02cb9ffa83a0e8ff283f4d01d0044eb533e.tar.gz
tmwa-1ba5b02cb9ffa83a0e8ff283f4d01d0044eb533e.tar.bz2
tmwa-1ba5b02cb9ffa83a0e8ff283f4d01d0044eb533e.tar.xz
tmwa-1ba5b02cb9ffa83a0e8ff283f4d01d0044eb533e.zip
Ensure that a continuous rise in drop rate boosts results in a continuous rise in actual drop rate.
-rw-r--r--src/generic/random.cpp4
-rw-r--r--src/generic/random.hpp14
-rw-r--r--src/generic/random.t.hpp5
-rw-r--r--src/map/mob.cpp42
4 files changed, 53 insertions, 12 deletions
diff --git a/src/generic/random.cpp b/src/generic/random.cpp
index e37a3d1..d29c984 100644
--- a/src/generic/random.cpp
+++ b/src/generic/random.cpp
@@ -25,6 +25,8 @@ namespace tmwa
{
namespace random_
{
- std::mt19937 generate{std::random_device()()};
+ std::random_device seed_class;
+ std::mt19937 generate{seed_class()};//std::random_device()()};
+ std::mt19937_64 generate64{ ((uint64_t)seed_class() << 32) + seed_class()};
} // namespace random_
} // namespace tmwa
diff --git a/src/generic/random.hpp b/src/generic/random.hpp
index 897ad43..7310e21 100644
--- a/src/generic/random.hpp
+++ b/src/generic/random.hpp
@@ -33,8 +33,10 @@ namespace random_
{
/// Get a random number from 0 .. 2**32 - 1
extern std::mt19937 generate;
+ extern std::mt19937_64 generate64;
/// Get a random number from 0 .. bound - 1
+ // TODO: Deduplicate this.
inline
int to(int bound)
{
@@ -42,6 +44,13 @@ namespace random_
return dist(generate);
}
+ inline
+ int64_t to(int64_t bound)
+ {
+ std::uniform_int_distribution<int64_t> dist(0, bound - 1);
+ return dist(generate64);
+ }
+
/// Get a random number from low .. high (inclusive!)
inline
int in(int low, int high)
@@ -58,8 +67,9 @@ namespace random_
return dist(generate);
}
+ template<typename T = int>
inline
- bool chance(Fraction f)
+ bool chance(Fraction<T> f)
{
if (f.num <= 0)
return false;
@@ -75,7 +85,7 @@ namespace random_
template<class C>
auto choice(C&& c) -> decltype(*c.begin())
{
- return *(c.begin() + random_::to(c.size()));
+ return *(c.begin() + random_::to((int64_t)c.size()));
}
// allow bare braces
diff --git a/src/generic/random.t.hpp b/src/generic/random.t.hpp
index b4c4764..985ba3b 100644
--- a/src/generic/random.t.hpp
+++ b/src/generic/random.t.hpp
@@ -25,9 +25,10 @@ namespace tmwa
{
namespace random_
{
+ template<class T = int>
struct Fraction
{
- int num, den;
+ T num, den;
};
template<class T, T den>
@@ -35,7 +36,7 @@ namespace random_
{
T num;
- operator Fraction()
+ operator Fraction<T>()
{
return {num, den};
}
diff --git a/src/map/mob.cpp b/src/map/mob.cpp
index fc41d19..6224b82 100644
--- a/src/map/mob.cpp
+++ b/src/map/mob.cpp
@@ -67,10 +67,11 @@ namespace map
{
constexpr interval_t MIN_MOBTHINKTIME = 100_ms;
+// TODO: template type deduction is a C++17+ feature.
// Move probability in the negligent mode MOB (rate of 1000 minute)
-constexpr random_::Fraction MOB_LAZYMOVEPERC {50, 1000};
+constexpr random_::Fraction<int> MOB_LAZYMOVEPERC {50, 1000};
// Warp probability in the negligent mode MOB (rate of 1000 minute)
-constexpr random_::Fraction MOB_LAZYWARPPERC {20, 1000};
+constexpr random_::Fraction<int> MOB_LAZYWARPPERC {20, 1000};
struct mob_db_& get_mob_db(Species s)
{
@@ -2735,16 +2736,43 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage,
const auto& drop_info = mob_info.dropitem[i];
if (!drop_info.nameid)
continue;
- random_::Fixed<int, 10000> drop_rate = drop_info.p;
+
+ // WARNING: possible overflows.
+ // maximum denominator: 10000*100*4*100 = 20% of INT_MAX
+ // maximum numerator is hard to predict as it depends on
+ // config/GM settings. In future, rares beyond 1:10000
+ // might be supported and so let's just use 64 bit fractions.
+ random_::Fraction<int64_t> f;
+ f.num = drop_info.p.num;
+ f.den = 10000;
+
if (sd && battle_config.drops_by_luk > 0)
- drop_rate.num += (sd->status.attrs[ATTR::LUK] * battle_config.drops_by_luk) / 100; // drops affected by luk [Valaris]
+ {
+ // You are reading this correctly, this is an additive boost.
+ // MLHerc has a multiplicative one as well.
+ //drop_rate.num += (sd->status.attrs[ATTR::LUK] * battle_config.drops_by_luk) / 100; // drops affected by luk [Valaris]
+ // n += (L*DL) / 100 => n := n + (L*DL)/100 = 100*n/100 + (L*DL)/100
+ // = (100*n + (L*DL)) / 100
+ // drops affected by luk [Valaris]
+ f.num = 100*f.num + (sd->status.attrs[ATTR::LUK] * battle_config.drops_by_luk);
+ f.den *= 100;
+ }
+
+ int64_t den_scale = 100; // avoids a division.
if (sd && battle_config.pk_mode == 1
&& (mob_info.lv - sd->status.base_level >= 20))
- drop_rate.num *= 1.25; // pk_mode increase drops if 20 level difference [Valaris]
+ {
+ //drop_rate.num *= 1.25; // pk_mode increase drops if 20 level difference [Valaris]
+ // p = (1.25 * n)/d = 5/4 * n/d = n/(4/5*d)
+ den_scale = 100/5;// Denominator is always divisible by 5
+ f.den *= 4;
+ }
// server-wide drop rate scaling
- drop_rate.num = (drop_rate.num * battle_config.drop_rate) / 100;
- if (!random_::chance(drop_rate))
+ f.num *= battle_config.drop_rate;
+ f.den *= den_scale;
+
+ if (!random_::chance(f))
continue;
struct delay_item_drop ditem {};