mirror of
https://github.com/EQEmu/Server.git
synced 2026-02-03 04:03:53 +00:00
commit
7bea9a7273
18
.gitignore
vendored
18
.gitignore
vendored
@ -37,4 +37,20 @@ perl/
|
||||
submodules/*
|
||||
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/
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# EQEmulator Core Server
|
||||
|Travis CI (Linux)|Appveyor w/ Bots (Windows) |Appveyor w/o Bots (Windows) |
|
||||
|Travis CI (Linux)|Appveyor (Windows x86) |Appveyor (Windows x64) |
|
||||
|:---:|:---:|:---:|
|
||||
|[](https://travis-ci.org/EQEmu/Server) |[](https://ci.appveyor.com/project/KimLS/server-87crp/branch/master) |[](https://ci.appveyor.com/project/KimLS/server-w0pq2/branch/master) |
|
||||
|[](https://travis-ci.org/EQEmu/Server) |[](https://ci.appveyor.com/project/KimLS/server) |[](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
|
||||
- [EQEmulator Forums](http://www.eqemulator.org/forums)
|
||||
- [EQEmulator Wiki](https://github.com/EQEmu/Server/wiki)
|
||||
- [EQEmulator Wiki](https://eqemu.gitbook.io/)
|
||||
|
||||
## Related Repositories
|
||||
* [ProjectEQ Quests](https://github.com/ProjectEQ/projecteqquests)
|
||||
|
||||
@ -9,6 +9,7 @@ SET(common_sources
|
||||
crash.cpp
|
||||
crc16.cpp
|
||||
crc32.cpp
|
||||
database/database_dump_service.cpp
|
||||
database.cpp
|
||||
database_conversions.cpp
|
||||
database_instances.cpp
|
||||
@ -31,6 +32,7 @@ SET(common_sources
|
||||
event_sub.cpp
|
||||
extprofile.cpp
|
||||
faction.cpp
|
||||
file_util.cpp
|
||||
guild_base.cpp
|
||||
guilds.cpp
|
||||
inventory_profile.cpp
|
||||
@ -120,6 +122,7 @@ SET(common_headers
|
||||
cli/argh.h
|
||||
cli/eqemu_command_handler.h
|
||||
cli/terminal_color.hpp
|
||||
database/database_dump_service.h
|
||||
data_verification.h
|
||||
database.h
|
||||
database_schema.h
|
||||
@ -150,6 +153,7 @@ SET(common_headers
|
||||
event_sub.h
|
||||
extprofile.h
|
||||
faction.h
|
||||
file_util.h
|
||||
features.h
|
||||
fixed_memory_hash_set.h
|
||||
fixed_memory_variable_hash_set.h
|
||||
|
||||
@ -96,7 +96,7 @@ namespace EQEmuCommand {
|
||||
"\nCommand" <<
|
||||
termcolor::reset << "\n\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;
|
||||
|
||||
std::cout << command_string.str() << std::endl;
|
||||
|
||||
@ -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() {
|
||||
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]);
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
@ -2335,3 +2405,4 @@ int Database::GetInstanceID(uint32 char_id, uint32 zone_id) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -133,9 +133,13 @@ public:
|
||||
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 GetGuildIDByCharID(uint32 char_id);
|
||||
uint32 GetGroupIDByCharID(uint32 char_id);
|
||||
uint32 GetRaidIDByCharID(uint32 char_id);
|
||||
|
||||
void GetAccountName(uint32 accountid, char* name, uint32* oLSAccountID = 0);
|
||||
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);
|
||||
|
||||
/* Instancing */
|
||||
@ -192,19 +196,19 @@ public:
|
||||
|
||||
void GetAccountFromID(uint32 id, char* oAccountName, int16* oStatus);
|
||||
void SetAgreementFlag(uint32 acctid);
|
||||
|
||||
|
||||
int GetIPExemption(std::string account_ip);
|
||||
|
||||
int GetInstanceID(uint32 char_id, uint32 zone_id);
|
||||
|
||||
|
||||
/* Groups */
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
||||
uint32 GetGroupID(const char* name);
|
||||
|
||||
|
||||
void ClearGroup(uint32 gid = 0);
|
||||
void ClearGroupLeader(uint32 gid = 0);
|
||||
void SetGroupID(const char* name, uint32 id, uint32 charid, uint32 ismerc = false);
|
||||
|
||||
569
common/database/database_dump_service.cpp
Normal file
569
common/database/database_dump_service.cpp
Normal 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;
|
||||
}
|
||||
91
common/database/database_dump_service.h
Normal file
91
common/database/database_dump_service.h
Normal 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
|
||||
@ -97,42 +97,53 @@ bool Database::CheckInstanceExists(uint16 instance_id) {
|
||||
bool Database::CheckInstanceExpired(uint16 instance_id)
|
||||
{
|
||||
|
||||
int32 start_time = 0;
|
||||
int32 duration = 0;
|
||||
int32 start_time = 0;
|
||||
int32 duration = 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);
|
||||
|
||||
if (!results.Success())
|
||||
if (!results.Success()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
if (results.RowCount() == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
start_time = atoi(row[0]);
|
||||
duration = atoi(row[1]);
|
||||
start_time = atoi(row[0]);
|
||||
duration = atoi(row[1]);
|
||||
never_expires = atoi(row[2]);
|
||||
|
||||
if (never_expires == 1)
|
||||
if (never_expires == 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
timeval tv;
|
||||
timeval tv{};
|
||||
gettimeofday(&tv, nullptr);
|
||||
|
||||
if ((start_time + duration) <= tv.tv_sec)
|
||||
return true;
|
||||
return (start_time + duration) <= tv.tv_sec;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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)"
|
||||
" values(%lu, %lu, %lu, UNIX_TIMESTAMP(), %lu)",
|
||||
(unsigned long)instance_id, (unsigned long)zone_id, (unsigned long)version, (unsigned long)duration);
|
||||
std::string query = StringFormat(
|
||||
"INSERT INTO instance_list (id, zone, version, start_time, duration)"
|
||||
" values (%u, %u, %u, UNIX_TIMESTAMP(), %u)",
|
||||
instance_id,
|
||||
zone_id,
|
||||
version,
|
||||
duration
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
return results.Success();
|
||||
@ -140,66 +151,84 @@ bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version
|
||||
|
||||
bool Database::GetUnusedInstanceID(uint16 &instance_id)
|
||||
{
|
||||
uint32 count = RuleI(Zone, ReservedInstances);
|
||||
uint32 max = 65535;
|
||||
uint32 max_reserved_instance_id = RuleI(Instances, ReservedInstances);
|
||||
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);
|
||||
|
||||
if (!results.Success())
|
||||
{
|
||||
if (!results.Success()) {
|
||||
instance_id = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
{
|
||||
instance_id = 0;
|
||||
return false;
|
||||
if (results.RowCount() == 0) {
|
||||
instance_id = max_reserved_instance_id;
|
||||
return true;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
if (atoi(row[0]) <= max)
|
||||
{
|
||||
if (atoi(row[0]) <= max) {
|
||||
instance_id = atoi(row[0]);
|
||||
|
||||
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);
|
||||
|
||||
if (!results.Success())
|
||||
{
|
||||
if (!results.Success()) {
|
||||
instance_id = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
{
|
||||
if (results.RowCount() == 0) {
|
||||
instance_id = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
count++;
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
{
|
||||
if (count < atoi(row[0]))
|
||||
{
|
||||
instance_id = count;
|
||||
max_reserved_instance_id++;
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
if (max_reserved_instance_id < atoi(row[0])) {
|
||||
instance_id = max_reserved_instance_id;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (count > max)
|
||||
{
|
||||
if (max_reserved_instance_id > max) {
|
||||
instance_id = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
count++;
|
||||
max_reserved_instance_id++;
|
||||
}
|
||||
|
||||
instance_id = count;
|
||||
instance_id = max_reserved_instance_id;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -486,8 +515,7 @@ void Database::BuryCorpsesInInstance(uint16 instance_id) {
|
||||
void Database::DeleteInstance(uint16 instance_id)
|
||||
{
|
||||
|
||||
std::string query = StringFormat("DELETE FROM instance_list WHERE id=%u", instance_id);
|
||||
QueryDatabase(query);
|
||||
std::string query;
|
||||
|
||||
query = StringFormat("DELETE FROM instance_list_player WHERE id=%u", instance_id);
|
||||
QueryDatabase(query);
|
||||
@ -548,17 +576,36 @@ void Database::GetCharactersInInstance(uint16 instance_id, std::list<uint32> &ch
|
||||
|
||||
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);
|
||||
|
||||
if (!results.Success())
|
||||
if (!results.Success()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
if (results.RowCount() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
DeleteInstance(atoi(row[0]));
|
||||
}
|
||||
}
|
||||
|
||||
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(), "
|
||||
"duration=%u WHERE id=%u", new_duration, instance_id);
|
||||
auto results = QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
*/
|
||||
@ -129,6 +130,7 @@ namespace DatabaseSchema {
|
||||
"character_tribute",
|
||||
"completed_tasks",
|
||||
"data_buckets",
|
||||
"discovered_items",
|
||||
"faction_values",
|
||||
"friends",
|
||||
"guild_bank",
|
||||
@ -141,9 +143,12 @@ namespace DatabaseSchema {
|
||||
"inventory_snapshots",
|
||||
"keyring",
|
||||
"mail",
|
||||
"petitions",
|
||||
"player_titlesets",
|
||||
"quest_globals",
|
||||
"sharedbank",
|
||||
"spell_buckets",
|
||||
"spell_globals",
|
||||
"timers",
|
||||
"titles",
|
||||
"trader",
|
||||
@ -233,7 +238,6 @@ namespace DatabaseSchema {
|
||||
"task_activities",
|
||||
"tasks",
|
||||
"tasksets",
|
||||
"titles",
|
||||
"tradeskill_recipe",
|
||||
"tradeskill_recipe_entries",
|
||||
"traps",
|
||||
@ -255,33 +259,49 @@ namespace DatabaseSchema {
|
||||
static std::vector<std::string> GetServerTables()
|
||||
{
|
||||
return {
|
||||
"banned_ips",
|
||||
"bugs",
|
||||
"bug_reports",
|
||||
"chatchannels",
|
||||
"command_settings",
|
||||
"db_str",
|
||||
"discovered_items",
|
||||
"eqtime",
|
||||
"eventlog",
|
||||
"gm_ips",
|
||||
"hackers",
|
||||
"ip_exemptions",
|
||||
"launcher",
|
||||
"launcher_zones",
|
||||
"level_exp_mods",
|
||||
"logsys_categories",
|
||||
"name_filter",
|
||||
"perl_event_export_settings",
|
||||
"petitions",
|
||||
"profanity_list",
|
||||
"reports",
|
||||
"rule_sets",
|
||||
"rule_values",
|
||||
"saylink",
|
||||
"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
|
||||
* Tables that keep track of server state
|
||||
@ -292,9 +312,15 @@ namespace DatabaseSchema {
|
||||
{
|
||||
return {
|
||||
"adventure_members",
|
||||
"chatchannels",
|
||||
"banned_ips",
|
||||
"bug_reports",
|
||||
"bugs",
|
||||
"eventlog",
|
||||
"gm_ips",
|
||||
"group_id",
|
||||
"group_leaders",
|
||||
"hackers",
|
||||
"ip_exemptions",
|
||||
"item_tick",
|
||||
"lfguild",
|
||||
"merchantlist_temp",
|
||||
@ -302,9 +328,10 @@ namespace DatabaseSchema {
|
||||
"raid_details",
|
||||
"raid_leaders",
|
||||
"raid_members",
|
||||
"reports",
|
||||
"respawn_times",
|
||||
"spell_buckets",
|
||||
"spell_globals",
|
||||
"saylink",
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -25,6 +25,10 @@ namespace EQ
|
||||
uv_run(&m_loop, UV_RUN_DEFAULT);
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
uv_stop(&m_loop);
|
||||
}
|
||||
|
||||
uv_loop_t* Handle() { return &m_loop; }
|
||||
|
||||
private:
|
||||
|
||||
67
common/file_util.cpp
Normal file
67
common/file_util.cpp
Normal 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
32
common/file_util.h
Normal 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
|
||||
@ -912,7 +912,7 @@ bool BaseGuildManager::GetEntireGuild(uint32 guild_id, std::vector<CharGuildInfo
|
||||
return(false);
|
||||
|
||||
//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);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
@ -941,7 +941,7 @@ bool BaseGuildManager::GetCharInfo(const char *char_name, CharGuildInfo &into) {
|
||||
m_db->DoEscapeString(esc, char_name, nl);
|
||||
|
||||
//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);
|
||||
auto results = m_db->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
@ -969,9 +969,9 @@ bool BaseGuildManager::GetCharInfo(uint32 char_id, CharGuildInfo &into) {
|
||||
//load up the rank info for each guild.
|
||||
std::string query;
|
||||
#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
|
||||
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
|
||||
auto results = m_db->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
|
||||
@ -605,6 +605,8 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
|
||||
ProcessDecodedPacket(StaticPacket(current, subpacket_length));
|
||||
current += subpacket_length;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_SessionRequest:
|
||||
|
||||
@ -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, 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_BOOL(Character, ProcessFearedProximity, false, "Processes proximity checks when feared")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
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_BOOL(Zone, UsePEQZoneDebuffs, true, "Will determine if #peqzone will debuff players or not when used")
|
||||
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, RadiantCrystalItemID, 40903, "")
|
||||
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_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_INT
|
||||
#undef RULE_REAL
|
||||
|
||||
@ -129,13 +129,17 @@ void Timer::SetTimer(uint32 set_timer_time) {
|
||||
}
|
||||
}
|
||||
|
||||
uint32 Timer::GetRemainingTime() const {
|
||||
uint32 Timer::GetRemainingTime() const
|
||||
{
|
||||
if (enabled) {
|
||||
if (current_time - start_time > timer_time)
|
||||
if (current_time - start_time > timer_time) {
|
||||
return 0;
|
||||
else
|
||||
}
|
||||
else {
|
||||
return (start_time + timer_time) - current_time;
|
||||
} else {
|
||||
}
|
||||
}
|
||||
else {
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,10 +34,10 @@
|
||||
* 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
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9026
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9027
|
||||
#else
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 0 // must be 0
|
||||
#endif
|
||||
|
||||
@ -47,8 +47,13 @@ ChatChannel::ChatChannel(std::string inName, std::string inOwner, std::string in
|
||||
|
||||
Moderated = false;
|
||||
|
||||
LogInfo("New ChatChannel created: Name: [[{}]], Owner: [[{}]], Password: [[{}]], MinStatus: [{}]",
|
||||
Name.c_str(), Owner.c_str(), Password.c_str(), MinimumStatus);
|
||||
LogDebug(
|
||||
"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) {
|
||||
|
||||
LogInfo("RemoveChannel([{}])", Channel->GetName().c_str());
|
||||
LogDebug("RemoveChannel ([{}])", Channel->GetName().c_str());
|
||||
|
||||
LinkedListIterator<ChatChannel*> iterator(ChatChannels);
|
||||
|
||||
@ -175,7 +180,7 @@ void ChatChannelList::RemoveChannel(ChatChannel *Channel) {
|
||||
|
||||
void ChatChannelList::RemoveAllChannels() {
|
||||
|
||||
LogInfo("RemoveAllChannels");
|
||||
LogDebug("RemoveAllChannels");
|
||||
|
||||
LinkedListIterator<ChatChannel*> iterator(ChatChannels);
|
||||
|
||||
@ -242,7 +247,7 @@ void ChatChannel::AddClient(Client *c) {
|
||||
|
||||
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);
|
||||
|
||||
@ -267,7 +272,7 @@ bool ChatChannel::RemoveClient(Client *c) {
|
||||
|
||||
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();
|
||||
|
||||
@ -304,7 +309,7 @@ bool ChatChannel::RemoveClient(Client *c) {
|
||||
if((Password.length() == 0) || (RuleI(Channels, DeleteTimer) == 0))
|
||||
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);
|
||||
}
|
||||
@ -402,7 +407,7 @@ void ChatChannel::SendMessageToChannel(std::string Message, Client* Sender) {
|
||||
|
||||
if(ChannelClient)
|
||||
{
|
||||
LogInfo("Sending message to [{}] from [{}]",
|
||||
LogDebug("Sending message to [{}] from [{}]",
|
||||
ChannelClient->GetName().c_str(), Sender->GetName().c_str());
|
||||
|
||||
if (cv_messages[static_cast<uint32>(ChannelClient->GetClientVersion())].length() == 0) {
|
||||
@ -505,7 +510,7 @@ ChatChannel *ChatChannelList::AddClientToChannel(std::string ChannelName, Client
|
||||
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);
|
||||
|
||||
@ -581,7 +586,7 @@ void ChatChannelList::Process() {
|
||||
|
||||
if(CurrentChannel && CurrentChannel->ReadyToDelete()) {
|
||||
|
||||
LogInfo("Empty temporary password protected channel [{}] being destroyed",
|
||||
LogDebug("Empty temporary password protected channel [{}] being destroyed",
|
||||
CurrentChannel->GetName().c_str());
|
||||
|
||||
RemoveChannel(CurrentChannel);
|
||||
@ -597,7 +602,7 @@ void ChatChannel::AddInvitee(const std::string &Invitee)
|
||||
if (!IsInvitee(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)) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -235,7 +235,7 @@ std::vector<std::string> ParseRecipients(std::string RecipientString) {
|
||||
|
||||
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;
|
||||
|
||||
@ -304,7 +304,7 @@ static void ProcessMailTo(Client *c, std::string MailMessage) {
|
||||
|
||||
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());
|
||||
|
||||
int PacketLength = 10 + Recipient.length() + Subject.length();
|
||||
@ -556,6 +556,17 @@ void Client::CloseConnection() {
|
||||
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) {
|
||||
|
||||
if (!c) return;
|
||||
@ -634,10 +645,12 @@ void Clientlist::Process()
|
||||
//
|
||||
std::string::size_type LastPeriod = MailBoxString.find_last_of(".");
|
||||
|
||||
if (LastPeriod == std::string::npos)
|
||||
if (LastPeriod == std::string::npos) {
|
||||
CharacterName = MailBoxString;
|
||||
else
|
||||
}
|
||||
else {
|
||||
CharacterName = MailBoxString.substr(LastPeriod + 1);
|
||||
}
|
||||
|
||||
LogInfo("Received login for user [{}] with key [{}]",
|
||||
MailBox, Key);
|
||||
@ -652,8 +665,9 @@ void Clientlist::Process()
|
||||
|
||||
database.GetAccountStatus((*it));
|
||||
|
||||
if ((*it)->GetConnectionType() == ConnectionTypeCombined)
|
||||
if ((*it)->GetConnectionType() == ConnectionTypeCombined) {
|
||||
(*it)->SendFriends();
|
||||
}
|
||||
|
||||
(*it)->SendMailBoxes();
|
||||
|
||||
@ -865,7 +879,9 @@ void Clientlist::CloseAllConnections() {
|
||||
void Client::AddCharacter(int CharID, const char *CharacterName, int Level) {
|
||||
|
||||
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;
|
||||
NewCharacter.CharID = CharID;
|
||||
NewCharacter.Name = CharacterName;
|
||||
@ -874,6 +890,10 @@ void Client::AddCharacter(int CharID, const char *CharacterName, int Level) {
|
||||
Characters.push_back(NewCharacter);
|
||||
}
|
||||
|
||||
void Client::SendKeepAlive() {
|
||||
QueuePacket(new EQApplicationPacket(OP_SessionReady, 0));
|
||||
}
|
||||
|
||||
void Client::SendMailBoxes() {
|
||||
|
||||
int Count = Characters.size();
|
||||
@ -930,7 +950,7 @@ void Client::AddToChannelList(ChatChannel *JoinedChannel) {
|
||||
for (int i = 0; i < MAX_JOINED_CHANNELS; i++)
|
||||
if (JoinedChannels[i] == nullptr) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -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)))
|
||||
{
|
||||
LogInfo("MailBoxName() called with CurrentMailBox set to [{}] and Characters.size() is [{}]",
|
||||
CurrentMailBox, Characters.size());
|
||||
|
||||
return "";
|
||||
return std::string();
|
||||
}
|
||||
|
||||
LogInfo("MailBoxName() called with CurrentMailBox set to [{}] and Characters.size() is [{}]",
|
||||
CurrentMailBox, Characters.size());
|
||||
LogDebug("MailBoxName() called with CurrentMailBox set to [{}] and Characters.size() is [{}]",
|
||||
CurrentMailBox, Characters.size());
|
||||
|
||||
return Characters[CurrentMailBox].Name;
|
||||
|
||||
|
||||
@ -143,7 +143,7 @@ public:
|
||||
void SetConnectionType(char c);
|
||||
ConnectionType GetConnectionType() { return TypeOfConnection; }
|
||||
EQEmu::versions::ClientVersion GetClientVersion() { return ClientVersion_; }
|
||||
|
||||
|
||||
inline bool IsMailConnection() { return (TypeOfConnection == ConnectionTypeMail) || (TypeOfConnection == ConnectionTypeCombined); }
|
||||
void SendNotification(int MailBoxNumber, std::string From, std::string Subject, int MessageID);
|
||||
void ChangeMailBox(int NewMailBox);
|
||||
@ -151,6 +151,7 @@ public:
|
||||
void SendFriends();
|
||||
int GetCharID();
|
||||
void SendUptime();
|
||||
void SendKeepAlive();
|
||||
|
||||
private:
|
||||
unsigned int CurrentMailBox;
|
||||
@ -183,6 +184,7 @@ public:
|
||||
void Process();
|
||||
void CloseAllConnections();
|
||||
Client *FindCharacter(std::string CharacterName);
|
||||
void CheckForStaleConnectionsAll();
|
||||
void CheckForStaleConnections(Client *c);
|
||||
Client *IsCharacterOnline(std::string CharacterName);
|
||||
void ProcessOPMailCommand(Client *c, std::string CommandString);
|
||||
|
||||
@ -108,7 +108,7 @@ void Database::GetAccountStatus(Client *client)
|
||||
{
|
||||
|
||||
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()
|
||||
);
|
||||
|
||||
@ -173,7 +173,7 @@ int Database::FindAccount(const char *characterName, Client *client)
|
||||
|
||||
query = StringFormat(
|
||||
"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
|
||||
);
|
||||
|
||||
@ -320,7 +320,7 @@ void Database::SendHeaders(Client *client)
|
||||
int unknownField3 = 1;
|
||||
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) {
|
||||
return;
|
||||
|
||||
24
ucs/ucs.cpp
24
ucs/ucs.cpp
@ -70,17 +70,18 @@ int main() {
|
||||
// Check every minute for unused channels we can delete
|
||||
//
|
||||
Timer ChannelListProcessTimer(60000);
|
||||
Timer ClientConnectionPruneTimer(60000);
|
||||
|
||||
Timer InterserverTimer(INTERSERVER_TIMER); // does auto-reconnect
|
||||
|
||||
LogInfo("Starting EQEmu Universal Chat Server");
|
||||
|
||||
if (!ucsconfig::LoadConfig()) {
|
||||
LogInfo("Loading server configuration failed");
|
||||
if (!ucsconfig::LoadConfig()) {
|
||||
LogInfo("Loading server configuration failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
Config = ucsconfig::get();
|
||||
Config = ucsconfig::get();
|
||||
|
||||
WorldShortName = Config->ShortName;
|
||||
|
||||
@ -144,19 +145,26 @@ int main() {
|
||||
|
||||
worldserver = new WorldServer;
|
||||
|
||||
while(RunLoops) {
|
||||
auto loop_fn = [&](EQ::Timer* t) {
|
||||
|
||||
Timer::SetCurrentTime();
|
||||
|
||||
g_Clientlist->Process();
|
||||
|
||||
if(ChannelListProcessTimer.Check())
|
||||
if (ChannelListProcessTimer.Check()) {
|
||||
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();
|
||||
|
||||
|
||||
@ -61,7 +61,7 @@ void WorldServer::ProcessMessage(uint16 opcode, EQ::Net::Packet &p)
|
||||
ServerPacket tpack(opcode, p);
|
||||
ServerPacket *pack = &tpack;
|
||||
|
||||
LogInfo("Received Opcode: {:#04x}", opcode);
|
||||
LogNetcode("Received Opcode: {:#04x}", opcode);
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
|
||||
@ -52,6 +52,10 @@ if (-e "eqemu_server_skip_update.txt") {
|
||||
$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_xml_to_json_conversion() if $ARGV[0] eq "convert_xml";
|
||||
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);
|
||||
}
|
||||
|
||||
map_files_fetch_bulk();
|
||||
map_files_fetch_bulk() if !$skip_self_maps_update_check;
|
||||
opcodes_fetch();
|
||||
plugins_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") {
|
||||
print "[Update] Database up to date...\n";
|
||||
exit;
|
||||
if (trim($db_version[2]) == 0) {
|
||||
print "[Update] Continuing bootup\n";
|
||||
exit;
|
||||
}
|
||||
}
|
||||
else {
|
||||
#::: 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 {
|
||||
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";
|
||||
unzip('updates_staged/peq_beta.zip', 'updates_staged/peq_db/');
|
||||
my $start_dir = "updates_staged/peq_db";
|
||||
unzip('updates_staged/peq-latest.zip', 'updates_staged/peq_db/');
|
||||
my $start_dir = "updates_staged/peq_db/peq-dump";
|
||||
find(
|
||||
sub { push @files, $File::Find::name unless -d; },
|
||||
$start_dir
|
||||
);
|
||||
for my $file (@files) {
|
||||
$destination_file = $file;
|
||||
$destination_file =~ s/updates_staged\/peq_db\///g;
|
||||
if ($file =~ /peqbeta|player_tables/i) {
|
||||
$destination_file =~ s/updates_staged\/peq_db\/peq-dump\///g;
|
||||
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";
|
||||
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 {
|
||||
|
||||
@ -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"
|
||||
@ -1,6 +0,0 @@
|
||||
command_settings
|
||||
inventory_versions
|
||||
launcher
|
||||
rule_sets
|
||||
rule_values
|
||||
variables
|
||||
@ -405,6 +405,7 @@
|
||||
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|
|
||||
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:
|
||||
# This won't be needed after this system is implemented, but it is used database that are not
|
||||
|
||||
@ -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|
|
||||
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|
|
||||
9027|2020_03_30_bots_view_update.sql|SELECT * FROM db_version WHERE bots_version >= 9027|empty|
|
||||
|
||||
# Upgrade conditions:
|
||||
# This won't be needed after this system is implemented, but it is used database that are not
|
||||
|
||||
24
utils/sql/git/bots/required/2020_03_30_bots_view_update.sql
Normal file
24
utils/sql/git/bots/required/2020_03_30_bots_view_update.sql
Normal 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;
|
||||
@ -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
71
utils/sql/peq-dump/peq-dump.sh
Executable 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]"
|
||||
@ -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
|
||||
@ -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
|
||||
@ -714,7 +714,7 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
EQApplicationPacket *outapp;
|
||||
uint32 tmpaccid = 0;
|
||||
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);
|
||||
eqs->Close();
|
||||
return true;
|
||||
|
||||
@ -415,6 +415,7 @@ int main(int argc, char** argv) {
|
||||
RegisterConsoleFunctions(console);
|
||||
}
|
||||
|
||||
zoneserver_list.Init();
|
||||
std::unique_ptr<EQ::Net::ServertalkServer> server_connection;
|
||||
server_connection.reset(new EQ::Net::ServertalkServer());
|
||||
|
||||
|
||||
@ -6,29 +6,38 @@
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/md5.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/event/timer.h"
|
||||
|
||||
UCSConnection::UCSConnection()
|
||||
{
|
||||
Stream = 0;
|
||||
connection = 0;
|
||||
}
|
||||
|
||||
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");
|
||||
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;
|
||||
if (Stream) {
|
||||
Stream->OnMessage(std::bind(&UCSConnection::ProcessPacket, this, std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
m_keepalive.reset(new EQ::Timer(5000, true, std::bind(&UCSConnection::OnKeepAlive, this, std::placeholders::_1)));
|
||||
}
|
||||
|
||||
void UCSConnection::ProcessPacket(uint16 opcode, EQ::Net::Packet &p)
|
||||
{
|
||||
if (!Stream)
|
||||
if (!connection)
|
||||
return;
|
||||
|
||||
ServerPacket tpack(opcode, p);
|
||||
@ -60,10 +69,10 @@ void UCSConnection::ProcessPacket(uint16 opcode, EQ::Net::Packet &p)
|
||||
|
||||
void UCSConnection::SendPacket(ServerPacket* pack)
|
||||
{
|
||||
if (!Stream)
|
||||
if (!connection)
|
||||
return;
|
||||
|
||||
Stream->SendPacket(pack);
|
||||
connection->SendPacket(pack);
|
||||
}
|
||||
|
||||
void UCSConnection::SendMessage(const char *From, const char *Message)
|
||||
@ -78,3 +87,13 @@ void UCSConnection::SendMessage(const char *From, const char *Message)
|
||||
SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
void UCSConnection::OnKeepAlive(EQ::Timer *t)
|
||||
{
|
||||
if (!connection) {
|
||||
return;
|
||||
}
|
||||
|
||||
ServerPacket pack(ServerOP_KeepAlive, 0);
|
||||
connection->SendPacket(&pack);
|
||||
}
|
||||
|
||||
13
world/ucs.h
13
world/ucs.h
@ -4,6 +4,7 @@
|
||||
#include "../common/types.h"
|
||||
#include "../common/net/servertalk_server_connection.h"
|
||||
#include "../common/servertalk.h"
|
||||
#include "../common/event/timer.h"
|
||||
#include <memory>
|
||||
|
||||
class UCSConnection
|
||||
@ -13,11 +14,17 @@ public:
|
||||
void SetConnection(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection);
|
||||
void ProcessPacket(uint16 opcode, EQ::Net::Packet &p);
|
||||
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);
|
||||
private:
|
||||
inline std::string GetIP() const { return (Stream && Stream->Handle()) ? Stream->Handle()->RemoteIP() : 0; }
|
||||
std::shared_ptr<EQ::Net::ServertalkServerConnection> Stream;
|
||||
inline std::string GetIP() const { return (connection && connection->Handle()) ? connection->Handle()->RemoteIP() : 0; }
|
||||
std::shared_ptr<EQ::Net::ServertalkServerConnection> connection;
|
||||
|
||||
/**
|
||||
* Keepalive
|
||||
*/
|
||||
std::unique_ptr<EQ::Timer> m_keepalive;
|
||||
void OnKeepAlive(EQ::Timer *t);
|
||||
};
|
||||
|
||||
#endif /*UCS_H_*/
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
#include "../common/version.h"
|
||||
#include "worlddb.h"
|
||||
#include "../common/database_schema.h"
|
||||
#include "../common/database/database_dump_service.h"
|
||||
|
||||
namespace WorldserverCommandHandler {
|
||||
|
||||
@ -51,6 +52,7 @@ namespace WorldserverCommandHandler {
|
||||
function_map["database:version"] = &WorldserverCommandHandler::DatabaseVersion;
|
||||
function_map["database:set-account-status"] = &WorldserverCommandHandler::DatabaseSetAccountStatus;
|
||||
function_map["database:schema"] = &WorldserverCommandHandler::DatabaseGetSchema;
|
||||
function_map["database:dump"] = &WorldserverCommandHandler::DatabaseDump;
|
||||
|
||||
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)
|
||||
{
|
||||
description = "Displays server database schema";
|
||||
description = "Displays server database schema";
|
||||
|
||||
if (cmd[{"-h", "--help"}]) {
|
||||
return;
|
||||
@ -202,4 +204,71 @@ namespace WorldserverCommandHandler {
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -30,6 +30,7 @@ namespace WorldserverCommandHandler {
|
||||
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 DatabaseGetSchema(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||
void DatabaseDump(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -39,7 +39,6 @@ ZSList::ZSList()
|
||||
{
|
||||
NextID = 1;
|
||||
CurGroupID = 1;
|
||||
LastAllocatedPort = 0;
|
||||
memset(pLockedZones, 0, sizeof(pLockedZones));
|
||||
|
||||
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();
|
||||
while (iter != zone_server_list.end()) {
|
||||
if ((*iter)->GetUUID().compare(uuid) == 0) {
|
||||
auto port = (*iter)->GetCPort();
|
||||
zone_server_list.erase(iter);
|
||||
|
||||
if (port != 0) {
|
||||
m_ports_free.push_back(port);
|
||||
}
|
||||
return;
|
||||
}
|
||||
iter++;
|
||||
@ -239,6 +243,14 @@ bool ZSList::SetLockedZone(uint16 iZoneID, bool iLock) {
|
||||
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) {
|
||||
for (auto &zone : pLockedZones) {
|
||||
if (zone == iZoneID)
|
||||
@ -577,30 +589,15 @@ void ZSList::RebootZone(const char* ip1, uint16 port, const char* ip2, uint32 sk
|
||||
safe_delete_array(tmp);
|
||||
}
|
||||
|
||||
uint16 ZSList::GetAvailableZonePort()
|
||||
uint16 ZSList::GetAvailableZonePort()
|
||||
{
|
||||
const WorldConfig *Config = WorldConfig::get();
|
||||
int i;
|
||||
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++;
|
||||
if (m_ports_free.empty()) {
|
||||
return 0;
|
||||
}
|
||||
LastAllocatedPort = port;
|
||||
|
||||
return port;
|
||||
auto first = m_ports_free.front();
|
||||
m_ports_free.pop_front();
|
||||
return first;
|
||||
}
|
||||
|
||||
uint32 ZSList::TriggerBootup(uint32 iZoneID, uint32 iInstanceID) {
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include "../common/event/timer.h"
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <deque>
|
||||
|
||||
class WorldTCPConnection;
|
||||
class ServerPacket;
|
||||
@ -22,6 +23,7 @@ public:
|
||||
ZSList();
|
||||
~ZSList();
|
||||
|
||||
void Init();
|
||||
bool IsZoneLocked(uint16 iZoneID);
|
||||
bool SendPacket(ServerPacket *pack);
|
||||
bool SendPacket(uint32 zoneid, ServerPacket *pack);
|
||||
@ -73,8 +75,7 @@ private:
|
||||
uint32 NextID;
|
||||
uint16 pLockedZones[MaxLockedZones];
|
||||
uint32 CurGroupID;
|
||||
uint16 LastAllocatedPort;
|
||||
|
||||
std::deque<uint16> m_ports_free;
|
||||
std::unique_ptr<EQ::Timer> m_tick;
|
||||
std::unique_ptr<EQ::Timer> m_keepalive;
|
||||
|
||||
|
||||
@ -32,6 +32,7 @@
|
||||
#endif
|
||||
|
||||
#include "map.h"
|
||||
#include "water_map.h"
|
||||
|
||||
extern Zone* zone;
|
||||
//#define LOSDEBUG 6
|
||||
@ -237,6 +238,11 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
||||
if (!mob->CastToClient()->ClientFinishedLoading() || mob->CastToClient()->IsHoveringForRespawn() || mob->CastToClient()->bZoning)
|
||||
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
|
||||
|
||||
@ -256,6 +256,7 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
TotalSecondsPlayed = 0;
|
||||
keyring.clear();
|
||||
bind_sight_target = nullptr;
|
||||
p_raid_instance = nullptr;
|
||||
mercid = 0;
|
||||
mercSlot = 0;
|
||||
InitializeMercInfo();
|
||||
@ -1918,7 +1919,7 @@ void Client::CheckManaEndUpdate() {
|
||||
else if (group) {
|
||||
group->SendEndurancePacketFrom(this);
|
||||
}
|
||||
|
||||
|
||||
auto endurance_packet = new EQApplicationPacket(OP_EnduranceUpdate, sizeof(EnduranceUpdate_Struct));
|
||||
EnduranceUpdate_Struct* endurance_update = (EnduranceUpdate_Struct*)endurance_packet->pBuffer;
|
||||
endurance_update->cur_end = GetEndurance();
|
||||
@ -8757,6 +8758,11 @@ void Client::CheckRegionTypeChanges()
|
||||
if (last_region_type == new_region)
|
||||
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
|
||||
last_region_type = new_region;
|
||||
|
||||
@ -9198,7 +9204,7 @@ void Client::SetSecondaryWeaponOrnamentation(uint32 model_id)
|
||||
secondary_item->SetOrnamentationIDFile(model_id);
|
||||
SendItemPacket(EQEmu::invslot::slotSecondary, secondary_item, ItemPacketTrade);
|
||||
WearChange(EQEmu::textures::weaponSecondary, static_cast<uint16>(model_id), 0);
|
||||
|
||||
|
||||
Message(Chat::Yellow, "Your secondary weapon appearance has been modified");
|
||||
}
|
||||
}
|
||||
@ -9287,3 +9293,41 @@ void Client::SetBotOption(BotOwnerOption boo, bool flag) {
|
||||
}
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
@ -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(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 RemoveFromInstance(uint16 instance_id);
|
||||
void WhoAll();
|
||||
@ -691,7 +692,7 @@ public:
|
||||
|
||||
int GetClientMaxLevel() const { return client_max_level; }
|
||||
void SetClientMaxLevel(int max_level) { client_max_level = max_level; }
|
||||
|
||||
|
||||
void CheckManaEndUpdate();
|
||||
void SendManaUpdate();
|
||||
void SendEnduranceUpdate();
|
||||
@ -1294,6 +1295,8 @@ public:
|
||||
|
||||
void CheckRegionTypeChanges();
|
||||
|
||||
WaterRegionType GetLastRegion() { return last_region_type; }
|
||||
|
||||
int32 CalcATK();
|
||||
|
||||
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);
|
||||
glm::vec4 &GetLastPositionBeforeBulkUpdate();
|
||||
|
||||
Raid *p_raid_instance;
|
||||
|
||||
protected:
|
||||
friend class Mob;
|
||||
void CalcItemBonuses(StatBonuses* newbon);
|
||||
@ -1340,6 +1345,7 @@ protected:
|
||||
char *adv_data;
|
||||
|
||||
private:
|
||||
|
||||
eqFilterMode ClientFilters[_FilterCount];
|
||||
int32 HandlePacket(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);
|
||||
|
||||
int client_max_level;
|
||||
|
||||
|
||||
#ifdef BOTS
|
||||
|
||||
|
||||
public:
|
||||
enum BotOwnerOption : size_t {
|
||||
booDeathMarquee,
|
||||
@ -1652,7 +1658,7 @@ public:
|
||||
|
||||
bool GetBotOption(BotOwnerOption boo) const;
|
||||
void SetBotOption(BotOwnerOption boo, bool flag = true);
|
||||
|
||||
|
||||
bool GetBotPulling() { return m_bot_pulling; }
|
||||
void SetBotPulling(bool flag = true) { m_bot_pulling = flag; }
|
||||
|
||||
|
||||
@ -599,7 +599,7 @@ void Client::CompleteConnect()
|
||||
if (group)
|
||||
group->SendHPManaEndPacketsTo(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//bulk raid send in here eventually
|
||||
|
||||
@ -818,35 +818,45 @@ void Client::CompleteConnect()
|
||||
database.QueryDatabase(
|
||||
StringFormat(
|
||||
"UPDATE `character_data` SET `last_login` = UNIX_TIMESTAMP() WHERE id = %u",
|
||||
this->CharacterID()
|
||||
CharacterID()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (zone) {
|
||||
if (zone->GetInstanceTimer()) {
|
||||
uint32 ttime = zone->GetInstanceTimer()->GetRemainingTime();
|
||||
uint32 day = (ttime / 86400000);
|
||||
uint32 hour = (ttime / 3600000) % 24;
|
||||
uint32 minute = (ttime / 60000) % 60;
|
||||
uint32 second = (ttime / 1000) % 60;
|
||||
if (day) {
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
if (zone && zone->GetInstanceTimer()) {
|
||||
|
||||
bool is_permanent = false;
|
||||
uint32 remaining_time_seconds = database.GetTimeRemainingInstance(zone->GetInstanceID(), is_permanent);
|
||||
uint32 day = (remaining_time_seconds / 86400);
|
||||
uint32 hour = (remaining_time_seconds / 3600) % 24;
|
||||
uint32 minute = (remaining_time_seconds / 60) % 60;
|
||||
uint32 second = (remaining_time_seconds / 1) % 60;
|
||||
|
||||
if (day) {
|
||||
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
|
||||
);
|
||||
}
|
||||
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();
|
||||
@ -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 */
|
||||
// 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
|
||||
m_inv.SetGMInventory(true);
|
||||
m_inv.SetGMInventory(true);
|
||||
loaditems = database.GetInventory(cid, &m_inv); /* Load Character Inventory */
|
||||
database.LoadCharacterBandolier(cid, &m_pp); /* Load Character Bandolier */
|
||||
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();
|
||||
}
|
||||
SetClientMaxLevel(client_max_level);
|
||||
|
||||
|
||||
// we know our class now, so we might have to fix our consume timer!
|
||||
if (class_ == MONK)
|
||||
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.
|
||||
|
||||
uint16 poison_skill = GetSkill(EQEmu::skills::SkillApplyPoison);
|
||||
|
||||
|
||||
if (ChanceRoll < (.75 + poison_skill / 1000)) {
|
||||
ApplyPoisonSuccessResult = 1;
|
||||
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.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
PlayerPositionUpdateClient_Struct *ppu = (PlayerPositionUpdateClient_Struct *) app->pBuffer;
|
||||
|
||||
|
||||
/* Boat handling */
|
||||
if (ppu->spawn_id != GetID()) {
|
||||
/* If player is controlling boat */
|
||||
@ -4374,16 +4392,16 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
|
||||
controlling_boat_id = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
auto boat_delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, EQ10toFloat(ppu->delta_heading));
|
||||
boat->SetDelta(boat_delta);
|
||||
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||
PlayerPositionUpdateServer_Struct *ppus = (PlayerPositionUpdateServer_Struct *) outapp->pBuffer;
|
||||
boat->MakeSpawnUpdate(ppus);
|
||||
entity_list.QueueCloseClients(boat, outapp, true, 300, this, false);
|
||||
safe_delete(outapp);
|
||||
|
||||
|
||||
/* 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);
|
||||
return;
|
||||
@ -4398,9 +4416,9 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
|
||||
if (cmob != nullptr) {
|
||||
cmob->SetPosition(ppu->x_pos, ppu->y_pos, ppu->z_pos);
|
||||
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);
|
||||
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)));
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
// position. If the client is in a boat, we need to add the boat pos and
|
||||
// the client offset together.
|
||||
|
||||
|
||||
float cx = ppu->x_pos;
|
||||
float cy = ppu->y_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. */
|
||||
float rewind_x_diff = 0;
|
||||
float rewind_y_diff = 0;
|
||||
|
||||
|
||||
rewind_x_diff = cx - m_RewindLocation.x;
|
||||
rewind_x_diff *= rewind_x_diff;
|
||||
rewind_y_diff = cy - m_RewindLocation.y;
|
||||
rewind_y_diff *= rewind_y_diff;
|
||||
|
||||
/*
|
||||
|
||||
/*
|
||||
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
|
||||
his pre-PPU x and y for /rewind, in case he gets stuck.
|
||||
*/
|
||||
|
||||
|
||||
if ((rewind_x_diff > 750) || (rewind_y_diff > 750))
|
||||
m_RewindLocation = glm::vec3(m_Position);
|
||||
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
|
||||
if ((rewind_x_diff > 5000) || (rewind_y_diff > 5000))
|
||||
m_RewindLocation = glm::vec3(cx, cy, cz);
|
||||
|
||||
|
||||
if (proximity_timer.Check()) {
|
||||
entity_list.ProcessMove(this, glm::vec3(cx, cy, cz));
|
||||
if (RuleB(TaskSystem, EnableTaskSystem) && RuleB(TaskSystem, EnableTaskProximity))
|
||||
ProcessTaskProximities(cx, cy, cz);
|
||||
|
||||
|
||||
m_Proximity = glm::vec3(cx, cy, cz);
|
||||
}
|
||||
|
||||
|
||||
/* Update internal state */
|
||||
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 (zone->random.Real(0, 100) < 70)//should be good
|
||||
CheckIncreaseSkill(EQEmu::skills::SkillTracking, nullptr, -20);
|
||||
}
|
||||
|
||||
|
||||
/* Break Hide if moving without sneaking and set rewind timer if moved */
|
||||
if (cy != m_Position.y || cx != m_Position.x) {
|
||||
if ((hidden || improved_hidden) && !sneaking) {
|
||||
@ -4500,7 +4518,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
|
||||
}
|
||||
rewind_timer.Start(30000, true);
|
||||
}
|
||||
|
||||
|
||||
/* Handle client aggro scanning timers NPCs */
|
||||
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;
|
||||
|
||||
|
||||
/* Update internal server position from what the client has sent */
|
||||
m_Position.x = cx;
|
||||
m_Position.y = cy;
|
||||
m_Position.z = cz;
|
||||
|
||||
|
||||
/* Visual Debugging */
|
||||
if (RuleB(Character, OPClientUpdateVisualDebug)) {
|
||||
LogDebug("ClientUpdate: ppu x: [{}] y: [{}] z: [{}] h: [{}]", cx, cy, cz, new_heading);
|
||||
this->SendAppearanceEffect(78, 0, 0, 0, 0);
|
||||
this->SendAppearanceEffect(41, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
/* Only feed real time updates when client is moving */
|
||||
if (is_client_moving || new_heading != m_Position.w || new_animation != animation) {
|
||||
|
||||
|
||||
animation = ppu->animation;
|
||||
m_Position.w = new_heading;
|
||||
|
||||
|
||||
/* Broadcast update to other clients */
|
||||
auto outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||
PlayerPositionUpdateServer_Struct *position_update = (PlayerPositionUpdateServer_Struct *) outapp->pBuffer;
|
||||
|
||||
|
||||
MakeSpawnUpdate(position_update);
|
||||
|
||||
|
||||
if (gm_hide_me) {
|
||||
entity_list.QueueClientsStatus(this, outapp, true, Admin(), 255);
|
||||
} else {
|
||||
entity_list.QueueCloseClients(this, outapp, true, RuleI(Range, ClientPositionUpdates), nullptr, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Always send position updates to group - send when beyond normal ClientPositionUpdate range */
|
||||
Group *group = this->GetGroup();
|
||||
Raid *raid = this->GetRaid();
|
||||
|
||||
|
||||
if (raid) {
|
||||
raid->QueueClients(this, outapp, true, true, (RuleI(Range, ClientPositionUpdates) * -1));
|
||||
} else if (group) {
|
||||
group->QueueClients(this, outapp, true, true, (RuleI(Range, ClientPositionUpdates) * -1));
|
||||
}
|
||||
|
||||
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
|
||||
if (zone->watermap) {
|
||||
if (zone->watermap->InLiquid(glm::vec3(m_Position))) {
|
||||
CheckIncreaseSkill(EQEmu::skills::SkillSwimming, nullptr, -17);
|
||||
|
||||
|
||||
// Dismount horses when entering water
|
||||
if (GetHorseId() && RuleB(Character, DismountWater)) {
|
||||
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);
|
||||
else {
|
||||
FindPersonRequest_Struct* t = (FindPersonRequest_Struct*)app->pBuffer;
|
||||
|
||||
|
||||
std::vector<FindPerson_Point> points;
|
||||
Mob* target = entity_list.GetMob(t->npc_id);
|
||||
|
||||
|
||||
if (target == nullptr) {
|
||||
//empty length packet == not found.
|
||||
EQApplicationPacket outapp(OP_FindPersonReply, 0);
|
||||
QueuePacket(&outapp);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!RuleB(Pathing, Find) && RuleB(Bazaar, EnableWarpToTrader) && target->IsClient() && (target->CastToClient()->Trader ||
|
||||
target->CastToClient()->Buyer)) {
|
||||
Message(Chat::Yellow, "Moving you to Trader %s", target->GetName());
|
||||
MovePC(zone->GetZoneID(), zone->GetInstanceID(), target->GetX(), target->GetY(), target->GetZ(), 0.0f);
|
||||
}
|
||||
|
||||
|
||||
if (!RuleB(Pathing, Find) || !zone->pathing)
|
||||
{
|
||||
//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 End(target->GetX(), target->GetY(), target->GetZ() + (target->GetSize() < 6.0 ? 6 : target->GetSize()) * HEAD_POSITION);
|
||||
|
||||
|
||||
bool partial = false;
|
||||
bool stuck = false;
|
||||
auto pathlist = zone->pathing->FindRoute(Start, End, partial, stuck);
|
||||
|
||||
|
||||
if (pathlist.empty() || partial)
|
||||
{
|
||||
EQApplicationPacket outapp(OP_FindPersonReply, 0);
|
||||
QueuePacket(&outapp);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Live appears to send the points in this order:
|
||||
// Final destination.
|
||||
// Current Position.
|
||||
// rest of the points.
|
||||
FindPerson_Point p;
|
||||
|
||||
|
||||
int PointNumber = 0;
|
||||
|
||||
|
||||
bool LeadsToTeleporter = false;
|
||||
|
||||
|
||||
auto v = pathlist.back();
|
||||
|
||||
|
||||
p.x = v.pos.x;
|
||||
p.y = v.pos.y;
|
||||
p.z = v.pos.z;
|
||||
points.push_back(p);
|
||||
|
||||
|
||||
p.x = GetX();
|
||||
p.y = GetY();
|
||||
p.z = GetZ();
|
||||
points.push_back(p);
|
||||
|
||||
|
||||
for (auto Iterator = pathlist.begin(); Iterator != pathlist.end(); ++Iterator)
|
||||
{
|
||||
if ((*Iterator).teleport) // Teleporter
|
||||
@ -5829,7 +5847,7 @@ void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app)
|
||||
LeadsToTeleporter = true;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
glm::vec3 v = (*Iterator).pos;
|
||||
p.x = v.x;
|
||||
p.y = v.y;
|
||||
@ -5837,17 +5855,17 @@ void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app)
|
||||
points.push_back(p);
|
||||
++PointNumber;
|
||||
}
|
||||
|
||||
|
||||
if (!LeadsToTeleporter)
|
||||
{
|
||||
p.x = target->GetX();
|
||||
p.y = target->GetY();
|
||||
p.z = target->GetZ();
|
||||
|
||||
|
||||
points.push_back(p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SendPathPacket(points);
|
||||
}
|
||||
}
|
||||
@ -11090,14 +11108,14 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
{
|
||||
case RaidCommandInviteIntoExisting:
|
||||
case RaidCommandInvite: {
|
||||
|
||||
|
||||
Client *player_to_invite = entity_list.GetClientByName(raid_command_packet->player_name);
|
||||
|
||||
if (!player_to_invite)
|
||||
break;
|
||||
|
||||
Group *player_to_invite_group = player_to_invite->GetGroup();
|
||||
|
||||
|
||||
if (player_to_invite->HasRaid()) {
|
||||
Message(Chat::Red, "%s is already in a raid.", player_to_invite->GetName());
|
||||
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.");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* Send out invite to the client */
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct));
|
||||
RaidGeneral_Struct *raid_command = (RaidGeneral_Struct*)outapp->pBuffer;
|
||||
@ -11124,7 +11142,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
raid_command->action = 20;
|
||||
|
||||
player_to_invite->QueuePacket(outapp);
|
||||
|
||||
|
||||
safe_delete(outapp);
|
||||
|
||||
break;
|
||||
@ -11220,7 +11238,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
}
|
||||
if (player_invited_group->IsLeader(player_invited_group->members[x])) {
|
||||
Client *c = nullptr;
|
||||
|
||||
|
||||
if (player_invited_group->members[x]->IsClient())
|
||||
c = player_invited_group->members[x]->CastToClient();
|
||||
else
|
||||
@ -11230,24 +11248,24 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, c);
|
||||
raid->AddMember(c, raid_free_group_id, true, true, true);
|
||||
raid->SendBulkRaid(c);
|
||||
|
||||
|
||||
if (raid->IsLocked()) {
|
||||
raid->SendRaidLockTo(c);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Client *c = nullptr;
|
||||
|
||||
|
||||
if (player_invited_group->members[x]->IsClient())
|
||||
c = player_invited_group->members[x]->CastToClient();
|
||||
else
|
||||
continue;
|
||||
|
||||
|
||||
raid->SendRaidCreate(c);
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, c);
|
||||
raid->AddMember(c, raid_free_group_id);
|
||||
raid->SendBulkRaid(c);
|
||||
|
||||
|
||||
if (raid->IsLocked()) {
|
||||
raid->SendRaidLockTo(c);
|
||||
}
|
||||
@ -11281,12 +11299,12 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
c = group->members[x]->CastToClient();
|
||||
else
|
||||
continue;
|
||||
|
||||
|
||||
raid->SendRaidCreate(c);
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, c);
|
||||
raid->AddMember(c, raid_free_group_id, false, true);
|
||||
raid->SendBulkRaid(c);
|
||||
|
||||
|
||||
if (raid->IsLocked()) {
|
||||
raid->SendRaidLockTo(c);
|
||||
}
|
||||
@ -11294,17 +11312,17 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
else
|
||||
{
|
||||
Client *c = nullptr;
|
||||
|
||||
|
||||
if (group->members[x]->IsClient())
|
||||
c = group->members[x]->CastToClient();
|
||||
else
|
||||
continue;
|
||||
|
||||
|
||||
raid->SendRaidCreate(c);
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, c);
|
||||
raid->AddMember(c, raid_free_group_id);
|
||||
raid->SendBulkRaid(c);
|
||||
|
||||
|
||||
if (raid->IsLocked()) {
|
||||
raid->SendRaidLockTo(c);
|
||||
}
|
||||
@ -11321,7 +11339,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
if (player_invited_group) {
|
||||
|
||||
raid = new Raid(player_accepting_invite);
|
||||
|
||||
|
||||
entity_list.AddRaid(raid);
|
||||
raid->SetRaidDetails();
|
||||
Client *addClientig = nullptr;
|
||||
@ -11345,7 +11363,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
raid->SendMakeLeaderPacketTo(raid->leadername, c);
|
||||
raid->AddMember(c, 0, true, true, true);
|
||||
raid->SendBulkRaid(c);
|
||||
|
||||
|
||||
if (raid->IsLocked()) {
|
||||
raid->SendRaidLockTo(c);
|
||||
}
|
||||
@ -11470,7 +11488,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
raid->SetGroupLeader(raid_command_packet->leader_name, false);
|
||||
|
||||
/* We were the leader of our old group */
|
||||
if (old_group < 12) {
|
||||
if (old_group < 12) {
|
||||
/* Assign new group leader if we can */
|
||||
for (int x = 0; x < MAX_RAID_MEMBERS; x++) {
|
||||
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);
|
||||
|
||||
worldserver.SendPacket(pack);
|
||||
|
||||
|
||||
safe_delete(pack);
|
||||
}
|
||||
break;
|
||||
@ -11545,7 +11563,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
raid->SetGroupLeader(raid_command_packet->leader_name, false);
|
||||
for (int x = 0; x < MAX_RAID_MEMBERS; x++) {
|
||||
if (raid->members[x].GroupNumber == oldgrp && strlen(raid->members[x].membername) > 0 && strcmp(raid->members[x].membername, raid_command_packet->leader_name) != 0){
|
||||
|
||||
|
||||
raid->SetGroupLeader(raid->members[x].membername);
|
||||
raid->UpdateGroupAAs(oldgrp);
|
||||
|
||||
@ -11568,7 +11586,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
strn0cpy(raid_command->playername, raid->members[x].membername, 64);
|
||||
raid_command->zoneid = zone->GetZoneID();
|
||||
raid_command->instance_id = zone->GetInstanceID();
|
||||
|
||||
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
@ -11583,14 +11601,14 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
else {
|
||||
auto pack = new ServerPacket(ServerOP_RaidGroupDisband, sizeof(ServerRaidGeneralAction_Struct));
|
||||
ServerRaidGeneralAction_Struct* raid_command = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
|
||||
|
||||
|
||||
raid_command->rid = raid->GetID();
|
||||
raid_command->zoneid = zone->GetZoneID();
|
||||
raid_command->instance_id = zone->GetInstanceID();
|
||||
strn0cpy(raid_command->playername, raid_command_packet->leader_name, 64);
|
||||
|
||||
worldserver.SendPacket(pack);
|
||||
|
||||
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
@ -13327,13 +13345,17 @@ void Client::Handle_OP_Split(const EQApplicationPacket *app)
|
||||
Split_Struct *split = (Split_Struct *)app->pBuffer;
|
||||
//Per the note above, Im not exactly sure what to do on 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.");
|
||||
return;
|
||||
}
|
||||
Group *cgroup = GetGroup();
|
||||
if (cgroup == nullptr) {
|
||||
//invalid group, not sure if we should say more...
|
||||
|
||||
Group *group = nullptr;
|
||||
Raid *raid = nullptr;
|
||||
|
||||
if (IsRaidGrouped())
|
||||
raid = GetRaid();
|
||||
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.");
|
||||
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.");
|
||||
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;
|
||||
|
||||
|
||||
143
zone/command.cpp
143
zone/command.cpp
@ -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("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("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("emotesearch", "Searches NPC Emotes", 80, command_emotesearch) ||
|
||||
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]));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Mob *target=c->GetTarget();
|
||||
@ -7782,7 +7921,7 @@ void command_npcemote(Client *c, const Seperator *sep)
|
||||
void command_npceditmass(Client *c, const Seperator *sep)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@ -7930,7 +8069,7 @@ void command_npceditmass(Client *c, const Seperator *sep)
|
||||
std::string saylink = fmt::format(
|
||||
"#npceditmass {} {}{} {} {} apply",
|
||||
search_column,
|
||||
(exact_match ? '=' : '\0'),
|
||||
(exact_match ? "=" : ""),
|
||||
search_value,
|
||||
change_column,
|
||||
change_value
|
||||
|
||||
@ -91,6 +91,7 @@ void command_disablerecipe(Client *c, const Seperator *sep);
|
||||
void command_disarmtrap(Client *c, const Seperator *sep);
|
||||
void command_distance(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_emotesearch(Client* c, const Seperator *sep);
|
||||
void command_emoteview(Client* c, const Seperator *sep);
|
||||
|
||||
@ -822,6 +822,54 @@ XS(XS__isdisctome) {
|
||||
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) {
|
||||
dXSARGS;
|
||||
@ -2342,7 +2390,6 @@ XS(XS__updatetaskactivity) {
|
||||
XS(XS__resettaskactivity);
|
||||
XS(XS__resettaskactivity) {
|
||||
dXSARGS;
|
||||
unsigned int task, activity;
|
||||
if (items == 2) {
|
||||
int task_id = (int) SvIV(ST(0));
|
||||
int activity_id = (int) SvIV(ST(1));
|
||||
@ -2613,6 +2660,23 @@ XS(XS__istaskappropriate) {
|
||||
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) {
|
||||
dXSARGS;
|
||||
@ -2797,6 +2861,51 @@ XS(XS__collectitems) {
|
||||
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) {
|
||||
dXSARGS;
|
||||
@ -3063,6 +3172,25 @@ XS(XS__RemoveFromInstanceByCharID) {
|
||||
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) {
|
||||
dXSARGS;
|
||||
@ -3151,6 +3279,93 @@ XS(XS__saylink) {
|
||||
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) {
|
||||
dXSARGS;
|
||||
@ -3169,6 +3384,58 @@ XS(XS__getguildnamebyid) {
|
||||
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) {
|
||||
dXSARGS;
|
||||
@ -3875,6 +4142,7 @@ EXTERN_C XS(boot_quest) {
|
||||
newXS(strcpy(buf, "RemoveAllFromInstance"), XS__RemoveAllFromInstance, file);
|
||||
newXS(strcpy(buf, "RemoveFromInstance"), XS__RemoveFromInstance, 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, "SetRunning"), XS__SetRunning, 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, "collectitems"), XS__collectitems, 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, "creategroundobject"), XS__CreateGroundObject, 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, "forcedoorclose"), XS__forcedoorclose, 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, "getitemname"), XS__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, "getcharnamebyid"), XS__getcharnamebyid, file);
|
||||
newXS(strcpy(buf, "getcurrencyitemid"), XS__getcurrencyitemid, 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, "getplayerburiedcorpsecount"), XS__getplayerburiedcorpsecount, file);
|
||||
newXS(strcpy(buf, "getplayercorpsecount"), XS__getplayercorpsecount, file);
|
||||
newXS(strcpy(buf, "getplayercorpsecountbyzoneid"), XS__getplayercorpsecountbyzoneid, 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, "gmmove"), XS__gmmove, file);
|
||||
newXS(strcpy(buf, "gmsay"), XS__gmsay, file);
|
||||
|
||||
@ -498,7 +498,7 @@ void EntityList::MobProcess()
|
||||
size_t sz = mob_list.size();
|
||||
|
||||
#ifdef IDLE_WHEN_EMPTY
|
||||
if (numclients > 0 ||
|
||||
if (numclients > 0 ||
|
||||
mob->GetWanderType() == 4 || mob->GetWanderType() == 6) {
|
||||
// Normal processing, or assuring that spawns that should
|
||||
// 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);
|
||||
|
||||
auto position = door->GetPosition();
|
||||
|
||||
|
||||
new_door.xPos = position.x;
|
||||
new_door.yPos = position.y;
|
||||
new_door.zPos = position.z;
|
||||
new_door.heading = position.w;
|
||||
|
||||
|
||||
new_door.incline = door->GetIncline();
|
||||
new_door.size = door->GetSize();
|
||||
new_door.doorId = door->GetDoorID();
|
||||
@ -1984,17 +1984,26 @@ Raid *EntityList::GetRaidByID(uint32 id)
|
||||
|
||||
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();
|
||||
|
||||
while (iterator != raid_list.end()) {
|
||||
for (int x = 0; x < MAX_RAID_MEMBERS; x++)
|
||||
if ((*iterator)->members[x].member)
|
||||
if((*iterator)->members[x].member == client)
|
||||
for (auto &member : (*iterator)->members) {
|
||||
if (member.member) {
|
||||
if (member.member == client) {
|
||||
client->p_raid_instance = *iterator;
|
||||
return *iterator;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++iterator;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -3277,13 +3286,15 @@ void EntityList::Evade(Mob *who)
|
||||
void EntityList::ClearAggro(Mob* targ)
|
||||
{
|
||||
Client *c = nullptr;
|
||||
if (targ->IsClient())
|
||||
if (targ->IsClient()) {
|
||||
c = targ->CastToClient();
|
||||
}
|
||||
auto it = npc_list.begin();
|
||||
while (it != npc_list.end()) {
|
||||
if (it->second->CheckAggro(targ)) {
|
||||
if (c)
|
||||
if (c) {
|
||||
c->RemoveXTarget(it->second, false);
|
||||
}
|
||||
it->second->RemoveFromHateList(targ);
|
||||
}
|
||||
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)
|
||||
{
|
||||
auto it = npc_list.begin();
|
||||
|
||||
@ -447,6 +447,7 @@ public:
|
||||
|
||||
void Process();
|
||||
void ClearAggro(Mob* targ);
|
||||
void ClearWaterAggro(Mob* targ);
|
||||
void ClearFeignAggro(Mob* targ);
|
||||
void ClearZoneFeignAggro(Client* targ);
|
||||
void AggroZone(Mob* who, uint32 hate = 0);
|
||||
|
||||
@ -2913,23 +2913,33 @@ void Client::SendItemPacket(int16 slot_id, const EQEmu::ItemInstance* inst, Item
|
||||
if (!inst)
|
||||
return;
|
||||
|
||||
if (slot_id <= EQEmu::invslot::POSSESSIONS_END && slot_id >= EQEmu::invslot::POSSESSIONS_BEGIN) {
|
||||
if ((((uint64)1 << slot_id) & 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);
|
||||
if ((((uint64)1 << temp_slot) & GetInv().GetLookup()->PossessionsBitmask) == 0)
|
||||
return;
|
||||
}
|
||||
else if (slot_id <= EQEmu::invslot::BANK_END && slot_id >= EQEmu::invslot::BANK_BEGIN) {
|
||||
if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize.Bank)
|
||||
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)
|
||||
return;
|
||||
if (packet_type != ItemPacketMerchant) {
|
||||
if (slot_id <= EQEmu::invslot::POSSESSIONS_END && slot_id >= EQEmu::invslot::POSSESSIONS_BEGIN) {
|
||||
if ((((uint64)1 << slot_id) & GetInv().GetLookup()->PossessionsBitmask) == 0) {
|
||||
LogError("Item not sent to merchant : slot [{}]", slot_id);
|
||||
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);
|
||||
if ((((uint64)1 << temp_slot) & GetInv().GetLookup()->PossessionsBitmask) == 0) {
|
||||
LogError("Item not sent to merchant2 : slot [{}]", slot_id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (slot_id <= EQEmu::invslot::BANK_END && slot_id >= EQEmu::invslot::BANK_BEGIN) {
|
||||
if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize.Bank) {
|
||||
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)
|
||||
|
||||
@ -90,6 +90,11 @@ void Lua_Client::SetPVP(bool v) {
|
||||
self->SetPVP(v);
|
||||
}
|
||||
|
||||
void Lua_Client::SendToGuildHall() {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SendToGuildHall();
|
||||
}
|
||||
|
||||
bool Lua_Client::GetPVP() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->GetPVP();
|
||||
@ -1584,6 +1589,7 @@ luabind::scope lua_register_client() {
|
||||
.def("Disconnect", (void(Lua_Client::*)(void))&Lua_Client::Disconnect)
|
||||
.def("IsLD", (bool(Lua_Client::*)(void))&Lua_Client::IsLD)
|
||||
.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("Duck", (void(Lua_Client::*)(void))&Lua_Client::Duck)
|
||||
.def("Stand", (void(Lua_Client::*)(void))&Lua_Client::Stand)
|
||||
|
||||
@ -39,6 +39,7 @@ public:
|
||||
void Disconnect();
|
||||
bool IsLD();
|
||||
void WorldKick();
|
||||
void SendToGuildHall();
|
||||
bool GetAnon();
|
||||
void Duck();
|
||||
void Stand();
|
||||
|
||||
@ -393,6 +393,18 @@ bool lua_is_disc_tome(int 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() {
|
||||
quest_manager.safemove();
|
||||
}
|
||||
@ -729,6 +741,10 @@ bool lua_is_task_appropriate(int 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) {
|
||||
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);
|
||||
}
|
||||
|
||||
int lua_count_item(uint32 item_id) {
|
||||
return quest_manager.countitem(item_id);
|
||||
}
|
||||
|
||||
void lua_update_spawn_timer(uint32 id, uint32 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);
|
||||
}
|
||||
|
||||
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) {
|
||||
char text[256] = { 0 };
|
||||
strncpy(text, phrase, 255);
|
||||
@ -854,10 +878,50 @@ bool lua_delete_data(std::string 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) {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
quest_manager.RemoveAllFromInstance(instance_id);
|
||||
}
|
||||
@ -1632,6 +1700,9 @@ luabind::scope lua_register_general() {
|
||||
luabind::def("depop_zone", &lua_depop_zone),
|
||||
luabind::def("repop_zone", &lua_repop_zone),
|
||||
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("rain", &lua_rain),
|
||||
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("completed_tasks_in_set", &lua_completed_tasks_in_set),
|
||||
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("clear_spawn_timers", &lua_clear_spawn_timers),
|
||||
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("modify_npc_stat", &lua_modify_npc_stat),
|
||||
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("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_count_item", &lua_merchant_count_item),
|
||||
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))&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, std::string))&lua_set_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_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("destroy_instance", &lua_destroy_instance),
|
||||
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("remove_from_instance", &lua_remove_from_instance),
|
||||
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("flag_instance_by_group_leader", &lua_flag_instance_by_group_leader),
|
||||
luabind::def("flag_instance_by_raid_leader", &lua_flag_instance_by_raid_leader),
|
||||
|
||||
@ -52,14 +52,14 @@ uint32 Lua_Raid::GetTotalRaidDamage(Lua_Mob 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();
|
||||
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();
|
||||
self->SplitMoney(copper, silver, gold, platinum, splitter);
|
||||
self->SplitMoney(gid, copper, silver, gold, platinum, splitter);
|
||||
}
|
||||
|
||||
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("SplitExp", (void(Lua_Raid::*)(uint32,Lua_Mob))&Lua_Raid::SplitExp)
|
||||
.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,Lua_Client))&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,uint32,Lua_Client))&Lua_Raid::SplitMoney)
|
||||
.def("BalanceHP", (void(Lua_Raid::*)(int,uint32))&Lua_Raid::BalanceHP)
|
||||
.def("IsLeader", (bool(Lua_Raid::*)(const char*))&Lua_Raid::IsLeader)
|
||||
.def("IsGroupLeader", (bool(Lua_Raid::*)(const char*))&Lua_Raid::IsGroupLeader)
|
||||
|
||||
@ -34,8 +34,8 @@ public:
|
||||
int GetGroup(Lua_Client c);
|
||||
void SplitExp(uint32 exp, Lua_Mob other);
|
||||
uint32 GetTotalRaidDamage(Lua_Mob other);
|
||||
void SplitMoney(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);
|
||||
void SplitMoney(uint32 gid, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Lua_Client splitter);
|
||||
void BalanceHP(int penalty, uint32 group_id);
|
||||
bool IsLeader(const char *c);
|
||||
bool IsLeader(Lua_Client c);
|
||||
|
||||
@ -92,7 +92,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "../common/unix.h"
|
||||
#endif
|
||||
|
||||
volatile bool RunLoops = true;
|
||||
extern volatile bool is_zone_loaded;
|
||||
|
||||
EntityList entity_list;
|
||||
@ -577,19 +576,19 @@ int main(int argc, char** argv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
Zone::Shutdown(true);
|
||||
LogInfo("Shutting down...");
|
||||
LogSys.CloseFileLogs();
|
||||
EQ::EventLoop::Get().Shutdown();
|
||||
}
|
||||
|
||||
void CatchSignal(int sig_num) {
|
||||
#ifdef _WINDOWS
|
||||
LogInfo("Recieved signal: [{}]", sig_num);
|
||||
#endif
|
||||
RunLoops = false;
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
Zone::Shutdown(true);
|
||||
RunLoops = false;
|
||||
LogInfo("Shutting down...");
|
||||
LogSys.CloseFileLogs();
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
/* Update Window Title with relevant information */
|
||||
|
||||
@ -747,6 +747,13 @@ void Client::AI_Process()
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
24
zone/npc.cpp
24
zone/npc.cpp
@ -694,11 +694,6 @@ void NPC::RemoveCash() {
|
||||
|
||||
bool NPC::Process()
|
||||
{
|
||||
if (IsStunned() && stunned_timer.Check()) {
|
||||
Mob::UnStun();
|
||||
this->spun_timer.Disable();
|
||||
}
|
||||
|
||||
if (p_depop)
|
||||
{
|
||||
Mob* owner = entity_list.GetMob(this->ownerid);
|
||||
@ -711,6 +706,11 @@ bool NPC::Process()
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsStunned() && stunned_timer.Check()) {
|
||||
Mob::UnStun();
|
||||
this->spun_timer.Disable();
|
||||
}
|
||||
|
||||
SpellProcess();
|
||||
|
||||
@ -962,7 +962,7 @@ void NPC::Depop(bool StartSpawnTimer) {
|
||||
}
|
||||
|
||||
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]) {
|
||||
case SE_Stamina: {
|
||||
if(IsEngaged() && GetHPRatio() < 100)
|
||||
@ -3093,6 +3093,14 @@ bool NPC::AICheckCloseBeneficialSpells(
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!mob->CheckLosFN(caster)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mob->GetReverseFactionCon(caster) >= FACTION_KINDLY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LogAICastBeneficialClose(
|
||||
"NPC [{}] Distance [{}] Cast Range [{}] Caster [{}]",
|
||||
mob->GetCleanName(),
|
||||
@ -3101,10 +3109,6 @@ bool NPC::AICheckCloseBeneficialSpells(
|
||||
caster->GetCleanName()
|
||||
);
|
||||
|
||||
if (mob->GetReverseFactionCon(caster) >= FACTION_KINDLY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((spell_types & SpellType_Buff) && !RuleB(NPC, BuffFriends)) {
|
||||
if (mob != caster) {
|
||||
spell_types = SpellType_Heal;
|
||||
|
||||
@ -245,6 +245,27 @@ XS(XS_Client_WorldKick) {
|
||||
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) {
|
||||
dXSARGS;
|
||||
@ -2439,7 +2460,7 @@ XS(XS_Client_MemmedCount) {
|
||||
|
||||
RETVAL = THIS->MemmedCount();
|
||||
XSprePUSH;
|
||||
PUSHu((UV) RETVAL);
|
||||
PUSHu((UV) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
@ -4786,7 +4807,7 @@ XS(XS_Client_AddLevelBasedExp) {
|
||||
|
||||
if (items > 2)
|
||||
max_level = (uint8) SvUV(ST(2));
|
||||
|
||||
|
||||
if (items > 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, "SendSpellAnim"), XS_Client_SendSpellAnim, 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, "SendZoneFlagInfo"), XS_Client_SendZoneFlagInfo, file, "$$");
|
||||
newXSproto(strcpy(buf, "SetAAPoints"), XS_Client_SetAAPoints, file, "$$");
|
||||
|
||||
@ -247,13 +247,14 @@ XS(XS_Raid_SplitMoney); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Raid_SplitMoney) {
|
||||
dXSARGS;
|
||||
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;
|
||||
uint32 copper = (uint32) SvUV(ST(1));
|
||||
uint32 silver = (uint32) SvUV(ST(2));
|
||||
uint32 gold = (uint32) SvUV(ST(3));
|
||||
uint32 platinum = (uint32) SvUV(ST(4));
|
||||
uint32 gid = (uint32) SvUV(ST(1));
|
||||
uint32 copper = (uint32) SvUV(ST(2));
|
||||
uint32 silver = (uint32) SvUV(ST(3));
|
||||
uint32 gold = (uint32) SvUV(ST(4));
|
||||
uint32 platinum = (uint32) SvUV(ST(5));
|
||||
|
||||
if (sv_derived_from(ST(0), "Raid")) {
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
@ -263,7 +264,7 @@ XS(XS_Raid_SplitMoney) {
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->SplitMoney(copper, silver, gold, platinum);
|
||||
THIS->SplitMoney(gid, copper, silver, gold, platinum);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
@ -569,7 +570,7 @@ XS(boot_Raid) {
|
||||
newXSproto(strcpy(buf, "GetGroup"), XS_Raid_GetGroup, file, "$$");
|
||||
newXSproto(strcpy(buf, "SplitExp"), XS_Raid_SplitExp, 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, "IsLeader"), XS_Raid_IsLeader, file, "$$");
|
||||
newXSproto(strcpy(buf, "IsGroupLeader"), XS_Raid_IsGroupLeader, file, "$$");
|
||||
|
||||
@ -906,6 +906,31 @@ bool QuestManager::isdisctome(int item_id) {
|
||||
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() {
|
||||
QuestManagerCurrentQuestVars();
|
||||
if (initiator && initiator->IsClient())
|
||||
@ -2432,6 +2457,16 @@ bool QuestManager::istaskappropriate(int task) {
|
||||
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() {
|
||||
if(!zone)
|
||||
return;
|
||||
@ -2580,6 +2615,32 @@ int QuestManager::collectitems(uint32 item_id, bool remove)
|
||||
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)
|
||||
{
|
||||
bool found = false;
|
||||
@ -2670,6 +2731,23 @@ const char* QuestManager::varlink(char* perltext, int item_id) {
|
||||
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)
|
||||
{
|
||||
QuestManagerCurrentQuestVars();
|
||||
@ -2811,6 +2889,10 @@ void QuestManager::RemoveFromInstanceByCharID(uint16 instance_id, uint32 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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (guild_id > 0)
|
||||
return guild_mgr.GetGuildName(guild_id);
|
||||
@ -2876,6 +2997,27 @@ const char* QuestManager::getguildnamebyid(int guild_id) {
|
||||
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)
|
||||
{
|
||||
QuestManagerCurrentQuestVars();
|
||||
|
||||
@ -107,6 +107,9 @@ public:
|
||||
void level(int newlevel);
|
||||
void traindisc(int discipline_tome_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 rain(int weather);
|
||||
void snow(int weather);
|
||||
@ -213,12 +216,15 @@ public:
|
||||
int activetasksinset(int taskset);
|
||||
int completedtasksinset(int taskset);
|
||||
bool istaskappropriate(int task);
|
||||
std::string gettaskname(uint32 task_id);
|
||||
void clearspawntimers();
|
||||
void ze(int type, const char *str);
|
||||
void we(int type, const char *str);
|
||||
int getlevel(uint8 type);
|
||||
int collectitems(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);
|
||||
bool checktitle(int titlecheck);
|
||||
void removetitle(int titlecheck);
|
||||
@ -242,6 +248,7 @@ public:
|
||||
void AssignRaidToInstance(uint16 instance_id);
|
||||
void RemoveFromInstance(uint16 instance_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 RemoveRaidFromInstance(uint16 instance_id); //potentially useful but not implmented at this time.
|
||||
void RemoveAllFromInstance(uint16 instance_id);
|
||||
@ -250,7 +257,16 @@ public:
|
||||
void FlagInstanceByRaidLeader(uint32 zone, int16 version);
|
||||
const char* varlink(char* perltext, int item_id);
|
||||
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);
|
||||
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);
|
||||
bool IsRunning();
|
||||
void FlyMode(GravityBehavior flymode);
|
||||
|
||||
@ -177,6 +177,7 @@ void Raid::RemoveMember(const char *characterName)
|
||||
if(client) {
|
||||
client->SetRaidGrouped(false);
|
||||
client->LeaveRaidXTargets(this);
|
||||
client->p_raid_instance = nullptr;
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
if (gid == RAID_GROUPLESS)
|
||||
return;
|
||||
|
||||
if(copper == 0 && silver == 0 && gold == 0 && platinum == 0)
|
||||
return;
|
||||
|
||||
uint32 i;
|
||||
uint8 membercount = 0;
|
||||
for (i = 0; i < MAX_RAID_MEMBERS; i++) {
|
||||
if (members[i].member != nullptr) {
|
||||
if (members[i].member != nullptr && members[i].GroupNumber == gid) {
|
||||
membercount++;
|
||||
}
|
||||
}
|
||||
@ -809,11 +815,11 @@ void Raid::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum
|
||||
msg += " as your split";
|
||||
|
||||
for (i = 0; i < MAX_RAID_MEMBERS; i++) {
|
||||
if (members[i].member != nullptr) { // If Group Member is Client
|
||||
//I could not get MoneyOnCorpse to work, so we use this
|
||||
members[i].member->AddMoneyToPP(cpsplit, spsplit, gpsplit, ppsplit, true);
|
||||
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
|
||||
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)
|
||||
{
|
||||
if(!to)
|
||||
if (!to) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct));
|
||||
RaidGeneral_Struct *rg = (RaidGeneral_Struct*)outapp->pBuffer;
|
||||
@ -1609,7 +1616,7 @@ void Raid::SendHPManaEndPacketsFrom(Mob *mob)
|
||||
return;
|
||||
|
||||
uint32 group_id = 0;
|
||||
|
||||
|
||||
if(mob->IsClient())
|
||||
group_id = this->GetGroup(mob->CastToClient());
|
||||
|
||||
@ -1617,7 +1624,7 @@ void Raid::SendHPManaEndPacketsFrom(Mob *mob)
|
||||
EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct));
|
||||
|
||||
mob->CreateHPPacket(&hpapp);
|
||||
|
||||
|
||||
for(int x = 0; x < MAX_RAID_MEMBERS; x++) {
|
||||
if(members[x].member) {
|
||||
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->mana = mob->GetManaPercent();
|
||||
members[x].member->QueuePacket(&outapp, false);
|
||||
|
||||
|
||||
outapp.SetOpcode(OP_MobEnduranceUpdate);
|
||||
MobEnduranceUpdate_Struct *endurance_update = (MobEnduranceUpdate_Struct *)outapp.pBuffer;
|
||||
endurance_update->endurance = mob->GetEndurancePercent();
|
||||
|
||||
@ -159,7 +159,7 @@ public:
|
||||
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 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 TeleportGroup(Mob* sender, uint32 zoneID, uint16 instance_id, float x, float y, float z, float heading, uint32 gid);
|
||||
|
||||
@ -3426,6 +3426,8 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r
|
||||
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
|
||||
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
|
||||
//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);
|
||||
|
||||
// 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));
|
||||
CombatDamage_Struct *cd = (CombatDamage_Struct *)message_packet->pBuffer;
|
||||
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_pitch = action->hit_pitch;
|
||||
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(
|
||||
spelltar, /* Sender */
|
||||
message_packet, /* Packet */
|
||||
@ -3990,6 +3991,13 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r
|
||||
true, /* Packet ACK */
|
||||
(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(message_packet);
|
||||
|
||||
@ -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)
|
||||
{
|
||||
if (Tasks[TaskID]->MinLevel)
|
||||
|
||||
@ -299,6 +299,7 @@ public:
|
||||
bool AppropriateLevel(int TaskID, int PlayerLevel);
|
||||
int GetTaskMinLevel(int TaskID);
|
||||
int GetTaskMaxLevel(int TaskID);
|
||||
std::string GetTaskName(uint32 task_id);
|
||||
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 SendActiveTasksToClient(Client *c, bool TaskComplete=false);
|
||||
|
||||
@ -57,7 +57,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
extern EntityList entity_list;
|
||||
extern Zone* zone;
|
||||
extern volatile bool is_zone_loaded;
|
||||
extern void CatchSignal(int);
|
||||
extern void Shutdown();
|
||||
extern WorldServer worldserver;
|
||||
extern PetitionList petition_list;
|
||||
extern uint32 numclients;
|
||||
@ -192,8 +192,15 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
if (pack->size != sizeof(ServerConnectInfo))
|
||||
break;
|
||||
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;
|
||||
}
|
||||
case ServerOP_ChannelMessage: {
|
||||
@ -482,7 +489,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
}
|
||||
case ServerOP_ShutdownAll: {
|
||||
entity_list.Save();
|
||||
CatchSignal(2);
|
||||
Shutdown();
|
||||
break;
|
||||
}
|
||||
case ServerOP_ZoneShutdown: {
|
||||
@ -1874,9 +1881,11 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
}
|
||||
case ServerOP_UCSServerStatusReply:
|
||||
{
|
||||
auto ucsss = (UCSServerStatus_Struct*)pack->pBuffer;
|
||||
if (zone)
|
||||
auto ucsss = (UCSServerStatus_Struct *) pack->pBuffer;
|
||||
if (zone) {
|
||||
zone->SetUCSServerAvailable((ucsss->available != 0), ucsss->timestamp);
|
||||
LogInfo("UCS Server is now [{}]", (ucsss->available == 1 ? "online" : "offline"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ServerOP_CZSetEntityVariableByNPCTypeID:
|
||||
|
||||
207
zone/zone.cpp
207
zone/zone.cpp
@ -140,7 +140,7 @@ bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) {
|
||||
if(iInstanceID != 0)
|
||||
{
|
||||
auto pack = new ServerPacket(ServerOP_AdventureZoneData, sizeof(uint16));
|
||||
*((uint16*)pack->pBuffer) = iInstanceID;
|
||||
*((uint16*)pack->pBuffer) = iInstanceID;
|
||||
worldserver.SendPacket(pack);
|
||||
delete pack;
|
||||
}
|
||||
@ -330,81 +330,156 @@ bool Zone::LoadGroundSpawns() {
|
||||
return(true);
|
||||
}
|
||||
|
||||
int Zone::SaveTempItem(uint32 merchantid, uint32 npcid, uint32 item, int32 charges, bool sold) {
|
||||
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;
|
||||
}
|
||||
void Zone::DumpMerchantList(uint32 npcid) {
|
||||
std::list<TempMerchantList> tmp_merlist = tmpmerchanttable[npcid];
|
||||
std::list<TempMerchantList>::const_iterator tmp_itr;
|
||||
bool update_charges = false;
|
||||
TempMerchantList ml;
|
||||
while (freeslot == 0 && !update_charges) {
|
||||
freeslot = i;
|
||||
for (tmp_itr = tmp_merlist.begin(); tmp_itr != tmp_merlist.end(); ++tmp_itr) {
|
||||
ml = *tmp_itr;
|
||||
if (ml.item == item) {
|
||||
update_charges = true;
|
||||
freeslot = 0;
|
||||
break;
|
||||
}
|
||||
if ((ml.slot == i) || (ml.origslot == i)) {
|
||||
freeslot = 0;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
|
||||
for (tmp_itr = tmp_merlist.begin(); tmp_itr != tmp_merlist.end(); ++tmp_itr) {
|
||||
ml = *tmp_itr;
|
||||
|
||||
LogInventory("slot[{}] Orig[{}] Item[{}] Charges[{}]", ml.slot, ml.origslot, ml.item, ml.charges);
|
||||
}
|
||||
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();
|
||||
std::list<TempMerchantList> oldtmp_merlist = tmpmerchanttable[npcid];
|
||||
for (tmp_itr = oldtmp_merlist.begin(); tmp_itr != oldtmp_merlist.end(); ++tmp_itr) {
|
||||
TempMerchantList ml2 = *tmp_itr;
|
||||
if(ml2.item != item)
|
||||
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;
|
||||
|
||||
if (sold)
|
||||
return ml.slot;
|
||||
|
||||
//DumpMerchantList(npcid);
|
||||
return ml.slot;
|
||||
}
|
||||
if (freeslot) {
|
||||
if (charges < 0) //sanity check only, shouldnt happen
|
||||
else {
|
||||
if (charges < 0) { //sanity check only, shouldnt happen
|
||||
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];
|
||||
TempMerchantList ml2;
|
||||
ml2.charges = charges;
|
||||
LogInventory("Adding slot [{}] with [{}] charges.", first_empty_mslot, charges);
|
||||
ml2.item = item;
|
||||
ml2.npcid = npcid;
|
||||
ml2.slot = freeslot;
|
||||
ml2.origslot = ml2.slot;
|
||||
ml2.slot = first_empty_mslot;
|
||||
ml2.origslot = first_empty_slot;
|
||||
tmp_merlist.push_back(ml2);
|
||||
tmpmerchanttable[npcid] = tmp_merlist;
|
||||
//DumpMerchantList(npcid);
|
||||
return ml2.slot;
|
||||
}
|
||||
return freeslot;
|
||||
}
|
||||
|
||||
uint32 Zone::GetTempMerchantQuantity(uint32 NPCID, uint32 Slot) {
|
||||
@ -413,8 +488,10 @@ uint32 Zone::GetTempMerchantQuantity(uint32 NPCID, uint32 Slot) {
|
||||
std::list<TempMerchantList>::const_iterator 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 0;
|
||||
}
|
||||
@ -491,7 +568,7 @@ void Zone::LoadNewMerchantData(uint32 merchantid) {
|
||||
|
||||
void Zone::GetMerchantDataForZoneLoad() {
|
||||
LogInfo("Loading Merchant Lists");
|
||||
std::string query = StringFormat(
|
||||
std::string query = StringFormat(
|
||||
"SELECT "
|
||||
"DISTINCT ml.merchantid, "
|
||||
"ml.slot, "
|
||||
@ -734,7 +811,7 @@ void Zone::Shutdown(bool quiet)
|
||||
|
||||
if (RuleB(Zone, KillProcessOnDynamicShutdown)) {
|
||||
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());
|
||||
bool GraveYardLoaded = database.GetZoneGraveyard(graveyard_id(), &pgraveyard_zoneid, &m_Graveyard.x, &m_Graveyard.y, &m_Graveyard.z, &m_Graveyard.w);
|
||||
|
||||
|
||||
if (GraveYardLoaded) {
|
||||
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.
|
||||
bool Zone::Init(bool iStaticZone) {
|
||||
SetStaticZone(iStaticZone);
|
||||
|
||||
|
||||
//load the zone config file.
|
||||
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
|
||||
@ -1089,7 +1166,7 @@ bool Zone::LoadZoneCFG(const char* filename, uint16 instance_id)
|
||||
if (instance_id != 0)
|
||||
{
|
||||
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))
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
uint32 Zone::GetInstanceTimeRemaining() const
|
||||
{
|
||||
return instance_time_remaining;
|
||||
}
|
||||
|
||||
void Zone::SetInstanceTimeRemaining(uint32 instance_time_remaining)
|
||||
{
|
||||
Zone::instance_time_remaining = instance_time_remaining;
|
||||
}
|
||||
|
||||
@ -163,6 +163,7 @@ public:
|
||||
inline void ShowNPCGlobalLoot(Client *to, NPC *who) { m_global_loot.ShowNPCGlobalLoot(to, who); }
|
||||
inline void ShowZoneGlobalLoot(Client *to) { m_global_loot.ShowZoneGlobalLoot(to); }
|
||||
int GetZoneTotalBlockedSpells() { return zone_total_blocked_spells; }
|
||||
void DumpMerchantList(uint32 npcid);
|
||||
int SaveTempItem(uint32 merchantid, uint32 npcid, uint32 item, int32 charges, bool sold = false);
|
||||
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 *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
|
||||
*
|
||||
@ -361,6 +365,7 @@ private:
|
||||
uint8 zone_type;
|
||||
uint16 instanceversion;
|
||||
uint32 instanceid;
|
||||
uint32 instance_time_remaining;
|
||||
uint32 pgraveyard_id, pgraveyard_zoneid;
|
||||
uint32 pMaxClients;
|
||||
uint32 zoneid;
|
||||
|
||||
@ -3703,7 +3703,7 @@ void ZoneDatabase::LoadBuffs(Client *client)
|
||||
if (!IsValidSpell(buffs[index].spellid))
|
||||
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) {
|
||||
buffs[index].spellid = SPELL_UNKNOWN;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user