Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

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