Jump to content

Separated table for costume bonuses


Recommended Posts

Costume bonuses are taken from item_attr table but this is quite a limit.

We are going to create a second table item_attr_costume which will contain only costume bonuses.

Transform costume and Enchant costume will take bonus from the new table item_attr_costume.

 

 

Let's start.

 

Open ClientManagerBoot.cpp and add at the end


bool CClientManager::InitializeCostumeAttrTable()
{
	char query[4096];
	snprintf(query, sizeof(query),
		"SELECT apply, apply+0, prob, lv1, lv2, lv3, lv4, lv5, weapon, body, wrist, foots, neck, head, shield, ear FROM item_attr_costume%s ORDER BY apply",
		GetTablePostfix());

	std::unique_ptr<SQLMsg> pkMsg(CDBManager::instance().DirectQuery(query));
	SQLResult* pRes = pkMsg->Get();

	if (!pRes->uiNumRows)
	{
		sys_err("no result from item_attr_costume");
		return false;
	}

	if (!m_vec_costumeAttrTable.empty())
	{
		sys_log(0, "RELOAD: item_attr_costume");
		m_vec_costumeAttrTable.clear();
	}

	m_vec_costumeAttrTable.reserve(pRes->uiNumRows);

	MYSQL_ROW	data;

	while ((data = mysql_fetch_row(pRes->pSQLResult)))
	{
		TItemAttrTable t{};

		int col = 0;

		strlcpy(t.szApply, data[col++], sizeof(t.szApply));
		str_to_number(t.dwApplyIndex, data[col++]);
		str_to_number(t.dwProb, data[col++]);
		str_to_number(t.lValues[0], data[col++]);
		str_to_number(t.lValues[1], data[col++]);
		str_to_number(t.lValues[2], data[col++]);
		str_to_number(t.lValues[3], data[col++]);
		str_to_number(t.lValues[4], data[col++]);
		str_to_number(t.bMaxLevelBySet[ATTRIBUTE_SET_WEAPON], data[col++]);
		str_to_number(t.bMaxLevelBySet[ATTRIBUTE_SET_BODY], data[col++]);
		str_to_number(t.bMaxLevelBySet[ATTRIBUTE_SET_WRIST], data[col++]);
		str_to_number(t.bMaxLevelBySet[ATTRIBUTE_SET_FOOTS], data[col++]);
		str_to_number(t.bMaxLevelBySet[ATTRIBUTE_SET_NECK], data[col++]);
		str_to_number(t.bMaxLevelBySet[ATTRIBUTE_SET_HEAD], data[col++]);
		str_to_number(t.bMaxLevelBySet[ATTRIBUTE_SET_SHIELD], data[col++]);
		str_to_number(t.bMaxLevelBySet[ATTRIBUTE_SET_EAR], data[col++]);

		m_vec_costumeAttrTable.push_back(t);
	}

	return true;
}

 

Search

	if (!InitializeItemRareTable())
	{
		sys_err("InitializeItemRareTable FAILED");
		return false;
	}

 

add under

 

	if (!InitializeCostumeAttrTable())
	{
		sys_err("InitializeCostumeAttrTable FAILED");
		return false;
	}

 

open ClientManager.h and look for

	bool		InitializeMonarch();

add under

	bool        InitializeCostumeAttrTable();

 

look for

	std::vector<TItemAttrTable>		m_vec_itemRareTable;

add under

	std::vector<TItemAttrTable>     m_vec_costumeAttrTable;

open ClientManager.cpp and look for

		tmp->EncodeWORD(m_vec_itemRareTable.size());
		tmp->Encode(&m_vec_itemRareTable[0], sizeof(TItemAttrTable) * m_vec_itemRareTable.size());

add under

		tmp->EncodeWORD(m_vec_costumeAttrTable.size());
		tmp->Encode(&m_vec_costumeAttrTable[0], sizeof(TItemAttrTable) * m_vec_costumeAttrTable.size());

 

look for

		sizeof(WORD) + sizeof(WORD) + sizeof(TItemAttrTable) * m_vec_itemRareTable.size() +

 

add under

		sizeof(WORD) + sizeof(WORD) + sizeof(TItemAttrTable) * m_vec_costumeAttrTable.size() +

 

look for

		tmp->EncodeHeader(HEADER_DG_RELOAD_PROTO, 0,
			sizeof(WORD) + sizeof(TSkillTable) * m_vec_skillTable.size() +
			sizeof(WORD) + sizeof(TBanwordTable) * m_vec_banwordTable.size() +
			sizeof(WORD) + sizeof(TItemTable) * m_vec_itemTable.size() +
			sizeof(WORD) + sizeof(TMobTable) * m_vec_mobTable.size() +
			sizeof(WORD) + sizeof(TShopTable) * m_iShopTableSize +
			sizeof(WORD) + sizeof(TRefineTable) * m_iRefineTableSize +
			sizeof(WORD) + sizeof(TItemAttrTable) * m_vec_itemAttrTable.size() +
			sizeof(WORD) + sizeof(TItemAttrTable) * m_vec_itemRareTable.size();

 

and change it like this

		tmp->EncodeHeader(HEADER_DG_RELOAD_PROTO, 0,
			sizeof(WORD) + sizeof(TSkillTable) * m_vec_skillTable.size() +
			sizeof(WORD) + sizeof(TBanwordTable) * m_vec_banwordTable.size() +
			sizeof(WORD) + sizeof(TItemTable) * m_vec_itemTable.size() +
			sizeof(WORD) + sizeof(TMobTable) * m_vec_mobTable.size() +
			sizeof(WORD) + sizeof(TShopTable) * m_iShopTableSize +
			sizeof(WORD) + sizeof(TRefineTable) * m_iRefineTableSize +
			sizeof(WORD) + sizeof(TItemAttrTable) * m_vec_itemAttrTable.size() +
			sizeof(WORD) + sizeof(TItemAttrTable) * m_vec_itemRareTable.size() +
			sizeof(WORD) + sizeof(TItemAttrTable) * m_vec_costumeAttrTable.size());

 

look for

	peer->EncodeWORD(sizeof(TItemAttrTable));
	peer->EncodeWORD(m_vec_itemRareTable.size());
	peer->Encode(&m_vec_itemRareTable[0], sizeof(TItemAttrTable) * m_vec_itemRareTable.size());

add under

	peer->EncodeWORD(sizeof(TItemAttrTable));
	peer->EncodeWORD(m_vec_costumeAttrTable.size());
	peer->Encode(&m_vec_costumeAttrTable[0], sizeof(TItemAttrTable) * m_vec_costumeAttrTable.size());

 

open constants.cpp and look for

TItemAttrMap g_map_itemRare;

add under

TItemAttrMap g_map_itemAttrCostume;

 

open constants.h and look for

extern TItemAttrMap g_map_itemRare;

add under

extern TItemAttrMap g_map_itemAttrCostume;

 

open input_db.cpp and look for

	/*
     * ITEM RARE
     */
	if (decode_2bytes(data) != sizeof(TItemAttrTable))
	{
		sys_err("item rare table size error");
		thecore_shutdown();
		return;
	}
	data += 2;

	size = decode_2bytes(data);
	data += 2;
	sys_log(0, "BOOT: ITEM_RARE: %d", size);

	if (size)
	{
		TItemAttrTable * p = (TItemAttrTable *) data;

		for (int i = 0; i < size; ++i, ++p)
		{
			if (p->dwApplyIndex >= MAX_APPLY_NUM)
				continue;

			g_map_itemRare[p->dwApplyIndex] = *p;
			sys_log(0, "ITEM_RARE[%d]: %s %u", p->dwApplyIndex, p->szApply, p->dwProb);
		}
	}

	data += size * sizeof(TItemAttrTable);

 

add under


	/*
	 * ITEM ATTR COSTUME
	 */
	if (decode_2bytes(data) != sizeof(TItemAttrTable))
	{
		sys_err("item attr costume table size error");
		thecore_shutdown();
		return;
	}
	data += 2;

	size = decode_2bytes(data);
	data += 2;
	sys_log(0, "BOOT: ITEM_ATTR_COSTUME: %d", size);

	if (size)
	{
		TItemAttrTable* p = (TItemAttrTable*)data;

		for (int i = 0; i < size; ++i, ++p)
		{
			if (p->dwApplyIndex >= MAX_APPLY_NUM)
				continue;

			g_map_itemAttrCostume[p->dwApplyIndex] = *p;
			sys_log(0, "ITEM_ATTR_COSTUME[%d]: %s %u", p->dwApplyIndex, p->szApply, p->dwProb);
		}
	}

	data += size * sizeof(TItemAttrTable);

 

open item_attribute.cpp and add these functions at the end (I don't remember why I rewrote this part, just replace your functions if you already have them)

 

bool CItem::AddCostumeAttribute()
{
	int count = GetAttributeCount();

	if (count >= COSTUME_ATTRIBUTE_MAX_LEVEL)
		return false;

	int pos = count;
	TPlayerItemAttribute& attr = m_aAttr[pos];

	int nAttrSet = GetAttributeSetIndex();
	std::vector<int> avail;

	for (int i = 0; i < MAX_APPLY_NUM; ++i)
	{
		const TItemAttrTable& r = g_map_itemAttrCostume[i];

		if (r.dwApplyIndex != 0 && r.bMaxLevelBySet[nAttrSet] > 0 && HasAttr(i) != true)
		{
			avail.push_back(i);
		}
	}

	if (avail.size() == 0) {
		return false;
	}

	const TItemAttrTable& r = g_map_itemAttrCostume[avail[number(0, avail.size() - 1)]];

	int nAttrLevel = number(1, 5);

	if (nAttrLevel > r.bMaxLevelBySet[nAttrSet])
		nAttrLevel = r.bMaxLevelBySet[nAttrSet];

	attr.bType = r.dwApplyIndex;
	attr.sValue = r.lValues[nAttrLevel - 1];

	UpdatePacket();

	Save();

	return true;
}

bool CItem::AddRandomNumberOfCostumeAttributes()
{
	int cnt = GetAttributeCount();
  	int new_bonus_cnt = number(1, 3);

	for (int i = 0; i < cnt; ++i)
	{
		m_aAttr[i].bType = 0;
		m_aAttr[i].sValue = 0;
	}
  
  	for (int i = 0; i < new_bonus_cnt ; ++i)
	{
		AddCostumeAttribute();
	}

	return true;
}

bool CItem::ChangeCostumeAttribute()
{
	int cnt = GetAttributeCount();

	for (int i = 0; i < cnt; ++i)
	{
		m_aAttr[i].bType = 0;
		m_aAttr[i].sValue = 0;
	}

	for (int i = 0; i < cnt; ++i)
	{
		AddCostumeAttribute();
	}

	return true;
}

 

 

open item_length.h and look for

	ITEM_ATTRIBUTE_MAX_LEVEL = 5,

add under

	COSTUME_ATTRIBUTE_MAX_LEVEL = 5,

 

open item.h and look for

		int			GetRareAttrCount();
		bool		AddRareAttribute();

add under

		bool		AddCostumeAttribute();
		bool		ChangeCostumeAttribute();
		bool		AddRandomNumberOfCostumeAttributes();

 

 

open char_item.cpp and look for

 

							switch (item->GetSubType())
							{
								case USE_CHANGE_COSTUME_ATTR:
									item2->ChangeAttribute();
									{
										char buf[21];
										snprintf(buf, sizeof(buf), "%u", item2->GetID());
										LogManager::instance().ItemLog(this, item, "CHANGE_COSTUME_ATTR", buf);
									}
									break;
								case USE_RESET_COSTUME_ATTR:
									item2->ClearAttribute();
									item2->AlterToMagicItem();
									{
										char buf[21];
										snprintf(buf, sizeof(buf), "%u", item2->GetID());
										LogManager::instance().ItemLog(this, item, "RESET_COSTUME_ATTR", buf);
									}
									break;
							}

							ChatPacket(CHAT_TYPE_INFO, LC_TEXT("¼Ó¼ºÀ» º¯°æÇÏ¿´½À´Ï´Ù."));

							item->SetCount(item->GetCount() - 1);
							break;

 

replace with

							if (item->GetSubType() == USE_RESET_COSTUME_ATTR) {
								if (item2->GetAttributeCount() < 3) {
									if (item2->AddCostumeAttribute()) {
										item->SetCount(item->GetCount() - 1);
									}
								}
							
							}
							else {
								if (item2->GetAttributeCount() == 0)
								{
									ChatPacket(CHAT_TYPE_INFO, "You must add some bonuses first.");
									return false;
								}

								if (item2->ChangeCostumeAttribute()) {
									item->SetCount(item->GetCount() - 1);
								}
							}
							break;

 

 

run this query in your database player:

 

DROP TABLE IF EXISTS `item_attr_costume`;
CREATE TABLE `item_attr_costume` (
  `apply` enum('MAX_HP','MAX_SP','CON','INT','STR','DEX','ATT_SPEED','MOV_SPEED','CAST_SPEED','HP_REGEN','SP_REGEN','POISON_PCT','STUN_PCT','SLOW_PCT','CRITICAL_PCT','PENETRATE_PCT','ATTBONUS_HUMAN','ATTBONUS_ANIMAL','ATTBONUS_ORC','ATTBONUS_MILGYO','ATTBONUS_UNDEAD','ATTBONUS_DEVIL','STEAL_HP','STEAL_SP','MANA_BURN_PCT','DAMAGE_SP_RECOVER','BLOCK','DODGE','RESIST_SWORD','RESIST_TWOHAND','RESIST_DAGGER','RESIST_BELL','RESIST_FAN','RESIST_BOW','RESIST_FIRE','RESIST_ELEC','RESIST_MAGIC','RESIST_WIND','REFLECT_MELEE','REFLECT_CURSE','POISON_REDUCE','KILL_SP_RECOVER','EXP_DOUBLE_BONUS','GOLD_DOUBLE_BONUS','ITEM_DROP_BONUS','POTION_BONUS','KILL_HP_RECOVER','IMMUNE_STUN','IMMUNE_SLOW','IMMUNE_FALL','SKILL','BOW_DISTANCE','ATT_GRADE_BONUS','DEF_GRADE_BONUS','MAGIC_ATT_GRADE_BONUS','MAGIC_DEF_GRADE_BONUS','CURSE_PCT','MAX_STAMINA','ATT_BONUS_TO_WARRIOR','ATT_BONUS_TO_ASSASSIN','ATT_BONUS_TO_SURA','ATT_BONUS_TO_SHAMAN','ATT_BONUS_TO_MONSTER','ATT_BONUS','MALL_DEFBONUS','MALL_EXPBONUS','MALL_ITEMBONUS','MALL_GOLDBONUS','MAX_HP_PCT','MAX_SP_PCT','SKILL_DAMAGE_BONUS','NORMAL_HIT_DAMAGE_BONUS','SKILL_DEFEND_BONUS','NORMAL_HIT_DEFEND_BONUS','PC_BANG_EXP_BONUS','PC_BANG_DROP_BONUS','EXTRACT_HP_PCT','RESIST_WARRIOR','RESIST_ASSASSIN','RESIST_SURA','RESIST_SHAMAN','ENERGY','DEF_GRADE','COSTUME_ATTR_BONUS','MAGIC_ATT_BONUS_PER','MELEE_MAGIC_ATT_BONUS_PER','RESIST_ICE','RESIST_EARTH','RESIST_DARK','RESIST_CRITICAL','RESIST_PENETRATE','BLEEDING_REDUCE','BLEEDING_PCT','ATT_BONUS_TO_WOLFMAN','RESIST_WOLFMAN','RESIST_CLAW') NOT NULL DEFAULT 'MAX_HP',
  `prob` int unsigned NOT NULL DEFAULT '0',
  `lv1` int unsigned NOT NULL DEFAULT '0',
  `lv2` int unsigned NOT NULL DEFAULT '0',
  `lv3` int unsigned NOT NULL DEFAULT '0',
  `lv4` int unsigned NOT NULL DEFAULT '0',
  `lv5` int unsigned NOT NULL DEFAULT '0',
  `weapon` int unsigned NOT NULL DEFAULT '0',
  `body` int unsigned NOT NULL DEFAULT '0',
  `wrist` int unsigned NOT NULL DEFAULT '0',
  `foots` int unsigned NOT NULL DEFAULT '0',
  `neck` int unsigned NOT NULL DEFAULT '0',
  `head` int unsigned NOT NULL DEFAULT '0',
  `shield` int unsigned NOT NULL DEFAULT '0',
  `ear` int unsigned NOT NULL DEFAULT '0',
  `costume_body` int unsigned NOT NULL DEFAULT '0',
  `costume_hair` int unsigned NOT NULL DEFAULT '0',
  `costume_weapon` int unsigned NOT NULL DEFAULT '0'
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
SET FOREIGN_KEY_CHECKS=1;

 

and you can add bonuses you want for costumes in it :)

 

that's it :) 

  • Metin2 Dev 2
  • Love 1
Link to post
16 minutes ago, Hi Ley said:

the weapon, body,wrist, neck, etc etc are useless, the only ones needed are costume_body, hair and at last, weapon.

Yes, of course. You can drop the not necessary columns if you want but more modificaitons to the source are required.

 

Link to post
21 hours ago, Cappuccino said:

Costume bonuses are taken from item_attr table but this is quite a limit.

May I ask why is this limited?

You could as well just create separate fields for costume_body, costume_head, costume_weapon (or even costume_acce, if wanted), in the common item_attr table, and you'd break the limitation, if any.

Link to post
2 hours ago, PACI said:

May I ask why is this limited?

You could as well just create separate fields for costume_body, costume_head, costume_weapon (or even costume_acce, if wanted), in the common item_attr table, and you'd break the limitation, if any.

Yes you can, but the bonus values will be shared with normal items.

For example, you might want to set a different bonus value for "chance of critical damage" for costumes.

Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



Shoutbox

Shoutbox

Chatroom Rules

 

Join our Discord

A request for help = Shoutbox Ban

Be respectful & Respect the rules

 

×
×
  • 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.