Jump to content

Advanced Mount Bonus System


Recommended Posts

  • Premium

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 4
  • Eyes 1
  • Good 1
  • muscle 1
  • Love 4
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.