mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-12 05:21: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, 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_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_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()
|
RULE_CATEGORY_END()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
169
zone/bot.cpp
169
zone/bot.cpp
@ -236,8 +236,157 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to
|
|||||||
|
|
||||||
LoadAAs();
|
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());
|
bot_owner->Message(Chat::Red, "&s for '%s'", BotDatabase::fail::LoadBuffs(), GetCleanName());
|
||||||
|
}
|
||||||
|
|
||||||
CalcBotStats(false);
|
CalcBotStats(false);
|
||||||
hp_regen = CalcHPRegen();
|
hp_regen = CalcHPRegen();
|
||||||
@ -4726,9 +4875,9 @@ bool Bot::Death(Mob *killerMob, int32 damage, uint16 spell_id, EQEmu::skills::Sk
|
|||||||
Mob *my_owner = GetBotOwner();
|
Mob *my_owner = GetBotOwner();
|
||||||
if (my_owner && my_owner->IsClient() && my_owner->CastToClient()->GetBotOption(Client::booDeathMarquee)) {
|
if (my_owner && my_owner->IsClient() && my_owner->CastToClient()->GetBotOption(Client::booDeathMarquee)) {
|
||||||
if (killerMob)
|
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
|
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);
|
Mob *give_exp = hate_list.GetDamageTopOnHateList(this);
|
||||||
@ -8989,6 +9138,20 @@ Bot* EntityList::GetBotByBotName(std::string botName) {
|
|||||||
return Result;
|
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) {
|
void EntityList::AddBot(Bot *newBot, bool SendSpawnPacket, bool dontqueue) {
|
||||||
if(newBot) {
|
if(newBot) {
|
||||||
newBot->SetID(GetFreeID());
|
newBot->SetID(GetFreeID());
|
||||||
|
|||||||
@ -1321,6 +1321,8 @@ int bot_command_init(void)
|
|||||||
if (
|
if (
|
||||||
bot_command_add("actionable", "Lists actionable command arguments and use descriptions", 0, bot_command_actionable) ||
|
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("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("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("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) ||
|
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);
|
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)
|
void bot_command_attack(Client *c, const Seperator *sep)
|
||||||
{
|
{
|
||||||
if (helper_command_alias_fail(c, "bot_command_attack", sep->arg[0], "attack")) {
|
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 \"#00CCCC\">null</td>"
|
||||||
"<td><c \"#888888\">(toggles)</td>"
|
"<td><c \"#888888\">(toggles)</td>"
|
||||||
"</tr>"
|
"</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>"
|
"<tr>"
|
||||||
"<td><c \"#CCCCCC\">current</td>"
|
"<td><c \"#CCCCCC\">current</td>"
|
||||||
"<td></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.");
|
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")) {
|
else if (!owner_option.compare("current")) {
|
||||||
|
|
||||||
std::string window_title = "Current Bot Owner Options Settings";
|
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\">spawnmessage</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||||
"<tr>" "<td><c \"#CCCCCC\">altcombat</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\">autodefend</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||||
|
"<tr>" "<td><c \"#CCCCCC\">buffcounter</td>" "<td><c \"#00CC00\">{}</td>" "</tr>"
|
||||||
"</table>",
|
"</table>",
|
||||||
(c->GetBotOption(Client::booDeathMarquee) ? "enabled" : "disabled"),
|
(c->GetBotOption(Client::booDeathMarquee) ? "enabled" : "disabled"),
|
||||||
(c->GetBotOption(Client::booStatsUpdate) ? "enabled" : "disabled"),
|
(c->GetBotOption(Client::booStatsUpdate) ? "enabled" : "disabled"),
|
||||||
(c->GetBotOption(Client::booSpawnMessageSay) ? "say" : (c->GetBotOption(Client::booSpawnMessageTell) ? "tell" : "silent")),
|
(c->GetBotOption(Client::booSpawnMessageSay) ? "say" : (c->GetBotOption(Client::booSpawnMessageTell) ? "tell" : "silent")),
|
||||||
(c->GetBotOption(Client::booSpawnMessageClassSpecific) ? "class" : "default"),
|
(c->GetBotOption(Client::booSpawnMessageClassSpecific) ? "class" : "default"),
|
||||||
(RuleB(Bots, AllowOwnerOptionAltCombat) ? (c->GetBotOption(Client::booAltCombat) ? "enabled" : "disabled") : "restricted"),
|
(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());
|
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);
|
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)
|
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]);
|
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
|
// bot commands
|
||||||
void bot_command_actionable(Client *c, const Seperator *sep);
|
void bot_command_actionable(Client *c, const Seperator *sep);
|
||||||
void bot_command_aggressive(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_attack(Client *c, const Seperator *sep);
|
||||||
void bot_command_bind_affinity(Client *c, const Seperator *sep);
|
void bot_command_bind_affinity(Client *c, const Seperator *sep);
|
||||||
void bot_command_bot(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);
|
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);
|
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_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);
|
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);
|
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);
|
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::booSpawnMessageClassSpecific:
|
||||||
case Client::booAltCombat:
|
case Client::booAltCombat:
|
||||||
case Client::booAutoDefend:
|
case Client::booAutoDefend:
|
||||||
|
case Client::booBuffCounter:
|
||||||
{
|
{
|
||||||
query = fmt::format(
|
query = fmt::format(
|
||||||
"REPLACE INTO `bot_owner_options`(`owner_id`, `option_type`, `option_value`) VALUES ('{}', '{}', '{}')",
|
"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[booSpawnMessageClassSpecific] = true;
|
||||||
bot_owner_options[booAltCombat] = RuleB(Bots, AllowOwnerOptionAltCombat);
|
bot_owner_options[booAltCombat] = RuleB(Bots, AllowOwnerOptionAltCombat);
|
||||||
bot_owner_options[booAutoDefend] = RuleB(Bots, AllowOwnerOptionAutoDefend);
|
bot_owner_options[booAutoDefend] = RuleB(Bots, AllowOwnerOptionAutoDefend);
|
||||||
|
bot_owner_options[booBuffCounter] = false;
|
||||||
|
|
||||||
SetBotPulling(false);
|
SetBotPulling(false);
|
||||||
SetBotPrecombat(false);
|
SetBotPrecombat(false);
|
||||||
|
|||||||
@ -1640,6 +1640,7 @@ public:
|
|||||||
booSpawnMessageClassSpecific,
|
booSpawnMessageClassSpecific,
|
||||||
booAltCombat,
|
booAltCombat,
|
||||||
booAutoDefend,
|
booAutoDefend,
|
||||||
|
booBuffCounter,
|
||||||
_booCount
|
_booCount
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -553,6 +553,7 @@ private:
|
|||||||
Mob* GetMobByBotID(uint32 botID);
|
Mob* GetMobByBotID(uint32 botID);
|
||||||
Bot* GetBotByBotID(uint32 botID);
|
Bot* GetBotByBotID(uint32 botID);
|
||||||
Bot* GetBotByBotName(std::string botName);
|
Bot* GetBotByBotName(std::string botName);
|
||||||
|
Client* GetBotOwnerByBotEntityID(uint16 entityID);
|
||||||
std::list<Bot*> GetBotsByBotOwnerCharacterID(uint32 botOwnerCharacterID);
|
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
|
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;
|
bool bDepleted = false;
|
||||||
int buff_max = GetMaxTotalSlots();
|
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]
|
//Spell specific procs [Type 7,10,11]
|
||||||
if (IsValidSpell(spell_id)) {
|
if (IsValidSpell(spell_id)) {
|
||||||
for (int d = 0; d < buff_max; d++) {
|
for (int d = 0; d < buff_max; d++) {
|
||||||
if (buffs[d].spellid == spell_id && buffs[d].numhits > 0 &&
|
if (buffs[d].spellid == spell_id && buffs[d].numhits > 0 &&
|
||||||
spells[buffs[d].spellid].numhitstype == static_cast<int>(type)) {
|
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) {
|
if (--buffs[d].numhits == 0) {
|
||||||
CastOnNumHitFade(buffs[d].spellid);
|
CastOnNumHitFade(buffs[d].spellid);
|
||||||
if (!TryFadeEffect(d))
|
if (!TryFadeEffect(d))
|
||||||
@ -5679,6 +5692,13 @@ void Mob::CheckNumHitsRemaining(NumHit type, int32 buff_slot, uint16 spell_id)
|
|||||||
} else if (type == NumHit::MatchingSpells) {
|
} else if (type == NumHit::MatchingSpells) {
|
||||||
if (buff_slot >= 0) {
|
if (buff_slot >= 0) {
|
||||||
if (--buffs[buff_slot].numhits == 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);
|
CastOnNumHitFade(buffs[buff_slot].spellid);
|
||||||
if (!TryFadeEffect(buff_slot))
|
if (!TryFadeEffect(buff_slot))
|
||||||
BuffFadeBySlot(buff_slot , true);
|
BuffFadeBySlot(buff_slot , true);
|
||||||
@ -5691,6 +5711,13 @@ void Mob::CheckNumHitsRemaining(NumHit type, int32 buff_slot, uint16 spell_id)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (IsValidSpell(buffs[d].spellid) && m_spellHitsLeft[d] == buffs[d].spellid) {
|
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) {
|
if (--buffs[d].numhits == 0) {
|
||||||
CastOnNumHitFade(buffs[d].spellid);
|
CastOnNumHitFade(buffs[d].spellid);
|
||||||
m_spellHitsLeft[d] = 0;
|
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++) {
|
for (int d = 0; d < buff_max; d++) {
|
||||||
if (IsValidSpell(buffs[d].spellid) && buffs[d].numhits > 0 &&
|
if (IsValidSpell(buffs[d].spellid) && buffs[d].numhits > 0 &&
|
||||||
spells[buffs[d].spellid].numhitstype == static_cast<int>(type)) {
|
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) {
|
if (--buffs[d].numhits == 0) {
|
||||||
CastOnNumHitFade(buffs[d].spellid);
|
CastOnNumHitFade(buffs[d].spellid);
|
||||||
if (!TryFadeEffect(d))
|
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...
|
//for some stupid reason SK procs return theirs one base off...
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user