new version commit

This commit is contained in:
mikx
2025-09-29 02:27:58 -04:00
commit 3e8d31e686
9244 changed files with 7357899 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
[*]
charset = utf-8
indent_style = space
indent_size = 4
tab_width = 4
insert_final_newline = true
trim_trailing_whitespace = true
max_line_length = 80

105
modules/mod-item-upgrade/.gitattributes vendored Normal file
View File

@@ -0,0 +1,105 @@
## AUTO-DETECT
## Handle line endings automatically for files detected as
## text and leave all files detected as binary untouched.
## This will handle all files NOT defined below.
* text=auto eol=lf
# Text
*.conf text
*.conf.dist text
*.cmake text
## Scripts
*.sh text
*.fish text
*.lua text
## SQL
*.sql text
## C++
*.c text
*.cc text
*.cxx text
*.cpp text
*.c++ text
*.hpp text
*.h text
*.h++ text
*.hh text
## For documentation
# Documents
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain
## DOCUMENTATION
*.markdown text
*.md text
*.mdwn text
*.mdown text
*.mkd text
*.mkdn text
*.mdtxt text
*.mdtext text
*.txt text
AUTHORS text
CHANGELOG text
CHANGES text
CONTRIBUTING text
COPYING text
copyright text
*COPYRIGHT* text
INSTALL text
license text
LICENSE text
NEWS text
readme text
*README* text
TODO text
## GRAPHICS
*.ai binary
*.bmp binary
*.eps binary
*.gif binary
*.ico binary
*.jng binary
*.jp2 binary
*.jpg binary
*.jpeg binary
*.jpx binary
*.jxr binary
*.pdf binary
*.png binary
*.psb binary
*.psd binary
*.svg text
*.svgz binary
*.tif binary
*.tiff binary
*.wbmp binary
*.webp binary
## ARCHIVES
*.7z binary
*.gz binary
*.jar binary
*.rar binary
*.tar binary
*.zip binary
## EXECUTABLES
*.exe binary
*.pyc binary

View File

@@ -0,0 +1,72 @@
name: Bug report
description: Create a bug report to help us improve.
title: "Bug: "
body:
- type: textarea
id: current
attributes:
label: Current Behaviour
description: |
Description of the problem or issue here.
Include entries of affected creatures / items / quests / spells etc.
If this is a crash, post the crashlog (upload to https://gist.github.com/) and include the link here.
Never upload files! Use GIST for text and YouTube for videos!
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected Behaviour
description: |
Tell us what should happen instead.
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: Steps to reproduce the problem
description: |
What does someone else need to do to encounter the same bug?
placeholder: |
1. Step 1
2. Step 2
3. Step 3
validations:
required: true
- type: textarea
id: extra
attributes:
label: Extra Notes
description: |
Do you have any extra notes that can help solve the issue that does not fit any other field?
placeholder: |
None
validations:
required: false
- type: textarea
id: commit
attributes:
label: AC rev. hash/commit
description: |
Copy the result of the `.server debug` command (if you need to run it from the client get a prat addon)
validations:
required: true
- type: input
id: os
attributes:
label: Operating system
description: |
The Operating System the Server is running on.
i.e. Windows 11 x64, Debian 10 x64, macOS 12, Ubuntu 20.04
validations:
required: true
- type: textarea
id: custom
attributes:
label: Custom changes or Modules
description: |
List which custom changes or modules you have applied, i.e. Eluna module, etc.
placeholder: |
None
validations:
required: false

View File

@@ -0,0 +1,33 @@
name: Feature request
description: Suggest an idea for this project
title: "Feature: "
body:
- type: markdown
attributes:
value: |
Thank you for taking your time to fill out a feature request. Remember to fill out all fields including the title above.
An issue that is not properly filled out will be closed.
- type: textarea
id: description
attributes:
label: Describe your feature request or suggestion in detail
description: |
A clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
id: solution
attributes:
label: Describe a possible solution to your feature or suggestion in detail
description: |
A clear and concise description of any alternative solutions or features you've considered.
validations:
required: false
- type: textarea
id: additional
attributes:
label: Additional context
description: |
Add any other context or screenshots about the feature request here.
validations:
required: false

View File

@@ -0,0 +1,112 @@
# ![logo](https://raw.githubusercontent.com/azerothcore/azerothcore.github.io/master/images/logo-github.png) AzerothCore
# Item upgrades for AzerothCore
## Overview
Adds the possibility to individually upgrade items. **EVERY** stat can be upgraded, provided you enable them in the .conf file and add them in database. Upgrades are rank-based, meaning you can incrementally upgrade each stat, starting with rank 1 to rank n. Players will need to purchase the previous rank in order to advance to the next. Stats that can be upgraded along with their ranks are in reloadable tables, meaning you can add stats and/or ranks, modify or even delete them without restarting the server. Player's upgrades will be updated accordingly after the data is reloaded.
## Limitations
1. Due to the nature of **WOTLK** client, the upgraded **STATS** will only be visible to the owner. Also, items with random properties (like "of the Bear", "of Intellect" etc) will always send the original stats. **This is only visual, stats will be there nonetheless!**
2. You **CAN'T** add or replace stats, you can only upgrade current item's stats.
3. Upgrades will be lost (of course) when trading, sending mail, depositing to guild bank, deposit to auction.
4. Heirlooms can't be upgraded.
## How to install
1. Clone this repository to your AzerothCore repo modules folder. You should now have mod-item-upgrade there.
2. Re-run cmake to generate the solution.
3. Re-build your project.
4. You should have mod_item_upgrade.conf.dist copied in configs/modules after building, copy this to configs/modules in your server's base directory.
5. Start the server, .sql files should automatically be imported in DB, if not, apply them manually.
WARNING: this mod requires at least this version of AzerothCore https://github.com/azerothcore/azerothcore-wotlk/commit/87fbdb7967094f19a00a3e5623115588c689cae6
## How to use
Let's say you want players to be able to upgrade **STAMINA** by 5% and 10% respectively. All you need to do is insert **two** lines in **mod_item_upgrade_stats** table:
* **id** - this is an unique identifier for this stat/rank, just choose the next available id (current maximum + 1), try to keep it consecutive
* **stat_type** - since we want stamina, put 7 for this. This column corresponds to **ItemModType** enum in **ItemTemplate.h**. Consult this enum to find each stat, the enum names should be self-explanatory. **EVERY** stat is allowed for upgrade!
* **stat_mod_pct** - percentage increase for the rank, since we want 5% and 10%, put **5** for first line and **10** for second line.
* **stat_rank** - this **MUST ALWAYS** start with 1 and be consecutive. Each rank **MUST ALWAYS** be an upgrade, meaning **stat_mod_pct** for rank **x** must be **SMALLER** that **stat_mod_pct** for rank **x+1**. So put **1** for the **5%** increase line and **2** for the **10%** increase line. If later you want to add the upgrade possibility to **20%** for stamina, just add another line with **stat_mod_pct** = 20 and **stat_rank** = 3.
Let's say you inserted the two lines and their **id** is 10 (for rank 1) and 11 (for rank 2). Now players are ready to upgrade item's stamina by 5% and 10% respectively. But now they **CAN** do it for free, since these two ranks have no requirements! If you want these ranks to have some requirements, let's use the second table **mod_item_upgrade_stats_req**:
* **id** - this is just an unique identifier with AUTO_INCREMENT, just leave it null and MySQL will generate an id for you
* **stat_id** - this corresponds to **mod_item_upgrade_stats.id**, in our case we have 10 (for rank 1) and 11 (for rank 2).
* **req_type** - type of requirement, this corresponds to **UpgradeStatReqType** enum in **item_upgrade.h**. Possible values:
* 1 - requires **money**
* 2 - requires **honor points**
* 3 - requires **arena points**
* 4 - requires **item(s)**
* 5 - requires **NOTHING**, has no effect whether added or not in this table, should not be used here, only in **mod_item_upgrade_stats_req_override** (see below)
* **req_val1** - based on **req_type**:
* when req_type = 1 (money), then this is a numeric value corresponding to the amount of required **copper** (e.g 10000000 means the rank will require 1000 gold to be bought)
* when req_type = 2 (honor), then this is a numeric value corresponding to how many honor points are required to buy the rank
* when req_type = 3 (arena), then this is a numeric value corresponding to how many arena points are required to buy the rank
* when req_type = 4 (item), then this is the **entry** (see **item_template.entry**) of the required item(s) to buy the rank
* **req_val2** - based on **req_type**:
* **UNUSED** when req_type is not 4
* when req_type = 4 (item), then this is the amount of **req_val1** item(s) required to buy the rank
So let's say you want players to upgrade stamina by 5% for **FREE**, then you don't have to insert anything in this table for **stat_id** 10. But for the 10% increase, you want the players to have 10x Badge of Justice and 1000 honor. So, we need to insert two lines: one with **stat_id** = 11, **req_type** = 2 (honor) and **req_val1** = 1000 and another line with **stat_id** = 11, **req_type** = 4 (item), **req_val1** = 29434 (entry for Badge of Justice) and **req_val2** = 10 (requires 10x badges).
There is some sample data already inserted in these tables.
### Overriding requirements on per item basis
**mod_item_upgrade_stats_req** will be used to globally define requirements for each rank. This means that **EVERY** item will have the same requirements for a certain rank. We can override this behaviour and set requirements for each item individually. For this, use **mod_item_upgrade_stats_req_override** table which has the exact same structure as **mod_item_upgrade_stats_req**, except there is one more field: **item_entry** which is the entry of the item. So simply follow the above procedure to add requirements and simply fill **item_entry** with the entry of the item that you want.
### Allowing and blacklisting items
You can allow or blacklist certain items by using two tables:
* **mod_item_upgrade_allowed_items** - if you add some entries to this table, then **ONLY** these items will be available for upgrade. This is useful when you want to exclude **ALL** items and only add a few that have the possibily to be upgraded.
* **mod_item_upgrade_blacklisted_items** - every item that is added here will no longer be available for upgrading. This is useful when you want to add upgrade possibility to **ALL** items but simply exclude a few.
These two tables have only one column **entry** which corresponds to the entry of the item (**item_template.entry**). You can have the same entry in both allowed and blacklisted tables, in which case the item will become **blacklisted**. If players already bought some upgrades for a certain item and then you decide to **blacklist** that item, then the upgrade will become **inactive** (it will show as inactive in the Upgraded items menu). The upgrade will then become **active** if you decide to remove the blacklist for the item.
### Allowing and blacklisting **ranks** for items
There is the possibility to allow or blacklist **ranks** for certain items. Just like above, two tables are involved:
* **mod_item_upgrade_allowed_stats_items** - link a certain rank (**stat_id**, this points to **mod_item_upgrade_stats.id**) with as many items as you want. If there are records for a certain **stat_id**, this means that **ONLY** these items will be able to gain/use this rank.
* **mod_item_upgrade_blacklisted_stats_items** - If there are records for a certain **stat_id**, this means that these items will no longer be able to gain/use this rank.
### Random upgrades on loot
There are configurable options to automatically upgrade items when players loot them (Titanforging-like system). Maximum possible rank gained by each stat is configurable via **ItemUpgrade.RandomUpgradeMaxRank** option. The chance for an automatic upgrade to occur is configurable via **ItemUpgrade.RandomUpgradeChance**. The maximum number of stats that can be upgraded is also configurable via **ItemUpgrade.RandomUpgradeMaxStatCount**. Stats to be upgraded are chosen **randomly**. Rewarded quest items and items looted via party (need, greed rolls) are also eligible for automatic upgrades.
## Ingame usage
Use .npc add 200003 to spawn the Master Item Upgrade NPC. The rest is self explanatory.
### Editing related tables and hot-reloading data
Everything is reloadable, meaning you can **add** stats and rank(s), **modify** current ranks, **delete** stats and ranks, add **allowed** and **blacklisted** items. The only table that you shouldn't manually modify is **character_item_upgrade**, as the data here will be validated against the main tables and orphaned records will be automatically deleted. However, modifying this table won't cause any harm, and you can actually manually delete or add character upgrades here if you want.
**WARNING**: before starting to edit database, you should **lock** the Gossip NPC so that players can't use it in the meantime. This is **NOT** required but **strongly** advised, in this way players can't buy some upgrades while you can potentially remove them in the background, etc. Locking the NPC is done via **.item_upgrade lock** command or via the **NPC itself** if the player has administrator role (GM level 3). After you locked the NPC and finished editing the database, you can use **.item_upgrade reload** command to reload everything. This will **correctly** refresh everything related to item upgrades for every connected player (stats, visuals) and will refresh the menus for the Gossip NPC.
### Removing upgrades from an item
There is a configuration option that allows players to restore items to their original stats (remove upgrades). You can also configure a **token** (and it's quantity) to be given to the player when purging an upgrade. You **can't** purge individual stats or ranks, there is no point, you can only remove **ALL** upgrades from an item at once.
## Weapon damage upgrades
This module adds the possibility to upgrade weapon damage (physical damage, dps - min/max damage). The system is toggleable via the configuration.
## Some photos
![pic1](https://github.com/silviu20092/mod-item-upgrade/blob/master/pics/pic1.jpg?raw=true)
![pic2](https://github.com/silviu20092/mod-item-upgrade/blob/master/pics/pic2.jpg?raw=true)
![pic3](https://github.com/silviu20092/mod-item-upgrade/blob/master/pics/pic3.jpg?raw=true)
![pic4](https://github.com/silviu20092/mod-item-upgrade/blob/master/pics/pic4.jpg?raw=true)
![pic4_1](https://github.com/silviu20092/mod-item-upgrade/blob/master/pics/pic4_1.jpg?raw=true)
![pic5](https://github.com/silviu20092/mod-item-upgrade/blob/master/pics/pic5.jpg?raw=true)
![pic6](https://github.com/silviu20092/mod-item-upgrade/blob/master/pics/pic6.jpg?raw=true)
![pic7](https://github.com/silviu20092/mod-item-upgrade/blob/master/pics/pic7.jpg?raw=true)
![pic8](https://github.com/silviu20092/mod-item-upgrade/blob/master/pics/pic8.jpg?raw=true)
![pic9](https://github.com/silviu20092/mod-item-upgrade/blob/master/pics/pic9.jpg?raw=true)
![pic10](https://github.com/silviu20092/mod-item-upgrade/blob/master/pics/pic10.jpg?raw=true)
![pic11](https://github.com/silviu20092/mod-item-upgrade/blob/master/pics/pic11.jpg?raw=true)
![pic12](https://github.com/silviu20092/mod-item-upgrade/blob/master/pics/pic12.jpg?raw=true)
## Credits
- silviu20092

View File

@@ -0,0 +1,11 @@
name: core-build
on:
push:
pull_request:
workflow_dispatch:
jobs:
build:
uses: azerothcore/reusable-workflows/.github/workflows/core_build_modules.yml@main
with:
module_repo: ${{ github.event.repository.name }}

View File

@@ -0,0 +1,19 @@
name: Codestyle Checks
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
check-codestyle:
strategy:
fail-fast: false
runs-on: ubuntu-latest
name: Check Codestyling
steps:
- uses: actions/checkout@v2
- name: Check Codestyling
run: source ./apps/ci/ci-codestyle.sh

48
modules/mod-item-upgrade/.gitignore vendored Normal file
View File

@@ -0,0 +1,48 @@
!.gitignore
#
#Generic
#
.directory
.mailmap
*.orig
*.rej
*.*~
.hg/
*.kdev*
.DS_Store
CMakeLists.txt.user
*.bak
*.patch
*.diff
*.REMOTE.*
*.BACKUP.*
*.BASE.*
*.LOCAL.*
#
# IDE & other softwares
#
/.settings/
/.externalToolBuilders/*
# exclude in all levels
nbproject/
.sync.ffs_db
*.kate-swp
#
# Eclipse
#
*.pydevproject
.metadata
.gradle
tmp/
*.tmp
*.swp
*~.nib
local.properties
.settings/
.loadpath
.project
.cproject

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 AzerothCore
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

View File

@@ -0,0 +1,40 @@
#!/bin/bash
set -e
echo "Codestyle check script:"
echo
declare -A singleLineRegexChecks=(
["LOG_.+GetCounter"]="Use ObjectGuid::ToString().c_str() method instead of ObjectGuid::GetCounter() when logging. Check the lines above"
["[[:blank:]]$"]="Remove whitespace at the end of the lines above"
["\t"]="Replace tabs with 4 spaces in the lines above"
)
for check in ${!singleLineRegexChecks[@]}; do
echo " Checking RegEx: '${check}'"
if grep -P -r -I -n ${check} src; then
echo
echo "${singleLineRegexChecks[$check]}"
exit 1
fi
done
declare -A multiLineRegexChecks=(
["LOG_[^;]+GetCounter"]="Use ObjectGuid::ToString().c_str() method instead of ObjectGuid::GetCounter() when logging. Check the lines above"
["\n\n\n"]="Multiple blank lines detected, keep only one. Check the files above"
)
for check in ${!multiLineRegexChecks[@]}; do
echo " Checking RegEx: '${check}'"
if grep -Pzo -r -I ${check} src; then
echo
echo
echo "${multiLineRegexChecks[$check]}"
exit 1
fi
done
echo
echo "Everything looks good"

View File

View File

@@ -0,0 +1,240 @@
#
# Credits: silviu20092
#
[worldserver]
########################################
# Item upgrade module configuration
########################################
#
# ItemUpgrade.Enable
# Description: Enable the module or not. If the module is toggled off, items that were previously upgraded will lose their upgrade bonus.
# Re-enabling the module will restore the already upgraded item bonuses.
# Default: 0 - Disabled
# 1 - Enabled
#
ItemUpgrade.Enable = 1
#
# ItemUpgrade.AllowedStats
# Description: Stats that are allowed to be upgraded. These correspond to the ItemModType enum from ItemTemplate.h
# For example, to allow "Attack power" to be upgraded, there is ITEM_MOD_ATTACK_POWER = 38 in the enum,
# so just add it to the list of allowed stats. Values are separated by ,
# Items that were upgraded with a certain stat will LOSE their upgrade bonus if you remove the stat from
# allowed list. If you re-add the stat, the items will GAIN back their upgrade bonus for that stat.
# Default: 3,4,5,6,7,32,36,45
#
ItemUpgrade.AllowedStats = 3,4,5,6,7,32,36,45
#
# ItemUpgrade.SendUpgradedItemsPackets
# Description: Whether to send SMSG_ITEM_QUERY_SINGLE_RESPONSE for upgraded items. This will ensure that owner will see the stats correctly
# when reading item description. ONLY the owner will see the stats though and this DOES NOT work for items that have random
# properties (stats that are random after acquiring the item, such as "of the Bear" or "of Intellect" items). The limitation
# is due to WOTLK client nature and is not possible to be solved. Weapon upgrades (min/max damage increased) WILL also be
# visible for items with random properties.
# THIS ONLY AFFECTS VISUALS, UPGRADED STATS WILL BE THERE NONETHELESS!
# Default: 0 - Disabled
# 1 - Enabled
#
ItemUpgrade.SendUpgradedItemsPackets = 1
#
# ItemUpgrade.SendUpgradedItemsPacketsPrioritization
# Description: Since SMSG_ITEM_QUERY_SINGLE_RESPONSE is sent by item ENTRY and not by universal identifier (GUID) it means that if
# multiple items with the same entry have upgrades (whether stat upgrades or weapon upgrades) then the player will see
# the exact same stats and damage for ALL items with the same entry. So there must be some kind of prioritization,
# whether to choose the item with the most stat upgrades or with the highest weapon upgrade percentage.
# Example: if player has two Ramaladni's Blade of Culling and both items were upgraded, one with 5% weapon damage upgrade
# and the other with 10% weapon damage upgrade AND ItemUpgrade.SendUpgradedItemsPacketsPrioritization is 1
# then the player will see both weapons have 10% more damage. Again this is only VISUAL, stats are correctly
# calculated for both!
# Values : 0 - Prioritize upgraded stats (items with higher number of upgraded stats will be prioritized)
# 1 - Prioritize weapon upgrade (items with the highest weapon upgrade percentage will be prioritized)
# Default : 0
#
ItemUpgrade.SendUpgradedItemsPacketsPrioritization = 0
#
# ItemUpgrade.AllowUpgradesPurge
# Description: Allows the players to purge upgrades from their items.
# Default: 0 - Disabled
# 1 - Enabled
#
ItemUpgrade.AllowUpgradesPurge = 1
#
# ItemUpgrade.UpgradePurgeToken
# Description: Give the player a token (item) when purging an upgrade. This is just an item entry, can be anything. Only active when
# ItemUpgrade.AllowUpgradesPurge = 1
# Default: 0 - No token
# Item Entry - the entry of token
#
ItemUpgrade.UpgradePurgeToken = 0
#
# ItemUpgrade.UpgradePurgeTokenCount
# Description: How many ItemUpgrade.UpgradePurgeToken to give when players purge an upgrade. Only active when ItemUpgrade.AllowUpgradesPurge = 1
# and ItemUpgrade.UpgradePurgeToken is a valid item entry
# Default: 0 - No effect
# 1+ - count
#
ItemUpgrade.UpgradePurgeTokenCount = 0
#
# ItemUpgrade.RefundAllOnPurge
# Description: Refund all items/gold/honor/arena when purging that were used to upgrade the item. EVERYTHING is refunded, meaning if the item
# has rank 3 stamina for example, it will refund everything from rank 1 to 3. Only active when
# ItemUpgrade.AllowUpgradesPurge = 1
# Default: 1 - Refund everything that was used to upgrade the item
#
ItemUpgrade.RefundAllOnPurge = 1
#
# ItemUpgrade.RandomUpgradesOnLoot
# Description: Whether looted items (including from party loot, quest items) can be automatically upgraded. Titanforging-like system.
# Default: 0 - No
# 1 - Yes, automatic item upgrades enabled
#
ItemUpgrade.RandomUpgradesOnLoot = 0
#
# ItemUpgrade.RandomUpgradesBroadcastLoginMsg
# Description: Let players know that random item upgrades are ON via a message that will be sent when player logs in.
# Only has effect when ItemUpgrade.RandomUpgradesOnLoot = 1. Just set to "" (double quotes) if you don't want to broadcast anything.
# Default: |cffeb891a[ITEM UPGRADES SYSTEM]:|r Random item upgrades are active. You have a chance to gain stat upgrades on loot for eligible items.
#
ItemUpgrade.RandomUpgradesBroadcastLoginMsg = |cffeb891a[ITEM UPGRADES SYSTEM]:|r Random item upgrades are active. You have a chance to gain stat upgrades on loot for eligible items.
#
# ItemUpgrade.RandomUpgradeChance
# Description: Automatic upgrade chance, only has effect when ItemUpgrade.RandomUpgradesOnLoot = 1. Must be > 0.
# Default: 2 - 2% chance for items to be automatically upgraded when looted
#
ItemUpgrade.RandomUpgradeChance = 2
#
# ItemUpgrade.RandomUpgradeMaxStatCount
# Description: How many stats can be automatically upgraded. This will always be a roll between 1 and the value that you choose here. So if
# you choose 4 for example, a value between 1 and 4 will be rolled. If 3 is rolled, then 3 stats will be upgraded up to ItemUpgrade.RandomUpgradeMaxRank.
# The chosen stats are also random. If an item has LESS stats than the rolled value, then ALL stats will be upgraded up to ItemUpgrade.RandomUpgradeMaxRank.
# Choose a value between 1 and 10.
# Default: 2 - maximum 2 stats will be upgraded (so always 1 or 2 stats)
#
ItemUpgrade.RandomUpgradeMaxStatCount = 2
#
# ItemUpgrade.RandomUpgradeMaxRank
# Description: Maximum upgrade rank that can be chosen. This will always be a roll between 1 and the value that you choose here. So if
# you choose 3 for example, a value between 1 and 3 will be rolled. If 2 is rolled, then the stat will be upgraded to RANK 2.
# If there is no RANK n, then RANK n-1 is chosen, if RANK n-1 is still not available, then the next available rank is searched
# until found.
# Default: 3 - each stat can go up to RANK 3
#
ItemUpgrade.RandomUpgradeMaxRank = 3
#
# ItemUpgrade.RandomUpgradeWhenBuying
# Description: Whether items that are bought from vendors can be randomly upgraded
# Default: 0 - don't randomly upgrade bought items
#
ItemUpgrade.RandomUpgradeWhenBuying = 0
#
# ItemUpgrade.RandomUpgradeWhenLooting
# Description: Whether items that are looted can be randomly upgraded
# Default: 1 - randomly upgrade looted items
#
ItemUpgrade.RandomUpgradeWhenLooting = 1
#
# ItemUpgrade.RandomUpgradeWhenWinning
# Description: Whether items that are won by Need/Greel rolls in raid/party can be randomly upgraded
# Default: 1 - randomly upgrade won items
#
ItemUpgrade.RandomUpgradeWhenWinning = 1
#
# ItemUpgrade.RandomUpgradeOnQuestReward
# Description: Whether quest rewarded items can be randomly upgraded
# Default: 1 - randomly upgrade quest rewarded items
#
ItemUpgrade.RandomUpgradeOnQuestReward = 1
#
# ItemUpgrade.RandomUpgradeWhenCrafting
# Description: Whether crafted items can be randomly upgraded
# Default: 1 - randomly upgrade crafted items
#
ItemUpgrade.RandomUpgradeWhenCrafting = 1
#
# ItemUpgrade.UpgradeWeaponDamage
# Description: Shows a menu where weapon physical damage can be upgraded (min/max damage of a weapon)
# Default: 1 - show the menu
#
ItemUpgrade.UpgradeWeaponDamage = 1
#
# ItemUpgrade.UpgradeWeaponDamagePercents
# Description: A list of percentages (separated by comma) that the players can select when upgrading their weapons.
# Numbers here will be sorted ascending and they will act like ranks, players will have to purchase
# the previous rank (percentage) in order to buy the next one.
# For example: 5,10,15 - lets say that a player wants to upgrade the damage of a weapon by 10%; the player
# can't directly upgrade by 10%, the player will need to buy the 5% damage increase first.
# When a percentage is chosen for upgrade, weapon's physical min/max damage will be increased by this percent.
# Default: 5,10,15 - can choose to upgrade by 5%, 10% and 15% respectively
# Only takes effect when ItemUpgrade.UpgradeWeaponDamage is 1
#
ItemUpgrade.UpgradeWeaponDamagePercents = 5,10,15
#
# ItemUpgrade.UpgradeWeaponDamageToken
# Description: A token (item) that is to be used when players want to upgrade the damage of a weapon.
# Default: 0 - No token
# Item Entry - the entry of token
# Only takes effect when ItemUpgrade.UpgradeWeaponDamage is 1
#
ItemUpgrade.UpgradeWeaponDamageToken = 0
#
# ItemUpgrade.UpgradeWeaponDamageTokenCount
# Description: The number of ItemUpgrade.UpgradeWeaponDamageToken required to purchase a weapon damage rank.
# Default: 1 - 1x ItemUpgrade.UpgradeWeaponDamageToken
# Only takes effect when ItemUpgrade.UpgradeWeaponDamage is 1
# Only takes effect when ItemUpgrade.UpgradeWeaponDamageToken is a valid item
#
ItemUpgrade.UpgradeWeaponDamageTokenCount = 1
#
# ItemUpgrade.UpgradeWeaponDamageMoney
# Description: Money (copper) required for players to pay when buying a weapon damage upgrade.
# Default: 0 - No money
# Only takes effect when ItemUpgrade.UpgradeWeaponDamage is 1
#
ItemUpgrade.UpgradeWeaponDamageMoney = 0

View File

View File

@@ -0,0 +1,7 @@
DROP TABLE IF EXISTS `character_item_upgrade`;
CREATE TABLE `character_item_upgrade`(
`guid` int unsigned not null,
`item_guid` int unsigned not null,
`stat_id` int unsigned not null,
PRIMARY KEY (`guid`, `item_guid`, `stat_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

View File

@@ -0,0 +1,7 @@
DROP TABLE IF EXISTS `character_weapon_upgrade`;
CREATE TABLE `character_weapon_upgrade`(
`guid` int unsigned not null,
`item_guid` int unsigned not null,
`upgrade_perc` float not null,
PRIMARY KEY (`guid`, `item_guid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

View File

@@ -0,0 +1,5 @@
DROP TABLE IF EXISTS `mod_item_upgrade_allowed_items`;
CREATE TABLE `mod_item_upgrade_allowed_items`(
`entry` int unsigned not null,
PRIMARY KEY (`entry`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

View File

@@ -0,0 +1,6 @@
DROP TABLE IF EXISTS `mod_item_upgrade_allowed_stats_items`;
CREATE TABLE `mod_item_upgrade_allowed_stats_items`(
`stat_id` int unsigned not null,
`entry` int unsigned not null,
PRIMARY KEY (`stat_id`, `entry`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

View File

@@ -0,0 +1,5 @@
DROP TABLE IF EXISTS `mod_item_upgrade_blacklisted_items`;
CREATE TABLE `mod_item_upgrade_blacklisted_items`(
`entry` int unsigned not null,
PRIMARY KEY (`entry`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

View File

@@ -0,0 +1,6 @@
DROP TABLE IF EXISTS `mod_item_upgrade_blacklisted_stats_items`;
CREATE TABLE `mod_item_upgrade_blacklisted_stats_items`(
`stat_id` int unsigned not null,
`entry` int unsigned not null,
PRIMARY KEY (`stat_id`, `entry`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

View File

@@ -0,0 +1,25 @@
DROP TABLE IF EXISTS `mod_item_upgrade_stats`;
CREATE TABLE `mod_item_upgrade_stats`(
`id` int unsigned not null,
`stat_type` tinyint unsigned NOT NULL,
`stat_mod_pct` float not null,
`stat_rank` smallint unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `mod_item_upgrade_stats` (`id`, `stat_type`, `stat_mod_pct`, `stat_rank`) VALUES (1, 3, 5, 1);
INSERT INTO `mod_item_upgrade_stats` (`id`, `stat_type`, `stat_mod_pct`, `stat_rank`) VALUES (2, 4, 5, 1);
INSERT INTO `mod_item_upgrade_stats` (`id`, `stat_type`, `stat_mod_pct`, `stat_rank`) VALUES (3, 5, 5, 1);
INSERT INTO `mod_item_upgrade_stats` (`id`, `stat_type`, `stat_mod_pct`, `stat_rank`) VALUES (4, 6, 5, 1);
INSERT INTO `mod_item_upgrade_stats` (`id`, `stat_type`, `stat_mod_pct`, `stat_rank`) VALUES (5, 7, 5, 1);
INSERT INTO `mod_item_upgrade_stats` (`id`, `stat_type`, `stat_mod_pct`, `stat_rank`) VALUES (6, 32, 5, 1);
INSERT INTO `mod_item_upgrade_stats` (`id`, `stat_type`, `stat_mod_pct`, `stat_rank`) VALUES (7, 36, 5, 1);
INSERT INTO `mod_item_upgrade_stats` (`id`, `stat_type`, `stat_mod_pct`, `stat_rank`) VALUES (8, 45, 5, 1);
INSERT INTO `mod_item_upgrade_stats` (`id`, `stat_type`, `stat_mod_pct`, `stat_rank`) VALUES (9, 3, 10, 2);
INSERT INTO `mod_item_upgrade_stats` (`id`, `stat_type`, `stat_mod_pct`, `stat_rank`) VALUES (10, 4, 10, 2);
INSERT INTO `mod_item_upgrade_stats` (`id`, `stat_type`, `stat_mod_pct`, `stat_rank`) VALUES (11, 5, 10, 2);
INSERT INTO `mod_item_upgrade_stats` (`id`, `stat_type`, `stat_mod_pct`, `stat_rank`) VALUES (12, 6, 10, 2);
INSERT INTO `mod_item_upgrade_stats` (`id`, `stat_type`, `stat_mod_pct`, `stat_rank`) VALUES (13, 7, 10, 2);
INSERT INTO `mod_item_upgrade_stats` (`id`, `stat_type`, `stat_mod_pct`, `stat_rank`) VALUES (14, 32, 10, 2);
INSERT INTO `mod_item_upgrade_stats` (`id`, `stat_type`, `stat_mod_pct`, `stat_rank`) VALUES (15, 36, 10, 2);
INSERT INTO `mod_item_upgrade_stats` (`id`, `stat_type`, `stat_mod_pct`, `stat_rank`) VALUES (16, 45, 10, 2);

View File

@@ -0,0 +1,34 @@
DROP TABLE IF EXISTS `mod_item_upgrade_stats_req`;
CREATE TABLE `mod_item_upgrade_stats_req`(
`id` int unsigned not null AUTO_INCREMENT,
`stat_id` int unsigned not null,
`req_type` tinyint unsigned not null,
`req_val1` float not null,
`req_val2` float,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `mod_item_upgrade_stats_req` (`stat_id`, `req_type`, `req_val1`) VALUES (1, 1, 10000000);
INSERT INTO `mod_item_upgrade_stats_req` (`stat_id`, `req_type`, `req_val1`) VALUES (2, 1, 10000000);
INSERT INTO `mod_item_upgrade_stats_req` (`stat_id`, `req_type`, `req_val1`) VALUES (3, 1, 10000000);
INSERT INTO `mod_item_upgrade_stats_req` (`stat_id`, `req_type`, `req_val1`) VALUES (4, 1, 10000000);
INSERT INTO `mod_item_upgrade_stats_req` (`stat_id`, `req_type`, `req_val1`) VALUES (5, 1, 10000000);
INSERT INTO `mod_item_upgrade_stats_req` (`stat_id`, `req_type`, `req_val1`) VALUES (6, 1, 10000000);
INSERT INTO `mod_item_upgrade_stats_req` (`stat_id`, `req_type`, `req_val1`) VALUES (7, 1, 10000000);
INSERT INTO `mod_item_upgrade_stats_req` (`stat_id`, `req_type`, `req_val1`) VALUES (8, 1, 10000000);
INSERT INTO `mod_item_upgrade_stats_req` (`stat_id`, `req_type`, `req_val1`) VALUES (9, 1, 10000000);
INSERT INTO `mod_item_upgrade_stats_req` (`stat_id`, `req_type`, `req_val1`) VALUES (10, 1, 10000000);
INSERT INTO `mod_item_upgrade_stats_req` (`stat_id`, `req_type`, `req_val1`) VALUES (11, 1, 10000000);
INSERT INTO `mod_item_upgrade_stats_req` (`stat_id`, `req_type`, `req_val1`) VALUES (12, 1, 10000000);
INSERT INTO `mod_item_upgrade_stats_req` (`stat_id`, `req_type`, `req_val1`) VALUES (13, 1, 10000000);
INSERT INTO `mod_item_upgrade_stats_req` (`stat_id`, `req_type`, `req_val1`) VALUES (14, 1, 10000000);
INSERT INTO `mod_item_upgrade_stats_req` (`stat_id`, `req_type`, `req_val1`) VALUES (15, 1, 10000000);
INSERT INTO `mod_item_upgrade_stats_req` (`stat_id`, `req_type`, `req_val1`) VALUES (16, 1, 10000000);
INSERT INTO `mod_item_upgrade_stats_req` (`stat_id`, `req_type`, `req_val1`, `req_val2`) VALUES (9, 4, 29434, 100);
INSERT INTO `mod_item_upgrade_stats_req` (`stat_id`, `req_type`, `req_val1`, `req_val2`) VALUES (10, 4, 29434, 100);
INSERT INTO `mod_item_upgrade_stats_req` (`stat_id`, `req_type`, `req_val1`, `req_val2`) VALUES (11, 4, 29434, 100);
INSERT INTO `mod_item_upgrade_stats_req` (`stat_id`, `req_type`, `req_val1`, `req_val2`) VALUES (12, 4, 29434, 100);
INSERT INTO `mod_item_upgrade_stats_req` (`stat_id`, `req_type`, `req_val1`, `req_val2`) VALUES (13, 4, 29434, 100);
INSERT INTO `mod_item_upgrade_stats_req` (`stat_id`, `req_type`, `req_val1`, `req_val2`) VALUES (14, 4, 29434, 100);
INSERT INTO `mod_item_upgrade_stats_req` (`stat_id`, `req_type`, `req_val1`, `req_val2`) VALUES (15, 4, 29434, 100);
INSERT INTO `mod_item_upgrade_stats_req` (`stat_id`, `req_type`, `req_val1`, `req_val2`) VALUES (16, 4, 29434, 100);

View File

@@ -0,0 +1,10 @@
DROP TABLE IF EXISTS `mod_item_upgrade_stats_req_override`;
CREATE TABLE `mod_item_upgrade_stats_req_override` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`stat_id` int unsigned NOT NULL,
`item_entry` int unsigned NOT NULL,
`req_type` tinyint unsigned NOT NULL,
`req_val1` float DEFAULT NULL,
`req_val2` float DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

View File

@@ -0,0 +1 @@
CREATE UNIQUE INDEX `idx_stat` ON `mod_item_upgrade_stats` (`stat_type`, `stat_mod_pct`);

View File

@@ -0,0 +1 @@
ALTER TABLE `mod_item_upgrade_stats_req` MODIFY `req_val1` FLOAT;

View File

@@ -0,0 +1,10 @@
SET @Entry = 200003;
SET @Name = "Master";
SET @Subname = "Item Upgrades";
DELETE FROM `creature_template_model` WHERE `CreatureID` = @Entry;
DELETE FROM `creature_template` WHERE `entry` = @Entry;
INSERT INTO `creature_template` (`entry`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction`, `npcflag`, `scale`, `rank`, `dmgschool`, `baseattacktime`, `rangeattacktime`, `unit_class`, `unit_flags`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `AIName`, `MovementType`, `HoverHeight`, `RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`) VALUES
(@Entry, @Name, @Subname, null, 0, 80, 80, 2, 35, 1, 1, 0, 0, 2000, 0, 1, 2147483648, 7, 138936390, 0, 0, 0, '', 0, 1, 0, 0, 1, 0, 0, 'npc_item_upgrade');
INSERT INTO `creature_template_model` (`CreatureID`, `Idx`, `CreatureDisplayID`, `DisplayScale`, `Probability`, `VerifiedBuild`) VALUES (@Entry, 0, 19646, 1, 1, 0);

View File

@@ -0,0 +1,4 @@
DELETE FROM `command` WHERE `name`='item_upgrade reload';
INSERT INTO `command`(`name`, `security`, `help`) VALUES ('item_upgrade reload', 3, 'Syntax: .item_upgrade reload
Reloads all necessary data for the Item Upgrades module.');

View File

@@ -0,0 +1,4 @@
DELETE FROM `command` WHERE `name`='item_upgrade lock';
INSERT INTO `command`(`name`, `security`, `help`) VALUES ('item_upgrade lock', 3, 'Syntax: .item_upgrade lock
Locks the Item Upgrade NPC for safe database edit. Players won''t be able to use the NPC anymore, the lock will be released when using .item_upgrade reload command');

View File

@@ -0,0 +1,4 @@
DELETE FROM `command` WHERE `name`='item_upgrade list';
INSERT INTO `command`(`name`, `security`, `help`) VALUES ('item_upgrade list', 0, 'Syntax: .item_upgrade list
Lists player''s upgraded items, only searches through equipped items.');

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 693 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 723 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 837 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 800 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 826 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 837 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 657 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 825 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 720 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 705 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 553 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 KiB

View File

@@ -0,0 +1,25 @@
<!-- First of all, THANK YOU for your contribution. -->
## Changes Proposed:
-
-
## Issues Addressed:
<!-- If your fix has a relating issue, link it below -->
- Closes
## SOURCE:
<!-- If you can, include a source that can strengthen your claim -->
## Tests Performed:
<!-- Does it build without errors? Did you test in-game? What did you test? On which OS did you test? Describe any other tests performed -->
-
-
## How to Test the Changes:
<!-- Describe in a detailed step-by-step order how to test the changes -->
1.
2.
3.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,397 @@
/*
* Credits: silviu20092
*/
#ifndef _ITEM_UPGRADE_H_
#define _ITEM_UPGRADE_H_
#include <vector>
#include "GossipDef.h"
#include "Player.h"
#include "item_upgrade_config.h"
class ItemUpgrade
{
private:
ItemUpgrade();
~ItemUpgrade();
public:
enum PagedDataType
{
PAGED_DATA_TYPE_ITEMS,
PAGED_DATA_TYPE_STATS,
PAGED_DATA_TYPE_REQS,
PAGED_DATA_TYPE_UPGRADED_ITEMS,
PAGED_DATA_TYPE_UPGRADED_ITEMS_STATS,
PAGED_DATA_TYPE_ITEMS_FOR_PURGE,
PAGED_DATA_TYPE_ITEMS_BULK,
PAGED_DATA_TYPE_STATS_BULK,
PAGED_DATA_TYPE_STAT_UPGRADE_BULK,
PAGED_DATA_TYPE_REQS_BULK,
PAGED_DATA_TYPE_WEAPON_UPGRADE_ITEMS,
PAGED_DATA_TYPE_WEAPON_UPGRADE_PERCS,
PAGED_DATA_TYPE_WEAPON_UPGRADE_PERC_INFO,
PAGED_DATA_TYPE_WEAPON_UPGRADE_ITEMS_CHECK,
PAGED_DATA_TYPE_WEAPON_UPGRADE_ITEMS_CHECK_INFO,
MAX_PAGED_DATA_TYPE
};
enum IdentifierType
{
BASE_IDENTIFIER,
ITEM_IDENTIFIER,
FLOAT_IDENTIFIER
};
enum ItemVisualsPriority
{
PRIORITIZE_STATS,
PRIORITIZE_WEAPON_DAMAGE
};
struct Identifier
{
uint32 id;
std::string name;
std::string uiName;
GossipOptionIcon optionIcon;
Identifier() : id(0), optionIcon(GOSSIP_ICON_INTERACT_1) {}
virtual IdentifierType GetType() const
{
return BASE_IDENTIFIER;
}
};
struct ItemIdentifier : public Identifier
{
ObjectGuid guid;
IdentifierType GetType() const override
{
return ITEM_IDENTIFIER;
}
};
struct FloatIdentifier : public Identifier
{
float modPct;
IdentifierType GetType() const override
{
return FLOAT_IDENTIFIER;
}
};
struct UpgradeStat;
struct PagedData
{
static constexpr int PAGE_SIZE = 12;
uint32 totalPages;
uint32 currentPage;
bool reloaded;
PagedDataType type;
const UpgradeStat* upgradeStat;
ItemIdentifier item;
std::vector<Identifier *> data;
float pct;
PagedData() : totalPages(0), currentPage(0), reloaded(false), type(MAX_PAGED_DATA_TYPE), upgradeStat(nullptr), pct(0.0f) {}
void Reset();
void CalculateTotals();
void SortAndCalculateTotals();
bool IsEmpty() const;
const Identifier* FindIdentifierById(uint32 id) const;
};
typedef std::unordered_map<uint32, PagedData> PagedDataMap;
enum UpgradeStatReqType
{
REQ_TYPE_COPPER = 1,
REQ_TYPE_HONOR,
REQ_TYPE_ARENA,
REQ_TYPE_ITEM,
REQ_TYPE_NONE,
MAX_REQ_TYPE
};
struct UpgradeStatReq
{
/* Associated stat ID from UpgradeStat */
uint32 statId;
/*
Possible values:
1 = this rank requires money (copper, gold) to be bought
2 = this rank requires honor points to be bought
3 = this rank requires arena points to be bought
4 = this rank requires certain item(s) to be bought
*/
UpgradeStatReqType reqType;
/*
* If reqType = 1 THEN required copper to purchase rank
* If reqType = 2 THEN required honor points to purchase rank
* If reqType = 3 THEN required arena points to purchase rank
* If reqType = 4 THEN item ENTRY (from item_template.entry) required to purchase rank
*/
float reqVal1;
/*
* If reqType = 4 THEN item count required to purchase rank
* NOT USED otherwise
*/
float reqVal2;
UpgradeStatReq()
{
statId = 0;
reqType = MAX_REQ_TYPE;
reqVal1 = 0.0f;
reqVal2 = 0.0f;
}
UpgradeStatReq(uint32 statId, UpgradeStatReqType reqType, float reqVal1, float reqVal2)
: statId(statId), reqType(reqType), reqVal1(reqVal1), reqVal2(reqVal2) {}
UpgradeStatReq(uint32 statId, UpgradeStatReqType reqType, float reqVal1)
: statId(statId), reqType(reqType), reqVal1(reqVal1), reqVal2(0.0f) {}
UpgradeStatReq(uint32 statId, UpgradeStatReqType reqType)
: statId(statId), reqType(reqType), reqVal1(0.0f), reqVal2(0.0f) {}
};
typedef std::vector<UpgradeStatReq> StatRequirementContainer;
struct UpgradeStat
{
uint32 statId;
uint32 statType;
float statModPct;
uint16 statRank;
};
typedef std::vector<UpgradeStat> UpgradeStatContainer;
struct CharacterUpgrade
{
uint32 guid;
ObjectGuid itemGuid;
const UpgradeStat* upgradeStat;
float upgradeStatModPct;
};
typedef std::unordered_map<uint32, std::vector<CharacterUpgrade>> CharacterUpgradeContainer;
struct ItemUpgradeInfo
{
ObjectGuid itemGuid;
std::vector<const UpgradeStat*> upgrades;
const UpgradeStat* weaponUpgrade;
};
typedef std::set<uint32> ItemEntryContainer;
typedef std::unordered_map<uint32, std::set<uint32>> StatWithItemContainer;
public:
static ItemUpgrade* instance();
template <class Container, typename T>
static T* FindInContainer(const Container& c, const T& val)
{
typename Container::const_iterator citr = std::find_if(c.begin(), c.end(), [&](const T& value) { return value == val; });
return citr != c.end() ? (T*)(&*citr) : nullptr;
}
bool GetBoolConfig(ItemUpgradeBoolConfigs index) const;
std::string GetStringConfig(ItemUpgradeStringConfigs index) const;
float GetFloatConfig(ItemUpgradeFloatConfigs index) const;
int32 GetIntConfig(ItemUpgradeIntConfigs index) const;
void LoadConfig(bool reload);
void LoadFromDB(bool reload = false);
void BuildUpgradableItemCatalogue(const Player* player, PagedDataType type);
void BuildStatsUpgradeCatalogue(const Player* player, const Item* item);
void BuildStatsUpgradeCatalogueBulk(const Player* player, const Item* item);
void BuildStatsUpgradeByPctCatalogueBulk(const Player* player, const Item* item, float pct);
void BuildStatsRequirementsCatalogueBulk(const Player* player, const Item* item, float pct);
void BuildStatsRequirementsCatalogue(const Player* player, const UpgradeStat* upgradeStat, const Item* item);
void BuildAlreadyUpgradedItemsCatalogue(const Player* player, PagedDataType type);
void BuildItemUpgradeStatsCatalogue(const Player* player, const Item* item);
void BuildWeaponPercentUpgradesCatalogue(const Player* player, const Item* item);
void BuildWeaponUpgradesPercentInfoCatalogue(const Player* player, const Item* item, float pct);
void BuildWeaponUpgradeInfoCatalogue(const Player* player, const Item* item);
PagedData& GetPagedData(const Player* player);
PagedDataMap& GetPagedDataMap();
bool AddPagedData(Player* player, Creature* creature, uint32 page);
bool TakePagedDataAction(Player* player, Creature* creature, uint32 action);
bool IsValidItemForUpgrade(const Item* item, const Player* player) const;
bool IsValidWeaponForUpgrade(const Item* item, const Player* player) const;
int32 HandleStatModifier(const Player* player, uint8 slot, uint32 statType, int32 amount) const;
int32 HandleStatModifier(const Player* player, Item* item, uint32 statType, int32 amount, EnchantmentSlot slot) const;
std::pair<float, float> HandleWeaponModifier(const Player* player, uint8 slot, float minDamage, float maxDamage) const;
std::pair<float, float> HandleWeaponModifier(const Player* player, const Item* item, float minDamage, float maxDamag) const;
void HandleItemRemove(Player* player, Item* item);
void HandleCharacterRemove(uint32 guid);
void SetReloading(bool value);
bool GetReloading() const;
void HandleDataReload(bool apply);
void UpdateVisualCache(Player* player);
void VisualFeedback(Player* player);
bool ChooseRandomUpgrade(Player* player, Item* item);
void BuildWeaponUpgradeReqs();
static std::string StatTypeToString(uint32 statType);
static std::string EquipmentSlotToString(EquipmentSlots slot);
static std::vector<_ItemStat> LoadItemStatInfo(const Item* item);
static const _ItemStat* GetStatByType(const std::vector<_ItemStat>& statInfo, uint32 statType);
static std::pair<float, float> GetItemProtoDamage(const ItemTemplate* proto);
static std::pair<float, float> GetItemProtoDamage(const Item* item);
static std::string FormatFloat(float val, uint32 decimals = 2);
static std::string FormatIncrease(float prev, float next);
static int32 CalculateModPct(int32 value, const UpgradeStat* upgradeStat);
static float CalculateModPctF(float value, const UpgradeStat* upgradeStat);
std::vector<const UpgradeStat*> FindUpgradesForItem(const Player* player, const Item* item) const;
const UpgradeStat* FindUpgradeForWeapon(const Player* player, const Item* item) const;
bool IsInactiveStatUpgrade(const Item* item, const UpgradeStat* upgradeStat) const;
bool IsInactiveWeaponUpgrade() const;
public:
static std::string ItemIcon(const ItemTemplate* proto, uint32 width, uint32 height, int x, int y);
static std::string ItemIcon(const ItemTemplate* proto);
static std::string ItemNameWithLocale(const Player* player, const ItemTemplate* itemTemplate, int32 randomPropertyId);
static std::string ItemLink(const Player* player, const ItemTemplate* itemTemplate, int32 randomPropertyId);
static std::string ItemLink(const Player* player, const Item* item);
static void SendMessage(const Player* player, const std::string& message);
private:
static constexpr int VISUAL_FEEDBACK_SPELL_ID = 46331;
ItemUpgradeConfig cfg;
bool reloading;
std::vector<uint32> allowedStats;
UpgradeStatContainer upgradeStatList;
PagedDataMap playerPagedData;
CharacterUpgradeContainer characterUpgradeData;
ItemEntryContainer allowedItems;
ItemEntryContainer blacklistedItems;
StatWithItemContainer allowedStatItems;
StatWithItemContainer blacklistedStatItems;
std::map<float, std::vector<const ItemUpgrade::UpgradeStat*>> upgradesPctMap;
std::unordered_map<uint32, StatRequirementContainer> baseStatRequirements;
std::unordered_map<uint32, std::unordered_map<uint32, StatRequirementContainer>> overrideStatRequirements;
UpgradeStatContainer weaponUpgradeStats;
CharacterUpgradeContainer characterWeaponUpgradeData;
StatRequirementContainer weaponUpgradeReqs;
static bool CompareIdentifier(const Identifier* a, const Identifier* b);
static std::string CopperToMoneyStr(uint32 money, bool colored);
static std::string FormatItemLocation(const Player* player, const Item* item);
void CleanupDB(bool reload);
void LoadStatRequirements();
void LoadStatRequirementsOverrides();
void LoadUpgradeStats();
void LoadCharacterUpgradeData();
void LoadCharacterWeaponUpgradeData();
void LoadAllowedItems();
void LoadAllowedStatsItems();
void LoadBlacklistedItems();
void LoadBlacklistedStatsItems();
bool IsValidReqType(uint8 reqType) const;
bool ValidateReq(uint32 id, UpgradeStatReqType reqType, float val1, float val2, const std::string& table) const;
void AddItemToPagedData(const Item* item, const Player* player, PagedData& pagedData);
bool _AddPagedData(Player* player, const PagedData& pagedData, uint32 page) const;
void NoPagedData(Player* player, const PagedData& pagedData) const;
std::string ItemLinkForUI(const Item* item, const Player* player) const;
void MergeStatRequirements(std::unordered_map<uint32, StatRequirementContainer>& statRequirementMap, bool validate = true);
template <typename Func>
const UpgradeStat* _FindUpgradeStat(const UpgradeStatContainer& upgradeStatContainer, Func f) const
{
UpgradeStatContainer::const_iterator citer = std::find_if(upgradeStatContainer.begin(), upgradeStatContainer.end(), f);
if (citer != upgradeStatContainer.end())
return &*citer;
return nullptr;
}
const UpgradeStat* FindUpgradeStat(uint32 statId) const;
const UpgradeStat* FindUpgradeStat(uint32 statType, uint16 rank) const;
const UpgradeStat* FindWeaponUpgradeStat(float pct) const;
const UpgradeStat* FindNearestWeaponUpgradeStat(float pct) const;
const UpgradeStat* FindNextWeaponUpgradeStat(float pct) const;
std::vector<const UpgradeStat*> _FindUpgradesForItem(const CharacterUpgradeContainer& characterUpgradeDataContainer, const Player* player, const Item* item) const;
const UpgradeStat* FindUpgradeForItem(const Player* player, const Item* item, uint32 statType) const;
bool MeetsRequirement(const Player* player, const UpgradeStatReq& req) const;
bool MeetsRequirement(const Player* player, const UpgradeStat* upgradeStat, const Item* item) const;
bool MeetsRequirement(const Player* player, const StatRequirementContainer* reqs) const;
void TakeRequirements(Player* player, const UpgradeStat* upgradeStat, const Item* item);
void TakeRequirements(Player* player, const StatRequirementContainer* reqs);
void TakeWeaponUpgradeRequirements(Player* player);
bool PurchaseUpgrade(Player* player);
bool PurchaseWeaponUpgrade(Player* player);
void AddUpgradedItemToPagedData(const Item* item, const Player* player, PagedData& pagedData, const std::string &from);
void HandleDataReload(Player* player, bool apply);
std::vector<Item*> GetPlayerItems(const Player* player, bool inBankAlso) const;
bool IsAllowedItem(const Item* item) const;
bool IsBlacklistedItem(const Item* item) const;
void SendItemPacket(Player* player, Item* item) const;
std::pair<uint32, uint32> CalculateItemLevel(const Player* player, Item* item, const UpgradeStat* upgrade = nullptr) const;
public:
static uint32 CalculateItemLevelPublic(const Player* player, Item* item);
private:
std::pair<uint32, uint32> CalculateItemLevel(const Player* player, Item* item, std::unordered_map<uint32, const UpgradeStat*>) const;
void RemoveItemUpgradeFromContainer(CharacterUpgradeContainer& upgradesContainer, Player* player, Item* item);
void RemoveItemUpgrade(Player* player, Item* item);
void RemoveWeaponUpgrade(Player* player, Item* item);
bool AddUpgradeForNewItem(Player* player, Item* item, const UpgradeStat* upgrade, const _ItemStat* stat);
void AddItemUpgradeToDB(const Player* player, const Item* item, const UpgradeStat* upgrade) const;
const UpgradeStat* FindNearestUpgradeStat(uint32 statType, uint16 rank, const Item* item) const;
bool IsAllowedStatForItem(const Item* item, const UpgradeStat* upgrade) const;
bool IsBlacklistedStatForItem(const Item* item, const UpgradeStat* upgrade) const;
bool CanApplyUpgradeForItem(const Item* item, const UpgradeStat* upgrade) const;
Item* FindItemIdentifierFromPage(const PagedData& pagedData, uint32 id, Player* player) const;
void CreateUpgradesPctMap();
std::unordered_map<uint32, const UpgradeStat*> FindAllUpgradeableRanks(const Player* player, const Item* item, float pct) const;
StatRequirementContainer BuildBulkRequirements(const std::unordered_map<uint32, const UpgradeStat*>& upgrades, const Item* item) const;
void BuildRequirementsPage(const Player* player, PagedData& pagedData, const StatRequirementContainer* reqs) const;
bool PurchaseUpgradeBulk(Player* player);
bool HandlePurchaseRank(Player* player, Item* item, const UpgradeStat* upgrade);
bool HandlePurchaseWeaponUpgrade(Player* player, Item* item, const UpgradeStat* upgrade);
bool CheckDataValidity() const;
bool IsValidStatType(uint32 statType) const;
const StatRequirementContainer* GetStatRequirements(const UpgradeStat* upgrade, const Item* item) const;
bool EmptyRequirements(const StatRequirementContainer* reqs) const;
void EquipItem(Player* player, Item* item);
bool TryRefundRequirements(Player* player, const StatRequirementContainer& reqs);
bool RefundEverything(Player* player, Item* item, const std::vector<const ItemUpgrade::UpgradeStat*>& upgrades);
bool TryAddItem(Player* player, uint32 entry, uint32 count, bool add);
bool IsAllowedStatType(uint32 statType) const;
void LoadAllowedStats(const std::string& stats);
void LoadWeaponUpgradePercents(const std::string& percents);
bool MeetsWeaponUpgradeRequirement(const Player* player) const;
bool PurgeUpgrade(Player* player, Item* item);
bool PurgeWeaponUpgrade(Player* player, Item* item);
ItemVisualsPriority GetItemVisualsPriority() const;
};
#define sItemUpgrade ItemUpgrade::instance()
#endif

View File

@@ -0,0 +1,155 @@
/*
* Credits: silviu20092
*/
#include "ScriptMgr.h"
#include "Chat.h"
#include "CommandScript.h"
#include "item_upgrade.h"
using namespace Acore::ChatCommands;
class item_upgrade_commandscript : public CommandScript
{
private:
static std::unordered_map<uint32, uint32> cmdListUpgradesTimerMap;
static constexpr uint32 listUpgradesDiffTimer = 10000;
public:
item_upgrade_commandscript() : CommandScript("item_upgrade_commandscript") { }
ChatCommandTable GetCommands() const override
{
static ChatCommandTable itemUpgradeSubcommandTable =
{
{ "reload", HandleReloadModItemUpgrade, SEC_ADMINISTRATOR, Console::Yes },
{ "lock", HandleLockItemUpgrade, SEC_ADMINISTRATOR, Console::Yes },
{ "list", HandleListUpgrades, SEC_PLAYER, Console::No }
};
static ChatCommandTable itemUpgradeCommandTable =
{
{ "item_upgrade", itemUpgradeSubcommandTable }
};
return itemUpgradeCommandTable;
}
private:
static bool HandleReloadModItemUpgrade(ChatHandler* handler)
{
ItemUpgrade::PagedDataMap& pagedData = sItemUpgrade->GetPagedDataMap();
for (auto& itr : pagedData)
itr.second.reloaded = true;
sItemUpgrade->SetReloading(true);
sItemUpgrade->HandleDataReload(false);
sItemUpgrade->LoadFromDB(true);
sItemUpgrade->HandleDataReload(true);
sItemUpgrade->SetReloading(false);
handler->SendGlobalGMSysMessage("Item Upgrade module data successfully reloaded.");
return true;
}
static bool HandleLockItemUpgrade(ChatHandler* handler)
{
sItemUpgrade->SetReloading(true);
handler->SendSysMessage("Item Upgrade NPC is now locked, it is now safe to edit database tables. Release the lock by using .item_upgrade reload command");
return true;
}
static bool HandleListUpgrades(ChatHandler* handler, Optional<PlayerIdentifier> target)
{
if (!target)
target = PlayerIdentifier::FromTargetOrSelf(handler);
if (!target)
return false;
Player* player = target->GetConnectedPlayer();
uint32 currentTime = getMSTime();
uint32 lastTime = cmdListUpgradesTimerMap[player->GetGUID().GetCounter()];
uint32 diff = getMSTimeDiff(lastTime, currentTime);
if (lastTime > 0 && diff < listUpgradesDiffTimer)
{
handler->PSendSysMessage("Please try again in {} seconds.", (listUpgradesDiffTimer - diff) / 1000);
return true;
}
cmdListUpgradesTimerMap[player->GetGUID().GetCounter()] = currentTime;
uint32 upgradedItems = 0;
uint32 upgradedStats = 0;
uint32 weaponUpgrades = 0;
for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
{
if (const Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
{
std::vector<const ItemUpgrade::UpgradeStat*> upgrades = sItemUpgrade->FindUpgradesForItem(player, item);
const ItemUpgrade::UpgradeStat* weaponUpgrade = sItemUpgrade->FindUpgradeForWeapon(player, item);
if (!upgrades.empty() || weaponUpgrade != nullptr)
{
upgradedItems++;
std::string slot = ItemUpgrade::EquipmentSlotToString((EquipmentSlots)i);
handler->PSendSysMessage("{} [{}]", ItemUpgrade::ItemLink(player, item), slot);
if (!upgrades.empty())
{
upgradedStats += upgrades.size();
std::vector<_ItemStat> statInfo = ItemUpgrade::LoadItemStatInfo(item);
handler->PSendSysMessage("Found {} stat upgrades:", upgrades.size());
for (const auto* stat : upgrades)
{
const _ItemStat* foundStat = ItemUpgrade::GetStatByType(statInfo, stat->statType);
ASSERT(foundStat != nullptr);
std::ostringstream oss;
oss << "|cffb50505" << foundStat->ItemStatValue << "|r --> ";
oss << "|cff056e3a" << ItemUpgrade::CalculateModPct(foundStat->ItemStatValue, stat) << "|r";
std::ostringstream statusOss;
if (sItemUpgrade->IsInactiveStatUpgrade(item, stat))
statusOss << "|cffb50505INACTIVE|r";
else
statusOss << "|cff056e3aACTIVE|r";
handler->PSendSysMessage("{} increased by {}% [RANK {}] [{}] [{}]", ItemUpgrade::StatTypeToString(stat->statType), stat->statModPct, stat->statRank, oss.str(), statusOss.str());
}
}
if (weaponUpgrade != nullptr)
{
weaponUpgrades++;
std::pair<float, float> dmgInfo = ItemUpgrade::GetItemProtoDamage(item);
float upgradedMinDamage = std::floor(ItemUpgrade::CalculateModPctF(dmgInfo.first, weaponUpgrade));
float upgradedMaxDamage = std::ceil(ItemUpgrade::CalculateModPctF(dmgInfo.second, weaponUpgrade));
std::ostringstream statusOss;
if (sItemUpgrade->IsInactiveWeaponUpgrade())
statusOss << "|cffb50505INACTIVE|r";
else
statusOss << "|cff056e3aACTIVE|r";
handler->PSendSysMessage("This weapon is upgraded by {}%, [MIN DAMAGE {}], [MAX DAMAGE {}] [{}]",
ItemUpgrade::FormatFloat(weaponUpgrade->statModPct),
ItemUpgrade::FormatIncrease(dmgInfo.first, upgradedMinDamage),
ItemUpgrade::FormatIncrease(dmgInfo.second, upgradedMaxDamage),
statusOss.str());
}
handler->SendSysMessage("--------------- NEXT ITEM OR END ---------------");
}
}
}
if (upgradedItems == 0 && weaponUpgrades == 0)
handler->PSendSysMessage("{} does not have any upgrades.", player->GetPlayerName());
else
handler->PSendSysMessage("{} has a total of: {} upgraded item(s), {} upgraded stat(s), {} upgraded weapon(s).", player->GetPlayerName(), upgradedItems, upgradedStats, weaponUpgrades);
return true;
}
};
std::unordered_map<uint32, uint32> item_upgrade_commandscript::cmdListUpgradesTimerMap;
void AddSC_item_upgrade_commandscript()
{
new item_upgrade_commandscript();
}

View File

@@ -0,0 +1,85 @@
/*
* Credits: silviu20092
*/
#include "ItemTemplate.h"
#include "item_upgrade_config.h"
#include "Config.h"
#include "Player.h"
ItemUpgradeConfig::ItemUpgradeConfig()
{
memset(boolConfigs, 0, sizeof(boolConfigs));
memset(floatConfigs, 0, sizeof(floatConfigs));
memset(intConfigs, 0, sizeof(intConfigs));
}
void ItemUpgradeConfig::Initialize()
{
boolConfigs[CONFIG_ITEM_UPGRADE_ENABLED] = sConfigMgr->GetOption<bool>("ItemUpgrade.Enable", true);
boolConfigs[CONFIG_ITEM_UPGRADE_SEND_PACKETS] = sConfigMgr->GetOption<bool>("ItemUpgrade.SendUpgradedItemsPackets", false);
boolConfigs[CONFIG_ITEM_UPGRADE_ALLOW_PURGE] = sConfigMgr->GetOption<bool>("ItemUpgrade.AllowUpgradesPurge", false);
boolConfigs[CONFIG_ITEM_UPGRADE_REFUND_ALL_ON_PURGE] = sConfigMgr->GetOption<bool>("ItemUpgrade.RefundAllOnPurge", true);
boolConfigs[CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES] = sConfigMgr->GetOption<bool>("ItemUpgrade.RandomUpgradesOnLoot", false);
boolConfigs[CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_BUY] = sConfigMgr->GetOption<bool>("ItemUpgrade.RandomUpgradeWhenBuying", false);
boolConfigs[CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_LOOT] = sConfigMgr->GetOption<bool>("ItemUpgrade.RandomUpgradeWhenLooting", true);
boolConfigs[CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_WIN] = sConfigMgr->GetOption<bool>("ItemUpgrade.RandomUpgradeWhenWinning", true);
boolConfigs[CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_QUEST_REWARD] = sConfigMgr->GetOption<bool>("ItemUpgrade.RandomUpgradeOnQuestReward", true);
boolConfigs[CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_CRAFTING] = sConfigMgr->GetOption<bool>("ItemUpgrade.RandomUpgradeWhenCrafting", true);
boolConfigs[CONFIG_ITEM_UPGRADE_WEAPON_DAMAGE] = sConfigMgr->GetOption<bool>("ItemUpgrade.UpgradeWeaponDamage", true);
stringConfigs[CONFIG_ITEM_UPGRADE_ALLOWED_STATS] = sConfigMgr->GetOption<std::string>("ItemUpgrade.AllowedStats", "0,3,4,5,6,7,32,36,45");
stringConfigs[CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_LOGIN_MSG] = sConfigMgr->GetOption<std::string>("ItemUpgrade.RandomUpgradesBroadcastLoginMsg", "");
stringConfigs[CONFIG_ITEM_UPGRADE_WEAPON_DAMAGE_PERCENTS] = sConfigMgr->GetOption<std::string>("ItemUpgrade.UpgradeWeaponDamagePercents", "5,10,15");
floatConfigs[CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_CHANCE] = sConfigMgr->GetOption<float>("ItemUpgrade.RandomUpgradeChance", 2.0f);
if (floatConfigs[CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_CHANCE] <= 0.0f)
floatConfigs[CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_CHANCE] = 2.0f;
else if (floatConfigs[CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_CHANCE] > 100.0f)
floatConfigs[CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_CHANCE] = 100.0f;
intConfigs[CONFIG_ITEM_UPGRADE_SEND_PACKETS_PRIORITY] = sConfigMgr->GetOption<int32>("ItemUpgrade.SendUpgradedItemsPacketsPrioritization", 0);
intConfigs[CONFIG_ITEM_UPGRADE_PURGE_TOKEN] = sConfigMgr->GetOption<int32>("ItemUpgrade.UpgradePurgeToken", 0);
if (intConfigs[CONFIG_ITEM_UPGRADE_PURGE_TOKEN] < 0)
intConfigs[CONFIG_ITEM_UPGRADE_PURGE_TOKEN] = 0;
intConfigs[CONFIG_ITEM_UPGRADE_PURGE_TOKEN_COUNT] = sConfigMgr->GetOption<int32>("ItemUpgrade.UpgradePurgeTokenCount", 1);
if (intConfigs[CONFIG_ITEM_UPGRADE_PURGE_TOKEN_COUNT] < 1)
intConfigs[CONFIG_ITEM_UPGRADE_PURGE_TOKEN_COUNT] = 1;
intConfigs[CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_MAX_STATS] = sConfigMgr->GetOption<int32>("ItemUpgrade.RandomUpgradeMaxStatCount", 2);
if (intConfigs[CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_MAX_STATS] <= 0)
intConfigs[CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_MAX_STATS] = 2;
else if (intConfigs[CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_MAX_STATS] > MAX_ITEM_PROTO_STATS)
intConfigs[CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_MAX_STATS] = MAX_ITEM_PROTO_STATS;
intConfigs[CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_MAX_RANK] = sConfigMgr->GetOption<int32>("ItemUpgrade.RandomUpgradeMaxRank", 3);
if (intConfigs[CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_MAX_RANK] <= 0)
intConfigs[CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_MAX_RANK] = 3;
intConfigs[CONFIG_ITEM_UPGRADE_WEAPON_DAMAGE_TOKEN] = sConfigMgr->GetOption<int32>("ItemUpgrade.UpgradeWeaponDamageToken", 0);
if (intConfigs[CONFIG_ITEM_UPGRADE_WEAPON_DAMAGE_TOKEN] < 0)
intConfigs[CONFIG_ITEM_UPGRADE_WEAPON_DAMAGE_TOKEN] = 0;
intConfigs[CONFIG_ITEM_UPGRADE_WEAPON_DAMAGE_TOKEN_COUNT] = sConfigMgr->GetOption<int32>("ItemUpgrade.UpgradeWeaponDamageTokenCount", 1);
if (intConfigs[CONFIG_ITEM_UPGRADE_WEAPON_DAMAGE_TOKEN_COUNT] < 1)
intConfigs[CONFIG_ITEM_UPGRADE_WEAPON_DAMAGE_TOKEN_COUNT] = 1;
intConfigs[CONFIG_ITEM_UPGRADE_WEAPON_DAMAGE_MONEY] = sConfigMgr->GetOption<int32>("ItemUpgrade.UpgradeWeaponDamageMoney", 0);
if (intConfigs[CONFIG_ITEM_UPGRADE_WEAPON_DAMAGE_MONEY] < 0 || intConfigs[CONFIG_ITEM_UPGRADE_WEAPON_DAMAGE_MONEY] > MAX_MONEY_AMOUNT)
intConfigs[CONFIG_ITEM_UPGRADE_WEAPON_DAMAGE_MONEY] = 0;
}
bool ItemUpgradeConfig::GetBoolConfig(ItemUpgradeBoolConfigs index) const
{
return boolConfigs[index];
}
std::string ItemUpgradeConfig::GetStringConfig(ItemUpgradeStringConfigs index) const
{
return stringConfigs[index];
}
float ItemUpgradeConfig::GetFloatConfig(ItemUpgradeFloatConfigs index) const
{
return floatConfigs[index];
}
int32 ItemUpgradeConfig::GetIntConfig(ItemUpgradeIntConfigs index) const
{
return intConfigs[index];
}

View File

@@ -0,0 +1,72 @@
/*
* Credits: silviu20092
*/
#ifndef _ITEM_UPGRADE_CONFIG_H_
#define _ITEM_UPGRADE_CONFIG_H_
#include <string>
#include "Define.h"
enum ItemUpgradeBoolConfigs
{
CONFIG_ITEM_UPGRADE_ENABLED = 0,
CONFIG_ITEM_UPGRADE_SEND_PACKETS,
CONFIG_ITEM_UPGRADE_ALLOW_PURGE,
CONFIG_ITEM_UPGRADE_REFUND_ALL_ON_PURGE,
CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES,
CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_BUY,
CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_LOOT,
CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_WIN,
CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_QUEST_REWARD,
CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_CRAFTING,
CONFIG_ITEM_UPGRADE_WEAPON_DAMAGE,
MAX_ITEM_UPGRADE_BOOL_CONFIGS
};
enum ItemUpgradeStringConfigs
{
CONFIG_ITEM_UPGRADE_ALLOWED_STATS = 0,
CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_LOGIN_MSG,
CONFIG_ITEM_UPGRADE_WEAPON_DAMAGE_PERCENTS,
MAX_ITEM_UPGRADE_STRING_CONFIGS
};
enum ItemUpgradeFloatConfigs
{
CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_CHANCE = 0,
MAX_ITEM_UPGRADE_FLOAT_CONFIGS
};
enum ItemUpgradeIntConfigs
{
CONFIG_ITEM_UPGRADE_PURGE_TOKEN = 0,
CONFIG_ITEM_UPGRADE_PURGE_TOKEN_COUNT,
CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_MAX_STATS,
CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_MAX_RANK,
CONFIG_ITEM_UPGRADE_WEAPON_DAMAGE_TOKEN,
CONFIG_ITEM_UPGRADE_WEAPON_DAMAGE_TOKEN_COUNT,
CONFIG_ITEM_UPGRADE_WEAPON_DAMAGE_MONEY,
CONFIG_ITEM_UPGRADE_SEND_PACKETS_PRIORITY,
MAX_ITEM_UPGRADE_INT_CONFIGS
};
class ItemUpgradeConfig
{
private:
bool boolConfigs[MAX_ITEM_UPGRADE_BOOL_CONFIGS];
std::string stringConfigs[MAX_ITEM_UPGRADE_STRING_CONFIGS];
float floatConfigs[MAX_ITEM_UPGRADE_FLOAT_CONFIGS];
int32 intConfigs[MAX_ITEM_UPGRADE_INT_CONFIGS];
public:
ItemUpgradeConfig();
void Initialize();
bool GetBoolConfig(ItemUpgradeBoolConfigs index) const;
std::string GetStringConfig(ItemUpgradeStringConfigs index) const;
float GetFloatConfig(ItemUpgradeFloatConfigs index) const;
int32 GetIntConfig(ItemUpgradeIntConfigs index) const;
};
#endif

View File

@@ -0,0 +1,23 @@
/*
* Credits: silviu20092
*/
#include "ScriptMgr.h"
#include "item_upgrade.h"
class item_upgrade_itemscript : public AllItemScript
{
public:
item_upgrade_itemscript() : AllItemScript("item_upgrade_itemscript") {}
bool CanItemRemove(Player* player, Item* item) override
{
sItemUpgrade->HandleItemRemove(player, item);
return true;
}
};
void AddSC_item_upgrade_itemscript()
{
new item_upgrade_itemscript();
}

View File

@@ -0,0 +1,125 @@
/*
* Credits: silviu20092
*/
#include "ScriptMgr.h"
#include "DatabaseEnv.h"
#include "Player.h"
#include "item_upgrade.h"
class item_upgrade_playerscript : public PlayerScript
{
private:
class SendUpgradePackets : public BasicEvent
{
public:
SendUpgradePackets(Player* player) : player(player)
{
player->m_Events.AddEvent(this, player->m_Events.CalculateTime(DELAY_MS));
}
bool Execute(uint64 /*e_time*/, uint32 /*p_time*/)
{
sItemUpgrade->UpdateVisualCache(player);
return true;
}
private:
static constexpr uint64 DELAY_MS = 3000;
Player* player;
};
public:
item_upgrade_playerscript() : PlayerScript("item_upgrade_playerscript",
{
PLAYERHOOK_ON_APPLY_ITEM_MODS_BEFORE,
PLAYERHOOK_ON_APPLY_ENCHANTMENT_ITEM_MODS_BEFORE,
PLAYERHOOK_ON_AFTER_MOVE_ITEM_FROM_INVENTORY,
PLAYERHOOK_ON_DELETE_FROM_DB,
PLAYERHOOK_ON_LOGIN,
PLAYERHOOK_ON_LOOT_ITEM,
PLAYERHOOK_ON_GROUP_ROLL_REWARD_ITEM,
PLAYERHOOK_ON_QUEST_REWARD_ITEM,
PLAYERHOOK_ON_CREATE_ITEM,
PLAYERHOOK_ON_AFTER_STORE_OR_EQUIP_NEW_ITEM,
PLAYERHOOK_ON_APPLY_WEAPON_DAMAGE
}) {}
void OnPlayerApplyItemModsBefore(Player* player, uint8 slot, bool /*apply*/, uint8 /*itemProtoStatNumber*/, uint32 statType, int32& val) override
{
val = sItemUpgrade->HandleStatModifier(player, slot, statType, val);
}
void OnPlayerApplyEnchantmentItemModsBefore(Player* player, Item* item, EnchantmentSlot slot, bool /*apply*/, uint32 enchant_spell_id, uint32& enchant_amount) override
{
enchant_amount = sItemUpgrade->HandleStatModifier(player, item, enchant_spell_id, enchant_amount, slot);
}
void OnPlayerAfterMoveItemFromInventory(Player* player, Item* it, uint8 /*bag*/, uint8 /*slot*/, bool /*update*/) override
{
sItemUpgrade->HandleItemRemove(player, it);
}
void OnPlayerDeleteFromDB(CharacterDatabaseTransaction trans, uint32 guid) override
{
trans->Append("DELETE FROM character_item_upgrade WHERE guid = {}", guid);
trans->Append("DELETE FROM character_weapon_upgrade WHERE guid = {}", guid);
sItemUpgrade->HandleCharacterRemove(guid);
}
void OnPlayerLogin(Player* player) override
{
new SendUpgradePackets(player);
if (sItemUpgrade->GetBoolConfig(CONFIG_ITEM_UPGRADE_ENABLED) && sItemUpgrade->GetBoolConfig(CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES))
{
const std::string& loginMsg = sItemUpgrade->GetStringConfig(CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_LOGIN_MSG);
if (!loginMsg.empty())
ItemUpgrade::SendMessage(player, loginMsg);
}
}
void OnPlayerLootItem(Player* player, Item* item, uint32 /*count*/, ObjectGuid /*lootguid*/) override
{
if (sItemUpgrade->GetBoolConfig(CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_LOOT))
sItemUpgrade->ChooseRandomUpgrade(player, item);
}
void OnPlayerGroupRollRewardItem(Player* player, Item* item, uint32 /*count*/, RollVote /*voteType*/, Roll* /*roll*/) override
{
if (sItemUpgrade->GetBoolConfig(CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_WIN))
sItemUpgrade->ChooseRandomUpgrade(player, item);
}
void OnPlayerQuestRewardItem(Player* player, Item* item, uint32 /*count*/) override
{
if (sItemUpgrade->GetBoolConfig(CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_QUEST_REWARD))
sItemUpgrade->ChooseRandomUpgrade(player, item);
}
void OnPlayerCreateItem(Player* player, Item* item, uint32 /*count*/) override
{
if (sItemUpgrade->GetBoolConfig(CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_CRAFTING))
sItemUpgrade->ChooseRandomUpgrade(player, item);
}
void OnPlayerAfterStoreOrEquipNewItem(Player* player, uint32 /*vendorslot*/, Item* item, uint8 /*count*/, uint8 /*bag*/, uint8 /*slot*/, ItemTemplate const* /*pProto*/, Creature* /*pVendor*/, VendorItem const* /*crItem*/, bool /*bStore*/) override
{
if (sItemUpgrade->GetBoolConfig(CONFIG_ITEM_UPGRADE_RANDOM_UPGRADES_BUY))
sItemUpgrade->ChooseRandomUpgrade(player, item);
}
void OnPlayerApplyWeaponDamage(Player* player, uint8 slot, ItemTemplate const* /*proto*/, float& minDamage, float& maxDamage, uint8 damageIndex) override
{
if (damageIndex == 0)
{
std::pair<float, float> upgradedDmgInfo = sItemUpgrade->HandleWeaponModifier(player, slot, minDamage, maxDamage);
minDamage = upgradedDmgInfo.first;
maxDamage = upgradedDmgInfo.second;
}
}
};
void AddSC_item_upgrade_playerscript()
{
new item_upgrade_playerscript();
}

View File

@@ -0,0 +1,45 @@
/*
* Credits: silviu20092
*/
#include "ScriptMgr.h"
#include "Config.h"
#include "item_upgrade.h"
class item_upgrade_worldscript : public WorldScript
{
public:
item_upgrade_worldscript() : WorldScript("item_upgrade_worldscript",
{
WORLDHOOK_ON_AFTER_CONFIG_LOAD,
WORLDHOOK_ON_BEFORE_WORLD_INITIALIZED
}) {}
void OnAfterConfigLoad(bool reload) override
{
if (reload)
{
ItemUpgrade::PagedDataMap& pagedData = sItemUpgrade->GetPagedDataMap();
for (auto& itr : pagedData)
itr.second.reloaded = true;
sItemUpgrade->HandleDataReload(false);
}
sItemUpgrade->LoadConfig(reload);
if (reload)
sItemUpgrade->HandleDataReload(true);
}
void OnBeforeWorldInitialized() override
{
sItemUpgrade->LoadFromDB();
sItemUpgrade->BuildWeaponUpgradeReqs();
}
};
void AddSC_item_upgrade_worldscript()
{
new item_upgrade_worldscript();
}

View File

@@ -0,0 +1,19 @@
/*
* Credits: silviu20092
*/
void AddSC_item_upgrade_worldscript();
void AddSC_npc_item_upgrade();
void AddSC_item_upgrade_commandscript();
void AddSC_item_upgrade_playerscript();
void AddSC_item_upgrade_itemscript();
void Addmod_item_upgradeScripts()
{
AddSC_item_upgrade_worldscript();
AddSC_npc_item_upgrade();
AddSC_item_upgrade_commandscript();
AddSC_item_upgrade_playerscript();
AddSC_item_upgrade_itemscript();
}

View File

@@ -0,0 +1,224 @@
/*
* Credits: silviu20092
*/
#include "ScriptMgr.h"
#include "ScriptedGossip.h"
#include "Creature.h"
#include "Player.h"
#include "Item.h"
#include "item_upgrade.h"
class npc_item_upgrade : public CreatureScript
{
private:
bool CloseGossip(Player* player, bool retValue = true)
{
CloseGossipMenuFor(player);
return retValue;
}
static Item* GetPagedDataItem(const ItemUpgrade::PagedData& pagedData, Player* player)
{
Item* item = player->GetItemByGuid(pagedData.item.guid);
bool validItem = pagedData.type == ItemUpgrade::PAGED_DATA_TYPE_WEAPON_UPGRADE_PERC_INFO ? sItemUpgrade->IsValidWeaponForUpgrade(item, player) : sItemUpgrade->IsValidItemForUpgrade(item, player);
if (!validItem)
{
ItemUpgrade::SendMessage(player, "Item is no longer available for upgrade.");
return nullptr;
}
return item;
}
bool AddUpgradeWeaponsSubmenu(Player* player, Creature* creature)
{
ClearGossipMenuFor(player);
AddGossipItemFor(player, GOSSIP_ICON_BATTLE, "Choose a weapon to upgrade", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9);
AddGossipItemFor(player, GOSSIP_ICON_INTERACT_1, "See upgraded weapons", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10);
AddGossipItemFor(player, GOSSIP_ICON_CHAT, "<- [Back]", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF);
SendGossipMenuFor(player, DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
return true;
}
public:
npc_item_upgrade() : CreatureScript("npc_item_upgrade")
{
}
bool OnGossipHello(Player* player, Creature* creature) override
{
if (sItemUpgrade->GetReloading())
{
ItemUpgrade::SendMessage(player, "Item Upgrade data is being reloaded by an administrator, please retry.");
return CloseGossip(player);
}
sItemUpgrade->GetPagedData(player).reloaded = false;
if (!sItemUpgrade->GetBoolConfig(CONFIG_ITEM_UPGRADE_ENABLED))
AddGossipItemFor(player, GOSSIP_ICON_CHAT, "|cffb50505NOT AVAILABLE|r", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF);
else
{
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, "Choose an item to upgrade (by stat, one-by-one)", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, "Choose an item to upgrade (all stats at once)", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7);
if (sItemUpgrade->GetBoolConfig(CONFIG_ITEM_UPGRADE_ALLOW_PURGE))
AddGossipItemFor(player, GOSSIP_ICON_INTERACT_1, "Purge upgrades", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6);
AddGossipItemFor(player, GOSSIP_ICON_INTERACT_1, "See upgraded items", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3);
if (sItemUpgrade->GetBoolConfig(CONFIG_ITEM_UPGRADE_WEAPON_DAMAGE))
AddGossipItemFor(player, GOSSIP_ICON_BATTLE, "[Weapon damage upgrade system] ->", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8);
AddGossipItemFor(player, GOSSIP_ICON_BATTLE, "Update visual cache", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4);
if (player->GetSession()->GetSecurity() == SEC_ADMINISTRATOR)
AddGossipItemFor(player, GOSSIP_ICON_INTERACT_1, "Lock for database edit", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5, "The NPC will no longer be available to players until you release the lock with .item_upgrade reload command.", 0, false);
}
AddGossipItemFor(player, GOSSIP_ICON_CHAT, "Nevermind...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
SendGossipMenuFor(player, DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
return true;
}
bool OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action) override
{
ItemUpgrade::PagedData& pagedData = sItemUpgrade->GetPagedData(player);
if (sItemUpgrade->GetReloading() || pagedData.reloaded)
{
ItemUpgrade::SendMessage(player, "Item Upgrade data is being reloaded by an administrator, please retry.");
return CloseGossip(player, false);
}
if (sender == GOSSIP_SENDER_MAIN)
{
if (action == GOSSIP_ACTION_INFO_DEF)
{
ClearGossipMenuFor(player);
return OnGossipHello(player, creature);
}
else if (action == GOSSIP_ACTION_INFO_DEF + 1)
return CloseGossip(player);
else if (action == GOSSIP_ACTION_INFO_DEF + 2)
{
sItemUpgrade->BuildUpgradableItemCatalogue(player, ItemUpgrade::PAGED_DATA_TYPE_ITEMS);
return sItemUpgrade->AddPagedData(player, creature, 0);
}
else if (action == GOSSIP_ACTION_INFO_DEF + 3)
{
sItemUpgrade->BuildAlreadyUpgradedItemsCatalogue(player, ItemUpgrade::PAGED_DATA_TYPE_UPGRADED_ITEMS);
return sItemUpgrade->AddPagedData(player, creature, 0);
}
else if (action == GOSSIP_ACTION_INFO_DEF + 4)
{
sItemUpgrade->UpdateVisualCache(player);
sItemUpgrade->VisualFeedback(player);
return CloseGossip(player);
}
else if (action == GOSSIP_ACTION_INFO_DEF + 5)
{
sItemUpgrade->SetReloading(true);
return CloseGossip(player);
}
else if (action == GOSSIP_ACTION_INFO_DEF + 6)
{
sItemUpgrade->BuildAlreadyUpgradedItemsCatalogue(player, ItemUpgrade::PAGED_DATA_TYPE_ITEMS_FOR_PURGE);
return sItemUpgrade->AddPagedData(player, creature, 0);
}
else if (action == GOSSIP_ACTION_INFO_DEF + 7)
{
sItemUpgrade->BuildUpgradableItemCatalogue(player, ItemUpgrade::PAGED_DATA_TYPE_ITEMS_BULK);
return sItemUpgrade->AddPagedData(player, creature, 0);
}
else if (action == GOSSIP_ACTION_INFO_DEF + 8)
return AddUpgradeWeaponsSubmenu(player, creature);
else if (action == GOSSIP_ACTION_INFO_DEF + 9)
{
sItemUpgrade->BuildUpgradableItemCatalogue(player, ItemUpgrade::PAGED_DATA_TYPE_WEAPON_UPGRADE_ITEMS);
return sItemUpgrade->AddPagedData(player, creature, 0);
}
else if (action == GOSSIP_ACTION_INFO_DEF + 10)
{
sItemUpgrade->BuildAlreadyUpgradedItemsCatalogue(player, ItemUpgrade::PAGED_DATA_TYPE_WEAPON_UPGRADE_ITEMS_CHECK);
return sItemUpgrade->AddPagedData(player, creature, 0);
}
}
else if (sender == GOSSIP_SENDER_MAIN + 1)
{
uint32 id = action - GOSSIP_ACTION_INFO_DEF;
return sItemUpgrade->TakePagedDataAction(player, creature, id);
}
else if (sender == GOSSIP_SENDER_MAIN + 2)
{
uint32 page = action - GOSSIP_ACTION_INFO_DEF;
return sItemUpgrade->AddPagedData(player, creature, page);
}
else if (sender == GOSSIP_SENDER_MAIN + 9)
{
sItemUpgrade->BuildUpgradableItemCatalogue(player, ItemUpgrade::PAGED_DATA_TYPE_ITEMS);
return sItemUpgrade->AddPagedData(player, creature, 0);
}
else if (sender == GOSSIP_SENDER_MAIN + 10)
{
Item* item = GetPagedDataItem(pagedData, player);
if (item == nullptr)
return CloseGossip(player, false);
sItemUpgrade->BuildStatsUpgradeCatalogue(player, item);
return sItemUpgrade->AddPagedData(player, creature, 0);
}
else if (sender == GOSSIP_SENDER_MAIN + 11)
{
sItemUpgrade->BuildAlreadyUpgradedItemsCatalogue(player, ItemUpgrade::PAGED_DATA_TYPE_UPGRADED_ITEMS);
return sItemUpgrade->AddPagedData(player, creature, 0);
}
else if (sender == GOSSIP_SENDER_MAIN + 12)
{
sItemUpgrade->BuildUpgradableItemCatalogue(player, ItemUpgrade::PAGED_DATA_TYPE_ITEMS_BULK);
return sItemUpgrade->AddPagedData(player, creature, 0);
}
else if (sender == GOSSIP_SENDER_MAIN + 13)
{
Item* item = GetPagedDataItem(pagedData, player);
if (item == nullptr)
return CloseGossip(player, false);
sItemUpgrade->BuildStatsUpgradeCatalogueBulk(player, item);
return sItemUpgrade->AddPagedData(player, creature, 0);
}
else if (sender == GOSSIP_SENDER_MAIN + 14)
{
Item* item = GetPagedDataItem(pagedData, player);
if (item == nullptr)
return CloseGossip(player, false);
sItemUpgrade->BuildStatsUpgradeByPctCatalogueBulk(player, item, pagedData.pct);
return sItemUpgrade->AddPagedData(player, creature, 0);
}
else if (sender == GOSSIP_SENDER_MAIN + 15)
return AddUpgradeWeaponsSubmenu(player, creature);
else if (sender == GOSSIP_SENDER_MAIN + 16)
{
sItemUpgrade->BuildUpgradableItemCatalogue(player, ItemUpgrade::PAGED_DATA_TYPE_WEAPON_UPGRADE_ITEMS);
return sItemUpgrade->AddPagedData(player, creature, 0);
}
else if (sender == GOSSIP_SENDER_MAIN + 17)
{
Item* item = GetPagedDataItem(pagedData, player);
if (item == nullptr)
return CloseGossip(player, false);
sItemUpgrade->BuildWeaponPercentUpgradesCatalogue(player, item);
return sItemUpgrade->AddPagedData(player, creature, 0);
}
else if (sender == GOSSIP_SENDER_MAIN + 18)
return AddUpgradeWeaponsSubmenu(player, creature);
else if (sender == GOSSIP_SENDER_MAIN + 19)
{
sItemUpgrade->BuildAlreadyUpgradedItemsCatalogue(player, ItemUpgrade::PAGED_DATA_TYPE_WEAPON_UPGRADE_ITEMS_CHECK);
return sItemUpgrade->AddPagedData(player, creature, 0);
}
return false;
}
};
void AddSC_npc_item_upgrade()
{
new npc_item_upgrade();
}