Compare commits

..

8 Commits

Author SHA1 Message Date
KimLS 3ef106dc64 Bot compile fix 2021-09-27 00:57:04 -07:00
KimLS 7453326f87 HP overflow is now gated by a rule for clients (bots and mercs will always get fixed hp), fix for phantom stat aa regression 2021-09-21 21:29:28 -07:00
KimLS b82dfb91ae Fix for bot breaking, I don't normally build bots. 2021-09-16 11:21:37 -07:00
KimLS 5891b2c426 Change out 300 for named constant 2021-09-16 00:58:57 -07:00
KimLS 6e16f6c1b6 Match the client's bugged state with natural durability, remove redundant statbonus maxhp 2021-09-16 00:53:11 -07:00
KimLS fba333fe8a Suggested change, and simplified the AA function 2021-09-11 22:42:35 -07:00
KimLS edb7ea4ee3 Fix for build 2021-09-11 21:21:50 -07:00
KimLS 66cf4b546c Various changes:
- Heroic Sta HP calc will now apply after natural durability.
- The base 5 hp that everyone gets will now apply after natural
durability.
- Fixed a rounding issue in the mana calc that would sometimes give
the player +1 mana
- Fixed the endurance calc to match the client better.
- When a server has a custom stat cap active the new stat caps
will be reflected on the client.
    This is done by reserving an AA slot for a "Phantom" AA that will
    act like Planar Power with the difference between what the client
    sees and what the server has.
- AA slots cap now will be 300 (the later clients max)
instead of 240 (titanium's max)
2021-09-10 19:52:28 -07:00
218 changed files with 19777 additions and 32118 deletions
+1 -2
View File
@@ -9,8 +9,7 @@
"defines": [], "defines": [],
"compilerPath": "/usr/bin/gcc", "compilerPath": "/usr/bin/gcc",
"cStandard": "c11", "cStandard": "c11",
"cppStandard": "c++17", "cppStandard": "c++17"
"configurationProvider": "ms-vscode.cmake-tools"
} }
], ],
"version": 4 "version": 4
-8
View File
@@ -1,8 +0,0 @@
{
"files.associations": {
"chrono": "cpp",
"xutility": "cpp",
"iterator": "cpp",
"*.ipp": "cpp"
}
}
+14 -14
View File
@@ -6,7 +6,7 @@
{ {
"label": "make", "label": "make",
"type": "shell", "type": "shell",
"command": "mkdir -p build && cd build && make", "command": "cd bin && make",
"group": { "group": {
"kind": "build", "kind": "build",
"isDefault": true "isDefault": true
@@ -18,7 +18,7 @@
{ {
"label": "make clean", "label": "make clean",
"type": "shell", "type": "shell",
"command": "mkdir -p build && cd build && make clean", "command": "cd bin && make clean",
"group": { "group": {
"kind": "build", "kind": "build",
"isDefault": true "isDefault": true
@@ -30,7 +30,7 @@
{ {
"label": "cmake", "label": "cmake",
"type": "shell", "type": "shell",
"command": "mkdir -p build && cd build && rm CMakeCache.txt && cmake -DEQEMU_BUILD_LOGIN=ON -DEQEMU_BUILD_LUA=ON -G 'Unix Makefiles' ..", "command": "mkdir -p bin && cd bin && rm CMakeCache.txt && cmake -DEQEMU_BUILD_LOGIN=ON -DEQEMU_BUILD_LUA=ON -G 'Unix Makefiles' ..",
"group": { "group": {
"kind": "build", "kind": "build",
"isDefault": true "isDefault": true
@@ -52,7 +52,7 @@
{ {
"label": "download maps", "label": "download maps",
"type": "shell", "type": "shell",
"command": "mkdir -p build && cd build/bin && wget https://codeload.github.com/Akkadius/EQEmuMaps/zip/master -O maps.zip && unzip -o maps.zip && rm ./maps -rf && mv EQEmuMaps-master maps && rm maps.zip", "command": "mkdir -p bin && cd bin && wget https://codeload.github.com/Akkadius/EQEmuMaps/zip/master -O maps.zip && unzip -o maps.zip && rm ./maps -rf && mv EQEmuMaps-master maps && rm maps.zip",
"group": { "group": {
"kind": "build", "kind": "build",
"isDefault": true "isDefault": true
@@ -64,7 +64,7 @@
{ {
"label": "download quests", "label": "download quests",
"type": "shell", "type": "shell",
"command": "mkdir -p build && cd build/bin && cd server && git -C ./quests pull 2> /dev/null || git clone https://github.com/ProjectEQ/projecteqquests.git quests", "command": "mkdir -p bin && cd bin && cd server && git -C ./quests pull 2> /dev/null || git clone https://github.com/ProjectEQ/projecteqquests.git quests",
"group": { "group": {
"kind": "build", "kind": "build",
"isDefault": true "isDefault": true
@@ -76,7 +76,7 @@
{ {
"label": "download eqemu_config", "label": "download eqemu_config",
"type": "shell", "type": "shell",
"command": "mkdir -p build && cd build/bin && wget --no-check-certificate https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/eqemu_config_docker.json -O eqemu_config.json", "command": "mkdir -p bin && cd bin && wget --no-check-certificate https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/eqemu_config_docker.json -O eqemu_config.json",
"group": { "group": {
"kind": "build", "kind": "build",
"isDefault": true "isDefault": true
@@ -88,7 +88,7 @@
{ {
"label": "rebuild database (mariadb must be started)", "label": "rebuild database (mariadb must be started)",
"type": "shell", "type": "shell",
"command": "mkdir -p build && cd build/bin && docker run -i --rm --privileged -v ${HOST_PROJECT_PATH}/build/bin:/src --network=eqemu -it eqemu/server:0.0.3 bash -c './eqemu_server.pl source_peq_db && ./eqemu_server.pl check_db_updates && ./eqemu_server.pl assets && ./eqemu_server.pl lua_modules && ./eqemu_server.pl opcodes && ./eqemu_server.pl linux_login_server_setup'", "command": "mkdir -p bin && cd bin && docker run -i --rm --privileged -v ${HOST_PROJECT_PATH}/bin:/src --network=eqemu -it eqemu/server:0.0.3 bash -c './eqemu_server.pl source_peq_db && ./eqemu_server.pl check_db_updates && ./eqemu_server.pl linux_login_server_setup'",
"group": { "group": {
"kind": "build", "kind": "build",
"isDefault": true "isDefault": true
@@ -100,7 +100,7 @@
{ {
"label": "zone 7000", "label": "zone 7000",
"type": "shell", "type": "shell",
"command": "docker stop zone7000 | true && docker network create eqemu | true && docker run -i --rm --name zone7000 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --privileged -v ${HOST_PROJECT_PATH}/build/bin:/src --ulimit core=10000000 --network=eqemu -p 7000:7000/udp -e LD_LIBRARY_PATH=/src/ eqemu/server:0.0.3 gdb -ex run --args ./zone dynamic_zone7000:7000", "command": "docker stop zone7000 | true && docker network create eqemu | true && docker run -i --rm --name zone7000 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --privileged -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 --network=eqemu -p 7000:7000/udp -e LD_LIBRARY_PATH=/src/ eqemu/server:0.0.3 gdb -ex run --args ./zone dynamic_zone7000:7000",
"group": { "group": {
"kind": "test", "kind": "test",
"isDefault": true "isDefault": true
@@ -109,7 +109,7 @@
{ {
"label": "zone 7001", "label": "zone 7001",
"type": "shell", "type": "shell",
"command": "docker stop zone7001 | true && docker network create eqemu | true && docker run -i --rm --name zone7001 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --privileged -v ${HOST_PROJECT_PATH}/build/bin:/src --ulimit core=10000000 --network=eqemu -p 7001:7001/udp -e LD_LIBRARY_PATH=/src/ eqemu/server:0.0.3 gdb -ex run --args ./zone dynamic_zone7001:7001", "command": "docker stop zone7001 | true && docker network create eqemu | true && docker run -i --rm --name zone7001 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --privileged -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 --network=eqemu -p 7001:7001/udp -e LD_LIBRARY_PATH=/src/ eqemu/server:0.0.3 gdb -ex run --args ./zone dynamic_zone7001:7001",
"group": { "group": {
"kind": "test", "kind": "test",
"isDefault": true "isDefault": true
@@ -118,7 +118,7 @@
{ {
"label": "loginserver", "label": "loginserver",
"type": "shell", "type": "shell",
"command": "docker stop loginserver | true && docker network create eqemu | true && docker run -i --rm --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --privileged -v ${HOST_PROJECT_PATH}/build/bin:/src --ulimit core=10000000 --network=eqemu --name loginserver -p 5999:5999/udp -p 5998:5998/udp -e LD_LIBRARY_PATH=/src/ eqemu/server:0.0.3 gdb -ex run --args ./loginserver", "command": "docker stop loginserver | true && docker network create eqemu | true && docker run -i --rm --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --privileged -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 --network=eqemu --name loginserver -p 5999:5999/udp -p 5998:5998/udp -e LD_LIBRARY_PATH=/src/ eqemu/server:0.0.3 gdb -ex run --args ./loginserver",
"group": { "group": {
"kind": "test", "kind": "test",
"isDefault": true "isDefault": true
@@ -127,7 +127,7 @@
{ {
"label": "shared_memory, world", "label": "shared_memory, world",
"type": "shell", "type": "shell",
"command": "docker stop sharedmemory | true && docker stop world | true && docker network create eqemu | true && docker run --rm -v ${HOST_PROJECT_PATH}/build/bin:/src --network=eqemu --name sharedmemory eqemu/server:0.0.3 ./shared_memory && docker run --rm -v ${HOST_PROJECT_PATH}/build/bin:/src --ulimit core=10000000 -e LD_LIBRARY_PATH=/src/ --network=eqemu --name world -p 9000:9000 -p 9000:9000/udp -p 9001:9001 -p 9080:9080 eqemu/server:0.0.3 gdb -ex run ./world", "command": "docker stop sharedmemory | true && docker stop world | true && docker network create eqemu | true && docker run --rm -v ${HOST_PROJECT_PATH}/bin:/src --network=eqemu --name sharedmemory eqemu/server:0.0.3 ./shared_memory && docker run --rm -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 -e LD_LIBRARY_PATH=/src/ --network=eqemu --name world -p 9000:9000 -p 9000:9000/udp -p 9001:9001 -p 9080:9080 eqemu/server:0.0.3 gdb -ex run ./world",
"group": { "group": {
"kind": "test", "kind": "test",
"isDefault": true "isDefault": true
@@ -136,7 +136,7 @@
{ {
"label": "queryserv", "label": "queryserv",
"type": "shell", "type": "shell",
"command": "docker stop queryserv | true && docker run --rm -v ${HOST_PROJECT_PATH}/build/bin:/src --ulimit core=10000000 -e LD_LIBRARY_PATH=/src/ --network=eqemu --name queryserv eqemu/server:0.0.3 gdb -ex run ./queryserv", "command": "docker stop queryserv | true && docker run --rm -v ${HOST_PROJECT_PATH}/bin:/src --ulimit core=10000000 -e LD_LIBRARY_PATH=/src/ --network=eqemu --name queryserv eqemu/server:0.0.3 gdb -ex run ./queryserv",
"group": { "group": {
"kind": "test", "kind": "test",
"isDefault": true "isDefault": true
@@ -145,7 +145,7 @@
{ {
"label": "mariadb", "label": "mariadb",
"type": "shell", "type": "shell",
"command": "docker stop mariadb | true && cd bin && docker network create eqemu | true && docker run --rm -v ${HOST_PROJECT_PATH}/build/bin/db:/bitnami/mariadb -p 3306:3306 -e MARIADB_DATABASE=peq -e MARIADB_USER=eqemu -e MARIADB_PASSWORD=eqemupass -e ALLOW_EMPTY_PASSWORD=yes --name mariadb --network=eqemu bitnami/mariadb:latest", "command": "docker stop mariadb | true && cd bin && docker network create eqemu | true && docker run --rm -v ${HOST_PROJECT_PATH}/bin/db:/bitnami/mariadb -p 3306:3306 -e MARIADB_DATABASE=peq -e MARIADB_USER=eqemu -e MARIADB_PASSWORD=eqemupass -e ALLOW_EMPTY_PASSWORD=yes --name mariadb --network=eqemu bitnami/mariadb:latest",
"group": { "group": {
"kind": "test", "kind": "test",
"isDefault": true "isDefault": true
@@ -154,7 +154,7 @@
{ {
"label": "ucs", "label": "ucs",
"type": "shell", "type": "shell",
"command": "docker stop ucs | true && cd bin && docker network create eqemu | true && docker run --rm -v ${HOST_PROJECT_PATH}/build/bin:/src -p 7778:7778 --name ucs --network=eqemu eqemu/server:0.0.3 gdb -ex run ./ucs", "command": "docker stop ucs | true && cd bin && docker network create eqemu | true && docker run --rm -v ${HOST_PROJECT_PATH}/bin:/src -p 7778:7778 --name ucs --network=eqemu eqemu/server:0.0.3 gdb -ex run ./ucs",
"group": { "group": {
"kind": "test", "kind": "test",
"isDefault": true "isDefault": true
+1 -1
View File
@@ -3,7 +3,7 @@
############################################ ############################################
# #
# New changelog can be found here # New changelog can be found here
# https://docs.eqemu.io/server/changelog/server # https://eqemu.gitbook.io/changelog/
# #
############################################ ############################################
# Deprecated # Deprecated
+1 -3
View File
@@ -526,7 +526,6 @@ SET(common_headers
guild_base.h guild_base.h
guilds.h guilds.h
http/httplib.h http/httplib.h
http/uri.h
inventory_profile.h inventory_profile.h
inventory_slot.h inventory_slot.h
ipc_mutex.h ipc_mutex.h
@@ -639,8 +638,7 @@ SET(common_headers
StackWalker/StackWalker.h StackWalker/StackWalker.h
util/memory_stream.h util/memory_stream.h
util/directory.h util/directory.h
util/uuid.h util/uuid.h)
)
SOURCE_GROUP(Event FILES SOURCE_GROUP(Event FILES
event/event_loop.h event/event_loop.h
+26 -124
View File
@@ -39,7 +39,6 @@
#include "unix.h" #include "unix.h"
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/time.h> #include <sys/time.h>
#endif #endif
#include "database.h" #include "database.h"
@@ -47,8 +46,6 @@
#include "extprofile.h" #include "extprofile.h"
#include "string_util.h" #include "string_util.h"
#include "database_schema.h" #include "database_schema.h"
#include "http/httplib.h"
#include "http/uri.h"
extern Client client; extern Client client;
@@ -2042,64 +2039,62 @@ void Database::ClearRaidLeader(uint32 gid, uint32 rid)
QueryDatabase(query); QueryDatabase(query);
} }
void Database::UpdateAdventureStatsEntry(uint32 char_id, uint8 theme, bool win, bool remove) void Database::UpdateAdventureStatsEntry(uint32 char_id, uint8 theme, bool win)
{ {
std::string field; std::string field;
switch(theme) {
case LDoNThemes::GUK: { switch(theme)
{
case 1:
{
field = "guk_"; field = "guk_";
break; break;
} }
case LDoNThemes::MIR: { case 2:
{
field = "mir_"; field = "mir_";
break; break;
} }
case LDoNThemes::MMC: { case 3:
{
field = "mmc_"; field = "mmc_";
break; break;
} }
case LDoNThemes::RUJ: { case 4:
{
field = "ruj_"; field = "ruj_";
break; break;
} }
case LDoNThemes::TAK: { case 5:
{
field = "tak_"; field = "tak_";
break; break;
} }
default: { default:
{
return; return;
} }
} }
field += win ? "wins" : "losses"; if (win)
std::string field_operation = remove ? "-" : "+"; field += "wins";
else
field += "losses";
std::string query = fmt::format( std::string query = StringFormat("UPDATE `adventure_stats` SET %s=%s+1 WHERE player_id=%u",field.c_str(), field.c_str(), char_id);
"UPDATE `adventure_stats` SET {} = {} {} 1 WHERE player_id = {}",
field,
field,
field_operation,
char_id
);
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
if (results.RowsAffected() != 0) { if (results.RowsAffected() != 0)
return; return;
}
if (!remove) { query = StringFormat("INSERT INTO `adventure_stats` SET %s=1, player_id=%u", field.c_str(), char_id);
query = fmt::format(
"INSERT INTO `adventure_stats` SET {} = 1, player_id = {}",
field,
char_id
);
QueryDatabase(query); QueryDatabase(query);
} }
}
bool Database::GetAdventureStats(uint32 char_id, AdventureStats_Struct *as) bool Database::GetAdventureStats(uint32 char_id, AdventureStats_Struct *as)
{ {
std::string query = fmt::format( std::string query = StringFormat(
"SELECT " "SELECT "
"`guk_wins`, " "`guk_wins`, "
"`mir_wins`, " "`mir_wins`, "
@@ -2114,7 +2109,7 @@ bool Database::GetAdventureStats(uint32 char_id, AdventureStats_Struct *as)
"FROM " "FROM "
"`adventure_stats` " "`adventure_stats` "
"WHERE " "WHERE "
"player_id = {}", "player_id = %u ",
char_id char_id
); );
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
@@ -2273,35 +2268,6 @@ int Database::GetIPExemption(std::string account_ip) {
return RuleI(World, MaxClientsPerIP); return RuleI(World, MaxClientsPerIP);
} }
void Database::SetIPExemption(std::string account_ip, int exemption_amount) {
std::string query = fmt::format(
"SELECT `exemption_id` FROM `ip_exemptions` WHERE `exemption_ip` = '{}'",
account_ip
);
auto results = QueryDatabase(query);
uint32 exemption_id = 0;
if (results.Success() && results.RowCount() > 0) {
auto row = results.begin();
exemption_id = atoi(row[0]);
}
query = fmt::format(
"INSERT INTO `ip_exemptions` (`exemption_ip`, `exemption_amount`) VALUES ('{}', {})",
account_ip,
exemption_amount
);
if (exemption_id != 0) {
query = fmt::format(
"UPDATE `ip_exemptions` SET `exemption_amount` = {} WHERE `exemption_ip` = '{}'",
exemption_amount,
account_ip
);
}
QueryDatabase(query);
}
int Database::GetInstanceID(uint32 char_id, uint32 zone_id) { int Database::GetInstanceID(uint32 char_id, uint32 zone_id) {
std::string query = StringFormat("SELECT instance_list.id FROM instance_list INNER JOIN instance_list_player ON instance_list.id = instance_list_player.id WHERE instance_list.zone = '%i' AND instance_list_player.charid = '%i'", zone_id, char_id); std::string query = StringFormat("SELECT instance_list.id FROM instance_list INNER JOIN instance_list_player ON instance_list.id = instance_list_player.id WHERE instance_list.zone = '%i' AND instance_list_player.charid = '%i'", zone_id, char_id);
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
@@ -2452,67 +2418,3 @@ bool Database::CopyCharacter(
return true; return true;
} }
void Database::SourceDatabaseTableFromUrl(std::string table_name, std::string url)
{
try {
uri request_uri(url);
LogHTTP(
"[SourceDatabaseTableFromUrl] parsing url [{}] path [{}] host [{}] query_string [{}] protocol [{}] port [{}]",
url,
request_uri.get_path(),
request_uri.get_host(),
request_uri.get_query(),
request_uri.get_scheme(),
request_uri.get_port()
);
if (!DoesTableExist(table_name)) {
LogMySQLQuery("Table [{}] does not exist. Downloading from Github and installing...", table_name);
// http get request
httplib::Client cli(
fmt::format(
"{}://{}",
request_uri.get_scheme(),
request_uri.get_host()
).c_str()
);
cli.set_connection_timeout(0, 60000000); // 60 sec
cli.set_read_timeout(60, 0); // 60 seconds
cli.set_write_timeout(60, 0); // 60 seconds
int sourced_queries = 0;
if (auto res = cli.Get(request_uri.get_path().c_str())) {
if (res->status == 200) {
for (auto &s: SplitString(res->body, ';')) {
if (!trim(s).empty()) {
auto results = QueryDatabase(s);
if (!results.ErrorMessage().empty()) {
LogError("Error sourcing SQL [{}]", results.ErrorMessage());
return;
}
sourced_queries++;
}
}
}
}
else {
LogError("Error retrieving URL [{}]", url);
}
LogMySQLQuery(
"Table [{}] installed. Sourced [{}] queries",
table_name,
sourced_queries
);
}
}
catch (std::invalid_argument iae) {
LogError("[SourceDatabaseTableFromUrl] URI parser error [{}]", iae.what());
}
}
+1 -4
View File
@@ -176,7 +176,7 @@ public:
/* Adventure related. */ /* Adventure related. */
void UpdateAdventureStatsEntry(uint32 char_id, uint8 theme, bool win = false, bool remove = false); void UpdateAdventureStatsEntry(uint32 char_id, uint8 theme, bool win);
bool GetAdventureStats(uint32 char_id, AdventureStats_Struct *as); bool GetAdventureStats(uint32 char_id, AdventureStats_Struct *as);
/* Account Related */ /* Account Related */
@@ -199,7 +199,6 @@ public:
void SetAgreementFlag(uint32 acctid); void SetAgreementFlag(uint32 acctid);
int GetIPExemption(std::string account_ip); int GetIPExemption(std::string account_ip);
void SetIPExemption(std::string account_ip, int exemption_amount);
int GetInstanceID(uint32 char_id, uint32 zone_id); int GetInstanceID(uint32 char_id, uint32 zone_id);
@@ -270,8 +269,6 @@ public:
int CountInvSnapshots(); int CountInvSnapshots();
void ClearInvSnapshots(bool from_now = false); void ClearInvSnapshots(bool from_now = false);
void SourceDatabaseTableFromUrl(std::string table_name, std::string url);
private: private:
-45
View File
@@ -18,7 +18,6 @@
*/ */
#include "emu_constants.h" #include "emu_constants.h"
#include "languages.h"
int16 EQ::invtype::GetInvTypeSize(int16 inv_type) { int16 EQ::invtype::GetInvTypeSize(int16 inv_type) {
@@ -153,47 +152,3 @@ int EQ::constants::ConvertStanceTypeToIndex(StanceType stance_type) {
return 0; return 0;
} }
const std::map<int, std::string>& EQ::constants::GetLanguageMap()
{
static const std::map<int, std::string> language_map = {
{ LANG_COMMON_TONGUE, "Common Tongue" },
{ LANG_BARBARIAN, "Barbarian" },
{ LANG_ERUDIAN, "Erudian" },
{ LANG_ELVISH, "Elvish" },
{ LANG_DARK_ELVISH, "Dark Elvish" },
{ LANG_DWARVISH, "Dwarvish" },
{ LANG_TROLL, "Troll" },
{ LANG_OGRE, "Ogre" },
{ LANG_GNOMISH, "Gnomish" },
{ LANG_HALFLING, "Halfling" },
{ LANG_THIEVES_CANT, "Thieves Cant" },
{ LANG_OLD_ERUDIAN, "Old Erudian" },
{ LANG_ELDER_ELVISH, "Elder Elvish" },
{ LANG_FROGLOK, "Froglok" },
{ LANG_GOBLIN, "Goblin" },
{ LANG_GNOLL, "Gnoll" },
{ LANG_COMBINE_TONGUE, "Combine Tongue" },
{ LANG_ELDER_TEIRDAL, "Elder Teirdal" },
{ LANG_LIZARDMAN, "Lizardman" },
{ LANG_ORCISH, "Orcish" },
{ LANG_FAERIE, "Faerie" },
{ LANG_DRAGON, "Dragon" },
{ LANG_ELDER_DRAGON, "Elder Dragon" },
{ LANG_DARK_SPEECH, "Dark Speech" },
{ LANG_VAH_SHIR, "Vah Shir" },
{ LANG_ALARAN, "Alaran" },
{ LANG_HADAL, "Hadal" },
{ LANG_UNKNOWN, "Unknown" }
};
return language_map;
}
std::string EQ::constants::GetLanguageName(int language_id)
{
if (language_id >= LANG_COMMON_TONGUE && language_id <= LANG_UNKNOWN) {
auto languages = EQ::constants::GetLanguageMap();
return languages[language_id];
}
return std::string();
}
-3
View File
@@ -223,9 +223,6 @@ namespace EQ
const char *GetStanceName(StanceType stance_type); const char *GetStanceName(StanceType stance_type);
int ConvertStanceTypeToIndex(StanceType stance_type); int ConvertStanceTypeToIndex(StanceType stance_type);
extern const std::map<int, std::string>& GetLanguageMap();
std::string GetLanguageName(int language_id);
const int STANCE_TYPE_FIRST = stancePassive; const int STANCE_TYPE_FIRST = stancePassive;
const int STANCE_TYPE_LAST = stanceBurnAE; const int STANCE_TYPE_LAST = stanceBurnAE;
const int STANCE_TYPE_COUNT = stanceBurnAE; const int STANCE_TYPE_COUNT = stanceBurnAE;
-35
View File
@@ -974,39 +974,4 @@ enum class DynamicZoneMemberStatus : uint8_t
LinkDead LinkDead
}; };
enum LDoNThemes {
Unused = 0,
GUK,
MIR,
MMC,
RUJ,
TAK
};
enum LDoNThemeBits {
UnusedBit = 0,
GUKBit = 1,
MIRBit = 2,
MMCBit = 4,
RUJBit = 8,
TAKBit = 16
};
enum StartZoneIndex {
Odus = 0,
Qeynos,
Halas,
Rivervale,
Freeport,
Neriak,
Grobb,
Oggok,
Kaladim,
GreaterFaydark,
Felwithe,
Akanon,
Cabilis,
SharVahl
};
#endif /*COMMON_EQ_CONSTANTS_H*/ #endif /*COMMON_EQ_CONSTANTS_H*/
+6 -8
View File
@@ -384,9 +384,7 @@ struct NewZone_Struct {
/*0716*/ uint32 FastRegenEndurance; /*0716*/ uint32 FastRegenEndurance;
/*0720*/ uint32 NPCAggroMaxDist; /*0720*/ uint32 NPCAggroMaxDist;
/*0724*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, if this value is 0, it prevents you from running off edges that would end up underworld /*0724*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, if this value is 0, it prevents you from running off edges that would end up underworld
/*0728*/ uint32 LavaDamage; // Seen 50 /*0728*/
/*0732*/ uint32 MinLavaDamage; // Seen 10
/*0736*/
}; };
/* /*
@@ -862,7 +860,7 @@ static const uint32 MAX_PP_LANGUAGE = 28;
static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE; // 100 - actual skills buffer size static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE; // 100 - actual skills buffer size
static const uint32 MAX_PP_INNATE_SKILL = 25; static const uint32 MAX_PP_INNATE_SKILL = 25;
static const uint32 MAX_PP_AA_ARRAY = 240; static const uint32 MAX_PP_AA_ARRAY = 300;
static const uint32 MAX_GROUP_MEMBERS = 6; static const uint32 MAX_GROUP_MEMBERS = 6;
static const uint32 MAX_RECAST_TYPES = 20; static const uint32 MAX_RECAST_TYPES = 20;
@@ -4342,8 +4340,8 @@ struct AARankPrereq_Struct
struct AARankEffect_Struct struct AARankEffect_Struct
{ {
int32 effect_id; int32 effect_id;
int32 base_value; int32 base1;
int32 limit_value; int32 base2;
int32 slot; int32 slot;
}; };
@@ -4351,8 +4349,8 @@ struct AARankEffect_Struct
struct AA_Ability { struct AA_Ability {
/*00*/ uint32 skill_id; /*00*/ uint32 skill_id;
/*04*/ uint32 base_value; /*04*/ uint32 base1;
/*08*/ uint32 limit_value; /*08*/ uint32 base2;
/*12*/ uint32 slot; /*12*/ uint32 slot;
}; };
-13
View File
@@ -44,12 +44,6 @@ void EQEmuConfig::parse_config()
if (_root["server"]["world"]["loginserver"].get("legacy", "0").asString() == "1") { LoginLegacy = true; } if (_root["server"]["world"]["loginserver"].get("legacy", "0").asString() == "1") { LoginLegacy = true; }
LoginAccount = _root["server"]["world"]["loginserver"].get("account", "").asString(); LoginAccount = _root["server"]["world"]["loginserver"].get("account", "").asString();
LoginPassword = _root["server"]["world"]["loginserver"].get("password", "").asString(); LoginPassword = _root["server"]["world"]["loginserver"].get("password", "").asString();
// at least today, this is wrong a majority of the time
// remove this if eqemulator ever upgrades its loginserver
if (LoginHost.find("login.eqemulator.net") != std::string::npos) {
LoginLegacy = true;
}
} }
else { else {
char str[32]; char str[32];
@@ -68,13 +62,6 @@ void EQEmuConfig::parse_config()
loginconfig->LoginLegacy = false; loginconfig->LoginLegacy = false;
if (_root["server"]["world"][str].get("legacy", "0").asString() == "1") { loginconfig->LoginLegacy = true; } if (_root["server"]["world"][str].get("legacy", "0").asString() == "1") { loginconfig->LoginLegacy = true; }
// at least today, this is wrong a majority of the time
// remove this if eqemulator ever upgrades its loginserver
if (loginconfig->LoginHost.find("login.eqemulator.net") != std::string::npos) {
loginconfig->LoginLegacy = true;
}
loginlist.Insert(loginconfig); loginlist.Insert(loginconfig);
} while (LoginCount < 100); } while (LoginCount < 100);
} }
-2
View File
@@ -130,8 +130,6 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
log_settings[Logs::Loot].log_to_gmsay = static_cast<uint8>(Logs::General); log_settings[Logs::Loot].log_to_gmsay = static_cast<uint8>(Logs::General);
log_settings[Logs::Scheduler].log_to_console = static_cast<uint8>(Logs::General); log_settings[Logs::Scheduler].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Cheat].log_to_console = static_cast<uint8>(Logs::General); log_settings[Logs::Cheat].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::HTTP].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::HTTP].log_to_gmsay = static_cast<uint8>(Logs::General);
/** /**
* RFC 5424 * RFC 5424
-4
View File
@@ -125,8 +125,6 @@ namespace Logs {
Cheat, Cheat,
ClientList, ClientList,
DiaWind, DiaWind,
HTTP,
Saylink,
MaxCategoryID /* Don't Remove this */ MaxCategoryID /* Don't Remove this */
}; };
@@ -210,8 +208,6 @@ namespace Logs {
"Cheat", "Cheat",
"ClientList", "ClientList",
"DialogueWindow", "DialogueWindow",
"HTTP",
"Saylink",
}; };
} }
-26
View File
@@ -676,26 +676,6 @@
OutF(LogSys, Logs::Detail, Logs::DiaWind, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\ OutF(LogSys, Logs::Detail, Logs::DiaWind, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0) } while (0)
#define LogHTTP(message, ...) do {\
if (LogSys.log_settings[Logs::HTTP].is_category_enabled == 1)\
OutF(LogSys, Logs::General, Logs::HTTP, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogHTTPDetail(message, ...) do {\
if (LogSys.log_settings[Logs::HTTP].is_category_enabled == 1)\
OutF(LogSys, Logs::Detail, Logs::HTTP, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogSaylink(message, ...) do {\
if (LogSys.log_settings[Logs::Saylink].is_category_enabled == 1)\
OutF(LogSys, Logs::General, Logs::Saylink, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogSaylinkDetail(message, ...) do {\
if (LogSys.log_settings[Logs::Saylink].is_category_enabled == 1)\
OutF(LogSys, Logs::Detail, Logs::Saylink, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define Log(debug_level, log_category, message, ...) do {\ #define Log(debug_level, log_category, message, ...) do {\
if (LogSys.log_settings[log_category].is_category_enabled == 1)\ if (LogSys.log_settings[log_category].is_category_enabled == 1)\
LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\ LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
@@ -1086,12 +1066,6 @@
#define LogDiaWindDetail(message, ...) do {\ #define LogDiaWindDetail(message, ...) do {\
} while (0) } while (0)
#define LogHTTP(message, ...) do {\
} while (0)
#define LogHTTPDetail(message, ...) do {\
} while (0)
#define Log(debug_level, log_category, message, ...) do {\ #define Log(debug_level, log_category, message, ...) do {\
} while (0) } while (0)
-633
View File
@@ -1,633 +0,0 @@
// Copyright (C) 2015 Ben Lewis <benjf5+github@gmail.com>
// Licensed under the MIT license.
// https://github.com/ben-zen/uri-library
#pragma once
#include <cctype>
#include <map>
#include <string>
#include <stdexcept>
#include <utility>
class uri {
/* URIs are broadly divided into two categories: hierarchical and
* non-hierarchical. Both hierarchical URIs and non-hierarchical URIs have a
* few elements in common; all URIs have a scheme of one or more alphanumeric
* characters followed by a colon, and they all may optionally have a query
* component preceded by a question mark, and a fragment component preceded by
* an octothorpe (hash mark: '#'). The query consists of stanzas separated by
* either ampersands ('&') or semicolons (';') (but only one or the other),
* and each stanza consists of a key and an optional value; if the value
* exists, the key and value must be divided by an equals sign.
*
* The following is an example from Wikipedia of a hierarchical URI:
* scheme:[//[user:password@]domain[:port]][/]path[?query][#fragment]
*/
public:
enum class scheme_category {
Hierarchical,
NonHierarchical
};
enum class component {
Scheme,
Content,
Username,
Password,
Host,
Port,
Path,
Query,
Fragment
};
enum class query_argument_separator {
ampersand,
semicolon
};
uri(
char const *uri_text, scheme_category category = scheme_category::Hierarchical,
query_argument_separator separator = query_argument_separator::ampersand
) :
m_category(category),
m_path_is_rooted(false),
m_port(0),
m_separator(separator)
{
setup(std::string(uri_text), category);
};
uri(
std::string const &uri_text, scheme_category category = scheme_category::Hierarchical,
query_argument_separator separator = query_argument_separator::ampersand
) :
m_category(category),
m_path_is_rooted(false),
m_port(0),
m_separator(separator)
{
setup(uri_text, category);
};
uri(
std::map<component, std::string> const &components,
scheme_category category,
bool rooted_path,
query_argument_separator separator = query_argument_separator::ampersand
) :
m_category(category),
m_path_is_rooted(rooted_path),
m_separator(separator)
{
if (components.count(component::Scheme)) {
if (components.at(component::Scheme).length() == 0) {
throw std::invalid_argument("Scheme cannot be empty.");
}
m_scheme = components.at(component::Scheme);
}
else {
throw std::invalid_argument("A URI must have a scheme.");
}
if (category == scheme_category::Hierarchical) {
if (components.count(component::Content)) {
throw std::invalid_argument("The content component is only for use in non-hierarchical URIs.");
}
bool has_username = components.count(component::Username);
bool has_password = components.count(component::Password);
if (has_username && has_password) {
m_username = components.at(component::Username);
m_password = components.at(component::Password);
}
else if ((has_username && !has_password) || (!has_username && has_password)) {
throw std::invalid_argument("If a username or password is supplied, both must be provided.");
}
if (components.count(component::Host)) {
m_host = components.at(component::Host);
}
if (components.count(component::Port)) {
m_port = std::stoul(components.at(component::Port));
}
if (components.count(component::Path)) {
m_path = components.at(component::Path);
}
else {
throw std::invalid_argument("A path is required on a hierarchical URI, even an empty path.");
}
}
else {
if (components.count(component::Username)
|| components.count(component::Password)
|| components.count(component::Host)
|| components.count(component::Port)
|| components.count(component::Path)) {
throw std::invalid_argument("None of the hierarchical components are allowed in a non-hierarchical URI.");
}
if (components.count(component::Content)) {
m_content = components.at(component::Content);
}
else {
throw std::invalid_argument(
"Content is a required component for a non-hierarchical URI, even an empty string."
);
}
}
if (components.count(component::Query)) {
m_query = components.at(component::Query);
}
if (components.count(component::Fragment)) {
m_fragment = components.at(component::Fragment);
}
}
uri(uri const &other, std::map<component, std::string> const &replacements) :
m_category(other.m_category),
m_path_is_rooted(other.m_path_is_rooted),
m_separator(other.m_separator)
{
m_scheme = (replacements.count(component::Scheme))
? replacements.at(component::Scheme) : other.m_scheme;
if (m_category == scheme_category::Hierarchical) {
m_username = (replacements.count(component::Username))
? replacements.at(component::Username) : other.m_username;
m_password = (replacements.count(component::Password))
? replacements.at(component::Password) : other.m_password;
m_host = (replacements.count(component::Host))
? replacements.at(component::Host) : other.m_host;
m_port = (replacements.count(component::Port))
? std::stoul(replacements.at(component::Port)) : other.m_port;
m_path = (replacements.count(component::Path))
? replacements.at(component::Path) : other.m_path;
}
else {
m_content = (replacements.count(component::Content))
? replacements.at(component::Content) : other.m_content;
}
m_query = (replacements.count(component::Query))
? replacements.at(component::Query) : other.m_query;
m_fragment = (replacements.count(component::Fragment))
? replacements.at(component::Fragment) : other.m_fragment;
}
// Copy constructor; just use the copy assignment operator internally.
uri(uri const &other)
{
*this = other;
};
// Copy assignment operator
uri &operator=(uri const &other)
{
if (this != &other) {
m_scheme = other.m_scheme;
m_content = other.m_content;
m_username = other.m_username;
m_password = other.m_password;
m_host = other.m_host;
m_path = other.m_path;
m_query = other.m_query;
m_fragment = other.m_fragment;
m_query_dict = other.m_query_dict;
m_category = other.m_category;
m_port = other.m_port;
m_path_is_rooted = other.m_path_is_rooted;
m_separator = other.m_separator;
}
return *this;
}
~uri() {};
std::string const &get_scheme() const
{
return m_scheme;
};
scheme_category get_scheme_category() const
{
return m_category;
};
std::string const &get_content() const
{
if (m_category != scheme_category::NonHierarchical) {
throw std::domain_error("The content component is only valid for non-hierarchical URIs.");
}
return m_content;
};
std::string const &get_username() const
{
if (m_category != scheme_category::Hierarchical) {
throw std::domain_error("The username component is only valid for hierarchical URIs.");
}
return m_username;
};
std::string const &get_password() const
{
if (m_category != scheme_category::Hierarchical) {
throw std::domain_error("The password component is only valid for hierarchical URIs.");
}
return m_password;
};
std::string const &get_host() const
{
if (m_category != scheme_category::Hierarchical) {
throw std::domain_error("The host component is only valid for hierarchical URIs.");
}
return m_host;
};
unsigned long get_port() const
{
if (m_category != scheme_category::Hierarchical) {
throw std::domain_error("The port component is only valid for hierarchical URIs.");
}
return m_port;
};
std::string const &get_path() const
{
if (m_category != scheme_category::Hierarchical) {
throw std::domain_error("The path component is only valid for hierarchical URIs.");
}
return m_path;
};
std::string const &get_query() const
{
return m_query;
};
std::map<std::string, std::string> const &get_query_dictionary() const
{
return m_query_dict;
};
std::string const &get_fragment() const
{
return m_fragment;
};
std::string to_string() const
{
std::string full_uri;
full_uri.append(m_scheme);
full_uri.append(":");
if (m_content.length() > m_path.length()) {
full_uri.append("//");
if (!(m_username.empty() || m_password.empty())) {
full_uri.append(m_username);
full_uri.append(":");
full_uri.append(m_password);
full_uri.append("@");
}
full_uri.append(m_host);
if (m_port != 0) {
full_uri.append(":");
full_uri.append(std::to_string(m_port));
}
}
if (m_path_is_rooted) {
full_uri.append("/");
}
full_uri.append(m_path);
if (!m_query.empty()) {
full_uri.append("?");
full_uri.append(m_query);
}
if (!m_fragment.empty()) {
full_uri.append("#");
full_uri.append(m_fragment);
}
return full_uri;
};
private:
void setup(std::string const &uri_text, scheme_category category)
{
size_t const uri_length = uri_text.length();
if (uri_length == 0) {
throw std::invalid_argument("URIs cannot be of zero length.");
}
std::string::const_iterator cursor = parse_scheme(
uri_text,
uri_text.begin());
// After calling parse_scheme, *cursor == ':'; none of the following parsers
// expect a separator character, so we advance the cursor upon calling them.
cursor = parse_content(uri_text, (cursor + 1));
if ((cursor != uri_text.end()) && (*cursor == '?')) {
cursor = parse_query(uri_text, (cursor + 1));
}
if ((cursor != uri_text.end()) && (*cursor == '#')) {
cursor = parse_fragment(uri_text, (cursor + 1));
}
init_query_dictionary(); // If the query string is empty, this will be empty too.
};
std::string::const_iterator parse_scheme(
std::string const &uri_text,
std::string::const_iterator scheme_start
)
{
std::string::const_iterator scheme_end = scheme_start;
while ((scheme_end != uri_text.end()) && (*scheme_end != ':')) {
if (!(std::isalnum(*scheme_end) || (*scheme_end == '-')
|| (*scheme_end == '+') || (*scheme_end == '.'))) {
throw std::invalid_argument(
"Invalid character found in the scheme component. Supplied URI was: \""
+ uri_text + "\"."
);
}
++scheme_end;
}
if (scheme_end == uri_text.end()) {
throw std::invalid_argument(
"End of URI found while parsing the scheme. Supplied URI was: \""
+ uri_text + "\"."
);
}
if (scheme_start == scheme_end) {
throw std::invalid_argument(
"Scheme component cannot be zero-length. Supplied URI was: \""
+ uri_text + "\"."
);
}
m_scheme = std::move(std::string(scheme_start, scheme_end));
return scheme_end;
};
std::string::const_iterator parse_content(
std::string const &uri_text,
std::string::const_iterator content_start
)
{
std::string::const_iterator content_end = content_start;
while ((content_end != uri_text.end()) && (*content_end != '?') && (*content_end != '#')) {
++content_end;
}
m_content = std::move(std::string(content_start, content_end));
if ((m_category == scheme_category::Hierarchical) && (m_content.length() > 0)) {
// If it's a hierarchical URI, the content should be parsed for the hierarchical components.
std::string::const_iterator path_start = m_content.begin();
std::string::const_iterator path_end = m_content.end();
if (!m_content.compare(0, 2, "//")) {
// In this case an authority component is present.
std::string::const_iterator authority_cursor = (m_content.begin() + 2);
if (m_content.find_first_of('@') != std::string::npos) {
std::string::const_iterator userpass_divider = parse_username(
uri_text,
m_content,
authority_cursor
);
authority_cursor = parse_password(uri_text, m_content, (userpass_divider + 1));
// After this call, *authority_cursor == '@', so we skip over it.
++authority_cursor;
}
authority_cursor = parse_host(uri_text, m_content, authority_cursor);
if ((authority_cursor != m_content.end()) && (*authority_cursor == ':')) {
authority_cursor = parse_port(uri_text, m_content, (authority_cursor + 1));
}
if ((authority_cursor != m_content.end()) && (*authority_cursor == '/')) {
// Then the path is rooted, and we should note this.
m_path_is_rooted = true;
path_start = authority_cursor + 1;
}
// If we've reached the end and no path is present then set path_start
// to the end.
if (authority_cursor == m_content.end()) {
path_start = m_content.end();
}
}
else if (!m_content.compare(0, 1, "/")) {
m_path_is_rooted = true;
++path_start;
}
// We can now build the path based on what remains in the content string,
// since that's all that exists after the host and optional port component.
m_path = std::move(std::string(path_start, path_end));
}
return content_end;
};
std::string::const_iterator parse_username(
std::string const &uri_text,
std::string const &content,
std::string::const_iterator username_start
)
{
std::string::const_iterator username_end = username_start;
// Since this is only reachable when '@' was in the content string, we can
// ignore the end-of-string case.
while (*username_end != ':') {
if (*username_end == '@') {
throw std::invalid_argument(
"Username must be followed by a password. Supplied URI was: \""
+ uri_text + "\"."
);
}
++username_end;
}
m_username = std::move(std::string(username_start, username_end));
return username_end;
};
std::string::const_iterator parse_password(
std::string const &uri_text,
std::string const &content,
std::string::const_iterator password_start
)
{
std::string::const_iterator password_end = password_start;
while (*password_end != '@') {
++password_end;
}
m_password = std::move(std::string(password_start, password_end));
return password_end;
};
std::string::const_iterator parse_host(
std::string const &uri_text,
std::string const &content,
std::string::const_iterator host_start
)
{
std::string::const_iterator host_end = host_start;
// So, the host can contain a few things. It can be a domain, it can be an
// IPv4 address, it can be an IPv6 address, or an IPvFuture literal. In the
// case of those last two, it's of the form [...] where what's between the
// brackets is a matter of which IPv?? version it is.
while (host_end != content.end()) {
if (*host_end == '[') {
// We're parsing an IPv6 or IPvFuture address, so we should handle that
// instead of the normal procedure.
while ((host_end != content.end()) && (*host_end != ']')) {
++host_end;
}
if (host_end == content.end()) {
throw std::invalid_argument(
"End of content component encountered "
"while parsing the host component. "
"Supplied URI was: \""
+ uri_text + "\"."
);
}
++host_end;
break;
// We can stop looping, we found the end of the IP literal, which is the
// whole of the host component when one's in use.
}
else if ((*host_end == ':') || (*host_end == '/')) {
break;
}
else {
++host_end;
}
}
m_host = std::move(std::string(host_start, host_end));
return host_end;
};
std::string::const_iterator parse_port(
std::string const &uri_text,
std::string const &content,
std::string::const_iterator port_start
)
{
std::string::const_iterator port_end = port_start;
while ((port_end != content.end()) && (*port_end != '/')) {
if (!std::isdigit(*port_end)) {
throw std::invalid_argument(
"Invalid character while parsing the port. "
"Supplied URI was: \"" + uri_text + "\"."
);
}
++port_end;
}
m_port = std::stoul(std::string(port_start, port_end));
return port_end;
};
std::string::const_iterator parse_query(
std::string const &uri_text,
std::string::const_iterator query_start
)
{
std::string::const_iterator query_end = query_start;
while ((query_end != uri_text.end()) && (*query_end != '#')) {
// Queries can contain almost any character except hash, which is reserved
// for the start of the fragment.
++query_end;
}
m_query = std::move(std::string(query_start, query_end));
return query_end;
};
std::string::const_iterator parse_fragment(
std::string const &uri_text,
std::string::const_iterator fragment_start
)
{
m_fragment = std::move(std::string(fragment_start, uri_text.end()));
return uri_text.end();
};
void init_query_dictionary()
{
if (!m_query.empty()) {
// Loop over the query string looking for '&'s, then check each one for
// an '=' to find keys and values; if there's not an '=' then the key
// will have an empty value in the map.
char separator = (m_separator == query_argument_separator::ampersand) ? '&' : ';';
size_t carat = 0;
size_t stanza_end = m_query.find_first_of(separator);
do {
std::string stanza = m_query.substr(
carat,
((stanza_end != std::string::npos) ? (stanza_end - carat) : std::string::npos));
size_t key_value_divider = stanza.find_first_of('=');
std::string key = stanza.substr(0, key_value_divider);
std::string value;
if (key_value_divider != std::string::npos) {
value = stanza.substr((key_value_divider + 1));
}
if (m_query_dict.count(key) != 0) {
throw std::invalid_argument("Bad key in the query string!");
}
m_query_dict.emplace(key, value);
carat = ((stanza_end != std::string::npos) ? (stanza_end + 1)
: std::string::npos);
stanza_end = m_query.find_first_of(separator, carat);
} while ((stanza_end != std::string::npos)
|| (carat != std::string::npos));
}
}
std::string m_scheme;
std::string m_content;
std::string m_username;
std::string m_password;
std::string m_host;
std::string m_path;
std::string m_query;
std::string m_fragment;
std::map<std::string, std::string> m_query_dict;
scheme_category m_category;
unsigned long m_port;
bool m_path_is_rooted;
query_argument_separator m_separator;
};
+1 -1
View File
@@ -224,7 +224,7 @@ EQ::ItemInstance* EQ::InventoryProfile::GetItem(int16 slot_id, uint8 bagidx) con
return GetItem(InventoryProfile::CalcSlotId(slot_id, bagidx)); return GetItem(InventoryProfile::CalcSlotId(slot_id, bagidx));
} }
// Put an item into specified slot // Put an item snto specified slot
int16 EQ::InventoryProfile::PutItem(int16 slot_id, const ItemInstance& inst) int16 EQ::InventoryProfile::PutItem(int16 slot_id, const ItemInstance& inst)
{ {
if (slot_id <= EQ::invslot::POSSESSIONS_END && slot_id >= EQ::invslot::POSSESSIONS_BEGIN) { if (slot_id <= EQ::invslot::POSSESSIONS_END && slot_id >= EQ::invslot::POSSESSIONS_BEGIN) {
+1 -1
View File
@@ -482,7 +482,7 @@ namespace EQ
uint32 Haste; uint32 Haste;
uint32 DamageShield; uint32 DamageShield;
uint32 RecastDelay; uint32 RecastDelay;
int RecastType; uint32 RecastType;
uint32 AugDistiller; uint32 AugDistiller;
bool Attuneable; bool Attuneable;
bool NoPet; bool NoPet;
+2 -151
View File
@@ -11,7 +11,6 @@ EQ::Net::ServertalkServerConnection::ServertalkServerConnection(std::shared_ptr<
m_connection->OnRead(std::bind(&ServertalkServerConnection::OnRead, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); m_connection->OnRead(std::bind(&ServertalkServerConnection::OnRead, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
m_connection->OnDisconnect(std::bind(&ServertalkServerConnection::OnDisconnect, this, std::placeholders::_1)); m_connection->OnDisconnect(std::bind(&ServertalkServerConnection::OnDisconnect, this, std::placeholders::_1));
m_connection->Start(); m_connection->Start();
m_legacy_mode = false;
} }
EQ::Net::ServertalkServerConnection::~ServertalkServerConnection() EQ::Net::ServertalkServerConnection::~ServertalkServerConnection()
@@ -20,63 +19,8 @@ EQ::Net::ServertalkServerConnection::~ServertalkServerConnection()
void EQ::Net::ServertalkServerConnection::Send(uint16_t opcode, EQ::Net::Packet & p) void EQ::Net::ServertalkServerConnection::Send(uint16_t opcode, EQ::Net::Packet & p)
{ {
if (m_legacy_mode) {
if (!m_connection)
return;
if (opcode == ServerOP_UsertoWorldReq) {
auto req_in = (UsertoWorldRequest_Struct*)p.Data();
EQ::Net::DynamicPacket req;
size_t i = 0;
req.PutUInt32(i, req_in->lsaccountid); i += 4;
req.PutUInt32(i, req_in->worldid); i += 4;
req.PutUInt32(i, req_in->FromID); i += 4;
req.PutUInt32(i, req_in->ToID); i += 4;
req.PutData(i, req_in->IPAddr, 64); i += 64;
EQ::Net::DynamicPacket out;
out.PutUInt16(0, ServerOP_UsertoWorldReqLeg);
out.PutUInt16(2, req.Length() + 4);
out.PutPacket(4, req);
m_connection->Write((const char*)out.Data(), out.Length());
return;
}
if (opcode == ServerOP_LSClientAuth) {
auto req_in = (ClientAuth_Struct*)p.Data();
EQ::Net::DynamicPacket req;
size_t i = 0;
req.PutUInt32(i, req_in->loginserver_account_id); i += 4;
req.PutData(i, req_in->account_name, 30); i += 30;
req.PutData(i, req_in->key, 30); i += 30;
req.PutUInt8(i, req_in->lsadmin); i += 1;
req.PutUInt16(i, req_in->is_world_admin); i += 2;
req.PutUInt32(i, req_in->ip); i += 4;
req.PutUInt8(i, req_in->is_client_from_local_network); i += 1;
EQ::Net::DynamicPacket out;
out.PutUInt16(0, ServerOP_LSClientAuthLeg);
out.PutUInt16(2, req.Length() + 4);
out.PutPacket(4, req);
m_connection->Write((const char*)out.Data(), out.Length());
return;
}
EQ::Net::DynamicPacket out;
out.PutUInt16(0, opcode);
out.PutUInt16(2, p.Length() + 4);
out.PutPacket(4, p);
m_connection->Write((const char*)out.Data(), out.Length());
} else {
// pad zero size packets // pad zero size packets
// pad packets that would cause a collision with legacy identification code if (p.Length() == 0) {
// It's unlikely we'd send a 4MB msg for any reason but just incase.
if (p.Length() == 0 || p.Length() == 43061256) {
p.PutUInt8(0, 0); p.PutUInt8(0, 0);
} }
@@ -87,7 +31,6 @@ void EQ::Net::ServertalkServerConnection::Send(uint16_t opcode, EQ::Net::Packet
InternalSend(ServertalkMessage, out); InternalSend(ServertalkMessage, out);
} }
}
void EQ::Net::ServertalkServerConnection::SendPacket(ServerPacket *p) void EQ::Net::ServertalkServerConnection::SendPacket(ServerPacket *p)
{ {
@@ -111,41 +54,17 @@ void EQ::Net::ServertalkServerConnection::OnMessage(std::function<void(uint16_t,
void EQ::Net::ServertalkServerConnection::OnRead(TCPConnection *c, const unsigned char *data, size_t sz) void EQ::Net::ServertalkServerConnection::OnRead(TCPConnection *c, const unsigned char *data, size_t sz)
{ {
m_buffer.insert(m_buffer.end(), (const char*)data, (const char*)data + sz); m_buffer.insert(m_buffer.end(), (const char*)data, (const char*)data + sz);
if (m_legacy_mode) {
ProcessOldReadBuffer();
} else {
ProcessReadBuffer(); ProcessReadBuffer();
} }
}
void EQ::Net::ServertalkServerConnection::ProcessReadBuffer() void EQ::Net::ServertalkServerConnection::ProcessReadBuffer()
{ {
size_t current = 0; size_t current = 0;
size_t total = m_buffer.size(); size_t total = m_buffer.size();
constexpr size_t ls_info_size = sizeof(ServerNewLSInfo_Struct);
while (current < total) { while (current < total) {
auto left = total - current; auto left = total - current;
if (left < 4) {
break;
}
auto leg_opcode = *(uint16_t*)&m_buffer[current];
auto leg_size = *(uint16_t*)&m_buffer[current + 2] - 4;
//this creates a small edge case where the exact size of a
//packet from the modern protocol can't be "43061256"
//so in send we pad it one byte if that's the case
if (leg_opcode == ServerOP_NewLSInfo && leg_size == sizeof(ServerNewLSInfo_Struct)) {
m_legacy_mode = true;
m_identifier = "World";
m_parent->ConnectionIdentified(this);
ProcessOldReadBuffer();
return;
}
/* /*
//header: //header:
//uint32 length; //uint32 length;
@@ -210,57 +129,6 @@ void EQ::Net::ServertalkServerConnection::ProcessReadBuffer()
} }
} }
void EQ::Net::ServertalkServerConnection::ProcessOldReadBuffer()
{
size_t current = 0;
size_t total = m_buffer.size();
while (current < total) {
auto left = total - current;
/*
//header:
//uint32 length;
//uint8 type;
*/
uint16_t length = 0;
uint16_t opcode = 0;
if (left < 4) {
break;
}
opcode = *(uint16_t*)&m_buffer[current];
length = *(uint16_t*)&m_buffer[current + 2];
if (length < 4) {
break;
}
length -= 4;
if (current + 4 + length > total) {
break;
}
if (length == 0) {
EQ::Net::DynamicPacket p;
ProcessMessageOld(opcode, p);
}
else {
EQ::Net::StaticPacket p(&m_buffer[current + 4], length);
ProcessMessageOld(opcode, p);
}
current += length + 4;
}
if (current == total) {
m_buffer.clear();
}
else {
m_buffer.erase(m_buffer.begin(), m_buffer.begin() + current);
}
}
void EQ::Net::ServertalkServerConnection::OnDisconnect(TCPConnection *c) void EQ::Net::ServertalkServerConnection::OnDisconnect(TCPConnection *c)
{ {
m_parent->ConnectionDisconnected(this); m_parent->ConnectionDisconnected(this);
@@ -276,7 +144,7 @@ void EQ::Net::ServertalkServerConnection::SendHello()
void EQ::Net::ServertalkServerConnection::InternalSend(ServertalkPacketType type, EQ::Net::Packet &p) void EQ::Net::ServertalkServerConnection::InternalSend(ServertalkPacketType type, EQ::Net::Packet &p)
{ {
if (!m_connection || m_legacy_mode) if (!m_connection)
return; return;
EQ::Net::DynamicPacket out; EQ::Net::DynamicPacket out;
@@ -333,20 +201,3 @@ void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
LogError("Error parsing message from client: {0}", ex.what()); LogError("Error parsing message from client: {0}", ex.what());
} }
} }
void EQ::Net::ServertalkServerConnection::ProcessMessageOld(uint16_t opcode, EQ::Net::Packet &p)
{
try {
auto cb = m_message_callbacks.find(opcode);
if (cb != m_message_callbacks.end()) {
cb->second(opcode, p);
}
if (m_message_callback) {
m_message_callback(opcode, p);
}
}
catch (std::exception &ex) {
LogError("Error parsing legacy message from client: {0}", ex.what());
}
}
@@ -27,13 +27,11 @@ namespace EQ
private: private:
void OnRead(TCPConnection* c, const unsigned char* data, size_t sz); void OnRead(TCPConnection* c, const unsigned char* data, size_t sz);
void ProcessReadBuffer(); void ProcessReadBuffer();
void ProcessOldReadBuffer();
void OnDisconnect(TCPConnection* c); void OnDisconnect(TCPConnection* c);
void SendHello(); void SendHello();
void InternalSend(ServertalkPacketType type, EQ::Net::Packet &p); void InternalSend(ServertalkPacketType type, EQ::Net::Packet &p);
void ProcessHandshake(EQ::Net::Packet &p); void ProcessHandshake(EQ::Net::Packet &p);
void ProcessMessage(EQ::Net::Packet &p); void ProcessMessage(EQ::Net::Packet &p);
void ProcessMessageOld(uint16_t opcode, EQ::Net::Packet &p);
std::shared_ptr<EQ::Net::TCPConnection> m_connection; std::shared_ptr<EQ::Net::TCPConnection> m_connection;
ServertalkServer *m_parent; ServertalkServer *m_parent;
@@ -43,7 +41,6 @@ namespace EQ
std::function<void(uint16_t, EQ::Net::Packet&)> m_message_callback; std::function<void(uint16_t, EQ::Net::Packet&)> m_message_callback;
std::string m_identifier; std::string m_identifier;
std::string m_uuid; std::string m_uuid;
bool m_legacy_mode;
}; };
} }
} }
+2 -11
View File
@@ -1863,8 +1863,8 @@ namespace RoF
/*fill in some unknowns with observed values, hopefully it will help */ /*fill in some unknowns with observed values, hopefully it will help */
eq->unknown800 = -1; eq->unknown800 = -1;
eq->unknown844 = 600; eq->unknown844 = 600;
OUT(LavaDamage); eq->unknown880 = 50;
OUT(MinLavaDamage); eq->unknown884 = 10;
eq->unknown888 = 1; eq->unknown888 = 1;
eq->unknown889 = 0; eq->unknown889 = 0;
eq->unknown890 = 1; eq->unknown890 = 1;
@@ -2098,15 +2098,6 @@ namespace RoF
outapp->WriteUInt32(emu->aa_array[r].charges); outapp->WriteUInt32(emu->aa_array[r].charges);
} }
// Fill the other 60 AAs with zeroes
for (uint32 r = 0; r < structs::MAX_PP_AA_ARRAY - MAX_PP_AA_ARRAY; r++)
{
outapp->WriteUInt32(0);
outapp->WriteUInt32(0);
outapp->WriteUInt32(0);
}
outapp->WriteUInt32(structs::MAX_PP_SKILL); outapp->WriteUInt32(structs::MAX_PP_SKILL);
for (uint32 r = 0; r < structs::MAX_PP_SKILL; r++) for (uint32 r = 0; r < structs::MAX_PP_SKILL; r++)
+2 -11
View File
@@ -1919,8 +1919,8 @@ namespace RoF2
eq->SkyRelated2 = -1; eq->SkyRelated2 = -1;
eq->NPCAggroMaxDist = 600; eq->NPCAggroMaxDist = 600;
eq->FilterID = 2008; // Guild Lobby observed value eq->FilterID = 2008; // Guild Lobby observed value
OUT(LavaDamage); eq->LavaDamage = 50;
OUT(MinLavaDamage); eq->MinLavaDamage = 10;
eq->bDisallowManaStone = 1; eq->bDisallowManaStone = 1;
eq->bNoBind = 0; eq->bNoBind = 0;
eq->bNoAttack = 0; eq->bNoAttack = 0;
@@ -2155,15 +2155,6 @@ namespace RoF2
outapp->WriteUInt32(emu->aa_array[r].charges); outapp->WriteUInt32(emu->aa_array[r].charges);
} }
// Fill the other 60 AAs with zeroes
for (uint32 r = 0; r < structs::MAX_PP_AA_ARRAY - MAX_PP_AA_ARRAY; r++)
{
outapp->WriteUInt32(0);
outapp->WriteUInt32(0);
outapp->WriteUInt32(0);
}
outapp->WriteUInt32(structs::MAX_PP_SKILL); outapp->WriteUInt32(structs::MAX_PP_SKILL);
for (uint32 r = 0; r < structs::MAX_PP_SKILL; r++) for (uint32 r = 0; r < structs::MAX_PP_SKILL; r++)
+2 -2
View File
@@ -4361,8 +4361,8 @@ struct UseAA_Struct {
struct AA_Ability { struct AA_Ability {
/*00*/ uint32 skill_id; /*00*/ uint32 skill_id;
/*04*/ uint32 base_value; /*04*/ uint32 base1;
/*08*/ uint32 limit_value; /*08*/ uint32 base2;
/*12*/ uint32 slot; /*12*/ uint32 slot;
/*16*/ /*16*/
}; };
+4 -4
View File
@@ -581,8 +581,8 @@ struct NewZone_Struct {
/*0868*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, -1 affects some collisions /*0868*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, -1 affects some collisions
/*0872*/ uint32 scriptIDSomething3; /*0872*/ uint32 scriptIDSomething3;
/*0876*/ uint32 SuspendBuffs; /*0876*/ uint32 SuspendBuffs;
/*0880*/ uint32 LavaDamage; // Seen 50 /*0880*/ uint32 unknown880; // Seen 50
/*0884*/ uint32 MinLavaDamage; // Seen 10 /*0884*/ uint32 unknown884; // Seen 10
/*0888*/ uint8 unknown888; // Seen 1 /*0888*/ uint8 unknown888; // Seen 1
/*0889*/ uint8 unknown889; // Seen 0 (POK) or 1 (rujj) /*0889*/ uint8 unknown889; // Seen 0 (POK) or 1 (rujj)
/*0890*/ uint8 unknown890; // Seen 1 /*0890*/ uint8 unknown890; // Seen 1
@@ -4305,8 +4305,8 @@ struct UseAA_Struct {
struct AA_Ability { struct AA_Ability {
/*00*/ uint32 skill_id; /*00*/ uint32 skill_id;
/*04*/ uint32 base_value; /*04*/ uint32 base1;
/*08*/ uint32 limit_value; /*08*/ uint32 base2;
/*12*/ uint32 slot; /*12*/ uint32 slot;
/*16*/ /*16*/
}; };
+5 -6
View File
@@ -1388,8 +1388,8 @@ namespace SoD
/*fill in some unknowns with observed values, hopefully it will help */ /*fill in some unknowns with observed values, hopefully it will help */
eq->unknown800 = -1; eq->unknown800 = -1;
eq->unknown844 = 600; eq->unknown844 = 600;
OUT(LavaDamage); eq->unknown880 = 50;
OUT(MinLavaDamage); eq->unknown884 = 10;
eq->unknown888 = 1; eq->unknown888 = 1;
eq->unknown889 = 0; eq->unknown889 = 0;
eq->unknown890 = 1; eq->unknown890 = 1;
@@ -1504,8 +1504,7 @@ namespace SoD
OUT(item_tint.Slot[r].Color); OUT(item_tint.Slot[r].Color);
} }
// OUT(unknown00224[48]); // OUT(unknown00224[48]);
//NOTE: new client supports 300 AAs, our internal rep/PP //NOTE: new client supports 300 AAs
//only supports 240..
for (r = 0; r < MAX_PP_AA_ARRAY; r++) { for (r = 0; r < MAX_PP_AA_ARRAY; r++) {
OUT(aa_array[r].AA); OUT(aa_array[r].AA);
OUT(aa_array[r].value); OUT(aa_array[r].value);
@@ -1874,8 +1873,8 @@ namespace SoD
for(auto i = 0; i < eq->total_abilities; ++i) { for(auto i = 0; i < eq->total_abilities; ++i) {
eq->abilities[i].skill_id = inapp->ReadUInt32(); eq->abilities[i].skill_id = inapp->ReadUInt32();
eq->abilities[i].base_value = inapp->ReadUInt32(); eq->abilities[i].base1 = inapp->ReadUInt32();
eq->abilities[i].limit_value = inapp->ReadUInt32(); eq->abilities[i].base2 = inapp->ReadUInt32();
eq->abilities[i].slot = inapp->ReadUInt32(); eq->abilities[i].slot = inapp->ReadUInt32();
} }
+4 -4
View File
@@ -450,8 +450,8 @@ struct NewZone_Struct {
/*0868*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, -1 affects some collisions /*0868*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, -1 affects some collisions
/*0872*/ uint32 scriptIDSomething3; /*0872*/ uint32 scriptIDSomething3;
/*0876*/ uint32 SuspendBuffs; /*0876*/ uint32 SuspendBuffs;
/*0880*/ uint32 LavaDamage; //seen 50 /*0880*/ uint32 unknown880; //seen 50
/*0884*/ uint32 MinLavaDamage; //seen 10 /*0884*/ uint32 unknown884; //seen 10
/*0888*/ uint8 unknown888; //seen 1 /*0888*/ uint8 unknown888; //seen 1
/*0889*/ uint8 unknown889; //seen 0 (POK) or 1 (rujj) /*0889*/ uint8 unknown889; //seen 0 (POK) or 1 (rujj)
/*0890*/ uint8 unknown890; //seen 1 /*0890*/ uint8 unknown890; //seen 1
@@ -3748,8 +3748,8 @@ struct UseAA_Struct {
struct AA_Ability { struct AA_Ability {
/*00*/ uint32 skill_id; /*00*/ uint32 skill_id;
/*04*/ uint32 base_value; /*04*/ uint32 base1;
/*08*/ uint32 limit_value; /*08*/ uint32 base2;
/*12*/ uint32 slot; /*12*/ uint32 slot;
/*16*/ /*16*/
}; };
+5 -6
View File
@@ -1066,8 +1066,8 @@ namespace SoF
/*fill in some unknowns with observed values, hopefully it will help */ /*fill in some unknowns with observed values, hopefully it will help */
eq->unknown796 = -1; eq->unknown796 = -1;
eq->unknown840 = 600; eq->unknown840 = 600;
OUT(LavaDamage); eq->unknown876 = 50;
OUT(MinLavaDamage); eq->unknown880 = 10;
eq->unknown884 = 1; eq->unknown884 = 1;
eq->unknown885 = 0; eq->unknown885 = 0;
eq->unknown886 = 1; eq->unknown886 = 1;
@@ -1172,8 +1172,7 @@ namespace SoF
OUT(item_tint.Slot[r].Color); OUT(item_tint.Slot[r].Color);
} }
// OUT(unknown00224[48]); // OUT(unknown00224[48]);
//NOTE: new client supports 300 AAs, our internal rep/PP //NOTE: new client supports 300 AAs
//only supports 240..
for (r = 0; r < MAX_PP_AA_ARRAY; r++) { for (r = 0; r < MAX_PP_AA_ARRAY; r++) {
OUT(aa_array[r].AA); OUT(aa_array[r].AA);
OUT(aa_array[r].value); OUT(aa_array[r].value);
@@ -1545,8 +1544,8 @@ namespace SoF
for(auto i = 0; i < eq->total_abilities; ++i) { for(auto i = 0; i < eq->total_abilities; ++i) {
eq->abilities[i].skill_id = inapp->ReadUInt32(); eq->abilities[i].skill_id = inapp->ReadUInt32();
eq->abilities[i].base_value = inapp->ReadUInt32(); eq->abilities[i].base1 = inapp->ReadUInt32();
eq->abilities[i].limit_value = inapp->ReadUInt32(); eq->abilities[i].base2 = inapp->ReadUInt32();
eq->abilities[i].slot = inapp->ReadUInt32(); eq->abilities[i].slot = inapp->ReadUInt32();
} }
+4 -4
View File
@@ -454,8 +454,8 @@ struct NewZone_Struct {
/*0864*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, -1 affects some collisions /*0864*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, -1 affects some collisions
/*0868*/ uint32 scriptIDSomething3; /*0868*/ uint32 scriptIDSomething3;
/*0872*/ uint32 SuspendBuffs; /*0872*/ uint32 SuspendBuffs;
/*0876*/ uint32 LavaDamage; //seen 50 /*0876*/ uint32 unknown876; //seen 50
/*0880*/ uint32 MinLavaDamage; //seen 10 /*0880*/ uint32 unknown880; //seen 10
/*0884*/ uint8 unknown884; //seen 1 /*0884*/ uint8 unknown884; //seen 1
/*0885*/ uint8 unknown885; //seen 0 (POK) or 1 (rujj) /*0885*/ uint8 unknown885; //seen 0 (POK) or 1 (rujj)
/*0886*/ uint8 unknown886; //seen 1 /*0886*/ uint8 unknown886; //seen 1
@@ -3673,8 +3673,8 @@ struct UseAA_Struct {
struct AA_Ability { struct AA_Ability {
/*00*/ uint32 skill_id; /*00*/ uint32 skill_id;
/*04*/ uint32 base_value; /*04*/ uint32 base1;
/*08*/ uint32 limit_value; /*08*/ uint32 base2;
/*12*/ uint32 slot; /*12*/ uint32 slot;
/*16*/ /*16*/
}; };
+2 -2
View File
@@ -1338,8 +1338,8 @@ namespace Titanium
for(auto i = 0; i < eq->total_abilities; ++i) { for(auto i = 0; i < eq->total_abilities; ++i) {
eq->abilities[i].skill_id = inapp->ReadUInt32(); eq->abilities[i].skill_id = inapp->ReadUInt32();
eq->abilities[i].base_value = inapp->ReadUInt32(); eq->abilities[i].base1 = inapp->ReadUInt32();
eq->abilities[i].limit_value = inapp->ReadUInt32(); eq->abilities[i].base2 = inapp->ReadUInt32();
eq->abilities[i].slot = inapp->ReadUInt32(); eq->abilities[i].slot = inapp->ReadUInt32();
} }
+2 -2
View File
@@ -3180,8 +3180,8 @@ struct UseAA_Struct {
struct AA_Ability { struct AA_Ability {
/*00*/ uint32 skill_id; /*00*/ uint32 skill_id;
/*04*/ uint32 base_value; /*04*/ uint32 base1;
/*08*/ uint32 limit_value; /*08*/ uint32 base2;
/*12*/ uint32 slot; /*12*/ uint32 slot;
}; };
+5 -6
View File
@@ -1614,8 +1614,8 @@ namespace UF
/*fill in some unknowns with observed values, hopefully it will help */ /*fill in some unknowns with observed values, hopefully it will help */
eq->unknown800 = -1; eq->unknown800 = -1;
eq->unknown844 = 600; eq->unknown844 = 600;
OUT(LavaDamage); eq->unknown880 = 50;
OUT(MinLavaDamage); eq->unknown884 = 10;
eq->unknown888 = 1; eq->unknown888 = 1;
eq->unknown889 = 0; eq->unknown889 = 0;
eq->unknown890 = 1; eq->unknown890 = 1;
@@ -1734,8 +1734,7 @@ namespace UF
OUT(item_tint.Slot[r].Color); OUT(item_tint.Slot[r].Color);
} }
// OUT(unknown00224[48]); // OUT(unknown00224[48]);
//NOTE: new client supports 300 AAs, our internal rep/PP //NOTE: new client supports 300 AAs
//only supports 240..
for (r = 0; r < MAX_PP_AA_ARRAY; r++) { for (r = 0; r < MAX_PP_AA_ARRAY; r++) {
eq->aa_array[r].AA = emu->aa_array[r].AA; eq->aa_array[r].AA = emu->aa_array[r].AA;
eq->aa_array[r].value = emu->aa_array[r].value; eq->aa_array[r].value = emu->aa_array[r].value;
@@ -2139,8 +2138,8 @@ namespace UF
for(auto i = 0; i < eq->total_abilities; ++i) { for(auto i = 0; i < eq->total_abilities; ++i) {
eq->abilities[i].skill_id = inapp->ReadUInt32(); eq->abilities[i].skill_id = inapp->ReadUInt32();
eq->abilities[i].base_value = inapp->ReadUInt32(); eq->abilities[i].base1 = inapp->ReadUInt32();
eq->abilities[i].limit_value = inapp->ReadUInt32(); eq->abilities[i].base2 = inapp->ReadUInt32();
eq->abilities[i].slot = inapp->ReadUInt32(); eq->abilities[i].slot = inapp->ReadUInt32();
} }
+4 -4
View File
@@ -450,8 +450,8 @@ struct NewZone_Struct {
/*0868*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, -1 affects some collisions /*0868*/ uint32 underworld_teleport_index; // > 0 teleports w/ zone point index, invalid succors, -1 affects some collisions
/*0872*/ uint32 scriptIDSomething3; /*0872*/ uint32 scriptIDSomething3;
/*0876*/ uint32 SuspendBuffs; /*0876*/ uint32 SuspendBuffs;
/*0880*/ uint32 LavaDamage; //seen 50 /*0880*/ uint32 unknown880; //seen 50
/*0884*/ uint32 MinLavaDamage; //seen 10 /*0884*/ uint32 unknown884; //seen 10
/*0888*/ uint8 unknown888; //seen 1 /*0888*/ uint8 unknown888; //seen 1
/*0889*/ uint8 unknown889; //seen 0 (POK) or 1 (rujj) /*0889*/ uint8 unknown889; //seen 0 (POK) or 1 (rujj)
/*0890*/ uint8 unknown890; //seen 1 /*0890*/ uint8 unknown890; //seen 1
@@ -3803,8 +3803,8 @@ struct UseAA_Struct {
struct AA_Ability { struct AA_Ability {
/*00*/ uint32 skill_id; /*00*/ uint32 skill_id;
/*04*/ uint32 base_value; /*04*/ uint32 base1;
/*08*/ uint32 limit_value; /*08*/ uint32 base2;
/*12*/ uint32 slot; /*12*/ uint32 slot;
/*16*/ /*16*/
}; };
-12
View File
@@ -2232,15 +2232,3 @@ bool PlayerAppearance::IsValidWoad(uint16 race_id, uint8 gender_id, uint8 woad_v
} }
return false; return false;
} }
const char* GetGenderName(uint32 gender_id) {
const char* gender_name = "Unknown";
if (gender_id == MALE) {
gender_name = "Male";
} else if (gender_id == FEMALE) {
gender_name = "Female";
} else if (gender_id == NEUTER) {
gender_name = "Neuter";
}
return gender_name;
}
-9
View File
@@ -851,7 +851,6 @@
const char* GetRaceIDName(uint16 race_id); const char* GetRaceIDName(uint16 race_id);
const char* GetPlayerRaceName(uint32 player_race_value); const char* GetPlayerRaceName(uint32 player_race_value);
const char* GetGenderName(uint32 gender_id);
uint32 GetPlayerRaceValue(uint16 race_id); uint32 GetPlayerRaceValue(uint16 race_id);
uint32 GetPlayerRaceBit(uint16 race_id); uint32 GetPlayerRaceBit(uint16 race_id);
@@ -1603,14 +1602,6 @@ namespace PlayerAppearance
#define RACE_FALLEN_KNIGHT_722 722 #define RACE_FALLEN_KNIGHT_722 722
#define RACE_SERVANT_OF_SHADOW_723 723 #define RACE_SERVANT_OF_SHADOW_723 723
#define RACE_LUCLIN_724 724 #define RACE_LUCLIN_724 724
#define RACE_XARIC_725 725
#define RACE_DERVISH_726 726
#define RACE_DERVISH_727 727
#define RACE_LUCLIN_728 728
#define RACE_LUCLIN_729 729
#define RACE_ORB_730 730
#define RACE_LUCLIN_731 731
#define RACE_PEGASUS_732 732
#define RACE_INTERACTIVE_OBJECT_2250 2250 #define RACE_INTERACTIVE_OBJECT_2250 2250
#endif #endif
@@ -148,7 +148,7 @@ public:
entry.zone_in_time = 1800; entry.zone_in_time = 1800;
entry.win_points = 0; entry.win_points = 0;
entry.lose_points = 0; entry.lose_points = 0;
entry.theme = LDoNThemes::GUK; entry.theme = 1;
entry.zone_in_zone_id = 0; entry.zone_in_zone_id = 0;
entry.zone_in_x = 0; entry.zone_in_x = 0;
entry.zone_in_y = 0; entry.zone_in_y = 0;
@@ -717,7 +717,7 @@ public:
entry.itemclass = 0; entry.itemclass = 0;
entry.itemtype = 0; entry.itemtype = 0;
entry.ldonprice = 0; entry.ldonprice = 0;
entry.ldontheme = LDoNThemes::Unused; entry.ldontheme = 0;
entry.ldonsold = 0; entry.ldonsold = 0;
entry.light = 0; entry.light = 0;
entry.lore = ""; entry.lore = "";
@@ -1,346 +0,0 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
*/
#ifndef EQEMU_BASE_TOOL_GAME_OBJECTS_REPOSITORY_H
#define EQEMU_BASE_TOOL_GAME_OBJECTS_REPOSITORY_H
#include "../../database.h"
#include "../../string_util.h"
#include <ctime>
class BaseToolGameObjectsRepository {
public:
struct ToolGameObjects {
int id;
int zoneid;
std::string zonesn;
std::string object_name;
std::string file_from;
int is_global;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"zoneid",
"zonesn",
"object_name",
"file_from",
"is_global",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"zoneid",
"zonesn",
"object_name",
"file_from",
"is_global",
};
}
static std::string ColumnsRaw()
{
return std::string(implode(", ", Columns()));
}
static std::string SelectColumnsRaw()
{
return std::string(implode(", ", SelectColumns()));
}
static std::string TableName()
{
return std::string("tool_game_objects");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static ToolGameObjects NewEntity()
{
ToolGameObjects entry{};
entry.id = 0;
entry.zoneid = 0;
entry.zonesn = "";
entry.object_name = "";
entry.file_from = "";
entry.is_global = 0;
return entry;
}
static ToolGameObjects GetToolGameObjectsEntry(
const std::vector<ToolGameObjects> &tool_game_objectss,
int tool_game_objects_id
)
{
for (auto &tool_game_objects : tool_game_objectss) {
if (tool_game_objects.id == tool_game_objects_id) {
return tool_game_objects;
}
}
return NewEntity();
}
static ToolGameObjects FindOne(
Database& db,
int tool_game_objects_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
BaseSelect(),
tool_game_objects_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
ToolGameObjects entry{};
entry.id = atoi(row[0]);
entry.zoneid = atoi(row[1]);
entry.zonesn = row[2] ? row[2] : "";
entry.object_name = row[3] ? row[3] : "";
entry.file_from = row[4] ? row[4] : "";
entry.is_global = atoi(row[5]);
return entry;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int tool_game_objects_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
tool_game_objects_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
ToolGameObjects tool_game_objects_entry
)
{
std::vector<std::string> update_values;
auto columns = Columns();
update_values.push_back(columns[1] + " = " + std::to_string(tool_game_objects_entry.zoneid));
update_values.push_back(columns[2] + " = '" + EscapeString(tool_game_objects_entry.zonesn) + "'");
update_values.push_back(columns[3] + " = '" + EscapeString(tool_game_objects_entry.object_name) + "'");
update_values.push_back(columns[4] + " = '" + EscapeString(tool_game_objects_entry.file_from) + "'");
update_values.push_back(columns[5] + " = " + std::to_string(tool_game_objects_entry.is_global));
auto results = db.QueryDatabase(
fmt::format(
"UPDATE {} SET {} WHERE {} = {}",
TableName(),
implode(", ", update_values),
PrimaryKey(),
tool_game_objects_entry.id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static ToolGameObjects InsertOne(
Database& db,
ToolGameObjects tool_game_objects_entry
)
{
std::vector<std::string> insert_values;
insert_values.push_back(std::to_string(tool_game_objects_entry.id));
insert_values.push_back(std::to_string(tool_game_objects_entry.zoneid));
insert_values.push_back("'" + EscapeString(tool_game_objects_entry.zonesn) + "'");
insert_values.push_back("'" + EscapeString(tool_game_objects_entry.object_name) + "'");
insert_values.push_back("'" + EscapeString(tool_game_objects_entry.file_from) + "'");
insert_values.push_back(std::to_string(tool_game_objects_entry.is_global));
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseInsert(),
implode(",", insert_values)
)
);
if (results.Success()) {
tool_game_objects_entry.id = results.LastInsertedID();
return tool_game_objects_entry;
}
tool_game_objects_entry = NewEntity();
return tool_game_objects_entry;
}
static int InsertMany(
Database& db,
std::vector<ToolGameObjects> tool_game_objects_entries
)
{
std::vector<std::string> insert_chunks;
for (auto &tool_game_objects_entry: tool_game_objects_entries) {
std::vector<std::string> insert_values;
insert_values.push_back(std::to_string(tool_game_objects_entry.id));
insert_values.push_back(std::to_string(tool_game_objects_entry.zoneid));
insert_values.push_back("'" + EscapeString(tool_game_objects_entry.zonesn) + "'");
insert_values.push_back("'" + EscapeString(tool_game_objects_entry.object_name) + "'");
insert_values.push_back("'" + EscapeString(tool_game_objects_entry.file_from) + "'");
insert_values.push_back(std::to_string(tool_game_objects_entry.is_global));
insert_chunks.push_back("(" + implode(",", insert_values) + ")");
}
std::vector<std::string> insert_values;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseInsert(),
implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static std::vector<ToolGameObjects> All(Database& db)
{
std::vector<ToolGameObjects> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
ToolGameObjects entry{};
entry.id = atoi(row[0]);
entry.zoneid = atoi(row[1]);
entry.zonesn = row[2] ? row[2] : "";
entry.object_name = row[3] ? row[3] : "";
entry.file_from = row[4] ? row[4] : "";
entry.is_global = atoi(row[5]);
all_entries.push_back(entry);
}
return all_entries;
}
static std::vector<ToolGameObjects> GetWhere(Database& db, std::string where_filter)
{
std::vector<ToolGameObjects> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {}",
BaseSelect(),
where_filter
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
ToolGameObjects entry{};
entry.id = atoi(row[0]);
entry.zoneid = atoi(row[1]);
entry.zonesn = row[2] ? row[2] : "";
entry.object_name = row[3] ? row[3] : "";
entry.file_from = row[4] ? row[4] : "";
entry.is_global = atoi(row[5]);
all_entries.push_back(entry);
}
return all_entries;
}
static int DeleteWhere(Database& db, std::string where_filter)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {}",
TableName(),
where_filter
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int Truncate(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"TRUNCATE TABLE {}",
TableName()
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_TOOL_GAME_OBJECTS_REPOSITORY_H
@@ -110,8 +110,6 @@ public:
std::string content_flags; std::string content_flags;
std::string content_flags_disabled; std::string content_flags_disabled;
int underworld_teleport_index; int underworld_teleport_index;
int lava_damage;
int min_lava_damage;
}; };
static std::string PrimaryKey() static std::string PrimaryKey()
@@ -214,8 +212,6 @@ public:
"content_flags", "content_flags",
"content_flags_disabled", "content_flags_disabled",
"underworld_teleport_index", "underworld_teleport_index",
"lava_damage",
"min_lava_damage",
}; };
} }
@@ -343,8 +339,6 @@ public:
entry.content_flags = ""; entry.content_flags = "";
entry.content_flags_disabled = ""; entry.content_flags_disabled = "";
entry.underworld_teleport_index = 0; entry.underworld_teleport_index = 0;
entry.lava_damage = 50;
entry.min_lava_damage = 10;
return entry; return entry;
} }
@@ -472,8 +466,6 @@ public:
entry.content_flags = row[89] ? row[89] : ""; entry.content_flags = row[89] ? row[89] : "";
entry.content_flags_disabled = row[90] ? row[90] : ""; entry.content_flags_disabled = row[90] ? row[90] : "";
entry.underworld_teleport_index = atoi(row[91]); entry.underworld_teleport_index = atoi(row[91]);
entry.lava_damage = atoi(row[92]);
entry.min_lava_damage = atoi(row[93]);
return entry; return entry;
} }
@@ -598,8 +590,6 @@ public:
update_values.push_back(columns[89] + " = '" + EscapeString(zone_entry.content_flags) + "'"); update_values.push_back(columns[89] + " = '" + EscapeString(zone_entry.content_flags) + "'");
update_values.push_back(columns[90] + " = '" + EscapeString(zone_entry.content_flags_disabled) + "'"); update_values.push_back(columns[90] + " = '" + EscapeString(zone_entry.content_flags_disabled) + "'");
update_values.push_back(columns[91] + " = " + std::to_string(zone_entry.underworld_teleport_index)); update_values.push_back(columns[91] + " = " + std::to_string(zone_entry.underworld_teleport_index));
update_values.push_back(columns[92] + " = " + std::to_string(zone_entry.lava_damage));
update_values.push_back(columns[93] + " = " + std::to_string(zone_entry.min_lava_damage));
auto results = db.QueryDatabase( auto results = db.QueryDatabase(
fmt::format( fmt::format(
@@ -713,8 +703,6 @@ public:
insert_values.push_back("'" + EscapeString(zone_entry.content_flags) + "'"); insert_values.push_back("'" + EscapeString(zone_entry.content_flags) + "'");
insert_values.push_back("'" + EscapeString(zone_entry.content_flags_disabled) + "'"); insert_values.push_back("'" + EscapeString(zone_entry.content_flags_disabled) + "'");
insert_values.push_back(std::to_string(zone_entry.underworld_teleport_index)); insert_values.push_back(std::to_string(zone_entry.underworld_teleport_index));
insert_values.push_back(std::to_string(zone_entry.lava_damage));
insert_values.push_back(std::to_string(zone_entry.min_lava_damage));
auto results = db.QueryDatabase( auto results = db.QueryDatabase(
fmt::format( fmt::format(
@@ -836,8 +824,6 @@ public:
insert_values.push_back("'" + EscapeString(zone_entry.content_flags) + "'"); insert_values.push_back("'" + EscapeString(zone_entry.content_flags) + "'");
insert_values.push_back("'" + EscapeString(zone_entry.content_flags_disabled) + "'"); insert_values.push_back("'" + EscapeString(zone_entry.content_flags_disabled) + "'");
insert_values.push_back(std::to_string(zone_entry.underworld_teleport_index)); insert_values.push_back(std::to_string(zone_entry.underworld_teleport_index));
insert_values.push_back(std::to_string(zone_entry.lava_damage));
insert_values.push_back(std::to_string(zone_entry.min_lava_damage));
insert_chunks.push_back("(" + implode(",", insert_values) + ")"); insert_chunks.push_back("(" + implode(",", insert_values) + ")");
} }
@@ -963,8 +949,6 @@ public:
entry.content_flags = row[89] ? row[89] : ""; entry.content_flags = row[89] ? row[89] : "";
entry.content_flags_disabled = row[90] ? row[90] : ""; entry.content_flags_disabled = row[90] ? row[90] : "";
entry.underworld_teleport_index = atoi(row[91]); entry.underworld_teleport_index = atoi(row[91]);
entry.lava_damage = atoi(row[92]);
entry.min_lava_damage = atoi(row[93]);
all_entries.push_back(entry); all_entries.push_back(entry);
} }
@@ -1081,8 +1065,6 @@ public:
entry.content_flags = row[89] ? row[89] : ""; entry.content_flags = row[89] ? row[89] : "";
entry.content_flags_disabled = row[90] ? row[90] : ""; entry.content_flags_disabled = row[90] ? row[90] : "";
entry.underworld_teleport_index = atoi(row[91]); entry.underworld_teleport_index = atoi(row[91]);
entry.lava_damage = atoi(row[92]);
entry.min_lava_damage = atoi(row[93]);
all_entries.push_back(entry); all_entries.push_back(entry);
} }
@@ -1,70 +0,0 @@
/**
* 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_TOOL_GAME_OBJECTS_REPOSITORY_H
#define EQEMU_TOOL_GAME_OBJECTS_REPOSITORY_H
#include "../database.h"
#include "../string_util.h"
#include "base/base_tool_game_objects_repository.h"
class ToolGameObjectsRepository: public BaseToolGameObjectsRepository {
public:
/**
* This file was auto generated and can be modified and extended upon
*
* Base repository methods are automatically
* generated in the "base" version of this repository. The base repository
* is immutable and to be left untouched, while methods in this class
* are used as extension methods for more specific persistence-layer
* accessors or mutators.
*
* Base Methods (Subject to be expanded upon in time)
*
* Note: Not all tables are designed appropriately to fit functionality with all base methods
*
* InsertOne
* UpdateOne
* DeleteOne
* FindOne
* GetWhere(std::string where_filter)
* DeleteWhere(std::string where_filter)
* InsertMany
* All
*
* Example custom methods in a repository
*
* ToolGameObjectsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* ToolGameObjectsRepository::GetWhereNeverExpires()
* ToolGameObjectsRepository::GetWhereXAndY()
* ToolGameObjectsRepository::DeleteWhereXAndY()
*
* Most of the above could be covered by base methods, but if you as a developer
* find yourself re-using logic for other parts of the code, its best to just make a
* method that can be re-used easily elsewhere especially if it can use a base repository
* method and encapsulate filters there
*/
// Custom extended repository methods here
};
#endif //EQEMU_TOOL_GAME_OBJECTS_REPOSITORY_H
+3 -35
View File
@@ -139,7 +139,6 @@ RULE_INT(Character, TradeskillUpMakePoison, 2, "Make Poison skillup rate adjustm
RULE_INT(Character, TradeskillUpPottery, 4, "Pottery skillup rate adjustment. Lower is faster") RULE_INT(Character, TradeskillUpPottery, 4, "Pottery skillup rate adjustment. Lower is faster")
RULE_INT(Character, TradeskillUpResearch, 1, "Research skillup rate adjustment. Lower is faster") RULE_INT(Character, TradeskillUpResearch, 1, "Research skillup rate adjustment. Lower is faster")
RULE_INT(Character, TradeskillUpTinkering, 2, "Tinkering skillup rate adjustment. Lower is faster") RULE_INT(Character, TradeskillUpTinkering, 2, "Tinkering skillup rate adjustment. Lower is faster")
RULE_INT(Character, TradeskillUpTailoring, 2, "Tailoring skillup rate adjustment. Lower is faster")
RULE_BOOL(Character, MarqueeHPUpdates, false, "Will show health percentage in center of screen if health lesser than 100%") RULE_BOOL(Character, MarqueeHPUpdates, false, "Will show health percentage in center of screen if health lesser than 100%")
RULE_INT(Character, IksarCommonTongue, 95, "Starting value for Common Tongue for Iksars") RULE_INT(Character, IksarCommonTongue, 95, "Starting value for Common Tongue for Iksars")
RULE_INT(Character, OgreCommonTongue, 95, "Starting value for Common Tongue for Ogres") RULE_INT(Character, OgreCommonTongue, 95, "Starting value for Common Tongue for Ogres")
@@ -168,12 +167,7 @@ RULE_BOOL(Character, EnableCharacterEXPMods, false, "Enables character zone-base
RULE_BOOL(Character, PVPEnableGuardFactionAssist, true, "Enables faction based assisting against the aggresor in pvp.") RULE_BOOL(Character, PVPEnableGuardFactionAssist, true, "Enables faction based assisting against the aggresor in pvp.")
RULE_BOOL(Character, SkillUpFromItems, true, "Allow Skill ups from clickable items") RULE_BOOL(Character, SkillUpFromItems, true, "Allow Skill ups from clickable items")
RULE_BOOL(Character, EnableTestBuff, false, "Allow the use of /testbuff") RULE_BOOL(Character, EnableTestBuff, false, "Allow the use of /testbuff")
RULE_BOOL(Character, UseResurrectionSickness, true, "Use Resurrection Sickness based on Resurrection spell cast, set to false to disable Resurrection Sickness.") RULE_BOOL(Character, FixHPCalculationOverflow, true, "Fix the HP overflow bug in HP calcs, this is a client bug, if fixed and clients overflow their hp wont match the server's hp but the difference serverside can be significant so it's left as an option.")
RULE_INT(Character, OldResurrectionSicknessSpellID, 757, "757 is Default Old Resurrection Sickness Spell ID")
RULE_INT(Character, ResurrectionSicknessSpellID, 756, "756 is Default Resurrection Sickness Spell ID")
RULE_BOOL(Character, EnableBardMelody, true, "Enable Bard /melody by default, to disable change to false for a classic experience.")
RULE_BOOL(Character, EnableRangerAutoFire, true, "Enable Ranger /autofire by default, to disable change to false for a classic experience.")
RULE_BOOL(Character, EnableTGB, true, "Enable /tgb (Target Group Buff) by default, to disable change to false for a classic experience.")
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(Mercs) RULE_CATEGORY(Mercs)
@@ -188,9 +182,6 @@ RULE_INT(Mercs, AggroRadiusPuller, 25, "Determines the distance from which a mer
RULE_INT(Mercs, ResurrectRadius, 50, "Determines the distance from which a healer merc will attempt to resurrect a group member's corpse") RULE_INT(Mercs, ResurrectRadius, 50, "Determines the distance from which a healer merc will attempt to resurrect a group member's corpse")
RULE_INT(Mercs, ScaleRate, 100, "Merc scale factor") RULE_INT(Mercs, ScaleRate, 100, "Merc scale factor")
RULE_BOOL(Mercs, AllowMercSuspendInCombat, true, "Allow merc suspend in combat") RULE_BOOL(Mercs, AllowMercSuspendInCombat, true, "Allow merc suspend in combat")
RULE_BOOL(Mercs, IsMercsElixirEnabled, false, "Override AI with elixir logic")
RULE_INT(Mercs, MercsElixirHealPercent, 90, "Heal allies at this percent health")
RULE_INT(Mercs, MercsElixirAEMinimum, 3, "AE Minimum to trigger AE spells (heals and nukes)")
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(Guild) RULE_CATEGORY(Guild)
@@ -329,7 +320,7 @@ RULE_INT(Spells, MaxDiscSlotsNPC, 0, "Maximum number of NPC disc slots. NPC don'
RULE_INT(Spells, MaxTotalSlotsNPC, 60, "Maximum total of NPC slots. The default value is the limit of the Titanium client") RULE_INT(Spells, MaxTotalSlotsNPC, 60, "Maximum total of NPC slots. The default value is the limit of the Titanium client")
RULE_INT(Spells, MaxTotalSlotsPET, 30, "Maximum total of pet slots. The default value is the limit of the Titanium client") RULE_INT(Spells, MaxTotalSlotsPET, 30, "Maximum total of pet slots. The default value is the limit of the Titanium client")
RULE_BOOL (Spells, EnableBlockedBuffs, true, "Allow blocked spells") RULE_BOOL (Spells, EnableBlockedBuffs, true, "Allow blocked spells")
RULE_INT(Spells, ReflectType, 4, "Reflect type. 0=disabled, 1=single target player spells only, 2=all player spells, 3=all single target spells, 4=all spells") RULE_INT(Spells, ReflectType, 3, "Reflect type. 0=disabled, 1=single target player spells only, 2=all player spells, 3=all single target spells, 4=all spells")
RULE_BOOL(Spells, ReflectMessagesClose, true, "True (Live functionality) is for Reflect messages to show to players within close proximity. False shows just player reflecting") RULE_BOOL(Spells, ReflectMessagesClose, true, "True (Live functionality) is for Reflect messages to show to players within close proximity. False shows just player reflecting")
RULE_INT(Spells, VirusSpreadDistance, 30, "The distance a viral spell will jump to its next victim") RULE_INT(Spells, VirusSpreadDistance, 30, "The distance a viral spell will jump to its next victim")
RULE_BOOL(Spells, LiveLikeFocusEffects, true, "Determines whether specific healing, dmg and mana reduction focuses are randomized") RULE_BOOL(Spells, LiveLikeFocusEffects, true, "Determines whether specific healing, dmg and mana reduction focuses are randomized")
@@ -390,10 +381,6 @@ RULE_BOOL(Spells, PreventFactionWarOnCharmBreak, false, "Enable spell interupts
RULE_BOOL(Spells, AllowDoubleInvis, false, "Allows you to cast invisibility spells on a player that is already invisible") RULE_BOOL(Spells, AllowDoubleInvis, false, "Allows you to cast invisibility spells on a player that is already invisible")
RULE_BOOL(Spells, AllowSpellMemorizeFromItem, false, "Allows players to memorize spells by right-clicking spell scrolls") RULE_BOOL(Spells, AllowSpellMemorizeFromItem, false, "Allows players to memorize spells by right-clicking spell scrolls")
RULE_BOOL(Spells, InvisRequiresGroup, false, "Invis requires the the target to be in group.") RULE_BOOL(Spells, InvisRequiresGroup, false, "Invis requires the the target to be in group.")
RULE_INT(Spells, ClericInnateHealFocus, 5, "Clerics on live get a 5 pct innate heal focus")
RULE_BOOL(Spells, DOTsScaleWithSpellDmg, false, "Allow SpellDmg stat to affect DoT spells")
RULE_BOOL(Spells, HOTsScaleWithHealAmt, false, "Allow HealAmt stat to affect HoT spells")
RULE_BOOL(Spells, CompoundLifetapHeals, true, "True: Lifetap heals calculate damage bonuses and then heal bonuses. False: Lifetaps heal using the amount damaged to mob.")
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(Combat) RULE_CATEGORY(Combat)
@@ -405,8 +392,7 @@ RULE_INT(Combat, ArcheryCritDifficulty, 3400, "Value against which is rolled to
RULE_INT(Combat, ThrowingCritDifficulty, 1100, "Value against which is rolled to check if a throwing crit is triggered. Lower is easier") RULE_INT(Combat, ThrowingCritDifficulty, 1100, "Value against which is rolled to check if a throwing crit is triggered. Lower is easier")
RULE_BOOL(Combat, NPCCanCrit, false, "Setting whether an NPC can land critical hits") RULE_BOOL(Combat, NPCCanCrit, false, "Setting whether an NPC can land critical hits")
RULE_BOOL(Combat, UseIntervalAC, true, "Switch whether bonuses, armour class, multipliers, classes and caps should be considered in the calculation of damage values") RULE_BOOL(Combat, UseIntervalAC, true, "Switch whether bonuses, armour class, multipliers, classes and caps should be considered in the calculation of damage values")
RULE_INT(Combat, PetAttackMagicLevel, 10, "Level at which pets can cause magic damage, no longer used") RULE_INT(Combat, PetAttackMagicLevel, 30, "Level at which pets can cause magic damage")
RULE_INT(Combat, NPCAttackMagicLevel, 10, "Level at which NPC and pets can cause magic damage")
RULE_BOOL(Combat, EnableFearPathing, true, "Setting whether to use pathing during fear") RULE_BOOL(Combat, EnableFearPathing, true, "Setting whether to use pathing during fear")
RULE_BOOL(Combat, FleeGray, true, "If true FleeGrayHPRatio will be used") RULE_BOOL(Combat, FleeGray, true, "If true FleeGrayHPRatio will be used")
RULE_INT(Combat, FleeGrayHPRatio, 50, "HP percentage when a Gray NPC begins to flee") RULE_INT(Combat, FleeGrayHPRatio, 50, "HP percentage when a Gray NPC begins to flee")
@@ -492,8 +478,6 @@ RULE_BOOL(Combat, UseExtendedPoisonProcs, false, "Allow old school poisons to la
RULE_BOOL(Combat, EnableSneakPull, false, "Enable implementation of Sneak Pull") RULE_BOOL(Combat, EnableSneakPull, false, "Enable implementation of Sneak Pull")
RULE_INT(Combat, SneakPullAssistRange, 400, "Modified range of assist for sneak pull") RULE_INT(Combat, SneakPullAssistRange, 400, "Modified range of assist for sneak pull")
RULE_BOOL(Combat, Classic2HBAnimation, false, "2HB will use the 2 hand piercing animation instead of the overhead slashing animation") RULE_BOOL(Combat, Classic2HBAnimation, false, "2HB will use the 2 hand piercing animation instead of the overhead slashing animation")
RULE_BOOL(Combat, ArcheryConsumesAmmo, true, "Set to false to disable Archery Ammo Consumption")
RULE_BOOL(Combat, ThrowingConsumesAmmo, true, "Set to false to disable Throwing Ammo Consumption")
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(NPC) RULE_CATEGORY(NPC)
@@ -525,7 +509,6 @@ RULE_BOOL(NPC, NPCHealOnGate, true, "Will the NPC Heal on Gate")
RULE_BOOL(NPC, UseMeditateBasedManaRegen, false, "Based NPC ooc regen on Meditate skill") RULE_BOOL(NPC, UseMeditateBasedManaRegen, false, "Based NPC ooc regen on Meditate skill")
RULE_REAL(NPC, NPCHealOnGateAmount, 25, "How much the NPC will heal on gate if enabled") RULE_REAL(NPC, NPCHealOnGateAmount, 25, "How much the NPC will heal on gate if enabled")
RULE_BOOL(NPC, AnimalsOpenDoors, true, "Determines or not whether animals open doors or not when they approach them") RULE_BOOL(NPC, AnimalsOpenDoors, true, "Determines or not whether animals open doors or not when they approach them")
RULE_INT(NPC, MaxRaceID, 732, "Maximum Race ID, RoF2 by default supports up to 732")
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(Aggro) RULE_CATEGORY(Aggro)
@@ -598,13 +581,6 @@ RULE_REAL(Bots, LeashDistance, 562500.0f, "Distance a bot is allowed to travel f
RULE_BOOL(Bots, AllowApplyPoisonCommand, true, "Allows the use of the bot command 'applypoison'") RULE_BOOL(Bots, AllowApplyPoisonCommand, true, "Allows the use of the bot command 'applypoison'")
RULE_BOOL(Bots, AllowApplyPotionCommand, true, "Allows the use of the bot command 'applypotion'") RULE_BOOL(Bots, AllowApplyPotionCommand, true, "Allows the use of the bot command 'applypotion'")
RULE_BOOL(Bots, RestrictApplyPotionToRogue, true, "Restricts the bot command 'applypotion' to rogue-usable potions (i.e., poisons)") RULE_BOOL(Bots, RestrictApplyPotionToRogue, true, "Restricts the bot command 'applypotion' to rogue-usable potions (i.e., poisons)")
RULE_BOOL(Bots, OldRaceRezEffects, false, "Older clients had ID 757 for races with high starting STR, but it doesn't seem used anymore")
RULE_BOOL(Bots, ResurrectionSickness, true, "Use Resurrection Sickness based on Resurrection spell cast, set to false to disable Resurrection Sickness.")
RULE_INT(Bots, OldResurrectionSicknessSpell, 757, "757 is Default Old Resurrection Sickness Spell")
RULE_INT(Bots, ResurrectionSicknessSpell, 756, "756 is Default Resurrection Sickness Spell")
RULE_BOOL(Bots, IsBotsElixirEnabled, false, "Override AI with elixir logic")
RULE_INT(Bots, BotsElixirHealPercent, 90, "Heal allies at this percent health")
RULE_INT(Bots, BotsElixirAEMinimum, 3, "AE Minimum to trigger AE spells (heals and nukes)")
RULE_CATEGORY_END() RULE_CATEGORY_END()
#endif #endif
@@ -623,10 +599,6 @@ RULE_INT(Chat, IntervalDurationMS, 60000, "Interval length in milliseconds")
RULE_INT(Chat, KarmaUpdateIntervalMS, 1200000, "Karma update interval in milliseconds") RULE_INT(Chat, KarmaUpdateIntervalMS, 1200000, "Karma update interval in milliseconds")
RULE_INT(Chat, KarmaGlobalChatLimit, 72, "Amount of karma you need to be able to talk in ooc/auction/chat below the level limit") RULE_INT(Chat, KarmaGlobalChatLimit, 72, "Amount of karma you need to be able to talk in ooc/auction/chat below the level limit")
RULE_INT(Chat, GlobalChatLevelLimit, 8, "Level limit you need to of reached to talk in ooc/auction/chat if your karma is too low") RULE_INT(Chat, GlobalChatLevelLimit, 8, "Level limit you need to of reached to talk in ooc/auction/chat if your karma is too low")
RULE_BOOL(Chat, AutoInjectSaylinksToSay, true, "Automatically injects saylinks into dialogue that has [brackets in them]")
RULE_BOOL(Chat, AutoInjectSaylinksToClientMessage, true, "Automatically injects saylinks into dialogue that has [brackets in them]")
RULE_BOOL(Chat, QuestDialogueUsesDialogueWindow, false, "Pipes all quest dialogue to dialogue window")
RULE_BOOL(Chat, DialogueWindowAnimatesNPCsIfNoneSet, true, "If there is no animation specified in the dialogue window markdown then it will choose a random greet animation such as wave or salute")
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(Merchant) RULE_CATEGORY(Merchant)
@@ -808,10 +780,6 @@ RULE_BOOL(Cheat, EnableMQFastMemDetector, true, "Enable the MQFastMem Detector.
RULE_BOOL(Cheat, MarkMQWarpLT, false, "Mark clients makeing smaller warps") RULE_BOOL(Cheat, MarkMQWarpLT, false, "Mark clients makeing smaller warps")
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(Command)
RULE_BOOL(Command, DyeCommandRequiresDyes, false, "Enable this to require a Prismatic Dye (32557) each time someone uses #dye.")
RULE_CATEGORY_END()
#undef RULE_CATEGORY #undef RULE_CATEGORY
#undef RULE_INT #undef RULE_INT
#undef RULE_REAL #undef RULE_REAL
+27 -195
View File
@@ -24,10 +24,7 @@
#include "item_instance.h" #include "item_instance.h"
#include "item_data.h" #include "item_data.h"
#include "../zone/zonedb.h" #include "../zone/zonedb.h"
#include <algorithm>
// static bucket global
std::vector<SaylinkRepository::Saylink> g_cached_saylinks = {};
bool EQ::saylink::DegenerateLinkBody(SayLinkBody_Struct &say_link_body_struct, const std::string &say_link_body) bool EQ::saylink::DegenerateLinkBody(SayLinkBody_Struct &say_link_body_struct, const std::string &say_link_body)
{ {
@@ -298,9 +295,33 @@ std::string EQ::SayLinkEngine::GenerateQuestSaylink(std::string saylink_text, bo
{ {
uint32 saylink_id = 0; uint32 saylink_id = 0;
SaylinkRepository::Saylink saylink = GetOrSaveSaylink(saylink_text); /**
if (saylink.id > 0) { * Query for an existing phrase and id in the saylink table
saylink_id = saylink.id; */
std::string query = StringFormat(
"SELECT `id` FROM `saylink` WHERE `phrase` = '%s' LIMIT 1",
EscapeString(saylink_text).c_str());
auto results = database.QueryDatabase(query);
if (results.Success()) {
if (results.RowCount() >= 1) {
for (auto row = results.begin(); row != results.end(); ++row)
saylink_id = static_cast<uint32>(atoi(row[0]));
}
else {
std::string insert_query = StringFormat(
"INSERT INTO `saylink` (`phrase`) VALUES ('%s')",
EscapeString(saylink_text).c_str());
results = database.QueryDatabase(insert_query);
if (!results.Success()) {
LogError("Error in saylink phrase queries {}", results.ErrorMessage().c_str());
}
else {
saylink_id = results.LastInsertedID();
}
}
} }
/** /**
@@ -319,192 +340,3 @@ std::string EQ::SayLinkEngine::GenerateQuestSaylink(std::string saylink_text, bo
return linker.GenerateLink(); return linker.GenerateLink();
} }
std::string EQ::SayLinkEngine::InjectSaylinksIfNotExist(const char *message)
{
std::string new_message = message;
int link_index = 0;
int saylink_index = 0;
std::vector<std::string> links = {};
std::vector<std::string> saylinks = {};
int saylink_length = 50;
std::string saylink_separator = "\u0012";
std::string saylink_partial = "00000";
LogSaylinkDetail("new_message pre pass 1 [{}]", new_message);
// first pass - strip existing saylinks by putting placeholder anchors on them
for (auto &saylink: split_string(new_message, saylink_separator)) {
if (!saylink.empty() && saylink.length() > saylink_length &&
saylink.find(saylink_partial) != std::string::npos) {
saylinks.emplace_back(saylink);
LogSaylinkDetail("Found saylink [{}]", saylink);
// replace with anchor
find_replace(
new_message,
fmt::format("{}", saylink),
fmt::format("<saylink:{}>", saylink_index)
);
saylink_index++;
}
}
LogSaylinkDetail("new_message post pass 1 [{}]", new_message);
LogSaylinkDetail("saylink separator count [{}]", std::count(new_message.begin(), new_message.end(), '\u0012'));
// loop through brackets until none exist
if (new_message.find('[') != std::string::npos) {
for (auto &b: split_string(new_message, "[")) {
if (!b.empty() && b.find(']') != std::string::npos) {
std::vector<std::string> right_split = split_string(b, "]");
if (!right_split.empty()) {
std::string bracket_message = trim(right_split[0]);
// we shouldn't see a saylink fragment here, ignore this bracket
if (bracket_message.find(saylink_partial) != std::string::npos) {
continue;
}
// skip where multiple saylinks are within brackets
if (bracket_message.find(saylink_separator) != std::string::npos &&
std::count(bracket_message.begin(), bracket_message.end(), '\u0012') > 1) {
continue;
}
// if non empty bracket contents
if (!bracket_message.empty()) {
LogSaylinkDetail("Found bracket_message [{}]", bracket_message);
// already a saylink
// todo: improve this later
if (!bracket_message.empty() &&
(bracket_message.length() > saylink_length ||
bracket_message.find(saylink_separator) != std::string::npos)) {
links.emplace_back(bracket_message);
}
else {
links.emplace_back(
EQ::SayLinkEngine::GenerateQuestSaylink(
bracket_message,
false,
bracket_message
)
);
}
// replace with anchor
find_replace(
new_message,
fmt::format("[{}]", bracket_message),
fmt::format("<prelink:{}>", link_index)
);
link_index++;
}
}
}
}
}
LogSaylinkDetail("new_message post pass 2 (post brackets) [{}]", new_message);
// strip any current delimiters of saylinks
find_replace(new_message, saylink_separator, "");
// pop links onto anchors
link_index = 0;
for (auto &link: links) {
// strip any current delimiters of saylinks
find_replace(link, saylink_separator, "");
find_replace(
new_message,
fmt::format("<prelink:{}>", link_index),
fmt::format("[\u0012{}\u0012]", link)
);
link_index++;
}
LogSaylinkDetail("new_message post pass 3 (post prelink anchor pop) [{}]", new_message);
// pop links onto anchors
saylink_index = 0;
for (auto &link: saylinks) {
// strip any current delimiters of saylinks
find_replace(link, saylink_separator, "");
// check to see if we did a double anchor pass (existing saylink that was also inside brackets)
// this means we found a saylink and we're checking to see if we're already encoded before double encoding
if (new_message.find(fmt::format("\u0012<saylink:{}>\u0012", saylink_index)) != std::string::npos) {
LogSaylinkDetail("Found encoded saylink at index [{}]", saylink_index);
find_replace(
new_message,
fmt::format("\u0012<saylink:{}>\u0012", saylink_index),
fmt::format("\u0012{}\u0012", link)
);
saylink_index++;
continue;
}
find_replace(
new_message,
fmt::format("<saylink:{}>", saylink_index),
fmt::format("\u0012{}\u0012", link)
);
saylink_index++;
}
LogSaylinkDetail("new_message post pass 4 (post saylink anchor pop) [{}]", new_message);
return new_message;
}
void EQ::SayLinkEngine::LoadCachedSaylinks()
{
auto saylinks = SaylinkRepository::GetWhere(database, "phrase not like '%#%'");
LogSaylink("Loaded [{}] saylinks into cache", saylinks.size());
g_cached_saylinks = saylinks;
}
SaylinkRepository::Saylink EQ::SayLinkEngine::GetOrSaveSaylink(std::string saylink_text)
{
// return cached saylink if exist
if (!g_cached_saylinks.empty()) {
for (auto &s: g_cached_saylinks) {
if (s.phrase == saylink_text) {
return s;
}
}
}
auto saylinks = SaylinkRepository::GetWhere(
database,
fmt::format("phrase = '{}'", EscapeString(saylink_text))
);
// return if found from the database
if (!saylinks.empty()) {
return saylinks[0];
}
// if not found in database - save
if (saylinks.empty()) {
auto new_saylink = SaylinkRepository::NewEntity();
new_saylink.phrase = saylink_text;
// persist to database
auto link = SaylinkRepository::InsertOne(database, new_saylink);
if (link.id > 0) {
g_cached_saylinks.emplace_back(link);
return link;
}
}
return {};
}
+1 -4
View File
@@ -23,7 +23,7 @@
#include "types.h" #include "types.h"
#include <string> #include <string>
#include "repositories/saylink_repository.h"
struct ServerLootItem_Struct; struct ServerLootItem_Struct;
@@ -105,8 +105,6 @@ namespace EQ
void Reset(); void Reset();
static std::string InjectSaylinksIfNotExist(const char *message);
static void LoadCachedSaylinks();
private: private:
void generate_body(); void generate_body();
void generate_text(); void generate_text();
@@ -122,7 +120,6 @@ namespace EQ
std::string m_LinkBody; std::string m_LinkBody;
std::string m_LinkText; std::string m_LinkText;
bool m_Error; bool m_Error;
static SaylinkRepository::Saylink GetOrSaveSaylink(std::string saylink_text);
}; };
} /*EQEmu*/ } /*EQEmu*/
+572 -166
View File
@@ -227,26 +227,90 @@
#define ServerOP_HotReloadQuests 0x4011 #define ServerOP_HotReloadQuests 0x4011
#define ServerOP_UpdateSchedulerEvents 0x4012 #define ServerOP_UpdateSchedulerEvents 0x4012
#define ServerOP_CZDialogueWindow 0x4500 #define ServerOP_CZCastSpellPlayer 0x4500
#define ServerOP_CZLDoNUpdate 0x4501 #define ServerOP_CZCastSpellGroup 0x4501
#define ServerOP_CZMarquee 0x4502 #define ServerOP_CZCastSpellRaid 0x4502
#define ServerOP_CZMessage 0x4503 #define ServerOP_CZCastSpellGuild 0x4503
#define ServerOP_CZMove 0x4504 #define ServerOP_CZMarqueePlayer 0x4504
#define ServerOP_CZSetEntityVariable 0x4505 #define ServerOP_CZMarqueeGroup 0x4505
#define ServerOP_CZSignal 0x4506 #define ServerOP_CZMarqueeRaid 0x4506
#define ServerOP_CZSpell 0x4507 #define ServerOP_CZMarqueeGuild 0x4507
#define ServerOP_CZTaskUpdate 0x4508 #define ServerOP_CZMessagePlayer 0x4508
#define ServerOP_CZClientMessageString 0x4509 #define ServerOP_CZMessageGroup 0x4509
#define ServerOP_CZMessageRaid 0x4510
#define ServerOP_CZMessageGuild 0x4511
#define ServerOP_CZMovePlayer 0x4512
#define ServerOP_CZMoveGroup 0x4513
#define ServerOP_CZMoveRaid 0x4514
#define ServerOP_CZMoveGuild 0x4515
#define ServerOP_CZMoveInstancePlayer 0x4516
#define ServerOP_CZMoveInstanceGroup 0x4517
#define ServerOP_CZMoveInstanceRaid 0x4518
#define ServerOP_CZMoveInstanceGuild 0x4519
#define ServerOP_CZRemoveSpellPlayer 0x4520
#define ServerOP_CZRemoveSpellGroup 0x4521
#define ServerOP_CZRemoveSpellRaid 0x4522
#define ServerOP_CZRemoveSpellGuild 0x4523
#define ServerOP_CZSetEntityVariableByClientName 0x4524
#define ServerOP_CZSetEntityVariableByNPCTypeID 0x4525
#define ServerOP_CZSetEntityVariableByGroupID 0x4526
#define ServerOP_CZSetEntityVariableByRaidID 0x4527
#define ServerOP_CZSetEntityVariableByGuildID 0x4528
#define ServerOP_CZSignalClient 0x4529
#define ServerOP_CZSignalClientByName 0x4530
#define ServerOP_CZSignalNPC 0x4531
#define ServerOP_CZSignalGroup 0x4532
#define ServerOP_CZSignalRaid 0x4533
#define ServerOP_CZSignalGuild 0x4534
#define ServerOP_CZTaskActivityResetPlayer 0x4535
#define ServerOP_CZTaskActivityResetGroup 0x4536
#define ServerOP_CZTaskActivityResetRaid 0x4537
#define ServerOP_CZTaskActivityResetGuild 0x4538
#define ServerOP_CZTaskActivityUpdatePlayer 0x4539
#define ServerOP_CZTaskActivityUpdateGroup 0x4540
#define ServerOP_CZTaskActivityUpdateRaid 0x4541
#define ServerOP_CZTaskActivityUpdateGuild 0x4542
#define ServerOP_CZTaskAssignPlayer 0x4543
#define ServerOP_CZTaskAssignGroup 0x4544
#define ServerOP_CZTaskAssignRaid 0x4545
#define ServerOP_CZTaskAssignGuild 0x4546
#define ServerOP_CZTaskDisablePlayer 0x4547
#define ServerOP_CZTaskDisableGroup 0x4548
#define ServerOP_CZTaskDisableRaid 0x4549
#define ServerOP_CZTaskDisableGuild 0x4550
#define ServerOP_CZTaskEnablePlayer 0x4551
#define ServerOP_CZTaskEnableGroup 0x4552
#define ServerOP_CZTaskEnableRaid 0x4553
#define ServerOP_CZTaskEnableGuild 0x4554
#define ServerOP_CZTaskFailPlayer 0x4555
#define ServerOP_CZTaskFailGroup 0x4556
#define ServerOP_CZTaskFailRaid 0x4557
#define ServerOP_CZTaskFailGuild 0x4558
#define ServerOP_CZTaskRemovePlayer 0x4559
#define ServerOP_CZTaskRemoveGroup 0x4560
#define ServerOP_CZTaskRemoveRaid 0x4561
#define ServerOP_CZTaskRemoveGuild 0x4562
#define ServerOP_CZClientMessageString 0x4563
#define ServerOP_CZLDoNUpdate 0x4564
#define ServerOP_WWDialogueWindow 0x4750 #define ServerOP_WWAssignTask 0x4750
#define ServerOP_WWLDoNUpdate 0x4751 #define ServerOP_WWCastSpell 0x4751
#define ServerOP_WWMarquee 0x4752 #define ServerOP_WWCompleteActivity 0x4752
#define ServerOP_WWMessage 0x4753 #define ServerOP_WWDisableTask 0x4753
#define ServerOP_WWMove 0x4754 #define ServerOP_WWEnableTask 0x4754
#define ServerOP_WWSetEntityVariable 0x4755 #define ServerOP_WWFailTask 0x4755
#define ServerOP_WWSignal 0x4756 #define ServerOP_WWMarquee 0x4756
#define ServerOP_WWSpell 0x4757 #define ServerOP_WWMessage 0x4757
#define ServerOP_WWTaskUpdate 0x4758 #define ServerOP_WWMove 0x4758
#define ServerOP_WWMoveInstance 0x4759
#define ServerOP_WWRemoveSpell 0x4760
#define ServerOP_WWRemoveTask 0x4761
#define ServerOP_WWResetActivity 0x4762
#define ServerOP_WWSetEntityVariableClient 0x4763
#define ServerOP_WWSetEntityVariableNPC 0x4764
#define ServerOP_WWSignalClient 0x4765
#define ServerOP_WWSignalNPC 0x4766
#define ServerOP_WWUpdateActivity 0x4767
/** /**
* QueryServer * QueryServer
@@ -261,79 +325,17 @@
#define ServerOP_QSPlayerDropItem 0x5007 #define ServerOP_QSPlayerDropItem 0x5007
enum { enum {
CZUpdateType_Character, CZLDoNUpdateType_Character = 0,
CZUpdateType_Group, CZLDoNUpdateType_Group,
CZUpdateType_Raid, CZLDoNUpdateType_Raid,
CZUpdateType_Guild, CZLDoNUpdateType_Guild,
CZUpdateType_Expedition, CZLDoNUpdateType_Expedition
CZUpdateType_ClientName,
CZUpdateType_NPC
}; };
enum { enum {
CZLDoNUpdateSubtype_AddLoss, CZLDoNUpdateSubtype_Win = 0,
CZLDoNUpdateSubtype_AddPoints, CZLDoNUpdateSubtype_Loss,
CZLDoNUpdateSubtype_AddWin, CZLDoNUpdateSubtype_Points
CZLDoNUpdateSubtype_RemoveLoss,
CZLDoNUpdateSubtype_RemoveWin,
};
enum {
CZMoveUpdateSubtype_MoveZone,
CZMoveUpdateSubtype_MoveZoneInstance
};
enum {
CZSpellUpdateSubtype_Cast,
CZSpellUpdateSubtype_Remove
};
enum {
CZTaskUpdateSubtype_ActivityReset,
CZTaskUpdateSubtype_ActivityUpdate,
CZTaskUpdateSubtype_AssignTask,
CZTaskUpdateSubtype_DisableTask,
CZTaskUpdateSubtype_EnableTask,
CZTaskUpdateSubtype_FailTask,
CZTaskUpdateSubtype_RemoveTask
};
enum {
WWLDoNUpdateType_AddLoss,
WWLDoNUpdateType_AddPoints,
WWLDoNUpdateType_AddWin,
WWLDoNUpdateType_RemoveLoss,
WWLDoNUpdateType_RemoveWin
};
enum {
WWMoveUpdateType_MoveZone,
WWMoveUpdateType_MoveZoneInstance
};
enum {
WWSetEntityVariableUpdateType_Character,
WWSetEntityVariableUpdateType_NPC
};
enum {
WWSignalUpdateType_Character,
WWSignalUpdateType_NPC
};
enum {
WWSpellUpdateType_Cast,
WWSpellUpdateType_Remove
};
enum {
WWTaskUpdateType_ActivityReset,
WWTaskUpdateType_ActivityUpdate,
WWTaskUpdateType_AssignTask,
WWTaskUpdateType_DisableTask,
WWTaskUpdateType_EnableTask,
WWTaskUpdateType_FailTask,
WWTaskUpdateType_RemoveTask
}; };
/* Query Serv Generic Packet Flag/Type Enumeration */ /* Query Serv Generic Packet Flag/Type Enumeration */
@@ -1438,107 +1440,489 @@ struct QSGeneralQuery_Struct {
char QueryString[0]; char QueryString[0];
}; };
struct CZCastSpellPlayer_Struct {
int character_id;
uint32 spell_id;
};
struct CZCastSpellGroup_Struct {
int group_id;
uint32 spell_id;
};
struct CZCastSpellRaid_Struct {
int raid_id;
uint32 spell_id;
};
struct CZCastSpellGuild_Struct {
int guild_id;
uint32 spell_id;
};
struct CZClientSignal_Struct {
int character_id;
uint32 signal;
};
struct CZGroupSignal_Struct {
int group_id;
uint32 signal;
};
struct CZRaidSignal_Struct {
int raid_id;
uint32 signal;
};
struct CZGuildSignal_Struct {
int guild_id;
uint32 signal;
};
struct CZNPCSignal_Struct {
uint32 npctype_id;
uint32 signal;
};
struct CZClientMessageString_Struct { struct CZClientMessageString_Struct {
uint32 string_id; uint32 string_id;
uint16 chat_type; uint16 chat_type;
char client_name[64]; char character_name[64];
uint32 args_size; uint32 args_size;
char args[1]; // null delimited char args[1]; // null delimited
}; };
struct CZDialogueWindow_Struct { struct CZClientSignalByName_Struct {
uint8 update_type; // 0 - Character, 1 - Group, 2 - Raid, 3 - Guild, 4 - Expedition, 5 - Character Name char character_name[64];
int update_identifier; // Character ID, Group ID, Raid ID, Guild ID, or Expedition ID based on update type, 0 for Character Name uint32 signal;
char message[4096];
char client_name[64]; // Only used by Character Name Type, else empty
}; };
struct CZLDoNUpdate_Struct { struct CZCompleteActivityPlayer_Struct {
uint8 update_type; // 0 - Character, 1 - Group, 2 - Raid, 3 - Guild, 4 - Expedition, 5 - Character Name int character_id;
uint8 update_subtype; // 0 - Loss, 1 - Points, 2 - Win uint32 task_id;
int update_identifier; // Character ID, Group ID, Raid ID, Guild ID, or Expedition ID based on update type, 0 for Character Name int activity_id;
uint32 theme_id;
int points; // Only used in Points Subtype, else 1
char client_name[64]; // Only used by Character Name Type, else empty
}; };
struct CZMarquee_Struct { struct CZCompleteActivityGroup_Struct {
uint8 update_type; // 0 - Character, 1 - Group, 2 - Raid, 3 - Guild, 4 - Expedition, 5 - Character Name int group_id;
int update_identifier; // Character ID, Group ID, Raid ID, Guild ID, or Expedition ID based on update type, 0 for Character Name uint32 task_id;
int activity_id;
};
struct CZCompleteActivityRaid_Struct {
int raid_id;
uint32 task_id;
int activity_id;
};
struct CZCompleteActivityGuild_Struct {
int guild_id;
uint32 task_id;
int activity_id;
};
struct CZMovePlayer_Struct {
int character_id;
char zone_short_name[32];
};
struct CZMarqueePlayer_Struct {
int character_id;
uint32 type; uint32 type;
uint32 priority; uint32 priority;
uint32 fade_in; uint32 fade_in;
uint32 fade_out; uint32 fade_out;
uint32 duration; uint32 duration;
char message[512]; char message[512];
char client_name[64]; // Only used by Character Name Type, else empty
}; };
struct CZMessage_Struct { struct CZMarqueeGroup_Struct {
uint8 update_type; // 0 - Character, 1 - Group, 2 - Raid, 3 - Guild, 4 - Expedition, 5 - Character Name int group_id;
int update_identifier; // Group ID, Raid ID, Guild ID, or Expedition ID based on update type, 0 for Character Name
uint32 type; uint32 type;
uint32 priority;
uint32 fade_in;
uint32 fade_out;
uint32 duration;
char message[512]; char message[512];
char client_name[64]; // Only used by Character Name Type, else empty
}; };
struct CZMove_Struct { struct CZMarqueeRaid_Struct {
uint8 update_type; // 0 - Character, 1 - Group, 2 - Raid, 3 - Guild, 4 - Expedition, 5 - Character Name int raid_id;
uint8 update_subtype; // 0 - Move Zone, 1 - Move Zone Instance uint32 type;
int update_identifier; // Character ID, Group ID, Raid ID, Guild ID, or Expedition ID based on update type, 0 for Character Name uint32 priority;
uint16 instance_id; // Only used by Move Zone Instance, else 0 uint32 fade_in;
char zone_short_name[32]; // Only by with Move Zone, else empty uint32 fade_out;
char client_name[64]; // Only used by Character Name Type, else empty uint32 duration;
char message[512];
}; };
struct CZSetEntityVariable_Struct { struct CZMarqueeGuild_Struct {
uint8 update_type; // 0 - Character, 1 - Group, 2 - Raid, 3 - Guild, 4 - Expedition, 5 - Character Name, 6 - NPC int guild_id;
int update_identifier; // Group ID, Raid ID, Guild ID, Expedition ID, or NPC ID based on update type, 0 for Character Name uint32 type;
uint32 priority;
uint32 fade_in;
uint32 fade_out;
uint32 duration;
char message[512];
};
struct CZMessagePlayer_Struct {
uint32 type;
char character_name[64];
char message[512];
};
struct CZMessageGroup_Struct {
uint32 type;
int group_id;
char message[512];
};
struct CZMessageRaid_Struct {
uint32 type;
int raid_id;
char message[512];
};
struct CZMessageGuild_Struct {
uint32 type;
int guild_id;
char message[512];
};
struct CZMoveGroup_Struct {
int group_id;
char zone_short_name[32];
};
struct CZMoveRaid_Struct {
int raid_id;
char zone_short_name[32];
};
struct CZMoveGuild_Struct {
int guild_id;
char zone_short_name[32];
};
struct CZMoveInstancePlayer_Struct {
int character_id;
uint16 instance_id;
};
struct CZMoveInstanceGroup_Struct {
int group_id;
uint16 instance_id;
};
struct CZMoveInstanceRaid_Struct {
int raid_id;
uint16 instance_id;
};
struct CZMoveInstanceGuild_Struct {
int guild_id;
uint16 instance_id;
};
struct CZRemoveSpellPlayer_Struct {
int character_id;
uint32 spell_id;
};
struct CZRemoveSpellGroup_Struct {
int group_id;
uint32 spell_id;
};
struct CZRemoveSpellRaid_Struct {
int raid_id;
uint32 spell_id;
};
struct CZRemoveSpellGuild_Struct {
int guild_id;
uint32 spell_id;
};
struct CZRemoveTaskPlayer_Struct {
int character_id;
uint32 task_id;
};
struct CZRemoveTaskGroup_Struct {
int group_id;
uint32 task_id;
};
struct CZRemoveTaskRaid_Struct {
int raid_id;
uint32 task_id;
};
struct CZRemoveTaskGuild_Struct {
int guild_id;
uint32 task_id;
};
struct CZResetActivityPlayer_Struct {
int character_id;
uint32 task_id;
int activity_id;
};
struct CZResetActivityGroup_Struct {
int group_id;
uint32 task_id;
int activity_id;
};
struct CZResetActivityRaid_Struct {
int raid_id;
uint32 task_id;
int activity_id;
};
struct CZResetActivityGuild_Struct {
int guild_id;
uint32 task_id;
int activity_id;
};
struct CZSetEntVarByNPCTypeID_Struct {
uint32 npctype_id;
char variable_name[256]; char variable_name[256];
char variable_value[256]; char variable_value[256];
char client_name[64]; // Only used by Character Type, else empty
}; };
struct CZSignal_Struct { struct CZSetEntVarByClientName_Struct {
uint8 update_type; // 0 - Character, 1 - Group, 2 - Raid, 3 - Guild, 4 - Expedition, 5 - Character Name, 6 - NPC char character_name[64];
int update_identifier; // Character ID, Group ID, Raid ID, Guild ID, Expedition ID, or NPC ID based on update type, 0 for Character Name char variable_name[256];
uint32 signal; char variable_value[256];
char client_name[64]; // Only used by Character Name Type, else empty
}; };
struct CZSpell_Struct { struct CZSetEntVarByGroupID_Struct {
uint8 update_type; // 0 - Character, 1 - Group, 2 - Raid, 3 - Guild, 4 - Expedition, 5 - Character Name int group_id;
uint8 update_subtype; // 0 - Cast Spell, 1 - Remove Spell char variable_name[256];
int update_identifier; // Character ID, Group ID, Raid ID, Guild ID, or Expedition ID based on update type, 0 for Character Name char variable_value[256];
uint32 spell_id;
char client_name[64]; // Only used by Character Name Type, else empty
}; };
struct CZTaskUpdate_Struct { struct CZSetEntVarByRaidID_Struct {
uint8 update_type; // 0 - Character, 1 - Group, 2 - Raid, 3 - Guild, 4 - Expedition, 5 - Character Name int raid_id;
uint8 update_subtype; // 0 - Activity Reset, 1 - Activity Update, 2 - Assign Task, 3 - Disable Task, 4 - Enable Task, 5 - Fail Task, 6 - Remove Task char variable_name[256];
int update_identifier; // Character ID, Group ID, Raid ID, Guild ID, or Expedition ID based on update type, 0 for Character Name char variable_value[256];
uint32 task_identifier;
int task_subidentifier; // Activity ID for Activity Reset and Activity Update, NPC Entity ID for Assign Task, else -1
int update_count; // Only used by Activity Update, else 1
bool enforce_level_requirement; // Only used by Assign Task
char client_name[64]; // Only used by Character Name Type, else empty
}; };
struct WWDialogueWindow_Struct { struct CZSetEntVarByGuildID_Struct {
char message[4096]; int guild_id;
uint8 min_status; char variable_name[256];
uint8 max_status; char variable_value[256];
}; };
struct WWLDoNUpdate_Struct { struct CZTaskActivityResetPlayer_Struct {
uint8 update_type; // 0 - Loss, 1 - Points, 2 - Win int character_id;
uint32 task_id;
int activity_id;
};
struct CZTaskActivityResetGroup_Struct {
int group_id;
uint32 task_id;
int activity_id;
};
struct CZTaskActivityResetRaid_Struct {
int raid_id;
uint32 task_id;
int activity_id;
};
struct CZTaskActivityResetGuild_Struct {
int guild_id;
uint32 task_id;
int activity_id;
};
struct CZTaskActivityUpdatePlayer_Struct {
int character_id;
uint32 task_id;
int activity_id;
int activity_count;
};
struct CZTaskActivityUpdateGroup_Struct {
int group_id;
uint32 task_id;
int activity_id;
int activity_count;
};
struct CZTaskActivityUpdateRaid_Struct {
int raid_id;
uint32 task_id;
int activity_id;
int activity_count;
};
struct CZTaskActivityUpdateGuild_Struct {
int guild_id;
uint32 task_id;
int activity_id;
int activity_count;
};
struct CZTaskAssignPlayer_Struct {
uint16 npc_entity_id;
int character_id;
uint32 task_id;
bool enforce_level_requirement;
};
struct CZTaskAssignGroup_Struct {
uint16 npc_entity_id;
int group_id;
uint32 task_id;
bool enforce_level_requirement;
};
struct CZTaskAssignRaid_Struct {
uint16 npc_entity_id;
int raid_id;
uint32 task_id;
bool enforce_level_requirement;
};
struct CZTaskAssignGuild_Struct {
uint16 npc_entity_id;
int guild_id;
uint32 task_id;
bool enforce_level_requirement;
};
struct CZTaskDisablePlayer_Struct {
int character_id;
uint32 task_id;
};
struct CZTaskDisableGroup_Struct {
int group_id;
uint32 task_id;
};
struct CZTaskDisableRaid_Struct {
int raid_id;
uint32 task_id;
};
struct CZTaskDisableGuild_Struct {
int guild_id;
uint32 task_id;
};
struct CZTaskEnablePlayer_Struct {
int character_id;
uint32 task_id;
};
struct CZTaskEnableGroup_Struct {
int group_id;
uint32 task_id;
};
struct CZTaskEnableRaid_Struct {
int raid_id;
uint32 task_id;
};
struct CZTaskEnableGuild_Struct {
int guild_id;
uint32 task_id;
};
struct CZTaskFailPlayer_Struct {
int character_id;
uint32 task_id;
};
struct CZTaskFailGroup_Struct {
int group_id;
uint32 task_id;
};
struct CZTaskFailRaid_Struct {
int raid_id;
uint32 task_id;
};
struct CZTaskFailGuild_Struct {
int guild_id;
uint32 task_id;
};
struct CZTaskRemovePlayer_Struct {
uint16 npc_entity_id;
int character_id;
uint32 task_id;
};
struct CZTaskRemoveGroup_Struct {
uint16 npc_entity_id;
int group_id;
uint32 task_id;
};
struct CZTaskRemoveRaid_Struct {
uint16 npc_entity_id;
int raid_id;
uint32 task_id;
};
struct CZTaskRemoveGuild_Struct {
uint16 npc_entity_id;
int guild_id;
uint32 task_id;
};
struct CZLDoNUpdate_Struct {
uint8 update_type; // 0 - Character, 1 - Group, 2 - Raid, 3 - Guild, 4 - Expedition
uint8 update_subtype; // 0 - Win, 1 - Loss, 2 - Points
int update_identifier; // Character ID, Group ID, Raid ID, Guild ID, or Expedition ID based on update type
uint32 theme_id; uint32 theme_id;
int points; // Only used in Points Subtype, else 1 int points; // Always 1, except for when Points are used
};
struct WWAssignTask_Struct {
uint16 npc_entity_id;
uint32 task_id;
bool enforce_level_requirement;
uint8 min_status; uint8 min_status;
uint8 max_status; uint8 max_status;
}; };
struct WWCastSpell_Struct {
uint32 spell_id;
uint8 min_status;
uint8 max_status;
};
struct WWDisableTask_Struct {
uint32 task_id;
uint8 min_status;
uint8 max_status;
};
struct WWEnableTask_Struct {
uint32 task_id;
uint8 min_status;
uint8 max_status;
};
struct WWFailTask_Struct {
uint32 task_id;
uint8 min_status;
uint8 max_status;
};
struct WWMarquee_Struct { struct WWMarquee_Struct {
uint32 type; uint32 type;
uint32 priority; uint32 priority;
@@ -1558,41 +1942,63 @@ struct WWMessage_Struct {
}; };
struct WWMove_Struct { struct WWMove_Struct {
uint8 update_type; // 0 - Move Zone, 1 - Move Zone Instance char zone_short_name[32];
char zone_short_name[32]; // Used with Move Zone
uint16 instance_id; // Used with Move Zone Instance
uint8 min_status; uint8 min_status;
uint8 max_status; uint8 max_status;
}; };
struct WWSetEntityVariable_Struct { struct WWMoveInstance_Struct {
uint8 update_type; // 0 - Character, 1 - NPC uint16 instance_id;
uint8 min_status;
uint8 max_status;
};
struct WWRemoveSpell_Struct {
uint32 spell_id;
uint8 min_status;
uint8 max_status;
};
struct WWRemoveTask_Struct {
uint32 task_id;
uint8 min_status;
uint8 max_status;
};
struct WWResetActivity_Struct {
uint32 task_id;
int activity_id;
uint8 min_status;
uint8 max_status;
};
struct WWSetEntVarClient_Struct {
char variable_name[256]; char variable_name[256];
char variable_value[256]; char variable_value[256];
uint8 min_status; uint8 min_status;
uint8 max_status; uint8 max_status;
}; };
struct WWSignal_Struct { struct WWSetEntVarNPC_Struct {
uint8 update_type; // 0 - Character, 1 - NPC char variable_name[256];
char variable_value[256];
};
struct WWSignalClient_Struct {
uint32 signal; uint32 signal;
uint8 min_status; uint8 min_status;
uint8 max_status; uint8 max_status;
}; };
struct WWSpell_Struct { struct WWSignalNPC_Struct {
uint8 update_type; // 0 - Cast Spell, 1 - Remove Spell uint32 signal;
uint32 spell_id;
uint8 min_status;
uint8 max_status;
}; };
struct WWTaskUpdate_Struct { struct WWUpdateActivity_Struct {
uint8 update_type; // 0 - Activity Reset, 1 - Activity Update, 2 - Assign Task, 3 - Disable Task, 4 - Enable Task, 5 - Fail Task, 6 - Remove Task uint32 task_id;
uint32 task_identifier; int activity_id;
int task_subidentifier; // Activity ID for Activity Reset and Activity Update, NPC Entity ID for Assign Task, else -1 int activity_count;
int update_count; // Update Count for Activity Update, else 1
bool enforce_level_requirement; // Only used by Assign Task, else false
uint8 min_status; uint8 min_status;
uint8 max_status; uint8 max_status;
}; };
+58 -59
View File
@@ -1118,7 +1118,7 @@ void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_
item.Haste = (uint32)atoul(row[ItemField::haste]); item.Haste = (uint32)atoul(row[ItemField::haste]);
item.DamageShield = (uint32)atoul(row[ItemField::damageshield]); item.DamageShield = (uint32)atoul(row[ItemField::damageshield]);
item.RecastDelay = (uint32)atoul(row[ItemField::recastdelay]); item.RecastDelay = (uint32)atoul(row[ItemField::recastdelay]);
item.RecastType = (int)atoi(row[ItemField::recasttype]); item.RecastType = (uint32)atoul(row[ItemField::recasttype]);
item.GuildFavor = (uint32)atoul(row[ItemField::guildfavor]); item.GuildFavor = (uint32)atoul(row[ItemField::guildfavor]);
item.AugDistiller = (uint32)atoul(row[ItemField::augdistiller]); item.AugDistiller = (uint32)atoul(row[ItemField::augdistiller]);
item.Attuneable = (atoi(row[ItemField::attuneable]) == 0) ? false : true; item.Attuneable = (atoi(row[ItemField::attuneable]) == 0) ? false : true;
@@ -1682,7 +1682,7 @@ void SharedDatabase::LoadDamageShieldTypes(SPDat_Spell_Struct* sp, int32 iMaxSpe
for(auto row = results.begin(); row != results.end(); ++row) { for(auto row = results.begin(); row != results.end(); ++row) {
int spellID = atoi(row[0]); int spellID = atoi(row[0]);
if((spellID > 0) && (spellID <= iMaxSpellID)) if((spellID > 0) && (spellID <= iMaxSpellID))
sp[spellID].damage_shield_type = atoi(row[1]); sp[spellID].DamageShieldType = atoi(row[1]);
} }
} }
@@ -1762,48 +1762,48 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
strn0cpy(sp[tempid].spell_fades, row[8], sizeof(sp[tempid].spell_fades)); strn0cpy(sp[tempid].spell_fades, row[8], sizeof(sp[tempid].spell_fades));
sp[tempid].range=static_cast<float>(atof(row[9])); sp[tempid].range=static_cast<float>(atof(row[9]));
sp[tempid].aoe_range=static_cast<float>(atof(row[10])); sp[tempid].aoerange=static_cast<float>(atof(row[10]));
sp[tempid].push_back=static_cast<float>(atof(row[11])); sp[tempid].pushback=static_cast<float>(atof(row[11]));
sp[tempid].push_up=static_cast<float>(atof(row[12])); sp[tempid].pushup=static_cast<float>(atof(row[12]));
sp[tempid].cast_time=atoi(row[13]); sp[tempid].cast_time=atoi(row[13]);
sp[tempid].recovery_time=atoi(row[14]); sp[tempid].recovery_time=atoi(row[14]);
sp[tempid].recast_time=atoi(row[15]); sp[tempid].recast_time=atoi(row[15]);
sp[tempid].buff_duration_formula=atoi(row[16]); sp[tempid].buffdurationformula=atoi(row[16]);
sp[tempid].buff_duration=atoi(row[17]); sp[tempid].buffduration=atoi(row[17]);
sp[tempid].aoe_duration=atoi(row[18]); sp[tempid].AEDuration=atoi(row[18]);
sp[tempid].mana=atoi(row[19]); sp[tempid].mana=atoi(row[19]);
int y=0; int y=0;
for(y=0; y< EFFECT_COUNT;y++) for(y=0; y< EFFECT_COUNT;y++)
sp[tempid].base_value[y]=atoi(row[20+y]); // effect_base_value sp[tempid].base[y]=atoi(row[20+y]); // effect_base_value
for(y=0; y < EFFECT_COUNT; y++) for(y=0; y < EFFECT_COUNT; y++)
sp[tempid].limit_value[y]=atoi(row[32+y]); // effect_limit_value sp[tempid].base2[y]=atoi(row[32+y]); // effect_limit_value
for(y=0; y< EFFECT_COUNT;y++) for(y=0; y< EFFECT_COUNT;y++)
sp[tempid].max_value[y]=atoi(row[44+y]); sp[tempid].max[y]=atoi(row[44+y]);
for(y=0; y< 4;y++) for(y=0; y< 4;y++)
sp[tempid].component[y]=atoi(row[58+y]); sp[tempid].components[y]=atoi(row[58+y]);
for(y=0; y< 4;y++) for(y=0; y< 4;y++)
sp[tempid].component_count[y]=atoi(row[62+y]); sp[tempid].component_counts[y]=atoi(row[62+y]);
for(y=0; y< 4;y++) for(y=0; y< 4;y++)
sp[tempid].no_expend_reagent[y]=atoi(row[66+y]); sp[tempid].NoexpendReagent[y]=atoi(row[66+y]);
for(y=0; y< EFFECT_COUNT;y++) for(y=0; y< EFFECT_COUNT;y++)
sp[tempid].formula[y]=atoi(row[70+y]); sp[tempid].formula[y]=atoi(row[70+y]);
sp[tempid].good_effect=atoi(row[83]); sp[tempid].goodEffect=atoi(row[83]);
sp[tempid].activated=atoi(row[84]); sp[tempid].Activated=atoi(row[84]);
sp[tempid].resist_type=atoi(row[85]); sp[tempid].resisttype=atoi(row[85]);
for(y=0; y< EFFECT_COUNT;y++) for(y=0; y< EFFECT_COUNT;y++)
sp[tempid].effect_id[y]=atoi(row[86+y]); sp[tempid].effectid[y]=atoi(row[86+y]);
sp[tempid].target_type = (SpellTargetType) atoi(row[98]); sp[tempid].targettype = (SpellTargetType) atoi(row[98]);
sp[tempid].base_difficulty=atoi(row[99]); sp[tempid].basediff=atoi(row[99]);
int tmp_skill = atoi(row[100]);; int tmp_skill = atoi(row[100]);;
@@ -1812,15 +1812,15 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
else else
sp[tempid].skill = (EQ::skills::SkillType) tmp_skill; sp[tempid].skill = (EQ::skills::SkillType) tmp_skill;
sp[tempid].zone_type=atoi(row[101]); sp[tempid].zonetype=atoi(row[101]);
sp[tempid].environment_type=atoi(row[102]); sp[tempid].EnvironmentType=atoi(row[102]);
sp[tempid].time_of_day=atoi(row[103]); sp[tempid].TimeOfDay=atoi(row[103]);
for(y=0; y < PLAYER_CLASS_COUNT;y++) for(y=0; y < PLAYER_CLASS_COUNT;y++)
sp[tempid].classes[y]=atoi(row[104+y]); sp[tempid].classes[y]=atoi(row[104+y]);
sp[tempid].casting_animation=atoi(row[120]); sp[tempid].CastingAnim=atoi(row[120]);
sp[tempid].spell_affect_index=atoi(row[123]); sp[tempid].SpellAffectIndex=atoi(row[123]);
sp[tempid].disallow_sit=atoi(row[124]); sp[tempid].disallow_sit=atoi(row[124]);
sp[tempid].deity_agnostic=atoi(row[125]); sp[tempid].deity_agnostic=atoi(row[125]);
@@ -1829,32 +1829,31 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
sp[tempid].new_icon=atoi(row[144]); sp[tempid].new_icon=atoi(row[144]);
sp[tempid].uninterruptable=atoi(row[146]) != 0; sp[tempid].uninterruptable=atoi(row[146]) != 0;
sp[tempid].resist_difficulty=atoi(row[147]); sp[tempid].ResistDiff=atoi(row[147]);
sp[tempid].unstackable_dot = atoi(row[148]) != 0; sp[tempid].dot_stacking_exempt = atoi(row[148]) != 0;
sp[tempid].recourse_link = atoi(row[150]); sp[tempid].RecourseLink = atoi(row[150]);
sp[tempid].no_partial_resist = atoi(row[151]) != 0; sp[tempid].no_partial_resist = atoi(row[151]) != 0;
sp[tempid].short_buff_box = atoi(row[154]); sp[tempid].short_buff_box = atoi(row[154]);
sp[tempid].description_id = atoi(row[155]); sp[tempid].descnum = atoi(row[155]);
sp[tempid].type_description_id = atoi(row[156]); sp[tempid].typedescnum = atoi(row[156]);
sp[tempid].effect_description_id = atoi(row[157]); sp[tempid].effectdescnum = atoi(row[157]);
sp[tempid].npc_no_los = atoi(row[159]) != 0; sp[tempid].npc_no_los = atoi(row[159]) != 0;
sp[tempid].feedbackable = atoi(row[160]) != 0;
sp[tempid].reflectable = atoi(row[161]) != 0; sp[tempid].reflectable = atoi(row[161]) != 0;
sp[tempid].bonus_hate=atoi(row[162]); sp[tempid].bonushate=atoi(row[162]);
sp[tempid].ldon_trap = atoi(row[165]) != 0; sp[tempid].ldon_trap = atoi(row[165]) != 0;
sp[tempid].endurance_cost=atoi(row[166]); sp[tempid].EndurCost=atoi(row[166]);
sp[tempid].timer_id=atoi(row[167]); sp[tempid].EndurTimerIndex=atoi(row[167]);
sp[tempid].is_discipline = atoi(row[168]) != 0; sp[tempid].IsDisciplineBuff = atoi(row[168]) != 0;
sp[tempid].hate_added=atoi(row[173]); sp[tempid].HateAdded=atoi(row[173]);
sp[tempid].endurance_upkeep=atoi(row[174]); sp[tempid].EndurUpkeep=atoi(row[174]);
sp[tempid].hit_number_type = atoi(row[175]); sp[tempid].numhitstype = atoi(row[175]);
sp[tempid].hit_number = atoi(row[176]); sp[tempid].numhits = atoi(row[176]);
sp[tempid].pvp_resist_base=atoi(row[177]); sp[tempid].pvpresistbase=atoi(row[177]);
sp[tempid].pvp_resist_per_level=atoi(row[178]); sp[tempid].pvpresistcalc=atoi(row[178]);
sp[tempid].pvp_resist_cap=atoi(row[179]); sp[tempid].pvpresistcap=atoi(row[179]);
sp[tempid].spell_category=atoi(row[180]); sp[tempid].spell_category=atoi(row[180]);
sp[tempid].pvp_duration = atoi(row[181]); sp[tempid].pvp_duration = atoi(row[181]);
sp[tempid].pvp_duration_cap = atoi(row[182]); sp[tempid].pvp_duration_cap = atoi(row[182]);
@@ -1862,11 +1861,11 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
sp[tempid].cast_not_standing = atoi(row[184]) != 0; sp[tempid].cast_not_standing = atoi(row[184]) != 0;
sp[tempid].can_mgb=atoi(row[185]); sp[tempid].can_mgb=atoi(row[185]);
sp[tempid].dispel_flag = atoi(row[186]); sp[tempid].dispel_flag = atoi(row[186]);
sp[tempid].min_resist = atoi(row[189]); sp[tempid].MinResist = atoi(row[189]);
sp[tempid].max_resist = atoi(row[190]); sp[tempid].MaxResist = atoi(row[190]);
sp[tempid].viral_targets = atoi(row[191]); sp[tempid].viral_targets = atoi(row[191]);
sp[tempid].viral_timer = atoi(row[192]); sp[tempid].viral_timer = atoi(row[192]);
sp[tempid].nimbus_effect = atoi(row[193]); sp[tempid].NimbusEffect = atoi(row[193]);
sp[tempid].directional_start = static_cast<float>(atoi(row[194])); sp[tempid].directional_start = static_cast<float>(atoi(row[194]));
sp[tempid].directional_end = static_cast<float>(atoi(row[195])); sp[tempid].directional_end = static_cast<float>(atoi(row[195]));
sp[tempid].sneak = atoi(row[196]) != 0; sp[tempid].sneak = atoi(row[196]) != 0;
@@ -1874,29 +1873,29 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
sp[tempid].no_detrimental_spell_aggro = atoi(row[198]) != 0; sp[tempid].no_detrimental_spell_aggro = atoi(row[198]) != 0;
sp[tempid].suspendable = atoi(row[200]) != 0; sp[tempid].suspendable = atoi(row[200]) != 0;
sp[tempid].viral_range = atoi(row[201]); sp[tempid].viral_range = atoi(row[201]);
sp[tempid].song_cap = atoi(row[202]); sp[tempid].songcap = atoi(row[202]);
sp[tempid].no_block = atoi(row[205]); sp[tempid].no_block = atoi(row[205]);
sp[tempid].spell_group=atoi(row[207]); sp[tempid].spellgroup=atoi(row[207]);
sp[tempid].rank = atoi(row[208]); sp[tempid].rank = atoi(row[208]);
sp[tempid].no_resist=atoi(row[209]); sp[tempid].no_resist=atoi(row[209]);
sp[tempid].cast_restriction = atoi(row[211]); sp[tempid].CastRestriction = atoi(row[211]);
sp[tempid].allow_rest = atoi(row[212]) != 0; sp[tempid].AllowRest = atoi(row[212]) != 0;
sp[tempid].can_cast_in_combat = atoi(row[213]) != 0; sp[tempid].InCombat = atoi(row[213]) != 0;
sp[tempid].can_cast_out_of_combat = atoi(row[214]) != 0; sp[tempid].OutofCombat = atoi(row[214]) != 0;
sp[tempid].override_crit_chance = atoi(row[217]); sp[tempid].override_crit_chance = atoi(row[217]);
sp[tempid].aoe_max_targets = atoi(row[218]); sp[tempid].aemaxtargets = atoi(row[218]);
sp[tempid].no_heal_damage_item_mod = atoi(row[219]); sp[tempid].no_heal_damage_item_mod = atoi(row[219]);
sp[tempid].caster_requirement_id = atoi(row[220]); sp[tempid].caster_requirement_id = atoi(row[220]);
sp[tempid].spell_class = atoi(row[221]); sp[tempid].spell_class = atoi(row[221]);
sp[tempid].spell_subclass = atoi(row[222]); sp[tempid].spell_subclass = atoi(row[222]);
sp[tempid].persist_death = atoi(row[224]) != 0; sp[tempid].persistdeath = atoi(row[224]) != 0;
sp[tempid].min_distance = atof(row[227]); sp[tempid].min_dist = atof(row[227]);
sp[tempid].min_distance_mod = atof(row[228]); sp[tempid].min_dist_mod = atof(row[228]);
sp[tempid].max_distance = atof(row[229]); sp[tempid].max_dist = atof(row[229]);
sp[tempid].max_distance_mod = atof(row[230]); sp[tempid].max_dist_mod = atof(row[230]);
sp[tempid].min_range = static_cast<float>(atoi(row[231])); sp[tempid].min_range = static_cast<float>(atoi(row[231]));
sp[tempid].no_remove = atoi(row[232]) != 0; sp[tempid].no_remove = atoi(row[232]) != 0;
sp[tempid].damage_shield_type = 0; sp[tempid].DamageShieldType = 0;
} }
LoadDamageShieldTypes(sp, max_spells); LoadDamageShieldTypes(sp, max_spells);
+96 -10
View File
@@ -177,7 +177,8 @@ bool EQ::skills::IsMeleeDmg(SkillType skill)
const std::map<EQ::skills::SkillType, std::string>& EQ::skills::GetSkillTypeMap() const std::map<EQ::skills::SkillType, std::string>& EQ::skills::GetSkillTypeMap()
{ {
static const std::map<SkillType, std::string> skill_type_map = { /* VS2013 code
static const std::map<SkillUseTypes, std::string> skill_use_types_map = {
{ Skill1HBlunt, "1H Blunt" }, { Skill1HBlunt, "1H Blunt" },
{ Skill1HSlashing, "1H Slashing" }, { Skill1HSlashing, "1H Slashing" },
{ Skill2HBlunt, "2H Blunt" }, { Skill2HBlunt, "2H Blunt" },
@@ -257,16 +258,101 @@ const std::map<EQ::skills::SkillType, std::string>& EQ::skills::GetSkillTypeMap(
{ SkillTripleAttack, "Triple Attack" }, { SkillTripleAttack, "Triple Attack" },
{ Skill2HPiercing, "2H Piercing" } { Skill2HPiercing, "2H Piercing" }
}; };
return skill_type_map; */
}
std::string EQ::skills::GetSkillName(SkillType skill) /* VS2012 code - begin */
{
if (skill >= Skill1HBlunt && skill <= Skill2HPiercing) { static const char* skill_use_names[SkillCount] = {
auto skills = GetSkillTypeMap(); "1H Blunt",
return skills[skill]; "1H Slashing",
} "2H Blunt",
return std::string(); "2H Slashing",
"Abjuration",
"Alteration",
"Apply Poison",
"Archery",
"Backstab",
"Bind Wound",
"Bash",
"Block",
"Brass Instruments",
"Channeling",
"Conjuration",
"Defense",
"Disarm",
"Disarm Traps",
"Divination",
"Dodge",
"Double Attack",
"Dragon Punch",
"Dual Wield",
"Eagle Strike",
"Evocation",
"Feign Death",
"Flying Kick",
"Forage",
"Hand to Hand",
"Hide",
"Kick",
"Meditate",
"Mend",
"Offense",
"Parry",
"Pick Lock",
"1H Piercing",
"Riposte",
"Round Kick",
"Safe Fall",
"Sense Heading",
"Singing",
"Sneak",
"Specialize Abjuration",
"Specialize Alteration",
"Specialize Conjuration",
"Specialize Divination",
"Specialize Evocation",
"Pick Pockets",
"Stringed Instruments",
"Swimming",
"Throwing",
"Tiger Claw",
"Tracking",
"Wind Instruments",
"Fishing",
"Make Poison",
"Tinkering",
"Research",
"Alchemy",
"Baking",
"Tailoring",
"Sense Traps",
"Blacksmithing",
"Fletching",
"Brewing",
"Alcohol Tolerance",
"Begging",
"Jewelry Making",
"Pottery",
"Percussion Instruments",
"Intimidation",
"Berserking",
"Taunt",
"Frenzy",
"Remove Traps",
"Triple Attack",
"2H Piercing"
};
static std::map<SkillType, std::string> skill_type_map;
skill_type_map.clear();
for (int i = Skill1HBlunt; i < SkillCount; ++i)
skill_type_map[(SkillType)i] = skill_use_names[i];
/* VS2012 code - end */
return skill_type_map;
} }
EQ::SkillProfile::SkillProfile() EQ::SkillProfile::SkillProfile()
-1
View File
@@ -171,7 +171,6 @@ namespace EQ
extern const std::map<SkillType, std::string>& GetSkillTypeMap(); extern const std::map<SkillType, std::string>& GetSkillTypeMap();
std::string GetSkillName(SkillType skill);
} /*skills*/ } /*skills*/
struct SkillProfile { // prototype - not implemented struct SkillProfile { // prototype - not implemented
+162 -325
View File
@@ -87,7 +87,7 @@
bool IsTargetableAESpell(uint16 spell_id) bool IsTargetableAESpell(uint16 spell_id)
{ {
if (IsValidSpell(spell_id) && spells[spell_id].target_type == ST_AETarget) { if (IsValidSpell(spell_id) && spells[spell_id].targettype == ST_AETarget) {
return true; return true;
} }
@@ -103,8 +103,8 @@ bool IsLifetapSpell(uint16 spell_id)
{ {
// Ancient Lifebane: 2115 // Ancient Lifebane: 2115
if (IsValidSpell(spell_id) && if (IsValidSpell(spell_id) &&
(spells[spell_id].target_type == ST_Tap || (spells[spell_id].targettype == ST_Tap ||
spells[spell_id].target_type == ST_TargetAETap || spells[spell_id].targettype == ST_TargetAETap ||
spell_id == 2115)) spell_id == 2115))
return true; return true;
@@ -124,7 +124,7 @@ bool IsStunSpell(uint16 spell_id)
bool IsSummonSpell(uint16 spellid) bool IsSummonSpell(uint16 spellid)
{ {
for (int o = 0; o < EFFECT_COUNT; o++) { for (int o = 0; o < EFFECT_COUNT; o++) {
uint32 tid = spells[spellid].effect_id[o]; uint32 tid = spells[spellid].effectid[o];
if (tid == SE_SummonPet || tid == SE_SummonItem || tid == SE_SummonPC) if (tid == SE_SummonPet || tid == SE_SummonItem || tid == SE_SummonPC)
return true; return true;
} }
@@ -140,10 +140,10 @@ bool IsEvacSpell(uint16 spellid)
bool IsDamageSpell(uint16 spellid) bool IsDamageSpell(uint16 spellid)
{ {
for (int o = 0; o < EFFECT_COUNT; o++) { for (int o = 0; o < EFFECT_COUNT; o++) {
uint32 tid = spells[spellid].effect_id[o]; uint32 tid = spells[spellid].effectid[o];
if ((tid == SE_CurrentHPOnce || tid == SE_CurrentHP) && if ((tid == SE_CurrentHPOnce || tid == SE_CurrentHP) &&
spells[spellid].target_type != ST_Tap && spells[spellid].buff_duration < 1 && spells[spellid].targettype != ST_Tap && spells[spellid].buffduration < 1 &&
spells[spellid].base_value[o] < 0) spells[spellid].base[o] < 0)
return true; return true;
} }
@@ -163,8 +163,8 @@ bool IsCureSpell(uint16 spell_id)
bool CureEffect = false; bool CureEffect = false;
for(int i = 0; i < EFFECT_COUNT; i++){ for(int i = 0; i < EFFECT_COUNT; i++){
if (sp.effect_id[i] == SE_DiseaseCounter || sp.effect_id[i] == SE_PoisonCounter if (sp.effectid[i] == SE_DiseaseCounter || sp.effectid[i] == SE_PoisonCounter
|| sp.effect_id[i] == SE_CurseCounter || sp.effect_id[i] == SE_CorruptionCounter) || sp.effectid[i] == SE_CurseCounter || sp.effectid[i] == SE_CorruptionCounter)
CureEffect = true; CureEffect = true;
} }
@@ -179,8 +179,8 @@ bool IsSlowSpell(uint16 spell_id)
const SPDat_Spell_Struct &sp = spells[spell_id]; const SPDat_Spell_Struct &sp = spells[spell_id];
for(int i = 0; i < EFFECT_COUNT; i++) for(int i = 0; i < EFFECT_COUNT; i++)
if ((sp.effect_id[i] == SE_AttackSpeed && sp.base_value[i] < 100) || if ((sp.effectid[i] == SE_AttackSpeed && sp.base[i] < 100) ||
(sp.effect_id[i] == SE_AttackSpeed4)) (sp.effectid[i] == SE_AttackSpeed4))
return true; return true;
return false; return false;
@@ -191,8 +191,8 @@ bool IsHasteSpell(uint16 spell_id)
const SPDat_Spell_Struct &sp = spells[spell_id]; const SPDat_Spell_Struct &sp = spells[spell_id];
for(int i = 0; i < EFFECT_COUNT; i++) for(int i = 0; i < EFFECT_COUNT; i++)
if(sp.effect_id[i] == SE_AttackSpeed) if(sp.effectid[i] == SE_AttackSpeed)
return (sp.base_value[i] < 100); return (sp.base[i] < 100);
return false; return false;
} }
@@ -210,7 +210,7 @@ bool IsPercentalHealSpell(uint16 spell_id)
bool IsGroupOnlySpell(uint16 spell_id) bool IsGroupOnlySpell(uint16 spell_id)
{ {
return IsValidSpell(spell_id) && spells[spell_id].good_effect == 2; return IsValidSpell(spell_id) && spells[spell_id].goodEffect == 2;
} }
bool IsBeneficialSpell(uint16 spell_id) bool IsBeneficialSpell(uint16 spell_id)
@@ -219,10 +219,10 @@ bool IsBeneficialSpell(uint16 spell_id)
return false; return false;
// You'd think just checking goodEffect flag would be enough? // You'd think just checking goodEffect flag would be enough?
if (spells[spell_id].good_effect == 1) { if (spells[spell_id].goodEffect == 1) {
// If the target type is ST_Self or ST_Pet and is a SE_CancleMagic spell // If the target type is ST_Self or ST_Pet and is a SE_CancleMagic spell
// it is not Beneficial // it is not Beneficial
SpellTargetType tt = spells[spell_id].target_type; SpellTargetType tt = spells[spell_id].targettype;
if (tt != ST_Self && tt != ST_Pet && if (tt != ST_Self && tt != ST_Pet &&
IsEffectInSpell(spell_id, SE_CancelMagic)) IsEffectInSpell(spell_id, SE_CancelMagic))
return false; return false;
@@ -231,14 +231,14 @@ bool IsBeneficialSpell(uint16 spell_id)
// We need to check more things! // We need to check more things!
if (tt == ST_Target || tt == ST_AETarget || tt == ST_Animal || if (tt == ST_Target || tt == ST_AETarget || tt == ST_Animal ||
tt == ST_Undead || tt == ST_Pet) { tt == ST_Undead || tt == ST_Pet) {
uint16 sai = spells[spell_id].spell_affect_index; uint16 sai = spells[spell_id].SpellAffectIndex;
// If the resisttype is magic and SpellAffectIndex is Calm/memblur/dispell sight // If the resisttype is magic and SpellAffectIndex is Calm/memblur/dispell sight
// it's not beneficial // it's not beneficial
if (spells[spell_id].resist_type == RESIST_MAGIC) { if (spells[spell_id].resisttype == RESIST_MAGIC) {
// checking these SAI cause issues with the rng defensive proc line // checking these SAI cause issues with the rng defensive proc line
// So I guess instead of fixing it for real, just a quick hack :P // So I guess instead of fixing it for real, just a quick hack :P
if (spells[spell_id].effect_id[0] != SE_DefensiveProc && if (spells[spell_id].effectid[0] != SE_DefensiveProc &&
(sai == SAI_Calm || sai == SAI_Dispell_Sight || sai == SAI_Memory_Blur || (sai == SAI_Calm || sai == SAI_Dispell_Sight || sai == SAI_Memory_Blur ||
sai == SAI_Calm_Song)) sai == SAI_Calm_Song))
return false; return false;
@@ -252,7 +252,7 @@ bool IsBeneficialSpell(uint16 spell_id)
} }
// And finally, if goodEffect is not 0 or if it's a group spell it's beneficial // And finally, if goodEffect is not 0 or if it's a group spell it's beneficial
return spells[spell_id].good_effect != 0 || IsGroupSpell(spell_id); return spells[spell_id].goodEffect != 0 || IsGroupSpell(spell_id);
} }
bool IsDetrimentalSpell(uint16 spell_id) bool IsDetrimentalSpell(uint16 spell_id)
@@ -364,8 +364,8 @@ bool IsImprovedDamageSpell(uint16 spell_id)
bool IsAEDurationSpell(uint16 spell_id) bool IsAEDurationSpell(uint16 spell_id)
{ {
if (IsValidSpell(spell_id) && if (IsValidSpell(spell_id) &&
(spells[spell_id].target_type == ST_AETarget || spells[spell_id].target_type == ST_UndeadAE) && (spells[spell_id].targettype == ST_AETarget || spells[spell_id].targettype == ST_UndeadAE) &&
spells[spell_id].aoe_duration != 0) spells[spell_id].AEDuration != 0)
return true; return true;
return false; return false;
@@ -383,7 +383,7 @@ bool IsPureNukeSpell(uint16 spell_id)
effect_count++; effect_count++;
if (effect_count == 1 && IsEffectInSpell(spell_id, SE_CurrentHP) && if (effect_count == 1 && IsEffectInSpell(spell_id, SE_CurrentHP) &&
spells[spell_id].buff_duration == 0 && IsDamageSpell(spell_id)) spells[spell_id].buffduration == 0 && IsDamageSpell(spell_id))
return true; return true;
return false; return false;
@@ -392,7 +392,7 @@ bool IsPureNukeSpell(uint16 spell_id)
bool IsAENukeSpell(uint16 spell_id) bool IsAENukeSpell(uint16 spell_id)
{ {
if (IsValidSpell(spell_id) && IsPureNukeSpell(spell_id) && if (IsValidSpell(spell_id) && IsPureNukeSpell(spell_id) &&
spells[spell_id].aoe_range > 0) spells[spell_id].aoerange > 0)
return true; return true;
return false; return false;
@@ -401,7 +401,7 @@ bool IsAENukeSpell(uint16 spell_id)
bool IsPBAENukeSpell(uint16 spell_id) bool IsPBAENukeSpell(uint16 spell_id)
{ {
if (IsValidSpell(spell_id) && IsPureNukeSpell(spell_id) && if (IsValidSpell(spell_id) && IsPureNukeSpell(spell_id) &&
spells[spell_id].aoe_range > 0 && spells[spell_id].target_type == ST_AECaster) spells[spell_id].aoerange > 0 && spells[spell_id].targettype == ST_AECaster)
return true; return true;
return false; return false;
@@ -410,7 +410,7 @@ bool IsPBAENukeSpell(uint16 spell_id)
bool IsAERainNukeSpell(uint16 spell_id) bool IsAERainNukeSpell(uint16 spell_id)
{ {
if (IsValidSpell(spell_id) && IsPureNukeSpell(spell_id) && if (IsValidSpell(spell_id) && IsPureNukeSpell(spell_id) &&
spells[spell_id].aoe_range > 0 && spells[spell_id].aoe_duration > 1000) spells[spell_id].aoerange > 0 && spells[spell_id].AEDuration > 1000)
return true; return true;
return false; return false;
@@ -424,12 +424,12 @@ bool IsPartialCapableSpell(uint16 spell_id)
// spell uses 600 (partial) scale if first effect is damage, else it uses 200 scale. // spell uses 600 (partial) scale if first effect is damage, else it uses 200 scale.
// this includes DoTs. no_partial_resist excludes spells like necro snares // this includes DoTs. no_partial_resist excludes spells like necro snares
for (int o = 0; o < EFFECT_COUNT; o++) { for (int o = 0; o < EFFECT_COUNT; o++) {
auto tid = spells[spell_id].effect_id[o]; auto tid = spells[spell_id].effectid[o];
if (IsBlankSpellEffect(spell_id, o)) if (IsBlankSpellEffect(spell_id, o))
continue; continue;
if ((tid == SE_CurrentHPOnce || tid == SE_CurrentHP) && spells[spell_id].base_value[o] < 0) if ((tid == SE_CurrentHPOnce || tid == SE_CurrentHP) && spells[spell_id].base[o] < 0)
return true; return true;
return false; return false;
@@ -452,9 +452,9 @@ bool IsResistableSpell(uint16 spell_id)
bool IsGroupSpell(uint16 spell_id) bool IsGroupSpell(uint16 spell_id)
{ {
if (IsValidSpell(spell_id) && if (IsValidSpell(spell_id) &&
(spells[spell_id].target_type == ST_AEBard || (spells[spell_id].targettype == ST_AEBard ||
spells[spell_id].target_type == ST_Group || spells[spell_id].targettype == ST_Group ||
spells[spell_id].target_type == ST_GroupTeleport)) spells[spell_id].targettype == ST_GroupTeleport))
return true; return true;
return false; return false;
@@ -464,7 +464,7 @@ bool IsGroupSpell(uint16 spell_id)
bool IsTGBCompatibleSpell(uint16 spell_id) bool IsTGBCompatibleSpell(uint16 spell_id)
{ {
if (IsValidSpell(spell_id) && if (IsValidSpell(spell_id) &&
(!IsDetrimentalSpell(spell_id) && spells[spell_id].buff_duration != 0 && (!IsDetrimentalSpell(spell_id) && spells[spell_id].buffduration != 0 &&
!IsBardSong(spell_id) && !IsEffectInSpell(spell_id, SE_Illusion))) !IsBardSong(spell_id) && !IsEffectInSpell(spell_id, SE_Illusion)))
return true; return true;
@@ -473,7 +473,7 @@ bool IsTGBCompatibleSpell(uint16 spell_id)
bool IsBardSong(uint16 spell_id) bool IsBardSong(uint16 spell_id)
{ {
if (IsValidSpell(spell_id) && spells[spell_id].classes[BARD - 1] < 255 && !spells[spell_id].is_discipline) if (IsValidSpell(spell_id) && spells[spell_id].classes[BARD - 1] < 255 && !spells[spell_id].IsDisciplineBuff)
return true; return true;
return false; return false;
@@ -487,7 +487,7 @@ bool IsEffectInSpell(uint16 spellid, int effect)
return false; return false;
for (j = 0; j < EFFECT_COUNT; j++) for (j = 0; j < EFFECT_COUNT; j++)
if (spells[spellid].effect_id[j] == effect) if (spells[spellid].effectid[j] == effect)
return true; return true;
return false; return false;
@@ -498,15 +498,15 @@ bool IsEffectInSpell(uint16 spellid, int effect)
// the blanks // the blanks
bool IsBlankSpellEffect(uint16 spellid, int effect_index) bool IsBlankSpellEffect(uint16 spellid, int effect_index)
{ {
int effect, base_value, formula; int effect, base, formula;
effect = spells[spellid].effect_id[effect_index]; effect = spells[spellid].effectid[effect_index];
base_value = spells[spellid].base_value[effect_index]; base = spells[spellid].base[effect_index];
formula = spells[spellid].formula[effect_index]; formula = spells[spellid].formula[effect_index];
// SE_CHA is "spacer" // SE_CHA is "spacer"
// SE_Stacking* are also considered blank where this is used // SE_Stacking* are also considered blank where this is used
if (effect == SE_Blank || (effect == SE_CHA && base_value == 0 && formula == 100) || if (effect == SE_Blank || (effect == SE_CHA && base == 0 && formula == 100) ||
effect == SE_StackingCommand_Block || effect == SE_StackingCommand_Overwrite) effect == SE_StackingCommand_Block || effect == SE_StackingCommand_Overwrite)
return true; return true;
@@ -561,7 +561,7 @@ int GetSpellEffectIndex(uint16 spell_id, int effect)
return -1; return -1;
for (i = 0; i < EFFECT_COUNT; i++) for (i = 0; i < EFFECT_COUNT; i++)
if (spells[spell_id].effect_id[i] == effect) if (spells[spell_id].effectid[i] == effect)
return i; return i;
return -1; return -1;
@@ -591,7 +591,7 @@ bool BeneficialSpell(uint16 spell_id)
/*|| spells[spell_id].stacking == 27*/ ) /*|| spells[spell_id].stacking == 27*/ )
return true; return true;
switch (spells[spell_id].good_effect) { switch (spells[spell_id].goodEffect) {
case 1: case 1:
case 3: case 3:
return true; return true;
@@ -602,7 +602,7 @@ bool BeneficialSpell(uint16 spell_id)
bool GroupOnlySpell(uint16 spell_id) bool GroupOnlySpell(uint16 spell_id)
{ {
switch (spells[spell_id].good_effect) { switch (spells[spell_id].goodEffect) {
case 2: case 2:
case 3: case 3:
return true; return true;
@@ -623,9 +623,9 @@ int32 CalculatePoisonCounters(uint16 spell_id)
int32 Counters = 0; int32 Counters = 0;
for (int i = 0; i < EFFECT_COUNT; i++) for (int i = 0; i < EFFECT_COUNT; i++)
if (spells[spell_id].effect_id[i] == SE_PoisonCounter && if (spells[spell_id].effectid[i] == SE_PoisonCounter &&
spells[spell_id].base_value[i] > 0) spells[spell_id].base[i] > 0)
Counters += spells[spell_id].base_value[i]; Counters += spells[spell_id].base[i];
return Counters; return Counters;
} }
@@ -637,9 +637,9 @@ int32 CalculateDiseaseCounters(uint16 spell_id)
int32 Counters = 0; int32 Counters = 0;
for (int i = 0; i < EFFECT_COUNT; i++) for (int i = 0; i < EFFECT_COUNT; i++)
if(spells[spell_id].effect_id[i] == SE_DiseaseCounter && if(spells[spell_id].effectid[i] == SE_DiseaseCounter &&
spells[spell_id].base_value[i] > 0) spells[spell_id].base[i] > 0)
Counters += spells[spell_id].base_value[i]; Counters += spells[spell_id].base[i];
return Counters; return Counters;
} }
@@ -651,9 +651,9 @@ int32 CalculateCurseCounters(uint16 spell_id)
int32 Counters = 0; int32 Counters = 0;
for (int i = 0; i < EFFECT_COUNT; i++) for (int i = 0; i < EFFECT_COUNT; i++)
if(spells[spell_id].effect_id[i] == SE_CurseCounter && if(spells[spell_id].effectid[i] == SE_CurseCounter &&
spells[spell_id].base_value[i] > 0) spells[spell_id].base[i] > 0)
Counters += spells[spell_id].base_value[i]; Counters += spells[spell_id].base[i];
return Counters; return Counters;
} }
@@ -665,9 +665,9 @@ int32 CalculateCorruptionCounters(uint16 spell_id)
int32 Counters = 0; int32 Counters = 0;
for (int i = 0; i < EFFECT_COUNT; i++) for (int i = 0; i < EFFECT_COUNT; i++)
if (spells[spell_id].effect_id[i] == SE_CorruptionCounter && if (spells[spell_id].effectid[i] == SE_CorruptionCounter &&
spells[spell_id].base_value[i] > 0) spells[spell_id].base[i] > 0)
Counters += spells[spell_id].base_value[i]; Counters += spells[spell_id].base[i];
return Counters; return Counters;
} }
@@ -695,7 +695,7 @@ bool IsDisciplineBuff(uint16 spell_id)
if (!IsValidSpell(spell_id)) if (!IsValidSpell(spell_id))
return false; return false;
if (spells[spell_id].is_discipline && spells[spell_id].target_type == ST_Self) if (spells[spell_id].IsDisciplineBuff && spells[spell_id].targettype == ST_Self)
return true; return true;
return false; return false;
@@ -707,7 +707,7 @@ bool IsDiscipline(uint16 spell_id)
return false; return false;
if (spells[spell_id].mana == 0 && if (spells[spell_id].mana == 0 &&
(spells[spell_id].endurance_cost || spells[spell_id].endurance_upkeep)) (spells[spell_id].EndurCost || spells[spell_id].EndurUpkeep))
return true; return true;
return false; return false;
@@ -719,7 +719,7 @@ bool IsCombatSkill(uint16 spell_id)
return false; return false;
//Check if Discipline //Check if Discipline
if ((spells[spell_id].mana == 0 && (spells[spell_id].endurance_cost || spells[spell_id].endurance_upkeep))) if ((spells[spell_id].mana == 0 && (spells[spell_id].EndurCost || spells[spell_id].EndurUpkeep)))
return true; return true;
return false; return false;
@@ -738,7 +738,7 @@ bool IsRuneSpell(uint16 spell_id)
{ {
if (IsValidSpell(spell_id)) if (IsValidSpell(spell_id))
for (int i = 0; i < EFFECT_COUNT; i++) for (int i = 0; i < EFFECT_COUNT; i++)
if (spells[spell_id].effect_id[i] == SE_Rune) if (spells[spell_id].effectid[i] == SE_Rune)
return true; return true;
return false; return false;
@@ -748,7 +748,7 @@ bool IsMagicRuneSpell(uint16 spell_id)
{ {
if(IsValidSpell(spell_id)) if(IsValidSpell(spell_id))
for(int i = 0; i < EFFECT_COUNT; i++) for(int i = 0; i < EFFECT_COUNT; i++)
if(spells[spell_id].effect_id[i] == SE_AbsorbMagicAtt) if(spells[spell_id].effectid[i] == SE_AbsorbMagicAtt)
return true; return true;
return false; return false;
@@ -758,8 +758,8 @@ bool IsManaTapSpell(uint16 spell_id)
{ {
if (IsValidSpell(spell_id)) if (IsValidSpell(spell_id))
for (int i = 0; i < EFFECT_COUNT; i++) for (int i = 0; i < EFFECT_COUNT; i++)
if (spells[spell_id].effect_id[i] == SE_CurrentMana && if (spells[spell_id].effectid[i] == SE_CurrentMana &&
spells[spell_id].target_type == ST_Tap) spells[spell_id].targettype == ST_Tap)
return true; return true;
return false; return false;
@@ -788,8 +788,8 @@ bool IsPartialDeathSaveSpell(uint16 spell_id)
return false; return false;
for (int i = 0; i < EFFECT_COUNT; i++) for (int i = 0; i < EFFECT_COUNT; i++)
if (spells[spell_id].effect_id[i] == SE_DeathSave && if (spells[spell_id].effectid[i] == SE_DeathSave &&
spells[spell_id].base_value[i] == 1) spells[spell_id].base[i] == 1)
return true; return true;
return false; return false;
@@ -802,8 +802,8 @@ bool IsFullDeathSaveSpell(uint16 spell_id)
return false; return false;
for (int i = 0; i < EFFECT_COUNT; i++) for (int i = 0; i < EFFECT_COUNT; i++)
if (spells[spell_id].effect_id[i] == SE_DeathSave && if (spells[spell_id].effectid[i] == SE_DeathSave &&
spells[spell_id].base_value[i] == 2) spells[spell_id].base[i] == 2)
return true; return true;
return false; return false;
@@ -833,14 +833,6 @@ bool IsTeleportSpell(uint16 spell_id)
return false; return false;
} }
bool IsTranslocateSpell(uint16 spell_id)
{
if (IsEffectInSpell(spell_id, SE_Translocate))
return true;
return false;
}
bool IsGateSpell(uint16 spell_id) bool IsGateSpell(uint16 spell_id)
{ {
if (IsEffectInSpell(spell_id, SE_Gate)) if (IsEffectInSpell(spell_id, SE_Gate))
@@ -852,7 +844,7 @@ bool IsGateSpell(uint16 spell_id)
bool IsPlayerIllusionSpell(uint16 spell_id) bool IsPlayerIllusionSpell(uint16 spell_id)
{ {
if (IsEffectInSpell(spell_id, SE_Illusion) && if (IsEffectInSpell(spell_id, SE_Illusion) &&
spells[spell_id].target_type == ST_Self) spells[spell_id].targettype == ST_Self)
return true; return true;
return false; return false;
@@ -861,7 +853,7 @@ bool IsPlayerIllusionSpell(uint16 spell_id)
int GetSpellEffectDescNum(uint16 spell_id) int GetSpellEffectDescNum(uint16 spell_id)
{ {
if (IsValidSpell(spell_id)) if (IsValidSpell(spell_id))
return spells[spell_id].effect_description_id; return spells[spell_id].effectdescnum;
return -1; return -1;
} }
@@ -872,12 +864,12 @@ DmgShieldType GetDamageShieldType(uint16 spell_id, int32 DSType)
// else, make a guess, based on the resist type. Default return value is DS_THORNS // else, make a guess, based on the resist type. Default return value is DS_THORNS
if (IsValidSpell(spell_id)) { if (IsValidSpell(spell_id)) {
LogSpells("DamageShieldType for spell [{}] ([{}]) is [{}]", spell_id, LogSpells("DamageShieldType for spell [{}] ([{}]) is [{}]", spell_id,
spells[spell_id].name, spells[spell_id].damage_shield_type); spells[spell_id].name, spells[spell_id].DamageShieldType);
if (spells[spell_id].damage_shield_type) if (spells[spell_id].DamageShieldType)
return (DmgShieldType) spells[spell_id].damage_shield_type; return (DmgShieldType) spells[spell_id].DamageShieldType;
switch (spells[spell_id].resist_type) { switch (spells[spell_id].resisttype) {
case RESIST_COLD: case RESIST_COLD:
return DS_TORMENT; return DS_TORMENT;
case RESIST_FIRE: case RESIST_FIRE:
@@ -907,12 +899,12 @@ bool IsLDoNObjectSpell(uint16 spell_id)
int32 GetSpellResistType(uint16 spell_id) int32 GetSpellResistType(uint16 spell_id)
{ {
return spells[spell_id].resist_type; return spells[spell_id].resisttype;
} }
int32 GetSpellTargetType(uint16 spell_id) int32 GetSpellTargetType(uint16 spell_id)
{ {
return (int32)spells[spell_id].target_type; return (int32)spells[spell_id].targettype;
} }
bool IsHealOverTimeSpell(uint16 spell_id) bool IsHealOverTimeSpell(uint16 spell_id)
@@ -937,7 +929,7 @@ bool IsFastHealSpell(uint16 spell_id)
const int MaxFastHealCastingTime = 2000; const int MaxFastHealCastingTime = 2000;
if (spells[spell_id].cast_time <= MaxFastHealCastingTime && if (spells[spell_id].cast_time <= MaxFastHealCastingTime &&
spells[spell_id].effect_id[0] == 0 && spells[spell_id].base_value[0] > 0 && spells[spell_id].effectid[0] == 0 && spells[spell_id].base[0] > 0 &&
!IsGroupSpell(spell_id)) !IsGroupSpell(spell_id))
return true; return true;
@@ -949,7 +941,7 @@ bool IsVeryFastHealSpell(uint16 spell_id)
const int MaxFastHealCastingTime = 1000; const int MaxFastHealCastingTime = 1000;
if (spells[spell_id].cast_time <= MaxFastHealCastingTime && if (spells[spell_id].cast_time <= MaxFastHealCastingTime &&
spells[spell_id].effect_id[0] == 0 && spells[spell_id].base_value[0] > 0 && spells[spell_id].effectid[0] == 0 && spells[spell_id].base[0] > 0 &&
!IsGroupSpell(spell_id)) !IsGroupSpell(spell_id))
return true; return true;
@@ -958,8 +950,8 @@ bool IsVeryFastHealSpell(uint16 spell_id)
bool IsRegularSingleTargetHealSpell(uint16 spell_id) bool IsRegularSingleTargetHealSpell(uint16 spell_id)
{ {
if(spells[spell_id].effect_id[0] == 0 && spells[spell_id].base_value[0] > 0 && if(spells[spell_id].effectid[0] == 0 && spells[spell_id].base[0] > 0 &&
spells[spell_id].target_type == ST_Target && spells[spell_id].buff_duration == 0 && spells[spell_id].targettype == ST_Target && spells[spell_id].buffduration == 0 &&
!IsCompleteHealSpell(spell_id) && !IsCompleteHealSpell(spell_id) &&
!IsHealOverTimeSpell(spell_id) && !IsGroupSpell(spell_id)) !IsHealOverTimeSpell(spell_id) && !IsGroupSpell(spell_id))
return true; return true;
@@ -985,7 +977,7 @@ bool IsGroupCompleteHealSpell(uint16 spell_id)
bool IsGroupHealOverTimeSpell(uint16 spell_id) bool IsGroupHealOverTimeSpell(uint16 spell_id)
{ {
if( IsGroupSpell(spell_id) && IsHealOverTimeSpell(spell_id) && spells[spell_id].buff_duration < 10) if( IsGroupSpell(spell_id) && IsHealOverTimeSpell(spell_id) && spells[spell_id].buffduration < 10)
return true; return true;
return false; return false;
@@ -1016,8 +1008,8 @@ bool IsResistDebuffSpell(uint16 spell_id)
bool IsSelfConversionSpell(uint16 spell_id) bool IsSelfConversionSpell(uint16 spell_id)
{ {
if (GetSpellTargetType(spell_id) == ST_Self && IsEffectInSpell(spell_id, SE_CurrentMana) && if (GetSpellTargetType(spell_id) == ST_Self && IsEffectInSpell(spell_id, SE_CurrentMana) &&
IsEffectInSpell(spell_id, SE_CurrentHP) && spells[spell_id].base_value[GetSpellEffectIndex(spell_id, SE_CurrentMana)] > 0 && IsEffectInSpell(spell_id, SE_CurrentHP) && spells[spell_id].base[GetSpellEffectIndex(spell_id, SE_CurrentMana)] > 0 &&
spells[spell_id].base_value[GetSpellEffectIndex(spell_id, SE_CurrentHP)] < 0) spells[spell_id].base[GetSpellEffectIndex(spell_id, SE_CurrentHP)] < 0)
return true; return true;
else else
return false; return false;
@@ -1026,7 +1018,7 @@ bool IsSelfConversionSpell(uint16 spell_id)
// returns true for both detrimental and beneficial buffs // returns true for both detrimental and beneficial buffs
bool IsBuffSpell(uint16 spell_id) bool IsBuffSpell(uint16 spell_id)
{ {
if (IsValidSpell(spell_id) && (spells[spell_id].buff_duration || spells[spell_id].buff_duration_formula)) if (IsValidSpell(spell_id) && (spells[spell_id].buffduration || spells[spell_id].buffdurationformula))
return true; return true;
return false; return false;
@@ -1034,7 +1026,7 @@ bool IsBuffSpell(uint16 spell_id)
bool IsPersistDeathSpell(uint16 spell_id) bool IsPersistDeathSpell(uint16 spell_id)
{ {
if (IsValidSpell(spell_id) && spells[spell_id].persist_death) if (IsValidSpell(spell_id) && spells[spell_id].persistdeath)
return true; return true;
return false; return false;
@@ -1051,8 +1043,8 @@ bool IsSuspendableSpell(uint16 spell_id)
uint32 GetMorphTrigger(uint32 spell_id) uint32 GetMorphTrigger(uint32 spell_id)
{ {
for (int i = 0; i < EFFECT_COUNT; ++i) for (int i = 0; i < EFFECT_COUNT; ++i)
if (spells[spell_id].effect_id[i] == SE_CastOnFadeEffect) if (spells[spell_id].effectid[i] == SE_CastOnFadeEffect)
return spells[spell_id].base_value[i]; return spells[spell_id].base[i];
return 0; return 0;
} }
@@ -1060,9 +1052,9 @@ uint32 GetMorphTrigger(uint32 spell_id)
bool IsCastonFadeDurationSpell(uint16 spell_id) bool IsCastonFadeDurationSpell(uint16 spell_id)
{ {
for (int i = 0; i < EFFECT_COUNT; ++i) { for (int i = 0; i < EFFECT_COUNT; ++i) {
if (spells[spell_id].effect_id[i] == SE_CastOnFadeEffect if (spells[spell_id].effectid[i] == SE_CastOnFadeEffect
|| spells[spell_id].effect_id[i] == SE_CastOnFadeEffectNPC || spells[spell_id].effectid[i] == SE_CastOnFadeEffectNPC
|| spells[spell_id].effect_id[i] == SE_CastOnFadeEffectAlways){ || spells[spell_id].effectid[i] == SE_CastOnFadeEffectAlways){
return true; return true;
} }
@@ -1073,7 +1065,7 @@ bool IsCastonFadeDurationSpell(uint16 spell_id)
bool IsPowerDistModSpell(uint16 spell_id) bool IsPowerDistModSpell(uint16 spell_id)
{ {
if (IsValidSpell(spell_id) && if (IsValidSpell(spell_id) &&
(spells[spell_id].max_distance_mod || spells[spell_id].min_distance_mod) && spells[spell_id].max_distance > spells[spell_id].min_distance) (spells[spell_id].max_dist_mod || spells[spell_id].min_dist_mod) && spells[spell_id].max_dist > spells[spell_id].min_dist)
return true; return true;
return false; return false;
@@ -1082,8 +1074,8 @@ bool IsPowerDistModSpell(uint16 spell_id)
uint32 GetPartialMeleeRuneReduction(uint32 spell_id) uint32 GetPartialMeleeRuneReduction(uint32 spell_id)
{ {
for (int i = 0; i < EFFECT_COUNT; ++i) for (int i = 0; i < EFFECT_COUNT; ++i)
if (spells[spell_id].effect_id[i] == SE_MitigateMeleeDamage) if (spells[spell_id].effectid[i] == SE_MitigateMeleeDamage)
return spells[spell_id].base_value[i]; return spells[spell_id].base[i];
return 0; return 0;
} }
@@ -1091,8 +1083,8 @@ uint32 GetPartialMeleeRuneReduction(uint32 spell_id)
uint32 GetPartialMagicRuneReduction(uint32 spell_id) uint32 GetPartialMagicRuneReduction(uint32 spell_id)
{ {
for (int i = 0; i < EFFECT_COUNT; ++i) for (int i = 0; i < EFFECT_COUNT; ++i)
if (spells[spell_id].effect_id[i] == SE_MitigateSpellDamage) if (spells[spell_id].effectid[i] == SE_MitigateSpellDamage)
return spells[spell_id].base_value[i]; return spells[spell_id].base[i];
return 0; return 0;
} }
@@ -1100,8 +1092,8 @@ uint32 GetPartialMagicRuneReduction(uint32 spell_id)
uint32 GetPartialMeleeRuneAmount(uint32 spell_id) uint32 GetPartialMeleeRuneAmount(uint32 spell_id)
{ {
for (int i = 0; i < EFFECT_COUNT; ++i) for (int i = 0; i < EFFECT_COUNT; ++i)
if (spells[spell_id].effect_id[i] == SE_MitigateMeleeDamage) if (spells[spell_id].effectid[i] == SE_MitigateMeleeDamage)
return spells[spell_id].max_value[i]; return spells[spell_id].max[i];
return 0; return 0;
} }
@@ -1109,8 +1101,8 @@ uint32 GetPartialMeleeRuneAmount(uint32 spell_id)
uint32 GetPartialMagicRuneAmount(uint32 spell_id) uint32 GetPartialMagicRuneAmount(uint32 spell_id)
{ {
for (int i = 0; i < EFFECT_COUNT; ++i) for (int i = 0; i < EFFECT_COUNT; ++i)
if (spells[spell_id].effect_id[i] == SE_MitigateSpellDamage) if (spells[spell_id].effectid[i] == SE_MitigateSpellDamage)
return spells[spell_id].max_value[i]; return spells[spell_id].max[i];
return 0; return 0;
} }
@@ -1119,7 +1111,7 @@ uint32 GetPartialMagicRuneAmount(uint32 spell_id)
bool DetrimentalSpellAllowsRest(uint16 spell_id) bool DetrimentalSpellAllowsRest(uint16 spell_id)
{ {
if (IsValidSpell(spell_id)) if (IsValidSpell(spell_id))
return spells[spell_id].allow_rest; return spells[spell_id].AllowRest;
return false; return false;
} }
@@ -1138,7 +1130,7 @@ bool IsStackableDot(uint16 spell_id)
if (!IsValidSpell(spell_id)) if (!IsValidSpell(spell_id))
return false; return false;
const auto &spell = spells[spell_id]; const auto &spell = spells[spell_id];
if (spell.unstackable_dot || spell.good_effect || !spell.buff_duration_formula) if (spell.dot_stacking_exempt || spell.goodEffect || !spell.buffdurationformula)
return false; return false;
return IsEffectInSpell(spell_id, SE_CurrentHP) || IsEffectInSpell(spell_id, SE_GravityEffect); return IsEffectInSpell(spell_id, SE_CurrentHP) || IsEffectInSpell(spell_id, SE_GravityEffect);
} }
@@ -1230,7 +1222,7 @@ bool IsEffectIgnoredInStacking(int spa)
case SE_LimitClass: case SE_LimitClass:
case SE_LimitRace: case SE_LimitRace:
case SE_FcBaseEffects: case SE_FcBaseEffects:
case SE_FFItemClass: case 415:
case SE_SkillDamageAmount2: case SE_SkillDamageAmount2:
case SE_FcLimitUse: case SE_FcLimitUse:
case SE_FcIncreaseNumHits: case SE_FcIncreaseNumHits:
@@ -1255,7 +1247,6 @@ bool IsEffectIgnoredInStacking(int spa)
case SE_Ff_ReuseTimeMax: case SE_Ff_ReuseTimeMax:
case SE_Ff_Value_Min: case SE_Ff_Value_Min:
case SE_Ff_Value_Max: case SE_Ff_Value_Max:
case SE_Ff_FocusTimerMin:
return true; return true;
default: default:
return false; return false;
@@ -1297,8 +1288,6 @@ bool IsFocusLimit(int spa)
case SE_Ff_ReuseTimeMax: case SE_Ff_ReuseTimeMax:
case SE_Ff_Value_Min: case SE_Ff_Value_Min:
case SE_Ff_Value_Max: case SE_Ff_Value_Max:
case SE_Ff_FocusTimerMin:
case SE_FFItemClass:
return true; return true;
default: default:
return false; return false;
@@ -1308,7 +1297,7 @@ bool IsFocusLimit(int spa)
uint32 GetNimbusEffect(uint16 spell_id) uint32 GetNimbusEffect(uint16 spell_id)
{ {
if (IsValidSpell(spell_id)) if (IsValidSpell(spell_id))
return (int32)spells[spell_id].nimbus_effect; return (int32)spells[spell_id].NimbusEffect;
return 0; return 0;
} }
@@ -1322,9 +1311,9 @@ int32 GetFuriousBash(uint16 spell_id)
int32 mod = 0; int32 mod = 0;
for (int i = 0; i < EFFECT_COUNT; ++i) for (int i = 0; i < EFFECT_COUNT; ++i)
if (spells[spell_id].effect_id[i] == SE_SpellHateMod) if (spells[spell_id].effectid[i] == SE_SpellHateMod)
mod = spells[spell_id].base_value[i]; mod = spells[spell_id].base[i];
else if (spells[spell_id].effect_id[i] == SE_LimitEffect && spells[spell_id].base_value[i] == 999) else if (spells[spell_id].effectid[i] == SE_LimitEffect && spells[spell_id].base[i] == 999)
found_effect_limit = true; found_effect_limit = true;
if (found_effect_limit) if (found_effect_limit)
@@ -1345,8 +1334,8 @@ bool IsSpellUsableThisZoneType(uint16 spell_id, uint8 zone_type)
{ {
//check if spell can be cast in any zone (-1 or 255), then if spell zonetype matches zone's zonetype //check if spell can be cast in any zone (-1 or 255), then if spell zonetype matches zone's zonetype
// || spells[spell_id].zonetype == 255 comparing signed 8 bit int to 255 is always false // || spells[spell_id].zonetype == 255 comparing signed 8 bit int to 255 is always false
if (IsValidSpell(spell_id) && (spells[spell_id].zone_type == -1 || if (IsValidSpell(spell_id) && (spells[spell_id].zonetype == -1 ||
spells[spell_id].zone_type == zone_type)) spells[spell_id].zonetype == zone_type))
return true; return true;
return false; return false;
@@ -1359,109 +1348,16 @@ const char* GetSpellName(uint16 spell_id)
bool SpellRequiresTarget(int spell_id) bool SpellRequiresTarget(int spell_id)
{ {
if (spells[spell_id].target_type == ST_AEClientV1 || if (spells[spell_id].targettype == ST_AEClientV1 ||
spells[spell_id].target_type == ST_Self || spells[spell_id].targettype == ST_Self ||
spells[spell_id].target_type == ST_AECaster || spells[spell_id].targettype == ST_AECaster ||
spells[spell_id].target_type == ST_Ring || spells[spell_id].targettype == ST_Ring ||
spells[spell_id].target_type == ST_Beam) { spells[spell_id].targettype == ST_Beam) {
return false; return false;
} }
return true; return true;
} }
bool IsInstrumentModAppliedToSpellEffect(int32 spell_id, int effect)
{
//Effects that are verified modifiable by bard instrument/singing mods, or highly likely due to similiar type of effect.
switch (effect) {
//Only modify instant endurance or mana effects (Ie. Mana drain, Crescendo line)
case SE_CurrentEndurance:
case SE_CurrentMana: {
if (spells[spell_id].buff_duration == 0) {
return true;
}
//Mana regen is not modified.
return false;
}
case SE_CurrentHP:
case SE_ArmorClass:
case SE_ACv2:
case SE_MovementSpeed:
case SE_ATK:
case SE_STR:
case SE_DEX:
case SE_AGI:
case SE_STA:
case SE_INT:
case SE_WIS:
case SE_CHA:
case SE_AllStats:
case SE_ResistFire:
case SE_ResistCold:
case SE_ResistPoison:
case SE_ResistDisease:
case SE_ResistMagic:
case SE_ResistAll:
case SE_ResistCorruption:
case SE_Rune:
case SE_AbsorbMagicAtt:
case SE_DamageShield:
case SE_MitigateDamageShield:
case SE_Amplification: //On live Amplification is modified by singing mods, including itself.
case SE_TripleAttackChance:
case SE_Flurry:
case SE_DamageModifier:
case SE_DamageModifier2:
case SE_MinDamageModifier:
case SE_ProcChance:
case SE_PetFlurry: // ? Need verified
case SE_DiseaseCounter:
case SE_PoisonCounter:
case SE_CurseCounter:
case SE_CorruptionCounter:
return true;
/*
Following are confirmed NOT modifiable by instrument/singing mods.
Focus Effects, Proc Effects, Spell Triggers are not modified but handled elsewhere, not neccessary to checked here.
*/
case SE_AttackSpeed: //(Haste AND Slow not modifiable)
case SE_AttackSpeed2:
case SE_AttackSpeed3:
case SE_Lull:
case SE_ChangeFrenzyRad:
case SE_Harmony:
case SE_AddFaction:
//case SE_CurrentMana: // duration only
case SE_ManaRegen_v2:
//case SE_CurrentEndurance: // duration only
case SE_PersistentEffect:
case SE_ReduceReuseTimer:
case SE_Stun:
case SE_Mez:
case SE_WipeHateList: //?
case SE_CancelMagic:
case SE_ManaAbsorbPercentDamage:
case SE_ResistSpellChance:
case SE_Reflect:
case SE_MitigateSpellDamage:
case SE_MitigateMeleeDamage:
case SE_AllInstrumentMod:
case SE_AddSingingMod:
case SE_SongModCap:
case SE_BardSongRange:
case SE_TemporaryPets:
case SE_SpellOnDeath:
return false;
default:
return true;
}
//Allowing anything not confirmed to be restricted / allowed to receive modifiers, as to not inhbit anyone making custom bard songs.
}
int GetSpellStatValue(uint32 spell_id, const char* stat_identifier, uint8 slot) int GetSpellStatValue(uint32 spell_id, const char* stat_identifier, uint8 slot)
{ {
if (!IsValidSpell(spell_id)) if (!IsValidSpell(spell_id))
@@ -1484,152 +1380,93 @@ int GetSpellStatValue(uint32 spell_id, const char* stat_identifier, uint8 slot)
} }
if (slot < 12) { if (slot < 12) {
if (id == "base") { return spells[spell_id].base_value[slot]; } if (id == "base") { return spells[spell_id].base[slot]; }
else if (id == "base2") { return spells[spell_id].limit_value[slot]; } else if (id == "base2") { return spells[spell_id].base2[slot]; }
else if (id == "max") { return spells[spell_id].max_value[slot]; } else if (id == "max") { return spells[spell_id].max[slot]; }
else if (id == "formula") { return spells[spell_id].formula[slot]; } else if (id == "formula") { return spells[spell_id].formula[slot]; }
else if (id == "effectid") { return spells[spell_id].effect_id[slot]; } else if (id == "effectid") { return spells[spell_id].effectid[slot]; }
} }
if (slot < 4) { if (slot < 4) {
if (id == "components") { return spells[spell_id].component[slot]; } if (id == "components") { return spells[spell_id].components[slot]; }
else if (id == "component_counts") { return spells[spell_id].component_count[slot]; } else if (id == "component_counts") { return spells[spell_id].component_counts[slot]; }
else if (id == "noexpendreagent") { return spells[spell_id].no_expend_reagent[slot]; } else if (id == "NoexpendReagent") { return spells[spell_id].NoexpendReagent[slot]; }
} }
if (id == "range") { return static_cast<int32>(spells[spell_id].range); } if (id == "range") { return static_cast<int32>(spells[spell_id].range); }
else if (id == "aoe_range") { return static_cast<int32>(spells[spell_id].aoe_range); } else if (id == "aoerange") { return static_cast<int32>(spells[spell_id].aoerange); }
else if (id == "push_back") { return static_cast<int32>(spells[spell_id].push_back); } else if (id == "pushback") { return static_cast<int32>(spells[spell_id].pushback); }
else if (id == "push_up") { return static_cast<int32>(spells[spell_id].push_up); } else if (id == "pushup") { return static_cast<int32>(spells[spell_id].pushup); }
else if (id == "cast_time") { return spells[spell_id].cast_time; } else if (id == "cast_time") { return spells[spell_id].cast_time; }
else if (id == "recovery_time") { return spells[spell_id].recovery_time; } else if (id == "recovery_time") { return spells[spell_id].recovery_time; }
else if (id == "recast_time") { return spells[spell_id].recast_time; } else if (id == "recast_time") { return spells[spell_id].recast_time; }
else if (id == "buff_duration_formula") { return spells[spell_id].buff_duration_formula; } else if (id == "buffdurationformula") { return spells[spell_id].buffdurationformula; }
else if (id == "buff_duration") { return spells[spell_id].buff_duration; } else if (id == "buffduration") { return spells[spell_id].buffduration; }
else if (id == "aeduration") { return spells[spell_id].aoe_duration; } else if (id == "AEDuration") { return spells[spell_id].AEDuration; }
else if (id == "mana") { return spells[spell_id].mana; } else if (id == "mana") { return spells[spell_id].mana; }
//else if (id == "LightType") {stat = spells[spell_id].LightType; } - Not implemented //else if (id == "LightType") {stat = spells[spell_id].LightType; } - Not implemented
else if (id == "goodeffect") { return spells[spell_id].good_effect; } else if (id == "goodEffect") { return spells[spell_id].goodEffect; }
else if (id == "activated") { return spells[spell_id].activated; } else if (id == "Activated") { return spells[spell_id].Activated; }
else if (id == "resisttype") { return spells[spell_id].resist_type; } else if (id == "resisttype") { return spells[spell_id].resisttype; }
else if (id == "targettype") { return spells[spell_id].target_type; } else if (id == "targettype") { return spells[spell_id].targettype; }
else if (id == "basediff") { return spells[spell_id].base_difficulty; } else if (id == "basediff") { return spells[spell_id].basediff; }
else if (id == "skill") { return spells[spell_id].skill; } else if (id == "skill") { return spells[spell_id].skill; }
else if (id == "zonetype") { return spells[spell_id].zone_type; } else if (id == "zonetype") { return spells[spell_id].zonetype; }
else if (id == "environmenttype") { return spells[spell_id].environment_type; } else if (id == "EnvironmentType") { return spells[spell_id].EnvironmentType; }
else if (id == "timeofday") { return spells[spell_id].time_of_day; } else if (id == "TimeOfDay") { return spells[spell_id].TimeOfDay; }
else if (id == "castinganim") { return spells[spell_id].casting_animation; } else if (id == "CastingAnim") { return spells[spell_id].CastingAnim; }
else if (id == "spellaffectindex") { return spells[spell_id].spell_affect_index; } else if (id == "SpellAffectIndex") { return spells[spell_id].SpellAffectIndex; }
else if (id == "disallow_sit") { return spells[spell_id].disallow_sit; } else if (id == "disallow_sit") { return spells[spell_id].disallow_sit; }
//else if (id == "spellanim") {stat = spells[spell_id].spellanim; } - Not implemented //else if (id == "spellanim") {stat = spells[spell_id].spellanim; } - Not implemented
else if (id == "uninterruptable") { return spells[spell_id].uninterruptable; } else if (id == "uninterruptable") { return spells[spell_id].uninterruptable; }
else if (id == "resistdiff") { return spells[spell_id].resist_difficulty; } else if (id == "ResistDiff") { return spells[spell_id].ResistDiff; }
else if (id == "dot_stacking_exempt") { return spells[spell_id].unstackable_dot; } else if (id == "dot_stacking_exempt") { return spells[spell_id].dot_stacking_exempt; }
else if (id == "recourselink") { return spells[spell_id].recourse_link; } else if (id == "RecourseLink") { return spells[spell_id].RecourseLink; }
else if (id == "no_partial_resist") { return spells[spell_id].no_partial_resist; } else if (id == "no_partial_resist") { return spells[spell_id].no_partial_resist; }
else if (id == "short_buff_box") { return spells[spell_id].short_buff_box; } else if (id == "short_buff_box") { return spells[spell_id].short_buff_box; }
else if (id == "descnum") { return spells[spell_id].description_id; } else if (id == "descnum") { return spells[spell_id].descnum; }
else if (id == "effectdescnum") { return spells[spell_id].effect_description_id; } else if (id == "effectdescnum") { return spells[spell_id].effectdescnum; }
else if (id == "npc_no_los") { return spells[spell_id].npc_no_los; } else if (id == "npc_no_los") { return spells[spell_id].npc_no_los; }
else if (id == "feedbackable") { return spells[spell_id].feedbackable; }
else if (id == "reflectable") { return spells[spell_id].reflectable; } else if (id == "reflectable") { return spells[spell_id].reflectable; }
else if (id == "bonushate") { return spells[spell_id].bonus_hate; } else if (id == "bonushate") { return spells[spell_id].bonushate; }
else if (id == "endurcost") { return spells[spell_id].endurance_cost; } else if (id == "EndurCost") { return spells[spell_id].EndurCost; }
else if (id == "endurtimerindex") { return spells[spell_id].timer_id; } else if (id == "EndurTimerIndex") { return spells[spell_id].EndurTimerIndex; }
else if (id == "isdisciplinebuff") { return spells[spell_id].is_discipline; } else if (id == "IsDisciplineBuff") { return spells[spell_id].IsDisciplineBuff; }
else if (id == "hateadded") { return spells[spell_id].hate_added; } else if (id == "HateAdded") { return spells[spell_id].HateAdded; }
else if (id == "endurupkeep") { return spells[spell_id].endurance_upkeep; } else if (id == "EndurUpkeep") { return spells[spell_id].EndurUpkeep; }
else if (id == "numhitstype") { return spells[spell_id].hit_number_type; } else if (id == "numhitstype") { return spells[spell_id].numhitstype; }
else if (id == "numhits") { return spells[spell_id].hit_number; } else if (id == "numhits") { return spells[spell_id].numhits; }
else if (id == "pvpresistbase") { return spells[spell_id].pvp_resist_base; } else if (id == "pvpresistbase") { return spells[spell_id].pvpresistbase; }
else if (id == "pvpresistcalc") { return spells[spell_id].pvp_resist_per_level; } else if (id == "pvpresistcalc") { return spells[spell_id].pvpresistcalc; }
else if (id == "pvpresistcap") { return spells[spell_id].pvp_resist_cap; } else if (id == "pvpresistcap") { return spells[spell_id].pvpresistcap; }
else if (id == "spell_category") { return spells[spell_id].spell_category; } else if (id == "spell_category") { return spells[spell_id].spell_category; }
else if (id == "can_mgb") { return spells[spell_id].can_mgb; } else if (id == "can_mgb") { return spells[spell_id].can_mgb; }
else if (id == "dispel_flag") { return spells[spell_id].dispel_flag; } else if (id == "dispel_flag") { return spells[spell_id].dispel_flag; }
else if (id == "minresist") { return spells[spell_id].min_resist; } else if (id == "MinResist") { return spells[spell_id].MinResist; }
else if (id == "maxresist") { return spells[spell_id].max_resist; } else if (id == "MaxResist") { return spells[spell_id].MaxResist; }
else if (id == "viral_targets") { return spells[spell_id].viral_targets; } else if (id == "viral_targets") { return spells[spell_id].viral_targets; }
else if (id == "viral_timer") { return spells[spell_id].viral_timer; } else if (id == "viral_timer") { return spells[spell_id].viral_timer; }
else if (id == "nimbuseffect") { return spells[spell_id].nimbus_effect; } else if (id == "NimbusEffect") { return spells[spell_id].NimbusEffect; }
else if (id == "directional_start") { return static_cast<int32>(spells[spell_id].directional_start); } else if (id == "directional_start") { return static_cast<int32>(spells[spell_id].directional_start); }
else if (id == "directional_end") { return static_cast<int32>(spells[spell_id].directional_end); } else if (id == "directional_end") { return static_cast<int32>(spells[spell_id].directional_end); }
else if (id == "not_focusable") { return spells[spell_id].not_focusable; } else if (id == "not_focusable") { return spells[spell_id].not_focusable; }
else if (id == "suspendable") { return spells[spell_id].suspendable; } else if (id == "suspendable") { return spells[spell_id].suspendable; }
else if (id == "viral_range") { return spells[spell_id].viral_range; } else if (id == "viral_range") { return spells[spell_id].viral_range; }
else if (id == "spellgroup") { return spells[spell_id].spell_group; } else if (id == "spellgroup") { return spells[spell_id].spellgroup; }
else if (id == "rank") { return spells[spell_id].rank; } else if (id == "rank") { return spells[spell_id].rank; }
else if (id == "no_resist") { return spells[spell_id].no_resist; } else if (id == "no_resist") { return spells[spell_id].no_resist; }
else if (id == "castrestriction") { return spells[spell_id].cast_restriction; } else if (id == "CastRestriction") { return spells[spell_id].CastRestriction; }
else if (id == "allowrest") { return spells[spell_id].allow_rest; } else if (id == "AllowRest") { return spells[spell_id].AllowRest; }
else if (id == "incombat") { return spells[spell_id].can_cast_in_combat; } else if (id == "InCombat") { return spells[spell_id].InCombat; }
else if (id == "outofcombat") { return spells[spell_id].can_cast_out_of_combat; } else if (id == "OutofCombat") { return spells[spell_id].OutofCombat; }
else if (id == "aemaxtargets") { return spells[spell_id].aoe_max_targets; } else if (id == "aemaxtargets") { return spells[spell_id].aemaxtargets; }
else if (id == "no_heal_damage_item_mod") { return spells[spell_id].no_heal_damage_item_mod; } else if (id == "no_heal_damage_item_mod") { return spells[spell_id].no_heal_damage_item_mod; }
else if (id == "persistdeath") { return spells[spell_id].persist_death; } else if (id == "persistdeath") { return spells[spell_id].persistdeath; }
else if (id == "min_dist") { return static_cast<int32>(spells[spell_id].min_distance); } else if (id == "min_dist") { return static_cast<int32>(spells[spell_id].min_dist); }
else if (id == "min_dist_mod") { return static_cast<int32>(spells[spell_id].min_distance_mod); } else if (id == "min_dist_mod") { return static_cast<int32>(spells[spell_id].min_dist_mod); }
else if (id == "max_dist") { return static_cast<int32>(spells[spell_id].max_distance); } else if (id == "max_dist") { return static_cast<int32>(spells[spell_id].max_dist); }
else if (id == "min_range") { return static_cast<int32>(spells[spell_id].min_range); } else if (id == "min_range") { return static_cast<int32>(spells[spell_id].min_range); }
else if (id == "damageshieldtype") { return spells[spell_id].damage_shield_type; } else if (id == "DamageShieldType") { return spells[spell_id].DamageShieldType; }
return 0; return 0;
} }
bool IsVirusSpell(int32 spell_id)
{
if (GetViralMinSpreadTime(spell_id) && GetViralMaxSpreadTime(spell_id) && GetViralSpreadRange(spell_id)){
return true;
}
return false;
}
int32 GetViralMinSpreadTime(int32 spell_id)
{
return spells[spell_id].viral_targets;
}
int32 GetViralMaxSpreadTime(int32 spell_id)
{
return spells[spell_id].viral_timer;
}
int32 GetViralSpreadRange(int32 spell_id)
{
return spells[spell_id].viral_range;
}
uint32 GetProcLimitTimer(int32 spell_id, int proc_type) {
//This allows for support for effects that may have multiple different proc types and timers.
if (!IsValidSpell(spell_id)) {
return 0;
}
bool use_next_timer = false;
for (int i = 0; i < EFFECT_COUNT; ++i) {
if (proc_type == SE_WeaponProc) {
if (spells[spell_id].effect_id[i] == SE_WeaponProc || spells[spell_id].effect_id[i] == SE_AddMeleeProc) {
use_next_timer = true;
}
}
if (proc_type == SE_RangedProc) {
if (spells[spell_id].effect_id[i] == SE_RangedProc) {
use_next_timer = true;
}
}
if (proc_type == SE_DefensiveProc) {
if (spells[spell_id].effect_id[i] == SE_DefensiveProc) {
use_next_timer = true;
}
}
if (use_next_timer && spells[spell_id].effect_id[i] == SE_Proc_Timer_Modifier) {
return spells[spell_id].limit_value[i];
}
}
return 0;
}
+81 -107
View File
@@ -129,8 +129,6 @@
#define SPELL_SPIRITUAL_ECHO 1248 #define SPELL_SPIRITUAL_ECHO 1248
#define SPELL_BRISTLING_ARMAMENT 1249 #define SPELL_BRISTLING_ARMAMENT 1249
#define SPELL_WATON_DESTRUCTION 1250 #define SPELL_WATON_DESTRUCTION 1250
#define SPELL_TRANSLOCATE_GROUP 1334
#define SPELL_TRANSLOCATE 1422
#define SPELL_ACTING_MAGIC_RESIST_I 1900 #define SPELL_ACTING_MAGIC_RESIST_I 1900
#define SPELL_ACTING_FIRE_RESIST_I 1901 #define SPELL_ACTING_FIRE_RESIST_I 1901
#define SPELL_ACTING_COLD_RESIST_I 1902 #define SPELL_ACTING_COLD_RESIST_I 1902
@@ -155,11 +153,8 @@
#define SPELL_ACTING_SPIRIT_I 1921 #define SPELL_ACTING_SPIRIT_I 1921
#define SPELL_ACTING_SPIRIT_II 1922 #define SPELL_ACTING_SPIRIT_II 1922
#define SPELL_RESURRECTION_SICKNESS 756 #define SPELL_RESURRECTION_SICKNESS 756
#define SPELL_RESURRECTION_SICKNESS4 757
#define SPELL_TELEPORT 3243
#define SPELL_RESURRECTION_SICKNESS2 5249 #define SPELL_RESURRECTION_SICKNESS2 5249
#define SPELL_REVIVAL_SICKNESS 13087 #define SPELL_REVIVAL_SICKNESS 13087
#define SPELL_RESURRECTION_SICKNESS3 37624
#define SPELL_PACT_OF_HATE_RECOURSE 40375 #define SPELL_PACT_OF_HATE_RECOURSE 40375
#define SPELL_INCENDIARY_OOZE_BUFF 32513 #define SPELL_INCENDIARY_OOZE_BUFF 32513
@@ -177,12 +172,9 @@
#define EFFECT_COUNT 12 #define EFFECT_COUNT 12
#define MAX_SPELL_TRIGGER 12 // One for each slot(only 6 for AA since AA use 2) #define MAX_SPELL_TRIGGER 12 // One for each slot(only 6 for AA since AA use 2)
#define MAX_RESISTABLE_EFFECTS 12 // Number of effects that are typcially checked agianst resists. #define MAX_RESISTABLE_EFFECTS 12 // Number of effects that are typcially checked agianst resists.
#define MaxLimitInclude 18 //Number(x 0.5) of focus Limiters that have inclusive checks used when calcing focus effects #define MaxLimitInclude 16 //Number(x 0.5) of focus Limiters that have inclusive checks used when calcing focus effects
#define MAX_SKILL_PROCS 4 //Number of spells to check skill procs from. (This is arbitrary) [Single spell can have multiple proc checks] #define MAX_SKILL_PROCS 4 //Number of spells to check skill procs from. (This is arbitrary) [Single spell can have multiple proc checks]
#define MAX_AA_PROCS 16 //(Actual Proc Amount is MAX_AA_PROCS/4) Number of spells to check AA procs from. (This is arbitrary)
#define MAX_SYMPATHETIC_PROCS 10 // Number of sympathetic procs a client can have (This is arbitrary) #define MAX_SYMPATHETIC_PROCS 10 // Number of sympathetic procs a client can have (This is arbitrary)
#define MAX_FOCUS_PROC_LIMIT_TIMERS 20 //Number of focus recast timers that can be going at same time (This is arbitrary)
#define MAX_PROC_LIMIT_TIMERS 8 //Number of proc delay timers that can be going at same time, different proc types get their own timer array. (This is arbitrary)
@@ -206,9 +198,7 @@ enum FocusLimitIncludes {
IncludeExistsSELimitSpellClass = 12, IncludeExistsSELimitSpellClass = 12,
IncludeFoundSELimitSpellClass = 13, IncludeFoundSELimitSpellClass = 13,
IncludeExistsSELimitSpellSubclass = 14, IncludeExistsSELimitSpellSubclass = 14,
IncludeFoundSELimitSpellSubclass = 15, IncludeFoundSELimitSpellSubclass = 15
IncludeExistsSEFFItemClass = 16,
IncludeFoundSEFFItemClass = 17
}; };
/* /*
The id's correspond to 'type' 39 in live(2021) dbstr_us gives the message for target and caster restricted effects. These are not present in the ROF2 dbstr_us. The id's correspond to 'type' 39 in live(2021) dbstr_us gives the message for target and caster restricted effects. These are not present in the ROF2 dbstr_us.
@@ -519,15 +509,6 @@ enum NegateSpellEffectType
NEGATE_SPA_SPELLBONUS_AND_AABONUS = 5, NEGATE_SPA_SPELLBONUS_AND_AABONUS = 5,
NEGATE_SPA_ITEMBONUS_AND_AABONUS = 6, NEGATE_SPA_ITEMBONUS_AND_AABONUS = 6,
}; };
//Used for rule RuleI(Spells, ReflectType))
enum ReflectSpellType
{
REFLECT_DISABLED = 0,
REFLECT_SINGLE_TARGET_SPELLS_ONLY = 1,
REFLECT_ALL_PLAYER_SPELLS = 2,
RELFECT_ALL_SINGLE_TARGET_SPELLS = 3,
REFLECT_ALL_SPELLS = 4,
};
enum SpellTypes : uint32 enum SpellTypes : uint32
{ {
@@ -566,7 +547,7 @@ const uint32 SPELL_TYPES_INNATE = (SpellType_Nuke | SpellType_Lifetap | SpellTyp
// These should not be used to determine spell category.. // These should not be used to determine spell category..
// They are a graphical affects (effects?) index only // They are a graphical affects (effects?) index only
// TODO: import sai list // TODO: import sai list
enum spell_affect_index { enum SpellAffectIndex {
SAI_Summon_Mount_Unclass = -1, SAI_Summon_Mount_Unclass = -1,
SAI_Direct_Damage = 0, SAI_Direct_Damage = 0,
SAI_Heal_Cure = 1, SAI_Heal_Cure = 1,
@@ -765,7 +746,7 @@ typedef enum {
//#define SE_TransferItem 60 // not used //#define SE_TransferItem 60 // not used
#define SE_Identify 61 // implemented #define SE_Identify 61 // implemented
//#define SE_ItemID 62 // not used //#define SE_ItemID 62 // not used
#define SE_WipeHateList 63 // implemented, @Memblur, chance to wipe hate list of target, base: pct chance, limit: none, max: ? (not implemented), Note: caster level and CHA add to pct chance #define SE_WipeHateList 63 // implemented
#define SE_SpinTarget 64 // implemented - TO DO: Not sure stun portion is working correctly #define SE_SpinTarget 64 // implemented - TO DO: Not sure stun portion is working correctly
#define SE_InfraVision 65 // implemented #define SE_InfraVision 65 // implemented
#define SE_UltraVision 66 // implemented #define SE_UltraVision 66 // implemented
@@ -820,7 +801,7 @@ typedef enum {
#define SE_Hunger 115 // implemented - Song of Sustenance #define SE_Hunger 115 // implemented - Song of Sustenance
#define SE_CurseCounter 116 // implemented #define SE_CurseCounter 116 // implemented
#define SE_MagicWeapon 117 // implemented - makes weapon magical #define SE_MagicWeapon 117 // implemented - makes weapon magical
#define SE_Amplification 118 // implemented, @Song, stackable singing mod, base: mod%, limit: none, max: none, Note: Can focus itself. #define SE_Amplification 118 // implemented - Harmonize/Amplification (stacks with other singing mods)
#define SE_AttackSpeed3 119 // implemented #define SE_AttackSpeed3 119 // implemented
#define SE_HealRate 120 // implemented - reduces healing by a % #define SE_HealRate 120 // implemented - reduces healing by a %
#define SE_ReverseDS 121 // implemented #define SE_ReverseDS 121 // implemented
@@ -856,11 +837,11 @@ typedef enum {
#define SE_SuspendPet 151 // implemented, @Pet, allow caster to have an extra suspended pet, base: 0=no buffs/items 1=buffs+items, limit: none, max: none #define SE_SuspendPet 151 // implemented, @Pet, allow caster to have an extra suspended pet, base: 0=no buffs/items 1=buffs+items, limit: none, max: none
#define SE_TemporaryPets 152 // implemented #define SE_TemporaryPets 152 // implemented
#define SE_BalanceHP 153 // implemented #define SE_BalanceHP 153 // implemented
#define SE_DispelDetrimental 154 // implemented, @Dispel, removes only detrimental effects on a target, base: pct chance (950=95%), limit: none, max: none #define SE_DispelDetrimental 154 // implemented
#define SE_SpellCritDmgIncrease 155 // implemented - no known live spells use this currently #define SE_SpellCritDmgIncrease 155 // implemented - no known live spells use this currently
#define SE_IllusionCopy 156 // implemented - Deception #define SE_IllusionCopy 156 // implemented - Deception
#define SE_SpellDamageShield 157 // implemented, @DS, causes non-melee damage on caster of a spell, base: Amt DS (negative), limit: none, max: unknown (same as base but +) #define SE_SpellDamageShield 157 // implemented - Petrad's Protection
#define SE_Reflect 158 // implemented, @SpellMisc, reflect casted detrimental spell back at caster, base: chance pct, limit: resist modifier (positive value reduces resists), max: pct of base dmg mod (50=50pct of base) #define SE_Reflect 158 // implemented
#define SE_AllStats 159 // implemented #define SE_AllStats 159 // implemented
//#define SE_MakeDrunk 160 // *not implemented - Effect works entirely client side (Should check against tolerance) //#define SE_MakeDrunk 160 // *not implemented - Effect works entirely client side (Should check against tolerance)
#define SE_MitigateSpellDamage 161 // implemented - rune with max value #define SE_MitigateSpellDamage 161 // implemented - rune with max value
@@ -881,7 +862,7 @@ typedef enum {
#define SE_DualWieldChance 176 // implemented #define SE_DualWieldChance 176 // implemented
#define SE_DoubleAttackChance 177 // implemented #define SE_DoubleAttackChance 177 // implemented
#define SE_MeleeLifetap 178 // implemented #define SE_MeleeLifetap 178 // implemented
#define SE_AllInstrumentMod 179 // implemented, @Song, set mod for ALL instrument/singing skills that will be used if higher then item mods, base: mod%, limit: none, max: none #define SE_AllInstrumentMod 179 // implemented
#define SE_ResistSpellChance 180 // implemented #define SE_ResistSpellChance 180 // implemented
#define SE_ResistFearChance 181 // implemented #define SE_ResistFearChance 181 // implemented
#define SE_HundredHands 182 // implemented #define SE_HundredHands 182 // implemented
@@ -911,7 +892,7 @@ typedef enum {
#define SE_AETaunt 206 // implemented #define SE_AETaunt 206 // implemented
#define SE_FleshToBone 207 // implemented #define SE_FleshToBone 207 // implemented
//#define SE_PurgePoison 208 // not used //#define SE_PurgePoison 208 // not used
#define SE_DispelBeneficial 209 // implemented, @Dispel, removes only beneficial effects on a target, base: pct chance (950=95%), limit: none, max: none #define SE_DispelBeneficial 209 // implemented
#define SE_PetShield 210 // implmented, @ShieldAbility, allows pet to 'shield' owner for 50 pct of damage taken for a duration, base: Time multiplier 1=12 seconds, 2=24 ect, limit: mitigation on pet owner override (not on live), max: mitigation on pet overide (not on live) #define SE_PetShield 210 // implmented, @ShieldAbility, allows pet to 'shield' owner for 50 pct of damage taken for a duration, base: Time multiplier 1=12 seconds, 2=24 ect, limit: mitigation on pet owner override (not on live), max: mitigation on pet overide (not on live)
#define SE_AEMelee 211 // implemented TO DO: Implement to allow NPC use (client only atm). #define SE_AEMelee 211 // implemented TO DO: Implement to allow NPC use (client only atm).
#define SE_FrenziedDevastation 212 // implemented - increase spell criticals + all DD spells cast 2x mana. #define SE_FrenziedDevastation 212 // implemented - increase spell criticals + all DD spells cast 2x mana.
@@ -944,7 +925,7 @@ typedef enum {
#define SE_FeignedCastOnChance 239 // implemented - ability gives you an increasing chance for your feigned deaths to not be revealed by spells cast upon you. #define SE_FeignedCastOnChance 239 // implemented - ability gives you an increasing chance for your feigned deaths to not be revealed by spells cast upon you.
//#define SE_StringUnbreakable 240 // not used [Likely related to above - you become immune to feign breaking on a resisted spell and have a good chance of feigning through a spell that successfully lands upon you.] //#define SE_StringUnbreakable 240 // not used [Likely related to above - you become immune to feign breaking on a resisted spell and have a good chance of feigning through a spell that successfully lands upon you.]
#define SE_ImprovedReclaimEnergy 241 // implemented - increase the amount of mana returned to you when reclaiming your pet. #define SE_ImprovedReclaimEnergy 241 // implemented - increase the amount of mana returned to you when reclaiming your pet.
#define SE_IncreaseChanceMemwipe 242 // implemented - @Memblur, increases the chance to wipe hate with memory blurr, base: chance pct, limit: none, max: none, Note: Mods final blur chance after other bonuses added. #define SE_IncreaseChanceMemwipe 242 // implemented - increases the chance to wipe hate with memory blurr
#define SE_CharmBreakChance 243 // implemented - Total Domination #define SE_CharmBreakChance 243 // implemented - Total Domination
#define SE_RootBreakChance 244 // implemented[AA] reduce the chance that your root will break. #define SE_RootBreakChance 244 // implemented[AA] reduce the chance that your root will break.
#define SE_TrapCircumvention 245 // *not implemented[AA] - decreases the chance that you will set off a trap when opening a chest #define SE_TrapCircumvention 245 // *not implemented[AA] - decreases the chance that you will set off a trap when opening a chest
@@ -962,8 +943,8 @@ typedef enum {
#define SE_PetDiscipline 257 // not implemented as bonus - /pet hold - official name is GivePetHold #define SE_PetDiscipline 257 // not implemented as bonus - /pet hold - official name is GivePetHold
#define SE_TripleBackstab 258 // implemented[AA] - chance to perform a triple backstab #define SE_TripleBackstab 258 // implemented[AA] - chance to perform a triple backstab
#define SE_CombatStability 259 // implemented[AA] - damage mitigation #define SE_CombatStability 259 // implemented[AA] - damage mitigation
#define SE_AddSingingMod 260 // implemented, @Song, set mod for specific instrument/singing skills that will be used if higher then item mods, base: mod%, limit: ItemType ID, max: none #define SE_AddSingingMod 260 // implemented[AA] - Instrument/Singing Mastery, base1 is the mod, base2 is the ItemType
#define SE_SongModCap 261 // implemented, @Song, raise max song modifier cap, base: amt, limit: none, max: none, Note: No longer used on live #define SE_SongModCap 261 // implemented[AA] - Song Mod cap increase (no longer used on live)
#define SE_RaiseStatCap 262 // implemented #define SE_RaiseStatCap 262 // implemented
#define SE_TradeSkillMastery 263 // implemented - lets you raise more than one tradeskill above master. #define SE_TradeSkillMastery 263 // implemented - lets you raise more than one tradeskill above master.
#define SE_HastenedAASkill 264 // implemented #define SE_HastenedAASkill 264 // implemented
@@ -972,7 +953,7 @@ typedef enum {
#define SE_AddPetCommand 267 // implemented - sets command base2 to base1 #define SE_AddPetCommand 267 // implemented - sets command base2 to base1
#define SE_ReduceTradeskillFail 268 // implemented - reduces chance to fail with given tradeskill by a percent chance #define SE_ReduceTradeskillFail 268 // implemented - reduces chance to fail with given tradeskill by a percent chance
#define SE_MaxBindWound 269 // implemented[AA] - Increase max HP you can bind wound. #define SE_MaxBindWound 269 // implemented[AA] - Increase max HP you can bind wound.
#define SE_BardSongRange 270 // implemented, @Song, increase range of beneficial bard songs, base: mod%, limit: none, max: none , Note: example Sionachie's Crescendo #define SE_BardSongRange 270 // implemented[AA] - increase range of beneficial bard songs (Sionachie's Crescendo)
#define SE_BaseMovementSpeed 271 // implemented[AA] - mods basemove speed, doesn't stack with other move mods #define SE_BaseMovementSpeed 271 // implemented[AA] - mods basemove speed, doesn't stack with other move mods
#define SE_CastingLevel2 272 // implemented #define SE_CastingLevel2 272 // implemented
#define SE_CriticalDoTChance 273 // implemented #define SE_CriticalDoTChance 273 // implemented
@@ -993,7 +974,7 @@ typedef enum {
#define SE_SkillAttackProc 288 // implemented[AA] - Chance to proc spell on skill attack usage (ex. Dragon Punch) #define SE_SkillAttackProc 288 // implemented[AA] - Chance to proc spell on skill attack usage (ex. Dragon Punch)
#define SE_CastOnFadeEffect 289 // implemented - Triggers only if fades after natural duration. #define SE_CastOnFadeEffect 289 // implemented - Triggers only if fades after natural duration.
#define SE_IncreaseRunSpeedCap 290 // implemented[AA] - increases run speed over the hard cap #define SE_IncreaseRunSpeedCap 290 // implemented[AA] - increases run speed over the hard cap
#define SE_Purify 291 // implemented, @Dispel, remove up specified amount of detiremental spells, base: amt removed, limit: none, max: none, Note: excluding charm, fear, resurrection, and revival sickness #define SE_Purify 291 // implemented - Removes determental effects
#define SE_StrikeThrough2 292 // implemented[AA] - increasing chance of bypassing an opponent's special defenses, such as dodge, block, parry, and riposte. #define SE_StrikeThrough2 292 // implemented[AA] - increasing chance of bypassing an opponent's special defenses, such as dodge, block, parry, and riposte.
#define SE_FrontalStunResist 293 // implemented[AA] - Reduce chance to be stunned from front. -- live descriptions sounds like this isn't limited to frontal anymore #define SE_FrontalStunResist 293 // implemented[AA] - Reduce chance to be stunned from front. -- live descriptions sounds like this isn't limited to frontal anymore
#define SE_CriticalSpellChance 294 // implemented - increase chance to critical hit and critical damage modifier. #define SE_CriticalSpellChance 294 // implemented - increase chance to critical hit and critical damage modifier.
@@ -1084,7 +1065,7 @@ typedef enum {
#define SE_ShadowStepDirectional 379 // implemented - handled by client #define SE_ShadowStepDirectional 379 // implemented - handled by client
#define SE_Knockdown 380 // implemented - small knock back(handled by client) #define SE_Knockdown 380 // implemented - small knock back(handled by client)
//#define SE_KnockTowardCaster 381 // *not implemented (Call of Hither) knocks you back to caster (value) distance units infront //#define SE_KnockTowardCaster 381 // *not implemented (Call of Hither) knocks you back to caster (value) distance units infront
#define SE_NegateSpellEffect 382 // implemented, @Debuff, negates specific spell effect benefits for the duration of the debuff and prevent non-duration spell effect from working, base: see NegateSpellEffecttype Enum, limit: SPA id, max: none #define SE_NegateSpellEffect 382 // implemented, @Debuff, negates specific spell effect benefits for the duration of the debuff, base: see NegateSpellEffecttype Enum, limit: SPA id, max: none
#define SE_SympatheticProc 383 // implemented, @Fc, On Caster, cast on spell use, base: variable proc chance on cast time, limit: spellid #define SE_SympatheticProc 383 // implemented, @Fc, On Caster, cast on spell use, base: variable proc chance on cast time, limit: spellid
#define SE_Leap 384 // implemented - Leap effect, ie stomping leap #define SE_Leap 384 // implemented - Leap effect, ie stomping leap
#define SE_LimitSpellGroup 385 // implemented, @Ff, Spell group(s) that a spell focus can require or exclude, base1: spellgroup id, Include: Positive Exclude: Negative #define SE_LimitSpellGroup 385 // implemented, @Ff, Spell group(s) that a spell focus can require or exclude, base1: spellgroup id, Include: Positive Exclude: Negative
@@ -1095,9 +1076,9 @@ typedef enum {
#define SE_FcTimerLockout 390 // implemented, @Fc, On Caster, set a spell to be on recast timer, base: recast duration milliseconds, Note: Applied from casted spells only #define SE_FcTimerLockout 390 // implemented, @Fc, On Caster, set a spell to be on recast timer, base: recast duration milliseconds, Note: Applied from casted spells only
#define SE_LimitManaMax 391 // implemented, @Ff, Mininum mana of spell that can be focused, base1: mana amt #define SE_LimitManaMax 391 // implemented, @Ff, Mininum mana of spell that can be focused, base1: mana amt
#define SE_FcHealAmt 392 // implemented, @Fc, On Caster, spell healing mod flat amt, base: amt #define SE_FcHealAmt 392 // implemented, @Fc, On Caster, spell healing mod flat amt, base: amt
#define SE_FcHealPctIncoming 393 // implemented, @Fc, On Target, heal received mod pct, base: pct, limit: random max pct #define SE_FcHealPctIncoming 393 // implemented, @Fc, On Target, heal received critical chance mod, base: chance pct
#define SE_FcHealAmtIncoming 394 // implemented, @Fc, On Target, heal received mod flat amt, base: amt #define SE_FcHealAmtIncoming 394 // implemented, @Fc, On Target, heal received mod flat amt, base: amt
#define SE_FcHealPctCritIncoming 395 // implemented, @Fc, On Target, heal received mod pct, base: pct, limit: random max pct #define SE_FcHealPctCritIncoming 395 // implemented, @Fc, On Target, heal received mod pct, base: pct
#define SE_FcHealAmtCrit 396 // implemented, @Fc, On Caster, spell healing mod flat amt, base: amt #define SE_FcHealAmtCrit 396 // implemented, @Fc, On Caster, spell healing mod flat amt, base: amt
#define SE_PetMeleeMitigation 397 // implemented[AA] - additional mitigation to your pets. Adds AC #define SE_PetMeleeMitigation 397 // implemented[AA] - additional mitigation to your pets. Adds AC
#define SE_SwarmPetDuration 398 // implemented - Affects the duration of swarm pets #define SE_SwarmPetDuration 398 // implemented - Affects the duration of swarm pets
@@ -1117,7 +1098,7 @@ typedef enum {
#define SE_LimitRace 412 // implemented, @Ff, Race that can use the spell focus, base1: race, Note: not used in any known live spells. Use only single race at a time. #define SE_LimitRace 412 // implemented, @Ff, Race that can use the spell focus, base1: race, Note: not used in any known live spells. Use only single race at a time.
#define SE_FcBaseEffects 413 // implemented, @Fc, On Caster, base spell effectiveness mod pct, base: pct #define SE_FcBaseEffects 413 // implemented, @Fc, On Caster, base spell effectiveness mod pct, base: pct
#define SE_LimitCastingSkill 414 // implemented, @Ff, Spell and singing skills(s) that a spell focus can require or exclude, base1: skill id, Include: Positive Exclude: Negative #define SE_LimitCastingSkill 414 // implemented, @Ff, Spell and singing skills(s) that a spell focus can require or exclude, base1: skill id, Include: Positive Exclude: Negative
#define SE_FFItemClass 415 // implemented, @Ff, Limits focuses to be applied only from item click. base1: item ItemType (-1 to include for all ItemTypes,-1000 to exclude clicks from getting the focus, or exclude specific SubTypes or Slots if set), limit: item SubType (-1 for all SubTypes), max: item Slots (bitmask of valid slots, -1 ALL slots), Note: not used on live. See comments in Mob::CalcFocusEffect for more details. //#define SE_FFItemClass 415 // not used - base1 matches ItemType, base2 matches SubType, -1 ignored, max is bitmask of valid slots
#define SE_ACv2 416 // implemented - New AC spell effect #define SE_ACv2 416 // implemented - New AC spell effect
#define SE_ManaRegen_v2 417 // implemented - New mana regen effect #define SE_ManaRegen_v2 417 // implemented - New mana regen effect
#define SE_SkillDamageAmount2 418 // implemented - adds skill damage directly to certain attacks #define SE_SkillDamageAmount2 418 // implemented - adds skill damage directly to certain attacks
@@ -1144,8 +1125,8 @@ typedef enum {
#define SE_Assassinate 439 // implemented[AA] - Assassinate damage #define SE_Assassinate 439 // implemented[AA] - Assassinate damage
#define SE_FinishingBlowLvl 440 // implemented[AA] - Sets the level Finishing blow can be triggered on an NPC #define SE_FinishingBlowLvl 440 // implemented[AA] - Sets the level Finishing blow can be triggered on an NPC
#define SE_DistanceRemoval 441 // implemented - Buff is removed from target when target moves X amount of distance away from where initially hit. #define SE_DistanceRemoval 441 // implemented - Buff is removed from target when target moves X amount of distance away from where initially hit.
#define SE_TriggerOnReqTarget 442 // implemented, @SpellTrigger, triggers a spell when Target Requirement conditions are met (see enum SpellRestriction for IDs), base: spellid, limit: SpellRestriction ID, max: none, Note: Usually cast on a target #define SE_TriggerOnReqTarget 442 // implemented - triggers a spell which a certain criteria are met (below X amount of hp,mana,end, number of pets on hatelist)
#define SE_TriggerOnReqCaster 443 // implemented, @SpellTrigger, triggers a spell when Caster Requirement conditions are met (see enum SpellRestriction for IDs), base: spellid, limit: SpellRestriction ID, max: none, Note: Usually self only #define SE_TriggerOnReqCaster 443 // implemented - triggers a spell which a certain criteria are met (below X amount of hp,mana,end, number of pets on hatelist)
#define SE_ImprovedTaunt 444 // implemented - Locks Aggro On Caster and Decrease other Players Aggro by X% on NPC targets below level Y #define SE_ImprovedTaunt 444 // implemented - Locks Aggro On Caster and Decrease other Players Aggro by X% on NPC targets below level Y
//#define SE_AddMercSlot 445 // *not implemented[AA] - [Hero's Barracks] Allows you to conscript additional mercs. //#define SE_AddMercSlot 445 // *not implemented[AA] - [Hero's Barracks] Allows you to conscript additional mercs.
#define SE_AStacker 446 // implementet - bufff stacking blocker (26219 | Qirik's Watch) #define SE_AStacker 446 // implementet - bufff stacking blocker (26219 | Qirik's Watch)
@@ -1213,8 +1194,8 @@ typedef enum {
#define SE_Fc_Amplify_Amt 508 // implemented, @Fc, On Caster, damage-heal-dot mod flat amt, base: amt #define SE_Fc_Amplify_Amt 508 // implemented, @Fc, On Caster, damage-heal-dot mod flat amt, base: amt
#define SE_Health_Transfer 509 // implemented - exchange health for damage or healing on a target. ie Lifeburn/Act of Valor #define SE_Health_Transfer 509 // implemented - exchange health for damage or healing on a target. ie Lifeburn/Act of Valor
#define SE_Fc_ResistIncoming 510 // implemented, @Fc, On Target, resist modifier, base: amt #define SE_Fc_ResistIncoming 510 // implemented, @Fc, On Target, resist modifier, base: amt
#define SE_Ff_FocusTimerMin 511 // implemented, @Ff, sets a recast time until focus can be used again, base: 1, limit: time ms, Note: ie. limit to 1 trigger every 1.5 seconds //#define SE_Ff_FocusTimerMin 511 //
#define SE_Proc_Timer_Modifier 512 // implemented - limits procs per amount of a time based on timer value, base: 1, limit: time ms, Note:, ie limit to 1 proc every 55 seconds) #define SE_Proc_Timer_Modifier 512 // implemented - spell trigger limiter used currently with SPA 481, ie. limit to 1 proc every 1.5 seconds (base=1 base2=1500).
//#define SE_Mana_Max_Percent 513 // //#define SE_Mana_Max_Percent 513 //
//#define SE_Endurance_Max_Percent 514 // //#define SE_Endurance_Max_Percent 514 //
#define SE_AC_Avoidance_Max_Percent 515 // implemented - stackable avoidance modifier #define SE_AC_Avoidance_Max_Percent 515 // implemented - stackable avoidance modifier
@@ -1257,44 +1238,44 @@ struct SPDat_Spell_Struct
/* 007 */ char cast_on_other[64]; // Message when spell is cast on someone else -- CASTEDOTHERTXT /* 007 */ char cast_on_other[64]; // Message when spell is cast on someone else -- CASTEDOTHERTXT
/* 008 */ char spell_fades[64]; // Spell fades -- SPELLGONE /* 008 */ char spell_fades[64]; // Spell fades -- SPELLGONE
/* 009 */ float range; // -- RANGE /* 009 */ float range; // -- RANGE
/* 010 */ float aoe_range; // -- IMPACTRANGE /* 010 */ float aoerange; // -- IMPACTRANGE
/* 011 */ float push_back; // -- OUTFORCE /* 011 */ float pushback; // -- OUTFORCE
/* 012 */ float push_up; // -- UPFORCE /* 012 */ float pushup; // -- UPFORCE
/* 013 */ uint32 cast_time; // Cast time -- CASTINGTIME /* 013 */ uint32 cast_time; // Cast time -- CASTINGTIME
/* 014 */ uint32 recovery_time; // Recovery time -- RECOVERYDELAY /* 014 */ uint32 recovery_time; // Recovery time -- RECOVERYDELAY
/* 015 */ uint32 recast_time; // Recast same spell time -- SPELLDELAY /* 015 */ uint32 recast_time; // Recast same spell time -- SPELLDELAY
/* 016 */ uint32 buff_duration_formula; // -- DURATIONBASE /* 016 */ uint32 buffdurationformula; // -- DURATIONBASE
/* 017 */ uint32 buff_duration; // -- DURATIONCAP /* 017 */ uint32 buffduration; // -- DURATIONCAP
/* 018 */ uint32 aoe_duration; // sentinel, rain of something -- IMPACTDURATION /* 018 */ uint32 AEDuration; // sentinel, rain of something -- IMPACTDURATION
/* 019 */ uint16 mana; // Mana Used -- MANACOST /* 019 */ uint16 mana; // Mana Used -- MANACOST
/* 020 */ int base_value[EFFECT_COUNT]; //various purposes -- BASEAFFECT1 .. BASEAFFECT12 /* 020 */ int base[EFFECT_COUNT]; //various purposes -- BASEAFFECT1 .. BASEAFFECT12
/* 032 */ int limit_value[EFFECT_COUNT]; //various purposes -- BASE_EFFECT2_1 ... BASE_EFFECT2_12 /* 032 */ int base2[EFFECT_COUNT]; //various purposes -- BASE_EFFECT2_1 ... BASE_EFFECT2_12
/* 044 */ int32 max_value[EFFECT_COUNT]; // -- AFFECT1CAP ... AFFECT12CAP /* 044 */ int32 max[EFFECT_COUNT]; // -- AFFECT1CAP ... AFFECT12CAP
/* 056 */ //uint16 icon; // Spell icon -- IMAGENUMBER /* 056 */ //uint16 icon; // Spell icon -- IMAGENUMBER
/* 057 */ //uint16 memicon; // Icon on membarthing -- MEMIMAGENUMBER /* 057 */ //uint16 memicon; // Icon on membarthing -- MEMIMAGENUMBER
/* 058 */ int32 component[4]; // reagents -- EXPENDREAGENT1 ... EXPENDREAGENT4 /* 058 */ int32 components[4]; // reagents -- EXPENDREAGENT1 ... EXPENDREAGENT4
/* 062 */ int component_count[4]; // amount of regents used -- EXPENDQTY1 ... EXPENDQTY4 /* 062 */ int component_counts[4]; // amount of regents used -- EXPENDQTY1 ... EXPENDQTY4
/* 066 */ int no_expend_reagent[4]; // focus items (Need but not used; Flame Lick has a Fire Beetle Eye focus.) /* 066 */ int NoexpendReagent[4]; // focus items (Need but not used; Flame Lick has a Fire Beetle Eye focus.)
// If it is a number between 1-4 it means components[number] is a focus and not to expend it // If it is a number between 1-4 it means components[number] is a focus and not to expend it
// If it is a valid itemid it means this item is a focus as well // If it is a valid itemid it means this item is a focus as well
// -- NOEXPENDREAGENT1 ... NOEXPENDREAGENT4 // -- NOEXPENDREAGENT1 ... NOEXPENDREAGENT4
/* 070 */ uint16 formula[EFFECT_COUNT]; // Spell's value formula -- LEVELAFFECT1MOD ... LEVELAFFECT12MOD /* 070 */ uint16 formula[EFFECT_COUNT]; // Spell's value formula -- LEVELAFFECT1MOD ... LEVELAFFECT12MOD
/* 082 */ //int LightType; // probaly another effecttype flag -- LIGHTTYPE /* 082 */ //int LightType; // probaly another effecttype flag -- LIGHTTYPE
/* 083 */ int8 good_effect; //0=detrimental, 1=Beneficial, 2=Beneficial, Group Only -- BENEFICIAL /* 083 */ int8 goodEffect; //0=detrimental, 1=Beneficial, 2=Beneficial, Group Only -- BENEFICIAL
/* 084 */ int activated; // probably another effecttype flag -- ACTIVATED /* 084 */ int Activated; // probably another effecttype flag -- ACTIVATED
/* 085 */ int resist_type; // -- RESISTTYPE /* 085 */ int resisttype; // -- RESISTTYPE
/* 086 */ int effect_id[EFFECT_COUNT]; // Spell's effects -- SPELLAFFECT1 ... SPELLAFFECT12 /* 086 */ int effectid[EFFECT_COUNT]; // Spell's effects -- SPELLAFFECT1 ... SPELLAFFECT12
/* 098 */ SpellTargetType target_type; // Spell's Target -- TYPENUMBER /* 098 */ SpellTargetType targettype; // Spell's Target -- TYPENUMBER
/* 099 */ int base_difficulty; // base difficulty fizzle adjustment -- BASEDIFFICULTY /* 099 */ int basediff; // base difficulty fizzle adjustment -- BASEDIFFICULTY
/* 100 */ EQ::skills::SkillType skill; // -- CASTINGSKILL /* 100 */ EQ::skills::SkillType skill; // -- CASTINGSKILL
/* 101 */ int8 zone_type; // 01=Outdoors, 02=dungeons, ff=Any -- ZONETYPE /* 101 */ int8 zonetype; // 01=Outdoors, 02=dungeons, ff=Any -- ZONETYPE
/* 102 */ int8 environment_type; // -- ENVIRONMENTTYPE /* 102 */ int8 EnvironmentType; // -- ENVIRONMENTTYPE
/* 103 */ int8 time_of_day; // -- TIMEOFDAY /* 103 */ int8 TimeOfDay; // -- TIMEOFDAY
/* 104 */ uint8 classes[PLAYER_CLASS_COUNT]; // Classes, and their min levels -- WARRIORMIN ... BERSERKERMIN /* 104 */ uint8 classes[PLAYER_CLASS_COUNT]; // Classes, and their min levels -- WARRIORMIN ... BERSERKERMIN
/* 120 */ uint8 casting_animation; // -- CASTINGANIM /* 120 */ uint8 CastingAnim; // -- CASTINGANIM
/* 121 */ //uint8 TargetAnim; // -- TARGETANIM /* 121 */ //uint8 TargetAnim; // -- TARGETANIM
/* 122 */ //uint32 TravelType; // -- TRAVELTYPE /* 122 */ //uint32 TravelType; // -- TRAVELTYPE
/* 123 */ uint16 spell_affect_index; // -- SPELLAFFECTINDEX /* 123 */ uint16 SpellAffectIndex; // -- SPELLAFFECTINDEX
/* 124 */ int8 disallow_sit; // 124: high-end Yaulp spells (V, VI, VII, VIII [Rk 1, 2, & 3], & Gallenite's Bark of Fury -- CANCELONSIT /* 124 */ int8 disallow_sit; // 124: high-end Yaulp spells (V, VI, VII, VIII [Rk 1, 2, & 3], & Gallenite's Bark of Fury -- CANCELONSIT
/* 125 */ int8 deity_agnostic;// 125: Words of the Skeptic -- DEITY_AGNOSTIC /* 125 */ int8 deity_agnostic;// 125: Words of the Skeptic -- DEITY_AGNOSTIC
/* 126 */ int8 deities[16]; // Deity check. 201 - 216 per http://www.eqemulator.net/wiki/wikka.php?wakka=DeityList /* 126 */ int8 deities[16]; // Deity check. 201 - 216 per http://www.eqemulator.net/wiki/wikka.php?wakka=DeityList
@@ -1306,36 +1287,36 @@ struct SPDat_Spell_Struct
/* 144 */ int16 new_icon; // Spell icon used by the client in uifiles/default/spells??.tga, both for spell gems & buff window. Looks to depreciate icon & memicon -- NEW_ICON /* 144 */ int16 new_icon; // Spell icon used by the client in uifiles/default/spells??.tga, both for spell gems & buff window. Looks to depreciate icon & memicon -- NEW_ICON
/* 145 */ //int16 spellanim; // Doesn't look like it's the same as #doanim, so not sure what this is, particles I think -- SPELL_EFFECT_INDEX /* 145 */ //int16 spellanim; // Doesn't look like it's the same as #doanim, so not sure what this is, particles I think -- SPELL_EFFECT_INDEX
/* 146 */ bool uninterruptable; // Looks like anything != 0 is uninterruptable. Values are mostly -1, 0, & 1 (Fetid Breath = 90?) -- NO_INTERRUPT /* 146 */ bool uninterruptable; // Looks like anything != 0 is uninterruptable. Values are mostly -1, 0, & 1 (Fetid Breath = 90?) -- NO_INTERRUPT
/* 147 */ int16 resist_difficulty; // -- RESIST_MOD /* 147 */ int16 ResistDiff; // -- RESIST_MOD
/* 148 */ bool unstackable_dot; // -- NOT_STACKABLE_DOT /* 148 */ bool dot_stacking_exempt; // -- NOT_STACKABLE_DOT
/* 149 */ //int deletable; // -- DELETE_OK /* 149 */ //int deletable; // -- DELETE_OK
/* 150 */ uint16 recourse_link; // -- REFLECT_SPELLINDEX /* 150 */ uint16 RecourseLink; // -- REFLECT_SPELLINDEX
/* 151 */ bool no_partial_resist; // 151: -1, 0, or 1 -- NO_PARTIAL_SAVE /* 151 */ bool no_partial_resist; // 151: -1, 0, or 1 -- NO_PARTIAL_SAVE
/* 152 */ //bool small_targets_only; // -- SMALL_TARGETS_ONLY /* 152 */ //bool small_targets_only; // -- SMALL_TARGETS_ONLY
/* 153 */ //bool uses_persistent_particles; // -- USES_PERSISTENT_PARTICLES /* 153 */ //bool uses_persistent_particles; // -- USES_PERSISTENT_PARTICLES
/* 154 */ int8 short_buff_box; // != 0, goes to short buff box. -- BARD_BUFF_BOX /* 154 */ int8 short_buff_box; // != 0, goes to short buff box. -- BARD_BUFF_BOX
/* 155 */ int description_id; // eqstr of description of spell -- DESCRIPTION_INDEX /* 155 */ int descnum; // eqstr of description of spell -- DESCRIPTION_INDEX
/* 156 */ int type_description_id; // eqstr of type description -- PRIMARY_CATEGORY /* 156 */ int typedescnum; // eqstr of type description -- PRIMARY_CATEGORY
/* 157 */ int effect_description_id; // eqstr of effect description -- SECONDARY_CATEGORY_1 /* 157 */ int effectdescnum; // eqstr of effect description -- SECONDARY_CATEGORY_1
/* 158 */ //int secondary_category_2; //Category Desc ID 3 -- SECONDARY_CATEGORY_2 /* 158 */ //int secondary_category_2; //Category Desc ID 3 -- SECONDARY_CATEGORY_2
/* 159 */ bool npc_no_los; // -- NO_NPC_LOS /* 159 */ bool npc_no_los; // -- NO_NPC_LOS
/* 160 */ bool feedbackable; // -- FEEDBACKABLE /* 160 */ //bool feedbackable; // -- FEEDBACKABLE
/* 161 */ bool reflectable; // -- REFLECTABLE /* 161 */ bool reflectable; // -- REFLECTABLE
/* 162 */ int bonus_hate; // -- HATE_MOD /* 162 */ int bonushate; // -- HATE_MOD
/* 163 */ //int resist_per_level; // -- RESIST_PER_LEVEL /* 163 */ //int resist_per_level; // -- RESIST_PER_LEVEL
/* 164 */ //int resist_cap; // for most spells this appears to mimic ResistDiff -- RESIST_CAP /* 164 */ //int resist_cap; // for most spells this appears to mimic ResistDiff -- RESIST_CAP
/* 165 */ bool ldon_trap; //Flag found on all LDON trap / chest related spells. -- AFFECT_INANIMATE /* 165 */ bool ldon_trap; //Flag found on all LDON trap / chest related spells. -- AFFECT_INANIMATE
/* 166 */ int endurance_cost; // -- STAMINA_COST /* 166 */ int EndurCost; // -- STAMINA_COST
/* 167 */ int8 timer_id; // bad name, used for all spells -- TIMER_INDEX /* 167 */ int8 EndurTimerIndex; // bad name, used for all spells -- TIMER_INDEX
/* 168 */ bool is_discipline; //Will goto the combat window when cast -- IS_SKILL /* 168 */ bool IsDisciplineBuff; //Will goto the combat window when cast -- IS_SKILL
/* 169 - 172*/ //These are zero for ALL spells, also removed from live -- ATTACK_OPENING, DEFENSE_OPENING, SKILL_OPENING, NPC_ERROR_OPENING /* 169 - 172*/ //These are zero for ALL spells, also removed from live -- ATTACK_OPENING, DEFENSE_OPENING, SKILL_OPENING, NPC_ERROR_OPENING
/* 173 */ int hate_added; // -- SPELL_HATE_GIVEN /* 173 */ int HateAdded; // -- SPELL_HATE_GIVEN
/* 174 */ int endurance_upkeep; // -- ENDUR_UPKEEP /* 174 */ int EndurUpkeep; // -- ENDUR_UPKEEP
/* 175 */ int hit_number_type; // defines which type of behavior will tick down the numhit counter. -- LIMITED_USE_TYPE /* 175 */ int numhitstype; // defines which type of behavior will tick down the numhit counter. -- LIMITED_USE_TYPE
/* 176 */ int hit_number; // -- LIMITED_USE_COUNT /* 176 */ int numhits; // -- LIMITED_USE_COUNT
/* 177 */ int pvp_resist_base; // -- PVP_RESIST_MOD /* 177 */ int pvpresistbase; // -- PVP_RESIST_MOD
/* 178 */ int pvp_resist_per_level; // -- PVP_RESIST_PER_LEVEL /* 178 */ int pvpresistcalc; // -- PVP_RESIST_PER_LEVEL
/* 179 */ int pvp_resist_cap; // -- PVP_RESIST_CAP /* 179 */ int pvpresistcap; // -- PVP_RESIST_CAP
/* 180 */ int spell_category; // -- GLOBAL_GROUP /* 180 */ int spell_category; // -- GLOBAL_GROUP
/* 181 */ int pvp_duration; // buffdurationformula for PvP -- PVP_DURATION /* 181 */ int pvp_duration; // buffdurationformula for PvP -- PVP_DURATION
/* 182 */ int pvp_duration_cap; // buffduration for PvP -- PVP_DURATION_CAP /* 182 */ int pvp_duration_cap; // buffduration for PvP -- PVP_DURATION_CAP
@@ -1345,11 +1326,11 @@ struct SPDat_Spell_Struct
/* 186 */ int dispel_flag; // -- NO_DISPELL /* 186 */ int dispel_flag; // -- NO_DISPELL
/* 187 */ //int npc_category; // -- NPC_MEM_CATEGORY /* 187 */ //int npc_category; // -- NPC_MEM_CATEGORY
/* 188 */ //int npc_usefulness; // -- NPC_USEFULNESS /* 188 */ //int npc_usefulness; // -- NPC_USEFULNESS
/* 189 */ int min_resist; // -- MIN_RESIST /* 189 */ int MinResist; // -- MIN_RESIST
/* 190 */ int max_resist; // -- MAX_RESIST /* 190 */ int MaxResist; // -- MAX_RESIST
/* 191 */ uint8 viral_targets; // -- MIN_SPREAD_TIME /* 191 */ uint8 viral_targets; // -- MIN_SPREAD_TIME
/* 192 */ uint8 viral_timer; // -- MAX_SPREAD_TIME /* 192 */ uint8 viral_timer; // -- MAX_SPREAD_TIME
/* 193 */ int nimbus_effect; // -- DURATION_PARTICLE_EFFECT /* 193 */ int NimbusEffect; // -- DURATION_PARTICLE_EFFECT
/* 194 */ float directional_start; //Cone Start Angle: -- CONE_START_ANGLE /* 194 */ float directional_start; //Cone Start Angle: -- CONE_START_ANGLE
/* 195 */ float directional_end; // Cone End Angle: -- CONE_END_ANGLE /* 195 */ float directional_end; // Cone End Angle: -- CONE_END_ANGLE
/* 196 */ bool sneak; // effect can only be used if sneaking (rogue 'Daggerfall' ect) -- SNEAK_ATTACK /* 196 */ bool sneak; // effect can only be used if sneaking (rogue 'Daggerfall' ect) -- SNEAK_ATTACK
@@ -1358,35 +1339,35 @@ struct SPDat_Spell_Struct
/* 199 */ //bool show_wear_off_message; // -- SHOW_WEAR_OFF_MESSAGE /* 199 */ //bool show_wear_off_message; // -- SHOW_WEAR_OFF_MESSAGE
/* 200 */ bool suspendable; // buff is suspended in suspended buff zones -- IS_COUNTDOWN_HELD /* 200 */ bool suspendable; // buff is suspended in suspended buff zones -- IS_COUNTDOWN_HELD
/* 201 */ int viral_range; // -- SPREAD_RADIUS /* 201 */ int viral_range; // -- SPREAD_RADIUS
/* 202 */ int song_cap; // individual song cap -- BASE_EFFECTS_FOCUS_CAP /* 202 */ int songcap; // individual song cap -- BASE_EFFECTS_FOCUS_CAP
/* 203 */ //bool stacks_with_self; // -- STACKS_WITH_SELF /* 203 */ //bool stacks_with_self; // -- STACKS_WITH_SELF
/* 204 */ //int not_shown_to_player; // client skips this -- NOT_SHOWN_TO_PLAYER /* 204 */ //int not_shown_to_player; // client skips this -- NOT_SHOWN_TO_PLAYER
/* 205 */ bool no_block; // -- NO_BUFF_BLOCK /* 205 */ bool no_block; // -- NO_BUFF_BLOCK
/* 206 */ //int8 anim_variation; // -- ANIM_VARIATION /* 206 */ //int8 anim_variation; // -- ANIM_VARIATION
/* 207 */ int spell_group; // -- SPELL_GROUP /* 207 */ int spellgroup; // -- SPELL_GROUP
/* 208 */ int rank; //increments AA effects with same name -- SPELL_GROUP_RANK /* 208 */ int rank; //increments AA effects with same name -- SPELL_GROUP_RANK
/* 209 */ int no_resist; //makes spells unresistable, which makes charms unbreakable as well. -- NO_RESIST /* 209 */ int no_resist; //makes spells unresistable, which makes charms unbreakable as well. -- NO_RESIST
/* 210 */ // bool allow_spellscribe; // -- ALLOW_SPELLSCRIBE /* 210 */ // bool allow_spellscribe; // -- ALLOW_SPELLSCRIBE
/* 211 */ int cast_restriction; //Various restriction categories for spells most seem targetable race related but have also seen others for instance only castable if target hp 20% or lower or only if target out of combat -- SPELL_REQ_ASSOCIATION_ID /* 211 */ int CastRestriction; //Various restriction categories for spells most seem targetable race related but have also seen others for instance only castable if target hp 20% or lower or only if target out of combat -- SPELL_REQ_ASSOCIATION_ID
/* 212 */ bool allow_rest; // -- BYPASS_REGEN_CHECK /* 212 */ bool AllowRest; // -- BYPASS_REGEN_CHECK
/* 213 */ bool can_cast_in_combat; //Allow spell if target is in combat -- CAN_CAST_IN_COMBAT /* 213 */ bool InCombat; //Allow spell if target is in combat -- CAN_CAST_IN_COMBAT
/* 214 */ bool can_cast_out_of_combat; //Allow spell if target is out of combat -- CAN_CAST_OUT_OF_COMBAT /* 214 */ bool OutofCombat; //Allow spell if target is out of combat -- CAN_CAST_OUT_OF_COMBAT
/* 215 */ //bool show_dot_message; // -- SHOW_DOT_MESSAGE /* 215 */ //bool show_dot_message; // -- SHOW_DOT_MESSAGE
/* 216 */ //bool invalid; // -- INVALID /* 216 */ //bool invalid; // -- INVALID
/* 217 */ int override_crit_chance; //Places a cap on the max chance to critical -- OVERRIDE_CRIT_CHANCE /* 217 */ int override_crit_chance; //Places a cap on the max chance to critical -- OVERRIDE_CRIT_CHANCE
/* 218 */ int aoe_max_targets; //Is used for various AE effects -- MAX_TARGETS /* 218 */ int aemaxtargets; //Is used for various AE effects -- MAX_TARGETS
/* 219 */ int no_heal_damage_item_mod; // -- NO_HEAL_DAMAGE_ITEM_MOD /* 219 */ int no_heal_damage_item_mod; // -- NO_HEAL_DAMAGE_ITEM_MOD
/* 220 */ int caster_requirement_id; // -- CASTER_REQUIREMENT_ID /* 220 */ int caster_requirement_id; // -- CASTER_REQUIREMENT_ID
/* 221 */ int spell_class; // -- SPELL_CLASS /* 221 */ int spell_class; // -- SPELL_CLASS
/* 222 */ int spell_subclass; // -- SPELL_SUBCLASS /* 222 */ int spell_subclass; // -- SPELL_SUBCLASS
/* 223 */ //int ai_valid_targets; // -- AI_VALID_TARGETS /* 223 */ //int ai_valid_targets; // -- AI_VALID_TARGETS
/* 224 */ bool persist_death; // buff doesn't get stripped on death -- NO_STRIP_ON_DEATH /* 224 */ bool persistdeath; // buff doesn't get stripped on death -- NO_STRIP_ON_DEATH
/* 225 */ //float base_effects_focus_slope; // -- BASE_EFFECTS_FOCUS_SLOPE /* 225 */ //float base_effects_focus_slope; // -- BASE_EFFECTS_FOCUS_SLOPE
/* 226 */ //float base_effects_focus_offset; // -- BASE_EFFECTS_FOCUS_OFFSET /* 226 */ //float base_effects_focus_offset; // -- BASE_EFFECTS_FOCUS_OFFSET
/* 227 */ float min_distance; //spell power modified by distance from caster (Min Distance) -- DISTANCE_MOD_CLOSE_DIST /* 227 */ float min_dist; //spell power modified by distance from caster (Min Distance) -- DISTANCE_MOD_CLOSE_DIST
/* 228 */ float min_distance_mod; //spell power modified by distance from caster (Modifier at Min Distance) -- DISTANCE_MOD_CLOSE_MULT /* 228 */ float min_dist_mod; //spell power modified by distance from caster (Modifier at Min Distance) -- DISTANCE_MOD_CLOSE_MULT
/* 229 */ float max_distance; //spell power modified by distance from caster (Max Distance) -- DISTANCE_MOD_FAR_DIST /* 229 */ float max_dist; //spell power modified by distance from caster (Max Distance) -- DISTANCE_MOD_FAR_DIST
/* 230 */ float max_distance_mod; //spell power modified by distance from caster (Modifier at Max Distance) -- DISTANCE_MOD_FAR_MULT /* 230 */ float max_dist_mod; //spell power modified by distance from caster (Modifier at Max Distance) -- DISTANCE_MOD_FAR_MULT
/* The client also does this /* The client also does this
* v26 = *(float *)&v4->DistanceModFarDist - *(float *)&v4->DistanceModCloseDist; * v26 = *(float *)&v4->DistanceModFarDist - *(float *)&v4->DistanceModCloseDist;
* if ( v26 > -0.00000011920929 && v26 < 0.00000011920929 ) * if ( v26 > -0.00000011920929 && v26 < 0.00000011920929 )
@@ -1400,7 +1381,7 @@ struct SPDat_Spell_Struct
/* 234 */ //bool only_during_fast_regen; // -- ONLY_DURING_FAST_REGEN /* 234 */ //bool only_during_fast_regen; // -- ONLY_DURING_FAST_REGEN
/* 235 */ //bool is_beta_only; // -- IS_BETA_ONLY /* 235 */ //bool is_beta_only; // -- IS_BETA_ONLY
/* 236 */ //int spell_subgroup; // -- SPELL_SUBGROUP /* 236 */ //int spell_subgroup; // -- SPELL_SUBGROUP
uint8 damage_shield_type; // This field does not exist in spells_us.txt uint8 DamageShieldType; // This field does not exist in spells_us.txt
}; };
extern const SPDat_Spell_Struct* spells; extern const SPDat_Spell_Struct* spells;
@@ -1480,7 +1461,6 @@ bool IsPartialDeathSaveSpell(uint16 spell_id);
bool IsShadowStepSpell(uint16 spell_id); bool IsShadowStepSpell(uint16 spell_id);
bool IsSuccorSpell(uint16 spell_id); bool IsSuccorSpell(uint16 spell_id);
bool IsTeleportSpell(uint16 spell_id); bool IsTeleportSpell(uint16 spell_id);
bool IsTranslocateSpell(uint16 spell_id);
bool IsGateSpell(uint16 spell_id); bool IsGateSpell(uint16 spell_id);
bool IsPlayerIllusionSpell(uint16 spell_id); // seveian 2008-09-23 bool IsPlayerIllusionSpell(uint16 spell_id); // seveian 2008-09-23
bool IsLDoNObjectSpell(uint16 spell_id); bool IsLDoNObjectSpell(uint16 spell_id);
@@ -1513,13 +1493,7 @@ bool IsBardOnlyStackEffect(int effect);
bool IsCastWhileInvis(uint16 spell_id); bool IsCastWhileInvis(uint16 spell_id);
bool IsEffectIgnoredInStacking(int spa); bool IsEffectIgnoredInStacking(int spa);
bool IsFocusLimit(int spa); bool IsFocusLimit(int spa);
bool SpellRequiresTarget(int target_type); bool SpellRequiresTarget(int targettype);
bool IsVirusSpell(int32 spell_id);
int GetViralMinSpreadTime(int32 spell_id);
int GetViralMaxSpreadTime(int32 spell_id);
int GetViralSpreadRange(int32 spell_id);
bool IsInstrumentModAppliedToSpellEffect(int32 spell_id, int effect);
uint32 GetProcLimitTimer(int32 spell_id, int proc_type);
int CalcPetHp(int levelb, int classb, int STA = 75); int CalcPetHp(int levelb, int classb, int STA = 75);
int GetSpellEffectDescNum(uint16 spell_id); int GetSpellEffectDescNum(uint16 spell_id);
+65 -479
View File
@@ -16,7 +16,6 @@
#include "string_util.h" #include "string_util.h"
#include <algorithm> #include <algorithm>
#include <cctype>
#ifdef _WINDOWS #ifdef _WINDOWS
#include <windows.h> #include <windows.h>
@@ -26,7 +25,6 @@
#define strcasecmp _stricmp #define strcasecmp _stricmp
#else #else
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <iostream> #include <iostream>
@@ -61,10 +59,9 @@ const std::string vStringFormat(const char *format, va_list args)
// We shouldn't have a format error by this point, but I can't imagine what error we // We shouldn't have a format error by this point, but I can't imagine what error we
// could have by this point. Still, return empty string; // could have by this point. Still, return empty string;
if (characters_used < 0) { if (characters_used < 0)
output.clear(); output.clear();
} }
}
return output; return output;
} }
@@ -89,9 +86,8 @@ const std::string str_toupper(std::string s)
const std::string ucfirst(std::string s) const std::string ucfirst(std::string s)
{ {
std::string output = s; std::string output = s;
if (!s.empty()) { if (!s.empty())
output[0] = static_cast<char>(::toupper(s[0])); output[0] = static_cast<char>(::toupper(s[0]));
}
return output; return output;
} }
@@ -105,8 +101,7 @@ const std::string StringFormat(const char *format, ...)
return output; return output;
} }
std::vector<std::string> SplitString(const std::string &str, const char delim) std::vector<std::string> SplitString(const std::string &str, const char delim) {
{
std::vector<std::string> ret; std::vector<std::string> ret;
std::string::size_type start = 0; std::string::size_type start = 0;
auto end = str.find(delim); auto end = str.find(delim);
@@ -116,9 +111,8 @@ std::vector<std::string> SplitString(const std::string &str, const char delim)
end = str.find(delim, start); end = str.find(delim, start);
} }
// this will catch the last word since the string is unlikely to end with a delimiter // this will catch the last word since the string is unlikely to end with a delimiter
if (str.length() > start) { if (str.length() > start)
ret.emplace_back(str, start, str.length() - start); ret.emplace_back(str, start, str.length() - start);
}
return ret; return ret;
} }
@@ -158,16 +152,14 @@ std::string get_between(const std::string &s, std::string start_delim, std::stri
return ""; return "";
} }
std::string::size_type std::string::size_type search_deliminated_string(const std::string &haystack, const std::string &needle, const char deliminator)
search_deliminated_string(const std::string &haystack, const std::string &needle, const char deliminator)
{ {
// this shouldn't go out of bounds, even without obvious bounds checks // this shouldn't go out of bounds, even without obvious bounds checks
auto pos = haystack.find(needle); auto pos = haystack.find(needle);
while (pos != std::string::npos) { while (pos != std::string::npos) {
auto c = haystack[pos + needle.length()]; auto c = haystack[pos + needle.length()];
if ((c == '\0' || c == deliminator) && (pos == 0 || haystack[pos - 1] == deliminator)) { if ((c == '\0' || c == deliminator) && (pos == 0 || haystack[pos - 1] == deliminator))
return pos; return pos;
}
pos = haystack.find(needle, pos + needle.length()); pos = haystack.find(needle, pos + needle.length());
} }
return std::string::npos; return std::string::npos;
@@ -209,8 +201,7 @@ std::vector<std::string> wrap(std::vector<std::string> &src, std::string charact
return new_vector; return new_vector;
} }
std::string EscapeString(const std::string &s) std::string EscapeString(const std::string &s) {
{
std::string ret; std::string ret;
size_t sz = s.length(); size_t sz = s.length();
@@ -247,8 +238,7 @@ std::string EscapeString(const std::string &s)
return ret; return ret;
} }
std::string EscapeString(const char *src, size_t sz) std::string EscapeString(const char *src, size_t sz) {
{
std::string ret; std::string ret;
for(size_t i = 0; i < sz; ++i) { for(size_t i = 0; i < sz; ++i) {
@@ -284,8 +274,7 @@ std::string EscapeString(const char *src, size_t sz)
return ret; return ret;
} }
bool StringIsNumber(const std::string &s) bool StringIsNumber(const std::string &s) {
{
try { try {
auto r = stod(s); auto r = stod(s);
return true; return true;
@@ -295,18 +284,15 @@ bool StringIsNumber(const std::string &s)
} }
} }
void ToLowerString(std::string &s) void ToLowerString(std::string &s) {
{
std::transform(s.begin(), s.end(), s.begin(), ::tolower); std::transform(s.begin(), s.end(), s.begin(), ::tolower);
} }
void ToUpperString(std::string &s) void ToUpperString(std::string &s) {
{
std::transform(s.begin(), s.end(), s.begin(), ::toupper); std::transform(s.begin(), s.end(), s.begin(), ::toupper);
} }
std::string JoinString(const std::vector<std::string> &ar, const std::string &delim) std::string JoinString(const std::vector<std::string>& ar, const std::string &delim) {
{
std::string ret; std::string ret;
for (size_t i = 0; i < ar.size(); ++i) { for (size_t i = 0; i < ar.size(); ++i) {
if (i != 0) { if (i != 0) {
@@ -358,11 +344,9 @@ void ParseAccountString(const std::string &s, std::string &account, std::string
// normal strncpy doesnt put a null term on copied strings, this one does // normal strncpy doesnt put a null term on copied strings, this one does
// ref: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcecrt/htm/_wcecrt_strncpy_wcsncpy.asp // ref: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcecrt/htm/_wcecrt_strncpy_wcsncpy.asp
char *strn0cpy(char *dest, const char *source, uint32 size) char* strn0cpy(char* dest, const char* source, uint32 size) {
{ if (!dest)
if (!dest) {
return 0; return 0;
}
if (size == 0 || source == 0) { if (size == 0 || source == 0) {
dest[0] = 0; dest[0] = 0;
return dest; return dest;
@@ -374,11 +358,9 @@ char *strn0cpy(char *dest, const char *source, uint32 size)
// String N w/null Copy Truncated? // String N w/null Copy Truncated?
// return value =true if entire string(source) fit, false if it was truncated // return value =true if entire string(source) fit, false if it was truncated
bool strn0cpyt(char *dest, const char *source, uint32 size) bool strn0cpyt(char* dest, const char* source, uint32 size) {
{ if (!dest)
if (!dest) {
return 0; return 0;
}
if (size == 0 || source == 0) { if (size == 0 || source == 0) {
dest[0] = 0; dest[0] = 0;
return false; return false;
@@ -388,145 +370,111 @@ bool strn0cpyt(char *dest, const char *source, uint32 size)
return (bool)(source[strlen(dest)] == 0); return (bool)(source[strlen(dest)] == 0);
} }
const char *MakeLowerString(const char *source) const char *MakeLowerString(const char *source) {
{
static char str[128]; static char str[128];
if (!source) { if (!source)
return nullptr; return nullptr;
}
MakeLowerString(source, str); MakeLowerString(source, str);
return str; return str;
} }
void MakeLowerString(const char *source, char *target) void MakeLowerString(const char *source, char *target) {
{
if (!source || !target) { if (!source || !target) {
*target = 0; *target = 0;
return; return;
} }
while (*source) { while (*source)
{
*target = tolower(*source); *target = tolower(*source);
target++; target++; source++;
source++;
} }
*target = 0; *target = 0;
} }
uint32 hextoi(const char *num) uint32 hextoi(const char* num) {
{ if (num == nullptr)
if (num == nullptr) {
return 0; return 0;
}
int len = strlen(num); int len = strlen(num);
if (len < 3) { if (len < 3)
return 0; return 0;
}
if (num[0] != '0' || (num[1] != 'x' && num[1] != 'X')) { if (num[0] != '0' || (num[1] != 'x' && num[1] != 'X'))
return 0; return 0;
}
uint32 ret = 0; uint32 ret = 0;
int mul = 1; int mul = 1;
for (int i = len - 1; i >= 2; i--) { for (int i = len - 1; i >= 2; i--) {
if (num[i] >= 'A' && num[i] <= 'F') { if (num[i] >= 'A' && num[i] <= 'F')
ret += ((num[i] - 'A') + 10) * mul; ret += ((num[i] - 'A') + 10) * mul;
} else if (num[i] >= 'a' && num[i] <= 'f')
else if (num[i] >= 'a' && num[i] <= 'f') {
ret += ((num[i] - 'a') + 10) * mul; ret += ((num[i] - 'a') + 10) * mul;
} else if (num[i] >= '0' && num[i] <= '9')
else if (num[i] >= '0' && num[i] <= '9') {
ret += (num[i] - '0') * mul; ret += (num[i] - '0') * mul;
} else
else {
return 0; return 0;
}
mul *= 16; mul *= 16;
} }
return ret; return ret;
} }
uint64 hextoi64(const char *num) uint64 hextoi64(const char* num) {
{ if (num == nullptr)
if (num == nullptr) {
return 0; return 0;
}
int len = strlen(num); int len = strlen(num);
if (len < 3) { if (len < 3)
return 0; return 0;
}
if (num[0] != '0' || (num[1] != 'x' && num[1] != 'X')) { if (num[0] != '0' || (num[1] != 'x' && num[1] != 'X'))
return 0; return 0;
}
uint64 ret = 0; uint64 ret = 0;
int mul = 1; int mul = 1;
for (int i = len - 1; i >= 2; i--) { for (int i = len - 1; i >= 2; i--) {
if (num[i] >= 'A' && num[i] <= 'F') { if (num[i] >= 'A' && num[i] <= 'F')
ret += ((num[i] - 'A') + 10) * mul; ret += ((num[i] - 'A') + 10) * mul;
} else if (num[i] >= 'a' && num[i] <= 'f')
else if (num[i] >= 'a' && num[i] <= 'f') {
ret += ((num[i] - 'a') + 10) * mul; ret += ((num[i] - 'a') + 10) * mul;
} else if (num[i] >= '0' && num[i] <= '9')
else if (num[i] >= '0' && num[i] <= '9') {
ret += (num[i] - '0') * mul; ret += (num[i] - '0') * mul;
} else
else {
return 0; return 0;
}
mul *= 16; mul *= 16;
} }
return ret; return ret;
} }
bool atobool(const char *iBool) bool atobool(const char* iBool) {
{
if (iBool == nullptr) { if (iBool == nullptr)
return false; return false;
} if (!strcasecmp(iBool, "true"))
if (!strcasecmp(iBool, "true")) {
return true; return true;
} if (!strcasecmp(iBool, "false"))
if (!strcasecmp(iBool, "false")) {
return false; return false;
} if (!strcasecmp(iBool, "yes"))
if (!strcasecmp(iBool, "yes")) {
return true; return true;
} if (!strcasecmp(iBool, "no"))
if (!strcasecmp(iBool, "no")) {
return false; return false;
} if (!strcasecmp(iBool, "on"))
if (!strcasecmp(iBool, "on")) {
return true; return true;
} if (!strcasecmp(iBool, "off"))
if (!strcasecmp(iBool, "off")) {
return false; return false;
} if (!strcasecmp(iBool, "enable"))
if (!strcasecmp(iBool, "enable")) {
return true; return true;
} if (!strcasecmp(iBool, "disable"))
if (!strcasecmp(iBool, "disable")) {
return false; return false;
} if (!strcasecmp(iBool, "enabled"))
if (!strcasecmp(iBool, "enabled")) {
return true; return true;
} if (!strcasecmp(iBool, "disabled"))
if (!strcasecmp(iBool, "disabled")) {
return false; return false;
} if (!strcasecmp(iBool, "y"))
if (!strcasecmp(iBool, "y")) {
return true; return true;
} if (!strcasecmp(iBool, "n"))
if (!strcasecmp(iBool, "n")) {
return false; return false;
} if (atoi(iBool))
if (atoi(iBool)) {
return true; return true;
}
return false; return false;
} }
@@ -535,18 +483,20 @@ char *CleanMobName(const char *in, char *out)
{ {
unsigned i, j; unsigned i, j;
for (i = j = 0; i < strlen(in); i++) { for (i = j = 0; i < strlen(in); i++)
{
// convert _ to space.. any other conversions like this? I *think* this // convert _ to space.. any other conversions like this? I *think* this
// is the only non alpha char that's not stripped but converted. // is the only non alpha char that's not stripped but converted.
if (in[i] == '_') { if (in[i] == '_')
{
out[j++] = ' '; out[j++] = ' ';
} }
else { else
if (isalpha(in[i]) || (in[i] == '`')) { // numbers, #, or any other crap just gets skipped {
if (isalpha(in[i]) || (in[i] == '`')) // numbers, #, or any other crap just gets skipped
out[j++] = in[i]; out[j++] = in[i];
} }
} }
}
out[j] = 0; // terimnate the string before returning it out[j] = 0; // terimnate the string before returning it
return out; return out;
} }
@@ -555,10 +505,9 @@ char *CleanMobName(const char *in, char *out)
void RemoveApostrophes(std::string &s) void RemoveApostrophes(std::string &s)
{ {
for (unsigned int i = 0; i < s.length(); ++i) for (unsigned int i = 0; i < s.length(); ++i)
if (s[i] == '\'') { if (s[i] == '\'')
s[i] = '_'; s[i] = '_';
} }
}
char *RemoveApostrophes(const char *s) char *RemoveApostrophes(const char *s)
{ {
@@ -567,9 +516,8 @@ char *RemoveApostrophes(const char *s)
strcpy(NewString, s); strcpy(NewString, s);
for (unsigned int i = 0; i < strlen(NewString); ++i) for (unsigned int i = 0; i < strlen(NewString); ++i)
if (NewString[i] == '\'') { if (NewString[i] == '\'')
NewString[i] = '_'; NewString[i] = '_';
}
return NewString; return NewString;
} }
@@ -591,10 +539,9 @@ bool isAlphaNumeric(const char *text)
for (unsigned int charIndex = 0; charIndex<strlen(text); charIndex++) { for (unsigned int charIndex = 0; charIndex<strlen(text); charIndex++) {
if ((text[charIndex] < 'a' || text[charIndex] > 'z') && if ((text[charIndex] < 'a' || text[charIndex] > 'z') &&
(text[charIndex] < 'A' || text[charIndex] > 'Z') && (text[charIndex] < 'A' || text[charIndex] > 'Z') &&
(text[charIndex] < '0' || text[charIndex] > '9')) { (text[charIndex] < '0' || text[charIndex] > '9'))
return false; return false;
} }
}
return true; return true;
} }
@@ -651,371 +598,10 @@ std::string numberToWords(unsigned long long int n)
std::string FormatName(const std::string& char_name) std::string FormatName(const std::string& char_name)
{ {
std::string formatted(char_name); std::string formatted(char_name);
if (!formatted.empty()) { if (!formatted.empty())
{
std::transform(formatted.begin(), formatted.end(), formatted.begin(), ::tolower); std::transform(formatted.begin(), formatted.end(), formatted.begin(), ::tolower);
formatted[0] = ::toupper(formatted[0]); formatted[0] = ::toupper(formatted[0]);
} }
return formatted; return formatted;
} }
bool IsAllowedWorldServerCharacterList(char c)
{
const char *valid_characters = ":[](){}.!@#$%^&*-=+<>/\\|'\"";
if (strchr(valid_characters, c)) {
return true;
}
return false;
}
void SanitizeWorldServerName(char *name)
{
std::string server_long_name = name;
strcpy(name, SanitizeWorldServerName(server_long_name).c_str());
}
std::string SanitizeWorldServerName(std::string server_long_name)
{
server_long_name.erase(
std::remove_if(
server_long_name.begin(),
server_long_name.end(),
[](char c) {
return !(std::isalpha(c) || std::isalnum(c) || std::isspace(c) || IsAllowedWorldServerCharacterList(c));
}
), server_long_name.end()
);
server_long_name = trim(server_long_name);
// bad word filter
for (auto &piece: split_string(server_long_name, " ")) {
for (auto &word: GetBadWords()) {
// for shorter words that can actually be part of legitimate words
// make sure that it isn't part of another word by matching on a space
if (str_tolower(piece) == word) {
find_replace(
server_long_name,
piece,
repeat("*", (int) word.length())
);
continue;
}
auto pos = str_tolower(piece).find(word);
if (str_tolower(piece).find(word) != std::string::npos && piece.length() > 4 && word.length() > 4) {
auto found_word = piece.substr(pos, word.length());
std::string replaced_piece = piece.substr(pos, word.length());
find_replace(
server_long_name,
replaced_piece,
repeat("*", (int) word.length())
);
}
}
}
return server_long_name;
}
std::string repeat(std::string s, int n)
{
std::string s1 = s;
for (int i = 1; i < n; i++) {
s += s1;
}
return s;
}
std::vector<std::string> GetBadWords()
{
return std::vector<std::string>{
"2g1c",
"acrotomophilia",
"anal",
"anilingus",
"anus",
"apeshit",
"arsehole",
"ass",
"asshole",
"assmunch",
"autoerotic",
"babeland",
"bangbros",
"bangbus",
"bareback",
"barenaked",
"bastard",
"bastardo",
"bastinado",
"bbw",
"bdsm",
"beaner",
"beaners",
"beaver",
"beastiality",
"bestiality",
"bimbos",
"birdlock",
"bitch",
"bitches",
"blowjob",
"blumpkin",
"bollocks",
"bondage",
"boner",
"boob",
"boobs",
"bukkake",
"bulldyke",
"bullshit",
"bung",
"bunghole",
"busty",
"butt",
"buttcheeks",
"butthole",
"camel toe",
"camgirl",
"camslut",
"camwhore",
"carpetmuncher",
"cialis",
"circlejerk",
"clit",
"clitoris",
"clusterfuck",
"cock",
"cocks",
"coprolagnia",
"coprophilia",
"cornhole",
"coon",
"coons",
"creampie",
"cum",
"cumming",
"cumshot",
"cumshots",
"cunnilingus",
"cunt",
"darkie",
"daterape",
"deepthroat",
"dendrophilia",
"dick",
"dildo",
"dingleberry",
"dingleberries",
"doggiestyle",
"doggystyle",
"dolcett",
"domination",
"dominatrix",
"dommes",
"hump",
"dvda",
"ecchi",
"ejaculation",
"erotic",
"erotism",
"escort",
"eunuch",
"fag",
"faggot",
"fecal",
"felch",
"fellatio",
"feltch",
"femdom",
"figging",
"fingerbang",
"fingering",
"fisting",
"footjob",
"frotting",
"fuck",
"fuckin",
"fucking",
"fucktards",
"fudgepacker",
"futanari",
"gangbang",
"gangbang",
"gaysex",
"genitals",
"goatcx",
"goatse",
"gokkun",
"goodpoop",
"goregasm",
"grope",
"g-spot",
"guro",
"handjob",
"hentai",
"homoerotic",
"honkey",
"hooker",
"horny",
"humping",
"incest",
"intercourse",
"jailbait",
"jigaboo",
"jiggaboo",
"jiggerboo",
"jizz",
"juggs",
"kike",
"kinbaku",
"kinkster",
"kinky",
"knobbing",
"livesex",
"lolita",
"lovemaking",
"masturbate",
"masturbating",
"masturbation",
"milf",
"mong",
"motherfucker",
"muffdiving",
"nambla",
"nawashi",
"negro",
"neonazi",
"nigga",
"nigger",
"nimphomania",
"nipple",
"nipples",
"nsfw",
"nude",
"nudity",
"nutten",
"nympho",
"nymphomania",
"octopussy",
"omorashi",
"orgasm",
"orgy",
"paedophile",
"paki",
"panties",
"panty",
"pedobear",
"pedophile",
"pegging",
"penis",
"pikey",
"pissing",
"pisspig",
"playboy",
"ponyplay",
"poof",
"poon",
"poontang",
"punany",
"poopchute",
"porn",
"porno",
"pornography",
"pthc",
"pubes",
"pussy",
"queaf",
"queef",
"quim",
"raghead",
"rape",
"raping",
"rapist",
"rectum",
"rimjob",
"rimming",
"sadism",
"santorum",
"scat",
"schlong",
"scissoring",
"semen",
"sex",
"sexcam",
"sexo",
"sexy",
"sexual",
"sexually",
"sexuality",
"shemale",
"shibari",
"shit",
"shitblimp",
"shitty",
"shota",
"shrimping",
"skeet",
"slanteye",
"slut",
"s&m",
"smut",
"snatch",
"snowballing",
"sodomize",
"sodomy",
"spastic",
"spic",
"splooge",
"spooge",
"spunk",
"strapon",
"strappado",
"suck",
"sucks",
"swastika",
"swinger",
"threesome",
"throating",
"thumbzilla",
"tight white",
"tit",
"tits",
"titties",
"titty",
"topless",
"tosser",
"towelhead",
"tranny",
"tribadism",
"tubgirl",
"tushy",
"twat",
"twink",
"twinkie",
"undressing",
"upskirt",
"urophilia",
"vagina",
"viagra",
"vibrator",
"vorarephilia",
"voyeur",
"voyeurweb",
"voyuer",
"vulva",
"wank",
"wetback",
"whore",
"worldsex",
"xx",
"xxx",
"yaoi",
"yiffy",
"zoophilia"
};
}
-5
View File
@@ -208,11 +208,6 @@ void RemoveApostrophes(std::string &s);
std::string convert2digit(int n, std::string suffix); std::string convert2digit(int n, std::string suffix);
std::string numberToWords(unsigned long long int n); std::string numberToWords(unsigned long long int n);
std::string FormatName(const std::string& char_name); std::string FormatName(const std::string& char_name);
bool IsAllowedWorldServerCharacterList(char c);
void SanitizeWorldServerName(char *name);
std::string SanitizeWorldServerName(std::string server_long_name);
std::string repeat(std::string s, int n);
std::vector<std::string> GetBadWords();
template<typename InputIterator, typename OutputIterator> template<typename InputIterator, typename OutputIterator>
auto CleanMobName(InputIterator first, InputIterator last, OutputIterator result) auto CleanMobName(InputIterator first, InputIterator last, OutputIterator result)
+1 -1
View File
@@ -34,7 +34,7 @@
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt * Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/ */
#define CURRENT_BINARY_DATABASE_VERSION 9174 #define CURRENT_BINARY_DATABASE_VERSION 9172
#ifdef BOTS #ifdef BOTS
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9028 #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9028
+1 -1
View File
@@ -22,7 +22,7 @@ SET(eqlogin_headers
loginserver_command_handler.h loginserver_command_handler.h
loginserver_webserver.h loginserver_webserver.h
login_server.h login_server.h
login_types.h login_structures.h
options.h options.h
server_manager.h server_manager.h
world_server.h world_server.h
+22 -130
View File
@@ -1,9 +1,28 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 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 "account_management.h" #include "account_management.h"
#include "login_server.h" #include "login_server.h"
#include "../common/event/task_scheduler.h" #include "../common/event/task_scheduler.h"
#include "../common/event/event_loop.h" #include "../common/event/event_loop.h"
#include "../common/net/dns.h" #include "../common/net/dns.h"
#include "../common/string_util.h"
extern LoginServer server; extern LoginServer server;
EQ::Event::TaskScheduler task_runner; EQ::Event::TaskScheduler task_runner;
@@ -281,8 +300,6 @@ bool AccountManagement::UpdateLoginserverWorldAdminAccountPasswordById(
return updated_account; return updated_account;
} }
constexpr int REQUEST_TIMEOUT_MS = 1500;
/** /**
* @param in_account_username * @param in_account_username
* @param in_account_password * @param in_account_password
@@ -378,144 +395,19 @@ uint32 AccountManagement::CheckExternalLoginserverUserCredentials(
} }
); );
auto s = SplitString(server.options.GetEQEmuLoginServerAddress(), ':');
if (s.size() == 2) {
auto address = s[0];
auto port = std::stoi(s[1]);
EQ::Net::DNSLookup( EQ::Net::DNSLookup(
address, port, false, [&](const std::string &addr) { "login.eqemulator.net", 5999, false, [&](const std::string &addr) {
if (addr.empty()) { if (addr.empty()) {
ret = 0; ret = 0;
running = false; running = false;
} }
mgr.Connect(addr, port); mgr.Connect(addr, 5999);
} }
); );
}
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
auto &loop = EQ::EventLoop::Get(); auto &loop = EQ::EventLoop::Get();
while (running) { while (running) {
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
if (std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() > REQUEST_TIMEOUT_MS) {
LogInfo("[CheckExternalLoginserverUserCredentials] Deadline exceeded [{}]", REQUEST_TIMEOUT_MS);
running = false;
}
loop.Process();
}
return ret;
}
);
return res.get();
}
uint32 AccountManagement::HealthCheckUserLogin()
{
std::string in_account_username = "healthcheckuser";
std::string in_account_password = "healthcheckpassword";
auto res = task_runner.Enqueue(
[&]() -> uint32 {
bool running = true;
uint32 ret = 0;
EQ::Net::DaybreakConnectionManager mgr;
std::shared_ptr<EQ::Net::DaybreakConnection> c;
mgr.OnNewConnection(
[&](std::shared_ptr<EQ::Net::DaybreakConnection> connection) {
c = connection;
}
);
mgr.OnConnectionStateChange(
[&](
std::shared_ptr<EQ::Net::DaybreakConnection> conn,
EQ::Net::DbProtocolStatus from,
EQ::Net::DbProtocolStatus to
) {
if (EQ::Net::StatusConnected == to) {
EQ::Net::DynamicPacket p;
p.PutUInt16(0, 1); //OP_SessionReady
p.PutUInt32(2, 2);
c->QueuePacket(p);
}
else if (EQ::Net::StatusDisconnected == to) {
running = false;
}
}
);
mgr.OnPacketRecv(
[&](std::shared_ptr<EQ::Net::DaybreakConnection> conn, const EQ::Net::Packet &p) {
auto opcode = p.GetUInt16(0);
switch (opcode) {
case 0x0017: //OP_ChatMessage
{
size_t buffer_len =
in_account_username.length() + in_account_password.length() + 2;
std::unique_ptr<char[]> buffer(new char[buffer_len]);
strcpy(&buffer[0], in_account_username.c_str());
strcpy(&buffer[in_account_username.length() + 1], in_account_password.c_str());
size_t encrypted_len = buffer_len;
if (encrypted_len % 8 > 0) {
encrypted_len = ((encrypted_len / 8) + 1) * 8;
}
EQ::Net::DynamicPacket p;
p.Resize(12 + encrypted_len);
p.PutUInt16(0, 2); //OP_Login
p.PutUInt32(2, 3);
eqcrypt_block(&buffer[0], buffer_len, (char *) p.Data() + 12, true);
c->QueuePacket(p);
break;
}
case 0x0018: {
auto encrypt_size = p.Length() - 12;
if (encrypt_size % 8 > 0) {
encrypt_size = (encrypt_size / 8) * 8;
}
std::unique_ptr<char[]> decrypted(new char[encrypt_size]);
eqcrypt_block((char *) p.Data() + 12, encrypt_size, &decrypted[0], false);
EQ::Net::StaticPacket sp(&decrypted[0], encrypt_size);
auto response_error = sp.GetUInt16(1);
{
// we only care to see the response code
ret = response_error;
running = false;
}
break;
}
}
}
);
mgr.Connect("127.0.0.1", 5999);
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
auto &loop = EQ::EventLoop::Get();
while (running) {
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
if (std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() > 2000) {
ret = 0;
running = false;
}
loop.Process(); loop.Process();
} }
+19 -2
View File
@@ -1,3 +1,22 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 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_ACCOUNT_MANAGEMENT_H #ifndef EQEMU_ACCOUNT_MANAGEMENT_H
#define EQEMU_ACCOUNT_MANAGEMENT_H #define EQEMU_ACCOUNT_MANAGEMENT_H
@@ -89,8 +108,6 @@ public:
uint32 in_account_id, uint32 in_account_id,
const std::string &in_account_password_hash const std::string &in_account_password_hash
); );
static uint32 HealthCheckUserLogin();
}; };
+195 -146
View File
@@ -1,10 +1,29 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 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 "client.h" #include "client.h"
#include "login_server.h" #include "login_server.h"
#include "../common/misc_functions.h" #include "../common/misc_functions.h"
#include "../common/eqemu_logsys.h" #include "../common/eqemu_logsys.h"
#include "../common/string_util.h" #include "../common/string_util.h"
#include "encryption.h" #include "encryption.h"
#include "account_management.h"
extern LoginServer server; extern LoginServer server;
@@ -14,17 +33,17 @@ extern LoginServer server;
*/ */
Client::Client(std::shared_ptr<EQStreamInterface> c, LSClientVersion v) Client::Client(std::shared_ptr<EQStreamInterface> c, LSClientVersion v)
{ {
m_connection = c; connection = c;
m_client_version = v; version = v;
m_client_status = cs_not_sent_session_ready; status = cs_not_sent_session_ready;
m_account_id = 0; account_id = 0;
m_play_server_id = 0; play_server_id = 0;
m_play_sequence_id = 0; play_sequence_id = 0;
} }
bool Client::Process() bool Client::Process()
{ {
EQApplicationPacket *app = m_connection->PopPacket(); EQApplicationPacket *app = connection->PopPacket();
while (app) { while (app) {
if (server.options.IsTraceOn()) { if (server.options.IsTraceOn()) {
LogDebug("Application packet received from client (size {0})", app->Size()); LogDebug("Application packet received from client (size {0})", app->Size());
@@ -34,9 +53,9 @@ bool Client::Process()
DumpPacket(app); DumpPacket(app);
} }
if (m_client_status == cs_failed_to_login) { if (status == cs_failed_to_login) {
delete app; delete app;
app = m_connection->PopPacket(); app = connection->PopPacket();
continue; continue;
} }
@@ -93,7 +112,7 @@ bool Client::Process()
} }
delete app; delete app;
app = m_connection->PopPacket(); app = connection->PopPacket();
} }
return true; return true;
@@ -107,7 +126,7 @@ bool Client::Process()
*/ */
void Client::Handle_SessionReady(const char *data, unsigned int size) void Client::Handle_SessionReady(const char *data, unsigned int size)
{ {
if (m_client_status != cs_not_sent_session_ready) { if (status != cs_not_sent_session_ready) {
LogError("Session ready received again after already being received"); LogError("Session ready received again after already being received");
return; return;
} }
@@ -117,24 +136,40 @@ void Client::Handle_SessionReady(const char *data, unsigned int size)
return; return;
} }
m_client_status = cs_waiting_for_login; status = cs_waiting_for_login;
/** /**
* The packets are identical between the two versions * The packets are mostly the same but slightly different between the two versions
*/ */
auto *outapp = new EQApplicationPacket(OP_ChatMessage, sizeof(LoginHandShakeReply_Struct)); if (version == cv_sod) {
auto buf = reinterpret_cast<LoginHandShakeReply_Struct*>(outapp->pBuffer); auto *outapp = new EQApplicationPacket(OP_ChatMessage, 17);
buf->base_header.sequence = 0x02; outapp->pBuffer[0] = 0x02;
buf->base_reply.success = true; outapp->pBuffer[10] = 0x01;
buf->base_reply.error_str_id = 0x65; // 101 "No Error" outapp->pBuffer[11] = 0x65;
if (server.options.IsDumpOutPacketsOn()) { if (server.options.IsDumpOutPacketsOn()) {
DumpPacket(outapp); DumpPacket(outapp);
} }
m_connection->QueuePacket(outapp); connection->QueuePacket(outapp);
delete outapp; delete outapp;
} }
else {
const char *msg = "ChatMessage";
auto *outapp = new EQApplicationPacket(OP_ChatMessage, 16 + strlen(msg));
outapp->pBuffer[0] = 0x02;
outapp->pBuffer[10] = 0x01;
outapp->pBuffer[11] = 0x65;
strcpy((char *) (outapp->pBuffer + 15), msg);
if (server.options.IsDumpOutPacketsOn()) {
DumpPacket(outapp);
}
connection->QueuePacket(outapp);
delete outapp;
}
}
/** /**
* Verifies login and send a reply * Verifies login and send a reply
@@ -144,23 +179,19 @@ void Client::Handle_SessionReady(const char *data, unsigned int size)
*/ */
void Client::Handle_Login(const char *data, unsigned int size) void Client::Handle_Login(const char *data, unsigned int size)
{ {
if (m_client_status != cs_waiting_for_login) { if (status != cs_waiting_for_login) {
LogError("Login received after already having logged in"); LogError("Login received after already having logged in");
return; return;
} }
// login user/pass are variable length after unencrypted opcode and base message header (size includes opcode) if ((size - 12) % 8 != 0) {
constexpr int header_size = sizeof(uint16_t) + sizeof(LoginBaseMessage_Struct); LogError("Login received packet of size: {0}, this would cause a block corruption, discarding", size);
int data_size = size - header_size;
if (size <= header_size) {
LogError("Login received packet of size: {0}, this would cause a buffer overflow, discarding", size);
return; return;
} }
if (data_size % 8 != 0) { if (size < sizeof(LoginLoginRequest_Struct)) {
LogError("Login received packet of size: {0}, this would cause a block corruption, discarding", size); LogError("Login received packet of size: {0}, this would cause a buffer overflow, discarding", size);
return; return;
} }
@@ -177,14 +208,13 @@ void Client::Handle_Login(const char *data, unsigned int size)
std::string db_account_password_hash; std::string db_account_password_hash;
std::string outbuffer; std::string outbuffer;
outbuffer.resize(data_size); outbuffer.resize(size - 12);
if (outbuffer.length() == 0) { if (outbuffer.length() == 0) {
LogError("Corrupt buffer sent to server, no length"); LogError("Corrupt buffer sent to server, no length");
return; return;
} }
// data starts at base message header (opcode not included) auto r = eqcrypt_block(data + 10, size - 12, &outbuffer[0], 0);
auto r = eqcrypt_block(data + sizeof(LoginBaseMessage_Struct), data_size, &outbuffer[0], 0);
if (r == nullptr) { if (r == nullptr) {
LogError("Failed to decrypt eqcrypt block"); LogError("Failed to decrypt eqcrypt block");
return; return;
@@ -198,8 +228,7 @@ void Client::Handle_Login(const char *data, unsigned int size)
return; return;
} }
// only need to copy the base header for reply options, ignore login info memcpy(&llrs, data, sizeof(LoginLoginRequest_Struct));
memcpy(&m_llrs, data, sizeof(LoginBaseMessage_Struct));
bool result = false; bool result = false;
if (outbuffer[0] == 0 && outbuffer[1] == 0) { if (outbuffer[0] == 0 && outbuffer[1] == 0) {
@@ -207,7 +236,7 @@ void Client::Handle_Login(const char *data, unsigned int size)
cred = (&outbuffer[2 + user.length()]); cred = (&outbuffer[2 + user.length()]);
result = server.db->GetLoginTokenDataFromToken( result = server.db->GetLoginTokenDataFromToken(
cred, cred,
m_connection->GetRemoteAddr(), connection->GetRemoteAddr(),
db_account_id, db_account_id,
db_loginserver, db_loginserver,
user user
@@ -223,16 +252,11 @@ void Client::Handle_Login(const char *data, unsigned int size)
user = components[1]; user = components[1];
} }
// health checks
if (ProcessHealthCheck(user)) {
DoFailedLogin();
return;
}
LogInfo( LogInfo(
"Attempting password based login [{0}] login [{1}]", "Attempting password based login [{0}] login [{1}] user [{2}]",
user, user,
db_loginserver db_loginserver,
user
); );
ParseAccountString(user, user, db_loginserver); ParseAccountString(user, user, db_loginserver);
@@ -243,7 +267,7 @@ void Client::Handle_Login(const char *data, unsigned int size)
LogDebug("[VerifyLoginHash] Success [{0}]", (result ? "true" : "false")); LogDebug("[VerifyLoginHash] Success [{0}]", (result ? "true" : "false"));
} }
else { else {
m_client_status = cs_creating_account; status = cs_creating_account;
AttemptLoginAccountCreation(user, cred, db_loginserver); AttemptLoginAccountCreation(user, cred, db_loginserver);
return; return;
@@ -281,14 +305,14 @@ void Client::Handle_Login(const char *data, unsigned int size)
*/ */
void Client::Handle_Play(const char *data) void Client::Handle_Play(const char *data)
{ {
if (m_client_status != cs_logged_in) { if (status != cs_logged_in) {
LogError("Client sent a play request when they were not logged in, discarding"); LogError("Client sent a play request when they were not logged in, discarding");
return; return;
} }
const auto *play = (const PlayEverquestRequest_Struct *) data; const auto *play = (const PlayEverquestRequest_Struct *) data;
auto server_id_in = (unsigned int) play->server_number; auto server_id_in = (unsigned int) play->ServerNumber;
auto sequence_in = (unsigned int) play->base_header.sequence; auto sequence_in = (unsigned int) play->Sequence;
if (server.options.IsTraceOn()) { if (server.options.IsTraceOn()) {
LogInfo( LogInfo(
@@ -299,10 +323,10 @@ void Client::Handle_Play(const char *data)
); );
} }
m_play_server_id = (unsigned int) play->server_number; this->play_server_id = (unsigned int) play->ServerNumber;
m_play_sequence_id = sequence_in; play_sequence_id = sequence_in;
m_play_server_id = server_id_in; play_server_id = server_id_in;
server.server_manager->SendUserToWorldRequest(server_id_in, m_account_id, m_loginserver_name); server.server_manager->SendUserToWorldRequest(server_id_in, account_id, loginserver_name);
} }
/** /**
@@ -310,13 +334,14 @@ void Client::Handle_Play(const char *data)
*/ */
void Client::SendServerListPacket(uint32 seq) void Client::SendServerListPacket(uint32 seq)
{ {
auto outapp = server.server_manager->CreateServerListPacket(this, seq); EQApplicationPacket *outapp = server.server_manager->CreateServerListPacket(this, seq);
if (server.options.IsDumpOutPacketsOn()) { if (server.options.IsDumpOutPacketsOn()) {
DumpPacket(outapp.get()); DumpPacket(outapp);
} }
m_connection->QueuePacket(outapp.get()); connection->QueuePacket(outapp);
delete outapp;
} }
void Client::SendPlayResponse(EQApplicationPacket *outapp) void Client::SendPlayResponse(EQApplicationPacket *outapp)
@@ -325,12 +350,12 @@ void Client::SendPlayResponse(EQApplicationPacket *outapp)
LogDebug("Sending play response for {0}", GetAccountName()); LogDebug("Sending play response for {0}", GetAccountName());
// server_log->LogPacket(log_network_trace, (const char*)outapp->pBuffer, outapp->size); // server_log->LogPacket(log_network_trace, (const char*)outapp->pBuffer, outapp->size);
} }
m_connection->QueuePacket(outapp); connection->QueuePacket(outapp);
} }
void Client::GenerateKey() void Client::GenerateKey()
{ {
m_key.clear(); key.clear();
int count = 0; int count = 0;
while (count < 10) { while (count < 10) {
static const char key_selection[] = static const char key_selection[] =
@@ -342,7 +367,7 @@ void Client::GenerateKey()
'6', '7', '8', '9' '6', '7', '8', '9'
}; };
m_key.append((const char *) &key_selection[m_random.Int(0, 35)], 1); key.append((const char *) &key_selection[random.Int(0, 35)], 1);
count++; count++;
} }
} }
@@ -358,8 +383,6 @@ void Client::AttemptLoginAccountCreation(
const std::string &loginserver const std::string &loginserver
) )
{ {
LogInfo("[AttemptLoginAccountCreation] user [{}] loginserver [{}]", user, loginserver);
#ifdef LSPX #ifdef LSPX
if (loginserver == "eqemu") { if (loginserver == "eqemu") {
LogInfo("Attempting login account creation via '{0}'", loginserver); LogInfo("Attempting login account creation via '{0}'", loginserver);
@@ -370,21 +393,61 @@ void Client::AttemptLoginAccountCreation(
return; return;
} }
if (server.options.GetEQEmuLoginServerAddress().length() == 0) {
uint32 account_id = AccountManagement::CheckExternalLoginserverUserCredentials( DoFailedLogin();
user,
pass
);
if (account_id > 0) {
LogInfo("[AttemptLoginAccountCreation] Found and creating eqemu account [{}]", account_id);
CreateEQEmuAccount(user, pass, account_id);
return; return;
} }
auto addr_components = SplitString(server.options.GetEQEmuLoginServerAddress(), ':');
if (addr_components.size() != 2) {
DoFailedLogin(); DoFailedLogin();
return; return;
} }
stored_user = user;
stored_pass = pass;
auto address = addr_components[0];
auto port = std::stoi(addr_components[1]);
EQ::Net::DNSLookup(
address, port, false, [=](const std::string &addr) {
if (addr.empty()) {
DoFailedLogin();
return;
}
login_connection_manager.reset(new EQ::Net::DaybreakConnectionManager());
login_connection_manager->OnNewConnection(
std::bind(
&Client::LoginOnNewConnection,
this,
std::placeholders::_1
)
);
login_connection_manager->OnConnectionStateChange(
std::bind(
&Client::LoginOnStatusChange,
this,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3
)
);
login_connection_manager->OnPacketRecv(
std::bind(
&Client::LoginOnPacketRecv,
this,
std::placeholders::_1,
std::placeholders::_2
)
);
login_connection_manager->Connect(addr, port);
}
);
return;
}
#endif #endif
if (server.options.CanAutoCreateAccounts() && loginserver == "local") { if (server.options.CanAutoCreateAccounts() && loginserver == "local") {
@@ -398,36 +461,26 @@ void Client::AttemptLoginAccountCreation(
void Client::DoFailedLogin() void Client::DoFailedLogin()
{ {
m_stored_user.clear(); stored_user.clear();
m_stored_pass.clear(); stored_pass.clear();
// unencrypted EQApplicationPacket outapp(OP_LoginAccepted, sizeof(LoginLoginFailed_Struct));
LoginBaseMessage_Struct base_header{}; auto *login_failed = (LoginLoginFailed_Struct *) outapp.pBuffer;
base_header.sequence = m_llrs.sequence; // login (3)
base_header.encrypt_type = m_llrs.encrypt_type;
// encrypted login_failed->unknown1 = llrs.unknown1;
PlayerLoginReply_Struct login_reply{}; login_failed->unknown2 = llrs.unknown2;
login_reply.base_reply.success = false; login_failed->unknown3 = llrs.unknown3;
login_reply.base_reply.error_str_id = 105; // Error - The username and/or password were not valid login_failed->unknown4 = llrs.unknown4;
login_failed->unknown5 = llrs.unknown5;
char encrypted_buffer[80] = {0}; memcpy(login_failed->unknown6, FailedLoginResponseData, sizeof(FailedLoginResponseData));
auto rc = eqcrypt_block((const char*)&login_reply, sizeof(login_reply), encrypted_buffer, 1);
if (rc == nullptr) {
LogDebug("Failed to encrypt eqcrypt block for failed login");
}
constexpr int outsize = sizeof(LoginBaseMessage_Struct) + sizeof(encrypted_buffer);
EQApplicationPacket outapp(OP_LoginAccepted, outsize);
outapp.WriteData(&base_header, sizeof(base_header));
outapp.WriteData(&encrypted_buffer, sizeof(encrypted_buffer));
if (server.options.IsDumpOutPacketsOn()) { if (server.options.IsDumpOutPacketsOn()) {
DumpPacket(&outapp); DumpPacket(&outapp);
} }
m_connection->QueuePacket(&outapp); connection->QueuePacket(&outapp);
m_client_status = cs_failed_to_login; status = cs_failed_to_login;
} }
/** /**
@@ -523,64 +576,68 @@ void Client::DoSuccessfulLogin(
const std::string &db_loginserver const std::string &db_loginserver
) )
{ {
m_stored_user.clear(); stored_user.clear();
m_stored_pass.clear(); stored_pass.clear();
server.client_manager->RemoveExistingClient(db_account_id, db_loginserver); server.client_manager->RemoveExistingClient(db_account_id, db_loginserver);
in_addr in{}; in_addr in{};
in.s_addr = m_connection->GetRemoteIP(); in.s_addr = connection->GetRemoteIP();
server.db->UpdateLSAccountData(db_account_id, std::string(inet_ntoa(in))); server.db->UpdateLSAccountData(db_account_id, std::string(inet_ntoa(in)));
GenerateKey(); GenerateKey();
m_account_id = db_account_id; account_id = db_account_id;
m_account_name = in_account_name; account_name = in_account_name;
m_loginserver_name = db_loginserver; loginserver_name = db_loginserver;
// unencrypted auto *outapp = new EQApplicationPacket(OP_LoginAccepted, 10 + 80);
LoginBaseMessage_Struct base_header{}; auto *login_accepted = (LoginAccepted_Struct *) outapp->pBuffer;
base_header.sequence = m_llrs.sequence; login_accepted->unknown1 = llrs.unknown1;
base_header.compressed = false; login_accepted->unknown2 = llrs.unknown2;
base_header.encrypt_type = m_llrs.encrypt_type; login_accepted->unknown3 = llrs.unknown3;
base_header.unk3 = m_llrs.unk3; login_accepted->unknown4 = llrs.unknown4;
login_accepted->unknown5 = llrs.unknown5;
// not serializing any of the variable length strings so just use struct directly auto *login_failed_attempts = new LoginFailedAttempts_Struct;
PlayerLoginReply_Struct login_reply{}; memset(login_failed_attempts, 0, sizeof(LoginFailedAttempts_Struct));
login_reply.base_reply.success = true;
login_reply.base_reply.error_str_id = 101; // No Error login_failed_attempts->failed_attempts = 0;
login_reply.unk1 = 0; login_failed_attempts->message = 0x01;
login_reply.unk2 = 0; login_failed_attempts->lsid = db_account_id;
login_reply.lsid = db_account_id; login_failed_attempts->unknown3[3] = 0x03;
login_reply.failed_attempts = 0; login_failed_attempts->unknown4[3] = 0x02;
login_reply.show_player_count = server.options.IsShowPlayerCountEnabled(); login_failed_attempts->unknown5[0] = 0xe7;
login_reply.offer_min_days = 99; login_failed_attempts->unknown5[1] = 0x03;
login_reply.offer_min_views = -1; login_failed_attempts->unknown6[0] = 0xff;
login_reply.offer_cooldown_minutes = 0; login_failed_attempts->unknown6[1] = 0xff;
login_reply.web_offer_number = 0; login_failed_attempts->unknown6[2] = 0xff;
login_reply.web_offer_min_days = 99; login_failed_attempts->unknown6[3] = 0xff;
login_reply.web_offer_min_views = -1; login_failed_attempts->unknown7[0] = 0xa0;
login_reply.web_offer_cooldown_minutes = 0; login_failed_attempts->unknown7[1] = 0x05;
memcpy(login_reply.key, m_key.c_str(), m_key.size()); login_failed_attempts->unknown8[3] = 0x02;
login_failed_attempts->unknown9[0] = 0xff;
login_failed_attempts->unknown9[1] = 0x03;
login_failed_attempts->unknown11[0] = 0x63;
login_failed_attempts->unknown12[0] = 0x01;
memcpy(login_failed_attempts->key, key.c_str(), key.size());
char encrypted_buffer[80] = {0}; char encrypted_buffer[80] = {0};
auto rc = eqcrypt_block((const char*)&login_reply, sizeof(login_reply), encrypted_buffer, 1); auto rc = eqcrypt_block((const char *) login_failed_attempts, 75, encrypted_buffer, 1);
if (rc == nullptr) { if (rc == nullptr) {
LogDebug("Failed to encrypt eqcrypt block"); LogDebug("Failed to encrypt eqcrypt block");
} }
constexpr int outsize = sizeof(LoginBaseMessage_Struct) + sizeof(encrypted_buffer); memcpy(login_accepted->encrypt, encrypted_buffer, 80);
auto outapp = std::make_unique<EQApplicationPacket>(OP_LoginAccepted, outsize);
outapp->WriteData(&base_header, sizeof(base_header));
outapp->WriteData(&encrypted_buffer, sizeof(encrypted_buffer));
if (server.options.IsDumpOutPacketsOn()) { if (server.options.IsDumpOutPacketsOn()) {
DumpPacket(outapp.get()); DumpPacket(outapp);
} }
m_connection->QueuePacket(outapp.get()); connection->QueuePacket(outapp);
delete outapp;
m_client_status = cs_logged_in; status = cs_logged_in;
} }
/** /**
@@ -632,7 +689,7 @@ void Client::CreateEQEmuAccount(
*/ */
void Client::LoginOnNewConnection(std::shared_ptr<EQ::Net::DaybreakConnection> connection) void Client::LoginOnNewConnection(std::shared_ptr<EQ::Net::DaybreakConnection> connection)
{ {
m_login_connection = connection; login_connection = connection;
} }
/** /**
@@ -694,16 +751,16 @@ void Client::LoginSendSessionReady()
p.PutUInt16(0, 1); //OP_SessionReady p.PutUInt16(0, 1); //OP_SessionReady
p.PutUInt32(2, 2); p.PutUInt32(2, 2);
m_login_connection->QueuePacket(p); login_connection->QueuePacket(p);
} }
void Client::LoginSendLogin() void Client::LoginSendLogin()
{ {
size_t buffer_len = m_stored_user.length() + m_stored_pass.length() + 2; size_t buffer_len = stored_user.length() + stored_pass.length() + 2;
std::unique_ptr<char[]> buffer(new char[buffer_len]); std::unique_ptr<char[]> buffer(new char[buffer_len]);
strcpy(&buffer[0], m_stored_user.c_str()); strcpy(&buffer[0], stored_user.c_str());
strcpy(&buffer[m_stored_user.length() + 1], m_stored_pass.c_str()); strcpy(&buffer[stored_user.length() + 1], stored_pass.c_str());
size_t encrypted_len = buffer_len; size_t encrypted_len = buffer_len;
@@ -718,7 +775,7 @@ void Client::LoginSendLogin()
eqcrypt_block(&buffer[0], buffer_len, (char *) p.Data() + 12, true); eqcrypt_block(&buffer[0], buffer_len, (char *) p.Data() + 12, true);
m_login_connection->QueuePacket(p); login_connection->QueuePacket(p);
} }
/** /**
@@ -739,7 +796,7 @@ void Client::LoginProcessLoginResponse(const EQ::Net::Packet &p)
EQ::Net::StaticPacket sp(&decrypted[0], encrypt_size); EQ::Net::StaticPacket sp(&decrypted[0], encrypt_size);
auto response_error = sp.GetUInt16(1); auto response_error = sp.GetUInt16(1);
m_login_connection_manager->OnConnectionStateChange( login_connection_manager->OnConnectionStateChange(
std::bind( std::bind(
&Client::LoginOnStatusChangeIgnored, &Client::LoginOnStatusChangeIgnored,
this, this,
@@ -752,26 +809,18 @@ void Client::LoginProcessLoginResponse(const EQ::Net::Packet &p)
if (response_error > 101) { if (response_error > 101) {
LogDebug("response [{0}] failed login", response_error); LogDebug("response [{0}] failed login", response_error);
DoFailedLogin(); DoFailedLogin();
m_login_connection->Close(); login_connection->Close();
} }
else { else {
LogDebug( LogDebug(
"response [{0}] login succeeded user [{1}]", "response [{0}] login succeeded user [{1}]",
response_error, response_error,
m_stored_user stored_user
); );
auto m_dbid = sp.GetUInt32(8); auto m_dbid = sp.GetUInt32(8);
CreateEQEmuAccount(m_stored_user, m_stored_pass, m_dbid); CreateEQEmuAccount(stored_user, stored_pass, m_dbid);
m_login_connection->Close(); login_connection->Close();
} }
} }
bool Client::ProcessHealthCheck(std::string username)
{
if (username == "healthcheckuser") {
return true;
}
return false;
}
+56 -24
View File
@@ -1,3 +1,23 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 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_CLIENT_H #ifndef EQEMU_CLIENT_H
#define EQEMU_CLIENT_H #define EQEMU_CLIENT_H
@@ -7,9 +27,22 @@
#include "../common/eq_stream_intf.h" #include "../common/eq_stream_intf.h"
#include "../common/net/dns.h" #include "../common/net/dns.h"
#include "../common/net/daybreak_connection.h" #include "../common/net/daybreak_connection.h"
#include "login_types.h" #include "login_structures.h"
#include <memory> #include <memory>
enum LSClientVersion {
cv_titanium,
cv_sod
};
enum LSClientStatus {
cs_not_sent_session_ready,
cs_waiting_for_login,
cs_creating_account,
cs_failed_to_login,
cs_logged_in
};
/** /**
* Client class, controls a single client and it's connection to the login server * Client class, controls a single client and it's connection to the login server
*/ */
@@ -83,49 +116,49 @@ public:
* *
* @return * @return
*/ */
unsigned int GetAccountID() const { return m_account_id; } unsigned int GetAccountID() const { return account_id; }
/** /**
* Gets the loginserver name of this client * Gets the loginserver name of this client
* *
* @return * @return
*/ */
std::string GetLoginServerName() const { return m_loginserver_name; } std::string GetLoginServerName() const { return loginserver_name; }
/** /**
* Gets the account name of this client * Gets the account name of this client
* *
* @return * @return
*/ */
std::string GetAccountName() const { return m_account_name; } std::string GetAccountName() const { return account_name; }
/** /**
* Gets the key generated at login for this client * Gets the key generated at login for this client
* *
* @return * @return
*/ */
std::string GetKey() const { return m_key; } std::string GetKey() const { return key; }
/** /**
* Gets the server selected to be played on for this client * Gets the server selected to be played on for this client
* *
* @return * @return
*/ */
unsigned int GetPlayServerID() const { return m_play_server_id; } unsigned int GetPlayServerID() const { return play_server_id; }
/** /**
* Gets the play sequence state for this client * Gets the play sequence state for this client
* *
* @return * @return
*/ */
unsigned int GetPlaySequence() const { return m_play_sequence_id; } unsigned int GetPlaySequence() const { return play_sequence_id; }
/** /**
* Gets the connection for this client * Gets the connection for this client
* *
* @return * @return
*/ */
std::shared_ptr<EQStreamInterface> GetConnection() { return m_connection; } std::shared_ptr<EQStreamInterface> GetConnection() { return connection; }
/** /**
* Attempts to create a login account * Attempts to create a login account
@@ -162,24 +195,24 @@ public:
void CreateEQEmuAccount(const std::string &in_account_name, const std::string &in_account_password, unsigned int loginserver_account_id); void CreateEQEmuAccount(const std::string &in_account_name, const std::string &in_account_password, unsigned int loginserver_account_id);
private: private:
EQ::Random m_random; EQ::Random random;
std::shared_ptr<EQStreamInterface> m_connection; std::shared_ptr<EQStreamInterface> connection;
LSClientVersion m_client_version; LSClientVersion version;
LSClientStatus m_client_status; LSClientStatus status;
std::string m_account_name; std::string account_name;
unsigned int m_account_id; unsigned int account_id;
std::string m_loginserver_name; std::string loginserver_name;
unsigned int m_play_server_id; unsigned int play_server_id;
unsigned int m_play_sequence_id; unsigned int play_sequence_id;
std::string m_key; std::string key;
std::unique_ptr<EQ::Net::DaybreakConnectionManager> m_login_connection_manager; std::unique_ptr<EQ::Net::DaybreakConnectionManager> login_connection_manager;
std::shared_ptr<EQ::Net::DaybreakConnection> m_login_connection; std::shared_ptr<EQ::Net::DaybreakConnection> login_connection;
LoginBaseMessage_Struct m_llrs; LoginLoginRequest_Struct llrs;
std::string m_stored_user; std::string stored_user;
std::string m_stored_pass; std::string stored_pass;
void LoginOnNewConnection(std::shared_ptr<EQ::Net::DaybreakConnection> connection); void LoginOnNewConnection(std::shared_ptr<EQ::Net::DaybreakConnection> connection);
void LoginOnStatusChange( void LoginOnStatusChange(
std::shared_ptr<EQ::Net::DaybreakConnection> conn, std::shared_ptr<EQ::Net::DaybreakConnection> conn,
@@ -195,7 +228,6 @@ private:
void LoginSendSessionReady(); void LoginSendSessionReady();
void LoginSendLogin(); void LoginSendLogin();
void LoginProcessLoginResponse(const EQ::Net::Packet &p); void LoginProcessLoginResponse(const EQ::Net::Packet &p);
static bool ProcessHealthCheck(std::string username);
}; };
#endif #endif
+25 -6
View File
@@ -1,3 +1,23 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 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 "client_manager.h" #include "client_manager.h"
#include "login_server.h" #include "login_server.h"
@@ -5,7 +25,6 @@ extern LoginServer server;
extern bool run_server; extern bool run_server;
#include "../common/eqemu_logsys.h" #include "../common/eqemu_logsys.h"
#include "../common/misc.h"
ClientManager::ClientManager() ClientManager::ClientManager()
{ {
@@ -33,8 +52,8 @@ ClientManager::ClientManager()
titanium_stream->OnNewConnection( titanium_stream->OnNewConnection(
[this](std::shared_ptr<EQ::Net::EQStream> stream) { [this](std::shared_ptr<EQ::Net::EQStream> stream) {
LogInfo( LogInfo(
"New Titanium client connection from [{0}:{1}]", "New Titanium client connection from {0}:{1}",
long2ip(stream->GetRemoteIP()), stream->GetRemoteIP(),
stream->GetRemotePort() stream->GetRemotePort()
); );
@@ -68,13 +87,13 @@ ClientManager::ClientManager()
sod_stream->OnNewConnection( sod_stream->OnNewConnection(
[this](std::shared_ptr<EQ::Net::EQStream> stream) { [this](std::shared_ptr<EQ::Net::EQStream> stream) {
LogInfo( LogInfo(
"New SoD+ client connection from [{0}:{1}]", "New SoD client connection from {0}:{1}",
long2ip(stream->GetRemoteIP()), stream->GetRemoteIP(),
stream->GetRemotePort() stream->GetRemotePort()
); );
stream->SetOpcodeManager(&sod_ops); stream->SetOpcodeManager(&sod_ops);
auto *c = new Client(stream, cv_sod); Client *c = new Client(stream, cv_sod);
clients.push_back(c); clients.push_back(c);
} }
); );
+20
View File
@@ -1,3 +1,23 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 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_CLIENTMANAGER_H #ifndef EQEMU_CLIENTMANAGER_H
#define EQEMU_CLIENTMANAGER_H #define EQEMU_CLIENTMANAGER_H
+66 -44
View File
@@ -1,3 +1,23 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 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 "../common/global_define.h" #include "../common/global_define.h"
#include "database.h" #include "database.h"
@@ -25,6 +45,11 @@ Database::Database(
std::string name std::string name
) )
{ {
this->user = user;
this->pass = pass;
this->host = host;
this->name = name;
uint32 errnum = 0; uint32 errnum = 0;
char errbuf[MYSQL_ERRMSG_SIZE]; char errbuf[MYSQL_ERRMSG_SIZE];
if (!Open( if (!Open(
@@ -50,8 +75,8 @@ Database::Database(
*/ */
Database::~Database() Database::~Database()
{ {
if (m_database) { if (database) {
mysql_close(m_database); mysql_close(database);
} }
} }
@@ -330,13 +355,11 @@ void Database::UpdateLoginserverAccountPasswordHash(
/** /**
* @param short_name * @param short_name
* @param long_name
* @param login_world_server_admin_id * @param login_world_server_admin_id
* @return * @return
*/ */
Database::DbWorldRegistration Database::GetWorldRegistration( Database::DbWorldRegistration Database::GetWorldRegistration(
const std::string &short_name, const std::string &short_name,
const std::string &long_name,
uint32 login_world_server_admin_id uint32 login_world_server_admin_id
) )
{ {
@@ -352,46 +375,45 @@ Database::DbWorldRegistration Database::GetWorldRegistration(
" login_world_servers AS WSR\n" " login_world_servers AS WSR\n"
" JOIN login_server_list_types AS SLT ON WSR.login_server_list_type_id = SLT.id\n" " JOIN login_server_list_types AS SLT ON WSR.login_server_list_type_id = SLT.id\n"
"WHERE\n" "WHERE\n"
" WSR.short_name = '{}' AND WSR.long_name = '{}' AND WSR.login_server_admin_id = {} LIMIT 1", " WSR.short_name = '{0}' AND WSR.login_server_admin_id = {1} LIMIT 1",
EscapeString(short_name), EscapeString(short_name),
EscapeString(long_name),
login_world_server_admin_id login_world_server_admin_id
); );
Database::DbWorldRegistration r{}; Database::DbWorldRegistration world_registration{};
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
if (!results.Success() || results.RowCount() != 1) { if (!results.Success() || results.RowCount() != 1) {
return r; return world_registration;
} }
auto row = results.begin(); auto row = results.begin();
r.loaded = true; world_registration.loaded = true;
r.server_id = std::stoi(row[0]); world_registration.server_id = std::stoi(row[0]);
r.server_description = row[1]; world_registration.server_description = row[1];
r.server_list_type = std::stoi(row[3]); world_registration.server_list_type = std::stoi(row[3]);
r.is_server_trusted = std::stoi(row[2]) > 0; world_registration.is_server_trusted = std::stoi(row[2]) > 0;
r.server_list_description = row[4]; world_registration.server_list_description = row[4];
r.server_admin_id = std::stoi(row[5]); world_registration.server_admin_id = std::stoi(row[5]);
if (r.server_admin_id <= 0) { if (world_registration.server_admin_id <= 0) {
return r; return world_registration;
} }
auto world_registration_query = fmt::format( auto world_registration_query = fmt::format(
"SELECT account_name, account_password FROM login_server_admins WHERE id = {0} LIMIT 1", "SELECT account_name, account_password FROM login_server_admins WHERE id = {0} LIMIT 1",
r.server_admin_id world_registration.server_admin_id
); );
auto world_registration_results = QueryDatabase(world_registration_query); auto world_registration_results = QueryDatabase(world_registration_query);
if (world_registration_results.Success() && world_registration_results.RowCount() == 1) { if (world_registration_results.Success() && world_registration_results.RowCount() == 1) {
auto world_registration_row = world_registration_results.begin(); auto world_registration_row = world_registration_results.begin();
r.server_admin_account_name = world_registration_row[0]; world_registration.server_admin_account_name = world_registration_row[0];
r.server_admin_account_password = world_registration_row[1]; world_registration.server_admin_account_password = world_registration_row[1];
} }
return r; return world_registration;
} }
/** /**
@@ -643,21 +665,21 @@ Database::DbLoginServerAdmin Database::GetLoginServerAdmin(const std::string &ac
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
Database::DbLoginServerAdmin r{}; Database::DbLoginServerAdmin login_server_admin{};
if (results.RowCount() == 1) { if (results.RowCount() == 1) {
auto row = results.begin(); auto row = results.begin();
r.loaded = true; login_server_admin.loaded = true;
r.id = std::stoi(row[0]); login_server_admin.id = std::stoi(row[0]);
r.account_name = row[1]; login_server_admin.account_name = row[1];
r.account_password = row[2]; login_server_admin.account_password = row[2];
r.first_name = row[3]; login_server_admin.first_name = row[3];
r.last_name = row[4]; login_server_admin.last_name = row[4];
r.email = row[5]; login_server_admin.email = row[5];
r.registration_date = row[7]; login_server_admin.registration_date = row[7];
r.registration_ip_address = row[8]; login_server_admin.registration_ip_address = row[8];
} }
return r; return login_server_admin;
} }
/** /**
@@ -679,20 +701,20 @@ Database::DbLoginServerAccount Database::GetLoginServerAccountByAccountName(
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
Database::DbLoginServerAccount r{}; Database::DbLoginServerAccount login_server_account{};
if (results.RowCount() == 1) { if (results.RowCount() == 1) {
auto row = results.begin(); auto row = results.begin();
r.loaded = true; login_server_account.loaded = true;
r.id = std::stoi(row[0]); login_server_account.id = std::stoi(row[0]);
r.account_name = row[1]; login_server_account.account_name = row[1];
r.account_password = row[2]; login_server_account.account_password = row[2];
r.account_email = row[3]; login_server_account.account_email = row[3];
r.source_loginserver = row[4]; login_server_account.source_loginserver = row[4];
r.last_ip_address = row[5]; login_server_account.last_ip_address = row[5];
r.last_login_date = row[6]; login_server_account.last_login_date = row[6];
r.created_at = row[7]; login_server_account.created_at = row[7];
r.updated_at = row[8]; login_server_account.updated_at = row[8];
} }
return r; return login_server_account;
} }
+24 -5
View File
@@ -1,3 +1,23 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 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_DATABASEMYSQL_H #ifndef EQEMU_DATABASEMYSQL_H
#define EQEMU_DATABASEMYSQL_H #define EQEMU_DATABASEMYSQL_H
@@ -12,7 +32,7 @@
class Database : public DBcore { class Database : public DBcore {
public: public:
Database() { m_database = nullptr; } Database() { database = nullptr; }
/** /**
* Constructor, tries to set our database to connect to the supplied options. * Constructor, tries to set our database to connect to the supplied options.
@@ -29,7 +49,7 @@ public:
* Destructor, frees our database if needed. * Destructor, frees our database if needed.
*/ */
~Database(); ~Database();
bool IsConnected() { return (m_database != nullptr); } bool IsConnected() { return (database != nullptr); }
/** /**
* Retrieves the login data (password hash and account id) from the account name provided needed for client login procedure. * Retrieves the login data (password hash and account id) from the account name provided needed for client login procedure.
@@ -138,13 +158,11 @@ public:
* Returns true if the record was found, false otherwise * Returns true if the record was found, false otherwise
* *
* @param short_name * @param short_name
* @param long_name
* @param login_world_server_admin_id * @param login_world_server_admin_id
* @return * @return
*/ */
Database::DbWorldRegistration GetWorldRegistration( Database::DbWorldRegistration GetWorldRegistration(
const std::string &short_name, const std::string &short_name,
const std::string &long_name,
uint32 login_world_server_admin_id uint32 login_world_server_admin_id
); );
@@ -280,7 +298,8 @@ public:
); );
protected: protected:
MYSQL *m_database{}; std::string user, pass, host, port, name;
MYSQL *database{};
}; };
#endif #endif
+20
View File
@@ -1,3 +1,23 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 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
*
*/
#pragma once #pragma once
#include <string> #include <string>
+20
View File
@@ -1,3 +1,23 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 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 EQEMUCAPI__H #ifndef EQEMUCAPI__H
#define EQEMUCAPI__H #define EQEMUCAPI__H
+23 -1
View File
@@ -1,7 +1,29 @@
#include <utility>
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 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_LOGINSERVER_H #ifndef EQEMU_LOGINSERVER_H
#define EQEMU_LOGINSERVER_H #define EQEMU_LOGINSERVER_H
#include <utility>
#include "../common/json_config.h" #include "../common/json_config.h"
#include "database.h" #include "database.h"
#include "encryption.h" #include "encryption.h"
+117
View File
@@ -0,0 +1,117 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 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_LOGINSTRUCTURES_H
#define EQEMU_LOGINSTRUCTURES_H
#pragma pack(1)
struct LoginChatMessage_Struct {
short Unknown0;
uint32 Unknown1;
uint32 Unknown2;
uint32 Unknown3;
uint8 Unknown4;
char ChatMessage[1];
};
struct LoginLoginRequest_Struct {
short unknown1;
short unknown2;
short unknown3;
short unknown4;
short unknown5;
char unknown6[16];
};
struct LoginAccepted_Struct {
short unknown1;
short unknown2;
short unknown3;
short unknown4;
short unknown5;
char encrypt[80];
};
struct LoginFailedAttempts_Struct {
char message; //0x01
char unknown2[7]; //0x00
uint32 lsid;
char key[11]; //10 char + null term;
uint32 failed_attempts;
char unknown3[4]; //0x00, 0x00, 0x00, 0x03
char unknown4[4]; //0x00, 0x00, 0x00, 0x02
char unknown5[4]; //0xe7, 0x03, 0x00, 0x00
char unknown6[4]; //0xff, 0xff, 0xff, 0xff
char unknown7[4]; //0xa0, 0x05, 0x00, 0x00
char unknown8[4]; //0x00, 0x00, 0x00, 0x02
char unknown9[4]; //0xff, 0x03, 0x00, 0x00
char unknown10[4]; //0x00, 0x00, 0x00, 0x00
char unknown11[4]; //0x63, 0x00, 0x00, 0x00
char unknown12[4]; //0x01, 0x00, 0x00, 0x00
char unknown13[4]; //0x00, 0x00, 0x00, 0x00
char unknown14[4]; //0x00, 0x00, 0x00, 0x00
};
struct LoginLoginFailed_Struct {
short unknown1;
short unknown2;
short unknown3;
short unknown4;
short unknown5;
char unknown6[74];
};
struct ServerListHeader_Struct {
uint32 Unknown1;
uint32 Unknown2;
uint32 Unknown3;
uint32 Unknown4;
uint32 NumberOfServers;
};
struct PlayEverquestRequest_Struct {
uint16 Sequence;
uint32 Unknown1;
uint32 Unknown2;
uint32 ServerNumber;
};
struct PlayEverquestResponse_Struct {
uint8 Sequence;
uint8 Unknown1[9];
uint8 Allowed;
uint16 Message;
uint8 Unknown2[3];
uint32 ServerNumber;
};
static const unsigned char FailedLoginResponseData[] = {
0xf6, 0x85, 0x9c, 0x23, 0x57, 0x7e, 0x3e, 0x55, 0xb3, 0x4c, 0xf8, 0xc8, 0xcb, 0x77, 0xd5, 0x16,
0x09, 0x7a, 0x63, 0xdc, 0x57, 0x7e, 0x3e, 0x55, 0xb3, 0x4c, 0xf8, 0xc8, 0xcb, 0x77, 0xd5, 0x16,
0x09, 0x7a, 0x63, 0xdc, 0x57, 0x7e, 0x3e, 0x55, 0xb3
};
#pragma pack()
#endif
-143
View File
@@ -1,143 +0,0 @@
#ifndef EQEMU_LOGINSTRUCTURES_H
#define EQEMU_LOGINSTRUCTURES_H
#pragma pack(1)
// unencrypted base message header in all packets
struct LoginBaseMessage_Struct {
int32_t sequence; // request type/login sequence (2: handshake, 3: login, 4: serverlist, ...)
bool compressed; // true: deflated
int8_t encrypt_type; // 1: invert (unused) 2: des (2 for encrypted player logins and order expansions) (client uses what it sent, ignores in reply)
int32_t unk3; // unused?
};
struct LoginBaseReplyMessage_Struct {
bool success; // 0: failure (shows error string) 1: success
int32_t error_str_id; // last error eqlsstr id, default: 101 (no error)
char str[1]; // variable length, unknown (may be unused, this struct is a common pattern elsewhere)
};
struct LoginHandShakeReply_Struct {
LoginBaseMessage_Struct base_header;
LoginBaseReplyMessage_Struct base_reply;
char unknown[1]; // variable length string
};
// for reference, login buffer is variable (minimum size 8 due to encryption)
struct PlayerLogin_Struct {
LoginBaseMessage_Struct base_header;
char username[1];
char password[1];
};
// variable length, can use directly if not serializing strings
struct PlayerLoginReply_Struct {
// base header excluded to make struct data easier to encrypt
//LoginBaseMessage_Struct base_header;
LoginBaseReplyMessage_Struct base_reply;
int8_t unk1; // (default: 0)
int8_t unk2; // (default: 0)
int32_t lsid; // (default: -1)
char key[11]; // client reads until null (variable length)
int32_t failed_attempts;
bool show_player_count; // admin flag, enables admin button and shows server player counts (default: false)
int32_t offer_min_days; // guess, needs more investigation, maybe expansion offers (default: 99)
int32_t offer_min_views; // guess (default: -1)
int32_t offer_cooldown_minutes; // guess (default: 0)
int32_t web_offer_number; // web order view number, 0 nothing (default: 0)
int32_t web_offer_min_days; // number of days to show offer (based on first offer time in client eqls ini) (default: 99)
int32_t web_offer_min_views; // mininum views, -1 for no minimum, 0 for never shows (based on client eqls ini) (default: -1)
int32_t web_offer_cooldown_minutes; // minimum minutes between offers (based on last offer time in client eqls ini) (default: 0)
char username[1]; // variable length, if not empty client attempts to re-login to server select when quitting from char select and sends this in a struct
char unknown[1]; // variable length, password unlikely? client doesn't send this on re-login from char select
};
// variable length, for reference
struct LoginClientServerData_Struct {
char ip[1];
int32_t server_type; // legends, preferred, standard
int32_t server_id;
char server_name[1];
char country_code[1]; // if doesn't match client locale then server is colored dark grey in list and joining is prevented (to block for "us" use one of "kr", "tw", "jp", "de", "fr", or "cn") (ISO 3166-1 alpha-2)
char language_code[1];
int32_t server_status; // see ServerStatusFlags
int32_t player_count;
};
// variable length, for reference
struct ServerListReply_Struct {
LoginBaseMessage_Struct base_header;
LoginBaseReplyMessage_Struct base_reply;
int32_t server_count;
LoginClientServerData_Struct servers[0];
};
struct PlayEverquestRequest_Struct {
LoginBaseMessage_Struct base_header;
uint32 server_number;
};
// SCJoinServerReply
struct PlayEverquestResponse_Struct {
LoginBaseMessage_Struct base_header;
LoginBaseReplyMessage_Struct base_reply;
uint32 server_number;
};
#pragma pack()
enum LSClientVersion {
cv_titanium,
cv_sod
};
enum LSClientStatus {
cs_not_sent_session_ready,
cs_waiting_for_login,
cs_creating_account,
cs_failed_to_login,
cs_logged_in
};
namespace LS {
namespace ServerStatusFlags {
enum eServerStatusFlags {
Up = 0, // default
Down = 1,
Unused = 2,
Locked = 4 // can be combined with Down to show "Locked (Down)"
};
}
namespace ServerTypeFlags {
enum eServerTypeFlags {
None = 0,
Standard = 1,
Unknown2 = 2,
Unknown4 = 4,
Preferred = 8,
Legends = 16 // can be combined with Preferred flag to override color in Legends section with Preferred color (green)
};
}
enum ServerType {
Standard = 3,
Preferred = 2,
Legends = 1,
};
namespace ErrStr {
constexpr static int ERROR_NONE = 101; // No Error
constexpr static int ERROR_UNKNOWN = 102; // Error - Unknown Error Occurred
constexpr static int ERROR_ACTIVE_CHARACTER = 111; // Error 1018: You currently have an active character on that EverQuest Server, please allow a minute for synchronization and try again.
constexpr static int ERROR_SERVER_UNAVAILABLE = 326; // That server is currently unavailable. Please check the EverQuest webpage for current server status and try again later.
constexpr static int ERROR_ACCOUNT_SUSPENDED = 337; // This account is currently suspended. Please contact customer service for more information.
constexpr static int ERROR_ACCOUNT_BANNED = 338; // This account is currently banned. Please contact customer service for more information.
constexpr static int ERROR_WORLD_MAX_CAPACITY = 339; // The world server is currently at maximum capacity and not allowing further logins until the number of players online decreases. Please try again later.
};
}
#endif
-3
View File
@@ -11,9 +11,6 @@
}, },
"worldservers": { "worldservers": {
"unregistered_allowed": true, "unregistered_allowed": true,
"show_player_count": false,
"dev_test_servers_list_bottom": false,
"special_character_start_list_bottom": false,
"reject_duplicate_servers": false "reject_duplicate_servers": false
}, },
"web_api": { "web_api": {
+3 -3
View File
@@ -5,7 +5,7 @@ CREATE TABLE `login_accounts` (
`account_password` text NOT NULL, `account_password` text NOT NULL,
`account_email` varchar(100) NOT NULL, `account_email` varchar(100) NOT NULL,
`source_loginserver` varchar(64) DEFAULT NULL, `source_loginserver` varchar(64) DEFAULT NULL,
`last_ip_address` varchar(30) NOT NULL, `last_ip_address` varchar(15) NOT NULL,
`last_login_date` datetime NOT NULL, `last_login_date` datetime NOT NULL,
`created_at` datetime DEFAULT NULL, `created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT current_timestamp(), `updated_at` datetime DEFAULT current_timestamp(),
@@ -22,7 +22,7 @@ CREATE TABLE `login_server_admins` (
`last_name` varchar(50) NOT NULL, `last_name` varchar(50) NOT NULL,
`email` varchar(100) NOT NULL, `email` varchar(100) NOT NULL,
`registration_date` datetime NOT NULL, `registration_date` datetime NOT NULL,
`registration_ip_address` varchar(30) NOT NULL, `registration_ip_address` varchar(15) NOT NULL,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
@@ -45,7 +45,7 @@ CREATE TABLE `login_world_servers` (
`tag_description` varchar(50) NOT NULL DEFAULT '', `tag_description` varchar(50) NOT NULL DEFAULT '',
`login_server_list_type_id` int(11) NOT NULL, `login_server_list_type_id` int(11) NOT NULL,
`last_login_date` datetime DEFAULT NULL, `last_login_date` datetime DEFAULT NULL,
`last_ip_address` varchar(30) DEFAULT NULL, `last_ip_address` varchar(15) DEFAULT NULL,
`login_server_admin_id` int(11) NOT NULL, `login_server_admin_id` int(11) NOT NULL,
`is_server_trusted` int(11) NOT NULL, `is_server_trusted` int(11) NOT NULL,
`note` varchar(255) DEFAULT NULL, `note` varchar(255) DEFAULT NULL,
+20 -21
View File
@@ -1,3 +1,23 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 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 <iostream> #include <iostream>
#include <random> #include <random>
#include "loginserver_command_handler.h" #include "loginserver_command_handler.h"
@@ -38,7 +58,6 @@ namespace LoginserverCommandHandler {
function_map["web-api-token:list"] = &LoginserverCommandHandler::ListLoginserverApiTokens; function_map["web-api-token:list"] = &LoginserverCommandHandler::ListLoginserverApiTokens;
function_map["world-admin:create"] = &LoginserverCommandHandler::CreateLoginserverWorldAdminAccount; function_map["world-admin:create"] = &LoginserverCommandHandler::CreateLoginserverWorldAdminAccount;
function_map["world-admin:update"] = &LoginserverCommandHandler::UpdateLoginserverWorldAdminAccountPassword; function_map["world-admin:update"] = &LoginserverCommandHandler::UpdateLoginserverWorldAdminAccountPassword;
function_map["health:check-login"] = &LoginserverCommandHandler::HealthCheckLogin;
EQEmuCommand::HandleMenu(function_map, cmd, argc, argv); EQEmuCommand::HandleMenu(function_map, cmd, argc, argv);
} }
@@ -282,24 +301,4 @@ namespace LoginserverCommandHandler {
cmd(3).str() cmd(3).str()
); );
} }
/**
* @param argc
* @param argv
* @param cmd
* @param description
*/
void HealthCheckLogin(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Checks login health using a test user";
std::vector<std::string> arguments = {};
std::vector<std::string> options = {};
if (cmd[{"-h", "--help"}]) {
return;
}
LogInfo("[CLI] [HealthCheck] Response code [{}]", AccountManagement::HealthCheckUserLogin());
}
} }
+20 -1
View File
@@ -1,3 +1,23 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 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 "iostream" #include "iostream"
#include "../common/cli/eqemu_command_handler.h" #include "../common/cli/eqemu_command_handler.h"
@@ -14,7 +34,6 @@ namespace LoginserverCommandHandler {
void UpdateLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description); void UpdateLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description);
void CheckExternalLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description); void CheckExternalLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description);
void UpdateLoginserverWorldAdminAccountPassword(int argc, char **argv, argh::parser &cmd, std::string &description); void UpdateLoginserverWorldAdminAccountPassword(int argc, char **argv, argh::parser &cmd, std::string &description);
void HealthCheckLogin(int argc, char **argv, argh::parser &cmd, std::string &description);
}; };
+22 -21
View File
@@ -1,3 +1,23 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 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 "loginserver_webserver.h" #include "loginserver_webserver.h"
#include "server_manager.h" #include "server_manager.h"
#include "login_server.h" #include "login_server.h"
@@ -32,14 +52,13 @@ namespace LoginserverWebserver {
while (iter != server.server_manager->getWorldServers().end()) { while (iter != server.server_manager->getWorldServers().end()) {
Json::Value row; Json::Value row;
row["server_long_name"] = (*iter)->GetServerLongName(); row["server_long_name"] = (*iter)->GetServerLongName();
row["server_short_name"] = (*iter)->GetServerShortName(); row["server_short_name"] = (*iter)->GetServerLongName();
row["server_list_type_id"] = (*iter)->GetServerListID(); row["server_list_id"] = (*iter)->GetServerListID();
row["server_status"] = (*iter)->GetStatus(); row["server_status"] = (*iter)->GetStatus();
row["zones_booted"] = (*iter)->GetZonesBooted(); row["zones_booted"] = (*iter)->GetZonesBooted();
row["local_ip"] = (*iter)->GetLocalIP(); row["local_ip"] = (*iter)->GetLocalIP();
row["remote_ip"] = (*iter)->GetRemoteIP(); row["remote_ip"] = (*iter)->GetRemoteIP();
row["players_online"] = (*iter)->GetPlayersOnline(); row["players_online"] = (*iter)->GetPlayersOnline();
row["world_id"] = (*iter)->GetServerId();
response.append(row); response.append(row);
++iter; ++iter;
} }
@@ -297,24 +316,6 @@ namespace LoginserverWebserver {
LoginserverWebserver::SendResponse(response, res); LoginserverWebserver::SendResponse(response, res);
} }
); );
api.Get(
"/probes/healthcheck", [](const httplib::Request &request, httplib::Response &res) {
Json::Value response;
uint32 login_response = AccountManagement::HealthCheckUserLogin();
response["status"] = login_response;
if (login_response == 0) {
response["message"] = "Process unresponsive, exiting...";
LogInfo("Probes healthcheck unresponsive, exiting...");
}
LoginserverWebserver::SendResponse(response, res);
if (login_response == 0) {
std::exit(0);
}
}
);
} }
/** /**
+20
View File
@@ -1,3 +1,23 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 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_LOGINSERVER_WEBSERVER_H #ifndef EQEMU_LOGINSERVER_WEBSERVER_H
#define EQEMU_LOGINSERVER_WEBSERVER_H #define EQEMU_LOGINSERVER_WEBSERVER_H
+24 -39
View File
@@ -1,3 +1,23 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 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 "../common/global_define.h" #include "../common/global_define.h"
#include "../common/types.h" #include "../common/types.h"
#include "../common/opcodemgr.h" #include "../common/opcodemgr.h"
@@ -10,7 +30,6 @@
#include "login_server.h" #include "login_server.h"
#include "loginserver_webserver.h" #include "loginserver_webserver.h"
#include "loginserver_command_handler.h" #include "loginserver_command_handler.h"
#include "../common/string_util.h"
#include <time.h> #include <time.h>
#include <stdlib.h> #include <stdlib.h>
#include <string> #include <string>
@@ -21,7 +40,6 @@ LoginServer server;
EQEmuLogSys LogSys; EQEmuLogSys LogSys;
bool run_server = true; bool run_server = true;
void ResolveAddresses();
void CatchSignal(int sig_num) void CatchSignal(int sig_num)
{ {
} }
@@ -62,30 +80,8 @@ void LoadServerConfig()
"worldservers", "worldservers",
"reject_duplicate_servers", "reject_duplicate_servers",
false false
) ));
); server.options.AllowUnregistered(server.config.GetVariableBool("worldservers", "unregistered_allowed", true));
server.options.SetShowPlayerCount(server.config.GetVariableBool("worldservers", "show_player_count", false));
server.options.AllowUnregistered(
server.config.GetVariableBool(
"worldservers",
"unregistered_allowed",
true
)
);
server.options.SetWorldDevTestServersListBottom(
server.config.GetVariableBool(
"worldservers",
"dev_test_servers_list_bottom",
false
)
);
server.options.SetWorldSpecialCharacterStartListBottom(
server.config.GetVariableBool(
"worldservers",
"special_character_start_list_bottom",
false
)
);
/** /**
* Account * Account
@@ -142,13 +138,11 @@ void start_web_server()
httplib::Server api; httplib::Server api;
api.set_logger( api.set_logger([](const auto& req, const auto& res) {
[](const auto &req, const auto &res) {
if (!req.path.empty()) { if (!req.path.empty()) {
LogInfo("[API] Request [{}] via [{}:{}]", req.path, req.remote_addr, req.remote_port); LogInfo("[API] Request [{}] via [{}:{}]", req.path, req.remote_addr, req.remote_port);
} }
} });
);
LoginserverWebserver::RegisterRoutes(api); LoginserverWebserver::RegisterRoutes(api);
api.listen("0.0.0.0", web_api_port); api.listen("0.0.0.0", web_api_port);
@@ -262,15 +256,6 @@ int main(int argc, char **argv)
#endif #endif
LogInfo("[Config] [WorldServer] IsRejectingDuplicateServers [{0}]", server.options.IsRejectingDuplicateServers()); LogInfo("[Config] [WorldServer] IsRejectingDuplicateServers [{0}]", server.options.IsRejectingDuplicateServers());
LogInfo("[Config] [WorldServer] IsUnregisteredAllowed [{0}]", server.options.IsUnregisteredAllowed()); LogInfo("[Config] [WorldServer] IsUnregisteredAllowed [{0}]", server.options.IsUnregisteredAllowed());
LogInfo("[Config] [WorldServer] ShowPlayerCount [{0}]", server.options.IsShowPlayerCountEnabled());
LogInfo(
"[Config] [WorldServer] DevAndTestServersListBottom [{0}]",
server.options.IsWorldDevTestServersListBottom()
);
LogInfo(
"[Config] [WorldServer] SpecialCharactersStartListBottom [{0}]",
server.options.IsWorldSpecialCharacterStartListBottom()
);
LogInfo("[Config] [Security] GetEncryptionMode [{0}]", server.options.GetEncryptionMode()); LogInfo("[Config] [Security] GetEncryptionMode [{0}]", server.options.GetEncryptionMode());
LogInfo("[Config] [Security] IsTokenLoginAllowed [{0}]", server.options.IsTokenLoginAllowed()); LogInfo("[Config] [Security] IsTokenLoginAllowed [{0}]", server.options.IsTokenLoginAllowed());
LogInfo("[Config] [Security] IsPasswordLoginAllowed [{0}]", server.options.IsPasswordLoginAllowed()); LogInfo("[Config] [Security] IsPasswordLoginAllowed [{0}]", server.options.IsPasswordLoginAllowed());
+20 -27
View File
@@ -1,3 +1,23 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 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_OPTIONS_H #ifndef EQEMU_OPTIONS_H
#define EQEMU_OPTIONS_H #define EQEMU_OPTIONS_H
@@ -113,29 +133,6 @@ public:
inline void UpdateInsecurePasswords(bool b) { update_insecure_passwords = b; } inline void UpdateInsecurePasswords(bool b) { update_insecure_passwords = b; }
inline bool IsUpdatingInsecurePasswords() const { return update_insecure_passwords; } inline bool IsUpdatingInsecurePasswords() const { return update_insecure_passwords; }
inline bool IsShowPlayerCountEnabled() const
{
return show_player_count;
}
inline void SetShowPlayerCount(bool show_player_count)
{
Options::show_player_count = show_player_count;
}
inline bool IsWorldDevTestServersListBottom() const { return world_dev_test_servers_list_bottom; }
inline void SetWorldDevTestServersListBottom(bool dev_test_servers_list_bottom)
{
Options::world_dev_test_servers_list_bottom = dev_test_servers_list_bottom;
}
inline bool IsWorldSpecialCharacterStartListBottom() const
{
return world_special_character_start_list_bottom;
}
inline void SetWorldSpecialCharacterStartListBottom(bool world_special_character_start_list_bottom)
{
Options::world_special_character_start_list_bottom = world_special_character_start_list_bottom;
}
private: private:
bool allow_unregistered; bool allow_unregistered;
bool trace; bool trace;
@@ -143,11 +140,8 @@ private:
bool dump_in_packets; bool dump_in_packets;
bool dump_out_packets; bool dump_out_packets;
bool reject_duplicate_servers; bool reject_duplicate_servers;
bool world_dev_test_servers_list_bottom;
bool world_special_character_start_list_bottom;
bool allow_token_login; bool allow_token_login;
bool allow_password_login; bool allow_password_login;
bool show_player_count;
bool auto_create_accounts; bool auto_create_accounts;
bool auto_link_accounts; bool auto_link_accounts;
bool update_insecure_passwords; bool update_insecure_passwords;
@@ -156,6 +150,5 @@ private:
std::string default_loginserver_name; std::string default_loginserver_name;
}; };
#endif #endif
+169 -64
View File
@@ -1,6 +1,26 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 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 "server_manager.h" #include "server_manager.h"
#include "login_server.h" #include "login_server.h"
#include "login_types.h" #include "login_structures.h"
#include <stdlib.h> #include <stdlib.h>
#include "../common/eqemu_logsys.h" #include "../common/eqemu_logsys.h"
@@ -13,15 +33,15 @@ ServerManager::ServerManager()
{ {
int listen_port = server.config.GetVariableInt("general", "listen_port", 5998); int listen_port = server.config.GetVariableInt("general", "listen_port", 5998);
m_server_connection = std::make_unique<EQ::Net::ServertalkServer>(); server_connection = std::make_unique<EQ::Net::ServertalkServer>();
EQ::Net::ServertalkServerOptions opts; EQ::Net::ServertalkServerOptions opts;
opts.port = listen_port; opts.port = listen_port;
opts.ipv6 = false; opts.ipv6 = false;
m_server_connection->Listen(opts); server_connection->Listen(opts);
LogInfo("Loginserver now listening on port [{0}]", listen_port); LogInfo("Loginserver now listening on port [{0}]", listen_port);
m_server_connection->OnConnectionIdentified( server_connection->OnConnectionIdentified(
"World", [this](std::shared_ptr<EQ::Net::ServertalkServerConnection> world_connection) { "World", [this](std::shared_ptr<EQ::Net::ServertalkServerConnection> world_connection) {
LogInfo( LogInfo(
"New World Server connection from {0}:{1}", "New World Server connection from {0}:{1}",
@@ -29,8 +49,8 @@ ServerManager::ServerManager()
world_connection->Handle()->RemotePort() world_connection->Handle()->RemotePort()
); );
auto iter = m_world_servers.begin(); auto iter = world_servers.begin();
while (iter != m_world_servers.end()) { while (iter != world_servers.end()) {
if ((*iter)->GetConnection()->Handle()->RemoteIP().compare(world_connection->Handle()->RemoteIP()) == if ((*iter)->GetConnection()->Handle()->RemoteIP().compare(world_connection->Handle()->RemoteIP()) ==
0 && 0 &&
(*iter)->GetConnection()->Handle()->RemotePort() == world_connection->Handle()->RemotePort()) { (*iter)->GetConnection()->Handle()->RemotePort() == world_connection->Handle()->RemotePort()) {
@@ -41,27 +61,27 @@ ServerManager::ServerManager()
world_connection->Handle()->RemotePort() world_connection->Handle()->RemotePort()
); );
m_world_servers.erase(iter); world_servers.erase(iter);
break; break;
} }
++iter; ++iter;
} }
m_world_servers.push_back(std::make_unique<WorldServer>(world_connection)); world_servers.push_back(std::make_unique<WorldServer>(world_connection));
} }
); );
m_server_connection->OnConnectionRemoved( server_connection->OnConnectionRemoved(
"World", [this](std::shared_ptr<EQ::Net::ServertalkServerConnection> c) { "World", [this](std::shared_ptr<EQ::Net::ServertalkServerConnection> c) {
auto iter = m_world_servers.begin(); auto iter = world_servers.begin();
while (iter != m_world_servers.end()) { while (iter != world_servers.end()) {
if ((*iter)->GetConnection()->GetUUID() == c->GetUUID()) { if ((*iter)->GetConnection()->GetUUID() == c->GetUUID()) {
LogInfo( LogInfo(
"World server {0} has been disconnected, removing.", "World server {0} has been disconnected, removing.",
(*iter)->GetServerLongName() (*iter)->GetServerLongName()
); );
m_world_servers.erase(iter); world_servers.erase(iter);
return; return;
} }
@@ -80,8 +100,8 @@ ServerManager::~ServerManager() = default;
*/ */
WorldServer *ServerManager::GetServerByAddress(const std::string &ip_address, int port) WorldServer *ServerManager::GetServerByAddress(const std::string &ip_address, int port)
{ {
auto iter = m_world_servers.begin(); auto iter = world_servers.begin();
while (iter != m_world_servers.end()) { while (iter != world_servers.end()) {
if ((*iter)->GetConnection()->Handle()->RemoteIP() == ip_address && if ((*iter)->GetConnection()->Handle()->RemoteIP() == ip_address &&
(*iter)->GetConnection()->Handle()->RemotePort()) { (*iter)->GetConnection()->Handle()->RemotePort()) {
return (*iter).get(); return (*iter).get();
@@ -97,8 +117,9 @@ WorldServer *ServerManager::GetServerByAddress(const std::string &ip_address, in
* @param sequence * @param sequence
* @return * @return
*/ */
std::unique_ptr<EQApplicationPacket> ServerManager::CreateServerListPacket(Client *client, uint32 sequence) EQApplicationPacket *ServerManager::CreateServerListPacket(Client *client, uint32 sequence)
{ {
unsigned int packet_size = sizeof(ServerListHeader_Struct);
unsigned int server_count = 0; unsigned int server_count = 0;
in_addr in{}; in_addr in{};
in.s_addr = client->GetConnection()->GetRemoteIP(); in.s_addr = client->GetConnection()->GetRemoteIP();
@@ -106,60 +127,144 @@ std::unique_ptr<EQApplicationPacket> ServerManager::CreateServerListPacket(Clien
LogDebug("ServerManager::CreateServerListPacket via client address [{0}]", client_ip); LogDebug("ServerManager::CreateServerListPacket via client address [{0}]", client_ip);
for (const auto& world_server : m_world_servers) auto iter = world_servers.begin();
{ while (iter != world_servers.end()) {
if (world_server->IsAuthorized()) { if (!(*iter)->IsAuthorized()) {
++server_count;
}
}
SerializeBuffer buf;
// LoginBaseMessage_Struct header
buf.WriteInt32(sequence);
buf.WriteInt8(0);
buf.WriteInt8(0);
buf.WriteInt32(0);
// LoginBaseReplyMessage_Struct
buf.WriteInt8(true); // success (no error)
buf.WriteInt32(0x65); // 101 "No Error" eqlsstr
buf.WriteString("");
// ServerListReply_Struct
buf.WriteInt32(server_count);
for (const auto& world_server : m_world_servers)
{
if (!world_server->IsAuthorized()) {
LogDebug( LogDebug(
"ServerManager::CreateServerListPacket | Server [{}] via IP [{}] is not authorized to be listed", "ServerManager::CreateServerListPacket | Server [{0}] via IP [{1}] is not authorized to be listed",
world_server->GetServerLongName(), (*iter)->GetServerLongName(),
world_server->GetConnection()->Handle()->RemoteIP() (*iter)->GetConnection()->Handle()->RemoteIP()
); );
++iter;
continue; continue;
} }
bool use_local_ip = false; std::string world_ip = (*iter)->GetConnection()->Handle()->RemoteIP();
if (world_ip == client_ip) {
std::string world_ip = world_server->GetConnection()->Handle()->RemoteIP(); packet_size += (*iter)->GetServerLongName().size() + (*iter)->GetLocalIP().size() + 24;
if (world_ip == client_ip || IpUtil::IsIpInPrivateRfc1918(client_ip)) {
use_local_ip = true;
}
LogDebug( LogDebug(
"CreateServerListPacket | Building list entry | Client [{}] IP [{}] Server Long Name [{}] Server IP [{}] ({})", "CreateServerListPacket | Building list entry | Client [{0}] IP [{1}] Server Long Name [{2}] Server IP [{3}] (Local)",
client->GetAccountName(), client->GetAccountName(),
client_ip, client_ip,
world_server->GetServerLongName(), (*iter)->GetServerLongName(),
use_local_ip ? world_server->GetLocalIP() : world_server->GetRemoteIP(), (*iter)->GetLocalIP()
use_local_ip ? "Local" : "Remote"
); );
}
else if (IpUtil::IsIpInPrivateRfc1918(client_ip)) {
packet_size += (*iter)->GetServerLongName().size() + (*iter)->GetLocalIP().size() + 24;
world_server->SerializeForClientServerList(buf, use_local_ip); LogDebug(
"CreateServerListPacket | Building list entry | Client [{0}] IP [{1}] Server Long Name [{2}] Server IP [{3}] (Local)",
client->GetAccountName(),
client_ip,
(*iter)->GetServerLongName(),
(*iter)->GetLocalIP()
);
}
else {
packet_size += (*iter)->GetServerLongName().size() + (*iter)->GetRemoteIP().size() + 24;
LogDebug(
"CreateServerListPacket | Building list entry | Client [{0}] IP [{1}] Server Long Name [{2}] Server IP [{3}] (Remote)",
client->GetAccountName(),
client_ip,
(*iter)->GetServerLongName(),
(*iter)->GetRemoteIP()
);
} }
return std::make_unique<EQApplicationPacket>(OP_ServerListResponse, buf); server_count++;
++iter;
}
auto *outapp = new EQApplicationPacket(OP_ServerListResponse, packet_size);
auto *server_list = (ServerListHeader_Struct *) outapp->pBuffer;
server_list->Unknown1 = sequence;
server_list->Unknown2 = 0x00000000;
server_list->Unknown3 = 0x01650000;
/**
* Not sure what this is but it should be noted setting it to
* 0xFFFFFFFF crashes the client so: don't do that.
*/
server_list->Unknown4 = 0x00000000;
server_list->NumberOfServers = server_count;
unsigned char *data_pointer = outapp->pBuffer;
data_pointer += sizeof(ServerListHeader_Struct);
iter = world_servers.begin();
while (iter != world_servers.end()) {
if (!(*iter)->IsAuthorized()) {
++iter;
continue;
}
std::string world_ip = (*iter)->GetConnection()->Handle()->RemoteIP();
if (world_ip == client_ip) {
memcpy(data_pointer, (*iter)->GetLocalIP().c_str(), (*iter)->GetLocalIP().size());
data_pointer += ((*iter)->GetLocalIP().size() + 1);
}
else if (IpUtil::IsIpInPrivateRfc1918(client_ip)) {
memcpy(data_pointer, (*iter)->GetLocalIP().c_str(), (*iter)->GetLocalIP().size());
data_pointer += ((*iter)->GetLocalIP().size() + 1);
}
else {
memcpy(data_pointer, (*iter)->GetRemoteIP().c_str(), (*iter)->GetRemoteIP().size());
data_pointer += ((*iter)->GetRemoteIP().size() + 1);
}
switch ((*iter)->GetServerListID()) {
case 1: {
*(unsigned int *) data_pointer = 0x00000030;
break;
}
case 2: {
*(unsigned int *) data_pointer = 0x00000009;
break;
}
default: {
*(unsigned int *) data_pointer = 0x00000001;
}
}
data_pointer += 4;
*(unsigned int *) data_pointer = (*iter)->GetServerId();
data_pointer += 4;
memcpy(data_pointer, (*iter)->GetServerLongName().c_str(), (*iter)->GetServerLongName().size());
data_pointer += ((*iter)->GetServerLongName().size() + 1);
memcpy(data_pointer, "EN", 2);
data_pointer += 3;
memcpy(data_pointer, "US", 2);
data_pointer += 3;
// 0 = Up, 1 = Down, 2 = Up, 3 = down, 4 = locked, 5 = locked(down)
if ((*iter)->GetStatus() < 0) {
if ((*iter)->GetZonesBooted() == 0) {
*(uint32 *) data_pointer = 0x01;
}
else {
*(uint32 *) data_pointer = 0x04;
}
}
else {
*(uint32 *) data_pointer = 0x02;
}
data_pointer += 4;
*(uint32 *) data_pointer = (*iter)->GetPlayersOnline();
data_pointer += 4;
++iter;
}
return outapp;
} }
/** /**
@@ -173,9 +278,9 @@ void ServerManager::SendUserToWorldRequest(
const std::string &client_loginserver const std::string &client_loginserver
) )
{ {
auto iter = m_world_servers.begin(); auto iter = world_servers.begin();
bool found = false; bool found = false;
while (iter != m_world_servers.end()) { while (iter != world_servers.end()) {
if ((*iter)->GetServerId() == server_id) { if ((*iter)->GetServerId() == server_id) {
EQ::Net::DynamicPacket outapp; EQ::Net::DynamicPacket outapp;
outapp.Resize(sizeof(UsertoWorldRequest_Struct)); outapp.Resize(sizeof(UsertoWorldRequest_Struct));
@@ -211,8 +316,8 @@ bool ServerManager::ServerExists(
WorldServer *ignore WorldServer *ignore
) )
{ {
auto iter = m_world_servers.begin(); auto iter = world_servers.begin();
while (iter != m_world_servers.end()) { while (iter != world_servers.end()) {
if ((*iter).get() == ignore) { if ((*iter).get() == ignore) {
++iter; ++iter;
continue; continue;
@@ -238,8 +343,8 @@ void ServerManager::DestroyServerByName(
WorldServer *ignore WorldServer *ignore
) )
{ {
auto iter = m_world_servers.begin(); auto iter = world_servers.begin();
while (iter != m_world_servers.end()) { while (iter != world_servers.end()) {
if ((*iter).get() == ignore) { if ((*iter).get() == ignore) {
++iter; ++iter;
continue; continue;
@@ -248,7 +353,7 @@ void ServerManager::DestroyServerByName(
if ((*iter)->GetServerLongName().compare(server_long_name) == 0 && if ((*iter)->GetServerLongName().compare(server_long_name) == 0 &&
(*iter)->GetServerShortName().compare(server_short_name) == 0) { (*iter)->GetServerShortName().compare(server_short_name) == 0) {
(*iter)->GetConnection()->Handle()->Disconnect(); (*iter)->GetConnection()->Handle()->Disconnect();
iter = m_world_servers.erase(iter); iter = world_servers.erase(iter);
continue; continue;
} }
@@ -261,5 +366,5 @@ void ServerManager::DestroyServerByName(
*/ */
const std::list<std::unique_ptr<WorldServer>> &ServerManager::getWorldServers() const const std::list<std::unique_ptr<WorldServer>> &ServerManager::getWorldServers() const
{ {
return m_world_servers; return world_servers;
} }
+23 -3
View File
@@ -1,3 +1,23 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 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_SERVERMANAGER_H #ifndef EQEMU_SERVERMANAGER_H
#define EQEMU_SERVERMANAGER_H #define EQEMU_SERVERMANAGER_H
@@ -45,7 +65,7 @@ public:
* @param sequence * @param sequence
* @return * @return
*/ */
std::unique_ptr<EQApplicationPacket> CreateServerListPacket(Client *client, uint32 sequence); EQApplicationPacket *CreateServerListPacket(Client *client, uint32 sequence);
/** /**
* Checks to see if there is a server exists with this name, ignoring option * Checks to see if there is a server exists with this name, ignoring option
@@ -83,8 +103,8 @@ private:
*/ */
WorldServer *GetServerByAddress(const std::string &ip_address, int port); WorldServer *GetServerByAddress(const std::string &ip_address, int port);
std::unique_ptr<EQ::Net::ServertalkServer> m_server_connection; std::unique_ptr<EQ::Net::ServertalkServer> server_connection;
std::list<std::unique_ptr<WorldServer>> m_world_servers; std::list<std::unique_ptr<WorldServer>> world_servers;
}; };
+155 -227
View File
@@ -1,8 +1,28 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 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 "world_server.h" #include "world_server.h"
#include "login_server.h" #include "login_server.h"
#include "login_types.h" #include "login_structures.h"
#include "../common/eqemu_logsys.h"
#include "../common/ip_util.h" #include "../common/ip_util.h"
#include "../common/string_util.h"
extern LoginServer server; extern LoginServer server;
@@ -11,16 +31,16 @@ extern LoginServer server;
*/ */
WorldServer::WorldServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> worldserver_connection) WorldServer::WorldServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> worldserver_connection)
{ {
m_connection = worldserver_connection; connection = worldserver_connection;
m_zones_booted = 0; zones_booted = 0;
m_players_online = 0; players_online = 0;
m_server_status = 0; server_status = 0;
m_server_id = 0; server_id = 0;
m_server_list_type_id = 0; server_list_type_id = 0;
m_server_process_type = 0; server_process_type = 0;
m_is_server_authorized = false; is_server_authorized = false;
m_is_server_trusted = false; is_server_trusted = false;
m_is_server_logged_in = false; is_server_logged_in = false;
worldserver_connection->OnMessage( worldserver_connection->OnMessage(
ServerOP_NewLSInfo, ServerOP_NewLSInfo,
@@ -52,25 +72,21 @@ WorldServer::WorldServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> wo
std::bind(&WorldServer::ProcessLSAccountUpdate, this, std::placeholders::_1, std::placeholders::_2) std::bind(&WorldServer::ProcessLSAccountUpdate, this, std::placeholders::_1, std::placeholders::_2)
); );
m_keepalive = std::make_unique<EQ::Timer>( m_keepalive = std::make_unique<EQ::Timer>(1000, true, std::bind(&WorldServer::OnKeepAlive, this, std::placeholders::_1));
1000,
true,
std::bind(&WorldServer::OnKeepAlive, this, std::placeholders::_1)
);
} }
WorldServer::~WorldServer() = default; WorldServer::~WorldServer() = default;
void WorldServer::Reset() void WorldServer::Reset()
{ {
m_server_id; server_id;
m_zones_booted = 0; zones_booted = 0;
m_players_online = 0; players_online = 0;
m_server_status = 0; server_status = 0;
m_server_list_type_id = 0; server_list_type_id = 0;
m_server_process_type = 0; server_process_type = 0;
m_is_server_authorized = false; is_server_authorized = false;
m_is_server_logged_in = false; is_server_logged_in = false;
} }
/** /**
@@ -100,14 +116,8 @@ void WorldServer::ProcessNewLSInfo(uint16_t opcode, const EQ::Net::Packet &packe
return; return;
} }
auto *info = (ServerNewLSInfo_Struct *) packet.Data();
// if for whatever reason the world server is not sending an address, use the local address it sends auto *info = (ServerNewLSInfo_Struct *) packet.Data();
std::string remote_ip_addr = info->remote_ip_address;
std::string local_ip_addr = info->local_ip_address;
if (remote_ip_addr.empty() && !local_ip_addr.empty() && local_ip_addr != "127.0.0.1") {
strcpy(info->remote_ip_address, local_ip_addr.c_str());
}
LogInfo( LogInfo(
"New World Server Info | name [{0}] shortname [{1}] remote_address [{2}] local_address [{3}] account [{4}] password [{5}] server_type [{6}]", "New World Server Info | name [{0}] shortname [{1}] remote_address [{2}] local_address [{3}] account [{4}] password [{5}] server_type [{6}]",
@@ -198,15 +208,15 @@ void WorldServer::ProcessUserToWorldResponseLegacy(uint16_t opcode, const EQ::Ne
LogDebug("User-To-World Response received"); LogDebug("User-To-World Response received");
} }
auto *r = (UsertoWorldResponseLegacy_Struct *) packet.Data(); auto *user_to_world_response = (UsertoWorldResponseLegacy_Struct *) packet.Data();
LogDebug("Trying to find client with user id of [{0}]", r->lsaccountid); LogDebug("Trying to find client with user id of [{0}]", user_to_world_response->lsaccountid);
Client *client = server.client_manager->GetClient(r->lsaccountid, "eqemu"); Client *client = server.client_manager->GetClient(user_to_world_response->lsaccountid, "eqemu");
if (client) { if (client) {
LogDebug( LogDebug(
"Found client with user id of [{0}] and account name of [{1}]", "Found client with user id of [{0}] and account name of [{1}]",
r->lsaccountid, user_to_world_response->lsaccountid,
client->GetAccountName() client->GetAccountName()
); );
@@ -216,11 +226,11 @@ void WorldServer::ProcessUserToWorldResponseLegacy(uint16_t opcode, const EQ::Ne
); );
auto *per = (PlayEverquestResponse_Struct *) outapp->pBuffer; auto *per = (PlayEverquestResponse_Struct *) outapp->pBuffer;
per->base_header.sequence = client->GetPlaySequence(); per->Sequence = client->GetPlaySequence();
per->server_number = client->GetPlayServerID(); per->ServerNumber = client->GetPlayServerID();
if (r->response > 0) { if (user_to_world_response->response > 0) {
per->base_reply.success = true; per->Allowed = 1;
SendClientAuth( SendClientAuth(
client->GetConnection()->GetRemoteAddr(), client->GetConnection()->GetRemoteAddr(),
client->GetAccountName(), client->GetAccountName(),
@@ -230,37 +240,36 @@ void WorldServer::ProcessUserToWorldResponseLegacy(uint16_t opcode, const EQ::Ne
); );
} }
switch (r->response) { switch (user_to_world_response->response) {
case UserToWorldStatusSuccess: case UserToWorldStatusSuccess:
per->base_reply.error_str_id = LS::ErrStr::ERROR_NONE; per->Message = 101;
break; break;
case UserToWorldStatusWorldUnavail: case UserToWorldStatusWorldUnavail:
per->base_reply.error_str_id = LS::ErrStr::ERROR_SERVER_UNAVAILABLE; per->Message = 326;
break; break;
case UserToWorldStatusSuspended: case UserToWorldStatusSuspended:
per->base_reply.error_str_id = LS::ErrStr::ERROR_ACCOUNT_SUSPENDED; per->Message = 337;
break; break;
case UserToWorldStatusBanned: case UserToWorldStatusBanned:
per->base_reply.error_str_id = LS::ErrStr::ERROR_ACCOUNT_BANNED; per->Message = 338;
break; break;
case UserToWorldStatusWorldAtCapacity: case UserToWorldStatusWorldAtCapacity:
per->base_reply.error_str_id = LS::ErrStr::ERROR_WORLD_MAX_CAPACITY; per->Message = 339;
break; break;
case UserToWorldStatusAlreadyOnline: case UserToWorldStatusAlreadyOnline:
per->base_reply.error_str_id = LS::ErrStr::ERROR_ACTIVE_CHARACTER; per->Message = 111;
break; break;
default: default:
per->base_reply.error_str_id = LS::ErrStr::ERROR_UNKNOWN; per->Message = 102;
break;
} }
if (server.options.IsWorldTraceOn()) { if (server.options.IsWorldTraceOn()) {
LogDebug( LogDebug(
"Sending play response: allowed [{0}] sequence [{1}] server number [{2}] message [{3}]", "Sending play response: allowed [{0}] sequence [{1}] server number [{2}] message [{3}]",
per->base_reply.success, per->Allowed,
per->base_header.sequence, per->Sequence,
per->server_number, per->ServerNumber,
per->base_reply.error_str_id per->Message
); );
LogDebug("[Size: [{0}]] {1}", outapp->size, DumpPacketToString(outapp)); LogDebug("[Size: [{0}]] {1}", outapp->size, DumpPacketToString(outapp));
@@ -276,7 +285,7 @@ void WorldServer::ProcessUserToWorldResponseLegacy(uint16_t opcode, const EQ::Ne
else { else {
LogError( LogError(
"Received User-To-World Response for [{0}] but could not find the client referenced!", "Received User-To-World Response for [{0}] but could not find the client referenced!",
r->lsaccountid user_to_world_response->lsaccountid
); );
} }
} }
@@ -335,8 +344,8 @@ void WorldServer::ProcessUserToWorldResponse(uint16_t opcode, const EQ::Net::Pac
); );
auto *per = (PlayEverquestResponse_Struct *) outapp->pBuffer; auto *per = (PlayEverquestResponse_Struct *) outapp->pBuffer;
per->base_header.sequence = client->GetPlaySequence(); per->Sequence = client->GetPlaySequence();
per->server_number = client->GetPlayServerID(); per->ServerNumber = client->GetPlayServerID();
LogDebug( LogDebug(
"Found sequence and play of [{0}] [{1}]", "Found sequence and play of [{0}] [{1}]",
@@ -347,7 +356,7 @@ void WorldServer::ProcessUserToWorldResponse(uint16_t opcode, const EQ::Net::Pac
LogDebug("[Size: [{0}]] {1}", outapp->size, DumpPacketToString(outapp)); LogDebug("[Size: [{0}]] {1}", outapp->size, DumpPacketToString(outapp));
if (user_to_world_response->response > 0) { if (user_to_world_response->response > 0) {
per->base_reply.success = true; per->Allowed = 1;
SendClientAuth( SendClientAuth(
client->GetConnection()->GetRemoteAddr(), client->GetConnection()->GetRemoteAddr(),
client->GetAccountName(), client->GetAccountName(),
@@ -359,35 +368,34 @@ void WorldServer::ProcessUserToWorldResponse(uint16_t opcode, const EQ::Net::Pac
switch (user_to_world_response->response) { switch (user_to_world_response->response) {
case UserToWorldStatusSuccess: case UserToWorldStatusSuccess:
per->base_reply.error_str_id = LS::ErrStr::ERROR_NONE; per->Message = 101;
break; break;
case UserToWorldStatusWorldUnavail: case UserToWorldStatusWorldUnavail:
per->base_reply.error_str_id = LS::ErrStr::ERROR_SERVER_UNAVAILABLE; per->Message = 326;
break; break;
case UserToWorldStatusSuspended: case UserToWorldStatusSuspended:
per->base_reply.error_str_id = LS::ErrStr::ERROR_ACCOUNT_SUSPENDED; per->Message = 337;
break; break;
case UserToWorldStatusBanned: case UserToWorldStatusBanned:
per->base_reply.error_str_id = LS::ErrStr::ERROR_ACCOUNT_BANNED; per->Message = 338;
break; break;
case UserToWorldStatusWorldAtCapacity: case UserToWorldStatusWorldAtCapacity:
per->base_reply.error_str_id = LS::ErrStr::ERROR_WORLD_MAX_CAPACITY; per->Message = 339;
break; break;
case UserToWorldStatusAlreadyOnline: case UserToWorldStatusAlreadyOnline:
per->base_reply.error_str_id = LS::ErrStr::ERROR_ACTIVE_CHARACTER; per->Message = 111;
break; break;
default: default:
per->base_reply.error_str_id = LS::ErrStr::ERROR_UNKNOWN; per->Message = 102;
break;
} }
if (server.options.IsTraceOn()) { if (server.options.IsTraceOn()) {
LogDebug( LogDebug(
"Sending play response with following data, allowed [{0}], sequence {1}, server number {2}, message {3}", "Sending play response with following data, allowed [{0}], sequence {1}, server number {2}, message {3}",
per->base_reply.success, per->Allowed,
per->base_header.sequence, per->Sequence,
per->server_number, per->ServerNumber,
per->base_reply.error_str_id per->Message
); );
LogDebug("[Size: [{0}]] {1}", outapp->size, DumpPacketToString(outapp)); LogDebug("[Size: [{0}]] {1}", outapp->size, DumpPacketToString(outapp));
} }
@@ -435,7 +443,7 @@ void WorldServer::ProcessLSAccountUpdate(uint16_t opcode, const EQ::Net::Packet
} }
if (server.options.IsWorldTraceOn()) { if (server.options.IsWorldTraceOn()) {
LogDebug("ServerOP_LSAccountUpdate packet received from [{0}]", m_short_name); LogDebug("ServerOP_LSAccountUpdate packet received from [{0}]", short_name);
} }
auto *loginserver_update = (ServerLSAccountUpdate_Struct *) packet.Data(); auto *loginserver_update = (ServerLSAccountUpdate_Struct *) packet.Data();
@@ -478,8 +486,6 @@ void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct *new_world_server_info
return; return;
} }
SanitizeWorldServerName(new_world_server_info_packet->server_long_name);
SetAccountPassword(new_world_server_info_packet->account_password) SetAccountPassword(new_world_server_info_packet->account_password)
->SetLongName(new_world_server_info_packet->server_long_name) ->SetLongName(new_world_server_info_packet->server_long_name)
->SetShortName(new_world_server_info_packet->server_short_name) ->SetShortName(new_world_server_info_packet->server_short_name)
@@ -500,8 +506,8 @@ void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct *new_world_server_info
else { else {
if (server.server_manager->ServerExists(GetServerLongName(), GetServerShortName(), this)) { if (server.server_manager->ServerExists(GetServerLongName(), GetServerShortName(), this)) {
LogInfo("World tried to login but there already exists a server that has that name, destroying [{}]", LogInfo("World tried to login but there already exists a server that has that name, destroying [{}]",
m_long_name); long_name);
server.server_manager->DestroyServerByName(m_long_name, m_short_name, this); server.server_manager->DestroyServerByName(long_name, short_name, this);
} }
} }
@@ -545,7 +551,6 @@ void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct *new_world_server_info
Database::DbWorldRegistration Database::DbWorldRegistration
world_registration = server.db->GetWorldRegistration( world_registration = server.db->GetWorldRegistration(
GetServerShortName(), GetServerShortName(),
GetServerLongName(),
world_server_admin_id world_server_admin_id
); );
@@ -573,12 +578,6 @@ void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct *new_world_server_info
GetServerLongName(), GetServerLongName(),
GetRemoteIp() GetRemoteIp()
); );
WorldServer::FormatWorldServerName(
new_world_server_info_packet->server_long_name,
world_registration.server_list_type
);
SetLongName(new_world_server_info_packet->server_long_name);
} }
/** /**
@@ -620,7 +619,7 @@ void WorldServer::SendClientAuth(
strncpy(client_auth.loginserver_name, &loginserver_name[0], 64); strncpy(client_auth.loginserver_name, &loginserver_name[0], 64);
const std::string &client_address(ip); const std::string &client_address(ip);
std::string world_address(m_connection->Handle()->RemoteIP()); std::string world_address(connection->Handle()->RemoteIP());
if (client_address == world_address) { if (client_address == world_address) {
client_auth.is_client_from_local_network = 1; client_auth.is_client_from_local_network = 1;
@@ -656,22 +655,13 @@ void WorldServer::SendClientAuth(
); );
outapp.PutSerialize(0, client_auth); outapp.PutSerialize(0, client_auth);
m_connection->Send(ServerOP_LSClientAuth, outapp); connection->Send(ServerOP_LSClientAuth, outapp);
if (server.options.IsDumpInPacketsOn()) { if (server.options.IsDumpInPacketsOn()) {
DumpPacket(ServerOP_LSClientAuth, outapp); DumpPacket(ServerOP_LSClientAuth, outapp);
} }
} }
constexpr static int MAX_ACCOUNT_NAME_LENGTH = 30;
constexpr static int MAX_ACCOUNT_PASSWORD_LENGTH = 30;
constexpr static int MAX_SERVER_LONG_NAME_LENGTH = 200;
constexpr static int MAX_SERVER_SHORT_NAME_LENGTH = 50;
constexpr static int MAX_SERVER_LOCAL_ADDRESS_LENGTH = 125;
constexpr static int MAX_SERVER_REMOTE_ADDRESS_LENGTH = 125;
constexpr static int MAX_SERVER_VERSION_LENGTH = 64;
constexpr static int MAX_SERVER_PROTOCOL_VERSION = 25;
/** /**
* @param new_world_server_info_packet * @param new_world_server_info_packet
* @return * @return
@@ -680,32 +670,41 @@ bool WorldServer::HandleNewLoginserverInfoValidation(
ServerNewLSInfo_Struct *new_world_server_info_packet ServerNewLSInfo_Struct *new_world_server_info_packet
) )
{ {
if (strlen(new_world_server_info_packet->account_name) >= MAX_ACCOUNT_NAME_LENGTH) { const int max_account_name_length = 30;
LogError("Handle_NewLSInfo error [account_name] was too long | max [{0}]", MAX_ACCOUNT_NAME_LENGTH); const int max_account_password_length = 30;
const int max_server_long_name_length = 200;
const int max_server_short_name_length = 50;
const int max_server_local_address_length = 125;
const int max_server_remote_address_length = 125;
const int max_server_version_length = 64;
const int max_server_protocol_version = 25;
if (strlen(new_world_server_info_packet->account_name) >= max_account_name_length) {
LogError("Handle_NewLSInfo error [account_name] was too long | max [{0}]", max_account_name_length);
return false; return false;
} }
else if (strlen(new_world_server_info_packet->account_password) >= MAX_ACCOUNT_PASSWORD_LENGTH) { else if (strlen(new_world_server_info_packet->account_password) >= max_account_password_length) {
LogError("Handle_NewLSInfo error [account_password] was too long | max [{0}]", MAX_ACCOUNT_PASSWORD_LENGTH); LogError("Handle_NewLSInfo error [account_password] was too long | max [{0}]", max_account_password_length);
return false; return false;
} }
else if (strlen(new_world_server_info_packet->server_long_name) >= MAX_SERVER_LONG_NAME_LENGTH) { else if (strlen(new_world_server_info_packet->server_long_name) >= max_server_long_name_length) {
LogError("Handle_NewLSInfo error [server_long_name] was too long | max [{0}]", MAX_SERVER_LONG_NAME_LENGTH); LogError("Handle_NewLSInfo error [server_long_name] was too long | max [{0}]", max_server_long_name_length);
return false; return false;
} }
else if (strlen(new_world_server_info_packet->server_short_name) >= MAX_SERVER_SHORT_NAME_LENGTH) { else if (strlen(new_world_server_info_packet->server_short_name) >= max_server_short_name_length) {
LogError("Handle_NewLSInfo error [server_short_name] was too long | max [{0}]", MAX_SERVER_SHORT_NAME_LENGTH); LogError("Handle_NewLSInfo error [server_short_name] was too long | max [{0}]", max_server_short_name_length);
return false; return false;
} }
else if (strlen(new_world_server_info_packet->server_version) >= MAX_SERVER_VERSION_LENGTH) { else if (strlen(new_world_server_info_packet->server_version) >= max_server_short_name_length) {
LogError("Handle_NewLSInfo error [server_version] was too long | max [{0}]", MAX_SERVER_VERSION_LENGTH); LogError("Handle_NewLSInfo error [server_version] was too long | max [{0}]", max_server_version_length);
return false; return false;
} }
else if (strlen(new_world_server_info_packet->protocol_version) >= MAX_SERVER_PROTOCOL_VERSION) { else if (strlen(new_world_server_info_packet->protocol_version) >= max_server_protocol_version) {
LogError("Handle_NewLSInfo error [protocol_version] was too long | max [{0}]", MAX_SERVER_PROTOCOL_VERSION); LogError("Handle_NewLSInfo error [protocol_version] was too long | max [{0}]", max_server_protocol_version);
return false; return false;
} }
if (strlen(new_world_server_info_packet->local_ip_address) <= MAX_SERVER_LOCAL_ADDRESS_LENGTH) { if (strlen(new_world_server_info_packet->local_ip_address) <= max_server_local_address_length) {
if (strlen(new_world_server_info_packet->local_ip_address) == 0) { if (strlen(new_world_server_info_packet->local_ip_address) == 0) {
LogError("Handle_NewLSInfo error, local address was null, defaulting to localhost"); LogError("Handle_NewLSInfo error, local address was null, defaulting to localhost");
SetLocalIp("127.0.0.1"); SetLocalIp("127.0.0.1");
@@ -715,17 +714,17 @@ bool WorldServer::HandleNewLoginserverInfoValidation(
} }
} }
else { else {
LogError("Handle_NewLSInfo error, local address was too long | max [{0}]", MAX_SERVER_LOCAL_ADDRESS_LENGTH); LogError("Handle_NewLSInfo error, local address was too long | max [{0}]", max_server_local_address_length);
return false; return false;
} }
if (strlen(new_world_server_info_packet->remote_ip_address) <= MAX_SERVER_REMOTE_ADDRESS_LENGTH) { if (strlen(new_world_server_info_packet->remote_ip_address) <= max_server_remote_address_length) {
if (strlen(new_world_server_info_packet->remote_ip_address) == 0) { if (strlen(new_world_server_info_packet->remote_ip_address) == 0) {
SetRemoteIp(GetConnection()->Handle()->RemoteIP()); SetRemoteIp(GetConnection()->Handle()->RemoteIP());
LogWarning( LogWarning(
"Remote address was null, defaulting to stream address [{0}]", "Remote address was null, defaulting to stream address [{0}]",
m_remote_ip_address remote_ip_address
); );
} }
else { else {
@@ -737,7 +736,7 @@ bool WorldServer::HandleNewLoginserverInfoValidation(
LogWarning( LogWarning(
"Handle_NewLSInfo remote address was too long, defaulting to stream address [{0}]", "Handle_NewLSInfo remote address was too long, defaulting to stream address [{0}]",
m_remote_ip_address remote_ip_address
); );
} }
@@ -797,7 +796,7 @@ bool WorldServer::HandleNewLoginserverRegisteredOnly(
if (IsServerTrusted()) { if (IsServerTrusted()) {
LogDebug("WorldServer::HandleNewLoginserverRegisteredOnly | ServerOP_LSAccountUpdate sent to world"); LogDebug("WorldServer::HandleNewLoginserverRegisteredOnly | ServerOP_LSAccountUpdate sent to world");
EQ::Net::DynamicPacket outapp; EQ::Net::DynamicPacket outapp;
m_connection->Send(ServerOP_LSAccountUpdate, outapp); connection->Send(ServerOP_LSAccountUpdate, outapp);
} }
} }
else { else {
@@ -848,8 +847,6 @@ bool WorldServer::HandleNewLoginserverInfoUnregisteredAllowed(
->SetIsServerTrusted(world_registration.is_server_trusted) ->SetIsServerTrusted(world_registration.is_server_trusted)
->SetServerListTypeId(world_registration.server_list_type); ->SetServerListTypeId(world_registration.server_list_type);
SetIsServerAuthorized(true);
bool does_world_server_pass_authentication_check = ( bool does_world_server_pass_authentication_check = (
world_registration.server_admin_account_name == GetAccountName() && world_registration.server_admin_account_name == GetAccountName() &&
WorldServer::ValidateWorldServerAdminLogin( WorldServer::ValidateWorldServerAdminLogin(
@@ -867,7 +864,7 @@ bool WorldServer::HandleNewLoginserverInfoUnregisteredAllowed(
if (does_world_server_have_non_empty_credentials) { if (does_world_server_have_non_empty_credentials) {
if (does_world_server_pass_authentication_check) { if (does_world_server_pass_authentication_check) {
SetIsServerLoggedIn(true); SetIsServerAuthorized(true);
LogInfo( LogInfo(
"Server long_name [{0}] short_name [{1}] successfully logged in", "Server long_name [{0}] short_name [{1}] successfully logged in",
@@ -878,13 +875,16 @@ bool WorldServer::HandleNewLoginserverInfoUnregisteredAllowed(
if (IsServerTrusted()) { if (IsServerTrusted()) {
LogDebug("WorldServer::HandleNewLoginserverRegisteredOnly | ServerOP_LSAccountUpdate sent to world"); LogDebug("WorldServer::HandleNewLoginserverRegisteredOnly | ServerOP_LSAccountUpdate sent to world");
EQ::Net::DynamicPacket outapp; EQ::Net::DynamicPacket outapp;
m_connection->Send(ServerOP_LSAccountUpdate, outapp); connection->Send(ServerOP_LSAccountUpdate, outapp);
} }
} }
else { else {
// server is authorized to be on the loginserver list but didn't pass login check
/**
* this is the first of two cases where we should deny access even if unregistered is allowed
*/
LogInfo( LogInfo(
"Server long_name [{0}] short_name [{1}] attempted to log in but account and password did not match the entry in the database. Unregistered still allowed", "Server long_name [{0}] short_name [{1}] attempted to log in but account and password did not match the entry in the database.",
GetServerLongName(), GetServerLongName(),
GetServerShortName() GetServerShortName()
); );
@@ -892,7 +892,9 @@ bool WorldServer::HandleNewLoginserverInfoUnregisteredAllowed(
} }
else { else {
// server is authorized to be on the loginserver list but didn't pass login check /**
* this is the second of two cases where we should deny access even if unregistered is allowed
*/
if (!GetAccountName().empty() || !GetAccountPassword().empty()) { if (!GetAccountName().empty() || !GetAccountPassword().empty()) {
LogInfo( LogInfo(
"Server [{0}] [{1}] did not login but this server required a password to login", "Server [{0}] [{1}] did not login but this server required a password to login",
@@ -901,6 +903,7 @@ bool WorldServer::HandleNewLoginserverInfoUnregisteredAllowed(
); );
} }
else { else {
SetIsServerAuthorized(true);
LogInfo( LogInfo(
"Server [{0}] [{1}] did not login but unregistered servers are allowed", "Server [{0}] [{1}] did not login but unregistered servers are allowed",
GetServerLongName(), GetServerLongName(),
@@ -936,12 +939,14 @@ bool WorldServer::HandleNewLoginserverInfoUnregisteredAllowed(
} }
} }
// Auto create a registration /**
* Auto create a registration
*/
if (!server.db->CreateWorldRegistration( if (!server.db->CreateWorldRegistration(
GetServerLongName(), GetServerLongName(),
GetServerShortName(), GetServerShortName(),
GetRemoteIp(), GetRemoteIp(),
m_server_id, server_id,
server_admin_id server_admin_id
)) { )) {
return false; return false;
@@ -1033,56 +1038,13 @@ bool WorldServer::ValidateWorldServerAdminLogin(
return false; return false;
} }
void WorldServer::SerializeForClientServerList(SerializeBuffer &out, bool use_local_ip) const
{
// see LoginClientServerData_Struct
if (use_local_ip) {
out.WriteString(GetLocalIP());
}
else {
out.WriteString(GetRemoteIP());
}
switch (GetServerListID()) {
case LS::ServerType::Legends:
out.WriteInt32(LS::ServerTypeFlags::Legends);
break;
case LS::ServerType::Preferred:
out.WriteInt32(LS::ServerTypeFlags::Preferred);
break;
default:
out.WriteInt32(LS::ServerTypeFlags::Standard);
break;
}
out.WriteUInt32(GetServerId());
out.WriteString(GetServerLongName());
out.WriteString("us"); // country code
out.WriteString("en"); // language code
// 0 = Up, 1 = Down, 2 = Up, 3 = down, 4 = locked, 5 = locked(down)
if (GetStatus() < 0) {
if (GetZonesBooted() == 0) {
out.WriteInt32(LS::ServerStatusFlags::Down);
}
else {
out.WriteInt32(LS::ServerStatusFlags::Locked);
}
}
else {
out.WriteInt32(LS::ServerStatusFlags::Up);
}
out.WriteUInt32(GetPlayersOnline());
}
/** /**
* @param in_server_list_id * @param in_server_list_id
* @return * @return
*/ */
WorldServer *WorldServer::SetServerListTypeId(unsigned int in_server_list_id) WorldServer *WorldServer::SetServerListTypeId(unsigned int in_server_list_id)
{ {
m_server_list_type_id = in_server_list_id; server_list_type_id = in_server_list_id;
return this; return this;
} }
@@ -1092,7 +1054,7 @@ WorldServer *WorldServer::SetServerListTypeId(unsigned int in_server_list_id)
*/ */
const std::string &WorldServer::GetServerDescription() const const std::string &WorldServer::GetServerDescription() const
{ {
return m_server_description; return server_description;
} }
/** /**
@@ -1100,7 +1062,7 @@ const std::string &WorldServer::GetServerDescription() const
*/ */
WorldServer *WorldServer::SetServerDescription(const std::string &in_server_description) WorldServer *WorldServer::SetServerDescription(const std::string &in_server_description)
{ {
WorldServer::m_server_description = in_server_description; WorldServer::server_description = in_server_description;
return this; return this;
} }
@@ -1110,7 +1072,7 @@ WorldServer *WorldServer::SetServerDescription(const std::string &in_server_desc
*/ */
bool WorldServer::IsServerAuthorized() const bool WorldServer::IsServerAuthorized() const
{ {
return m_is_server_authorized; return is_server_authorized;
} }
/** /**
@@ -1118,7 +1080,7 @@ bool WorldServer::IsServerAuthorized() const
*/ */
WorldServer *WorldServer::SetIsServerAuthorized(bool in_is_server_authorized) WorldServer *WorldServer::SetIsServerAuthorized(bool in_is_server_authorized)
{ {
WorldServer::m_is_server_authorized = in_is_server_authorized; WorldServer::is_server_authorized = in_is_server_authorized;
return this; return this;
} }
@@ -1128,7 +1090,7 @@ WorldServer *WorldServer::SetIsServerAuthorized(bool in_is_server_authorized)
*/ */
bool WorldServer::IsServerLoggedIn() const bool WorldServer::IsServerLoggedIn() const
{ {
return m_is_server_logged_in; return is_server_logged_in;
} }
/** /**
@@ -1136,7 +1098,7 @@ bool WorldServer::IsServerLoggedIn() const
*/ */
WorldServer *WorldServer::SetIsServerLoggedIn(bool in_is_server_logged_in) WorldServer *WorldServer::SetIsServerLoggedIn(bool in_is_server_logged_in)
{ {
WorldServer::m_is_server_logged_in = in_is_server_logged_in; WorldServer::is_server_logged_in = in_is_server_logged_in;
return this; return this;
} }
@@ -1146,7 +1108,7 @@ WorldServer *WorldServer::SetIsServerLoggedIn(bool in_is_server_logged_in)
*/ */
bool WorldServer::IsServerTrusted() const bool WorldServer::IsServerTrusted() const
{ {
return m_is_server_trusted; return is_server_trusted;
} }
/** /**
@@ -1154,7 +1116,7 @@ bool WorldServer::IsServerTrusted() const
*/ */
WorldServer *WorldServer::SetIsServerTrusted(bool in_is_server_trusted) WorldServer *WorldServer::SetIsServerTrusted(bool in_is_server_trusted)
{ {
WorldServer::m_is_server_trusted = in_is_server_trusted; WorldServer::is_server_trusted = in_is_server_trusted;
return this; return this;
} }
@@ -1164,7 +1126,7 @@ WorldServer *WorldServer::SetIsServerTrusted(bool in_is_server_trusted)
*/ */
WorldServer *WorldServer::SetZonesBooted(unsigned int in_zones_booted) WorldServer *WorldServer::SetZonesBooted(unsigned int in_zones_booted)
{ {
WorldServer::m_zones_booted = in_zones_booted; WorldServer::zones_booted = in_zones_booted;
return this; return this;
} }
@@ -1174,7 +1136,7 @@ WorldServer *WorldServer::SetZonesBooted(unsigned int in_zones_booted)
*/ */
WorldServer *WorldServer::SetPlayersOnline(unsigned int in_players_online) WorldServer *WorldServer::SetPlayersOnline(unsigned int in_players_online)
{ {
WorldServer::m_players_online = in_players_online; WorldServer::players_online = in_players_online;
return this; return this;
} }
@@ -1184,7 +1146,7 @@ WorldServer *WorldServer::SetPlayersOnline(unsigned int in_players_online)
*/ */
WorldServer *WorldServer::SetServerStatus(int in_server_status) WorldServer *WorldServer::SetServerStatus(int in_server_status)
{ {
WorldServer::m_server_status = in_server_status; WorldServer::server_status = in_server_status;
return this; return this;
} }
@@ -1194,7 +1156,7 @@ WorldServer *WorldServer::SetServerStatus(int in_server_status)
*/ */
WorldServer *WorldServer::SetServerProcessType(unsigned int in_server_process_type) WorldServer *WorldServer::SetServerProcessType(unsigned int in_server_process_type)
{ {
WorldServer::m_server_process_type = in_server_process_type; WorldServer::server_process_type = in_server_process_type;
return this; return this;
} }
@@ -1204,7 +1166,7 @@ WorldServer *WorldServer::SetServerProcessType(unsigned int in_server_process_ty
*/ */
WorldServer *WorldServer::SetLongName(const std::string &in_long_name) WorldServer *WorldServer::SetLongName(const std::string &in_long_name)
{ {
WorldServer::m_long_name = in_long_name; WorldServer::long_name = in_long_name;
return this; return this;
} }
@@ -1214,7 +1176,7 @@ WorldServer *WorldServer::SetLongName(const std::string &in_long_name)
*/ */
WorldServer *WorldServer::SetShortName(const std::string &in_short_name) WorldServer *WorldServer::SetShortName(const std::string &in_short_name)
{ {
WorldServer::m_short_name = in_short_name; WorldServer::short_name = in_short_name;
return this; return this;
} }
@@ -1224,7 +1186,7 @@ WorldServer *WorldServer::SetShortName(const std::string &in_short_name)
*/ */
WorldServer *WorldServer::SetAccountName(const std::string &in_account_name) WorldServer *WorldServer::SetAccountName(const std::string &in_account_name)
{ {
WorldServer::m_account_name = in_account_name; WorldServer::account_name = in_account_name;
return this; return this;
} }
@@ -1234,7 +1196,7 @@ WorldServer *WorldServer::SetAccountName(const std::string &in_account_name)
*/ */
WorldServer *WorldServer::SetAccountPassword(const std::string &in_account_password) WorldServer *WorldServer::SetAccountPassword(const std::string &in_account_password)
{ {
WorldServer::m_account_password = in_account_password; WorldServer::account_password = in_account_password;
return this; return this;
} }
@@ -1244,7 +1206,7 @@ WorldServer *WorldServer::SetAccountPassword(const std::string &in_account_passw
*/ */
WorldServer *WorldServer::SetRemoteIp(const std::string &in_remote_ip) WorldServer *WorldServer::SetRemoteIp(const std::string &in_remote_ip)
{ {
WorldServer::m_remote_ip_address = in_remote_ip; WorldServer::remote_ip_address = in_remote_ip;
return this; return this;
} }
@@ -1254,7 +1216,7 @@ WorldServer *WorldServer::SetRemoteIp(const std::string &in_remote_ip)
*/ */
WorldServer *WorldServer::SetLocalIp(const std::string &in_local_ip) WorldServer *WorldServer::SetLocalIp(const std::string &in_local_ip)
{ {
WorldServer::m_local_ip = in_local_ip; WorldServer::local_ip = in_local_ip;
return this; return this;
} }
@@ -1264,7 +1226,7 @@ WorldServer *WorldServer::SetLocalIp(const std::string &in_local_ip)
*/ */
WorldServer *WorldServer::SetProtocol(const std::string &in_protocol) WorldServer *WorldServer::SetProtocol(const std::string &in_protocol)
{ {
WorldServer::m_protocol = in_protocol; WorldServer::protocol = in_protocol;
return this; return this;
} }
@@ -1274,7 +1236,7 @@ WorldServer *WorldServer::SetProtocol(const std::string &in_protocol)
*/ */
WorldServer *WorldServer::SetVersion(const std::string &in_version) WorldServer *WorldServer::SetVersion(const std::string &in_version)
{ {
WorldServer::m_version = in_version; WorldServer::version = in_version;
return this; return this;
} }
@@ -1284,7 +1246,7 @@ WorldServer *WorldServer::SetVersion(const std::string &in_version)
*/ */
int WorldServer::GetServerStatus() const int WorldServer::GetServerStatus() const
{ {
return m_server_status; return server_status;
} }
/** /**
@@ -1292,7 +1254,7 @@ int WorldServer::GetServerStatus() const
*/ */
unsigned int WorldServer::GetServerListTypeId() const unsigned int WorldServer::GetServerListTypeId() const
{ {
return m_server_list_type_id; return server_list_type_id;
} }
/** /**
@@ -1300,7 +1262,7 @@ unsigned int WorldServer::GetServerListTypeId() const
*/ */
unsigned int WorldServer::GetServerProcessType() const unsigned int WorldServer::GetServerProcessType() const
{ {
return m_server_process_type; return server_process_type;
} }
/** /**
@@ -1308,7 +1270,7 @@ unsigned int WorldServer::GetServerProcessType() const
*/ */
const std::string &WorldServer::GetAccountName() const const std::string &WorldServer::GetAccountName() const
{ {
return m_account_name; return account_name;
} }
/** /**
@@ -1316,7 +1278,7 @@ const std::string &WorldServer::GetAccountName() const
*/ */
const std::string &WorldServer::GetAccountPassword() const const std::string &WorldServer::GetAccountPassword() const
{ {
return m_account_password; return account_password;
} }
/** /**
@@ -1324,7 +1286,7 @@ const std::string &WorldServer::GetAccountPassword() const
*/ */
const std::string &WorldServer::GetRemoteIp() const const std::string &WorldServer::GetRemoteIp() const
{ {
return m_remote_ip_address; return remote_ip_address;
} }
/** /**
@@ -1332,7 +1294,7 @@ const std::string &WorldServer::GetRemoteIp() const
*/ */
const std::string &WorldServer::GetLocalIp() const const std::string &WorldServer::GetLocalIp() const
{ {
return m_local_ip; return local_ip;
} }
/** /**
@@ -1340,7 +1302,7 @@ const std::string &WorldServer::GetLocalIp() const
*/ */
const std::string &WorldServer::GetProtocol() const const std::string &WorldServer::GetProtocol() const
{ {
return m_protocol; return protocol;
} }
/** /**
@@ -1348,45 +1310,11 @@ const std::string &WorldServer::GetProtocol() const
*/ */
const std::string &WorldServer::GetVersion() const const std::string &WorldServer::GetVersion() const
{ {
return m_version; return version;
} }
void WorldServer::OnKeepAlive(EQ::Timer *t) void WorldServer::OnKeepAlive(EQ::Timer *t)
{ {
ServerPacket pack(ServerOP_KeepAlive, 0); ServerPacket pack(ServerOP_KeepAlive, 0);
m_connection->SendPacket(&pack); connection->SendPacket(&pack);
}
void WorldServer::FormatWorldServerName(char *name, int8 server_list_type)
{
std::string server_long_name = name;
server_long_name = trim(server_long_name);
bool name_set_to_bottom = false;
if (server_list_type == LS::ServerType::Standard) {
if (server.options.IsWorldDevTestServersListBottom()) {
std::string s = str_tolower(server_long_name);
if (s.find("dev") != std::string::npos) {
server_long_name = fmt::format("|D| {}", server_long_name);
name_set_to_bottom = true;
}
else if (s.find("test") != std::string::npos) {
server_long_name = fmt::format("|T| {}", server_long_name);
name_set_to_bottom = true;
}
else if (s.find("installer") != std::string::npos) {
server_long_name = fmt::format("|I| {}", server_long_name);
name_set_to_bottom = true;
}
}
if (server.options.IsWorldSpecialCharacterStartListBottom() && !name_set_to_bottom) {
auto first_char = server_long_name.c_str()[0];
if (IsAllowedWorldServerCharacterList(first_char) && first_char != '|') {
server_long_name = fmt::format("|*| {}", server_long_name);
name_set_to_bottom = true;
}
}
}
strn0cpy(name, server_long_name.c_str(), 201);
} }
+53 -35
View File
@@ -1,3 +1,23 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 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_WORLDSERVER_H #ifndef EQEMU_WORLDSERVER_H
#define EQEMU_WORLDSERVER_H #define EQEMU_WORLDSERVER_H
@@ -30,44 +50,44 @@ public:
/** /**
* Accesses connection, it is intentional that this is not const (trust me). * Accesses connection, it is intentional that this is not const (trust me).
*/ */
std::shared_ptr<EQ::Net::ServertalkServerConnection> GetConnection() { return m_connection; } std::shared_ptr<EQ::Net::ServertalkServerConnection> GetConnection() { return connection; }
void SetConnection(std::shared_ptr<EQ::Net::ServertalkServerConnection> c) { m_connection = c; } void SetConnection(std::shared_ptr<EQ::Net::ServertalkServerConnection> c) { connection = c; }
/** /**
* @return * @return
*/ */
unsigned int GetServerId() const { return m_server_id; } unsigned int GetServerId() const { return server_id; }
WorldServer *SetServerId(unsigned int id) WorldServer *SetServerId(unsigned int id)
{ {
m_server_id = id; server_id = id;
return this; return this;
} }
/** /**
* @return * @return
*/ */
std::string GetServerLongName() const { return m_long_name; } std::string GetServerLongName() const { return long_name; }
std::string GetServerShortName() const { return m_short_name; } std::string GetServerShortName() const { return short_name; }
/** /**
* Gets whether the server is authorized to show up on the server list or not * Gets whether the server is authorized to show up on the server list or not
* @return * @return
*/ */
bool IsAuthorized() const { return m_is_server_authorized; } bool IsAuthorized() const { return is_server_authorized; }
std::string GetLocalIP() const { return m_local_ip; } std::string GetLocalIP() const { return local_ip; }
std::string GetRemoteIP() const { return m_remote_ip_address; } std::string GetRemoteIP() const { return remote_ip_address; }
/** /**
* Gets what kind of server this server is (legends, preferred, normal) * Gets what kind of server this server is (legends, preferred, normal)
* *
* @return * @return
*/ */
unsigned int GetServerListID() const { return m_server_list_type_id; } unsigned int GetServerListID() const { return server_list_type_id; }
WorldServer *SetServerListTypeId(unsigned int in_server_list_id); WorldServer *SetServerListTypeId(unsigned int in_server_list_id);
int GetStatus() const { return m_server_status; } int GetStatus() const { return server_status; }
unsigned int GetZonesBooted() const { return m_zones_booted; } unsigned int GetZonesBooted() const { return zones_booted; }
unsigned int GetPlayersOnline() const { return m_players_online; } unsigned int GetPlayersOnline() const { return players_online; }
/** /**
* Takes the info struct we received from world and processes it * Takes the info struct we received from world and processes it
@@ -150,8 +170,6 @@ public:
bool HandleNewLoginserverRegisteredOnly(Database::DbWorldRegistration &world_registration); bool HandleNewLoginserverRegisteredOnly(Database::DbWorldRegistration &world_registration);
bool HandleNewLoginserverInfoUnregisteredAllowed(Database::DbWorldRegistration &world_registration); bool HandleNewLoginserverInfoUnregisteredAllowed(Database::DbWorldRegistration &world_registration);
void SerializeForClientServerList(class SerializeBuffer& out, bool use_local_ip) const;
private: private:
/** /**
@@ -166,26 +184,27 @@ private:
void ProcessUserToWorldResponse(uint16_t opcode, const EQ::Net::Packet &packet); void ProcessUserToWorldResponse(uint16_t opcode, const EQ::Net::Packet &packet);
void ProcessLSAccountUpdate(uint16_t opcode, const EQ::Net::Packet &packet); void ProcessLSAccountUpdate(uint16_t opcode, const EQ::Net::Packet &packet);
std::shared_ptr<EQ::Net::ServertalkServerConnection> m_connection; std::shared_ptr<EQ::Net::ServertalkServerConnection> connection;
unsigned int m_zones_booted; unsigned int zones_booted;
unsigned int m_players_online; unsigned int players_online;
int m_server_status; int server_status;
unsigned int m_server_id; unsigned int server_id;
unsigned int m_server_list_type_id; unsigned int server_list_type_id;
unsigned int m_server_process_type; unsigned int server_process_type;
std::string m_server_description; std::string server_description;
std::string m_long_name; std::string long_name;
std::string m_short_name; std::string short_name;
std::string m_account_name; std::string account_name;
std::string m_account_password; std::string account_password;
std::string m_remote_ip_address; std::string remote_ip_address;
std::string m_local_ip; std::string local_ip;
std::string m_protocol; std::string protocol;
std::string m_version; std::string version;
bool m_is_server_authorized;
bool m_is_server_logged_in; bool is_server_authorized;
bool m_is_server_trusted; bool is_server_logged_in;
bool is_server_trusted;
/** /**
* Keepalive * Keepalive
@@ -194,7 +213,6 @@ private:
void OnKeepAlive(EQ::Timer *t); void OnKeepAlive(EQ::Timer *t);
std::unique_ptr<EQ::Timer> m_keepalive; std::unique_ptr<EQ::Timer> m_keepalive;
static void FormatWorldServerName(char *name, int8 server_list_type);
}; };
#endif #endif
@@ -157,7 +157,7 @@ foreach my $table_to_generate (@tables) {
$table_found_in_schema = 0; $table_found_in_schema = 0;
} }
if ($table_found_in_schema == 0 && ($requested_table_to_generate eq "" || $requested_table_to_generate eq "all")) { if ($table_found_in_schema == 0) {
print "Table [$table_to_generate] not found in schema, skipping\n"; print "Table [$table_to_generate] not found in schema, skipping\n";
next; next;
} }
-2
View File
@@ -426,8 +426,6 @@
9170|2021_03_03_instance_safereturns.sql|SHOW TABLES LIKE 'character_instance_safereturns'|empty| 9170|2021_03_03_instance_safereturns.sql|SHOW TABLES LIKE 'character_instance_safereturns'|empty|
9171|2021_03_30_remove_dz_is_current_member.sql|SHOW COLUMNS FROM `dynamic_zone_members` LIKE 'is_current_member'|not_empty| 9171|2021_03_30_remove_dz_is_current_member.sql|SHOW COLUMNS FROM `dynamic_zone_members` LIKE 'is_current_member'|not_empty|
9172|2021_05_21_shared_tasks.sql|SHOW TABLES LIKE 'shared_tasks'|empty| 9172|2021_05_21_shared_tasks.sql|SHOW TABLES LIKE 'shared_tasks'|empty|
9173|2021_09_14_zone_lava_damage.sql|SHOW COLUMNS FROM `zone` LIKE 'lava_damage'|empty|
9174|2021_10_09_not_null_door_columns.sql|SELECT * FROM db_version WHERE version >= 9174|empty|
# Upgrade conditions: # Upgrade conditions:
# This won't be needed after this system is implemented, but it is used database that are not # This won't be needed after this system is implemented, but it is used database that are not
@@ -1,3 +0,0 @@
ALTER TABLE login_accounts MODIFY COLUMN last_ip_address VARCHAR(30) NOT NULL;
ALTER TABLE login_server_admins MODIFY COLUMN registration_ip_address VARCHAR(30) NOT NULL;
ALTER TABLE login_world_servers MODIFY COLUMN last_ip_address VARCHAR(30) DEFAULT NULL;
@@ -10,4 +10,4 @@ CREATE TABLE `character_instance_safereturns` (
`safe_heading` float NOT NULL DEFAULT 0, `safe_heading` float NOT NULL DEFAULT 0,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `character_id` (`character_id`) UNIQUE KEY `character_id` (`character_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1; ) ENGINE=InnoDB DEFAULT CHARSET=latin1
@@ -1 +0,0 @@
ALTER TABLE zone ADD lava_damage INT(11) NULL DEFAULT '50' AFTER underworld_teleport_index, ADD min_lava_damage INT(11) NOT NULL DEFAULT '10' AFTER lava_damage;
@@ -1,18 +0,0 @@
-- update any null columns to non-null value first to avoid data truncation errors
-- this will likely only affect the buffer column
update `doors` set `doors`.`dest_x` = 0 where `doors`.`dest_x` is null;
update `doors` set `doors`.`dest_y` = 0 where `doors`.`dest_y` is null;
update `doors` set `doors`.`dest_z` = 0 where `doors`.`dest_z` is null;
update `doors` set `doors`.`dest_heading` = 0 where `doors`.`dest_heading` is null;
update `doors` set `doors`.`invert_state` = 0 where `doors`.`invert_state` is null;
update `doors` set `doors`.`incline` = 0 where `doors`.`incline` is null;
update `doors` set `doors`.`buffer` = 0 where `doors`.`buffer` is null;
ALTER TABLE `doors`
CHANGE COLUMN `dest_x` `dest_x` FLOAT NOT NULL DEFAULT '0' AFTER `dest_instance`,
CHANGE COLUMN `dest_y` `dest_y` FLOAT NOT NULL DEFAULT '0' AFTER `dest_x`,
CHANGE COLUMN `dest_z` `dest_z` FLOAT NOT NULL DEFAULT '0' AFTER `dest_y`,
CHANGE COLUMN `dest_heading` `dest_heading` FLOAT NOT NULL DEFAULT '0' AFTER `dest_z`,
CHANGE COLUMN `invert_state` `invert_state` INT(11) NOT NULL DEFAULT '0' AFTER `dest_heading`,
CHANGE COLUMN `incline` `incline` INT(11) NOT NULL DEFAULT '0' AFTER `invert_state`,
CHANGE COLUMN `buffer` `buffer` FLOAT NOT NULL DEFAULT '0' AFTER `size`;
+61 -59
View File
@@ -1343,67 +1343,71 @@ void ClientList::GetClients(const char *zone_name, std::vector<ClientListEntry *
void ClientList::SendClientVersionSummary(const char *Name) void ClientList::SendClientVersionSummary(const char *Name)
{ {
std::vector<uint32> unique_ips; uint32 ClientTitaniumCount = 0;
std::map<EQ::versions::ClientVersion,int> client_count = { uint32 ClientSoFCount = 0;
{ EQ::versions::ClientVersion::Titanium, 0 }, uint32 ClientSoDCount = 0;
{ EQ::versions::ClientVersion::SoF, 0 }, uint32 ClientUnderfootCount = 0;
{ EQ::versions::ClientVersion::SoD, 0 }, uint32 ClientRoFCount = 0;
{ EQ::versions::ClientVersion::UF, 0 }, uint32 ClientRoF2Count = 0;
{ EQ::versions::ClientVersion::RoF, 0 },
{ EQ::versions::ClientVersion::RoF2, 0 }
};
LinkedListIterator<ClientListEntry*> Iterator(clientlist); LinkedListIterator<ClientListEntry*> Iterator(clientlist);
Iterator.Reset();
while (Iterator.MoreElements()) {
ClientListEntry* CLE = Iterator.GetData();
if (CLE && CLE->zone()) {
auto client_version = CLE->GetClientVersion();
if (
client_version >= (uint8) EQ::versions::ClientVersion::Titanium &&
client_version <= (uint8) EQ::versions::ClientVersion::RoF2
) {
client_count[(EQ::versions::ClientVersion)client_version]++;
}
if (std::find(unique_ips.begin(), unique_ips.begin(), CLE->GetIP()) == unique_ips.end()) { Iterator.Reset();
unique_ips.push_back(CLE->GetIP());
while(Iterator.MoreElements())
{
ClientListEntry* CLE = Iterator.GetData();
if(CLE && CLE->zone())
{
switch(CLE->GetClientVersion())
{
case 1:
{
break;
}
case 2:
{
++ClientTitaniumCount;
break;
}
case 3:
{
++ClientSoFCount;
break;
}
case 4:
{
++ClientSoDCount;
break;
}
case 5:
{
++ClientUnderfootCount;
break;
}
case 6:
{
++ClientRoFCount;
break;
}
case 7:
{
++ClientRoF2Count;
break;
}
default:
break;
} }
} }
Iterator.Advance(); Iterator.Advance();
} }
uint32 total_clients = ( zoneserver_list.SendEmoteMessage(Name, 0, 0, 13, "There are %i Titanium, %i SoF, %i SoD, %i UF, %i RoF, %i RoF2 clients currently connected.",
client_count[EQ::versions::ClientVersion::Titanium] + ClientTitaniumCount, ClientSoFCount, ClientSoDCount, ClientUnderfootCount, ClientRoFCount, ClientRoF2Count);
client_count[EQ::versions::ClientVersion::SoF] +
client_count[EQ::versions::ClientVersion::SoD] +
client_count[EQ::versions::ClientVersion::UF] +
client_count[EQ::versions::ClientVersion::RoF] +
client_count[EQ::versions::ClientVersion::RoF2]
);
zoneserver_list.SendEmoteMessage(
Name,
0,
0,
Chat::White,
fmt::format(
"There {} {} Titanium, {} SoF, {} SoD, {} UF, {} RoF, and {} RoF2 Client{} currently connected for a total of {} Client{} and {} Unique IP{} connected.",
(total_clients != 1 ? "are" : "is"),
client_count[EQ::versions::ClientVersion::Titanium],
client_count[EQ::versions::ClientVersion::SoF],
client_count[EQ::versions::ClientVersion::SoD],
client_count[EQ::versions::ClientVersion::UF],
client_count[EQ::versions::ClientVersion::RoF],
client_count[EQ::versions::ClientVersion::RoF2],
(total_clients != 1 ? "s" : ""),
total_clients,
(total_clients != 1 ? "s" : ""),
unique_ips.size(),
(unique_ips.size() != 1 ? "s" : "")
).c_str()
);
} }
void ClientList::OnTick(EQ::Timer *t) void ClientList::OnTick(EQ::Timer *t)
@@ -1585,14 +1589,12 @@ void ClientList::SendCharacterMessage(ClientListEntry* character, int chat_type,
return; return;
} }
uint32_t pack_size = sizeof(CZMessage_Struct); uint32_t pack_size = sizeof(CZMessagePlayer_Struct);
auto pack = std::make_unique<ServerPacket>(ServerOP_CZMessage, pack_size); auto pack = std::make_unique<ServerPacket>(ServerOP_CZMessagePlayer, pack_size);
auto buf = reinterpret_cast<CZMessage_Struct*>(pack->pBuffer); auto buf = reinterpret_cast<CZMessagePlayer_Struct*>(pack->pBuffer);
buf->update_type = CZUpdateType_ClientName;
buf->update_identifier = 0;
buf->type = chat_type; buf->type = chat_type;
strn0cpy(buf->character_name, character->name(), sizeof(buf->character_name));
strn0cpy(buf->message, message.c_str(), sizeof(buf->message)); strn0cpy(buf->message, message.c_str(), sizeof(buf->message));
strn0cpy(buf->client_name, character->name(), sizeof(buf->client_name));
character->Server()->SendPacket(pack.get()); character->Server()->SendPacket(pack.get());
} }
@@ -1631,7 +1633,7 @@ void ClientList::SendCharacterMessageID(ClientListEntry* character,
auto buf = reinterpret_cast<CZClientMessageString_Struct*>(pack->pBuffer); auto buf = reinterpret_cast<CZClientMessageString_Struct*>(pack->pBuffer);
buf->string_id = eqstr_id; buf->string_id = eqstr_id;
buf->chat_type = chat_type; buf->chat_type = chat_type;
strn0cpy(buf->client_name, character->name(), sizeof(buf->client_name)); strn0cpy(buf->character_name, character->name(), sizeof(buf->character_name));
buf->args_size = args_size; buf->args_size = args_size;
memcpy(buf->args, serialized_args.buffer(), serialized_args.size()); memcpy(buf->args, serialized_args.buffer(), serialized_args.size());
+9 -16
View File
@@ -778,14 +778,8 @@ void ConsoleWorldShutdown(
zoneserver_list.WorldShutDown(0, 0); zoneserver_list.WorldShutDown(0, 0);
} }
else if (strcasecmp(args[0].c_str(), "disable") == 0) { else if (strcasecmp(args[0].c_str(), "disable") == 0) {
connection->SendLine("[SYSTEM] World shutdown has been aborted."); connection->SendLine("<SYSTEMWIDE MESSAGE>:SYSTEM MSG:World shutdown aborted.");
zoneserver_list.SendEmoteMessage( zoneserver_list.SendEmoteMessage(0, 0, 0, 15, "<SYSTEMWIDE MESSAGE>:SYSTEM MSG:World shutdown aborted.");
0,
0,
0,
Chat::Yellow,
"[SYSTEM] World shutdown has been aborted."
);
zoneserver_list.shutdowntimer->Disable(); zoneserver_list.shutdowntimer->Disable();
zoneserver_list.reminder->Disable(); zoneserver_list.reminder->Disable();
} }
@@ -832,14 +826,13 @@ void ConsoleSignalCharByName(
connection->SendLine(StringFormat("Signal Sent to %s with ID %i", (char *) args[0].c_str(), atoi(args[1].c_str()))); connection->SendLine(StringFormat("Signal Sent to %s with ID %i", (char *) args[0].c_str(), atoi(args[1].c_str())));
uint32 message_len = strlen((char *) args[0].c_str()) + 1; uint32 message_len = strlen((char *) args[0].c_str()) + 1;
auto pack = new ServerPacket(ServerOP_CZSignal, sizeof(CZSignal_Struct) + message_len); auto pack = new ServerPacket(
CZSignal_Struct* CZS = (CZSignal_Struct*) pack->pBuffer; ServerOP_CZSignalClientByName,
uint8 update_type = CZUpdateType_ClientName; sizeof(CZClientSignalByName_Struct) + message_len
int update_identifier = 0; );
CZS->update_type = update_type; CZClientSignalByName_Struct *CZSC = (CZClientSignalByName_Struct *) pack->pBuffer;
CZS->update_identifier = update_identifier; strn0cpy(CZSC->character_name, (char *) args[0].c_str(), 64);
CZS->signal = atoi(args[1].c_str()); CZSC->signal = atoi(args[1].c_str());
strn0cpy(CZS->client_name, (char *) args[0].c_str(), 64);
zoneserver_list.SendPacket(pack); zoneserver_list.SendPacket(pack);
safe_delete(pack); safe_delete(pack);
} }
+2 -14
View File
@@ -750,20 +750,8 @@ void Console::ProcessCommand(const char* command) {
zoneserver_list.WorldShutDown(0, 0); zoneserver_list.WorldShutDown(0, 0);
} }
else if(strcasecmp(sep.arg[1], "disable") == 0) { else if(strcasecmp(sep.arg[1], "disable") == 0) {
SendEmoteMessage( SendEmoteMessage(0,0,0,15,"<SYSTEMWIDE MESSAGE>:SYSTEM MSG:World shutdown aborted.");
0, zoneserver_list.SendEmoteMessage(0,0,0,15,"<SYSTEMWIDE MESSAGE>:SYSTEM MSG:World shutdown aborted.");
0,
0,
Chat::Yellow,
"[SYSTEM] World shutdown has been aborted."
);
zoneserver_list.SendEmoteMessage(
0,
0,
0,
Chat::Yellow,
"[SYSTEM] World shutdown has been aborted."
);
zoneserver_list.shutdowntimer->Disable(); zoneserver_list.shutdowntimer->Disable();
zoneserver_list.reminder->Disable(); zoneserver_list.reminder->Disable();
} }
+69 -100
View File
@@ -46,12 +46,12 @@ extern volatile bool RunLoops;
LoginServer::LoginServer(const char *iAddress, uint16 iPort, const char *Account, const char *Password, bool legacy) LoginServer::LoginServer(const char *iAddress, uint16 iPort, const char *Account, const char *Password, bool legacy)
{ {
strn0cpy(m_loginserver_address, iAddress, 256); strn0cpy(LoginServerAddress, iAddress, 256);
m_loginserver_port = iPort; LoginServerPort = iPort;
m_login_account = Account; LoginAccount = Account;
m_login_password = Password; LoginPassword = Password;
m_can_account_update = false; CanAccountUpdate = false;
m_is_legacy = legacy; IsLegacy = legacy;
Connect(); Connect();
} }
@@ -93,10 +93,7 @@ void LoginServer::ProcessUsertoWorldReqLeg(uint16_t opcode, EQ::Net::Packet &p)
if (Config->Locked) { if (Config->Locked) {
if (status < (RuleI(GM, MinStatusToBypassLockedServer))) { if (status < (RuleI(GM, MinStatusToBypassLockedServer))) {
LogDebug( LogDebug("[ProcessUsertoWorldReqLeg] Server locked and status is not high enough for account_id [{0}]", utwr->lsaccountid);
"[ProcessUsertoWorldReqLeg] Server locked and status is not high enough for account_id [{0}]",
utwr->lsaccountid
);
utwrs->response = UserToWorldStatusWorldUnavail; utwrs->response = UserToWorldStatusWorldUnavail;
SendPacket(&outpack); SendPacket(&outpack);
return; return;
@@ -174,10 +171,7 @@ void LoginServer::ProcessUsertoWorldReq(uint16_t opcode, EQ::Net::Packet &p)
if (Config->Locked == true) { if (Config->Locked == true) {
if (status < (RuleI(GM, MinStatusToBypassLockedServer))) { if (status < (RuleI(GM, MinStatusToBypassLockedServer))) {
LogDebug( LogDebug("[ProcessUsertoWorldReq] Server locked and status is not high enough for account_id [{0}]", utwr->lsaccountid);
"[ProcessUsertoWorldReq] Server locked and status is not high enough for account_id [{0}]",
utwr->lsaccountid
);
utwrs->response = UserToWorldStatusWorldUnavail; utwrs->response = UserToWorldStatusWorldUnavail;
SendPacket(&outpack); SendPacket(&outpack);
return; return;
@@ -326,63 +320,61 @@ void LoginServer::ProcessLSAccountUpdate(uint16_t opcode, EQ::Net::Packet &p)
LogNetcode("Received ServerPacket from LS OpCode {:#04x}", opcode); LogNetcode("Received ServerPacket from LS OpCode {:#04x}", opcode);
LogNetcode("Received ServerOP_LSAccountUpdate packet from loginserver"); LogNetcode("Received ServerOP_LSAccountUpdate packet from loginserver");
m_can_account_update = true; CanAccountUpdate = true;
} }
bool LoginServer::Connect() bool LoginServer::Connect()
{ {
char errbuf[1024]; char errbuf[1024];
if ((m_loginserver_ip = ResolveIP(m_loginserver_address, errbuf)) == 0) { if ((LoginServerIP = ResolveIP(LoginServerAddress, errbuf)) == 0) {
LogInfo("Unable to resolve [{}] to an IP", m_loginserver_address); LogInfo("Unable to resolve [{}] to an IP", LoginServerAddress);
return false; return false;
} }
if (m_loginserver_ip == 0 || m_loginserver_port == 0) { if (LoginServerIP == 0 || LoginServerPort == 0) {
LogInfo( LogInfo(
"Connect info incomplete, cannot connect: [{0}:{1}]", "Connect info incomplete, cannot connect: [{0}:{1}]",
m_loginserver_address, LoginServerAddress,
m_loginserver_port LoginServerPort
); );
return false; return false;
} }
if (m_is_legacy) { if (IsLegacy) {
m_legacy_client = std::make_unique<EQ::Net::ServertalkLegacyClient>( legacy_client = std::make_unique<EQ::Net::ServertalkLegacyClient>(LoginServerAddress, LoginServerPort, false);
m_loginserver_address, legacy_client->OnConnect(
m_loginserver_port,
false
);
m_legacy_client->OnConnect(
[this](EQ::Net::ServertalkLegacyClient *client) { [this](EQ::Net::ServertalkLegacyClient *client) {
if (client) { if (client) {
LogInfo( LogInfo(
"Connected to Legacy Loginserver: [{0}:{1}]", "Connected to Legacy Loginserver: [{0}:{1}]",
m_loginserver_address, LoginServerAddress,
m_loginserver_port LoginServerPort
); );
SendInfo(); SendInfo();
SendStatus(); SendStatus();
zoneserver_list.SendLSZones(); zoneserver_list.SendLSZones();
m_statusupdate_timer = std::make_unique<EQ::Timer>( statusupdate_timer = std::make_unique<EQ::Timer>(
LoginServer_StatusUpdateInterval, true, [this](EQ::Timer *t) { LoginServer_StatusUpdateInterval, true, [this](EQ::Timer *t) {
SendStatus(); SendStatus();
} }
); );
} }
else { else {
LogInfo( LogInfo(
"Could not connect to Legacy Loginserver: [{0}:{1}]", "Could not connect to Legacy Loginserver: [{0}:{1}]",
m_loginserver_address, LoginServerAddress,
m_loginserver_port LoginServerPort
); );
} }
} }
); );
m_legacy_client->OnMessage( legacy_client->OnMessage(
ServerOP_UsertoWorldReqLeg, ServerOP_UsertoWorldReqLeg,
std::bind( std::bind(
&LoginServer::ProcessUsertoWorldReqLeg, &LoginServer::ProcessUsertoWorldReqLeg,
@@ -391,7 +383,7 @@ bool LoginServer::Connect()
std::placeholders::_2 std::placeholders::_2
) )
); );
m_legacy_client->OnMessage( legacy_client->OnMessage(
ServerOP_UsertoWorldReq, ServerOP_UsertoWorldReq,
std::bind( std::bind(
&LoginServer::ProcessUsertoWorldReq, &LoginServer::ProcessUsertoWorldReq,
@@ -400,7 +392,7 @@ bool LoginServer::Connect()
std::placeholders::_2 std::placeholders::_2
) )
); );
m_legacy_client->OnMessage( legacy_client->OnMessage(
ServerOP_LSClientAuthLeg, ServerOP_LSClientAuthLeg,
std::bind( std::bind(
&LoginServer::ProcessLSClientAuthLegacy, &LoginServer::ProcessLSClientAuthLegacy,
@@ -409,7 +401,7 @@ bool LoginServer::Connect()
std::placeholders::_2 std::placeholders::_2
) )
); );
m_legacy_client->OnMessage( legacy_client->OnMessage(
ServerOP_LSClientAuth, ServerOP_LSClientAuth,
std::bind( std::bind(
&LoginServer::ProcessLSClientAuth, &LoginServer::ProcessLSClientAuth,
@@ -418,7 +410,7 @@ bool LoginServer::Connect()
std::placeholders::_2 std::placeholders::_2
) )
); );
m_legacy_client->OnMessage( legacy_client->OnMessage(
ServerOP_LSFatalError, ServerOP_LSFatalError,
std::bind( std::bind(
&LoginServer::ProcessLSFatalError, &LoginServer::ProcessLSFatalError,
@@ -427,7 +419,7 @@ bool LoginServer::Connect()
std::placeholders::_2 std::placeholders::_2
) )
); );
m_legacy_client->OnMessage( legacy_client->OnMessage(
ServerOP_SystemwideMessage, ServerOP_SystemwideMessage,
std::bind( std::bind(
&LoginServer::ProcessSystemwideMessage, &LoginServer::ProcessSystemwideMessage,
@@ -436,7 +428,7 @@ bool LoginServer::Connect()
std::placeholders::_2 std::placeholders::_2
) )
); );
m_legacy_client->OnMessage( legacy_client->OnMessage(
ServerOP_LSRemoteAddr, ServerOP_LSRemoteAddr,
std::bind( std::bind(
&LoginServer::ProcessLSRemoteAddr, &LoginServer::ProcessLSRemoteAddr,
@@ -445,7 +437,7 @@ bool LoginServer::Connect()
std::placeholders::_2 std::placeholders::_2
) )
); );
m_legacy_client->OnMessage( legacy_client->OnMessage(
ServerOP_LSAccountUpdate, ServerOP_LSAccountUpdate,
std::bind( std::bind(
&LoginServer::ProcessLSAccountUpdate, &LoginServer::ProcessLSAccountUpdate,
@@ -456,26 +448,20 @@ bool LoginServer::Connect()
); );
} }
else { else {
m_client = std::make_unique<EQ::Net::ServertalkClient>( client = std::make_unique<EQ::Net::ServertalkClient>(LoginServerAddress, LoginServerPort, false, "World", "");
m_loginserver_address, client->OnConnect(
m_loginserver_port,
false,
"World",
""
);
m_client->OnConnect(
[this](EQ::Net::ServertalkClient *client) { [this](EQ::Net::ServertalkClient *client) {
if (client) { if (client) {
LogInfo( LogInfo(
"Connected to Loginserver: [{0}:{1}]", "Connected to Loginserver: [{0}:{1}]",
m_loginserver_address, LoginServerAddress,
m_loginserver_port LoginServerPort
); );
SendInfo(); SendInfo();
SendStatus(); SendStatus();
zoneserver_list.SendLSZones(); zoneserver_list.SendLSZones();
m_statusupdate_timer = std::make_unique<EQ::Timer>( statusupdate_timer = std::make_unique<EQ::Timer>(
LoginServer_StatusUpdateInterval, true, [this](EQ::Timer *t) { LoginServer_StatusUpdateInterval, true, [this](EQ::Timer *t) {
SendStatus(); SendStatus();
@@ -485,14 +471,14 @@ bool LoginServer::Connect()
else { else {
LogInfo( LogInfo(
"Could not connect to Loginserver: [{0}:{1}]", "Could not connect to Loginserver: [{0}:{1}]",
m_loginserver_address, LoginServerAddress,
m_loginserver_port LoginServerPort
); );
} }
} }
); );
m_client->OnMessage( client->OnMessage(
ServerOP_UsertoWorldReqLeg, ServerOP_UsertoWorldReqLeg,
std::bind( std::bind(
&LoginServer::ProcessUsertoWorldReqLeg, &LoginServer::ProcessUsertoWorldReqLeg,
@@ -501,7 +487,7 @@ bool LoginServer::Connect()
std::placeholders::_2 std::placeholders::_2
) )
); );
m_client->OnMessage( client->OnMessage(
ServerOP_UsertoWorldReq, ServerOP_UsertoWorldReq,
std::bind( std::bind(
&LoginServer::ProcessUsertoWorldReq, &LoginServer::ProcessUsertoWorldReq,
@@ -510,7 +496,7 @@ bool LoginServer::Connect()
std::placeholders::_2 std::placeholders::_2
) )
); );
m_client->OnMessage( client->OnMessage(
ServerOP_LSClientAuthLeg, ServerOP_LSClientAuthLeg,
std::bind( std::bind(
&LoginServer::ProcessLSClientAuthLegacy, &LoginServer::ProcessLSClientAuthLegacy,
@@ -519,7 +505,7 @@ bool LoginServer::Connect()
std::placeholders::_2 std::placeholders::_2
) )
); );
m_client->OnMessage( client->OnMessage(
ServerOP_LSClientAuth, ServerOP_LSClientAuth,
std::bind( std::bind(
&LoginServer::ProcessLSClientAuth, &LoginServer::ProcessLSClientAuth,
@@ -528,7 +514,7 @@ bool LoginServer::Connect()
std::placeholders::_2 std::placeholders::_2
) )
); );
m_client->OnMessage( client->OnMessage(
ServerOP_LSFatalError, ServerOP_LSFatalError,
std::bind( std::bind(
&LoginServer::ProcessLSFatalError, &LoginServer::ProcessLSFatalError,
@@ -537,7 +523,7 @@ bool LoginServer::Connect()
std::placeholders::_2 std::placeholders::_2
) )
); );
m_client->OnMessage( client->OnMessage(
ServerOP_SystemwideMessage, ServerOP_SystemwideMessage,
std::bind( std::bind(
&LoginServer::ProcessSystemwideMessage, &LoginServer::ProcessSystemwideMessage,
@@ -546,7 +532,7 @@ bool LoginServer::Connect()
std::placeholders::_2 std::placeholders::_2
) )
); );
m_client->OnMessage( client->OnMessage(
ServerOP_LSRemoteAddr, ServerOP_LSRemoteAddr,
std::bind( std::bind(
&LoginServer::ProcessLSRemoteAddr, &LoginServer::ProcessLSRemoteAddr,
@@ -555,7 +541,7 @@ bool LoginServer::Connect()
std::placeholders::_2 std::placeholders::_2
) )
); );
m_client->OnMessage( client->OnMessage(
ServerOP_LSAccountUpdate, ServerOP_LSAccountUpdate,
std::bind( std::bind(
&LoginServer::ProcessLSAccountUpdate, &LoginServer::ProcessLSAccountUpdate,
@@ -566,10 +552,7 @@ bool LoginServer::Connect()
); );
} }
m_keepalive = std::make_unique<EQ::Timer>( m_keepalive = std::make_unique<EQ::Timer>(1000, true, std::bind(&LoginServer::OnKeepAlive, this, std::placeholders::_1));
1000,
true,
std::bind(&LoginServer::OnKeepAlive, this, std::placeholders::_1));
return true; return true;
} }
@@ -583,42 +566,28 @@ void LoginServer::SendInfo()
pack->size = sizeof(ServerNewLSInfo_Struct); pack->size = sizeof(ServerNewLSInfo_Struct);
pack->pBuffer = new uchar[pack->size]; pack->pBuffer = new uchar[pack->size];
memset(pack->pBuffer, 0, pack->size); memset(pack->pBuffer, 0, pack->size);
ServerNewLSInfo_Struct *lsi = (ServerNewLSInfo_Struct *) pack->pBuffer;
auto *l = (ServerNewLSInfo_Struct *) pack->pBuffer; strcpy(lsi->protocol_version, EQEMU_PROTOCOL_VERSION);
strcpy(l->protocol_version, EQEMU_PROTOCOL_VERSION); strcpy(lsi->server_version, LOGIN_VERSION);
strcpy(l->server_version, LOGIN_VERSION); strcpy(lsi->server_long_name, Config->LongName.c_str());
strcpy(l->server_long_name, Config->LongName.c_str()); strcpy(lsi->server_short_name, Config->ShortName.c_str());
strcpy(l->server_short_name, Config->ShortName.c_str()); strn0cpy(lsi->account_name, LoginAccount.c_str(), 30);
strn0cpy(l->account_name, m_login_account.c_str(), 30); strn0cpy(lsi->account_password, LoginPassword.c_str(), 30);
strn0cpy(l->account_password, m_login_password.c_str(), 30);
if (Config->WorldAddress.length()) { if (Config->WorldAddress.length()) {
strcpy(l->remote_ip_address, Config->WorldAddress.c_str()); strcpy(lsi->remote_ip_address, Config->WorldAddress.c_str());
} }
if (Config->LocalAddress.length()) { if (Config->LocalAddress.length()) {
strcpy(l->local_ip_address, Config->LocalAddress.c_str()); strcpy(lsi->local_ip_address, Config->LocalAddress.c_str());
} }
else { else {
auto local_addr = m_is_legacy ? m_legacy_client->Handle()->LocalIP() : m_client->Handle()->LocalIP(); auto local_addr = IsLegacy ? legacy_client->Handle()->LocalIP() : client->Handle()->LocalIP();
strcpy(l->local_ip_address, local_addr.c_str()); strcpy(lsi->local_ip_address, local_addr.c_str());
WorldConfig::SetLocalAddress(l->local_ip_address); WorldConfig::SetLocalAddress(lsi->local_ip_address);
} }
LogInfo(
"[LoginServer::SendInfo] protocol_version [{}] server_version [{}] long_name [{}] short_name [{}] account_name [{}] remote_ip_address [{}] local_ip [{}]",
l->protocol_version,
l->server_version,
l->server_long_name,
l->server_short_name,
l->account_name,
l->remote_ip_address,
l->local_ip_address
);
SendPacket(pack); SendPacket(pack);
delete pack; delete pack;
} }
void LoginServer::SendStatus() void LoginServer::SendStatus()
{ {
auto pack = new ServerPacket; auto pack = new ServerPacket;
@@ -649,14 +618,14 @@ void LoginServer::SendStatus()
*/ */
void LoginServer::SendPacket(ServerPacket *pack) void LoginServer::SendPacket(ServerPacket *pack)
{ {
if (m_is_legacy) { if (IsLegacy) {
if (m_legacy_client) { if (legacy_client) {
m_legacy_client->SendPacket(pack); legacy_client->SendPacket(pack);
} }
} }
else { else {
if (m_client) { if (client) {
m_client->SendPacket(pack); client->SendPacket(pack);
} }
} }
} }
@@ -667,11 +636,11 @@ void LoginServer::SendAccountUpdate(ServerPacket *pack)
if (CanUpdate()) { if (CanUpdate()) {
LogInfo( LogInfo(
"Sending ServerOP_LSAccountUpdate packet to loginserver: [{0}]:[{1}]", "Sending ServerOP_LSAccountUpdate packet to loginserver: [{0}]:[{1}]",
m_loginserver_address, LoginServerAddress,
m_loginserver_port LoginServerPort
); );
strn0cpy(ls_account_update->worldaccount, m_login_account.c_str(), 30); strn0cpy(ls_account_update->worldaccount, LoginAccount.c_str(), 30);
strn0cpy(ls_account_update->worldpassword, m_login_password.c_str(), 30); strn0cpy(ls_account_update->worldpassword, LoginPassword.c_str(), 30);
SendPacket(pack); SendPacket(pack);
} }
} }
+33 -16
View File
@@ -1,3 +1,20 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef LOGINSERVER_H #ifndef LOGINSERVER_H
#define LOGINSERVER_H #define LOGINSERVER_H
@@ -25,20 +42,20 @@ public:
void SendAccountUpdate(ServerPacket *pack); void SendAccountUpdate(ServerPacket *pack);
bool Connected() bool Connected()
{ {
if (m_is_legacy) { if (IsLegacy) {
if (m_legacy_client) { if (legacy_client) {
return m_legacy_client->Connected(); return legacy_client->Connected();
} }
} }
else { else {
if (m_client) { if (client) {
return m_client->Connected(); return client->Connected();
} }
} }
return false; return false;
} }
bool CanUpdate() { return m_can_account_update; } bool CanUpdate() { return CanAccountUpdate; }
private: private:
void ProcessUsertoWorldReqLeg(uint16_t opcode, EQ::Net::Packet &p); void ProcessUsertoWorldReqLeg(uint16_t opcode, EQ::Net::Packet &p);
@@ -53,15 +70,15 @@ private:
void OnKeepAlive(EQ::Timer *t); void OnKeepAlive(EQ::Timer *t);
std::unique_ptr<EQ::Timer> m_keepalive; std::unique_ptr<EQ::Timer> m_keepalive;
std::unique_ptr<EQ::Net::ServertalkClient> m_client; std::unique_ptr<EQ::Net::ServertalkClient> client;
std::unique_ptr<EQ::Net::ServertalkLegacyClient> m_legacy_client; std::unique_ptr<EQ::Net::ServertalkLegacyClient> legacy_client;
std::unique_ptr<EQ::Timer> m_statusupdate_timer; std::unique_ptr<EQ::Timer> statusupdate_timer;
char m_loginserver_address[256]; char LoginServerAddress[256];
uint32 m_loginserver_ip; uint32 LoginServerIP;
uint16 m_loginserver_port; uint16 LoginServerPort;
std::string m_login_account; std::string LoginAccount;
std::string m_login_password; std::string LoginPassword;
bool m_can_account_update; bool CanAccountUpdate;
bool m_is_legacy; bool IsLegacy;
}; };
#endif #endif
+1 -1
View File
@@ -1311,7 +1311,7 @@ void SharedTaskManager::SendMembersMessageID(
for (const auto &member : shared_task->GetMembers()) { for (const auto &member : shared_task->GetMembers()) {
auto character = client_list.FindCLEByCharacterID(member.character_id); auto character = client_list.FindCLEByCharacterID(member.character_id);
if (character && character->Server()) { if (character && character->Server()) {
strn0cpy(buf->client_name, character->name(), sizeof(buf->client_name)); strn0cpy(buf->character_name, character->name(), sizeof(buf->character_name));
character->Server()->SendPacket(pack.get()); character->Server()->SendPacket(pack.get());
} }
} }
+47 -58
View File
@@ -645,12 +645,7 @@ bool WorldDatabase::GetStartZone(
} }
void WorldDatabase::SetSoFDefaultStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct* in_cc){ void WorldDatabase::SetSoFDefaultStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct* in_cc){
int sof_start_zone_id = RuleI(World, SoFStartZoneID); if (in_cc->start_zone == RuleI(World, TutorialZoneID)) {
if (sof_start_zone_id > 0) {
in_pp->zone_id = sof_start_zone_id;
in_cc->start_zone = in_pp->zone_id;
}
else if (in_cc->start_zone == RuleI(World, TutorialZoneID)) {
in_pp->zone_id = in_cc->start_zone; in_pp->zone_id = in_cc->start_zone;
} }
else { else {
@@ -658,114 +653,108 @@ void WorldDatabase::SetSoFDefaultStartZone(PlayerProfile_Struct* in_pp, CharCrea
in_pp->y = in_pp->binds[0].y = -20.0f; in_pp->y = in_pp->binds[0].y = -20.0f;
in_pp->z = in_pp->binds[0].z = 0.79f; in_pp->z = in_pp->binds[0].z = 0.79f;
in_pp->heading = in_pp->binds[0].heading = 0.0f; in_pp->heading = in_pp->binds[0].heading = 0.0f;
in_pp->zone_id = in_pp->binds[0].zone_id = Zones::CRESCENT; // Crescent Reach. in_pp->zone_id = in_pp->binds[0].zone_id = 394; // Crescent Reach.
} }
} }
void WorldDatabase::SetTitaniumDefaultStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct* in_cc) void WorldDatabase::SetTitaniumDefaultStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct* in_cc)
{ {
int titanium_start_zone_id = RuleI(World, TitaniumStartZoneID);
if (titanium_start_zone_id > 0) {
in_pp->zone_id = titanium_start_zone_id;
in_pp->binds[0].zone_id = titanium_start_zone_id;
} else {
switch (in_cc->start_zone) switch (in_cc->start_zone)
{ {
case StartZoneIndex::Odus: case 0:
{ {
if (in_cc->deity == EQ::deity::DeityCazicThule) // Cazic-Thule Erudites go to Paineel if (in_cc->deity == 203) // Cazic-Thule Erudites go to Paineel
{ {
in_pp->zone_id = Zones::PAINEEL; // paineel in_pp->zone_id = 75; // paineel
in_pp->binds[0].zone_id = Zones::PAINEEL; in_pp->binds[0].zone_id = 75;
} }
else else
{ {
in_pp->zone_id = Zones::ERUDNEXT; // erudnext in_pp->zone_id = 24; // erudnext
in_pp->binds[0].zone_id = Zones::TOX; // tox in_pp->binds[0].zone_id = 38; // tox
} }
break; break;
} }
case StartZoneIndex::Qeynos: case 1:
{ {
in_pp->zone_id = Zones::QEYNOS2; // qeynos2 in_pp->zone_id = 2; // qeynos2
in_pp->binds[0].zone_id = Zones::QEYNOS2; // qeynos2 in_pp->binds[0].zone_id = 2; // qeynos2
break; break;
} }
case StartZoneIndex::Halas: case 2:
{ {
in_pp->zone_id = Zones::HALAS; // halas in_pp->zone_id = 29; // halas
in_pp->binds[0].zone_id = Zones::EVERFROST; // everfrost in_pp->binds[0].zone_id = 30; // everfrost
break; break;
} }
case StartZoneIndex::Rivervale: case 3:
{ {
in_pp->zone_id = Zones::RIVERVALE; // rivervale in_pp->zone_id = 19; // rivervale
in_pp->binds[0].zone_id = Zones::KITHICOR; // kithicor in_pp->binds[0].zone_id = 20; // kithicor
break; break;
} }
case StartZoneIndex::Freeport: case 4:
{ {
in_pp->zone_id = Zones::FREPORTW; // freportw in_pp->zone_id = 9; // freportw
in_pp->binds[0].zone_id = Zones::FREPORTW; // freportw in_pp->binds[0].zone_id = 9; // freportw
break; break;
} }
case StartZoneIndex::Neriak: case 5:
{ {
in_pp->zone_id = Zones::NERIAKA; // neriaka in_pp->zone_id = 40; // neriaka
in_pp->binds[0].zone_id = Zones::NEKTULOS; // nektulos in_pp->binds[0].zone_id = 25; // nektulos
break; break;
} }
case StartZoneIndex::Grobb: case 6:
{ {
in_pp->zone_id = Zones::GROBB; // grobb in_pp->zone_id = 52; // gukta
in_pp->binds[0].zone_id = Zones::INNOTHULE; // innothule in_pp->binds[0].zone_id = 46; // innothule
break; break;
} }
case StartZoneIndex::Oggok: case 7:
{ {
in_pp->zone_id = Zones::OGGOK; // oggok in_pp->zone_id = 49; // oggok
in_pp->binds[0].zone_id = Zones::FEERROTT; // feerrott in_pp->binds[0].zone_id = 47; // feerrott
break; break;
} }
case StartZoneIndex::Kaladim: case 8:
{ {
in_pp->zone_id = Zones::KALADIMA; // kaladima in_pp->zone_id = 60; // kaladima
in_pp->binds[0].zone_id = Zones::BUTCHER; // butcher in_pp->binds[0].zone_id = 68; // butcher
break; break;
} }
case StartZoneIndex::GreaterFaydark: case 9:
{ {
in_pp->zone_id = Zones::GFAYDARK; // gfaydark in_pp->zone_id = 54; // gfaydark
in_pp->binds[0].zone_id = Zones::GFAYDARK; // gfaydark in_pp->binds[0].zone_id = 54; // gfaydark
break; break;
} }
case StartZoneIndex::Felwithe: case 10:
{ {
in_pp->zone_id = Zones::FELWITHEA; // felwithea in_pp->zone_id = 61; // felwithea
in_pp->binds[0].zone_id = Zones::GFAYDARK; // gfaydark in_pp->binds[0].zone_id = 54; // gfaydark
break; break;
} }
case StartZoneIndex::Akanon: case 11:
{ {
in_pp->zone_id = Zones::AKANON; // akanon in_pp->zone_id = 55; // akanon
in_pp->binds[0].zone_id = Zones::STEAMFONT; // steamfont in_pp->binds[0].zone_id = 56; // steamfont
break; break;
} }
case StartZoneIndex::Cabilis: case 12:
{ {
in_pp->zone_id = Zones::CABWEST; // cabwest in_pp->zone_id = 82; // cabwest
in_pp->binds[0].zone_id = Zones::FIELDOFBONE; // fieldofbone in_pp->binds[0].zone_id = 78; // fieldofbone
break; break;
} }
case StartZoneIndex::SharVahl: case 13:
{ {
in_pp->zone_id = Zones::SHARVAHL; // sharvahl in_pp->zone_id = 155; // sharvahl
in_pp->binds[0].zone_id = Zones::SHARVAHL; // sharvahl in_pp->binds[0].zone_id = 155; // sharvahl
break; break;
} }
} }
} }
}
void WorldDatabase::GetLauncherList(std::vector<std::string> &rl) { void WorldDatabase::GetLauncherList(std::vector<std::string> &rl) {
rl.clear(); rl.clear();
+3 -21
View File
@@ -110,16 +110,7 @@ void ZSList::Process() {
} }
if (reminder && reminder->Check() && shutdowntimer) { if (reminder && reminder->Check() && shutdowntimer) {
SendEmoteMessage( SendEmoteMessage(0, 0, 0, 15, "<SYSTEMWIDE MESSAGE>:SYSTEM MSG:World coming down, everyone log out now. World will shut down in %i minutes...", ((shutdowntimer->GetRemainingTime() / 1000) / 60));
0,
0,
0,
Chat::Yellow,
fmt::format(
"[SYSTEM] World will be shutting down in {} minutes.",
((shutdowntimer->GetRemainingTime() / 1000) / 60)
).c_str()
);
} }
} }
@@ -686,16 +677,7 @@ void ZSList::UpdateUCSServerAvailable(bool ucss_available) {
void ZSList::WorldShutDown(uint32 time, uint32 interval) void ZSList::WorldShutDown(uint32 time, uint32 interval)
{ {
if (time > 0) { if (time > 0) {
SendEmoteMessage( SendEmoteMessage(0, 0, 0, 15, "<SYSTEMWIDE MESSAGE>:SYSTEM MSG:World coming down in %i minutes, everyone log out before this time.", (time / 60));
0,
0,
0,
Chat::Yellow,
fmt::format(
"[SYSTEM] World will be shutting down in {} minutes.",
(time / 60)
).c_str()
);
time *= 1000; time *= 1000;
interval *= 1000; interval *= 1000;
@@ -708,7 +690,7 @@ void ZSList::WorldShutDown(uint32 time, uint32 interval)
reminder->Start(); reminder->Start();
} }
else { else {
SendEmoteMessage(0, 0, 0, 15, "[SYSTEM] World is shutting down."); SendEmoteMessage(0, 0, 0, 15, "<SYSTEMWIDE MESSAGE>:SYSTEM MSG:World coming down, everyone log out now.");
auto pack = new ServerPacket; auto pack = new ServerPacket;
pack->opcode = ServerOP_ShutdownAll; pack->opcode = ServerOP_ShutdownAll;
pack->size = 0; pack->size = 0;
+80 -30
View File
@@ -40,7 +40,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "expedition_message.h" #include "expedition_message.h"
#include "shared_task_world_messaging.h" #include "shared_task_world_messaging.h"
#include "../common/shared_tasks.h" #include "../common/shared_tasks.h"
#include "shared_task_manager.h"
extern ClientList client_list; extern ClientList client_list;
extern GroupLFPList LFPGroupList; extern GroupLFPList LFPGroupList;
@@ -51,8 +50,6 @@ extern volatile bool UCSServerAvailable_;
extern AdventureManager adventure_manager; extern AdventureManager adventure_manager;
extern UCSConnection UCSLink; extern UCSConnection UCSLink;
extern QueryServConnection QSLink; extern QueryServConnection QSLink;
extern SharedTaskManager shared_task_manager;
void CatchSignal(int sig_num); void CatchSignal(int sig_num);
ZoneServer::ZoneServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection, EQ::Net::ConsoleServer *console) ZoneServer::ZoneServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection, EQ::Net::ConsoleServer *console)
@@ -453,7 +450,6 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
break; break;
scm->noreply = true; scm->noreply = true;
scm->queued = 3; // offline scm->queued = 3; // offline
scm->chan_num = ChatChannel_TellEcho;
strcpy(scm->deliverto, scm->from); strcpy(scm->deliverto, scm->from);
// ideally this would be trimming off the message too, oh well // ideally this would be trimming off the message too, oh well
sender->Server()->SendPacket(pack); sender->Server()->SendPacket(pack);
@@ -467,7 +463,6 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
break; break;
scm->noreply = true; scm->noreply = true;
scm->queued = 2; // queue full scm->queued = 2; // queue full
scm->chan_num = ChatChannel_TellEcho;
strcpy(scm->deliverto, scm->from); strcpy(scm->deliverto, scm->from);
sender->Server()->SendPacket(pack); sender->Server()->SendPacket(pack);
} }
@@ -483,7 +478,6 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
break; break;
scm->noreply = true; scm->noreply = true;
scm->queued = 1; // queued scm->queued = 1; // queued
scm->chan_num = ChatChannel_TellEcho;
strcpy(scm->deliverto, scm->from); strcpy(scm->deliverto, scm->from);
sender->Server()->SendPacket(pack); sender->Server()->SendPacket(pack);
} }
@@ -614,7 +608,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
if (sci->local_address[0]) { if (sci->local_address[0]) {
strn0cpy(client_local_address, sci->local_address, 250); strn0cpy(client_local_address, sci->local_address, 250);
LogInfo("Zone specified local address [{}]", sci->local_address); LogInfo("Zone specified local address [{}]", sci->address);
} }
if (sci->process_id) { if (sci->process_id) {
@@ -1246,42 +1240,98 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
QSLink.SendPacket(pack); QSLink.SendPacket(pack);
break; break;
} }
case ServerOP_CZDialogueWindow: case ServerOP_CZCastSpellPlayer:
case ServerOP_CZCastSpellGroup:
case ServerOP_CZCastSpellRaid:
case ServerOP_CZCastSpellGuild:
case ServerOP_CZMarqueePlayer:
case ServerOP_CZMarqueeGroup:
case ServerOP_CZMarqueeRaid:
case ServerOP_CZMarqueeGuild:
case ServerOP_CZMessagePlayer:
case ServerOP_CZMessageGroup:
case ServerOP_CZMessageRaid:
case ServerOP_CZMessageGuild:
case ServerOP_CZMovePlayer:
case ServerOP_CZMoveGroup:
case ServerOP_CZMoveRaid:
case ServerOP_CZMoveGuild:
case ServerOP_CZMoveInstancePlayer:
case ServerOP_CZMoveInstanceGroup:
case ServerOP_CZMoveInstanceRaid:
case ServerOP_CZMoveInstanceGuild:
case ServerOP_CZRemoveSpellPlayer:
case ServerOP_CZRemoveSpellGroup:
case ServerOP_CZRemoveSpellRaid:
case ServerOP_CZRemoveSpellGuild:
case ServerOP_CZSetEntityVariableByClientName:
case ServerOP_CZSetEntityVariableByNPCTypeID:
case ServerOP_CZSetEntityVariableByGroupID:
case ServerOP_CZSetEntityVariableByRaidID:
case ServerOP_CZSetEntityVariableByGuildID:
case ServerOP_CZSignalNPC:
case ServerOP_CZSignalClient:
case ServerOP_CZSignalClientByName:
case ServerOP_CZSignalGroup:
case ServerOP_CZSignalRaid:
case ServerOP_CZSignalGuild:
case ServerOP_CZTaskActivityResetPlayer:
case ServerOP_CZTaskActivityResetGroup:
case ServerOP_CZTaskActivityResetRaid:
case ServerOP_CZTaskActivityResetGuild:
case ServerOP_CZTaskActivityUpdatePlayer:
case ServerOP_CZTaskActivityUpdateGroup:
case ServerOP_CZTaskActivityUpdateRaid:
case ServerOP_CZTaskActivityUpdateGuild:
case ServerOP_CZTaskAssignPlayer:
case ServerOP_CZTaskAssignGroup:
case ServerOP_CZTaskAssignRaid:
case ServerOP_CZTaskAssignGuild:
case ServerOP_CZTaskDisablePlayer:
case ServerOP_CZTaskDisableGroup:
case ServerOP_CZTaskDisableRaid:
case ServerOP_CZTaskDisableGuild:
case ServerOP_CZTaskEnablePlayer:
case ServerOP_CZTaskEnableGroup:
case ServerOP_CZTaskEnableRaid:
case ServerOP_CZTaskEnableGuild:
case ServerOP_CZTaskFailPlayer:
case ServerOP_CZTaskFailGroup:
case ServerOP_CZTaskFailRaid:
case ServerOP_CZTaskFailGuild:
case ServerOP_CZTaskRemovePlayer:
case ServerOP_CZTaskRemoveGroup:
case ServerOP_CZTaskRemoveRaid:
case ServerOP_CZTaskRemoveGuild:
case ServerOP_CZLDoNUpdate: case ServerOP_CZLDoNUpdate:
case ServerOP_CZMarquee: case ServerOP_WWAssignTask:
case ServerOP_CZMessage: case ServerOP_WWCastSpell:
case ServerOP_CZMove: case ServerOP_WWDisableTask:
case ServerOP_CZSetEntityVariable: case ServerOP_WWEnableTask:
case ServerOP_CZSignal: case ServerOP_WWFailTask:
case ServerOP_CZSpell:
case ServerOP_CZTaskUpdate:
case ServerOP_WWDialogueWindow:
case ServerOP_WWLDoNUpdate:
case ServerOP_WWMarquee: case ServerOP_WWMarquee:
case ServerOP_WWMessage: case ServerOP_WWMessage:
case ServerOP_WWMove: case ServerOP_WWMove:
case ServerOP_WWSetEntityVariable: case ServerOP_WWMoveInstance:
case ServerOP_WWSignal: case ServerOP_WWRemoveSpell:
case ServerOP_WWSpell: case ServerOP_WWRemoveTask:
case ServerOP_WWTaskUpdate: case ServerOP_WWResetActivity:
case ServerOP_WWSetEntityVariableClient:
case ServerOP_WWSetEntityVariableNPC:
case ServerOP_WWSignalClient:
case ServerOP_WWSignalNPC:
case ServerOP_WWUpdateActivity:
case ServerOP_DepopAllPlayersCorpses: case ServerOP_DepopAllPlayersCorpses:
case ServerOP_DepopPlayerCorpse: case ServerOP_DepopPlayerCorpse:
case ServerOP_ReloadTitles: case ServerOP_ReloadTitles:
case ServerOP_SpawnStatusChange: case ServerOP_SpawnStatusChange:
case ServerOP_ReloadTasks:
case ServerOP_ReloadWorld: case ServerOP_ReloadWorld:
case ServerOP_UpdateSpawn: case ServerOP_UpdateSpawn:
{ {
zoneserver_list.SendPacket(pack); zoneserver_list.SendPacket(pack);
break; break;
} }
case ServerOP_ReloadTasks:
{
// world needs to update its copy of task data as well
shared_task_manager.LoadTaskData();
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_ChangeSharedMem: { case ServerOP_ChangeSharedMem: {
std::string hotfix_name = std::string((char*)pack->pBuffer); std::string hotfix_name = std::string((char*)pack->pBuffer);
@@ -1312,7 +1362,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
case ServerOP_CZClientMessageString: case ServerOP_CZClientMessageString:
{ {
auto buf = reinterpret_cast<CZClientMessageString_Struct*>(pack->pBuffer); auto buf = reinterpret_cast<CZClientMessageString_Struct*>(pack->pBuffer);
client_list.SendPacket(buf->client_name, pack); client_list.SendPacket(buf->character_name, pack);
break; break;
} }
case ServerOP_ExpeditionLockout: case ServerOP_ExpeditionLockout:
-5
View File
@@ -26,7 +26,6 @@ SET(zone_sources
dialogue_window.cpp dialogue_window.cpp
dynamic_zone.cpp dynamic_zone.cpp
effects.cpp effects.cpp
elixir.cpp
embparser.cpp embparser.cpp
embparser_api.cpp embparser_api.cpp
embperl.cpp embperl.cpp
@@ -81,7 +80,6 @@ SET(zone_sources
fearpath.cpp fearpath.cpp
forage.cpp forage.cpp
global_loot_manager.cpp global_loot_manager.cpp
gm_commands/door_manipulation.cpp
groups.cpp groups.cpp
guild.cpp guild.cpp
guild_mgr.cpp guild_mgr.cpp
@@ -122,7 +120,6 @@ SET(zone_sources
perl_player_corpse.cpp perl_player_corpse.cpp
perl_questitem.cpp perl_questitem.cpp
perl_raids.cpp perl_raids.cpp
perl_spell.cpp
perlpacket.cpp perlpacket.cpp
petitions.cpp petitions.cpp
pets.cpp pets.cpp
@@ -188,7 +185,6 @@ SET(zone_headers
doors.h doors.h
dialogue_window.h dialogue_window.h
dynamic_zone.h dynamic_zone.h
elixir.h
embparser.h embparser.h
embperl.h embperl.h
embxs.h embxs.h
@@ -202,7 +198,6 @@ SET(zone_headers
fastmath.h fastmath.h
forage.h forage.h
global_loot_manager.h global_loot_manager.h
gm_commands/door_manipulation.h
groups.h groups.h
guild_mgr.h guild_mgr.h
hate_list.h hate_list.h
+80 -13
View File
@@ -37,6 +37,12 @@ Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
extern QueryServ* QServ; extern QueryServ* QServ;
namespace detail
{
static const uint32 PhantomStatId = 999999;
}
void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, uint32 duration_override, bool followme, bool sticktarg, uint16 *eye_id) { void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, uint32 duration_override, bool followme, bool sticktarg, uint16 *eye_id) {
//It might not be a bad idea to put these into the database, eventually.. //It might not be a bad idea to put these into the database, eventually..
@@ -69,10 +75,10 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u
for (int x = 0; x < MAX_SWARM_PETS; x++) for (int x = 0; x < MAX_SWARM_PETS; x++)
{ {
if (spells[spell_id].effect_id[x] == SE_TemporaryPets) if (spells[spell_id].effectid[x] == SE_TemporaryPets)
{ {
pet.count = spells[spell_id].base_value[x]; pet.count = spells[spell_id].base[x];
pet.duration = spells[spell_id].max_value[x]; pet.duration = spells[spell_id].max[x];
} }
} }
@@ -493,7 +499,6 @@ void Client::ResetAA() {
m_pp.group_leadership_exp = 0; m_pp.group_leadership_exp = 0;
m_pp.raid_leadership_exp = 0; m_pp.raid_leadership_exp = 0;
database.DeleteCharacterAAs(CharacterID());
database.DeleteCharacterLeadershipAAs(CharacterID()); database.DeleteCharacterLeadershipAAs(CharacterID());
} }
@@ -765,7 +770,7 @@ void Client::InspectBuffs(Client* Inspector, int Rank)
continue; continue;
ib->spell_id[packet_index] = buffs[i].spellid; ib->spell_id[packet_index] = buffs[i].spellid;
if (Rank > 1) if (Rank > 1)
ib->tics_remaining[packet_index] = spells[buffs[i].spellid].buff_duration_formula == DF_Permanent ? 0xFFFFFFFF : buffs[i].ticsremaining; ib->tics_remaining[packet_index] = spells[buffs[i].spellid].buffdurationformula == DF_Permanent ? 0xFFFFFFFF : buffs[i].ticsremaining;
packet_index++; packet_index++;
} }
@@ -846,6 +851,8 @@ void Client::SendAlternateAdvancementTable() {
SendAlternateAdvancementRank(aa.first, 1); SendAlternateAdvancementRank(aa.first, 1);
} }
} }
SendPhantomStatsAlternateAdvancementRank();
} }
void Client::SendAlternateAdvancementRank(int aa_id, int level) { void Client::SendAlternateAdvancementRank(int aa_id, int level) {
@@ -905,8 +912,8 @@ void Client::SendAlternateAdvancementRank(int aa_id, int level) {
outapp->SetWritePosition(sizeof(AARankInfo_Struct)); outapp->SetWritePosition(sizeof(AARankInfo_Struct));
for(auto &effect : rank->effects) { for(auto &effect : rank->effects) {
outapp->WriteSInt32(effect.effect_id); outapp->WriteSInt32(effect.effect_id);
outapp->WriteSInt32(effect.base_value); outapp->WriteSInt32(effect.base1);
outapp->WriteSInt32(effect.limit_value); outapp->WriteSInt32(effect.base2);
outapp->WriteSInt32(effect.slot); outapp->WriteSInt32(effect.slot);
} }
@@ -919,6 +926,54 @@ void Client::SendAlternateAdvancementRank(int aa_id, int level) {
safe_delete(outapp); safe_delete(outapp);
} }
void Client::SendPhantomStatsAlternateAdvancementRank() {
//We only need to send phantom stats if stats are set to a custom value
if (RuleI(Character, StatCap) <= 0) {
return;
}
auto diff = RuleI(Character, StatCap) - GetMaxStat(false);
int size = sizeof(AARankInfo_Struct) + (sizeof(AARankEffect_Struct) * 7);
auto outapp = new EQApplicationPacket(OP_SendAATable, size);
AARankInfo_Struct *aai = (AARankInfo_Struct*)outapp->pBuffer;
aai->id = detail::PhantomStatId;
aai->upper_hotkey_sid = -1;
aai->lower_hotkey_sid = -1;
aai->title_sid = detail::PhantomStatId;
aai->desc_sid = detail::PhantomStatId;
aai->cost = 1;
aai->seq = detail::PhantomStatId;
aai->type = 3;
aai->spell = -1;
aai->spell_type = 0;
aai->spell_refresh = 0;
aai->classes = 16777215;
aai->level_req = 1;
aai->current_level = 2;
aai->max_level = 1;
aai->prev_id = -1;
aai->next_id = -1;
aai->total_cost = 1;
aai->expansion = 0;
aai->category = -1;
aai->charges = 0;
aai->grant_only = 1;
aai->total_effects = 7;
aai->total_prereqs = 0;
outapp->SetWritePosition(sizeof(AARankInfo_Struct));
for (int i = 0; i < 7; ++i) {
outapp->WriteSInt32(SE_RaiseStatCap);
outapp->WriteSInt32(diff);
outapp->WriteSInt32(i);
outapp->WriteSInt32(i + 1);
}
QueuePacket(outapp);
safe_delete(outapp);
}
void Client::SendAlternateAdvancementStats() { void Client::SendAlternateAdvancementStats() {
auto outapp = new EQApplicationPacket(OP_AAExpUpdate, sizeof(AltAdvStats_Struct)); auto outapp = new EQApplicationPacket(OP_AAExpUpdate, sizeof(AltAdvStats_Struct));
AltAdvStats_Struct *aps = (AltAdvStats_Struct *)outapp->pBuffer; AltAdvStats_Struct *aps = (AltAdvStats_Struct *)outapp->pBuffer;
@@ -934,7 +989,19 @@ void Client::SendAlternateAdvancementPoints() {
AATable_Struct* aa2 = (AATable_Struct *)outapp->pBuffer; AATable_Struct* aa2 = (AATable_Struct *)outapp->pBuffer;
int i = 0; int i = 0;
if (RuleI(Character, StatCap) > 0)
{
aa2->aa_list[i].AA = detail::PhantomStatId;
aa2->aa_list[i].value = 1;
aa2->aa_list[i].charges = 0;
i++;
}
for(auto &aa : zone->aa_abilities) { for(auto &aa : zone->aa_abilities) {
if (i >= MAX_PP_AA_ARRAY) {
continue;
}
uint32 charges = 0; uint32 charges = 0;
auto ranks = GetAA(aa.second->first_rank_id, &charges); auto ranks = GetAA(aa.second->first_rank_id, &charges);
if(ranks) { if(ranks) {
@@ -1230,7 +1297,7 @@ void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) {
} }
// //
// Modern clients don't require pet targeted for AA casts that are ST_Pet // Modern clients don't require pet targeted for AA casts that are ST_Pet
if (spells[rank->spell].target_type == ST_Pet || spells[rank->spell].target_type == ST_SummonedPet) if (spells[rank->spell].targettype == ST_Pet || spells[rank->spell].targettype == ST_SummonedPet)
target_id = GetPetID(); target_id = GetPetID();
// extra handling for cast_not_standing spells // extra handling for cast_not_standing spells
@@ -1250,7 +1317,7 @@ void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) {
else { else {
// Bards can cast instant cast AAs while they are casting another song // Bards can cast instant cast AAs while they are casting another song
if (spells[rank->spell].cast_time == 0 && GetClass() == BARD && IsBardSong(casting_spell_id)) { if (spells[rank->spell].cast_time == 0 && GetClass() == BARD && IsBardSong(casting_spell_id)) {
if (!SpellFinished(rank->spell, entity_list.GetMob(target_id), EQ::spells::CastingSlot::AltAbility, spells[rank->spell].mana, -1, spells[rank->spell].resist_difficulty, false)) { if (!SpellFinished(rank->spell, entity_list.GetMob(target_id), EQ::spells::CastingSlot::AltAbility, spells[rank->spell].mana, -1, spells[rank->spell].ResistDiff, false)) {
return; return;
} }
ExpendAlternateAdvancementCharge(ability->id); ExpendAlternateAdvancementCharge(ability->id);
@@ -1286,8 +1353,8 @@ int Mob::GetAlternateAdvancementCooldownReduction(AA::Rank *rank_in) {
} }
for(auto &effect : rank->effects) { for(auto &effect : rank->effects) {
if(effect.effect_id == SE_HastenedAASkill && effect.limit_value == ability_in->id) { if(effect.effect_id == SE_HastenedAASkill && effect.base2 == ability_in->id) {
return effect.base_value; return effect.base1;
} }
} }
} }
@@ -1745,8 +1812,8 @@ bool ZoneDatabase::LoadAlternateAdvancementAbilities(std::unordered_map<int, std
int rank_id = atoi(row[0]); int rank_id = atoi(row[0]);
effect.slot = atoi(row[1]); effect.slot = atoi(row[1]);
effect.effect_id = atoi(row[2]); effect.effect_id = atoi(row[2]);
effect.base_value = atoi(row[3]); effect.base1 = atoi(row[3]);
effect.limit_value = atoi(row[4]); effect.base2 = atoi(row[4]);
if(effect.slot < 1) if(effect.slot < 1)
continue; continue;
+2 -2
View File
@@ -29,8 +29,8 @@ struct RankEffect
{ {
int slot; int slot;
int effect_id; int effect_id;
int base_value; int base1;
int limit_value; int base2;
}; };
} }
+26 -38
View File
@@ -851,17 +851,6 @@ bool Mob::CombatRange(Mob* other, float fixed_size_mod, bool aeRampage)
size_mod *= RuleR(Combat,HitBoxMod); // used for testing sizemods on different races. size_mod *= RuleR(Combat,HitBoxMod); // used for testing sizemods on different races.
size_mod *= fixed_size_mod; // used to extend the size_mod size_mod *= fixed_size_mod; // used to extend the size_mod
// Melee chasing fleeing mobs is borked. The client updates don't
// come to the server quickly enough, especially when mob is running
// and/or PC has good run speed. This change is a hack, but it greatly
// improved playability and "you are too far away" while chasing
// a fleeing mob. The Blind check is to make sure that this does not
// apply to disoriented fleeing mobs who need proximity to turn and fight.
if (other->currently_fleeing && !other->IsBlind())
{
size_mod *= 3;
}
// prevention of ridiculously sized hit boxes // prevention of ridiculously sized hit boxes
if (size_mod > 10000) if (size_mod > 10000)
size_mod = size_mod / 7; size_mod = size_mod / 7;
@@ -874,7 +863,7 @@ bool Mob::CombatRange(Mob* other, float fixed_size_mod, bool aeRampage)
bool DoLoSCheck = true; bool DoLoSCheck = true;
float max_dist = static_cast<float>(GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 0)); float max_dist = static_cast<float>(GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 0));
float min_distance = static_cast<float>(GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 1)); float min_dist = static_cast<float>(GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 1));
if (GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 2)) if (GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 2))
DoLoSCheck = false; //Ignore line of sight check DoLoSCheck = false; //Ignore line of sight check
@@ -884,12 +873,12 @@ bool Mob::CombatRange(Mob* other, float fixed_size_mod, bool aeRampage)
max_dist = max_dist * max_dist; max_dist = max_dist * max_dist;
if (!min_distance) if (!min_dist)
min_distance = size_mod; //Default to melee range min_dist = size_mod; //Default to melee range
else else
min_distance = min_distance * min_distance; min_dist = min_dist * min_dist;
if ((DoLoSCheck && CheckLastLosState()) && (_DistNoRoot >= min_distance && _DistNoRoot <= max_dist)) if ((DoLoSCheck && CheckLastLosState()) && (_DistNoRoot >= min_dist && _DistNoRoot <= max_dist))
SetPseudoRoot(true); SetPseudoRoot(true);
else else
SetPseudoRoot(false); SetPseudoRoot(false);
@@ -912,7 +901,6 @@ bool Mob::CombatRange(Mob* other, float fixed_size_mod, bool aeRampage)
} }
return true; return true;
} }
return false; return false;
} }
@@ -1003,16 +991,16 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, Mob *target, bool isproc)
default_aggro = target_hp / 15; default_aggro = target_hp / 15;
for (int o = 0; o < EFFECT_COUNT; o++) { for (int o = 0; o < EFFECT_COUNT; o++) {
switch (spells[spell_id].effect_id[o]) { switch (spells[spell_id].effectid[o]) {
case SE_CurrentHPOnce: case SE_CurrentHPOnce:
case SE_CurrentHP: { case SE_CurrentHP: {
int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base_value[o], spells[spell_id].max_value[o], slevel, spell_id); int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
if(val < 0) if(val < 0)
AggroAmount -= val; AggroAmount -= val;
break; break;
} }
case SE_MovementSpeed: { case SE_MovementSpeed: {
int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base_value[o], spells[spell_id].max_value[o], slevel, spell_id); int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
if (val < 0) if (val < 0)
AggroAmount += default_aggro; AggroAmount += default_aggro;
break; break;
@@ -1020,7 +1008,7 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, Mob *target, bool isproc)
case SE_AttackSpeed: case SE_AttackSpeed:
case SE_AttackSpeed2: case SE_AttackSpeed2:
case SE_AttackSpeed3: { case SE_AttackSpeed3: {
int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base_value[o], spells[spell_id].max_value[o], slevel, spell_id); int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
if (val < 100) if (val < 100)
AggroAmount += default_aggro; AggroAmount += default_aggro;
break; break;
@@ -1038,7 +1026,7 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, Mob *target, bool isproc)
break; break;
case SE_ACv2: case SE_ACv2:
case SE_ArmorClass: { case SE_ArmorClass: {
int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base_value[o], spells[spell_id].max_value[o], slevel, spell_id); int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
if (val < 0) if (val < 0)
AggroAmount += default_aggro; AggroAmount += default_aggro;
break; break;
@@ -1056,19 +1044,19 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, Mob *target, bool isproc)
case SE_INT: case SE_INT:
case SE_WIS: case SE_WIS:
case SE_CHA: { case SE_CHA: {
int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base_value[o], spells[spell_id].max_value[o], slevel, spell_id); int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
if (val < 0) if (val < 0)
AggroAmount += 10; AggroAmount += 10;
break; break;
} }
case SE_ResistAll: { case SE_ResistAll: {
int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base_value[o], spells[spell_id].max_value[o], slevel, spell_id); int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
if (val < 0) if (val < 0)
AggroAmount += 50; AggroAmount += 50;
break; break;
} }
case SE_AllStats: { case SE_AllStats: {
int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base_value[o], spells[spell_id].max_value[o], slevel, spell_id); int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
if (val < 0) if (val < 0)
AggroAmount += 70; AggroAmount += 70;
break; break;
@@ -1110,7 +1098,7 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, Mob *target, bool isproc)
case SE_ManaRegen_v2: case SE_ManaRegen_v2:
case SE_ManaPool: case SE_ManaPool:
case SE_CurrentEndurance: { case SE_CurrentEndurance: {
int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base_value[o], spells[spell_id].max_value[o], slevel, spell_id); int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
if (val < 0) if (val < 0)
AggroAmount -= val * 2; AggroAmount -= val * 2;
break; break;
@@ -1122,7 +1110,7 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, Mob *target, bool isproc)
break; break;
case SE_ReduceHate: case SE_ReduceHate:
case SE_InstantHate: case SE_InstantHate:
nonModifiedAggro = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base_value[o], spells[spell_id].max_value[o], slevel, spell_id); nonModifiedAggro = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
break; break;
} }
} }
@@ -1133,8 +1121,8 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, Mob *target, bool isproc)
if (dispel && target && target->GetHateAmount(this) < 100) if (dispel && target && target->GetHateAmount(this) < 100)
AggroAmount += 50; AggroAmount += 50;
if (spells[spell_id].hate_added > 0) // overrides the hate (ex. tash) if (spells[spell_id].HateAdded > 0) // overrides the hate (ex. tash)
AggroAmount = spells[spell_id].hate_added; AggroAmount = spells[spell_id].HateAdded;
if (GetOwner() && IsPet()) if (GetOwner() && IsPet())
AggroAmount = AggroAmount * RuleI(Aggro, PetSpellAggroMod) / 100; AggroAmount = AggroAmount * RuleI(Aggro, PetSpellAggroMod) / 100;
@@ -1149,10 +1137,10 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, Mob *target, bool isproc)
// initial aggro gets a bonus 100 besides for dispel or hate override // initial aggro gets a bonus 100 besides for dispel or hate override
// We add this 100 in AddToHateList so we need to account for the oddities here // We add this 100 in AddToHateList so we need to account for the oddities here
if (dispel && spells[spell_id].hate_added > 0 && !on_hatelist) if (dispel && spells[spell_id].HateAdded > 0 && !on_hatelist)
AggroAmount -= 100; AggroAmount -= 100;
return AggroAmount + spells[spell_id].bonus_hate + nonModifiedAggro; return AggroAmount + spells[spell_id].bonushate + nonModifiedAggro;
} }
//healing and buffing aggro //healing and buffing aggro
@@ -1163,7 +1151,7 @@ int32 Mob::CheckHealAggroAmount(uint16 spell_id, Mob *target, uint32 heal_possib
bool ignore_default_buff = false; // rune/hot don't use the default 9, HP buffs that heal (virtue) do use the default bool ignore_default_buff = false; // rune/hot don't use the default 9, HP buffs that heal (virtue) do use the default
for (int o = 0; o < EFFECT_COUNT; o++) { for (int o = 0; o < EFFECT_COUNT; o++) {
switch (spells[spell_id].effect_id[o]) { switch (spells[spell_id].effectid[o]) {
case SE_CurrentHP: case SE_CurrentHP:
case SE_PercentalHeal: case SE_PercentalHeal:
{ {
@@ -1173,7 +1161,7 @@ int32 Mob::CheckHealAggroAmount(uint16 spell_id, Mob *target, uint32 heal_possib
} }
// hate based on base healing power of the spell // hate based on base healing power of the spell
int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o],
spells[spell_id].base_value[o], spells[spell_id].max_value[o], GetLevel(), spell_id); spells[spell_id].base[o], spells[spell_id].max[o], GetLevel(), spell_id);
if (val > 0) { if (val > 0) {
if (heal_possible < val) if (heal_possible < val)
val = heal_possible; // capped to amount healed val = heal_possible; // capped to amount healed
@@ -1189,7 +1177,7 @@ int32 Mob::CheckHealAggroAmount(uint16 spell_id, Mob *target, uint32 heal_possib
} }
case SE_Rune: case SE_Rune:
AggroAmount += CalcSpellEffectValue_formula(spells[spell_id].formula[o], AggroAmount += CalcSpellEffectValue_formula(spells[spell_id].formula[o],
spells[spell_id].base_value[o], spells[spell_id].max_value[o], GetLevel(), spell_id) * 2; spells[spell_id].base[o], spells[spell_id].max[o], GetLevel(), spell_id) * 2;
ignore_default_buff = true; ignore_default_buff = true;
break; break;
case SE_HealOverTime: case SE_HealOverTime:
@@ -1269,7 +1257,7 @@ bool Mob::PassCharismaCheck(Mob* caster, uint16 spell_id) {
if(!caster) return false; if(!caster) return false;
if(spells[spell_id].resist_difficulty <= -600) if(spells[spell_id].ResistDiff <= -600)
return true; return true;
float resist_check = 0; float resist_check = 0;
@@ -1284,9 +1272,9 @@ bool Mob::PassCharismaCheck(Mob* caster, uint16 spell_id) {
return true; return true;
if (RuleB(Spells, CharismaCharmDuration)) if (RuleB(Spells, CharismaCharmDuration))
resist_check = ResistSpell(spells[spell_id].resist_type, spell_id, caster,false,0,true,true); resist_check = ResistSpell(spells[spell_id].resisttype, spell_id, caster,false,0,true,true);
else else
resist_check = ResistSpell(spells[spell_id].resist_type, spell_id, caster, false,0, false, true); resist_check = ResistSpell(spells[spell_id].resisttype, spell_id, caster, false,0, false, true);
//2: The mob makes a resistance check against the charm //2: The mob makes a resistance check against the charm
if (resist_check == 100) if (resist_check == 100)
@@ -1310,7 +1298,7 @@ bool Mob::PassCharismaCheck(Mob* caster, uint16 spell_id) {
{ {
// Assume this is a harmony/pacify spell // Assume this is a harmony/pacify spell
// If 'Lull' spell resists, do a second resist check with a charisma modifier AND regular resist checks. If resists agian you gain aggro. // If 'Lull' spell resists, do a second resist check with a charisma modifier AND regular resist checks. If resists agian you gain aggro.
resist_check = ResistSpell(spells[spell_id].resist_type, spell_id, caster, false,0,true); resist_check = ResistSpell(spells[spell_id].resisttype, spell_id, caster, false,0,true);
if (resist_check == 100) if (resist_check == 100)
return true; return true;
} }
+1
View File
@@ -478,6 +478,7 @@ Json::Value ApiGetMobListDetail(EQ::Net::WebsocketServerConnection *connection,
row["has_temp_pets_active"] = mob->HasTempPetsActive(); row["has_temp_pets_active"] = mob->HasTempPetsActive();
row["has_two_hand_blunt_equiped"] = mob->HasTwoHandBluntEquiped(); row["has_two_hand_blunt_equiped"] = mob->HasTwoHandBluntEquiped();
row["has_two_hander_equipped"] = mob->HasTwoHanderEquipped(); row["has_two_hander_equipped"] = mob->HasTwoHanderEquipped();
row["has_virus"] = mob->HasVirus();
row["hate_summon"] = mob->HateSummon(); row["hate_summon"] = mob->HateSummon();
row["helm_texture"] = mob->GetHelmTexture(); row["helm_texture"] = mob->GetHelmTexture();
row["hp"] = mob->GetHP(); row["hp"] = mob->GetHP();
+94 -288
View File
@@ -59,7 +59,6 @@ extern FastMath g_Math;
extern EntityList entity_list; extern EntityList entity_list;
extern Zone* zone; extern Zone* zone;
//SYNC WITH: tune.cpp, mob.h TuneAttackAnimation
EQ::skills::SkillType Mob::AttackAnimation(int Hand, const EQ::ItemInstance* weapon, EQ::skills::SkillType skillinuse) EQ::skills::SkillType Mob::AttackAnimation(int Hand, const EQ::ItemInstance* weapon, EQ::skills::SkillType skillinuse)
{ {
// Determine animation // Determine animation
@@ -141,30 +140,14 @@ EQ::skills::SkillType Mob::AttackAnimation(int Hand, const EQ::ItemInstance* wea
} }
// If we're attacking with the secondary hand, play the dual wield anim // If we're attacking with the secondary hand, play the dual wield anim
if (Hand == EQ::invslot::slotSecondary) {// DW anim if (Hand == EQ::invslot::slotSecondary) // DW anim
type = animDualWield; type = animDualWield;
//allow animation chance to fire to be similar to your dw chance
if (GetDualWieldingSameDelayWeapons() == 2) {
SetDualWieldingSameDelayWeapons(3);
}
}
//If both weapons have same delay this allows a chance for DW animation
if (GetDualWieldingSameDelayWeapons() && Hand == EQ::invslot::slotPrimary) {
if (GetDualWieldingSameDelayWeapons() == 3 && zone->random.Roll(50)) {
type = animDualWield;
SetDualWieldingSameDelayWeapons(2);//Don't roll again till you do another dw attack.
}
SetDualWieldingSameDelayWeapons(2);//Ensures first attack is always primary.
}
DoAnim(type, 0, false); DoAnim(type, 0, false);
return skillinuse; return skillinuse;
} }
//SYNC WITH: tune.cpp, mob.h Tunecompute_tohit
int Mob::compute_tohit(EQ::skills::SkillType skillinuse) int Mob::compute_tohit(EQ::skills::SkillType skillinuse)
{ {
int tohit = GetSkill(EQ::skills::SkillOffense) + 7; int tohit = GetSkill(EQ::skills::SkillOffense) + 7;
@@ -185,7 +168,6 @@ int Mob::compute_tohit(EQ::skills::SkillType skillinuse)
} }
// return -1 in cases that always hit // return -1 in cases that always hit
//SYNC WITH: tune.cpp, mob.h TuneGetTotalToHit
int Mob::GetTotalToHit(EQ::skills::SkillType skill, int chance_mod) int Mob::GetTotalToHit(EQ::skills::SkillType skill, int chance_mod)
{ {
if (chance_mod >= 10000) // override for stuff like SE_SkillAttack if (chance_mod >= 10000) // override for stuff like SE_SkillAttack
@@ -249,7 +231,6 @@ int Mob::GetTotalToHit(EQ::skills::SkillType skill, int chance_mod)
// based on dev quotes // based on dev quotes
// the AGI bonus has actually drastically changed from classic // the AGI bonus has actually drastically changed from classic
//SYNC WITH: tune.cpp, mob.h Tunecompute_defense
int Mob::compute_defense() int Mob::compute_defense()
{ {
int defense = GetSkill(EQ::skills::SkillDefense) * 400 / 225; int defense = GetSkill(EQ::skills::SkillDefense) * 400 / 225;
@@ -278,7 +259,6 @@ int Mob::compute_defense()
} }
// return -1 in cases that always miss // return -1 in cases that always miss
// SYNC WITH : tune.cpp, mob.h TuneGetTotalDefense()
int Mob::GetTotalDefense() int Mob::GetTotalDefense()
{ {
auto avoidance = compute_defense() + 10; // add 10 in case the NPC's stats are fucked auto avoidance = compute_defense() + 10; // add 10 in case the NPC's stats are fucked
@@ -306,7 +286,6 @@ int Mob::GetTotalDefense()
// called when a mob is attacked, does the checks to see if it's a hit // called when a mob is attacked, does the checks to see if it's a hit
// and does other mitigation checks. 'this' is the mob being attacked. // and does other mitigation checks. 'this' is the mob being attacked.
// SYNC WITH : tune.cpp, mob.h TuneCheckHitChance()
bool Mob::CheckHitChance(Mob* other, DamageHitInfo &hit) bool Mob::CheckHitChance(Mob* other, DamageHitInfo &hit)
{ {
#ifdef LUA_EQEMU #ifdef LUA_EQEMU
@@ -417,20 +396,6 @@ bool Mob::AvoidDamage(Mob *other, DamageHitInfo &hit)
counter_dodge = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 4); counter_dodge = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 4);
} }
int modify_all = 0;
int modify_riposte = 0;
int modify_block = 0;
int modify_parry = 0;
int modify_dodge = 0;
if (GetSpecialAbility(MODIFY_AVOID_DAMAGE)) {
modify_all = GetSpecialAbilityParam(MODIFY_AVOID_DAMAGE, 0);
modify_riposte = GetSpecialAbilityParam(MODIFY_AVOID_DAMAGE, 1);
modify_block = GetSpecialAbilityParam(MODIFY_AVOID_DAMAGE, 2);
modify_parry = GetSpecialAbilityParam(MODIFY_AVOID_DAMAGE, 3);
modify_dodge = GetSpecialAbilityParam(MODIFY_AVOID_DAMAGE, 4);
}
// riposte -- it may seem crazy, but if the attacker has SPA 173 on them, they are immune to Ripo // riposte -- it may seem crazy, but if the attacker has SPA 173 on them, they are immune to Ripo
bool ImmuneRipo = attacker->aabonuses.RiposteChance || attacker->spellbonuses.RiposteChance || attacker->itembonuses.RiposteChance || attacker->IsEnraged(); bool ImmuneRipo = attacker->aabonuses.RiposteChance || attacker->spellbonuses.RiposteChance || attacker->itembonuses.RiposteChance || attacker->IsEnraged();
// Need to check if we have something in MainHand to actually attack with (or fists) // Need to check if we have something in MainHand to actually attack with (or fists)
@@ -455,10 +420,6 @@ bool Mob::AvoidDamage(Mob *other, DamageHitInfo &hit)
float counter = (counter_riposte + counter_all) / 100.0f; float counter = (counter_riposte + counter_all) / 100.0f;
chance -= chance * counter; chance -= chance * counter;
} }
if (modify_riposte || modify_all) {
float npc_modifier = (modify_riposte + modify_all) / 100.0f;
chance += chance * npc_modifier;
}
// AA Slippery Attacks // AA Slippery Attacks
if (hit.hand == EQ::invslot::slotSecondary) { if (hit.hand == EQ::invslot::slotSecondary) {
int slip = aabonuses.OffhandRiposteFail + itembonuses.OffhandRiposteFail + spellbonuses.OffhandRiposteFail; int slip = aabonuses.OffhandRiposteFail + itembonuses.OffhandRiposteFail + spellbonuses.OffhandRiposteFail;
@@ -498,10 +459,6 @@ bool Mob::AvoidDamage(Mob *other, DamageHitInfo &hit)
float counter = (counter_block + counter_all) / 100.0f; float counter = (counter_block + counter_all) / 100.0f;
chance -= chance * counter; chance -= chance * counter;
} }
if (modify_block || modify_all) {
float npc_modifier = (modify_block + modify_all) / 100.0f;
chance += chance * npc_modifier;
}
if (zone->random.Roll(chance)) { if (zone->random.Roll(chance)) {
hit.damage_done = DMG_BLOCKED; hit.damage_done = DMG_BLOCKED;
return true; return true;
@@ -525,10 +482,6 @@ bool Mob::AvoidDamage(Mob *other, DamageHitInfo &hit)
float counter = (counter_parry + counter_all) / 100.0f; float counter = (counter_parry + counter_all) / 100.0f;
chance -= chance * counter; chance -= chance * counter;
} }
if (modify_parry || modify_all) {
float npc_modifier = (modify_parry + modify_all) / 100.0f;
chance += chance * npc_modifier;
}
if (zone->random.Roll(chance)) { if (zone->random.Roll(chance)) {
hit.damage_done = DMG_PARRIED; hit.damage_done = DMG_PARRIED;
return true; return true;
@@ -552,10 +505,6 @@ bool Mob::AvoidDamage(Mob *other, DamageHitInfo &hit)
float counter = (counter_dodge + counter_all) / 100.0f; float counter = (counter_dodge + counter_all) / 100.0f;
chance -= chance * counter; chance -= chance * counter;
} }
if (modify_dodge || modify_all) {
float npc_modifier = (modify_dodge + modify_all) / 100.0f;
chance += chance * npc_modifier;
}
if (zone->random.Roll(chance)) { if (zone->random.Roll(chance)) {
hit.damage_done = DMG_DODGED; hit.damage_done = DMG_DODGED;
return true; return true;
@@ -839,7 +788,7 @@ int Mob::GetClassRaceACBonus()
return ac_bonus; return ac_bonus;
} }
//SYNC WITH: tune.cpp, mob.h TuneACSum
int Mob::ACSum(bool skip_caps) int Mob::ACSum(bool skip_caps)
{ {
int ac = 0; // this should be base AC whenever shrouds come around int ac = 0; // this should be base AC whenever shrouds come around
@@ -937,7 +886,7 @@ int Mob::GetBestMeleeSkill()
return bestSkill; return bestSkill;
} }
//SYNC WITH: tune.cpp, mob.h Tuneoffense
int Mob::offense(EQ::skills::SkillType skill) int Mob::offense(EQ::skills::SkillType skill)
{ {
int offense = GetSkill(skill); int offense = GetSkill(skill);
@@ -992,7 +941,7 @@ double Mob::RollD20(int offense, int mitigation)
return mods[index]; return mods[index];
} }
//SYNC WITH: tune.cpp, mob.h TuneMeleeMitigation
void Mob::MeleeMitigation(Mob *attacker, DamageHitInfo &hit, ExtraAttackOptions *opts) void Mob::MeleeMitigation(Mob *attacker, DamageHitInfo &hit, ExtraAttackOptions *opts)
{ {
#ifdef LUA_EQEMU #ifdef LUA_EQEMU
@@ -1041,34 +990,31 @@ int Mob::GetWeaponDamage(Mob *against, const EQ::ItemData *weapon_item) {
//check to see if our weapons or fists are magical. //check to see if our weapons or fists are magical.
if (against->GetSpecialAbility(IMMUNE_MELEE_NONMAGICAL)) { if (against->GetSpecialAbility(IMMUNE_MELEE_NONMAGICAL)) {
if (GetSpecialAbility(SPECATK_MAGICAL)) { if (weapon_item) {
dmg = 1;
}
//On live this occurs for ALL NPC's >= 10
else if (IsNPC() && GetLevel() >= RuleI(Combat, NPCAttackMagicLevel)) {
dmg = 1;
}
else if (weapon_item) {
if (weapon_item->Magic) { if (weapon_item->Magic) {
if (weapon_item->Damage && (weapon_item->IsType1HWeapon() || weapon_item->IsType2HWeapon())) {
dmg = weapon_item->Damage; dmg = weapon_item->Damage;
//this is more for non weapon items, ex: boots for kick
//they don't have a dmg but we should be able to hit magical
dmg = dmg <= 0 ? 1 : dmg;
} }
//Non weapon items, ie. boots for kick. else
else if (weapon_item->ItemType == EQ::item::ItemTypeArmor) {
dmg = 1;
}
else {
return 0; return 0;
} }
}
else { else {
return 0; if ((GetClass() == MONK || GetClass() == BEASTLORD) && GetLevel() >= 30) {
}
}
else if ((GetClass() == MONK || GetClass() == BEASTLORD) && GetLevel() >= 30) {
dmg = GetHandToHandDamage(); dmg = GetHandToHandDamage();
} }
else { else if (GetOwner() && GetLevel() >= RuleI(Combat, PetAttackMagicLevel)) {
//pets wouldn't actually use this but...
//it gives us an idea if we can hit due to the dual nature of this function
dmg = 1;
}
else if (GetSpecialAbility(SPECATK_MAGICAL))
{
dmg = 1;
}
else
return 0; return 0;
} }
} }
@@ -1368,7 +1314,6 @@ int Client::DoDamageCaps(int base_damage)
} }
// other is the defender, this is the attacker // other is the defender, this is the attacker
//SYNC WITH: tune.cpp, mob.h TuneDoAttack
void Mob::DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts) void Mob::DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts)
{ {
if (!other) if (!other)
@@ -1426,7 +1371,6 @@ void Mob::DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts)
//note: throughout this method, setting `damage` to a negative is a way to //note: throughout this method, setting `damage` to a negative is a way to
//stop the attack calculations //stop the attack calculations
// IsFromSpell added to allow spell effects to use Attack. (Mainly for the Rampage AA right now.) // IsFromSpell added to allow spell effects to use Attack. (Mainly for the Rampage AA right now.)
//SYNC WITH: tune.cpp, mob.h TuneClientAttack
bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts) bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts)
{ {
if (!other) { if (!other) {
@@ -1608,7 +1552,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
float chance = aabonuses.SkillAttackProc[SBIndex::SKILLPROC_CHANCE] / 1000.0f; float chance = aabonuses.SkillAttackProc[SBIndex::SKILLPROC_CHANCE] / 1000.0f;
if (zone->random.Roll(chance)) if (zone->random.Roll(chance))
SpellFinished(aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID], other, EQ::spells::CastingSlot::Item, 0, -1, SpellFinished(aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID], other, EQ::spells::CastingSlot::Item, 0, -1,
spells[aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID]].resist_difficulty); spells[aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID]].ResistDiff);
} }
other->Damage(this, my_hit.damage_done, SPELL_UNKNOWN, my_hit.skill, true, -1, false, m_specialattacks); other->Damage(this, my_hit.damage_done, SPELL_UNKNOWN, my_hit.skill, true, -1, false, m_specialattacks);
@@ -1684,14 +1628,9 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQ::skills::Skill
if (!spell) if (!spell)
spell = SPELL_UNKNOWN; spell = SPELL_UNKNOWN;
std::string export_string = fmt::format( char buffer[48] = { 0 };
"{} {} {} {}", snprintf(buffer, 47, "%d %d %d %d", killerMob ? killerMob->GetID() : 0, damage, spell, static_cast<int>(attack_skill));
killerMob ? killerMob->GetID() : 0, if (parse->EventPlayer(EVENT_DEATH, this, buffer, 0) != 0) {
damage,
spell,
static_cast<int>(attack_skill)
);
if (parse->EventPlayer(EVENT_DEATH, this, export_string, 0) != 0) {
if (GetHP() < 0) { if (GetHP() < 0) {
SetHP(0); SetHP(0);
} }
@@ -1746,17 +1685,11 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQ::skills::Skill
// #2: figure out things that affect the player dying and mark them dead // #2: figure out things that affect the player dying and mark them dead
InterruptSpell(); InterruptSpell();
Mob* m_pet = GetPet();
SetPet(0); SetPet(0);
SetHorseId(0); SetHorseId(0);
ShieldAbilityClearVariables(); ShieldAbilityClearVariables();
dead = true; dead = true;
if (m_pet && m_pet->IsCharmed()) {
m_pet->BuffFadeByEffect(SE_Charm);
}
if (GetMerc()) { if (GetMerc()) {
GetMerc()->Suspend(); GetMerc()->Suspend();
} }
@@ -1993,10 +1926,10 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQ::skills::Skill
QServ->PlayerLogEvent(Player_Log_Deaths, this->CharacterID(), event_desc); QServ->PlayerLogEvent(Player_Log_Deaths, this->CharacterID(), event_desc);
} }
parse->EventPlayer(EVENT_DEATH_COMPLETE, this, export_string, 0); parse->EventPlayer(EVENT_DEATH_COMPLETE, this, buffer, 0);
return true; return true;
} }
//SYNC WITH: tune.cpp, mob.h TuneNPCAttack
bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts) bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts)
{ {
if (!other) { if (!other) {
@@ -2248,7 +2181,7 @@ void NPC::Damage(Mob* other, int32 damage, uint16 spell_id, EQ::skills::SkillTyp
if (IsLDoNTrapped()) if (IsLDoNTrapped())
{ {
MessageString(Chat::Red, LDON_ACCIDENT_SETOFF2); MessageString(Chat::Red, LDON_ACCIDENT_SETOFF2);
SpellFinished(GetLDoNTrapSpellID(), other, EQ::spells::CastingSlot::Item, 0, -1, spells[GetLDoNTrapSpellID()].resist_difficulty, false); SpellFinished(GetLDoNTrapSpellID(), other, EQ::spells::CastingSlot::Item, 0, -1, spells[GetLDoNTrapSpellID()].ResistDiff, false);
SetLDoNTrapSpellID(0); SetLDoNTrapSpellID(0);
SetLDoNTrapped(false); SetLDoNTrapped(false);
SetLDoNTrapDetected(false); SetLDoNTrapDetected(false);
@@ -2273,8 +2206,11 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, EQ::skills::SkillTy
Mob *oos = nullptr; Mob *oos = nullptr;
if (killer_mob) { if (killer_mob) {
oos = killer_mob->GetOwnerOrSelf(); oos = killer_mob->GetOwnerOrSelf();
std::string buffer = fmt::format("{} {} {} {}", killer_mob->GetID(), damage, spell, static_cast<int>(attack_skill));
if (parse->EventNPC(EVENT_DEATH, this, oos, buffer.c_str(), 0) != 0) { char buffer[48] = { 0 };
snprintf(buffer, 47, "%d %d %d %d", killer_mob->GetID(), damage, spell, static_cast<int>(attack_skill));
if (parse->EventNPC(EVENT_DEATH, this, oos, buffer, 0) != 0) {
if (GetHP() < 0) { if (GetHP() < 0) {
SetHP(0); SetHP(0);
} }
@@ -2297,8 +2233,10 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, EQ::skills::SkillTy
} }
} }
else { else {
std::string buffer = fmt::format("{} {} {} {}", 0, damage, spell, static_cast<int>(attack_skill)); char buffer[48] = { 0 };
if (parse->EventNPC(EVENT_DEATH, this, nullptr, buffer.c_str(), 0) != 0) { snprintf(buffer, 47, "%d %d %d %d", 0, damage, spell, static_cast<int>(attack_skill));
if (parse->EventNPC(EVENT_DEATH, this, nullptr, buffer, 0) != 0) {
if (GetHP() < 0) { if (GetHP() < 0) {
SetHP(0); SetHP(0);
} }
@@ -2419,7 +2357,9 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, EQ::skills::SkillTy
give_exp_client->GetCleanName(), give_exp_client->GetCleanName(),
GetNPCTypeID() GetNPCTypeID()
); );
task_manager->HandleUpdateTasksOnKill(give_exp_client, GetNPCTypeID()); give_exp_client
->GetTaskState()
->HandleUpdateTasksOnKill(give_exp_client, GetNPCTypeID());
} }
if (kr) { if (kr) {
@@ -2689,15 +2629,16 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, EQ::skills::SkillTy
entity_list.UpdateFindableNPCState(this, true); entity_list.UpdateFindableNPCState(this, true);
std::string buffer = fmt::format("{} {} {} {}", killer_mob ? killer_mob->GetID() : 0, damage, spell, static_cast<int>(attack_skill)); char buffer[48] = { 0 };
parse->EventNPC(EVENT_DEATH_COMPLETE, this, oos, buffer.c_str(), 0); snprintf(buffer, 47, "%d %d %d %d", killer_mob ? killer_mob->GetID() : 0, damage, spell, static_cast<int>(attack_skill));
parse->EventNPC(EVENT_DEATH_COMPLETE, this, oos, buffer, 0);
/* Zone controller process EVENT_DEATH_ZONE (Death events) */ /* Zone controller process EVENT_DEATH_ZONE (Death events) */
if (RuleB(Zone, UseZoneController)) { if (RuleB(Zone, UseZoneController)) {
auto controller = entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID); if (entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID) && this->GetNPCTypeID() != ZONE_CONTROLLER_NPC_ID) {
if (controller && GetNPCTypeID() != ZONE_CONTROLLER_NPC_ID) { char data_pass[100] = { 0 };
std::string data_pass = fmt::format("{} {} {} {} {}", killer_mob ? killer_mob->GetID() : 0, damage, spell, static_cast<int>(attack_skill), GetNPCTypeID()); snprintf(data_pass, 99, "%d %d %d %d %d", killer_mob ? killer_mob->GetID() : 0, damage, spell, static_cast<int>(attack_skill), this->GetNPCTypeID());
parse->EventNPC(EVENT_DEATH_ZONE, controller, nullptr, data_pass.c_str(), 0); parse->EventNPC(EVENT_DEATH_ZONE, entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID)->CastToNPC(), nullptr, data_pass, 0);
} }
} }
@@ -2760,9 +2701,8 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
} }
} }
if (other->IsNPC() && (other->IsPet() || other->CastToNPC()->GetSwarmOwner() > 0)) { if (other->IsNPC() && (other->IsPet() || other->CastToNPC()->GetSwarmOwner() > 0))
TryTriggerOnCastRequirement(); TryTriggerOnValueAmount(false, false, false, true);
}
if (IsClient() && !IsAIControlled()) if (IsClient() && !IsAIControlled())
return; return;
@@ -2936,15 +2876,10 @@ void Mob::DamageShield(Mob* attacker, bool spell_ds) {
spellid = spellbonuses.DamageShieldSpellID; spellid = spellbonuses.DamageShieldSpellID;
} }
else { else {
DS = spellbonuses.SpellDamageShield + itembonuses.SpellDamageShield + aabonuses.SpellDamageShield; DS = spellbonuses.SpellDamageShield;
rev_ds = 0; rev_ds = 0;
// This ID returns "you are burned", seemed most appropriate for spell DS // This ID returns "you are burned", seemed most appropriate for spell DS
spellid = 2166; spellid = 2166;
/*
Live Message - not yet used on emu
Feedback onto you "YOUR mind burns from TARGETS NAME's feedback for %i points of non-melee damage."
Feedback onto other "TARGETS NAME's mind burns from YOUR feedback for %i points of non-melee damage."
*/
} }
if (DS == 0 && rev_ds == 0) if (DS == 0 && rev_ds == 0)
@@ -2978,7 +2913,6 @@ void Mob::DamageShield(Mob* attacker, bool spell_ds) {
DS -= DS * ds_mitigation / 100; DS -= DS * ds_mitigation / 100;
} }
attacker->Damage(this, -DS, spellid, EQ::skills::SkillAbjuration/*hackish*/, false); attacker->Damage(this, -DS, spellid, EQ::skills::SkillAbjuration/*hackish*/, false);
//we can assume there is a spell now //we can assume there is a spell now
auto outapp = new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct)); auto outapp = new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct));
@@ -3194,7 +3128,7 @@ int32 Mob::ReduceDamage(int32 damage)
if (spellbonuses.NegateAttacks[SBIndex::NEGATE_ATK_EXISTS]) { if (spellbonuses.NegateAttacks[SBIndex::NEGATE_ATK_EXISTS]) {
slot = spellbonuses.NegateAttacks[SBIndex::NEGATE_ATK_BUFFSLOT]; slot = spellbonuses.NegateAttacks[SBIndex::NEGATE_ATK_BUFFSLOT];
if (slot >= 0) { if (slot >= 0) {
if (--buffs[slot].hit_number == 0) { if (--buffs[slot].numhits == 0) {
if (!TryFadeEffect(slot)) if (!TryFadeEffect(slot))
BuffFadeBySlot(slot, true); BuffFadeBySlot(slot, true);
@@ -3283,7 +3217,7 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi
if (!iBuffTic && spellbonuses.NegateAttacks[SBIndex::NEGATE_ATK_EXISTS]) { if (!iBuffTic && spellbonuses.NegateAttacks[SBIndex::NEGATE_ATK_EXISTS]) {
slot = spellbonuses.NegateAttacks[SBIndex::NEGATE_ATK_BUFFSLOT]; slot = spellbonuses.NegateAttacks[SBIndex::NEGATE_ATK_BUFFSLOT];
if (slot >= 0) { if (slot >= 0) {
if (--buffs[slot].hit_number == 0) { if (--buffs[slot].numhits == 0) {
if (!TryFadeEffect(slot)) if (!TryFadeEffect(slot))
BuffFadeBySlot(slot, true); BuffFadeBySlot(slot, true);
@@ -3409,7 +3343,7 @@ int32 Mob::ReduceAllDamage(int32 damage)
if (GetMana() >= mana_reduced) { if (GetMana() >= mana_reduced) {
damage -= mana_reduced; damage -= mana_reduced;
SetMana(GetMana() - mana_reduced); SetMana(GetMana() - mana_reduced);
TryTriggerOnCastRequirement(); TryTriggerOnValueAmount(false, true);
} }
} }
@@ -3422,7 +3356,7 @@ int32 Mob::ReduceAllDamage(int32 damage)
if (IsClient() && CastToClient()->GetEndurance() >= endurance_drain) { if (IsClient() && CastToClient()->GetEndurance() >= endurance_drain) {
damage -= damage_reduced; damage -= damage_reduced;
CastToClient()->SetEndurance(CastToClient()->GetEndurance() - endurance_drain); CastToClient()->SetEndurance(CastToClient()->GetEndurance() - endurance_drain);
TryTriggerOnCastRequirement(); TryTriggerOnValueAmount(false, false, true);
} }
} }
@@ -3433,37 +3367,17 @@ int32 Mob::ReduceAllDamage(int32 damage)
bool Mob::HasProcs() const bool Mob::HasProcs() const
{ {
for (int i = 0; i < MAX_PROCS; i++) { for (int i = 0; i < MAX_PROCS; i++)
if (PermaProcs[i].spellID != SPELL_UNKNOWN || SpellProcs[i].spellID != SPELL_UNKNOWN) { if (PermaProcs[i].spellID != SPELL_UNKNOWN || SpellProcs[i].spellID != SPELL_UNKNOWN)
return true; return true;
}
}
if (IsClient()) {
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
if (aabonuses.SpellProc[i]) {
return true;
}
}
}
return false; return false;
} }
bool Mob::HasDefensiveProcs() const bool Mob::HasDefensiveProcs() const
{ {
for (int i = 0; i < MAX_PROCS; i++) { for (int i = 0; i < MAX_PROCS; i++)
if (DefensiveProcs[i].spellID != SPELL_UNKNOWN) { if (DefensiveProcs[i].spellID != SPELL_UNKNOWN)
return true; return true;
}
}
if (IsClient()) {
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
if (aabonuses.DefensiveProc[i]) {
return true;
}
}
}
return false; return false;
} }
@@ -3488,19 +3402,9 @@ bool Mob::HasSkillProcSuccess() const
bool Mob::HasRangedProcs() const bool Mob::HasRangedProcs() const
{ {
for (int i = 0; i < MAX_PROCS; i++){ for (int i = 0; i < MAX_PROCS; i++)
if (RangedProcs[i].spellID != SPELL_UNKNOWN) { if (RangedProcs[i].spellID != SPELL_UNKNOWN)
return true; return true;
}
}
if (IsClient()) {
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
if (aabonuses.RangedProc[i]) {
return true;
}
}
}
return false; return false;
} }
@@ -3620,7 +3524,7 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
if (spell_id != SPELL_UNKNOWN && IsLifetapSpell(spell_id)) { if (spell_id != SPELL_UNKNOWN && IsLifetapSpell(spell_id)) {
int healed = damage; int healed = damage;
healed = RuleB(Spells, CompoundLifetapHeals) ? attacker->GetActSpellHealing(spell_id, healed) : healed; healed = attacker->GetActSpellHealing(spell_id, healed);
LogCombat("Applying lifetap heal of [{}] to [{}]", healed, attacker->GetName()); LogCombat("Applying lifetap heal of [{}] to [{}]", healed, attacker->GetName());
attacker->HealDamage(healed); attacker->HealDamage(healed);
@@ -3742,7 +3646,7 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
TryDeathSave(); TryDeathSave();
} }
TryTriggerOnCastRequirement(); TryTriggerOnValueAmount(true);
//fade mez if we are mezzed //fade mez if we are mezzed
if (IsMezzed() && attacker) { if (IsMezzed() && attacker) {
@@ -4134,61 +4038,33 @@ void Mob::TryDefensiveProc(Mob *on, uint16 hand) {
return; return;
} }
if (!HasDefensiveProcs()) { if (!HasDefensiveProcs())
return; return;
}
if (!on->HasDied() && on->GetHP() > 0) { if (!on->HasDied() && on->GetHP() > 0) {
float ProcChance, ProcBonus; float ProcChance, ProcBonus;
on->GetDefensiveProcChances(ProcBonus, ProcChance, hand, this); on->GetDefensiveProcChances(ProcBonus, ProcChance, hand, this);
if (hand == EQ::invslot::slotSecondary) { if (hand != EQ::invslot::slotPrimary)
ProcChance /= 2; ProcChance /= 2;
}
int level_penalty = 0; int level_penalty = 0;
int level_diff = GetLevel() - on->GetLevel(); int level_diff = GetLevel() - on->GetLevel();
if (level_diff > 6) {//10% penalty per level if > 6 levels over target. if (level_diff > 6)//10% penalty per level if > 6 levels over target.
level_penalty = (level_diff - 6) * 10; level_penalty = (level_diff - 6) * 10;
}
ProcChance -= ProcChance*level_penalty / 100; ProcChance -= ProcChance*level_penalty / 100;
if (ProcChance < 0) { if (ProcChance < 0)
return; return;
}
//Spell Procs and Quest added procs
for (int i = 0; i < MAX_PROCS; i++) { for (int i = 0; i < MAX_PROCS; i++) {
if (IsValidSpell(DefensiveProcs[i].spellID)) { if (IsValidSpell(DefensiveProcs[i].spellID)) {
if (!IsProcLimitTimerActive(DefensiveProcs[i].base_spellID, DefensiveProcs[i].proc_reuse_time, SE_DefensiveProc)) {
float chance = ProcChance * (static_cast<float>(DefensiveProcs[i].chance) / 100.0f); float chance = ProcChance * (static_cast<float>(DefensiveProcs[i].chance) / 100.0f);
if (zone->random.Roll(chance)) { if (zone->random.Roll(chance)) {
ExecWeaponProc(nullptr, DefensiveProcs[i].spellID, on); ExecWeaponProc(nullptr, DefensiveProcs[i].spellID, on);
CheckNumHitsRemaining(NumHit::DefensiveSpellProcs, 0, DefensiveProcs[i].base_spellID); CheckNumHitsRemaining(NumHit::DefensiveSpellProcs, 0, DefensiveProcs[i].base_spellID);
SetProcLimitTimer(DefensiveProcs[i].base_spellID, DefensiveProcs[i].proc_reuse_time, SE_DefensiveProc);
}
}
}
}
//AA Procs
if (IsClient()){
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
int32 aa_rank_id = aabonuses.DefensiveProc[i];
int32 aa_spell_id = aabonuses.DefensiveProc[i + 1];
int32 aa_proc_chance = 100 + aabonuses.DefensiveProc[i + 2];
uint32 aa_proc_reuse_timer = aabonuses.DefensiveProc[i + 3];
if (aa_rank_id) {
if (!IsProcLimitTimerActive(-aa_rank_id, aa_proc_reuse_timer, SE_DefensiveProc)) {
float chance = ProcChance * (static_cast<float>(aa_proc_chance) / 100.0f);
if (zone->random.Roll(chance) && IsValidSpell(aa_spell_id)) {
ExecWeaponProc(nullptr, aa_spell_id, on);
SetProcLimitTimer(-aa_rank_id, aa_proc_reuse_timer, SE_DefensiveProc);
}
}
} }
} }
} }
@@ -4233,9 +4109,7 @@ void Mob::TryWeaponProc(const EQ::ItemInstance* weapon_g, Mob *on, uint16 hand)
void Mob::TryWeaponProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon, Mob *on, uint16 hand) void Mob::TryWeaponProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon, Mob *on, uint16 hand)
{ {
if (!on) {
return;
}
if (!weapon) if (!weapon)
return; return;
uint16 skillinuse = 28; uint16 skillinuse = 28;
@@ -4245,7 +4119,7 @@ void Mob::TryWeaponProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon
ProcBonus += static_cast<float>(itembonuses.ProcChance) / 10.0f; // Combat Effects ProcBonus += static_cast<float>(itembonuses.ProcChance) / 10.0f; // Combat Effects
float ProcChance = GetProcChances(ProcBonus, hand); float ProcChance = GetProcChances(ProcBonus, hand);
if (hand == EQ::invslot::slotSecondary) if (hand != EQ::invslot::slotPrimary) //Is Archery intened to proc at 50% rate?
ProcChance /= 2; ProcChance /= 2;
// Try innate proc on weapon // Try innate proc on weapon
@@ -4319,16 +4193,12 @@ void Mob::TryWeaponProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon
void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon, Mob *on, uint16 hand) void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon, Mob *on, uint16 hand)
{ {
if (!on) {
return;
}
float ProcBonus = static_cast<float>(spellbonuses.SpellProcChance + float ProcBonus = static_cast<float>(spellbonuses.SpellProcChance +
itembonuses.SpellProcChance + aabonuses.SpellProcChance); itembonuses.SpellProcChance + aabonuses.SpellProcChance);
float ProcChance = 0.0f; float ProcChance = 0.0f;
ProcChance = GetProcChances(ProcBonus, hand); ProcChance = GetProcChances(ProcBonus, hand);
if (hand == EQ::invslot::slotSecondary) if (hand != EQ::invslot::slotPrimary) //Is Archery intened to proc at 50% rate?
ProcChance /= 2; ProcChance /= 2;
bool rangedattk = false; bool rangedattk = false;
@@ -4356,7 +4226,7 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
// Not ranged // Not ranged
if (!rangedattk) { if (!rangedattk) {
// Perma procs (Not used for AA, they are handled below) // Perma procs (AAs)
if (PermaProcs[i].spellID != SPELL_UNKNOWN) { if (PermaProcs[i].spellID != SPELL_UNKNOWN) {
if (zone->random.Roll(PermaProcs[i].chance)) { // TODO: Do these get spell bonus? if (zone->random.Roll(PermaProcs[i].chance)) { // TODO: Do these get spell bonus?
LogCombat("Permanent proc [{}] procing spell [{}] ([{}] percent chance)", i, PermaProcs[i].spellID, PermaProcs[i].chance); LogCombat("Permanent proc [{}] procing spell [{}] ([{}] percent chance)", i, PermaProcs[i].spellID, PermaProcs[i].chance);
@@ -4374,32 +4244,28 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
continue; // Process the poison proc last per @mackal continue; // Process the poison proc last per @mackal
} }
if (!IsProcLimitTimerActive(SpellProcs[i].base_spellID, SpellProcs[i].proc_reuse_time, SE_WeaponProc)) {
float chance = ProcChance * (static_cast<float>(SpellProcs[i].chance) / 100.0f); float chance = ProcChance * (static_cast<float>(SpellProcs[i].chance) / 100.0f);
if (zone->random.Roll(chance)) { if (zone->random.Roll(chance)) {
LogCombat("Spell proc [{}] procing spell [{}] ([{}] percent chance)", i, SpellProcs[i].spellID, chance); LogCombat("Spell proc [{}] procing spell [{}] ([{}] percent chance)", i, SpellProcs[i].spellID, chance);
SendBeginCast(SpellProcs[i].spellID, 0); SendBeginCast(SpellProcs[i].spellID, 0);
ExecWeaponProc(nullptr, SpellProcs[i].spellID, on, SpellProcs[i].level_override); ExecWeaponProc(nullptr, SpellProcs[i].spellID, on, SpellProcs[i].level_override);
SetProcLimitTimer(SpellProcs[i].base_spellID, SpellProcs[i].proc_reuse_time, SE_WeaponProc); CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0,
CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0, SpellProcs[i].base_spellID); SpellProcs[i].base_spellID);
} }
else { else {
LogCombat("Spell proc [{}] failed to proc [{}] ([{}] percent chance)", i, SpellProcs[i].spellID, chance); LogCombat("Spell proc [{}] failed to proc [{}] ([{}] percent chance)", i, SpellProcs[i].spellID, chance);
} }
} }
} }
}
else if (rangedattk) { // ranged only else if (rangedattk) { // ranged only
// ranged spell procs (buffs) // ranged spell procs (buffs)
if (RangedProcs[i].spellID != SPELL_UNKNOWN) { if (RangedProcs[i].spellID != SPELL_UNKNOWN) {
if (!IsProcLimitTimerActive(RangedProcs[i].base_spellID, RangedProcs[i].proc_reuse_time, SE_RangedProc)) {
float chance = ProcChance * (static_cast<float>(RangedProcs[i].chance) / 100.0f); float chance = ProcChance * (static_cast<float>(RangedProcs[i].chance) / 100.0f);
if (zone->random.Roll(chance)) { if (zone->random.Roll(chance)) {
LogCombat("Ranged proc [{}] procing spell [{}] ([{}] percent chance)", i, RangedProcs[i].spellID, chance); LogCombat("Ranged proc [{}] procing spell [{}] ([{}] percent chance)", i, RangedProcs[i].spellID, chance);
ExecWeaponProc(nullptr, RangedProcs[i].spellID, on); ExecWeaponProc(nullptr, RangedProcs[i].spellID, on);
CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0, RangedProcs[i].base_spellID); CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0,
SetProcLimitTimer(RangedProcs[i].base_spellID, RangedProcs[i].proc_reuse_time, SE_RangedProc); RangedProcs[i].base_spellID);
} }
else { else {
LogCombat("Ranged proc [{}] failed to proc [{}] ([{}] percent chance)", i, RangedProcs[i].spellID, chance); LogCombat("Ranged proc [{}] failed to proc [{}] ([{}] percent chance)", i, RangedProcs[i].spellID, chance);
@@ -4407,49 +4273,6 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
} }
} }
} }
}
//AA Procs
if (IsClient()) {
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
int32 aa_rank_id = 0;
int32 aa_spell_id = SPELL_UNKNOWN;
int32 aa_proc_chance = 100;
uint32 aa_proc_reuse_timer = 0;
int proc_type = 0; //used to deterimne which timer array is used.
if (!rangedattk) {
aa_rank_id = aabonuses.SpellProc[i];
aa_spell_id = aabonuses.SpellProc[i + 1];
aa_proc_chance += aabonuses.SpellProc[i + 2];
aa_proc_reuse_timer = aabonuses.SpellProc[i + 3];
proc_type = SE_WeaponProc;
}
else {
aa_rank_id = aabonuses.RangedProc[i];
aa_spell_id = aabonuses.RangedProc[i + 1];
aa_proc_chance += aabonuses.RangedProc[i + 2];
aa_proc_reuse_timer = aabonuses.RangedProc[i + 3];
proc_type = SE_RangedProc;
}
if (aa_rank_id) {
if (!IsProcLimitTimerActive(-aa_rank_id, aa_proc_reuse_timer, proc_type)) {
float chance = ProcChance * (static_cast<float>(aa_proc_chance) / 100.0f);
if (zone->random.Roll(chance) && IsValidSpell(aa_spell_id)) {
LogCombat("AA proc [{}] procing spell [{}] ([{}] percent chance)", aa_rank_id, aa_spell_id, chance);
ExecWeaponProc(nullptr, aa_spell_id, on);
SetProcLimitTimer(-aa_rank_id, aa_proc_reuse_timer, proc_type);
}
else {
LogCombat("AA proc [{}] failed to proc [{}] ([{}] percent chance)", aa_rank_id, aa_spell_id, chance);
}
}
}
}
}
if (poison_slot > -1) { if (poison_slot > -1) {
bool one_shot = !RuleB(Combat, UseExtendedPoisonProcs); bool one_shot = !RuleB(Combat, UseExtendedPoisonProcs);
@@ -5082,14 +4905,14 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
for (int i = 0; i < EFFECT_COUNT; i++) { for (int i = 0; i < EFFECT_COUNT; i++) {
if (spells[base_spell_id].effect_id[i] == SE_SkillProc || spells[base_spell_id].effect_id[i] == SE_SkillProcSuccess) { if (spells[base_spell_id].effectid[i] == SE_SkillProc || spells[base_spell_id].effectid[i] == SE_SkillProcSuccess) {
proc_spell_id = spells[base_spell_id].base_value[i]; proc_spell_id = spells[base_spell_id].base[i];
ProcMod = static_cast<float>(spells[base_spell_id].limit_value[i]); ProcMod = static_cast<float>(spells[base_spell_id].base2[i]);
} }
else if (spells[base_spell_id].effect_id[i] == SE_LimitToSkill && spells[base_spell_id].base_value[i] <= EQ::skills::HIGHEST_SKILL) { else if (spells[base_spell_id].effectid[i] == SE_LimitToSkill && spells[base_spell_id].base[i] <= EQ::skills::HIGHEST_SKILL) {
if (CanProc && spells[base_spell_id].base_value[i] == skill && IsValidSpell(proc_spell_id)) { if (CanProc && spells[base_spell_id].base[i] == skill && IsValidSpell(proc_spell_id)) {
float final_chance = chance * (ProcMod / 100.0f); float final_chance = chance * (ProcMod / 100.0f);
if (zone->random.Roll(final_chance)) { if (zone->random.Roll(final_chance)) {
ExecWeaponProc(nullptr, proc_spell_id, on); ExecWeaponProc(nullptr, proc_spell_id, on);
@@ -5126,14 +4949,14 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
ProcMod = 0; ProcMod = 0;
for (int i = 0; i < EFFECT_COUNT; i++) { for (int i = 0; i < EFFECT_COUNT; i++) {
if (spells[base_spell_id].effect_id[i] == SE_SkillProc || spells[base_spell_id].effect_id[i] == SE_SkillProcSuccess) { if (spells[base_spell_id].effectid[i] == SE_SkillProc || spells[base_spell_id].effectid[i] == SE_SkillProcSuccess) {
proc_spell_id = spells[base_spell_id].base_value[i]; proc_spell_id = spells[base_spell_id].base[i];
ProcMod = static_cast<float>(spells[base_spell_id].limit_value[i]); ProcMod = static_cast<float>(spells[base_spell_id].base2[i]);
} }
else if (spells[base_spell_id].effect_id[i] == SE_LimitToSkill && spells[base_spell_id].base_value[i] <= EQ::skills::HIGHEST_SKILL) { else if (spells[base_spell_id].effectid[i] == SE_LimitToSkill && spells[base_spell_id].base[i] <= EQ::skills::HIGHEST_SKILL) {
if (CanProc && spells[base_spell_id].base_value[i] == skill && IsValidSpell(proc_spell_id)) { if (CanProc && spells[base_spell_id].base[i] == skill && IsValidSpell(proc_spell_id)) {
float final_chance = chance * (ProcMod / 100.0f); float final_chance = chance * (ProcMod / 100.0f);
if (zone->random.Roll(final_chance)) { if (zone->random.Roll(final_chance)) {
ExecWeaponProc(nullptr, proc_spell_id, on); ExecWeaponProc(nullptr, proc_spell_id, on);
@@ -5155,8 +4978,8 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
CanProc = true; CanProc = true;
uint32 effect_id = 0; uint32 effect_id = 0;
int32 base_value = 0; int32 base1 = 0;
int32 limit_value = 0; int32 base2 = 0;
uint32 slot = 0; uint32 slot = 0;
for (int e = 0; e < MAX_SKILL_PROCS; e++) { for (int e = 0; e < MAX_SKILL_PROCS; e++) {
@@ -5184,17 +5007,17 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
for (auto &effect : rank->effects) { for (auto &effect : rank->effects) {
effect_id = effect.effect_id; effect_id = effect.effect_id;
base_value = effect.base_value; base1 = effect.base1;
limit_value = effect.limit_value; base2 = effect.base2;
slot = effect.slot; slot = effect.slot;
if (effect_id == SE_SkillProc || effect_id == SE_SkillProcSuccess) { if (effect_id == SE_SkillProc || effect_id == SE_SkillProcSuccess) {
proc_spell_id = base_value; proc_spell_id = base1;
ProcMod = static_cast<float>(limit_value); ProcMod = static_cast<float>(base2);
} }
else if (effect_id == SE_LimitToSkill && base_value <= EQ::skills::HIGHEST_SKILL) { else if (effect_id == SE_LimitToSkill && base1 <= EQ::skills::HIGHEST_SKILL) {
if (CanProc && base_value == skill && IsValidSpell(proc_spell_id)) { if (CanProc && base1 == skill && IsValidSpell(proc_spell_id)) {
float final_chance = chance * (ProcMod / 100.0f); float final_chance = chance * (ProcMod / 100.0f);
if (zone->random.Roll(final_chance)) { if (zone->random.Roll(final_chance)) {
@@ -5223,7 +5046,7 @@ float Mob::GetSkillProcChances(uint16 ReuseTime, uint16 hand) {
if (!ReuseTime && hand) { if (!ReuseTime && hand) {
weapon_speed = GetWeaponSpeedbyHand(hand); weapon_speed = GetWeaponSpeedbyHand(hand);
ProcChance = static_cast<float>(weapon_speed) * (RuleR(Combat, AvgProcsPerMinute) / 60000.0f); ProcChance = static_cast<float>(weapon_speed) * (RuleR(Combat, AvgProcsPerMinute) / 60000.0f);
if (hand == EQ::invslot::slotSecondary) if (hand != EQ::invslot::slotPrimary)
ProcChance /= 2; ProcChance /= 2;
} }
@@ -5564,8 +5387,6 @@ void Mob::SetAttackTimer()
void Client::SetAttackTimer() void Client::SetAttackTimer()
{ {
float haste_mod = GetHaste() * 0.01f; float haste_mod = GetHaste() * 0.01f;
int primary_speed = 0;
int secondary_speed = 0;
//default value for attack timer in case they have //default value for attack timer in case they have
//an invalid weapon equipped: //an invalid weapon equipped:
@@ -5643,21 +5464,6 @@ void Client::SetAttackTimer()
speed = static_cast<int>(speed + ((hhe / 100.0f) * delay)); speed = static_cast<int>(speed + ((hhe / 100.0f) * delay));
} }
TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true, true); TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true, true);
if (i == EQ::invslot::slotPrimary) {
primary_speed = speed;
}
else if (i == EQ::invslot::slotSecondary) {
secondary_speed = speed;
}
}
//To allow for duel wield animation to display correctly if both weapons have same delay
if (primary_speed == secondary_speed) {
SetDualWieldingSameDelayWeapons(1);
}
else {
SetDualWieldingSameDelayWeapons(0);
} }
} }
+4 -4
View File
@@ -98,7 +98,7 @@ bool Beacon::Process()
{ {
// NPCs should never be affected by an AE they cast. PB AEs shouldn't affect caster either // NPCs should never be affected by an AE they cast. PB AEs shouldn't affect caster either
// I don't think any other cases that get here matter // I don't think any other cases that get here matter
bool affect_caster = (!caster->IsNPC() && !caster->IsAIControlled()) && spells[spell_id].target_type != ST_AECaster; bool affect_caster = (!caster->IsNPC() && !caster->IsAIControlled()) && spells[spell_id].targettype != ST_AECaster;
entity_list.AESpell(caster, this, spell_id, affect_caster, resist_adjust, &max_targets); entity_list.AESpell(caster, this, spell_id, affect_caster, resist_adjust, &max_targets);
} }
else else
@@ -127,10 +127,10 @@ void Beacon::AELocationSpell(Mob *caster, uint16 cast_spell_id, int16 resist_adj
caster_id = caster->GetID(); caster_id = caster->GetID();
spell_id = cast_spell_id; spell_id = cast_spell_id;
this->resist_adjust = resist_adjust; this->resist_adjust = resist_adjust;
spell_iterations = spells[spell_id].aoe_duration / 2500; spell_iterations = spells[spell_id].AEDuration / 2500;
spell_iterations = spell_iterations < 1 ? 1 : spell_iterations; // at least 1 spell_iterations = spell_iterations < 1 ? 1 : spell_iterations; // at least 1
if (spells[spell_id].aoe_max_targets) if (spells[spell_id].aemaxtargets)
max_targets = spells[spell_id].aoe_max_targets; max_targets = spells[spell_id].aemaxtargets;
spell_timer.Start(2500); spell_timer.Start(2500);
spell_timer.Trigger(); spell_timer.Trigger();
} }
+473 -586
View File
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More