eluna-scripts-ornfelt/lua/WowEmulationScriptPack/patch/ItemEnchantVisuals.diff

311 lines
11 KiB
Diff
Raw Permalink Normal View History

2023-08-16 00:50:59 +02:00
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;
+}