diff --git a/changelog.txt b/changelog.txt index e3f74ce08..742edb5a5 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,64 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 11/7/2015 == +Akkadius: Implemented #repopclose [distance in units] - Used for development purposes, defaults to 500 units + - Real case use: Large zones with 700 NPC's and you are making fast quick tweaks to nearby NPC's you can refresh just the NPC's around you instead of all in the zone + - This can be quite the time saver + - This command will depop all NPC's and only respawn the NPC's that are 500 units around you or unless you specify otherwise + +== 11/2/2015 == +Akkadius: Performance boost (exponential) - Adjusted default idle cast check timers in rules + - Spells:AI_IdleNoSpellMinRecast 500 (Now 6000) 6 seconds + - Spells:AI_IdleNoSpellMaxRecast 2000 (Now 60000) 60 seconds + - Database version 9089 will take care of this update automatically only if you used the default values + - The CPU cost of NPC's checking the entire entity list to cast beneficial spells (Heals/Buffs) becomes extremely high when higher NPC count zones exist (Based off of process profiling) + - Distance checks for every single NPC to every single other NPC who are casting beneficial spells occur every .5 - 2 seconds unless npc_spells dictates other values, which most of the time it does not + - Zones that once fluctuated from 1-8% CPU with no activity (Idle but players present) now idle at .5% based on my testings due + to this change in conjunction with the past few performance commits, these are zones that have 600-800 NPC's in them + - These values normally are overidden by the spells table (npc_spells), fields (idle_no_sp_recast_min, idle_no_sp_recast_max) + +== 11/1/2015 == +Akkadius: Made many performance optimizing oriented code changes in the source + - Added Rate limit the rate in which signals are processed for NPC's (.5 seconds instead of .01 seconds) +Akkadius: Added Perl Export Settings which should heavily reduce the Perl footprint + - Normally when any sub EVENT_ gets triggered, all kinds of variables have to get exported every single time an event is triggered and + this can make Perl very slow when events are triggered constantly + - The two most taxing variable exports are the item variables ($itemcount{} $hasitem{} $oncursor{}) and qglobals ($qglobals{}) + - qglobals can pose to be an issue quickly when global qglobals build up, it is highly recommend to use the GetGlobal() and SetGlobal() + methods instead as they don't reference the hashmap $qglobals{} that is rebuilt every single time a sub event is triggered + - A stress test conducted with 10,000 samples shows an excess of time taken to export variables: http://i.imgur.com/NEpW1tS.png + - After the Perl Export Settings table is implemented, and all exports are shut off you see the following test result: + http://i.imgur.com/Du5hth9.png + - The difference of eliminating uneeded exports brings the overhead and footprint of 10,000 triggers from 54 seconds to 2 seconds + - In a 10,000 sample test (10,000 sub event triggers), exporting item variables adds 12 seconds alone, when item variables are only needed in + EVENT_ITEM and EVENT_SAY a majority of the time if at all + - In a 10,000 sample test (10,000 sub event triggers), exporting qglobals with approximately 1,000 global qglobals in the database creates + about 11-20 seconds of delay on its own (Depending on hardware of course) + - I've written a parser that has determined which of these exports are needed in which sub routines and have turned off all of the unneeded + exports in sub routines that do not need them and used it to create the default table that will be installed in the database. + - The export table is called 'perl_event_export_settings' and it resembles the following structure and contains all current 81 EVENTS + - If an entry doesn't exist in this table and a new subroutine is added to the source, all exports will be on by default for that routine + + +----------+-----------------------------------------+-----------------+------------+-------------+-------------+--------------+ + | event_id | event_description | export_qglobals | export_mob | export_zone | export_item | export_event | + +----------+-----------------------------------------+-----------------+------------+-------------+-------------+--------------+ + | 0 | EVENT_SAY | 1 | 1 | 1 | 1 | 1 | + | 1 | EVENT_ITEM | 1 | 1 | 1 | 0 | 1 | + | 2 | EVENT_DEATH | 1 | 1 | 1 | 0 | 1 | + | 3 | EVENT_SPAWN | 1 | 1 | 1 | 0 | 1 | + | 4 | EVENT_ATTACK | 0 | 1 | 1 | 0 | 1 | + | 5 | EVENT_COMBAT | 1 | 1 | 1 | 0 | 1 | + +----------+-----------------------------------------+-----------------+------------+-------------+-------------+--------------+ + + - If a change is made to this table while the server is live and running, you can hot reload all zone process settings via: + #reloadperlexportsettings + - For those who wonder what "exports" are, they are reference to variables that are made available at runtime of the sub event, such as: + (export_qglobals) (Heavy) : $qglobals https://github.com/EQEmu/Server/blob/master/zone/embparser.cpp#L916 + (export_item) (Heavy) : $itemcount{} $hasitem{} $oncursor{} https://github.com/EQEmu/Server/blob/master/zone/embparser.cpp#L1103 + (export_zone) : $zoneid, $instanceid, $zoneln etc. https://github.com/EQEmu/Server/blob/master/zone/embparser.cpp#L1083 + (export_mob) : $x, $y, $z, $h, $hpratio etc. https://github.com/EQEmu/Server/blob/master/zone/embparser.cpp#L1032 + (export_event) : (event specific) IE: EVENT_SAY ($text) https://github.com/EQEmu/Server/blob/master/zone/embparser.cpp#L1141 + == 10/16/2015 == Uleat: Added command '#bot clearfollowdistance [ | spawned | all ]' to coincide with the activation of the load/save feature for follow_distance diff --git a/cmake/FindMySQL.cmake b/cmake/FindMySQL.cmake index 0578c8b0c..5a7927552 100644 --- a/cmake/FindMySQL.cmake +++ b/cmake/FindMySQL.cmake @@ -21,6 +21,12 @@ IF(MYSQL_ROOT) NAMES mysql.h PATHS ${MYSQL_ROOT}/include PATH_SUFFIXES mysql + NO_DEFAULT_PATH + NO_SYSTEM_ENVIRONMENT_PATH + ) + FIND_PATH(MySQL_INCLUDE_DIR + NAMES mysql.h + PATH_SUFFIXES mysql ) ELSE(MYSQL_ROOT) FIND_PATH(MySQL_INCLUDE_DIR @@ -30,49 +36,46 @@ ELSE(MYSQL_ROOT) ENDIF(MYSQL_ROOT) # Library -SET(MySQL_NAMES libmysql mysqlclient_r mysqlclient) +SET(MySQL_NAMES libmysql) IF(MYSQL_ROOT) - FIND_LIBRARY(MySQL_LIBRARY_DEBUG + FIND_LIBRARY(MySQL_LIBRARY NAMES ${MySQL_NAMES} - PATHS ${MYSQL_ROOT}/lib/debug /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64 + PATHS ${MYSQL_ROOT}/lib PATH_SUFFIXES mysql + NO_DEFAULT_PATH + NO_SYSTEM_ENVIRONMENT_PATH ) - - FIND_LIBRARY(MySQL_LIBRARY_RELEASE + + FIND_LIBRARY(MySQL_LIBRARY NAMES ${MySQL_NAMES} - PATHS ${MYSQL_ROOT}/lib /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64 PATH_SUFFIXES mysql ) ELSE(MYSQL_ROOT) - FIND_LIBRARY(MySQL_LIBRARY_DEBUG - NAMES ${MySQL_NAMES} - PATHS /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64 - PATH_SUFFIXES mysql - ) - - FIND_LIBRARY(MySQL_LIBRARY_RELEASE - NAMES ${MySQL_NAMES} + FIND_LIBRARY(MySQL_LIBRARY + NAMES ${MySQL_NAMES} mysqlclient_r mysqlclient PATHS /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64 PATH_SUFFIXES mysql ) ENDIF(MYSQL_ROOT) -IF (MySQL_INCLUDE_DIR AND MySQL_LIBRARY_DEBUG AND MySQL_LIBRARY_RELEASE) +IF (MySQL_INCLUDE_DIR AND MySQL_LIBRARY) SET(MySQL_FOUND TRUE) - SET( MySQL_LIBRARIES ${MySQL_LIBRARY_DEBUG} ${MySQL_LIBRARY_RELEASE} ) -ELSE (MySQL_INCLUDE_DIR AND MySQL_LIBRARY_DEBUG AND MySQL_LIBRARY_RELEASE) + SET( MySQL_LIBRARIES ${MySQL_LIBRARY} ) +ELSE (MySQL_INCLUDE_DIR AND MySQL_LIBRARY) SET(MySQL_FOUND FALSE) SET( MySQL_LIBRARIES ) -ENDIF (MySQL_INCLUDE_DIR AND MySQL_LIBRARY_DEBUG AND MySQL_LIBRARY_RELEASE) +ENDIF (MySQL_INCLUDE_DIR AND MySQL_LIBRARY) # handle the QUIETLY and REQUIRED arguments and set MySQL_FOUND to TRUE if # all listed variables are TRUE INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(MySQL DEFAULT_MSG MySQL_LIBRARY_DEBUG MySQL_LIBRARY_RELEASE MySQL_INCLUDE_DIR) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(MySQL DEFAULT_MSG MySQL_LIBRARY MySQL_INCLUDE_DIR) IF(MySQL_FOUND) - SET( MySQL_LIBRARIES ${MySQL_LIBRARY_DEBUG} ${MySQL_LIBRARY_RELEASE} ) + SET( MySQL_LIBRARY_RELEASE ${MySQL_LIBRARY} ) + SET( MySQL_LIBRARY_DEBUG ${MySQL_LIBRARY} ) + SET( MySQL_LIBRARIES ${MySQL_LIBRARY_RELEASE} ${MySQL_LIBRARY_DEBUG} ) ELSE(MySQL_FOUND) SET( MySQL_LIBRARIES ) ENDIF(MySQL_FOUND) diff --git a/common/base_packet.h b/common/base_packet.h index 027b8d2fb..16a527ade 100644 --- a/common/base_packet.h +++ b/common/base_packet.h @@ -67,6 +67,8 @@ public: uint8 ReadUInt8() { uint8 value = *(uint8 *)(pBuffer + _rpos); _rpos += sizeof(uint8); return value; } uint8 ReadUInt8(uint32 Offset) const { uint8 value = *(uint8 *)(pBuffer + Offset); return value; } + uint16 ReadUInt16() { uint16 value = *(uint16 *)(pBuffer + _rpos); _rpos += sizeof(uint16); return value; } + uint16 ReadUInt16(uint32 Offset) const { uint16 value = *(uint16 *)(pBuffer + Offset); return value; } uint32 ReadUInt32() { uint32 value = *(uint32 *)(pBuffer + _rpos); _rpos += sizeof(uint32); return value; } uint32 ReadUInt32(uint32 Offset) const { uint32 value = *(uint32 *)(pBuffer + Offset); return value; } void ReadString(char *str) { uint32 len = static_cast(strlen((char *)(pBuffer + _rpos))) + 1; memcpy(str, pBuffer + _rpos, len); _rpos += len; } diff --git a/common/database.h b/common/database.h index c3771f67c..f066cb417 100644 --- a/common/database.h +++ b/common/database.h @@ -23,6 +23,7 @@ #include "global_define.h" #include "eqemu_logsys.h" + #include "types.h" #include "dbcore.h" #include "linked_list.h" diff --git a/common/dbcore.cpp b/common/dbcore.cpp index d256f7b42..76e87cde1 100644 --- a/common/dbcore.cpp +++ b/common/dbcore.cpp @@ -128,7 +128,12 @@ MySQLRequestResult DBcore::QueryDatabase(const char* query, uint32 querylen, boo MySQLRequestResult requestResult(res, (uint32)mysql_affected_rows(&mysql), rowCount, (uint32)mysql_field_count(&mysql), (uint32)mysql_insert_id(&mysql)); if (Log.log_settings[Logs::MySQLQuery].is_category_enabled == 1) - Log.Out(Logs::General, Logs::MySQLQuery, "%s (%u rows returned)", query, rowCount, requestResult.RowCount()); + { + if ((strncasecmp(query, "select", 6) == 0)) + Log.Out(Logs::General, Logs::MySQLQuery, "%s (%u row%s returned)", query, requestResult.RowCount(), requestResult.RowCount() == 1 ? "" : "s"); + else + Log.Out(Logs::General, Logs::MySQLQuery, "%s (%u row%s affected)", query, requestResult.RowsAffected(), requestResult.RowsAffected() == 1 ? "" : "s"); + } return requestResult; } diff --git a/common/emu_oplist.h b/common/emu_oplist.h index 4ef1761bd..223491ecd 100644 --- a/common/emu_oplist.h +++ b/common/emu_oplist.h @@ -215,6 +215,7 @@ N(OP_GroupUpdate), N(OP_GroupUpdateB), N(OP_GroupUpdateLeaderAA), N(OP_GuildBank), +N(OP_GuildBankItemList), N(OP_GuildCreate), N(OP_GuildDelete), N(OP_GuildDemote), @@ -535,6 +536,8 @@ N(OP_WorldLogout), N(OP_WorldObjectsSent), N(OP_WorldUnknown001), N(OP_XTargetAutoAddHaters), +N(OP_XTargetOpen), +N(OP_XTargetOpenResponse), N(OP_XTargetRequest), N(OP_XTargetResponse), N(OP_YellForHelp), diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index 3f6476ba9..74eb9536e 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -4724,6 +4724,22 @@ struct GuildBankItemUpdate_Struct /*226*/ uint16 Unknown226; }; +// newer clients (RoF+) send a list that contains 240 entries +// The packets don't actually use all 64 chars in the strings, but we'll just overallocate for these +struct GuildBankItemListEntry_Struct +{ + uint8 vaild; + uint32 permissions; + char whofor[64]; + char donator[64]; + uint32 item_id; + uint32 item_icon; + uint32 quantity; + uint8 allow_merge; // 1 here for non-full stacks + uint8 usable; + char item_name[64]; +}; + struct GuildBankClear_Struct { /*00*/ uint32 Action; diff --git a/common/eqemu_logsys.cpp b/common/eqemu_logsys.cpp index 36176c399..189c45bf6 100644 --- a/common/eqemu_logsys.cpp +++ b/common/eqemu_logsys.cpp @@ -116,7 +116,7 @@ void EQEmuLogSys::LoadLogSettingsDefaults() platform_file_name = "ucs"; else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformLogin) platform_file_name = "login"; - else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformLogin) + else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformLaunch) platform_file_name = "launcher"; } diff --git a/common/features.h b/common/features.h index 0860788e1..2ede4b4be 100644 --- a/common/features.h +++ b/common/features.h @@ -154,11 +154,12 @@ enum { //reuse times enum { //timer settings, all in milliseconds AImovement_duration = 100, AIthink_duration = 150, - AIscanarea_delay = 500, + AIscanarea_delay = 6000, AIfeignremember_delay = 500, AItarget_check_duration = 500, AIClientScanarea_delay = 750, //used in REVERSE_AGGRO AIassistcheck_delay = 3000, //now often a fighting NPC will yell for help + AI_check_signal_timer_delay = 500, // How often EVENT_SIGNAL checks are processed ClientProximity_interval = 150, CombatEventTimer_expire = 12000, Tribute_duration = 600000, diff --git a/common/item_struct.h b/common/item_struct.h index 1fcb49f51..64292f490 100644 --- a/common/item_struct.h +++ b/common/item_struct.h @@ -51,7 +51,7 @@ ** */ struct ItemEffect_Struct { - int16 Effect; + int32 Effect; uint8 Type; uint8 Level; uint8 Level2; diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index 4ee6d4ec0..79c7271fd 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -1179,6 +1179,54 @@ namespace RoF dest->FastQueuePacket(&outapp); } + ENCODE(OP_GuildBank) + { + auto in = *p; + *p = nullptr; + auto outapp = new EQApplicationPacket(OP_GuildBank, in->size + 4); // all of them are 4 bytes bigger + + // The first action in the enum was removed, everything 1 less + // Normally we cast them to their structs, but there are so many here! will only do when it's easier + switch (in->ReadUInt32()) { + case 10: // GuildBankAcknowledge + outapp->WriteUInt32(9); + outapp->WriteUInt32(in->ReadUInt32()); + outapp->WriteUInt32(0); + break; + case 5: // GuildBankDeposit (ack) + outapp->WriteUInt32(4); + outapp->WriteUInt32(in->ReadUInt32()); + outapp->WriteUInt32(0); + outapp->WriteUInt32(in->ReadUInt32()); + break; + case 1: { // GuildBankItemUpdate + auto emu = (GuildBankItemUpdate_Struct *)in->pBuffer; + auto eq = (structs::GuildBankItemUpdate_Struct *)outapp->pBuffer; + eq->Action = 0; + OUT(Unknown004); + eq->Unknown08 = 0; + OUT(SlotID); + OUT(Area); + OUT(Unknown012); + OUT(ItemID); + OUT(Icon); + OUT(Quantity); + OUT(Permissions); + OUT(AllowMerge); + OUT(Useable); + OUT_str(ItemName); + OUT_str(Donator); + OUT_str(WhoFor); + OUT(Unknown226); + break; + } + default: + break; + } + delete in; + dest->FastQueuePacket(&outapp); + } + ENCODE(OP_GuildMemberList) { //consume the packet @@ -4590,6 +4638,92 @@ namespace RoF DECODE_FORWARD(OP_GroupInvite); } + DECODE(OP_GuildBank) + { + // all actions are 1 off due to the removal of one of enums + switch (__packet->ReadUInt32()) { + case 2: {// GuildBankPromote + DECODE_LENGTH_EXACT(structs::GuildBankPromote_Struct); + SETUP_DIRECT_DECODE(GuildBankPromote_Struct, structs::GuildBankPromote_Struct); + emu->Action = 3; + IN(Unknown04); + IN(Slot); + IN(Slot2); + FINISH_DIRECT_DECODE(); + return; + } + case 3: { // GuildBankViewItem + DECODE_LENGTH_EXACT(structs::GuildBankViewItem_Struct); + SETUP_DIRECT_DECODE(GuildBankViewItem_Struct, structs::GuildBankViewItem_Struct); + emu->Action = 4; + IN(Unknown04); + IN(SlotID); + IN(Area); + IN(Unknown12); + IN(Unknown16); + FINISH_DIRECT_DECODE(); + return; + } + case 4: { // GuildBankDeposit + __packet->WriteUInt32(5); + return; + } + case 5: { // GuildBankPermissions + DECODE_LENGTH_EXACT(structs::GuildBankPermissions_Struct); + SETUP_DIRECT_DECODE(GuildBankPermissions_Struct, structs::GuildBankPermissions_Struct); + emu->Action = 6; + IN(Unknown04); + IN(SlotID); + IN(Unknown10); + IN(ItemID); + IN(Permissions); + strn0cpy(emu->MemberName, eq->MemberName, 64); + FINISH_DIRECT_DECODE(); + return; + } + case 6: { // GuildBankWithdraw + DECODE_LENGTH_EXACT(structs::GuildBankWithdrawItem_Struct); + SETUP_DIRECT_DECODE(GuildBankWithdrawItem_Struct, structs::GuildBankWithdrawItem_Struct); + emu->Action = 7; + IN(Unknown04); + IN(SlotID); + IN(Area); + IN(Unknown12); + IN(Quantity); + FINISH_DIRECT_DECODE(); + return; + } + case 7: { // GuildBankSplitStacks + DECODE_LENGTH_EXACT(structs::GuildBankWithdrawItem_Struct); + SETUP_DIRECT_DECODE(GuildBankWithdrawItem_Struct, structs::GuildBankWithdrawItem_Struct); + emu->Action = 8; + IN(Unknown04); + IN(SlotID); + IN(Area); + IN(Unknown12); + IN(Quantity); + FINISH_DIRECT_DECODE(); + return; + } + case 8: { // GuildBankMergeStacks + DECODE_LENGTH_EXACT(structs::GuildBankWithdrawItem_Struct); + SETUP_DIRECT_DECODE(GuildBankWithdrawItem_Struct, structs::GuildBankWithdrawItem_Struct); + emu->Action = 9; + IN(Unknown04); + IN(SlotID); + IN(Area); + IN(Unknown12); + IN(Quantity); + FINISH_DIRECT_DECODE(); + return; + } + default: + Log.Out(Logs::Detail, Logs::Netcode, "Unhandled OP_GuildBank action"); + __packet->SetOpcode(OP_Unknown); /* invalidate the packet */ + return; + } + } + DECODE(OP_GuildDemote) { DECODE_LENGTH_EXACT(structs::GuildDemoteStruct); diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 7319dc98b..e5cc77791 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -1250,6 +1250,54 @@ namespace RoF2 dest->FastQueuePacket(&outapp); } + ENCODE(OP_GuildBank) + { + auto in = *p; + *p = nullptr; + auto outapp = new EQApplicationPacket(OP_GuildBank, in->size + 4); // all of them are 4 bytes bigger + + // The first action in the enum was removed, everything 1 less + // Normally we cast them to their structs, but there are so many here! will only do when it's easier + switch (in->ReadUInt32()) { + case 10: // GuildBankAcknowledge + outapp->WriteUInt32(9); + outapp->WriteUInt32(in->ReadUInt32()); + outapp->WriteUInt32(0); + break; + case 5: // GuildBankDeposit (ack) + outapp->WriteUInt32(4); + outapp->WriteUInt32(in->ReadUInt32()); + outapp->WriteUInt32(0); + outapp->WriteUInt32(in->ReadUInt32()); + break; + case 1: { // GuildBankItemUpdate + auto emu = (GuildBankItemUpdate_Struct *)in->pBuffer; + auto eq = (structs::GuildBankItemUpdate_Struct *)outapp->pBuffer; + eq->Action = 0; + OUT(Unknown004); + eq->Unknown08 = 0; + OUT(SlotID); + OUT(Area); + OUT(Unknown012); + OUT(ItemID); + OUT(Icon); + OUT(Quantity); + OUT(Permissions); + OUT(AllowMerge); + OUT(Useable); + OUT_str(ItemName); + OUT_str(Donator); + OUT_str(WhoFor); + OUT(Unknown226); + break; + } + default: + break; + } + delete in; + dest->FastQueuePacket(&outapp); + } + ENCODE(OP_GuildMemberList) { //consume the packet @@ -4739,6 +4787,92 @@ namespace RoF2 DECODE_FORWARD(OP_GroupInvite); } + DECODE(OP_GuildBank) + { + // all actions are 1 off due to the removal of one of enums + switch (__packet->ReadUInt32()) { + case 2: {// GuildBankPromote + DECODE_LENGTH_EXACT(structs::GuildBankPromote_Struct); + SETUP_DIRECT_DECODE(GuildBankPromote_Struct, structs::GuildBankPromote_Struct); + emu->Action = 3; + IN(Unknown04); + IN(Slot); + IN(Slot2); + FINISH_DIRECT_DECODE(); + return; + } + case 3: { // GuildBankViewItem + DECODE_LENGTH_EXACT(structs::GuildBankViewItem_Struct); + SETUP_DIRECT_DECODE(GuildBankViewItem_Struct, structs::GuildBankViewItem_Struct); + emu->Action = 4; + IN(Unknown04); + IN(SlotID); + IN(Area); + IN(Unknown12); + IN(Unknown16); + FINISH_DIRECT_DECODE(); + return; + } + case 4: { // GuildBankDeposit + __packet->WriteUInt32(5); + return; + } + case 5: { // GuildBankPermissions + DECODE_LENGTH_EXACT(structs::GuildBankPermissions_Struct); + SETUP_DIRECT_DECODE(GuildBankPermissions_Struct, structs::GuildBankPermissions_Struct); + emu->Action = 6; + IN(Unknown04); + IN(SlotID); + IN(Unknown10); + IN(ItemID); + IN(Permissions); + strn0cpy(emu->MemberName, eq->MemberName, 64); + FINISH_DIRECT_DECODE(); + return; + } + case 6: { // GuildBankWithdraw + DECODE_LENGTH_EXACT(structs::GuildBankWithdrawItem_Struct); + SETUP_DIRECT_DECODE(GuildBankWithdrawItem_Struct, structs::GuildBankWithdrawItem_Struct); + emu->Action = 7; + IN(Unknown04); + IN(SlotID); + IN(Area); + IN(Unknown12); + IN(Quantity); + FINISH_DIRECT_DECODE(); + return; + } + case 7: { // GuildBankSplitStacks + DECODE_LENGTH_EXACT(structs::GuildBankWithdrawItem_Struct); + SETUP_DIRECT_DECODE(GuildBankWithdrawItem_Struct, structs::GuildBankWithdrawItem_Struct); + emu->Action = 8; + IN(Unknown04); + IN(SlotID); + IN(Area); + IN(Unknown12); + IN(Quantity); + FINISH_DIRECT_DECODE(); + return; + } + case 8: { // GuildBankMergeStacks + DECODE_LENGTH_EXACT(structs::GuildBankWithdrawItem_Struct); + SETUP_DIRECT_DECODE(GuildBankWithdrawItem_Struct, structs::GuildBankWithdrawItem_Struct); + emu->Action = 9; + IN(Unknown04); + IN(SlotID); + IN(Area); + IN(Unknown12); + IN(Quantity); + FINISH_DIRECT_DECODE(); + return; + } + default: + Log.Out(Logs::Detail, Logs::Netcode, "Unhandled OP_GuildBank action"); + __packet->SetOpcode(OP_Unknown); /* invalidate the packet */ + return; + } + } + DECODE(OP_GuildDemote) { DECODE_LENGTH_EXACT(structs::GuildDemoteStruct); diff --git a/common/patches/rof2_ops.h b/common/patches/rof2_ops.h index 3bb69af5e..9fe76e33c 100644 --- a/common/patches/rof2_ops.h +++ b/common/patches/rof2_ops.h @@ -57,6 +57,7 @@ E(OP_GroupFollow) E(OP_GroupFollow2) E(OP_GroupInvite) E(OP_GroupUpdate) +E(OP_GuildBank) E(OP_GuildMemberList) E(OP_GuildMemberUpdate) E(OP_GuildsList) @@ -152,6 +153,7 @@ D(OP_GroupFollow) D(OP_GroupFollow2) D(OP_GroupInvite) D(OP_GroupInvite2) +D(OP_GuildBank) D(OP_GuildDemote) D(OP_GuildRemove) D(OP_GuildStatus) diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index 22748af8d..1e93b7434 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -1859,6 +1859,114 @@ struct GuildUpdate_Struct { GuildsListEntry_Struct entry; }; +struct GuildBankAck_Struct +{ +/*00*/ uint32 Action; // 10 +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +}; + +struct GuildBankDepositAck_Struct +{ +/*00*/ uint32 Action; // 10 +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*08*/ uint32 Fail; //1 = Fail, 0 = Success +}; + +struct GuildBankPromote_Struct +{ +/*00*/ uint32 Action; // 3 +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*12*/ uint32 Slot; +/*16*/ uint32 Slot2; // Always appears to be the same as Slot for Action code 3 +/*20*/ uint32 unknown20; +}; + +struct GuildBankPermissions_Struct +{ +/*00*/ uint32 Action; // 6 +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*08*/ uint16 SlotID; +/*10*/ uint16 Unknown10; // Saw 1, probably indicating it is the main area rather than deposits +/*12*/ uint32 ItemID; +/*16*/ uint32 Permissions; +/*20*/ char MemberName[64]; +}; + +struct GuildBankViewItem_Struct +{ +/*00*/ uint32 Action; +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*08*/ uint16 SlotID; // 0 = Deposit area, 1 = Main area +/*10*/ uint16 Area; +/*12*/ uint32 Unknown12; +/*16*/ uint32 Unknown16; +}; + +struct GuildBankWithdrawItem_Struct +{ +/*00*/ uint32 Action; +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*08*/ uint16 SlotID; +/*10*/ uint16 Area; +/*12*/ uint32 Unknown12; +/*16*/ uint32 Quantity; +/*20*/ +}; + +struct GuildBankItemUpdate_Struct +{ + void Init(uint32 inAction, uint32 inUnknown004, uint16 inSlotID, uint16 inArea, uint16 inUnknown012, uint32 inItemID, uint32 inIcon, uint32 inQuantity, + uint32 inPermissions, uint32 inAllowMerge, bool inUseable) + { + Action = inAction; + Unknown004 = inUnknown004; + SlotID = inSlotID; + Area = inArea; + Unknown012 = inUnknown012; + ItemID = inItemID; + Icon = inIcon; + Quantity = inQuantity; + Permissions = inPermissions; + AllowMerge = inAllowMerge; + Useable = inUseable; + ItemName[0] = '\0'; + Donator[0] = '\0'; + WhoFor[0] = '\0'; + }; + +/*000*/ uint32 Action; +/*004*/ uint32 Unknown004; +/*008*/ uint32 Unknown08; +/*012*/ uint16 SlotID; +/*014*/ uint16 Area; +/*016*/ uint32 Unknown012; +/*020*/ uint32 ItemID; +/*024*/ uint32 Icon; +/*028*/ uint32 Quantity; +/*032*/ uint32 Permissions; +/*036*/ uint8 AllowMerge; +/*037*/ uint8 Useable; // Used in conjunction with the Public-if-useable permission. +/*038*/ char ItemName[64]; +/*102*/ char Donator[64]; +/*166*/ char WhoFor[64]; +/*230*/ uint16 Unknown226; +}; + +struct GuildBankClear_Struct +{ +/*00*/ uint32 Action; +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*12*/ uint32 DepositAreaCount; +/*16*/ uint32 MainAreaCount; +}; + /* ** Money Loot ** Length: 22 Bytes @@ -4624,7 +4732,7 @@ struct ClickEffectStruct struct ProcEffectStruct { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; @@ -4639,7 +4747,7 @@ struct ProcEffectStruct struct WornEffectStruct //worn, focus and scroll effect { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; diff --git a/common/patches/rof_ops.h b/common/patches/rof_ops.h index 8e9adfdc9..606c51c62 100644 --- a/common/patches/rof_ops.h +++ b/common/patches/rof_ops.h @@ -42,6 +42,7 @@ E(OP_GroupFollow) E(OP_GroupFollow2) E(OP_GroupInvite) E(OP_GroupUpdate) +E(OP_GuildBank) E(OP_GuildMemberList) E(OP_GuildMemberUpdate) E(OP_GuildsList) @@ -137,6 +138,7 @@ D(OP_GroupFollow) D(OP_GroupFollow2) D(OP_GroupInvite) D(OP_GroupInvite2) +D(OP_GuildBank) D(OP_GuildDemote) D(OP_GuildRemove) D(OP_GuildStatus) diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index adbfbb7fa..e24935d35 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -1889,6 +1889,114 @@ struct GuildUpdate_Struct { GuildsListEntry_Struct entry; }; +struct GuildBankAck_Struct +{ +/*00*/ uint32 Action; // 10 +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +}; + +struct GuildBankDepositAck_Struct +{ +/*00*/ uint32 Action; // 10 +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*08*/ uint32 Fail; //1 = Fail, 0 = Success +}; + +struct GuildBankPromote_Struct +{ +/*00*/ uint32 Action; // 3 +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*12*/ uint32 Slot; +/*16*/ uint32 Slot2; // Always appears to be the same as Slot for Action code 3 +/*20*/ uint32 unknown20; +}; + +struct GuildBankPermissions_Struct +{ +/*00*/ uint32 Action; // 6 +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*08*/ uint16 SlotID; +/*10*/ uint16 Unknown10; // Saw 1, probably indicating it is the main area rather than deposits +/*12*/ uint32 ItemID; +/*16*/ uint32 Permissions; +/*20*/ char MemberName[64]; +}; + +struct GuildBankViewItem_Struct +{ +/*00*/ uint32 Action; +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*08*/ uint16 SlotID; // 0 = Deposit area, 1 = Main area +/*10*/ uint16 Area; +/*12*/ uint32 Unknown12; +/*16*/ uint32 Unknown16; +}; + +struct GuildBankWithdrawItem_Struct +{ +/*00*/ uint32 Action; +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*08*/ uint16 SlotID; +/*10*/ uint16 Area; +/*12*/ uint32 Unknown12; +/*16*/ uint32 Quantity; +/*20*/ +}; + +struct GuildBankItemUpdate_Struct +{ + void Init(uint32 inAction, uint32 inUnknown004, uint16 inSlotID, uint16 inArea, uint16 inUnknown012, uint32 inItemID, uint32 inIcon, uint32 inQuantity, + uint32 inPermissions, uint32 inAllowMerge, bool inUseable) + { + Action = inAction; + Unknown004 = inUnknown004; + SlotID = inSlotID; + Area = inArea; + Unknown012 = inUnknown012; + ItemID = inItemID; + Icon = inIcon; + Quantity = inQuantity; + Permissions = inPermissions; + AllowMerge = inAllowMerge; + Useable = inUseable; + ItemName[0] = '\0'; + Donator[0] = '\0'; + WhoFor[0] = '\0'; + }; + +/*000*/ uint32 Action; +/*004*/ uint32 Unknown004; +/*008*/ uint32 Unknown08; +/*012*/ uint16 SlotID; +/*014*/ uint16 Area; +/*016*/ uint32 Unknown012; +/*020*/ uint32 ItemID; +/*024*/ uint32 Icon; +/*028*/ uint32 Quantity; +/*032*/ uint32 Permissions; +/*036*/ uint8 AllowMerge; +/*037*/ uint8 Useable; // Used in conjunction with the Public-if-useable permission. +/*038*/ char ItemName[64]; +/*102*/ char Donator[64]; +/*166*/ char WhoFor[64]; +/*230*/ uint16 Unknown226; +}; + +struct GuildBankClear_Struct +{ +/*00*/ uint32 Action; +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*12*/ uint32 DepositAreaCount; +/*16*/ uint32 MainAreaCount; +}; + /* ** Money Loot ** Length: 22 Bytes @@ -4623,7 +4731,7 @@ struct ClickEffectStruct struct ProcEffectStruct { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; @@ -4638,7 +4746,7 @@ struct ProcEffectStruct struct WornEffectStruct //worn, focus and scroll effect { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; diff --git a/common/patches/sod_structs.h b/common/patches/sod_structs.h index 4e537221c..d9abef4c6 100644 --- a/common/patches/sod_structs.h +++ b/common/patches/sod_structs.h @@ -4111,7 +4111,7 @@ struct ClickEffectStruct struct ProcEffectStruct { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; @@ -4126,7 +4126,7 @@ struct ProcEffectStruct struct WornEffectStruct //worn, focus and scroll effect { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; diff --git a/common/patches/sof_structs.h b/common/patches/sof_structs.h index d15f20999..db7cfe028 100644 --- a/common/patches/sof_structs.h +++ b/common/patches/sof_structs.h @@ -3965,7 +3965,7 @@ struct ClickEffectStruct struct ProcEffectStruct { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; @@ -3980,7 +3980,7 @@ struct ProcEffectStruct struct WornEffectStruct //worn, focus and scroll effect { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; diff --git a/common/patches/uf_structs.h b/common/patches/uf_structs.h index 046eb5138..3631edea3 100644 --- a/common/patches/uf_structs.h +++ b/common/patches/uf_structs.h @@ -4206,7 +4206,7 @@ struct ClickEffectStruct struct ProcEffectStruct { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; @@ -4221,7 +4221,7 @@ struct ProcEffectStruct struct WornEffectStruct //worn, focus and scroll effect { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; diff --git a/common/ruletypes.h b/common/ruletypes.h index 1b4baa371..411489ca1 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -347,8 +347,8 @@ RULE_INT(Spells, AI_EngagedDetrimentalChance, 20) // Chance during third AI Cast RULE_INT(Spells, AI_PursueNoSpellMinRecast, 500) // AI spell recast time(MS) check when no spell is cast while chasing target. (min time in random) RULE_INT(Spells, AI_PursueNoSpellMaxRecast, 2000) // AI spell recast time(MS) check when no spell is cast while chasing target. (max time in random) RULE_INT(Spells, AI_PursueDetrimentalChance, 90) // Chance while chasing target to cast a detrimental spell. -RULE_INT(Spells, AI_IdleNoSpellMinRecast, 500) // AI spell recast time(MS) check when no spell is cast while idle. (min time in random) -RULE_INT(Spells, AI_IdleNoSpellMaxRecast, 2000) // AI spell recast time(MS) check when no spell is cast while chasing target. (max time in random) +RULE_INT(Spells, AI_IdleNoSpellMinRecast, 6000) // AI spell recast time(MS) check when no spell is cast while idle. (min time in random) +RULE_INT(Spells, AI_IdleNoSpellMaxRecast, 60000) // AI spell recast time(MS) check when no spell is cast while chasing target. (max time in random) RULE_INT(Spells, AI_IdleBeneficialChance, 100) // Chance while idle to do a beneficial spell on self or others. RULE_BOOL(Spells, SHDProcIDOffByOne, true) // pre June 2009 SHD spell procs were off by 1, they stopped doing this in June 2009 (so UF+ spell files need this false) RULE_BOOL(Spells, Jun182014HundredHandsRevamp, false) // this should be true for if you import a spell file newer than June 18, 2014 @@ -475,6 +475,8 @@ RULE_BOOL(NPC, ReturnNonQuestNoDropItems, false) // Returns NO DROP items on NPC RULE_INT(NPC, StartEnrageValue, 9) // % HP that an NPC will begin to enrage RULE_BOOL(NPC, LiveLikeEnrage, false) // If set to true then only player controlled pets will enrage RULE_BOOL(NPC, EnableMeritBasedFaction, false) // If set to true, faction will given in the same way as experience (solo/group/raid) +RULE_INT(NPC, NPCToNPCAggroTimerMin, 500) +RULE_INT(NPC, NPCToNPCAggroTimerMax, 6000) RULE_CATEGORY_END() RULE_CATEGORY(Aggro) diff --git a/common/servertalk.h b/common/servertalk.h index 0945d500d..e7ce947c5 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -182,6 +182,7 @@ #define ServerOP_CZMessagePlayer 0x4008 #define ServerOP_ReloadWorld 0x4009 #define ServerOP_ReloadLogs 0x4010 +#define ServerOP_ReloadPerlExportSettings 0x4011 /* Query Server OP Codes */ #define ServerOP_QSPlayerLogTrades 0x5010 #define ServerOP_QSPlayerLogHandins 0x5011 @@ -548,6 +549,7 @@ struct ServerConnectInfo { char address[250]; char local_address[250]; uint16 port; + uint32 process_id; }; struct ServerGMGoto_Struct { diff --git a/common/shareddb.cpp b/common/shareddb.cpp index ed4106598..0c8fae730 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -997,23 +997,23 @@ void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_ strcpy(item.CharmFile,row[ItemField::charmfile]); - item.Proc.Effect = (uint16)atoul(row[ItemField::proceffect]); + item.Proc.Effect = (int32)atoul(row[ItemField::proceffect]); item.Proc.Type = (uint8)atoul(row[ItemField::proctype]); item.Proc.Level = (uint8)atoul(row[ItemField::proclevel]); item.Proc.Level2 = (uint8)atoul(row[ItemField::proclevel2]); - item.Worn.Effect = (uint16)atoul(row[ItemField::worneffect]); + item.Worn.Effect = (int32)atoul(row[ItemField::worneffect]); item.Worn.Type = (uint8)atoul(row[ItemField::worntype]); item.Worn.Level = (uint8)atoul(row[ItemField::wornlevel]); item.Worn.Level2 = (uint8)atoul(row[ItemField::wornlevel2]); - item.Focus.Effect = (uint16)atoul(row[ItemField::focuseffect]); + item.Focus.Effect = (int32)atoul(row[ItemField::focuseffect]); item.Focus.Type = (uint8)atoul(row[ItemField::focustype]); item.Focus.Level = (uint8)atoul(row[ItemField::focuslevel]); item.Focus.Level2 = (uint8)atoul(row[ItemField::focuslevel2]); - item.Scroll.Effect = (uint16)atoul(row[ItemField::scrolleffect]); + item.Scroll.Effect = (int32)atoul(row[ItemField::scrolleffect]); item.Scroll.Type = (uint8)atoul(row[ItemField::scrolltype]); item.Scroll.Level = (uint8)atoul(row[ItemField::scrolllevel]); item.Scroll.Level2 = (uint8)atoul(row[ItemField::scrolllevel2]); - item.Bard.Effect = (uint16)atoul(row[ItemField::bardeffect]); + item.Bard.Effect = (int32)atoul(row[ItemField::bardeffect]); item.Bard.Type = (uint8)atoul(row[ItemField::bardtype]); item.Bard.Level = (uint8)atoul(row[ItemField::bardlevel]); item.Bard.Level2 = (uint8)atoul(row[ItemField::bardlevel2]); diff --git a/common/version.h b/common/version.h index d8a6b6077..4f39b595c 100644 --- a/common/version.h +++ b/common/version.h @@ -30,7 +30,7 @@ Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9087 +#define CURRENT_BINARY_DATABASE_VERSION 9089 #ifdef BOTS #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9000 #else diff --git a/utils/patches/patch_RoF.conf b/utils/patches/patch_RoF.conf index 6e3f0ab1a..7a33eb459 100644 --- a/utils/patches/patch_RoF.conf +++ b/utils/patches/patch_RoF.conf @@ -131,6 +131,7 @@ OP_GuildPromote=0x2945 OP_GuildPublicNote=0x3c2c OP_GuildManageBanker=0x389c # Was 0x096d OP_GuildBank=0x2ab0 # Was 0x10c3 +OP_GuildBankItemList=0x1cbf OP_SetGuildRank=0x3599 OP_GuildUpdateURLAndChannel=0x7851 OP_GuildStatus=0x25a5 @@ -235,6 +236,8 @@ OP_TargetHoTT=0x3af5 OP_XTargetResponse=0x7f64 OP_XTargetRequest=0x6753 OP_XTargetAutoAddHaters=0x5f51 +OP_XTargetOpen=0x7423 +OP_XTargetOpenResponse=0x27e8 OP_TargetBuffs=0x1c71 OP_BuffCreate=0x71f5 OP_BuffRemoveRequest=0x7efd diff --git a/utils/patches/patch_RoF2.conf b/utils/patches/patch_RoF2.conf index 5e67f4c11..6afb7209e 100644 --- a/utils/patches/patch_RoF2.conf +++ b/utils/patches/patch_RoF2.conf @@ -130,6 +130,7 @@ OP_GuildPromote=0x6a98 OP_GuildPublicNote=0x5053 OP_GuildManageBanker=0x3f35 OP_GuildBank=0x5134 +OP_GuildBankItemList=0x7850 OP_SetGuildRank=0x0b9c OP_GuildUpdateURLAndChannel=0x2958 OP_GuildStatus=0x7326 @@ -235,6 +236,8 @@ OP_TargetBuffs=0x4f4b OP_XTargetResponse=0x4d59 OP_XTargetRequest=0x3763 OP_XTargetAutoAddHaters=0x672f +OP_XTargetOpen=0x61df +OP_XTargetOpenResponse=0x3ef8 OP_BuffCreate=0x3377 OP_BuffRemoveRequest=0x64f2 OP_DeleteSpawn=0x7280 diff --git a/utils/patches/patch_UF.conf b/utils/patches/patch_UF.conf index 6f94c92db..e3af9aa7d 100644 --- a/utils/patches/patch_UF.conf +++ b/utils/patches/patch_UF.conf @@ -239,6 +239,8 @@ OP_TargetHoTT=0x790c # C OP_XTargetResponse=0x6eb5 # OP_XTargetRequest=0x4750 # OP_XTargetAutoAddHaters=0x1a28 # +OP_XTargetOpen=0x11ae +OP_XTargetOpenResponse=0x45d3 OP_TargetBuffs=0x3f24 # C OP_BuffCreate=0x2121 # V OP_BuffRemoveRequest=0x4065 diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 239fdbb67..aa1e46be9 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -341,6 +341,8 @@ 9085|2015_07_01_Marquee_Rule.sql|SELECT * FROM `rule_values` WHERE `rule_name` LIKE '%Character:MarqueeHPUpdates%'|empty| 9086|2015_07_02_aa_rework.sql|SHOW TABLES LIKE 'aa_ranks'|empty| 9087|2015_09_25_inventory_snapshots.sql|SHOW TABLES LIKE 'inventory_snapshots'|empty| +9088|2015_11_01_perl_event_export_settings.sql|SHOW TABLES LIKE 'perl_event_export_settings'|empty| +9089|2015_11_02_ai_idle_no_spell_recast_default_changes.sql|SELECT * FROM `rule_values` WHERE `rule_name` LIKE '%Spells:AI_IdleNoSpellMinRecast%' AND `rule_value` = '500'|not_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/2015_11_01_perl_event_export_settings.sql b/utils/sql/git/required/2015_11_01_perl_event_export_settings.sql new file mode 100644 index 000000000..14efd90a5 --- /dev/null +++ b/utils/sql/git/required/2015_11_01_perl_event_export_settings.sql @@ -0,0 +1,95 @@ +CREATE TABLE `perl_event_export_settings` ( + `event_id` int(11) NOT NULL, + `event_description` varchar(150) DEFAULT NULL, + `export_qglobals` smallint(11) DEFAULT '0', + `export_mob` smallint(11) DEFAULT '0', + `export_zone` smallint(11) DEFAULT '0', + `export_item` smallint(11) DEFAULT '0', + `export_event` smallint(11) DEFAULT '0', + PRIMARY KEY (`event_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- ---------------------------- +-- Records of perl_event_export_settings +-- ---------------------------- +INSERT INTO `perl_event_export_settings` VALUES ('0', 'EVENT_SAY', '1', '1', '1', '1', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('1', 'EVENT_ITEM', '1', '1', '1', '1', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('2', 'EVENT_DEATH', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('3', 'EVENT_SPAWN', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('4', 'EVENT_ATTACK', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('5', 'EVENT_COMBAT', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('6', 'EVENT_AGGRO', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('7', 'EVENT_SLAY', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('8', 'EVENT_NPC_SLAY', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('9', 'EVENT_WAYPOINT_ARRIVE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('10', 'EVENT_WAYPOINT_DEPART', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('11', 'EVENT_TIMER', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('12', 'EVENT_SIGNAL', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('13', 'EVENT_HP', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('14', 'EVENT_ENTER', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('15', 'EVENT_EXIT', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('16', 'EVENT_ENTERZONE', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('17', 'EVENT_CLICKDOOR', '1', '1', '1', '1', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('18', 'EVENT_LOOT', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('19', 'EVENT_ZONE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('20', 'EVENT_LEVEL_UP', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('21', 'EVENT_KILLED_MERIT', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('22', 'EVENT_CAST_ON', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('23', 'EVENT_TASKACCEPTED', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('24', 'EVENT_TASK_STAGE_COMPLETE', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('25', 'EVENT_TASK_UPDATE', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('26', 'EVENT_TASK_COMPLETE', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('27', 'EVENT_TASK_FAIL', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('28', 'EVENT_AGGRO_SAY', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('29', 'EVENT_PLAYER_PICKUP', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('30', 'EVENT_POPUPRESPONSE', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('31', 'EVENT_ENVIRONMENTAL_DAMAGE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('32', 'EVENT_PROXIMITY_SAY', '1', '1', '1', '1', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('33', 'EVENT_CAST', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('34', 'EVENT_CAST_BEGIN', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('35', 'EVENT_SCALE_CALC', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('36', 'EVENT_ITEM_ENTER_ZONE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('37', 'EVENT_TARGET_CHANGE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('38', 'EVENT_HATE_LIST', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('39', 'EVENT_SPELL_EFFECT_CLIENT', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('40', 'EVENT_SPELL_EFFECT_NPC', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('41', 'EVENT_SPELL_EFFECT_BUFF_TIC_CLIENT', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('42', 'EVENT_SPELL_EFFECT_BUFF_TIC_NPC', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('43', 'EVENT_SPELL_FADE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('44', 'EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('45', 'EVENT_COMBINE_SUCCESS', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('46', 'EVENT_COMBINE_FAILURE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('47', 'EVENT_ITEM_CLICK', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('48', 'EVENT_ITEM_CLICK_CAST', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('49', 'EVENT_GROUP_CHANGE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('50', 'EVENT_FORAGE_SUCCESS', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('51', 'EVENT_FORAGE_FAILURE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('52', 'EVENT_FISH_START', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('53', 'EVENT_FISH_SUCCESS', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('54', 'EVENT_FISH_FAILURE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('55', 'EVENT_CLICK_OBJECT', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('56', 'EVENT_DISCOVER_ITEM', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('57', 'EVENT_DISCONNECT', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('58', 'EVENT_CONNECT', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('59', 'EVENT_ITEM_TICK', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('60', 'EVENT_DUEL_WIN', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('61', 'EVENT_DUEL_LOSE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('62', 'EVENT_ENCOUNTER_LOAD', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('63', 'EVENT_ENCOUNTER_UNLOAD', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('64', 'EVENT_SAY', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('65', 'EVENT_DROP_ITEM', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('66', 'EVENT_DESTROY_ITEM', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('67', 'EVENT_FEIGN_DEATH', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('68', 'EVENT_WEAPON_PROC', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('69', 'EVENT_EQUIP_ITEM', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('70', 'EVENT_UNEQUIP_ITEM', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('71', 'EVENT_AUGMENT_ITEM', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('72', 'EVENT_UNAUGMENT_ITEM', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('73', 'EVENT_AUGMENT_INSERT', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('74', 'EVENT_AUGMENT_REMOVE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('75', 'EVENT_ENTER_AREA', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('76', 'EVENT_LEAVE_AREA', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('77', 'EVENT_RESPAWN', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('78', 'EVENT_DEATH_COMPLETE', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('79', 'EVENT_UNHANDLED_OPCODE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('80', 'EVENT_TICK', '0', '1', '1', '0', '1'); diff --git a/utils/sql/git/required/2015_11_02_ai_idle_no_spell_recast_default_changes.sql b/utils/sql/git/required/2015_11_02_ai_idle_no_spell_recast_default_changes.sql new file mode 100644 index 000000000..fe09523c7 --- /dev/null +++ b/utils/sql/git/required/2015_11_02_ai_idle_no_spell_recast_default_changes.sql @@ -0,0 +1,2 @@ +UPDATE `rule_values` SET `rule_value` = '6000' WHERE `rule_value` = '500' AND `rule_name` = 'Spells:AI_IdleNoSpellMinRecast'; +UPDATE `rule_values` SET `rule_value` = '60000' WHERE `rule_value` = '2000' AND `rule_name` = 'Spells:AI_IdleNoSpellMaxRecast'; \ No newline at end of file diff --git a/world/zonelist.cpp b/world/zonelist.cpp index 22d783f5d..3332e0578 100644 --- a/world/zonelist.cpp +++ b/world/zonelist.cpp @@ -283,57 +283,84 @@ void ZSList::ListLockedZones(const char* to, WorldTCPConnection* connection) { } void ZSList::SendZoneStatus(const char* to, int16 admin, WorldTCPConnection* connection) { + LinkedListIterator iterator(list); struct in_addr in; iterator.Reset(); char locked[4]; - if (WorldConfig::get()->Locked == true) + if (WorldConfig::get()->Locked == true){ strcpy(locked, "Yes"); - else + } + else { strcpy(locked, "No"); + } char* output = 0; uint32 outsize = 0, outlen = 0; - if (connection->IsConsole()) + + if (connection->IsConsole()){ AppendAnyLenString(&output, &outsize, &outlen, "World Locked: %s\r\n", locked); - else + } + else{ AppendAnyLenString(&output, &outsize, &outlen, "World Locked: %s^", locked); - if (connection->IsConsole()) + } + if (connection->IsConsole()){ AppendAnyLenString(&output, &outsize, &outlen, "Zoneservers online:\r\n"); - else + } + else{ AppendAnyLenString(&output, &outsize, &outlen, "Zoneservers online:^"); -// connection->SendEmoteMessage(to, 0, 0, 0, "World Locked: %s", locked); -// connection->SendEmoteMessage(to, 0, 0, 0, "Zoneservers online:"); - int v=0, w=0, x=0, y=0, z=0; - char tmpStatic[2] = { 0, 0 }, tmpZone[64]; - memset(tmpZone, 0, sizeof(tmpZone)); - ZoneServer* zs = 0; - while(iterator.MoreElements()) { - zs = iterator.GetData(); - in.s_addr = zs->GetIP(); + } - if(zs->IsStaticZone()) + int v = 0, w = 0, x = 0, y = 0, z = 0; + char is_static_string[2] = { 0, 0 }, zone_data_string[64]; + memset(zone_data_string, 0, sizeof(zone_data_string)); + + ZoneServer* zone_server_data = 0; + + while (iterator.MoreElements()) { + zone_server_data = iterator.GetData(); + in.s_addr = zone_server_data->GetIP(); + + if (zone_server_data->IsStaticZone()){ z++; - else if (zs->GetZoneID() != 0) + } + else if (zone_server_data->GetZoneID() != 0){ w++; - else if(zs->GetZoneID() == 0 && !zs->IsBootingUp()) + } + else if (zone_server_data->GetZoneID() == 0 && !zone_server_data->IsBootingUp()){ v++; + } - if (zs->IsStaticZone()) - tmpStatic[0] = 'S'; + if (zone_server_data->IsStaticZone()) + is_static_string[0] = 'S'; else - tmpStatic[0] = ' '; + is_static_string[0] = 'D'; if (admin >= 150) { - if (zs->GetZoneID()) - snprintf(tmpZone, sizeof(tmpZone), "%s (%i)", zs->GetZoneName(), zs->GetZoneID()); - else if (zs->IsBootingUp()) - strcpy(tmpZone, "..."); - else - tmpZone[0] = 0; + if (zone_server_data->GetZoneID()){ + snprintf(zone_data_string, sizeof(zone_data_string), "%s (%i)", zone_server_data->GetZoneName(), zone_server_data->GetZoneID()); + } + else if (zone_server_data->IsBootingUp()){ + strcpy(zone_data_string, "..."); + } + else{ + zone_data_string[0] = 0; + } - AppendAnyLenString(&output, &outsize, &outlen, " #%-3i %s %15s:%-5i %2i %s:%i %s", zs->GetID(), tmpStatic, inet_ntoa(in), zs->GetPort(), zs->NumPlayers(), zs->GetCAddress(), zs->GetCPort(), tmpZone); + AppendAnyLenString(&output, &outsize, &outlen, + "#%-3i :: %s :: %15s:%-5i :: %2i :: %s:%i :: %s :: (%u)", + zone_server_data->GetID(), + is_static_string, + inet_ntoa(in), + zone_server_data->GetPort(), + zone_server_data->NumPlayers(), + zone_server_data->GetCAddress(), + zone_server_data->GetCPort(), + zone_data_string, + zone_server_data->GetZoneOSProcessID() + ); + if (outlen >= 3584) { connection->SendEmoteMessageRaw(to, 0, 0, 10, output); safe_delete(output); @@ -348,12 +375,12 @@ void ZSList::SendZoneStatus(const char* to, int16 admin, WorldTCPConnection* con } x++; } - else if (zs->GetZoneID() != 0) { - if (zs->GetZoneID()) - strcpy(tmpZone, zs->GetZoneName()); + else if (zone_server_data->GetZoneID() != 0) { + if (zone_server_data->GetZoneID()) + strcpy(zone_data_string, zone_server_data->GetZoneName()); else - tmpZone[0] = 0; - AppendAnyLenString(&output, &outsize, &outlen, " #%i %s %s", zs->GetID(), tmpStatic, tmpZone); + zone_data_string[0] = 0; + AppendAnyLenString(&output, &outsize, &outlen, " #%i %s %s", zone_server_data->GetID(), is_static_string, zone_data_string); if (outlen >= 3584) { connection->SendEmoteMessageRaw(to, 0, 0, 10, output); safe_delete(output); @@ -361,25 +388,32 @@ void ZSList::SendZoneStatus(const char* to, int16 admin, WorldTCPConnection* con outlen = 0; } else { - if (connection->IsConsole()) + if (connection->IsConsole()){ AppendAnyLenString(&output, &outsize, &outlen, "\r\n"); - else + } + else{ AppendAnyLenString(&output, &outsize, &outlen, "^"); + } } x++; } y++; iterator.Advance(); } - if (connection->IsConsole()) + + if (connection->IsConsole()){ AppendAnyLenString(&output, &outsize, &outlen, "%i servers listed. %i servers online.\r\n", x, y); - else + } + else { AppendAnyLenString(&output, &outsize, &outlen, "%i servers listed. %i servers online.^", x, y); - AppendAnyLenString(&output, &outsize, &outlen, "%i zones are static zones, %i zones are booted zones, %i zones available.",z,w,v); -// connection->SendEmoteMessage(to, 0, 0, "%i servers listed. %i servers online.", x, y); -// connection->SendEmoteMessage(to,0,0,"%i zones are static zones, %i zones are booted zones, %i zones available.",z,w,v); - if (output) + } + + AppendAnyLenString(&output, &outsize, &outlen, "%i zones are static zones, %i zones are booted zones, %i zones available.", z, w, v); + + if (output){ connection->SendEmoteMessageRaw(to, 0, 0, 10, output); + } + safe_delete(output); } diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index d36507f04..f6447f3f4 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -49,20 +49,24 @@ extern QueryServConnection QSLink; void CatchSignal(int sig_num); ZoneServer::ZoneServer(EmuTCPConnection* itcpc) -: WorldTCPConnection(), tcpc(itcpc), ls_zboot(5000) { - ID = zoneserver_list.GetNextID(); +: WorldTCPConnection(), tcpc(itcpc), zone_boot_timer(5000) { + + /* Set Process tracking variable defaults */ + memset(zone_name, 0, sizeof(zone_name)); memset(compiled, 0, sizeof(compiled)); - zoneID = 0; - instanceID = 0; + memset(client_address, 0, sizeof(client_address)); + memset(client_local_address, 0, sizeof(client_local_address)); - memset(clientaddress, 0, sizeof(clientaddress)); - memset(clientlocaladdress, 0, sizeof(clientlocaladdress)); - clientport = 0; - BootingUp = false; - authenticated = false; - staticzone = false; - pNumPlayers = 0; + zone_server_id = zoneserver_list.GetNextID(); + zone_server_zone_id = 0; + instance_id = 0; + zone_os_process_id = 0; + client_port = 0; + is_booting_up = false; + is_authenticated = false; + is_static_zone = false; + zone_player_count = 0; } ZoneServer::~ZoneServer() { @@ -72,7 +76,7 @@ ZoneServer::~ZoneServer() { } bool ZoneServer::SetZone(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { - BootingUp = false; + is_booting_up = false; const char* zn = MakeLowerString(database.GetZoneName(iZoneID)); char* longname; @@ -81,17 +85,17 @@ bool ZoneServer::SetZone(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { Log.Out(Logs::Detail, Logs::World_Server,"Setting to '%s' (%d:%d)%s",(zn) ? zn : "",iZoneID, iInstanceID, iStaticZone ? " (Static)" : ""); - zoneID = iZoneID; - instanceID = iInstanceID; + zone_server_zone_id = iZoneID; + instance_id = iInstanceID; if(iZoneID!=0) - oldZoneID = iZoneID; - if (zoneID == 0) { + zone_server_previous_zone_id = iZoneID; + if (zone_server_zone_id == 0) { client_list.CLERemoveZSRef(this); - pNumPlayers = 0; + zone_player_count = 0; LSSleepUpdate(GetPrevZoneID()); } - staticzone = iStaticZone; + is_static_zone = iStaticZone; if (zn) { @@ -111,7 +115,7 @@ bool ZoneServer::SetZone(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { } client_list.ZoneBootup(this); - ls_zboot.Start(); + zone_boot_timer.Start(); return true; } @@ -172,19 +176,19 @@ void ZoneServer::LSSleepUpdate(uint32 zoneid){ bool ZoneServer::Process() { if (!tcpc->Connected()) return false; - if(ls_zboot.Check()){ + if(zone_boot_timer.Check()){ LSBootUpdate(GetZoneID(), true); - ls_zboot.Disable(); + zone_boot_timer.Disable(); } ServerPacket *pack = 0; while((pack = tcpc->PopPacket())) { - if (!authenticated) { + if (!is_authenticated) { if (WorldConfig::get()->SharedKey.length() > 0) { if (pack->opcode == ServerOP_ZAAuth && pack->size == 16) { uint8 tmppass[16]; MD5::Generate((const uchar*) WorldConfig::get()->SharedKey.c_str(), WorldConfig::get()->SharedKey.length(), tmppass); if (memcmp(pack->pBuffer, tmppass, 16) == 0) - authenticated = true; + is_authenticated = true; else { struct in_addr in; in.s_addr = GetIP(); @@ -210,7 +214,7 @@ bool ZoneServer::Process() { else { Log.Out(Logs::Detail, Logs::World_Server,"**WARNING** You have not configured a world shared key in your config file. You should add a STRING element to your element to prevent unauthroized zone access."); - authenticated = true; + is_authenticated = true; } } switch(pack->opcode) { @@ -582,29 +586,33 @@ bool ZoneServer::Process() { ServerConnectInfo* sci = (ServerConnectInfo*) pack->pBuffer; if (!sci->port) { - clientport = zoneserver_list.GetAvailableZonePort(); + client_port = zoneserver_list.GetAvailableZonePort(); ServerPacket p(ServerOP_SetConnectInfo, sizeof(ServerConnectInfo)); memset(p.pBuffer,0,sizeof(ServerConnectInfo)); ServerConnectInfo* sci = (ServerConnectInfo*) p.pBuffer; - sci->port = clientport; + sci->port = client_port; SendPacket(&p); - Log.Out(Logs::Detail, Logs::World_Server,"Auto zone port configuration. Telling zone to use port %d",clientport); + Log.Out(Logs::Detail, Logs::World_Server,"Auto zone port configuration. Telling zone to use port %d",client_port); } else { - clientport = sci->port; - Log.Out(Logs::Detail, Logs::World_Server,"Zone specified port %d.",clientport); + client_port = sci->port; + Log.Out(Logs::Detail, Logs::World_Server,"Zone specified port %d.",client_port); } if(sci->address[0]) { - strn0cpy(clientaddress, sci->address, 250); + strn0cpy(client_address, sci->address, 250); Log.Out(Logs::Detail, Logs::World_Server, "Zone specified address %s.", sci->address); } if(sci->local_address[0]) { - strn0cpy(clientlocaladdress, sci->local_address, 250); + strn0cpy(client_local_address, sci->local_address, 250); Log.Out(Logs::Detail, Logs::World_Server, "Zone specified local address %s.", sci->address); } + if (sci->process_id){ + zone_os_process_id = sci->process_id; + } + } case ServerOP_SetLaunchName: { if(pack->size != sizeof(LaunchName_Struct)) @@ -818,6 +826,11 @@ bool ZoneServer::Process() { RuleManager::Instance()->LoadRules(&database, "default"); break; } + case ServerOP_ReloadPerlExportSettings: + { + zoneserver_list.SendPacket(pack); + break; + } case ServerOP_CameraShake: { zoneserver_list.SendPacket(pack); @@ -1411,13 +1424,13 @@ void ZoneServer::ChangeWID(uint32 iCharID, uint32 iWID) { void ZoneServer::TriggerBootup(uint32 iZoneID, uint32 iInstanceID, const char* adminname, bool iMakeStatic) { - BootingUp = true; - zoneID = iZoneID; - instanceID = iInstanceID; + is_booting_up = true; + zone_server_zone_id = iZoneID; + instance_id = iInstanceID; auto pack = new ServerPacket(ServerOP_ZoneBootup, sizeof(ServerZoneStateChange_struct)); ServerZoneStateChange_struct* s = (ServerZoneStateChange_struct *) pack->pBuffer; - s->ZoneServerID = ID; + s->ZoneServerID = zone_server_id; if (adminname != 0) strcpy(s->adminname, adminname); @@ -1434,7 +1447,7 @@ void ZoneServer::TriggerBootup(uint32 iZoneID, uint32 iInstanceID, const char* a } void ZoneServer::IncomingClient(Client* client) { - BootingUp = true; + is_booting_up = true; auto pack = new ServerPacket(ServerOP_ZoneIncClient, sizeof(ServerZoneIncomingClient_Struct)); ServerZoneIncomingClient_Struct* s = (ServerZoneIncomingClient_Struct*) pack->pBuffer; s->zoneid = GetZoneID(); diff --git a/world/zoneserver.h b/world/zoneserver.h index 125ac33f9..8d26271d1 100644 --- a/world/zoneserver.h +++ b/world/zoneserver.h @@ -44,7 +44,7 @@ public: void LSBootUpdate(uint32 zoneid, uint32 iInstanceID = 0, bool startup = false); void LSSleepUpdate(uint32 zoneid); void LSShutDownUpdate(uint32 zoneid); - uint32 GetPrevZoneID() { return oldZoneID; } + uint32 GetPrevZoneID() { return zone_server_previous_zone_id; } void ChangeWID(uint32 iCharID, uint32 iWID); void SendGroupIDs(); @@ -52,41 +52,45 @@ public: inline const char* GetZoneLongName() const { return long_name; } const char* GetCompileTime() const{ return compiled; } void SetCompile(char* in_compile){ strcpy(compiled,in_compile); } - inline uint32 GetZoneID() const { return zoneID; } + inline uint32 GetZoneID() const { return zone_server_zone_id; } inline uint32 GetIP() const { return tcpc->GetrIP(); } inline uint16 GetPort() const { return tcpc->GetrPort(); } - inline const char* GetCAddress() const { return clientaddress; } - inline const char* GetCLocalAddress() const { return clientlocaladdress; } - inline uint16 GetCPort() const { return clientport; } - inline uint32 GetID() const { return ID; } - inline bool IsBootingUp() const { return BootingUp; } - inline bool IsStaticZone() const{ return staticzone; } - inline uint32 NumPlayers() const { return pNumPlayers; } - inline void AddPlayer() { pNumPlayers++; } - inline void RemovePlayer() { pNumPlayers--; } + inline const char* GetCAddress() const { return client_address; } + inline const char* GetCLocalAddress() const { return client_local_address; } + inline uint16 GetCPort() const { return client_port; } + inline uint32 GetID() const { return zone_server_id; } + inline bool IsBootingUp() const { return is_booting_up; } + inline bool IsStaticZone() const{ return is_static_zone; } + inline uint32 NumPlayers() const { return zone_player_count; } + inline void AddPlayer() { zone_player_count++; } + inline void RemovePlayer() { zone_player_count--; } inline const char * GetLaunchName() const { return(launcher_name.c_str()); } inline const char * GetLaunchedName() const { return(launched_name.c_str()); } - inline uint32 GetInstanceID() { return instanceID; } - inline void SetInstanceID(uint32 i) { instanceID = i; } + inline uint32 GetInstanceID() { return instance_id; } + inline void SetInstanceID(uint32 i) { instance_id = i; } + + inline uint32 GetZoneOSProcessID() { return zone_os_process_id; } + private: EmuTCPConnection* const tcpc; - uint32 ID; - char clientaddress[250]; - char clientlocaladdress[250]; - uint16 clientport; - bool BootingUp; - bool staticzone; - bool authenticated; - uint32 pNumPlayers; + uint32 zone_server_id; + char client_address[250]; + char client_local_address[250]; + uint16 client_port; + bool is_booting_up; + bool is_static_zone; + bool is_authenticated; + uint32 zone_player_count; char compiled[25]; char zone_name[32]; char long_name[256]; - uint32 zoneID; - uint32 oldZoneID; - Timer ls_zboot; - uint32 instanceID; //instance ids contain a zone id, and a zone version + uint32 zone_server_zone_id; + uint32 zone_server_previous_zone_id; + Timer zone_boot_timer; + uint32 instance_id; //instance ids contain a zone id, and a zone version + uint32 zone_os_process_id; std::string launcher_name; //the launcher which started us std::string launched_name; //the name of the zone we launched. }; diff --git a/zone/aggro.cpp b/zone/aggro.cpp index 574ac335d..a1903c8ca 100644 --- a/zone/aggro.cpp +++ b/zone/aggro.cpp @@ -1189,21 +1189,21 @@ int32 Mob::CheckHealAggroAmount(uint16 spell_id, Mob *target, uint32 heal_possib } void Mob::AddFeignMemory(Client* attacker) { - if(feign_memory_list.empty() && AIfeignremember_timer != nullptr) - AIfeignremember_timer->Start(AIfeignremember_delay); + if(feign_memory_list.empty() && AI_feign_remember_timer != nullptr) + AI_feign_remember_timer->Start(AIfeignremember_delay); feign_memory_list.insert(attacker->CharacterID()); } void Mob::RemoveFromFeignMemory(Client* attacker) { feign_memory_list.erase(attacker->CharacterID()); - if(feign_memory_list.empty() && AIfeignremember_timer != nullptr) - AIfeignremember_timer->Disable(); + if(feign_memory_list.empty() && AI_feign_remember_timer != nullptr) + AI_feign_remember_timer->Disable(); if(feign_memory_list.empty()) { minLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMin); maxLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMax); - if(AIfeignremember_timer != nullptr) - AIfeignremember_timer->Disable(); + if(AI_feign_remember_timer != nullptr) + AI_feign_remember_timer->Disable(); } } @@ -1220,8 +1220,8 @@ void Mob::ClearFeignMemory() { feign_memory_list.clear(); minLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMin); maxLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMax); - if(AIfeignremember_timer != nullptr) - AIfeignremember_timer->Disable(); + if(AI_feign_remember_timer != nullptr) + AI_feign_remember_timer->Disable(); } bool Mob::PassCharismaCheck(Mob* caster, uint16 spell_id) { diff --git a/zone/bot.cpp b/zone/bot.cpp index ac84ffc5c..477581eba 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -6,7 +6,7 @@ #include "quest_parser_collection.h" #include "../common/string_util.h" -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; // This constructor is used during the bot create command Bot::Bot(NPCType npcTypeData, Client* botOwner) : NPC(&npcTypeData, nullptr, glm::vec4(), 0, false), rest_timer(1) { @@ -2286,7 +2286,7 @@ bool Bot::Process() { BuffProcess(); CalcRestState(); - if(curfp) + if(currently_fleeing) ProcessFlee(); if(GetHP() < GetMaxHP()) @@ -2685,7 +2685,7 @@ void Bot::AI_Process() { if(GetHasBeenSummoned()) { if(IsBotCaster() || IsBotArcher()) { - if (AImovement_timer->Check()) { + if (AI_movement_timer->Check()) { if(!GetTarget() || (IsBotCaster() && !IsBotCasterCombatRange(GetTarget())) || (IsBotArcher() && IsArcheryRange(GetTarget())) || (DistanceSquaredNoZ(static_cast(m_Position), m_PreSummonLocation) < 10)) { if(GetTarget()) FaceTarget(GetTarget()); @@ -2831,7 +2831,7 @@ void Bot::AI_Process() { } } - if(AImovement_timer->Check()) { + if(AI_movement_timer->Check()) { if(!IsMoving() && GetClass() == ROGUE && !BehindMob(GetTarget(), GetX(), GetY())) { // Move the rogue to behind the mob float newX = 0; @@ -2967,7 +2967,7 @@ void Bot::AI_Process() { AI_PursueCastCheck(); } - if (AImovement_timer->Check()) { + if (AI_movement_timer->Check()) { if(!IsRooted()) { Log.Out(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", GetTarget()->GetCleanName()); CalculateNewPosition2(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), GetRunspeed()); @@ -2995,7 +2995,7 @@ void Bot::AI_Process() { if (m_PlayerState & static_cast(PlayerState::Aggressive)) SendRemovePlayerState(PlayerState::Aggressive); - if(!IsMoving() && AIthink_timer->Check() && !spellend_timer.Enabled()) { + if(!IsMoving() && AI_think_timer->Check() && !spellend_timer.Enabled()) { if(GetBotStance() != BotStancePassive) { if(!AI_IdleCastCheck() && !IsCasting()) BotMeditate(true); @@ -3004,7 +3004,7 @@ void Bot::AI_Process() { BotMeditate(true); } - if(AImovement_timer->Check()) { + if(AI_movement_timer->Check()) { if(GetFollowID()) { Mob* follow = entity_list.GetMob(GetFollowID()); if(follow) { @@ -3737,9 +3737,9 @@ Bot* Bot::LoadBot(uint32 botID, std::string* errorMessage) " `drakkin_tattoo`," " `drakkin_details`," " `ac`," /*not in-use[26]*/ - " `atk`," + " `atk`," /*not in-use[27]*/ " `hp`," - " `mana`," /*not in-use[29]*/ + " `mana`," " `str`," /*not in-use[30]*/ " `sta`," /*not in-use[31]*/ " `cha`," /*not in-use[32]*/ @@ -3753,8 +3753,8 @@ Bot* Bot::LoadBot(uint32 botID, std::string* errorMessage) " `poison`," /*not in-use[40]*/ " `disease`," /*not in-use[41]*/ " `corruption`," /*not in-use[42]*/ - " `show_helm`," - " `follow_distance`" + " `show_helm`,"//43 + " `follow_distance`"//44 " FROM `bot_data`" " WHERE `bot_id` = '%u'", botID @@ -3791,8 +3791,8 @@ Bot* Bot::LoadBot(uint32 botID, std::string* errorMessage) atoi(row[23]), atoi(row[24]), atoi(row[25]), - atoi(row[27]), atoi(row[28]), + atoi(row[29]), defaultNPCTypeStruct.MR, defaultNPCTypeStruct.CR, defaultNPCTypeStruct.DR, diff --git a/zone/client.cpp b/zone/client.cpp index 24a916b2a..f65a30350 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -53,7 +53,7 @@ extern volatile bool RunLoops; extern QueryServ* QServ; extern EntityList entity_list; extern Zone* zone; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; extern WorldServer worldserver; extern uint32 numclients; extern PetitionList petition_list; @@ -371,7 +371,7 @@ Client::~Client() { GetTarget()->IsTargeted(-1); //if we are in a group and we are not zoning, force leave the group - if(isgrouped && !zoning && ZoneLoaded) + if(isgrouped && !zoning && is_zone_loaded) LeaveGroup(); UpdateWho(2); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index d8ffb6a68..a766f0470 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -66,7 +66,7 @@ extern QueryServ* QServ; extern Zone* zone; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; extern WorldServer worldserver; extern PetitionList petition_list; extern EntityList entity_list; @@ -386,6 +386,7 @@ void MapOpcodes() ConnectedOpcodes[OP_WhoAllRequest] = &Client::Handle_OP_WhoAllRequest; ConnectedOpcodes[OP_WorldUnknown001] = &Client::Handle_OP_Ignore; ConnectedOpcodes[OP_XTargetAutoAddHaters] = &Client::Handle_OP_XTargetAutoAddHaters; + ConnectedOpcodes[OP_XTargetOpen] = &Client::Handle_OP_XTargetOpen; ConnectedOpcodes[OP_XTargetRequest] = &Client::Handle_OP_XTargetRequest; ConnectedOpcodes[OP_YellForHelp] = &Client::Handle_OP_YellForHelp; ConnectedOpcodes[OP_ZoneChange] = &Client::Handle_OP_ZoneChange; @@ -6682,20 +6683,6 @@ void Client::Handle_OP_GuildBank(const EQApplicationPacket *app) uint32 Action = VARSTRUCT_DECODE_TYPE(uint32, Buffer); uint32 sentAction = Action; - if (GetClientVersion() >= ClientVersion::RoF) - { - Action += 1; - /* - // Need to find all of the action types for RoF and switch case here - switch(Action) - { - case 4: - Action = 5; - break; - } - */ - } - if (!IsInAGuild()) { Message(13, "You must be in a Guild to use the Guild Bank."); @@ -13925,6 +13912,18 @@ void Client::Handle_OP_XTargetAutoAddHaters(const EQApplicationPacket *app) XTargetAutoAddHaters = app->ReadUInt8(0); } +void Client::Handle_OP_XTargetOpen(const EQApplicationPacket *app) +{ + if (app->size != 4) { + Log.Out(Logs::General, Logs::None, "Size mismatch in OP_XTargetOpen, expected 1, got %i", app->size); + DumpPacket(app); + return; + } + + auto outapp = new EQApplicationPacket(OP_XTargetOpenResponse, 0); + FastQueuePacket(&outapp); +} + void Client::Handle_OP_XTargetRequest(const EQApplicationPacket *app) { if (app->size < 12) diff --git a/zone/client_packet.h b/zone/client_packet.h index a39e3fb74..2635724dd 100644 --- a/zone/client_packet.h +++ b/zone/client_packet.h @@ -292,6 +292,7 @@ void Handle_OP_WearChange(const EQApplicationPacket *app); void Handle_OP_WhoAllRequest(const EQApplicationPacket *app); void Handle_OP_XTargetAutoAddHaters(const EQApplicationPacket *app); + void Handle_OP_XTargetOpen(const EQApplicationPacket *app); void Handle_OP_XTargetRequest(const EQApplicationPacket *app); void Handle_OP_YellForHelp(const EQApplicationPacket *app); void Handle_OP_ZoneChange(const EQApplicationPacket *app); diff --git a/zone/client_process.cpp b/zone/client_process.cpp index f7fb46d12..a0be235a7 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -55,7 +55,7 @@ extern QueryServ* QServ; extern Zone* zone; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; extern WorldServer worldserver; extern PetitionList petition_list; extern EntityList entity_list; diff --git a/zone/command.cpp b/zone/command.cpp index 5fe6244ad..1aaf159b0 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -334,6 +334,7 @@ int command_init(void) { command_add("reloadallrules", "Executes a reload of all rules.", 80, command_reloadallrules) || command_add("reloademote", "Reloads NPC Emotes", 80, command_reloademote) || command_add("reloadlevelmods", nullptr,255, command_reloadlevelmods) || + command_add("reloadperlexportsettings", nullptr, 255, command_reloadperlexportsettings) || command_add("reloadqst", " - Clear quest cache (any argument causes it to also stop all timers)", 150, command_reloadqst) || command_add("reloadquest", " - Clear quest cache (any argument causes it to also stop all timers)", 150, command_reloadqst) || command_add("reloadrulesworld", "Executes a reload of all rules in world specifically.", 80, command_reloadworldrules) || @@ -343,6 +344,7 @@ int command_init(void) { command_add("reloadzonepoints", "- Reload zone points from database", 150, command_reloadzps) || command_add("reloadzps", nullptr,0, command_reloadzps) || command_add("repop", "[delay] - Repop the zone with optional delay", 100, command_repop) || + command_add("repopclose", "[distance in units] Repops only NPC's nearby for fast development purposes", 100, command_repopclose) || command_add("resetaa", "- Resets a Player's AA in their profile and refunds spent AA's to unspent, may disconnect player.", 200, command_resetaa) || command_add("resetaa_timer", "Command to reset AA cooldown timers.", 200, command_resetaa_timer) || command_add("revoke", "[charname] [1/0] - Makes charname unable to talk on OOC", 200, command_revoke) || @@ -3920,9 +3922,11 @@ void command_repop(Client *c, const Seperator *sep) LinkedListIterator iterator(zone->spawn2_list); iterator.Reset(); while (iterator.MoreElements()) { - std::string query = StringFormat("DELETE FROM respawn_times WHERE id = %lu AND instance_id = %lu", - (unsigned long)iterator.GetData()->GetID(), - (unsigned long)zone->GetInstanceID()); + std::string query = StringFormat( + "DELETE FROM respawn_times WHERE id = %lu AND instance_id = %lu", + (unsigned long)iterator.GetData()->GetID(), + (unsigned long)zone->GetInstanceID() + ); auto results = database.QueryDatabase(query); iterator.Advance(); } @@ -3939,6 +3943,33 @@ void command_repop(Client *c, const Seperator *sep) zone->Repop(atoi(sep->arg[timearg])*1000); } +void command_repopclose(Client *c, const Seperator *sep) +{ + int repop_distance = 500; + + if (sep->arg[1] && strcasecmp(sep->arg[1], "force") == 0) { + + LinkedListIterator iterator(zone->spawn2_list); + iterator.Reset(); + while (iterator.MoreElements()) { + std::string query = StringFormat( + "DELETE FROM respawn_times WHERE id = %lu AND instance_id = %lu", + (unsigned long)iterator.GetData()->GetID(), + (unsigned long)zone->GetInstanceID() + ); + auto results = database.QueryDatabase(query); + iterator.Advance(); + } + c->Message(0, "Zone depop: Force resetting spawn timers."); + } + if (sep->IsNumber(1)) { + repop_distance = atoi(sep->arg[1]); + } + + c->Message(0, "Zone depoped. Repopping NPC's within %i distance units", repop_distance); + zone->RepopClose(c->GetPosition(), repop_distance); +} + void command_spawnstatus(Client *c, const Seperator *sep) { if((sep->arg[1][0] == 'e') | (sep->arg[1][0] == 'E')) @@ -10768,4 +10799,16 @@ void command_apply_shared_memory(Client *c, const Seperator *sep) { strcpy((char*)pack.pBuffer, hotfix_name.c_str()); } worldserver.SendPacket(&pack); +} + +void command_reloadperlexportsettings(Client *c, const Seperator *sep) +{ + if (c) + { + ServerPacket *pack = new ServerPacket(ServerOP_ReloadPerlExportSettings, 0); + worldserver.SendPacket(pack); + c->Message(13, "Successfully sent the packet to world to reload Perl Export settings"); + safe_delete(pack); + + } } \ No newline at end of file diff --git a/zone/command.h b/zone/command.h index 03e30a786..ac6107a20 100644 --- a/zone/command.h +++ b/zone/command.h @@ -187,6 +187,7 @@ void command_myskills(Client *c, const Seperator *sep); void command_depop(Client *c, const Seperator *sep); void command_depopzone(Client *c, const Seperator *sep); void command_repop(Client *c, const Seperator *sep); +void command_repopclose(Client *c, const Seperator *sep); void command_spawnstatus(Client *c, const Seperator *sep); void command_nukebuffs(Client *c, const Seperator *sep); void command_zuwcoords(Client *c, const Seperator *sep); @@ -332,6 +333,7 @@ void command_load_shared_memory(Client *c, const Seperator *sep); void command_apply_shared_memory(Client *c, const Seperator *sep); void command_untraindisc(Client *c, const Seperator *sep); void command_untraindiscs(Client *c, const Seperator *sep); +void command_reloadperlexportsettings(Client *c, const Seperator *sep); #ifdef EQPROFILE void command_profiledump(Client *c, const Seperator *sep); diff --git a/zone/embparser.cpp b/zone/embparser.cpp index 389f93d1f..617d17d2e 100644 --- a/zone/embparser.cpp +++ b/zone/embparser.cpp @@ -183,15 +183,31 @@ int PerlembParser::EventCommon(QuestEventID event, uint32 objid, const char * da int char_id = 0; ExportCharID(package_name, char_id, npcmob, mob); - ExportQGlobals(isPlayerQuest, isGlobalPlayerQuest, isGlobalNPC, isItemQuest, isSpellQuest, - package_name, npcmob, mob, char_id); + + /* Check for QGlobal export event enable */ + if (parse->perl_event_export_settings[event].qglobals){ + ExportQGlobals(isPlayerQuest, isGlobalPlayerQuest, isGlobalNPC, isItemQuest, isSpellQuest, package_name, npcmob, mob, char_id); + } - //ExportGenericVariables(); - ExportMobVariables(isPlayerQuest, isGlobalPlayerQuest, isGlobalNPC, isItemQuest, isSpellQuest, - package_name, mob, npcmob); - ExportZoneVariables(package_name); - ExportItemVariables(package_name, mob); - ExportEventVariables(package_name, event, objid, data, npcmob, iteminst, mob, extradata, extra_pointers); + /* Check for Mob export event enable */ + if (parse->perl_event_export_settings[event].mob){ + ExportMobVariables(isPlayerQuest, isGlobalPlayerQuest, isGlobalNPC, isItemQuest, isSpellQuest, package_name, mob, npcmob); + } + + /* Check for Zone export event enable */ + if (parse->perl_event_export_settings[event].zone){ + ExportZoneVariables(package_name); + } + + /* Check for Item export event enable */ + if (parse->perl_event_export_settings[event].item){ + ExportItemVariables(package_name, mob); + } + + /* Check for Event export event enable */ + if (parse->perl_event_export_settings[event].event_variables){ + ExportEventVariables(package_name, event, objid, data, npcmob, iteminst, mob, extradata, extra_pointers); + } if(isPlayerQuest || isGlobalPlayerQuest){ return SendCommands(package_name.c_str(), sub_name, 0, mob, mob, nullptr); @@ -199,8 +215,7 @@ int PerlembParser::EventCommon(QuestEventID event, uint32 objid, const char * da else if(isItemQuest) { return SendCommands(package_name.c_str(), sub_name, 0, mob, mob, iteminst); } - else if(isSpellQuest) - { + else if(isSpellQuest){ if(mob) { return SendCommands(package_name.c_str(), sub_name, 0, mob, mob, nullptr); } else { diff --git a/zone/embparser.h b/zone/embparser.h index 1357ae20b..9b33b1ad2 100644 --- a/zone/embparser.h +++ b/zone/embparser.h @@ -75,6 +75,7 @@ public: virtual std::string GetVar(std::string name); virtual void ReloadQuests(); virtual uint32 GetIdentifier() { return 0xf8b05c11; } + private: Embperl *perl; diff --git a/zone/entity.cpp b/zone/entity.cpp index af256a9ba..23848f73e 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -51,7 +51,7 @@ #endif extern Zone *zone; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; extern WorldServer worldserver; extern NetConnection net; extern uint32 numclients; @@ -2350,7 +2350,7 @@ void EntityList::Clear() void EntityList::UpdateWho(bool iSendFullUpdate) { - if ((!worldserver.Connected()) || !ZoneLoaded) + if ((!worldserver.Connected()) || !is_zone_loaded) return; uint32 tmpNumUpdates = numclients + 5; ServerPacket* pack = 0; @@ -2448,6 +2448,8 @@ void EntityList::Depop(bool StartSpawnTimer) if (pnpc->IsFindable()) UpdateFindableNPCState(pnpc, true); + pnpc->WipeHateList(); + pnpc->Depop(StartSpawnTimer); } } diff --git a/zone/fearpath.cpp b/zone/fearpath.cpp index 0fd5ffa98..bbcf4d4c6 100644 --- a/zone/fearpath.cpp +++ b/zone/fearpath.cpp @@ -33,7 +33,7 @@ extern Zone* zone; //this is called whenever we are damaged to process possible fleeing void Mob::CheckFlee() { //if were allready fleeing, dont need to check more... - if(flee_mode && curfp) + if(flee_mode && currently_fleeing) return; //dont bother if we are immune to fleeing @@ -101,7 +101,7 @@ void Mob::ProcessFlee() //When ImmuneToFlee effect fades it will turn fear back on and check if it can still flee. if (flee_mode && (GetSpecialAbility(IMMUNE_FLEEING) || spellbonuses.ImmuneToFlee) && !spellbonuses.IsFeared && !spellbonuses.IsBlind) { - curfp = false; + currently_fleeing = false; return; } @@ -118,7 +118,7 @@ void Mob::ProcessFlee() //see if we are legitimately feared or blind now if (!spellbonuses.IsFeared && !spellbonuses.IsBlind) { //not feared or blind... were done... - curfp = false; + currently_fleeing = false; return; } } @@ -140,7 +140,7 @@ void Mob::CalculateNewFearpoint() if(Route.size() > 0) { m_FearWalkTarget = glm::vec3(Loc.x, Loc.y, Loc.z); - curfp = true; + currently_fleeing = true; Log.Out(Logs::Detail, Logs::None, "Feared to node %i (%8.3f, %8.3f, %8.3f)", Node, Loc.x, Loc.y, Loc.z); return; @@ -151,7 +151,7 @@ void Mob::CalculateNewFearpoint() int loop = 0; float ranx, rany, ranz; - curfp = false; + currently_fleeing = false; while (loop < 100) //Max 100 tries { int ran = 250 - (loop*2); @@ -164,11 +164,11 @@ void Mob::CalculateNewFearpoint() float fdist = ranz - GetZ(); if (fdist >= -12 && fdist <= 12 && CheckCoordLosNoZLeaps(GetX(),GetY(),GetZ(),ranx,rany,ranz)) { - curfp = true; + currently_fleeing = true; break; } } - if (curfp) + if (currently_fleeing) m_FearWalkTarget = glm::vec3(ranx, rany, ranz); else //Break fear BuffFadeByEffect(SE_Fear); diff --git a/zone/guild.cpp b/zone/guild.cpp index 12f785b02..7b3c104f8 100644 --- a/zone/guild.cpp +++ b/zone/guild.cpp @@ -248,7 +248,9 @@ void Client::RefreshGuildInfo() if((guild_id != OldGuildID) && GuildBanks) { - ClearGuildBank(); + // Unsure about this for RoF+ ... But they don't have that action anymore so fuck it + if (GetClientVersion() < ClientVersion::RoF) + ClearGuildBank(); if(guild_id != GUILD_NONE) GuildBanks->SendGuildBank(this); diff --git a/zone/guild_mgr.cpp b/zone/guild_mgr.cpp index a5188def9..ed9957908 100644 --- a/zone/guild_mgr.cpp +++ b/zone/guild_mgr.cpp @@ -29,7 +29,7 @@ ZoneGuildManager guild_mgr; GuildBankManager *GuildBanks; extern WorldServer worldserver; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; void ZoneGuildManager::SendGuildRefresh(uint32 guild_id, bool name, bool motd, bool rank, bool relation) { Log.Out(Logs::Detail, Logs::Guilds, "Sending guild refresh for %d to world, changes: name=%d, motd=%d, rank=d, relation=%d", guild_id, name, motd, rank, relation); @@ -334,7 +334,7 @@ void ZoneGuildManager::ProcessWorldPacket(ServerPacket *pack) { case ServerOP_GuildRankUpdate: { - if(ZoneLoaded) + if(is_zone_loaded) { if(pack->size != sizeof(ServerGuildRankUpdate_Struct)) { @@ -388,7 +388,7 @@ void ZoneGuildManager::ProcessWorldPacket(ServerPacket *pack) { { ServerGuildMemberUpdate_Struct *sgmus = (ServerGuildMemberUpdate_Struct*)pack->pBuffer; - if(ZoneLoaded) + if(is_zone_loaded) { EQApplicationPacket *outapp = new EQApplicationPacket(OP_GuildMemberUpdate, sizeof(GuildMemberUpdate_Struct)); @@ -407,7 +407,7 @@ void ZoneGuildManager::ProcessWorldPacket(ServerPacket *pack) { break; } case ServerOP_OnlineGuildMembersResponse: - if (ZoneLoaded) + if (is_zone_loaded) { char *Buffer = (char *)pack->pBuffer; @@ -443,7 +443,7 @@ void ZoneGuildManager::ProcessWorldPacket(ServerPacket *pack) { case ServerOP_LFGuildUpdate: { - if(ZoneLoaded) + if(is_zone_loaded) { char GuildName[33]; char Comments[257]; @@ -688,11 +688,68 @@ void GuildBankManager::SendGuildBank(Client *c) return; } + auto &guild_bank = *Iterator; + + // RoF+ uses a bulk list packet -- This is also how the Action 0 of older clients basically works + if (c->GetClientVersionBit() & BIT_RoFAndLater) { + auto outapp = new EQApplicationPacket(OP_GuildBankItemList, sizeof(GuildBankItemListEntry_Struct) * 240); + for (int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i) { + const Item_Struct *Item = database.GetItem(guild_bank->Items.DepositArea[i].ItemID); + if (Item) { + outapp->WriteUInt8(1); + outapp->WriteUInt32(guild_bank->Items.DepositArea[i].Permissions); + outapp->WriteString(guild_bank->Items.DepositArea[i].WhoFor); + outapp->WriteString(guild_bank->Items.DepositArea[i].Donator); + outapp->WriteUInt32(Item->ID); + outapp->WriteUInt32(Item->Icon); + if (Item->Stackable) { + outapp->WriteUInt32(guild_bank->Items.DepositArea[i].Quantity); + outapp->WriteUInt8(Item->StackSize == guild_bank->Items.DepositArea[i].Quantity ? 0 : 1); + } else { + outapp->WriteUInt32(1); + outapp->WriteUInt8(0); + } + outapp->WriteUInt8(Item->IsEquipable(c->GetBaseRace(), c->GetBaseClass()) ? 1 : 0); + outapp->WriteString(Item->Name); + } else { + outapp->WriteUInt8(0); // empty + } + } + outapp->SetWritePosition(outapp->GetWritePosition() + 20); // newer clients have 40 deposit slots, keep them 0 for now + + for (int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i) { + const Item_Struct *Item = database.GetItem(guild_bank->Items.MainArea[i].ItemID); + if (Item) { + outapp->WriteUInt8(1); + outapp->WriteUInt32(guild_bank->Items.MainArea[i].Permissions); + outapp->WriteString(guild_bank->Items.MainArea[i].WhoFor); + outapp->WriteString(guild_bank->Items.MainArea[i].Donator); + outapp->WriteUInt32(Item->ID); + outapp->WriteUInt32(Item->Icon); + if (Item->Stackable) { + outapp->WriteUInt32(guild_bank->Items.MainArea[i].Quantity); + outapp->WriteUInt8(Item->StackSize == guild_bank->Items.MainArea[i].Quantity ? 0 : 1); + } else { + outapp->WriteUInt32(1); + outapp->WriteUInt8(0); + } + outapp->WriteUInt8(Item->IsEquipable(c->GetBaseRace(), c->GetBaseClass()) ? 1 : 0); + outapp->WriteString(Item->Name); + } else { + outapp->WriteUInt8(0); // empty + } + } + + outapp->size = outapp->GetWritePosition(); // truncate to used size + c->FastQueuePacket(&outapp); + return; + } + for(int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i) { - if((*Iterator)->Items.DepositArea[i].ItemID > 0) + if(guild_bank->Items.DepositArea[i].ItemID > 0) { - const Item_Struct *Item = database.GetItem((*Iterator)->Items.DepositArea[i].ItemID); + const Item_Struct *Item = database.GetItem(guild_bank->Items.DepositArea[i].ItemID); if(!Item) continue; @@ -703,22 +760,22 @@ void GuildBankManager::SendGuildBank(Client *c) if(!Item->Stackable) gbius->Init(GuildBankItemUpdate, 1, i, GuildBankDepositArea, 1, Item->ID, Item->Icon, 1, - (*Iterator)->Items.DepositArea[i].Permissions, 0, 0); + guild_bank->Items.DepositArea[i].Permissions, 0, 0); else { - if((*Iterator)->Items.DepositArea[i].Quantity == Item->StackSize) + if(guild_bank->Items.DepositArea[i].Quantity == Item->StackSize) gbius->Init(GuildBankItemUpdate, 1, i, GuildBankDepositArea, 1, Item->ID, Item->Icon, - (*Iterator)->Items.DepositArea[i].Quantity, (*Iterator)->Items.DepositArea[i].Permissions, 0, 0); + guild_bank->Items.DepositArea[i].Quantity, guild_bank->Items.DepositArea[i].Permissions, 0, 0); else gbius->Init(GuildBankItemUpdate, 1, i, GuildBankDepositArea, 1, Item->ID, Item->Icon, - (*Iterator)->Items.DepositArea[i].Quantity, (*Iterator)->Items.DepositArea[i].Permissions, 1, 0); + guild_bank->Items.DepositArea[i].Quantity, guild_bank->Items.DepositArea[i].Permissions, 1, 0); } strn0cpy(gbius->ItemName, Item->Name, sizeof(gbius->ItemName)); - strn0cpy(gbius->Donator, (*Iterator)->Items.DepositArea[i].Donator, sizeof(gbius->Donator)); + strn0cpy(gbius->Donator, guild_bank->Items.DepositArea[i].Donator, sizeof(gbius->Donator)); - strn0cpy(gbius->WhoFor, (*Iterator)->Items.DepositArea[i].WhoFor, sizeof(gbius->WhoFor)); + strn0cpy(gbius->WhoFor, guild_bank->Items.DepositArea[i].WhoFor, sizeof(gbius->WhoFor)); c->FastQueuePacket(&outapp); } @@ -726,9 +783,9 @@ void GuildBankManager::SendGuildBank(Client *c) for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i) { - if((*Iterator)->Items.MainArea[i].ItemID > 0) + if(guild_bank->Items.MainArea[i].ItemID > 0) { - const Item_Struct *Item = database.GetItem((*Iterator)->Items.MainArea[i].ItemID); + const Item_Struct *Item = database.GetItem(guild_bank->Items.MainArea[i].ItemID); if(!Item) continue; @@ -741,22 +798,22 @@ void GuildBankManager::SendGuildBank(Client *c) if(!Item->Stackable) gbius->Init(GuildBankItemUpdate, 1, i, GuildBankMainArea, 1, Item->ID, Item->Icon, 1, - (*Iterator)->Items.MainArea[i].Permissions, 0, Useable); + guild_bank->Items.MainArea[i].Permissions, 0, Useable); else { - if((*Iterator)->Items.MainArea[i].Quantity == Item->StackSize) + if(guild_bank->Items.MainArea[i].Quantity == Item->StackSize) gbius->Init(GuildBankItemUpdate, 1, i, GuildBankMainArea, 1, Item->ID, Item->Icon, - (*Iterator)->Items.MainArea[i].Quantity, (*Iterator)->Items.MainArea[i].Permissions, 0, Useable); + guild_bank->Items.MainArea[i].Quantity, guild_bank->Items.MainArea[i].Permissions, 0, Useable); else gbius->Init(GuildBankItemUpdate, 1, i, GuildBankMainArea, 1, Item->ID, Item->Icon, - (*Iterator)->Items.MainArea[i].Quantity, (*Iterator)->Items.MainArea[i].Permissions, 1, Useable); + guild_bank->Items.MainArea[i].Quantity, guild_bank->Items.MainArea[i].Permissions, 1, Useable); } strn0cpy(gbius->ItemName, Item->Name, sizeof(gbius->ItemName)); - strn0cpy(gbius->Donator, (*Iterator)->Items.MainArea[i].Donator, sizeof(gbius->Donator)); + strn0cpy(gbius->Donator, guild_bank->Items.MainArea[i].Donator, sizeof(gbius->Donator)); - strn0cpy(gbius->WhoFor, (*Iterator)->Items.MainArea[i].WhoFor, sizeof(gbius->WhoFor)); + strn0cpy(gbius->WhoFor, guild_bank->Items.MainArea[i].WhoFor, sizeof(gbius->WhoFor)); c->FastQueuePacket(&outapp); } diff --git a/zone/merc.cpp b/zone/merc.cpp index 68907fb5b..b4125735e 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -18,7 +18,7 @@ #include "../common/string_util.h" #include "../common/rulesys.h" -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; Merc::Merc(const NPCType* d, float x, float y, float z, float heading) : NPC(d, nullptr, glm::vec4(x, y, z, heading), 0, false), endupkeep_timer(1000), rest_timer(1), confidence_timer(6000), check_target_timer(2000) @@ -1428,7 +1428,7 @@ void Merc::AI_Process() { if(RuleB(Combat, EnableFearPathing)) { CalculateNewFearpoint(); - if(curfp) { + if(currently_fleeing) { return; } } @@ -1500,7 +1500,7 @@ void Merc::AI_Process() { } } - if(AImovement_timer->Check()) + if(AI_movement_timer->Check()) { if(!IsMoving() && GetClass() == ROGUE && !BehindMob(GetTarget(), GetX(), GetY())) { @@ -1645,7 +1645,7 @@ void Merc::AI_Process() { AI_PursueCastCheck(); } - if (AImovement_timer->Check()) + if (AI_movement_timer->Check()) { if(!IsRooted()) { Log.Out(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", GetTarget()->GetCleanName()); @@ -1687,7 +1687,7 @@ void Merc::AI_Process() { if(!check_target_timer.Enabled()) check_target_timer.Start(2000, false); - if(!IsMoving() && AIthink_timer->Check() && !spellend_timer.Enabled()) + if(!IsMoving() && AI_think_timer->Check() && !spellend_timer.Enabled()) { //TODO: Implement passive stances. //if(GetStance() != MercStancePassive) { @@ -1698,7 +1698,7 @@ void Merc::AI_Process() { } } - if(AImovement_timer->Check()) + if(AI_movement_timer->Check()) { if(GetFollowID()) { @@ -5777,7 +5777,7 @@ bool Merc::RemoveMercFromGroup(Merc* merc, Group* group) { { merc->SetFollowID(0); - if (group->GroupCount() <= 2 && merc->GetGroup() == group && ZoneLoaded) + if (group->GroupCount() <= 2 && merc->GetGroup() == group && is_zone_loaded) { group->DisbandGroup(); } diff --git a/zone/merc.h b/zone/merc.h index 4f52d7367..1e409e0ce 100644 --- a/zone/merc.h +++ b/zone/merc.h @@ -192,6 +192,7 @@ public: virtual void ScaleStats(int scalepercent, bool setmax = false); virtual void CalcBonuses(); int32 GetEndurance() const {return cur_end;} //This gets our current endurance + inline uint8 GetEndurancePercent() { return (uint8)((float)cur_end / (float)max_end * 100.0f); } inline virtual int32 GetAC() const { return AC; } inline virtual int32 GetATK() const { return ATK; } inline virtual int32 GetATKBonus() const { return itembonuses.ATK + spellbonuses.ATK; } diff --git a/zone/mob.cpp b/zone/mob.cpp index fc46aac75..eccf04a76 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -113,7 +113,7 @@ Mob::Mob(const char* in_name, targeted = 0; tar_ndx=0; tar_vector=0; - curfp = false; + currently_fleeing = false; AI_Init(); SetMoving(false); @@ -371,7 +371,7 @@ Mob::Mob(const char* in_name, follow=0; follow_dist = 100; // Default Distance for Follow flee_mode = false; - curfp = false; + currently_fleeing = false; flee_timer.Start(); permarooted = (runspeed > 0) ? false : true; @@ -503,13 +503,9 @@ void Mob::SetInvisible(uint8 state) SendAppearancePacket(AT_Invis, invisible); // Invis and hide breaks charms - if ((this->GetPetType() == petCharmed) && (invisible || hidden || improved_hidden)) - { - Mob* formerpet = this->GetPet(); - - if(formerpet) - formerpet->BuffFadeByEffect(SE_Charm); - } + auto formerpet = GetPet(); + if (formerpet && formerpet->GetPetType() == petCharmed && (invisible || hidden || improved_hidden)) + formerpet->BuffFadeByEffect(SE_Charm); } //check to see if `this` is invisible to `other` diff --git a/zone/mob.h b/zone/mob.h index 5032abcf6..2ca027023 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -925,8 +925,8 @@ public: virtual FACTION_VALUE GetReverseFactionCon(Mob* iOther) { return FACTION_INDIFFERENT; } inline bool IsTrackable() const { return(trackable); } - Timer* GetAIThinkTimer() { return AIthink_timer.get(); } - Timer* GetAIMovementTimer() { return AImovement_timer.get(); } + Timer* GetAIThinkTimer() { return AI_think_timer.get(); } + Timer* GetAIMovementTimer() { return AI_movement_timer.get(); } Timer GetAttackTimer() { return attack_timer; } Timer GetAttackDWTimer() { return attack_dw_timer; } inline bool IsFindable() { return findable; } @@ -1254,14 +1254,15 @@ protected: uint32 maxLastFightingDelayMoving; float pAggroRange; float pAssistRange; - std::unique_ptr AIthink_timer; - std::unique_ptr AImovement_timer; - std::unique_ptr AItarget_check_timer; + std::unique_ptr AI_think_timer; + std::unique_ptr AI_movement_timer; + std::unique_ptr AI_target_check_timer; bool movetimercompleted; bool permarooted; - std::unique_ptr AIscanarea_timer; - std::unique_ptr AIwalking_timer; - std::unique_ptr AIfeignremember_timer; + std::unique_ptr AI_scan_area_timer; + std::unique_ptr AI_walking_timer; + std::unique_ptr AI_feign_remember_timer; + std::unique_ptr AI_check_signal_timer; uint32 pLastFightingDelayMoving; HateList hate_list; std::set feign_memory_list; @@ -1295,7 +1296,7 @@ protected: int patrol; glm::vec3 m_FearWalkTarget; - bool curfp; + bool currently_fleeing; // Pathing // diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 3f3911c8d..25ed72441 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -423,12 +423,14 @@ bool EntityList::AICheckCloseBeneficialSpells(NPC* caster, uint8 iChance, float void Mob::AI_Init() { pAIControlled = false; - AIthink_timer.reset(nullptr); - AIwalking_timer.reset(nullptr); - AImovement_timer.reset(nullptr); - AItarget_check_timer.reset(nullptr); - AIfeignremember_timer.reset(nullptr); - AIscanarea_timer.reset(nullptr); + AI_think_timer.reset(nullptr); + AI_walking_timer.reset(nullptr); + AI_movement_timer.reset(nullptr); + AI_target_check_timer.reset(nullptr); + AI_feign_remember_timer.reset(nullptr); + AI_scan_area_timer.reset(nullptr); + AI_check_signal_timer.reset(nullptr); + minLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMin); maxLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMax); @@ -472,16 +474,18 @@ void Mob::AI_Start(uint32 iMoveDelay) { pLastFightingDelayMoving = 0; pAIControlled = true; - AIthink_timer = std::unique_ptr(new Timer(AIthink_duration)); - AIthink_timer->Trigger(); - AIwalking_timer = std::unique_ptr(new Timer(0)); - AImovement_timer = std::unique_ptr(new Timer(AImovement_duration)); - AItarget_check_timer = std::unique_ptr(new Timer(AItarget_check_duration)); - AIfeignremember_timer = std::unique_ptr(new Timer(AIfeignremember_delay)); - AIscanarea_timer = std::unique_ptr(new Timer(AIscanarea_delay)); + AI_think_timer = std::unique_ptr(new Timer(AIthink_duration)); + AI_think_timer->Trigger(); + AI_walking_timer = std::unique_ptr(new Timer(0)); + AI_movement_timer = std::unique_ptr(new Timer(AImovement_duration)); + AI_target_check_timer = std::unique_ptr(new Timer(AItarget_check_duration)); + AI_feign_remember_timer = std::unique_ptr(new Timer(AIfeignremember_delay)); + AI_scan_area_timer = std::unique_ptr(new Timer(RandomTimer(RuleI(NPC, NPCToNPCAggroTimerMin), RuleI(NPC, NPCToNPCAggroTimerMax)))); + AI_check_signal_timer = std::unique_ptr(new Timer(AI_check_signal_timer_delay)); + #ifdef REVERSE_AGGRO if(IsNPC() && !CastToNPC()->WillAggroNPCs()) - AIscanarea_timer->Disable(); + AI_scan_area_timer->Disable(); #endif if (GetAggroRange() == 0) @@ -538,12 +542,13 @@ void Mob::AI_Stop() { pAIControlled = false; - AIthink_timer.reset(nullptr); - AIwalking_timer.reset(nullptr); - AImovement_timer.reset(nullptr); - AItarget_check_timer.reset(nullptr); - AIscanarea_timer.reset(nullptr); - AIfeignremember_timer.reset(nullptr); + AI_think_timer.reset(nullptr); + AI_walking_timer.reset(nullptr); + AI_movement_timer.reset(nullptr); + AI_target_check_timer.reset(nullptr); + AI_scan_area_timer.reset(nullptr); + AI_feign_remember_timer.reset(nullptr); + AI_check_signal_timer.reset(nullptr); hate_list.WipeHateList(); } @@ -725,7 +730,7 @@ void Client::AI_Process() if (!IsAIControlled()) return; - if (!(AIthink_timer->Check() || attack_timer.Check(false))) + if (!(AI_think_timer->Check() || attack_timer.Check(false))) return; if (IsCasting()) @@ -759,7 +764,7 @@ void Client::AI_Process() } if(RuleB(Combat, EnableFearPathing)){ - if(curfp) { + if(currently_fleeing) { if(IsRooted()) { //make sure everybody knows were not moving, for appearance sake if(IsMoving()) @@ -771,7 +776,7 @@ void Client::AI_Process() //continue on to attack code, ensuring that we execute the engaged code engaged = true; } else { - if(AImovement_timer->Check()) { + if(AI_movement_timer->Check()) { int speed = GetFearSpeed(); animation = speed; speed *= 2; @@ -808,7 +813,7 @@ void Client::AI_Process() SetTarget(hate_list.GetClosestEntOnHateList(this)); else { - if(AItarget_check_timer->Check()) + if(AI_target_check_timer->Check()) { SetTarget(hate_list.GetEntWithMostHateOnList(this)); } @@ -832,7 +837,7 @@ void Client::AI_Process() DoClassAttacks(GetTarget()); } - if (AImovement_timer->Check()) { + if (AI_movement_timer->Check()) { if (CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w) { SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY())); @@ -858,7 +863,7 @@ void Client::AI_Process() } else { if(!IsRooted()) { - if(AImovement_timer->Check()) + if(AI_movement_timer->Check()) { int newspeed = GetRunspeed(); animation = newspeed; @@ -889,7 +894,7 @@ void Client::AI_Process() } else { - if(AIfeignremember_timer->Check()) { + if(AI_feign_remember_timer->Check()) { std::set::iterator RememberedCharID; RememberedCharID = feign_memory_list.begin(); while (RememberedCharID != feign_memory_list.end()) { @@ -917,7 +922,7 @@ void Client::AI_Process() float dist = DistanceSquared(m_Position, owner->GetPosition()); if (dist >= 400) { - if(AImovement_timer->Check()) + if(AI_movement_timer->Check()) { int nspeed = (dist >= 5625 ? GetRunspeed() : GetWalkspeed()); animation = nspeed; @@ -943,7 +948,7 @@ void Mob::AI_Process() { if (!IsAIControlled()) return; - if (!(AIthink_timer->Check() || attack_timer.Check(false))) + if (!(AI_think_timer->Check() || attack_timer.Check(false))) return; if (IsCasting()) @@ -955,7 +960,7 @@ void Mob::AI_Process() { // Begin: Additions for Wiz Fear Code // if(RuleB(Combat, EnableFearPathing)){ - if(curfp) { + if(currently_fleeing) { if(IsRooted() || (IsBlind() && CombatRange(hate_list.GetClosestEntOnHateList(this)))) { //make sure everybody knows were not moving, for appearance sake if(IsMoving()) @@ -968,7 +973,7 @@ void Mob::AI_Process() { //continue on to attack code, ensuring that we execute the engaged code engaged = true; } else { - if(AImovement_timer->Check()) { + if(AI_movement_timer->Check()) { // Check if we have reached the last fear point if ((std::abs(GetX() - m_FearWalkTarget.x) < 0.1) && (std::abs(GetY() - m_FearWalkTarget.y) < 0.1)) { @@ -998,7 +1003,7 @@ void Mob::AI_Process() { } // trigger EVENT_SIGNAL if required - if(IsNPC()) { + if (AI_check_signal_timer->Check() && IsNPC()) { CastToNPC()->CheckSignal(); } @@ -1012,7 +1017,7 @@ void Mob::AI_Process() { SetTarget(hate_list.GetClosestEntOnHateList(this)); else { - if(AItarget_check_timer->Check()) + if(AI_target_check_timer->Check()) { if (IsFocused()) { if (!target) { @@ -1074,7 +1079,7 @@ void Mob::AI_Process() { if (is_combat_range) { - if (AImovement_timer->Check()) + if (AI_movement_timer->Check()) { if(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w) { @@ -1268,7 +1273,7 @@ void Mob::AI_Process() { WipeHateList(); Heal(); BuffFadeAll(); - AIwalking_timer->Start(100); + AI_walking_timer->Start(100); pLastFightingDelayMoving = Timer::GetCurrentTime(); return; } else if(tar != nullptr) { @@ -1290,7 +1295,7 @@ void Mob::AI_Process() { if(AI_PursueCastCheck()){ //we did something, so do not process movement. } - else if (AImovement_timer->Check()) + else if (AI_movement_timer->Check()) { if(!IsRooted()) { Log.Out(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", target->GetName()); @@ -1323,7 +1328,7 @@ void Mob::AI_Process() { { if (m_PlayerState & static_cast(PlayerState::Aggressive)) SendRemovePlayerState(PlayerState::Aggressive); - if(AIfeignremember_timer->Check()) { + if(AI_feign_remember_timer->Check()) { // 6/14/06 // Improved Feign Death Memory // check to see if any of our previous feigned targets have gotten up. @@ -1348,7 +1353,7 @@ void Mob::AI_Process() { { //we processed a spell action, so do nothing else. } - else if (AIscanarea_timer->Check()) + else if (AI_scan_area_timer->Check()) { /* * This is where NPCs look around to see if they want to attack anybody. @@ -1359,11 +1364,16 @@ void Mob::AI_Process() { * */ - Mob* tmptar = entity_list.AICheckCloseAggro(this, GetAggroRange(), GetAssistRange()); - if (tmptar) - AddToHateList(tmptar); + Mob* temp_target = entity_list.AICheckCloseAggro(this, GetAggroRange(), GetAssistRange()); + if (temp_target){ + AddToHateList(temp_target); + } + + AI_scan_area_timer->Disable(); + AI_scan_area_timer->Start(RandomTimer(RuleI(NPC, NPCToNPCAggroTimerMin), RuleI(NPC, NPCToNPCAggroTimerMax)), false); + } - else if (AImovement_timer->Check() && !IsRooted()) + else if (AI_movement_timer->Check() && !IsRooted()) { if (IsPet()) { @@ -1534,10 +1544,10 @@ void NPC::AI_DoMovement() { } else if (roamer) { - if (AIwalking_timer->Check()) + if (AI_walking_timer->Check()) { movetimercompleted=true; - AIwalking_timer->Disable(); + AI_walking_timer->Disable(); } @@ -1547,7 +1557,7 @@ void NPC::AI_DoMovement() { if (movetimercompleted==true) { // time to pause at wp is over AI_SetupNextWaypoint(); } // endif (movetimercompleted==true) - else if (!(AIwalking_timer->Enabled())) + else if (!(AI_walking_timer->Enabled())) { // currently moving bool doMove = true; if (m_CurrentWayPoint.x == GetX() && m_CurrentWayPoint.y == GetY()) @@ -1568,7 +1578,7 @@ void NPC::AI_DoMovement() { sprintf(temp, "%d", cur_wp); parse->EventNPC(EVENT_WAYPOINT_ARRIVE, CastToNPC(), nullptr, temp, 0); // start moving directly to next waypoint if we're at a 0 pause waypoint and we didn't get quest halted. - if (!AIwalking_timer->Enabled()) + if (!AI_walking_timer->Enabled()) AI_SetupNextWaypoint(); else doMove = false; @@ -1759,7 +1769,7 @@ void Mob::AI_Event_Engaged(Mob* attacker, bool iYellForHelp) { void Mob::AI_Event_NoLongerEngaged() { if (!IsAIControlled()) return; - this->AIwalking_timer->Start(RandomTimer(3000,20000)); + this->AI_walking_timer->Start(RandomTimer(3000,20000)); pLastFightingDelayMoving = Timer::GetCurrentTime(); if (minLastFightingDelayMoving == maxLastFightingDelayMoving) pLastFightingDelayMoving += minLastFightingDelayMoving; @@ -1856,15 +1866,15 @@ bool NPC::AI_PursueCastCheck() { bool NPC::AI_IdleCastCheck() { if (AIautocastspell_timer->Check(false)) { -#if MobAI_DEBUG_Spells >= 25 - std::cout << "Non-Engaged autocast check triggered: " << this->GetName() << std::endl; -#endif AIautocastspell_timer->Disable(); //prevent the timer from going off AGAIN while we are casting. if (!AICastSpell(this, AISpellVar.idle_beneficial_chance, SpellType_Heal | SpellType_Buff | SpellType_Pet)) { if(!entity_list.AICheckCloseBeneficialSpells(this, 33, MobAISpellRange, SpellType_Heal | SpellType_Buff)) { //if we didnt cast any spells, our autocast timer just resets to the //last duration it was set to... try to put up a more reasonable timer... AIautocastspell_timer->Start(RandomTimer(AISpellVar.idle_no_sp_recast_min, AISpellVar.idle_no_sp_recast_max), false); + + Log.Out(Logs::Moderate, Logs::Spells, "Triggering AI_IdleCastCheck :: Mob %s - Min : %u Max : %u", this->GetCleanName(), AISpellVar.idle_no_sp_recast_min, AISpellVar.idle_no_sp_recast_max); + } //else, spell casting finishing will reset the timer. } //else, spell casting finishing will reset the timer. return(true); diff --git a/zone/net.cpp b/zone/net.cpp index acf217b84..0d5d546d6 100644 --- a/zone/net.cpp +++ b/zone/net.cpp @@ -84,7 +84,7 @@ #endif volatile bool RunLoops = true; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; TimeoutManager timeout_manager; NetConnection net; @@ -110,6 +110,7 @@ extern void MapOpcodes(); int main(int argc, char** argv) { RegisterExecutablePlatform(ExePlatformZone); Log.LoadLogSettingsDefaults(); + set_exception_handler(); QServ = new QueryServ; @@ -339,6 +340,10 @@ int main(int argc, char** argv) { #ifdef EMBPERL PerlembParser *perl_parser = new PerlembParser(); parse->RegisterQuestInterface(perl_parser, "pl"); + + /* Load Perl Event Export Settings */ + parse->LoadPerlEventExportSettings(parse->perl_event_export_settings); + #endif //now we have our parser, load the quests @@ -388,10 +393,10 @@ int main(int argc, char** argv) { worldserver.Process(); - if (!eqsf.IsOpen() && Config->ZonePort!=0) { - Log.Out(Logs::General, Logs::Zone_Server, "Starting EQ Network server on port %d",Config->ZonePort); + if (!eqsf.IsOpen() && Config->ZonePort != 0) { + Log.Out(Logs::General, Logs::Zone_Server, "Starting EQ Network server on port %d", Config->ZonePort); if (!eqsf.Open(Config->ZonePort)) { - Log.Out(Logs::General, Logs::Error, "Failed to open port %d",Config->ZonePort); + Log.Out(Logs::General, Logs::Error, "Failed to open port %d", Config->ZonePort); ZoneConfig::SetZonePort(0); worldserver.Disconnect(); worldwasconnected = false; @@ -405,7 +410,7 @@ int main(int argc, char** argv) { //structures and opcodes for that patch. struct in_addr in; in.s_addr = eqss->GetRemoteIP(); - Log.Out(Logs::Detail, Logs::World_Server, "New connection from %s:%d", inet_ntoa(in),ntohs(eqss->GetRemotePort())); + Log.Out(Logs::Detail, Logs::World_Server, "New connection from %s:%d", inet_ntoa(in), ntohs(eqss->GetRemotePort())); stream_identifier.AddStream(eqss); //takes the stream } @@ -437,12 +442,12 @@ int main(int argc, char** argv) { worldwasconnected = true; } else { - if (worldwasconnected && ZoneLoaded) + if (worldwasconnected && is_zone_loaded) entity_list.ChannelMessageFromWorld(0, 0, 6, 0, 0, "WARNING: World server connection lost"); worldwasconnected = false; } - if (ZoneLoaded && zoneupdate_timer.Check()) { + if (is_zone_loaded && zoneupdate_timer.Check()) { { if(net.group_timer.Enabled() && net.group_timer.Check()) entity_list.GroupProcess(); diff --git a/zone/npc.cpp b/zone/npc.cpp index 72264a1a2..ebdd8a79d 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -53,7 +53,7 @@ #endif extern Zone* zone; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; extern EntityList entity_list; NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int iflymode, bool IsCorpse) @@ -605,7 +605,7 @@ bool NPC::Process() parse->EventNPC(EVENT_TICK, this, nullptr, "", 0); BuffProcess(); - if(curfp) + if(currently_fleeing) ProcessFlee(); uint32 bonus = 0; diff --git a/zone/quest_parser_collection.cpp b/zone/quest_parser_collection.cpp index 845769532..1f4f99c0e 100644 --- a/zone/quest_parser_collection.cpp +++ b/zone/quest_parser_collection.cpp @@ -1032,3 +1032,42 @@ int QuestParserCollection::DispatchEventSpell(QuestEventID evt, NPC* npc, Client } return ret; } + +void QuestParserCollection::LoadPerlEventExportSettings(PerlEventExportSettings* perl_event_export_settings) { + + Log.Out(Logs::General, Logs::Zone_Server, "Loading Perl Event Export Settings..."); + + /* Write Defaults First (All Enabled) */ + for (int i = 0; i < _LargestEventID; i++){ + perl_event_export_settings[i].qglobals = 1; + perl_event_export_settings[i].mob = 1; + perl_event_export_settings[i].zone = 1; + perl_event_export_settings[i].item = 1; + perl_event_export_settings[i].event_variables = 1; + } + + std::string query = + "SELECT " + "event_id, " + "event_description, " + "export_qglobals, " + "export_mob, " + "export_zone, " + "export_item, " + "export_event " + "FROM " + "perl_event_export_settings " + "ORDER BY event_id"; + + int event_id = 0; + auto results = database.QueryDatabase(query); + for (auto row = results.begin(); row != results.end(); ++row) { + event_id = atoi(row[0]); + perl_event_export_settings[event_id].qglobals = atoi(row[2]); + perl_event_export_settings[event_id].mob = atoi(row[3]); + perl_event_export_settings[event_id].zone = atoi(row[4]); + perl_event_export_settings[event_id].item = atoi(row[5]); + perl_event_export_settings[event_id].event_variables = atoi(row[6]); + } + +} \ No newline at end of file diff --git a/zone/quest_parser_collection.h b/zone/quest_parser_collection.h index 3ebce378c..7a0cec274 100644 --- a/zone/quest_parser_collection.h +++ b/zone/quest_parser_collection.h @@ -77,6 +77,27 @@ public: void GetErrors(std::list &err); + /* + Internally used memory reference for all Perl Event Export Settings + Some exports are very taxing on CPU given how much an event is called. + + These are loaded via DB and have defaults loaded in PerlEventExportSettingsDefaults. + + Database loaded via Database::LoadPerlEventExportSettings(log_settings) + */ + + struct PerlEventExportSettings { + uint8 qglobals; + uint8 mob; + uint8 zone; + uint8 item; + uint8 event_variables; + }; + + PerlEventExportSettings perl_event_export_settings[_LargestEventID]; + + void LoadPerlEventExportSettings(PerlEventExportSettings* perl_event_export_settings); + private: bool HasQuestSubLocal(uint32 npcid, QuestEventID evt); bool HasQuestSubGlobal(QuestEventID evt); diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index c42356ea9..f2461ed4b 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -351,6 +351,112 @@ void Spawn2::DeathReset(bool realdeath) } } +bool ZoneDatabase::PopulateZoneSpawnListClose(uint32 zoneid, LinkedList &spawn2_list, int16 version, const glm::vec4& client_position, uint32 repop_distance) +{ + std::unordered_map spawn_times; + + float mob_distance = 0; + + timeval tv; + gettimeofday(&tv, nullptr); + + /* Bulk Load NPC Types Data into the cache */ + database.LoadNPCTypesData(0, true); + + std::string spawn_query = StringFormat( + "SELECT " + "respawn_times.id, " + "respawn_times.`start`, " + "respawn_times.duration " + "FROM " + "respawn_times " + "WHERE instance_id = %u", + zone->GetInstanceID() + ); + auto results = QueryDatabase(spawn_query); + for (auto row = results.begin(); row != results.end(); ++row) { + uint32 start_duration = atoi(row[1]) > 0 ? atoi(row[1]) : 0; + uint32 end_duration = atoi(row[2]) > 0 ? atoi(row[2]) : 0; + + /* Our current time was expired */ + if ((start_duration + end_duration) <= tv.tv_sec) { + spawn_times[atoi(row[0])] = 0; + } + /* We still have time left on this timer */ + else { + spawn_times[atoi(row[0])] = ((start_duration + end_duration) - tv.tv_sec) * 1000; + } + } + + const char *zone_name = database.GetZoneName(zoneid); + std::string query = StringFormat( + "SELECT " + "id, " + "spawngroupID, " + "x, " + "y, " + "z, " + "heading, " + "respawntime, " + "variance, " + "pathgrid, " + "_condition, " + "cond_value, " + "enabled, " + "animation " + "FROM " + "spawn2 " + "WHERE zone = '%s' AND version = %u", + zone_name, + version + ); + results = QueryDatabase(query); + + if (!results.Success()) { + return false; + } + + for (auto row = results.begin(); row != results.end(); ++row) { + + uint32 spawn_time_left = 0; + Spawn2* new_spawn = 0; + bool perl_enabled = atoi(row[11]) == 1 ? true : false; + + if (spawn_times.count(atoi(row[0])) != 0) + spawn_time_left = spawn_times[atoi(row[0])]; + + glm::vec4 point; + point.x = atof(row[2]); + point.y = atof(row[3]); + + mob_distance = DistanceNoZ(client_position, point); + + if (mob_distance > repop_distance) + continue; + + new_spawn = new Spawn2( // + atoi(row[0]), // uint32 in_spawn2_id + atoi(row[1]), // uint32 spawngroup_id + atof(row[2]), // float in_x + atof(row[3]), // float in_y + atof(row[4]), // float in_z + atof(row[5]), // float in_heading + atoi(row[6]), // uint32 respawn + atoi(row[7]), // uint32 variance + spawn_time_left, // uint32 timeleft + atoi(row[8]), // uint32 grid + atoi(row[9]), // uint16 in_cond_id + atoi(row[10]), // int16 in_min_value + perl_enabled, // bool in_enabled + (EmuAppearance)atoi(row[12]) // EmuAppearance anim + ); + + spawn2_list.Insert(new_spawn); + } + + return true; +} + bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList &spawn2_list, int16 version, uint32 repopdelay) { std::unordered_map spawn_times; diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index ecb0698e0..e866d1e0f 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -38,7 +38,7 @@ extern Zone* zone; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; extern WorldServer worldserver; @@ -283,9 +283,13 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove //do any AAs apply to these spells? if(dmg < 0) { + if (!PassCastRestriction(false, spells[spell_id].base2[i], true)) + break; dmg = -dmg; Damage(caster, dmg, spell_id, spell.skill, false, buffslot, false); } else { + if (!PassCastRestriction(false, spells[spell_id].base2[i], false)) + break; HealDamage(dmg, caster); } break; @@ -864,7 +868,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove } CalculateNewFearpoint(); - if(curfp) + if(currently_fleeing) { break; } @@ -3429,6 +3433,8 @@ void Mob::DoBuffTic(const Buffs_Struct &buff, int slot, Mob *caster) switch (effect) { case SE_CurrentHP: { + if (!PassCastRestriction(false, spells[buff.spellid].base2[i], true)) + break; effect_value = CalcSpellEffectValue(buff.spellid, i, buff.casterlevel, buff.instrument_mod, caster, buff.ticsremaining); // Handle client cast DOTs here. @@ -3944,8 +3950,8 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) } case SE_Blind: - if (curfp && !FindType(SE_Fear)) - curfp = false; + if (currently_fleeing && !FindType(SE_Fear)) + currently_fleeing = false; break; case SE_Fear: @@ -3958,8 +3964,8 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) CastToClient()->AI_Stop(); } - if(curfp) { - curfp = false; + if(currently_fleeing) { + currently_fleeing = false; break; } } @@ -3974,7 +3980,7 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) { if(RuleB(Combat, EnableFearPathing)){ if(flee_mode) { - curfp = true; + currently_fleeing = true; CheckFlee(); break; } @@ -6224,16 +6230,17 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama Range 410 - 411 : UNKOWN Range 500 - 599 : Heal if HP less than a specified value Range 600 - 699 : Limit to Body Type [base2 - 600 = Body] - Range 700 : UNKNOWN + Range 700 : NPC only -- from patch notes "Wizard - Arcane Fusion no longer deals damage to non-NPC targets. This should ensure that wizards who fail their Bucolic Gambit are slightly less likely to annihilate themselves." Range 701 : NOT PET Range 800 : UKNOWN Range 818 - 819 : If Undead/If Not Undead Range 820 - 822 : UKNOWN Range 835 : Unknown *not implemented - Range 836 - 837 : Progression Server / Live Server *not implemented - Range 839 : Unknown *not implemented + Range 836 - 837 : Progression Server / Live Server *not fully implemented + Range 839 : Progression Server and GoD released -- broken until Oct 21 2015 on live *not fully implemented Range 842 - 844 : Humaniod lv MAX ((842 - 800) * 2) Range 845 - 847 : UNKNOWN + Range 860 - 871 : Humanoid lv MAX 860 = 90, 871 = 104 *not implemented Range 10000 - 11000 : Limit to Race [base2 - 10000 = Race] (*Not on live: Too useful a function to not implement) THIS IS A WORK IN PROGRESS */ @@ -6387,6 +6394,11 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama return true; break; + case 700: + if (IsNPC()) + return true; + break; + case 701: if (!IsPet()) return true; @@ -6402,6 +6414,15 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama return true; break; + case 836: + return true; // todo implement progression flag assume not progression for now + + case 837: + return false; // todo implement progression flag assume not progression for now + + case 839: + return true; // todo implement progression flag assume not progression for now, this one is a check if GoD is live + case 842: if (GetBodyType() == BT_Humanoid && GetLevel() <= 84) return true; @@ -6789,4 +6810,4 @@ void Client::BreakFeignDeathWhenCastOn(bool IsResisted) SetFeigned(false); Message_StringID(MT_SpellFailure,FD_CAST_ON); } -} \ No newline at end of file +} diff --git a/zone/spells.cpp b/zone/spells.cpp index 86c489185..9ec68c3ff 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -101,7 +101,7 @@ Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) extern Zone* zone; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; extern WorldServer worldserver; // this is run constantly for every mob @@ -2267,7 +2267,9 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 } } // one may want to check if this is a disc or not, but we actually don't, there are non disc stuff that have end cost - if (spells[spell_id].EndurCost) { + // lets not consume end for custom items that have disc procs. + // One might also want to filter out USE_ITEM_SPELL_SLOT, but DISCIPLINE_SPELL_SLOT are both #defined to the same thing ... + if (spells[spell_id].EndurCost && !isproc) { auto end_cost = spells[spell_id].EndurCost; if (mgb) end_cost *= 2; diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index e900c6838..5ab46dc1f 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -94,7 +94,7 @@ void NPC::ResumeWandering() { if (GetGrid() < 0) { // we were paused by a quest - AIwalking_timer->Disable(); + AI_walking_timer->Disable(); SetGrid( 0 - GetGrid()); if (cur_wp==-1) { // got here by a MoveTo() @@ -103,10 +103,10 @@ void NPC::ResumeWandering() } Log.Out(Logs::Detail, Logs::Pathing, "Resume Wandering requested. Grid %d, wp %d", GetGrid(), cur_wp); } - else if (AIwalking_timer->Enabled()) + else if (AI_walking_timer->Enabled()) { // we are at a waypoint paused normally Log.Out(Logs::Detail, Logs::Pathing, "Resume Wandering on timed pause. Grid %d, wp %d", GetGrid(), cur_wp); - AIwalking_timer->Trigger(); // disable timer to end pause now + AI_walking_timer->Trigger(); // disable timer to end pause now } else { @@ -145,7 +145,7 @@ void NPC::PauseWandering(int pausetime) } else { // specified waiting time, he'll resume after that - AIwalking_timer->Start(pausetime*1000); // set the timer + AI_walking_timer->Start(pausetime*1000); // set the timer } } else { Log.Out(Logs::General, Logs::Error, "NPC not on grid - can't pause wandering: %lu", (unsigned long)GetNPCTypeID()); @@ -162,7 +162,7 @@ void NPC::MoveTo(const glm::vec4& position, bool saveguardspot) SetGrid( 0 - GetGrid()); // get him moving again Log.Out(Logs::Detail, Logs::AI, "MoveTo during quest wandering. Canceling quest wandering and going back to grid %d when MoveTo is done.", GetGrid()); } - AIwalking_timer->Disable(); // disable timer in case he is paused at a wp + AI_walking_timer->Disable(); // disable timer in case he is paused at a wp if (cur_wp>=0) { // we've not already done a MoveTo() save_wp=cur_wp; // save the current waypoint @@ -193,8 +193,8 @@ void NPC::MoveTo(const glm::vec4& position, bool saveguardspot) m_CurrentWayPoint = position; cur_wp_pause = 0; pLastFightingDelayMoving = 0; - if(AIwalking_timer->Enabled()) - AIwalking_timer->Start(100); + if(AI_walking_timer->Enabled()) + AI_walking_timer->Start(100); } void NPC::UpdateWaypoint(int wp_index) @@ -393,8 +393,8 @@ void NPC::SetWaypointPause() //Declare time to wait on current WP if (cur_wp_pause == 0) { - AIwalking_timer->Start(100); - AIwalking_timer->Trigger(); + AI_walking_timer->Start(100); + AI_walking_timer->Trigger(); } else { @@ -402,13 +402,13 @@ void NPC::SetWaypointPause() switch (pausetype) { case 0: //Random Half - AIwalking_timer->Start((cur_wp_pause - zone->random.Int(0, cur_wp_pause-1)/2)*1000); + AI_walking_timer->Start((cur_wp_pause - zone->random.Int(0, cur_wp_pause-1)/2)*1000); break; case 1: //Full - AIwalking_timer->Start(cur_wp_pause*1000); + AI_walking_timer->Start(cur_wp_pause*1000); break; case 2: //Random Full - AIwalking_timer->Start(zone->random.Int(0, cur_wp_pause-1)*1000); + AI_walking_timer->Start(zone->random.Int(0, cur_wp_pause-1)*1000); break; } } @@ -484,7 +484,7 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo Log.Out(Logs::Detail, Logs::AI, "Calc Position2 (%.3f, %.3f, %.3f): Jumping pure Z.", x, y, z); return true; } - Log.Out(Logs::Detail, Logs::AI, "Calc Position2 (%.3f, %.3f, %.3f) inWater=%d: We are there.", x, y, z, inWater); + // Log.Out(Logs::Detail, Logs::AI, "Calc Position2 (%.3f, %.3f, %.3f) inWater=%d: We are there.", x, y, z, inWater); return false; } else if ((std::abs(m_Position.x - x) < 0.1) && (std::abs(m_Position.y - y) < 0.1)) { Log.Out(Logs::Detail, Logs::AI, "Calc Position2 (%.3f, %.3f, %.3f): X/Y difference <0.1, Jumping to target.", x, y, z); diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index 029975efe..5f32992bc 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -39,6 +39,7 @@ #include "client.h" #include "corpse.h" #include "entity.h" +#include "quest_parser_collection.h" #include "guild_mgr.h" #include "mob.h" #include "net.h" @@ -53,13 +54,16 @@ extern EntityList entity_list; extern Zone* zone; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; extern void CatchSignal(int); extern WorldServer worldserver; extern NetConnection net; extern PetitionList petition_list; extern uint32 numclients; extern volatile bool RunLoops; +extern QuestParserCollection *parse; + +// QuestParserCollection *parse = 0; WorldServer::WorldServer() : WorldConnection(EmuTCPConnection::packetModeZone) @@ -85,7 +89,7 @@ WorldServer::~WorldServer() { safe_delete(pack); }*/ -void WorldServer::SetZone(uint32 iZoneID, uint32 iInstanceID) { +void WorldServer::SetZoneData(uint32 iZoneID, uint32 iInstanceID) { ServerPacket* pack = new ServerPacket(ServerOP_SetZone, sizeof(SetZone_Struct)); SetZone_Struct* szs = (SetZone_Struct*) pack->pBuffer; szs->zoneid = iZoneID; @@ -99,10 +103,9 @@ void WorldServer::SetZone(uint32 iZoneID, uint32 iInstanceID) { void WorldServer::OnConnected() { WorldConnection::OnConnected(); - ServerPacket* pack; - //tell the launcher what name we were started with. + /* Tell the launcher what our information is */ pack = new ServerPacket(ServerOP_SetLaunchName,sizeof(LaunchName_Struct)); LaunchName_Struct* ln = (LaunchName_Struct*)pack->pBuffer; strn0cpy(ln->launcher_name, m_launcherName.c_str(), 32); @@ -110,28 +113,38 @@ void WorldServer::OnConnected() { SendPacket(pack); safe_delete(pack); + /* Tell the Worldserver basic information about this zone process */ pack = new ServerPacket(ServerOP_SetConnectInfo, sizeof(ServerConnectInfo)); ServerConnectInfo* sci = (ServerConnectInfo*) pack->pBuffer; + auto config = ZoneConfig::get(); sci->port = ZoneConfig::get()->ZonePort; if(config->WorldAddress.length() > 0) { strn0cpy(sci->address, config->WorldAddress.c_str(), 250); } - if(config->LocalAddress.length() > 0) { strn0cpy(sci->local_address, config->LocalAddress.c_str(), 250); } + /* Fetch process ID */ + if (getpid()){ + sci->process_id = getpid(); + } + else { + sci->process_id = 0; + } + SendPacket(pack); safe_delete(pack); - if (ZoneLoaded) { - this->SetZone(zone->GetZoneID(), zone->GetInstanceID()); + if (is_zone_loaded) { + this->SetZoneData(zone->GetZoneID(), zone->GetInstanceID()); entity_list.UpdateWho(true); this->SendEmoteMessage(0, 0, 15, "Zone connect: %s", zone->GetLongName()); - zone->GetTimeSync(); - } else { - this->SetZone(0); + zone->GetTimeSync(); + } + else { + this->SetZoneData(0); } pack = new ServerPacket(ServerOP_LSZoneBoot,sizeof(ZoneBoot_Struct)); @@ -174,7 +187,7 @@ void WorldServer::Process() { break; } case ServerOP_ChannelMessage: { - if (!ZoneLoaded) + if (!is_zone_loaded) break; ServerChannelMessage_Struct* scm = (ServerChannelMessage_Struct*) pack->pBuffer; if (scm->deliverto[0] == 0) { @@ -207,7 +220,7 @@ void WorldServer::Process() { } case ServerOP_VoiceMacro: { - if (!ZoneLoaded) + if (!is_zone_loaded) break; ServerVoiceMacro_Struct* svm = (ServerVoiceMacro_Struct*) pack->pBuffer; @@ -264,7 +277,7 @@ void WorldServer::Process() { case ServerOP_SpawnCondition: { if(pack->size != sizeof(ServerSpawnCondition_Struct)) break; - if (!ZoneLoaded) + if (!is_zone_loaded) break; ServerSpawnCondition_Struct* ssc = (ServerSpawnCondition_Struct*) pack->pBuffer; @@ -274,7 +287,7 @@ void WorldServer::Process() { case ServerOP_SpawnEvent: { if(pack->size != sizeof(ServerSpawnEvent_Struct)) break; - if (!ZoneLoaded) + if (!is_zone_loaded) break; ServerSpawnEvent_Struct* sse = (ServerSpawnEvent_Struct*) pack->pBuffer; @@ -285,7 +298,7 @@ void WorldServer::Process() { case ServerOP_AcceptWorldEntrance: { if(pack->size != sizeof(WorldToZone_Struct)) break; - if (!ZoneLoaded) + if (!is_zone_loaded) break; WorldToZone_Struct* wtz = (WorldToZone_Struct*) pack->pBuffer; @@ -300,7 +313,7 @@ void WorldServer::Process() { case ServerOP_ZoneToZoneRequest: { if(pack->size != sizeof(ZoneToZone_Struct)) break; - if (!ZoneLoaded) + if (!is_zone_loaded) break; ZoneToZone_Struct* ztz = (ZoneToZone_Struct*) pack->pBuffer; @@ -376,7 +389,7 @@ void WorldServer::Process() { break; } case ServerOP_WhoAllReply:{ - if(!ZoneLoaded) + if(!is_zone_loaded) break; @@ -403,7 +416,7 @@ void WorldServer::Process() { break; } case ServerOP_EmoteMessage: { - if (!ZoneLoaded) + if (!is_zone_loaded) break; ServerEmoteMessage_Struct* sem = (ServerEmoteMessage_Struct*) pack->pBuffer; if (sem->to[0] != 0) { @@ -461,8 +474,8 @@ void WorldServer::Process() { break; } // Annouce the change to the world - if (!ZoneLoaded) { - SetZone(0); + if (!is_zone_loaded) { + SetZoneData(0); } else { SendEmoteMessage(0, 0, 15, "Zone shutdown: %s", zone->GetLongName()); @@ -479,8 +492,8 @@ void WorldServer::Process() { break; } ServerZoneStateChange_struct* zst = (ServerZoneStateChange_struct *) pack->pBuffer; - if (ZoneLoaded) { - SetZone(zone->GetZoneID(), zone->GetInstanceID()); + if (is_zone_loaded) { + SetZoneData(zone->GetZoneID(), zone->GetInstanceID()); if (zst->zoneid == zone->GetZoneID()) { // This packet also doubles as "incoming client" notification, lets not shut down before they get here zone->StartShutdownTimer(AUTHENTICATION_TIMEOUT * 1000); @@ -503,8 +516,8 @@ void WorldServer::Process() { break; } ServerZoneIncomingClient_Struct* szic = (ServerZoneIncomingClient_Struct*) pack->pBuffer; - if (ZoneLoaded) { - SetZone(zone->GetZoneID(), zone->GetInstanceID()); + if (is_zone_loaded) { + SetZoneData(zone->GetZoneID(), zone->GetInstanceID()); if (szic->zoneid == zone->GetZoneID()) { zone->AddAuth(szic); // This packet also doubles as "incoming client" notification, lets not shut down before they get here @@ -540,7 +553,7 @@ void WorldServer::Process() { if (client != 0) { if (skp->adminrank >= client->Admin()) { client->WorldKick(); - if (ZoneLoaded) + if (is_zone_loaded) SendEmoteMessage(skp->adminname, 0, 0, "Remote Kick: %s booted in zone %s.", skp->name, zone->GetShortName()); else SendEmoteMessage(skp->adminname, 0, 0, "Remote Kick: %s booted.", skp->name); @@ -556,7 +569,7 @@ void WorldServer::Process() { if (client != 0) { if (skp->admin >= client->Admin()) { client->GMKill(); - if (ZoneLoaded) + if (is_zone_loaded) SendEmoteMessage(skp->gmname, 0, 0, "Remote Kill: %s killed in zone %s.", skp->target, zone->GetShortName()); else SendEmoteMessage(skp->gmname, 0, 0, "Remote Kill: %s killed.", skp->target); @@ -594,7 +607,7 @@ void WorldServer::Process() { std::cout << "Wrong size on ServerOP_GMGoto. Got: " << pack->size << ", Expected: " << sizeof(ServerGMGoto_Struct) << std::endl; break; } - if (!ZoneLoaded) + if (!is_zone_loaded) break; ServerGMGoto_Struct* gmg = (ServerGMGoto_Struct*) pack->pBuffer; Client* client = entity_list.GetClientByName(gmg->gotoname); @@ -1733,6 +1746,10 @@ void WorldServer::Process() { database.LoadLogSettings(Log.log_settings); break; } + case ServerOP_ReloadPerlExportSettings: { + parse->LoadPerlEventExportSettings(parse->perl_event_export_settings); + break; + } case ServerOP_CameraShake: { if(zone) diff --git a/zone/worldserver.h b/zone/worldserver.h index c1e86421f..e1831ea4c 100644 --- a/zone/worldserver.h +++ b/zone/worldserver.h @@ -37,7 +37,7 @@ public: bool SendEmoteMessage(const char* to, uint32 to_guilddbid, uint32 type, const char* message, ...); bool SendEmoteMessage(const char* to, uint32 to_guilddbid, int16 to_minstatus, uint32 type, const char* message, ...); bool SendVoiceMacro(Client* From, uint32 Type, char* Target, uint32 MacroNumber, uint32 GroupOrRaidID = 0); - void SetZone(uint32 iZoneID, uint32 iInstanceID = 0); + void SetZoneData(uint32 iZoneID, uint32 iInstanceID = 0); uint32 SendGroupIdRequest(); bool RezzPlayer(EQApplicationPacket* rpack, uint32 rezzexp, uint32 dbid, uint16 opcode); bool IsOOCMuted() const { return(oocmuted); } diff --git a/zone/zone.cpp b/zone/zone.cpp index 63730d0aa..b3a6fc1ca 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -74,7 +74,7 @@ extern Zone* zone; Mutex MZoneShutdown; -volatile bool ZoneLoaded = false; +volatile bool is_zone_loaded = false; Zone* zone = 0; bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { @@ -82,9 +82,9 @@ bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { if (iZoneID == 0 || zonename == 0) return false; - if (zone != 0 || ZoneLoaded) { + if (zone != 0 || is_zone_loaded) { std::cerr << "Error: Zone::Bootup call when zone already booted!" << std::endl; - worldserver.SetZone(0); + worldserver.SetZoneData(0); return false; } @@ -97,7 +97,7 @@ bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { if (!zone->Init(iStaticZone)) { safe_delete(zone); std::cerr << "Zone->Init failed" << std::endl; - worldserver.SetZone(0); + worldserver.SetZoneData(0); return false; } zone->zonemap = Map::LoadMapFile(zone->map_name); @@ -131,9 +131,9 @@ bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { } } - ZoneLoaded = true; + is_zone_loaded = true; - worldserver.SetZone(iZoneID, iInstanceID); + worldserver.SetZoneData(iZoneID, iInstanceID); if(iInstanceID != 0) { ServerPacket *pack = new ServerPacket(ServerOP_AdventureZoneData, sizeof(uint16)); @@ -660,12 +660,12 @@ void Zone::LoadMercSpells(){ } bool Zone::IsLoaded() { - return ZoneLoaded; + return is_zone_loaded; } void Zone::Shutdown(bool quite) { - if (!ZoneLoaded) + if (!is_zone_loaded) return; entity_list.StopMobAI(); @@ -699,7 +699,7 @@ void Zone::Shutdown(bool quite) zone->SetZoneHasCurrentTime(false); if (!quite) Log.Out(Logs::General, Logs::Normal, "Zone shutdown: going to sleep"); - ZoneLoaded = false; + is_zone_loaded = false; zone->ResetAuth(); safe_delete(zone); @@ -846,7 +846,7 @@ Zone::~Zone() { safe_delete(watermap); safe_delete(pathing); if (worldserver.Connected()) { - worldserver.SetZone(0); + worldserver.SetZoneData(0); } safe_delete_array(short_name); safe_delete_array(long_name); @@ -1445,6 +1445,29 @@ void Zone::ClearNPCTypeCache(int id) { } } +void Zone::RepopClose(const glm::vec4& client_position, uint32 repop_distance) +{ + + if (!Depop()) + return; + + LinkedListIterator iterator(spawn2_list); + + iterator.Reset(); + while (iterator.MoreElements()) { + iterator.RemoveCurrent(); + } + + quest_manager.ClearAllTimers(); + + if (!database.PopulateZoneSpawnListClose(zoneid, spawn2_list, GetInstanceVersion(), client_position, repop_distance)) + Log.Out(Logs::General, Logs::None, "Error in Zone::Repop: database.PopulateZoneSpawnList failed"); + + initgrids_timer.Start(); + + mod_repop(); +} + void Zone::Repop(uint32 delay) { if(!Depop()) diff --git a/zone/zone.h b/zone/zone.h index 94bba72e4..d7ecc6237 100644 --- a/zone/zone.h +++ b/zone/zone.h @@ -140,6 +140,7 @@ public: bool Depop(bool StartSpawnTimer = false); void Repop(uint32 delay = 0); + void RepopClose(const glm::vec4& client_position, uint32 repop_distance); void ClearNPCTypeCache(int id); void SpawnStatus(Mob* client); void ShowEnabledSpawnStatus(Mob* client); diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index e92704fe6..591f8c3d3 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -46,7 +46,7 @@ void ZoneDatabase::ZDBInitVars() { ZoneDatabase::~ZoneDatabase() { unsigned int x; if (npc_spells_cache) { - for (x=0; x<=npc_spells_maxid; x++) { + for (x = 0; x <= npc_spells_maxid; x++) { safe_delete_array(npc_spells_cache[x]); } safe_delete_array(npc_spells_cache); @@ -54,7 +54,7 @@ ZoneDatabase::~ZoneDatabase() { safe_delete_array(npc_spells_loadtried); if (npc_spellseffects_cache) { - for (x=0; x<=npc_spellseffects_maxid; x++) { + for (x = 0; x <= npc_spellseffects_maxid; x++) { safe_delete_array(npc_spellseffects_cache[x]); } safe_delete_array(npc_spellseffects_cache); @@ -62,7 +62,7 @@ ZoneDatabase::~ZoneDatabase() { safe_delete_array(npc_spellseffects_loadtried); if (faction_array != nullptr) { - for (x=0; x <= max_faction; x++) { + for (x = 0; x <= max_faction; x++) { if (faction_array[x] != 0) safe_delete(faction_array[x]); } diff --git a/zone/zonedb.h b/zone/zonedb.h index 9b2a5105b..c4d26792d 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -7,6 +7,7 @@ #include "../common/faction.h" #include "../common/eqemu_logsys.h" #include "aa_ability.h" +#include "event_codes.h" class Client; class Corpse; @@ -358,6 +359,7 @@ public: bool LoadSpawnGroups(const char* zone_name, uint16 version, SpawnGroupList* spawn_group_list); bool LoadSpawnGroupsByID(int spawngroupid, SpawnGroupList* spawn_group_list); bool PopulateZoneSpawnList(uint32 zoneid, LinkedList &spawn2_list, int16 version, uint32 repopdelay = 0); + bool PopulateZoneSpawnListClose(uint32 zoneid, LinkedList &spawn2_list, int16 version, const glm::vec4& client_position, uint32 repop_distance); Spawn2* LoadSpawn2(LinkedList &spawn2_list, uint32 spawn2id, uint32 timeleft); bool CreateSpawn2(Client *c, uint32 spawngroup, const char* zone, const glm::vec4& position, uint32 respawn, uint32 variance, uint16 condition, int16 cond_value); void UpdateRespawnTime(uint32 id, uint16 instance_id,uint32 timeleft);