mirror of
https://github.com/ZhengPeiRu21/mod-reagent-bank
synced 2025-11-29 15:08:16 +08:00
Initial commit.
This commit is contained in:
8
.editorconfig
Normal file
8
.editorconfig
Normal 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
.gitattributes
vendored
Normal file
105
.gitattributes
vendored
Normal 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
|
||||
49
.github/workflows/core-build.yml
vendored
Normal file
49
.github/workflows/core-build.yml
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
name: core-build
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
compiler: [clang]
|
||||
runs-on: ubuntu-latest
|
||||
name: ${{ matrix.compiler }}
|
||||
env:
|
||||
COMPILER: ${{ matrix.compiler }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
repository: 'azerothcore/azerothcore-wotlk'
|
||||
ref: 'master'
|
||||
submodules: 'recursive'
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
path: 'modules/skeleton-module'
|
||||
- name: Cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: /home/runner/.ccache
|
||||
key: ccache:${{ matrix.compiler }}:${{ github.ref }}:${{ github.sha }}
|
||||
restore-keys: |
|
||||
ccache:${{ matrix.compiler }}:${{ github.ref }}
|
||||
ccache:${{ matrix.compiler }}
|
||||
- name: Configure OS
|
||||
run: source ./acore.sh install-deps
|
||||
env:
|
||||
CONTINUOUS_INTEGRATION: true
|
||||
- name: Create conf/config.sh
|
||||
run: source ./apps/ci/ci-conf.sh
|
||||
- name: Import db
|
||||
run: source ./apps/ci/ci-import-db.sh
|
||||
- name: Build
|
||||
run: source ./apps/ci/ci-compile.sh
|
||||
- name: Dry run
|
||||
run: source ./apps/ci/ci-worldserver-dry-run.sh
|
||||
- name: Check startup errors
|
||||
run: source ./apps/ci/ci-error-check.sh
|
||||
- name: Run unit tests
|
||||
run: source ./apps/ci/ci-run-unit-tests.sh
|
||||
48
.gitignore
vendored
Normal file
48
.gitignore
vendored
Normal 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
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 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.
|
||||
32
conf/conf.sh.dist
Normal file
32
conf/conf.sh.dist
Normal file
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
## CUSTOM SQL - Important file used by the db_assembler.sh
|
||||
## Keep only the required variables (base sql files or updates, depending on the DB)
|
||||
|
||||
## BASE SQL
|
||||
|
||||
DB_AUTH_CUSTOM_PATHS+=(
|
||||
"$MOD_SKELETON_ROOT/sql/auth/base/"
|
||||
)
|
||||
|
||||
DB_CHARACTERS_CUSTOM_PATHS+=(
|
||||
"$MOD_SKELETON_ROOT/sql/characters/base/"
|
||||
)
|
||||
|
||||
DB_WORLD_CUSTOM_PATHS+=(
|
||||
"$MOD_SKELETON_ROOT/sql/world/base/"
|
||||
)
|
||||
|
||||
## UPDATES
|
||||
|
||||
DB_AUTH_UPDATES_PATHS+=(
|
||||
"$MOD_SKELETON_ROOT/sql/auth/updates/"
|
||||
)
|
||||
|
||||
DB_CHARACTERS_UPDATES_PATHS+=(
|
||||
"$MOD_SKELETON_ROOT/sql/characters/updates/"
|
||||
)
|
||||
|
||||
DB_WORLD_UPDATES_PATHS+=(
|
||||
"$MOD_SKELETON_ROOT/sql/world/updates/"
|
||||
)
|
||||
17
conf/reagent_bank.conf.dist
Normal file
17
conf/reagent_bank.conf.dist
Normal file
@@ -0,0 +1,17 @@
|
||||
#
|
||||
# Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
#
|
||||
|
||||
[worldserver]
|
||||
|
||||
########################################
|
||||
# Reagent Bank Config
|
||||
########################################
|
||||
#
|
||||
# ReagentBank.Enable
|
||||
# Description: Enable the reagent bank
|
||||
# Default: 0 - Disabled
|
||||
# 1 - Enabled
|
||||
#
|
||||
|
||||
ReagentBank.Enable = 1
|
||||
10
include.sh
Normal file
10
include.sh
Normal file
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
## GETS THE CURRENT MODULE ROOT DIRECTORY
|
||||
MOD_SKELETON_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/" && pwd )"
|
||||
|
||||
source $MOD_SKELETON_ROOT"/conf/conf.sh.dist"
|
||||
|
||||
if [ -f $MOD_SKELETON_ROOT"/conf/conf.sh" ]; then
|
||||
source $MOD_SKELETON_ROOT"/conf/conf.sh"
|
||||
fi
|
||||
0
sql/auth/updates/.gitkeep
Normal file
0
sql/auth/updates/.gitkeep
Normal file
7
sql/characters/base/create_table.sql
Normal file
7
sql/characters/base/create_table.sql
Normal file
@@ -0,0 +1,7 @@
|
||||
CREATE TABLE IF NOT EXISTS `custom_reagent_bank` (
|
||||
`character_id` int(11) NOT NULL,
|
||||
`item_entry` int(11) NOT NULL,
|
||||
`item_subclass` int(11) NOT NULL,
|
||||
`amount` int(11) NOT NULL,
|
||||
PRIMARY KEY (`character_id`,`item_entry`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
0
sql/characters/updates/.gitkeep
Normal file
0
sql/characters/updates/.gitkeep
Normal file
7
sql/world/base/reagent_bank_NPC.sql
Normal file
7
sql/world/base/reagent_bank_NPC.sql
Normal file
@@ -0,0 +1,7 @@
|
||||
SET
|
||||
@Entry = 190011,
|
||||
@Name = "Ling";
|
||||
DELETE FROM `creature_template` WHERE `entry` = @Entry;
|
||||
|
||||
INSERT INTO `creature_template` (`entry`, `modelid1`, `modelid2`, `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, 15965, 0, @Name, 'Reagent Banker', NULL, 0, 6, 6, 0, 35, 1, 1, 0, 0, 2000, 0, 1, 0, 7, 138412032, 0, 0, 0, '', 0, 1, 0, 0, 1, 0, 2, 'npc_reagent_banker');
|
||||
0
sql/world/updates/.gitkeep
Normal file
0
sql/world/updates/.gitkeep
Normal file
271
src/ReagentBank.cpp
Normal file
271
src/ReagentBank.cpp
Normal file
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
*/
|
||||
|
||||
#include "ReagentBank.h"
|
||||
|
||||
// Add player scripts
|
||||
class npc_reagent_banker : public CreatureScript
|
||||
{
|
||||
private:
|
||||
std::string GetItemLink(uint32 entry, WorldSession* session) const
|
||||
{
|
||||
int loc_idx = session->GetSessionDbLocaleIndex();
|
||||
const ItemTemplate *temp = sObjectMgr->GetItemTemplate(entry);
|
||||
std::string name = temp->Name1;
|
||||
if (ItemLocale const* il = sObjectMgr->GetItemLocale(temp->ItemId))
|
||||
ObjectMgr::GetLocaleString(il->Name, loc_idx, name);
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << "|c" << std::hex << ItemQualityColors[temp->Quality] << std::dec <<
|
||||
"|Hitem:" << temp->ItemId << ":" <<
|
||||
(uint32)0 << "|h[" << name << "]|h|r";
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string GetItemIcon(uint32 entry, uint32 width, uint32 height, int x, int y) const
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "|TInterface";
|
||||
const ItemTemplate *temp = sObjectMgr->GetItemTemplate(entry);
|
||||
const ItemDisplayInfoEntry *dispInfo = NULL;
|
||||
if (temp)
|
||||
{
|
||||
dispInfo = sItemDisplayInfoStore.LookupEntry(temp->DisplayInfoID);
|
||||
if (dispInfo)
|
||||
ss << "/ICONS/" << dispInfo->inventoryIcon;
|
||||
}
|
||||
if (!dispInfo)
|
||||
ss << "/InventoryItems/WoWUnknownItem01";
|
||||
ss << ":" << width << ":" << height << ":" << x << ":" << y << "|t";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void WithdrawItem(Player* player, uint32 entry)
|
||||
{
|
||||
// This query can be changed to async to improve performance, but there will be some visual bugs because the query will not be done executing when the menu refreshes
|
||||
WorldSession *session = player->GetSession();
|
||||
|
||||
std::string query = "SELECT amount FROM custom_reagent_bank WHERE character_id = " + std::to_string(player->GetSession()->GetAccountId()) + " AND item_entry = " + std::to_string(entry);
|
||||
QueryResult result = CharacterDatabase.Query("SELECT amount FROM custom_reagent_bank WHERE character_id = " + std::to_string(player->GetSession()->GetAccountId()) + " AND item_entry = " + std::to_string(entry));
|
||||
if (result)
|
||||
{
|
||||
uint32 storedAmount = (*result)[0].Get<uint32>();
|
||||
const ItemTemplate *temp = sObjectMgr->GetItemTemplate(entry);
|
||||
uint32 stackSize = temp->GetMaxStackSize();
|
||||
if (storedAmount <= stackSize)
|
||||
{
|
||||
// Give the player all of the item and remove it from the DB
|
||||
ItemPosCountVec dest;
|
||||
InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, entry, storedAmount);
|
||||
if (msg == EQUIP_ERR_OK)
|
||||
{
|
||||
CharacterDatabase.Execute("DELETE FROM custom_reagent_bank WHERE character_id = {} AND item_entry = {}", player->GetGUID().GetCounter(), entry);
|
||||
Item* item = player->StoreNewItem(dest, entry, true);
|
||||
player->SendNewItem(item, storedAmount, true, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
player->SendEquipError(msg, nullptr, nullptr, entry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Give the player a single stack
|
||||
ItemPosCountVec dest;
|
||||
InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, entry, stackSize);
|
||||
if (msg == EQUIP_ERR_OK)
|
||||
{
|
||||
CharacterDatabase.Execute("UPDATE custom_reagent_bank SET amount = {} WHERE character_id = {} AND item_entry = {}", storedAmount - stackSize, player->GetGUID().GetCounter(), entry);
|
||||
Item* item = player->StoreNewItem(dest, entry, true);
|
||||
player->SendNewItem(item, stackSize, true, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
player->SendEquipError(msg, nullptr, nullptr, entry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateItemCount(std::map<uint32, uint32> &entryToAmountMap, std::map<uint32, uint32> &entryToSubclassMap, Item* pItem, Player* player, uint32 bagSlot, uint32 itemSlot)
|
||||
{
|
||||
uint32 count = pItem->GetCount();
|
||||
ItemTemplate const *itemTemplate = pItem->GetTemplate();
|
||||
if (itemTemplate->Class != ITEM_CLASS_TRADE_GOODS || itemTemplate->GetMaxStackSize() == 1)
|
||||
return;
|
||||
uint32 itemEntry = itemTemplate->ItemId;
|
||||
uint32 itemSubclass = itemTemplate->SubClass;
|
||||
if (!entryToAmountMap.count(itemEntry))
|
||||
{
|
||||
// Item does not exist yet in storage
|
||||
entryToAmountMap[itemEntry] = count;
|
||||
entryToSubclassMap[itemEntry] = itemSubclass;
|
||||
}
|
||||
else
|
||||
{
|
||||
entryToAmountMap[itemEntry] = entryToAmountMap.find(itemEntry)->second + count;
|
||||
}
|
||||
// The item counts have been updated, remove the original items from the player
|
||||
player->DestroyItem(bagSlot, itemSlot, true);
|
||||
}
|
||||
|
||||
void DepositAllReagents(Player* player) {
|
||||
WorldSession *session = player->GetSession();
|
||||
std::string query = "SELECT item_entry, item_subclass, amount FROM custom_reagent_bank WHERE character_id = " + std::to_string(player->GetGUID().GetCounter());
|
||||
session->GetQueryProcessor().AddCallback( CharacterDatabase.AsyncQuery(query).WithCallback([=](QueryResult result) {
|
||||
std::map<uint32, uint32> entryToAmountMap;
|
||||
std::map<uint32, uint32> entryToSubclassMap;
|
||||
if (result)
|
||||
{
|
||||
do {
|
||||
uint32 itemEntry = (*result)[0].Get<uint32>();
|
||||
uint32 itemSubclass = (*result)[1].Get<uint32>();
|
||||
uint32 itemAmount = (*result)[2].Get<uint32>();
|
||||
entryToAmountMap[itemEntry] = itemAmount;
|
||||
entryToSubclassMap[itemEntry] = itemSubclass;
|
||||
} while (result->NextRow());
|
||||
}
|
||||
// Inventory Items
|
||||
for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; ++i)
|
||||
{
|
||||
if (Item* pItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
|
||||
{
|
||||
UpdateItemCount(entryToAmountMap, entryToSubclassMap, pItem, player, INVENTORY_SLOT_BAG_0, i);
|
||||
}
|
||||
|
||||
}
|
||||
// Bag Items
|
||||
for (uint32 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
|
||||
{
|
||||
Bag* bag = player->GetBagByPos(i);
|
||||
if (!bag)
|
||||
continue;
|
||||
for (uint32 j = 0; j < bag->GetBagSize(); j++) {
|
||||
if (Item * pItem = player->GetItemByPos(i, j))
|
||||
{
|
||||
UpdateItemCount(entryToAmountMap, entryToSubclassMap, pItem, player, i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (entryToAmountMap.size() != 0)
|
||||
{
|
||||
auto trans = CharacterDatabase.BeginTransaction();
|
||||
for (std::pair<uint32, uint32> mapEntry : entryToAmountMap)
|
||||
{
|
||||
uint32 itemEntry = mapEntry.first;
|
||||
uint32 itemAmount = mapEntry.second;
|
||||
uint32 itemSubclass = entryToSubclassMap.find(itemEntry)->second;
|
||||
trans->Append("REPLACE INTO custom_reagent_bank (character_id, item_entry, item_subclass, amount) VALUES ({}, {}, {}, {})", player->GetGUID().GetCounter(), itemEntry, itemSubclass, itemAmount);
|
||||
}
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
}
|
||||
}));
|
||||
ChatHandler(player->GetSession()).PSendSysMessage("All reagents deposited successfully.");
|
||||
CloseGossipMenuFor(player);
|
||||
}
|
||||
|
||||
public:
|
||||
npc_reagent_banker() : CreatureScript("npc_reagent_banker") { }
|
||||
|
||||
bool OnGossipHello(Player* player, Creature* creature) override
|
||||
{
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, GetItemIcon(4359, 30, 30, -18, 0) + "Parts", ITEM_SUBCLASS_PARTS, 0);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, GetItemIcon(4358, 30, 30, -18, 0) + "Explosives", ITEM_SUBCLASS_EXPLOSIVES, 0);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, GetItemIcon(4388, 30, 30, -18, 0) + "Devices", ITEM_SUBCLASS_DEVICES, 0);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, GetItemIcon(1206, 30, 30, -18, 0) + "Jewelcrafting", ITEM_SUBCLASS_JEWELCRAFTING, 0);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, GetItemIcon(2589, 30, 30, -18, 0) + "Cloth", ITEM_SUBCLASS_CLOTH, 0);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, GetItemIcon(2318, 30, 30, -18, 0) + "Leather", ITEM_SUBCLASS_LEATHER, 0);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, GetItemIcon(2772, 30, 30, -18, 0) + "Metal & Stone", ITEM_SUBCLASS_METAL_STONE, 0);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, GetItemIcon(12208, 30, 30, -18, 0) + "Meat", ITEM_SUBCLASS_MEAT, 0);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, GetItemIcon(2453, 30, 30, -18, 0) + "Herb", ITEM_SUBCLASS_HERB, 0);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, GetItemIcon(7068, 30, 30, -18, 0) + "Elemental", ITEM_SUBCLASS_ELEMENTAL, 0);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, GetItemIcon(10940, 30, 30, -18, 0) + "Enchanting", ITEM_SUBCLASS_ENCHANTING, 0);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, GetItemIcon(23572, 30, 30, -18, 0) + "Nether Material", ITEM_SUBCLASS_MATERIAL, 0);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, GetItemIcon(2604, 30, 30, -18, 0) + "Other Trade Goods", ITEM_SUBCLASS_TRADE_GOODS_OTHER, 0);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, GetItemIcon(38682, 30, 30, -18, 0) + "Armor Vellum", ITEM_SUBCLASS_ARMOR_ENCHANTMENT, 0);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, GetItemIcon(39349, 30, 30, -18, 0) + "Weapon Vellum", ITEM_SUBCLASS_WEAPON_ENCHANTMENT, 0);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, "Deposit All Reagents", DEPOSIT_ALL_REAGENTS, 0);
|
||||
SendGossipMenuFor(player, NPC_TEXT_ID, creature->GetGUID());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnGossipSelect(Player* player, Creature* creature, uint32 item_subclass, uint32 gossipPageNumber) override
|
||||
{
|
||||
player->PlayerTalkClass->ClearMenus();
|
||||
if (item_subclass > MAX_PAGE_NUMBER)
|
||||
{
|
||||
// item_subclass is actually an item ID to withdraw
|
||||
// Get the actual item subclass from the template
|
||||
const ItemTemplate *temp = sObjectMgr->GetItemTemplate(item_subclass);
|
||||
WithdrawItem(player, item_subclass);
|
||||
ShowReagentItems(player, creature, temp->SubClass, gossipPageNumber);
|
||||
return true;
|
||||
}
|
||||
if (item_subclass == DEPOSIT_ALL_REAGENTS)
|
||||
{
|
||||
DepositAllReagents(player);
|
||||
return true;
|
||||
}
|
||||
else if (item_subclass == MAIN_MENU)
|
||||
{
|
||||
OnGossipHello(player, creature);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowReagentItems(player, creature, item_subclass, gossipPageNumber);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void ShowReagentItems(Player* player, Creature* creature, uint32 item_subclass, uint16 gossipPageNumber)
|
||||
{
|
||||
WorldSession* session = player->GetSession();
|
||||
std::string query = "SELECT item_entry, amount FROM custom_reagent_bank WHERE character_id = " + std::to_string(player->GetSession()->GetAccountId()) + " AND item_subclass = " +
|
||||
std::to_string(item_subclass) + " ORDER BY item_entry";
|
||||
session->GetQueryProcessor().AddCallback(CharacterDatabase.AsyncQuery(query).WithCallback([=](QueryResult result)
|
||||
{
|
||||
uint32 startValue = (gossipPageNumber * (MAX_OPTIONS));
|
||||
uint32 endValue = (gossipPageNumber + 1) * (MAX_OPTIONS) - 1;
|
||||
std::map<uint32, uint32> entryToAmountMap;
|
||||
std::vector<uint32> itemEntries;
|
||||
if (result) {
|
||||
do {
|
||||
uint32 itemEntry = (*result)[0].Get<uint32>();
|
||||
uint32 itemAmount = (*result)[1].Get<uint32>();
|
||||
entryToAmountMap[itemEntry] = itemAmount;
|
||||
itemEntries.push_back(itemEntry);
|
||||
} while (result->NextRow());
|
||||
}
|
||||
for (uint32 i = startValue; i <= endValue; i++)
|
||||
{
|
||||
if (itemEntries.empty() || i > itemEntries.size() - 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
uint32 itemEntry = itemEntries.at(i);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, GetItemIcon(itemEntry, 30, 30, -18, 0) + GetItemLink(itemEntry, session) + " (" + std::to_string(entryToAmountMap.find(itemEntry)->second) + ")", itemEntry, gossipPageNumber);
|
||||
}
|
||||
if (gossipPageNumber > 0)
|
||||
{
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, "Previous Page", item_subclass, gossipPageNumber - 1);
|
||||
}
|
||||
if (endValue < entryToAmountMap.size())
|
||||
{
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, "Next Page", item_subclass, gossipPageNumber + 1);
|
||||
}
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tBack...", MAIN_MENU, 0);
|
||||
SendGossipMenuFor(player, NPC_TEXT_ID, creature->GetGUID());
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
// Add all scripts in one
|
||||
void AddSC_mod_reagent_bank()
|
||||
{
|
||||
new npc_reagent_banker();
|
||||
}
|
||||
25
src/ReagentBank.h
Normal file
25
src/ReagentBank.h
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
#ifndef AZEROTHCORE_REAGENTBANK_H
|
||||
#define AZEROTHCORE_REAGENTBANK_H
|
||||
#include "ScriptMgr.h"
|
||||
#include "Player.h"
|
||||
#include "Config.h"
|
||||
#include "Chat.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "ScriptedGossip.h"
|
||||
#include "Item.h"
|
||||
#include "ItemTemplate.h"
|
||||
#include <map>
|
||||
|
||||
#define MAX_OPTIONS 23
|
||||
#define MAX_PAGE_NUMBER 700 // Values higher than this are considered Item IDs
|
||||
#define NPC_TEXT_ID 4259 // Pre-existing NPC text
|
||||
|
||||
enum GossipItemType : uint8
|
||||
{
|
||||
DEPOSIT_ALL_REAGENTS = 16,
|
||||
MAIN_MENU = 17
|
||||
};
|
||||
|
||||
|
||||
#endif //AZEROTHCORE_REAGENTBANK_H
|
||||
15
src/ReagentBank_loader.cpp
Normal file
15
src/ReagentBank_loader.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
*/
|
||||
|
||||
// From SC
|
||||
void AddSC_mod_reagent_bank();
|
||||
|
||||
// Add all
|
||||
// cf. the naming convention https://github.com/azerothcore/azerothcore-wotlk/blob/master/doc/changelog/master.md#how-to-upgrade-4
|
||||
// additionally replace all '-' in the module folder name with '_' here
|
||||
void Addmod_reagent_bankScripts()
|
||||
{
|
||||
AddSC_mod_reagent_bank();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user