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
+2 -2
View File
@@ -54,5 +54,5 @@ bin/
/Win32
/x64
/client_files/**/CMakeFiles/
.idea
submodules/libuv
.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 israidleader;
int islooter;
int isbot;
};
static std::string PrimaryKey()
@@ -46,6 +47,7 @@ public:
"isgroupleader",
"israidleader",
"islooter",
"isbot",
};
}
@@ -90,6 +92,7 @@ public:
entry.isgroupleader = 0;
entry.israidleader = 0;
entry.islooter = 0;
entry.isbot = 0;
return entry;
}
@@ -133,7 +136,8 @@ public:
entry.name = row[5] ? row[5] : "";
entry.isgroupleader = atoi(row[6]);
entry.israidleader = atoi(row[7]);
entry.islooter = atoi(row[8]);
entry.islooter = atoi(row[8]);
entry.isbot = atoi(row[9]);
return entry;
}
@@ -176,6 +180,7 @@ public:
update_values.push_back(columns[6] + " = " + std::to_string(raid_members_entry.isgroupleader));
update_values.push_back(columns[7] + " = " + std::to_string(raid_members_entry.israidleader));
update_values.push_back(columns[8] + " = " + std::to_string(raid_members_entry.islooter));
update_values.push_back(columns[9] + " = " + std::to_string(raid_members_entry.isbot)); //Mitch
auto results = db.QueryDatabase(
fmt::format(
@@ -206,6 +211,7 @@ public:
insert_values.push_back(std::to_string(raid_members_entry.isgroupleader));
insert_values.push_back(std::to_string(raid_members_entry.israidleader));
insert_values.push_back(std::to_string(raid_members_entry.islooter));
insert_values.push_back(std::to_string(raid_members_entry.isbot));
auto results = db.QueryDatabase(
fmt::format(
@@ -244,6 +250,7 @@ public:
insert_values.push_back(std::to_string(raid_members_entry.isgroupleader));
insert_values.push_back(std::to_string(raid_members_entry.israidleader));
insert_values.push_back(std::to_string(raid_members_entry.islooter));
insert_values.push_back(std::to_string(raid_members_entry.isbot));
insert_chunks.push_back("(" + implode(",", insert_values) + ")");
}
@@ -286,6 +293,7 @@ public:
entry.isgroupleader = atoi(row[6]);
entry.israidleader = atoi(row[7]);
entry.islooter = atoi(row[8]);
entry.isbot = atoi(row[9]);
all_entries.push_back(entry);
}
@@ -319,6 +327,7 @@ public:
entry.isgroupleader = atoi(row[6]);
entry.israidleader = atoi(row[7]);
entry.islooter = atoi(row[8]);
entry.isbot = atoi(row[9]);
all_entries.push_back(entry);
}
+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, AllowApplyPotionCommand, true, "Allows the use of the bot command 'applypotion'")
RULE_BOOL(Bots, RestrictApplyPotionToRogue, true, "Restricts the bot command 'applypotion' to rogue-usable potions (i.e., poisons)")
RULE_BOOL(Bots, DisplayHealDamage, false, "Enables the display of bot heal damage to the 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, 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, ResurrectionSicknessSpell, 756, "756 is Default Resurrection Sickness Spell")
RULE_CATEGORY_END()
#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_array(d) if(d) { delete[] d; d=nullptr; }
//#define safe_delete(d)(_RPTF0(_CRT_WARN,"Testing delete function\n"));
//#define safe_delete(d) if(d) { }
//#define safe_delete_array(d) if(d) { }
#define L32(i) ((uint32) i)
#define H32(i) ((uint32) (i >> 32))
#define L16(i) ((uint16) i)
+130 -29
View File
@@ -49,6 +49,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
extern QueryServ* QServ;
extern WorldServer worldserver;
extern FastMath g_Math;
extern bool Critical;
#ifdef _WINDOWS
#define snprintf _snprintf
@@ -3582,7 +3583,7 @@ bool Mob::CheckDoubleAttack()
return zone->random.Int(1, 500) <= chance;
}
void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const EQ::skills::SkillType skill_used, bool &avoidable, const int8 buffslot, const bool iBuffTic, eSpecialAttacks special) {
void Mob::CommonDamage(Mob* attacker, int& damage, const uint16 spell_id, const EQ::skills::SkillType skill_used, bool& avoidable, const int8 buffslot, const bool iBuffTic, eSpecialAttacks special) {
// This method is called with skill_used=ABJURE for Damage Shield damage.
bool FromDamageShield = (skill_used == EQ::skills::SkillAbjuration);
bool ignore_invul = false;
@@ -3652,7 +3653,7 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
// and remove sitting regen. Removes bug where client clicks sit
// during battle and gains pet hp-regen and bugs the sit button.
if (IsPet()) {
Mob *owner = this->GetOwner();
Mob* owner = this->GetOwner();
if (owner && owner->IsClient()) {
if (GetPetOrder() == SPO_Sit) {
SetPetOrder(SPO_Follow);
@@ -3665,7 +3666,7 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
} //end `if there is some damage being done and theres anattacker person involved`
Mob *pet = GetPet();
Mob* pet = GetPet();
// pets that have GHold will never automatically add NPCs
// pets that have Hold and no Focus will add NPCs if they're engaged
// pets that have Hold and Focus will not add NPCs
@@ -3681,7 +3682,7 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
!attacker->IsCorpse() &&
!pet->IsGHeld() &&
!attacker->IsTrap()
) {
) {
if (!pet->IsHeld()) {
LogAggro("Sending pet [{}] into battle due to attack", pet->GetName());
if (IsClient()) {
@@ -3905,12 +3906,12 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
//Note: if players can become pets, they will not receive damage messages of their own
//this was done to simplify the code here (since we can only effectively skip one mob on queue)
eqFilterType filter;
Mob *skip = attacker;
Mob* skip = attacker;
if (attacker && attacker->GetOwnerID()) {
//attacker is a pet, let pet owners see their pet's damage
Mob* owner = attacker->GetOwner();
if (owner && owner->IsClient()) {
if (((spell_id != SPELL_UNKNOWN) || (FromDamageShield)) && damage>0) {
if (((spell_id != SPELL_UNKNOWN) || (FromDamageShield)) && damage > 0) {
//special crap for spell damage, looks hackish to me
char val1[20] = { 0 };
owner->MessageString(Chat::NonMelee, OTHER_HIT_NONMELEE, GetCleanName(), ConvertArray(damage, val1));
@@ -3931,6 +3932,33 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
owner->CastToClient()->QueuePacket(outapp, true, CLIENT_CONNECTED, filter);
}
}
#ifdef BOTS
else if (owner && owner->IsBot() && RuleB(Bots, DisplaySpellDamage)) {
if (((spell_id != SPELL_UNKNOWN) || (FromDamageShield)) && damage > 0) {
//special crap for spell damage, looks hackish to me
char val1[20] = { 0 };
owner->CastToBot()->GetBotOwner()->CastToClient()->MessageString(Chat::NonMelee, OTHER_HIT_NONMELEE, attacker->GetCleanName(), ConvertArray(damage, val1));
}
else {
if (damage > 0) {
if (spell_id != SPELL_UNKNOWN)
filter = iBuffTic ? FilterDOT : FilterSpellDamage;
else
filter = FilterPetHits;
}
else if (damage == -5)
filter = FilterNone; //cant filter invulnerable
else
filter = FilterPetMisses;
if (!FromDamageShield)
owner->CastToBot()->GetBotOwner()->CastToClient()->QueuePacket(outapp, true, CLIENT_CONNECTED, filter);
}
}
#endif
skip = owner;
}
else {
@@ -3969,8 +3997,10 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
filter = FilterNone; //cant filter invulnerable
else
filter = FilterMyMisses;
//set to filter duplicate message to the client if client uses #damage to themselves
//if (!attacker->IsClient() && attacker->CastToClient()->GetID() != attacker->GetTarget()->GetID()) {
attacker->CastToClient()->QueuePacket(outapp, true, CLIENT_CONNECTED, filter);
//}
}
}
skip = attacker;
@@ -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
// we don't send them here.
if (!FromDamageShield) {
#ifdef BOTS
// If a bot is the attacker, send a damage message ot the Bot Owner
if (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(
this, /* Sender */
outapp, /* packet */
@@ -4001,10 +4044,10 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
skip, /* Skip this mob */
true, /* Packet ACK */
filter /* eqFilterType filter */
);
);
//send the damage to ourself if we are a client
if (IsClient()) {
if (IsClient() && this != attacker) { //need to add a filter to remove duplicate display for #damage to self
//I dont think any filters apply to damage affecting us
CastToClient()->QueuePacket(outapp);
}
@@ -4034,11 +4077,25 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
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)
{
int32 maxhp = GetMaxHP();
int32 curhp = GetHP();
@@ -4053,15 +4110,16 @@ void Mob::HealDamage(uint32 amount, Mob *caster, uint16 spell_id)
if (caster) {
if (IsBuffSpell(spell_id)) { // hots
// message to caster
if (caster->IsClient() && caster == this) {
if (caster->CastToClient()->ClientVersionBit() & EQ::versions::maskSoFAndLater)
if ((caster->IsClient() && caster == this)) {
if (caster->CastToClient()->ClientVersionBit() & EQ::versions::maskSoFAndLater) {
FilteredMessageString(caster, Chat::NonMelee, FilterHealOverTime,
HOT_HEAL_SELF, itoa(acthealed), spells[spell_id].name);
}
else
FilteredMessageString(caster, Chat::NonMelee, FilterHealOverTime,
YOU_HEALED, GetCleanName(), itoa(acthealed));
}
else if (caster->IsClient() && caster != this) {
else if ((caster->IsClient() && caster != this)) {
if (caster->CastToClient()->ClientVersionBit() & EQ::versions::maskSoFAndLater)
caster->FilteredMessageString(caster, Chat::NonMelee, FilterHealOverTime,
HOT_HEAL_OTHER, GetCleanName(), itoa(acthealed),
@@ -4070,8 +4128,35 @@ void Mob::HealDamage(uint32 amount, Mob *caster, uint16 spell_id)
caster->FilteredMessageString(caster, Chat::NonMelee, FilterHealOverTime,
YOU_HEAL, GetCleanName(), itoa(acthealed));
}
#ifdef BOTS
if (caster->IsBot() && this != caster->CastToBot()->GetBotOwner() && RuleB(Bots, DisplayHealDamage)) {
// %1 healed %2 for %3 hit points from %4's %5
const char s2[]{ " healed " };
const char s4[]{ " for " };
const char s6[]{ " hit points from " };
const char s8[]{ "'s " };
caster->CastToBot()->GetBotOwner()->FilteredMessageString(
caster->CastToBot()->GetBotOwner(), //send to the Bot Owner's client
Chat::NonMelee,
FilterHealOverTime,
GENERIC_9_STRINGS, //using generic for testing purposes %1 %2 %3 %4 %5 %6 %7 %8 %9
caster->GetCleanName(), // %1 caster (bot's) name
s2, // %2
this->GetCleanName(), // %3 caster (bot's) target
s4, // %4
itoa(acthealed), // %5 amount healed
s6, // %6
caster->GetCleanName(), // %7 caster (bot's) name
s8, // %8
spells[spell_id].name // %9 spell name
);
}
#endif // BOTS
// message to target
if (IsClient() && caster != this) {
if ((IsClient() && caster != this)) {
if (CastToClient()->ClientVersionBit() & EQ::versions::maskSoFAndLater)
FilteredMessageString(this, Chat::NonMelee, FilterHealOverTime,
HOT_HEALED_OTHER, caster->GetCleanName(),
@@ -4084,25 +4169,41 @@ void Mob::HealDamage(uint32 amount, Mob *caster, uint16 spell_id)
else { // normal heals
FilteredMessageString(caster, Chat::NonMelee, FilterSpellDamage,
YOU_HEALED, caster->GetCleanName(), itoa(acthealed));
#ifndef BOTS
if (caster != this)
caster->FilteredMessageString(caster, Chat::NonMelee, FilterSpellDamage,
YOU_HEAL, GetCleanName(), itoa(acthealed));
}
}
else {
Message(Chat::NonMelee, "You have been healed for %d points of damage.", acthealed);
}
}
#endif
#ifdef BOTS
if (caster->IsBot() && RuleB(Bots, DisplayHealDamage)) {
caster->CastToBot()->GetBotOwner()->FilteredMessageString(caster->CastToBot()->GetBotOwner(),
Chat::NonMelee, FilterSpellDamage, GENERIC_9_STRINGS,
caster->GetCleanName(), " healed ", this->GetCleanName(), " for ", itoa(acthealed), " hit points.", " ", " ", " ");
}
else if (caster != this) {
caster->FilteredMessageString(caster, Chat::NonMelee, FilterSpellDamage,
YOU_HEAL, GetCleanName(), itoa(acthealed));
if (curhp < maxhp) {
if ((curhp + amount) > maxhp)
curhp = maxhp;
else
curhp += amount;
SetHP(curhp);
}
}
#endif // BOTS
SendHPUpdate();
}
else {
Message(Chat::NonMelee, "You have been healed for %d points of damage.", acthealed);
}
}
if (curhp < maxhp) {
if ((curhp + amount) > maxhp)
curhp = maxhp;
else
curhp += amount;
SetHP(curhp);
SendHPUpdate();
}
}
//proc chance includes proc bonus
+770 -18
View File
@@ -20,6 +20,7 @@
#include "bot.h"
#include "object.h"
#include "raids.h"
#include "doors.h"
#include "quest_parser_collection.h"
#include "lua_parser.h"
@@ -27,6 +28,7 @@
#include "../common/say_link.h"
extern volatile bool is_zone_loaded;
extern bool Critical;
// This constructor is used during the bot create command
Bot::Bot(NPCType *npcTypeData, Client* botOwner) : NPC(npcTypeData, nullptr, glm::vec4(), Ground, false), rest_timer(1), ping_timer(1) {
@@ -2123,7 +2125,11 @@ bool Bot::Process()
}
// Bot AI
AI_Process();
Raid* bot_raid = entity_list.GetRaidByBotName(this->GetName());
if (bot_raid)
AI_Process_Raid();
else
AI_Process();
return true;
}
@@ -2362,11 +2368,11 @@ void Bot::AI_Process()
Client* bot_owner = (GetBotOwner() && GetBotOwner()->IsClient() ? GetBotOwner()->CastToClient() : nullptr);
Group* bot_group = GetGroup();
//#pragma region PRIMARY AI SKIP CHECKS
// Primary reasons for not processing AI
if (!bot_owner || !bot_group || !IsAIControlled()) {
if (!bot_owner || (!bot_group) || !IsAIControlled()) {
return;
}
@@ -2379,7 +2385,12 @@ void Bot::AI_Process()
}
// We also need a leash owner and follow mob (subset of primary AI criteria)
Client* leash_owner = (bot_group->GetLeader() && bot_group->GetLeader()->IsClient() ? bot_group->GetLeader()->CastToClient() : bot_owner);
Client* leash_owner = nullptr;
if (bot_group) {
leash_owner = (bot_group->GetLeader() && bot_group->GetLeader()->IsClient() ? bot_group->GetLeader()->CastToClient() : bot_owner);
}
if (!leash_owner) {
return;
}
@@ -3810,7 +3821,7 @@ void Bot::Depop() {
entity_list.RemoveFromHateLists(this);
if(HasGroup())
Bot::RemoveBotFromGroup(this, GetGroup());
if(HasPet())
GetPet()->Depop();
@@ -3865,7 +3876,13 @@ bool Bot::Spawn(Client* botCharacterOwner) {
this->SendWearChange(materialFromSlot);
}
}
Raid* raid = entity_list.GetRaidByBotName(this->GetName());
if (raid)
{
raid->VerifyRaid();
this->SetRaidGrouped(true);
}
return true;
}
@@ -4727,7 +4744,24 @@ bool Bot::Death(Mob *killerMob, int32 damage, uint16 spell_id, EQ::skills::Skill
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());
// }
return true;
}
@@ -6692,7 +6726,7 @@ int32 Bot::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
if (spells[spell_id].target_type == ST_Self)
return value;
bool Critical = false;
Critical = false;
int32 value_BaseEffect = 0;
value_BaseEffect = (value + (value*GetBotFocusEffect(focusFcBaseEffects, spell_id) / 100));
// Need to scale HT damage differently after level 40! It no longer scales by the constant value in the spell file. It scales differently, instead of 10 more damage per level, it does 30 more damage per level. So we multiply the level minus 40 times 20 if they are over level 40.
@@ -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)
value += (GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value) * ratio / 100);
entity_list.MessageClose(this, false, 100, Chat::SpellCrit, "%s delivers a critical blast! (%d)", GetName(), -value);
//Mitch
//if (!RuleB(Bots, DisplaySpellDamage))
entity_list.MessageClose(this, false, 100, Chat::SpellCrit, "%s\'s %s delivers a critical blast to %s! (%d)", GetName(), spells[spell_id].name, target->GetCleanName(), -value);
return value;
}
@@ -6769,7 +6804,7 @@ int32 Bot::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
int32 value_BaseEffect = 0;
int32 chance = 0;
int8 modifier = 1;
bool Critical = false;
Critical = false; //mitch
value_BaseEffect = (value + (value*GetBotFocusEffect(focusFcBaseEffects, spell_id) / 100));
value = value_BaseEffect;
value += int(value_BaseEffect*GetBotFocusEffect(focusImprovedHeal, spell_id) / 100);
@@ -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 isMainGroupMGB = false;
Raid* raid = entity_list.GetRaidByBotName(this->GetName());
if(isMainGroupMGB && (GetClass() != BARD)) {
BotGroupSay(this, "MGB %s", spells[spell_id].name);
SpellOnTarget(spell_id, this);
entity_list.AESpell(this, this, spell_id, true);
} else {
}
else if (raid)
{
//for (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();
if(g) {
for(int i = 0; i < MAX_GROUP_MEMBERS; ++i) {
@@ -8084,6 +8135,16 @@ void Bot::Camp(bool databaseSave) {
//auto group = GetGroup();
if(GetGroup())
RemoveBotFromGroup(this, GetGroup());
//Mitch
Raid* bot_raid = entity_list.GetRaidByBotName(this->GetName());
if (bot_raid) {
uint32 gid = bot_raid->GetGroup(this->GetName());
bot_raid->SendRaidGroupRemove(this->GetName(), bot_raid->GetGroup(this->GetName()));
bot_raid->RemoveMember(this->GetName());
bot_raid->GroupUpdate(gid);
}
// RemoveBotFromGroup() code is too complicated for this to work as-is (still needs to be addressed to prevent memory leaks)
//if (group->GroupCount() < 2)
@@ -8098,9 +8159,14 @@ void Bot::Camp(bool databaseSave) {
}
void Bot::Zone() {
if(HasGroup())
Raid* raid = entity_list.GetRaidByBotName(this->GetName());
if (raid) {
raid->MemberZoned(this->CastToClient());
}
else if (HasGroup()) {
GetGroup()->MemberZoned(this);
}
Save();
Depop();
}
@@ -8304,8 +8370,9 @@ Bot* Bot::GetBotByBotClientOwnerAndBotName(Client* c, std::string botName) {
void Bot::ProcessBotGroupInvite(Client* c, std::string botName) {
if(c) {
// Bot* invitedBot = GetBotByBotClientOwnerAndBotName(entity_list.GetBotByBotName(botName)->GetOwner()->CastToClient(), botName);
Bot* invitedBot = GetBotByBotClientOwnerAndBotName(c, botName);
//Mitch changed entity from c
if(invitedBot && !invitedBot->HasGroup()) {
if(!c->IsGrouped()) {
Group *g = new Group(c);
@@ -8349,7 +8416,11 @@ void Bot::ProcessClientZoneChange(Client* botOwner) {
Bot* tempBot = *itr;
if(tempBot) {
if(tempBot->HasGroup()) {
Raid* raid = entity_list.GetRaidByBotName(tempBot->GetName());
if (raid) {
tempBot->Zone();
}
else if(tempBot->HasGroup()) {
Group* g = tempBot->GetGroup();
if(g && g->IsGroupMember(botOwner)) {
if(botOwner && botOwner->IsClient()) {
@@ -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(caster->HasGroup()) {
Group *g = caster->GetGroup();
if(caster->HasGroup() || caster->IsRaidGrouped()) {
float hpRatioToHeal = 25.0f;
switch(caster->GetBotStance()) {
case EQ::constants::stanceReactive:
@@ -8921,6 +9032,11 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl
hpRatioToHeal = 25.0f;
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) {
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
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()) {
Group *g = caster->GetGroup();
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) {
@@ -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 (botCasterClass == BARD || caster->IsEngaged())
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();
if (g) {
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 };
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
+17 -2
View File
@@ -35,6 +35,7 @@
#include "../common/global_define.h"
#include "guild_mgr.h"
#include "worldserver.h"
#include "raids.h"
#include <sstream>
@@ -151,8 +152,8 @@ public:
ExtraAttackOptions *opts = nullptr);
virtual bool HasRaid() { return (GetRaid() ? true : false); }
virtual bool HasGroup() { return (GetGroup() ? true : false); }
virtual Raid* GetRaid() { return entity_list.GetRaidByMob(this); }
virtual Group* GetGroup() { return entity_list.GetGroupByMob(this); }
virtual Raid* GetRaid() { return entity_list.GetRaidByMob(this); } // GetRaidByMob(this);
virtual Group* GetGroup() { return entity_list.GetGroupByMob(this); } // GetGroupByMob;
// Common, but informal "interfaces" with Client object
uint32 CharacterID() { return GetBotID(); } // Just returns the Bot Id
@@ -377,6 +378,15 @@ public:
static bool CheckDisciplineRecastTimers(Bot *caster, int timer_index);
static uint32 GetDisciplineRemainingTime(Bot *caster, int timer_index);
//Raid methods
void PetAIProcess_Raid();
void AI_Process_Raid();
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> GetBotSpellsForSpellEffectAndTargetType(Bot* botCaster, int spellEffect, SpellTargetType targetType);
static std::list<BotSpell> GetBotSpellsBySpellType(Bot* botCaster, uint32 spellType);
@@ -597,6 +607,9 @@ public:
int32 GetBaseDR() { return _baseDR; }
int32 GetBaseCorrup() { return _baseCorrup; }
//Raid additions
Raid* p_raid_instance;
protected:
virtual void PetAIProcess();
virtual void BotMeditate(bool isSitting);
@@ -661,6 +674,7 @@ private:
Timer m_auto_defend_timer;
//Timer m_combat_jitter_timer;
//bool m_combat_jitter_flag;
bool m_dirtyautohaters;
bool m_guard_flag;
bool m_hold_flag;
bool m_attack_flag;
@@ -727,6 +741,7 @@ private:
public:
static uint8 spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND];
};
#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)
return false;
//modified query for usecase of a BOTID sharing a CHARACTERID.
//in this usecase, when the BOTID=CHARACTERID of BOT OWNER, this BOTID would be added to the GROUP
query = StringFormat(
"SELECT `charid`"
" FROM `group_id`"
" WHERE `groupid` = '%u'"
" AND `charid` IN ("
" SELECT `bot_id`"
" FROM `bot_data`"
" WHERE `owner_id` = '%u'"
" )",
"SELECT `mob_id` FROM `vw_groups` "
"WHERE `group_id` = '%u' "
"AND `mob_type`='B' "
"AND `mob_id` IN (SELECT `bot_id` FROM `bot_data` WHERE `owner_id` = '%u');"
, group_id, owner_id);
/*query = StringFormat(
"SELECT `charid` FROM `group_id` WHERE `groupid` = '%u'"
" AND `charid` IN (SELECT `bot_id` FROM `bot_data` WHERE `owner_id` = '%u')"
" AND `group_id.name` NOT IN (SELECT `name` FROM `character_data`)",
group_id,
owner_id
);
owner_id);*/
auto results = database.QueryDatabase(query);
if (!results.Success())
+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
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
the Free Software Foundation; version 2 ogroupf the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
@@ -31,6 +31,13 @@
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) {
return false;
}
+5 -4
View File
@@ -804,9 +804,10 @@ void Client::QueuePacket(const EQApplicationPacket* app, bool ack_req, CLIENT_CO
// todo: save packets for later use
AddPacket(app, ack_req);
}
else
if(eqs)
eqs->QueuePacket(app, ack_req);
else if (eqs) // && !IsBot()) //Mitch added the BoTcheck for a fail safe on trying to send a packet to a BoT!
{
eqs->QueuePacket(app, ack_req);
}
}
void Client::FastQueuePacket(EQApplicationPacket** app, bool ack_req, CLIENT_CONN_STATUS required_state) {
@@ -817,7 +818,7 @@ void Client::FastQueuePacket(EQApplicationPacket** app, bool ack_req, CLIENT_CON
return;
}
else {
if(eqs)
if(eqs) // && !IsBot()) //Mitch added
eqs->FastQueuePacket((EQApplicationPacket **)app, ack_req);
else if (app && (*app))
delete *app;
+694 -486
View File
File diff suppressed because it is too large Load Diff
+3
View File
@@ -31,6 +31,8 @@
#include "zone_store.h"
#include "position.h"
extern bool Critical; //Mitch
float Mob::GetActSpellRange(uint16 spell_id, float range, bool IsBard)
{
float extrange = 100;
@@ -316,6 +318,7 @@ int32 Mob::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
value += value * CastToNPC()->GetSpellFocusHeal() / 100;
}
Critical = false;
int32 base_value = value;
int16 critical_chance = 0;
int8 critical_modifier = 1;
+45 -3
View File
@@ -2088,17 +2088,17 @@ Raid *EntityList::GetRaidByID(uint32 id)
return nullptr;
}
Raid *EntityList::GetRaidByClient(Client* client)
Raid* EntityList::GetRaidByClient(Client* client)
{
if (client->p_raid_instance) {
return client->p_raid_instance;
}
std::list<Raid *>::iterator iterator;
std::list<Raid*>::iterator iterator;
iterator = raid_list.begin();
while (iterator != raid_list.end()) {
for (auto &member : (*iterator)->members) {
for (auto& member : (*iterator)->members) {
if (member.member) {
if (member.member == client) {
client->p_raid_instance = *iterator;
@@ -2113,6 +2113,48 @@ Raid *EntityList::GetRaidByClient(Client* client)
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)
{
std::list<Raid *>::iterator iterator;
+4
View File
@@ -198,6 +198,10 @@ public:
Raid *GetRaidByClient(Client* client);
Raid *GetRaidByID(uint32 id);
Raid *GetRaidByLeaderName(const char *leader);
#ifdef BOTS
Raid* GetRaidByBotName(const char* name);
Raid* GetRaidByBot(Bot* bot);
#endif
Corpse *GetCorpseByOwner(Client* client);
Corpse *GetCorpseByOwnerWithinRange(Client* client, Mob* center, int range);
+1 -1
View File
@@ -1097,7 +1097,7 @@ void Raid::SplitExp(uint32 exp, Mob* other) {
return;
for (unsigned int x = 0; x < MAX_RAID_MEMBERS; x++) {
if (members[x].member != nullptr) // If Group Member is Client
if (members[x].member != nullptr && members[x].member->CastToBot()->GetBotID() == 0) // If Group Member is Client
{
Client *cmember = members[x].member;
// add exp + exp cap
+60 -3
View File
@@ -248,10 +248,24 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte
uint32 i = 0;
for (i = 0; i < MAX_GROUP_MEMBERS; ++i)
{
if(!strcasecmp(membername[i], NewMemberName))
#ifdef BOTSS
if (newmember->IsBot() && !newmember->HasGroup() && !strcasecmp(membername[i], NewMemberName)) // Mitch
{
//Bot::RemoveBotFromGroup(newmember->CastToBot(), members[0]->GetGroup());
//Group::DelMember(newmember);
memset(membername[i], 0, 64);
members[i] = nullptr;
}
else if (!strcasecmp(membername[i], NewMemberName))
{
return false;
}
#else
if (!strcasecmp(membername[i], NewMemberName))
{
return false;
}
#endif
}
// Put them in the group
@@ -1140,7 +1154,13 @@ void Group::TeleportGroup(Mob* sender, uint32 zoneID, uint16 instance_id, float
}
bool Group::LearnMembers() {
std::string query = StringFormat("SELECT name FROM group_id WHERE groupid = %lu", (unsigned long)GetID());
//std::string query = StringFormat("SELECT name FROM group_id WHERE groupid = %lu", (unsigned long)GetID());
std::string query = StringFormat("SELECT name FROM group_id "
"WHERE group_id.groupid = %lu AND group_id.name NOT "
"IN(SELECT group_leaders.leadername FROM group_leaders WHERE gid = %lu)"
, (unsigned long)GetID()
, (unsigned long)GetID());
auto results = database.QueryDatabase(query);
if (!results.Success())
return false;
@@ -1155,7 +1175,7 @@ bool Group::LearnMembers() {
return false;
}
int memberIndex = 0;
int memberIndex = 1; //starts at 1 becasuse leader [0] is done specifically
for(auto row = results.begin(); row != results.end(); ++row) {
if(!row[0])
continue;
@@ -1165,7 +1185,24 @@ bool Group::LearnMembers() {
memberIndex++;
}
// for leader only [0] /Mitch
query = StringFormat("SELECT leadername FROM group_leaders WHERE group_leaders.gid = %lu", (unsigned long)GetID());
auto results2 = database.QueryDatabase(query);
if (!results2.Success())
return false;
if (results2.RowCount() == 0) {
LogError(
"Error getting group leader for group [{}]: [{}]",
(unsigned long)GetID(),
results2.ErrorMessage().c_str()
);
return false;
}
auto row2 = results2.begin();
members[0] = nullptr;
strn0cpy(membername[0], row2[0], 64);
return true;
}
@@ -1176,6 +1213,22 @@ void Group::VerifyGroup() {
Only called every once in a while (on member re-join for now).
*/
// To do
// Reset the membername array to match the group_id database records?
// When doing this manually, it seem to have resolved the issue.
// Only want to do this when the database Name does not match the array
// Could this be done from the LearnGroup method?
// reset the members and membername array for this group
// Mitch
for (int i = 0; i < MAX_GROUP_MEMBERS; i++) {
members[i] = nullptr;
memset(membername[i],'\0',64);
//membername[i][0] == '\0');
}
// repopulate the membername array from the database to ensure the local zone instance has accurate information
Group::LearnMembers();
uint32 i;
for (i = 0; i < MAX_GROUP_MEMBERS; i++) {
if (membername[i][0] == '\0') {
@@ -1195,6 +1248,10 @@ void Group::VerifyGroup() {
members[i] = nullptr;
continue;
}
//if (them == nullptr && members[i] == nullptr) { //fixes a group bug with bots Mitch added Jan 1 2022
// membername[i][0] = '\0';
// continue;
//}
if(them != nullptr && members[i] != them) { //our pointer is out of date... not so good.
#if EQDEBUG >= 5
+1
View File
@@ -88,6 +88,7 @@ volatile bool RunLoops = true;
#endif
extern volatile bool is_zone_loaded;
extern bool Critical = false;
EntityList entity_list;
WorldServer worldserver;
+1 -1
View File
@@ -3855,7 +3855,7 @@ void Mob::QuestJournalledSay(Client *QuestInitiator, const char *str, Journal::O
const char *Mob::GetCleanName()
{
if (!strlen(clean_name)) {
if (clean_name != NULL && !strlen(clean_name)) { //extra check added for crash condition. Mitch
CleanMobName(GetName(), clean_name);
}
+199 -20
View File
@@ -24,6 +24,7 @@
#include "groups.h"
#include "mob.h"
#include "raids.h"
#include "bot.h" //Mitch
#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, "
"groupid = %lu, _class = %d, level = %d, name = '%s', "
"isgroupleader = %d, israidleader = %d, islooter = %d",
"isgroupleader = %d, israidleader = %d, islooter = %d, isbot = 0",
(unsigned long)GetID(), (unsigned long)c->CharacterID(),
(unsigned long)group, c->GetClass(), c->GetLevel(),
c->GetName(), groupleader, rleader, looter);
@@ -109,6 +110,14 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo
LearnMembers();
VerifyRaid();
#ifdef BOTS
if (rleader) {
database.SetRaidGroupLeaderInfo(group, GetID());
UpdateRaidAAs();
}
else
#endif
if (rleader) {
database.SetRaidGroupLeaderInfo(RAID_GROUPLESS, GetID());
UpdateRaidAAs();
@@ -162,6 +171,86 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo
worldserver.SendPacket(pack);
safe_delete(pack);
}
//Mitch
void Raid::AddBot(Bot* b, uint32 group, bool rleader, bool groupleader, bool looter) {
if (!b)
return;
std::string query = StringFormat("INSERT INTO raid_members SET raidid = %lu, charid = %lu, "
"groupid = %lu, _class = %d, level = %d, name = '%s', "
"isgroupleader = %d, israidleader = %d, islooter = %d, 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)
{
@@ -169,6 +258,17 @@ void Raid::RemoveMember(const char *characterName)
auto results = database.QueryDatabase(query);
Client *client = entity_list.GetClientByName(characterName);
#ifdef BOTS
Bot* bot = entity_list.GetBotByBotName(characterName);
if (bot) {
bot->SetFollowID(bot->GetOwner()->CastToClient()->GetID());
bot->SetGrouped(false);
bot->SetTarget(nullptr);
bot->SetRaidGrouped(false);
}
#endif
disbandCheck = true;
SendRaidRemoveAll(characterName);
SendRaidDisband(client);
@@ -963,7 +1063,7 @@ void Raid::SendRaidAdd(const char *who, Client *to)
for(int x = 0; x < MAX_RAID_MEMBERS; x++)
{
if(strcmp(members[x].membername, who) == 0)
if(strcmp(members[x].membername, who) == 0)// || !members[x].SentToBotOwner) //Mitch
{
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidAddMember_Struct));
RaidAddMember_Struct *ram = (RaidAddMember_Struct*)outapp->pBuffer;
@@ -983,12 +1083,12 @@ void Raid::SendRaidAdd(const char *who, Client *to)
void Raid::SendRaidAddAll(const char *who)
{
for(int x = 0; x < MAX_RAID_MEMBERS; x++)
for (int x = 0; x < MAX_RAID_MEMBERS; x++)
{
if(strcmp(members[x].membername, who) == 0)
if (strcmp(members[x].membername, who) == 0 )
{
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidAddMember_Struct));
RaidAddMember_Struct *ram = (RaidAddMember_Struct*)outapp->pBuffer;
RaidAddMember_Struct* ram = (RaidAddMember_Struct*)outapp->pBuffer;
ram->raidGen.action = raidAdd;
ram->raidGen.parameter = members[x].GroupNumber;
strcpy(ram->raidGen.leader_name, members[x].membername);
@@ -999,6 +1099,7 @@ void Raid::SendRaidAddAll(const char *who)
this->QueuePacket(outapp);
safe_delete(outapp);
return;
}
}
}
@@ -1111,11 +1212,14 @@ void Raid::SendBulkRaid(Client *to)
if(!to)
return;
if (members[GetPlayerIndex(to)].IsBot)
return;
for(int x = 0; x < MAX_RAID_MEMBERS; x++)
{
if(strlen(members[x].membername) > 0 && (strcmp(members[x].membername, to->GetName()) != 0)) //don't send ourself
if(members[x].member && strlen(members[x].membername) > 0 && (strcmp(members[x].membername, to->GetName()) != 0)) //don't send ourself
{
SendRaidAdd(members[x].membername, to);
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++)
{
if(members[x].member)
if(members[x].member && !members[x].IsBot)
{
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
{
//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));
RaidLeadershipUpdate_Struct *rg = (RaidLeadershipUpdate_Struct*)outapp->pBuffer;
rg->action = raidMakeLeader;
@@ -1148,6 +1257,9 @@ void Raid::SendMakeLeaderPacketTo(const char *who, Client *to)
if(!to)
return;
if (members[GetPlayerIndex(who)].IsBot)
return;
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct));
RaidLeadershipUpdate_Struct *rg = (RaidLeadershipUpdate_Struct*)outapp->pBuffer;
rg->action = raidMakeLeader;
@@ -1178,6 +1290,9 @@ void Raid::SendGroupUpdate(Client *to)
if(!to)
return;
if (members[GetPlayerIndex(to)].IsBot)
return;
auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupUpdate2_Struct));
GroupUpdate2_Struct* gu = (GroupUpdate2_Struct*)outapp->pBuffer;
gu->action = groupActUpdate;
@@ -1224,7 +1339,7 @@ void Raid::GroupUpdate(uint32 gid, bool initial)
{
if(strlen(members[x].membername) > 0){
if(members[x].GroupNumber == gid){
if(members[x].member) {
if (members[x].member) {
SendGroupUpdate(members[x].member);
SendGroupLeadershipAA(members[x].member, gid);
}
@@ -1366,6 +1481,9 @@ void Raid::SendRaidMOTDToWorld()
void Raid::SendGroupLeadershipAA(Client *c, uint32 gid)
{
if (members[GetPlayerIndex(c)].IsBot)
return;
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct));
RaidLeadershipUpdate_Struct *rlaa = (RaidLeadershipUpdate_Struct *)outapp->pBuffer;
rlaa->action = raidSetLeaderAbilities;
@@ -1381,17 +1499,46 @@ void Raid::SendGroupLeadershipAA(Client *c, uint32 gid)
void Raid::SendGroupLeadershipAA(uint32 gid)
{
for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++)
if (members[i].member && members[i].GroupNumber == gid)
if (members[i].member && members[i].GroupNumber == gid && !members[i].IsBot)
SendGroupLeadershipAA(members[i].member, gid);
}
void Raid::SendAllRaidLeadershipAA()
{
for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++)
if (members[i].member)
if (members[i].member && !members[i].IsBot)
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)
{
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));
std::string query = StringFormat("SELECT name, groupid, _class, level, "
"isgroupleader, israidleader, islooter "
"isgroupleader, israidleader, islooter, isbot "
"FROM raid_members WHERE raidid = %lu",
(unsigned long)GetID());
auto results = database.QueryDatabase(query);
@@ -1489,6 +1636,7 @@ bool Raid::LearnMembers()
members[index].IsGroupLeader = atoi(row[4]);
members[index].IsRaidLeader = atoi(row[5]);
members[index].IsLooter = atoi(row[6]);
members[index].IsBot = atoi(row[7]); //Mitch
++index;
}
@@ -1504,14 +1652,25 @@ void Raid::VerifyRaid()
}
else{
Client *c = entity_list.GetClientByName(members[x].membername);
#ifdef BOTS
Bot* b = entity_list.GetBotByBotName(members[x].membername); //Mitch
#endif
if(c){
members[x].member = c;
members[x].IsBot = false;
}
else{
#ifdef BOTS
else if(b){
members[x].member = b->CastToClient(); //Raid requires client* we are forcing it here to be a BOT
members[x].IsBot = true; //Used to identify those members who are Bots
}
#endif
else {
members[x].member = nullptr;
members[x].IsBot = false;
}
}
if(members[x].IsRaidLeader){
if(members[x].IsRaidLeader){
if(strlen(members[x].membername) > 0){
SetLeader(members[x].member);
strn0cpy(leadername, members[x].membername, 64);
@@ -1561,7 +1720,7 @@ void Raid::SendHPManaEndPacketsTo(Client *client)
EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct));
for(int x = 0; x < MAX_RAID_MEMBERS; x++) {
if(members[x].member) {
if(members[x].member && !members[x].IsBot) {
if((members[x].member != client) && (members[x].GroupNumber == group_id)) {
members[x].member->CreateHPPacket(&hp_packet);
@@ -1603,7 +1762,7 @@ void Raid::SendHPManaEndPacketsFrom(Mob *mob)
mob->CreateHPPacket(&hpapp);
for(int x = 0; x < MAX_RAID_MEMBERS; x++) {
if(members[x].member) {
if(members[x].member && !members[x].IsBot) {
if(!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) {
members[x].member->QueuePacket(&hpapp, false);
if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) {
@@ -1636,7 +1795,7 @@ void Raid::SendManaPacketFrom(Mob *mob)
EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct));
for (int x = 0; x < MAX_RAID_MEMBERS; x++) {
if (members[x].member) {
if (members[x].member && !members[x].IsBot) {
if (!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) {
if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) {
outapp.SetOpcode(OP_MobManaUpdate);
@@ -1663,7 +1822,7 @@ void Raid::SendEndurancePacketFrom(Mob *mob)
EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct));
for (int x = 0; x < MAX_RAID_MEMBERS; x++) {
if (members[x].member) {
if (members[x].member && !members[x].IsBot) {
if (!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) {
if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) {
outapp.SetOpcode(OP_MobEnduranceUpdate);
@@ -1770,9 +1929,14 @@ void Raid::CheckGroupMentor(uint32 group_id, Client *c)
void Raid::SetDirtyAutoHaters()
{
for (int i = 0; i < MAX_RAID_MEMBERS; ++i)
if (members[i].member)
if (members[i].member && members[i].IsBot)
{
members[i].member->CastToBot()->SetDirtyAutoHaters();
}
else if (members[i].member && !members[i].IsBot)
{
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*/) {
@@ -1791,6 +1955,9 @@ void Raid::QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_re
if (!members[i].member->IsClient())
continue;
if (members[i].IsBot)
continue;
if (ignore_sender && members[i].member == sender)
continue;
@@ -1853,3 +2020,15 @@ bool Raid::DoesAnyMemberHaveExpeditionLockout(
return Expedition::HasLockoutByCharacterName(raid_member.membername, expedition_name, event_name);
});
}
Mob* Raid::GetRaidMainAssistOneByName(const char* name)
{
Raid* raid = entity_list.GetRaidByBotName(name);
std::vector<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 IsRaidLeader;
bool IsLooter;
#ifdef BOTS
bool IsBot = false;
bool IsGroupHealer;
bool IsRaidSlower;
bool IsRaidMainAssistOne;
bool IsRaidMainAssistTwo;
bool IsRaidMainTank;
bool IsRaidOffTankOne;
bool IsRaidOffTankTwo;
#endif
};
struct GroupMentor {
@@ -112,6 +122,12 @@ public:
bool IsRaid() { return true; }
void AddMember(Client *c, uint32 group = 0xFFFFFFFF, bool rleader=false, bool groupleader=false, bool looter=false);
#ifdef BOTS
void AddBot(Bot* b, uint32 group = 0xFFFFFFFF, bool rleader=false, bool groupleader=false, bool looter=false); //Mitch
void RaidBotGroupSay(Bot* b, uint8 language, uint8 lang_skill, const char* msg, ...); //Mitch
static Mob* GetRaidMainAssistOneByName(const char* name);
bool IsRaidMemberBot(Client* client);
#endif
void RemoveMember(const char *c);
void DisbandRaid();
void MoveMember(const char *name, uint32 newGroup);
@@ -121,6 +137,7 @@ public:
bool IsGroupLeader(const char *who);
bool IsRaidMember(const char *name);
void UpdateLevel(const char *name, int newLevel);
uint32 GetFreeGroup();
uint8 GroupCount(uint32 gid);
@@ -241,6 +258,7 @@ public:
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> GetRaidGroupMembers(uint32 gid);
RaidMember members[MAX_RAID_MEMBERS];
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);
}
else {
#ifndef BOTS
MessageString(Chat::SpellFailure, TARGET_RESISTED, spells[spell_id].name);
spelltar->MessageString(Chat::SpellFailure, YOU_RESIST, spells[spell_id].name);
#endif
#ifdef BOTS
if (this->IsBot() && IsHarmonySpell(spell_id)) {
if (IsGrouped() && this->GetGroup()->GetLeader()->IsClient()) {
Bot::BotGroupSay(this, "Your target RESISTED %s", spells[spell_id].name);
}
else {
this->CastToBot()->GetBotOwner()->MessageString(Chat::SpellFailure, TARGET_RESISTED, spells[spell_id].name);
}
}
else {
MessageString(Chat::SpellFailure, TARGET_RESISTED, spells[spell_id].name);
spelltar->MessageString(Chat::SpellFailure, YOU_RESIST, spells[spell_id].name);
}
#endif
}
if (spelltar->IsAIControlled()) {
@@ -3957,7 +3973,16 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, int reflect_effectivenes
return false;
}
}
#ifdef BOTS //Added to display when a HarmonySpell was successful from a bot
if (this->IsBot() && IsHarmonySpell(spell_id)) {
if (IsGrouped() && this->GetGroup()->GetLeader()->IsClient()) {
Bot::BotGroupSay(this, "Your spell was mostly successful.");
}
else {
this->CastToBot()->GetBotOwner()->MessageString(Chat::SpellFailure, SLOW_MOSTLY_SUCCESSFUL);
}
}
#endif
if (spelltar->IsClient()){
spelltar->CastToClient()->BreakSneakWhenCastOn(this, false);
spelltar->CastToClient()->BreakFeignDeathWhenCastOn(false);