feat(Scripts/Commands): add .mail list and .mail return commands (#25213)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
35102dcfe9
commit
fc2d3f332e
4 changed files with 422 additions and 1 deletions
|
|
@ -0,0 +1,19 @@
|
|||
-- Add mail commands
|
||||
DELETE FROM `command` WHERE `name` IN ('mail', 'mail list', 'mail return');
|
||||
INSERT INTO `command` (`name`, `security`, `help`) VALUES
|
||||
('mail', 2, 'Syntax: .mail $subcommand\nType .mail to see a list of subcommands or .help mail $subcommand to see info on subcommands.'),
|
||||
('mail list', 2, 'Syntax: .mail list [$player]\nDisplays all mail data (except subject and body) for the target player.'),
|
||||
('mail return', 2, 'Syntax: .mail return $player $mailId\nReturns the specified mail to its original sender.');
|
||||
|
||||
-- Add acore_string entries for mail commands
|
||||
DELETE FROM `acore_string` WHERE `entry` IN (5135, 5136, 5137, 5138, 5139, 5140, 5141, 5142, 5143);
|
||||
INSERT INTO `acore_string` (`entry`, `content_default`, `locale_koKR`, `locale_frFR`, `locale_deDE`, `locale_zhCN`, `locale_zhTW`, `locale_esES`, `locale_esMX`, `locale_ruRU`) VALUES
|
||||
(5135, 'Mail list for player {}:', '플레이어 {}의 우편 목록:', 'Liste des courriers du joueur {} :', 'Postliste für Spieler {}:', '玩家 {} 的邮件列表:', '玩家 {} 的郵件列表:', 'Lista de correo del jugador {}:', 'Lista de correo del jugador {}:', 'Список писем игрока {}:'),
|
||||
(5136, ' ID: {} | Type: {} | Stationery: {} | Template: {} | Sender: {} ({}) | Receiver: {} | Expires: {} | Delivered: {} | Money: {} | COD: {} | Flags: {} | Items: {}', ' ID: {} | 유형: {} | 편지지: {} | 템플릿: {} | 발신자: {} ({}) | 수신자: {} | 만료: {} | 배달: {} | 금액: {} | 대금상환: {} | 플래그: {} | 아이템: {}', ' ID : {} | Type : {} | Papeterie : {} | Modèle : {} | Expéditeur : {} ({}) | Destinataire : {} | Expiration : {} | Livré : {} | Argent : {} | Remboursement : {} | Drapeaux : {} | Objets : {}', ' ID: {} | Typ: {} | Briefpapier: {} | Vorlage: {} | Absender: {} ({}) | Empfänger: {} | Ablauf: {} | Zugestellt: {} | Gold: {} | Nachnahme: {} | Flags: {} | Gegenstände: {}', ' ID:{} | 类型:{} | 信纸:{} | 模板:{} | 发件人:{} ({}) | 收件人:{} | 过期:{} | 投递:{} | 金币:{} | 货到付款:{} | 标记:{} | 物品:{}', ' ID:{} | 類型:{} | 信紙:{} | 範本:{} | 寄件人:{} ({}) | 收件人:{} | 到期:{} | 投遞:{} | 金幣:{} | 貨到付款:{} | 標記:{} | 物品:{}', ' ID: {} | Tipo: {} | Papelería: {} | Plantilla: {} | Remitente: {} ({}) | Destinatario: {} | Expira: {} | Entregado: {} | Dinero: {} | Contrareembolso: {} | Marcas: {} | Objetos: {}', ' ID: {} | Tipo: {} | Papelería: {} | Plantilla: {} | Remitente: {} ({}) | Destinatario: {} | Expira: {} | Entregado: {} | Dinero: {} | Contrareembolso: {} | Marcas: {} | Objetos: {}', ' ID: {} | Тип: {} | Бланк: {} | Шаблон: {} | Отправитель: {} ({}) | Получатель: {} | Истекает: {} | Доставлено: {} | Деньги: {} | Наложенный платёж: {} | Флаги: {} | Предметы: {}'),
|
||||
(5137, 'No mail found for player {}.', '플레이어 {}의 우편이 없습니다.', 'Aucun courrier trouvé pour le joueur {}.', 'Keine Post für Spieler {} gefunden.', '未找到玩家 {} 的邮件。', '未找到玩家 {} 的郵件。', 'No se encontró correo para el jugador {}.', 'No se encontró correo para el jugador {}.', 'Письма для игрока {} не найдены.'),
|
||||
(5138, 'Mail #{} returned to sender for player {}.', '우편 #{}이(가) 플레이어 {}의 발신자에게 반송되었습니다.', 'Courrier #{} renvoyé à l''expéditeur pour le joueur {}.', 'Post #{} wurde an den Absender für Spieler {} zurückgesendet.', '邮件 #{} 已退回给玩家 {} 的发件人。', '郵件 #{} 已退回給玩家 {} 的寄件人。', 'Correo #{} devuelto al remitente del jugador {}.', 'Correo #{} devuelto al remitente del jugador {}.', 'Письмо #{} возвращено отправителю для игрока {}.'),
|
||||
(5139, 'Mail #{} not found.', '우편 #{}을(를) 찾을 수 없습니다.', 'Courrier #{} introuvable.', 'Post #{} nicht gefunden.', '未找到邮件 #{}。', '未找到郵件 #{}。', 'Correo #{} no encontrado.', 'Correo #{} no encontrado.', 'Письмо #{} не найдено.'),
|
||||
(5140, 'Only normal mail can be returned.', '일반 우편만 반송할 수 있습니다.', 'Seul le courrier normal peut être renvoyé.', 'Nur normale Post kann zurückgesendet werden.', '只能退回普通邮件。', '只能退回普通郵件。', 'Solo se puede devolver correo normal.', 'Solo se puede devolver correo normal.', 'Можно вернуть только обычные письма.'),
|
||||
(5141, 'Mail has no valid sender to return to.', '반송할 유효한 발신자가 없습니다.', 'Le courrier n''a pas d''expéditeur valide.', 'Die Post hat keinen gültigen Absender.', '邮件没有有效的发件人可退回。', '郵件沒有有效的寄件人可退回。', 'El correo no tiene un remitente válido.', 'El correo no tiene un remitente válido.', 'У письма нет действительного отправителя для возврата.'),
|
||||
(5142, 'Mail has already been returned.', '이미 반송된 우편입니다.', 'Ce courrier a déjà été renvoyé.', 'Diese Post wurde bereits zurückgesendet.', '邮件已被退回。', '郵件已被退回。', 'El correo ya ha sido devuelto.', 'El correo ya ha sido devuelto.', 'Письмо уже было возвращено.'),
|
||||
(5143, 'A script hook prevented this mail from being returned.', '스크립트 후크가 이 우편의 반송을 차단했습니다.', 'Un hook de script a empêché le renvoi de ce courrier.', 'Ein Script-Hook hat die Rücksendung dieser Post verhindert.', '脚本钩子阻止了此邮件的退回。', '腳本鉤子阻止了此郵件的退回。', 'Un hook de script impidió la devolución de este correo.', 'Un hook de script impidió la devolución de este correo.', 'Хук скрипта предотвратил возврат этого письма.');
|
||||
|
|
@ -1215,7 +1215,18 @@ enum AcoreStrings
|
|||
LANG_AUTOBROADCAST_LOCALE_ENTRY = 5133,
|
||||
LANG_AUTOBROADCAST_INVALID_LOCALE = 5134,
|
||||
|
||||
// Room for more strings 5135-9999
|
||||
// Mail commands
|
||||
LANG_MAIL_LIST_HEADER = 5135,
|
||||
LANG_MAIL_LIST_ENTRY = 5136,
|
||||
LANG_MAIL_LIST_EMPTY = 5137,
|
||||
LANG_MAIL_RETURN_SUCCESS = 5138,
|
||||
LANG_MAIL_RETURN_NOT_FOUND = 5139,
|
||||
LANG_MAIL_RETURN_NOT_NORMAL = 5140,
|
||||
LANG_MAIL_RETURN_NO_SENDER = 5141,
|
||||
LANG_MAIL_RETURN_ALREADY_RETURNED = 5142,
|
||||
LANG_MAIL_RETURN_HOOK_BLOCKED = 5143,
|
||||
|
||||
// Room for more strings 5144-9999
|
||||
|
||||
// Level requirement notifications
|
||||
LANG_SAY_REQ = 6604,
|
||||
|
|
|
|||
389
src/server/scripts/Commands/cs_mail.cpp
Normal file
389
src/server/scripts/Commands/cs_mail.cpp
Normal file
|
|
@ -0,0 +1,389 @@
|
|||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Bag.h"
|
||||
#include "CharacterCache.h"
|
||||
#include "Chat.h"
|
||||
#include "CommandScript.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "GameTime.h"
|
||||
#include "Language.h"
|
||||
#include "Mail.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "Timer.h"
|
||||
|
||||
using namespace Acore::ChatCommands;
|
||||
|
||||
class mail_commandscript : public CommandScript
|
||||
{
|
||||
public:
|
||||
mail_commandscript() : CommandScript("mail_commandscript") { }
|
||||
|
||||
ChatCommandTable GetCommands() const override
|
||||
{
|
||||
static ChatCommandTable mailCommandTable =
|
||||
{
|
||||
{ "list", HandleMailListCommand, SEC_GAMEMASTER, Console::Yes },
|
||||
{ "return", HandleMailReturnCommand, SEC_GAMEMASTER, Console::Yes }
|
||||
};
|
||||
|
||||
static ChatCommandTable commandTable =
|
||||
{
|
||||
{ "mail", mailCommandTable }
|
||||
};
|
||||
|
||||
return commandTable;
|
||||
}
|
||||
|
||||
static char const* GetMailTypeString(uint8 messageType)
|
||||
{
|
||||
switch (messageType)
|
||||
{
|
||||
case MAIL_NORMAL: return "Normal";
|
||||
case MAIL_AUCTION: return "Auction";
|
||||
case MAIL_CREATURE: return "Creature";
|
||||
case MAIL_GAMEOBJECT: return "GameObject";
|
||||
case MAIL_CALENDAR: return "Calendar";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static char const* GetMailStationeryString(uint8 stationery)
|
||||
{
|
||||
switch (stationery)
|
||||
{
|
||||
case MAIL_STATIONERY_TEST: return "Test";
|
||||
case MAIL_STATIONERY_DEFAULT: return "Default";
|
||||
case MAIL_STATIONERY_GM: return "GM";
|
||||
case MAIL_STATIONERY_AUCTION: return "Auction";
|
||||
case MAIL_STATIONERY_VAL: return "Valentine";
|
||||
case MAIL_STATIONERY_CHR: return "Christmas";
|
||||
case MAIL_STATIONERY_ORP: return "Orphan";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string GetItemListString(std::vector<MailItemInfo> const& items)
|
||||
{
|
||||
if (items.empty())
|
||||
return "none";
|
||||
|
||||
std::string result;
|
||||
for (size_t i = 0; i < items.size(); ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
result += ", ";
|
||||
|
||||
result += Acore::StringFormat("{}(guid:{})", items[i].item_template, items[i].item_guid);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool HandleMailListCommand(ChatHandler* handler, Optional<PlayerIdentifier> target)
|
||||
{
|
||||
if (!target)
|
||||
target = PlayerIdentifier::FromTargetOrSelf(handler);
|
||||
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
Player* player = target->GetConnectedPlayer();
|
||||
|
||||
if (player)
|
||||
{
|
||||
PlayerMails const& mails = player->GetMails();
|
||||
|
||||
if (mails.empty())
|
||||
{
|
||||
handler->PSendSysMessage(LANG_MAIL_LIST_EMPTY, handler->playerLink(target->GetName()));
|
||||
return true;
|
||||
}
|
||||
|
||||
handler->PSendSysMessage(LANG_MAIL_LIST_HEADER, handler->playerLink(target->GetName()));
|
||||
|
||||
for (Mail const* mail : mails)
|
||||
{
|
||||
std::string senderName;
|
||||
if (mail->messageType == MAIL_NORMAL)
|
||||
sCharacterCache->GetCharacterNameByGuid(ObjectGuid(HighGuid::Player, mail->sender), senderName);
|
||||
|
||||
std::string expireStr = Acore::Time::TimeToTimestampStr(Seconds(mail->expire_time));
|
||||
std::string deliverStr = Acore::Time::TimeToTimestampStr(Seconds(mail->deliver_time));
|
||||
|
||||
handler->PSendSysMessage(LANG_MAIL_LIST_ENTRY,
|
||||
mail->messageID, GetMailTypeString(mail->messageType), GetMailStationeryString(mail->stationery),
|
||||
mail->mailTemplateId, mail->sender, senderName, mail->receiver,
|
||||
expireStr, deliverStr, mail->money, mail->COD, mail->checked, GetItemListString(mail->items));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ObjectGuid::LowType lowGuid = target->GetGUID().GetCounter();
|
||||
|
||||
QueryResult result = CharacterDatabase.Query(
|
||||
"SELECT id, messageType, sender, receiver, subject, body, expire_time, deliver_time, money, cod, checked, stationery, mailTemplateId"
|
||||
" FROM mail WHERE receiver = {} AND deliver_time <= {} ORDER BY id DESC",
|
||||
lowGuid, GameTime::GetGameTime().count());
|
||||
|
||||
if (!result)
|
||||
{
|
||||
handler->PSendSysMessage(LANG_MAIL_LIST_EMPTY, handler->playerLink(target->GetName()));
|
||||
return true;
|
||||
}
|
||||
|
||||
handler->PSendSysMessage(LANG_MAIL_LIST_HEADER, handler->playerLink(target->GetName()));
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
uint32 messageID = fields[0].Get<uint32>();
|
||||
uint8 messageType = fields[1].Get<uint8>();
|
||||
uint32 sender = fields[2].Get<uint32>();
|
||||
uint32 receiver = fields[3].Get<uint32>();
|
||||
// fields[4] = subject (skipped)
|
||||
// fields[5] = body (skipped)
|
||||
uint32 expireTime = fields[6].Get<uint32>();
|
||||
uint32 deliverTime = fields[7].Get<uint32>();
|
||||
uint32 money = fields[8].Get<uint32>();
|
||||
uint32 cod = fields[9].Get<uint32>();
|
||||
uint32 checked = fields[10].Get<uint32>();
|
||||
uint8 stationery = fields[11].Get<uint8>();
|
||||
uint16 mailTemplate = fields[12].Get<uint16>();
|
||||
|
||||
std::string senderName;
|
||||
if (messageType == MAIL_NORMAL)
|
||||
sCharacterCache->GetCharacterNameByGuid(ObjectGuid(HighGuid::Player, sender), senderName);
|
||||
|
||||
std::string expireStr = Acore::Time::TimeToTimestampStr(Seconds(expireTime));
|
||||
std::string deliverStr = Acore::Time::TimeToTimestampStr(Seconds(deliverTime));
|
||||
|
||||
// For offline players we don't have item details loaded
|
||||
handler->PSendSysMessage(LANG_MAIL_LIST_ENTRY,
|
||||
messageID, GetMailTypeString(messageType), GetMailStationeryString(stationery),
|
||||
mailTemplate, sender, senderName, receiver,
|
||||
expireStr, deliverStr, money, cod, checked, "N/A (offline)");
|
||||
} while (result->NextRow());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleMailReturnCommand(ChatHandler* handler, PlayerIdentifier target, uint32 mailId)
|
||||
{
|
||||
// Query mail data from DB so this works for offline players
|
||||
QueryResult result = CharacterDatabase.Query(
|
||||
"SELECT messageType, sender, receiver, subject, body, money, mailTemplateId, checked, deliver_time"
|
||||
" FROM mail WHERE id = {}", mailId);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
handler->SendErrorMessage(LANG_MAIL_RETURN_NOT_FOUND, mailId);
|
||||
return true;
|
||||
}
|
||||
|
||||
Field* fields = result->Fetch();
|
||||
uint8 messageType = fields[0].Get<uint8>();
|
||||
uint32 sender = fields[1].Get<uint32>();
|
||||
uint32 receiver = fields[2].Get<uint32>();
|
||||
std::string subject = fields[3].Get<std::string>();
|
||||
std::string body = fields[4].Get<std::string>();
|
||||
uint32 money = fields[5].Get<uint32>();
|
||||
uint16 mailTemplate = fields[6].Get<uint16>();
|
||||
uint32 checked = fields[7].Get<uint32>();
|
||||
uint32 deliverTime = fields[8].Get<uint32>();
|
||||
|
||||
// Reject undelivered mail, same as the core handler
|
||||
if (deliverTime > GameTime::GetGameTime().count())
|
||||
{
|
||||
handler->SendErrorMessage(LANG_MAIL_RETURN_NOT_FOUND, mailId);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Verify the mail belongs to the target player
|
||||
if (receiver != target.GetGUID().GetCounter())
|
||||
{
|
||||
handler->SendErrorMessage(LANG_MAIL_RETURN_NOT_FOUND, mailId);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (messageType != MAIL_NORMAL)
|
||||
{
|
||||
handler->SendErrorMessage(LANG_MAIL_RETURN_NOT_NORMAL);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!sender)
|
||||
{
|
||||
handler->SendErrorMessage(LANG_MAIL_RETURN_NO_SENDER);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (checked & MAIL_CHECK_MASK_RETURNED)
|
||||
{
|
||||
handler->SendErrorMessage(LANG_MAIL_RETURN_ALREADY_RETURNED);
|
||||
return true;
|
||||
}
|
||||
|
||||
Player* player = target.GetConnectedPlayer();
|
||||
|
||||
// Run the same script hook as the client return handler, failing early before any deletions
|
||||
if (player)
|
||||
{
|
||||
Mail* m = player->GetMail(mailId);
|
||||
if (m)
|
||||
{
|
||||
ObjectGuid senderGuid = ObjectGuid(HighGuid::Player, sender);
|
||||
|
||||
if (m->HasItems())
|
||||
{
|
||||
for (auto const& itemInfo : m->items)
|
||||
{
|
||||
Item* item = player->GetMItem(itemInfo.item_guid);
|
||||
if (item && !sScriptMgr->OnPlayerCanSendMail(player, senderGuid, ObjectGuid::Empty, subject, body, money, 0, item))
|
||||
{
|
||||
handler->SendErrorMessage(LANG_MAIL_RETURN_HOOK_BLOCKED);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!sScriptMgr->OnPlayerCanSendMail(player, senderGuid, ObjectGuid::Empty, subject, body, money, 0, nullptr))
|
||||
{
|
||||
handler->SendErrorMessage(LANG_MAIL_RETURN_HOOK_BLOCKED);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Same logic as WorldSession::HandleReturnToSender
|
||||
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_BY_ID);
|
||||
stmt->SetData(0, mailId);
|
||||
trans->Append(stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM_BY_ID);
|
||||
stmt->SetData(0, mailId);
|
||||
trans->Append(stmt);
|
||||
|
||||
MailDraft draft(subject, body);
|
||||
if (mailTemplate)
|
||||
draft = MailDraft(mailTemplate, false);
|
||||
|
||||
if (player)
|
||||
{
|
||||
// Online: same logic as WorldSession::HandleReturnToSender
|
||||
// Get pointer before RemoveMail (which removes from deque but does not delete the object)
|
||||
Mail* m = player->GetMail(mailId);
|
||||
|
||||
player->RemoveMail(mailId);
|
||||
|
||||
if (m && m->HasItems())
|
||||
{
|
||||
for (auto const& itemInfo : m->items)
|
||||
{
|
||||
if (Item* item = player->GetMItem(itemInfo.item_guid))
|
||||
draft.AddItem(item);
|
||||
|
||||
player->RemoveMItem(itemInfo.item_guid);
|
||||
}
|
||||
}
|
||||
|
||||
delete m;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Offline: load Item* objects from DB using same query shape as CHAR_SEL_MAILITEMS
|
||||
// (LEFT JOIN to handle dangling mail_items) and same logic as Player::_LoadMailedItem
|
||||
QueryResult itemResult = CharacterDatabase.Query(
|
||||
"SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments,"
|
||||
" randomPropertyId, durability, playedTime, text, mi.item_guid, itemEntry, ii.owner_guid"
|
||||
" FROM mail_items mi LEFT JOIN item_instance ii ON mi.item_guid = ii.guid"
|
||||
" WHERE mi.mail_id = {}", mailId);
|
||||
|
||||
if (itemResult)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field* itemFields = itemResult->Fetch();
|
||||
uint32 itemGuid = itemFields[11].Get<uint32>();
|
||||
uint32 itemEntry = itemFields[12].Get<uint32>();
|
||||
|
||||
// Handle dangling mail_items (missing item_instance)
|
||||
if (!itemEntry)
|
||||
{
|
||||
LOG_ERROR("misc", "cs_mail: Mail #{} has dangling mail_items row for item_guid {}. Cleaning up.", mailId, itemGuid);
|
||||
|
||||
CharacterDatabasePreparedStatement* delStmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_MAIL_ITEM);
|
||||
delStmt->SetData(0, itemGuid);
|
||||
trans->Append(delStmt);
|
||||
continue;
|
||||
}
|
||||
|
||||
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemEntry);
|
||||
if (!proto)
|
||||
{
|
||||
LOG_ERROR("misc", "cs_mail: Mail #{} has unknown item (entry: {}, guid: {}). Cleaning up.", mailId, itemEntry, itemGuid);
|
||||
|
||||
CharacterDatabasePreparedStatement* delStmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_MAIL_ITEM);
|
||||
delStmt->SetData(0, itemGuid);
|
||||
trans->Append(delStmt);
|
||||
continue;
|
||||
}
|
||||
|
||||
Item* item = NewItemOrBag(proto);
|
||||
ObjectGuid ownerGuid = itemFields[13].Get<uint32>()
|
||||
? ObjectGuid::Create<HighGuid::Player>(itemFields[13].Get<uint32>())
|
||||
: ObjectGuid::Empty;
|
||||
|
||||
if (!item->LoadFromDB(itemGuid, ownerGuid, itemFields, itemEntry))
|
||||
{
|
||||
LOG_ERROR("misc", "cs_mail: Item (GUID: {}) in mail #{} failed to load. Cleaning up.", itemGuid, mailId);
|
||||
|
||||
CharacterDatabasePreparedStatement* delStmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_MAIL_ITEM);
|
||||
delStmt->SetData(0, itemGuid);
|
||||
trans->Append(delStmt);
|
||||
|
||||
item->FSetState(ITEM_REMOVED);
|
||||
CharacterDatabaseTransaction nullTrans = CharacterDatabaseTransaction(nullptr);
|
||||
item->SaveToDB(nullTrans);
|
||||
return true;
|
||||
}
|
||||
|
||||
draft.AddItem(item);
|
||||
} while (itemResult->NextRow());
|
||||
}
|
||||
}
|
||||
|
||||
uint32 accountId = sCharacterCache->GetCharacterAccountIdByGuid(ObjectGuid(HighGuid::Player, receiver));
|
||||
draft.AddMoney(money).SendReturnToSender(accountId, receiver, sender, trans);
|
||||
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
|
||||
sCharacterCache->DecreaseCharacterMailCount(ObjectGuid(HighGuid::Player, receiver));
|
||||
|
||||
handler->PSendSysMessage(LANG_MAIL_RETURN_SUCCESS, mailId, handler->playerLink(target.GetName()));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_mail_commandscript()
|
||||
{
|
||||
new mail_commandscript();
|
||||
}
|
||||
|
|
@ -43,6 +43,7 @@ void AddSC_learn_commandscript();
|
|||
void AddSC_lfg_commandscript();
|
||||
void AddSC_list_commandscript();
|
||||
void AddSC_lookup_commandscript();
|
||||
void AddSC_mail_commandscript();
|
||||
void AddSC_message_commandscript();
|
||||
void AddSC_misc_commandscript();
|
||||
void AddSC_mmaps_commandscript();
|
||||
|
|
@ -98,6 +99,7 @@ void AddCommandsScripts()
|
|||
AddSC_lfg_commandscript();
|
||||
AddSC_list_commandscript();
|
||||
AddSC_lookup_commandscript();
|
||||
AddSC_mail_commandscript();
|
||||
AddSC_message_commandscript();
|
||||
AddSC_misc_commandscript();
|
||||
AddSC_mmaps_commandscript();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue