mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-16 18:52:22 +00:00
Merge branch 'master' of https://github.com/neckkola/Server
This commit is contained in:
+2
-2
@@ -54,5 +54,5 @@ bin/
|
||||
/Win32
|
||||
/x64
|
||||
/client_files/**/CMakeFiles/
|
||||
|
||||
.idea
|
||||
submodules/libuv
|
||||
.idea
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "x64-Debug",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Debug",
|
||||
"inheritEnvironments": [ "msvc_x64_x64" ],
|
||||
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -28,6 +28,9 @@ public:
|
||||
int isgroupleader;
|
||||
int israidleader;
|
||||
int islooter;
|
||||
#ifdef BOTS
|
||||
int isbot;
|
||||
#endif
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
@@ -47,6 +50,9 @@ public:
|
||||
"isgroupleader",
|
||||
"israidleader",
|
||||
"islooter",
|
||||
#ifdef BOTS
|
||||
"isbot",
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
@@ -111,6 +117,9 @@ public:
|
||||
entry.isgroupleader = 0;
|
||||
entry.israidleader = 0;
|
||||
entry.islooter = 0;
|
||||
#ifdef BOTS
|
||||
entry.isbot = 0;
|
||||
#endif
|
||||
|
||||
return entry;
|
||||
}
|
||||
@@ -154,7 +163,10 @@ public:
|
||||
entry.name = row[5] ? row[5] : "";
|
||||
entry.isgroupleader = atoi(row[6]);
|
||||
entry.israidleader = atoi(row[7]);
|
||||
entry.islooter = atoi(row[8]);
|
||||
entry.islooter = atoi(row[8]);
|
||||
#ifdef BOTS
|
||||
entry.isbot = atoi(row[9]);
|
||||
#endif
|
||||
|
||||
return entry;
|
||||
}
|
||||
@@ -197,6 +209,9 @@ public:
|
||||
update_values.push_back(columns[6] + " = " + std::to_string(raid_members_entry.isgroupleader));
|
||||
update_values.push_back(columns[7] + " = " + std::to_string(raid_members_entry.israidleader));
|
||||
update_values.push_back(columns[8] + " = " + std::to_string(raid_members_entry.islooter));
|
||||
#ifdef BOTS
|
||||
update_values.push_back(columns[9] + " = " + std::to_string(raid_members_entry.isbot));
|
||||
#endif
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -227,7 +242,9 @@ public:
|
||||
insert_values.push_back(std::to_string(raid_members_entry.isgroupleader));
|
||||
insert_values.push_back(std::to_string(raid_members_entry.israidleader));
|
||||
insert_values.push_back(std::to_string(raid_members_entry.islooter));
|
||||
|
||||
#ifdef BOTS
|
||||
insert_values.push_back(std::to_string(raid_members_entry.isbot));
|
||||
#endif
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES ({})",
|
||||
@@ -265,7 +282,9 @@ public:
|
||||
insert_values.push_back(std::to_string(raid_members_entry.isgroupleader));
|
||||
insert_values.push_back(std::to_string(raid_members_entry.israidleader));
|
||||
insert_values.push_back(std::to_string(raid_members_entry.islooter));
|
||||
|
||||
#ifdef BOTS
|
||||
insert_values.push_back(std::to_string(raid_members_entry.isbot));
|
||||
#endif
|
||||
insert_chunks.push_back("(" + implode(",", insert_values) + ")");
|
||||
}
|
||||
|
||||
@@ -307,7 +326,9 @@ public:
|
||||
entry.isgroupleader = atoi(row[6]);
|
||||
entry.israidleader = atoi(row[7]);
|
||||
entry.islooter = atoi(row[8]);
|
||||
|
||||
#ifdef BOTS
|
||||
entry.isbot = atoi(row[9]);
|
||||
#endif
|
||||
all_entries.push_back(entry);
|
||||
}
|
||||
|
||||
@@ -340,7 +361,9 @@ public:
|
||||
entry.isgroupleader = atoi(row[6]);
|
||||
entry.israidleader = atoi(row[7]);
|
||||
entry.islooter = atoi(row[8]);
|
||||
|
||||
#ifdef BOTS
|
||||
entry.isbot = atoi(row[9]);
|
||||
#endif
|
||||
all_entries.push_back(entry);
|
||||
}
|
||||
|
||||
|
||||
@@ -622,10 +622,13 @@ RULE_REAL(Bots, LeashDistance, 562500.0f, "Distance a bot is allowed to travel f
|
||||
RULE_BOOL(Bots, AllowApplyPoisonCommand, true, "Allows the use of the bot command 'applypoison'")
|
||||
RULE_BOOL(Bots, AllowApplyPotionCommand, true, "Allows the use of the bot command 'applypotion'")
|
||||
RULE_BOOL(Bots, RestrictApplyPotionToRogue, true, "Restricts the bot command 'applypotion' to rogue-usable potions (i.e., poisons)")
|
||||
RULE_BOOL(Bots, DisplayHealDamage, false, "Enables the display of bot heal damage to the bot owner client")
|
||||
RULE_BOOL(Bots, DisplaySpellDamage, false, "Enables the display of bot spell damage to the bot owner client")
|
||||
RULE_BOOL(Bots, OldRaceRezEffects, false, "Older clients had ID 757 for races with high starting STR, but it doesn't seem used anymore")
|
||||
RULE_BOOL(Bots, ResurrectionSickness, true, "Use Resurrection Sickness based on Resurrection spell cast, set to false to disable Resurrection Sickness.")
|
||||
RULE_INT(Bots, OldResurrectionSicknessSpell, 757, "757 is Default Old Resurrection Sickness Spell")
|
||||
RULE_INT(Bots, ResurrectionSicknessSpell, 756, "756 is Default Resurrection Sickness Spell")
|
||||
|
||||
RULE_CATEGORY_END()
|
||||
#endif
|
||||
|
||||
|
||||
@@ -57,6 +57,9 @@ typedef const char Const_char; //for perl XS
|
||||
|
||||
#define safe_delete(d) if(d) { delete d; d=nullptr; }
|
||||
#define safe_delete_array(d) if(d) { delete[] d; d=nullptr; }
|
||||
//#define safe_delete(d)(_RPTF0(_CRT_WARN,"Testing delete function\n"));
|
||||
//#define safe_delete(d) if(d) { }
|
||||
//#define safe_delete_array(d) if(d) { }
|
||||
#define L32(i) ((uint32) i)
|
||||
#define H32(i) ((uint32) (i >> 32))
|
||||
#define L16(i) ((uint16) i)
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
9026|2019_09_09_bots_owner_options_rework.sql|SHOW COLUMNS FROM `bot_owner_options` LIKE 'option_type'|empty|
|
||||
9027|2020_03_30_bots_view_update.sql|SELECT * FROM db_version WHERE bots_version >= 9027|empty|
|
||||
9028|2021_06_04_bot_create_combinations.sql|SHOW TABLES LIKE 'bot_create_combinations'|empty|
|
||||
9029|2022_02_08_bots_raid_members.sql|SELECT * FROM db_version WHERE bots_version >= 9028|empty|
|
||||
|
||||
# Upgrade conditions:
|
||||
# This won't be needed after this system is implemented, but it is used database that are not
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE `raid_members` ADD COLUMN `isbot` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '';
|
||||
@@ -11,6 +11,7 @@ SET(zone_sources
|
||||
beacon.cpp
|
||||
bonuses.cpp
|
||||
bot.cpp
|
||||
bot_raid.cpp
|
||||
bot_command.cpp
|
||||
bot_database.cpp
|
||||
botspellsai.cpp
|
||||
|
||||
+17
-2
@@ -35,6 +35,7 @@
|
||||
#include "../common/global_define.h"
|
||||
#include "guild_mgr.h"
|
||||
#include "worldserver.h"
|
||||
#include "raids.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
@@ -151,8 +152,8 @@ public:
|
||||
ExtraAttackOptions *opts = nullptr);
|
||||
virtual bool HasRaid() { return (GetRaid() ? true : false); }
|
||||
virtual bool HasGroup() { return (GetGroup() ? true : false); }
|
||||
virtual Raid* GetRaid() { return entity_list.GetRaidByMob(this); }
|
||||
virtual Group* GetGroup() { return entity_list.GetGroupByMob(this); }
|
||||
virtual Raid* GetRaid() { return entity_list.GetRaidByMob(this); } // GetRaidByMob(this);
|
||||
virtual Group* GetGroup() { return entity_list.GetGroupByMob(this); } // GetGroupByMob;
|
||||
|
||||
// Common, but informal "interfaces" with Client object
|
||||
uint32 CharacterID() { return GetBotID(); } // Just returns the Bot Id
|
||||
@@ -375,6 +376,15 @@ public:
|
||||
static bool CheckDisciplineRecastTimers(Bot *caster, int timer_index);
|
||||
static uint32 GetDisciplineRemainingTime(Bot *caster, int timer_index);
|
||||
|
||||
//Raid methods
|
||||
void PetAIProcess_Raid();
|
||||
void AI_Process_Raid();
|
||||
bool AICastSpell_Raid(Mob* tar, uint8 iChance, uint32 iSpellTypes);
|
||||
static void ProcessRaidInvite(Bot* invitee, Client* invitor);
|
||||
static void ProcessRaidInvite(Client* invitee, Client* invitor);
|
||||
uint8 GetNumberNeedingHealedInRaidGroup(uint8 hpr, bool includePets);
|
||||
inline void SetDirtyAutoHaters() { m_dirtyautohaters = true; }
|
||||
|
||||
static std::list<BotSpell> GetBotSpellsForSpellEffect(Bot* botCaster, int spellEffect);
|
||||
static std::list<BotSpell> GetBotSpellsForSpellEffectAndTargetType(Bot* botCaster, int spellEffect, SpellTargetType targetType);
|
||||
static std::list<BotSpell> GetBotSpellsBySpellType(Bot* botCaster, uint32 spellType);
|
||||
@@ -610,6 +620,9 @@ public:
|
||||
int32 GetBaseDR() { return _baseDR; }
|
||||
int32 GetBaseCorrup() { return _baseCorrup; }
|
||||
|
||||
//Raid additions
|
||||
Raid* p_raid_instance;
|
||||
|
||||
protected:
|
||||
virtual void PetAIProcess();
|
||||
virtual void BotMeditate(bool isSitting);
|
||||
@@ -674,6 +687,7 @@ private:
|
||||
Timer m_auto_defend_timer;
|
||||
//Timer m_combat_jitter_timer;
|
||||
//bool m_combat_jitter_flag;
|
||||
bool m_dirtyautohaters;
|
||||
bool m_guard_flag;
|
||||
bool m_hold_flag;
|
||||
bool m_attack_flag;
|
||||
@@ -740,6 +754,7 @@ private:
|
||||
|
||||
public:
|
||||
static uint8 spell_casting_chances[SPELL_TYPE_COUNT][PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND];
|
||||
|
||||
};
|
||||
|
||||
#endif // BOTS
|
||||
|
||||
+2630
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,47 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef BOT_RAID_H
|
||||
#define BOT_RAID_H
|
||||
|
||||
#ifdef BOTS
|
||||
|
||||
#include "bot_structs.h"
|
||||
#include "mob.h"
|
||||
#include "client.h"
|
||||
#include "pets.h"
|
||||
#include "heal_rotation.h"
|
||||
#include "groups.h"
|
||||
#include "corpse.h"
|
||||
#include "zonedb.h"
|
||||
#include "zone_store.h"
|
||||
#include "string_ids.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/global_define.h"
|
||||
#include "guild_mgr.h"
|
||||
#include "worldserver.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
extern WorldServer worldserver;
|
||||
|
||||
//void Bot::PetAIProcess_Raid();
|
||||
|
||||
#endif // BOTS
|
||||
|
||||
#endif // BOT_RAID_H
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
the Free Software Foundation; version 2 ogroupf the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
@@ -31,6 +31,13 @@
|
||||
|
||||
bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) {
|
||||
|
||||
// Bot AI
|
||||
Raid* raid = entity_list.GetRaidByBotName(this->GetName());
|
||||
if (raid) {
|
||||
return AICastSpell_Raid(tar, iChance, iSpellTypes);
|
||||
//return true;
|
||||
}
|
||||
|
||||
if (!tar) {
|
||||
return false;
|
||||
}
|
||||
|
||||
+5
-4
@@ -807,9 +807,10 @@ void Client::QueuePacket(const EQApplicationPacket* app, bool ack_req, CLIENT_CO
|
||||
// todo: save packets for later use
|
||||
AddPacket(app, ack_req);
|
||||
}
|
||||
else
|
||||
if(eqs)
|
||||
eqs->QueuePacket(app, ack_req);
|
||||
else if (eqs)
|
||||
{
|
||||
eqs->QueuePacket(app, ack_req);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::FastQueuePacket(EQApplicationPacket** app, bool ack_req, CLIENT_CONN_STATUS required_state) {
|
||||
@@ -820,7 +821,7 @@ void Client::FastQueuePacket(EQApplicationPacket** app, bool ack_req, CLIENT_CON
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if(eqs)
|
||||
if(eqs)
|
||||
eqs->FastQueuePacket((EQApplicationPacket **)app, ack_req);
|
||||
else if (app && (*app))
|
||||
delete *app;
|
||||
|
||||
+695
-485
File diff suppressed because it is too large
Load Diff
+47
-3
@@ -2137,17 +2137,17 @@ Raid *EntityList::GetRaidByID(uint32 id)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Raid *EntityList::GetRaidByClient(Client* client)
|
||||
Raid* EntityList::GetRaidByClient(Client* client)
|
||||
{
|
||||
if (client->p_raid_instance) {
|
||||
return client->p_raid_instance;
|
||||
}
|
||||
|
||||
std::list<Raid *>::iterator iterator;
|
||||
std::list<Raid*>::iterator iterator;
|
||||
iterator = raid_list.begin();
|
||||
|
||||
while (iterator != raid_list.end()) {
|
||||
for (auto &member : (*iterator)->members) {
|
||||
for (auto& member : (*iterator)->members) {
|
||||
if (member.member) {
|
||||
if (member.member == client) {
|
||||
client->p_raid_instance = *iterator;
|
||||
@@ -2161,6 +2161,50 @@ Raid *EntityList::GetRaidByClient(Client* client)
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
#ifdef BOTS
|
||||
Raid* EntityList::GetRaidByBotName(const char* name)
|
||||
{
|
||||
|
||||
std::list<Raid*>::iterator iterator;
|
||||
iterator = raid_list.begin();
|
||||
|
||||
while (iterator != raid_list.end()) {
|
||||
for (auto& member : (*iterator)->members) {
|
||||
if (member.membername) {
|
||||
if (strcmp(member.membername, name) == 0) {
|
||||
//client->p_raid_instance = *iterator;
|
||||
return *iterator;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++iterator;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BOTS
|
||||
Raid* EntityList::GetRaidByBot(Bot* bot)
|
||||
{
|
||||
|
||||
std::list<Raid*>::iterator iterator;
|
||||
iterator = raid_list.begin();
|
||||
|
||||
while (iterator != raid_list.end()) {
|
||||
for (auto& member : (*iterator)->members) {
|
||||
if (member.member && member.member->CastToBot() == bot) {
|
||||
bot->p_raid_instance = *iterator;
|
||||
return *iterator;
|
||||
}
|
||||
}
|
||||
++iterator;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
Raid *EntityList::GetRaidByMob(Mob *mob)
|
||||
{
|
||||
|
||||
@@ -200,6 +200,10 @@ public:
|
||||
Raid *GetRaidByClient(Client* client);
|
||||
Raid *GetRaidByID(uint32 id);
|
||||
Raid *GetRaidByLeaderName(const char *leader);
|
||||
#ifdef BOTS
|
||||
Raid* GetRaidByBotName(const char* name);
|
||||
Raid* GetRaidByBot(Bot* bot);
|
||||
#endif
|
||||
|
||||
Corpse *GetCorpseByOwner(Client* client);
|
||||
Corpse *GetCorpseByOwnerWithinRange(Client* client, Mob* center, int range);
|
||||
|
||||
@@ -1097,7 +1097,11 @@ void Raid::SplitExp(uint32 exp, Mob* other) {
|
||||
return;
|
||||
|
||||
for (unsigned int x = 0; x < MAX_RAID_MEMBERS; x++) {
|
||||
#ifdef BOTS
|
||||
if (members[x].member != nullptr && !members[x].IsBot) // If Group Member is Client
|
||||
#else
|
||||
if (members[x].member != nullptr) // If Group Member is Client
|
||||
#endif
|
||||
{
|
||||
Client *cmember = members[x].member;
|
||||
// add exp + exp cap
|
||||
|
||||
+57
-3
@@ -248,10 +248,24 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte
|
||||
uint32 i = 0;
|
||||
for (i = 0; i < MAX_GROUP_MEMBERS; ++i)
|
||||
{
|
||||
if(!strcasecmp(membername[i], NewMemberName))
|
||||
#ifdef BOTSS
|
||||
if (newmember->IsBot() && !newmember->HasGroup() && !strcasecmp(membername[i], NewMemberName)) // Mitch
|
||||
{
|
||||
//Bot::RemoveBotFromGroup(newmember->CastToBot(), members[0]->GetGroup());
|
||||
//Group::DelMember(newmember);
|
||||
memset(membername[i], 0, 64);
|
||||
members[i] = nullptr;
|
||||
}
|
||||
else if (!strcasecmp(membername[i], NewMemberName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (!strcasecmp(membername[i], NewMemberName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Put them in the group
|
||||
@@ -1140,7 +1154,13 @@ void Group::TeleportGroup(Mob* sender, uint32 zoneID, uint16 instance_id, float
|
||||
}
|
||||
|
||||
bool Group::LearnMembers() {
|
||||
std::string query = StringFormat("SELECT name FROM group_id WHERE groupid = %lu", (unsigned long)GetID());
|
||||
//std::string query = StringFormat("SELECT name FROM group_id WHERE groupid = %lu", (unsigned long)GetID());
|
||||
std::string query = StringFormat("SELECT name FROM group_id "
|
||||
"WHERE group_id.groupid = %lu AND group_id.name NOT "
|
||||
"IN(SELECT group_leaders.leadername FROM group_leaders WHERE gid = %lu)"
|
||||
, (unsigned long)GetID()
|
||||
, (unsigned long)GetID());
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
@@ -1155,7 +1175,7 @@ bool Group::LearnMembers() {
|
||||
return false;
|
||||
}
|
||||
|
||||
int memberIndex = 0;
|
||||
int memberIndex = 1; //starts at 1 becasuse leader [0] is done specifically
|
||||
for(auto row = results.begin(); row != results.end(); ++row) {
|
||||
if(!row[0])
|
||||
continue;
|
||||
@@ -1165,7 +1185,24 @@ bool Group::LearnMembers() {
|
||||
|
||||
memberIndex++;
|
||||
}
|
||||
// for leader only [0] /Mitch
|
||||
query = StringFormat("SELECT leadername FROM group_leaders WHERE group_leaders.gid = %lu", (unsigned long)GetID());
|
||||
auto results2 = database.QueryDatabase(query);
|
||||
if (!results2.Success())
|
||||
return false;
|
||||
|
||||
if (results2.RowCount() == 0) {
|
||||
LogError(
|
||||
"Error getting group leader for group [{}]: [{}]",
|
||||
(unsigned long)GetID(),
|
||||
results2.ErrorMessage().c_str()
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
auto row2 = results2.begin();
|
||||
members[0] = nullptr;
|
||||
strn0cpy(membername[0], row2[0], 64);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1176,6 +1213,22 @@ void Group::VerifyGroup() {
|
||||
Only called every once in a while (on member re-join for now).
|
||||
*/
|
||||
|
||||
// To do
|
||||
// Reset the membername array to match the group_id database records?
|
||||
// When doing this manually, it seem to have resolved the issue.
|
||||
// Only want to do this when the database Name does not match the array
|
||||
// Could this be done from the LearnGroup method?
|
||||
// reset the members and membername array for this group
|
||||
// Mitch
|
||||
for (int i = 0; i < MAX_GROUP_MEMBERS; i++) {
|
||||
members[i] = nullptr;
|
||||
memset(membername[i],'\0',64);
|
||||
//membername[i][0] == '\0');
|
||||
}
|
||||
// repopulate the membername array from the database to ensure the local zone instance has accurate information
|
||||
|
||||
Group::LearnMembers();
|
||||
|
||||
uint32 i;
|
||||
for (i = 0; i < MAX_GROUP_MEMBERS; i++) {
|
||||
if (membername[i][0] == '\0') {
|
||||
@@ -1196,6 +1249,7 @@ void Group::VerifyGroup() {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if(them != nullptr && members[i] != them) { //our pointer is out of date... not so good.
|
||||
#if EQDEBUG >= 5
|
||||
LogDebug("Member of group [{}] named [{}] had an out of date pointer!!", (unsigned long)GetID(), membername[i]);
|
||||
|
||||
+2
-1
@@ -88,6 +88,7 @@ volatile bool RunLoops = true;
|
||||
#endif
|
||||
|
||||
extern volatile bool is_zone_loaded;
|
||||
extern bool Critical = false;
|
||||
|
||||
EntityList entity_list;
|
||||
WorldServer worldserver;
|
||||
@@ -578,7 +579,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
EQ::Timer process_timer(loop_fn);
|
||||
process_timer.Start(32, true);
|
||||
|
||||
|
||||
EQ::EventLoop::Get().Run();
|
||||
|
||||
entity_list.Clear();
|
||||
|
||||
+1
-1
@@ -3987,7 +3987,7 @@ void Mob::QuestJournalledSay(Client *QuestInitiator, const char *str, Journal::O
|
||||
|
||||
const char *Mob::GetCleanName()
|
||||
{
|
||||
if (!strlen(clean_name)) {
|
||||
if (!strlen(clean_name)) {
|
||||
CleanMobName(GetName(), clean_name);
|
||||
}
|
||||
|
||||
|
||||
+199
-17
@@ -24,6 +24,7 @@
|
||||
#include "groups.h"
|
||||
#include "mob.h"
|
||||
#include "raids.h"
|
||||
#include "bot.h"
|
||||
|
||||
#include "worldserver.h"
|
||||
|
||||
@@ -95,13 +96,22 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo
|
||||
if(!c)
|
||||
return;
|
||||
|
||||
#ifdef BOTS
|
||||
std::string query = StringFormat("INSERT INTO raid_members SET raidid = %lu, charid = %lu, "
|
||||
"groupid = %lu, _class = %d, level = %d, name = '%s', "
|
||||
"isgroupleader = %d, israidleader = %d, islooter = %d",
|
||||
"isgroupleader = %d, israidleader = %d, islooter = %d, isbot = 0",
|
||||
(unsigned long)GetID(), (unsigned long)c->CharacterID(),
|
||||
(unsigned long)group, c->GetClass(), c->GetLevel(),
|
||||
c->GetName(), groupleader, rleader, looter);
|
||||
auto results = database.QueryDatabase(query);
|
||||
#else
|
||||
std::string query = StringFormat("INSERT INTO raid_members SET raidid = %lu, charid = %lu, "
|
||||
"groupid = %lu, _class = %d, level = %d, name = '%s', "
|
||||
"isgroupleader = %d, israidleader = %d, islooter = %d",
|
||||
(unsigned long)GetID(), (unsigned long)c->CharacterID(),
|
||||
(unsigned long)group, c->GetClass(), c->GetLevel(),
|
||||
c->GetName(), groupleader, rleader, looter);
|
||||
#endif
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
if(!results.Success()) {
|
||||
LogError("Error inserting into raid members: [{}]", results.ErrorMessage().c_str());
|
||||
@@ -109,6 +119,14 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo
|
||||
|
||||
LearnMembers();
|
||||
VerifyRaid();
|
||||
|
||||
#ifdef BOTS
|
||||
if (rleader) {
|
||||
database.SetRaidGroupLeaderInfo(group, GetID());
|
||||
UpdateRaidAAs();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (rleader) {
|
||||
database.SetRaidGroupLeaderInfo(RAID_GROUPLESS, GetID());
|
||||
UpdateRaidAAs();
|
||||
@@ -163,12 +181,65 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
#ifdef BOTS
|
||||
void Raid::AddBot(Bot* b, uint32 group, bool rleader, bool groupleader, bool looter) {
|
||||
if (!b)
|
||||
return;
|
||||
|
||||
std::string query = StringFormat("INSERT INTO raid_members SET raidid = %lu, charid = %lu, "
|
||||
"groupid = %lu, _class = %d, level = %d, name = '%s', "
|
||||
"isgroupleader = %d, israidleader = %d, islooter = %d, isbot = 1",
|
||||
(unsigned long)GetID(), (unsigned long)b->GetBotID(),
|
||||
(unsigned long)group, b->GetClass(), b->GetLevel(),
|
||||
b->GetName(), groupleader, rleader, looter);
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
LogError("Error inserting into raid members: [{}]", results.ErrorMessage().c_str());
|
||||
}
|
||||
|
||||
LearnMembers();
|
||||
VerifyRaid();
|
||||
|
||||
if (group < 12) //Jan22
|
||||
GroupUpdate(group); //Jan22
|
||||
else // get raid AAs, GroupUpdate will handles it otherwise Jan 22
|
||||
SendGroupLeadershipAA(b->GetOwner()->CastToClient(), RAID_GROUPLESS); //Is this needed for bots? Jan 22
|
||||
SendRaidAddAll(b->GetName());
|
||||
|
||||
b->SetRaidGrouped(true);
|
||||
b->p_raid_instance = this;
|
||||
|
||||
|
||||
auto pack = new ServerPacket(ServerOP_RaidAdd, sizeof(ServerRaidGeneralAction_Struct));
|
||||
ServerRaidGeneralAction_Struct* rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
|
||||
rga->rid = GetID();
|
||||
strn0cpy(rga->playername, b->GetName(), 64);
|
||||
rga->zoneid = zone->GetZoneID();
|
||||
rga->instance_id = zone->GetInstanceID();
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void Raid::RemoveMember(const char *characterName)
|
||||
{
|
||||
std::string query = StringFormat("DELETE FROM raid_members where name='%s'", characterName);
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
Client *client = entity_list.GetClientByName(characterName);
|
||||
#ifdef BOTS
|
||||
Bot* bot = entity_list.GetBotByBotName(characterName);
|
||||
|
||||
if (bot) {
|
||||
bot->SetFollowID(bot->GetOwner()->CastToClient()->GetID());
|
||||
bot->SetGrouped(false);
|
||||
bot->SetTarget(nullptr);
|
||||
bot->SetRaidGrouped(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
disbandCheck = true;
|
||||
SendRaidRemoveAll(characterName);
|
||||
SendRaidDisband(client);
|
||||
@@ -983,12 +1054,12 @@ void Raid::SendRaidAdd(const char *who, Client *to)
|
||||
|
||||
void Raid::SendRaidAddAll(const char *who)
|
||||
{
|
||||
for(int x = 0; x < MAX_RAID_MEMBERS; x++)
|
||||
for (int x = 0; x < MAX_RAID_MEMBERS; x++)
|
||||
{
|
||||
if(strcmp(members[x].membername, who) == 0)
|
||||
if (strcmp(members[x].membername, who) == 0 )
|
||||
{
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidAddMember_Struct));
|
||||
RaidAddMember_Struct *ram = (RaidAddMember_Struct*)outapp->pBuffer;
|
||||
RaidAddMember_Struct* ram = (RaidAddMember_Struct*)outapp->pBuffer;
|
||||
ram->raidGen.action = raidAdd;
|
||||
ram->raidGen.parameter = members[x].GroupNumber;
|
||||
strcpy(ram->raidGen.leader_name, members[x].membername);
|
||||
@@ -999,6 +1070,7 @@ void Raid::SendRaidAddAll(const char *who)
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1111,11 +1183,16 @@ void Raid::SendBulkRaid(Client *to)
|
||||
if(!to)
|
||||
return;
|
||||
|
||||
#ifdef BOTS
|
||||
if (members[GetPlayerIndex(to)].IsBot)
|
||||
return;
|
||||
#endif
|
||||
|
||||
for(int x = 0; x < MAX_RAID_MEMBERS; x++)
|
||||
{
|
||||
if(strlen(members[x].membername) > 0 && (strcmp(members[x].membername, to->GetName()) != 0)) //don't send ourself
|
||||
if(members[x].member && strlen(members[x].membername) > 0 && (strcmp(members[x].membername, to->GetName()) != 0)) //don't send ourself
|
||||
{
|
||||
SendRaidAdd(members[x].membername, to);
|
||||
SendRaidAdd(members[x].membername, to);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1124,7 +1201,11 @@ void Raid::QueuePacket(const EQApplicationPacket *app, bool ack_req)
|
||||
{
|
||||
for(int x = 0; x < MAX_RAID_MEMBERS; x++)
|
||||
{
|
||||
#ifdef BOTS
|
||||
if(members[x].member && !members[x].IsBot)
|
||||
#else
|
||||
if(members[x].member)
|
||||
#endif
|
||||
{
|
||||
members[x].member->QueuePacket(app, ack_req);
|
||||
}
|
||||
@@ -1133,6 +1214,12 @@ void Raid::QueuePacket(const EQApplicationPacket *app, bool ack_req)
|
||||
|
||||
void Raid::SendMakeLeaderPacket(const char *who) //30
|
||||
{
|
||||
|
||||
#ifdef BOTS
|
||||
if (entity_list.GetBotByBotName(who) && members[GetPlayerIndex(who)].IsBot)
|
||||
return;
|
||||
#endif
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct));
|
||||
RaidLeadershipUpdate_Struct *rg = (RaidLeadershipUpdate_Struct*)outapp->pBuffer;
|
||||
rg->action = raidMakeLeader;
|
||||
@@ -1148,6 +1235,11 @@ void Raid::SendMakeLeaderPacketTo(const char *who, Client *to)
|
||||
if(!to)
|
||||
return;
|
||||
|
||||
#ifdef BOTS
|
||||
if (members[GetPlayerIndex(who)].IsBot)
|
||||
return;
|
||||
#endif
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct));
|
||||
RaidLeadershipUpdate_Struct *rg = (RaidLeadershipUpdate_Struct*)outapp->pBuffer;
|
||||
rg->action = raidMakeLeader;
|
||||
@@ -1178,6 +1270,11 @@ void Raid::SendGroupUpdate(Client *to)
|
||||
if(!to)
|
||||
return;
|
||||
|
||||
#ifdef BOTS
|
||||
if (members[GetPlayerIndex(to)].IsBot)
|
||||
return;
|
||||
#endif
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupUpdate2_Struct));
|
||||
GroupUpdate2_Struct* gu = (GroupUpdate2_Struct*)outapp->pBuffer;
|
||||
gu->action = groupActUpdate;
|
||||
@@ -1224,7 +1321,7 @@ void Raid::GroupUpdate(uint32 gid, bool initial)
|
||||
{
|
||||
if(strlen(members[x].membername) > 0){
|
||||
if(members[x].GroupNumber == gid){
|
||||
if(members[x].member) {
|
||||
if (members[x].member) {
|
||||
SendGroupUpdate(members[x].member);
|
||||
SendGroupLeadershipAA(members[x].member, gid);
|
||||
}
|
||||
@@ -1366,6 +1463,11 @@ void Raid::SendRaidMOTDToWorld()
|
||||
|
||||
void Raid::SendGroupLeadershipAA(Client *c, uint32 gid)
|
||||
{
|
||||
#ifdef BOTS
|
||||
if (members[GetPlayerIndex(c)].IsBot)
|
||||
return;
|
||||
#endif
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct));
|
||||
RaidLeadershipUpdate_Struct *rlaa = (RaidLeadershipUpdate_Struct *)outapp->pBuffer;
|
||||
rlaa->action = raidSetLeaderAbilities;
|
||||
@@ -1381,17 +1483,26 @@ void Raid::SendGroupLeadershipAA(Client *c, uint32 gid)
|
||||
void Raid::SendGroupLeadershipAA(uint32 gid)
|
||||
{
|
||||
for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++)
|
||||
#ifdef BOTS
|
||||
if (members[i].member && members[i].GroupNumber == gid && !members[i].IsBot)
|
||||
#else
|
||||
if (members[i].member && members[i].GroupNumber == gid)
|
||||
#endif
|
||||
SendGroupLeadershipAA(members[i].member, gid);
|
||||
}
|
||||
|
||||
void Raid::SendAllRaidLeadershipAA()
|
||||
{
|
||||
for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++)
|
||||
#ifdef BOTS
|
||||
if (members[i].member && !members[i].IsBot)
|
||||
#else
|
||||
if (members[i].member)
|
||||
SendGroupLeadershipAA(members[i].member, members[i].GroupNumber);
|
||||
#endif
|
||||
SendGroupLeadershipAA(members[i].member, members[i].GroupNumber);
|
||||
}
|
||||
|
||||
|
||||
void Raid::LockRaid(bool lockFlag)
|
||||
{
|
||||
std::string query = StringFormat("UPDATE raid_details SET locked = %d WHERE raidid = %lu",
|
||||
@@ -1457,11 +1568,18 @@ bool Raid::LearnMembers()
|
||||
{
|
||||
memset(members, 0, (sizeof(RaidMember)*MAX_RAID_MEMBERS));
|
||||
|
||||
#ifdef BOTS
|
||||
std::string query = StringFormat("SELECT name, groupid, _class, level, "
|
||||
"isgroupleader, israidleader, islooter "
|
||||
"isgroupleader, israidleader, islooter, isbot "
|
||||
"FROM raid_members WHERE raidid = %lu",
|
||||
(unsigned long)GetID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
#else
|
||||
std::string query = StringFormat("SELECT name, groupid, _class, level, "
|
||||
"isgroupleader, israidleader, islooter "
|
||||
"FROM raid_members WHERE raidid = %lu",
|
||||
(unsigned long)GetID());
|
||||
#endif
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
|
||||
@@ -1489,7 +1607,10 @@ bool Raid::LearnMembers()
|
||||
members[index].IsGroupLeader = atoi(row[4]);
|
||||
members[index].IsRaidLeader = atoi(row[5]);
|
||||
members[index].IsLooter = atoi(row[6]);
|
||||
++index;
|
||||
#ifdef BOTS
|
||||
members[index].IsBot = atoi(row[7]);
|
||||
#endif
|
||||
++index;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1504,14 +1625,32 @@ void Raid::VerifyRaid()
|
||||
}
|
||||
else{
|
||||
Client *c = entity_list.GetClientByName(members[x].membername);
|
||||
#ifdef BOTS
|
||||
Bot* b = entity_list.GetBotByBotName(members[x].membername);
|
||||
#endif
|
||||
if(c){
|
||||
members[x].member = c;
|
||||
#ifdef BOTS
|
||||
members[x].IsBot = false;
|
||||
#endif
|
||||
}
|
||||
else{
|
||||
#ifdef BOTS
|
||||
else if(b){
|
||||
//Raid requires client* we are forcing it here to be a BOT. Care is needed here as any client function that
|
||||
//does not exist within the Bot Class will likely corrupt memory for the member object. Good practice to test the IsBot
|
||||
//attribute before calling a client function or casting to client.
|
||||
members[x].member = b->CastToClient();
|
||||
members[x].IsBot = true; //Used to identify those members who are Bots
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
members[x].member = nullptr;
|
||||
#ifdef BOTS
|
||||
members[x].IsBot = false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if(members[x].IsRaidLeader){
|
||||
if(members[x].IsRaidLeader){
|
||||
if(strlen(members[x].membername) > 0){
|
||||
SetLeader(members[x].member);
|
||||
strn0cpy(leadername, members[x].membername, 64);
|
||||
@@ -1561,7 +1700,11 @@ void Raid::SendHPManaEndPacketsTo(Client *client)
|
||||
EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct));
|
||||
|
||||
for(int x = 0; x < MAX_RAID_MEMBERS; x++) {
|
||||
if(members[x].member) {
|
||||
#ifdef BOTS
|
||||
if(members[x].member && !members[x].IsBot) {
|
||||
#else
|
||||
if (members[x].member) {
|
||||
#endif
|
||||
if((members[x].member != client) && (members[x].GroupNumber == group_id)) {
|
||||
|
||||
members[x].member->CreateHPPacket(&hp_packet);
|
||||
@@ -1603,7 +1746,11 @@ void Raid::SendHPManaEndPacketsFrom(Mob *mob)
|
||||
mob->CreateHPPacket(&hpapp);
|
||||
|
||||
for(int x = 0; x < MAX_RAID_MEMBERS; x++) {
|
||||
if(members[x].member) {
|
||||
#ifdef BOTS
|
||||
if(members[x].member && !members[x].IsBot) {
|
||||
#else
|
||||
if (members[x].member) {
|
||||
#endif
|
||||
if(!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) {
|
||||
members[x].member->QueuePacket(&hpapp, false);
|
||||
if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) {
|
||||
@@ -1636,7 +1783,11 @@ void Raid::SendManaPacketFrom(Mob *mob)
|
||||
EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct));
|
||||
|
||||
for (int x = 0; x < MAX_RAID_MEMBERS; x++) {
|
||||
#ifdef BOTS
|
||||
if (members[x].member && !members[x].IsBot) {
|
||||
#else
|
||||
if (members[x].member) {
|
||||
#endif
|
||||
if (!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) {
|
||||
if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) {
|
||||
outapp.SetOpcode(OP_MobManaUpdate);
|
||||
@@ -1663,7 +1814,11 @@ void Raid::SendEndurancePacketFrom(Mob *mob)
|
||||
EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct));
|
||||
|
||||
for (int x = 0; x < MAX_RAID_MEMBERS; x++) {
|
||||
#ifdef BTOS
|
||||
if (members[x].member && !members[x].IsBot) {
|
||||
#else
|
||||
if (members[x].member) {
|
||||
#endif
|
||||
if (!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) {
|
||||
if (members[x].member->ClientVersion() >= EQ::versions::ClientVersion::SoD) {
|
||||
outapp.SetOpcode(OP_MobEnduranceUpdate);
|
||||
@@ -1770,9 +1925,18 @@ void Raid::CheckGroupMentor(uint32 group_id, Client *c)
|
||||
void Raid::SetDirtyAutoHaters()
|
||||
{
|
||||
for (int i = 0; i < MAX_RAID_MEMBERS; ++i)
|
||||
#ifdef BOTS
|
||||
if (members[i].member && members[i].IsBot)
|
||||
{
|
||||
members[i].member->CastToBot()->SetDirtyAutoHaters();
|
||||
}
|
||||
else if (members[i].member && !members[i].IsBot)
|
||||
#else
|
||||
if (members[i].member)
|
||||
#endif
|
||||
{
|
||||
members[i].member->SetDirtyAutoHaters();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void Raid::QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_required /*= true*/, bool ignore_sender /*= true*/, float distance /*= 0*/, bool group_only /*= true*/) {
|
||||
@@ -1791,6 +1955,10 @@ void Raid::QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_re
|
||||
if (!members[i].member->IsClient())
|
||||
continue;
|
||||
|
||||
#ifdef BOTS
|
||||
if (members[i].IsBot)
|
||||
continue;
|
||||
#endif
|
||||
if (ignore_sender && members[i].member == sender)
|
||||
continue;
|
||||
|
||||
@@ -1853,3 +2021,17 @@ bool Raid::DoesAnyMemberHaveExpeditionLockout(
|
||||
return Expedition::HasLockoutByCharacterName(raid_member.membername, expedition_name, event_name);
|
||||
});
|
||||
}
|
||||
#ifdef BOTS
|
||||
Mob* Raid::GetRaidMainAssistOneByName(const char* name)
|
||||
{
|
||||
Raid* raid = entity_list.GetRaidByBotName(name);
|
||||
std::vector<RaidMember> raid_members = raid->GetMembers();
|
||||
|
||||
for (RaidMember iter : raid_members)
|
||||
{
|
||||
if (iter.IsRaidMainAssistOne)
|
||||
return iter.member->CastToMob();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -88,6 +88,10 @@ struct RaidMember{
|
||||
bool IsGroupLeader;
|
||||
bool IsRaidLeader;
|
||||
bool IsLooter;
|
||||
#ifdef BOTS
|
||||
bool IsBot = false;
|
||||
bool IsRaidMainAssistOne = false;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct GroupMentor {
|
||||
@@ -112,6 +116,11 @@ public:
|
||||
bool IsRaid() { return true; }
|
||||
|
||||
void AddMember(Client *c, uint32 group = 0xFFFFFFFF, bool rleader=false, bool groupleader=false, bool looter=false);
|
||||
#ifdef BOTS
|
||||
void AddBot(Bot* b, uint32 group = 0xFFFFFFFF, bool rleader=false, bool groupleader=false, bool looter=false);
|
||||
void RaidBotGroupSay(Bot* b, uint8 language, uint8 lang_skill, const char* msg, ...); //Not yet implemented
|
||||
Mob* GetRaidMainAssistOneByName(const char* name);
|
||||
#endif
|
||||
void RemoveMember(const char *c);
|
||||
void DisbandRaid();
|
||||
void MoveMember(const char *name, uint32 newGroup);
|
||||
@@ -121,6 +130,7 @@ public:
|
||||
bool IsGroupLeader(const char *who);
|
||||
bool IsRaidMember(const char *name);
|
||||
void UpdateLevel(const char *name, int newLevel);
|
||||
|
||||
|
||||
uint32 GetFreeGroup();
|
||||
uint8 GroupCount(uint32 gid);
|
||||
@@ -241,6 +251,7 @@ public:
|
||||
bool DoesAnyMemberHaveExpeditionLockout(const std::string& expedition_name, const std::string& event_name, int max_check_count = 0);
|
||||
|
||||
std::vector<RaidMember> GetMembers() const;
|
||||
std::vector<RaidMember> GetRaidGroupMembers(uint32 gid);
|
||||
|
||||
RaidMember members[MAX_RAID_MEMBERS];
|
||||
char leadername[64];
|
||||
|
||||
+1
-1
@@ -154,7 +154,7 @@ bool Spawn2::Process() {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (timer.Check()) {
|
||||
if (timer.Check() && zone->spawn2_timer.Enabled()) {
|
||||
timer.Disable();
|
||||
|
||||
LogSpawns("Spawn2 [{}]: Timer has triggered", spawn2_id);
|
||||
|
||||
@@ -1742,6 +1742,7 @@ bool Zone::Depop(bool StartSpawnTimer) {
|
||||
itr = npctable.begin();
|
||||
delete itr->second;
|
||||
itr->second = nullptr;
|
||||
|
||||
npctable.erase(itr);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user