From daec5bde662dcb6b9241e14b802c91f64be4358a Mon Sep 17 00:00:00 2001 From: Natedog2012 Date: Wed, 26 Nov 2014 13:57:18 -0800 Subject: [PATCH] Item Transformation now works! --- common/item.cpp | 56 +++++++++++++++++++ common/item.h | 7 +++ common/patches/rof.cpp | 10 ++++ common/patches/underfoot.cpp | 6 ++ common/ruletypes.h | 2 + common/shareddb.cpp | 27 +++++++-- .../2014_11_26_TransformationRules.sql | 3 + .../2014_11_26_InventoryTableUpdate.sql | 4 ++ world/worlddb.cpp | 3 + zone/client.cpp | 18 +++++- zone/client.h | 2 +- zone/client_packet.cpp | 4 ++ zone/inventory.cpp | 7 ++- zone/mob.cpp | 3 + zone/string_ids.h | 2 + zone/tradeskills.cpp | 20 +++++++ 16 files changed, 166 insertions(+), 8 deletions(-) create mode 100644 utils/sql/git/optional/2014_11_26_TransformationRules.sql create mode 100644 utils/sql/git/required/2014_11_26_InventoryTableUpdate.sql diff --git a/common/item.cpp b/common/item.cpp index e59edebe3..ca469aa6e 100644 --- a/common/item.cpp +++ b/common/item.cpp @@ -1412,6 +1412,8 @@ ItemInst::ItemInst(const Item_Struct* item, int16 charges) { m_scaledItem = nullptr; m_evolveInfo = nullptr; m_scaling = false; + m_ornamenticon = 0; + m_ornamentidfile = 0; } ItemInst::ItemInst(SharedDatabase *db, uint32 item_id, int16 charges) { @@ -1434,6 +1436,8 @@ ItemInst::ItemInst(SharedDatabase *db, uint32 item_id, int16 charges) { m_scaledItem = nullptr; m_evolveInfo = nullptr; m_scaling = false; + m_ornamenticon = 0; + m_ornamentidfile = 0; } ItemInst::ItemInst(ItemInstTypes use_type) { @@ -1451,6 +1455,8 @@ ItemInst::ItemInst(ItemInstTypes use_type) { m_scaledItem = nullptr; m_evolveInfo = nullptr; m_scaling = false; + m_ornamenticon = 0; + m_ornamentidfile = 0; } // Make a copy of an ItemInst object @@ -1501,6 +1507,8 @@ ItemInst::ItemInst(const ItemInst& copy) m_evolveInfo = nullptr; m_scaling = copy.m_scaling; + m_ornamenticon = copy.m_ornamenticon; + m_ornamentidfile = copy.m_ornamentidfile; } // Clean up container contents @@ -1789,6 +1797,54 @@ ItemInst* ItemInst::GetOrnamentationAug(int ornamentationAugtype) const return nullptr; } +bool ItemInst::CanTransform(const Item_Struct *ItemToTry, const Item_Struct *Container, bool AllowAll) { + if (!ItemToTry || !Container) return false; + + if (ItemToTry->ItemType == ItemTypeArrow || strnlen(Container->CharmFile, 30) == 0) + return false; + + if (AllowAll && Container->CharmFile != "ITEMTRANSFIGSHIELD" && Container->CharmFile != "ITEMTransfigBow") { + switch (ItemToTry->ItemType) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 35: + case 45: + return true; + } + } + + static std::map types = { + { "ITEMTransfig1HP", 2 }, + { "ITEMTransfig1HS", 0 }, + { "ITEMTransfig2HB", 4 }, + { "ITEMTransfig2HP", 35 }, + { "ITEMTransfig2HS", 1 }, + { "ITEMTransfigBlunt", 3 }, + { "ITEMTransfigBow", 5 }, + { "ITEMTransfigHTH", 45 }, + { "ITEMTRANSFIGSHIELD", 8 }, + { "ITEMTransfigSlashing", 0 } + }; + + auto i = types.find(Container->CharmFile); + if (i != types.end() && i->second == ItemToTry->ItemType) + return true; + + static std::map typestwo = { + { "ITEMTransfigBlunt", 4 }, + { "ITEMTransfigSlashing", 1 } + }; + + i = typestwo.find(Container->CharmFile); + if (i != typestwo.end() && i->second == ItemToTry->ItemType) + return true; + + return false; +} + uint32 ItemInst::GetAugmentItemID(uint8 slot) const { uint32 id = NO_ITEM; diff --git a/common/item.h b/common/item.h index e6d1e8bee..cce166eb0 100644 --- a/common/item.h +++ b/common/item.h @@ -330,6 +330,7 @@ public: ItemInst* RemoveAugment(uint8 index); bool IsAugmented(); ItemInst* GetOrnamentationAug(int ornamentationAugtype) const; + static bool CanTransform(const Item_Struct *ItemToTry, const Item_Struct *Container, bool AllowAll = false); // Has attack/delay? bool IsWeapon() const; @@ -392,6 +393,10 @@ public: void SetActivated(bool activated) { m_activated = activated; } int8 GetEvolveLvl() const { return m_evolveLvl; } void SetScaling(bool v) { m_scaling = v; } + uint32 GetOrnamentationIcon() const { return m_ornamenticon; } + void SetOrnamentIcon(uint32 ornament_icon) { m_ornamenticon = ornament_icon; } + uint32 GetOrnamentationIDFile() const { return m_ornamentidfile; } + void SetOrnamentationIDFile(uint32 ornament_idfile) { m_ornamentidfile = ornament_idfile; } void Initialize(SharedDatabase *db = nullptr); void ScaleItem(); @@ -436,6 +441,8 @@ protected: Item_Struct* m_scaledItem; EvolveInfo* m_evolveInfo; bool m_scaling; + uint32 m_ornamenticon; + uint32 m_ornamentidfile; // // Items inside of this item (augs or contents); diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index 092101d7d..c7efe0264 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -4888,6 +4888,16 @@ namespace RoF //Icon ornaIcon = aug_weap->Icon; } + else if (inst->GetOrnamentationIDFile() && inst->GetOrnamentationIcon()) { + char tmp[30]; memset(tmp, 0x0, 30); sprintf(tmp, "IT%d", inst->GetOrnamentationIDFile()); + //Mainhand + ss.write(tmp, strlen(tmp)); + ss.write((const char*)&null_term, sizeof(uint8)); + //Offhand + ss.write(tmp, strlen(tmp)); + ss.write((const char*)&null_term, sizeof(uint8)); + ornaIcon = inst->GetOrnamentationIcon(); + } else { ss.write((const char*)&null_term, sizeof(uint8)); //no mh ss.write((const char*)&null_term, sizeof(uint8));//no of diff --git a/common/patches/underfoot.cpp b/common/patches/underfoot.cpp index adc4ed6e3..c9d726a25 100644 --- a/common/patches/underfoot.cpp +++ b/common/patches/underfoot.cpp @@ -3664,6 +3664,12 @@ namespace Underfoot ss.write((const char*)&null_term, sizeof(uint8)); ornaIcon = aug_weap->Icon; } + else if (inst->GetOrnamentationIDFile() && inst->GetOrnamentationIcon()) { + char tmp[30]; memset(tmp, 0x0, 30); sprintf(tmp, "IT%d", inst->GetOrnamentationIDFile()); + ss.write(tmp, strlen(tmp)); + ss.write((const char*)&null_term, sizeof(uint8)); + ornaIcon = inst->GetOrnamentationIcon(); + } else { ss.write((const char*)&null_term, sizeof(uint8)); //no idfile } diff --git a/common/ruletypes.h b/common/ruletypes.h index 052571d82..b3e9b4f1c 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -586,6 +586,8 @@ RULE_CATEGORY( Inventory ) RULE_BOOL ( Inventory, EnforceAugmentRestriction, true) // Forces augment slot restrictions RULE_BOOL ( Inventory, EnforceAugmentUsability, true) // Forces augmented item usability RULE_BOOL ( Inventory, EnforceAugmentWear, true) // Forces augment wear slot validation +RULE_BOOL ( Inventory, DeleteTransformationMold, true) //False if you want mold to last forever +RULE_BOOL ( Inventory, AllowAnyWeaponTransformation, false) //Weapons can use any weapon transformation RULE_CATEGORY_END() RULE_CATEGORY( Client ) diff --git a/common/shareddb.cpp b/common/shareddb.cpp index d543db87f..05c7b6962 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -199,14 +199,14 @@ bool SharedDatabase::UpdateInventorySlot(uint32 char_id, const ItemInst* inst, i // Update/Insert item std::string query = StringFormat("REPLACE INTO inventory " "(charid, slotid, itemid, charges, instnodrop, custom_data, color, " - "augslot1, augslot2, augslot3, augslot4, augslot5) " + "augslot1, augslot2, augslot3, augslot4, augslot5, ornamenticon, ornamentidfile) " "VALUES( %lu, %lu, %lu, %lu, %lu, '%s', %lu, " - "%lu, %lu, %lu, %lu, %lu)", + "%lu, %lu, %lu, %lu, %lu, %lu, %lu)", (unsigned long)char_id, (unsigned long)slot_id, (unsigned long)inst->GetItem()->ID, (unsigned long)charges, (unsigned long)(inst->IsInstNoDrop()? 1: 0), inst->GetCustomDataString().c_str(), (unsigned long)inst->GetColor(), (unsigned long)augslot[0], (unsigned long)augslot[1], (unsigned long)augslot[2], - (unsigned long)augslot[3],(unsigned long)augslot[4]); + (unsigned long)augslot[3],(unsigned long)augslot[4], (unsigned long)inst->GetOrnamentationIcon(), (unsigned long)inst->GetOrnamentationIDFile()); auto results = QueryDatabase(query); // Save bag contents, if slot supports bag contents @@ -488,7 +488,7 @@ bool SharedDatabase::GetSharedBank(uint32 id, Inventory* inv, bool is_charid) { bool SharedDatabase::GetInventory(uint32 char_id, Inventory* inv) { // Retrieve character inventory std::string query = StringFormat("SELECT slotid, itemid, charges, color, augslot1, " - "augslot2, augslot3, augslot4, augslot5, instnodrop, custom_data " + "augslot2, augslot3, augslot4, augslot5, instnodrop, custom_data, ornamenticon, ornamentidfile " "FROM inventory WHERE charid = %i ORDER BY slotid", char_id); auto results = QueryDatabase(query); if (!results.Success()) { @@ -513,6 +513,9 @@ bool SharedDatabase::GetInventory(uint32 char_id, Inventory* inv) { bool instnodrop = (row[9] && (uint16)atoi(row[9]))? true: false; + uint32 ornament_icon = (uint32)atoul(row[11]); + uint32 ornament_idfile = (uint32)atoul(row[12]); + const Item_Struct* item = GetItem(item_id); if (!item) { @@ -549,6 +552,11 @@ bool SharedDatabase::GetInventory(uint32 char_id, Inventory* inv) { value.push_back(v); } } + if (ornament_icon > 0) + inst->SetOrnamentIcon(ornament_icon); + + if (ornament_idfile > 0) + inst->SetOrnamentationIDFile(ornament_idfile); if (instnodrop || (((slot_id >= EmuConstants::EQUIPMENT_BEGIN && slot_id <= EmuConstants::EQUIPMENT_END) || slot_id == MainPowerSource) && inst->GetItem()->Attuneable)) inst->SetInstNoDrop(true); @@ -591,7 +599,7 @@ bool SharedDatabase::GetInventory(uint32 char_id, Inventory* inv) { bool SharedDatabase::GetInventory(uint32 account_id, char* name, Inventory* inv) { // Retrieve character inventory std::string query = StringFormat("SELECT slotid, itemid, charges, color, augslot1, " - "augslot2, augslot3, augslot4, augslot5, instnodrop, custom_data " + "augslot2, augslot3, augslot4, augslot5, instnodrop, custom_data, ornamenticon, ornamentidfile " "FROM inventory INNER JOIN character_data ch " "ON ch.id = charid WHERE ch.name = '%s' AND ch.account_id = %i ORDER BY slotid", name, account_id); @@ -617,6 +625,9 @@ bool SharedDatabase::GetInventory(uint32 account_id, char* name, Inventory* inv) aug[4] = (uint32)atoi(row[8]); bool instnodrop = (row[9] && (uint16)atoi(row[9])) ? true : false; + uint32 ornament_icon = (uint32)atoul(row[11]); + uint32 ornament_idfile = (uint32)atoul(row[12]); + const Item_Struct* item = GetItem(item_id); int16 put_slot_id = INVALID_INDEX; if(!item) @@ -651,6 +662,12 @@ bool SharedDatabase::GetInventory(uint32 account_id, char* name, Inventory* inv) } } + + if (ornament_icon > 0) + inst->SetOrnamentIcon(ornament_icon); + + if (ornament_idfile > 0) + inst->SetOrnamentationIDFile(ornament_idfile); if (color > 0) inst->SetColor(color); diff --git a/utils/sql/git/optional/2014_11_26_TransformationRules.sql b/utils/sql/git/optional/2014_11_26_TransformationRules.sql new file mode 100644 index 000000000..d31b6b26e --- /dev/null +++ b/utils/sql/git/optional/2014_11_26_TransformationRules.sql @@ -0,0 +1,3 @@ +--Optional Transformation Rules +INSERT INTO `rule_values` VALUES (1, 'Inventory:DeleteTransformationMold', 'true', 'false to keep transformation mold forever'); +INSERT INTO `rule_values` VALUES (1, 'Inventory:AllowAnyWeaponTransformation', 'false', 'True allows any MELEE weapon to use the other melee type transformatios'); diff --git a/utils/sql/git/required/2014_11_26_InventoryTableUpdate.sql b/utils/sql/git/required/2014_11_26_InventoryTableUpdate.sql new file mode 100644 index 000000000..ca25e4e2d --- /dev/null +++ b/utils/sql/git/required/2014_11_26_InventoryTableUpdate.sql @@ -0,0 +1,4 @@ +--Inventory table update +ALTER TABLE `inventory` + ADD COLUMN `ornamenticon` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `custom_data`, + ADD COLUMN `ornamentidfile` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `ornamenticon`; \ No newline at end of file diff --git a/world/worlddb.cpp b/world/worlddb.cpp index cd01e01b2..458025349 100644 --- a/world/worlddb.cpp +++ b/world/worlddb.cpp @@ -197,6 +197,9 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct* if (item->GetOrnamentationAug(ornamentationAugtype)) { idfile = atoi(&item->GetOrnamentationAug(ornamentationAugtype)->GetItem()->IDFile[2]); } + else if (item->GetOrnamentationIcon() && item->GetOrnamentationIDFile()) { + idfile = item->GetOrnamentationIDFile(); + } else { idfile = atoi(&item->GetItem()->IDFile[2]); } diff --git a/zone/client.cpp b/zone/client.cpp index 9541959ba..7ceb12496 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -1889,6 +1889,9 @@ void Client::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) if (strlen(item->IDFile) > 2) ns->spawn.equipment[MaterialPrimary] = atoi(&item->IDFile[2]); } + else if (inst->GetOrnamentationIcon() && inst->GetOrnamentationIDFile()) { + ns->spawn.equipment[MaterialPrimary] = inst->GetOrnamentationIDFile(); + } else { item = inst->GetItem(); if (strlen(item->IDFile) > 2) @@ -1901,6 +1904,9 @@ void Client::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) if (strlen(item->IDFile) > 2) ns->spawn.equipment[MaterialSecondary] = atoi(&item->IDFile[2]); } + else if (inst->GetOrnamentationIcon() && inst->GetOrnamentationIDFile()) { + ns->spawn.equipment[MaterialSecondary] = inst->GetOrnamentationIDFile(); + } else { item = inst->GetItem(); if (strlen(item->IDFile) > 2) @@ -2766,6 +2772,9 @@ void Client::SetMaterial(int16 in_slot, uint32 item_id) { item = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem(); m_pp.item_material[MaterialPrimary] = atoi(item->IDFile + 2); } + else if (inst && inst->GetOrnamentationIcon() && inst->GetOrnamentationIDFile()) { + m_pp.item_material[MaterialPrimary] = inst->GetOrnamentationIDFile(); + } else { m_pp.item_material[MaterialPrimary] = atoi(item->IDFile + 2); } @@ -2776,6 +2785,9 @@ void Client::SetMaterial(int16 in_slot, uint32 item_id) { item = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem(); m_pp.item_material[MaterialSecondary] = atoi(item->IDFile + 2); } + else if (inst && inst->GetOrnamentationIcon() && inst->GetOrnamentationIDFile()) { + m_pp.item_material[MaterialSecondary] = inst->GetOrnamentationIDFile(); + } else { m_pp.item_material[MaterialSecondary] = atoi(item->IDFile + 2); } @@ -5832,7 +5844,11 @@ void Client::ProcessInspectRequest(Client* requestee, Client* requester) { const Item_Struct *aug_weap = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem(); strcpy(insr->itemnames[L], item->Name); insr->itemicons[L] = aug_weap->Icon; - } + } + else if (inst->GetOrnamentationIcon() && inst->GetOrnamentationIDFile()) { + strcpy(insr->itemnames[L], item->Name); + insr->itemicons[L] = inst->GetOrnamentationIcon(); + } else { strcpy(insr->itemnames[L], item->Name); insr->itemicons[L] = item->Icon; diff --git a/zone/client.h b/zone/client.h index dcf665bab..4c69917fd 100644 --- a/zone/client.h +++ b/zone/client.h @@ -810,7 +810,7 @@ public: void QSSwapItemAuditor(MoveItem_Struct* move_in, bool postaction_call = false); void PutLootInInventory(int16 slot_id, const ItemInst &inst, ServerLootItem_Struct** bag_item_data = 0); bool AutoPutLootInInventory(ItemInst& inst, bool try_worn = false, bool try_cursor = true, ServerLootItem_Struct** bag_item_data = 0); - bool SummonItem(uint32 item_id, int16 charges = -1, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0, uint32 aug5 = 0, bool attuned = false, uint16 to_slot = MainCursor); + bool SummonItem(uint32 item_id, int16 charges = -1, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0, uint32 aug5 = 0, bool attuned = false, uint16 to_slot = MainCursor, uint32 ornament_icon = 0, uint32 ornament_idfile = 0); void SetStats(uint8 type,int16 set_val); void IncStats(uint8 type,int16 increase_val); void DropItem(int16 slot_id); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 000ed8fcc..a12247cc6 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -8031,6 +8031,10 @@ void Client::Handle_OP_InspectAnswer(const EQApplicationPacket *app) strcpy(insr->itemnames[L], item->Name); insr->itemicons[L] = aug_weap->Icon; } + else if (inst->GetOrnamentationIcon() && inst->GetOrnamentationIDFile()) { + strcpy(insr->itemnames[L], item->Name); + insr->itemicons[L] = inst->GetOrnamentationIcon(); + } else { strcpy(insr->itemnames[L], item->Name); insr->itemicons[L] = item->Icon; diff --git a/zone/inventory.cpp b/zone/inventory.cpp index 76b077e2d..a7f61819e 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -199,7 +199,7 @@ bool Client::CheckLoreConflict(const Item_Struct* item) { return (m_inv.HasItemByLoreGroup(item->LoreGroup, ~invWhereSharedBank) != INVALID_INDEX); } -bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, bool attuned, uint16 to_slot) { +bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, bool attuned, uint16 to_slot, uint32 ornament_icon, uint32 ornament_idfile) { this->EVENT_ITEM_ScriptStopReturn(); // TODO: update calling methods and script apis to handle a failure return @@ -557,6 +557,11 @@ bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2, // attune item if(attuned && inst->GetItem()->Attuneable) inst->SetInstNoDrop(true); + + if(ornament_icon > 0 && ornament_idfile > 0) { + inst->SetOrnamentIcon(ornament_icon); + inst->SetOrnamentationIDFile(ornament_idfile); + } // check to see if item is usable in requested slot if(enforceusable && (((to_slot >= MainCharm) && (to_slot <= MainAmmo)) || (to_slot == MainPowerSource))) { diff --git a/zone/mob.cpp b/zone/mob.cpp index 15fb731e2..35a019252 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -2455,6 +2455,9 @@ int32 Mob::GetEquipmentMaterial(uint8 material_slot) const item = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem(); return atoi(&item->IDFile[2]); } + else if (inst->GetOrnamentationIcon() && inst->GetOrnamentationIDFile()) { + return inst->GetOrnamentationIDFile(); + } else { if (strlen(item->IDFile) > 2) return atoi(&item->IDFile[2]); diff --git a/zone/string_ids.h b/zone/string_ids.h index 5375c2d7d..044dd215f 100644 --- a/zone/string_ids.h +++ b/zone/string_ids.h @@ -296,6 +296,8 @@ #define GUILD_BANK_FULL 6098 // There is no more room in the Guild Bank. #define GUILD_BANK_TRANSFERRED 6100 // '%1' transferred to Guild Bank from Deposits. #define GUILD_BANK_EMPTY_HANDS 6108 // You must empty your hands to withdraw from the Guild Bank. +#define TRANSFORM_FAILED 6326 //This mold cannot be applied to your %1. +#define TRANSFORM_COMPLETE 6327 //You have successfully transformed your %1. #define GENERIC_STRING 6688 //%1 (used to any basic message) #define SENTINEL_TRIG_YOU 6724 //You have triggered your sentinel. #define SENTINEL_TRIG_OTHER 6725 //%1 has triggered your sentinel. diff --git a/zone/tradeskills.cpp b/zone/tradeskills.cpp index c7ac3339e..e9de6c4a6 100644 --- a/zone/tradeskills.cpp +++ b/zone/tradeskills.cpp @@ -283,6 +283,26 @@ void Object::HandleCombine(Client* user, const NewCombine_Struct* in_combine, Ob } container = inst; + if (container->GetItem()->BagType == BagTypeTransformationmold) { + const ItemInst* inst = container->GetItem(0); + bool AllowAll = RuleB(Inventory, AllowAnyWeaponTransformation); + if (inst && ItemInst::CanTransform(inst->GetItem(), container->GetItem(), AllowAll)) { + const Item_Struct* new_weapon = inst->GetItem(); + user->DeleteItemInInventory(Inventory::CalcSlotId(in_combine->container_slot, 0), 0, true); + container->Clear(); + user->SummonItem(new_weapon->ID, inst->GetCharges(), inst->GetAugmentItemID(0), inst->GetAugmentItemID(1), inst->GetAugmentItemID(2), inst->GetAugmentItemID(3), inst->GetAugmentItemID(4), inst->IsInstNoDrop(), MainCursor, container->GetItem()->Icon, atoi(container->GetItem()->IDFile + 2)); + user->Message_StringID(4, TRANSFORM_COMPLETE, inst->GetItem()->Name); + if (RuleB(Inventory, DeleteTransformationMold)) + user->DeleteItemInInventory(in_combine->container_slot, 0, true); + } + else if (inst) { + user->Message_StringID(4, TRANSFORM_FAILED, inst->GetItem()->Name); + } + EQApplicationPacket* outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0); + user->QueuePacket(outapp); + safe_delete(outapp); + return; + } DBTradeskillRecipe_Struct spec; if (!database.GetTradeRecipe(container, c_type, some_id, user->CharacterID(), &spec)) {