From 76812e20511c1e940d50c7c22fb208742084868f Mon Sep 17 00:00:00 2001 From: Neckkola Date: Thu, 25 Mar 2021 21:10:45 -0300 Subject: [PATCH 01/55] Fix for GENERIC_9_STRINGS --- zone/client.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zone/client.cpp b/zone/client.cpp index 96e18dcd9..8ad656506 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -3163,7 +3163,7 @@ void Client::MessageString(uint32 type, uint32 string_id, const char* message1, int i = 0, argcount = 0, length = 0; char *bufptr = nullptr; - const char *message_arg[9] = {0}; + const char *message_arg[10] = {0}; if(type==Chat::Emote) type=4; @@ -3299,7 +3299,7 @@ void Client::FilteredMessageString(Mob *sender, uint32 type, eqFilterType filter int i = 0, argcount = 0, length = 0; char *bufptr = nullptr; - const char *message_arg[9] = {0}; + const char *message_arg[10] = {0}; if (type == Chat::Emote) type = 4; From dd1ce19d4fd6f408acef848e79f6b68d16dbc152 Mon Sep 17 00:00:00 2001 From: Neckkola Date: Thu, 25 Mar 2021 21:18:52 -0300 Subject: [PATCH 02/55] Add Bot Heal Message Display Creates a new rule to display Bot heal messages to the Bot Owner --- common/ruletypes.h | 1 + zone/attack.cpp | 78 ++++++++++++++++++++++++++++++++++++---------- 2 files changed, 62 insertions(+), 17 deletions(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index 31fb54fce..7eca4b0cc 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -614,6 +614,7 @@ RULE_REAL(Bots, LeashDistance, 562500.0f, "Distance a bot is allowed to travel f 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_BOOL(Bots, DisplayHealDamage, false, "Enables the display of bot heal damage to the client") RULE_CATEGORY_END() #endif diff --git a/zone/attack.cpp b/zone/attack.cpp index 3f614598a..61cd3fdce 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -3853,7 +3853,7 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const } -void Mob::HealDamage(uint32 amount, Mob *caster, uint16 spell_id) +void Mob::HealDamage(uint32 amount, Mob* caster, uint16 spell_id) { int32 maxhp = GetMaxHP(); int32 curhp = GetHP(); @@ -3868,15 +3868,16 @@ void Mob::HealDamage(uint32 amount, Mob *caster, uint16 spell_id) if (caster) { if (IsBuffSpell(spell_id)) { // hots // message to caster - if (caster->IsClient() && caster == this) { - if (caster->CastToClient()->ClientVersionBit() & EQ::versions::maskSoFAndLater) + if ((caster->IsClient() && caster == this)) { + if (caster->CastToClient()->ClientVersionBit() & EQ::versions::maskSoFAndLater) { FilteredMessageString(caster, Chat::NonMelee, FilterHealOverTime, HOT_HEAL_SELF, itoa(acthealed), spells[spell_id].name); + } else FilteredMessageString(caster, Chat::NonMelee, FilterHealOverTime, YOU_HEALED, GetCleanName(), itoa(acthealed)); } - else if (caster->IsClient() && caster != this) { + else if ((caster->IsClient() && caster != this)) { if (caster->CastToClient()->ClientVersionBit() & EQ::versions::maskSoFAndLater) caster->FilteredMessageString(caster, Chat::NonMelee, FilterHealOverTime, HOT_HEAL_OTHER, GetCleanName(), itoa(acthealed), @@ -3885,8 +3886,35 @@ void Mob::HealDamage(uint32 amount, Mob *caster, uint16 spell_id) caster->FilteredMessageString(caster, Chat::NonMelee, FilterHealOverTime, YOU_HEAL, GetCleanName(), itoa(acthealed)); } +#ifdef BOTS + if (caster->IsBot() && this != caster->CastToBot()->GetBotOwner() && RuleB(Bots, DisplayHealDamage)) { + + + // %1 healed %2 for %3 hit points from %4's %5 + const char s2[]{ " healed " }; + const char s4[]{ " for " }; + const char s6[]{ " hit points from " }; + const char s8[]{ "'s " }; + + caster->CastToBot()->GetBotOwner()->FilteredMessageString( + caster->CastToBot()->GetBotOwner(), //send to the Bot Owner's client + Chat::NonMelee, + FilterHealOverTime, + GENERIC_9_STRINGS, //using generic for testing purposes %1 %2 %3 %4 %5 %6 %7 %8 %9 + caster->GetCleanName(), // %1 caster (bot's) name + s2, // %2 + this->GetCleanName(), // %3 caster (bot's) target + s4, // %4 + itoa(acthealed), // %5 amount healed + s6, // %6 + caster->GetCleanName(), // %7 caster (bot's) name + s8, // %8 + spells[spell_id].name // %9 spell name + ); + } +#endif // BOTS // message to target - if (IsClient() && caster != this) { + if ((IsClient() && caster != this)) { if (CastToClient()->ClientVersionBit() & EQ::versions::maskSoFAndLater) FilteredMessageString(this, Chat::NonMelee, FilterHealOverTime, HOT_HEALED_OTHER, caster->GetCleanName(), @@ -3899,25 +3927,41 @@ void Mob::HealDamage(uint32 amount, Mob *caster, uint16 spell_id) else { // normal heals FilteredMessageString(caster, Chat::NonMelee, FilterSpellDamage, YOU_HEALED, caster->GetCleanName(), itoa(acthealed)); +#ifndef BOTS if (caster != this) caster->FilteredMessageString(caster, Chat::NonMelee, FilterSpellDamage, YOU_HEAL, GetCleanName(), itoa(acthealed)); } - } - else { - Message(Chat::NonMelee, "You have been healed for %d points of damage.", acthealed); - } - } +#endif +#ifdef BOTS + if (caster->IsBot() && RuleB(Bots, DisplayHealDamage)) { + caster->CastToBot()->GetBotOwner()->FilteredMessageString(caster->CastToBot()->GetBotOwner(), + Chat::NonMelee, FilterSpellDamage, GENERIC_9_STRINGS, + caster->GetCleanName(), " healed ", this->GetCleanName(), " for ", itoa(acthealed), " hit points.", " ", " ", " "); + } + else if (caster != this) { + caster->FilteredMessageString(caster, Chat::NonMelee, FilterSpellDamage, + YOU_HEAL, GetCleanName(), itoa(acthealed)); - if (curhp < maxhp) { - if ((curhp + amount) > maxhp) - curhp = maxhp; - else - curhp += amount; - SetHP(curhp); + } + } +#endif // BOTS - SendHPUpdate(); } + else { + Message(Chat::NonMelee, "You have been healed for %d points of damage.", acthealed); + } +} + +if (curhp < maxhp) { + if ((curhp + amount) > maxhp) + curhp = maxhp; + else + curhp += amount; + SetHP(curhp); + + SendHPUpdate(); +} } //proc chance includes proc bonus From bcf067765669d6d330bb9ddd64a69dea03a7308c Mon Sep 17 00:00:00 2001 From: Neckkola Date: Thu, 25 Mar 2021 23:05:37 -0300 Subject: [PATCH 03/55] 2021-03-25 11L04pm Spell and Heal Rule added to allow for Bot spell and heal damage to be sent to the Bot Owner's Group. Also added a check to remove duplicate message for #damage on self. --- common/ruletypes.h | 3 ++- zone/attack.cpp | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index 7eca4b0cc..5d311279f 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -614,7 +614,8 @@ RULE_REAL(Bots, LeashDistance, 562500.0f, "Distance a bot is allowed to travel f 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_BOOL(Bots, DisplayHealDamage, false, "Enables the display of bot heal damage to the client") +RULE_BOOL(Bots, DisplayHealDamage, false, "Enables the display of bot heal damage to the bot owner client") +RULE_BOOL(Bots, DisplaySpellDamage, false, "Enables the display of bot spell damage to the bot owner client") RULE_CATEGORY_END() #endif diff --git a/zone/attack.cpp b/zone/attack.cpp index 61cd3fdce..ef6b6e719 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -3807,7 +3807,20 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const // If this is Damage Shield damage, the correct OP_Damage packets will be sent from Mob::DamageShield, so // we don't send them here. if (!FromDamageShield) { - +#ifdef BOTS + // If a bot is the attacker, send a damage message ot the Bot Owner + if (spell_id != SPELL_UNKNOWN && damage > 0 && attacker && attacker != this && attacker->IsBot() && RuleB(Bots, DisplaySpellDamage)) { + attacker->CastToBot()->GetBotOwner()->FilteredMessageString( + attacker->CastToBot()->GetBotOwner(), + Chat::DotDamage, + FilterDOT, + OTHER_HIT_DOT, + attacker->GetTarget()->GetCleanName(), + itoa(damage), + attacker->GetCleanName(), + spells[spell_id].name); + } +#endif entity_list.QueueCloseClients( this, /* Sender */ outapp, /* packet */ @@ -3819,7 +3832,7 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const ); //send the damage to ourself if we are a client - if (IsClient()) { + if (IsClient() && spell_id != SPELL_UNKNOWN) { //added !SPELL_UNKNOWN to remove duplicate display for #damage to self //I dont think any filters apply to damage affecting us CastToClient()->QueuePacket(outapp); } @@ -3849,6 +3862,22 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const spells[spell_id].name /* Message4 */ ); } +#ifdef BOTS + // If a bot is the attacker, send a damage message ot the Bot Owner + else if (spell_id != SPELL_UNKNOWN && attacker->IsBot() && damage > 0 && attacker && attacker !=this && RuleB(Bots, DisplaySpellDamage)) { + attacker->CastToBot()->GetBotOwner()->FilteredMessageString( + attacker->CastToBot()->GetBotOwner(), + Chat::DotDamage, + FilterDOT, + OTHER_HIT_DOT, + attacker->GetTarget()->GetCleanName(), + itoa(damage), + attacker->GetCleanName(), + spells[spell_id].name); + } + +#endif + } //end packet sending } From 0a5d8b42f1d6121ee3abf3fde95c6f492a99dae5 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Thu, 30 Dec 2021 15:34:41 -0400 Subject: [PATCH 04/55] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1db525804..1c39264c8 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,4 @@ bin/ /Win32 /x64 /client_files/**/CMakeFiles/ +CMakeSettings.json From bcf28bc35c3ea3566e7ae1e1a4a8a0a8a7682ff6 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Thu, 30 Dec 2021 15:42:03 -0400 Subject: [PATCH 05/55] BOT work Added BOT logging damage/heals to owner Added BOT message to owner for harmony fails Made var Critical global to remove duplicate crit messages Added a NULL check to Mob:GetCleanname() --- CMakeSettings.json | 15 ++++++ zone/attack.cpp | 112 ++++++++++++++++++++++++++++----------------- zone/bot.cpp | 10 ++-- zone/effects.cpp | 6 ++- zone/main.cpp | 1 + zone/mob.cpp | 2 +- zone/spells.cpp | 27 ++++++++++- 7 files changed, 123 insertions(+), 50 deletions(-) create mode 100644 CMakeSettings.json diff --git a/CMakeSettings.json b/CMakeSettings.json new file mode 100644 index 000000000..9204f06eb --- /dev/null +++ b/CMakeSettings.json @@ -0,0 +1,15 @@ +{ + "configurations": [ + { + "name": "x64-Debug", + "generator": "Ninja", + "configurationType": "Debug", + "inheritEnvironments": [ "msvc_x64_x64" ], + "buildRoot": "${projectDir}\\out\\build\\${name}", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "" + } + ] +} \ No newline at end of file diff --git a/zone/attack.cpp b/zone/attack.cpp index ef6b6e719..c2286d341 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -49,6 +49,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA extern QueryServ* QServ; extern WorldServer worldserver; extern FastMath g_Math; +extern bool Critical; #ifdef _WINDOWS #define snprintf _snprintf @@ -3401,7 +3402,7 @@ bool Mob::CheckDoubleAttack() return zone->random.Int(1, 500) <= chance; } -void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const EQ::skills::SkillType skill_used, bool &avoidable, const int8 buffslot, const bool iBuffTic, eSpecialAttacks special) { +void Mob::CommonDamage(Mob* attacker, int& damage, const uint16 spell_id, const EQ::skills::SkillType skill_used, bool& avoidable, const int8 buffslot, const bool iBuffTic, eSpecialAttacks special) { // This method is called with skill_used=ABJURE for Damage Shield damage. bool FromDamageShield = (skill_used == EQ::skills::SkillAbjuration); bool ignore_invul = false; @@ -3466,12 +3467,12 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const // emote goes with every one ... even npcs entity_list.MessageClose(this, true, RuleI(Range, SpellMessages), Chat::Emote, "%s beams a smile at %s", attacker->GetCleanName(), this->GetCleanName()); } - + // If a client pet is damaged while sitting, stand, fix sit button, // and remove sitting regen. Removes bug where client clicks sit // during battle and gains pet hp-regen and bugs the sit button. if (IsPet()) { - Mob *owner = this->GetOwner(); + Mob* owner = this->GetOwner(); if (owner && owner->IsClient()) { if (GetPetOrder() == SPO_Sit) { SetPetOrder(SPO_Follow); @@ -3479,28 +3480,28 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const // fix GUI sit button to be unpressed and stop sitting regen owner->CastToClient()->SetPetCommandState(PET_BUTTON_SIT, 0); SetAppearance(eaStanding); - } + } } } //end `if there is some damage being done and theres anattacker person involved` - Mob *pet = GetPet(); + Mob* pet = GetPet(); // pets that have GHold will never automatically add NPCs // pets that have Hold and no Focus will add NPCs if they're engaged // pets that have Hold and Focus will not add NPCs if ( - pet && - !pet->IsFamiliar() && - !pet->GetSpecialAbility(IMMUNE_AGGRO) && - !pet->IsEngaged() && - attacker && - !(pet->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && attacker->IsClient()) && - !(pet->GetSpecialAbility(IMMUNE_AGGRO_NPC) && attacker->IsNPC()) && - attacker != this && - !attacker->IsCorpse() && - !pet->IsGHeld() && + pet && + !pet->IsFamiliar() && + !pet->GetSpecialAbility(IMMUNE_AGGRO) && + !pet->IsEngaged() && + attacker && + !(pet->GetSpecialAbility(IMMUNE_AGGRO_CLIENT) && attacker->IsClient()) && + !(pet->GetSpecialAbility(IMMUNE_AGGRO_NPC) && attacker->IsNPC()) && + attacker != this && + !attacker->IsCorpse() && + !pet->IsGHeld() && !attacker->IsTrap() - ) { + ) { if (!pet->IsHeld()) { LogAggro("Sending pet [{}] into battle due to attack", pet->GetName()); if (IsClient()) { @@ -3720,12 +3721,12 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const //Note: if players can become pets, they will not receive damage messages of their own //this was done to simplify the code here (since we can only effectively skip one mob on queue) eqFilterType filter; - Mob *skip = attacker; + Mob* skip = attacker; if (attacker && attacker->GetOwnerID()) { //attacker is a pet, let pet owners see their pet's damage Mob* owner = attacker->GetOwner(); if (owner && owner->IsClient()) { - if (((spell_id != SPELL_UNKNOWN) || (FromDamageShield)) && damage>0) { + if (((spell_id != SPELL_UNKNOWN) || (FromDamageShield)) && damage > 0) { //special crap for spell damage, looks hackish to me char val1[20] = { 0 }; owner->MessageString(Chat::NonMelee, OTHER_HIT_NONMELEE, GetCleanName(), ConvertArray(damage, val1)); @@ -3746,6 +3747,33 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const owner->CastToClient()->QueuePacket(outapp, true, CLIENT_CONNECTED, filter); } } + +#ifdef BOTS + else if (owner && owner->IsBot() && RuleB(Bots, DisplaySpellDamage)) { + if (((spell_id != SPELL_UNKNOWN) || (FromDamageShield)) && damage > 0) { + //special crap for spell damage, looks hackish to me + char val1[20] = { 0 }; + owner->CastToBot()->GetBotOwner()->CastToClient()->MessageString(Chat::NonMelee, OTHER_HIT_NONMELEE, attacker->GetCleanName(), ConvertArray(damage, val1)); + + } + else { + if (damage > 0) { + if (spell_id != SPELL_UNKNOWN) + filter = iBuffTic ? FilterDOT : FilterSpellDamage; + else + filter = FilterPetHits; + } + else if (damage == -5) + filter = FilterNone; //cant filter invulnerable + else + filter = FilterPetMisses; + + if (!FromDamageShield) + owner->CastToBot()->GetBotOwner()->CastToClient()->QueuePacket(outapp, true, CLIENT_CONNECTED, filter); + + } + } +#endif skip = owner; } else { @@ -3784,8 +3812,10 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const filter = FilterNone; //cant filter invulnerable else filter = FilterMyMisses; - + //set to filter duplicate message to the client if client uses #damage to themselves + //if (!attacker->IsClient() && attacker->CastToClient()->GetID() != attacker->GetTarget()->GetID()) { attacker->CastToClient()->QueuePacket(outapp, true, CLIENT_CONNECTED, filter); + //} } } skip = attacker; @@ -3808,14 +3838,14 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const // we don't send them here. if (!FromDamageShield) { #ifdef BOTS - // If a bot is the attacker, send a damage message ot the Bot Owner - if (spell_id != SPELL_UNKNOWN && damage > 0 && attacker && attacker != this && attacker->IsBot() && RuleB(Bots, DisplaySpellDamage)) { + // If a bot is the attacker, send a damage message ot the Bot Owner + if (spell_id != SPELL_UNKNOWN && damage > 0 && !Critical && attacker && attacker != this && attacker->IsBot() && RuleB(Bots, DisplaySpellDamage)) { attacker->CastToBot()->GetBotOwner()->FilteredMessageString( - attacker->CastToBot()->GetBotOwner(), - Chat::DotDamage, + attacker->CastToBot()->GetBotOwner(), + Chat::DotDamage, FilterDOT, - OTHER_HIT_DOT, - attacker->GetTarget()->GetCleanName(), + OTHER_HIT_DOT, + attacker->GetTarget()->GetCleanName(), itoa(damage), attacker->GetCleanName(), spells[spell_id].name); @@ -3829,10 +3859,10 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const skip, /* Skip this mob */ true, /* Packet ACK */ filter /* eqFilterType filter */ - ); + ); //send the damage to ourself if we are a client - if (IsClient() && spell_id != SPELL_UNKNOWN) { //added !SPELL_UNKNOWN to remove duplicate display for #damage to self + if (IsClient() && this != attacker) { //need to add a filter to remove duplicate display for #damage to self //I dont think any filters apply to damage affecting us CastToClient()->QueuePacket(outapp); } @@ -3864,23 +3894,21 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const } #ifdef BOTS // If a bot is the attacker, send a damage message ot the Bot Owner - else if (spell_id != SPELL_UNKNOWN && attacker->IsBot() && damage > 0 && attacker && attacker !=this && RuleB(Bots, DisplaySpellDamage)) { - attacker->CastToBot()->GetBotOwner()->FilteredMessageString( - attacker->CastToBot()->GetBotOwner(), - Chat::DotDamage, - FilterDOT, - OTHER_HIT_DOT, - attacker->GetTarget()->GetCleanName(), - itoa(damage), - attacker->GetCleanName(), - spells[spell_id].name); - } - + else if (spell_id != SPELL_UNKNOWN && attacker->IsBot() && damage > 0 && !Critical && attacker && attacker != this && RuleB(Bots, DisplaySpellDamage)) { + attacker->CastToBot()->GetBotOwner()->FilteredMessageString( + attacker->CastToBot()->GetBotOwner(), + Chat::DotDamage, + FilterDOT, + OTHER_HIT_DOT, + attacker->GetTarget()->GetCleanName(), + itoa(damage), + attacker->GetCleanName(), + spells[spell_id].name); + } #endif + } - } //end packet sending - -} +} //end packet sending void Mob::HealDamage(uint32 amount, Mob* caster, uint16 spell_id) { diff --git a/zone/bot.cpp b/zone/bot.cpp index 59bdf9788..2ac70c6ea 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -27,6 +27,7 @@ #include "../common/say_link.h" extern volatile bool is_zone_loaded; +extern bool Critical; // This constructor is used during the bot create command Bot::Bot(NPCType *npcTypeData, Client* botOwner) : NPC(npcTypeData, nullptr, glm::vec4(), Ground, false), rest_timer(1), ping_timer(1) { @@ -6983,7 +6984,7 @@ int32 Bot::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { if (spells[spell_id].targettype == ST_Self) return value; - bool Critical = false; + Critical = false; int32 value_BaseEffect = 0; value_BaseEffect = (value + (value*GetBotFocusEffect(focusFcBaseEffects, spell_id) / 100)); // Need to scale HT damage differently after level 40! It no longer scales by the constant value in the spell file. It scales differently, instead of 10 more damage per level, it does 30 more damage per level. So we multiply the level minus 40 times 20 if they are over level 40. @@ -7028,8 +7029,9 @@ int32 Bot::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) value += (GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value) * ratio / 100); - - entity_list.MessageClose(this, false, 100, Chat::SpellCrit, "%s delivers a critical blast! (%d)", GetName(), -value); + //Mitch + //if (!RuleB(Bots, DisplaySpellDamage)) + entity_list.MessageClose(this, false, 100, Chat::SpellCrit, "%s\'s %s delivers a critical blast to %s! (%d)", GetName(), spells[spell_id].name, target->GetCleanName(), -value); return value; } @@ -7060,7 +7062,7 @@ int32 Bot::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { int32 value_BaseEffect = 0; int32 chance = 0; int8 modifier = 1; - bool Critical = false; + Critical = false; //mitch value_BaseEffect = (value + (value*GetBotFocusEffect(focusFcBaseEffects, spell_id) / 100)); value = value_BaseEffect; value += int(value_BaseEffect*GetBotFocusEffect(focusImprovedHeal, spell_id) / 100); diff --git a/zone/effects.cpp b/zone/effects.cpp index b62a2b383..f7f5f9863 100644 --- a/zone/effects.cpp +++ b/zone/effects.cpp @@ -31,6 +31,8 @@ #include "zone_store.h" #include "position.h" +extern bool Critical; //Mitch + float Mob::GetActSpellRange(uint16 spell_id, float range, bool IsBard) { float extrange = 100; @@ -48,7 +50,7 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { if (IsNPC()) value += value*CastToNPC()->GetSpellFocusDMG()/100; - bool Critical = false; + Critical = false; //Mitch removed bool int32 value_BaseEffect = 0; int chance = 0; @@ -268,7 +270,7 @@ int32 Mob::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { int32 value_BaseEffect = 0; int16 chance = 0; int8 modifier = 1; - bool Critical = false; + Critical = false; //mitch value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100); diff --git a/zone/main.cpp b/zone/main.cpp index dc708a517..b0d1a9f4d 100644 --- a/zone/main.cpp +++ b/zone/main.cpp @@ -87,6 +87,7 @@ volatile bool RunLoops = true; #endif extern volatile bool is_zone_loaded; +extern bool Critical = false; EntityList entity_list; WorldServer worldserver; diff --git a/zone/mob.cpp b/zone/mob.cpp index dbee488e5..efaf619ef 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -3032,7 +3032,7 @@ void Mob::QuestJournalledSay(Client *QuestInitiator, const char *str, Journal::O const char *Mob::GetCleanName() { - if (!strlen(clean_name)) { + if (clean_name != NULL && !strlen(clean_name)) { //extra check added for crash condition. Mitch CleanMobName(GetName(), clean_name); } diff --git a/zone/spells.cpp b/zone/spells.cpp index b4e001ad2..f1000dfd4 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -3846,8 +3846,24 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r spelltar->MessageString(Chat::SpellFailure, YOU_RESIST, spells[spell_id].name); } else { +#ifndef BOTS MessageString(Chat::SpellFailure, TARGET_RESISTED, spells[spell_id].name); spelltar->MessageString(Chat::SpellFailure, YOU_RESIST, spells[spell_id].name); +#endif +#ifdef BOTS + if (this->IsBot() && IsHarmonySpell(spell_id)) { + if (IsGrouped() && this->GetGroup()->GetLeader()->IsClient()) { + Bot::BotGroupSay(this, "Your target RESISTED %s", spells[spell_id].name); + } + else { + this->CastToBot()->GetBotOwner()->MessageString(Chat::SpellFailure, TARGET_RESISTED, spells[spell_id].name); + } + } + else { + MessageString(Chat::SpellFailure, TARGET_RESISTED, spells[spell_id].name); + spelltar->MessageString(Chat::SpellFailure, YOU_RESIST, spells[spell_id].name); + } +#endif } if (spelltar->IsAIControlled()) { @@ -3875,7 +3891,16 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r return false; } } - +#ifdef BOTS //Added to display when a HarmonySpell was successful from a bot + if (this->IsBot() && IsHarmonySpell(spell_id)) { + if (IsGrouped() && this->GetGroup()->GetLeader()->IsClient()) { + Bot::BotGroupSay(this, "Your spell was mostly successful."); + } + else { + this->CastToBot()->GetBotOwner()->MessageString(Chat::SpellFailure, SLOW_MOSTLY_SUCCESSFUL); + } + } +#endif if (spelltar->IsClient()){ spelltar->CastToClient()->BreakSneakWhenCastOn(this, false); spelltar->CastToClient()->BreakFeignDeathWhenCastOn(false); From ba0c03af08cf90400d8f2f2e1bfeb5890fb5ad7e Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Mon, 3 Jan 2022 11:52:08 -0400 Subject: [PATCH 06/55] Bot Group Work Fixed botid=charid spawn on zone issue Added a group_list update on zone to refresh from database to fix a dangling pointer to a Bot object that was camped but was previously in a group within the zone being entered. Modified Bot::ProcessBotGroupInvite to use the client of the bot when doing the Bot initialization so that a leader can invite another owner's Bot --- zone/bot.cpp | 4 +-- zone/bot_database.cpp | 23 ++++++++-------- zone/groups.cpp | 63 ++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 74 insertions(+), 16 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index 2ac70c6ea..a9545c7e8 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -8596,8 +8596,8 @@ Bot* Bot::GetBotByBotClientOwnerAndBotName(Client* c, std::string botName) { void Bot::ProcessBotGroupInvite(Client* c, std::string botName) { if(c) { - Bot* invitedBot = GetBotByBotClientOwnerAndBotName(c, botName); - + Bot* invitedBot = GetBotByBotClientOwnerAndBotName(entity_list.GetBotByBotName(botName)->GetOwner()->CastToClient(), botName); + //Mitch changed entity from c if(invitedBot && !invitedBot->HasGroup()) { if(!c->IsGrouped()) { Group *g = new Group(c); diff --git a/zone/bot_database.cpp b/zone/bot_database.cpp index c419fd355..b05fa7e98 100644 --- a/zone/bot_database.cpp +++ b/zone/bot_database.cpp @@ -2632,19 +2632,20 @@ bool BotDatabase::LoadGroupedBotsByGroupID(const uint32 owner_id, const uint32 g { if (!group_id || !owner_id) return false; - + //modified query for usecase of a BOTID sharing a CHARACTERID. + //in this usecase, when the BOTID=CHARACTERID of BOT OWNER, this BOTID would be added to the GROUP query = StringFormat( - "SELECT `charid`" - " FROM `group_id`" - " WHERE `groupid` = '%u'" - " AND `charid` IN (" - " SELECT `bot_id`" - " FROM `bot_data`" - " WHERE `owner_id` = '%u'" - " )", + "SELECT `mob_id` FROM `vw_groups` " + "WHERE `group_id` = '%u' " + "AND `mob_type`='B' " + "AND `mob_id` IN (SELECT `bot_id` FROM `bot_data` WHERE `owner_id` = '%u');" + , group_id, owner_id); + /*query = StringFormat( + "SELECT `charid` FROM `group_id` WHERE `groupid` = '%u'" + " AND `charid` IN (SELECT `bot_id` FROM `bot_data` WHERE `owner_id` = '%u')" + " AND `group_id.name` NOT IN (SELECT `name` FROM `character_data`)", group_id, - owner_id - ); + owner_id);*/ auto results = database.QueryDatabase(query); if (!results.Success()) diff --git a/zone/groups.cpp b/zone/groups.cpp index 13188dcb9..5d44dc5df 100644 --- a/zone/groups.cpp +++ b/zone/groups.cpp @@ -248,10 +248,24 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte uint32 i = 0; for (i = 0; i < MAX_GROUP_MEMBERS; ++i) { - if(!strcasecmp(membername[i], NewMemberName)) +#ifdef BOTSS + if (newmember->IsBot() && !newmember->HasGroup() && !strcasecmp(membername[i], NewMemberName)) // Mitch + { + //Bot::RemoveBotFromGroup(newmember->CastToBot(), members[0]->GetGroup()); + //Group::DelMember(newmember); + memset(membername[i], 0, 64); + members[i] = nullptr; + } + else if (!strcasecmp(membername[i], NewMemberName)) { return false; } +#else + if (!strcasecmp(membername[i], NewMemberName)) + { + return false; + } +#endif } // Put them in the group @@ -1176,7 +1190,13 @@ void Group::TeleportGroup(Mob* sender, uint32 zoneID, uint16 instance_id, float } bool Group::LearnMembers() { - std::string query = StringFormat("SELECT name FROM group_id WHERE groupid = %lu", (unsigned long)GetID()); + //std::string query = StringFormat("SELECT name FROM group_id WHERE groupid = %lu", (unsigned long)GetID()); + std::string query = StringFormat("SELECT name FROM group_id " + "WHERE group_id.groupid = %lu AND group_id.name NOT " + "IN(SELECT group_leaders.leadername FROM group_leaders WHERE gid = %lu)" + , (unsigned long)GetID() + , (unsigned long)GetID()); + auto results = database.QueryDatabase(query); if (!results.Success()) return false; @@ -1191,7 +1211,7 @@ bool Group::LearnMembers() { return false; } - int memberIndex = 0; + int memberIndex = 1; //starts at 1 becasuse leader [0] is done specifically for(auto row = results.begin(); row != results.end(); ++row) { if(!row[0]) continue; @@ -1201,7 +1221,24 @@ bool Group::LearnMembers() { memberIndex++; } + // for leader only [0] /Mitch + query = StringFormat("SELECT leadername FROM group_leaders WHERE group_leaders.gid = %lu", (unsigned long)GetID()); + auto results2 = database.QueryDatabase(query); + if (!results2.Success()) + return false; + if (results2.RowCount() == 0) { + LogError( + "Error getting group leader for group [{}]: [{}]", + (unsigned long)GetID(), + results2.ErrorMessage().c_str() + ); + + return false; + } + auto row2 = results2.begin(); + members[0] = nullptr; + strn0cpy(membername[0], row2[0], 64); return true; } @@ -1212,6 +1249,22 @@ void Group::VerifyGroup() { Only called every once in a while (on member re-join for now). */ + // To do + // Reset the membername array to match the group_id database records? + // When doing this manually, it seem to have resolved the issue. + // Only want to do this when the database Name does not match the array + // Could this be done from the LearnGroup method? + // reset the members and membername array for this group + // Mitch + for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { + members[i] = nullptr; + memset(membername[i],'\0',64); + //membername[i][0] == '\0'); + } + // repopulate the membername array from the database to ensure the local zone instance has accurate information + + Group::LearnMembers(); + uint32 i; for (i = 0; i < MAX_GROUP_MEMBERS; i++) { if (membername[i][0] == '\0') { @@ -1231,6 +1284,10 @@ void Group::VerifyGroup() { members[i] = nullptr; continue; } + //if (them == nullptr && members[i] == nullptr) { //fixes a group bug with bots Mitch added Jan 1 2022 + // membername[i][0] = '\0'; + // continue; + //} if(them != nullptr && members[i] != them) { //our pointer is out of date... not so good. #if EQDEBUG >= 5 From 6802681abe7be19260c1f77419d857883da5d3a4 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Tue, 4 Jan 2022 23:40:00 -0400 Subject: [PATCH 07/55] Jan 4 Basic structure in place for Raid::AddBot though not working --- zone/bot.cpp | 272 +++++++++++++++++++++++++++++++++++++++++ zone/bot.h | 1 + zone/client_packet.cpp | 57 +++++++-- zone/raids.cpp | 76 ++++++++++++ zone/raids.h | 1 + 5 files changed, 396 insertions(+), 11 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index a9545c7e8..c52725585 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -20,6 +20,7 @@ #include "bot.h" #include "object.h" +#include "raids.h" #include "doors.h" #include "quest_parser_collection.h" #include "lua_parser.h" @@ -10093,4 +10094,275 @@ void Bot::StopMoving(float new_heading) uint8 Bot::spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND] = { 0 }; +void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { + //Client* player_accepting_invite = entity_list.GetClientByName(raid_command_packet->player_name); + + if (player_accepting_invite) { + if (player_accepting_invite->IsRaidGrouped()) { + b_owner->MessageString(Chat::White, ALREADY_IN_RAID, player_accepting_invite->GetName()); //group failed, must invite members not in raid... + return; + } + Raid* raid = entity_list.GetRaidByMob(player_accepting_invite); + if (raid) { + raid->VerifyRaid(); + Group* group = player_accepting_invite->GetGroup(); + if (group) { + if (group->GroupCount() + raid->RaidCount() > MAX_RAID_MEMBERS) { + b_owner->Message(Chat::Red, "Invite failed, group invite would create a raid larger than the maximum number of members allowed."); + return; + } + } + else { + if (1 + raid->RaidCount() > MAX_RAID_MEMBERS) { + b_owner->Message(Chat::Red, "Invite failed, member invite would create a raid larger than the maximum number of members allowed."); + return; + } + } + if (group) {//add us all + uint32 free_group_id = raid->GetFreeGroup(); + Client* addClient = nullptr; + for (int x = 0; x < 6; x++) { + if (group->members[x]) { + Client* c = nullptr; + if (group->members[x]->IsBot()) + c = group->members[x]->CastToClient(); + + if (!addClient) + { + addClient = c; + raid->SetGroupLeader(addClient->GetName()); + } + + raid->SendRaidCreate(b_owner); + raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); + if (group->IsLeader(group->members[x])) + raid->AddMember(c, free_group_id, false, true); + else + raid->AddMember(c, free_group_id); + raid->SendBulkRaid(b_owner); + if (raid->IsLocked()) { + raid->SendRaidLockTo(b_owner); + } + } + } + group->JoinRaidXTarget(raid); + group->DisbandGroup(true); + raid->GroupUpdate(free_group_id); + } + else { + raid->SendRaidCreate(b_owner); + raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); + raid->AddMember(b_owner); + raid->SendBulkRaid(b_owner); + if (raid->IsLocked()) { + raid->SendRaidLockTo(b_owner); + } + } + } + else + { + Group* player_invited_group = player_accepting_invite->GetGroup(); + Group* group = entity_list.GetGroupByClient(b_owner); // player_accepting_invite->GetGroup(); + if (group) //if our target has a group + { +// raid = new Raid(player_accepting_invite); + raid = new Raid(b_owner); + entity_list.AddRaid(raid); + raid->SetRaidDetails(); + + uint32 raid_free_group_id = raid->GetFreeGroup(); + + /* If we already have a group then cycle through adding us... */ + if (player_invited_group) { + Client* client_to_be_leader = nullptr; + for (int x = 0; x < 6; x++) { + if (player_invited_group->members[x]) { + if (!client_to_be_leader) { + if (player_invited_group->members[x]->IsClient()) { + client_to_be_leader = player_invited_group->members[x]->CastToClient(); + raid->SetGroupLeader(client_to_be_leader->GetName()); + } + } + if (player_invited_group->IsLeader(player_invited_group->members[x])) { + Client* c = nullptr; + + if (player_invited_group->members[x]->IsClient() || player_invited_group->members[x]->IsBot()) + c = player_invited_group->members[x]->CastToClient(); + else + continue; + + raid->SendRaidCreate(b_owner); + raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); + raid->AddMember(c, raid_free_group_id, true, true, true); + raid->SendBulkRaid(c); + + if (raid->IsLocked()) { + raid->SendRaidLockTo(b_owner); + } + } + else { + Client* c = nullptr; + + if (player_invited_group->members[x]->IsClient() || player_invited_group->members[x]->IsBot()) + c = player_invited_group->members[x]->CastToClient(); + else + continue; + + raid->SendRaidCreate(b_owner); + raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); + raid->AddMember(c, raid_free_group_id); + raid->SendBulkRaid(b_owner); + + if (raid->IsLocked()) { + raid->SendRaidLockTo(b_owner); + } + } + } + } + player_invited_group->JoinRaidXTarget(raid, true); + player_invited_group->DisbandGroup(true); + raid->GroupUpdate(raid_free_group_id); + raid_free_group_id = raid->GetFreeGroup(); + } + else { +// raid->SendRaidCreate(player_accepting_invite); +// raid->AddMember(player_accepting_invite, 0xFFFFFFFF, true, false, true); + raid->SendRaidCreate(b_owner); + raid->AddMember(b_owner, 0xFFFFFFFF, true, false, true); + } + + Client* client_to_add = nullptr; + /* Add client to an existing group */ + for (int x = 0; x < 6; x++) { + if (group->members[x]) { + if (!client_to_add) { + if (group->members[x]->IsClient() || group->members[x]->IsBot()) { + client_to_add = group->members[x]->CastToClient(); + raid->SetGroupLeader(client_to_add->GetName()); + } + } + if (group->IsLeader(group->members[x])) { + Client* c = nullptr; + + if (group->members[x]->IsClient() || group->members[x]->IsClient()) + c = group->members[x]->CastToClient(); + else + continue; + + raid->SendRaidCreate(b_owner); + raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); + raid->AddMember(c, raid_free_group_id, false, true); + raid->SendBulkRaid(b_owner); + + if (raid->IsLocked()) { + raid->SendRaidLockTo(b_owner); + } + } + else + { + Client* c = nullptr; + + if (group->members[x]->IsClient() || group->members[x]->IsBot()) + c = group->members[x]->CastToClient(); + else + continue; + + raid->SendRaidCreate(b_owner); + raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); + raid->AddMember(c, raid_free_group_id); + raid->SendBulkRaid(b_owner); + + if (raid->IsLocked()) { + raid->SendRaidLockTo(b_owner); + } + } + } + } + group->JoinRaidXTarget(raid); + group->DisbandGroup(true); + + raid->GroupUpdate(raid_free_group_id); + } + /* Target does not have a group */ + else { + if (player_invited_group) { + + raid = new Raid(b_owner); + + entity_list.AddRaid(raid); + raid->SetRaidDetails(); + Client* addClientig = nullptr; + for (int x = 0; x < 6; x++) { + if (player_invited_group->members[x]) { + if (!addClientig) { + if (player_invited_group->members[x]->IsClient() || player_invited_group->members[x]->IsBot()) { + addClientig = player_invited_group->members[x]->CastToClient(); + raid->SetGroupLeader(addClientig->GetName()); + } + } + if (player_invited_group->IsLeader(player_invited_group->members[x])) { + Client* c = nullptr; + + if (player_invited_group->members[x]->IsClient() || player_invited_group->members[x]->IsBot()) + c = player_invited_group->members[x]->CastToClient(); + else + continue; + + raid->SendRaidCreate(b_owner); + raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); + raid->AddMember(c, 0, true, true, true); + raid->SendBulkRaid(b_owner); + + if (raid->IsLocked()) { + raid->SendRaidLockTo(b_owner); + } + } + else + { + Client* c = nullptr; + if (player_invited_group->members[x]->IsClient() || player_invited_group->members[x]->IsBot()) + c = player_invited_group->members[x]->CastToClient(); + else + continue; + + raid->SendRaidCreate(b_owner); + raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); + raid->AddMember(c, 0); + raid->SendBulkRaid(b_owner); + if (raid->IsLocked()) { + raid->SendRaidLockTo(b_owner); + } + } + } + } + raid->SendRaidCreate(b_owner); + raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); + raid->SendBulkRaid(b_owner); + player_invited_group->JoinRaidXTarget(raid, true); + raid->AddMember(b_owner); + player_invited_group->DisbandGroup(true); + raid->GroupUpdate(0); + if (raid->IsLocked()) { + raid->SendRaidLockTo(b_owner); + } + } + else { // neither has a group + raid = new Raid(b_owner); + entity_list.AddRaid(raid); + raid->SetRaidDetails(); +// raid->SendRaidCreate(b_owner); // Not needed as one raid member is a bot + raid->SendRaidCreate(b_owner); + raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); + raid->AddMember(b_owner, 0xFFFFFFFF, true, false, true); + raid->SendBulkRaid(b_owner); + raid->AddBot(player_accepting_invite); + if (raid->IsLocked()) { + raid->SendRaidLockTo(b_owner); + } + } + } + } + } + } + #endif diff --git a/zone/bot.h b/zone/bot.h index caa556cf9..eb82a253e 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -362,6 +362,7 @@ public: static std::string RaceIdToString(uint16 raceId); static bool IsBotAttackAllowed(Mob* attacker, Mob* target, bool& hasRuleDefined); static Bot* GetBotByBotClientOwnerAndBotName(Client* c, std::string botName); + static void ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner); //Mitch static void ProcessBotGroupInvite(Client* c, std::string botName); static void ProcessBotGroupDisband(Client* c, std::string botName); static void BotOrderCampAll(Client* c); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index d6ef48140..7eae849c4 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -25,6 +25,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include #include +#include "bot.h" #ifdef _WINDOWS #define snprintf _snprintf @@ -11321,7 +11322,38 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) { case RaidCommandInviteIntoExisting: case RaidCommandInvite: { +//Mitch +#ifdef BOTS + Bot* player_to_invite = nullptr; + Client* player_to_invite_owner = nullptr; + if (entity_list.GetBotByBotName(raid_command_packet->player_name)) { + Bot* player_to_invite = entity_list.GetBotByBotName(raid_command_packet->player_name); + Client* player_to_invite_owner = player_to_invite->GetOwner()->CastToClient(); + if (!player_to_invite) { + break; + } + + Group* player_to_invite_group = player_to_invite->GetGroup(); + + if (player_to_invite->HasRaid()) { + Message(Chat::Red, "%s is already in a raid.", player_to_invite->GetName()); + break; + } + + if (player_to_invite_group && player_to_invite_group->IsGroupMember(this)) { + MessageString(Chat::Red, ALREADY_IN_PARTY); + break; + } + + if (player_to_invite_group && !player_to_invite_group->IsLeader(player_to_invite)) { + Message(Chat::Red, "You can only invite an ungrouped player or group leader to join your raid."); + break; + } + + Bot::ProcessRaidInvite(player_to_invite, player_to_invite_owner); + } +#else Client *player_to_invite = entity_list.GetClientByName(raid_command_packet->player_name); if (!player_to_invite) @@ -11344,22 +11376,25 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) break; } - /* Send out invite to the client */ - auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); - RaidGeneral_Struct *raid_command = (RaidGeneral_Struct*)outapp->pBuffer; + /* Send out invite to the client */ + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); + RaidGeneral_Struct* raid_command = (RaidGeneral_Struct*)outapp->pBuffer; - strn0cpy(raid_command->leader_name, raid_command_packet->leader_name, 64); - strn0cpy(raid_command->player_name, raid_command_packet->player_name, 64); + strn0cpy(raid_command->leader_name, raid_command_packet->leader_name, 64); + strn0cpy(raid_command->player_name, raid_command_packet->player_name, 64); - raid_command->parameter = 0; - raid_command->action = 20; + raid_command->parameter = 0; + raid_command->action = 20; - player_to_invite->QueuePacket(outapp); + player_to_invite->QueuePacket(outapp); - safe_delete(outapp); + safe_delete(outapp); +#endif - break; - } + break; + } + + case RaidCommandAcceptInvite: { Client *player_accepting_invite = entity_list.GetClientByName(raid_command_packet->player_name); if (player_accepting_invite) { diff --git a/zone/raids.cpp b/zone/raids.cpp index 55e6d9e55..fb5e9a03a 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -24,6 +24,7 @@ #include "groups.h" #include "mob.h" #include "raids.h" +#include "bot.h" //Mitch #include "worldserver.h" @@ -162,6 +163,81 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo worldserver.SendPacket(pack); safe_delete(pack); } +//Mitch +void Raid::AddBot(Bot* b, uint32 group, bool rleader, bool groupleader, bool looter) { + if (!b) + return; + + std::string query = StringFormat("INSERT INTO raid_members SET raidid = %lu, charid = %lu, " + "groupid = %lu, _class = %d, level = %d, name = '%s', " + "isgroupleader = %d, israidleader = %d, islooter = %d", + (unsigned long)GetID(), (unsigned long)b->GetBotID(), + (unsigned long)group, b->GetClass(), b->GetLevel(), + b->GetName(), groupleader, rleader, looter); + auto results = database.QueryDatabase(query); + + if (!results.Success()) { + LogError("Error inserting into raid members: [{}]", results.ErrorMessage().c_str()); + } + + LearnMembers(); + VerifyRaid(); + if (rleader) { + database.SetRaidGroupLeaderInfo(RAID_GROUPLESS, GetID()); + UpdateRaidAAs(); + } + if (group != RAID_GROUPLESS && groupleader) { + database.SetRaidGroupLeaderInfo(group, GetID()); + UpdateGroupAAs(group); + } + if (group < 12) + GroupUpdate(group); + else // get raid AAs, GroupUpdate will handles it otherwise + //SendGroupLeadershipAA(c, RAID_GROUPLESS); Is this needed for bots? + SendRaidAddAll(b->GetOwner()->GetName()); + + b->SetRaidGrouped(true); + SendRaidMOTD(b->GetOwner()->CastToClient()); + + // Mitch What to do here? + // xtarget shit .......... + //if (group == RAID_GROUPLESS) { + // if (rleader) { + // GetXTargetAutoMgr()->merge(*c->GetXTargetAutoMgr()); + // c->GetXTargetAutoMgr()->clear(); + // c->SetXTargetAutoMgr(GetXTargetAutoMgr()); + // } + // else { + // if (!c->GetXTargetAutoMgr()->empty()) { + // GetXTargetAutoMgr()->merge(*c->GetXTargetAutoMgr()); + // c->GetXTargetAutoMgr()->clear(); + // c->RemoveAutoXTargets(); + // } + + // c->SetXTargetAutoMgr(GetXTargetAutoMgr()); + + // if (!c->GetXTargetAutoMgr()->empty()) + // c->SetDirtyAutoHaters(); + // } + //} + + Raid* raid_update = nullptr; + raid_update = b->GetOwner()->GetRaid(); + if (raid_update) { + raid_update->SendHPManaEndPacketsTo(b->GetOwner()->CastToClient()); + raid_update->SendHPManaEndPacketsFrom(b->GetOwner()->CastToClient()); + } + + auto pack = new ServerPacket(ServerOP_RaidAdd, sizeof(ServerRaidGeneralAction_Struct)); + ServerRaidGeneralAction_Struct* rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer; + rga->rid = GetID(); + strn0cpy(rga->playername, b->GetOwner()->GetName(), 64); + rga->zoneid = zone->GetZoneID(); + rga->instance_id = zone->GetInstanceID(); + worldserver.SendPacket(pack); + safe_delete(pack); +} + void Raid::RemoveMember(const char *characterName) { diff --git a/zone/raids.h b/zone/raids.h index a04d1eb54..1662bb6ad 100644 --- a/zone/raids.h +++ b/zone/raids.h @@ -112,6 +112,7 @@ public: bool IsRaid() { return true; } void AddMember(Client *c, uint32 group = 0xFFFFFFFF, bool rleader=false, bool groupleader=false, bool looter=false); + void AddBot(Bot* b, uint32 group = 0xFFFFFFFF, bool rleader=false, bool groupleader=false, bool looter=false); void RemoveMember(const char *c); void DisbandRaid(); void MoveMember(const char *name, uint32 newGroup); From d85646b637e88432d8b7c602852cb713cea565a5 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Wed, 5 Jan 2022 17:33:52 -0400 Subject: [PATCH 08/55] Basement Jan 5 --- .gitignore | 1 + zone/raids.cpp | 25 +++++++++++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 1db525804..4f64e32a6 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,4 @@ bin/ /Win32 /x64 /client_files/**/CMakeFiles/ +submodules/libuv diff --git a/zone/raids.cpp b/zone/raids.cpp index fb5e9a03a..cdd23fefc 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -194,7 +194,7 @@ void Raid::AddBot(Bot* b, uint32 group, bool rleader, bool groupleader, bool loo GroupUpdate(group); else // get raid AAs, GroupUpdate will handles it otherwise //SendGroupLeadershipAA(c, RAID_GROUPLESS); Is this needed for bots? - SendRaidAddAll(b->GetOwner()->GetName()); + //SendRaidAddAll(b->GetOwner()->GetName()); b->SetRaidGrouped(true); SendRaidMOTD(b->GetOwner()->CastToClient()); @@ -231,7 +231,7 @@ void Raid::AddBot(Bot* b, uint32 group, bool rleader, bool groupleader, bool loo auto pack = new ServerPacket(ServerOP_RaidAdd, sizeof(ServerRaidGeneralAction_Struct)); ServerRaidGeneralAction_Struct* rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer; rga->rid = GetID(); - strn0cpy(rga->playername, b->GetOwner()->GetName(), 64); + strn0cpy(rga->playername, b->GetName(), 64); rga->zoneid = zone->GetZoneID(); rga->instance_id = zone->GetInstanceID(); worldserver.SendPacket(pack); @@ -1097,7 +1097,7 @@ void Raid::SendRaidAddAll(const char *who) { for(int x = 0; x < MAX_RAID_MEMBERS; x++) { - if(strcmp(members[x].membername, who) == 0) + if(strcmp(members[x].membername, who) == 0 && members[x].membername != "MyBard") //Mitch add IsBot { auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidAddMember_Struct)); RaidAddMember_Struct *ram = (RaidAddMember_Struct*)outapp->pBuffer; @@ -1227,7 +1227,12 @@ void Raid::SendBulkRaid(Client *to) { if(strlen(members[x].membername) > 0 && (strcmp(members[x].membername, to->GetName()) != 0)) //don't send ourself { - SendRaidAdd(members[x].membername, to); +#ifdef BOTS + if(!entity_list.GetBotByBotName(members[x].membername)) + SendRaidAdd(members[x].membername, to); +#else + SendRaidAdd(members[x].membername, to); +#endif } } } @@ -1616,14 +1621,22 @@ void Raid::VerifyRaid() } else{ Client *c = entity_list.GetClientByName(members[x].membername); +#ifdef BOTS + Bot* b = entity_list.GetBotByBotName(members[x].membername); //Mitch +#endif if(c){ members[x].member = c; } - else{ +#ifdef BOTS + else if(b){ + members[x].member = b->CastToClient(); //Raid requires client* we are forcing it here to be a BOT + } +#endif + else { members[x].member = nullptr; } } - if(members[x].IsRaidLeader){ + if(members[x].IsRaidLeader && !members[x].member->IsBot()){ //Mitch added reference to IsBot if(strlen(members[x].membername) > 0){ SetLeader(members[x].member); strn0cpy(leadername, members[x].membername, 64); From 42ef4a2891d7fe88da95f96f132db51cef943f9f Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Wed, 5 Jan 2022 22:46:06 -0400 Subject: [PATCH 09/55] End of day Jan 5 Working Raid Invite to a Bot. --- zone/bot.cpp | 11 ++++++----- zone/client_packet.cpp | 40 +++++++++++++++++++++------------------- zone/raids.cpp | 16 ++++++++-------- 3 files changed, 35 insertions(+), 32 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index c52725585..133e3f4ec 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -10102,7 +10102,7 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { b_owner->MessageString(Chat::White, ALREADY_IN_RAID, player_accepting_invite->GetName()); //group failed, must invite members not in raid... return; } - Raid* raid = entity_list.GetRaidByMob(player_accepting_invite); + Raid* raid = entity_list.GetRaidByClient(b_owner); if (raid) { raid->VerifyRaid(); Group* group = player_accepting_invite->GetGroup(); @@ -10150,9 +10150,9 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { raid->GroupUpdate(free_group_id); } else { - raid->SendRaidCreate(b_owner); - raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); - raid->AddMember(b_owner); + //raid->SendRaidCreate(b_owner); + //raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); + raid->AddBot(player_accepting_invite); raid->SendBulkRaid(b_owner); if (raid->IsLocked()) { raid->SendRaidLockTo(b_owner); @@ -10354,8 +10354,9 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { raid->SendRaidCreate(b_owner); raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); raid->AddMember(b_owner, 0xFFFFFFFF, true, false, true); - raid->SendBulkRaid(b_owner); raid->AddBot(player_accepting_invite); + raid->SendBulkRaid(b_owner); + if (raid->IsLocked()) { raid->SendRaidLockTo(b_owner); } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 7eae849c4..e06610fbb 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -11322,7 +11322,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) { case RaidCommandInviteIntoExisting: case RaidCommandInvite: { -//Mitch + //Mitch #ifdef BOTS Bot* player_to_invite = nullptr; Client* player_to_invite_owner = nullptr; @@ -11353,28 +11353,30 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) Bot::ProcessRaidInvite(player_to_invite, player_to_invite_owner); } -#else - Client *player_to_invite = entity_list.GetClientByName(raid_command_packet->player_name); + else + { +#endif + Client* player_to_invite = entity_list.GetClientByName(raid_command_packet->player_name); - if (!player_to_invite) - break; + if (!player_to_invite) + break; - Group *player_to_invite_group = player_to_invite->GetGroup(); + Group* player_to_invite_group = player_to_invite->GetGroup(); - if (player_to_invite->HasRaid()) { - Message(Chat::Red, "%s is already in a raid.", player_to_invite->GetName()); - break; - } + if (player_to_invite->HasRaid()) { + Message(Chat::Red, "%s is already in a raid.", player_to_invite->GetName()); + break; + } - if (player_to_invite_group && player_to_invite_group->IsGroupMember(this)) { - MessageString(Chat::Red, ALREADY_IN_PARTY); - break; - } + if (player_to_invite_group && player_to_invite_group->IsGroupMember(this)) { + MessageString(Chat::Red, ALREADY_IN_PARTY); + break; + } - if (player_to_invite_group && !player_to_invite_group->IsLeader(player_to_invite)) { - Message(Chat::Red, "You can only invite an ungrouped player or group leader to join your raid."); - break; - } + if (player_to_invite_group && !player_to_invite_group->IsLeader(player_to_invite)) { + Message(Chat::Red, "You can only invite an ungrouped player or group leader to join your raid."); + break; + } /* Send out invite to the client */ auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); @@ -11389,10 +11391,10 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) player_to_invite->QueuePacket(outapp); safe_delete(outapp); -#endif break; } + } case RaidCommandAcceptInvite: { diff --git a/zone/raids.cpp b/zone/raids.cpp index cdd23fefc..35cbc6b5a 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -221,12 +221,12 @@ void Raid::AddBot(Bot* b, uint32 group, bool rleader, bool groupleader, bool loo // } //} - Raid* raid_update = nullptr; - raid_update = b->GetOwner()->GetRaid(); - if (raid_update) { - raid_update->SendHPManaEndPacketsTo(b->GetOwner()->CastToClient()); - raid_update->SendHPManaEndPacketsFrom(b->GetOwner()->CastToClient()); - } +// Raid* raid_update = nullptr; +// raid_update = b->GetOwner()->GetRaid(); +// if (raid_update) { +// raid_update->SendHPManaEndPacketsTo(b->GetOwner()->CastToClient()); +// raid_update->SendHPManaEndPacketsFrom(b->GetOwner()->CastToClient()); +// } auto pack = new ServerPacket(ServerOP_RaidAdd, sizeof(ServerRaidGeneralAction_Struct)); ServerRaidGeneralAction_Struct* rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer; @@ -1227,7 +1227,7 @@ void Raid::SendBulkRaid(Client *to) { if(strlen(members[x].membername) > 0 && (strcmp(members[x].membername, to->GetName()) != 0)) //don't send ourself { -#ifdef BOTS +#ifdef BOTSS if(!entity_list.GetBotByBotName(members[x].membername)) SendRaidAdd(members[x].membername, to); #else @@ -1241,7 +1241,7 @@ void Raid::QueuePacket(const EQApplicationPacket *app, bool ack_req) { for(int x = 0; x < MAX_RAID_MEMBERS; x++) { - if(members[x].member) + if(members[x].member && !members[x].member->IsBot()) { members[x].member->QueuePacket(app, ack_req); } From fdb23f1a5f28bc6a493287570524b381f23093ab Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Thu, 6 Jan 2022 17:18:34 -0400 Subject: [PATCH 10/55] Update to Client::QueuePacket to not attempt to send a packet to a BoT. Not clean, but a broad solution. --- zone/bot.cpp | 50 ++++++++++++++++++++++++++++++++++--------------- zone/client.cpp | 2 +- zone/raids.cpp | 13 +++++-------- 3 files changed, 41 insertions(+), 24 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index 133e3f4ec..7fff6c472 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -10121,25 +10121,45 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { if (group) {//add us all uint32 free_group_id = raid->GetFreeGroup(); Client* addClient = nullptr; + Bot* addBot = nullptr; for (int x = 0; x < 6; x++) { if (group->members[x]) { Client* c = nullptr; - if (group->members[x]->IsBot()) + Bot* b = nullptr; + if (group->members[x]->IsBot()) { + b = group->members[x]->CastToBot(); + if (x == 0) { + raid->AddBot(b, free_group_id, false, true, false); + raid->SetGroupLeader(b->GetName()); + } + else { + raid->AddBot(b, free_group_id, false, false, false); + } + } + else if (group->members[x]->IsClient()) { c = group->members[x]->CastToClient(); - - if (!addClient) - { - addClient = c; - raid->SetGroupLeader(addClient->GetName()); + if (x == 0) { + raid->AddMember(c, free_group_id, false, true, false); + raid->SetGroupLeader(c->GetName()); + } + else { + raid->AddMember(c, free_group_id, false, false, false); + } } - raid->SendRaidCreate(b_owner); - raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); - if (group->IsLeader(group->members[x])) - raid->AddMember(c, free_group_id, false, true); - else - raid->AddMember(c, free_group_id); - raid->SendBulkRaid(b_owner); + //if (!addClient) + //{ + // addClient = c; + // raid->SetGroupLeader(addClient->GetName()); + //} + + //raid->SendRaidCreate(b_owner); + //raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); + //if (group->IsLeader(group->members[x])) +// raid->AddMember(c, free_group_id, false, true); + // else + // raid->AddMember(c, free_group_id); + //raid->SendRaidGroupAdd(b_owner->GetName(), free_group_id); if (raid->IsLocked()) { raid->SendRaidLockTo(b_owner); } @@ -10149,7 +10169,7 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { group->DisbandGroup(true); raid->GroupUpdate(free_group_id); } - else { + else { // Jan 6 this also now works. One player already in a raid, invites one or many bots. //raid->SendRaidCreate(b_owner); //raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); raid->AddBot(player_accepting_invite); @@ -10346,7 +10366,7 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { raid->SendRaidLockTo(b_owner); } } - else { // neither has a group + else { // neither has a group - Jan 6 this appears to work now. One ungrouped player, one/many ungrouped bots raid = new Raid(b_owner); entity_list.AddRaid(raid); raid->SetRaidDetails(); diff --git a/zone/client.cpp b/zone/client.cpp index 8ad656506..3c5c25131 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -813,7 +813,7 @@ void Client::QueuePacket(const EQApplicationPacket* app, bool ack_req, CLIENT_CO AddPacket(app, ack_req); } else - if(eqs) + if(eqs && !IsBot()) //Mitch added the BoTcheck for a fail safe on trying to send a packet to a BoT! eqs->QueuePacket(app, ack_req); } diff --git a/zone/raids.cpp b/zone/raids.cpp index 35cbc6b5a..ce077e43e 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -188,7 +188,7 @@ void Raid::AddBot(Bot* b, uint32 group, bool rleader, bool groupleader, bool loo } if (group != RAID_GROUPLESS && groupleader) { database.SetRaidGroupLeaderInfo(group, GetID()); - UpdateGroupAAs(group); + //UpdateGroupAAs(group); } if (group < 12) GroupUpdate(group); @@ -1227,12 +1227,7 @@ void Raid::SendBulkRaid(Client *to) { if(strlen(members[x].membername) > 0 && (strcmp(members[x].membername, to->GetName()) != 0)) //don't send ourself { -#ifdef BOTSS - if(!entity_list.GetBotByBotName(members[x].membername)) SendRaidAdd(members[x].membername, to); -#else - SendRaidAdd(members[x].membername, to); -#endif } } } @@ -1342,8 +1337,10 @@ void Raid::GroupUpdate(uint32 gid, bool initial) if(strlen(members[x].membername) > 0){ if(members[x].GroupNumber == gid){ if(members[x].member) { - SendGroupUpdate(members[x].member); - SendGroupLeadershipAA(members[x].member, gid); + if (members[x].member->IsClient()) { //Mitch added + SendGroupUpdate(members[x].member); + SendGroupLeadershipAA(members[x].member, gid); + } } } } From ec26281ad50b91ada78e443f7ee2e38c346258c9 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Thu, 6 Jan 2022 19:54:06 -0400 Subject: [PATCH 11/55] Updated Raid::VerifyRaid --- zone/bot.cpp | 5 +++-- zone/raids.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index 7fff6c472..a2ccbe234 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -10108,13 +10108,13 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { Group* group = player_accepting_invite->GetGroup(); if (group) { if (group->GroupCount() + raid->RaidCount() > MAX_RAID_MEMBERS) { - b_owner->Message(Chat::Red, "Invite failed, group invite would create a raid larger than the maximum number of members allowed."); + b_owner->Message(Chat::Red, "Invite failed, bot group invite would create a raid larger than the maximum number of members allowed."); return; } } else { if (1 + raid->RaidCount() > MAX_RAID_MEMBERS) { - b_owner->Message(Chat::Red, "Invite failed, member invite would create a raid larger than the maximum number of members allowed."); + b_owner->Message(Chat::Red, "Invite failed, bot invite would create a raid larger than the maximum number of members allowed."); return; } } @@ -10122,6 +10122,7 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { uint32 free_group_id = raid->GetFreeGroup(); Client* addClient = nullptr; Bot* addBot = nullptr; + for (int x = 0; x < 6; x++) { if (group->members[x]) { Client* c = nullptr; diff --git a/zone/raids.cpp b/zone/raids.cpp index ce077e43e..3b589b8a8 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -1633,7 +1633,7 @@ void Raid::VerifyRaid() members[x].member = nullptr; } } - if(members[x].IsRaidLeader && !members[x].member->IsBot()){ //Mitch added reference to IsBot + if(members[x].IsRaidLeader){ if(strlen(members[x].membername) > 0){ SetLeader(members[x].member); strn0cpy(leadername, members[x].membername, 64); From 40e3484bb41219d59794cc7301e38cf2018c521a Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Fri, 7 Jan 2022 18:57:26 -0400 Subject: [PATCH 12/55] Some Bot Raid working --- zone/bot.cpp | 16 ++++++++++++---- zone/raids.cpp | 19 ++++++++++++------- zone/raids.h | 3 ++- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index a2ccbe234..40dd18456 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -10136,16 +10136,24 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { else { raid->AddBot(b, free_group_id, false, false, false); } + raid->SendBulkRaid(b->CastToClient()); } else if (group->members[x]->IsClient()) { c = group->members[x]->CastToClient(); if (x == 0) { + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, free_group_id, false, true, false); raid->SetGroupLeader(c->GetName()); } else { + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, free_group_id, false, false, false); } + raid->SendBulkRaid(c); + if (raid->IsLocked()) + raid->SendRaidLockTo(c); } //if (!addClient) @@ -10161,9 +10169,7 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { // else // raid->AddMember(c, free_group_id); //raid->SendRaidGroupAdd(b_owner->GetName(), free_group_id); - if (raid->IsLocked()) { - raid->SendRaidLockTo(b_owner); - } + } } group->JoinRaidXTarget(raid); @@ -10174,7 +10180,9 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { //raid->SendRaidCreate(b_owner); //raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); raid->AddBot(player_accepting_invite); - raid->SendBulkRaid(b_owner); + // Set indicator that bot owner has already received this update. Mitch + + //raid->SendBulkRaid(b_owner); if (raid->IsLocked()) { raid->SendRaidLockTo(b_owner); } diff --git a/zone/raids.cpp b/zone/raids.cpp index 3b589b8a8..32f19045a 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -194,10 +194,11 @@ void Raid::AddBot(Bot* b, uint32 group, bool rleader, bool groupleader, bool loo GroupUpdate(group); else // get raid AAs, GroupUpdate will handles it otherwise //SendGroupLeadershipAA(c, RAID_GROUPLESS); Is this needed for bots? - //SendRaidAddAll(b->GetOwner()->GetName()); - + SendRaidAddAll(b->GetName()); + + members[GetPlayerIndex(b->GetName())].SentToBotOwner = true; //Mitch indicates that the BotOwner has received this raid info already. b->SetRaidGrouped(true); - SendRaidMOTD(b->GetOwner()->CastToClient()); + //SendRaidMOTD(b->GetOwner()->CastToClient()); // Mitch What to do here? // xtarget shit .......... @@ -1075,7 +1076,7 @@ void Raid::SendRaidAdd(const char *who, Client *to) for(int x = 0; x < MAX_RAID_MEMBERS; x++) { - if(strcmp(members[x].membername, who) == 0) + if(strcmp(members[x].membername, who) == 0 || !members[x].SentToBotOwner) //Mitch { auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidAddMember_Struct)); RaidAddMember_Struct *ram = (RaidAddMember_Struct*)outapp->pBuffer; @@ -1095,12 +1096,15 @@ void Raid::SendRaidAdd(const char *who, Client *to) void Raid::SendRaidAddAll(const char *who) { - for(int x = 0; x < MAX_RAID_MEMBERS; x++) + for (int x = 0; x < MAX_RAID_MEMBERS; x++) { - if(strcmp(members[x].membername, who) == 0 && members[x].membername != "MyBard") //Mitch add IsBot + if (strcmp(members[x].membername, who) == 0 ) //Mitch add IsBot + //if (!members[x].member->IsBot() || + // strcmp(members[x].membername, who) == 0 || + // (members[x].SentToBotOwner && members[x].member->GetOwnerID() != entity_list.GetClientByName(who)->CharacterID())) //Mitch add IsBot { auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidAddMember_Struct)); - RaidAddMember_Struct *ram = (RaidAddMember_Struct*)outapp->pBuffer; + RaidAddMember_Struct* ram = (RaidAddMember_Struct*)outapp->pBuffer; ram->raidGen.action = raidAdd; ram->raidGen.parameter = members[x].GroupNumber; strcpy(ram->raidGen.leader_name, members[x].membername); @@ -1111,6 +1115,7 @@ void Raid::SendRaidAddAll(const char *who) this->QueuePacket(outapp); safe_delete(outapp); return; + } } } diff --git a/zone/raids.h b/zone/raids.h index 1662bb6ad..9961be2e8 100644 --- a/zone/raids.h +++ b/zone/raids.h @@ -88,6 +88,7 @@ struct RaidMember{ bool IsGroupLeader; bool IsRaidLeader; bool IsLooter; + bool SentToBotOwner; }; struct GroupMentor { @@ -112,7 +113,7 @@ public: bool IsRaid() { return true; } void AddMember(Client *c, uint32 group = 0xFFFFFFFF, bool rleader=false, bool groupleader=false, bool looter=false); - void AddBot(Bot* b, uint32 group = 0xFFFFFFFF, bool rleader=false, bool groupleader=false, bool looter=false); + void AddBot(Bot* b, uint32 group = 0xFFFFFFFF, bool rleader=false, bool groupleader=false, bool looter=false); //Mitch void RemoveMember(const char *c); void DisbandRaid(); void MoveMember(const char *name, uint32 newGroup); From b8b5ca0e67f078c5d539fae1e59237f15b73a363 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Fri, 7 Jan 2022 20:09:38 -0400 Subject: [PATCH 13/55] Before VS Crash --- zone/bot.cpp | 14 ++++++++------ zone/client.cpp | 2 +- zone/raids.cpp | 8 +++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index 40dd18456..b678d681b 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -10103,9 +10103,9 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { return; } Raid* raid = entity_list.GetRaidByClient(b_owner); - if (raid) { + if (raid) { // Does a raid already exist? raid->VerifyRaid(); - Group* group = player_accepting_invite->GetGroup(); + Group* group = player_accepting_invite->GetGroup(); if (group) { if (group->GroupCount() + raid->RaidCount() > MAX_RAID_MEMBERS) { b_owner->Message(Chat::Red, "Invite failed, bot group invite would create a raid larger than the maximum number of members allowed."); @@ -10118,7 +10118,8 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { return; } } - if (group) {//add us all +//Usecase #3 - Raid already created, Bot is BotGroupLeader. + if (group) {//add us all // Is the player already in a group? If yes, add all players from the group uint32 free_group_id = raid->GetFreeGroup(); Client* addClient = nullptr; Bot* addBot = nullptr; @@ -10176,7 +10177,7 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { group->DisbandGroup(true); raid->GroupUpdate(free_group_id); } - else { // Jan 6 this also now works. One player already in a raid, invites one or many bots. + else { // Jan 6 this also now works. // If not in a group, invite the individual player //raid->SendRaidCreate(b_owner); //raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); raid->AddBot(player_accepting_invite); @@ -10189,7 +10190,7 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { } } else - { + { // A raid does not already exist. One needs to be created before going forward Group* player_invited_group = player_accepting_invite->GetGroup(); Group* group = entity_list.GetGroupByClient(b_owner); // player_accepting_invite->GetGroup(); if (group) //if our target has a group @@ -10375,6 +10376,7 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { raid->SendRaidLockTo(b_owner); } } +//Usecase #2 - Neither the invitor and Bot has a group. else { // neither has a group - Jan 6 this appears to work now. One ungrouped player, one/many ungrouped bots raid = new Raid(b_owner); entity_list.AddRaid(raid); @@ -10384,7 +10386,7 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); raid->AddMember(b_owner, 0xFFFFFFFF, true, false, true); raid->AddBot(player_accepting_invite); - raid->SendBulkRaid(b_owner); +// raid->SendBulkRaid(b_owner); //Removed to correct usecase #2 if (raid->IsLocked()) { raid->SendRaidLockTo(b_owner); diff --git a/zone/client.cpp b/zone/client.cpp index 3c5c25131..e47acc2ad 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -825,7 +825,7 @@ void Client::FastQueuePacket(EQApplicationPacket** app, bool ack_req, CLIENT_CON return; } else { - if(eqs) + if(eqs && !IsBot()) //Mitch added eqs->FastQueuePacket((EQApplicationPacket **)app, ack_req); else if (app && (*app)) delete *app; diff --git a/zone/raids.cpp b/zone/raids.cpp index 32f19045a..575afadda 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -1341,11 +1341,9 @@ void Raid::GroupUpdate(uint32 gid, bool initial) { if(strlen(members[x].membername) > 0){ if(members[x].GroupNumber == gid){ - if(members[x].member) { - if (members[x].member->IsClient()) { //Mitch added - SendGroupUpdate(members[x].member); - SendGroupLeadershipAA(members[x].member, gid); - } + if (members[x].member) { + SendGroupUpdate(members[x].member); + SendGroupLeadershipAA(members[x].member, gid); } } } From 947fb239a941d1bd77ea346b2909f579a5fb8ea3 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Sat, 8 Jan 2022 00:03:05 -0400 Subject: [PATCH 14/55] Use Case 1, 2, 3,4,7 working. Need to fix 5, 6, 8 --- zone/bot.cpp | 486 ++++++++++++++++++++++++------------------------- zone/raids.cpp | 10 +- 2 files changed, 240 insertions(+), 256 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index b678d681b..d1b1ec6f9 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -10097,297 +10097,281 @@ uint8 Bot::spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQ::const void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { //Client* player_accepting_invite = entity_list.GetClientByName(raid_command_packet->player_name); - if (player_accepting_invite) { - if (player_accepting_invite->IsRaidGrouped()) { - b_owner->MessageString(Chat::White, ALREADY_IN_RAID, player_accepting_invite->GetName()); //group failed, must invite members not in raid... + if (player_accepting_invite) { + if (player_accepting_invite->IsRaidGrouped()) { + b_owner->MessageString(Chat::White, ALREADY_IN_RAID, player_accepting_invite->GetName()); //group failed, must invite members not in raid... + return; + } + Raid* raid = entity_list.GetRaidByClient(b_owner); + if (raid) { // Does a raid already exist? + raid->VerifyRaid(); + Group* group = player_accepting_invite->GetGroup(); + if (group) { + if (group->GroupCount() + raid->RaidCount() > MAX_RAID_MEMBERS) { + b_owner->Message(Chat::Red, "Invite failed, bot group invite would create a raid larger than the maximum number of members allowed."); return; } - Raid* raid = entity_list.GetRaidByClient(b_owner); - if (raid) { // Does a raid already exist? - raid->VerifyRaid(); - Group* group = player_accepting_invite->GetGroup(); - if (group) { - if (group->GroupCount() + raid->RaidCount() > MAX_RAID_MEMBERS) { - b_owner->Message(Chat::Red, "Invite failed, bot group invite would create a raid larger than the maximum number of members allowed."); - return; - } - } - else { - if (1 + raid->RaidCount() > MAX_RAID_MEMBERS) { - b_owner->Message(Chat::Red, "Invite failed, bot invite would create a raid larger than the maximum number of members allowed."); - return; - } - } -//Usecase #3 - Raid already created, Bot is BotGroupLeader. - if (group) {//add us all // Is the player already in a group? If yes, add all players from the group - uint32 free_group_id = raid->GetFreeGroup(); - Client* addClient = nullptr; - Bot* addBot = nullptr; - - for (int x = 0; x < 6; x++) { - if (group->members[x]) { - Client* c = nullptr; - Bot* b = nullptr; - if (group->members[x]->IsBot()) { - b = group->members[x]->CastToBot(); - if (x == 0) { - raid->AddBot(b, free_group_id, false, true, false); - raid->SetGroupLeader(b->GetName()); - } - else { - raid->AddBot(b, free_group_id, false, false, false); - } - raid->SendBulkRaid(b->CastToClient()); - } - else if (group->members[x]->IsClient()) { - c = group->members[x]->CastToClient(); - if (x == 0) { - raid->SendRaidCreate(c); - raid->SendMakeLeaderPacketTo(raid->leadername, c); - raid->AddMember(c, free_group_id, false, true, false); - raid->SetGroupLeader(c->GetName()); - } - else { - raid->SendRaidCreate(c); - raid->SendMakeLeaderPacketTo(raid->leadername, c); - raid->AddMember(c, free_group_id, false, false, false); - } - raid->SendBulkRaid(c); - if (raid->IsLocked()) - raid->SendRaidLockTo(c); - } + } + else { + if (1 + raid->RaidCount() > MAX_RAID_MEMBERS) { + b_owner->Message(Chat::Red, "Invite failed, bot invite would create a raid larger than the maximum number of members allowed."); + return; + } + } + //Usecase #3 - Raid already created, Bot is BotGroupLeader. + if (group) {//add us all // Is the player already in a group? If yes, add all players from the group + uint32 free_group_id = raid->GetFreeGroup(); + Client* addClient = nullptr; + Bot* addBot = nullptr; - //if (!addClient) - //{ - // addClient = c; - // raid->SetGroupLeader(addClient->GetName()); - //} + for (int x = 0; x < 6; x++) { + if (group->members[x]) { + Client* c = nullptr; + Bot* b = nullptr; + if (group->members[x]->IsBot()) { + b = group->members[x]->CastToBot(); + if (x == 0) { + raid->AddBot(b, free_group_id, false, true, false); + raid->SetGroupLeader(b->GetName()); + } + else { + raid->AddBot(b, free_group_id, false, false, false); + } + raid->SendBulkRaid(b->CastToClient()); + } + else if (group->members[x]->IsClient()) { + c = group->members[x]->CastToClient(); + if (x == 0) { + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); + raid->AddMember(c, free_group_id, false, true, false); + raid->SetGroupLeader(c->GetName()); + } + else { + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); + raid->AddMember(c, free_group_id, false, false, false); + } + raid->SendBulkRaid(c); + if (raid->IsLocked()) + raid->SendRaidLockTo(c); + } - //raid->SendRaidCreate(b_owner); - //raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); - //if (group->IsLeader(group->members[x])) + //if (!addClient) + //{ + // addClient = c; + // raid->SetGroupLeader(addClient->GetName()); + //} + + //raid->SendRaidCreate(b_owner); + //raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); + //if (group->IsLeader(group->members[x])) // raid->AddMember(c, free_group_id, false, true); // else // raid->AddMember(c, free_group_id); //raid->SendRaidGroupAdd(b_owner->GetName(), free_group_id); - - } - } - group->JoinRaidXTarget(raid); - group->DisbandGroup(true); - raid->GroupUpdate(free_group_id); - } - else { // Jan 6 this also now works. // If not in a group, invite the individual player - //raid->SendRaidCreate(b_owner); - //raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); - raid->AddBot(player_accepting_invite); - // Set indicator that bot owner has already received this update. Mitch - - //raid->SendBulkRaid(b_owner); - if (raid->IsLocked()) { - raid->SendRaidLockTo(b_owner); - } + } } - else - { // A raid does not already exist. One needs to be created before going forward - Group* player_invited_group = player_accepting_invite->GetGroup(); - Group* group = entity_list.GetGroupByClient(b_owner); // player_accepting_invite->GetGroup(); - if (group) //if our target has a group - { -// raid = new Raid(player_accepting_invite); - raid = new Raid(b_owner); - entity_list.AddRaid(raid); - raid->SetRaidDetails(); + group->JoinRaidXTarget(raid); + group->DisbandGroup(true); + raid->GroupUpdate(free_group_id); + } + else { // Jan 6 this also now works. // If not in a group, invite the individual player + //raid->SendRaidCreate(b_owner); + //raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); + raid->AddBot(player_accepting_invite); + // Set indicator that bot owner has already received this update. Mitch - uint32 raid_free_group_id = raid->GetFreeGroup(); + //raid->SendBulkRaid(b_owner); + if (raid->IsLocked()) { + raid->SendRaidLockTo(b_owner); + } + } + } + //No raid exists. + else + { // A raid does not already exist. One needs to be created before going forward + Group* player_invited_group = player_accepting_invite->GetGroup(); + Group* group = entity_list.GetGroupByClient(b_owner); // player_accepting_invite->GetGroup(); + if (group) //if our target has a group + { + // raid = new Raid(player_accepting_invite); + raid = new Raid(b_owner); + entity_list.AddRaid(raid); + raid->SetRaidDetails(); - /* If we already have a group then cycle through adding us... */ - if (player_invited_group) { - Client* client_to_be_leader = nullptr; - for (int x = 0; x < 6; x++) { - if (player_invited_group->members[x]) { - if (!client_to_be_leader) { - if (player_invited_group->members[x]->IsClient()) { - client_to_be_leader = player_invited_group->members[x]->CastToClient(); - raid->SetGroupLeader(client_to_be_leader->GetName()); - } - } - if (player_invited_group->IsLeader(player_invited_group->members[x])) { - Client* c = nullptr; + uint32 raid_free_group_id = raid->GetFreeGroup(); - if (player_invited_group->members[x]->IsClient() || player_invited_group->members[x]->IsBot()) - c = player_invited_group->members[x]->CastToClient(); - else - continue; - - raid->SendRaidCreate(b_owner); - raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); - raid->AddMember(c, raid_free_group_id, true, true, true); - raid->SendBulkRaid(c); - - if (raid->IsLocked()) { - raid->SendRaidLockTo(b_owner); - } - } - else { - Client* c = nullptr; - - if (player_invited_group->members[x]->IsClient() || player_invited_group->members[x]->IsBot()) - c = player_invited_group->members[x]->CastToClient(); - else - continue; - - raid->SendRaidCreate(b_owner); - raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); - raid->AddMember(c, raid_free_group_id); - raid->SendBulkRaid(b_owner); - - if (raid->IsLocked()) { - raid->SendRaidLockTo(b_owner); - } - } + /* If we already have a group then cycle through adding us... */ + if (player_invited_group) { + Client* client_to_be_leader = nullptr; + for (int x = 0; x < 6; x++) { + if (player_invited_group->members[x]) { + if (!client_to_be_leader) { + if (player_invited_group->members[x]->IsClient()) { + client_to_be_leader = player_invited_group->members[x]->CastToClient(); + raid->SetGroupLeader(client_to_be_leader->GetName()); } } - player_invited_group->JoinRaidXTarget(raid, true); - player_invited_group->DisbandGroup(true); - raid->GroupUpdate(raid_free_group_id); - raid_free_group_id = raid->GetFreeGroup(); - } - else { -// raid->SendRaidCreate(player_accepting_invite); -// raid->AddMember(player_accepting_invite, 0xFFFFFFFF, true, false, true); - raid->SendRaidCreate(b_owner); - raid->AddMember(b_owner, 0xFFFFFFFF, true, false, true); - } + if (player_invited_group->IsLeader(player_invited_group->members[x])) { + Client* c = nullptr; - Client* client_to_add = nullptr; - /* Add client to an existing group */ - for (int x = 0; x < 6; x++) { - if (group->members[x]) { - if (!client_to_add) { - if (group->members[x]->IsClient() || group->members[x]->IsBot()) { - client_to_add = group->members[x]->CastToClient(); - raid->SetGroupLeader(client_to_add->GetName()); - } - } - if (group->IsLeader(group->members[x])) { - Client* c = nullptr; - - if (group->members[x]->IsClient() || group->members[x]->IsClient()) - c = group->members[x]->CastToClient(); - else - continue; - - raid->SendRaidCreate(b_owner); - raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); - raid->AddMember(c, raid_free_group_id, false, true); - raid->SendBulkRaid(b_owner); - - if (raid->IsLocked()) { - raid->SendRaidLockTo(b_owner); - } - } + if (player_invited_group->members[x]->IsClient() || player_invited_group->members[x]->IsBot()) + c = player_invited_group->members[x]->CastToClient(); else - { - Client* c = nullptr; + continue; - if (group->members[x]->IsClient() || group->members[x]->IsBot()) - c = group->members[x]->CastToClient(); - else - continue; + raid->SendRaidCreate(b_owner); + raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); + raid->AddMember(c, raid_free_group_id, true, true, true); + raid->SendBulkRaid(c); - raid->SendRaidCreate(b_owner); - raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); - raid->AddMember(c, raid_free_group_id); - raid->SendBulkRaid(b_owner); + if (raid->IsLocked()) { + raid->SendRaidLockTo(b_owner); + } + } + else { + Client* c = nullptr; - if (raid->IsLocked()) { - raid->SendRaidLockTo(b_owner); - } + if (player_invited_group->members[x]->IsClient() || player_invited_group->members[x]->IsBot()) + c = player_invited_group->members[x]->CastToClient(); + else + continue; + + raid->SendRaidCreate(b_owner); + raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); + raid->AddMember(c, raid_free_group_id); + raid->SendBulkRaid(b_owner); + + if (raid->IsLocked()) { + raid->SendRaidLockTo(b_owner); } } } - group->JoinRaidXTarget(raid); - group->DisbandGroup(true); - - raid->GroupUpdate(raid_free_group_id); } - /* Target does not have a group */ - else { - if (player_invited_group) { + player_invited_group->JoinRaidXTarget(raid, true); + player_invited_group->DisbandGroup(true); + raid->GroupUpdate(raid_free_group_id); + raid_free_group_id = raid->GetFreeGroup(); + } + else { + // raid->SendRaidCreate(player_accepting_invite); + // raid->AddMember(player_accepting_invite, 0xFFFFFFFF, true, false, true); + raid->SendRaidCreate(b_owner); + raid->AddMember(b_owner, 0xFFFFFFFF, true, false, true); + } - raid = new Raid(b_owner); - - entity_list.AddRaid(raid); - raid->SetRaidDetails(); - Client* addClientig = nullptr; - for (int x = 0; x < 6; x++) { - if (player_invited_group->members[x]) { - if (!addClientig) { - if (player_invited_group->members[x]->IsClient() || player_invited_group->members[x]->IsBot()) { - addClientig = player_invited_group->members[x]->CastToClient(); - raid->SetGroupLeader(addClientig->GetName()); - } - } - if (player_invited_group->IsLeader(player_invited_group->members[x])) { - Client* c = nullptr; - - if (player_invited_group->members[x]->IsClient() || player_invited_group->members[x]->IsBot()) - c = player_invited_group->members[x]->CastToClient(); - else - continue; - - raid->SendRaidCreate(b_owner); - raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); - raid->AddMember(c, 0, true, true, true); - raid->SendBulkRaid(b_owner); - - if (raid->IsLocked()) { - raid->SendRaidLockTo(b_owner); - } - } - else - { - Client* c = nullptr; - if (player_invited_group->members[x]->IsClient() || player_invited_group->members[x]->IsBot()) - c = player_invited_group->members[x]->CastToClient(); - else - continue; - - raid->SendRaidCreate(b_owner); - raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); - raid->AddMember(c, 0); - raid->SendBulkRaid(b_owner); - if (raid->IsLocked()) { - raid->SendRaidLockTo(b_owner); - } - } - } + Client* client_to_add = nullptr; + /* Add client to an existing group */ + for (int x = 0; x < 6; x++) { + if (group->members[x]) { + if (!client_to_add) { + if (group->members[x]->IsClient() || group->members[x]->IsBot()) { + client_to_add = group->members[x]->CastToClient(); + raid->SetGroupLeader(client_to_add->GetName()); } + } + if (group->IsLeader(group->members[x])) { + Client* c = nullptr; + + if (group->members[x]->IsClient() || group->members[x]->IsClient()) + c = group->members[x]->CastToClient(); + else + continue; + raid->SendRaidCreate(b_owner); raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); + raid->AddMember(c, raid_free_group_id, false, true); raid->SendBulkRaid(b_owner); - player_invited_group->JoinRaidXTarget(raid, true); - raid->AddMember(b_owner); - player_invited_group->DisbandGroup(true); - raid->GroupUpdate(0); + if (raid->IsLocked()) { raid->SendRaidLockTo(b_owner); } } -//Usecase #2 - Neither the invitor and Bot has a group. - else { // neither has a group - Jan 6 this appears to work now. One ungrouped player, one/many ungrouped bots + else + { + Client* c = nullptr; + + if (group->members[x]->IsClient() || group->members[x]->IsBot()) + c = group->members[x]->CastToClient(); + else + continue; + + raid->SendRaidCreate(b_owner); + raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); + raid->AddMember(c, raid_free_group_id); + raid->SendBulkRaid(b_owner); + + if (raid->IsLocked()) { + raid->SendRaidLockTo(b_owner); + } + } + } + } + group->JoinRaidXTarget(raid); + group->DisbandGroup(true); + + raid->GroupUpdate(raid_free_group_id); + } + /* Target does not have a group */ +//No raid and bot owner does not have group. Now check for bot having a group + else { + if (player_invited_group) { + // No raid, No bot owner group, bot has group + raid = new Raid(b_owner); + entity_list.AddRaid(raid); + raid->SetRaidDetails(); + raid->SendRaidCreate(b_owner); + raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); + raid->AddMember(b_owner, 0xFFFFFFFF, true, false, true); + + for (int x = 0; x < 6; x++) { + if (player_invited_group->members[x]) { + Client* c = nullptr; + Bot* b = nullptr; + if (player_invited_group->members[x]->IsBot()) { + b = player_invited_group->members[x]->CastToBot(); + if (x == 0) { + raid->AddBot(b, 0, false, true, false); + raid->SetGroupLeader(b->GetName()); + } + else { + raid->AddBot(b, 0, false, false, false); + } + } + else if (group->members[x]->IsClient()) { + c = group->members[x]->CastToClient(); + if (x == 0) { + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); + raid->AddMember(c, 0, false, true, false); + raid->SetGroupLeader(c->GetName()); + } + else { + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); + raid->AddMember(c, 0, false, false, false); + } + } + } + } + player_invited_group->JoinRaidXTarget(raid, true); + player_invited_group->DisbandGroup(true); + raid->GroupUpdate(0); + if (raid->IsLocked()) { + raid->SendRaidLockTo(b_owner); + } + } +//Usecase #2 - No raid, no bot owner group, no bot group. Working + else { raid = new Raid(b_owner); entity_list.AddRaid(raid); raid->SetRaidDetails(); -// raid->SendRaidCreate(b_owner); // Not needed as one raid member is a bot raid->SendRaidCreate(b_owner); raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); raid->AddMember(b_owner, 0xFFFFFFFF, true, false, true); raid->AddBot(player_accepting_invite); -// raid->SendBulkRaid(b_owner); //Removed to correct usecase #2 - if (raid->IsLocked()) { raid->SendRaidLockTo(b_owner); } diff --git a/zone/raids.cpp b/zone/raids.cpp index 575afadda..dcec202e2 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -190,11 +190,11 @@ void Raid::AddBot(Bot* b, uint32 group, bool rleader, bool groupleader, bool loo database.SetRaidGroupLeaderInfo(group, GetID()); //UpdateGroupAAs(group); } - if (group < 12) - GroupUpdate(group); - else // get raid AAs, GroupUpdate will handles it otherwise +// if (group < 12) +// GroupUpdate(group); +// else // get raid AAs, GroupUpdate will handles it otherwise //SendGroupLeadershipAA(c, RAID_GROUPLESS); Is this needed for bots? - SendRaidAddAll(b->GetName()); + SendRaidAddAll(b->GetName()); members[GetPlayerIndex(b->GetName())].SentToBotOwner = true; //Mitch indicates that the BotOwner has received this raid info already. b->SetRaidGrouped(true); @@ -1076,7 +1076,7 @@ void Raid::SendRaidAdd(const char *who, Client *to) for(int x = 0; x < MAX_RAID_MEMBERS; x++) { - if(strcmp(members[x].membername, who) == 0 || !members[x].SentToBotOwner) //Mitch + if(strcmp(members[x].membername, who) == 0)// || !members[x].SentToBotOwner) //Mitch { auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidAddMember_Struct)); RaidAddMember_Struct *ram = (RaidAddMember_Struct*)outapp->pBuffer; From 8fc3ac1e504464a08723d82c7d313414543a2f61 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Sat, 8 Jan 2022 10:06:36 -0400 Subject: [PATCH 15/55] Work on usecase 5 --- zone/bot.cpp | 15 +++++++++++---- zone/client_packet.cpp | 24 +++++++++++++++++++++++- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index d1b1ec6f9..fae13abe9 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -10119,6 +10119,7 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { } } //Usecase #3 - Raid already created, Bot is BotGroupLeader. + //UseCase #5 - Raid already created, Client is groupleader with at least one Bot in group if (group) {//add us all // Is the player already in a group? If yes, add all players from the group uint32 free_group_id = raid->GetFreeGroup(); Client* addClient = nullptr; @@ -10189,14 +10190,20 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { } } } - //No raid exists. +// No raid exists at this point +// Usecase #1 - Client invites another client. No groups involved. Handled by Raid Accept Invite routine +// Usecase #2 - Client invites their own bot. No groups involved. Handled here. +// Usecase #4 - Client invites their own bot to a group then to raid. Handled here. +// Usecase #5 - Client invites another client that is in a group with their own bot. Handled here. +// Usecase #6 - Client with a bot in a group invites another client that is in a group with their own bot. Handled here. else - { // A raid does not already exist. One needs to be created before going forward + { Group* player_invited_group = player_accepting_invite->GetGroup(); Group* group = entity_list.GetGroupByClient(b_owner); // player_accepting_invite->GetGroup(); - if (group) //if our target has a group + if (group) +// No raid. Invited member (Bot Owner) has a group. Member inviting does not have a group +// Usecase #5 { - // raid = new Raid(player_accepting_invite); raid = new Raid(b_owner); entity_list.AddRaid(raid); raid->SetRaidDetails(); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index e06610fbb..6f036e096 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -11326,7 +11326,9 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) #ifdef BOTS Bot* player_to_invite = nullptr; Client* player_to_invite_owner = nullptr; - if (entity_list.GetBotByBotName(raid_command_packet->player_name)) { + + + if (entity_list.GetBotByBotName(raid_command_packet->player_name) ) { Bot* player_to_invite = entity_list.GetBotByBotName(raid_command_packet->player_name); Client* player_to_invite_owner = player_to_invite->GetOwner()->CastToClient(); @@ -11352,6 +11354,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) } Bot::ProcessRaidInvite(player_to_invite, player_to_invite_owner); + break; } else { @@ -11378,6 +11381,25 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) break; } +// bool player_accepting_invite_has_bots_in_group = false; + Bot* b = nullptr; + Group* g = player_to_invite->GetGroup(); + if (player_to_invite->HasGroup() && g->IsLeader(player_to_invite)) + { + for (int x = 0; x < 6; x++) + { + if (g->members[x]->IsBot()) + { + b = entity_list.GetBotByBotName(g->members[x]->GetName()); +// player_accepting_invite_has_bots_in_group = true; + break; + } + } + Bot::ProcessRaidInvite(b, player_to_invite); + break; + } + + /* Send out invite to the client */ auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); RaidGeneral_Struct* raid_command = (RaidGeneral_Struct*)outapp->pBuffer; From 1c57e5b8982c170b50dfd4ae8cbe609740043df9 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Sat, 8 Jan 2022 20:39:47 -0400 Subject: [PATCH 16/55] A few more use cases working --- zone/bot.cpp | 78 ++++++++++++++++++++++++++---------------- zone/client_packet.cpp | 53 ++++++++++++++++------------ 2 files changed, 80 insertions(+), 51 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index fae13abe9..d87c91a75 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -10095,7 +10095,6 @@ void Bot::StopMoving(float new_heading) uint8 Bot::spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND] = { 0 }; void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { - //Client* player_accepting_invite = entity_list.GetClientByName(raid_command_packet->player_name); if (player_accepting_invite) { if (player_accepting_invite->IsRaidGrouped()) { @@ -10103,9 +10102,12 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { return; } Raid* raid = entity_list.GetRaidByClient(b_owner); - if (raid) { // Does a raid already exist? + +// Check to see if a raid already exists. + if (raid) { raid->VerifyRaid(); Group* group = player_accepting_invite->GetGroup(); +// A few checks here. If player is in a group, is there room for another group. If not in a group, is there room for one more player. if (group) { if (group->GroupCount() + raid->RaidCount() > MAX_RAID_MEMBERS) { b_owner->Message(Chat::Red, "Invite failed, bot group invite would create a raid larger than the maximum number of members allowed."); @@ -10118,8 +10120,9 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { return; } } - //Usecase #3 - Raid already created, Bot is BotGroupLeader. - //UseCase #5 - Raid already created, Client is groupleader with at least one Bot in group + +//Usecase #3 - Raid already created, Bot is BotGroupLeader. +//UseCase #5 - Raid already created, Client is groupleader with at least one Bot in group if (group) {//add us all // Is the player already in a group? If yes, add all players from the group uint32 free_group_id = raid->GetFreeGroup(); Client* addClient = nullptr; @@ -10190,6 +10193,7 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { } } } + // No raid exists at this point // Usecase #1 - Client invites another client. No groups involved. Handled by Raid Accept Invite routine // Usecase #2 - Client invites their own bot. No groups involved. Handled here. @@ -10198,20 +10202,32 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { // Usecase #6 - Client with a bot in a group invites another client that is in a group with their own bot. Handled here. else { +// No raid at this point. +// Several usecases here. +// 1. Inviting Client does not have a group, invited player is a single client +// 2. Inviting Client does not have a group, invited player is a single bot that they own +// 3. Inviting Client does not have a group, invited player is a single bot that they do not own +// 4. Inviting Client does not have a group, invited player is a single bot in a group of other bots +// 5. Inviting Client does not have a group, invited player is a single bot in a group of other mixed players and bots +// 6. Inviting Client does not have a group, invited player is a single client in a group of other players only +// 7. Inviting Client does not have a group, invited player is a single client in a group of bots only +// 8. Inviting Client does not have a group, invited player is a single client in a group of mixed players and bots + Group* player_invited_group = player_accepting_invite->GetGroup(); Group* group = entity_list.GetGroupByClient(b_owner); // player_accepting_invite->GetGroup(); +// No raid. Check to see if Inviting client has a group? if (group) -// No raid. Invited member (Bot Owner) has a group. Member inviting does not have a group -// Usecase #5 +// No raid. Inviting client has a group. { raid = new Raid(b_owner); entity_list.AddRaid(raid); raid->SetRaidDetails(); uint32 raid_free_group_id = raid->GetFreeGroup(); - - /* If we already have a group then cycle through adding us... */ + +// No raid. Inviting client has a group. Check to see if invited player has a group? if (player_invited_group) { +// No raid. Inviting client has a group. Invited client has a group. Client* client_to_be_leader = nullptr; for (int x = 0; x < 6; x++) { if (player_invited_group->members[x]) { @@ -10262,6 +10278,7 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { raid->GroupUpdate(raid_free_group_id); raid_free_group_id = raid->GetFreeGroup(); } + // No raid. Inviting client has a group. Invited client DOES NOT HAVE a group. else { // raid->SendRaidCreate(player_accepting_invite); // raid->AddMember(player_accepting_invite, 0xFFFFFFFF, true, false, true); @@ -10321,17 +10338,16 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { raid->GroupUpdate(raid_free_group_id); } - /* Target does not have a group */ -//No raid and bot owner does not have group. Now check for bot having a group else { if (player_invited_group) { - // No raid, No bot owner group, bot has group +// No raid. Inviting client DOES NOT HAVE a group. Invited client has a group. +// Usecase 4 - No raid, no inviter group, bot in a group of bots +// Usecase 5 - No raid, no inviter group, bot in a group of mixed players and bots +// Usecase 7 - No raid, no inviter group, client in a group of bots +// Usecase 8 - No raid, no inviter group, client in a group of mixed players and bots raid = new Raid(b_owner); entity_list.AddRaid(raid); raid->SetRaidDetails(); - raid->SendRaidCreate(b_owner); - raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); - raid->AddMember(b_owner, 0xFFFFFFFF, true, false, true); for (int x = 0; x < 6; x++) { if (player_invited_group->members[x]) { @@ -10347,8 +10363,8 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { raid->AddBot(b, 0, false, false, false); } } - else if (group->members[x]->IsClient()) { - c = group->members[x]->CastToClient(); + else if (player_invited_group->members[x]->IsClient()) { + c = player_invited_group->members[x]->CastToClient(); if (x == 0) { raid->SendRaidCreate(c); raid->SendMakeLeaderPacketTo(raid->leadername, c); @@ -10363,6 +10379,10 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { } } } + raid->SendRaidCreate(b_owner); + raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); + raid->SendBulkRaid(b_owner); + raid->AddMember(b_owner, 0xFFFFFFFF, true, false, true); player_invited_group->JoinRaidXTarget(raid, true); player_invited_group->DisbandGroup(true); raid->GroupUpdate(0); @@ -10370,22 +10390,22 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { raid->SendRaidLockTo(b_owner); } } -//Usecase #2 - No raid, no bot owner group, no bot group. Working - else { - raid = new Raid(b_owner); - entity_list.AddRaid(raid); - raid->SetRaidDetails(); - raid->SendRaidCreate(b_owner); - raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); - raid->AddMember(b_owner, 0xFFFFFFFF, true, false, true); - raid->AddBot(player_accepting_invite); - if (raid->IsLocked()) { - raid->SendRaidLockTo(b_owner); - } - } +// No raid. Inviting client DOES NOT HAVE a group. Invited client DOES NOT HAVE a group. Working? + else { + raid = new Raid(b_owner); + entity_list.AddRaid(raid); + raid->SetRaidDetails(); + raid->SendRaidCreate(b_owner); + raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); + raid->AddMember(b_owner, 0xFFFFFFFF, true, false, true); + raid->AddBot(player_accepting_invite); + if (raid->IsLocked()) { + raid->SendRaidLockTo(b_owner); } } } } + } +} #endif diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 6f036e096..9f34798cc 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -11326,6 +11326,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) #ifdef BOTS Bot* player_to_invite = nullptr; Client* player_to_invite_owner = nullptr; + + if (entity_list.GetBotByBotName(raid_command_packet->player_name) ) { @@ -11337,17 +11339,22 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) } Group* player_to_invite_group = player_to_invite->GetGroup(); + // Not allowed: Invite a bot that is not owned by the inviter and is not in a group. They could be in a group with their owner! + if (player_to_invite->GetOwnerID() != player_to_invite_owner->CharacterID() && !player_to_invite_group) { + Message(Chat::Red, "%s is not grouped and not your Bot. You can only invite your Bots, or Bots grouped with others.", player_to_invite->GetName()); + } + //Not allowed: Invite a bot that is already within a raid. if (player_to_invite->HasRaid()) { Message(Chat::Red, "%s is already in a raid.", player_to_invite->GetName()); break; } - + // Not allowed: Invite a bot that is in a group that is already a member if (player_to_invite_group && player_to_invite_group->IsGroupMember(this)) { MessageString(Chat::Red, ALREADY_IN_PARTY); break; } - + // Not allowed: Invite a bot that is in a group but not the groupleader if (player_to_invite_group && !player_to_invite_group->IsLeader(player_to_invite)) { Message(Chat::Red, "You can only invite an ungrouped player or group leader to join your raid."); break; @@ -11375,31 +11382,12 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) MessageString(Chat::Red, ALREADY_IN_PARTY); break; } - + // Not allowed: Invite a client that is in a group but not the groupleader if (player_to_invite_group && !player_to_invite_group->IsLeader(player_to_invite)) { Message(Chat::Red, "You can only invite an ungrouped player or group leader to join your raid."); break; } -// bool player_accepting_invite_has_bots_in_group = false; - Bot* b = nullptr; - Group* g = player_to_invite->GetGroup(); - if (player_to_invite->HasGroup() && g->IsLeader(player_to_invite)) - { - for (int x = 0; x < 6; x++) - { - if (g->members[x]->IsBot()) - { - b = entity_list.GetBotByBotName(g->members[x]->GetName()); -// player_accepting_invite_has_bots_in_group = true; - break; - } - } - Bot::ProcessRaidInvite(b, player_to_invite); - break; - } - - /* Send out invite to the client */ auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); RaidGeneral_Struct* raid_command = (RaidGeneral_Struct*)outapp->pBuffer; @@ -11421,6 +11409,27 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) case RaidCommandAcceptInvite: { Client *player_accepting_invite = entity_list.GetClientByName(raid_command_packet->player_name); + +#ifdef BOTS + // If the accepting client is in a group with a Bot, send the invite to Bot:ProcessRaidInvite + // instead of remaining here. + Bot* b = nullptr; + Client* c = entity_list.GetClientByName(raid_command_packet->leader_name); + Group* g = c->GetGroup(); + if (c->HasGroup() && g->IsLeader(c)) + { + for (int x = 0; x < 6; x++) + { + if (g->members[x]->IsBot()) + { + b = entity_list.GetBotByBotName(g->members[x]->GetName()); + break; + } + } + Bot::ProcessRaidInvite(b, player_accepting_invite); + break; + } +#endif if (player_accepting_invite) { if (IsRaidGrouped()) { player_accepting_invite->MessageString(Chat::White, ALREADY_IN_RAID, GetName()); //group failed, must invite members not in raid... From e5371253cbc65ef499418debe84845511903c9ab Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Sun, 9 Jan 2022 11:24:59 -0400 Subject: [PATCH 17/55] New work on Raid invite with a invitor having a group --- zone/bot.cpp | 73 +++++++++++++++++++++++++++++++++++------- zone/bot.h | 1 + zone/client_packet.cpp | 28 ++++++++++++---- 3 files changed, 83 insertions(+), 19 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index d87c91a75..dd9520e24 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -10094,8 +10094,56 @@ void Bot::StopMoving(float new_heading) uint8 Bot::spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND] = { 0 }; +void Bot::ProcessRaidInvite2(Client* invitee, Client* invitor) { + + Raid* raid = entity_list.GetRaidByClient(invitor); + Group* g_invitee = invitee->GetGroup(); + Group* g_invitor = invitor->GetGroup(); + + if (raid) + { + if (g_invitee) + { + //As there is already a raid, just add this group + } + else + { + //As there is already a raid and no group, just add this single client + } + } + else + { + //As there is no raid + //First, create the raid + if (g_invitor) + { + //Second, add the invitor group + if (g_invitee) + { + //Third, add the invitee group + } + else + { + //Third, no group so add the single client + } + } + else + { + //Second, add the single invitor + if (g_invitee) + { + //Third, add the invitee group + } + else + { + //Third, no group so add the single client + } + } + } +} + void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { - + if (player_accepting_invite) { if (player_accepting_invite->IsRaidGrouped()) { b_owner->MessageString(Chat::White, ALREADY_IN_RAID, player_accepting_invite->GetName()); //group failed, must invite members not in raid... @@ -10123,7 +10171,7 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { //Usecase #3 - Raid already created, Bot is BotGroupLeader. //UseCase #5 - Raid already created, Client is groupleader with at least one Bot in group - if (group) {//add us all // Is the player already in a group? If yes, add all players from the group + if (group) { uint32 free_group_id = raid->GetFreeGroup(); Client* addClient = nullptr; Bot* addBot = nullptr; @@ -10204,15 +10252,15 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { { // No raid at this point. // Several usecases here. -// 1. Inviting Client does not have a group, invited player is a single client -// 2. Inviting Client does not have a group, invited player is a single bot that they own -// 3. Inviting Client does not have a group, invited player is a single bot that they do not own -// 4. Inviting Client does not have a group, invited player is a single bot in a group of other bots -// 5. Inviting Client does not have a group, invited player is a single bot in a group of other mixed players and bots -// 6. Inviting Client does not have a group, invited player is a single client in a group of other players only -// 7. Inviting Client does not have a group, invited player is a single client in a group of bots only -// 8. Inviting Client does not have a group, invited player is a single client in a group of mixed players and bots - +// Working from raids.cpp 1. Inviting Client does not have a group, invited player is a single client +// Working 2. Inviting Client does not have a group, invited player is a single bot that they own +// Working 3. Inviting Client does not have a group, invited player is a single bot that they do not own +// Working 4. Inviting Client does not have a group, invited player is a single bot in a group of other bots +// Working 5. Inviting Client does not have a group, invited player is a single bot in a group of other mixed players and bots +// Working from raids.cpp 6. Inviting Client does not have a group, invited player is a single client in a group of other players only +// Working 7. Inviting Client does not have a group, invited player is a single client in a group of bots only +// Working 8. Inviting Client does not have a group, invited player is a single client in a group of mixed players and bots + Group* player_invited_group = player_accepting_invite->GetGroup(); Group* group = entity_list.GetGroupByClient(b_owner); // player_accepting_invite->GetGroup(); // No raid. Check to see if Inviting client has a group? @@ -10390,7 +10438,8 @@ void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { raid->SendRaidLockTo(b_owner); } } -// No raid. Inviting client DOES NOT HAVE a group. Invited client DOES NOT HAVE a group. Working? +// 2. Inviting Client does not have a group, invited player is a single bot that they own +// 3. Inviting Client does not have a group, invited player is a single bot that they do not own else { raid = new Raid(b_owner); entity_list.AddRaid(raid); diff --git a/zone/bot.h b/zone/bot.h index eb82a253e..dc5f8e091 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -363,6 +363,7 @@ public: static bool IsBotAttackAllowed(Mob* attacker, Mob* target, bool& hasRuleDefined); static Bot* GetBotByBotClientOwnerAndBotName(Client* c, std::string botName); static void ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner); //Mitch + static void ProcessRaidInvite2(Client* invitee, Client* invitor); //Mitch static void ProcessBotGroupInvite(Client* c, std::string botName); static void ProcessBotGroupDisband(Client* c, std::string botName); static void BotOrderCampAll(Client* c); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 9f34798cc..a062c89ae 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -11414,20 +11414,34 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) // If the accepting client is in a group with a Bot, send the invite to Bot:ProcessRaidInvite // instead of remaining here. Bot* b = nullptr; - Client* c = entity_list.GetClientByName(raid_command_packet->leader_name); - Group* g = c->GetGroup(); - if (c->HasGroup() && g->IsLeader(c)) + Client* invitee = entity_list.GetClientByName(raid_command_packet->leader_name); + Client* invitor = entity_list.GetClientByName(raid_command_packet->player_name); + Group* g_invitee = invitee->GetGroup(); + Group* g_invitor = invitor->GetGroup(); + + if (invitee->HasGroup() && g_invitee->IsLeader(invitee)) { for (int x = 0; x < 6; x++) { - if (g->members[x]->IsBot()) + if (g_invitee->members[x]->IsBot()) { - b = entity_list.GetBotByBotName(g->members[x]->GetName()); + b = entity_list.GetBotByBotName(g_invitee->members[x]->GetName()); + Bot::ProcessRaidInvite(b, player_accepting_invite); + break; + } + } + } + if (invitee && invitor->HasGroup() && g_invitor->IsLeader(invitor)) + { + for (int x = 0; x < 6; x++) + { + if (g_invitor->members[x]->IsBot()) + { + b = entity_list.GetBotByBotName(g_invitor->members[x]->GetName()); + Bot::ProcessRaidInvite2(player_accepting_invite); break; } } - Bot::ProcessRaidInvite(b, player_accepting_invite); - break; } #endif if (player_accepting_invite) { From c9480ad08059f2a2877983ee739129791180354c Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Mon, 10 Jan 2022 12:00:31 -0400 Subject: [PATCH 18/55] Bot Raid inviting working for all use cases --- zone/bot.cpp | 686 ++++++++++++++++++++++++----------------- zone/client_packet.cpp | 46 +-- 2 files changed, 438 insertions(+), 294 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index dd9520e24..b09834fd4 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -10105,353 +10105,487 @@ void Bot::ProcessRaidInvite2(Client* invitee, Client* invitor) { if (g_invitee) { //As there is already a raid, just add this group + raid->SendBulkRaid(invitee); + uint32 raid_free_group_id = raid->GetFreeGroup(); + for (int x = 0; x < 6; x++) { + if (g_invitee->members[x]) { + Client* c = nullptr; + Bot* b = nullptr; + if (g_invitee->members[x] && g_invitee->members[x]->IsBot()) { + b = g_invitee->members[x]->CastToBot(); + if (x == 0) { + raid->AddBot(b, raid_free_group_id, false, true, false); + raid->SetGroupLeader(b->GetName()); + } + else { + raid->AddBot(b, raid_free_group_id, false, false, false); + } + } + else if (g_invitee->members[x] && g_invitee->members[x]->IsClient()) { + c = g_invitee->members[x]->CastToClient(); + if (x == 0) { + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); + raid->AddMember(c, raid_free_group_id, false, true, false); + raid->SetGroupLeader(c->GetName()); + if (raid->IsLocked()) { + raid->SendRaidLockTo(c); + } + } + else { + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); + raid->AddMember(c, raid_free_group_id, false, false, false); + if (raid->IsLocked()) { + raid->SendRaidLockTo(c); + } + } + } + } + } +// raid->SendBulkRaid(invitor); //Send a raid updates to the invitor + g_invitee->JoinRaidXTarget(raid, true); + g_invitee->DisbandGroup(true); + if (raid->IsLocked()) { + raid->SendRaidLockTo(invitor); + } } else { //As there is already a raid and no group, just add this single client + raid->SendRaidCreate(invitee); + raid->SendMakeLeaderPacketTo(raid->leadername, invitee); + raid->AddMember(invitee); + if (raid->IsLocked()) { + raid->SendRaidLockTo(invitee); + } } } else { //As there is no raid //First, create the raid + raid = new Raid(invitor); + entity_list.AddRaid(raid); + raid->SetRaidDetails(); + if (g_invitor) { - //Second, add the invitor group + //Second, add the invitor group as group 0 + for (int x = 0; x < 6; x++) { + if (g_invitor->members[x]) { + Client* c = nullptr; + Bot* b = nullptr; + if (g_invitor->members[x] && g_invitor->members[x]->IsBot()) { + b = g_invitor->members[x]->CastToBot(); + if (x == 0) { + raid->AddBot(b, 0, false, true, false); + raid->SetGroupLeader(b->GetName()); + } + else { + raid->AddBot(b, 0, false, false, false); + } + } + else if (g_invitor->members[x] && g_invitor->members[x]->IsClient()) { + c = g_invitor->members[x]->CastToClient(); + if (x == 0) { + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); + raid->AddMember(c, 0, false, true, false); + raid->SetGroupLeader(c->GetName()); + if (raid->IsLocked()) { + raid->SendRaidLockTo(c); + } + } + else { + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); + raid->AddMember(c, 0, false, false, false); + if (raid->IsLocked()) { + raid->SendRaidLockTo(c); + } + } + } + } + } + raid->SendBulkRaid(invitee); //Send a raid updates to the invitor + g_invitor->JoinRaidXTarget(raid, true); + g_invitor->DisbandGroup(true); + if (raid->IsLocked()) { + raid->SendRaidLockTo(invitor); + } if (g_invitee) { //Third, add the invitee group + uint32 raid_free_group_id = raid->GetFreeGroup(); + for (int x = 0; x < 6; x++) { + if (g_invitee->members[x]) { + Client* c = nullptr; + Bot* b = nullptr; + if (g_invitee->members[x] && g_invitee->members[x]->IsBot()) { + b = g_invitee->members[x]->CastToBot(); + if (x == 0) { + raid->AddBot(b, raid_free_group_id, false, true, false); + raid->SetGroupLeader(b->GetName()); + } + else { + raid->AddBot(b, raid_free_group_id, false, false, false); + } + } + else if (g_invitee->members[x] && g_invitee->members[x]->IsClient()) { + c = g_invitee->members[x]->CastToClient(); + if (x == 0) { + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); + raid->AddMember(c, raid_free_group_id, false, true, false); + raid->SetGroupLeader(c->GetName()); + if (raid->IsLocked()) { + raid->SendRaidLockTo(c); + } + } + else { + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); + raid->AddMember(c, raid_free_group_id, false, false, false); + if (raid->IsLocked()) { + raid->SendRaidLockTo(c); + } + } + } + } + } +// raid->SendBulkRaid(invitee); //Send a raid updates to the invitee + g_invitee->JoinRaidXTarget(raid, true); + g_invitee->DisbandGroup(true); + if (raid->IsLocked()) { + raid->SendRaidLockTo(invitor); + } } else { //Third, no group so add the single client + raid->SendRaidCreate(invitee); + raid->SendMakeLeaderPacketTo(raid->leadername, invitee); + raid->AddMember(invitee); +// raid->SendBulkRaid(invitee); + if (raid->IsLocked()) { + raid->SendRaidLockTo(invitee); + } } } else { //Second, add the single invitor + raid->SendRaidCreate(invitor); + raid->SendMakeLeaderPacketTo(raid->leadername, invitor); + raid->AddMember(invitor, 0xFFFFFFFF, true, false, true); + raid->SendBulkRaid(invitee); //Send a raid updates to the invitee + if (raid->IsLocked()) { + raid->SendRaidLockTo(invitor); + } if (g_invitee) { //Third, add the invitee group + uint32 raid_free_group_id = raid->GetFreeGroup(); + for (int x = 0; x < 6; x++) { + if (g_invitee->members[x]) { + Client* c = nullptr; + Bot* b = nullptr; + if (g_invitee->members[x] && g_invitee->members[x]->IsBot()) { + b = g_invitee->members[x]->CastToBot(); + if (x == 0) { + raid->AddBot(b, raid_free_group_id, false, true, false); + raid->SetGroupLeader(b->GetName()); + } + else { + raid->AddBot(b, raid_free_group_id, false, false, false); + } + } + else if (g_invitee->members[x] && g_invitee->members[x]->IsClient()) { + c = g_invitee->members[x]->CastToClient(); + if (x == 0) { + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); + raid->AddMember(c, raid_free_group_id, false, true, false); + raid->SetGroupLeader(c->GetName()); + if (raid->IsLocked()) { + raid->SendRaidLockTo(c); + } + } + else { + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); + raid->AddMember(c, raid_free_group_id, false, false, false); + if (raid->IsLocked()) { + raid->SendRaidLockTo(c); + } + } + } + } + } + g_invitee->JoinRaidXTarget(raid, true); + g_invitee->DisbandGroup(true); + if (raid->IsLocked()) { + raid->SendRaidLockTo(invitor); + } } else { - //Third, no group so add the single client + //Third, no group so add the single client invitee + raid->SendRaidCreate(invitee); + raid->SendMakeLeaderPacketTo(raid->leadername, invitee); + raid->AddMember(invitee); + if (raid->IsLocked()) { + raid->SendRaidLockTo(invitee); + } } } } } -void Bot::ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner) { - - if (player_accepting_invite) { - if (player_accepting_invite->IsRaidGrouped()) { - b_owner->MessageString(Chat::White, ALREADY_IN_RAID, player_accepting_invite->GetName()); //group failed, must invite members not in raid... - return; +void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { + + Raid* raid = entity_list.GetRaidByClient(invitor); + Group* g_invitee = invitee->GetGroup(); + Group* g_invitor = invitor->GetGroup(); + + if (raid) + { + if (g_invitee) + { + //As there is already a raid, just add this group + uint32 raid_free_group_id = raid->GetFreeGroup(); + for (int x = 0; x < 6; x++) { + if (g_invitee->members[x]) { + Client* c = nullptr; + Bot* b = nullptr; + if (g_invitee->members[x] && g_invitee->members[x]->IsBot()) { + b = g_invitee->members[x]->CastToBot(); + if (x == 0) { + raid->AddBot(b, raid_free_group_id, false, true, false); + raid->SetGroupLeader(b->GetName()); + } + else { + raid->AddBot(b, raid_free_group_id, false, false, false); + } + } + else if (g_invitee->members[x] && g_invitee->members[x]->IsClient()) { + c = g_invitee->members[x]->CastToClient(); + if (x == 0) { + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); + raid->AddMember(c, raid_free_group_id, false, true, false); + raid->SetGroupLeader(c->GetName()); + if (raid->IsLocked()) { + raid->SendRaidLockTo(c); + } + } + else { + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); + raid->AddMember(c, raid_free_group_id, false, false, false); + if (raid->IsLocked()) { + raid->SendRaidLockTo(c); + } + } + } + } + } + // raid->SendBulkRaid(invitor); //Send a raid updates to the invitor + g_invitee->JoinRaidXTarget(raid, true); + g_invitee->DisbandGroup(true); + if (raid->IsLocked()) { + raid->SendRaidLockTo(invitor); + } } - Raid* raid = entity_list.GetRaidByClient(b_owner); + else + { + //As there is already a raid and no group, just add this single client + //raid->SendRaidCreate(invitee); + //raid->SendMakeLeaderPacketTo(raid->leadername, invitee); + raid->AddBot(invitee); + //if (raid->IsLocked()) { + // raid->SendRaidLockTo(invitee); + //} + } + } + else + { + //As there is no raid + //First, create the raid + raid = new Raid(invitor); + entity_list.AddRaid(raid); + raid->SetRaidDetails(); -// Check to see if a raid already exists. - if (raid) { - raid->VerifyRaid(); - Group* group = player_accepting_invite->GetGroup(); -// A few checks here. If player is in a group, is there room for another group. If not in a group, is there room for one more player. - if (group) { - if (group->GroupCount() + raid->RaidCount() > MAX_RAID_MEMBERS) { - b_owner->Message(Chat::Red, "Invite failed, bot group invite would create a raid larger than the maximum number of members allowed."); - return; + if (g_invitor) + { + //Second, add the invitor group as group 0 + for (int x = 0; x < 6; x++) { + if (g_invitor->members[x]) { + Client* c = nullptr; + Bot* b = nullptr; + if (g_invitor->members[x] && g_invitor->members[x]->IsBot()) { + b = g_invitor->members[x]->CastToBot(); + if (x == 0) { + raid->AddBot(b, 0, false, true, false); + raid->SetGroupLeader(b->GetName()); + } + else { + raid->AddBot(b, 0, false, false, false); + } + } + else if (g_invitor->members[x] && g_invitor->members[x]->IsClient()) { + c = g_invitor->members[x]->CastToClient(); + if (x == 0) { + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); + raid->AddMember(c, 0, false, true, false); + raid->SetGroupLeader(c->GetName()); + if (raid->IsLocked()) { + raid->SendRaidLockTo(c); + } + } + else { + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); + raid->AddMember(c, 0, false, false, false); + if (raid->IsLocked()) { + raid->SendRaidLockTo(c); + } + } + } } } - else { - if (1 + raid->RaidCount() > MAX_RAID_MEMBERS) { - b_owner->Message(Chat::Red, "Invite failed, bot invite would create a raid larger than the maximum number of members allowed."); - return; - } +// raid->SendBulkRaid(invitee); //Send a raid updates to the invitor + g_invitor->JoinRaidXTarget(raid, true); + g_invitor->DisbandGroup(true); + if (raid->IsLocked()) { + raid->SendRaidLockTo(invitor); } - -//Usecase #3 - Raid already created, Bot is BotGroupLeader. -//UseCase #5 - Raid already created, Client is groupleader with at least one Bot in group - if (group) { - uint32 free_group_id = raid->GetFreeGroup(); - Client* addClient = nullptr; - Bot* addBot = nullptr; - + if (g_invitee) + { + //Third, add the invitee group + uint32 raid_free_group_id = raid->GetFreeGroup(); for (int x = 0; x < 6; x++) { - if (group->members[x]) { + if (g_invitee->members[x]) { Client* c = nullptr; Bot* b = nullptr; - if (group->members[x]->IsBot()) { - b = group->members[x]->CastToBot(); + if (g_invitee->members[x] && g_invitee->members[x]->IsBot()) { + b = g_invitee->members[x]->CastToBot(); if (x == 0) { - raid->AddBot(b, free_group_id, false, true, false); + raid->AddBot(b, raid_free_group_id, false, true, false); raid->SetGroupLeader(b->GetName()); } else { - raid->AddBot(b, free_group_id, false, false, false); + raid->AddBot(b, raid_free_group_id, false, false, false); } - raid->SendBulkRaid(b->CastToClient()); } - else if (group->members[x]->IsClient()) { - c = group->members[x]->CastToClient(); + else if (g_invitee->members[x] && g_invitee->members[x]->IsClient()) { + c = g_invitee->members[x]->CastToClient(); if (x == 0) { raid->SendRaidCreate(c); raid->SendMakeLeaderPacketTo(raid->leadername, c); - raid->AddMember(c, free_group_id, false, true, false); + raid->AddMember(c, raid_free_group_id, false, true, false); raid->SetGroupLeader(c->GetName()); + if (raid->IsLocked()) { + raid->SendRaidLockTo(c); + } } else { raid->SendRaidCreate(c); raid->SendMakeLeaderPacketTo(raid->leadername, c); - raid->AddMember(c, free_group_id, false, false, false); - } - raid->SendBulkRaid(c); - if (raid->IsLocked()) - raid->SendRaidLockTo(c); - } - - //if (!addClient) - //{ - // addClient = c; - // raid->SetGroupLeader(addClient->GetName()); - //} - - //raid->SendRaidCreate(b_owner); - //raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); - //if (group->IsLeader(group->members[x])) -// raid->AddMember(c, free_group_id, false, true); - // else - // raid->AddMember(c, free_group_id); - //raid->SendRaidGroupAdd(b_owner->GetName(), free_group_id); - - } - } - group->JoinRaidXTarget(raid); - group->DisbandGroup(true); - raid->GroupUpdate(free_group_id); - } - else { // Jan 6 this also now works. // If not in a group, invite the individual player - //raid->SendRaidCreate(b_owner); - //raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); - raid->AddBot(player_accepting_invite); - // Set indicator that bot owner has already received this update. Mitch - - //raid->SendBulkRaid(b_owner); - if (raid->IsLocked()) { - raid->SendRaidLockTo(b_owner); - } - } - } - -// No raid exists at this point -// Usecase #1 - Client invites another client. No groups involved. Handled by Raid Accept Invite routine -// Usecase #2 - Client invites their own bot. No groups involved. Handled here. -// Usecase #4 - Client invites their own bot to a group then to raid. Handled here. -// Usecase #5 - Client invites another client that is in a group with their own bot. Handled here. -// Usecase #6 - Client with a bot in a group invites another client that is in a group with their own bot. Handled here. - else - { -// No raid at this point. -// Several usecases here. -// Working from raids.cpp 1. Inviting Client does not have a group, invited player is a single client -// Working 2. Inviting Client does not have a group, invited player is a single bot that they own -// Working 3. Inviting Client does not have a group, invited player is a single bot that they do not own -// Working 4. Inviting Client does not have a group, invited player is a single bot in a group of other bots -// Working 5. Inviting Client does not have a group, invited player is a single bot in a group of other mixed players and bots -// Working from raids.cpp 6. Inviting Client does not have a group, invited player is a single client in a group of other players only -// Working 7. Inviting Client does not have a group, invited player is a single client in a group of bots only -// Working 8. Inviting Client does not have a group, invited player is a single client in a group of mixed players and bots - - Group* player_invited_group = player_accepting_invite->GetGroup(); - Group* group = entity_list.GetGroupByClient(b_owner); // player_accepting_invite->GetGroup(); -// No raid. Check to see if Inviting client has a group? - if (group) -// No raid. Inviting client has a group. - { - raid = new Raid(b_owner); - entity_list.AddRaid(raid); - raid->SetRaidDetails(); - - uint32 raid_free_group_id = raid->GetFreeGroup(); - -// No raid. Inviting client has a group. Check to see if invited player has a group? - if (player_invited_group) { -// No raid. Inviting client has a group. Invited client has a group. - Client* client_to_be_leader = nullptr; - for (int x = 0; x < 6; x++) { - if (player_invited_group->members[x]) { - if (!client_to_be_leader) { - if (player_invited_group->members[x]->IsClient()) { - client_to_be_leader = player_invited_group->members[x]->CastToClient(); - raid->SetGroupLeader(client_to_be_leader->GetName()); + raid->AddMember(c, raid_free_group_id, false, false, false); + if (raid->IsLocked()) { + raid->SendRaidLockTo(c); } } - if (player_invited_group->IsLeader(player_invited_group->members[x])) { - Client* c = nullptr; - - if (player_invited_group->members[x]->IsClient() || player_invited_group->members[x]->IsBot()) - c = player_invited_group->members[x]->CastToClient(); - else - continue; - - raid->SendRaidCreate(b_owner); - raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); - raid->AddMember(c, raid_free_group_id, true, true, true); - raid->SendBulkRaid(c); - + } + } + } + //raid->SendBulkRaid(invitor); //Send a raid updates to the invitor + g_invitee->JoinRaidXTarget(raid, true); + g_invitee->DisbandGroup(true); + if (raid->IsLocked()) { + raid->SendRaidLockTo(invitor); + } + } + else + { + //Third, no group so add the single client + //raid->SendRaidCreate(invitee); + //raid->SendMakeLeaderPacketTo(raid->leadername, invitee); + raid->AddBot(invitee); + // raid->SendBulkRaid(invitee); + //if (raid->IsLocked()) { + // raid->SendRaidLockTo(invitee); + //} + } + } + else + { + //Second, add the single invitor + raid->SendRaidCreate(invitor); + raid->SendMakeLeaderPacketTo(raid->leadername, invitor); + raid->AddMember(invitor, 0xFFFFFFFF, true, false, true); + if (raid->IsLocked()) { + raid->SendRaidLockTo(invitor); + } + if (g_invitee) + { + //Third, add the invitee group + uint32 raid_free_group_id = raid->GetFreeGroup(); + for (int x = 0; x < 6; x++) { + if (g_invitee->members[x]) { + Client* c = nullptr; + Bot* b = nullptr; + if (g_invitee->members[x] && g_invitee->members[x]->IsBot()) { + b = g_invitee->members[x]->CastToBot(); + if (x == 0) { + raid->AddBot(b, raid_free_group_id, false, true, false); + raid->SetGroupLeader(b->GetName()); + } + else { + raid->AddBot(b, raid_free_group_id, false, false, false); + } + } + else if (g_invitee->members[x] && g_invitee->members[x]->IsClient()) { + c = g_invitee->members[x]->CastToClient(); + if (x == 0) { + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); + raid->AddMember(c, raid_free_group_id, false, true, false); + raid->SetGroupLeader(c->GetName()); if (raid->IsLocked()) { - raid->SendRaidLockTo(b_owner); + raid->SendRaidLockTo(c); } } else { - Client* c = nullptr; - - if (player_invited_group->members[x]->IsClient() || player_invited_group->members[x]->IsBot()) - c = player_invited_group->members[x]->CastToClient(); - else - continue; - - raid->SendRaidCreate(b_owner); - raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); - raid->AddMember(c, raid_free_group_id); - raid->SendBulkRaid(b_owner); - + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); + raid->AddMember(c, raid_free_group_id, false, false, false); if (raid->IsLocked()) { - raid->SendRaidLockTo(b_owner); + raid->SendRaidLockTo(c); } } } } - player_invited_group->JoinRaidXTarget(raid, true); - player_invited_group->DisbandGroup(true); - raid->GroupUpdate(raid_free_group_id); - raid_free_group_id = raid->GetFreeGroup(); } - // No raid. Inviting client has a group. Invited client DOES NOT HAVE a group. - else { - // raid->SendRaidCreate(player_accepting_invite); - // raid->AddMember(player_accepting_invite, 0xFFFFFFFF, true, false, true); - raid->SendRaidCreate(b_owner); - raid->AddMember(b_owner, 0xFFFFFFFF, true, false, true); + // raid->SendBulkRaid(invitor); //Send a raid updates to the invitor + g_invitee->JoinRaidXTarget(raid, true); + g_invitee->DisbandGroup(true); + if (raid->IsLocked()) { + raid->SendRaidLockTo(invitor); } - - Client* client_to_add = nullptr; - /* Add client to an existing group */ - for (int x = 0; x < 6; x++) { - if (group->members[x]) { - if (!client_to_add) { - if (group->members[x]->IsClient() || group->members[x]->IsBot()) { - client_to_add = group->members[x]->CastToClient(); - raid->SetGroupLeader(client_to_add->GetName()); - } - } - if (group->IsLeader(group->members[x])) { - Client* c = nullptr; - - if (group->members[x]->IsClient() || group->members[x]->IsClient()) - c = group->members[x]->CastToClient(); - else - continue; - - raid->SendRaidCreate(b_owner); - raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); - raid->AddMember(c, raid_free_group_id, false, true); - raid->SendBulkRaid(b_owner); - - if (raid->IsLocked()) { - raid->SendRaidLockTo(b_owner); - } - } - else - { - Client* c = nullptr; - - if (group->members[x]->IsClient() || group->members[x]->IsBot()) - c = group->members[x]->CastToClient(); - else - continue; - - raid->SendRaidCreate(b_owner); - raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); - raid->AddMember(c, raid_free_group_id); - raid->SendBulkRaid(b_owner); - - if (raid->IsLocked()) { - raid->SendRaidLockTo(b_owner); - } - } - } - } - group->JoinRaidXTarget(raid); - group->DisbandGroup(true); - - raid->GroupUpdate(raid_free_group_id); } - else { - if (player_invited_group) { -// No raid. Inviting client DOES NOT HAVE a group. Invited client has a group. -// Usecase 4 - No raid, no inviter group, bot in a group of bots -// Usecase 5 - No raid, no inviter group, bot in a group of mixed players and bots -// Usecase 7 - No raid, no inviter group, client in a group of bots -// Usecase 8 - No raid, no inviter group, client in a group of mixed players and bots - raid = new Raid(b_owner); - entity_list.AddRaid(raid); - raid->SetRaidDetails(); - - for (int x = 0; x < 6; x++) { - if (player_invited_group->members[x]) { - Client* c = nullptr; - Bot* b = nullptr; - if (player_invited_group->members[x]->IsBot()) { - b = player_invited_group->members[x]->CastToBot(); - if (x == 0) { - raid->AddBot(b, 0, false, true, false); - raid->SetGroupLeader(b->GetName()); - } - else { - raid->AddBot(b, 0, false, false, false); - } - } - else if (player_invited_group->members[x]->IsClient()) { - c = player_invited_group->members[x]->CastToClient(); - if (x == 0) { - raid->SendRaidCreate(c); - raid->SendMakeLeaderPacketTo(raid->leadername, c); - raid->AddMember(c, 0, false, true, false); - raid->SetGroupLeader(c->GetName()); - } - else { - raid->SendRaidCreate(c); - raid->SendMakeLeaderPacketTo(raid->leadername, c); - raid->AddMember(c, 0, false, false, false); - } - } - } - } - raid->SendRaidCreate(b_owner); - raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); - raid->SendBulkRaid(b_owner); - raid->AddMember(b_owner, 0xFFFFFFFF, true, false, true); - player_invited_group->JoinRaidXTarget(raid, true); - player_invited_group->DisbandGroup(true); - raid->GroupUpdate(0); - if (raid->IsLocked()) { - raid->SendRaidLockTo(b_owner); - } - } -// 2. Inviting Client does not have a group, invited player is a single bot that they own -// 3. Inviting Client does not have a group, invited player is a single bot that they do not own - else { - raid = new Raid(b_owner); - entity_list.AddRaid(raid); - raid->SetRaidDetails(); - raid->SendRaidCreate(b_owner); - raid->SendMakeLeaderPacketTo(raid->leadername, b_owner); - raid->AddMember(b_owner, 0xFFFFFFFF, true, false, true); - raid->AddBot(player_accepting_invite); - if (raid->IsLocked()) { - raid->SendRaidLockTo(b_owner); - } - } + else + { + //Third, no group so add the single client invitee + //raid->SendRaidCreate(invitee); + //raid->SendMakeLeaderPacketTo(raid->leadername, invitee); + raid->AddBot(invitee); + //if (raid->IsLocked()) { + // raid->SendRaidLockTo(invitee); + //} } } } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index a062c89ae..60f2b9f1d 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -11327,9 +11327,6 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) Bot* player_to_invite = nullptr; Client* player_to_invite_owner = nullptr; - - - if (entity_list.GetBotByBotName(raid_command_packet->player_name) ) { Bot* player_to_invite = entity_list.GetBotByBotName(raid_command_packet->player_name); Client* player_to_invite_owner = player_to_invite->GetOwner()->CastToClient(); @@ -11419,30 +11416,43 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) Group* g_invitee = invitee->GetGroup(); Group* g_invitor = invitor->GetGroup(); - if (invitee->HasGroup() && g_invitee->IsLeader(invitee)) + bool invitor_has_bot = false; + bool invitee_has_bot = false; + + if (g_invitor && g_invitor->IsLeader(invitor)) { for (int x = 0; x < 6; x++) { - if (g_invitee->members[x]->IsBot()) - { - b = entity_list.GetBotByBotName(g_invitee->members[x]->GetName()); - Bot::ProcessRaidInvite(b, player_accepting_invite); - break; - } - } - } - if (invitee && invitor->HasGroup() && g_invitor->IsLeader(invitor)) - { - for (int x = 0; x < 6; x++) - { - if (g_invitor->members[x]->IsBot()) + if (g_invitor->members[x] && g_invitor->members[x]->IsBot()) { b = entity_list.GetBotByBotName(g_invitor->members[x]->GetName()); - Bot::ProcessRaidInvite2(player_accepting_invite); + invitee_has_bot = true; + } + } + } + if (g_invitee && g_invitee->IsLeader(invitee)) + { + for (int x = 0; x < 6; x++) + { + if (g_invitee->members[x] && g_invitee->members[x]->IsBot()) + { + b = entity_list.GetBotByBotName(g_invitee->members[x]->GetName()); + invitee_has_bot = true; break; } } } + if (invitor_has_bot || invitee_has_bot) { + Bot::ProcessRaidInvite2(invitee, invitor); + break; + } + else + if (invitee->IsBot()) + { + Bot::ProcessRaidInvite(b, player_accepting_invite); + break; + } + #endif if (player_accepting_invite) { if (IsRaidGrouped()) { From 9eca086b1c5fd9d6d2177a21efc5bb53812e8929 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Mon, 10 Jan 2022 18:01:06 -0400 Subject: [PATCH 19/55] A few changes --- zone/bot.cpp | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index b09834fd4..c51129359 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -10106,6 +10106,7 @@ void Bot::ProcessRaidInvite2(Client* invitee, Client* invitor) { { //As there is already a raid, just add this group raid->SendBulkRaid(invitee); + raid->SendMakeLeaderPacketTo(raid->leadername, invitee); //added to resolve Basic's raid window not showing a raid leader uint32 raid_free_group_id = raid->GetFreeGroup(); for (int x = 0; x < 6; x++) { if (g_invitee->members[x]) { @@ -10154,8 +10155,8 @@ void Bot::ProcessRaidInvite2(Client* invitee, Client* invitor) { { //As there is already a raid and no group, just add this single client raid->SendRaidCreate(invitee); - raid->SendMakeLeaderPacketTo(raid->leadername, invitee); raid->AddMember(invitee); + raid->SendMakeLeaderPacketTo(raid->leadername, invitee); //moved to be after the addmember to resolve raid window not showing a raid leader if (raid->IsLocked()) { raid->SendRaidLockTo(invitee); } @@ -10168,6 +10169,8 @@ void Bot::ProcessRaidInvite2(Client* invitee, Client* invitor) { raid = new Raid(invitor); entity_list.AddRaid(raid); raid->SetRaidDetails(); + raid->SendRaidCreate(invitor); + raid->SendMakeLeaderPacketTo(raid->leadername, invitor); //added to resolve no raid leader shown in Rola's raid window if (g_invitor) { @@ -10181,9 +10184,11 @@ void Bot::ProcessRaidInvite2(Client* invitee, Client* invitor) { if (x == 0) { raid->AddBot(b, 0, false, true, false); raid->SetGroupLeader(b->GetName()); + raid->GroupUpdate(0); } else { raid->AddBot(b, 0, false, false, false); + raid->GroupUpdate(0); } } else if (g_invitor->members[x] && g_invitor->members[x]->IsClient()) { @@ -10193,6 +10198,7 @@ void Bot::ProcessRaidInvite2(Client* invitee, Client* invitor) { raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, 0, false, true, false); raid->SetGroupLeader(c->GetName()); + raid->GroupUpdate(0); if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -10201,6 +10207,7 @@ void Bot::ProcessRaidInvite2(Client* invitee, Client* invitor) { raid->SendRaidCreate(c); raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, 0, false, false, false); + raid->GroupUpdate(0); if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -10227,9 +10234,11 @@ void Bot::ProcessRaidInvite2(Client* invitee, Client* invitor) { if (x == 0) { raid->AddBot(b, raid_free_group_id, false, true, false); raid->SetGroupLeader(b->GetName()); + raid->GroupUpdate(raid_free_group_id); } else { raid->AddBot(b, raid_free_group_id, false, false, false); + raid->GroupUpdate(raid_free_group_id); } } else if (g_invitee->members[x] && g_invitee->members[x]->IsClient()) { @@ -10239,6 +10248,7 @@ void Bot::ProcessRaidInvite2(Client* invitee, Client* invitor) { raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, raid_free_group_id, false, true, false); raid->SetGroupLeader(c->GetName()); + raid->GroupUpdate(raid_free_group_id); if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -10247,6 +10257,7 @@ void Bot::ProcessRaidInvite2(Client* invitee, Client* invitor) { raid->SendRaidCreate(c); raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, raid_free_group_id, false, false, false); + raid->GroupUpdate(raid_free_group_id); if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -10296,9 +10307,11 @@ void Bot::ProcessRaidInvite2(Client* invitee, Client* invitor) { if (x == 0) { raid->AddBot(b, raid_free_group_id, false, true, false); raid->SetGroupLeader(b->GetName()); + raid->GroupUpdate(raid_free_group_id); } else { raid->AddBot(b, raid_free_group_id, false, false, false); + raid->GroupUpdate(raid_free_group_id); } } else if (g_invitee->members[x] && g_invitee->members[x]->IsClient()) { @@ -10308,6 +10321,7 @@ void Bot::ProcessRaidInvite2(Client* invitee, Client* invitor) { raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, raid_free_group_id, false, true, false); raid->SetGroupLeader(c->GetName()); + raid->GroupUpdate(raid_free_group_id); if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -10316,6 +10330,7 @@ void Bot::ProcessRaidInvite2(Client* invitee, Client* invitor) { raid->SendRaidCreate(c); raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, raid_free_group_id, false, false, false); + raid->GroupUpdate(raid_free_group_id); if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -10364,9 +10379,11 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { if (x == 0) { raid->AddBot(b, raid_free_group_id, false, true, false); raid->SetGroupLeader(b->GetName()); + raid->GroupUpdate(raid_free_group_id); } else { raid->AddBot(b, raid_free_group_id, false, false, false); + raid->GroupUpdate(raid_free_group_id); } } else if (g_invitee->members[x] && g_invitee->members[x]->IsClient()) { @@ -10376,6 +10393,7 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, raid_free_group_id, false, true, false); raid->SetGroupLeader(c->GetName()); + raid->GroupUpdate(raid_free_group_id); if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -10384,6 +10402,7 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { raid->SendRaidCreate(c); raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, raid_free_group_id, false, false, false); + raid->GroupUpdate(raid_free_group_id); if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -10429,9 +10448,11 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { if (x == 0) { raid->AddBot(b, 0, false, true, false); raid->SetGroupLeader(b->GetName()); + raid->GroupUpdate(0); } else { raid->AddBot(b, 0, false, false, false); + raid->GroupUpdate(0); } } else if (g_invitor->members[x] && g_invitor->members[x]->IsClient()) { @@ -10441,6 +10462,7 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, 0, false, true, false); raid->SetGroupLeader(c->GetName()); + raid->GroupUpdate(0); if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -10449,6 +10471,7 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { raid->SendRaidCreate(c); raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, 0, false, false, false); + raid->GroupUpdate(0); if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -10475,9 +10498,11 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { if (x == 0) { raid->AddBot(b, raid_free_group_id, false, true, false); raid->SetGroupLeader(b->GetName()); + raid->GroupUpdate(raid_free_group_id); } else { raid->AddBot(b, raid_free_group_id, false, false, false); + raid->GroupUpdate(raid_free_group_id); } } else if (g_invitee->members[x] && g_invitee->members[x]->IsClient()) { @@ -10487,6 +10512,7 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, raid_free_group_id, false, true, false); raid->SetGroupLeader(c->GetName()); + raid->GroupUpdate(raid_free_group_id); if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -10495,6 +10521,7 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { raid->SendRaidCreate(c); raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, raid_free_group_id, false, false, false); + raid->GroupUpdate(raid_free_group_id); if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -10543,9 +10570,11 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { if (x == 0) { raid->AddBot(b, raid_free_group_id, false, true, false); raid->SetGroupLeader(b->GetName()); + raid->GroupUpdate(raid_free_group_id); } else { raid->AddBot(b, raid_free_group_id, false, false, false); + raid->GroupUpdate(raid_free_group_id); } } else if (g_invitee->members[x] && g_invitee->members[x]->IsClient()) { @@ -10555,6 +10584,7 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, raid_free_group_id, false, true, false); raid->SetGroupLeader(c->GetName()); + raid->GroupUpdate(raid_free_group_id); if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -10563,6 +10593,7 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { raid->SendRaidCreate(c); raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, raid_free_group_id, false, false, false); + raid->GroupUpdate(raid_free_group_id); if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -10583,6 +10614,7 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { //raid->SendRaidCreate(invitee); //raid->SendMakeLeaderPacketTo(raid->leadername, invitee); raid->AddBot(invitee); + invitee->SetFollowID(invitor->GetID()); //if (raid->IsLocked()) { // raid->SendRaidLockTo(invitee); //} From bd831d2b4afa0248d1992db74323d509f180edb0 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Tue, 11 Jan 2022 08:29:19 -0400 Subject: [PATCH 20/55] end of day jan 10 --- zone/bot.cpp | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index c51129359..e937098c6 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -2539,11 +2539,16 @@ void Bot::AI_Process() Client* bot_owner = (GetBotOwner() && GetBotOwner()->IsClient() ? GetBotOwner()->CastToClient() : nullptr); Group* bot_group = GetGroup(); + + Raid* bot_raid = entity_list.GetRaidByClient(bot_owner); + int bot_raid_group = 0; + if (bot_raid) + bot_raid_group = bot_raid->GetGroup(GetName()) + 1; //#pragma region PRIMARY AI SKIP CHECKS // Primary reasons for not processing AI - if (!bot_owner || !bot_group || !IsAIControlled()) { + if (!bot_owner || (!bot_group && !bot_raid_group) || !IsAIControlled()) { return; } @@ -10144,6 +10149,7 @@ void Bot::ProcessRaidInvite2(Client* invitee, Client* invitor) { } } } + raid->GroupUpdate(raid_free_group_id); // raid->SendBulkRaid(invitor); //Send a raid updates to the invitor g_invitee->JoinRaidXTarget(raid, true); g_invitee->DisbandGroup(true); @@ -10215,6 +10221,7 @@ void Bot::ProcessRaidInvite2(Client* invitee, Client* invitor) { } } } + raid->GroupUpdate(0); raid->SendBulkRaid(invitee); //Send a raid updates to the invitor g_invitor->JoinRaidXTarget(raid, true); g_invitor->DisbandGroup(true); @@ -10265,6 +10272,7 @@ void Bot::ProcessRaidInvite2(Client* invitee, Client* invitor) { } } } + raid->GroupUpdate(raid_free_group_id); // raid->SendBulkRaid(invitee); //Send a raid updates to the invitee g_invitee->JoinRaidXTarget(raid, true); g_invitee->DisbandGroup(true); @@ -10338,6 +10346,7 @@ void Bot::ProcessRaidInvite2(Client* invitee, Client* invitor) { } } } + raid->GroupUpdate(raid_free_group_id); g_invitee->JoinRaidXTarget(raid, true); g_invitee->DisbandGroup(true); if (raid->IsLocked()) { @@ -10435,6 +10444,8 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { raid = new Raid(invitor); entity_list.AddRaid(raid); raid->SetRaidDetails(); + raid->SendRaidCreate(invitor); + raid->SendMakeGroupLeaderPacketTo(raid->leadername, invitor); if (g_invitor) { @@ -10448,11 +10459,12 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { if (x == 0) { raid->AddBot(b, 0, false, true, false); raid->SetGroupLeader(b->GetName()); - raid->GroupUpdate(0); + //raid->GroupUpdate(0); } else { raid->AddBot(b, 0, false, false, false); - raid->GroupUpdate(0); + //raid->GroupUpdate(0); + b->SetFollowID(g_invitor->GetLeader()->GetID()); } } else if (g_invitor->members[x] && g_invitor->members[x]->IsClient()) { @@ -10462,7 +10474,7 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, 0, false, true, false); raid->SetGroupLeader(c->GetName()); - raid->GroupUpdate(0); + //raid->GroupUpdate(0, true); if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -10471,7 +10483,7 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { raid->SendRaidCreate(c); raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, 0, false, false, false); - raid->GroupUpdate(0); + //raid->GroupUpdate(0, true); if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -10479,9 +10491,11 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { } } } +// raid->GroupUpdate(0, true); // raid->SendBulkRaid(invitee); //Send a raid updates to the invitor g_invitor->JoinRaidXTarget(raid, true); g_invitor->DisbandGroup(true); + raid->GroupUpdate(0, true); if (raid->IsLocked()) { raid->SendRaidLockTo(invitor); } @@ -10498,11 +10512,9 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { if (x == 0) { raid->AddBot(b, raid_free_group_id, false, true, false); raid->SetGroupLeader(b->GetName()); - raid->GroupUpdate(raid_free_group_id); } else { raid->AddBot(b, raid_free_group_id, false, false, false); - raid->GroupUpdate(raid_free_group_id); } } else if (g_invitee->members[x] && g_invitee->members[x]->IsClient()) { @@ -10512,7 +10524,6 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, raid_free_group_id, false, true, false); raid->SetGroupLeader(c->GetName()); - raid->GroupUpdate(raid_free_group_id); if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -10521,7 +10532,6 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { raid->SendRaidCreate(c); raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, raid_free_group_id, false, false, false); - raid->GroupUpdate(raid_free_group_id); if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -10532,6 +10542,7 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { //raid->SendBulkRaid(invitor); //Send a raid updates to the invitor g_invitee->JoinRaidXTarget(raid, true); g_invitee->DisbandGroup(true); + raid->GroupUpdate(raid_free_group_id); if (raid->IsLocked()) { raid->SendRaidLockTo(invitor); } @@ -10570,11 +10581,9 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { if (x == 0) { raid->AddBot(b, raid_free_group_id, false, true, false); raid->SetGroupLeader(b->GetName()); - raid->GroupUpdate(raid_free_group_id); } else { raid->AddBot(b, raid_free_group_id, false, false, false); - raid->GroupUpdate(raid_free_group_id); } } else if (g_invitee->members[x] && g_invitee->members[x]->IsClient()) { @@ -10584,7 +10593,6 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, raid_free_group_id, false, true, false); raid->SetGroupLeader(c->GetName()); - raid->GroupUpdate(raid_free_group_id); if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -10593,7 +10601,6 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { raid->SendRaidCreate(c); raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, raid_free_group_id, false, false, false); - raid->GroupUpdate(raid_free_group_id); if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -10604,6 +10611,7 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { // raid->SendBulkRaid(invitor); //Send a raid updates to the invitor g_invitee->JoinRaidXTarget(raid, true); g_invitee->DisbandGroup(true); + raid->GroupUpdate(raid_free_group_id); if (raid->IsLocked()) { raid->SendRaidLockTo(invitor); } From 4098d9db519820be5ea7c876331442710f218ae2 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Tue, 11 Jan 2022 17:40:10 -0400 Subject: [PATCH 21/55] Jan 11 --- zone/bot.cpp | 30 +++++++++++++++++++++++------- zone/client_packet.cpp | 13 ++++++++++++- zone/entity.cpp | 27 ++++++++++++++++++++++++--- zone/entity.h | 3 +++ zone/raids.cpp | 12 +++++++++++- 5 files changed, 73 insertions(+), 12 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index e937098c6..db8f5b40d 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -2540,15 +2540,12 @@ void Bot::AI_Process() Client* bot_owner = (GetBotOwner() && GetBotOwner()->IsClient() ? GetBotOwner()->CastToClient() : nullptr); Group* bot_group = GetGroup(); - Raid* bot_raid = entity_list.GetRaidByClient(bot_owner); - int bot_raid_group = 0; - if (bot_raid) - bot_raid_group = bot_raid->GetGroup(GetName()) + 1; - + Raid* bot_raid = entity_list.GetRaidByBot(this); + //#pragma region PRIMARY AI SKIP CHECKS // Primary reasons for not processing AI - if (!bot_owner || (!bot_group && !bot_raid_group) || !IsAIControlled()) { + if (!bot_owner || (!bot_group && !bot_raid) || !IsAIControlled()) { return; } @@ -2561,7 +2558,21 @@ void Bot::AI_Process() } // We also need a leash owner and follow mob (subset of primary AI criteria) - Client* leash_owner = (bot_group->GetLeader() && bot_group->GetLeader()->IsClient() ? bot_group->GetLeader()->CastToClient() : bot_owner); + Client* leash_owner = nullptr; + + if (bot_group) { + leash_owner = (bot_group->GetLeader() && bot_group->GetLeader()->IsClient() ? bot_group->GetLeader()->CastToClient() : bot_owner); + } + else if (bot_raid) { + int bot_raid_group = bot_raid->GetGroup(GetName()); + if (bot_raid_group > 0) { + leash_owner = bot_raid->GetGroupLeader(bot_raid_group)->CastToClient(); + } + else { + leash_owner = bot_raid->GetLeader(); + } + } + if (!leash_owner) { return; } @@ -8382,6 +8393,11 @@ void Bot::Camp(bool databaseSave) { //auto group = GetGroup(); if(GetGroup()) RemoveBotFromGroup(this, GetGroup()); + + //Mitch + Raid* bot_raid = entity_list.GetRaidByBot(this); + if (bot_raid) + bot_raid->RemoveMember(this->GetName()); // RemoveBotFromGroup() code is too complicated for this to work as-is (still needs to be addressed to prevent memory leaks) //if (group->GroupCount() < 2) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 60f2b9f1d..6dbdfdc33 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -11723,6 +11723,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) } case RaidCommandDisband: { Raid *raid = entity_list.GetRaidByClient(this); + Client* c = entity_list.GetClientByName(raid_command_packet->leader_name); + if (raid) { uint32 group = raid->GetGroup(raid_command_packet->leader_name); @@ -11753,7 +11755,16 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) } } } - +#ifdef BOTS + //check to see if the leader_name has any bots in the raid + //if so, remove them as well + + for (int i = 0; i < MAX_RAID_MEMBERS; ++i) + { + if (raid->members[i] && raid->members[i].member->IsBot() && raid->members[i].member->GetOwnerID() == entity_list.GetClientByName(raid_command_packet->leader_name)->CharacterID()) + raid->RemoveMember(raid->members[i].membername); + } +#endif raid->RemoveMember(raid_command_packet->leader_name); Client *c = entity_list.GetClientByName(raid_command_packet->leader_name); if (c) diff --git a/zone/entity.cpp b/zone/entity.cpp index bf6e44a2d..f301f6726 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -2023,17 +2023,17 @@ Raid *EntityList::GetRaidByID(uint32 id) return nullptr; } -Raid *EntityList::GetRaidByClient(Client* client) +Raid* EntityList::GetRaidByClient(Client* client) { if (client->p_raid_instance) { return client->p_raid_instance; } - std::list::iterator iterator; + std::list::iterator iterator; iterator = raid_list.begin(); while (iterator != raid_list.end()) { - for (auto &member : (*iterator)->members) { + for (auto& member : (*iterator)->members) { if (member.member) { if (member.member == client) { client->p_raid_instance = *iterator; @@ -2048,6 +2048,27 @@ Raid *EntityList::GetRaidByClient(Client* client) return nullptr; } +Raid* EntityList::GetRaidByBot(Bot* bot) +{ + std::list::iterator iterator; + iterator = raid_list.begin(); + + while (iterator != raid_list.end()) { + for (auto& member : (*iterator)->members) { + if (member.member) { + if (member.member == bot->CastToClient()) { + //client->p_raid_instance = *iterator; + return *iterator; + } + } + } + + ++iterator; + } + + return nullptr; +} + Raid *EntityList::GetRaidByMob(Mob *mob) { std::list::iterator iterator; diff --git a/zone/entity.h b/zone/entity.h index b4855b42e..0bbc298bc 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -197,6 +197,9 @@ public: Raid *GetRaidByClient(Client* client); Raid *GetRaidByID(uint32 id); Raid *GetRaidByLeaderName(const char *leader); +#ifdef BOTS + Raid* GetRaidByBot(Bot* bot); +#endif Corpse *GetCorpseByOwner(Client* client); Corpse *GetCorpseByOwnerWithinRange(Client* client, Mob* center, int range); diff --git a/zone/raids.cpp b/zone/raids.cpp index dcec202e2..2777bb637 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -246,6 +246,16 @@ void Raid::RemoveMember(const char *characterName) auto results = database.QueryDatabase(query); Client *client = entity_list.GetClientByName(characterName); +#ifdef BOTS + Bot* bot = entity_list.GetBotByBotName(characterName); + + if (bot) { + bot->SetFollowID(bot->GetOwner()->GetID()); + bot->SetGrouped(0); + bot->SetTarget(nullptr); + } +#endif + disbandCheck = true; SendRaidRemoveAll(characterName); SendRaidDisband(client); @@ -1731,7 +1741,7 @@ void Raid::SendHPManaEndPacketsFrom(Mob *mob) if(members[x].member) { if(!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) { members[x].member->QueuePacket(&hpapp, false); - if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) { + if (members[x].member->IsClient() && members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) { //Mitch outapp.SetOpcode(OP_MobManaUpdate); MobManaUpdate_Struct *mana_update = (MobManaUpdate_Struct *)outapp.pBuffer; mana_update->spawn_id = mob->GetID(); From d62171f34d9b10704fa0afa4909b57c900f92a25 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Wed, 12 Jan 2022 00:01:58 -0400 Subject: [PATCH 22/55] end of day Jan 11 --- zone/bot.cpp | 2 +- zone/client_packet.cpp | 37 ++++++++++++++++++++++++++----------- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index db8f5b40d..5d028277a 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -10510,7 +10510,7 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { // raid->GroupUpdate(0, true); // raid->SendBulkRaid(invitee); //Send a raid updates to the invitor g_invitor->JoinRaidXTarget(raid, true); - g_invitor->DisbandGroup(true); +// g_invitor->DisbandGroup(true); raid->GroupUpdate(0, true); if (raid->IsLocked()) { raid->SendRaidLockTo(invitor); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 6dbdfdc33..20612c166 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -11755,20 +11755,35 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) } } } -#ifdef BOTS - //check to see if the leader_name has any bots in the raid - //if so, remove them as well - - for (int i = 0; i < MAX_RAID_MEMBERS; ++i) - { - if (raid->members[i] && raid->members[i].member->IsBot() && raid->members[i].member->GetOwnerID() == entity_list.GetClientByName(raid_command_packet->leader_name)->CharacterID()) - raid->RemoveMember(raid->members[i].membername); - } -#endif raid->RemoveMember(raid_command_packet->leader_name); Client *c = entity_list.GetClientByName(raid_command_packet->leader_name); - if (c) + if (c) { +#ifdef BOTS + //check to see if the leader_name has any bots in the raid + //if so, remove them as well + +// for (int i = 0; i < MAX_RAID_MEMBERS; ++i) +// { +// if (raid->members[i].member && raid->members[i].member->IsBot() && raid->members[i].member->CastToBot()->GetOwner()->CastToClient()->CharacterID() == entity_list.GetClientByName(raid_command_packet->leader_name)->CharacterID()) +// raid->RemoveMember(raid->members[i].membername); +// } + std::vector raid_members_bots; + int owner_id = entity_list.GetClientByName(raid_command_packet->leader_name)->CharacterID(); + for (int i = 0; i < MAX_RAID_MEMBERS; ++i) + { + if (raid->members[i].member && raid->members[i].member->IsBot() && raid->members[i].member->CastToBot()->GetOwner()->CastToClient()->CharacterID() == owner_id) + { + raid_members_bots.emplace_back(raid->members[i].member->CastToBot()); + } + } + for (auto bot_iter : raid_members_bots) { + if (bot_iter && bot_iter->IsBot()) + raid->RemoveMember(bot_iter->GetName()); + } +#endif + raid->SendGroupDisband(c); + } else { auto pack = new ServerPacket(ServerOP_RaidGroupDisband, sizeof(ServerRaidGeneralAction_Struct)); From 6411c2335ed48615c13e05f08b5730f1be83a6d0 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Wed, 12 Jan 2022 18:47:56 -0400 Subject: [PATCH 23/55] Bot Invite/Accept cleanup --- zone/bot.cpp | 2 +- zone/bot.h | 4 +- zone/client_packet.cpp | 1103 ++++++++++++++++++++-------------------- 3 files changed, 553 insertions(+), 556 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index 5d028277a..09486f678 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -10115,7 +10115,7 @@ void Bot::StopMoving(float new_heading) uint8 Bot::spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND] = { 0 }; -void Bot::ProcessRaidInvite2(Client* invitee, Client* invitor) { +void Bot::ProcessRaidInvite(Client* invitee, Client* invitor) { Raid* raid = entity_list.GetRaidByClient(invitor); Group* g_invitee = invitee->GetGroup(); diff --git a/zone/bot.h b/zone/bot.h index dc5f8e091..a553c2f6c 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -362,8 +362,8 @@ public: static std::string RaceIdToString(uint16 raceId); static bool IsBotAttackAllowed(Mob* attacker, Mob* target, bool& hasRuleDefined); static Bot* GetBotByBotClientOwnerAndBotName(Client* c, std::string botName); - static void ProcessRaidInvite(Bot* player_accepting_invite, Client* b_owner); //Mitch - static void ProcessRaidInvite2(Client* invitee, Client* invitor); //Mitch + static void ProcessRaidInvite(Bot* invitee, Client* invitor); //Mitch + static void ProcessRaidInvite(Client* invitee, Client* invitor); //Mitch static void ProcessBotGroupInvite(Client* c, std::string botName); static void ProcessBotGroupDisband(Client* c, std::string botName); static void BotOrderCampAll(Client* c); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 20612c166..70ce5a98b 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -11309,7 +11309,7 @@ void Client::Handle_OP_QueryUCSServerStatus(const EQApplicationPacket *app) } } -void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) +void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) { if (app->size < sizeof(RaidGeneral_Struct)) { LogError("Wrong size: OP_RaidCommand, size=[{}], expected at least [{}]", app->size, sizeof(RaidGeneral_Struct)); @@ -11317,49 +11317,48 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) return; } - RaidGeneral_Struct *raid_command_packet = (RaidGeneral_Struct*)app->pBuffer; + RaidGeneral_Struct* raid_command_packet = (RaidGeneral_Struct*)app->pBuffer; switch (raid_command_packet->action) { - case RaidCommandInviteIntoExisting: - case RaidCommandInvite: { - //Mitch -#ifdef BOTS - Bot* player_to_invite = nullptr; - Client* player_to_invite_owner = nullptr; - - if (entity_list.GetBotByBotName(raid_command_packet->player_name) ) { - Bot* player_to_invite = entity_list.GetBotByBotName(raid_command_packet->player_name); - Client* player_to_invite_owner = player_to_invite->GetOwner()->CastToClient(); + case RaidCommandInviteIntoExisting: + case RaidCommandInvite: { - if (!player_to_invite) { - break; - } +#ifdef BOTS //Mitch - Group* player_to_invite_group = player_to_invite->GetGroup(); - // Not allowed: Invite a bot that is not owned by the inviter and is not in a group. They could be in a group with their owner! - if (player_to_invite->GetOwnerID() != player_to_invite_owner->CharacterID() && !player_to_invite_group) { - Message(Chat::Red, "%s is not grouped and not your Bot. You can only invite your Bots, or Bots grouped with others.", player_to_invite->GetName()); - } + Bot* player_to_invite = nullptr; + Client* player_to_invite_owner = nullptr; - //Not allowed: Invite a bot that is already within a raid. - if (player_to_invite->HasRaid()) { - Message(Chat::Red, "%s is already in a raid.", player_to_invite->GetName()); - break; - } - // Not allowed: Invite a bot that is in a group that is already a member - if (player_to_invite_group && player_to_invite_group->IsGroupMember(this)) { - MessageString(Chat::Red, ALREADY_IN_PARTY); - break; - } - // Not allowed: Invite a bot that is in a group but not the groupleader - if (player_to_invite_group && !player_to_invite_group->IsLeader(player_to_invite)) { - Message(Chat::Red, "You can only invite an ungrouped player or group leader to join your raid."); - break; - } + if (entity_list.GetBotByBotName(raid_command_packet->player_name)) { + Bot* player_to_invite = entity_list.GetBotByBotName(raid_command_packet->player_name); + Client* player_to_invite_owner = player_to_invite->GetOwner()->CastToClient(); + Group* player_to_invite_group = player_to_invite->GetGroup(); - Bot::ProcessRaidInvite(player_to_invite, player_to_invite_owner); + if (!player_to_invite) { break; } + + //Not allowed: Invite a bot that is already within a raid. + if (player_to_invite->IsRaidGrouped()) { + MessageString(Chat::White, ALREADY_IN_RAID, GetName()); //must invite members not in raid... + return; + } + + // Not allowed: Invite a bot that is not owned by the invitor + if (player_to_invite->IsBot() && + player_to_invite->CastToBot()->GetOwner()->CastToClient()->CharacterID() != + player_to_invite_owner->CharacterID()) { + Message(Chat::Red, "%s is not your Bot. You can only invite your Bots, or players grouped with bots.", player_to_invite->GetName()); + } + + // Not allowed: Invite a bot that is in a group but the bot is not the group leader + if (player_to_invite_group && !player_to_invite_group->IsLeader(player_to_invite->CastToMob())) { + Message(Chat::Red, "You can only invite group leaders or ungrouped bots. Try %s instead.", player_to_invite_group->GetLeader()->GetName()); + break; + } + + Bot::ProcessRaidInvite(player_to_invite, player_to_invite_owner); + break; + } else { #endif @@ -11403,223 +11402,169 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) } } - - case RaidCommandAcceptInvite: { - Client *player_accepting_invite = entity_list.GetClientByName(raid_command_packet->player_name); + case RaidCommandAcceptInvite: { + Client* player_accepting_invite = entity_list.GetClientByName(raid_command_packet->player_name); #ifdef BOTS - // If the accepting client is in a group with a Bot, send the invite to Bot:ProcessRaidInvite - // instead of remaining here. - Bot* b = nullptr; - Client* invitee = entity_list.GetClientByName(raid_command_packet->leader_name); - Client* invitor = entity_list.GetClientByName(raid_command_packet->player_name); - Group* g_invitee = invitee->GetGroup(); - Group* g_invitor = invitor->GetGroup(); + // If the accepting client is in a group with a Bot or the invitor is in a group with a Bot, send the invite to Bot:ProcessRaidInvite + // instead of remaining here. + Bot* b = nullptr; + Client* invitee = entity_list.GetClientByName(raid_command_packet->leader_name); + Client* invitor = entity_list.GetClientByName(raid_command_packet->player_name); + Group* g_invitee = invitee->GetGroup(); + Group* g_invitor = invitor->GetGroup(); - bool invitor_has_bot = false; - bool invitee_has_bot = false; + if (invitee && invitee->IsRaidGrouped()) { + invitor->MessageString(Chat::White, ALREADY_IN_RAID, GetName()); //group failed, must invite members not in raid... + return; + } - if (g_invitor && g_invitor->IsLeader(invitor)) + bool invitor_has_bot = false; + bool invitee_has_bot = false; + + if (g_invitor && g_invitor->IsLeader(invitor)) + { + for (int x = 0; x < 6; x++) { - for (int x = 0; x < 6; x++) + if (g_invitor->members[x] && g_invitor->members[x]->IsBot()) { - if (g_invitor->members[x] && g_invitor->members[x]->IsBot()) - { - b = entity_list.GetBotByBotName(g_invitor->members[x]->GetName()); - invitee_has_bot = true; - } + b = entity_list.GetBotByBotName(g_invitor->members[x]->GetName()); + invitee_has_bot = true; } } - if (g_invitee && g_invitee->IsLeader(invitee)) + } + if (g_invitee && g_invitee->IsLeader(invitee)) + { + for (int x = 0; x < 6; x++) { - for (int x = 0; x < 6; x++) + if (g_invitee->members[x] && g_invitee->members[x]->IsBot()) { - if (g_invitee->members[x] && g_invitee->members[x]->IsBot()) - { - b = entity_list.GetBotByBotName(g_invitee->members[x]->GetName()); - invitee_has_bot = true; - break; - } + b = entity_list.GetBotByBotName(g_invitee->members[x]->GetName()); + invitee_has_bot = true; + break; } } - if (invitor_has_bot || invitee_has_bot) { - Bot::ProcessRaidInvite2(invitee, invitor); - break; - } - else - if (invitee->IsBot()) - { - Bot::ProcessRaidInvite(b, player_accepting_invite); - break; - } + } + if (invitor_has_bot || invitee_has_bot) { + Bot::ProcessRaidInvite(invitee, invitor); //two clients with one or both having groups with bots + break; + } + else if (invitee->IsBot()) + { + Bot::ProcessRaidInvite(b, player_accepting_invite); //client inviting a bot + break; + } #endif - if (player_accepting_invite) { - if (IsRaidGrouped()) { - player_accepting_invite->MessageString(Chat::White, ALREADY_IN_RAID, GetName()); //group failed, must invite members not in raid... - return; + if (player_accepting_invite) { + if (IsRaidGrouped()) { + player_accepting_invite->MessageString(Chat::White, ALREADY_IN_RAID, GetName()); //group failed, must invite members not in raid... + return; + } + Raid* raid = entity_list.GetRaidByClient(player_accepting_invite); + if (raid) { + raid->VerifyRaid(); + Group* group = GetGroup(); + if (group) { + if (group->GroupCount() + raid->RaidCount() > MAX_RAID_MEMBERS) { + player_accepting_invite->Message(Chat::Red, "Invite failed, group invite would create a raid larger than the maximum number of members allowed."); + return; + } } - Raid *raid = entity_list.GetRaidByClient(player_accepting_invite); - if (raid) { - raid->VerifyRaid(); - Group *group = GetGroup(); - if (group) { - if (group->GroupCount() + raid->RaidCount() > MAX_RAID_MEMBERS) { - player_accepting_invite->Message(Chat::Red, "Invite failed, group invite would create a raid larger than the maximum number of members allowed."); - return; - } + else { + if (1 + raid->RaidCount() > MAX_RAID_MEMBERS) { + player_accepting_invite->Message(Chat::Red, "Invite failed, member invite would create a raid larger than the maximum number of members allowed."); + return; } - else { - if (1 + raid->RaidCount() > MAX_RAID_MEMBERS) { - player_accepting_invite->Message(Chat::Red, "Invite failed, member invite would create a raid larger than the maximum number of members allowed."); - return; - } - } - if (group) {//add us all - uint32 free_group_id = raid->GetFreeGroup(); - Client *addClient = nullptr; - for (int x = 0; x < 6; x++) { - if (group->members[x]) { - Client *c = nullptr; - if (group->members[x]->IsClient()) - c = group->members[x]->CastToClient(); - else - continue; + } + if (group) {//add us all + uint32 free_group_id = raid->GetFreeGroup(); + Client* addClient = nullptr; + for (int x = 0; x < 6; x++) { + if (group->members[x]) { + Client* c = nullptr; + if (group->members[x]->IsClient()) + c = group->members[x]->CastToClient(); + else + continue; - if (!addClient) - { - addClient = c; - raid->SetGroupLeader(addClient->GetName()); - } + if (!addClient) + { + addClient = c; + raid->SetGroupLeader(addClient->GetName()); + } - raid->SendRaidCreate(c); - raid->SendMakeLeaderPacketTo(raid->leadername, c); - if (group->IsLeader(group->members[x])) - raid->AddMember(c, free_group_id, false, true); - else - raid->AddMember(c, free_group_id); - raid->SendBulkRaid(c); - if (raid->IsLocked()) { - raid->SendRaidLockTo(c); - } + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); + if (group->IsLeader(group->members[x])) + raid->AddMember(c, free_group_id, false, true); + else + raid->AddMember(c, free_group_id); + raid->SendBulkRaid(c); + if (raid->IsLocked()) { + raid->SendRaidLockTo(c); } } - group->JoinRaidXTarget(raid); - group->DisbandGroup(true); - raid->GroupUpdate(free_group_id); } - else { - raid->SendRaidCreate(this); - raid->SendMakeLeaderPacketTo(raid->leadername, this); - raid->AddMember(this); - raid->SendBulkRaid(this); - if (raid->IsLocked()) { - raid->SendRaidLockTo(this); - } + group->JoinRaidXTarget(raid); + group->DisbandGroup(true); + raid->GroupUpdate(free_group_id); + } + else { + raid->SendRaidCreate(this); + raid->SendMakeLeaderPacketTo(raid->leadername, this); + raid->AddMember(this); + raid->SendBulkRaid(this); + if (raid->IsLocked()) { + raid->SendRaidLockTo(this); } } - else + } + else + { + Group* player_invited_group = player_accepting_invite->GetGroup(); + Group* group = GetGroup(); + if (group) //if our target has a group { - Group *player_invited_group = player_accepting_invite->GetGroup(); - Group *group = GetGroup(); - if (group) //if our target has a group - { - raid = new Raid(player_accepting_invite); - entity_list.AddRaid(raid); - raid->SetRaidDetails(); + raid = new Raid(player_accepting_invite); + entity_list.AddRaid(raid); + raid->SetRaidDetails(); - uint32 raid_free_group_id = raid->GetFreeGroup(); + uint32 raid_free_group_id = raid->GetFreeGroup(); - /* If we already have a group then cycle through adding us... */ - if (player_invited_group) { - Client *client_to_be_leader = nullptr; - for (int x = 0; x < 6; x++) { - if (player_invited_group->members[x]) { - if (!client_to_be_leader) { - if (player_invited_group->members[x]->IsClient()) { - client_to_be_leader = player_invited_group->members[x]->CastToClient(); - raid->SetGroupLeader(client_to_be_leader->GetName()); - } - } - if (player_invited_group->IsLeader(player_invited_group->members[x])) { - Client *c = nullptr; - - if (player_invited_group->members[x]->IsClient()) - c = player_invited_group->members[x]->CastToClient(); - else - continue; - - raid->SendRaidCreate(c); - raid->SendMakeLeaderPacketTo(raid->leadername, c); - raid->AddMember(c, raid_free_group_id, true, true, true); - raid->SendBulkRaid(c); - - if (raid->IsLocked()) { - raid->SendRaidLockTo(c); - } - } - else { - Client *c = nullptr; - - if (player_invited_group->members[x]->IsClient()) - c = player_invited_group->members[x]->CastToClient(); - else - continue; - - raid->SendRaidCreate(c); - raid->SendMakeLeaderPacketTo(raid->leadername, c); - raid->AddMember(c, raid_free_group_id); - raid->SendBulkRaid(c); - - if (raid->IsLocked()) { - raid->SendRaidLockTo(c); - } - } - } - } - player_invited_group->JoinRaidXTarget(raid, true); - player_invited_group->DisbandGroup(true); - raid->GroupUpdate(raid_free_group_id); - raid_free_group_id = raid->GetFreeGroup(); - } - else { - raid->SendRaidCreate(player_accepting_invite); - raid->AddMember(player_accepting_invite, 0xFFFFFFFF, true, false, true); - } - - Client *client_to_add = nullptr; - /* Add client to an existing group */ + /* If we already have a group then cycle through adding us... */ + if (player_invited_group) { + Client* client_to_be_leader = nullptr; for (int x = 0; x < 6; x++) { - if (group->members[x]) { - if (!client_to_add) { - if (group->members[x]->IsClient()) { - client_to_add = group->members[x]->CastToClient(); - raid->SetGroupLeader(client_to_add->GetName()); + if (player_invited_group->members[x]) { + if (!client_to_be_leader) { + if (player_invited_group->members[x]->IsClient()) { + client_to_be_leader = player_invited_group->members[x]->CastToClient(); + raid->SetGroupLeader(client_to_be_leader->GetName()); } } - if (group->IsLeader(group->members[x])) { - Client *c = nullptr; + if (player_invited_group->IsLeader(player_invited_group->members[x])) { + Client* c = nullptr; - if (group->members[x]->IsClient()) - c = group->members[x]->CastToClient(); + if (player_invited_group->members[x]->IsClient()) + c = player_invited_group->members[x]->CastToClient(); else continue; raid->SendRaidCreate(c); raid->SendMakeLeaderPacketTo(raid->leadername, c); - raid->AddMember(c, raid_free_group_id, false, true); + raid->AddMember(c, raid_free_group_id, true, true, true); raid->SendBulkRaid(c); if (raid->IsLocked()) { raid->SendRaidLockTo(c); } } - else - { - Client *c = nullptr; + else { + Client* c = nullptr; - if (group->members[x]->IsClient()) - c = group->members[x]->CastToClient(); + if (player_invited_group->members[x]->IsClient()) + c = player_invited_group->members[x]->CastToClient(); else continue; @@ -11634,422 +11579,474 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) } } } - group->JoinRaidXTarget(raid); - group->DisbandGroup(true); - + player_invited_group->JoinRaidXTarget(raid, true); + player_invited_group->DisbandGroup(true); raid->GroupUpdate(raid_free_group_id); + raid_free_group_id = raid->GetFreeGroup(); } - /* Target does not have a group */ else { - if (player_invited_group) { + raid->SendRaidCreate(player_accepting_invite); + raid->AddMember(player_accepting_invite, 0xFFFFFFFF, true, false, true); + } - raid = new Raid(player_accepting_invite); + Client* client_to_add = nullptr; + /* Add client to an existing group */ + for (int x = 0; x < 6; x++) { + if (group->members[x]) { + if (!client_to_add) { + if (group->members[x]->IsClient()) { + client_to_add = group->members[x]->CastToClient(); + raid->SetGroupLeader(client_to_add->GetName()); + } + } + if (group->IsLeader(group->members[x])) { + Client* c = nullptr; - entity_list.AddRaid(raid); - raid->SetRaidDetails(); - Client *addClientig = nullptr; - for (int x = 0; x < 6; x++) { - if (player_invited_group->members[x]) { - if (!addClientig) { - if (player_invited_group->members[x]->IsClient()) { - addClientig = player_invited_group->members[x]->CastToClient(); - raid->SetGroupLeader(addClientig->GetName()); - } + if (group->members[x]->IsClient()) + c = group->members[x]->CastToClient(); + else + continue; + + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); + raid->AddMember(c, raid_free_group_id, false, true); + raid->SendBulkRaid(c); + + if (raid->IsLocked()) { + raid->SendRaidLockTo(c); + } + } + else + { + Client* c = nullptr; + + if (group->members[x]->IsClient()) + c = group->members[x]->CastToClient(); + else + continue; + + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); + raid->AddMember(c, raid_free_group_id); + raid->SendBulkRaid(c); + + if (raid->IsLocked()) { + raid->SendRaidLockTo(c); + } + } + } + } + group->JoinRaidXTarget(raid); + group->DisbandGroup(true); + + raid->GroupUpdate(raid_free_group_id); + } + /* Target does not have a group */ + else { + if (player_invited_group) { + + raid = new Raid(player_accepting_invite); + + entity_list.AddRaid(raid); + raid->SetRaidDetails(); + Client* addClientig = nullptr; + for (int x = 0; x < 6; x++) { + if (player_invited_group->members[x]) { + if (!addClientig) { + if (player_invited_group->members[x]->IsClient()) { + addClientig = player_invited_group->members[x]->CastToClient(); + raid->SetGroupLeader(addClientig->GetName()); } - if (player_invited_group->IsLeader(player_invited_group->members[x])) { - Client *c = nullptr; + } + if (player_invited_group->IsLeader(player_invited_group->members[x])) { + Client* c = nullptr; - if (player_invited_group->members[x]->IsClient()) - c = player_invited_group->members[x]->CastToClient(); - else - continue; - - raid->SendRaidCreate(c); - raid->SendMakeLeaderPacketTo(raid->leadername, c); - raid->AddMember(c, 0, true, true, true); - raid->SendBulkRaid(c); - - if (raid->IsLocked()) { - raid->SendRaidLockTo(c); - } - } + if (player_invited_group->members[x]->IsClient()) + c = player_invited_group->members[x]->CastToClient(); else - { - Client *c = nullptr; - if (player_invited_group->members[x]->IsClient()) - c = player_invited_group->members[x]->CastToClient(); - else - continue; + continue; - raid->SendRaidCreate(c); - raid->SendMakeLeaderPacketTo(raid->leadername, c); - raid->AddMember(c, 0); - raid->SendBulkRaid(c); - if (raid->IsLocked()) { - raid->SendRaidLockTo(c); - } + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); + raid->AddMember(c, 0, true, true, true); + raid->SendBulkRaid(c); + + if (raid->IsLocked()) { + raid->SendRaidLockTo(c); + } + } + else + { + Client* c = nullptr; + if (player_invited_group->members[x]->IsClient()) + c = player_invited_group->members[x]->CastToClient(); + else + continue; + + raid->SendRaidCreate(c); + raid->SendMakeLeaderPacketTo(raid->leadername, c); + raid->AddMember(c, 0); + raid->SendBulkRaid(c); + if (raid->IsLocked()) { + raid->SendRaidLockTo(c); } } } - raid->SendRaidCreate(this); - raid->SendMakeLeaderPacketTo(raid->leadername, this); - raid->SendBulkRaid(this); - player_invited_group->JoinRaidXTarget(raid, true); - raid->AddMember(this); - player_invited_group->DisbandGroup(true); - raid->GroupUpdate(0); - if (raid->IsLocked()) { - raid->SendRaidLockTo(this); - } } - else { // neither has a group - raid = new Raid(player_accepting_invite); - entity_list.AddRaid(raid); - raid->SetRaidDetails(); - raid->SendRaidCreate(player_accepting_invite); - raid->SendRaidCreate(this); - raid->SendMakeLeaderPacketTo(raid->leadername, this); - raid->AddMember(player_accepting_invite, 0xFFFFFFFF, true, false, true); - raid->SendBulkRaid(this); - raid->AddMember(this); - if (raid->IsLocked()) { - raid->SendRaidLockTo(this); - } + raid->SendRaidCreate(this); + raid->SendMakeLeaderPacketTo(raid->leadername, this); + raid->SendBulkRaid(this); + player_invited_group->JoinRaidXTarget(raid, true); + raid->AddMember(this); + player_invited_group->DisbandGroup(true); + raid->GroupUpdate(0); + if (raid->IsLocked()) { + raid->SendRaidLockTo(this); + } + } + else { // neither has a group + raid = new Raid(player_accepting_invite); + entity_list.AddRaid(raid); + raid->SetRaidDetails(); + raid->SendRaidCreate(player_accepting_invite); + raid->SendRaidCreate(this); + raid->SendMakeLeaderPacketTo(raid->leadername, this); + raid->AddMember(player_accepting_invite, 0xFFFFFFFF, true, false, true); + raid->SendBulkRaid(this); + raid->AddMember(this); + if (raid->IsLocked()) { + raid->SendRaidLockTo(this); } } } } - break; } - case RaidCommandDisband: { - Raid *raid = entity_list.GetRaidByClient(this); - Client* c = entity_list.GetClientByName(raid_command_packet->leader_name); + break; + } + case RaidCommandDisband: { + Raid* raid = entity_list.GetRaidByClient(this); + Client* c = entity_list.GetClientByName(raid_command_packet->leader_name); - if (raid) { - uint32 group = raid->GetGroup(raid_command_packet->leader_name); + if (raid) { + uint32 group = raid->GetGroup(raid_command_packet->leader_name); - if (group < 12) { - uint32 i = raid->GetPlayerIndex(raid_command_packet->leader_name); - if (raid->members[i].IsGroupLeader) { //assign group leader to someone else - for (int x = 0; x < MAX_RAID_MEMBERS; x++) { - if (strlen(raid->members[x].membername) > 0 && i != x) { - if (raid->members[x].GroupNumber == group) { - raid->SetGroupLeader(raid_command_packet->leader_name, false); - raid->SetGroupLeader(raid->members[x].membername); - raid->UpdateGroupAAs(group); - break; - } - } - } - - } - if (raid->members[i].IsRaidLeader) { - for (int x = 0; x < MAX_RAID_MEMBERS; x++) { - if (strlen(raid->members[x].membername) > 0 && strcmp(raid->members[x].membername, raid->members[i].membername) != 0) - { - raid->SetRaidLeader(raid->members[i].membername, raid->members[x].membername); - raid->UpdateRaidAAs(); - raid->SendAllRaidLeadershipAA(); + if (group < 12) { + uint32 i = raid->GetPlayerIndex(raid_command_packet->leader_name); + if (raid->members[i].IsGroupLeader) { //assign group leader to someone else + for (int x = 0; x < MAX_RAID_MEMBERS; x++) { + if (strlen(raid->members[x].membername) > 0 && i != x) { + if (raid->members[x].GroupNumber == group) { + raid->SetGroupLeader(raid_command_packet->leader_name, false); + raid->SetGroupLeader(raid->members[x].membername); + raid->UpdateGroupAAs(group); break; } } } - } - raid->RemoveMember(raid_command_packet->leader_name); - Client *c = entity_list.GetClientByName(raid_command_packet->leader_name); - if (c) { -#ifdef BOTS - //check to see if the leader_name has any bots in the raid - //if so, remove them as well -// for (int i = 0; i < MAX_RAID_MEMBERS; ++i) -// { -// if (raid->members[i].member && raid->members[i].member->IsBot() && raid->members[i].member->CastToBot()->GetOwner()->CastToClient()->CharacterID() == entity_list.GetClientByName(raid_command_packet->leader_name)->CharacterID()) -// raid->RemoveMember(raid->members[i].membername); -// } - std::vector raid_members_bots; - int owner_id = entity_list.GetClientByName(raid_command_packet->leader_name)->CharacterID(); - for (int i = 0; i < MAX_RAID_MEMBERS; ++i) - { - if (raid->members[i].member && raid->members[i].member->IsBot() && raid->members[i].member->CastToBot()->GetOwner()->CastToClient()->CharacterID() == owner_id) + } + if (raid->members[i].IsRaidLeader) { + for (int x = 0; x < MAX_RAID_MEMBERS; x++) { + if (strlen(raid->members[x].membername) > 0 && strcmp(raid->members[x].membername, raid->members[i].membername) != 0) { - raid_members_bots.emplace_back(raid->members[i].member->CastToBot()); + raid->SetRaidLeader(raid->members[i].membername, raid->members[x].membername); + raid->UpdateRaidAAs(); + raid->SendAllRaidLeadershipAA(); + break; } } - for (auto bot_iter : raid_members_bots) { - if (bot_iter && bot_iter->IsBot()) - raid->RemoveMember(bot_iter->GetName()); + } + } + raid->RemoveMember(raid_command_packet->leader_name); + Client* c = entity_list.GetClientByName(raid_command_packet->leader_name); + if (c) { +#ifdef BOTS + + //Mitch added to remove all bots if the Bot_Owner is removed from the Raid + //Does not camp the Bots, just removes from the raid + std::vector raid_members_bots; + int owner_id = entity_list.GetClientByName(raid_command_packet->leader_name)->CharacterID(); + for (int i = 0; i < MAX_RAID_MEMBERS; ++i) + { + if (raid->members[i].member && raid->members[i].member->IsBot() && raid->members[i].member->CastToBot()->GetOwner()->CastToClient()->CharacterID() == owner_id) + { + raid_members_bots.emplace_back(raid->members[i].member->CastToBot()); } + } + for (auto bot_iter : raid_members_bots) { + if (bot_iter && bot_iter->IsBot()) + raid->RemoveMember(bot_iter->GetName()); + } #endif - raid->SendGroupDisband(c); - } - else { - auto pack = - new ServerPacket(ServerOP_RaidGroupDisband, sizeof(ServerRaidGeneralAction_Struct)); - ServerRaidGeneralAction_Struct* rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer; - rga->rid = GetID(); - rga->zoneid = zone->GetZoneID(); - rga->instance_id = zone->GetInstanceID(); - strn0cpy(rga->playername, raid_command_packet->leader_name, 64); - worldserver.SendPacket(pack); - safe_delete(pack); - } - //r->SendRaidGroupRemove(ri->leader_name, grp); - raid->GroupUpdate(group);// break - //} + raid->SendGroupDisband(c); } - break; + else { + auto pack = + new ServerPacket(ServerOP_RaidGroupDisband, sizeof(ServerRaidGeneralAction_Struct)); + ServerRaidGeneralAction_Struct* rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer; + rga->rid = GetID(); + rga->zoneid = zone->GetZoneID(); + rga->instance_id = zone->GetInstanceID(); + strn0cpy(rga->playername, raid_command_packet->leader_name, 64); + worldserver.SendPacket(pack); + safe_delete(pack); + } + //r->SendRaidGroupRemove(ri->leader_name, grp); + raid->GroupUpdate(group);// break + //} } - case RaidCommandMoveGroup: - { - Raid *raid = entity_list.GetRaidByClient(this); - if (raid) { - /* Moving to group */ - if (raid_command_packet->parameter < 12) { - uint8 group_count = raid->GroupCount(raid_command_packet->parameter); + break; + } + case RaidCommandMoveGroup: + { + Raid* raid = entity_list.GetRaidByClient(this); + if (raid) { + /* Moving to group */ + if (raid_command_packet->parameter < 12) { + uint8 group_count = raid->GroupCount(raid_command_packet->parameter); - if (group_count < 6) { - Client *c = entity_list.GetClientByName(raid_command_packet->leader_name); - uint32 old_group = raid->GetGroup(raid_command_packet->leader_name); - if (raid_command_packet->parameter == old_group) //don't rejoin grp if we order to join same group. - break; + if (group_count < 6) { + Client* c = entity_list.GetClientByName(raid_command_packet->leader_name); + uint32 old_group = raid->GetGroup(raid_command_packet->leader_name); + if (raid_command_packet->parameter == old_group) //don't rejoin grp if we order to join same group. + break; - if (raid->members[raid->GetPlayerIndex(raid_command_packet->leader_name)].IsGroupLeader) { - raid->SetGroupLeader(raid_command_packet->leader_name, false); - - /* We were the leader of our old group */ - if (old_group < 12) { - /* Assign new group leader if we can */ - for (int x = 0; x < MAX_RAID_MEMBERS; x++) { - if (raid->members[x].GroupNumber == old_group) { - if (strcmp(raid_command_packet->leader_name, raid->members[x].membername) != 0 && strlen(raid_command_packet->leader_name) > 0) { - raid->SetGroupLeader(raid->members[x].membername); - raid->UpdateGroupAAs(old_group); - - Client *client_to_update = entity_list.GetClientByName(raid->members[x].membername); - if (client_to_update) { - raid->SendRaidRemove(raid->members[x].membername, client_to_update); - raid->SendRaidCreate(client_to_update); - raid->SendMakeLeaderPacketTo(raid->leadername, client_to_update); - raid->SendRaidAdd(raid->members[x].membername, client_to_update); - raid->SendBulkRaid(client_to_update); - if (raid->IsLocked()) { - raid->SendRaidLockTo(client_to_update); - } - } - else { - auto pack = new ServerPacket(ServerOP_RaidChangeGroup, sizeof(ServerRaidGeneralAction_Struct)); - ServerRaidGeneralAction_Struct *raid_command_packet = (ServerRaidGeneralAction_Struct*)pack->pBuffer; - - raid_command_packet->rid = raid->GetID(); - raid_command_packet->zoneid = zone->GetZoneID(); - raid_command_packet->instance_id = zone->GetInstanceID(); - strn0cpy(raid_command_packet->playername, raid->members[x].membername, 64); - - worldserver.SendPacket(pack); - - safe_delete(pack); - } - break; - } - } - } - } - } - if (group_count == 0) { - raid->SetGroupLeader(raid_command_packet->leader_name); - raid->UpdateGroupAAs(raid_command_packet->parameter); - } - - raid->MoveMember(raid_command_packet->leader_name, raid_command_packet->parameter); - if (c) { - raid->SendGroupDisband(c); - } - else { - auto pack = new ServerPacket(ServerOP_RaidGroupDisband, sizeof(ServerRaidGeneralAction_Struct)); - ServerRaidGeneralAction_Struct* raid_command = (ServerRaidGeneralAction_Struct*)pack->pBuffer; - raid_command->rid = raid->GetID(); - raid_command->zoneid = zone->GetZoneID(); - raid_command->instance_id = zone->GetInstanceID(); - strn0cpy(raid_command->playername, raid_command_packet->leader_name, 64); - worldserver.SendPacket(pack); - safe_delete(pack); - } - - /* Send group update to our new group */ - raid->GroupUpdate(raid_command_packet->parameter); - - /* If our old was a group send update there too */ - if (old_group < 12) - raid->GroupUpdate(old_group); - - } - } - /* Move player to ungrouped bank */ - else { - Client *c = entity_list.GetClientByName(raid_command_packet->leader_name); - uint32 oldgrp = raid->GetGroup(raid_command_packet->leader_name); if (raid->members[raid->GetPlayerIndex(raid_command_packet->leader_name)].IsGroupLeader) { raid->SetGroupLeader(raid_command_packet->leader_name, false); - for (int x = 0; x < MAX_RAID_MEMBERS; x++) { - if (raid->members[x].GroupNumber == oldgrp && strlen(raid->members[x].membername) > 0 && strcmp(raid->members[x].membername, raid_command_packet->leader_name) != 0){ - raid->SetGroupLeader(raid->members[x].membername); - raid->UpdateGroupAAs(oldgrp); + /* We were the leader of our old group */ + if (old_group < 12) { + /* Assign new group leader if we can */ + for (int x = 0; x < MAX_RAID_MEMBERS; x++) { + if (raid->members[x].GroupNumber == old_group) { + if (strcmp(raid_command_packet->leader_name, raid->members[x].membername) != 0 && strlen(raid_command_packet->leader_name) > 0) { + raid->SetGroupLeader(raid->members[x].membername); + raid->UpdateGroupAAs(old_group); - Client *client_leaving_group = entity_list.GetClientByName(raid->members[x].membername); - if (client_leaving_group) { - raid->SendRaidRemove(raid->members[x].membername, client_leaving_group); - raid->SendRaidCreate(client_leaving_group); - raid->SendMakeLeaderPacketTo(raid->leadername, client_leaving_group); - raid->SendRaidAdd(raid->members[x].membername, client_leaving_group); - raid->SendBulkRaid(client_leaving_group); - if (raid->IsLocked()) { - raid->SendRaidLockTo(client_leaving_group); + Client* client_to_update = entity_list.GetClientByName(raid->members[x].membername); + if (client_to_update) { + raid->SendRaidRemove(raid->members[x].membername, client_to_update); + raid->SendRaidCreate(client_to_update); + raid->SendMakeLeaderPacketTo(raid->leadername, client_to_update); + raid->SendRaidAdd(raid->members[x].membername, client_to_update); + raid->SendBulkRaid(client_to_update); + if (raid->IsLocked()) { + raid->SendRaidLockTo(client_to_update); + } + } + else { + auto pack = new ServerPacket(ServerOP_RaidChangeGroup, sizeof(ServerRaidGeneralAction_Struct)); + ServerRaidGeneralAction_Struct* raid_command_packet = (ServerRaidGeneralAction_Struct*)pack->pBuffer; + + raid_command_packet->rid = raid->GetID(); + raid_command_packet->zoneid = zone->GetZoneID(); + raid_command_packet->instance_id = zone->GetInstanceID(); + strn0cpy(raid_command_packet->playername, raid->members[x].membername, 64); + + worldserver.SendPacket(pack); + + safe_delete(pack); + } + break; } } - else { - auto pack = new ServerPacket( ServerOP_RaidChangeGroup, sizeof(ServerRaidGeneralAction_Struct)); - ServerRaidGeneralAction_Struct *raid_command = (ServerRaidGeneralAction_Struct*)pack->pBuffer; - - raid_command->rid = raid->GetID(); - strn0cpy(raid_command->playername, raid->members[x].membername, 64); - raid_command->zoneid = zone->GetZoneID(); - raid_command->instance_id = zone->GetInstanceID(); - - worldserver.SendPacket(pack); - safe_delete(pack); - } - break; } } } - raid->MoveMember(raid_command_packet->leader_name, 0xFFFFFFFF); + if (group_count == 0) { + raid->SetGroupLeader(raid_command_packet->leader_name); + raid->UpdateGroupAAs(raid_command_packet->parameter); + } + + raid->MoveMember(raid_command_packet->leader_name, raid_command_packet->parameter); if (c) { raid->SendGroupDisband(c); } else { auto pack = new ServerPacket(ServerOP_RaidGroupDisband, sizeof(ServerRaidGeneralAction_Struct)); ServerRaidGeneralAction_Struct* raid_command = (ServerRaidGeneralAction_Struct*)pack->pBuffer; - raid_command->rid = raid->GetID(); raid_command->zoneid = zone->GetZoneID(); raid_command->instance_id = zone->GetInstanceID(); strn0cpy(raid_command->playername, raid_command_packet->leader_name, 64); - worldserver.SendPacket(pack); - safe_delete(pack); } - raid->GroupUpdate(oldgrp); + /* Send group update to our new group */ + raid->GroupUpdate(raid_command_packet->parameter); + + /* If our old was a group send update there too */ + if (old_group < 12) + raid->GroupUpdate(old_group); + } } + /* Move player to ungrouped bank */ + else { + Client* c = entity_list.GetClientByName(raid_command_packet->leader_name); + uint32 oldgrp = raid->GetGroup(raid_command_packet->leader_name); + if (raid->members[raid->GetPlayerIndex(raid_command_packet->leader_name)].IsGroupLeader) { + raid->SetGroupLeader(raid_command_packet->leader_name, false); + for (int x = 0; x < MAX_RAID_MEMBERS; x++) { + if (raid->members[x].GroupNumber == oldgrp && strlen(raid->members[x].membername) > 0 && strcmp(raid->members[x].membername, raid_command_packet->leader_name) != 0) { - Client *client_moved = entity_list.GetClientByName(raid_command_packet->leader_name); + raid->SetGroupLeader(raid->members[x].membername); + raid->UpdateGroupAAs(oldgrp); - if (client_moved && client_moved->GetRaid()) { - client_moved->GetRaid()->SendHPManaEndPacketsTo(client_moved); - client_moved->GetRaid()->SendHPManaEndPacketsFrom(client_moved); + Client* client_leaving_group = entity_list.GetClientByName(raid->members[x].membername); + if (client_leaving_group) { + raid->SendRaidRemove(raid->members[x].membername, client_leaving_group); + raid->SendRaidCreate(client_leaving_group); + raid->SendMakeLeaderPacketTo(raid->leadername, client_leaving_group); + raid->SendRaidAdd(raid->members[x].membername, client_leaving_group); + raid->SendBulkRaid(client_leaving_group); + if (raid->IsLocked()) { + raid->SendRaidLockTo(client_leaving_group); + } + } + else { + auto pack = new ServerPacket(ServerOP_RaidChangeGroup, sizeof(ServerRaidGeneralAction_Struct)); + ServerRaidGeneralAction_Struct* raid_command = (ServerRaidGeneralAction_Struct*)pack->pBuffer; - Log(Logs::General, Logs::HPUpdate, - "Client::Handle_OP_RaidCommand :: %s sending and recieving HP/Mana/End updates", - client_moved->GetCleanName() - ); - } + raid_command->rid = raid->GetID(); + strn0cpy(raid_command->playername, raid->members[x].membername, 64); + raid_command->zoneid = zone->GetZoneID(); + raid_command->instance_id = zone->GetInstanceID(); - break; - } - case RaidCommandRaidLock: - { - Raid *raid = entity_list.GetRaidByClient(this); - if (raid) { - if (!raid->IsLocked()) - raid->LockRaid(true); - else - raid->SendRaidLockTo(this); - } - break; - } - case RaidCommandRaidUnlock: - { - Raid *raid = entity_list.GetRaidByClient(this); - if (raid) - { - if (raid->IsLocked()) - raid->LockRaid(false); - else - raid->SendRaidUnlockTo(this); - } - break; - } - case RaidCommandLootType2: - case RaidCommandLootType: - { - Raid *raid = entity_list.GetRaidByClient(this); - if (raid) { - Message(Chat::Yellow, "Loot type changed to: %d.", raid_command_packet->parameter); - raid->ChangeLootType(raid_command_packet->parameter); - } - break; - } - - case RaidCommandAddLooter2: - case RaidCommandAddLooter: - { - Raid *raid = entity_list.GetRaidByClient(this); - if (raid) { - Message(Chat::Yellow, "Adding %s as a raid looter.", raid_command_packet->leader_name); - raid->AddRaidLooter(raid_command_packet->leader_name); - } - break; - } - - case RaidCommandRemoveLooter2: - case RaidCommandRemoveLooter: - { - Raid *raid = entity_list.GetRaidByClient(this); - if (raid) { - Message(Chat::Yellow, "Removing %s as a raid looter.", raid_command_packet->leader_name); - raid->RemoveRaidLooter(raid_command_packet->leader_name); - } - break; - } - - case RaidCommandMakeLeader: - { - Raid *raid = entity_list.GetRaidByClient(this); - if (raid) { - if (strcmp(raid->leadername, GetName()) == 0) { - raid->SetRaidLeader(GetName(), raid_command_packet->leader_name); - raid->UpdateRaidAAs(); - raid->SendAllRaidLeadershipAA(); + worldserver.SendPacket(pack); + safe_delete(pack); + } + break; + } + } } + raid->MoveMember(raid_command_packet->leader_name, 0xFFFFFFFF); + if (c) { + raid->SendGroupDisband(c); + } + else { + auto pack = new ServerPacket(ServerOP_RaidGroupDisband, sizeof(ServerRaidGeneralAction_Struct)); + ServerRaidGeneralAction_Struct* raid_command = (ServerRaidGeneralAction_Struct*)pack->pBuffer; + + raid_command->rid = raid->GetID(); + raid_command->zoneid = zone->GetZoneID(); + raid_command->instance_id = zone->GetInstanceID(); + strn0cpy(raid_command->playername, raid_command_packet->leader_name, 64); + + worldserver.SendPacket(pack); + + safe_delete(pack); + } + + raid->GroupUpdate(oldgrp); } - break; } - case RaidCommandSetMotd: + Client* client_moved = entity_list.GetClientByName(raid_command_packet->leader_name); + + if (client_moved && client_moved->GetRaid()) { + client_moved->GetRaid()->SendHPManaEndPacketsTo(client_moved); + client_moved->GetRaid()->SendHPManaEndPacketsFrom(client_moved); + + Log(Logs::General, Logs::HPUpdate, + "Client::Handle_OP_RaidCommand :: %s sending and recieving HP/Mana/End updates", + client_moved->GetCleanName() + ); + } + + break; + } + case RaidCommandRaidLock: + { + Raid* raid = entity_list.GetRaidByClient(this); + if (raid) { + if (!raid->IsLocked()) + raid->LockRaid(true); + else + raid->SendRaidLockTo(this); + } + break; + } + case RaidCommandRaidUnlock: + { + Raid* raid = entity_list.GetRaidByClient(this); + if (raid) { - Raid *raid = entity_list.GetRaidByClient(this); - if (!raid) - break; - // we don't use the RaidGeneral here! - RaidMOTD_Struct *motd = (RaidMOTD_Struct *)app->pBuffer; - raid->SetRaidMOTD(std::string(motd->motd)); - raid->SaveRaidMOTD(); - raid->SendRaidMOTDToWorld(); - break; + if (raid->IsLocked()) + raid->LockRaid(false); + else + raid->SendRaidUnlockTo(this); } + break; + } + case RaidCommandLootType2: + case RaidCommandLootType: + { + Raid* raid = entity_list.GetRaidByClient(this); + if (raid) { + Message(Chat::Yellow, "Loot type changed to: %d.", raid_command_packet->parameter); + raid->ChangeLootType(raid_command_packet->parameter); + } + break; + } - default: { - Message(Chat::Red, "Raid command (%d) NYI", raid_command_packet->action); - break; + case RaidCommandAddLooter2: + case RaidCommandAddLooter: + { + Raid* raid = entity_list.GetRaidByClient(this); + if (raid) { + Message(Chat::Yellow, "Adding %s as a raid looter.", raid_command_packet->leader_name); + raid->AddRaidLooter(raid_command_packet->leader_name); } + break; + } + + case RaidCommandRemoveLooter2: + case RaidCommandRemoveLooter: + { + Raid* raid = entity_list.GetRaidByClient(this); + if (raid) { + Message(Chat::Yellow, "Removing %s as a raid looter.", raid_command_packet->leader_name); + raid->RemoveRaidLooter(raid_command_packet->leader_name); + } + break; + } + + case RaidCommandMakeLeader: + { + Raid* raid = entity_list.GetRaidByClient(this); + if (raid) { + if (strcmp(raid->leadername, GetName()) == 0) { + raid->SetRaidLeader(GetName(), raid_command_packet->leader_name); + raid->UpdateRaidAAs(); + raid->SendAllRaidLeadershipAA(); + } + } + break; + } + + case RaidCommandSetMotd: + { + Raid* raid = entity_list.GetRaidByClient(this); + if (!raid) + break; + // we don't use the RaidGeneral here! + RaidMOTD_Struct* motd = (RaidMOTD_Struct*)app->pBuffer; + raid->SetRaidMOTD(std::string(motd->motd)); + raid->SaveRaidMOTD(); + raid->SendRaidMOTDToWorld(); + break; + } + + default: { + Message(Chat::Red, "Raid command (%d) NYI", raid_command_packet->action); + break; + } } } - + void Client::Handle_OP_RandomReq(const EQApplicationPacket *app) { if (app->size != sizeof(RandomReq_Struct)) { From 0d009a7a258630b178db71827510f9fd91d9bb1f Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Sat, 15 Jan 2022 11:27:19 -0400 Subject: [PATCH 24/55] Start of moving raid bot functions to their own methods --- bin/zone/bot_raid.cpp | 34 ++++++++++++++++++++++++++++++++ bin/zone/bot_raid.h | 46 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 bin/zone/bot_raid.cpp create mode 100644 bin/zone/bot_raid.h diff --git a/bin/zone/bot_raid.cpp b/bin/zone/bot_raid.cpp new file mode 100644 index 000000000..dd65d68ad --- /dev/null +++ b/bin/zone/bot_raid.cpp @@ -0,0 +1,34 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifdef BOTS + +#include "bot.h" +#include "bot_raid.h" +#include "object.h" +#include "raids.h" +#include "doors.h" +#include "quest_parser_collection.h" +#include "lua_parser.h" +#include "../common/string_util.h" +#include "../common/say_link.h" + +extern volatile bool is_zone_loaded; +extern bool Critical; + +#endif diff --git a/bin/zone/bot_raid.h b/bin/zone/bot_raid.h new file mode 100644 index 000000000..ab012b381 --- /dev/null +++ b/bin/zone/bot_raid.h @@ -0,0 +1,46 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef BOT_H +#define BOT_H + +#ifdef BOTS + +#include "bot_structs.h" +#include "mob.h" +#include "client.h" +#include "pets.h" +#include "heal_rotation.h" +#include "groups.h" +#include "corpse.h" +#include "zonedb.h" +#include "zone_store.h" +#include "string_ids.h" +#include "../common/misc_functions.h" +#include "../common/global_define.h" +#include "guild_mgr.h" +#include "worldserver.h" + +#include + + +extern WorldServer worldserver; + +#endif // BOTS + +#endif // BOT_H From 37e9d419e60d6de7bce90b1e2f03480658c61c8a Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Sat, 15 Jan 2022 11:27:50 -0400 Subject: [PATCH 25/55] More bot raid changes --- bin/zone/bot_raid.cpp | 34 - zone/bot.cpp | 19 +- zone/bot.h | 8 +- zone/bot_raid.cpp | 1530 +++++++++++++++++++++++++++++++++ {bin/zone => zone}/bot_raid.h | 9 +- zone/botspellsai.cpp | 7 + zone/raids.h | 1 + 7 files changed, 1555 insertions(+), 53 deletions(-) delete mode 100644 bin/zone/bot_raid.cpp create mode 100644 zone/bot_raid.cpp rename {bin/zone => zone}/bot_raid.h (93%) diff --git a/bin/zone/bot_raid.cpp b/bin/zone/bot_raid.cpp deleted file mode 100644 index dd65d68ad..000000000 --- a/bin/zone/bot_raid.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY except by those people which sell it, which - are required to give you total support for your newly bought product; - without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifdef BOTS - -#include "bot.h" -#include "bot_raid.h" -#include "object.h" -#include "raids.h" -#include "doors.h" -#include "quest_parser_collection.h" -#include "lua_parser.h" -#include "../common/string_util.h" -#include "../common/say_link.h" - -extern volatile bool is_zone_loaded; -extern bool Critical; - -#endif diff --git a/zone/bot.cpp b/zone/bot.cpp index 09486f678..e345bf50a 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -2300,7 +2300,11 @@ bool Bot::Process() } // Bot AI - AI_Process(); + Raid* raid = entity_list.GetRaidByBot(this); + if (raid) + AI_Process_Raid(); + else + AI_Process(); return true; } @@ -2540,12 +2544,10 @@ void Bot::AI_Process() Client* bot_owner = (GetBotOwner() && GetBotOwner()->IsClient() ? GetBotOwner()->CastToClient() : nullptr); Group* bot_group = GetGroup(); - Raid* bot_raid = entity_list.GetRaidByBot(this); - //#pragma region PRIMARY AI SKIP CHECKS // Primary reasons for not processing AI - if (!bot_owner || (!bot_group && !bot_raid) || !IsAIControlled()) { + if (!bot_owner || (!bot_group) || !IsAIControlled()) { return; } @@ -2563,15 +2565,6 @@ void Bot::AI_Process() if (bot_group) { leash_owner = (bot_group->GetLeader() && bot_group->GetLeader()->IsClient() ? bot_group->GetLeader()->CastToClient() : bot_owner); } - else if (bot_raid) { - int bot_raid_group = bot_raid->GetGroup(GetName()); - if (bot_raid_group > 0) { - leash_owner = bot_raid->GetGroupLeader(bot_raid_group)->CastToClient(); - } - else { - leash_owner = bot_raid->GetLeader(); - } - } if (!leash_owner) { return; diff --git a/zone/bot.h b/zone/bot.h index a553c2f6c..8062c645a 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -362,8 +362,6 @@ public: static std::string RaceIdToString(uint16 raceId); static bool IsBotAttackAllowed(Mob* attacker, Mob* target, bool& hasRuleDefined); static Bot* GetBotByBotClientOwnerAndBotName(Client* c, std::string botName); - static void ProcessRaidInvite(Bot* invitee, Client* invitor); //Mitch - static void ProcessRaidInvite(Client* invitee, Client* invitor); //Mitch static void ProcessBotGroupInvite(Client* c, std::string botName); static void ProcessBotGroupDisband(Client* c, std::string botName); static void BotOrderCampAll(Client* c); @@ -381,6 +379,12 @@ public: static bool CheckDisciplineRecastTimers(Bot *caster, int timer_index); static uint32 GetDisciplineRemainingTime(Bot *caster, int timer_index); + //Raid methods + void PetAIProcess_Raid(); + void AI_Process_Raid(); + static void ProcessRaidInvite(Bot* invitee, Client* invitor); //Mitch + static void ProcessRaidInvite(Client* invitee, Client* invitor); //Mitch + static std::list GetBotSpellsForSpellEffect(Bot* botCaster, int spellEffect); static std::list GetBotSpellsForSpellEffectAndTargetType(Bot* botCaster, int spellEffect, SpellTargetType targetType); static std::list GetBotSpellsBySpellType(Bot* botCaster, uint32 spellType); diff --git a/zone/bot_raid.cpp b/zone/bot_raid.cpp new file mode 100644 index 000000000..b695b2de6 --- /dev/null +++ b/zone/bot_raid.cpp @@ -0,0 +1,1530 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifdef BOTS + +#include "bot.h" +#include "bot_raid.h" +#include "object.h" +#include "raids.h" +#include "doors.h" +#include "quest_parser_collection.h" +#include "lua_parser.h" +#include "../common/string_util.h" +#include "../common/say_link.h" + +extern volatile bool is_zone_loaded; +extern bool Critical; + +// AI Processing for the Bot object + +constexpr float MAX_CASTER_DISTANCE[PLAYER_CLASS_COUNT] = { + 0, (34 * 34), (24 * 24), (28 * 28), (26 * 26), (42 * 42), 0, (30 * 30), 0, (38 * 38), (54 * 54), (48 * 48), (52 * 52), (50 * 50), (32 * 32), 0 + // W C P R S D M B R S N W M E B B + // A L A N H R N R O H E I A N S E + // R R L G D U K D G M C Z G C T R +}; + +void Bot::AI_Process_Raid() +{ +#define TEST_COMBATANTS() if (!GetTarget() || GetAppearance() == eaDead) { return; } +#define PULLING_BOT (GetPullingFlag() || GetReturningFlag()) +#define NOT_PULLING_BOT (!GetPullingFlag() && !GetReturningFlag()) +#define GUARDING (GetGuardFlag()) +#define NOT_GUARDING (!GetGuardFlag()) +#define HOLDING (GetHoldFlag()) +#define NOT_HOLDING (!GetHoldFlag()) +#define PASSIVE (GetBotStance() == EQ::constants::stancePassive) +#define NOT_PASSIVE (GetBotStance() != EQ::constants::stancePassive) + + Raid* raid = entity_list.GetRaidByBot(this); + Client* bot_owner = (GetBotOwner() && GetBotOwner()->IsClient() ? GetBotOwner()->CastToClient() : nullptr); + int r_group = raid->GetGroup(GetName()); + + LogAI("Bot_Raid: Entered Raid Process() for [{}].", this->GetCleanName()); + + //#pragma region PRIMARY AI SKIP CHECKS + + // Primary reasons for not processing AI + if (!bot_owner || (!raid) || !IsAIControlled()) { + return; + } + + if (bot_owner->IsDead()) { + + SetTarget(nullptr); + SetBotOwner(nullptr); + + return; + } + + // We also need a leash owner and follow mob (subset of primary AI criteria) + Client* leash_owner = nullptr; + if (r_group > 0) { + leash_owner = raid->GetGroupLeader(r_group)->CastToClient(); + } + else { + leash_owner = raid->GetLeader(); + } + + if (!leash_owner) { + return; + } + + //#pragma endregion + + Mob* follow_mob = entity_list.GetMob(GetFollowID()); + if (!follow_mob) { + + follow_mob = leash_owner; + SetFollowID(leash_owner->GetID()); + } + + // Berserk updates should occur if primary AI criteria are met + if (GetClass() == WARRIOR || GetClass() == BERSERKER) { + + if (!berserk && GetHP() > 0 && GetHPRatio() < 30.0f) { + + entity_list.MessageCloseString(this, false, 200, 0, BERSERK_START, GetName()); + berserk = true; + } + + if (berserk && GetHPRatio() >= 30.0f) { + + entity_list.MessageCloseString(this, false, 200, 0, BERSERK_END, GetName()); + berserk = false; + } + } + + //#pragma region SECONDARY AI SKIP CHECKS + + // Secondary reasons for not processing AI + if (GetPauseAI() || IsStunned() || IsMezzed() || (GetAppearance() == eaDead)) { + + if (IsCasting()) { + InterruptSpell(); + } + + if (IsMyHealRotationSet() || (AmICastingForHealRotation() && m_member_of_heal_rotation->CastingMember() == this)) { + + AdvanceHealRotation(false); + m_member_of_heal_rotation->SetMemberIsCasting(this, false); + } + + return; + } + + //#pragma endregion + + float fm_distance = DistanceSquared(m_Position, follow_mob->GetPosition()); + float lo_distance = DistanceSquared(m_Position, leash_owner->GetPosition()); + float leash_distance = RuleR(Bots, LeashDistance); + + //#pragma region CURRENTLY CASTING CHECKS + + if (IsCasting()) { + + if (IsHealRotationMember() && + m_member_of_heal_rotation->CastingOverride() && + m_member_of_heal_rotation->CastingTarget() != nullptr && + m_member_of_heal_rotation->CastingReady() && + m_member_of_heal_rotation->CastingMember() == this && + !m_member_of_heal_rotation->MemberIsCasting(this)) + { + InterruptSpell(); + } + else if (AmICastingForHealRotation() && m_member_of_heal_rotation->CastingMember() == this) { + + AdvanceHealRotation(false); + return; + } + else if (GetClass() != BARD) { + + if (IsEngaged()) { + return; + } + + if ( + (NOT_GUARDING && fm_distance > GetFollowDistance()) || // Cancel out-of-combat casting if movement to follow mob is required + (GUARDING && DistanceSquared(GetPosition(), GetGuardPoint()) > GetFollowDistance()) // Cancel out-of-combat casting if movement to guard point is required + ) { + InterruptSpell(); + } + + return; + } + } + else if (IsHealRotationMember()) { + m_member_of_heal_rotation->SetMemberIsCasting(this, false); + } + + //#pragma endregion + + // Can't move if rooted... + if (IsRooted() && IsMoving()) { + + StopMoving(); + return; + } + + //#pragma region HEAL ROTATION CASTING CHECKS + + if (IsMyHealRotationSet()) { + + if (AIHealRotation(HealRotationTarget(), UseHealRotationFastHeals())) { + + m_member_of_heal_rotation->SetMemberIsCasting(this); + m_member_of_heal_rotation->UpdateTargetHealingStats(HealRotationTarget()); + AdvanceHealRotation(); + } + else { + + m_member_of_heal_rotation->SetMemberIsCasting(this, false); + AdvanceHealRotation(false); + } + } + + //#pragma endregion + + bool bo_alt_combat = (RuleB(Bots, AllowOwnerOptionAltCombat) && bot_owner->GetBotOption(Client::booAltCombat)); + + //#pragma region ATTACK FLAG + + if (GetAttackFlag()) { // Push owner's target onto our hate list + + if (GetPet() && PULLING_BOT) { + GetPet()->SetPetOrder(m_previous_pet_order); + } + + SetAttackFlag(false); + SetAttackingFlag(false); + SetPullFlag(false); + SetPullingFlag(false); + SetReturningFlag(false); + bot_owner->SetBotPulling(false); + + if (NOT_HOLDING && NOT_PASSIVE) { + + auto attack_target = bot_owner->GetTarget(); + if (attack_target) { + + InterruptSpell(); + WipeHateList(); + AddToHateList(attack_target, 1); + SetTarget(attack_target); + SetAttackingFlag(); + if (HasPet() && (GetClass() != ENCHANTER || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 2)) { + + GetPet()->WipeHateList(); + GetPet()->AddToHateList(attack_target, 1); + GetPet()->SetTarget(attack_target); + } + } + } + } + + //#pragma endregion + + //#pragma region PULL FLAG + + else if (GetPullFlag()) { // Push owner's target onto our hate list and set flags so other bots do not aggro + + SetAttackFlag(false); + SetAttackingFlag(false); + SetPullFlag(false); + SetPullingFlag(false); + SetReturningFlag(false); + bot_owner->SetBotPulling(false); + + if (NOT_HOLDING && NOT_PASSIVE) { + + auto pull_target = bot_owner->GetTarget(); + if (pull_target) { + + Bot::BotGroupSay(this, "Pulling %s to the group..", pull_target->GetCleanName()); + InterruptSpell(); + WipeHateList(); + AddToHateList(pull_target, 1); + SetTarget(pull_target); + SetPullingFlag(); + bot_owner->SetBotPulling(); + if (HasPet() && (GetClass() != ENCHANTER || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 1)) { + + GetPet()->WipeHateList(); + GetPet()->SetTarget(nullptr); + m_previous_pet_order = GetPet()->GetPetOrder(); + GetPet()->SetPetOrder(SPO_Guard); + } + } + } + } + + //#pragma endregion + + //#pragma region ALT COMBAT (ACQUIRE HATE) + + else if (bo_alt_combat && m_alt_combat_hate_timer.Check(false)) { // 'Alt Combat' gives some more 'control' options on how bots process aggro + + // Empty hate list - let's find some aggro + if (!IsEngaged() && NOT_HOLDING && NOT_PASSIVE && (!bot_owner->GetBotPulling() || NOT_PULLING_BOT)) { + + Mob* lo_target = leash_owner->GetTarget(); + if (lo_target && + lo_target->IsNPC() && + !lo_target->IsMezzed() && + ((bot_owner->GetBotOption(Client::booAutoDefend) && lo_target->GetHateAmount(leash_owner)) || leash_owner->AutoAttackEnabled()) && + lo_distance <= leash_distance && + DistanceSquared(m_Position, lo_target->GetPosition()) <= leash_distance && + (CheckLosFN(lo_target) || leash_owner->CheckLosFN(lo_target)) && + IsAttackAllowed(lo_target)) + { + AddToHateList(lo_target, 1); + if (HasPet() && (GetClass() != ENCHANTER || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 2)) { + + GetPet()->AddToHateList(lo_target, 1); + GetPet()->SetTarget(lo_target); + } + } + else { + + std::vector raid_group_members = raid->GetRaidGroupMembers(r_group); + for (RaidMember iter : raid_group_members) { + +// for (int counter = 0; counter < raid->GroupCount(r_group); counter++) { +// Group* bot_group = this->GetGroup(); + Mob* bg_member = iter.member;// bot_group->members[counter]; + if (!bg_member) { + continue; + } + + Mob* bgm_target = bg_member->GetTarget(); + if (!bgm_target || !bgm_target->IsNPC()) { + continue; + } + + if (!bgm_target->IsMezzed() && + ((bot_owner->GetBotOption(Client::booAutoDefend) && bgm_target->GetHateAmount(bg_member)) || leash_owner->AutoAttackEnabled()) && + lo_distance <= leash_distance && + DistanceSquared(m_Position, bgm_target->GetPosition()) <= leash_distance && + (CheckLosFN(bgm_target) || leash_owner->CheckLosFN(bgm_target)) && + IsAttackAllowed(bgm_target)) + { + AddToHateList(bgm_target, 1); + if (HasPet() && (GetClass() != ENCHANTER || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 2)) { + + GetPet()->AddToHateList(bgm_target, 1); + GetPet()->SetTarget(bgm_target); + } + + break; + } + } + } + } + } + + //#pragma endregion + + glm::vec3 Goal(0, 0, 0); + + // We have aggro to choose from + if (IsEngaged()) { + + if (rest_timer.Enabled()) { + rest_timer.Disable(); + } + + //#pragma region PULLING FLAG (TARGET VALIDATION) + + if (GetPullingFlag()) { + + if (!GetTarget()) { + + WipeHateList(); + SetTarget(nullptr); + SetPullingFlag(false); + SetReturningFlag(false); + bot_owner->SetBotPulling(false); + if (GetPet()) { + GetPet()->SetPetOrder(m_previous_pet_order); + } + + return; + } + else if (GetTarget()->GetHateList().size()) { + + WipeHateList(); + SetTarget(nullptr); + SetPullingFlag(false); + SetReturningFlag(); + + return; + } + else { + // Default action is to aggress towards enemy + } + } + + //#pragma endregion + + //#pragma region RETURNING FLAG + + else if (GetReturningFlag()) { + + // Need to make it back to group before clearing return flag + if (fm_distance <= GetFollowDistance()) { + + // Once we're back, clear blocking flags so everyone else can join in + SetReturningFlag(false); + bot_owner->SetBotPulling(false); + if (GetPet()) { + GetPet()->SetPetOrder(m_previous_pet_order); + } + } + + // Need to keep puller out of combat until they reach their 'return to' destination + if (HasTargetReflection()) { + + SetTarget(nullptr); + WipeHateList(); + + return; + } + } + + //#pragma endregion + + //#pragma region ALT COMBAT (ACQUIRE TARGET) + + else if (bo_alt_combat && m_alt_combat_hate_timer.Check()) { // Find a mob from hate list to target + + // Group roles can be expounded upon in the future + Group* bot_group = this->GetGroup(); //Mitch + auto assist_mob = entity_list.GetMob(bot_group->GetMainAssistName()); + bool find_target = true; + + if (assist_mob) { + + if (assist_mob->GetTarget()) { + + if (assist_mob != this) { + + SetTarget(assist_mob->GetTarget()); + if (HasPet() && (GetClass() != ENCHANTER || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 2)) { + + // This artificially inflates pet's target aggro..but, less expensive than checking hate each AI process + GetPet()->AddToHateList(assist_mob->GetTarget(), 1); + GetPet()->SetTarget(assist_mob->GetTarget()); + } + } + + find_target = false; + } + else if (assist_mob != this) { + + SetTarget(nullptr); + if (HasPet() && (GetClass() != ENCHANTER || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 1)) { + + GetPet()->WipeHateList(); + GetPet()->SetTarget(nullptr); + } + + find_target = false; + } + } + + if (find_target) { + + if (IsRooted()) { + SetTarget(hate_list.GetClosestEntOnHateList(this, true)); + } + else { + + // This will keep bots on target for now..but, future updates will allow for rooting/stunning + SetTarget(hate_list.GetEscapingEntOnHateList(leash_owner, leash_distance)); + if (!GetTarget()) { + SetTarget(hate_list.GetEntWithMostHateOnList(this, nullptr, true)); + } + } + } + } + + //#pragma endregion + + //#pragma region DEFAULT (ACQUIRE TARGET) + + else { + + // Default behavior doesn't have a means of acquiring a target from the bot's hate list.. + // ..that action occurs through commands or out-of-combat checks + // (Use current target, if already in combat) + } + + //#pragma endregion + + //#pragma region VERIFY TARGET AND STANCE + + Mob* tar = GetTarget(); // We should have a target..if not, we're awaiting new orders + if (!tar || PASSIVE) { + + SetTarget(nullptr); + WipeHateList(); + SetAttackFlag(false); + SetAttackingFlag(false); + if (PULLING_BOT) { + + // 'Flags' should only be set on the bot that is pulling + SetPullingFlag(false); + SetReturningFlag(false); + bot_owner->SetBotPulling(false); + if (GetPet()) { + GetPet()->SetPetOrder(m_previous_pet_order); + } + } + + if (GetArchetype() == ARCHETYPE_CASTER) { + BotMeditate(true); + } + + return; + } + + //#pragma endregion + + //#pragma region ATTACKING FLAG (HATE VALIDATION) + + if (GetAttackingFlag() && tar->CheckAggro(this)) { + SetAttackingFlag(false); + } + + //#pragma endregion + + float tar_distance = DistanceSquared(m_Position, tar->GetPosition()); + + //#pragma region TARGET VALIDATION + + // DOUBLE-CHECK THIS CRITERIA + + // Verify that our target has attackable criteria + if (HOLDING || + !tar->IsNPC() || + tar->IsMezzed() || + lo_distance > leash_distance || + tar_distance > leash_distance || + (!GetAttackingFlag() && !CheckLosFN(tar) && !leash_owner->CheckLosFN(tar)) || // This is suppose to keep bots from attacking things behind walls + !IsAttackAllowed(tar) || + (bo_alt_combat && + (!GetAttackingFlag() && NOT_PULLING_BOT && !leash_owner->AutoAttackEnabled() && !tar->GetHateAmount(this) && !tar->GetHateAmount(leash_owner)) + ) + ) + { + // Normally, we wouldn't want to do this without class checks..but, too many issues can arise if we let enchanter animation pets run rampant + if (HasPet()) { + + GetPet()->RemoveFromHateList(tar); + GetPet()->SetTarget(nullptr); + } + + RemoveFromHateList(tar); + SetTarget(nullptr); + + SetAttackFlag(false); + SetAttackingFlag(false); + if (PULLING_BOT) { + + SetPullingFlag(false); + SetReturningFlag(false); + bot_owner->SetBotPulling(false); + if (GetPet()) { + GetPet()->SetPetOrder(m_previous_pet_order); + } + } + + if (IsMoving()) { + StopMoving(); + } + + return; + } + + //#pragma endregion + + // This causes conflicts with default pet handler (bounces between targets) + if (NOT_PULLING_BOT && HasPet() && (GetClass() != ENCHANTER || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 2)) { + + // We don't add to hate list here because it's assumed to already be on the list + GetPet()->SetTarget(tar); + } + + if (DivineAura()) { + return; + } + + if (!(m_PlayerState & static_cast(PlayerState::Aggressive))) { + SendAddPlayerState(PlayerState::Aggressive); + } + + //#pragma region PULLING FLAG (ACTIONABLE RANGE) + + if (GetPullingFlag()) { + + constexpr size_t PULL_AGGRO = 5225; // spells[5225]: 'Throw Stone' - 0 cast time + + if (tar_distance <= (spells[PULL_AGGRO].range * spells[PULL_AGGRO].range)) { + + StopMoving(); + CastSpell(PULL_AGGRO, tar->GetID()); + return; + } + } + + //#pragma endregion + + //#pragma region COMBAT RANGE CALCS + + bool atCombatRange = false; + + const auto* p_item = GetBotItem(EQ::invslot::slotPrimary); + const auto* s_item = GetBotItem(EQ::invslot::slotSecondary); + + bool behind_mob = false; + bool backstab_weapon = false; + if (GetClass() == ROGUE) { + + behind_mob = BehindMob(tar, GetX(), GetY()); // Can be separated for other future use + backstab_weapon = p_item && p_item->GetItemBackstabDamage(); + } + + // Calculate melee distances + float melee_distance_max = 0.0f; + float melee_distance = 0.0f; + { + float size_mod = GetSize(); + float other_size_mod = tar->GetSize(); + + if (GetRace() == RT_DRAGON || GetRace() == RT_WURM || GetRace() == RT_DRAGON_7) { // For races with a fixed size + size_mod = 60.0f; + } + else if (size_mod < 6.0f) { + size_mod = 8.0f; + } + + if (tar->GetRace() == RT_DRAGON || tar->GetRace() == RT_WURM || tar->GetRace() == RT_DRAGON_7) { // For races with a fixed size + other_size_mod = 60.0f; + } + else if (other_size_mod < 6.0f) { + other_size_mod = 8.0f; + } + + if (other_size_mod > size_mod) { + size_mod = other_size_mod; + } + + if (size_mod > 29.0f) { + size_mod *= size_mod; + } + else if (size_mod > 19.0f) { + size_mod *= (size_mod * 2.0f); + } + else { + size_mod *= (size_mod * 4.0f); + } + + // Prevention of ridiculously sized hit boxes + if (size_mod > 10000.0f) { + size_mod = (size_mod / 7.0f); + } + + melee_distance_max = size_mod; + + switch (GetClass()) { + case WARRIOR: + case PALADIN: + case SHADOWKNIGHT: + if (p_item && p_item->GetItem()->IsType2HWeapon()) { + melee_distance = melee_distance_max * 0.45f; + } + else if ((s_item && s_item->GetItem()->IsTypeShield()) || (!p_item && !s_item)) { + melee_distance = melee_distance_max * 0.35f; + } + else { + melee_distance = melee_distance_max * 0.40f; + } + + break; + case NECROMANCER: + case WIZARD: + case MAGICIAN: + case ENCHANTER: + if (p_item && p_item->GetItem()->IsType2HWeapon()) { + melee_distance = melee_distance_max * 0.95f; + } + else { + melee_distance = melee_distance_max * 0.75f; + } + + break; + case ROGUE: + if (behind_mob && backstab_weapon) { + if (p_item->GetItem()->IsType2HWeapon()) { // 'p_item' tested in 'backstab_weapon' check above + melee_distance = melee_distance_max * 0.30f; + } + else { + melee_distance = melee_distance_max * 0.25f; + } + + break; + } + // Fall-through + default: + if (p_item && p_item->GetItem()->IsType2HWeapon()) { + melee_distance = melee_distance_max * 0.70f; + } + else { + melee_distance = melee_distance_max * 0.50f; + } + + break; + } + } + float melee_distance_min = melee_distance / 2.0f; + + // Calculate caster distances + float caster_distance_max = 0.0f; + float caster_distance_min = 0.0f; + float caster_distance = 0.0f; + { + if (GetLevel() >= GetStopMeleeLevel() && GetClass() >= WARRIOR && GetClass() <= BERSERKER) { + caster_distance_max = MAX_CASTER_DISTANCE[(GetClass() - 1)]; + } + + if (caster_distance_max) { + + caster_distance_min = melee_distance_max; + if (caster_distance_max <= caster_distance_min) { + caster_distance_max = caster_distance_min * 1.25f; + } + + caster_distance = ((caster_distance_max + caster_distance_min) / 2); + } + } + + bool atArcheryRange = IsArcheryRange(tar); + + if (GetRangerAutoWeaponSelect()) { + + bool changeWeapons = false; + + if (atArcheryRange && !IsBotArcher()) { + + SetBotArcher(true); + changeWeapons = true; + } + else if (!atArcheryRange && IsBotArcher()) { + + SetBotArcher(false); + changeWeapons = true; + } + + if (changeWeapons) { + ChangeBotArcherWeapons(IsBotArcher()); + } + } + + if (IsBotArcher() && atArcheryRange) { + atCombatRange = true; + } + else if (caster_distance_max && tar_distance <= caster_distance_max) { + atCombatRange = true; + } + else if (tar_distance <= melee_distance) { + atCombatRange = true; + } + + //#pragma endregion + + //#pragma region ENGAGED AT COMBAT RANGE + + // We can fight + if (atCombatRange) { + + //if (IsMoving() || GetCombatJitterFlag()) { // StopMoving() needs to be called so that the jitter timer can be reset + if (IsMoving()) { + + // Since we're using a pseudo-shadowstep for jitter, disregard the combat jitter flag + //if (!GetCombatJitterFlag()) { + StopMoving(CalculateHeadingToTarget(tar->GetX(), tar->GetY())); + //} + + return; + } + + // Combat 'jitter' code + // Note: Combat Jitter is disabled until a working movement solution can be found + if (AI_movement_timer->Check() && (!spellend_timer.Enabled() || GetClass() == BARD)) { + + if (!IsRooted()) { + + if (HasTargetReflection()) { + + if (!tar->IsFeared() && !tar->IsStunned()) { + + if (GetClass() == ROGUE) { + + if (m_evade_timer.Check(false)) { // Attempt to evade + + int timer_duration = (HideReuseTime - GetSkillReuseTime(EQ::skills::SkillHide)) * 1000; + if (timer_duration < 0) { + timer_duration = 0; + } + + m_evade_timer.Start(timer_duration); + if (zone->random.Int(0, 260) < (int)GetSkill(EQ::skills::SkillHide)) { + RogueEvade(tar); + } + + return; + } + } + + //if (tar->IsRooted()) { // Move caster/rogue back from rooted mob - out of combat range, if necessary + + // if (GetArchetype() == ARCHETYPE_CASTER || GetClass() == ROGUE) { + + // if (tar_distance <= melee_distance_max) { + + // if (PlotPositionAroundTarget(this, Goal.x, Goal.y, Goal.z)) { + // //if (PlotPositionBehindMeFacingTarget(tar, Goal.x, Goal.y, Goal.z)) { + + // Teleport(Goal); + // //WalkTo(Goal.x, Goal.y, Goal.z); + // SetCombatJitterFlag(); + + // return; + // } + // } + // } + //} + } + } + //else { + + // if (caster_distance_min && tar_distance < caster_distance_min && !tar->IsFeared()) { // Caster back-off adjustment + + // if (PlotPositionAroundTarget(this, Goal.x, Goal.y, Goal.z)) { + // //if (PlotPositionBehindMeFacingTarget(tar, Goal.x, Goal.y, Goal.z)) { + + // if (DistanceSquared(Goal, tar->GetPosition()) <= caster_distance_max) { + + // Teleport(Goal); + // //WalkTo(Goal.x, Goal.y, Goal.z); + // SetCombatJitterFlag(); + + // return; + // } + // } + // } + // else if (tar_distance < melee_distance_min) { // Melee back-off adjustment + + // if (PlotPositionAroundTarget(this, Goal.x, Goal.y, Goal.z)) { + // //if (PlotPositionBehindMeFacingTarget(tar, Goal.x, Goal.y, Goal.z)) { + + // if (DistanceSquared(Goal, tar->GetPosition()) <= melee_distance_max) { + + // Teleport(Goal); + // //WalkTo(Goal.x, Goal.y, Goal.z); + // SetCombatJitterFlag(); + + // return; + // } + // } + // } + // else if (backstab_weapon && !behind_mob) { // Move the rogue to behind the mob + + // if (PlotPositionAroundTarget(tar, Goal.x, Goal.y, Goal.z)) { + // //if (PlotPositionOnArcBehindTarget(tar, Goal.x, Goal.y, Goal.z, melee_distance)) { + + // float distance_squared = DistanceSquared(Goal, tar->GetPosition()); + // if (/*distance_squared >= melee_distance_min && */distance_squared <= melee_distance_max) { + + // Teleport(Goal); + // //RunTo(Goal.x, Goal.y, Goal.z); + // SetCombatJitterFlag(); + + // return; + // } + // } + // } + // else if (m_combat_jitter_timer.Check()) { + + // if (!caster_distance && PlotPositionAroundTarget(tar, Goal.x, Goal.y, Goal.z)) { + // //if (!caster_distance && PlotPositionOnArcInFrontOfTarget(tar, Goal.x, Goal.y, Goal.z, melee_distance)) { + + // float distance_squared = DistanceSquared(Goal, tar->GetPosition()); + // if (/*distance_squared >= melee_distance_min && */distance_squared <= melee_distance_max) { + + // Teleport(Goal); + // //WalkTo(Goal.x, Goal.y, Goal.z); + // SetCombatJitterFlag(); + + // return; + // } + // } + // else if (caster_distance && PlotPositionAroundTarget(tar, Goal.x, Goal.y, Goal.z)) { + // //else if (caster_distance && PlotPositionOnArcInFrontOfTarget(tar, Goal.x, Goal.y, Goal.z, caster_distance)) { + + // float distance_squared = DistanceSquared(Goal, tar->GetPosition()); + // if (/*distance_squared >= caster_distance_min && */distance_squared <= caster_distance_max) { + + // Teleport(Goal); + // //WalkTo(Goal.x, Goal.y, Goal.z); + // SetCombatJitterFlag(); + + // return; + // } + // } + // } + + // if (!IsFacingMob(tar)) { + + // FaceTarget(tar); + // return; + // } + //} + } + else { + + if (!IsSitting() && !IsFacingMob(tar)) { + + FaceTarget(tar); + return; + } + } + } + + if (!IsBotNonSpellFighter() && AI_EngagedCastCheck()) { + return; + } + + // Up to this point, GetTarget() has been safe to dereference since the initial + // TEST_COMBATANTS() call. Due to the chance of the target dying and our pointer + // being nullified, we need to test it before dereferencing to avoid crashes + + if (IsBotArcher() && ranged_timer.Check(false)) { // Can shoot mezzed, stunned and dead!? + + TEST_COMBATANTS(); + if (GetTarget()->GetHPRatio() <= 99.0f) { + BotRangedAttack(tar); + } + } + else if (!IsBotArcher() && GetLevel() < GetStopMeleeLevel()) { + + // We can't fight if we don't have a target, are stun/mezzed or dead.. + // Stop attacking if the target is enraged + TEST_COMBATANTS(); + if (tar->IsEnraged() && !BehindMob(tar, GetX(), GetY())) { + return; + } + + // First, special attack per class (kick, backstab etc..) + TEST_COMBATANTS(); + DoClassAttacks(tar); + + TEST_COMBATANTS(); + if (attack_timer.Check()) { // Process primary weapon attacks + + Attack(tar, EQ::invslot::slotPrimary); + + TEST_COMBATANTS(); + TriggerDefensiveProcs(tar, EQ::invslot::slotPrimary, false); + + TEST_COMBATANTS(); + TryWeaponProc(p_item, tar, EQ::invslot::slotPrimary); + + // bool tripleSuccess = false; + + TEST_COMBATANTS(); + if (CanThisClassDoubleAttack()) { + + if (CheckBotDoubleAttack()) { + Attack(tar, EQ::invslot::slotPrimary, true); + } + + TEST_COMBATANTS(); + if (GetSpecialAbility(SPECATK_TRIPLE) && CheckBotDoubleAttack(true)) { + // tripleSuccess = true; + Attack(tar, EQ::invslot::slotPrimary, true); + } + + TEST_COMBATANTS(); + // quad attack, does this belong here?? + if (GetSpecialAbility(SPECATK_QUAD) && CheckBotDoubleAttack(true)) { + Attack(tar, EQ::invslot::slotPrimary, true); + } + } + + TEST_COMBATANTS(); + // Live AA - Flurry, Rapid Strikes ect (Flurry does not require Triple Attack). + int32 flurrychance = (aabonuses.FlurryChance + spellbonuses.FlurryChance + itembonuses.FlurryChance); + if (flurrychance) { + + if (zone->random.Int(0, 100) < flurrychance) { + + MessageString(Chat::NPCFlurry, YOU_FLURRY); + Attack(tar, EQ::invslot::slotPrimary, false); + + TEST_COMBATANTS(); + Attack(tar, EQ::invslot::slotPrimary, false); + } + } + + TEST_COMBATANTS(); + int32 ExtraAttackChanceBonus = (spellbonuses.ExtraAttackChance + itembonuses.ExtraAttackChance + aabonuses.ExtraAttackChance); + if (ExtraAttackChanceBonus) { + + if (p_item && p_item->GetItem()->IsType2HWeapon()) { + + if (zone->random.Int(0, 100) < ExtraAttackChanceBonus) { + Attack(tar, EQ::invslot::slotPrimary, false); + } + } + } + } + + TEST_COMBATANTS(); + if (attack_dw_timer.Check() && CanThisClassDualWield()) { // Process secondary weapon attacks + + const EQ::ItemData* s_itemdata = nullptr; + // Can only dual wield without a weapon if you're a monk + if (s_item || (GetClass() == MONK)) { + + if (s_item) { + s_itemdata = s_item->GetItem(); + } + + int weapon_type = 0; // No weapon type. + bool use_fist = true; + if (s_itemdata) { + + weapon_type = s_itemdata->ItemType; + use_fist = false; + } + + if (use_fist || !s_itemdata->IsType2HWeapon()) { + + float DualWieldProbability = 0.0f; + + int32 Ambidexterity = (aabonuses.Ambidexterity + spellbonuses.Ambidexterity + itembonuses.Ambidexterity); + DualWieldProbability = ((GetSkill(EQ::skills::SkillDualWield) + GetLevel() + Ambidexterity) / 400.0f); // 78.0 max + + int32 DWBonus = (spellbonuses.DualWieldChance + itembonuses.DualWieldChance); + DualWieldProbability += (DualWieldProbability * float(DWBonus) / 100.0f); + + float random = zone->random.Real(0, 1); + if (random < DualWieldProbability) { // Max 78% of DW + + Attack(tar, EQ::invslot::slotSecondary); // Single attack with offhand + + TEST_COMBATANTS(); + TryWeaponProc(s_item, tar, EQ::invslot::slotSecondary); + + TEST_COMBATANTS(); + if (CanThisClassDoubleAttack() && CheckBotDoubleAttack()) { + + if (tar->GetHP() > -10) { + Attack(tar, EQ::invslot::slotSecondary); // Single attack with offhand + } + } + } + } + } + } + } + + if (GetAppearance() == eaDead) { + return; + } + } + + //#pragma endregion + + //#pragma region ENGAGED NOT AT COMBAT RANGE + + else { // To far away to fight (GetTarget() validity can be iffy below this point - including outer scopes) + + // This code actually gets processed when we are too far away from target and have not engaged yet, too + if (/*!GetCombatJitterFlag() && */AI_movement_timer->Check() && (!spellend_timer.Enabled() || GetClass() == BARD)) { // Pursue processing + + if (GetTarget() && !IsRooted()) { + + LogAI("Pursuing [{}] while engaged", GetTarget()->GetCleanName()); + Goal = GetTarget()->GetPosition(); + if (DistanceSquared(m_Position, Goal) <= leash_distance) { + RunTo(Goal.x, Goal.y, Goal.z); + } + else { + + WipeHateList(); + SetTarget(nullptr); + if (HasPet() && (GetClass() != ENCHANTER || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 2)) { + + GetPet()->WipeHateList(); + GetPet()->SetTarget(nullptr); + } + } + + return; + } + else { + + if (IsMoving()) { + StopMoving(); + } + return; + } + } + + if (GetTarget() && GetTarget()->IsFeared() && !spellend_timer.Enabled() && AI_think_timer->Check()) { + + if (!IsFacingMob(GetTarget())) { + FaceTarget(GetTarget()); + } + + // This is a mob that is fleeing either because it has been feared or is low on hitpoints + AI_PursueCastCheck(); // This appears to always return true..can't trust for success/fail + + return; + } + } // End not in combat range + +//#pragma endregion + + if (!IsMoving() && !spellend_timer.Enabled()) { // This may actually need work... + + if (GetTarget() && AI_EngagedCastCheck()) { + BotMeditate(false); + } + else if (GetArchetype() == ARCHETYPE_CASTER) { + BotMeditate(true); + } + + return; + } + } + else { // Out-of-combat behavior + + SetAttackFlag(false); + SetAttackingFlag(false); + if (!bot_owner->GetBotPulling()) { + + SetPullingFlag(false); + SetReturningFlag(false); + } + + //#pragma region AUTO DEFEND + + // This is as close as I could get without modifying the aggro mechanics and making it an expensive process... + // 'class Client' doesn't make use of hate_list... + if (RuleB(Bots, AllowOwnerOptionAutoDefend) && bot_owner->GetBotOption(Client::booAutoDefend)) { + + if (!m_auto_defend_timer.Enabled()) { + + m_auto_defend_timer.Start(zone->random.Int(250, 1250)); // random timer to simulate 'awareness' (cuts down on scanning overhead) + return; + } + + if (m_auto_defend_timer.Check() && bot_owner->GetAggroCount()) { + + if (NOT_HOLDING && NOT_PASSIVE) { + + auto xhaters = bot_owner->GetXTargetAutoMgr(); + if (xhaters && !xhaters->empty()) { + + for (auto hater_iter : xhaters->get_list()) { + + if (!hater_iter.spawn_id) { + continue; + } + + if (bot_owner->GetBotPulling() && bot_owner->GetTarget() && hater_iter.spawn_id == bot_owner->GetTarget()->GetID()) { + continue; + } + + auto hater = entity_list.GetMob(hater_iter.spawn_id); + if (hater && !hater->IsMezzed() && DistanceSquared(hater->GetPosition(), bot_owner->GetPosition()) <= leash_distance) { + + // This is roughly equivilent to npc attacking a client pet owner + AddToHateList(hater, 1); + SetTarget(hater); + SetAttackingFlag(); + if (HasPet() && (GetClass() != ENCHANTER || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 2)) { + + GetPet()->AddToHateList(hater, 1); + GetPet()->SetTarget(hater); + } + + m_auto_defend_timer.Disable(); + + return; + } + } + } + } + } + } + + //#pragma endregion + + SetTarget(nullptr); + + if (HasPet() && (GetClass() != ENCHANTER || GetPet()->GetPetType() != petAnimation || GetAA(aaAnimationEmpathy) >= 1)) { + + GetPet()->WipeHateList(); + GetPet()->SetTarget(nullptr); + } + + if (m_PlayerState & static_cast(PlayerState::Aggressive)) { + SendRemovePlayerState(PlayerState::Aggressive); + } + + //#pragma region OK TO IDLE + + // Ok to idle + if ((NOT_GUARDING && fm_distance <= GetFollowDistance()) || (GUARDING && DistanceSquared(GetPosition(), GetGuardPoint()) <= GetFollowDistance())) { + + if (!IsMoving() && AI_think_timer->Check() && !spellend_timer.Enabled()) { + + if (NOT_PASSIVE) { + + if (!AI_IdleCastCheck() && !IsCasting() && GetClass() != BARD) { + BotMeditate(true); + } + } + else { + + if (GetClass() != BARD) { + BotMeditate(true); + } + } + + return; + } + } + + // Non-engaged movement checks + if (AI_movement_timer->Check() && (!IsCasting() || GetClass() == BARD)) { + + if (GUARDING) { + Goal = GetGuardPoint(); + } + else { + Goal = follow_mob->GetPosition(); + } + float destination_distance = DistanceSquared(GetPosition(), Goal); + + if ((!bot_owner->GetBotPulling() || PULLING_BOT) && (destination_distance > GetFollowDistance())) { + + if (!IsRooted()) { + + if (rest_timer.Enabled()) { + rest_timer.Disable(); + } + + bool running = true; + + if (destination_distance < GetFollowDistance() + BOT_FOLLOW_DISTANCE_WALK) { + running = false; + } + + if (running) { + RunTo(Goal.x, Goal.y, Goal.z); + } + else { + WalkTo(Goal.x, Goal.y, Goal.z); + } + + return; + } + } + else { + + if (IsMoving()) { + + StopMoving(); + return; + } + } + } + + // Basically, bard bots get a chance to cast idle spells while moving + if (GetClass() == BARD && IsMoving() && NOT_PASSIVE) { + + if (!spellend_timer.Enabled() && AI_think_timer->Check()) { + + AI_IdleCastCheck(); + return; + } + } + + //#pragma endregion + + } + +#undef TEST_COMBATANTS +#undef PULLING_BOT +#undef NOT_PULLING_BOT +#undef GUARDING +#undef NOT_GUARDING +#undef HOLDING +#undef NOT_HOLDING +#undef PASSIVE +#undef NOT_PASSIVE +} + +// AI Processing for a Bot object's pet if Bot is a member of a raid +void Bot::PetAIProcess_Raid() { + if (!HasPet() || !GetPet() || !GetPet()->IsNPC()) + return; + + Mob* BotOwner = this->GetBotOwner(); + NPC* botPet = this->GetPet()->CastToNPC(); + if (!botPet->GetOwner() || !botPet->GetID() || !botPet->GetOwnerID()) { + Kill(); + return; + } + + if (!botPet->IsAIControlled() || botPet->GetAttackTimer().Check(false) || botPet->IsCasting() || !botPet->GetOwner()->IsBot()) + return; + + if (IsEngaged()) { + if (botPet->IsRooted()) + botPet->SetTarget(hate_list.GetClosestEntOnHateList(botPet)); + else + botPet->SetTarget(hate_list.GetEntWithMostHateOnList(botPet)); + + // Let's check if we have a los with our target. + // If we don't, our hate_list is wiped. + // It causes some cpu stress but without it, it was causing the bot/pet to aggro behind wall, floor etc... + if (!botPet->CheckLosFN(botPet->GetTarget()) || botPet->GetTarget()->IsMezzed() || !botPet->IsAttackAllowed(GetTarget())) { + botPet->WipeHateList(); + botPet->SetTarget(botPet->GetOwner()); + return; + } + + botPet->FaceTarget(botPet->GetTarget()); + bool is_combat_range = botPet->CombatRange(botPet->GetTarget()); + // Ok, we're engaged, each class type has a special AI + // Only melee class will go to melee. Casters and healers will stay behind, following the leader by default. + // I should probably make the casters staying in place so they can cast.. + + // Ok, we 're a melee or any other class lvl<12. Yes, because after it becomes hard to go in melee for casters.. even for bots.. + if (is_combat_range) { + botPet->GetAIMovementTimer()->Check(); + if (botPet->IsMoving()) { + botPet->SetHeading(botPet->GetTarget()->GetHeading()); + if (moved) { + moved = false; + botPet->SetRunAnimSpeed(0); + } + } + + if (!botPet->IsMoving()) { + float newX = 0; + float newY = 0; + float newZ = 0; + bool petHasAggro = false; + if (botPet->GetTarget() && botPet->GetTarget()->GetHateTop() && botPet->GetTarget()->GetHateTop() == botPet) + petHasAggro = true; + + if (botPet->GetClass() == ROGUE && !petHasAggro && !botPet->BehindMob(botPet->GetTarget(), botPet->GetX(), botPet->GetY())) { + // Move the rogue to behind the mob + if (botPet->PlotPositionAroundTarget(botPet->GetTarget(), newX, newY, newZ)) { + botPet->RunTo(newX, newY, newZ); + return; + } + } + else if (GetTarget() == botPet->GetTarget() && !petHasAggro && !botPet->BehindMob(botPet->GetTarget(), botPet->GetX(), botPet->GetY())) { + // If the bot owner and the bot are fighting the same mob, then move the pet to the rear arc of the mob + if (botPet->PlotPositionAroundTarget(botPet->GetTarget(), newX, newY, newZ)) { + botPet->RunTo(newX, newY, newZ); + return; + } + } + else if (DistanceSquaredNoZ(botPet->GetPosition(), botPet->GetTarget()->GetPosition()) < botPet->GetTarget()->GetSize()) { + // Let's try to adjust our melee range so we don't appear to be bunched up + bool isBehindMob = false; + bool moveBehindMob = false; + if (botPet->BehindMob(botPet->GetTarget(), botPet->GetX(), botPet->GetY())) + isBehindMob = true; + + if (!isBehindMob && !petHasAggro) + moveBehindMob = true; + + if (botPet->PlotPositionAroundTarget(botPet->GetTarget(), newX, newY, newZ, moveBehindMob)) { + botPet->RunTo(newX, newY, newZ); + return; + } + } + } + + // we can't fight if we don't have a target, are stun/mezzed or dead.. + if (botPet->GetTarget() && !botPet->IsStunned() && !botPet->IsMezzed() && (botPet->GetAppearance() != eaDead)) { + // check the delay on the attack + if (botPet->GetAttackTimer().Check()) { + // Stop attacking while we are on a front arc and the target is enraged + if (!botPet->BehindMob(botPet->GetTarget(), botPet->GetX(), botPet->GetY()) && botPet->GetTarget()->IsEnraged()) + return; + + if (botPet->Attack(GetTarget(), EQ::invslot::slotPrimary)) // try the main hand + if (botPet->GetTarget()) { + // We're a pet so we re able to dual attack + int32 RandRoll = zone->random.Int(0, 99); + if (botPet->CanThisClassDoubleAttack() && (RandRoll < (botPet->GetLevel() + NPCDualAttackModifier))) { + if (botPet->Attack(botPet->GetTarget(), EQ::invslot::slotPrimary)) {} + } + } + + if (botPet->GetOwner()->IsBot()) { + int aa_chance = 0; + int aa_skill = 0; + // Magician AA + aa_skill += botPet->GetOwner()->GetAA(aaElementalAlacrity); + // Necromancer AA + aa_skill += botPet->GetOwner()->GetAA(aaQuickeningofDeath); + // Beastlord AA + aa_skill += botPet->GetOwner()->GetAA(aaWardersAlacrity); + if (aa_skill >= 1) + aa_chance += ((aa_skill > 5 ? 5 : aa_skill) * 4); + + if (aa_skill >= 6) + aa_chance += ((aa_skill - 5 > 3 ? 3 : aa_skill - 5) * 7); + + if (aa_skill >= 9) + aa_chance += ((aa_skill - 8 > 3 ? 3 : aa_skill - 8) * 3); + + if (aa_skill >= 12) + aa_chance += ((aa_skill - 11) * 1); + + + //aa_chance += botPet->GetOwner()->GetAA(aaCompanionsAlacrity) * 3; + + if (zone->random.Int(1, 100) < aa_chance) + Flurry(nullptr); + } + + // Ok now, let's check pet's offhand. + if (botPet->GetAttackDWTimer().Check() && botPet->GetOwnerID() && botPet->GetOwner() && ((botPet->GetOwner()->GetClass() == MAGICIAN) || (botPet->GetOwner()->GetClass() == NECROMANCER) || (botPet->GetOwner()->GetClass() == SHADOWKNIGHT) || (botPet->GetOwner()->GetClass() == BEASTLORD))) { + if (botPet->GetOwner()->GetLevel() >= 24) { + float DualWieldProbability = ((botPet->GetSkill(EQ::skills::SkillDualWield) + botPet->GetLevel()) / 400.0f); + DualWieldProbability -= zone->random.Real(0, 1); + if (DualWieldProbability < 0) { + botPet->Attack(botPet->GetTarget(), EQ::invslot::slotSecondary); + if (botPet->CanThisClassDoubleAttack()) { + int32 RandRoll = zone->random.Int(0, 99); + if (RandRoll < (botPet->GetLevel() + 20)) + botPet->Attack(botPet->GetTarget(), EQ::invslot::slotSecondary); + } + } + } + } + if (!botPet->GetOwner()) + return; + + // Special attack + botPet->DoClassAttacks(botPet->GetTarget()); + } + // See if the pet can cast any spell + botPet->AI_EngagedCastCheck(); + } + } + else { + // Now, if we cannot reach our target + if (!botPet->HateSummon()) { + if (botPet->GetTarget() && botPet->AI_PursueCastCheck()) {} + else if (botPet->GetTarget() && botPet->GetAIMovementTimer()->Check()) { + botPet->SetRunAnimSpeed(0); + if (!botPet->IsRooted()) { + LogAI("Pursuing [{}] while engaged", botPet->GetTarget()->GetCleanName()); + botPet->RunTo(botPet->GetTarget()->GetX(), botPet->GetTarget()->GetY(), botPet->GetTarget()->GetZ()); + return; + } + else { + botPet->SetHeading(botPet->GetTarget()->GetHeading()); + if (moved) { + moved = false; + StopNavigation(); + botPet->StopNavigation(); + } + } + } + } + } + } + else { + // Ok if we're not engaged, what's happening.. + if (botPet->GetTarget() != botPet->GetOwner()) + botPet->SetTarget(botPet->GetOwner()); + + if (!IsMoving()) + botPet->AI_IdleCastCheck(); + + if (botPet->GetAIMovementTimer()->Check()) { + switch (pStandingPetOrder) { + case SPO_Follow: { + float dist = DistanceSquared(botPet->GetPosition(), botPet->GetTarget()->GetPosition()); + botPet->SetRunAnimSpeed(0); + if (dist > 184) { + botPet->RunTo(botPet->GetTarget()->GetX(), botPet->GetTarget()->GetY(), botPet->GetTarget()->GetZ()); + return; + } + else { + botPet->SetHeading(botPet->GetTarget()->GetHeading()); + if (moved) { + moved = false; + StopNavigation(); + botPet->StopNavigation(); + } + } + break; + } + case SPO_Sit: + botPet->SetAppearance(eaSitting); + break; + case SPO_Guard: + botPet->NextGuardPosition(); + break; + } + } + } +} + +std::vector Raid::GetRaidGroupMembers(uint32 gid) +{ + std::vector raid_group_members; + for (int i = 0; i < MAX_RAID_MEMBERS; ++i) + { + if (members[i].member && members[i].GroupNumber == gid) + { + raid_group_members.emplace_back(members[i]); + } + } + return raid_group_members; +} + + +#endif diff --git a/bin/zone/bot_raid.h b/zone/bot_raid.h similarity index 93% rename from bin/zone/bot_raid.h rename to zone/bot_raid.h index ab012b381..66d55bab8 100644 --- a/bin/zone/bot_raid.h +++ b/zone/bot_raid.h @@ -16,8 +16,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef BOT_H -#define BOT_H +#ifndef BOT_RAID_H +#define BOT_RAID_H #ifdef BOTS @@ -38,9 +38,10 @@ #include - extern WorldServer worldserver; +//void Bot::PetAIProcess_Raid(); + #endif // BOTS -#endif // BOT_H +#endif // BOT_RAID_H diff --git a/zone/botspellsai.cpp b/zone/botspellsai.cpp index e03c996fd..5dd7569de 100644 --- a/zone/botspellsai.cpp +++ b/zone/botspellsai.cpp @@ -31,6 +31,13 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { + // Bot AI + Raid* raid = entity_list.GetRaidByBot(this); + if (raid) { + AI_CastSpell_Raid(); + return true; + } + if (!tar) { return false; } diff --git a/zone/raids.h b/zone/raids.h index 9961be2e8..432140982 100644 --- a/zone/raids.h +++ b/zone/raids.h @@ -123,6 +123,7 @@ public: bool IsGroupLeader(const char *who); bool IsRaidMember(const char *name); void UpdateLevel(const char *name, int newLevel); + std::vector GetRaidGroupMembers(uint32 gid); uint32 GetFreeGroup(); uint8 GroupCount(uint32 gid); From ec2e79c04201a0aa347ffcd207c2a17daa3a7e06 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Sun, 16 Jan 2022 20:22:56 -0400 Subject: [PATCH 26/55] More raid spell work --- zone/bot.h | 2 + zone/bot_raid.cpp | 1081 ++++++++++++++++++++++++++++++++++++++++++ zone/botspellsai.cpp | 2 +- zone/raids.h | 1 + 4 files changed, 1085 insertions(+), 1 deletion(-) diff --git a/zone/bot.h b/zone/bot.h index 8062c645a..90ae7e8cb 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -382,8 +382,10 @@ public: //Raid methods void PetAIProcess_Raid(); void AI_Process_Raid(); + bool AICastSpell_Raid(Mob* tar, uint8 iChance, uint32 iSpellTypes); static void ProcessRaidInvite(Bot* invitee, Client* invitor); //Mitch static void ProcessRaidInvite(Client* invitee, Client* invitor); //Mitch + uint8 GetNumberNeedingHealedInRaidGroup(uint8 hpr, bool includePets); //Mitch static std::list GetBotSpellsForSpellEffect(Bot* botCaster, int spellEffect); static std::list GetBotSpellsForSpellEffectAndTargetType(Bot* botCaster, int spellEffect, SpellTargetType targetType); diff --git a/zone/bot_raid.cpp b/zone/bot_raid.cpp index b695b2de6..936ba9ee9 100644 --- a/zone/bot_raid.cpp +++ b/zone/bot_raid.cpp @@ -257,6 +257,7 @@ void Bot::AI_Process_Raid() if (pull_target) { Bot::BotGroupSay(this, "Pulling %s to the group..", pull_target->GetCleanName()); + //raid->RaidBotGroupSay(this, 0, 100, "Pulling %s to the group..", pull_target->GetCleanName()); InterruptSpell(); WipeHateList(); AddToHateList(pull_target, 1); @@ -1526,5 +1527,1085 @@ std::vector Raid::GetRaidGroupMembers(uint32 gid) return raid_group_members; } +bool Bot::AICastSpell_Raid(Mob* tar, uint8 iChance, uint32 iSpellTypes) { + // Bot AI Raid + + Raid* raid = entity_list.GetRaidByBot(this); + if (!raid) + return false; + + if (!tar) { + return false; + } + + if (!AI_HasSpells()) + return false; + + if (iChance < 100) { + if (zone->random.Int(0, 100) > iChance) { + return false; + } + } + + if (tar->GetAppearance() == eaDead) { + if ((tar->IsClient() && tar->CastToClient()->GetFeigned()) || tar->IsBot()) { + // do nothing + } + else { + return false; + } + } + + uint8 botClass = GetClass(); + uint8 botLevel = GetLevel(); + + bool checked_los = false; //we do not check LOS until we are absolutely sure we need to, and we only do it once. + + bool castedSpell = false; + + BotSpell botSpell; + botSpell.SpellId = 0; + botSpell.SpellIndex = 0; + botSpell.ManaCost = 0; + + switch (iSpellTypes) { + case SpellType_Mez: { + if (tar->GetBodyType() != BT_Giant) { + if (!checked_los) { + if (!CheckLosFN(tar)) + break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call + + checked_los = true; + } + + //TODO + //Check if single target or AoE mez is best + //if (TARGETS ON MT IS => 3 THEN botSpell = AoEMez) + //if (TARGETS ON MT IS <= 2 THEN botSpell = BestMez) + + botSpell = GetBestBotSpellForMez(this); + + if (botSpell.SpellId == 0) + break; + + Mob* addMob = GetFirstIncomingMobToMez(this, botSpell); + + if (!addMob) { + //Say("!addMob."); + break; + } + + if (!(!addMob->IsImmuneToSpell(botSpell.SpellId, this) && addMob->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0)) + break; + + castedSpell = AIDoSpellCast(botSpell.SpellIndex, addMob, botSpell.ManaCost); + + if (castedSpell) + BotGroupSay(this, "Attempting to mez %s.", addMob->GetCleanName()); + //raid->RaidBotGroupSay(this, 0, 100, "Attempting to mez %s.", addMob->GetCleanName()); + } + break; + } + case SpellType_Heal: { + if (tar->DontHealMeBefore() < Timer::GetCurrentTime()) { + uint8 hpr = (uint8)tar->GetHPRatio(); + bool hasAggro = false; + bool isPrimaryHealer = false; + + if (this->IsRaidGrouped()) { + isPrimaryHealer = IsGroupHealer(); + } + + if (hpr < 95 || (tar->IsClient() && (hpr < 95)) || (botClass == BARD)) { + if (tar->GetClass() == NECROMANCER) { + // Give necromancers a chance to go lifetap something or cleric can spend too much mana on a necro + if (hpr >= 40) { + break; + } + } + + if (tar->GetClass() == SHAMAN) { + // Give shaman the chance to canni without wasting the cleric's mana + if (hpr >= 80) { + break; + } + } + + // Evaluate the situation + if ((IsEngaged()) && ((botClass == CLERIC) || (botClass == DRUID) || (botClass == SHAMAN) || (botClass == PALADIN))) { + if (tar->GetTarget() && tar->GetTarget()->GetHateTop() && tar->GetTarget()->GetHateTop() == tar) { + hasAggro = true; + } + + if (hpr < 35) { + botSpell = GetBestBotSpellForFastHeal(this); + } + else if (hpr >= 35 && hpr < 70) { + if (GetNumberNeedingHealedInRaidGroup(60, false) >= 3) + botSpell = GetBestBotSpellForGroupHeal(this); + + if (botSpell.SpellId == 0) + botSpell = GetBestBotSpellForPercentageHeal(this); + } + else if (hpr >= 70 && hpr < 95) { + if (GetNumberNeedingHealedInRaidGroup(80, false) >= 3) + botSpell = GetBestBotSpellForGroupHealOverTime(this); + + if (hasAggro) + botSpell = GetBestBotSpellForPercentageHeal(this); + } + else { + if (!tar->FindType(SE_HealOverTime)) + botSpell = GetBestBotSpellForHealOverTime(this); + } + } + else if ((botClass == CLERIC) || (botClass == DRUID) || (botClass == SHAMAN) || (botClass == PALADIN)) { + if (GetNumberNeedingHealedInRaidGroup(40, true) >= 2) { + botSpell = GetBestBotSpellForGroupCompleteHeal(this); + + if (botSpell.SpellId == 0) + botSpell = GetBestBotSpellForGroupHeal(this); + + if (botSpell.SpellId == 0) + botSpell = GetBestBotSpellForGroupHealOverTime(this); + + if (hpr < 40) { + if (botSpell.SpellId == 0) + botSpell = GetBestBotSpellForPercentageHeal(this); + } + } + else if (GetNumberNeedingHealedInRaidGroup(60, true) >= 2) { + botSpell = GetBestBotSpellForGroupHeal(this); + + if (botSpell.SpellId == 0) + botSpell = GetBestBotSpellForGroupHealOverTime(this); + + if (hpr < 40) { + if (botSpell.SpellId == 0) + botSpell = GetBestBotSpellForPercentageHeal(this); + } + } + else if (hpr < 40) + botSpell = GetBestBotSpellForPercentageHeal(this); + else if (hpr >= 40 && hpr < 75) + botSpell = GetBestBotSpellForRegularSingleTargetHeal(this); + else { + if (hpr < 90 && !tar->FindType(SE_HealOverTime)) + botSpell = GetBestBotSpellForHealOverTime(this); + } + } + else { + float hpRatioToCast = 0.0f; + + switch (this->GetBotStance()) { + case EQ::constants::stanceEfficient: + case EQ::constants::stanceAggressive: + hpRatioToCast = isPrimaryHealer ? 90.0f : 50.0f; + break; + case EQ::constants::stanceBalanced: + hpRatioToCast = isPrimaryHealer ? 95.0f : 75.0f; + break; + case EQ::constants::stanceReactive: + hpRatioToCast = isPrimaryHealer ? 100.0f : 90.0f; + break; + case EQ::constants::stanceBurn: + case EQ::constants::stanceBurnAE: + hpRatioToCast = isPrimaryHealer ? 75.0f : 25.0f; + break; + default: + hpRatioToCast = isPrimaryHealer ? 100.0f : 0.0f; + break; + } + + //If we're at specified mana % or below, don't heal as hybrid + if (tar->GetHPRatio() <= hpRatioToCast) + botSpell = GetBestBotSpellForRegularSingleTargetHeal(this); + } + + if (botSpell.SpellId == 0) + botSpell = GetBestBotSpellForRegularSingleTargetHeal(this); + + if (botSpell.SpellId == 0) + botSpell = GetFirstBotSpellForSingleTargetHeal(this); + + if (botSpell.SpellId == 0 && botClass == BARD) { + botSpell = GetFirstBotSpellBySpellType(this, SpellType_Heal); + } + + // If there is still no spell id, then there isn't going to be one so we are done + if (botSpell.SpellId == 0) + break; + + // Can we cast this spell on this target? + if (!(spells[botSpell.SpellId].targettype == ST_GroupTeleport || spells[botSpell.SpellId].targettype == ST_Target || tar == this) + && !(tar->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0)) + break; + + uint32 TempDontHealMeBeforeTime = tar->DontHealMeBefore(); + + castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost, &TempDontHealMeBeforeTime); + + if (castedSpell) { + /*if(TempDontHealMeBeforeTime != tar->DontHealMeBefore()) + tar->SetDontHealMeBefore(TempDontHealMeBeforeTime); + + // For non-HoT heals, do a 4 second delay + // TODO: Replace this code with logic that calculates the delay based on number of clerics in rotation + // and ignores heals for anyone except the main tank + if(!IsHealOverTimeSpell(botSpell.SpellId)) { + if(IsCompleteHealSpell(botSpell.SpellId)) { + // Complete Heal 4 second rotation + tar->SetDontHealMeBefore(Timer::GetCurrentTime() + 4000); + } + else { + tar->SetDontHealMeBefore(Timer::GetCurrentTime() + 1000); + } + }*/ + if (botClass != BARD) { + if (IsGroupSpell(botSpell.SpellId)) { + if (IsRaidGrouped()) { + uint32 r_group = raid->GetGroup(GetName()); + std::vector raid_group_members = raid->GetRaidGroupMembers(r_group); + BotGroupSay(this, "Casting %s.", spells[botSpell.SpellId].name); + //raid->RaidBotGroupSay(this, 0, 100, "Casting %s.", spells[botSpell.SpellId].name); + for (RaidMember iter : raid_group_members) { + if (iter.member && !iter.member->qglobal) { + iter.member->SetDontHealMeBefore(Timer::GetCurrentTime() + 1000); + } + } + } + } + else { + if (tar != this) //we don't need spam of bots healing themselves + BotGroupSay(this, "Casting %s on %s", spells[botSpell.SpellId].name, tar->GetCleanName()); + tar->SetDontHealMeBefore(Timer::GetCurrentTime() + 2000); + } + } + } + } + } + break; + } + case SpellType_Root: { + if (!tar->IsRooted() && tar->DontRootMeBefore() < Timer::GetCurrentTime()) { + if (!checked_los) { + if (!CheckLosFN(tar)) + break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call + + checked_los = true; + } + + // TODO: If there is a ranger in the group then don't allow root spells + + botSpell = GetFirstBotSpellBySpellType(this, iSpellTypes); + + if (botSpell.SpellId == 0) + break; + + if (tar->CanBuffStack(botSpell.SpellId, botLevel, true) == 0) + break; + + uint32 TempDontRootMeBefore = tar->DontRootMeBefore(); + + castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost, &TempDontRootMeBefore); + + if (TempDontRootMeBefore != tar->DontRootMeBefore()) + tar->SetDontRootMeBefore(TempDontRootMeBefore); + } + break; + } + case SpellType_Buff: { + if (tar->DontBuffMeBefore() < Timer::GetCurrentTime()) { + std::list buffSpellList = GetBotSpellsBySpellType(this, SpellType_Buff); + + for (std::list::iterator itr = buffSpellList.begin(); itr != buffSpellList.end(); ++itr) { + BotSpell selectedBotSpell = *itr; + + if (selectedBotSpell.SpellId == 0) + continue; + + // no buffs with illusions.. use #bot command to cast illusions + if (IsEffectInSpell(selectedBotSpell.SpellId, SE_Illusion) && tar != this) + continue; + + //no teleport spells use #bot command to cast teleports + if (IsEffectInSpell(selectedBotSpell.SpellId, SE_Teleport) || IsEffectInSpell(selectedBotSpell.SpellId, SE_Succor)) + continue; + + // can not cast buffs for your own pet only on another pet that isn't yours + if ((spells[selectedBotSpell.SpellId].targettype == ST_Pet) && (tar != this->GetPet())) + continue; + + // Validate target + + if (!((spells[selectedBotSpell.SpellId].targettype == ST_Target || spells[selectedBotSpell.SpellId].targettype == ST_Pet || tar == this || + spells[selectedBotSpell.SpellId].targettype == ST_Group || spells[selectedBotSpell.SpellId].targettype == ST_GroupTeleport || + (botClass == BARD && spells[selectedBotSpell.SpellId].targettype == ST_AEBard)) + && !tar->IsImmuneToSpell(selectedBotSpell.SpellId, this) + && (tar->CanBuffStack(selectedBotSpell.SpellId, botLevel, true) >= 0))) { + continue; + } + + // Put the zone levitate and movement check here since bots are able to bypass the client casting check + if ((IsEffectInSpell(selectedBotSpell.SpellId, SE_Levitate) && !zone->CanLevitate()) + || (IsEffectInSpell(selectedBotSpell.SpellId, SE_MovementSpeed) && !zone->CanCastOutdoor())) { + if (botClass != BARD || !IsSpellUsableThisZoneType(selectedBotSpell.SpellId, zone->GetZoneType())) { + continue; + } + } + + switch (tar->GetArchetype()) + { + case ARCHETYPE_CASTER: + //TODO: probably more caster specific spell effects in here + if (IsEffectInSpell(selectedBotSpell.SpellId, SE_AttackSpeed) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ATK) || + IsEffectInSpell(selectedBotSpell.SpellId, SE_STR) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ReverseDS)) + { + continue; + } + break; + case ARCHETYPE_MELEE: + if (IsEffectInSpell(selectedBotSpell.SpellId, SE_IncreaseSpellHaste) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ManaPool) || + IsEffectInSpell(selectedBotSpell.SpellId, SE_CastingLevel) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ManaRegen_v2) || + IsEffectInSpell(selectedBotSpell.SpellId, SE_CurrentMana)) + { + continue; + } + break; + case ARCHETYPE_HYBRID: + //Hybrids get all buffs + default: + break; + } + + if (botClass == ENCHANTER && IsEffectInSpell(selectedBotSpell.SpellId, SE_Rune)) + { + float manaRatioToCast = 75.0f; + + switch (this->GetBotStance()) { + case EQ::constants::stanceEfficient: + manaRatioToCast = 90.0f; + break; + case EQ::constants::stanceBalanced: + case EQ::constants::stanceAggressive: + manaRatioToCast = 75.0f; + break; + case EQ::constants::stanceReactive: + case EQ::constants::stanceBurn: + case EQ::constants::stanceBurnAE: + manaRatioToCast = 50.0f; + break; + default: + manaRatioToCast = 75.0f; + break; + } + + //If we're at specified mana % or below, don't rune as enchanter + if (this->GetManaRatio() <= manaRatioToCast) + break; + } + + if (CheckSpellRecastTimers(this, itr->SpellIndex)) + { + + uint32 TempDontBuffMeBefore = tar->DontBuffMeBefore(); + + castedSpell = AIDoSpellCast(selectedBotSpell.SpellIndex, tar, selectedBotSpell.ManaCost, &TempDontBuffMeBefore); + + if (TempDontBuffMeBefore != tar->DontBuffMeBefore()) + tar->SetDontBuffMeBefore(TempDontBuffMeBefore); + } + + if (castedSpell) + break; + } + } + break; + } + case SpellType_Escape: { + uint8 hpr = (uint8)GetHPRatio(); + bool mayGetAggro = false; + +#ifdef IPC + if (hpr <= 5 || (IsNPC() && CastToNPC()->IsInteractive() && tar != this)) +#else + if (hpr > 15 && ((botClass == WIZARD) || (botClass == ENCHANTER) || (botClass == RANGER))) + mayGetAggro = HasOrMayGetAggro(); //classes have hate reducing spells + + if (hpr <= 15 || mayGetAggro) +#endif + { + botSpell = GetFirstBotSpellBySpellType(this, iSpellTypes); + + if (botSpell.SpellId == 0) + break; + + if (IsInvulnerabilitySpell(botSpell.SpellId)) + tar = this; //target self for invul type spells + + castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost); + } + break; + } + case SpellType_Nuke: { + if ((tar->GetHPRatio() <= 95.0f) || ((botClass == BARD) || (botClass == SHAMAN) || (botClass == ENCHANTER))) + { + if (!checked_los) { + if (!CheckLosFN(tar)) + break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call + + checked_los = true; + } + + if (botClass == CLERIC || botClass == ENCHANTER) + { + float manaRatioToCast = 75.0f; + + switch (this->GetBotStance()) { + case EQ::constants::stanceEfficient: + manaRatioToCast = 90.0f; + break; + case EQ::constants::stanceBalanced: + manaRatioToCast = 75.0f; + break; + case EQ::constants::stanceReactive: + case EQ::constants::stanceAggressive: + manaRatioToCast = 50.0f; + break; + case EQ::constants::stanceBurn: + case EQ::constants::stanceBurnAE: + manaRatioToCast = 25.0f; + break; + default: + manaRatioToCast = 50.0f; + break; + } + + //If we're at specified mana % or below, don't nuke as cleric or enchanter + if (this->GetManaRatio() <= manaRatioToCast) + break; + } + + if (botClass == MAGICIAN || botClass == SHADOWKNIGHT || botClass == NECROMANCER || botClass == PALADIN || botClass == RANGER || botClass == DRUID || botClass == CLERIC) { + if (tar->GetBodyType() == BT_Undead || tar->GetBodyType() == BT_SummonedUndead || tar->GetBodyType() == BT_Vampire) + botSpell = GetBestBotSpellForNukeByTargetType(this, ST_Undead); + else if (tar->GetBodyType() == BT_Summoned || tar->GetBodyType() == BT_Summoned2 || tar->GetBodyType() == BT_Summoned3) + botSpell = GetBestBotSpellForNukeByTargetType(this, ST_Summoned); + } + + if (botClass == PALADIN || botClass == DRUID || botClass == CLERIC || botClass == ENCHANTER || botClass == WIZARD) { + if (botSpell.SpellId == 0) { + uint8 stunChance = (tar->IsCasting() ? 30 : 15); + + if (botClass == PALADIN) + stunChance = 50; + + if (!tar->GetSpecialAbility(UNSTUNABLE) && !tar->IsStunned() && (zone->random.Int(1, 100) <= stunChance)) { + botSpell = GetBestBotSpellForStunByTargetType(this, ST_Target); + } + } + } + + if (botClass == WIZARD && botSpell.SpellId == 0) { + botSpell = GetBestBotWizardNukeSpellByTargetResists(this, tar); + } + + if (botSpell.SpellId == 0) + botSpell = GetBestBotSpellForNukeByTargetType(this, ST_Target); + + if (botSpell.SpellId == 0) + break; + + if (!(!tar->IsImmuneToSpell(botSpell.SpellId, this) && (tar->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0))) + break; + + if (IsFearSpell(botSpell.SpellId)) { + // don't let fear cast if the npc isn't snared or rooted + if (tar->GetSnaredAmount() == -1) { + if (!tar->IsRooted()) + break; + } + } + + castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost); + } + break; + } + case SpellType_Dispel: { + if (tar->GetHPRatio() > 95.0f) { + if (!checked_los) { + if (!CheckLosFN(tar)) + break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call + + checked_los = true; + } + + botSpell = GetFirstBotSpellBySpellType(this, iSpellTypes); + + if (botSpell.SpellId == 0) + break; + + // TODO: Check target to see if there is anything to dispel + + if (tar->CountDispellableBuffs() > 0) { + castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost); + } + } + break; + } + case SpellType_Pet: { + //keep mobs from recasting pets when they have them. + if (!IsPet() && !GetPetID() && !IsBotCharmer()) { + if (botClass == WIZARD) { + auto buffs_max = GetMaxBuffSlots(); + auto my_buffs = GetBuffs(); + int familiar_buff_slot = -1; + if (buffs_max && my_buffs) { + for (int index = 0; index < buffs_max; ++index) { + if (IsEffectInSpell(my_buffs[index].spellid, SE_Familiar)) { + MakePet(my_buffs[index].spellid, spells[my_buffs[index].spellid].teleport_zone); + familiar_buff_slot = index; + break; + } + } + } + if (GetPetID()) + break; + + if (familiar_buff_slot >= 0) { + BuffFadeBySlot(familiar_buff_slot); + break; + } + + botSpell = GetFirstBotSpellBySpellType(this, SpellType_Pet); + } + else if (botClass == MAGICIAN) { + botSpell = GetBestBotMagicianPetSpell(this); + } + else { + botSpell = GetFirstBotSpellBySpellType(this, SpellType_Pet); + } + + if (botSpell.SpellId == 0) + break; + + castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost); + } + break; + } + case SpellType_InCombatBuff: { + + if (botClass == SHAMAN) { + checked_los = true; + + std::list inCombatBuffList = GetBotSpellsBySpellType(this, SpellType_InCombatBuff); + + for (std::list::iterator itr = inCombatBuffList.begin(); itr != inCombatBuffList.end(); ++itr) { + BotSpell selectedBotSpell = *itr; + + if (selectedBotSpell.SpellId == 0) + continue; + + if (CheckSpellRecastTimers(this, itr->SpellIndex)) + { + if (!(!tar->IsImmuneToSpell(selectedBotSpell.SpellId, this) && (spells[selectedBotSpell.SpellId].buffduration < 1 || tar->CanBuffStack(selectedBotSpell.SpellId, botLevel, true) >= 0))) + continue; + + //short duration buffs or other buffs only to be cast during combat. + if (IsSelfConversionSpell(selectedBotSpell.SpellId)) { + if (GetManaRatio() > 90.0f || GetHPRatio() < 50.0f || GetHPRatio() < (GetManaRatio() + 10.0f)) + break; //don't cast if low hp, lots of mana, or if mana is higher than hps + } + + castedSpell = AIDoSpellCast(selectedBotSpell.SpellIndex, tar, selectedBotSpell.ManaCost); + } + + if (castedSpell) + break; + } + } + else if (botClass == BARD) { + if (tar->DontBuffMeBefore() < Timer::GetCurrentTime()) { + std::list inCombatBuffList = GetBotSpellsBySpellType(this, SpellType_InCombatBuff); + + for (std::list::iterator itr = inCombatBuffList.begin(); itr != inCombatBuffList.end(); ++itr) { + BotSpell selectedBotSpell = *itr; + + if (selectedBotSpell.SpellId == 0) + continue; + + if (CheckSpellRecastTimers(this, itr->SpellIndex)) { + uint32 TempDontBuffMeBefore = tar->DontBuffMeBefore(); + + // no buffs with illusions.. use #bot command to cast illusions + if (IsEffectInSpell(selectedBotSpell.SpellId, SE_Illusion) && tar != this) + continue; + + //no teleport spells use #bot command to cast teleports + if (IsEffectInSpell(selectedBotSpell.SpellId, SE_Teleport) || IsEffectInSpell(selectedBotSpell.SpellId, SE_Succor)) + continue; + + // can not cast buffs for your own pet only on another pet that isn't yours + if ((spells[selectedBotSpell.SpellId].targettype == ST_Pet) && (tar != this->GetPet())) + continue; + + // Validate target + + if (!((spells[selectedBotSpell.SpellId].targettype == ST_Target || spells[selectedBotSpell.SpellId].targettype == ST_Pet || tar == this || + spells[selectedBotSpell.SpellId].targettype == ST_Group || spells[selectedBotSpell.SpellId].targettype == ST_GroupTeleport || + (botClass == BARD && spells[selectedBotSpell.SpellId].targettype == ST_AEBard)) + && !tar->IsImmuneToSpell(selectedBotSpell.SpellId, this) + && (tar->CanBuffStack(selectedBotSpell.SpellId, botLevel, true) >= 0))) { + continue; + } + + // Put the zone levitate and movement check here since bots are able to bypass the client casting check + if ((IsEffectInSpell(selectedBotSpell.SpellId, SE_Levitate) && !zone->CanLevitate()) + || (IsEffectInSpell(selectedBotSpell.SpellId, SE_MovementSpeed) && !zone->CanCastOutdoor())) { + if (!IsSpellUsableThisZoneType(selectedBotSpell.SpellId, zone->GetZoneType())) { + continue; + } + } + + if (!IsGroupSpell(selectedBotSpell.SpellId)) { + //Only check archetype if song is not a group spell + switch (tar->GetArchetype()) { + case ARCHETYPE_CASTER: + //TODO: probably more caster specific spell effects in here + if (IsEffectInSpell(selectedBotSpell.SpellId, SE_AttackSpeed) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ATK) || + IsEffectInSpell(selectedBotSpell.SpellId, SE_STR) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ReverseDS)) + { + continue; + } + break; + case ARCHETYPE_MELEE: + if (IsEffectInSpell(selectedBotSpell.SpellId, SE_IncreaseSpellHaste) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ManaPool) || + IsEffectInSpell(selectedBotSpell.SpellId, SE_CastingLevel) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ManaRegen_v2) || + IsEffectInSpell(selectedBotSpell.SpellId, SE_CurrentMana)) + { + continue; + } + break; + case ARCHETYPE_HYBRID: + //Hybrids get all buffs + default: + break; + } + } + + castedSpell = AIDoSpellCast(selectedBotSpell.SpellIndex, tar, selectedBotSpell.ManaCost, &TempDontBuffMeBefore); + + if (TempDontBuffMeBefore != tar->DontBuffMeBefore()) + tar->SetDontBuffMeBefore(TempDontBuffMeBefore); + } + + if (castedSpell) + break; + } + } + } + break; + } + case SpellType_Lifetap: { + if (GetHPRatio() < 90.0f) { + if (!checked_los) { + if (!CheckLosFN(tar)) + break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call + + checked_los = true; + } + + botSpell = GetFirstBotSpellBySpellType(this, iSpellTypes); + + if (botSpell.SpellId == 0) + break; + + if (!(!tar->IsImmuneToSpell(botSpell.SpellId, this) && (tar->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0))) + break; + + castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost); + } + break; + } + case SpellType_Snare: { + if (tar->DontSnareMeBefore() < Timer::GetCurrentTime()) { + if (!checked_los) { + if (!CheckLosFN(tar)) + break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call + + checked_los = true; + } + + botSpell = GetFirstBotSpellBySpellType(this, iSpellTypes); + + if (botSpell.SpellId == 0) + break; + + if (!(!tar->IsImmuneToSpell(botSpell.SpellId, this) && tar->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0)) + break; + + uint32 TempDontSnareMeBefore = tar->DontSnareMeBefore(); + + castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost, &TempDontSnareMeBefore); + + if (TempDontSnareMeBefore != tar->DontSnareMeBefore()) + tar->SetDontSnareMeBefore(TempDontSnareMeBefore); + } + break; + } + case SpellType_DOT: { + if ((tar->GetHPRatio() <= 98.0f) && (tar->DontDotMeBefore() < Timer::GetCurrentTime()) && (tar->GetHPRatio() > 15.0f)) { + if (!checked_los) { + if (!CheckLosFN(tar)) + break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call + + checked_los = true; + } + + if (GetClass() == BARD) { + std::list dotList = GetPrioritizedBotSpellsBySpellType(this, SpellType_DOT); + + const int maxDotSelect = 5; + int dotSelectCounter = 0; + + for (std::list::iterator itr = dotList.begin(); itr != dotList.end(); ++itr) { + BotSpell selectedBotSpell = *itr; + + if (selectedBotSpell.SpellId == 0) + continue; + + if (CheckSpellRecastTimers(this, itr->SpellIndex)) + { + + if (!(!tar->IsImmuneToSpell(selectedBotSpell.SpellId, this) && tar->CanBuffStack(selectedBotSpell.SpellId, botLevel, true) >= 0)) + continue; + + uint32 TempDontDotMeBefore = tar->DontDotMeBefore(); + + castedSpell = AIDoSpellCast(selectedBotSpell.SpellIndex, tar, selectedBotSpell.ManaCost, &TempDontDotMeBefore); + + if (TempDontDotMeBefore != tar->DontDotMeBefore()) + tar->SetDontDotMeBefore(TempDontDotMeBefore); + } + + dotSelectCounter++; + + if ((dotSelectCounter == maxDotSelect) || castedSpell) + break; + } + } + else { + std::list dotList = GetBotSpellsBySpellType(this, SpellType_DOT); + + const int maxDotSelect = 5; + int dotSelectCounter = 0; + + for (std::list::iterator itr = dotList.begin(); itr != dotList.end(); ++itr) { + BotSpell selectedBotSpell = *itr; + + if (selectedBotSpell.SpellId == 0) + continue; + + if (CheckSpellRecastTimers(this, itr->SpellIndex)) + { + + if (!(!tar->IsImmuneToSpell(selectedBotSpell.SpellId, this) && tar->CanBuffStack(selectedBotSpell.SpellId, botLevel, true) >= 0)) + continue; + + uint32 TempDontDotMeBefore = tar->DontDotMeBefore(); + + castedSpell = AIDoSpellCast(selectedBotSpell.SpellIndex, tar, selectedBotSpell.ManaCost, &TempDontDotMeBefore); + + if (TempDontDotMeBefore != tar->DontDotMeBefore()) + tar->SetDontDotMeBefore(TempDontDotMeBefore); + } + + dotSelectCounter++; + + if ((dotSelectCounter == maxDotSelect) || castedSpell) + break; + } + } + } + break; + } + case SpellType_Slow: { + if (tar->GetHPRatio() <= 99.0f) { + + if (!checked_los) { + if (!CheckLosFN(tar)) + break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call + + checked_los = true; + } + + switch (botClass) { + case BARD: { + // probably needs attackable check + std::list botSongList = GetPrioritizedBotSpellsBySpellType(this, SpellType_Slow); + for (auto iter : botSongList) { + if (!iter.SpellId) + continue; + if (!CheckSpellRecastTimers(this, iter.SpellIndex)) + continue; + if (spells[iter.SpellId].zonetype != -1 && zone->GetZoneType() != -1 && spells[iter.SpellId].zonetype != zone->GetZoneType()) // is this bit or index? + continue; + if (spells[iter.SpellId].targettype != ST_Target) + continue; + if (tar->CanBuffStack(iter.SpellId, botLevel, true) < 0) + continue; + + castedSpell = AIDoSpellCast(iter.SpellIndex, tar, iter.ManaCost); + if (castedSpell) + break; + } + + break; + } + case ENCHANTER: { + botSpell = GetBestBotSpellForMagicBasedSlow(this); + break; + } + case SHAMAN: + case BEASTLORD: { + botSpell = GetBestBotSpellForDiseaseBasedSlow(this); + + if (botSpell.SpellId == 0 || ((tar->GetMR() - 50) < (tar->GetDR() + spells[botSpell.SpellId].ResistDiff))) + botSpell = GetBestBotSpellForMagicBasedSlow(this); + break; + } + } + + if (botSpell.SpellId == 0) + break; + + if (!(!tar->IsImmuneToSpell(botSpell.SpellId, this) && tar->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0)) + break; + + castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost); + + if (castedSpell && GetClass() != BARD) + BotGroupSay(this, "Attempting to slow %s.", tar->GetCleanName()); + } + break; + } + case SpellType_Debuff: { + if ((tar->GetHPRatio() <= 99.0f) || ((botClass == BARD) || (botClass == SHAMAN) || (botClass == ENCHANTER) || (botClass == DRUID)) && (tar->GetHPRatio() > 40.0f)) + { + if (!checked_los) { + if (!CheckLosFN(tar)) + break; //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call + + checked_los = true; + } + + botSpell = GetBestBotSpellForResistDebuff(this, tar); + + if (botSpell.SpellId == 0) + botSpell = GetDebuffBotSpell(this, tar); + + if (botSpell.SpellId == 0) + break; + + if (!(!tar->IsImmuneToSpell(botSpell.SpellId, this) && (tar->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0))) + break; + + castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost); + } + break; + } + case SpellType_Cure: { + if (GetNeedsCured(tar) && (tar->DontCureMeBefore() < Timer::GetCurrentTime()) && !(GetNumberNeedingHealedInGroup(25, false) > 0) && !(GetNumberNeedingHealedInGroup(40, false) > 2)) + { + botSpell = GetBestBotSpellForCure(this, tar); + + if (botSpell.SpellId == 0) + break; + + uint32 TempDontCureMeBeforeTime = tar->DontCureMeBefore(); + + castedSpell = AIDoSpellCast(botSpell.SpellIndex, tar, botSpell.ManaCost, &TempDontCureMeBeforeTime); + + if (castedSpell) { + if (botClass != BARD) { + if (IsGroupSpell(botSpell.SpellId)) { + Group* g; + + if (this->HasGroup()) { + Group* g = this->GetGroup(); + + if (g) { + for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { + if (g->members[i] && !g->members[i]->qglobal) { + if (TempDontCureMeBeforeTime != tar->DontCureMeBefore()) + g->members[i]->SetDontCureMeBefore(Timer::GetCurrentTime() + 4000); + } + } + } + } + } + else { + if (TempDontCureMeBeforeTime != tar->DontCureMeBefore()) + tar->SetDontCureMeBefore(Timer::GetCurrentTime() + 4000); + } + } + } + } + break; + } + case SpellType_Resurrect: + break; + case SpellType_HateRedux: { + // assumed group member at this point + if (GetClass() == BARD) { + std::list botSongList = GetPrioritizedBotSpellsBySpellType(this, SpellType_HateRedux); + for (auto iter : botSongList) { + if (!iter.SpellId) + continue; + if (!CheckSpellRecastTimers(this, iter.SpellIndex)) + continue; + if (spells[iter.SpellId].zonetype != -1 && zone->GetZoneType() != -1 && spells[iter.SpellId].zonetype != zone->GetZoneType()) // is this bit or index? + continue; + if (spells[iter.SpellId].targettype != ST_Target) + continue; + if (tar->CanBuffStack(iter.SpellId, botLevel, true) < 0) + continue; + + castedSpell = AIDoSpellCast(iter.SpellIndex, tar, iter.ManaCost); + if (castedSpell) { + BotGroupSay(this, "Attempting to reduce hate on %s.", tar->GetCleanName()); + break; + } + } + } + + break; + } + case SpellType_InCombatBuffSong: { + if (GetClass() != BARD || tar != this) // In-Combat songs can be cast Out-of-Combat in preparation for battle + break; + + std::list botSongList = GetPrioritizedBotSpellsBySpellType(this, SpellType_InCombatBuffSong); + for (auto iter : botSongList) { + if (!iter.SpellId) + continue; + if (!CheckSpellRecastTimers(this, iter.SpellIndex)) + continue; + if (spells[iter.SpellId].zonetype != -1 && zone->GetZoneType() != -1 && spells[iter.SpellId].zonetype != zone->GetZoneType()) // is this bit or index? + continue; + switch (spells[iter.SpellId].targettype) { + case ST_AEBard: + case ST_AECaster: + case ST_GroupTeleport: + case ST_Group: + case ST_Self: + break; + default: + continue; + } + if (tar->CanBuffStack(iter.SpellId, botLevel, true) < 0) + continue; + + castedSpell = AIDoSpellCast(iter.SpellIndex, tar, iter.ManaCost); + if (castedSpell) + break; + } + + break; + } + case SpellType_OutOfCombatBuffSong: { + if (GetClass() != BARD || tar != this || IsEngaged()) // Out-of-Combat songs can not be cast in combat + break; + + std::list botSongList = GetPrioritizedBotSpellsBySpellType(this, SpellType_OutOfCombatBuffSong); + for (auto iter : botSongList) { + if (!iter.SpellId) + continue; + if (!CheckSpellRecastTimers(this, iter.SpellIndex)) + continue; + if (spells[iter.SpellId].zonetype != -1 && zone->GetZoneType() != -1 && spells[iter.SpellId].zonetype != zone->GetZoneType()) // is this bit or index? + continue; + switch (spells[iter.SpellId].targettype) { + case ST_AEBard: + case ST_AECaster: + case ST_GroupTeleport: + case ST_Group: + case ST_Self: + break; + default: + continue; + } + if (tar->CanBuffStack(iter.SpellId, botLevel, true) < 0) + continue; + + castedSpell = AIDoSpellCast(iter.SpellIndex, tar, iter.ManaCost); + if (castedSpell) + break; + } + + break; + } + case SpellType_PreCombatBuff: { + break; + } + case SpellType_PreCombatBuffSong: { + break; + } + default: + break; + } + + return castedSpell; +} + +void Raid::RaidBotGroupSay(Bot* b, uint8 language, uint8 lang_skill, const char* msg, ...) +{ + if (!b) + return; + + char buf[1000]; + va_list ap; + va_start(ap, msg); + vsnprintf(buf, 1000, msg, ap); + va_end(ap); + + uint32 groupToUse = GetGroup(b->GetName()); + + if (groupToUse > 11) + return; + + auto pack = new ServerPacket(ServerOP_RaidGroupSay, sizeof(ServerRaidMessage_Struct) + strlen(msg) + 1); + ServerRaidMessage_Struct* rga = (ServerRaidMessage_Struct*)pack->pBuffer; + rga->rid = GetID(); + rga->gid = groupToUse; + rga->language = language; + rga->lang_skill = lang_skill; + strn0cpy(rga->from, b->GetName(), 64); + + strcpy(rga->message, buf); // this is safe because we are allocating enough space for the entire msg above + + worldserver.SendPacket(pack); + //safe_delete(pack); +} + +uint8 Bot::GetNumberNeedingHealedInRaidGroup(uint8 hpr, bool includePets) { + uint8 needHealed = 0; + Raid* raid = nullptr; + raid = entity_list.GetRaidByBot(this); + uint32 r_group = raid->GetGroup(this->GetName()); + std::vector raid_group_members = raid->GetRaidGroupMembers(r_group); + for (RaidMember iter : raid_group_members) { + if (iter.member && !iter.member->qglobal) { + if (iter.member->GetHPRatio() <= hpr) + needHealed++; + + if (includePets) { + if (iter.member->GetPet() && iter.member->GetPet()->GetHPRatio() <= hpr) + needHealed++; + } + } + } + return needHealed; +} #endif diff --git a/zone/botspellsai.cpp b/zone/botspellsai.cpp index 5dd7569de..c2e04f17d 100644 --- a/zone/botspellsai.cpp +++ b/zone/botspellsai.cpp @@ -34,7 +34,7 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { // Bot AI Raid* raid = entity_list.GetRaidByBot(this); if (raid) { - AI_CastSpell_Raid(); + AICastSpell_Raid(tar, iChance, iSpellTypes); return true; } diff --git a/zone/raids.h b/zone/raids.h index 432140982..edcdc65be 100644 --- a/zone/raids.h +++ b/zone/raids.h @@ -114,6 +114,7 @@ public: void AddMember(Client *c, uint32 group = 0xFFFFFFFF, bool rleader=false, bool groupleader=false, bool looter=false); void AddBot(Bot* b, uint32 group = 0xFFFFFFFF, bool rleader=false, bool groupleader=false, bool looter=false); //Mitch + void RaidBotGroupSay(Bot* b, uint8 language, uint8 lang_skill, const char* msg, ...); //Mitch void RemoveMember(const char *c); void DisbandRaid(); void MoveMember(const char *name, uint32 newGroup); From 26c12d46efb881887931eb8f6bf46550f09ec79e Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Mon, 17 Jan 2022 10:00:25 -0400 Subject: [PATCH 27/55] end of day Jan 16 --- zone/bot_raid.cpp | 2 +- zone/botspellsai.cpp | 4 ++-- zone/client_packet.cpp | 16 ++++++++++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/zone/bot_raid.cpp b/zone/bot_raid.cpp index 936ba9ee9..604640924 100644 --- a/zone/bot_raid.cpp +++ b/zone/bot_raid.cpp @@ -54,7 +54,7 @@ void Bot::AI_Process_Raid() Raid* raid = entity_list.GetRaidByBot(this); Client* bot_owner = (GetBotOwner() && GetBotOwner()->IsClient() ? GetBotOwner()->CastToClient() : nullptr); - int r_group = raid->GetGroup(GetName()); + uint32 r_group = raid->GetGroup(GetName()); LogAI("Bot_Raid: Entered Raid Process() for [{}].", this->GetCleanName()); diff --git a/zone/botspellsai.cpp b/zone/botspellsai.cpp index c2e04f17d..f4f76f310 100644 --- a/zone/botspellsai.cpp +++ b/zone/botspellsai.cpp @@ -34,8 +34,8 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { // Bot AI Raid* raid = entity_list.GetRaidByBot(this); if (raid) { - AICastSpell_Raid(tar, iChance, iSpellTypes); - return true; + return AICastSpell_Raid(tar, iChance, iSpellTypes); + //return true; } if (!tar) { diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 70ce5a98b..35a26956f 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -569,6 +569,22 @@ void Client::CompleteConnect() if (raid) { SetRaidGrouped(true); raid->LearnMembers(); +#ifdef BOTS + std::vector r_members = raid->GetMembers(); + for (RaidMember iter : r_members) { + if (iter.member && iter.member->IsBot() && iter.member->GetOwner()->CastToClient()->CharacterID() == this->CharacterID()) { + iter.member->CastToBot()->Spawn(this); + iter.member->CastToBot()->SetRaidGrouped(true); + uint32 r_group = raid->GetGroup(iter.member->GetName()); + if (r_group > 0) { + iter.member->CastToBot()->SetFollowID(raid->GetGroupLeader(r_group)->CastToClient()->GetID()); + } + else { + iter.member->CastToBot()->SetFollowID(raid->GetLeader()->GetID()); + } + } + } +#endif raid->VerifyRaid(); raid->GetRaidDetails(); /* From 937d1b1a51d1e39519841200e9053953311ad244 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Mon, 17 Jan 2022 17:56:17 -0400 Subject: [PATCH 28/55] spawn work --- zone/client_packet.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 35a26956f..5092375f0 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -68,6 +68,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #ifdef BOTS #include "bot.h" +#include "bot_command.h" #endif extern QueryServ* QServ; @@ -573,7 +574,10 @@ void Client::CompleteConnect() std::vector r_members = raid->GetMembers(); for (RaidMember iter : r_members) { if (iter.member && iter.member->IsBot() && iter.member->GetOwner()->CastToClient()->CharacterID() == this->CharacterID()) { - iter.member->CastToBot()->Spawn(this); + char buffer[70]; + sprintf(buffer, "spawn %s", iter.member->GetName()); + bot_command_real_dispatch(this, buffer); + //iter.member->CastToBot()->Spawn(this); iter.member->CastToBot()->SetRaidGrouped(true); uint32 r_group = raid->GetGroup(iter.member->GetName()); if (r_group > 0) { From 29ec9145659991cfc4be0f0a4ea8f4750946c1ea Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Mon, 17 Jan 2022 23:53:25 -0400 Subject: [PATCH 29/55] Spawn on login working --- zone/bot.cpp | 4 ++-- zone/bot_raid.cpp | 2 +- zone/client_packet.cpp | 31 ++++++++++++++++++------------- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index e345bf50a..d8685eb83 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -2300,8 +2300,8 @@ bool Bot::Process() } // Bot AI - Raid* raid = entity_list.GetRaidByBot(this); - if (raid) + uint32 raid = entity_list.GetRaidByBot(this)->GetID(); + if (raid >= 0) AI_Process_Raid(); else AI_Process(); diff --git a/zone/bot_raid.cpp b/zone/bot_raid.cpp index 604640924..ef85d9c3e 100644 --- a/zone/bot_raid.cpp +++ b/zone/bot_raid.cpp @@ -75,7 +75,7 @@ void Bot::AI_Process_Raid() // We also need a leash owner and follow mob (subset of primary AI criteria) Client* leash_owner = nullptr; - if (r_group > 0) { + if (r_group >= 0) { leash_owner = raid->GetGroupLeader(r_group)->CastToClient(); } else { diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 5092375f0..0b901ef0b 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -571,20 +571,25 @@ void Client::CompleteConnect() SetRaidGrouped(true); raid->LearnMembers(); #ifdef BOTS + std::list bots_list; + database.botdb.LoadBotsList(this->CharacterID(), bots_list); std::vector r_members = raid->GetMembers(); - for (RaidMember iter : r_members) { - if (iter.member && iter.member->IsBot() && iter.member->GetOwner()->CastToClient()->CharacterID() == this->CharacterID()) { - char buffer[70]; - sprintf(buffer, "spawn %s", iter.member->GetName()); - bot_command_real_dispatch(this, buffer); - //iter.member->CastToBot()->Spawn(this); - iter.member->CastToBot()->SetRaidGrouped(true); - uint32 r_group = raid->GetGroup(iter.member->GetName()); - if (r_group > 0) { - iter.member->CastToBot()->SetFollowID(raid->GetGroupLeader(r_group)->CastToClient()->GetID()); - } - else { - iter.member->CastToBot()->SetFollowID(raid->GetLeader()->GetID()); + for (const RaidMember& iter : r_members) { + if (iter.membername) { + for (const BotsAvailableList& b_iter : bots_list) + { + if (strcmp(iter.membername, b_iter.Name) == 0) + { + char buffer[71] = "^spawn "; + strcat(buffer, iter.membername); + bot_command_real_dispatch(this, buffer); + Bot* b = entity_list.GetBotByBotName(iter.membername); + if (b) + { + b->SetRaidGrouped(true); + //b->SetFollowID(this->GetID()); + } + } } } } From 5e475ad8cdfae219169bcbc70ccc9f889eceab08 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Tue, 18 Jan 2022 22:33:09 -0400 Subject: [PATCH 30/55] End of Day Jan 18 --- zone/bot.cpp | 32 +++++++++++++++++++++----------- zone/bot_raid.cpp | 17 +++++++++++------ zone/botspellsai.cpp | 2 +- zone/client_packet.cpp | 7 ++++++- zone/entity.cpp | 7 ++++--- zone/entity.h | 2 +- 6 files changed, 44 insertions(+), 23 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index d8685eb83..dbf8ddd9c 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -2300,8 +2300,8 @@ bool Bot::Process() } // Bot AI - uint32 raid = entity_list.GetRaidByBot(this)->GetID(); - if (raid >= 0) + Raid* bot_raid = entity_list.GetRaidByBotName(this->GetName()); + if (bot_raid) AI_Process_Raid(); else AI_Process(); @@ -8388,7 +8388,7 @@ void Bot::Camp(bool databaseSave) { RemoveBotFromGroup(this, GetGroup()); //Mitch - Raid* bot_raid = entity_list.GetRaidByBot(this); + Raid* bot_raid = entity_list.GetRaidByBotName(this->GetName()); if (bot_raid) bot_raid->RemoveMember(this->GetName()); @@ -8405,9 +8405,14 @@ void Bot::Camp(bool databaseSave) { } void Bot::Zone() { - if(HasGroup()) + Raid* raid = entity_list.GetRaidByBotName(this->GetName()); + if (raid) { + raid->MemberZoned(this->CastToClient()); + } + else if (HasGroup()) { GetGroup()->MemberZoned(this); - + } + Save(); Depop(); } @@ -8656,7 +8661,11 @@ void Bot::ProcessClientZoneChange(Client* botOwner) { Bot* tempBot = *itr; if(tempBot) { - if(tempBot->HasGroup()) { + Raid* raid = entity_list.GetRaidByBotName(tempBot->GetName()); + if (raid) { + tempBot->Zone(); + } + else if(tempBot->HasGroup()) { Group* g = tempBot->GetGroup(); if(g && g->IsGroupMember(botOwner)) { if(botOwner && botOwner->IsClient()) { @@ -10454,7 +10463,8 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { entity_list.AddRaid(raid); raid->SetRaidDetails(); raid->SendRaidCreate(invitor); - raid->SendMakeGroupLeaderPacketTo(raid->leadername, invitor); + raid->SetLeader(invitor); //Added Jan 18 + raid->SendMakeLeaderPacketTo(raid->leadername, invitor); if (g_invitor) { @@ -10480,9 +10490,9 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { c = g_invitor->members[x]->CastToClient(); if (x == 0) { raid->SendRaidCreate(c); - raid->SendMakeLeaderPacketTo(raid->leadername, c); - raid->AddMember(c, 0, false, true, false); - raid->SetGroupLeader(c->GetName()); + raid->SendMakeLeaderPacketTo(invitor->GetName(), c); + raid->AddMember(c, 0, true, true, true); + //raid->SetGroupLeader(c->GetName()); //Mitch Jan 18 //raid->GroupUpdate(0, true); if (raid->IsLocked()) { raid->SendRaidLockTo(c); @@ -10572,7 +10582,7 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { { //Second, add the single invitor raid->SendRaidCreate(invitor); - raid->SendMakeLeaderPacketTo(raid->leadername, invitor); + raid->SendMakeLeaderPacketTo(invitor->GetName(), invitor); //Mitch Jan 18 raid->AddMember(invitor, 0xFFFFFFFF, true, false, true); if (raid->IsLocked()) { raid->SendRaidLockTo(invitor); diff --git a/zone/bot_raid.cpp b/zone/bot_raid.cpp index ef85d9c3e..808c8f138 100644 --- a/zone/bot_raid.cpp +++ b/zone/bot_raid.cpp @@ -52,7 +52,7 @@ void Bot::AI_Process_Raid() #define PASSIVE (GetBotStance() == EQ::constants::stancePassive) #define NOT_PASSIVE (GetBotStance() != EQ::constants::stancePassive) - Raid* raid = entity_list.GetRaidByBot(this); + Raid* raid = entity_list.GetRaidByBotName(this->GetName()); Client* bot_owner = (GetBotOwner() && GetBotOwner()->IsClient() ? GetBotOwner()->CastToClient() : nullptr); uint32 r_group = raid->GetGroup(GetName()); @@ -75,11 +75,11 @@ void Bot::AI_Process_Raid() // We also need a leash owner and follow mob (subset of primary AI criteria) Client* leash_owner = nullptr; - if (r_group >= 0) { - leash_owner = raid->GetGroupLeader(r_group)->CastToClient(); + if (r_group < 12) { + leash_owner = raid->GetGroupLeader(r_group); } else { - leash_owner = raid->GetLeader(); + leash_owner = bot_owner; } if (!leash_owner) { @@ -94,7 +94,12 @@ void Bot::AI_Process_Raid() follow_mob = leash_owner; SetFollowID(leash_owner->GetID()); } + + if (send_hp_update_timer.Check(false)) { + raid->SendHPManaEndPacketsFrom(this); + + } // Berserk updates should occur if primary AI criteria are met if (GetClass() == WARRIOR || GetClass() == BERSERKER) { @@ -1531,7 +1536,7 @@ bool Bot::AICastSpell_Raid(Mob* tar, uint8 iChance, uint32 iSpellTypes) { // Bot AI Raid - Raid* raid = entity_list.GetRaidByBot(this); + Raid* raid = entity_list.GetRaidByBotName(this->GetName()); if (!raid) return false; @@ -2592,7 +2597,7 @@ void Raid::RaidBotGroupSay(Bot* b, uint8 language, uint8 lang_skill, const char* uint8 Bot::GetNumberNeedingHealedInRaidGroup(uint8 hpr, bool includePets) { uint8 needHealed = 0; Raid* raid = nullptr; - raid = entity_list.GetRaidByBot(this); + raid = entity_list.GetRaidByBotName(this->GetName()); uint32 r_group = raid->GetGroup(this->GetName()); std::vector raid_group_members = raid->GetRaidGroupMembers(r_group); for (RaidMember iter : raid_group_members) { diff --git a/zone/botspellsai.cpp b/zone/botspellsai.cpp index f4f76f310..5b0288485 100644 --- a/zone/botspellsai.cpp +++ b/zone/botspellsai.cpp @@ -32,7 +32,7 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { // Bot AI - Raid* raid = entity_list.GetRaidByBot(this); + Raid* raid = entity_list.GetRaidByBotName(this->GetName()); if (raid) { return AICastSpell_Raid(tar, iChance, iSpellTypes); //return true; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 0b901ef0b..7e7d3b60e 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -6988,7 +6988,12 @@ void Client::Handle_OP_GroupInvite2(const EQApplicationPacket *app) } #ifdef BOTS else if (Invitee->IsBot()) { - Bot::ProcessBotGroupInvite(this, std::string(Invitee->GetName())); + Client* inviter = entity_list.GetClientByName(gis->inviter_name); + Bot* invitee = entity_list.GetBotByBotName(gis->invitee_name); + if (inviter->IsRaidGrouped()) + Bot::ProcessRaidInvite(invitee, inviter); + else + Bot::ProcessBotGroupInvite(this, std::string(Invitee->GetName())); } #endif } diff --git a/zone/entity.cpp b/zone/entity.cpp index f301f6726..cc78fe6ca 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -2048,15 +2048,16 @@ Raid* EntityList::GetRaidByClient(Client* client) return nullptr; } -Raid* EntityList::GetRaidByBot(Bot* bot) +Raid* EntityList::GetRaidByBotName(const char* name) { + std::list::iterator iterator; iterator = raid_list.begin(); while (iterator != raid_list.end()) { for (auto& member : (*iterator)->members) { - if (member.member) { - if (member.member == bot->CastToClient()) { + if (member.membername) { + if (strcmp(member.membername, name) == 0) { //client->p_raid_instance = *iterator; return *iterator; } diff --git a/zone/entity.h b/zone/entity.h index 0bbc298bc..45f588ccf 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -198,7 +198,7 @@ public: Raid *GetRaidByID(uint32 id); Raid *GetRaidByLeaderName(const char *leader); #ifdef BOTS - Raid* GetRaidByBot(Bot* bot); + Raid* GetRaidByBotName(const char* name); #endif Corpse *GetCorpseByOwner(Client* client); From f26b4913394ba75e73a4b191ef60688f679e6acb Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Wed, 19 Jan 2022 23:35:04 -0400 Subject: [PATCH 31/55] Raid leader and mana/hp updates fixed --- zone/bot.cpp | 53 ++++++++++++++++++++++++++++++++++++++++------- zone/bot_raid.cpp | 3 +++ zone/raids.cpp | 1 + 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index dbf8ddd9c..12d511988 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -7713,11 +7713,25 @@ bool Bot::DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, EQ::spe bool Bot::DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, EQ::spells::CastingSlot slot, bool& stopLogic) { bool isMainGroupMGB = false; + Raid* raid = entity_list.GetRaidByBotName(this->GetName()); + if(isMainGroupMGB && (GetClass() != BARD)) { BotGroupSay(this, "MGB %s", spells[spell_id].name); SpellOnTarget(spell_id, this); entity_list.AESpell(this, this, spell_id, true); - } else { + } + else if (raid) + { + for (RaidMember iter : raid->GetRaidGroupMembers(raid->GetGroup(this->GetName()))) { + if (iter.member) { + SpellOnTarget(spell_id, iter.member); + if (iter.member && iter.member->GetPetID()) + SpellOnTarget(spell_id, iter.member ->GetPet()); + } + } + } + else + { Group *g = GetGroup(); if(g) { for(int i = 0; i < MAX_GROUP_MEMBERS; ++i) { @@ -9277,7 +9291,19 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl else return false; } - +//added raid check + if (caster->IsRaidGrouped()) { + Raid* raid = entity_list.GetRaidByBotName(caster->GetName()); + uint32 g = raid->GetGroup(caster->GetName()); + if (g < 12) { + for (RaidMember &iter : raid->GetRaidGroupMembers(g)) { + if (iter.member) { + if (caster->AICastSpell(iter.member, chanceToCast, SpellType_Buff) || caster->AICastSpell(iter.member->GetPet(), chanceToCast, SpellType_Buff)) + return true; + } + } + } + } if(caster->HasGroup()) { Group *g = caster->GetGroup(); if(g) { @@ -9333,6 +9359,19 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl if (botCasterClass == BARD || caster->IsEngaged()) return false; + //added raid check + if (caster->IsRaidGrouped()) { + Raid* raid = entity_list.GetRaidByBotName(caster->GetName()); + uint32 g = raid->GetGroup(caster->GetName()); + if (g < 12) { + for (RaidMember& iter : raid->GetRaidGroupMembers(g)) { + if (iter.member) { + if (caster->AICastSpell(iter.member, iChance, SpellType_PreCombatBuff) || caster->AICastSpell(iter.member->GetPet(), iChance, SpellType_PreCombatBuff)) + return true; + } + } + } + } if (caster->HasGroup()) { Group *g = caster->GetGroup(); if (g) { @@ -10462,9 +10501,9 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { raid = new Raid(invitor); entity_list.AddRaid(raid); raid->SetRaidDetails(); - raid->SendRaidCreate(invitor); - raid->SetLeader(invitor); //Added Jan 18 - raid->SendMakeLeaderPacketTo(raid->leadername, invitor); +// raid->SendRaidCreate(invitor); +// raid->SetLeader(invitor); //Added Jan 18 +// raid->SendMakeLeaderPacketTo(raid->leadername, invitor); if (g_invitor) { @@ -10490,8 +10529,8 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { c = g_invitor->members[x]->CastToClient(); if (x == 0) { raid->SendRaidCreate(c); - raid->SendMakeLeaderPacketTo(invitor->GetName(), c); raid->AddMember(c, 0, true, true, true); + raid->SendMakeLeaderPacketTo(raid->leadername, c); //raid->SetGroupLeader(c->GetName()); //Mitch Jan 18 //raid->GroupUpdate(0, true); if (raid->IsLocked()) { @@ -10582,8 +10621,8 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { { //Second, add the single invitor raid->SendRaidCreate(invitor); - raid->SendMakeLeaderPacketTo(invitor->GetName(), invitor); //Mitch Jan 18 raid->AddMember(invitor, 0xFFFFFFFF, true, false, true); + raid->SendMakeLeaderPacketTo(invitor->GetName(), invitor); //Mitch Jan 18 if (raid->IsLocked()) { raid->SendRaidLockTo(invitor); } diff --git a/zone/bot_raid.cpp b/zone/bot_raid.cpp index 808c8f138..74cd5592f 100644 --- a/zone/bot_raid.cpp +++ b/zone/bot_raid.cpp @@ -95,6 +95,9 @@ void Bot::AI_Process_Raid() SetFollowID(leash_owner->GetID()); } + if (this->mana_timer.Check(false)) { + raid->SendHPManaEndPacketsFrom(this); + } if (send_hp_update_timer.Check(false)) { raid->SendHPManaEndPacketsFrom(this); diff --git a/zone/raids.cpp b/zone/raids.cpp index 2777bb637..22629b917 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -253,6 +253,7 @@ void Raid::RemoveMember(const char *characterName) bot->SetFollowID(bot->GetOwner()->GetID()); bot->SetGrouped(0); bot->SetTarget(nullptr); + bot->SetRaidGrouped(0); } #endif From 58b1373fc09078f09314e9c14d4f49c099b90d54 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Thu, 20 Jan 2022 19:49:51 -0400 Subject: [PATCH 32/55] Spell Tracking --- zone/raids.cpp | 1 - zone/raids.h | 12 +++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/zone/raids.cpp b/zone/raids.cpp index 22629b917..e5be93d41 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -196,7 +196,6 @@ void Raid::AddBot(Bot* b, uint32 group, bool rleader, bool groupleader, bool loo //SendGroupLeadershipAA(c, RAID_GROUPLESS); Is this needed for bots? SendRaidAddAll(b->GetName()); - members[GetPlayerIndex(b->GetName())].SentToBotOwner = true; //Mitch indicates that the BotOwner has received this raid info already. b->SetRaidGrouped(true); //SendRaidMOTD(b->GetOwner()->CastToClient()); diff --git a/zone/raids.h b/zone/raids.h index edcdc65be..5ac1910f5 100644 --- a/zone/raids.h +++ b/zone/raids.h @@ -88,7 +88,15 @@ struct RaidMember{ bool IsGroupLeader; bool IsRaidLeader; bool IsLooter; - bool SentToBotOwner; +#ifdef BOTS + bool IsGroupHealer; + bool IsRaidSlower; + bool IsRaidMainAssistOne; + bool IsRaidMainAssistTwo; + bool IsRaidMainTank; + bool IsRaidOffTankOne; + bool IsRaidOffTankTwo; +#endif }; struct GroupMentor { @@ -113,8 +121,10 @@ public: bool IsRaid() { return true; } void AddMember(Client *c, uint32 group = 0xFFFFFFFF, bool rleader=false, bool groupleader=false, bool looter=false); +#ifdef BOTS void AddBot(Bot* b, uint32 group = 0xFFFFFFFF, bool rleader=false, bool groupleader=false, bool looter=false); //Mitch void RaidBotGroupSay(Bot* b, uint8 language, uint8 lang_skill, const char* msg, ...); //Mitch +#endif void RemoveMember(const char *c); void DisbandRaid(); void MoveMember(const char *name, uint32 newGroup); From 4215a47d8259affe8477bb774c82c6d0c3d1c737 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Fri, 21 Jan 2022 00:06:59 -0400 Subject: [PATCH 33/55] Issue with Bot Death in raid when casted upon. 1741 raid.cpp --- zone/bot.cpp | 125 ++++++++++++++++++++++++++++++++++++++++++++++--- zone/raids.cpp | 2 +- 2 files changed, 119 insertions(+), 8 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index 12d511988..09d3549fb 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -5028,8 +5028,9 @@ bool Bot::Death(Mob *killerMob, int32 damage, uint16 spell_id, EQ::skills::Skill if ((GetPullingFlag() || GetReturningFlag()) && my_owner && my_owner->IsClient()) { my_owner->CastToClient()->SetBotPulling(false); } - - entity_list.RemoveBot(this->GetID()); + if (!this->IsRaidGrouped()) + entity_list.RemoveBot(this->GetID()); + return true; } @@ -8403,8 +8404,11 @@ void Bot::Camp(bool databaseSave) { //Mitch Raid* bot_raid = entity_list.GetRaidByBotName(this->GetName()); - if (bot_raid) + if (bot_raid) { + bot_raid->SendRaidGroupRemove(this->GetName(), bot_raid->GetGroup(this->GetName())); bot_raid->RemoveMember(this->GetName()); + } + // RemoveBotFromGroup() code is too complicated for this to work as-is (still needs to be addressed to prevent memory leaks) //if (group->GroupCount() < 2) @@ -9230,11 +9234,49 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl } } } +#ifdef BOTS + else if (caster->IsRaidGrouped()) + { + //added raid check + Raid* raid = entity_list.GetRaidByBotName(caster->GetName()); + uint32 g = raid->GetGroup(caster->GetName()); + if (g < 12) { + for (RaidMember& iter : raid->GetRaidGroupMembers(g)) { + if (iter.member && !iter.member->qglobal) { + if (iter.member->IsClient() && iter.member->GetHPRatio() < 90) { + if (caster->AICastSpell(iter.member, 100, SpellType_Heal)) + return true; + } + else if ((iter.member->GetClass() == WARRIOR || iter.member->GetClass() == PALADIN || iter.member->GetClass() == SHADOWKNIGHT) && iter.member->GetHPRatio() < 95) { + if (caster->AICastSpell(iter.member, 100, SpellType_Heal)) + return true; + } + else if (iter.member->GetClass() == ENCHANTER && iter.member->GetHPRatio() < 80) { + if (caster->AICastSpell(iter.member, 100, SpellType_Heal)) + return true; + } + else if (iter.member->GetHPRatio() < 70) { + if (caster->AICastSpell(iter.member, 100, SpellType_Heal)) + return true; + } + + } + + if (iter.member && !iter.member->qglobal && iter.member->HasPet() && iter.member->GetPet()->GetHPRatio() < 50) { + if (iter.member->GetPet()->GetOwner() != caster && caster->IsEngaged() && iter.member->IsCasting() && iter.member->GetClass() != ENCHANTER) + continue; + + if (caster->AICastSpell(iter.member->GetPet(), 100, SpellType_Heal)) + return true; + } + } + } + } +#endif } if( botCasterClass == PALADIN || botCasterClass == BEASTLORD || botCasterClass == RANGER) { - if(caster->HasGroup()) { - Group *g = caster->GetGroup(); + if(caster->HasGroup() || caster->IsRaidGrouped()) { float hpRatioToHeal = 25.0f; switch(caster->GetBotStance()) { case EQ::constants::stanceReactive: @@ -9251,6 +9293,9 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl hpRatioToHeal = 25.0f; break; } + Group* g = caster->GetGroup(); + Raid* raid = entity_list.GetRaidByBotName(caster->GetName()); + uint32 gid = raid->GetGroup(caster->GetName()); if(g) { for(int i = 0; i < MAX_GROUP_MEMBERS; i++) { @@ -9279,6 +9324,37 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl } } } + else if (gid < 12) + { + for (RaidMember& iter : raid->GetRaidGroupMembers(gid)) { + if (iter.member && !iter.member->qglobal) { + if (iter.member->IsClient() && iter.member->GetHPRatio() < hpRatioToHeal) { + if (caster->AICastSpell(iter.member, 100, SpellType_Heal)) + return true; + } + else if ((iter.member->GetClass() == WARRIOR || iter.member->GetClass() == PALADIN || iter.member->GetClass() == SHADOWKNIGHT) && iter.member->GetHPRatio() < hpRatioToHeal) { + if (caster->AICastSpell(iter.member, 100, SpellType_Heal)) + return true; + } + else if (iter.member->GetClass() == ENCHANTER && iter.member->GetHPRatio() < hpRatioToHeal) { + if (caster->AICastSpell(iter.member, 100, SpellType_Heal)) + return true; + } + else if (iter.member->GetHPRatio() < hpRatioToHeal / 2) { + if (caster->AICastSpell(iter.member, 100, SpellType_Heal)) + return true; + } + } + + if (iter.member && !iter.member->qglobal && iter.member->HasPet() && iter.member->GetPet()->GetHPRatio() < 25) { + if (iter.member->GetPet()->GetOwner() != caster && caster->IsEngaged() && iter.member->IsCasting() && iter.member->GetClass() != ENCHANTER) + continue; + + if (caster->AICastSpell(iter.member->GetPet(), 100, SpellType_Heal)) + return true; + } + } + } } } } @@ -9291,6 +9367,7 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl else return false; } +#ifdef BOTS //added raid check if (caster->IsRaidGrouped()) { Raid* raid = entity_list.GetRaidByBotName(caster->GetName()); @@ -9304,6 +9381,7 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl } } } +#endif if(caster->HasGroup()) { Group *g = caster->GetGroup(); if(g) { @@ -9336,6 +9414,26 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl } } } + else if (caster->IsRaidGrouped()) + { + Raid* raid = entity_list.GetRaidByBotName(caster->GetName()); + uint32 gid = raid->GetGroup(caster->GetName()); + if (gid < 12) { + for (RaidMember& iter : raid->GetRaidGroupMembers(gid)) { + if (iter.member && caster->GetNeedsCured(iter.member)) { + if (caster->AICastSpell(iter.member, caster->GetChanceToCastBySpellType(SpellType_Cure), SpellType_Cure)) + return true; + else if (botCasterClass == BARD) + return false; + } + + if (iter.member && iter.member->GetPet() && caster->GetNeedsCured(iter.member->GetPet())) { + if (caster->AICastSpell(iter.member->GetPet(), (int)caster->GetChanceToCastBySpellType(SpellType_Cure) / 4, SpellType_Cure)) + return true; + } + } + } + } } if (iSpellTypes == SpellType_HateRedux) { @@ -9353,6 +9451,20 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl } } } + else if (caster->IsRaidGrouped()) + { + Raid* raid = entity_list.GetRaidByBotName(caster->GetName()); + uint32 gid = raid->GetGroup(caster->GetName()); + if (gid < 12) { + for (RaidMember& iter : raid->GetRaidGroupMembers(gid)) { + if (iter.member && caster->GetNeedsHateRedux(iter.member)) { + if (caster->AICastSpell(iter.member, caster->GetChanceToCastBySpellType(SpellType_HateRedux), SpellType_HateRedux)) + return true; + } + } + } + } + } if (iSpellTypes == SpellType_PreCombatBuff) { @@ -9371,8 +9483,7 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl } } } - } - if (caster->HasGroup()) { + } else if (caster->HasGroup()) { Group *g = caster->GetGroup(); if (g) { for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { diff --git a/zone/raids.cpp b/zone/raids.cpp index e5be93d41..7fd865f12 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -1738,7 +1738,7 @@ void Raid::SendHPManaEndPacketsFrom(Mob *mob) mob->CreateHPPacket(&hpapp); for(int x = 0; x < MAX_RAID_MEMBERS; x++) { - if(members[x].member) { + if(members[x].member && members[x].membername) { if(!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) { members[x].member->QueuePacket(&hpapp, false); if (members[x].member->IsClient() && members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) { //Mitch From 5a9c8c18c1d23816e33ad90317d29ea186c2eb79 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Fri, 21 Jan 2022 23:31:59 -0400 Subject: [PATCH 34/55] Bot Death fixed and few other crashes --- zone/bot.cpp | 27 +++++++++++++++++++++++++-- zone/bot.h | 1 + zone/bot_raid.cpp | 30 ++++++++++++------------------ zone/botspellsai.cpp | 2 +- zone/client.cpp | 7 ++++--- zone/raids.cpp | 13 ++++++++++++- zone/raids.h | 1 + 7 files changed, 56 insertions(+), 25 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index 09d3549fb..f5bb347fd 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -4049,7 +4049,13 @@ bool Bot::Spawn(Client* botCharacterOwner) { this->SendWearChange(materialFromSlot); } } + Raid* raid = entity_list.GetRaidByBotName(this->GetName()); + if (raid) + { + raid->VerifyRaid(); + this->SetRaidGrouped(true); + } return true; } @@ -5028,8 +5034,23 @@ bool Bot::Death(Mob *killerMob, int32 damage, uint16 spell_id, EQ::skills::Skill if ((GetPullingFlag() || GetReturningFlag()) && my_owner && my_owner->IsClient()) { my_owner->CastToClient()->SetBotPulling(false); } - if (!this->IsRaidGrouped()) + + Raid* raid = entity_list.GetRaidByBotName(this->GetName()); + uint32 gid = raid->GetGroup(this->GetName()); + if (raid) + { + for (int x = 0; x < MAX_RAID_MEMBERS; x++) + { + if (strcmp(raid->members[x].membername, this->GetName()) == 0) + { + raid->members[x].member = nullptr; + } + } + } + else + { entity_list.RemoveBot(this->GetID()); + } return true; } @@ -9294,8 +9315,10 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl break; } Group* g = caster->GetGroup(); + uint32 gid = 0xff; Raid* raid = entity_list.GetRaidByBotName(caster->GetName()); - uint32 gid = raid->GetGroup(caster->GetName()); + if (raid) + uint32 gid = raid->GetGroup(caster->GetName()); if(g) { for(int i = 0; i < MAX_GROUP_MEMBERS; i++) { diff --git a/zone/bot.h b/zone/bot.h index 90ae7e8cb..323a8f227 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -35,6 +35,7 @@ #include "../common/global_define.h" #include "guild_mgr.h" #include "worldserver.h" +#include "raids.h" #include diff --git a/zone/bot_raid.cpp b/zone/bot_raid.cpp index 74cd5592f..3d946b292 100644 --- a/zone/bot_raid.cpp +++ b/zone/bot_raid.cpp @@ -19,7 +19,6 @@ #ifdef BOTS #include "bot.h" -#include "bot_raid.h" #include "object.h" #include "raids.h" #include "doors.h" @@ -75,7 +74,7 @@ void Bot::AI_Process_Raid() // We also need a leash owner and follow mob (subset of primary AI criteria) Client* leash_owner = nullptr; - if (r_group < 12) { + if (r_group < 12 && !leash_owner) { leash_owner = raid->GetGroupLeader(r_group); } else { @@ -313,9 +312,7 @@ void Bot::AI_Process_Raid() std::vector raid_group_members = raid->GetRaidGroupMembers(r_group); for (RaidMember iter : raid_group_members) { - -// for (int counter = 0; counter < raid->GroupCount(r_group); counter++) { -// Group* bot_group = this->GetGroup(); + Mob* bg_member = iter.member;// bot_group->members[counter]; if (!bg_member) { continue; @@ -422,9 +419,9 @@ void Bot::AI_Process_Raid() else if (bo_alt_combat && m_alt_combat_hate_timer.Check()) { // Find a mob from hate list to target - // Group roles can be expounded upon in the future - Group* bot_group = this->GetGroup(); //Mitch - auto assist_mob = entity_list.GetMob(bot_group->GetMainAssistName()); + // Raid Group roles can be expounded upon in the future + //r_group is the uint32 group id + auto assist_mob = raid->GetRaidMainAssistOneByName(this->GetName()); bool find_target = true; if (assist_mob) { @@ -1540,6 +1537,7 @@ bool Bot::AICastSpell_Raid(Mob* tar, uint8 iChance, uint32 iSpellTypes) { // Bot AI Raid Raid* raid = entity_list.GetRaidByBotName(this->GetName()); + uint32 r_group = raid->GetGroup(GetName()); if (!raid) return false; @@ -2424,7 +2422,7 @@ bool Bot::AICastSpell_Raid(Mob* tar, uint8 iChance, uint32 iSpellTypes) { break; } case SpellType_Cure: { - if (GetNeedsCured(tar) && (tar->DontCureMeBefore() < Timer::GetCurrentTime()) && !(GetNumberNeedingHealedInGroup(25, false) > 0) && !(GetNumberNeedingHealedInGroup(40, false) > 2)) + if (GetNeedsCured(tar) && (tar->DontCureMeBefore() < Timer::GetCurrentTime()) && !(GetNumberNeedingHealedInRaidGroup(25, false) > 0) && !(GetNumberNeedingHealedInRaidGroup(40, false) > 2)) { botSpell = GetBestBotSpellForCure(this, tar); @@ -2438,16 +2436,12 @@ bool Bot::AICastSpell_Raid(Mob* tar, uint8 iChance, uint32 iSpellTypes) { if (castedSpell) { if (botClass != BARD) { if (IsGroupSpell(botSpell.SpellId)) { - Group* g; - - if (this->HasGroup()) { - Group* g = this->GetGroup(); - - if (g) { - for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { - if (g->members[i] && !g->members[i]->qglobal) { + if (this->IsRaidGrouped()) { + if (r_group) { + for (RaidMember iter : raid->GetRaidGroupMembers(r_group)) { + if (iter.member && !iter.member->qglobal) { if (TempDontCureMeBeforeTime != tar->DontCureMeBefore()) - g->members[i]->SetDontCureMeBefore(Timer::GetCurrentTime() + 4000); + iter.member->SetDontCureMeBefore(Timer::GetCurrentTime() + 4000); } } } diff --git a/zone/botspellsai.cpp b/zone/botspellsai.cpp index 5b0288485..94b119e71 100644 --- a/zone/botspellsai.cpp +++ b/zone/botspellsai.cpp @@ -3,7 +3,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. + the Free Software Foundation; version 2 ogroupf the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY except by those people which sell it, which diff --git a/zone/client.cpp b/zone/client.cpp index e47acc2ad..0dfd55dfd 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -812,9 +812,10 @@ void Client::QueuePacket(const EQApplicationPacket* app, bool ack_req, CLIENT_CO // todo: save packets for later use AddPacket(app, ack_req); } - else - if(eqs && !IsBot()) //Mitch added the BoTcheck for a fail safe on trying to send a packet to a BoT! - eqs->QueuePacket(app, ack_req); + else if (eqs && !IsBot()) //Mitch added the BoTcheck for a fail safe on trying to send a packet to a BoT! + { + eqs->QueuePacket(app, ack_req); + } } void Client::FastQueuePacket(EQApplicationPacket** app, bool ack_req, CLIENT_CONN_STATUS required_state) { diff --git a/zone/raids.cpp b/zone/raids.cpp index 7fd865f12..689aff450 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -1738,7 +1738,7 @@ void Raid::SendHPManaEndPacketsFrom(Mob *mob) mob->CreateHPPacket(&hpapp); for(int x = 0; x < MAX_RAID_MEMBERS; x++) { - if(members[x].member && members[x].membername) { + if(members[x].member) { if(!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) { members[x].member->QueuePacket(&hpapp, false); if (members[x].member->IsClient() && members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) { //Mitch @@ -1988,3 +1988,14 @@ bool Raid::DoesAnyMemberHaveExpeditionLockout( return Expedition::HasLockoutByCharacterName(raid_member.membername, expedition_name, event_name); }); } +Mob* Raid::GetRaidMainAssistOneByName(const char* name) +{ + Raid* raid = entity_list.GetRaidByBotName(name); + std::vector raid_members = raid->GetMembers(); + + for (RaidMember& iter : raid_members) + { + if (iter.IsRaidMainAssistOne) + return iter.member->CastToMob(); + } +} diff --git a/zone/raids.h b/zone/raids.h index 5ac1910f5..8c31d210f 100644 --- a/zone/raids.h +++ b/zone/raids.h @@ -124,6 +124,7 @@ public: #ifdef BOTS void AddBot(Bot* b, uint32 group = 0xFFFFFFFF, bool rleader=false, bool groupleader=false, bool looter=false); //Mitch void RaidBotGroupSay(Bot* b, uint8 language, uint8 lang_skill, const char* msg, ...); //Mitch + static Mob* GetRaidMainAssistOneByName(const char* name); #endif void RemoveMember(const char *c); void DisbandRaid(); From 19004730ad3fd114b0cd09619718fd307e98ead9 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Sun, 23 Jan 2022 23:49:00 -0400 Subject: [PATCH 35/55] Working on botgroup removal --- zone/bot.cpp | 13 ++++++- zone/bot_raid.cpp | 5 ++- zone/client_packet.cpp | 87 +++++++++++++++++++++++++++++++++--------- zone/raids.cpp | 36 +++++++++++------ 4 files changed, 108 insertions(+), 33 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index f5bb347fd..2caf3abc0 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -8426,8 +8426,10 @@ void Bot::Camp(bool databaseSave) { //Mitch Raid* bot_raid = entity_list.GetRaidByBotName(this->GetName()); if (bot_raid) { + uint32 gid = bot_raid->GetGroup(this->GetName()); bot_raid->SendRaidGroupRemove(this->GetName(), bot_raid->GetGroup(this->GetName())); bot_raid->RemoveMember(this->GetName()); + bot_raid->GroupUpdate(gid); } @@ -8655,7 +8657,8 @@ Bot* Bot::GetBotByBotClientOwnerAndBotName(Client* c, std::string botName) { void Bot::ProcessBotGroupInvite(Client* c, std::string botName) { if(c) { - Bot* invitedBot = GetBotByBotClientOwnerAndBotName(entity_list.GetBotByBotName(botName)->GetOwner()->CastToClient(), botName); +// Bot* invitedBot = GetBotByBotClientOwnerAndBotName(entity_list.GetBotByBotName(botName)->GetOwner()->CastToClient(), botName); + Bot* invitedBot = GetBotByBotClientOwnerAndBotName(c, botName); //Mitch changed entity from c if(invitedBot && !invitedBot->HasGroup()) { if(!c->IsGrouped()) { @@ -10292,6 +10295,9 @@ uint8 Bot::spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQ::const void Bot::ProcessRaidInvite(Client* invitee, Client* invitor) { + if (!invitee || !invitor) + return; + Raid* raid = entity_list.GetRaidByClient(invitor); Group* g_invitee = invitee->GetGroup(); Group* g_invitor = invitor->GetGroup(); @@ -10560,6 +10566,9 @@ void Bot::ProcessRaidInvite(Client* invitee, Client* invitor) { void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { + if (!invitee || !invitor) + return; + Raid* raid = entity_list.GetRaidByClient(invitor); Group* g_invitee = invitee->GetGroup(); Group* g_invitor = invitor->GetGroup(); @@ -10686,7 +10695,7 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { // raid->GroupUpdate(0, true); // raid->SendBulkRaid(invitee); //Send a raid updates to the invitor g_invitor->JoinRaidXTarget(raid, true); -// g_invitor->DisbandGroup(true); + g_invitor->DisbandGroup(true); //Added Jan 23 to fix group database and entity integrity raid->GroupUpdate(0, true); if (raid->IsLocked()) { raid->SendRaidLockTo(invitor); diff --git a/zone/bot_raid.cpp b/zone/bot_raid.cpp index 3d946b292..c66fa32ff 100644 --- a/zone/bot_raid.cpp +++ b/zone/bot_raid.cpp @@ -74,7 +74,10 @@ void Bot::AI_Process_Raid() // We also need a leash owner and follow mob (subset of primary AI criteria) Client* leash_owner = nullptr; - if (r_group < 12 && !leash_owner) { + if (r_group < 12 && raid->IsGroupLeader(this->GetName())) { + leash_owner = raid->GetLeader(); + } + else if (r_group < 12) { leash_owner = raid->GetGroupLeader(r_group); } else { diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 7e7d3b60e..996071459 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -11756,10 +11756,79 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) case RaidCommandDisband: { Raid* raid = entity_list.GetRaidByClient(this); Client* c = entity_list.GetClientByName(raid_command_packet->leader_name); + Bot* b = entity_list.GetBotByBotName(raid_command_packet->leader_name); if (raid) { uint32 group = raid->GetGroup(raid_command_packet->leader_name); +#ifdef BOTS + //Mitch added to remove all bots if the Bot_Owner is removed from the Raid + //Does not camp the Bots, just removes from the raid + std::vector raid_members_bots; + if (c) + { + int owner_id = c->CharacterID(); + for (int i = 0; i < MAX_RAID_MEMBERS; ++i) + { + if (raid->members[i].member && raid->members[i].member->IsBot() && raid->members[i].member->CastToBot()->GetOwner()->CastToClient()->CharacterID() == owner_id) + { + raid_members_bots.emplace_back(raid->members[i].member->CastToBot()); + } + } + // If the bot is a group leader then re-create the botgroup, dropping any clients + for (auto bot_iter : raid_members_bots) { + if (bot_iter && bot_iter->IsBot()) + if (raid->IsGroupLeader(bot_iter->GetName())) + { + uint32 gid = raid->GetGroup(bot_iter->GetName()); + std::vector r_group_members = raid->GetRaidGroupMembers(gid); + Group* group_inst = new Group(bot_iter); + entity_list.AddGroup(group_inst); + database.SetGroupID(bot_iter->GetCleanName(), group_inst->GetID(), bot_iter->GetBotID()); + database.SetGroupLeaderName(group_inst->GetID(), bot_iter->GetCleanName()); + bot_iter->SetFollowID(c->GetID()); + for (auto member_iter : r_group_members) { + if (!member_iter.member->IsClient() && strcmp(member_iter.membername, bot_iter->GetName()) == 0) + bot_iter->SetFollowID(owner_id); + else + Bot::AddBotToGroup(member_iter.member->CastToBot(), group_inst); + } + } + raid->RemoveMember(bot_iter->GetName()); + } + } + else if (b) + { + uint32 gid = raid->GetGroup(raid_command_packet->leader_name); + if (gid < 12 && raid->GetGroupLeader(gid)->IsBot()) + { + Client* c2 = entity_list.GetClientByName(raid_command_packet->player_name); + if (c2 && !raid->IsGroupLeader(raid_command_packet->leader_name)) { + c2->Message(Chat::Red, "%s is in a Bot Group. Please disband %s instead.", + raid_command_packet->leader_name, raid->GetGroupLeader(gid)->CastToBot()->GetName()); + break; + } + else + { + uint32 gid = raid->GetGroup(b->GetName()); + std::vector r_group_members = raid->GetRaidGroupMembers(gid); + Group* group_inst = new Group(b); + entity_list.AddGroup(group_inst); + database.SetGroupID(b->GetCleanName(), group_inst->GetID(), b->GetBotID()); + database.SetGroupLeaderName(group_inst->GetID(), b->GetCleanName()); + for (auto member_iter : r_group_members) { + if (!member_iter.member->IsClient() && strcmp(member_iter.membername, b->GetName()) == 0) + member_iter.member->SetFollowID(b->GetOwner()->CastToClient()->GetID()); + else + Bot::AddBotToGroup(member_iter.member->CastToBot(), group_inst); + raid->RemoveMember(member_iter.membername); + } + + } + + } + } +#endif if (group < 12) { uint32 i = raid->GetPlayerIndex(raid_command_packet->leader_name); if (raid->members[i].IsGroupLeader) { //assign group leader to someone else @@ -11790,24 +11859,6 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) raid->RemoveMember(raid_command_packet->leader_name); Client* c = entity_list.GetClientByName(raid_command_packet->leader_name); if (c) { -#ifdef BOTS - - //Mitch added to remove all bots if the Bot_Owner is removed from the Raid - //Does not camp the Bots, just removes from the raid - std::vector raid_members_bots; - int owner_id = entity_list.GetClientByName(raid_command_packet->leader_name)->CharacterID(); - for (int i = 0; i < MAX_RAID_MEMBERS; ++i) - { - if (raid->members[i].member && raid->members[i].member->IsBot() && raid->members[i].member->CastToBot()->GetOwner()->CastToClient()->CharacterID() == owner_id) - { - raid_members_bots.emplace_back(raid->members[i].member->CastToBot()); - } - } - for (auto bot_iter : raid_members_bots) { - if (bot_iter && bot_iter->IsBot()) - raid->RemoveMember(bot_iter->GetName()); - } -#endif raid->SendGroupDisband(c); } diff --git a/zone/raids.cpp b/zone/raids.cpp index 689aff450..ac83812ff 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -110,6 +110,14 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo LearnMembers(); VerifyRaid(); + +#ifdef BOTS + if (rleader) { + database.SetRaidGroupLeaderInfo(group, GetID()); + UpdateRaidAAs(); + } + else +#endif if (rleader) { database.SetRaidGroupLeaderInfo(RAID_GROUPLESS, GetID()); UpdateRaidAAs(); @@ -182,18 +190,22 @@ void Raid::AddBot(Bot* b, uint32 group, bool rleader, bool groupleader, bool loo LearnMembers(); VerifyRaid(); - if (rleader) { - database.SetRaidGroupLeaderInfo(RAID_GROUPLESS, GetID()); - UpdateRaidAAs(); - } - if (group != RAID_GROUPLESS && groupleader) { - database.SetRaidGroupLeaderInfo(group, GetID()); - //UpdateGroupAAs(group); - } -// if (group < 12) -// GroupUpdate(group); -// else // get raid AAs, GroupUpdate will handles it otherwise - //SendGroupLeadershipAA(c, RAID_GROUPLESS); Is this needed for bots? +// Bots are being invited and cannot be the raid leader +// if (rleader) { +// database.SetRaidGroupLeaderInfo(RAID_GROUPLESS, GetID()); +// UpdateRaidAAs(); +// } + +// Bots can be group leaders, though they do not have GroupAA +// if (group != RAID_GROUPLESS && groupleader) { +// database.SetRaidGroupLeaderInfo(group, GetID()); +// UpdateGroupAAs(group); //Mitch Jan 22 +// } + + if (group < 12) //Jan22 + GroupUpdate(group); //Jan22 + else // get raid AAs, GroupUpdate will handles it otherwise Jan 22 + SendGroupLeadershipAA(b->GetOwner()->CastToClient(), RAID_GROUPLESS); //Is this needed for bots? Jan 22 SendRaidAddAll(b->GetName()); b->SetRaidGrouped(true); From c9b8127236cee8f4c297b797971ff9ef710198fb Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Mon, 24 Jan 2022 17:05:28 -0400 Subject: [PATCH 36/55] Bot Disbanding Work 90% --- zone/client_packet.cpp | 97 ++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 47 deletions(-) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 996071459..f7b1c2ae4 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -11755,9 +11755,10 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) } case RaidCommandDisband: { Raid* raid = entity_list.GetRaidByClient(this); - Client* c = entity_list.GetClientByName(raid_command_packet->leader_name); - Bot* b = entity_list.GetBotByBotName(raid_command_packet->leader_name); - + Client* c_to_disband = entity_list.GetClientByName(raid_command_packet->leader_name); + Client* c_doing_disband = entity_list.GetClientByName(raid_command_packet->player_name); + Bot* b_to_disband = entity_list.GetBotByBotName(raid_command_packet->leader_name); + if (raid) { uint32 group = raid->GetGroup(raid_command_packet->leader_name); @@ -11765,9 +11766,10 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) //Mitch added to remove all bots if the Bot_Owner is removed from the Raid //Does not camp the Bots, just removes from the raid std::vector raid_members_bots; - if (c) + if (c_to_disband) { - int owner_id = c->CharacterID(); + // Determine if the client has any BOTS in the raid + uint32 owner_id = c_to_disband->CharacterID(); for (int i = 0; i < MAX_RAID_MEMBERS; ++i) { if (raid->members[i].member && raid->members[i].member->IsBot() && raid->members[i].member->CastToBot()->GetOwner()->CastToClient()->CharacterID() == owner_id) @@ -11775,57 +11777,58 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) raid_members_bots.emplace_back(raid->members[i].member->CastToBot()); } } - // If the bot is a group leader then re-create the botgroup, dropping any clients + // If any of the bots are a group leader then re-create the botgroup on disband, dropping any clients for (auto bot_iter : raid_members_bots) { - if (bot_iter && bot_iter->IsBot()) - if (raid->IsGroupLeader(bot_iter->GetName())) - { - uint32 gid = raid->GetGroup(bot_iter->GetName()); - std::vector r_group_members = raid->GetRaidGroupMembers(gid); - Group* group_inst = new Group(bot_iter); - entity_list.AddGroup(group_inst); - database.SetGroupID(bot_iter->GetCleanName(), group_inst->GetID(), bot_iter->GetBotID()); - database.SetGroupLeaderName(group_inst->GetID(), bot_iter->GetCleanName()); - bot_iter->SetFollowID(c->GetID()); - for (auto member_iter : r_group_members) { - if (!member_iter.member->IsClient() && strcmp(member_iter.membername, bot_iter->GetName()) == 0) - bot_iter->SetFollowID(owner_id); - else - Bot::AddBotToGroup(member_iter.member->CastToBot(), group_inst); - } - } - raid->RemoveMember(bot_iter->GetName()); - } - } - else if (b) - { - uint32 gid = raid->GetGroup(raid_command_packet->leader_name); - if (gid < 12 && raid->GetGroupLeader(gid)->IsBot()) - { - Client* c2 = entity_list.GetClientByName(raid_command_packet->player_name); - if (c2 && !raid->IsGroupLeader(raid_command_packet->leader_name)) { - c2->Message(Chat::Red, "%s is in a Bot Group. Please disband %s instead.", - raid_command_packet->leader_name, raid->GetGroupLeader(gid)->CastToBot()->GetName()); - break; - } - else + if (bot_iter && raid->IsGroupLeader(bot_iter->GetName())) { - uint32 gid = raid->GetGroup(b->GetName()); + // Remove the entire BOT group in this case + uint32 gid = raid->GetGroup(bot_iter->GetName()); std::vector r_group_members = raid->GetRaidGroupMembers(gid); - Group* group_inst = new Group(b); + Group* group_inst = new Group(bot_iter); entity_list.AddGroup(group_inst); - database.SetGroupID(b->GetCleanName(), group_inst->GetID(), b->GetBotID()); - database.SetGroupLeaderName(group_inst->GetID(), b->GetCleanName()); + database.SetGroupID(bot_iter->GetCleanName(), group_inst->GetID(), bot_iter->GetBotID()); + database.SetGroupLeaderName(group_inst->GetID(), bot_iter->GetCleanName()); for (auto member_iter : r_group_members) { - if (!member_iter.member->IsClient() && strcmp(member_iter.membername, b->GetName()) == 0) - member_iter.member->SetFollowID(b->GetOwner()->CastToClient()->GetID()); + if (!member_iter.member->IsClient() && strcmp(member_iter.membername, bot_iter->GetName()) == 0) + bot_iter->SetFollowID(owner_id); else Bot::AddBotToGroup(member_iter.member->CastToBot(), group_inst); - raid->RemoveMember(member_iter.membername); + raid->RemoveMember(bot_iter->GetName()); } - } - + } + } + else if (b_to_disband) + { + uint32 gid = raid->GetGroup(b_to_disband->GetName()); + if (gid < 12 && raid->IsGroupLeader(b_to_disband->GetName())) + { + // If any of the bots are a group leader then re-create the botgroup on disband, dropping any clients + std::vector r_group_members = raid->GetRaidGroupMembers(gid); + uint32 owner_id = b_to_disband->CastToBot()->GetOwner()->CastToClient()->CharacterID(); + if (raid->IsGroupLeader(b_to_disband->GetName())) + { + // Remove the entire BOT group in this case + //uint32 gid = raid->GetGroup(b_to_disband->GetName()); + //std::vector r_group_members = raid->GetRaidGroupMembers(gid); + Group* group_inst = new Group(b_to_disband); + entity_list.AddGroup(group_inst); + database.SetGroupID(b_to_disband->GetCleanName(), group_inst->GetID(), b_to_disband->GetBotID()); + database.SetGroupLeaderName(group_inst->GetID(), b_to_disband->GetCleanName()); + for (auto member_iter : r_group_members) { + if (!member_iter.member->IsClient() && strcmp(member_iter.membername, b_to_disband->GetName()) == 0) + b_to_disband->SetFollowID(owner_id); + else + Bot::AddBotToGroup(member_iter.member->CastToBot(), group_inst); + raid->RemoveMember(member_iter.member->CastToBot()->GetName()); + } + } + } + else if (gid <12 && raid->GetGroupLeader(gid)->IsBot()) + { + c_doing_disband->Message(Chat::Yellow, "%s is in a Bot Group. Please disband %s instead to remove the entire Bot group.", + raid_command_packet->leader_name, raid->GetGroupLeader(gid)->CastToBot()->GetName()); + break; } } #endif From 3098acdc953ff97320ffe808e459dc4f10a723f4 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Mon, 24 Jan 2022 23:05:17 -0400 Subject: [PATCH 37/55] Looks like BOTs are working --- zone/client_packet.cpp | 16 ++++++++++++---- zone/raids.cpp | 6 +++--- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index f7b1c2ae4..9ff37b676 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -6989,9 +6989,9 @@ void Client::Handle_OP_GroupInvite2(const EQApplicationPacket *app) #ifdef BOTS else if (Invitee->IsBot()) { Client* inviter = entity_list.GetClientByName(gis->inviter_name); - Bot* invitee = entity_list.GetBotByBotName(gis->invitee_name); + //Bot* invitee = entity_list.GetBotByBotName(gis->invitee_name); if (inviter->IsRaidGrouped()) - Bot::ProcessRaidInvite(invitee, inviter); + Bot::ProcessRaidInvite(Invitee->CastToBot(), inviter); else Bot::ProcessBotGroupInvite(this, std::string(Invitee->GetName())); } @@ -11779,10 +11779,11 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) } // If any of the bots are a group leader then re-create the botgroup on disband, dropping any clients for (auto bot_iter : raid_members_bots) { - if (bot_iter && raid->IsGroupLeader(bot_iter->GetName())) + if (bot_iter && raid->IsRaidMember(bot_iter->GetName()) && raid->IsGroupLeader(bot_iter->GetName())) { // Remove the entire BOT group in this case uint32 gid = raid->GetGroup(bot_iter->GetName()); + std::vector r_group_members = raid->GetRaidGroupMembers(gid); Group* group_inst = new Group(bot_iter); entity_list.AddGroup(group_inst); @@ -11791,11 +11792,16 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) for (auto member_iter : r_group_members) { if (!member_iter.member->IsClient() && strcmp(member_iter.membername, bot_iter->GetName()) == 0) bot_iter->SetFollowID(owner_id); + else Bot::AddBotToGroup(member_iter.member->CastToBot(), group_inst); raid->RemoveMember(bot_iter->GetName()); } } + else if (bot_iter && raid->IsRaidMember(bot_iter->GetName())) + { + raid->RemoveMember(bot_iter->GetName()); + } } } else if (b_to_disband) @@ -11823,6 +11829,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) raid->RemoveMember(member_iter.member->CastToBot()->GetName()); } } + break; } else if (gid <12 && raid->GetGroupLeader(gid)->IsBot()) { @@ -11878,7 +11885,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) } //r->SendRaidGroupRemove(ri->leader_name, grp); raid->GroupUpdate(group);// break - //} + if (!raid->RaidCount()) + raid->DisbandRaid(); } break; } diff --git a/zone/raids.cpp b/zone/raids.cpp index ac83812ff..657c8a604 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -261,10 +261,10 @@ void Raid::RemoveMember(const char *characterName) Bot* bot = entity_list.GetBotByBotName(characterName); if (bot) { - bot->SetFollowID(bot->GetOwner()->GetID()); - bot->SetGrouped(0); + bot->SetFollowID(bot->GetOwner()->CastToClient()->GetID()); + bot->SetGrouped(false); bot->SetTarget(nullptr); - bot->SetRaidGrouped(0); + bot->SetRaidGrouped(false); } #endif From cf2c7060bec2f83afcb1897965ee61a37a528a6c Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Tue, 25 Jan 2022 19:06:38 -0400 Subject: [PATCH 38/55] Fixed a bot crash --- zone/bot.cpp | 5 +++-- zone/bot.h | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index 2caf3abc0..9cca12353 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -5036,10 +5036,11 @@ bool Bot::Death(Mob *killerMob, int32 damage, uint16 spell_id, EQ::skills::Skill } Raid* raid = entity_list.GetRaidByBotName(this->GetName()); - uint32 gid = raid->GetGroup(this->GetName()); + if (raid) { - for (int x = 0; x < MAX_RAID_MEMBERS; x++) + + for (int x = 0; x < MAX_RAID_MEMBERS; x++) { if (strcmp(raid->members[x].membername, this->GetName()) == 0) { diff --git a/zone/bot.h b/zone/bot.h index 323a8f227..bef90cf0e 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -387,6 +387,7 @@ public: static void ProcessRaidInvite(Bot* invitee, Client* invitor); //Mitch static void ProcessRaidInvite(Client* invitee, Client* invitor); //Mitch uint8 GetNumberNeedingHealedInRaidGroup(uint8 hpr, bool includePets); //Mitch + inline void SetDirtyAutoHaters() { m_dirtyautohaters = true; } static std::list GetBotSpellsForSpellEffect(Bot* botCaster, int spellEffect); static std::list GetBotSpellsForSpellEffectAndTargetType(Bot* botCaster, int spellEffect, SpellTargetType targetType); @@ -736,6 +737,9 @@ private: bool SavePet(); // Save and depop bot pet if there is one bool DeletePet(); + //Raid Additions + bool m_dirtyautohaters; + public: static uint8 spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND]; }; From 478fa24a707c283f0eea37f74bfa6a10546c8b42 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Tue, 25 Jan 2022 23:16:33 -0400 Subject: [PATCH 39/55] bug tracing on entity list mismatch --- zone/bot.cpp | 8 ++++---- zone/bot.h | 4 ++-- zone/mob.cpp | 3 ++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index 9cca12353..e46d8d025 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -5048,10 +5048,10 @@ bool Bot::Death(Mob *killerMob, int32 damage, uint16 spell_id, EQ::skills::Skill } } } - else - { - entity_list.RemoveBot(this->GetID()); - } +// else +// { + entity_list.RemoveBot(this->GetID()); +// } return true; } diff --git a/zone/bot.h b/zone/bot.h index bef90cf0e..f0cc3510b 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -152,8 +152,8 @@ public: ExtraAttackOptions *opts = nullptr); virtual bool HasRaid() { return (GetRaid() ? true : false); } virtual bool HasGroup() { return (GetGroup() ? true : false); } - virtual Raid* GetRaid() { return entity_list.GetRaidByMob(this); } - virtual Group* GetGroup() { return entity_list.GetGroupByMob(this); } + virtual Raid* GetRaid() { return entity_list.GetRaidByMob(this); } // GetRaidByMob(this); + virtual Group* GetGroup() { return entity_list.GetGroupByMob(this); } // GetGroupByMob; // Common, but informal "interfaces" with Client object uint32 CharacterID() { return GetBotID(); } // Just returns the Bot Id diff --git a/zone/mob.cpp b/zone/mob.cpp index efaf619ef..c51d372f2 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -3033,7 +3033,8 @@ void Mob::QuestJournalledSay(Client *QuestInitiator, const char *str, Journal::O const char *Mob::GetCleanName() { if (clean_name != NULL && !strlen(clean_name)) { //extra check added for crash condition. Mitch - CleanMobName(GetName(), clean_name); + if (this) + CleanMobName(GetName(), clean_name); } return clean_name; From c2d1857223f3e5297d588a8c71d25cab13ada8f9 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Sat, 29 Jan 2022 19:31:57 -0400 Subject: [PATCH 40/55] safe_delete resoves problem. No to track down leak --- common/types.h | 3 ++ zone/bot.cpp | 104 +++++++++++++++++++++++++--------------------- zone/bot_raid.cpp | 29 +++++++------ zone/raids.h | 3 +- 4 files changed, 78 insertions(+), 61 deletions(-) diff --git a/common/types.h b/common/types.h index b3be97d32..2a6355296 100644 --- a/common/types.h +++ b/common/types.h @@ -57,6 +57,9 @@ typedef const char Const_char; //for perl XS #define safe_delete(d) if(d) { delete d; d=nullptr; } #define safe_delete_array(d) if(d) { delete[] d; d=nullptr; } +//#define safe_delete(d)(_RPTF0(_CRT_WARN,"Testing delete function\n")); +//#define safe_delete(d) if(d) { } +//#define safe_delete_array(d) if(d) { } #define L32(i) ((uint32) i) #define H32(i) ((uint32) (i >> 32)) #define L16(i) ((uint16) i) diff --git a/zone/bot.cpp b/zone/bot.cpp index e46d8d025..e2628a34e 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -7745,11 +7745,13 @@ bool Bot::DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, EQ::spel } else if (raid) { - for (RaidMember iter : raid->GetRaidGroupMembers(raid->GetGroup(this->GetName()))) { - if (iter.member) { - SpellOnTarget(spell_id, iter.member); - if (iter.member && iter.member->GetPetID()) - SpellOnTarget(spell_id, iter.member ->GetPet()); + //for (auto& iter : raid->GetRaidGroupMembers(raid->GetGroup(this->GetName()))) { + std::vector raid_group_members = raid->GetRaidGroupMembers(raid->GetGroup(this->GetName())); + for (std::vector::iterator iter = raid_group_members.begin(); iter != raid_group_members.end(); ++iter) { + if (iter->member) { + SpellOnTarget(spell_id, iter->member); + if (iter->member && iter->member->GetPetID()) + SpellOnTarget(spell_id, iter->member ->GetPet()); } } } @@ -9264,34 +9266,36 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl { //added raid check Raid* raid = entity_list.GetRaidByBotName(caster->GetName()); - uint32 g = raid->GetGroup(caster->GetName()); - if (g < 12) { - for (RaidMember& iter : raid->GetRaidGroupMembers(g)) { - if (iter.member && !iter.member->qglobal) { - if (iter.member->IsClient() && iter.member->GetHPRatio() < 90) { - if (caster->AICastSpell(iter.member, 100, SpellType_Heal)) + uint32 gid = raid->GetGroup(caster->GetName()); + if (gid < 12) { + std::vector raid_group_members = raid->GetRaidGroupMembers(gid); + for (std::vector::iterator iter = raid_group_members.begin(); iter != raid_group_members.end(); ++iter) { + //for (auto& iter : raid->GetRaidGroupMembers(g)) { + if (iter->member && !iter->member->qglobal) { + if (iter->member->IsClient() && iter->member->GetHPRatio() < 90) { + if (caster->AICastSpell(iter->member, 100, SpellType_Heal)) return true; } - else if ((iter.member->GetClass() == WARRIOR || iter.member->GetClass() == PALADIN || iter.member->GetClass() == SHADOWKNIGHT) && iter.member->GetHPRatio() < 95) { - if (caster->AICastSpell(iter.member, 100, SpellType_Heal)) + else if ((iter->member->GetClass() == WARRIOR || iter->member->GetClass() == PALADIN || iter->member->GetClass() == SHADOWKNIGHT) && iter->member->GetHPRatio() < 95) { + if (caster->AICastSpell(iter->member, 100, SpellType_Heal)) return true; } - else if (iter.member->GetClass() == ENCHANTER && iter.member->GetHPRatio() < 80) { - if (caster->AICastSpell(iter.member, 100, SpellType_Heal)) + else if (iter->member->GetClass() == ENCHANTER && iter->member->GetHPRatio() < 80) { + if (caster->AICastSpell(iter->member, 100, SpellType_Heal)) return true; } - else if (iter.member->GetHPRatio() < 70) { - if (caster->AICastSpell(iter.member, 100, SpellType_Heal)) + else if (iter->member->GetHPRatio() < 70) { + if (caster->AICastSpell(iter->member, 100, SpellType_Heal)) return true; } } - if (iter.member && !iter.member->qglobal && iter.member->HasPet() && iter.member->GetPet()->GetHPRatio() < 50) { - if (iter.member->GetPet()->GetOwner() != caster && caster->IsEngaged() && iter.member->IsCasting() && iter.member->GetClass() != ENCHANTER) + if (iter->member && !iter->member->qglobal && iter->member->HasPet() && iter->member->GetPet()->GetHPRatio() < 50) { + if (iter->member->GetPet()->GetOwner() != caster && caster->IsEngaged() && iter->member->IsCasting() && iter->member->GetClass() != ENCHANTER) continue; - if (caster->AICastSpell(iter.member->GetPet(), 100, SpellType_Heal)) + if (caster->AICastSpell(iter->member->GetPet(), 100, SpellType_Heal)) return true; } } @@ -9353,31 +9357,33 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl } else if (gid < 12) { - for (RaidMember& iter : raid->GetRaidGroupMembers(gid)) { - if (iter.member && !iter.member->qglobal) { - if (iter.member->IsClient() && iter.member->GetHPRatio() < hpRatioToHeal) { - if (caster->AICastSpell(iter.member, 100, SpellType_Heal)) + std::vector raid_group_members = raid->GetRaidGroupMembers(gid); + for (std::vector::iterator iter = raid_group_members.begin(); iter != raid_group_members.end(); ++iter) { + //for (auto& iter : raid->GetRaidGroupMembers(gid)) { + if (iter->member && !iter->member->qglobal) { + if (iter->member->IsClient() && iter->member->GetHPRatio() < hpRatioToHeal) { + if (caster->AICastSpell(iter->member, 100, SpellType_Heal)) return true; } - else if ((iter.member->GetClass() == WARRIOR || iter.member->GetClass() == PALADIN || iter.member->GetClass() == SHADOWKNIGHT) && iter.member->GetHPRatio() < hpRatioToHeal) { - if (caster->AICastSpell(iter.member, 100, SpellType_Heal)) + else if ((iter->member->GetClass() == WARRIOR || iter->member->GetClass() == PALADIN || iter->member->GetClass() == SHADOWKNIGHT) && iter->member->GetHPRatio() < hpRatioToHeal) { + if (caster->AICastSpell(iter->member, 100, SpellType_Heal)) return true; } - else if (iter.member->GetClass() == ENCHANTER && iter.member->GetHPRatio() < hpRatioToHeal) { - if (caster->AICastSpell(iter.member, 100, SpellType_Heal)) + else if (iter->member->GetClass() == ENCHANTER && iter->member->GetHPRatio() < hpRatioToHeal) { + if (caster->AICastSpell(iter->member, 100, SpellType_Heal)) return true; } - else if (iter.member->GetHPRatio() < hpRatioToHeal / 2) { - if (caster->AICastSpell(iter.member, 100, SpellType_Heal)) + else if (iter->member->GetHPRatio() < hpRatioToHeal / 2) { + if (caster->AICastSpell(iter->member, 100, SpellType_Heal)) return true; } } - if (iter.member && !iter.member->qglobal && iter.member->HasPet() && iter.member->GetPet()->GetHPRatio() < 25) { - if (iter.member->GetPet()->GetOwner() != caster && caster->IsEngaged() && iter.member->IsCasting() && iter.member->GetClass() != ENCHANTER) + if (iter->member && !iter->member->qglobal && iter->member->HasPet() && iter->member->GetPet()->GetHPRatio() < 25) { + if (iter->member->GetPet()->GetOwner() != caster && caster->IsEngaged() && iter->member->IsCasting() && iter->member->GetClass() != ENCHANTER) continue; - if (caster->AICastSpell(iter.member->GetPet(), 100, SpellType_Heal)) + if (caster->AICastSpell(iter->member->GetPet(), 100, SpellType_Heal)) return true; } } @@ -9400,9 +9406,10 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl Raid* raid = entity_list.GetRaidByBotName(caster->GetName()); uint32 g = raid->GetGroup(caster->GetName()); if (g < 12) { - for (RaidMember &iter : raid->GetRaidGroupMembers(g)) { - if (iter.member) { - if (caster->AICastSpell(iter.member, chanceToCast, SpellType_Buff) || caster->AICastSpell(iter.member->GetPet(), chanceToCast, SpellType_Buff)) + std::vector raid_group_members = raid->GetRaidGroupMembers(g); + for (std::vector::iterator iter = raid_group_members.begin(); iter != raid_group_members.end(); ++iter) { + if (iter->member) { + if (caster->AICastSpell(iter->member, chanceToCast, SpellType_Buff) || caster->AICastSpell(iter->member->GetPet(), chanceToCast, SpellType_Buff)) return true; } } @@ -9446,16 +9453,17 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl Raid* raid = entity_list.GetRaidByBotName(caster->GetName()); uint32 gid = raid->GetGroup(caster->GetName()); if (gid < 12) { - for (RaidMember& iter : raid->GetRaidGroupMembers(gid)) { - if (iter.member && caster->GetNeedsCured(iter.member)) { - if (caster->AICastSpell(iter.member, caster->GetChanceToCastBySpellType(SpellType_Cure), SpellType_Cure)) + std::vector raid_group_members = raid->GetRaidGroupMembers(gid); + for (std::vector::iterator iter = raid_group_members.begin(); iter != raid_group_members.end(); ++iter) { + if (iter->member && caster->GetNeedsCured(iter->member)) { + if (caster->AICastSpell(iter->member, caster->GetChanceToCastBySpellType(SpellType_Cure), SpellType_Cure)) return true; else if (botCasterClass == BARD) return false; } - if (iter.member && iter.member->GetPet() && caster->GetNeedsCured(iter.member->GetPet())) { - if (caster->AICastSpell(iter.member->GetPet(), (int)caster->GetChanceToCastBySpellType(SpellType_Cure) / 4, SpellType_Cure)) + if (iter->member && iter->member->GetPet() && caster->GetNeedsCured(iter->member->GetPet())) { + if (caster->AICastSpell(iter->member->GetPet(), (int)caster->GetChanceToCastBySpellType(SpellType_Cure) / 4, SpellType_Cure)) return true; } } @@ -9483,9 +9491,10 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl Raid* raid = entity_list.GetRaidByBotName(caster->GetName()); uint32 gid = raid->GetGroup(caster->GetName()); if (gid < 12) { - for (RaidMember& iter : raid->GetRaidGroupMembers(gid)) { - if (iter.member && caster->GetNeedsHateRedux(iter.member)) { - if (caster->AICastSpell(iter.member, caster->GetChanceToCastBySpellType(SpellType_HateRedux), SpellType_HateRedux)) + std::vector raid_group_members = raid->GetRaidGroupMembers(gid); + for (std::vector::iterator iter = raid_group_members.begin(); iter != raid_group_members.end(); ++iter) { + if (iter->member && caster->GetNeedsHateRedux(iter->member)) { + if (caster->AICastSpell(iter->member, caster->GetChanceToCastBySpellType(SpellType_HateRedux), SpellType_HateRedux)) return true; } } @@ -9503,9 +9512,10 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl Raid* raid = entity_list.GetRaidByBotName(caster->GetName()); uint32 g = raid->GetGroup(caster->GetName()); if (g < 12) { - for (RaidMember& iter : raid->GetRaidGroupMembers(g)) { - if (iter.member) { - if (caster->AICastSpell(iter.member, iChance, SpellType_PreCombatBuff) || caster->AICastSpell(iter.member->GetPet(), iChance, SpellType_PreCombatBuff)) + std::vector raid_group_members = raid->GetRaidGroupMembers(g); + for (std::vector::iterator iter = raid_group_members.begin(); iter != raid_group_members.end(); ++iter) { + if (iter->member) { + if (caster->AICastSpell(iter->member, iChance, SpellType_PreCombatBuff) || caster->AICastSpell(iter->member->GetPet(), iChance, SpellType_PreCombatBuff)) return true; } } diff --git a/zone/bot_raid.cpp b/zone/bot_raid.cpp index c66fa32ff..78ae8c909 100644 --- a/zone/bot_raid.cpp +++ b/zone/bot_raid.cpp @@ -314,9 +314,9 @@ void Bot::AI_Process_Raid() else { std::vector raid_group_members = raid->GetRaidGroupMembers(r_group); - for (RaidMember iter : raid_group_members) { + for (std::vector::iterator iter = raid_group_members.begin(); iter != raid_group_members.end(); ++iter) { - Mob* bg_member = iter.member;// bot_group->members[counter]; + Mob* bg_member = iter->member;// bot_group->members[counter]; if (!bg_member) { continue; } @@ -1525,6 +1525,8 @@ void Bot::PetAIProcess_Raid() { std::vector Raid::GetRaidGroupMembers(uint32 gid) { std::vector raid_group_members; + raid_group_members.clear(); + for (int i = 0; i < MAX_RAID_MEMBERS; ++i) { if (members[i].member && members[i].GroupNumber == gid) @@ -1775,12 +1777,12 @@ bool Bot::AICastSpell_Raid(Mob* tar, uint8 iChance, uint32 iSpellTypes) { if (IsGroupSpell(botSpell.SpellId)) { if (IsRaidGrouped()) { uint32 r_group = raid->GetGroup(GetName()); - std::vector raid_group_members = raid->GetRaidGroupMembers(r_group); BotGroupSay(this, "Casting %s.", spells[botSpell.SpellId].name); //raid->RaidBotGroupSay(this, 0, 100, "Casting %s.", spells[botSpell.SpellId].name); - for (RaidMember iter : raid_group_members) { - if (iter.member && !iter.member->qglobal) { - iter.member->SetDontHealMeBefore(Timer::GetCurrentTime() + 1000); + std::vector raid_group_members = raid->GetRaidGroupMembers(r_group); + for (std::vector::iterator iter = raid_group_members.begin(); iter != raid_group_members.end(); ++iter) { + if (iter->member && !iter->member->qglobal) { + iter->member->SetDontHealMeBefore(Timer::GetCurrentTime() + 1000); } } } @@ -2441,10 +2443,11 @@ bool Bot::AICastSpell_Raid(Mob* tar, uint8 iChance, uint32 iSpellTypes) { if (IsGroupSpell(botSpell.SpellId)) { if (this->IsRaidGrouped()) { if (r_group) { - for (RaidMember iter : raid->GetRaidGroupMembers(r_group)) { - if (iter.member && !iter.member->qglobal) { + std::vector raid_group_members = raid->GetRaidGroupMembers(r_group); + for (std::vector::iterator iter = raid_group_members.begin(); iter != raid_group_members.end(); ++iter) { + if (iter->member && !iter->member->qglobal) { if (TempDontCureMeBeforeTime != tar->DontCureMeBefore()) - iter.member->SetDontCureMeBefore(Timer::GetCurrentTime() + 4000); + iter->member->SetDontCureMeBefore(Timer::GetCurrentTime() + 4000); } } } @@ -2600,13 +2603,13 @@ uint8 Bot::GetNumberNeedingHealedInRaidGroup(uint8 hpr, bool includePets) { raid = entity_list.GetRaidByBotName(this->GetName()); uint32 r_group = raid->GetGroup(this->GetName()); std::vector raid_group_members = raid->GetRaidGroupMembers(r_group); - for (RaidMember iter : raid_group_members) { - if (iter.member && !iter.member->qglobal) { - if (iter.member->GetHPRatio() <= hpr) + for (std::vector::iterator iter = raid_group_members.begin(); iter != raid_group_members.end(); ++iter) { + if (iter->member && !iter->member->qglobal) { + if (iter->member->GetHPRatio() <= hpr) needHealed++; if (includePets) { - if (iter.member->GetPet() && iter.member->GetPet()->GetHPRatio() <= hpr) + if (iter->member->GetPet() && iter->member->GetPet()->GetHPRatio() <= hpr) needHealed++; } } diff --git a/zone/raids.h b/zone/raids.h index 8c31d210f..5bce90df9 100644 --- a/zone/raids.h +++ b/zone/raids.h @@ -135,7 +135,7 @@ public: bool IsGroupLeader(const char *who); bool IsRaidMember(const char *name); void UpdateLevel(const char *name, int newLevel); - std::vector GetRaidGroupMembers(uint32 gid); + uint32 GetFreeGroup(); uint8 GroupCount(uint32 gid); @@ -257,6 +257,7 @@ public: bool DoesAnyMemberHaveExpeditionLockout(const std::string& expedition_name, const std::string& event_name, int max_check_count = 0); std::vector GetMembers() const; + std::vector GetRaidGroupMembers(uint32 gid); RaidMember members[MAX_RAID_MEMBERS]; char leadername[64]; From ed552af6f1e8fa1425c53930c1bf1165077f5154 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Sat, 29 Jan 2022 21:53:06 -0400 Subject: [PATCH 41/55] seems to be working --- zone/bot.h | 7 ++++--- zone/bot_raid.cpp | 18 ++++++++++-------- zone/entity.cpp | 22 +++++++++++++++++++++- zone/entity.h | 1 + 4 files changed, 36 insertions(+), 12 deletions(-) diff --git a/zone/bot.h b/zone/bot.h index f0cc3510b..4edf3d4a1 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -387,6 +387,7 @@ public: static void ProcessRaidInvite(Bot* invitee, Client* invitor); //Mitch static void ProcessRaidInvite(Client* invitee, Client* invitor); //Mitch uint8 GetNumberNeedingHealedInRaidGroup(uint8 hpr, bool includePets); //Mitch + bool m_dirtyautohaters; inline void SetDirtyAutoHaters() { m_dirtyautohaters = true; } static std::list GetBotSpellsForSpellEffect(Bot* botCaster, int spellEffect); @@ -609,6 +610,9 @@ public: int32 GetBaseDR() { return _baseDR; } int32 GetBaseCorrup() { return _baseCorrup; } + //Raid additions + Raid* p_raid_instance; + protected: virtual void PetAIProcess(); virtual void BotMeditate(bool isSitting); @@ -737,9 +741,6 @@ private: bool SavePet(); // Save and depop bot pet if there is one bool DeletePet(); - //Raid Additions - bool m_dirtyautohaters; - public: static uint8 spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND]; }; diff --git a/zone/bot_raid.cpp b/zone/bot_raid.cpp index 78ae8c909..167652d6a 100644 --- a/zone/bot_raid.cpp +++ b/zone/bot_raid.cpp @@ -1531,7 +1531,7 @@ std::vector Raid::GetRaidGroupMembers(uint32 gid) { if (members[i].member && members[i].GroupNumber == gid) { - raid_group_members.emplace_back(members[i]); + raid_group_members.push_back(members[i]); } } return raid_group_members; @@ -1780,9 +1780,10 @@ bool Bot::AICastSpell_Raid(Mob* tar, uint8 iChance, uint32 iSpellTypes) { BotGroupSay(this, "Casting %s.", spells[botSpell.SpellId].name); //raid->RaidBotGroupSay(this, 0, 100, "Casting %s.", spells[botSpell.SpellId].name); std::vector raid_group_members = raid->GetRaidGroupMembers(r_group); - for (std::vector::iterator iter = raid_group_members.begin(); iter != raid_group_members.end(); ++iter) { - if (iter->member && !iter->member->qglobal) { - iter->member->SetDontHealMeBefore(Timer::GetCurrentTime() + 1000); + //for (std::vector::iterator iter = raid_group_members.begin(); iter != raid_group_members.end(); ++iter) { + for (int i = 0; i < raid_group_members.size(); ++i){ + if (raid_group_members.at(i).member && !raid_group_members.at(i).member->qglobal) { + raid_group_members.at(i).member->SetDontHealMeBefore(Timer::GetCurrentTime() + 1000); } } } @@ -2603,13 +2604,14 @@ uint8 Bot::GetNumberNeedingHealedInRaidGroup(uint8 hpr, bool includePets) { raid = entity_list.GetRaidByBotName(this->GetName()); uint32 r_group = raid->GetGroup(this->GetName()); std::vector raid_group_members = raid->GetRaidGroupMembers(r_group); - for (std::vector::iterator iter = raid_group_members.begin(); iter != raid_group_members.end(); ++iter) { - if (iter->member && !iter->member->qglobal) { - if (iter->member->GetHPRatio() <= hpr) + //for (std::vector::iterator iter = raid_group_members.begin(); iter != raid_group_members.end(); ++iter) { + for (int i = 0; i< raid_group_members.size(); ++i) { + if (raid_group_members.at(i).member && !raid_group_members.at(i).member->qglobal) { + if (raid_group_members.at(i).member->GetHPRatio() <= hpr) needHealed++; if (includePets) { - if (iter->member->GetPet() && iter->member->GetPet()->GetHPRatio() <= hpr) + if (raid_group_members.at(i).member->GetPet() && raid_group_members.at(i).member->GetPet()->GetHPRatio() <= hpr) needHealed++; } } diff --git a/zone/entity.cpp b/zone/entity.cpp index cc78fe6ca..328f2f2ee 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -2050,7 +2050,7 @@ Raid* EntityList::GetRaidByClient(Client* client) Raid* EntityList::GetRaidByBotName(const char* name) { - + std::list::iterator iterator; iterator = raid_list.begin(); @@ -2070,6 +2070,26 @@ Raid* EntityList::GetRaidByBotName(const char* name) return nullptr; } +Raid* EntityList::GetRaidByBot(Bot* bot) +{ + + std::list::iterator iterator; + iterator = raid_list.begin(); + + while (iterator != raid_list.end()) { + for (auto& member : (*iterator)->members) { + if (member.member && member.member->CastToBot() == bot) { + bot->p_raid_instance = *iterator; + return *iterator; + } + } + ++iterator; + } + return nullptr; +} + + + Raid *EntityList::GetRaidByMob(Mob *mob) { std::list::iterator iterator; diff --git a/zone/entity.h b/zone/entity.h index 45f588ccf..ddc796319 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -199,6 +199,7 @@ public: Raid *GetRaidByLeaderName(const char *leader); #ifdef BOTS Raid* GetRaidByBotName(const char* name); + Raid* GetRaidByBot(Bot* bot); #endif Corpse *GetCorpseByOwner(Client* client); From fbaeb00f397c763940f7aba5ebfe43efd8eb09ab Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Sun, 30 Jan 2022 22:40:11 -0400 Subject: [PATCH 42/55] Memory corruption found - sending packets to BoTs using Client class --- zone/attack.cpp | 4 ++-- zone/bot.h | 3 ++- zone/exp.cpp | 2 +- zone/mob.cpp | 3 +-- zone/raids.cpp | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/zone/attack.cpp b/zone/attack.cpp index c2286d341..b2bd97395 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -3839,7 +3839,7 @@ void Mob::CommonDamage(Mob* attacker, int& damage, const uint16 spell_id, const if (!FromDamageShield) { #ifdef BOTS // If a bot is the attacker, send a damage message ot the Bot Owner - if (spell_id != SPELL_UNKNOWN && damage > 0 && !Critical && attacker && attacker != this && attacker->IsBot() && RuleB(Bots, DisplaySpellDamage)) { + if (attacker->GetTarget() && spell_id != SPELL_UNKNOWN && damage > 0 && !Critical && attacker && attacker != this && attacker->IsBot() && RuleB(Bots, DisplaySpellDamage)) { attacker->CastToBot()->GetBotOwner()->FilteredMessageString( attacker->CastToBot()->GetBotOwner(), Chat::DotDamage, @@ -3894,7 +3894,7 @@ void Mob::CommonDamage(Mob* attacker, int& damage, const uint16 spell_id, const } #ifdef BOTS // If a bot is the attacker, send a damage message ot the Bot Owner - else if (spell_id != SPELL_UNKNOWN && attacker->IsBot() && damage > 0 && !Critical && attacker && attacker != this && RuleB(Bots, DisplaySpellDamage)) { + else if (attacker->GetTarget() && spell_id != SPELL_UNKNOWN && attacker->IsBot() && damage > 0 && !Critical && attacker && attacker != this && RuleB(Bots, DisplaySpellDamage)) { attacker->CastToBot()->GetBotOwner()->FilteredMessageString( attacker->CastToBot()->GetBotOwner(), Chat::DotDamage, diff --git a/zone/bot.h b/zone/bot.h index 4edf3d4a1..ffb50fe87 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -387,7 +387,6 @@ public: static void ProcessRaidInvite(Bot* invitee, Client* invitor); //Mitch static void ProcessRaidInvite(Client* invitee, Client* invitor); //Mitch uint8 GetNumberNeedingHealedInRaidGroup(uint8 hpr, bool includePets); //Mitch - bool m_dirtyautohaters; inline void SetDirtyAutoHaters() { m_dirtyautohaters = true; } static std::list GetBotSpellsForSpellEffect(Bot* botCaster, int spellEffect); @@ -677,6 +676,7 @@ private: Timer m_auto_defend_timer; //Timer m_combat_jitter_timer; //bool m_combat_jitter_flag; + bool m_dirtyautohaters; bool m_guard_flag; bool m_hold_flag; bool m_attack_flag; @@ -743,6 +743,7 @@ private: public: static uint8 spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND]; + }; #endif // BOTS diff --git a/zone/exp.cpp b/zone/exp.cpp index 608a7c4ad..b625935e6 100644 --- a/zone/exp.cpp +++ b/zone/exp.cpp @@ -1089,7 +1089,7 @@ void Raid::SplitExp(uint32 exp, Mob* other) { return; for (unsigned int x = 0; x < MAX_RAID_MEMBERS; x++) { - if (members[x].member != nullptr) // If Group Member is Client + if (members[x].member != nullptr && members[x].member->CastToBot()->GetBotID() == 0) // If Group Member is Client { Client *cmember = members[x].member; // add exp + exp cap diff --git a/zone/mob.cpp b/zone/mob.cpp index c51d372f2..efaf619ef 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -3033,8 +3033,7 @@ void Mob::QuestJournalledSay(Client *QuestInitiator, const char *str, Journal::O const char *Mob::GetCleanName() { if (clean_name != NULL && !strlen(clean_name)) { //extra check added for crash condition. Mitch - if (this) - CleanMobName(GetName(), clean_name); + CleanMobName(GetName(), clean_name); } return clean_name; diff --git a/zone/raids.cpp b/zone/raids.cpp index 657c8a604..23f0b2740 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -1750,7 +1750,7 @@ void Raid::SendHPManaEndPacketsFrom(Mob *mob) mob->CreateHPPacket(&hpapp); for(int x = 0; x < MAX_RAID_MEMBERS; x++) { - if(members[x].member) { + if(members[x].member && members[x].member->CastToBot()->GetBotID() == 0 ) { if(!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) { members[x].member->QueuePacket(&hpapp, false); if (members[x].member->IsClient() && members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) { //Mitch @@ -1810,7 +1810,7 @@ void Raid::SendEndurancePacketFrom(Mob *mob) EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct)); for (int x = 0; x < MAX_RAID_MEMBERS; x++) { - if (members[x].member) { + if (members[x].member && members[x].member->CastToBot()->GetBotID() == 0) { if (!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) { if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) { outapp.SetOpcode(OP_MobEnduranceUpdate); @@ -1917,7 +1917,7 @@ void Raid::CheckGroupMentor(uint32 group_id, Client *c) void Raid::SetDirtyAutoHaters() { for (int i = 0; i < MAX_RAID_MEMBERS; ++i) - if (members[i].member) + if (members[i].member && members[i].member->CastToBot()->GetBotID() == 0) members[i].member->SetDirtyAutoHaters(); } From 5566ea4d857df5929ff11a93e85d8dcf097f0ab7 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Mon, 31 Jan 2022 17:35:37 -0400 Subject: [PATCH 43/55] added Raid::IsRaidMemberBot() --- zone/raids.cpp | 20 +++++++++++++++----- zone/raids.h | 1 + 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/zone/raids.cpp b/zone/raids.cpp index 23f0b2740..116f55b65 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -1531,6 +1531,16 @@ void Raid::SendAllRaidLeadershipAA() SendGroupLeadershipAA(members[i].member, members[i].GroupNumber); } +bool Raid::IsRaidMemberBot(Client* client) +{ + if (client->CastToBot()->GetBotID() == 0) { + return false; + } + else + { + return true; + } +} void Raid::LockRaid(bool lockFlag) { std::string query = StringFormat("UPDATE raid_details SET locked = %d WHERE raidid = %lu", @@ -1708,7 +1718,7 @@ void Raid::SendHPManaEndPacketsTo(Client *client) EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct)); for(int x = 0; x < MAX_RAID_MEMBERS; x++) { - if(members[x].member) { + if(members[x].member && !IsRaidMemberBot(members[x].member)) { if((members[x].member != client) && (members[x].GroupNumber == group_id)) { members[x].member->CreateHPPacket(&hp_packet); @@ -1750,10 +1760,10 @@ void Raid::SendHPManaEndPacketsFrom(Mob *mob) mob->CreateHPPacket(&hpapp); for(int x = 0; x < MAX_RAID_MEMBERS; x++) { - if(members[x].member && members[x].member->CastToBot()->GetBotID() == 0 ) { + if(members[x].member && !IsRaidMemberBot(members[x].member)) { if(!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) { members[x].member->QueuePacket(&hpapp, false); - if (members[x].member->IsClient() && members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) { //Mitch + if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) { outapp.SetOpcode(OP_MobManaUpdate); MobManaUpdate_Struct *mana_update = (MobManaUpdate_Struct *)outapp.pBuffer; mana_update->spawn_id = mob->GetID(); @@ -1783,7 +1793,7 @@ void Raid::SendManaPacketFrom(Mob *mob) EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct)); for (int x = 0; x < MAX_RAID_MEMBERS; x++) { - if (members[x].member) { + if (members[x].member && !IsRaidMemberBot(members[x].member)) { if (!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) { if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) { outapp.SetOpcode(OP_MobManaUpdate); @@ -1810,7 +1820,7 @@ void Raid::SendEndurancePacketFrom(Mob *mob) EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct)); for (int x = 0; x < MAX_RAID_MEMBERS; x++) { - if (members[x].member && members[x].member->CastToBot()->GetBotID() == 0) { + if (members[x].member && !IsRaidMemberBot(members[x].member)) { if (!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) { if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) { outapp.SetOpcode(OP_MobEnduranceUpdate); diff --git a/zone/raids.h b/zone/raids.h index 5bce90df9..156f3f548 100644 --- a/zone/raids.h +++ b/zone/raids.h @@ -125,6 +125,7 @@ public: void AddBot(Bot* b, uint32 group = 0xFFFFFFFF, bool rleader=false, bool groupleader=false, bool looter=false); //Mitch void RaidBotGroupSay(Bot* b, uint8 language, uint8 lang_skill, const char* msg, ...); //Mitch static Mob* GetRaidMainAssistOneByName(const char* name); + bool IsRaidMemberBot(Client* client); #endif void RemoveMember(const char *c); void DisbandRaid(); From 5113415d5cfdca0cfacb7ee3443337caa3b6f96b Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Thu, 3 Feb 2022 20:20:23 -0400 Subject: [PATCH 44/55] Update p_raid_instance --- zone/bot.cpp | 19 ++++++++++--------- zone/client_packet.cpp | 1 + zone/raids.cpp | 1 + 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index e2628a34e..bfd17530d 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -3994,7 +3994,15 @@ void Bot::Depop() { entity_list.RemoveFromHateLists(this); if(HasGroup()) Bot::RemoveBotFromGroup(this, GetGroup()); - + + //Mitch + Raid* bot_raid = entity_list.GetRaidByBotName(this->GetName()); + if (bot_raid) { + uint32 gid = bot_raid->GetGroup(this->GetName()); + bot_raid->SendRaidGroupRemove(this->GetName(), bot_raid->GetGroup(this->GetName())); + bot_raid->RemoveMember(this->GetName()); + bot_raid->GroupUpdate(gid); + } if(HasPet()) GetPet()->Depop(); @@ -8426,14 +8434,7 @@ void Bot::Camp(bool databaseSave) { if(GetGroup()) RemoveBotFromGroup(this, GetGroup()); - //Mitch - Raid* bot_raid = entity_list.GetRaidByBotName(this->GetName()); - if (bot_raid) { - uint32 gid = bot_raid->GetGroup(this->GetName()); - bot_raid->SendRaidGroupRemove(this->GetName(), bot_raid->GetGroup(this->GetName())); - bot_raid->RemoveMember(this->GetName()); - bot_raid->GroupUpdate(gid); - } + // RemoveBotFromGroup() code is too complicated for this to work as-is (still needs to be addressed to prevent memory leaks) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 9ff37b676..2fb9f99b8 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -587,6 +587,7 @@ void Client::CompleteConnect() if (b) { b->SetRaidGrouped(true); + b->p_raid_instance = raid; //b->SetFollowID(this->GetID()); } } diff --git a/zone/raids.cpp b/zone/raids.cpp index 116f55b65..62c7aa91d 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -209,6 +209,7 @@ void Raid::AddBot(Bot* b, uint32 group, bool rleader, bool groupleader, bool loo SendRaidAddAll(b->GetName()); b->SetRaidGrouped(true); + b->p_raid_instance = this; //SendRaidMOTD(b->GetOwner()->CastToClient()); // Mitch What to do here? From 50230bcd0cb442602270ac0cc4c1eaa97513cf2f Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Thu, 3 Feb 2022 20:40:30 -0400 Subject: [PATCH 45/55] g3 --- zone/bot.h | 2 +- zone/bot_raid.cpp | 1 + zone/client.cpp | 4 ++-- zone/raids.cpp | 42 +++++++++++++++++++++++++++++++----------- 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/zone/bot.h b/zone/bot.h index ffb50fe87..df8361bab 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -387,7 +387,7 @@ public: static void ProcessRaidInvite(Bot* invitee, Client* invitor); //Mitch static void ProcessRaidInvite(Client* invitee, Client* invitor); //Mitch uint8 GetNumberNeedingHealedInRaidGroup(uint8 hpr, bool includePets); //Mitch - inline void SetDirtyAutoHaters() { m_dirtyautohaters = true; } + inline void SetDirtyAutoHaters() { m_dirtyautohaters = true; } //Mitch static std::list GetBotSpellsForSpellEffect(Bot* botCaster, int spellEffect); static std::list GetBotSpellsForSpellEffectAndTargetType(Bot* botCaster, int spellEffect, SpellTargetType targetType); diff --git a/zone/bot_raid.cpp b/zone/bot_raid.cpp index 167652d6a..0e0450a1e 100644 --- a/zone/bot_raid.cpp +++ b/zone/bot_raid.cpp @@ -231,6 +231,7 @@ void Bot::AI_Process_Raid() if (NOT_HOLDING && NOT_PASSIVE) { auto attack_target = bot_owner->GetTarget(); + if (attack_target) { InterruptSpell(); diff --git a/zone/client.cpp b/zone/client.cpp index 0dfd55dfd..7a34a142a 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -812,7 +812,7 @@ void Client::QueuePacket(const EQApplicationPacket* app, bool ack_req, CLIENT_CO // todo: save packets for later use AddPacket(app, ack_req); } - else if (eqs && !IsBot()) //Mitch added the BoTcheck for a fail safe on trying to send a packet to a BoT! + else if (eqs) // && !IsBot()) //Mitch added the BoTcheck for a fail safe on trying to send a packet to a BoT! { eqs->QueuePacket(app, ack_req); } @@ -826,7 +826,7 @@ void Client::FastQueuePacket(EQApplicationPacket** app, bool ack_req, CLIENT_CON return; } else { - if(eqs && !IsBot()) //Mitch added + if(eqs) // && !IsBot()) //Mitch added eqs->FastQueuePacket((EQApplicationPacket **)app, ack_req); else if (app && (*app)) delete *app; diff --git a/zone/raids.cpp b/zone/raids.cpp index 116f55b65..27b6635b5 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -1120,10 +1120,7 @@ void Raid::SendRaidAddAll(const char *who) { for (int x = 0; x < MAX_RAID_MEMBERS; x++) { - if (strcmp(members[x].membername, who) == 0 ) //Mitch add IsBot - //if (!members[x].member->IsBot() || - // strcmp(members[x].membername, who) == 0 || - // (members[x].SentToBotOwner && members[x].member->GetOwnerID() != entity_list.GetClientByName(who)->CharacterID())) //Mitch add IsBot + if (strcmp(members[x].membername, who) == 0 ) { auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidAddMember_Struct)); RaidAddMember_Struct* ram = (RaidAddMember_Struct*)outapp->pBuffer; @@ -1249,10 +1246,13 @@ void Raid::SendBulkRaid(Client *to) { if(!to) return; + + if (IsRaidMemberBot(to)) + return; for(int x = 0; x < MAX_RAID_MEMBERS; x++) { - if(strlen(members[x].membername) > 0 && (strcmp(members[x].membername, to->GetName()) != 0)) //don't send ourself + if(members[x].member && strlen(members[x].membername) > 0 && (strcmp(members[x].membername, to->GetName()) != 0)) //don't send ourself { SendRaidAdd(members[x].membername, to); } @@ -1263,7 +1263,7 @@ void Raid::QueuePacket(const EQApplicationPacket *app, bool ack_req) { for(int x = 0; x < MAX_RAID_MEMBERS; x++) { - if(members[x].member && !members[x].member->IsBot()) + if(members[x].member && !IsRaidMemberBot(members[x].member)) { members[x].member->QueuePacket(app, ack_req); } @@ -1272,6 +1272,9 @@ void Raid::QueuePacket(const EQApplicationPacket *app, bool ack_req) void Raid::SendMakeLeaderPacket(const char *who) //30 { + if (entity_list.GetBotByBotName(who) && IsRaidMemberBot(entity_list.GetBotByBotName(who)->CastToClient())) + return; + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct)); RaidLeadershipUpdate_Struct *rg = (RaidLeadershipUpdate_Struct*)outapp->pBuffer; rg->action = raidMakeLeader; @@ -1287,6 +1290,9 @@ void Raid::SendMakeLeaderPacketTo(const char *who, Client *to) if(!to) return; + if (IsRaidMemberBot(to)) + return; + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct)); RaidLeadershipUpdate_Struct *rg = (RaidLeadershipUpdate_Struct*)outapp->pBuffer; rg->action = raidMakeLeader; @@ -1317,6 +1323,9 @@ void Raid::SendGroupUpdate(Client *to) if(!to) return; + if (IsRaidMemberBot(to)) + return; + auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupUpdate2_Struct)); GroupUpdate2_Struct* gu = (GroupUpdate2_Struct*)outapp->pBuffer; gu->action = groupActUpdate; @@ -1434,7 +1443,7 @@ void Raid::SendRaidUnlockTo(Client *c) void Raid::SendGroupDisband(Client *to) { - if(!to) + if(!to || IsRaidMemberBot(to)) return; auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupUpdate_Struct)); @@ -1505,6 +1514,9 @@ void Raid::SendRaidMOTDToWorld() void Raid::SendGroupLeadershipAA(Client *c, uint32 gid) { + if (IsRaidMemberBot(c)) + return; + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct)); RaidLeadershipUpdate_Struct *rlaa = (RaidLeadershipUpdate_Struct *)outapp->pBuffer; rlaa->action = raidSetLeaderAbilities; @@ -1520,14 +1532,14 @@ void Raid::SendGroupLeadershipAA(Client *c, uint32 gid) void Raid::SendGroupLeadershipAA(uint32 gid) { for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++) - if (members[i].member && members[i].GroupNumber == gid) + if (members[i].member && members[i].GroupNumber == gid && !IsRaidMemberBot(members[i].member)) SendGroupLeadershipAA(members[i].member, gid); } void Raid::SendAllRaidLeadershipAA() { for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++) - if (members[i].member) + if (members[i].member && !IsRaidMemberBot(members[i].member)) SendGroupLeadershipAA(members[i].member, members[i].GroupNumber); } @@ -1927,9 +1939,14 @@ void Raid::CheckGroupMentor(uint32 group_id, Client *c) void Raid::SetDirtyAutoHaters() { for (int i = 0; i < MAX_RAID_MEMBERS; ++i) - if (members[i].member && members[i].member->CastToBot()->GetBotID() == 0) + if (members[i].member && IsRaidMemberBot(members[i].member)) + { + members[i].member->CastToBot()->SetDirtyAutoHaters(); + } + else if (members[i].member && members[i].member->CastToClient()->IsClient()) + { members[i].member->SetDirtyAutoHaters(); - + } } void Raid::QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_required /*= true*/, bool ignore_sender /*= true*/, float distance /*= 0*/, bool group_only /*= true*/) { @@ -1948,6 +1965,9 @@ void Raid::QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_re if (!members[i].member->IsClient()) continue; + if (IsRaidMemberBot(members[i].member)) + continue; + if (ignore_sender && members[i].member == sender) continue; From 2b625bb347c68feb6a3abd61fcace755f1310d91 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Sat, 5 Feb 2022 20:52:34 -0400 Subject: [PATCH 46/55] Final - Bot Raid Working --- zone/bot.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index bfd17530d..d508b7a42 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -3995,14 +3995,6 @@ void Bot::Depop() { if(HasGroup()) Bot::RemoveBotFromGroup(this, GetGroup()); - //Mitch - Raid* bot_raid = entity_list.GetRaidByBotName(this->GetName()); - if (bot_raid) { - uint32 gid = bot_raid->GetGroup(this->GetName()); - bot_raid->SendRaidGroupRemove(this->GetName(), bot_raid->GetGroup(this->GetName())); - bot_raid->RemoveMember(this->GetName()); - bot_raid->GroupUpdate(gid); - } if(HasPet()) GetPet()->Depop(); @@ -8434,7 +8426,14 @@ void Bot::Camp(bool databaseSave) { if(GetGroup()) RemoveBotFromGroup(this, GetGroup()); - + //Mitch + Raid* bot_raid = entity_list.GetRaidByBotName(this->GetName()); + if (bot_raid) { + uint32 gid = bot_raid->GetGroup(this->GetName()); + bot_raid->SendRaidGroupRemove(this->GetName(), bot_raid->GetGroup(this->GetName())); + bot_raid->RemoveMember(this->GetName()); + bot_raid->GroupUpdate(gid); + } // RemoveBotFromGroup() code is too complicated for this to work as-is (still needs to be addressed to prevent memory leaks) From deb4f10ea8972b7287d1121b2979dbc3b3045e44 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Mon, 7 Feb 2022 21:35:53 -0400 Subject: [PATCH 47/55] Fixed IsRaidMemberBot to remove memory leak Fixed altcombat crash though RaidMainAssist (428) needs fixing --- zone/bot_raid.cpp | 4 ++++ zone/raids.cpp | 31 +++++++++++++++++++++++++------ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/zone/bot_raid.cpp b/zone/bot_raid.cpp index 0e0450a1e..38edc4ac8 100644 --- a/zone/bot_raid.cpp +++ b/zone/bot_raid.cpp @@ -428,6 +428,10 @@ void Bot::AI_Process_Raid() auto assist_mob = raid->GetRaidMainAssistOneByName(this->GetName()); bool find_target = true; + if (!assist_mob) { + bot_owner->Message(Chat::Yellow, "Assist Mob is nullptr"); + } + if (assist_mob) { if (assist_mob->GetTarget()) { diff --git a/zone/raids.cpp b/zone/raids.cpp index fbc1f5b68..daca6d2aa 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -1546,12 +1546,30 @@ void Raid::SendAllRaidLeadershipAA() bool Raid::IsRaidMemberBot(Client* client) { - if (client->CastToBot()->GetBotID() == 0) { - return false; + std::string query = StringFormat("SELECT mob_type FROM vw_bot_character_mobs WHERE name = '%s' LIMIT 1", + client->GetCleanName()); + auto results = database.QueryDatabase(query); + + if (!results.Success()) + return true; //return true to avoid sending a packet to a non-existant client as a failsafe + + if (results.RowCount() == 0) { + LogError( + "Error getting B/C info for character name [{}] for IsRaidMemberBot. Error [{}]", + client->GetCleanName(), + results.ErrorMessage().c_str() + ); + return true;//return true to avoid sending a packet to a non-existant client as a failsafe } - else - { - return true; + + auto row = results.begin(); + const char* c = "C"; + const char* b = "B"; + if (strcmp(row[0], c) == 0) { + return false; // client is a client + } + else if (strcmp(row[0], b) == 0) { + return true; // client is actually a bot } } void Raid::LockRaid(bool lockFlag) @@ -2036,9 +2054,10 @@ Mob* Raid::GetRaidMainAssistOneByName(const char* name) Raid* raid = entity_list.GetRaidByBotName(name); std::vector raid_members = raid->GetMembers(); - for (RaidMember& iter : raid_members) + for (RaidMember iter : raid_members) { if (iter.IsRaidMainAssistOne) return iter.member->CastToMob(); } + return nullptr; } From 9b3c65a34ccff982b823eda3970cd6af1f577ee2 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Tue, 8 Feb 2022 17:34:57 -0400 Subject: [PATCH 48/55] add RaidMember.IsBot --- .../base/base_raid_members_repository.h | 11 ++++- zone/raids.cpp | 49 +++++++++++-------- zone/raids.h | 1 + 3 files changed, 39 insertions(+), 22 deletions(-) diff --git a/common/repositories/base/base_raid_members_repository.h b/common/repositories/base/base_raid_members_repository.h index b4c9ef94f..cb7fc2c65 100644 --- a/common/repositories/base/base_raid_members_repository.h +++ b/common/repositories/base/base_raid_members_repository.h @@ -27,6 +27,7 @@ public: int isgroupleader; int israidleader; int islooter; + int isbot; }; static std::string PrimaryKey() @@ -46,6 +47,7 @@ public: "isgroupleader", "israidleader", "islooter", + "isbot", }; } @@ -90,6 +92,7 @@ public: entry.isgroupleader = 0; entry.israidleader = 0; entry.islooter = 0; + entry.isbot = 0; return entry; } @@ -133,7 +136,8 @@ public: entry.name = row[5] ? row[5] : ""; entry.isgroupleader = atoi(row[6]); entry.israidleader = atoi(row[7]); - entry.islooter = atoi(row[8]); + entry.islooter = atoi(row[8]); + entry.isbot = atoi(row[9]); return entry; } @@ -176,6 +180,7 @@ public: update_values.push_back(columns[6] + " = " + std::to_string(raid_members_entry.isgroupleader)); update_values.push_back(columns[7] + " = " + std::to_string(raid_members_entry.israidleader)); update_values.push_back(columns[8] + " = " + std::to_string(raid_members_entry.islooter)); + update_values.push_back(columns[9] + " = " + std::to_string(raid_members_entry.isbot)); //Mitch auto results = db.QueryDatabase( fmt::format( @@ -206,6 +211,7 @@ public: insert_values.push_back(std::to_string(raid_members_entry.isgroupleader)); insert_values.push_back(std::to_string(raid_members_entry.israidleader)); insert_values.push_back(std::to_string(raid_members_entry.islooter)); + insert_values.push_back(std::to_string(raid_members_entry.isbot)); auto results = db.QueryDatabase( fmt::format( @@ -244,6 +250,7 @@ public: insert_values.push_back(std::to_string(raid_members_entry.isgroupleader)); insert_values.push_back(std::to_string(raid_members_entry.israidleader)); insert_values.push_back(std::to_string(raid_members_entry.islooter)); + insert_values.push_back(std::to_string(raid_members_entry.isbot)); insert_chunks.push_back("(" + implode(",", insert_values) + ")"); } @@ -286,6 +293,7 @@ public: entry.isgroupleader = atoi(row[6]); entry.israidleader = atoi(row[7]); entry.islooter = atoi(row[8]); + entry.isbot = atoi(row[9]); all_entries.push_back(entry); } @@ -319,6 +327,7 @@ public: entry.isgroupleader = atoi(row[6]); entry.israidleader = atoi(row[7]); entry.islooter = atoi(row[8]); + entry.isbot = atoi(row[9]); all_entries.push_back(entry); } diff --git a/zone/raids.cpp b/zone/raids.cpp index daca6d2aa..e2c2a97c3 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -98,7 +98,7 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo std::string query = StringFormat("INSERT INTO raid_members SET raidid = %lu, charid = %lu, " "groupid = %lu, _class = %d, level = %d, name = '%s', " - "isgroupleader = %d, israidleader = %d, islooter = %d", + "isgroupleader = %d, israidleader = %d, islooter = %d, isbot = 0", (unsigned long)GetID(), (unsigned long)c->CharacterID(), (unsigned long)group, c->GetClass(), c->GetLevel(), c->GetName(), groupleader, rleader, looter); @@ -178,7 +178,7 @@ void Raid::AddBot(Bot* b, uint32 group, bool rleader, bool groupleader, bool loo std::string query = StringFormat("INSERT INTO raid_members SET raidid = %lu, charid = %lu, " "groupid = %lu, _class = %d, level = %d, name = '%s', " - "isgroupleader = %d, israidleader = %d, islooter = %d", + "isgroupleader = %d, israidleader = %d, islooter = %d, isbot = 1", (unsigned long)GetID(), (unsigned long)b->GetBotID(), (unsigned long)group, b->GetClass(), b->GetLevel(), b->GetName(), groupleader, rleader, looter); @@ -1248,12 +1248,12 @@ void Raid::SendBulkRaid(Client *to) if(!to) return; - if (IsRaidMemberBot(to)) - return; + //if (IsRaidMemberBot(to)) + // return; for(int x = 0; x < MAX_RAID_MEMBERS; x++) { - if(members[x].member && strlen(members[x].membername) > 0 && (strcmp(members[x].membername, to->GetName()) != 0)) //don't send ourself + if(members[x].member && !members[x].IsBot && strlen(members[x].membername) > 0 && (strcmp(members[x].membername, to->GetName()) != 0)) //don't send ourself { SendRaidAdd(members[x].membername, to); } @@ -1264,7 +1264,7 @@ void Raid::QueuePacket(const EQApplicationPacket *app, bool ack_req) { for(int x = 0; x < MAX_RAID_MEMBERS; x++) { - if(members[x].member && !IsRaidMemberBot(members[x].member)) + if(members[x].member && !members[x].IsBot) { members[x].member->QueuePacket(app, ack_req); } @@ -1273,7 +1273,9 @@ void Raid::QueuePacket(const EQApplicationPacket *app, bool ack_req) void Raid::SendMakeLeaderPacket(const char *who) //30 { - if (entity_list.GetBotByBotName(who) && IsRaidMemberBot(entity_list.GetBotByBotName(who)->CastToClient())) + + //if (entity_list.GetBotByBotName(who) && IsRaidMemberBot(entity_list.GetBotByBotName(who)->CastToClient())) + if (entity_list.GetBotByBotName(who) && members[GetPlayerIndex(who)].IsBot) return; auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct)); @@ -1291,7 +1293,7 @@ void Raid::SendMakeLeaderPacketTo(const char *who, Client *to) if(!to) return; - if (IsRaidMemberBot(to)) + if (members[GetPlayerIndex(who)].IsBot) return; auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct)); @@ -1324,7 +1326,7 @@ void Raid::SendGroupUpdate(Client *to) if(!to) return; - if (IsRaidMemberBot(to)) + if (members[GetPlayerIndex(to)].IsBot) return; auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupUpdate2_Struct)); @@ -1444,7 +1446,7 @@ void Raid::SendRaidUnlockTo(Client *c) void Raid::SendGroupDisband(Client *to) { - if(!to || IsRaidMemberBot(to)) + if(!to || members[GetPlayerIndex(to)].IsBot) return; auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupUpdate_Struct)); @@ -1515,7 +1517,7 @@ void Raid::SendRaidMOTDToWorld() void Raid::SendGroupLeadershipAA(Client *c, uint32 gid) { - if (IsRaidMemberBot(c)) + if (members[GetPlayerIndex(c)].IsBot) return; auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct)); @@ -1533,14 +1535,14 @@ void Raid::SendGroupLeadershipAA(Client *c, uint32 gid) void Raid::SendGroupLeadershipAA(uint32 gid) { for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++) - if (members[i].member && members[i].GroupNumber == gid && !IsRaidMemberBot(members[i].member)) + if (members[i].member && members[i].GroupNumber == gid && !members[i].IsBot) SendGroupLeadershipAA(members[i].member, gid); } void Raid::SendAllRaidLeadershipAA() { for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++) - if (members[i].member && !IsRaidMemberBot(members[i].member)) + if (members[i].member && !members[i].IsBot) SendGroupLeadershipAA(members[i].member, members[i].GroupNumber); } @@ -1572,6 +1574,7 @@ bool Raid::IsRaidMemberBot(Client* client) return true; // client is actually a bot } } + void Raid::LockRaid(bool lockFlag) { std::string query = StringFormat("UPDATE raid_details SET locked = %d WHERE raidid = %lu", @@ -1638,7 +1641,7 @@ bool Raid::LearnMembers() memset(members, 0, (sizeof(RaidMember)*MAX_RAID_MEMBERS)); std::string query = StringFormat("SELECT name, groupid, _class, level, " - "isgroupleader, israidleader, islooter " + "isgroupleader, israidleader, islooter, isbot " "FROM raid_members WHERE raidid = %lu", (unsigned long)GetID()); auto results = database.QueryDatabase(query); @@ -1669,6 +1672,7 @@ bool Raid::LearnMembers() members[index].IsGroupLeader = atoi(row[4]); members[index].IsRaidLeader = atoi(row[5]); members[index].IsLooter = atoi(row[6]); + members[index].IsBot = atoi(row[7]); //Mitch ++index; } @@ -1689,14 +1693,17 @@ void Raid::VerifyRaid() #endif if(c){ members[x].member = c; + members[x].IsBot = false; } #ifdef BOTS else if(b){ members[x].member = b->CastToClient(); //Raid requires client* we are forcing it here to be a BOT + members[x].IsBot = true; //Used to identify those members who are Bots } #endif else { members[x].member = nullptr; + members[x].IsBot = false; } } if(members[x].IsRaidLeader){ @@ -1749,7 +1756,7 @@ void Raid::SendHPManaEndPacketsTo(Client *client) EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct)); for(int x = 0; x < MAX_RAID_MEMBERS; x++) { - if(members[x].member && !IsRaidMemberBot(members[x].member)) { + if(members[x].member && !members[x].IsBot) { if((members[x].member != client) && (members[x].GroupNumber == group_id)) { members[x].member->CreateHPPacket(&hp_packet); @@ -1791,7 +1798,7 @@ void Raid::SendHPManaEndPacketsFrom(Mob *mob) mob->CreateHPPacket(&hpapp); for(int x = 0; x < MAX_RAID_MEMBERS; x++) { - if(members[x].member && !IsRaidMemberBot(members[x].member)) { + if(members[x].member && !members[x].IsBot) { if(!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) { members[x].member->QueuePacket(&hpapp, false); if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) { @@ -1824,7 +1831,7 @@ void Raid::SendManaPacketFrom(Mob *mob) EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct)); for (int x = 0; x < MAX_RAID_MEMBERS; x++) { - if (members[x].member && !IsRaidMemberBot(members[x].member)) { + if (members[x].member && !members[x].IsBot) { if (!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) { if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) { outapp.SetOpcode(OP_MobManaUpdate); @@ -1851,7 +1858,7 @@ void Raid::SendEndurancePacketFrom(Mob *mob) EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct)); for (int x = 0; x < MAX_RAID_MEMBERS; x++) { - if (members[x].member && !IsRaidMemberBot(members[x].member)) { + if (members[x].member && !members[x].IsBot) { if (!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) { if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) { outapp.SetOpcode(OP_MobEnduranceUpdate); @@ -1958,11 +1965,11 @@ void Raid::CheckGroupMentor(uint32 group_id, Client *c) void Raid::SetDirtyAutoHaters() { for (int i = 0; i < MAX_RAID_MEMBERS; ++i) - if (members[i].member && IsRaidMemberBot(members[i].member)) + if (members[i].member && members[i].IsBot) { members[i].member->CastToBot()->SetDirtyAutoHaters(); } - else if (members[i].member && members[i].member->CastToClient()->IsClient()) + else if (members[i].member && !members[i].IsBot) { members[i].member->SetDirtyAutoHaters(); } @@ -1984,7 +1991,7 @@ void Raid::QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_re if (!members[i].member->IsClient()) continue; - if (IsRaidMemberBot(members[i].member)) + if (members[i].IsBot) continue; if (ignore_sender && members[i].member == sender) diff --git a/zone/raids.h b/zone/raids.h index 156f3f548..2daff6d4e 100644 --- a/zone/raids.h +++ b/zone/raids.h @@ -89,6 +89,7 @@ struct RaidMember{ bool IsRaidLeader; bool IsLooter; #ifdef BOTS + bool IsBot = false; bool IsGroupHealer; bool IsRaidSlower; bool IsRaidMainAssistOne; From 2985d4c4883b500d11e96a7ef3412a093cb2110f Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Tue, 8 Feb 2022 20:36:26 -0400 Subject: [PATCH 49/55] Repaired IsBot function to be more preformant. Now works on standard performance machine --- zone/raids.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/zone/raids.cpp b/zone/raids.cpp index e2c2a97c3..b96eedf43 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -1247,13 +1247,13 @@ void Raid::SendBulkRaid(Client *to) { if(!to) return; - - //if (IsRaidMemberBot(to)) - // return; + + if (members[GetPlayerIndex(to)].IsBot) + return; for(int x = 0; x < MAX_RAID_MEMBERS; x++) { - if(members[x].member && !members[x].IsBot && strlen(members[x].membername) > 0 && (strcmp(members[x].membername, to->GetName()) != 0)) //don't send ourself + if(members[x].member && strlen(members[x].membername) > 0 && (strcmp(members[x].membername, to->GetName()) != 0)) //don't send ourself { SendRaidAdd(members[x].membername, to); } @@ -1446,7 +1446,7 @@ void Raid::SendRaidUnlockTo(Client *c) void Raid::SendGroupDisband(Client *to) { - if(!to || members[GetPlayerIndex(to)].IsBot) + if(!to) return; auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupUpdate_Struct)); From 14f536505ecfd18818eeeb373d4db518d23b571b Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Sat, 12 Feb 2022 21:42:28 -0400 Subject: [PATCH 50/55] Fixed Bard AE Target Spells Removed assert for buffs --- zone/spells.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/zone/spells.cpp b/zone/spells.cpp index a03f05408..0c2a762a6 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -2418,15 +2418,15 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, ui case AECaster: case AETarget: { -#ifdef BOTS - if(IsBot()) { - bool StopLogic = false; - if(!this->CastToBot()->DoFinishedSpellAETarget(spell_id, spell_target, slot, StopLogic)) - return false; - if(StopLogic) - break; - } -#endif //BOTS +//#ifdef BOTS +// if(IsBot()) { +// bool StopLogic = false; +// if(!this->CastToBot()->DoFinishedSpellAETarget(spell_id, spell_target, slot, StopLogic)) +// return false; +// if(StopLogic) +// break; +// } +//#endif //BOTS // we can't cast an AE spell without something to center it on assert(ae_center != nullptr); @@ -3332,7 +3332,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid } // now add buff at emptyslot - assert(buffs[emptyslot].spellid == SPELL_UNKNOWN); // sanity check + //assert(buffs[emptyslot].spellid == SPELL_UNKNOWN); // sanity check buffs[emptyslot].spellid = spell_id; buffs[emptyslot].casterlevel = caster_level; From 16ba0fb67418f28e71451eccbaafadd1f2f49897 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Sun, 13 Feb 2022 11:21:31 -0400 Subject: [PATCH 51/55] updated based on Feb 2022 master updates --- zone/bot_raid.cpp | 50 +++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/zone/bot_raid.cpp b/zone/bot_raid.cpp index 38edc4ac8..d7853299a 100644 --- a/zone/bot_raid.cpp +++ b/zone/bot_raid.cpp @@ -968,8 +968,8 @@ void Bot::AI_Process_Raid() TriggerDefensiveProcs(tar, EQ::invslot::slotPrimary, false); TEST_COMBATANTS(); - TryWeaponProc(p_item, tar, EQ::invslot::slotPrimary); - + //TryWeaponProc(p_item, tar, EQ::invslot::slotPrimary); + TryCombatProcs(p_item, tar, EQ::invslot::slotPrimary); // bool tripleSuccess = false; TEST_COMBATANTS(); @@ -1008,7 +1008,10 @@ void Bot::AI_Process_Raid() } TEST_COMBATANTS(); - int32 ExtraAttackChanceBonus = (spellbonuses.ExtraAttackChance + itembonuses.ExtraAttackChance + aabonuses.ExtraAttackChance); + //int32 ExtraAttackChanceBonus = (spellbonuses.ExtraAttackChance + itembonuses.ExtraAttackChance + aabonuses.ExtraAttackChance); + auto ExtraAttackChanceBonus = + (spellbonuses.ExtraAttackChance[0] + itembonuses.ExtraAttackChance[0] + + aabonuses.ExtraAttackChance[0]); if (ExtraAttackChanceBonus) { if (p_item && p_item->GetItem()->IsType2HWeapon()) { @@ -1055,7 +1058,8 @@ void Bot::AI_Process_Raid() Attack(tar, EQ::invslot::slotSecondary); // Single attack with offhand TEST_COMBATANTS(); - TryWeaponProc(s_item, tar, EQ::invslot::slotSecondary); + TryCombatProcs(s_item, tar, EQ::invslot::slotSecondary); + //TryWeaponProc(s_item, tar, EQ::invslot::slotSecondary); TEST_COMBATANTS(); if (CanThisClassDoubleAttack() && CheckBotDoubleAttack()) { @@ -1754,7 +1758,7 @@ bool Bot::AICastSpell_Raid(Mob* tar, uint8 iChance, uint32 iSpellTypes) { break; // Can we cast this spell on this target? - if (!(spells[botSpell.SpellId].targettype == ST_GroupTeleport || spells[botSpell.SpellId].targettype == ST_Target || tar == this) + if (!(spells[botSpell.SpellId].target_type == ST_GroupTeleport || spells[botSpell.SpellId].target_type == ST_Target || tar == this) && !(tar->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0)) break; @@ -1851,14 +1855,14 @@ bool Bot::AICastSpell_Raid(Mob* tar, uint8 iChance, uint32 iSpellTypes) { continue; // can not cast buffs for your own pet only on another pet that isn't yours - if ((spells[selectedBotSpell.SpellId].targettype == ST_Pet) && (tar != this->GetPet())) + if ((spells[selectedBotSpell.SpellId].target_type == ST_Pet) && (tar != this->GetPet())) continue; // Validate target - if (!((spells[selectedBotSpell.SpellId].targettype == ST_Target || spells[selectedBotSpell.SpellId].targettype == ST_Pet || tar == this || - spells[selectedBotSpell.SpellId].targettype == ST_Group || spells[selectedBotSpell.SpellId].targettype == ST_GroupTeleport || - (botClass == BARD && spells[selectedBotSpell.SpellId].targettype == ST_AEBard)) + if (!((spells[selectedBotSpell.SpellId].target_type == ST_Target || spells[selectedBotSpell.SpellId].target_type == ST_Pet || tar == this || + spells[selectedBotSpell.SpellId].target_type == ST_Group || spells[selectedBotSpell.SpellId].target_type == ST_GroupTeleport || + (botClass == BARD && spells[selectedBotSpell.SpellId].target_type == ST_AEBard)) && !tar->IsImmuneToSpell(selectedBotSpell.SpellId, this) && (tar->CanBuffStack(selectedBotSpell.SpellId, botLevel, true) >= 0))) { continue; @@ -2126,7 +2130,7 @@ bool Bot::AICastSpell_Raid(Mob* tar, uint8 iChance, uint32 iSpellTypes) { if (CheckSpellRecastTimers(this, itr->SpellIndex)) { - if (!(!tar->IsImmuneToSpell(selectedBotSpell.SpellId, this) && (spells[selectedBotSpell.SpellId].buffduration < 1 || tar->CanBuffStack(selectedBotSpell.SpellId, botLevel, true) >= 0))) + if (!(!tar->IsImmuneToSpell(selectedBotSpell.SpellId, this) && (spells[selectedBotSpell.SpellId].buff_duration < 1 || tar->CanBuffStack(selectedBotSpell.SpellId, botLevel, true) >= 0))) continue; //short duration buffs or other buffs only to be cast during combat. @@ -2164,14 +2168,14 @@ bool Bot::AICastSpell_Raid(Mob* tar, uint8 iChance, uint32 iSpellTypes) { continue; // can not cast buffs for your own pet only on another pet that isn't yours - if ((spells[selectedBotSpell.SpellId].targettype == ST_Pet) && (tar != this->GetPet())) + if ((spells[selectedBotSpell.SpellId].target_type == ST_Pet) && (tar != this->GetPet())) continue; // Validate target - if (!((spells[selectedBotSpell.SpellId].targettype == ST_Target || spells[selectedBotSpell.SpellId].targettype == ST_Pet || tar == this || - spells[selectedBotSpell.SpellId].targettype == ST_Group || spells[selectedBotSpell.SpellId].targettype == ST_GroupTeleport || - (botClass == BARD && spells[selectedBotSpell.SpellId].targettype == ST_AEBard)) + if (!((spells[selectedBotSpell.SpellId].target_type == ST_Target || spells[selectedBotSpell.SpellId].target_type == ST_Pet || tar == this || + spells[selectedBotSpell.SpellId].target_type == ST_Group || spells[selectedBotSpell.SpellId].target_type == ST_GroupTeleport || + (botClass == BARD && spells[selectedBotSpell.SpellId].target_type == ST_AEBard)) && !tar->IsImmuneToSpell(selectedBotSpell.SpellId, this) && (tar->CanBuffStack(selectedBotSpell.SpellId, botLevel, true) >= 0))) { continue; @@ -2366,9 +2370,9 @@ bool Bot::AICastSpell_Raid(Mob* tar, uint8 iChance, uint32 iSpellTypes) { continue; if (!CheckSpellRecastTimers(this, iter.SpellIndex)) continue; - if (spells[iter.SpellId].zonetype != -1 && zone->GetZoneType() != -1 && spells[iter.SpellId].zonetype != zone->GetZoneType()) // is this bit or index? + if (spells[iter.SpellId].zone_type != -1 && zone->GetZoneType() != -1 && spells[iter.SpellId].zone_type != zone->GetZoneType()) // is this bit or index? continue; - if (spells[iter.SpellId].targettype != ST_Target) + if (spells[iter.SpellId].target_type != ST_Target) continue; if (tar->CanBuffStack(iter.SpellId, botLevel, true) < 0) continue; @@ -2388,7 +2392,7 @@ bool Bot::AICastSpell_Raid(Mob* tar, uint8 iChance, uint32 iSpellTypes) { case BEASTLORD: { botSpell = GetBestBotSpellForDiseaseBasedSlow(this); - if (botSpell.SpellId == 0 || ((tar->GetMR() - 50) < (tar->GetDR() + spells[botSpell.SpellId].ResistDiff))) + if (botSpell.SpellId == 0 || ((tar->GetMR() - 50) < (tar->GetDR() + spells[botSpell.SpellId].resist_difficulty))) botSpell = GetBestBotSpellForMagicBasedSlow(this); break; } @@ -2479,9 +2483,9 @@ bool Bot::AICastSpell_Raid(Mob* tar, uint8 iChance, uint32 iSpellTypes) { continue; if (!CheckSpellRecastTimers(this, iter.SpellIndex)) continue; - if (spells[iter.SpellId].zonetype != -1 && zone->GetZoneType() != -1 && spells[iter.SpellId].zonetype != zone->GetZoneType()) // is this bit or index? + if (spells[iter.SpellId].zone_type != -1 && zone->GetZoneType() != -1 && spells[iter.SpellId].zone_type != zone->GetZoneType()) // is this bit or index? continue; - if (spells[iter.SpellId].targettype != ST_Target) + if (spells[iter.SpellId].target_type != ST_Target) continue; if (tar->CanBuffStack(iter.SpellId, botLevel, true) < 0) continue; @@ -2506,9 +2510,9 @@ bool Bot::AICastSpell_Raid(Mob* tar, uint8 iChance, uint32 iSpellTypes) { continue; if (!CheckSpellRecastTimers(this, iter.SpellIndex)) continue; - if (spells[iter.SpellId].zonetype != -1 && zone->GetZoneType() != -1 && spells[iter.SpellId].zonetype != zone->GetZoneType()) // is this bit or index? + if (spells[iter.SpellId].zone_type != -1 && zone->GetZoneType() != -1 && spells[iter.SpellId].zone_type != zone->GetZoneType()) // is this bit or index? continue; - switch (spells[iter.SpellId].targettype) { + switch (spells[iter.SpellId].target_type) { case ST_AEBard: case ST_AECaster: case ST_GroupTeleport: @@ -2538,9 +2542,9 @@ bool Bot::AICastSpell_Raid(Mob* tar, uint8 iChance, uint32 iSpellTypes) { continue; if (!CheckSpellRecastTimers(this, iter.SpellIndex)) continue; - if (spells[iter.SpellId].zonetype != -1 && zone->GetZoneType() != -1 && spells[iter.SpellId].zonetype != zone->GetZoneType()) // is this bit or index? + if (spells[iter.SpellId].zone_type != -1 && zone->GetZoneType() != -1 && spells[iter.SpellId].zone_type != zone->GetZoneType()) // is this bit or index? continue; - switch (spells[iter.SpellId].targettype) { + switch (spells[iter.SpellId].target_type) { case ST_AEBard: case ST_AECaster: case ST_GroupTeleport: From ff3cd08189192a92ecf46d052bb55d3369ff6ead Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Sun, 13 Feb 2022 11:56:13 -0400 Subject: [PATCH 52/55] Added bot_db_updates and version increment --- utils/sql/git/bots/bots_db_update_manifest.txt | 1 + utils/sql/git/bots/required/2022_02_08_bots_raid_members.sql | 1 + 2 files changed, 2 insertions(+) create mode 100644 utils/sql/git/bots/required/2022_02_08_bots_raid_members.sql diff --git a/utils/sql/git/bots/bots_db_update_manifest.txt b/utils/sql/git/bots/bots_db_update_manifest.txt index 221020683..114ee942a 100644 --- a/utils/sql/git/bots/bots_db_update_manifest.txt +++ b/utils/sql/git/bots/bots_db_update_manifest.txt @@ -27,6 +27,7 @@ 9026|2019_09_09_bots_owner_options_rework.sql|SHOW COLUMNS FROM `bot_owner_options` LIKE 'option_type'|empty| 9027|2020_03_30_bots_view_update.sql|SELECT * FROM db_version WHERE bots_version >= 9027|empty| 9028|2021_06_04_bot_create_combinations.sql|SHOW TABLES LIKE 'bot_create_combinations'|empty| +9029|2022_02_08_bots_raid_members.sql|SELECT * FROM db_version WHERE bots_version >= 9028|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/bots/required/2022_02_08_bots_raid_members.sql b/utils/sql/git/bots/required/2022_02_08_bots_raid_members.sql new file mode 100644 index 000000000..1f80a1a29 --- /dev/null +++ b/utils/sql/git/bots/required/2022_02_08_bots_raid_members.sql @@ -0,0 +1 @@ +ALTER TABLE `raid_members` ADD COLUMN `isbot` TINYINT(1) NOT NULL DEFAULT 0 COMMENT ''; \ No newline at end of file From d67fa473a2cfc4f765c0564fa2adc7a42921fe7c Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Wed, 23 Feb 2022 15:58:13 -0400 Subject: [PATCH 53/55] Cleanup of bot raid work and inclusion of bot_raid in cmake --- .../base/base_raid_members_repository.h | 24 ++- zone/CMakeLists.txt | 1 + zone/bot.cpp | 13 +- zone/bot.h | 8 +- zone/client.cpp | 4 +- zone/client_packet.cpp | 14 +- zone/entity.cpp | 6 +- zone/exp.cpp | 6 +- zone/groups.cpp | 5 +- zone/mob.cpp | 2 +- zone/raids.cpp | 163 +++++++++--------- zone/raids.h | 15 +- 12 files changed, 135 insertions(+), 126 deletions(-) diff --git a/common/repositories/base/base_raid_members_repository.h b/common/repositories/base/base_raid_members_repository.h index 88169a5ab..f37a44186 100644 --- a/common/repositories/base/base_raid_members_repository.h +++ b/common/repositories/base/base_raid_members_repository.h @@ -27,7 +27,9 @@ public: int isgroupleader; int israidleader; int islooter; +#ifdef BOTS int isbot; +#endif }; static std::string PrimaryKey() @@ -47,7 +49,9 @@ public: "isgroupleader", "israidleader", "islooter", +#ifdef BOTS "isbot", +#endif }; } @@ -92,7 +96,9 @@ public: entry.isgroupleader = 0; entry.israidleader = 0; entry.islooter = 0; +#ifdef BOTS entry.isbot = 0; +#endif return entry; } @@ -137,7 +143,9 @@ public: entry.isgroupleader = atoi(row[6]); entry.israidleader = atoi(row[7]); entry.islooter = atoi(row[8]); +#ifdef BOTS entry.isbot = atoi(row[9]); +#endif return entry; } @@ -180,7 +188,9 @@ public: update_values.push_back(columns[6] + " = " + std::to_string(raid_members_entry.isgroupleader)); update_values.push_back(columns[7] + " = " + std::to_string(raid_members_entry.israidleader)); update_values.push_back(columns[8] + " = " + std::to_string(raid_members_entry.islooter)); - update_values.push_back(columns[9] + " = " + std::to_string(raid_members_entry.isbot)); //Mitch +#ifdef BOTS + update_values.push_back(columns[9] + " = " + std::to_string(raid_members_entry.isbot)); +#endif auto results = db.QueryDatabase( fmt::format( @@ -211,8 +221,9 @@ public: insert_values.push_back(std::to_string(raid_members_entry.isgroupleader)); insert_values.push_back(std::to_string(raid_members_entry.israidleader)); insert_values.push_back(std::to_string(raid_members_entry.islooter)); +#ifdef BOTS insert_values.push_back(std::to_string(raid_members_entry.isbot)); - +#endif auto results = db.QueryDatabase( fmt::format( "{} VALUES ({})", @@ -250,8 +261,9 @@ public: insert_values.push_back(std::to_string(raid_members_entry.isgroupleader)); insert_values.push_back(std::to_string(raid_members_entry.israidleader)); insert_values.push_back(std::to_string(raid_members_entry.islooter)); +#ifdef BOTS insert_values.push_back(std::to_string(raid_members_entry.isbot)); - +#endif insert_chunks.push_back("(" + implode(",", insert_values) + ")"); } @@ -293,8 +305,9 @@ public: entry.isgroupleader = atoi(row[6]); entry.israidleader = atoi(row[7]); entry.islooter = atoi(row[8]); +#ifdef BOTS entry.isbot = atoi(row[9]); - +#endif all_entries.push_back(entry); } @@ -327,8 +340,9 @@ public: entry.isgroupleader = atoi(row[6]); entry.israidleader = atoi(row[7]); entry.islooter = atoi(row[8]); +#ifdef BOTS entry.isbot = atoi(row[9]); - +#endif all_entries.push_back(entry); } diff --git a/zone/CMakeLists.txt b/zone/CMakeLists.txt index 3c24da07a..6afb4bb85 100644 --- a/zone/CMakeLists.txt +++ b/zone/CMakeLists.txt @@ -11,6 +11,7 @@ SET(zone_sources beacon.cpp bonuses.cpp bot.cpp + bot_raid.cpp bot_command.cpp bot_database.cpp botspellsai.cpp diff --git a/zone/bot.cpp b/zone/bot.cpp index a7c9bd6f5..a4333eb66 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -8370,9 +8370,8 @@ Bot* Bot::GetBotByBotClientOwnerAndBotName(Client* c, std::string botName) { void Bot::ProcessBotGroupInvite(Client* c, std::string botName) { if(c) { -// Bot* invitedBot = GetBotByBotClientOwnerAndBotName(entity_list.GetBotByBotName(botName)->GetOwner()->CastToClient(), botName); Bot* invitedBot = GetBotByBotClientOwnerAndBotName(c, botName); - //Mitch changed entity from c + if(invitedBot && !invitedBot->HasGroup()) { if(!c->IsGrouped()) { Group *g = new Group(c); @@ -10402,8 +10401,7 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { raid->SendRaidCreate(c); raid->AddMember(c, 0, true, true, true); raid->SendMakeLeaderPacketTo(raid->leadername, c); - //raid->SetGroupLeader(c->GetName()); //Mitch Jan 18 - //raid->GroupUpdate(0, true); + if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -10479,13 +10477,8 @@ void Bot::ProcessRaidInvite(Bot* invitee, Client* invitor) { else { //Third, no group so add the single client - //raid->SendRaidCreate(invitee); - //raid->SendMakeLeaderPacketTo(raid->leadername, invitee); raid->AddBot(invitee); - // raid->SendBulkRaid(invitee); - //if (raid->IsLocked()) { - // raid->SendRaidLockTo(invitee); - //} + } } else diff --git a/zone/bot.h b/zone/bot.h index 6cd8eb519..7a0c34b32 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -382,10 +382,10 @@ public: void PetAIProcess_Raid(); void AI_Process_Raid(); bool AICastSpell_Raid(Mob* tar, uint8 iChance, uint32 iSpellTypes); - static void ProcessRaidInvite(Bot* invitee, Client* invitor); //Mitch - static void ProcessRaidInvite(Client* invitee, Client* invitor); //Mitch - uint8 GetNumberNeedingHealedInRaidGroup(uint8 hpr, bool includePets); //Mitch - inline void SetDirtyAutoHaters() { m_dirtyautohaters = true; } //Mitch + static void ProcessRaidInvite(Bot* invitee, Client* invitor); + static void ProcessRaidInvite(Client* invitee, Client* invitor); + uint8 GetNumberNeedingHealedInRaidGroup(uint8 hpr, bool includePets); + inline void SetDirtyAutoHaters() { m_dirtyautohaters = true; } static std::list GetBotSpellsForSpellEffect(Bot* botCaster, int spellEffect); static std::list GetBotSpellsForSpellEffectAndTargetType(Bot* botCaster, int spellEffect, SpellTargetType targetType); diff --git a/zone/client.cpp b/zone/client.cpp index f2a831a45..5dfdd8318 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -804,7 +804,7 @@ void Client::QueuePacket(const EQApplicationPacket* app, bool ack_req, CLIENT_CO // todo: save packets for later use AddPacket(app, ack_req); } - else if (eqs) // && !IsBot()) //Mitch added the BoTcheck for a fail safe on trying to send a packet to a BoT! + else if (eqs) { eqs->QueuePacket(app, ack_req); } @@ -818,7 +818,7 @@ void Client::FastQueuePacket(EQApplicationPacket** app, bool ack_req, CLIENT_CON return; } else { - if(eqs) // && !IsBot()) //Mitch added + if(eqs) eqs->FastQueuePacket((EQApplicationPacket **)app, ack_req); else if (app && (*app)) delete *app; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index d07920f4d..c7fdd3a4c 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -11455,7 +11455,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) case RaidCommandInviteIntoExisting: case RaidCommandInvite: { -#ifdef BOTS //Mitch +#ifdef BOTS Bot* player_to_invite = nullptr; Client* player_to_invite_owner = nullptr; @@ -11532,7 +11532,9 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) break; } +#ifdef BOTS } +#endif case RaidCommandAcceptInvite: { Client* player_accepting_invite = entity_list.GetClientByName(raid_command_packet->player_name); @@ -11581,7 +11583,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) Bot::ProcessRaidInvite(invitee, invitor); //two clients with one or both having groups with bots break; } - else if (invitee->IsBot()) + else if (invitee && invitee->IsBot()) { Bot::ProcessRaidInvite(b, player_accepting_invite); //client inviting a bot break; @@ -11859,13 +11861,15 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) Raid* raid = entity_list.GetRaidByClient(this); Client* c_to_disband = entity_list.GetClientByName(raid_command_packet->leader_name); Client* c_doing_disband = entity_list.GetClientByName(raid_command_packet->player_name); +#ifdef BOTS Bot* b_to_disband = entity_list.GetBotByBotName(raid_command_packet->leader_name); - +#endif + if (raid) { uint32 group = raid->GetGroup(raid_command_packet->leader_name); #ifdef BOTS - //Mitch added to remove all bots if the Bot_Owner is removed from the Raid + //Added to remove all bots if the Bot_Owner is removed from the Raid //Does not camp the Bots, just removes from the raid std::vector raid_members_bots; if (c_to_disband) @@ -11917,8 +11921,6 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app) if (raid->IsGroupLeader(b_to_disband->GetName())) { // Remove the entire BOT group in this case - //uint32 gid = raid->GetGroup(b_to_disband->GetName()); - //std::vector r_group_members = raid->GetRaidGroupMembers(gid); Group* group_inst = new Group(b_to_disband); entity_list.AddGroup(group_inst); database.SetGroupID(b_to_disband->GetCleanName(), group_inst->GetID(), b_to_disband->GetBotID()); diff --git a/zone/entity.cpp b/zone/entity.cpp index e1270a49c..c9e6a4023 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -2112,7 +2112,7 @@ Raid* EntityList::GetRaidByClient(Client* client) return nullptr; } - +#ifdef BOTS Raid* EntityList::GetRaidByBotName(const char* name) { @@ -2134,7 +2134,9 @@ Raid* EntityList::GetRaidByBotName(const char* name) return nullptr; } +#endif +#ifdef BOTS Raid* EntityList::GetRaidByBot(Bot* bot) { @@ -2152,7 +2154,7 @@ Raid* EntityList::GetRaidByBot(Bot* bot) } return nullptr; } - +#endif Raid *EntityList::GetRaidByMob(Mob *mob) diff --git a/zone/exp.cpp b/zone/exp.cpp index 045a9bba6..e46dcce48 100644 --- a/zone/exp.cpp +++ b/zone/exp.cpp @@ -1097,7 +1097,11 @@ void Raid::SplitExp(uint32 exp, Mob* other) { return; for (unsigned int x = 0; x < MAX_RAID_MEMBERS; x++) { - if (members[x].member != nullptr && members[x].member->CastToBot()->GetBotID() == 0) // If Group Member is Client +#ifdef BOTS + if (members[x].member != nullptr && !members[x].IsBot) // If Group Member is Client +#else + if (members[x].member != nullptr) // If Group Member is Client +#endif { Client *cmember = members[x].member; // add exp + exp cap diff --git a/zone/groups.cpp b/zone/groups.cpp index f2867f9d1..425eeb419 100644 --- a/zone/groups.cpp +++ b/zone/groups.cpp @@ -1248,10 +1248,7 @@ void Group::VerifyGroup() { members[i] = nullptr; continue; } - //if (them == nullptr && members[i] == nullptr) { //fixes a group bug with bots Mitch added Jan 1 2022 - // membername[i][0] = '\0'; - // continue; - //} + if(them != nullptr && members[i] != them) { //our pointer is out of date... not so good. #if EQDEBUG >= 5 diff --git a/zone/mob.cpp b/zone/mob.cpp index 306421057..aca66b7e3 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -3855,7 +3855,7 @@ void Mob::QuestJournalledSay(Client *QuestInitiator, const char *str, Journal::O const char *Mob::GetCleanName() { - if (clean_name != NULL && !strlen(clean_name)) { //extra check added for crash condition. Mitch + if (!strlen(clean_name)) { CleanMobName(GetName(), clean_name); } diff --git a/zone/raids.cpp b/zone/raids.cpp index 56d5b31c8..cbe90cf0a 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -24,7 +24,7 @@ #include "groups.h" #include "mob.h" #include "raids.h" -#include "bot.h" //Mitch +#include "bot.h" #include "worldserver.h" @@ -96,13 +96,22 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo if(!c) return; +#ifdef BOTS std::string query = StringFormat("INSERT INTO raid_members SET raidid = %lu, charid = %lu, " "groupid = %lu, _class = %d, level = %d, name = '%s', " "isgroupleader = %d, israidleader = %d, islooter = %d, isbot = 0", (unsigned long)GetID(), (unsigned long)c->CharacterID(), (unsigned long)group, c->GetClass(), c->GetLevel(), c->GetName(), groupleader, rleader, looter); - auto results = database.QueryDatabase(query); +#else + std::string query = StringFormat("INSERT INTO raid_members SET raidid = %lu, charid = %lu, " + "groupid = %lu, _class = %d, level = %d, name = '%s', " + "isgroupleader = %d, israidleader = %d, islooter = %d", + (unsigned long)GetID(), (unsigned long)c->CharacterID(), + (unsigned long)group, c->GetClass(), c->GetLevel(), + c->GetName(), groupleader, rleader, looter); +#endif + auto results = database.QueryDatabase(query); if(!results.Success()) { LogError("Error inserting into raid members: [{}]", results.ErrorMessage().c_str()); @@ -171,7 +180,8 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo worldserver.SendPacket(pack); safe_delete(pack); } -//Mitch + +#ifdef BOTS void Raid::AddBot(Bot* b, uint32 group, bool rleader, bool groupleader, bool looter) { if (!b) return; @@ -190,17 +200,6 @@ void Raid::AddBot(Bot* b, uint32 group, bool rleader, bool groupleader, bool loo LearnMembers(); VerifyRaid(); -// Bots are being invited and cannot be the raid leader -// if (rleader) { -// database.SetRaidGroupLeaderInfo(RAID_GROUPLESS, GetID()); -// UpdateRaidAAs(); -// } - -// Bots can be group leaders, though they do not have GroupAA -// if (group != RAID_GROUPLESS && groupleader) { -// database.SetRaidGroupLeaderInfo(group, GetID()); -// UpdateGroupAAs(group); //Mitch Jan 22 -// } if (group < 12) //Jan22 GroupUpdate(group); //Jan22 @@ -210,36 +209,7 @@ void Raid::AddBot(Bot* b, uint32 group, bool rleader, bool groupleader, bool loo b->SetRaidGrouped(true); b->p_raid_instance = this; - //SendRaidMOTD(b->GetOwner()->CastToClient()); - // Mitch What to do here? - // xtarget shit .......... - //if (group == RAID_GROUPLESS) { - // if (rleader) { - // GetXTargetAutoMgr()->merge(*c->GetXTargetAutoMgr()); - // c->GetXTargetAutoMgr()->clear(); - // c->SetXTargetAutoMgr(GetXTargetAutoMgr()); - // } - // else { - // if (!c->GetXTargetAutoMgr()->empty()) { - // GetXTargetAutoMgr()->merge(*c->GetXTargetAutoMgr()); - // c->GetXTargetAutoMgr()->clear(); - // c->RemoveAutoXTargets(); - // } - - // c->SetXTargetAutoMgr(GetXTargetAutoMgr()); - - // if (!c->GetXTargetAutoMgr()->empty()) - // c->SetDirtyAutoHaters(); - // } - //} - -// Raid* raid_update = nullptr; -// raid_update = b->GetOwner()->GetRaid(); -// if (raid_update) { -// raid_update->SendHPManaEndPacketsTo(b->GetOwner()->CastToClient()); -// raid_update->SendHPManaEndPacketsFrom(b->GetOwner()->CastToClient()); -// } auto pack = new ServerPacket(ServerOP_RaidAdd, sizeof(ServerRaidGeneralAction_Struct)); ServerRaidGeneralAction_Struct* rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer; @@ -250,6 +220,7 @@ void Raid::AddBot(Bot* b, uint32 group, bool rleader, bool groupleader, bool loo worldserver.SendPacket(pack); safe_delete(pack); } +#endif void Raid::RemoveMember(const char *characterName) @@ -1063,7 +1034,7 @@ void Raid::SendRaidAdd(const char *who, Client *to) for(int x = 0; x < MAX_RAID_MEMBERS; x++) { - if(strcmp(members[x].membername, who) == 0)// || !members[x].SentToBotOwner) //Mitch + if(strcmp(members[x].membername, who) == 0) { auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidAddMember_Struct)); RaidAddMember_Struct *ram = (RaidAddMember_Struct*)outapp->pBuffer; @@ -1212,8 +1183,10 @@ void Raid::SendBulkRaid(Client *to) if(!to) return; +#ifdef BOTS if (members[GetPlayerIndex(to)].IsBot) return; +#endif for(int x = 0; x < MAX_RAID_MEMBERS; x++) { @@ -1228,7 +1201,11 @@ void Raid::QueuePacket(const EQApplicationPacket *app, bool ack_req) { for(int x = 0; x < MAX_RAID_MEMBERS; x++) { +#ifdef BOTS if(members[x].member && !members[x].IsBot) +#else + if(members[x].member) +#endif { members[x].member->QueuePacket(app, ack_req); } @@ -1238,9 +1215,10 @@ void Raid::QueuePacket(const EQApplicationPacket *app, bool ack_req) void Raid::SendMakeLeaderPacket(const char *who) //30 { - //if (entity_list.GetBotByBotName(who) && IsRaidMemberBot(entity_list.GetBotByBotName(who)->CastToClient())) +#ifdef BOTS if (entity_list.GetBotByBotName(who) && members[GetPlayerIndex(who)].IsBot) return; +#endif auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct)); RaidLeadershipUpdate_Struct *rg = (RaidLeadershipUpdate_Struct*)outapp->pBuffer; @@ -1257,8 +1235,10 @@ void Raid::SendMakeLeaderPacketTo(const char *who, Client *to) if(!to) return; +#ifdef BOTS if (members[GetPlayerIndex(who)].IsBot) return; +#endif auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct)); RaidLeadershipUpdate_Struct *rg = (RaidLeadershipUpdate_Struct*)outapp->pBuffer; @@ -1290,8 +1270,10 @@ void Raid::SendGroupUpdate(Client *to) if(!to) return; +#ifdef BOTS if (members[GetPlayerIndex(to)].IsBot) return; +#endif auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupUpdate2_Struct)); GroupUpdate2_Struct* gu = (GroupUpdate2_Struct*)outapp->pBuffer; @@ -1481,8 +1463,10 @@ void Raid::SendRaidMOTDToWorld() void Raid::SendGroupLeadershipAA(Client *c, uint32 gid) { +#ifdef BOTS if (members[GetPlayerIndex(c)].IsBot) return; +#endif auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct)); RaidLeadershipUpdate_Struct *rlaa = (RaidLeadershipUpdate_Struct *)outapp->pBuffer; @@ -1499,45 +1483,25 @@ void Raid::SendGroupLeadershipAA(Client *c, uint32 gid) void Raid::SendGroupLeadershipAA(uint32 gid) { for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++) +#ifdef BOTS if (members[i].member && members[i].GroupNumber == gid && !members[i].IsBot) +#else + if (members[i].member && members[i].GroupNumber == gid) +#endif SendGroupLeadershipAA(members[i].member, gid); } void Raid::SendAllRaidLeadershipAA() { for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++) +#ifdef BOTS if (members[i].member && !members[i].IsBot) - SendGroupLeadershipAA(members[i].member, members[i].GroupNumber); +#else + if (members[i].member) +#endif + SendGroupLeadershipAA(members[i].member, members[i].GroupNumber); } -bool Raid::IsRaidMemberBot(Client* client) -{ - std::string query = StringFormat("SELECT mob_type FROM vw_bot_character_mobs WHERE name = '%s' LIMIT 1", - client->GetCleanName()); - auto results = database.QueryDatabase(query); - - if (!results.Success()) - return true; //return true to avoid sending a packet to a non-existant client as a failsafe - - if (results.RowCount() == 0) { - LogError( - "Error getting B/C info for character name [{}] for IsRaidMemberBot. Error [{}]", - client->GetCleanName(), - results.ErrorMessage().c_str() - ); - return true;//return true to avoid sending a packet to a non-existant client as a failsafe - } - - auto row = results.begin(); - const char* c = "C"; - const char* b = "B"; - if (strcmp(row[0], c) == 0) { - return false; // client is a client - } - else if (strcmp(row[0], b) == 0) { - return true; // client is actually a bot - } -} void Raid::LockRaid(bool lockFlag) { @@ -1604,11 +1568,18 @@ bool Raid::LearnMembers() { memset(members, 0, (sizeof(RaidMember)*MAX_RAID_MEMBERS)); +#ifdef BOTS std::string query = StringFormat("SELECT name, groupid, _class, level, " "isgroupleader, israidleader, islooter, isbot " "FROM raid_members WHERE raidid = %lu", (unsigned long)GetID()); - auto results = database.QueryDatabase(query); +#else + std::string query = StringFormat("SELECT name, groupid, _class, level, " + "isgroupleader, israidleader, islooter " + "FROM raid_members WHERE raidid = %lu", + (unsigned long)GetID()); +#endif + auto results = database.QueryDatabase(query); if (!results.Success()) return false; @@ -1636,8 +1607,10 @@ bool Raid::LearnMembers() members[index].IsGroupLeader = atoi(row[4]); members[index].IsRaidLeader = atoi(row[5]); members[index].IsLooter = atoi(row[6]); - members[index].IsBot = atoi(row[7]); //Mitch - ++index; +#ifdef BOTS + members[index].IsBot = atoi(row[7]); +#endif + ++index; } return true; @@ -1653,21 +1626,28 @@ void Raid::VerifyRaid() else{ Client *c = entity_list.GetClientByName(members[x].membername); #ifdef BOTS - Bot* b = entity_list.GetBotByBotName(members[x].membername); //Mitch + Bot* b = entity_list.GetBotByBotName(members[x].membername); #endif if(c){ members[x].member = c; +#ifdef BOTS members[x].IsBot = false; +#endif } #ifdef BOTS else if(b){ - members[x].member = b->CastToClient(); //Raid requires client* we are forcing it here to be a BOT + //Raid requires client* we are forcing it here to be a BOT. Care is needed here as any client function that + //does not exist within the Bot Class will likely corrupt memory for the member object. Good practice to test the IsBot + //attribute before calling a client function or casting to client. + members[x].member = b->CastToClient(); members[x].IsBot = true; //Used to identify those members who are Bots } #endif else { members[x].member = nullptr; +#ifdef BOTS members[x].IsBot = false; +#endif } } if(members[x].IsRaidLeader){ @@ -1720,7 +1700,11 @@ void Raid::SendHPManaEndPacketsTo(Client *client) EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct)); for(int x = 0; x < MAX_RAID_MEMBERS; x++) { +#ifdef BOTS if(members[x].member && !members[x].IsBot) { +#else + if (members[x].member) { +#endif if((members[x].member != client) && (members[x].GroupNumber == group_id)) { members[x].member->CreateHPPacket(&hp_packet); @@ -1762,7 +1746,11 @@ void Raid::SendHPManaEndPacketsFrom(Mob *mob) mob->CreateHPPacket(&hpapp); for(int x = 0; x < MAX_RAID_MEMBERS; x++) { +#ifdef BOTS if(members[x].member && !members[x].IsBot) { +#else + if (members[x].member) { +#endif if(!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) { members[x].member->QueuePacket(&hpapp, false); if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) { @@ -1795,7 +1783,11 @@ void Raid::SendManaPacketFrom(Mob *mob) EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct)); for (int x = 0; x < MAX_RAID_MEMBERS; x++) { +#ifdef BOTS if (members[x].member && !members[x].IsBot) { +#else + if (members[x].member) { +#endif if (!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) { if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) { outapp.SetOpcode(OP_MobManaUpdate); @@ -1822,7 +1814,11 @@ void Raid::SendEndurancePacketFrom(Mob *mob) EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct)); for (int x = 0; x < MAX_RAID_MEMBERS; x++) { +#ifdef BTOS if (members[x].member && !members[x].IsBot) { +#else + if (members[x].member) { +#endif if (!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) { if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) { outapp.SetOpcode(OP_MobEnduranceUpdate); @@ -1929,11 +1925,15 @@ void Raid::CheckGroupMentor(uint32 group_id, Client *c) void Raid::SetDirtyAutoHaters() { for (int i = 0; i < MAX_RAID_MEMBERS; ++i) +#ifdef BOTS if (members[i].member && members[i].IsBot) { members[i].member->CastToBot()->SetDirtyAutoHaters(); } else if (members[i].member && !members[i].IsBot) +#else + if (members[i].member) +#endif { members[i].member->SetDirtyAutoHaters(); } @@ -1955,9 +1955,10 @@ void Raid::QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_re if (!members[i].member->IsClient()) continue; +#ifdef BOTS if (members[i].IsBot) continue; - +#endif if (ignore_sender && members[i].member == sender) continue; @@ -2020,6 +2021,7 @@ bool Raid::DoesAnyMemberHaveExpeditionLockout( return Expedition::HasLockoutByCharacterName(raid_member.membername, expedition_name, event_name); }); } +#ifdef BOTS Mob* Raid::GetRaidMainAssistOneByName(const char* name) { Raid* raid = entity_list.GetRaidByBotName(name); @@ -2032,3 +2034,4 @@ Mob* Raid::GetRaidMainAssistOneByName(const char* name) } return nullptr; } +#endif diff --git a/zone/raids.h b/zone/raids.h index cfaea07e7..141fd17ca 100644 --- a/zone/raids.h +++ b/zone/raids.h @@ -90,13 +90,7 @@ struct RaidMember{ bool IsLooter; #ifdef BOTS bool IsBot = false; - bool IsGroupHealer; - bool IsRaidSlower; - bool IsRaidMainAssistOne; - bool IsRaidMainAssistTwo; - bool IsRaidMainTank; - bool IsRaidOffTankOne; - bool IsRaidOffTankTwo; + bool IsRaidMainAssistOne = false; #endif }; @@ -123,10 +117,9 @@ public: void AddMember(Client *c, uint32 group = 0xFFFFFFFF, bool rleader=false, bool groupleader=false, bool looter=false); #ifdef BOTS - void AddBot(Bot* b, uint32 group = 0xFFFFFFFF, bool rleader=false, bool groupleader=false, bool looter=false); //Mitch - void RaidBotGroupSay(Bot* b, uint8 language, uint8 lang_skill, const char* msg, ...); //Mitch - static Mob* GetRaidMainAssistOneByName(const char* name); - bool IsRaidMemberBot(Client* client); + void AddBot(Bot* b, uint32 group = 0xFFFFFFFF, bool rleader=false, bool groupleader=false, bool looter=false); + void RaidBotGroupSay(Bot* b, uint8 language, uint8 lang_skill, const char* msg, ...); //Not yet implemented + Mob* GetRaidMainAssistOneByName(const char* name); #endif void RemoveMember(const char *c); void DisbandRaid(); From 9836c80a9d307b8ede3888cb26f0a32b4bf0db0d Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Sun, 27 Feb 2022 15:25:15 -0400 Subject: [PATCH 54/55] Fix repop crash --- zone/gm_commands/repop.cpp | 5 +++-- zone/main.cpp | 2 +- zone/spawn2.cpp | 2 +- zone/zone.cpp | 1 + 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/zone/gm_commands/repop.cpp b/zone/gm_commands/repop.cpp index 114ef6fa5..b4ff199f3 100755 --- a/zone/gm_commands/repop.cpp +++ b/zone/gm_commands/repop.cpp @@ -24,9 +24,10 @@ void command_repop(Client *c, const Seperator *sep) if (!sep->IsNumber(timearg)) { c->Message(Chat::White, "Zone depopped - repopping now."); - + + zone->spawn2_timer.Disable(); zone->Repop(); - + zone->spawn2_timer.Enable(); /* Force a spawn2 timer trigger so we don't delay actually spawning the NPC's */ zone->spawn2_timer.Trigger(); return; diff --git a/zone/main.cpp b/zone/main.cpp index fa6d47259..3dcba3b86 100644 --- a/zone/main.cpp +++ b/zone/main.cpp @@ -579,7 +579,7 @@ int main(int argc, char** argv) { EQ::Timer process_timer(loop_fn); process_timer.Start(32, true); - + EQ::EventLoop::Get().Run(); entity_list.Clear(); diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index f15ff12c3..e39463be4 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -154,7 +154,7 @@ bool Spawn2::Process() { return true; } - if (timer.Check()) { + if (timer.Check() && zone->spawn2_timer.Enabled()) { timer.Disable(); LogSpawns("Spawn2 [{}]: Timer has triggered", spawn2_id); diff --git a/zone/zone.cpp b/zone/zone.cpp index 2dffad339..13c02ac45 100755 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -1738,6 +1738,7 @@ bool Zone::Depop(bool StartSpawnTimer) { itr = npctable.begin(); delete itr->second; itr->second = nullptr; + npctable.erase(itr); } From b52c03c7968ff6dd1edca66794a0cba0739e16f3 Mon Sep 17 00:00:00 2001 From: neckkola <65987027+neckkola@users.noreply.github.com> Date: Wed, 11 May 2022 18:59:16 -0300 Subject: [PATCH 55/55] Bot databse change to not use view --- zone/bot_database.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/zone/bot_database.cpp b/zone/bot_database.cpp index 5427b3397..6be285a5a 100644 --- a/zone/bot_database.cpp +++ b/zone/bot_database.cpp @@ -2634,18 +2634,17 @@ bool BotDatabase::LoadGroupedBotsByGroupID(const uint32 owner_id, const uint32 g return false; //modified query for usecase of a BOTID sharing a CHARACTERID. //in this usecase, when the BOTID=CHARACTERID of BOT OWNER, this BOTID would be added to the GROUP - query = StringFormat( + /*query = StringFormat( "SELECT `mob_id` FROM `vw_groups` " "WHERE `group_id` = '%u' " "AND `mob_type`='B' " "AND `mob_id` IN (SELECT `bot_id` FROM `bot_data` WHERE `owner_id` = '%u');" - , group_id, owner_id); - /*query = StringFormat( + , group_id, owner_id);*/ + query = StringFormat( "SELECT `charid` FROM `group_id` WHERE `groupid` = '%u'" - " AND `charid` IN (SELECT `bot_id` FROM `bot_data` WHERE `owner_id` = '%u')" - " AND `group_id.name` NOT IN (SELECT `name` FROM `character_data`)", + " AND `name` IN (SELECT `name` FROM `bot_data` WHERE `owner_id` = '%u')", group_id, - owner_id);*/ + owner_id); auto results = database.QueryDatabase(query); if (!results.Success())