mirror of
https://github.com/EQEmu/Server.git
synced 2026-06-28 13:27:15 +00:00
Merge branch 'master' of https://github.com/neckkola/Server
This commit is contained in:
+1
-1
@@ -54,5 +54,5 @@ bin/
|
||||
/Win32
|
||||
/x64
|
||||
/client_files/**/CMakeFiles/
|
||||
|
||||
submodules/libuv
|
||||
.idea
|
||||
@@ -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": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -28,6 +28,9 @@ public:
|
||||
int isgroupleader;
|
||||
int israidleader;
|
||||
int islooter;
|
||||
#ifdef BOTS
|
||||
int isbot;
|
||||
#endif
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
@@ -47,6 +50,9 @@ public:
|
||||
"isgroupleader",
|
||||
"israidleader",
|
||||
"islooter",
|
||||
#ifdef BOTS
|
||||
"isbot",
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
@@ -111,6 +117,9 @@ public:
|
||||
entry.isgroupleader = 0;
|
||||
entry.israidleader = 0;
|
||||
entry.islooter = 0;
|
||||
#ifdef BOTS
|
||||
entry.isbot = 0;
|
||||
#endif
|
||||
|
||||
return entry;
|
||||
}
|
||||
@@ -155,6 +164,9 @@ public:
|
||||
entry.isgroupleader = atoi(row[6]);
|
||||
entry.israidleader = atoi(row[7]);
|
||||
entry.islooter = atoi(row[8]);
|
||||
#ifdef BOTS
|
||||
entry.isbot = atoi(row[9]);
|
||||
#endif
|
||||
|
||||
return entry;
|
||||
}
|
||||
@@ -197,6 +209,9 @@ public:
|
||||
update_values.push_back(columns[6] + " = " + std::to_string(raid_members_entry.isgroupleader));
|
||||
update_values.push_back(columns[7] + " = " + std::to_string(raid_members_entry.israidleader));
|
||||
update_values.push_back(columns[8] + " = " + std::to_string(raid_members_entry.islooter));
|
||||
#ifdef BOTS
|
||||
update_values.push_back(columns[9] + " = " + std::to_string(raid_members_entry.isbot));
|
||||
#endif
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -227,7 +242,9 @@ public:
|
||||
insert_values.push_back(std::to_string(raid_members_entry.isgroupleader));
|
||||
insert_values.push_back(std::to_string(raid_members_entry.israidleader));
|
||||
insert_values.push_back(std::to_string(raid_members_entry.islooter));
|
||||
|
||||
#ifdef BOTS
|
||||
insert_values.push_back(std::to_string(raid_members_entry.isbot));
|
||||
#endif
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES ({})",
|
||||
@@ -265,7 +282,9 @@ public:
|
||||
insert_values.push_back(std::to_string(raid_members_entry.isgroupleader));
|
||||
insert_values.push_back(std::to_string(raid_members_entry.israidleader));
|
||||
insert_values.push_back(std::to_string(raid_members_entry.islooter));
|
||||
|
||||
#ifdef BOTS
|
||||
insert_values.push_back(std::to_string(raid_members_entry.isbot));
|
||||
#endif
|
||||
insert_chunks.push_back("(" + implode(",", insert_values) + ")");
|
||||
}
|
||||
|
||||
@@ -307,7 +326,9 @@ public:
|
||||
entry.isgroupleader = atoi(row[6]);
|
||||
entry.israidleader = atoi(row[7]);
|
||||
entry.islooter = atoi(row[8]);
|
||||
|
||||
#ifdef BOTS
|
||||
entry.isbot = atoi(row[9]);
|
||||
#endif
|
||||
all_entries.push_back(entry);
|
||||
}
|
||||
|
||||
@@ -340,7 +361,9 @@ public:
|
||||
entry.isgroupleader = atoi(row[6]);
|
||||
entry.israidleader = atoi(row[7]);
|
||||
entry.islooter = atoi(row[8]);
|
||||
|
||||
#ifdef BOTS
|
||||
entry.isbot = atoi(row[9]);
|
||||
#endif
|
||||
all_entries.push_back(entry);
|
||||
}
|
||||
|
||||
|
||||
@@ -622,10 +622,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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
9026|2019_09_09_bots_owner_options_rework.sql|SHOW COLUMNS FROM `bot_owner_options` LIKE 'option_type'|empty|
|
||||
9027|2020_03_30_bots_view_update.sql|SELECT * FROM db_version WHERE bots_version >= 9027|empty|
|
||||
9028|2021_06_04_bot_create_combinations.sql|SHOW TABLES LIKE 'bot_create_combinations'|empty|
|
||||
9029|2022_02_08_bots_raid_members.sql|SELECT * FROM db_version WHERE bots_version >= 9028|empty|
|
||||
|
||||
# Upgrade conditions:
|
||||
# This won't be needed after this system is implemented, but it is used database that are not
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE `raid_members` ADD COLUMN `isbot` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '';
|
||||
@@ -11,6 +11,7 @@ SET(zone_sources
|
||||
beacon.cpp
|
||||
bonuses.cpp
|
||||
bot.cpp
|
||||
bot_raid.cpp
|
||||
bot_command.cpp
|
||||
bot_database.cpp
|
||||
botspellsai.cpp
|
||||
|
||||
+17
-2
@@ -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
|
||||
@@ -375,6 +376,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);
|
||||
static void ProcessRaidInvite(Client* invitee, Client* invitor);
|
||||
uint8 GetNumberNeedingHealedInRaidGroup(uint8 hpr, bool includePets);
|
||||
inline void SetDirtyAutoHaters() { m_dirtyautohaters = true; }
|
||||
|
||||
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);
|
||||
@@ -610,6 +620,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);
|
||||
@@ -674,6 +687,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;
|
||||
@@ -740,6 +754,7 @@ private:
|
||||
|
||||
public:
|
||||
static uint8 spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND];
|
||||
|
||||
};
|
||||
|
||||
#endif // BOTS
|
||||
|
||||
+2630
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+3
-2
@@ -807,10 +807,11 @@ void Client::QueuePacket(const EQApplicationPacket* app, bool ack_req, CLIENT_CO
|
||||
// todo: save packets for later use
|
||||
AddPacket(app, ack_req);
|
||||
}
|
||||
else
|
||||
if(eqs)
|
||||
else if (eqs)
|
||||
{
|
||||
eqs->QueuePacket(app, ack_req);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::FastQueuePacket(EQApplicationPacket** app, bool ack_req, CLIENT_CONN_STATUS required_state) {
|
||||
// if the program doesnt care about the status or if the status isnt what we requested
|
||||
|
||||
+214
-4
@@ -25,6 +25,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <zlib.h>
|
||||
#include "bot.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#define snprintf _snprintf
|
||||
@@ -72,6 +73,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
#ifdef BOTS
|
||||
#include "bot.h"
|
||||
#include "bot_command.h"
|
||||
#endif
|
||||
|
||||
extern QueryServ* QServ;
|
||||
@@ -588,6 +590,31 @@ void Client::CompleteConnect()
|
||||
if (raid) {
|
||||
SetRaidGrouped(true);
|
||||
raid->LearnMembers();
|
||||
#ifdef BOTS
|
||||
std::list<BotsAvailableList> bots_list;
|
||||
database.botdb.LoadBotsList(this->CharacterID(), bots_list);
|
||||
std::vector<RaidMember> r_members = raid->GetMembers();
|
||||
for (const RaidMember& iter : r_members) {
|
||||
if (iter.membername) {
|
||||
for (const BotsAvailableList& b_iter : bots_list)
|
||||
{
|
||||
if (strcmp(iter.membername, b_iter.Name) == 0)
|
||||
{
|
||||
char buffer[71] = "^spawn ";
|
||||
strcat(buffer, iter.membername);
|
||||
bot_command_real_dispatch(this, buffer);
|
||||
Bot* b = entity_list.GetBotByBotName(iter.membername);
|
||||
if (b)
|
||||
{
|
||||
b->SetRaidGrouped(true);
|
||||
b->p_raid_instance = raid;
|
||||
//b->SetFollowID(this->GetID());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
raid->VerifyRaid();
|
||||
raid->GetRaidDetails();
|
||||
/*
|
||||
@@ -6966,6 +6993,11 @@ void Client::Handle_OP_GroupInvite2(const EQApplicationPacket *app)
|
||||
}
|
||||
#ifdef BOTS
|
||||
else if (Invitee->IsBot()) {
|
||||
Client* inviter = entity_list.GetClientByName(gis->inviter_name);
|
||||
//Bot* invitee = entity_list.GetBotByBotName(gis->invitee_name);
|
||||
if (inviter->IsRaidGrouped())
|
||||
Bot::ProcessRaidInvite(Invitee->CastToBot(), inviter);
|
||||
else
|
||||
Bot::ProcessBotGroupInvite(this, std::string(Invitee->GetName()));
|
||||
}
|
||||
#endif
|
||||
@@ -11419,6 +11451,45 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
case RaidCommandInviteIntoExisting:
|
||||
case RaidCommandInvite: {
|
||||
|
||||
#ifdef BOTS
|
||||
|
||||
Bot* player_to_invite = nullptr;
|
||||
Client* player_to_invite_owner = nullptr;
|
||||
|
||||
if (entity_list.GetBotByBotName(raid_command_packet->player_name)) {
|
||||
Bot* player_to_invite = entity_list.GetBotByBotName(raid_command_packet->player_name);
|
||||
Client* player_to_invite_owner = player_to_invite->GetOwner()->CastToClient();
|
||||
Group* player_to_invite_group = player_to_invite->GetGroup();
|
||||
|
||||
if (!player_to_invite) {
|
||||
break;
|
||||
}
|
||||
|
||||
//Not allowed: Invite a bot that is already within a raid.
|
||||
if (player_to_invite->IsRaidGrouped()) {
|
||||
MessageString(Chat::White, ALREADY_IN_RAID, GetName()); //must invite members not in raid...
|
||||
return;
|
||||
}
|
||||
|
||||
// Not allowed: Invite a bot that is not owned by the invitor
|
||||
if (player_to_invite->IsBot() &&
|
||||
player_to_invite->CastToBot()->GetOwner()->CastToClient()->CharacterID() !=
|
||||
player_to_invite_owner->CharacterID()) {
|
||||
Message(Chat::Red, "%s is not your Bot. You can only invite your Bots, or players grouped with bots.", player_to_invite->GetName());
|
||||
}
|
||||
|
||||
// Not allowed: Invite a bot that is in a group but the bot is not the group leader
|
||||
if (player_to_invite_group && !player_to_invite_group->IsLeader(player_to_invite->CastToMob())) {
|
||||
Message(Chat::Red, "You can only invite group leaders or ungrouped bots. Try %s instead.", player_to_invite_group->GetLeader()->GetName());
|
||||
break;
|
||||
}
|
||||
|
||||
Bot::ProcessRaidInvite(player_to_invite, player_to_invite_owner);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
Client* player_to_invite = entity_list.GetClientByName(raid_command_packet->player_name);
|
||||
|
||||
if (!player_to_invite)
|
||||
@@ -11435,7 +11506,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
MessageString(Chat::Red, ALREADY_IN_PARTY);
|
||||
break;
|
||||
}
|
||||
|
||||
// Not allowed: Invite a client that is in a group but not the groupleader
|
||||
if (player_to_invite_group && !player_to_invite_group->IsLeader(player_to_invite)) {
|
||||
Message(Chat::Red, "You can only invite an ungrouped player or group leader to join your raid.");
|
||||
break;
|
||||
@@ -11457,8 +11528,64 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
|
||||
break;
|
||||
}
|
||||
#ifdef BOTS
|
||||
}
|
||||
#endif
|
||||
|
||||
case RaidCommandAcceptInvite: {
|
||||
Client* player_accepting_invite = entity_list.GetClientByName(raid_command_packet->player_name);
|
||||
|
||||
#ifdef BOTS
|
||||
// If the accepting client is in a group with a Bot or the invitor is in a group with a Bot, send the invite to Bot:ProcessRaidInvite
|
||||
// instead of remaining here.
|
||||
Bot* b = nullptr;
|
||||
Client* invitee = entity_list.GetClientByName(raid_command_packet->leader_name);
|
||||
Client* invitor = entity_list.GetClientByName(raid_command_packet->player_name);
|
||||
Group* g_invitee = invitee->GetGroup();
|
||||
Group* g_invitor = invitor->GetGroup();
|
||||
|
||||
if (invitee && invitee->IsRaidGrouped()) {
|
||||
invitor->MessageString(Chat::White, ALREADY_IN_RAID, GetName()); //group failed, must invite members not in raid...
|
||||
return;
|
||||
}
|
||||
|
||||
bool invitor_has_bot = false;
|
||||
bool invitee_has_bot = false;
|
||||
|
||||
if (g_invitor && g_invitor->IsLeader(invitor))
|
||||
{
|
||||
for (int x = 0; x < 6; x++)
|
||||
{
|
||||
if (g_invitor->members[x] && g_invitor->members[x]->IsBot())
|
||||
{
|
||||
b = entity_list.GetBotByBotName(g_invitor->members[x]->GetName());
|
||||
invitee_has_bot = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (g_invitee && g_invitee->IsLeader(invitee))
|
||||
{
|
||||
for (int x = 0; x < 6; x++)
|
||||
{
|
||||
if (g_invitee->members[x] && g_invitee->members[x]->IsBot())
|
||||
{
|
||||
b = entity_list.GetBotByBotName(g_invitee->members[x]->GetName());
|
||||
invitee_has_bot = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (invitor_has_bot || invitee_has_bot) {
|
||||
Bot::ProcessRaidInvite(invitee, invitor); //two clients with one or both having groups with bots
|
||||
break;
|
||||
}
|
||||
else if (invitee && invitee->IsBot())
|
||||
{
|
||||
Bot::ProcessRaidInvite(b, player_accepting_invite); //client inviting a bot
|
||||
break;
|
||||
}
|
||||
|
||||
#endif
|
||||
if (player_accepting_invite) {
|
||||
if (IsRaidGrouped()) {
|
||||
player_accepting_invite->MessageString(Chat::White, ALREADY_IN_RAID, GetName()); //group failed, must invite members not in raid...
|
||||
@@ -11728,9 +11855,90 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
}
|
||||
case RaidCommandDisband: {
|
||||
Raid* raid = entity_list.GetRaidByClient(this);
|
||||
Client* c_to_disband = entity_list.GetClientByName(raid_command_packet->leader_name);
|
||||
Client* c_doing_disband = entity_list.GetClientByName(raid_command_packet->player_name);
|
||||
#ifdef BOTS
|
||||
Bot* b_to_disband = entity_list.GetBotByBotName(raid_command_packet->leader_name);
|
||||
#endif
|
||||
|
||||
if (raid) {
|
||||
uint32 group = raid->GetGroup(raid_command_packet->leader_name);
|
||||
|
||||
#ifdef BOTS
|
||||
//Added to remove all bots if the Bot_Owner is removed from the Raid
|
||||
//Does not camp the Bots, just removes from the raid
|
||||
std::vector<Bot*> raid_members_bots;
|
||||
if (c_to_disband)
|
||||
{
|
||||
// Determine if the client has any BOTS in the raid
|
||||
uint32 owner_id = c_to_disband->CharacterID();
|
||||
for (int i = 0; i < MAX_RAID_MEMBERS; ++i)
|
||||
{
|
||||
if (raid->members[i].member && raid->members[i].member->IsBot() && raid->members[i].member->CastToBot()->GetOwner()->CastToClient()->CharacterID() == owner_id)
|
||||
{
|
||||
raid_members_bots.emplace_back(raid->members[i].member->CastToBot());
|
||||
}
|
||||
}
|
||||
// If any of the bots are a group leader then re-create the botgroup on disband, dropping any clients
|
||||
for (auto bot_iter : raid_members_bots) {
|
||||
if (bot_iter && raid->IsRaidMember(bot_iter->GetName()) && raid->IsGroupLeader(bot_iter->GetName()))
|
||||
{
|
||||
// Remove the entire BOT group in this case
|
||||
uint32 gid = raid->GetGroup(bot_iter->GetName());
|
||||
|
||||
std::vector<RaidMember> r_group_members = raid->GetRaidGroupMembers(gid);
|
||||
Group* group_inst = new Group(bot_iter);
|
||||
entity_list.AddGroup(group_inst);
|
||||
database.SetGroupID(bot_iter->GetCleanName(), group_inst->GetID(), bot_iter->GetBotID());
|
||||
database.SetGroupLeaderName(group_inst->GetID(), bot_iter->GetCleanName());
|
||||
for (auto member_iter : r_group_members) {
|
||||
if (!member_iter.member->IsClient() && strcmp(member_iter.membername, bot_iter->GetName()) == 0)
|
||||
bot_iter->SetFollowID(owner_id);
|
||||
|
||||
else
|
||||
Bot::AddBotToGroup(member_iter.member->CastToBot(), group_inst);
|
||||
raid->RemoveMember(bot_iter->GetName());
|
||||
}
|
||||
}
|
||||
else if (bot_iter && raid->IsRaidMember(bot_iter->GetName()))
|
||||
{
|
||||
raid->RemoveMember(bot_iter->GetName());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (b_to_disband)
|
||||
{
|
||||
uint32 gid = raid->GetGroup(b_to_disband->GetName());
|
||||
if (gid < 12 && raid->IsGroupLeader(b_to_disband->GetName()))
|
||||
{
|
||||
// If any of the bots are a group leader then re-create the botgroup on disband, dropping any clients
|
||||
std::vector<RaidMember> r_group_members = raid->GetRaidGroupMembers(gid);
|
||||
uint32 owner_id = b_to_disband->CastToBot()->GetOwner()->CastToClient()->CharacterID();
|
||||
if (raid->IsGroupLeader(b_to_disband->GetName()))
|
||||
{
|
||||
// Remove the entire BOT group in this case
|
||||
Group* group_inst = new Group(b_to_disband);
|
||||
entity_list.AddGroup(group_inst);
|
||||
database.SetGroupID(b_to_disband->GetCleanName(), group_inst->GetID(), b_to_disband->GetBotID());
|
||||
database.SetGroupLeaderName(group_inst->GetID(), b_to_disband->GetCleanName());
|
||||
for (auto member_iter : r_group_members) {
|
||||
if (!member_iter.member->IsClient() && strcmp(member_iter.membername, b_to_disband->GetName()) == 0)
|
||||
b_to_disband->SetFollowID(owner_id);
|
||||
else
|
||||
Bot::AddBotToGroup(member_iter.member->CastToBot(), group_inst);
|
||||
raid->RemoveMember(member_iter.member->CastToBot()->GetName());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (gid <12 && raid->GetGroupLeader(gid)->IsBot())
|
||||
{
|
||||
c_doing_disband->Message(Chat::Yellow, "%s is in a Bot Group. Please disband %s instead to remove the entire Bot group.",
|
||||
raid_command_packet->leader_name, raid->GetGroupLeader(gid)->CastToBot()->GetName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (group < 12) {
|
||||
uint32 i = raid->GetPlayerIndex(raid_command_packet->leader_name);
|
||||
if (raid->members[i].IsGroupLeader) { //assign group leader to someone else
|
||||
@@ -11758,11 +11966,12 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
raid->RemoveMember(raid_command_packet->leader_name);
|
||||
Client* c = entity_list.GetClientByName(raid_command_packet->leader_name);
|
||||
if (c)
|
||||
if (c) {
|
||||
|
||||
raid->SendGroupDisband(c);
|
||||
}
|
||||
else {
|
||||
auto pack =
|
||||
new ServerPacket(ServerOP_RaidGroupDisband, sizeof(ServerRaidGeneralAction_Struct));
|
||||
@@ -11776,7 +11985,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
}
|
||||
//r->SendRaidGroupRemove(ri->leader_name, grp);
|
||||
raid->GroupUpdate(group);// break
|
||||
//}
|
||||
if (!raid->RaidCount())
|
||||
raid->DisbandRaid();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2161,6 +2161,50 @@ Raid *EntityList::GetRaidByClient(Client* client)
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
#ifdef BOTS
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BOTS
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
Raid *EntityList::GetRaidByMob(Mob *mob)
|
||||
{
|
||||
|
||||
@@ -200,6 +200,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);
|
||||
|
||||
@@ -1097,7 +1097,11 @@ void Raid::SplitExp(uint32 exp, Mob* other) {
|
||||
return;
|
||||
|
||||
for (unsigned int x = 0; x < MAX_RAID_MEMBERS; x++) {
|
||||
#ifdef BOTS
|
||||
if (members[x].member != nullptr && !members[x].IsBot) // If Group Member is Client
|
||||
#else
|
||||
if (members[x].member != nullptr) // If Group Member is Client
|
||||
#endif
|
||||
{
|
||||
Client *cmember = members[x].member;
|
||||
// add exp + exp cap
|
||||
|
||||
+56
-2
@@ -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)
|
||||
{
|
||||
#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') {
|
||||
@@ -1196,6 +1249,7 @@ void Group::VerifyGroup() {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if(them != nullptr && members[i] != them) { //our pointer is out of date... not so good.
|
||||
#if EQDEBUG >= 5
|
||||
LogDebug("Member of group [{}] named [{}] had an out of date pointer!!", (unsigned long)GetID(), membername[i]);
|
||||
|
||||
@@ -88,6 +88,7 @@ volatile bool RunLoops = true;
|
||||
#endif
|
||||
|
||||
extern volatile bool is_zone_loaded;
|
||||
extern bool Critical = false;
|
||||
|
||||
EntityList entity_list;
|
||||
WorldServer worldserver;
|
||||
|
||||
+184
-2
@@ -24,6 +24,7 @@
|
||||
#include "groups.h"
|
||||
#include "mob.h"
|
||||
#include "raids.h"
|
||||
#include "bot.h"
|
||||
|
||||
#include "worldserver.h"
|
||||
|
||||
@@ -95,12 +96,21 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo
|
||||
if(!c)
|
||||
return;
|
||||
|
||||
#ifdef BOTS
|
||||
std::string query = StringFormat("INSERT INTO raid_members SET raidid = %lu, charid = %lu, "
|
||||
"groupid = %lu, _class = %d, level = %d, name = '%s', "
|
||||
"isgroupleader = %d, israidleader = %d, islooter = %d, isbot = 0",
|
||||
(unsigned long)GetID(), (unsigned long)c->CharacterID(),
|
||||
(unsigned long)group, c->GetClass(), c->GetLevel(),
|
||||
c->GetName(), groupleader, rleader, looter);
|
||||
#else
|
||||
std::string query = StringFormat("INSERT INTO raid_members SET raidid = %lu, charid = %lu, "
|
||||
"groupid = %lu, _class = %d, level = %d, name = '%s', "
|
||||
"isgroupleader = %d, israidleader = %d, islooter = %d",
|
||||
(unsigned long)GetID(), (unsigned long)c->CharacterID(),
|
||||
(unsigned long)group, c->GetClass(), c->GetLevel(),
|
||||
c->GetName(), groupleader, rleader, looter);
|
||||
#endif
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
if(!results.Success()) {
|
||||
@@ -109,6 +119,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();
|
||||
@@ -163,12 +181,65 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
#ifdef BOTS
|
||||
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();
|
||||
|
||||
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;
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
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);
|
||||
#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);
|
||||
@@ -999,6 +1070,7 @@ void Raid::SendRaidAddAll(const char *who)
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1111,9 +1183,14 @@ void Raid::SendBulkRaid(Client *to)
|
||||
if(!to)
|
||||
return;
|
||||
|
||||
#ifdef BOTS
|
||||
if (members[GetPlayerIndex(to)].IsBot)
|
||||
return;
|
||||
#endif
|
||||
|
||||
for(int x = 0; x < MAX_RAID_MEMBERS; x++)
|
||||
{
|
||||
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);
|
||||
}
|
||||
@@ -1124,7 +1201,11 @@ void Raid::QueuePacket(const EQApplicationPacket *app, bool ack_req)
|
||||
{
|
||||
for(int x = 0; x < MAX_RAID_MEMBERS; x++)
|
||||
{
|
||||
#ifdef BOTS
|
||||
if(members[x].member && !members[x].IsBot)
|
||||
#else
|
||||
if(members[x].member)
|
||||
#endif
|
||||
{
|
||||
members[x].member->QueuePacket(app, ack_req);
|
||||
}
|
||||
@@ -1133,6 +1214,12 @@ void Raid::QueuePacket(const EQApplicationPacket *app, bool ack_req)
|
||||
|
||||
void Raid::SendMakeLeaderPacket(const char *who) //30
|
||||
{
|
||||
|
||||
#ifdef BOTS
|
||||
if (entity_list.GetBotByBotName(who) && members[GetPlayerIndex(who)].IsBot)
|
||||
return;
|
||||
#endif
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct));
|
||||
RaidLeadershipUpdate_Struct *rg = (RaidLeadershipUpdate_Struct*)outapp->pBuffer;
|
||||
rg->action = raidMakeLeader;
|
||||
@@ -1148,6 +1235,11 @@ void Raid::SendMakeLeaderPacketTo(const char *who, Client *to)
|
||||
if(!to)
|
||||
return;
|
||||
|
||||
#ifdef BOTS
|
||||
if (members[GetPlayerIndex(who)].IsBot)
|
||||
return;
|
||||
#endif
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct));
|
||||
RaidLeadershipUpdate_Struct *rg = (RaidLeadershipUpdate_Struct*)outapp->pBuffer;
|
||||
rg->action = raidMakeLeader;
|
||||
@@ -1178,6 +1270,11 @@ void Raid::SendGroupUpdate(Client *to)
|
||||
if(!to)
|
||||
return;
|
||||
|
||||
#ifdef BOTS
|
||||
if (members[GetPlayerIndex(to)].IsBot)
|
||||
return;
|
||||
#endif
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupUpdate2_Struct));
|
||||
GroupUpdate2_Struct* gu = (GroupUpdate2_Struct*)outapp->pBuffer;
|
||||
gu->action = groupActUpdate;
|
||||
@@ -1366,6 +1463,11 @@ void Raid::SendRaidMOTDToWorld()
|
||||
|
||||
void Raid::SendGroupLeadershipAA(Client *c, uint32 gid)
|
||||
{
|
||||
#ifdef BOTS
|
||||
if (members[GetPlayerIndex(c)].IsBot)
|
||||
return;
|
||||
#endif
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct));
|
||||
RaidLeadershipUpdate_Struct *rlaa = (RaidLeadershipUpdate_Struct *)outapp->pBuffer;
|
||||
rlaa->action = raidSetLeaderAbilities;
|
||||
@@ -1381,17 +1483,26 @@ void Raid::SendGroupLeadershipAA(Client *c, uint32 gid)
|
||||
void Raid::SendGroupLeadershipAA(uint32 gid)
|
||||
{
|
||||
for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++)
|
||||
#ifdef BOTS
|
||||
if (members[i].member && members[i].GroupNumber == gid && !members[i].IsBot)
|
||||
#else
|
||||
if (members[i].member && members[i].GroupNumber == gid)
|
||||
#endif
|
||||
SendGroupLeadershipAA(members[i].member, gid);
|
||||
}
|
||||
|
||||
void Raid::SendAllRaidLeadershipAA()
|
||||
{
|
||||
for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++)
|
||||
#ifdef BOTS
|
||||
if (members[i].member && !members[i].IsBot)
|
||||
#else
|
||||
if (members[i].member)
|
||||
#endif
|
||||
SendGroupLeadershipAA(members[i].member, members[i].GroupNumber);
|
||||
}
|
||||
|
||||
|
||||
void Raid::LockRaid(bool lockFlag)
|
||||
{
|
||||
std::string query = StringFormat("UPDATE raid_details SET locked = %d WHERE raidid = %lu",
|
||||
@@ -1457,10 +1568,17 @@ bool Raid::LearnMembers()
|
||||
{
|
||||
memset(members, 0, (sizeof(RaidMember)*MAX_RAID_MEMBERS));
|
||||
|
||||
#ifdef BOTS
|
||||
std::string query = StringFormat("SELECT name, groupid, _class, level, "
|
||||
"isgroupleader, israidleader, islooter, isbot "
|
||||
"FROM raid_members WHERE raidid = %lu",
|
||||
(unsigned long)GetID());
|
||||
#else
|
||||
std::string query = StringFormat("SELECT name, groupid, _class, level, "
|
||||
"isgroupleader, israidleader, islooter "
|
||||
"FROM raid_members WHERE raidid = %lu",
|
||||
(unsigned long)GetID());
|
||||
#endif
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
@@ -1489,6 +1607,9 @@ bool Raid::LearnMembers()
|
||||
members[index].IsGroupLeader = atoi(row[4]);
|
||||
members[index].IsRaidLeader = atoi(row[5]);
|
||||
members[index].IsLooter = atoi(row[6]);
|
||||
#ifdef BOTS
|
||||
members[index].IsBot = atoi(row[7]);
|
||||
#endif
|
||||
++index;
|
||||
}
|
||||
|
||||
@@ -1504,11 +1625,29 @@ void Raid::VerifyRaid()
|
||||
}
|
||||
else{
|
||||
Client *c = entity_list.GetClientByName(members[x].membername);
|
||||
#ifdef BOTS
|
||||
Bot* b = entity_list.GetBotByBotName(members[x].membername);
|
||||
#endif
|
||||
if(c){
|
||||
members[x].member = c;
|
||||
#ifdef BOTS
|
||||
members[x].IsBot = false;
|
||||
#endif
|
||||
}
|
||||
#ifdef BOTS
|
||||
else if(b){
|
||||
//Raid requires client* we are forcing it here to be a BOT. Care is needed here as any client function that
|
||||
//does not exist within the Bot Class will likely corrupt memory for the member object. Good practice to test the IsBot
|
||||
//attribute before calling a client function or casting to client.
|
||||
members[x].member = b->CastToClient();
|
||||
members[x].IsBot = true; //Used to identify those members who are Bots
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
members[x].member = nullptr;
|
||||
#ifdef BOTS
|
||||
members[x].IsBot = false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if(members[x].IsRaidLeader){
|
||||
@@ -1561,7 +1700,11 @@ void Raid::SendHPManaEndPacketsTo(Client *client)
|
||||
EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct));
|
||||
|
||||
for(int x = 0; x < MAX_RAID_MEMBERS; x++) {
|
||||
#ifdef BOTS
|
||||
if(members[x].member && !members[x].IsBot) {
|
||||
#else
|
||||
if (members[x].member) {
|
||||
#endif
|
||||
if((members[x].member != client) && (members[x].GroupNumber == group_id)) {
|
||||
|
||||
members[x].member->CreateHPPacket(&hp_packet);
|
||||
@@ -1603,7 +1746,11 @@ void Raid::SendHPManaEndPacketsFrom(Mob *mob)
|
||||
mob->CreateHPPacket(&hpapp);
|
||||
|
||||
for(int x = 0; x < MAX_RAID_MEMBERS; x++) {
|
||||
#ifdef BOTS
|
||||
if(members[x].member && !members[x].IsBot) {
|
||||
#else
|
||||
if (members[x].member) {
|
||||
#endif
|
||||
if(!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) {
|
||||
members[x].member->QueuePacket(&hpapp, false);
|
||||
if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) {
|
||||
@@ -1636,7 +1783,11 @@ void Raid::SendManaPacketFrom(Mob *mob)
|
||||
EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct));
|
||||
|
||||
for (int x = 0; x < MAX_RAID_MEMBERS; x++) {
|
||||
#ifdef BOTS
|
||||
if (members[x].member && !members[x].IsBot) {
|
||||
#else
|
||||
if (members[x].member) {
|
||||
#endif
|
||||
if (!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) {
|
||||
if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) {
|
||||
outapp.SetOpcode(OP_MobManaUpdate);
|
||||
@@ -1663,7 +1814,11 @@ void Raid::SendEndurancePacketFrom(Mob *mob)
|
||||
EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct));
|
||||
|
||||
for (int x = 0; x < MAX_RAID_MEMBERS; x++) {
|
||||
#ifdef BTOS
|
||||
if (members[x].member && !members[x].IsBot) {
|
||||
#else
|
||||
if (members[x].member) {
|
||||
#endif
|
||||
if (!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) {
|
||||
if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) {
|
||||
outapp.SetOpcode(OP_MobEnduranceUpdate);
|
||||
@@ -1770,9 +1925,18 @@ void Raid::CheckGroupMentor(uint32 group_id, Client *c)
|
||||
void Raid::SetDirtyAutoHaters()
|
||||
{
|
||||
for (int i = 0; i < MAX_RAID_MEMBERS; ++i)
|
||||
#ifdef BOTS
|
||||
if (members[i].member && members[i].IsBot)
|
||||
{
|
||||
members[i].member->CastToBot()->SetDirtyAutoHaters();
|
||||
}
|
||||
else if (members[i].member && !members[i].IsBot)
|
||||
#else
|
||||
if (members[i].member)
|
||||
#endif
|
||||
{
|
||||
members[i].member->SetDirtyAutoHaters();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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,10 @@ void Raid::QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_re
|
||||
if (!members[i].member->IsClient())
|
||||
continue;
|
||||
|
||||
#ifdef BOTS
|
||||
if (members[i].IsBot)
|
||||
continue;
|
||||
#endif
|
||||
if (ignore_sender && members[i].member == sender)
|
||||
continue;
|
||||
|
||||
@@ -1853,3 +2021,17 @@ bool Raid::DoesAnyMemberHaveExpeditionLockout(
|
||||
return Expedition::HasLockoutByCharacterName(raid_member.membername, expedition_name, event_name);
|
||||
});
|
||||
}
|
||||
#ifdef BOTS
|
||||
Mob* Raid::GetRaidMainAssistOneByName(const char* name)
|
||||
{
|
||||
Raid* raid = entity_list.GetRaidByBotName(name);
|
||||
std::vector<RaidMember> raid_members = raid->GetMembers();
|
||||
|
||||
for (RaidMember iter : raid_members)
|
||||
{
|
||||
if (iter.IsRaidMainAssistOne)
|
||||
return iter.member->CastToMob();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -88,6 +88,10 @@ struct RaidMember{
|
||||
bool IsGroupLeader;
|
||||
bool IsRaidLeader;
|
||||
bool IsLooter;
|
||||
#ifdef BOTS
|
||||
bool IsBot = false;
|
||||
bool IsRaidMainAssistOne = false;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct GroupMentor {
|
||||
@@ -112,6 +116,11 @@ 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);
|
||||
void RaidBotGroupSay(Bot* b, uint8 language, uint8 lang_skill, const char* msg, ...); //Not yet implemented
|
||||
Mob* GetRaidMainAssistOneByName(const char* name);
|
||||
#endif
|
||||
void RemoveMember(const char *c);
|
||||
void DisbandRaid();
|
||||
void MoveMember(const char *name, uint32 newGroup);
|
||||
@@ -122,6 +131,7 @@ public:
|
||||
bool IsRaidMember(const char *name);
|
||||
void UpdateLevel(const char *name, int newLevel);
|
||||
|
||||
|
||||
uint32 GetFreeGroup();
|
||||
uint8 GroupCount(uint32 gid);
|
||||
uint8 RaidCount();
|
||||
@@ -241,6 +251,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];
|
||||
|
||||
+1
-1
@@ -154,7 +154,7 @@ bool Spawn2::Process() {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (timer.Check()) {
|
||||
if (timer.Check() && zone->spawn2_timer.Enabled()) {
|
||||
timer.Disable();
|
||||
|
||||
LogSpawns("Spawn2 [{}]: Timer has triggered", spawn2_id);
|
||||
|
||||
@@ -1742,6 +1742,7 @@ bool Zone::Depop(bool StartSpawnTimer) {
|
||||
itr = npctable.begin();
|
||||
delete itr->second;
|
||||
itr->second = nullptr;
|
||||
|
||||
npctable.erase(itr);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user