14 Commits

Author SHA1 Message Date
gasaichandesu b920ec50ab fix(premium): fix premium migration being generated with older schema
version
2026-08-19 17:17:01 +04:00
gasaichandesu 5918cf7b1a feat(premium): add SQL data for premium feature 2026-08-19 16:50:58 +04:00
gasaichan e04f0f068c feat(premium): implement summon squire spell interceptor
Squire summon spell is intercepted to summon custom NPC with "service" dialogue options such as open mail, open bank, etc.
2026-08-19 12:43:32 +02:00
gasaichandesu 85287568b5 Merge branch 'master' of ssh://git.moon-well.online:2222/sindoring/moonwell-core into feature/premium 2026-08-17 11:30:49 +04:00
sindoring 75600c767f fix 2026-08-13 01:26:42 +04:00
sindoring bfb4aee94b new customization 2026-08-13 00:52:57 +04:00
gasaichan 9d7bfe2516 feat(premium): fix premium script startup errors 2026-08-10 16:14:18 +02:00
gasaichandesu b5f3f51208 feat(premium): implement premium system through ACCOUNT_FLAG_RECURRING_BILLING flag 2026-08-10 17:40:02 +04:00
sindoring 88ed7f639f fix 2026-08-08 12:27:31 +04:00
sindoring 889fe02d1b увеличение сложности подземелий 2026-08-08 11:53:07 +04:00
sindoring 52868e6634 fix import 2026-08-07 14:09:56 +04:00
gasaichan a45158f756 Merge pull request 'feat(transmog): add transmog module' (#2) from feature/collections into master
Reviewed-on: #2
2026-08-07 10:03:54 +03:00
gasaichandesu 4d36c6f702 fix(sql): fix transmog sql being imported in incorrect database 2026-08-07 08:05:47 +04:00
gasaichandesu ed017ab51a feat(transmog): add transmog module 2026-08-07 06:21:22 +04:00
16 changed files with 29192 additions and 12250 deletions
+22 -16
View File
@@ -183,25 +183,25 @@ ACORE_WORLD_DBC_ENFORCE_ITEM_ATTRIBUTES=0
ACORE_WORLD_INSTANCE_IGNORE_RAID=1
# Множитель физического урона обычной элиты.
ACORE_WORLD_RATE_CREATURE_ELITE_ELITE_DAMAGE=0.80
ACORE_WORLD_RATE_CREATURE_ELITE_ELITE_DAMAGE=1.00
# Множитель физического урона rare.
ACORE_WORLD_RATE_CREATURE_RARE_DAMAGE=0.80
ACORE_WORLD_RATE_CREATURE_RARE_DAMAGE=1.00
# Множитель физического урона rare elite.
ACORE_WORLD_RATE_CREATURE_RAREELITE_DAMAGE=0.75
ACORE_WORLD_RATE_CREATURE_RAREELITE_DAMAGE=1.00
# Множитель физического урона world boss.
ACORE_WORLD_RATE_CREATURE_WORLDBOSS_DAMAGE=1
# Множитель spell-урона обычной элиты.
ACORE_WORLD_RATE_CREATURE_ELITE_ELITE_SPELL_DAMAGE=0.80
ACORE_WORLD_RATE_CREATURE_ELITE_ELITE_SPELL_DAMAGE=1.00
# Множитель spell-урона rare.
ACORE_WORLD_RATE_CREATURE_RARE_SPELL_DAMAGE=0.80
ACORE_WORLD_RATE_CREATURE_RARE_SPELL_DAMAGE=1.00
# Множитель spell-урона rare elite.
ACORE_WORLD_RATE_CREATURE_RAREELITE_SPELL_DAMAGE=0.75
ACORE_WORLD_RATE_CREATURE_RAREELITE_SPELL_DAMAGE=1.00
# Множитель spell-урона world boss.
ACORE_WORLD_RATE_CREATURE_WORLDBOSS_SPELL_DAMAGE=1
@@ -223,10 +223,10 @@ ACORE_WORLD_RATE_CREATURE_WORLDBOSS_HP=1
# ------------------------------------------------------------------------------
# Минимальное число игроков, до которого скейлится обычный инст.
ACORE_AUTOBALANCE_MIN_PLAYERS=1
ACORE_AUTOBALANCE_MIN_PLAYERS=2
# Минимальное число игроков для heroic 5ppl.
ACORE_AUTOBALANCE_MIN_PLAYERS_HEROIC=1
ACORE_AUTOBALANCE_MIN_PLAYERS_HEROIC=2
# Минимальное число игроков для рейдов normal.
ACORE_AUTOBALANCE_MIN_PLAYERS_RAID=1
@@ -234,23 +234,29 @@ ACORE_AUTOBALANCE_MIN_PLAYERS_RAID=1
# Минимальное число игроков для рейдов heroic.
ACORE_AUTOBALANCE_MIN_PLAYERS_RAID_HEROIC=1
# Насколько уровней ниже игрока могут скейлиться мобы обычного подземелья.
ACORE_AUTOBALANCE_LEVEL_SCALING_FLOOR_DUNGEONS=1
# Насколько уровней ниже игрока могут скейлиться мобы heroic-подземелья.
ACORE_AUTOBALANCE_LEVEL_SCALING_FLOOR_HEROIC_DUNGEONS=1
# Множитель HP обычных мобов в normal 5ppl.
ACORE_AUTOBALANCE_STAT_MODIFIER_HEALTH=1.30
ACORE_AUTOBALANCE_STAT_MODIFIER_HEALTH=1.55
# Множитель урона обычных мобов в normal 5ppl.
ACORE_AUTOBALANCE_STAT_MODIFIER_DAMAGE=1.10
ACORE_AUTOBALANCE_STAT_MODIFIER_DAMAGE=2.00
# Множитель HP боссов в normal 5ppl.
ACORE_AUTOBALANCE_STAT_MODIFIER_BOSS_HEALTH=1.40
ACORE_AUTOBALANCE_STAT_MODIFIER_BOSS_HEALTH=2.00
# Множитель HP обычных мобов в heroic 5ppl.
ACORE_AUTOBALANCE_STAT_MODIFIER_HEROIC_HEALTH=1.25
ACORE_AUTOBALANCE_STAT_MODIFIER_HEROIC_HEALTH=1.65
# Множитель урона обычных мобов в heroic 5ppl.
ACORE_AUTOBALANCE_STAT_MODIFIER_HEROIC_DAMAGE=1.05
ACORE_AUTOBALANCE_STAT_MODIFIER_HEROIC_DAMAGE=2.20
# Множитель HP боссов в heroic 5ppl.
ACORE_AUTOBALANCE_STAT_MODIFIER_HEROIC_BOSS_HEALTH=1.35
ACORE_AUTOBALANCE_STAT_MODIFIER_HEROIC_BOSS_HEALTH=2.20
# Кривая скейла рейдов: чем ниже значение, тем быстрее растет сложность с игроками.
ACORE_AUTOBALANCE_INFLECTION_POINT_RAID=0.75
@@ -265,10 +271,10 @@ ACORE_AUTOBALANCE_INFLECTION_POINT_RAID_HEROIC=0.80
ACORE_AUTOBALANCE_INFLECTION_POINT_RAID_HEROIC_BOSS_MODIFIER=1.45
# Множитель урона боссов в обычных 5ppl.
ACORE_AUTOBALANCE_STAT_MODIFIER_BOSS_DAMAGE=1.00
ACORE_AUTOBALANCE_STAT_MODIFIER_BOSS_DAMAGE=2.50
# Множитель урона боссов в heroic 5ppl.
ACORE_AUTOBALANCE_STAT_MODIFIER_HEROIC_BOSS_DAMAGE=0.90
ACORE_AUTOBALANCE_STAT_MODIFIER_HEROIC_BOSS_DAMAGE=2.80
# Общий множитель статов рейда normal.
ACORE_AUTOBALANCE_STAT_MODIFIER_RAID_GLOBAL=0.85
Binary file not shown.
+3
View File
@@ -48,6 +48,9 @@ services:
- ./modules:/azerothcore/modules:ro
- ./lua_scripts:/azerothcore/lua_scripts
- ./client_patch/enUS/DBFilesClient/LFGDungeons.dbc:/azerothcore/env/dist/data/dbc/LFGDungeons.dbc:ro
- ./client_patch/enUS/DBFilesClient/BarberShopStyle.dbc:/azerothcore/env/dist/data/dbc/BarberShopStyle.dbc:ro
- ./client_patch/enUS/DBFilesClient/CreatureDisplayInfoExtra.dbc:/azerothcore/env/dist/data/dbc/CreatureDisplayInfoExtra.dbc:ro
- ./client_patch/enUS/DBFilesClient/SpellVisualKitModelAttach.dbc:/azerothcore/env/dist/data/dbc/SpellVisualKitModelAttach.dbc:ro
volumes:
playerbots-ai-cache:
+1012 -1775
View File
File diff suppressed because it is too large Load Diff
+26646 -10438
View File
File diff suppressed because it is too large Load Diff
+21 -1
View File
@@ -156,7 +156,7 @@ import_mythicplus_sql() {
log "repairing MythicPlus world bootstrap entries"
mysql_exec "acore_world" "
DELETE FROM creature WHERE id = 900001;
DELETE FROM gameobject WHERE id = 900000;
DELETE FROM gameobject WHERE id1 = 900000;
DELETE FROM creature_template_locale WHERE entry = 900001;
DELETE FROM item_template_locale WHERE ID = 900100;
DELETE FROM creature_template_model WHERE CreatureID = 900001;
@@ -279,6 +279,16 @@ import_playerbots_ru_sql() {
import_sql_file "acore_characters" "$names_sql_file"
}
import_transmog_sql() {
log "Started importing Transmogrification SQL files"
local account_transmog_sql="$ROOT_DIR/sql/Transmogrification/auth.sql"
local character_transmog_sql="$ROOT_DIR/sql/Transmogrification/char.sql"
maybe_import_table "acore_auth" "account_transmog" "$account_transmog_sql"
maybe_import_table "acore_characters" "character_transmog" "$character_transmog_sql"
}
configure_server_motd() {
log "configuring MoonWell login message"
mysql_exec "acore_auth" "
@@ -331,6 +341,14 @@ import_encounter_journal_sql() {
fi
}
import_premium_sql() {
log "Started importing Premium SQL files"
local world_premium_sql="$ROOT_DIR/sql/Premium/world.sql"
import_sql_file "acore_world" "$world_premium_sql"
}
if (($# > 0)); then
case "$1" in
-h|--help)
@@ -362,6 +380,8 @@ import_aoe_loot_sql
import_playerbots_ru_sql
import_encounter_journal_sql
import_store_sql
import_transmog_sql
import_premium_sql
configure_server_motd
log "custom SQL bootstrap completed"
+1
View File
@@ -0,0 +1 @@
return {}
+172
View File
@@ -0,0 +1,172 @@
local PLAYER_EVENT_ON_LOGIN = 3
local PLAYER_EVENT_ON_SPELL_CAST = 5
local PLAYER_EVENT_ON_LOGOUT = 4
local PLAYER_EVENT_ON_COMMAND = 42
local PREMIUM_FLAG_INDEX = 100
local ACCOUNT_FLAG_RECURRING_BILLING = 8192
local SUMMON_SQUIRE_SPELL_ID = 80000
local SQUIRE_CREATURE_TEMPLATE_ID = 9000001
local NPC_TEXT_ID = 10000000
---todo extract to utils
---@param inputstr string
---@param separator string
---@return table
local function SplitString(inputstr, separator)
if separator == nil then
separator = "%s"
end
local t = {}
for str in string.gmatch(inputstr, "([^" .. separator .. "]+)") do
table.insert(t, str)
end
return t
end
---@return boolean
local function IsPremium(player)
return player:HasFlag(PREMIUM_FLAG_INDEX, 1)
end
local function OnPremiumPlayer(player)
if not IsPremium(player) then
return
end
player:SendAreaTriggerMessage(
'На вашем аккаунте активна подписка Premium! Благодарим за поддержку проекта MoonWell.')
player:LearnSpell(SUMMON_SQUIRE_SPELL_ID)
player:SendBroadcastMessage("Милостью Элуны вам была выдана способность |cff71d5ff|Hspell:" ..
SUMMON_SQUIRE_SPELL_ID .. "|h[" .. "Призыв Оруженосца]h|")
end
local function RefreshPremiumStatus(player)
local query = AuthDBQuery("SELECT flags FROM account WHERE id = " .. player:GetAccountId())
if query then
local function HasFlag(mask, flag)
return bit_and(mask, flag) == flag
end
local flags = query:GetUInt32(0)
if HasFlag(flags, ACCOUNT_FLAG_RECURRING_BILLING) then
player:SetFlag(PREMIUM_FLAG_INDEX, 1)
OnPremiumPlayer(player)
return true
end
end
return false
end
local function ApplyPremium(player)
AuthDBExecute(
string.format(
"UPDATE account SET flags = flags | %d WHERE id = %d",
ACCOUNT_FLAG_RECURRING_BILLING,
player:GetAccountId()
)
)
RefreshPremiumStatus(player)
end
local function OnLogin(event, player)
RefreshPremiumStatus(player)
end
--- @param event any
--- @param player any
--- @param command string
--- @param chatHandler any
local function OnCommand(event, player, command, chatHandler)
---Console is not supported yet
if not player then return end
local parts = SplitString(command:lower(), ' ')
if parts[1] ~= 'premium' then return end
if parts[2] == 'add' then
ApplyPremium(player:GetSelection())
end
return false
end
local function OnSummonSquireCast(player)
local x, y, z, o = player:GetLocation()
local squire = player:SpawnCreature(SQUIRE_CREATURE_TEMPLATE_ID, x + 1, y + 1, z, o, 1, 30000)
if squire then
squire:SetFaction(player:GetFaction())
end
end
local function OnSpellCast(event, player, spell, skipCheck)
local spellId = spell:GetEntry()
if spellId == SUMMON_SQUIRE_SPELL_ID then
OnSummonSquireCast(player)
end
end
local function OnGossipHello(event, player, creature)
player:GossipClearMenu()
player:GossipMenuAddItem(4, "Открыть почтовый ящик", 900001, 1)
player:GossipMenuAddItem(1, "Открыть банк", 900001, 2)
player:GossipMenuAddItem(6, "Открыть аукцион", 900001, 3)
player:GossipMenuAddItem(4, "Отремонтировать снаряжение", 900001, 4)
player:GossipSendMenu(NPC_TEXT_ID, creature)
end
local function OnGossipSelect(event, player, creature, sender, intid, code)
if sender == 900001 then
if intid == 1 then
player:SendShowMailBox(creature:GetGUID())
player:GossipComplete()
end
if intid == 2 then
player:SendShowBank(creature)
player:GossipComplete()
end
if intid == 3 then
player:SendAuctionMenu(creature)
player:GossipComplete()
end
if intid == 4 then
player:DurabilityRepairAll()
player:PlayDirectSound(1116)
player:GossipComplete()
end
end
end
local function OnLogout(event, player)
player:RemoveSpell(SUMMON_SQUIRE_SPELL_ID)
end
RegisterCreatureGossipEvent(SQUIRE_CREATURE_TEMPLATE_ID, 1, OnGossipHello)
RegisterCreatureGossipEvent(SQUIRE_CREATURE_TEMPLATE_ID, 2, OnGossipSelect)
RegisterPlayerEvent(PLAYER_EVENT_ON_LOGIN, OnLogin)
RegisterPlayerEvent(PLAYER_EVENT_ON_LOGOUT, OnLogout)
RegisterPlayerEvent(PLAYER_EVENT_ON_COMMAND, OnCommand)
RegisterPlayerEvent(PLAYER_EVENT_ON_SPELL_CAST, OnSpellCast)
@@ -0,0 +1,838 @@
-- ╔════════════════════════════════════════════════════════════════════════╗
-- ║ Transmog System Eluna Script by DanielTheDeveloper ║
-- ╚════════════════════════════════════════════════════════════════════════╝
--
-- ╔══════════════════════════╗
-- ╔══════════════════════║ Transmog System Settings ║══════════════════════╗
-- ║ ╚══════════════════════════╝ ║
-- ║ Automatically adds transmog appearances to the players account-wide ║
-- ║ transmog collection when they equip an item for the first time. ║
-- ║ ║
-- ║ It is recommended to leave this option enabled. ║
-- ╟────────────────────────────────────────────────────────────────────────╢
local ADD_NEWLY_EQUIPPED_ITEMS_TO_THE_TRANSMOG_LIST = true --║
-- ╟────────────────────────────────────────────────────────────────────────╢
-- ║ ║
-- ║ Automatically adds transmog appearances to the players account-wide ║
-- ║ transmog collection when they loot an item for the first time. ║
-- ║ ║
-- ║ It is recommended to leave this option disabled as it creates the ║
-- ║ potential for a more healthy transmog economy to exist inside the ║
-- ║ auction house. ║
-- ╟────────────────────────────────────────────────────────────────────────╢
local ADD_NEWLY_LOOTED_ITEMS_TO_THE_TRANSMOG_LIST = false --║
-- ╟────────────────────────────────────────────────────────────────────────╢
-- ║ ║
-- ║ Automatically adds all applicable quest reward items as transmog ║
-- ║ appearances to the players account-wide transmog collection when ║
-- ║ completing a quest, regardless of which quest reward the player ║
-- ║ actually decided to select. ║
-- ║ ║
-- ║ It is recommended to leave this option enabled as it eliminates the ║
-- ║ dilemma of deciding between a potential transmog appearance or gear ║
-- ║ that is useful for the character. ║
-- ╟────────────────────────────────────────────────────────────────────────╢
local ADD_QUEST_REWARD_ITEMS_TO_THE_TRANSMOG_LIST = true --║
-- ╟────────────────────────────────────────────────────────────────────────╢
-- ║ ║
-- ║ Restricts armor transmog appearances to items made up of the same ║
-- ║ material. As an example, with this option enabled, cloth chest pieces ║
-- ║ can only be transmogrified to appear as other cloth chest pieces. ║
-- ║ When this option is disabled, cloth chest pieces can be ║
-- ║ transmogrified to appear as a cloth, leather, mail, or plate chest ║
-- ║ piece. ║
-- ║ ║
-- ║ It is recommended to leave this option enabled as it leaves the ║
-- ║ class fantasy intact. ║
-- ╟────────────────────────────────────────────────────────────────────────╢
local RESTRICT_ARMOR_TRANSMOG_TO_SIMILAR_MATERIALS = true --║
-- ╟────────────────────────────────────────────────────────────────────────╢
-- ║ ║
-- ║ Restricts weapon transmog appearances to the same weapon. As an ║
-- ║ example, with this option enabled, two-handed swords can only be ║
-- ║ transmogrified to appear as other two-handed swords. When this option ║
-- ║ is disabled, two-handed swords can be transmogrified to appear as a ║
-- ║ one-handed sword, staff, polearm, fishing pole, etc. ║
-- ║ ║
-- ║ It is recommended to leave this option enabled as it leaves the ║
-- ║ class fantasy intact. ║
-- ╟────────────────────────────────────────────────────────────────────────╢
local RESTRICT_WEAPON_TRANSMOG_TO_SIMILAR_WEAPONS = true --║
-- ╚════════════════════════════════════════════════════════════════════════╝
local AIO = AIO or require("AIO")
local TransmogrificationHandler = AIO.AddHandlers("TransmogrificationServer", {})
local SLOTS = 6
local CALC = 281
local PLAYER_VISIBLE_ITEM_1_ENTRYID = 283 -- Head
local PLAYER_VISIBLE_ITEM_3_ENTRYID = 287 -- Shoulder
local PLAYER_VISIBLE_ITEM_4_ENTRYID = 289 -- Shirt
local PLAYER_VISIBLE_ITEM_5_ENTRYID = 291 -- Chest
local PLAYER_VISIBLE_ITEM_6_ENTRYID = 293 -- Waist
local PLAYER_VISIBLE_ITEM_7_ENTRYID = 295 -- Legs
local PLAYER_VISIBLE_ITEM_8_ENTRYID = 297 -- Feet
local PLAYER_VISIBLE_ITEM_9_ENTRYID = 299 -- Wrist
local PLAYER_VISIBLE_ITEM_10_ENTRYID = 301 -- Hands
local PLAYER_VISIBLE_ITEM_15_ENTRYID = 311 -- Back
local PLAYER_VISIBLE_ITEM_16_ENTRYID = 313 -- Main
local PLAYER_VISIBLE_ITEM_17_ENTRYID = 315 -- Off
local PLAYER_VISIBLE_ITEM_18_ENTRYID = 317 -- Ranged
local PLAYER_VISIBLE_ITEM_19_ENTRYID = 319 -- Tabard
local UNUSABLE_INVENTORY_TYPES = {[2] = true, [11] = true, [12] = true, [18] = true, [24] = true, [27] = true, [28] = true}
-- TODO: Add further language support.
local localeMessages = {
LOOT_ITEM_LOCALE = {
[0] = " has been added to your appearance collection.", -- enUS/enGB
[3] = " wurde deiner Transmog-Sammlung hinzugefügt.", -- deDE
}
}
local function GetLocalizedMessage(messageID, locale, ...)
local message = localeMessages[messageID][locale] or localeMessages[messageID][0]
if select("#", ...) > 0 then
return string.format(message, ...)
end
return message
end
function Transmog_CalculateSlot(slot)
if (slot == 0) then
slot = 1
elseif (slot >= 2) then
slot = slot + 1
end
return CALC + (slot * 2);
end
function Transmog_CalculateSlotReverse(slot)
local reverseSlot = (slot - CALC) / 2
if (reverseSlot == 1) then
return 0;
end
return reverseSlot;
end
function Transmog_OnCharacterCreate(event, player)
local playerGUID = player:GetGUIDLow()
CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_1_ENTRYID .. "', NULL, '');") -- Head
CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_3_ENTRYID .. "', NULL, '');") -- Shoulder
CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_4_ENTRYID .. "', NULL, '');") -- Shirt
CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_5_ENTRYID .. "', NULL, '');") -- Chest
CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_6_ENTRYID .. "', NULL, '');") -- Waist
CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_7_ENTRYID .. "', NULL, '');") -- Legs
CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_8_ENTRYID .. "', NULL, '');") -- Feet
CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_9_ENTRYID .. "', NULL, '');") -- Wrist
CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_10_ENTRYID .. "', NULL, '');") -- Hands
CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_15_ENTRYID .. "', NULL, '');") -- Back
CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_16_ENTRYID .. "', NULL, '');") -- Main
CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_17_ENTRYID .. "', NULL, '');") -- Off
CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_18_ENTRYID .. "', NULL, '');") -- Ranged
CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_19_ENTRYID .. "', NULL, '');") -- Tabard
end
function Transmog_OnCharacterDelete(event, guid)
CharDBQuery("DELETE FROM character_transmog WHERE player_guid = " .. guid .. "")
end
function Transmog_OnCharacterLogin(event, player)
local playerGUID = player:GetGUIDLow()
local playerExistsQuery = CharDBQuery("SELECT COUNT(*) FROM character_transmog WHERE player_guid = " .. playerGUID .. ";")
local playerExists = playerExistsQuery:GetUInt32(0) > 0
if not playerExists then
Transmog_OnCharacterCreate(event, player)
end
end
function TransmogrificationHandler.LootItemLocale(player, item, count, locale)
local accountGUID = player:GetAccountId()
local itemID
local itemTemplate
if type(item) == "number" then
itemID = item
itemTemplate = GetItemTemplate(itemID)
else
itemTemplate = item:GetItemTemplate()
itemID = itemTemplate:GetItemId()
end
local inventoryType = itemTemplate:GetInventoryType()
local inventorySubType = itemTemplate:GetSubClass()
local class = itemTemplate:GetClass()
if (class == 2 or class == 4) and not UNUSABLE_INVENTORY_TYPES[inventoryType] then
local countQuery = AuthDBQuery("SELECT COUNT(*) FROM account_transmog WHERE account_id = " .. accountGUID .. " AND unlocked_item_id = " .. itemID .. ";")
local count = countQuery:GetUInt32(0)
local isNewTransmog = (count == 0)
local displayID = itemTemplate:GetDisplayId()
local displayExistsQuery = AuthDBQuery("SELECT COUNT(*) FROM account_transmog WHERE account_id = " .. accountGUID .. " AND display_id = " .. displayID .. ";")
local displayExists = displayExistsQuery:GetUInt32(0) > 0
if isNewTransmog and not displayExists then
local itemName = itemTemplate:GetName()
local locItemName = itemTemplate:GetName(locale)
local itemQuality = itemTemplate:GetQuality()
itemName = itemName:gsub("'", "''")
AuthDBQuery("INSERT IGNORE INTO `account_transmog` (`account_id`, `unlocked_item_id`, `inventory_type`, `inventory_subtype`,`display_id`, `item_name`) VALUES (" .. accountGUID .. ", " .. itemID .. ", " .. inventoryType .. ", " .. inventorySubType .. ", " .. displayID .. ", '" .. itemName .. "');")
if locItemName == nil then
locItemName = itemTemplate:GetName(0)
end
local qualityColors = {
[0] = "|cff9d9d9d", -- Poor
[1] = "|cffffffff", -- Common
[2] = "|cff1eff00", -- Uncommon
[3] = "|cff0070dd", -- Rare
[4] = "|cffa335ee", -- Epic
[5] = "|cffff8000", -- Legendary
[6] = "|cffe6cc80" -- Heirloom
}
local colorCode = qualityColors[itemQuality] or "|cffffffff" -- Default to white if quality not found
local itemLink = "|Hitem:" .. itemID .. ":0:0:0:0:0:0:0:0|h" .. colorCode .. "[" .. locItemName .. "]|r|h|r"
player:SendBroadcastMessage(itemLink .. GetLocalizedMessage("LOOT_ITEM_LOCALE", locale))
end
end
end
function GetDisplaySlotForEquipmentSlot(equipSlot)
local slotMapping = {
[0] = PLAYER_VISIBLE_ITEM_1_ENTRYID, -- Head
[2] = PLAYER_VISIBLE_ITEM_3_ENTRYID, -- Shoulders
[3] = PLAYER_VISIBLE_ITEM_4_ENTRYID, -- Shirt
[4] = PLAYER_VISIBLE_ITEM_5_ENTRYID, -- Chest
[5] = PLAYER_VISIBLE_ITEM_6_ENTRYID, -- Waist
[6] = PLAYER_VISIBLE_ITEM_7_ENTRYID, -- Legs
[7] = PLAYER_VISIBLE_ITEM_8_ENTRYID, -- Feet
[8] = PLAYER_VISIBLE_ITEM_9_ENTRYID, -- Wrists
[9] = PLAYER_VISIBLE_ITEM_10_ENTRYID, -- Hands
[14] = PLAYER_VISIBLE_ITEM_15_ENTRYID, -- Back
[15] = PLAYER_VISIBLE_ITEM_16_ENTRYID, -- Main Hand
[16] = PLAYER_VISIBLE_ITEM_17_ENTRYID, -- Off Hand
[17] = PLAYER_VISIBLE_ITEM_18_ENTRYID, -- Ranged
[18] = PLAYER_VISIBLE_ITEM_19_ENTRYID -- Tabard
}
return slotMapping[equipSlot]
end
function Transmog_OnEquipItem(event, player, item, bag, slot)
local itemID = item:GetItemTemplate():GetItemId()
local locale = player:GetDbLocaleIndex()
if ADD_NEWLY_EQUIPPED_ITEMS_TO_THE_TRANSMOG_LIST then
TransmogrificationHandler.LootItemLocale(player, itemID, 1, locale)
end
local class = item:GetItemTemplate():GetClass()
local inventoryType = item:GetItemTemplate():GetInventoryType()
if (class == 2 or class == 4) and not UNUSABLE_INVENTORY_TYPES[inventoryType] then
local playerGUID = player:GetGUIDLow()
local displaySlot = GetDisplaySlotForEquipmentSlot(slot)
if displaySlot then
CharDBQuery("UPDATE character_transmog SET real_item = " .. itemID .. " WHERE player_guid = " .. playerGUID .. " AND slot = " .. displaySlot)
end
end
end
function Transmog_OnLootItem(event, player, item, count)
local locale = player:GetDbLocaleIndex()
TransmogrificationHandler.LootItemLocale(player, item, 1, locale)
end
function Transmog_OnQuestComplete(event, player, quest)
local questID = quest:GetId()
local locale = player:GetDbLocaleIndex()
local questRewardsQuery = WorldDBQuery("SELECT RewardItem1, RewardItem2, RewardItem3, RewardItem4, RewardChoiceItemID1, RewardChoiceItemID2, RewardChoiceItemID3, RewardChoiceItemID4, RewardChoiceItemID5, RewardChoiceItemID6 FROM quest_template WHERE ID = " .. questID .. ";")
if not questRewardsQuery then
return
end
for i = 0, 9 do
local itemID = questRewardsQuery:GetUInt32(i)
if itemID and itemID > 0 then
TransmogrificationHandler.LootItemLocale(player, itemID, 1, locale)
end
end
end
function GetEquipmentSlot(displaySlot)
-- Map from display/visual slots to actual equipment slots
local slotMapping = {
[PLAYER_VISIBLE_ITEM_1_ENTRYID] = 0, -- Head (0 in equipment slot system)
[PLAYER_VISIBLE_ITEM_3_ENTRYID] = 2, -- Shoulders
[PLAYER_VISIBLE_ITEM_4_ENTRYID] = 3, -- Shirt
[PLAYER_VISIBLE_ITEM_5_ENTRYID] = 4, -- Chest
[PLAYER_VISIBLE_ITEM_6_ENTRYID] = 5, -- Waist
[PLAYER_VISIBLE_ITEM_7_ENTRYID] = 6, -- Legs
[PLAYER_VISIBLE_ITEM_8_ENTRYID] = 7, -- Feet
[PLAYER_VISIBLE_ITEM_9_ENTRYID] = 8, -- Wrists
[PLAYER_VISIBLE_ITEM_10_ENTRYID] = 9, -- Hands
[PLAYER_VISIBLE_ITEM_15_ENTRYID] = 14, -- Back/Cloak
[PLAYER_VISIBLE_ITEM_16_ENTRYID] = 15, -- Main Hand
[PLAYER_VISIBLE_ITEM_17_ENTRYID] = 16, -- Off Hand
[PLAYER_VISIBLE_ITEM_18_ENTRYID] = 17, -- Ranged
[PLAYER_VISIBLE_ITEM_19_ENTRYID] = 18, -- Tabard
}
return slotMapping[displaySlot] or Transmog_CalculateSlotReverse(displaySlot)
end
-- TODO: add lua/c++ function for unequip!!
function TransmogrificationHandler.OnUnequipItem(player)
local playerGUID = player:GetGUIDLow()
-- Check all slots to see if any items were unequipped
local slots = {
PLAYER_VISIBLE_ITEM_1_ENTRYID, -- Head
PLAYER_VISIBLE_ITEM_3_ENTRYID, -- Shoulder
PLAYER_VISIBLE_ITEM_4_ENTRYID, -- Shirt
PLAYER_VISIBLE_ITEM_5_ENTRYID, -- Chest
PLAYER_VISIBLE_ITEM_6_ENTRYID, -- Waist
PLAYER_VISIBLE_ITEM_7_ENTRYID, -- Legs
PLAYER_VISIBLE_ITEM_8_ENTRYID, -- Feet
PLAYER_VISIBLE_ITEM_9_ENTRYID, -- Wrist
PLAYER_VISIBLE_ITEM_10_ENTRYID, -- Hands
PLAYER_VISIBLE_ITEM_15_ENTRYID, -- Back
PLAYER_VISIBLE_ITEM_16_ENTRYID, -- Main
PLAYER_VISIBLE_ITEM_17_ENTRYID, -- Off
PLAYER_VISIBLE_ITEM_18_ENTRYID, -- Ranged
PLAYER_VISIBLE_ITEM_19_ENTRYID -- Tabard
}
for _, slot in ipairs(slots) do
-- Get the corresponding equipment slot
local equipmentSlot = GetEquipmentSlot(slot)
-- Check if this slot has an item equipped
local currentItem = player:GetEquippedItemBySlot(equipmentSlot)
-- If the slot is empty but we have a transmog value, we need to clear it
if not currentItem then
local transmogQuery = CharDBQuery("SELECT item FROM character_transmog WHERE player_guid = "..playerGUID.." AND slot = "..slot..";")
if transmogQuery and transmogQuery:GetUInt32(0) and transmogQuery:GetUInt32(0) > 0 then
-- Clear the transmog by setting both item and real_item to NULL
CharDBQuery("UPDATE character_transmog SET item = NULL, real_item = NULL WHERE player_guid = "..playerGUID.." AND slot = "..slot..";")
player:SetUInt32Value(tonumber(slot), 0)
-- Inform the client to update the display for this slot
AIO.Handle(player, "TransmogrificationServer", "ClearSlotTransmogrification", slot)
end
end
end
end
function Transmog_Load(player)
local playerGUID = player:GetGUIDLow()
local transmogs = CharDBQuery("SELECT item, slot FROM character_transmog WHERE player_guid = "..playerGUID..";")
if (transmogs == nil) then
return;
end
for i = 1, transmogs:GetRowCount(), 1 do
local currentRow = transmogs:GetRow()
local slot = currentRow["slot"]
local item = currentRow["item"]
if (item ~= nil and item ~= '') then
player:SetUInt32Value(tonumber(slot), item)
end
transmogs:NextRow()
end
end
function Transmog_OnLogin(event, player)
-- Apply transmog on login
-- Transmog_Load(player)
--local item = player:GetEquippedItemBySlot(4)
--print(item:GetName())
end
function TransmogrificationHandler.LoadPlayer(player)
Transmog_Load(player)
player:SetUInt32Value(147, 1) -- use unit padding
end
function TransmogrificationHandler.EquipTransmogItem(player, item, slot)
local playerGUID = player:GetGUIDLow()
if item == nil and item ~= 0 then
local oldItem = CharDBQuery("SELECT real_item FROM character_transmog WHERE player_guid = "..playerGUID.." AND slot = "..slot..";")
local oldItemID = oldItem:GetUInt32(0)
if oldItemID == nil or oldItemID == 0 then
CharDBQuery("INSERT INTO character_transmog (`player_guid`, `slot`, `item`) VALUES ("..playerGUID..", '"..slot.."', NULL) ON DUPLICATE KEY UPDATE item = VALUES(item);")
player:SetUInt32Value(tonumber(slot), 0)
return
end
CharDBQuery("INSERT INTO character_transmog (`player_guid`, `slot`, `item`, `real_item`) VALUES ("..playerGUID..", '"..slot.."', NULL, "..oldItemID..") ON DUPLICATE KEY UPDATE item = VALUES(item), real_item = VALUES(real_item);")
player:SetUInt32Value(tonumber(slot), oldItemID)
return
end
local oldItem = CharDBQuery("SELECT real_item FROM character_transmog WHERE player_guid = "..playerGUID.." AND slot = "..slot..";")
local oldItemID = oldItem:GetUInt32(0)
if oldItemID == nil or oldItemID == 0 then
CharDBQuery("INSERT INTO character_transmog (`player_guid`, `slot`, `item`) VALUES ("..playerGUID..", '"..slot.."', "..item..") ON DUPLICATE KEY UPDATE item = VALUES(item);")
else
CharDBQuery("INSERT INTO character_transmog (`player_guid`, `slot`, `item`, `real_item`) VALUES ("..playerGUID..", '"..slot.."', "..item..", "..oldItemID..") ON DUPLICATE KEY UPDATE item = VALUES(item), real_item = VALUES(real_item);")
end
player:SetUInt32Value(tonumber(slot), item)
end
function TransmogrificationHandler.EquipAllTransmogItems(player, transmogPreview)
if (transmogPreview == {}) then
return;
end
local playerGUID = player:GetGUIDLow()
for slot, item in ipairs(transmogPreview) do
player:SetUInt32Value(tonumber(slot), item)
CharDBQuery("INSERT INTO character_transmog (`player_guid`, `slot`, `item`) VALUES ("..playerGUID..", '"..slot.."', "..item..") ON DUPLICATE KEY UPDATE item = VALUES(item);")
end
end
function TransmogrificationHandler.UnequipTransmogItem(player, slot)
local playerGUID = player:GetGUIDLow()
-- Get the corresponding equipment slot using our mapping function
local equipmentSlot = GetEquipmentSlot(slot)
-- Check if there's an actual item equipped in this slot
local currentItem = player:GetEquippedItemBySlot(equipmentSlot)
-- If no item is currently equipped, we should set the visual to 0
if not currentItem then
CharDBQuery("UPDATE character_transmog SET item = NULL, real_item = NULL WHERE player_guid = "..playerGUID.." AND slot = "..slot..";")
player:SetUInt32Value(tonumber(slot), 0)
return
end
-- Otherwise, handle normally but ensure we're setting to the real item or 0
local oldItem = CharDBQuery("SELECT real_item FROM character_transmog WHERE player_guid = "..playerGUID.." AND slot = "..slot..";")
-- If no record or null real_item, set to the actual item's appearance
if not oldItem or not oldItem:GetUInt32(0) or oldItem:GetUInt32(0) == 0 then
-- Here we set item to NULL (not 0) to indicate no transmog is applied
CharDBQuery("UPDATE character_transmog SET item = NULL WHERE player_guid = "..playerGUID.." AND slot = "..slot..";")
-- Get the current equipped item's ID to display
local realItemID = currentItem:GetItemTemplate():GetItemId()
player:SetUInt32Value(tonumber(slot), realItemID)
return
end
-- If we have a real_item value, restore that appearance
local oldItemID = oldItem:GetUInt32(0)
CharDBQuery("UPDATE character_transmog SET item = NULL WHERE player_guid = "..playerGUID.." AND slot = "..slot..";")
player:SetUInt32Value(tonumber(slot), oldItemID)
end
function TransmogrificationHandler.displayTransmog(player, spellid)
AIO.Handle(player, "TransmogrificationServer", "TransmogrificationFrame")
return false
end
function TransmogrificationHandler.Print(player, ...)
print(...)
end
function TransmogrificationHandler.SetTransmogItemIDs(player)
local playerGUID = player:GetGUIDLow()
local transmogs = CharDBQuery('SELECT item, real_item, slot FROM character_transmog WHERE player_guid = '..playerGUID..';') -- AND slot NOT IN ("313", "315", "317")
if (transmogs == nil) then
return;
end
for i = 1, transmogs:GetRowCount(), 1 do
local currentRow = transmogs:GetRow()
local item = currentRow["item"]
local slot = currentRow["slot"]
local real_item = currentRow["real_item"]
local validSlotItem = player:GetUInt32Value(tonumber(slot))
if (validSlotItem == 0) then
CharDBQuery("INSERT INTO character_transmog (`player_guid`, `slot`, `item`, `real_item`) VALUES ("..playerGUID..", '"..slot.."', 0, "..real_item..") ON DUPLICATE KEY UPDATE item = VALUES(item), real_item = VALUES(real_item);")
end
if (not item or item == 0 and real_item ~= nil and real_item ~= 0 and (validSlotItem ~= 0 or not validSlotItem)) then
AIO.Handle(player, "TransmogrificationServer", "SetTransmogItemIDClient", slot, 0, real_item)
else
AIO.Handle(player, "TransmogrificationServer", "SetTransmogItemIDClient", slot, item, real_item)
end
transmogs:NextRow()
end
end
function TransmogrificationHandler.SetCurrentSlotItemIDs(player, slot, page)
local accountGUID = player:GetAccountId()
-- Define inventory type mapping
local inventoryTypesMapping = {
[PLAYER_VISIBLE_ITEM_1_ENTRYID] = "= 1",
[PLAYER_VISIBLE_ITEM_3_ENTRYID] = "= 3",
[PLAYER_VISIBLE_ITEM_4_ENTRYID] = "= 4",
[PLAYER_VISIBLE_ITEM_5_ENTRYID] = "IN (5, 20)",
[PLAYER_VISIBLE_ITEM_6_ENTRYID] = "= 6",
[PLAYER_VISIBLE_ITEM_7_ENTRYID] = "= 7",
[PLAYER_VISIBLE_ITEM_8_ENTRYID] = "= 8",
[PLAYER_VISIBLE_ITEM_9_ENTRYID] = "= 9",
[PLAYER_VISIBLE_ITEM_10_ENTRYID] = "= 10",
[PLAYER_VISIBLE_ITEM_15_ENTRYID] = "= 16",
[PLAYER_VISIBLE_ITEM_16_ENTRYID] = "IN (13, 17, 21)",
[PLAYER_VISIBLE_ITEM_17_ENTRYID] = "IN (13, 17, 22, 23, 14)",
[PLAYER_VISIBLE_ITEM_18_ENTRYID] = "IN (15, 25, 26)",
[PLAYER_VISIBLE_ITEM_19_ENTRYID] = "= 19"
}
-- Get the inventory type for the given slot
local inventoryTypes = inventoryTypesMapping[slot]
if not inventoryTypes then
return -- Slot not valid, exit early
end
local equipmentSlot = nil
if slot == PLAYER_VISIBLE_ITEM_3_ENTRYID then
equipmentSlot = 2 -- Shoulder
elseif slot == PLAYER_VISIBLE_ITEM_4_ENTRYID then
equipmentSlot = 3 -- Shirt
elseif slot == PLAYER_VISIBLE_ITEM_5_ENTRYID then
equipmentSlot = 4 -- Chest
elseif slot == PLAYER_VISIBLE_ITEM_6_ENTRYID then
equipmentSlot = 5 -- Waist
elseif slot == PLAYER_VISIBLE_ITEM_10_ENTRYID then
equipmentSlot = 9 -- Hands
elseif slot == PLAYER_VISIBLE_ITEM_15_ENTRYID then
equipmentSlot = 14 -- Back
elseif slot == PLAYER_VISIBLE_ITEM_16_ENTRYID then
equipmentSlot = 15 -- Main
elseif slot == PLAYER_VISIBLE_ITEM_17_ENTRYID then
equipmentSlot = 16 -- Off
elseif slot == PLAYER_VISIBLE_ITEM_18_ENTRYID then
equipmentSlot = 17 -- Ranged
else
equipmentSlot = Transmog_CalculateSlotReverse(slot)
end
local currentItem = player:GetEquippedItemBySlot(equipmentSlot)
local equippedItemType = nil
local equippedItemSubType = nil
if currentItem then
equippedItemType = currentItem:GetClass()
equippedItemSubType = currentItem:GetSubClass()
end
-- Calculate page offset for pagination
local pageOffset = (page > 1) and (SLOTS * (page - 1)) or 0
local queryConditions = "account_id = " .. accountGUID .. " AND inventory_type " .. inventoryTypes
if equippedItemSubType then
if (RESTRICT_ARMOR_TRANSMOG_TO_SIMILAR_MATERIALS and equippedItemType == 4) then
if slot == PLAYER_VISIBLE_ITEM_5_ENTRYID then -- Special check for chestpiece/robes.
queryConditions = queryConditions .. " AND inventory_subtype = " .. equippedItemSubType
else
queryConditions = queryConditions .. " AND inventory_subtype = " .. equippedItemSubType
end
elseif (RESTRICT_WEAPON_TRANSMOG_TO_SIMILAR_WEAPONS and equippedItemType == 2) then
queryConditions = queryConditions .. " AND inventory_subtype = " .. equippedItemSubType
end
end
-- Query to count matching transmogs
local countQuery = string.format(
"SELECT COUNT(unlocked_item_id) FROM account_transmog WHERE %s",
queryConditions
)
local countResult = AuthDBQuery(countQuery)
if not countResult then
AIO.Handle(player, "TransmogrificationServer", "InitTab", {}, page, false)
return
end
-- Get the total number of transmogs
local totalTransmogs = countResult:GetUInt32(0)
local hasMorePages = (totalTransmogs > SLOTS * page)
-- Query to retrieve transmogs for the current page
local transmogQuery = string.format(
"SELECT unlocked_item_id FROM account_transmog WHERE %s LIMIT %d OFFSET %d;",
queryConditions, SLOTS, pageOffset
)
local transmogs = AuthDBQuery(transmogQuery)
if not transmogs then
AIO.Handle(player, "TransmogrificationServer", "InitTab", {}, page, false)
return
end
-- Collect the unlocked item IDs
local currentSlotItemIDs = {}
for i = 1, transmogs:GetRowCount() do
local currentRow = transmogs:GetRow()
local item = currentRow["unlocked_item_id"]
table.insert(currentSlotItemIDs, item)
transmogs:NextRow()
end
-- Return the result to the player
AIO.Handle(player, "TransmogrificationServer", "InitTab", currentSlotItemIDs, page, hasMorePages)
end
function TransmogrificationHandler.SetSearchCurrentSlotItemIDs(player, slot, page, search)
-- Ensure search is not empty or nil
if ( search == nil or serach == '' ) then
return;
end
-- Escape special characters in search string
search = search:gsub("[%'`&\"]", "%%")
-- Define slot-to-inventory type mapping
local inventoryTypesMapping = {
[PLAYER_VISIBLE_ITEM_1_ENTRYID] = "= 1",
[PLAYER_VISIBLE_ITEM_3_ENTRYID] = "= 3",
[PLAYER_VISIBLE_ITEM_4_ENTRYID] = "= 4",
[PLAYER_VISIBLE_ITEM_5_ENTRYID] = "IN (5, 20)",
[PLAYER_VISIBLE_ITEM_6_ENTRYID] = "= 6",
[PLAYER_VISIBLE_ITEM_7_ENTRYID] = "= 7",
[PLAYER_VISIBLE_ITEM_8_ENTRYID] = "= 8",
[PLAYER_VISIBLE_ITEM_9_ENTRYID] = "= 9",
[PLAYER_VISIBLE_ITEM_10_ENTRYID] = "= 10",
[PLAYER_VISIBLE_ITEM_15_ENTRYID] = "= 16",
[PLAYER_VISIBLE_ITEM_16_ENTRYID] = "IN (13, 17, 21)",
[PLAYER_VISIBLE_ITEM_17_ENTRYID] = "IN (13, 17, 22, 23, 14)",
[PLAYER_VISIBLE_ITEM_18_ENTRYID] = "IN (15, 25, 26)",
[PLAYER_VISIBLE_ITEM_19_ENTRYID] = "= 19"
}
-- Get inventory type for the given slot
local inventoryTypes = inventoryTypesMapping[slot]
if not inventoryTypes then
return -- Slot not valid
end
local equipmentSlot = nil
if slot == PLAYER_VISIBLE_ITEM_3_ENTRYID then
equipmentSlot = 2 -- Shoulder
elseif slot == PLAYER_VISIBLE_ITEM_4_ENTRYID then
equipmentSlot = 3 -- Shirt
elseif slot == PLAYER_VISIBLE_ITEM_5_ENTRYID then
equipmentSlot = 4 -- Chest
elseif slot == PLAYER_VISIBLE_ITEM_6_ENTRYID then
equipmentSlot = 5 -- Waist
elseif slot == PLAYER_VISIBLE_ITEM_10_ENTRYID then
equipmentSlot = 9 -- Hands
elseif slot == PLAYER_VISIBLE_ITEM_15_ENTRYID then
equipmentSlot = 14 -- Back
elseif slot == PLAYER_VISIBLE_ITEM_16_ENTRYID then
equipmentSlot = 15 -- Main
elseif slot == PLAYER_VISIBLE_ITEM_17_ENTRYID then
equipmentSlot = 16 -- Off
elseif slot == PLAYER_VISIBLE_ITEM_18_ENTRYID then
equipmentSlot = 17 -- Ranged
else
equipmentSlot = Transmog_CalculateSlotReverse(slot)
end
local currentItem = player:GetEquippedItemBySlot(equipmentSlot)
local equippedItemType = nil
local equippedItemSubType = nil
if currentItem then
equippedItemType = currentItem:GetClass()
equippedItemSubType = currentItem:GetSubClass()
end
-- Calculate page offset
local pageOffset = (page > 1) and (SLOTS * (page - 1)) or 0
local queryConditions = "account_id = " .. player:GetAccountId() .. " AND inventory_type " .. inventoryTypes .. " AND (display_id LIKE '%" .. search .. "%' OR item_name LIKE '%" .. search .. "%')"
if equippedItemSubType then
if (RESTRICT_ARMOR_TRANSMOG_TO_SIMILAR_MATERIALS and equippedItemType == 4) then
if slot == PLAYER_VISIBLE_ITEM_5_ENTRYID then -- Special check for chestpiece/robes.
queryConditions = queryConditions .. " AND inventory_subtype = " .. equippedItemSubType
else
queryConditions = queryConditions .. " AND inventory_subtype = " .. equippedItemSubType
end
elseif (RESTRICT_WEAPON_TRANSMOG_TO_SIMILAR_WEAPONS and equippedItemType == 2) then
queryConditions = queryConditions .. " AND inventory_subtype = " .. equippedItemSubType
end
end
-- Query to count matching transmogs
local countQuery = string.format(
"SELECT COUNT(unlocked_item_id) FROM account_transmog WHERE %s;",
queryConditions
)
local countResult = AuthDBQuery(countQuery)
if not countResult then
AIO.Handle(player, "TransmogrificationServer", "InitTab", {}, page, false)
return
end
local totalTransmogs = countResult:GetUInt32(0)
local hasMorePages = (totalTransmogs > SLOTS * page)
-- Query to get transmogs
local transmogQuery = string.format(
"SELECT unlocked_item_id FROM account_transmog WHERE %s LIMIT %d OFFSET %d;",
queryConditions, SLOTS, pageOffset
)
local transmogs = AuthDBQuery(transmogQuery)
if not transmogs then
AIO.Handle(player, "TransmogrificationServer", "InitTab", {}, page, false)
return
end
-- Collect the unlocked item IDs
local currentSlotItemIDs = {}
for i = 1, transmogs:GetRowCount() do
local currentRow = transmogs:GetRow()
local item = currentRow["unlocked_item_id"]
table.insert(currentSlotItemIDs, item)
transmogs:NextRow()
end
-- Return the result
AIO.Handle(player, "TransmogrificationServer", "InitTab", currentSlotItemIDs, page, hasMorePages)
end
function TransmogrificationHandler.SetEquipmentTransmogInfo(player, slot, currentSlotTooltip)
local playerGUID = player:GetGUIDLow()
local transmog = CharDBQuery("SELECT COUNT(item) FROM character_transmog WHERE player_guid = "..playerGUID.." AND slot = '"..slot.."';")
if (transmog == nil) then
return;
end
if (transmog:GetUInt32(0) ~= 0) then
AIO.Handle(player, "TransmogrificationServer", "SetEquipmentTransmogInfoClient", currentSlotTooltip)
end
end
function TransmogrificationHandler.GetItemsWithSameAppearance(player, itemID)
-- Query the server for the display ID of the new item
local displayIDQuery = "SELECT displayid FROM item_template WHERE entry = " .. itemID .. ";"
local displayIDResult = WorldDBQuery(displayIDQuery)
if not displayIDResult then
return
end
local displayID = displayIDResult:GetUInt32(0)
-- Find all items with the same display ID
local matchingItemsQuery = "SELECT entry FROM item_template WHERE displayid = " .. displayID .. ";"
local matchingItemsResult = WorldDBQuery(matchingItemsQuery)
if not matchingItemsResult then
return
end
-- Collect the matching item IDs into a table
local matchingItems = {}
for i = 1, matchingItemsResult:GetRowCount() do
local currentRow = matchingItemsResult:GetRow()
local matchingItemID = currentRow["entry"]
table.insert(matchingItems, matchingItemID)
matchingItemsResult:NextRow()
end
-- Send the matching transmogs to the client
AIO.Handle(player, "TransmogrificationServer", "ReceiveMatchingAppearances", itemID, matchingItems)
end
function TransmogrificationHandler.SendCollectedTransmogItemIDs(player)
local accountGUID = player:GetAccountId()
-- Query to retrieve collected transmog display IDs
local collectedDisplayIDsQuery = "SELECT DISTINCT display_id FROM account_transmog WHERE account_id = " .. accountGUID .. ";"
local displayIDsResult = AuthDBQuery(collectedDisplayIDsQuery)
if not displayIDsResult then
AIO.Handle(player, "TransmogrificationServer", "ReceiveCollectedAppearances", {}, 0)
return
end
-- Count the unique appearances.
local uniqueAppearancesCount = displayIDsResult:GetRowCount()
-- Collect the display IDs into a table
local collectedDisplayIDs = {}
for i = 1, displayIDsResult:GetRowCount() do
local currentRow = displayIDsResult:GetRow()
local displayID = currentRow["display_id"]
table.insert(collectedDisplayIDs, displayID)
displayIDsResult:NextRow()
end
local collectedAppearances = {}
-- For each display ID, find all items that share the appearance
for _, displayID in ipairs(collectedDisplayIDs) do
local itemsWithDisplayQuery = "SELECT entry FROM item_template WHERE displayid = " .. displayID .. ";"
local itemsResult = WorldDBQuery(itemsWithDisplayQuery)
if itemsResult then
for j = 1, itemsResult:GetRowCount() do
local itemRow = itemsResult:GetRow()
local itemID = itemRow["entry"]
table.insert(collectedAppearances, itemID)
itemsResult:NextRow()
end
end
end
-- Send the collected transmogs to the client
AIO.Handle(player, "TransmogrificationServer", "ReceiveCollectedAppearances", collectedAppearances, uniqueAppearancesCount)
end
RegisterPlayerEvent(1, Transmog_OnCharacterCreate)
RegisterPlayerEvent(2, Transmog_OnCharacterDelete)
RegisterPlayerEvent(3, Transmog_OnCharacterLogin)
RegisterPlayerEvent(29, Transmog_OnEquipItem)
RegisterPlayerEvent(30, function(event, player, bag, slot)
if bag == 255 then
TransmogrificationHandler.OnUnequipItem(player)
end
end)
if ADD_NEWLY_LOOTED_ITEMS_TO_THE_TRANSMOG_LIST then
RegisterPlayerEvent(32, Transmog_OnLootItem)
RegisterPlayerEvent(51, Transmog_OnLootItem)
RegisterPlayerEvent(52, Transmog_OnLootItem)
RegisterPlayerEvent(53, Transmog_OnLootItem)
RegisterPlayerEvent(56, Transmog_OnLootItem)
end
if ADD_QUEST_REWARD_ITEMS_TO_THE_TRANSMOG_LIST then
RegisterPlayerEvent(54, Transmog_OnQuestComplete)
end
RegisterPlayerEvent(42, function(event, player, command)
if command:lower() == "transmog sync" then
TransmogrificationHandler.SendCollectedTransmogItemIDs(player)
return false
end
return true
end)
print("[Eluna] Transmog System loaded successfully.")
+2 -2
View File
@@ -61,9 +61,9 @@
# false - (disabled)
Eluna.Enabled = true
Eluna.TraceBack = false
Eluna.TraceBack = true
Eluna.ScriptPath = "lua_scripts"
Eluna.PlayerAnnounceReload = false
Eluna.PlayerAnnounceReload = true
Eluna.RequirePaths = ""
Eluna.RequireCPaths = ""
Eluna.AutoReload = false
+27 -18
View File
@@ -23,35 +23,37 @@ FORCE_PLAYERBOTS="${FORCE_PLAYERBOTS:-${ACORE_PLAYERBOTS_FORCE:-0}}"
: "${ACORE_WORLD_CONSOLE_ENABLE:=0}"
: "${ACORE_WORLD_DBC_ENFORCE_ITEM_ATTRIBUTES:=0}"
: "${ACORE_WORLD_INSTANCE_IGNORE_RAID:=1}"
: "${ACORE_WORLD_RATE_CREATURE_ELITE_ELITE_DAMAGE:=0.80}"
: "${ACORE_WORLD_RATE_CREATURE_RARE_DAMAGE:=0.80}"
: "${ACORE_WORLD_RATE_CREATURE_RAREELITE_DAMAGE:=0.75}"
: "${ACORE_WORLD_RATE_CREATURE_ELITE_ELITE_DAMAGE:=1.00}"
: "${ACORE_WORLD_RATE_CREATURE_RARE_DAMAGE:=1.00}"
: "${ACORE_WORLD_RATE_CREATURE_RAREELITE_DAMAGE:=1.00}"
: "${ACORE_WORLD_RATE_CREATURE_WORLDBOSS_DAMAGE:=1}"
: "${ACORE_WORLD_RATE_CREATURE_ELITE_ELITE_SPELL_DAMAGE:=0.80}"
: "${ACORE_WORLD_RATE_CREATURE_RARE_SPELL_DAMAGE:=0.80}"
: "${ACORE_WORLD_RATE_CREATURE_RAREELITE_SPELL_DAMAGE:=0.75}"
: "${ACORE_WORLD_RATE_CREATURE_ELITE_ELITE_SPELL_DAMAGE:=1.00}"
: "${ACORE_WORLD_RATE_CREATURE_RARE_SPELL_DAMAGE:=1.00}"
: "${ACORE_WORLD_RATE_CREATURE_RAREELITE_SPELL_DAMAGE:=1.00}"
: "${ACORE_WORLD_RATE_CREATURE_WORLDBOSS_SPELL_DAMAGE:=1}"
: "${ACORE_WORLD_RATE_CREATURE_ELITE_ELITE_HP:=0.75}"
: "${ACORE_WORLD_RATE_CREATURE_RARE_HP:=0.70}"
: "${ACORE_WORLD_RATE_CREATURE_RAREELITE_HP:=0.65}"
: "${ACORE_WORLD_RATE_CREATURE_WORLDBOSS_HP:=1}"
: "${ACORE_AUTOBALANCE_MIN_PLAYERS:=1}"
: "${ACORE_AUTOBALANCE_MIN_PLAYERS_HEROIC:=1}"
: "${ACORE_AUTOBALANCE_MIN_PLAYERS:=2}"
: "${ACORE_AUTOBALANCE_MIN_PLAYERS_HEROIC:=2}"
: "${ACORE_AUTOBALANCE_MIN_PLAYERS_RAID:=1}"
: "${ACORE_AUTOBALANCE_MIN_PLAYERS_RAID_HEROIC:=1}"
: "${ACORE_AUTOBALANCE_STAT_MODIFIER_HEALTH:=1.30}"
: "${ACORE_AUTOBALANCE_STAT_MODIFIER_DAMAGE:=1.10}"
: "${ACORE_AUTOBALANCE_STAT_MODIFIER_BOSS_HEALTH:=1.40}"
: "${ACORE_AUTOBALANCE_STAT_MODIFIER_HEROIC_HEALTH:=1.25}"
: "${ACORE_AUTOBALANCE_STAT_MODIFIER_HEROIC_DAMAGE:=1.05}"
: "${ACORE_AUTOBALANCE_STAT_MODIFIER_HEROIC_BOSS_HEALTH:=1.35}"
: "${ACORE_AUTOBALANCE_LEVEL_SCALING_FLOOR_DUNGEONS:=1}"
: "${ACORE_AUTOBALANCE_LEVEL_SCALING_FLOOR_HEROIC_DUNGEONS:=1}"
: "${ACORE_AUTOBALANCE_STAT_MODIFIER_HEALTH:=1.55}"
: "${ACORE_AUTOBALANCE_STAT_MODIFIER_DAMAGE:=2.00}"
: "${ACORE_AUTOBALANCE_STAT_MODIFIER_BOSS_HEALTH:=2.00}"
: "${ACORE_AUTOBALANCE_STAT_MODIFIER_HEROIC_HEALTH:=1.65}"
: "${ACORE_AUTOBALANCE_STAT_MODIFIER_HEROIC_DAMAGE:=2.20}"
: "${ACORE_AUTOBALANCE_STAT_MODIFIER_HEROIC_BOSS_HEALTH:=2.20}"
: "${ACORE_AUTOBALANCE_INFLECTION_POINT_RAID:=0.75}"
: "${ACORE_AUTOBALANCE_INFLECTION_POINT_RAID_BOSS_MODIFIER:=1.35}"
: "${ACORE_AUTOBALANCE_INFLECTION_POINT_RAID_HEROIC:=0.80}"
: "${ACORE_AUTOBALANCE_INFLECTION_POINT_RAID_HEROIC_BOSS_MODIFIER:=1.45}"
: "${ACORE_AUTOBALANCE_STAT_MODIFIER_BOSS_DAMAGE:=1.00}"
: "${ACORE_AUTOBALANCE_STAT_MODIFIER_HEROIC_BOSS_DAMAGE:=0.90}"
: "${ACORE_AUTOBALANCE_STAT_MODIFIER_BOSS_DAMAGE:=2.50}"
: "${ACORE_AUTOBALANCE_STAT_MODIFIER_HEROIC_BOSS_DAMAGE:=2.80}"
: "${ACORE_AUTOBALANCE_STAT_MODIFIER_RAID_GLOBAL:=0.85}"
: "${ACORE_AUTOBALANCE_STAT_MODIFIER_RAID_DAMAGE:=0.75}"
: "${ACORE_AUTOBALANCE_STAT_MODIFIER_RAID_BOSS_HEALTH:=0.70}"
@@ -401,14 +403,21 @@ AutoBalance.MinPlayers.Heroic = ${ACORE_AUTOBALANCE_MIN_PLAYERS_HEROIC}
AutoBalance.MinPlayers.Raid = ${ACORE_AUTOBALANCE_MIN_PLAYERS_RAID}
AutoBalance.MinPlayers.RaidHeroic = ${ACORE_AUTOBALANCE_MIN_PLAYERS_RAID_HEROIC}
# Do not downscale dungeon creatures far below the highest player. The module
# default of 5 made level 38 Scarlet Monastery mobs become level 29 for a
# level 32 player, reducing their damage a second time after player scaling.
AutoBalance.LevelScaling.DynamicLevel.Floor.Dungeons = ${ACORE_AUTOBALANCE_LEVEL_SCALING_FLOOR_DUNGEONS}
AutoBalance.LevelScaling.DynamicLevel.Floor.HeroicDungeons = ${ACORE_AUTOBALANCE_LEVEL_SCALING_FLOOR_HEROIC_DUNGEONS}
# So raids scale down harder at low player counts.
AutoBalance.InflectionPointRaid = ${ACORE_AUTOBALANCE_INFLECTION_POINT_RAID}
AutoBalance.InflectionPointRaid.BossModifier = ${ACORE_AUTOBALANCE_INFLECTION_POINT_RAID_BOSS_MODIFIER}
AutoBalance.InflectionPointRaidHeroic = ${ACORE_AUTOBALANCE_INFLECTION_POINT_RAID_HEROIC}
AutoBalance.InflectionPointRaidHeroic.BossModifier = ${ACORE_AUTOBALANCE_INFLECTION_POINT_RAID_HEROIC_BOSS_MODIFIER}
# Moderate solo profile for 5-man dungeons: longer fights with a controlled
# damage increase, while keeping one-player scaling enabled.
# Medium solo profile for 5-man dungeons. A solo player is scaled against a
# two-player floor so large trash pulls are dangerous, while bosses receive
# extra health and damage to remain meaningful without requiring a full group.
AutoBalance.StatModifier.Health = ${ACORE_AUTOBALANCE_STAT_MODIFIER_HEALTH}
AutoBalance.StatModifier.Damage = ${ACORE_AUTOBALANCE_STAT_MODIFIER_DAMAGE}
AutoBalance.StatModifier.Boss.Health = ${ACORE_AUTOBALANCE_STAT_MODIFIER_BOSS_HEALTH}
+380
View File
@@ -0,0 +1,380 @@
-- Create Squire NPC
INSERT
INTO
acore_world.creature_template (entry,
difficulty_entry_1,
difficulty_entry_2,
difficulty_entry_3,
KillCredit1,
KillCredit2,
name,
subname,
IconName,
gossip_menu_id,
minlevel,
maxlevel,
`exp`,
faction,
npcflag,
speed_walk,
speed_run,
speed_swim,
speed_flight,
detection_range,
`rank`,
dmgschool,
DamageModifier,
BaseAttackTime,
RangeAttackTime,
BaseVariance,
RangeVariance,
unit_class,
unit_flags,
unit_flags2,
dynamicflags,
family,
`type`,
type_flags,
lootid,
pickpocketloot,
skinloot,
PetSpellDataId,
VehicleId,
mingold,
maxgold,
AIName,
MovementType,
HoverHeight,
HealthModifier,
ManaModifier,
ArmorModifier,
ExperienceModifier,
RacialLeader,
movementId,
RegenHealth,
mechanic_immune_mask,
spell_school_immune_mask,
flags_extra,
ScriptName,
VerifiedBuild)
VALUES
(9000001,
29831,
0,
0,
0,
0,
'Eluna Squire',
'',
'',
0,
81,
81,
2,
21,
1,
1.0,
1.42857,
1.0,
1.0,
20.0,
1,
0,
7.5,
2000,
2000,
1.0,
1.0,
1,
64,
2048,
8,
0,
6,
72,
100003,
0,
0,
0,
0,
1163,
1524,
'SmartAI',
0,
1.0,
4.0,
1.0,
1.0,
2.5,
0,
144,
1,
1007366674,
0,
0,
'',
12340) ON DUPLICATE KEY UPDATE entry = entry;
-- Add Squire localization
INSERT INTO
acore_world.creature_template_locale (entry,
locale,
Name,
Title,
VerifiedBuild)
VALUES
(9000001,
'ruRU',
'Оруженосец',
'',
12340) ON DUPLICATE KEY UPDATE entry = entry;
-- Add Squire model
INSERT
INTO
acore_world.creature_template_model (CreatureID,
Idx,
CreatureDisplayID,
DisplayScale,
Probability,
VerifiedBuild)
VALUES
(9000001,
0,
16927,
1.0,
1.0,
12340) ON
DUPLICATE KEY
UPDATE
CreatureID = CreatureID;
-- Add Squire dialogue text
INSERT
INTO
acore_world.npc_text (ID,
text0_0,
text0_1,
BroadcastTextID0,
lang0,
Probability0,
em0_0,
em0_1,
em0_2,
em0_3,
em0_4,
em0_5,
text1_0,
text1_1,
BroadcastTextID1,
lang1,
Probability1,
em1_0,
em1_1,
em1_2,
em1_3,
em1_4,
em1_5,
text2_0,
text2_1,
BroadcastTextID2,
lang2,
Probability2,
em2_0,
em2_1,
em2_2,
em2_3,
em2_4,
em2_5,
text3_0,
text3_1,
BroadcastTextID3,
lang3,
Probability3,
em3_0,
em3_1,
em3_2,
em3_3,
em3_4,
em3_5,
text4_0,
text4_1,
BroadcastTextID4,
lang4,
Probability4,
em4_0,
em4_1,
em4_2,
em4_3,
em4_4,
em4_5,
text5_0,
text5_1,
BroadcastTextID5,
lang5,
Probability5,
em5_0,
em5_1,
em5_2,
em5_3,
em5_4,
em5_5,
text6_0,
text6_1,
BroadcastTextID6,
lang6,
Probability6,
em6_0,
em6_1,
em6_2,
em6_3,
em6_4,
em6_5,
text7_0,
text7_1,
BroadcastTextID7,
lang7,
Probability7,
em7_0,
em7_1,
em7_2,
em7_3,
em7_4,
em7_5,
VerifiedBuild)
VALUES
(10000000,
'',
'By the grace of the stars, I have been bound to your side, $n. This ancient pile of bones is ready to serve you.',
0,
0,
0.0,
0,
0,
0,
0,
0,
0,
'',
'',
0,
0,
0.0,
0,
0,
0,
0,
0,
0,
'',
'',
0,
0,
0.0,
0,
0,
0,
0,
0,
0,
'',
'',
0,
0,
0.0,
0,
0,
0,
0,
0,
0,
'',
'',
0,
0,
0.0,
0,
0,
0,
0,
0,
0,
'',
'',
0,
0,
0.0,
0,
0,
0,
0,
0,
0,
'',
'',
0,
0,
0.0,
0,
0,
0,
0,
0,
0,
'',
'',
0,
0,
0.0,
0,
0,
0,
0,
0,
0,
0) ON DUPLICATE KEY UPDATE ID = ID;
-- Add squire dialogue text locale
INSERT
INTO
acore_world.npc_text_locale (ID,
Locale,
Text0_0,
Text0_1,
Text1_0,
Text1_1,
Text2_0,
Text2_1,
Text3_0,
Text3_1,
Text4_0,
Text4_1,
Text5_0,
Text5_1,
Text6_0,
Text6_1,
Text7_0,
Text7_1)
VALUES
(10000000,
'ruRU',
'',
'Милостью высших сил я был приставлен к тебе, $n. Эти древние кости готовы служить. Чего желаешь?',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'') ON DUPLICATE KEY UPDATE ID = ID;
+35
View File
@@ -0,0 +1,35 @@
-- --------------------------------------------------------
-- Host: 192.168.0.167
-- Server-Version: 8.3.0 - MySQL Community Server - GPL
-- Server-Betriebssystem: Linux
-- HeidiSQL Version: 12.8.0.6908
-- --------------------------------------------------------
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!50503 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!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' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
-- Exportiere Struktur von Tabelle acore_auth.account_transmog
CREATE TABLE IF NOT EXISTS `account_transmog` (
`account_id` int unsigned NOT NULL,
`unlocked_item_id` int unsigned NOT NULL,
`inventory_type` int unsigned DEFAULT NULL,
`inventory_subtype` int unsigned DEFAULT NULL,
`display_id` int unsigned NOT NULL,
`item_name` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
UNIQUE KEY `account_item_id` (`account_id`,`unlocked_item_id`) USING BTREE,
UNIQUE KEY `account_display_id` (`account_id`,`display_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- Daten-Export vom Benutzer nicht ausgewählt
/*!40103 SET TIME_ZONE=IFNULL(@OLD_TIME_ZONE, 'system') */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */;
+33
View File
@@ -0,0 +1,33 @@
-- --------------------------------------------------------
-- Host: 192.168.0.167
-- Server-Version: 8.3.0 - MySQL Community Server - GPL
-- Server-Betriebssystem: Linux
-- HeidiSQL Version: 12.8.0.6908
-- --------------------------------------------------------
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!50503 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!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' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
-- Exportiere Struktur von Tabelle acore_characters.character_transmog
CREATE TABLE IF NOT EXISTS `character_transmog` (
`player_guid` int unsigned DEFAULT NULL,
`slot` varchar(3) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`item` int unsigned DEFAULT NULL,
`real_item` int unsigned DEFAULT NULL,
UNIQUE KEY `player_and_slot` (`player_guid`,`slot`) USING BTREE,
KEY `player_and_slot_key` (`player_guid`,`slot`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- Daten-Export vom Benutzer nicht ausgewählt
/*!40103 SET TIME_ZONE=IFNULL(@OLD_TIME_ZONE, 'system') */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */;