• Unfortunately, we have experienced significant hard drive damage that requires urgent maintenance and rebuilding. The forum will be a state of read only until we install our new drives and rebuild all the configurations needed. Please follow our Facebook page for updates, we will be back up shortly! (The forum could go offline at any given time due to the nature of the failed drives whilst awaiting the upgrades.) When you see an Incapsula error, you know we are in the process of migration.

Arcemu [LUA] Transmogrification

Newbie Spellweaver
Joined
Dec 2, 2011
Messages
54
Reaction score
3
Hey, since this section seems to be dead I decided to add some scripts I am using for my server.
Enjoy :)

Transmogrification.lua
Code:
local NPCENTRY = 123123 -- Your NPC's entry

-- Warning! Executes quite some code. Delay in milliseconds. (applies transmogs)
local DELAY = 500 -- 500 (best visual update, very low population), 1000 (good visual update, very low population), 2000+ (slow visual update, medium  to high population)

-- DO NOT TOUCH ANYTHING BELOW!

-- Transmog table and functions.
local Transmogs, Hello, Select, AddTransmog, RemoveTransmog, GetValidSources, LoadTransmogs, ApplyTransmogs

-- Key0 is the key for inv_slots table, which contains the slotID. Key0 is also used for the inv_slot_names table
local inv_slots =		{0,			2,				4,			5,			6,		7,		8,			9,			14,		15,				16,			17}
local inv_slot_names =	{"Head",	"Shoulders",	"Chest",	"Waist",	"Legs",	"Feet",	"Wrists",	"Hands",	"Back",	"Main hand",	"Off hand",	"Ranged"}

local INV_BAG, INV_START, INV_END = 255, 1, #inv_slots
local VISIBLE_ITEM_ENTRY_0 = 283
local BAGS =
{
	{BAG = INV_BAG, START = 23, END = 38},
	{BAG = 19, START = 0, END = 35},
	{BAG = 20, START = 0, END = 35},
	{BAG = 21, START = 0, END = 35},
	{BAG = 22, START = 0, END = 35},
}

-- bags -1 inventory and backpack, 19-22 other bags
-- slots 0-18 equipment
-- slots 19-22 bags
-- slots 23-38 backpack
-- slots 0-35 other bags

local space = 20
local opt_space = 100
local opt_amount = 13 -- Warning! Do not use over 30

local Data = {}

function Hello(unit, event, player)
	Data[tostring(player:GetGUID())] = nil
	unit:GossipCreateMenu(100, player, 0)
	for Key0 = INV_START, INV_END do
		unit:GossipMenuAddItem(3, inv_slot_names[Key0], Key0+space, 0, "", 0)
	end
	unit:GossipMenuAddItem(4, "Remove all transmogrifications", 0, 0, "Remove transmogrifications from equipped items?", 0)
	unit:GossipSendMenu(player)
end

function Select(unit, event, player, id, intid, code)
	local pGUID = tostring(player:GetGUID())
	if(intid == 0) then -- remove all transmogs
		for Key0 = INV_START, INV_END do
			RemoveTransmog(inv_slots[Key0], player)
		end
		player:SendAreaTriggerMessage("Transmogrifications removed")
		Hello(unit, event, player)
	elseif(intid == 1) then
		Hello(unit, event, player)
	elseif(intid > INV_START and intid <= INV_END+1) then -- remove one transmog
		RemoveTransmog(inv_slots[intid-1], player)
		player:SendAreaTriggerMessage("Transmogrification removed from "..inv_slot_names[intid-1])
		Select(unit, event, player, id, intid+space-1, code)
	elseif(intid >= INV_START+space and intid <= INV_END+space) then
		local Key0 = intid-space
		local sources = GetValidSources(inv_slots[Key0], player)
		if(not sources) then
			player:SendAreaTriggerMessage("No item in that slot")
			Hello(unit, event, player)
		elseif(#sources < 2) then
			player:SendAreaTriggerMessage("No suitable items in bags")
			Hello(unit, event, player)
		else
			Data[pGUID] = {Key0, sources}
			unit:GossipCreateMenu(100, player, 0)
			for k = 1, #sources-1 do
				unit:GossipMenuAddItem(4, sources[k]:GetName(), k+INV_END+space, 0, "", 0)
			end
			unit:GossipMenuAddItem(4, "Remove transmogrification from "..inv_slot_names[Key0], Key0+1, 0, "Remove transmogrif ication from "..inv_slot_names[Key0].."?", 0)
			unit:GossipMenuAddItem(7, "Back..", 1, 0, "", 0)
			unit:GossipSendMenu(player)
		end
	elseif(intid > INV_END+space and intid <= INV_END+space+opt_amount) then
		local slot = inv_slots[Data[pGUID][1]]
		local target = player:GetInventoryItem(INV_BAG, slot)
		local origGUID = Data[pGUID][2][#Data[pGUID][2]] -- no cheating with swapping items on the fly
		if(target and tostring(target:GetGUID()) == origGUID) then
			local source = Data[pGUID][2][intid-INV_END-space]
			if(source and source:GetOwner():IsInWorld() and pGUID == tostring(source:GetOwner():GetGUID())) then
				AddTransmog(slot, player, source:GetEntryId())
				player:SendAreaTriggerMessage(inv_slot_names[Data[pGUID][1]].." transmogrified")
			else
				player:SendAreaTriggerMessage("Source item is not in bags")
			end
		else
			player:SendAreaTriggerMessage("Target item was unequipped")
		end
		Select(unit, event, player, id, Data[pGUID][1]+space, code)
	end
end

function AddTransmog(slot, player, fake)
	local item = player:GetInventoryItem(INV_BAG, slot)
	if (item) then
		local pGUID, iGUID = tostring(player:GetGUID()), tostring(item:GetGUID())
		player:SetUInt32Value(VISIBLE_ITEM_ENTRY_0+(slot * 2), fake)
		if (not Transmogs[pGUID]) then
			Transmogs[pGUID] = {}
		end
		if (not Transmogs[pGUID][slot]) then
			Transmogs[pGUID][slot] = {}
		end
		Transmogs[pGUID][slot][iGUID] = fake
		CharDBQuery('REPLACE INTO Transmog_items (player_GUID, item_GUID, slot, fake) VALUES ("'..pGUID..'", "'..iGUID..'", '..slot..', '..fake..')')
		return true
	end
	return false
end

function RemoveTransmog(slot, player)
	local pGUID = tostring(player:GetGUID())
	if (Transmogs[pGUID] and Transmogs[pGUID][slot]) then
		local item = player:GetInventoryItem(INV_BAG, slot)
		if (item) then
			local iGUID = tostring(item:GetGUID())
			if (Transmogs[pGUID][slot][iGUID]) then
				player:SetUInt32Value(VISIBLE_ITEM_ENTRY_0+(slot * 2), item:GetEntryId())
				Transmogs[pGUID][slot][iGUID] = nil
				CharDBQuery('DELETE FROM Transmog_items WHERE item_GUID = "'..iGUID..'"')
				return true
			end
		end
	end
	return false
end

function GetValidSources(inv_slot, player) -- returns nil or a table containing the items (can be empty)
	local item = player:GetInventoryItem(INV_BAG, inv_slot)
	if (not item) then return nil end
	local items = {}
	local entries = {}
	local hasitems = false
	for k, DATA in ipairs(BAGS) do
		if (DATA.BAG == INV_BAG or player:GetInventoryItem(INV_BAG, DATA.BAG)) then -- skip nonexistant bags
			for slot = DATA.START, DATA.END do
				local item = player:GetInventoryItem(DATA.BAG, slot)
				if(item) then
					table.insert(entries, item:GetEntryId())
					items[item:GetEntryId()] = item
					if (not hasitems) then hasitems = true end
				end
			end
		end
	end
	if (hasitems) then
		local Q = WorldDBQuery("SELECT inventorytype FROM items WHERE entry = "..item:GetEntryId())
		if (Q) then
			local Q = WorldDBQuery("SELECT entry FROM items WHERE entry IN("..table.concat(entries, ',')..") and inventorytype = "..Q:GetColumn(0):GetULong().." LIMIT "..opt_amount)
			if (Q) then
				local suitable = {}
				for i = 1, Q:GetRowCount() do
					table.insert(suitable, items[Q:GetColumn(0):GetULong()]) -- Could possibly add performance if we let this security off
					Q:NextRow()
				end
				table.insert(suitable, tostring(item:GetGUID()))
				return suitable
			end
		end
	end
	return {}
end

function LoadTransmogs()
	local Time = os.time()
	print("Loading transmogrifications..")
	Transmogs = {}
	-- CharDBQuery("DELETE FROM transmog_items WHERE NOT EXISTS (SELECT 1 FROM playeritems WHERE item_GUID = guid) OR NOT EXISTS (SELECT 1 FROM characters WHERE player_GUID = guid)") -- cleanup before load
	local Q = CharDBQuery("SELECT player_GUID, item_GUID, slot, fake FROM Transmog_items")
	if (Q) then
		for i = 1, Q:GetRowCount() do
			local pGUID, iGUID, slot, fake = Q:GetColumn(0):GetString(), Q:GetColumn(1):GetString(), Q:GetColumn(2):GetULong(), Q:GetColumn(3):GetULong()
			if (not Transmogs[pGUID]) then
				Transmogs[pGUID] = {}
			end
			if (not Transmogs[pGUID][slot]) then
				Transmogs[pGUID][slot] = {}
			end
			Transmogs[pGUID][slot][iGUID] = fake
			Q:NextRow()
		end
	end
	print("Transmogrifications loaded in "..(os.time()-Time).." seconds")
end

function ApplyTransmogs() -- minimum looping and checking
	local players = GetPlayersInWorld()
	for k, player in ipairs(players) do -- loop players
		if (player and player:IsInWorld()) then -- player exists
			local pGUID = tostring(player:GetGUID())
			if (Transmogs[pGUID]) then -- has transmogs
				for slot, Data in pairs(Transmogs[pGUID]) do -- looop transmog slots
					local item = player:GetInventoryItem(INV_BAG, slot)
					if (item) then -- has item in slot
						local iGUID = tostring(item:GetGUID())
						if(Data[iGUID]) then -- check if item has transmog saved
							player:SetUInt32Value(283+(slot * 2), Data[iGUID]) -- apply transmog
						end
					end
				end
			end
		end
	end
end

RegisterUnitGossipEvent(NPCENTRY, 1, Hello)
RegisterUnitGossipEvent(NPCENTRY, 2, Select)
LoadTransmogs()
CreateLuaEvent(ApplyTransmogs, DELAY, 0)

Import this into your character database:
Code:
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;

-- Dumping structure for table arc_char.transmog_items
CREATE TABLE `transmog_items` (
  `player_GUID` text NOT NULL COMMENT 'owner guid',
  `item_GUID` text NOT NULL COMMENT 'item guid',
  `slot` int(10) unsigned NOT NULL COMMENT 'equip slot',
  `fake` int(10) unsigned NOT NULL COMMENT 'fake entry'
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='This table is used for storing the transmogrification information.\r\nDo not edit this table or it''s contents.';

-- Data exporting was unselected.
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

Credits to at arcemu.org, for making this.
 
Back
Top