From 852d951b650e1be3fd6ea02ae7863111e31f87a1 Mon Sep 17 00:00:00 2001 From: Uleat Date: Mon, 6 Jan 2020 15:41:05 -0500 Subject: [PATCH 01/57] Reworked EVENT_COMMAND handling and addressed script commands not present during help use --- zone/bot_command.cpp | 6 ++++++ zone/client.cpp | 11 ++++++----- zone/command.cpp | 6 ++++++ zone/embparser.cpp | 15 +++++++++++---- zone/event_codes.h | 1 + zone/lua_parser.cpp | 4 +++- zone/lua_parser_events.cpp | 19 +++++++++++++++++++ zone/lua_parser_events.h | 2 ++ 8 files changed, 54 insertions(+), 10 deletions(-) diff --git a/zone/bot_command.cpp b/zone/bot_command.cpp index 8030d4898..dc9d40aab 100644 --- a/zone/bot_command.cpp +++ b/zone/bot_command.cpp @@ -3414,6 +3414,12 @@ void bot_command_help(Client *c, const Seperator *sep) c->Message(m_usage, "%c%s - %s", BOT_COMMAND_CHAR, command_iter.first.c_str(), command_iter.second->desc == nullptr ? "[no description]" : command_iter.second->desc); ++bot_commands_shown; } + if (parse->PlayerHasQuestSub(EVENT_BOT_COMMAND)) { + int i = parse->EventPlayer(EVENT_BOT_COMMAND, c, sep->msg, 0); + if (i >= 1) { + bot_commands_shown += i; + } + } c->Message(m_message, "%d bot command%s listed.", bot_commands_shown, bot_commands_shown != 1 ? "s" : ""); c->Message(m_note, "type %ccommand [help | usage] for more information", BOT_COMMAND_CHAR); } diff --git a/zone/client.cpp b/zone/client.cpp index f77dc1fd4..d258ae7bf 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -1119,14 +1119,11 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s break; } - if (EQEmu::ProfanityManager::IsCensorshipActive()) - EQEmu::ProfanityManager::RedactMessage(message); - #ifdef BOTS if (message[0] == BOT_COMMAND_CHAR) { if (bot_command_dispatch(this, message) == -2) { - if (parse->PlayerHasQuestSub(EVENT_COMMAND)) { - int i = parse->EventPlayer(EVENT_COMMAND, this, message, 0); + if (parse->PlayerHasQuestSub(EVENT_BOT_COMMAND)) { + int i = parse->EventPlayer(EVENT_BOT_COMMAND, this, message, 0); if (i == 0 && !RuleB(Chat, SuppressCommandErrors)) { Message(Chat::Red, "Bot command '%s' not recognized.", message); } @@ -1140,6 +1137,10 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s } #endif + if (EQEmu::ProfanityManager::IsCensorshipActive()) { + EQEmu::ProfanityManager::RedactMessage(message); + } + Mob* sender = this; if (GetPet() && GetTarget() == GetPet() && GetPet()->FindType(SE_VoiceGraft)) sender = GetPet(); diff --git a/zone/command.cpp b/zone/command.cpp index cf8e47d6a..1f5da287c 100755 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -783,6 +783,12 @@ void command_help(Client *c, const Seperator *sep) commands_shown++; c->Message(Chat::White, " %c%s %s", COMMAND_CHAR, cur->first.c_str(), cur->second->desc == nullptr?"":cur->second->desc); } + if (parse->PlayerHasQuestSub(EVENT_COMMAND)) { + int i = parse->EventPlayer(EVENT_COMMAND, c, sep->msg, 0); + if (i >= 1) { + commands_shown += i; + } + } c->Message(Chat::White, "%d command%s listed.", commands_shown, commands_shown!=1?"s":""); } diff --git a/zone/embparser.cpp b/zone/embparser.cpp index 920d3a249..0f6fffd69 100644 --- a/zone/embparser.cpp +++ b/zone/embparser.cpp @@ -98,7 +98,7 @@ const char *QuestEventSubroutines[_LargestEventID] = { "EVENT_DUEL_LOSE", "EVENT_ENCOUNTER_LOAD", "EVENT_ENCOUNTER_UNLOAD", - "EVENT_SAY", + "EVENT_COMMAND", "EVENT_DROP_ITEM", "EVENT_DESTROY_ITEM", "EVENT_FEIGN_DEATH", @@ -119,6 +119,7 @@ const char *QuestEventSubroutines[_LargestEventID] = { "EVENT_DEATH_ZONE", "EVENT_USE_SKILL", "EVENT_COMBINE_VALIDATE", + "EVENT_BOT_COMMAND" }; PerlembParser::PerlembParser() : perl(nullptr) @@ -1542,9 +1543,9 @@ void PerlembParser::ExportEventVariables( } case EVENT_COMMAND: { - ExportVar(package_name.c_str(), "text", data); - ExportVar(package_name.c_str(), "data", "0"); - ExportVar(package_name.c_str(), "langid", "0"); + Seperator sep(data); + ExportVar(package_name.c_str(), "command", (sep.arg[0] + 1)); + ExportVar(package_name.c_str(), "args", (sep.argnum > 1 ? (&data[strlen(sep.arg[0]) + 1]) : "0")); break; } @@ -1610,6 +1611,12 @@ void PerlembParser::ExportEventVariables( ExportVar(package_name.c_str(), "tradeskill_id", tradeskill_id.c_str()); break; } + case EVENT_BOT_COMMAND: { + Seperator sep(data); + ExportVar(package_name.c_str(), "bot_command", (sep.arg[0] + 1)); + ExportVar(package_name.c_str(), "args", (sep.argnum > 1 ? (&data[strlen(sep.arg[0]) + 1]) : "0")); + break; + } default: { break; diff --git a/zone/event_codes.h b/zone/event_codes.h index 4560cc767..110101cf9 100644 --- a/zone/event_codes.h +++ b/zone/event_codes.h @@ -87,6 +87,7 @@ typedef enum { EVENT_DEATH_ZONE, EVENT_USE_SKILL, EVENT_COMBINE_VALIDATE, + EVENT_BOT_COMMAND, _LargestEventID } QuestEventID; diff --git a/zone/lua_parser.cpp b/zone/lua_parser.cpp index 437bc5121..620ee14d1 100644 --- a/zone/lua_parser.cpp +++ b/zone/lua_parser.cpp @@ -124,7 +124,8 @@ const char *LuaEvents[_LargestEventID] = { "event_spawn_zone", "event_death_zone", "event_use_skill", - "event_combine_validate" + "event_combine_validate", + "event_bot_command" }; extern Zone *zone; @@ -208,6 +209,7 @@ LuaParser::LuaParser() { PlayerArgumentDispatch[EVENT_UNHANDLED_OPCODE] = handle_player_packet; PlayerArgumentDispatch[EVENT_USE_SKILL] = handle_player_use_skill; PlayerArgumentDispatch[EVENT_COMBINE_VALIDATE] = handle_player_combine_validate; + PlayerArgumentDispatch[EVENT_BOT_COMMAND] = handle_player_bot_command; ItemArgumentDispatch[EVENT_ITEM_CLICK] = handle_item_click; ItemArgumentDispatch[EVENT_ITEM_CLICK_CAST] = handle_item_click; diff --git a/zone/lua_parser_events.cpp b/zone/lua_parser_events.cpp index f4f1dd3af..3ca9edad7 100644 --- a/zone/lua_parser_events.cpp +++ b/zone/lua_parser_events.cpp @@ -539,6 +539,25 @@ void handle_player_combine_validate(QuestInterface* parse, lua_State* L, Client* lua_setfield(L, -2, "tradeskill_id"); } +void handle_player_bot_command(QuestInterface* parse, lua_State* L, Client* client, std::string data, uint32 extra_data, + std::vector* extra_pointers) { + Seperator sep(data.c_str(), ' ', 10, 100, true); + std::string bot_command(sep.arg[0] + 1); + lua_pushstring(L, bot_command.c_str()); + lua_setfield(L, -2, "bot_command"); + + luabind::adl::object args = luabind::newtable(L); + int max_args = sep.GetMaxArgNum(); + for (int i = 1; i < max_args; ++i) { + if (strlen(sep.arg[i]) > 0) { + args[i] = std::string(sep.arg[i]); + } + } + + args.push(L); + lua_setfield(L, -2, "args"); +} + //Item void handle_item_click(QuestInterface *parse, lua_State* L, Client* client, EQEmu::ItemInstance* item, Mob *mob, std::string data, uint32 extra_data, std::vector *extra_pointers) { diff --git a/zone/lua_parser_events.h b/zone/lua_parser_events.h index 0054b31e1..9eeeb11cb 100644 --- a/zone/lua_parser_events.h +++ b/zone/lua_parser_events.h @@ -99,6 +99,8 @@ void handle_player_use_skill(QuestInterface *parse, lua_State* L, Client* client std::vector *extra_pointers); void handle_player_combine_validate(QuestInterface* parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector* extra_pointers); +void handle_player_bot_command(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, + std::vector *extra_pointers); //Item void handle_item_click(QuestInterface *parse, lua_State* L, Client* client, EQEmu::ItemInstance* item, Mob *mob, std::string data, uint32 extra_data, From 77ae4f0c3fff7286ee3afd10f9e68f5a077df16c Mon Sep 17 00:00:00 2001 From: Akkadius Date: Tue, 7 Jan 2020 16:09:14 -0600 Subject: [PATCH 02/57] Update missing aliases for when log compilation flag is turned off [skip ci] --- common/eqemu_logsys_log_aliases.h | 36 +++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/common/eqemu_logsys_log_aliases.h b/common/eqemu_logsys_log_aliases.h index 138a6f851..1c003fff9 100644 --- a/common/eqemu_logsys_log_aliases.h +++ b/common/eqemu_logsys_log_aliases.h @@ -842,6 +842,42 @@ #define LogStatusDetail(message, ...) do {\ } while (0) +#define LogAIScanClose(message, ...) do {\ +} while (0) + +#define LogAIScanCloseDetail(message, ...) do {\ +} while (0) + +#define LogAIYellForHelp(message, ...) do {\ +} while (0) + +#define LogAIYellForHelpDetail(message, ...) do {\ +} while (0) + +#define LogAICastBeneficialClose(message, ...) do {\ +} while (0) + +#define LogAICastBeneficialCloseDetail(message, ...) do {\ +} while (0) + +#define LogAoeCast(message, ...) do {\ +} while (0) + +#define LogAoeCastDetail(message, ...) do {\ +} while (0) + +#define LogEntityManagement(message, ...) do {\ +} while (0) + +#define LogEntityManagementDetail(message, ...) do {\ +} while (0) + +#define LogFlee(message, ...) do {\ +} while (0) + +#define LogFleeDetail(message, ...) do {\ +} while (0) + #define Log(debug_level, log_category, message, ...) do {\ } while (0) From b9e87abb3cb63ecf9f343ec6bbbbd508dee4ca2f Mon Sep 17 00:00:00 2001 From: Akkadius Date: Fri, 10 Jan 2020 02:54:29 -0600 Subject: [PATCH 03/57] Implement Character Soft Deletes --- common/database.cpp | 121 ++++--- common/database.h | 2 +- common/ruletypes.h | 1 + common/version.h | 2 +- utils/sql/db_update_manifest.txt | 1 + .../2020_01_10_character_soft_deletes.sql | 1 + world/worlddb.cpp | 334 ++++++++++-------- world/worlddb.h | 2 +- 8 files changed, 269 insertions(+), 195 deletions(-) create mode 100644 utils/sql/git/required/2020_01_10_character_soft_deletes.sql diff --git a/common/database.cpp b/common/database.cpp index fde091322..2723b8102 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -341,65 +341,88 @@ bool Database::ReserveName(uint32 account_id, char* name) { return true; } -/* - Delete the character with the name "name" - returns false on failure, true otherwise -*/ -bool Database::DeleteCharacter(char *name) { - uint32 charid = 0; - if(!name || !strlen(name)) { +/** + * @param character_name + * @return + */ +bool Database::DeleteCharacter(char *character_name) { + uint32 character_id = 0; + if(!character_name || !strlen(character_name)) { LogInfo("DeleteCharacter: request to delete without a name (empty char slot)"); return false; } - LogInfo("Database::DeleteCharacter name : [{}]", name); - /* Get id from character_data before deleting record so we can clean up the rest of the tables */ - std::string query = StringFormat("SELECT `id` from `character_data` WHERE `name` = '%s'", name); - auto results = QueryDatabase(query); - for (auto row = results.begin(); row != results.end(); ++row) { charid = atoi(row[0]); } - if (charid <= 0){ - LogError("Database::DeleteCharacter :: Character ({}) not found, stopping delete...", name); + std::string query = StringFormat("SELECT `id` from `character_data` WHERE `name` = '%s'", character_name); + auto results = QueryDatabase(query); + for (auto row = results.begin(); row != results.end(); ++row) { + character_id = atoi(row[0]); + } + + if (character_id <= 0) { + LogError("DeleteCharacter | Invalid Character ID [{}]", character_name); return false; } - query = StringFormat("DELETE FROM `quest_globals` WHERE `charid` = '%d'", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_activities` WHERE `charid` = '%d'", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_enabledtasks` WHERE `charid` = '%d'", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_tasks` WHERE `charid` = '%d'", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `completed_tasks` WHERE `charid` = '%d'", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `friends` WHERE `charid` = '%d'", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `mail` WHERE `charid` = '%d'", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `timers` WHERE `char_id` = '%d'", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `inventory` WHERE `charid` = '%d'", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `char_recipe_list` WHERE `char_id` = '%d'", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `adventure_stats` WHERE `player_id` ='%d'", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `zone_flags` WHERE `charID` = '%d'", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `titles` WHERE `char_id` = '%d'", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `player_titlesets` WHERE `char_id` = '%d'", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `keyring` WHERE `char_id` = '%d'", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `faction_values` WHERE `char_id` = '%d'", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `instance_list_player` WHERE `charid` = '%d'", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_data` WHERE `id` = '%d'", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_skills` WHERE `id` = %u", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_languages` WHERE `id` = %u", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_bind` WHERE `id` = %u", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_alternate_abilities` WHERE `id` = %u", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_currency` WHERE `id` = %u", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_data` WHERE `id` = %u", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_spells` WHERE `id` = %u", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_memmed_spells` WHERE `id` = %u", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_disciplines` WHERE `id` = %u", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_material` WHERE `id` = %u", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_tribute` WHERE `id` = %u", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_bandolier` WHERE `id` = %u", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_potionbelt` WHERE `id` = %u", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_inspect_messages` WHERE `id` = %u", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_leadership_abilities` WHERE `id` = %u", charid); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_alt_currency` WHERE `char_id` = '%d'", charid); QueryDatabase(query); + std::string delete_type = "hard-deleted"; + if (RuleB(Character, SoftDeletes)) { + delete_type = "soft-deleted"; + std::string query = fmt::format( + SQL( + UPDATE + character_data + SET + deleted_at = NOW() + WHERE + id = '{}' + ), + character_id + ); + + QueryDatabase(query); + + return true; + } + + LogInfo("DeleteCharacter | Character [{}] ({}) is being [{}]", character_name, character_id, delete_type); + + query = StringFormat("DELETE FROM `quest_globals` WHERE `charid` = '%d'", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `character_activities` WHERE `charid` = '%d'", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `character_enabledtasks` WHERE `charid` = '%d'", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `character_tasks` WHERE `charid` = '%d'", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `completed_tasks` WHERE `charid` = '%d'", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `friends` WHERE `charid` = '%d'", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `mail` WHERE `charid` = '%d'", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `timers` WHERE `char_id` = '%d'", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `inventory` WHERE `charid` = '%d'", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `char_recipe_list` WHERE `char_id` = '%d'", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `adventure_stats` WHERE `player_id` ='%d'", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `zone_flags` WHERE `charID` = '%d'", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `titles` WHERE `char_id` = '%d'", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `player_titlesets` WHERE `char_id` = '%d'", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `keyring` WHERE `char_id` = '%d'", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `faction_values` WHERE `char_id` = '%d'", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `instance_list_player` WHERE `charid` = '%d'", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `character_data` WHERE `id` = '%d'", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `character_skills` WHERE `id` = %u", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `character_languages` WHERE `id` = %u", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `character_bind` WHERE `id` = %u", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `character_alternate_abilities` WHERE `id` = %u", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `character_currency` WHERE `id` = %u", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `character_data` WHERE `id` = %u", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `character_spells` WHERE `id` = %u", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `character_memmed_spells` WHERE `id` = %u", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `character_disciplines` WHERE `id` = %u", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `character_material` WHERE `id` = %u", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `character_tribute` WHERE `id` = %u", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `character_bandolier` WHERE `id` = %u", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `character_potionbelt` WHERE `id` = %u", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `character_inspect_messages` WHERE `id` = %u", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `character_leadership_abilities` WHERE `id` = %u", character_id); QueryDatabase(query); + query = StringFormat("DELETE FROM `character_alt_currency` WHERE `char_id` = '%d'", character_id); QueryDatabase(query); #ifdef BOTS query = StringFormat("DELETE FROM `guild_members` WHERE `char_id` = '%d' AND GetMobTypeById(%i) = 'C'", charid); // note: only use of GetMobTypeById() #else - query = StringFormat("DELETE FROM `guild_members` WHERE `char_id` = '%d'", charid); + query = StringFormat("DELETE FROM `guild_members` WHERE `char_id` = '%d'", character_id); #endif QueryDatabase(query); diff --git a/common/database.h b/common/database.h index c84b5301c..f569da20b 100644 --- a/common/database.h +++ b/common/database.h @@ -107,7 +107,7 @@ public: bool AddToNameFilter(const char* name); bool CreateCharacter(uint32 account_id, char* name, uint16 gender, uint16 race, uint16 class_, uint8 str, uint8 sta, uint8 cha, uint8 dex, uint8 int_, uint8 agi, uint8 wis, uint8 face); - bool DeleteCharacter(char* name); + bool DeleteCharacter(char* character_name); bool MoveCharacterToZone(const char* charname, const char* zonename); bool MoveCharacterToZone(const char* charname, const char* zonename,uint32 zoneid); bool MoveCharacterToZone(uint32 iCharID, const char* iZonename); diff --git a/common/ruletypes.h b/common/ruletypes.h index c6e99e5f4..3de392d45 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -158,6 +158,7 @@ RULE_BOOL(Character, AllowCrossClassTrainers, false, "") RULE_BOOL(Character, PetsUseReagents, true, "Pets use reagent on spells") RULE_BOOL(Character, DismountWater, true, "Dismount horses when entering water") RULE_BOOL(Character, UseNoJunkFishing, false, "Disregards junk items when fishing") +RULE_BOOL(Character, SoftDeletes, true, "When characters are deleted in character select, they are only soft deleted") RULE_CATEGORY_END() RULE_CATEGORY(Mercs) diff --git a/common/version.h b/common/version.h index 17e69601a..0f659d57b 100644 --- a/common/version.h +++ b/common/version.h @@ -34,7 +34,7 @@ * Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9145 +#define CURRENT_BINARY_DATABASE_VERSION 9146 #ifdef BOTS #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9026 diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index e68450e7d..aa7897e7f 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -399,6 +399,7 @@ 9143|2019_09_16_account_table_changes.sql|SHOW COLUMNS FROM `account` LIKE 'ls_id'|empty| 9144|2019_11_09_logsys_description_update.sql|SELECT * FROM db_version WHERE version >= 9143|empty| 9145|2019_12_24_banned_ips_update.sql|SHOW TABLES LIKE 'Banned_IPs'|not_empty| +9146|2020_01_10_character_soft_deletes.sql|SHOW COLUMNS FROM `character_data` LIKE 'deleted_at'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2020_01_10_character_soft_deletes.sql b/utils/sql/git/required/2020_01_10_character_soft_deletes.sql new file mode 100644 index 000000000..17496b141 --- /dev/null +++ b/utils/sql/git/required/2020_01_10_character_soft_deletes.sql @@ -0,0 +1 @@ +ALTER TABLE `character_data` ADD COLUMN `deleted_at` datetime NULL DEFAULT NULL; \ No newline at end of file diff --git a/world/worlddb.cpp b/world/worlddb.cpp index fbd4cdf94..3682b93f6 100644 --- a/world/worlddb.cpp +++ b/world/worlddb.cpp @@ -31,23 +31,27 @@ extern std::vector character_create_allocations; extern std::vector character_create_race_class_combos; -// the current stuff is at the bottom of this function -void WorldDatabase::GetCharSelectInfo(uint32 accountID, EQApplicationPacket **outApp, uint32 clientVersionBit) +/** + * @param account_id + * @param out_app + * @param client_version_bit + */ +void WorldDatabase::GetCharSelectInfo(uint32 account_id, EQApplicationPacket **out_app, uint32 client_version_bit) { - /* Set Character Creation Limit */ - EQEmu::versions::ClientVersion client_version = EQEmu::versions::ConvertClientVersionBitToClientVersion(clientVersionBit); + EQEmu::versions::ClientVersion size_t character_limit = EQEmu::constants::StaticLookup(client_version)->CharacterCreationLimit; // Validate against absolute server max if (character_limit > EQEmu::constants::CHARACTER_CREATION_LIMIT) character_limit = EQEmu::constants::CHARACTER_CREATION_LIMIT; + } // Force Titanium clients to use '8' - if (client_version == EQEmu::versions::ClientVersion::Titanium) + if (client_version == EQEmu::versions::ClientVersion::Titanium) { character_limit = 8; - - /* Get Character Info */ - std::string cquery = StringFormat( + } + + std::string character_list_query = StringFormat( "SELECT " "`id`, " // 0 "name, " // 1 @@ -71,237 +75,281 @@ void WorldDatabase::GetCharSelectInfo(uint32 accountID, EQApplicationPacket **ou "zone_id " // 19 "FROM " "character_data " - "WHERE `account_id` = %i ORDER BY `name` LIMIT %u", accountID, character_limit); - auto results = database.QueryDatabase(cquery); + "WHERE `account_id` = %i AND deleted_at IS NULL ORDER BY `name` LIMIT %u", + account_id, + character_limit + ); + + auto results = database.QueryDatabase(character_list_query); size_t character_count = results.RowCount(); if (character_count == 0) { - *outApp = new EQApplicationPacket(OP_SendCharInfo, sizeof(CharacterSelect_Struct)); - CharacterSelect_Struct *cs = (CharacterSelect_Struct *)(*outApp)->pBuffer; - cs->CharCount = 0; + *out_app = new EQApplicationPacket(OP_SendCharInfo, sizeof(CharacterSelect_Struct)); + CharacterSelect_Struct *cs = (CharacterSelect_Struct *) (*out_app)->pBuffer; + cs->CharCount = 0; cs->TotalChars = character_limit; return; } size_t packet_size = sizeof(CharacterSelect_Struct) + (sizeof(CharacterSelectEntry_Struct) * character_count); - *outApp = new EQApplicationPacket(OP_SendCharInfo, packet_size); + *out_app = new EQApplicationPacket(OP_SendCharInfo, packet_size); - unsigned char *buff_ptr = (*outApp)->pBuffer; - CharacterSelect_Struct *cs = (CharacterSelect_Struct *)buff_ptr; + unsigned char *buff_ptr = (*out_app)->pBuffer; + CharacterSelect_Struct *cs = (CharacterSelect_Struct *) buff_ptr; - cs->CharCount = character_count; + cs->CharCount = character_count; cs->TotalChars = character_limit; buff_ptr += sizeof(CharacterSelect_Struct); for (auto row = results.begin(); row != results.end(); ++row) { - CharacterSelectEntry_Struct *cse = (CharacterSelectEntry_Struct *)buff_ptr; - PlayerProfile_Struct pp; - EQEmu::InventoryProfile inv; + CharacterSelectEntry_Struct *p_character_select_entry_struct = (CharacterSelectEntry_Struct *) buff_ptr; + PlayerProfile_Struct player_profile_struct; + EQEmu::InventoryProfile inventory_profile; - pp.SetPlayerProfileVersion(EQEmu::versions::ConvertClientVersionToMobVersion(client_version)); - inv.SetInventoryVersion(client_version); - inv.SetGMInventory(true); // charsel can not interact with items..but, no harm in setting to full expansion support + player_profile_struct.SetPlayerProfileVersion(EQEmu::versions::ConvertClientVersionToMobVersion(client_version)); + inventory_profile.SetInventoryVersion(client_version); + inventory_profile.SetGMInventory(true); // charsel can not interact with items..but, no harm in setting to full expansion support - uint32 character_id = (uint32)atoi(row[0]); - uint8 has_home = 0; - uint8 has_bind = 0; + uint32 character_id = (uint32) atoi(row[0]); + uint8 has_home = 0; + uint8 has_bind = 0; - memset(&pp, 0, sizeof(PlayerProfile_Struct)); - - /* Fill CharacterSelectEntry_Struct */ - memset(cse->Name, 0, sizeof(cse->Name)); - strcpy(cse->Name, row[1]); - cse->Class = (uint8)atoi(row[4]); - cse->Race = (uint32)atoi(row[3]); - cse->Level = (uint8)atoi(row[5]); - cse->ShroudClass = cse->Class; - cse->ShroudRace = cse->Race; - cse->Zone = (uint16)atoi(row[19]); - cse->Instance = 0; - cse->Gender = (uint8)atoi(row[2]); - cse->Face = (uint8)atoi(row[15]); + memset(&player_profile_struct, 0, sizeof(PlayerProfile_Struct)); - for (uint32 matslot = 0; matslot < EQEmu::textures::materialCount; matslot++) { // Processed below - cse->Equip[matslot].Material = 0; - cse->Equip[matslot].Unknown1 = 0; - cse->Equip[matslot].EliteModel = 0; - cse->Equip[matslot].HerosForgeModel = 0; - cse->Equip[matslot].Unknown2 = 0; - cse->Equip[matslot].Color = 0; - } + memset(p_character_select_entry_struct->Name, 0, sizeof(p_character_select_entry_struct->Name)); + strcpy(p_character_select_entry_struct->Name, row[1]); + p_character_select_entry_struct->Class = (uint8) atoi(row[4]); + p_character_select_entry_struct->Race = (uint32) atoi(row[3]); + p_character_select_entry_struct->Level = (uint8) atoi(row[5]); + p_character_select_entry_struct->ShroudClass = p_character_select_entry_struct->Class; + p_character_select_entry_struct->ShroudRace = p_character_select_entry_struct->Race; + p_character_select_entry_struct->Zone = (uint16) atoi(row[19]); + p_character_select_entry_struct->Instance = 0; + p_character_select_entry_struct->Gender = (uint8) atoi(row[2]); + p_character_select_entry_struct->Face = (uint8) atoi(row[15]); - cse->Unknown15 = 0xFF; - cse->Unknown19 = 0xFF; - cse->DrakkinTattoo = (uint32)atoi(row[17]); - cse->DrakkinDetails = (uint32)atoi(row[18]); - cse->Deity = (uint32)atoi(row[6]); - cse->PrimaryIDFile = 0; // Processed Below - cse->SecondaryIDFile = 0; // Processed Below - cse->HairColor = (uint8)atoi(row[9]); - cse->BeardColor = (uint8)atoi(row[10]); - cse->EyeColor1 = (uint8)atoi(row[11]); - cse->EyeColor2 = (uint8)atoi(row[12]); - cse->HairStyle = (uint8)atoi(row[13]); - cse->Beard = (uint8)atoi(row[14]); - cse->GoHome = 0; // Processed Below - cse->Tutorial = 0; // Processed Below - cse->DrakkinHeritage = (uint32)atoi(row[16]); - cse->Unknown1 = 0; - cse->Enabled = 1; - cse->LastLogin = (uint32)atoi(row[7]); // RoF2 value: 1212696584 - cse->Unknown2 = 0; - /* Fill End */ + for (uint32 material_slot = 0; material_slot < EQEmu::textures::materialCount; material_slot++) { + p_character_select_entry_struct->Equip[material_slot].Material = 0; + p_character_select_entry_struct->Equip[material_slot].Unknown1 = 0; + p_character_select_entry_struct->Equip[material_slot].EliteModel = 0; + p_character_select_entry_struct->Equip[material_slot].HerosForgeModel = 0; + p_character_select_entry_struct->Equip[material_slot].Unknown2 = 0; + p_character_select_entry_struct->Equip[material_slot].Color = 0; + } + + p_character_select_entry_struct->Unknown15 = 0xFF; + p_character_select_entry_struct->Unknown19 = 0xFF; + p_character_select_entry_struct->DrakkinTattoo = (uint32) atoi(row[17]); + p_character_select_entry_struct->DrakkinDetails = (uint32) atoi(row[18]); + p_character_select_entry_struct->Deity = (uint32) atoi(row[6]); + p_character_select_entry_struct->PrimaryIDFile = 0; // Processed Below + p_character_select_entry_struct->SecondaryIDFile = 0; // Processed Below + p_character_select_entry_struct->HairColor = (uint8) atoi(row[9]); + p_character_select_entry_struct->BeardColor = (uint8) atoi(row[10]); + p_character_select_entry_struct->EyeColor1 = (uint8) atoi(row[11]); + p_character_select_entry_struct->EyeColor2 = (uint8) atoi(row[12]); + p_character_select_entry_struct->HairStyle = (uint8) atoi(row[13]); + p_character_select_entry_struct->Beard = (uint8) atoi(row[14]); + p_character_select_entry_struct->GoHome = 0; // Processed Below + p_character_select_entry_struct->Tutorial = 0; // Processed Below + p_character_select_entry_struct->DrakkinHeritage = (uint32) atoi(row[16]); + p_character_select_entry_struct->Unknown1 = 0; + p_character_select_entry_struct->Enabled = 1; + p_character_select_entry_struct->LastLogin = (uint32) atoi(row[7]); // RoF2 value: 1212696584 + p_character_select_entry_struct->Unknown2 = 0; if (RuleB(World, EnableReturnHomeButton)) { int now = time(nullptr); - if ((now - atoi(row[7])) >= RuleI(World, MinOfflineTimeToReturnHome)) - cse->GoHome = 1; + if ((now - atoi(row[7])) >= RuleI(World, MinOfflineTimeToReturnHome)) { + p_character_select_entry_struct->GoHome = 1; + } } - if (RuleB(World, EnableTutorialButton) && (cse->Level <= RuleI(World, MaxLevelForTutorial))) { - cse->Tutorial = 1; + if (RuleB(World, EnableTutorialButton) && (p_character_select_entry_struct->Level <= RuleI(World, MaxLevelForTutorial))) { + p_character_select_entry_struct->Tutorial = 1; } - /* Set Bind Point Data for any character that may possibly be missing it for any reason */ - cquery = StringFormat("SELECT `zone_id`, `instance_id`, `x`, `y`, `z`, `heading`, `slot` FROM `character_bind` WHERE `id` = %i LIMIT 5", character_id); - auto results_bind = database.QueryDatabase(cquery); - auto bind_count = results_bind.RowCount(); - for (auto row_b = results_bind.begin(); row_b != results_bind.end(); ++row_b) { + /** + * Bind + */ + character_list_query = StringFormat( + "SELECT `zone_id`, `instance_id`, `x`, `y`, `z`, `heading`, `slot` FROM `character_bind` WHERE `id` = %i LIMIT 5", + character_id + ); + auto results_bind = database.QueryDatabase(character_list_query); + auto bind_count = results_bind.RowCount(); + for (auto row_b = results_bind.begin(); row_b != results_bind.end(); ++row_b) { if (row_b[6] && atoi(row_b[6]) == 4) { has_home = 1; // If our bind count is less than 5, we need to actually make use of this data so lets parse it if (bind_count < 5) { - pp.binds[4].zoneId = atoi(row_b[0]); - pp.binds[4].instance_id = atoi(row_b[1]); - pp.binds[4].x = atof(row_b[2]); - pp.binds[4].y = atof(row_b[3]); - pp.binds[4].z = atof(row_b[4]); - pp.binds[4].heading = atof(row_b[5]); + player_profile_struct.binds[4].zoneId = atoi(row_b[0]); + player_profile_struct.binds[4].instance_id = atoi(row_b[1]); + player_profile_struct.binds[4].x = atof(row_b[2]); + player_profile_struct.binds[4].y = atof(row_b[3]); + player_profile_struct.binds[4].z = atof(row_b[4]); + player_profile_struct.binds[4].heading = atof(row_b[5]); } } - if (row_b[6] && atoi(row_b[6]) == 0){ has_bind = 1; } + if (row_b[6] && atoi(row_b[6]) == 0) { has_bind = 1; } } if (has_home == 0 || has_bind == 0) { - cquery = StringFormat("SELECT `zone_id`, `bind_id`, `x`, `y`, `z` FROM `start_zones` WHERE `player_class` = %i AND `player_deity` = %i AND `player_race` = %i", - cse->Class, cse->Deity, cse->Race); - auto results_bind = database.QueryDatabase(cquery); - for (auto row_d = results_bind.begin(); row_d != results_bind.end(); ++row_d) { + character_list_query = StringFormat( + "SELECT `zone_id`, `bind_id`, `x`, `y`, `z` FROM `start_zones` WHERE `player_class` = %i AND `player_deity` = %i AND `player_race` = %i", + p_character_select_entry_struct->Class, + p_character_select_entry_struct->Deity, + p_character_select_entry_struct->Race + ); + auto results_bind = database.QueryDatabase(character_list_query); + for (auto row_d = results_bind.begin(); row_d != results_bind.end(); ++row_d) { /* If a bind_id is specified, make them start there */ if (atoi(row_d[1]) != 0) { - pp.binds[4].zoneId = (uint32)atoi(row_d[1]); - GetSafePoints(pp.binds[4].zoneId, 0, &pp.binds[4].x, &pp.binds[4].y, &pp.binds[4].z); + player_profile_struct.binds[4].zoneId = (uint32) atoi(row_d[1]); + GetSafePoints(player_profile_struct.binds[4].zoneId, 0, &player_profile_struct.binds[4].x, &player_profile_struct.binds[4].y, &player_profile_struct.binds[4].z); } - /* Otherwise, use the zone and coordinates given */ + /* Otherwise, use the zone and coordinates given */ else { - pp.binds[4].zoneId = (uint32)atoi(row_d[0]); + player_profile_struct.binds[4].zoneId = (uint32) atoi(row_d[0]); float x = atof(row_d[2]); float y = atof(row_d[3]); float z = atof(row_d[4]); - if (x == 0 && y == 0 && z == 0){ GetSafePoints(pp.binds[4].zoneId, 0, &x, &y, &z); } - pp.binds[4].x = x; pp.binds[4].y = y; pp.binds[4].z = z; + if (x == 0 && y == 0 && z == 0) { GetSafePoints(player_profile_struct.binds[4].zoneId, 0, &x, &y, &z); } + player_profile_struct.binds[4].x = x; + player_profile_struct.binds[4].y = y; + player_profile_struct.binds[4].z = z; } } - pp.binds[0] = pp.binds[4]; + player_profile_struct.binds[0] = player_profile_struct.binds[4]; /* If no home bind set, set it */ if (has_home == 0) { - std::string query = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, slot)" + std::string query = StringFormat( + "REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, slot)" " VALUES (%u, %u, %u, %f, %f, %f, %f, %i)", - character_id, pp.binds[4].zoneId, 0, pp.binds[4].x, pp.binds[4].y, pp.binds[4].z, pp.binds[4].heading, 4); - auto results_bset = QueryDatabase(query); + character_id, + player_profile_struct.binds[4].zoneId, + 0, + player_profile_struct.binds[4].x, + player_profile_struct.binds[4].y, + player_profile_struct.binds[4].z, + player_profile_struct.binds[4].heading, + 4 + ); + auto results_bset = QueryDatabase(query); } /* If no regular bind set, set it */ if (has_bind == 0) { - std::string query = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, slot)" + std::string query = StringFormat( + "REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, slot)" " VALUES (%u, %u, %u, %f, %f, %f, %f, %i)", - character_id, pp.binds[0].zoneId, 0, pp.binds[0].x, pp.binds[0].y, pp.binds[0].z, pp.binds[0].heading, 0); - auto results_bset = QueryDatabase(query); + character_id, + player_profile_struct.binds[0].zoneId, + 0, + player_profile_struct.binds[0].x, + player_profile_struct.binds[0].y, + player_profile_struct.binds[0].z, + player_profile_struct.binds[0].heading, + 0 + ); + auto results_bset = QueryDatabase(query); } } /* If our bind count is less than 5, then we have null data that needs to be filled in. */ if (bind_count < 5) { // we know that home and main bind must be valid here, so we don't check those // we also use home to fill in the null data like live does. - for (int i = 1; i < 4; i++) { - if (pp.binds[i].zoneId != 0) // we assume 0 is the only invalid one ... + for (int i = 1; i < 4; i++) { + if (player_profile_struct.binds[i].zoneId != 0) { // we assume 0 is the only invalid one ... continue; + } - std::string query = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, slot)" + std::string query = StringFormat( + "REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, slot)" " VALUES (%u, %u, %u, %f, %f, %f, %f, %i)", - character_id, pp.binds[4].zoneId, 0, pp.binds[4].x, pp.binds[4].y, pp.binds[4].z, pp.binds[4].heading, i); - auto results_bset = QueryDatabase(query); + character_id, + player_profile_struct.binds[4].zoneId, + 0, + player_profile_struct.binds[4].x, + player_profile_struct.binds[4].y, + player_profile_struct.binds[4].z, + player_profile_struct.binds[4].heading, + i + ); + auto results_bset = QueryDatabase(query); } } - /* Bind End */ - /* Load Character Material Data for Char Select */ - cquery = StringFormat("SELECT slot, red, green, blue, use_tint, color FROM `character_material` WHERE `id` = %u", character_id); - auto results_b = database.QueryDatabase(cquery); uint8 slot = 0; - for (auto row_b = results_b.begin(); row_b != results_b.end(); ++row_b) { + character_list_query = StringFormat( + "SELECT slot, red, green, blue, use_tint, color FROM `character_material` WHERE `id` = %u", + character_id + ); + auto results_b = database.QueryDatabase(character_list_query); + uint8 slot = 0; + for (auto row_b = results_b.begin(); row_b != results_b.end(); ++row_b) { slot = atoi(row_b[0]); - pp.item_tint.Slot[slot].Red = atoi(row_b[1]); - pp.item_tint.Slot[slot].Green = atoi(row_b[2]); - pp.item_tint.Slot[slot].Blue = atoi(row_b[3]); - pp.item_tint.Slot[slot].UseTint = atoi(row_b[4]); + player_profile_struct.item_tint.Slot[slot].Red = atoi(row_b[1]); + player_profile_struct.item_tint.Slot[slot].Green = atoi(row_b[2]); + player_profile_struct.item_tint.Slot[slot].Blue = atoi(row_b[3]); + player_profile_struct.item_tint.Slot[slot].UseTint = atoi(row_b[4]); } - /* Character Material Data End */ - /* Load Inventory */ - // If we ensure that the material data is updated appropriately, we can do away with inventory loads - if (GetCharSelInventory(accountID, cse->Name, &inv)) { - const EQEmu::ItemData* item = nullptr; - const EQEmu::ItemInstance* inst = nullptr; - int16 invslot = 0; + if (GetCharSelInventory(account_id, p_character_select_entry_struct->Name, &inventory_profile)) { + const EQEmu::ItemData *item = nullptr; + const EQEmu::ItemInstance *inst = nullptr; + int16 inventory_slot = 0; for (uint32 matslot = EQEmu::textures::textureBegin; matslot < EQEmu::textures::materialCount; matslot++) { - invslot = EQEmu::InventoryProfile::CalcSlotFromMaterial(matslot); - if (invslot == INVALID_INDEX) { continue; } - inst = inv.GetItem(invslot); - if (inst == nullptr) { continue; } + inventory_slot = EQEmu::InventoryProfile::CalcSlotFromMaterial(matslot); + if (inventory_slot == INVALID_INDEX) { continue; } + inst = inventory_profile.GetItem(inventory_slot); + if (inst == nullptr) { + continue; + } item = inst->GetItem(); - if (item == nullptr) { continue; } + if (item == nullptr) { + continue; + } if (matslot > 6) { - uint32 idfile = 0; + uint32 item_id_file = 0; // Weapon Models if (inst->GetOrnamentationIDFile() != 0) { - idfile = inst->GetOrnamentationIDFile(); - cse->Equip[matslot].Material = idfile; + item_id_file = inst->GetOrnamentationIDFile(); + p_character_select_entry_struct->Equip[matslot].Material = item_id_file; } else { if (strlen(item->IDFile) > 2) { - idfile = atoi(&item->IDFile[2]); - cse->Equip[matslot].Material = idfile; + item_id_file = atoi(&item->IDFile[2]); + p_character_select_entry_struct->Equip[matslot].Material = item_id_file; } } if (matslot == EQEmu::textures::weaponPrimary) { - cse->PrimaryIDFile = idfile; + p_character_select_entry_struct->PrimaryIDFile = item_id_file; } else { - cse->SecondaryIDFile = idfile; + p_character_select_entry_struct->SecondaryIDFile = item_id_file; } } else { uint32 color = 0; - if (pp.item_tint.Slot[matslot].UseTint) { - color = pp.item_tint.Slot[matslot].Color; + if (player_profile_struct.item_tint.Slot[matslot].UseTint) { + color = player_profile_struct.item_tint.Slot[matslot].Color; } else { color = inst->GetColor(); } // Armor Materials/Models - cse->Equip[matslot].Material = item->Material; - cse->Equip[matslot].EliteModel = item->EliteMaterial; - cse->Equip[matslot].HerosForgeModel = inst->GetOrnamentHeroModel(matslot); - cse->Equip[matslot].Color = color; + p_character_select_entry_struct->Equip[matslot].Material = item->Material; + p_character_select_entry_struct->Equip[matslot].EliteModel = item->EliteMaterial; + p_character_select_entry_struct->Equip[matslot].HerosForgeModel = inst->GetOrnamentHeroModel(matslot); + p_character_select_entry_struct->Equip[matslot].Color = color; } } } else { - printf("Error loading inventory for %s\n", cse->Name); + printf("Error loading inventory for %s\n", p_character_select_entry_struct->Name); } - /* Load Inventory End */ buff_ptr += sizeof(CharacterSelectEntry_Struct); } diff --git a/world/worlddb.h b/world/worlddb.h index 036c0dc40..e367803ec 100644 --- a/world/worlddb.h +++ b/world/worlddb.h @@ -30,7 +30,7 @@ struct CharacterSelect_Struct; class WorldDatabase : public SharedDatabase { public: bool GetStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct* in_cc, bool isTitanium); - void GetCharSelectInfo(uint32 accountID, EQApplicationPacket **outApp, uint32 clientVersionBit); + void GetCharSelectInfo(uint32 account_id, EQApplicationPacket **out_app, uint32 client_version_bit); int MoveCharacterToBind(int CharID, uint8 bindnum = 0); void GetLauncherList(std::vector &result); From f81b9d82448b666585591b8513f126f3fddf6f8d Mon Sep 17 00:00:00 2001 From: Akkadius Date: Fri, 10 Jan 2020 02:54:34 -0600 Subject: [PATCH 04/57] Update worlddb.cpp --- world/worlddb.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/world/worlddb.cpp b/world/worlddb.cpp index 3682b93f6..f45207273 100644 --- a/world/worlddb.cpp +++ b/world/worlddb.cpp @@ -39,10 +39,10 @@ extern std::vector character_create_race_class_combos; void WorldDatabase::GetCharSelectInfo(uint32 account_id, EQApplicationPacket **out_app, uint32 client_version_bit) { EQEmu::versions::ClientVersion + client_version = EQEmu::versions::ConvertClientVersionBitToClientVersion(client_version_bit); size_t character_limit = EQEmu::constants::StaticLookup(client_version)->CharacterCreationLimit; - - // Validate against absolute server max - if (character_limit > EQEmu::constants::CHARACTER_CREATION_LIMIT) + + if (character_limit > EQEmu::constants::CHARACTER_CREATION_LIMIT) { character_limit = EQEmu::constants::CHARACTER_CREATION_LIMIT; } From d1fb74ff5f17e61774ca0623041fb796e3bfb7e5 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Fri, 10 Jan 2020 02:59:52 -0600 Subject: [PATCH 05/57] Fix bot table --- common/database.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/database.cpp b/common/database.cpp index 2723b8102..f6adc3659 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -420,7 +420,7 @@ bool Database::DeleteCharacter(char *character_name) { query = StringFormat("DELETE FROM `character_leadership_abilities` WHERE `id` = %u", character_id); QueryDatabase(query); query = StringFormat("DELETE FROM `character_alt_currency` WHERE `char_id` = '%d'", character_id); QueryDatabase(query); #ifdef BOTS - query = StringFormat("DELETE FROM `guild_members` WHERE `char_id` = '%d' AND GetMobTypeById(%i) = 'C'", charid); // note: only use of GetMobTypeById() + query = StringFormat("DELETE FROM `guild_members` WHERE `char_id` = '%d' AND GetMobTypeById(%i) = 'C'", character_id); // note: only use of GetMobTypeById() #else query = StringFormat("DELETE FROM `guild_members` WHERE `char_id` = '%d'", character_id); #endif From 3c6cdd09051544beb15361d3c5d92b6f65bb06cf Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sat, 11 Jan 2020 18:02:01 -0600 Subject: [PATCH 06/57] Update character_table_list.txt for now until replaced [skip ci] --- utils/sql/character_table_list.txt | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/utils/sql/character_table_list.txt b/utils/sql/character_table_list.txt index 8a47abf67..385827379 100644 --- a/utils/sql/character_table_list.txt +++ b/utils/sql/character_table_list.txt @@ -1,9 +1,16 @@ +aa_timers +account +account_ip +account_flags +account_rewards +adventure_details adventure_stats +buyer char_recipe_list -character_auras character_activities character_alt_currency character_alternate_abilities +character_auras character_bandolier character_bind character_buffs @@ -20,15 +27,22 @@ character_leadership_abilities character_material character_memmed_spells character_pet_buffs +character_pet_info character_pet_inventory character_potionbelt character_skills character_spells +character_tasks character_tribute completed_tasks +data_buckets faction_values friends +guild_bank guild_members +guild_ranks +guild_relations +guilds instance_list_player inventory inventory_snapshots @@ -36,6 +50,9 @@ keyring mail player_titlesets quest_globals +sharedbank timers titles -zone_flags +trader +trader_audit +zone_flags" \ No newline at end of file From 9dacd0bd7a17f48966449b8c354127c353f848fa Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sat, 11 Jan 2020 18:19:27 -0600 Subject: [PATCH 07/57] Remove aa_timers from character tables [skip ci] --- common/database_schema.h | 1 - utils/scripts/schema.xml | 5738 ---------------------------- utils/sql/character_table_list.txt | 1 - 3 files changed, 5740 deletions(-) delete mode 100644 utils/scripts/schema.xml diff --git a/common/database_schema.h b/common/database_schema.h index 6033e85b5..73637c877 100644 --- a/common/database_schema.h +++ b/common/database_schema.h @@ -33,7 +33,6 @@ namespace DatabaseSchema { static std::vector GetPlayerTables() { std::vector tables = { - "aa_timers", "account", "account_ip", "account_flags", diff --git a/utils/scripts/schema.xml b/utils/scripts/schema.xml deleted file mode 100644 index dcfa687be..000000000 --- a/utils/scripts/schema.xml +++ /dev/null @@ -1,5738 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - -
diff --git a/utils/sql/character_table_list.txt b/utils/sql/character_table_list.txt index 385827379..ab6610dab 100644 --- a/utils/sql/character_table_list.txt +++ b/utils/sql/character_table_list.txt @@ -1,4 +1,3 @@ -aa_timers account account_ip account_flags From 6c2100a650f7a78cc96a43a5c290b605da5e2382 Mon Sep 17 00:00:00 2001 From: Uleat Date: Sun, 12 Jan 2020 01:32:51 -0500 Subject: [PATCH 08/57] Fix for perl EVENT_COMMAND not exporting single arguments --- zone/embparser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zone/embparser.cpp b/zone/embparser.cpp index 0f6fffd69..ef1b404a2 100644 --- a/zone/embparser.cpp +++ b/zone/embparser.cpp @@ -1545,7 +1545,7 @@ void PerlembParser::ExportEventVariables( case EVENT_COMMAND: { Seperator sep(data); ExportVar(package_name.c_str(), "command", (sep.arg[0] + 1)); - ExportVar(package_name.c_str(), "args", (sep.argnum > 1 ? (&data[strlen(sep.arg[0]) + 1]) : "0")); + ExportVar(package_name.c_str(), "args", (sep.argnum >= 1 ? (&data[strlen(sep.arg[0]) + 1]) : "0")); break; } @@ -1614,7 +1614,7 @@ void PerlembParser::ExportEventVariables( case EVENT_BOT_COMMAND: { Seperator sep(data); ExportVar(package_name.c_str(), "bot_command", (sep.arg[0] + 1)); - ExportVar(package_name.c_str(), "args", (sep.argnum > 1 ? (&data[strlen(sep.arg[0]) + 1]) : "0")); + ExportVar(package_name.c_str(), "args", (sep.argnum >= 1 ? (&data[strlen(sep.arg[0]) + 1]) : "0")); break; } From 306a08b9ac428a4e8527adb9f9439bdfaa47d835 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 12 Jan 2020 19:37:53 -0600 Subject: [PATCH 09/57] Unify / streamline scanning logic calls, do a manual scan on enter and cleanup logging --- zone/client_packet.cpp | 2 ++ zone/client_process.cpp | 23 +---------------------- zone/entity.cpp | 7 ++++++- zone/npc.cpp | 6 ------ 4 files changed, 9 insertions(+), 29 deletions(-) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 4291cd054..36081601d 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -905,6 +905,8 @@ void Client::CompleteConnect() entity_list.RefreshClientXTargets(this); worldserver.RequestTellQueue(GetName()); + + entity_list.ScanCloseMobs(close_mobs, this); } // connecting opcode handlers diff --git a/zone/client_process.cpp b/zone/client_process.cpp index 14b2036cf..d8ec451a9 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -256,28 +256,7 @@ bool Client::Process() { * Used in aggro checks */ if (mob_close_scan_timer.Check()) { - close_mobs.clear(); - - float scan_range = RuleI(Range, MobCloseScanDistance) * RuleI(Range, MobCloseScanDistance); - auto &mob_list = entity_list.GetMobList(); - - for (auto itr : mob_list) { - Mob *mob = itr.second; - float distance = DistanceSquared(m_Position, mob->GetPosition()); - - if (mob->GetID() <= 0) { - continue; - } - - if (mob->IsNPC() || mob->IsClient()) { - if (distance <= scan_range) { - close_mobs.insert(std::pair(mob->GetID(), mob)); - } - else if ((mob->GetAggroRange() * mob->GetAggroRange()) > scan_range) { - close_mobs.insert(std::pair(mob->GetID(), mob)); - } - } - } + entity_list.ScanCloseMobs(close_mobs, this); } bool may_use_attacks = false; diff --git a/zone/entity.cpp b/zone/entity.cpp index adb29011f..dc90a41b1 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -2654,7 +2654,12 @@ void EntityList::ScanCloseMobs(std::unordered_map &close_mobs, Mo } } - LogAIScanClose("Close List Size [{}] for mob [{}]", close_mobs.size(), scanning_mob->GetCleanName()); + LogAIScanClose( + "[{}] Scanning Close List | list_size [{}] moving [{}]", + scanning_mob->GetCleanName(), + close_mobs.size(), + scanning_mob->IsMoving() ? "true" : "false" + ); } bool EntityList::RemoveMerc(uint16 delete_id) diff --git a/zone/npc.cpp b/zone/npc.cpp index 8b4996177..ed5f37bb5 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -705,12 +705,6 @@ bool NPC::Process() SpellProcess(); if (mob_scan_close.Check()) { - LogAIScanClose( - "is_moving [{}] npc [{}] timer [{}]", - moving ? "true" : "false", - GetCleanName(), - mob_scan_close.GetDuration() - ); entity_list.ScanCloseMobs(close_mobs, this); From 6366a3fa38696e20fcfcc3f4490ee763be405bba Mon Sep 17 00:00:00 2001 From: Uleat Date: Sun, 12 Jan 2020 21:11:43 -0500 Subject: [PATCH 10/57] Fix for silent saylinks and EVENT_COMMAND calls --- zone/client_packet.cpp | 17 +++++++++++++++++ zone/embparser.cpp | 6 ++++++ 2 files changed, 23 insertions(+) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 4291cd054..2be564058 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -8286,6 +8286,15 @@ void Client::Handle_OP_ItemLinkClick(const EQApplicationPacket *app) if (GetTarget() && GetTarget()->IsNPC()) { if (silentsaylink) { parse->EventNPC(EVENT_SAY, GetTarget()->CastToNPC(), this, response.c_str(), 0); + + if (response[0] == '#' && parse->PlayerHasQuestSub(EVENT_COMMAND)) { + parse->EventPlayer(EVENT_COMMAND, this, response.substr(1).c_str(), 0); + } +#ifdef BOTS + else if (response[0] == '^' && parse->PlayerHasQuestSub(EVENT_BOT_COMMAND)) { + parse->EventPlayer(EVENT_BOT_COMMAND, this, response.substr(1).c_str(), 0); + } +#endif parse->EventPlayer(EVENT_SAY, this, response.c_str(), 0); } else { @@ -8296,6 +8305,14 @@ void Client::Handle_OP_ItemLinkClick(const EQApplicationPacket *app) } else { if (silentsaylink) { + if (response[0] == '#' && parse->PlayerHasQuestSub(EVENT_COMMAND)) { + parse->EventPlayer(EVENT_COMMAND, this, response.substr(1).c_str(), 0); + } +#ifdef BOTS + else if (response[0] == '^' && parse->PlayerHasQuestSub(EVENT_BOT_COMMAND)) { + parse->EventPlayer(EVENT_BOT_COMMAND, this, response.substr(1).c_str(), 0); + } +#endif parse->EventPlayer(EVENT_SAY, this, response.c_str(), 0); } else { diff --git a/zone/embparser.cpp b/zone/embparser.cpp index ef1b404a2..f89c09ad4 100644 --- a/zone/embparser.cpp +++ b/zone/embparser.cpp @@ -1546,6 +1546,9 @@ void PerlembParser::ExportEventVariables( Seperator sep(data); ExportVar(package_name.c_str(), "command", (sep.arg[0] + 1)); ExportVar(package_name.c_str(), "args", (sep.argnum >= 1 ? (&data[strlen(sep.arg[0]) + 1]) : "0")); + ExportVar(package_name.c_str(), "data", objid); + ExportVar(package_name.c_str(), "text", data); + ExportVar(package_name.c_str(), "langid", extradata); break; } @@ -1615,6 +1618,9 @@ void PerlembParser::ExportEventVariables( Seperator sep(data); ExportVar(package_name.c_str(), "bot_command", (sep.arg[0] + 1)); ExportVar(package_name.c_str(), "args", (sep.argnum >= 1 ? (&data[strlen(sep.arg[0]) + 1]) : "0")); + ExportVar(package_name.c_str(), "data", objid); + ExportVar(package_name.c_str(), "text", data); + ExportVar(package_name.c_str(), "langid", extradata); break; } From c438819ed666edca68936754e749e0392025cd7f Mon Sep 17 00:00:00 2001 From: Uleat Date: Sun, 12 Jan 2020 22:40:05 -0500 Subject: [PATCH 11/57] Fix for command redirect of '#bot' using EVENT_COMMAND invocation --- zone/command.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zone/command.cpp b/zone/command.cpp index 1f5da287c..e3f884481 100755 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -13270,8 +13270,8 @@ void command_bot(Client *c, const Seperator *sep) } if (bot_command_dispatch(c, bot_message.c_str()) == -2) { - if (parse->PlayerHasQuestSub(EVENT_COMMAND)) { - int i = parse->EventPlayer(EVENT_COMMAND, c, bot_message, 0); + if (parse->PlayerHasQuestSub(EVENT_BOT_COMMAND)) { + int i = parse->EventPlayer(EVENT_BOT_COMMAND, c, bot_message, 0); if (i == 0 && !RuleB(Chat, SuppressCommandErrors)) { c->Message(Chat::Red, "Bot command '%s' not recognized.", bot_message.c_str()); } From 9bdb70b2f0a5358a4cd2e8865b171758135d56e8 Mon Sep 17 00:00:00 2001 From: Uleat Date: Mon, 13 Jan 2020 01:47:39 -0500 Subject: [PATCH 12/57] Fatality! (Fix for event_say parse events not observing the correct parser for their situation) --- zone/client.cpp | 27 +++++++++++++++++++++------ zone/client_packet.cpp | 8 ++++++-- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/zone/client.cpp b/zone/client.cpp index d258ae7bf..9ea27869a 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -1106,14 +1106,22 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s case ChatChannel_Say: { /* Say */ if(message[0] == COMMAND_CHAR) { if(command_dispatch(this, message) == -2) { - if(parse->PlayerHasQuestSub(EVENT_COMMAND)) { + if (parse->PlayerHasQuestSub(EVENT_COMMAND)) { int i = parse->EventPlayer(EVENT_COMMAND, this, message, 0); - if(i == 0 && !RuleB(Chat, SuppressCommandErrors)) { + if (i == 0 && !RuleB(Chat, SuppressCommandErrors)) { Message(Chat::Red, "Command '%s' not recognized.", message); } - } else { - if(!RuleB(Chat, SuppressCommandErrors)) + } + else if (parse->PlayerHasQuestSub(EVENT_SAY)) { + int i = parse->EventPlayer(EVENT_SAY, this, message, 0); + if (i == 0 && !RuleB(Chat, SuppressCommandErrors)) { Message(Chat::Red, "Command '%s' not recognized.", message); + } + } + else { + if (!RuleB(Chat, SuppressCommandErrors)) { + Message(Chat::Red, "Command '%s' not recognized.", message); + } } } break; @@ -1128,9 +1136,16 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s Message(Chat::Red, "Bot command '%s' not recognized.", message); } } - else { - if (!RuleB(Chat, SuppressCommandErrors)) + else if (parse->PlayerHasQuestSub(EVENT_SAY)) { + int i = parse->EventPlayer(EVENT_SAY, this, message, 0); + if (i == 0 && !RuleB(Chat, SuppressCommandErrors)) { Message(Chat::Red, "Bot command '%s' not recognized.", message); + } + } + else { + if (!RuleB(Chat, SuppressCommandErrors)) { + Message(Chat::Red, "Bot command '%s' not recognized.", message); + } } } break; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 8d583985d..6a8ef9dd3 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -8297,7 +8297,9 @@ void Client::Handle_OP_ItemLinkClick(const EQApplicationPacket *app) parse->EventPlayer(EVENT_BOT_COMMAND, this, response.substr(1).c_str(), 0); } #endif - parse->EventPlayer(EVENT_SAY, this, response.c_str(), 0); + else { + parse->EventPlayer(EVENT_SAY, this, response.c_str(), 0); + } } else { Message(Chat::LightGray, "You say, '%s'", response.c_str()); @@ -8315,7 +8317,9 @@ void Client::Handle_OP_ItemLinkClick(const EQApplicationPacket *app) parse->EventPlayer(EVENT_BOT_COMMAND, this, response.substr(1).c_str(), 0); } #endif - parse->EventPlayer(EVENT_SAY, this, response.c_str(), 0); + else { + parse->EventPlayer(EVENT_SAY, this, response.c_str(), 0); + } } else { Message(Chat::LightGray, "You say, '%s'", response.c_str()); From 61790ef195c29d0be7419123e9796fff631d3b60 Mon Sep 17 00:00:00 2001 From: Uleat Date: Mon, 13 Jan 2020 19:01:42 -0500 Subject: [PATCH 13/57] Wasn't quite dead... (Removed substring call from silent saylink parsing) --- zone/client_packet.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 6a8ef9dd3..ebc6bd38a 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -8290,11 +8290,11 @@ void Client::Handle_OP_ItemLinkClick(const EQApplicationPacket *app) parse->EventNPC(EVENT_SAY, GetTarget()->CastToNPC(), this, response.c_str(), 0); if (response[0] == '#' && parse->PlayerHasQuestSub(EVENT_COMMAND)) { - parse->EventPlayer(EVENT_COMMAND, this, response.substr(1).c_str(), 0); + parse->EventPlayer(EVENT_COMMAND, this, response.c_str(), 0); } #ifdef BOTS else if (response[0] == '^' && parse->PlayerHasQuestSub(EVENT_BOT_COMMAND)) { - parse->EventPlayer(EVENT_BOT_COMMAND, this, response.substr(1).c_str(), 0); + parse->EventPlayer(EVENT_BOT_COMMAND, this, response.c_str(), 0); } #endif else { @@ -8310,11 +8310,11 @@ void Client::Handle_OP_ItemLinkClick(const EQApplicationPacket *app) else { if (silentsaylink) { if (response[0] == '#' && parse->PlayerHasQuestSub(EVENT_COMMAND)) { - parse->EventPlayer(EVENT_COMMAND, this, response.substr(1).c_str(), 0); + parse->EventPlayer(EVENT_COMMAND, this, response.c_str(), 0); } #ifdef BOTS else if (response[0] == '^' && parse->PlayerHasQuestSub(EVENT_BOT_COMMAND)) { - parse->EventPlayer(EVENT_BOT_COMMAND, this, response.substr(1).c_str(), 0); + parse->EventPlayer(EVENT_BOT_COMMAND, this, response.c_str(), 0); } #endif else { From 331032f4f4342f6dff01f59f23eed2f9e5173b60 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Tue, 14 Jan 2020 16:14:19 -0600 Subject: [PATCH 14/57] Push a scan when mobs first construct [skip ci] --- zone/mob.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zone/mob.cpp b/zone/mob.cpp index 8b8758771..94b53d1f9 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -459,6 +459,8 @@ Mob::Mob( #ifdef BOTS m_manual_follow = false; #endif + + mob_scan_close.Trigger(); } Mob::~Mob() From 79db824a3c7c279d09520cd1d6eb5d06f12c4dd5 Mon Sep 17 00:00:00 2001 From: Uleat Date: Wed, 15 Jan 2020 02:56:00 -0500 Subject: [PATCH 15/57] Fix for bots update reporting errors on server start-up after newer update applied [skip ci] --- utils/sql/git/bots/bots_db_update_manifest.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/sql/git/bots/bots_db_update_manifest.txt b/utils/sql/git/bots/bots_db_update_manifest.txt index 0a1e4466a..1e18516b7 100644 --- a/utils/sql/git/bots/bots_db_update_manifest.txt +++ b/utils/sql/git/bots/bots_db_update_manifest.txt @@ -21,9 +21,9 @@ 9020|2018_08_13_bots_inventory_update.sql|SELECT * FROM `inventory_versions` WHERE `version` = 2 and `bot_step` = 0|not_empty| 9021|2018_10_09_bots_owner_options.sql|SHOW TABLES LIKE 'bot_owner_options'|empty| 9022|2019_02_07_bots_stance_type_update.sql|SELECT * FROM `bot_spell_casting_chances` WHERE `spell_type_index` = '255' AND `class_id` = '255' AND `stance_index` = '0'|not_empty| -9023|2019_06_22_bots_owner_option_stats_update.sql|SHOW COLUMNS FROM `bot_owner_options` LIKE 'stats_update'|empty| +9023|2019_06_22_bots_owner_option_stats_update.sql|SELECT * FROM db_version WHERE bots_version >= 9023|empty| 9024|2019_06_27_bots_pet_get_lost.sql|SELECT `bot_command` FROM `bot_command_settings` WHERE `bot_command` LIKE 'petgetlost'|empty| -9025|2019_08_26_bots_owner_option_spawn_message.sql|SHOW COLUMNS FROM `bot_owner_options` LIKE 'spawn_message_enabled'|empty| +9025|2019_08_26_bots_owner_option_spawn_message.sql|SELECT * FROM db_version WHERE bots_version >= 9025|empty| 9026|2019_09_09_bots_owner_options_rework.sql|SHOW COLUMNS FROM `bot_owner_options` LIKE 'option_type'|empty| # Upgrade conditions: From d5067c4c3a87790c81a1c69fa4c47e91cdf5fc02 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Wed, 15 Jan 2020 19:30:47 -0500 Subject: [PATCH 16/57] Treat bots like PCs for pcnpc_only_flag --- zone/effects.cpp | 6 ++++-- zone/entity.cpp | 4 ++-- zone/spells.cpp | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/zone/effects.cpp b/zone/effects.cpp index 5528f784a..7e2ecdbc7 100644 --- a/zone/effects.cpp +++ b/zone/effects.cpp @@ -809,11 +809,13 @@ void EntityList::AESpell( * 1 = PC * 2 = NPC */ - if (spells[spell_id].pcnpc_only_flag == 1 && !current_mob->IsClient() && !current_mob->IsMerc()) { + if (spells[spell_id].pcnpc_only_flag == 1 && !current_mob->IsClient() && !current_mob->IsMerc() && + !current_mob->IsBot()) { continue; } - if (spells[spell_id].pcnpc_only_flag == 2 && (current_mob->IsClient() || current_mob->IsMerc())) { + if (spells[spell_id].pcnpc_only_flag == 2 && + (current_mob->IsClient() || current_mob->IsMerc() || current_mob->IsBot())) { continue; } diff --git a/zone/entity.cpp b/zone/entity.cpp index dc90a41b1..3d926e651 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -4960,10 +4960,10 @@ void EntityList::GetTargetsForConeArea(Mob *start, float min_radius, float radiu continue; } // check PC/NPC only flag 1 = PCs, 2 = NPCs - if (pcnpc == 1 && !ptr->IsClient() && !ptr->IsMerc()) { + if (pcnpc == 1 && !ptr->IsClient() && !ptr->IsMerc() && !ptr->IsBot()) { ++it; continue; - } else if (pcnpc == 2 && (ptr->IsClient() || ptr->IsMerc())) { + } else if (pcnpc == 2 && (ptr->IsClient() || ptr->IsMerc() || ptr->IsBot())) { ++it; continue; } diff --git a/zone/spells.cpp b/zone/spells.cpp index afeac90e9..a1e926a1c 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -3455,9 +3455,9 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r // 1 = PCs, 2 = NPCs if (spells[spell_id].pcnpc_only_flag && spells[spell_id].targettype != ST_AETargetHateList && spells[spell_id].targettype != ST_HateList) { - if (spells[spell_id].pcnpc_only_flag == 1 && !spelltar->IsClient() && !spelltar->IsMerc()) + if (spells[spell_id].pcnpc_only_flag == 1 && !spelltar->IsClient() && !spelltar->IsMerc() && !spelltar->IsBot()) return false; - else if (spells[spell_id].pcnpc_only_flag == 2 && (spelltar->IsClient() || spelltar->IsMerc())) + else if (spells[spell_id].pcnpc_only_flag == 2 && (spelltar->IsClient() || spelltar->IsMerc() || spelltar->IsBot())) return false; } From 28b0526857e6d9c082fd792410a44d328883498f Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 16 Jan 2020 15:16:21 -0500 Subject: [PATCH 17/57] Change NPCType::deity to uint32 to match client data type Fixes overflow warning in bot.cpp Shouldn't need DeityAgnostic_LB anymore either --- zone/zonedump.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/zonedump.h b/zone/zonedump.h index 302d4ee25..6010c9480 100644 --- a/zone/zonedump.h +++ b/zone/zonedump.h @@ -44,7 +44,7 @@ struct NPCType uint16 race; uint8 class_; uint8 bodytype; // added for targettype support - uint8 deity; //not loaded from DB + uint32 deity; //not loaded from DB uint8 level; uint32 npc_id; uint8 texture; From 7ce88b30ad9b5a1e595c73aa7aaab7da413d1c29 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 16 Jan 2020 15:47:25 -0500 Subject: [PATCH 18/57] Remove Bot::BotfocusType This was just a maintenance burden keeping it in sync with focusType (and it wasn't!) --- zone/bot.cpp | 110 +++++++++++++++++++++++++------------------------- zone/bot.h | 40 ++---------------- zone/pets.cpp | 2 +- 3 files changed, 59 insertions(+), 93 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index b5628ecb4..ccb3e99df 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -5234,7 +5234,7 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b return false; } -int32 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint32 points, uint16 spell_id) +int32 Bot::CalcBotAAFocus(focusType type, uint32 aa_ID, uint32 points, uint16 spell_id) { const SPDat_Spell_Struct &spell = spells[spell_id]; int32 value = 0; @@ -5557,8 +5557,8 @@ int32 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint32 points, uint16 return (value * lvlModifier / 100); } -int32 Bot::GetBotFocusEffect(BotfocusType bottype, uint16 spell_id) { - if (IsBardSong(spell_id) && bottype != BotfocusFcBaseEffects) +int32 Bot::GetBotFocusEffect(focusType bottype, uint16 spell_id) { + if (IsBardSong(spell_id) && bottype != focusFcBaseEffects) return 0; int32 realTotal = 0; @@ -5567,7 +5567,7 @@ int32 Bot::GetBotFocusEffect(BotfocusType bottype, uint16 spell_id) { bool rand_effectiveness = false; //Improved Healing, Damage & Mana Reduction are handled differently in that some are random percentages //In these cases we need to find the most powerful effect, so that each piece of gear wont get its own chance - if((bottype == BotfocusManaCost || bottype == BotfocusImprovedHeal || bottype == BotfocusImprovedDamage) && RuleB(Spells, LiveLikeFocusEffects)) + if((bottype == focusManaCost || bottype == focusImprovedHeal || bottype == focusImprovedDamage) && RuleB(Spells, LiveLikeFocusEffects)) rand_effectiveness = true; //Check if item focus effect exists for the client. @@ -5708,16 +5708,16 @@ int32 Bot::GetBotFocusEffect(BotfocusType bottype, uint16 spell_id) { } } - if(bottype == BotfocusReagentCost && IsSummonPetSpell(spell_id) && GetAA(aaElementalPact)) + if(bottype == focusReagentCost && IsSummonPetSpell(spell_id) && GetAA(aaElementalPact)) return 100; - if(bottype == BotfocusReagentCost && (IsEffectInSpell(spell_id, SE_SummonItem) || IsSacrificeSpell(spell_id))) + if(bottype == focusReagentCost && (IsEffectInSpell(spell_id, SE_SummonItem) || IsSacrificeSpell(spell_id))) return 0; return (realTotal + realTotal2); } -int32 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spell_id, bool best_focus) { +int32 Bot::CalcBotFocusEffect(focusType bottype, uint16 focus_id, uint16 spell_id, bool best_focus) { if(!IsValidSpell(focus_id) || !IsValidSpell(spell_id)) return 0; @@ -5847,7 +5847,7 @@ int32 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel return 0; break; case SE_ImprovedDamage: - if (bottype == BotfocusImprovedDamage) { + if (bottype == focusImprovedDamage) { if(best_focus) { if (focus_spell.base2[i] != 0) value = focus_spell.base2[i]; @@ -5861,7 +5861,7 @@ int32 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel } break; case SE_ImprovedHeal: - if (bottype == BotfocusImprovedHeal) { + if (bottype == focusImprovedHeal) { if(best_focus) { if (focus_spell.base2[i] != 0) value = focus_spell.base2[i]; @@ -5875,7 +5875,7 @@ int32 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel } break; case SE_ReduceManaCost: - if (bottype == BotfocusManaCost) { + if (bottype == focusManaCost) { if(best_focus) { if (focus_spell.base2[i] != 0) value = focus_spell.base2[i]; @@ -5889,39 +5889,39 @@ int32 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel } break; case SE_IncreaseSpellHaste: - if (bottype == BotfocusSpellHaste && focus_spell.base[i] > value) + if (bottype == focusSpellHaste && focus_spell.base[i] > value) value = focus_spell.base[i]; break; case SE_IncreaseSpellDuration: - if (bottype == BotfocusSpellDuration && focus_spell.base[i] > value) + if (bottype == focusSpellDuration && focus_spell.base[i] > value) value = focus_spell.base[i]; break; case SE_SpellDurationIncByTic: - if (bottype == BotfocusSpellDurByTic && focus_spell.base[i] > value) + if (bottype == focusSpellDurByTic && focus_spell.base[i] > value) value = focus_spell.base[i]; break; case SE_SwarmPetDuration: - if (bottype == BotfocusSwarmPetDuration && focus_spell.base[i] > value) + if (bottype == focusSwarmPetDuration && focus_spell.base[i] > value) value = focus_spell.base[i]; break; case SE_IncreaseRange: - if (bottype == BotfocusRange && focus_spell.base[i] > value) + if (bottype == focusRange && focus_spell.base[i] > value) value = focus_spell.base[i]; break; case SE_ReduceReagentCost: - if (bottype == BotfocusReagentCost && focus_spell.base[i] > value) + if (bottype == focusReagentCost && focus_spell.base[i] > value) value = focus_spell.base[i]; break; case SE_PetPowerIncrease: - if (bottype == BotfocusPetPower && focus_spell.base[i] > value) + if (bottype == focusPetPower && focus_spell.base[i] > value) value = focus_spell.base[i]; break; case SE_SpellResistReduction: - if (bottype == BotfocusResistRate && focus_spell.base[i] > value) + if (bottype == focusResistRate && focus_spell.base[i] > value) value = focus_spell.base[i]; break; case SE_SpellHateMod: - if (bottype == BotfocusSpellHateMod) { + if (bottype == focusSpellHateMod) { if(value != 0) { if(value > 0) { if(focus_spell.base[i] > value) @@ -5936,12 +5936,12 @@ int32 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel } break; case SE_ReduceReuseTimer: { - if(bottype == BotfocusReduceRecastTime) + if(bottype == focusReduceRecastTime) value = (focus_spell.base[i] / 1000); break; } case SE_TriggerOnCast: { - if(bottype == BotfocusTriggerOnCast) { + if(bottype == focusTriggerOnCast) { if(zone->random.Int(0, 100) <= focus_spell.base[i]) value = focus_spell.base2[i]; else @@ -5950,24 +5950,24 @@ int32 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel break; } case SE_FcSpellVulnerability: { - if(bottype == BotfocusSpellVulnerability) + if(bottype == focusSpellVulnerability) value = focus_spell.base[i]; break; } case SE_BlockNextSpellFocus: { - if(bottype == BotfocusBlockNextSpell) { + if(bottype == focusBlockNextSpell) { if(zone->random.Int(1, 100) <= focus_spell.base[i]) value = 1; } break; } case SE_FcTwincast: { - if(bottype == BotfocusTwincast) + if(bottype == focusTwincast) value = focus_spell.base[i]; break; } case SE_SympatheticProc: { - if(bottype == BotfocusSympatheticProc) { + if(bottype == focusSympatheticProc) { float ProcChance = GetSympatheticProcChances(spell_id, focus_spell.base[i]); if(zone->random.Real(0, 1) <= ProcChance) value = focus_id; @@ -5977,49 +5977,49 @@ int32 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel break; } case SE_FcDamageAmt: { - if(bottype == BotfocusFcDamageAmt) + if(bottype == focusFcDamageAmt) value = focus_spell.base[i]; break; } case SE_FcDamageAmtCrit: { - if(bottype == BotfocusFcDamageAmtCrit) + if(bottype == focusFcDamageAmtCrit) value = focus_spell.base[i]; break; } case SE_FcHealAmtIncoming: - if(bottype == BotfocusFcHealAmtIncoming) + if(bottype == focusFcHealAmtIncoming) value = focus_spell.base[i]; break; case SE_FcHealPctCritIncoming: - if (bottype == BotfocusFcHealPctCritIncoming) + if (bottype == focusFcHealPctCritIncoming) value = focus_spell.base[i]; break; case SE_FcHealAmtCrit: - if(bottype == BotfocusFcHealAmtCrit) + if(bottype == focusFcHealAmtCrit) value = focus_spell.base[i]; break; case SE_FcHealAmt: - if(bottype == BotfocusFcHealAmt) + if(bottype == focusFcHealAmt) value = focus_spell.base[i]; break; case SE_FcHealPctIncoming: - if(bottype == BotfocusFcHealPctIncoming) + if(bottype == focusFcHealPctIncoming) value = focus_spell.base[i]; break; case SE_FcBaseEffects: { - if (bottype == BotfocusFcBaseEffects) + if (bottype == focusFcBaseEffects) value = focus_spell.base[i]; break; } case SE_FcDamagePctCrit: { - if(bottype == BotfocusFcDamagePctCrit) + if(bottype == focusFcDamagePctCrit) value = focus_spell.base[i]; break; } case SE_FcIncreaseNumHits: { - if(bottype == BotfocusIncreaseNumHits) + if(bottype == focusIncreaseNumHits) value = focus_spell.base[i]; break; @@ -6559,14 +6559,14 @@ void Bot::DoClassAttacks(Mob *target, bool IsRiposte) { int32 Bot::CheckAggroAmount(uint16 spellid) { int32 AggroAmount = Mob::CheckAggroAmount(spellid, nullptr); - int32 focusAggro = GetBotFocusEffect(BotfocusSpellHateMod, spellid); + int32 focusAggro = GetBotFocusEffect(focusSpellHateMod, spellid); AggroAmount = (AggroAmount * (100 + focusAggro) / 100); return AggroAmount; } int32 Bot::CheckHealAggroAmount(uint16 spellid, Mob *target, uint32 heal_possible) { int32 AggroAmount = Mob::CheckHealAggroAmount(spellid, target, heal_possible); - int32 focusAggro = GetBotFocusEffect(BotfocusSpellHateMod, spellid); + int32 focusAggro = GetBotFocusEffect(focusSpellHateMod, spellid); AggroAmount = (AggroAmount * (100 + focusAggro) / 100); return AggroAmount; } @@ -6840,7 +6840,7 @@ int32 Bot::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { bool Critical = false; int32 value_BaseEffect = 0; - value_BaseEffect = (value + (value*GetBotFocusEffect(BotfocusFcBaseEffects, spell_id) / 100)); + value_BaseEffect = (value + (value*GetBotFocusEffect(focusFcBaseEffects, spell_id) / 100)); // Need to scale HT damage differently after level 40! It no longer scales by the constant value in the spell file. It scales differently, instead of 10 more damage per level, it does 30 more damage per level. So we multiply the level minus 40 times 20 if they are over level 40. if ( (spell_id == SPELL_HARM_TOUCH || spell_id == SPELL_HARM_TOUCH2 || spell_id == SPELL_IMP_HARM_TOUCH ) && GetLevel() > 40) value -= ((GetLevel() - 40) * 20); @@ -6868,16 +6868,16 @@ int32 Bot::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { ratio += RuleI(Spells, WizCritRatio); if (Critical) { value = (value_BaseEffect * ratio / 100); - value += (value_BaseEffect * GetBotFocusEffect(BotfocusImprovedDamage, spell_id) / 100); - value += (int(value_BaseEffect * GetBotFocusEffect(BotfocusFcDamagePctCrit, spell_id) / 100) * ratio / 100); + value += (value_BaseEffect * GetBotFocusEffect(focusImprovedDamage, spell_id) / 100); + value += (int(value_BaseEffect * GetBotFocusEffect(focusFcDamagePctCrit, spell_id) / 100) * ratio / 100); if (target) { value += (int(value_BaseEffect * target->GetVulnerability(this, spell_id, 0) / 100) * ratio / 100); value -= target->GetFcDamageAmtIncoming(this, spell_id); } - value -= (GetBotFocusEffect(BotfocusFcDamageAmtCrit, spell_id) * ratio / 100); + value -= (GetBotFocusEffect(focusFcDamageAmtCrit, spell_id) * ratio / 100); - value -= GetBotFocusEffect(BotfocusFcDamageAmt, spell_id); + value -= GetBotFocusEffect(focusFcDamageAmt, spell_id); if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) value += (GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value) * ratio / 100); @@ -6889,15 +6889,15 @@ int32 Bot::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { } value = value_BaseEffect; - value += (value_BaseEffect * GetBotFocusEffect(BotfocusImprovedDamage, spell_id) / 100); - value += (value_BaseEffect * GetBotFocusEffect(BotfocusFcDamagePctCrit, spell_id) / 100); + value += (value_BaseEffect * GetBotFocusEffect(focusImprovedDamage, spell_id) / 100); + value += (value_BaseEffect * GetBotFocusEffect(focusFcDamagePctCrit, spell_id) / 100); if (target) { value += (value_BaseEffect * target->GetVulnerability(this, spell_id, 0) / 100); value -= target->GetFcDamageAmtIncoming(this, spell_id); } - value -= GetBotFocusEffect(BotfocusFcDamageAmtCrit, spell_id); - value -= GetBotFocusEffect(BotfocusFcDamageAmt, spell_id); + value -= GetBotFocusEffect(focusFcDamageAmtCrit, spell_id); + value -= GetBotFocusEffect(focusFcDamageAmt, spell_id); if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) value += GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value); @@ -6912,9 +6912,9 @@ int32 Bot::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { int32 chance = 0; int8 modifier = 1; bool Critical = false; - value_BaseEffect = (value + (value*GetBotFocusEffect(BotfocusFcBaseEffects, spell_id) / 100)); + value_BaseEffect = (value + (value*GetBotFocusEffect(focusFcBaseEffects, spell_id) / 100)); value = value_BaseEffect; - value += int(value_BaseEffect*GetBotFocusEffect(BotfocusImprovedHeal, spell_id) / 100); + value += int(value_BaseEffect*GetBotFocusEffect(focusImprovedHeal, spell_id) / 100); if(spells[spell_id].buffduration < 1) { chance += (itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance); chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id); @@ -6927,8 +6927,8 @@ int32 Bot::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { } value *= modifier; - value += (GetBotFocusEffect(BotfocusFcHealAmtCrit, spell_id) * modifier); - value += GetBotFocusEffect(BotfocusFcHealAmt, spell_id); + value += (GetBotFocusEffect(focusFcHealAmtCrit, spell_id) * modifier); + value += GetBotFocusEffect(focusFcHealAmt, spell_id); value += target->GetFocusIncoming(focusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id); if(itembonuses.HealAmt && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) @@ -6953,7 +6953,7 @@ int32 Bot::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { int32 Bot::GetActSpellCasttime(uint16 spell_id, int32 casttime) { int32 cast_reducer = 0; - cast_reducer += GetBotFocusEffect(BotfocusSpellHaste, spell_id); + cast_reducer += GetBotFocusEffect(focusSpellHaste, spell_id); uint8 botlevel = GetLevel(); uint8 botclass = GetClass(); if (botlevel >= 51 && casttime >= 3000 && !BeneficialSpell(spell_id) && (botclass == SHADOWKNIGHT || botclass == RANGER || botclass == PALADIN || botclass == BEASTLORD )) @@ -7088,7 +7088,7 @@ int32 Bot::GetActSpellCost(uint16 spell_id, int32 cost) { } } - int32 focus_redux = GetBotFocusEffect(BotfocusManaCost, spell_id); + int32 focus_redux = GetBotFocusEffect(focusManaCost, spell_id); if(focus_redux > 0) PercentManaReduction += zone->random.Real(1, (double)focus_redux); @@ -7115,14 +7115,14 @@ int32 Bot::GetActSpellCost(uint16 spell_id, int32 cost) { float Bot::GetActSpellRange(uint16 spell_id, float range) { float extrange = 100; - extrange += GetBotFocusEffect(BotfocusRange, spell_id); + extrange += GetBotFocusEffect(focusRange, spell_id); return ((range * extrange) / 100); } int32 Bot::GetActSpellDuration(uint16 spell_id, int32 duration) { int increase = 100; - increase += GetBotFocusEffect(BotfocusSpellDuration, spell_id); - int tic_inc = 0; tic_inc = GetBotFocusEffect(BotfocusSpellDurByTic, spell_id); + increase += GetBotFocusEffect(focusSpellDuration, spell_id); + int tic_inc = 0; tic_inc = GetBotFocusEffect(focusSpellDurByTic, spell_id); if(IsBeneficialSpell(spell_id)) { switch (GetAA(aaSpellCastingReinforcement)) { diff --git a/zone/bot.h b/zone/bot.h index 97bb6892c..b456fd77f 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -99,40 +99,6 @@ class Bot : public NPC { friend class Mob; public: // Class enums - enum BotfocusType { //focus types - BotfocusSpellHaste = 1, - BotfocusSpellDuration, - BotfocusRange, - BotfocusReagentCost, - BotfocusManaCost, - BotfocusImprovedHeal, - BotfocusImprovedDamage, - BotfocusImprovedDOT, //i dont know about this... - BotfocusFcDamagePctCrit, - BotfocusImprovedUndeadDamage, - BotfocusPetPower, - BotfocusResistRate, - BotfocusSpellHateMod, - BotfocusTriggerOnCast, - BotfocusSpellVulnerability, - BotfocusTwincast, - BotfocusSympatheticProc, - BotfocusFcDamageAmt, - BotfocusFcDamageAmtCrit, - BotfocusSpellDurByTic, - BotfocusSwarmPetDuration, - BotfocusReduceRecastTime, - BotfocusBlockNextSpell, - BotfocusFcHealPctIncoming, - BotfocusFcDamageAmtIncoming, - BotfocusFcHealAmtIncoming, - BotfocusFcBaseEffects, - BotfocusIncreaseNumHits, - BotfocusFcHealPctCritIncoming, - BotfocusFcHealAmt, - BotfocusFcHealAmtCrit, - }; - enum BotTradeType { // types of trades a bot can do BotTradeClientNormal, BotTradeClientNoDropNoTrade @@ -636,9 +602,9 @@ protected: virtual void PetAIProcess(); virtual void BotMeditate(bool isSitting); virtual bool CheckBotDoubleAttack(bool Triple = false); - virtual int32 GetBotFocusEffect(BotfocusType bottype, uint16 spell_id); - virtual int32 CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spell_id, bool best_focus=false); - virtual int32 CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint32 points, uint16 spell_id); + virtual int32 GetBotFocusEffect(focusType bottype, uint16 spell_id); + virtual int32 CalcBotFocusEffect(focusType bottype, uint16 focus_id, uint16 spell_id, bool best_focus=false); + virtual int32 CalcBotAAFocus(focusType type, uint32 aa_ID, uint32 points, uint16 spell_id); virtual void PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* client); virtual bool AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0); diff --git a/zone/pets.cpp b/zone/pets.cpp index 438509b77..b4897940a 100644 --- a/zone/pets.cpp +++ b/zone/pets.cpp @@ -199,7 +199,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower, } #ifdef BOTS else if (this->IsBot()) - act_power = CastToBot()->GetBotFocusEffect(Bot::BotfocusPetPower, spell_id); + act_power = CastToBot()->GetBotFocusEffect(focusPetPower, spell_id); #endif } else if (petpower > 0) From 607379110bdae825821a7b5acee8d2cebfc87c5f Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 16 Jan 2020 16:00:38 -0500 Subject: [PATCH 19/57] Add some focus effects bots were missing --- zone/bot.cpp | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index ccb3e99df..5579b4bc5 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -5388,6 +5388,10 @@ int32 Bot::CalcBotAAFocus(focusType type, uint32 aa_ID, uint32 points, uint16 sp if (type == focusImprovedDamage && base1 > value) value = base1; break; + case SE_ImprovedDamage2: + if (type == focusImprovedDamage2 && base1 > value) + value = base1; + break; case SE_ImprovedHeal: if (type == focusImprovedHeal && base1 > value) value = base1; @@ -5499,6 +5503,11 @@ int32 Bot::CalcBotAAFocus(focusType type, uint32 aa_ID, uint32 points, uint16 sp value = base1; break; } + case SE_FcDamageAmt2: { + if(type == focusFcDamageAmt2) + value = base1; + break; + } case SE_FcDamageAmtCrit: { if(type == focusFcDamageAmtCrit) value = base1; @@ -5567,7 +5576,7 @@ int32 Bot::GetBotFocusEffect(focusType bottype, uint16 spell_id) { bool rand_effectiveness = false; //Improved Healing, Damage & Mana Reduction are handled differently in that some are random percentages //In these cases we need to find the most powerful effect, so that each piece of gear wont get its own chance - if((bottype == focusManaCost || bottype == focusImprovedHeal || bottype == focusImprovedDamage) && RuleB(Spells, LiveLikeFocusEffects)) + if(RuleB(Spells, LiveLikeFocusEffects) && (bottype == focusManaCost || bottype == focusImprovedHeal || bottype == focusImprovedDamage || bottype == focusImprovedDamage2 || bottype == focusResistRate)) rand_effectiveness = true; //Check if item focus effect exists for the client. @@ -5860,6 +5869,20 @@ int32 Bot::CalcBotFocusEffect(focusType bottype, uint16 focus_id, uint16 spell_i value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); } break; + case SE_ImprovedDamage2: + if (bottype == focusImprovedDamage2) { + if(best_focus) { + if (focus_spell.base2[i] != 0) + value = focus_spell.base2[i]; + else + value = focus_spell.base[i]; + } + else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) + value = focus_spell.base[i]; + else + value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); + } + break; case SE_ImprovedHeal: if (bottype == focusImprovedHeal) { if(best_focus) { @@ -5981,6 +6004,11 @@ int32 Bot::CalcBotFocusEffect(focusType bottype, uint16 focus_id, uint16 spell_i value = focus_spell.base[i]; break; } + case SE_FcDamageAmt2: { + if(bottype == focusFcDamageAmt2) + value = focus_spell.base[i]; + break; + } case SE_FcDamageAmtCrit: { if(bottype == focusFcDamageAmtCrit) value = focus_spell.base[i]; @@ -6869,6 +6897,7 @@ int32 Bot::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { if (Critical) { value = (value_BaseEffect * ratio / 100); value += (value_BaseEffect * GetBotFocusEffect(focusImprovedDamage, spell_id) / 100); + value += (value_BaseEffect * GetBotFocusEffect(focusImprovedDamage2, spell_id) / 100); value += (int(value_BaseEffect * GetBotFocusEffect(focusFcDamagePctCrit, spell_id) / 100) * ratio / 100); if (target) { value += (int(value_BaseEffect * target->GetVulnerability(this, spell_id, 0) / 100) * ratio / 100); @@ -6878,6 +6907,7 @@ int32 Bot::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { value -= (GetBotFocusEffect(focusFcDamageAmtCrit, spell_id) * ratio / 100); value -= GetBotFocusEffect(focusFcDamageAmt, spell_id); + value -= GetBotFocusEffect(focusFcDamageAmt2, spell_id); if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) value += (GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value) * ratio / 100); @@ -6890,6 +6920,7 @@ int32 Bot::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { value = value_BaseEffect; value += (value_BaseEffect * GetBotFocusEffect(focusImprovedDamage, spell_id) / 100); + value += (value_BaseEffect * GetBotFocusEffect(focusImprovedDamage2, spell_id) / 100); value += (value_BaseEffect * GetBotFocusEffect(focusFcDamagePctCrit, spell_id) / 100); if (target) { value += (value_BaseEffect * target->GetVulnerability(this, spell_id, 0) / 100); @@ -6898,6 +6929,7 @@ int32 Bot::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { value -= GetBotFocusEffect(focusFcDamageAmtCrit, spell_id); value -= GetBotFocusEffect(focusFcDamageAmt, spell_id); + value -= GetBotFocusEffect(focusFcDamageAmt2, spell_id); if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) value += GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value); From 099da513ff2b41ea97cb1563a5c8fb56db9d7d7e Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 16 Jan 2020 16:18:08 -0500 Subject: [PATCH 20/57] Remove some unused misc.cpp functions (encode/decode) These were unused and throwing warnings, so throw them away! --- common/misc.cpp | 61 ------------------------------------------------- common/misc.h | 7 ------ 2 files changed, 68 deletions(-) diff --git a/common/misc.cpp b/common/misc.cpp index 792dfcbab..b9dc31d28 100644 --- a/common/misc.cpp +++ b/common/misc.cpp @@ -19,9 +19,6 @@ #include "types.h" #include -#define ENC(c) (((c) & 0x3f) + ' ') -#define DEC(c) (((c) - ' ') & 0x3f) - std::map DBFieldNames; #ifndef WIN32 @@ -333,64 +330,6 @@ void LoadItemDBFieldNames() { DBFieldNames[113]="unknown115"; // ? (end quote) } -void encode_length(unsigned long length, char *out) -{ -char buf[4]; - memcpy(buf,&length,sizeof(unsigned long)); - encode_chunk(buf,3,out); -} - -unsigned long encode(char *in, unsigned long length, char *out) -{ -unsigned long used=0,len=0; - while(used> 2); - *(out+1)=ENC((in[0] << 4)|(((len<2 ? 0 : in[1]) >> 4) & 0xF)); - *(out+2)=ENC(((len<2 ? 0 : in[1]) << 2)|(((len<3 ? 0 : in[2]) >> 6) & 0x3)); - *(out+3)=ENC((len<3 ? 0 : in[2])); -} - -void decode_chunk(char *in, char *out) -{ - *out = DEC(*in) << 2 | DEC(in[1]) >> 4; - *(out+1) = DEC(in[1]) << 4 | DEC(in[2]) >> 2; - *(out+2) = DEC(in[2]) << 6 | DEC(in[3]); -} - void dump_message_column(unsigned char *buffer, unsigned long length, std::string leader, FILE *to) { unsigned long i,j; diff --git a/common/misc.h b/common/misc.h index b33f2f32d..a099ab823 100644 --- a/common/misc.h +++ b/common/misc.h @@ -17,13 +17,6 @@ int Tokenize(std::string s, std::map & tokens, char delim='|'); void LoadItemDBFieldNames(); -void encode_length(unsigned long length, char *out); -unsigned long decode_length(char *in); -unsigned long encode(char *in, unsigned long length, char *out); -void decode(char *in, char *out); -void encode_chunk(char *in, int len, char *out); -void decode_chunk(char *in, char *out); - #ifndef WIN32 int print_stacktrace(); #endif From a307747c2954dc2e0509e40664c80206e24781c4 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 16 Jan 2020 16:51:24 -0500 Subject: [PATCH 21/57] Nuke unused command_itemtest --- zone/command.cpp | 19 ------------------- zone/command.h | 1 - 2 files changed, 20 deletions(-) diff --git a/zone/command.cpp b/zone/command.cpp index e3f884481..877529c2b 100755 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -2173,25 +2173,6 @@ void command_spoff(Client *c, const Seperator *sep) safe_delete(outapp); } -void command_itemtest(Client *c, const Seperator *sep) -{ - char chBuffer[8192] = {0}; - //Using this to determine new item layout - FILE* f = nullptr; - if (!(f = fopen("c:\\EQEMUcvs\\ItemDump.txt", "rb"))) { - c->Message(Chat::Red, "Error: Could not open c:\\EQEMUcvs\\ItemDump.txt"); - return; - } - - fread(chBuffer, sizeof(chBuffer), sizeof(char), f); - fclose(f); - - auto outapp = new EQApplicationPacket(OP_ItemLinkResponse, strlen(chBuffer) + 5); - memcpy(&outapp->pBuffer[4], chBuffer, strlen(chBuffer)); - c->QueuePacket(outapp); - safe_delete(outapp); -} - void command_gassign(Client *c, const Seperator *sep) { if (sep->IsNumber(1) && c->GetTarget() && c->GetTarget()->IsNPC() && c->GetTarget()->CastToNPC()->GetSpawnPointID() > 0) { diff --git a/zone/command.h b/zone/command.h index 1c9d8fe7c..d64950f9c 100644 --- a/zone/command.h +++ b/zone/command.h @@ -150,7 +150,6 @@ void command_ipc(Client *c, const Seperator *sep); void command_iplookup(Client *c, const Seperator *sep); void command_iteminfo(Client *c, const Seperator *sep); void command_itemsearch(Client *c, const Seperator *sep); -void command_itemtest(Client *c, const Seperator *sep); void command_kick(Client *c, const Seperator *sep); void command_killallnpcs(Client *c, const Seperator *sep); void command_kill(Client *c, const Seperator *sep); From 945ca1278c202172b930f35e7c15a8ee4093d414 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 16 Jan 2020 17:02:35 -0500 Subject: [PATCH 22/57] Remove some unnecessary this == null checks --- common/servertalk.h | 3 --- zone/mob.h | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/common/servertalk.h b/common/servertalk.h index 3aef636ca..b9cb6202e 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -262,9 +262,6 @@ public: } ServerPacket* Copy() { - if (this == 0) { - return 0; - } ServerPacket* ret = new ServerPacket(this->opcode, this->size); if (this->size) memcpy(ret->pBuffer, this->pBuffer, this->size); diff --git a/zone/mob.h b/zone/mob.h index f0fc79548..d48f47e6d 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -624,8 +624,7 @@ public: //AI static uint32 GetLevelCon(uint8 mylevel, uint8 iOtherLevel); - inline uint32 GetLevelCon(uint8 iOtherLevel) const { - return this ? GetLevelCon(GetLevel(), iOtherLevel) : CON_GRAY; } + inline uint32 GetLevelCon(uint8 iOtherLevel) const { return GetLevelCon(GetLevel(), iOtherLevel); } virtual void AddToHateList(Mob* other, uint32 hate = 0, int32 damage = 0, bool iYellForHelp = true, bool bFrenzy = false, bool iBuffTic = false, uint16 spell_id = SPELL_UNKNOWN, bool pet_comand = false); bool RemoveFromHateList(Mob* mob); From e6a14beb2e9bf33aa93c0cfa01cef29e8868e295 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 16 Jan 2020 17:06:11 -0500 Subject: [PATCH 23/57] Remove another unnecessary this == null check --- common/ptimer.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/common/ptimer.cpp b/common/ptimer.cpp index 032ac5945..e6338bdf9 100644 --- a/common/ptimer.cpp +++ b/common/ptimer.cpp @@ -190,10 +190,6 @@ bool PersistentTimer::Clear(Database *db) { /* This function checks if the timer triggered */ bool PersistentTimer::Expired(Database *db, bool iReset) { - if (this == nullptr) { - LogError("Null timer during ->Check()!?\n"); - return(true); - } uint32 current_time = get_current_time(); if (current_time-start_time >= timer_time) { if (enabled && iReset) { From e4c4e5edb2238d3a74e09364f422bae9faf77903 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 16 Jan 2020 17:17:31 -0500 Subject: [PATCH 24/57] References shouldn't be null --- common/linked_list.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/common/linked_list.h b/common/linked_list.h index 246677db4..8ac4b51d8 100644 --- a/common/linked_list.h +++ b/common/linked_list.h @@ -278,12 +278,6 @@ void LinkedListIterator::Replace(const TYPE& new_data) template void LinkedListIterator::Reset() { - if (!(&list)) - { - current_element=0; - return; - } - if (dir == FORWARD) { current_element = list.first; From 14402c9c4103d3a9308ef72405015cb4bbd89b75 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 16 Jan 2020 17:44:46 -0500 Subject: [PATCH 25/57] Fix unreachable switch statements in console_server_connection.cpp --- common/net/console_server_connection.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/common/net/console_server_connection.cpp b/common/net/console_server_connection.cpp index 795c73140..aab26d188 100644 --- a/common/net/console_server_connection.cpp +++ b/common/net/console_server_connection.cpp @@ -116,17 +116,21 @@ bool EQ::Net::ConsoleServerConnection::SendChannelMessage(const ServerChannelMes } switch (scm->chan_num) { - if (RuleB(Chat, ServerWideAuction)) { - case 4: { + case 4: { + if (RuleB(Chat, ServerWideAuction)) { QueueMessage(fmt::format("{0} auctions, '{1}'", scm->from, scm->message)); break; + } else { // I think we want default action in this case? + return false; } } - if (RuleB(Chat, ServerWideOOC)) { - case 5: { + case 5: { + if (RuleB(Chat, ServerWideOOC)) { QueueMessage(fmt::format("{0} says ooc, '{1}'", scm->from, scm->message)); break; + } else { // I think we want default action in this case? + return false; } } From baf4cc62eb2e8f081e2a4b7cba479dcd623ed580 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 16 Jan 2020 18:04:20 -0500 Subject: [PATCH 26/57] Fix format truncation in RoF2 OP_Trader --- common/patches/rof2.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 11bb99af7..36257771b 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -37,6 +37,7 @@ #include #include #include +#include namespace RoF2 @@ -3548,7 +3549,7 @@ namespace RoF2 { eq->items[i].Unknown18 = 0; if (i < 80) { - snprintf(eq->items[i].SerialNumber, sizeof(eq->items[i].SerialNumber), "%016d", emu->SerialNumber[i]); + snprintf(eq->items[i].SerialNumber, sizeof(eq->items[i].SerialNumber), "%016" PRId64, emu->SerialNumber[i]); eq->ItemCost[i] = emu->ItemCost[i]; } else { From 139b6c34e512904b082f45cc52de3518750a2949 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 16 Jan 2020 19:03:36 -0500 Subject: [PATCH 27/57] Change things -Wcatch-value complains about to references --- common/eqemu_config.h | 2 +- common/json_config.cpp | 10 +++--- common/net/websocket_server.cpp | 10 +++--- world/web_interface.cpp | 12 +++---- zone/lua_client.cpp | 14 ++++----- zone/lua_general.cpp | 38 +++++++++++----------- zone/lua_mob.cpp | 56 ++++++++++++++++----------------- 7 files changed, 71 insertions(+), 71 deletions(-) diff --git a/common/eqemu_config.h b/common/eqemu_config.h index e75737d76..a4fb7797f 100644 --- a/common/eqemu_config.h +++ b/common/eqemu_config.h @@ -165,7 +165,7 @@ class EQEmuConfig fconfig >> _config->_root; _config->parse_config(); } - catch (std::exception) { + catch (std::exception &) { return false; } return true; diff --git a/common/json_config.cpp b/common/json_config.cpp index d262038f6..5f4c47b71 100644 --- a/common/json_config.cpp +++ b/common/json_config.cpp @@ -32,7 +32,7 @@ EQ::JsonConfigFile EQ::JsonConfigFile::Load( try { ifs >> ret.m_root; } - catch (std::exception) { + catch (std::exception &) { return ret; } @@ -81,7 +81,7 @@ std::string EQ::JsonConfigFile::GetVariableString( return m_root[title][parameter].asString(); } } - catch (std::exception) { + catch (std::exception &) { return default_value; } @@ -105,7 +105,7 @@ int EQ::JsonConfigFile::GetVariableInt( return m_root[title][parameter].asInt(); } } - catch (std::exception) { + catch (std::exception &) { return default_value; } @@ -129,7 +129,7 @@ bool EQ::JsonConfigFile::GetVariableBool( return m_root[title][parameter].asBool(); } } - catch (std::exception) { + catch (std::exception &) { return default_value; } @@ -153,7 +153,7 @@ double EQ::JsonConfigFile::GetVariableDouble( return m_root[title][parameter].asDouble(); } } - catch (std::exception) { + catch (std::exception &) { return default_value; } diff --git a/common/net/websocket_server.cpp b/common/net/websocket_server.cpp index de1a0cf99..b46fc7953 100644 --- a/common/net/websocket_server.cpp +++ b/common/net/websocket_server.cpp @@ -61,7 +61,7 @@ EQ::Net::WebsocketServer::WebsocketServer(const std::string &addr, int port) auto &connection = iter->second; connection->GetWebsocketConnection()->ping("keepalive"); } - catch (std::exception) { + catch (std::exception &) { iter->second->GetTCPConnection()->Disconnect(); } @@ -157,7 +157,7 @@ void EQ::Net::WebsocketServer::DispatchEvent(WebsocketSubscriptionEvent evt, Jso } } } - catch (std::exception) { + catch (std::exception &) { } } @@ -190,7 +190,7 @@ Json::Value EQ::Net::WebsocketServer::Login(WebsocketServerConnection *connectio return ret; } - catch (std::exception) { + catch (std::exception &) { throw WebsocketException("Unable to process login request"); } } @@ -212,7 +212,7 @@ Json::Value EQ::Net::WebsocketServer::Subscribe(WebsocketServerConnection *conne catch (WebsocketException &ex) { throw ex; } - catch (std::exception) { + catch (std::exception &) { throw WebsocketException("Unable to process unsubscribe request"); } } @@ -234,7 +234,7 @@ Json::Value EQ::Net::WebsocketServer::Unsubscribe(WebsocketServerConnection *con catch (WebsocketException &ex) { throw ex; } - catch (std::exception) { + catch (std::exception &) { throw WebsocketException("Unable to process unsubscribe request"); } } diff --git a/world/web_interface.cpp b/world/web_interface.cpp index 191d8cca1..773e955b6 100644 --- a/world/web_interface.cpp +++ b/world/web_interface.cpp @@ -24,7 +24,7 @@ void WebInterface::OnCall(uint16 opcode, EQ::Net::Packet &p) std::stringstream ss(json_str); ss >> root; } - catch (std::exception) { + catch (std::exception &) { SendError("Could not parse request"); return; } @@ -40,7 +40,7 @@ void WebInterface::OnCall(uint16 opcode, EQ::Net::Packet &p) return; } } - catch (std::exception) { + catch (std::exception &) { SendError("Invalid request: method not supplied"); return; } @@ -49,7 +49,7 @@ void WebInterface::OnCall(uint16 opcode, EQ::Net::Packet &p) try { params = root["params"]; } - catch (std::exception) { + catch (std::exception &) { params = nullptr; } @@ -57,7 +57,7 @@ void WebInterface::OnCall(uint16 opcode, EQ::Net::Packet &p) try { id = root["id"].asString(); } - catch (std::exception) { + catch (std::exception &) { id = ""; } @@ -82,7 +82,7 @@ void WebInterface::Send(const Json::Value &value) p.PutString(0, ss.str()); m_connection->Send(ServerOP_WebInterfaceCall, p); } - catch (std::exception) { + catch (std::exception &) { //Log error } } @@ -116,7 +116,7 @@ void WebInterface::SendEvent(const Json::Value &value) p.PutString(0, ss.str()); m_connection->Send(ServerOP_WebInterfaceEvent, p); } - catch (std::exception) { + catch (std::exception &) { //Log error } } diff --git a/zone/lua_client.cpp b/zone/lua_client.cpp index 64ce0cafa..14c009b12 100644 --- a/zone/lua_client.cpp +++ b/zone/lua_client.cpp @@ -1397,7 +1397,7 @@ void Lua_Client::QuestReward(Lua_Mob target, luabind::adl::object reward) { if (luabind::type(cur) != LUA_TNIL) { try { copper = luabind::object_cast(cur); - } catch (luabind::cast_failed) { + } catch (luabind::cast_failed &) { } } @@ -1405,7 +1405,7 @@ void Lua_Client::QuestReward(Lua_Mob target, luabind::adl::object reward) { if (luabind::type(cur) != LUA_TNIL) { try { silver = luabind::object_cast(cur); - } catch (luabind::cast_failed) { + } catch (luabind::cast_failed &) { } } @@ -1413,7 +1413,7 @@ void Lua_Client::QuestReward(Lua_Mob target, luabind::adl::object reward) { if (luabind::type(cur) != LUA_TNIL) { try { gold = luabind::object_cast(cur); - } catch (luabind::cast_failed) { + } catch (luabind::cast_failed &) { } } @@ -1421,7 +1421,7 @@ void Lua_Client::QuestReward(Lua_Mob target, luabind::adl::object reward) { if (luabind::type(cur) != LUA_TNIL) { try { platinum = luabind::object_cast(cur); - } catch (luabind::cast_failed) { + } catch (luabind::cast_failed &) { } } @@ -1429,7 +1429,7 @@ void Lua_Client::QuestReward(Lua_Mob target, luabind::adl::object reward) { if (luabind::type(cur) != LUA_TNIL) { try { itemid = luabind::object_cast(cur); - } catch (luabind::cast_failed) { + } catch (luabind::cast_failed &) { } } @@ -1437,7 +1437,7 @@ void Lua_Client::QuestReward(Lua_Mob target, luabind::adl::object reward) { if (luabind::type(cur) != LUA_TNIL) { try { exp = luabind::object_cast(cur); - } catch (luabind::cast_failed) { + } catch (luabind::cast_failed &) { } } @@ -1445,7 +1445,7 @@ void Lua_Client::QuestReward(Lua_Mob target, luabind::adl::object reward) { if (luabind::type(cur) != LUA_TNIL) { try { faction = luabind::object_cast(cur); - } catch (luabind::cast_failed) { + } catch (luabind::cast_failed &) { } } diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index 7f714fd6b..ff0c6b10a 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -571,7 +571,7 @@ void lua_task_selector(luabind::adl::object table) { if(luabind::type(cur) != LUA_TNIL) { try { cur_value = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } else { count = i - 1; @@ -601,7 +601,7 @@ void lua_enable_task(luabind::adl::object table) { if(luabind::type(cur) != LUA_TNIL) { try { cur_value = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } else { count = i - 1; @@ -628,7 +628,7 @@ void lua_disable_task(luabind::adl::object table) { if(luabind::type(cur) != LUA_TNIL) { try { cur_value = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } else { count = i - 1; @@ -1156,7 +1156,7 @@ void lua_add_spawn_point(luabind::adl::object table) { if(luabind::type(cur) != LUA_TNIL) { try { spawn2_id = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { return; } } else { @@ -1167,7 +1167,7 @@ void lua_add_spawn_point(luabind::adl::object table) { if(luabind::type(cur) != LUA_TNIL) { try { spawngroup_id = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { return; } } else { @@ -1178,7 +1178,7 @@ void lua_add_spawn_point(luabind::adl::object table) { if(luabind::type(cur) != LUA_TNIL) { try { x = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { return; } } else { @@ -1189,7 +1189,7 @@ void lua_add_spawn_point(luabind::adl::object table) { if(luabind::type(cur) != LUA_TNIL) { try { y = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { return; } } else { @@ -1200,7 +1200,7 @@ void lua_add_spawn_point(luabind::adl::object table) { if(luabind::type(cur) != LUA_TNIL) { try { z = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { return; } } else { @@ -1211,7 +1211,7 @@ void lua_add_spawn_point(luabind::adl::object table) { if(luabind::type(cur) != LUA_TNIL) { try { heading = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { return; } } else { @@ -1222,7 +1222,7 @@ void lua_add_spawn_point(luabind::adl::object table) { if(luabind::type(cur) != LUA_TNIL) { try { respawn = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { return; } } else { @@ -1233,7 +1233,7 @@ void lua_add_spawn_point(luabind::adl::object table) { if(luabind::type(cur) != LUA_TNIL) { try { variance = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { return; } } else { @@ -1244,7 +1244,7 @@ void lua_add_spawn_point(luabind::adl::object table) { if(luabind::type(cur) != LUA_TNIL) { try { timeleft = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -1252,7 +1252,7 @@ void lua_add_spawn_point(luabind::adl::object table) { if(luabind::type(cur) != LUA_TNIL) { try { grid = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -1260,7 +1260,7 @@ void lua_add_spawn_point(luabind::adl::object table) { if(luabind::type(cur) != LUA_TNIL) { try { condition_id = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -1268,7 +1268,7 @@ void lua_add_spawn_point(luabind::adl::object table) { if(luabind::type(cur) != LUA_TNIL) { try { condition_min_value = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -1276,7 +1276,7 @@ void lua_add_spawn_point(luabind::adl::object table) { if(luabind::type(cur) != LUA_TNIL) { try { enabled = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -1284,7 +1284,7 @@ void lua_add_spawn_point(luabind::adl::object table) { if(luabind::type(cur) != LUA_TNIL) { try { animation = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -1399,7 +1399,7 @@ void lua_update_zone_header(std::string type, std::string value) { try { \ npc_type->name = luabind::object_cast(cur); \ } \ - catch(luabind::cast_failed) { \ + catch(luabind::cast_failed &) { \ npc_type->size = default_value; \ } \ } \ @@ -1415,7 +1415,7 @@ void lua_update_zone_header(std::string type, std::string value) { std::string tmp = luabind::object_cast(cur); \ strncpy(npc_type->name, tmp.c_str(), str_length); \ } \ - catch(luabind::cast_failed) { \ + catch(luabind::cast_failed &) { \ strncpy(npc_type->name, default_value, str_length); \ } \ } \ diff --git a/zone/lua_mob.cpp b/zone/lua_mob.cpp index 7d769b8dd..4860ae1e8 100644 --- a/zone/lua_mob.cpp +++ b/zone/lua_mob.cpp @@ -113,7 +113,7 @@ bool Lua_Mob::Attack(Lua_Mob other, int hand, bool from_riposte, bool is_striket if(luabind::type(cur) != LUA_TNIL) { try { options.armor_pen_flat = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -121,7 +121,7 @@ bool Lua_Mob::Attack(Lua_Mob other, int hand, bool from_riposte, bool is_striket if(luabind::type(cur) != LUA_TNIL) { try { options.crit_flat = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -129,7 +129,7 @@ bool Lua_Mob::Attack(Lua_Mob other, int hand, bool from_riposte, bool is_striket if(luabind::type(cur) != LUA_TNIL) { try { options.damage_flat = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -137,7 +137,7 @@ bool Lua_Mob::Attack(Lua_Mob other, int hand, bool from_riposte, bool is_striket if(luabind::type(cur) != LUA_TNIL) { try { options.hate_flat = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -145,7 +145,7 @@ bool Lua_Mob::Attack(Lua_Mob other, int hand, bool from_riposte, bool is_striket if(luabind::type(cur) != LUA_TNIL) { try { options.armor_pen_percent = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -153,7 +153,7 @@ bool Lua_Mob::Attack(Lua_Mob other, int hand, bool from_riposte, bool is_striket if(luabind::type(cur) != LUA_TNIL) { try { options.crit_percent = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -161,7 +161,7 @@ bool Lua_Mob::Attack(Lua_Mob other, int hand, bool from_riposte, bool is_striket if(luabind::type(cur) != LUA_TNIL) { try { options.damage_percent = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -169,7 +169,7 @@ bool Lua_Mob::Attack(Lua_Mob other, int hand, bool from_riposte, bool is_striket if(luabind::type(cur) != LUA_TNIL) { try { options.hate_percent = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } } @@ -785,7 +785,7 @@ void Lua_Mob::QuestSay(Lua_Client client, const char *message, luabind::adl::obj if (luabind::type(cur) != LUA_TNIL) { try { journal_opts.speak_mode = static_cast(luabind::object_cast(cur)); - } catch (luabind::cast_failed) { + } catch (luabind::cast_failed &) { } } @@ -793,7 +793,7 @@ void Lua_Mob::QuestSay(Lua_Client client, const char *message, luabind::adl::obj if (luabind::type(cur) != LUA_TNIL) { try { journal_opts.journal_mode = static_cast(luabind::object_cast(cur)); - } catch (luabind::cast_failed) { + } catch (luabind::cast_failed &) { } } @@ -801,7 +801,7 @@ void Lua_Mob::QuestSay(Lua_Client client, const char *message, luabind::adl::obj if (luabind::type(cur) != LUA_TNIL) { try { journal_opts.language = luabind::object_cast(cur); - } catch (luabind::cast_failed) { + } catch (luabind::cast_failed &) { } } @@ -809,7 +809,7 @@ void Lua_Mob::QuestSay(Lua_Client client, const char *message, luabind::adl::obj if (luabind::type(cur) != LUA_TNIL) { try { journal_opts.message_type = luabind::object_cast(cur); - } catch (luabind::cast_failed) { + } catch (luabind::cast_failed &) { } } } @@ -1568,7 +1568,7 @@ void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) { if(luabind::type(cur) != LUA_TNIL) { try { race = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -1576,7 +1576,7 @@ void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) { if(luabind::type(cur) != LUA_TNIL) { try { gender = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -1584,7 +1584,7 @@ void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) { if(luabind::type(cur) != LUA_TNIL) { try { texture = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -1592,7 +1592,7 @@ void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) { if(luabind::type(cur) != LUA_TNIL) { try { helmtexture = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -1600,7 +1600,7 @@ void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) { if(luabind::type(cur) != LUA_TNIL) { try { haircolor = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -1608,7 +1608,7 @@ void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) { if(luabind::type(cur) != LUA_TNIL) { try { beardcolor = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -1616,7 +1616,7 @@ void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) { if(luabind::type(cur) != LUA_TNIL) { try { eyecolor1 = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -1624,7 +1624,7 @@ void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) { if(luabind::type(cur) != LUA_TNIL) { try { eyecolor2 = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -1632,7 +1632,7 @@ void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) { if(luabind::type(cur) != LUA_TNIL) { try { hairstyle = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -1640,7 +1640,7 @@ void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) { if(luabind::type(cur) != LUA_TNIL) { try { luclinface = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -1648,7 +1648,7 @@ void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) { if(luabind::type(cur) != LUA_TNIL) { try { beard = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -1656,7 +1656,7 @@ void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) { if(luabind::type(cur) != LUA_TNIL) { try { aa_title = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -1664,7 +1664,7 @@ void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) { if(luabind::type(cur) != LUA_TNIL) { try { drakkin_heritage = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -1672,7 +1672,7 @@ void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) { if(luabind::type(cur) != LUA_TNIL) { try { drakkin_tattoo = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -1680,7 +1680,7 @@ void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) { if(luabind::type(cur) != LUA_TNIL) { try { drakkin_details = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } @@ -1688,7 +1688,7 @@ void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) { if(luabind::type(cur) != LUA_TNIL) { try { size = luabind::object_cast(cur); - } catch(luabind::cast_failed) { + } catch(luabind::cast_failed &) { } } From 4241fba7e2217dc802ba72f6991622fdb6e73266 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 16 Jan 2020 19:10:04 -0500 Subject: [PATCH 28/57] Forgot 2 exceptions --- common/net/daybreak_connection.cpp | 2 +- common/string_util.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/net/daybreak_connection.cpp b/common/net/daybreak_connection.cpp index b10203854..8448049f5 100644 --- a/common/net/daybreak_connection.cpp +++ b/common/net/daybreak_connection.cpp @@ -399,7 +399,7 @@ void EQ::Net::DaybreakConnection::Process() ProcessQueue(); } - catch (std::exception ex) { + catch (std::exception &ex) { if (m_owner->m_on_error_message) { m_owner->m_on_error_message(fmt::format("Error processing connection: {0}", ex.what())); } diff --git a/common/string_util.cpp b/common/string_util.cpp index b48bee1b3..df3790def 100644 --- a/common/string_util.cpp +++ b/common/string_util.cpp @@ -222,7 +222,7 @@ bool StringIsNumber(const std::string &s) { auto r = stod(s); return true; } - catch (std::exception) { + catch (std::exception &) { return false; } } From e1408ede6b871dcdc80461b5760d1467bddcd445 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 16 Jan 2020 19:22:17 -0500 Subject: [PATCH 29/57] Remove AdventureManager::Load since it doesn't do anything --- world/adventure_manager.cpp | 99 ------------------------------------- world/adventure_manager.h | 1 - world/main.cpp | 1 - 3 files changed, 101 deletions(-) diff --git a/world/adventure_manager.cpp b/world/adventure_manager.cpp index 65e264a19..c3e70b7ed 100644 --- a/world/adventure_manager.cpp +++ b/world/adventure_manager.cpp @@ -2119,102 +2119,3 @@ void AdventureManager::Save() } } -void AdventureManager::Load() -{ - //disabled for now - return; - - char *data = nullptr; - FILE *f = fopen("adventure_state.dat", "r"); - if(f) - { - fseek(f, 0, SEEK_END); - long length = ftell(f); - if(length > 0) - { - data = new char[length]; - fseek(f, 0, SEEK_SET); - fread(data, length, 1, f); - } - fclose(f); - } - - if(data) - { - char *ptr = data; - - int number_of_adventures = *((int*)ptr); - ptr += sizeof(int); - - for(int i = 0; i < number_of_adventures; ++i) - { - int count = *((int*)ptr); - ptr += sizeof(int); - - int a_count = *((int*)ptr); - ptr += sizeof(int); - - int template_id = *((int*)ptr); - ptr += sizeof(int); - - int status = *((int*)ptr); - ptr += sizeof(int); - - int instance_id = *((int*)ptr); - ptr += sizeof(int); - - int rem_time = *((int*)ptr); - ptr += sizeof(int); - - int num_players = *((int*)ptr); - ptr += sizeof(int); - - AdventureTemplate *t = GetAdventureTemplate(template_id); - if(t) - { - auto adv = - new Adventure(t, count, a_count, (AdventureStatus)status, instance_id, rem_time); - for(int j = 0; j < num_players; ++j) - { - adv->AddPlayer((const char*)ptr, false); - ptr += strlen((const char*)ptr); - ptr += 1; - } - adventure_list.push_back(adv); - } - else - { - for(int j = 0; j < num_players; ++j) - { - ptr += strlen((const char*)ptr); - ptr += 1; - } - } - } - - int number_of_finished = *((int*)ptr); - ptr += sizeof(int); - - for(int k = 0; k < number_of_finished; ++k) - { - AdventureFinishEvent afe; - afe.win = *((bool*)ptr); - ptr += sizeof(bool); - - afe.points = *((int*)ptr); - ptr += sizeof(int); - - afe.theme = *((int*)ptr); - ptr += sizeof(int); - - afe.name = (const char*)ptr; - ptr += strlen((const char*)ptr); - ptr += 1; - - finished_list.push_back(afe); - } - - safe_delete_array(data); - } -} - diff --git a/world/adventure_manager.h b/world/adventure_manager.h index 5c9a4e560..ae4bf950f 100644 --- a/world/adventure_manager.h +++ b/world/adventure_manager.h @@ -34,7 +34,6 @@ public: void AddFinishedEvent(AdventureFinishEvent fe) { finished_list.push_back(fe); Save(); } bool PopFinishedEvent(const char *name, AdventureFinishEvent &fe); void Save(); - void Load(); Adventure **GetFinishedAdventures(const char *player, int &count); Adventure *GetActiveAdventure(const char *player); diff --git a/world/main.cpp b/world/main.cpp index 0ab5f2089..72cc6d391 100644 --- a/world/main.cpp +++ b/world/main.cpp @@ -396,7 +396,6 @@ int main(int argc, char** argv) { LogInfo("Unable to load adventure templates"); } - adventure_manager.Load(); adventure_manager.LoadLeaderboardInfo(); LogInfo("Purging expired instances"); From a9ef2474d478c2c1cb5eee2332f09c4e74e5e5d9 Mon Sep 17 00:00:00 2001 From: Uleat Date: Thu, 16 Jan 2020 20:49:03 -0500 Subject: [PATCH 30/57] Updated eqemu_server.pl to use the appveyor archive when setting up bots [skip ci] --- utils/scripts/eqemu_server.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/scripts/eqemu_server.pl b/utils/scripts/eqemu_server.pl index 658f3709d..76084f23f 100755 --- a/utils/scripts/eqemu_server.pl +++ b/utils/scripts/eqemu_server.pl @@ -813,7 +813,7 @@ sub fetch_utility_scripts { sub setup_bots { if ($OS eq "Windows") { - fetch_latest_windows_binaries_bots(); + fetch_latest_windows_appveyor_bots(); } if ($OS eq "Linux") { build_linux_source("bots"); @@ -821,7 +821,7 @@ sub setup_bots { bots_db_management(); run_database_check(); - print "Bots should be setup, run your server and the #bot command should be available in-game\n"; + print "Bots should be setup, run your server and the bot command should be available in-game (type '^help')\n"; } sub show_menu_prompt { From d47bf6a73b266d06326d11952bb732422969f7f1 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Fri, 17 Jan 2020 14:35:32 -0500 Subject: [PATCH 31/57] Update waypoints.cpp Fixed log message to be correct. --- zone/waypoints.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index 10e4a11f3..b6033744c 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -159,7 +159,7 @@ void NPC::PauseWandering(int pausetime) if (GetGrid() != 0) { moving = false; DistractedFromGrid = true; - LogPathing("Paused Wandering requested. Grid [{}]. Resuming in [{}] ms (0=not until told)", GetGrid(), pausetime); + LogPathing("Paused Wandering requested. Grid [{}]. Resuming in [{}] seconds (0=not until told)", GetGrid(), pausetime); StopNavigation(); if (pausetime < 1) { // negative grid number stops him dead in his tracks until ResumeWandering() SetGrid(0 - GetGrid()); From feefd7a23b98483028183312890247252f3d55d3 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Fri, 17 Jan 2020 17:30:38 -0500 Subject: [PATCH 32/57] Update default NPC:NPCGatePercent value to something more live like --- common/ruletypes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index 3de392d45..dab1d02e1 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -519,7 +519,7 @@ RULE_INT(NPC, NPCToNPCAggroTimerMin, 500, "") RULE_INT(NPC, NPCToNPCAggroTimerMax, 6000, "") RULE_BOOL(NPC, UseClassAsLastName, true, "Uses class archetype as LastName for npcs with none") RULE_BOOL(NPC, NewLevelScaling, true, "Better level scaling, use old if new formulas would break your server") -RULE_INT(NPC, NPCGatePercent, 5, "% at which the NPC Will attempt to gate at") +RULE_INT(NPC, NPCGatePercent, 20, "% at which the NPC Will attempt to gate at") RULE_BOOL(NPC, NPCGateNearBind, false, "Will NPC attempt to gate when near bind location?") RULE_INT(NPC, NPCGateDistanceBind, 75, "Distance from bind before NPC will attempt to gate") RULE_BOOL(NPC, NPCHealOnGate, true, "Will the NPC Heal on Gate") From 43df845233613237a93247c2a6fcd8ffb5d8eecf Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sat, 18 Jan 2020 21:42:51 -0500 Subject: [PATCH 33/57] Fix issue with overflow in Mob::SendHPUpdate --- zone/mob.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/mob.cpp b/zone/mob.cpp index 94b53d1f9..af8aa25ab 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -1369,7 +1369,7 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal } } - int8 current_hp_percent = static_cast(max_hp == 0 ? 0 : static_cast(current_hp * 100 / max_hp)); + auto current_hp_percent = GetIntHPRatio(); Log(Logs::General, Logs::HPUpdate, From 8eb60302a284da606eff3f94c1ce38f47d0c5877 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Sun, 19 Jan 2020 16:03:09 -0500 Subject: [PATCH 34/57] Update attack.cpp Fix to Monk Mitigation. Divided weight by 10 to convert to stones. --- zone/attack.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zone/attack.cpp b/zone/attack.cpp index a48f4008e..911f22dfb 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -724,7 +724,7 @@ int Mob::GetClassRaceACBonus() hardcap = 32; softcap = 15; } - int weight = IsClient() ? CastToClient()->CalcCurrentWeight() : 0; + int weight = IsClient() ? CastToClient()->CalcCurrentWeight()/10 : 0; if (weight < hardcap - 1) { int temp = level + 5; if (weight > softcap) { @@ -5491,4 +5491,4 @@ int32 Mob::GetHPRegen() const int32 Mob::GetManaRegen() const { return mana_regen; -} \ No newline at end of file +} From 6f73278cf858935f58d736600e3c4c50aefe044e Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 19 Jan 2020 21:57:28 -0600 Subject: [PATCH 35/57] Fix annoying aura crash that has been around for a year and a half, add aura logging, utilize close lists --- common/eqemu_logsys.h | 2 + common/eqemu_logsys_log_aliases.h | 16 + zone/aura.cpp | 673 +++++++++++++++++++----------- zone/aura.h | 2 +- zone/entity.cpp | 18 + zone/entity.h | 2 +- zone/mob.cpp | 2 + 7 files changed, 471 insertions(+), 244 deletions(-) diff --git a/common/eqemu_logsys.h b/common/eqemu_logsys.h index 184ccffe2..9fa164d98 100644 --- a/common/eqemu_logsys.h +++ b/common/eqemu_logsys.h @@ -113,6 +113,7 @@ namespace Logs { AoeCast, EntityManagement, Flee, + Aura, MaxCategoryID /* Don't Remove this */ }; @@ -185,6 +186,7 @@ namespace Logs { "AOE Cast", "Entity Management", "Flee", + "Aura", }; } diff --git a/common/eqemu_logsys_log_aliases.h b/common/eqemu_logsys_log_aliases.h index 1c003fff9..ccfc54f3a 100644 --- a/common/eqemu_logsys_log_aliases.h +++ b/common/eqemu_logsys_log_aliases.h @@ -551,6 +551,16 @@ OutF(LogSys, Logs::Detail, Logs::Flee, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\ } while (0) +#define LogAura(message, ...) do {\ + if (LogSys.log_settings[Logs::Aura].is_category_enabled == 1)\ + OutF(LogSys, Logs::General, Logs::Aura, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\ +} while (0) + +#define LogAuraDetail(message, ...) do {\ + if (LogSys.log_settings[Logs::Aura].is_category_enabled == 1)\ + OutF(LogSys, Logs::Detail, Logs::Aura, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\ +} while (0) + #define Log(debug_level, log_category, message, ...) do {\ if (LogSys.log_settings[log_category].is_category_enabled == 1)\ LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\ @@ -878,6 +888,12 @@ #define LogFleeDetail(message, ...) do {\ } while (0) +#define LogAura(message, ...) do {\ +} while (0) + +#define LogAuraDetail(message, ...) do {\ +} while (0) + #define Log(debug_level, log_category, message, ...) do {\ } while (0) diff --git a/zone/aura.cpp b/zone/aura.cpp index 0830816c1..50026f998 100644 --- a/zone/aura.cpp +++ b/zone/aura.cpp @@ -6,8 +6,9 @@ #include "raids.h" Aura::Aura(NPCType *type_data, Mob *owner, AuraRecord &record) - : NPC(type_data, 0, owner->GetPosition(), GravityBehavior::Flying), spell_id(record.spell_id), distance(record.distance), - remove_timer(record.duration), movement_timer(100), process_timer(1000), aura_id(-1) + : NPC(type_data, 0, owner->GetPosition(), GravityBehavior::Flying), spell_id(record.spell_id), + distance(record.distance), + remove_timer(record.duration), movement_timer(100), process_timer(1000), aura_id(-1) { GiveNPCTypeData(type_data); // we will delete this later on m_owner = owner->GetID(); @@ -17,42 +18,48 @@ Aura::Aura(NPCType *type_data, Mob *owner, AuraRecord &record) cast_timer.Disable(); // we don't want to be enabled yet } - if (record.aura_type < static_cast(AuraType::Max)) + if (record.aura_type < static_cast(AuraType::Max)) { type = static_cast(record.aura_type); - else + } + else { type = AuraType::OnAllGroupMembers; + } - if (record.spawn_type < static_cast(AuraSpawns::Max)) + if (record.spawn_type < static_cast(AuraSpawns::Max)) { spawn_type = static_cast(record.spawn_type); - else + } + else { spawn_type = AuraSpawns::GroupMembers; + } - if (record.movement < static_cast(AuraMovement::Max)) + if (record.movement < static_cast(AuraMovement::Max)) { movement_type = static_cast(record.movement); - else + } + else { movement_type = AuraMovement::Follow; + } switch (type) { - case AuraType::OnAllFriendlies: - process_func = &Aura::ProcessOnAllFriendlies; - break; - case AuraType::OnAllGroupMembers: - process_func = &Aura::ProcessOnAllGroupMembers; - break; - case AuraType::OnGroupMembersPets: - process_func = &Aura::ProcessOnGroupMembersPets; - break; - case AuraType::Totem: - process_func = &Aura::ProcessTotem; - break; - case AuraType::EnterTrap: - process_func = &Aura::ProcessEnterTrap; - break; - case AuraType::ExitTrap: - process_func = &Aura::ProcessExitTrap; - break; - default: - process_func = nullptr; + case AuraType::OnAllFriendlies: + process_func = &Aura::ProcessOnAllFriendlies; + break; + case AuraType::OnAllGroupMembers: + process_func = &Aura::ProcessOnAllGroupMembers; + break; + case AuraType::OnGroupMembersPets: + process_func = &Aura::ProcessOnGroupMembersPets; + break; + case AuraType::Totem: + process_func = &Aura::ProcessTotem; + break; + case AuraType::EnterTrap: + process_func = &Aura::ProcessEnterTrap; + break; + case AuraType::ExitTrap: + process_func = &Aura::ProcessExitTrap; + break; + default: + process_func = nullptr; } } @@ -64,9 +71,9 @@ Mob *Aura::GetOwner() // not 100% sure how this one should work and PVP affects ... void Aura::ProcessOnAllFriendlies(Mob *owner) { - auto &mob_list = entity_list.GetMobList(); // read only reference so we can do it all inline + auto &mob_list = entity_list.GetCloseMobList(this, distance); std::set delayed_remove; - bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter + bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter for (auto &e : mob_list) { auto mob = e.second; @@ -74,13 +81,16 @@ void Aura::ProcessOnAllFriendlies(Mob *owner) auto it = casted_on.find(mob->GetID()); if (it != casted_on.end()) { // we are already on the list, let's check for removal - if (DistanceSquared(GetPosition(), mob->GetPosition()) > distance) + if (DistanceSquared(GetPosition(), mob->GetPosition()) > distance) { delayed_remove.insert(mob->GetID()); - } else { // not on list, lets check if we're in range + } + } + else { // not on list, lets check if we're in range if (DistanceSquared(GetPosition(), mob->GetPosition()) <= distance) { casted_on.insert(mob->GetID()); - if (is_buff) + if (is_buff) { SpellFinished(spell_id, mob); + } } } } @@ -88,30 +98,34 @@ void Aura::ProcessOnAllFriendlies(Mob *owner) for (auto &e : delayed_remove) { auto mob = entity_list.GetMob(e); - if (mob != nullptr && is_buff) // some auras cast instant spells so no need to remove + if (mob != nullptr && is_buff) { // some auras cast instant spells so no need to remove mob->BuffFadeBySpellIDAndCaster(spell_id, GetID()); + } casted_on.erase(e); } // so if we have a cast timer and our set isn't empty and timer is disabled we need to enable it - if (cast_timer.GetDuration() > 0 && !cast_timer.Enabled() && !casted_on.empty()) + if (cast_timer.GetDuration() > 0 && !cast_timer.Enabled() && !casted_on.empty()) { cast_timer.Start(); + } - if (!cast_timer.Enabled() || !cast_timer.Check()) + if (!cast_timer.Enabled() || !cast_timer.Check()) { return; + } for (auto &e : casted_on) { auto mob = entity_list.GetMob(e); - if (mob != nullptr) + if (mob != nullptr) { SpellFinished(spell_id, mob); + } } } void Aura::ProcessOnAllGroupMembers(Mob *owner) { - auto &mob_list = entity_list.GetMobList(); // read only reference so we can do it all inline + auto &mob_list = entity_list.GetCloseMobList(this, distance); std::set delayed_remove; - bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter + bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter if (owner->IsRaidGrouped() && owner->IsClient()) { // currently raids are just client, but safety check auto raid = owner->GetRaid(); @@ -126,9 +140,12 @@ void Aura::ProcessOnAllGroupMembers(Mob *owner) auto idx = raid->GetPlayerIndex(c); if (c->GetID() == m_owner) { return DistanceSquared(GetPosition(), c->GetPosition()) <= distance; - } else if (idx == 0xFFFFFFFF || raid->members[idx].GroupNumber != group_id || raid->members[idx].GroupNumber == 0xFFFFFFFF) { + } + else if (idx == 0xFFFFFFFF || raid->members[idx].GroupNumber != group_id || + raid->members[idx].GroupNumber == 0xFFFFFFFF) { return false; - } else if (DistanceSquared(GetPosition(), c->GetPosition()) > distance) { + } + else if (DistanceSquared(GetPosition(), c->GetPosition()) > distance) { return false; } return true; @@ -138,9 +155,12 @@ void Aura::ProcessOnAllGroupMembers(Mob *owner) auto idx = raid->GetPlayerIndex(m->GetOwner()->CastToClient()); if (m->GetOwner()->GetID() == m_owner) { return DistanceSquared(GetPosition(), m->GetPosition()) <= distance; - } else if (idx == 0xFFFFFFFF || raid->members[idx].GroupNumber != group_id || raid->members[idx].GroupNumber == 0xFFFFFFFF) { + } + else if (idx == 0xFFFFFFFF || raid->members[idx].GroupNumber != group_id || + raid->members[idx].GroupNumber == 0xFFFFFFFF) { return false; - } else if (DistanceSquared(GetPosition(), m->GetPosition()) > distance) { + } + else if (DistanceSquared(GetPosition(), m->GetPosition()) > distance) { return false; } return true; @@ -148,14 +168,18 @@ void Aura::ProcessOnAllGroupMembers(Mob *owner) auto verify_raid_client_swarm = [&raid, &group_id, this](NPC *n) { auto owner = entity_list.GetMob(n->GetSwarmOwner()); - if (owner == nullptr) + if (owner == nullptr) { return false; + } auto idx = raid->GetPlayerIndex(owner->CastToClient()); if (owner->GetID() == m_owner) { return DistanceSquared(GetPosition(), n->GetPosition()) <= distance; - } else if (idx == 0xFFFFFFFF || raid->members[idx].GroupNumber != group_id || raid->members[idx].GroupNumber == 0xFFFFFFFF) { + } + else if (idx == 0xFFFFFFFF || raid->members[idx].GroupNumber != group_id || + raid->members[idx].GroupNumber == 0xFFFFFFFF) { return false; - } else if (DistanceSquared(GetPosition(), n->GetPosition()) > distance) { + } + else if (DistanceSquared(GetPosition(), n->GetPosition()) > distance) { return false; } return true; @@ -164,40 +188,52 @@ void Aura::ProcessOnAllGroupMembers(Mob *owner) for (auto &e : mob_list) { auto mob = e.second; // step 1: check if we're already managing this NPC's buff - auto it = casted_on.find(mob->GetID()); + auto it = casted_on.find(mob->GetID()); if (it != casted_on.end()) { // verify still good! if (mob->IsClient()) { - if (!verify_raid_client(mob->CastToClient())) - delayed_remove.insert(mob->GetID()); - } else if (mob->IsPet() && mob->IsPetOwnerClient() && mob->GetOwner()) { - if (!verify_raid_client_pet(mob)) - delayed_remove.insert(mob->GetID()); - } else if (mob->IsNPC() && mob->IsPetOwnerClient()) { - auto npc = mob->CastToNPC(); - if (!verify_raid_client_swarm(npc)) + if (!verify_raid_client(mob->CastToClient())) { delayed_remove.insert(mob->GetID()); + } } - } else { // we're not on it! + else if (mob->IsPet() && mob->IsPetOwnerClient() && mob->GetOwner()) { + if (!verify_raid_client_pet(mob)) { + delayed_remove.insert(mob->GetID()); + } + } + else if (mob->IsNPC() && mob->IsPetOwnerClient()) { + auto npc = mob->CastToNPC(); + if (!verify_raid_client_swarm(npc)) { + delayed_remove.insert(mob->GetID()); + } + } + } + else { // we're not on it! if (mob->IsClient() && verify_raid_client(mob->CastToClient())) { casted_on.insert(mob->GetID()); - if (is_buff) + if (is_buff) { SpellFinished(spell_id, mob); - } else if (mob->IsPet() && mob->IsPetOwnerClient() && mob->GetOwner() && verify_raid_client_pet(mob)) { + } + } + else if (mob->IsPet() && mob->IsPetOwnerClient() && mob->GetOwner() && verify_raid_client_pet(mob)) { casted_on.insert(mob->GetID()); - if (is_buff) + if (is_buff) { SpellFinished(spell_id, mob); - } else if (mob->IsNPC() && mob->IsPetOwnerClient()) { + } + } + else if (mob->IsNPC() && mob->IsPetOwnerClient()) { auto npc = mob->CastToNPC(); if (verify_raid_client_swarm(npc)) { casted_on.insert(mob->GetID()); - if (is_buff) + if (is_buff) { SpellFinished(spell_id, mob); + } } } } } - } else if (owner->IsGrouped()) { + } + else if (owner->IsGrouped()) { auto group = owner->GetGroup(); if (group == nullptr) { // uh oh owner->RemoveAura(GetID(), false, true); @@ -207,107 +243,133 @@ void Aura::ProcessOnAllGroupMembers(Mob *owner) // lambdas to make for loop less ugly auto verify_group_pet = [&group, this](Mob *m) { auto owner = m->GetOwner(); - if (owner != nullptr && group->IsGroupMember(owner) && DistanceSquared(GetPosition(), m->GetPosition()) <= distance) + if (owner != nullptr && group->IsGroupMember(owner) && + DistanceSquared(GetPosition(), m->GetPosition()) <= distance) { return true; + } return false; }; auto verify_group_swarm = [&group, this](NPC *n) { auto owner = entity_list.GetMob(n->GetSwarmOwner()); - if (owner != nullptr && group->IsGroupMember(owner) && DistanceSquared(GetPosition(), n->GetPosition()) <= distance) + if (owner != nullptr && group->IsGroupMember(owner) && + DistanceSquared(GetPosition(), n->GetPosition()) <= distance) { return true; + } return false; }; for (auto &e : mob_list) { auto mob = e.second; - auto it = casted_on.find(mob->GetID()); + auto it = casted_on.find(mob->GetID()); if (it != casted_on.end()) { // make sure we're still valid if (mob->IsPet()) { - if (!verify_group_pet(mob)) + if (!verify_group_pet(mob)) { delayed_remove.insert(mob->GetID()); - } else if (mob->IsNPC() && mob->CastToNPC()->GetSwarmInfo()) { - if (!verify_group_swarm(mob->CastToNPC())) + } + } + else if (mob->IsNPC() && mob->CastToNPC()->GetSwarmInfo()) { + if (!verify_group_swarm(mob->CastToNPC())) { delayed_remove.insert(mob->GetID()); - } else if (!group->IsGroupMember(mob) || DistanceSquared(GetPosition(), mob->GetPosition()) > distance) { + } + } + else if (!group->IsGroupMember(mob) || DistanceSquared(GetPosition(), mob->GetPosition()) > distance) { delayed_remove.insert(mob->GetID()); } - } else { // not on, check if we should be! + } + else { // not on, check if we should be! if (mob->IsPet() && verify_group_pet(mob)) { casted_on.insert(mob->GetID()); - if (is_buff) + if (is_buff) { SpellFinished(spell_id, mob); - } else if (mob->IsNPC() && mob->CastToNPC()->GetSwarmInfo() && verify_group_swarm(mob->CastToNPC())) { + } + } + else if (mob->IsNPC() && mob->CastToNPC()->GetSwarmInfo() && verify_group_swarm(mob->CastToNPC())) { casted_on.insert(mob->GetID()); - if (is_buff) + if (is_buff) { SpellFinished(spell_id, mob); - } else if (group->IsGroupMember(mob) && DistanceSquared(GetPosition(), mob->GetPosition()) <= distance) { + } + } + else if (group->IsGroupMember(mob) && DistanceSquared(GetPosition(), mob->GetPosition()) <= distance) { casted_on.insert(mob->GetID()); - if (is_buff) + if (is_buff) { SpellFinished(spell_id, mob); + } } } } - } else { - auto verify_solo = [&owner, this](Mob *m) { - if (m->IsPet() && m->GetOwnerID() == owner->GetID()) + } + else { + auto verify_solo = [&owner, this](Mob *m) { + if (m->IsPet() && m->GetOwnerID() == owner->GetID()) { return true; - else if (m->IsNPC() && m->CastToNPC()->GetSwarmOwner() == owner->GetID()) + } + else if (m->IsNPC() && m->CastToNPC()->GetSwarmOwner() == owner->GetID()) { return true; - else if (m->GetID() == owner->GetID()) + } + else if (m->GetID() == owner->GetID()) { return true; - else + } + else { return false; + } }; for (auto &e : mob_list) { - auto mob = e.second; - auto it = casted_on.find(mob->GetID()); + auto mob = e.second; + auto it = casted_on.find(mob->GetID()); bool good = verify_solo(mob); if (it != casted_on.end()) { // make sure still valid if (!good || DistanceSquared(GetPosition(), mob->GetPosition()) > distance) { delayed_remove.insert(mob->GetID()); } - } else if (good && DistanceSquared(GetPosition(), mob->GetPosition()) <= distance) { + } + else if (good && DistanceSquared(GetPosition(), mob->GetPosition()) <= distance) { casted_on.insert(mob->GetID()); - if (is_buff) + if (is_buff) { SpellFinished(spell_id, mob); + } } } } for (auto &e : delayed_remove) { auto mob = entity_list.GetMob(e); - if (mob != nullptr && is_buff) // some auras cast instant spells so no need to remove + if (mob != nullptr && is_buff) { // some auras cast instant spells so no need to remove mob->BuffFadeBySpellIDAndCaster(spell_id, GetID()); + } casted_on.erase(e); } // so if we have a cast timer and our set isn't empty and timer is disabled we need to enable it - if (cast_timer.GetDuration() > 0 && !cast_timer.Enabled() && !casted_on.empty()) + if (cast_timer.GetDuration() > 0 && !cast_timer.Enabled() && !casted_on.empty()) { cast_timer.Start(); + } - if (!cast_timer.Enabled() || !cast_timer.Check()) + if (!cast_timer.Enabled() || !cast_timer.Check()) { return; + } // some auras have to recast (DRU for example, non-buff too) for (auto &e : casted_on) { auto mob = entity_list.GetMob(e); - if (mob != nullptr) + if (mob != nullptr) { SpellFinished(spell_id, mob); + } } } void Aura::ProcessOnGroupMembersPets(Mob *owner) { - auto &mob_list = entity_list.GetMobList(); // read only reference so we can do it all inline + auto &mob_list = entity_list.GetCloseMobList(this,distance); std::set delayed_remove; - bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter + bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter // This type can either live on the pet (level 55/70 MAG aura) or on the pet owner (level 85 MAG aura) - auto group_member = owner->GetOwnerOrSelf(); + auto group_member = owner->GetOwnerOrSelf(); - if (group_member->IsRaidGrouped() && group_member->IsClient()) { // currently raids are just client, but safety check + if (group_member->IsRaidGrouped() && + group_member->IsClient()) { // currently raids are just client, but safety check auto raid = group_member->GetRaid(); if (raid == nullptr) { // well shit owner->RemoveAura(GetID(), false, true); @@ -320,9 +382,12 @@ void Aura::ProcessOnGroupMembersPets(Mob *owner) auto idx = raid->GetPlayerIndex(m->GetOwner()->CastToClient()); if (m->GetOwner()->GetID() == group_member->GetID()) { return DistanceSquared(GetPosition(), m->GetPosition()) <= distance; - } else if (idx == 0xFFFFFFFF || raid->members[idx].GroupNumber != group_id || raid->members[idx].GroupNumber == 0xFFFFFFFF) { + } + else if (idx == 0xFFFFFFFF || raid->members[idx].GroupNumber != group_id || + raid->members[idx].GroupNumber == 0xFFFFFFFF) { return false; - } else if (DistanceSquared(GetPosition(), m->GetPosition()) > distance) { + } + else if (DistanceSquared(GetPosition(), m->GetPosition()) > distance) { return false; } return true; @@ -330,14 +395,18 @@ void Aura::ProcessOnGroupMembersPets(Mob *owner) auto verify_raid_client_swarm = [&raid, &group_id, &group_member, this](NPC *n) { auto owner = entity_list.GetMob(n->GetSwarmOwner()); - if (owner == nullptr) + if (owner == nullptr) { return false; + } auto idx = raid->GetPlayerIndex(owner->CastToClient()); if (owner->GetID() == group_member->GetID()) { return DistanceSquared(GetPosition(), n->GetPosition()) <= distance; - } else if (idx == 0xFFFFFFFF || raid->members[idx].GroupNumber != group_id || raid->members[idx].GroupNumber == 0xFFFFFFFF) { + } + else if (idx == 0xFFFFFFFF || raid->members[idx].GroupNumber != group_id || + raid->members[idx].GroupNumber == 0xFFFFFFFF) { return false; - } else if (DistanceSquared(GetPosition(), n->GetPosition()) > distance) { + } + else if (DistanceSquared(GetPosition(), n->GetPosition()) > distance) { return false; } return true; @@ -346,35 +415,44 @@ void Aura::ProcessOnGroupMembersPets(Mob *owner) for (auto &e : mob_list) { auto mob = e.second; // step 1: check if we're already managing this NPC's buff - auto it = casted_on.find(mob->GetID()); + auto it = casted_on.find(mob->GetID()); if (it != casted_on.end()) { // verify still good! if (mob->IsPet() && mob->IsPetOwnerClient() && mob->GetOwner()) { - if (!verify_raid_client_pet(mob)) - delayed_remove.insert(mob->GetID()); - } else if (mob->IsNPC() && mob->IsPetOwnerClient()) { - auto npc = mob->CastToNPC(); - if (!verify_raid_client_swarm(npc)) + if (!verify_raid_client_pet(mob)) { delayed_remove.insert(mob->GetID()); + } } - } else { // we're not on it! + else if (mob->IsNPC() && mob->IsPetOwnerClient()) { + auto npc = mob->CastToNPC(); + if (!verify_raid_client_swarm(npc)) { + delayed_remove.insert(mob->GetID()); + } + } + } + else { // we're not on it! if (mob->IsClient()) { continue; // never hit client - } else if (mob->IsPet() && mob->IsPetOwnerClient() && mob->GetOwner() && verify_raid_client_pet(mob)) { + } + else if (mob->IsPet() && mob->IsPetOwnerClient() && mob->GetOwner() && verify_raid_client_pet(mob)) { casted_on.insert(mob->GetID()); - if (is_buff) + if (is_buff) { SpellFinished(spell_id, mob); - } else if (mob->IsNPC() && mob->IsPetOwnerClient()) { + } + } + else if (mob->IsNPC() && mob->IsPetOwnerClient()) { auto npc = mob->CastToNPC(); if (verify_raid_client_swarm(npc)) { casted_on.insert(mob->GetID()); - if (is_buff) + if (is_buff) { SpellFinished(spell_id, mob); + } } } } } - } else if (group_member->IsGrouped()) { + } + else if (group_member->IsGrouped()) { auto group = group_member->GetGroup(); if (group == nullptr) { // uh oh owner->RemoveAura(GetID(), false, true); @@ -384,111 +462,131 @@ void Aura::ProcessOnGroupMembersPets(Mob *owner) // lambdas to make for loop less ugly auto verify_group_pet = [&group, this](Mob *m) { auto owner = m->GetOwner(); - if (owner != nullptr && group->IsGroupMember(owner) && DistanceSquared(GetPosition(), m->GetPosition()) <= distance) - return true; - return false; + return owner != nullptr && group->IsGroupMember(owner) && + DistanceSquared(GetPosition(), m->GetPosition()) <= distance; }; auto verify_group_swarm = [&group, this](NPC *n) { auto owner = entity_list.GetMob(n->GetSwarmOwner()); - if (owner != nullptr && group->IsGroupMember(owner) && DistanceSquared(GetPosition(), n->GetPosition()) <= distance) - return true; - return false; + return owner != nullptr && group->IsGroupMember(owner) && + DistanceSquared(GetPosition(), n->GetPosition()) <= distance; }; for (auto &e : mob_list) { auto mob = e.second; - auto it = casted_on.find(mob->GetID()); + auto it = casted_on.find(mob->GetID()); if (it != casted_on.end()) { // make sure we're still valid if (mob->IsPet()) { - if (!verify_group_pet(mob)) - delayed_remove.insert(mob->GetID()); - } else if (mob->IsNPC() && mob->CastToNPC()->GetSwarmInfo()) { - if (!verify_group_swarm(mob->CastToNPC())) + if (!verify_group_pet(mob)) { delayed_remove.insert(mob->GetID()); + } } - } else { // not on, check if we should be! + else if (mob->IsNPC() && mob->CastToNPC()->GetSwarmInfo()) { + if (!verify_group_swarm(mob->CastToNPC())) { + delayed_remove.insert(mob->GetID()); + } + } + } + else { // not on, check if we should be! if (mob->IsClient()) { continue; - } else if (mob->IsPet() && verify_group_pet(mob)) { + } + else if (mob->IsPet() && verify_group_pet(mob)) { casted_on.insert(mob->GetID()); - if (is_buff) + if (is_buff) { SpellFinished(spell_id, mob); - } else if (mob->IsNPC() && mob->CastToNPC()->GetSwarmInfo() && verify_group_swarm(mob->CastToNPC())) { + } + } + else if (mob->IsNPC() && mob->CastToNPC()->GetSwarmInfo() && verify_group_swarm(mob->CastToNPC())) { casted_on.insert(mob->GetID()); - if (is_buff) + if (is_buff) { SpellFinished(spell_id, mob); + } } } } - } else { - auto verify_solo = [&group_member, this](Mob *m) { - if (m->IsPet() && m->GetOwnerID() == group_member->GetID()) + } + else { + auto verify_solo = [&group_member, this](Mob *m) { + if (m->IsPet() && m->GetOwnerID() == group_member->GetID()) { return true; - else if (m->IsNPC() && m->CastToNPC()->GetSwarmOwner() == group_member->GetID()) + } + else if (m->IsNPC() && m->CastToNPC()->GetSwarmOwner() == group_member->GetID()) { return true; - else + } + else { return false; + } }; for (auto &e : mob_list) { - auto mob = e.second; - auto it = casted_on.find(mob->GetID()); + auto mob = e.second; + auto it = casted_on.find(mob->GetID()); bool good = verify_solo(mob); if (it != casted_on.end()) { // make sure still valid if (!good || DistanceSquared(GetPosition(), mob->GetPosition()) > distance) { delayed_remove.insert(mob->GetID()); } - } else if (good && DistanceSquared(GetPosition(), mob->GetPosition()) <= distance) { + } + else if (good && DistanceSquared(GetPosition(), mob->GetPosition()) <= distance) { casted_on.insert(mob->GetID()); - if (is_buff) + if (is_buff) { SpellFinished(spell_id, mob); + } } } } for (auto &e : delayed_remove) { auto mob = entity_list.GetMob(e); - if (mob != nullptr && is_buff) // some auras cast instant spells so no need to remove + if (mob != nullptr && is_buff) { // some auras cast instant spells so no need to remove mob->BuffFadeBySpellIDAndCaster(spell_id, GetID()); + } casted_on.erase(e); } // so if we have a cast timer and our set isn't empty and timer is disabled we need to enable it - if (cast_timer.GetDuration() > 0 && !cast_timer.Enabled() && !casted_on.empty()) + if (cast_timer.GetDuration() > 0 && !cast_timer.Enabled() && !casted_on.empty()) { cast_timer.Start(); + } - if (!cast_timer.Enabled() || !cast_timer.Check()) + if (!cast_timer.Enabled() || !cast_timer.Check()) { return; + } // some auras have to recast (DRU for example, non-buff too) for (auto &e : casted_on) { auto mob = entity_list.GetMob(e); - if (mob != nullptr) + if (mob != nullptr) { SpellFinished(spell_id, mob); + } } } void Aura::ProcessTotem(Mob *owner) { - auto &mob_list = entity_list.GetMobList(); // read only reference so we can do it all inline + auto &mob_list = entity_list.GetCloseMobList(this, distance); std::set delayed_remove; - bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter + bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter for (auto &e : mob_list) { auto mob = e.second; - if (mob == this) + if (mob == this) { continue; - if (mob == owner) + } + if (mob == owner) { continue; + } if (owner->IsAttackAllowed(mob)) { // might need more checks ... bool in_range = DistanceSquared(GetPosition(), mob->GetPosition()) <= distance; - auto it = casted_on.find(mob->GetID()); + auto it = casted_on.find(mob->GetID()); if (it != casted_on.end()) { - if (!in_range) + if (!in_range) { delayed_remove.insert(mob->GetID()); - } else if (in_range) { + } + } + else if (in_range) { casted_on.insert(mob->GetID()); SpellFinished(spell_id, mob); } @@ -497,33 +595,38 @@ void Aura::ProcessTotem(Mob *owner) for (auto &e : delayed_remove) { auto mob = entity_list.GetMob(e); - if (mob != nullptr && is_buff) // some auras cast instant spells so no need to remove + if (mob != nullptr && is_buff) { // some auras cast instant spells so no need to remove mob->BuffFadeBySpellIDAndCaster(spell_id, GetID()); + } casted_on.erase(e); } // so if we have a cast timer and our set isn't empty and timer is disabled we need to enable it - if (cast_timer.GetDuration() > 0 && !cast_timer.Enabled() && !casted_on.empty()) + if (cast_timer.GetDuration() > 0 && !cast_timer.Enabled() && !casted_on.empty()) { cast_timer.Start(); + } - if (!cast_timer.Enabled() || !cast_timer.Check()) + if (!cast_timer.Enabled() || !cast_timer.Check()) { return; + } for (auto &e : casted_on) { auto mob = entity_list.GetMob(e); - if (mob != nullptr) + if (mob != nullptr) { SpellFinished(spell_id, mob); + } } } void Aura::ProcessEnterTrap(Mob *owner) { - auto &mob_list = entity_list.GetMobList(); // read only reference so we can do it all inline + auto &mob_list = entity_list.GetCloseMobList(this, distance); for (auto &e : mob_list) { auto mob = e.second; - if (mob == this) + if (mob == this) { continue; + } // might need more checks ... if (owner->IsAttackAllowed(mob) && DistanceSquared(GetPosition(), mob->GetPosition()) <= distance) { SpellFinished(spell_id, mob); @@ -535,23 +638,25 @@ void Aura::ProcessEnterTrap(Mob *owner) void Aura::ProcessExitTrap(Mob *owner) { - auto &mob_list = entity_list.GetMobList(); // read only reference so we can do it all inline + auto &mob_list = entity_list.GetCloseMobList(this, distance); for (auto &e : mob_list) { auto mob = e.second; - if (mob == this) + if (mob == this) { continue; + } // might need more checks ... if (owner->IsAttackAllowed(mob)) { bool in_range = DistanceSquared(GetPosition(), mob->GetPosition()) <= distance; - auto it = casted_on.find(mob->GetID()); + auto it = casted_on.find(mob->GetID()); if (it != casted_on.end()) { if (!in_range) { SpellFinished(spell_id, mob); owner->RemoveAura(GetID(), false); // if we're a buff we don't want to strip :P break; } - } else if (in_range) { + } + else if (in_range) { casted_on.insert(mob->GetID()); } } @@ -562,9 +667,14 @@ void Aura::ProcessExitTrap(Mob *owner) // and hard to reason about void Aura::ProcessSpawns() { - const auto &clients = entity_list.GetClientList(); - for (auto &e : clients) { - auto c = e.second; + const auto &clients = entity_list.GetCloseMobList(this, distance); + for (auto &e : clients) { + if (!e.second->IsClient()) { + continue; + } + + auto c = e.second->CastToClient(); + bool spawned = spawned_for.find(c->GetID()) != spawned_for.end(); if (ShouldISpawnFor(c)) { if (!spawned) { @@ -574,21 +684,22 @@ void Aura::ProcessSpawns() SendArmorAppearance(c); spawned_for.insert(c->GetID()); } - } else if (spawned) { + } + else if (spawned) { EQApplicationPacket app; CreateDespawnPacket(&app, false); c->QueuePacket(&app); spawned_for.erase(c->GetID()); } } - return; } bool Aura::Process() { // Aura::Depop clears buffs - if (p_depop) + if (p_depop) { return false; + } auto owner = entity_list.GetMob(m_owner); if (owner == nullptr) { @@ -604,7 +715,7 @@ bool Aura::Process() if (movement_type == AuraMovement::Follow && GetPosition() != owner->GetPosition() && movement_timer.Check()) { m_Position = owner->GetPosition(); auto app = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); - auto spu = (PlayerPositionUpdateServer_Struct*)app->pBuffer; + auto spu = (PlayerPositionUpdateServer_Struct *) app->pBuffer; MakeSpawnUpdate(spu); auto it = spawned_for.begin(); while (it != spawned_for.end()) { @@ -612,7 +723,8 @@ bool Aura::Process() if (client) { client->QueuePacket(app); ++it; - } else { + } + else { it = spawned_for.erase(it); } } @@ -620,14 +732,17 @@ bool Aura::Process() } // TODO: waypoints? - if (!process_timer.Check()) + if (!process_timer.Check()) { return true; + } - if (spawn_type != AuraSpawns::Noone) - ProcessSpawns(); // bit of a hack + if (spawn_type != AuraSpawns::Noone) { + ProcessSpawns(); + } // bit of a hack - if (process_func) + if (process_func) { process_func(*this, owner); + } // TODO: quest calls return true; @@ -635,49 +750,61 @@ bool Aura::Process() bool Aura::ShouldISpawnFor(Client *c) { - if (spawn_type == AuraSpawns::Noone) + if (spawn_type == AuraSpawns::Noone) { return false; + } - if (spawn_type == AuraSpawns::Everyone) + if (spawn_type == AuraSpawns::Everyone) { return true; + } // hey, it's our owner! - if (c->GetID() == m_owner) + if (c->GetID() == m_owner) { return true; + } // so this one is a bit trickier auto owner = GetOwner(); - if (owner == nullptr) - return false; // hmm + if (owner == nullptr) { + return false; + } // hmm owner = owner->GetOwnerOrSelf(); // pet auras we need the pet's owner - if (owner == nullptr) // shouldn't really be needed + if (owner == nullptr) { // shouldn't really be needed return false; + } // gotta check again for pet aura case -.- - if (owner == c) + if (owner == c) { return true; + } if (owner->IsRaidGrouped() && owner->IsClient()) { auto raid = owner->GetRaid(); - if (raid == nullptr) - return false; // hmm - auto group_id = raid->GetGroup(owner->CastToClient()); - if (group_id == 0xFFFFFFFF) // owner handled above, and they're in a raid and groupless + if (raid == nullptr) { return false; + } // hmm + auto group_id = raid->GetGroup(owner->CastToClient()); + if (group_id == 0xFFFFFFFF) { // owner handled above, and they're in a raid and groupless + return false; + } auto idx = raid->GetPlayerIndex(c); - if (idx == 0xFFFFFFFF) // they're not in our raid! + if (idx == 0xFFFFFFFF) { // they're not in our raid! return false; + } - if (raid->members[idx].GroupNumber != group_id) // in our raid, but not our group + if (raid->members[idx].GroupNumber != group_id) { // in our raid, but not our group return false; + } return true; // we got here so we know that 1 they're in our raid and 2 they're in our group! - } else if (owner->IsGrouped()) { + } + else if (owner->IsGrouped()) { auto group = owner->GetGroup(); - if (group == nullptr) - return false; // hmm + if (group == nullptr) { + return false; + } // hmm // easy, in our group return group->IsGroupMember(c); @@ -693,22 +820,23 @@ void Aura::Depop(bool skip_strip) if (!skip_strip && IsBuffSpell(spell_id)) { for (auto &e : casted_on) { auto mob = entity_list.GetMob(e); - if (mob != nullptr) + if (mob != nullptr) { mob->BuffFadeBySpellIDAndCaster(spell_id, GetID()); + } } } casted_on.clear(); p_depop = true; } -// This creates an aura from a casted spell void Mob::MakeAura(uint16 spell_id) { // TODO: verify room in AuraMgr - if (!IsValidSpell(spell_id)) + if (!IsValidSpell(spell_id)) { return; + } - AuraRecord record; + AuraRecord record{}; if (!database.GetAuraEntry(spell_id, record)) { Message(Chat::Red, "Unable to find data for aura %s", spells[spell_id].name); LogError("Unable to find data for aura [{}], check auras table", spell_id); @@ -718,7 +846,7 @@ void Mob::MakeAura(uint16 spell_id) if (!IsValidSpell(record.spell_id)) { Message(Chat::Red, "Casted spell (%d) is not valid for aura %s", record.spell_id, spells[spell_id].name); LogError("Casted spell ([{}]) is not valid for aura [{}], check auras table", - record.spell_id, spell_id); + record.spell_id, spell_id); return; } @@ -729,23 +857,28 @@ void Mob::MakeAura(uint16 spell_id) bool trap = false; switch (static_cast(record.aura_type)) { - case AuraType::ExitTrap: - case AuraType::EnterTrap: - case AuraType::Totem: - trap = true; - break; - default: - trap = false; - break; + case AuraType::ExitTrap: + case AuraType::EnterTrap: + case AuraType::Totem: + trap = true; + break; + default: + trap = false; + break; } - if (!CanSpawnAura(trap)) + if (!CanSpawnAura(trap)) { return; + } const auto base = database.LoadNPCTypesData(record.npc_type); if (base == nullptr) { Message(Chat::Red, "Unable to load NPC data for aura %s", spells[spell_id].teleport_zone); - LogError("Unable to load NPC data for aura [{}] (NPC ID [{}]), check auras and npc_types tables", spells[spell_id].teleport_zone, record.npc_type); + LogError( + "Unable to load NPC data for aura [{}] (NPC ID [{}]), check auras and npc_types tables", + spells[spell_id].teleport_zone, + record.npc_type + ); return; } @@ -756,65 +889,82 @@ void Mob::MakeAura(uint16 spell_id) auto npc = new Aura(npc_type, this, record); npc->SetAuraID(spell_id); - if (trap) - npc->TryMoveAlong(5.0f, 0.0f, false); // try to place 5 units in front + if (trap) { + npc->TryMoveAlong(5.0f, 0.0f, false); + } // try to place 5 units in front entity_list.AddNPC(npc, false); - if (trap) + if (trap) { AddTrap(npc, record); - else + } + else { AddAura(npc, record); + } } bool ZoneDatabase::GetAuraEntry(uint16 spell_id, AuraRecord &record) { - auto query = StringFormat("SELECT npc_type, name, spell_id, distance, aura_type, spawn_type, movement, " - "duration, icon, cast_time FROM auras WHERE type='%d'", - spell_id); + auto query = StringFormat( + "SELECT npc_type, name, spell_id, distance, aura_type, spawn_type, movement, " + "duration, icon, cast_time FROM auras WHERE type='%d'", + spell_id + ); auto results = QueryDatabase(query); - if (!results.Success()) + if (!results.Success()) { return false; + } - if (results.RowCount() != 1) + if (results.RowCount() != 1) { return false; + } auto row = results.begin(); record.npc_type = atoi(row[0]); strn0cpy(record.name, row[1], 64); - record.spell_id = atoi(row[2]); - record.distance = atoi(row[3]); + record.spell_id = atoi(row[2]); + record.distance = atoi(row[3]); record.distance *= record.distance; // so we can avoid sqrt - record.aura_type = atoi(row[4]); + record.aura_type = atoi(row[4]); record.spawn_type = atoi(row[5]); - record.movement = atoi(row[6]); - record.duration = atoi(row[7]) * 1000; // DB is in seconds - record.icon = atoi(row[8]); - record.cast_time = atoi(row[9]) * 1000; // DB is in seconds + record.movement = atoi(row[6]); + record.duration = atoi(row[7]) * 1000; // DB is in seconds + record.icon = atoi(row[8]); + record.cast_time = atoi(row[9]) * 1000; // DB is in seconds return true; } void Mob::AddAura(Aura *aura, AuraRecord &record) { + LogAura( + "[AddAura] aura owner [{}] spawn_id [{}] aura_name [{}]", + GetCleanName(), + aura->GetID(), + aura->GetCleanName() + ); + // this is called only when it's safe assert(aura != nullptr); strn0cpy(aura_mgr.auras[aura_mgr.count].name, aura->GetCleanName(), 64); aura_mgr.auras[aura_mgr.count].spawn_id = aura->GetID(); - aura_mgr.auras[aura_mgr.count].aura = aura; - if (record.icon == -1) + aura_mgr.auras[aura_mgr.count].aura = aura; + if (record.icon == -1) { aura_mgr.auras[aura_mgr.count].icon = spells[record.spell_id].new_icon; - else + } + else { aura_mgr.auras[aura_mgr.count].icon = record.icon; + } + if (IsClient()) { - auto outapp = new EQApplicationPacket(OP_UpdateAura, sizeof(AuraCreate_Struct)); - auto aura_create = (AuraCreate_Struct *)outapp->pBuffer; + auto outapp = new EQApplicationPacket(OP_UpdateAura, sizeof(AuraCreate_Struct)); + auto aura_create = (AuraCreate_Struct *) outapp->pBuffer; aura_create->action = 0; - aura_create->type = 1; // this can be 0 sometimes too + aura_create->type = 1; // this can be 0 sometimes too strn0cpy(aura_create->aura_name, aura_mgr.auras[aura_mgr.count].name, 64); aura_create->entity_id = aura_mgr.auras[aura_mgr.count].spawn_id; - aura_create->icon = aura_mgr.auras[aura_mgr.count].icon; + aura_create->icon = aura_mgr.auras[aura_mgr.count].icon; CastToClient()->FastQueuePacket(&outapp); } // we can increment this now @@ -823,15 +973,24 @@ void Mob::AddAura(Aura *aura, AuraRecord &record) void Mob::AddTrap(Aura *aura, AuraRecord &record) { + LogAura( + "[AddTrap] aura owner [{}] spawn_id [{}] aura_name [{}]", + GetCleanName(), + aura->GetID(), + aura->GetCleanName() + ); + // this is called only when it's safe assert(aura != nullptr); strn0cpy(trap_mgr.auras[trap_mgr.count].name, aura->GetCleanName(), 64); trap_mgr.auras[trap_mgr.count].spawn_id = aura->GetID(); - trap_mgr.auras[trap_mgr.count].aura = aura; - if (record.icon == -1) + trap_mgr.auras[trap_mgr.count].aura = aura; + if (record.icon == -1) { trap_mgr.auras[trap_mgr.count].icon = spells[record.spell_id].new_icon; - else + } + else { trap_mgr.auras[trap_mgr.count].icon = record.icon; + } // doesn't send to client trap_mgr.count++; } @@ -841,7 +1000,8 @@ bool Mob::CanSpawnAura(bool trap) if (trap && !HasFreeTrapSlots()) { MessageString(Chat::SpellFailure, NO_MORE_TRAPS); return false; - } else if (!trap && !HasFreeAuraSlots()) { + } + else if (!trap && !HasFreeAuraSlots()) { MessageString(Chat::SpellFailure, NO_MORE_AURAS); return false; } @@ -861,8 +1021,16 @@ void Mob::RemoveAllAuras() // this is sent on camp/zone, so it just despawns? if (aura_mgr.count) { for (auto &e : aura_mgr.auras) { - if (e.aura) + if (e.aura) { + LogAura( + "[RemoveAllAuras] aura owner [{}] spawn_id [{}] aura_name [{}]", + GetCleanName(), + e.spawn_id, + e.name + ); + e.aura->Depop(); + } } } @@ -870,8 +1038,16 @@ void Mob::RemoveAllAuras() if (trap_mgr.count) { for (auto &e : trap_mgr.auras) { - if (e.aura) + if (e.aura) { + LogAura( + "[RemoveAllAuras] trap owner [{}] spawn_id [{}] aura_name [{}]", + GetCleanName(), + e.spawn_id, + e.name + ); + e.aura->Depop(); + } } } @@ -883,24 +1059,36 @@ void Mob::RemoveAura(int spawn_id, bool skip_strip, bool expired) for (int i = 0; i < aura_mgr.count; ++i) { auto &aura = aura_mgr.auras[i]; if (aura.spawn_id == spawn_id) { - if (aura.aura) + LogAura( + "[RemoveAura] mob [{}] spawn_id [{}] skip_strip [{}] expired [{}]", + GetCleanName(), + spawn_id, + skip_strip ? "true" : "false", + expired ? "true" : "false" + ); + + if (aura.aura) { aura.aura->Depop(skip_strip); + } if (expired && IsClient()) { + // TODO: verify color CastToClient()->SendColoredText( - Chat::Yellow, StringFormat("%s has expired.", aura.name)); // TODO: verify color + Chat::Yellow, + StringFormat("%s has expired.", aura.name) + ); // need to update client UI too auto app = new EQApplicationPacket(OP_UpdateAura, sizeof(AuraDestory_Struct)); - auto ads = (AuraDestory_Struct *)app->pBuffer; - ads->action = 1; // delete + auto ads = (AuraDestory_Struct *) app->pBuffer; + ads->action = 1; // delete ads->entity_id = spawn_id; CastToClient()->QueuePacket(app); safe_delete(app); } while (aura_mgr.count - 1 > i) { i++; - aura.spawn_id = aura_mgr.auras[i].spawn_id; - aura.icon = aura_mgr.auras[i].icon; - aura.aura = aura_mgr.auras[i].aura; + aura.spawn_id = aura_mgr.auras[i].spawn_id; + aura.icon = aura_mgr.auras[i].icon; + aura.aura = aura_mgr.auras[i].aura; aura_mgr.auras[i].aura = nullptr; strn0cpy(aura.name, aura_mgr.auras[i].name, 64); } @@ -912,16 +1100,18 @@ void Mob::RemoveAura(int spawn_id, bool skip_strip, bool expired) for (int i = 0; i < trap_mgr.count; ++i) { auto &aura = trap_mgr.auras[i]; if (aura.spawn_id == spawn_id) { - if (aura.aura) + if (aura.aura) { aura.aura->Depop(skip_strip); - if (expired && IsClient()) + } + if (expired && IsClient()) { CastToClient()->SendColoredText( - Chat::Yellow, StringFormat("%s has expired.", aura.name)); // TODO: verify color + Chat::Yellow, StringFormat("%s has expired.", aura.name)); + } // TODO: verify color while (trap_mgr.count - 1 > i) { i++; - aura.spawn_id = trap_mgr.auras[i].spawn_id; - aura.icon = trap_mgr.auras[i].icon; - aura.aura = trap_mgr.auras[i].aura; + aura.spawn_id = trap_mgr.auras[i].spawn_id; + aura.icon = trap_mgr.auras[i].icon; + aura.aura = trap_mgr.auras[i].aura; trap_mgr.auras[i].aura = nullptr; strn0cpy(aura.name, trap_mgr.auras[i].name, 64); } @@ -930,6 +1120,5 @@ void Mob::RemoveAura(int spawn_id, bool skip_strip, bool expired) } } - return; } diff --git a/zone/aura.h b/zone/aura.h index ff4f2d51c..ae4cd0a4a 100644 --- a/zone/aura.h +++ b/zone/aura.h @@ -73,7 +73,7 @@ private: int m_owner; int aura_id; // spell ID of the aura spell -1 if aura isn't from a casted spell int spell_id; // spell we cast - int distance; // distance we remove + float distance; // distance we remove Timer remove_timer; // when we depop Timer process_timer; // rate limit process calls Timer cast_timer; // some auras pulse diff --git a/zone/entity.cpp b/zone/entity.cpp index 3d926e651..b13fb5649 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -2624,6 +2624,24 @@ bool EntityList::RemoveMobFromCloseLists(Mob *mob) return false; } +/** + * @param mob + * @return + */ +void EntityList::RemoveAuraFromMobs(Mob *aura) +{ + LogEntityManagement( + "Attempting to remove aura [{}] from mobs entity_id ({})", + aura->GetCleanName(), + aura->GetID() + ); + + for (auto &it : mob_list) { + auto mob = it.second; + mob->RemoveAura(aura->GetID()); + } +} + /** * @param close_mobs * @param scanning_mob diff --git a/zone/entity.h b/zone/entity.h index a296ca794..505f34963 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -293,6 +293,7 @@ public: bool RemoveObject(uint16 delete_id); bool RemoveProximity(uint16 delete_npc_id); bool RemoveMobFromCloseLists(Mob *mob); + void RemoveAuraFromMobs(Mob *aura); void RemoveAllMobs(); void RemoveAllClients(); void RemoveAllNPCs(); @@ -584,7 +585,6 @@ private: private: std::list bot_list; #endif - }; class BulkZoneSpawnPacket { diff --git a/zone/mob.cpp b/zone/mob.cpp index af8aa25ab..71e876938 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -503,6 +503,8 @@ Mob::~Mob() UninitializeBuffSlots(); entity_list.RemoveMobFromCloseLists(this); + entity_list.RemoveAuraFromMobs(this); + close_mobs.clear(); #ifdef BOTS From 9cc73f2b4a3dcfc6588712aad452c728a0762ed8 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Mon, 20 Jan 2020 14:24:29 -0500 Subject: [PATCH 36/57] Fix formula for mana There were errors in the old formula for wis/int values over 201. --- zone/client_mods.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/zone/client_mods.cpp b/zone/client_mods.cpp index 1b8735d7d..2d61a59ec 100644 --- a/zone/client_mods.cpp +++ b/zone/client_mods.cpp @@ -610,14 +610,13 @@ int32 Client::CalcBaseMana() case 'I': WisInt = GetINT(); if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) { + ConvertedWisInt = WisInt; + int over200 = WisInt; if (WisInt > 100) { - ConvertedWisInt = (((WisInt - 100) * 5 / 2) + 100); - if (WisInt > 201) { - ConvertedWisInt -= ((WisInt - 201) * 5 / 4); + if (WisInt > 200) { + over200 = (WisInt - 200) / -2 + WisInt; } - } - else { - ConvertedWisInt = WisInt; + ConvertedWisInt = (3 * over200 - 300) / 2 + over200; } auto base_data = database.GetBaseData(GetLevel(), GetClass()); if (base_data) { @@ -643,14 +642,13 @@ int32 Client::CalcBaseMana() case 'W': WisInt = GetWIS(); if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) { + ConvertedWisInt = WisInt; + int over200 = WisInt; if (WisInt > 100) { - ConvertedWisInt = (((WisInt - 100) * 5 / 2) + 100); - if (WisInt > 201) { - ConvertedWisInt -= ((WisInt - 201) * 5 / 4); + if (WisInt > 200) { + over200 = (WisInt - 200) / -2 + WisInt; } - } - else { - ConvertedWisInt = WisInt; + ConvertedWisInt = (3 * over200 - 300) / 2 + over200; } auto base_data = database.GetBaseData(GetLevel(), GetClass()); if (base_data) { From 8e6dd638ffc5a7660d284e48dac4728436b0e173 Mon Sep 17 00:00:00 2001 From: Kinglykrab Date: Mon, 20 Jan 2020 20:20:06 -0500 Subject: [PATCH 37/57] Implement SE_SummonCorpseZone (SPA 388). - This SPA summons all of a targeted group or raid group member's corpses from anywhere in the world. - Example Spell 16247 (Summon Remains) --- common/spdat.h | 2 +- zone/spell_effects.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++ zone/string_ids.h | 2 ++ zone/zonedb.cpp | 41 +++++++++++++++++++++++++++++++++ zone/zonedb.h | 2 ++ 5 files changed, 98 insertions(+), 1 deletion(-) diff --git a/common/spdat.h b/common/spdat.h index 416f63561..c7c6027c6 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -607,7 +607,7 @@ typedef enum { #define SE_LimitSpellGroup 385 // implemented - Limits to spell group(ie type 3 reuse reduction augs that are class specific and thus all share s SG) #define SE_CastOnCurer 386 // implemented - Casts a spell on the person curing #define SE_CastOnCure 387 // implemented - Casts a spell on the cured person -//#define SE_SummonCorpseZone 388 // *not implemented - summons a corpse from any zone(nec AA) +#define SE_SummonCorpseZone 388 // implemented - summons a corpse from any zone(nec AA) #define SE_FcTimerRefresh 389 // implemented - Refresh spell icons //#define SE_FcTimerLockout 390 // *not implemented - Sets recast timers to specific value, focus limited. #define SE_LimitManaMax 391 // implemented diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 0f29c38ce..2a30cf924 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -1820,6 +1820,58 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove break; } + case SE_SummonCorpseZone: + { + if (IsClient()) { + Client* client_target = this->CastToClient(); + if(client_target->IsGrouped()) { + Group* group = client_target->GetGroup(); + if(!group->IsGroupMember(caster)) { + if (caster != this) { + caster->MessageString(Chat::Red, SUMMON_ONLY_GROUP_CORPSE); + break; + } + } + } else if (caster) { + if(caster->IsRaidGrouped()) { + Raid *raid = caster->GetRaid(); + uint32 group_id = raid->GetGroup(caster->GetName()); + if(group_id > 0 && group_id < MAX_RAID_GROUPS) { + if(raid->GetGroup(client_target->GetName()) != group_id) { + caster->MessageString(Chat::Red, SUMMON_ONLY_GROUP_CORPSE); + break; + } + } + } else { + if(caster != this) { + caster->MessageString(Chat::Red, SUMMON_ONLY_GROUP_CORPSE); + break; + } + } + } + + if(client_target) { + if(database.CountCharacterCorpses(client_target->CharacterID()) == 0) { + if (caster == this) { + Message(Chat::Yellow, "You have no corpses to summon."); + } else { + caster->Message(Chat::Yellow, "%s has no corpses to summon.", client_target->GetCleanName()); + } + } else { + if (caster == this) { + Message(Chat::Spells, "Summoning your corpses."); + } else { + caster->MessageString(Chat::Spells, SUMMONING_CORPSE_ZONE, client_target->GetCleanName()); + } + client_target->SummonAllCorpses(client_target->GetPosition()); + } + } else { + MessageString(Chat::Spells, TARGET_NOT_FOUND); + LogError("[{}] attempted to cast spell id [{}] with spell effect SE_SummonCorpseZone, but could not cast target into a Client object", GetCleanName(), spell_id); + } + } + break; + } case SE_AddMeleeProc: case SE_WeaponProc: { diff --git a/zone/string_ids.h b/zone/string_ids.h index acab3df22..0948d13a8 100644 --- a/zone/string_ids.h +++ b/zone/string_ids.h @@ -65,6 +65,7 @@ #define SILENCED_STRING 207 //You *CANNOT* cast spells, you have been silenced! #define CANNOT_AFFECT_PC 210 //That spell can not affect this target PC. #define SPELL_NEED_TAR 214 //You must first select a target for this spell! +#define SUMMON_ONLY_GROUP_CORPSE 215 //You must first target a living group member whose corpse you wish to summon. #define ONLY_ON_CORPSES 221 //This spell only works on corpses. #define CANT_DRAIN_SELF 224 //You can't drain yourself! #define CORPSE_NOT_VALID 230 //This corpse is not valid. @@ -169,6 +170,7 @@ #define PVP_ON 552 //You are now player kill and follow the ways of Discord. #define GENERIC_STRINGID_SAY 554 //%1 says '%T2' #define CANNOT_WAKE 555 //%1 tells you, 'I am unable to wake %2, master.' +#define SUMMONING_CORPSE_ZONE 596 //Summoning %1's corpse(s). #define PET_HOLD_SET_ON 698 //The pet hold mode has been set to on. #define PET_HOLD_SET_OFF 699 //The pet hold mode has been set to off. #define PET_FOCUS_SET_ON 700 //The pet focus mode has been set to on. diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index dc2e29cad..d5346877d 100755 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -4707,6 +4707,47 @@ bool ZoneDatabase::SummonAllCharacterCorpses(uint32 char_id, uint32 dest_zone_id return (CorpseCount > 0); } +int ZoneDatabase::CountCharacterCorpses(uint32 char_id) { + std::string query = fmt::format( + SQL( + SELECT + COUNT(*) + FROM + character_corpses + WHERE + charid = '{}' + ), + char_id + ); + auto results = QueryDatabase(query); + for (auto row = results.begin(); row != results.end(); ++row) { + return atoi(row[0]); + } + return 0; +} + +int ZoneDatabase::CountCharacterCorpsesByZoneID(uint32 char_id, uint32 zone_id) { + std::string query = fmt::format( + SQL( + SELECT + COUNT(*) + FROM + character_corpses + WHERE + charid = '{}' + AND + zone_id = '{}' + ), + char_id, + zone_id + ); + auto results = QueryDatabase(query); + for (auto row = results.begin(); row != results.end(); ++row) { + return atoi(row[0]); + } + return 0; +} + bool ZoneDatabase::UnburyCharacterCorpse(uint32 db_id, uint32 new_zone_id, uint16 new_instance_id, const glm::vec4& position) { std::string query = StringFormat("UPDATE `character_corpses` " "SET `is_buried` = 0, `zone_id` = %u, `instance_id` = %u, " diff --git a/zone/zonedb.h b/zone/zonedb.h index e93a40713..f28ac5ec4 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -356,6 +356,8 @@ public: bool DeleteCharacterCorpse(uint32 dbid); bool SummonAllCharacterCorpses(uint32 char_id, uint32 dest_zoneid, uint16 dest_instanceid, const glm::vec4& position); bool SummonAllGraveyardCorpses(uint32 cur_zoneid, uint32 dest_zoneid, uint16 dest_instanceid, const glm::vec4& position); + int CountCharacterCorpses(uint32 char_id); + int CountCharacterCorpsesByZoneID(uint32 char_id, uint32 zone_id); bool UnburyCharacterCorpse(uint32 dbid, uint32 new_zoneid, uint16 dest_instanceid, const glm::vec4& position); bool LoadCharacterCorpses(uint32 iZoneID, uint16 iInstanceID); bool DeleteGraveyard(uint32 zone_id, uint32 graveyard_id); From caceae1028492dc61b5eb81f6e61fad8a5e4da9f Mon Sep 17 00:00:00 2001 From: Kinglykrab Date: Mon, 20 Jan 2020 20:23:11 -0500 Subject: [PATCH 38/57] Implement Corpse counting methods for global/zone-specific counting. Global: - Perl: quest::getplayercorpsecount(uint32 char_id); - Lua: eq.get_player_corpse_count(uint32 char_id); Zone-specific: - Perl: quest::getplayercorpsecountbyzoneid(uint32 char_id, uint32 zone_id); - Lua: eq.get_player_corpse_count_by_zone_id(uint32 char_id, uint32 zone_id); --- zone/embparser_api.cpp | 39 +++++++++++++++++++++++++++++++++++++++ zone/lua_general.cpp | 10 ++++++++++ zone/questmgr.cpp | 15 +++++++++++++++ zone/questmgr.h | 2 ++ 4 files changed, 66 insertions(+) diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index c29c28e20..871cc0ced 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -1812,6 +1812,43 @@ XS(XS__summonallplayercorpses) { XSRETURN(1); } +XS(XS__getplayercorpsecount); +XS(XS__getplayercorpsecount) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: quest::getplayercorpsecount(uint32 char_id)"); + + uint32 RETVAL; + dXSTARG; + + uint32 char_id = (int) SvIV(ST(0)); + + RETVAL = quest_manager.getplayercorpsecount(char_id); + XSprePUSH; + PUSHu((IV) RETVAL); + + XSRETURN(1); +} + +XS(XS__getplayercorpsecountbyzoneid); +XS(XS__getplayercorpsecountbyzoneid) { + dXSARGS; + if (items != 2) + Perl_croak(aTHX_ "Usage: quest::getplayercorpsecountbyzoneid(uint32 char_id, uint32 zone_id)"); + + uint32 RETVAL; + dXSTARG; + + uint32 char_id = (int) SvIV(ST(0)); + uint32 zone_id = (int)SvIV(ST(1)); + + RETVAL = quest_manager.getplayercorpsecountbyzoneid(char_id, zone_id); + XSprePUSH; + PUSHu((IV) RETVAL); + + XSRETURN(1); +} + XS(XS__getplayerburiedcorpsecount); XS(XS__getplayerburiedcorpsecount) { dXSARGS; @@ -3907,6 +3944,8 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "getguildnamebyid"), XS__getguildnamebyid, file); newXS(strcpy(buf, "getlevel"), XS__getlevel, file); newXS(strcpy(buf, "getplayerburiedcorpsecount"), XS__getplayerburiedcorpsecount, file); + newXS(strcpy(buf, "getplayercorpsecount"), XS__getplayercorpsecount, file); + newXS(strcpy(buf, "getplayercorpsecountbyzoneid"), XS__getplayercorpsecountbyzoneid, file); newXS(strcpy(buf, "gettaskactivitydonecount"), XS__gettaskactivitydonecount, file); newXS(strcpy(buf, "givecash"), XS__givecash, file); newXS(strcpy(buf, "gmmove"), XS__gmmove, file); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index ff0c6b10a..0d1086ad1 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -549,6 +549,14 @@ void lua_summon_all_player_corpses(uint32 char_id, float x, float y, float z, fl quest_manager.summonallplayercorpses(char_id, glm::vec4(x, y, z, h)); } +int lua_get_player_corpse_count(uint32 char_id) { + return database.CountCharacterCorpses(char_id); +} + +int lua_get_player_corpse_count_by_zone_id(uint32 char_id, uint32 zone_id) { + return database.CountCharacterCorpsesByZoneID(char_id, zone_id); +} + int lua_get_player_buried_corpse_count(uint32 char_id) { return quest_manager.getplayerburiedcorpsecount(char_id); } @@ -1663,6 +1671,8 @@ luabind::scope lua_register_general() { luabind::def("toggle_spawn_event", &lua_toggle_spawn_event), luabind::def("summon_buried_player_corpse", &lua_summon_buried_player_corpse), luabind::def("summon_all_player_corpses", &lua_summon_all_player_corpses), + luabind::def("get_player_corpse_count", &lua_get_player_corpse_count), + luabind::def("get_player_corpse_count_by_zone_id", &lua_get_player_corpse_count_by_zone_id), luabind::def("get_player_buried_corpse_count", &lua_get_player_buried_corpse_count), luabind::def("bury_player_corpse", &lua_bury_player_corpse), luabind::def("task_selector", &lua_task_selector), diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 69e55a57f..b48cd8993 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -1910,6 +1910,21 @@ bool QuestManager::summonallplayercorpses(uint32 char_id, const glm::vec4& posit return true; } +int QuestManager::getplayercorpsecount(uint32 char_id) { + if (char_id > 0) + return database.CountCharacterCorpses(char_id); + + return 0; + +} + +int QuestManager::getplayercorpsecountbyzoneid(uint32 char_id, uint32 zone_id) { + if (char_id > 0 && zone_id > 0) + return database.CountCharacterCorpsesByZoneID(char_id, zone_id); + + return 0; +} + uint32 QuestManager::getplayerburiedcorpsecount(uint32 char_id) { uint32 Result = 0; diff --git a/zone/questmgr.h b/zone/questmgr.h index 1b9ea9c4d..5ad551c43 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -172,6 +172,8 @@ public: bool summonburiedplayercorpse(uint32 char_id, const glm::vec4& position); bool summonallplayercorpses(uint32 char_id, const glm::vec4& position); uint32 getplayerburiedcorpsecount(uint32 char_id); + int getplayercorpsecount(uint32 char_id); + int getplayercorpsecountbyzoneid(uint32 char_id, uint32 zone_id); bool buryplayercorpse(uint32 char_id); void forcedooropen(uint32 doorid, bool altmode); void forcedoorclose(uint32 doorid, bool altmode); From 8b37ef5e672d16d3a7baf41659baa4bc42abee66 Mon Sep 17 00:00:00 2001 From: Kinglykrab Date: Mon, 20 Jan 2020 21:14:28 -0500 Subject: [PATCH 39/57] Formatting --- zone/questmgr.cpp | 8 ++++---- zone/spell_effects.cpp | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index b48cd8993..bea136e28 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -1911,17 +1911,17 @@ bool QuestManager::summonallplayercorpses(uint32 char_id, const glm::vec4& posit } int QuestManager::getplayercorpsecount(uint32 char_id) { - if (char_id > 0) + if (char_id > 0) { return database.CountCharacterCorpses(char_id); - + } return 0; } int QuestManager::getplayercorpsecountbyzoneid(uint32 char_id, uint32 zone_id) { - if (char_id > 0 && zone_id > 0) + if (char_id > 0 && zone_id > 0) { return database.CountCharacterCorpsesByZoneID(char_id, zone_id); - + } return 0; } diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 2a30cf924..693222e9f 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -1824,34 +1824,34 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove { if (IsClient()) { Client* client_target = this->CastToClient(); - if(client_target->IsGrouped()) { + if (client_target->IsGrouped()) { Group* group = client_target->GetGroup(); - if(!group->IsGroupMember(caster)) { + if (!group->IsGroupMember(caster)) { if (caster != this) { caster->MessageString(Chat::Red, SUMMON_ONLY_GROUP_CORPSE); break; } } } else if (caster) { - if(caster->IsRaidGrouped()) { + if (caster->IsRaidGrouped()) { Raid *raid = caster->GetRaid(); uint32 group_id = raid->GetGroup(caster->GetName()); - if(group_id > 0 && group_id < MAX_RAID_GROUPS) { - if(raid->GetGroup(client_target->GetName()) != group_id) { + if (group_id > 0 && group_id < MAX_RAID_GROUPS) { + if (raid->GetGroup(client_target->GetName()) != group_id) { caster->MessageString(Chat::Red, SUMMON_ONLY_GROUP_CORPSE); break; } } } else { - if(caster != this) { + if (caster != this) { caster->MessageString(Chat::Red, SUMMON_ONLY_GROUP_CORPSE); break; } } } - if(client_target) { - if(database.CountCharacterCorpses(client_target->CharacterID()) == 0) { + if (client_target) { + if (database.CountCharacterCorpses(client_target->CharacterID()) == 0) { if (caster == this) { Message(Chat::Yellow, "You have no corpses to summon."); } else { From c590cf7c35e118a9e876a0c533a67ba118dc6cc6 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 23 Jan 2020 23:36:13 -0500 Subject: [PATCH 40/57] Let's try updating travis to bionic --- .travis.yml | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/.travis.yml b/.travis.yml index faed5b846..38db9d797 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,26 +1,18 @@ language: cpp compiler: gcc -dist: trusty +dist: bionic -before_install: - - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test - - sudo apt-get update -qq - - mkdir $HOME/usr - - export PATH="$HOME/usr/bin:$PATH" - - wget https://cmake.org/files/v3.11/cmake-3.11.2-Linux-x86_64.sh - - chmod +x cmake-3.11.2-Linux-x86_64.sh - - ./cmake-3.11.2-Linux-x86_64.sh --prefix=$HOME/usr --exclude-subdir --skip-license +addons: + apt: + packages: + - libmysqlclient-dev + - libperl-dev + - libboost-dev + - liblua5.1-0-dev + - zlib1g-dev + - uuid-dev + - libssl-dev -install: - - sudo apt-get install -qq g++-7 - - sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-7 90 - - sudo apt-get install libmysqlclient-dev - - sudo apt-get install libperl-dev - - sudo apt-get install libboost-dev - - sudo apt-get install liblua5.1-0-dev - - sudo apt-get install zlib1g-dev - - sudo apt-get install uuid-dev - - sudo apt-get install libssl-dev script: - cmake -G "Unix Makefiles" -DEQEMU_BUILD_TESTS=ON -DEQEMU_ENABLE_BOTS=ON -DEQEMU_BUILD_LOGIN=ON - make -j2 From c2b3e852724f67b2540ef9405bf1554138e8161b Mon Sep 17 00:00:00 2001 From: regneq Date: Fri, 24 Jan 2020 15:11:08 -0800 Subject: [PATCH 41/57] Added new pathgrid type 7 (GridCenterPoint). This grid causes a NPC to alternate between the first waypoint in their grid (Number 1 in the editor) and a random waypoint. (1 - 7 - 1 - 4 - 1 - 11 - 1 - 5 - 1, etc) Changed the wandertype IDs to an enum so we know what we're looking at. Added new pathgrid type 8 (GridRandomCenterPoint). (SQL required) This new type causes a NPC to alternate between a random waypoint in grid_entries and a random waypoint marked with the new centerpoint column set to true. If no waypoints are marked as a centerpoint, this wandertype will not work. There is no numbering requirement or limit for centerpoints. You can have as many as you need. New spawngroup field: wp_spawns (SQL required). Added a new spawngroup field, which is a boolean that if true changes the behavior of spawngroups this way: If the spawnpoint in the spawngroup has a grid, the NPC will spawn at a random waypoint location taken from its grid instead of the spawnpoint location. New randompath behavior: The randompath grid type will now use the closest waypoint as its current waypoint on spawning. This allows multiple spawn locations to use the same grid without having the undesirable behavior of walking to the first waypoint through walls and ignoring waypoint nodes. NPC::GetClosestWaypoint() was renamed to NPC::GetClosestWaypoints() as it was filling a list of multiple waypoints. a new method NPC::GetClosestWaypoint() returns a single waypoint in the form of an integer. --- utils/sql/db_update_manifest.txt | 1 + .../2020_01_24_grid_centerpoint_wp.sql | 2 + zone/common.h | 13 ++ zone/mob_ai.cpp | 30 +++- zone/npc.h | 5 +- zone/spawn2.cpp | 22 ++- zone/spawn2.h | 2 +- zone/spawngroup.cpp | 16 +- zone/spawngroup.h | 4 +- zone/waypoints.cpp | 165 +++++++++++++++--- zone/zonedb.h | 2 + 11 files changed, 219 insertions(+), 43 deletions(-) create mode 100644 utils/sql/git/required/2020_01_24_grid_centerpoint_wp.sql diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index aa7897e7f..53a71e109 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -400,6 +400,7 @@ 9144|2019_11_09_logsys_description_update.sql|SELECT * FROM db_version WHERE version >= 9143|empty| 9145|2019_12_24_banned_ips_update.sql|SHOW TABLES LIKE 'Banned_IPs'|not_empty| 9146|2020_01_10_character_soft_deletes.sql|SHOW COLUMNS FROM `character_data` LIKE 'deleted_at'|empty| +9147|2020_01_24_grid_centerpoint_wp.sql|SHOW COLUMNS FROM `grid_entries` LIKE 'centerpoint'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2020_01_24_grid_centerpoint_wp.sql b/utils/sql/git/required/2020_01_24_grid_centerpoint_wp.sql new file mode 100644 index 000000000..b4a118242 --- /dev/null +++ b/utils/sql/git/required/2020_01_24_grid_centerpoint_wp.sql @@ -0,0 +1,2 @@ +alter table grid_entries add column `centerpoint` tinyint(4) not null default 0; +alter table spawngroup add column `wp_spawns` tinyint(1) unsigned not null default 0; \ No newline at end of file diff --git a/zone/common.h b/zone/common.h index e06fa134a..2d97527fc 100644 --- a/zone/common.h +++ b/zone/common.h @@ -647,6 +647,19 @@ enum { SKILLUP_FAILURE = 2 }; +enum { + GridCircular, + GridRandom10, + GridRandom, + GridPatrol, + GridOneWayRepop, + GridRand5LoS, + GridOneWayDepop, + GridCenterPoint, + GridRandomCenterPoint, + GridRandomPath +}; + typedef enum { petFamiliar, //only listens to /pet get lost petAnimation, //does not listen to any commands diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 525948bb2..43d85c450 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1693,12 +1693,32 @@ void NPC::AI_DoMovement() { GetZ(), GetGrid()); + if (wandertype == GridRandomPath) + { + if (cur_wp == patrol) + { + // reached our randomly selected destination; force a pause + if (cur_wp_pause == 0) + { + if (Waypoints.size() > 0 && Waypoints[0].pause) + cur_wp_pause = Waypoints[0].pause; + else + cur_wp_pause = 38; + } + Log(Logs::Detail, Logs::AI, "NPC using wander type GridRandomPath on grid %d at waypoint %d has reached its random destination; pause time is %d", GetGrid(), cur_wp, cur_wp_pause); + } + else + cur_wp_pause = 0; // skipping pauses until destination + } + SetWaypointPause(); - SetAppearance(eaStanding, false); - if (cur_wp_pause > 0) { + if (GetAppearance() != eaStanding) { + SetAppearance(eaStanding, false); + } + if (cur_wp_pause > 0 && m_CurrentWayPoint.w >= 0.0) { RotateTo(m_CurrentWayPoint.w); } - + //kick off event_waypoint arrive char temp[16]; sprintf(temp, "%d", cur_wp); @@ -1789,12 +1809,12 @@ void NPC::AI_SetupNextWaypoint() { } } - if (wandertype == 4 && cur_wp == CastToNPC()->GetMaxWp()) { + if (wandertype == GridOneWayRepop && cur_wp == CastToNPC()->GetMaxWp()) { CastToNPC()->Depop(true); //depop and restart spawn timer if (found_spawn) found_spawn->SetNPCPointerNull(); } - else if (wandertype == 6 && cur_wp == CastToNPC()->GetMaxWp()) { + else if (wandertype == GridOneWayDepop && cur_wp == CastToNPC()->GetMaxWp()) { CastToNPC()->Depop(false);//depop without spawn timer if (found_spawn) found_spawn->SetNPCPointerNull(); diff --git a/zone/npc.h b/zone/npc.h index 84ab8b4ef..d0ecdf1ca 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -303,7 +303,7 @@ public: int GetMaxWp() const { return max_wp; } void DisplayWaypointInfo(Client *to); void CalculateNewWaypoint(); - void AssignWaypoints(int32 grid); + void AssignWaypoints(int32 grid, int start_wp = 0); void SetWaypointPause(); void UpdateWaypoint(int wp_index); @@ -312,7 +312,8 @@ public: void ResumeWandering(); void PauseWandering(int pausetime); void MoveTo(const glm::vec4& position, bool saveguardspot); - void GetClosestWaypoint(std::list &wp_list, int count, const glm::vec3& location); + void GetClosestWaypoints(std::list &wp_list, int count, const glm::vec3& location); + int GetClosestWaypoint(const glm::vec3& location); uint32 GetEquippedItemFromTextureSlot(uint8 material_slot) const; // returns item id int32 GetEquipmentMaterial(uint8 material_slot) const; diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index e6d265813..958500550 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -233,6 +233,20 @@ bool Spawn2::Process() { } currentnpcid = npcid; + + glm::vec4 loc(x, y, z, heading); + int starting_wp = 0; + if (spawn_group->wp_spawns && grid_ > 0) + { + glm::vec4 wploc; + starting_wp = database.GetRandomWaypointLocFromGrid(wploc, zone->GetZoneID(), grid_); + if (wploc.x != 0.0f || wploc.y != 0.0f || wploc.z != 0.0f) + { + loc = wploc; + Log(Logs::General, Logs::Spawns, "spawning at random waypoint #%i loc: (%.3f, %.3f, %.3f).", starting_wp , loc.x, loc.y, loc.z); + } + } + NPC *npc = new NPC(tmp, this, glm::vec4(x, y, z, heading), GravityBehavior::Water); npc->mod_prespawn(this); @@ -275,7 +289,7 @@ bool Spawn2::Process() { z ); - LoadGrid(); + LoadGrid(starting_wp); } else { LogSpawns("Spawn2 [{}]: Group [{}] spawned [{}] ([{}]) at ([{}], [{}], [{}]). Grid loading delayed", @@ -302,7 +316,7 @@ void Spawn2::Disable() enabled = false; } -void Spawn2::LoadGrid() { +void Spawn2::LoadGrid(int start_wp) { if (!npcthis) return; if (grid_ < 1) @@ -311,8 +325,8 @@ void Spawn2::LoadGrid() { return; //dont set an NPC's grid until its loaded for them. npcthis->SetGrid(grid_); - npcthis->AssignWaypoints(grid_); - LogSpawns("Spawn2 [{}]: Loading grid [{}] for [{}]", spawn2_id, grid_, npcthis->GetName()); + npcthis->AssignWaypoints(grid_, start_wp); + LogSpawns("Spawn2 [{}]: Loading grid [{}] for [{}]; starting wp is [{}]", spawn2_id, grid_, npcthis->GetName(), start_wp); } /* diff --git a/zone/spawn2.h b/zone/spawn2.h index a626b7084..bf6530876 100644 --- a/zone/spawn2.h +++ b/zone/spawn2.h @@ -36,7 +36,7 @@ public: uint16 cond_id = SC_AlwaysEnabled, int16 min_value = 0, bool in_enabled = true, EmuAppearance anim = eaStanding); ~Spawn2(); - void LoadGrid(); + void LoadGrid(int start_wp = 0); void Enable() { enabled = true; } void Disable(); bool Enabled() { return enabled; } diff --git a/zone/spawngroup.cpp b/zone/spawngroup.cpp index cc3735386..6a7817bce 100644 --- a/zone/spawngroup.cpp +++ b/zone/spawngroup.cpp @@ -48,7 +48,8 @@ SpawnGroup::SpawnGroup( int delay_in, int despawn_in, uint32 despawn_timer_in, - int min_delay_in + int min_delay_in, + bool wp_spawns_in ) { id = in_id; @@ -63,6 +64,7 @@ SpawnGroup::SpawnGroup( delay = delay_in; despawn = despawn_in; despawn_timer = despawn_timer_in; + wp_spawns = wp_spawns_in; } uint32 SpawnGroup::GetNPCType(uint16 in_filter) @@ -198,7 +200,8 @@ bool ZoneDatabase::LoadSpawnGroups(const char *zone_name, uint16 version, SpawnG spawngroup.delay, spawngroup.despawn, spawngroup.despawn_timer, - spawngroup.mindelay + spawngroup.mindelay, + spawngroup.wp_spawns FROM spawn2, spawngroup @@ -229,7 +232,8 @@ bool ZoneDatabase::LoadSpawnGroups(const char *zone_name, uint16 version, SpawnG atoi(row[8]), atoi(row[9]), atoi(row[10]), - atoi(row[11]) + atoi(row[11]), + atoi(row[12]) ); spawn_group_list->AddSpawnGroup(new_spawn_group); @@ -305,7 +309,8 @@ bool ZoneDatabase::LoadSpawnGroupsByID(int spawn_group_id, SpawnGroupList *spawn spawngroup.delay, spawngroup.despawn, spawngroup.despawn_timer, - spawngroup.mindelay + spawngroup.mindelay, + spawngroup.wp_spawns FROM spawngroup WHERE @@ -332,7 +337,8 @@ bool ZoneDatabase::LoadSpawnGroupsByID(int spawn_group_id, SpawnGroupList *spawn atoi(row[8]), atoi(row[9]), atoi(row[10]), - atoi(row[11]) + atoi(row[11]), + atoi(row[12]) ); spawn_group_list->AddSpawnGroup(new_spawn_group); diff --git a/zone/spawngroup.h b/zone/spawngroup.h index 2a4c1af6c..a1068cea0 100644 --- a/zone/spawngroup.h +++ b/zone/spawngroup.h @@ -49,13 +49,15 @@ public: int delay_in, int despawn_in, uint32 despawn_timer_in, - int min_delay_in + int min_delay_in, + bool wp_spawns_in ); ~SpawnGroup(); uint32 GetNPCType(uint16 condition_value_filter=1); void AddSpawnEntry(SpawnEntry *newEntry); uint32 id; + bool wp_spawns; // if true, spawn NPCs at a random waypoint location (if spawnpoint has a grid) instead of the spawnpoint's loc float roamdist; float roambox[4]; int min_delay; diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index b6033744c..0bd18edbf 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -244,14 +244,14 @@ void NPC::CalculateNewWaypoint() int old_wp = cur_wp; bool reached_end = false; bool reached_beginning = false; - if (cur_wp == max_wp) + if (cur_wp == max_wp - 1) //cur_wp starts at 0, max_wp starts at 1. reached_end = true; if (cur_wp == 0) reached_beginning = true; switch (wandertype) { - case 0: //circle + case GridCircular: { if (reached_end) cur_wp = 0; @@ -259,10 +259,10 @@ void NPC::CalculateNewWaypoint() cur_wp = cur_wp + 1; break; } - case 1: //10 closest + case GridRandom10: { std::list closest; - GetClosestWaypoint(closest, 10, glm::vec3(GetPosition())); + GetClosestWaypoints(closest, 10, glm::vec3(GetPosition())); auto iter = closest.begin(); if (closest.size() != 0) { @@ -273,30 +273,64 @@ void NPC::CalculateNewWaypoint() break; } - case 2: //random + case GridRandom: + case GridCenterPoint: { - cur_wp = zone->random.Int(0, Waypoints.size() - 1); - if (cur_wp == old_wp) + if (wandertype == GridCenterPoint && !reached_beginning) { - if (cur_wp == (Waypoints.size() - 1)) + cur_wp = 0; + } + else + { + cur_wp = zone->random.Int(0, Waypoints.size() - 1); + if (cur_wp == old_wp || (wandertype == GridCenterPoint && cur_wp == 0)) { - if (cur_wp > 0) + if (cur_wp == (Waypoints.size() - 1)) { - cur_wp--; + if (cur_wp > 0) + { + cur_wp--; + } } - } - else if (cur_wp == 0) - { - if ((Waypoints.size() - 1) > 0) + else if (cur_wp == 0) { - cur_wp++; + if ((Waypoints.size() - 1) > 0) + { + cur_wp++; + } } } } break; } - case 3: //patrol + case GridRandomCenterPoint: + { + bool on_center = Waypoints[cur_wp].centerpoint; + std::vector random_waypoints; + for (auto &w : Waypoints) + { + wplist wpl = w; + if (wpl.index != cur_wp && + ((on_center && !wpl.centerpoint) || (!on_center && wpl.centerpoint))) + { + random_waypoints.push_back(w); + } + } + + if (random_waypoints.size() == 0) + { + cur_wp = 0; + } + else + { + int windex = zone->random.Roll0(random_waypoints.size()); + cur_wp = random_waypoints[windex].index; + } + + break; + } + case GridPatrol: { if (reached_end) patrol = 1; @@ -309,16 +343,16 @@ void NPC::CalculateNewWaypoint() break; } - case 4: //goto the end and depop with spawn timer - case 6: //goto the end and depop without spawn timer + case GridOneWayRepop: + case GridOneWayDepop: { cur_wp = cur_wp + 1; break; } - case 5: //pick random closest 5 and pick one that's in sight + case GridRand5LoS: { std::list closest; - GetClosestWaypoint(closest, 5, glm::vec3(GetPosition())); + GetClosestWaypoints(closest, 5, glm::vec3(GetPosition())); auto iter = closest.begin(); while (iter != closest.end()) @@ -341,6 +375,25 @@ void NPC::CalculateNewWaypoint() } break; } + case GridRandomPath: // randomly select a waypoint but follow path to it instead of walk directly to it ignoring walls + { + if (Waypoints.size() == 0) + { + cur_wp = 0; + } + else + { + if (cur_wp == patrol) // reutilizing patrol member instead of making new member for this wander type; here we use it to save a random waypoint + { + while (patrol == cur_wp) + patrol = zone->random.Int(0, Waypoints.size() - 1); + } + if (patrol > cur_wp) + cur_wp = cur_wp + 1; + else + cur_wp = cur_wp - 1; + } + } } // Preserve waypoint setting for quest controlled NPCs @@ -357,7 +410,30 @@ bool wp_distance_pred(const wp_distance& left, const wp_distance& right) return left.dist < right.dist; } -void NPC::GetClosestWaypoint(std::list &wp_list, int count, const glm::vec3& location) +int NPC::GetClosestWaypoint(const glm::vec3& location) +{ + if (Waypoints.size() <= 1) + return 0; + + int closest = 0; + float closestDist = 9999999.0f; + float dist; + + for (int i = 0; i < Waypoints.size(); ++i) + { + dist = DistanceSquared(location, glm::vec3(Waypoints[i].x, Waypoints[i].y, Waypoints[i].z)); + + if (dist < closestDist) + { + closestDist = dist; + closest = i; + } + } + return closest; +} + +// fills wp_list with the closest count number of waypoints +void NPC::GetClosestWaypoints(std::list &wp_list, int count, const glm::vec3& location) { wp_list.clear(); if (Waypoints.size() <= count) @@ -485,7 +561,7 @@ void Mob::StopNavigation() { mMovementManager->StopNavigation(this); } -void NPC::AssignWaypoints(int32 grid) +void NPC::AssignWaypoints(int32 grid, int start_wp) { if (grid == 0) return; // grid ID 0 not supported @@ -518,7 +594,7 @@ void NPC::AssignWaypoints(int32 grid) SetGrid(grid); // Assign grid number // Retrieve all waypoints for this grid - query = StringFormat("SELECT `x`,`y`,`z`,`pause`,`heading` " + query = StringFormat("SELECT `x`,`y`,`z`,`pause`,`heading`, `centerpoint` " "FROM grid_entries WHERE `gridid` = %i AND `zoneid` = %i " "ORDER BY `number`", grid, zone->GetZoneID()); results = database.QueryDatabase(query); @@ -539,14 +615,22 @@ void NPC::AssignWaypoints(int32 grid) newwp.pause = atoi(row[3]); newwp.heading = atof(row[4]); + newwp.centerpoint = atobool(row[5]); Waypoints.push_back(newwp); } - UpdateWaypoint(0); + cur_wp = start_wp; + UpdateWaypoint(start_wp); SetWaypointPause(); - if (wandertype == 1 || wandertype == 2 || wandertype == 5) + if (wandertype == GridRandomPath) { + cur_wp = GetClosestWaypoint(glm::vec3(GetPosition())); + patrol = cur_wp; + } + + if (wandertype == GridRandom10 || wandertype == GridRandom || wandertype == GridRand5LoS) CalculateNewWaypoint(); + } void Mob::SendTo(float new_x, float new_y, float new_z) { @@ -1058,6 +1142,37 @@ int ZoneDatabase::GetHighestWaypoint(uint32 zoneid, uint32 gridid) { return atoi(row[0]); } +int ZoneDatabase::GetRandomWaypointLocFromGrid(glm::vec4 &loc, uint16 zoneid, int grid) +{ + loc.x = loc.y = loc.z = loc.w = 0.0f; + + std::string query = StringFormat("SELECT `x`,`y`,`z`,`heading` " + "FROM grid_entries WHERE `gridid` = %i AND `zoneid` = %u ORDER BY `number`", grid, zone->GetZoneID()); + auto results = database.QueryDatabase(query); + if (!results.Success()) { + Log(Logs::General, Logs::Error, "MySQL Error while trying get random waypoint loc from grid %i in zoneid %u; %s", grid, zoneid, results.ErrorMessage().c_str()); + return 0; + } + + if (results.RowCount() > 0) + { + int roll = zone->random.Int(0, results.RowCount() - 1); + int i = 0; + auto row = results.begin(); + while (i < roll) + { + row++; + i++; + } + loc.x = atof(row[0]); + loc.y = atof(row[1]); + loc.z = atof(row[2]); + loc.w = atof(row[3]); + return i; + } + return 0; +} + void NPC::SaveGuardSpotCharm() { m_GuardPointSaved = m_GuardPoint; diff --git a/zone/zonedb.h b/zone/zonedb.h index f28ac5ec4..d5c02c693 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -47,6 +47,7 @@ struct wplist { float z; int pause; float heading; + bool centerpoint; }; #pragma pack(1) @@ -434,6 +435,7 @@ public: void AssignGrid(Client *client, int grid, int spawn2id); int GetHighestGrid(uint32 zoneid); int GetHighestWaypoint(uint32 zoneid, uint32 gridid); + int GetRandomWaypointLocFromGrid(glm::vec4 &loc, uint16 zoneid, int grid); /* NPCs */ From ff897dc90ab302346a2ca6a50bf83242ca7ea8e4 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Fri, 24 Jan 2020 20:36:33 -0500 Subject: [PATCH 42/57] Update CURRENT_BINARY_DATABASE_VERSION --- common/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/version.h b/common/version.h index 0f659d57b..5d00daaf4 100644 --- a/common/version.h +++ b/common/version.h @@ -34,7 +34,7 @@ * Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9146 +#define CURRENT_BINARY_DATABASE_VERSION 9147 #ifdef BOTS #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9026 From 2f49266d086e80e8b76150d85c6847bd1fb90caf Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sat, 25 Jan 2020 18:26:59 -0600 Subject: [PATCH 43/57] Fix bots db updates when bins are in bin folder [skip ci] --- utils/scripts/eqemu_server.pl | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/utils/scripts/eqemu_server.pl b/utils/scripts/eqemu_server.pl index 76084f23f..2c769e811 100755 --- a/utils/scripts/eqemu_server.pl +++ b/utils/scripts/eqemu_server.pl @@ -2216,11 +2216,18 @@ sub get_bots_db_version { } sub bots_db_management { + + my $world_path = "world"; + if (-e "bin/world") { + $world_path = "bin/world"; + } + + #::: Get Binary DB version if ($OS eq "Windows") { - @db_version = split(': ', `world db_version`); + @db_version = split(': ', `$world_path db_version`); } if ($OS eq "Linux") { - @db_version = split(': ', `./world db_version`); + @db_version = split(': ', `./$world_path db_version`); } #::: Main Binary Database version From 6514ccc41c80edf6ce3dd93156ac4169553018f3 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sat, 25 Jan 2020 18:30:52 -0600 Subject: [PATCH 44/57] Bot updates are killing running regular updates afterwards [skip ci] --- utils/scripts/eqemu_server.pl | 3 --- 1 file changed, 3 deletions(-) diff --git a/utils/scripts/eqemu_server.pl b/utils/scripts/eqemu_server.pl index 2c769e811..40762a2bd 100755 --- a/utils/scripts/eqemu_server.pl +++ b/utils/scripts/eqemu_server.pl @@ -547,10 +547,7 @@ sub check_for_world_bootup_database_update { sleep(1); bots_db_management(); run_database_check(); - print "[Update] Continuing bootup\n"; analytics_insertion("auto database bots upgrade world", $db . " :: Binary DB Version / Local DB Version :: " . $binary_database_version . " / " . $local_database_version); - - exit; } else { print "[Update] Bots database up to Date: Continuing World Bootup...\n"; From c6ba29f2e5449920bd1c822efe7fb7267cd3d0ed Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sat, 25 Jan 2020 18:41:15 -0600 Subject: [PATCH 45/57] Revert commit until further testing [skip ci] --- utils/scripts/eqemu_server.pl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/utils/scripts/eqemu_server.pl b/utils/scripts/eqemu_server.pl index 40762a2bd..2c769e811 100755 --- a/utils/scripts/eqemu_server.pl +++ b/utils/scripts/eqemu_server.pl @@ -547,7 +547,10 @@ sub check_for_world_bootup_database_update { sleep(1); bots_db_management(); run_database_check(); + print "[Update] Continuing bootup\n"; analytics_insertion("auto database bots upgrade world", $db . " :: Binary DB Version / Local DB Version :: " . $binary_database_version . " / " . $local_database_version); + + exit; } else { print "[Update] Bots database up to Date: Continuing World Bootup...\n"; From c82d08cf11adc85c0c3edc91852c98c6069bf92c Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 26 Jan 2020 16:31:15 -0600 Subject: [PATCH 46/57] Make sure character soft deletes do not reserve name once deleted, add optional retro script to run for servers who had soft deletes running prior to this commit --- common/database.cpp | 1 + .../git/optional/2020_01_26_soft_delete_retro.sql | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 utils/sql/git/optional/2020_01_26_soft_delete_retro.sql diff --git a/common/database.cpp b/common/database.cpp index f6adc3659..ac5ae16bf 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -371,6 +371,7 @@ bool Database::DeleteCharacter(char *character_name) { UPDATE character_data SET + name = SUBSTRING(CONCAT(name, '-deleted-', UNIX_TIMESTAMP()), 1, 64), deleted_at = NOW() WHERE id = '{}' diff --git a/utils/sql/git/optional/2020_01_26_soft_delete_retro.sql b/utils/sql/git/optional/2020_01_26_soft_delete_retro.sql new file mode 100644 index 000000000..d3d0c7c4b --- /dev/null +++ b/utils/sql/git/optional/2020_01_26_soft_delete_retro.sql @@ -0,0 +1,12 @@ +-- Run this to un-reserve deleted characters +UPDATE + character_data +SET + name = SUBSTRING( + CONCAT(name, '-deleted-', UNIX_TIMESTAMP()), + 1, + 64 + ) +WHERE + deleted_at IS NOT NULL + AND name NOT LIKE '%-deleted-%'; \ No newline at end of file From 43da07fb55231eb520113a5745c36aab91e5d2bf Mon Sep 17 00:00:00 2001 From: hg <4683435+hgtw@users.noreply.github.com> Date: Tue, 28 Jan 2020 19:04:47 -0500 Subject: [PATCH 47/57] Fix zone crash when a group member raid invites own group leader --- zone/client_packet.cpp | 5 +++++ zone/string_ids.h | 1 + 2 files changed, 6 insertions(+) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index ebc6bd38a..dfb7ab673 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -11130,6 +11130,11 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) break; } + if (player_to_invite_group && player_to_invite_group->IsGroupMember(this)) { + MessageString(Chat::Red, ALREADY_IN_PARTY); + break; + } + if (player_to_invite_group && !player_to_invite_group->IsLeader(player_to_invite)) { Message(Chat::Red, "You can only invite an ungrouped player or group leader to join your raid."); break; diff --git a/zone/string_ids.h b/zone/string_ids.h index 0948d13a8..25321b3c9 100644 --- a/zone/string_ids.h +++ b/zone/string_ids.h @@ -417,6 +417,7 @@ #define TARGET_PLAYER_FOR_GUILD_STATUS 12260 #define GROUP_INVITEE_NOT_FOUND 12268 //You must target a player or use /invite to invite someone to your group. #define GROUP_INVITEE_SELF 12270 //12270 You cannot invite yourself. +#define ALREADY_IN_PARTY 12272 //That person is already in your party. #define NO_LONGER_HIDDEN 12337 //You are no longer hidden. #define STOP_SNEAKING 12338 //You stop sneaking #define NOT_IN_CONTROL 12368 //You do not have control of yourself right now. From 92d32feb0dd98de4a8460292b9ff84ab11697382 Mon Sep 17 00:00:00 2001 From: Uleat Date: Tue, 28 Jan 2020 21:24:14 -0500 Subject: [PATCH 48/57] Fix for player hp updates not matching between client and server --- zone/client_mods.cpp | 4 ++++ zone/mob.cpp | 15 ++++++++++++++- zone/mob.h | 1 + zone/spell_effects.cpp | 3 +++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/zone/client_mods.cpp b/zone/client_mods.cpp index 2d61a59ec..255201090 100644 --- a/zone/client_mods.cpp +++ b/zone/client_mods.cpp @@ -336,6 +336,10 @@ int32 Client::CalcMaxHP() current_hp = curHP_cap; } } + + // hack fix for client health not reflecting server value + last_max_hp = 0; + return max_hp; } diff --git a/zone/mob.cpp b/zone/mob.cpp index 71e876938..a6de82eee 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -186,6 +186,7 @@ Mob::Mob( last_hp_percent = 0; last_hp = 0; + last_max_hp = 0; current_speed = base_runspeed; @@ -1334,6 +1335,16 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal * If our HP is different from last HP update call - let's update selves */ if (IsClient()) { + + // delay to allow the client to catch up on buff states + if (max_hp != last_max_hp) { + + last_max_hp = max_hp; + CastToClient()->hp_self_update_throttle_timer.Trigger(); + + return; + } + if (current_hp != last_hp || force_update_all) { /** @@ -1341,10 +1352,12 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal */ if (this->CastToClient()->hp_self_update_throttle_timer.Check() || force_update_all) { Log(Logs::General, Logs::HPUpdate, - "Mob::SendHPUpdate :: Update HP of self (%s) HP: %i last: %i skip_self: %s", + "Mob::SendHPUpdate :: Update HP of self (%s) HP: %i/%i last: %i/%i skip_self: %s", this->GetCleanName(), current_hp, + max_hp, last_hp, + last_max_hp, (skip_self ? "true" : "false") ); diff --git a/zone/mob.h b/zone/mob.h index d48f47e6d..7c095a001 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -1526,6 +1526,7 @@ protected: int8 last_hp_percent; int32 last_hp; + int32 last_max_hp; int cur_wp; glm::vec4 m_CurrentWayPoint; diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 693222e9f..63a4a113f 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -286,6 +286,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove dmg = -dmg; } + // hack fix for client health not reflecting server value + last_hp = 0; + //do any AAs apply to these spells? if(dmg < 0) { if (!PassCastRestriction(false, spells[spell_id].base2[i], true)) From 712366293d661c3d37452f7cfb4ac80cfe84ce86 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Thu, 30 Jan 2020 11:10:57 -0500 Subject: [PATCH 49/57] Further refine monk weight checks for floating point --- zone/attack.cpp | 51 ++++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/zone/attack.cpp b/zone/attack.cpp index 911f22dfb..da8dd6e3d 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -659,85 +659,88 @@ int Mob::GetClassRaceACBonus() auto level = GetLevel(); if (GetClass() == MONK) { int hardcap = 30; - int softcap = 14; + double softcap = 14.9; if (level > 99) { hardcap = 58; - softcap = 35; + softcap = 35.9; } else if (level > 94) { hardcap = 57; - softcap = 34; + softcap = 34.9; } else if (level > 89) { hardcap = 56; - softcap = 33; + softcap = 33.9; } else if (level > 84) { hardcap = 55; - softcap = 32; + softcap = 32.9; } else if (level > 79) { hardcap = 54; - softcap = 31; + softcap = 31.9; } else if (level > 74) { hardcap = 53; - softcap = 30; + softcap = 30.9; } else if (level > 69) { hardcap = 53; - softcap = 28; + softcap = 28.9; } else if (level > 64) { hardcap = 53; - softcap = 26; + softcap = 26.9; } else if (level > 63) { hardcap = 50; - softcap = 24; + softcap = 24.9; } else if (level > 61) { hardcap = 47; - softcap = 24; + softcap = 24.9; } else if (level > 59) { hardcap = 45; - softcap = 24; + softcap = 24.9; } else if (level > 54) { hardcap = 40; - softcap = 20; + softcap = 20.9; } else if (level > 50) { hardcap = 38; - softcap = 18; + softcap = 18.9; } else if (level > 44) { hardcap = 36; - softcap = 17; + softcap = 17.9; } else if (level > 29) { hardcap = 34; - softcap = 16; + softcap = 16.9; } else if (level > 14) { hardcap = 32; - softcap = 15; + softcap = 15.9; } - int weight = IsClient() ? CastToClient()->CalcCurrentWeight()/10 : 0; + + double weight = IsClient() ? CastToClient()->CalcCurrentWeight()/10.0 : 0; + if (weight < hardcap - 1) { - int temp = level + 5; + double temp = level + 5; if (weight > softcap) { double redux = (weight - softcap) * 6.66667; - redux = (100.0 - std::min(100.0, redux)) * 0.01; - temp = std::max(0, static_cast(temp * redux)); + redux = (100.0 - redux) * 0.01; + temp = temp * redux; } - ac_bonus = (4 * temp) / 3; + ac_bonus = (4.0 * temp) / 3; + //LogError("weight[{}] temp[{}] ac_bonus[{}]", weight, temp, ac_bonus); } else if (weight > hardcap + 1) { - int temp = level + 5; + double temp = level + 5; double multiplier = std::min(1.0, (weight - (hardcap - 10.0)) / 100.0); - temp = (4 * temp) / 3; + temp = (4.0 * temp) / 3; ac_bonus -= static_cast(temp * multiplier); } } From f968d0df4c9a0493ceb5535d31d764a74d2cfa7d Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Thu, 30 Jan 2020 15:04:06 -0500 Subject: [PATCH 50/57] Reduce changes to those suggested by @mackal --- zone/attack.cpp | 54 ++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/zone/attack.cpp b/zone/attack.cpp index da8dd6e3d..724a8575a 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -655,92 +655,92 @@ double Mob::GetSoftcapReturns() int Mob::GetClassRaceACBonus() { + int ac_bonus = 0; + auto level = GetLevel(); + if (GetClass() == MONK) { int ac_bonus = 0; auto level = GetLevel(); if (GetClass() == MONK) { int hardcap = 30; - double softcap = 14.9; + int softcap = 14; if (level > 99) { hardcap = 58; - softcap = 35.9; + softcap = 35; } else if (level > 94) { hardcap = 57; - softcap = 34.9; + softcap = 34; } else if (level > 89) { hardcap = 56; - softcap = 33.9; + softcap = 33; } else if (level > 84) { hardcap = 55; - softcap = 32.9; + softcap = 32; } else if (level > 79) { hardcap = 54; - softcap = 31.9; + softcap = 31; } else if (level > 74) { hardcap = 53; - softcap = 30.9; + softcap = 30; } else if (level > 69) { hardcap = 53; - softcap = 28.9; + softcap = 28; } else if (level > 64) { hardcap = 53; - softcap = 26.9; + softcap = 26; } else if (level > 63) { hardcap = 50; - softcap = 24.9; + softcap = 24; } else if (level > 61) { hardcap = 47; - softcap = 24.9; + softcap = 24; } else if (level > 59) { hardcap = 45; - softcap = 24.9; + softcap = 24; } else if (level > 54) { hardcap = 40; - softcap = 20.9; + softcap = 20; } else if (level > 50) { hardcap = 38; - softcap = 18.9; + softcap = 18; } else if (level > 44) { hardcap = 36; - softcap = 17.9; + softcap = 17; } else if (level > 29) { hardcap = 34; - softcap = 16.9; + softcap = 16; } else if (level > 14) { hardcap = 32; - softcap = 15.9; + softcap = 15; } - - double weight = IsClient() ? CastToClient()->CalcCurrentWeight()/10.0 : 0; - + double weight = IsClient() ? CastToClient()->CalcCurrentWeight()/10.0:0; if (weight < hardcap - 1) { double temp = level + 5; if (weight > softcap) { - double redux = (weight - softcap) * 6.66667; - redux = (100.0 - redux) * 0.01; - temp = temp * redux; + double redux = static_cast(weight - softcap) * 6.66667; + redux = (100.0 - std::min(100.0, redux)) * 0.01; + temp = std::max(0.0, temp * redux); } - ac_bonus = (4.0 * temp) / 3; - //LogError("weight[{}] temp[{}] ac_bonus[{}]", weight, temp, ac_bonus); + ac_bonus = static_cast((4.0 * temp) / 3.0); } else if (weight > hardcap + 1) { double temp = level + 5; - double multiplier = std::min(1.0, (weight - (hardcap - 10.0)) / 100.0); - temp = (4.0 * temp) / 3; + double multiplier = std::min(1.0, (weight - (static_cast(hardcap) - 10.0)) / 100.0); + temp = (4.0 * temp) / 3.0; ac_bonus -= static_cast(temp * multiplier); } } From bcb08f99f089329f768f0f60eb5ad477ca10ef3d Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Thu, 30 Jan 2020 15:05:41 -0500 Subject: [PATCH 51/57] Update attack.cpp --- zone/attack.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/zone/attack.cpp b/zone/attack.cpp index 724a8575a..f532fc04a 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -655,9 +655,6 @@ double Mob::GetSoftcapReturns() int Mob::GetClassRaceACBonus() { - int ac_bonus = 0; - auto level = GetLevel(); - if (GetClass() == MONK) { int ac_bonus = 0; auto level = GetLevel(); if (GetClass() == MONK) { From 83ad9c86dbed0545de661774baf03dd973e57f3f Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Thu, 30 Jan 2020 15:19:02 -0500 Subject: [PATCH 52/57] Update attack.cpp --- zone/attack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/attack.cpp b/zone/attack.cpp index f532fc04a..308592041 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -724,7 +724,7 @@ int Mob::GetClassRaceACBonus() hardcap = 32; softcap = 15; } - double weight = IsClient() ? CastToClient()->CalcCurrentWeight()/10.0:0; + int weight = IsClient() ? CastToClient()->CalcCurrentWeight()/10 : 0; if (weight < hardcap - 1) { double temp = level + 5; if (weight > softcap) { From 50a39057e4bfd36141d69aa16539b60bdbfa1dca Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sat, 1 Feb 2020 19:27:15 -0500 Subject: [PATCH 53/57] Update QuestReward_Struct --- common/eq_packet_structs.h | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index 53d7021ba..3fe2430db 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -35,6 +35,7 @@ static const uint32 MAX_MERC = 100; static const uint32 MAX_MERC_GRADES = 10; static const uint32 MAX_MERC_STANCES = 10; static const uint32 BLOCKED_BUFF_COUNT = 20; +static const uint32 QUESTREWARD_COUNT = 8; /* @@ -2180,14 +2181,7 @@ struct QuestReward_Struct /*024*/ uint32 silver; // Gives silver to the client /*028*/ uint32 gold; // Gives gold to the client /*032*/ uint32 platinum; // Gives platinum to the client - /*036*/ uint32 item_id; - /*040*/ uint32 unknown040; - /*044*/ uint32 unknown044; - /*048*/ uint32 unknown048; - /*052*/ uint32 unknown052; - /*056*/ uint32 unknown056; - /*060*/ uint32 unknown060; - /*064*/ uint32 unknown064; + /*036*/ int32 item_id[QUESTREWARD_COUNT]; // -1 for nothing /*068*/ }; From b02e87cce72a9a413de3213aeaa91883e2ce26bc Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sat, 1 Feb 2020 19:54:26 -0500 Subject: [PATCH 54/57] Fix Client::QuestReward for struct adjustment --- zone/client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/client.cpp b/zone/client.cpp index 9ea27869a..eb157dc2f 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -8539,7 +8539,7 @@ void Client::QuestReward(Mob* target, uint32 copper, uint32 silver, uint32 gold, qr->silver = silver; qr->gold = gold; qr->platinum = platinum; - qr->item_id = itemid; + qr->item_id[0] = itemid; qr->exp_reward = exp; if (copper > 0 || silver > 0 || gold > 0 || platinum > 0) From ab3d65b2ea344fed0f6bf1fdcc5b92ce0ec2989c Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Sat, 1 Feb 2020 20:29:48 -0500 Subject: [PATCH 55/57] Fix FixZ regarding the use of model in npc_types This fix only impacts those that use the model field in npc_types to override race on the client. GetModel() returns model if set, otherwise race. As a refresher, the model field is there so the server can still see a mob as its base race for things like bane, while the client can use a new model. FixZ needs to know about this. --- zone/waypoints.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index 0bd18edbf..65f4fd099 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -771,7 +771,7 @@ void Mob::FixZ(int32 z_find_offset /*= 5*/, bool fix_client_z /*= false*/) { float Mob::GetZOffset() const { float offset = 3.125f; - switch (race) { + switch (GetModel()) { case RACE_BASILISK_436: offset = 0.577f; break; From 59903313e4c46ff8b7cae6b8c7eb7b6d46a35f82 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sat, 1 Feb 2020 22:20:19 -0500 Subject: [PATCH 56/57] Expand Lua's Client QuestReward function You can now use it to summon up to 8 items ex: `e.other:QuestReward(e.self, {items = {28745, 28092}, exp = 250})` This expands the version that takes a table. The new item is a table (in the main table) called items, which needs to be auto keyed like the example above. If you also provide the old itemid key, it will be ignored if the items is there. --- zone/client.cpp | 36 ++++++++++++++++++++++++++++++ zone/client.h | 1 + zone/lua_client.cpp | 54 ++++++++++++++++++++++++++++++++++----------- 3 files changed, 78 insertions(+), 13 deletions(-) diff --git a/zone/client.cpp b/zone/client.cpp index eb157dc2f..acbb7cc74 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -8566,6 +8566,42 @@ void Client::QuestReward(Mob* target, uint32 copper, uint32 silver, uint32 gold, safe_delete(outapp); } +void Client::QuestReward(Mob* target, const QuestReward_Struct &reward, bool faction) +{ + auto outapp = new EQApplicationPacket(OP_Sound, sizeof(QuestReward_Struct)); + memset(outapp->pBuffer, 0, sizeof(QuestReward_Struct)); + QuestReward_Struct* qr = (QuestReward_Struct*)outapp->pBuffer; + + memcpy(qr, &reward, sizeof(QuestReward_Struct)); + + // not set in caller because reasons + qr->mob_id = target->GetID(); // Entity ID for the from mob name + + if (reward.copper > 0 || reward.silver > 0 || reward.gold > 0 || reward.platinum > 0) + AddMoneyToPP(reward.copper, reward.silver, reward.gold, reward.platinum, false); + + for (int i = 0; i < QUESTREWARD_COUNT; ++i) + if (reward.item_id[i] > 0) + SummonItem(reward.item_id[i], 0, 0, 0, 0, 0, 0, false, EQEmu::invslot::slotCursor); + + if (faction) + { + if (target->IsNPC()) + { + int32 nfl_id = target->CastToNPC()->GetNPCFactionID(); + SetFactionLevel(CharacterID(), nfl_id, GetBaseClass(), GetBaseRace(), GetDeity(), true); + qr->faction = target->CastToNPC()->GetPrimaryFaction(); + qr->faction_mod = 1; // Too lazy to get real value, not sure if this is even used by client anyhow. + } + } + + if (reward.exp_reward> 0) + AddEXP(reward.exp_reward); + + QueuePacket(outapp, true, Client::CLIENT_CONNECTED); + safe_delete(outapp); +} + void Client::SendHPUpdateMarquee(){ if (!this || !this->IsClient() || !this->current_hp || !this->max_hp) return; diff --git a/zone/client.h b/zone/client.h index 4ff431520..300073bb5 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1282,6 +1282,7 @@ public: int32 GetMeleeDamage(Mob* other, bool GetMinDamage = false); void QuestReward(Mob* target, uint32 copper = 0, uint32 silver = 0, uint32 gold = 0, uint32 platinum = 0, uint32 itemid = 0, uint32 exp = 0, bool faction = false); + void QuestReward(Mob* target, const QuestReward_Struct &reward, bool faction); // TODO: Fix faction processing void ResetHPUpdateTimer() { hpupdate_timer.Start(); } diff --git a/zone/lua_client.cpp b/zone/lua_client.cpp index 14c009b12..9d0873360 100644 --- a/zone/lua_client.cpp +++ b/zone/lua_client.cpp @@ -1385,18 +1385,23 @@ void Lua_Client::QuestReward(Lua_Mob target, luabind::adl::object reward) { return; } - uint32 copper = 0; - uint32 silver = 0; - uint32 gold = 0; - uint32 platinum = 0; - uint32 itemid = 0; - uint32 exp = 0; + QuestReward_Struct quest_reward; + quest_reward.mob_id = 0; + quest_reward.target_id = self->GetID(); + quest_reward.copper = 0; + quest_reward.silver = 0; + quest_reward.gold = 0; + quest_reward.platinum = 0; + quest_reward.exp_reward = 0; + quest_reward.faction = 0; + quest_reward.faction_mod = 0; bool faction = false; + std::fill(std::begin(quest_reward.item_id), std::end(quest_reward.item_id), -1); auto cur = reward["copper"]; if (luabind::type(cur) != LUA_TNIL) { try { - copper = luabind::object_cast(cur); + quest_reward.copper = luabind::object_cast(cur); } catch (luabind::cast_failed &) { } } @@ -1404,7 +1409,7 @@ void Lua_Client::QuestReward(Lua_Mob target, luabind::adl::object reward) { cur = reward["silver"]; if (luabind::type(cur) != LUA_TNIL) { try { - silver = luabind::object_cast(cur); + quest_reward.silver = luabind::object_cast(cur); } catch (luabind::cast_failed &) { } } @@ -1412,7 +1417,7 @@ void Lua_Client::QuestReward(Lua_Mob target, luabind::adl::object reward) { cur = reward["gold"]; if (luabind::type(cur) != LUA_TNIL) { try { - gold = luabind::object_cast(cur); + quest_reward.gold = luabind::object_cast(cur); } catch (luabind::cast_failed &) { } } @@ -1420,7 +1425,7 @@ void Lua_Client::QuestReward(Lua_Mob target, luabind::adl::object reward) { cur = reward["platinum"]; if (luabind::type(cur) != LUA_TNIL) { try { - platinum = luabind::object_cast(cur); + quest_reward.platinum = luabind::object_cast(cur); } catch (luabind::cast_failed &) { } } @@ -1428,7 +1433,30 @@ void Lua_Client::QuestReward(Lua_Mob target, luabind::adl::object reward) { cur = reward["itemid"]; if (luabind::type(cur) != LUA_TNIL) { try { - itemid = luabind::object_cast(cur); + quest_reward.item_id[0] = luabind::object_cast(cur); + } catch (luabind::cast_failed &) { + } + } + + // if you define both an itemid and items table, the itemid is thrown away + // should we error? + cur = reward["items"]; + if (luabind::type(cur) == LUA_TTABLE) { + try { + // assume they defined a compatible table + for (int i = 1; i <= QUESTREWARD_COUNT; ++i) { + auto item = cur[i]; + int cur_value = -1; + if (luabind::type(item) != LUA_TNIL) { + try { + cur_value = luabind::object_cast(item); + } catch (luabind::cast_failed &) { + } + } else { + break; + } + quest_reward.item_id[i - 1] = cur_value; + } } catch (luabind::cast_failed &) { } } @@ -1436,7 +1464,7 @@ void Lua_Client::QuestReward(Lua_Mob target, luabind::adl::object reward) { cur = reward["exp"]; if (luabind::type(cur) != LUA_TNIL) { try { - exp = luabind::object_cast(cur); + quest_reward.exp_reward = luabind::object_cast(cur); } catch (luabind::cast_failed &) { } } @@ -1449,7 +1477,7 @@ void Lua_Client::QuestReward(Lua_Mob target, luabind::adl::object reward) { } } - self->QuestReward(target, copper, silver, gold, platinum, itemid, exp, faction); + self->QuestReward(target, quest_reward, faction); } bool Lua_Client::IsDead() { From 424b669cbbe574764d121d65f97722e01a92c906 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sun, 2 Feb 2020 16:39:46 -0500 Subject: [PATCH 57/57] Target not required for newer clients in QuestReward --- zone/client.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/zone/client.cpp b/zone/client.cpp index acbb7cc74..6b366afba 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -8533,7 +8533,7 @@ void Client::QuestReward(Mob* target, uint32 copper, uint32 silver, uint32 gold, memset(outapp->pBuffer, 0, sizeof(QuestReward_Struct)); QuestReward_Struct* qr = (QuestReward_Struct*)outapp->pBuffer; - qr->mob_id = target->GetID(); // Entity ID for the from mob name + qr->mob_id = target ? target->GetID() : 0; // Entity ID for the from mob name qr->target_id = GetID(); // The Client ID (this) qr->copper = copper; qr->silver = silver; @@ -8550,7 +8550,7 @@ void Client::QuestReward(Mob* target, uint32 copper, uint32 silver, uint32 gold, if (faction) { - if (target->IsNPC()) + if (target && target->IsNPC()) { int32 nfl_id = target->CastToNPC()->GetNPCFactionID(); SetFactionLevel(CharacterID(), nfl_id, GetBaseClass(), GetBaseRace(), GetDeity(), true); @@ -8575,7 +8575,7 @@ void Client::QuestReward(Mob* target, const QuestReward_Struct &reward, bool fac memcpy(qr, &reward, sizeof(QuestReward_Struct)); // not set in caller because reasons - qr->mob_id = target->GetID(); // Entity ID for the from mob name + qr->mob_id = target ? target->GetID() : 0; // Entity ID for the from mob name if (reward.copper > 0 || reward.silver > 0 || reward.gold > 0 || reward.platinum > 0) AddMoneyToPP(reward.copper, reward.silver, reward.gold, reward.platinum, false); @@ -8586,7 +8586,7 @@ void Client::QuestReward(Mob* target, const QuestReward_Struct &reward, bool fac if (faction) { - if (target->IsNPC()) + if (target && target->IsNPC()) { int32 nfl_id = target->CastToNPC()->GetNPCFactionID(); SetFactionLevel(CharacterID(), nfl_id, GetBaseClass(), GetBaseRace(), GetDeity(), true);