Merge pull request #4 from neckkola/Bot_Raid_work

Bot raid work
This commit is contained in:
neckkola
2022-02-13 08:02:01 -04:00
committed by GitHub
24 changed files with 4700 additions and 583 deletions
+1 -1
View File
@@ -54,5 +54,5 @@ bin/
/Win32 /Win32
/x64 /x64
/client_files/**/CMakeFiles/ /client_files/**/CMakeFiles/
submodules/libuv
.idea .idea
+15
View File
@@ -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": ""
}
]
}
@@ -27,6 +27,7 @@ public:
int isgroupleader; int isgroupleader;
int israidleader; int israidleader;
int islooter; int islooter;
int isbot;
}; };
static std::string PrimaryKey() static std::string PrimaryKey()
@@ -46,6 +47,7 @@ public:
"isgroupleader", "isgroupleader",
"israidleader", "israidleader",
"islooter", "islooter",
"isbot",
}; };
} }
@@ -90,6 +92,7 @@ public:
entry.isgroupleader = 0; entry.isgroupleader = 0;
entry.israidleader = 0; entry.israidleader = 0;
entry.islooter = 0; entry.islooter = 0;
entry.isbot = 0;
return entry; return entry;
} }
@@ -134,6 +137,7 @@ public:
entry.isgroupleader = atoi(row[6]); entry.isgroupleader = atoi(row[6]);
entry.israidleader = atoi(row[7]); entry.israidleader = atoi(row[7]);
entry.islooter = atoi(row[8]); entry.islooter = atoi(row[8]);
entry.isbot = atoi(row[9]);
return entry; 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[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[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[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( auto results = db.QueryDatabase(
fmt::format( 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.isgroupleader));
insert_values.push_back(std::to_string(raid_members_entry.israidleader)); 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.islooter));
insert_values.push_back(std::to_string(raid_members_entry.isbot));
auto results = db.QueryDatabase( auto results = db.QueryDatabase(
fmt::format( 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.isgroupleader));
insert_values.push_back(std::to_string(raid_members_entry.israidleader)); 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.islooter));
insert_values.push_back(std::to_string(raid_members_entry.isbot));
insert_chunks.push_back("(" + implode(",", insert_values) + ")"); insert_chunks.push_back("(" + implode(",", insert_values) + ")");
} }
@@ -286,6 +293,7 @@ public:
entry.isgroupleader = atoi(row[6]); entry.isgroupleader = atoi(row[6]);
entry.israidleader = atoi(row[7]); entry.israidleader = atoi(row[7]);
entry.islooter = atoi(row[8]); entry.islooter = atoi(row[8]);
entry.isbot = atoi(row[9]);
all_entries.push_back(entry); all_entries.push_back(entry);
} }
@@ -319,6 +327,7 @@ public:
entry.isgroupleader = atoi(row[6]); entry.isgroupleader = atoi(row[6]);
entry.israidleader = atoi(row[7]); entry.israidleader = atoi(row[7]);
entry.islooter = atoi(row[8]); entry.islooter = atoi(row[8]);
entry.isbot = atoi(row[9]);
all_entries.push_back(entry); all_entries.push_back(entry);
} }
+3
View File
@@ -617,10 +617,13 @@ 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, 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, 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, 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 bot owner client")
RULE_BOOL(Bots, DisplaySpellDamage, false, "Enables the display of bot spell damage to the bot owner client")
RULE_BOOL(Bots, OldRaceRezEffects, false, "Older clients had ID 757 for races with high starting STR, but it doesn't seem used anymore") RULE_BOOL(Bots, OldRaceRezEffects, false, "Older clients had ID 757 for races with high starting STR, but it doesn't seem used anymore")
RULE_BOOL(Bots, ResurrectionSickness, true, "Use Resurrection Sickness based on Resurrection spell cast, set to false to disable Resurrection Sickness.") RULE_BOOL(Bots, ResurrectionSickness, true, "Use Resurrection Sickness based on Resurrection spell cast, set to false to disable Resurrection Sickness.")
RULE_INT(Bots, OldResurrectionSicknessSpell, 757, "757 is Default Old Resurrection Sickness Spell") RULE_INT(Bots, OldResurrectionSicknessSpell, 757, "757 is Default Old Resurrection Sickness Spell")
RULE_INT(Bots, ResurrectionSicknessSpell, 756, "756 is Default Resurrection Sickness Spell") RULE_INT(Bots, ResurrectionSicknessSpell, 756, "756 is Default Resurrection Sickness Spell")
RULE_CATEGORY_END() RULE_CATEGORY_END()
#endif #endif
+3
View File
@@ -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(d) if(d) { delete d; d=nullptr; }
#define safe_delete_array(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 L32(i) ((uint32) i)
#define H32(i) ((uint32) (i >> 32)) #define H32(i) ((uint32) (i >> 32))
#define L16(i) ((uint16) i) #define L16(i) ((uint16) i)
+110 -9
View File
@@ -49,6 +49,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
extern QueryServ* QServ; extern QueryServ* QServ;
extern WorldServer worldserver; extern WorldServer worldserver;
extern FastMath g_Math; extern FastMath g_Math;
extern bool Critical;
#ifdef _WINDOWS #ifdef _WINDOWS
#define snprintf _snprintf #define snprintf _snprintf
@@ -3931,6 +3932,33 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
owner->CastToClient()->QueuePacket(outapp, true, CLIENT_CONNECTED, filter); 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; skip = owner;
} }
else { else {
@@ -3969,8 +3997,10 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
filter = FilterNone; //cant filter invulnerable filter = FilterNone; //cant filter invulnerable
else else
filter = FilterMyMisses; 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); attacker->CastToClient()->QueuePacket(outapp, true, CLIENT_CONNECTED, filter);
//}
} }
} }
skip = attacker; skip = attacker;
@@ -3992,7 +4022,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 // If this is Damage Shield damage, the correct OP_Damage packets will be sent from Mob::DamageShield, so
// we don't send them here. // we don't send them here.
if (!FromDamageShield) { if (!FromDamageShield) {
#ifdef BOTS
// If a bot is the attacker, send a damage message ot the Bot Owner
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,
FilterDOT,
OTHER_HIT_DOT,
attacker->GetTarget()->GetCleanName(),
itoa(damage),
attacker->GetCleanName(),
spells[spell_id].name);
}
#endif
entity_list.QueueCloseClients( entity_list.QueueCloseClients(
this, /* Sender */ this, /* Sender */
outapp, /* packet */ outapp, /* packet */
@@ -4004,7 +4047,7 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
); );
//send the damage to ourself if we are a client //send the damage to ourself if we are a client
if (IsClient()) { 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 //I dont think any filters apply to damage affecting us
CastToClient()->QueuePacket(outapp); CastToClient()->QueuePacket(outapp);
} }
@@ -4034,9 +4077,23 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
spells[spell_id].name /* Message4 */ spells[spell_id].name /* Message4 */
); );
} }
} //end packet sending #ifdef BOTS
// If a bot is the attacker, send a damage message ot the Bot Owner
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,
FilterDOT,
OTHER_HIT_DOT,
attacker->GetTarget()->GetCleanName(),
itoa(damage),
attacker->GetCleanName(),
spells[spell_id].name);
} }
#endif
}
} //end packet sending
void Mob::HealDamage(uint32 amount, Mob* caster, uint16 spell_id) void Mob::HealDamage(uint32 amount, Mob* caster, uint16 spell_id)
{ {
@@ -4053,15 +4110,16 @@ void Mob::HealDamage(uint32 amount, Mob *caster, uint16 spell_id)
if (caster) { if (caster) {
if (IsBuffSpell(spell_id)) { // hots if (IsBuffSpell(spell_id)) { // hots
// message to caster // message to caster
if (caster->IsClient() && caster == this) { if ((caster->IsClient() && caster == this)) {
if (caster->CastToClient()->ClientVersionBit() & EQ::versions::maskSoFAndLater) if (caster->CastToClient()->ClientVersionBit() & EQ::versions::maskSoFAndLater) {
FilteredMessageString(caster, Chat::NonMelee, FilterHealOverTime, FilteredMessageString(caster, Chat::NonMelee, FilterHealOverTime,
HOT_HEAL_SELF, itoa(acthealed), spells[spell_id].name); HOT_HEAL_SELF, itoa(acthealed), spells[spell_id].name);
}
else else
FilteredMessageString(caster, Chat::NonMelee, FilterHealOverTime, FilteredMessageString(caster, Chat::NonMelee, FilterHealOverTime,
YOU_HEALED, GetCleanName(), itoa(acthealed)); YOU_HEALED, GetCleanName(), itoa(acthealed));
} }
else if (caster->IsClient() && caster != this) { else if ((caster->IsClient() && caster != this)) {
if (caster->CastToClient()->ClientVersionBit() & EQ::versions::maskSoFAndLater) if (caster->CastToClient()->ClientVersionBit() & EQ::versions::maskSoFAndLater)
caster->FilteredMessageString(caster, Chat::NonMelee, FilterHealOverTime, caster->FilteredMessageString(caster, Chat::NonMelee, FilterHealOverTime,
HOT_HEAL_OTHER, GetCleanName(), itoa(acthealed), HOT_HEAL_OTHER, GetCleanName(), itoa(acthealed),
@@ -4070,8 +4128,35 @@ void Mob::HealDamage(uint32 amount, Mob *caster, uint16 spell_id)
caster->FilteredMessageString(caster, Chat::NonMelee, FilterHealOverTime, caster->FilteredMessageString(caster, Chat::NonMelee, FilterHealOverTime,
YOU_HEAL, GetCleanName(), itoa(acthealed)); 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 // message to target
if (IsClient() && caster != this) { if ((IsClient() && caster != this)) {
if (CastToClient()->ClientVersionBit() & EQ::versions::maskSoFAndLater) if (CastToClient()->ClientVersionBit() & EQ::versions::maskSoFAndLater)
FilteredMessageString(this, Chat::NonMelee, FilterHealOverTime, FilteredMessageString(this, Chat::NonMelee, FilterHealOverTime,
HOT_HEALED_OTHER, caster->GetCleanName(), HOT_HEALED_OTHER, caster->GetCleanName(),
@@ -4084,10 +4169,26 @@ void Mob::HealDamage(uint32 amount, Mob *caster, uint16 spell_id)
else { // normal heals else { // normal heals
FilteredMessageString(caster, Chat::NonMelee, FilterSpellDamage, FilteredMessageString(caster, Chat::NonMelee, FilterSpellDamage,
YOU_HEALED, caster->GetCleanName(), itoa(acthealed)); YOU_HEALED, caster->GetCleanName(), itoa(acthealed));
#ifndef BOTS
if (caster != this) if (caster != this)
caster->FilteredMessageString(caster, Chat::NonMelee, FilterSpellDamage, caster->FilteredMessageString(caster, Chat::NonMelee, FilterSpellDamage,
YOU_HEAL, GetCleanName(), itoa(acthealed)); YOU_HEAL, GetCleanName(), itoa(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));
}
}
#endif // BOTS
} }
else { else {
Message(Chat::NonMelee, "You have been healed for %d points of damage.", acthealed); Message(Chat::NonMelee, "You have been healed for %d points of damage.", acthealed);
+766 -14
View File
@@ -20,6 +20,7 @@
#include "bot.h" #include "bot.h"
#include "object.h" #include "object.h"
#include "raids.h"
#include "doors.h" #include "doors.h"
#include "quest_parser_collection.h" #include "quest_parser_collection.h"
#include "lua_parser.h" #include "lua_parser.h"
@@ -27,6 +28,7 @@
#include "../common/say_link.h" #include "../common/say_link.h"
extern volatile bool is_zone_loaded; extern volatile bool is_zone_loaded;
extern bool Critical;
// This constructor is used during the bot create command // 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) { Bot::Bot(NPCType *npcTypeData, Client* botOwner) : NPC(npcTypeData, nullptr, glm::vec4(), Ground, false), rest_timer(1), ping_timer(1) {
@@ -2123,6 +2125,10 @@ bool Bot::Process()
} }
// Bot AI // Bot AI
Raid* bot_raid = entity_list.GetRaidByBotName(this->GetName());
if (bot_raid)
AI_Process_Raid();
else
AI_Process(); AI_Process();
return true; return true;
@@ -2366,7 +2372,7 @@ void Bot::AI_Process()
//#pragma region PRIMARY AI SKIP CHECKS //#pragma region PRIMARY AI SKIP CHECKS
// Primary reasons for not processing AI // Primary reasons for not processing AI
if (!bot_owner || !bot_group || !IsAIControlled()) { if (!bot_owner || (!bot_group) || !IsAIControlled()) {
return; return;
} }
@@ -2379,7 +2385,12 @@ void Bot::AI_Process()
} }
// We also need a leash owner and follow mob (subset of primary AI criteria) // 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);
}
if (!leash_owner) { if (!leash_owner) {
return; return;
} }
@@ -3865,7 +3876,13 @@ bool Bot::Spawn(Client* botCharacterOwner) {
this->SendWearChange(materialFromSlot); this->SendWearChange(materialFromSlot);
} }
} }
Raid* raid = entity_list.GetRaidByBotName(this->GetName());
if (raid)
{
raid->VerifyRaid();
this->SetRaidGrouped(true);
}
return true; return true;
} }
@@ -4727,7 +4744,24 @@ bool Bot::Death(Mob *killerMob, int32 damage, uint16 spell_id, EQ::skills::Skill
my_owner->CastToClient()->SetBotPulling(false); my_owner->CastToClient()->SetBotPulling(false);
} }
Raid* raid = entity_list.GetRaidByBotName(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()); entity_list.RemoveBot(this->GetID());
// }
return true; return true;
} }
@@ -6692,7 +6726,7 @@ int32 Bot::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
if (spells[spell_id].target_type == ST_Self) if (spells[spell_id].target_type == ST_Self)
return value; return value;
bool Critical = false; Critical = false;
int32 value_BaseEffect = 0; int32 value_BaseEffect = 0;
value_BaseEffect = (value + (value*GetBotFocusEffect(focusFcBaseEffects, spell_id) / 100)); 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. // 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.
@@ -6737,8 +6771,9 @@ int32 Bot::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5)
value += (GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value) * ratio / 100); value += (GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value) * ratio / 100);
//Mitch
entity_list.MessageClose(this, false, 100, Chat::SpellCrit, "%s delivers a critical blast! (%d)", GetName(), -value); //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; return value;
} }
@@ -6769,7 +6804,7 @@ int32 Bot::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
int32 value_BaseEffect = 0; int32 value_BaseEffect = 0;
int32 chance = 0; int32 chance = 0;
int8 modifier = 1; int8 modifier = 1;
bool Critical = false; Critical = false; //mitch
value_BaseEffect = (value + (value*GetBotFocusEffect(focusFcBaseEffects, spell_id) / 100)); value_BaseEffect = (value + (value*GetBotFocusEffect(focusFcBaseEffects, spell_id) / 100));
value = value_BaseEffect; value = value_BaseEffect;
value += int(value_BaseEffect*GetBotFocusEffect(focusImprovedHeal, spell_id) / 100); value += int(value_BaseEffect*GetBotFocusEffect(focusImprovedHeal, spell_id) / 100);
@@ -7411,11 +7446,27 @@ 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 Bot::DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, EQ::spells::CastingSlot slot, bool& stopLogic) {
bool isMainGroupMGB = false; bool isMainGroupMGB = false;
Raid* raid = entity_list.GetRaidByBotName(this->GetName());
if(isMainGroupMGB && (GetClass() != BARD)) { if(isMainGroupMGB && (GetClass() != BARD)) {
BotGroupSay(this, "MGB %s", spells[spell_id].name); BotGroupSay(this, "MGB %s", spells[spell_id].name);
SpellOnTarget(spell_id, this); SpellOnTarget(spell_id, this);
entity_list.AESpell(this, this, spell_id, true); entity_list.AESpell(this, this, spell_id, true);
} else { }
else if (raid)
{
//for (auto& iter : raid->GetRaidGroupMembers(raid->GetGroup(this->GetName()))) {
std::vector<RaidMember> raid_group_members = raid->GetRaidGroupMembers(raid->GetGroup(this->GetName()));
for (std::vector<RaidMember>::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());
}
}
}
else
{
Group *g = GetGroup(); Group *g = GetGroup();
if(g) { if(g) {
for(int i = 0; i < MAX_GROUP_MEMBERS; ++i) { for(int i = 0; i < MAX_GROUP_MEMBERS; ++i) {
@@ -8085,6 +8136,16 @@ void Bot::Camp(bool databaseSave) {
if(GetGroup()) if(GetGroup())
RemoveBotFromGroup(this, 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) // RemoveBotFromGroup() code is too complicated for this to work as-is (still needs to be addressed to prevent memory leaks)
//if (group->GroupCount() < 2) //if (group->GroupCount() < 2)
// group->DisbandGroup(); // group->DisbandGroup();
@@ -8098,8 +8159,13 @@ void Bot::Camp(bool databaseSave) {
} }
void Bot::Zone() { void Bot::Zone() {
if(HasGroup()) Raid* raid = entity_list.GetRaidByBotName(this->GetName());
if (raid) {
raid->MemberZoned(this->CastToClient());
}
else if (HasGroup()) {
GetGroup()->MemberZoned(this); GetGroup()->MemberZoned(this);
}
Save(); Save();
Depop(); Depop();
@@ -8304,8 +8370,9 @@ Bot* Bot::GetBotByBotClientOwnerAndBotName(Client* c, std::string botName) {
void Bot::ProcessBotGroupInvite(Client* c, std::string botName) { void Bot::ProcessBotGroupInvite(Client* c, std::string botName) {
if(c) { if(c) {
// Bot* invitedBot = GetBotByBotClientOwnerAndBotName(entity_list.GetBotByBotName(botName)->GetOwner()->CastToClient(), botName);
Bot* invitedBot = GetBotByBotClientOwnerAndBotName(c, botName); Bot* invitedBot = GetBotByBotClientOwnerAndBotName(c, botName);
//Mitch changed entity from c
if(invitedBot && !invitedBot->HasGroup()) { if(invitedBot && !invitedBot->HasGroup()) {
if(!c->IsGrouped()) { if(!c->IsGrouped()) {
Group *g = new Group(c); Group *g = new Group(c);
@@ -8349,7 +8416,11 @@ void Bot::ProcessClientZoneChange(Client* botOwner) {
Bot* tempBot = *itr; Bot* tempBot = *itr;
if(tempBot) { if(tempBot) {
if(tempBot->HasGroup()) { Raid* raid = entity_list.GetRaidByBotName(tempBot->GetName());
if (raid) {
tempBot->Zone();
}
else if(tempBot->HasGroup()) {
Group* g = tempBot->GetGroup(); Group* g = tempBot->GetGroup();
if(g && g->IsGroupMember(botOwner)) { if(g && g->IsGroupMember(botOwner)) {
if(botOwner && botOwner->IsClient()) { if(botOwner && botOwner->IsClient()) {
@@ -8900,11 +8971,51 @@ 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 gid = raid->GetGroup(caster->GetName());
if (gid < 12) {
std::vector<RaidMember> raid_group_members = raid->GetRaidGroupMembers(gid);
for (std::vector<RaidMember>::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))
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( botCasterClass == PALADIN || botCasterClass == BEASTLORD || botCasterClass == RANGER) {
if(caster->HasGroup()) { if(caster->HasGroup() || caster->IsRaidGrouped()) {
Group *g = caster->GetGroup();
float hpRatioToHeal = 25.0f; float hpRatioToHeal = 25.0f;
switch(caster->GetBotStance()) { switch(caster->GetBotStance()) {
case EQ::constants::stanceReactive: case EQ::constants::stanceReactive:
@@ -8921,6 +9032,11 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl
hpRatioToHeal = 25.0f; hpRatioToHeal = 25.0f;
break; break;
} }
Group* g = caster->GetGroup();
uint32 gid = 0xff;
Raid* raid = entity_list.GetRaidByBotName(caster->GetName());
if (raid)
uint32 gid = raid->GetGroup(caster->GetName());
if(g) { if(g) {
for(int i = 0; i < MAX_GROUP_MEMBERS; i++) { for(int i = 0; i < MAX_GROUP_MEMBERS; i++) {
@@ -8949,6 +9065,39 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl
} }
} }
} }
else if (gid < 12)
{
std::vector<RaidMember> raid_group_members = raid->GetRaidGroupMembers(gid);
for (std::vector<RaidMember>::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))
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;
}
}
}
} }
} }
} }
@@ -8961,7 +9110,22 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl
else else
return false; return false;
} }
#ifdef BOTS
//added raid check
if (caster->IsRaidGrouped()) {
Raid* raid = entity_list.GetRaidByBotName(caster->GetName());
uint32 g = raid->GetGroup(caster->GetName());
if (g < 12) {
std::vector<RaidMember> raid_group_members = raid->GetRaidGroupMembers(g);
for (std::vector<RaidMember>::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;
}
}
}
}
#endif
if(caster->HasGroup()) { if(caster->HasGroup()) {
Group *g = caster->GetGroup(); Group *g = caster->GetGroup();
if(g) { if(g) {
@@ -8994,6 +9158,27 @@ 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) {
std::vector<RaidMember> raid_group_members = raid->GetRaidGroupMembers(gid);
for (std::vector<RaidMember>::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))
return true;
}
}
}
}
} }
if (iSpellTypes == SpellType_HateRedux) { if (iSpellTypes == SpellType_HateRedux) {
@@ -9011,13 +9196,41 @@ 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) {
std::vector<RaidMember> raid_group_members = raid->GetRaidGroupMembers(gid);
for (std::vector<RaidMember>::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;
}
}
}
}
} }
if (iSpellTypes == SpellType_PreCombatBuff) { if (iSpellTypes == SpellType_PreCombatBuff) {
if (botCasterClass == BARD || caster->IsEngaged()) if (botCasterClass == BARD || caster->IsEngaged())
return false; return false;
if (caster->HasGroup()) { //added raid check
if (caster->IsRaidGrouped()) {
Raid* raid = entity_list.GetRaidByBotName(caster->GetName());
uint32 g = raid->GetGroup(caster->GetName());
if (g < 12) {
std::vector<RaidMember> raid_group_members = raid->GetRaidGroupMembers(g);
for (std::vector<RaidMember>::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;
}
}
}
} else if (caster->HasGroup()) {
Group *g = caster->GetGroup(); Group *g = caster->GetGroup();
if (g) { if (g) {
for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { for (int i = 0; i < MAX_GROUP_MEMBERS; i++) {
@@ -9808,4 +10021,543 @@ void Bot::StopMoving(float new_heading)
uint8 Bot::spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND] = { 0 }; uint8 Bot::spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND] = { 0 };
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();
if (raid)
{
if (g_invitee)
{
//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]) {
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->GroupUpdate(raid_free_group_id);
// 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->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);
}
}
}
else
{
//As there is no raid
//First, create the raid
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)
{
//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());
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()) {
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->GroupUpdate(0);
if (raid->IsLocked()) {
raid->SendRaidLockTo(c);
}
}
else {
raid->SendRaidCreate(c);
raid->SendMakeLeaderPacketTo(raid->leadername, c);
raid->AddMember(c, 0, false, false, false);
raid->GroupUpdate(0);
if (raid->IsLocked()) {
raid->SendRaidLockTo(c);
}
}
}
}
}
raid->GroupUpdate(0);
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());
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()) {
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());
raid->GroupUpdate(raid_free_group_id);
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);
raid->GroupUpdate(raid_free_group_id);
if (raid->IsLocked()) {
raid->SendRaidLockTo(c);
}
}
}
}
}
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);
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());
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()) {
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());
raid->GroupUpdate(raid_free_group_id);
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);
raid->GroupUpdate(raid_free_group_id);
if (raid->IsLocked()) {
raid->SendRaidLockTo(c);
}
}
}
}
}
raid->GroupUpdate(raid_free_group_id);
g_invitee->JoinRaidXTarget(raid, true);
g_invitee->DisbandGroup(true);
if (raid->IsLocked()) {
raid->SendRaidLockTo(invitor);
}
}
else
{
//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* invitee, Client* invitor) {
if (!invitee || !invitor)
return;
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());
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()) {
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());
raid->GroupUpdate(raid_free_group_id);
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);
raid->GroupUpdate(raid_free_group_id);
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->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();
// raid->SendRaidCreate(invitor);
// raid->SetLeader(invitor); //Added Jan 18
// raid->SendMakeLeaderPacketTo(raid->leadername, invitor);
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());
//raid->GroupUpdate(0);
}
else {
raid->AddBot(b, 0, false, false, false);
//raid->GroupUpdate(0);
b->SetFollowID(g_invitor->GetLeader()->GetID());
}
}
else if (g_invitor->members[x] && g_invitor->members[x]->IsClient()) {
c = g_invitor->members[x]->CastToClient();
if (x == 0) {
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);
}
}
else {
raid->SendRaidCreate(c);
raid->SendMakeLeaderPacketTo(raid->leadername, c);
raid->AddMember(c, 0, false, false, false);
//raid->GroupUpdate(0, true);
if (raid->IsLocked()) {
raid->SendRaidLockTo(c);
}
}
}
}
}
// raid->GroupUpdate(0, true);
// raid->SendBulkRaid(invitee); //Send a raid updates to the invitor
g_invitor->JoinRaidXTarget(raid, 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);
}
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(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);
}
}
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->AddMember(invitor, 0xFFFFFFFF, true, false, true);
raid->SendMakeLeaderPacketTo(invitor->GetName(), invitor); //Mitch Jan 18
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(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);
}
}
else
{
//Third, no group so add the single client invitee
//raid->SendRaidCreate(invitee);
//raid->SendMakeLeaderPacketTo(raid->leadername, invitee);
raid->AddBot(invitee);
invitee->SetFollowID(invitor->GetID());
//if (raid->IsLocked()) {
// raid->SendRaidLockTo(invitee);
//}
}
}
}
}
#endif #endif
+17 -2
View File
@@ -35,6 +35,7 @@
#include "../common/global_define.h" #include "../common/global_define.h"
#include "guild_mgr.h" #include "guild_mgr.h"
#include "worldserver.h" #include "worldserver.h"
#include "raids.h"
#include <sstream> #include <sstream>
@@ -151,8 +152,8 @@ public:
ExtraAttackOptions *opts = nullptr); ExtraAttackOptions *opts = nullptr);
virtual bool HasRaid() { return (GetRaid() ? true : false); } virtual bool HasRaid() { return (GetRaid() ? true : false); }
virtual bool HasGroup() { return (GetGroup() ? true : false); } virtual bool HasGroup() { return (GetGroup() ? true : false); }
virtual Raid* GetRaid() { return entity_list.GetRaidByMob(this); } virtual Raid* GetRaid() { return entity_list.GetRaidByMob(this); } // GetRaidByMob(this);
virtual Group* GetGroup() { return entity_list.GetGroupByMob(this); } virtual Group* GetGroup() { return entity_list.GetGroupByMob(this); } // GetGroupByMob;
// Common, but informal "interfaces" with Client object // Common, but informal "interfaces" with Client object
uint32 CharacterID() { return GetBotID(); } // Just returns the Bot Id uint32 CharacterID() { return GetBotID(); } // Just returns the Bot Id
@@ -377,6 +378,15 @@ public:
static bool CheckDisciplineRecastTimers(Bot *caster, int timer_index); static bool CheckDisciplineRecastTimers(Bot *caster, int timer_index);
static uint32 GetDisciplineRemainingTime(Bot *caster, int timer_index); static uint32 GetDisciplineRemainingTime(Bot *caster, int timer_index);
//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
inline void SetDirtyAutoHaters() { m_dirtyautohaters = true; } //Mitch
static std::list<BotSpell> GetBotSpellsForSpellEffect(Bot* botCaster, int spellEffect); static std::list<BotSpell> GetBotSpellsForSpellEffect(Bot* botCaster, int spellEffect);
static std::list<BotSpell> GetBotSpellsForSpellEffectAndTargetType(Bot* botCaster, int spellEffect, SpellTargetType targetType); static std::list<BotSpell> GetBotSpellsForSpellEffectAndTargetType(Bot* botCaster, int spellEffect, SpellTargetType targetType);
static std::list<BotSpell> GetBotSpellsBySpellType(Bot* botCaster, uint32 spellType); static std::list<BotSpell> GetBotSpellsBySpellType(Bot* botCaster, uint32 spellType);
@@ -597,6 +607,9 @@ public:
int32 GetBaseDR() { return _baseDR; } int32 GetBaseDR() { return _baseDR; }
int32 GetBaseCorrup() { return _baseCorrup; } int32 GetBaseCorrup() { return _baseCorrup; }
//Raid additions
Raid* p_raid_instance;
protected: protected:
virtual void PetAIProcess(); virtual void PetAIProcess();
virtual void BotMeditate(bool isSitting); virtual void BotMeditate(bool isSitting);
@@ -661,6 +674,7 @@ private:
Timer m_auto_defend_timer; Timer m_auto_defend_timer;
//Timer m_combat_jitter_timer; //Timer m_combat_jitter_timer;
//bool m_combat_jitter_flag; //bool m_combat_jitter_flag;
bool m_dirtyautohaters;
bool m_guard_flag; bool m_guard_flag;
bool m_hold_flag; bool m_hold_flag;
bool m_attack_flag; bool m_attack_flag;
@@ -727,6 +741,7 @@ private:
public: public:
static uint8 spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND]; static uint8 spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND];
}; };
#endif // BOTS #endif // BOTS
+12 -11
View File
@@ -2632,19 +2632,20 @@ bool BotDatabase::LoadGroupedBotsByGroupID(const uint32 owner_id, const uint32 g
{ {
if (!group_id || !owner_id) if (!group_id || !owner_id)
return false; 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 `charid`" "SELECT `mob_id` FROM `vw_groups` "
" FROM `group_id`" "WHERE `group_id` = '%u' "
" WHERE `groupid` = '%u'" "AND `mob_type`='B' "
" AND `charid` IN (" "AND `mob_id` IN (SELECT `bot_id` FROM `bot_data` WHERE `owner_id` = '%u');"
" SELECT `bot_id`" , group_id, owner_id);
" FROM `bot_data`" /*query = StringFormat(
" WHERE `owner_id` = '%u'" "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, group_id,
owner_id owner_id);*/
);
auto results = database.QueryDatabase(query); auto results = database.QueryDatabase(query);
if (!results.Success()) if (!results.Success())
+2626
View File
File diff suppressed because it is too large Load Diff
+47
View File
@@ -0,0 +1,47 @@
/* 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_RAID_H
#define BOT_RAID_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 <sstream>
extern WorldServer worldserver;
//void Bot::PetAIProcess_Raid();
#endif // BOTS
#endif // BOT_RAID_H
+8 -1
View File
@@ -3,7 +3,7 @@
This program is free software; you can redistribute it and/or modify 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 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, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which but WITHOUT ANY WARRANTY except by those people which sell it, which
@@ -31,6 +31,13 @@
bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) {
// Bot AI
Raid* raid = entity_list.GetRaidByBotName(this->GetName());
if (raid) {
return AICastSpell_Raid(tar, iChance, iSpellTypes);
//return true;
}
if (!tar) { if (!tar) {
return false; return false;
} }
+4 -3
View File
@@ -804,10 +804,11 @@ void Client::QueuePacket(const EQApplicationPacket* app, bool ack_req, CLIENT_CO
// todo: save packets for later use // todo: save packets for later use
AddPacket(app, ack_req); AddPacket(app, ack_req);
} }
else else if (eqs) // && !IsBot()) //Mitch added the BoTcheck for a fail safe on trying to send a packet to a BoT!
if(eqs) {
eqs->QueuePacket(app, ack_req); eqs->QueuePacket(app, ack_req);
} }
}
void Client::FastQueuePacket(EQApplicationPacket** app, bool ack_req, CLIENT_CONN_STATUS required_state) { void Client::FastQueuePacket(EQApplicationPacket** app, bool ack_req, CLIENT_CONN_STATUS required_state) {
// if the program doesnt care about the status or if the status isnt what we requested // if the program doesnt care about the status or if the status isnt what we requested
@@ -817,7 +818,7 @@ void Client::FastQueuePacket(EQApplicationPacket** app, bool ack_req, CLIENT_CON
return; return;
} }
else { else {
if(eqs) if(eqs) // && !IsBot()) //Mitch added
eqs->FastQueuePacket((EQApplicationPacket **)app, ack_req); eqs->FastQueuePacket((EQApplicationPacket **)app, ack_req);
else if (app && (*app)) else if (app && (*app))
delete *app; delete *app;
+212 -4
View File
@@ -25,6 +25,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <zlib.h> #include <zlib.h>
#include "bot.h"
#ifdef _WINDOWS #ifdef _WINDOWS
#define snprintf _snprintf #define snprintf _snprintf
@@ -72,6 +73,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#ifdef BOTS #ifdef BOTS
#include "bot.h" #include "bot.h"
#include "bot_command.h"
#endif #endif
extern QueryServ* QServ; extern QueryServ* QServ;
@@ -587,6 +589,31 @@ void Client::CompleteConnect()
if (raid) { if (raid) {
SetRaidGrouped(true); SetRaidGrouped(true);
raid->LearnMembers(); raid->LearnMembers();
#ifdef BOTS
std::list<BotsAvailableList> bots_list;
database.botdb.LoadBotsList(this->CharacterID(), bots_list);
std::vector<RaidMember> r_members = raid->GetMembers();
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->p_raid_instance = raid;
//b->SetFollowID(this->GetID());
}
}
}
}
}
#endif
raid->VerifyRaid(); raid->VerifyRaid();
raid->GetRaidDetails(); raid->GetRaidDetails();
/* /*
@@ -6970,6 +6997,11 @@ void Client::Handle_OP_GroupInvite2(const EQApplicationPacket *app)
} }
#ifdef BOTS #ifdef BOTS
else if (Invitee->IsBot()) { else if (Invitee->IsBot()) {
Client* inviter = entity_list.GetClientByName(gis->inviter_name);
//Bot* invitee = entity_list.GetBotByBotName(gis->invitee_name);
if (inviter->IsRaidGrouped())
Bot::ProcessRaidInvite(Invitee->CastToBot(), inviter);
else
Bot::ProcessBotGroupInvite(this, std::string(Invitee->GetName())); Bot::ProcessBotGroupInvite(this, std::string(Invitee->GetName()));
} }
#endif #endif
@@ -11423,6 +11455,45 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
case RaidCommandInviteIntoExisting: case RaidCommandInviteIntoExisting:
case RaidCommandInvite: { case RaidCommandInvite: {
#ifdef BOTS //Mitch
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();
Group* player_to_invite_group = player_to_invite->GetGroup();
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
Client* player_to_invite = entity_list.GetClientByName(raid_command_packet->player_name); Client* player_to_invite = entity_list.GetClientByName(raid_command_packet->player_name);
if (!player_to_invite) if (!player_to_invite)
@@ -11439,7 +11510,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
MessageString(Chat::Red, ALREADY_IN_PARTY); MessageString(Chat::Red, ALREADY_IN_PARTY);
break; 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)) { 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."); Message(Chat::Red, "You can only invite an ungrouped player or group leader to join your raid.");
break; break;
@@ -11461,8 +11532,62 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
break; break;
} }
}
case RaidCommandAcceptInvite: { case RaidCommandAcceptInvite: {
Client* player_accepting_invite = entity_list.GetClientByName(raid_command_packet->player_name); 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 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();
if (invitee && invitee->IsRaidGrouped()) {
invitor->MessageString(Chat::White, ALREADY_IN_RAID, GetName()); //group failed, must invite members not in raid...
return;
}
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_invitor->members[x] && g_invitor->members[x]->IsBot())
{
b = entity_list.GetBotByBotName(g_invitor->members[x]->GetName());
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::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 (player_accepting_invite) {
if (IsRaidGrouped()) { if (IsRaidGrouped()) {
player_accepting_invite->MessageString(Chat::White, ALREADY_IN_RAID, GetName()); //group failed, must invite members not in raid... player_accepting_invite->MessageString(Chat::White, ALREADY_IN_RAID, GetName()); //group failed, must invite members not in raid...
@@ -11732,9 +11857,90 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
} }
case RaidCommandDisband: { case RaidCommandDisband: {
Raid* raid = entity_list.GetRaidByClient(this); 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);
Bot* b_to_disband = entity_list.GetBotByBotName(raid_command_packet->leader_name);
if (raid) { if (raid) {
uint32 group = raid->GetGroup(raid_command_packet->leader_name); 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<Bot*> raid_members_bots;
if (c_to_disband)
{
// 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)
{
raid_members_bots.emplace_back(raid->members[i].member->CastToBot());
}
}
// 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->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<RaidMember> 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());
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)
{
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<RaidMember> 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<RaidMember> 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());
}
}
break;
}
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
if (group < 12) { if (group < 12) {
uint32 i = raid->GetPlayerIndex(raid_command_packet->leader_name); uint32 i = raid->GetPlayerIndex(raid_command_packet->leader_name);
if (raid->members[i].IsGroupLeader) { //assign group leader to someone else if (raid->members[i].IsGroupLeader) { //assign group leader to someone else
@@ -11762,11 +11968,12 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
} }
} }
} }
raid->RemoveMember(raid_command_packet->leader_name); raid->RemoveMember(raid_command_packet->leader_name);
Client* c = entity_list.GetClientByName(raid_command_packet->leader_name); Client* c = entity_list.GetClientByName(raid_command_packet->leader_name);
if (c) if (c) {
raid->SendGroupDisband(c); raid->SendGroupDisband(c);
}
else { else {
auto pack = auto pack =
new ServerPacket(ServerOP_RaidGroupDisband, sizeof(ServerRaidGeneralAction_Struct)); new ServerPacket(ServerOP_RaidGroupDisband, sizeof(ServerRaidGeneralAction_Struct));
@@ -11780,7 +11987,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
} }
//r->SendRaidGroupRemove(ri->leader_name, grp); //r->SendRaidGroupRemove(ri->leader_name, grp);
raid->GroupUpdate(group);// break raid->GroupUpdate(group);// break
//} if (!raid->RaidCount())
raid->DisbandRaid();
} }
break; break;
} }
+3
View File
@@ -31,6 +31,8 @@
#include "zone_store.h" #include "zone_store.h"
#include "position.h" #include "position.h"
extern bool Critical; //Mitch
float Mob::GetActSpellRange(uint16 spell_id, float range, bool IsBard) float Mob::GetActSpellRange(uint16 spell_id, float range, bool IsBard)
{ {
float extrange = 100; float extrange = 100;
@@ -316,6 +318,7 @@ int32 Mob::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
value += value * CastToNPC()->GetSpellFocusHeal() / 100; value += value * CastToNPC()->GetSpellFocusHeal() / 100;
} }
Critical = false;
int32 base_value = value; int32 base_value = value;
int16 critical_chance = 0; int16 critical_chance = 0;
int8 critical_modifier = 1; int8 critical_modifier = 1;
+42
View File
@@ -2113,6 +2113,48 @@ Raid *EntityList::GetRaidByClient(Client* client)
return nullptr; return nullptr;
} }
Raid* EntityList::GetRaidByBotName(const char* name)
{
std::list<Raid*>::iterator iterator;
iterator = raid_list.begin();
while (iterator != raid_list.end()) {
for (auto& member : (*iterator)->members) {
if (member.membername) {
if (strcmp(member.membername, name) == 0) {
//client->p_raid_instance = *iterator;
return *iterator;
}
}
}
++iterator;
}
return nullptr;
}
Raid* EntityList::GetRaidByBot(Bot* bot)
{
std::list<Raid*>::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) Raid *EntityList::GetRaidByMob(Mob *mob)
{ {
std::list<Raid *>::iterator iterator; std::list<Raid *>::iterator iterator;
+4
View File
@@ -198,6 +198,10 @@ public:
Raid *GetRaidByClient(Client* client); Raid *GetRaidByClient(Client* client);
Raid *GetRaidByID(uint32 id); Raid *GetRaidByID(uint32 id);
Raid *GetRaidByLeaderName(const char *leader); Raid *GetRaidByLeaderName(const char *leader);
#ifdef BOTS
Raid* GetRaidByBotName(const char* name);
Raid* GetRaidByBot(Bot* bot);
#endif
Corpse *GetCorpseByOwner(Client* client); Corpse *GetCorpseByOwner(Client* client);
Corpse *GetCorpseByOwnerWithinRange(Client* client, Mob* center, int range); Corpse *GetCorpseByOwnerWithinRange(Client* client, Mob* center, int range);
+1 -1
View File
@@ -1097,7 +1097,7 @@ void Raid::SplitExp(uint32 exp, Mob* other) {
return; return;
for (unsigned int x = 0; x < MAX_RAID_MEMBERS; x++) { 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; Client *cmember = members[x].member;
// add exp + exp cap // add exp + exp cap
+59 -2
View File
@@ -248,10 +248,24 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte
uint32 i = 0; uint32 i = 0;
for (i = 0; i < MAX_GROUP_MEMBERS; ++i) for (i = 0; i < MAX_GROUP_MEMBERS; ++i)
{ {
#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)) if (!strcasecmp(membername[i], NewMemberName))
{ {
return false; return false;
} }
#endif
} }
// Put them in the group // Put them in the group
@@ -1140,7 +1154,13 @@ void Group::TeleportGroup(Mob* sender, uint32 zoneID, uint16 instance_id, float
} }
bool Group::LearnMembers() { 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); auto results = database.QueryDatabase(query);
if (!results.Success()) if (!results.Success())
return false; return false;
@@ -1155,7 +1175,7 @@ bool Group::LearnMembers() {
return false; 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) { for(auto row = results.begin(); row != results.end(); ++row) {
if(!row[0]) if(!row[0])
continue; continue;
@@ -1165,7 +1185,24 @@ bool Group::LearnMembers() {
memberIndex++; 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; return true;
} }
@@ -1176,6 +1213,22 @@ void Group::VerifyGroup() {
Only called every once in a while (on member re-join for now). 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; uint32 i;
for (i = 0; i < MAX_GROUP_MEMBERS; i++) { for (i = 0; i < MAX_GROUP_MEMBERS; i++) {
if (membername[i][0] == '\0') { if (membername[i][0] == '\0') {
@@ -1195,6 +1248,10 @@ void Group::VerifyGroup() {
members[i] = nullptr; members[i] = nullptr;
continue; 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(them != nullptr && members[i] != them) { //our pointer is out of date... not so good.
#if EQDEBUG >= 5 #if EQDEBUG >= 5
+1
View File
@@ -88,6 +88,7 @@ volatile bool RunLoops = true;
#endif #endif
extern volatile bool is_zone_loaded; extern volatile bool is_zone_loaded;
extern bool Critical = false;
EntityList entity_list; EntityList entity_list;
WorldServer worldserver; WorldServer worldserver;
+1 -1
View File
@@ -3855,7 +3855,7 @@ void Mob::QuestJournalledSay(Client *QuestInitiator, const char *str, Journal::O
const char *Mob::GetCleanName() 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); CleanMobName(GetName(), clean_name);
} }
+192 -13
View File
@@ -24,6 +24,7 @@
#include "groups.h" #include "groups.h"
#include "mob.h" #include "mob.h"
#include "raids.h" #include "raids.h"
#include "bot.h" //Mitch
#include "worldserver.h" #include "worldserver.h"
@@ -97,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, " std::string query = StringFormat("INSERT INTO raid_members SET raidid = %lu, charid = %lu, "
"groupid = %lu, _class = %d, level = %d, name = '%s', " "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)GetID(), (unsigned long)c->CharacterID(),
(unsigned long)group, c->GetClass(), c->GetLevel(), (unsigned long)group, c->GetClass(), c->GetLevel(),
c->GetName(), groupleader, rleader, looter); c->GetName(), groupleader, rleader, looter);
@@ -109,6 +110,14 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo
LearnMembers(); LearnMembers();
VerifyRaid(); VerifyRaid();
#ifdef BOTS
if (rleader) {
database.SetRaidGroupLeaderInfo(group, GetID());
UpdateRaidAAs();
}
else
#endif
if (rleader) { if (rleader) {
database.SetRaidGroupLeaderInfo(RAID_GROUPLESS, GetID()); database.SetRaidGroupLeaderInfo(RAID_GROUPLESS, GetID());
UpdateRaidAAs(); UpdateRaidAAs();
@@ -162,6 +171,86 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo
worldserver.SendPacket(pack); worldserver.SendPacket(pack);
safe_delete(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, isbot = 1",
(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();
// 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);
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;
rga->rid = GetID();
strn0cpy(rga->playername, b->GetName(), 64);
rga->zoneid = zone->GetZoneID();
rga->instance_id = zone->GetInstanceID();
worldserver.SendPacket(pack);
safe_delete(pack);
}
void Raid::RemoveMember(const char *characterName) void Raid::RemoveMember(const char *characterName)
{ {
@@ -169,6 +258,17 @@ void Raid::RemoveMember(const char *characterName)
auto results = database.QueryDatabase(query); auto results = database.QueryDatabase(query);
Client *client = entity_list.GetClientByName(characterName); Client *client = entity_list.GetClientByName(characterName);
#ifdef BOTS
Bot* bot = entity_list.GetBotByBotName(characterName);
if (bot) {
bot->SetFollowID(bot->GetOwner()->CastToClient()->GetID());
bot->SetGrouped(false);
bot->SetTarget(nullptr);
bot->SetRaidGrouped(false);
}
#endif
disbandCheck = true; disbandCheck = true;
SendRaidRemoveAll(characterName); SendRaidRemoveAll(characterName);
SendRaidDisband(client); SendRaidDisband(client);
@@ -963,7 +1063,7 @@ void Raid::SendRaidAdd(const char *who, Client *to)
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) if(strcmp(members[x].membername, who) == 0)// || !members[x].SentToBotOwner) //Mitch
{ {
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidAddMember_Struct)); auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidAddMember_Struct));
RaidAddMember_Struct *ram = (RaidAddMember_Struct*)outapp->pBuffer; RaidAddMember_Struct *ram = (RaidAddMember_Struct*)outapp->pBuffer;
@@ -999,6 +1099,7 @@ void Raid::SendRaidAddAll(const char *who)
this->QueuePacket(outapp); this->QueuePacket(outapp);
safe_delete(outapp); safe_delete(outapp);
return; return;
} }
} }
} }
@@ -1111,9 +1212,12 @@ void Raid::SendBulkRaid(Client *to)
if(!to) if(!to)
return; return;
if (members[GetPlayerIndex(to)].IsBot)
return;
for(int x = 0; x < MAX_RAID_MEMBERS; x++) 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); SendRaidAdd(members[x].membername, to);
} }
@@ -1124,7 +1228,7 @@ void Raid::QueuePacket(const EQApplicationPacket *app, bool ack_req)
{ {
for(int x = 0; x < MAX_RAID_MEMBERS; x++) for(int x = 0; x < MAX_RAID_MEMBERS; x++)
{ {
if(members[x].member) if(members[x].member && !members[x].IsBot)
{ {
members[x].member->QueuePacket(app, ack_req); members[x].member->QueuePacket(app, ack_req);
} }
@@ -1133,6 +1237,11 @@ void Raid::QueuePacket(const EQApplicationPacket *app, bool ack_req)
void Raid::SendMakeLeaderPacket(const char *who) //30 void Raid::SendMakeLeaderPacket(const char *who) //30
{ {
//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)); auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct));
RaidLeadershipUpdate_Struct *rg = (RaidLeadershipUpdate_Struct*)outapp->pBuffer; RaidLeadershipUpdate_Struct *rg = (RaidLeadershipUpdate_Struct*)outapp->pBuffer;
rg->action = raidMakeLeader; rg->action = raidMakeLeader;
@@ -1148,6 +1257,9 @@ void Raid::SendMakeLeaderPacketTo(const char *who, Client *to)
if(!to) if(!to)
return; return;
if (members[GetPlayerIndex(who)].IsBot)
return;
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct)); auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct));
RaidLeadershipUpdate_Struct *rg = (RaidLeadershipUpdate_Struct*)outapp->pBuffer; RaidLeadershipUpdate_Struct *rg = (RaidLeadershipUpdate_Struct*)outapp->pBuffer;
rg->action = raidMakeLeader; rg->action = raidMakeLeader;
@@ -1178,6 +1290,9 @@ void Raid::SendGroupUpdate(Client *to)
if(!to) if(!to)
return; return;
if (members[GetPlayerIndex(to)].IsBot)
return;
auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupUpdate2_Struct)); auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupUpdate2_Struct));
GroupUpdate2_Struct* gu = (GroupUpdate2_Struct*)outapp->pBuffer; GroupUpdate2_Struct* gu = (GroupUpdate2_Struct*)outapp->pBuffer;
gu->action = groupActUpdate; gu->action = groupActUpdate;
@@ -1366,6 +1481,9 @@ void Raid::SendRaidMOTDToWorld()
void Raid::SendGroupLeadershipAA(Client *c, uint32 gid) void Raid::SendGroupLeadershipAA(Client *c, uint32 gid)
{ {
if (members[GetPlayerIndex(c)].IsBot)
return;
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct)); auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct));
RaidLeadershipUpdate_Struct *rlaa = (RaidLeadershipUpdate_Struct *)outapp->pBuffer; RaidLeadershipUpdate_Struct *rlaa = (RaidLeadershipUpdate_Struct *)outapp->pBuffer;
rlaa->action = raidSetLeaderAbilities; rlaa->action = raidSetLeaderAbilities;
@@ -1381,17 +1499,46 @@ void Raid::SendGroupLeadershipAA(Client *c, uint32 gid)
void Raid::SendGroupLeadershipAA(uint32 gid) void Raid::SendGroupLeadershipAA(uint32 gid)
{ {
for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++) 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 && !members[i].IsBot)
SendGroupLeadershipAA(members[i].member, gid); SendGroupLeadershipAA(members[i].member, gid);
} }
void Raid::SendAllRaidLeadershipAA() void Raid::SendAllRaidLeadershipAA()
{ {
for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++) for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++)
if (members[i].member) if (members[i].member && !members[i].IsBot)
SendGroupLeadershipAA(members[i].member, members[i].GroupNumber); 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) void Raid::LockRaid(bool lockFlag)
{ {
std::string query = StringFormat("UPDATE raid_details SET locked = %d WHERE raidid = %lu", std::string query = StringFormat("UPDATE raid_details SET locked = %d WHERE raidid = %lu",
@@ -1458,7 +1605,7 @@ bool Raid::LearnMembers()
memset(members, 0, (sizeof(RaidMember)*MAX_RAID_MEMBERS)); memset(members, 0, (sizeof(RaidMember)*MAX_RAID_MEMBERS));
std::string query = StringFormat("SELECT name, groupid, _class, level, " std::string query = StringFormat("SELECT name, groupid, _class, level, "
"isgroupleader, israidleader, islooter " "isgroupleader, israidleader, islooter, isbot "
"FROM raid_members WHERE raidid = %lu", "FROM raid_members WHERE raidid = %lu",
(unsigned long)GetID()); (unsigned long)GetID());
auto results = database.QueryDatabase(query); auto results = database.QueryDatabase(query);
@@ -1489,6 +1636,7 @@ bool Raid::LearnMembers()
members[index].IsGroupLeader = atoi(row[4]); members[index].IsGroupLeader = atoi(row[4]);
members[index].IsRaidLeader = atoi(row[5]); members[index].IsRaidLeader = atoi(row[5]);
members[index].IsLooter = atoi(row[6]); members[index].IsLooter = atoi(row[6]);
members[index].IsBot = atoi(row[7]); //Mitch
++index; ++index;
} }
@@ -1504,11 +1652,22 @@ void Raid::VerifyRaid()
} }
else{ else{
Client *c = entity_list.GetClientByName(members[x].membername); Client *c = entity_list.GetClientByName(members[x].membername);
#ifdef BOTS
Bot* b = entity_list.GetBotByBotName(members[x].membername); //Mitch
#endif
if(c){ if(c){
members[x].member = 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 { else {
members[x].member = nullptr; members[x].member = nullptr;
members[x].IsBot = false;
} }
} }
if(members[x].IsRaidLeader){ if(members[x].IsRaidLeader){
@@ -1561,7 +1720,7 @@ void Raid::SendHPManaEndPacketsTo(Client *client)
EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct)); EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct));
for(int x = 0; x < MAX_RAID_MEMBERS; x++) { for(int x = 0; x < MAX_RAID_MEMBERS; x++) {
if(members[x].member) { if(members[x].member && !members[x].IsBot) {
if((members[x].member != client) && (members[x].GroupNumber == group_id)) { if((members[x].member != client) && (members[x].GroupNumber == group_id)) {
members[x].member->CreateHPPacket(&hp_packet); members[x].member->CreateHPPacket(&hp_packet);
@@ -1603,7 +1762,7 @@ void Raid::SendHPManaEndPacketsFrom(Mob *mob)
mob->CreateHPPacket(&hpapp); mob->CreateHPPacket(&hpapp);
for(int x = 0; x < MAX_RAID_MEMBERS; x++) { for(int x = 0; x < MAX_RAID_MEMBERS; x++) {
if(members[x].member) { if(members[x].member && !members[x].IsBot) {
if(!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) { if(!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) {
members[x].member->QueuePacket(&hpapp, false); members[x].member->QueuePacket(&hpapp, false);
if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) { if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) {
@@ -1636,7 +1795,7 @@ void Raid::SendManaPacketFrom(Mob *mob)
EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct)); EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct));
for (int x = 0; x < MAX_RAID_MEMBERS; x++) { for (int x = 0; x < MAX_RAID_MEMBERS; x++) {
if (members[x].member) { if (members[x].member && !members[x].IsBot) {
if (!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) { if (!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) {
if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) { if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) {
outapp.SetOpcode(OP_MobManaUpdate); outapp.SetOpcode(OP_MobManaUpdate);
@@ -1663,7 +1822,7 @@ void Raid::SendEndurancePacketFrom(Mob *mob)
EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct)); EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct));
for (int x = 0; x < MAX_RAID_MEMBERS; x++) { for (int x = 0; x < MAX_RAID_MEMBERS; x++) {
if (members[x].member) { if (members[x].member && !members[x].IsBot) {
if (!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) { if (!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) {
if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) { if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) {
outapp.SetOpcode(OP_MobEnduranceUpdate); outapp.SetOpcode(OP_MobEnduranceUpdate);
@@ -1770,9 +1929,14 @@ void Raid::CheckGroupMentor(uint32 group_id, Client *c)
void Raid::SetDirtyAutoHaters() void Raid::SetDirtyAutoHaters()
{ {
for (int i = 0; i < MAX_RAID_MEMBERS; ++i) for (int i = 0; i < MAX_RAID_MEMBERS; ++i)
if (members[i].member) if (members[i].member && members[i].IsBot)
{
members[i].member->CastToBot()->SetDirtyAutoHaters();
}
else if (members[i].member && !members[i].IsBot)
{
members[i].member->SetDirtyAutoHaters(); 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*/) { void Raid::QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_required /*= true*/, bool ignore_sender /*= true*/, float distance /*= 0*/, bool group_only /*= true*/) {
@@ -1791,6 +1955,9 @@ void Raid::QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_re
if (!members[i].member->IsClient()) if (!members[i].member->IsClient())
continue; continue;
if (members[i].IsBot)
continue;
if (ignore_sender && members[i].member == sender) if (ignore_sender && members[i].member == sender)
continue; continue;
@@ -1853,3 +2020,15 @@ bool Raid::DoesAnyMemberHaveExpeditionLockout(
return Expedition::HasLockoutByCharacterName(raid_member.membername, expedition_name, event_name); return Expedition::HasLockoutByCharacterName(raid_member.membername, expedition_name, event_name);
}); });
} }
Mob* Raid::GetRaidMainAssistOneByName(const char* name)
{
Raid* raid = entity_list.GetRaidByBotName(name);
std::vector<RaidMember> raid_members = raid->GetMembers();
for (RaidMember iter : raid_members)
{
if (iter.IsRaidMainAssistOne)
return iter.member->CastToMob();
}
return nullptr;
}
+18
View File
@@ -88,6 +88,16 @@ struct RaidMember{
bool IsGroupLeader; bool IsGroupLeader;
bool IsRaidLeader; bool IsRaidLeader;
bool IsLooter; bool IsLooter;
#ifdef BOTS
bool IsBot = false;
bool IsGroupHealer;
bool IsRaidSlower;
bool IsRaidMainAssistOne;
bool IsRaidMainAssistTwo;
bool IsRaidMainTank;
bool IsRaidOffTankOne;
bool IsRaidOffTankTwo;
#endif
}; };
struct GroupMentor { struct GroupMentor {
@@ -112,6 +122,12 @@ public:
bool IsRaid() { return true; } bool IsRaid() { return true; }
void AddMember(Client *c, uint32 group = 0xFFFFFFFF, bool rleader=false, bool groupleader=false, bool looter=false); 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);
#endif
void RemoveMember(const char *c); void RemoveMember(const char *c);
void DisbandRaid(); void DisbandRaid();
void MoveMember(const char *name, uint32 newGroup); void MoveMember(const char *name, uint32 newGroup);
@@ -122,6 +138,7 @@ public:
bool IsRaidMember(const char *name); bool IsRaidMember(const char *name);
void UpdateLevel(const char *name, int newLevel); void UpdateLevel(const char *name, int newLevel);
uint32 GetFreeGroup(); uint32 GetFreeGroup();
uint8 GroupCount(uint32 gid); uint8 GroupCount(uint32 gid);
uint8 RaidCount(); uint8 RaidCount();
@@ -241,6 +258,7 @@ public:
bool DoesAnyMemberHaveExpeditionLockout(const std::string& expedition_name, const std::string& event_name, int max_check_count = 0); bool DoesAnyMemberHaveExpeditionLockout(const std::string& expedition_name, const std::string& event_name, int max_check_count = 0);
std::vector<RaidMember> GetMembers() const; std::vector<RaidMember> GetMembers() const;
std::vector<RaidMember> GetRaidGroupMembers(uint32 gid);
RaidMember members[MAX_RAID_MEMBERS]; RaidMember members[MAX_RAID_MEMBERS];
char leadername[64]; char leadername[64];
+26 -1
View File
@@ -3928,8 +3928,24 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, int reflect_effectivenes
spelltar->MessageString(Chat::SpellFailure, YOU_RESIST, spells[spell_id].name); spelltar->MessageString(Chat::SpellFailure, YOU_RESIST, spells[spell_id].name);
} }
else { else {
#ifndef BOTS
MessageString(Chat::SpellFailure, TARGET_RESISTED, spells[spell_id].name); MessageString(Chat::SpellFailure, TARGET_RESISTED, spells[spell_id].name);
spelltar->MessageString(Chat::SpellFailure, YOU_RESIST, 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()) { if (spelltar->IsAIControlled()) {
@@ -3957,7 +3973,16 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, int reflect_effectivenes
return false; 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()){ if (spelltar->IsClient()){
spelltar->CastToClient()->BreakSneakWhenCastOn(this, false); spelltar->CastToClient()->BreakSneakWhenCastOn(this, false);
spelltar->CastToClient()->BreakFeignDeathWhenCastOn(false); spelltar->CastToClient()->BreakFeignDeathWhenCastOn(false);