Jump to content
×
×
  • Create New...

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 2
Link to comment
Share on other sites

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 comment
Share on other sites

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.

when you return 0 and server doesn't boot:

unknown.png

Link to comment
Share on other sites

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 comment
Share on other sites

  • 9 months later...

Before you share your C++ edit, please test it on your own, this code cant work. with your Edit I get compile error because of the char_item.cpp if I change my values item2->AddAttribute(); & ChangeAttribute to AddCostumeAttribute & ChangeCostumeAttribute() it only removes my item and dont add / change bonus.

Edited by crewfire1337
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.


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.