mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 06:21:28 +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 8523658d3bacdc068bcafaa652d2100afecddfc2. * 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:
parent
e778041198
commit
45da8cab61
@ -16,11 +16,14 @@
|
||||
#include "../../strings.h"
|
||||
#include <ctime>
|
||||
|
||||
|
||||
class BaseRaidMembersRepository {
|
||||
public:
|
||||
struct RaidMembers {
|
||||
uint64_t id;
|
||||
int32_t raidid;
|
||||
int32_t charid;
|
||||
int32_t bot_id;
|
||||
uint32_t groupid;
|
||||
int8_t _class;
|
||||
int8_t level;
|
||||
@ -32,14 +35,16 @@ public:
|
||||
|
||||
static std::string PrimaryKey()
|
||||
{
|
||||
return std::string("charid");
|
||||
return std::string("id");
|
||||
}
|
||||
|
||||
static std::vector<std::string> Columns()
|
||||
{
|
||||
return {
|
||||
"id",
|
||||
"raidid",
|
||||
"charid",
|
||||
"bot_id",
|
||||
"groupid",
|
||||
"_class",
|
||||
"level",
|
||||
@ -53,8 +58,10 @@ public:
|
||||
static std::vector<std::string> SelectColumns()
|
||||
{
|
||||
return {
|
||||
"id",
|
||||
"raidid",
|
||||
"charid",
|
||||
"bot_id",
|
||||
"groupid",
|
||||
"_class",
|
||||
"level",
|
||||
@ -102,8 +109,10 @@ public:
|
||||
{
|
||||
RaidMembers e{};
|
||||
|
||||
e.id = 0;
|
||||
e.raidid = 0;
|
||||
e.charid = 0;
|
||||
e.bot_id = 0;
|
||||
e.groupid = 0;
|
||||
e._class = 0;
|
||||
e.level = 0;
|
||||
@ -121,7 +130,7 @@ public:
|
||||
)
|
||||
{
|
||||
for (auto &raid_members : raid_memberss) {
|
||||
if (raid_members.charid == raid_members_id) {
|
||||
if (raid_members.id == raid_members_id) {
|
||||
return raid_members;
|
||||
}
|
||||
}
|
||||
@ -136,8 +145,9 @@ public:
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
"{} WHERE {} = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
PrimaryKey(),
|
||||
raid_members_id
|
||||
)
|
||||
);
|
||||
@ -146,15 +156,17 @@ public:
|
||||
if (results.RowCount() == 1) {
|
||||
RaidMembers e{};
|
||||
|
||||
e.raidid = static_cast<int32_t>(atoi(row[0]));
|
||||
e.charid = static_cast<int32_t>(atoi(row[1]));
|
||||
e.groupid = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
|
||||
e._class = static_cast<int8_t>(atoi(row[3]));
|
||||
e.level = static_cast<int8_t>(atoi(row[4]));
|
||||
e.name = row[5] ? row[5] : "";
|
||||
e.isgroupleader = static_cast<int8_t>(atoi(row[6]));
|
||||
e.israidleader = static_cast<int8_t>(atoi(row[7]));
|
||||
e.islooter = static_cast<int8_t>(atoi(row[8]));
|
||||
e.id = strtoull(row[0], nullptr, 10);
|
||||
e.raidid = static_cast<int32_t>(atoi(row[1]));
|
||||
e.charid = static_cast<int32_t>(atoi(row[2]));
|
||||
e.bot_id = static_cast<int32_t>(atoi(row[3]));
|
||||
e.groupid = static_cast<uint32_t>(strtoul(row[4], nullptr, 10));
|
||||
e._class = static_cast<int8_t>(atoi(row[5]));
|
||||
e.level = static_cast<int8_t>(atoi(row[6]));
|
||||
e.name = row[7] ? row[7] : "";
|
||||
e.isgroupleader = static_cast<int8_t>(atoi(row[8]));
|
||||
e.israidleader = static_cast<int8_t>(atoi(row[9]));
|
||||
e.islooter = static_cast<int8_t>(atoi(row[10]));
|
||||
|
||||
return e;
|
||||
}
|
||||
@ -188,15 +200,16 @@ public:
|
||||
|
||||
auto columns = Columns();
|
||||
|
||||
v.push_back(columns[0] + " = " + std::to_string(e.raidid));
|
||||
v.push_back(columns[1] + " = " + std::to_string(e.charid));
|
||||
v.push_back(columns[2] + " = " + std::to_string(e.groupid));
|
||||
v.push_back(columns[3] + " = " + std::to_string(e._class));
|
||||
v.push_back(columns[4] + " = " + std::to_string(e.level));
|
||||
v.push_back(columns[5] + " = '" + Strings::Escape(e.name) + "'");
|
||||
v.push_back(columns[6] + " = " + std::to_string(e.isgroupleader));
|
||||
v.push_back(columns[7] + " = " + std::to_string(e.israidleader));
|
||||
v.push_back(columns[8] + " = " + std::to_string(e.islooter));
|
||||
v.push_back(columns[1] + " = " + std::to_string(e.raidid));
|
||||
v.push_back(columns[2] + " = " + std::to_string(e.charid));
|
||||
v.push_back(columns[3] + " = " + std::to_string(e.bot_id));
|
||||
v.push_back(columns[4] + " = " + std::to_string(e.groupid));
|
||||
v.push_back(columns[5] + " = " + std::to_string(e._class));
|
||||
v.push_back(columns[6] + " = " + std::to_string(e.level));
|
||||
v.push_back(columns[7] + " = '" + Strings::Escape(e.name) + "'");
|
||||
v.push_back(columns[8] + " = " + std::to_string(e.isgroupleader));
|
||||
v.push_back(columns[9] + " = " + std::to_string(e.israidleader));
|
||||
v.push_back(columns[10] + " = " + std::to_string(e.islooter));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@ -204,7 +217,7 @@ public:
|
||||
TableName(),
|
||||
Strings::Implode(", ", v),
|
||||
PrimaryKey(),
|
||||
e.charid
|
||||
e.id
|
||||
)
|
||||
);
|
||||
|
||||
@ -218,8 +231,10 @@ public:
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.raidid));
|
||||
v.push_back(std::to_string(e.charid));
|
||||
v.push_back(std::to_string(e.bot_id));
|
||||
v.push_back(std::to_string(e.groupid));
|
||||
v.push_back(std::to_string(e._class));
|
||||
v.push_back(std::to_string(e.level));
|
||||
@ -237,7 +252,7 @@ public:
|
||||
);
|
||||
|
||||
if (results.Success()) {
|
||||
e.charid = results.LastInsertedID();
|
||||
e.id = results.LastInsertedID();
|
||||
return e;
|
||||
}
|
||||
|
||||
@ -256,8 +271,10 @@ public:
|
||||
for (auto &e: entries) {
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.raidid));
|
||||
v.push_back(std::to_string(e.charid));
|
||||
v.push_back(std::to_string(e.bot_id));
|
||||
v.push_back(std::to_string(e.groupid));
|
||||
v.push_back(std::to_string(e._class));
|
||||
v.push_back(std::to_string(e.level));
|
||||
@ -298,15 +315,17 @@ public:
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
RaidMembers e{};
|
||||
|
||||
e.raidid = static_cast<int32_t>(atoi(row[0]));
|
||||
e.charid = static_cast<int32_t>(atoi(row[1]));
|
||||
e.groupid = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
|
||||
e._class = static_cast<int8_t>(atoi(row[3]));
|
||||
e.level = static_cast<int8_t>(atoi(row[4]));
|
||||
e.name = row[5] ? row[5] : "";
|
||||
e.isgroupleader = static_cast<int8_t>(atoi(row[6]));
|
||||
e.israidleader = static_cast<int8_t>(atoi(row[7]));
|
||||
e.islooter = static_cast<int8_t>(atoi(row[8]));
|
||||
e.id = strtoull(row[0], nullptr, 10);
|
||||
e.raidid = static_cast<int32_t>(atoi(row[1]));
|
||||
e.charid = static_cast<int32_t>(atoi(row[2]));
|
||||
e.bot_id = static_cast<int32_t>(atoi(row[3]));
|
||||
e.groupid = static_cast<uint32_t>(strtoul(row[4], nullptr, 10));
|
||||
e._class = static_cast<int8_t>(atoi(row[5]));
|
||||
e.level = static_cast<int8_t>(atoi(row[6]));
|
||||
e.name = row[7] ? row[7] : "";
|
||||
e.isgroupleader = static_cast<int8_t>(atoi(row[8]));
|
||||
e.israidleader = static_cast<int8_t>(atoi(row[9]));
|
||||
e.islooter = static_cast<int8_t>(atoi(row[10]));
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@ -331,15 +350,17 @@ public:
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
RaidMembers e{};
|
||||
|
||||
e.raidid = static_cast<int32_t>(atoi(row[0]));
|
||||
e.charid = static_cast<int32_t>(atoi(row[1]));
|
||||
e.groupid = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
|
||||
e._class = static_cast<int8_t>(atoi(row[3]));
|
||||
e.level = static_cast<int8_t>(atoi(row[4]));
|
||||
e.name = row[5] ? row[5] : "";
|
||||
e.isgroupleader = static_cast<int8_t>(atoi(row[6]));
|
||||
e.israidleader = static_cast<int8_t>(atoi(row[7]));
|
||||
e.islooter = static_cast<int8_t>(atoi(row[8]));
|
||||
e.id = strtoull(row[0], nullptr, 10);
|
||||
e.raidid = static_cast<int32_t>(atoi(row[1]));
|
||||
e.charid = static_cast<int32_t>(atoi(row[2]));
|
||||
e.bot_id = static_cast<int32_t>(atoi(row[3]));
|
||||
e.groupid = static_cast<uint32_t>(strtoul(row[4], nullptr, 10));
|
||||
e._class = static_cast<int8_t>(atoi(row[5]));
|
||||
e.level = static_cast<int8_t>(atoi(row[6]));
|
||||
e.name = row[7] ? row[7] : "";
|
||||
e.isgroupleader = static_cast<int8_t>(atoi(row[8]));
|
||||
e.israidleader = static_cast<int8_t>(atoi(row[9]));
|
||||
e.islooter = static_cast<int8_t>(atoi(row[10]));
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
|
||||
@ -99,8 +99,9 @@ public:
|
||||
}
|
||||
}
|
||||
~Seperator() {
|
||||
for (int i=0; i<=maxargnum; i++)
|
||||
for (int i=0; i<=maxargnum; i++) {
|
||||
safe_delete_array(arg[i]);
|
||||
}
|
||||
safe_delete_array(arg);
|
||||
safe_delete_array(argplus);
|
||||
safe_delete_array(msg);
|
||||
|
||||
@ -42,7 +42,8 @@
|
||||
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||
*/
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9224
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9225
|
||||
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9038
|
||||
|
||||
#endif
|
||||
|
||||
@ -478,6 +478,7 @@
|
||||
9222|2023_02_28_npc_scaling_zone_list_version_list.sql|SHOW COLUMNS FROM `npc_scale_global_base` LIKE 'zone_id_list'|empty|
|
||||
9223|2023_03_04_npc_scale_global_base_heroic_strikethrough.sql|SHOW COLUMNS FROM `npc_scale_global_base` LIKE 'heroic_strikethrough'|empty|
|
||||
9224|2023_03_08_npc_scale_global_base_avoidance.sql|SHOW COLUMNS FROM `npc_scale_global_base` LIKE 'hp_regen_per_second'|empty|
|
||||
9225|2023_01_21_bots_raid_members.sql|SHOW COLUMNS FROM `raid_members` LIKE 'botid'|empty|
|
||||
|
||||
# Upgrade conditions:
|
||||
# This won't be needed after this system is implemented, but it is used database that are not
|
||||
|
||||
4
utils/sql/git/required/2023_01_21_bots_raid_members.sql
Normal file
4
utils/sql/git/required/2023_01_21_bots_raid_members.sql
Normal file
@ -0,0 +1,4 @@
|
||||
DROP INDEX IF EXISTS `PRIMARY` ON `raid_members`;
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS `UNIQUE` ON `raid_members`(`name`);
|
||||
ALTER TABLE `raid_members` ADD COLUMN `bot_id` int(4) NOT NULL DEFAULT 0 AFTER `charid`;
|
||||
ALTER TABLE `raid_members` ADD COLUMN `id` BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT FIRST;
|
||||
@ -120,8 +120,9 @@ ClientListEntry::~ClientListEntry()
|
||||
Camp(); // updates zoneserver's numplayers
|
||||
client_list.RemoveCLEReferances(this);
|
||||
}
|
||||
for (auto &elem : tell_queue)
|
||||
safe_delete_array(elem);
|
||||
for (auto& elem: tell_queue) {
|
||||
safe_delete_array(elem)
|
||||
};
|
||||
tell_queue.clear();
|
||||
}
|
||||
|
||||
@ -282,8 +283,9 @@ void ClientListEntry::ClearVars(bool iAll)
|
||||
pLFG = 0;
|
||||
gm = 0;
|
||||
pClientVersion = 0;
|
||||
for (auto &elem : tell_queue)
|
||||
safe_delete_array(elem);
|
||||
for (auto& elem: tell_queue) {
|
||||
safe_delete_array(elem)
|
||||
};
|
||||
tell_queue.clear();
|
||||
}
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@ SET(zone_sources
|
||||
beacon.cpp
|
||||
bonuses.cpp
|
||||
bot.cpp
|
||||
bot_raid.cpp
|
||||
bot_command.cpp
|
||||
bot_database.cpp
|
||||
botspellsai.cpp
|
||||
|
||||
@ -3829,11 +3829,11 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
|
||||
} //end `if there is some damage being done and theres anattacker person involved`
|
||||
|
||||
Mob *pet = GetPet();
|
||||
// pets that have GHold will never automatically add NPCs
|
||||
// pets that have Hold and no Focus will add NPCs if they're engaged
|
||||
// pets that have Hold and Focus will not add NPCs
|
||||
if (
|
||||
Mob* pet = GetPet();
|
||||
pet &&
|
||||
!pet->IsFamiliar() &&
|
||||
!pet->GetSpecialAbility(IMMUNE_AGGRO) &&
|
||||
@ -3844,9 +3844,9 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
attacker != this &&
|
||||
!attacker->IsCorpse() &&
|
||||
!pet->IsGHeld() &&
|
||||
!attacker->IsTrap()
|
||||
!attacker->IsTrap() &&
|
||||
!pet->IsHeld()
|
||||
) {
|
||||
if (!pet->IsHeld()) {
|
||||
LogAggro("Sending pet [{}] into battle due to attack", pet->GetName());
|
||||
if (IsClient()) {
|
||||
// if pet was sitting his new mode is follow
|
||||
@ -3864,7 +3864,6 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
pet->SetTarget(attacker);
|
||||
MessageString(Chat::NPCQuestSay, PET_ATTACKING, pet->GetCleanName(), attacker->GetCleanName());
|
||||
}
|
||||
}
|
||||
|
||||
if (GetTempPetCount()) {
|
||||
entity_list.AddTempPetsToHateListOnOwnerDamage(this, attacker, spell_id);
|
||||
@ -3884,9 +3883,18 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
else {
|
||||
int64 origdmg = damage;
|
||||
damage = AffectMagicalDamage(damage, spell_id, iBuffTic, attacker);
|
||||
if (origdmg != damage && attacker && attacker->IsClient()) {
|
||||
if (attacker->CastToClient()->GetFilter(FilterDamageShields) != FilterHide)
|
||||
attacker->Message(Chat::Yellow, "The Spellshield absorbed %d of %d points of damage", origdmg - damage, origdmg);
|
||||
if (
|
||||
origdmg != damage &&
|
||||
attacker &&
|
||||
attacker->IsClient() &&
|
||||
attacker->CastToClient()->GetFilter(FilterDamageShields) != FilterHide
|
||||
) {
|
||||
attacker->Message(
|
||||
Chat::Yellow,
|
||||
"The Spellshield absorbed %d of %d points of damage",
|
||||
origdmg - damage,
|
||||
origdmg
|
||||
);
|
||||
}
|
||||
if (damage == 0 && attacker && origdmg != damage && IsClient()) {
|
||||
//Kayen: Probably need to add a filter for this - Not sure if this msg is correct but there should be a message for spell negate/runes.
|
||||
@ -4212,7 +4220,7 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
//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();
|
||||
@ -4239,6 +4247,7 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
owner->CastToClient()->QueuePacket(outapp, true, CLIENT_CONNECTED, filter);
|
||||
}
|
||||
}
|
||||
|
||||
skip = owner;
|
||||
}
|
||||
else {
|
||||
@ -4385,11 +4394,11 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
spells[spell_id].name /* Message4 */
|
||||
);
|
||||
}
|
||||
} //end packet sending
|
||||
}
|
||||
|
||||
}
|
||||
} //end packet sending
|
||||
|
||||
void Mob::HealDamage(uint64 amount, Mob *caster, uint16 spell_id)
|
||||
void Mob::HealDamage(uint64 amount, Mob* caster, uint16 spell_id)
|
||||
{
|
||||
int64 maxhp = GetMaxHP();
|
||||
int64 curhp = GetHP();
|
||||
@ -4404,15 +4413,16 @@ void Mob::HealDamage(uint64 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),
|
||||
@ -4421,6 +4431,7 @@ void Mob::HealDamage(uint64 amount, Mob *caster, uint16 spell_id)
|
||||
caster->FilteredMessageString(caster, Chat::NonMelee, FilterHealOverTime,
|
||||
YOU_HEAL, GetCleanName(), itoa(acthealed));
|
||||
}
|
||||
|
||||
// message to target
|
||||
if (IsClient() && caster != this) {
|
||||
if (CastToClient()->ClientVersionBit() & EQ::versions::maskSoFAndLater)
|
||||
@ -4435,7 +4446,7 @@ void Mob::HealDamage(uint64 amount, Mob *caster, uint16 spell_id)
|
||||
else { // normal heals
|
||||
FilteredMessageString(caster, Chat::NonMelee, FilterSpellDamage,
|
||||
YOU_HEALED, caster->GetCleanName(), itoa(acthealed));
|
||||
if (caster != this)
|
||||
|
||||
caster->FilteredMessageString(caster, Chat::NonMelee, FilterSpellDamage,
|
||||
YOU_HEAL, GetCleanName(), itoa(acthealed));
|
||||
}
|
||||
@ -4446,10 +4457,12 @@ void Mob::HealDamage(uint64 amount, Mob *caster, uint16 spell_id)
|
||||
}
|
||||
|
||||
if (curhp < maxhp) {
|
||||
if ((curhp + amount) > maxhp)
|
||||
if ((curhp + amount) > maxhp) {
|
||||
curhp = maxhp;
|
||||
else
|
||||
}
|
||||
else {
|
||||
curhp += amount;
|
||||
}
|
||||
SetHP(curhp);
|
||||
|
||||
SendHPUpdate();
|
||||
|
||||
4219
zone/bot.cpp
4219
zone/bot.cpp
File diff suppressed because it is too large
Load Diff
277
zone/bot.h
277
zone/bot.h
@ -33,6 +33,7 @@
|
||||
#include "../common/global_define.h"
|
||||
#include "guild_mgr.h"
|
||||
#include "worldserver.h"
|
||||
#include "raids.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
@ -42,9 +43,6 @@ constexpr uint32 BOT_FOLLOW_DISTANCE_WALK = 1000; // as DSq value (~31.623 units
|
||||
|
||||
constexpr uint32 BOT_KEEP_ALIVE_INTERVAL = 5000; // 5 seconds
|
||||
|
||||
//constexpr uint32 BOT_COMBAT_JITTER_INTERVAL_MIN = 5000; // 5 seconds
|
||||
//constexpr uint32 BOT_COMBAT_JITTER_INTERVAL_MAX = 20000; // 20 seconds
|
||||
|
||||
extern WorldServer worldserver;
|
||||
|
||||
constexpr int BotAISpellRange = 100; // TODO: Write a method that calcs what the bot's spell range is based on spell, equipment, AA, whatever and replace this
|
||||
@ -53,8 +51,6 @@ constexpr int MaxDisciplineTimer = 10;
|
||||
constexpr int DisciplineReuseStart = MaxSpellTimer + 1;
|
||||
constexpr int MaxTimer = MaxSpellTimer + MaxDisciplineTimer;
|
||||
|
||||
|
||||
|
||||
// nHSND negative Healer/Slower/Nuker/Doter
|
||||
// pH positive Healer
|
||||
// pS positive Slower
|
||||
@ -141,13 +137,13 @@ public:
|
||||
void Damage(Mob* from, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1,
|
||||
bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) override;
|
||||
|
||||
bool HasRaid() final { return (GetRaid() ? true : false); }
|
||||
bool HasGroup() final { return (GetGroup() ? true : false); }
|
||||
Raid* GetRaid() final { return entity_list.GetRaidByMob(this); }
|
||||
bool HasRaid() final { return GetRaid() != nullptr; }
|
||||
bool HasGroup() final { return GetGroup() != nullptr; }
|
||||
Raid* GetRaid() final { return entity_list.GetRaidByBot(this); }
|
||||
Group* GetGroup() final { return entity_list.GetGroupByMob(this); }
|
||||
|
||||
// Common, but informal "interfaces" with Client object
|
||||
uint32 CharacterID() { return GetBotID(); } // Just returns the Bot Id
|
||||
uint32 CharacterID() const { return GetBotID(); }
|
||||
inline bool IsInAGuild() const { return (_guildId != GUILD_NONE && _guildId != 0); }
|
||||
inline bool IsInGuild(uint32 in_gid) const { return (in_gid == _guildId && IsInAGuild()); }
|
||||
inline uint32 GuildID() const { return _guildId; }
|
||||
@ -173,20 +169,19 @@ public:
|
||||
int GetHandToHandDamage(void) override;
|
||||
bool TryFinishingBlow(Mob *defender, int64 &damage) override;
|
||||
void DoRiposte(Mob* defender) override;
|
||||
inline int32 GetATK() const override { return ATK + itembonuses.ATK + spellbonuses.ATK + ((GetSTR() + GetSkill(EQ::skills::SkillOffense)) * 9 / 10); }
|
||||
inline int32 GetATK() { return ATK + itembonuses.ATK + spellbonuses.ATK + ((GetSTR() + GetSkill(EQ::skills::SkillOffense)) * 9 / 10); }
|
||||
inline int32 GetATKBonus() const override { return itembonuses.ATK + spellbonuses.ATK; }
|
||||
uint32 GetTotalATK();
|
||||
uint32 GetATKRating();
|
||||
uint16 GetPrimarySkillValue();
|
||||
uint16 MaxSkill(EQ::skills::SkillType skillid, uint16 class_, uint16 level) const;
|
||||
inline uint16 MaxSkill(EQ::skills::SkillType skillid) const { return MaxSkill(skillid, GetClass(), GetLevel()); }
|
||||
inline uint16 MaxSkill(EQ::skills::SkillType skillid) { return MaxSkill(skillid, GetClass(), GetLevel()); }
|
||||
int GetBaseSkillDamage(EQ::skills::SkillType skill, Mob *target = nullptr) override;
|
||||
void DoSpecialAttackDamage(Mob *who, EQ::skills::SkillType skill, int32 max_damage, int32 min_damage = 1, int32 hate_override = -1, int ReuseTime = 10, bool HitChance = false);
|
||||
void TryBackstab(Mob *other,int ReuseTime = 10) override;
|
||||
void RogueBackstab(Mob* other, bool min_damage = false, int ReuseTime = 10) override;
|
||||
void RogueAssassinate(Mob* other) override;
|
||||
void DoClassAttacks(Mob *target, bool IsRiposte=false);
|
||||
bool CanDoSpecialAttack(Mob *other);
|
||||
void CalcBonuses() override;
|
||||
void CalcItemBonuses(StatBonuses* newbon);
|
||||
void AddItemBonuses(const EQ::ItemInstance *inst, StatBonuses* newbon, bool isAug = false, bool isTribute = false, int rec_override = 0);
|
||||
@ -197,7 +192,7 @@ public:
|
||||
bool IsNPC() const override { return false; }
|
||||
Mob* GetOwner() override;
|
||||
Mob* GetOwnerOrSelf() override;
|
||||
inline bool HasOwner() override { return (GetBotOwner() ? true : false); }
|
||||
inline bool HasOwner() override { return GetBotOwner() != nullptr; }
|
||||
int64 CalcMaxMana() override;
|
||||
void SetAttackTimer() override;
|
||||
uint64 GetClassHPFactor();
|
||||
@ -215,36 +210,35 @@ public:
|
||||
void Stand();
|
||||
bool IsSitting() const override;
|
||||
bool IsStanding();
|
||||
int GetWalkspeed() const override { return (int)((float)_GetWalkSpeed() * 1.785714285f); } // 1.25 / 0.7 = 1.7857142857142857142857142857143
|
||||
int GetRunspeed() const override { return (int)((float)_GetRunSpeed() * 1.785714285f); }
|
||||
int GetWalkspeed() { return (int)((float)_GetWalkSpeed() * 1.785714285f); } // 1.25 / 0.7 = 1.7857142857142857142857142857143
|
||||
int GetRunspeed() { return (int)((float)_GetRunSpeed() * 1.785714285f); }
|
||||
void WalkTo(float x, float y, float z) override;
|
||||
void RunTo(float x, float y, float z) override;
|
||||
void StopMoving() override;
|
||||
void StopMoving(float new_heading) override;
|
||||
//bool GetCombatJitterFlag() { return m_combat_jitter_flag; }
|
||||
bool GetGuardFlag() { return m_guard_flag; }
|
||||
|
||||
bool GetGuardFlag() const { return m_guard_flag; }
|
||||
void SetGuardFlag(bool flag = true) { m_guard_flag = flag; }
|
||||
bool GetHoldFlag() { return m_hold_flag; }
|
||||
bool GetHoldFlag() const { return m_hold_flag; }
|
||||
void SetHoldFlag(bool flag = true) { m_hold_flag = flag; }
|
||||
bool GetAttackFlag() { return m_attack_flag; }
|
||||
bool GetAttackFlag() const { return m_attack_flag; }
|
||||
void SetAttackFlag(bool flag = true) { m_attack_flag = flag; }
|
||||
bool GetAttackingFlag() { return m_attacking_flag; }
|
||||
bool GetPullFlag() { return m_pull_flag; }
|
||||
bool GetAttackingFlag() const { return m_attacking_flag; }
|
||||
bool GetPullFlag() const { return m_pull_flag; }
|
||||
void SetPullFlag(bool flag = true) { m_pull_flag = flag; }
|
||||
bool GetPullingFlag() { return m_pulling_flag; }
|
||||
bool GetReturningFlag() { return m_returning_flag; }
|
||||
bool GetPullingFlag() const { return m_pulling_flag; }
|
||||
bool GetReturningFlag() const { return m_returning_flag; }
|
||||
bool UseDiscipline(uint32 spell_id, uint32 target);
|
||||
uint8 GetNumberNeedingHealedInGroup(uint8 hpr, bool includePets);
|
||||
uint8 GetNumberNeedingHealedInGroup(uint8 hpr, bool includePets, Raid* raid);
|
||||
uint8 GetNumberNeedingHealedInRaidGroup(uint8& need_healed, uint8 hpr, bool includePets, Raid* raid);
|
||||
bool GetNeedsCured(Mob *tar);
|
||||
bool GetNeedsHateRedux(Mob *tar);
|
||||
bool HasOrMayGetAggro();
|
||||
void SetDefaultBotStance();
|
||||
void SetSurname(std::string bot_surname);
|
||||
void SetTitle(std::string bot_title);
|
||||
void SetSuffix(std::string bot_suffix);
|
||||
std::string GetSurname() { return _surname; }
|
||||
std::string GetTitle() { return _title; }
|
||||
std::string GetSuffix() { return _suffix; }
|
||||
void SetSurname(std::string_view bot_surname);
|
||||
void SetTitle(std::string_view bot_title);
|
||||
void SetSuffix(std::string_view bot_suffix);
|
||||
std::string GetSurname() const { return _surname; }
|
||||
std::string GetTitle() const { return _title; }
|
||||
std::string GetSuffix() const { return _suffix; }
|
||||
inline virtual int32 GetMaxStat();
|
||||
inline virtual int32 GetMaxResist();
|
||||
inline virtual int32 GetMaxSTR();
|
||||
@ -285,16 +279,15 @@ public:
|
||||
int GroupLeadershipAAHealthRegeneration();
|
||||
int GroupLeadershipAAOffenseEnhancement();
|
||||
void CalcRestState();
|
||||
int64 CalcMaxEndurance(); //This calculates the maximum endurance we can have
|
||||
int64 CalcBaseEndurance(); //Calculates Base End
|
||||
int64 CalcEnduranceRegen(); //Calculates endurance regen used in DoEnduranceRegen()
|
||||
int64 GetEndurance() const {return cur_end;} //This gets our current endurance
|
||||
int64 GetMaxEndurance() const {return max_end;} //This gets our endurance from the last CalcMaxEndurance() call
|
||||
int64 CalcMaxEndurance();
|
||||
int64 CalcBaseEndurance();
|
||||
int64 CalcEnduranceRegen();
|
||||
int64 GetEndurance() const override {return cur_end;}
|
||||
int64 GetMaxEndurance() const override {return max_end;}
|
||||
int64 CalcEnduranceRegenCap();
|
||||
inline uint8 GetEndurancePercent() { return (uint8)((float)cur_end / (float)max_end * 100.0f); }
|
||||
void SetEndurance(int32 newEnd); //This sets the current endurance to the new value
|
||||
void DoEnduranceRegen(); //This Regenerates endurance
|
||||
void DoEnduranceUpkeep(); //does the endurance upkeep
|
||||
inline uint8 GetEndurancePercent() override { return (uint8)((float)cur_end / (float)max_end * 100.0f); }
|
||||
void SetEndurance(int32 newEnd) override;
|
||||
void DoEnduranceUpkeep();
|
||||
|
||||
bool AI_AddBotSpells(uint32 bot_spell_id);
|
||||
void AddSpellToBotList(
|
||||
@ -330,19 +323,20 @@ public:
|
||||
);
|
||||
|
||||
void AI_Bot_Event_SpellCastFinished(bool iCastSucceeded, uint16 slot);
|
||||
|
||||
// AI Methods
|
||||
bool AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes);
|
||||
bool AI_EngagedCastCheck() override;
|
||||
bool AI_PursueCastCheck() override;
|
||||
bool AI_IdleCastCheck() override;
|
||||
bool AIHealRotation(Mob* tar, bool useFastHeals);
|
||||
bool GetPauseAI() { return _pauseAI; }
|
||||
bool GetPauseAI() const { return _pauseAI; }
|
||||
void SetPauseAI(bool pause_flag) { _pauseAI = pause_flag; }
|
||||
uint8 GetStopMeleeLevel() { return _stopMeleeLevel; }
|
||||
uint8 GetStopMeleeLevel() const { return _stopMeleeLevel; }
|
||||
void SetStopMeleeLevel(uint8 level);
|
||||
void SetGuardMode();
|
||||
void SetHoldMode();
|
||||
uint32 GetBotCasterRange() { return m_bot_caster_range; }
|
||||
uint32 GetBotCasterRange() const { return m_bot_caster_range; }
|
||||
bool IsValidSpellRange(uint16 spell_id, Mob const* tar);
|
||||
|
||||
// Bot AI Methods
|
||||
@ -375,7 +369,7 @@ public:
|
||||
bool IsImmuneToSpell(uint16 spell_id, Mob *caster) override;
|
||||
virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction, EQ::spells::CastingSlot slot);
|
||||
virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, EQ::spells::CastingSlot slot = EQ::spells::CastingSlot::Item, int32 casttime = -1, int32 mana_cost = -1,
|
||||
uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, uint32 aa_id = 0);
|
||||
uint32* oSpellWillFinish = nullptr, uint32 item_slot = 0xFFFFFFFF, uint32 aa_id = 0);
|
||||
inline int64 GetFocusEffect(focusType type, uint16 spell_id, Mob *caster = nullptr, bool from_buff_tic = false) override
|
||||
{ return Mob::GetFocusEffect(type, spell_id, caster, from_buff_tic); }
|
||||
inline bool Attack(Mob* other, int Hand = EQ::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false,
|
||||
@ -389,25 +383,29 @@ public:
|
||||
|
||||
bool GetBotOwnerDataBuckets();
|
||||
bool GetBotDataBuckets();
|
||||
bool CheckDataBucket(std::string bucket_name, std::string bucket_value, uint8 bucket_comparison);
|
||||
bool CheckDataBucket(const std::string& bucket_name, const std::string& bucket_value, uint8 bucket_comparison);
|
||||
|
||||
// Bot Equipment & Inventory Class Methods
|
||||
void BotTradeAddItem(const EQ::ItemInstance* inst, uint16 slot_id, std::string* error_message, bool save_to_database = true);
|
||||
void EquipBot(std::string* error_message);
|
||||
bool CheckLoreConflict(const EQ::ItemData* item);
|
||||
void UpdateEquipmentLight() override { m_Light.Type[EQ::lightsource::LightEquipment] = m_inv.FindBrightestLightType(); m_Light.Level[EQ::lightsource::LightEquipment] = EQ::lightsource::TypeToLevel(m_Light.Type[EQ::lightsource::LightEquipment]); }
|
||||
inline EQ::InventoryProfile& GetInv() { return m_inv; }
|
||||
void UpdateEquipmentLight() override
|
||||
{
|
||||
m_Light.Type[EQ::lightsource::LightEquipment] = m_inv.FindBrightestLightType();
|
||||
m_Light.Level[EQ::lightsource::LightEquipment] = EQ::lightsource::TypeToLevel(m_Light.Type[EQ::lightsource::LightEquipment]);
|
||||
}
|
||||
|
||||
inline EQ::InventoryProfile& GetInv() override { return m_inv; }
|
||||
|
||||
// Static Class Methods
|
||||
//static void DestroyBotRaidObjects(Client* client); // Can be removed after bot raids are dumped
|
||||
static Bot* LoadBot(uint32 botID);
|
||||
static uint32 SpawnedBotCount(const uint32 owner_id, uint8 class_id = NO_CLASS);
|
||||
static void LevelBotWithClient(Client* client, uint8 level, bool sendlvlapp);
|
||||
//static bool SetBotOwnerCharacterID(uint32 botID, uint32 botOwnerCharacterID, std::string* error_message);
|
||||
|
||||
static bool IsBotAttackAllowed(Mob* attacker, Mob* target, bool& hasRuleDefined);
|
||||
static Bot* GetBotByBotClientOwnerAndBotName(Client* c, std::string botName);
|
||||
static void ProcessBotGroupInvite(Client* c, std::string botName);
|
||||
static void ProcessBotGroupDisband(Client* c, std::string botName);
|
||||
static Bot* GetBotByBotClientOwnerAndBotName(Client* c, const std::string& botName);
|
||||
static void ProcessBotGroupInvite(Client* c, std::string const& botName);
|
||||
static void ProcessBotGroupDisband(Client* c, const std::string& botName);
|
||||
static void BotOrderCampAll(Client* c, uint8 class_id = NO_CLASS);
|
||||
static void ProcessBotInspectionRequest(Bot* inspectedBot, Client* client);
|
||||
static void LoadAndSpawnAllZonedBots(Client* bot_owner);
|
||||
@ -415,14 +413,21 @@ public:
|
||||
static Bot* GetFirstBotInGroup(Group* group);
|
||||
static void ProcessClientZoneChange(Client* botOwner);
|
||||
static void ProcessBotOwnerRefDelete(Mob* botOwner); // Removes a Client* reference when the Client object is destroyed
|
||||
static void ProcessGuildInvite(Client* guildOfficer, Bot* botToGuild); // Processes a client's request to guild a bot
|
||||
static bool ProcessGuildRemoval(Client* guildOfficer, std::string botName); // Processes a client's request to deguild a bot
|
||||
static int32 GetSpellRecastTimer(Bot *caster, int timer_index);
|
||||
static bool CheckSpellRecastTimers(Bot *caster, int SpellIndex);
|
||||
static int32 GetDisciplineRecastTimer(Bot *caster, int timer_index);
|
||||
static bool CheckDisciplineRecastTimers(Bot *caster, int timer_index);
|
||||
static uint32 GetDisciplineRemainingTime(Bot *caster, int timer_index);
|
||||
|
||||
//Raid methods
|
||||
static void ProcessRaidInvite(Mob* invitee, Client* invitor, bool group_invite = false);
|
||||
static void RemoveBotFromRaid(Bot* bot);
|
||||
inline void SetDirtyAutoHaters() { m_dirtyautohaters = true; }
|
||||
static void CreateBotRaid(Mob* invitee, Client* invitor, bool group_invite, Raid* raid);
|
||||
static void
|
||||
ProcessBotGroupAdd(Group* group, Raid* raid, Client* client = nullptr, bool new_raid = false, bool initial = false);
|
||||
|
||||
|
||||
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);
|
||||
@ -452,8 +457,8 @@ public:
|
||||
static BotSpell GetBestBotSpellForResistDebuff(Bot* botCaster, Mob* target);
|
||||
|
||||
static NPCType *CreateDefaultNPCTypeStructForBot(
|
||||
std::string botName,
|
||||
std::string botLastName,
|
||||
const std::string& botName,
|
||||
const std::string& botLastName,
|
||||
uint8 botLevel,
|
||||
uint16 botRace,
|
||||
uint8 botClass,
|
||||
@ -467,8 +472,8 @@ public:
|
||||
|
||||
// "GET" Class Methods
|
||||
uint32 GetBotID() const { return _botID; }
|
||||
uint32 GetBotOwnerCharacterID() { return _botOwnerCharacterID; }
|
||||
uint32 GetBotSpellID() { return npc_spells_id; }
|
||||
uint32 GetBotOwnerCharacterID() const { return _botOwnerCharacterID; }
|
||||
uint32 GetBotSpellID() const { return npc_spells_id; }
|
||||
Mob* GetBotOwner() { return this->_botOwner; }
|
||||
uint32 GetBotArcheryRange();
|
||||
EQ::ItemInstance* GetBotItem(uint16 slot_id);
|
||||
@ -486,18 +491,12 @@ public:
|
||||
uint8 GetChanceToCastBySpellType(uint32 spellType);
|
||||
bool GetBotEnforceSpellSetting() { return m_enforce_spell_settings; }
|
||||
float GetBotCasterMaxRange(float melee_distance_max);
|
||||
bool IsGroupHealer() { return m_CastingRoles.GroupHealer; }
|
||||
bool IsGroupSlower() { return m_CastingRoles.GroupSlower; }
|
||||
bool IsGroupNuker() { return m_CastingRoles.GroupNuker; }
|
||||
bool IsGroupDoter() { return m_CastingRoles.GroupDoter; }
|
||||
bool IsGroupHealer() const { return m_CastingRoles.GroupHealer; }
|
||||
bool IsGroupSlower() const { return m_CastingRoles.GroupSlower; }
|
||||
bool IsGroupNuker() const { return m_CastingRoles.GroupNuker; }
|
||||
bool IsGroupDoter() const { return m_CastingRoles.GroupDoter; }
|
||||
static void UpdateGroupCastingRoles(const Group* group, bool disband = false);
|
||||
|
||||
//bool IsRaidHealer() { return m_CastingRoles.RaidHealer; }
|
||||
//bool IsRaidSlower() { return m_CastingRoles.RaidSlower; }
|
||||
//bool IsRaidNuker() { return m_CastingRoles.RaidNuker; }
|
||||
//bool IsRaidDoter() { return m_CastingRoles.RaidDoter; }
|
||||
//static void UpdateRaidCastingRoles(const Raid* raid, bool disband = false);
|
||||
|
||||
bool IsBotCaster() { return IsCasterClass(GetClass()); }
|
||||
bool IsBotHybrid() { return IsHybridClass(GetClass()); }
|
||||
bool IsBotINTCaster() { return IsINTCasterClass(GetClass()); }
|
||||
@ -506,7 +505,6 @@ public:
|
||||
bool IsBotFighter() { return IsFighterClass(GetClass()); }
|
||||
bool IsBotNonSpellFighter() { return IsNonSpellFighterClass(GetClass()); }
|
||||
uint8 GetBotClass() { return GetClass(); }
|
||||
bool CanHeal();
|
||||
int GetRawACNoShield(int &shield_ac);
|
||||
|
||||
// new heal rotation code
|
||||
@ -532,8 +530,8 @@ public:
|
||||
|
||||
std::shared_ptr<HealRotation>* MemberOfHealRotation() { return &m_member_of_heal_rotation; }
|
||||
|
||||
bool GetAltOutOfCombatBehavior() { return _altoutofcombatbehavior;}
|
||||
bool GetShowHelm() { return _showhelm; }
|
||||
bool GetAltOutOfCombatBehavior() const { return _altoutofcombatbehavior;}
|
||||
bool GetShowHelm() const { return _showhelm; }
|
||||
inline int32 GetSTR() const override { return STR; }
|
||||
inline int32 GetSTA() const override { return STA; }
|
||||
inline int32 GetDEX() const override { return DEX; }
|
||||
@ -609,7 +607,6 @@ public:
|
||||
void SetBotCharmer(bool c) { _botCharmer = c; }
|
||||
void SetPetChooser(bool p) { _petChooser = p; }
|
||||
void SetBotOwner(Mob* botOwner) { this->_botOwner = botOwner; }
|
||||
// void SetBotOwnerCharacterID(uint32 botOwnerCharacterID) { _botOwnerCharacterID = botOwnerCharacterID; }
|
||||
void SetRangerAutoWeaponSelect(bool enable) { GetClass() == RANGER ? _rangerAutoWeaponSelect = enable : _rangerAutoWeaponSelect = false; }
|
||||
void SetBotStance(EQ::constants::StanceType botStance) {
|
||||
if (botStance >= EQ::constants::stancePassive && botStance <= EQ::constants::stanceBurnAE)
|
||||
@ -650,7 +647,7 @@ public:
|
||||
void SetBotEnforceSpellSetting(bool enforcespellsettings, bool save = false);
|
||||
bool GetBotEnforceSpellSetting() const { return m_enforce_spell_settings; }
|
||||
|
||||
static void SpawnBotGroupByName(Client* c, std::string botgroup_name, uint32 leader_id);
|
||||
static void SpawnBotGroupByName(Client* c, const std::string& botgroup_name, uint32 leader_id);
|
||||
|
||||
std::string CreateSayLink(Client* botOwner, const char* message, const char* name);
|
||||
|
||||
@ -663,8 +660,8 @@ public:
|
||||
// Publicized private functions
|
||||
static NPCType *FillNPCTypeStruct(
|
||||
uint32 botSpellsID,
|
||||
std::string botName,
|
||||
std::string botLastName,
|
||||
const std::string& botName,
|
||||
const std::string& botLastName,
|
||||
uint8 botLevel,
|
||||
uint16 botRace,
|
||||
uint8 botClass,
|
||||
@ -722,43 +719,116 @@ public:
|
||||
// New accessors for BotDatabase access
|
||||
bool DeleteBot();
|
||||
uint32* GetTimers() { return timers; }
|
||||
uint32 GetLastZoneID() { return _lastZoneId; }
|
||||
int32 GetBaseAC() { return _baseAC; }
|
||||
int32 GetBaseATK() { return _baseATK; }
|
||||
int32 GetBaseSTR() { return _baseSTR; }
|
||||
int32 GetBaseSTA() { return _baseSTA; }
|
||||
int32 GetBaseCHA() { return _baseCHA; }
|
||||
int32 GetBaseDEX() { return _baseDEX; }
|
||||
int32 GetBaseINT() { return _baseINT; }
|
||||
int32 GetBaseAGI() { return _baseAGI; }
|
||||
int32 GetBaseWIS() { return _baseWIS; }
|
||||
int32 GetBaseFR() { return _baseFR; }
|
||||
int32 GetBaseCR() { return _baseCR; }
|
||||
int32 GetBaseMR() { return _baseMR; }
|
||||
int32 GetBasePR() { return _basePR; }
|
||||
int32 GetBaseDR() { return _baseDR; }
|
||||
int32 GetBaseCorrup() { return _baseCorrup; }
|
||||
uint32 GetLastZoneID() const { return _lastZoneId; }
|
||||
int32 GetBaseAC() const { return _baseAC; }
|
||||
int32 GetBaseATK() const { return _baseATK; }
|
||||
int32 GetBaseSTR() const { return _baseSTR; }
|
||||
int32 GetBaseSTA() const { return _baseSTA; }
|
||||
int32 GetBaseCHA() const { return _baseCHA; }
|
||||
int32 GetBaseDEX() const { return _baseDEX; }
|
||||
int32 GetBaseINT() const { return _baseINT; }
|
||||
int32 GetBaseAGI() const { return _baseAGI; }
|
||||
int32 GetBaseWIS() const { return _baseWIS; }
|
||||
int32 GetBaseFR() const { return _baseFR; }
|
||||
int32 GetBaseCR() const { return _baseCR; }
|
||||
int32 GetBaseMR() const { return _baseMR; }
|
||||
int32 GetBasePR() const { return _basePR; }
|
||||
int32 GetBaseDR() const { return _baseDR; }
|
||||
int32 GetBaseCorrup() const { return _baseCorrup; }
|
||||
|
||||
void Signal(int signal_id);
|
||||
void SendPayload(int payload_id, std::string payload_value = std::string());
|
||||
void OwnerMessage(std::string message);
|
||||
void OwnerMessage(const std::string& message);
|
||||
|
||||
//Raid additions
|
||||
Raid* p_raid_instance;
|
||||
|
||||
static uint8 spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND];
|
||||
|
||||
bool BotCastMez(Mob* tar, uint8 botLevel, bool checked_los, BotSpell& botSpell, Raid* raid);
|
||||
bool BotCastHeal(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpell, Raid* raid);
|
||||
bool BotCastRoot(Mob* tar, uint8 botLevel, uint32 iSpellTypes, BotSpell& botSpell, const bool& checked_los);
|
||||
bool BotCastBuff(Mob* tar, uint8 botLevel, uint8 botClass);
|
||||
bool BotCastEscape(Mob*& tar, uint8 botClass, BotSpell& botSpell, uint32 iSpellTypes);
|
||||
bool BotCastNuke(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpell, const bool& checked_los);
|
||||
bool BotCastDispel(Mob* tar, BotSpell& botSpell, uint32 iSpellTypes, const bool& checked_los);
|
||||
bool BotCastPet(Mob* tar, uint8 botClass, BotSpell& botSpell);
|
||||
bool BotCastCombatBuff(Mob* tar, uint8 botLevel, uint8 botClass);
|
||||
bool BotCastLifetap(Mob* tar, uint8 botLevel, BotSpell& botSpell, const bool& checked_los, uint32 iSpellTypes);
|
||||
bool BotCastSnare(Mob* tar, uint8 botLevel, BotSpell& botSpell, const bool& checked_los, uint32 iSpellTypes);
|
||||
bool BotCastDOT(Mob* tar, uint8 botLevel, const BotSpell& botSpell, const bool& checked_los);
|
||||
bool BotCastSlow(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpell, const bool& checked_los, Raid* raid);
|
||||
bool BotCastDebuff(Mob* tar, uint8 botLevel, BotSpell& botSpell, bool checked_los);
|
||||
bool BotCastCure(Mob* tar, uint8 botClass, BotSpell& botSpell, Raid* raid);
|
||||
bool BotCastHateReduction(Mob* tar, uint8 botLevel, const BotSpell& botSpell);
|
||||
bool BotCastCombatSong(Mob* tar, uint8 botLevel);
|
||||
bool BotCastSong(Mob* tar, uint8 botLevel);
|
||||
|
||||
bool CheckIfIncapacitated();
|
||||
bool IsAIProcessValid(const Client* bot_owner, const Group* bot_group, const Raid* raid);
|
||||
|
||||
Client* SetLeashOwner(Client* bot_owner, Group* bot_group, Raid* raid, uint32 r_group) const;
|
||||
Mob* SetFollowMob(Client* leash_owner);
|
||||
|
||||
Mob* GetBotTarget(Client* bot_owner);
|
||||
void AcquireBotTarget(Group* bot_group, Raid* raid, Client* leash_owner, float leash_distance);
|
||||
void SetBotTarget(Client* bot_owner, Raid* raid, Group* bot_group, Client* leash_owner, float lo_distance, float leash_distance, bool bo_alt_combat);
|
||||
void SetLeashOwnerTarget(Client* leash_owner, Client* bot_owner, float lo_distance, float leash_distance);
|
||||
void SetOwnerTarget(Client* bot_owner);
|
||||
void SetBotGroupTarget(const Client* bot_owner, Client* leash_owner, float lo_distance, float leash_distance, Mob* const& bg_member, Mob* bgm_target);
|
||||
bool IsValidTarget(Client* bot_owner, Client* leash_owner, float lo_distance, float leash_distance, bool bo_alt_combat, Mob* tar, float tar_distance);
|
||||
|
||||
bool PullingFlagChecks(Client* bot_owner);
|
||||
bool ReturningFlagChecks(Client* bot_owner, float fm_distance);
|
||||
void BotPullerProcess(Client* bot_owner, Raid* raid);
|
||||
|
||||
|
||||
// Movement Methods
|
||||
void CalcMeleeDistances(
|
||||
const Mob* tar,
|
||||
const EQ::ItemInstance* const& p_item,
|
||||
const EQ::ItemInstance* const& s_item,
|
||||
bool behind_mob,
|
||||
bool backstab_weapon,
|
||||
float& melee_distance_max,
|
||||
float& melee_distance
|
||||
) const;
|
||||
|
||||
// Combat Checks
|
||||
void SetBerserkState();
|
||||
bool CheckIfCasting(float fm_distance);
|
||||
void HealRotationChecks();
|
||||
void CheckCombatRange(Mob* tar, float tar_distance, bool& atCombatRange, const EQ::ItemInstance*& p_item, const EQ::ItemInstance*& s_item);
|
||||
|
||||
// Try Combat Methods
|
||||
bool TryEvade(Mob* tar);
|
||||
bool TryFacingTarget(Mob* tar);
|
||||
bool TryRangedAttack(Mob* tar);
|
||||
bool TryClassAttacks(Mob* tar);
|
||||
bool TryPrimaryWeaponAttacks(Mob* tar, const EQ::ItemInstance* p_item);
|
||||
bool TrySecondaryWeaponAttacks(Mob* tar, const EQ::ItemInstance* s_item);
|
||||
bool TryPursueTarget(float leash_distance, glm::vec3& Goal);
|
||||
bool TryMeditate();
|
||||
bool TryAutoDefend(Client* bot_owner, float leash_distance);
|
||||
bool TryIdleChecks(float fm_distance);
|
||||
bool TryNonCombatMovementChecks(Client* bot_owner, const Mob* follow_mob, glm::vec3& Goal);
|
||||
bool TryBardMovementCasts();
|
||||
void SetRangerCombatWeapon(bool atArcheryRange);
|
||||
|
||||
// Public "Refactor" Methods
|
||||
static bool CheckSpawnConditions(Client* c);
|
||||
|
||||
protected:
|
||||
void PetAIProcess();
|
||||
void BotMeditate(bool isSitting);
|
||||
bool CheckBotDoubleAttack(bool Triple = false);
|
||||
void PerformTradeWithClient(int16 begin_slot_id, int16 end_slot_id, Client* client);
|
||||
bool AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0) override;
|
||||
bool AIDoSpellCast(int32 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = nullptr) override;
|
||||
|
||||
BotCastingRoles& GetCastingRoles() { return m_CastingRoles; }
|
||||
void SetGroupHealer(bool flag = true) { m_CastingRoles.GroupHealer = flag; }
|
||||
void SetGroupSlower(bool flag = true) { m_CastingRoles.GroupSlower = flag; }
|
||||
void SetGroupNuker(bool flag = true) { m_CastingRoles.GroupNuker = flag; }
|
||||
void SetGroupDoter(bool flag = true) { m_CastingRoles.GroupDoter = flag; }
|
||||
//void SetRaidHealer(bool flag = true) { m_CastingRoles.RaidHealer = flag; }
|
||||
//void SetRaidSlower(bool flag = true) { m_CastingRoles.RaidSlower = flag; }
|
||||
//void SetRaidNuker(bool flag = true) { m_CastingRoles.RaidNuker = flag; }
|
||||
//void SetRaidDoter(bool flag = true) { m_CastingRoles.RaidDoter = flag; }
|
||||
std::deque<int> bot_signal_q;
|
||||
|
||||
std::vector<BotSpells_Struct> AIBot_spells;
|
||||
@ -801,8 +871,7 @@ private:
|
||||
Timer m_evade_timer; // can be moved to pTimers at some point
|
||||
Timer m_alt_combat_hate_timer;
|
||||
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;
|
||||
@ -849,15 +918,12 @@ private:
|
||||
|
||||
// Class Methods
|
||||
void LoadAAs();
|
||||
int32 acmod();
|
||||
void GenerateBaseStats();
|
||||
void GenerateAppearance();
|
||||
void GenerateArmorClass();
|
||||
int32 GenerateBaseHitPoints();
|
||||
int32 GenerateBaseManaPoints();
|
||||
void GenerateSpecialAttacks();
|
||||
void SetBotID(uint32 botID);
|
||||
//void SetCombatJitterFlag(bool flag = true) { m_combat_jitter_flag = flag; }
|
||||
void SetAttackingFlag(bool flag = true) { m_attacking_flag = flag; }
|
||||
void SetPullingFlag(bool flag = true) { m_pulling_flag = flag; }
|
||||
void SetReturningFlag(bool flag = true) { m_returning_flag = flag; }
|
||||
@ -870,9 +936,6 @@ private:
|
||||
bool LoadPet(); // Load and spawn bot pet if there is one
|
||||
bool SavePet(); // Save and depop bot pet if there is one
|
||||
bool DeletePet();
|
||||
|
||||
public:
|
||||
static uint8 spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND];
|
||||
};
|
||||
|
||||
bool IsSpellInBotList(DBbotspells_Struct* spell_list, uint16 iSpellID);
|
||||
|
||||
@ -202,12 +202,14 @@ public:
|
||||
if (target_type == BCEnum::TT_None)
|
||||
continue;
|
||||
|
||||
uint8 class_levels[16] = { 0 };
|
||||
uint8 class_levels[16] = {0};
|
||||
bool player_spell = false;
|
||||
for (int class_type = WARRIOR; class_type <= BERSERKER; ++class_type) {
|
||||
int class_index = CLASSIDTOINDEX(class_type);
|
||||
if (spells[spell_id].classes[class_index] == 0 || spells[spell_id].classes[class_index] > HARD_LEVEL_CAP)
|
||||
if (spells[spell_id].classes[class_index] == 0 ||
|
||||
spells[spell_id].classes[class_index] > HARD_LEVEL_CAP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
class_levels[class_index] = spells[spell_id].classes[class_index];
|
||||
player_spell = true;
|
||||
@ -235,8 +237,7 @@ public:
|
||||
case SE_Succor:
|
||||
if (!strcmp(spells[spell_id].teleport_zone, "same")) {
|
||||
entry_prototype = new STEscapeEntry;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
entry_prototype = new STDepartEntry;
|
||||
entry_prototype->SafeCastToDepart()->single = !BCSpells::IsGroupType(target_type);
|
||||
}
|
||||
@ -245,8 +246,7 @@ public:
|
||||
if (spells[spell_id].teleport_zone[0] == '\0') {
|
||||
entry_prototype = new STSendHomeEntry();
|
||||
entry_prototype->SafeCastToSendHome()->group = BCSpells::IsGroupType(target_type);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
entry_prototype = new STDepartEntry;
|
||||
entry_prototype->SafeCastToDepart()->single = !BCSpells::IsGroupType(target_type);
|
||||
}
|
||||
@ -255,8 +255,8 @@ public:
|
||||
if (spells[spell_id].base_value[EFFECTIDTOINDEX(1)] > 100) {
|
||||
entry_prototype = new STSizeEntry;
|
||||
entry_prototype->SafeCastToSize()->size_type = BCEnum::SzT_Enlarge;
|
||||
}
|
||||
else if (spells[spell_id].base_value[EFFECTIDTOINDEX(1)] > 0 && spells[spell_id].base_value[EFFECTIDTOINDEX(1)] < 100) {
|
||||
} else if (spells[spell_id].base_value[EFFECTIDTOINDEX(1)] > 0 &&
|
||||
spells[spell_id].base_value[EFFECTIDTOINDEX(1)] < 100) {
|
||||
entry_prototype = new STSizeEntry;
|
||||
entry_prototype->SafeCastToSize()->size_type = BCEnum::SzT_Reduce;
|
||||
}
|
||||
@ -343,7 +343,8 @@ public:
|
||||
while (spells[spell_id].type_description_id == 27) {
|
||||
if (!spells[spell_id].good_effect)
|
||||
break;
|
||||
if (spells[spell_id].skill != EQ::skills::SkillOffense && spells[spell_id].skill != EQ::skills::SkillDefense)
|
||||
if (spells[spell_id].skill != EQ::skills::SkillOffense &&
|
||||
spells[spell_id].skill != EQ::skills::SkillDefense)
|
||||
break;
|
||||
|
||||
entry_prototype = new STStanceEntry();
|
||||
@ -364,26 +365,33 @@ public:
|
||||
|
||||
for (int i = EffectIDFirst; i <= EffectIDLast; ++i) {
|
||||
int effect_index = EFFECTIDTOINDEX(i);
|
||||
if (spells[spell_id].effect_id[effect_index] != SE_Blind && spells[spell_id].base_value[effect_index] >= 0)
|
||||
if (spells[spell_id].effect_id[effect_index] != SE_Blind &&
|
||||
spells[spell_id].base_value[effect_index] >= 0)
|
||||
continue;
|
||||
else if (spells[spell_id].effect_id[effect_index] == SE_Blind && !spells[spell_id].good_effect)
|
||||
else if (spells[spell_id].effect_id[effect_index] == SE_Blind &&
|
||||
!spells[spell_id].good_effect)
|
||||
continue;
|
||||
|
||||
switch (spells[spell_id].effect_id[effect_index]) {
|
||||
case SE_Blind:
|
||||
entry_prototype->SafeCastToCure()->cure_value[AILMENTIDTOINDEX(BCEnum::AT_Blindness)] += spells[spell_id].base_value[effect_index];
|
||||
entry_prototype->SafeCastToCure()->cure_value[AILMENTIDTOINDEX(
|
||||
BCEnum::AT_Blindness)] += spells[spell_id].base_value[effect_index];
|
||||
break;
|
||||
case SE_DiseaseCounter:
|
||||
entry_prototype->SafeCastToCure()->cure_value[AILMENTIDTOINDEX(BCEnum::AT_Disease)] += spells[spell_id].base_value[effect_index];
|
||||
entry_prototype->SafeCastToCure()->cure_value[AILMENTIDTOINDEX(
|
||||
BCEnum::AT_Disease)] += spells[spell_id].base_value[effect_index];
|
||||
break;
|
||||
case SE_PoisonCounter:
|
||||
entry_prototype->SafeCastToCure()->cure_value[AILMENTIDTOINDEX(BCEnum::AT_Poison)] += spells[spell_id].base_value[effect_index];
|
||||
entry_prototype->SafeCastToCure()->cure_value[AILMENTIDTOINDEX(
|
||||
BCEnum::AT_Poison)] += spells[spell_id].base_value[effect_index];
|
||||
break;
|
||||
case SE_CurseCounter:
|
||||
entry_prototype->SafeCastToCure()->cure_value[AILMENTIDTOINDEX(BCEnum::AT_Curse)] += spells[spell_id].base_value[effect_index];
|
||||
entry_prototype->SafeCastToCure()->cure_value[AILMENTIDTOINDEX(
|
||||
BCEnum::AT_Curse)] += spells[spell_id].base_value[effect_index];
|
||||
break;
|
||||
case SE_CorruptionCounter:
|
||||
entry_prototype->SafeCastToCure()->cure_value[AILMENTIDTOINDEX(BCEnum::AT_Corruption)] += spells[spell_id].base_value[effect_index];
|
||||
entry_prototype->SafeCastToCure()->cure_value[AILMENTIDTOINDEX(
|
||||
BCEnum::AT_Corruption)] += spells[spell_id].base_value[effect_index];
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
@ -409,22 +417,28 @@ public:
|
||||
|
||||
switch (spells[spell_id].effect_id[effect_index]) {
|
||||
case SE_ResistFire:
|
||||
entry_prototype->SafeCastToResistance()->resist_value[RESISTANCEIDTOINDEX(BCEnum::RT_Fire)] += spells[spell_id].base_value[effect_index];
|
||||
entry_prototype->SafeCastToResistance()->resist_value[RESISTANCEIDTOINDEX(
|
||||
BCEnum::RT_Fire)] += spells[spell_id].base_value[effect_index];
|
||||
break;
|
||||
case SE_ResistCold:
|
||||
entry_prototype->SafeCastToResistance()->resist_value[RESISTANCEIDTOINDEX(BCEnum::RT_Cold)] += spells[spell_id].base_value[effect_index];
|
||||
entry_prototype->SafeCastToResistance()->resist_value[RESISTANCEIDTOINDEX(
|
||||
BCEnum::RT_Cold)] += spells[spell_id].base_value[effect_index];
|
||||
break;
|
||||
case SE_ResistPoison:
|
||||
entry_prototype->SafeCastToResistance()->resist_value[RESISTANCEIDTOINDEX(BCEnum::RT_Poison)] += spells[spell_id].base_value[effect_index];
|
||||
entry_prototype->SafeCastToResistance()->resist_value[RESISTANCEIDTOINDEX(
|
||||
BCEnum::RT_Poison)] += spells[spell_id].base_value[effect_index];
|
||||
break;
|
||||
case SE_ResistDisease:
|
||||
entry_prototype->SafeCastToResistance()->resist_value[RESISTANCEIDTOINDEX(BCEnum::RT_Disease)] += spells[spell_id].base_value[effect_index];
|
||||
entry_prototype->SafeCastToResistance()->resist_value[RESISTANCEIDTOINDEX(
|
||||
BCEnum::RT_Disease)] += spells[spell_id].base_value[effect_index];
|
||||
break;
|
||||
case SE_ResistMagic:
|
||||
entry_prototype->SafeCastToResistance()->resist_value[RESISTANCEIDTOINDEX(BCEnum::RT_Magic)] += spells[spell_id].base_value[effect_index];
|
||||
entry_prototype->SafeCastToResistance()->resist_value[RESISTANCEIDTOINDEX(
|
||||
BCEnum::RT_Magic)] += spells[spell_id].base_value[effect_index];
|
||||
break;
|
||||
case SE_ResistCorruption:
|
||||
entry_prototype->SafeCastToResistance()->resist_value[RESISTANCEIDTOINDEX(BCEnum::RT_Corruption)] += spells[spell_id].base_value[effect_index];
|
||||
entry_prototype->SafeCastToResistance()->resist_value[RESISTANCEIDTOINDEX(
|
||||
BCEnum::RT_Corruption)] += spells[spell_id].base_value[effect_index];
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
@ -459,7 +473,8 @@ public:
|
||||
if (!entry_prototype)
|
||||
continue;
|
||||
|
||||
if (target_type == BCEnum::TT_Self && (entry_prototype->BCST() != BCEnum::SpT_Stance && entry_prototype->BCST() != BCEnum::SpT_SummonCorpse)) {
|
||||
if (target_type == BCEnum::TT_Self && (entry_prototype->BCST() != BCEnum::SpT_Stance &&
|
||||
entry_prototype->BCST() != BCEnum::SpT_SummonCorpse)) {
|
||||
#ifdef BCSTSPELLDUMP
|
||||
LogError("DELETING entry_prototype (primary clause) - name: [{}], target_type: [{}], BCST: [{}]",
|
||||
spells[spell_id].name, BCEnum::TargetTypeEnumToString(target_type).c_str(), BCEnum::SpellTypeEnumToString(entry_prototype->BCST()).c_str());
|
||||
@ -545,7 +560,8 @@ public:
|
||||
|
||||
bot_command_spells[spell_entry->BCST()].push_back(spell_entry);
|
||||
|
||||
if (bot_levels.find(class_type) == bot_levels.end() || bot_levels[class_type] > class_levels[class_index])
|
||||
if (bot_levels.find(class_type) == bot_levels.end() ||
|
||||
bot_levels[class_type] > class_levels[class_index])
|
||||
bot_levels[class_type] = class_levels[class_index];
|
||||
}
|
||||
|
||||
@ -561,15 +577,15 @@ public:
|
||||
#ifdef BCSTSPELLDUMP
|
||||
spell_dump();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static void Unload() {
|
||||
for (auto map_iter : bot_command_spells) {
|
||||
if (map_iter.second.empty())
|
||||
continue;
|
||||
for (auto list_iter : map_iter.second)
|
||||
for (auto list_iter: map_iter.second) {
|
||||
safe_delete(list_iter);
|
||||
}
|
||||
map_iter.second.clear();
|
||||
}
|
||||
bot_command_spells.clear();
|
||||
@ -596,7 +612,6 @@ public:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static void remove_inactive() {
|
||||
if (bot_command_spells.empty())
|
||||
@ -620,8 +635,10 @@ private:
|
||||
}
|
||||
});
|
||||
|
||||
for (auto del_iter : *removed_spells_list)
|
||||
for (auto del_iter: *removed_spells_list)
|
||||
{
|
||||
safe_delete(del_iter);
|
||||
}
|
||||
removed_spells_list->clear();
|
||||
|
||||
if (RuleI(Bots, CommandSpellRank) == 1) {
|
||||
@ -645,8 +662,9 @@ private:
|
||||
return false;
|
||||
});
|
||||
|
||||
for (auto del_iter : *removed_spells_list)
|
||||
for (auto del_iter: *removed_spells_list) {
|
||||
safe_delete(del_iter);
|
||||
}
|
||||
removed_spells_list->clear();
|
||||
}
|
||||
|
||||
@ -669,8 +687,9 @@ private:
|
||||
return false;
|
||||
});
|
||||
|
||||
for (auto del_iter : *removed_spells_list)
|
||||
for (auto del_iter: *removed_spells_list) {
|
||||
safe_delete(del_iter);
|
||||
}
|
||||
removed_spells_list->clear();
|
||||
}
|
||||
|
||||
@ -696,8 +715,9 @@ private:
|
||||
return false;
|
||||
});
|
||||
|
||||
for (auto del_iter : *removed_spells_list)
|
||||
for (auto del_iter: *removed_spells_list) {
|
||||
safe_delete(del_iter);
|
||||
}
|
||||
removed_spells_list->clear();
|
||||
}
|
||||
|
||||
@ -1255,6 +1275,8 @@ int bot_command_count; // how many bot commands we have
|
||||
// init has been performed to point at the real function
|
||||
int (*bot_command_dispatch)(Client *,char const *) = bot_command_not_avail;
|
||||
|
||||
|
||||
|
||||
std::map<std::string, BotCommandRecord *> bot_command_list;
|
||||
std::map<std::string, std::string> bot_command_aliases;
|
||||
|
||||
@ -1926,7 +1948,7 @@ namespace MyBots
|
||||
if (!clear_list)
|
||||
UniquifySBL(sbl);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace ActionableTarget
|
||||
{
|
||||
@ -2120,7 +2142,7 @@ namespace ActionableTarget
|
||||
return target[target_type];
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
namespace ActionableBots
|
||||
{
|
||||
@ -2461,7 +2483,7 @@ namespace ActionableBots
|
||||
|
||||
ActionableBots::Filter_ByHighestSkill(bot_owner, sbl, EQ::skills::SkillPickLock, pick_lock_value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@ -2817,7 +2839,7 @@ void bot_command_bind_affinity(Client *c, const Seperator *sep)
|
||||
|
||||
void bot_command_bot(Client *c, const Seperator *sep)
|
||||
{
|
||||
/* VS2012 code - begin */
|
||||
|
||||
std::list<const char*> subcommand_list;
|
||||
subcommand_list.push_back("botappearance");
|
||||
subcommand_list.push_back("botcamp");
|
||||
@ -2838,14 +2860,6 @@ void bot_command_bot(Client *c, const Seperator *sep)
|
||||
subcommand_list.push_back("bottogglearcher");
|
||||
subcommand_list.push_back("bottogglehelm");
|
||||
subcommand_list.push_back("botupdate");
|
||||
/* VS2012 code - end */
|
||||
|
||||
/* VS2013 code
|
||||
const std::list<const char*> subcommand_list = {
|
||||
"botappearance", "botcamp", "botclone", "botcreate", "botdelete", "botdetails", "botdyearmor", "botinspectmessage", "botfollowdistance",
|
||||
"botlist", "botoutofcombat", "botreport", "botspawn", "botstance", "botsummon", "bottogglearcher", "bottogglehelm", "botupdate"
|
||||
};
|
||||
*/
|
||||
|
||||
if (helper_command_alias_fail(c, "bot_command_bot", sep->arg[0], "bot"))
|
||||
return;
|
||||
@ -3352,7 +3366,7 @@ void bot_command_guard(Client *c, const Seperator *sep)
|
||||
|
||||
void bot_command_heal_rotation(Client *c, const Seperator *sep)
|
||||
{
|
||||
/* VS2012 code - begin */
|
||||
|
||||
std::list<const char*> subcommand_list;
|
||||
subcommand_list.push_back("healrotationadaptivetargeting");
|
||||
subcommand_list.push_back("healrotationaddmember");
|
||||
@ -3374,16 +3388,6 @@ void bot_command_heal_rotation(Client *c, const Seperator *sep)
|
||||
subcommand_list.push_back("healrotationsethot");
|
||||
subcommand_list.push_back("healrotationstart");
|
||||
subcommand_list.push_back("healrotationstop");
|
||||
/* VS2012 code - end */
|
||||
|
||||
/* VS2013 code
|
||||
const std::list<const char*> subcommand_list = {
|
||||
"healrotationadaptivetargeting", "healrotationaddmember", "healrotationaddtarget", "healrotationadjustcritical", "healrotationadjustsafe",
|
||||
"healrotationcastoverride", "healrotationchangeinterval", "healrotationclearhot", "healrotationcleartargets", "healrotationcreate",
|
||||
"healrotationdelete", "healrotationfastheals", "healrotationlist", "healrotationremovemember", "healrotationremovetarget", "healrotationsave",
|
||||
"healrotationresetlimits", "healrotationsethot", "healrotationstart", "healrotationstop"
|
||||
};
|
||||
*/
|
||||
|
||||
if (helper_command_alias_fail(c, "bot_command_heal_rotation", sep->arg[0], "healrotation"))
|
||||
return;
|
||||
@ -3540,17 +3544,12 @@ void bot_command_identify(Client *c, const Seperator *sep)
|
||||
|
||||
void bot_command_inventory(Client *c, const Seperator *sep)
|
||||
{
|
||||
/* VS2012 code - begin */
|
||||
|
||||
std::list<const char*> subcommand_list;
|
||||
subcommand_list.push_back("inventorygive");
|
||||
subcommand_list.push_back("inventorylist");
|
||||
subcommand_list.push_back("inventoryremove");
|
||||
subcommand_list.push_back("inventorywindow");
|
||||
/* VS2012 code - end */
|
||||
|
||||
/* VS2013 code
|
||||
const std::list<const char*> subcommand_list = { "inventorygive", "inventorylist", "inventoryremove", "inventorywindow" };
|
||||
*/
|
||||
|
||||
if (helper_command_alias_fail(c, "bot_command_inventory", sep->arg[0], "inventory"))
|
||||
return;
|
||||
@ -4015,7 +4014,7 @@ void bot_command_owner_option(Client *c, const Seperator *sep)
|
||||
|
||||
database.botdb.SaveOwnerOption(c->CharacterID(), Client::booDeathMarquee, c->GetBotOption(Client::booDeathMarquee));
|
||||
|
||||
c->Message(Chat::White, "Bot 'death marquee' is now %s.", (c->GetBotOption(Client::booDeathMarquee) == true ? "enabled" : "disabled"));
|
||||
c->Message(Chat::White, "Bot 'death marquee' is now %s.", (c->GetBotOption(Client::booDeathMarquee) ? "enabled" : "disabled"));
|
||||
}
|
||||
else if (!owner_option.compare("statsupdate")) {
|
||||
|
||||
@ -4031,7 +4030,7 @@ void bot_command_owner_option(Client *c, const Seperator *sep)
|
||||
|
||||
database.botdb.SaveOwnerOption(c->CharacterID(), Client::booStatsUpdate, c->GetBotOption(Client::booStatsUpdate));
|
||||
|
||||
c->Message(Chat::White, "Bot 'stats update' is now %s.", (c->GetBotOption(Client::booStatsUpdate) == true ? "enabled" : "disabled"));
|
||||
c->Message(Chat::White, "Bot 'stats update' is now %s.", (c->GetBotOption(Client::booStatsUpdate) ? "enabled" : "disabled"));
|
||||
}
|
||||
else if (!owner_option.compare("spawnmessage")) {
|
||||
|
||||
@ -4117,7 +4116,7 @@ void bot_command_owner_option(Client *c, const Seperator *sep)
|
||||
|
||||
database.botdb.SaveOwnerOption(c->CharacterID(), Client::booAltCombat, c->GetBotOption(Client::booAltCombat));
|
||||
|
||||
c->Message(Chat::White, "Bot 'alt combat' is now %s.", (c->GetBotOption(Client::booAltCombat) == true ? "enabled" : "disabled"));
|
||||
c->Message(Chat::White, "Bot 'alt combat' is now %s.", (c->GetBotOption(Client::booAltCombat) ? "enabled" : "disabled"));
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "Bot owner option 'altcombat' is not allowed on this server.");
|
||||
@ -4139,7 +4138,7 @@ void bot_command_owner_option(Client *c, const Seperator *sep)
|
||||
|
||||
database.botdb.SaveOwnerOption(c->CharacterID(), Client::booAutoDefend, c->GetBotOption(Client::booAutoDefend));
|
||||
|
||||
c->Message(Chat::White, "Bot 'auto defend' is now %s.", (c->GetBotOption(Client::booAutoDefend) == true ? "enabled" : "disabled"));
|
||||
c->Message(Chat::White, "Bot 'auto defend' is now %s.", (c->GetBotOption(Client::booAutoDefend) ? "enabled" : "disabled"));
|
||||
}
|
||||
else {
|
||||
c->Message(Chat::White, "Bot owner option 'autodefend' is not allowed on this server.");
|
||||
@ -4159,7 +4158,7 @@ void bot_command_owner_option(Client *c, const Seperator *sep)
|
||||
|
||||
database.botdb.SaveOwnerOption(c->CharacterID(), Client::booBuffCounter, c->GetBotOption(Client::booBuffCounter));
|
||||
|
||||
c->Message(Chat::White, "Bot 'buff counter' is now %s.", (c->GetBotOption(Client::booBuffCounter) == true ? "enabled" : "disabled"));
|
||||
c->Message(Chat::White, "Bot 'buff counter' is now %s.", (c->GetBotOption(Client::booBuffCounter) ? "enabled" : "disabled"));
|
||||
}
|
||||
else if (!owner_option.compare("monkwumessage")) {
|
||||
|
||||
@ -4175,7 +4174,11 @@ void bot_command_owner_option(Client *c, const Seperator *sep)
|
||||
|
||||
database.botdb.SaveOwnerOption(c->CharacterID(), Client::booMonkWuMessage, c->GetBotOption(Client::booMonkWuMessage));
|
||||
|
||||
c->Message(Chat::White, "Bot 'monk wu message' is now %s.", (c->GetBotOption(Client::booMonkWuMessage) == true ? "enabled" : "disabled"));
|
||||
c->Message(
|
||||
Chat::White,
|
||||
"Bot 'monk wu message' is now %s.",
|
||||
(c->GetBotOption(Client::booMonkWuMessage) ? "enabled" : "disabled")
|
||||
);
|
||||
}
|
||||
else if (!owner_option.compare("current")) {
|
||||
|
||||
@ -4214,16 +4217,11 @@ void bot_command_owner_option(Client *c, const Seperator *sep)
|
||||
|
||||
void bot_command_pet(Client *c, const Seperator *sep)
|
||||
{
|
||||
/* VS2012 code - begin */
|
||||
|
||||
std::list<const char*> subcommand_list;
|
||||
subcommand_list.push_back("petgetlost");
|
||||
subcommand_list.push_back("petremove");
|
||||
subcommand_list.push_back("petsettype");
|
||||
/* VS2012 code - end */
|
||||
|
||||
/* VS2013 code
|
||||
const std::list<const char*> subcommand_list = { "petgetlost", "petremove", "petsettype" };
|
||||
*/
|
||||
|
||||
if (helper_command_alias_fail(c, "bot_command_pet", sep->arg[0], "pet"))
|
||||
return;
|
||||
@ -4317,7 +4315,7 @@ void bot_command_precombat(Client* c, const Seperator* sep)
|
||||
c->SetBotPrecombat(!c->GetBotPrecombat());
|
||||
}
|
||||
|
||||
c->Message(Chat::White, "Precombat flag is now %s.", (c->GetBotPrecombat() == true ? "set" : "clear"));
|
||||
c->Message(Chat::White, "Precombat flag is now %s.", (c->GetBotPrecombat() ? "set" : "clear"));
|
||||
}
|
||||
|
||||
// TODO: Rework to allow owner specificed criteria for puller
|
||||
@ -5014,7 +5012,7 @@ void bot_command_water_breathing(Client *c, const Seperator *sep)
|
||||
*/
|
||||
void bot_subcommand_bot_appearance(Client *c, const Seperator *sep)
|
||||
{
|
||||
/* VS2012 code - begin */
|
||||
|
||||
std::list<const char*> subcommand_list;
|
||||
subcommand_list.push_back("botbeardcolor");
|
||||
subcommand_list.push_back("botbeardstyle");
|
||||
@ -5026,14 +5024,6 @@ void bot_subcommand_bot_appearance(Client *c, const Seperator *sep)
|
||||
subcommand_list.push_back("botheritage");
|
||||
subcommand_list.push_back("bottattoo");
|
||||
subcommand_list.push_back("botwoad");
|
||||
/* VS2012 code - end */
|
||||
|
||||
/* VS2013 code
|
||||
const std::list<const char*> subcommand_list = {
|
||||
"botbeardcolor", "botbeardstyle", "botdetails", "boteyes", "botface",
|
||||
"bothaircolor", "bothairstyle", "botheritage", "bottattoo", "botwoad"
|
||||
};
|
||||
*/
|
||||
|
||||
if (helper_command_alias_fail(c, "bot_subcommand_bot_appearance", sep->arg[0], "botappearance"))
|
||||
return;
|
||||
@ -6539,8 +6529,7 @@ void bot_subcommand_bot_spawn(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
if (c->GetFeigned()) {
|
||||
c->Message(Chat::White, "You cannot spawn a bot while feigned.");
|
||||
if (!Bot::CheckSpawnConditions(c)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -6654,39 +6643,6 @@ void bot_subcommand_bot_spawn(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
// this probably needs work...
|
||||
if (c->GetGroup()) {
|
||||
std::list<Mob*> group_list;
|
||||
c->GetGroup()->GetMemberList(group_list);
|
||||
for (auto member_iter : group_list) {
|
||||
if (!member_iter) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (member_iter->qglobal) { // what is this?? really should have had a message to describe failure... (can't spawn bots if you are assigned to a task/instance?)
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!member_iter->qglobal &&
|
||||
member_iter->GetAppearance() != eaDead &&
|
||||
(
|
||||
member_iter->IsEngaged() ||
|
||||
(
|
||||
member_iter->IsClient() &&
|
||||
member_iter->CastToClient()->GetAggroCount()
|
||||
)
|
||||
)
|
||||
) {
|
||||
c->Message(Chat::White, "You cannot summon bots while you are engaged.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (c->GetAggroCount()) {
|
||||
c->Message(Chat::White, "You cannot spawn bots while you are engaged.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto my_bot = Bot::LoadBot(bot_id);
|
||||
if (!my_bot) {
|
||||
c->Message(
|
||||
@ -7831,30 +7787,10 @@ void bot_subcommand_botgroup_load(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
if (c->GetFeigned()) {
|
||||
c->Message(Chat::White, "You cannot spawn a bot-group while feigned.");
|
||||
if (!Bot::CheckSpawnConditions(c)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* owner_group = c->GetGroup();
|
||||
if (owner_group) {
|
||||
std::list<Client*> member_list;
|
||||
owner_group->GetClientList(member_list);
|
||||
member_list.remove(nullptr);
|
||||
|
||||
for (auto member_iter : member_list) {
|
||||
if (member_iter->IsEngaged() || member_iter->GetAggroCount() > 0) {
|
||||
c->Message(Chat::White, "You cannot spawn bots while your group is engaged,");
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (c->GetAggroCount() > 0) {
|
||||
c->Message(Chat::White, "You cannot spawn bots while you are engaged,");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 botgroup_id = 0;
|
||||
if (!database.botdb.LoadBotGroupIDForLoadBotGroup(c->CharacterID(), botgroup_name, botgroup_id) || !botgroup_id) {
|
||||
c->Message(
|
||||
@ -10100,7 +10036,7 @@ bool helper_cast_standard_spell(Bot* casting_bot, Mob* target_mob, int spell_id,
|
||||
|
||||
bool helper_command_disabled(Client* bot_owner, bool rule_value, const char* command)
|
||||
{
|
||||
if (rule_value == false) {
|
||||
if (rule_value) {
|
||||
bot_owner->Message(Chat::White, "Bot command %s is not enabled on this server.", command);
|
||||
return true;
|
||||
}
|
||||
@ -10618,7 +10554,7 @@ void bot_command_spell_settings_toggle(Client *c, const Seperator *sep)
|
||||
|
||||
bool toggle = (
|
||||
sep->IsNumber(2) ?
|
||||
(Strings::ToInt(sep->arg[2]) ? true : false) :
|
||||
Strings::ToInt(sep->arg[2]) != 0 :
|
||||
atobool(sep->arg[2])
|
||||
);
|
||||
|
||||
|
||||
287
zone/bot_raid.cpp
Normal file
287
zone/bot_raid.cpp
Normal file
@ -0,0 +1,287 @@
|
||||
/* 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
|
||||
*/
|
||||
|
||||
#include "bot.h"
|
||||
#include "object.h"
|
||||
#include "raids.h"
|
||||
#include "doors.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "../common/data_verification.h"
|
||||
|
||||
extern volatile bool is_zone_loaded;
|
||||
extern bool Critical;
|
||||
|
||||
std::vector<RaidMember> Raid::GetRaidGroupMembers(uint32 gid)
|
||||
{
|
||||
std::vector<RaidMember> raid_group_members;
|
||||
raid_group_members.clear();
|
||||
|
||||
for (int i = 0; i < MAX_RAID_MEMBERS; ++i)
|
||||
{
|
||||
if (members[i].member && members[i].GroupNumber == gid)
|
||||
{
|
||||
raid_group_members.push_back(members[i]);
|
||||
}
|
||||
}
|
||||
return raid_group_members;
|
||||
}
|
||||
|
||||
// Returns Bot members that are in the raid
|
||||
// passing in owner will return all Bots that have the same owner.
|
||||
std::vector<Bot*> Raid::GetRaidBotMembers(uint32 owner)
|
||||
{
|
||||
std::vector<Bot*> raid_members_bots;
|
||||
raid_members_bots.clear();
|
||||
|
||||
for (int i = 0; i < MAX_RAID_MEMBERS; i++) {
|
||||
if (
|
||||
members[i].member &&
|
||||
members[i].member->IsBot()
|
||||
) {
|
||||
auto b_member = members[i].member->CastToBot();
|
||||
if (owner && b_member->GetBotOwnerCharacterID() == owner) {
|
||||
raid_members_bots.emplace_back(b_member);
|
||||
} else if (!owner) {
|
||||
raid_members_bots.emplace_back(b_member);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return raid_members_bots;
|
||||
}
|
||||
|
||||
// Returns Bot members that are in the group specified
|
||||
// passing in owner will return only Bots that have the same owner.
|
||||
std::vector<Bot*> Raid::GetRaidGroupBotMembers(uint32 gid)
|
||||
{
|
||||
std::vector<Bot*> raid_members_bots;
|
||||
raid_members_bots.clear();
|
||||
|
||||
for (int i = 0; i < MAX_RAID_MEMBERS; i++) {
|
||||
if (
|
||||
members[i].member &&
|
||||
members[i].member->IsBot() &&
|
||||
members[i].GroupNumber == gid
|
||||
) {
|
||||
auto b_member = members[i].member->CastToBot();
|
||||
raid_members_bots.emplace_back(b_member);
|
||||
raid_members_bots.emplace_back(b_member);
|
||||
}
|
||||
}
|
||||
|
||||
return raid_members_bots;
|
||||
}
|
||||
|
||||
void Raid::HandleBotGroupDisband(uint32 owner, uint32 gid)
|
||||
{
|
||||
auto raid_members_bots = gid != RAID_GROUPLESS ? GetRaidGroupBotMembers(gid) : GetRaidBotMembers(owner);
|
||||
|
||||
// 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) {
|
||||
|
||||
// Remove the entire BOT group in this case
|
||||
if (
|
||||
bot_iter &&
|
||||
gid != RAID_GROUPLESS &&
|
||||
IsRaidMember(bot_iter->GetName()) &&
|
||||
IsGroupLeader(bot_iter->GetName())
|
||||
) {
|
||||
auto r_group_members = GetRaidGroupMembers(GetGroup(bot_iter->GetName()));
|
||||
auto 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->GetName());
|
||||
|
||||
for (auto member_iter: r_group_members) {
|
||||
if (member_iter.member->IsBot()) {
|
||||
auto b_member = member_iter.member->CastToBot();
|
||||
if (strcmp(b_member->GetName(), bot_iter->GetName()) == 0) {
|
||||
bot_iter->SetFollowID(owner);
|
||||
} else {
|
||||
Bot::AddBotToGroup(b_member, group_inst);
|
||||
}
|
||||
Bot::RemoveBotFromRaid(b_member);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Bot::RemoveBotFromRaid(bot_iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8 Bot::GetNumberNeedingHealedInRaidGroup(uint8& need_healed, uint8 hpr, bool includePets, Raid* raid) {
|
||||
|
||||
if (raid) {
|
||||
uint32 r_group = raid->GetGroup(GetName());
|
||||
auto raid_group_members = raid->GetRaidGroupMembers(r_group);
|
||||
|
||||
for (auto& m: raid_group_members) {
|
||||
if (m.member && !m.member->qglobal) {
|
||||
if (m.member->GetHPRatio() <= hpr) {
|
||||
need_healed++;
|
||||
}
|
||||
|
||||
if (includePets) {
|
||||
if (m.member->GetPet() && m.member->GetPet()->GetHPRatio() <= hpr) {
|
||||
need_healed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return need_healed;
|
||||
}
|
||||
|
||||
void Bot::ProcessRaidInvite(Mob* invitee, Client* invitor, bool group_invite) {
|
||||
|
||||
if (!invitee || !invitor) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (invitee->IsBot() &&
|
||||
invitor->HasRaid() &&
|
||||
invitee->GetOwner()->HasRaid() &&
|
||||
invitor->GetRaid()->IsRaidMember(invitee->GetOwner()->GetName())
|
||||
) {
|
||||
// If the Bot Owner is in our raid we need to be able to invite their Bots
|
||||
}
|
||||
else if (invitee->IsBot() && (invitee->CastToBot()->GetBotOwnerCharacterID() != invitor->CharacterID())) {
|
||||
invitor->Message(
|
||||
Chat::Red,
|
||||
fmt::format(
|
||||
"{} is not your Bot. You can only invite your own Bots, or Bots that belong to a Raid member.",
|
||||
invitee->GetCleanName()
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
Raid* raid = entity_list.GetRaidByClient(invitor);
|
||||
|
||||
Bot::CreateBotRaid(invitee, invitor, group_invite, raid);
|
||||
}
|
||||
|
||||
void Bot::CreateBotRaid(Mob* invitee, Client* invitor, bool group_invite, Raid* raid) {
|
||||
|
||||
Group* g_invitee = invitee->GetGroup();
|
||||
Group* g_invitor = invitor->GetGroup();
|
||||
|
||||
if (g_invitee && invitor->IsClient()) {
|
||||
if (!g_invitee->IsLeader(invitee)) {
|
||||
invitor->Message(
|
||||
Chat::Red,
|
||||
fmt::format(
|
||||
"You can only invite group leaders or ungrouped bots. Try {} instead.",
|
||||
g_invitee->GetLeader()->GetCleanName()
|
||||
).c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool new_raid = false;
|
||||
if (!raid) {
|
||||
new_raid = true;
|
||||
raid = new Raid(invitor);
|
||||
entity_list.AddRaid(raid);
|
||||
raid->SetRaidDetails();
|
||||
}
|
||||
|
||||
// Add Invitor to new raid
|
||||
if (new_raid) {
|
||||
if (g_invitor) {
|
||||
ProcessBotGroupAdd(g_invitor, raid, nullptr, true, true);
|
||||
} else {
|
||||
raid->SendRaidCreate(invitor);
|
||||
raid->AddMember(invitor, 0xFFFFFFFF, true, false, true);
|
||||
raid->SendMakeLeaderPacketTo(invitor->GetName(), invitor);
|
||||
if (raid->IsLocked()) {
|
||||
raid->SendRaidLockTo(invitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add Bot Group or Client Bot Group to raid
|
||||
if (g_invitee) {
|
||||
ProcessBotGroupAdd(g_invitee, raid);
|
||||
|
||||
// Add individual client to raid
|
||||
} else if (invitee->IsClient()) {
|
||||
ProcessBotGroupAdd(g_invitee, raid, invitee->CastToClient());
|
||||
|
||||
// Add individual bot to raid
|
||||
} else {
|
||||
auto gid = raid->GetGroup(invitor->GetName());
|
||||
auto b = invitee->CastToBot();
|
||||
|
||||
// gives us a choice to either invite directly into the clients Raid Group, or just into the Raid
|
||||
if (group_invite && raid->GroupCount(gid) < MAX_GROUP_MEMBERS) {
|
||||
raid->AddBot(b, gid);
|
||||
} else {
|
||||
raid->AddBot(b);
|
||||
}
|
||||
|
||||
if (new_raid) {
|
||||
invitee->SetFollowID(invitor->GetID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Bot::ProcessBotGroupAdd(Group* group, Raid* raid, Client* client, bool new_raid, bool initial) {
|
||||
|
||||
uint32 raid_free_group_id = raid->GetFreeGroup();
|
||||
if (group) {
|
||||
for (int x = 0; x < MAX_GROUP_MEMBERS; x++) {
|
||||
if (group->members[x]) {
|
||||
Client* c = nullptr;
|
||||
Bot* b = nullptr;
|
||||
|
||||
if (group->members[x] && group->members[x]->IsBot()) {
|
||||
b = group->members[x]->CastToBot();
|
||||
raid->AddBot(b, raid_free_group_id, false, x == 0, false);
|
||||
} else if (group->members[x] && group->members[x]->IsClient()) {
|
||||
c = group->members[x]->CastToClient();
|
||||
raid->SendRaidCreate(c);
|
||||
raid->AddMember(
|
||||
c,
|
||||
raid_free_group_id,
|
||||
new_raid,
|
||||
x == 0,
|
||||
false
|
||||
);
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, c);
|
||||
raid->SendBulkRaid(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
group->JoinRaidXTarget(raid, initial);
|
||||
group->DisbandGroup(true);
|
||||
} else if (client) {
|
||||
raid->SendRaidCreate(client);
|
||||
raid->AddMember(client, RAID_GROUPLESS, false, false, true);
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, client);
|
||||
raid->SendBulkRaid(client);
|
||||
if (raid->IsLocked()) {
|
||||
raid->SendRaidLockTo(client);
|
||||
}
|
||||
}
|
||||
|
||||
raid->GroupUpdate(raid_free_group_id);
|
||||
}
|
||||
|
||||
|
||||
41
zone/bot_raid.h
Normal file
41
zone/bot_raid.h
Normal file
@ -0,0 +1,41 @@
|
||||
/* 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
|
||||
|
||||
|
||||
#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 "../common/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 "raids.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#endif // BOT_RAID_H
|
||||
1816
zone/botspellsai.cpp
1816
zone/botspellsai.cpp
File diff suppressed because it is too large
Load Diff
@ -814,9 +814,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)
|
||||
else if (eqs)
|
||||
{
|
||||
eqs->QueuePacket(app, ack_req);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::FastQueuePacket(EQApplicationPacket** app, bool ack_req, CLIENT_CONN_STATUS required_state) {
|
||||
@ -1330,6 +1331,7 @@ void Client::ChannelMessageSend(const char* from, const char* to, uint8 chan_num
|
||||
|
||||
cm->chan_num = chan_num;
|
||||
strcpy(&cm->message[0], buffer);
|
||||
|
||||
QueuePacket(&app);
|
||||
|
||||
bool senderCanTrainSelf = RuleB(Client, SelfLanguageLearning);
|
||||
|
||||
@ -2047,6 +2047,7 @@ private:
|
||||
bool CanTradeFVNoDropItem();
|
||||
void SendMobPositions();
|
||||
void PlayerTradeEventLog(Trade *t, Trade *t2);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -51,7 +51,7 @@ int32 Client::GetMaxStat() const
|
||||
else {
|
||||
base = 330;
|
||||
}
|
||||
return (base);
|
||||
return base;
|
||||
}
|
||||
|
||||
int32 Client::GetMaxResist() const
|
||||
|
||||
@ -25,6 +25,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <zlib.h>
|
||||
#include "bot.h"
|
||||
#include "bot_command.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#define snprintf _snprintf
|
||||
@ -606,6 +608,29 @@ void Client::CompleteConnect()
|
||||
if (raid) {
|
||||
SetRaidGrouped(true);
|
||||
raid->LearnMembers();
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
raid->VerifyRaid();
|
||||
raid->GetRaidDetails();
|
||||
/*
|
||||
@ -1534,27 +1559,27 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
group->SetNPCMarker(NPCMarkerName);
|
||||
group->SetGroupAAs(&GLAA);
|
||||
group->SetGroupMentor(mentor_percent, mentoree_name);
|
||||
|
||||
//group->NotifyMainTank(this, 1);
|
||||
//group->NotifyMainAssist(this, 1);
|
||||
//group->NotifyPuller(this, 1);
|
||||
|
||||
// If we are the leader, force an update of our group AAs to other members in the zone, in case
|
||||
// we purchased a new one while out-of-zone.
|
||||
if (group->IsLeader(this))
|
||||
group->SendLeadershipAAUpdate();
|
||||
}
|
||||
group->LearnMembers();
|
||||
JoinGroupXTargets(group);
|
||||
group->UpdatePlayer(this);
|
||||
LFG = false;
|
||||
}
|
||||
|
||||
/* Load Bots */
|
||||
if (RuleB(Bots, Enabled)) {
|
||||
database.botdb.LoadOwnerOptions(this);
|
||||
// TODO: mod below function for loading spawned botgroups
|
||||
Bot::LoadAndSpawnAllZonedBots(this);
|
||||
}
|
||||
|
||||
// If we are the leader, force an update of our group AAs to other members in the zone, in case
|
||||
// we purchased a new one while out-of-zone.
|
||||
// needs to be done after spawning bots
|
||||
if (group && group->IsLeader(this)) {
|
||||
group->SendLeadershipAAUpdate();
|
||||
}
|
||||
|
||||
m_inv.SetGMInventory((bool)m_pp.gm); // set to current gm state for calc
|
||||
CalcBonuses();
|
||||
if (RuleB(Zone, EnableLoggedOffReplenishments) &&
|
||||
@ -2379,7 +2404,7 @@ void Client::Handle_OP_AdventureRequest(const EQApplicationPacket *app)
|
||||
if (IsRaidGrouped())
|
||||
{
|
||||
int i = 0;
|
||||
for (int x = 0; x < 72; ++x)
|
||||
for (int x = 0; x < MAX_RAID_MEMBERS; ++x)
|
||||
{
|
||||
if (i == group_members)
|
||||
{
|
||||
@ -2398,7 +2423,7 @@ void Client::Handle_OP_AdventureRequest(const EQApplicationPacket *app)
|
||||
else
|
||||
{
|
||||
int i = 0;
|
||||
for (int x = 0; x < 6; ++x)
|
||||
for (int x = 0; x < MAX_GROUP_MEMBERS; ++x)
|
||||
{
|
||||
if (i == group_members)
|
||||
{
|
||||
@ -4194,10 +4219,6 @@ void Client::Handle_OP_Bug(const EQApplicationPacket *app)
|
||||
|
||||
void Client::Handle_OP_Camp(const EQApplicationPacket *app)
|
||||
{
|
||||
if (RuleB(Bots, Enabled)) {
|
||||
Bot::BotOrderCampAll(this);
|
||||
}
|
||||
|
||||
if (IsLFP())
|
||||
worldserver.StopLFP(CharacterID());
|
||||
|
||||
@ -6984,56 +7005,58 @@ void Client::Handle_OP_GroupDisband(const EQApplicationPacket *app)
|
||||
GroupGeneric_Struct* gd = (GroupGeneric_Struct*)app->pBuffer;
|
||||
|
||||
Raid *raid = entity_list.GetRaidByClient(this);
|
||||
if (raid)
|
||||
{
|
||||
Mob* memberToDisband = nullptr;
|
||||
if (raid) {
|
||||
Mob *memberToDisband = nullptr;
|
||||
|
||||
if (!raid->IsGroupLeader(GetName()))
|
||||
if (!raid->IsGroupLeader(GetName())) {
|
||||
memberToDisband = this;
|
||||
else
|
||||
} else {
|
||||
memberToDisband = GetTarget();
|
||||
}
|
||||
|
||||
if (!memberToDisband)
|
||||
if (!memberToDisband) {
|
||||
memberToDisband = entity_list.GetMob(gd->name2);
|
||||
}
|
||||
|
||||
if (!memberToDisband)
|
||||
if (!memberToDisband) {
|
||||
memberToDisband = this;
|
||||
}
|
||||
|
||||
if (!memberToDisband->IsClient())
|
||||
if (!memberToDisband->IsOfClientBot()) {
|
||||
return;
|
||||
|
||||
}
|
||||
//we have a raid.. see if we're in a raid group
|
||||
uint32 grp = raid->GetGroup(memberToDisband->GetName());
|
||||
bool wasGrpLdr = raid->members[raid->GetPlayerIndex(memberToDisband->GetName())].IsGroupLeader;
|
||||
if (grp < 12) {
|
||||
if (wasGrpLdr) {
|
||||
raid->SetGroupLeader(memberToDisband->GetName(), false);
|
||||
for (int x = 0; x < MAX_RAID_MEMBERS; x++)
|
||||
{
|
||||
if (raid->members[x].GroupNumber == grp)
|
||||
{
|
||||
if (strlen(raid->members[x].membername) > 0 && strcmp(raid->members[x].membername, memberToDisband->GetName()) != 0)
|
||||
{
|
||||
for (int x = 0; x < MAX_RAID_MEMBERS; x++) {
|
||||
if (raid->members[x].GroupNumber == grp) {
|
||||
if (strlen(raid->members[x].membername) > 0 &&
|
||||
strcmp(raid->members[x].membername, memberToDisband->GetName()) != 0) {
|
||||
raid->SetGroupLeader(raid->members[x].membername);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
raid->MoveMember(memberToDisband->GetName(), 0xFFFFFFFF);
|
||||
raid->GroupUpdate(grp); //break
|
||||
//raid->SendRaidGroupRemove(memberToDisband->GetName(), grp);
|
||||
//raid->SendGroupUpdate(memberToDisband->CastToClient());
|
||||
raid->MoveMember(memberToDisband->GetName(), RAID_GROUPLESS);
|
||||
raid->GroupUpdate(grp);
|
||||
|
||||
if (memberToDisband->IsClient()) {
|
||||
raid->SendGroupDisband(memberToDisband->CastToClient());
|
||||
}
|
||||
}
|
||||
//we're done
|
||||
return;
|
||||
}
|
||||
|
||||
Group* group = GetGroup();
|
||||
|
||||
if (!group)
|
||||
if (!group) {
|
||||
return;
|
||||
}
|
||||
|
||||
// this block is necessary to allow more control over controlling how bots are zoned or camped.
|
||||
if (RuleB(Bots, Enabled) && Bot::GroupHasBot(group)) {
|
||||
@ -7043,13 +7066,17 @@ void Client::Handle_OP_GroupDisband(const EQApplicationPacket *app)
|
||||
}
|
||||
else {
|
||||
Mob* tempMember = entity_list.GetMob(gd->name1); //Name1 is the target you are disbanding
|
||||
|
||||
if (tempMember && tempMember->IsBot()) {
|
||||
tempMember->CastToBot()->RemoveBotFromGroup(tempMember->CastToBot(), group);
|
||||
auto b = tempMember->CastToBot();
|
||||
Bot::RemoveBotFromGroup(b, group);
|
||||
|
||||
if (LFP)
|
||||
{
|
||||
// If we are looking for players, update to show we are on our own now.
|
||||
UpdateLFP();
|
||||
}
|
||||
|
||||
return; //No need to continue from here we were removing a bot from party
|
||||
}
|
||||
}
|
||||
@ -7251,7 +7278,15 @@ void Client::Handle_OP_GroupInvite2(const EQApplicationPacket *app)
|
||||
}
|
||||
}
|
||||
else if (Invitee->IsBot()) {
|
||||
Client* inviter = entity_list.GetClientByName(gis->inviter_name);
|
||||
if (inviter && inviter->IsRaidGrouped() && !Invitee->HasRaid()) {
|
||||
Bot::ProcessRaidInvite(Invitee->CastToBot(), inviter, true);
|
||||
}
|
||||
else if (!Invitee->HasRaid()) {
|
||||
Bot::ProcessBotGroupInvite(this, std::string(Invitee->GetName()));
|
||||
} else {
|
||||
MessageString(Chat::LightGray, ALREADY_IN_RAID, Invitee->GetCleanName());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -11742,7 +11777,7 @@ void Client::Handle_OP_QueryUCSServerStatus(const EQApplicationPacket *app)
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app)
|
||||
{
|
||||
if (app->size < sizeof(RaidGeneral_Struct)) {
|
||||
LogError("Wrong size: OP_RaidCommand, size=[{}], expected at least [{}]", app->size, sizeof(RaidGeneral_Struct));
|
||||
@ -11750,18 +11785,42 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
RaidGeneral_Struct *raid_command_packet = (RaidGeneral_Struct*)app->pBuffer;
|
||||
auto raid_command_packet = (RaidGeneral_Struct*)app->pBuffer;
|
||||
switch (raid_command_packet->action)
|
||||
{
|
||||
case RaidCommandInviteIntoExisting:
|
||||
case RaidCommandInvite: {
|
||||
|
||||
Client *player_to_invite = entity_list.GetClientByName(raid_command_packet->player_name);
|
||||
Bot* player_to_invite = nullptr;
|
||||
|
||||
if (!player_to_invite)
|
||||
if (RuleB(Bots, Enabled) && entity_list.GetBotByBotName(raid_command_packet->player_name)) {
|
||||
Bot* player_to_invite = entity_list.GetBotByBotName(raid_command_packet->player_name);
|
||||
Group* player_to_invite_group = player_to_invite->GetGroup();
|
||||
|
||||
if (!player_to_invite) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (player_to_invite_group && player_to_invite_group->IsGroupMember(this)) {
|
||||
MessageString(Chat::Red, ALREADY_IN_PARTY);
|
||||
break;
|
||||
}
|
||||
|
||||
if (player_to_invite->IsRaidGrouped()) {
|
||||
MessageString(Chat::White, ALREADY_IN_RAID, player_to_invite->GetCleanName()); //must invite members not in raid...
|
||||
return;
|
||||
}
|
||||
|
||||
Bot::ProcessRaidInvite(player_to_invite, this);
|
||||
break;
|
||||
|
||||
Group *player_to_invite_group = player_to_invite->GetGroup();
|
||||
} else {
|
||||
Client* player_to_invite = entity_list.GetClientByName(raid_command_packet->player_name);
|
||||
if (!player_to_invite) {
|
||||
break;
|
||||
}
|
||||
|
||||
Group* player_to_invite_group = player_to_invite->GetGroup();
|
||||
|
||||
if (player_to_invite->HasRaid()) {
|
||||
Message(Chat::Red, "%s is already in a raid.", player_to_invite->GetName());
|
||||
@ -11772,7 +11831,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;
|
||||
@ -11780,7 +11839,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
|
||||
/* Send out invite to the client */
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct));
|
||||
RaidGeneral_Struct *raid_command = (RaidGeneral_Struct*)outapp->pBuffer;
|
||||
RaidGeneral_Struct* raid_command = (RaidGeneral_Struct*)outapp->pBuffer;
|
||||
|
||||
strn0cpy(raid_command->leader_name, raid_command_packet->leader_name, 64);
|
||||
strn0cpy(raid_command->player_name, raid_command_packet->player_name, 64);
|
||||
@ -11794,35 +11853,81 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case RaidCommandAcceptInvite: {
|
||||
Client *player_accepting_invite = entity_list.GetClientByName(raid_command_packet->player_name);
|
||||
if (player_accepting_invite) {
|
||||
if (IsRaidGrouped()) {
|
||||
player_accepting_invite->MessageString(Chat::White, ALREADY_IN_RAID, GetName()); //group failed, must invite members not in raid...
|
||||
Client* player_sending_invite = entity_list.GetClientByName(raid_command_packet->player_name);
|
||||
|
||||
// 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);
|
||||
|
||||
if (!invitee || !invitor) {
|
||||
return;
|
||||
}
|
||||
Raid *raid = entity_list.GetRaidByClient(player_accepting_invite);
|
||||
|
||||
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 (RuleB(Bots, Enabled)) {
|
||||
if (g_invitor && g_invitor->IsLeader(invitor)) {
|
||||
for (const auto& g_invitor_member : g_invitor->members) {
|
||||
if (g_invitor_member && g_invitor_member->IsBot()) {
|
||||
invitee_has_bot = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (g_invitee && g_invitee->IsLeader(invitee)) {
|
||||
for (const auto& g_invitee_member : g_invitee->members) {
|
||||
if (g_invitee_member && g_invitee_member->IsBot()) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (player_sending_invite) {
|
||||
if (IsRaidGrouped()) {
|
||||
player_sending_invite->MessageString(Chat::White, ALREADY_IN_RAID, GetName()); //group failed, must invite members not in raid...
|
||||
return;
|
||||
}
|
||||
Raid* raid = entity_list.GetRaidByClient(player_sending_invite);
|
||||
if (raid) {
|
||||
raid->VerifyRaid();
|
||||
Group *group = GetGroup();
|
||||
Group* group = GetGroup();
|
||||
if (group) {
|
||||
if (group->GroupCount() + raid->RaidCount() > MAX_RAID_MEMBERS) {
|
||||
player_accepting_invite->Message(Chat::Red, "Invite failed, group invite would create a raid larger than the maximum number of members allowed.");
|
||||
player_sending_invite->Message(Chat::Red, "Invite failed, group invite would create a raid larger than the maximum number of members allowed.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (1 + raid->RaidCount() > MAX_RAID_MEMBERS) {
|
||||
player_accepting_invite->Message(Chat::Red, "Invite failed, member invite would create a raid larger than the maximum number of members allowed.");
|
||||
player_sending_invite->Message(Chat::Red, "Invite failed, member invite would create a raid larger than the maximum number of members allowed.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (group) {//add us all
|
||||
uint32 free_group_id = raid->GetFreeGroup();
|
||||
Client *addClient = nullptr;
|
||||
for (int x = 0; x < 6; x++) {
|
||||
Client* addClient = nullptr;
|
||||
for (int x = 0; x < MAX_GROUP_MEMBERS; x++) {
|
||||
if (group->members[x]) {
|
||||
Client *c = nullptr;
|
||||
Client* c = nullptr;
|
||||
if (group->members[x]->IsClient())
|
||||
c = group->members[x]->CastToClient();
|
||||
else
|
||||
@ -11835,12 +11940,12 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
raid->SendRaidCreate(c);
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, c);
|
||||
if (group->IsLeader(group->members[x]))
|
||||
raid->AddMember(c, free_group_id, false, true);
|
||||
else
|
||||
raid->AddMember(c, free_group_id);
|
||||
raid->SendBulkRaid(c);
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, c);
|
||||
if (raid->IsLocked()) {
|
||||
raid->SendRaidLockTo(c);
|
||||
}
|
||||
@ -11852,9 +11957,9 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
}
|
||||
else {
|
||||
raid->SendRaidCreate(this);
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, this);
|
||||
raid->AddMember(this);
|
||||
raid->SendBulkRaid(this);
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, this);
|
||||
if (raid->IsLocked()) {
|
||||
raid->SendRaidLockTo(this);
|
||||
}
|
||||
@ -11862,76 +11967,74 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
}
|
||||
else
|
||||
{
|
||||
Group *player_invited_group = player_accepting_invite->GetGroup();
|
||||
Group *group = GetGroup();
|
||||
auto player_sending_invite_group = player_sending_invite->GetGroup();
|
||||
Group* group = GetGroup();
|
||||
if (group) //if our target has a group
|
||||
{
|
||||
raid = new Raid(player_accepting_invite);
|
||||
raid = new Raid(player_sending_invite);
|
||||
entity_list.AddRaid(raid);
|
||||
raid->SetRaidDetails();
|
||||
|
||||
uint32 raid_free_group_id = raid->GetFreeGroup();
|
||||
|
||||
/* If we already have a group then cycle through adding us... */
|
||||
if (player_invited_group) {
|
||||
Client *client_to_be_leader = nullptr;
|
||||
for (int x = 0; x < 6; x++) {
|
||||
if (player_invited_group->members[x]) {
|
||||
if (player_sending_invite_group) {
|
||||
Client* client_to_be_leader = nullptr;
|
||||
for (const auto& sending_invite_member : player_sending_invite_group->members) {
|
||||
if (sending_invite_member) {
|
||||
if (!client_to_be_leader) {
|
||||
if (player_invited_group->members[x]->IsClient()) {
|
||||
client_to_be_leader = player_invited_group->members[x]->CastToClient();
|
||||
if (sending_invite_member->IsClient()) {
|
||||
client_to_be_leader = sending_invite_member->CastToClient();
|
||||
raid->SetGroupLeader(client_to_be_leader->GetName());
|
||||
}
|
||||
}
|
||||
if (player_invited_group->IsLeader(player_invited_group->members[x])) {
|
||||
Client *c = nullptr;
|
||||
if (player_sending_invite_group->IsLeader(sending_invite_member)) {
|
||||
Client* c = nullptr;
|
||||
|
||||
if (player_invited_group->members[x]->IsClient())
|
||||
c = player_invited_group->members[x]->CastToClient();
|
||||
if (sending_invite_member->IsClient())
|
||||
c = sending_invite_member->CastToClient();
|
||||
else
|
||||
continue;
|
||||
|
||||
raid->SendRaidCreate(c);
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, c);
|
||||
raid->AddMember(c, raid_free_group_id, true, true, true);
|
||||
raid->SendBulkRaid(c);
|
||||
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, c);
|
||||
if (raid->IsLocked()) {
|
||||
raid->SendRaidLockTo(c);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Client *c = nullptr;
|
||||
Client* c = nullptr;
|
||||
|
||||
if (player_invited_group->members[x]->IsClient())
|
||||
c = player_invited_group->members[x]->CastToClient();
|
||||
if (sending_invite_member->IsClient())
|
||||
c = sending_invite_member->CastToClient();
|
||||
else
|
||||
continue;
|
||||
|
||||
raid->SendRaidCreate(c);
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, c);
|
||||
raid->AddMember(c, raid_free_group_id);
|
||||
raid->SendBulkRaid(c);
|
||||
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, c);
|
||||
if (raid->IsLocked()) {
|
||||
raid->SendRaidLockTo(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
player_invited_group->JoinRaidXTarget(raid, true);
|
||||
player_invited_group->DisbandGroup(true);
|
||||
player_sending_invite_group->JoinRaidXTarget(raid, true);
|
||||
player_sending_invite_group->DisbandGroup(true);
|
||||
raid->GroupUpdate(raid_free_group_id);
|
||||
raid_free_group_id = raid->GetFreeGroup();
|
||||
}
|
||||
else {
|
||||
raid->SendRaidCreate(player_accepting_invite);
|
||||
raid->AddMember(player_accepting_invite, 0xFFFFFFFF, true, false, true);
|
||||
raid->SendRaidCreate(player_sending_invite);
|
||||
raid->AddMember(player_sending_invite, RAID_GROUPLESS, true, false, true);
|
||||
}
|
||||
|
||||
Client *client_to_add = nullptr;
|
||||
Client* client_to_add = nullptr;
|
||||
/* Add client to an existing group */
|
||||
for (int x = 0; x < 6; x++) {
|
||||
for (int x = 0; x < MAX_GROUP_MEMBERS; x++) {
|
||||
if (group->members[x]) {
|
||||
if (!client_to_add) {
|
||||
if (group->members[x]->IsClient()) {
|
||||
@ -11940,7 +12043,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
}
|
||||
}
|
||||
if (group->IsLeader(group->members[x])) {
|
||||
Client *c = nullptr;
|
||||
Client* c = nullptr;
|
||||
|
||||
if (group->members[x]->IsClient())
|
||||
c = group->members[x]->CastToClient();
|
||||
@ -11948,9 +12051,9 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
continue;
|
||||
|
||||
raid->SendRaidCreate(c);
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, c);
|
||||
raid->AddMember(c, raid_free_group_id, false, true);
|
||||
raid->SendBulkRaid(c);
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, c);
|
||||
|
||||
if (raid->IsLocked()) {
|
||||
raid->SendRaidLockTo(c);
|
||||
@ -11958,7 +12061,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
}
|
||||
else
|
||||
{
|
||||
Client *c = nullptr;
|
||||
Client* c = nullptr;
|
||||
|
||||
if (group->members[x]->IsClient())
|
||||
c = group->members[x]->CastToClient();
|
||||
@ -11966,10 +12069,9 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
continue;
|
||||
|
||||
raid->SendRaidCreate(c);
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, c);
|
||||
raid->AddMember(c, raid_free_group_id);
|
||||
raid->SendBulkRaid(c);
|
||||
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, c);
|
||||
if (raid->IsLocked()) {
|
||||
raid->SendRaidLockTo(c);
|
||||
}
|
||||
@ -11983,50 +12085,49 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
}
|
||||
/* Target does not have a group */
|
||||
else {
|
||||
if (player_invited_group) {
|
||||
if (player_sending_invite_group) {
|
||||
|
||||
raid = new Raid(player_accepting_invite);
|
||||
raid = new Raid(player_sending_invite);
|
||||
|
||||
entity_list.AddRaid(raid);
|
||||
raid->SetRaidDetails();
|
||||
Client *addClientig = nullptr;
|
||||
for (int x = 0; x < 6; x++) {
|
||||
if (player_invited_group->members[x]) {
|
||||
Client* addClientig = nullptr;
|
||||
for (int x = 0; x < MAX_GROUP_MEMBERS; x++) {
|
||||
if (player_sending_invite_group->members[x]) {
|
||||
if (!addClientig) {
|
||||
if (player_invited_group->members[x]->IsClient()) {
|
||||
addClientig = player_invited_group->members[x]->CastToClient();
|
||||
if (player_sending_invite_group->members[x]->IsClient()) {
|
||||
addClientig = player_sending_invite_group->members[x]->CastToClient();
|
||||
raid->SetGroupLeader(addClientig->GetName());
|
||||
}
|
||||
}
|
||||
if (player_invited_group->IsLeader(player_invited_group->members[x])) {
|
||||
Client *c = nullptr;
|
||||
if (player_sending_invite_group->IsLeader(player_sending_invite_group->members[x])) {
|
||||
Client* c = nullptr;
|
||||
|
||||
if (player_invited_group->members[x]->IsClient())
|
||||
c = player_invited_group->members[x]->CastToClient();
|
||||
if (player_sending_invite_group->members[x]->IsClient())
|
||||
c = player_sending_invite_group->members[x]->CastToClient();
|
||||
else
|
||||
continue;
|
||||
|
||||
raid->SendRaidCreate(c);
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, c);
|
||||
raid->AddMember(c, 0, true, true, true);
|
||||
raid->SendBulkRaid(c);
|
||||
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, c);
|
||||
if (raid->IsLocked()) {
|
||||
raid->SendRaidLockTo(c);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Client *c = nullptr;
|
||||
if (player_invited_group->members[x]->IsClient())
|
||||
c = player_invited_group->members[x]->CastToClient();
|
||||
Client* c = nullptr;
|
||||
if (player_sending_invite_group->members[x]->IsClient())
|
||||
c = player_sending_invite_group->members[x]->CastToClient();
|
||||
else
|
||||
continue;
|
||||
|
||||
raid->SendRaidCreate(c);
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, c);
|
||||
raid->AddMember(c, 0);
|
||||
raid->SendBulkRaid(c);
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, c);
|
||||
if (raid->IsLocked()) {
|
||||
raid->SendRaidLockTo(c);
|
||||
}
|
||||
@ -12034,26 +12135,26 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
}
|
||||
}
|
||||
raid->SendRaidCreate(this);
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, this);
|
||||
raid->SendBulkRaid(this);
|
||||
player_invited_group->JoinRaidXTarget(raid, true);
|
||||
player_sending_invite_group->JoinRaidXTarget(raid, true);
|
||||
raid->AddMember(this);
|
||||
player_invited_group->DisbandGroup(true);
|
||||
player_sending_invite_group->DisbandGroup(true);
|
||||
raid->GroupUpdate(0);
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, this);
|
||||
if (raid->IsLocked()) {
|
||||
raid->SendRaidLockTo(this);
|
||||
}
|
||||
}
|
||||
else { // neither has a group
|
||||
raid = new Raid(player_accepting_invite);
|
||||
raid = new Raid(player_sending_invite);
|
||||
entity_list.AddRaid(raid);
|
||||
raid->SetRaidDetails();
|
||||
raid->SendRaidCreate(player_accepting_invite);
|
||||
raid->SendRaidCreate(player_sending_invite);
|
||||
raid->SendRaidCreate(this);
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, this);
|
||||
raid->AddMember(player_accepting_invite, 0xFFFFFFFF, true, false, true);
|
||||
raid->AddMember(player_sending_invite, RAID_GROUPLESS, true, false, true);
|
||||
raid->SendBulkRaid(this);
|
||||
raid->AddMember(this);
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, this);
|
||||
if (raid->IsLocked()) {
|
||||
raid->SendRaidLockTo(this);
|
||||
}
|
||||
@ -12064,10 +12165,56 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
break;
|
||||
}
|
||||
case RaidCommandDisband: {
|
||||
Raid *raid = entity_list.GetRaidByClient(this);
|
||||
Raid* raid = entity_list.GetRaidByClient(this);
|
||||
Client* c_to_disband = entity_list.GetClientByName(raid_command_packet->leader_name);
|
||||
Client* c_doing_disband = entity_list.GetClientByName(raid_command_packet->player_name);
|
||||
|
||||
if (raid) {
|
||||
raid->VerifyRaid();
|
||||
uint32 group = raid->GetGroup(raid_command_packet->leader_name);
|
||||
|
||||
if (RuleB(Bots, Enabled)) {
|
||||
Bot* const b_to_disband = entity_list.GetBotByBotName(raid_command_packet->leader_name);
|
||||
|
||||
//Added to remove all bots if the Bot_Owner is removed from the Raid
|
||||
//Does not camp the Bots, just removes from the raid
|
||||
if (c_to_disband) {
|
||||
raid->HandleBotGroupDisband(c_to_disband->CharacterID());
|
||||
raid->RemoveMember(raid_command_packet->leader_name);
|
||||
if (raid->IsLeader(c_to_disband->GetName())) {
|
||||
uint32 i = raid->GetPlayerIndex(raid_command_packet->leader_name);
|
||||
raid->SetNewRaidLeader(i);
|
||||
}
|
||||
raid->SendGroupDisband(c_to_disband);
|
||||
raid->GroupUpdate(group);
|
||||
if (!raid->RaidCount() || !raid->GetLeader()) {
|
||||
raid->DisbandRaid();
|
||||
}
|
||||
break;
|
||||
} else if (b_to_disband) {
|
||||
uint32 gid = raid->GetGroup(b_to_disband->GetName());
|
||||
|
||||
if (gid < 12 && (raid->IsGroupLeader(b_to_disband->GetName()) || raid->GroupCount(gid) < 2)) {
|
||||
uint32 owner_id = b_to_disband->CastToBot()->GetOwner()->CastToClient()->CharacterID();
|
||||
raid->HandleBotGroupDisband(owner_id, gid);
|
||||
|
||||
} else if (b_to_disband && raid->IsRaidMember(b_to_disband->GetName())) {
|
||||
Bot::RemoveBotFromRaid(b_to_disband);
|
||||
|
||||
} else if (gid < 12 && raid->GetGroupLeader(gid) && raid->GetGroupLeader(gid)->IsBot()) {
|
||||
c_doing_disband->Message(
|
||||
Chat::Yellow,
|
||||
fmt::format(
|
||||
"{} is in a Bot Group. Please disband {} instead to remove the entire Bot group.",
|
||||
raid_command_packet->leader_name,
|
||||
raid->GetGroupLeader(gid)->CastToBot()->GetName()
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (group < 12) {
|
||||
uint32 i = raid->GetPlayerIndex(raid_command_packet->leader_name);
|
||||
if (raid->members[i].IsGroupLeader) { //assign group leader to someone else
|
||||
@ -12081,25 +12228,15 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (raid->members[i].IsRaidLeader) {
|
||||
for (int x = 0; x < MAX_RAID_MEMBERS; x++) {
|
||||
if (strlen(raid->members[x].membername) > 0 && strcmp(raid->members[x].membername, raid->members[i].membername) != 0)
|
||||
{
|
||||
raid->SetRaidLeader(raid->members[i].membername, raid->members[x].membername);
|
||||
raid->UpdateRaidAAs();
|
||||
raid->SendAllRaidLeadershipAA();
|
||||
break;
|
||||
raid->SetNewRaidLeader(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
raid->RemoveMember(raid_command_packet->leader_name);
|
||||
Client *c = entity_list.GetClientByName(raid_command_packet->leader_name);
|
||||
if (c)
|
||||
Client* c = entity_list.GetClientByName(raid_command_packet->leader_name);
|
||||
if (c) {
|
||||
|
||||
raid->SendGroupDisband(c);
|
||||
}
|
||||
else {
|
||||
auto pack =
|
||||
new ServerPacket(ServerOP_RaidGroupDisband, sizeof(ServerRaidGeneralAction_Struct));
|
||||
@ -12111,22 +12248,22 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
//r->SendRaidGroupRemove(ri->leader_name, grp);
|
||||
raid->GroupUpdate(group);// break
|
||||
//}
|
||||
if (!raid->RaidCount())
|
||||
raid->DisbandRaid();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RaidCommandMoveGroup:
|
||||
{
|
||||
Raid *raid = entity_list.GetRaidByClient(this);
|
||||
Raid* raid = entity_list.GetRaidByClient(this);
|
||||
if (raid) {
|
||||
/* Moving to group */
|
||||
if (raid_command_packet->parameter < 12) {
|
||||
uint8 group_count = raid->GroupCount(raid_command_packet->parameter);
|
||||
|
||||
if (group_count < 6) {
|
||||
Client *c = entity_list.GetClientByName(raid_command_packet->leader_name);
|
||||
Client* c = entity_list.GetClientByName(raid_command_packet->leader_name);
|
||||
uint32 old_group = raid->GetGroup(raid_command_packet->leader_name);
|
||||
if (raid_command_packet->parameter == old_group) //don't rejoin grp if we order to join same group.
|
||||
break;
|
||||
@ -12143,7 +12280,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
raid->SetGroupLeader(raid->members[x].membername);
|
||||
raid->UpdateGroupAAs(old_group);
|
||||
|
||||
Client *client_to_update = entity_list.GetClientByName(raid->members[x].membername);
|
||||
Client* client_to_update = entity_list.GetClientByName(raid->members[x].membername);
|
||||
if (client_to_update) {
|
||||
raid->SendRaidRemove(raid->members[x].membername, client_to_update);
|
||||
raid->SendRaidCreate(client_to_update);
|
||||
@ -12156,7 +12293,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
}
|
||||
else {
|
||||
auto pack = new ServerPacket(ServerOP_RaidChangeGroup, sizeof(ServerRaidGeneralAction_Struct));
|
||||
ServerRaidGeneralAction_Struct *raid_command_packet = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
|
||||
ServerRaidGeneralAction_Struct* raid_command_packet = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
|
||||
|
||||
raid_command_packet->rid = raid->GetID();
|
||||
raid_command_packet->zoneid = zone->GetZoneID();
|
||||
@ -12204,17 +12341,17 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
}
|
||||
/* Move player to ungrouped bank */
|
||||
else {
|
||||
Client *c = entity_list.GetClientByName(raid_command_packet->leader_name);
|
||||
Client* c = entity_list.GetClientByName(raid_command_packet->leader_name);
|
||||
uint32 oldgrp = raid->GetGroup(raid_command_packet->leader_name);
|
||||
if (raid->members[raid->GetPlayerIndex(raid_command_packet->leader_name)].IsGroupLeader) {
|
||||
raid->SetGroupLeader(raid_command_packet->leader_name, false);
|
||||
for (int x = 0; x < MAX_RAID_MEMBERS; x++) {
|
||||
if (raid->members[x].GroupNumber == oldgrp && strlen(raid->members[x].membername) > 0 && strcmp(raid->members[x].membername, raid_command_packet->leader_name) != 0){
|
||||
if (raid->members[x].GroupNumber == oldgrp && strlen(raid->members[x].membername) > 0 && strcmp(raid->members[x].membername, raid_command_packet->leader_name) != 0) {
|
||||
|
||||
raid->SetGroupLeader(raid->members[x].membername);
|
||||
raid->UpdateGroupAAs(oldgrp);
|
||||
|
||||
Client *client_leaving_group = entity_list.GetClientByName(raid->members[x].membername);
|
||||
Client* client_leaving_group = entity_list.GetClientByName(raid->members[x].membername);
|
||||
if (client_leaving_group) {
|
||||
raid->SendRaidRemove(raid->members[x].membername, client_leaving_group);
|
||||
raid->SendRaidCreate(client_leaving_group);
|
||||
@ -12226,8 +12363,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
}
|
||||
}
|
||||
else {
|
||||
auto pack = new ServerPacket( ServerOP_RaidChangeGroup, sizeof(ServerRaidGeneralAction_Struct));
|
||||
ServerRaidGeneralAction_Struct *raid_command = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
|
||||
auto pack = new ServerPacket(ServerOP_RaidChangeGroup, sizeof(ServerRaidGeneralAction_Struct));
|
||||
ServerRaidGeneralAction_Struct* raid_command = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
|
||||
|
||||
raid_command->rid = raid->GetID();
|
||||
strn0cpy(raid_command->playername, raid->members[x].membername, 64);
|
||||
@ -12241,7 +12378,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
}
|
||||
}
|
||||
}
|
||||
raid->MoveMember(raid_command_packet->leader_name, 0xFFFFFFFF);
|
||||
raid->MoveMember(raid_command_packet->leader_name, RAID_GROUPLESS);
|
||||
if (c) {
|
||||
raid->SendGroupDisband(c);
|
||||
}
|
||||
@ -12263,7 +12400,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
}
|
||||
}
|
||||
|
||||
Client *client_moved = entity_list.GetClientByName(raid_command_packet->leader_name);
|
||||
Client* client_moved = entity_list.GetClientByName(raid_command_packet->leader_name);
|
||||
|
||||
if (client_moved && client_moved->GetRaid()) {
|
||||
client_moved->GetRaid()->SendHPManaEndPacketsTo(client_moved);
|
||||
@ -12279,7 +12416,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
}
|
||||
case RaidCommandRaidLock:
|
||||
{
|
||||
Raid *raid = entity_list.GetRaidByClient(this);
|
||||
Raid* raid = entity_list.GetRaidByClient(this);
|
||||
if (raid) {
|
||||
if (!raid->IsLocked())
|
||||
raid->LockRaid(true);
|
||||
@ -12290,7 +12427,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
}
|
||||
case RaidCommandRaidUnlock:
|
||||
{
|
||||
Raid *raid = entity_list.GetRaidByClient(this);
|
||||
Raid* raid = entity_list.GetRaidByClient(this);
|
||||
if (raid)
|
||||
{
|
||||
if (raid->IsLocked())
|
||||
@ -12303,7 +12440,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
case RaidCommandLootType2:
|
||||
case RaidCommandLootType:
|
||||
{
|
||||
Raid *raid = entity_list.GetRaidByClient(this);
|
||||
Raid* raid = entity_list.GetRaidByClient(this);
|
||||
if (raid) {
|
||||
Message(Chat::Yellow, "Loot type changed to: %d.", raid_command_packet->parameter);
|
||||
raid->ChangeLootType(raid_command_packet->parameter);
|
||||
@ -12314,7 +12451,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
case RaidCommandAddLooter2:
|
||||
case RaidCommandAddLooter:
|
||||
{
|
||||
Raid *raid = entity_list.GetRaidByClient(this);
|
||||
Raid* raid = entity_list.GetRaidByClient(this);
|
||||
if (raid) {
|
||||
Message(Chat::Yellow, "Adding %s as a raid looter.", raid_command_packet->leader_name);
|
||||
raid->AddRaidLooter(raid_command_packet->leader_name);
|
||||
@ -12325,7 +12462,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
case RaidCommandRemoveLooter2:
|
||||
case RaidCommandRemoveLooter:
|
||||
{
|
||||
Raid *raid = entity_list.GetRaidByClient(this);
|
||||
Raid* raid = entity_list.GetRaidByClient(this);
|
||||
if (raid) {
|
||||
Message(Chat::Yellow, "Removing %s as a raid looter.", raid_command_packet->leader_name);
|
||||
raid->RemoveRaidLooter(raid_command_packet->leader_name);
|
||||
@ -12335,7 +12472,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
|
||||
case RaidCommandMakeLeader:
|
||||
{
|
||||
Raid *raid = entity_list.GetRaidByClient(this);
|
||||
Raid* raid = entity_list.GetRaidByClient(this);
|
||||
if (raid) {
|
||||
if (strcmp(raid->leadername, GetName()) == 0) {
|
||||
raid->SetRaidLeader(GetName(), raid_command_packet->leader_name);
|
||||
@ -12348,11 +12485,11 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
|
||||
case RaidCommandSetMotd:
|
||||
{
|
||||
Raid *raid = entity_list.GetRaidByClient(this);
|
||||
Raid* raid = entity_list.GetRaidByClient(this);
|
||||
if (!raid)
|
||||
break;
|
||||
// we don't use the RaidGeneral here!
|
||||
RaidMOTD_Struct *motd = (RaidMOTD_Struct *)app->pBuffer;
|
||||
RaidMOTD_Struct* motd = (RaidMOTD_Struct*)app->pBuffer;
|
||||
raid->SetRaidMOTD(std::string(motd->motd));
|
||||
raid->SaveRaidMOTD();
|
||||
raid->SendRaidMOTDToWorld();
|
||||
@ -12366,6 +12503,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Client::Handle_OP_RandomReq(const EQApplicationPacket *app)
|
||||
{
|
||||
if (app->size != sizeof(RandomReq_Struct)) {
|
||||
|
||||
@ -194,6 +194,9 @@ bool Client::Process() {
|
||||
}
|
||||
|
||||
if (camp_timer.Check()) {
|
||||
Raid* raid = entity_list.GetRaidByClient(this);
|
||||
if (raid)
|
||||
raid->RemoveMember(this->GetName());
|
||||
LeaveGroup();
|
||||
Save();
|
||||
if (GetMerc())
|
||||
|
||||
@ -204,7 +204,7 @@ void command_pvp(Client *c, const Seperator *sep);
|
||||
void command_qglobal(Client *c, const Seperator *sep);
|
||||
void command_questerrors(Client *c, const Seperator *sep);
|
||||
void command_race(Client *c, const Seperator *sep);
|
||||
void command_raidloot(Client *c, const Seperator *sep);
|
||||
void command_raidloot(Client* c, const Seperator* sep);
|
||||
void command_randomfeatures(Client *c, const Seperator *sep);
|
||||
void command_refreshgroup(Client *c, const Seperator *sep);
|
||||
void command_reload(Client *c, const Seperator *sep);
|
||||
|
||||
@ -389,9 +389,7 @@ void EntityList::GroupProcess()
|
||||
for (auto &group : group_list)
|
||||
group->Process();
|
||||
|
||||
#if EQDEBUG >= 5
|
||||
CheckGroupList (__FILE__, __LINE__);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void EntityList::QueueToGroupsForNPCHealthAA(Mob *sender, const EQApplicationPacket *app)
|
||||
@ -609,9 +607,7 @@ void EntityList::AddGroup(Group *group)
|
||||
}
|
||||
|
||||
AddGroup(group, gid);
|
||||
#if EQDEBUG >= 5
|
||||
CheckGroupList (__FILE__, __LINE__);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void EntityList::AddGroup(Group *group, uint32 gid)
|
||||
@ -2115,9 +2111,6 @@ Group *EntityList::GetGroupByMob(Mob *mob)
|
||||
return *iterator;
|
||||
++iterator;
|
||||
}
|
||||
#if EQDEBUG >= 5
|
||||
CheckGroupList (__FILE__, __LINE__);
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -2132,9 +2125,6 @@ Group *EntityList::GetGroupByLeaderName(const char *leader)
|
||||
return *iterator;
|
||||
++iterator;
|
||||
}
|
||||
#if EQDEBUG >= 5
|
||||
CheckGroupList (__FILE__, __LINE__);
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -2149,9 +2139,6 @@ Group *EntityList::GetGroupByID(uint32 group_id)
|
||||
return *iterator;
|
||||
++iterator;
|
||||
}
|
||||
#if EQDEBUG >= 5
|
||||
CheckGroupList (__FILE__, __LINE__);
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -2170,13 +2157,12 @@ Group *EntityList::GetGroupByClient(Client *client)
|
||||
iterator = group_list.begin();
|
||||
|
||||
while (iterator != group_list.end()) {
|
||||
if ((*iterator)->IsGroupMember(client->CastToMob()))
|
||||
if ((*iterator)->IsGroupMember(client->CastToMob())) {
|
||||
return *iterator;
|
||||
}
|
||||
++iterator;
|
||||
}
|
||||
#if EQDEBUG >= 5
|
||||
CheckGroupList (__FILE__, __LINE__);
|
||||
#endif
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -2187,9 +2173,9 @@ Raid *EntityList::GetRaidByLeaderName(const char *leader)
|
||||
iterator = raid_list.begin();
|
||||
|
||||
while (iterator != raid_list.end()) {
|
||||
if ((*iterator)->GetLeader())
|
||||
if(strcmp((*iterator)->GetLeader()->GetName(), leader) == 0)
|
||||
if ((*iterator)->GetLeader() && strcmp((*iterator)->GetLeader()->GetName(), leader) == 0) {
|
||||
return *iterator;
|
||||
}
|
||||
++iterator;
|
||||
}
|
||||
return nullptr;
|
||||
@ -2209,30 +2195,71 @@ 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) {
|
||||
if (member.member) {
|
||||
if (member.member == client) {
|
||||
for (const auto& member : (*iterator)->members) {
|
||||
if (member.member && member.member == client) {
|
||||
client->p_raid_instance = *iterator;
|
||||
return *iterator;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++iterator;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
Raid* EntityList::GetRaidByBotName(const char* name)
|
||||
{
|
||||
std::list<RaidMember> rm;
|
||||
auto GetMembersWithNames = [&rm](Raid const* r) -> std::list<RaidMember> {
|
||||
for (const auto& m : r->members) {
|
||||
if (strlen(m.membername) > 0)
|
||||
rm.push_back(m);
|
||||
}
|
||||
return rm;
|
||||
};
|
||||
|
||||
for (const auto& r : raid_list) {
|
||||
for (const auto& m : GetMembersWithNames(r)) {
|
||||
if (strcmp(m.membername, name) == 0) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Raid* EntityList::GetRaidByBot(const Bot* bot)
|
||||
{
|
||||
std::list<RaidMember> rm;
|
||||
auto GetMembersWhoAreBots = [&rm](Raid* r) -> std::list<RaidMember> {
|
||||
for (auto const& m : r->members) {
|
||||
if (m.IsBot) {
|
||||
rm.push_back(m);
|
||||
}
|
||||
}
|
||||
return rm;
|
||||
};
|
||||
|
||||
for (const auto& r : raid_list) {
|
||||
for (const auto& m : GetMembersWhoAreBots(r)) {
|
||||
if (m.member->CastToBot() == bot) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
Raid *EntityList::GetRaidByMob(Mob *mob)
|
||||
{
|
||||
@ -2658,6 +2685,12 @@ void EntityList::RemoveAllNPCs()
|
||||
npc_limit_list.clear();
|
||||
}
|
||||
|
||||
void EntityList::RemoveAllBots()
|
||||
{
|
||||
// doesn't clear the data
|
||||
bot_list.clear();
|
||||
}
|
||||
|
||||
void EntityList::RemoveAllMercs()
|
||||
{
|
||||
// doesn't clear the data
|
||||
@ -2671,9 +2704,6 @@ void EntityList::RemoveAllGroups()
|
||||
group_list.pop_front();
|
||||
safe_delete(group);
|
||||
}
|
||||
#if EQDEBUG >= 5
|
||||
CheckGroupList (__FILE__, __LINE__);
|
||||
#endif
|
||||
}
|
||||
|
||||
void EntityList::RemoveAllRaids()
|
||||
@ -3081,6 +3111,8 @@ void EntityList::Clear()
|
||||
{
|
||||
RemoveAllClients();
|
||||
entity_list.RemoveAllTraps(); //we can have child npcs so we go first
|
||||
entity_list.RemoveAllMercs();
|
||||
entity_list.RemoveAllBots();
|
||||
entity_list.RemoveAllNPCs();
|
||||
entity_list.RemoveAllMobs();
|
||||
entity_list.RemoveAllCorpses();
|
||||
|
||||
@ -192,7 +192,8 @@ public:
|
||||
Client* GetRandomClient(const glm::vec3& location = glm::vec3(0.f), float distance = 0, Client* exclude_client = nullptr);
|
||||
NPC* GetRandomNPC(const glm::vec3& location = glm::vec3(0.f), float distance = 0, NPC* exclude_npc = nullptr);
|
||||
Mob* GetRandomMob(const glm::vec3& location = glm::vec3(0.f), float distance = 0, Mob* exclude_mob = nullptr);
|
||||
Group *GetGroupByMob(Mob* mob);
|
||||
Group* GetGroupByMob(Mob* mob);
|
||||
Group* GetGroupByBot(Bot* bot);
|
||||
bool IsInSameGroupOrRaidGroup(Client *client1, Client *client2);
|
||||
Group *GetGroupByClient(Client* client);
|
||||
Group *GetGroupByID(uint32 id);
|
||||
@ -201,6 +202,8 @@ public:
|
||||
Raid *GetRaidByClient(Client* client);
|
||||
Raid *GetRaidByID(uint32 id);
|
||||
Raid *GetRaidByLeaderName(const char *leader);
|
||||
Raid* GetRaidByBotName(const char* name);
|
||||
Raid* GetRaidByBot(const Bot* bot);
|
||||
|
||||
Corpse *GetCorpseByOwner(Client* client);
|
||||
Corpse *GetCorpseByOwnerWithinRange(Client* client, Mob* center, int range);
|
||||
@ -304,6 +307,7 @@ public:
|
||||
void RemoveAllMobs();
|
||||
void RemoveAllClients();
|
||||
void RemoveAllNPCs();
|
||||
void RemoveAllBots();
|
||||
void RemoveAllMercs();
|
||||
void RemoveAllGroups();
|
||||
void RemoveAllCorpses();
|
||||
@ -619,7 +623,7 @@ private:
|
||||
bool RemoveBot(uint16 entityID);
|
||||
Mob* GetMobByBotID(uint32 botID);
|
||||
Bot* GetBotByBotID(uint32 botID);
|
||||
Bot* GetBotByBotName(std::string botName);
|
||||
Bot* GetBotByBotName(std::string_view botName);
|
||||
Client* GetBotOwnerByBotEntityID(uint32 entity_id);
|
||||
Client* GetBotOwnerByBotID(const uint32 bot_id);
|
||||
std::list<Bot*> GetBotsByBotOwnerCharacterID(uint32 botOwnerCharacterID);
|
||||
|
||||
@ -1200,7 +1200,7 @@ void Raid::SplitExp(const uint64 exp, Mob* other) {
|
||||
}
|
||||
|
||||
for (const auto& m : members) {
|
||||
if (m.member) {
|
||||
if (m.member && !m.IsBot) {
|
||||
const int32 diff = m.member->GetLevel() - highest_level;
|
||||
int32 max_diff = -(m.member->GetLevel() * 15 / 10 - m.member->GetLevel());
|
||||
|
||||
|
||||
@ -67,4 +67,3 @@ void command_raidloot(Client *c, const Seperator *sep)
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
#include "worldserver.h"
|
||||
#include "string_ids.h"
|
||||
#include "../common/events/player_event_logs.h"
|
||||
#include "../common/repositories/group_id_repository.h"
|
||||
|
||||
extern EntityList entity_list;
|
||||
extern WorldServer worldserver;
|
||||
@ -246,7 +247,7 @@ 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))
|
||||
if (!strcasecmp(membername[i], NewMemberName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -495,7 +496,7 @@ void Group::SendEndurancePacketFrom(Mob* member)
|
||||
|
||||
//updates a group member's client pointer when they zone in
|
||||
//if the group was in the zone already
|
||||
bool Group::UpdatePlayer(Mob* update){
|
||||
bool Group::UpdatePlayer(Mob* update) {
|
||||
|
||||
if (!update)
|
||||
return false;
|
||||
@ -1138,29 +1139,30 @@ 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());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
|
||||
if (results.RowCount() == 0) {
|
||||
LogError(
|
||||
"Error getting group members for group [{}]: [{}]",
|
||||
(unsigned long) GetID(),
|
||||
results.ErrorMessage().c_str()
|
||||
auto rows = GroupIdRepository::GetWhere(
|
||||
database,
|
||||
fmt::format(
|
||||
"groupid = {}",
|
||||
GetID()
|
||||
)
|
||||
);
|
||||
|
||||
if (rows.empty()) {
|
||||
LogError(
|
||||
"Error getting group members for group [{}]",
|
||||
GetID()
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
int memberIndex = 0;
|
||||
for(auto row = results.begin(); row != results.end(); ++row) {
|
||||
if(!row[0])
|
||||
for (const auto& member : rows) {
|
||||
if (member.name.empty()) {
|
||||
continue;
|
||||
|
||||
}
|
||||
members[memberIndex] = nullptr;
|
||||
strn0cpy(membername[memberIndex], row[0], 64);
|
||||
|
||||
strn0cpy(membername[memberIndex], member.name.c_str(), 64);
|
||||
memberIndex++;
|
||||
}
|
||||
|
||||
@ -1174,36 +1176,23 @@ void Group::VerifyGroup() {
|
||||
Only called every once in a while (on member re-join for now).
|
||||
*/
|
||||
|
||||
uint32 i;
|
||||
for (i = 0; i < MAX_GROUP_MEMBERS; i++) {
|
||||
for (uint32 i = 0; i < MAX_GROUP_MEMBERS; i++) {
|
||||
if (membername[i][0] == '\0') {
|
||||
#if EQDEBUG >= 7
|
||||
LogDebug("Group [{}]: Verify [{}]: Empty.\n", (unsigned long)GetID(), i);
|
||||
#endif
|
||||
members[i] = nullptr;
|
||||
continue;
|
||||
}
|
||||
|
||||
Mob *them = entity_list.GetMob(membername[i]);
|
||||
if(them == nullptr && members[i] != nullptr) { //they aren't in zone
|
||||
#if EQDEBUG >= 6
|
||||
LogDebug("Member of group [{}] named [{}] has disappeared!!", (unsigned long)GetID(), membername[i]);
|
||||
#endif
|
||||
membername[i][0] = '\0';
|
||||
members[i] = nullptr;
|
||||
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]);
|
||||
#endif
|
||||
members[i] = them;
|
||||
continue;
|
||||
}
|
||||
#if EQDEBUG >= 8
|
||||
LogDebug("Member of group [{}] named [{}] is valid", (unsigned long)GetID(), membername[i]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -85,6 +85,7 @@ volatile bool RunLoops = true;
|
||||
#endif
|
||||
|
||||
extern volatile bool is_zone_loaded;
|
||||
extern bool Critical = false;
|
||||
|
||||
#include "zone_event_scheduler.h"
|
||||
#include "../common/file.h"
|
||||
|
||||
@ -1833,6 +1833,8 @@ private:
|
||||
EQ::InventoryProfile m_inv;
|
||||
std::shared_ptr<HealRotation> m_target_of_heal_rotation;
|
||||
bool m_manual_follow;
|
||||
|
||||
void DoSpellInterrupt(uint16 spell_id, int32 mana_cost, int my_curmana);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -369,7 +369,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes, bool bInnates
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NPC::AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore) {
|
||||
bool NPC::AIDoSpellCast(int32 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore) {
|
||||
LogAI("spellid [{}] tar [{}] mana [{}] Name [{}]", AIspells[i].spellid, tar->GetName(), mana_cost, spells[AIspells[i].spellid].name);
|
||||
casting_spell_AIindex = i;
|
||||
|
||||
|
||||
@ -589,7 +589,7 @@ protected:
|
||||
std::vector<AISpells_Struct> AIspells;
|
||||
bool HasAISpell;
|
||||
virtual bool AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes, bool bInnates = false);
|
||||
virtual bool AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0);
|
||||
virtual bool AIDoSpellCast(int32 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0);
|
||||
AISpellsVar_Struct AISpellVar;
|
||||
int64 GetFocusEffect(focusType type, uint16 spell_id, Mob *caster = nullptr, bool from_buff_tic = false) override;
|
||||
uint16 innate_proc_spell_id;
|
||||
|
||||
482
zone/raids.cpp
482
zone/raids.cpp
@ -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;
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
auto* rga = (ServerRaidGeneralAction_Struct*) pack->pBuffer;
|
||||
strn0cpy(rga->playername, c->GetName(), sizeof(rga->playername));
|
||||
rga->rid = GetID();
|
||||
strn0cpy(rga->playername, c->GetName(), 64);
|
||||
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;
|
||||
auto* rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
|
||||
rga->rid = GetID();
|
||||
rga->instance_id = zone->GetInstanceID();
|
||||
strn0cpy(rga->playername, characterName, 64);
|
||||
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;
|
||||
auto* rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
|
||||
rga->rid = GetID();
|
||||
strn0cpy(rga->playername, " ", 64);
|
||||
rga->zoneid = zone->GetZoneID();
|
||||
rga->instance_id = zone->GetInstanceID();
|
||||
strn0cpy(rga->playername, " ", sizeof(rga->playername));
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
|
||||
@ -216,8 +294,12 @@ 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);
|
||||
|
||||
const auto query = fmt::format(
|
||||
"UPDATE raid_members SET groupid = {} WHERE name = '{}'",
|
||||
newGroup,
|
||||
name
|
||||
);
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
LearnMembers();
|
||||
@ -225,9 +307,9 @@ void Raid::MoveMember(const char *name, uint32 newGroup)
|
||||
SendRaidMoveAll(name);
|
||||
|
||||
auto pack = new ServerPacket(ServerOP_RaidChangeGroup, sizeof(ServerRaidGeneralAction_Struct));
|
||||
ServerRaidGeneralAction_Struct *rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
|
||||
auto* rga = (ServerRaidGeneralAction_Struct*) pack->pBuffer;
|
||||
strn0cpy(rga->playername, name, sizeof(rga->playername));
|
||||
rga->rid = GetID();
|
||||
strn0cpy(rga->playername, name, 64);
|
||||
rga->zoneid = zone->GetZoneID();
|
||||
rga->instance_id = zone->GetInstanceID();
|
||||
worldserver.SendPacket(pack);
|
||||
@ -236,17 +318,20 @@ 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);
|
||||
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;
|
||||
auto* rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
|
||||
strn0cpy(rga->playername, who, sizeof(rga->playername));
|
||||
rga->rid = GetID();
|
||||
strn0cpy(rga->playername, who, 64);
|
||||
rga->zoneid = zone->GetZoneID();
|
||||
rga->instance_id = zone->GetInstanceID();
|
||||
worldserver.SendPacket(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,40 +1605,48 @@ void Raid::SaveRaidMOTD()
|
||||
|
||||
bool Raid::LearnMembers()
|
||||
{
|
||||
memset(members, 0, (sizeof(RaidMember)*MAX_RAID_MEMBERS));
|
||||
memset(members, 0, (sizeof(RaidMember) * MAX_RAID_MEMBERS));
|
||||
|
||||
const auto query = fmt::format(
|
||||
"SELECT name, groupid, _class, level, "
|
||||
"isgroupleader, israidleader, islooter, bot_id "
|
||||
"FROM raid_members WHERE raidid = {} ORDER BY groupid",
|
||||
GetID()
|
||||
);
|
||||
|
||||
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())
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(results.RowCount() == 0) {
|
||||
LogError("Error getting raid members for raid [{}]: [{}]", (unsigned long)GetID(), results.ErrorMessage().c_str());
|
||||
if (!results.RowCount()) {
|
||||
LogError("Error getting raid members for raid [{}]: [{}]", GetID(), results.ErrorMessage());
|
||||
disbandCheck = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
for(auto row = results.begin(); row != results.end(); ++row) {
|
||||
if(!row[0])
|
||||
for (auto row: results) {
|
||||
if (!row[0]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
strn0cpy(members[index].membername, row[0], sizeof(members[index].membername));
|
||||
uint32 group_id = Strings::ToUnsignedInt(row[1]);
|
||||
|
||||
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]);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1528,28 +1655,34 @@ bool Raid::LearnMembers()
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
zone/raids.h
12
zone/raids.h
@ -88,6 +88,8 @@ struct RaidMember{
|
||||
bool IsGroupLeader;
|
||||
bool IsRaidLeader;
|
||||
bool IsLooter;
|
||||
bool IsBot = false;
|
||||
bool IsRaidMainAssistOne = false;
|
||||
};
|
||||
|
||||
struct GroupMentor {
|
||||
@ -113,6 +115,11 @@ public:
|
||||
bool IsRaid() { return true; }
|
||||
|
||||
void AddMember(Client *c, uint32 group = 0xFFFFFFFF, bool rleader=false, bool groupleader=false, bool looter=false);
|
||||
void AddBot(Bot* b, uint32 group = 0xFFFFFFFF, bool rleader=false, bool groupleader=false, bool looter=false);
|
||||
void RaidGroupSay(const char* msg, const char* from, uint8 language, uint8 lang_skill);
|
||||
void RaidSay(const char* msg, const char* from, uint8 language, uint8 lang_skill);
|
||||
bool IsEngaged();
|
||||
Mob* GetRaidMainAssistOneByName(const char* name);
|
||||
void RemoveMember(const char *c);
|
||||
void DisbandRaid();
|
||||
void MoveMember(const char *name, uint32 newGroup);
|
||||
@ -124,6 +131,7 @@ public:
|
||||
bool IsRaidMember(const char* name);
|
||||
bool IsRaidMember(Client *c);
|
||||
void UpdateLevel(const char *name, int newLevel);
|
||||
void SetNewRaidLeader(uint32 i);
|
||||
|
||||
uint32 GetFreeGroup();
|
||||
uint8 GroupCount(uint32 gid);
|
||||
@ -244,6 +252,10 @@ 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);
|
||||
std::vector<Bot*> GetRaidGroupBotMembers(uint32 gid);
|
||||
std::vector<Bot*> GetRaidBotMembers(uint32 owner = 0);
|
||||
void HandleBotGroupDisband(uint32 owner, uint32 gid = RAID_GROUPLESS);
|
||||
|
||||
RaidMember members[MAX_RAID_MEMBERS];
|
||||
char leadername[64];
|
||||
|
||||
@ -430,26 +430,16 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
|
||||
// If you're at full mana, let it cast even if you dont have enough mana
|
||||
|
||||
// we calculated this above, now enforce it
|
||||
if (mana_cost > 0 && slot != CastingSlot::Item) {
|
||||
if (mana_cost > 0 && slot != CastingSlot::Item || (IsBot() && !CastToBot()->IsBotNonSpellFighter())) {
|
||||
int my_curmana = GetMana();
|
||||
int my_maxmana = GetMaxMana();
|
||||
if (my_curmana < mana_cost) {// not enough mana
|
||||
//this is a special case for NPCs with no mana...
|
||||
if (IsNPC() && my_curmana == my_maxmana){
|
||||
if (IsNPC() && my_curmana == my_maxmana) {
|
||||
mana_cost = 0;
|
||||
} else {
|
||||
//The client will prevent spell casting if insufficient mana, this is only for serverside enforcement.
|
||||
LogSpells("Spell Error not enough mana spell=[{}] mymana=[{}] cost=[{}]\n", spell_id, my_curmana, mana_cost);
|
||||
if (IsClient()) {
|
||||
//clients produce messages... npcs should not for this case
|
||||
MessageString(Chat::Red, INSUFFICIENT_MANA);
|
||||
InterruptSpell();
|
||||
} else {
|
||||
InterruptSpell(0, 0, 0); //the 0 args should cause no messages
|
||||
}
|
||||
ZeroCastingVars();
|
||||
return(false);
|
||||
}
|
||||
DoSpellInterrupt(spell_id, mana_cost, my_curmana);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -475,7 +465,7 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
|
||||
// cast time is 0, just finish it right now and be done with it
|
||||
if(cast_time == 0) {
|
||||
CastedSpellFinished(spell_id, target_id, slot, mana_cost, item_slot, resist_adjust); //
|
||||
return(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ok we know it has a cast time so we can start the timer now
|
||||
@ -501,7 +491,20 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
|
||||
}
|
||||
}
|
||||
|
||||
return(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mob::DoSpellInterrupt(uint16 spell_id, int32 mana_cost, int my_curmana) {
|
||||
//The client will prevent spell casting if insufficient mana, this is only for serverside enforcement.
|
||||
LogSpells("Spell Error not enough mana spell=[{}] mymana=[{}] cost=[{}]\n", spell_id, my_curmana, mana_cost);
|
||||
if (IsClient()) {
|
||||
//clients produce messages... npcs should not for this case
|
||||
MessageString(Chat::Red, INSUFFICIENT_MANA);
|
||||
InterruptSpell();
|
||||
} else {
|
||||
InterruptSpell(0, 0, 0); //the 0 args should cause no messages
|
||||
}
|
||||
ZeroCastingVars();
|
||||
}
|
||||
|
||||
void Mob::SendBeginCast(uint16 spell_id, uint32 casttime)
|
||||
@ -4153,7 +4156,6 @@ bool Mob::SpellOnTarget(
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (spelltar->IsClient()){
|
||||
spelltar->CastToClient()->BreakSneakWhenCastOn(this, false);
|
||||
spelltar->CastToClient()->BreakFeignDeathWhenCastOn(false);
|
||||
|
||||
@ -362,6 +362,7 @@
|
||||
#define PETITION_NO_DELETE 5053 //You do not have a petition in the queue.
|
||||
#define PETITION_DELETED 5054 //Your petition was successfully deleted.
|
||||
#define ALREADY_IN_RAID 5060 //%1 is already in a raid.
|
||||
#define ALREADY_IN_YOUR_RAID 5077 //%1 is already in your raid.
|
||||
#define GAIN_RAIDEXP 5085 //You gained raid experience!
|
||||
#define DUNGEON_SEALED 5141 //The gateway to the dungeon is sealed off to you. Perhaps you would be able to enter if you needed to adventure there.
|
||||
#define ADVENTURE_COMPLETE 5147 //You received %1 points for successfully completing the adventure.
|
||||
|
||||
@ -1500,7 +1500,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
if (strcmp(rmsg->from, r->members[x].member->GetName()) != 0)
|
||||
{
|
||||
if (r->members[x].GroupNumber == rmsg->gid) {
|
||||
if (r->members[x].member->GetFilter(FilterGroupChat) != 0)
|
||||
if (!r->members[x].IsBot && r->members[x].member->GetFilter(FilterGroupChat) != 0)
|
||||
{
|
||||
r->members[x].member->ChannelMessageSend(rmsg->from, r->members[x].member->GetName(), ChatChannel_Group, rmsg->language, rmsg->lang_skill, rmsg->message);
|
||||
}
|
||||
@ -1524,7 +1524,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
if (r->members[x].member) {
|
||||
if (strcmp(rmsg->from, r->members[x].member->GetName()) != 0)
|
||||
{
|
||||
if (r->members[x].member->GetFilter(FilterGroupChat) != 0)
|
||||
if (!r->members[x].IsBot && r->members[x].member->GetFilter(FilterGroupChat) != 0)
|
||||
{
|
||||
r->members[x].member->ChannelMessageSend(rmsg->from, r->members[x].member->GetName(), ChatChannel_Raid, rmsg->language, rmsg->lang_skill, rmsg->message);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user