TheDragster 20 Posted April 1, 2021 Share Posted April 1, 2021 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. 1 Link to comment Share on other sites More sharing options...
Premium Intel 758 Posted April 2, 2021 Premium Share Posted April 2, 2021 (edited) 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 April 2, 2021 by xXIntelXx Link to comment Share on other sites More sharing options...
TheDragster 20 Posted April 2, 2021 Author Share Posted April 2, 2021 (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 April 2, 2021 by TheDragster Link to comment Share on other sites More sharing options...
Premium Intel 758 Posted April 2, 2021 Premium Share Posted April 2, 2021 (edited) 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 April 2, 2021 by xXIntelXx Link to comment Share on other sites More sharing options...
TheDragster 20 Posted April 2, 2021 Author Share Posted April 2, 2021 (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 April 2, 2021 by TheDragster Link to comment Share on other sites More sharing options...
Silver Sonitex 1438 Posted April 2, 2021 Silver Share Posted April 2, 2021 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 More sharing options...
Premium Intel 758 Posted April 2, 2021 Premium Share Posted April 2, 2021 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 More sharing options...
TheDragster 20 Posted April 2, 2021 Author Share Posted April 2, 2021 (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 April 2, 2021 by TheDragster Link to comment Share on other sites More sharing options...
Premium Intel 758 Posted April 2, 2021 Premium Share Posted April 2, 2021 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 More sharing options...
TheDragster 20 Posted April 2, 2021 Author Share Posted April 2, 2021 (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 April 2, 2021 by TheDragster Link to comment Share on other sites More sharing options...
LMAOAtWannabeDevs 0 Posted July 20, 2022 Share Posted July 20, 2022 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 More sharing options...
Silver Sonitex 1438 Posted July 20, 2022 Silver Share Posted July 20, 2022 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 1 1 Link to comment Share on other sites More sharing options...
LMAOAtWannabeDevs 0 Posted July 20, 2022 Share Posted July 20, 2022 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. 2 Link to comment Share on other sites More sharing options...
Premium msnas 1420 Posted July 20, 2022 Premium Share Posted July 20, 2022 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 More sharing options...
Premium Intel 758 Posted July 20, 2022 Premium Share Posted July 20, 2022 (edited) 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. I am curious as well to know where that POINT is used in original sources.. Edited August 15, 2022 by Metin2 Dev Core X - External 2 Internal 2 Link to comment Share on other sites More sharing options...
DrTurk 133 Posted July 20, 2022 Share Posted July 20, 2022 its not used, maybe they changed that after the source got leaked Link to comment Share on other sites More sharing options...
Denizeri24 35 Posted July 20, 2022 Share Posted July 20, 2022 (edited) 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); } NOTE : I just made the fix now, I don't know if there will be a problem.. Edited August 15, 2022 by Metin2 Dev Core X - External 2 Internal Link to comment Share on other sites More sharing options...
PeterCZ 1 Posted July 22, 2022 Share Posted July 22, 2022 (edited) 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); } 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 August 15, 2022 by Metin2 Dev Core X - External 2 Internal Link to comment Share on other sites More sharing options...
Denizeri24 35 Posted July 22, 2022 Share Posted July 22, 2022 3 hours ago, PeterCZ said: 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 idk, I added it from another files a long time ago. Link to comment Share on other sites More sharing options...
PeterCZ 1 Posted July 22, 2022 Share Posted July 22, 2022 4 hours ago, Denizeri24 said: idk, I added it from another files a long time ago. Hello, you probably wouldn't share how to add this possibly send in a private message or share the full instructions. Thank you Link to comment Share on other sites More sharing options...
Denizeri24 35 Posted July 22, 2022 Share Posted July 22, 2022 4 hours ago, PeterCZ said: Hello, you probably wouldn't share how to add this possibly send in a private message or share the full instructions. Thank you https://metin2.dev/topic/7472-how-to-use-pickup-motion/ 1 Link to comment Share on other sites More sharing options...
Recommended Posts