Jump to content

Recommended Posts

  • Active+ Member

special_item_group.json

Why?

First things first, I truly dislike the weird tab sperated file format, second using a json schema you have good IDE integration, third I was bored and I also wanted the polymorph marble bit from chests bit Gurgarath posted, besides that you can set any socket you may wish.

Requirements

Installing requirements (Using vcpkg and CMake)

Run command.

vcpkg install nlohmann-json

Add to the CMakeLists.txt for game (src/game/CMakeLists.txt)

# nlohmann/json
find_package(nlohmann_json CONFIG REQUIRED)
target_link_libraries(${PROJECT_NAME} PRIVATE nlohmann_json::nlohmann_json)

Changes

Please do not fully copy paste the values as your source will probably differ from my own code. I'm also using SPDLPG, you might want to change it's calls to the equivalent sys_ function.

item_manager_read_tables.cpp
Add at the top of the file after your includes

#include <nlohmann/json.hpp>

Function ReadSpecialDropItemFile
Here you'll find most of the changes as it does all the file parsing.

This is the hidden content, please

item_manager.h (CSpecialItemGroup)
All the changes here are for supporting the sockets changes.

Spoiler
class CSpecialItemGroup
{
public:
	enum EGiveType
	{
		NONE,
		GOLD,
		EXP,
		MOB,
		SLOW,
		DRAIN_HP,
		POISON,
		MOB_GROUP,
	};

	// QUEST 타입은 퀘스트 스크립트에서 vnum.sig_use를 사용할 수 있는 그룹이다.
	//		단, 이 그룹에 들어가기 위해서는 ITEM 자체의 TYPE이 QUEST여야 한다.
	// SPECIAL 타입은 idx, item_vnum, attr_vnum을 입력한다. attr_vnum은 위에 CSpecialAttrGroup의 Vnum이다.
	//		이 그룹에 들어있는 아이템은 같이 착용할 수 없다.
	enum ESIGType
	{
		NORMAL,
		PCT,
		QUEST,
		SPECIAL
	};

	struct CSpecialItemInfo
	{
		DWORD vnum;
		int count;
		int rare;
		std::vector<int> sockets;

		CSpecialItemInfo(DWORD _vnum, int _count, int _rare, std::vector<int> _sockets)
			: vnum(_vnum), count(_count), rare(_rare), sockets(_sockets)
		{
		}
	};

	CSpecialItemGroup(DWORD vnum, BYTE type = 0)
		: m_dwVnum(vnum), m_bType(type)
	{
	}

	void AddItem(DWORD vnum, int count, int prob, int rare, std::vector<int> sockets)
	{
		if (!prob)
			return;
		if (!m_vecProbs.empty())
			prob += m_vecProbs.back();
		m_vecProbs.push_back(prob);
		m_vecItems.push_back(CSpecialItemInfo(vnum, count, rare, sockets));
	}

	bool IsEmpty() const
	{
		return m_vecProbs.empty();
	}

	// Type Multi, 즉 m_bType == PCT 인 경우,
	// 확률을 더해가지 않고, 독립적으로 계산하여 아이템을 생성한다.
	// 따라서 여러 개의 아이템이 생성될 수 있다.
	// by rtsummit
	int GetMultiIndex(std::vector<int> &idx_vec) const
	{
		idx_vec.clear();
		if (m_bType == PCT)
		{
			int count = 0;
			if (Random::get(1, 100) <= m_vecProbs[0])
			{
				idx_vec.push_back(0);
				count++;
			}
			for (uint i = 1; i < m_vecProbs.size(); i++)
			{
				if (Random::get(1, 100) <= m_vecProbs[i] - m_vecProbs[i - 1])
				{
					idx_vec.push_back(i);
					count++;
				}
			}
			return count;
		}
		else
		{
			idx_vec.push_back(GetOneIndex());
			return 1;
		}
	}

	int GetOneIndex() const
	{
		int n = Random::get(1, m_vecProbs.back());
		itertype(m_vecProbs) it = lower_bound(m_vecProbs.begin(), m_vecProbs.end(), n);
		return std::distance(m_vecProbs.begin(), it);
	}

	int GetVnum(int idx) const
	{
		return m_vecItems[idx].vnum;
	}

	int GetCount(int idx) const
	{
		return m_vecItems[idx].count;
	}

	int GetRarePct(int idx) const
	{
		return m_vecItems[idx].rare;
	}

	std::vector<int> GetSockets(int idx) const
	{
		return m_vecItems[idx].sockets;
	}

	bool Contains(DWORD dwVnum) const
	{
		for (DWORD i = 0; i < m_vecItems.size(); i++)
		{
			if (m_vecItems[i].vnum == dwVnum)
				return true;
		}
		return false;
	}

	// Group의 Type이 Special인 경우에
	// dwVnum에 매칭되는 AttrVnum을 return해준다.
	DWORD GetAttrVnum(DWORD dwVnum) const
	{
		if (CSpecialItemGroup::SPECIAL != m_bType)
			return 0;
		for (itertype(m_vecItems) it = m_vecItems.begin(); it != m_vecItems.end(); it++)
		{
			if (it->vnum == dwVnum)
			{
				return it->count;
			}
		}
		return 0;
	}

	DWORD m_dwVnum;
	BYTE m_bType;
	std::vector<int> m_vecProbs;
	std::vector<CSpecialItemInfo> m_vecItems; // vnum, count
};

 

char_item.cpp (GiveItemFromSpecialItemGroup)
Here as well all changes are for supporting the sockets.

Spoiler
bool CHARACTER::GiveItemFromSpecialItemGroup(DWORD dwGroupNum, std::vector<DWORD> &dwItemVnums,
											 std::vector<DWORD> &dwItemCounts, std::vector<LPITEM> &item_gets, int &count)
{
	const CSpecialItemGroup *pGroup = ITEM_MANAGER::instance().GetSpecialItemGroup(dwGroupNum);

	if (!pGroup)
	{
		SPDLOG_ERROR("cannot find special item group {}", dwGroupNum);
		return false;
	}

	std::vector<int> idxes;
	int n = pGroup->GetMultiIndex(idxes);

	bool bSuccess;

	for (int i = 0; i < n; i++)
	{
		bSuccess = false;
		int idx = idxes[i];
		DWORD dwVnum = pGroup->GetVnum(idx);
		DWORD dwCount = pGroup->GetCount(idx);
		int iRarePct = pGroup->GetRarePct(idx);
		std::vector<int> vSockets = pGroup->GetSockets(idx);
		LPITEM item_get = NULL;
		switch (dwVnum)
		{
		case CSpecialItemGroup::GOLD:
			PointChange(POINT_GOLD, dwCount);
			LogManager::instance().CharLog(this, dwCount, "TREASURE_GOLD", "");

			bSuccess = true;
			break;

		case CSpecialItemGroup::EXP:
		{
			PointChange(POINT_EXP, dwCount);
			LogManager::instance().CharLog(this, dwCount, "TREASURE_EXP", "");

			bSuccess = true;
		}
		break;

		case CSpecialItemGroup::MOB:
		{
			SPDLOG_DEBUG("CSpecialItemGroup::MOB {}", dwCount);
			int x = GetX() + Random::get(-500, 500);
			int y = GetY() + Random::get(-500, 500);

			LPCHARACTER ch = CHARACTER_MANAGER::instance().SpawnMob(dwCount, GetMapIndex(), x, y, 0, true, -1);
			if (ch)
				ch->SetAggressive();
			bSuccess = true;
		}
		break;

		case CSpecialItemGroup::SLOW:
		{
			SPDLOG_DEBUG("CSpecialItemGroup::SLOW {}", -(int)dwCount);
			AddAffect(AFFECT_SLOW, POINT_MOV_SPEED, -(int)dwCount, AFF_SLOW, 300, 0, true);
			bSuccess = true;
		}
		break;

		case CSpecialItemGroup::DRAIN_HP:
		{
			int iDropHP = GetMaxHP() * dwCount / 100;
			SPDLOG_DEBUG("CSpecialItemGroup::DRAIN_HP {}", -iDropHP);
			iDropHP = std::min(iDropHP, GetHP() - 1);
			SPDLOG_DEBUG("CSpecialItemGroup::DRAIN_HP {}", -iDropHP);
			PointChange(POINT_HP, -iDropHP);
			bSuccess = true;
		}
		break;

		case CSpecialItemGroup::POISON:
		{
			AttackedByPoison(NULL);
			bSuccess = true;
		}
		break;

		case CSpecialItemGroup::MOB_GROUP:
		{
			int sx = GetX() - Random::get(300, 500);
			int sy = GetY() - Random::get(300, 500);
			int ex = GetX() + Random::get(300, 500);
			int ey = GetY() + Random::get(300, 500);
			CHARACTER_MANAGER::instance().SpawnGroup(dwCount, GetMapIndex(), sx, sy, ex, ey, NULL, true);

			bSuccess = true;
		}
		break;
		default:
		{
			item_get = AutoGiveItem(dwVnum, dwCount, iRarePct);

			if (item_get)
			{
				if (vSockets.size() != 0)
				{
					for (int socketIdx = 0; socketIdx < vSockets.size(); ++socketIdx)
						item_get->SetSocket(socketIdx, vSockets[socketIdx]);
				}

				bSuccess = true;
			}
		}
		break;
		}

		if (bSuccess)
		{
			dwItemVnums.push_back(dwVnum);
			dwItemCounts.push_back(dwCount);
			item_gets.push_back(item_get);
			count++;
		}
		else
		{
			return false;
		}
	}
	return bSuccess;
}

 

Input_db.cpp
Everything  here is pretty simple, just look for wherever you call something like the below and make .txt into .json

snprintf(szSpecialItemGroupFileName, sizeof(szSpecialItemGroupFileName),
			 "%s/special_item_group.json", LocaleService_GetBasePath().c_str());


File Conversion
As for the conversion part all you need to do is paste your `special_item_group.txt` into the textbox in the url below and click submit, that should give you a good JSON file to start with using the schema I provide in a different repo.

M2 JSON - Special Item Group

  • Metin2 Dev 9
  • Good 2
  • muscle 1
  • Love 3
Link to comment
https://metin2.dev/topic/34065-special-item-group-json/
Share on other sites

Don't use any images from : imgur, turkmmop, freakgamers, inforge, hizliresim... Or your content will be deleted without notice...
Use : https://metin2.download/media/add/

Please use https://metin2.download/ when uploading files smaller than 100MB, otherwise the approval will take longer due to manual upload.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • 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.