Merge pull request #5 from EQEmu/master

Update from master
This commit is contained in:
Paul Coene 2020-04-02 11:50:50 -04:00 committed by GitHub
commit f2b68e6783
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 1705 additions and 405 deletions

17
.gitignore vendored
View File

@ -37,4 +37,19 @@ 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
/client_files/**/CMakeFiles/

View File

@ -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) |
|:---:|:---:|:---:|
|[![Linux CI](https://travis-ci.org/EQEmu/Server.svg?branch=master)](https://travis-ci.org/EQEmu/Server) |[![Build status](https://ci.appveyor.com/api/projects/status/scr25kmntx36c1ub/branch/master?svg=true)](https://ci.appveyor.com/project/KimLS/server-87crp/branch/master) |[![Build status](https://ci.appveyor.com/api/projects/status/mdwbr4o9l6mxqofj/branch/master?svg=true)](https://ci.appveyor.com/project/KimLS/server-w0pq2/branch/master) |
|[![Linux CI](https://travis-ci.org/EQEmu/Server.svg?branch=master)](https://travis-ci.org/EQEmu/Server) |[![Build status](https://ci.appveyor.com/api/projects/status/v3utuu0dttm2cqd0?svg=true)](https://ci.appveyor.com/project/KimLS/server) |[![Build status](https://ci.appveyor.com/api/projects/status/scr25kmntx36c1ub?svg=true)](https://ci.appveyor.com/project/KimLS/server-87crp) |
***

View File

@ -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

View File

@ -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;

View File

@ -2158,6 +2158,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
*/

View File

@ -133,6 +133,8 @@ 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);

View File

@ -0,0 +1,569 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <string>
#include <cstdio>
#include <iterator>
#include "database_dump_service.h"
#include "../eqemu_logsys.h"
#include "../string_util.h"
#include "../eqemu_config.h"
#include "../database_schema.h"
#include "../file_util.h"
#include <ctime>
#if _WIN32
#include <windows.h>
#else
#include <sys/time.h>
#endif
#define DATABASE_DUMP_PATH "backups/"
/**
* @param cmd
* @param return_result
* @return
*/
std::string DatabaseDumpService::execute(const std::string &cmd, bool return_result = true)
{
const char *file_name = "db-exec-result.txt";
if (return_result) {
#ifdef _WINDOWS
std::system((cmd + " > " + file_name + " 2>&1").c_str());
#else
std::system((cmd + " > " + file_name).c_str());
#endif
}
else {
std::system((cmd).c_str());
}
std::string result;
if (return_result) {
std::ifstream file(file_name);
result = {std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()};
std::remove(file_name);
}
return result;
}
/**
* @return bool
*/
bool DatabaseDumpService::IsMySQLInstalled()
{
std::string version_output = GetMySQLVersion();
return version_output.find("mysql") != std::string::npos && version_output.find("Ver") != std::string::npos;
}
/**
* Linux
* @return bool
*/
bool DatabaseDumpService::IsTarAvailable()
{
std::string version_output = execute("tar --version");
return version_output.find("GNU tar") != std::string::npos;
}
/**
* Windows
* @return bool
*/
bool DatabaseDumpService::Is7ZipAvailable()
{
std::string version_output = execute("7z --help");
return version_output.find("7-Zip") != std::string::npos;
}
/**
* @return
*/
bool DatabaseDumpService::HasCompressionBinary()
{
return IsTarAvailable() || Is7ZipAvailable();
}
/**
* @return
*/
std::string DatabaseDumpService::GetMySQLVersion()
{
std::string version_output = execute("mysql --version");
return trim(version_output);
}
/**
* @return
*/
std::string DatabaseDumpService::GetBaseMySQLDumpCommand()
{
auto config = EQEmuConfig::get();
return fmt::format(
"mysqldump -u {} -p{} -h {} {}",
config->DatabaseUsername,
config->DatabasePassword,
config->DatabaseHost,
config->DatabaseDB
);
}
/**
* @return
*/
std::string DatabaseDumpService::GetPlayerTablesList()
{
std::string tables_list;
std::vector<std::string> tables = DatabaseSchema::GetPlayerTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return trim(tables_list);
}
/**
* @return
*/
std::string DatabaseDumpService::GetLoginTableList()
{
std::string tables_list;
std::vector<std::string> tables = DatabaseSchema::GetLoginTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return trim(tables_list);
}
/**
* @return
*/
std::string DatabaseDumpService::GetQueryServTables()
{
std::string tables_list;
std::vector<std::string> tables = DatabaseSchema::GetQueryServerTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return trim(tables_list);
}
/**
* @return
*/
std::string DatabaseDumpService::GetSystemTablesList()
{
std::string tables_list;
std::vector<std::string> tables = DatabaseSchema::GetServerTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
tables = DatabaseSchema::GetVersionTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return trim(tables_list);
}
/**
* @return
*/
std::string DatabaseDumpService::GetStateTablesList()
{
std::string tables_list;
std::vector<std::string> tables = DatabaseSchema::GetStateTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return trim(tables_list);
}
/**
* @return
*/
std::string DatabaseDumpService::GetContentTablesList()
{
std::string tables_list;
std::vector<std::string> tables = DatabaseSchema::GetContentTables();
for (const auto &table : tables) {
tables_list += table + " ";
}
return trim(tables_list);
}
/**
* @return
*/
std::string GetDumpDate()
{
time_t now = time(nullptr);
struct tm time_struct{};
char buf[80];
time_struct = *localtime(&now);
strftime(buf, sizeof(buf), "%Y-%m-%d", &time_struct);
std::string time = buf;
return time;
}
/**
* @return
*/
std::string DatabaseDumpService::GetSetDumpPath()
{
return !GetDumpPath().empty() ? GetDumpPath() : DATABASE_DUMP_PATH;
}
/**
* @return
*/
std::string DatabaseDumpService::GetDumpFileNameWithPath()
{
return GetSetDumpPath() + GetDumpFileName();
}
void DatabaseDumpService::Dump()
{
if (!IsMySQLInstalled()) {
LogError("MySQL is not installed; Please check your PATH for a valid MySQL installation");
return;
}
if (IsDumpDropTableSyntaxOnly()) {
SetDumpOutputToConsole(true);
}
if (IsDumpOutputToConsole()) {
LogSys.SilenceConsoleLogging();
}
LogInfo("MySQL installed [{}]", GetMySQLVersion());
SetDumpFileName(EQEmuConfig::get()->DatabaseDB + '-' + GetDumpDate());
auto config = EQEmuConfig::get();
LogInfo(
"Database [{}] Host [{}] Username [{}]",
config->DatabaseDB,
config->DatabaseHost,
config->DatabaseUsername
);
std::string options = "--allow-keywords --extended-insert";
if (IsDumpWithNoData()) {
options += " --no-data";
}
if (!IsDumpTableLock()) {
options += " --skip-lock-tables";
}
std::string tables_to_dump;
std::string dump_descriptor;
if (!IsDumpAllTables()) {
if (IsDumpPlayerTables()) {
tables_to_dump += GetPlayerTablesList() + " ";
dump_descriptor += "-player";
}
if (IsDumpSystemTables()) {
tables_to_dump += GetSystemTablesList() + " ";
dump_descriptor += "-system";
}
if (IsDumpStateTables()) {
tables_to_dump += GetStateTablesList() + " ";
dump_descriptor += "-state";
}
if (IsDumpContentTables()) {
tables_to_dump += GetContentTablesList() + " ";
dump_descriptor += "-content";
}
if (IsDumpLoginServerTables()) {
tables_to_dump += GetLoginTableList() + " ";
dump_descriptor += "-login";
}
if (IsDumpQueryServerTables()) {
tables_to_dump += GetQueryServTables();
dump_descriptor += "-queryserv";
}
}
if (!dump_descriptor.empty()) {
SetDumpFileName(GetDumpFileName() + dump_descriptor);
}
/**
* If we are dumping to stdout then we don't generate a file
*/
std::string pipe_file;
if (!IsDumpOutputToConsole()) {
pipe_file = fmt::format(" > {}.sql", GetDumpFileNameWithPath());
}
std::string execute_command = fmt::format(
"{} {} {} {}",
GetBaseMySQLDumpCommand(),
options,
tables_to_dump,
pipe_file
);
if (!FileUtil::exists(GetSetDumpPath()) && !IsDumpOutputToConsole()) {
FileUtil::mkdir(GetSetDumpPath());
}
if (IsDumpDropTableSyntaxOnly()) {
std::vector<std::string> tables = SplitString(tables_to_dump, ' ');
for (auto &table : tables) {
std::cout << "DROP TABLE IF EXISTS `" << table << "`;" << std::endl;
}
if (tables_to_dump.empty()) {
std::cerr << "No tables were specified" << std::endl;
}
}
else {
std::string execution_result = execute(execute_command, IsDumpOutputToConsole());
if (!execution_result.empty()) {
std::cout << execution_result;
}
}
if (!tables_to_dump.empty()) {
LogInfo("Dumping Tables [{}]", tables_to_dump);
}
LogInfo("Database dump created at [{}.sql]", GetDumpFileNameWithPath());
if (IsDumpWithCompression() && !IsDumpOutputToConsole()) {
if (HasCompressionBinary()) {
LogInfo("Compression requested... Compressing dump [{}.sql]", GetDumpFileNameWithPath());
if (IsTarAvailable()) {
execute(
fmt::format(
"tar -zcvf {}.tar.gz -C {} {}.sql",
GetDumpFileNameWithPath(),
GetSetDumpPath(),
GetDumpFileName()
)
);
LogInfo("Compressed dump created at [{}.tar.gz]", GetDumpFileNameWithPath());
}
else if (Is7ZipAvailable()) {
execute(
fmt::format(
"7z a -t7z {}.zip {}.sql",
GetDumpFileNameWithPath(),
GetDumpFileNameWithPath()
)
);
LogInfo("Compressed dump created at [{}.zip]", GetDumpFileNameWithPath());
}
else {
LogInfo("Compression requested, but no available compression binary was found");
}
}
else {
LogWarning("Compression requested but binary not found... Skipping...");
}
}
// LogDebug("[{}] dump-to-console", IsDumpOutputToConsole());
// LogDebug("[{}] dump-path", GetSetDumpPath());
// LogDebug("[{}] compression", (IsDumpWithCompression() ? "true" : "false"));
// LogDebug("[{}] query-serv", (IsDumpQueryServerTables() ? "true" : "false"));
// LogDebug("[{}] has-compression-binary", (HasCompressionBinary() ? "true" : "false"));
// LogDebug("[{}] content", (IsDumpContentTables() ? "true" : "false"));
// LogDebug("[{}] no-data", (IsDumpWithNoData() ? "true" : "false"));
// LogDebug("[{}] login", (IsDumpLoginServerTables() ? "true" : "false"));
// LogDebug("[{}] player", (IsDumpPlayerTables() ? "true" : "false"));
// LogDebug("[{}] system", (IsDumpSystemTables() ? "true" : "false"));
}
bool DatabaseDumpService::IsDumpSystemTables() const
{
return dump_system_tables;
}
void DatabaseDumpService::SetDumpSystemTables(bool dump_system_tables)
{
DatabaseDumpService::dump_system_tables = dump_system_tables;
}
bool DatabaseDumpService::IsDumpContentTables() const
{
return dump_content_tables;
}
void DatabaseDumpService::SetDumpContentTables(bool dump_content_tables)
{
DatabaseDumpService::dump_content_tables = dump_content_tables;
}
bool DatabaseDumpService::IsDumpPlayerTables() const
{
return dump_player_tables;
}
void DatabaseDumpService::SetDumpPlayerTables(bool dump_player_tables)
{
DatabaseDumpService::dump_player_tables = dump_player_tables;
}
bool DatabaseDumpService::IsDumpLoginServerTables() const
{
return dump_login_server_tables;
}
void DatabaseDumpService::SetDumpLoginServerTables(bool dump_login_server_tables)
{
DatabaseDumpService::dump_login_server_tables = dump_login_server_tables;
}
bool DatabaseDumpService::IsDumpWithNoData() const
{
return dump_with_no_data;
}
void DatabaseDumpService::SetDumpWithNoData(bool dump_with_no_data)
{
DatabaseDumpService::dump_with_no_data = dump_with_no_data;
}
bool DatabaseDumpService::IsDumpAllTables() const
{
return dump_all_tables;
}
void DatabaseDumpService::SetDumpAllTables(bool dump_all_tables)
{
DatabaseDumpService::dump_all_tables = dump_all_tables;
}
bool DatabaseDumpService::IsDumpTableLock() const
{
return dump_table_lock;
}
void DatabaseDumpService::SetDumpTableLock(bool dump_table_lock)
{
DatabaseDumpService::dump_table_lock = dump_table_lock;
}
bool DatabaseDumpService::IsDumpWithCompression() const
{
return dump_with_compression;
}
void DatabaseDumpService::SetDumpWithCompression(bool dump_with_compression)
{
DatabaseDumpService::dump_with_compression = dump_with_compression;
}
const std::string &DatabaseDumpService::GetDumpPath() const
{
return dump_path;
}
void DatabaseDumpService::SetDumpPath(const std::string &dump_path)
{
DatabaseDumpService::dump_path = dump_path;
}
void DatabaseDumpService::SetDumpFileName(const std::string &dump_file_name)
{
DatabaseDumpService::dump_file_name = dump_file_name;
}
const std::string &DatabaseDumpService::GetDumpFileName() const
{
return dump_file_name;
}
bool DatabaseDumpService::IsDumpQueryServerTables() const
{
return dump_query_server_tables;
}
void DatabaseDumpService::SetDumpQueryServerTables(bool dump_query_server_tables)
{
DatabaseDumpService::dump_query_server_tables = dump_query_server_tables;
}
bool DatabaseDumpService::IsDumpOutputToConsole() const
{
return dump_output_to_console;
}
void DatabaseDumpService::SetDumpOutputToConsole(bool dump_output_to_console)
{
DatabaseDumpService::dump_output_to_console = dump_output_to_console;
}
bool DatabaseDumpService::IsDumpDropTableSyntaxOnly() const
{
return dump_drop_table_syntax_only;
}
void DatabaseDumpService::SetDumpDropTableSyntaxOnly(bool dump_drop_table_syntax_only)
{
DatabaseDumpService::dump_drop_table_syntax_only = dump_drop_table_syntax_only;
}
bool DatabaseDumpService::IsDumpStateTables() const
{
return dump_state_tables;
}
void DatabaseDumpService::SetDumpStateTables(bool dump_state_tables)
{
DatabaseDumpService::dump_state_tables = dump_state_tables;
}

View File

@ -0,0 +1,91 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef EQEMU_DATABASE_DUMP_SERVICE_H
#define EQEMU_DATABASE_DUMP_SERVICE_H
class DatabaseDumpService {
public:
void Dump();
bool IsDumpAllTables() const;
void SetDumpAllTables(bool dump_all_tables);
bool IsDumpWithNoData() const;
void SetDumpWithNoData(bool dump_with_no_data);
bool IsDumpSystemTables() const;
void SetDumpSystemTables(bool dump_system_tables);
bool IsDumpContentTables() const;
void SetDumpContentTables(bool dump_content_tables);
bool IsDumpPlayerTables() const;
void SetDumpPlayerTables(bool dump_player_tables);
bool IsDumpLoginServerTables() const;
void SetDumpLoginServerTables(bool dump_login_server_tables);
bool IsDumpTableLock() const;
void SetDumpTableLock(bool dump_table_lock);
bool IsDumpWithCompression() const;
void SetDumpWithCompression(bool dump_with_compression);
const std::string &GetDumpPath() const;
void SetDumpPath(const std::string &dump_path);
const std::string &GetDumpFileName() const;
void SetDumpFileName(const std::string &dump_file_name);
bool IsDumpQueryServerTables() const;
void SetDumpQueryServerTables(bool dump_query_server_tables);
bool IsDumpOutputToConsole() const;
void SetDumpOutputToConsole(bool dump_output_to_console);
bool IsDumpDropTableSyntaxOnly() const;
void SetDumpDropTableSyntaxOnly(bool dump_drop_table_syntax_only);
bool IsDumpStateTables() const;
void SetDumpStateTables(bool dump_state_tables);
private:
bool dump_all_tables = false;
bool dump_state_tables = false;
bool dump_system_tables = false;
bool dump_content_tables = false;
bool dump_player_tables = false;
bool dump_query_server_tables = false;
bool dump_login_server_tables = false;
bool dump_with_no_data = false;
bool dump_table_lock = false;
bool dump_with_compression = false;
bool dump_output_to_console = false;
bool dump_drop_table_syntax_only = false;
std::string dump_path;
std::string dump_file_name;
std::string execute(const std::string &cmd, bool return_result);
bool IsMySQLInstalled();
std::string GetMySQLVersion();
std::string GetBaseMySQLDumpCommand();
std::string GetPlayerTablesList();
std::string GetSystemTablesList();
std::string GetStateTablesList();
std::string GetContentTablesList();
std::string GetLoginTableList();
bool IsTarAvailable();
bool Is7ZipAvailable();
bool HasCompressionBinary();
std::string GetDumpFileNameWithPath();
std::string GetSetDumpPath();
std::string GetQueryServTables();
};
#endif //EQEMU_DATABASE_DUMP_SERVICE_H

View File

@ -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",
};
}

View File

@ -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
View File

@ -0,0 +1,67 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <fstream>
#include "file_util.h"
#ifdef _WINDOWS
#include <direct.h>
#include <conio.h>
#include <iostream>
#include <dos.h>
#include <windows.h>
#include <process.h>
#else
#include <unistd.h>
#include <sys/stat.h>
#endif
/**
* @param name
* @return
*/
bool FileUtil::exists(const std::string &name)
{
std::ifstream f(name.c_str());
return f.good();
}
/**
* @param directory_name
*/
void FileUtil::mkdir(const std::string& directory_name)
{
#ifdef _WINDOWS
struct _stat st;
if (_stat(directory_name.c_str(), &st) == 0) // exists
return;
_mkdir(directory_name.c_str());
#else
struct stat st{};
if (stat(directory_name.c_str(), &st) == 0) { // exists
return;
}
::mkdir(directory_name.c_str(), 0755);
#endif
}

32
common/file_util.h Normal file
View File

@ -0,0 +1,32 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef EQEMU_FILE_UTIL_H
#define EQEMU_FILE_UTIL_H
class FileUtil {
public:
static bool exists(const std::string &name);
static void mkdir(const std::string& directory_name);
};
#endif //EQEMU_FILE_UTIL_H

View File

@ -912,7 +912,7 @@ bool BaseGuildManager::GetEntireGuild(uint32 guild_id, std::vector<CharGuildInfo
return(false);
//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()) {

View File

@ -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

View File

@ -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 {

View File

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

View File

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

View File

@ -404,7 +404,8 @@
9148|2020_01_28_corpse_guild_consent_id.sql|SHOW COLUMNS FROM `character_corpses` LIKE 'guild_consent_id'|empty|
9149|2020_02_06_globalloot.sql|SHOW COLUMNS FROM `global_loot` LIKE 'hot_zone'|empty|
9150|2020_02_06_aa_reset_on_death.sql|SHOW COLUMNS FROM `aa_ability` LIKE 'reset_on_death'|empty|
9151|2020_03_05_npc_always_aggro.sql|SHOW COLUMNS FROM `npc_types` LIKE 'always_aggros_foes'|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

View File

@ -25,6 +25,7 @@
9024|2019_06_27_bots_pet_get_lost.sql|SELECT `bot_command` FROM `bot_command_settings` WHERE `bot_command` LIKE 'petgetlost'|empty|
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

View File

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

View File

@ -1 +1 @@
ALTER TABLE `npc_types` ADD COLUMN `always_aggros_foes` tinyint(4) NOT NULL DEFAULT 0;
ALTER TABLE `npc_types` ADD COLUMN `always_aggro` tinyint(1) NOT NULL DEFAULT 0;

View File

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

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

@ -0,0 +1,70 @@
#!/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"
bash -c "${world_bin} database:dump --query-serv-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_queryserv.sql"
# with content
bash -c "${world_bin} database:dump --content-tables --dump-output-to-console > ${dump_path}create_tables_content.sql"
bash -c "${world_bin} database:dump --system-tables --dump-output-to-console > ${dump_path}create_tables_system.sql"
#############################################
# "all" exports
#############################################
bash -c "cd ${dump_path} && ls * | grep create | sed 's/.*/source &;/' > create_all_tables.sql"
bash -c "cd ${dump_path} && ls * | grep drop | sed 's/.*/source &;/' > drop_all_tables.sql"
#############################################
# zip
#############################################
human_date=$(date +"%B-%d-%Y" | tr '[:upper:]' '[:lower:]')
echo "Compressing..."
bash -c "cd /tmp/ && rm -rf peq-latest.zip && zip peq-latest.zip peq-dump/* && mv ${dump_path}peq-latest.zip /tmp/peq-latest.zip"
echo "Cleaning up..."
rm -rf ${dump_path}
echo "Dump located [/tmp/peq-latest.zip]"

View File

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

View File

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

View File

@ -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());

View File

@ -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();
}
}

View File

@ -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);
};

View File

@ -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) {

View File

@ -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;

View File

@ -139,7 +139,7 @@ void NPC::DescribeAggro(Client *towho, Mob *mob, bool verbose) {
if (RuleB(Aggro, UseLevelAggro))
{
if (GetLevel() < RuleI(Aggro, MinAggroLevel) && mob->GetLevelCon(GetLevel()) == CON_GRAY && GetBodyType() != 3 && !AlwaysAggrosFoes())
if (GetLevel() < RuleI(Aggro, MinAggroLevel) && mob->GetLevelCon(GetLevel()) == CON_GRAY && GetBodyType() != 3 && !AlwaysAggro())
{
towho->Message(Chat::White, "...%s is red to me (basically)", mob->GetName(), dist2, iAggroRange2);
return;
@ -147,7 +147,7 @@ void NPC::DescribeAggro(Client *towho, Mob *mob, bool verbose) {
}
else
{
if(GetINT() > RuleI(Aggro, IntAggroThreshold) && mob->GetLevelCon(GetLevel()) == CON_GRAY && !AlwaysAggrosFoes()) {
if(GetINT() > RuleI(Aggro, IntAggroThreshold) && mob->GetLevelCon(GetLevel()) == CON_GRAY && !AlwaysAggro()) {
towho->Message(Chat::White, "...%s is red to me (basically)", mob->GetName(),
dist2, iAggroRange2);
return;
@ -318,7 +318,7 @@ bool Mob::CheckWillAggro(Mob *mob) {
//old InZone check taken care of above by !mob->CastToClient()->Connected()
(
( GetLevel() >= RuleI(Aggro, MinAggroLevel))
||(GetBodyType() == 3) || AlwaysAggrosFoes()
||(GetBodyType() == 3) || AlwaysAggro()
||( mob->IsClient() && mob->CastToClient()->IsSitting() )
||( mob->GetLevelCon(GetLevel()) != CON_GRAY)
@ -352,7 +352,7 @@ bool Mob::CheckWillAggro(Mob *mob) {
//old InZone check taken care of above by !mob->CastToClient()->Connected()
(
( GetINT() <= RuleI(Aggro, IntAggroThreshold) )
|| AlwaysAggrosFoes()
|| AlwaysAggro()
||( mob->IsClient() && mob->CastToClient()->IsSitting() )
||( mob->GetLevelCon(GetLevel()) != CON_GRAY)
@ -384,7 +384,7 @@ bool Mob::CheckWillAggro(Mob *mob) {
LogAggro("Dist^2: [{}]\n", dist2);
LogAggro("Range^2: [{}]\n", iAggroRange2);
LogAggro("Faction: [{}]\n", fv);
LogAggro("AlwaysAggroFlag: [{}]\n", AlwaysAggrosFoes());
LogAggro("AlwaysAggroFlag: [{}]\n", AlwaysAggro());
LogAggro("Int: [{}]\n", GetINT());
LogAggro("Con: [{}]\n", GetLevelCon(mob->GetLevel()));

View File

@ -7797,6 +7797,8 @@ FACTION_VALUE Client::GetFactionLevel(uint32 char_id, uint32 npc_id, uint32 p_ra
// few optimizations
if (GetFeigned())
return FACTION_INDIFFERENT;
if(!zone->CanDoCombat())
return FACTION_INDIFFERENT;
if (invisible_undead && tnpc && !tnpc->SeeInvisibleUndead())
return FACTION_INDIFFERENT;
if (IsInvisible(tnpc))

View File

@ -13327,13 +13327,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 +13349,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;

View File

@ -196,6 +196,7 @@ int command_init(void)
command_add("disarmtrap", "Analog for ldon disarm trap for the newer clients since we still don't have it working.", 80, command_disarmtrap) ||
command_add("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

View File

@ -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);

View File

@ -262,7 +262,7 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
0, // uint8 in_legtexture,
0, // uint8 in_feettexture,
0, // uint8 in_usemodel,
0 // bool in_always_aggros_foes
0 // bool in_always_aggro
),
corpse_decay_timer(RuleI(Character, CorpseDecayTimeMS)),
corpse_rez_timer(RuleI(Character, CorpseResTimeMS)),

View File

@ -822,6 +822,22 @@ XS(XS__isdisctome) {
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__safemove);
XS(XS__safemove) {
dXSARGS;
@ -2342,7 +2358,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 +2628,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 +2829,35 @@ 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__UpdateSpawnTimer);
XS(XS__UpdateSpawnTimer) {
dXSARGS;
@ -3063,6 +3124,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;
@ -3169,6 +3249,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 +4007,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 +4032,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);
@ -3939,14 +4073,20 @@ EXTERN_C XS(boot_quest) {
newXS(strcpy(buf, "forcedoorclose"), XS__forcedoorclose, file);
newXS(strcpy(buf, "forcedooropen"), XS__forcedooropen, 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, "get_spawn_condition"), XS__get_spawn_condition, 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, "getspellname"), XS__getspellname, 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);

View File

@ -393,6 +393,10 @@ bool lua_is_disc_tome(int item_id) {
return quest_manager.isdisctome(item_id);
}
std::string lua_get_spell_name(uint32 spell_id) {
return quest_manager.getspellname(spell_id);
}
void lua_safe_move() {
quest_manager.safemove();
}
@ -729,6 +733,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 +789,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 +815,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);
@ -858,6 +874,18 @@ 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);
}
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 +938,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 +1664,7 @@ 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_spell_name", (std::string(*)(uint32))&lua_get_spell_name),
luabind::def("safe_move", &lua_safe_move),
luabind::def("rain", &lua_rain),
luabind::def("snow", &lua_snow),
@ -1699,6 +1732,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 +1746,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),
@ -1728,6 +1764,9 @@ luabind::scope lua_register_general() {
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_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_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 +1781,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),

View File

@ -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)

View File

@ -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);

View File

@ -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 */

View File

@ -94,7 +94,7 @@ Mob::Mob(
uint8 in_legtexture,
uint8 in_feettexture,
uint16 in_usemodel,
bool in_always_aggros_foes
bool in_always_aggro
) :
attack_timer(2000),
attack_dw_timer(2000),
@ -276,7 +276,7 @@ Mob::Mob(
qglobal = 0;
spawned = false;
rare_spawn = false;
always_aggros_foes = in_always_aggros_foes;
always_aggro = in_always_aggro;
InitializeBuffSlots();

View File

@ -579,7 +579,7 @@ public:
inline const GravityBehavior GetFlyMode() const { return flymode; }
bool IsBoat() const;
bool IsControllableBoat() const;
inline const bool AlwaysAggrosFoes() const { return always_aggros_foes; }
inline const bool AlwaysAggro() const { return always_aggro; }
//Group
virtual bool HasRaid() = 0;
@ -1391,7 +1391,7 @@ protected:
Timer ranged_timer;
float attack_speed; //% increase/decrease in attack speed (not haste)
int attack_delay; //delay between attacks in 10ths of seconds
bool always_aggros_foes;
bool always_aggro;
int16 slow_mitigation; // Allows for a slow mitigation (100 = 100%, 50% = 50%)
Timer tic_timer;
Timer mana_timer;

View File

@ -114,7 +114,7 @@ NPC::NPC(const NPCType *npc_type_data, Spawn2 *in_respawn, const glm::vec4 &posi
npc_type_data->legtexture,
npc_type_data->feettexture,
npc_type_data->use_model,
npc_type_data->always_aggros_foes
npc_type_data->always_aggro
),
attacked_timer(CombatEventTimer_expire),
swarm_timer(100),
@ -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;

View 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, "$$");

View File

@ -906,6 +906,15 @@ bool QuestManager::isdisctome(int item_id) {
return(true);
}
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;
}
void QuestManager::safemove() {
QuestManagerCurrentQuestVars();
if (initiator && initiator->IsClient())
@ -2432,6 +2441,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 +2599,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 +2715,16 @@ 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;
}
uint16 QuestManager::CreateInstance(const char *zone, int16 version, uint32 duration)
{
QuestManagerCurrentQuestVars();
@ -2811,6 +2866,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();
@ -2876,6 +2935,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();

View File

@ -107,6 +107,7 @@ public:
void level(int newlevel);
void traindisc(int discipline_tome_item_id);
bool isdisctome(int item_id);
std::string getspellname(uint32 spell_id);
void safemove();
void rain(int weather);
void snow(int weather);
@ -213,12 +214,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 +246,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);
@ -251,6 +256,9 @@ public:
const char* varlink(char* perltext, int item_id);
std::string saylink(char *saylink_text, bool silent, const char *link_name);
const char* getguildnamebyid(int guild_id);
int getguildidbycharid(uint32 char_id);
int getgroupidbycharid(uint32 char_id);
int getraididbycharid(uint32 char_id);
void SetRunning(bool val);
bool IsRunning();
void FlyMode(GravityBehavior flymode);

View File

@ -728,15 +728,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 +814,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());
}
}
}

View File

@ -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);

View File

@ -3426,6 +3426,8 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r
bool isproc, int level_override)
{
bool 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,7 @@ 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)){
if(!IsEffectInSpell(spell_id, SE_BindAffinity) && !is_damage_or_lifetap_spell){
entity_list.QueueCloseClients(
spelltar, /* Sender */
message_packet, /* Packet */
@ -3990,6 +3989,19 @@ 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 &&
(IsClient() ||
(HasOwner() &&
GetOwner()->IsClient()
)
)
) {
(HasOwner() ? GetOwner() : this)->CastToClient()->QueuePacket(
message_packet,
true,
Mob::CLIENT_CONNECTINGALL,
(spelltar->IsClient() ? FilterPCSpells : FilterNPCSpells)
);
}
safe_delete(action_packet);
safe_delete(message_packet);

View File

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

View File

@ -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);

View File

@ -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: {

View File

@ -2507,7 +2507,7 @@ const NPCType *ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
"npc_types.stuck_behavior, "
"npc_types.model, "
"npc_types.flymode, "
"npc_types.always_aggros_foes "
"npc_types.always_aggro "
"FROM npc_types %s",
where_condition.c_str()
);
@ -2709,7 +2709,7 @@ const NPCType *ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
temp_npctype_data->stuck_behavior = atoi(row[109]);
temp_npctype_data->use_model = atoi(row[110]);
temp_npctype_data->flymode = atoi(row[111]);
temp_npctype_data->always_aggros_foes = atoi(row[112]);
temp_npctype_data->always_aggro = atoi(row[112]);
temp_npctype_data->skip_auto_scale = false; // hardcoded here for now
@ -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;

View File

@ -147,7 +147,7 @@ struct NPCType
int8 stuck_behavior;
uint16 use_model;
int8 flymode;
bool always_aggros_foes;
bool always_aggro;
};
namespace player_lootitem {