mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
Added bot commands 'applypoison' and 'applypotion' .. new bot owner option 'buffcounter'
This commit is contained in:
parent
86593798a9
commit
35fe27eb5d
@ -599,6 +599,9 @@ RULE_INT(Bots, AllowedGenders, 0x3, "Bitmask of allowed bot genders")
|
||||
RULE_BOOL(Bots, AllowOwnerOptionAltCombat, true, "When option is enabled, bots will use an auto-/shared-aggro combat model")
|
||||
RULE_BOOL(Bots, AllowOwnerOptionAutoDefend, true, "When option is enabled, bots will defend their owner on enemy aggro")
|
||||
RULE_REAL(Bots, LeashDistance, 562500.0f, "Distance a bot is allowed to travel from leash owner before being pulled back (squared value)")
|
||||
RULE_BOOL(Bots, AllowApplyPoisonCommand, true, "Allows the use of the bot command 'applypoison'")
|
||||
RULE_BOOL(Bots, AllowApplyPotionCommand, true, "Allows the use of the bot command 'applypotion'")
|
||||
RULE_BOOL(Bots, RestrictApplyPotionToRogue, true, "Restricts the bot command 'applypotion' to rogue-usable potions (i.e., poisons)")
|
||||
RULE_CATEGORY_END()
|
||||
#endif
|
||||
|
||||
|
||||
169
zone/bot.cpp
169
zone/bot.cpp
@ -236,8 +236,157 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to
|
||||
|
||||
LoadAAs();
|
||||
|
||||
if (!database.botdb.LoadBuffs(this) && bot_owner)
|
||||
// copied from client CompleteConnect() handler - watch for problems
|
||||
// (may have to move to post-spawn location if certain buffs still don't process correctly)
|
||||
if (database.botdb.LoadBuffs(this) && bot_owner) {
|
||||
|
||||
//reapply some buffs
|
||||
uint32 buff_count = GetMaxTotalSlots();
|
||||
for (uint32 j1 = 0; j1 < buff_count; j1++) {
|
||||
if (!IsValidSpell(buffs[j1].spellid))
|
||||
continue;
|
||||
|
||||
const SPDat_Spell_Struct& spell = spells[buffs[j1].spellid];
|
||||
|
||||
int NimbusEffect = GetNimbusEffect(buffs[j1].spellid);
|
||||
if (NimbusEffect) {
|
||||
if (!IsNimbusEffectActive(NimbusEffect))
|
||||
SendSpellEffect(NimbusEffect, 500, 0, 1, 3000, true);
|
||||
}
|
||||
|
||||
for (int x1 = 0; x1 < EFFECT_COUNT; x1++) {
|
||||
switch (spell.effectid[x1]) {
|
||||
case SE_IllusionCopy:
|
||||
case SE_Illusion: {
|
||||
if (spell.base[x1] == -1) {
|
||||
if (gender == 1)
|
||||
gender = 0;
|
||||
else if (gender == 0)
|
||||
gender = 1;
|
||||
SendIllusionPacket(GetRace(), gender, 0xFF, 0xFF);
|
||||
}
|
||||
else if (spell.base[x1] == -2) // WTF IS THIS
|
||||
{
|
||||
if (GetRace() == 128 || GetRace() == 130 || GetRace() <= 12)
|
||||
SendIllusionPacket(GetRace(), GetGender(), spell.base2[x1], spell.max[x1]);
|
||||
}
|
||||
else if (spell.max[x1] > 0)
|
||||
{
|
||||
SendIllusionPacket(spell.base[x1], 0xFF, spell.base2[x1], spell.max[x1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
SendIllusionPacket(spell.base[x1], 0xFF, 0xFF, 0xFF);
|
||||
}
|
||||
switch (spell.base[x1]) {
|
||||
case OGRE:
|
||||
SendAppearancePacket(AT_Size, 9);
|
||||
break;
|
||||
case TROLL:
|
||||
SendAppearancePacket(AT_Size, 8);
|
||||
break;
|
||||
case VAHSHIR:
|
||||
case BARBARIAN:
|
||||
SendAppearancePacket(AT_Size, 7);
|
||||
break;
|
||||
case HALF_ELF:
|
||||
case WOOD_ELF:
|
||||
case DARK_ELF:
|
||||
case FROGLOK:
|
||||
SendAppearancePacket(AT_Size, 5);
|
||||
break;
|
||||
case DWARF:
|
||||
SendAppearancePacket(AT_Size, 4);
|
||||
break;
|
||||
case HALFLING:
|
||||
case GNOME:
|
||||
SendAppearancePacket(AT_Size, 3);
|
||||
break;
|
||||
default:
|
||||
SendAppearancePacket(AT_Size, 6);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
//case SE_SummonHorse: {
|
||||
// SummonHorse(buffs[j1].spellid);
|
||||
// //hasmount = true; //this was false, is that the correct thing?
|
||||
// break;
|
||||
//}
|
||||
case SE_Silence:
|
||||
{
|
||||
Silence(true);
|
||||
break;
|
||||
}
|
||||
case SE_Amnesia:
|
||||
{
|
||||
Amnesia(true);
|
||||
break;
|
||||
}
|
||||
case SE_DivineAura:
|
||||
{
|
||||
invulnerable = true;
|
||||
break;
|
||||
}
|
||||
case SE_Invisibility2:
|
||||
case SE_Invisibility:
|
||||
{
|
||||
invisible = true;
|
||||
SendAppearancePacket(AT_Invis, 1);
|
||||
break;
|
||||
}
|
||||
case SE_Levitate:
|
||||
{
|
||||
if (!zone->CanLevitate())
|
||||
{
|
||||
//if (!GetGM())
|
||||
//{
|
||||
SendAppearancePacket(AT_Levitate, 0);
|
||||
BuffFadeByEffect(SE_Levitate);
|
||||
//Message(Chat::Red, "You can't levitate in this zone.");
|
||||
//}
|
||||
}
|
||||
else {
|
||||
SendAppearancePacket(AT_Levitate, 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SE_InvisVsUndead2:
|
||||
case SE_InvisVsUndead:
|
||||
{
|
||||
invisible_undead = true;
|
||||
break;
|
||||
}
|
||||
case SE_InvisVsAnimals:
|
||||
{
|
||||
invisible_animals = true;
|
||||
break;
|
||||
}
|
||||
case SE_AddMeleeProc:
|
||||
case SE_WeaponProc:
|
||||
{
|
||||
AddProcToWeapon(GetProcID(buffs[j1].spellid, x1), false, 100 + spells[buffs[j1].spellid].base2[x1], buffs[j1].spellid, buffs[j1].casterlevel);
|
||||
break;
|
||||
}
|
||||
case SE_DefensiveProc:
|
||||
{
|
||||
AddDefensiveProc(GetProcID(buffs[j1].spellid, x1), 100 + spells[buffs[j1].spellid].base2[x1], buffs[j1].spellid);
|
||||
break;
|
||||
}
|
||||
case SE_RangedProc:
|
||||
{
|
||||
AddRangedProc(GetProcID(buffs[j1].spellid, x1), 100 + spells[buffs[j1].spellid].base2[x1], buffs[j1].spellid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else {
|
||||
bot_owner->Message(Chat::Red, "&s for '%s'", BotDatabase::fail::LoadBuffs(), GetCleanName());
|
||||
}
|
||||
|
||||
CalcBotStats(false);
|
||||
hp_regen = CalcHPRegen();
|
||||
@ -4726,9 +4875,9 @@ bool Bot::Death(Mob *killerMob, int32 damage, uint16 spell_id, EQEmu::skills::Sk
|
||||
Mob *my_owner = GetBotOwner();
|
||||
if (my_owner && my_owner->IsClient() && my_owner->CastToClient()->GetBotOption(Client::booDeathMarquee)) {
|
||||
if (killerMob)
|
||||
my_owner->CastToClient()->SendMarqueeMessage(Chat::Yellow, 510, 0, 1000, 3000, StringFormat("%s has been slain by %s", GetCleanName(), killerMob->GetCleanName()));
|
||||
my_owner->CastToClient()->SendMarqueeMessage(Chat::Red, 510, 0, 1000, 3000, StringFormat("%s has been slain by %s", GetCleanName(), killerMob->GetCleanName()));
|
||||
else
|
||||
my_owner->CastToClient()->SendMarqueeMessage(Chat::Yellow, 510, 0, 1000, 3000, StringFormat("%s has been slain", GetCleanName()));
|
||||
my_owner->CastToClient()->SendMarqueeMessage(Chat::Red, 510, 0, 1000, 3000, StringFormat("%s has been slain", GetCleanName()));
|
||||
}
|
||||
|
||||
Mob *give_exp = hate_list.GetDamageTopOnHateList(this);
|
||||
@ -8989,6 +9138,20 @@ Bot* EntityList::GetBotByBotName(std::string botName) {
|
||||
return Result;
|
||||
}
|
||||
|
||||
Client* EntityList::GetBotOwnerByBotEntityID(uint16 entityID) {
|
||||
Client* Result = nullptr;
|
||||
if (entityID > 0) {
|
||||
for (std::list<Bot*>::iterator botListItr = bot_list.begin(); botListItr != bot_list.end(); ++botListItr) {
|
||||
Bot* tempBot = *botListItr;
|
||||
if (tempBot && tempBot->GetID() == entityID) {
|
||||
Result = tempBot->GetBotOwner()->CastToClient();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
void EntityList::AddBot(Bot *newBot, bool SendSpawnPacket, bool dontqueue) {
|
||||
if(newBot) {
|
||||
newBot->SetID(GetFreeID());
|
||||
|
||||
@ -1321,6 +1321,8 @@ int bot_command_init(void)
|
||||
if (
|
||||
bot_command_add("actionable", "Lists actionable command arguments and use descriptions", 0, bot_command_actionable) ||
|
||||
bot_command_add("aggressive", "Orders a bot to use a aggressive discipline", 0, bot_command_aggressive) ||
|
||||
bot_command_add("applypoison", "Applies cursor-held poison to a rogue bot's weapon", 0, bot_command_apply_poison) ||
|
||||
bot_command_add("applypotion", "Applies cursor-held potion to a bot's effects", 0, bot_command_apply_potion) ||
|
||||
bot_command_add("attack", "Orders bots to attack a designated target", 0, bot_command_attack) ||
|
||||
bot_command_add("bindaffinity", "Orders a bot to attempt an affinity binding", 0, bot_command_bind_affinity) ||
|
||||
bot_command_add("bot", "Lists the available bot management [subcommands]", 0, bot_command_bot) ||
|
||||
@ -2579,6 +2581,166 @@ void bot_command_aggressive(Client *c, const Seperator *sep)
|
||||
c->Message(m_action, "%i of %i bots have used aggressive disciplines", success_count, candidate_count);
|
||||
}
|
||||
|
||||
void bot_command_apply_poison(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (helper_command_disabled(c, RuleB(Bots, AllowApplyPoisonCommand), "applypoison")) {
|
||||
return;
|
||||
}
|
||||
if (helper_command_alias_fail(c, "bot_command_apply_poison", sep->arg[0], "applypoison")) {
|
||||
return;
|
||||
}
|
||||
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||
|
||||
c->Message(m_usage, "usage: <rogue_bot_target> %s", sep->arg[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
Bot *my_rogue_bot = nullptr;
|
||||
if (c->GetTarget() && c->GetTarget()->IsBot() && c->GetTarget()->CastToBot()->GetBotOwnerCharacterID() == c->CharacterID() && c->GetTarget()->CastToBot()->GetClass() == ROGUE) {
|
||||
my_rogue_bot = c->GetTarget()->CastToBot();
|
||||
}
|
||||
if (!my_rogue_bot) {
|
||||
|
||||
c->Message(m_fail, "You must target a rogue bot that you own to use this command!");
|
||||
return;
|
||||
}
|
||||
if (my_rogue_bot->GetLevel() < 18) {
|
||||
|
||||
c->Message(m_fail, "Your rogue bot must be level 18 before %s can apply poison!", (my_rogue_bot->GetGender() == 1 ? "she" : "he"));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto poison_instance = c->GetInv().GetItem(EQEmu::invslot::slotCursor);
|
||||
if (!poison_instance) {
|
||||
|
||||
c->Message(m_fail, "No item found on cursor!");
|
||||
return;
|
||||
}
|
||||
|
||||
auto poison_data = poison_instance->GetItem();
|
||||
if (!poison_data) {
|
||||
|
||||
c->Message(m_fail, "No data found for cursor item!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (poison_data->ItemType == EQEmu::item::ItemTypePoison) {
|
||||
|
||||
if ((~poison_data->Races) & GetPlayerRaceBit(my_rogue_bot->GetRace())) {
|
||||
|
||||
c->Message(m_fail, "Invalid race for weapon poison!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (poison_data->Proc.Level2 > my_rogue_bot->GetLevel()) {
|
||||
|
||||
c->Message(m_fail, "This poison is too powerful for your intended target!");
|
||||
return;
|
||||
}
|
||||
|
||||
// generalized from client ApplyPoison handler
|
||||
double ChanceRoll = zone->random.Real(0, 1);
|
||||
uint16 poison_skill = 95 + ((my_rogue_bot->GetLevel() - 18) * 5);
|
||||
if (poison_skill > 200) {
|
||||
poison_skill = 200;
|
||||
}
|
||||
bool apply_poison_chance = (ChanceRoll < (.75 + poison_skill / 1000));
|
||||
|
||||
if (apply_poison_chance && my_rogue_bot->AddProcToWeapon(poison_data->Proc.Effect, false, (my_rogue_bot->GetDEX() / 100) + 103, POISON_PROC)) {
|
||||
c->Message(m_action, "Successfully applied %s to %s's weapon.", poison_data->Name, my_rogue_bot->GetCleanName());
|
||||
}
|
||||
else {
|
||||
c->Message(m_fail, "Failed to apply %s to %s's weapon.", poison_data->Name, my_rogue_bot->GetCleanName());
|
||||
}
|
||||
|
||||
c->DeleteItemInInventory(EQEmu::invslot::slotCursor, 1, true);
|
||||
}
|
||||
else {
|
||||
|
||||
c->Message(m_fail, "Item on cursor is not a weapon poison!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void bot_command_apply_potion(Client* c, const Seperator* sep)
|
||||
{
|
||||
if (helper_command_disabled(c, RuleB(Bots, AllowApplyPotionCommand), "applypotion")) {
|
||||
return;
|
||||
}
|
||||
if (helper_command_alias_fail(c, "bot_command_apply_potion", sep->arg[0], "applypotion")) {
|
||||
return;
|
||||
}
|
||||
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||
|
||||
c->Message(m_usage, "usage: <bot_target> %s", sep->arg[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
Bot* my_bot = nullptr;
|
||||
if (c->GetTarget() && c->GetTarget()->IsBot() && c->GetTarget()->CastToBot()->GetBotOwnerCharacterID() == c->CharacterID()) {
|
||||
my_bot = c->GetTarget()->CastToBot();
|
||||
}
|
||||
if (!my_bot) {
|
||||
|
||||
c->Message(m_fail, "You must target a bot that you own to use this command!");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto potion_instance = c->GetInv().GetItem(EQEmu::invslot::slotCursor);
|
||||
if (!potion_instance) {
|
||||
|
||||
c->Message(m_fail, "No item found on cursor!");
|
||||
return;
|
||||
}
|
||||
|
||||
auto potion_data = potion_instance->GetItem();
|
||||
if (!potion_data) {
|
||||
|
||||
c->Message(m_fail, "No data found for cursor item!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (potion_data->ItemType == EQEmu::item::ItemTypePotion && potion_data->Click.Effect > 0) {
|
||||
|
||||
if (RuleB(Bots, RestrictApplyPotionToRogue) && potion_data->Classes != PLAYER_CLASS_ROGUE_BIT) {
|
||||
|
||||
c->Message(m_fail, "This command is restricted to rogue poison potions only!");
|
||||
return;
|
||||
}
|
||||
if ((~potion_data->Races) & GetPlayerRaceBit(my_bot->GetRace())) {
|
||||
|
||||
c->Message(m_fail, "Invalid race for potion!");
|
||||
return;
|
||||
}
|
||||
if ((~potion_data->Classes) & GetPlayerClassBit(my_bot->GetClass())) {
|
||||
|
||||
c->Message(m_fail, "Invalid class for potion!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (potion_data->Click.Level2 > my_bot->GetLevel()) {
|
||||
|
||||
c->Message(m_fail, "This potion is too powerful for your intended target!");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: figure out best way to handle casting time/animation
|
||||
if (my_bot->SpellFinished(potion_data->Click.Effect, my_bot, EQEmu::spells::CastingSlot::Item, 0)) {
|
||||
c->Message(m_action, "Successfully applied %s to %s's buff effects.", potion_data->Name, my_bot->GetCleanName());
|
||||
}
|
||||
else {
|
||||
c->Message(m_fail, "Failed to apply %s to %s's buff effects.", potion_data->Name, my_bot->GetCleanName());
|
||||
}
|
||||
|
||||
c->DeleteItemInInventory(EQEmu::invslot::slotCursor, 1, true);
|
||||
}
|
||||
else {
|
||||
|
||||
c->Message(m_fail, "Item on cursor is not a potion!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void bot_command_attack(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (helper_command_alias_fail(c, "bot_command_attack", sep->arg[0], "attack")) {
|
||||
@ -3637,6 +3799,16 @@ void bot_command_owner_option(Client *c, const Seperator *sep)
|
||||
"<td><c \"#00CCCC\">null</td>"
|
||||
"<td><c \"#888888\">(toggles)</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td><c \"#CCCCCC\">buffcounter</td>"
|
||||
"<td><c \"#00CC00\">enable <c \"#CCCCCC\">| <c \"#00CC00\">disable</td>"
|
||||
"<td><c \"#888888\">marquee message on buff counter change</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td></td>"
|
||||
"<td><c \"#00CCCC\">null</td>"
|
||||
"<td><c \"#888888\">(toggles)</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td><c \"#CCCCCC\">current</td>"
|
||||
"<td></td>"
|
||||
@ -3796,6 +3968,22 @@ void bot_command_owner_option(Client *c, const Seperator *sep)
|
||||
c->Message(m_fail, "Bot owner option 'autodefend' is not allowed on this server.");
|
||||
}
|
||||
}
|
||||
else if (!owner_option.compare("buffcounter")) {
|
||||
|
||||
if (!argument.compare("enable")) {
|
||||
c->SetBotOption(Client::booBuffCounter, true);
|
||||
}
|
||||
else if (!argument.compare("disable")) {
|
||||
c->SetBotOption(Client::booBuffCounter, false);
|
||||
}
|
||||
else {
|
||||
c->SetBotOption(Client::booBuffCounter, !c->GetBotOption(Client::booBuffCounter));
|
||||
}
|
||||
|
||||
database.botdb.SaveOwnerOption(c->CharacterID(), Client::booBuffCounter, c->GetBotOption(Client::booBuffCounter));
|
||||
|
||||
c->Message(m_action, "Bot 'buff counter' is now %s.", (c->GetBotOption(Client::booBuffCounter) == true ? "enabled" : "disabled"));
|
||||
}
|
||||
else if (!owner_option.compare("current")) {
|
||||
|
||||
std::string window_title = "Current Bot Owner Options Settings";
|
||||
@ -3811,13 +3999,15 @@ void bot_command_owner_option(Client *c, const Seperator *sep)
|
||||
"<tr>" "<td><c \"#CCCCCC\">spawnmessage</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||
"<tr>" "<td><c \"#CCCCCC\">altcombat</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||
"<tr>" "<td><c \"#CCCCCC\">autodefend</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||
"<tr>" "<td><c \"#CCCCCC\">buffcounter</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||
"</table>",
|
||||
(c->GetBotOption(Client::booDeathMarquee) ? "enabled" : "disabled"),
|
||||
(c->GetBotOption(Client::booStatsUpdate) ? "enabled" : "disabled"),
|
||||
(c->GetBotOption(Client::booSpawnMessageSay) ? "say" : (c->GetBotOption(Client::booSpawnMessageTell) ? "tell" : "silent")),
|
||||
(c->GetBotOption(Client::booSpawnMessageClassSpecific) ? "class" : "default"),
|
||||
(RuleB(Bots, AllowOwnerOptionAltCombat) ? (c->GetBotOption(Client::booAltCombat) ? "enabled" : "disabled") : "restricted"),
|
||||
(RuleB(Bots, AllowOwnerOptionAutoDefend) ? (c->GetBotOption(Client::booAutoDefend) ? "enabled" : "disabled") : "restricted")
|
||||
(RuleB(Bots, AllowOwnerOptionAutoDefend) ? (c->GetBotOption(Client::booAutoDefend) ? "enabled" : "disabled") : "restricted"),
|
||||
(c->GetBotOption(Client::booBuffCounter) ? "enabled" : "disabled")
|
||||
);
|
||||
|
||||
c->SendPopupToClient(window_title.c_str(), window_text.c_str());
|
||||
@ -8444,6 +8634,16 @@ bool helper_cast_standard_spell(Bot* casting_bot, Mob* target_mob, int spell_id,
|
||||
return casting_bot->CastSpell(spell_id, target_mob->GetID(), EQEmu::spells::CastingSlot::Gem2, -1, -1, dont_root_before);
|
||||
}
|
||||
|
||||
bool helper_command_disabled(Client* bot_owner, bool rule_value, const char* command)
|
||||
{
|
||||
if (rule_value == false) {
|
||||
bot_owner->Message(m_fail, "Bot command %s is not enabled on this server.", command);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool helper_command_alias_fail(Client *bot_owner, const char* command_handler, const char *alias, const char *command)
|
||||
{
|
||||
auto alias_iter = bot_command_aliases.find(&alias[1]);
|
||||
|
||||
@ -553,6 +553,8 @@ void bot_command_log_command(Client *c, const char *message);
|
||||
// bot commands
|
||||
void bot_command_actionable(Client *c, const Seperator *sep);
|
||||
void bot_command_aggressive(Client *c, const Seperator *sep);
|
||||
void bot_command_apply_poison(Client *c, const Seperator *sep);
|
||||
void bot_command_apply_potion(Client* c, const Seperator* sep);
|
||||
void bot_command_attack(Client *c, const Seperator *sep);
|
||||
void bot_command_bind_affinity(Client *c, const Seperator *sep);
|
||||
void bot_command_bot(Client *c, const Seperator *sep);
|
||||
@ -671,6 +673,7 @@ void helper_bot_appearance_form_update(Bot *my_bot);
|
||||
uint32 helper_bot_create(Client *bot_owner, std::string bot_name, uint8 bot_class, uint16 bot_race, uint8 bot_gender);
|
||||
void helper_bot_out_of_combat(Client *bot_owner, Bot *my_bot);
|
||||
bool helper_cast_standard_spell(Bot* casting_bot, Mob* target_mob, int spell_id, bool annouce_cast = true, uint32* dont_root_before = nullptr);
|
||||
bool helper_command_disabled(Client *bot_owner, bool rule_value, const char *command);
|
||||
bool helper_command_alias_fail(Client *bot_owner, const char* command_handler, const char *alias, const char *command);
|
||||
void helper_command_depart_list(Client* bot_owner, Bot* druid_bot, Bot* wizard_bot, bcst_list* local_list, bool single_flag = false);
|
||||
bool helper_is_help_or_usage(const char* arg);
|
||||
|
||||
@ -2256,6 +2256,7 @@ bool BotDatabase::SaveOwnerOption(const uint32 owner_id, size_t type, const bool
|
||||
case Client::booSpawnMessageClassSpecific:
|
||||
case Client::booAltCombat:
|
||||
case Client::booAutoDefend:
|
||||
case Client::booBuffCounter:
|
||||
{
|
||||
query = fmt::format(
|
||||
"REPLACE INTO `bot_owner_options`(`owner_id`, `option_type`, `option_value`) VALUES ('{}', '{}', '{}')",
|
||||
|
||||
@ -356,6 +356,7 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
bot_owner_options[booSpawnMessageClassSpecific] = true;
|
||||
bot_owner_options[booAltCombat] = RuleB(Bots, AllowOwnerOptionAltCombat);
|
||||
bot_owner_options[booAutoDefend] = RuleB(Bots, AllowOwnerOptionAutoDefend);
|
||||
bot_owner_options[booBuffCounter] = false;
|
||||
|
||||
SetBotPulling(false);
|
||||
SetBotPrecombat(false);
|
||||
|
||||
@ -1640,6 +1640,7 @@ public:
|
||||
booSpawnMessageClassSpecific,
|
||||
booAltCombat,
|
||||
booAutoDefend,
|
||||
booBuffCounter,
|
||||
_booCount
|
||||
};
|
||||
|
||||
|
||||
@ -553,6 +553,7 @@ private:
|
||||
Mob* GetMobByBotID(uint32 botID);
|
||||
Bot* GetBotByBotID(uint32 botID);
|
||||
Bot* GetBotByBotName(std::string botName);
|
||||
Client* GetBotOwnerByBotEntityID(uint16 entityID);
|
||||
std::list<Bot*> GetBotsByBotOwnerCharacterID(uint32 botOwnerCharacterID);
|
||||
|
||||
bool Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, float iRange, uint32 iSpellTypes); // TODO: Evaluate this closesly in hopes to eliminate
|
||||
|
||||
@ -5662,11 +5662,24 @@ void Mob::CheckNumHitsRemaining(NumHit type, int32 buff_slot, uint16 spell_id)
|
||||
bool bDepleted = false;
|
||||
int buff_max = GetMaxTotalSlots();
|
||||
|
||||
#ifdef BOTS
|
||||
std::string buff_name;
|
||||
size_t buff_counter = 0;
|
||||
bool buff_update = false;
|
||||
#endif
|
||||
|
||||
//Spell specific procs [Type 7,10,11]
|
||||
if (IsValidSpell(spell_id)) {
|
||||
for (int d = 0; d < buff_max; d++) {
|
||||
if (buffs[d].spellid == spell_id && buffs[d].numhits > 0 &&
|
||||
spells[buffs[d].spellid].numhitstype == static_cast<int>(type)) {
|
||||
|
||||
#ifdef BOTS
|
||||
buff_name = spells[buffs[d].spellid].name;
|
||||
buff_counter = (buffs[d].numhits - 1);
|
||||
buff_update = true;
|
||||
#endif
|
||||
|
||||
if (--buffs[d].numhits == 0) {
|
||||
CastOnNumHitFade(buffs[d].spellid);
|
||||
if (!TryFadeEffect(d))
|
||||
@ -5679,6 +5692,13 @@ void Mob::CheckNumHitsRemaining(NumHit type, int32 buff_slot, uint16 spell_id)
|
||||
} else if (type == NumHit::MatchingSpells) {
|
||||
if (buff_slot >= 0) {
|
||||
if (--buffs[buff_slot].numhits == 0) {
|
||||
|
||||
#ifdef BOTS
|
||||
buff_name = spells[buffs[buff_slot].spellid].name;
|
||||
buff_counter = (buffs[buff_slot].numhits - 1);
|
||||
buff_update = true;
|
||||
#endif
|
||||
|
||||
CastOnNumHitFade(buffs[buff_slot].spellid);
|
||||
if (!TryFadeEffect(buff_slot))
|
||||
BuffFadeBySlot(buff_slot , true);
|
||||
@ -5691,6 +5711,13 @@ void Mob::CheckNumHitsRemaining(NumHit type, int32 buff_slot, uint16 spell_id)
|
||||
continue;
|
||||
|
||||
if (IsValidSpell(buffs[d].spellid) && m_spellHitsLeft[d] == buffs[d].spellid) {
|
||||
|
||||
#ifdef BOTS
|
||||
buff_name = spells[buffs[d].spellid].name;
|
||||
buff_counter = (buffs[d].numhits - 1);
|
||||
buff_update = true;
|
||||
#endif
|
||||
|
||||
if (--buffs[d].numhits == 0) {
|
||||
CastOnNumHitFade(buffs[d].spellid);
|
||||
m_spellHitsLeft[d] = 0;
|
||||
@ -5706,6 +5733,13 @@ void Mob::CheckNumHitsRemaining(NumHit type, int32 buff_slot, uint16 spell_id)
|
||||
for (int d = 0; d < buff_max; d++) {
|
||||
if (IsValidSpell(buffs[d].spellid) && buffs[d].numhits > 0 &&
|
||||
spells[buffs[d].spellid].numhitstype == static_cast<int>(type)) {
|
||||
|
||||
#ifdef BOTS
|
||||
buff_name = spells[buffs[d].spellid].name;
|
||||
buff_counter = (buffs[d].numhits - 1);
|
||||
buff_update = true;
|
||||
#endif
|
||||
|
||||
if (--buffs[d].numhits == 0) {
|
||||
CastOnNumHitFade(buffs[d].spellid);
|
||||
if (!TryFadeEffect(d))
|
||||
@ -5716,6 +5750,28 @@ void Mob::CheckNumHitsRemaining(NumHit type, int32 buff_slot, uint16 spell_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BOTS
|
||||
if (IsBot() && buff_update) {
|
||||
auto bot_owner = entity_list.GetBotOwnerByBotEntityID(GetID());
|
||||
if (bot_owner && bot_owner->GetBotOption(Client::booBuffCounter)) {
|
||||
bot_owner->CastToClient()->SendMarqueeMessage(
|
||||
Chat::Yellow,
|
||||
510,
|
||||
0,
|
||||
1000,
|
||||
3000,
|
||||
StringFormat(
|
||||
"%s has [%u] hit%s remaining on '%s'",
|
||||
GetCleanName(),
|
||||
buff_counter,
|
||||
(buff_counter == 1 ? "" : "s"),
|
||||
buff_name.c_str()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//for some stupid reason SK procs return theirs one base off...
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user