Cappuccino 43 Posted February 7, 2021 Share Posted February 7, 2021 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 2 2 Link to comment Share on other sites More sharing options...
Hi Ley 601 Posted February 8, 2021 Share Posted February 8, 2021 the weapon, body,wrist, neck, etc etc are useless, the only ones needed are costume_body, hair and at last, weapon. Link to comment Share on other sites More sharing options...
Cappuccino 43 Posted February 8, 2021 Author Share Posted February 8, 2021 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 More sharing options...
Developer PACI 921 Posted February 8, 2021 Developer Share Posted February 8, 2021 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: Link to comment Share on other sites More sharing options...
Cappuccino 43 Posted February 8, 2021 Author Share Posted February 8, 2021 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 More sharing options...
crewfire1337 31 Posted November 22, 2021 Share Posted November 22, 2021 (edited) 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 November 22, 2021 by crewfire1337 Link to comment Share on other sites More sharing options...
garofolo 12 Posted December 29, 2022 Share Posted December 29, 2022 (edited) I tested and that works. But he is reading the item_attr_rare table bonuses instead of `item_attr_costume` everything is fine same the tutorial. that is my char_item.cpp Spoiler case 79998 : // ADDBONUS TRAJE { LPITEM item2; if (!IsValidItemPosition(DestCell) || !(item2 = GetInventoryItem(wDestCell))) return false; if (item2->IsExchanging() == true) return false; if (item2->IsEquipped() == true) // Fix return false; // if (item2->GetType() == ITEM_COSTUME) // Fix // return false; if (item2->GetAttributeSetIndex() == -1) { ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Nao foi possivel.")); return false; } if (item2->GetType() == ITEM_COSTUME) // Fix { if (item2->GetAttributeCount() < 3) { if (item2->AddCostumeAttribute()) { item->SetCount(item->GetCount() - 1); } } else { ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Nao e possivel adicionar mais bonus")); } } } break; and my item_atribrute.cpp Spoiler same tutorial using const TItemAttrTable& r = g_map_itemAttrCostume[avail[number(0, avail.size() - 1)]]; i make clientemanager and clientmanagerboot.cpp same as in the tutorial. that dont make sense =/ Edited December 29, 2022 by garofolo Link to comment Share on other sites More sharing options...
Recommended Posts