mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-13 17:09:08 +00:00
These contains various fixes, fixes that have history worked one in past more then once as person as group, aswell @Wishmaster117. But due various reasons we had to drop them due priority or simply timewise. These fixes have recollected again by @Regrad based on his crash logs. Most crash logs we have, i am talking 30+ of them, to many to post here. @Regrad running a larger server 100+ real players with bots, which means he will walk into issues that most of us wont or are extremely difficult to reproduce. @Regrad used LLM to solve them based on crash log and mentioned his server crashes almost disappeared, instead of redoing every single PR and pull them apart. I tried to keep his bunch of changes together as whole, reviewed them, some redone, verified again etc etc. This is not how would normally do this. But since i want @Regrad being able to confirm, we need this in a package as a whole. Pulling them apart in the current situation is simply to much, to complicated in the verification process. So this PR is open and in my opinion has priority above others, but @Regrad is only person who can give the green light for the mod-playerbot changes for now. I, we spend huge amount of time into these issues over last couple of months. I will put other PR's on hold for abit. --------- Signed-off-by: Engardium <regradius@gmail.com> Co-authored-by: Engardium <regradius@gmail.com>
229 lines
6.3 KiB
C++
229 lines
6.3 KiB
C++
/*
|
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
*/
|
|
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <vector>
|
|
|
|
#include "ReadyCheckAction.h"
|
|
#include "Event.h"
|
|
#include "Playerbots.h"
|
|
|
|
std::string const formatPercent(std::string const name, uint8 value, float percent)
|
|
{
|
|
std::ostringstream out;
|
|
|
|
std::string color;
|
|
if (percent > 75)
|
|
color = "|cff00ff00";
|
|
else if (percent > 50)
|
|
color = "|cffffff00";
|
|
else
|
|
color = "|cffff0000";
|
|
|
|
out << "|cffffffff[" << name << "]" << color << "x" << (int)value;
|
|
return out.str();
|
|
}
|
|
|
|
class ReadyChecker
|
|
{
|
|
public:
|
|
virtual ~ReadyChecker() = default;
|
|
virtual bool Check(PlayerbotAI* botAI, AiObjectContext* context) = 0;
|
|
virtual std::string const getName() = 0;
|
|
virtual bool PrintAlways() { return true; }
|
|
|
|
static std::vector<std::unique_ptr<ReadyChecker>> checkers;
|
|
static std::once_flag initFlag;
|
|
};
|
|
|
|
std::vector<std::unique_ptr<ReadyChecker>> ReadyChecker::checkers;
|
|
std::once_flag ReadyChecker::initFlag;
|
|
|
|
class HealthChecker : public ReadyChecker
|
|
{
|
|
public:
|
|
bool Check(PlayerbotAI* botAI, AiObjectContext* context) override
|
|
{
|
|
return AI_VALUE2(uint8, "health", "self target") > sPlayerbotAIConfig->almostFullHealth;
|
|
}
|
|
|
|
std::string const getName() override { return "HP"; }
|
|
};
|
|
|
|
class ManaChecker : public ReadyChecker
|
|
{
|
|
public:
|
|
bool Check(PlayerbotAI* botAI, AiObjectContext* context) override
|
|
{
|
|
return !AI_VALUE2(bool, "has mana", "self target") ||
|
|
AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig->mediumHealth;
|
|
}
|
|
|
|
std::string const getName() override { return "MP"; }
|
|
};
|
|
|
|
class DistanceChecker : public ReadyChecker
|
|
{
|
|
public:
|
|
bool Check(PlayerbotAI* botAI, AiObjectContext* context) override
|
|
{
|
|
Player* bot = botAI->GetBot();
|
|
if (Player* master = botAI->GetMaster())
|
|
{
|
|
bool distance = bot->GetDistance(master) <= sPlayerbotAIConfig->sightDistance;
|
|
if (!distance)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool PrintAlways() override { return false; }
|
|
std::string const getName() override { return "Far away"; }
|
|
};
|
|
|
|
class HunterChecker : public ReadyChecker
|
|
{
|
|
public:
|
|
bool Check(PlayerbotAI* botAI, AiObjectContext* context) override
|
|
{
|
|
Player* bot = botAI->GetBot();
|
|
if (bot->getClass() == CLASS_HUNTER)
|
|
{
|
|
if (!bot->GetUInt32Value(PLAYER_AMMO_ID))
|
|
{
|
|
botAI->TellError("Out of ammo!");
|
|
return false;
|
|
}
|
|
|
|
if (!bot->GetPet())
|
|
{
|
|
botAI->TellError("No pet!");
|
|
return false;
|
|
}
|
|
|
|
if (bot->GetPet()->GetHappinessState() == UNHAPPY)
|
|
{
|
|
botAI->TellError("Pet is unhappy!");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool PrintAlways() override { return false; }
|
|
std::string const getName() override { return "Far away"; }
|
|
};
|
|
|
|
class ItemCountChecker : public ReadyChecker
|
|
{
|
|
public:
|
|
ItemCountChecker(std::string const item, std::string const name) : item(item), name(name) {}
|
|
|
|
bool Check(PlayerbotAI* botAI, AiObjectContext* context) override
|
|
{
|
|
return AI_VALUE2(uint32, "item count", item) > 0;
|
|
}
|
|
|
|
std::string const getName() override { return name; }
|
|
|
|
private:
|
|
std::string const item;
|
|
std::string const name;
|
|
};
|
|
|
|
class ManaPotionChecker : public ItemCountChecker
|
|
{
|
|
public:
|
|
ManaPotionChecker(std::string const item, std::string const name) : ItemCountChecker(item, name) {}
|
|
|
|
bool Check(PlayerbotAI* botAI, AiObjectContext* context) override
|
|
{
|
|
return !AI_VALUE2(bool, "has mana", "self target") || ItemCountChecker::Check(botAI, context);
|
|
}
|
|
};
|
|
|
|
bool ReadyCheckAction::Execute(Event event)
|
|
{
|
|
WorldPacket& p = event.getPacket();
|
|
ObjectGuid player;
|
|
p.rpos(0);
|
|
if (!p.empty())
|
|
{
|
|
p >> player;
|
|
if (player == bot->GetGUID())
|
|
return false;
|
|
}
|
|
|
|
return ReadyCheck();
|
|
}
|
|
|
|
bool ReadyCheckAction::ReadyCheck()
|
|
{
|
|
std::call_once(
|
|
ReadyChecker::initFlag,
|
|
[]()
|
|
{
|
|
ReadyChecker::checkers.reserve(8);
|
|
|
|
ReadyChecker::checkers.emplace_back(std::make_unique<HealthChecker>());
|
|
ReadyChecker::checkers.emplace_back(std::make_unique<ManaChecker>());
|
|
ReadyChecker::checkers.emplace_back(std::make_unique<DistanceChecker>());
|
|
ReadyChecker::checkers.emplace_back(std::make_unique<HunterChecker>());
|
|
|
|
ReadyChecker::checkers.emplace_back(std::make_unique<ItemCountChecker>("food", "Food"));
|
|
ReadyChecker::checkers.emplace_back(std::make_unique<ManaPotionChecker>("drink", "Water"));
|
|
ReadyChecker::checkers.emplace_back(std::make_unique<ItemCountChecker>("healing potion", "Hpot"));
|
|
ReadyChecker::checkers.emplace_back(std::make_unique<ManaPotionChecker>("mana potion", "Mpot"));
|
|
});
|
|
|
|
bool result = true;
|
|
for (auto const& checkerPtr : ReadyChecker::checkers)
|
|
{
|
|
if (!checkerPtr)
|
|
continue;
|
|
|
|
bool ok = checkerPtr->Check(botAI, context);
|
|
result = result && ok;
|
|
}
|
|
|
|
std::ostringstream out;
|
|
|
|
uint32 hp = AI_VALUE2(uint32, "item count", "healing potion");
|
|
out << formatPercent("Hp", hp, 100.0 * hp / 5);
|
|
|
|
out << ", ";
|
|
uint32 food = AI_VALUE2(uint32, "item count", "food");
|
|
out << formatPercent("Food", food, 100.0 * food / 20);
|
|
|
|
if (AI_VALUE2(bool, "has mana", "self target"))
|
|
{
|
|
out << ", ";
|
|
uint32 mp = AI_VALUE2(uint32, "item count", "mana potion");
|
|
out << formatPercent("Mp", mp, 100.0 * mp / 5);
|
|
|
|
out << ", ";
|
|
uint32 water = AI_VALUE2(uint32, "item count", "water");
|
|
out << formatPercent("Water", water, 100.0 * water / 20);
|
|
}
|
|
|
|
botAI->TellMaster(out);
|
|
|
|
WorldPacket packet(MSG_RAID_READY_CHECK);
|
|
packet << bot->GetGUID();
|
|
packet << uint8(1);
|
|
bot->GetSession()->HandleRaidReadyCheckOpcode(packet);
|
|
|
|
botAI->ChangeStrategy("-ready check", BOT_STATE_NON_COMBAT);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool FinishReadyCheckAction::Execute(Event event) { return ReadyCheck(); }
|