First version of Transmog Module for AC

This commit is contained in:
Yehonal
2016-11-17 10:25:43 +01:00
commit e341965797
17 changed files with 1943 additions and 0 deletions

8
src/CMakeLists.txt Normal file
View File

@@ -0,0 +1,8 @@
CU_SET_PATH("CMAKE_TRANSM_SRC_DIR" "${CMAKE_CURRENT_LIST_DIR}")
AC_ADD_SCRIPT("${CMAKE_TRANSM_SRC_DIR}/transmog_scripts.cpp")
AC_ADD_SCRIPT("${CMAKE_TRANSM_SRC_DIR}/Transmogrification.cpp")
CU_ADD_HOOK(AFTER_WORLDSERVER_CMAKE "${CMAKE_TRANSM_SRC_DIR}/cmake/after_ws.cmake")
AC_ADD_SCRIPT_LOADER("Transmog" "${CMAKE_TRANSM_SRC_DIR}/transmog_scripts_loader.h")

716
src/Transmogrification.cpp Normal file
View File

@@ -0,0 +1,716 @@
#include "Transmogrification.h"
#ifdef PRESETS
void Transmogrification::PresetTransmog(Player* player, Item* itemTransmogrified, uint32 fakeEntry, uint8 slot)
{
sLog->outDebug(LOG_FILTER_MODULES, "Transmogrification::PresetTransmog");
if (!EnableSets)
return;
if (!player || !itemTransmogrified)
return;
if (slot >= EQUIPMENT_SLOT_END)
return;
if (!CanTransmogrifyItemWithItem(player, itemTransmogrified->GetTemplate(), sObjectMgr->GetItemTemplate(fakeEntry)))
return;
// [AZTH] Custom
if (GetFakeEntry(itemTransmogrified->GetGUID()))
DeleteFakeEntry(player, slot, itemTransmogrified);
SetFakeEntry(player, fakeEntry, slot, itemTransmogrified); // newEntry
itemTransmogrified->UpdatePlayedTime(player);
itemTransmogrified->SetOwnerGUID(player->GetGUID());
itemTransmogrified->SetNotRefundable(player);
itemTransmogrified->ClearSoulboundTradeable(player);
}
void Transmogrification::LoadPlayerSets(uint64 pGUID)
{
sLog->outDebug(LOG_FILTER_MODULES, "Transmogrification::LoadPlayerSets");
for (presetData::iterator it = presetById[pGUID].begin(); it != presetById[pGUID].end(); ++it)
it->second.clear();
presetById[pGUID].clear();
presetByName[pGUID].clear();
QueryResult result = CharacterDatabase.PQuery("SELECT `PresetID`, `SetName`, `SetData` FROM `custom_transmogrification_sets` WHERE Owner = %u", GUID_LOPART(pGUID));
if (result)
{
do
{
uint8 PresetID = (*result)[0].GetUInt8();
std::string SetName = (*result)[1].GetString();
std::istringstream SetData((*result)[2].GetString());
while (SetData.good())
{
uint32 slot;
uint32 entry;
SetData >> slot >> entry;
if (SetData.fail())
break;
if (slot >= EQUIPMENT_SLOT_END)
{
sLog->outError("Item entry (FakeEntry: %u, playerGUID: %u, slot: %u, presetId: %u) has invalid slot, ignoring.", entry, GUID_LOPART(pGUID), slot, uint32(PresetID));
continue;
}
if (sObjectMgr->GetItemTemplate(entry))
presetById[pGUID][PresetID][slot] = entry; // Transmogrification::Preset(presetName, fakeEntry);
//else
//sLog->outError(LOG_FILTER_SQL, "Item entry (FakeEntry: %u, playerGUID: %u, slot: %u, presetId: %u) does not exist, ignoring.", entry, GUID_LOPART(pGUID), uint32(slot), uint32(PresetID));
}
if (!presetById[pGUID][PresetID].empty())
{
presetByName[pGUID][PresetID] = SetName;
// load all presets anyways
//if (presetByName[pGUID].size() >= GetMaxSets())
// break;
}
else // should be deleted on startup, so this never runs (shouldnt..)
{
presetById[pGUID].erase(PresetID);
CharacterDatabase.PExecute("DELETE FROM `custom_transmogrification_sets` WHERE Owner = %u AND PresetID = %u", GUID_LOPART(pGUID), PresetID);
}
} while (result->NextRow());
}
}
bool Transmogrification::GetEnableSets() const
{
return EnableSets;
}
uint8 Transmogrification::GetMaxSets() const
{
return MaxSets;
}
float Transmogrification::GetSetCostModifier() const
{
return SetCostModifier;
}
int32 Transmogrification::GetSetCopperCost() const
{
return SetCopperCost;
}
void Transmogrification::UnloadPlayerSets(uint64 pGUID)
{
for (presetData::iterator it = presetById[pGUID].begin(); it != presetById[pGUID].end(); ++it)
it->second.clear();
presetById[pGUID].clear();
presetByName[pGUID].clear();
}
#endif
const char* Transmogrification::GetSlotName(uint8 slot, WorldSession* /*session*/) const
{
sLog->outDebug(LOG_FILTER_MODULES, "Transmogrification::GetSlotName");
switch (slot)
{
case EQUIPMENT_SLOT_HEAD: return "Head";// session->GetTrinityString(LANG_SLOT_NAME_HEAD);
case EQUIPMENT_SLOT_SHOULDERS: return "Shoulders";// session->GetTrinityString(LANG_SLOT_NAME_SHOULDERS);
case EQUIPMENT_SLOT_BODY: return "Shirt";// session->GetTrinityString(LANG_SLOT_NAME_BODY);
case EQUIPMENT_SLOT_CHEST: return "Chest";// session->GetTrinityString(LANG_SLOT_NAME_CHEST);
case EQUIPMENT_SLOT_WAIST: return "Waist";// session->GetTrinityString(LANG_SLOT_NAME_WAIST);
case EQUIPMENT_SLOT_LEGS: return "Legs";// session->GetTrinityString(LANG_SLOT_NAME_LEGS);
case EQUIPMENT_SLOT_FEET: return "Feet";// session->GetTrinityString(LANG_SLOT_NAME_FEET);
case EQUIPMENT_SLOT_WRISTS: return "Wrists";// session->GetTrinityString(LANG_SLOT_NAME_WRISTS);
case EQUIPMENT_SLOT_HANDS: return "Hands";// session->GetTrinityString(LANG_SLOT_NAME_HANDS);
case EQUIPMENT_SLOT_BACK: return "Back";// session->GetTrinityString(LANG_SLOT_NAME_BACK);
case EQUIPMENT_SLOT_MAINHAND: return "Main hand";// session->GetTrinityString(LANG_SLOT_NAME_MAINHAND);
case EQUIPMENT_SLOT_OFFHAND: return "Off hand";// session->GetTrinityString(LANG_SLOT_NAME_OFFHAND);
case EQUIPMENT_SLOT_RANGED: return "Ranged";// session->GetTrinityString(LANG_SLOT_NAME_RANGED);
case EQUIPMENT_SLOT_TABARD: return "Tabard";// session->GetTrinityString(LANG_SLOT_NAME_TABARD);
default: return NULL;
}
}
std::string Transmogrification::GetItemIcon(uint32 entry, uint32 width, uint32 height, int x, int y) const
{
sLog->outDebug(LOG_FILTER_MODULES, "Transmogrification::GetItemIcon");
std::ostringstream ss;
ss << "|TInterface";
const ItemTemplate* temp = sObjectMgr->GetItemTemplate(entry);
const ItemDisplayInfoEntry* dispInfo = NULL;
if (temp)
{
dispInfo = sItemDisplayInfoStore.LookupEntry(temp->DisplayInfoID);
if (dispInfo)
ss << "/ICONS/" << dispInfo->inventoryIcon;
}
if (!dispInfo)
ss << "/InventoryItems/WoWUnknownItem01";
ss << ":" << width << ":" << height << ":" << x << ":" << y << "|t";
return ss.str();
}
std::string Transmogrification::GetSlotIcon(uint8 slot, uint32 width, uint32 height, int x, int y) const
{
sLog->outDebug(LOG_FILTER_MODULES, "Transmogrification::GetSlotIcon");
std::ostringstream ss;
ss << "|TInterface/PaperDoll/";
switch (slot)
{
case EQUIPMENT_SLOT_HEAD: ss << "UI-PaperDoll-Slot-Head"; break;
case EQUIPMENT_SLOT_SHOULDERS: ss << "UI-PaperDoll-Slot-Shoulder"; break;
case EQUIPMENT_SLOT_BODY: ss << "UI-PaperDoll-Slot-Shirt"; break;
case EQUIPMENT_SLOT_CHEST: ss << "UI-PaperDoll-Slot-Chest"; break;
case EQUIPMENT_SLOT_WAIST: ss << "UI-PaperDoll-Slot-Waist"; break;
case EQUIPMENT_SLOT_LEGS: ss << "UI-PaperDoll-Slot-Legs"; break;
case EQUIPMENT_SLOT_FEET: ss << "UI-PaperDoll-Slot-Feet"; break;
case EQUIPMENT_SLOT_WRISTS: ss << "UI-PaperDoll-Slot-Wrists"; break;
case EQUIPMENT_SLOT_HANDS: ss << "UI-PaperDoll-Slot-Hands"; break;
case EQUIPMENT_SLOT_BACK: ss << "UI-PaperDoll-Slot-Chest"; break;
case EQUIPMENT_SLOT_MAINHAND: ss << "UI-PaperDoll-Slot-MainHand"; break;
case EQUIPMENT_SLOT_OFFHAND: ss << "UI-PaperDoll-Slot-SecondaryHand"; break;
case EQUIPMENT_SLOT_RANGED: ss << "UI-PaperDoll-Slot-Ranged"; break;
case EQUIPMENT_SLOT_TABARD: ss << "UI-PaperDoll-Slot-Tabard"; break;
default: ss << "UI-Backpack-EmptySlot";
}
ss << ":" << width << ":" << height << ":" << x << ":" << y << "|t";
return ss.str();
}
std::string Transmogrification::GetItemLink(Item* item, WorldSession* session) const
{
sLog->outDebug(LOG_FILTER_MODULES, "Transmogrification::GetItemLink");
int loc_idx = session->GetSessionDbLocaleIndex();
const ItemTemplate* temp = item->GetTemplate();
std::string name = temp->Name1;
if (ItemLocale const* il = sObjectMgr->GetItemLocale(temp->ItemId))
ObjectMgr::GetLocaleString(il->Name, loc_idx, name);
if (int32 itemRandPropId = item->GetItemRandomPropertyId())
{
char* const* suffix = NULL;
if (itemRandPropId < 0)
{
const ItemRandomSuffixEntry* itemRandEntry = sItemRandomSuffixStore.LookupEntry(-item->GetItemRandomPropertyId());
if (itemRandEntry)
suffix = itemRandEntry->nameSuffix;
}
else
{
const ItemRandomPropertiesEntry* itemRandEntry = sItemRandomPropertiesStore.LookupEntry(item->GetItemRandomPropertyId());
if (itemRandEntry)
suffix = itemRandEntry->nameSuffix;
}
if (suffix)
{
std::string test(suffix[(name != temp->Name1) ? loc_idx : DEFAULT_LOCALE]);
if (!test.empty())
{
name += ' ';
name += test;
}
}
}
std::ostringstream oss;
oss << "|c" << std::hex << ItemQualityColors[temp->Quality] << std::dec <<
"|Hitem:" << temp->ItemId << ":" <<
item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT) << ":" <<
item->GetEnchantmentId(SOCK_ENCHANTMENT_SLOT) << ":" <<
item->GetEnchantmentId(SOCK_ENCHANTMENT_SLOT_2) << ":" <<
item->GetEnchantmentId(SOCK_ENCHANTMENT_SLOT_3) << ":" <<
item->GetEnchantmentId(BONUS_ENCHANTMENT_SLOT) << ":" <<
item->GetItemRandomPropertyId() << ":" << item->GetItemSuffixFactor() << ":" <<
(uint32)item->GetOwner()->getLevel() << "|h[" << name << "]|h|r";
return oss.str();
}
std::string Transmogrification::GetItemLink(uint32 entry, WorldSession* session) const
{
sLog->outDebug(LOG_FILTER_MODULES, "Transmogrification::GetItemLink");
const ItemTemplate* temp = sObjectMgr->GetItemTemplate(entry);
int loc_idx = session->GetSessionDbLocaleIndex();
std::string name = temp->Name1;
if (ItemLocale const* il = sObjectMgr->GetItemLocale(entry))
ObjectMgr::GetLocaleString(il->Name, loc_idx, name);
std::ostringstream oss;
oss << "|c" << std::hex << ItemQualityColors[temp->Quality] << std::dec <<
"|Hitem:" << entry << ":0:0:0:0:0:0:0:0:0|h[" << name << "]|h|r";
return oss.str();
}
uint32 Transmogrification::GetFakeEntry(uint64 itemGUID) const
{
sLog->outDebug(LOG_FILTER_MODULES, "Transmogrification::GetFakeEntry");
transmogData::const_iterator itr = dataMap.find(itemGUID);
if (itr == dataMap.end()) return 0;
transmogMap::const_iterator itr2 = entryMap.find(itr->second);
if (itr2 == entryMap.end()) return 0;
transmogData::const_iterator itr3 = itr2->second.find(itemGUID);
if (itr3 == itr2->second.end()) return 0;
return itr3->second;
}
void Transmogrification::UpdateItem(Player* player, Item* item) const
{
sLog->outDebug(LOG_FILTER_MODULES, "Transmogrification::UpdateItem");
if (item->IsEquipped())
{
player->SetVisibleItemSlot(item->GetSlot(), item);
if (player->IsInWorld())
item->SendUpdateToPlayer(player);
}
}
void Transmogrification::DeleteFakeEntry(Player* player, uint8 slot, Item* itemTransmogrified, SQLTransaction* trans)
{
//if (!GetFakeEntry(item))
// return false;
DeleteFakeFromDB(itemTransmogrified->GetGUID(), trans);
UpdateItem(player, itemTransmogrified);
}
void Transmogrification::SetFakeEntry(Player* player, uint32 newEntry, uint8 slot, Item* itemTransmogrified)
{
uint64 itemGUID = itemTransmogrified->GetGUID();
entryMap[player->GetGUID()][itemGUID] = newEntry;
dataMap[itemGUID] = player->GetGUID();
CharacterDatabase.PExecute("REPLACE INTO custom_transmogrification (GUID, FakeEntry, Owner) VALUES (%u, %u, %u)", GUID_LOPART(itemGUID), newEntry, player->GetGUIDLow());
UpdateItem(player, itemTransmogrified);
}
TransmogTrinityStrings Transmogrification::Transmogrify(Player* player, uint64 itemGUID, uint8 slot, /*uint32 newEntry, */bool no_cost)
{
int32 cost = 0;
// slot of the transmogrified item
if (slot >= EQUIPMENT_SLOT_END)
{
// TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) tried to transmogrify an item (lowguid: %u) with a wrong slot (%u) when transmogrifying items.", player->GetGUIDLow(), player->GetName().c_str(), GUID_LOPART(itemGUID), slot);
return LANG_ERR_TRANSMOG_INVALID_SLOT;
}
Item* itemTransmogrifier = NULL;
// guid of the transmogrifier item, if it's not 0
if (itemGUID)
{
itemTransmogrifier = player->GetItemByGuid(itemGUID);
if (!itemTransmogrifier)
{
//TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) tried to transmogrify with an invalid item (lowguid: %u).", player->GetGUIDLow(), player->GetName().c_str(), GUID_LOPART(itemGUID));
return LANG_ERR_TRANSMOG_MISSING_SRC_ITEM;
}
}
// transmogrified item
Item* itemTransmogrified = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
if (!itemTransmogrified)
{
//TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) tried to transmogrify an invalid item in a valid slot (slot: %u).", player->GetGUIDLow(), player->GetName().c_str(), slot);
return LANG_ERR_TRANSMOG_MISSING_DEST_ITEM;
}
if (!itemTransmogrifier) // reset look newEntry
{
// Custom
DeleteFakeEntry(player, slot, itemTransmogrified);
}
else
{
if (!CanTransmogrifyItemWithItem(player, itemTransmogrified->GetTemplate(), itemTransmogrifier->GetTemplate()))
{
//TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) failed CanTransmogrifyItemWithItem (%u with %u).", player->GetGUIDLow(), player->GetName().c_str(), itemTransmogrified->GetEntry(), itemTransmogrifier->GetEntry());
return LANG_ERR_TRANSMOG_INVALID_ITEMS;
}
if (!no_cost)
{
if (RequireToken)
{
if (player->HasItemCount(TokenEntry, TokenAmount))
player->DestroyItemCount(TokenEntry, TokenAmount, true);
else
return LANG_ERR_TRANSMOG_NOT_ENOUGH_TOKENS;
}
cost = GetSpecialPrice(itemTransmogrified->GetTemplate());
cost *= ScaledCostModifier;
cost += CopperCost;
if (cost) // 0 cost if reverting look
{
if (cost < 0)
sLog->outDebug(LOG_FILTER_MODULES, "Transmogrification::Transmogrify - %s (%u) transmogrification invalid cost (non negative, amount %i). Transmogrified %u with %u", player->GetName().c_str(), player->GetGUIDLow(), -cost, itemTransmogrified->GetEntry(), itemTransmogrifier->GetEntry());
else
{
if (!player->HasEnoughMoney(cost))
return LANG_ERR_TRANSMOG_NOT_ENOUGH_MONEY;
player->ModifyMoney(-cost, false);
}
}
}
// Custom
SetFakeEntry(player, itemTransmogrifier->GetEntry(), slot, itemTransmogrified); // newEntry
itemTransmogrified->UpdatePlayedTime(player);
itemTransmogrified->SetOwnerGUID(player->GetGUID());
itemTransmogrified->SetNotRefundable(player);
itemTransmogrified->ClearSoulboundTradeable(player);
if (itemTransmogrifier->GetTemplate()->Bonding == BIND_WHEN_EQUIPED || itemTransmogrifier->GetTemplate()->Bonding == BIND_WHEN_USE)
itemTransmogrifier->SetBinding(true);
itemTransmogrifier->SetOwnerGUID(player->GetGUID());
itemTransmogrifier->SetNotRefundable(player);
itemTransmogrifier->ClearSoulboundTradeable(player);
}
// trusting the client, if it got here it has to have enough money
// ... unless client was modified
if (cost) // 0 cost if reverting look
player->ModifyMoney(-1 * cost, false);
return LANG_ERR_TRANSMOG_OK;
}
bool Transmogrification::CanTransmogrifyItemWithItem(Player* player, ItemTemplate const* target, ItemTemplate const* source) const
{
if (!target || !source)
return false;
if (source->ItemId == target->ItemId)
return false;
if (source->DisplayInfoID == target->DisplayInfoID)
return false;
if (source->Class != target->Class)
return false;
if (source->InventoryType == INVTYPE_BAG ||
source->InventoryType == INVTYPE_RELIC ||
// source->InventoryType == INVTYPE_BODY ||
source->InventoryType == INVTYPE_FINGER ||
source->InventoryType == INVTYPE_TRINKET ||
source->InventoryType == INVTYPE_AMMO ||
source->InventoryType == INVTYPE_QUIVER)
return false;
if (target->InventoryType == INVTYPE_BAG ||
target->InventoryType == INVTYPE_RELIC ||
// target->InventoryType == INVTYPE_BODY ||
target->InventoryType == INVTYPE_FINGER ||
target->InventoryType == INVTYPE_TRINKET ||
target->InventoryType == INVTYPE_AMMO ||
target->InventoryType == INVTYPE_QUIVER)
return false;
if (!SuitableForTransmogrification(player, target) || !SuitableForTransmogrification(player, source)) // if (!transmogrified->CanTransmogrify() || !transmogrifier->CanBeTransmogrified())
return false;
if (IsRangedWeapon(source->Class, source->SubClass) != IsRangedWeapon(target->Class, target->SubClass))
return false;
if (source->SubClass != target->SubClass && !IsRangedWeapon(target->Class, target->SubClass))
{
if (source->Class == ITEM_CLASS_ARMOR && !AllowMixedArmorTypes)
return false;
if (source->Class == ITEM_CLASS_WEAPON && !AllowMixedWeaponTypes)
return false;
}
if (source->InventoryType != target->InventoryType)
{
if (source->Class == ITEM_CLASS_WEAPON && !(IsRangedWeapon(target->Class, target->SubClass) ||
(
// [AZTH] Yehonal: fixed weapon check
(target->InventoryType == INVTYPE_WEAPON || target->InventoryType == INVTYPE_2HWEAPON || target->InventoryType == INVTYPE_WEAPONMAINHAND || target->InventoryType == INVTYPE_WEAPONOFFHAND)
&& (source->InventoryType == INVTYPE_WEAPON || source->InventoryType == INVTYPE_2HWEAPON || source->InventoryType == INVTYPE_WEAPONMAINHAND || source->InventoryType == INVTYPE_WEAPONOFFHAND)
)
))
return false;
if (source->Class == ITEM_CLASS_ARMOR &&
!((source->InventoryType == INVTYPE_CHEST || source->InventoryType == INVTYPE_ROBE) &&
(target->InventoryType == INVTYPE_CHEST || target->InventoryType == INVTYPE_ROBE)))
return false;
}
return true;
}
bool Transmogrification::SuitableForTransmogrification(Player* player, ItemTemplate const* proto) const
{
// ItemTemplate const* proto = item->GetTemplate();
if (!player || !proto)
return false;
if (proto->Class != ITEM_CLASS_ARMOR &&
proto->Class != ITEM_CLASS_WEAPON)
return false;
// Skip all checks for allowed items
if (IsAllowed(proto->ItemId))
return true;
//[AZTH] Yehonal
if (/*TODO: conf here*/ proto->SubClass>0 && player->GetSkillValue(proto->GetSkill()) == 0)
return false;
if (IsNotAllowed(proto->ItemId))
return false;
if (!AllowFishingPoles && proto->Class == ITEM_CLASS_WEAPON && proto->SubClass == ITEM_SUBCLASS_WEAPON_FISHING_POLE)
return false;
if (!IsAllowedQuality(proto->Quality)) // (proto->Quality == ITEM_QUALITY_LEGENDARY)
return false;
if ((proto->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY) && player->GetTeamId() != TEAM_HORDE)
return false;
if ((proto->Flags2 & ITEM_FLAGS_EXTRA_ALLIANCE_ONLY) && player->GetTeamId() != TEAM_ALLIANCE)
return false;
if (!IgnoreReqClass && (proto->AllowableClass & player->getClassMask()) == 0)
return false;
if (!IgnoreReqRace && (proto->AllowableRace & player->getRaceMask()) == 0)
return false;
if (!IgnoreReqSkill && proto->RequiredSkill != 0)
{
if (player->GetSkillValue(proto->RequiredSkill) == 0)
return false;
else if (player->GetSkillValue(proto->RequiredSkill) < proto->RequiredSkillRank)
return false;
}
if (!IgnoreReqSpell && proto->RequiredSpell != 0 && !player->HasSpell(proto->RequiredSpell))
return false;
if (!IgnoreReqLevel && player->getLevel() < proto->RequiredLevel)
return false;
// If World Event is not active, prevent using event dependant items
if (!IgnoreReqEvent && proto->HolidayId && !IsHolidayActive((HolidayIds)proto->HolidayId))
return false;
if (!IgnoreReqStats)
{
if (!proto->RandomProperty && !proto->RandomSuffix
/*[AZTH] Yehonal: we should transmorg also items without stats*/
&& proto->StatsCount > 0)
{
bool found = false;
for (uint8 i = 0; i < proto->StatsCount; ++i)
{
if (proto->ItemStat[i].ItemStatValue != 0)
{
found = true;
break;
}
}
if (!found)
return false;
}
}
return true;
}
uint32 Transmogrification::GetSpecialPrice(ItemTemplate const* proto) const
{
uint32 cost = proto->SellPrice < 10000 ? 10000 : proto->SellPrice;
return cost;
}
bool Transmogrification::IsRangedWeapon(uint32 Class, uint32 SubClass) const
{
return Class == ITEM_CLASS_WEAPON && (
SubClass == ITEM_SUBCLASS_WEAPON_BOW ||
SubClass == ITEM_SUBCLASS_WEAPON_GUN ||
SubClass == ITEM_SUBCLASS_WEAPON_CROSSBOW);
}
bool Transmogrification::IsAllowed(uint32 entry) const
{
return Allowed.find(entry) != Allowed.end();
}
bool Transmogrification::IsNotAllowed(uint32 entry) const
{
return NotAllowed.find(entry) != NotAllowed.end();
}
bool Transmogrification::IsAllowedQuality(uint32 quality) const
{
switch (quality)
{
case ITEM_QUALITY_POOR: return AllowPoor;
case ITEM_QUALITY_NORMAL: return AllowCommon;
case ITEM_QUALITY_UNCOMMON: return AllowUncommon;
case ITEM_QUALITY_RARE: return AllowRare;
case ITEM_QUALITY_EPIC: return AllowEpic;
case ITEM_QUALITY_LEGENDARY: return AllowLegendary;
case ITEM_QUALITY_ARTIFACT: return AllowArtifact;
case ITEM_QUALITY_HEIRLOOM: return AllowHeirloom;
default: return false;
}
}
void Transmogrification::LoadConfig(bool reload)
{
#ifdef PRESETS
EnableSetInfo = sConfigMgr->GetBoolDefault("Transmogrification.EnableSetInfo", true);
SetNpcText = uint32(sConfigMgr->GetIntDefault("Transmogrification.SetNpcText", 50001));
EnableSets = sConfigMgr->GetBoolDefault("Transmogrification.EnableSets", true);
MaxSets = (uint8)sConfigMgr->GetIntDefault("Transmogrification.MaxSets", 10);
SetCostModifier = sConfigMgr->GetFloatDefault("Transmogrification.SetCostModifier", 3.0f);
SetCopperCost = sConfigMgr->GetIntDefault("Transmogrification.SetCopperCost", 0);
if (MaxSets > MAX_OPTIONS)
MaxSets = MAX_OPTIONS;
if (reload) // dont store presets for nothing
{
SessionMap const& sessions = sWorld->GetAllSessions();
for (SessionMap::const_iterator it = sessions.begin(); it != sessions.end(); ++it)
{
if (Player* player = it->second->GetPlayer())
{
// skipping session check
UnloadPlayerSets(player->GetGUID());
if (GetEnableSets())
LoadPlayerSets(player->GetGUID());
}
}
}
#endif
EnableTransmogInfo = sConfigMgr->GetBoolDefault("Transmogrification.EnableTransmogInfo", true);
TransmogNpcText = uint32(sConfigMgr->GetIntDefault("Transmogrification.TransmogNpcText", 50000));
std::istringstream issAllowed(sConfigMgr->GetStringDefault("Transmogrification.Allowed", ""));
std::istringstream issNotAllowed(sConfigMgr->GetStringDefault("Transmogrification.NotAllowed", ""));
while (issAllowed.good())
{
uint32 entry;
issAllowed >> entry;
if (issAllowed.fail())
break;
Allowed.insert(entry);
}
while (issNotAllowed.good())
{
uint32 entry;
issNotAllowed >> entry;
if (issNotAllowed.fail())
break;
NotAllowed.insert(entry);
}
ScaledCostModifier = sConfigMgr->GetFloatDefault("Transmogrification.ScaledCostModifier", 1.0f);
CopperCost = sConfigMgr->GetIntDefault("Transmogrification.CopperCost", 0);
RequireToken = sConfigMgr->GetBoolDefault("Transmogrification.RequireToken", false);
TokenEntry = uint32(sConfigMgr->GetIntDefault("Transmogrification.TokenEntry", 49426));
TokenAmount = uint32(sConfigMgr->GetIntDefault("Transmogrification.TokenAmount", 1));
AllowPoor = sConfigMgr->GetBoolDefault("Transmogrification.AllowPoor", false);
AllowCommon = sConfigMgr->GetBoolDefault("Transmogrification.AllowCommon", false);
AllowUncommon = sConfigMgr->GetBoolDefault("Transmogrification.AllowUncommon", true);
AllowRare = sConfigMgr->GetBoolDefault("Transmogrification.AllowRare", true);
AllowEpic = sConfigMgr->GetBoolDefault("Transmogrification.AllowEpic", true);
AllowLegendary = sConfigMgr->GetBoolDefault("Transmogrification.AllowLegendary", false);
AllowArtifact = sConfigMgr->GetBoolDefault("Transmogrification.AllowArtifact", false);
AllowHeirloom = sConfigMgr->GetBoolDefault("Transmogrification.AllowHeirloom", true);
AllowMixedArmorTypes = sConfigMgr->GetBoolDefault("Transmogrification.AllowMixedArmorTypes", false);
AllowMixedWeaponTypes = sConfigMgr->GetBoolDefault("Transmogrification.AllowMixedWeaponTypes", false);
AllowFishingPoles = sConfigMgr->GetBoolDefault("Transmogrification.AllowFishingPoles", false);
IgnoreReqRace = sConfigMgr->GetBoolDefault("Transmogrification.IgnoreReqRace", false);
IgnoreReqClass = sConfigMgr->GetBoolDefault("Transmogrification.IgnoreReqClass", false);
IgnoreReqSkill = sConfigMgr->GetBoolDefault("Transmogrification.IgnoreReqSkill", false);
IgnoreReqSpell = sConfigMgr->GetBoolDefault("Transmogrification.IgnoreReqSpell", false);
IgnoreReqLevel = sConfigMgr->GetBoolDefault("Transmogrification.IgnoreReqLevel", false);
IgnoreReqEvent = sConfigMgr->GetBoolDefault("Transmogrification.IgnoreReqEvent", false);
IgnoreReqStats = sConfigMgr->GetBoolDefault("Transmogrification.IgnoreReqStats", false);
if (!sObjectMgr->GetItemTemplate(TokenEntry))
{
//sLog->outError(LOG_FILTER_SERVER_LOADING, "Transmogrification.TokenEntry (%u) does not exist. Using default.", TokenEntry);
TokenEntry = 49426;
}
}
void Transmogrification::DeleteFakeFromDB(uint64 itemGUID, SQLTransaction* trans)
{
if (dataMap.find(itemGUID) != dataMap.end())
{
if (entryMap.find(dataMap[itemGUID]) != entryMap.end())
entryMap[dataMap[itemGUID]].erase(itemGUID);
dataMap.erase(itemGUID);
}
if (trans)
(*trans)->PAppend("DELETE FROM custom_transmogrification WHERE GUID = %u", GUID_LOPART(itemGUID));
else
CharacterDatabase.PExecute("DELETE FROM custom_transmogrification WHERE GUID = %u", GUID_LOPART(itemGUID));
}
bool Transmogrification::GetEnableTransmogInfo() const
{
return EnableTransmogInfo;
}
uint32 Transmogrification::GetTransmogNpcText() const
{
return TransmogNpcText;
}
bool Transmogrification::GetEnableSetInfo() const
{
return EnableSetInfo;
}
uint32 Transmogrification::GetSetNpcText() const
{
return SetNpcText;
}
float Transmogrification::GetScaledCostModifier() const
{
return ScaledCostModifier;
}
int32 Transmogrification::GetCopperCost() const
{
return CopperCost;
}
bool Transmogrification::GetRequireToken() const
{
return RequireToken;
}
uint32 Transmogrification::GetTokenEntry() const
{
return TokenEntry;
}
uint32 Transmogrification::GetTokenAmount() const
{
return TokenAmount;
}
bool Transmogrification::GetAllowMixedArmorTypes() const
{
return AllowMixedArmorTypes;
};
bool Transmogrification::GetAllowMixedWeaponTypes() const
{
return AllowMixedWeaponTypes;
};

152
src/Transmogrification.h Normal file
View File

@@ -0,0 +1,152 @@
#ifndef DEF_TRANSMOGRIFICATION_H
#define DEF_TRANSMOGRIFICATION_H
#include <vector>
#include "Define.h"
#include "ScriptPCH.h"
#include "Language.h"
#include "Config.h"
#define PRESETS // comment this line to disable preset feature totally
#define MAX_OPTIONS 25 // do not alter
class Item;
class Player;
class WorldSession;
struct ItemTemplate;
enum TransmogTrinityStrings // Language.h might have same entries, appears when executing SQL, change if needed
{
LANG_ERR_TRANSMOG_OK = 11100, // change this
LANG_ERR_TRANSMOG_INVALID_SLOT,
LANG_ERR_TRANSMOG_INVALID_SRC_ENTRY,
LANG_ERR_TRANSMOG_MISSING_SRC_ITEM,
LANG_ERR_TRANSMOG_MISSING_DEST_ITEM,
LANG_ERR_TRANSMOG_INVALID_ITEMS,
LANG_ERR_TRANSMOG_NOT_ENOUGH_MONEY,
LANG_ERR_TRANSMOG_NOT_ENOUGH_TOKENS,
LANG_ERR_UNTRANSMOG_OK,
LANG_ERR_UNTRANSMOG_NO_TRANSMOGS,
#ifdef PRESETS
LANG_PRESET_ERR_INVALID_NAME,
#endif
};
class Transmogrification
{
public:
typedef UNORDERED_MAP<uint64, uint64> transmogData;
typedef UNORDERED_MAP<uint64, transmogData> transmogMap;
transmogMap entryMap; // entryMap[pGUID][iGUID] = entry
transmogData dataMap; // dataMap[iGUID] = pGUID
#ifdef PRESETS
bool EnableSetInfo;
uint32 SetNpcText;
typedef std::map<uint8, uint32> slotMap;
typedef std::map<uint8, slotMap> presetData;
typedef UNORDERED_MAP<uint64, presetData> presetDataMap;
presetDataMap presetById; // presetById[pGUID][presetID][slot] = entry
typedef std::map<uint8, std::string> presetIdMap;
typedef UNORDERED_MAP<uint64, presetIdMap> presetNameMap;
presetNameMap presetByName; // presetByName[pGUID][presetID] = presetName
void PresetTransmog(Player* player, Item* itemTransmogrified, uint32 fakeEntry, uint8 slot);
bool EnableSets;
uint8 MaxSets;
float SetCostModifier;
int32 SetCopperCost;
bool GetEnableSets() const;
uint8 GetMaxSets() const;
float GetSetCostModifier() const;
int32 GetSetCopperCost() const;
void LoadPlayerSets(uint64 pGUID);
void UnloadPlayerSets(uint64 pGUID);
#endif
bool EnableTransmogInfo;
uint32 TransmogNpcText;
// Use IsAllowed() and IsNotAllowed()
// these are thread unsafe, but assumed to be static data so it should be safe
std::set<uint32> Allowed;
std::set<uint32> NotAllowed;
float ScaledCostModifier;
int32 CopperCost;
bool RequireToken;
uint32 TokenEntry;
uint32 TokenAmount;
bool AllowPoor;
bool AllowCommon;
bool AllowUncommon;
bool AllowRare;
bool AllowEpic;
bool AllowLegendary;
bool AllowArtifact;
bool AllowHeirloom;
bool AllowMixedArmorTypes;
bool AllowMixedWeaponTypes;
bool AllowFishingPoles;
bool IgnoreReqRace;
bool IgnoreReqClass;
bool IgnoreReqSkill;
bool IgnoreReqSpell;
bool IgnoreReqLevel;
bool IgnoreReqEvent;
bool IgnoreReqStats;
bool IsAllowed(uint32 entry) const;
bool IsNotAllowed(uint32 entry) const;
bool IsAllowedQuality(uint32 quality) const;
bool IsRangedWeapon(uint32 Class, uint32 SubClass) const;
void LoadConfig(bool reload); // thread unsafe
std::string GetItemIcon(uint32 entry, uint32 width, uint32 height, int x, int y) const;
std::string GetSlotIcon(uint8 slot, uint32 width, uint32 height, int x, int y) const;
const char * GetSlotName(uint8 slot, WorldSession* session) const;
std::string GetItemLink(Item* item, WorldSession* session) const;
std::string GetItemLink(uint32 entry, WorldSession* session) const;
uint32 GetFakeEntry(uint64 itemGUID) const;
void UpdateItem(Player* player, Item* item) const;
void DeleteFakeEntry(Player* player, uint8 slot, Item* itemTransmogrified, SQLTransaction* trans = NULL);
void SetFakeEntry(Player* player, uint32 newEntry, uint8 slot, Item* itemTransmogrified);
TransmogTrinityStrings Transmogrify(Player* player, uint64 itemGUID, uint8 slot, /*uint32 newEntry, */bool no_cost = false);
bool CanTransmogrifyItemWithItem(Player* player, ItemTemplate const* destination, ItemTemplate const* source) const;
bool SuitableForTransmogrification(Player* player, ItemTemplate const* proto) const;
// bool CanBeTransmogrified(Item const* item);
// bool CanTransmogrify(Item const* item);
uint32 GetSpecialPrice(ItemTemplate const* proto) const;
void DeleteFakeFromDB(uint64 itemGUID, SQLTransaction* trans = NULL);
float GetScaledCostModifier() const;
int32 GetCopperCost() const;
bool GetRequireToken() const;
uint32 GetTokenEntry() const;
uint32 GetTokenAmount() const;
bool GetAllowMixedArmorTypes() const;
bool GetAllowMixedWeaponTypes() const;
// Config
bool GetEnableTransmogInfo() const;
uint32 GetTransmogNpcText() const;
bool GetEnableSetInfo() const;
uint32 GetSetNpcText() const;
};
#define sTransmogrification ACE_Singleton<Transmogrification, ACE_Null_Mutex>::instance()
#endif

13
src/cmake/after_ws.cmake Normal file
View File

@@ -0,0 +1,13 @@
if ( MSVC )
add_custom_command(TARGET worldserver
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_TRANSM_DIR}/conf/transmog.conf.dist ${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/
)
elseif ( MINGW )
add_custom_command(TARGET worldserver
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_TRANSM_DIR}/conf/transmog.conf.dist ${CMAKE_BINARY_DIR}/bin/
)
endif()
install(FILES "${CMAKE_TRANSM_DIR}/conf/transmog.conf.dist" DESTINATION ${CONF_DIR})

473
src/transmog_scripts.cpp Normal file
View File

@@ -0,0 +1,473 @@
/*
5.0
Transmogrification 3.3.5a - Gossip menu
By Rochet2
ScriptName for NPC:
Creature_Transmogrify
TODO:
Make DB saving even better (Deleting)? What about coding?
Fix the cost formula
-- Too much data handling, use default costs
Are the qualities right?
Blizzard might have changed the quality requirements.
(TC handles it with stat checks)
Cant transmogrify rediculus items // Foereaper: would be fun to stab people with a fish
-- Cant think of any good way to handle this easily, could rip flagged items from cata DB
*/
#include "Transmogrification.h"
#define sT sTransmogrification
#define GTS session->GetTrinityString // dropped translation support, no one using?
class npc_transmogrifier : public CreatureScript
{
public:
npc_transmogrifier() : CreatureScript("npc_transmogrifier") { }
bool OnGossipHello(Player* player, Creature* creature)
{
WorldSession* session = player->GetSession();
if (sT->GetEnableTransmogInfo())
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Misc_Book_11:30:30:-18:0|tHow transmogrification works", EQUIPMENT_SLOT_END + 9, 0);
for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
{
if (const char* slotName = sT->GetSlotName(slot, session))
{
Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
uint32 entry = newItem ? sT->GetFakeEntry(newItem->GetGUID()) : 0;
std::string icon = entry ? sT->GetItemIcon(entry, 30, 30, -18, 0) : sT->GetSlotIcon(slot, 30, 30, -18, 0);
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, icon + std::string(slotName), EQUIPMENT_SLOT_END, slot);
}
}
#ifdef PRESETS
if (sT->GetEnableSets())
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/RAIDFRAME/UI-RAIDFRAME-MAINASSIST:30:30:-18:0|tManage sets", EQUIPMENT_SLOT_END + 4, 0);
#endif
player->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Enchant_Disenchant:30:30:-18:0|tRemove all transmogrifications", EQUIPMENT_SLOT_END + 2, 0, "Remove transmogrifications from all equipped items?", 0, false);
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/PaperDollInfoFrame/UI-GearManager-Undo:30:30:-18:0|tUpdate menu", EQUIPMENT_SLOT_END + 1, 0);
player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
return true;
}
bool OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action)
{
player->PlayerTalkClass->ClearMenus();
WorldSession* session = player->GetSession();
switch (sender)
{
case EQUIPMENT_SLOT_END: // Show items you can use
ShowTransmogItems(player, creature, action);
break;
case EQUIPMENT_SLOT_END + 1: // Main menu
OnGossipHello(player, creature);
break;
case EQUIPMENT_SLOT_END + 2: // Remove Transmogrifications
{
bool removed = false;
SQLTransaction trans = CharacterDatabase.BeginTransaction();
for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
{
if (Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
{
if (!sT->GetFakeEntry(newItem->GetGUID()))
continue;
sT->DeleteFakeEntry(player, slot, newItem, &trans);
removed = true;
}
}
if (removed)
{
session->SendAreaTriggerMessage(GTS(LANG_ERR_UNTRANSMOG_OK));
CharacterDatabase.CommitTransaction(trans);
}
else
session->SendNotification(LANG_ERR_UNTRANSMOG_NO_TRANSMOGS);
OnGossipHello(player, creature);
} break;
case EQUIPMENT_SLOT_END + 3: // Remove Transmogrification from single item
{
if (Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, action))
{
if (sT->GetFakeEntry(newItem->GetGUID()))
{
sT->DeleteFakeEntry(player, action, newItem);
session->SendAreaTriggerMessage(GTS(LANG_ERR_UNTRANSMOG_OK));
}
else
session->SendNotification(LANG_ERR_UNTRANSMOG_NO_TRANSMOGS);
}
OnGossipSelect(player, creature, EQUIPMENT_SLOT_END, action);
} break;
#ifdef PRESETS
case EQUIPMENT_SLOT_END + 4: // Presets menu
{
if (!sT->GetEnableSets())
{
OnGossipHello(player, creature);
return true;
}
if (sT->GetEnableSetInfo())
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Misc_Book_11:30:30:-18:0|tHow sets work", EQUIPMENT_SLOT_END + 10, 0);
for (Transmogrification::presetIdMap::const_iterator it = sT->presetByName[player->GetGUID()].begin(); it != sT->presetByName[player->GetGUID()].end(); ++it)
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Misc_Statue_02:30:30:-18:0|t" + it->second, EQUIPMENT_SLOT_END + 6, it->first);
if (sT->presetByName[player->GetGUID()].size() < sT->GetMaxSets())
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/GuildBankFrame/UI-GuildBankFrame-NewTab:30:30:-18:0|tSave set", EQUIPMENT_SLOT_END + 8, 0);
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tBack..", EQUIPMENT_SLOT_END + 1, 0);
player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
} break;
case EQUIPMENT_SLOT_END + 5: // Use preset
{
if (!sT->GetEnableSets())
{
OnGossipHello(player, creature);
return true;
}
// action = presetID
for (Transmogrification::slotMap::const_iterator it = sT->presetById[player->GetGUID()][action].begin(); it != sT->presetById[player->GetGUID()][action].end(); ++it)
{
if (Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, it->first))
sT->PresetTransmog(player, item, it->second, it->first);
}
OnGossipSelect(player, creature, EQUIPMENT_SLOT_END + 6, action);
} break;
case EQUIPMENT_SLOT_END + 6: // view preset
{
if (!sT->GetEnableSets())
{
OnGossipHello(player, creature);
return true;
}
// action = presetID
for (Transmogrification::slotMap::const_iterator it = sT->presetById[player->GetGUID()][action].begin(); it != sT->presetById[player->GetGUID()][action].end(); ++it)
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, sT->GetItemIcon(it->second, 30, 30, -18, 0) + sT->GetItemLink(it->second, session), sender, action);
player->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Misc_Statue_02:30:30:-18:0|tUse set", EQUIPMENT_SLOT_END + 5, action, "Using this set for transmogrify will bind transmogrified items to you and make them non-refundable and non-tradeable.\nDo you wish to continue?\n\n" + sT->presetByName[player->GetGUID()][action], 0, false);
player->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_MONEY_BAG, "|TInterface/PaperDollInfoFrame/UI-GearManager-LeaveItem-Opaque:30:30:-18:0|tDelete set", EQUIPMENT_SLOT_END + 7, action, "Are you sure you want to delete " + sT->presetByName[player->GetGUID()][action] + "?", 0, false);
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tBack..", EQUIPMENT_SLOT_END + 4, 0);
player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
} break;
case EQUIPMENT_SLOT_END + 7: // Delete preset
{
if (!sT->GetEnableSets())
{
OnGossipHello(player, creature);
return true;
}
// action = presetID
CharacterDatabase.PExecute("DELETE FROM `custom_transmogrification_sets` WHERE Owner = %u AND PresetID = %u", player->GetGUIDLow(), action);
sT->presetById[player->GetGUID()][action].clear();
sT->presetById[player->GetGUID()].erase(action);
sT->presetByName[player->GetGUID()].erase(action);
OnGossipSelect(player, creature, EQUIPMENT_SLOT_END + 4, 0);
} break;
case EQUIPMENT_SLOT_END + 8: // Save preset
{
if (!sT->GetEnableSets() || sT->presetByName[player->GetGUID()].size() >= sT->GetMaxSets())
{
OnGossipHello(player, creature);
return true;
}
uint32 cost = 0;
bool canSave = false;
for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
{
if (!sT->GetSlotName(slot, session))
continue;
if (Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
{
uint32 entry = sT->GetFakeEntry(newItem->GetGUID());
if (!entry)
continue;
const ItemTemplate* temp = sObjectMgr->GetItemTemplate(entry);
if (!temp)
continue;
if (!sT->SuitableForTransmogrification(player, temp)) // no need to check?
continue;
cost += sT->GetSpecialPrice(temp);
canSave = true;
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, sT->GetItemIcon(entry, 30, 30, -18, 0) + sT->GetItemLink(entry, session), EQUIPMENT_SLOT_END + 8, 0);
}
}
if (canSave)
player->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_MONEY_BAG, "|TInterface/GuildBankFrame/UI-GuildBankFrame-NewTab:30:30:-18:0|tSave set", 0, 0, "Insert set name", cost*sT->GetSetCostModifier() + sT->GetSetCopperCost(), true);
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/PaperDollInfoFrame/UI-GearManager-Undo:30:30:-18:0|tUpdate menu", sender, action);
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tBack..", EQUIPMENT_SLOT_END + 4, 0);
player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
} break;
case EQUIPMENT_SLOT_END + 10: // Set info
{
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tBack..", EQUIPMENT_SLOT_END + 4, 0);
player->SEND_GOSSIP_MENU(sT->GetSetNpcText(), creature->GetGUID());
} break;
#endif
case EQUIPMENT_SLOT_END + 9: // Transmog info
{
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tBack..", EQUIPMENT_SLOT_END + 1, 0);
player->SEND_GOSSIP_MENU(sT->GetTransmogNpcText(), creature->GetGUID());
} break;
default: // Transmogrify
{
if (!sender && !action)
{
OnGossipHello(player, creature);
return true;
}
// sender = slot, action = display
TransmogTrinityStrings res = sT->Transmogrify(player, MAKE_NEW_GUID(action, 0, HIGHGUID_ITEM), sender);
if (res == LANG_ERR_TRANSMOG_OK)
session->SendAreaTriggerMessage(GTS(LANG_ERR_TRANSMOG_OK));
else
session->SendNotification(res);
// OnGossipSelect(player, creature, EQUIPMENT_SLOT_END, sender);
// ShowTransmogItems(player, creature, sender);
player->CLOSE_GOSSIP_MENU(); // Wait for SetMoney to get fixed, issue #10053
} break;
}
return true;
}
#ifdef PRESETS
bool OnGossipSelectCode(Player* player, Creature* creature, uint32 sender, uint32 action, const char* code)
{
player->PlayerTalkClass->ClearMenus();
if (sender || action)
return true; // should never happen
if (!sT->GetEnableSets())
{
OnGossipHello(player, creature);
return true;
}
std::string name(code);
if (name.find('"') != std::string::npos || name.find('\\') != std::string::npos)
player->GetSession()->SendNotification(LANG_PRESET_ERR_INVALID_NAME);
else
{
for (uint8 presetID = 0; presetID < sT->GetMaxSets(); ++presetID) // should never reach over max
{
if (sT->presetByName[player->GetGUID()].find(presetID) != sT->presetByName[player->GetGUID()].end())
continue; // Just remember never to use presetByName[pGUID][presetID] when finding etc!
int32 cost = 0;
std::map<uint8, uint32> items;
for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
{
if (!sT->GetSlotName(slot, player->GetSession()))
continue;
if (Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
{
uint32 entry = sT->GetFakeEntry(newItem->GetGUID());
if (!entry)
continue;
const ItemTemplate* temp = sObjectMgr->GetItemTemplate(entry);
if (!temp)
continue;
if (!sT->SuitableForTransmogrification(player, temp))
continue;
cost += sT->GetSpecialPrice(temp);
items[slot] = entry;
}
}
if (items.empty())
break; // no transmogrified items were found to be saved
cost *= sT->GetSetCostModifier();
cost += sT->GetSetCopperCost();
if (!player->HasEnoughMoney(cost))
{
player->GetSession()->SendNotification(LANG_ERR_TRANSMOG_NOT_ENOUGH_MONEY);
break;
}
std::ostringstream ss;
for (std::map<uint8, uint32>::iterator it = items.begin(); it != items.end(); ++it)
{
ss << uint32(it->first) << ' ' << it->second << ' ';
sT->presetById[player->GetGUID()][presetID][it->first] = it->second;
}
sT->presetByName[player->GetGUID()][presetID] = name; // Make sure code doesnt mess up SQL!
CharacterDatabase.PExecute("REPLACE INTO `custom_transmogrification_sets` (`Owner`, `PresetID`, `SetName`, `SetData`) VALUES (%u, %u, \"%s\", \"%s\")", player->GetGUIDLow(), uint32(presetID), name.c_str(), ss.str().c_str());
if (cost)
player->ModifyMoney(cost);
break;
}
}
//OnGossipSelect(player, creature, EQUIPMENT_SLOT_END+4, 0);
player->CLOSE_GOSSIP_MENU(); // Wait for SetMoney to get fixed, issue #10053
return true;
}
#endif
void ShowTransmogItems(Player* player, Creature* creature, uint8 slot) // Only checks bags while can use an item from anywhere in inventory
{
WorldSession* session = player->GetSession();
Item* oldItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
if (oldItem)
{
uint32 limit = 0;
uint32 price = sT->GetSpecialPrice(oldItem->GetTemplate());
price *= sT->GetScaledCostModifier();
price += sT->GetCopperCost();
std::ostringstream ss;
ss << std::endl;
if (sT->GetRequireToken())
ss << std::endl << std::endl << sT->GetTokenAmount() << " x " << sT->GetItemLink(sT->GetTokenEntry(), session);
for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; ++i)
{
if (limit > MAX_OPTIONS)
break;
Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, i);
if (!newItem)
continue;
if (!sT->CanTransmogrifyItemWithItem(player, oldItem->GetTemplate(), newItem->GetTemplate()))
continue;
if (sT->GetFakeEntry(oldItem->GetGUID()) == newItem->GetEntry())
continue;
++limit;
player->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_MONEY_BAG, sT->GetItemIcon(newItem->GetEntry(), 30, 30, -18, 0) + sT->GetItemLink(newItem, session), slot, newItem->GetGUIDLow(), "Using this item for transmogrify will bind it to you and make it non-refundable and non-tradeable.\nDo you wish to continue?\n\n" + sT->GetItemIcon(newItem->GetEntry(), 40, 40, -15, -10) + sT->GetItemLink(newItem, session) + ss.str(), price, false);
}
for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
{
Bag* bag = player->GetBagByPos(i);
if (!bag)
continue;
for (uint32 j = 0; j < bag->GetBagSize(); ++j)
{
if (limit > MAX_OPTIONS)
break;
Item* newItem = player->GetItemByPos(i, j);
if (!newItem)
continue;
if (!sT->CanTransmogrifyItemWithItem(player, oldItem->GetTemplate(), newItem->GetTemplate()))
continue;
if (sT->GetFakeEntry(oldItem->GetGUID()) == newItem->GetEntry())
continue;
++limit;
player->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_MONEY_BAG, sT->GetItemIcon(newItem->GetEntry(), 30, 30, -18, 0) + sT->GetItemLink(newItem, session), slot, newItem->GetGUIDLow(), "Using this item for transmogrify will bind it to you and make it non-refundable and non-tradeable.\nDo you wish to continue?\n\n" + sT->GetItemIcon(newItem->GetEntry(), 40, 40, -15, -10) + sT->GetItemLink(newItem, session) + ss.str(), price, false);
}
}
}
player->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Enchant_Disenchant:30:30:-18:0|tRemove transmogrification", EQUIPMENT_SLOT_END + 3, slot, "Remove transmogrification from the slot?", 0, false);
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/PaperDollInfoFrame/UI-GearManager-Undo:30:30:-18:0|tUpdate menu", EQUIPMENT_SLOT_END, slot);
player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tBack..", EQUIPMENT_SLOT_END + 1, 0);
player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
}
};
class PS_Transmogrification : public PlayerScript
{
public:
PS_Transmogrification() : PlayerScript("Player_Transmogrify") { }
void OnAfterSetVisibleItemSlot(Player* player, uint8 slot, Item *item) {
if (!item)
return;
if (uint32 entry = sT->GetFakeEntry(item->GetGUID()))
player->SetUInt32Value(PLAYER_VISIBLE_ITEM_1_ENTRYID + (slot * 2), entry);
}
void OnLogin(Player* player)
{
uint64 playerGUID = player->GetGUID();
sT->entryMap.erase(playerGUID);
QueryResult result = CharacterDatabase.PQuery("SELECT GUID, FakeEntry FROM custom_transmogrification WHERE Owner = %u", player->GetGUIDLow());
if (result)
{
do
{
uint64 itemGUID = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_ITEM);
uint32 fakeEntry = (*result)[1].GetUInt32();
if (sObjectMgr->GetItemTemplate(fakeEntry))
{
sT->dataMap[itemGUID] = playerGUID;
sT->entryMap[playerGUID][itemGUID] = fakeEntry;
}
else
{
//sLog->outError(LOG_FILTER_SQL, "Item entry (Entry: %u, itemGUID: %u, playerGUID: %u) does not exist, ignoring.", fakeEntry, GUID_LOPART(itemGUID), player->GetGUIDLow());
// CharacterDatabase.PExecute("DELETE FROM custom_transmogrification WHERE FakeEntry = %u", fakeEntry);
}
} while (result->NextRow());
for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
{
if (Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
player->SetVisibleItemSlot(slot, item);
}
}
#ifdef PRESETS
if (sT->GetEnableSets())
sT->LoadPlayerSets(playerGUID);
#endif
}
void OnLogout(Player* player)
{
uint32 pGUID = player->GetGUID();
for (Transmogrification::transmogData::const_iterator it = sT->entryMap[pGUID].begin(); it != sT->entryMap[pGUID].end(); ++it)
sT->dataMap.erase(it->first);
sT->entryMap.erase(pGUID);
#ifdef PRESETS
if (sT->GetEnableSets())
sT->UnloadPlayerSets(pGUID);
#endif
}
};
class WS_Transmogrification : public WorldScript
{
public:
WS_Transmogrification() : WorldScript("WS_Transmogrification") { }
void OnAfterConfigLoad(bool reload)
{
if (reload)
sT->LoadConfig(reload);
}
void OnStartup()
{
sT->LoadConfig(false);
//sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Deleting non-existing transmogrification entries...");
CharacterDatabase.Execute("DELETE FROM custom_transmogrification WHERE NOT EXISTS (SELECT 1 FROM item_instance WHERE item_instance.guid = custom_transmogrification.GUID)");
#ifdef PRESETS
// Clean even if disabled
// Dont delete even if player has more presets than should
CharacterDatabase.Execute("DELETE FROM `custom_transmogrification_sets` WHERE NOT EXISTS(SELECT 1 FROM characters WHERE characters.guid = custom_transmogrification_sets.Owner)");
#endif
}
};
class global_transmog_script : public GlobalScript {
public:
global_transmog_script() : GlobalScript("global_transmog_script") { }
void OnItemDelFromDB(SQLTransaction& trans, uint32 itemGuid) {
sT->DeleteFakeFromDB(itemGuid, &trans);
}
void OnMirrorImageDisplayItem(const Item *item, uint32 &display) {
if (uint32 entry = sTransmogrification->GetFakeEntry(item->GetGUID()))
display=uint32(sObjectMgr->GetItemTemplate(entry)->DisplayInfoID);
}
};
void AddSC_transmog() {
new global_transmog_script();
new npc_transmogrifier();
new PS_Transmogrification();
new WS_Transmogrification();
}

View File

@@ -0,0 +1,12 @@
#ifndef TRANSMOGR_SCRIPTS_LOADER_H
#define TRANSMOGR_SCRIPTS_LOADER_H
void AddSC_transmog();
void AddTransmogScripts()
{
AddSC_transmog();
}
#endif /* TRANSMOG_SCRIPTS_LOADER_H */