Merge pull request #5 from EQEmu/master

eqemu merge update
This commit is contained in:
regneq 2020-05-04 08:30:48 -07:00 committed by GitHub
commit 7bea9a7273
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
73 changed files with 2671 additions and 709 deletions

18
.gitignore vendored
View File

@ -37,4 +37,20 @@ perl/
submodules/* submodules/*
cmake-build-debug/ cmake-build-debug/
.nfs.* .nfs.*
# Visual Studio and CMAKE Generated Files
/.vs/
*.vcxproj
*.vcxproj.filters
*.vcxproj.user
*.cmake
*.ilk
*.pdb
*.sln
*.dir/
libs/
bin/
/Win32
/x64
/client_files/**/CMakeFiles/

View File

@ -1,7 +1,7 @@
# EQEmulator Core Server # EQEmulator Core Server
|Travis CI (Linux)|Appveyor w/ Bots (Windows) |Appveyor w/o Bots (Windows) | |Travis CI (Linux)|Appveyor (Windows x86) |Appveyor (Windows x64) |
|:---:|:---:|:---:| |:---:|:---:|:---:|
|[![Linux CI](https://travis-ci.org/EQEmu/Server.svg?branch=master)](https://travis-ci.org/EQEmu/Server) |[![Build status](https://ci.appveyor.com/api/projects/status/scr25kmntx36c1ub/branch/master?svg=true)](https://ci.appveyor.com/project/KimLS/server-87crp/branch/master) |[![Build status](https://ci.appveyor.com/api/projects/status/mdwbr4o9l6mxqofj/branch/master?svg=true)](https://ci.appveyor.com/project/KimLS/server-w0pq2/branch/master) | |[![Linux CI](https://travis-ci.org/EQEmu/Server.svg?branch=master)](https://travis-ci.org/EQEmu/Server) |[![Build status](https://ci.appveyor.com/api/projects/status/v3utuu0dttm2cqd0?svg=true)](https://ci.appveyor.com/project/KimLS/server) |[![Build status](https://ci.appveyor.com/api/projects/status/scr25kmntx36c1ub?svg=true)](https://ci.appveyor.com/project/KimLS/server-87crp) |
*** ***
@ -52,7 +52,7 @@ forum, although pull requests will be much quicker and easier on all parties.
## Resources ## Resources
- [EQEmulator Forums](http://www.eqemulator.org/forums) - [EQEmulator Forums](http://www.eqemulator.org/forums)
- [EQEmulator Wiki](https://github.com/EQEmu/Server/wiki) - [EQEmulator Wiki](https://eqemu.gitbook.io/)
## Related Repositories ## Related Repositories
* [ProjectEQ Quests](https://github.com/ProjectEQ/projecteqquests) * [ProjectEQ Quests](https://github.com/ProjectEQ/projecteqquests)

View File

@ -9,6 +9,7 @@ SET(common_sources
crash.cpp crash.cpp
crc16.cpp crc16.cpp
crc32.cpp crc32.cpp
database/database_dump_service.cpp
database.cpp database.cpp
database_conversions.cpp database_conversions.cpp
database_instances.cpp database_instances.cpp
@ -31,6 +32,7 @@ SET(common_sources
event_sub.cpp event_sub.cpp
extprofile.cpp extprofile.cpp
faction.cpp faction.cpp
file_util.cpp
guild_base.cpp guild_base.cpp
guilds.cpp guilds.cpp
inventory_profile.cpp inventory_profile.cpp
@ -120,6 +122,7 @@ SET(common_headers
cli/argh.h cli/argh.h
cli/eqemu_command_handler.h cli/eqemu_command_handler.h
cli/terminal_color.hpp cli/terminal_color.hpp
database/database_dump_service.h
data_verification.h data_verification.h
database.h database.h
database_schema.h database_schema.h
@ -150,6 +153,7 @@ SET(common_headers
event_sub.h event_sub.h
extprofile.h extprofile.h
faction.h faction.h
file_util.h
features.h features.h
fixed_memory_hash_set.h fixed_memory_hash_set.h
fixed_memory_variable_hash_set.h fixed_memory_variable_hash_set.h

View File

@ -96,7 +96,7 @@ namespace EQEmuCommand {
"\nCommand" << "\nCommand" <<
termcolor::reset << "\n\n" << termcolor::reset << "\n\n" <<
termcolor::green << argv[1] << arguments_string << termcolor::reset << "\n" << termcolor::green << argv[1] << arguments_string << termcolor::reset << "\n" <<
termcolor::yellow << (!options_string.empty() ? "\nOptions\n" : "") << termcolor::yellow << (!options_string.empty() ? "\nOptions\n\n" : "") <<
termcolor::reset << termcolor::cyan << options_string << termcolor::reset; termcolor::reset << termcolor::cyan << options_string << termcolor::reset;
std::cout << command_string.str() << std::endl; std::cout << command_string.str() << std::endl;

View File

@ -925,6 +925,38 @@ void Database::GetCharName(uint32 char_id, char* name) {
} }
} }
const char* Database::GetCharNameByID(uint32 char_id) {
std::string query = fmt::format("SELECT `name` FROM `character_data` WHERE id = {}", char_id);
auto results = QueryDatabase(query);
if (!results.Success()) {
return "";
}
if (results.RowCount() == 0) {
return "";
}
auto row = results.begin();
return row[0];
}
const char* Database::GetNPCNameByID(uint32 npc_id) {
std::string query = fmt::format("SELECT `name` FROM `npc_types` WHERE id = {}", npc_id);
auto results = QueryDatabase(query);
if (!results.Success()) {
return "";
}
if (results.RowCount() == 0) {
return "";
}
auto row = results.begin();
return row[0];
}
bool Database::LoadVariables() { bool Database::LoadVariables() {
auto results = QueryDatabase(StringFormat("SELECT varname, value, unix_timestamp() FROM variables where unix_timestamp(ts) >= %d", varcache.last_update)); auto results = QueryDatabase(StringFormat("SELECT varname, value, unix_timestamp() FROM variables where unix_timestamp(ts) >= %d", varcache.last_update));
@ -2158,6 +2190,44 @@ uint32 Database::GetGuildIDByCharID(uint32 character_id)
return atoi(row[0]); return atoi(row[0]);
} }
uint32 Database::GetGroupIDByCharID(uint32 character_id)
{
std::string query = fmt::format(
SQL(
SELECT groupid
FROM group_id
WHERE charid = '{}'
),
character_id
);
auto results = QueryDatabase(query);
if (!results.Success())
return 0;
if (results.RowCount() == 0)
return 0;
auto row = results.begin();
return atoi(row[0]);
}
uint32 Database::GetRaidIDByCharID(uint32 character_id) {
std::string query = fmt::format(
SQL(
SELECT raidid
FROM raid_members
WHERE charid = '{}'
),
character_id
);
auto results = QueryDatabase(query);
for (auto row = results.begin(); row != results.end(); ++row) {
return atoi(row[0]);
}
return 0;
}
/** /**
* @param log_settings * @param log_settings
*/ */
@ -2335,3 +2405,4 @@ int Database::GetInstanceID(uint32 char_id, uint32 zone_id) {
return 0; return 0;
} }

View File

@ -133,9 +133,13 @@ public:
uint32 GetCharacterID(const char *name); uint32 GetCharacterID(const char *name);
uint32 GetCharacterInfo(const char* iName, uint32* oAccID = 0, uint32* oZoneID = 0, uint32* oInstanceID = 0, float* oX = 0, float* oY = 0, float* oZ = 0); uint32 GetCharacterInfo(const char* iName, uint32* oAccID = 0, uint32* oZoneID = 0, uint32* oInstanceID = 0, float* oX = 0, float* oY = 0, float* oZ = 0);
uint32 GetGuildIDByCharID(uint32 char_id); uint32 GetGuildIDByCharID(uint32 char_id);
uint32 GetGroupIDByCharID(uint32 char_id);
uint32 GetRaidIDByCharID(uint32 char_id);
void GetAccountName(uint32 accountid, char* name, uint32* oLSAccountID = 0); void GetAccountName(uint32 accountid, char* name, uint32* oLSAccountID = 0);
void GetCharName(uint32 char_id, char* name); void GetCharName(uint32 char_id, char* name);
const char *GetCharNameByID(uint32 char_id);
const char *GetNPCNameByID(uint32 npc_id);
void LoginIP(uint32 AccountID, const char* LoginIP); void LoginIP(uint32 AccountID, const char* LoginIP);
/* Instancing */ /* Instancing */
@ -192,19 +196,19 @@ public:
void GetAccountFromID(uint32 id, char* oAccountName, int16* oStatus); void GetAccountFromID(uint32 id, char* oAccountName, int16* oStatus);
void SetAgreementFlag(uint32 acctid); void SetAgreementFlag(uint32 acctid);
int GetIPExemption(std::string account_ip); int GetIPExemption(std::string account_ip);
int GetInstanceID(uint32 char_id, uint32 zone_id); int GetInstanceID(uint32 char_id, uint32 zone_id);
/* Groups */ /* Groups */
char* GetGroupLeaderForLogin(const char* name,char* leaderbuf); char* GetGroupLeaderForLogin(const char* name,char* leaderbuf);
char* GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* maintank = nullptr, char* assist = nullptr, char* puller = nullptr, char *marknpc = nullptr, char *mentoree = nullptr, int *mentor_percent = nullptr, GroupLeadershipAA_Struct* GLAA = nullptr); char* GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* maintank = nullptr, char* assist = nullptr, char* puller = nullptr, char *marknpc = nullptr, char *mentoree = nullptr, int *mentor_percent = nullptr, GroupLeadershipAA_Struct* GLAA = nullptr);
uint32 GetGroupID(const char* name); uint32 GetGroupID(const char* name);
void ClearGroup(uint32 gid = 0); void ClearGroup(uint32 gid = 0);
void ClearGroupLeader(uint32 gid = 0); void ClearGroupLeader(uint32 gid = 0);
void SetGroupID(const char* name, uint32 id, uint32 charid, uint32 ismerc = false); void SetGroupID(const char* name, uint32 id, uint32 charid, uint32 ismerc = false);

View File

@ -0,0 +1,569 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* 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 <string>
#include <cstdio>
#include <iterator>
#include "database_dump_service.h"
#include "../eqemu_logsys.h"
#include "../string_util.h"
#include "../eqemu_config.h"
#include "../database_schema.h"
#include "../file_util.h"
#include <ctime>
#if _WIN32
#include <windows.h>
#else
#include <sys/time.h>
#endif
#define DATABASE_DUMP_PATH "backups/"
/**
* @param cmd
* @param return_result
* @return
*/
std::string DatabaseDumpService::execute(const std::string &cmd, bool return_result = true)
{
const char *file_name = "db-exec-result.txt";
if (return_result) {
#ifdef _WINDOWS
std::system((cmd + " > " + file_name + " 2>&1").c_str());
#else
std::system((cmd + " > " + file_name).c_str());
#endif
}
else {
std::system((cmd).c_str());
}
std::string result;
if (return_result) {
std::ifstream file(file_name);
result = {std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()};
std::remove(file_name);
}
return result;
}
/**
* @return bool
*/
bool DatabaseDumpService::IsMySQLInstalled()
{
std::string version_output = GetMySQLVersion();
return version_output.find("mysql") != std::string::npos && version_output.find("Ver") != std::string::npos;
}
/**
* Linux
* @return bool
*/
bool DatabaseDumpService::IsTarAvailable()
{
std::string version_output = execute("tar --version");
return version_output.find("GNU tar") != std::string::npos;
}
/**
* Windows
* @return bool
*/
bool DatabaseDumpService::Is7ZipAvailable()
{
std::string version_output = execute("7z --help");
return version_output.find("7-Zip") != std::string::npos;
}
/**
* @return
*/
bool DatabaseDumpService::HasCompressionBinary()
{
return IsTarAvailable() || Is7ZipAvailable();
}
/**
* @return
*/
std::string DatabaseDumpService::GetMySQLVersion()
{
std::string version_output = execute("mysql --version");
return trim(version_output);
}
/**
* @return
*/
std::string DatabaseDumpService::GetBaseMySQLDumpCommand()
{
auto config = EQEmuConfig::get();
return fmt::format(
"mysqldump -u {} -p{} -h {} {}",
config->DatabaseUsername,
config->DatabasePassword,
config->DatabaseHost,
config->DatabaseDB
);
}
/**
* @return
*/
std::string DatabaseDumpService::GetPlayerTablesList()
{
std::string tables_list;
std::vector<std::string> tables = DatabaseSchema::GetPlayerTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return trim(tables_list);
}
/**
* @return
*/
std::string DatabaseDumpService::GetLoginTableList()
{
std::string tables_list;
std::vector<std::string> tables = DatabaseSchema::GetLoginTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return trim(tables_list);
}
/**
* @return
*/
std::string DatabaseDumpService::GetQueryServTables()
{
std::string tables_list;
std::vector<std::string> tables = DatabaseSchema::GetQueryServerTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return trim(tables_list);
}
/**
* @return
*/
std::string DatabaseDumpService::GetSystemTablesList()
{
std::string tables_list;
std::vector<std::string> tables = DatabaseSchema::GetServerTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
tables = DatabaseSchema::GetVersionTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return trim(tables_list);
}
/**
* @return
*/
std::string DatabaseDumpService::GetStateTablesList()
{
std::string tables_list;
std::vector<std::string> tables = DatabaseSchema::GetStateTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return trim(tables_list);
}
/**
* @return
*/
std::string DatabaseDumpService::GetContentTablesList()
{
std::string tables_list;
std::vector<std::string> tables = DatabaseSchema::GetContentTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return trim(tables_list);
}
/**
* @return
*/
std::string GetDumpDate()
{
time_t now = time(nullptr);
struct tm time_struct{};
char buf[80];
time_struct = *localtime(&now);
strftime(buf, sizeof(buf), "%Y-%m-%d", &time_struct);
std::string time = buf;
return time;
}
/**
* @return
*/
std::string DatabaseDumpService::GetSetDumpPath()
{
return !GetDumpPath().empty() ? GetDumpPath() : DATABASE_DUMP_PATH;
}
/**
* @return
*/
std::string DatabaseDumpService::GetDumpFileNameWithPath()
{
return GetSetDumpPath() + GetDumpFileName();
}
void DatabaseDumpService::Dump()
{
if (!IsMySQLInstalled()) {
LogError("MySQL is not installed; Please check your PATH for a valid MySQL installation");
return;
}
if (IsDumpDropTableSyntaxOnly()) {
SetDumpOutputToConsole(true);
}
if (IsDumpOutputToConsole()) {
LogSys.SilenceConsoleLogging();
}
LogInfo("MySQL installed [{}]", GetMySQLVersion());
SetDumpFileName(EQEmuConfig::get()->DatabaseDB + '-' + GetDumpDate());
auto config = EQEmuConfig::get();
LogInfo(
"Database [{}] Host [{}] Username [{}]",
config->DatabaseDB,
config->DatabaseHost,
config->DatabaseUsername
);
std::string options = "--allow-keywords --extended-insert";
if (IsDumpWithNoData()) {
options += " --no-data";
}
if (!IsDumpTableLock()) {
options += " --skip-lock-tables";
}
std::string tables_to_dump;
std::string dump_descriptor;
if (!IsDumpAllTables()) {
if (IsDumpPlayerTables()) {
tables_to_dump += GetPlayerTablesList() + " ";
dump_descriptor += "-player";
}
if (IsDumpSystemTables()) {
tables_to_dump += GetSystemTablesList() + " ";
dump_descriptor += "-system";
}
if (IsDumpStateTables()) {
tables_to_dump += GetStateTablesList() + " ";
dump_descriptor += "-state";
}
if (IsDumpContentTables()) {
tables_to_dump += GetContentTablesList() + " ";
dump_descriptor += "-content";
}
if (IsDumpLoginServerTables()) {
tables_to_dump += GetLoginTableList() + " ";
dump_descriptor += "-login";
}
if (IsDumpQueryServerTables()) {
tables_to_dump += GetQueryServTables();
dump_descriptor += "-queryserv";
}
}
if (!dump_descriptor.empty()) {
SetDumpFileName(GetDumpFileName() + dump_descriptor);
}
/**
* If we are dumping to stdout then we don't generate a file
*/
std::string pipe_file;
if (!IsDumpOutputToConsole()) {
pipe_file = fmt::format(" > {}.sql", GetDumpFileNameWithPath());
}
std::string execute_command = fmt::format(
"{} {} {} {}",
GetBaseMySQLDumpCommand(),
options,
tables_to_dump,
pipe_file
);
if (!FileUtil::exists(GetSetDumpPath()) && !IsDumpOutputToConsole()) {
FileUtil::mkdir(GetSetDumpPath());
}
if (IsDumpDropTableSyntaxOnly()) {
std::vector<std::string> tables = SplitString(tables_to_dump, ' ');
for (auto &table : tables) {
std::cout << "DROP TABLE IF EXISTS `" << table << "`;" << std::endl;
}
if (tables_to_dump.empty()) {
std::cerr << "No tables were specified" << std::endl;
}
}
else {
std::string execution_result = execute(execute_command, IsDumpOutputToConsole());
if (!execution_result.empty()) {
std::cout << execution_result;
}
}
if (!tables_to_dump.empty()) {
LogInfo("Dumping Tables [{}]", tables_to_dump);
}
LogInfo("Database dump created at [{}.sql]", GetDumpFileNameWithPath());
if (IsDumpWithCompression() && !IsDumpOutputToConsole()) {
if (HasCompressionBinary()) {
LogInfo("Compression requested... Compressing dump [{}.sql]", GetDumpFileNameWithPath());
if (IsTarAvailable()) {
execute(
fmt::format(
"tar -zcvf {}.tar.gz -C {} {}.sql",
GetDumpFileNameWithPath(),
GetSetDumpPath(),
GetDumpFileName()
)
);
LogInfo("Compressed dump created at [{}.tar.gz]", GetDumpFileNameWithPath());
}
else if (Is7ZipAvailable()) {
execute(
fmt::format(
"7z a -t7z {}.zip {}.sql",
GetDumpFileNameWithPath(),
GetDumpFileNameWithPath()
)
);
LogInfo("Compressed dump created at [{}.zip]", GetDumpFileNameWithPath());
}
else {
LogInfo("Compression requested, but no available compression binary was found");
}
}
else {
LogWarning("Compression requested but binary not found... Skipping...");
}
}
// LogDebug("[{}] dump-to-console", IsDumpOutputToConsole());
// LogDebug("[{}] dump-path", GetSetDumpPath());
// LogDebug("[{}] compression", (IsDumpWithCompression() ? "true" : "false"));
// LogDebug("[{}] query-serv", (IsDumpQueryServerTables() ? "true" : "false"));
// LogDebug("[{}] has-compression-binary", (HasCompressionBinary() ? "true" : "false"));
// LogDebug("[{}] content", (IsDumpContentTables() ? "true" : "false"));
// LogDebug("[{}] no-data", (IsDumpWithNoData() ? "true" : "false"));
// LogDebug("[{}] login", (IsDumpLoginServerTables() ? "true" : "false"));
// LogDebug("[{}] player", (IsDumpPlayerTables() ? "true" : "false"));
// LogDebug("[{}] system", (IsDumpSystemTables() ? "true" : "false"));
}
bool DatabaseDumpService::IsDumpSystemTables() const
{
return dump_system_tables;
}
void DatabaseDumpService::SetDumpSystemTables(bool dump_system_tables)
{
DatabaseDumpService::dump_system_tables = dump_system_tables;
}
bool DatabaseDumpService::IsDumpContentTables() const
{
return dump_content_tables;
}
void DatabaseDumpService::SetDumpContentTables(bool dump_content_tables)
{
DatabaseDumpService::dump_content_tables = dump_content_tables;
}
bool DatabaseDumpService::IsDumpPlayerTables() const
{
return dump_player_tables;
}
void DatabaseDumpService::SetDumpPlayerTables(bool dump_player_tables)
{
DatabaseDumpService::dump_player_tables = dump_player_tables;
}
bool DatabaseDumpService::IsDumpLoginServerTables() const
{
return dump_login_server_tables;
}
void DatabaseDumpService::SetDumpLoginServerTables(bool dump_login_server_tables)
{
DatabaseDumpService::dump_login_server_tables = dump_login_server_tables;
}
bool DatabaseDumpService::IsDumpWithNoData() const
{
return dump_with_no_data;
}
void DatabaseDumpService::SetDumpWithNoData(bool dump_with_no_data)
{
DatabaseDumpService::dump_with_no_data = dump_with_no_data;
}
bool DatabaseDumpService::IsDumpAllTables() const
{
return dump_all_tables;
}
void DatabaseDumpService::SetDumpAllTables(bool dump_all_tables)
{
DatabaseDumpService::dump_all_tables = dump_all_tables;
}
bool DatabaseDumpService::IsDumpTableLock() const
{
return dump_table_lock;
}
void DatabaseDumpService::SetDumpTableLock(bool dump_table_lock)
{
DatabaseDumpService::dump_table_lock = dump_table_lock;
}
bool DatabaseDumpService::IsDumpWithCompression() const
{
return dump_with_compression;
}
void DatabaseDumpService::SetDumpWithCompression(bool dump_with_compression)
{
DatabaseDumpService::dump_with_compression = dump_with_compression;
}
const std::string &DatabaseDumpService::GetDumpPath() const
{
return dump_path;
}
void DatabaseDumpService::SetDumpPath(const std::string &dump_path)
{
DatabaseDumpService::dump_path = dump_path;
}
void DatabaseDumpService::SetDumpFileName(const std::string &dump_file_name)
{
DatabaseDumpService::dump_file_name = dump_file_name;
}
const std::string &DatabaseDumpService::GetDumpFileName() const
{
return dump_file_name;
}
bool DatabaseDumpService::IsDumpQueryServerTables() const
{
return dump_query_server_tables;
}
void DatabaseDumpService::SetDumpQueryServerTables(bool dump_query_server_tables)
{
DatabaseDumpService::dump_query_server_tables = dump_query_server_tables;
}
bool DatabaseDumpService::IsDumpOutputToConsole() const
{
return dump_output_to_console;
}
void DatabaseDumpService::SetDumpOutputToConsole(bool dump_output_to_console)
{
DatabaseDumpService::dump_output_to_console = dump_output_to_console;
}
bool DatabaseDumpService::IsDumpDropTableSyntaxOnly() const
{
return dump_drop_table_syntax_only;
}
void DatabaseDumpService::SetDumpDropTableSyntaxOnly(bool dump_drop_table_syntax_only)
{
DatabaseDumpService::dump_drop_table_syntax_only = dump_drop_table_syntax_only;
}
bool DatabaseDumpService::IsDumpStateTables() const
{
return dump_state_tables;
}
void DatabaseDumpService::SetDumpStateTables(bool dump_state_tables)
{
DatabaseDumpService::dump_state_tables = dump_state_tables;
}

View File

@ -0,0 +1,91 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* 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 EQEMU_DATABASE_DUMP_SERVICE_H
#define EQEMU_DATABASE_DUMP_SERVICE_H
class DatabaseDumpService {
public:
void Dump();
bool IsDumpAllTables() const;
void SetDumpAllTables(bool dump_all_tables);
bool IsDumpWithNoData() const;
void SetDumpWithNoData(bool dump_with_no_data);
bool IsDumpSystemTables() const;
void SetDumpSystemTables(bool dump_system_tables);
bool IsDumpContentTables() const;
void SetDumpContentTables(bool dump_content_tables);
bool IsDumpPlayerTables() const;
void SetDumpPlayerTables(bool dump_player_tables);
bool IsDumpLoginServerTables() const;
void SetDumpLoginServerTables(bool dump_login_server_tables);
bool IsDumpTableLock() const;
void SetDumpTableLock(bool dump_table_lock);
bool IsDumpWithCompression() const;
void SetDumpWithCompression(bool dump_with_compression);
const std::string &GetDumpPath() const;
void SetDumpPath(const std::string &dump_path);
const std::string &GetDumpFileName() const;
void SetDumpFileName(const std::string &dump_file_name);
bool IsDumpQueryServerTables() const;
void SetDumpQueryServerTables(bool dump_query_server_tables);
bool IsDumpOutputToConsole() const;
void SetDumpOutputToConsole(bool dump_output_to_console);
bool IsDumpDropTableSyntaxOnly() const;
void SetDumpDropTableSyntaxOnly(bool dump_drop_table_syntax_only);
bool IsDumpStateTables() const;
void SetDumpStateTables(bool dump_state_tables);
private:
bool dump_all_tables = false;
bool dump_state_tables = false;
bool dump_system_tables = false;
bool dump_content_tables = false;
bool dump_player_tables = false;
bool dump_query_server_tables = false;
bool dump_login_server_tables = false;
bool dump_with_no_data = false;
bool dump_table_lock = false;
bool dump_with_compression = false;
bool dump_output_to_console = false;
bool dump_drop_table_syntax_only = false;
std::string dump_path;
std::string dump_file_name;
std::string execute(const std::string &cmd, bool return_result);
bool IsMySQLInstalled();
std::string GetMySQLVersion();
std::string GetBaseMySQLDumpCommand();
std::string GetPlayerTablesList();
std::string GetSystemTablesList();
std::string GetStateTablesList();
std::string GetContentTablesList();
std::string GetLoginTableList();
bool IsTarAvailable();
bool Is7ZipAvailable();
bool HasCompressionBinary();
std::string GetDumpFileNameWithPath();
std::string GetSetDumpPath();
std::string GetQueryServTables();
};
#endif //EQEMU_DATABASE_DUMP_SERVICE_H

View File

@ -97,42 +97,53 @@ bool Database::CheckInstanceExists(uint16 instance_id) {
bool Database::CheckInstanceExpired(uint16 instance_id) bool Database::CheckInstanceExpired(uint16 instance_id)
{ {
int32 start_time = 0; int32 start_time = 0;
int32 duration = 0; int32 duration = 0;
uint32 never_expires = 0; uint32 never_expires = 0;
std::string query = StringFormat("SELECT start_time, duration, never_expires FROM instance_list WHERE id=%u", instance_id); std::string query = StringFormat(
"SELECT start_time, duration, never_expires FROM instance_list WHERE id=%u",
instance_id
);
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
if (!results.Success()) if (!results.Success()) {
return true; return true;
}
if (results.RowCount() == 0) if (results.RowCount() == 0) {
return true; return true;
}
auto row = results.begin(); auto row = results.begin();
start_time = atoi(row[0]); start_time = atoi(row[0]);
duration = atoi(row[1]); duration = atoi(row[1]);
never_expires = atoi(row[2]); never_expires = atoi(row[2]);
if (never_expires == 1) if (never_expires == 1) {
return false; return false;
}
timeval tv; timeval tv{};
gettimeofday(&tv, nullptr); gettimeofday(&tv, nullptr);
if ((start_time + duration) <= tv.tv_sec) return (start_time + duration) <= tv.tv_sec;
return true;
return false;
} }
bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration) bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration)
{ {
std::string query = StringFormat("INSERT INTO instance_list (id, zone, version, start_time, duration)" std::string query = StringFormat(
" values(%lu, %lu, %lu, UNIX_TIMESTAMP(), %lu)", "INSERT INTO instance_list (id, zone, version, start_time, duration)"
(unsigned long)instance_id, (unsigned long)zone_id, (unsigned long)version, (unsigned long)duration); " values (%u, %u, %u, UNIX_TIMESTAMP(), %u)",
instance_id,
zone_id,
version,
duration
);
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
return results.Success(); return results.Success();
@ -140,66 +151,84 @@ bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version
bool Database::GetUnusedInstanceID(uint16 &instance_id) bool Database::GetUnusedInstanceID(uint16 &instance_id)
{ {
uint32 count = RuleI(Zone, ReservedInstances); uint32 max_reserved_instance_id = RuleI(Instances, ReservedInstances);
uint32 max = 65535; uint32 max = 32000;
std::string query = StringFormat(
"SELECT IFNULL(MAX(id),%u)+1 FROM instance_list WHERE id > %u",
max_reserved_instance_id,
max_reserved_instance_id
);
if (RuleB(Instances, RecycleInstanceIds)) {
query = (
SQL(
SELECT i.id + 1 AS next_available
FROM instance_list i
LEFT JOIN instance_list i2 ON i2.id = i.id + 1
WHERE i2.id IS NULL
ORDER BY i.id
LIMIT 0, 1;
)
);
}
std::string query = StringFormat("SELECT IFNULL(MAX(id),%u)+1 FROM instance_list WHERE id > %u", count, count);
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
if (!results.Success()) if (!results.Success()) {
{
instance_id = 0; instance_id = 0;
return false; return false;
} }
if (results.RowCount() == 0) if (results.RowCount() == 0) {
{ instance_id = max_reserved_instance_id;
instance_id = 0; return true;
return false;
} }
auto row = results.begin(); auto row = results.begin();
if (atoi(row[0]) <= max) if (atoi(row[0]) <= max) {
{
instance_id = atoi(row[0]); instance_id = atoi(row[0]);
return true; return true;
} }
query = StringFormat("SELECT id FROM instance_list where id > %u ORDER BY id", count); if (instance_id < max_reserved_instance_id) {
instance_id = max_reserved_instance_id;
return true;
}
query = StringFormat("SELECT id FROM instance_list where id > %u ORDER BY id", max_reserved_instance_id);
results = QueryDatabase(query); results = QueryDatabase(query);
if (!results.Success()) if (!results.Success()) {
{
instance_id = 0; instance_id = 0;
return false; return false;
} }
if (results.RowCount() == 0) if (results.RowCount() == 0) {
{
instance_id = 0; instance_id = 0;
return false; return false;
} }
count++; max_reserved_instance_id++;
for (auto row = results.begin(); row != results.end(); ++row) for (auto row = results.begin(); row != results.end(); ++row) {
{ if (max_reserved_instance_id < atoi(row[0])) {
if (count < atoi(row[0])) instance_id = max_reserved_instance_id;
{
instance_id = count;
return true; return true;
} }
if (count > max) if (max_reserved_instance_id > max) {
{
instance_id = 0; instance_id = 0;
return false; return false;
} }
count++; max_reserved_instance_id++;
} }
instance_id = count; instance_id = max_reserved_instance_id;
return true; return true;
} }
@ -486,8 +515,7 @@ void Database::BuryCorpsesInInstance(uint16 instance_id) {
void Database::DeleteInstance(uint16 instance_id) void Database::DeleteInstance(uint16 instance_id)
{ {
std::string query = StringFormat("DELETE FROM instance_list WHERE id=%u", instance_id); std::string query;
QueryDatabase(query);
query = StringFormat("DELETE FROM instance_list_player WHERE id=%u", instance_id); query = StringFormat("DELETE FROM instance_list_player WHERE id=%u", instance_id);
QueryDatabase(query); QueryDatabase(query);
@ -548,17 +576,36 @@ void Database::GetCharactersInInstance(uint16 instance_id, std::list<uint32> &ch
void Database::PurgeExpiredInstances() void Database::PurgeExpiredInstances()
{ {
std::string query("SELECT id FROM instance_list where (start_time+duration) <= UNIX_TIMESTAMP() and never_expires = 0");
/**
* Delay purging by a day so that we can continue using adjacent free instance id's
* from the table without risking the chance we immediately re-allocate a zone that freshly expired but
* has not been fully de-allocated
*/
std::string query =
SQL(
SELECT
id
FROM
instance_list
where
(start_time + duration) <= (UNIX_TIMESTAMP() - 86400)
and never_expires = 0
);
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
if (!results.Success()) if (!results.Success()) {
return; return;
}
if (results.RowCount() == 0) if (results.RowCount() == 0) {
return; return;
}
for (auto row = results.begin(); row != results.end(); ++row) for (auto row = results.begin(); row != results.end(); ++row) {
DeleteInstance(atoi(row[0])); DeleteInstance(atoi(row[0]));
}
} }
void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration) void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration)
@ -566,4 +613,4 @@ void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration)
std::string query = StringFormat("UPDATE `instance_list` SET start_time=UNIX_TIMESTAMP(), " std::string query = StringFormat("UPDATE `instance_list` SET start_time=UNIX_TIMESTAMP(), "
"duration=%u WHERE id=%u", new_duration, instance_id); "duration=%u WHERE id=%u", new_duration, instance_id);
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
} }

View File

@ -85,7 +85,8 @@ namespace DatabaseSchema {
} }
/** /**
* Gets all player and meta-data tables * @description Gets all player and meta-data tables
* @note These tables have no content in the PEQ daily dump
* *
* @return * @return
*/ */
@ -129,6 +130,7 @@ namespace DatabaseSchema {
"character_tribute", "character_tribute",
"completed_tasks", "completed_tasks",
"data_buckets", "data_buckets",
"discovered_items",
"faction_values", "faction_values",
"friends", "friends",
"guild_bank", "guild_bank",
@ -141,9 +143,12 @@ namespace DatabaseSchema {
"inventory_snapshots", "inventory_snapshots",
"keyring", "keyring",
"mail", "mail",
"petitions",
"player_titlesets", "player_titlesets",
"quest_globals", "quest_globals",
"sharedbank", "sharedbank",
"spell_buckets",
"spell_globals",
"timers", "timers",
"titles", "titles",
"trader", "trader",
@ -233,7 +238,6 @@ namespace DatabaseSchema {
"task_activities", "task_activities",
"tasks", "tasks",
"tasksets", "tasksets",
"titles",
"tradeskill_recipe", "tradeskill_recipe",
"tradeskill_recipe_entries", "tradeskill_recipe_entries",
"traps", "traps",
@ -255,33 +259,49 @@ namespace DatabaseSchema {
static std::vector<std::string> GetServerTables() static std::vector<std::string> GetServerTables()
{ {
return { return {
"banned_ips", "chatchannels",
"bugs",
"bug_reports",
"command_settings", "command_settings",
"db_str", "db_str",
"discovered_items",
"eqtime", "eqtime",
"eventlog",
"gm_ips",
"hackers",
"ip_exemptions",
"launcher", "launcher",
"launcher_zones", "launcher_zones",
"level_exp_mods", "level_exp_mods",
"logsys_categories", "logsys_categories",
"name_filter", "name_filter",
"perl_event_export_settings", "perl_event_export_settings",
"petitions",
"profanity_list", "profanity_list",
"reports",
"rule_sets", "rule_sets",
"rule_values", "rule_values",
"saylink",
"variables", "variables",
}; };
} }
/**
* Gets QueryServer tables
*
* @return
*/
static std::vector<std::string> GetQueryServerTables()
{
return {
"qs_merchant_transaction_record",
"qs_merchant_transaction_record_entries",
"qs_player_aa_rate_hourly",
"qs_player_delete_record",
"qs_player_delete_record_entries",
"qs_player_events",
"qs_player_handin_record",
"qs_player_handin_record_entries",
"qs_player_move_record",
"qs_player_move_record_entries",
"qs_player_npc_kill_record",
"qs_player_npc_kill_record_entries",
"qs_player_speech",
"qs_player_trade_record",
"qs_player_trade_record_entries",
};
}
/** /**
* Gets state tables * Gets state tables
* Tables that keep track of server state * Tables that keep track of server state
@ -292,9 +312,15 @@ namespace DatabaseSchema {
{ {
return { return {
"adventure_members", "adventure_members",
"chatchannels", "banned_ips",
"bug_reports",
"bugs",
"eventlog",
"gm_ips",
"group_id", "group_id",
"group_leaders", "group_leaders",
"hackers",
"ip_exemptions",
"item_tick", "item_tick",
"lfguild", "lfguild",
"merchantlist_temp", "merchantlist_temp",
@ -302,9 +328,10 @@ namespace DatabaseSchema {
"raid_details", "raid_details",
"raid_leaders", "raid_leaders",
"raid_members", "raid_members",
"reports",
"respawn_times", "respawn_times",
"spell_buckets", "saylink",
"spell_globals",
}; };
} }

View File

@ -25,6 +25,10 @@ namespace EQ
uv_run(&m_loop, UV_RUN_DEFAULT); uv_run(&m_loop, UV_RUN_DEFAULT);
} }
void Shutdown() {
uv_stop(&m_loop);
}
uv_loop_t* Handle() { return &m_loop; } uv_loop_t* Handle() { return &m_loop; }
private: private:

67
common/file_util.cpp Normal file
View File

@ -0,0 +1,67 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* 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 <fstream>
#include "file_util.h"
#ifdef _WINDOWS
#include <direct.h>
#include <conio.h>
#include <iostream>
#include <dos.h>
#include <windows.h>
#include <process.h>
#else
#include <unistd.h>
#include <sys/stat.h>
#endif
/**
* @param name
* @return
*/
bool FileUtil::exists(const std::string &name)
{
std::ifstream f(name.c_str());
return f.good();
}
/**
* @param directory_name
*/
void FileUtil::mkdir(const std::string& directory_name)
{
#ifdef _WINDOWS
struct _stat st;
if (_stat(directory_name.c_str(), &st) == 0) // exists
return;
_mkdir(directory_name.c_str());
#else
struct stat st{};
if (stat(directory_name.c_str(), &st) == 0) { // exists
return;
}
::mkdir(directory_name.c_str(), 0755);
#endif
}

32
common/file_util.h Normal file
View File

@ -0,0 +1,32 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* 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 EQEMU_FILE_UTIL_H
#define EQEMU_FILE_UTIL_H
class FileUtil {
public:
static bool exists(const std::string &name);
static void mkdir(const std::string& directory_name);
};
#endif //EQEMU_FILE_UTIL_H

View File

@ -912,7 +912,7 @@ bool BaseGuildManager::GetEntireGuild(uint32 guild_id, std::vector<CharGuildInfo
return(false); return(false);
//load up the rank info for each guild. //load up the rank info for each guild.
std::string query = StringFormat(GuildMemberBaseQuery " WHERE g.guild_id=%d", guild_id); std::string query = StringFormat(GuildMemberBaseQuery " WHERE g.guild_id=%d AND c.deleted_at IS NULL", guild_id);
auto results = m_db->QueryDatabase(query); auto results = m_db->QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {
return false; return false;
@ -941,7 +941,7 @@ bool BaseGuildManager::GetCharInfo(const char *char_name, CharGuildInfo &into) {
m_db->DoEscapeString(esc, char_name, nl); m_db->DoEscapeString(esc, char_name, nl);
//load up the rank info for each guild. //load up the rank info for each guild.
std::string query = StringFormat(GuildMemberBaseQuery " WHERE c.name='%s'", esc); std::string query = StringFormat(GuildMemberBaseQuery " WHERE c.name='%s' AND c.deleted_at IS NULL", esc);
safe_delete_array(esc); safe_delete_array(esc);
auto results = m_db->QueryDatabase(query); auto results = m_db->QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {
@ -969,9 +969,9 @@ bool BaseGuildManager::GetCharInfo(uint32 char_id, CharGuildInfo &into) {
//load up the rank info for each guild. //load up the rank info for each guild.
std::string query; std::string query;
#ifdef BOTS #ifdef BOTS
query = StringFormat(GuildMemberBaseQuery " WHERE c.id=%d AND c.mob_type = 'C'", char_id); query = StringFormat(GuildMemberBaseQuery " WHERE c.id=%d AND c.mob_type = 'C' AND c.deleted_at IS NULL", char_id);
#else #else
query = StringFormat(GuildMemberBaseQuery " WHERE c.id=%d", char_id); query = StringFormat(GuildMemberBaseQuery " WHERE c.id=%d AND c.deleted_at IS NULL", char_id);
#endif #endif
auto results = m_db->QueryDatabase(query); auto results = m_db->QueryDatabase(query);
if (!results.Success()) { if (!results.Success()) {

View File

@ -605,6 +605,8 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
ProcessDecodedPacket(StaticPacket(current, subpacket_length)); ProcessDecodedPacket(StaticPacket(current, subpacket_length));
current += subpacket_length; current += subpacket_length;
} }
break;
} }
case OP_SessionRequest: case OP_SessionRequest:

View File

@ -161,6 +161,7 @@ RULE_BOOL(Character, DismountWater, true, "Dismount horses when entering water")
RULE_BOOL(Character, UseNoJunkFishing, false, "Disregards junk items when fishing") RULE_BOOL(Character, UseNoJunkFishing, false, "Disregards junk items when fishing")
RULE_BOOL(Character, SoftDeletes, true, "When characters are deleted in character select, they are only soft deleted") RULE_BOOL(Character, SoftDeletes, true, "When characters are deleted in character select, they are only soft deleted")
RULE_INT(Character, DefaultGuild, 0, "If not 0, new characters placed into the guild # indicated") RULE_INT(Character, DefaultGuild, 0, "If not 0, new characters placed into the guild # indicated")
RULE_BOOL(Character, ProcessFearedProximity, false, "Processes proximity checks when feared")
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(Mercs) RULE_CATEGORY(Mercs)
@ -269,7 +270,6 @@ RULE_INT(Zone, PEQZoneDebuff1, 4454, "First debuff casted by #peqzone Default is
RULE_INT(Zone, PEQZoneDebuff2, 2209, "Second debuff casted by #peqzone Default is Tendrils of Apathy") RULE_INT(Zone, PEQZoneDebuff2, 2209, "Second debuff casted by #peqzone Default is Tendrils of Apathy")
RULE_BOOL(Zone, UsePEQZoneDebuffs, true, "Will determine if #peqzone will debuff players or not when used") RULE_BOOL(Zone, UsePEQZoneDebuffs, true, "Will determine if #peqzone will debuff players or not when used")
RULE_REAL(Zone, HotZoneBonus, 0.75, "") RULE_REAL(Zone, HotZoneBonus, 0.75, "")
RULE_INT(Zone, ReservedInstances, 30, "Will reserve this many instance ids for globals... probably not a good idea to change this while a server is running")
RULE_INT(Zone, EbonCrystalItemID, 40902, "") RULE_INT(Zone, EbonCrystalItemID, 40902, "")
RULE_INT(Zone, RadiantCrystalItemID, 40903, "") RULE_INT(Zone, RadiantCrystalItemID, 40903, "")
RULE_BOOL(Zone, LevelBasedEXPMods, false, "Allows you to use the level_exp_mods table in consideration to your players EXP hits") RULE_BOOL(Zone, LevelBasedEXPMods, false, "Allows you to use the level_exp_mods table in consideration to your players EXP hits")
@ -774,6 +774,12 @@ RULE_BOOL(HotReload, QuestsRepopWhenPlayersNotInCombat, true, "When a hot reload
RULE_BOOL(HotReload, QuestsResetTimersWithReload, true, "When a hot reload is triggered, quest timers will be reset") RULE_BOOL(HotReload, QuestsResetTimersWithReload, true, "When a hot reload is triggered, quest timers will be reset")
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(Instances)
RULE_INT(Instances, ReservedInstances, 30, "Will reserve this many instance ids for globals... probably not a good idea to change this while a server is running")
RULE_BOOL(Instances, RecycleInstanceIds, true, "Will recycle free instance ids instead of gradually running out at 32k")
RULE_INT(Instances, GuildHallExpirationDays, 90, "Amount of days before a Guild Hall instance expires")
RULE_CATEGORY_END()
#undef RULE_CATEGORY #undef RULE_CATEGORY
#undef RULE_INT #undef RULE_INT
#undef RULE_REAL #undef RULE_REAL

View File

@ -129,13 +129,17 @@ void Timer::SetTimer(uint32 set_timer_time) {
} }
} }
uint32 Timer::GetRemainingTime() const { uint32 Timer::GetRemainingTime() const
{
if (enabled) { if (enabled) {
if (current_time - start_time > timer_time) if (current_time - start_time > timer_time) {
return 0; return 0;
else }
else {
return (start_time + timer_time) - current_time; return (start_time + timer_time) - current_time;
} else { }
}
else {
return 0xFFFFFFFF; return 0xFFFFFFFF;
} }
} }

View File

@ -34,10 +34,10 @@
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt * Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/ */
#define CURRENT_BINARY_DATABASE_VERSION 9151 #define CURRENT_BINARY_DATABASE_VERSION 9152
#ifdef BOTS #ifdef BOTS
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9026 #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9027
#else #else
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 0 // must be 0 #define CURRENT_BINARY_BOTS_DATABASE_VERSION 0 // must be 0
#endif #endif

View File

@ -47,8 +47,13 @@ ChatChannel::ChatChannel(std::string inName, std::string inOwner, std::string in
Moderated = false; Moderated = false;
LogInfo("New ChatChannel created: Name: [[{}]], Owner: [[{}]], Password: [[{}]], MinStatus: [{}]", LogDebug(
Name.c_str(), Owner.c_str(), Password.c_str(), MinimumStatus); "New ChatChannel created: Name: [[{}]], Owner: [[{}]], Password: [[{}]], MinStatus: [{}]",
Name.c_str(),
Owner.c_str(),
Password.c_str(),
MinimumStatus
);
} }
@ -154,7 +159,7 @@ void ChatChannelList::SendAllChannels(Client *c) {
void ChatChannelList::RemoveChannel(ChatChannel *Channel) { void ChatChannelList::RemoveChannel(ChatChannel *Channel) {
LogInfo("RemoveChannel([{}])", Channel->GetName().c_str()); LogDebug("RemoveChannel ([{}])", Channel->GetName().c_str());
LinkedListIterator<ChatChannel*> iterator(ChatChannels); LinkedListIterator<ChatChannel*> iterator(ChatChannels);
@ -175,7 +180,7 @@ void ChatChannelList::RemoveChannel(ChatChannel *Channel) {
void ChatChannelList::RemoveAllChannels() { void ChatChannelList::RemoveAllChannels() {
LogInfo("RemoveAllChannels"); LogDebug("RemoveAllChannels");
LinkedListIterator<ChatChannel*> iterator(ChatChannels); LinkedListIterator<ChatChannel*> iterator(ChatChannels);
@ -242,7 +247,7 @@ void ChatChannel::AddClient(Client *c) {
int AccountStatus = c->GetAccountStatus(); int AccountStatus = c->GetAccountStatus();
LogInfo("Adding [{}] to channel [{}]", c->GetName().c_str(), Name.c_str()); LogDebug("Adding [{}] to channel [{}]", c->GetName().c_str(), Name.c_str());
LinkedListIterator<Client*> iterator(ClientsInChannel); LinkedListIterator<Client*> iterator(ClientsInChannel);
@ -267,7 +272,7 @@ bool ChatChannel::RemoveClient(Client *c) {
if(!c) return false; if(!c) return false;
LogInfo("RemoveClient [{}] from channel [{}]", c->GetName().c_str(), GetName().c_str()); LogDebug("RemoveClient [{}] from channel [{}]", c->GetName().c_str(), GetName().c_str());
bool HideMe = c->GetHideMe(); bool HideMe = c->GetHideMe();
@ -304,7 +309,7 @@ bool ChatChannel::RemoveClient(Client *c) {
if((Password.length() == 0) || (RuleI(Channels, DeleteTimer) == 0)) if((Password.length() == 0) || (RuleI(Channels, DeleteTimer) == 0))
return false; return false;
LogInfo("Starting delete timer for empty password protected channel [{}]", Name.c_str()); LogDebug("Starting delete timer for empty password protected channel [{}]", Name.c_str());
DeleteTimer.Start(RuleI(Channels, DeleteTimer) * 60000); DeleteTimer.Start(RuleI(Channels, DeleteTimer) * 60000);
} }
@ -402,7 +407,7 @@ void ChatChannel::SendMessageToChannel(std::string Message, Client* Sender) {
if(ChannelClient) if(ChannelClient)
{ {
LogInfo("Sending message to [{}] from [{}]", LogDebug("Sending message to [{}] from [{}]",
ChannelClient->GetName().c_str(), Sender->GetName().c_str()); ChannelClient->GetName().c_str(), Sender->GetName().c_str());
if (cv_messages[static_cast<uint32>(ChannelClient->GetClientVersion())].length() == 0) { if (cv_messages[static_cast<uint32>(ChannelClient->GetClientVersion())].length() == 0) {
@ -505,7 +510,7 @@ ChatChannel *ChatChannelList::AddClientToChannel(std::string ChannelName, Client
return nullptr; return nullptr;
} }
LogInfo("AddClient to channel [[{}]] with password [[{}]]", NormalisedName.c_str(), Password.c_str()); LogDebug("AddClient to channel [[{}]] with password [[{}]]", NormalisedName.c_str(), Password.c_str());
ChatChannel *RequiredChannel = FindChannel(NormalisedName); ChatChannel *RequiredChannel = FindChannel(NormalisedName);
@ -581,7 +586,7 @@ void ChatChannelList::Process() {
if(CurrentChannel && CurrentChannel->ReadyToDelete()) { if(CurrentChannel && CurrentChannel->ReadyToDelete()) {
LogInfo("Empty temporary password protected channel [{}] being destroyed", LogDebug("Empty temporary password protected channel [{}] being destroyed",
CurrentChannel->GetName().c_str()); CurrentChannel->GetName().c_str());
RemoveChannel(CurrentChannel); RemoveChannel(CurrentChannel);
@ -597,7 +602,7 @@ void ChatChannel::AddInvitee(const std::string &Invitee)
if (!IsInvitee(Invitee)) { if (!IsInvitee(Invitee)) {
Invitees.push_back(Invitee); Invitees.push_back(Invitee);
LogInfo("Added [{}] as invitee to channel [{}]", Invitee.c_str(), Name.c_str()); LogDebug("Added [{}] as invitee to channel [{}]", Invitee.c_str(), Name.c_str());
} }
} }
@ -608,7 +613,7 @@ void ChatChannel::RemoveInvitee(std::string Invitee)
if(it != std::end(Invitees)) { if(it != std::end(Invitees)) {
Invitees.erase(it); Invitees.erase(it);
LogInfo("Removed [{}] as invitee to channel [{}]", Invitee.c_str(), Name.c_str()); LogDebug("Removed [{}] as invitee to channel [{}]", Invitee.c_str(), Name.c_str());
} }
} }

View File

@ -235,7 +235,7 @@ std::vector<std::string> ParseRecipients(std::string RecipientString) {
static void ProcessMailTo(Client *c, std::string MailMessage) { static void ProcessMailTo(Client *c, std::string MailMessage) {
LogInfo("MAILTO: From [{}], [{}]", c->MailBoxName().c_str(), MailMessage.c_str()); LogDebug("MAILTO: From [{}], [{}]", c->MailBoxName().c_str(), MailMessage.c_str());
std::vector<std::string> Recipients; std::vector<std::string> Recipients;
@ -304,7 +304,7 @@ static void ProcessMailTo(Client *c, std::string MailMessage) {
if (!database.SendMail(Recipient, c->MailBoxName(), Subject, Body, RecipientsString)) { if (!database.SendMail(Recipient, c->MailBoxName(), Subject, Body, RecipientsString)) {
LogInfo("Failed in SendMail([{}], [{}], [{}], [{}])", Recipient.c_str(), LogError("Failed in SendMail([{}], [{}], [{}], [{}])", Recipient.c_str(),
c->MailBoxName().c_str(), Subject.c_str(), RecipientsString.c_str()); c->MailBoxName().c_str(), Subject.c_str(), RecipientsString.c_str());
int PacketLength = 10 + Recipient.length() + Subject.length(); int PacketLength = 10 + Recipient.length() + Subject.length();
@ -556,6 +556,17 @@ void Client::CloseConnection() {
ClientStream->ReleaseFromUse(); ClientStream->ReleaseFromUse();
} }
void Clientlist::CheckForStaleConnectionsAll()
{
LogDebug("Checking for stale connections");
auto it = ClientChatConnections.begin();
while (it != ClientChatConnections.end()) {
(*it)->SendKeepAlive();
++it;
}
}
void Clientlist::CheckForStaleConnections(Client *c) { void Clientlist::CheckForStaleConnections(Client *c) {
if (!c) return; if (!c) return;
@ -634,10 +645,12 @@ void Clientlist::Process()
// //
std::string::size_type LastPeriod = MailBoxString.find_last_of("."); std::string::size_type LastPeriod = MailBoxString.find_last_of(".");
if (LastPeriod == std::string::npos) if (LastPeriod == std::string::npos) {
CharacterName = MailBoxString; CharacterName = MailBoxString;
else }
else {
CharacterName = MailBoxString.substr(LastPeriod + 1); CharacterName = MailBoxString.substr(LastPeriod + 1);
}
LogInfo("Received login for user [{}] with key [{}]", LogInfo("Received login for user [{}] with key [{}]",
MailBox, Key); MailBox, Key);
@ -652,8 +665,9 @@ void Clientlist::Process()
database.GetAccountStatus((*it)); database.GetAccountStatus((*it));
if ((*it)->GetConnectionType() == ConnectionTypeCombined) if ((*it)->GetConnectionType() == ConnectionTypeCombined) {
(*it)->SendFriends(); (*it)->SendFriends();
}
(*it)->SendMailBoxes(); (*it)->SendMailBoxes();
@ -865,7 +879,9 @@ void Clientlist::CloseAllConnections() {
void Client::AddCharacter(int CharID, const char *CharacterName, int Level) { void Client::AddCharacter(int CharID, const char *CharacterName, int Level) {
if (!CharacterName) return; if (!CharacterName) return;
LogInfo("Adding character [{}] with ID [{}] for [{}]", CharacterName, CharID, GetName().c_str());
LogDebug("Adding character [{}] with ID [{}] for [{}]", CharacterName, CharID, GetName().c_str());
CharacterEntry NewCharacter; CharacterEntry NewCharacter;
NewCharacter.CharID = CharID; NewCharacter.CharID = CharID;
NewCharacter.Name = CharacterName; NewCharacter.Name = CharacterName;
@ -874,6 +890,10 @@ void Client::AddCharacter(int CharID, const char *CharacterName, int Level) {
Characters.push_back(NewCharacter); Characters.push_back(NewCharacter);
} }
void Client::SendKeepAlive() {
QueuePacket(new EQApplicationPacket(OP_SessionReady, 0));
}
void Client::SendMailBoxes() { void Client::SendMailBoxes() {
int Count = Characters.size(); int Count = Characters.size();
@ -930,7 +950,7 @@ void Client::AddToChannelList(ChatChannel *JoinedChannel) {
for (int i = 0; i < MAX_JOINED_CHANNELS; i++) for (int i = 0; i < MAX_JOINED_CHANNELS; i++)
if (JoinedChannels[i] == nullptr) { if (JoinedChannels[i] == nullptr) {
JoinedChannels[i] = JoinedChannel; JoinedChannels[i] = JoinedChannel;
LogInfo("Added Channel [{}] to slot [{}] for [{}]", JoinedChannel->GetName().c_str(), i + 1, GetName().c_str()); LogDebug("Added Channel [{}] to slot [{}] for [{}]", JoinedChannel->GetName().c_str(), i + 1, GetName().c_str());
return; return;
} }
} }
@ -2346,18 +2366,17 @@ void Client::SendFriends() {
} }
} }
std::string Client::MailBoxName() { std::string Client::MailBoxName()
{
if ((Characters.empty()) || (CurrentMailBox > (Characters.size() - 1))) {
LogDebug("MailBoxName() called with CurrentMailBox set to [{}] and Characters.size() is [{}]",
CurrentMailBox, Characters.size());
if ((Characters.empty()) || (CurrentMailBox > (Characters.size() - 1))) return std::string();
{
LogInfo("MailBoxName() called with CurrentMailBox set to [{}] and Characters.size() is [{}]",
CurrentMailBox, Characters.size());
return "";
} }
LogInfo("MailBoxName() called with CurrentMailBox set to [{}] and Characters.size() is [{}]", LogDebug("MailBoxName() called with CurrentMailBox set to [{}] and Characters.size() is [{}]",
CurrentMailBox, Characters.size()); CurrentMailBox, Characters.size());
return Characters[CurrentMailBox].Name; return Characters[CurrentMailBox].Name;

View File

@ -143,7 +143,7 @@ public:
void SetConnectionType(char c); void SetConnectionType(char c);
ConnectionType GetConnectionType() { return TypeOfConnection; } ConnectionType GetConnectionType() { return TypeOfConnection; }
EQEmu::versions::ClientVersion GetClientVersion() { return ClientVersion_; } EQEmu::versions::ClientVersion GetClientVersion() { return ClientVersion_; }
inline bool IsMailConnection() { return (TypeOfConnection == ConnectionTypeMail) || (TypeOfConnection == ConnectionTypeCombined); } inline bool IsMailConnection() { return (TypeOfConnection == ConnectionTypeMail) || (TypeOfConnection == ConnectionTypeCombined); }
void SendNotification(int MailBoxNumber, std::string From, std::string Subject, int MessageID); void SendNotification(int MailBoxNumber, std::string From, std::string Subject, int MessageID);
void ChangeMailBox(int NewMailBox); void ChangeMailBox(int NewMailBox);
@ -151,6 +151,7 @@ public:
void SendFriends(); void SendFriends();
int GetCharID(); int GetCharID();
void SendUptime(); void SendUptime();
void SendKeepAlive();
private: private:
unsigned int CurrentMailBox; unsigned int CurrentMailBox;
@ -183,6 +184,7 @@ public:
void Process(); void Process();
void CloseAllConnections(); void CloseAllConnections();
Client *FindCharacter(std::string CharacterName); Client *FindCharacter(std::string CharacterName);
void CheckForStaleConnectionsAll();
void CheckForStaleConnections(Client *c); void CheckForStaleConnections(Client *c);
Client *IsCharacterOnline(std::string CharacterName); Client *IsCharacterOnline(std::string CharacterName);
void ProcessOPMailCommand(Client *c, std::string CommandString); void ProcessOPMailCommand(Client *c, std::string CommandString);

View File

@ -108,7 +108,7 @@ void Database::GetAccountStatus(Client *client)
{ {
std::string query = StringFormat( std::string query = StringFormat(
"SELECT `status`, `hideme`, `karma`, `revoked` FROM `account` WHERE `id` = '%i' LIMIT 1", "SELECT `status`, `hideme`, `karma`, `revoked` FROM `account` WHERE `id` = %i LIMIT 1",
client->GetAccountID() client->GetAccountID()
); );
@ -173,7 +173,7 @@ int Database::FindAccount(const char *characterName, Client *client)
query = StringFormat( query = StringFormat(
"SELECT `id`, `name`, `level` FROM `character_data` " "SELECT `id`, `name`, `level` FROM `character_data` "
"WHERE `account_id` = %i AND `name` != '%s'", "WHERE `account_id` = %i AND `name` != '%s' AND deleted_at is NULL",
accountID, characterName accountID, characterName
); );
@ -320,7 +320,7 @@ void Database::SendHeaders(Client *client)
int unknownField3 = 1; int unknownField3 = 1;
int characterID = FindCharacter(client->MailBoxName().c_str()); int characterID = FindCharacter(client->MailBoxName().c_str());
LogInfo("Sendheaders for [{}], CharID is [{}]", client->MailBoxName().c_str(), characterID); LogDebug("Sendheaders for [{}], CharID is [{}]", client->MailBoxName().c_str(), characterID);
if (characterID <= 0) { if (characterID <= 0) {
return; return;

View File

@ -70,17 +70,18 @@ int main() {
// Check every minute for unused channels we can delete // Check every minute for unused channels we can delete
// //
Timer ChannelListProcessTimer(60000); Timer ChannelListProcessTimer(60000);
Timer ClientConnectionPruneTimer(60000);
Timer InterserverTimer(INTERSERVER_TIMER); // does auto-reconnect Timer InterserverTimer(INTERSERVER_TIMER); // does auto-reconnect
LogInfo("Starting EQEmu Universal Chat Server"); LogInfo("Starting EQEmu Universal Chat Server");
if (!ucsconfig::LoadConfig()) { if (!ucsconfig::LoadConfig()) {
LogInfo("Loading server configuration failed"); LogInfo("Loading server configuration failed");
return 1; return 1;
} }
Config = ucsconfig::get(); Config = ucsconfig::get();
WorldShortName = Config->ShortName; WorldShortName = Config->ShortName;
@ -144,19 +145,26 @@ int main() {
worldserver = new WorldServer; worldserver = new WorldServer;
while(RunLoops) { auto loop_fn = [&](EQ::Timer* t) {
Timer::SetCurrentTime(); Timer::SetCurrentTime();
g_Clientlist->Process(); g_Clientlist->Process();
if(ChannelListProcessTimer.Check()) if (ChannelListProcessTimer.Check()) {
ChannelList->Process(); ChannelList->Process();
}
EQ::EventLoop::Get().Process(); if (ClientConnectionPruneTimer.Check()) {
g_Clientlist->CheckForStaleConnectionsAll();
}
Sleep(5); };
}
EQ::Timer process_timer(loop_fn);
process_timer.Start(32, true);
EQ::EventLoop::Get().Run();
ChannelList->RemoveAllChannels(); ChannelList->RemoveAllChannels();

View File

@ -61,7 +61,7 @@ void WorldServer::ProcessMessage(uint16 opcode, EQ::Net::Packet &p)
ServerPacket tpack(opcode, p); ServerPacket tpack(opcode, p);
ServerPacket *pack = &tpack; ServerPacket *pack = &tpack;
LogInfo("Received Opcode: {:#04x}", opcode); LogNetcode("Received Opcode: {:#04x}", opcode);
switch (opcode) switch (opcode)
{ {

View File

@ -52,6 +52,10 @@ if (-e "eqemu_server_skip_update.txt") {
$skip_self_update_check = 1; $skip_self_update_check = 1;
} }
if (-e "eqemu_server_skip_maps_update.txt") {
$skip_self_maps_update_check = 1;
}
#::: Check for script self update #::: Check for script self update
check_xml_to_json_conversion() if $ARGV[0] eq "convert_xml"; check_xml_to_json_conversion() if $ARGV[0] eq "convert_xml";
do_self_update_check_routine() if !$skip_self_update_check; do_self_update_check_routine() if !$skip_self_update_check;
@ -460,7 +464,7 @@ sub do_installer_routines {
get_remote_file($install_repository_request_url . "libmysql.dll", "libmysql.dll", 1); get_remote_file($install_repository_request_url . "libmysql.dll", "libmysql.dll", 1);
} }
map_files_fetch_bulk(); map_files_fetch_bulk() if !$skip_self_maps_update_check;
opcodes_fetch(); opcodes_fetch();
plugins_fetch(); plugins_fetch();
quest_files_fetch(); quest_files_fetch();
@ -533,7 +537,10 @@ sub check_for_world_bootup_database_update {
if ($binary_database_version == $local_database_version && $ARGV[0] eq "ran_from_world") { if ($binary_database_version == $local_database_version && $ARGV[0] eq "ran_from_world") {
print "[Update] Database up to date...\n"; print "[Update] Database up to date...\n";
exit; if (trim($db_version[2]) == 0) {
print "[Update] Continuing bootup\n";
exit;
}
} }
else { else {
#::: We ran world - Database needs to update, lets backup and run updates and continue world bootup #::: We ran world - Database needs to update, lets backup and run updates and continue world bootup
@ -1705,26 +1712,22 @@ sub fetch_server_dlls {
sub fetch_peq_db_full { sub fetch_peq_db_full {
print "[Install] Downloading latest PEQ Database... Please wait...\n"; print "[Install] Downloading latest PEQ Database... Please wait...\n";
get_remote_file("http://edit.projecteq.net/weekly/peq_beta.zip", "updates_staged/peq_beta.zip", 1); get_remote_file("http://db.projecteq.net/api/v1/dump/latest", "updates_staged/peq-latest.zip", 1);
print "[Install] Downloaded latest PEQ Database... Extracting...\n"; print "[Install] Downloaded latest PEQ Database... Extracting...\n";
unzip('updates_staged/peq_beta.zip', 'updates_staged/peq_db/'); unzip('updates_staged/peq-latest.zip', 'updates_staged/peq_db/');
my $start_dir = "updates_staged/peq_db"; my $start_dir = "updates_staged/peq_db/peq-dump";
find( find(
sub { push @files, $File::Find::name unless -d; }, sub { push @files, $File::Find::name unless -d; },
$start_dir $start_dir
); );
for my $file (@files) { for my $file (@files) {
$destination_file = $file; $destination_file = $file;
$destination_file =~ s/updates_staged\/peq_db\///g; $destination_file =~ s/updates_staged\/peq_db\/peq-dump\///g;
if ($file =~ /peqbeta|player_tables/i) { if ($file =~ /create_tables_content|create_tables_login|create_tables_player|create_tables_queryserv|create_tables_state|create_tables_system/i) {
print "[Install] DB :: Installing :: " . $destination_file . "\n"; print "[Install] DB :: Installing :: " . $destination_file . "\n";
get_mysql_result_from_file($file); get_mysql_result_from_file($file);
} }
} }
#::: PEQ DB baseline version
print get_mysql_result("DELETE FROM db_version");
print get_mysql_result("INSERT INTO `db_version` (`version`) VALUES (9130);");
} }
sub map_files_fetch_bulk { sub map_files_fetch_bulk {

View File

@ -1,57 +0,0 @@
account
account_ip
account_flags
account_rewards
adventure_details
adventure_stats
buyer
char_recipe_list
character_activities
character_alt_currency
character_alternate_abilities
character_auras
character_bandolier
character_bind
character_buffs
character_corpse_items
character_corpses
character_currency
character_data
character_disciplines
character_enabledtasks
character_inspect_messages
character_item_recast
character_languages
character_leadership_abilities
character_material
character_memmed_spells
character_pet_buffs
character_pet_info
character_pet_inventory
character_potionbelt
character_skills
character_spells
character_tasks
character_tribute
completed_tasks
data_buckets
faction_values
friends
guild_bank
guild_members
guild_ranks
guild_relations
guilds
instance_list_player
inventory
inventory_snapshots
keyring
mail
player_titlesets
quest_globals
sharedbank
timers
titles
trader
trader_audit
zone_flags"

View File

@ -1,6 +0,0 @@
command_settings
inventory_versions
launcher
rule_sets
rule_values
variables

View File

@ -405,6 +405,7 @@
9149|2020_02_06_globalloot.sql|SHOW COLUMNS FROM `global_loot` LIKE 'hot_zone'|empty| 9149|2020_02_06_globalloot.sql|SHOW COLUMNS FROM `global_loot` LIKE 'hot_zone'|empty|
9150|2020_02_06_aa_reset_on_death.sql|SHOW COLUMNS FROM `aa_ability` LIKE 'reset_on_death'|empty| 9150|2020_02_06_aa_reset_on_death.sql|SHOW COLUMNS FROM `aa_ability` LIKE 'reset_on_death'|empty|
9151|2020_03_05_npc_always_aggro.sql|SHOW COLUMNS FROM `npc_types` LIKE 'always_aggro'|empty| 9151|2020_03_05_npc_always_aggro.sql|SHOW COLUMNS FROM `npc_types` LIKE 'always_aggro'|empty|
9152|2020_03_09_convert_myisam_to_innodb.sql|SELECT * FROM db_version WHERE version >= 9152|empty|
# Upgrade conditions: # Upgrade conditions:
# This won't be needed after this system is implemented, but it is used database that are not # This won't be needed after this system is implemented, but it is used database that are not

View File

@ -25,6 +25,7 @@
9024|2019_06_27_bots_pet_get_lost.sql|SELECT `bot_command` FROM `bot_command_settings` WHERE `bot_command` LIKE 'petgetlost'|empty| 9024|2019_06_27_bots_pet_get_lost.sql|SELECT `bot_command` FROM `bot_command_settings` WHERE `bot_command` LIKE 'petgetlost'|empty|
9025|2019_08_26_bots_owner_option_spawn_message.sql|SELECT * FROM db_version WHERE bots_version >= 9025|empty| 9025|2019_08_26_bots_owner_option_spawn_message.sql|SELECT * FROM db_version WHERE bots_version >= 9025|empty|
9026|2019_09_09_bots_owner_options_rework.sql|SHOW COLUMNS FROM `bot_owner_options` LIKE 'option_type'|empty| 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|
# Upgrade conditions: # Upgrade conditions:
# This won't be needed after this system is implemented, but it is used database that are not # This won't be needed after this system is implemented, but it is used database that are not

View File

@ -0,0 +1,24 @@
DROP VIEW IF EXISTS `vw_bot_character_mobs`;
-- Views
CREATE VIEW `vw_bot_character_mobs` AS
SELECT
_utf8'C' AS mob_type,
c.`id`,
c.`name`,
c.`class`,
c.`level`,
c.`last_login`,
c.`zone_id`,
c.`deleted_at`
FROM `character_data` AS c
UNION ALL
SELECT _utf8'B' AS mob_type,
b.`bot_id` AS id,
b.`name`,
b.`class`,
b.`level`,
b.`last_spawn` AS last_login,
b.`zone_id`,
NULL AS `deleted_at`
FROM `bot_data` AS b;

View File

@ -0,0 +1,95 @@
ALTER TABLE `account_flags` ENGINE=InnoDB;
ALTER TABLE `account_ip` ENGINE=InnoDB;
ALTER TABLE `account` ENGINE=InnoDB;
ALTER TABLE `adventure_template_entry_flavor` ENGINE=InnoDB;
ALTER TABLE `adventure_template_entry` ENGINE=InnoDB;
ALTER TABLE `altadv_vars` ENGINE=InnoDB;
ALTER TABLE `alternate_currency` ENGINE=InnoDB;
ALTER TABLE `banned_ips` ENGINE=InnoDB;
ALTER TABLE `base_data` ENGINE=InnoDB;
ALTER TABLE `blocked_spells` ENGINE=InnoDB;
ALTER TABLE `buyer` ENGINE=InnoDB;
ALTER TABLE `char_create_combinations` ENGINE=InnoDB;
ALTER TABLE `char_create_point_allocations` ENGINE=InnoDB;
ALTER TABLE `character_activities` ENGINE=InnoDB;
ALTER TABLE `character_enabledtasks` ENGINE=InnoDB;
ALTER TABLE `character_tasks` ENGINE=InnoDB;
ALTER TABLE `chatchannels` ENGINE=InnoDB;
ALTER TABLE `completed_tasks` ENGINE=InnoDB;
ALTER TABLE `damageshieldtypes` ENGINE=InnoDB;
ALTER TABLE `discovered_items` ENGINE=InnoDB;
ALTER TABLE `eqtime` ENGINE=InnoDB;
ALTER TABLE `eventlog` ENGINE=InnoDB;
ALTER TABLE `faction_list_mod` ENGINE=InnoDB;
ALTER TABLE `faction_list` ENGINE=InnoDB;
ALTER TABLE `faction_values` ENGINE=InnoDB;
ALTER TABLE `friends` ENGINE=InnoDB;
ALTER TABLE `goallists` ENGINE=InnoDB;
ALTER TABLE `guild_bank` ENGINE=InnoDB;
ALTER TABLE `guild_members` ENGINE=InnoDB;
ALTER TABLE `guild_ranks` ENGINE=InnoDB;
ALTER TABLE `guild_relations` ENGINE=InnoDB;
ALTER TABLE `guilds` ENGINE=InnoDB;
ALTER TABLE `hackers` ENGINE=InnoDB;
ALTER TABLE `horses` ENGINE=InnoDB;
ALTER TABLE `inventory_versions` ENGINE=InnoDB;
ALTER TABLE `item_tick` ENGINE=InnoDB;
ALTER TABLE `items` ENGINE=InnoDB;
ALTER TABLE `keyring` ENGINE=InnoDB;
ALTER TABLE `launcher_zones` ENGINE=InnoDB;
ALTER TABLE `launcher` ENGINE=InnoDB;
ALTER TABLE `ldon_trap_entries` ENGINE=InnoDB;
ALTER TABLE `ldon_trap_templates` ENGINE=InnoDB;
ALTER TABLE `lfguild` ENGINE=InnoDB;
ALTER TABLE `lootdrop_entries` ENGINE=InnoDB;
ALTER TABLE `lootdrop` ENGINE=InnoDB;
ALTER TABLE `loottable_entries` ENGINE=InnoDB;
ALTER TABLE `loottable` ENGINE=InnoDB;
ALTER TABLE `mail` ENGINE=InnoDB;
ALTER TABLE `merc_armorinfo` ENGINE=InnoDB;
ALTER TABLE `merc_buffs` ENGINE=InnoDB;
ALTER TABLE `merc_inventory` ENGINE=InnoDB;
ALTER TABLE `merc_merchant_entries` ENGINE=InnoDB;
ALTER TABLE `merc_merchant_template_entries` ENGINE=InnoDB;
ALTER TABLE `merc_merchant_templates` ENGINE=InnoDB;
ALTER TABLE `merc_name_types` ENGINE=InnoDB;
ALTER TABLE `merc_npc_types` ENGINE=InnoDB;
ALTER TABLE `merc_spell_list_entries` ENGINE=InnoDB;
ALTER TABLE `merc_spell_lists` ENGINE=InnoDB;
ALTER TABLE `merc_stance_entries` ENGINE=InnoDB;
ALTER TABLE `merc_stats` ENGINE=InnoDB;
ALTER TABLE `merc_subtypes` ENGINE=InnoDB;
ALTER TABLE `merc_templates` ENGINE=InnoDB;
ALTER TABLE `merc_types` ENGINE=InnoDB;
ALTER TABLE `merc_weaponinfo` ENGINE=InnoDB;
ALTER TABLE `mercs` ENGINE=InnoDB;
ALTER TABLE `name_filter` ENGINE=InnoDB;
ALTER TABLE `npc_types` ENGINE=InnoDB;
ALTER TABLE `object_contents` ENGINE=InnoDB;
ALTER TABLE `petitions` ENGINE=InnoDB;
ALTER TABLE `pets_equipmentset_entries` ENGINE=InnoDB;
ALTER TABLE `pets_equipmentset` ENGINE=InnoDB;
ALTER TABLE `player_titlesets` ENGINE=InnoDB;
ALTER TABLE `proximities` ENGINE=InnoDB;
ALTER TABLE `races` ENGINE=InnoDB;
ALTER TABLE `raid_details` ENGINE=InnoDB;
ALTER TABLE `raid_leaders` ENGINE=InnoDB;
ALTER TABLE `raid_members` ENGINE=InnoDB;
ALTER TABLE `rule_sets` ENGINE=InnoDB;
ALTER TABLE `rule_values` ENGINE=InnoDB;
ALTER TABLE `saylink` ENGINE=InnoDB;
ALTER TABLE `sharedbank` ENGINE=InnoDB;
ALTER TABLE `skill_caps` ENGINE=InnoDB;
ALTER TABLE `spell_globals` ENGINE=InnoDB;
ALTER TABLE `spells_new` ENGINE=InnoDB;
ALTER TABLE `task_activities` ENGINE=InnoDB;
ALTER TABLE `tasks` ENGINE=InnoDB;
ALTER TABLE `tasksets` ENGINE=InnoDB;
ALTER TABLE `timers` ENGINE=InnoDB;
ALTER TABLE `titles` ENGINE=InnoDB;
ALTER TABLE `trader_audit` ENGINE=InnoDB;
ALTER TABLE `trader` ENGINE=InnoDB;
ALTER TABLE `tradeskill_recipe_entries` ENGINE=InnoDB;
ALTER TABLE `tradeskill_recipe` ENGINE=InnoDB;
ALTER TABLE `variables` ENGINE=InnoDB;
ALTER TABLE `veteran_reward_templates` ENGINE=InnoDB;

71
utils/sql/peq-dump/peq-dump.sh Executable file
View File

@ -0,0 +1,71 @@
#!/usr/bin/env bash
# Run from the context of server directory
world_path=""
#############################################
# world path
#############################################
if [ -d "bin" ]
then
world_path="bin/"
fi
world_bin="${world_path}world"
echo "World path is [$world_path] bin is [$world_bin]"
#############################################
# dump
#############################################
dump_path=/tmp/peq-dump/
echo "Generating dump path [${dump_path}]"
rm -rf ${dump_path}
mkdir -p ${dump_path}
#############################################
# generate "drop_" table files
#############################################
echo "Generating [drop_*] table exports..."
bash -c "${world_bin} database:dump --content-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_content.sql"
bash -c "${world_bin} database:dump --login-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_login.sql"
bash -c "${world_bin} database:dump --player-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_player.sql"
bash -c "${world_bin} database:dump --system-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_system.sql"
bash -c "${world_bin} database:dump --state-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_state.sql"
bash -c "${world_bin} database:dump --query-serv-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_queryserv.sql"
#############################################
# generate "create_" table files
#############################################
echo "Generating [create_*] table exports..."
# structure only
bash -c "${world_bin} database:dump --login-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_login.sql"
bash -c "${world_bin} database:dump --player-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_player.sql"
bash -c "${world_bin} database:dump --state-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_state.sql"
echo 'REPLACE INTO `instance_list` VALUES (1,25,1,1,0,0,1),(2,25,2,1,0,0,1),(3,151,1,1,0,0,1),(4,114,1,1,0,0,1),(5,344,1,1,0,0,1),(6,202,0,1,0,0,1);' >> "${dump_path}create_tables_state.sql"
bash -c "${world_bin} database:dump --query-serv-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_queryserv.sql"
# with content
bash -c "${world_bin} database:dump --content-tables --dump-output-to-console > ${dump_path}create_tables_content.sql"
bash -c "${world_bin} database:dump --system-tables --dump-output-to-console > ${dump_path}create_tables_system.sql"
#############################################
# "all" exports
#############################################
bash -c "cd ${dump_path} && ls * | grep create | sed 's/.*/source &;/' > create_all_tables.sql"
bash -c "cd ${dump_path} && ls * | grep drop | sed 's/.*/source &;/' > drop_all_tables.sql"
#############################################
# zip
#############################################
human_date=$(date +"%B-%d-%Y" | tr '[:upper:]' '[:lower:]')
echo "Compressing..."
bash -c "cd /tmp/ && rm -rf peq-latest.zip && zip peq-latest.zip peq-dump/* && mv ${dump_path}peq-latest.zip /tmp/peq-latest.zip"
echo "Cleaning up..."
rm -rf ${dump_path}
echo "Dump located [/tmp/peq-latest.zip]"

View File

@ -1,113 +0,0 @@
aa_ability
aa_actions
aa_effects
aa_rank_effects
aa_rank_prereqs
aa_ranks
aa_required_level_cost
adventure_template
adventure_template_entry
adventure_template_entry_flavor
altadv_vars
alternate_currency
auras
base_data
blocked_spells
books
bug_reports
char_create_combinations
char_create_point_allocations
class_skill
damageshieldtypes
data_buckets
db_str
doors
eqtime
faction_base_data
faction_list
faction_list_mod
fear_hints
fishing
forage
global_loot
goallists
graveyard
grid
grid_entries
ground_spawns
horses
instance_list
items
ip_exemptions
ldon_trap_entries
ldon_trap_templates
level_exp_mods
logsys_categories
lootdrop
lootdrop_entries
loottable
loottable_entries
merc_armorinfo
merc_buffs
merc_inventory
merc_merchant_entries
merc_merchant_template_entries
merc_merchant_templates
merc_name_types
merc_npc_types
merc_spell_list_entries
merc_spell_lists
merc_stance_entries
merc_stats
merc_subtypes
merc_templates
merc_types
merc_weaponinfo
merchantlist
mercs
name_filter
npc_emotes
npc_faction
npc_faction_entries
npc_scale_global_base
npc_spells
npc_spells_effects
npc_spells_effects_entries
npc_spells_entries
npc_types
npc_types_metadata
npc_types_tint
object
perl_event_export_settings
pets
pets_equipmentset
pets_equipmentset_entries
profanity_list
proximities
races
saylink
skill_caps
spawn2
spawn_condition_values
spawn_conditions
spawn_events
spawnentry
spawngroup
spells_new
start_zones
starting_items
task_activities
tasks
tasksets
titles
tradeskill_recipe
tradeskill_recipe_entries
traps
tribute_levels
tributes
veteran_reward_templates
zone
zone_points
zone_server
zone_state_dump
zoneserver_auth

View File

@ -1,94 +0,0 @@
aa_timers
account
account_flags
account_ip
account_rewards
adventure_details
adventure_members
adventure_stats
banned_ips
bugs
buyer
char_recipe_list
character_activities
character_alt_currency
character_alternate_abilities
character_auras
character_bandolier
character_bind
character_buffs
character_corpse_items
character_corpses
character_currency
character_data
character_disciplines
character_enabledtasks
character_inspect_messages
character_item_recast
character_languages
character_leadership_abilities
character_material
character_memmed_spells
character_pet_buffs
character_pet_info
character_pet_inventory
character_potionbelt
character_skills
character_spells
character_tasks
character_tribute
chatchannels
completed_tasks
discovered_items
eventlog
faction_values
friends
gm_ips
group_id
group_leaders
guild_bank
guild_members
guild_ranks
guild_relations
guilds
hackers
instance_list_player
inventory
inventory_snapshots
item_tick
keyring
launcher_zones
lfguild
mail
merchantlist_temp
object_contents
petitions
player_titlesets
qs_merchant_transaction_record
qs_merchant_transaction_record_entries
qs_player_aa_rate_hourly
qs_player_delete_record
qs_player_delete_record_entries
qs_player_events
qs_player_handin_record
qs_player_handin_record_entries
qs_player_move_record
qs_player_move_record_entries
qs_player_npc_kill_record
qs_player_npc_kill_record_entries
qs_player_speech
qs_player_trade_record
qs_player_trade_record_entries
quest_globals
raid_details
raid_leaders
raid_members
reports
respawn_times
sharedbank
spell_buckets
spell_globals
timers
trader
trader_audit
zone_flags

View File

@ -714,7 +714,7 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
EQApplicationPacket *outapp; EQApplicationPacket *outapp;
uint32 tmpaccid = 0; uint32 tmpaccid = 0;
charid = database.GetCharacterInfo(char_name, &tmpaccid, &zone_id, &instance_id); charid = database.GetCharacterInfo(char_name, &tmpaccid, &zone_id, &instance_id);
if (charid == 0 || tmpaccid != GetAccountID()) { if (charid == 0) {
LogInfo("Could not get CharInfo for [{}]", char_name); LogInfo("Could not get CharInfo for [{}]", char_name);
eqs->Close(); eqs->Close();
return true; return true;

View File

@ -415,6 +415,7 @@ int main(int argc, char** argv) {
RegisterConsoleFunctions(console); RegisterConsoleFunctions(console);
} }
zoneserver_list.Init();
std::unique_ptr<EQ::Net::ServertalkServer> server_connection; std::unique_ptr<EQ::Net::ServertalkServer> server_connection;
server_connection.reset(new EQ::Net::ServertalkServer()); server_connection.reset(new EQ::Net::ServertalkServer());

View File

@ -6,29 +6,38 @@
#include "../common/misc_functions.h" #include "../common/misc_functions.h"
#include "../common/md5.h" #include "../common/md5.h"
#include "../common/packet_dump.h" #include "../common/packet_dump.h"
#include "../common/event/timer.h"
UCSConnection::UCSConnection() UCSConnection::UCSConnection()
{ {
Stream = 0; connection = 0;
} }
void UCSConnection::SetConnection(std::shared_ptr<EQ::Net::ServertalkServerConnection> inStream) void UCSConnection::SetConnection(std::shared_ptr<EQ::Net::ServertalkServerConnection> inStream)
{ {
if (Stream && Stream->Handle()) if (inStream && connection && connection->Handle()) {
{
LogInfo("Incoming UCS Connection while we were already connected to a UCS"); LogInfo("Incoming UCS Connection while we were already connected to a UCS");
Stream->Handle()->Disconnect(); connection->Handle()->Disconnect();
}
connection = inStream;
if (connection) {
connection->OnMessage(
std::bind(
&UCSConnection::ProcessPacket,
this,
std::placeholders::_1,
std::placeholders::_2
)
);
} }
Stream = inStream; m_keepalive.reset(new EQ::Timer(5000, true, std::bind(&UCSConnection::OnKeepAlive, this, std::placeholders::_1)));
if (Stream) {
Stream->OnMessage(std::bind(&UCSConnection::ProcessPacket, this, std::placeholders::_1, std::placeholders::_2));
}
} }
void UCSConnection::ProcessPacket(uint16 opcode, EQ::Net::Packet &p) void UCSConnection::ProcessPacket(uint16 opcode, EQ::Net::Packet &p)
{ {
if (!Stream) if (!connection)
return; return;
ServerPacket tpack(opcode, p); ServerPacket tpack(opcode, p);
@ -60,10 +69,10 @@ void UCSConnection::ProcessPacket(uint16 opcode, EQ::Net::Packet &p)
void UCSConnection::SendPacket(ServerPacket* pack) void UCSConnection::SendPacket(ServerPacket* pack)
{ {
if (!Stream) if (!connection)
return; return;
Stream->SendPacket(pack); connection->SendPacket(pack);
} }
void UCSConnection::SendMessage(const char *From, const char *Message) void UCSConnection::SendMessage(const char *From, const char *Message)
@ -78,3 +87,13 @@ void UCSConnection::SendMessage(const char *From, const char *Message)
SendPacket(pack); SendPacket(pack);
safe_delete(pack); safe_delete(pack);
} }
void UCSConnection::OnKeepAlive(EQ::Timer *t)
{
if (!connection) {
return;
}
ServerPacket pack(ServerOP_KeepAlive, 0);
connection->SendPacket(&pack);
}

View File

@ -4,6 +4,7 @@
#include "../common/types.h" #include "../common/types.h"
#include "../common/net/servertalk_server_connection.h" #include "../common/net/servertalk_server_connection.h"
#include "../common/servertalk.h" #include "../common/servertalk.h"
#include "../common/event/timer.h"
#include <memory> #include <memory>
class UCSConnection class UCSConnection
@ -13,11 +14,17 @@ public:
void SetConnection(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection); void SetConnection(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection);
void ProcessPacket(uint16 opcode, EQ::Net::Packet &p); void ProcessPacket(uint16 opcode, EQ::Net::Packet &p);
void SendPacket(ServerPacket* pack); void SendPacket(ServerPacket* pack);
void Disconnect() { if(Stream && Stream->Handle()) Stream->Handle()->Disconnect(); } void Disconnect() { if(connection && connection->Handle()) connection->Handle()->Disconnect(); }
void SendMessage(const char *From, const char *Message); void SendMessage(const char *From, const char *Message);
private: private:
inline std::string GetIP() const { return (Stream && Stream->Handle()) ? Stream->Handle()->RemoteIP() : 0; } inline std::string GetIP() const { return (connection && connection->Handle()) ? connection->Handle()->RemoteIP() : 0; }
std::shared_ptr<EQ::Net::ServertalkServerConnection> Stream; std::shared_ptr<EQ::Net::ServertalkServerConnection> connection;
/**
* Keepalive
*/
std::unique_ptr<EQ::Timer> m_keepalive;
void OnKeepAlive(EQ::Timer *t);
}; };
#endif /*UCS_H_*/ #endif /*UCS_H_*/

View File

@ -24,6 +24,7 @@
#include "../common/version.h" #include "../common/version.h"
#include "worlddb.h" #include "worlddb.h"
#include "../common/database_schema.h" #include "../common/database_schema.h"
#include "../common/database/database_dump_service.h"
namespace WorldserverCommandHandler { namespace WorldserverCommandHandler {
@ -51,6 +52,7 @@ namespace WorldserverCommandHandler {
function_map["database:version"] = &WorldserverCommandHandler::DatabaseVersion; function_map["database:version"] = &WorldserverCommandHandler::DatabaseVersion;
function_map["database:set-account-status"] = &WorldserverCommandHandler::DatabaseSetAccountStatus; function_map["database:set-account-status"] = &WorldserverCommandHandler::DatabaseSetAccountStatus;
function_map["database:schema"] = &WorldserverCommandHandler::DatabaseGetSchema; function_map["database:schema"] = &WorldserverCommandHandler::DatabaseGetSchema;
function_map["database:dump"] = &WorldserverCommandHandler::DatabaseDump;
EQEmuCommand::HandleMenu(function_map, cmd, argc, argv); EQEmuCommand::HandleMenu(function_map, cmd, argc, argv);
} }
@ -145,7 +147,7 @@ namespace WorldserverCommandHandler {
*/ */
void DatabaseGetSchema(int argc, char **argv, argh::parser &cmd, std::string &description) void DatabaseGetSchema(int argc, char **argv, argh::parser &cmd, std::string &description)
{ {
description = "Displays server database schema"; description = "Displays server database schema";
if (cmd[{"-h", "--help"}]) { if (cmd[{"-h", "--help"}]) {
return; return;
@ -202,4 +204,71 @@ namespace WorldserverCommandHandler {
std::cout << payload.str() << std::endl; std::cout << payload.str() << std::endl;
} }
/**
* @param argc
* @param argv
* @param cmd
* @param description
*/
void DatabaseDump(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Dumps server database tables";
if (cmd[{"-h", "--help"}]) {
return;
}
std::vector<std::string> arguments = {};
std::vector<std::string> options = {
"--all",
"--content-tables",
"--login-tables",
"--player-tables",
"--state-tables",
"--system-tables",
"--query-serv-tables",
"--table-structure-only",
"--table-lock",
"--dump-path=",
"--dump-output-to-console",
"--drop-table-syntax-only",
"--compress"
};
if (argc < 3) {
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
return;
}
auto database_dump_service = new DatabaseDumpService();
bool dump_all = cmd[{"-a", "--all"}];
if (!cmd("--dump-path").str().empty()) {
database_dump_service->SetDumpPath(cmd("--dump-path").str());
}
/**
* Set Option
*/
database_dump_service->SetDumpContentTables(cmd[{"--content-tables"}] || dump_all);
database_dump_service->SetDumpLoginServerTables(cmd[{"--login-tables"}] || dump_all);
database_dump_service->SetDumpPlayerTables(cmd[{"--player-tables"}] || dump_all);
database_dump_service->SetDumpStateTables(cmd[{"--state-tables"}] || dump_all);
database_dump_service->SetDumpSystemTables(cmd[{"--system-tables"}] || dump_all);
database_dump_service->SetDumpQueryServerTables(cmd[{"--query-serv-tables"}] || dump_all);
database_dump_service->SetDumpAllTables(dump_all);
database_dump_service->SetDumpWithNoData(cmd[{"--table-structure-only"}]);
database_dump_service->SetDumpTableLock(cmd[{"--table-lock"}]);
database_dump_service->SetDumpWithCompression(cmd[{"--compress"}]);
database_dump_service->SetDumpOutputToConsole(cmd[{"--dump-output-to-console"}]);
database_dump_service->SetDumpDropTableSyntaxOnly(cmd[{"--drop-table-syntax-only"}]);
/**
* Dump
*/
database_dump_service->Dump();
}
} }

View File

@ -30,6 +30,7 @@ namespace WorldserverCommandHandler {
void DatabaseVersion(int argc, char **argv, argh::parser &cmd, std::string &description); void DatabaseVersion(int argc, char **argv, argh::parser &cmd, std::string &description);
void DatabaseSetAccountStatus(int argc, char **argv, argh::parser &cmd, std::string &description); void DatabaseSetAccountStatus(int argc, char **argv, argh::parser &cmd, std::string &description);
void DatabaseGetSchema(int argc, char **argv, argh::parser &cmd, std::string &description); void DatabaseGetSchema(int argc, char **argv, argh::parser &cmd, std::string &description);
void DatabaseDump(int argc, char **argv, argh::parser &cmd, std::string &description);
}; };

View File

@ -39,7 +39,6 @@ ZSList::ZSList()
{ {
NextID = 1; NextID = 1;
CurGroupID = 1; CurGroupID = 1;
LastAllocatedPort = 0;
memset(pLockedZones, 0, sizeof(pLockedZones)); memset(pLockedZones, 0, sizeof(pLockedZones));
m_tick.reset(new EQ::Timer(5000, true, std::bind(&ZSList::OnTick, this, std::placeholders::_1))); m_tick.reset(new EQ::Timer(5000, true, std::bind(&ZSList::OnTick, this, std::placeholders::_1)));
@ -76,7 +75,12 @@ void ZSList::Remove(const std::string &uuid)
auto iter = zone_server_list.begin(); auto iter = zone_server_list.begin();
while (iter != zone_server_list.end()) { while (iter != zone_server_list.end()) {
if ((*iter)->GetUUID().compare(uuid) == 0) { if ((*iter)->GetUUID().compare(uuid) == 0) {
auto port = (*iter)->GetCPort();
zone_server_list.erase(iter); zone_server_list.erase(iter);
if (port != 0) {
m_ports_free.push_back(port);
}
return; return;
} }
iter++; iter++;
@ -239,6 +243,14 @@ bool ZSList::SetLockedZone(uint16 iZoneID, bool iLock) {
return false; return false;
} }
void ZSList::Init()
{
const WorldConfig* Config = WorldConfig::get();
for (uint16 i = Config->ZonePortLow; i <= Config->ZonePortHigh; ++i) {
m_ports_free.push_back(i);
}
}
bool ZSList::IsZoneLocked(uint16 iZoneID) { bool ZSList::IsZoneLocked(uint16 iZoneID) {
for (auto &zone : pLockedZones) { for (auto &zone : pLockedZones) {
if (zone == iZoneID) if (zone == iZoneID)
@ -577,30 +589,15 @@ void ZSList::RebootZone(const char* ip1, uint16 port, const char* ip2, uint32 sk
safe_delete_array(tmp); safe_delete_array(tmp);
} }
uint16 ZSList::GetAvailableZonePort() uint16 ZSList::GetAvailableZonePort()
{ {
const WorldConfig *Config = WorldConfig::get(); if (m_ports_free.empty()) {
int i; return 0;
uint16 port = 0;
if (LastAllocatedPort == 0)
i = Config->ZonePortLow;
else
i = LastAllocatedPort + 1;
while (i != LastAllocatedPort && port == 0) {
if (i>Config->ZonePortHigh)
i = Config->ZonePortLow;
if (!FindByPort(i)) {
port = i;
break;
}
i++;
} }
LastAllocatedPort = port;
return port; auto first = m_ports_free.front();
m_ports_free.pop_front();
return first;
} }
uint32 ZSList::TriggerBootup(uint32 iZoneID, uint32 iInstanceID) { uint32 ZSList::TriggerBootup(uint32 iZoneID, uint32 iInstanceID) {

View File

@ -7,6 +7,7 @@
#include "../common/event/timer.h" #include "../common/event/timer.h"
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <deque>
class WorldTCPConnection; class WorldTCPConnection;
class ServerPacket; class ServerPacket;
@ -22,6 +23,7 @@ public:
ZSList(); ZSList();
~ZSList(); ~ZSList();
void Init();
bool IsZoneLocked(uint16 iZoneID); bool IsZoneLocked(uint16 iZoneID);
bool SendPacket(ServerPacket *pack); bool SendPacket(ServerPacket *pack);
bool SendPacket(uint32 zoneid, ServerPacket *pack); bool SendPacket(uint32 zoneid, ServerPacket *pack);
@ -73,8 +75,7 @@ private:
uint32 NextID; uint32 NextID;
uint16 pLockedZones[MaxLockedZones]; uint16 pLockedZones[MaxLockedZones];
uint32 CurGroupID; uint32 CurGroupID;
uint16 LastAllocatedPort; std::deque<uint16> m_ports_free;
std::unique_ptr<EQ::Timer> m_tick; std::unique_ptr<EQ::Timer> m_tick;
std::unique_ptr<EQ::Timer> m_keepalive; std::unique_ptr<EQ::Timer> m_keepalive;

View File

@ -32,6 +32,7 @@
#endif #endif
#include "map.h" #include "map.h"
#include "water_map.h"
extern Zone* zone; extern Zone* zone;
//#define LOSDEBUG 6 //#define LOSDEBUG 6
@ -237,6 +238,11 @@ bool Mob::CheckWillAggro(Mob *mob) {
if (!mob->CastToClient()->ClientFinishedLoading() || mob->CastToClient()->IsHoveringForRespawn() || mob->CastToClient()->bZoning) if (!mob->CastToClient()->ClientFinishedLoading() || mob->CastToClient()->IsHoveringForRespawn() || mob->CastToClient()->bZoning)
return false; return false;
} }
// We don't want to aggro clients outside of water if we're water only.
if (mob->IsClient() && mob->CastToClient()->GetLastRegion() != RegionTypeWater && IsUnderwaterOnly()) {
return false;
}
/** /**
* Pets shouldn't scan for aggro * Pets shouldn't scan for aggro

View File

@ -256,6 +256,7 @@ Client::Client(EQStreamInterface* ieqs)
TotalSecondsPlayed = 0; TotalSecondsPlayed = 0;
keyring.clear(); keyring.clear();
bind_sight_target = nullptr; bind_sight_target = nullptr;
p_raid_instance = nullptr;
mercid = 0; mercid = 0;
mercSlot = 0; mercSlot = 0;
InitializeMercInfo(); InitializeMercInfo();
@ -1918,7 +1919,7 @@ void Client::CheckManaEndUpdate() {
else if (group) { else if (group) {
group->SendEndurancePacketFrom(this); group->SendEndurancePacketFrom(this);
} }
auto endurance_packet = new EQApplicationPacket(OP_EnduranceUpdate, sizeof(EnduranceUpdate_Struct)); auto endurance_packet = new EQApplicationPacket(OP_EnduranceUpdate, sizeof(EnduranceUpdate_Struct));
EnduranceUpdate_Struct* endurance_update = (EnduranceUpdate_Struct*)endurance_packet->pBuffer; EnduranceUpdate_Struct* endurance_update = (EnduranceUpdate_Struct*)endurance_packet->pBuffer;
endurance_update->cur_end = GetEndurance(); endurance_update->cur_end = GetEndurance();
@ -8757,6 +8758,11 @@ void Client::CheckRegionTypeChanges()
if (last_region_type == new_region) if (last_region_type == new_region)
return; return;
// If we got out of water clear any water aggro for water only npcs
if (last_region_type == RegionTypeWater) {
entity_list.ClearWaterAggro(this);
}
// region type changed // region type changed
last_region_type = new_region; last_region_type = new_region;
@ -9198,7 +9204,7 @@ void Client::SetSecondaryWeaponOrnamentation(uint32 model_id)
secondary_item->SetOrnamentationIDFile(model_id); secondary_item->SetOrnamentationIDFile(model_id);
SendItemPacket(EQEmu::invslot::slotSecondary, secondary_item, ItemPacketTrade); SendItemPacket(EQEmu::invslot::slotSecondary, secondary_item, ItemPacketTrade);
WearChange(EQEmu::textures::weaponSecondary, static_cast<uint16>(model_id), 0); WearChange(EQEmu::textures::weaponSecondary, static_cast<uint16>(model_id), 0);
Message(Chat::Yellow, "Your secondary weapon appearance has been modified"); Message(Chat::Yellow, "Your secondary weapon appearance has been modified");
} }
} }
@ -9287,3 +9293,41 @@ void Client::SetBotOption(BotOwnerOption boo, bool flag) {
} }
#endif #endif
void Client::SendToGuildHall()
{
std::string zone_short_name = "guildhall";
uint32 zone_id = database.GetZoneID(zone_short_name.c_str());
if (zone_id == 0) {
return;
}
uint32 expiration_time = (RuleI(Instances, GuildHallExpirationDays) * 86400);
uint16 instance_id = 0;
std::string guild_hall_instance_key = fmt::format("guild-hall-instance-{}", GuildID());
std::string instance_data = DataBucket::GetData(guild_hall_instance_key);
if (!instance_data.empty() && std::stoi(instance_data) > 0) {
instance_id = std::stoi(instance_data);
}
if (instance_id <= 0) {
if (!database.GetUnusedInstanceID(instance_id)) {
Message(Chat::Red, "Server was unable to find a free instance id.");
return;
}
if (!database.CreateInstance(instance_id, zone_id, 1, expiration_time)) {
Message(Chat::Red, "Server was unable to create a new instance.");
return;
}
DataBucket::SetData(
guild_hall_instance_key,
std::to_string(instance_id),
std::to_string(expiration_time)
);
}
AssignToInstance(instance_id);
MovePC(345, instance_id, -1.00, -1.00, 3.34, 0, 1);
}

View File

@ -633,6 +633,7 @@ public:
void MovePC(uint32 zoneID, float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited); void MovePC(uint32 zoneID, float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited);
void MovePC(float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited); void MovePC(float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited);
void MovePC(uint32 zoneID, uint32 instanceID, float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited); void MovePC(uint32 zoneID, uint32 instanceID, float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited);
void SendToGuildHall();
void AssignToInstance(uint16 instance_id); void AssignToInstance(uint16 instance_id);
void RemoveFromInstance(uint16 instance_id); void RemoveFromInstance(uint16 instance_id);
void WhoAll(); void WhoAll();
@ -691,7 +692,7 @@ public:
int GetClientMaxLevel() const { return client_max_level; } int GetClientMaxLevel() const { return client_max_level; }
void SetClientMaxLevel(int max_level) { client_max_level = max_level; } void SetClientMaxLevel(int max_level) { client_max_level = max_level; }
void CheckManaEndUpdate(); void CheckManaEndUpdate();
void SendManaUpdate(); void SendManaUpdate();
void SendEnduranceUpdate(); void SendEnduranceUpdate();
@ -1294,6 +1295,8 @@ public:
void CheckRegionTypeChanges(); void CheckRegionTypeChanges();
WaterRegionType GetLastRegion() { return last_region_type; }
int32 CalcATK(); int32 CalcATK();
uint32 trapid; //ID of trap player has triggered. This is cleared when the player leaves the trap's radius, or it despawns. uint32 trapid; //ID of trap player has triggered. This is cleared when the player leaves the trap's radius, or it despawns.
@ -1301,6 +1304,8 @@ public:
void SetLastPositionBeforeBulkUpdate(glm::vec4 in_last_position_before_bulk_update); void SetLastPositionBeforeBulkUpdate(glm::vec4 in_last_position_before_bulk_update);
glm::vec4 &GetLastPositionBeforeBulkUpdate(); glm::vec4 &GetLastPositionBeforeBulkUpdate();
Raid *p_raid_instance;
protected: protected:
friend class Mob; friend class Mob;
void CalcItemBonuses(StatBonuses* newbon); void CalcItemBonuses(StatBonuses* newbon);
@ -1340,6 +1345,7 @@ protected:
char *adv_data; char *adv_data;
private: private:
eqFilterMode ClientFilters[_FilterCount]; eqFilterMode ClientFilters[_FilterCount];
int32 HandlePacket(const EQApplicationPacket *app); int32 HandlePacket(const EQApplicationPacket *app);
void OPTGB(const EQApplicationPacket *app); void OPTGB(const EQApplicationPacket *app);
@ -1633,9 +1639,9 @@ private:
bool InterrogateInventory_error(int16 head, int16 index, const EQEmu::ItemInstance* inst, const EQEmu::ItemInstance* parent, int depth); bool InterrogateInventory_error(int16 head, int16 index, const EQEmu::ItemInstance* inst, const EQEmu::ItemInstance* parent, int depth);
int client_max_level; int client_max_level;
#ifdef BOTS #ifdef BOTS
public: public:
enum BotOwnerOption : size_t { enum BotOwnerOption : size_t {
booDeathMarquee, booDeathMarquee,
@ -1652,7 +1658,7 @@ public:
bool GetBotOption(BotOwnerOption boo) const; bool GetBotOption(BotOwnerOption boo) const;
void SetBotOption(BotOwnerOption boo, bool flag = true); void SetBotOption(BotOwnerOption boo, bool flag = true);
bool GetBotPulling() { return m_bot_pulling; } bool GetBotPulling() { return m_bot_pulling; }
void SetBotPulling(bool flag = true) { m_bot_pulling = flag; } void SetBotPulling(bool flag = true) { m_bot_pulling = flag; }

View File

@ -599,7 +599,7 @@ void Client::CompleteConnect()
if (group) if (group)
group->SendHPManaEndPacketsTo(this); group->SendHPManaEndPacketsTo(this);
} }
//bulk raid send in here eventually //bulk raid send in here eventually
@ -818,35 +818,45 @@ void Client::CompleteConnect()
database.QueryDatabase( database.QueryDatabase(
StringFormat( StringFormat(
"UPDATE `character_data` SET `last_login` = UNIX_TIMESTAMP() WHERE id = %u", "UPDATE `character_data` SET `last_login` = UNIX_TIMESTAMP() WHERE id = %u",
this->CharacterID() CharacterID()
) )
); );
} }
if (zone) { if (zone && zone->GetInstanceTimer()) {
if (zone->GetInstanceTimer()) {
uint32 ttime = zone->GetInstanceTimer()->GetRemainingTime(); bool is_permanent = false;
uint32 day = (ttime / 86400000); uint32 remaining_time_seconds = database.GetTimeRemainingInstance(zone->GetInstanceID(), is_permanent);
uint32 hour = (ttime / 3600000) % 24; uint32 day = (remaining_time_seconds / 86400);
uint32 minute = (ttime / 60000) % 60; uint32 hour = (remaining_time_seconds / 3600) % 24;
uint32 second = (ttime / 1000) % 60; uint32 minute = (remaining_time_seconds / 60) % 60;
if (day) { uint32 second = (remaining_time_seconds / 1) % 60;
Message(Chat::Yellow, "%s(%u) will expire in %u days, %u hours, %u minutes, and %u seconds.",
zone->GetLongName(), zone->GetInstanceID(), day, hour, minute, second); if (day) {
} Message(
else if (hour) { Chat::Yellow, "%s (%u) will expire in %u days, %u hours, %u minutes, and %u seconds.",
Message(Chat::Yellow, "%s(%u) will expire in %u hours, %u minutes, and %u seconds.", zone->GetLongName(), zone->GetInstanceID(), day, hour, minute, second
zone->GetLongName(), zone->GetInstanceID(), hour, minute, second); );
}
else if (minute) {
Message(Chat::Yellow, "%s(%u) will expire in %u minutes, and %u seconds.",
zone->GetLongName(), zone->GetInstanceID(), minute, second);
}
else {
Message(Chat::Yellow, "%s(%u) will expire in in %u seconds.",
zone->GetLongName(), zone->GetInstanceID(), second);
}
} }
else if (hour) {
Message(
Chat::Yellow, "%s (%u) will expire in %u hours, %u minutes, and %u seconds.",
zone->GetLongName(), zone->GetInstanceID(), hour, minute, second
);
}
else if (minute) {
Message(
Chat::Yellow, "%s (%u) will expire in %u minutes, and %u seconds.",
zone->GetLongName(), zone->GetInstanceID(), minute, second
);
}
else {
Message(
Chat::Yellow, "%s (%u) will expire in in %u seconds.",
zone->GetLongName(), zone->GetInstanceID(), second
);
}
} }
SendRewards(); SendRewards();
@ -1237,7 +1247,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
database.ClearOldRecastTimestamps(cid); /* Clear out our old recast timestamps to keep the DB clean */ database.ClearOldRecastTimestamps(cid); /* Clear out our old recast timestamps to keep the DB clean */
// set to full support in case they're a gm with items in disabled expansion slots..but, have their gm flag off... // set to full support in case they're a gm with items in disabled expansion slots..but, have their gm flag off...
// item loss will occur when they use the 'empty' slots, if this is not done // item loss will occur when they use the 'empty' slots, if this is not done
m_inv.SetGMInventory(true); m_inv.SetGMInventory(true);
loaditems = database.GetInventory(cid, &m_inv); /* Load Character Inventory */ loaditems = database.GetInventory(cid, &m_inv); /* Load Character Inventory */
database.LoadCharacterBandolier(cid, &m_pp); /* Load Character Bandolier */ database.LoadCharacterBandolier(cid, &m_pp); /* Load Character Bandolier */
database.LoadCharacterBindPoint(cid, &m_pp); /* Load Character Bind */ database.LoadCharacterBindPoint(cid, &m_pp); /* Load Character Bind */
@ -1341,7 +1351,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
client_max_level = GetCharMaxLevelFromBucket(); client_max_level = GetCharMaxLevelFromBucket();
} }
SetClientMaxLevel(client_max_level); SetClientMaxLevel(client_max_level);
// we know our class now, so we might have to fix our consume timer! // we know our class now, so we might have to fix our consume timer!
if (class_ == MONK) if (class_ == MONK)
consume_food_timer.SetTimer(CONSUMPTION_MNK_TIMER); consume_food_timer.SetTimer(CONSUMPTION_MNK_TIMER);
@ -2840,7 +2850,7 @@ void Client::Handle_OP_ApplyPoison(const EQApplicationPacket *app)
// rogue simply won't apply at all, no skill check done. // rogue simply won't apply at all, no skill check done.
uint16 poison_skill = GetSkill(EQEmu::skills::SkillApplyPoison); uint16 poison_skill = GetSkill(EQEmu::skills::SkillApplyPoison);
if (ChanceRoll < (.75 + poison_skill / 1000)) { if (ChanceRoll < (.75 + poison_skill / 1000)) {
ApplyPoisonSuccessResult = 1; ApplyPoisonSuccessResult = 1;
AddProcToWeapon(poison->Proc.Effect, false, (GetDEX() / 100) + 103, POISON_PROC); AddProcToWeapon(poison->Proc.Effect, false, (GetDEX() / 100) + 103, POISON_PROC);
@ -3917,7 +3927,7 @@ void Client::Handle_OP_Bug(const EQApplicationPacket *app)
Message(0, "Bug reporting is disabled on this server."); Message(0, "Bug reporting is disabled on this server.");
return; return;
} }
if (app->size != sizeof(BugReport_Struct)) { if (app->size != sizeof(BugReport_Struct)) {
printf("Wrong size of BugReport_Struct got %d expected %zu!\n", app->size, sizeof(BugReport_Struct)); printf("Wrong size of BugReport_Struct got %d expected %zu!\n", app->size, sizeof(BugReport_Struct));
} }
@ -4018,6 +4028,14 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
return; return;
} }
// Hack for broken RoF2 which allows casting after a zoned IVU/IVA
if (invisible_undead || invisible_animals) {
BuffFadeByEffect(SE_InvisVsAnimals);
BuffFadeByEffect(SE_InvisVsUndead);
BuffFadeByEffect(SE_InvisVsUndead2);
BuffFadeByEffect(SE_Invisibility); // Included per JJ for completeness - client handles this one atm
}
CastSpell_Struct* castspell = (CastSpell_Struct*)app->pBuffer; CastSpell_Struct* castspell = (CastSpell_Struct*)app->pBuffer;
m_TargetRing = glm::vec3(castspell->x_pos, castspell->y_pos, castspell->z_pos); m_TargetRing = glm::vec3(castspell->x_pos, castspell->y_pos, castspell->z_pos);
@ -4362,9 +4380,9 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
sizeof(PlayerPositionUpdateClient_Struct), app->size); sizeof(PlayerPositionUpdateClient_Struct), app->size);
return; return;
} }
PlayerPositionUpdateClient_Struct *ppu = (PlayerPositionUpdateClient_Struct *) app->pBuffer; PlayerPositionUpdateClient_Struct *ppu = (PlayerPositionUpdateClient_Struct *) app->pBuffer;
/* Boat handling */ /* Boat handling */
if (ppu->spawn_id != GetID()) { if (ppu->spawn_id != GetID()) {
/* If player is controlling boat */ /* If player is controlling boat */
@ -4374,16 +4392,16 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
controlling_boat_id = 0; controlling_boat_id = 0;
return; return;
} }
auto boat_delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, EQ10toFloat(ppu->delta_heading)); auto boat_delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, EQ10toFloat(ppu->delta_heading));
boat->SetDelta(boat_delta); boat->SetDelta(boat_delta);
auto outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); auto outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
PlayerPositionUpdateServer_Struct *ppus = (PlayerPositionUpdateServer_Struct *) outapp->pBuffer; PlayerPositionUpdateServer_Struct *ppus = (PlayerPositionUpdateServer_Struct *) outapp->pBuffer;
boat->MakeSpawnUpdate(ppus); boat->MakeSpawnUpdate(ppus);
entity_list.QueueCloseClients(boat, outapp, true, 300, this, false); entity_list.QueueCloseClients(boat, outapp, true, 300, this, false);
safe_delete(outapp); safe_delete(outapp);
/* Update the boat's position on the server, without sending an update */ /* Update the boat's position on the server, without sending an update */
boat->GMMove(ppu->x_pos, ppu->y_pos, ppu->z_pos, EQ12toFloat(ppu->heading), false); boat->GMMove(ppu->x_pos, ppu->y_pos, ppu->z_pos, EQ12toFloat(ppu->heading), false);
return; return;
@ -4398,9 +4416,9 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
if (cmob != nullptr) { if (cmob != nullptr) {
cmob->SetPosition(ppu->x_pos, ppu->y_pos, ppu->z_pos); cmob->SetPosition(ppu->x_pos, ppu->y_pos, ppu->z_pos);
cmob->SetHeading(EQ12toFloat(ppu->heading)); cmob->SetHeading(EQ12toFloat(ppu->heading));
mMovementManager->SendCommandToClients(cmob, 0.0, 0.0, 0.0, mMovementManager->SendCommandToClients(cmob, 0.0, 0.0, 0.0,
0.0, 0, ClientRangeAny, nullptr, this); 0.0, 0, ClientRangeAny, nullptr, this);
cmob->CastToNPC()->SaveGuardSpot(glm::vec4(ppu->x_pos, cmob->CastToNPC()->SaveGuardSpot(glm::vec4(ppu->x_pos,
ppu->y_pos, ppu->z_pos, EQ12toFloat(ppu->heading))); ppu->y_pos, ppu->z_pos, EQ12toFloat(ppu->heading)));
} }
} }
@ -4418,7 +4436,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
// From this point forward, we need to use a new set of variables for client // From this point forward, we need to use a new set of variables for client
// position. If the client is in a boat, we need to add the boat pos and // position. If the client is in a boat, we need to add the boat pos and
// the client offset together. // the client offset together.
float cx = ppu->x_pos; float cx = ppu->x_pos;
float cy = ppu->y_pos; float cy = ppu->y_pos;
float cz = ppu->z_pos; float cz = ppu->z_pos;
@ -4443,45 +4461,45 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
/* Check to see if PPU should trigger an update to the rewind position. */ /* Check to see if PPU should trigger an update to the rewind position. */
float rewind_x_diff = 0; float rewind_x_diff = 0;
float rewind_y_diff = 0; float rewind_y_diff = 0;
rewind_x_diff = cx - m_RewindLocation.x; rewind_x_diff = cx - m_RewindLocation.x;
rewind_x_diff *= rewind_x_diff; rewind_x_diff *= rewind_x_diff;
rewind_y_diff = cy - m_RewindLocation.y; rewind_y_diff = cy - m_RewindLocation.y;
rewind_y_diff *= rewind_y_diff; rewind_y_diff *= rewind_y_diff;
/* /*
We only need to store updated values if the player has moved. We only need to store updated values if the player has moved.
If the player has moved more than units for x or y, then we'll store If the player has moved more than units for x or y, then we'll store
his pre-PPU x and y for /rewind, in case he gets stuck. his pre-PPU x and y for /rewind, in case he gets stuck.
*/ */
if ((rewind_x_diff > 750) || (rewind_y_diff > 750)) if ((rewind_x_diff > 750) || (rewind_y_diff > 750))
m_RewindLocation = glm::vec3(m_Position); m_RewindLocation = glm::vec3(m_Position);
/* /*
If the PPU was a large jump, such as a cross zone gate or Call of Hero, If the PPU was a large jump, such as a cross zone gate or Call of Hero,
just update rewind coordinates to the new ppu coordinates. This will prevent exploitation. just update rewind coordinates to the new ppu coordinates. This will prevent exploitation.
*/ */
if ((rewind_x_diff > 5000) || (rewind_y_diff > 5000)) if ((rewind_x_diff > 5000) || (rewind_y_diff > 5000))
m_RewindLocation = glm::vec3(cx, cy, cz); m_RewindLocation = glm::vec3(cx, cy, cz);
if (proximity_timer.Check()) { if (proximity_timer.Check()) {
entity_list.ProcessMove(this, glm::vec3(cx, cy, cz)); entity_list.ProcessMove(this, glm::vec3(cx, cy, cz));
if (RuleB(TaskSystem, EnableTaskSystem) && RuleB(TaskSystem, EnableTaskProximity)) if (RuleB(TaskSystem, EnableTaskSystem) && RuleB(TaskSystem, EnableTaskProximity))
ProcessTaskProximities(cx, cy, cz); ProcessTaskProximities(cx, cy, cz);
m_Proximity = glm::vec3(cx, cy, cz); m_Proximity = glm::vec3(cx, cy, cz);
} }
/* Update internal state */ /* Update internal state */
m_Delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, EQ10toFloat(ppu->delta_heading)); m_Delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, EQ10toFloat(ppu->delta_heading));
if (IsTracking() && ((m_Position.x != cx) || (m_Position.y != cy))) { if (IsTracking() && ((m_Position.x != cx) || (m_Position.y != cy))) {
if (zone->random.Real(0, 100) < 70)//should be good if (zone->random.Real(0, 100) < 70)//should be good
CheckIncreaseSkill(EQEmu::skills::SkillTracking, nullptr, -20); CheckIncreaseSkill(EQEmu::skills::SkillTracking, nullptr, -20);
} }
/* Break Hide if moving without sneaking and set rewind timer if moved */ /* Break Hide if moving without sneaking and set rewind timer if moved */
if (cy != m_Position.y || cx != m_Position.x) { if (cy != m_Position.y || cx != m_Position.x) {
if ((hidden || improved_hidden) && !sneaking) { if ((hidden || improved_hidden) && !sneaking) {
@ -4500,7 +4518,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
} }
rewind_timer.Start(30000, true); rewind_timer.Start(30000, true);
} }
/* Handle client aggro scanning timers NPCs */ /* Handle client aggro scanning timers NPCs */
is_client_moving = (cy == m_Position.y && cx == m_Position.x) ? false : true; is_client_moving = (cy == m_Position.y && cx == m_Position.x) ? false : true;
@ -4564,55 +4582,55 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
} }
int32 new_animation = ppu->animation; int32 new_animation = ppu->animation;
/* Update internal server position from what the client has sent */ /* Update internal server position from what the client has sent */
m_Position.x = cx; m_Position.x = cx;
m_Position.y = cy; m_Position.y = cy;
m_Position.z = cz; m_Position.z = cz;
/* Visual Debugging */ /* Visual Debugging */
if (RuleB(Character, OPClientUpdateVisualDebug)) { if (RuleB(Character, OPClientUpdateVisualDebug)) {
LogDebug("ClientUpdate: ppu x: [{}] y: [{}] z: [{}] h: [{}]", cx, cy, cz, new_heading); LogDebug("ClientUpdate: ppu x: [{}] y: [{}] z: [{}] h: [{}]", cx, cy, cz, new_heading);
this->SendAppearanceEffect(78, 0, 0, 0, 0); this->SendAppearanceEffect(78, 0, 0, 0, 0);
this->SendAppearanceEffect(41, 0, 0, 0, 0); this->SendAppearanceEffect(41, 0, 0, 0, 0);
} }
/* Only feed real time updates when client is moving */ /* Only feed real time updates when client is moving */
if (is_client_moving || new_heading != m_Position.w || new_animation != animation) { if (is_client_moving || new_heading != m_Position.w || new_animation != animation) {
animation = ppu->animation; animation = ppu->animation;
m_Position.w = new_heading; m_Position.w = new_heading;
/* Broadcast update to other clients */ /* Broadcast update to other clients */
auto outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); auto outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
PlayerPositionUpdateServer_Struct *position_update = (PlayerPositionUpdateServer_Struct *) outapp->pBuffer; PlayerPositionUpdateServer_Struct *position_update = (PlayerPositionUpdateServer_Struct *) outapp->pBuffer;
MakeSpawnUpdate(position_update); MakeSpawnUpdate(position_update);
if (gm_hide_me) { if (gm_hide_me) {
entity_list.QueueClientsStatus(this, outapp, true, Admin(), 255); entity_list.QueueClientsStatus(this, outapp, true, Admin(), 255);
} else { } else {
entity_list.QueueCloseClients(this, outapp, true, RuleI(Range, ClientPositionUpdates), nullptr, true); entity_list.QueueCloseClients(this, outapp, true, RuleI(Range, ClientPositionUpdates), nullptr, true);
} }
/* Always send position updates to group - send when beyond normal ClientPositionUpdate range */ /* Always send position updates to group - send when beyond normal ClientPositionUpdate range */
Group *group = this->GetGroup(); Group *group = this->GetGroup();
Raid *raid = this->GetRaid(); Raid *raid = this->GetRaid();
if (raid) { if (raid) {
raid->QueueClients(this, outapp, true, true, (RuleI(Range, ClientPositionUpdates) * -1)); raid->QueueClients(this, outapp, true, true, (RuleI(Range, ClientPositionUpdates) * -1));
} else if (group) { } else if (group) {
group->QueueClients(this, outapp, true, true, (RuleI(Range, ClientPositionUpdates) * -1)); group->QueueClients(this, outapp, true, true, (RuleI(Range, ClientPositionUpdates) * -1));
} }
safe_delete(outapp); safe_delete(outapp);
} }
if (zone->watermap) { if (zone->watermap) {
if (zone->watermap->InLiquid(glm::vec3(m_Position))) { if (zone->watermap->InLiquid(glm::vec3(m_Position))) {
CheckIncreaseSkill(EQEmu::skills::SkillSwimming, nullptr, -17); CheckIncreaseSkill(EQEmu::skills::SkillSwimming, nullptr, -17);
// Dismount horses when entering water // Dismount horses when entering water
if (GetHorseId() && RuleB(Character, DismountWater)) { if (GetHorseId() && RuleB(Character, DismountWater)) {
SetHorseId(0); SetHorseId(0);
@ -5749,23 +5767,23 @@ void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app)
printf("Error in FindPersonRequest_Struct. Expected size of: %zu, but got: %i\n", sizeof(FindPersonRequest_Struct), app->size); printf("Error in FindPersonRequest_Struct. Expected size of: %zu, but got: %i\n", sizeof(FindPersonRequest_Struct), app->size);
else { else {
FindPersonRequest_Struct* t = (FindPersonRequest_Struct*)app->pBuffer; FindPersonRequest_Struct* t = (FindPersonRequest_Struct*)app->pBuffer;
std::vector<FindPerson_Point> points; std::vector<FindPerson_Point> points;
Mob* target = entity_list.GetMob(t->npc_id); Mob* target = entity_list.GetMob(t->npc_id);
if (target == nullptr) { if (target == nullptr) {
//empty length packet == not found. //empty length packet == not found.
EQApplicationPacket outapp(OP_FindPersonReply, 0); EQApplicationPacket outapp(OP_FindPersonReply, 0);
QueuePacket(&outapp); QueuePacket(&outapp);
return; return;
} }
if (!RuleB(Pathing, Find) && RuleB(Bazaar, EnableWarpToTrader) && target->IsClient() && (target->CastToClient()->Trader || if (!RuleB(Pathing, Find) && RuleB(Bazaar, EnableWarpToTrader) && target->IsClient() && (target->CastToClient()->Trader ||
target->CastToClient()->Buyer)) { target->CastToClient()->Buyer)) {
Message(Chat::Yellow, "Moving you to Trader %s", target->GetName()); Message(Chat::Yellow, "Moving you to Trader %s", target->GetName());
MovePC(zone->GetZoneID(), zone->GetInstanceID(), target->GetX(), target->GetY(), target->GetZ(), 0.0f); MovePC(zone->GetZoneID(), zone->GetInstanceID(), target->GetX(), target->GetY(), target->GetZ(), 0.0f);
} }
if (!RuleB(Pathing, Find) || !zone->pathing) if (!RuleB(Pathing, Find) || !zone->pathing)
{ {
//fill in the path array... //fill in the path array...
@ -5788,40 +5806,40 @@ void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app)
{ {
glm::vec3 Start(GetX(), GetY(), GetZ() + (GetSize() < 6.0 ? 6 : GetSize()) * HEAD_POSITION); glm::vec3 Start(GetX(), GetY(), GetZ() + (GetSize() < 6.0 ? 6 : GetSize()) * HEAD_POSITION);
glm::vec3 End(target->GetX(), target->GetY(), target->GetZ() + (target->GetSize() < 6.0 ? 6 : target->GetSize()) * HEAD_POSITION); glm::vec3 End(target->GetX(), target->GetY(), target->GetZ() + (target->GetSize() < 6.0 ? 6 : target->GetSize()) * HEAD_POSITION);
bool partial = false; bool partial = false;
bool stuck = false; bool stuck = false;
auto pathlist = zone->pathing->FindRoute(Start, End, partial, stuck); auto pathlist = zone->pathing->FindRoute(Start, End, partial, stuck);
if (pathlist.empty() || partial) if (pathlist.empty() || partial)
{ {
EQApplicationPacket outapp(OP_FindPersonReply, 0); EQApplicationPacket outapp(OP_FindPersonReply, 0);
QueuePacket(&outapp); QueuePacket(&outapp);
return; return;
} }
// Live appears to send the points in this order: // Live appears to send the points in this order:
// Final destination. // Final destination.
// Current Position. // Current Position.
// rest of the points. // rest of the points.
FindPerson_Point p; FindPerson_Point p;
int PointNumber = 0; int PointNumber = 0;
bool LeadsToTeleporter = false; bool LeadsToTeleporter = false;
auto v = pathlist.back(); auto v = pathlist.back();
p.x = v.pos.x; p.x = v.pos.x;
p.y = v.pos.y; p.y = v.pos.y;
p.z = v.pos.z; p.z = v.pos.z;
points.push_back(p); points.push_back(p);
p.x = GetX(); p.x = GetX();
p.y = GetY(); p.y = GetY();
p.z = GetZ(); p.z = GetZ();
points.push_back(p); points.push_back(p);
for (auto Iterator = pathlist.begin(); Iterator != pathlist.end(); ++Iterator) for (auto Iterator = pathlist.begin(); Iterator != pathlist.end(); ++Iterator)
{ {
if ((*Iterator).teleport) // Teleporter if ((*Iterator).teleport) // Teleporter
@ -5829,7 +5847,7 @@ void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app)
LeadsToTeleporter = true; LeadsToTeleporter = true;
break; break;
} }
glm::vec3 v = (*Iterator).pos; glm::vec3 v = (*Iterator).pos;
p.x = v.x; p.x = v.x;
p.y = v.y; p.y = v.y;
@ -5837,17 +5855,17 @@ void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app)
points.push_back(p); points.push_back(p);
++PointNumber; ++PointNumber;
} }
if (!LeadsToTeleporter) if (!LeadsToTeleporter)
{ {
p.x = target->GetX(); p.x = target->GetX();
p.y = target->GetY(); p.y = target->GetY();
p.z = target->GetZ(); p.z = target->GetZ();
points.push_back(p); points.push_back(p);
} }
} }
SendPathPacket(points); SendPathPacket(points);
} }
} }
@ -11090,14 +11108,14 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
{ {
case RaidCommandInviteIntoExisting: case RaidCommandInviteIntoExisting:
case RaidCommandInvite: { case RaidCommandInvite: {
Client *player_to_invite = entity_list.GetClientByName(raid_command_packet->player_name); Client *player_to_invite = entity_list.GetClientByName(raid_command_packet->player_name);
if (!player_to_invite) if (!player_to_invite)
break; break;
Group *player_to_invite_group = player_to_invite->GetGroup(); Group *player_to_invite_group = player_to_invite->GetGroup();
if (player_to_invite->HasRaid()) { if (player_to_invite->HasRaid()) {
Message(Chat::Red, "%s is already in a raid.", player_to_invite->GetName()); Message(Chat::Red, "%s is already in a raid.", player_to_invite->GetName());
break; break;
@ -11112,7 +11130,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
Message(Chat::Red, "You can only invite an ungrouped player or group leader to join your raid."); Message(Chat::Red, "You can only invite an ungrouped player or group leader to join your raid.");
break; break;
} }
/* Send out invite to the client */ /* Send out invite to the client */
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); 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;
@ -11124,7 +11142,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
raid_command->action = 20; raid_command->action = 20;
player_to_invite->QueuePacket(outapp); player_to_invite->QueuePacket(outapp);
safe_delete(outapp); safe_delete(outapp);
break; break;
@ -11220,7 +11238,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
} }
if (player_invited_group->IsLeader(player_invited_group->members[x])) { if (player_invited_group->IsLeader(player_invited_group->members[x])) {
Client *c = nullptr; Client *c = nullptr;
if (player_invited_group->members[x]->IsClient()) if (player_invited_group->members[x]->IsClient())
c = player_invited_group->members[x]->CastToClient(); c = player_invited_group->members[x]->CastToClient();
else else
@ -11230,24 +11248,24 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->SendMakeLeaderPacketTo(raid->leadername, c);
raid->AddMember(c, raid_free_group_id, true, true, true); raid->AddMember(c, raid_free_group_id, true, true, true);
raid->SendBulkRaid(c); raid->SendBulkRaid(c);
if (raid->IsLocked()) { if (raid->IsLocked()) {
raid->SendRaidLockTo(c); raid->SendRaidLockTo(c);
} }
} }
else { else {
Client *c = nullptr; Client *c = nullptr;
if (player_invited_group->members[x]->IsClient()) if (player_invited_group->members[x]->IsClient())
c = player_invited_group->members[x]->CastToClient(); c = player_invited_group->members[x]->CastToClient();
else else
continue; continue;
raid->SendRaidCreate(c); raid->SendRaidCreate(c);
raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->SendMakeLeaderPacketTo(raid->leadername, c);
raid->AddMember(c, raid_free_group_id); raid->AddMember(c, raid_free_group_id);
raid->SendBulkRaid(c); raid->SendBulkRaid(c);
if (raid->IsLocked()) { if (raid->IsLocked()) {
raid->SendRaidLockTo(c); raid->SendRaidLockTo(c);
} }
@ -11281,12 +11299,12 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
c = group->members[x]->CastToClient(); c = group->members[x]->CastToClient();
else else
continue; continue;
raid->SendRaidCreate(c); raid->SendRaidCreate(c);
raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->SendMakeLeaderPacketTo(raid->leadername, c);
raid->AddMember(c, raid_free_group_id, false, true); raid->AddMember(c, raid_free_group_id, false, true);
raid->SendBulkRaid(c); raid->SendBulkRaid(c);
if (raid->IsLocked()) { if (raid->IsLocked()) {
raid->SendRaidLockTo(c); raid->SendRaidLockTo(c);
} }
@ -11294,17 +11312,17 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
else else
{ {
Client *c = nullptr; Client *c = nullptr;
if (group->members[x]->IsClient()) if (group->members[x]->IsClient())
c = group->members[x]->CastToClient(); c = group->members[x]->CastToClient();
else else
continue; continue;
raid->SendRaidCreate(c); raid->SendRaidCreate(c);
raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->SendMakeLeaderPacketTo(raid->leadername, c);
raid->AddMember(c, raid_free_group_id); raid->AddMember(c, raid_free_group_id);
raid->SendBulkRaid(c); raid->SendBulkRaid(c);
if (raid->IsLocked()) { if (raid->IsLocked()) {
raid->SendRaidLockTo(c); raid->SendRaidLockTo(c);
} }
@ -11321,7 +11339,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
if (player_invited_group) { if (player_invited_group) {
raid = new Raid(player_accepting_invite); raid = new Raid(player_accepting_invite);
entity_list.AddRaid(raid); entity_list.AddRaid(raid);
raid->SetRaidDetails(); raid->SetRaidDetails();
Client *addClientig = nullptr; Client *addClientig = nullptr;
@ -11345,7 +11363,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->SendMakeLeaderPacketTo(raid->leadername, c);
raid->AddMember(c, 0, true, true, true); raid->AddMember(c, 0, true, true, true);
raid->SendBulkRaid(c); raid->SendBulkRaid(c);
if (raid->IsLocked()) { if (raid->IsLocked()) {
raid->SendRaidLockTo(c); raid->SendRaidLockTo(c);
} }
@ -11470,7 +11488,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
raid->SetGroupLeader(raid_command_packet->leader_name, false); raid->SetGroupLeader(raid_command_packet->leader_name, false);
/* We were the leader of our old group */ /* We were the leader of our old group */
if (old_group < 12) { if (old_group < 12) {
/* Assign new group leader if we can */ /* Assign new group leader if we can */
for (int x = 0; x < MAX_RAID_MEMBERS; x++) { for (int x = 0; x < MAX_RAID_MEMBERS; x++) {
if (raid->members[x].GroupNumber == old_group) { if (raid->members[x].GroupNumber == old_group) {
@ -11499,7 +11517,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
strn0cpy(raid_command_packet->playername, raid->members[x].membername, 64); strn0cpy(raid_command_packet->playername, raid->members[x].membername, 64);
worldserver.SendPacket(pack); worldserver.SendPacket(pack);
safe_delete(pack); safe_delete(pack);
} }
break; break;
@ -11545,7 +11563,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
raid->SetGroupLeader(raid_command_packet->leader_name, false); raid->SetGroupLeader(raid_command_packet->leader_name, false);
for (int x = 0; x < MAX_RAID_MEMBERS; x++) { 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->SetGroupLeader(raid->members[x].membername);
raid->UpdateGroupAAs(oldgrp); raid->UpdateGroupAAs(oldgrp);
@ -11568,7 +11586,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
strn0cpy(raid_command->playername, raid->members[x].membername, 64); strn0cpy(raid_command->playername, raid->members[x].membername, 64);
raid_command->zoneid = zone->GetZoneID(); raid_command->zoneid = zone->GetZoneID();
raid_command->instance_id = zone->GetInstanceID(); raid_command->instance_id = zone->GetInstanceID();
worldserver.SendPacket(pack); worldserver.SendPacket(pack);
safe_delete(pack); safe_delete(pack);
} }
@ -11583,14 +11601,14 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
else { else {
auto pack = new ServerPacket(ServerOP_RaidGroupDisband, sizeof(ServerRaidGeneralAction_Struct)); auto pack = new ServerPacket(ServerOP_RaidGroupDisband, sizeof(ServerRaidGeneralAction_Struct));
ServerRaidGeneralAction_Struct* raid_command = (ServerRaidGeneralAction_Struct*)pack->pBuffer; ServerRaidGeneralAction_Struct* raid_command = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
raid_command->rid = raid->GetID(); raid_command->rid = raid->GetID();
raid_command->zoneid = zone->GetZoneID(); raid_command->zoneid = zone->GetZoneID();
raid_command->instance_id = zone->GetInstanceID(); raid_command->instance_id = zone->GetInstanceID();
strn0cpy(raid_command->playername, raid_command_packet->leader_name, 64); strn0cpy(raid_command->playername, raid_command_packet->leader_name, 64);
worldserver.SendPacket(pack); worldserver.SendPacket(pack);
safe_delete(pack); safe_delete(pack);
} }
@ -13327,13 +13345,17 @@ void Client::Handle_OP_Split(const EQApplicationPacket *app)
Split_Struct *split = (Split_Struct *)app->pBuffer; Split_Struct *split = (Split_Struct *)app->pBuffer;
//Per the note above, Im not exactly sure what to do on error //Per the note above, Im not exactly sure what to do on error
//to notify the client of the error... //to notify the client of the error...
if (!isgrouped) {
Message(Chat::Red, "You can not split money if you're not in a group."); Group *group = nullptr;
return; Raid *raid = nullptr;
}
Group *cgroup = GetGroup(); if (IsRaidGrouped())
if (cgroup == nullptr) { raid = GetRaid();
//invalid group, not sure if we should say more... else if (IsGrouped())
group = GetGroup();
// is there an actual error message for this?
if (raid == nullptr && group == nullptr) {
Message(Chat::Red, "You can not split money if you're not in a group."); Message(Chat::Red, "You can not split money if you're not in a group.");
return; return;
} }
@ -13345,7 +13367,11 @@ void Client::Handle_OP_Split(const EQApplicationPacket *app)
Message(Chat::Red, "You do not have enough money to do that split."); Message(Chat::Red, "You do not have enough money to do that split.");
return; return;
} }
cgroup->SplitMoney(split->copper, split->silver, split->gold, split->platinum);
if (raid)
raid->SplitMoney(raid->GetGroup(this), split->copper, split->silver, split->gold, split->platinum);
else if (group)
group->SplitMoney(split->copper, split->silver, split->gold, split->platinum);
return; return;

View File

@ -196,6 +196,7 @@ int command_init(void)
command_add("disarmtrap", "Analog for ldon disarm trap for the newer clients since we still don't have it working.", 80, command_disarmtrap) || command_add("disarmtrap", "Analog for ldon disarm trap for the newer clients since we still don't have it working.", 80, command_disarmtrap) ||
command_add("distance", "- Reports the distance between you and your target.", 80, command_distance) || command_add("distance", "- Reports the distance between you and your target.", 80, command_distance) ||
command_add("doanim", "[animnum] [type] - Send an EmoteAnim for you or your target", 50, command_doanim) || command_add("doanim", "[animnum] [type] - Send an EmoteAnim for you or your target", 50, command_doanim) ||
command_add("editmassrespawn", "[name-search] [second-value] - Mass (Zone wide) NPC respawn timer editing command", 100, command_editmassrespawn) ||
command_add("emote", "['name'/'world'/'zone'] [type] [message] - Send an emote message", 80, command_emote) || command_add("emote", "['name'/'world'/'zone'] [type] [message] - Send an emote message", 80, command_emote) ||
command_add("emotesearch", "Searches NPC Emotes", 80, command_emotesearch) || command_add("emotesearch", "Searches NPC Emotes", 80, command_emotesearch) ||
command_add("emoteview", "Lists all NPC Emotes", 80, command_emoteview) || command_add("emoteview", "Lists all NPC Emotes", 80, command_emoteview) ||
@ -6525,6 +6526,144 @@ void command_doanim(Client *c, const Seperator *sep)
c->DoAnim(atoi(sep->arg[1]),atoi(sep->arg[2])); c->DoAnim(atoi(sep->arg[1]),atoi(sep->arg[2]));
} }
void command_editmassrespawn(Client* c, const Seperator* sep)
{
if (strcasecmp(sep->arg[1], "usage") == 0) {
c->Message(Chat::White, "#editmassrespawn [exact_match: =]npc_type_name new_respawn_seconds (apply)");
return;
}
std::string search_npc_type;
if (sep->arg[1]) {
search_npc_type = sep->arg[1];
}
int change_respawn_seconds = 0;
if (sep->arg[2] && sep->IsNumber(2)) {
change_respawn_seconds = atoi(sep->arg[2]);
}
bool change_apply = false;
if (sep->arg[3] && strcasecmp(sep->arg[3], "apply") == 0) {
change_apply = true;
}
std::string search_encapsulator = "%";
if (search_npc_type[0] == '=') {
search_npc_type = search_npc_type.substr(1);
search_encapsulator = "";
}
std::string query = fmt::format(
SQL(
SELECT npc_types.id, spawn2.spawngroupID, spawn2.id, npc_types.name, spawn2.respawntime
FROM spawn2
INNER JOIN spawnentry ON spawn2.spawngroupID = spawnentry.spawngroupID
INNER JOIN npc_types ON spawnentry.npcID = npc_types.id
WHERE spawn2.zone LIKE '{}'
AND spawn2.version = '{}'
AND npc_types.name LIKE '{}{}{}'
ORDER BY npc_types.id, spawn2.spawngroupID, spawn2.id
),
zone->GetShortName(),
zone->GetInstanceVersion(),
search_encapsulator,
search_npc_type,
search_encapsulator
);
std::string status = "(Searching)";
if (change_apply) {
status = "(Applying)";
}
int results_count = 0;
auto results = database.QueryDatabase(query);
if (results.Success() && results.RowCount()) {
results_count = results.RowCount();
for (auto row : results) {
c->Message(
Chat::Yellow,
fmt::format(
"NPC (npcid:{}) (sgid:{}) (s2id:{}) [{}] Respawn: Current [{}] New [{}] {}",
row[0],
row[1],
row[2],
row[3],
row[4],
change_respawn_seconds,
status
).c_str()
);
}
c->Message(Chat::Yellow, "Found (%i) NPC's that match this search...", results_count);
if (change_respawn_seconds > 0) {
if (change_apply) {
results = database.QueryDatabase(
fmt::format(
SQL(
UPDATE spawn2
SET respawntime = '{}'
WHERE id IN (
SELECT spawn2.id
FROM spawn2
INNER JOIN spawnentry ON spawn2.spawngroupID = spawnentry.spawngroupID
INNER JOIN npc_types ON spawnentry.npcID = npc_types.id
WHERE spawn2.zone LIKE '{}'
AND spawn2.version = '{}'
AND npc_types.name LIKE '{}{}{}'
)
),
change_respawn_seconds,
zone->GetShortName(),
zone->GetInstanceVersion(),
search_encapsulator,
search_npc_type,
search_encapsulator
)
);
if (results.Success()) {
c->Message(Chat::Yellow, "Changes applied to (%i) NPC 'Spawn2' entries", results_count);
zone->Repop();
}
else {
c->Message(Chat::Yellow, "Found (0) NPC's that match this search...");
}
}
else {
std::string saylink = fmt::format(
"#editmassrespawn {}{} {} apply",
(search_encapsulator.empty() ? "=" : ""),
search_npc_type,
change_respawn_seconds
);
c->Message(
Chat::Yellow, "To apply these changes, click <%s> or type [%s]",
EQEmu::SayLinkEngine::GenerateQuestSaylink(saylink, false, "Apply").c_str(),
saylink.c_str()
);
}
}
}
else {
c->Message(Chat::Yellow, "Found (0) NPC's that match this search...");
}
}
void command_randomfeatures(Client *c, const Seperator *sep) void command_randomfeatures(Client *c, const Seperator *sep)
{ {
Mob *target=c->GetTarget(); Mob *target=c->GetTarget();
@ -7782,7 +7921,7 @@ void command_npcemote(Client *c, const Seperator *sep)
void command_npceditmass(Client *c, const Seperator *sep) void command_npceditmass(Client *c, const Seperator *sep)
{ {
if (strcasecmp(sep->arg[1], "usage") == 0) { if (strcasecmp(sep->arg[1], "usage") == 0) {
c->Message(Chat::White, "#npceditmass search_column [exact_match: =]search_value change_column change_value"); c->Message(Chat::White, "#npceditmass search_column [exact_match: =]search_value change_column change_value (apply)");
return; return;
} }
@ -7930,7 +8069,7 @@ void command_npceditmass(Client *c, const Seperator *sep)
std::string saylink = fmt::format( std::string saylink = fmt::format(
"#npceditmass {} {}{} {} {} apply", "#npceditmass {} {}{} {} {} apply",
search_column, search_column,
(exact_match ? '=' : '\0'), (exact_match ? "=" : ""),
search_value, search_value,
change_column, change_column,
change_value change_value

View File

@ -91,6 +91,7 @@ void command_disablerecipe(Client *c, const Seperator *sep);
void command_disarmtrap(Client *c, const Seperator *sep); void command_disarmtrap(Client *c, const Seperator *sep);
void command_distance(Client *c, const Seperator *sep); void command_distance(Client *c, const Seperator *sep);
void command_doanim(Client *c, const Seperator *sep); void command_doanim(Client *c, const Seperator *sep);
void command_editmassrespawn(Client* c, const Seperator* sep);
void command_emote(Client *c, const Seperator *sep); void command_emote(Client *c, const Seperator *sep);
void command_emotesearch(Client* c, const Seperator *sep); void command_emotesearch(Client* c, const Seperator *sep);
void command_emoteview(Client* c, const Seperator *sep); void command_emoteview(Client* c, const Seperator *sep);

View File

@ -822,6 +822,54 @@ XS(XS__isdisctome) {
XSRETURN(1); XSRETURN(1);
} }
XS(XS__getracename);
XS(XS__getracename) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: quest::getracename(uint16 race_id)");
dXSTARG;
uint16 race_id = (int) SvIV(ST(0));
std::string race_name = quest_manager.getracename(race_id);
sv_setpv(TARG, race_name.c_str());
XSprePUSH;
PUSHTARG;
XSRETURN(1);
}
XS(XS__getspellname);
XS(XS__getspellname) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: quest::getspellname(uint32 spell_id)");
dXSTARG;
uint32 spell_id = (int) SvIV(ST(0));
std::string spell_name = quest_manager.getspellname(spell_id);
sv_setpv(TARG, spell_name.c_str());
XSprePUSH;
PUSHTARG;
XSRETURN(1);
}
XS(XS__getskillname);
XS(XS__getskillname) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: quest::getskillname(int skill_id)");
dXSTARG;
int skill_id = (int) SvIV(ST(0));
std::string skill_name = quest_manager.getskillname(skill_id);
sv_setpv(TARG, skill_name.c_str());
XSprePUSH;
PUSHTARG;
XSRETURN(1);
}
XS(XS__safemove); XS(XS__safemove);
XS(XS__safemove) { XS(XS__safemove) {
dXSARGS; dXSARGS;
@ -2342,7 +2390,6 @@ XS(XS__updatetaskactivity) {
XS(XS__resettaskactivity); XS(XS__resettaskactivity);
XS(XS__resettaskactivity) { XS(XS__resettaskactivity) {
dXSARGS; dXSARGS;
unsigned int task, activity;
if (items == 2) { if (items == 2) {
int task_id = (int) SvIV(ST(0)); int task_id = (int) SvIV(ST(0));
int activity_id = (int) SvIV(ST(1)); int activity_id = (int) SvIV(ST(1));
@ -2613,6 +2660,23 @@ XS(XS__istaskappropriate) {
XSRETURN(1); XSRETURN(1);
} }
XS(XS__gettaskname);
XS(XS__gettaskname) {
dXSARGS;
if (items != 1) {
Perl_croak(aTHX_ "Usage: quest::gettaskname(uint32 task_id)");
}
dXSTARG;
uint32 task_id = (int) SvIV(ST(0));
std::string task_name = quest_manager.gettaskname(task_id);
sv_setpv(TARG, task_name.c_str());
XSprePUSH;
PUSHTARG;
XSRETURN(1);
}
XS(XS__popup); // prototype to pass -Wmissing-prototypes XS(XS__popup); // prototype to pass -Wmissing-prototypes
XS(XS__popup) { XS(XS__popup) {
dXSARGS; dXSARGS;
@ -2797,6 +2861,51 @@ XS(XS__collectitems) {
XSRETURN_IV(quantity); XSRETURN_IV(quantity);
} }
XS(XS__countitem);
XS(XS__countitem) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: quest::countitem(int item_id)");
uint32 item_id = (int) SvIV(ST(0));
int quantity = quest_manager.countitem(item_id);
XSRETURN_IV(quantity);
}
XS(XS__getitemname);
XS(XS__getitemname) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: quest::getitemname(uint32 item_id)");
dXSTARG;
uint32 item_id = (int) SvIV(ST(0));
std::string item_name = quest_manager.getitemname(item_id);
sv_setpv(TARG, item_name.c_str());
XSprePUSH;
PUSHTARG;
XSRETURN(1);
}
XS(XS__getnpcnamebyid);
XS(XS__getnpcnamebyid) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: quest::getnpcnamebyid(uint32 npc_id)");
dXSTARG;
uint32 npc_id = (int) SvIV(ST(0));
const char *npc_name = quest_manager.getnpcnamebyid(npc_id);
sv_setpv(TARG, npc_name);
XSprePUSH;
PUSHTARG;
XSRETURN(1);
}
XS(XS__UpdateSpawnTimer); XS(XS__UpdateSpawnTimer);
XS(XS__UpdateSpawnTimer) { XS(XS__UpdateSpawnTimer) {
dXSARGS; dXSARGS;
@ -3063,6 +3172,25 @@ XS(XS__RemoveFromInstanceByCharID) {
XSRETURN_EMPTY; XSRETURN_EMPTY;
} }
XS(XS__CheckInstanceByCharID);
XS(XS__CheckInstanceByCharID) {
dXSARGS;
if (items != 2) {
Perl_croak(aTHX_ "Usage: quest::CheckInstanceByCharID(uint16 instance_id, uint32 char_id)");
}
bool RETVAL;
dXSTARG;
uint16 instance_id = (int) SvUV(ST(0));
uint32 char_id = (int) SvUV(ST(1));
RETVAL = quest_manager.CheckInstanceByCharID(instance_id, char_id);
XSprePUSH;
PUSHu((IV) RETVAL);
XSRETURN(1);
}
XS(XS__RemoveAllFromInstance); XS(XS__RemoveAllFromInstance);
XS(XS__RemoveAllFromInstance) { XS(XS__RemoveAllFromInstance) {
dXSARGS; dXSARGS;
@ -3151,6 +3279,93 @@ XS(XS__saylink) {
XSRETURN(1); XSRETURN(1);
} }
XS(XS__getcharnamebyid);
XS(XS__getcharnamebyid) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: quest::getcharnamebyid(uint32 char_id)");
dXSTARG;
Const_char *RETVAL;
uint32 char_id = (int) SvUV(ST(0));
RETVAL = quest_manager.getcharnamebyid(char_id);
sv_setpv(TARG, RETVAL);
XSprePUSH;
PUSHTARG;
}
XS(XS__getcharidbyname);
XS(XS__getcharidbyname) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: quest::getcharidbyname(string name)");
dXSTARG;
uint32 RETVAL;
const char *name = (const char *) SvPV_nolen(ST(0));
RETVAL = quest_manager.getcharidbyname(name);
XSprePUSH;
PUSHu((UV)RETVAL);
XSRETURN(1);
}
XS(XS__getclassname);
XS(XS__getclassname) {
dXSARGS;
if (items < 1 || items > 2)
Perl_croak(aTHX_ "Usage: quest::getclassname(uint8 class_id, [uint8 level = 0])");
dXSTARG;
std::string RETVAL;
uint8 class_id = (int) SvUV(ST(0));
uint8 level = 0;
if (items > 1)
level = (int) SvUV(ST(1));
RETVAL = quest_manager.getclassname(class_id, level);
sv_setpv(TARG, RETVAL.c_str());
XSprePUSH;
PUSHTARG;
XSRETURN(1);
}
XS(XS__getcurrencyitemid);
XS(XS__getcurrencyitemid) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: quest::getcurrencyitemid(int currency_id)");
dXSTARG;
int RETVAL;
int currency_id = (int) SvUV(ST(0));
RETVAL = quest_manager.getcurrencyitemid(currency_id);
XSprePUSH;
PUSHi((IV)RETVAL);
XSRETURN(1);
}
XS(XS__getcurrencyid);
XS(XS__getcurrencyid) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: quest::getcurrencyid(uint32 item_id)");
dXSTARG;
int RETVAL;
uint32 item_id = (int) SvUV(ST(0));
RETVAL = quest_manager.getcurrencyid(item_id);
XSprePUSH;
PUSHi((IV)RETVAL);
XSRETURN(1);
}
XS(XS__getguildnamebyid); XS(XS__getguildnamebyid);
XS(XS__getguildnamebyid) { XS(XS__getguildnamebyid) {
dXSARGS; dXSARGS;
@ -3169,6 +3384,58 @@ XS(XS__getguildnamebyid) {
XSRETURN(1); XSRETURN(1);
} }
XS(XS__getguildidbycharid);
XS(XS__getguildidbycharid) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: quest::getguildidbycharid(uint32 char_id)");
dXSTARG;
int RETVAL;
uint32 char_id = (int) SvUV(ST(0));
RETVAL = quest_manager.getguildidbycharid(char_id);
XSprePUSH;
PUSHi((IV)RETVAL);
XSRETURN(1);
}
XS(XS__getgroupidbycharid);
XS(XS__getgroupidbycharid) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: quest::getgroupidbycharid(uint32 char_id)");
dXSTARG;
int RETVAL;
uint32 char_id = (int) SvUV(ST(0));
RETVAL = quest_manager.getgroupidbycharid(char_id);
XSprePUSH;
PUSHi((IV)RETVAL);
XSRETURN(1);
}
XS(XS__getraididbycharid);
XS(XS__getraididbycharid) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: quest::getraididbycharid(uint32 char_id)");
dXSTARG;
int RETVAL;
uint32 char_id = (int) SvUV(ST(0));
RETVAL = quest_manager.getraididbycharid(char_id);
XSprePUSH;
PUSHi((IV)RETVAL);
XSRETURN(1);
}
XS(XS__SetRunning); XS(XS__SetRunning);
XS(XS__SetRunning) { XS(XS__SetRunning) {
dXSARGS; dXSARGS;
@ -3875,6 +4142,7 @@ EXTERN_C XS(boot_quest) {
newXS(strcpy(buf, "RemoveAllFromInstance"), XS__RemoveAllFromInstance, file); newXS(strcpy(buf, "RemoveAllFromInstance"), XS__RemoveAllFromInstance, file);
newXS(strcpy(buf, "RemoveFromInstance"), XS__RemoveFromInstance, file); newXS(strcpy(buf, "RemoveFromInstance"), XS__RemoveFromInstance, file);
newXS(strcpy(buf, "RemoveFromInstanceByCharID"), XS__RemoveFromInstanceByCharID, file); newXS(strcpy(buf, "RemoveFromInstanceByCharID"), XS__RemoveFromInstanceByCharID, file);
newXS(strcpy(buf, "CheckInstanceByCharID"), XS__CheckInstanceByCharID, file);
newXS(strcpy(buf, "SendMail"), XS__SendMail, file); newXS(strcpy(buf, "SendMail"), XS__SendMail, file);
newXS(strcpy(buf, "SetRunning"), XS__SetRunning, file); newXS(strcpy(buf, "SetRunning"), XS__SetRunning, file);
newXS(strcpy(buf, "activespeakactivity"), XS__activespeakactivity, file); newXS(strcpy(buf, "activespeakactivity"), XS__activespeakactivity, file);
@ -3899,6 +4167,7 @@ EXTERN_C XS(boot_quest) {
newXS(strcpy(buf, "clearspawntimers"), XS__clearspawntimers, file); newXS(strcpy(buf, "clearspawntimers"), XS__clearspawntimers, file);
newXS(strcpy(buf, "collectitems"), XS__collectitems, file); newXS(strcpy(buf, "collectitems"), XS__collectitems, file);
newXS(strcpy(buf, "completedtasksinset"), XS__completedtasksinset, file); newXS(strcpy(buf, "completedtasksinset"), XS__completedtasksinset, file);
newXS(strcpy(buf, "countitem"), XS__countitem, file);
newXS(strcpy(buf, "createdoor"), XS__CreateDoor, file); newXS(strcpy(buf, "createdoor"), XS__CreateDoor, file);
newXS(strcpy(buf, "creategroundobject"), XS__CreateGroundObject, file); newXS(strcpy(buf, "creategroundobject"), XS__CreateGroundObject, file);
newXS(strcpy(buf, "creategroundobjectfrommodel"), XS__CreateGroundObjectFromModel, file); newXS(strcpy(buf, "creategroundobjectfrommodel"), XS__CreateGroundObjectFromModel, file);
@ -3938,15 +4207,29 @@ EXTERN_C XS(boot_quest) {
newXS(strcpy(buf, "follow"), XS__follow, file); newXS(strcpy(buf, "follow"), XS__follow, file);
newXS(strcpy(buf, "forcedoorclose"), XS__forcedoorclose, file); newXS(strcpy(buf, "forcedoorclose"), XS__forcedoorclose, file);
newXS(strcpy(buf, "forcedooropen"), XS__forcedooropen, file); newXS(strcpy(buf, "forcedooropen"), XS__forcedooropen, file);
newXS(strcpy(buf, "getcharidbyname"), XS__getcharidbyname, file);
newXS(strcpy(buf, "getclassname"), XS__getclassname, file);
newXS(strcpy(buf, "getcurrencyid"), XS__getcurrencyid, file);
newXS(strcpy(buf, "getinventoryslotid"), XS__getinventoryslotid, file); newXS(strcpy(buf, "getinventoryslotid"), XS__getinventoryslotid, file);
newXS(strcpy(buf, "getitemname"), XS__getitemname, file);
newXS(strcpy(buf, "getItemName"), XS_qc_getItemName, file); newXS(strcpy(buf, "getItemName"), XS_qc_getItemName, file);
newXS(strcpy(buf, "getnpcnamebyid"), XS__getnpcnamebyid, file);
newXS(strcpy(buf, "get_spawn_condition"), XS__get_spawn_condition, file); newXS(strcpy(buf, "get_spawn_condition"), XS__get_spawn_condition, file);
newXS(strcpy(buf, "getcharnamebyid"), XS__getcharnamebyid, file);
newXS(strcpy(buf, "getcurrencyitemid"), XS__getcurrencyitemid, file);
newXS(strcpy(buf, "getguildnamebyid"), XS__getguildnamebyid, file); newXS(strcpy(buf, "getguildnamebyid"), XS__getguildnamebyid, file);
newXS(strcpy(buf, "getguildidbycharid"), XS__getguildidbycharid, file);
newXS(strcpy(buf, "getgroupidbycharid"), XS__getgroupidbycharid, file);
newXS(strcpy(buf, "getraididbycharid"), XS__getraididbycharid, file);
newXS(strcpy(buf, "getracename"), XS__getracename, file);
newXS(strcpy(buf, "getspellname"), XS__getspellname, file);
newXS(strcpy(buf, "getskillname"), XS__getskillname, file);
newXS(strcpy(buf, "getlevel"), XS__getlevel, file); newXS(strcpy(buf, "getlevel"), XS__getlevel, file);
newXS(strcpy(buf, "getplayerburiedcorpsecount"), XS__getplayerburiedcorpsecount, file); newXS(strcpy(buf, "getplayerburiedcorpsecount"), XS__getplayerburiedcorpsecount, file);
newXS(strcpy(buf, "getplayercorpsecount"), XS__getplayercorpsecount, file); newXS(strcpy(buf, "getplayercorpsecount"), XS__getplayercorpsecount, file);
newXS(strcpy(buf, "getplayercorpsecountbyzoneid"), XS__getplayercorpsecountbyzoneid, file); newXS(strcpy(buf, "getplayercorpsecountbyzoneid"), XS__getplayercorpsecountbyzoneid, file);
newXS(strcpy(buf, "gettaskactivitydonecount"), XS__gettaskactivitydonecount, file); newXS(strcpy(buf, "gettaskactivitydonecount"), XS__gettaskactivitydonecount, file);
newXS(strcpy(buf, "gettaskname"), XS__gettaskname, file);
newXS(strcpy(buf, "givecash"), XS__givecash, file); newXS(strcpy(buf, "givecash"), XS__givecash, file);
newXS(strcpy(buf, "gmmove"), XS__gmmove, file); newXS(strcpy(buf, "gmmove"), XS__gmmove, file);
newXS(strcpy(buf, "gmsay"), XS__gmsay, file); newXS(strcpy(buf, "gmsay"), XS__gmsay, file);

View File

@ -498,7 +498,7 @@ void EntityList::MobProcess()
size_t sz = mob_list.size(); size_t sz = mob_list.size();
#ifdef IDLE_WHEN_EMPTY #ifdef IDLE_WHEN_EMPTY
if (numclients > 0 || if (numclients > 0 ||
mob->GetWanderType() == 4 || mob->GetWanderType() == 6) { mob->GetWanderType() == 4 || mob->GetWanderType() == 6) {
// Normal processing, or assuring that spawns that should // Normal processing, or assuring that spawns that should
// path and depop do that. Otherwise all of these type mobs // path and depop do that. Otherwise all of these type mobs
@ -931,12 +931,12 @@ bool EntityList::MakeDoorSpawnPacket(EQApplicationPacket *app, Client *client)
memcpy(new_door.name, door->GetDoorName(), 32); memcpy(new_door.name, door->GetDoorName(), 32);
auto position = door->GetPosition(); auto position = door->GetPosition();
new_door.xPos = position.x; new_door.xPos = position.x;
new_door.yPos = position.y; new_door.yPos = position.y;
new_door.zPos = position.z; new_door.zPos = position.z;
new_door.heading = position.w; new_door.heading = position.w;
new_door.incline = door->GetIncline(); new_door.incline = door->GetIncline();
new_door.size = door->GetSize(); new_door.size = door->GetSize();
new_door.doorId = door->GetDoorID(); new_door.doorId = door->GetDoorID();
@ -1984,17 +1984,26 @@ Raid *EntityList::GetRaidByID(uint32 id)
Raid *EntityList::GetRaidByClient(Client* client) Raid *EntityList::GetRaidByClient(Client* client)
{ {
std::list<Raid *>::iterator iterator; if (client->p_raid_instance) {
return client->p_raid_instance;
}
std::list<Raid *>::iterator iterator;
iterator = raid_list.begin(); iterator = raid_list.begin();
while (iterator != raid_list.end()) { while (iterator != raid_list.end()) {
for (int x = 0; x < MAX_RAID_MEMBERS; x++) for (auto &member : (*iterator)->members) {
if ((*iterator)->members[x].member) if (member.member) {
if((*iterator)->members[x].member == client) if (member.member == client) {
client->p_raid_instance = *iterator;
return *iterator; return *iterator;
}
}
}
++iterator; ++iterator;
} }
return nullptr; return nullptr;
} }
@ -3277,13 +3286,15 @@ void EntityList::Evade(Mob *who)
void EntityList::ClearAggro(Mob* targ) void EntityList::ClearAggro(Mob* targ)
{ {
Client *c = nullptr; Client *c = nullptr;
if (targ->IsClient()) if (targ->IsClient()) {
c = targ->CastToClient(); c = targ->CastToClient();
}
auto it = npc_list.begin(); auto it = npc_list.begin();
while (it != npc_list.end()) { while (it != npc_list.end()) {
if (it->second->CheckAggro(targ)) { if (it->second->CheckAggro(targ)) {
if (c) if (c) {
c->RemoveXTarget(it->second, false); c->RemoveXTarget(it->second, false);
}
it->second->RemoveFromHateList(targ); it->second->RemoveFromHateList(targ);
} }
if (c && it->second->IsOnFeignMemory(c)) { if (c && it->second->IsOnFeignMemory(c)) {
@ -3294,6 +3305,32 @@ void EntityList::ClearAggro(Mob* targ)
} }
} }
//removes "targ" from all hate lists of mobs that are water only.
void EntityList::ClearWaterAggro(Mob* targ)
{
Client *c = nullptr;
if (targ->IsClient()) {
c = targ->CastToClient();
}
auto it = npc_list.begin();
while (it != npc_list.end()) {
if (it->second->IsUnderwaterOnly()) {
if (it->second->CheckAggro(targ)) {
if (c) {
c->RemoveXTarget(it->second, false);
}
it->second->RemoveFromHateList(targ);
}
if (c && it->second->IsOnFeignMemory(c)) {
it->second->RemoveFromFeignMemory(c); //just in case we feigned
c->RemoveXTarget(it->second, false);
}
}
++it;
}
}
void EntityList::ClearFeignAggro(Mob *targ) void EntityList::ClearFeignAggro(Mob *targ)
{ {
auto it = npc_list.begin(); auto it = npc_list.begin();

View File

@ -447,6 +447,7 @@ public:
void Process(); void Process();
void ClearAggro(Mob* targ); void ClearAggro(Mob* targ);
void ClearWaterAggro(Mob* targ);
void ClearFeignAggro(Mob* targ); void ClearFeignAggro(Mob* targ);
void ClearZoneFeignAggro(Client* targ); void ClearZoneFeignAggro(Client* targ);
void AggroZone(Mob* who, uint32 hate = 0); void AggroZone(Mob* who, uint32 hate = 0);

View File

@ -2913,23 +2913,33 @@ void Client::SendItemPacket(int16 slot_id, const EQEmu::ItemInstance* inst, Item
if (!inst) if (!inst)
return; return;
if (slot_id <= EQEmu::invslot::POSSESSIONS_END && slot_id >= EQEmu::invslot::POSSESSIONS_BEGIN) { if (packet_type != ItemPacketMerchant) {
if ((((uint64)1 << slot_id) & GetInv().GetLookup()->PossessionsBitmask) == 0) if (slot_id <= EQEmu::invslot::POSSESSIONS_END && slot_id >= EQEmu::invslot::POSSESSIONS_BEGIN) {
return; if ((((uint64)1 << slot_id) & GetInv().GetLookup()->PossessionsBitmask) == 0) {
} LogError("Item not sent to merchant : slot [{}]", slot_id);
else if (slot_id <= EQEmu::invbag::GENERAL_BAGS_END && slot_id >= EQEmu::invbag::GENERAL_BAGS_BEGIN) { return;
auto temp_slot = EQEmu::invslot::GENERAL_BEGIN + ((slot_id - EQEmu::invbag::GENERAL_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT); }
if ((((uint64)1 << temp_slot) & GetInv().GetLookup()->PossessionsBitmask) == 0) }
return; else if (slot_id <= EQEmu::invbag::GENERAL_BAGS_END && slot_id >= EQEmu::invbag::GENERAL_BAGS_BEGIN) {
} auto temp_slot = EQEmu::invslot::GENERAL_BEGIN + ((slot_id - EQEmu::invbag::GENERAL_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT);
else if (slot_id <= EQEmu::invslot::BANK_END && slot_id >= EQEmu::invslot::BANK_BEGIN) { if ((((uint64)1 << temp_slot) & GetInv().GetLookup()->PossessionsBitmask) == 0) {
if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize.Bank) LogError("Item not sent to merchant2 : slot [{}]", slot_id);
return; return;
} }
else if (slot_id <= EQEmu::invbag::BANK_BAGS_END && slot_id >= EQEmu::invbag::BANK_BAGS_BEGIN) { }
auto temp_slot = (slot_id - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT; else if (slot_id <= EQEmu::invslot::BANK_END && slot_id >= EQEmu::invslot::BANK_BEGIN) {
if (temp_slot >= GetInv().GetLookup()->InventoryTypeSize.Bank) if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize.Bank) {
return; LogError("Item not sent to merchant3 : slot [{}]", slot_id);
return;
}
}
else if (slot_id <= EQEmu::invbag::BANK_BAGS_END && slot_id >= EQEmu::invbag::BANK_BAGS_BEGIN) {
auto temp_slot = (slot_id - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT;
if (temp_slot >= GetInv().GetLookup()->InventoryTypeSize.Bank) {
LogError("Item not sent to merchant4 : slot [{}]", slot_id);
return;
}
}
} }
// Serialize item into |-delimited string (Titanium- uses '|' delimiter .. newer clients use pure data serialization) // Serialize item into |-delimited string (Titanium- uses '|' delimiter .. newer clients use pure data serialization)

View File

@ -90,6 +90,11 @@ void Lua_Client::SetPVP(bool v) {
self->SetPVP(v); self->SetPVP(v);
} }
void Lua_Client::SendToGuildHall() {
Lua_Safe_Call_Void();
self->SendToGuildHall();
}
bool Lua_Client::GetPVP() { bool Lua_Client::GetPVP() {
Lua_Safe_Call_Bool(); Lua_Safe_Call_Bool();
return self->GetPVP(); return self->GetPVP();
@ -1584,6 +1589,7 @@ luabind::scope lua_register_client() {
.def("Disconnect", (void(Lua_Client::*)(void))&Lua_Client::Disconnect) .def("Disconnect", (void(Lua_Client::*)(void))&Lua_Client::Disconnect)
.def("IsLD", (bool(Lua_Client::*)(void))&Lua_Client::IsLD) .def("IsLD", (bool(Lua_Client::*)(void))&Lua_Client::IsLD)
.def("WorldKick", (void(Lua_Client::*)(void))&Lua_Client::WorldKick) .def("WorldKick", (void(Lua_Client::*)(void))&Lua_Client::WorldKick)
.def("SendToGuildHall", (void(Lua_Client::*)(void))&Lua_Client::SendToGuildHall)
.def("GetAnon", (bool(Lua_Client::*)(void))&Lua_Client::GetAnon) .def("GetAnon", (bool(Lua_Client::*)(void))&Lua_Client::GetAnon)
.def("Duck", (void(Lua_Client::*)(void))&Lua_Client::Duck) .def("Duck", (void(Lua_Client::*)(void))&Lua_Client::Duck)
.def("Stand", (void(Lua_Client::*)(void))&Lua_Client::Stand) .def("Stand", (void(Lua_Client::*)(void))&Lua_Client::Stand)

View File

@ -39,6 +39,7 @@ public:
void Disconnect(); void Disconnect();
bool IsLD(); bool IsLD();
void WorldKick(); void WorldKick();
void SendToGuildHall();
bool GetAnon(); bool GetAnon();
void Duck(); void Duck();
void Stand(); void Stand();

View File

@ -393,6 +393,18 @@ bool lua_is_disc_tome(int item_id) {
return quest_manager.isdisctome(item_id); return quest_manager.isdisctome(item_id);
} }
std::string lua_get_race_name(uint32 race_id) {
return quest_manager.getracename(race_id);
}
std::string lua_get_spell_name(uint32 spell_id) {
return quest_manager.getspellname(spell_id);
}
std::string lua_get_skill_name(int skill_id) {
return quest_manager.getskillname(skill_id);
}
void lua_safe_move() { void lua_safe_move() {
quest_manager.safemove(); quest_manager.safemove();
} }
@ -729,6 +741,10 @@ bool lua_is_task_appropriate(int task) {
return quest_manager.istaskappropriate(task); return quest_manager.istaskappropriate(task);
} }
std::string lua_get_task_name(uint32 task_id) {
return quest_manager.gettaskname(task_id);
}
void lua_popup(const char *title, const char *text, uint32 id, uint32 buttons, uint32 duration) { void lua_popup(const char *title, const char *text, uint32 id, uint32 buttons, uint32 duration) {
quest_manager.popup(title, text, id, buttons, duration); quest_manager.popup(title, text, id, buttons, duration);
} }
@ -781,6 +797,10 @@ int lua_collect_items(uint32 item_id, bool remove) {
return quest_manager.collectitems(item_id, remove); return quest_manager.collectitems(item_id, remove);
} }
int lua_count_item(uint32 item_id) {
return quest_manager.countitem(item_id);
}
void lua_update_spawn_timer(uint32 id, uint32 new_time) { void lua_update_spawn_timer(uint32 id, uint32 new_time) {
quest_manager.UpdateSpawnTimer(id, new_time); quest_manager.UpdateSpawnTimer(id, new_time);
} }
@ -803,6 +823,10 @@ std::string lua_item_link(int item_id) {
return quest_manager.varlink(text, item_id); return quest_manager.varlink(text, item_id);
} }
std::string lua_get_item_name(uint32 item_id) {
return quest_manager.getitemname(item_id);
}
std::string lua_say_link(const char *phrase, bool silent, const char *link_name) { std::string lua_say_link(const char *phrase, bool silent, const char *link_name) {
char text[256] = { 0 }; char text[256] = { 0 };
strncpy(text, phrase, 255); strncpy(text, phrase, 255);
@ -854,10 +878,50 @@ bool lua_delete_data(std::string bucket_key) {
return DataBucket::DeleteData(bucket_key); return DataBucket::DeleteData(bucket_key);
} }
const char *lua_get_char_name_by_id(uint32 char_id) {
return database.GetCharNameByID(char_id);
}
uint32 lua_get_char_id_by_name(const char* name) {
return quest_manager.getcharidbyname(name);
}
std::string lua_get_class_name(uint8 class_id) {
return quest_manager.getclassname(class_id);
}
std::string lua_get_class_name(uint8 class_id, uint8 level) {
return quest_manager.getclassname(class_id, level);
}
int lua_get_currency_id(uint32 item_id) {
return quest_manager.getcurrencyid(item_id);
}
int lua_get_currency_item_id(int currency_id) {
return quest_manager.getcurrencyitemid(currency_id);
}
const char *lua_get_guild_name_by_id(uint32 guild_id) { const char *lua_get_guild_name_by_id(uint32 guild_id) {
return quest_manager.getguildnamebyid(guild_id); return quest_manager.getguildnamebyid(guild_id);
} }
int lua_get_guild_id_by_char_id(uint32 char_id) {
return database.GetGuildIDByCharID(char_id);
}
int lua_get_group_id_by_char_id(uint32 char_id) {
return database.GetGroupIDByCharID(char_id);
}
const char *lua_get_npc_name_by_id(uint32 npc_id) {
return quest_manager.getnpcnamebyid(npc_id);
}
int lua_get_raid_id_by_char_id(uint32 char_id) {
return database.GetRaidIDByCharID(char_id);
}
uint32 lua_create_instance(const char *zone, uint32 version, uint32 duration) { uint32 lua_create_instance(const char *zone, uint32 version, uint32 duration) {
return quest_manager.CreateInstance(zone, version, duration); return quest_manager.CreateInstance(zone, version, duration);
} }
@ -910,6 +974,10 @@ void lua_remove_from_instance_by_char_id(uint32 instance_id, uint32 char_id) {
quest_manager.RemoveFromInstanceByCharID(instance_id, char_id); quest_manager.RemoveFromInstanceByCharID(instance_id, char_id);
} }
bool lua_check_instance_by_char_id(uint32 instance_id, uint32 char_id) {
return quest_manager.CheckInstanceByCharID(instance_id, char_id);
}
void lua_remove_all_from_instance(uint32 instance_id) { void lua_remove_all_from_instance(uint32 instance_id) {
quest_manager.RemoveAllFromInstance(instance_id); quest_manager.RemoveAllFromInstance(instance_id);
} }
@ -1632,6 +1700,9 @@ luabind::scope lua_register_general() {
luabind::def("depop_zone", &lua_depop_zone), luabind::def("depop_zone", &lua_depop_zone),
luabind::def("repop_zone", &lua_repop_zone), luabind::def("repop_zone", &lua_repop_zone),
luabind::def("is_disc_tome", &lua_is_disc_tome), luabind::def("is_disc_tome", &lua_is_disc_tome),
luabind::def("get_race_name", (std::string(*)(uint16))&lua_get_race_name),
luabind::def("get_spell_name", (std::string(*)(uint32))&lua_get_spell_name),
luabind::def("get_skill_name", (std::string(*)(int))&lua_get_skill_name),
luabind::def("safe_move", &lua_safe_move), luabind::def("safe_move", &lua_safe_move),
luabind::def("rain", &lua_rain), luabind::def("rain", &lua_rain),
luabind::def("snow", &lua_snow), luabind::def("snow", &lua_snow),
@ -1699,6 +1770,7 @@ luabind::scope lua_register_general() {
luabind::def("active_tasks_in_set", &lua_active_tasks_in_set), luabind::def("active_tasks_in_set", &lua_active_tasks_in_set),
luabind::def("completed_tasks_in_set", &lua_completed_tasks_in_set), luabind::def("completed_tasks_in_set", &lua_completed_tasks_in_set),
luabind::def("is_task_appropriate", &lua_is_task_appropriate), luabind::def("is_task_appropriate", &lua_is_task_appropriate),
luabind::def("get_task_name", (std::string(*)(uint32))&lua_get_task_name),
luabind::def("popup", &lua_popup), luabind::def("popup", &lua_popup),
luabind::def("clear_spawn_timers", &lua_clear_spawn_timers), luabind::def("clear_spawn_timers", &lua_clear_spawn_timers),
luabind::def("zone_emote", &lua_zone_emote), luabind::def("zone_emote", &lua_zone_emote),
@ -1712,11 +1784,13 @@ luabind::scope lua_register_general() {
luabind::def("create_door", &lua_create_door), luabind::def("create_door", &lua_create_door),
luabind::def("modify_npc_stat", &lua_modify_npc_stat), luabind::def("modify_npc_stat", &lua_modify_npc_stat),
luabind::def("collect_items", &lua_collect_items), luabind::def("collect_items", &lua_collect_items),
luabind::def("count_item", &lua_count_item),
luabind::def("update_spawn_timer", &lua_update_spawn_timer), luabind::def("update_spawn_timer", &lua_update_spawn_timer),
luabind::def("merchant_set_item", (void(*)(uint32,uint32))&lua_merchant_set_item), luabind::def("merchant_set_item", (void(*)(uint32,uint32))&lua_merchant_set_item),
luabind::def("merchant_set_item", (void(*)(uint32,uint32,uint32))&lua_merchant_set_item), luabind::def("merchant_set_item", (void(*)(uint32,uint32,uint32))&lua_merchant_set_item),
luabind::def("merchant_count_item", &lua_merchant_count_item), luabind::def("merchant_count_item", &lua_merchant_count_item),
luabind::def("item_link", &lua_item_link), luabind::def("item_link", &lua_item_link),
luabind::def("get_item_name", (std::string(*)(uint32))&lua_get_item_name),
luabind::def("say_link", (std::string(*)(const char*,bool,const char*))&lua_say_link), luabind::def("say_link", (std::string(*)(const char*,bool,const char*))&lua_say_link),
luabind::def("say_link", (std::string(*)(const char*,bool))&lua_say_link), luabind::def("say_link", (std::string(*)(const char*,bool))&lua_say_link),
luabind::def("say_link", (std::string(*)(const char*))&lua_say_link), luabind::def("say_link", (std::string(*)(const char*))&lua_say_link),
@ -1727,7 +1801,17 @@ luabind::scope lua_register_general() {
luabind::def("set_data", (void(*)(std::string, std::string))&lua_set_data), luabind::def("set_data", (void(*)(std::string, std::string))&lua_set_data),
luabind::def("set_data", (void(*)(std::string, std::string, std::string))&lua_set_data), luabind::def("set_data", (void(*)(std::string, std::string, std::string))&lua_set_data),
luabind::def("delete_data", (bool(*)(std::string))&lua_delete_data), luabind::def("delete_data", (bool(*)(std::string))&lua_delete_data),
luabind::def("get_char_name_by_id", &lua_get_char_name_by_id),
luabind::def("get_char_id_by_name", (uint32(*)(const char*))&lua_get_char_id_by_name),
luabind::def("get_class_name", (std::string(*)(uint8))&lua_get_class_name),
luabind::def("get_class_name", (std::string(*)(uint8,uint8))&lua_get_class_name),
luabind::def("get_currency_id", &lua_get_currency_id),
luabind::def("get_currency_item_id", &lua_get_currency_item_id),
luabind::def("get_guild_name_by_id", &lua_get_guild_name_by_id), luabind::def("get_guild_name_by_id", &lua_get_guild_name_by_id),
luabind::def("get_guild_id_by_char_id", &lua_get_guild_id_by_char_id),
luabind::def("get_group_id_by_char_id", &lua_get_group_id_by_char_id),
luabind::def("get_npc_name_by_id", &lua_get_npc_name_by_id),
luabind::def("get_raid_id_by_char_id", &lua_get_raid_id_by_char_id),
luabind::def("create_instance", &lua_create_instance), luabind::def("create_instance", &lua_create_instance),
luabind::def("destroy_instance", &lua_destroy_instance), luabind::def("destroy_instance", &lua_destroy_instance),
luabind::def("update_instance_timer", &lua_update_instance_timer), luabind::def("update_instance_timer", &lua_update_instance_timer),
@ -1742,6 +1826,7 @@ luabind::scope lua_register_general() {
luabind::def("assign_raid_to_instance", &lua_assign_raid_to_instance), luabind::def("assign_raid_to_instance", &lua_assign_raid_to_instance),
luabind::def("remove_from_instance", &lua_remove_from_instance), luabind::def("remove_from_instance", &lua_remove_from_instance),
luabind::def("remove_from_instance_by_char_id", &lua_remove_from_instance_by_char_id), luabind::def("remove_from_instance_by_char_id", &lua_remove_from_instance_by_char_id),
luabind::def("check_instance_by_char_id", (bool(*)(uint16, uint32))&lua_check_instance_by_char_id),
luabind::def("remove_all_from_instance", &lua_remove_all_from_instance), luabind::def("remove_all_from_instance", &lua_remove_all_from_instance),
luabind::def("flag_instance_by_group_leader", &lua_flag_instance_by_group_leader), luabind::def("flag_instance_by_group_leader", &lua_flag_instance_by_group_leader),
luabind::def("flag_instance_by_raid_leader", &lua_flag_instance_by_raid_leader), luabind::def("flag_instance_by_raid_leader", &lua_flag_instance_by_raid_leader),

View File

@ -52,14 +52,14 @@ uint32 Lua_Raid::GetTotalRaidDamage(Lua_Mob other) {
return self->GetTotalRaidDamage(other); return self->GetTotalRaidDamage(other);
} }
void Lua_Raid::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum) { void Lua_Raid::SplitMoney(uint32 gid, uint32 copper, uint32 silver, uint32 gold, uint32 platinum) {
Lua_Safe_Call_Void(); Lua_Safe_Call_Void();
self->SplitMoney(copper, silver, gold, platinum); self->SplitMoney(gid, copper, silver, gold, platinum);
} }
void Lua_Raid::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Lua_Client splitter) { void Lua_Raid::SplitMoney(uint32 gid, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Lua_Client splitter) {
Lua_Safe_Call_Void(); Lua_Safe_Call_Void();
self->SplitMoney(copper, silver, gold, platinum, splitter); self->SplitMoney(gid, copper, silver, gold, platinum, splitter);
} }
void Lua_Raid::BalanceHP(int penalty, uint32 group_id) { void Lua_Raid::BalanceHP(int penalty, uint32 group_id) {
@ -146,8 +146,8 @@ luabind::scope lua_register_raid() {
.def("GetGroup", (int(Lua_Raid::*)(Lua_Client))&Lua_Raid::GetGroup) .def("GetGroup", (int(Lua_Raid::*)(Lua_Client))&Lua_Raid::GetGroup)
.def("SplitExp", (void(Lua_Raid::*)(uint32,Lua_Mob))&Lua_Raid::SplitExp) .def("SplitExp", (void(Lua_Raid::*)(uint32,Lua_Mob))&Lua_Raid::SplitExp)
.def("GetTotalRaidDamage", (uint32(Lua_Raid::*)(Lua_Mob))&Lua_Raid::GetTotalRaidDamage) .def("GetTotalRaidDamage", (uint32(Lua_Raid::*)(Lua_Mob))&Lua_Raid::GetTotalRaidDamage)
.def("SplitMoney", (void(Lua_Raid::*)(uint32,uint32,uint32,uint32))&Lua_Raid::SplitMoney) .def("SplitMoney", (void(Lua_Raid::*)(uint32,uint32,uint32,uint32,uint32))&Lua_Raid::SplitMoney)
.def("SplitMoney", (void(Lua_Raid::*)(uint32,uint32,uint32,uint32,Lua_Client))&Lua_Raid::SplitMoney) .def("SplitMoney", (void(Lua_Raid::*)(uint32,uint32,uint32,uint32,uint32,Lua_Client))&Lua_Raid::SplitMoney)
.def("BalanceHP", (void(Lua_Raid::*)(int,uint32))&Lua_Raid::BalanceHP) .def("BalanceHP", (void(Lua_Raid::*)(int,uint32))&Lua_Raid::BalanceHP)
.def("IsLeader", (bool(Lua_Raid::*)(const char*))&Lua_Raid::IsLeader) .def("IsLeader", (bool(Lua_Raid::*)(const char*))&Lua_Raid::IsLeader)
.def("IsGroupLeader", (bool(Lua_Raid::*)(const char*))&Lua_Raid::IsGroupLeader) .def("IsGroupLeader", (bool(Lua_Raid::*)(const char*))&Lua_Raid::IsGroupLeader)

View File

@ -34,8 +34,8 @@ public:
int GetGroup(Lua_Client c); int GetGroup(Lua_Client c);
void SplitExp(uint32 exp, Lua_Mob other); void SplitExp(uint32 exp, Lua_Mob other);
uint32 GetTotalRaidDamage(Lua_Mob other); uint32 GetTotalRaidDamage(Lua_Mob other);
void SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum); void SplitMoney(uint32 gid, uint32 copper, uint32 silver, uint32 gold, uint32 platinum);
void SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Lua_Client splitter); void SplitMoney(uint32 gid, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Lua_Client splitter);
void BalanceHP(int penalty, uint32 group_id); void BalanceHP(int penalty, uint32 group_id);
bool IsLeader(const char *c); bool IsLeader(const char *c);
bool IsLeader(Lua_Client c); bool IsLeader(Lua_Client c);

View File

@ -92,7 +92,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "../common/unix.h" #include "../common/unix.h"
#endif #endif
volatile bool RunLoops = true;
extern volatile bool is_zone_loaded; extern volatile bool is_zone_loaded;
EntityList entity_list; EntityList entity_list;
@ -577,19 +576,19 @@ int main(int argc, char** argv) {
return 0; return 0;
} }
void Shutdown()
{
Zone::Shutdown(true);
LogInfo("Shutting down...");
LogSys.CloseFileLogs();
EQ::EventLoop::Get().Shutdown();
}
void CatchSignal(int sig_num) { void CatchSignal(int sig_num) {
#ifdef _WINDOWS #ifdef _WINDOWS
LogInfo("Recieved signal: [{}]", sig_num); LogInfo("Recieved signal: [{}]", sig_num);
#endif #endif
RunLoops = false; Shutdown();
}
void Shutdown()
{
Zone::Shutdown(true);
RunLoops = false;
LogInfo("Shutting down...");
LogSys.CloseFileLogs();
} }
/* Update Window Title with relevant information */ /* Update Window Title with relevant information */

View File

@ -747,6 +747,13 @@ void Client::AI_Process()
RunTo(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z); RunTo(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z);
} }
} }
if (RuleB(Character, ProcessFearedProximity) && proximity_timer.Check()) {
entity_list.ProcessMove(this, glm::vec3(GetX(), GetY(), GetZ()));
if (RuleB(TaskSystem, EnableTaskSystem) && RuleB(TaskSystem, EnableTaskProximity))
ProcessTaskProximities(GetX(), GetY(), GetZ());
m_Proximity = glm::vec3(GetX(), GetY(), GetZ());
}
return; return;
} }

View File

@ -694,11 +694,6 @@ void NPC::RemoveCash() {
bool NPC::Process() bool NPC::Process()
{ {
if (IsStunned() && stunned_timer.Check()) {
Mob::UnStun();
this->spun_timer.Disable();
}
if (p_depop) if (p_depop)
{ {
Mob* owner = entity_list.GetMob(this->ownerid); Mob* owner = entity_list.GetMob(this->ownerid);
@ -711,6 +706,11 @@ bool NPC::Process()
} }
return false; return false;
} }
if (IsStunned() && stunned_timer.Check()) {
Mob::UnStun();
this->spun_timer.Disable();
}
SpellProcess(); SpellProcess();
@ -962,7 +962,7 @@ void NPC::Depop(bool StartSpawnTimer) {
} }
bool NPC::DatabaseCastAccepted(int spell_id) { bool NPC::DatabaseCastAccepted(int spell_id) {
for (int i=0; i < 12; i++) { for (int i=0; i < EFFECT_COUNT; i++) {
switch(spells[spell_id].effectid[i]) { switch(spells[spell_id].effectid[i]) {
case SE_Stamina: { case SE_Stamina: {
if(IsEngaged() && GetHPRatio() < 100) if(IsEngaged() && GetHPRatio() < 100)
@ -3093,6 +3093,14 @@ bool NPC::AICheckCloseBeneficialSpells(
continue; continue;
} }
if (!mob->CheckLosFN(caster)) {
continue;
}
if (mob->GetReverseFactionCon(caster) >= FACTION_KINDLY) {
continue;
}
LogAICastBeneficialClose( LogAICastBeneficialClose(
"NPC [{}] Distance [{}] Cast Range [{}] Caster [{}]", "NPC [{}] Distance [{}] Cast Range [{}] Caster [{}]",
mob->GetCleanName(), mob->GetCleanName(),
@ -3101,10 +3109,6 @@ bool NPC::AICheckCloseBeneficialSpells(
caster->GetCleanName() caster->GetCleanName()
); );
if (mob->GetReverseFactionCon(caster) >= FACTION_KINDLY) {
continue;
}
if ((spell_types & SpellType_Buff) && !RuleB(NPC, BuffFriends)) { if ((spell_types & SpellType_Buff) && !RuleB(NPC, BuffFriends)) {
if (mob != caster) { if (mob != caster) {
spell_types = SpellType_Heal; spell_types = SpellType_Heal;

View File

@ -245,6 +245,27 @@ XS(XS_Client_WorldKick) {
XSRETURN_EMPTY; XSRETURN_EMPTY;
} }
XS(XS_Client_SendToGuildHall); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_SendToGuildHall) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Client::SendToGuildHall(THIS)");
{
Client *THIS;
if (sv_derived_from(ST(0), "Client")) {
IV tmp = SvIV((SV *) SvRV(ST(0)));
THIS = INT2PTR(Client *, tmp);
} else
Perl_croak(aTHX_ "THIS is not of type Client");
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
THIS->SendToGuildHall();
}
XSRETURN_EMPTY;
}
XS(XS_Client_GetAnon); /* prototype to pass -Wmissing-prototypes */ XS(XS_Client_GetAnon); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_GetAnon) { XS(XS_Client_GetAnon) {
dXSARGS; dXSARGS;
@ -2439,7 +2460,7 @@ XS(XS_Client_MemmedCount) {
RETVAL = THIS->MemmedCount(); RETVAL = THIS->MemmedCount();
XSprePUSH; XSprePUSH;
PUSHu((UV) RETVAL); PUSHu((UV) RETVAL);
} }
XSRETURN(1); XSRETURN(1);
} }
@ -4786,7 +4807,7 @@ XS(XS_Client_AddLevelBasedExp) {
if (items > 2) if (items > 2)
max_level = (uint8) SvUV(ST(2)); max_level = (uint8) SvUV(ST(2));
if (items > 3) if (items > 3)
ignore_mods = (bool) SvTRUE(ST(3)); ignore_mods = (bool) SvTRUE(ST(3));
@ -6564,6 +6585,7 @@ XS(boot_Client) {
newXSproto(strcpy(buf, "SendSound"), XS_Client_SendSound, file, "$"); newXSproto(strcpy(buf, "SendSound"), XS_Client_SendSound, file, "$");
newXSproto(strcpy(buf, "SendSpellAnim"), XS_Client_SendSpellAnim, file, "$$$"); newXSproto(strcpy(buf, "SendSpellAnim"), XS_Client_SendSpellAnim, file, "$$$");
newXSproto(strcpy(buf, "SendTargetCommand"), XS_Client_SendTargetCommand, file, "$$"); newXSproto(strcpy(buf, "SendTargetCommand"), XS_Client_SendTargetCommand, file, "$$");
newXSproto(strcpy(buf, "SendToGuildHall"), XS_Client_SendToGuildHall, file, "$");
newXSproto(strcpy(buf, "SendWebLink"), XS_Client_SendWebLink, file, "$:$"); newXSproto(strcpy(buf, "SendWebLink"), XS_Client_SendWebLink, file, "$:$");
newXSproto(strcpy(buf, "SendZoneFlagInfo"), XS_Client_SendZoneFlagInfo, file, "$$"); newXSproto(strcpy(buf, "SendZoneFlagInfo"), XS_Client_SendZoneFlagInfo, file, "$$");
newXSproto(strcpy(buf, "SetAAPoints"), XS_Client_SetAAPoints, file, "$$"); newXSproto(strcpy(buf, "SetAAPoints"), XS_Client_SetAAPoints, file, "$$");

View File

@ -247,13 +247,14 @@ XS(XS_Raid_SplitMoney); /* prototype to pass -Wmissing-prototypes */
XS(XS_Raid_SplitMoney) { XS(XS_Raid_SplitMoney) {
dXSARGS; dXSARGS;
if (items != 5) if (items != 5)
Perl_croak(aTHX_ "Usage: Raid::SplitMoney(THIS, uint32 copper, uint32 silver, uint32 gold, uint32 platinum)"); Perl_croak(aTHX_ "Usage: Raid::SplitMoney(THIS, uint32 gid, uint32 copper, uint32 silver, uint32 gold, uint32 platinum)");
{ {
Raid *THIS; Raid *THIS;
uint32 copper = (uint32) SvUV(ST(1)); uint32 gid = (uint32) SvUV(ST(1));
uint32 silver = (uint32) SvUV(ST(2)); uint32 copper = (uint32) SvUV(ST(2));
uint32 gold = (uint32) SvUV(ST(3)); uint32 silver = (uint32) SvUV(ST(3));
uint32 platinum = (uint32) SvUV(ST(4)); uint32 gold = (uint32) SvUV(ST(4));
uint32 platinum = (uint32) SvUV(ST(5));
if (sv_derived_from(ST(0), "Raid")) { if (sv_derived_from(ST(0), "Raid")) {
IV tmp = SvIV((SV *) SvRV(ST(0))); IV tmp = SvIV((SV *) SvRV(ST(0)));
@ -263,7 +264,7 @@ XS(XS_Raid_SplitMoney) {
if (THIS == nullptr) if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
THIS->SplitMoney(copper, silver, gold, platinum); THIS->SplitMoney(gid, copper, silver, gold, platinum);
} }
XSRETURN_EMPTY; XSRETURN_EMPTY;
} }
@ -569,7 +570,7 @@ XS(boot_Raid) {
newXSproto(strcpy(buf, "GetGroup"), XS_Raid_GetGroup, file, "$$"); newXSproto(strcpy(buf, "GetGroup"), XS_Raid_GetGroup, file, "$$");
newXSproto(strcpy(buf, "SplitExp"), XS_Raid_SplitExp, file, "$$$"); newXSproto(strcpy(buf, "SplitExp"), XS_Raid_SplitExp, file, "$$$");
newXSproto(strcpy(buf, "GetTotalRaidDamage"), XS_Raid_GetTotalRaidDamage, file, "$$"); newXSproto(strcpy(buf, "GetTotalRaidDamage"), XS_Raid_GetTotalRaidDamage, file, "$$");
newXSproto(strcpy(buf, "SplitMoney"), XS_Raid_SplitMoney, file, "$$$$$"); newXSproto(strcpy(buf, "SplitMoney"), XS_Raid_SplitMoney, file, "$$$$$$");
newXSproto(strcpy(buf, "BalanceHP"), XS_Raid_BalanceHP, file, "$$$"); newXSproto(strcpy(buf, "BalanceHP"), XS_Raid_BalanceHP, file, "$$$");
newXSproto(strcpy(buf, "IsLeader"), XS_Raid_IsLeader, file, "$$"); newXSproto(strcpy(buf, "IsLeader"), XS_Raid_IsLeader, file, "$$");
newXSproto(strcpy(buf, "IsGroupLeader"), XS_Raid_IsGroupLeader, file, "$$"); newXSproto(strcpy(buf, "IsGroupLeader"), XS_Raid_IsGroupLeader, file, "$$");

View File

@ -906,6 +906,31 @@ bool QuestManager::isdisctome(int item_id) {
return(true); return(true);
} }
std::string QuestManager::getracename(uint16 race_id) {
return GetRaceIDName(race_id);
}
std::string QuestManager::getspellname(uint32 spell_id) {
if (!IsValidSpell(spell_id)) {
return "INVALID SPELL ID IN GETSPELLNAME";
}
std::string spell_name = GetSpellName(spell_id);
return spell_name;
}
std::string QuestManager::getskillname(int skill_id) {
if (skill_id >= 0 && skill_id < EQEmu::skills::SkillCount) {
std::map<EQEmu::skills::SkillType, std::string> Skills = EQEmu::skills::GetSkillTypeMap();
for (auto skills_iter : Skills) {
if (skill_id == skills_iter.first) {
return skills_iter.second;
}
}
}
return std::string();
}
void QuestManager::safemove() { void QuestManager::safemove() {
QuestManagerCurrentQuestVars(); QuestManagerCurrentQuestVars();
if (initiator && initiator->IsClient()) if (initiator && initiator->IsClient())
@ -2432,6 +2457,16 @@ bool QuestManager::istaskappropriate(int task) {
return false; return false;
} }
std::string QuestManager::gettaskname(uint32 task_id) {
QuestManagerCurrentQuestVars();
if (RuleB(TaskSystem, EnableTaskSystem)) {
return taskmanager->GetTaskName(task_id);
}
return std::string();
}
void QuestManager::clearspawntimers() { void QuestManager::clearspawntimers() {
if(!zone) if(!zone)
return; return;
@ -2580,6 +2615,32 @@ int QuestManager::collectitems(uint32 item_id, bool remove)
return quantity; return quantity;
} }
int QuestManager::countitem(uint32 item_id) {
QuestManagerCurrentQuestVars();
int quantity = 0;
EQEmu::ItemInstance *item = nullptr;
static const int16 slots[][2] = {
{ EQEmu::invslot::POSSESSIONS_BEGIN, EQEmu::invslot::POSSESSIONS_END },
{ EQEmu::invbag::GENERAL_BAGS_BEGIN, EQEmu::invbag::GENERAL_BAGS_END },
{ EQEmu::invbag::CURSOR_BAG_BEGIN, EQEmu::invbag::CURSOR_BAG_END},
{ EQEmu::invslot::BANK_BEGIN, EQEmu::invslot::BANK_END },
{ EQEmu::invbag::BANK_BAGS_BEGIN, EQEmu::invbag::BANK_BAGS_END },
{ EQEmu::invslot::SHARED_BANK_BEGIN, EQEmu::invslot::SHARED_BANK_END },
{ EQEmu::invbag::SHARED_BANK_BAGS_BEGIN, EQEmu::invbag::SHARED_BANK_BAGS_END },
};
const size_t size = sizeof(slots) / sizeof(slots[0]);
for (int slot_index = 0; slot_index < size; ++slot_index) {
for (int slot_id = slots[slot_index][0]; slot_id <= slots[slot_index][1]; ++slot_id) {
item = initiator->GetInv().GetItem(slot_id);
if (item && item->GetID() == item_id) {
quantity += item->IsStackable() ? item->GetCharges() : 1;
}
}
}
return quantity;
}
void QuestManager::UpdateSpawnTimer(uint32 id, uint32 newTime) void QuestManager::UpdateSpawnTimer(uint32 id, uint32 newTime)
{ {
bool found = false; bool found = false;
@ -2670,6 +2731,23 @@ const char* QuestManager::varlink(char* perltext, int item_id) {
return perltext; return perltext;
} }
std::string QuestManager::getitemname(uint32 item_id) {
const EQEmu::ItemData* item_data = database.GetItem(item_id);
if (!item_data) {
return "INVALID ITEM ID IN GETITEMNAME";
}
std::string item_name = item_data->Name;
return item_name;
}
const char *QuestManager::getnpcnamebyid(uint32 npc_id) {
if (npc_id > 0) {
return database.GetNPCNameByID(npc_id);
}
return "";
}
uint16 QuestManager::CreateInstance(const char *zone, int16 version, uint32 duration) uint16 QuestManager::CreateInstance(const char *zone, int16 version, uint32 duration)
{ {
QuestManagerCurrentQuestVars(); QuestManagerCurrentQuestVars();
@ -2811,6 +2889,10 @@ void QuestManager::RemoveFromInstanceByCharID(uint16 instance_id, uint32 char_id
database.RemoveClientFromInstance(instance_id, char_id); database.RemoveClientFromInstance(instance_id, char_id);
} }
bool QuestManager::CheckInstanceByCharID(uint16 instance_id, uint32 char_id) {
return database.CharacterInInstanceGroup(instance_id, char_id);
}
void QuestManager::RemoveAllFromInstance(uint16 instance_id) void QuestManager::RemoveAllFromInstance(uint16 instance_id)
{ {
QuestManagerCurrentQuestVars(); QuestManagerCurrentQuestVars();
@ -2869,6 +2951,45 @@ std::string QuestManager::saylink(char *saylink_text, bool silent, const char *l
return EQEmu::SayLinkEngine::GenerateQuestSaylink(saylink_text, silent, link_name); return EQEmu::SayLinkEngine::GenerateQuestSaylink(saylink_text, silent, link_name);
} }
const char* QuestManager::getcharnamebyid(uint32 char_id) {
if (char_id > 0) {
return database.GetCharNameByID(char_id);
}
return "";
}
uint32 QuestManager::getcharidbyname(const char* name) {
return database.GetCharacterID(name);
}
std::string QuestManager::getclassname(uint8 class_id, uint8 level) {
return GetClassIDName(class_id, level);
}
int QuestManager::getcurrencyid(uint32 item_id) {
auto iter = zone->AlternateCurrencies.begin();
while (iter != zone->AlternateCurrencies.end()) {
if (item_id == (*iter).item_id) {
return (*iter).id;
}
++iter;
}
return 0;
}
int QuestManager::getcurrencyitemid(int currency_id) {
if (currency_id > 0) {
auto iter = zone->AlternateCurrencies.begin();
while (iter != zone->AlternateCurrencies.end()) {
if (currency_id == (*iter).id) {
return (*iter).item_id;
}
++iter;
}
}
return 0;
}
const char* QuestManager::getguildnamebyid(int guild_id) { const char* QuestManager::getguildnamebyid(int guild_id) {
if (guild_id > 0) if (guild_id > 0)
return guild_mgr.GetGuildName(guild_id); return guild_mgr.GetGuildName(guild_id);
@ -2876,6 +2997,27 @@ const char* QuestManager::getguildnamebyid(int guild_id) {
return(""); return("");
} }
int QuestManager::getguildidbycharid(uint32 char_id) {
if (char_id > 0) {
return database.GetGuildIDByCharID(char_id);
}
return 0;
}
int QuestManager::getgroupidbycharid(uint32 char_id) {
if (char_id > 0) {
return database.GetGroupIDByCharID(char_id);
}
return 0;
}
int QuestManager::getraididbycharid(uint32 char_id) {
if (char_id > 0) {
return database.GetRaidIDByCharID(char_id);
}
return 0;
}
void QuestManager::SetRunning(bool val) void QuestManager::SetRunning(bool val)
{ {
QuestManagerCurrentQuestVars(); QuestManagerCurrentQuestVars();

View File

@ -107,6 +107,9 @@ public:
void level(int newlevel); void level(int newlevel);
void traindisc(int discipline_tome_item_id); void traindisc(int discipline_tome_item_id);
bool isdisctome(int item_id); bool isdisctome(int item_id);
std::string getracename(uint16 race_id);
std::string getspellname(uint32 spell_id);
std::string getskillname(int skill_id);
void safemove(); void safemove();
void rain(int weather); void rain(int weather);
void snow(int weather); void snow(int weather);
@ -213,12 +216,15 @@ public:
int activetasksinset(int taskset); int activetasksinset(int taskset);
int completedtasksinset(int taskset); int completedtasksinset(int taskset);
bool istaskappropriate(int task); bool istaskappropriate(int task);
std::string gettaskname(uint32 task_id);
void clearspawntimers(); void clearspawntimers();
void ze(int type, const char *str); void ze(int type, const char *str);
void we(int type, const char *str); void we(int type, const char *str);
int getlevel(uint8 type); int getlevel(uint8 type);
int collectitems(uint32 item_id, bool remove); int collectitems(uint32 item_id, bool remove);
int collectitems_processSlot(int16 slot_id, uint32 item_id, bool remove); int collectitems_processSlot(int16 slot_id, uint32 item_id, bool remove);
int countitem(uint32 item_id);
std::string getitemname(uint32 item_id);
void enabletitle(int titleset); void enabletitle(int titleset);
bool checktitle(int titlecheck); bool checktitle(int titlecheck);
void removetitle(int titlecheck); void removetitle(int titlecheck);
@ -242,6 +248,7 @@ public:
void AssignRaidToInstance(uint16 instance_id); void AssignRaidToInstance(uint16 instance_id);
void RemoveFromInstance(uint16 instance_id); void RemoveFromInstance(uint16 instance_id);
void RemoveFromInstanceByCharID(uint16 instance_id, uint32 char_id); void RemoveFromInstanceByCharID(uint16 instance_id, uint32 char_id);
bool CheckInstanceByCharID(uint16 instance_id, uint32 char_id);
//void RemoveGroupFromInstance(uint16 instance_id); //potentially useful but not implmented at this time. //void RemoveGroupFromInstance(uint16 instance_id); //potentially useful but not implmented at this time.
//void RemoveRaidFromInstance(uint16 instance_id); //potentially useful but not implmented at this time. //void RemoveRaidFromInstance(uint16 instance_id); //potentially useful but not implmented at this time.
void RemoveAllFromInstance(uint16 instance_id); void RemoveAllFromInstance(uint16 instance_id);
@ -250,7 +257,16 @@ public:
void FlagInstanceByRaidLeader(uint32 zone, int16 version); void FlagInstanceByRaidLeader(uint32 zone, int16 version);
const char* varlink(char* perltext, int item_id); const char* varlink(char* perltext, int item_id);
std::string saylink(char *saylink_text, bool silent, const char *link_name); std::string saylink(char *saylink_text, bool silent, const char *link_name);
const char* getcharnamebyid(uint32 char_id);
uint32 getcharidbyname(const char* name);
std::string getclassname(uint8 class_id, uint8 level = 0);
int getcurrencyid(uint32 item_id);
int getcurrencyitemid(int currency_id);
const char* getguildnamebyid(int guild_id); const char* getguildnamebyid(int guild_id);
int getguildidbycharid(uint32 char_id);
int getgroupidbycharid(uint32 char_id);
const char* getnpcnamebyid(uint32 npc_id);
int getraididbycharid(uint32 char_id);
void SetRunning(bool val); void SetRunning(bool val);
bool IsRunning(); bool IsRunning();
void FlyMode(GravityBehavior flymode); void FlyMode(GravityBehavior flymode);

View File

@ -177,6 +177,7 @@ void Raid::RemoveMember(const char *characterName)
if(client) { if(client) {
client->SetRaidGrouped(false); client->SetRaidGrouped(false);
client->LeaveRaidXTargets(this); client->LeaveRaidXTargets(this);
client->p_raid_instance = nullptr;
} }
auto pack = new ServerPacket(ServerOP_RaidRemove, sizeof(ServerRaidGeneralAction_Struct)); auto pack = new ServerPacket(ServerOP_RaidRemove, sizeof(ServerRaidGeneralAction_Struct));
@ -728,15 +729,20 @@ void Raid::BalanceMana(int32 penalty, uint32 gid, float range, Mob* caster, int3
} }
//basically the same as Group's version just with more people like a lot of non group specific raid stuff //basically the same as Group's version just with more people like a lot of non group specific raid stuff
void Raid::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter){ //this only functions if the member has a group in the raid. This does not support /autosplit?
void Raid::SplitMoney(uint32 gid, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter)
{
//avoid unneeded work //avoid unneeded work
if (gid == RAID_GROUPLESS)
return;
if(copper == 0 && silver == 0 && gold == 0 && platinum == 0) if(copper == 0 && silver == 0 && gold == 0 && platinum == 0)
return; return;
uint32 i; uint32 i;
uint8 membercount = 0; uint8 membercount = 0;
for (i = 0; i < MAX_RAID_MEMBERS; i++) { for (i = 0; i < MAX_RAID_MEMBERS; i++) {
if (members[i].member != nullptr) { if (members[i].member != nullptr && members[i].GroupNumber == gid) {
membercount++; membercount++;
} }
} }
@ -809,11 +815,11 @@ void Raid::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum
msg += " as your split"; msg += " as your split";
for (i = 0; i < MAX_RAID_MEMBERS; i++) { for (i = 0; i < MAX_RAID_MEMBERS; i++) {
if (members[i].member != nullptr) { // If Group Member is Client if (members[i].member != nullptr && members[i].GroupNumber == gid) { // If Group Member is Client
//I could not get MoneyOnCorpse to work, so we use this //I could not get MoneyOnCorpse to work, so we use this
members[i].member->AddMoneyToPP(cpsplit, spsplit, gpsplit, ppsplit, true); members[i].member->AddMoneyToPP(cpsplit, spsplit, gpsplit, ppsplit, true);
members[i].member->Message(Chat::Green, msg.c_str()); members[i].member->Message(Chat::Green, msg.c_str());
} }
} }
} }
@ -1073,8 +1079,9 @@ void Raid::SendRaidRemoveAll(const char *who)
void Raid::SendRaidDisband(Client *to) void Raid::SendRaidDisband(Client *to)
{ {
if(!to) if (!to) {
return; return;
}
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct));
RaidGeneral_Struct *rg = (RaidGeneral_Struct*)outapp->pBuffer; RaidGeneral_Struct *rg = (RaidGeneral_Struct*)outapp->pBuffer;
@ -1609,7 +1616,7 @@ void Raid::SendHPManaEndPacketsFrom(Mob *mob)
return; return;
uint32 group_id = 0; uint32 group_id = 0;
if(mob->IsClient()) if(mob->IsClient())
group_id = this->GetGroup(mob->CastToClient()); group_id = this->GetGroup(mob->CastToClient());
@ -1617,7 +1624,7 @@ void Raid::SendHPManaEndPacketsFrom(Mob *mob)
EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct)); EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct));
mob->CreateHPPacket(&hpapp); mob->CreateHPPacket(&hpapp);
for(int x = 0; x < MAX_RAID_MEMBERS; x++) { for(int x = 0; x < MAX_RAID_MEMBERS; x++) {
if(members[x].member) { if(members[x].member) {
if(!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) { if(!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) {
@ -1628,7 +1635,7 @@ void Raid::SendHPManaEndPacketsFrom(Mob *mob)
mana_update->spawn_id = mob->GetID(); mana_update->spawn_id = mob->GetID();
mana_update->mana = mob->GetManaPercent(); mana_update->mana = mob->GetManaPercent();
members[x].member->QueuePacket(&outapp, false); members[x].member->QueuePacket(&outapp, false);
outapp.SetOpcode(OP_MobEnduranceUpdate); outapp.SetOpcode(OP_MobEnduranceUpdate);
MobEnduranceUpdate_Struct *endurance_update = (MobEnduranceUpdate_Struct *)outapp.pBuffer; MobEnduranceUpdate_Struct *endurance_update = (MobEnduranceUpdate_Struct *)outapp.pBuffer;
endurance_update->endurance = mob->GetEndurancePercent(); endurance_update->endurance = mob->GetEndurancePercent();

View File

@ -159,7 +159,7 @@ public:
void BalanceHP(int32 penalty, uint32 gid, float range = 0, Mob* caster = nullptr, int32 limit = 0); void BalanceHP(int32 penalty, uint32 gid, float range = 0, Mob* caster = nullptr, int32 limit = 0);
void BalanceMana(int32 penalty, uint32 gid, float range = 0, Mob* caster = nullptr, int32 limit = 0); void BalanceMana(int32 penalty, uint32 gid, float range = 0, Mob* caster = nullptr, int32 limit = 0);
void HealGroup(uint32 heal_amt, Mob* caster, uint32 gid, float range = 0); void HealGroup(uint32 heal_amt, Mob* caster, uint32 gid, float range = 0);
void SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter = nullptr); void SplitMoney(uint32 gid, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter = nullptr);
void GroupBardPulse(Mob* caster, uint16 spellid, uint32 gid); void GroupBardPulse(Mob* caster, uint16 spellid, uint32 gid);
void TeleportGroup(Mob* sender, uint32 zoneID, uint16 instance_id, float x, float y, float z, float heading, uint32 gid); void TeleportGroup(Mob* sender, uint32 zoneID, uint16 instance_id, float x, float y, float z, float heading, uint32 gid);

View File

@ -3426,6 +3426,8 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r
bool isproc, int level_override) bool isproc, int level_override)
{ {
bool is_damage_or_lifetap_spell = IsDamageSpell(spell_id) || IsLifetapSpell(spell_id);
// well we can't cast a spell on target without a target // well we can't cast a spell on target without a target
if(!spelltar) if(!spelltar)
{ {
@ -3967,9 +3969,6 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r
// send to people in the area, ignoring caster and target // send to people in the area, ignoring caster and target
//live dosent send this to anybody but the caster //live dosent send this to anybody but the caster
//entity_list.QueueCloseClients(spelltar, action_packet, true, 200, this, true, spelltar->IsClient() ? FILTER_PCSPELLS : FILTER_NPCSPELLS); //entity_list.QueueCloseClients(spelltar, action_packet, true, 200, this, true, spelltar->IsClient() ? FILTER_PCSPELLS : FILTER_NPCSPELLS);
// TEMPORARY - this is the message for the spell.
// double message on effects that use ChangeHP - working on this
message_packet = new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct)); message_packet = new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct));
CombatDamage_Struct *cd = (CombatDamage_Struct *)message_packet->pBuffer; CombatDamage_Struct *cd = (CombatDamage_Struct *)message_packet->pBuffer;
cd->target = action->target; cd->target = action->target;
@ -3980,7 +3979,9 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r
cd->hit_heading = action->hit_heading; cd->hit_heading = action->hit_heading;
cd->hit_pitch = action->hit_pitch; cd->hit_pitch = action->hit_pitch;
cd->damage = 0; cd->damage = 0;
if(!IsEffectInSpell(spell_id, SE_BindAffinity)){
auto spellOwner = GetOwnerOrSelf();
if(!IsEffectInSpell(spell_id, SE_BindAffinity) && !is_damage_or_lifetap_spell){
entity_list.QueueCloseClients( entity_list.QueueCloseClients(
spelltar, /* Sender */ spelltar, /* Sender */
message_packet, /* Packet */ message_packet, /* Packet */
@ -3990,6 +3991,13 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r
true, /* Packet ACK */ true, /* Packet ACK */
(spelltar->IsClient() ? FilterPCSpells : FilterNPCSpells) /* Message Filter Type: (8 or 9) */ (spelltar->IsClient() ? FilterPCSpells : FilterNPCSpells) /* Message Filter Type: (8 or 9) */
); );
} else if (is_damage_or_lifetap_spell && spellOwner->IsClient()) {
spellOwner->CastToClient()->QueuePacket(
message_packet,
true,
Mob::CLIENT_CONNECTINGALL,
(spelltar->IsClient() ? FilterPCSpells : FilterNPCSpells)
);
} }
safe_delete(action_packet); safe_delete(action_packet);
safe_delete(message_packet); safe_delete(message_packet);

View File

@ -955,6 +955,17 @@ bool TaskManager::AppropriateLevel(int TaskID, int PlayerLevel) {
} }
std::string TaskManager::GetTaskName(uint32 task_id)
{
if (task_id > 0 && task_id < MAXTASKS) {
if (Tasks[task_id] != nullptr) {
return Tasks[task_id]->Title;
}
}
return std::string();
}
int TaskManager::GetTaskMinLevel(int TaskID) int TaskManager::GetTaskMinLevel(int TaskID)
{ {
if (Tasks[TaskID]->MinLevel) if (Tasks[TaskID]->MinLevel)

View File

@ -299,6 +299,7 @@ public:
bool AppropriateLevel(int TaskID, int PlayerLevel); bool AppropriateLevel(int TaskID, int PlayerLevel);
int GetTaskMinLevel(int TaskID); int GetTaskMinLevel(int TaskID);
int GetTaskMaxLevel(int TaskID); int GetTaskMaxLevel(int TaskID);
std::string GetTaskName(uint32 task_id);
void TaskSetSelector(Client *c, ClientTaskState *state, Mob *mob, int TaskSetID); void TaskSetSelector(Client *c, ClientTaskState *state, Mob *mob, int TaskSetID);
void TaskQuestSetSelector(Client *c, ClientTaskState *state, Mob *mob, int count, int *tasks); // task list provided by QuestManager (perl/lua) void TaskQuestSetSelector(Client *c, ClientTaskState *state, Mob *mob, int count, int *tasks); // task list provided by QuestManager (perl/lua)
void SendActiveTasksToClient(Client *c, bool TaskComplete=false); void SendActiveTasksToClient(Client *c, bool TaskComplete=false);

View File

@ -57,7 +57,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
extern EntityList entity_list; extern EntityList entity_list;
extern Zone* zone; extern Zone* zone;
extern volatile bool is_zone_loaded; extern volatile bool is_zone_loaded;
extern void CatchSignal(int); extern void Shutdown();
extern WorldServer worldserver; extern WorldServer worldserver;
extern PetitionList petition_list; extern PetitionList petition_list;
extern uint32 numclients; extern uint32 numclients;
@ -192,8 +192,15 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
if (pack->size != sizeof(ServerConnectInfo)) if (pack->size != sizeof(ServerConnectInfo))
break; break;
ServerConnectInfo* sci = (ServerConnectInfo*)pack->pBuffer; ServerConnectInfo* sci = (ServerConnectInfo*)pack->pBuffer;
LogInfo("World assigned Port: [{}] for this zone", sci->port);
ZoneConfig::SetZonePort(sci->port); if (sci->port == 0) {
LogCritical("World did not have a port to assign from this server, the port range was not large enough.");
Shutdown();
}
else {
LogInfo("World assigned Port: [{}] for this zone", sci->port);
ZoneConfig::SetZonePort(sci->port);
}
break; break;
} }
case ServerOP_ChannelMessage: { case ServerOP_ChannelMessage: {
@ -482,7 +489,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
} }
case ServerOP_ShutdownAll: { case ServerOP_ShutdownAll: {
entity_list.Save(); entity_list.Save();
CatchSignal(2); Shutdown();
break; break;
} }
case ServerOP_ZoneShutdown: { case ServerOP_ZoneShutdown: {
@ -1874,9 +1881,11 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
} }
case ServerOP_UCSServerStatusReply: case ServerOP_UCSServerStatusReply:
{ {
auto ucsss = (UCSServerStatus_Struct*)pack->pBuffer; auto ucsss = (UCSServerStatus_Struct *) pack->pBuffer;
if (zone) if (zone) {
zone->SetUCSServerAvailable((ucsss->available != 0), ucsss->timestamp); zone->SetUCSServerAvailable((ucsss->available != 0), ucsss->timestamp);
LogInfo("UCS Server is now [{}]", (ucsss->available == 1 ? "online" : "offline"));
}
break; break;
} }
case ServerOP_CZSetEntityVariableByNPCTypeID: case ServerOP_CZSetEntityVariableByNPCTypeID:

View File

@ -140,7 +140,7 @@ bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) {
if(iInstanceID != 0) if(iInstanceID != 0)
{ {
auto pack = new ServerPacket(ServerOP_AdventureZoneData, sizeof(uint16)); auto pack = new ServerPacket(ServerOP_AdventureZoneData, sizeof(uint16));
*((uint16*)pack->pBuffer) = iInstanceID; *((uint16*)pack->pBuffer) = iInstanceID;
worldserver.SendPacket(pack); worldserver.SendPacket(pack);
delete pack; delete pack;
} }
@ -330,81 +330,156 @@ bool Zone::LoadGroundSpawns() {
return(true); return(true);
} }
int Zone::SaveTempItem(uint32 merchantid, uint32 npcid, uint32 item, int32 charges, bool sold) { void Zone::DumpMerchantList(uint32 npcid) {
int freeslot = 0;
std::list<MerchantList> merlist = merchanttable[merchantid];
std::list<MerchantList>::const_iterator itr;
uint32 i = 1;
for (itr = merlist.begin(); itr != merlist.end(); ++itr) {
MerchantList ml = *itr;
if (ml.item == item)
return 0;
// Account for merchant lists with gaps in them.
if (ml.slot >= i)
i = ml.slot + 1;
}
std::list<TempMerchantList> tmp_merlist = tmpmerchanttable[npcid]; std::list<TempMerchantList> tmp_merlist = tmpmerchanttable[npcid];
std::list<TempMerchantList>::const_iterator tmp_itr; std::list<TempMerchantList>::const_iterator tmp_itr;
bool update_charges = false;
TempMerchantList ml; TempMerchantList ml;
while (freeslot == 0 && !update_charges) {
freeslot = i; for (tmp_itr = tmp_merlist.begin(); tmp_itr != tmp_merlist.end(); ++tmp_itr) {
for (tmp_itr = tmp_merlist.begin(); tmp_itr != tmp_merlist.end(); ++tmp_itr) { ml = *tmp_itr;
ml = *tmp_itr;
if (ml.item == item) { LogInventory("slot[{}] Orig[{}] Item[{}] Charges[{}]", ml.slot, ml.origslot, ml.item, ml.charges);
update_charges = true;
freeslot = 0;
break;
}
if ((ml.slot == i) || (ml.origslot == i)) {
freeslot = 0;
}
}
i++;
} }
if (update_charges) { }
int Zone::SaveTempItem(uint32 merchantid, uint32 npcid, uint32 item, int32 charges, bool sold) {
LogInventory("Transaction of [{}] [{}]", charges, item);
//DumpMerchantList(npcid);
// Iterate past main items.
// If the item being transacted is in this list, return 0;
std::list<MerchantList> merlist = merchanttable[merchantid];
std::list<MerchantList>::const_iterator itr;
uint32 temp_slot_index = 1;
for (itr = merlist.begin(); itr != merlist.end(); ++itr) {
MerchantList ml = *itr;
if (ml.item == item) {
return 0;
}
// Account for merchant lists with gaps in them.
if (ml.slot >= temp_slot_index) {
temp_slot_index = ml.slot + 1;
}
}
LogInventory("Searching Temporary List. Main list ended at [{}]", temp_slot_index-1);
// Now search the temporary list.
std::list<TempMerchantList> tmp_merlist = tmpmerchanttable[npcid];
std::list<TempMerchantList>::const_iterator tmp_itr;
TempMerchantList ml;
uint32 first_empty_slot = 0; // Save 1st vacant slot while searching..
bool found = false;
for (tmp_itr = tmp_merlist.begin(); tmp_itr != tmp_merlist.end(); ++tmp_itr) {
ml = *tmp_itr;
if (ml.item == item) {
found = true;
LogInventory("Item found in temp list at [{}] with [{}] charges", ml.origslot, ml.charges);
break;
}
}
if (found) {
tmp_merlist.clear(); tmp_merlist.clear();
std::list<TempMerchantList> oldtmp_merlist = tmpmerchanttable[npcid]; std::list<TempMerchantList> oldtmp_merlist = tmpmerchanttable[npcid];
for (tmp_itr = oldtmp_merlist.begin(); tmp_itr != oldtmp_merlist.end(); ++tmp_itr) { for (tmp_itr = oldtmp_merlist.begin(); tmp_itr != oldtmp_merlist.end(); ++tmp_itr) {
TempMerchantList ml2 = *tmp_itr; TempMerchantList ml2 = *tmp_itr;
if(ml2.item != item) if(ml2.item != item)
tmp_merlist.push_back(ml2); tmp_merlist.push_back(ml2);
else {
if (sold) {
LogInventory("Total charges is [{}] + [{}] charges", ml.charges, charges);
ml.charges = ml.charges + charges;
}
else {
ml.charges = charges;
LogInventory("new charges is [{}] charges", ml.charges);
}
if (!ml.origslot) {
ml.origslot = ml.slot;
}
if (charges > 0) {
database.SaveMerchantTemp(npcid, ml.origslot, item, ml.charges);
tmp_merlist.push_back(ml);
}
else {
database.DeleteMerchantTemp(npcid, ml.origslot);
}
}
} }
if (sold)
ml.charges = ml.charges + charges;
else
ml.charges = charges;
if (!ml.origslot)
ml.origslot = ml.slot;
if (charges > 0) {
database.SaveMerchantTemp(npcid, ml.origslot, item, ml.charges);
tmp_merlist.push_back(ml);
}
else {
database.DeleteMerchantTemp(npcid, ml.origslot);
}
tmpmerchanttable[npcid] = tmp_merlist; tmpmerchanttable[npcid] = tmp_merlist;
//DumpMerchantList(npcid);
if (sold) return ml.slot;
return ml.slot;
} }
if (freeslot) { else {
if (charges < 0) //sanity check only, shouldnt happen if (charges < 0) { //sanity check only, shouldnt happen
charges = 0x7FFF; charges = 0x7FFF;
database.SaveMerchantTemp(npcid, freeslot, item, charges); }
// Find an ununsed db slot #
std::list<int> slots;
TempMerchantList ml3;
for (tmp_itr = tmp_merlist.begin(); tmp_itr != tmp_merlist.end(); ++tmp_itr) {
ml3 = *tmp_itr;
slots.push_back(ml3.origslot);
}
slots.sort();
std::list<int>::const_iterator slots_itr;
uint32 first_empty_slot = 0;
uint32 idx = temp_slot_index;
for (slots_itr = slots.begin(); slots_itr != slots.end(); ++slots_itr) {
if (!first_empty_slot && *slots_itr > idx) {
LogInventory("Popped [{}]", *slots_itr);
LogInventory("First Gap Found at [{}]", idx);
break;
}
++idx;
}
first_empty_slot = idx;
// Find an ununsed mslot
slots.clear();
for (tmp_itr = tmp_merlist.begin(); tmp_itr != tmp_merlist.end(); ++tmp_itr) {
ml3 = *tmp_itr;
slots.push_back(ml3.slot);
}
slots.sort();
uint32 first_empty_mslot=0;
idx = temp_slot_index;
for (slots_itr = slots.begin(); slots_itr != slots.end(); ++slots_itr) {
if (!first_empty_mslot && *slots_itr > idx) {
LogInventory("Popped [{}]", *slots_itr);
LogInventory("First Gap Found at [{}]", idx);
break;
}
++idx;
}
first_empty_mslot = idx;
database.SaveMerchantTemp(npcid, first_empty_slot, item, charges);
tmp_merlist = tmpmerchanttable[npcid]; tmp_merlist = tmpmerchanttable[npcid];
TempMerchantList ml2; TempMerchantList ml2;
ml2.charges = charges; ml2.charges = charges;
LogInventory("Adding slot [{}] with [{}] charges.", first_empty_mslot, charges);
ml2.item = item; ml2.item = item;
ml2.npcid = npcid; ml2.npcid = npcid;
ml2.slot = freeslot; ml2.slot = first_empty_mslot;
ml2.origslot = ml2.slot; ml2.origslot = first_empty_slot;
tmp_merlist.push_back(ml2); tmp_merlist.push_back(ml2);
tmpmerchanttable[npcid] = tmp_merlist; tmpmerchanttable[npcid] = tmp_merlist;
//DumpMerchantList(npcid);
return ml2.slot;
} }
return freeslot;
} }
uint32 Zone::GetTempMerchantQuantity(uint32 NPCID, uint32 Slot) { uint32 Zone::GetTempMerchantQuantity(uint32 NPCID, uint32 Slot) {
@ -413,8 +488,10 @@ uint32 Zone::GetTempMerchantQuantity(uint32 NPCID, uint32 Slot) {
std::list<TempMerchantList>::const_iterator Iterator; std::list<TempMerchantList>::const_iterator Iterator;
for (Iterator = TmpMerchantList.begin(); Iterator != TmpMerchantList.end(); ++Iterator) for (Iterator = TmpMerchantList.begin(); Iterator != TmpMerchantList.end(); ++Iterator)
if ((*Iterator).slot == Slot) if ((*Iterator).slot == Slot) {
LogInventory("Slot [{}] has [{}] charges.", Slot, (*Iterator).charges);
return (*Iterator).charges; return (*Iterator).charges;
}
return 0; return 0;
} }
@ -491,7 +568,7 @@ void Zone::LoadNewMerchantData(uint32 merchantid) {
void Zone::GetMerchantDataForZoneLoad() { void Zone::GetMerchantDataForZoneLoad() {
LogInfo("Loading Merchant Lists"); LogInfo("Loading Merchant Lists");
std::string query = StringFormat( std::string query = StringFormat(
"SELECT " "SELECT "
"DISTINCT ml.merchantid, " "DISTINCT ml.merchantid, "
"ml.slot, " "ml.slot, "
@ -734,7 +811,7 @@ void Zone::Shutdown(bool quiet)
if (RuleB(Zone, KillProcessOnDynamicShutdown)) { if (RuleB(Zone, KillProcessOnDynamicShutdown)) {
LogInfo("[KillProcessOnDynamicShutdown] Shutting down"); LogInfo("[KillProcessOnDynamicShutdown] Shutting down");
std::exit(EXIT_SUCCESS); EQ::EventLoop::Get().Shutdown();
} }
} }
@ -816,7 +893,7 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name)
{ {
LogDebug("Graveyard ID is [{}]", graveyard_id()); LogDebug("Graveyard ID is [{}]", graveyard_id());
bool GraveYardLoaded = database.GetZoneGraveyard(graveyard_id(), &pgraveyard_zoneid, &m_Graveyard.x, &m_Graveyard.y, &m_Graveyard.z, &m_Graveyard.w); bool GraveYardLoaded = database.GetZoneGraveyard(graveyard_id(), &pgraveyard_zoneid, &m_Graveyard.x, &m_Graveyard.y, &m_Graveyard.z, &m_Graveyard.w);
if (GraveYardLoaded) { if (GraveYardLoaded) {
LogDebug("Loaded a graveyard for zone [{}]: graveyard zoneid is [{}] at [{}]", short_name, graveyard_zoneid(), to_string(m_Graveyard).c_str()); LogDebug("Loaded a graveyard for zone [{}]: graveyard zoneid is [{}] at [{}]", short_name, graveyard_zoneid(), to_string(m_Graveyard).c_str());
} }
@ -907,7 +984,7 @@ Zone::~Zone() {
//Modified for timezones. //Modified for timezones.
bool Zone::Init(bool iStaticZone) { bool Zone::Init(bool iStaticZone) {
SetStaticZone(iStaticZone); SetStaticZone(iStaticZone);
//load the zone config file. //load the zone config file.
if (!LoadZoneCFG(zone->GetShortName(), zone->GetInstanceVersion())) // try loading the zone name... if (!LoadZoneCFG(zone->GetShortName(), zone->GetInstanceVersion())) // try loading the zone name...
LoadZoneCFG(zone->GetFileName(), zone->GetInstanceVersion()); // if that fails, try the file name, then load defaults LoadZoneCFG(zone->GetFileName(), zone->GetInstanceVersion()); // if that fails, try the file name, then load defaults
@ -1089,7 +1166,7 @@ bool Zone::LoadZoneCFG(const char* filename, uint16 instance_id)
if (instance_id != 0) if (instance_id != 0)
{ {
safe_delete_array(map_name); safe_delete_array(map_name);
if(!database.GetZoneCFG(database.GetZoneID(filename), 0, &newzone_data, can_bind, can_combat, can_levitate, if(!database.GetZoneCFG(database.GetZoneID(filename), 0, &newzone_data, can_bind, can_combat, can_levitate,
can_castoutdoor, is_city, is_hotzone, allow_mercs, max_movement_update_range, zone_type, default_ruleset, &map_name)) can_castoutdoor, is_city, is_hotzone, allow_mercs, max_movement_update_range, zone_type, default_ruleset, &map_name))
{ {
LogError("Error loading the Zone Config"); LogError("Error loading the Zone Config");
@ -2455,3 +2532,13 @@ void Zone::SetQuestHotReloadQueued(bool in_quest_hot_reload_queued)
{ {
quest_hot_reload_queued = in_quest_hot_reload_queued; quest_hot_reload_queued = in_quest_hot_reload_queued;
} }
uint32 Zone::GetInstanceTimeRemaining() const
{
return instance_time_remaining;
}
void Zone::SetInstanceTimeRemaining(uint32 instance_time_remaining)
{
Zone::instance_time_remaining = instance_time_remaining;
}

View File

@ -163,6 +163,7 @@ public:
inline void ShowNPCGlobalLoot(Client *to, NPC *who) { m_global_loot.ShowNPCGlobalLoot(to, who); } inline void ShowNPCGlobalLoot(Client *to, NPC *who) { m_global_loot.ShowNPCGlobalLoot(to, who); }
inline void ShowZoneGlobalLoot(Client *to) { m_global_loot.ShowZoneGlobalLoot(to); } inline void ShowZoneGlobalLoot(Client *to) { m_global_loot.ShowZoneGlobalLoot(to); }
int GetZoneTotalBlockedSpells() { return zone_total_blocked_spells; } int GetZoneTotalBlockedSpells() { return zone_total_blocked_spells; }
void DumpMerchantList(uint32 npcid);
int SaveTempItem(uint32 merchantid, uint32 npcid, uint32 item, int32 charges, bool sold = false); int SaveTempItem(uint32 merchantid, uint32 npcid, uint32 item, int32 charges, bool sold = false);
int32 MobsAggroCount() { return aggroedmobs; } int32 MobsAggroCount() { return aggroedmobs; }
@ -278,6 +279,9 @@ public:
ZonePoint *GetClosestZonePoint(const glm::vec3 &location, uint32 to, Client *client, float max_distance = 40000.0f); ZonePoint *GetClosestZonePoint(const glm::vec3 &location, uint32 to, Client *client, float max_distance = 40000.0f);
ZonePoint *GetClosestZonePointWithoutZone(float x, float y, float z, Client *client, float max_distance = 40000.0f); ZonePoint *GetClosestZonePointWithoutZone(float x, float y, float z, Client *client, float max_distance = 40000.0f);
uint32 GetInstanceTimeRemaining() const;
void SetInstanceTimeRemaining(uint32 instance_time_remaining);
/** /**
* GMSay Callback for LogSys * GMSay Callback for LogSys
* *
@ -361,6 +365,7 @@ private:
uint8 zone_type; uint8 zone_type;
uint16 instanceversion; uint16 instanceversion;
uint32 instanceid; uint32 instanceid;
uint32 instance_time_remaining;
uint32 pgraveyard_id, pgraveyard_zoneid; uint32 pgraveyard_id, pgraveyard_zoneid;
uint32 pMaxClients; uint32 pMaxClients;
uint32 zoneid; uint32 zoneid;

View File

@ -3703,7 +3703,7 @@ void ZoneDatabase::LoadBuffs(Client *client)
if (!IsValidSpell(buffs[index].spellid)) if (!IsValidSpell(buffs[index].spellid))
continue; continue;
for (int effectIndex = 0; effectIndex < 12; ++effectIndex) { for (int effectIndex = 0; effectIndex < EFFECT_COUNT; ++effectIndex) {
if (spells[buffs[index].spellid].effectid[effectIndex] == SE_Charm) { if (spells[buffs[index].spellid].effectid[effectIndex] == SE_Charm) {
buffs[index].spellid = SPELL_UNKNOWN; buffs[index].spellid = SPELL_UNKNOWN;