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.

  • Metin2 Dev 1
Link to comment
Share on other sites

  • Premium

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 comment
Share on other sites

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 comment
Share on other sites

  • Premium
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 comment
Share on other sites

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 comment
Share on other sites

  • Premium
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 comment
Share on other sites

  • Premium
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 comment
Share on other sites

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 comment
Share on other sites

  • Premium
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 comment
Share on other sites

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 comment
Share on other sites

  • 1 year later...
On 4/2/2021 at 1:36 PM, Sonitex said:

 

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.

 

On 4/2/2021 at 2:09 PM, 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

I didn't even look at the source files but if you read the ingame description for double drop on equippable items it says it gives a chance to drop 2 items, instead of 1.

OBVIOUSLY this means somewhere there is a seperate calculation for the chance to drop a second item after one has already been determined to be dropped.

The only thing that's a lie here is the myth of Pserver devs being competent at all :)

Link to comment
Share on other sites

  • Premium
4 minutes ago, LMAOAtWannabeDevs said:

 

I didn't even look at the source files but if you read the ingame description for double drop on equippable items it says it gives a chance to drop 2 items, instead of 1.

OBVIOUSLY this means somewhere there is a seperate calculation for the chance to drop a second item after one has already been determined to be dropped.

The only thing that's a lie here is the myth of Pserver devs being competent at all 🙂

I'd love to see that separate item drop calculation of yours 🤡

  • Love 1
  • Love 1
Link to comment
Share on other sites

35 minutes ago, Sonitex said:

I'd love to see that separate item drop calculation of yours 🤡

Maybe I will look at the source files myself at some point but right now I'd rather just play on official servers 🙂

Since I have personally experienced the "double drop" since using a bracelet with 20% DD on DE server, I am quite convinced it has to be implemented somewhere.

It is especially noticeable when farming dragon stone shards, because the 2 dropped shards will in those instances be stackable, which is normally (unfortunately) not the case.

 

I stumbled upon this thread by googling for "metin2 random number generator" and don't want some baseless accusations of faulty coding stand uncontested in case other people come here the same way.

  • kekw 2
Link to comment
Share on other sites

  • Premium
1 hour ago, LMAOAtWannabeDevs said:

Maybe I will look at the source files myself at some point but right now I'd rather just play on official servers 🙂

Since I have personally experienced the "double drop" since using a bracelet with 20% DD on DE server, I am quite convinced it has to be implemented somewhere.

It is especially noticeable when farming dragon stone shards, because the 2 dropped shards will in those instances be stackable, which is normally (unfortunately) not the case.

 

I stumbled upon this thread by googling for "metin2 random number generator" and don't want some baseless accusations of faulty coding stand uncontested in case other people come here the same way.

// cmd_general.cpp
case POINT_ITEM_DROP_BONUS:	return LC_TEXT("%d%% 확률로 적퇴치시 아이템 2배 드롭"); 

// constants.cpp
{ POINT_ITEM_DROP_BONUS,	        },   // APPLY_ITEM_DROP_BONUS,	45 

// char.cpp
case POINT_ITEM_DROP_BONUS:	// 73  
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;

// char.h
POINT_ITEM_DROP_BONUS,		// 85 

Taken from the original source, this are all the referenced points.

 

void CHARACTER::Reward(bool bItemDrop)
{
	if (GetRaceNum() == 5001) // їЦ±ёґВ µ·А» №«Б¶°З µе·У
	{
		PIXEL_POSITION pos;

		if (!SECTREE_MANAGER::instance().GetMovablePosition(GetMapIndex(), GetX(), GetY(), pos))
			return;

		LPITEM item;
		int iGold = number(GetMobTable().dwGoldMin, GetMobTable().dwGoldMax);
		iGold = iGold * CHARACTER_MANAGER::instance().GetMobGoldAmountRate(NULL) / 100;
		iGold *= GetGoldMultipler();
		int iSplitCount = number(25, 35);

		sys_log(0, "WAEGU Dead gold %d split %d", iGold, iSplitCount);

		for (int i = 1; i <= iSplitCount; ++i)
		{
			if ((item = ITEM_MANAGER::instance().CreateItem(1, iGold / iSplitCount)))
			{
				if (i != 0)
				{
					pos.x = number(-7, 7) * 20;
					pos.y = number(-7, 7) * 20;

					pos.x += GetX();
					pos.y += GetY();
				}

				item->AddToGround(GetMapIndex(), pos);
				item->StartDestroyEvent();
			}
		}
		return;
	}

	//PROF_UNIT puReward("Reward");
   	LPCHARACTER pkAttacker = DistributeExp();

	if (!pkAttacker)
		return;

	//PROF_UNIT pu1("r1");
	if (pkAttacker->IsPC())
	{
		if (GetLevel() - pkAttacker->GetLevel() >= -10)
			if (pkAttacker->GetRealAlignment() < 0)
			{
				if (pkAttacker->IsEquipUniqueItem(UNIQUE_ITEM_FASTER_ALIGNMENT_UP_BY_KILL))
					pkAttacker->UpdateAlignment(14);
				else
					pkAttacker->UpdateAlignment(7);
			}
			else
				pkAttacker->UpdateAlignment(2);

		pkAttacker->SetQuestNPCID(GetVID());
		quest::CQuestManager::instance().Kill(pkAttacker->GetPlayerID(), GetRaceNum());
		CHARACTER_MANAGER::instance().KillLog(GetRaceNum());

		if (!number(0, 9))
		{
			if (pkAttacker->GetPoint(POINT_KILL_HP_RECOVERY))
			{
				int iHP = pkAttacker->GetMaxHP() * pkAttacker->GetPoint(POINT_KILL_HP_RECOVERY) / 100;
				pkAttacker->PointChange(POINT_HP, iHP);
				CreateFly(FLY_HP_SMALL, pkAttacker);
			}

			if (pkAttacker->GetPoint(POINT_KILL_SP_RECOVER))
			{
				int iSP = pkAttacker->GetMaxSP() * pkAttacker->GetPoint(POINT_KILL_SP_RECOVER) / 100;
				pkAttacker->PointChange(POINT_SP, iSP);
				CreateFly(FLY_SP_SMALL, pkAttacker);
			}
		}
	}
	//pu1.Pop();

	if (!bItemDrop)
		return;

	PIXEL_POSITION pos = GetXYZ();

	if (!SECTREE_MANAGER::instance().GetMovablePosition(GetMapIndex(), pos.x, pos.y, pos))
		return;

	//
	// µ· µе·У
	//
	//PROF_UNIT pu2("r2");
	if (test_server)
		sys_log(0, "Drop money : Attacker %s", pkAttacker->GetName());
	RewardGold(pkAttacker);
	//pu2.Pop();

	//
	// ѕЖАМЕЫ µе·У
	//
	//PROF_UNIT pu3("r3");
	LPITEM item;

	static std::vector<LPITEM> s_vec_item;
	s_vec_item.clear();

	if (ITEM_MANAGER::instance().CreateDropItem(this, pkAttacker, s_vec_item))
	{
		if (s_vec_item.size() == 0);
		else if (s_vec_item.size() == 1)
		{
			item = s_vec_item[0];
			item->AddToGround(GetMapIndex(), pos);

			if (CBattleArena::instance().IsBattleArenaMap(pkAttacker->GetMapIndex()) == false)
			{
				item->SetOwnership(pkAttacker);
			}

			item->StartDestroyEvent();

			pos.x = number(-7, 7) * 20;
			pos.y = number(-7, 7) * 20;
			pos.x += GetX();
			pos.y += GetY();

			sys_log(0, "DROP_ITEM: %s %d %d from %s", item->GetName(), pos.x, pos.y, GetName());
		}
		else
		{
			int iItemIdx = s_vec_item.size() - 1;

			std::priority_queue<std::pair<int, LPCHARACTER> > pq;

			int total_dam = 0;

			for (TDamageMap::iterator it = m_map_kDamage.begin(); it != m_map_kDamage.end(); ++it)
			{
				int iDamage = it->second.iTotalDamage;
				if (iDamage > 0)
				{
					LPCHARACTER ch = CHARACTER_MANAGER::instance().Find(it->first);

					if (ch)
					{
						pq.push(std::make_pair(iDamage, ch));
						total_dam += iDamage;
					}
				}
			}

			std::vector<LPCHARACTER> v;

			while (!pq.empty() && pq.top().first * 10 >= total_dam)
			{
				v.push_back(pq.top().second);
				pq.pop();
			}

			if (v.empty())
			{
				// µҐ№МБцё¦ ЖЇє°Ич ё№АМ БШ »з¶чАМ ѕшАёґП јТАЇ±З ѕшАЅ
				while (iItemIdx >= 0)
				{
					item = s_vec_item[iItemIdx--];

					if (!item)
					{
						sys_err("item null in vector idx %d", iItemIdx + 1);
						continue;
					}

					item->AddToGround(GetMapIndex(), pos);
					// 10% АМЗП µҐ№МБц БШ »з¶чіўё®ґВ јТАЇ±ЗѕшАЅ
					//item->SetOwnership(pkAttacker);
					item->StartDestroyEvent();

					pos.x = number(-7, 7) * 20;
					pos.y = number(-7, 7) * 20;
					pos.x += GetX();
					pos.y += GetY();

					sys_log(0, "DROP_ITEM: %s %d %d by %s", item->GetName(), pos.x, pos.y, GetName());
				}
			}
			else
			{
				// µҐ№МБц ё№АМ БШ »з¶чµй іўё®ёё јТАЇ±З іЄґІ°ЎБь
				std::vector<LPCHARACTER>::iterator it = v.begin();

				while (iItemIdx >= 0)
				{
					item = s_vec_item[iItemIdx--];

					if (!item)
					{
						sys_err("item null in vector idx %d", iItemIdx + 1);
						continue;
					}

					item->AddToGround(GetMapIndex(), pos);

					LPCHARACTER ch = *it;

					if (ch->GetParty())
						ch = ch->GetParty()->GetNextOwnership(ch, GetX(), GetY());

					++it;

					if (it == v.end())
						it = v.begin();

					if (CBattleArena::instance().IsBattleArenaMap(ch->GetMapIndex()) == false)
					{
						item->SetOwnership(ch);
					}

					item->StartDestroyEvent();

					pos.x = number(-7, 7) * 20;
					pos.y = number(-7, 7) * 20;
					pos.x += GetX();
					pos.y += GetY();

					sys_log(0, "DROP_ITEM: %s %d %d by %s", item->GetName(), pos.x, pos.y, GetName());
				}
			}
		}
	}

	m_map_kDamage.clear();
}

Default Reward function.

 

The only thing that actually adds some kind of calculation is ITEM_MANAGER::GetDropPct:

bool ITEM_MANAGER::GetDropPct(LPCHARACTER pkChr, LPCHARACTER pkKiller, OUT int& iDeltaPercent, OUT int& iRandRange)
{
 	if (NULL == pkChr || NULL == pkKiller)
		return false;

	.....

	iRandRange = 4000000;
	iRandRange = iRandRange * 100 / 
		(100 + 
		 CPrivManager::instance().GetPriv(pkKiller, PRIV_ITEM_DROP) + 
		 pkKiller->IsEquipUniqueItem(UNIQUE_ITEM_DOUBLE_ITEM)?100:0);

	if (distribution_test_server) iRandRange /= 3;

	return true;
}

// And the UNIQUE_ITEM_DOUBLE_ITEM is Thief's Gloves.

Please tell me where is the calculation for the Chance to drop double the Items/POINT_ITEM_DROP_BONUS.

 

Don't use your arguments by saying "it works on the official ones, so you're wrong", prove us wrong by using facts.

Link to comment
Share on other sites

  • Premium
1 hour ago, msnas said:
// cmd_general.cpp
case POINT_ITEM_DROP_BONUS:	return LC_TEXT("%d%% 확률로 적퇴치시 아이템 2배 드롭"); 

// constants.cpp
{ POINT_ITEM_DROP_BONUS,	        },   // APPLY_ITEM_DROP_BONUS,	45 

// char.cpp
case POINT_ITEM_DROP_BONUS:	// 73  
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;

// char.h
POINT_ITEM_DROP_BONUS,		// 85 

Taken from the original source, this are all the referenced points.

 

void CHARACTER::Reward(bool bItemDrop)
{
	if (GetRaceNum() == 5001) // їЦ±ёґВ µ·А» №«Б¶°З µе·У
	{
		PIXEL_POSITION pos;

		if (!SECTREE_MANAGER::instance().GetMovablePosition(GetMapIndex(), GetX(), GetY(), pos))
			return;

		LPITEM item;
		int iGold = number(GetMobTable().dwGoldMin, GetMobTable().dwGoldMax);
		iGold = iGold * CHARACTER_MANAGER::instance().GetMobGoldAmountRate(NULL) / 100;
		iGold *= GetGoldMultipler();
		int iSplitCount = number(25, 35);

		sys_log(0, "WAEGU Dead gold %d split %d", iGold, iSplitCount);

		for (int i = 1; i <= iSplitCount; ++i)
		{
			if ((item = ITEM_MANAGER::instance().CreateItem(1, iGold / iSplitCount)))
			{
				if (i != 0)
				{
					pos.x = number(-7, 7) * 20;
					pos.y = number(-7, 7) * 20;

					pos.x += GetX();
					pos.y += GetY();
				}

				item->AddToGround(GetMapIndex(), pos);
				item->StartDestroyEvent();
			}
		}
		return;
	}

	//PROF_UNIT puReward("Reward");
   	LPCHARACTER pkAttacker = DistributeExp();

	if (!pkAttacker)
		return;

	//PROF_UNIT pu1("r1");
	if (pkAttacker->IsPC())
	{
		if (GetLevel() - pkAttacker->GetLevel() >= -10)
			if (pkAttacker->GetRealAlignment() < 0)
			{
				if (pkAttacker->IsEquipUniqueItem(UNIQUE_ITEM_FASTER_ALIGNMENT_UP_BY_KILL))
					pkAttacker->UpdateAlignment(14);
				else
					pkAttacker->UpdateAlignment(7);
			}
			else
				pkAttacker->UpdateAlignment(2);

		pkAttacker->SetQuestNPCID(GetVID());
		quest::CQuestManager::instance().Kill(pkAttacker->GetPlayerID(), GetRaceNum());
		CHARACTER_MANAGER::instance().KillLog(GetRaceNum());

		if (!number(0, 9))
		{
			if (pkAttacker->GetPoint(POINT_KILL_HP_RECOVERY))
			{
				int iHP = pkAttacker->GetMaxHP() * pkAttacker->GetPoint(POINT_KILL_HP_RECOVERY) / 100;
				pkAttacker->PointChange(POINT_HP, iHP);
				CreateFly(FLY_HP_SMALL, pkAttacker);
			}

			if (pkAttacker->GetPoint(POINT_KILL_SP_RECOVER))
			{
				int iSP = pkAttacker->GetMaxSP() * pkAttacker->GetPoint(POINT_KILL_SP_RECOVER) / 100;
				pkAttacker->PointChange(POINT_SP, iSP);
				CreateFly(FLY_SP_SMALL, pkAttacker);
			}
		}
	}
	//pu1.Pop();

	if (!bItemDrop)
		return;

	PIXEL_POSITION pos = GetXYZ();

	if (!SECTREE_MANAGER::instance().GetMovablePosition(GetMapIndex(), pos.x, pos.y, pos))
		return;

	//
	// µ· µе·У
	//
	//PROF_UNIT pu2("r2");
	if (test_server)
		sys_log(0, "Drop money : Attacker %s", pkAttacker->GetName());
	RewardGold(pkAttacker);
	//pu2.Pop();

	//
	// ѕЖАМЕЫ µе·У
	//
	//PROF_UNIT pu3("r3");
	LPITEM item;

	static std::vector<LPITEM> s_vec_item;
	s_vec_item.clear();

	if (ITEM_MANAGER::instance().CreateDropItem(this, pkAttacker, s_vec_item))
	{
		if (s_vec_item.size() == 0);
		else if (s_vec_item.size() == 1)
		{
			item = s_vec_item[0];
			item->AddToGround(GetMapIndex(), pos);

			if (CBattleArena::instance().IsBattleArenaMap(pkAttacker->GetMapIndex()) == false)
			{
				item->SetOwnership(pkAttacker);
			}

			item->StartDestroyEvent();

			pos.x = number(-7, 7) * 20;
			pos.y = number(-7, 7) * 20;
			pos.x += GetX();
			pos.y += GetY();

			sys_log(0, "DROP_ITEM: %s %d %d from %s", item->GetName(), pos.x, pos.y, GetName());
		}
		else
		{
			int iItemIdx = s_vec_item.size() - 1;

			std::priority_queue<std::pair<int, LPCHARACTER> > pq;

			int total_dam = 0;

			for (TDamageMap::iterator it = m_map_kDamage.begin(); it != m_map_kDamage.end(); ++it)
			{
				int iDamage = it->second.iTotalDamage;
				if (iDamage > 0)
				{
					LPCHARACTER ch = CHARACTER_MANAGER::instance().Find(it->first);

					if (ch)
					{
						pq.push(std::make_pair(iDamage, ch));
						total_dam += iDamage;
					}
				}
			}

			std::vector<LPCHARACTER> v;

			while (!pq.empty() && pq.top().first * 10 >= total_dam)
			{
				v.push_back(pq.top().second);
				pq.pop();
			}

			if (v.empty())
			{
				// µҐ№МБцё¦ ЖЇє°Ич ё№АМ БШ »з¶чАМ ѕшАёґП јТАЇ±З ѕшАЅ
				while (iItemIdx >= 0)
				{
					item = s_vec_item[iItemIdx--];

					if (!item)
					{
						sys_err("item null in vector idx %d", iItemIdx + 1);
						continue;
					}

					item->AddToGround(GetMapIndex(), pos);
					// 10% АМЗП µҐ№МБц БШ »з¶чіўё®ґВ јТАЇ±ЗѕшАЅ
					//item->SetOwnership(pkAttacker);
					item->StartDestroyEvent();

					pos.x = number(-7, 7) * 20;
					pos.y = number(-7, 7) * 20;
					pos.x += GetX();
					pos.y += GetY();

					sys_log(0, "DROP_ITEM: %s %d %d by %s", item->GetName(), pos.x, pos.y, GetName());
				}
			}
			else
			{
				// µҐ№МБц ё№АМ БШ »з¶чµй іўё®ёё јТАЇ±З іЄґІ°ЎБь
				std::vector<LPCHARACTER>::iterator it = v.begin();

				while (iItemIdx >= 0)
				{
					item = s_vec_item[iItemIdx--];

					if (!item)
					{
						sys_err("item null in vector idx %d", iItemIdx + 1);
						continue;
					}

					item->AddToGround(GetMapIndex(), pos);

					LPCHARACTER ch = *it;

					if (ch->GetParty())
						ch = ch->GetParty()->GetNextOwnership(ch, GetX(), GetY());

					++it;

					if (it == v.end())
						it = v.begin();

					if (CBattleArena::instance().IsBattleArenaMap(ch->GetMapIndex()) == false)
					{
						item->SetOwnership(ch);
					}

					item->StartDestroyEvent();

					pos.x = number(-7, 7) * 20;
					pos.y = number(-7, 7) * 20;
					pos.x += GetX();
					pos.y += GetY();

					sys_log(0, "DROP_ITEM: %s %d %d by %s", item->GetName(), pos.x, pos.y, GetName());
				}
			}
		}
	}

	m_map_kDamage.clear();
}

Default Reward function.

 

The only thing that actually adds some kind of calculation is ITEM_MANAGER::GetDropPct:

bool ITEM_MANAGER::GetDropPct(LPCHARACTER pkChr, LPCHARACTER pkKiller, OUT int& iDeltaPercent, OUT int& iRandRange)
{
 	if (NULL == pkChr || NULL == pkKiller)
		return false;

	.....

	iRandRange = 4000000;
	iRandRange = iRandRange * 100 / 
		(100 + 
		 CPrivManager::instance().GetPriv(pkKiller, PRIV_ITEM_DROP) + 
		 pkKiller->IsEquipUniqueItem(UNIQUE_ITEM_DOUBLE_ITEM)?100:0);

	if (distribution_test_server) iRandRange /= 3;

	return true;
}

// And the UNIQUE_ITEM_DOUBLE_ITEM is Thief's Gloves.

Please tell me where is the calculation for the Chance to drop double the Items/POINT_ITEM_DROP_BONUS.

 

Don't use your arguments by saying "it works on the official ones, so you're wrong", prove us wrong by using facts.

spacer.png

 

I am curious as well to know where that POINT is used in original sources..

Edited by Metin2 Dev
Core X - External 2 Internal
  • Good 2
Link to comment
Share on other sites

Yes, I checked and it doesn't really work. I never noticed..

i think this bonus does not affect the chance of an item drop chance, but the amount of an item count. If it worked correctly, when the item dropped, it would have dropped 2 pieces instead of 1 piece, or 10 pieces instead of 5 pieces;

 

for my fix;

search " void CHARACTER::Reward " in char_battle.cpp


search again " if (ITEM_MANAGER::instance().CreateDropItem(this, pkAttacker, s_vec_item)) "

add after " item = s_vec_item[0]; " this;

if (pkAttacker->GetPoint(POINT_ITEM_DROP_BONUS) >= number(1, 100) && item->IsStackable())
{
	item->SetCount(item->GetCount() * 2);
}

 

TetGPQ8.jpg

 

 

NOTE : I just made the fix now, I don't know if there will be a problem..

Edited by Metin2 Dev
Core X - External 2 Internal
Link to comment
Share on other sites

On 7/20/2022 at 4:44 PM, Denizeri24 said:

Yes, I checked and it doesn't really work. I never noticed..

i think this bonus does not affect the chance of an item drop chance, but the amount of an item count. If it worked correctly, when the item dropped, it would have dropped 2 pieces instead of 1 piece, or 10 pieces instead of 5 pieces;

 

for my fix;

search " void CHARACTER::Reward " in char_battle.cpp


search again " if (ITEM_MANAGER::instance().CreateDropItem(this, pkAttacker, s_vec_item)) "

add after " item = s_vec_item[0]; " this;

if (pkAttacker->GetPoint(POINT_ITEM_DROP_BONUS) >= number(1, 100) && item->IsStackable())
{
	item->SetCount(item->GetCount() * 2);
}

 

TetGPQ8.jpg

 

 

NOTE : I just made the fix now, I don't know if there will be a problem..

Hello, I'm very sorry this is off topic. I would like to ask you if you have any instructions on how to add animation when picking up an object. Thank you very much 

Edited by Metin2 Dev
Core X - External 2 Internal
Link to comment
Share on other sites

Announcements



×
×
  • 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.