mirror of
https://github.com/ornfelt/azerothcore_lua_scripts
synced 2026-08-22 06:26:03 -04:00
310 lines
11 KiB
Diff
310 lines
11 KiB
Diff
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;
|
|
+}
|