Jump to content

Fix Target Info System


Intel

Recommended Posts

I appreciate the tutorial but many changes are not intuitive in fact. It would be nice to take the original System and make the various modifications to make it ready for use. There might be errors during the bugfix ... Some things don't add up. Is there a way to contact you privately?

Link to comment
Share on other sites

  • 4 months later...
  • 4 months later...

I found a little bug, if you have the same item as drop, both with count 1 but different pct, the target info only show the one with higher pct, but not that one with lower pct. Anyone has fixxed that problem? (When you make different counts, it works, only problem is with same count),

mob_drop_item: https://metin2.download/picture/toa06GE8ClHUvcFZpA2V6HjqUCL4R7ok/.png

ingame: https://metin2.download/picture/GPpRn94DBekNFWpa7r11Q3WB2UsWpPzQ/.png

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

  • 2 months later...
  • Premium
On 10/20/2022 at 12:11 PM, LordZiege said:

I found a little bug, if you have the same item as drop, both with count 1 but different pct, the target info only show the one with higher pct, but not that one with lower pct. Anyone has fixxed that problem? (When you make different counts, it works, only problem is with same count),

mob_drop_item: https://metin2.download/picture/toa06GE8ClHUvcFZpA2V6HjqUCL4R7ok/.png

ingame: https://metin2.download/picture/GPpRn94DBekNFWpa7r11Q3WB2UsWpPzQ/.png

Mh, I see different drops. This is my python part:

	if app.ENABLE_SEND_TARGET_INFO:
		def BINARY_AddTargetMonsterDropInfo(self, raceNum, itemVnum, itemCount, rarity):
			if not raceNum in uiTarget.MONSTER_INFO_DATA:
				uiTarget.MONSTER_INFO_DATA.update({raceNum : {}})
				uiTarget.MONSTER_INFO_DATA[raceNum].update({"items" : []})
			curList = uiTarget.MONSTER_INFO_DATA[raceNum]["items"]

			isUpgradeable = False
			isMetin = False
			item.SelectItem(itemVnum)
			if item.GetItemType() == item.ITEM_TYPE_WEAPON or item.GetItemType() == item.ITEM_TYPE_ARMOR:
				isUpgradeable = True
			elif item.GetItemType() == item.ITEM_TYPE_METIN:
				isMetin = True

			for curItem in curList:
				if isUpgradeable:
					if curItem.has_key("vnum_list") and curItem["vnum_list"][0] / 10 * 10 == itemVnum / 10 * 10:
						if not (itemVnum in curItem["vnum_list"]):
							curItem["vnum_list"].append(itemVnum)
						return
				elif isMetin:
					if curItem.has_key("vnum_list"):
						baseVnum = curItem["vnum_list"][0]
					if curItem.has_key("vnum_list") and (baseVnum - baseVnum%1000) == (itemVnum - itemVnum%1000):
						if not (itemVnum in curItem["vnum_list"]):
							curItem["vnum_list"].append(itemVnum)
						return
				else:
					if curItem.has_key("vnum") and curItem["vnum"] == itemVnum and curItem["count"] == itemCount and curItem["rarity"] == rarity:
						return

			if isUpgradeable or isMetin:
				curList.append({"vnum_list":[itemVnum], "count":itemCount, "rarity":rarity})
			else:
				curList.append({"vnum":itemVnum, "count":itemCount, "rarity":rarity})

 

Edited by xXIntelXx
Link to comment
Share on other sites

Hi i have a little problem with this system its work good but if you see the info, drop items seems not logic becose its shows more items even item that dont drop from that monster. But for First second show the right items, then it refresh And show wronk items. 

Someone have solution? 

Sorry for my bad english 😅

Link to comment
Share on other sites

1 hour ago, SanctusCZE said:

Hi i have a little problem with this system its work good but if you see the info, drop items seems not logic becose its shows more items even item that dont drop from that monster. But for First second show the right items, then it refresh And show wronk items. 

Someone have solution? 

Sorry for my bad english 😅

https://metin2.download/picture/dCyh0NwMEE0V9ZUP07MYoFu8EGL12GEb/.gif

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

  • Forum Moderator
4 hours ago, SanctusCZE said:

Hi i have a little problem with this system its work good but if you see the info, drop items seems not logic becose its shows more items even item that dont drop from that monster. But for First second show the right items, then it refresh And show wronk items. 

Someone have solution? 

Sorry for my bad english 😅

 

3 hours ago, SanctusCZE said:

Those are called "common_drop". This is how the game works. You can drop them on virtually any monsters, that's why they show there. Of course, it all comes to the logic of having them in this system, is it very good to have them for every monsters, or is it even worth to have them at all displayed? That's up to you. But this is not a bug

Edited by Metin2 Dev
Core X - External 2 Internal
  • Metin2 Dev 1

Gurgarath
coming soon

Link to comment
Share on other sites

7 hours ago, Gurgarath said:

 

Those are called "common_drop". This is how the game works. You can drop them on virtually any monsters, that's why they show there. Of course, it all comes to the logic of having them in this system, is it very good to have them for every monsters, or is it even worth to have them at all displayed? That's up to you. But this is not a bug

OK but if it show in this system, mob must drop that item. Problem is, they dont drop right items, they drop only a few drops. For example: Mob 101 drops only potion, but system shows weapons from lvl 65+, i found fix but i dont know if its right fix:

 https://www.pastebin.cz/en/p/dGB4UQm

 

But normally its look like that:

https://www.pastebin.cz/en/p/6qdYHnr

 

Edited by SanctusCZE
Link to comment
Share on other sites

  • 2 weeks later...
  • Premium
20 hours ago, SussyFlore96 said:

Hello! Can you let me a tutorial for rarity in this system? Thank you!

Example for drop item group, replace:

vec_item.push_back(std::make_pair(std::make_pair(v[i].dwVnum, v[i].iCount),v[i].rarity));

with:

vec_item.emplace_back(std::make_tuple(v[i].dwVnum, v[i].iCount, rarity));

(so make_pair with make_tuple and add rarity as the third parameter)

Rarities functions I've made:

int CalculateDropRarityCommonDropItem(int x)
{
	int pct = x;
	int rarity = 0;
	if(pct >= 4000000)
		rarity = 1;
	else if(pct < 40000000 && pct >= 200000 )
		rarity = 2;
	else if(pct < 200000 && pct >= 10000 )
		rarity = 3;
	else if(pct < 10000 && pct >= 5000 )
		rarity = 4;
	else if(pct < 5000 && pct >= 1000 )
		rarity = 5;
	else if(pct < 1000 && pct >= 0 )
		rarity = 6;
	
	return rarity;
}

int CalculateDropRarityKillDrop(int x, BYTE bType)
{
	int pct = x;
	int rarity = 0;
	if(pct == 1)
		rarity = 1;
	else if(pct > 1 && pct <= 300 )
		rarity = 2;
	else if(pct > 300 && pct <= 500 )
		rarity = 3;
	else if(pct > 500 && pct <= 2000 )
		rarity = 4;
	else if(pct > 2000 && pct <= 5000 )
		rarity = 5;
	else if(pct > 5000 )
		rarity = 6;
	
	return rarity;
}

int CalculateDropRarityDropItemGroup(int x, BYTE bType)
{
	int pct = x;
	int rarity = 0;
	switch(bType)
	{
		case CHAR_TYPE_BOSS:
		{
			if(pct >= 4000000)
				rarity = 1;
			else if(pct < 4000000 && pct >= 2600000 ) //100~65
				rarity = 2;
			else if(pct < 2600000 && pct >= 1600000 ) //65~40
				rarity = 3;
			else if(pct < 1600000 && pct >= 1000000 ) //40~25
				rarity = 4;
			else if(pct < 1000000 && pct >= 600000 ) //25~15
				rarity = 5;
			else if(pct < 600000 )
				rarity = 6;
		}
		break;	
		case CHAR_TYPE_MONSTER:
		{
			if(pct >= 4000000)
				rarity = 1;
			else if(pct < 4000000 && pct >= 1600000 ) //100~40
				rarity = 2;
			else if(pct < 1600000 && pct >= 800000 ) //40~20
				rarity = 3;
			else if(pct < 800000 && pct >= 200000 ) //20~5
				rarity = 4;
			else if(pct < 200000 && pct >= 20000 ) //5~0.5
				rarity = 5;
			else if(pct < 20000 )
				rarity = 6;
		}
		break;		
		case CHAR_TYPE_STONE:
		{
			if(pct >= 4000000)
				rarity = 1;
			else if(pct < 4000000 && pct >= 2000000 ) //100~50
				rarity = 2;
			else if(pct < 2000000 && pct >= 1000000 ) //50~25
				rarity = 3;
			else if(pct < 1000000 && pct >= 600000 ) //25~15
				rarity = 4;
			else if(pct < 600000 && pct >= 200000 ) //15~5
				rarity = 5;
			else if(pct < 200000 )
				rarity = 6;
		}
		break;
		default:
		{
			if(pct >= 4000000)
				rarity = 1;
			else if(pct < 4000000 && pct >= 2000000 ) //100~50
				rarity = 2;
			else if(pct < 2000000 && pct >= 1000000 ) //50~25
				rarity = 3;
			else if(pct < 1000000 && pct >= 600000 ) //25~15
				rarity = 4;
			else if(pct < 600000 && pct >= 200000 ) //15~5
				rarity = 5;
			else if(pct < 200000 )
				rarity = 6;
		}
		break;	
	}
	return rarity;
}

int CalculateDropRarityLevelItemGroup(float x, BYTE bType)
{
	float pct = x / 10000.0000;
	int rarity = 0;
	switch(bType)
	{
		case CHAR_TYPE_BOSS:
		{
			if(pct >= 100.0000)
				rarity = 1;
			else if(pct < 100.0000 && pct >= 65.0000 )
				rarity = 2;
			else if(pct < 65.0000 && pct >= 40.0000 )
				rarity = 3;
			else if(pct < 40.0000 && pct >= 25.0000 )
				rarity = 4;
			else if(pct < 25.0000 && pct >= 15.0000 )
				rarity = 5;
			else if(pct < 15.0000 )
				rarity = 6;				
		}
		break;
		case CHAR_TYPE_STONE:
		{
			if(pct >= 100.0000)
				rarity = 1;
			else if(pct < 100.0000 && pct >= 50.0000 )
				rarity = 2;
			else if(pct < 50.0000 && pct >= 25.0000 )
				rarity = 3;
			else if(pct < 25.0000 && pct >= 15.0000 )
				rarity = 4;
			else if(pct < 15.0000 && pct >= 5.0000 )
				rarity = 5;
			else if(pct < 5.0000 )
				rarity = 6;
		}
		break;
		case CHAR_TYPE_MONSTER:
		{
			if(pct >= 100.0000)
				rarity = 1;
			else if(pct < 100.0000 && pct >= 30.0000 )
				rarity = 2;
			else if(pct < 30.0000 && pct >= 15.0000 )
				rarity = 3;
			else if(pct < 15.0000 && pct >= 1.0000 )
				rarity = 4;
			else if(pct < 1.0000 && pct >= 0.1000 )
				rarity = 5;
			else if(pct < 0.1000 )
				rarity = 6;			
		}
		break;
		default:
		{
			if(pct >= 100.0000)
				rarity = 1;
			else if(pct < 100.0000 && pct >= 65.0000 )
				rarity = 2;
			else if(pct < 65.0000 && pct >= 40.0000 )
				rarity = 3;
			else if(pct < 40.0000 && pct >= 25.0000 )
				rarity = 4;
			else if(pct < 25.0000 && pct >= 15.0000 )
				rarity = 5;
			else if(pct < 15.0000 )
				rarity = 6;				
		}	
	}	
	return rarity;
}

int CalculateDropRarityTimeDrop(int x, BYTE bType)
{
	int pct = x;
	int rarity = 0;
	switch(bType)
	{
		case CHAR_TYPE_BOSS:
		{
			if(pct == 1000000)
				rarity = 1;
			else if(pct < 1000000 && pct >= 650000 )
				rarity = 2;
			else if(pct < 650000 && pct >= 400000 )
				rarity = 3;
			else if(pct < 400000 && pct >= 250000 )
				rarity = 4;
			else if(pct < 250000 && pct >= 150000 )
				rarity = 5;
			else if(pct < 150000 )
				rarity = 6;
		}
		break;	
		case CHAR_TYPE_MONSTER:
		{
			if(pct == 1000000)
				rarity = 1;
			else if(pct < 1000000 && pct >= 400000 )
				rarity = 2;
			else if(pct < 400000 && pct >= 200000 )
				rarity = 3;
			else if(pct < 200000 && pct >= 100000 )
				rarity = 4;
			else if(pct < 100000 && pct >= 5000 )
				rarity = 5;
			else if(pct < 5000 )
				rarity = 6;
		}
		break;		
		case CHAR_TYPE_STONE:
		{
			if(pct == 1000000)
				rarity = 1;
			else if(pct < 1000000 && pct >= 500000 )
				rarity = 2;
			else if(pct < 500000 && pct >= 250000 )
				rarity = 3;
			else if(pct < 250000 && pct >= 150000 )
				rarity = 4;
			else if(pct < 150000 && pct >= 50000 )
				rarity = 5;
			else if(pct < 50000 )
				rarity = 6;
		}
		default:
		{
			if(pct == 1000000)
				rarity = 1;
			else if(pct < 1000000 && pct >= 500000 )
				rarity = 2;
			else if(pct < 500000 && pct >= 250000 )
				rarity = 3;
			else if(pct < 250000 && pct >= 150000 )
				rarity = 4;
			else if(pct < 150000 && pct >= 50000 )
				rarity = 5;
			else if(pct < 50000 )
				rarity = 6;
		}
		break;	
	}	
	return rarity;
}

Hint: instead of the char type, since the BOSS type is not by default in the sources, you could pass the rank as well, then put the rank on the switch case and, if the rank is 5, check if it's a metin or not.

Therefore in the drop item group example would be like this:

	// Drop Item Group
	{
		auto it = m_map_pkDropItemGroup.find(pkChr->GetRaceNum());

		if(it != m_map_pkDropItemGroup.end())
		{
			auto v = it->second->GetVector();
			

			for (DWORD i = 0; i < v.size(); ++i)
			{
				if( iLevel >= (iMobLevel - 15) && iLevel <= (iMobLevel + 15) ) //don't show outside level limits
				{
					uint8_t rarity = CalculateDropRarityDropItemGroup(v[i].dwPct, bType);
					vec_item.emplace_back(std::make_tuple(v[i].dwVnum, v[i].iCount, rarity));
					//vec_item.push_back(std::make_pair(std::make_pair(v[i].dwVnum, v[i].iCount),v[i].rarity));
				}
			}
		}
	}

You can sort them by rarity like this:

	std::sort(vec_item.begin(),vec_item.end(), sortbyrarity); //then sort by rarity

sortbyrarity function:

bool sortbyrarity(std::tuple<int, int, int>& a,  
              std::tuple<int, int, int>& b) {
    return (std::get<2>(a) > std::get<2>(b)); 
}

and in input_main.cpp:

			pInfo.dwVID	= m_pkChrTarget->GetVID();
			pInfo.race = m_pkChrTarget->GetRaceNum();
			pInfo.dwVnum = std::get<0>(x);
			pInfo.count = std::get<1>(x);
			pInfo.rarity = std::get<2>(x);

this is how you get the data from the tuple and s_vec_item declaration changes to:

static std::vector<std::tuple<int,int,int>> s_vec_item;

Obviously you should change the packet accordingly and in bool CPythonNetworkStream::RecvTargetInfoPacket() change:

Py_BuildValue("(iii)", pInfoTargetPacket.race, pInfoTargetPacket.dwVnum, pInfoTargetPacket.count));

into:

Py_BuildValue("(iiii)", pInfoTargetPacket.race, pInfoTargetPacket.dwVnum, pInfoTargetPacket.count, pInfoTargetPacket.rarity));

game.py change of BINARY_AddTargetMonsterDropInfo:

	if app.ENABLE_SEND_TARGET_INFO:
		def BINARY_AddTargetMonsterDropInfo(self, raceNum, itemVnum, itemCount, rarity):
			if not raceNum in uiTarget.MONSTER_INFO_DATA:
				uiTarget.MONSTER_INFO_DATA.update({raceNum : {}})
				uiTarget.MONSTER_INFO_DATA[raceNum].update({"items" : []})
			curList = uiTarget.MONSTER_INFO_DATA[raceNum]["items"]

			isUpgradeable = False
			isMetin = False
			item.SelectItem(itemVnum)
			if item.GetItemType() == item.ITEM_TYPE_WEAPON or item.GetItemType() == item.ITEM_TYPE_ARMOR:
				isUpgradeable = True
			elif item.GetItemType() == item.ITEM_TYPE_METIN:
				isMetin = True

			for curItem in curList:
				if isUpgradeable:
					if curItem.has_key("vnum_list") and curItem["vnum_list"][0] / 10 * 10 == itemVnum / 10 * 10:
						if not (itemVnum in curItem["vnum_list"]):
							curItem["vnum_list"].append(itemVnum)
						return
				elif isMetin:
					if curItem.has_key("vnum_list"):
						baseVnum = curItem["vnum_list"][0]
					if curItem.has_key("vnum_list") and (baseVnum - baseVnum%1000) == (itemVnum - itemVnum%1000):
						if not (itemVnum in curItem["vnum_list"]):
							curItem["vnum_list"].append(itemVnum)
						return
				else:
					if curItem.has_key("vnum") and curItem["vnum"] == itemVnum and curItem["count"] == itemCount and curItem["rarity"] == rarity:
						return

			if isUpgradeable or isMetin:
				curList.append({"vnum_list":[itemVnum], "count":itemCount, "rarity":rarity})
			else:
				curList.append({"vnum":itemVnum, "count":itemCount, "rarity":rarity})

and in uitarget.py, the class ItemListBoxItem:

			class ItemListBoxItem(ui.Window):
				def __init__(self, width):
					ui.Window.__init__(self)

					image = ui.ExpandedImageBox()
					image.SetParent(self)
					image.Show()
					self.image = image

					nameLine = ui.TextLine()
					nameLine.SetParent(self)
					nameLine.SetPosition(32 + 5, 0)
					nameLine.Show()
					self.nameLine = nameLine

					rarity = ui.TextLine()
					rarity.SetParent(self)
					rarity.SetPosition(32 + 5, 13)
					rarity.Show()
					self.rarity = rarity

					self.SetSize(width, 32 + 5)

				def LoadImage(self, image, name = None):
					self.image.LoadImage(image)
					self.SetSize(self.GetWidth(), self.image.GetHeight() + 5)
					if name != None:
						self.SetText(name)

				def SetText(self, text):
					self.nameLine.SetText(text)

				def SetRarityText(self, text, rarity):
					TEXT_COLORS = [
					grp.GenerateColor(1.0, 0.0, 0.0, 1.0),	
					grp.GenerateColor(1.0, 1.0, 1.0, 1.0), 
					grp.GenerateColor(0.33, 1.0, 0.12, 1.0),
					grp.GenerateColor(0.42, 0.93, 0.76, 1.0),
					grp.GenerateColor(0.0, 0.89, 1.0, 1.0),
					grp.GenerateColor(0.41, 0.0, 1.0, 1.0),
					grp.GenerateColor(1.0, 0.86, 0.0, 1.0)
					]
					if rarity != 1:
						self.rarity.SetPackedFontColor(TEXT_COLORS[rarity])
					self.rarity.SetText(text)

__LoadInformation_Drops:

			def __LoadInformation_Drops(self, race):
				self.AppendSeperator()

				if race in MONSTER_INFO_DATA:
					if len(MONSTER_INFO_DATA[race]["items"]) == 0:
						self.AppendTextLine(localeInfo.TARGET_INFO_NO_ITEM_TEXT)
					else:
						itemListBox = ui.ListBoxExNew(32 + 5, self.MAX_ITEM_COUNT)
						itemListBox.SetSize(self.GetWidth() - 15 * 2 - ui.ScrollBar.SCROLLBAR_WIDTH, (32 + 5) * self.MAX_ITEM_COUNT)
						height = 0
						for curItem in MONSTER_INFO_DATA[race]["items"]:
							if curItem.has_key("vnum_list"):
								height += self.AppendItem(itemListBox, curItem["vnum_list"], curItem["count"], curItem["rarity"], race)
							else:
								height += self.AppendItem(itemListBox, curItem["vnum"], curItem["count"], curItem["rarity"], race)
						if height < itemListBox.GetHeight():
							itemListBox.SetSize(itemListBox.GetWidth(), height)
						self.AppendWindow(itemListBox, 15)
						itemListBox.SetBasePos(0)

						if len(MONSTER_INFO_DATA[race]["items"]) > itemListBox.GetViewItemCountFixed():
							itemScrollBar = ui.ScrollBar()
							itemScrollBar.SetParent(self)
							itemScrollBar.SetPosition(itemListBox.GetRight(), itemListBox.GetTop())
							itemScrollBar.SetScrollBarSize(32 * self.MAX_ITEM_COUNT + 5 * (self.MAX_ITEM_COUNT - 1))
							itemScrollBar.SetMiddleBarSize(float(self.MAX_ITEM_COUNT) / float(height / (32 + 5)))
							itemScrollBar.Show()
							itemListBox.SetScrollBar(itemScrollBar)
							self.scrollBar = itemListBox.GetScrollBar()
				else:
					self.AppendTextLine(localeInfo.TARGET_INFO_NO_ITEM_TEXT)

 

AppendItem:

			def AppendItem(self, listBox, vnums, count, rarity, race):
				if type(vnums) == int:
					vnum = vnums
				else:
					vnum = vnums[0]

				item.SelectItem(vnum)
				itemName = item.GetItemName()
				if type(vnums) != int and len(vnums) > 1:
					#vnums = sorted(vnums)
					realName = itemName[:itemName.find("+")]
					if item.GetItemType() == item.ITEM_TYPE_METIN:
						realName = localeInfo.TARGET_INFO_STONE_NAME
						itemName = realName + "+0 - +4"
					else:
						itemName = realName + "+" + str(vnums[0] % 10) + " - +" + str(vnums[len(vnums) - 1] % 10)
					vnum = vnums[len(vnums) - 1]

				myItem = self.ItemListBoxItem(listBox.GetWidth())
				myItem.LoadImage(item.GetIconImageFileName())
				if count <= 1:
					myItem.SetText(itemName)
				else:
					myItem.SetText("%dx %s" % (count, itemName))
				
				RARITY_NAMES_LIST = [localeInfo.DROP_RARITY_ERROR, localeInfo.DROP_GUARANTEED, localeInfo.DROP_COMMON, localeInfo.DROP_UNCOMMON, localeInfo.DROP_RARE, localeInfo.DROP_MYTHIC, localeInfo.DROP_LEGENDARY]
				myItem.SetRarityText("%s" % RARITY_NAMES_LIST[rarity], rarity)
				myItem.SAFE_SetOverInEvent(self.OnShowItemTooltip,vnum)
				myItem.SAFE_SetOverOutEvent(self.OnHideItemTooltip)
				listBox.AppendItem(myItem)

				if item.GetItemType() == item.ITEM_TYPE_METIN:
					self.stoneImg = myItem
					self.stoneVnum = vnums
					self.lastStoneVnum = self.STONE_LAST_VNUM + vnums[len(vnums) - 1] % 1000 / 100 * 100

				return myItem.GetHeight()

 

Edited by xXIntelXx
  • Metin2 Dev 2
Link to comment
Share on other sites

7 hours ago, xXIntelXx said:

Example for drop item group, replace:

vec_item.push_back(std::make_pair(std::make_pair(v[i].dwVnum, v[i].iCount),v[i].rarity));

with:

vec_item.emplace_back(std::make_tuple(v[i].dwVnum, v[i].iCount, rarity));

(so make_pair with make_tuple and add rarity as the third parameter)

Rarities functions I've made:

int CalculateDropRarityCommonDropItem(int x)
{
	int pct = x;
	int rarity = 0;
	if(pct >= 4000000)
		rarity = 1;
	else if(pct < 40000000 && pct >= 200000 )
		rarity = 2;
	else if(pct < 200000 && pct >= 10000 )
		rarity = 3;
	else if(pct < 10000 && pct >= 5000 )
		rarity = 4;
	else if(pct < 5000 && pct >= 1000 )
		rarity = 5;
	else if(pct < 1000 && pct >= 0 )
		rarity = 6;
	
	return rarity;
}

int CalculateDropRarityKillDrop(int x, BYTE bType)
{
	int pct = x;
	int rarity = 0;
	if(pct == 1)
		rarity = 1;
	else if(pct > 1 && pct <= 300 )
		rarity = 2;
	else if(pct > 300 && pct <= 500 )
		rarity = 3;
	else if(pct > 500 && pct <= 2000 )
		rarity = 4;
	else if(pct > 2000 && pct <= 5000 )
		rarity = 5;
	else if(pct > 5000 )
		rarity = 6;
	
	return rarity;
}

int CalculateDropRarityDropItemGroup(int x, BYTE bType)
{
	int pct = x;
	int rarity = 0;
	switch(bType)
	{
		case CHAR_TYPE_BOSS:
		{
			if(pct >= 4000000)
				rarity = 1;
			else if(pct < 4000000 && pct >= 2600000 ) //100~65
				rarity = 2;
			else if(pct < 2600000 && pct >= 1600000 ) //65~40
				rarity = 3;
			else if(pct < 1600000 && pct >= 1000000 ) //40~25
				rarity = 4;
			else if(pct < 1000000 && pct >= 600000 ) //25~15
				rarity = 5;
			else if(pct < 600000 )
				rarity = 6;
		}
		break;	
		case CHAR_TYPE_MONSTER:
		{
			if(pct >= 4000000)
				rarity = 1;
			else if(pct < 4000000 && pct >= 1600000 ) //100~40
				rarity = 2;
			else if(pct < 1600000 && pct >= 800000 ) //40~20
				rarity = 3;
			else if(pct < 800000 && pct >= 200000 ) //20~5
				rarity = 4;
			else if(pct < 200000 && pct >= 20000 ) //5~0.5
				rarity = 5;
			else if(pct < 20000 )
				rarity = 6;
		}
		break;		
		case CHAR_TYPE_STONE:
		{
			if(pct >= 4000000)
				rarity = 1;
			else if(pct < 4000000 && pct >= 2000000 ) //100~50
				rarity = 2;
			else if(pct < 2000000 && pct >= 1000000 ) //50~25
				rarity = 3;
			else if(pct < 1000000 && pct >= 600000 ) //25~15
				rarity = 4;
			else if(pct < 600000 && pct >= 200000 ) //15~5
				rarity = 5;
			else if(pct < 200000 )
				rarity = 6;
		}
		break;
		default:
		{
			if(pct >= 4000000)
				rarity = 1;
			else if(pct < 4000000 && pct >= 2000000 ) //100~50
				rarity = 2;
			else if(pct < 2000000 && pct >= 1000000 ) //50~25
				rarity = 3;
			else if(pct < 1000000 && pct >= 600000 ) //25~15
				rarity = 4;
			else if(pct < 600000 && pct >= 200000 ) //15~5
				rarity = 5;
			else if(pct < 200000 )
				rarity = 6;
		}
		break;	
	}
	return rarity;
}

int CalculateDropRarityLevelItemGroup(float x, BYTE bType)
{
	float pct = x / 10000.0000;
	int rarity = 0;
	switch(bType)
	{
		case CHAR_TYPE_BOSS:
		{
			if(pct >= 100.0000)
				rarity = 1;
			else if(pct < 100.0000 && pct >= 65.0000 )
				rarity = 2;
			else if(pct < 65.0000 && pct >= 40.0000 )
				rarity = 3;
			else if(pct < 40.0000 && pct >= 25.0000 )
				rarity = 4;
			else if(pct < 25.0000 && pct >= 15.0000 )
				rarity = 5;
			else if(pct < 15.0000 )
				rarity = 6;				
		}
		break;
		case CHAR_TYPE_STONE:
		{
			if(pct >= 100.0000)
				rarity = 1;
			else if(pct < 100.0000 && pct >= 50.0000 )
				rarity = 2;
			else if(pct < 50.0000 && pct >= 25.0000 )
				rarity = 3;
			else if(pct < 25.0000 && pct >= 15.0000 )
				rarity = 4;
			else if(pct < 15.0000 && pct >= 5.0000 )
				rarity = 5;
			else if(pct < 5.0000 )
				rarity = 6;
		}
		break;
		case CHAR_TYPE_MONSTER:
		{
			if(pct >= 100.0000)
				rarity = 1;
			else if(pct < 100.0000 && pct >= 30.0000 )
				rarity = 2;
			else if(pct < 30.0000 && pct >= 15.0000 )
				rarity = 3;
			else if(pct < 15.0000 && pct >= 1.0000 )
				rarity = 4;
			else if(pct < 1.0000 && pct >= 0.1000 )
				rarity = 5;
			else if(pct < 0.1000 )
				rarity = 6;			
		}
		break;
		default:
		{
			if(pct >= 100.0000)
				rarity = 1;
			else if(pct < 100.0000 && pct >= 65.0000 )
				rarity = 2;
			else if(pct < 65.0000 && pct >= 40.0000 )
				rarity = 3;
			else if(pct < 40.0000 && pct >= 25.0000 )
				rarity = 4;
			else if(pct < 25.0000 && pct >= 15.0000 )
				rarity = 5;
			else if(pct < 15.0000 )
				rarity = 6;				
		}	
	}	
	return rarity;
}

int CalculateDropRarityTimeDrop(int x, BYTE bType)
{
	int pct = x;
	int rarity = 0;
	switch(bType)
	{
		case CHAR_TYPE_BOSS:
		{
			if(pct == 1000000)
				rarity = 1;
			else if(pct < 1000000 && pct >= 650000 )
				rarity = 2;
			else if(pct < 650000 && pct >= 400000 )
				rarity = 3;
			else if(pct < 400000 && pct >= 250000 )
				rarity = 4;
			else if(pct < 250000 && pct >= 150000 )
				rarity = 5;
			else if(pct < 150000 )
				rarity = 6;
		}
		break;	
		case CHAR_TYPE_MONSTER:
		{
			if(pct == 1000000)
				rarity = 1;
			else if(pct < 1000000 && pct >= 400000 )
				rarity = 2;
			else if(pct < 400000 && pct >= 200000 )
				rarity = 3;
			else if(pct < 200000 && pct >= 100000 )
				rarity = 4;
			else if(pct < 100000 && pct >= 5000 )
				rarity = 5;
			else if(pct < 5000 )
				rarity = 6;
		}
		break;		
		case CHAR_TYPE_STONE:
		{
			if(pct == 1000000)
				rarity = 1;
			else if(pct < 1000000 && pct >= 500000 )
				rarity = 2;
			else if(pct < 500000 && pct >= 250000 )
				rarity = 3;
			else if(pct < 250000 && pct >= 150000 )
				rarity = 4;
			else if(pct < 150000 && pct >= 50000 )
				rarity = 5;
			else if(pct < 50000 )
				rarity = 6;
		}
		default:
		{
			if(pct == 1000000)
				rarity = 1;
			else if(pct < 1000000 && pct >= 500000 )
				rarity = 2;
			else if(pct < 500000 && pct >= 250000 )
				rarity = 3;
			else if(pct < 250000 && pct >= 150000 )
				rarity = 4;
			else if(pct < 150000 && pct >= 50000 )
				rarity = 5;
			else if(pct < 50000 )
				rarity = 6;
		}
		break;	
	}	
	return rarity;
}

Hint: instead of the char type, since the BOSS type is not by default in the sources, you could pass the rank as well, then put the rank on the switch case and, if the rank is 5, check if it's a metin or not.

Therefore in the drop item group example would be like this:

	// Drop Item Group
	{
		auto it = m_map_pkDropItemGroup.find(pkChr->GetRaceNum());

		if(it != m_map_pkDropItemGroup.end())
		{
			auto v = it->second->GetVector();
			

			for (DWORD i = 0; i < v.size(); ++i)
			{
				if( iLevel >= (iMobLevel - 15) && iLevel <= (iMobLevel + 15) ) //don't show outside level limits
				{
					uint8_t rarity = CalculateDropRarityDropItemGroup(v[i].dwPct, bType);
					vec_item.emplace_back(std::make_tuple(v[i].dwVnum, v[i].iCount, rarity));
					//vec_item.push_back(std::make_pair(std::make_pair(v[i].dwVnum, v[i].iCount),v[i].rarity));
				}
			}
		}
	}

and in input_main.cpp:

			pInfo.dwVID	= m_pkChrTarget->GetVID();
			pInfo.race = m_pkChrTarget->GetRaceNum();
			pInfo.dwVnum = std::get<0>(x);
			pInfo.count = std::get<1>(x);
			pInfo.rarity = std::get<2>(x);

this is how you get the data from the tuple and s_vec_item declaration changes to:

static std::vector<std::tuple<int,int,int>> s_vec_item;

Obviously you should change the packet accordingly and in bool CPythonNetworkStream::RecvTargetInfoPacket() change:

Py_BuildValue("(iii)", pInfoTargetPacket.race, pInfoTargetPacket.dwVnum, pInfoTargetPacket.count));

into:

Py_BuildValue("(iiii)", pInfoTargetPacket.race, pInfoTargetPacket.dwVnum, pInfoTargetPacket.count, pInfoTargetPacket.rarity));

game.py change of BINARY_AddTargetMonsterDropInfo:

	if app.ENABLE_SEND_TARGET_INFO:
		def BINARY_AddTargetMonsterDropInfo(self, raceNum, itemVnum, itemCount, rarity):
			if not raceNum in uiTarget.MONSTER_INFO_DATA:
				uiTarget.MONSTER_INFO_DATA.update({raceNum : {}})
				uiTarget.MONSTER_INFO_DATA[raceNum].update({"items" : []})
			curList = uiTarget.MONSTER_INFO_DATA[raceNum]["items"]

			isUpgradeable = False
			isMetin = False
			item.SelectItem(itemVnum)
			if item.GetItemType() == item.ITEM_TYPE_WEAPON or item.GetItemType() == item.ITEM_TYPE_ARMOR:
				isUpgradeable = True
			elif item.GetItemType() == item.ITEM_TYPE_METIN:
				isMetin = True

			for curItem in curList:
				if isUpgradeable:
					if curItem.has_key("vnum_list") and curItem["vnum_list"][0] / 10 * 10 == itemVnum / 10 * 10:
						if not (itemVnum in curItem["vnum_list"]):
							curItem["vnum_list"].append(itemVnum)
						return
				elif isMetin:
					if curItem.has_key("vnum_list"):
						baseVnum = curItem["vnum_list"][0]
					if curItem.has_key("vnum_list") and (baseVnum - baseVnum%1000) == (itemVnum - itemVnum%1000):
						if not (itemVnum in curItem["vnum_list"]):
							curItem["vnum_list"].append(itemVnum)
						return
				else:
					if curItem.has_key("vnum") and curItem["vnum"] == itemVnum and curItem["count"] == itemCount and curItem["rarity"] == rarity:
						return

			if isUpgradeable or isMetin:
				curList.append({"vnum_list":[itemVnum], "count":itemCount, "rarity":rarity})
			else:
				curList.append({"vnum":itemVnum, "count":itemCount, "rarity":rarity})

and in uitarget.py, the class ItemListBoxItem:

			class ItemListBoxItem(ui.Window):
				def __init__(self, width):
					ui.Window.__init__(self)

					image = ui.ExpandedImageBox()
					image.SetParent(self)
					image.Show()
					self.image = image

					nameLine = ui.TextLine()
					nameLine.SetParent(self)
					nameLine.SetPosition(32 + 5, 0)
					nameLine.Show()
					self.nameLine = nameLine

					rarity = ui.TextLine()
					rarity.SetParent(self)
					rarity.SetPosition(32 + 5, 13)
					rarity.Show()
					self.rarity = rarity

					self.SetSize(width, 32 + 5)

				def LoadImage(self, image, name = None):
					self.image.LoadImage(image)
					self.SetSize(self.GetWidth(), self.image.GetHeight() + 5)
					if name != None:
						self.SetText(name)

				def SetText(self, text):
					self.nameLine.SetText(text)

				def SetRarityText(self, text, rarity):
					TEXT_COLORS = [
					grp.GenerateColor(1.0, 0.0, 0.0, 1.0),	
					grp.GenerateColor(1.0, 1.0, 1.0, 1.0), 
					grp.GenerateColor(0.33, 1.0, 0.12, 1.0),
					grp.GenerateColor(0.42, 0.93, 0.76, 1.0),
					grp.GenerateColor(0.0, 0.89, 1.0, 1.0),
					grp.GenerateColor(0.41, 0.0, 1.0, 1.0),
					grp.GenerateColor(1.0, 0.86, 0.0, 1.0)
					]
					if rarity != 1:
						self.rarity.SetPackedFontColor(TEXT_COLORS[rarity])
					self.rarity.SetText(text)

__LoadInformation_Drops:

			def __LoadInformation_Drops(self, race):
				self.AppendSeperator()

				if race in MONSTER_INFO_DATA:
					if len(MONSTER_INFO_DATA[race]["items"]) == 0:
						self.AppendTextLine(localeInfo.TARGET_INFO_NO_ITEM_TEXT)
					else:
						itemListBox = ui.ListBoxExNew(32 + 5, self.MAX_ITEM_COUNT)
						itemListBox.SetSize(self.GetWidth() - 15 * 2 - ui.ScrollBar.SCROLLBAR_WIDTH, (32 + 5) * self.MAX_ITEM_COUNT)
						height = 0
						for curItem in MONSTER_INFO_DATA[race]["items"]:
							if curItem.has_key("vnum_list"):
								height += self.AppendItem(itemListBox, curItem["vnum_list"], curItem["count"], curItem["rarity"], race)
							else:
								height += self.AppendItem(itemListBox, curItem["vnum"], curItem["count"], curItem["rarity"], race)
						if height < itemListBox.GetHeight():
							itemListBox.SetSize(itemListBox.GetWidth(), height)
						self.AppendWindow(itemListBox, 15)
						itemListBox.SetBasePos(0)

						if len(MONSTER_INFO_DATA[race]["items"]) > itemListBox.GetViewItemCountFixed():
							itemScrollBar = ui.ScrollBar()
							itemScrollBar.SetParent(self)
							itemScrollBar.SetPosition(itemListBox.GetRight(), itemListBox.GetTop())
							itemScrollBar.SetScrollBarSize(32 * self.MAX_ITEM_COUNT + 5 * (self.MAX_ITEM_COUNT - 1))
							itemScrollBar.SetMiddleBarSize(float(self.MAX_ITEM_COUNT) / float(height / (32 + 5)))
							itemScrollBar.Show()
							itemListBox.SetScrollBar(itemScrollBar)
							self.scrollBar = itemListBox.GetScrollBar()
				else:
					self.AppendTextLine(localeInfo.TARGET_INFO_NO_ITEM_TEXT)

 

AppendItem:

			def AppendItem(self, listBox, vnums, count, rarity, race):
				if type(vnums) == int:
					vnum = vnums
				else:
					vnum = vnums[0]

				item.SelectItem(vnum)
				itemName = item.GetItemName()
				if type(vnums) != int and len(vnums) > 1:
					#vnums = sorted(vnums)
					realName = itemName[:itemName.find("+")]
					if item.GetItemType() == item.ITEM_TYPE_METIN:
						realName = localeInfo.TARGET_INFO_STONE_NAME
						itemName = realName + "+0 - +4"
					else:
						itemName = realName + "+" + str(vnums[0] % 10) + " - +" + str(vnums[len(vnums) - 1] % 10)
					vnum = vnums[len(vnums) - 1]

				myItem = self.ItemListBoxItem(listBox.GetWidth())
				myItem.LoadImage(item.GetIconImageFileName())
				if count <= 1:
					myItem.SetText(itemName)
				else:
					myItem.SetText("%dx %s" % (count, itemName))
				
				RARITY_NAMES_LIST = [localeInfo.DROP_RARITY_ERROR, localeInfo.DROP_GUARANTEED, localeInfo.DROP_COMMON, localeInfo.DROP_UNCOMMON, localeInfo.DROP_RARE, localeInfo.DROP_MYTHIC, localeInfo.DROP_LEGENDARY]
				myItem.SetRarityText("%s" % RARITY_NAMES_LIST[rarity], rarity)
				myItem.SAFE_SetOverInEvent(self.OnShowItemTooltip,vnum)
				myItem.SAFE_SetOverOutEvent(self.OnHideItemTooltip)
				listBox.AppendItem(myItem)

				if item.GetItemType() == item.ITEM_TYPE_METIN:
					self.stoneImg = myItem
					self.stoneVnum = vnums
					self.lastStoneVnum = self.STONE_LAST_VNUM + vnums[len(vnums) - 1] % 1000 / 100 * 100

				return myItem.GetHeight()

 

Thank you! Now I get this:

Spoiler

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

  • Premium
52 minutes ago, SussyFlore96 said:

Thank you! Now I get this:

You need c++11 (-std=c++11 on your makefile in the CXXFLAGS) I think.. I say I think because generally I'd understand this if you were trying to put some objects of a class with no default constructor (but they are integers...)

Spoiler

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

23 minutes ago, xXIntelXx said:

Oh hell no, I also use c++2a. That's odd. AH NO WAIT hold up lmao.

You need to add: #include <tuple> in input_main.cpp and item_manager.cpp

Thanks for your answer, but stil doesn't work, same error. In item_manager.h no need to add something? I don't know how to fix this...

Link to comment
Share on other sites

  • Premium
30 minutes ago, Mali said:

just use struct, that tuple looks ugly AF

or that, yeah lol

so:

//somewhere maybe a header in common/target_info.h
struct drop_info
{
	uint32_t vnum;
	uint16_t count;
	uint8_t rarity;
}
//and in input_main include the new header and the vector becomes:
static std::vector<drop_info> s_vec_item;

//and to read its info:
		for(const auto& x : s_vec_item)
		{
			pInfo.dwVID	= m_pkChrTarget->GetVID();
			pInfo.race = m_pkChrTarget->GetRaceNum();
			pInfo.dwVnum = x.vnum;
			pInfo.count = x.count;
			pInfo.rarity = x.rarity;
		//....

//and to fill the vector (include the header again):

	// Drop Item Group
	{
		auto it = m_map_pkDropItemGroup.find(pkChr->GetRaceNum());

		if(it != m_map_pkDropItemGroup.end())
		{
			auto v = it->second->GetVector();
			

			for (DWORD i = 0; i < v.size(); ++i)
			{
				if( iLevel >= (iMobLevel - 15) && iLevel <= (iMobLevel + 15) )
				{
                  			drop_info info{};
                  			info.vnum = v[i].dwVnum;
                  			info.count = v[i].iCount;
                  			info.rarity = CalculateDropRarityDropItemGroup(v[i].dwPct, bType);
					vec_item.emplace_back(info);
				}
			}
		}
	}

 

Edited by xXIntelXx
  • Metin2 Dev 1
Link to comment
Share on other sites

  • 3 months later...
  • Premium
17 minutes ago, anton96 said:

I'm having exactly the same issue, can anyone help us fix this? should we remove everything in common_drop_item?

I don't think your players would enjoy to be inundated by low level/useless items anyway.. but you can choose not to show the common_drop_item stuff

 

 

Link to comment
Share on other sites

On 5/15/2023 at 2:25 PM, Intel said:

I don't think your players would enjoy to be inundated by low level/useless items anyway.. but you can choose not to show the common_drop_item stuff

 

 

do those items from common drop item actually drop? I've never seen a lvl 61 weapon drop from a dog or wolf.

How do I choose not to show the common_drop_item stuff?

does it make any sense to show the drops from common_drop_item in the target information system?

 

Edited by anton96
Link to comment
Share on other sites

  • Premium
8 hours ago, anton96 said:

do those items from common drop item actually drop? I've never seen a lvl 61 weapon drop from a dog or wolf.

How do I choose not to show the common_drop_item stuff?

does it make any sense to show the drops from common_drop_item in the target information system?

 

Of course it makes sense, if you edit it (otherwise just clean it).

Also, technically, they can drop from a dog.

	std::vector<CItemDropInfo>::iterator it = g_vec_pkCommonDropItem[bRank].begin();

	while (it != g_vec_pkCommonDropItem[bRank].end())
	{
		const CItemDropInfo & c_rInfo = *(it++);

		if(iLevel < c_rInfo.m_iLevelStart || iLevel > c_rInfo.m_iLevelEnd)
			continue;

		TItemTable * table = GetTable(c_rInfo.m_dwVnum);

		if(!table)
			continue;

		int rarity = CalculateDropRarityCommonDropItem((c_rInfo.m_iPercent * iDeltaPercent) / 100, iRandRange);
		if(rarity){
			vec_item.emplace_back(std::make_tuple(c_rInfo.m_dwVnum, 1, rarity));
		}
	}



uint8_t CalculateDropRarityCommonDropItem(const uint32_t pct, const uint32_t randRange)
{
	uint8_t rarity = 0;
	if(pct <= 0){
		return rarity;
	}

	const float realPct = static_cast<float>(pct)/randRange;
	const float minimumPct = 1.0f/randRange;

	if(realPct >= 1.0f)
		rarity = 1;
	else if(realPct < 1.0f && realPct >= 0.05f)
		rarity = 2;
	else if(realPct < 0.05f && realPct >= 0.0025f)
		rarity = 3;
	else if(realPct < 0.0025f && realPct >= 0.00125f)
		rarity = 4;
	else if(realPct < 0.00125 && realPct >= 0.00025f)
		rarity = 5;
	else if(realPct < 0.00025f && realPct > minimumPct)
		rarity = 6;
	
	return rarity;
}

I can assure you, rarity will not be 0 and a player lv60 would see the drop if the range is that high (although it would be very very very very low)

  • Love 1
Link to comment
Share on other sites

  • 4 weeks later...
On 5/20/2023 at 7:15 PM, Intel said:

Of course it makes sense, if you edit it (otherwise just clean it).

Also, technically, they can drop from a dog.

	std::vector<CItemDropInfo>::iterator it = g_vec_pkCommonDropItem[bRank].begin();

	while (it != g_vec_pkCommonDropItem[bRank].end())
	{
		const CItemDropInfo & c_rInfo = *(it++);

		if(iLevel < c_rInfo.m_iLevelStart || iLevel > c_rInfo.m_iLevelEnd)
			continue;

		TItemTable * table = GetTable(c_rInfo.m_dwVnum);

		if(!table)
			continue;

		int rarity = CalculateDropRarityCommonDropItem((c_rInfo.m_iPercent * iDeltaPercent) / 100, iRandRange);
		if(rarity){
			vec_item.emplace_back(std::make_tuple(c_rInfo.m_dwVnum, 1, rarity));
		}
	}



uint8_t CalculateDropRarityCommonDropItem(const uint32_t pct, const uint32_t randRange)
{
	uint8_t rarity = 0;
	if(pct <= 0){
		return rarity;
	}

	const float realPct = static_cast<float>(pct)/randRange;
	const float minimumPct = 1.0f/randRange;

	if(realPct >= 1.0f)
		rarity = 1;
	else if(realPct < 1.0f && realPct >= 0.05f)
		rarity = 2;
	else if(realPct < 0.05f && realPct >= 0.0025f)
		rarity = 3;
	else if(realPct < 0.0025f && realPct >= 0.00125f)
		rarity = 4;
	else if(realPct < 0.00125 && realPct >= 0.00025f)
		rarity = 5;
	else if(realPct < 0.00025f && realPct > minimumPct)
		rarity = 6;
	
	return rarity;
}

I can assure you, rarity will not be 0 and a player lv60 would see the drop if the range is that high (although it would be very very very very low)

Should this be placed under :?

#ifdef __SEND_TARGET_INFO__
bool ITEM_MANAGER::CreateDropItemVector(LPCHARACTER pkChr, LPCHARACTER pkKiller, std::vector<LPITEM> & vec_item)
{
	if (pkChr->IsPolymorphed() || pkChr->IsPC())
	{
		return false;
	}

	int iLevel = pkKiller->GetLevel();

	BYTE bRank = pkChr->GetMobRank();
	LPITEM item = NULL;

	std::vector<CItemDropInfo>::iterator it = g_vec_pkCommonDropItem[bRank].begin();

Or does it go under :?

bool ITEM_MANAGER::CreateDropItem(LPCHARACTER pkChr, LPCHARACTER pkKiller, std::vector<LPITEM> & vec_item)
{
	int iLevel = pkKiller->GetLevel();

	int iDeltaPercent, iRandRange;
	if (!GetDropPct(pkChr, pkKiller, iDeltaPercent, iRandRange))
		return false;

	BYTE bRank = pkChr->GetMobRank();
	LPITEM item = NULL;

	// Common Drop Items
std::vector<CItemDropInfo>::iterator it = g_vec_pkCommonDropItem[bRank].begin();

I've gotten a bit confused as to what should calculate drop rate should replace...

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.