Skip to content

Instantly share code, notes, and snippets.

@walkline
Created June 5, 2012 07:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save walkline/2873435 to your computer and use it in GitHub Desktop.
Save walkline/2873435 to your computer and use it in GitHub Desktop.
Transmogrification
diff --git a/sql/updates/fc_updates_characters/fake_items.sql b/sql/updates/fc_updates_characters/fake_items.sql
new file mode 100644
index 0000000..3618ac1
--- /dev/null
+++ b/sql/updates/fc_updates_characters/fake_items.sql
@@ -0,0 +1,11 @@
+DROP TABLE IF EXISTS `fake_items`;
+CREATE TABLE `fake_items` (
+ `guid` int(11) NOT NULL,
+ `fakeEntry` int(11) NOT NULL,
+ PRIMARY KEY (`guid`)
+);
+
+INSERT INTO `gossip_menu` VALUES (51000, 51000);
+INSERT INTO npc_text (ID, text0_0, em0_1) VALUES
+(51000, 'Put in the first slot of bag item, that you want to transmogrify. In the second slot, put item with perfect display.', 0);
+
diff --git a/sql/updates/fc_updates_world/fake_items.sql b/sql/updates/fc_updates_world/fake_items.sql
new file mode 100644
index 0000000..7cfd4cc
--- /dev/null
+++ b/sql/updates/fc_updates_world/fake_items.sql
@@ -0,0 +1,3 @@
+DELETE FROM creature_template WHERE entry = '190001';
+INSERT INTO creature_template (entry, modelid1, name, subname, IconName, gossip_menu_id, minlevel, maxlevel, Health_mod, Mana_mod, Armor_mod, faction_A, faction_H, npcflag, speed_walk, speed_run, scale, rank, dmg_multiplier, unit_class, unit_flags, type, type_flags, InhabitType, RegenHealth, flags_extra, ScriptName) VALUES
+('190001', '15998', "Transmogrify Master", "", 'Speak', '50000', 71, 71, 1.56, 1.56, 1.56, 35, 35, 3, 1, 1.14286, 1.25, 1, 1, 1, 2, 7, 138936390, 3, 1, 2, 'npc_transmogrify');
diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp
index 23a3f50..d339a71 100755
--- a/src/server/game/Entities/Item/Item.cpp
+++ b/src/server/game/Entities/Item/Item.cpp
@@ -251,6 +251,8 @@ Item::Item()
m_refundRecipient = 0;
m_paidMoney = 0;
m_paidExtendedCost = 0;
+
+ m_fakeDisplayEntry = 0;
}
bool Item::Create(uint32 guidlow, uint32 itemid, Player const* owner)
@@ -468,6 +470,9 @@ bool Item::LoadFromDB(uint32 guid, uint64 owner_guid, Field* fields, uint32 entr
SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, fields[9].GetUInt32());
SetText(fields[10].GetString());
+ if (uint32 fakeEntry = sObjectMgr->GetFakeItemEntry(guid))
+ SetFakeDisplay(fakeEntry);
+
if (need_save) // normal item changed state set not work at loading
{
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ITEM_INSTANCE_ON_LOAD);
@@ -484,6 +489,7 @@ bool Item::LoadFromDB(uint32 guid, uint64 owner_guid, Field* fields, uint32 entr
/*static*/
void Item::DeleteFromDB(SQLTransaction& trans, uint32 itemGuid)
{
+ sObjectMgr->RemoveFakeItem(itemGuid);
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE);
stmt->setUInt32(0, itemGuid);
trans->Append(stmt);
@@ -491,6 +497,7 @@ void Item::DeleteFromDB(SQLTransaction& trans, uint32 itemGuid)
void Item::DeleteFromDB(SQLTransaction& trans)
{
+ RemoveFakeDisplay();
DeleteFromDB(trans, GetGUIDLow());
}
@@ -1207,3 +1214,50 @@ bool Item::CheckSoulboundTradeExpire()
return false;
}
+
+FakeResult Item::SetFakeDisplay(uint32 iEntry)
+{
+ if (!iEntry)
+ {
+ RemoveFakeDisplay();
+ return FAKE_ERR_OK;
+ }
+
+ ItemTemplate const* myTmpl = GetTemplate();
+ ItemTemplate const* otherTmpl = sObjectMgr->GetItemTemplate(iEntry);
+
+ if (!otherTmpl)
+ return FAKE_ERR_CANT_FIND_ITEM;
+
+ if (myTmpl->InventoryType != otherTmpl->InventoryType)
+ return FAKE_ERR_DIFF_SLOTS;
+
+ if (myTmpl->AllowableClass != otherTmpl->AllowableClass)
+ return FAKE_ERR_DIFF_CLASS;
+
+ if (myTmpl->AllowableRace != otherTmpl->AllowableRace)
+ return FAKE_ERR_DIFF_RACE;
+
+ if (otherTmpl->Quality == ITEM_QUALITY_LEGENDARY || otherTmpl->Quality == ITEM_QUALITY_POOR)
+ return FAKE_ERR_WRONG_QUALITY;
+
+ if (m_fakeDisplayEntry != iEntry)
+ {
+ sObjectMgr->SetFekeItem(GetGUIDLow(), iEntry);
+
+ (!m_fakeDisplayEntry) ? CharacterDatabase.PExecute("INSERT INTO fake_items VALUES (%u, %u)", GetGUIDLow(), iEntry) :
+ CharacterDatabase.PExecute("UPDATE fake_items SET fakeEntry = %u WHERE guid = %u", iEntry, GetGUIDLow());
+ m_fakeDisplayEntry = iEntry;
+ }
+
+ return FAKE_ERR_OK;
+}
+
+void Item::RemoveFakeDisplay()
+{
+ if (GetFakeDisplayEntry())
+ {
+ m_fakeDisplayEntry = 0;
+ CharacterDatabase.PExecute("DELETE FROM fake_items WHERE guid = %u", GetGUIDLow());
+ }
+}
diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h
index 1d5fcae..32f1ef6 100755
--- a/src/server/game/Entities/Item/Item.h
+++ b/src/server/game/Entities/Item/Item.h
@@ -152,6 +152,17 @@ enum SellResult
SELL_ERR_ONLY_EMPTY_BAG = 6 // can only do with empty bags
};
+enum FakeResult
+{
+ FAKE_ERR_CANT_FIND_OWNER,
+ FAKE_ERR_CANT_FIND_ITEM,
+ FAKE_ERR_WRONG_QUALITY,
+ FAKE_ERR_DIFF_SLOTS,
+ FAKE_ERR_DIFF_CLASS,
+ FAKE_ERR_DIFF_RACE,
+ FAKE_ERR_OK
+};
+
// -1 from client enchantment slot number
enum EnchantmentSlot
{
@@ -340,6 +351,10 @@ class Item : public Object
void BuildUpdate(UpdateDataMapType&);
uint32 GetScriptId() const { return GetTemplate()->ScriptId; }
+
+ FakeResult SetFakeDisplay(uint32 iEntry);
+ uint32 GetFakeDisplayEntry() { return m_fakeDisplayEntry; }
+ void RemoveFakeDisplay();
private:
std::string m_text;
uint8 m_slot;
@@ -352,5 +367,7 @@ class Item : public Object
uint32 m_paidMoney;
uint32 m_paidExtendedCost;
AllowedLooterSet allowedGUIDs;
+
+ uint32 m_fakeDisplayEntry;
};
#endif
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index dd35dea..fc8e4d0 100755
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -12719,7 +12719,7 @@ void Player::SetVisibleItemSlot(uint8 slot, Item* pItem)
{
if (pItem)
{
- SetUInt32Value(PLAYER_VISIBLE_ITEM_1_ENTRYID + (slot * 2), pItem->GetEntry());
+ SetUInt32Value(PLAYER_VISIBLE_ITEM_1_ENTRYID + (slot * 2), (pItem->GetFakeDisplayEntry()) ? pItem->GetFakeDisplayEntry() : pItem->GetEntry());
SetUInt16Value(PLAYER_VISIBLE_ITEM_1_ENCHANTMENT + (slot * 2), 0, pItem->GetEnchantmentId(PERM_ENCHANTMENT_SLOT));
SetUInt16Value(PLAYER_VISIBLE_ITEM_1_ENCHANTMENT + (slot * 2), 1, pItem->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT));
}
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index df6018f..054c6f0 100755
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -2692,6 +2692,27 @@ ItemTemplate const* ObjectMgr::GetItemTemplate(uint32 entry)
return NULL;
}
+uint32 ObjectMgr::GetFakeItemEntry(uint32 itemGuid)
+{
+ FakeItemsContainer::const_iterator itr = _fakeItemsStore.find(itemGuid);
+ if (itr != _fakeItemsStore.end())
+ return itr->second;
+
+ return 0;
+}
+
+void ObjectMgr::SetFekeItem(uint32 itemGuid, uint32 fakeEntry)
+{
+ _fakeItemsStore[itemGuid] = fakeEntry;
+}
+
+void ObjectMgr::RemoveFakeItem(uint32 itemGuid)
+{
+ FakeItemsContainer::iterator itr = _fakeItemsStore.find(itemGuid);
+ if (itr != _fakeItemsStore.end())
+ _fakeItemsStore.erase(itr);
+}
+
void ObjectMgr::LoadItemSetNameLocales()
{
uint32 oldMSTime = getMSTime();
@@ -2803,6 +2824,32 @@ void ObjectMgr::LoadItemSetNames()
sLog->outString();
}
+void ObjectMgr::LoadFakeItems()
+{
+ QueryResult result = CharacterDatabase.Query("SELECT `guid`, `fakeEntry` FROM `fake_items`");
+
+ if (!result)
+ {
+ sLog->outErrorDb(">> Loaded 0 fake items. DB table `fake_items` is empty.");
+ sLog->outString();
+ return;
+ }
+
+ do
+ {
+ Field* fields = result->Fetch();
+
+ uint32 guid = fields[0].GetUInt32();
+ uint32 fakeEntry = fields[1].GetUInt32();
+
+ _fakeItemsStore[guid] = fakeEntry;
+ }
+ while (result->NextRow());
+
+ sLog->outString(">> Loaded %u fake items.", _fakeItemsStore.size());
+ sLog->outString();
+}
+
void ObjectMgr::LoadVehicleTemplateAccessories()
{
uint32 oldMSTime = getMSTime();
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index f81e7f1..b8182a8 100755
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -402,6 +402,8 @@ typedef UNORDERED_MAP<uint32, PointOfInterestLocale> PointOfInterestLocaleContai
typedef std::multimap<uint32, uint32> QuestRelations;
typedef std::pair<QuestRelations::const_iterator, QuestRelations::const_iterator> QuestRelationBounds;
+typedef std::map<uint32, uint32> FakeItemsContainer;
+
struct PetLevelInfo
{
PetLevelInfo() : health(0), mana(0) { for (uint8 i=0; i < MAX_STATS; ++i) stats[i] = 0; }
@@ -641,6 +643,10 @@ class ObjectMgr
return NULL;
}
+ uint32 GetFakeItemEntry(uint32 itemGuid);
+ void SetFekeItem(uint32 itemGuid, uint32 fakeEntry);
+ void RemoveFakeItem(uint32 itemGuid);
+
InstanceTemplate const* GetInstanceTemplate(uint32 mapId);
PetLevelInfo const* GetPetLevelInfo(uint32 creature_id, uint8 level) const;
@@ -865,6 +871,7 @@ class ObjectMgr
void LoadItemLocales();
void LoadItemSetNames();
void LoadItemSetNameLocales();
+ void LoadFakeItems();
void LoadQuestLocales();
void LoadNpcTextLocales();
void LoadPageTextLocales();
@@ -1301,6 +1308,7 @@ class ObjectMgr
ItemTemplateContainer _itemTemplateStore;
ItemLocaleContainer _itemLocaleStore;
ItemSetNameLocaleContainer _itemSetNameLocaleStore;
+ FakeItemsContainer _fakeItemsStore;
QuestLocaleContainer _questLocaleStore;
NpcTextLocaleContainer _npcTextLocaleStore;
PageTextLocaleContainer _pageTextLocaleStore;
diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp
index e5833c5..fa6a6c9 100755
--- a/src/server/game/Scripting/ScriptLoader.cpp
+++ b/src/server/game/Scripting/ScriptLoader.cpp
@@ -38,6 +38,8 @@ void AddSC_ArgentTournament();
void AddSC_dalaran_squirrel();
// Arena Spectator
void AddSC_arena_spectator_script();
+// Transmogrify
+void AddSC_transmogrify_script();
// spells
void AddSC_deathknight_spell_scripts();
@@ -1271,5 +1273,6 @@ void AddCustomScripts()
AddSC_ArgentTournament();
AddSC_dalaran_squirrel();
AddSC_arena_spectator_script();
+ AddSC_transmogrify_script();
#endif
}
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index bd770bf..dfec836 100755
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1418,6 +1418,9 @@ void World::SetInitialWorldSettings()
sLog->outString("Loading Equipment templates...");
sObjectMgr->LoadEquipmentTemplates();
+ sLog->outString("Loading fake items...");
+ sObjectMgr->LoadFakeItems();
+
sLog->outString("Loading Creature templates...");
sObjectMgr->LoadCreatureTemplates();
diff --git a/src/server/scripts/Custom/CMakeLists.txt b/src/server/scripts/Custom/CMakeLists.txt
index 24477b0..c5dde7b 100644
--- a/src/server/scripts/Custom/CMakeLists.txt
+++ b/src/server/scripts/Custom/CMakeLists.txt
@@ -15,6 +15,7 @@ set(scripts_STAT_SRCS
Custom/argent_tournament.cpp
Custom/dalaran_squirrel.cpp
Custom/arena_spectator.cpp
+ Custom/npc_transmogrify.cpp
)
message(" -> Prepared: Custom")
diff --git a/src/server/scripts/Custom/npc_transmogrify.cpp b/src/server/scripts/Custom/npc_transmogrify.cpp
new file mode 100644
index 0000000..fa601a8
--- /dev/null
+++ b/src/server/scripts/Custom/npc_transmogrify.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* ScriptData
+Name: Transmogrify Npc
+%Complete: 100
+Category: Custom Script
+EndScriptData */
+
+#include "ScriptPCH.h"
+
+enum TransmogrifyActions {
+ ACTION_TRANSMOGRIFY_ADD_DISPLAY,
+ ACTION_TRANSMOGRIFY_REMOVE_DISPLAY
+};
+
+const uint16 PriceInGold = 1000 * 100 * 100; // 1k golds
+
+class npc_transmogrify : public CreatureScript
+{
+ public:
+ npc_transmogrify() : CreatureScript("npc_transmogrify") { }
+
+ bool OnGossipHello(Player* pPlayer, Creature* pCreature)
+ {
+ pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "Make exchange!", GOSSIP_SENDER_MAIN, ACTION_TRANSMOGRIFY_ADD_DISPLAY);
+ pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "Make item clean.", GOSSIP_SENDER_MAIN, ACTION_TRANSMOGRIFY_REMOVE_DISPLAY);
+ pPlayer->SEND_GOSSIP_MENU(51000, pCreature->GetGUID());
+ return true;
+ }
+
+ bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action)
+ {
+ player->PlayerTalkClass->SendCloseGossip();
+ switch (action)
+ {
+ case ACTION_TRANSMOGRIFY_ADD_DISPLAY:
+ TransmogrifyItem(player, creature);
+ break;
+ case ACTION_TRANSMOGRIFY_REMOVE_DISPLAY:
+ ClearItem(player, creature);
+ break;
+ }
+ return true;
+ }
+
+ void TransmogrifyItem(Player* player, Creature* creature)
+ {
+ ChatHandler handler(player);
+ Item *trItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, INVENTORY_SLOT_ITEM_START);
+ Item *displayItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, INVENTORY_SLOT_ITEM_START + 1);
+ if (!trItem || !displayItem)
+ {
+ handler.PSendSysMessage("Put item in the first and second slot!");
+ return;
+ }
+
+ if (!player->HasEnoughMoney(PriceInGold))
+ {
+ handler.PSendSysMessage("It costs %u gold!", PriceInGold);
+ return;
+ }
+
+ uint8 result = trItem->SetFakeDisplay(displayItem->GetTemplate()->ItemId);
+ switch (result)
+ {
+ case FAKE_ERR_CANT_FIND_ITEM:
+ handler.PSendSysMessage("Cant find item!");
+ break;
+ case FAKE_ERR_WRONG_QUALITY:
+ handler.PSendSysMessage("Item has wrong quality!");
+ break;
+ case FAKE_ERR_DIFF_SLOTS:
+ handler.PSendSysMessage("Items has different types!");
+ break;
+ case FAKE_ERR_DIFF_CLASS:
+ case FAKE_ERR_DIFF_RACE:
+ handler.PSendSysMessage("Items require different options!");
+ break;
+ case FAKE_ERR_OK:
+ {
+ WorldPacket data;
+ data << uint8(INVENTORY_SLOT_BAG_0);
+ data << uint8(trItem->GetSlot());
+ player->GetSession()->HandleAutoEquipItemOpcode(data);
+
+ player->ModifyMoney(-1 * PriceInGold);
+ creature->GetAI()->DoCast(63491);
+
+ break;
+ }
+ }
+ }
+
+ void ClearItem(Player *player, Creature* creature)
+ {
+ ChatHandler handler(player);
+ Item *trItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, INVENTORY_SLOT_ITEM_START);
+ if (!trItem)
+ {
+ handler.PSendSysMessage("Put item in the first slot!");
+ return;
+ }
+
+ trItem->RemoveFakeDisplay();
+
+ WorldPacket data;
+ data << uint8(INVENTORY_SLOT_BAG_0);
+ data << uint8(trItem->GetSlot());
+ player->GetSession()->HandleAutoEquipItemOpcode(data);
+
+ creature->GetAI()->DoCast(63491);
+ }
+};
+
+void AddSC_transmogrify_script()
+{
+ new npc_transmogrify;
+}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment