Files
mod-playerbots/src/GuildTaskMgr.cpp
SaW 9fbf60d812 Resolve most warnings - PlayerbotAI (#1025)
Resolve most warnings - PlayerbotAI

---------

Co-authored-by: blinkysc <37940565+blinkysc@users.noreply.github.com>
2025-03-01 14:19:07 +01:00

1244 lines
40 KiB
C++

/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "GuildTaskMgr.h"
#include "ChatHelper.h"
#include "Group.h"
#include "GuildMgr.h"
#include "Mail.h"
#include "MapMgr.h"
#include "PlayerbotFactory.h"
#include "Playerbots.h"
#include "RandomItemMgr.h"
#include "ServerFacade.h"
char* strstri(char const* str1, char const* str2);
enum GuildTaskType
{
GUILD_TASK_TYPE_NONE = 0,
GUILD_TASK_TYPE_ITEM = 1,
GUILD_TASK_TYPE_KILL = 2
};
void GuildTaskMgr::Update(Player* player, Player* guildMaster)
{
if (!sPlayerbotAIConfig->guildTaskEnabled)
return;
if (!GetTaskValue(0, 0, "advert_cleanup"))
{
CleanupAdverts();
RemoveDuplicatedAdverts();
SetTaskValue(0, 0, "advert_cleanup", 1, sPlayerbotAIConfig->guildTaskAdvertCleanupTime);
}
PlayerbotAI* masterBotAI = GET_PLAYERBOT_AI(guildMaster);
uint32 guildId = guildMaster->GetGuildId();
if (!guildId || !masterBotAI || !guildMaster->GetGuildId())
return;
if (!player->IsFriendlyTo(guildMaster))
return;
Guild* guild = sGuildMgr->GetGuildById(guildMaster->GetGuildId());
DenyReason reason = PLAYERBOT_DENY_NONE;
PlayerbotSecurityLevel secLevel = masterBotAI->GetSecurity()->LevelFor(player, &reason);
if (secLevel == PLAYERBOT_SECURITY_DENY_ALL ||
(secLevel == PLAYERBOT_SECURITY_TALK && reason != PLAYERBOT_DENY_FAR))
{
LOG_DEBUG("playerbots", "{} / {}: skipping guild task update - not enough security level, reason = {}",
guild->GetName().c_str(), player->GetName().c_str(), reason);
return;
}
LOG_DEBUG("playerbots", "{}: guild task update for player {}", guild->GetName().c_str(), player->GetName().c_str());
ObjectGuid::LowType owner = player->GetGUID().GetCounter();
uint32 activeTask = GetTaskValue(owner, guildId, "activeTask");
if (!activeTask)
{
SetTaskValue(owner, guildId, "killTask", 0, 0);
SetTaskValue(owner, guildId, "itemTask", 0, 0);
SetTaskValue(owner, guildId, "itemCount", 0, 0);
SetTaskValue(owner, guildId, "killTask", 0, 0);
SetTaskValue(owner, guildId, "killCount", 0, 0);
SetTaskValue(owner, guildId, "payment", 0, 0);
SetTaskValue(owner, guildId, "thanks", 1, 2 * sPlayerbotAIConfig->maxGuildTaskChangeTime);
SetTaskValue(owner, guildId, "reward", 1, 2 * sPlayerbotAIConfig->maxGuildTaskChangeTime);
uint32 task = CreateTask(player, guildId);
if (task == GUILD_TASK_TYPE_NONE)
{
LOG_ERROR("playerbots", "{} / {}: error creating guild task", guild->GetName().c_str(),
player->GetName().c_str());
}
uint32 time = urand(sPlayerbotAIConfig->minGuildTaskChangeTime, sPlayerbotAIConfig->maxGuildTaskChangeTime);
SetTaskValue(owner, guildId, "activeTask", task, time);
SetTaskValue(owner, guildId, "advertisement", 1,
urand(sPlayerbotAIConfig->minGuildTaskAdvertisementTime,
sPlayerbotAIConfig->maxGuildTaskAdvertisementTime));
LOG_DEBUG("playerbots", "{} / {}: guild task {} is set for {} secs", guild->GetName().c_str(),
player->GetName().c_str(), task, time);
return;
}
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
uint32 advertisement = GetTaskValue(owner, guildId, "advertisement");
if (!advertisement)
{
LOG_DEBUG("playerbots", "{} / {}: sending advertisement", guild->GetName().c_str(), player->GetName().c_str());
if (SendAdvertisement(trans, owner, guildId))
{
SetTaskValue(owner, guildId, "advertisement", 1,
urand(sPlayerbotAIConfig->minGuildTaskAdvertisementTime,
sPlayerbotAIConfig->maxGuildTaskAdvertisementTime));
}
else
{
LOG_DEBUG("playerbots", "{} / {}: error sending advertisement", guild->GetName().c_str(),
player->GetName().c_str());
}
}
uint32 thanks = GetTaskValue(owner, guildId, "thanks");
if (!thanks)
{
LOG_DEBUG("playerbots", "{} / {}: sending thanks", guild->GetName().c_str(), player->GetName().c_str());
if (SendThanks(trans, owner, guildId, GetTaskValue(owner, guildId, "payment")))
{
SetTaskValue(owner, guildId, "thanks", 1, 2 * sPlayerbotAIConfig->maxGuildTaskChangeTime);
SetTaskValue(owner, guildId, "payment", 0, 0);
}
else
{
LOG_DEBUG("playerbots", "{} / {}: error sending thanks", guild->GetName().c_str(),
player->GetName().c_str());
}
}
uint32 reward = GetTaskValue(owner, guildId, "reward");
if (!reward)
{
LOG_DEBUG("playerbots", "{} / {}: sending reward", guild->GetName().c_str(), player->GetName().c_str());
if (Reward(trans, owner, guildId))
{
SetTaskValue(owner, guildId, "reward", 1, 2 * sPlayerbotAIConfig->maxGuildTaskChangeTime);
SetTaskValue(owner, guildId, "payment", 0, 0);
}
else
{
LOG_DEBUG("playerbots", "{} / {}: error sending reward", guild->GetName().c_str(),
player->GetName().c_str());
}
}
CharacterDatabase.CommitTransaction(trans);
}
uint32 GuildTaskMgr::CreateTask(Player* owner, uint32 guildId)
{
switch (urand(0, 1))
{
case 0:
CreateItemTask(owner, guildId);
return GUILD_TASK_TYPE_ITEM;
default:
CreateKillTask(owner, guildId);
return GUILD_TASK_TYPE_KILL;
}
}
class RandomItemBySkillGuildTaskPredicate : public RandomItemPredicate
{
public:
RandomItemBySkillGuildTaskPredicate(Player* player) : RandomItemPredicate(), player(player) {}
bool Apply(ItemTemplate const* proto) override
{
//uint32* tradeSkills = PlayerbotFactory::tradeSkills;
for (uint32 i = 0; i < 13; ++i)
{
uint32 skillId = PlayerbotFactory::tradeSkills[i];
if (player->HasSkill(skillId) && RandomItemMgr::IsUsedBySkill(proto, skillId))
return true;
}
return false;
}
private:
Player* player;
};
bool GuildTaskMgr::CreateItemTask(Player* player, uint32 guildId)
{
if (!player || player->GetLevel() < 5)
return false;
RandomItemBySkillGuildTaskPredicate predicate(player);
uint32 itemId = sRandomItemMgr->GetRandomItem(player->GetLevel() - 5, RANDOM_ITEM_GUILD_TASK, &predicate);
if (!itemId)
{
LOG_ERROR("playerbots", "{} / {}: no items avaible for item task",
sGuildMgr->GetGuildById(guildId)->GetName().c_str(), player->GetName().c_str());
return false;
}
uint32 count = GetMaxItemTaskCount(itemId);
LOG_DEBUG("playerbots", "{} / {}: item task {} (x{})", sGuildMgr->GetGuildById(guildId)->GetName().c_str(),
player->GetName().c_str(), itemId, count);
SetTaskValue(player->GetGUID().GetCounter(), guildId, "itemCount", count,
sPlayerbotAIConfig->maxGuildTaskChangeTime);
SetTaskValue(player->GetGUID().GetCounter(), guildId, "itemTask", itemId,
sPlayerbotAIConfig->maxGuildTaskChangeTime);
return true;
}
bool GuildTaskMgr::CreateKillTask(Player* player, uint32 guildId)
{
if (!player)
return false;
uint32 rank = !urand(0, 2) ? CREATURE_ELITE_RAREELITE : CREATURE_ELITE_RARE;
std::vector<uint32> ids;
uint32 level = player->GetLevel();
QueryResult results = WorldDatabase.Query(
"SELECT ct.Entry, c.map, c.position_x, c.position_y, ct.Name FROM creature_template ct "
"JOIN creature c ON ct.Entry = c.id1 WHERE ct.MaxLevel < {} AND ct.MinLevel > {} AND ct.Rank = {} ",
level + 4, level - 3, rank);
if (results)
{
do
{
Field* fields = results->Fetch();
uint32 id = fields[0].Get<uint32>();
uint32 map = fields[1].Get<uint32>();
float x = fields[2].Get<float>();
float y = fields[3].Get<float>();
std::string const name = fields[4].Get<std::string>();
if (strstr(name.c_str(), "UNUSED"))
continue;
float dist = sServerFacade->GetDistance2d(player, x, y);
if (dist > sPlayerbotAIConfig->guildTaskKillTaskDistance || player->GetMapId() != map)
continue;
if (find(ids.begin(), ids.end(), id) == ids.end())
ids.push_back(id);
} while (results->NextRow());
}
if (ids.empty())
{
LOG_ERROR("playerbots", "{} / {}: no rare creatures available for kill task",
sGuildMgr->GetGuildById(guildId)->GetName().c_str(), player->GetName().c_str());
return false;
}
uint32 index = urand(0, ids.size() - 1);
uint32 creatureId = ids[index];
LOG_DEBUG("playerbots", "{} / {}: kill task {}", sGuildMgr->GetGuildById(guildId)->GetName().c_str(),
player->GetName().c_str(), creatureId);
SetTaskValue(player->GetGUID().GetCounter(), guildId, "killTask", creatureId,
sPlayerbotAIConfig->maxGuildTaskChangeTime);
return true;
}
bool GuildTaskMgr::SendAdvertisement(CharacterDatabaseTransaction& trans, uint32 owner, uint32 guildId)
{
Guild* guild = sGuildMgr->GetGuildById(guildId);
if (!guild)
return false;
Player* leader = ObjectAccessor::FindPlayer(guild->GetLeaderGUID());
if (!leader)
return false;
uint32 validIn;
GetTaskValue(owner, guildId, "activeTask", &validIn);
uint32 itemTask = GetTaskValue(owner, guildId, "itemTask");
if (itemTask)
return SendItemAdvertisement(trans, itemTask, owner, guildId, validIn);
uint32 killTask = GetTaskValue(owner, guildId, "killTask");
if (killTask)
return SendKillAdvertisement(trans, killTask, owner, guildId, validIn);
return false;
}
std::string const formatTime(uint32 secs)
{
std::ostringstream out;
if (secs < 3600)
{
out << secs / 60 << " min";
}
else if (secs < 7200)
{
out << "1 hr " << (secs - 3600) / 60 << " min";
}
else if (secs < 3600 * 24)
{
out << secs / 3600 << " hr";
}
else
{
out << secs / 3600 / 24 << " days";
}
return out.str();
}
std::string const formatDateTime(uint32 secs)
{
time_t rawtime = time(nullptr) + secs;
tm* timeinfo = localtime(&rawtime);
char buffer[256];
strftime(buffer, sizeof(buffer), "%b %d, %H:%M", timeinfo);
return std::string(buffer);
}
std::string const GetHelloText(uint32 owner)
{
ObjectGuid ownerGUID = ObjectGuid::Create<HighGuid::Player>(owner);
std::ostringstream body;
body << "Hello";
std::string playerName;
sCharacterCache->GetCharacterNameByGuid(ownerGUID, playerName);
if (!playerName.empty())
body << ", " << playerName;
body << ",\n\n";
return body.str();
}
bool GuildTaskMgr::SendItemAdvertisement(CharacterDatabaseTransaction& trans, uint32 itemId, uint32 owner,
uint32 guildId, uint32 validIn)
{
Guild* guild = sGuildMgr->GetGuildById(guildId);
Player* leader = ObjectAccessor::FindPlayer(guild->GetLeaderGUID());
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId);
if (!proto)
return false;
std::ostringstream body;
body << GetHelloText(owner);
body << "We are in a great need of " << proto->Name1 << ". If you could sell us ";
uint32 count = GetTaskValue(owner, guildId, "itemCount");
if (count > 1)
body << "at least " << count << " of them ";
else
body << "some ";
body << "we'd really appreciate that and pay a high price.\n\n";
body << "The task will expire at " << formatDateTime(validIn) << "\n";
body << "\n";
body << "Best Regards,\n";
body << guild->GetName() << "\n";
body << leader->GetName() << "\n";
std::ostringstream subject;
subject << "Guild Task: " << proto->Name1;
if (count > 1)
subject << " (x" << count << ")";
MailDraft(subject.str(), body.str()).SendMailTo(trans, MailReceiver(owner), MailSender(leader));
return true;
}
bool GuildTaskMgr::SendKillAdvertisement(CharacterDatabaseTransaction& trans, uint32 creatureId, uint32 owner,
uint32 guildId, uint32 validIn)
{
Guild* guild = sGuildMgr->GetGuildById(guildId);
Player* leader = ObjectAccessor::FindPlayer(guild->GetLeaderGUID());
CreatureTemplate const* proto = sObjectMgr->GetCreatureTemplate(creatureId);
if (!proto)
return false;
QueryResult result =
WorldDatabase.Query("SELECT map, position_x, position_y, position_z FROM creature WHERE id1 = {}", creatureId);
if (!result)
return false;
std::string location;
do
{
Field* fields = result->Fetch();
uint32 mapid = fields[0].Get<uint32>();
float x = fields[1].Get<float>();
float y = fields[2].Get<float>();
float z = fields[3].Get<float>();
Map* map = sMapMgr->FindMap(mapid, 0);
if (!map)
continue;
AreaTableEntry const* entry = sAreaTableStore.LookupEntry(map->GetAreaId(PHASEMASK_NORMAL, x, y, z));
if (!entry)
continue;
location = entry->area_name[0];
break;
} while (result->NextRow());
std::ostringstream body;
body << GetHelloText(owner);
body << "As you probably know " << proto->Name
<< " is wanted dead for the crimes it did against our guild. If you should kill it ";
body << "we'd really appreciate that.\n\n";
if (!location.empty())
body << proto->Name << "'s the last known location was " << location << ".\n";
body << "The task will expire at " << formatDateTime(validIn) << "\n";
body << "\n";
body << "Best Regards,\n";
body << guild->GetName() << "\n";
body << leader->GetName() << "\n";
std::ostringstream subject;
subject << "Guild Task: ";
if (proto->rank == CREATURE_ELITE_ELITE || proto->rank == CREATURE_ELITE_RAREELITE ||
proto->rank == CREATURE_ELITE_WORLDBOSS)
subject << "(Elite) ";
subject << proto->Name;
if (!location.empty())
subject << ", " << location;
MailDraft(subject.str(), body.str()).SendMailTo(trans, MailReceiver(owner), MailSender(leader));
return true;
}
bool GuildTaskMgr::SendThanks(CharacterDatabaseTransaction& trans, uint32 owner, uint32 guildId, uint32 payment)
{
Guild* guild = sGuildMgr->GetGuildById(guildId);
if (!guild)
return false;
Player* leader = ObjectAccessor::FindPlayer(guild->GetLeaderGUID());
if (!leader)
return false;
uint32 itemTask = GetTaskValue(owner, guildId, "itemTask");
if (itemTask)
{
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemTask);
if (!proto)
return false;
std::ostringstream body;
body << GetHelloText(owner);
body << "One of our guild members wishes to thank you for the " << proto->Name1 << "!";
uint32 count = GetTaskValue(owner, guildId, "itemCount");
if (count)
{
body << " If we have another ";
body << count << " of them that would help us tremendously.\n";
}
body << "\n";
body << "Thanks again,\n";
body << guild->GetName() << "\n";
body << leader->GetName() << "\n";
MailDraft("Thank You", body.str()).AddMoney(payment).SendMailTo(trans, MailReceiver(owner), MailSender(leader));
Player* player = ObjectAccessor::FindPlayer(ObjectGuid::Create<HighGuid::Player>(owner));
if (player)
SendCompletionMessage(player, "payed for");
return true;
}
return false;
}
uint32 GuildTaskMgr::GetMaxItemTaskCount(uint32 itemId)
{
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId);
if (!proto)
return 0;
if (!proto->Stackable || proto->GetMaxStackSize() == 1)
return 1;
if (proto->Quality == ITEM_QUALITY_NORMAL)
{
switch (proto->GetMaxStackSize())
{
case 5:
return urand(1, 3) * proto->GetMaxStackSize();
case 10:
return urand(2, 6) * proto->GetMaxStackSize() / 2;
case 20:
return urand(4, 12) * proto->GetMaxStackSize() / 4;
default:
return proto->GetMaxStackSize();
}
}
if (proto->Quality < ITEM_QUALITY_RARE)
{
switch (proto->GetMaxStackSize())
{
case 5:
return proto->GetMaxStackSize();
case 10:
return urand(1, 2) * proto->GetMaxStackSize() / 2;
case 20:
return urand(1, 4) * proto->GetMaxStackSize() / 4;
default:
return proto->GetMaxStackSize();
}
}
return 1;
}
bool GuildTaskMgr::IsGuildTaskItem(uint32 itemId, uint32 guildId)
{
uint32 value = 0;
PlayerbotsDatabasePreparedStatement* stmt =
PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_GUILD_TASKS_BY_VALUE);
stmt->SetData(0, itemId);
stmt->SetData(1, guildId);
stmt->SetData(2, "itemTask");
if (PreparedQueryResult result = PlayerbotsDatabase.Query(stmt))
{
Field* fields = result->Fetch();
value = fields[0].Get<uint32>();
uint32 lastChangeTime = fields[1].Get<uint32>();
uint32 validIn = fields[2].Get<uint32>();
if ((time(nullptr) - lastChangeTime) >= validIn)
value = 0;
}
return value;
}
std::map<uint32, uint32> GuildTaskMgr::GetTaskValues(uint32 owner, std::string const type,
[[maybe_unused]] uint32* validIn /* = nullptr */)
{
std::map<uint32, uint32> results;
PlayerbotsDatabasePreparedStatement* stmt =
PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_GUILD_TASKS_BY_OWNER);
stmt->SetData(0, owner);
stmt->SetData(1, type);
if (PreparedQueryResult result = PlayerbotsDatabase.Query(stmt))
{
do
{
Field* fields = result->Fetch();
uint32 value = fields[0].Get<uint32>();
uint32 lastChangeTime = fields[1].Get<uint32>();
uint32 secs = fields[2].Get<uint32>();
uint32 guildId = fields[3].Get<uint32>();
if ((time(nullptr) - lastChangeTime) >= secs)
value = 0;
results[guildId] = value;
} while (result->NextRow());
}
return results;
}
uint32 GuildTaskMgr::GetTaskValue(uint32 owner, uint32 guildId, std::string const type, [[maybe_unused]] uint32* validIn /* = nullptr */)
{
uint32 value = 0;
PlayerbotsDatabasePreparedStatement* stmt =
PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_GUILD_TASKS_BY_OWNER_AND_TYPE);
stmt->SetData(0, owner);
stmt->SetData(1, guildId);
stmt->SetData(2, type);
if (PreparedQueryResult result = PlayerbotsDatabase.Query(stmt))
{
Field* fields = result->Fetch();
value = fields[0].Get<uint32>();
uint32 lastChangeTime = fields[1].Get<uint32>();
uint32 secs = fields[2].Get<uint32>();
if ((time(nullptr) - lastChangeTime) >= secs)
value = 0;
if (validIn)
*validIn = secs;
}
return value;
}
uint32 GuildTaskMgr::SetTaskValue(uint32 owner, uint32 guildId, std::string const type, uint32 value, uint32 validIn)
{
PlayerbotsDatabasePreparedStatement* stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_DEL_GUILD_TASKS);
stmt->SetData(0, owner);
stmt->SetData(1, guildId);
stmt->SetData(2, type);
PlayerbotsDatabase.Execute(stmt);
if (value)
{
stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_INS_GUILD_TASKS);
stmt->SetData(0, owner);
stmt->SetData(1, guildId);
stmt->SetData(2, (uint32)time(nullptr));
stmt->SetData(3, validIn);
stmt->SetData(4, type);
stmt->SetData(5, value);
PlayerbotsDatabase.Execute(stmt);
}
return value;
}
bool GuildTaskMgr::HandleConsoleCommand(ChatHandler* /* handler */, char const* args)
{
if (!sPlayerbotAIConfig->guildTaskEnabled)
{
LOG_ERROR("playerbots", "Guild task system is currently disabled!");
return false;
}
if (!args || !*args)
{
LOG_ERROR("playerbots", "Usage: gtask stats/reset");
return false;
}
std::string const cmd = args;
if (cmd == "reset")
{
PlayerbotsDatabase.Execute("DELETE FROM playerbots_guild_tasks");
LOG_INFO("playerbots", "Guild tasks were reset for all players");
return true;
}
if (cmd == "stats")
{
LOG_INFO("playerbots", "Usage: gtask stats <player name>");
return true;
}
if (cmd.find("stats ") != std::string::npos)
{
std::string const charName = cmd.substr(cmd.find("stats ") + 6);
ObjectGuid guid = sCharacterCache->GetCharacterGuidByName(charName);
if (!guid)
{
LOG_ERROR("playerbots", "Player {} not found", charName.c_str());
return false;
}
uint32 owner = guid.GetCounter();
PlayerbotsDatabasePreparedStatement* stmt =
PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_GUILD_TASKS_BY_OWNER_ORDERED);
stmt->SetData(0, owner);
stmt->SetData(1, "activeTask");
if (PreparedQueryResult result = PlayerbotsDatabase.Query(stmt))
{
do
{
Field* fields = result->Fetch();
uint32 value = fields[0].Get<uint32>();
uint32 lastChangeTime = fields[1].Get<uint32>();
uint32 validIn = fields[2].Get<uint32>();
if ((time(nullptr) - lastChangeTime) >= validIn)
value = 0;
uint32 guildId = fields[3].Get<uint32>();
Guild* guild = sGuildMgr->GetGuildById(guildId);
if (!guild)
continue;
std::ostringstream name;
if (value == GUILD_TASK_TYPE_ITEM)
{
name << "ItemTask";
uint32 itemId = sGuildTaskMgr->GetTaskValue(owner, guildId, "itemTask");
uint32 itemCount = sGuildTaskMgr->GetTaskValue(owner, guildId, "itemCount");
if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId))
{
name << " (" << proto->Name1 << " x" << itemCount << ",";
switch (proto->Quality)
{
case ITEM_QUALITY_UNCOMMON:
name << "green";
break;
case ITEM_QUALITY_NORMAL:
name << "white";
break;
case ITEM_QUALITY_RARE:
name << "blue";
break;
case ITEM_QUALITY_EPIC:
name << "epic";
break;
case ITEM_QUALITY_LEGENDARY:
name << "yellow";
break;
}
name << ")";
}
}
else if (value == GUILD_TASK_TYPE_KILL)
{
name << "KillTask";
uint32 creatureId = sGuildTaskMgr->GetTaskValue(owner, guildId, "killTask");
if (CreatureTemplate const* proto = sObjectMgr->GetCreatureTemplate(creatureId))
{
name << " (" << proto->Name << ",";
switch (proto->rank)
{
case CREATURE_ELITE_RARE:
name << "rare";
break;
case CREATURE_ELITE_RAREELITE:
name << "rare elite";
break;
}
name << ")";
}
}
else
continue;
uint32 advertValidIn = 0;
uint32 advert = sGuildTaskMgr->GetTaskValue(owner, guildId, "advertisement", &advertValidIn);
if (advert && advertValidIn < validIn)
name << " advert in " << formatTime(advertValidIn);
uint32 thanksValidIn = 0;
uint32 thanks = sGuildTaskMgr->GetTaskValue(owner, guildId, "thanks", &thanksValidIn);
if (thanks && thanksValidIn < validIn)
name << " thanks in " << formatTime(thanksValidIn);
uint32 rewardValidIn = 0;
uint32 reward = sGuildTaskMgr->GetTaskValue(owner, guildId, "reward", &rewardValidIn);
if (reward && rewardValidIn < validIn)
name << " reward in " << formatTime(rewardValidIn);
uint32 paymentValidIn = 0;
uint32 payment = sGuildTaskMgr->GetTaskValue(owner, guildId, "payment", &paymentValidIn);
if (payment && paymentValidIn < validIn)
name << " payment " << ChatHelper::formatMoney(payment) << " in " << formatTime(paymentValidIn);
LOG_INFO("playerbots", "{}: {} valid in {} [{}]", charName.c_str(), name.str().c_str(),
formatTime(validIn).c_str(), guild->GetName().c_str());
} while (result->NextRow());
}
return true;
}
if (cmd == "cleanup")
{
sGuildTaskMgr->CleanupAdverts();
sGuildTaskMgr->RemoveDuplicatedAdverts();
return true;
}
if (cmd == "reward")
{
LOG_INFO("playerbots", "Usage: gtask reward <player name>");
return true;
}
if (cmd == "advert")
{
LOG_INFO("playerbots", "Usage: gtask advert <player name>");
return true;
}
bool reward = cmd.find("reward ") != std::string::npos;
bool advert = cmd.find("advert ") != std::string::npos;
if (reward || advert)
{
std::string charName;
if (reward)
charName = cmd.substr(cmd.find("reward ") + 7);
if (advert)
charName = cmd.substr(cmd.find("advert ") + 7);
ObjectGuid guid = sCharacterCache->GetCharacterGuidByName(charName);
if (!guid)
{
LOG_ERROR("playerbots", "Player {} not found", charName.c_str());
return false;
}
uint32 owner = guid.GetCounter();
PlayerbotsDatabasePreparedStatement* stmt =
PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_SEL_GUILD_TASKS_BY_OWNER_DISTINCT);
stmt->SetData(0, owner);
if (PreparedQueryResult result = PlayerbotsDatabase.Query(stmt))
{
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
do
{
Field* fields = result->Fetch();
uint32 guildId = fields[0].Get<uint32>();
Guild* guild = sGuildMgr->GetGuildById(guildId);
if (!guild)
continue;
if (reward)
sGuildTaskMgr->Reward(trans, owner, guildId);
if (advert)
sGuildTaskMgr->SendAdvertisement(trans, owner, guildId);
} while (result->NextRow());
CharacterDatabase.CommitTransaction(trans);
return true;
}
}
return false;
}
bool GuildTaskMgr::CheckItemTask(uint32 itemId, uint32 obtained, Player* ownerPlayer, Player* bot, bool byMail)
{
if (!bot)
return false;
uint32 guildId = bot->GetGuildId();
if (!guildId)
return false;
uint32 owner = ownerPlayer->GetGUID().GetCounter();
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
if (!guild)
return false;
if (!sRandomPlayerbotMgr->IsRandomBot(bot))
return false;
LOG_DEBUG("playerbots", "{} / {}: checking guild task", guild->GetName().c_str(), ownerPlayer->GetName().c_str());
uint32 itemTask = GetTaskValue(owner, guildId, "itemTask");
if (itemTask != itemId)
{
LOG_DEBUG("playerbots", "{} / {}: item {} is not guild task item ({})", guild->GetName().c_str(),
ownerPlayer->GetName().c_str(), itemId, itemTask);
if (byMail)
SendCompletionMessage(ownerPlayer, "made a mistake with");
return false;
}
uint32 count = GetTaskValue(owner, guildId, "itemCount");
if (!count)
{
return false;
}
uint32 rewardTime = urand(sPlayerbotAIConfig->minGuildTaskRewardTime, sPlayerbotAIConfig->maxGuildTaskRewardTime);
if (byMail)
{
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId);
if (!proto)
return false;
uint32 money = GetTaskValue(owner, guildId, "payment");
SetTaskValue(owner, guildId, "payment", money + proto->BuyPrice * obtained, rewardTime + 300);
}
if (obtained >= count)
{
LOG_DEBUG("playerbots", "{} / {}: guild task complete", guild->GetName().c_str(),
ownerPlayer->GetName().c_str());
SetTaskValue(owner, guildId, "reward", 1, rewardTime - 15);
SetTaskValue(owner, guildId, "itemCount", 0, 0);
SetTaskValue(owner, guildId, "thanks", 0, 0);
SendCompletionMessage(ownerPlayer, "completed");
}
else
{
LOG_DEBUG("playerbots", "{} / {}: guild task progress {}/{}", guild->GetName().c_str(),
ownerPlayer->GetName().c_str(), obtained, count);
SetTaskValue(owner, guildId, "itemCount", count - obtained, sPlayerbotAIConfig->maxGuildTaskChangeTime);
SetTaskValue(owner, guildId, "thanks", 1, rewardTime - 30);
SendCompletionMessage(ownerPlayer, "made a progress with");
}
return true;
}
bool GuildTaskMgr::Reward(CharacterDatabaseTransaction& trans, uint32 owner, uint32 guildId)
{
Guild* guild = sGuildMgr->GetGuildById(guildId);
if (!guild)
return false;
Player* leader = ObjectAccessor::FindPlayer(guild->GetLeaderGUID());
if (!leader)
return false;
Player* player = ObjectAccessor::FindPlayer(ObjectGuid::Create<HighGuid::Player>(owner));
if (!player)
return false;
uint32 itemTask = GetTaskValue(owner, guildId, "itemTask");
uint32 killTask = GetTaskValue(owner, guildId, "killTask");
if (!itemTask && !killTask)
return false;
std::ostringstream body;
body << GetHelloText(owner);
RandomItemType rewardType;
uint32 itemId = 0;
uint32 itemCount = 1;
if (itemTask)
{
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemTask);
if (!proto)
return false;
body << "We wish to thank you for the " << proto->Name1
<< " you provided so kindly. We really appreciate this and may this small gift bring you our thanks!\n";
body << "\n";
body << "Many thanks,\n";
body << guild->GetName() << "\n";
body << leader->GetName() << "\n";
rewardType = proto->Quality > ITEM_QUALITY_NORMAL ? RANDOM_ITEM_GUILD_TASK_REWARD_EQUIP_BLUE
: RANDOM_ITEM_GUILD_TASK_REWARD_EQUIP_GREEN;
itemId = sRandomItemMgr->GetRandomItem(player->GetLevel() - 5, rewardType);
}
else if (killTask)
{
CreatureTemplate const* proto = sObjectMgr->GetCreatureTemplate(killTask);
if (!proto)
return false;
body << "We wish to thank you for the " << proto->Name
<< " you've killed recently. We really appreciate this and may this small gift bring you our thanks!\n";
body << "\n";
body << "Many thanks,\n";
body << guild->GetName() << "\n";
body << leader->GetName() << "\n";
rewardType = proto->rank == CREATURE_ELITE_RARE ? RANDOM_ITEM_GUILD_TASK_REWARD_TRADE
: RANDOM_ITEM_GUILD_TASK_REWARD_TRADE_RARE;
itemId = sRandomItemMgr->GetRandomItem(player->GetLevel(), rewardType);
if (itemId)
{
ItemTemplate const* itemProto = sObjectMgr->GetItemTemplate(itemId);
if (proto)
{
if (itemProto->Quality == ITEM_QUALITY_NORMAL)
itemCount = itemProto->GetMaxStackSize();
if (proto->rank != CREATURE_ELITE_RARE && itemProto->Quality > ITEM_QUALITY_NORMAL)
itemCount = urand(1, itemProto->GetMaxStackSize());
}
}
}
uint32 payment = GetTaskValue(owner, guildId, "payment");
if (payment)
SendThanks(trans, owner, guildId, payment);
MailDraft draft("Thank You", body.str());
if (itemId)
{
Item* item = Item::CreateItem(itemId, itemCount);
if (item)
{
item->SaveToDB(trans);
draft.AddItem(item);
}
}
draft.SendMailTo(trans, MailReceiver(owner), MailSender(leader));
player = ObjectAccessor::FindPlayer(ObjectGuid::Create<HighGuid::Player>(owner));
if (player)
SendCompletionMessage(player, "rewarded for");
SetTaskValue(owner, guildId, "activeTask", 0, 0);
SetTaskValue(owner, guildId, "payment", 0, 0);
return true;
}
void GuildTaskMgr::CheckKillTask(Player* player, Unit* victim)
{
if (!player)
return;
if (Group* group = player->GetGroup())
{
for (GroupReference* gr = group->GetFirstMember(); gr; gr = gr->next())
{
CheckKillTaskInternal(gr->GetSource(), victim);
}
}
else
{
CheckKillTaskInternal(player, victim);
}
}
void GuildTaskMgr::SendCompletionMessage(Player* player, std::string const verb)
{
std::ostringstream out;
out << player->GetName() << " has " << verb << " a guild task";
if (Group* group = player->GetGroup())
{
for (GroupReference* gr = group->GetFirstMember(); gr; gr = gr->next())
{
Player* member = gr->GetSource();
if (member != player)
ChatHandler(member->GetSession()).PSendSysMessage(out.str().c_str());
}
}
else
{
if (PlayerbotAI* botAI = GET_PLAYERBOT_AI(player))
if (Player* master = botAI->GetMaster())
ChatHandler(master->GetSession()).PSendSysMessage(out.str().c_str());
}
std::ostringstream self;
self << "You have " << verb << " a guild task";
ChatHandler(player->GetSession()).PSendSysMessage(self.str().c_str());
}
void GuildTaskMgr::CheckKillTaskInternal(Player* player, Unit* victim)
{
ObjectGuid::LowType owner = player->GetGUID().GetCounter();
if (victim->GetTypeId() != TYPEID_UNIT)
return;
Creature* creature = reinterpret_cast<Creature*>(victim);
if (!creature)
return;
std::map<uint32, uint32> tasks = GetTaskValues(owner, "killTask");
for (std::map<uint32, uint32>::iterator i = tasks.begin(); i != tasks.end(); ++i)
{
uint32 guildId = i->first;
uint32 value = i->second;
Guild* guild = sGuildMgr->GetGuildById(guildId);
if (value != creature->GetEntry())
continue;
LOG_DEBUG("playerbots", "{} / {}: guild task complete", guild->GetName().c_str(), player->GetName().c_str());
SetTaskValue(owner, guildId, "reward", 1,
urand(sPlayerbotAIConfig->minGuildTaskRewardTime, sPlayerbotAIConfig->maxGuildTaskRewardTime));
SendCompletionMessage(player, "completed");
}
}
void GuildTaskMgr::CleanupAdverts()
{
uint32 deliverTime = time(nullptr) - sPlayerbotAIConfig->minGuildTaskChangeTime;
QueryResult result = CharacterDatabase.Query(
"SELECT id, receiver FROM mail WHERE subject LIKE 'Guild Task%%' AND deliver_time <= {}", deliverTime);
if (!result)
return;
uint32 count = 0;
do
{
Field* fields = result->Fetch();
uint32 id = fields[0].Get<uint32>();
if (Player* player = ObjectAccessor::FindPlayer(ObjectGuid::Create<HighGuid::Player>(fields[1].Get<uint32>())))
player->RemoveMail(id);
++count;
} while (result->NextRow());
if (count > 0)
{
CharacterDatabase.Execute("DELETE FROM mail WHERE subject LIKE 'Guild Task%%' AND deliver_time <= {}",
deliverTime);
LOG_INFO("playerbots", "{} old gtask adverts removed", count);
}
}
void GuildTaskMgr::RemoveDuplicatedAdverts()
{
uint32 deliverTime = time(nullptr);
QueryResult result = CharacterDatabase.Query(
"SELECT m.id, m.receiver FROM (SELECT MAX(id) AS id, subject, receiver FROM mail WHERE subject LIKE 'Guild "
"Task%%' "
"AND deliver_time <= {} GROUP BY subject, receiver) q JOIN mail m ON m.subject = q.subject WHERE m.id <> q.id "
"AND m.deliver_time <= {}",
deliverTime, deliverTime);
if (!result)
return;
std::vector<uint32> ids;
uint32 count = 0;
do
{
Field* fields = result->Fetch();
uint32 id = fields[0].Get<uint32>();
if (Player* player = ObjectAccessor::FindPlayer(ObjectGuid::Create<HighGuid::Player>(fields[1].Get<uint32>())))
player->RemoveMail(id);
++count;
ids.push_back(id);
} while (result->NextRow());
if (count > 0)
{
std::vector<uint32> buffer;
for (std::vector<uint32>::iterator i = ids.begin(); i != ids.end(); ++i)
{
buffer.push_back(*i);
if (buffer.size() > 50)
{
DeleteMail(buffer);
buffer.clear();
}
}
DeleteMail(buffer);
LOG_INFO("playerbots", "{} duplicated gtask adverts removed", count);
}
}
void GuildTaskMgr::DeleteMail(std::vector<uint32> buffer)
{
std::ostringstream sql;
sql << "DELETE FROM mail WHERE id IN (";
bool first = true;
for (std::vector<uint32>::iterator j = buffer.begin(); j != buffer.end(); ++j)
{
if (first)
first = false;
else
sql << ",";
sql << *j;
}
sql << ")";
CharacterDatabase.Execute(sql.str().c_str());
}
bool GuildTaskMgr::CheckTaskTransfer(std::string const text, Player* ownerPlayer, Player* bot)
{
if (!bot)
return false;
uint32 guildId = bot->GetGuildId();
if (!guildId)
return false;
ObjectGuid::LowType owner = ownerPlayer->GetGUID().GetCounter();
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
if (!guild)
return false;
if (!sRandomPlayerbotMgr->IsRandomBot(bot))
return false;
if (text.empty())
return false;
LOG_DEBUG("playerbots", "{} / {}: checking guild task transfer", guild->GetName().c_str(),
ownerPlayer->GetName().c_str());
uint32 account = ownerPlayer->GetSession()->GetAccountId();
if (QueryResult results = CharacterDatabase.Query("SELECT guid, name FROM characters WHERE account = {}", account))
{
do
{
Field* fields = results->Fetch();
uint32 newOwner = fields[0].Get<uint32>();
std::string const name = fields[1].Get<std::string>();
if (newOwner == bot->GetGUID().GetCounter())
continue;
std::wstring wnamepart;
if (!Utf8toWStr(name, wnamepart))
return false;
wstrToLower(wnamepart);
if (Utf8FitTo(text, wnamepart))
{
uint32 validIn;
uint32 activeTask = GetTaskValue(owner, guildId, "activeTask", &validIn);
uint32 itemTask = GetTaskValue(owner, guildId, "itemTask");
uint32 killTask = GetTaskValue(owner, guildId, "killTask");
if (itemTask || killTask)
{
SetTaskValue(newOwner, guildId, "activeTask", activeTask, validIn);
SetTaskValue(newOwner, guildId, "advertisement", 1, 15);
if (itemTask)
SetTaskValue(newOwner, guildId, "itemTask", itemTask, validIn);
if (killTask)
SetTaskValue(newOwner, guildId, "killTask", killTask, validIn);
SetTaskValue(owner, guildId, "activeTask", 0, 0);
SetTaskValue(owner, guildId, "payment", 0, 0);
SendCompletionMessage(ownerPlayer, "transfered");
}
}
} while (results->NextRow());
}
return true;
}