mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-16 22:58:34 +00:00
[Bots] Add Bot-specific Spell Settings. (#2553)
* [Bots] Add Bot-specific Spell Settings. # Notes - Allows players to set `priority`, `min_level`, `max_level`, `min_hp`, `max_hp`, and `is_enabled` settings per spell based on targeted bot. - Lets players disable spells they don't want their bots casting or change the criteria they cast them at if they want. * Update botspellsai.cpp * Update 2022_11_19_bot_spell_settings.sql * Typo. * Update botspellsai.cpp * Cleanup and add Reload Methods to Perl/Lua.
This commit is contained in:
+308
-8
@@ -25,6 +25,7 @@
|
||||
#include "lua_parser.h"
|
||||
#include "../common/strings.h"
|
||||
#include "../common/say_link.h"
|
||||
#include "../common/repositories/bot_spell_settings_repository.h"
|
||||
|
||||
extern volatile bool is_zone_loaded;
|
||||
|
||||
@@ -407,6 +408,7 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to
|
||||
|
||||
GetBotOwnerDataBuckets();
|
||||
GetBotDataBuckets();
|
||||
LoadBotSpellSettings();
|
||||
AI_AddBotSpells(GetBotSpellID());
|
||||
|
||||
CalcBotStats(false);
|
||||
@@ -10538,18 +10540,24 @@ bool Bot::GetBotOwnerDataBuckets()
|
||||
return false;
|
||||
}
|
||||
|
||||
auto query = fmt::format(
|
||||
const auto query = fmt::format(
|
||||
"SELECT `key`, `value` FROM data_buckets WHERE `key` LIKE '{}-%'",
|
||||
Strings::Escape(bot_owner->GetBucketKey())
|
||||
);
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bot_owner_data_buckets.clear();
|
||||
|
||||
if (!results.RowCount()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (auto row : results) {
|
||||
bot_data_buckets.insert(std::pair<std::string,std::string>(row[0], row[1]));
|
||||
bot_owner_data_buckets.insert(std::pair<std::string,std::string>(row[0], row[1]));
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -10557,16 +10565,22 @@ bool Bot::GetBotOwnerDataBuckets()
|
||||
|
||||
bool Bot::GetBotDataBuckets()
|
||||
{
|
||||
auto query = fmt::format(
|
||||
const auto query = fmt::format(
|
||||
"SELECT `key`, `value` FROM data_buckets WHERE `key` LIKE '{}-%'",
|
||||
Strings::Escape(GetBucketKey())
|
||||
);
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bot_data_buckets.clear();
|
||||
|
||||
if (!results.RowCount()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (auto row : results) {
|
||||
bot_data_buckets.insert(std::pair<std::string,std::string>(row[0], row[1]));
|
||||
}
|
||||
@@ -10591,7 +10605,7 @@ bool Bot::CheckDataBucket(std::string bucket_name, std::string bucket_value, uin
|
||||
bucket_name
|
||||
);
|
||||
|
||||
player_value = bot_data_buckets[full_name];
|
||||
player_value = bot_owner_data_buckets[full_name];
|
||||
if (player_value.empty()) {
|
||||
return false;
|
||||
}
|
||||
@@ -10635,6 +10649,292 @@ void Bot::SetExpansionBitmask(int expansion_bitmask, bool save)
|
||||
LoadAAs();
|
||||
}
|
||||
|
||||
bool Bot::AddBotSpellSetting(uint16 spell_id, BotSpellSetting* bs)
|
||||
{
|
||||
if (!IsValidSpell(spell_id) || !bs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto obs = GetBotSpellSetting(spell_id);
|
||||
if (obs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto s = BotSpellSettingsRepository::NewEntity();
|
||||
|
||||
s.spell_id = spell_id;
|
||||
s.bot_id = GetBotID();
|
||||
|
||||
s.priority = bs->priority;
|
||||
s.min_level = bs->min_level;
|
||||
s.max_level = bs->max_level;
|
||||
s.min_hp = bs->min_hp;
|
||||
s.max_hp = bs->max_hp;
|
||||
s.is_enabled = bs->is_enabled;
|
||||
|
||||
const auto& nbs = BotSpellSettingsRepository::InsertOne(content_db, s);
|
||||
if (!nbs.id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LoadBotSpellSettings();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Bot::DeleteBotSpellSetting(uint16 spell_id)
|
||||
{
|
||||
if (!IsValidSpell(spell_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto bs = GetBotSpellSetting(spell_id);
|
||||
if (!bs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BotSpellSettingsRepository::DeleteWhere(
|
||||
content_db,
|
||||
fmt::format(
|
||||
"bot_id = {} AND spell_id = {}",
|
||||
GetBotID(),
|
||||
spell_id
|
||||
)
|
||||
);
|
||||
LoadBotSpellSettings();
|
||||
return true;
|
||||
}
|
||||
|
||||
BotSpellSetting* Bot::GetBotSpellSetting(uint16 spell_id)
|
||||
{
|
||||
if (!IsValidSpell(spell_id) || !bot_spell_settings.count(spell_id)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto b = bot_spell_settings.find(spell_id);
|
||||
if (b != bot_spell_settings.end()) {
|
||||
return &b->second;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Bot::ListBotSpells()
|
||||
{
|
||||
auto bot_owner = GetBotOwner();
|
||||
if (!bot_owner) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (AIBot_spells.empty()) {
|
||||
bot_owner->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} has no AI Spells.",
|
||||
GetCleanName()
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
auto spell_count = 0;
|
||||
auto spell_number = 1;
|
||||
|
||||
for (const auto& s : AIBot_spells) {
|
||||
bot_owner->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Spell {} | Spell: {} ({})",
|
||||
spell_number,
|
||||
spells[s.spellid].name,
|
||||
s.spellid
|
||||
).c_str()
|
||||
);
|
||||
|
||||
bot_owner->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Spell {} | Priority: {} Health: {}",
|
||||
spell_number,
|
||||
s.priority,
|
||||
GetHPString(s.min_hp, s.max_hp)
|
||||
).c_str()
|
||||
);
|
||||
|
||||
spell_count++;
|
||||
spell_number++;
|
||||
}
|
||||
|
||||
bot_owner->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} has {} AI Spell{}.",
|
||||
GetCleanName(),
|
||||
spell_count,
|
||||
spell_count != 1 ? "s" :""
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
|
||||
void Bot::ListBotSpellSettings()
|
||||
{
|
||||
auto bot_owner = GetBotOwner();
|
||||
if (!bot_owner) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bot_spell_settings.size()) {
|
||||
bot_owner->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} does not have any spell settings.",
|
||||
GetCleanName()
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
auto setting_count = 0;
|
||||
auto setting_number = 1;
|
||||
|
||||
for (const auto& bs : bot_spell_settings) {
|
||||
bot_owner->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Setting {} | Spell: {} ({}) Enabled: {}",
|
||||
setting_number,
|
||||
spells[bs.first].name,
|
||||
bs.first,
|
||||
bs.second.is_enabled ? "Yes" : "No"
|
||||
).c_str()
|
||||
);
|
||||
|
||||
bot_owner->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Setting {} | Priority: {} Levels: {} Health: {}",
|
||||
setting_number,
|
||||
bs.second.priority,
|
||||
GetLevelString(bs.second.min_level, bs.second.max_level),
|
||||
GetHPString(bs.second.min_hp, bs.second.max_hp)
|
||||
).c_str()
|
||||
);
|
||||
|
||||
setting_count++;
|
||||
setting_number++;
|
||||
}
|
||||
|
||||
bot_owner->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} has {} spell setting{}.",
|
||||
GetCleanName(),
|
||||
setting_count,
|
||||
setting_count != 1 ? "s" : ""
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
|
||||
void Bot::LoadBotSpellSettings()
|
||||
{
|
||||
bot_spell_settings.clear();
|
||||
|
||||
auto s = BotSpellSettingsRepository::GetWhere(content_db, fmt::format("bot_id = {}", GetBotID()));
|
||||
if (s.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& e : s) {
|
||||
BotSpellSetting b;
|
||||
|
||||
b.priority = e.priority;
|
||||
b.min_level = e.min_level;
|
||||
b.max_level = e.max_level;
|
||||
b.min_hp = e.min_hp;
|
||||
b.max_hp = e.max_hp;
|
||||
b.is_enabled = e.is_enabled;
|
||||
|
||||
bot_spell_settings[e.spell_id] = b;
|
||||
}
|
||||
}
|
||||
|
||||
bool Bot::UpdateBotSpellSetting(uint16 spell_id, BotSpellSetting* bs)
|
||||
{
|
||||
if (!IsValidSpell(spell_id) || !bs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto s = BotSpellSettingsRepository::NewEntity();
|
||||
|
||||
s.spell_id = spell_id;
|
||||
s.bot_id = GetBotID();
|
||||
s.priority = bs->priority;
|
||||
s.min_level = bs->min_level;
|
||||
s.max_level = bs->max_level;
|
||||
s.min_hp = bs->min_hp;
|
||||
s.max_hp = bs->max_hp;
|
||||
s.is_enabled = bs->is_enabled;
|
||||
|
||||
auto obs = GetBotSpellSetting(spell_id);
|
||||
if (!obs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!BotSpellSettingsRepository::UpdateSpellSetting(content_db, s)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LoadBotSpellSettings();
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string Bot::GetLevelString(uint8 min_level, uint8 max_level)
|
||||
{
|
||||
std::string level_string = "Any";
|
||||
if (min_level && max_level) {
|
||||
level_string = fmt::format(
|
||||
"{} to {}",
|
||||
min_level,
|
||||
max_level
|
||||
);
|
||||
} else if (min_level && !max_level) {
|
||||
level_string = fmt::format(
|
||||
"{}+",
|
||||
min_level
|
||||
);
|
||||
} else if (!min_level && max_level) {
|
||||
level_string = fmt::format(
|
||||
"1 to {}",
|
||||
max_level
|
||||
);
|
||||
}
|
||||
|
||||
return level_string;
|
||||
}
|
||||
|
||||
std::string Bot::GetHPString(int8 min_hp, int8 max_hp)
|
||||
{
|
||||
std::string hp_string = "Any";
|
||||
if (min_hp && max_hp) {
|
||||
hp_string = fmt::format(
|
||||
"{}%% to {}%%",
|
||||
min_hp,
|
||||
max_hp
|
||||
);
|
||||
} else if (min_hp && !max_hp) {
|
||||
hp_string = fmt::format(
|
||||
"{}%% to 100%%",
|
||||
min_hp
|
||||
);
|
||||
} else if (!min_hp && max_hp) {
|
||||
hp_string = fmt::format(
|
||||
"1%% to {}%%",
|
||||
max_hp
|
||||
);
|
||||
}
|
||||
|
||||
return hp_string;
|
||||
}
|
||||
|
||||
uint8 Bot::spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND] = { 0 };
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user