mirror of
https://github.com/EQEmu/Server.git
synced 2026-06-09 22:20:24 +00:00
[Bots] Add Basic Bot Raiding Functionality (#2782)
* Fix for GENERIC_9_STRINGS
* Add Bot Heal Message Display
Creates a new rule to display Bot heal messages to the Bot Owner
* 2021-03-25 11L04pm
Spell and Heal Rule added to allow for Bot spell and heal damage to be sent to the Bot Owner's Group. Also added a check to remove duplicate message for #damage on self.
* Update .gitignore
* BOT work
Added BOT logging damage/heals to owner
Added BOT message to owner for harmony fails
Made var Critical global to remove duplicate crit messages
Added a NULL check to Mob:GetCleanname()
* Bot Group Work
Fixed botid=charid spawn on zone issue
Added a group_list update on zone to refresh from database to fix a dangling pointer to a Bot object that was camped but was previously in a group within the zone being entered.
Modified Bot::ProcessBotGroupInvite to use the client of the bot when doing the Bot initialization so that a leader can invite another owner's Bot
* Jan 4
Basic structure in place for Raid::AddBot though not working
* Basement Jan 5
* End of day Jan 5
Working Raid Invite to a Bot.
* Update to Client::QueuePacket to not attempt to send a packet to a BoT. Not clean, but a broad solution.
* Updated Raid::VerifyRaid
* Some Bot Raid working
* Before VS Crash
* Use Case 1, 2, 3,4,7 working.
Need to fix 5, 6, 8
* Work on usecase 5
* A few more use cases working
* New work on Raid invite with a invitor having a group
* Bot Raid inviting working for all use cases
* A few changes
* end of day jan 10
* Jan 11
* end of day Jan 11
* Bot Invite/Accept cleanup
* Start of moving raid bot functions to their own methods
* More bot raid changes
* More raid spell work
* end of day Jan 16
* spawn work
* Spawn on login working
* End of Day Jan 18
* Raid leader and mana/hp updates fixed
* Spell Tracking
* Issue with Bot Death in raid when casted upon. 1741 raid.cpp
* Bot Death fixed and few other crashes
* Working on botgroup removal
* Bot Disbanding Work 90%
* Looks like BOTs are working
* Fixed a bot crash
* bug tracing on entity list mismatch
* safe_delete resoves problem. No to track down leak
* seems to be working
* Memory corruption found - sending packets to BoTs using Client class
* added Raid::IsRaidMemberBot()
* Update p_raid_instance
* g3
* Final - Bot Raid Working
* Fixed IsRaidMemberBot to remove memory leak
Fixed altcombat crash though RaidMainAssist (428) needs fixing
* add RaidMember.IsBot
* Repaired IsBot function to be more preformant. Now works on standard performance machine
* Fixed Bard AE Target Spells
Removed assert for buffs
* updated based on Feb 2022 master updates
* Added bot_db_updates and version increment
* Cleanup of bot raid work and inclusion of bot_raid in cmake
* Delete .gitignore
* Revert "Delete .gitignore"
This reverts commit 8523658d3b.
* Fixed a packet issue
* Merged upstream/master
Merged upstream/master and removed ifdef BOTS as per recent dev approach for BOTS. Functionality is there, compiles and tests ok. A few problems to be resolved though this is a good baseline.
* Added sql update for raid_members to add isbot
* Updated Bot Follow Function
Bot will now follow the Group Leader if IsClient, otherwise follows the Bot Owner
* Updates to Bot Raid System
When camping a client, remove them from the raid. If they are leader, place leadership to the next client.
Update a few crash checks in bot_raid.cpp
* [BOTS] Added RuleB Enabled checks and updated base repo for raid_members
Updated several RuleB(Bots, Enabled) checks
Updated the base repo to be autogenerated.
Raid functionality should work with a non-bots enabled database.
* Few quick updates
* Updates
Corrected a number of comments. Compiled and tested against bot and non-bot database though requires the isbot column in raid_members for both.
Moved the db update out of the bot stream to make bot check code easier.
* Formatting and other small updates
* A few more RuleB(Bots, Enabled) additions
* Fix issue with conflict of bot ID versus character ID.
* Delete CMakeSettings.json
* Comment Updates and other
Several updates including
- fixed comments from PR
- added id to raid_members and unique index on name to avoid botid and charid conflicts
- updated a few raid functions for iterators
- reordered several raid operations to ensure send leader packet to be the last item to ensure proper updating on the client
- update sql to use Replace instead of Insert for botid conflicting with charid
* Exploit fix for Raid Bots
Added item from @Nite to disallow spawning or camping bots if Raid is engaged. Avoids abusive situations.
* Initial Commit
* fix Raid Window after zoning
The raid window was not fully updating for clients not in the zone.
* Cleanup
* Update
Fixed comments
* Resolve crash for MOTD
Fixed a crash situation sending a raid MOTD to BOTS.
* Update ruletypes.h
* Updated to resolve a few recent comments
Fixed some comments within attack.cpp
* fix sql query
* update repository
* prevent duplicate entries in raid after group invite, and cleanup
* fixes for botgroups not following, and add already in raid messages.
* fix messagestring
* fixes
* Cleanup, and resolving issues with disbanding
* refactoring
* more cleanup/fixing.
* fixes for removing from ground in raid
* Refactoring/fixing multiple clients
* fix for compiling
* Bugs from refactoring fixed
* Testing completed, cleaning up unwanted items/duplicate code.
* Cleaned up AICastSpell
* fix typos
* Refactoring
* Adding Raid checks to AI_Process/cleanup
* Fix a typo
Was getting a SQL error on BOT spawn. Fixed typo.
* fix for crash
* Fixed crash when inviting player, more refactoring
* AI_Process Refactoring work
* More Refactoring/fixes for follow
* Finish Refactoring AI_Process
* cleanup
* cleanup
* cleanup
* cleanup
* fix melee attack loop
* fix for leashowner.
* fix for leashowner.
* Bots persist in raid after client death/LD/Camp
* Fix Bot Groups when zoning after death.
* Fix Bots in group following after client death
* remove unnecessary query
* Allow Raid members to invite Bots if owner is in raid. cleanup
* optimization of raid verification
* remove this
* Code Cleanup
* formatting
* formatting
* formatting
* fix for macro
* add return for TryClassAttacks
* fix query
* fix for crash
* restrict camping/spawn in combat.
* Fix other crash issue.
* update learnmembers to use Strings::To, cleanup magic numbers
* fix for merge.
---------
Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
Co-authored-by: Aeadoin <109764533+Aeadoin@users.noreply.github.com>
This commit is contained in:
+375
-153
@@ -26,6 +26,7 @@
|
||||
#include "mob.h"
|
||||
#include "raids.h"
|
||||
#include "string_ids.h"
|
||||
#include "bot.h"
|
||||
|
||||
#include "worldserver.h"
|
||||
|
||||
@@ -94,41 +95,57 @@ bool Raid::Process()
|
||||
}
|
||||
|
||||
void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bool looter){
|
||||
if(!c)
|
||||
if (!c) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string query = StringFormat("INSERT INTO raid_members SET raidid = %lu, charid = %lu, "
|
||||
"groupid = %lu, _class = %d, level = %d, name = '%s', "
|
||||
"isgroupleader = %d, israidleader = %d, islooter = %d",
|
||||
(unsigned long)GetID(), (unsigned long)c->CharacterID(),
|
||||
(unsigned long)group, c->GetClass(), c->GetLevel(),
|
||||
c->GetName(), groupleader, rleader, looter);
|
||||
auto results = database.QueryDatabase(query);
|
||||
const auto query = fmt::format(
|
||||
"REPLACE INTO raid_members SET raidid = {}, charid = {}, bot_id = 0, "
|
||||
"groupid = {}, _class = {}, level = {}, name = '{}', "
|
||||
"isgroupleader = {}, israidleader = {}, islooter = {}",
|
||||
GetID(),
|
||||
c->CharacterID(),
|
||||
group,
|
||||
c->GetClass(),
|
||||
c->GetLevel(),
|
||||
c->GetName(),
|
||||
groupleader,
|
||||
rleader,
|
||||
looter
|
||||
);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if(!results.Success()) {
|
||||
LogError("Error inserting into raid members: [{}]", results.ErrorMessage().c_str());
|
||||
}
|
||||
|
||||
LearnMembers();
|
||||
VerifyRaid();
|
||||
|
||||
if (rleader) {
|
||||
database.SetRaidGroupLeaderInfo(group, GetID());
|
||||
UpdateRaidAAs();
|
||||
} else if (rleader) {
|
||||
database.SetRaidGroupLeaderInfo(RAID_GROUPLESS, GetID());
|
||||
UpdateRaidAAs();
|
||||
}
|
||||
|
||||
if (group != RAID_GROUPLESS && groupleader) {
|
||||
database.SetRaidGroupLeaderInfo(group, GetID());
|
||||
UpdateGroupAAs(group);
|
||||
}
|
||||
if(group < 12)
|
||||
|
||||
if (group < MAX_RAID_GROUPS) {
|
||||
GroupUpdate(group);
|
||||
else // get raid AAs, GroupUpdate will handles it otherwise
|
||||
} else { // get raid AAs, GroupUpdate will handles it otherwise
|
||||
SendGroupLeadershipAA(c, RAID_GROUPLESS);
|
||||
}
|
||||
|
||||
SendRaidAddAll(c->GetName());
|
||||
|
||||
c->SetRaidGrouped(true);
|
||||
SendRaidMOTD(c);
|
||||
|
||||
// xtarget shit ..........
|
||||
if (group == RAID_GROUPLESS) {
|
||||
if (rleader) {
|
||||
GetXTargetAutoMgr()->merge(*c->GetXTargetAutoMgr());
|
||||
@@ -148,54 +165,115 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo
|
||||
}
|
||||
}
|
||||
|
||||
Raid *raid_update = nullptr;
|
||||
raid_update = c->GetRaid();
|
||||
auto* raid_update = c->GetRaid();
|
||||
if (raid_update) {
|
||||
raid_update->SendHPManaEndPacketsTo(c);
|
||||
raid_update->SendHPManaEndPacketsFrom(c);
|
||||
}
|
||||
|
||||
auto pack = new ServerPacket(ServerOP_RaidAdd, sizeof(ServerRaidGeneralAction_Struct));
|
||||
ServerRaidGeneralAction_Struct *rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
|
||||
rga->rid = GetID();
|
||||
strn0cpy(rga->playername, c->GetName(), 64);
|
||||
rga->zoneid = zone->GetZoneID();
|
||||
auto* rga = (ServerRaidGeneralAction_Struct*) pack->pBuffer;
|
||||
strn0cpy(rga->playername, c->GetName(), sizeof(rga->playername));
|
||||
rga->rid = GetID();
|
||||
rga->zoneid = zone->GetZoneID();
|
||||
rga->instance_id = zone->GetInstanceID();
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Raid::AddBot(Bot* b, uint32 group, bool rleader, bool groupleader, bool looter) {
|
||||
if (!b) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto query = fmt::format(
|
||||
"REPLACE INTO raid_members SET raidid = {}, "
|
||||
"charid = 0, bot_id = {}, groupid = {}, _class = {}, level = {}, name = '{}', "
|
||||
"isgroupleader = {}, israidleader = {}, islooter = {}",
|
||||
GetID(),
|
||||
b->GetBotID(),
|
||||
group,
|
||||
b->GetClass(),
|
||||
b->GetLevel(),
|
||||
b->GetName(),
|
||||
groupleader,
|
||||
rleader,
|
||||
looter
|
||||
);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
LearnMembers();
|
||||
VerifyRaid();
|
||||
|
||||
if (group < MAX_RAID_GROUPS) {
|
||||
GroupUpdate(group);
|
||||
} else { // get raid AAs, GroupUpdate will handle it otherwise
|
||||
SendGroupLeadershipAA(b->GetOwner()->CastToClient(), RAID_GROUPLESS);
|
||||
}
|
||||
|
||||
SendRaidAddAll(b->GetName());
|
||||
|
||||
b->SetRaidGrouped(true);
|
||||
b->p_raid_instance = this;
|
||||
|
||||
|
||||
auto pack = new ServerPacket(ServerOP_RaidAdd, sizeof(ServerRaidGeneralAction_Struct));
|
||||
auto* rga = (ServerRaidGeneralAction_Struct*) pack->pBuffer;
|
||||
strn0cpy(rga->playername, b->GetName(), sizeof(rga->playername));
|
||||
rga->rid = GetID();
|
||||
rga->zoneid = zone->GetZoneID();
|
||||
rga->instance_id = zone->GetInstanceID();
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
|
||||
void Raid::RemoveMember(const char *characterName)
|
||||
{
|
||||
std::string query = StringFormat("DELETE FROM raid_members where name='%s'", characterName);
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
Client *client = entity_list.GetClientByName(characterName);
|
||||
auto* b = entity_list.GetBotByBotName(characterName);
|
||||
auto* c = entity_list.GetClientByName(characterName);
|
||||
|
||||
if (RuleB(Bots, Enabled) && b) {
|
||||
b = entity_list.GetBotByBotName(characterName);
|
||||
b->SetFollowID(b->GetOwner()->CastToClient()->GetID());
|
||||
b->SetTarget(nullptr);
|
||||
b->SetRaidGrouped(false);
|
||||
}
|
||||
|
||||
disbandCheck = true;
|
||||
SendRaidRemoveAll(characterName);
|
||||
SendRaidDisband(client);
|
||||
SendRaidDisband(c);
|
||||
LearnMembers();
|
||||
VerifyRaid();
|
||||
|
||||
if(client) {
|
||||
client->SetRaidGrouped(false);
|
||||
client->LeaveRaidXTargets(this);
|
||||
client->p_raid_instance = nullptr;
|
||||
if (c) {
|
||||
c->SetRaidGrouped(false);
|
||||
c->LeaveRaidXTargets(this);
|
||||
c->p_raid_instance = nullptr;
|
||||
}
|
||||
|
||||
auto pack = new ServerPacket(ServerOP_RaidRemove, sizeof(ServerRaidGeneralAction_Struct));
|
||||
ServerRaidGeneralAction_Struct *rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
|
||||
rga->rid = GetID();
|
||||
auto* rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
|
||||
rga->rid = GetID();
|
||||
rga->instance_id = zone->GetInstanceID();
|
||||
strn0cpy(rga->playername, characterName, 64);
|
||||
rga->zoneid = zone->GetZoneID();
|
||||
rga->zoneid = zone->GetZoneID();
|
||||
strn0cpy(rga->playername, characterName, sizeof(rga->playername));
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
void Raid::DisbandRaid()
|
||||
{
|
||||
std::string query = StringFormat("DELETE FROM raid_members WHERE raidid = %lu", (unsigned long)GetID());
|
||||
const auto query = fmt::format(
|
||||
"DELETE FROM raid_members WHERE raidid = {}",
|
||||
GetID()
|
||||
);
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
LearnMembers();
|
||||
@@ -203,11 +281,11 @@ void Raid::DisbandRaid()
|
||||
SendRaidDisbandAll();
|
||||
|
||||
auto pack = new ServerPacket(ServerOP_RaidDisband, sizeof(ServerRaidGeneralAction_Struct));
|
||||
ServerRaidGeneralAction_Struct *rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
|
||||
rga->rid = GetID();
|
||||
strn0cpy(rga->playername, " ", 64);
|
||||
rga->zoneid = zone->GetZoneID();
|
||||
auto* rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
|
||||
rga->rid = GetID();
|
||||
rga->zoneid = zone->GetZoneID();
|
||||
rga->instance_id = zone->GetInstanceID();
|
||||
strn0cpy(rga->playername, " ", sizeof(rga->playername));
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
|
||||
@@ -216,19 +294,23 @@ void Raid::DisbandRaid()
|
||||
|
||||
void Raid::MoveMember(const char *name, uint32 newGroup)
|
||||
{
|
||||
std::string query = StringFormat("UPDATE raid_members SET groupid = %lu WHERE name = '%s'",
|
||||
(unsigned long)newGroup, name);
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
const auto query = fmt::format(
|
||||
"UPDATE raid_members SET groupid = {} WHERE name = '{}'",
|
||||
newGroup,
|
||||
name
|
||||
);
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
LearnMembers();
|
||||
VerifyRaid();
|
||||
SendRaidMoveAll(name);
|
||||
|
||||
|
||||
auto pack = new ServerPacket(ServerOP_RaidChangeGroup, sizeof(ServerRaidGeneralAction_Struct));
|
||||
ServerRaidGeneralAction_Struct *rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
|
||||
rga->rid = GetID();
|
||||
strn0cpy(rga->playername, name, 64);
|
||||
rga->zoneid = zone->GetZoneID();
|
||||
auto* rga = (ServerRaidGeneralAction_Struct*) pack->pBuffer;
|
||||
strn0cpy(rga->playername, name, sizeof(rga->playername));
|
||||
rga->rid = GetID();
|
||||
rga->zoneid = zone->GetZoneID();
|
||||
rga->instance_id = zone->GetInstanceID();
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
@@ -236,18 +318,21 @@ void Raid::MoveMember(const char *name, uint32 newGroup)
|
||||
|
||||
void Raid::SetGroupLeader(const char *who, bool glFlag)
|
||||
{
|
||||
std::string query = StringFormat("UPDATE raid_members SET isgroupleader = %lu WHERE name = '%s'",
|
||||
(unsigned long)glFlag, who);
|
||||
auto results = database.QueryDatabase(query);
|
||||
const auto query = fmt::format(
|
||||
"UPDATE raid_members SET isgroupleader = {} WHERE name = '{}'",
|
||||
glFlag,
|
||||
who
|
||||
);
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
LearnMembers();
|
||||
VerifyRaid();
|
||||
|
||||
auto pack = new ServerPacket(ServerOP_RaidGroupLeader, sizeof(ServerRaidGeneralAction_Struct));
|
||||
ServerRaidGeneralAction_Struct *rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
|
||||
rga->rid = GetID();
|
||||
strn0cpy(rga->playername, who, 64);
|
||||
rga->zoneid = zone->GetZoneID();
|
||||
auto* rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
|
||||
strn0cpy(rga->playername, who, sizeof(rga->playername));
|
||||
rga->rid = GetID();
|
||||
rga->zoneid = zone->GetZoneID();
|
||||
rga->instance_id = zone->GetInstanceID();
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
@@ -406,13 +491,13 @@ uint32 Raid::GetFreeGroup()
|
||||
return x;
|
||||
}
|
||||
//if we get to here then there were no free groups so we added the group as free floating members.
|
||||
return 0xFFFFFFFF;
|
||||
return RAID_GROUPLESS;
|
||||
}
|
||||
|
||||
uint8 Raid::GroupCount(uint32 gid)
|
||||
{
|
||||
uint8 count = 0;
|
||||
if(gid < 12)
|
||||
if(gid < MAX_RAID_GROUPS)
|
||||
{
|
||||
for(int x = 0; x < MAX_RAID_MEMBERS; x++)
|
||||
{
|
||||
@@ -453,7 +538,7 @@ uint32 Raid::GetGroup(const char *name)
|
||||
if(strcmp(members[x].membername, name) == 0)
|
||||
return members[x].GroupNumber;
|
||||
}
|
||||
return 0xFFFFFFFF;
|
||||
return RAID_GROUPLESS;
|
||||
}
|
||||
|
||||
uint32 Raid::GetGroup(Client *c)
|
||||
@@ -463,7 +548,7 @@ uint32 Raid::GetGroup(Client *c)
|
||||
if(members[x].member == c)
|
||||
return members[x].GroupNumber;
|
||||
}
|
||||
return 0xFFFFFFFF;
|
||||
return RAID_GROUPLESS;
|
||||
}
|
||||
|
||||
void Raid::RaidSay(const char *msg, Client *c, uint8 language, uint8 lang_skill)
|
||||
@@ -474,7 +559,7 @@ void Raid::RaidSay(const char *msg, Client *c, uint8 language, uint8 lang_skill)
|
||||
auto pack = new ServerPacket(ServerOP_RaidSay, sizeof(ServerRaidMessage_Struct) + strlen(msg) + 1);
|
||||
ServerRaidMessage_Struct *rga = (ServerRaidMessage_Struct*)pack->pBuffer;
|
||||
rga->rid = GetID();
|
||||
rga->gid = 0xFFFFFFFF;
|
||||
rga->gid = RAID_GROUPLESS;
|
||||
rga->language = language;
|
||||
rga->lang_skill = lang_skill;
|
||||
strn0cpy(rga->from, c->GetName(), 64);
|
||||
@@ -992,19 +1077,21 @@ void Raid::SendRaidAdd(const char *who, Client *to)
|
||||
if(!to)
|
||||
return;
|
||||
|
||||
for(int x = 0; x < MAX_RAID_MEMBERS; x++)
|
||||
std::vector<RaidMember> rm = GetMembers();
|
||||
|
||||
for (const auto& m : rm)
|
||||
{
|
||||
if(strcmp(members[x].membername, who) == 0)
|
||||
if (strcmp(m.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;
|
||||
strn0cpy(ram->raidGen.leader_name, members[x].membername, 64);
|
||||
strn0cpy(ram->raidGen.player_name, members[x].membername, 64);
|
||||
ram->_class = members[x]._class;
|
||||
ram->level = members[x].level;
|
||||
ram->isGroupLeader = members[x].IsGroupLeader;
|
||||
ram->raidGen.parameter = m.GroupNumber;
|
||||
strn0cpy(ram->raidGen.leader_name, m.membername, 64);
|
||||
strn0cpy(ram->raidGen.player_name, m.membername, 64);
|
||||
ram->_class = m._class;
|
||||
ram->level = m.level;
|
||||
ram->isGroupLeader = m.IsGroupLeader;
|
||||
to->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
@@ -1014,19 +1101,21 @@ void Raid::SendRaidAdd(const char *who, Client *to)
|
||||
|
||||
void Raid::SendRaidAddAll(const char *who)
|
||||
{
|
||||
for(int x = 0; x < MAX_RAID_MEMBERS; x++)
|
||||
{
|
||||
if(strcmp(members[x].membername, who) == 0)
|
||||
std::vector<RaidMember> rm = GetMembers();
|
||||
|
||||
for (const auto& m : rm) {
|
||||
if (strcmp(m.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);
|
||||
strcpy(ram->raidGen.player_name, members[x].membername);
|
||||
ram->_class = members[x]._class;
|
||||
ram->level = members[x].level;
|
||||
ram->isGroupLeader = members[x].IsGroupLeader;
|
||||
ram->raidGen.parameter = m.GroupNumber;
|
||||
strcpy(ram->raidGen.leader_name, m.membername);
|
||||
strcpy(ram->raidGen.player_name, m.membername);
|
||||
ram->isGroupLeader = m.IsGroupLeader;
|
||||
ram->_class = m._class;
|
||||
ram->level = m.level;
|
||||
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
@@ -1129,12 +1218,13 @@ void Raid::SendRaidMoveAll(const char* who)
|
||||
SendRaidRemoveAll(who);
|
||||
if(c)
|
||||
SendRaidCreate(c);
|
||||
SendMakeLeaderPacket(leadername);
|
||||
SendRaidAddAll(who);
|
||||
if(c){
|
||||
SendBulkRaid(c);
|
||||
if(IsLocked()) { SendRaidLockTo(c); }
|
||||
}
|
||||
SendRaidAddAll(who);
|
||||
SendMakeLeaderPacket(leadername);
|
||||
|
||||
}
|
||||
|
||||
void Raid::SendBulkRaid(Client *to)
|
||||
@@ -1144,7 +1234,7 @@ void Raid::SendBulkRaid(Client *to)
|
||||
|
||||
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 (strlen(members[x].membername) > 0 && (strcmp(members[x].membername, to->GetName()) != 0)) //don't send ourself
|
||||
{
|
||||
SendRaidAdd(members[x].membername, to);
|
||||
}
|
||||
@@ -1155,7 +1245,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);
|
||||
}
|
||||
@@ -1164,6 +1254,11 @@ void Raid::QueuePacket(const EQApplicationPacket *app, bool ack_req)
|
||||
|
||||
void Raid::SendMakeLeaderPacket(const char *who) //30
|
||||
{
|
||||
|
||||
if (RuleB(Bots, Enabled) && 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;
|
||||
@@ -1176,8 +1271,13 @@ void Raid::SendMakeLeaderPacket(const char *who) //30
|
||||
|
||||
void Raid::SendMakeLeaderPacketTo(const char *who, Client *to)
|
||||
{
|
||||
if(!to)
|
||||
if (!to) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (RuleB(Bots, Enabled) && members[GetPlayerIndex(who)].IsBot) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct));
|
||||
RaidLeadershipUpdate_Struct *rg = (RaidLeadershipUpdate_Struct*)outapp->pBuffer;
|
||||
@@ -1206,8 +1306,13 @@ void Raid::SendMakeGroupLeaderPacketTo(const char *who, Client *to)
|
||||
|
||||
void Raid::SendGroupUpdate(Client *to)
|
||||
{
|
||||
if(!to)
|
||||
if (!to) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (RuleB(Bots, Enabled) && members[GetPlayerIndex(to)].IsBot) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupUpdate2_Struct));
|
||||
GroupUpdate2_Struct* gu = (GroupUpdate2_Struct*)outapp->pBuffer;
|
||||
@@ -1249,13 +1354,14 @@ void Raid::SendGroupUpdate(Client *to)
|
||||
|
||||
void Raid::GroupUpdate(uint32 gid, bool initial)
|
||||
{
|
||||
if(gid > 11) //ungrouped member doesn't need grouping.
|
||||
if(gid > 11) {//ungrouped member doesn't need grouping.
|
||||
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){
|
||||
if(members[x].GroupNumber == gid){
|
||||
if(members[x].member) {
|
||||
if (members[x].member) {
|
||||
SendGroupUpdate(members[x].member);
|
||||
SendGroupLeadershipAA(members[x].member, gid);
|
||||
}
|
||||
@@ -1362,6 +1468,10 @@ void Raid::SendRaidMOTD(Client *c)
|
||||
if (!c || motd.empty())
|
||||
return;
|
||||
|
||||
if (members[GetPlayerIndex(c)].IsBot) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t size = motd.size() + 1;
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidMOTD_Struct) + size);
|
||||
RaidMOTD_Struct *rmotd = (RaidMOTD_Struct *)outapp->pBuffer;
|
||||
@@ -1397,6 +1507,10 @@ void Raid::SendRaidMOTDToWorld()
|
||||
|
||||
void Raid::SendGroupLeadershipAA(Client *c, uint32 gid)
|
||||
{
|
||||
if (RuleB(Bots, Enabled) && members[GetPlayerIndex(c)].IsBot) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct));
|
||||
RaidLeadershipUpdate_Struct *rlaa = (RaidLeadershipUpdate_Struct *)outapp->pBuffer;
|
||||
rlaa->action = raidSetLeaderAbilities;
|
||||
@@ -1411,18 +1525,23 @@ 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)
|
||||
SendGroupLeadershipAA(members[i].member, gid);
|
||||
for (const auto& m : members) {
|
||||
if (m.member && m.GroupNumber == gid && !m.IsBot) {
|
||||
SendGroupLeadershipAA(m.member, gid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Raid::SendAllRaidLeadershipAA()
|
||||
{
|
||||
for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++)
|
||||
if (members[i].member)
|
||||
SendGroupLeadershipAA(members[i].member, members[i].GroupNumber);
|
||||
for (const auto& m : members) {
|
||||
if (m.member && !m.IsBot) {
|
||||
SendGroupLeadershipAA(m.member, m.GroupNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Raid::LockRaid(bool lockFlag)
|
||||
{
|
||||
std::string query = StringFormat("UPDATE raid_details SET locked = %d WHERE raidid = %lu",
|
||||
@@ -1486,70 +1605,84 @@ void Raid::SaveRaidMOTD()
|
||||
|
||||
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, "
|
||||
"isgroupleader, israidleader, islooter "
|
||||
"FROM raid_members WHERE raidid = %lu",
|
||||
(unsigned long)GetID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
const auto query = fmt::format(
|
||||
"SELECT name, groupid, _class, level, "
|
||||
"isgroupleader, israidleader, islooter, bot_id "
|
||||
"FROM raid_members WHERE raidid = {} ORDER BY groupid",
|
||||
GetID()
|
||||
);
|
||||
|
||||
if(results.RowCount() == 0) {
|
||||
LogError("Error getting raid members for raid [{}]: [{}]", (unsigned long)GetID(), results.ErrorMessage().c_str());
|
||||
disbandCheck = true;
|
||||
return false;
|
||||
}
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
for(auto row = results.begin(); row != results.end(); ++row) {
|
||||
if(!row[0])
|
||||
continue;
|
||||
if (!results.RowCount()) {
|
||||
LogError("Error getting raid members for raid [{}]: [{}]", GetID(), results.ErrorMessage());
|
||||
disbandCheck = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
members[index].member = nullptr;
|
||||
strn0cpy(members[index].membername, row[0], 64);
|
||||
uint32 groupNum = Strings::ToUnsignedInt(row[1]);
|
||||
if(groupNum > 11)
|
||||
members[index].GroupNumber = 0xFFFFFFFF;
|
||||
else
|
||||
members[index].GroupNumber = groupNum;
|
||||
int index = 0;
|
||||
for (auto row: results) {
|
||||
if (!row[0]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
members[index]._class = Strings::ToInt(row[2]);
|
||||
members[index].level = Strings::ToInt(row[3]);
|
||||
members[index].IsGroupLeader = Strings::ToInt(row[4]);
|
||||
members[index].IsRaidLeader = Strings::ToInt(row[5]);
|
||||
members[index].IsLooter = Strings::ToInt(row[6]);
|
||||
++index;
|
||||
}
|
||||
members[index].member = nullptr;
|
||||
strn0cpy(members[index].membername, row[0], sizeof(members[index].membername));
|
||||
uint32 group_id = Strings::ToUnsignedInt(row[1]);
|
||||
|
||||
if (group_id > 11) {
|
||||
members[index].GroupNumber = RAID_GROUPLESS;
|
||||
} else {
|
||||
members[index].GroupNumber = group_id;
|
||||
}
|
||||
|
||||
members[index]._class = Strings::ToUnsignedInt(row[2]);
|
||||
members[index].level = Strings::ToUnsignedInt(row[3]);
|
||||
members[index].IsGroupLeader = Strings::ToBool(row[4]);
|
||||
members[index].IsRaidLeader = Strings::ToBool(row[5]);
|
||||
members[index].IsLooter = Strings::ToBool(row[6]);
|
||||
members[index].IsBot = Strings::ToBool(row[7]) > 0;
|
||||
++index;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Raid::VerifyRaid()
|
||||
{
|
||||
for(int x = 0; x < MAX_RAID_MEMBERS; x++)
|
||||
{
|
||||
if(strlen(members[x].membername) == 0){
|
||||
members[x].member = nullptr;
|
||||
}
|
||||
else{
|
||||
Client *c = entity_list.GetClientByName(members[x].membername);
|
||||
if(c){
|
||||
members[x].member = c;
|
||||
}
|
||||
else{
|
||||
members[x].member = nullptr;
|
||||
for (auto& m : members) {
|
||||
if(strlen(m.membername) == 0){
|
||||
m.member = nullptr;
|
||||
} else {
|
||||
auto* c = entity_list.GetClientByName(m.membername);
|
||||
auto* b = entity_list.GetBotByBotName(m.membername);
|
||||
|
||||
if (c) {
|
||||
m.member = c;
|
||||
m.IsBot = false;
|
||||
} else if(RuleB(Bots, Enabled) && b){
|
||||
//Raid requires client* we are forcing it here to be a BOT. Care is needed here as any client function that
|
||||
//does not exist within the Bot Class will likely corrupt memory for the member object. Good practice to test the IsBot
|
||||
//attribute before calling a client function or casting to client.
|
||||
b = entity_list.GetBotByBotName(m.membername);
|
||||
m.member = b->CastToClient();
|
||||
m.IsBot = true; //Used to identify those members who are Bots
|
||||
} else {
|
||||
m.member = nullptr;
|
||||
m.IsBot = false;
|
||||
}
|
||||
}
|
||||
if(members[x].IsRaidLeader){
|
||||
if(strlen(members[x].membername) > 0){
|
||||
SetLeader(members[x].member);
|
||||
strn0cpy(leadername, members[x].membername, 64);
|
||||
}
|
||||
else
|
||||
{
|
||||
//should never happen, but maybe it is?
|
||||
|
||||
if (m.IsRaidLeader) {
|
||||
if (strlen(m.membername) > 0){
|
||||
SetLeader(m.member);
|
||||
strn0cpy(leadername, m.membername, sizeof(leadername));
|
||||
} else {
|
||||
SetLeader(nullptr);
|
||||
}
|
||||
}
|
||||
@@ -1577,7 +1710,7 @@ void Raid::MemberZoned(Client *c)
|
||||
}
|
||||
}
|
||||
|
||||
if (gid < 12 && group_mentor[gid].mentoree == c)
|
||||
if (gid < MAX_RAID_GROUPS && group_mentor[gid].mentoree == c)
|
||||
group_mentor[gid].mentoree = nullptr;
|
||||
}
|
||||
|
||||
@@ -1592,7 +1725,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);
|
||||
@@ -1634,7 +1767,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) {
|
||||
@@ -1667,7 +1800,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);
|
||||
@@ -1694,7 +1827,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);
|
||||
@@ -1801,9 +1934,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*/) {
|
||||
@@ -1812,22 +1950,25 @@ void Raid::QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_re
|
||||
uint32 group_id = GetGroup(sender->CastToClient());
|
||||
|
||||
/* If this is a group only packet and we're not in a group -- return */
|
||||
if (group_id == 0xFFFFFFFF && group_only)
|
||||
if (group_id == RAID_GROUPLESS && group_only)
|
||||
return;
|
||||
|
||||
for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++) {
|
||||
if (!members[i].member)
|
||||
if (!members[i].member) {
|
||||
continue;
|
||||
|
||||
if (!members[i].member->IsClient())
|
||||
}
|
||||
if (!members[i].member->IsClient()) {
|
||||
continue;
|
||||
|
||||
if (ignore_sender && members[i].member == sender)
|
||||
}
|
||||
if (members[i].IsBot) {
|
||||
continue;
|
||||
|
||||
if (group_only && members[i].GroupNumber != group_id)
|
||||
}
|
||||
if (ignore_sender && members[i].member == sender) {
|
||||
continue;
|
||||
|
||||
}
|
||||
if (group_only && members[i].GroupNumber != group_id) {
|
||||
continue;
|
||||
}
|
||||
/* If we don't have a distance requirement - send to all members */
|
||||
if (distance == 0) {
|
||||
members[i].member->CastToClient()->QueuePacket(app, ack_required);
|
||||
@@ -1884,3 +2025,84 @@ 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;
|
||||
}
|
||||
bool Raid::IsEngaged() {
|
||||
|
||||
std::vector<RaidMember> rm = GetMembers();
|
||||
for (const auto& m : rm) {
|
||||
if (m.member && !m.IsBot && (m.member->IsEngaged() || m.member->GetAggroCount() > 0)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void Raid::RaidGroupSay(const char* msg, const char* from, uint8 language, uint8 lang_skill)
|
||||
{
|
||||
if (!from)
|
||||
return;
|
||||
|
||||
uint32 groupToUse = GetGroup(from);
|
||||
|
||||
if (groupToUse > 11)
|
||||
return;
|
||||
|
||||
auto pack = new ServerPacket(ServerOP_RaidGroupSay, sizeof(ServerRaidMessage_Struct) + strlen(msg) + 1);
|
||||
ServerRaidMessage_Struct* rga = (ServerRaidMessage_Struct*)pack->pBuffer;
|
||||
rga->rid = GetID();
|
||||
rga->gid = groupToUse;
|
||||
rga->language = language;
|
||||
rga->lang_skill = lang_skill;
|
||||
strn0cpy(rga->from, from, 64);
|
||||
|
||||
strcpy(rga->message, msg); // this is safe because we are allocating enough space for the entire msg above
|
||||
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
void Raid::RaidSay(const char* msg, const char* from, uint8 language, uint8 lang_skill)
|
||||
{
|
||||
if (!from)
|
||||
return;
|
||||
|
||||
auto pack = new ServerPacket(ServerOP_RaidSay, sizeof(ServerRaidMessage_Struct) + strlen(msg) + 1);
|
||||
ServerRaidMessage_Struct* rga = (ServerRaidMessage_Struct*)pack->pBuffer;
|
||||
rga->rid = GetID();
|
||||
rga->gid = RAID_GROUPLESS;
|
||||
rga->language = language;
|
||||
rga->lang_skill = lang_skill;
|
||||
strn0cpy(rga->from, from, 64);
|
||||
|
||||
strcpy(rga->message, msg);
|
||||
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
void Raid::SetNewRaidLeader(uint32 i)
|
||||
{
|
||||
if (members[i].IsRaidLeader) {
|
||||
for (int x = 0; x < MAX_RAID_MEMBERS; x++) {
|
||||
if (!members[x].IsBot) {
|
||||
if (strlen(members[x].membername) > 0 && strcmp(members[x].membername, members[i].membername) != 0) {
|
||||
SetRaidLeader(members[i].membername, members[x].membername);
|
||||
UpdateRaidAAs();
|
||||
SendAllRaidLeadershipAA();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user