|
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp |
|
index 161fca4..8c68d8a 100644 |
|
--- a/src/server/game/Entities/Player/Player.cpp |
|
+++ b/src/server/game/Entities/Player/Player.cpp |
|
@@ -12486,12 +12486,13 @@ void Player::QuickEquipItem(uint16 pos, Item* pItem) |
|
} |
|
} |
|
|
|
+extern uint32 GetItemEnchantVisual(Player* player, Item* item); |
|
void Player::SetVisibleItemSlot(uint8 slot, Item* pItem) |
|
{ |
|
if (pItem) |
|
{ |
|
SetUInt32Value(PLAYER_VISIBLE_ITEM_1_ENTRYID + (slot * 2), pItem->GetEntry()); |
|
- SetUInt16Value(PLAYER_VISIBLE_ITEM_1_ENCHANTMENT + (slot * 2), 0, pItem->GetEnchantmentId(PERM_ENCHANTMENT_SLOT)); |
|
+ SetUInt16Value(PLAYER_VISIBLE_ITEM_1_ENCHANTMENT + (slot * 2), 0, GetItemEnchantVisual(this, pItem)); |
|
SetUInt16Value(PLAYER_VISIBLE_ITEM_1_ENCHANTMENT + (slot * 2), 1, pItem->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)); |
|
} |
|
else |
|
@@ -24930,6 +24931,7 @@ void Player::AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore cons |
|
} |
|
} |
|
|
|
+extern void SetRandomEnchantVisual(Player* player, Item* item); |
|
void Player::StoreLootItem(uint8 lootSlot, Loot* loot) |
|
{ |
|
QuestItem* qitem = NULL; |
|
@@ -25005,6 +25007,7 @@ void Player::StoreLootItem(uint8 lootSlot, Loot* loot) |
|
if (loot->containerID > 0) |
|
loot->DeleteLootItemFromContainerItemDB(item->itemid); |
|
|
|
+ SetRandomEnchantVisual(this, newitem); |
|
} |
|
else |
|
SendEquipError(msg, NULL, NULL, item->itemid); |
|
diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp |
|
index b4f1923..7531bd6 100644 |
|
--- a/src/server/game/Handlers/LootHandler.cpp |
|
+++ b/src/server/game/Handlers/LootHandler.cpp |
|
@@ -386,6 +386,7 @@ void WorldSession::DoLootRelease(ObjectGuid lguid) |
|
loot->RemoveLooter(player->GetGUID()); |
|
} |
|
|
|
+extern void SetRandomEnchantVisual(Player* player, Item* item); |
|
void WorldSession::HandleLootMasterGiveOpcode(WorldPacket& recvData) |
|
{ |
|
uint8 slotid; |
|
@@ -479,6 +480,7 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPacket& recvData) |
|
target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, loot->loot_type, item.count); |
|
target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item.itemid, item.count); |
|
|
|
+ SetRandomEnchantVisual(target, newitem); |
|
// mark as looted |
|
item.count = 0; |
|
item.is_looted = true; |
|
diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp |
|
index 025184f..042aebc 100644 |
|
--- a/src/server/game/Scripting/ScriptLoader.cpp |
|
+++ b/src/server/game/Scripting/ScriptLoader.cpp |
|
@@ -1416,6 +1416,7 @@ void AddBattlegroundScripts() |
|
#ifdef SCRIPTS |
|
/* This is where custom scripts' loading functions should be declared. */ |
|
|
|
+void AddSC_item_enchant_visuals(); |
|
#endif |
|
|
|
void AddCustomScripts() |
|
@@ -1423,5 +1424,6 @@ void AddCustomScripts() |
|
#ifdef SCRIPTS |
|
/* This is where custom scripts should be added. */ |
|
|
|
+ AddSC_item_enchant_visuals(); |
|
#endif |
|
} |
|
diff --git a/src/server/scripts/Custom/CMakeLists.txt b/src/server/scripts/Custom/CMakeLists.txt |
|
index 5218f76..c6bda8e 100644 |
|
--- a/src/server/scripts/Custom/CMakeLists.txt |
|
+++ b/src/server/scripts/Custom/CMakeLists.txt |
|
@@ -13,6 +13,7 @@ |
|
set(scripts_STAT_SRCS |
|
${scripts_STAT_SRCS} |
|
# ${sources_Custom} |
|
+ Custom/enchant_visuals.cpp |
|
) |
|
|
|
message(" -> Prepared: Custom") |
|
diff --git a/src/server/scripts/Custom/enchant_visuals.cpp b/src/server/scripts/Custom/enchant_visuals.cpp |
|
new file mode 100644 |
|
index 0000000..09b6d7f |
|
--- /dev/null |
|
+++ b/src/server/scripts/Custom/enchant_visuals.cpp |
|
@@ -0,0 +1,218 @@ |
|
+/* |
|
+Author: Rochet2 - https://rochet2.github.io/ |
|
+Source: https://rochet2.github.io/?page=Item_Enchant_Visuals |
|
+ |
|
+About: |
|
+All weapons looted have a 25% chance to have a random enchant *visual* |
|
+This is purely visual fun and the visual will be replaced if the weapon is enchanted. |
|
+ |
|
+This script is 100% automatic. Just add it to your source and DB table is automatically created |
|
+ |
|
+Works with BOOST and ACE |
|
+*/ |
|
+ |
|
+static const float chance = 0.25f; |
|
+ |
|
+// Do not edit anything below |
|
+ |
|
+#include "ScriptPCH.h" |
|
+ |
|
+#ifndef UNORDERED_MAP |
|
+#define UNORDERED_MAP std::unordered_map |
|
+#endif |
|
+ |
|
+#ifdef BOOST_VERSION |
|
+#define USING_BOOST |
|
+#endif |
|
+#ifdef USING_BOOST |
|
+#include <boost/thread/locks.hpp> |
|
+#include <boost/thread/shared_mutex.hpp> |
|
+#endif |
|
+ |
|
+static const uint32 ItemEnchants[] = { 3789, 3854, 3273, 3225, 3870, 1899, 2674, 2675, 2671, 2672, 3365, 2673, 2343, 425, 3855, 1894, 1103, 1898, 3345, 1743, 3093, 1900, 3846, 1606, 283, 1, 3265, 2, 3, 3266, 1903, 13, 26, 7, 803, 1896, 2666, 25 }; |
|
+static const uint32 ItemEnchants_size = (sizeof(ItemEnchants) / sizeof(*ItemEnchants)) - 1; |
|
+ |
|
+namespace |
|
+{ |
|
+ class RWLockable |
|
+ { |
|
+ public: |
|
+#ifdef USING_BOOST |
|
+ typedef boost::shared_mutex LockType; |
|
+ typedef boost::shared_lock<boost::shared_mutex> ReadGuard; |
|
+ typedef boost::unique_lock<boost::shared_mutex> WriteGuard; |
|
+#else |
|
+ typedef ACE_RW_Thread_Mutex LockType; |
|
+ typedef ACE_Read_Guard<LockType> ReadGuard; |
|
+ typedef ACE_Write_Guard<LockType> WriteGuard; |
|
+#endif |
|
+ LockType& GetLock() { return _lock; } |
|
+ private: |
|
+ LockType _lock; |
|
+ }; |
|
+ |
|
+ class EnchantStore : public RWLockable |
|
+ { |
|
+ public: |
|
+ typedef UNORDERED_MAP<uint32, uint32> ItemLowToEnchant; // map[itemguid] = {enchant} |
|
+ typedef UNORDERED_MAP<uint32, ItemLowToEnchant> PlayerLowToItemLowMap; // map[playerguid] = {ItemLowToEnchant} |
|
+ |
|
+ void LoadPlayerEnchants(uint32 playerLow) |
|
+ { |
|
+ QueryResult result = CharacterDatabase.PQuery("SELECT iguid, display FROM custom_item_enchant_visuals WHERE iguid IN(SELECT guid FROM item_instance WHERE owner_guid = %u)", playerLow); |
|
+ if (!result) |
|
+ return; |
|
+ |
|
+ ItemLowToEnchant temp; |
|
+ do |
|
+ { |
|
+ uint32 iguid = result->Fetch()[0].GetUInt32(); |
|
+ uint32 display = result->Fetch()[1].GetUInt32(); |
|
+ temp[iguid] = display; |
|
+ } while (result->NextRow()); |
|
+ |
|
+ WriteGuard lock(GetLock()); |
|
+ hashmap[playerLow] = temp; |
|
+ } |
|
+ |
|
+ void DeletePlayerEnchants(uint32 playerLow) |
|
+ { |
|
+ WriteGuard lock(GetLock()); |
|
+ hashmap.erase(playerLow); |
|
+ } |
|
+ |
|
+ void AddEnchant(uint32 playerLow, uint32 itemLow, uint32 enchant) |
|
+ { |
|
+ CharacterDatabase.PExecute("REPLACE INTO custom_item_enchant_visuals (iguid, display) VALUES (%u, %u)", itemLow, enchant); |
|
+ |
|
+ WriteGuard lock(GetLock()); |
|
+ hashmap[playerLow][itemLow] = enchant; |
|
+ } |
|
+ |
|
+ uint32 GetEnchant(uint32 playerLow, uint32 itemLow) |
|
+ { |
|
+ ReadGuard lock(GetLock()); |
|
+ |
|
+ PlayerLowToItemLowMap::iterator it = hashmap.find(playerLow); |
|
+ if (it == hashmap.end()) |
|
+ return 0; |
|
+ |
|
+ ItemLowToEnchant::iterator it2 = it->second.find(itemLow); |
|
+ if (it2 == it->second.end()) |
|
+ return 0; |
|
+ |
|
+ return it2->second; |
|
+ } |
|
+ |
|
+ void RemoveEnchant(uint32 playerLow, uint32 itemLow) |
|
+ { |
|
+ { |
|
+ WriteGuard lock(GetLock()); |
|
+ |
|
+ PlayerLowToItemLowMap::iterator it = hashmap.find(playerLow); |
|
+ if (it == hashmap.end()) |
|
+ return; |
|
+ |
|
+ it->second.erase(itemLow); |
|
+ if (it->second.empty()) |
|
+ hashmap.erase(playerLow); |
|
+ } |
|
+ |
|
+ CharacterDatabase.PExecute("DELETE FROM custom_item_enchant_visuals WHERE iguid = %u", itemLow); |
|
+ } |
|
+ |
|
+ private: |
|
+ PlayerLowToItemLowMap hashmap; |
|
+ }; |
|
+}; |
|
+ |
|
+static EnchantStore enchantStore; |
|
+ |
|
+uint32 GetItemEnchantVisual(Player* player, Item* item) |
|
+{ |
|
+ if (!player || !item) |
|
+ return 0; |
|
+ |
|
+ uint32 visual = enchantStore.GetEnchant(player->GetGUIDLow(), item->GetGUIDLow()); |
|
+ if (!visual) |
|
+ return 0; |
|
+ |
|
+ if (uint32 enchant = item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT)) |
|
+ { |
|
+ enchantStore.RemoveEnchant(player->GetGUIDLow(), item->GetGUIDLow()); |
|
+ player->SaveToDB(); |
|
+ return enchant; |
|
+ } |
|
+ |
|
+ return visual; |
|
+} |
|
+ |
|
+void SetRandomEnchantVisual(Player* player, Item* item) |
|
+{ |
|
+ if (!player || !item) |
|
+ return; |
|
+ |
|
+ const ItemTemplate* temp = item->GetTemplate(); |
|
+ if (temp->Class != ITEM_CLASS_WEAPON) |
|
+ return; |
|
+ |
|
+ if (temp->SubClass == ITEM_SUBCLASS_WEAPON_BOW || |
|
+ temp->SubClass == ITEM_SUBCLASS_WEAPON_GUN || |
|
+ temp->SubClass == ITEM_SUBCLASS_WEAPON_obsolete || |
|
+ temp->SubClass == ITEM_SUBCLASS_WEAPON_FIST || |
|
+ temp->SubClass == ITEM_SUBCLASS_WEAPON_THROWN || |
|
+ temp->SubClass == ITEM_SUBCLASS_WEAPON_SPEAR || |
|
+ temp->SubClass == ITEM_SUBCLASS_WEAPON_CROSSBOW || |
|
+ temp->SubClass == ITEM_SUBCLASS_WEAPON_WAND || |
|
+ temp->SubClass == ITEM_SUBCLASS_WEAPON_FISHING_POLE) |
|
+ return; |
|
+ |
|
+ if (rand_norm() >= chance) |
|
+ return; |
|
+ |
|
+ uint32 enchant = ItemEnchants[urand(0, ItemEnchants_size)]; |
|
+ enchantStore.AddEnchant(player->GetGUIDLow(), item->GetGUIDLow(), enchant); |
|
+ |
|
+ player->SaveToDB(); |
|
+ player->SetVisibleItemSlot(EQUIPMENT_SLOT_MAINHAND, player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND)); |
|
+ player->SetVisibleItemSlot(EQUIPMENT_SLOT_OFFHAND, player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND)); |
|
+} |
|
+ |
|
+class item_enchant_visuals : public PlayerScript |
|
+{ |
|
+public: |
|
+ item_enchant_visuals() : PlayerScript("item_enchant_visuals") |
|
+ { |
|
+ // Create DB table on startup if doesnt exist |
|
+ const char* sql = |
|
+ "CREATE TABLE IF NOT EXISTS `custom_item_enchant_visuals` (" |
|
+ " `iguid` INT(10) UNSIGNED NOT NULL COMMENT 'item DB guid'," |
|
+ " `display` INT(10) UNSIGNED NOT NULL COMMENT 'enchantID'," |
|
+ " PRIMARY KEY (`iguid`)" |
|
+ ")" |
|
+ "COMMENT='stores the enchant IDs for the visuals'" |
|
+ "COLLATE='latin1_swedish_ci'" |
|
+ "ENGINE=InnoDB;"; |
|
+ CharacterDatabase.DirectExecute(sql); |
|
+ |
|
+ // Delete unused rows from DB table |
|
+ CharacterDatabase.DirectExecute("DELETE FROM custom_item_enchant_visuals WHERE NOT EXISTS(SELECT 1 FROM item_instance WHERE custom_item_enchant_visuals.iguid = item_instance.guid)"); |
|
+ } |
|
+ |
|
+ void OnLogin(Player* player, bool /*firstLogin*/) override |
|
+ { |
|
+ enchantStore.LoadPlayerEnchants(player->GetGUIDLow()); |
|
+ player->SetVisibleItemSlot(EQUIPMENT_SLOT_MAINHAND, player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND)); |
|
+ player->SetVisibleItemSlot(EQUIPMENT_SLOT_OFFHAND, player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND)); |
|
+ } |
|
+ |
|
+ void OnLogout(Player* player) override |
|
+ { |
|
+ enchantStore.DeletePlayerEnchants(player->GetGUIDLow()); |
|
+ } |
|
+}; |
|
+ |
|
+void AddSC_item_enchant_visuals() |
|
+{ |
|
+ new item_enchant_visuals; |
|
+} |
Is it working for latest trinitycore??