Jump to content

Real random number Generator using c++ library


Recommended Posts

Hello all,

I recently found how stupid number generators inside source files are.

Currently, to generate a "random" number, the system seems to use function number(x,y).

I found out that this function is an ugly version of rand() % y + x, which does not really generates random number with real distribution.

I really don't know if other files use this or better solutions, but in files related to Drop that's what it is.

 

To make the point on how stupid this (not)random system is, just take a look at this :

 

iRandRange = 4000000;

    iRandRange = iRandRange * 100 /

        (100 +

            CPrivManager::instance().GetPriv(pkKiller, PRIV_ITEM_DROP) +

            (pkKiller->IsEquipUniqueItem(UNIQUE_ITEM_DOUBLE_ITEM) ? 100 : 0));

//example "random" generation: int random_number = number(1, iRandRange)

 

Why should you make a range of 4000000 to estabilish like 0.1% of drop? lmao

 

Thus I decided to share with you a real solution, that may can help you if you are issuing the same problem/question. I found it in the web.

It uses the standard C++ random distribution, and can also be replaced with boost's one.
There is needing to spend hardware resources for generating numbers, but I guess it is not this much, so please be careful and test it before using in real servers.

 

Include random c++ library(depending on your c++ version, if not available, then use Boost)

#include <random>



Then you can use inside cycles(for, while...):

std::random_device os_seed;

const uint_least32_t seed = os_seed();

std::mt19937 generator(seed); //the hardware number generator

std::uniform_int_distribution< uint_least32_t > distribute(1, max_range); //the number distribution

 

Example usage
 

int max_range = 100;

int extractions = 100;

int percent = 10;

int total_found = 0;

std::random_device os_seed;
const uint_least32_t seed = os_seed();
std::mt19937 generator(seed);
std::uniform_int_distribution< uint_least32_t > distribute(1, max_range);

for(int i = 0; i < extractions; i++){

  if(percent >= distribute(generator)){

   std::cout << "Number found at Extraction: "<< i+1 <<"\n";
   total_found++;

  }

}

std::cout << "Total found: " << total_found << "in " << extractions << "extractions \n";


Obviously you can adapt easily on any Percent you want to obtain in your source files, just work in the max_range variable.

 

Edited by TheDragster
  • Metin2 Dev 1
Link to post

Nice one, but this doesn't solve the "why they do this for 0.1%".

They basically do a random of a long range to "emulate" it, for ex in common_drop_item, 0.1% would be: (0.4*10000)/4000000 = 0.001->0.1%, because at the end, we are still using natural numbers ( DWORD dwPct = (DWORD) (d[i].fPercent * 10000.0f);)

One possible thing to do would be to rewrite the droppct logic to calculate differently deltapercent and irandrange (which would be your max_range) and use uniform_real_distribution instead of uniform_int_distribution (so that you can use floats/dobules/long doubles and just put the actual percentage you want (as long as irandrange is 100.0). I mean, u can still do it using their logic (and uniform_int_distribution), just remembering that the effective pct is 1/4th of what you put in the txts (unless it's type level limit).

Edited by xXIntelXx
Link to post
Posted (edited)

Yes, this function is intended to be used as a replace for drop logics inside the source files.

I mean, using this function, you can "skip" the Random range calculation(e.g. 400000) and the rest; Just insert for example a range of 100 to make a drop rate(distribute(Percent,100)).
It may be useful if you are planning to make other Drop logics/types, instead of the basic ones.

It is less mechanical, and also human-readable and editable, that's the goal.

For example if you want to build a new drop logic, in which for example a mob in a map drops at 0.1%, you have to calculate iRandRage, iDelta percent and other useless things, if you do not just copy-paste percent calculation from other drop logics.
By applying this function, you will just have to insert a percent(e.g. 1%), in a range(e.g. 100).

Edited by TheDragster
Link to post
19 minutes ago, TheDragster said:

Yes, this function is intended to be used as a replace for drop logics inside the source files.

I mean, using this function, you can "skip" the Random range calculation(e.g. 400000) and the res; Just insert for example 100 to make a drop rate(distribute(Percent,100)).
It may be useful if you are planning to make other Drop logics/types, instead of the basic ones.

It is less mechanical, and also human-readable and editable, that's the goal.

For example if you want to build a new drop logic, in which for example a mob in a map drops at 0.1%, you have to calculate iRandRage, iDelta percent and other useless things.
By applying this function, you will just have to insert a percent(e.g. 1%), in a range(e.g. 100).

No, I mean, I agree. It's a pain in the ass everytime being with a calculator and be like "ok, I want idk, 13.7% but I have to do *4 and so it's 54.8% bla bla bla". For other type of drops indeed, I just used the level limit logic, disregarding the iRandRange. The issue? It doesn't take the priv_drop into account.

 

Performance wise, instead, I found an interesting page on stack overflow: https://stackoverflow.com/questions/35358501/what-is-performance-wise-the-best-way-to-generate-random-bools

Edited by xXIntelXx
Link to post
Posted (edited)
38 minutes ago, xXIntelXx said:

No, I mean, I agree. It's a pain in the ass everytime being with a calculator and be like "ok, I want idk, 13.7% but I have to do *4 and so it's 54.8% bla bla bla". For other type of drops indeed, I just used the level limit logic, disregarding the iRandRange. The issue? It doesn't take the priv_drop into account.

 

Performance wise, instead, I found an interesting page on stack overflow: https://stackoverflow.com/questions/35358501/what-is-performance-wise-the-best-way-to-generate-random-bools

Nice one, there are many generator solutions in them, but you need to find the best bottleneck in terms of performance, because any of them has different efficiency based on generations; I guess the best would be the standard or bool.

To solve your issue, if you mean priv(empire) drop rates, then just divide the rate by 100 this formulae:

int gain = (100 + priv_drop_rate) /100;

and then multiply the percent by gain;

Note: I am referring to priv drop rates taken from database(or statically declared in source files), which are usually 100 multipliers(100,200...)

The main issue I found indeed, is the gain by items’ drop bonuses(double item chance or something like): 

Examining files, I didn’t find any drop rate which uses this bonus to increase the drop pct, so I guess it’s not used? I may be wrong, or maybe it’s a mistake only in my rev, but that’s it.

I guess items’ drop bonuses should increase some POINT_PC_.._BONUS., but it’s never used.

Neither in GetDropPct function, nor that bonus is ever increased. 
If it is so, then it could be a real problem, you’ll need to work on many files for it lmao

 

Edited by TheDragster
Link to post
  • VIP
4 minutes ago, TheDragster said:

Nice one, there are many generator solutions in them, but you need to find the best bottleneck in terms of performance, because any of them has different efficiency based on generations; I guess the best would be the standard or bool.

To solve your issue, if you mean priv(empire) drop rates, then just divide the rate by 100 this formulae:

int gain = (100 + priv_drop_rate) /100;

and then multiply the percent by gain;

Note: I am referring to priv drop rates taken from database(or statically declared in source files), which are usually 100 multipliers(100,200...)

The main issue I found indeed, is the gain by items’ drop bonuses(double item chance or something like): 

Examining files, I didn’t find any drop rate which uses this bonus to increase the drop pct, so I guess it’s not used? I may be wrong, or maybe it’s a mistake only in my rev, but that’s it.

I guess items’ drop bonuses should increase some POINT_PC_.._BONUS., but it’s never used.

Neither in GetDropPct function, nor that bonus is ever increased. 
If it is so, then it could be a real problem, you’ll need to work on many files for it lmao

 

 

Yeah double drop bonus is not used by default, you must add its functionality by yourself.

I couldn't believe it either, been playing this game for 10 years in a lie haha.

Link to post
1 minute ago, TheDragster said:

Nice one, there are many generator solutions in them, but you need to find the best bottleneck in terms of performance, because any of them has different efficiency based on generations;

To solve your issue, if you mean priv(empire) drop rates, then just divide the rate by 100 this formulae:

int gain = (100 + priv_drop_rate) /100;

and then multiply the percent by gain;

Note: I am referring to priv drop rates taken from database(or statically declared in source files), which are usually 100 multipliers(100,200...)

The main issue I found indeed, is the gain by items’ drop bonuses(double item chance or something like): 

Examining files, I didn’t find any drop rate which uses this bonus to increase the drop pct, so I guess it’s not used? I may be wrong, or maybe it’s a mistake only in my rev, but that’s it.

I guess items’ drop bonuses should increase some POINT_PC_.._BONUS., but it’s never used.

Neither in GetDropPct function, nor that bonus is ever increased. 
If it is so, then it could be a real problem, you’ll need to work on many files for it lmao

 

Mh, from my sources:
 

	// ADD_PREMIUM
	if (pkKiller->IsEquipUniqueGroup(UNIQUE_GROUP_DOUBLE_ITEM))
	{
		LPITEM pkItemDrop = pkKiller->GetEquipUniqueGroup(UNIQUE_GROUP_DOUBLE_ITEM);
		unsigned int pct_from_item = 0;
		float pct_bonus = 0.0;
		if(pkItemDrop != nullptr)
		{
			pct_from_item += pkItemDrop->GetValue(1);	
			pct_bonus = (static_cast<float>(pct_from_item) / 100.0) * static_cast<float>(iDeltaPercent);
		}
		iDeltaPercent += pct_bonus;
	}
	if(pkKiller->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_DROP_BONUS))
	{
		float pct_bonus = (static_cast<float>(pkKiller->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_DROP_BONUS)) / 100.0) * static_cast<float>(iDeltaPercent);
		iDeltaPercent += pct_bonus;
	}
	// END_OF_ADD_PREMIUM

and UNIQUE_GROUP_DOUBLE_ITEM is taken from special_item_group:

Group	gloves
{
	Vnum	10002
	1	72004	1	1.00
	2	72005	1	1.00
	3	72006	1	1.00
	4	100874	1	1.00
	5	100875	1	1.00
}

usually it's iDeltaPercent += iDeltaPercent; but since I have different pcts and still only one of them can be equipped I get the pct from the item_proto

Link to post
Posted (edited)
29 minutes ago, xXIntelXx said:

Mh, from my sources:
 


	// ADD_PREMIUM
	if (pkKiller->IsEquipUniqueGroup(UNIQUE_GROUP_DOUBLE_ITEM))
	{
		LPITEM pkItemDrop = pkKiller->GetEquipUniqueGroup(UNIQUE_GROUP_DOUBLE_ITEM);
		unsigned int pct_from_item = 0;
		float pct_bonus = 0.0;
		if(pkItemDrop != nullptr)
		{
			pct_from_item += pkItemDrop->GetValue(1);	
			pct_bonus = (static_cast<float>(pct_from_item) / 100.0) * static_cast<float>(iDeltaPercent);
		}
		iDeltaPercent += pct_bonus;
	}
	if(pkKiller->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_DROP_BONUS))
	{
		float pct_bonus = (static_cast<float>(pkKiller->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_DROP_BONUS)) / 100.0) * static_cast<float>(iDeltaPercent);
		iDeltaPercent += pct_bonus;
	}
	// END_OF_ADD_PREMIUM

and UNIQUE_GROUP_DOUBLE_ITEM is taken from special_item_group:


Group	gloves
{
	Vnum	10002
	1	72004	1	1.00
	2	72005	1	1.00
	3	72006	1	1.00
	4	100874	1	1.00
	5	100875	1	1.00
}

usually it's iDeltaPercent += iDeltaPercent; but since I have different pcts and still only one of them can be equipped I get the pct from the item_proto

Yes those are thief gloves, I mean the percent in player’s equip(necklace, bracelet), which gives for example +20% double item drop Pct for both 

As sonitex said, we played this game in a lie🤣

I would probably enable it in the future, and release, if no one will do, a guide to do it

Edited by TheDragster
Link to post
1 minute ago, TheDragster said:

Yes those are thief gloves, I mean the percent in player’s equip(necklace, bracelet), which gives for example +20% double item drop Pct for both 

As sonitex said, we played this game in a lie🤣

I would probably enable it in the future, and release, if no one will do, a guide to do it

Ooooh , that one is a compleeetely different thing, in theory it should work that the bonus is a chance for the double drop, but yeah, it's completely missing in every file LOL. Also for some reason DOUBLE_EXP_BONUS is iExp += iExp * 30 / 100;

 

Legit this game is a fucking lie lol

Link to post
Posted (edited)
37 minutes ago, xXIntelXx said:

Ooooh , that one is a compleeetely different thing, in theory it should work that the bonus is a chance for the double drop, but yeah, it's completely missing in every file LOL. Also for some reason DOUBLE_EXP_BONUS is iExp += iExp * 30 / 100;

 

Legit this game is a fucking lie lol

Yes there are many faults in this source code 🤣

By the way, I found maybe how the drop bonus from items are added:

There's a Variable : POINT_PC_BANG_DROP_BONUS(iCafe exp bonus? wtf😂), which has the applytype 76, instead of ITEM_DROP_BONUS(standard one), which has apply_type 45.


That variable(76), seems to be used in drop calculation, and also increased. So I guess it should work.

Another way to make it work, could be to increase POINT_PC_BANG_DROP_BONUS by POINT_ITEM_DROP_BONUS, this way, in char.cpp:

    case POINT_EXP_DOUBLE_BONUS:    // 71
    case POINT_GOLD_DOUBLE_BONUS:    // 72

//remove from here case POINT_ITEM_DROP_BONUS:    // 73
    case POINT_POTION_BONUS:    // 74
        if (GetPoint(type) + amount > 100)
        {
            sys_err("BONUS exceeded over 100!! point type: %d name: %s amount %d", type, GetName(), amount);
            amount = 100 - GetPoint(type);
        }

        SetPoint(type, GetPoint(type) + amount);
        val = GetPoint(type);
        break;

//add here case POINT_ITEM_DROP_BONUS:    // 73    
        SetPoint(POINT_PC_BANG_DROP_BONUS, amount);
        val = GetPoint(POINT_PC_BANG_DROP_BONUS);
        break;

 

Also if you want use this variable in standard drops, check out GetDropPct function, and remove the check to pc is PC_Bang

Edited by TheDragster
Link to post

I attended the webinar on Python advanced learning hosted by this forum for python developers. It's a great experience. Thanks for shared the latest updates and some practical tips. I also must add this comapny to your thread https://mlsdev.com

Edited by glenmclan
  • Confused 1
Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.