Jump to content

Recommended Posts

  • Bot

Dear Metin2Dev,

I believe that many servers are still using old quests for giving mount bonuses from inventory, which are not bad but not very efficient either. Since I haven't seen anyone share something similar yet, I thought I'd share my solution for getting mount bonuses from the inventory.

You need to specify the bonuses in groups, similar to how you specify mob, etc, special drops. After you have set it up and the item is in your inventory, you will receive the bonus you have set.

How is a mount's bonus structured?

locale/germany/mount_bonus_table.txt:
Group MountTest1
{ 
  vnum 71224 --Mount item vnum from item_proto (type must be ITEM_QUEST (18))
  --You can add maximum 5 bonuses from config (it can be extended) 
  1 13 5  --13 = APPLY_STUN_PCT
  2 14 10 --14 = APPLY_SLOW_PCT 
  3 15 15 --15 = APPLY_CRITICAL_PCT 
  4 16 20 --16 = APPLY_PENETRATE_PCT 
  5 17 25 --17 = APPLY_ATTBONUS_HUMAN 
}

This system works with items whose type is ITEM_QUEST (18). It means that your mount item type must be ITEM_QUEST or it won't give you the bonuses. In the future, i'm planning to extend this system for costume mounts, but you can also do it for yourself. I think this is a good starting point for those are using the old quest solutions to give bonuses from inventory. 

Tutorial:

CommonDefines.h:

Spoiler
#define ADVANCED_MOUNT_BONUS_SYSTEM
#ifdef ADVANCED_MOUNT_BONUS_SYSTEM
#define ADV_MAX_BONUS_COUNT 5 //This allows for a maximum reading of 5 bonuses. However, it can be modified at any time to allow for more bonuses.
#endif

char.cpp:

Spoiler

Search for RefreshAffect(); in void CHARACTER::ComputePoints() and place below:

#ifdef ADVANCED_MOUNT_BONUS_SYSTEM
	if (IsPC())
	{
		pk_CheckMountBonus.clear();
		LPITEM pkMountItem;

		for (int i = 0; i < INVENTORY_MAX_NUM; ++i)
		{
			if ((pkMountItem = GetInventoryItem(i)) && pkMountItem->GetType() == ITEM_QUEST)
			{
				if (std::find(pk_CheckMountBonus.begin(), pk_CheckMountBonus.end(), pkMountItem->GetVnum()) == pk_CheckMountBonus.end())
				{
					ITEM_MANAGER::instance().AddMountBonus(this, pkMountItem->GetVnum());
				}
			}
		}
	}
#endif

Add to the end of the file:

#ifdef ADVANCED_MOUNT_BONUS_SYSTEM
bool CHARACTER::CheckMountBonus(DWORD dwVnum)
{
	if (std::find(pk_CheckMountBonus.begin(), pk_CheckMountBonus.end(), dwVnum) == pk_CheckMountBonus.end())
		return false;

	return true;
}

bool CHARACTER::AddMountBonus(DWORD dwVnum, bool bAdd)
{
	itertype(pk_CheckMountBonus) it = std::find(pk_CheckMountBonus.begin(), pk_CheckMountBonus.end(), dwVnum);

	if (it == pk_CheckMountBonus.end())
	{
		if (bAdd)
		{
			pk_CheckMountBonus.push_back(dwVnum);
		}
	}
	else
	{
		if (!bAdd)
		{
			pk_CheckMountBonus.erase(it);
		}
	}

	return true;
}

#endif

char.h:

Spoiler

Search for DragonSoul_RefineWindow_CanRefine(); and add below:

#ifdef ADVANCED_MOUNT_BONUS_SYSTEM
	protected:
		std::vector<DWORD> pk_CheckMountBonus;
	public:
		bool CheckMountBonus(DWORD dwVnum);
		bool AddMountBonus(DWORD dwVnum, bool bAdd);
#endif

char_item.cpp:

Spoiler

Search for this in void CHARACTER::SetItem

	if (pItem && pItem->GetOwner())
	{
		assert(!"GetOwner exist");
		return;
	}

Add this below:

#ifdef ADVANCED_MOUNT_BONUS_SYSTEM
	if (pItem && window_type == INVENTORY && wCell < INVENTORY_MAX_NUM)
	{
		if (pItem->GetType() == ITEM_QUEST)
		{
			ITEM_MANAGER::instance().AddMountBonus(this, pItem->GetVnum());
		}
	}
#endif

input_db.cpp:

Spoiler

Search for:

	snprintf(szDragonSoulTableFileName, sizeof(szDragonSoulTableFileName),
		"%s/dragon_soul_table.txt", LocaleService_GetBasePath().c_str());

And add this below:

#ifdef ADVANCED_MOUNT_BONUS_SYSTEM
	char szMountBonusTableFileName[FILE_NAME_LEN];
	snprintf(szMountBonusTableFileName, sizeof(szMountBonusTableFileName),
		"%s/mount_bonus_table.txt", LocaleService_GetBasePath().c_str());
#endif

Search for:

	if (!ITEM_MANAGER::instance().ReadMonsterDropItemGroup(szMOBDropItemFileName))
	{
		sys_err("cannot load MOBDropItemFile: %s", szMOBDropItemFileName);
		thecore_shutdown();
		return;
	}

And add this below:

#ifdef ADVANCED_MOUNT_BONUS_SYSTEM
	sys_log(0, "LoadLocaleFile: MountBonusInvFile: %s", szMountBonusTableFileName);
	if (!ITEM_MANAGER::instance().ReadMountBonusConfig(szMountBonusTableFileName))
	{
		sys_err("cannot load MountBonusInventoryConfigFile: %s", szMountBonusTableFileName);
	}
#endif

item.cpp:

Spoiler

Search for LPCHARACTER pOwner = m_pOwner; in CItem:RemoveFromCharacter() and add below:

#ifdef ADVANCED_MOUNT_BONUS_SYSTEM
	if (GetType() == ITEM_QUEST)
	{
		bool bCanRemove = true;
		LPITEM pkMountItem;

		for (int i = 0; i < INVENTORY_MAX_NUM; ++i)
		{
			if ((pkMountItem = pOwner->GetInventoryItem(i)) && pkMountItem->GetVnum() == GetVnum())
			{
				if (!(GetID() == pkMountItem->GetID()))
				{
					bCanRemove = false;
					break;
				}
			}
		}

		if (bCanRemove)
			ITEM_MANAGER::instance().AddMountBonus(pOwner, GetVnum(), false);
	}
#endif

item_manager.cpp:

Spoiler

Add to the end of the file:

#ifdef ADVANCED_MOUNT_BONUS_SYSTEM
bool ITEM_MANAGER::ReadMountBonusConfig(const char* c_pszFileName)
{
	m_map_mount_bonus.clear();
	CTextFileLoader loader;

	if (!loader.Load(c_pszFileName))
		return false;

	std::string stName;

	for (DWORD i = 0; i < loader.GetChildNodeCount(); ++i)
	{
		loader.SetChildNode(i);
		loader.GetCurrentNodeName(&stName);

		int iVnum = 0;
		if (!loader.GetTokenInteger("vnum", &iVnum))
		{
			sys_err("ReadMountBonusConfig : Syntax error %s : no vnum, node %s", c_pszFileName, stName.c_str());
			loader.SetParentNode();
			return false;
		}

		PKMountBonusInfo pk_MountBonus;

		char buf[4];
		TTokenVector* pTok;
		for (int k = 1; k < ADV_MAX_BONUS_COUNT + 1; ++k)
		{
			snprintf(buf, sizeof(buf), "%d", k);

			pk_MountBonus.bType[k - 1] = 0;
			pk_MountBonus.lValue[k - 1] = 0;

			if (loader.GetTokenVector(buf, &pTok))
			{
				int apply = 0;
				str_to_number(apply, pTok->at(0).c_str());

				int value = 0;
				str_to_number(value, pTok->at(1).c_str());

				pk_MountBonus.bType[k - 1] = apply;
				pk_MountBonus.lValue[k - 1] = value;
			}
		}

		m_map_mount_bonus[iVnum] = pk_MountBonus;

		loader.SetParentNode();
	}

	return true;
}

bool ITEM_MANAGER::AddMountBonus(LPCHARACTER ch, DWORD dwVnum, bool bAdd)
{
	if (ch == NULL)
		return false;

	if (bAdd && ch->CheckMountBonus(dwVnum))
	{
		return false;
	}

	if (bAdd == false && ch->CheckMountBonus(dwVnum) == false)
	{
		return false;
	}

	auto it = m_map_mount_bonus.find(dwVnum);
	if (it == m_map_mount_bonus.end())
		return false;

	ch->AddMountBonus(dwVnum, bAdd);

	for (int i = 0; i < ADV_MAX_BONUS_COUNT; ++i)
	{
		if (it->second.bType[i] > 0 && it->second.lValue[i] > 0)
		{
			if (bAdd)
				ch->ApplyPoint(it->second.bType[i], it->second.lValue[i]);
			else
				ch->ApplyPoint(it->second.bType[i], -it->second.lValue[i]);
		}
	}

	return true;
}

#endif

item_manager.h:

Spoiler

 

Search for:

	public:
		DWORD	GetMaskVnum(DWORD dwVnum);
		std::map<DWORD, TItemTable>  m_map_vid;
		std::map<DWORD, TItemTable>&  GetVIDMap() { return m_map_vid; }
		std::vector<TItemTable>& GetVecProto() { return m_vec_prototype; }
		bool ReadItemVnumMaskTable(const char * c_pszFileName);

And add this above:

#ifdef ADVANCED_MOUNT_BONUS_SYSTEM
		struct PKMountBonusInfo
		{
			BYTE bType[ADV_MAX_BONUS_COUNT];
			long long int lValue[ADV_MAX_BONUS_COUNT];
		};

	public:
		bool ReadMountBonusConfig(const char* c_pszFileName);
		bool AddMountBonus(LPCHARACTER ch, DWORD dwVnum, bool bAdd = true);

	protected:
		std::map<DWORD, PKMountBonusInfo> m_map_mount_bonus;
#endif

If you have any ideas on how to make this system better, please leave a comment. 

I hope this will be useful for you. ?

 

Best Regards,

piktorvik

Edited by piktorvik
  • Metin2 Dev 5
  • Eyes 1
  • Good 1
  • muscle 1
  • Love 6

english_banner.gif

Link to comment
https://metin2.dev/topic/32208-advanced-mount-bonus-system/
Share on other sites

  • Premium
Group MountTest1
{ 
  vnum 71224
  1 STUN_PCT 5
  2 SLOW_PCT 10 
  3 CRITICAL_PCT 15 
  4 PENETRATE_PCT 20
  5 ATTBONUS_HUMAN 25
}

This way, a bit prettier

int apply = FN_get_apply_type(pTok->at(0).c_str());

 

Edited by Morpheus™
  • Metin2 Dev 3

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.