diff --git a/changelog.txt b/changelog.txt index d8ed052ab..e24dcd59d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,11 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 12/04/2014 == +Kayen: Ranged attacks will now more accurately check MAX firing range, fixing the issue where you would +hit ranged attack and nothing would happpen due to incorrect server side range checks. +Trevius: Initial addition of the RoF2 client from May 10th 2013 (currently available on Steam as the F2P client). +Trevius: RoF2 is disabled by default, but you can enable by editing /common/patches/patches.cpp (see comments) + == 12/01/2014 == Trevius: Mercenaries now spawn as the same Gender and Size of the Merchant they are purchased from. Trevius: Mercenaries now spawn with randomized facial features when purchased. diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 06a78bfea..ed33928e4 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -74,6 +74,7 @@ SET(common_sources patches/sod.cpp patches/sof.cpp patches/rof.cpp + patches/rof2.cpp patches/titanium.cpp patches/underfoot.cpp SocketLib/Base64.cpp @@ -170,6 +171,7 @@ SET(common_headers ptimer.h queue.h races.h + random.h rdtsc.h rulesys.h ruletypes.h @@ -221,6 +223,11 @@ SET(common_headers patches/rof_itemfields.h patches/rof_ops.h patches/rof_structs.h + patches/rof2.h + patches/rof2_constants.h + patches/rof2_itemfields.h + patches/rof2_ops.h + patches/rof2_structs.h patches/titanium.h patches/titanium_constants.h patches/titanium_itemfields.h @@ -274,6 +281,11 @@ SOURCE_GROUP(Patches FILES patches/rof_ops.h patches/rof_constants.h patches/rof_structs.h + patches/rof2.h + patches/rof2_itemfields.h + patches/rof2_ops.h + patches/rof2_constants.h + patches/rof2_structs.h patches/titanium.h patches/titanium_itemfields.h patches/titanium_ops.h @@ -289,6 +301,7 @@ SOURCE_GROUP(Patches FILES patches/sod.cpp patches/sof.cpp patches/rof.cpp + patches/rof2.cpp patches/titanium.cpp patches/underfoot.cpp ) @@ -340,7 +353,7 @@ ADD_LIBRARY(common ${common_sources} ${common_headers}) IF(UNIX) ADD_DEFINITIONS(-fPIC) SET_SOURCE_FILES_PROPERTIES("SocketLib/Mime.cpp" PROPERTY COMPILE_FLAGS -Wno-unused-result) - SET_SOURCE_FILES_PROPERTIES("patches/sod.cpp" "patches/sof.cpp" "patches/rof.cpp" "patches/underfoot.cpp" PROPERTIES COMPILE_FLAGS -O0) + SET_SOURCE_FILES_PROPERTIES("patches/sod.cpp" "patches/sof.cpp" "patches/rof.cpp" "patches/rof2.cpp" "patches/underfoot.cpp" PROPERTIES COMPILE_FLAGS -O0) ENDIF(UNIX) diff --git a/common/debug.cpp b/common/debug.cpp index 228d57631..3b283240a 100644 --- a/common/debug.cpp +++ b/common/debug.cpp @@ -1,7 +1,5 @@ #include #include -#include -#include #ifdef _WINDOWS #include @@ -12,14 +10,13 @@ #define strcasecmp _stricmp #else - + #include #include #endif #include "debug.h" -#include "string_util.h" #include "misc_functions.h" #include "platform.h" @@ -34,34 +31,37 @@ EQEMuLog *LogFile = &realLogFile; static const char* FileNames[EQEMuLog::MaxLogID] = { "logs/eqemu", "logs/eqemu", "logs/eqemu_error", "logs/eqemu_debug", "logs/eqemu_quest", "logs/eqemu_commands", "logs/crash" }; static const char* LogNames[EQEMuLog::MaxLogID] = { "Status", "Normal", "Error", "Debug", "Quest", "Command", "Crash" }; -EQEMuLog::EQEMuLog() { - for (int i=0; i= MaxLogID) { - return false; - } - bool dofile = false; - if (pLogStatus[id] & 1) { - dofile = open(id); - } - if (!(dofile || pLogStatus[id] & 2)) - return false; - LockMutex lock(&MLog[id]); - if (!logFileValid) - return false; //check again for threading race reasons (to avoid two mutexes) - - time_t aclock; - struct tm *newtime; - - time( &aclock ); /* Get time in seconds */ - newtime = localtime( &aclock ); /* Convert time to struct */ - - if (dofile) -#ifndef NO_PIDLOG - fprintf(fp[id], "[%02d.%02d. - %02d:%02d:%02d] ", newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec); -#else - fprintf(fp[id], "%04i [%02d.%02d. - %02d:%02d:%02d] ", getpid(), newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec); -#endif - - va_list argptr, tmpargptr; - va_start(argptr, fmt); - if (dofile) { - va_copy(tmpargptr, argptr); - vfprintf( fp[id], fmt, tmpargptr ); - } - if(logCallbackFmt[id]) { - msgCallbackFmt p = logCallbackFmt[id]; - va_copy(tmpargptr, argptr); - p(id, fmt, tmpargptr ); - } - if (pLogStatus[id] & 2) { - if (pLogStatus[id] & 8) { - fprintf(stderr, "[%s] ", LogNames[id]); - vfprintf( stderr, fmt, argptr ); - } - else { - fprintf(stdout, "[%s] ", LogNames[id]); - vfprintf( stdout, fmt, argptr ); - } - } - va_end(argptr); - if (dofile) - fprintf(fp[id], "\n"); - if (pLogStatus[id] & 2) { - if (pLogStatus[id] & 8) { - fprintf(stderr, "\n"); - fflush(stderr); - } else { - fprintf(stdout, "\n"); - fflush(stdout); - } - } - if(dofile) - fflush(fp[id]); - return true; -} - -//write with Prefix and a VA_list -bool EQEMuLog::writePVA(LogIDs id, const char *prefix, const char *fmt, va_list argptr) { +bool EQEMuLog::write(LogIDs id, const char *fmt, ...) +{ if (!logFileValid) { return false; } @@ -198,56 +128,61 @@ bool EQEMuLog::writePVA(LogIDs id, const char *prefix, const char *fmt, va_list return false; } LockMutex lock(&MLog[id]); - if (!logFileValid) - return false; //check again for threading race reasons (to avoid two mutexes) - + if (!logFileValid) { + return false; //check again for threading race reasons (to avoid two mutexes) + } time_t aclock; struct tm *newtime; - time( &aclock ); /* Get time in seconds */ newtime = localtime( &aclock ); /* Convert time to struct */ - - va_list tmpargptr; - + if (dofile) + #ifndef NO_PIDLOG + fprintf(fp[id], "[%02d.%02d. - %02d:%02d:%02d] ", newtime->tm_mon + 1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec); + #else + fprintf(fp[id], "%04i [%02d.%02d. - %02d:%02d:%02d] ", getpid(), newtime->tm_mon + 1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec); + #endif + va_list argptr, tmpargptr; + va_start(argptr, fmt); if (dofile) { -#ifndef NO_PIDLOG - fprintf(fp[id], "[%02d.%02d. - %02d:%02d:%02d] %s", newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec, prefix); -#else - fprintf(fp[id], "%04i [%02d.%02d. - %02d:%02d:%02d] %s", getpid(), newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec, prefix); -#endif va_copy(tmpargptr, argptr); vfprintf( fp[id], fmt, tmpargptr ); } - if(logCallbackPva[id]) { - msgCallbackPva p = logCallbackPva[id]; + if (logCallbackFmt[id]) { + msgCallbackFmt p = logCallbackFmt[id]; va_copy(tmpargptr, argptr); - p(id, prefix, fmt, tmpargptr ); + p(id, fmt, tmpargptr ); } if (pLogStatus[id] & 2) { if (pLogStatus[id] & 8) { - fprintf(stderr, "[%s] %s", LogNames[id], prefix); + fprintf(stderr, "[%s] ", LogNames[id]); vfprintf( stderr, fmt, argptr ); - } - else { - fprintf(stdout, "[%s] %s", LogNames[id], prefix); + } else { + fprintf(stdout, "[%s] ", LogNames[id]); vfprintf( stdout, fmt, argptr ); } } va_end(argptr); - if (dofile) + if (dofile) { fprintf(fp[id], "\n"); - if (pLogStatus[id] & 2) { - if (pLogStatus[id] & 8) - fprintf(stderr, "\n"); - else - fprintf(stdout, "\n"); } - if(dofile) + if (pLogStatus[id] & 2) { + if (pLogStatus[id] & 8) { + fprintf(stderr, "\n"); + fflush(stderr); + } else { + fprintf(stdout, "\n"); + fflush(stdout); + } + } + if (dofile) { fflush(fp[id]); + } return true; } -bool EQEMuLog::writebuf(LogIDs id, const char *buf, uint8 size, uint32 count) { +//write with Prefix and a VA_list +bool EQEMuLog::writePVA(LogIDs id, const char *prefix, const char *fmt, va_list argptr) +{ if (!logFileValid) { return false; } @@ -258,30 +193,92 @@ bool EQEMuLog::writebuf(LogIDs id, const char *buf, uint8 size, uint32 count) { if (pLogStatus[id] & 1) { dofile = open(id); } - if (!(dofile || pLogStatus[id] & 2)) + if (!(dofile || pLogStatus[id] & 2)) { return false; + } LockMutex lock(&MLog[id]); - if (!logFileValid) - return false; //check again for threading race reasons (to avoid two mutexes) - + if (!logFileValid) { + return false; //check again for threading race reasons (to avoid two mutexes) + } time_t aclock; struct tm *newtime; - time( &aclock ); /* Get time in seconds */ newtime = localtime( &aclock ); /* Convert time to struct */ + va_list tmpargptr; + if (dofile) { + #ifndef NO_PIDLOG + fprintf(fp[id], "[%02d.%02d. - %02d:%02d:%02d] %s", newtime->tm_mon + 1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec, prefix); + #else + fprintf(fp[id], "%04i [%02d.%02d. - %02d:%02d:%02d] %s", getpid(), newtime->tm_mon + 1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec, prefix); + #endif + va_copy(tmpargptr, argptr); + vfprintf( fp[id], fmt, tmpargptr ); + } + if (logCallbackPva[id]) { + msgCallbackPva p = logCallbackPva[id]; + va_copy(tmpargptr, argptr); + p(id, prefix, fmt, tmpargptr ); + } + if (pLogStatus[id] & 2) { + if (pLogStatus[id] & 8) { + fprintf(stderr, "[%s] %s", LogNames[id], prefix); + vfprintf( stderr, fmt, argptr ); + } else { + fprintf(stdout, "[%s] %s", LogNames[id], prefix); + vfprintf( stdout, fmt, argptr ); + } + } + va_end(argptr); + if (dofile) { + fprintf(fp[id], "\n"); + } + if (pLogStatus[id] & 2) { + if (pLogStatus[id] & 8) { + fprintf(stderr, "\n"); + } else { + fprintf(stdout, "\n"); + } + } + if (dofile) { + fflush(fp[id]); + } + return true; +} +bool EQEMuLog::writebuf(LogIDs id, const char *buf, uint8 size, uint32 count) +{ + if (!logFileValid) { + return false; + } + if (id >= MaxLogID) { + return false; + } + bool dofile = false; + if (pLogStatus[id] & 1) { + dofile = open(id); + } + if (!(dofile || pLogStatus[id] & 2)) { + return false; + } + LockMutex lock(&MLog[id]); + if (!logFileValid) { + return false; //check again for threading race reasons (to avoid two mutexes) + } + time_t aclock; + struct tm *newtime; + time( &aclock ); /* Get time in seconds */ + newtime = localtime( &aclock ); /* Convert time to struct */ if (dofile) -#ifndef NO_PIDLOG - fprintf(fp[id], "[%02d.%02d. - %02d:%02d:%02d] ", newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec); -#else - fprintf(fp[id], "%04i [%02d.%02d. - %02d:%02d:%02d] ", getpid(), newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec); -#endif - + #ifndef NO_PIDLOG + fprintf(fp[id], "[%02d.%02d. - %02d:%02d:%02d] ", newtime->tm_mon + 1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec); + #else + fprintf(fp[id], "%04i [%02d.%02d. - %02d:%02d:%02d] ", getpid(), newtime->tm_mon + 1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec); + #endif if (dofile) { fwrite(buf, size, count, fp[id]); fprintf(fp[id], "\n"); } - if(logCallbackBuf[id]) { + if (logCallbackBuf[id]) { msgCallbackBuf p = logCallbackBuf[id]; p(id, buf, size, count); } @@ -296,12 +293,14 @@ bool EQEMuLog::writebuf(LogIDs id, const char *buf, uint8 size, uint32 count) { fprintf(stdout, "\n"); } } - if(dofile) + if (dofile) { fflush(fp[id]); + } return true; } -bool EQEMuLog::writeNTS(LogIDs id, bool dofile, const char *fmt, ...) { +bool EQEMuLog::writeNTS(LogIDs id, bool dofile, const char *fmt, ...) +{ va_list argptr, tmpargptr; va_start(argptr, fmt); if (dofile) { @@ -309,132 +308,146 @@ bool EQEMuLog::writeNTS(LogIDs id, bool dofile, const char *fmt, ...) { vfprintf( fp[id], fmt, tmpargptr ); } if (pLogStatus[id] & 2) { - if (pLogStatus[id] & 8) + if (pLogStatus[id] & 8) { vfprintf( stderr, fmt, argptr ); - else + } else { vfprintf( stdout, fmt, argptr ); + } } va_end(argptr); return true; }; -bool EQEMuLog::Dump(LogIDs id, uint8* data, uint32 size, uint32 cols, uint32 skip) { +bool EQEMuLog::Dump(LogIDs id, uint8* data, uint32 size, uint32 cols, uint32 skip) +{ if (!logFileValid) { -#if EQDEBUG >= 10 - std::cerr << "Error: Dump() from null pointer" << std::endl; -#endif + #if EQDEBUG >= 10 + std::cerr << "Error: Dump() from null pointer" << std::endl; + #endif return false; } - if (size == 0) + if (size == 0) { return true; - if (!LogFile) + } + if (!LogFile) { return false; - if (id >= MaxLogID) + } + if (id >= MaxLogID) { return false; + } bool dofile = false; if (pLogStatus[id] & 1) { dofile = open(id); } - if (!(dofile || pLogStatus[id] & 2)) + if (!(dofile || pLogStatus[id] & 2)) { return false; + } LockMutex lock(&MLog[id]); - if (!logFileValid) - return false; //check again for threading race reasons (to avoid two mutexes) - + if (!logFileValid) { + return false; //check again for threading race reasons (to avoid two mutexes) + } write(id, "Dumping Packet: %i", size); // Output as HEX - - int beginningOfLineOffset = 0; + int beginningOfLineOffset = 0; uint32 indexInData; std::string asciiOutput; - - for(indexInData=skip; indexInData= 32 && data[indexInData] < 127) - { + if (data[indexInData] >= 32 && data[indexInData] < 127) { // According to http://msdn.microsoft.com/en-us/library/vstudio/ee404875(v=vs.100).aspx - // Visual Studio 2010 doesn't have std::to_string(int) but it does have the long long + // Visual Studio 2010 doesn't have std::to_string(int) but it does have the long long // version. asciiOutput.append(std::to_string((long long)data[indexInData])); - } - else - { + } else { asciiOutput.append("."); } } - uint32 k = ((indexInData-skip)-1)%cols; - if (k < 8) + uint32 k = ((indexInData - skip) - 1) % cols; + if (k < 8) { writeNTS(id, dofile, " "); - for (uint32 h = k+1; h < cols; h++) { + } + for (uint32 h = k + 1; h < cols; h++) { writeNTS(id, dofile, " "); } writeNTS(id, dofile, " | %s\n", asciiOutput.c_str()); - if (dofile) + if (dofile) { fflush(fp[id]); + } return true; } -void EQEMuLog::SetCallback(LogIDs id, msgCallbackFmt proc) { - if (!logFileValid) +void EQEMuLog::SetCallback(LogIDs id, msgCallbackFmt proc) +{ + if (!logFileValid) { return; + } if (id >= MaxLogID) { return; } logCallbackFmt[id] = proc; } -void EQEMuLog::SetCallback(LogIDs id, msgCallbackBuf proc) { - if (!logFileValid) +void EQEMuLog::SetCallback(LogIDs id, msgCallbackBuf proc) +{ + if (!logFileValid) { return; + } if (id >= MaxLogID) { return; } logCallbackBuf[id] = proc; } -void EQEMuLog::SetCallback(LogIDs id, msgCallbackPva proc) { - if (!logFileValid) +void EQEMuLog::SetCallback(LogIDs id, msgCallbackPva proc) +{ + if (!logFileValid) { return; + } if (id >= MaxLogID) { return; } logCallbackPva[id] = proc; } -void EQEMuLog::SetAllCallbacks(msgCallbackFmt proc) { - if (!logFileValid) +void EQEMuLog::SetAllCallbacks(msgCallbackFmt proc) +{ + if (!logFileValid) { return; + } int r; - for(r = Status; r < MaxLogID; r++) { + for (r = Status; r < MaxLogID; r++) { SetCallback((LogIDs)r, proc); } } -void EQEMuLog::SetAllCallbacks(msgCallbackBuf proc) { - if (!logFileValid) +void EQEMuLog::SetAllCallbacks(msgCallbackBuf proc) +{ + if (!logFileValid) { return; + } int r; - for(r = Status; r < MaxLogID; r++) { + for (r = Status; r < MaxLogID; r++) { SetCallback((LogIDs)r, proc); } } -void EQEMuLog::SetAllCallbacks(msgCallbackPva proc) { - if (!logFileValid) +void EQEMuLog::SetAllCallbacks(msgCallbackPva proc) +{ + if (!logFileValid) { return; + } int r; - for(r = Status; r < MaxLogID; r++) { + for (r = Status; r < MaxLogID; r++) { SetCallback((LogIDs)r, proc); } } diff --git a/common/emu_oplist.h b/common/emu_oplist.h index e8ce3b986..62978655a 100644 --- a/common/emu_oplist.h +++ b/common/emu_oplist.h @@ -74,7 +74,9 @@ N(OP_CharacterCreateRequest), N(OP_CharInventory), N(OP_Charm), N(OP_ChatMessage), +N(OP_ClearAA), N(OP_ClearBlockedBuffs), +N(OP_ClearLeadershipAbilities), N(OP_ClearNPCMarks), N(OP_ClearObject), N(OP_ClearSurname), diff --git a/common/eq_dictionary.cpp b/common/eq_dictionary.cpp index f85d3110f..3756ca8fe 100644 --- a/common/eq_dictionary.cpp +++ b/common/eq_dictionary.cpp @@ -539,7 +539,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ EmuConstants::MAP_POSSESSIONS_SIZE, /*Underfoot*/ EmuConstants::MAP_POSSESSIONS_SIZE, /*RoF*/ EmuConstants::MAP_POSSESSIONS_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::MAP_POSSESSIONS_SIZE, /*NPC*/ EmuConstants::MAP_POSSESSIONS_SIZE, /*Merc*/ EmuConstants::MAP_POSSESSIONS_SIZE, @@ -554,7 +554,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ EmuConstants::MAP_BANK_SIZE, /*Underfoot*/ EmuConstants::MAP_BANK_SIZE, /*RoF*/ EmuConstants::MAP_BANK_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::MAP_BANK_SIZE, /*NPC*/ NOT_USED, /*Merc*/ NOT_USED, @@ -569,7 +569,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ EmuConstants::MAP_SHARED_BANK_SIZE, /*Underfoot*/ EmuConstants::MAP_SHARED_BANK_SIZE, /*RoF*/ EmuConstants::MAP_SHARED_BANK_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::MAP_SHARED_BANK_SIZE, /*NPC*/ NOT_USED, /*Merc*/ NOT_USED, @@ -584,7 +584,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ EmuConstants::MAP_TRADE_SIZE, /*Underfoot*/ EmuConstants::MAP_TRADE_SIZE, /*RoF*/ EmuConstants::MAP_TRADE_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::MAP_TRADE_SIZE, /*NPC*/ 4, /*Merc*/ 4, @@ -599,7 +599,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ EmuConstants::MAP_WORLD_SIZE, /*Underfoot*/ EmuConstants::MAP_WORLD_SIZE, /*RoF*/ EmuConstants::MAP_WORLD_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::MAP_WORLD_SIZE, /*NPC*/ NOT_USED, /*Merc*/ NOT_USED, @@ -614,7 +614,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ EmuConstants::MAP_LIMBO_SIZE, /*Underfoot*/ EmuConstants::MAP_LIMBO_SIZE, /*RoF*/ EmuConstants::MAP_LIMBO_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::MAP_LIMBO_SIZE, /*NPC*/ NOT_USED, /*Merc*/ NOT_USED, @@ -629,7 +629,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ EmuConstants::MAP_TRIBUTE_SIZE, /*Underfoot*/ EmuConstants::MAP_TRIBUTE_SIZE, /*RoF*/ EmuConstants::MAP_TRIBUTE_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::MAP_TRIBUTE_SIZE, /*NPC*/ 0, /*Merc*/ 0, @@ -644,7 +644,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ 0, /*Underfoot*/ 0, /*RoF*/ EmuConstants::MAP_TROPHY_TRIBUTE_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::MAP_TROPHY_TRIBUTE_SIZE, /*NPC*/ 0, /*Merc*/ 0, @@ -659,7 +659,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ 0, /*Underfoot*/ 0, /*RoF*/ EmuConstants::MAP_GUILD_TRIBUTE_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::MAP_GUILD_TRIBUTE_SIZE, /*NPC*/ 0, /*Merc*/ 0, @@ -674,7 +674,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ 0, /*Underfoot*/ 0, /*RoF*/ EmuConstants::MAP_MERCHANT_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::MAP_MERCHANT_SIZE, /*NPC*/ 0, /*Merc*/ 0, @@ -689,7 +689,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ 0, /*Underfoot*/ 0, /*RoF*/ EmuConstants::MAP_DELETED_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::MAP_DELETED_SIZE, /*NPC*/ 0, /*Merc*/ 0, @@ -704,7 +704,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ SoD::consts::MAP_CORPSE_SIZE, /*Underfoot*/ Underfoot::consts::MAP_CORPSE_SIZE, /*RoF*/ RoF::consts::MAP_CORPSE_SIZE, -/*RoF2*/ 0, +/*RoF2*/ RoF2::consts::MAP_CORPSE_SIZE, /*NPC*/ 0, /*Merc*/ 0, @@ -719,7 +719,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ EmuConstants::MAP_BAZAAR_SIZE, /*Underfoot*/ EmuConstants::MAP_BAZAAR_SIZE, /*RoF*/ EmuConstants::MAP_BAZAAR_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::MAP_BAZAAR_SIZE, /*NPC*/ 0, // this may need to be 'EmuConstants::MAP_BAZAAR_SIZE' if offline client traders respawn as an npc /*Merc*/ 0, @@ -734,7 +734,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ SoD::consts::MAP_INSPECT_SIZE, /*Underfoot*/ Underfoot::consts::MAP_INSPECT_SIZE, /*RoF*/ RoF::consts::MAP_INSPECT_SIZE, -/*RoF2*/ 0, +/*RoF2*/ RoF2::consts::MAP_INSPECT_SIZE, /*NPC*/ NOT_USED, /*Merc*/ NOT_USED, @@ -749,7 +749,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ 0, /*Underfoot*/ 0, /*RoF*/ EmuConstants::MAP_REAL_ESTATE_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::MAP_REAL_ESTATE_SIZE, /*NPC*/ 0, /*Merc*/ 0, @@ -764,7 +764,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ 0, /*Underfoot*/ 0, /*RoF*/ EmuConstants::MAP_VIEW_MOD_PC_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::MAP_VIEW_MOD_PC_SIZE, /*NPC*/ 0, /*Merc*/ 0, @@ -779,7 +779,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ 0, /*Underfoot*/ 0, /*RoF*/ EmuConstants::MAP_VIEW_MOD_BANK_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::MAP_VIEW_MOD_BANK_SIZE, /*NPC*/ 0, /*Merc*/ 0, @@ -794,7 +794,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ 0, /*Underfoot*/ 0, /*RoF*/ EmuConstants::MAP_VIEW_MOD_SHARED_BANK_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::MAP_VIEW_MOD_SHARED_BANK_SIZE, /*NPC*/ 0, /*Merc*/ 0, @@ -809,7 +809,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ 0, /*Underfoot*/ 0, /*RoF*/ EmuConstants::MAP_VIEW_MOD_LIMBO_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::MAP_VIEW_MOD_LIMBO_SIZE, /*NPC*/ 0, /*Merc*/ 0, @@ -824,7 +824,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ 0, /*Underfoot*/ 0, /*RoF*/ EmuConstants::MAP_ALT_STORAGE_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::MAP_ALT_STORAGE_SIZE, /*NPC*/ 0, /*Merc*/ 0, @@ -839,7 +839,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ 0, /*Underfoot*/ 0, /*RoF*/ EmuConstants::MAP_ARCHIVED_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::MAP_ARCHIVED_SIZE, /*NPC*/ 0, /*Merc*/ 0, @@ -854,7 +854,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ 0, /*Underfoot*/ 0, /*RoF*/ EmuConstants::MAP_MAIL_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::MAP_MAIL_SIZE, /*NPC*/ 0, /*Merc*/ 0, @@ -869,7 +869,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ 0, /*Underfoot*/ 0, /*RoF*/ EmuConstants::MAP_GUILD_TROPHY_TRIBUTE_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::MAP_GUILD_TROPHY_TRIBUTE_SIZE, /*NPC*/ 0, /*Merc*/ 0, @@ -884,7 +884,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ NOT_USED, /*Underfoot*/ NOT_USED, /*RoF*/ EmuConstants::MAP_KRONO_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::MAP_KRONO_SIZE, /*NPC*/ 0, /*Merc*/ 0, @@ -899,7 +899,7 @@ uint16 EQLimits::InventoryMapSize(int16 map, uint32 version) { /*SoD*/ 0, /*Underfoot*/ 0, /*RoF*/ EmuConstants::MAP_OTHER_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::MAP_OTHER_SIZE, /*NPC*/ 0, /*Merc*/ 0, @@ -1012,7 +1012,7 @@ bool EQLimits::AllowsEmptyBagInBag(uint32 version) { /*SoD*/ SoD::limits::ALLOWS_EMPTY_BAG_IN_BAG, /*Underfoot*/ Underfoot::limits::ALLOWS_EMPTY_BAG_IN_BAG, /*RoF*/ RoF::limits::ALLOWS_EMPTY_BAG_IN_BAG, -/*RoF2*/ false, +/*RoF2*/ RoF2::limits::ALLOWS_EMPTY_BAG_IN_BAG, /*NPC*/ false, /*Merc*/ false, @@ -1033,7 +1033,7 @@ bool EQLimits::AllowsClickCastFromBag(uint32 version) { /*SoD*/ SoD::limits::ALLOWS_CLICK_CAST_FROM_BAG, /*Underfoot*/ Underfoot::limits::ALLOWS_CLICK_CAST_FROM_BAG, /*RoF*/ RoF::limits::ALLOWS_CLICK_CAST_FROM_BAG, -/*RoF2*/ false, +/*RoF2*/ RoF2::limits::ALLOWS_CLICK_CAST_FROM_BAG, /*NPC*/ false, /*Merc*/ false, @@ -1054,7 +1054,7 @@ uint16 EQLimits::ItemCommonSize(uint32 version) { /*SoD*/ EmuConstants::ITEM_COMMON_SIZE, /*Underfoot*/ EmuConstants::ITEM_COMMON_SIZE, /*RoF*/ EmuConstants::ITEM_COMMON_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::ITEM_COMMON_SIZE, /*NPC*/ EmuConstants::ITEM_COMMON_SIZE, /*Merc*/ EmuConstants::ITEM_COMMON_SIZE, @@ -1074,7 +1074,7 @@ uint16 EQLimits::ItemContainerSize(uint32 version) { /*SoD*/ EmuConstants::ITEM_CONTAINER_SIZE, /*Underfoot*/ EmuConstants::ITEM_CONTAINER_SIZE, /*RoF*/ EmuConstants::ITEM_CONTAINER_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::ITEM_CONTAINER_SIZE, /*NPC*/ EmuConstants::ITEM_CONTAINER_SIZE, /*Merc*/ EmuConstants::ITEM_CONTAINER_SIZE, @@ -1094,7 +1094,7 @@ bool EQLimits::CoinHasWeight(uint32 version) { /*SoD*/ SoD::limits::COIN_HAS_WEIGHT, /*Underfoot*/ Underfoot::limits::COIN_HAS_WEIGHT, /*RoF*/ RoF::limits::COIN_HAS_WEIGHT, -/*RoF2*/ true, +/*RoF2*/ RoF::limits::COIN_HAS_WEIGHT, /*NPC*/ true, /*Merc*/ true, @@ -1114,7 +1114,7 @@ uint32 EQLimits::BandoliersCount(uint32 version) { /*SoD*/ EmuConstants::BANDOLIERS_COUNT, /*Underfoot*/ EmuConstants::BANDOLIERS_COUNT, /*RoF*/ EmuConstants::BANDOLIERS_COUNT, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::BANDOLIERS_COUNT, /*NPC*/ NOT_USED, /*Merc*/ NOT_USED, @@ -1134,7 +1134,7 @@ uint32 EQLimits::BandolierSize(uint32 version) { /*SoD*/ EmuConstants::BANDOLIER_SIZE, /*Underfoot*/ EmuConstants::BANDOLIER_SIZE, /*RoF*/ EmuConstants::BANDOLIER_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::BANDOLIER_SIZE, /*NPC*/ NOT_USED, /*Merc*/ NOT_USED, @@ -1154,7 +1154,7 @@ uint32 EQLimits::PotionBeltSize(uint32 version) { /*SoD*/ EmuConstants::POTION_BELT_SIZE, /*Underfoot*/ EmuConstants::POTION_BELT_SIZE, /*RoF*/ EmuConstants::POTION_BELT_SIZE, -/*RoF2*/ 0, +/*RoF2*/ EmuConstants::POTION_BELT_SIZE, /*NPC*/ NOT_USED, /*Merc*/ NOT_USED, diff --git a/common/eq_dictionary.h b/common/eq_dictionary.h index c08809a12..8ef38c77c 100644 --- a/common/eq_dictionary.h +++ b/common/eq_dictionary.h @@ -32,7 +32,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "../common/patches/sod_constants.h" #include "../common/patches/underfoot_constants.h" #include "../common/patches/rof_constants.h" -//#include "../common/patches/rof2_constants.h" +#include "../common/patches/rof2_constants.h" // *** DO NOT CHANGE without a full understanding of the consequences..the server is set up to use these settings explicitly!! *** // *** You will cause compilation failures and corrupt your database if partial or incorrect attempts to change them are made!! *** diff --git a/common/misc_functions.cpp b/common/misc_functions.cpp index 882cc61c7..81fc2434b 100644 --- a/common/misc_functions.cpp +++ b/common/misc_functions.cpp @@ -54,20 +54,6 @@ #include #endif -static bool WELLRNG_init = false; -static int state_i = 0; -static unsigned int STATE[R]; -static unsigned int z0, z1, z2; -unsigned int (*WELLRNG19937)(void); -static unsigned int case_1 (void); -static unsigned int case_2 (void); -static unsigned int case_3 (void); -static unsigned int case_4 (void); -static unsigned int case_5 (void); -static unsigned int case_6 (void); -uint32 rnd_hash(time_t t, clock_t c); -void oneseed(const uint32 seed); - void CoutTimestamp(bool ms) { time_t rawtime; struct tm* gmt_t; @@ -179,41 +165,6 @@ const char * itoa(int num, char* a,int b) { } #endif -/* - * generate a random integer in the range low-high this - * should be used instead of the rand()%limit method - */ -int MakeRandomInt(int low, int high) -{ - if(low >= high) - return(low); - - //return (rand()%(high-low+1) + (low)); - if(!WELLRNG_init) { - WELLRNG_init = true; - oneseed( rnd_hash( time(nullptr), clock() ) ); - WELLRNG19937 = case_1; - } - unsigned int randomnum = ((WELLRNG19937)()); - if(randomnum == 0xffffffffUL) - return high; - return int ((randomnum / (double)0xffffffffUL) * (high - low + 1) + low); -} - -double MakeRandomFloat(double low, double high) -{ - if(low >= high) - return(low); - - //return (rand() / (double)RAND_MAX * (high - low) + low); - if(!WELLRNG_init) { - WELLRNG_init = true; - oneseed( rnd_hash( time(nullptr), clock() ) ); - WELLRNG19937 = case_1; - } - return ((WELLRNG19937)() / (double)0xffffffffUL * (high - low) + low); -} - uint32 rnd_hash( time_t t, clock_t c ) { // Get a uint32 from t and c @@ -239,111 +190,6 @@ uint32 rnd_hash( time_t t, clock_t c ) return ( h1 + differ++ ) ^ h2; } -void oneseed( const uint32 seed ) -{ - // Initialize generator state with seed - // See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier. - // In previous versions, most significant bits (MSBs) of the seed affect - // only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto. - register int j = 0; - STATE[j] = seed & 0xffffffffUL; - for (j = 1; j < R; j++) - { - STATE[j] = ( 1812433253UL * ( STATE[j-1] ^ (STATE[j-1] >> 30) ) + j ) & 0xffffffffUL; - } -} - -// WELL RNG code - -/* ***************************************************************************** */ -/* Copyright: Francois Panneton and Pierre L'Ecuyer, University of Montreal */ -/* Makoto Matsumoto, Hiroshima University */ -/* Notice: This code can be used freely for personal, academic, */ -/* or non-commercial purposes. For commercial purposes, */ -/* please contact P. L'Ecuyer at: lecuyer@iro.UMontreal.ca */ -/* A modified "maximally equidistributed" implementation */ -/* by Shin Harase, Hiroshima University. */ -/* ***************************************************************************** */ - -unsigned int case_1 (void){ - // state_i == 0 - z0 = (VRm1Under & MASKL) | (VRm2Under & MASKU); - z1 = MAT0NEG (-25, V0) ^ MAT0POS (27, VM1); - z2 = MAT3POS (9, VM2) ^ MAT0POS (1, VM3); - newV1 = z1 ^ z2; - newV0Under = MAT1 (z0) ^ MAT0NEG (-9, z1) ^ MAT0NEG (-21, z2) ^ MAT0POS (21, newV1); - state_i = R - 1; - WELLRNG19937 = case_3; - return (STATE[state_i] ^ (newVM2Over & BITMASK)); -} - -static unsigned int case_2 (void){ - // state_i == 1 - z0 = (VRm1 & MASKL) | (VRm2Under & MASKU); - z1 = MAT0NEG (-25, V0) ^ MAT0POS (27, VM1); - z2 = MAT3POS (9, VM2) ^ MAT0POS (1, VM3); - newV1 = z1 ^ z2; - newV0 = MAT1 (z0) ^ MAT0NEG (-9, z1) ^ MAT0NEG (-21, z2) ^ MAT0POS (21, newV1); - state_i = 0; - WELLRNG19937 = case_1; - return (STATE[state_i] ^ (newVM2 & BITMASK)); -} - -static unsigned int case_3 (void){ - // state_i+M1 >= R - z0 = (VRm1 & MASKL) | (VRm2 & MASKU); - z1 = MAT0NEG (-25, V0) ^ MAT0POS (27, VM1Over); - z2 = MAT3POS (9, VM2Over) ^ MAT0POS (1, VM3Over); - newV1 = z1 ^ z2; - newV0 = MAT1 (z0) ^ MAT0NEG (-9, z1) ^ MAT0NEG (-21, z2) ^ MAT0POS (21, newV1); - state_i--; - if (state_i + M1 < R) - WELLRNG19937 = case_5; - return (STATE[state_i] ^ (newVM2Over & BITMASK)); -} - -static unsigned int case_4 (void){ - // state_i+M3 >= R - z0 = (VRm1 & MASKL) | (VRm2 & MASKU); - z1 = MAT0NEG (-25, V0) ^ MAT0POS (27, VM1); - z2 = MAT3POS (9, VM2) ^ MAT0POS (1, VM3Over); - newV1 = z1 ^ z2; - newV0 = MAT1 (z0) ^ MAT0NEG (-9, z1) ^ MAT0NEG (-21, z2) ^ MAT0POS (21, newV1); - state_i--; - if (state_i + M3 < R) - WELLRNG19937 = case_6; - return (STATE[state_i] ^ (newVM2 & BITMASK)); -} - -static unsigned int case_5 (void){ - // state_i+M2 >= R - z0 = (VRm1 & MASKL) | (VRm2 & MASKU); - z1 = MAT0NEG (-25, V0) ^ MAT0POS (27, VM1); - z2 = MAT3POS (9, VM2Over) ^ MAT0POS (1, VM3Over); - newV1 = z1 ^ z2; - newV0 = MAT1 (z0) ^ MAT0NEG (-9, z1) ^ MAT0NEG (-21, z2) ^ MAT0POS (21, newV1); - state_i--; - if (state_i + M2 < R) - WELLRNG19937 = case_4; - return (STATE[state_i] ^ (newVM2Over & BITMASK)); -} - -static unsigned int case_6 (void){ - // 2 <= state_i <= (R - M3 - 1) - z0 = (VRm1 & MASKL) | (VRm2 & MASKU); - z1 = MAT0NEG (-25, V0) ^ MAT0POS (27, VM1); - z2 = MAT3POS (9, VM2) ^ MAT0POS (1, VM3); - newV1 = z1 ^ z2; - newV0 = MAT1 (z0) ^ MAT0NEG (-9, z1) ^ MAT0NEG (-21, z2) ^ MAT0POS (21, newV1); - state_i--; - if (state_i == 1) - WELLRNG19937 = case_2; - return (STATE[state_i] ^ (newVM2 & BITMASK)); -} - -// end WELL RNG code - - float EQ13toFloat(int d) { return ( float(d)/float(1<<2)); diff --git a/common/misc_functions.h b/common/misc_functions.h index abc9747b5..a013423ff 100644 --- a/common/misc_functions.h +++ b/common/misc_functions.h @@ -92,8 +92,6 @@ int32 filesize(FILE* fp); uint32 ResolveIP(const char* hostname, char* errbuf = 0); bool ParseAddress(const char* iAddress, uint32* oIP, uint16* oPort, char* errbuf = 0); void CoutTimestamp(bool ms = true); -int MakeRandomInt(int low, int high); -double MakeRandomFloat(double low, double high); float EQ13toFloat(int d); float NewEQ13toFloat(int d); float EQ19toFloat(int d); diff --git a/common/patches/patches.cpp b/common/patches/patches.cpp index 212042210..50d77a43f 100644 --- a/common/patches/patches.cpp +++ b/common/patches/patches.cpp @@ -8,7 +8,7 @@ #include "sof.h" #include "sod.h" #include "rof.h" -//#include "rof2.h" +#include "rof2.h" void RegisterAllPatches(EQStreamIdentifier &into) { Client62::Register(into); @@ -17,7 +17,7 @@ void RegisterAllPatches(EQStreamIdentifier &into) { SoD::Register(into); Underfoot::Register(into); RoF::Register(into); - //RoF2::Register(into); + RoF2::Register(into); } void ReloadAllPatches() { @@ -27,5 +27,5 @@ void ReloadAllPatches() { SoD::Reload(); Underfoot::Reload(); RoF::Reload(); - //RoF2::Reload(); + RoF2::Reload(); } diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp new file mode 100644 index 000000000..4d403253f --- /dev/null +++ b/common/patches/rof2.cpp @@ -0,0 +1,5677 @@ +#include "../debug.h" +#include "rof2.h" +#include "../opcodemgr.h" +#include "../logsys.h" +#include "../eq_stream_ident.h" +#include "../crc32.h" + +#include "../eq_packet_structs.h" +#include "../misc_functions.h" +#include "../string_util.h" +#include "../item.h" +#include "rof2_structs.h" +#include "../rulesys.h" + +#include +#include + +namespace RoF2 +{ + static const char *name = "RoF2"; + static OpcodeManager *opcodes = nullptr; + static Strategy struct_strategy; + + char* SerializeItem(const ItemInst *inst, int16 slot_id, uint32 *length, uint8 depth); + + // server to client inventory location converters + static inline structs::ItemSlotStruct ServerToRoF2Slot(uint32 ServerSlot); + static inline structs::MainInvItemSlotStruct ServerToRoF2MainInvSlot(uint32 ServerSlot); + static inline uint32 ServerToRoF2CorpseSlot(uint32 ServerCorpse); + + // client to server inventory location converters + static inline uint32 RoF2ToServerSlot(structs::ItemSlotStruct RoF2Slot); + static inline uint32 RoF2ToServerMainInvSlot(structs::MainInvItemSlotStruct RoF2Slot); + static inline uint32 RoF2ToServerCorpseSlot(uint32 RoF2Corpse); + + void Register(EQStreamIdentifier &into) + { + //create our opcode manager if we havent already + if (opcodes == nullptr) { + //TODO: get this file name from the config file + std::string opfile = "patch_"; + opfile += name; + opfile += ".conf"; + //load up the opcode manager. + //TODO: figure out how to support shared memory with multiple patches... + opcodes = new RegularOpcodeManager(); + if (!opcodes->LoadOpcodes(opfile.c_str())) { + _log(NET__OPCODES, "Error loading opcodes file %s. Not registering patch %s.", opfile.c_str(), name); + return; + } + } + + //ok, now we have what we need to register. + + EQStream::Signature signature; + std::string pname; + + //register our world signature. + pname = std::string(name) + "_world"; + signature.ignore_eq_opcode = 0; + signature.first_length = sizeof(structs::LoginInfo_Struct); + signature.first_eq_opcode = opcodes->EmuToEQ(OP_SendLoginInfo); + into.RegisterPatch(signature, pname.c_str(), &opcodes, &struct_strategy); + + //register our zone signature. + pname = std::string(name) + "_zone"; + signature.ignore_eq_opcode = opcodes->EmuToEQ(OP_AckPacket); + signature.first_length = sizeof(structs::ClientZoneEntry_Struct); + signature.first_eq_opcode = opcodes->EmuToEQ(OP_ZoneEntry); + into.RegisterPatch(signature, pname.c_str(), &opcodes, &struct_strategy); + + + + _log(NET__IDENTIFY, "Registered patch %s", name); + } + + void Reload() + { + //we have a big problem to solve here when we switch back to shared memory + //opcode managers because we need to change the manager pointer, which means + //we need to go to every stream and replace it's manager. + + if (opcodes != nullptr) { + //TODO: get this file name from the config file + std::string opfile = "patch_"; + opfile += name; + opfile += ".conf"; + if (!opcodes->ReloadOpcodes(opfile.c_str())) { + _log(NET__OPCODES, "Error reloading opcodes file %s for patch %s.", opfile.c_str(), name); + return; + } + _log(NET__OPCODES, "Reloaded opcodes for patch %s", name); + } + } + + Strategy::Strategy() : StructStrategy() + { + //all opcodes default to passthrough. +#include "ss_register.h" +#include "rof_ops.h" + } + + std::string Strategy::Describe() const + { + std::string r; + r += "Patch "; + r += name; + return(r); + } + + const EQClientVersion Strategy::ClientVersion() const + { + return EQClientRoF2; + } + +#include "ss_define.h" + +// ENCODE methods + ENCODE(OP_Action) + { + ENCODE_LENGTH_EXACT(Action_Struct); + SETUP_DIRECT_ENCODE(Action_Struct, structs::ActionAlt_Struct); + + OUT(target); + OUT(source); + OUT(level); + eq->unknown06 = 0; + eq->instrument_mod = 1.0f + (emu->instrument_mod - 10) / 10.0f; + eq->bard_focus_id = emu->bard_focus_id; + eq->knockback_angle = emu->sequence; + eq->unknown22 = 0; + OUT(type); + eq->damage = 0; + eq->unknown31 = 0; + OUT(spell); + eq->level2 = eq->level; + eq->effect_flag = emu->buff_unknown; + eq->unknown39 = 14; + eq->unknown43 = 0; + eq->unknown44 = 17; + eq->unknown45 = 0; + eq->unknown46 = -1; + eq->unknown50 = 0; + eq->unknown54 = 0; + + FINISH_ENCODE(); + } + + ENCODE(OP_AdventureMerchantSell) + { + ENCODE_LENGTH_EXACT(Adventure_Sell_Struct); + SETUP_DIRECT_ENCODE(Adventure_Sell_Struct, structs::Adventure_Sell_Struct); + + eq->unknown000 = 1; + OUT(npcid); + eq->slot = ServerToRoF2MainInvSlot(emu->slot); + OUT(charges); + OUT(sell_price); + + FINISH_ENCODE(); + } + + ENCODE(OP_AltCurrency) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + unsigned char *emu_buffer = in->pBuffer; + uint32 opcode = *((uint32*)emu_buffer); + + if (opcode == 8) { + AltCurrencyPopulate_Struct *populate = (AltCurrencyPopulate_Struct*)emu_buffer; + + EQApplicationPacket *outapp = new EQApplicationPacket(OP_AltCurrency, sizeof(structs::AltCurrencyPopulate_Struct) + + sizeof(structs::AltCurrencyPopulateEntry_Struct) * populate->count); + structs::AltCurrencyPopulate_Struct *out_populate = (structs::AltCurrencyPopulate_Struct*)outapp->pBuffer; + + out_populate->opcode = populate->opcode; + out_populate->count = populate->count; + for (uint32 i = 0; i < populate->count; ++i) { + out_populate->entries[i].currency_number = populate->entries[i].currency_number; + out_populate->entries[i].unknown00 = populate->entries[i].unknown00; + out_populate->entries[i].currency_number2 = populate->entries[i].currency_number2; + out_populate->entries[i].item_id = populate->entries[i].item_id; + out_populate->entries[i].item_icon = populate->entries[i].item_icon; + out_populate->entries[i].stack_size = populate->entries[i].stack_size; + out_populate->entries[i].display = ((populate->entries[i].stack_size > 0) ? 1 : 0); + } + + dest->FastQueuePacket(&outapp, ack_req); + } + else { + EQApplicationPacket *outapp = new EQApplicationPacket(OP_AltCurrency, sizeof(AltCurrencyUpdate_Struct)); + memcpy(outapp->pBuffer, emu_buffer, sizeof(AltCurrencyUpdate_Struct)); + dest->FastQueuePacket(&outapp, ack_req); + } + + //dest->FastQueuePacket(&outapp, ack_req); + delete in; + } + + ENCODE(OP_AltCurrencySell) + { + ENCODE_LENGTH_EXACT(AltCurrencySellItem_Struct); + SETUP_DIRECT_ENCODE(AltCurrencySellItem_Struct, structs::AltCurrencySellItem_Struct); + + OUT(merchant_entity_id); + eq->slot_id = ServerToRoF2Slot(emu->slot_id); + OUT(charges); + OUT(cost); + + FINISH_ENCODE(); + } + + ENCODE(OP_Animation) + { + ENCODE_LENGTH_EXACT(Animation_Struct); + SETUP_DIRECT_ENCODE(Animation_Struct, structs::Animation_Struct); + + OUT(spawnid); + OUT(value); + OUT(action); + + FINISH_ENCODE(); + } + + ENCODE(OP_ApplyPoison) + { + ENCODE_LENGTH_EXACT(ApplyPoison_Struct); + SETUP_DIRECT_ENCODE(ApplyPoison_Struct, structs::ApplyPoison_Struct); + + eq->inventorySlot = ServerToRoF2MainInvSlot(emu->inventorySlot); + OUT(success); + + FINISH_ENCODE(); + } + + ENCODE(OP_AugmentInfo) + { + ENCODE_LENGTH_EXACT(AugmentInfo_Struct); + SETUP_DIRECT_ENCODE(AugmentInfo_Struct, structs::AugmentInfo_Struct); + + OUT(itemid); + OUT(window); + strn0cpy(eq->augment_info, emu->augment_info, 64); + + FINISH_ENCODE(); + } + + ENCODE(OP_Barter) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + char *Buffer = (char *)in->pBuffer; + + uint32 SubAction = VARSTRUCT_DECODE_TYPE(uint32, Buffer); + + if (SubAction != Barter_BuyerAppearance) + { + dest->FastQueuePacket(&in, ack_req); + + return; + } + + unsigned char *__emu_buffer = in->pBuffer; + + in->size = 80; + + in->pBuffer = new unsigned char[in->size]; + + char *OutBuffer = (char *)in->pBuffer; + + char Name[64]; + + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, SubAction); + uint32 EntityID = VARSTRUCT_DECODE_TYPE(uint32, Buffer); + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, EntityID); + uint8 Toggle = VARSTRUCT_DECODE_TYPE(uint8, Buffer); + VARSTRUCT_DECODE_STRING(Name, Buffer); + VARSTRUCT_ENCODE_STRING(OutBuffer, Name); + OutBuffer = (char *)in->pBuffer + 72; + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, Toggle); + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + } + + ENCODE(OP_BazaarSearch) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + char *Buffer = (char *)in->pBuffer; + + uint8 SubAction = VARSTRUCT_DECODE_TYPE(uint8, Buffer); + + if (SubAction != BazaarSearchResults) + { + dest->FastQueuePacket(&in, ack_req); + return; + } + + unsigned char *__emu_buffer = in->pBuffer; + + BazaarSearchResults_Struct *emu = (BazaarSearchResults_Struct *)__emu_buffer; + + int EntryCount = in->size / sizeof(BazaarSearchResults_Struct); + + if (EntryCount == 0 || (in->size % sizeof(BazaarSearchResults_Struct)) != 0) + { + _log(NET__STRUCTS, "Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(BazaarSearchResults_Struct)); + delete in; + return; + } + + in->size = EntryCount * sizeof(structs::BazaarSearchResults_Struct); + in->pBuffer = new unsigned char[in->size]; + + memset(in->pBuffer, 0, in->size); + + structs::BazaarSearchResults_Struct *eq = (structs::BazaarSearchResults_Struct *)in->pBuffer; + + for (int i = 0; i < EntryCount; ++i, ++emu, ++eq) + { + OUT(Beginning.Action); + OUT(SellerID); + memcpy(eq->SellerName, emu->SellerName, sizeof(eq->SellerName)); + OUT(NumItems); + OUT(ItemID); + OUT(SerialNumber); + memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName)); + OUT(Cost); + OUT(ItemStat); + } + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + } + + ENCODE(OP_BeginCast) + { + SETUP_DIRECT_ENCODE(BeginCast_Struct, structs::BeginCast_Struct); + + OUT(spell_id); + OUT(caster_id); + OUT(cast_time); + + FINISH_ENCODE(); + } + + ENCODE(OP_BlockedBuffs) + { + ENCODE_LENGTH_EXACT(BlockedBuffs_Struct); + SETUP_DIRECT_ENCODE(BlockedBuffs_Struct, structs::BlockedBuffs_Struct); + + for (uint32 i = 0; i < BLOCKED_BUFF_COUNT; ++i) + eq->SpellID[i] = emu->SpellID[i]; + + // -1 for the extra 10 added in RoF2. We should really be encoding for the older clients, not RoF2, but + // we can sort that out later. + + for (uint32 i = BLOCKED_BUFF_COUNT; i < structs::BLOCKED_BUFF_COUNT; ++i) + eq->SpellID[i] = -1; + + OUT(Count); + OUT(Pet); + OUT(Initialise); + OUT(Flags); + + FINISH_ENCODE(); + } + + ENCODE(OP_Buff) + { + ENCODE_LENGTH_EXACT(SpellBuffFade_Struct); + SETUP_DIRECT_ENCODE(SpellBuffFade_Struct, structs::SpellBuffFade_Struct_Live); + + OUT(entityid); + eq->unknown004 = 2; + //eq->level = 80; + //eq->effect = 0; + OUT(level); + OUT(effect); + eq->unknown007 = 0; + eq->unknown008 = 1.0f; + OUT(spellid); + OUT(duration); + eq->playerId = 0x7cde; + OUT(slotid); + OUT(num_hits); + if (emu->bufffade == 1) + eq->bufffade = 1; + else + eq->bufffade = 2; + + // Bit of a hack. OP_Buff appears to add/remove the buff while OP_BuffCreate adds/removes the actual buff icon + EQApplicationPacket *outapp = nullptr; + if (eq->bufffade == 1) + { + outapp = new EQApplicationPacket(OP_BuffCreate, 29); + outapp->WriteUInt32(emu->entityid); + outapp->WriteUInt32(0x0271); // Unk + outapp->WriteUInt8(0); // Type of OP_BuffCreate packet ? + outapp->WriteUInt16(1); // 1 buff in this packet + outapp->WriteUInt32(emu->slotid); + outapp->WriteUInt32(0xffffffff); // SpellID (0xffff to remove) + outapp->WriteUInt32(0); // Duration + outapp->WriteUInt32(0); // ? + outapp->WriteUInt8(0); // Caster name + outapp->WriteUInt8(0); // Terminating byte + } + FINISH_ENCODE(); + + if (outapp) + dest->FastQueuePacket(&outapp); // Send the OP_BuffCreate to remove the buff + } + + ENCODE(OP_BuffCreate) + { + SETUP_VAR_ENCODE(BuffIcon_Struct); + + uint32 sz = 12 + (17 * emu->count); + __packet->size = sz; + __packet->pBuffer = new unsigned char[sz]; + memset(__packet->pBuffer, 0, sz); + + __packet->WriteUInt32(emu->entity_id); + __packet->WriteUInt32(0); // PlayerID ? + __packet->WriteUInt8(emu->all_buffs); // 1 indicates all buffs on the player (0 to add or remove a single buff) + __packet->WriteUInt16(emu->count); + + for (uint16 i = 0; i < emu->count; ++i) + { + uint16 buffslot = emu->entries[i].buff_slot; + // Not sure if this is needs amending for RoF2 yet. + if (emu->entries[i].buff_slot >= 25) + { + buffslot += 17; + } + + __packet->WriteUInt32(buffslot); + __packet->WriteUInt32(emu->entries[i].spell_id); + __packet->WriteUInt32(emu->entries[i].tics_remaining); + __packet->WriteUInt32(emu->entries[i].num_hits); // Unknown + __packet->WriteString(""); + } + __packet->WriteUInt8(!emu->all_buffs); // Unknown + + FINISH_ENCODE(); + } + + ENCODE(OP_CancelTrade) + { + ENCODE_LENGTH_EXACT(CancelTrade_Struct); + SETUP_DIRECT_ENCODE(CancelTrade_Struct, structs::CancelTrade_Struct); + + OUT(fromid); + OUT(action); + + FINISH_ENCODE(); + } + + ENCODE(OP_CastSpell) + { + ENCODE_LENGTH_EXACT(CastSpell_Struct); + SETUP_DIRECT_ENCODE(CastSpell_Struct, structs::CastSpell_Struct); + + if (emu->slot == 10) + eq->slot = 13; + else + OUT(slot); + + OUT(spell_id); + eq->inventoryslot = ServerToRoF2Slot(emu->inventoryslot); + //OUT(inventoryslot); + OUT(target_id); + + FINISH_ENCODE(); + } + + ENCODE(OP_ChannelMessage) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + ChannelMessage_Struct *emu = (ChannelMessage_Struct *)in->pBuffer; + + unsigned char *__emu_buffer = in->pBuffer; + + in->size = strlen(emu->sender) + 1 + strlen(emu->targetname) + 1 + strlen(emu->message) + 1 + 36; + in->pBuffer = new unsigned char[in->size]; + + char *OutBuffer = (char *)in->pBuffer; + + VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sender); + VARSTRUCT_ENCODE_STRING(OutBuffer, emu->targetname); + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->language); + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->chan_num); + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, 0); // Unknown + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->skill_in_language); + VARSTRUCT_ENCODE_STRING(OutBuffer, emu->message); + + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown + VARSTRUCT_ENCODE_TYPE(uint16, OutBuffer, 0); // Unknown + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, 0); // Unknown + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + } + + ENCODE(OP_CharInventory) + { + //consume the packet + EQApplicationPacket *in = *p; + + *p = nullptr; + + if (in->size == 0) { + + in->size = 4; + in->pBuffer = new uchar[in->size]; + + *((uint32 *)in->pBuffer) = 0; + + dest->FastQueuePacket(&in, ack_req); + return; + } + + //store away the emu struct + unsigned char *__emu_buffer = in->pBuffer; + + int ItemCount = in->size / sizeof(InternalSerializedItem_Struct); + + if (ItemCount == 0 || (in->size % sizeof(InternalSerializedItem_Struct)) != 0) { + + _log(NET__STRUCTS, "Wrong size on outbound %s: Got %d, expected multiple of %d", + opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(InternalSerializedItem_Struct)); + + delete in; + + return; + } + + InternalSerializedItem_Struct *eq = (InternalSerializedItem_Struct *)in->pBuffer; + + in->pBuffer = new uchar[4]; + *(uint32 *)in->pBuffer = ItemCount; + in->size = 4; + + for (int r = 0; r < ItemCount; r++, eq++) { + + uint32 Length = 0; + + char* Serialized = SerializeItem((const ItemInst*)eq->inst, eq->slot_id, &Length, 0); + + if (Serialized) { + + uchar *OldBuffer = in->pBuffer; + in->pBuffer = new uchar[in->size + Length]; + memcpy(in->pBuffer, OldBuffer, in->size); + + safe_delete_array(OldBuffer); + + memcpy(in->pBuffer + in->size, Serialized, Length); + in->size += Length; + + safe_delete_array(Serialized); + } + else { + _log(NET__ERROR, "Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); + } + } + + delete[] __emu_buffer; + + //_log(NET__ERROR, "Sending inventory to client"); + //_hex(NET__ERROR, in->pBuffer, in->size); + + dest->FastQueuePacket(&in, ack_req); + } + + ENCODE(OP_ClickObjectAction) + { + ENCODE_LENGTH_EXACT(ClickObjectAction_Struct); + SETUP_DIRECT_ENCODE(ClickObjectAction_Struct, structs::ClickObjectAction_Struct); + + OUT(drop_id); + eq->unknown04 = -1; + eq->unknown08 = -1; + OUT(type); + OUT(icon); + eq->unknown16 = 0; + OUT_str(object_name); + + FINISH_ENCODE(); + } + + ENCODE(OP_ClientUpdate) + { + ENCODE_LENGTH_EXACT(PlayerPositionUpdateServer_Struct); + SETUP_DIRECT_ENCODE(PlayerPositionUpdateServer_Struct, structs::PlayerPositionUpdateServer_Struct); + + OUT(spawn_id); + OUT(x_pos); + OUT(delta_x); + OUT(delta_y); + OUT(z_pos); + OUT(delta_heading); + OUT(y_pos); + OUT(delta_z); + OUT(animation); + OUT(heading); + + FINISH_ENCODE(); + } + + ENCODE(OP_Consider) + { + ENCODE_LENGTH_EXACT(Consider_Struct); + SETUP_DIRECT_ENCODE(Consider_Struct, structs::Consider_Struct); + + OUT(playerid); + OUT(targetid); + OUT(faction); + OUT(level); + OUT(pvpcon); + + FINISH_ENCODE(); + } + + ENCODE(OP_Damage) + { + ENCODE_LENGTH_EXACT(CombatDamage_Struct); + SETUP_DIRECT_ENCODE(CombatDamage_Struct, structs::CombatDamage_Struct); + + OUT(target); + OUT(source); + OUT(type); + OUT(spellid); + OUT(damage); + eq->sequence = emu->sequence; + + FINISH_ENCODE(); + } + + ENCODE(OP_DeleteCharge) { ENCODE_FORWARD(OP_MoveItem); } + + ENCODE(OP_DeleteItem) + { + ENCODE_LENGTH_EXACT(DeleteItem_Struct); + SETUP_DIRECT_ENCODE(DeleteItem_Struct, structs::DeleteItem_Struct); + + eq->from_slot = ServerToRoF2Slot(emu->from_slot); + eq->to_slot = ServerToRoF2Slot(emu->to_slot); + OUT(number_in_stack); + + FINISH_ENCODE(); + } + + ENCODE(OP_DeleteSpawn) + { + ENCODE_LENGTH_EXACT(DeleteSpawn_Struct); + SETUP_DIRECT_ENCODE(DeleteSpawn_Struct, structs::DeleteSpawn_Struct); + + OUT(spawn_id); + eq->unknown04 = 1; // Observed + + FINISH_ENCODE(); + } + + ENCODE(OP_DisciplineUpdate) + { + ENCODE_LENGTH_EXACT(Disciplines_Struct); + SETUP_DIRECT_ENCODE(Disciplines_Struct, structs::Disciplines_Struct); + + memcpy(&eq->values, &emu->values, sizeof(Disciplines_Struct)); + + FINISH_ENCODE(); + } + + ENCODE(OP_DzCompass) + { + SETUP_VAR_ENCODE(ExpeditionCompass_Struct); + ALLOC_VAR_ENCODE(structs::ExpeditionCompass_Struct, sizeof(structs::ExpeditionInfo_Struct) + sizeof(structs::ExpeditionCompassEntry_Struct) * emu->count); + + OUT(count); + + for (uint32 i = 0; i < emu->count; ++i) + { + OUT(entries[i].x); + OUT(entries[i].y); + OUT(entries[i].z); + } + + FINISH_ENCODE(); + } + + ENCODE(OP_DzExpeditionEndsWarning) + { + ENCODE_LENGTH_EXACT(ExpeditionExpireWarning); + SETUP_DIRECT_ENCODE(ExpeditionExpireWarning, structs::ExpeditionExpireWarning); + + OUT(minutes_remaining); + + FINISH_ENCODE(); + } + + ENCODE(OP_DzExpeditionInfo) + { + ENCODE_LENGTH_EXACT(ExpeditionInfo_Struct); + SETUP_DIRECT_ENCODE(ExpeditionInfo_Struct, structs::ExpeditionInfo_Struct); + + OUT(max_players); + eq->unknown004 = 785316192; + eq->unknown008 = 435601; + strncpy(eq->expedition_name, emu->expedition_name, sizeof(eq->expedition_name)); + strncpy(eq->leader_name, emu->leader_name, sizeof(eq->leader_name)); + + FINISH_ENCODE(); + } + + ENCODE(OP_DzExpeditionList) + { + SETUP_VAR_ENCODE(ExpeditionLockoutList_Struct); + + std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); + uint32 client_id = 0; + uint8 null_term = 0; + ss.write((const char*)&client_id, sizeof(uint32)); + ss.write((const char*)&emu->count, sizeof(uint32)); + for (uint32 i = 0; i < emu->count; ++i) + { + ss.write(emu->entries[i].expedition, strlen(emu->entries[i].expedition)); + ss.write((const char*)&null_term, sizeof(char)); + ss.write((const char*)&emu->entries[i].time_left, sizeof(uint32)); + ss.write((const char*)&client_id, sizeof(uint32)); + ss.write(emu->entries[i].expedition_event, strlen(emu->entries[i].expedition_event)); + ss.write((const char*)&null_term, sizeof(char)); + } + + __packet->size = ss.str().length(); + __packet->pBuffer = new unsigned char[__packet->size]; + memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size); + + FINISH_ENCODE(); + } + + ENCODE(OP_DzJoinExpeditionConfirm) + { + ENCODE_LENGTH_EXACT(ExpeditionJoinPrompt_Struct); + SETUP_DIRECT_ENCODE(ExpeditionJoinPrompt_Struct, structs::ExpeditionJoinPrompt_Struct); + + strncpy(eq->expedition_name, emu->expedition_name, sizeof(eq->expedition_name)); + strncpy(eq->player_name, emu->player_name, sizeof(eq->player_name)); + + FINISH_ENCODE(); + } + + ENCODE(OP_DzLeaderStatus) + { + SETUP_VAR_ENCODE(ExpeditionLeaderSet_Struct); + + std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); + uint32 client_id = 0; + uint8 null_term = 0; + + ss.write((const char*)&client_id, sizeof(uint32)); + ss.write((const char*)&client_id, sizeof(uint32)); + ss.write(emu->leader_name, strlen(emu->leader_name)); + ss.write((const char*)&null_term, sizeof(char)); + ss.write((const char*)&client_id, sizeof(uint32)); + ss.write((const char*)&client_id, sizeof(uint32));//0xffffffff + ss.write((const char*)&client_id, sizeof(uint32)); + ss.write((const char*)&client_id, sizeof(uint32)); + ss.write((const char*)&client_id, sizeof(uint32)); + ss.write((const char*)&client_id, sizeof(uint32)); + ss.write((const char*)&client_id, sizeof(uint32)); + ss.write((const char*)&client_id, sizeof(uint32)); + ss.write((const char*)&client_id, sizeof(uint32)); + ss.write((const char*)&client_id, sizeof(uint32)); + ss.write((const char*)&client_id, sizeof(uint32)); + ss.write((const char*)&client_id, sizeof(uint32));//1 + ss.write((const char*)&client_id, sizeof(uint32)); + + __packet->size = ss.str().length(); + __packet->pBuffer = new unsigned char[__packet->size]; + memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size); + + FINISH_ENCODE(); + } + + ENCODE(OP_DzMemberList) + { + SETUP_VAR_ENCODE(ExpeditionMemberList_Struct); + + std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); + + uint32 client_id = 0; + uint8 null_term = 0; + ss.write((const char*)&client_id, sizeof(uint32)); + ss.write((const char*)&emu->count, sizeof(uint32)); + for (uint32 i = 0; i < emu->count; ++i) + { + ss.write(emu->entries[i].name, strlen(emu->entries[i].name)); + ss.write((const char*)&null_term, sizeof(char)); + ss.write((const char*)&emu->entries[i].status, sizeof(char)); + } + + __packet->size = ss.str().length(); + __packet->pBuffer = new unsigned char[__packet->size]; + memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size); + + FINISH_ENCODE(); + } + + ENCODE(OP_ExpansionInfo) + { + ENCODE_LENGTH_EXACT(ExpansionInfo_Struct); + SETUP_DIRECT_ENCODE(ExpansionInfo_Struct, structs::ExpansionInfo_Struct); + + OUT(Expansions); + + FINISH_ENCODE(); + } + + ENCODE(OP_GMLastName) + { + ENCODE_LENGTH_EXACT(GMLastName_Struct); + SETUP_DIRECT_ENCODE(GMLastName_Struct, structs::GMLastName_Struct); + + OUT_str(name); + OUT_str(gmname); + OUT_str(lastname); + for (int i = 0; i<4; i++) + { + eq->unknown[i] = emu->unknown[i]; + } + + FINISH_ENCODE(); + } + + ENCODE(OP_GMTrainSkillConfirm) + { + ENCODE_LENGTH_EXACT(GMTrainSkillConfirm_Struct); + SETUP_DIRECT_ENCODE(GMTrainSkillConfirm_Struct, structs::GMTrainSkillConfirm_Struct); + + OUT(SkillID); + OUT(Cost); + OUT(NewSkill); + OUT_str(TrainerName); + + FINISH_ENCODE(); + } + + ENCODE(OP_GroundSpawn) + { + // We are not encoding the spawn_id field here, but it doesn't appear to matter. + // + EQApplicationPacket *in = *p; + *p = nullptr; + + Object_Struct *emu = (Object_Struct *)in->pBuffer; + + unsigned char *__emu_buffer = in->pBuffer; + + in->size = strlen(emu->object_name) + sizeof(Object_Struct)-1; + in->pBuffer = new unsigned char[in->size]; + + char *OutBuffer = (char *)in->pBuffer; + + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->drop_id); + VARSTRUCT_ENCODE_STRING(OutBuffer, emu->object_name); + VARSTRUCT_ENCODE_TYPE(uint16, OutBuffer, emu->zone_id); + VARSTRUCT_ENCODE_TYPE(uint16, OutBuffer, emu->zone_instance); + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->drop_id); // Some unique id + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Same for all objects in the zone + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->heading); + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // Normally 0, but seen (float)255.0 as well + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // Unknown + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 1); // Need to add emu->size to struct + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->y); + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->x); + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->z); + VARSTRUCT_ENCODE_TYPE(int32, OutBuffer, emu->object_type); // Unknown, observed 0x00000014 + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + } + + ENCODE(OP_GroupCancelInvite) + { + ENCODE_LENGTH_EXACT(GroupCancel_Struct); + SETUP_DIRECT_ENCODE(GroupCancel_Struct, structs::GroupCancel_Struct); + + memcpy(eq->name1, emu->name1, sizeof(eq->name1)); + memcpy(eq->name2, emu->name2, sizeof(eq->name2)); + OUT(toggle); + + FINISH_ENCODE(); + } + + ENCODE(OP_GroupFollow) + { + ENCODE_LENGTH_EXACT(GroupGeneric_Struct); + SETUP_DIRECT_ENCODE(GroupGeneric_Struct, structs::GroupFollow_Struct); + + memcpy(eq->name1, emu->name1, sizeof(eq->name1)); + memcpy(eq->name2, emu->name2, sizeof(eq->name2)); + + FINISH_ENCODE(); + } + + ENCODE(OP_GroupFollow2) + { + ENCODE_LENGTH_EXACT(GroupGeneric_Struct); + SETUP_DIRECT_ENCODE(GroupGeneric_Struct, structs::GroupFollow_Struct); + + memcpy(eq->name1, emu->name1, sizeof(eq->name1)); + memcpy(eq->name2, emu->name2, sizeof(eq->name2)); + + FINISH_ENCODE(); + } + + ENCODE(OP_GroupInvite) + { + ENCODE_LENGTH_EXACT(GroupGeneric_Struct); + SETUP_DIRECT_ENCODE(GroupGeneric_Struct, structs::GroupInvite_Struct); + + memcpy(eq->invitee_name, emu->name1, sizeof(eq->invitee_name)); + memcpy(eq->inviter_name, emu->name2, sizeof(eq->inviter_name)); + + FINISH_ENCODE(); + } + + ENCODE(OP_GroupUpdate) + { + //_log(NET__ERROR, "OP_GroupUpdate"); + EQApplicationPacket *in = *p; + GroupJoin_Struct *gjs = (GroupJoin_Struct*)in->pBuffer; + + //_log(NET__ERROR, "Received outgoing OP_GroupUpdate with action code %i", gjs->action); + if ((gjs->action == groupActLeave) || (gjs->action == groupActDisband)) + { + if ((gjs->action == groupActDisband) || !strcmp(gjs->yourname, gjs->membername)) + { + //_log(NET__ERROR, "Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername); + + EQApplicationPacket *outapp = new EQApplicationPacket(OP_GroupDisbandYou, sizeof(structs::GroupGeneric_Struct)); + + structs::GroupGeneric_Struct *ggs = (structs::GroupGeneric_Struct*)outapp->pBuffer; + memcpy(ggs->name1, gjs->yourname, sizeof(ggs->name1)); + memcpy(ggs->name2, gjs->membername, sizeof(ggs->name1)); + dest->FastQueuePacket(&outapp); + + // Make an empty GLAA packet to clear out their useable GLAAs + // + outapp = new EQApplicationPacket(OP_GroupLeadershipAAUpdate, sizeof(GroupLeadershipAAUpdate_Struct)); + + dest->FastQueuePacket(&outapp); + delete in; + return; + } + //if(gjs->action == groupActLeave) + // _log(NET__ERROR, "Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername); + + EQApplicationPacket *outapp = new EQApplicationPacket(OP_GroupDisbandOther, sizeof(structs::GroupGeneric_Struct)); + + structs::GroupGeneric_Struct *ggs = (structs::GroupGeneric_Struct*)outapp->pBuffer; + memcpy(ggs->name1, gjs->yourname, sizeof(ggs->name1)); + memcpy(ggs->name2, gjs->membername, sizeof(ggs->name2)); + //_hex(NET__ERROR, outapp->pBuffer, outapp->size); + dest->FastQueuePacket(&outapp); + + delete in; + return; + } + + if (in->size == sizeof(GroupUpdate2_Struct)) + { + // Group Update2 + //_log(NET__ERROR, "Struct is GroupUpdate2"); + + unsigned char *__emu_buffer = in->pBuffer; + GroupUpdate2_Struct *gu2 = (GroupUpdate2_Struct*)__emu_buffer; + + //_log(NET__ERROR, "Yourname is %s", gu2->yourname); + + int MemberCount = 1; + int PacketLength = 8 + strlen(gu2->leadersname) + 1 + 22 + strlen(gu2->yourname) + 1; + + for (int i = 0; i < 5; ++i) + { + //_log(NET__ERROR, "Membername[%i] is %s", i, gu2->membername[i]); + if (gu2->membername[i][0] != '\0') + { + PacketLength += (22 + strlen(gu2->membername[i]) + 1); + ++MemberCount; + } + } + + //_log(NET__ERROR, "Leadername is %s", gu2->leadersname); + + EQApplicationPacket *outapp = new EQApplicationPacket(OP_GroupUpdateB, PacketLength); + + char *Buffer = (char *)outapp->pBuffer; + + // Header + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // Think this should be SpawnID, but it doesn't seem to matter + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, MemberCount); + VARSTRUCT_ENCODE_STRING(Buffer, gu2->leadersname); + + // Leader + // + + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); + VARSTRUCT_ENCODE_STRING(Buffer, gu2->yourname); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); + //VARSTRUCT_ENCODE_STRING(Buffer, ""); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // This is a string + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0x46); // Observed 0x41 and 0x46 here + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); + VARSTRUCT_ENCODE_TYPE(uint16, Buffer, 0); + + int MemberNumber = 1; + + for (int i = 0; i < 5; ++i) + { + if (gu2->membername[i][0] == '\0') + continue; + + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, MemberNumber++); + VARSTRUCT_ENCODE_STRING(Buffer, gu2->membername[i]); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); + //VARSTRUCT_ENCODE_STRING(Buffer, ""); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // This is a string + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0x41); // Observed 0x41 and 0x46 here + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // Low byte is Main Assist Flag + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); + VARSTRUCT_ENCODE_TYPE(uint16, Buffer, 0); + } + + //_hex(NET__ERROR, outapp->pBuffer, outapp->size); + dest->FastQueuePacket(&outapp); + + outapp = new EQApplicationPacket(OP_GroupLeadershipAAUpdate, sizeof(GroupLeadershipAAUpdate_Struct)); + + GroupLeadershipAAUpdate_Struct *GLAAus = (GroupLeadershipAAUpdate_Struct*)outapp->pBuffer; + + GLAAus->NPCMarkerID = gu2->NPCMarkerID; + memcpy(&GLAAus->LeaderAAs, &gu2->leader_aas, sizeof(GLAAus->LeaderAAs)); + + dest->FastQueuePacket(&outapp); + delete in; + + return; + + } + //_log(NET__ERROR, "Generic GroupUpdate, yourname = %s, membername = %s", gjs->yourname, gjs->membername); + ENCODE_LENGTH_EXACT(GroupJoin_Struct); + SETUP_DIRECT_ENCODE(GroupJoin_Struct, structs::GroupJoin_Struct); + + memcpy(eq->membername, emu->membername, sizeof(eq->membername)); + + EQApplicationPacket *outapp = new EQApplicationPacket(OP_GroupLeadershipAAUpdate, sizeof(GroupLeadershipAAUpdate_Struct)); + GroupLeadershipAAUpdate_Struct *GLAAus = (GroupLeadershipAAUpdate_Struct*)outapp->pBuffer; + + GLAAus->NPCMarkerID = emu->NPCMarkerID; + + memcpy(&GLAAus->LeaderAAs, &emu->leader_aas, sizeof(GLAAus->LeaderAAs)); + //_hex(NET__ERROR, __packet->pBuffer, __packet->size); + + FINISH_ENCODE(); + + dest->FastQueuePacket(&outapp); + } + + ENCODE(OP_GuildMemberList) + { + //consume the packet + EQApplicationPacket *in = *p; + *p = nullptr; + + //store away the emu struct + unsigned char *__emu_buffer = in->pBuffer; + Internal_GuildMembers_Struct *emu = (Internal_GuildMembers_Struct *)in->pBuffer; + + //make a new EQ buffer. + uint32 pnl = strlen(emu->player_name); + uint32 length = sizeof(structs::GuildMembers_Struct) + pnl + + emu->count*sizeof(structs::GuildMemberEntry_Struct) + + emu->name_length + emu->note_length; + in->pBuffer = new uint8[length]; + in->size = length; + //no memset since we fill every byte. + + uint8 *buffer; + buffer = in->pBuffer; + + //easier way to setup GuildMembers_Struct + //set prefix name + strcpy((char *)buffer, emu->player_name); + buffer += pnl; + *buffer = '\0'; + buffer++; + + // Guild ID + buffer += sizeof(uint32); + + //add member count. + *((uint32 *)buffer) = htonl(emu->count); + buffer += sizeof(uint32); + + if (emu->count > 0) { + Internal_GuildMemberEntry_Struct *emu_e = emu->member; + const char *emu_name = (const char *)(__emu_buffer + + sizeof(Internal_GuildMembers_Struct)+ //skip header + emu->count * sizeof(Internal_GuildMemberEntry_Struct) //skip static length member data + ); + const char *emu_note = (emu_name + + emu->name_length + //skip name contents + emu->count //skip string terminators + ); + + structs::GuildMemberEntry_Struct *e = (structs::GuildMemberEntry_Struct *) buffer; + + uint32 r; + for (r = 0; r < emu->count; r++, emu_e++) { + + //the order we set things here must match the struct + + //nice helper macro +#define SlideStructString(field, str) \ + { \ + int sl = strlen(str); \ + memcpy(e->field, str, sl+1); \ + e = (structs::GuildMemberEntry_Struct *) ( ((uint8 *)e) + sl ); \ + str += sl + 1; \ + } +#define PutFieldN(field) e->field = htonl(emu_e->field) + + SlideStructString(name, emu_name); + PutFieldN(level); + PutFieldN(banker); + PutFieldN(class_); + + /* Translate older ranks to new values */ + switch (emu_e->rank) { + case 0: { e->rank = htonl(5); break; } // GUILD_MEMBER 0 + case 1: { e->rank = htonl(3); break; } // GUILD_OFFICER 1 + case 2: { e->rank = htonl(1); break; } // GUILD_LEADER 2 + default: { e->rank = htonl(emu_e->rank); break; } // GUILD_NONE + } + + PutFieldN(time_last_on); + PutFieldN(tribute_enable); + e->unknown01 = 0; + PutFieldN(total_tribute); + PutFieldN(last_tribute); + e->unknown_one = htonl(1); + SlideStructString(public_note, emu_note); + e->zoneinstance = 0; + e->zone_id = htons(emu_e->zone_id); + e->unknown_one2 = htonl(1); + e->unknown04 = 0; + +#undef SlideStructString +#undef PutFieldN + + e++; + } + } + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + } + + ENCODE(OP_GuildMemberUpdate) + { + SETUP_DIRECT_ENCODE(GuildMemberUpdate_Struct, structs::GuildMemberUpdate_Struct); + + OUT(GuildID); + memcpy(eq->MemberName, emu->MemberName, sizeof(eq->MemberName)); + OUT(ZoneID); + OUT(InstanceID); + OUT(LastSeen); + eq->Unknown76 = 0; + + FINISH_ENCODE(); + } + + ENCODE(OP_GuildsList) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + uint32 NumberOfGuilds = in->size / 64; + uint32 PacketSize = 68; // 64 x 0x00 + a uint32 that I am guessing is the highest guild ID in use. + + unsigned char *__emu_buffer = in->pBuffer; + + char *InBuffer = (char *)__emu_buffer; + + uint32 HighestGuildID = 0; + + for (unsigned int i = 0; i < NumberOfGuilds; ++i) + { + if (InBuffer[0]) + { + PacketSize += (5 + strlen(InBuffer)); + HighestGuildID = i - 1; + } + InBuffer += 64; + } + + PacketSize++; // Appears to be an extra 0x00 at the very end. + + in->size = PacketSize; + in->pBuffer = new unsigned char[in->size]; + + InBuffer = (char *)__emu_buffer; + + char *OutBuffer = (char *)in->pBuffer; + + // Init the first 64 bytes to zero, as per live. + // + memset(OutBuffer, 0, 64); + + OutBuffer += 64; + + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, HighestGuildID); + + for (unsigned int i = 0; i < NumberOfGuilds; ++i) + { + if (InBuffer[0]) + { + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, i - 1); + VARSTRUCT_ENCODE_STRING(OutBuffer, InBuffer); + } + InBuffer += 64; + } + + VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, 0x00); + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + } + + ENCODE(OP_HPUpdate) + { + SETUP_DIRECT_ENCODE(SpawnHPUpdate_Struct, structs::SpawnHPUpdate_Struct); + + OUT(spawn_id); + OUT(cur_hp); + OUT(max_hp); + + FINISH_ENCODE(); + } + + ENCODE(OP_Illusion) + { + ENCODE_LENGTH_EXACT(Illusion_Struct); + SETUP_DIRECT_ENCODE(Illusion_Struct, structs::Illusion_Struct); + + OUT(spawnid); + OUT_str(charname); + OUT(race); + OUT(unknown006[0]); + OUT(unknown006[1]); + OUT(gender); + OUT(texture); + OUT(helmtexture); + OUT(face); + OUT(hairstyle); + OUT(haircolor); + OUT(beard); + OUT(beardcolor); + OUT(size); + OUT(drakkin_heritage); + OUT(drakkin_tattoo); + OUT(drakkin_details); + eq->unknown316 = -1; // Observed + + FINISH_ENCODE(); + } + + /*ENCODE(OP_InspectAnswer) + { + ENCODE_LENGTH_EXACT(InspectResponse_Struct); + SETUP_DIRECT_ENCODE(InspectResponse_Struct, structs::InspectResponse_Struct); + + OUT(TargetID); + OUT(playerid); + + int r; + for (r = 0; r < 21; r++) { + strn0cpy(eq->itemnames[r], emu->itemnames[r], sizeof(eq->itemnames[r])); + } + // Swap last 2 slots for Arrow and Power Source + strn0cpy(eq->itemnames[21], emu->itemnames[22], sizeof(eq->itemnames[21])); + strn0cpy(eq->unknown_zero, emu->itemnames[21], sizeof(eq->unknown_zero)); + + int k; + for (k = 0; k < 21; k++) { + OUT(itemicons[k]); + } + // Swap last 2 slots for Arrow and Power Source + eq->itemicons[21] = emu->itemicons[22]; + eq->unknown_zero2 = emu->itemicons[21]; + strn0cpy(eq->text, emu->text, sizeof(eq->text)); + + FINISH_ENCODE(); + }*/ + + ENCODE(OP_InspectBuffs) + { + ENCODE_LENGTH_EXACT(InspectBuffs_Struct); + SETUP_DIRECT_ENCODE(InspectBuffs_Struct, structs::InspectBuffs_Struct); + + // we go over the internal 25 instead of the packet's since no entry is 0, which it will be already + for (int i = 0; i < BUFF_COUNT; i++) { + OUT(spell_id[i]); + OUT(tics_remaining[i]); + } + + FINISH_ENCODE(); + } + + ENCODE(OP_InspectRequest) + { + ENCODE_LENGTH_EXACT(Inspect_Struct); + SETUP_DIRECT_ENCODE(Inspect_Struct, structs::Inspect_Struct); + + OUT(TargetID); + OUT(PlayerID); + + FINISH_ENCODE(); + } + + ENCODE(OP_InterruptCast) + { + ENCODE_LENGTH_EXACT(InterruptCast_Struct); + SETUP_DIRECT_ENCODE(InterruptCast_Struct, structs::InterruptCast_Struct); + + OUT(spawnid); + OUT(messageid); + + FINISH_ENCODE(); + } + + ENCODE(OP_ItemLinkResponse) { ENCODE_FORWARD(OP_ItemPacket); } + + ENCODE(OP_ItemPacket) + { + //consume the packet + EQApplicationPacket *in = *p; + *p = nullptr; + + unsigned char *__emu_buffer = in->pBuffer; + ItemPacket_Struct *old_item_pkt = (ItemPacket_Struct *)__emu_buffer; + InternalSerializedItem_Struct *int_struct = (InternalSerializedItem_Struct *)(old_item_pkt->SerializedItem); + + uint32 length; + char *serialized = SerializeItem((ItemInst *)int_struct->inst, int_struct->slot_id, &length, 0); + + if (!serialized) { + _log(NET__STRUCTS, "Serialization failed on item slot %d.", int_struct->slot_id); + delete in; + return; + } + in->size = length + 4; + in->pBuffer = new unsigned char[in->size]; + ItemPacket_Struct *new_item_pkt = (ItemPacket_Struct *)in->pBuffer; + new_item_pkt->PacketType = old_item_pkt->PacketType; + memcpy(new_item_pkt->SerializedItem, serialized, length); + + delete[] __emu_buffer; + safe_delete_array(serialized); + dest->FastQueuePacket(&in, ack_req); + } + + ENCODE(OP_ItemVerifyReply) + { + ENCODE_LENGTH_EXACT(ItemVerifyReply_Struct); + SETUP_DIRECT_ENCODE(ItemVerifyReply_Struct, structs::ItemVerifyReply_Struct); + + eq->slot = ServerToRoF2Slot(emu->slot); + OUT(spell); + OUT(target); + + FINISH_ENCODE(); + } + + ENCODE(OP_LeadershipExpUpdate) + { + SETUP_DIRECT_ENCODE(LeadershipExpUpdate_Struct, structs::LeadershipExpUpdate_Struct); + + OUT(group_leadership_exp); + OUT(group_leadership_points); + OUT(raid_leadership_exp); + OUT(raid_leadership_points); + + FINISH_ENCODE(); + } + + ENCODE(OP_LogServer) + { + ENCODE_LENGTH_EXACT(LogServer_Struct); + SETUP_DIRECT_ENCODE(LogServer_Struct, structs::LogServer_Struct); + + strncpy(eq->worldshortname, emu->worldshortname, sizeof(eq->worldshortname)); + + //OUT(enablevoicemacros); // These two are lost, but must be one of the 1s in unknown[249] + //OUT(enablemail); + OUT(enable_pvp); + OUT(enable_FV); + + eq->unknown016 = 1; + eq->unknown020[0] = 1; + + eq->unknown249[0] = 1; + eq->unknown249[1] = 1; + eq->unknown249[8] = 1; + eq->unknown249[9] = 1; + eq->unknown249[12] = 1; + eq->unknown249[14] = 1; + eq->unknown249[15] = 1; + eq->unknown249[16] = 1; + + eq->unknown276[0] = 1.0f; + eq->unknown276[1] = 1.0f; + eq->unknown276[6] = 1.0f; + + FINISH_ENCODE(); + } + + ENCODE(OP_LootItem) + { + ENCODE_LENGTH_EXACT(LootingItem_Struct); + SETUP_DIRECT_ENCODE(LootingItem_Struct, structs::LootingItem_Struct); + + OUT(lootee); + OUT(looter); + eq->slot_id = ServerToRoF2CorpseSlot(emu->slot_id); + OUT(auto_loot); + + FINISH_ENCODE(); + } + + ENCODE(OP_ManaChange) + { + ENCODE_LENGTH_EXACT(ManaChange_Struct); + SETUP_DIRECT_ENCODE(ManaChange_Struct, structs::ManaChange_Struct); + + OUT(new_mana); + OUT(stamina); + OUT(spell_id); + eq->unknown16 = -1; // Self Interrupt/Success = -1, Fizzle = 1, Other Interrupt = 2? + + FINISH_ENCODE(); + } + + ENCODE(OP_MercenaryDataResponse) + { + //consume the packet + EQApplicationPacket *in = *p; + *p = nullptr; + + //store away the emu struct + unsigned char *__emu_buffer = in->pBuffer; + MercenaryMerchantList_Struct *emu = (MercenaryMerchantList_Struct *)__emu_buffer; + + char *Buffer = (char *)in->pBuffer; + + int PacketSize = sizeof(structs::MercenaryMerchantList_Struct) - 4 + emu->MercTypeCount * 4; + PacketSize += (sizeof(structs::MercenaryListEntry_Struct) - sizeof(structs::MercenaryStance_Struct)) * emu->MercCount; + + uint32 r; + uint32 k; + for (r = 0; r < emu->MercCount; r++) + { + PacketSize += sizeof(structs::MercenaryStance_Struct) * emu->Mercs[r].StanceCount; + } + + EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenaryDataResponse, PacketSize); + Buffer = (char *)outapp->pBuffer; + + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercTypeCount); + + for (r = 0; r < emu->MercTypeCount; r++) + { + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercGrades[r]); + } + + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercCount); + + for (r = 0; r < emu->MercCount; r++) + { + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->Mercs[r].MercID); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->Mercs[r].MercType); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->Mercs[r].MercSubType); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->Mercs[r].PurchaseCost); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->Mercs[r].UpkeepCost); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->Mercs[r].Status); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->Mercs[r].AltCurrencyCost); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->Mercs[r].AltCurrencyUpkeep); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->Mercs[r].AltCurrencyType); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->Mercs[r].MercUnk01); + VARSTRUCT_ENCODE_TYPE(int32, Buffer, emu->Mercs[r].TimeLeft); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->Mercs[r].MerchantSlot); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->Mercs[r].MercUnk02); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->Mercs[r].StanceCount); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->Mercs[r].MercUnk03); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->Mercs[r].MercUnk04); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // MercName + for (k = 0; k < emu->Mercs[r].StanceCount; k++) + { + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->Mercs[r].Stances[k].StanceIndex); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->Mercs[r].Stances[k].Stance); + } + } + + dest->FastQueuePacket(&outapp, ack_req); + delete in; + } + + ENCODE(OP_MercenaryDataUpdate) + { + //consume the packet + EQApplicationPacket *in = *p; + *p = nullptr; + + //store away the emu struct + unsigned char *__emu_buffer = in->pBuffer; + MercenaryDataUpdate_Struct *emu = (MercenaryDataUpdate_Struct *)__emu_buffer; + + char *Buffer = (char *)in->pBuffer; + + EQApplicationPacket *outapp; + + uint32 PacketSize = 0; + + // There are 2 different sized versions of this packet depending if a merc is hired or not + if (emu->MercStatus >= 0) + { + PacketSize += sizeof(structs::MercenaryDataUpdate_Struct) + (sizeof(structs::MercenaryData_Struct) - sizeof(structs::MercenaryStance_Struct)) * emu->MercCount; + + uint32 r; + uint32 k; + for (r = 0; r < emu->MercCount; r++) + { + PacketSize += sizeof(structs::MercenaryStance_Struct) * emu->MercData[r].StanceCount; + PacketSize += strlen(emu->MercData[r].MercName); // Null Terminator size already accounted for in the struct + } + + outapp = new EQApplicationPacket(OP_MercenaryDataUpdate, PacketSize); + Buffer = (char *)outapp->pBuffer; + + VARSTRUCT_ENCODE_TYPE(int32, Buffer, emu->MercStatus); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercCount); + + for (r = 0; r < emu->MercCount; r++) + { + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercData[r].MercID); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercData[r].MercType); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercData[r].MercSubType); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercData[r].PurchaseCost); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercData[r].UpkeepCost); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercData[r].Status); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercData[r].AltCurrencyCost); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercData[r].AltCurrencyUpkeep); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercData[r].AltCurrencyType); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->MercData[r].MercUnk01); + VARSTRUCT_ENCODE_TYPE(int32, Buffer, emu->MercData[r].TimeLeft); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercData[r].MerchantSlot); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercData[r].MercUnk02); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercData[r].StanceCount); + VARSTRUCT_ENCODE_TYPE(int32, Buffer, emu->MercData[r].MercUnk03); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->MercData[r].MercUnk04); + //VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // MercName + VARSTRUCT_ENCODE_STRING(Buffer, emu->MercData[r].MercName); + for (k = 0; k < emu->MercData[r].StanceCount; k++) + { + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercData[r].Stances[k].StanceIndex); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercData[r].Stances[k].Stance); + } + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 1); // MercUnk05 + } + } + else + { + PacketSize += sizeof(structs::NoMercenaryHired_Struct); + + outapp = new EQApplicationPacket(OP_MercenaryDataUpdate, PacketSize); + Buffer = (char *)outapp->pBuffer; + + VARSTRUCT_ENCODE_TYPE(int32, Buffer, emu->MercStatus); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercCount); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 1); + } + + dest->FastQueuePacket(&outapp, ack_req); + delete in; + } + + ENCODE(OP_MoveItem) + { + ENCODE_LENGTH_EXACT(MoveItem_Struct); + SETUP_DIRECT_ENCODE(MoveItem_Struct, structs::MoveItem_Struct); + + eq->from_slot = ServerToRoF2Slot(emu->from_slot); + eq->to_slot = ServerToRoF2Slot(emu->to_slot); + OUT(number_in_stack); + + FINISH_ENCODE(); + } + + ENCODE(OP_NewSpawn) { ENCODE_FORWARD(OP_ZoneSpawns); } + + ENCODE(OP_NewZone) + { + SETUP_DIRECT_ENCODE(NewZone_Struct, structs::NewZone_Struct); + + OUT_str(char_name); + OUT_str(zone_short_name); + OUT_str(zone_long_name); + OUT(ztype); + int r; + for (r = 0; r < 4; r++) { + OUT(fog_red[r]); + OUT(fog_green[r]); + OUT(fog_blue[r]); + OUT(fog_minclip[r]); + OUT(fog_maxclip[r]); + } + OUT(gravity); + OUT(time_type); + for (r = 0; r < 4; r++) { + OUT(rain_chance[r]); + } + for (r = 0; r < 4; r++) { + OUT(rain_duration[r]); + } + for (r = 0; r < 4; r++) { + OUT(snow_chance[r]); + } + for (r = 0; r < 4; r++) { + OUT(snow_duration[r]); + } + for (r = 0; r < 32; r++) { + eq->unknown537[r] = 0xFF; //observed + } + OUT(sky); + OUT(zone_exp_multiplier); + OUT(safe_y); + OUT(safe_x); + OUT(safe_z); + OUT(max_z); + OUT(underworld); + OUT(minclip); + OUT(maxclip); + OUT_str(zone_short_name2); + OUT(zone_id); + OUT(zone_instance); + OUT(SuspendBuffs); + + eq->FogDensity = emu->fog_density; + + /*fill in some unknowns with observed values, hopefully it will help */ + eq->unknown800 = -1; + eq->unknown844 = 600; + eq->unknown880 = 50; + eq->unknown884 = 10; + eq->unknown888 = 1; + eq->unknown889 = 0; + eq->unknown890 = 1; + eq->unknown891 = 0; + eq->unknown892 = 0; + eq->unknown893 = 0; + eq->fall_damage = 0; // 0 = Fall Damage on, 1 = Fall Damage off + eq->unknown895 = 0; + eq->unknown896 = 180; + eq->unknown900 = 180; + eq->unknown904 = 180; + eq->unknown908 = 2; + eq->unknown912 = 2; + eq->unknown932 = -1; // Set from PoK Example + eq->unknown936 = -1; // Set from PoK Example + eq->unknown944 = 1.0; // Set from PoK Example + + FINISH_ENCODE(); + } + + ENCODE(OP_OnLevelMessage) + { + ENCODE_LENGTH_EXACT(OnLevelMessage_Struct); + SETUP_DIRECT_ENCODE(OnLevelMessage_Struct, structs::OnLevelMessage_Struct); + + // This packet is variable sized now, but forcing it to the old packet size for now. + eq->Title_Count = 128; + memcpy(eq->Title, emu->Title, sizeof(eq->Title)); + eq->Text_Count = 4096; + memcpy(eq->Text, emu->Text, sizeof(eq->Text)); + OUT(Buttons); + OUT(Duration); + OUT(PopupID); + OUT(NegativeID); + // These two field names are used if Buttons == 1. We should add an interface to them via Perl. + eq->ButtonName0_Count = 25; + OUT_str(ButtonName0); + eq->ButtonName1_Count = 25; + OUT_str(ButtonName1); + + FINISH_ENCODE(); + } + + /* + ENCODE(OP_OpenNewTasksWindow) + { + AvailableTaskHeader_Struct* __emu_AvailableTaskHeader; + AvailableTaskData1_Struct* __emu_AvailableTaskData1; + AvailableTaskData2_Struct* __emu_AvailableTaskData2; + AvailableTaskTrailer_Struct* __emu_AvailableTaskTrailer; + + structs::AvailableTaskHeader_Struct* __eq_AvailableTaskHeader; + structs::AvailableTaskData1_Struct* __eq_AvailableTaskData1; + structs::AvailableTaskData2_Struct* __eq_AvailableTaskData2; + structs::AvailableTaskTrailer_Struct* __eq_AvailableTaskTrailer; + + EQApplicationPacket *in = *p; + *p = nullptr; + + unsigned char *__emu_buffer = in->pBuffer; + + __emu_AvailableTaskHeader = (AvailableTaskHeader_Struct*)__emu_buffer; + + // For each task, SoF has an extra uint32 and what appears to be space for a null terminated string. + // + in->size = in->size + (__emu_AvailableTaskHeader->TaskCount * 5); + + in->pBuffer = new unsigned char[in->size]; + + unsigned char *__eq_buffer = in->pBuffer; + + __eq_AvailableTaskHeader = (structs::AvailableTaskHeader_Struct*)__eq_buffer; + + char *__eq_ptr, *__emu_Ptr; + + // Copy Header + // + // + + __eq_AvailableTaskHeader->TaskCount = __emu_AvailableTaskHeader->TaskCount; + __eq_AvailableTaskHeader->unknown1 = __emu_AvailableTaskHeader->unknown1; + __eq_AvailableTaskHeader->TaskGiver = __emu_AvailableTaskHeader->TaskGiver; + + __emu_Ptr = (char *) __emu_AvailableTaskHeader + sizeof(AvailableTaskHeader_Struct); + __eq_ptr = (char *) __eq_AvailableTaskHeader + sizeof(structs::AvailableTaskHeader_Struct); + + for(uint32 i=0; i<__emu_AvailableTaskHeader->TaskCount; i++) { + + __emu_AvailableTaskData1 = (AvailableTaskData1_Struct*)__emu_Ptr; + __eq_AvailableTaskData1 = (structs::AvailableTaskData1_Struct*)__eq_ptr; + + __eq_AvailableTaskData1->TaskID = __emu_AvailableTaskData1->TaskID; + // This next unknown seems to affect the colour of the task title. 0x3f80000 is what I have seen + // in RoF2 packets. Changing it to 0x3f000000 makes the title red. + __eq_AvailableTaskData1->unknown1 = 0x3f800000; + __eq_AvailableTaskData1->TimeLimit = __emu_AvailableTaskData1->TimeLimit; + __eq_AvailableTaskData1->unknown2 = __emu_AvailableTaskData1->unknown2; + + __emu_Ptr += sizeof(AvailableTaskData1_Struct); + __eq_ptr += sizeof(structs::AvailableTaskData1_Struct); + + strcpy(__eq_ptr, __emu_Ptr); // Title + + __emu_Ptr += strlen(__emu_Ptr) + 1; + __eq_ptr += strlen(__eq_ptr) + 1; + + strcpy(__eq_ptr, __emu_Ptr); // Description + + __emu_Ptr += strlen(__emu_Ptr) + 1; + __eq_ptr += strlen(__eq_ptr) + 1; + + __eq_ptr[0] = 0; + __eq_ptr += strlen(__eq_ptr) + 1; + + __emu_AvailableTaskData2 = (AvailableTaskData2_Struct*)__emu_Ptr; + __eq_AvailableTaskData2 = (structs::AvailableTaskData2_Struct*)__eq_ptr; + + __eq_AvailableTaskData2->unknown1 = __emu_AvailableTaskData2->unknown1; + __eq_AvailableTaskData2->unknown2 = __emu_AvailableTaskData2->unknown2; + __eq_AvailableTaskData2->unknown3 = __emu_AvailableTaskData2->unknown3; + __eq_AvailableTaskData2->unknown4 = __emu_AvailableTaskData2->unknown4; + + __emu_Ptr += sizeof(AvailableTaskData2_Struct); + __eq_ptr += sizeof(structs::AvailableTaskData2_Struct); + + strcpy(__eq_ptr, __emu_Ptr); // Unknown string + + __emu_Ptr += strlen(__emu_Ptr) + 1; + __eq_ptr += strlen(__eq_ptr) + 1; + + strcpy(__eq_ptr, __emu_Ptr); // Unknown string + + __emu_Ptr += strlen(__emu_Ptr) + 1; + __eq_ptr += strlen(__eq_ptr) + 1; + + __emu_AvailableTaskTrailer = (AvailableTaskTrailer_Struct*)__emu_Ptr; + __eq_AvailableTaskTrailer = (structs::AvailableTaskTrailer_Struct*)__eq_ptr; + + __eq_AvailableTaskTrailer->ItemCount = __emu_AvailableTaskTrailer->ItemCount; + __eq_AvailableTaskTrailer->unknown1 = __emu_AvailableTaskTrailer->unknown1; + __eq_AvailableTaskTrailer->unknown2 = __emu_AvailableTaskTrailer->unknown2; + __eq_AvailableTaskTrailer->StartZone = __emu_AvailableTaskTrailer->StartZone; + + __emu_Ptr += sizeof(AvailableTaskTrailer_Struct); + __eq_ptr += sizeof(structs::AvailableTaskTrailer_Struct); + + strcpy(__eq_ptr, __emu_Ptr); // Unknown string + + __emu_Ptr += strlen(__emu_Ptr) + 1; + __eq_ptr += strlen(__eq_ptr) + 1; + } + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + } + */ + + ENCODE(OP_PetBuffWindow) + { + // The format of the RoF2 packet is identical to the OP_BuffCreate packet. + + SETUP_VAR_ENCODE(PetBuff_Struct); + + uint32 sz = 12 + (17 * emu->buffcount); + __packet->size = sz; + __packet->pBuffer = new unsigned char[sz]; + memset(__packet->pBuffer, 0, sz); + + __packet->WriteUInt32(emu->petid); + __packet->WriteUInt32(0); // PlayerID ? + __packet->WriteUInt8(1); // 1 indicates all buffs on the pet (0 to add or remove a single buff) + __packet->WriteUInt16(emu->buffcount); + + for (uint16 i = 0; i < BUFF_COUNT; ++i) + { + if (emu->spellid[i]) + { + __packet->WriteUInt32(i); + __packet->WriteUInt32(emu->spellid[i]); + __packet->WriteUInt32(emu->ticsremaining[i]); + __packet->WriteUInt32(0); // Unknown + __packet->WriteString(""); + } + } + __packet->WriteUInt8(0); // Unknown + + FINISH_ENCODE(); + } + + ENCODE(OP_PlayerProfile) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + unsigned char *__emu_buffer = in->pBuffer; + PlayerProfile_Struct *emu = (PlayerProfile_Struct *)__emu_buffer; + + uint32 PacketSize = 40000; // Calculate this later + + EQApplicationPacket *outapp = new EQApplicationPacket(OP_PlayerProfile, PacketSize); + + outapp->WriteUInt32(0); // Checksum, we will update this later + outapp->WriteUInt32(0); // Checksum size, we will update this later + + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + + + outapp->WriteUInt8(emu->gender); // Gender + outapp->WriteUInt32(emu->race); // Race + outapp->WriteUInt8(emu->class_); // Class + outapp->WriteUInt8(emu->level); // Level + outapp->WriteUInt8(emu->level); // Level1 + + + outapp->WriteUInt32(5); // Bind count + + for (int r = 0; r < 5; r++) + { + outapp->WriteUInt32(emu->binds[r].zoneId); + outapp->WriteFloat(emu->binds[r].x); + outapp->WriteFloat(emu->binds[r].y); + outapp->WriteFloat(emu->binds[r].z); + outapp->WriteFloat(emu->binds[r].heading); + } + + outapp->WriteUInt32(emu->deity); + outapp->WriteUInt32(emu->intoxication); + + outapp->WriteUInt32(10); // Unknown count + + for (int r = 0; r < 10; r++) + { + outapp->WriteUInt32(0); // Unknown + } + + outapp->WriteUInt32(22); // Equipment count + + for (int r = 0; r < 9; r++) + { + outapp->WriteUInt32(emu->item_material[r]); + outapp->WriteUInt32(0); + outapp->WriteUInt32(0); + outapp->WriteUInt32(0); + outapp->WriteUInt32(0); + } + + // Write zeroes for the next 13 equipment slots + + for (int r = 0; r < 13; r++) + { + outapp->WriteUInt32(0); + outapp->WriteUInt32(0); + outapp->WriteUInt32(0); + outapp->WriteUInt32(0); + outapp->WriteUInt32(0); + } + + outapp->WriteUInt32(9); // Equipment2 count + + for (int r = 0; r < 9; r++) + { + outapp->WriteUInt32(0); + outapp->WriteUInt32(0); + outapp->WriteUInt32(0); + outapp->WriteUInt32(0); + outapp->WriteUInt32(0); + } + + outapp->WriteUInt32(9); // Tint Count + + for (int r = 0; r < 7; r++) + { + outapp->WriteUInt32(emu->item_tint[r].color); + } + // Write zeroes for extra two tint values + outapp->WriteUInt32(0); + outapp->WriteUInt32(0); + + outapp->WriteUInt32(9); // Tint2 Count + + for (int r = 0; r < 7; r++) + { + outapp->WriteUInt32(emu->item_tint[r].color); + } + // Write zeroes for extra two tint values + outapp->WriteUInt32(0); + outapp->WriteUInt32(0); + + outapp->WriteUInt8(emu->haircolor); + outapp->WriteUInt8(emu->beardcolor); + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt8(emu->eyecolor1); + outapp->WriteUInt8(emu->eyecolor2); + outapp->WriteUInt8(emu->hairstyle); + outapp->WriteUInt8(emu->beard); + outapp->WriteUInt8(emu->face); + + // Think there should be an extra byte before the drakkin stuff (referred to as oldface in client) + // Then one of the five bytes following the drakkin stuff needs removing. + + outapp->WriteUInt32(emu->drakkin_heritage); + outapp->WriteUInt32(emu->drakkin_tattoo); + outapp->WriteUInt32(emu->drakkin_details); + + outapp->WriteUInt8(0); // Unknown + outapp->WriteUInt8(0); // Unknown + outapp->WriteUInt8(0); // Unknown + outapp->WriteUInt8(0); // Unknown + outapp->WriteUInt8(0); // Unknown + + outapp->WriteFloat(5.0f); // Height ? + + outapp->WriteFloat(3.0f); // Unknown + outapp->WriteFloat(2.5f); // Unknown + outapp->WriteFloat(5.5f); // Unknown + + outapp->WriteUInt32(0); // Primary ? + outapp->WriteUInt32(0); // Secondary ? + + outapp->WriteUInt32(emu->points); // Unspent skill points + outapp->WriteUInt32(emu->mana); + outapp->WriteUInt32(emu->cur_hp); + + outapp->WriteUInt32(emu->STR); + outapp->WriteUInt32(emu->STA); + outapp->WriteUInt32(emu->CHA); + outapp->WriteUInt32(emu->DEX); + outapp->WriteUInt32(emu->INT); + outapp->WriteUInt32(emu->AGI); + outapp->WriteUInt32(emu->WIS); + + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + + outapp->WriteUInt32(300); // AA Count + + for (uint32 r = 0; r < MAX_PP_AA_ARRAY; r++) + { + outapp->WriteUInt32(emu->aa_array[r].AA); + outapp->WriteUInt32(emu->aa_array[r].value); + outapp->WriteUInt32(0); + } + + // Fill the other 60 AAs with zeroes + + for (uint32 r = 0; r < structs::MAX_PP_AA_ARRAY - MAX_PP_AA_ARRAY; r++) + { + outapp->WriteUInt32(0); + outapp->WriteUInt32(0); + outapp->WriteUInt32(0); + } + + outapp->WriteUInt32(structs::MAX_PP_SKILL); + + for (uint32 r = 0; r < structs::MAX_PP_SKILL; r++) + { + outapp->WriteUInt32(emu->skills[r]); + } + + outapp->WriteUInt32(25); // Unknown count + + for (uint32 r = 0; r < 25; r++) + { + outapp->WriteUInt32(0); // Unknown + } + + outapp->WriteUInt32(structs::MAX_PP_DISCIPLINES); // Discipline count + + for (uint32 r = 0; r < MAX_PP_DISCIPLINES; r++) + { + outapp->WriteUInt32(emu->disciplines.values[r]); + } + + // Write zeroes for the rest of the disciplines + for (uint32 r = 0; r < structs::MAX_PP_DISCIPLINES - MAX_PP_DISCIPLINES; r++) + { + outapp->WriteUInt32(0); + } + + outapp->WriteUInt32(20); // Timestamp count + + for (uint32 r = 0; r < 20; r++) + { + outapp->WriteUInt32(0); + } + + outapp->WriteUInt32(MAX_RECAST_TYPES); // Timestamp count + + for (uint32 r = 0; r < MAX_RECAST_TYPES; r++) + { + outapp->WriteUInt32(emu->recastTimers[r]); + } + + outapp->WriteUInt32(100); // Timestamp2 count + + for (uint32 r = 0; r < 100; r++) + { + outapp->WriteUInt32(0); + } + + outapp->WriteUInt32(structs::MAX_PP_SPELLBOOK); // Spellbook slots + + for (uint32 r = 0; r < MAX_PP_SPELLBOOK; r++) + { + outapp->WriteUInt32(emu->spell_book[r]); + } + // zeroes for the rest of the spellbook slots + for (uint32 r = 0; r < structs::MAX_PP_SPELLBOOK - MAX_PP_SPELLBOOK; r++) + { + outapp->WriteUInt32(0xFFFFFFFFU); + } + + outapp->WriteUInt32(structs::MAX_PP_MEMSPELL); // Memorised spell slots + + for (uint32 r = 0; r < MAX_PP_MEMSPELL; r++) + { + outapp->WriteUInt32(emu->mem_spells[r]); + } + // zeroes for the rest of the slots + for (uint32 r = 0; r < structs::MAX_PP_MEMSPELL - MAX_PP_MEMSPELL; r++) + { + outapp->WriteUInt32(0xFFFFFFFFU); + } + + outapp->WriteUInt32(13); // Unknown count + + for (uint32 r = 0; r < 13; r++) + { + outapp->WriteUInt32(0); // Unknown + } + + outapp->WriteUInt8(0); // Unknown + + outapp->WriteUInt32(structs::BUFF_COUNT); + + //*000*/ uint8 slotid; // badly named... seems to be 2 for a real buff, 0 otherwise + //*001*/ float unknown004; // Seen 1 for no buff + //*005*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages + //*009*/ uint32 unknown016; + //*013*/ uint8 bard_modifier; + //*014*/ uint32 duration; + //*018*/ uint8 level; + //*019*/ uint32 spellid; + //*023*/ uint32 counters; + //*027*/ uint8 unknown0028[53]; + //*080*/ + + for (uint32 r = 0; r < BUFF_COUNT; r++) + { + float instrument_mod = 0.0f; + uint8 slotid = emu->buffs[r].slotid; + uint32 player_id = emu->buffs[r].player_id;; + + if (emu->buffs[r].spellid != 0xFFFF && emu->buffs[r].spellid != 0) + { + instrument_mod = 1.0f + (emu->buffs[r].bard_modifier - 10) / 10.0f; + slotid = 2; + player_id = 0x000717fd; + } + else + { + slotid = 0; + } + outapp->WriteUInt8(0); // Had this as slot, but always appears to be 0 on live. + outapp->WriteFloat(instrument_mod); + outapp->WriteUInt32(player_id); + outapp->WriteUInt8(0); + outapp->WriteUInt32(emu->buffs[r].counters); + //outapp->WriteUInt8(emu->buffs[r].bard_modifier); + outapp->WriteUInt32(emu->buffs[r].duration); + outapp->WriteUInt8(emu->buffs[r].level); + outapp->WriteUInt32(emu->buffs[r].spellid); + outapp->WriteUInt32(slotid); // Only ever seen 2 + outapp->WriteUInt32(0); + outapp->WriteUInt8(0); + outapp->WriteUInt32(emu->buffs[r].counters); // Appears twice ? + + for (uint32 j = 0; j < 44; ++j) + outapp->WriteUInt8(0); // Unknown + } + + for (uint32 r = 0; r < structs::BUFF_COUNT - BUFF_COUNT; r++) + { + // 80 bytes of zeroes + for (uint32 j = 0; j < 20; ++j) + outapp->WriteUInt32(0); + + } + + outapp->WriteUInt32(emu->platinum); + outapp->WriteUInt32(emu->gold); + outapp->WriteUInt32(emu->silver); + outapp->WriteUInt32(emu->copper); + + outapp->WriteUInt32(emu->platinum_cursor); + outapp->WriteUInt32(emu->gold_cursor); + outapp->WriteUInt32(emu->silver_cursor); + outapp->WriteUInt32(emu->copper_cursor); + + outapp->WriteUInt32(0); // Unknown + + outapp->WriteUInt32(0); // This is the cooldown timer for the monk 'Mend' skill. Client will add 6 minutes to this value the first time the + // player logs in. After that it will honour whatever value we send here. + + outapp->WriteUInt32(0); // Unknown + + outapp->WriteUInt32(emu->thirst_level); + outapp->WriteUInt32(emu->hunger_level); + + outapp->WriteUInt32(emu->aapoints_spent); + + outapp->WriteUInt32(5); // AA Points count ?? + outapp->WriteUInt32(1234); // AA Points assigned + outapp->WriteUInt32(0); // AA Points in General ? + outapp->WriteUInt32(0); // AA Points in Class ? + outapp->WriteUInt32(0); // AA Points in Archetype ? + outapp->WriteUInt32(0); // AA Points in Special ? + outapp->WriteUInt32(emu->aapoints); // AA Points unspent + + outapp->WriteUInt8(0); // Unknown + outapp->WriteUInt8(0); // Unknown + + outapp->WriteUInt32(structs::MAX_PLAYER_BANDOLIER); + + for (uint32 r = 0; r < EmuConstants::BANDOLIERS_COUNT; r++) + { + outapp->WriteString(emu->bandoliers[r].name); + + for (uint32 j = 0; j < EmuConstants::BANDOLIER_SIZE; ++j) + { + outapp->WriteString(emu->bandoliers[r].items[j].item_name); + outapp->WriteUInt32(emu->bandoliers[r].items[j].item_id); + outapp->WriteUInt32(emu->bandoliers[r].items[j].icon); + } + } + + for (uint32 r = 0; r < structs::MAX_PLAYER_BANDOLIER - EmuConstants::BANDOLIERS_COUNT; r++) + { + outapp->WriteString(""); + + for (uint32 j = 0; j < EmuConstants::BANDOLIER_SIZE; ++j) + { + outapp->WriteString(""); + outapp->WriteUInt32(0); + outapp->WriteUInt32(0); + } + } + + outapp->WriteUInt32(structs::MAX_POTIONS_IN_BELT); + + for (uint32 r = 0; r < EmuConstants::POTION_BELT_SIZE; r++) + { + outapp->WriteString(emu->potionbelt.items[r].item_name); + outapp->WriteUInt32(emu->potionbelt.items[r].item_id); + outapp->WriteUInt32(emu->potionbelt.items[r].icon); + } + + for (uint32 r = 0; r < structs::MAX_POTIONS_IN_BELT - EmuConstants::POTION_BELT_SIZE; r++) + { + outapp->WriteString(""); + outapp->WriteUInt32(0); + outapp->WriteUInt32(0); + } + + outapp->WriteSInt32(-1); // Unknown; + outapp->WriteSInt32(123); // HP Total ? + outapp->WriteSInt32(234); // Endurance Total ? + outapp->WriteSInt32(345); // Mana Total ? + + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + + outapp->WriteUInt32(20); // Unknown - Expansion count ? + + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(emu->endurance); + outapp->WriteUInt32(0); // Unknown - Observed 0x7cde - This is also seen in guild packets sent to this character. + outapp->WriteUInt32(0); // Unknown - Observed 0x64 + + outapp->WriteUInt32(64); // Name Length + + uint32 CurrentPosition = outapp->GetWritePosition(); + + outapp->WriteString(emu->name); + + outapp->SetWritePosition(CurrentPosition + 64); + + outapp->WriteUInt32(32); // Last Name Length + + CurrentPosition = outapp->GetWritePosition(); + + outapp->WriteString(emu->last_name); + + outapp->SetWritePosition(CurrentPosition + 32); + + outapp->WriteUInt32(emu->birthday); + outapp->WriteUInt32(emu->birthday); // Account start date ? + outapp->WriteUInt32(emu->lastlogin); + outapp->WriteUInt32(emu->timePlayedMin); + outapp->WriteUInt32(emu->timeentitledonaccount); + outapp->WriteUInt32(0x0007ffff); // Expansion bitmask + + outapp->WriteUInt32(structs::MAX_PP_LANGUAGE); + + for (uint32 r = 0; r < MAX_PP_LANGUAGE; r++) + { + outapp->WriteUInt8(emu->languages[r]); + } + + for (uint32 r = 0; r < structs::MAX_PP_LANGUAGE - MAX_PP_LANGUAGE; r++) + { + outapp->WriteUInt8(0); + } + + outapp->WriteUInt16(emu->zone_id); + outapp->WriteUInt16(emu->zoneInstance); + + outapp->WriteFloat(emu->y); + outapp->WriteFloat(emu->x); + outapp->WriteFloat(emu->z); + outapp->WriteFloat(emu->heading); + + outapp->WriteUInt8(0); // Unknown + outapp->WriteUInt8(emu->pvp); + outapp->WriteUInt8(0); // Unknown + outapp->WriteUInt8(emu->gm); + outapp->WriteUInt32(emu->guild_id); + outapp->WriteUInt8(0); // Unknown - observed 1 in a live packet. + outapp->WriteUInt32(0); // Unknown - observed 1 in a live packet. + outapp->WriteUInt8(0); // Unknown - observed 1 in a live packet. + outapp->WriteUInt32(0); // Unknown + + outapp->WriteUInt64(emu->exp); + outapp->WriteUInt8(0); // Unknown + + outapp->WriteUInt32(emu->platinum_bank); + outapp->WriteUInt32(emu->gold_bank); + outapp->WriteUInt32(emu->silver_bank); + outapp->WriteUInt32(emu->copper_bank); + + // Commenting out for RoF Test + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + + outapp->WriteUInt32(42); // The meaning of life ? + + for (uint32 r = 0; r < 42; r++) + { + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + } + + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + + outapp->WriteUInt32(emu->career_tribute_points); + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(emu->tribute_points); + outapp->WriteUInt32(0); // Unknown + + outapp->WriteUInt8(0); // Unknown + outapp->WriteUInt8(0); // Unknown + + outapp->WriteUInt32(EmuConstants::TRIBUTE_SIZE); + + for (uint32 r = 0; r < EmuConstants::TRIBUTE_SIZE; r++) + { + outapp->WriteUInt32(emu->tributes[r].tribute); + outapp->WriteUInt32(emu->tributes[r].tier); + } + + outapp->WriteUInt32(10); // Guild Tribute Count ? + + for (uint32 r = 0; r < 10; r++) + { + outapp->WriteUInt32(0xffffffff); + outapp->WriteUInt32(0); + } + + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + + /* + + // Begin RoF2 Test + for (uint32 r = 0; r < 1000; r++) + outapp->WriteUInt8(0); // Unknown + // End RoF2 Test + + // Block of 121 unknown bytes + for (uint32 r = 0; r < 121; r++) + outapp->WriteUInt8(0); // Unknown + + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(emu->currentRadCrystals); + outapp->WriteUInt32(emu->careerRadCrystals); + outapp->WriteUInt32(emu->currentEbonCrystals); + outapp->WriteUInt32(emu->careerEbonCrystals); + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + + // Unknown String ? + outapp->WriteUInt32(64); // Unknown + for (uint32 r = 0; r < 64; r++) + outapp->WriteUInt8(0); // Unknown + + outapp->WriteUInt8(0); // Unknown + outapp->WriteUInt8(0); // Unknown + outapp->WriteUInt8(0); // Unknown + + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + + outapp->WriteUInt8(0); // Unknown + outapp->WriteUInt8(0); // Unknown + outapp->WriteUInt8(0); // Unknown + + outapp->WriteUInt32(0); // Unknown + + outapp->WriteUInt8(0); // Unknown + outapp->WriteUInt8(0); // Unknown + outapp->WriteUInt8(0); // Unknown + + outapp->WriteUInt32(0); // Unknown + + outapp->WriteUInt8(0); // Unknown + + outapp->WriteUInt32(0); // Unknown + + // Unknown String ? + outapp->WriteUInt32(64); // Unknown + for (uint32 r = 0; r < 64; r++) + outapp->WriteUInt8(0); // Unknown + + // Unknown String ? + outapp->WriteUInt32(64); // Unknown + for (uint32 r = 0; r < 64; r++) + outapp->WriteUInt8(0); // Unknown + + outapp->WriteUInt32(0); // Unknown + + // Block of 320 unknown bytes + for (uint32 r = 0; r < 320; r++) + outapp->WriteUInt8(0); // Unknown + + // Block of 343 unknown bytes + for (uint32 r = 0; r < 343; r++) + outapp->WriteUInt8(0); // Unknown + + outapp->WriteUInt32(0); // Unknown + + outapp->WriteUInt8(emu->leadAAActive); + + outapp->WriteUInt32(6); // Count ... of LDoN stats ? + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(emu->ldon_points_guk); + outapp->WriteUInt32(emu->ldon_points_mir); + outapp->WriteUInt32(emu->ldon_points_mmc); + outapp->WriteUInt32(emu->ldon_points_ruj); + outapp->WriteUInt32(emu->ldon_points_tak); + + outapp->WriteUInt32(emu->ldon_points_available); + + outapp->WriteDouble(emu->group_leadership_exp); + outapp->WriteDouble(emu->raid_leadership_exp); + + outapp->WriteUInt32(emu->group_leadership_points); + outapp->WriteUInt32(emu->raid_leadership_points); + + outapp->WriteUInt32(64); // Group of 64 int32s follow Group/Raid Leadership abilities ? + + for (uint32 r = 0; r < MAX_LEADERSHIP_AA_ARRAY; r++) + outapp->WriteUInt32(emu->leader_abilities.ranks[r]); + + for (uint32 r = 0; r < 64 - MAX_LEADERSHIP_AA_ARRAY; r++) + outapp->WriteUInt32(0); // Unused/unsupported Leadership abilities + + outapp->WriteUInt32(emu->air_remaining); // ? + + // PVP Stats + + outapp->WriteUInt32(emu->PVPKills); + outapp->WriteUInt32(emu->PVPDeaths); + outapp->WriteUInt32(emu->PVPCurrentPoints); + outapp->WriteUInt32(emu->PVPCareerPoints); + outapp->WriteUInt32(emu->PVPBestKillStreak); + outapp->WriteUInt32(emu->PVPWorstDeathStreak); + outapp->WriteUInt32(emu->PVPCurrentKillStreak); + + // Last PVP Kill + + outapp->WriteString(emu->PVPLastKill.Name); + outapp->WriteUInt32(emu->PVPLastKill.Level); + outapp->WriteUInt32(emu->PVPLastKill.Race); + outapp->WriteUInt32(emu->PVPLastKill.Class); + outapp->WriteUInt32(emu->PVPLastKill.Zone); + outapp->WriteUInt32(emu->PVPLastKill.Time); + outapp->WriteUInt32(emu->PVPLastKill.Points); + + // Last PVP Death + + outapp->WriteString(emu->PVPLastDeath.Name); + outapp->WriteUInt32(emu->PVPLastDeath.Level); + outapp->WriteUInt32(emu->PVPLastDeath.Race); + outapp->WriteUInt32(emu->PVPLastDeath.Class); + outapp->WriteUInt32(emu->PVPLastDeath.Zone); + outapp->WriteUInt32(emu->PVPLastDeath.Time); + outapp->WriteUInt32(emu->PVPLastDeath.Points); + + outapp->WriteUInt32(emu->PVPNumberOfKillsInLast24Hours); + + // Last 50 Kills + outapp->WriteUInt32(50); + for (uint32 r = 0; r < 50; ++r) + { + outapp->WriteString(emu->PVPRecentKills[r].Name); + outapp->WriteUInt32(emu->PVPRecentKills[r].Level); + outapp->WriteUInt32(emu->PVPRecentKills[r].Race); + outapp->WriteUInt32(emu->PVPRecentKills[r].Class); + outapp->WriteUInt32(emu->PVPRecentKills[r].Zone); + outapp->WriteUInt32(emu->PVPRecentKills[r].Time); + outapp->WriteUInt32(emu->PVPRecentKills[r].Points); + } + + outapp->WriteUInt32(emu->expAA); + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + + */ + + outapp->WriteUInt8(emu->groupAutoconsent); + outapp->WriteUInt8(emu->raidAutoconsent); + outapp->WriteUInt8(emu->guildAutoconsent); + + outapp->WriteUInt8(0); // Unknown + + outapp->WriteUInt32(emu->level); // Level3 ? + + outapp->WriteUInt8(emu->showhelm); + + outapp->WriteUInt32(emu->RestTimer); + + outapp->WriteUInt32(1024); // Unknown Count + + // Block of 1024 unknown bytes + outapp->WriteUInt8(31); // Unknown + + for (uint32 r = 0; r < 1023; r++) + outapp->WriteUInt8(0); // Unknown + + outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(0); // Unknown + + // Think we need 1 byte of padding at the end + + outapp->WriteUInt8(0); // Unknown + + _log(NET__STRUCTS, "Player Profile Packet is %i bytes", outapp->GetWritePosition()); + + unsigned char *NewBuffer = new unsigned char[outapp->GetWritePosition()]; + memcpy(NewBuffer, outapp->pBuffer, outapp->GetWritePosition()); + safe_delete_array(outapp->pBuffer); + outapp->pBuffer = NewBuffer; + outapp->size = outapp->GetWritePosition(); + outapp->SetWritePosition(4); + outapp->WriteUInt32(outapp->size - 9); + + CRC32::SetEQChecksum(outapp->pBuffer, outapp->size - 1, 8); + //_hex(NET__ERROR, outapp->pBuffer, outapp->size); + + dest->FastQueuePacket(&outapp, ack_req); + delete in; + return; + } + + ENCODE(OP_RaidJoin) + { + EQApplicationPacket *inapp = *p; + unsigned char * __emu_buffer = inapp->pBuffer; + RaidCreate_Struct *raid_create = (RaidCreate_Struct*)__emu_buffer; + + EQApplicationPacket *outapp_create = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct)); + structs::RaidGeneral_Struct *general = (structs::RaidGeneral_Struct*)outapp_create->pBuffer; + + general->action = 8; + general->parameter = 1; + strn0cpy(general->leader_name, raid_create->leader_name, 64); + strn0cpy(general->player_name, raid_create->leader_name, 64); + + dest->FastQueuePacket(&outapp_create); + delete[] __emu_buffer; + } + + ENCODE(OP_RaidUpdate) + { + EQApplicationPacket *inapp = *p; + *p = nullptr; + unsigned char * __emu_buffer = inapp->pBuffer; + RaidGeneral_Struct *raid_gen = (RaidGeneral_Struct*)__emu_buffer; + + if (raid_gen->action == 0) // raid add has longer length than other raid updates + { + RaidAddMember_Struct* in_add_member = (RaidAddMember_Struct*)__emu_buffer; + + EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidAddMember_Struct)); + structs::RaidAddMember_Struct *add_member = (structs::RaidAddMember_Struct*)outapp->pBuffer; + + add_member->raidGen.action = in_add_member->raidGen.action; + add_member->raidGen.parameter = in_add_member->raidGen.parameter; + strn0cpy(add_member->raidGen.leader_name, in_add_member->raidGen.leader_name, 64); + strn0cpy(add_member->raidGen.player_name, in_add_member->raidGen.player_name, 64); + add_member->_class = in_add_member->_class; + add_member->level = in_add_member->level; + add_member->isGroupLeader = in_add_member->isGroupLeader; + add_member->flags[0] = in_add_member->flags[0]; + add_member->flags[1] = in_add_member->flags[1]; + add_member->flags[2] = in_add_member->flags[2]; + add_member->flags[3] = in_add_member->flags[3]; + add_member->flags[4] = in_add_member->flags[4]; + dest->FastQueuePacket(&outapp); + } + else if (raid_gen->action == 35) + { + RaidMOTD_Struct *inmotd = (RaidMOTD_Struct *)__emu_buffer; + EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidMOTD_Struct) + strlen(inmotd->motd) + 1); + structs::RaidMOTD_Struct *outmotd = (structs::RaidMOTD_Struct *)outapp->pBuffer; + + outmotd->general.action = inmotd->general.action; + strn0cpy(outmotd->general.player_name, inmotd->general.player_name, 64); + strn0cpy(outmotd->motd, inmotd->motd, strlen(inmotd->motd) + 1); + dest->FastQueuePacket(&outapp); + } + else if (raid_gen->action == 14 || raid_gen->action == 30) + { + RaidLeadershipUpdate_Struct *inlaa = (RaidLeadershipUpdate_Struct *)__emu_buffer; + EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct)); + structs::RaidLeadershipUpdate_Struct *outlaa = (structs::RaidLeadershipUpdate_Struct *)outapp->pBuffer; + + outlaa->action = inlaa->action; + strn0cpy(outlaa->player_name, inlaa->player_name, 64); + strn0cpy(outlaa->leader_name, inlaa->leader_name, 64); + memcpy(&outlaa->raid, &inlaa->raid, sizeof(RaidLeadershipAA_Struct)); + dest->FastQueuePacket(&outapp); + } + else + { + RaidGeneral_Struct* in_raid_general = (RaidGeneral_Struct*)__emu_buffer; + + EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct)); + structs::RaidGeneral_Struct *raid_general = (structs::RaidGeneral_Struct*)outapp->pBuffer; + strn0cpy(raid_general->leader_name, in_raid_general->leader_name, 64); + strn0cpy(raid_general->player_name, in_raid_general->player_name, 64); + raid_general->action = in_raid_general->action; + raid_general->parameter = in_raid_general->parameter; + dest->FastQueuePacket(&outapp); + } + + delete[] __emu_buffer; + } + + ENCODE(OP_ReadBook) + { + ENCODE_LENGTH_ATLEAST(BookText_Struct); + SETUP_DIRECT_ENCODE(BookText_Struct, structs::BookRequest_Struct); + + if (emu->window == 0xFF) + eq->window = 0xFFFFFFFF; + else + eq->window = emu->window; + OUT(type); + OUT(invslot); + strn0cpy(eq->txtfile, emu->booktext, sizeof(eq->txtfile)); + + FINISH_ENCODE(); + } + + ENCODE(OP_RecipeAutoCombine) + { + ENCODE_LENGTH_EXACT(RecipeAutoCombine_Struct); + SETUP_DIRECT_ENCODE(RecipeAutoCombine_Struct, structs::RecipeAutoCombine_Struct); + + OUT(object_type); + OUT(some_id); + eq->container_slot = ServerToRoF2Slot(emu->unknown1); + structs::ItemSlotStruct RoF2Slot; + RoF2Slot.SlotType = 8; // Observed + RoF2Slot.Unknown02 = 0; + RoF2Slot.MainSlot = 0xffff; + RoF2Slot.SubSlot = 0xffff; + RoF2Slot.AugSlot = 0xffff; + RoF2Slot.Unknown01 = 0; + eq->unknown_slot = RoF2Slot; + OUT(recipe_id); + OUT(reply_code); + + FINISH_ENCODE(); + } + + ENCODE(OP_RemoveBlockedBuffs) { ENCODE_FORWARD(OP_BlockedBuffs); } + + ENCODE(OP_RequestClientZoneChange) + { + ENCODE_LENGTH_EXACT(RequestClientZoneChange_Struct); + SETUP_DIRECT_ENCODE(RequestClientZoneChange_Struct, structs::RequestClientZoneChange_Struct); + + OUT(zone_id); + OUT(instance_id); + OUT(y); + OUT(x); + OUT(z); + OUT(heading); + eq->type = 0x0b; + eq->unknown004 = 0xffffffff; + eq->unknown172 = 0x0168b500; + + FINISH_ENCODE(); + } + + ENCODE(OP_RespondAA) + { + SETUP_DIRECT_ENCODE(AATable_Struct, structs::AATable_Struct); + + eq->aa_spent = emu->aa_spent; + // These fields may need to be correctly populated at some point + eq->aapoints_assigned = emu->aa_spent + 1; + eq->aa_spent_general = 0; + eq->aa_spent_archetype = 0; + eq->aa_spent_class = 0; + eq->aa_spent_special = 0; + + for (uint32 i = 0; i < MAX_PP_AA_ARRAY; ++i) + { + eq->aa_list[i].aa_skill = emu->aa_list[i].aa_skill; + eq->aa_list[i].aa_value = emu->aa_list[i].aa_value; + eq->aa_list[i].unknown08 = emu->aa_list[i].unknown08; + } + + FINISH_ENCODE(); + } + + ENCODE(OP_RezzRequest) + { + SETUP_DIRECT_ENCODE(Resurrect_Struct, structs::Resurrect_Struct); + + OUT(zone_id); + OUT(instance_id); + OUT(y); + OUT(x); + OUT(z); + OUT_str(your_name); + OUT_str(rezzer_name); + OUT(spellid); + OUT_str(corpse_name); + OUT(action); + + FINISH_ENCODE(); + } + + ENCODE(OP_SendAATable) + { + ENCODE_LENGTH_ATLEAST(SendAA_Struct); + SETUP_VAR_ENCODE(SendAA_Struct); + ALLOC_VAR_ENCODE(structs::SendAA_Struct, sizeof(structs::SendAA_Struct) + emu->total_abilities*sizeof(structs::AA_Ability)); + + // Check clientver field to verify this AA should be sent for SoF + // clientver 1 is for all clients and 5 is for Live + if (emu->clientver <= 5) + { + OUT(id); + eq->unknown004 = 1; + //eq->hotkey_sid = (emu->hotkey_sid==4294967295UL)?0:(emu->id - emu->current_level + 1); + //eq->hotkey_sid2 = (emu->hotkey_sid2==4294967295UL)?0:(emu->id - emu->current_level + 1); + //eq->title_sid = emu->id - emu->current_level + 1; + //eq->desc_sid = emu->id - emu->current_level + 1; + eq->hotkey_sid = (emu->hotkey_sid == 4294967295UL) ? -1 : (emu->sof_next_skill); + eq->hotkey_sid2 = (emu->hotkey_sid2 == 4294967295UL) ? -1 : (emu->sof_next_skill); + eq->title_sid = emu->sof_next_skill; + eq->desc_sid = emu->sof_next_skill; + OUT(class_type); + OUT(cost); + OUT(seq); + OUT(current_level); + eq->unknown037 = 1; // Introduced during HoT + OUT(prereq_skill); + eq->unknown045 = 1; // New Mar 21 2012 - Seen 1 + OUT(prereq_minpoints); + eq->type = emu->sof_type; + OUT(spellid); + eq->unknown057 = 1; // Introduced during HoT + OUT(spell_type); + OUT(spell_refresh); + OUT(classes); + OUT(berserker); + //eq->max_level = emu->sof_max_level; + OUT(max_level); + OUT(last_id); + OUT(next_id); + OUT(cost2); + eq->aa_expansion = emu->aa_expansion; + eq->special_category = emu->special_category; + OUT(total_abilities); + unsigned int r; + for (r = 0; r < emu->total_abilities; r++) { + OUT(abilities[r].skill_id); + OUT(abilities[r].base1); + OUT(abilities[r].base2); + OUT(abilities[r].slot); + } + } + + _hex(NET__ERROR, eq, sizeof(structs::SendAA_Struct) + emu->total_abilities*sizeof(structs::AA_Ability)); + + FINISH_ENCODE(); + } + + ENCODE(OP_SendCharInfo) + { + ENCODE_LENGTH_EXACT(CharacterSelect_Struct); + SETUP_VAR_ENCODE(CharacterSelect_Struct); + + //EQApplicationPacket *packet = *p; + //const CharacterSelect_Struct *emu = (CharacterSelect_Struct *) packet->pBuffer; + + int char_count; + int namelen = 0; + for (char_count = 0; char_count < 10; char_count++) { + if (emu->name[char_count][0] == '\0') + break; + if (strcmp(emu->name[char_count], "") == 0) + break; + namelen += strlen(emu->name[char_count]); + } + + int total_length = sizeof(structs::CharacterSelect_Struct) + + char_count * sizeof(structs::CharacterSelectEntry_Struct) + + namelen; + + ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, total_length); + + //unsigned char *eq_buffer = new unsigned char[total_length]; + //structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer; + + eq->char_count = char_count; + //eq->total_chars = 10; + + unsigned char *bufptr = (unsigned char *)eq->entries; + int r; + for (r = 0; r < char_count; r++) { + { //pre-name section... + structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr; + memcpy(eq2->name, emu->name[r], strlen(emu->name[r]) + 1); + } + //adjust for name. + bufptr += strlen(emu->name[r]); + { //post-name section... + structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr; + eq2->class_ = emu->class_[r]; + eq2->race = emu->race[r]; + eq2->level = emu->level[r]; + eq2->class_2 = emu->class_[r]; + eq2->race2 = emu->race[r]; + eq2->zone = emu->zone[r]; + eq2->instance = 0; + eq2->gender = emu->gender[r]; + eq2->face = emu->face[r]; + int k; + for (k = 0; k < _MaterialCount; k++) { + eq2->equip[k].equip0 = emu->equip[r][k]; + eq2->equip[k].equip1 = 0; + eq2->equip[k].equip2 = 0; + eq2->equip[k].itemid = 0; + eq2->equip[k].equip3 = emu->equip[r][k]; + eq2->equip[k].color.color = emu->cs_colors[r][k].color; + } + eq2->u15 = 0xff; + eq2->u19 = 0xFF; + eq2->drakkin_tattoo = emu->drakkin_tattoo[r]; + eq2->drakkin_details = emu->drakkin_details[r]; + eq2->deity = emu->deity[r]; + eq2->primary = emu->primary[r]; + eq2->secondary = emu->secondary[r]; + eq2->haircolor = emu->haircolor[r]; + eq2->beardcolor = emu->beardcolor[r]; + eq2->eyecolor1 = emu->eyecolor1[r]; + eq2->eyecolor2 = emu->eyecolor2[r]; + eq2->hairstyle = emu->hairstyle[r]; + eq2->beard = emu->beard[r]; + eq2->char_enabled = 1; + eq2->tutorial = emu->tutorial[r]; + eq2->drakkin_heritage = emu->drakkin_heritage[r]; + eq2->unknown1 = 0; + eq2->gohome = emu->gohome[r]; + eq2->LastLogin = 1212696584; + eq2->unknown2 = 0; + } + bufptr += sizeof(structs::CharacterSelectEntry_Struct); + } + + FINISH_ENCODE(); + } + + ENCODE(OP_SendMembership) + { + ENCODE_LENGTH_EXACT(Membership_Struct); + SETUP_DIRECT_ENCODE(Membership_Struct, structs::Membership_Struct); + + eq->membership = emu->membership; + eq->races = emu->races; + eq->classes = emu->classes; + eq->entrysize = 22; + for (int i = 0; i<21; i++) + { + eq->entries[i] = emu->entries[i]; + } + eq->entries[21] = 0; + + FINISH_ENCODE(); + } + + ENCODE(OP_SendZonepoints) + { + SETUP_VAR_ENCODE(ZonePoints); + ALLOC_VAR_ENCODE(structs::ZonePoints, sizeof(structs::ZonePoints) + sizeof(structs::ZonePoint_Entry) * (emu->count + 1)); + + eq->count = emu->count; + for (uint32 i = 0; i < emu->count; ++i) + { + eq->zpe[i].iterator = emu->zpe[i].iterator; + eq->zpe[i].x = emu->zpe[i].x; + eq->zpe[i].y = emu->zpe[i].y; + eq->zpe[i].z = emu->zpe[i].z; + eq->zpe[i].heading = emu->zpe[i].heading; + eq->zpe[i].zoneid = emu->zpe[i].zoneid; + eq->zpe[i].zoneinstance = emu->zpe[i].zoneinstance; + } + + FINISH_ENCODE(); + } + + ENCODE(OP_SetGuildRank) + { + ENCODE_LENGTH_EXACT(GuildSetRank_Struct); + SETUP_DIRECT_ENCODE(GuildSetRank_Struct, structs::GuildSetRank_Struct); + + eq->GuildID = emu->Unknown00; + + /* Translate older ranks to new values */ + switch (emu->Rank) { + case 0: { eq->Rank = 5; break; } // GUILD_MEMBER 0 + case 1: { eq->Rank = 3; break; } // GUILD_OFFICER 1 + case 2: { eq->Rank = 1; break; } // GUILD_LEADER 2 + default: { eq->Rank = emu->Rank; break; } + } + + memcpy(eq->MemberName, emu->MemberName, sizeof(eq->MemberName)); + OUT(Banker); + eq->Unknown76 = 1; + + FINISH_ENCODE(); + } + + ENCODE(OP_ShopPlayerBuy) + { + ENCODE_LENGTH_EXACT(Merchant_Sell_Struct); + SETUP_DIRECT_ENCODE(Merchant_Sell_Struct, structs::Merchant_Sell_Struct); + + OUT(npcid); + OUT(playerid); + OUT(itemslot); + OUT(quantity); + OUT(price); + + FINISH_ENCODE(); + } + + ENCODE(OP_ShopPlayerSell) + { + ENCODE_LENGTH_EXACT(Merchant_Purchase_Struct); + SETUP_DIRECT_ENCODE(Merchant_Purchase_Struct, structs::Merchant_Purchase_Struct); + + OUT(npcid); + eq->itemslot = ServerToRoF2MainInvSlot(emu->itemslot); + //OUT(itemslot); + OUT(quantity); + OUT(price); + + FINISH_ENCODE(); + } + + ENCODE(OP_ShopRequest) + { + ENCODE_LENGTH_EXACT(Merchant_Click_Struct); + SETUP_DIRECT_ENCODE(Merchant_Click_Struct, structs::Merchant_Click_Struct); + + OUT(npcid); + OUT(playerid); + OUT(command); + OUT(rate); + eq->unknown01 = 3; // Not sure what these values do yet, but list won't display without them + eq->unknown02 = 2592000; + + FINISH_ENCODE(); + } + + ENCODE(OP_SkillUpdate) + { + ENCODE_LENGTH_EXACT(SkillUpdate_Struct); + SETUP_DIRECT_ENCODE(SkillUpdate_Struct, structs::SkillUpdate_Struct); + + OUT(skillId); + OUT(value); + eq->unknown08 = 1; // Observed + eq->unknown09 = 80; // Observed + eq->unknown10 = 136; // Observed + eq->unknown11 = 54; // Observed + + FINISH_ENCODE(); + } + + ENCODE(OP_SomeItemPacketMaybe) + { + // This Opcode is not named very well. It is used for the animation of arrows leaving the player's bow + // and flying to the target. + // + + ENCODE_LENGTH_EXACT(Arrow_Struct); + SETUP_DIRECT_ENCODE(Arrow_Struct, structs::Arrow_Struct); + + OUT(src_y); + OUT(src_x); + OUT(src_z); + OUT(velocity); + OUT(launch_angle); + OUT(tilt); + OUT(arc); + OUT(source_id); + OUT(target_id); + OUT(item_id); + + eq->unknown070 = 175; // This needs to be set to something, else we get a 1HS animation instead of ranged. + + OUT(item_type); + OUT(skill); + + strncpy(eq->model_name, emu->model_name, sizeof(eq->model_name)); + + FINISH_ENCODE(); + } + + ENCODE(OP_SpawnAppearance) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + unsigned char *emu_buffer = in->pBuffer; + + SpawnAppearance_Struct *sas = (SpawnAppearance_Struct *)emu_buffer; + + if (sas->type != AT_Size) + { + dest->FastQueuePacket(&in, ack_req); + return; + } + + EQApplicationPacket *outapp = new EQApplicationPacket(OP_ChangeSize, sizeof(ChangeSize_Struct)); + + ChangeSize_Struct *css = (ChangeSize_Struct *)outapp->pBuffer; + + css->EntityID = sas->spawn_id; + css->Size = (float)sas->parameter; + css->Unknown08 = 0; + css->Unknown12 = 1.0f; + + dest->FastQueuePacket(&outapp, ack_req); + delete in; + } + + ENCODE(OP_SpawnDoor) + { + SETUP_VAR_ENCODE(Door_Struct); + int door_count = __packet->size / sizeof(Door_Struct); + int total_length = door_count * sizeof(structs::Door_Struct); + ALLOC_VAR_ENCODE(structs::Door_Struct, total_length); + + int r; + for (r = 0; r < door_count; r++) { + strncpy(eq[r].name, emu[r].name, sizeof(eq[r].name)); + eq[r].xPos = emu[r].xPos; + eq[r].yPos = emu[r].yPos; + eq[r].zPos = emu[r].zPos; + eq[r].heading = emu[r].heading; + eq[r].incline = emu[r].incline; + eq[r].size = emu[r].size; + eq[r].doorId = emu[r].doorId; + eq[r].opentype = emu[r].opentype; + eq[r].state_at_spawn = emu[r].state_at_spawn; + eq[r].invert_state = emu[r].invert_state; + eq[r].door_param = emu[r].door_param; + eq[r].unknown0080 = 0; + eq[r].unknown0081 = 1; // Both must be 1 to allow clicking doors + eq[r].unknown0082 = 0; + eq[r].unknown0083 = 1; // Both must be 1 to allow clicking doors + eq[r].unknown0084 = 0; + eq[r].unknown0085 = 0; + eq[r].unknown0086 = 0; + } + + FINISH_ENCODE(); + } + + ENCODE(OP_Stun) + { + ENCODE_LENGTH_EXACT(Stun_Struct); + SETUP_DIRECT_ENCODE(Stun_Struct, structs::Stun_Struct); + + OUT(duration); + eq->unknown005 = 163; + eq->unknown006 = 67; + + FINISH_ENCODE(); + } + + ENCODE(OP_TargetBuffs) { ENCODE_FORWARD(OP_BuffCreate); } + + ENCODE(OP_TaskDescription) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + EQApplicationPacket *outapp = new EQApplicationPacket(OP_TaskDescription, in->size + 1); + // Set the Write pointer as we don't know what has been done with the packet before we get it. + in->SetReadPosition(0); + // Copy the header + for (int i = 0; i < 5; ++i) + outapp->WriteUInt32(in->ReadUInt32()); + + // Copy Title + while (uint8 c = in->ReadUInt8()) + outapp->WriteUInt8(c); + outapp->WriteUInt8(0); + + outapp->WriteUInt32(in->ReadUInt32()); // Duration + outapp->WriteUInt32(in->ReadUInt32()); // Unknown + uint32 StartTime = in->ReadUInt32(); + outapp->WriteUInt32(time(nullptr) - StartTime); // RoF2 has elapsed time here rather than starttime + + // Copy the rest of the packet verbatim + uint32 BytesLeftToCopy = in->size - in->GetReadPosition(); + memcpy(outapp->pBuffer + outapp->GetWritePosition(), in->pBuffer + in->GetReadPosition(), BytesLeftToCopy); + + delete in; + dest->FastQueuePacket(&outapp, ack_req); + } + + ENCODE(OP_TaskHistoryReply) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + // First we need to calculate the length of the new packet + in->SetReadPosition(4); + uint32 ActivityCount = in->ReadUInt32(); + + uint32 Text1Length = 0; + uint32 Text2Length = 0; + uint32 Text3Length = 0; + + uint32 OutboundPacketSize = 8; + + for (uint32 i = 0; i < ActivityCount; ++i) + { + Text1Length = 0; + Text2Length = 0; + Text3Length = 0; + + in->ReadUInt32(); // Activity type + + // Skip past Text1 + while (in->ReadUInt8()) + ++Text1Length; + + // Skip past Text2 + while (in->ReadUInt8()) + ++Text2Length; + + in->ReadUInt32(); + in->ReadUInt32(); + in->ReadUInt32(); + uint32 ZoneID = in->ReadUInt32(); + in->ReadUInt32(); + + // Skip past Text3 + while (in->ReadUInt8()) + ++Text3Length; + + char ZoneNumber[10]; + + sprintf(ZoneNumber, "%i", ZoneID); + + OutboundPacketSize += (24 + Text1Length + 1 + Text2Length + Text3Length + 1 + 7 + (strlen(ZoneNumber) * 2)); + } + + in->SetReadPosition(0); + + EQApplicationPacket *outapp = new EQApplicationPacket(OP_TaskHistoryReply, OutboundPacketSize); + + outapp->WriteUInt32(in->ReadUInt32()); // Task index + outapp->WriteUInt32(in->ReadUInt32()); // Activity count + + for (uint32 i = 0; i < ActivityCount; ++i) + { + Text1Length = 0; + Text2Length = 0; + Text3Length = 0; + + outapp->WriteUInt32(in->ReadUInt32()); // ActivityType + + // Copy Text1 + while (uint8 c = in->ReadUInt8()) + outapp->WriteUInt8(c); + + outapp->WriteUInt8(0); // Text1 has a null terminator + + uint32 CurrentPosition = in->GetReadPosition(); + + // Determine Length of Text2 + while (in->ReadUInt8()) + ++Text2Length; + + outapp->WriteUInt32(Text2Length); + + in->SetReadPosition(CurrentPosition); + + // Copy Text2 + while (uint8 c = in->ReadUInt8()) + outapp->WriteUInt8(c); + + outapp->WriteUInt32(in->ReadUInt32()); // Goalcount + in->ReadUInt32(); + in->ReadUInt32(); + uint32 ZoneID = in->ReadUInt32(); + in->ReadUInt32(); + + char ZoneNumber[10]; + + sprintf(ZoneNumber, "%i", ZoneID); + + outapp->WriteUInt32(2); + outapp->WriteUInt8(0x2d); // "-" + outapp->WriteUInt8(0x31); // "1" + + outapp->WriteUInt32(2); + outapp->WriteUInt8(0x2d); // "-" + outapp->WriteUInt8(0x31); // "1" + outapp->WriteString(ZoneNumber); + + outapp->WriteUInt32(0); + + // Copy Tex3t + while (uint8 c = in->ReadUInt8()) + outapp->WriteUInt8(c); + + outapp->WriteUInt8(0); // Text3 has a null terminator + + outapp->WriteUInt8(0x31); // "1" + outapp->WriteString(ZoneNumber); + } + + delete in; + dest->FastQueuePacket(&outapp, ack_req); + } + + ENCODE(OP_Track) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + unsigned char *__emu_buffer = in->pBuffer; + Track_Struct *emu = (Track_Struct *)__emu_buffer; + + int EntryCount = in->size / sizeof(Track_Struct); + + if (EntryCount == 0 || ((in->size % sizeof(Track_Struct))) != 0) + { + _log(NET__STRUCTS, "Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Track_Struct)); + delete in; + return; + } + + int PacketSize = 2; + + for (int i = 0; i < EntryCount; ++i, ++emu) + PacketSize += (12 + strlen(emu->name)); + + emu = (Track_Struct *)__emu_buffer; + + in->size = PacketSize; + in->pBuffer = new unsigned char[in->size]; + + char *Buffer = (char *)in->pBuffer; + + VARSTRUCT_ENCODE_TYPE(uint16, Buffer, EntryCount); + + for (int i = 0; i < EntryCount; ++i, ++emu) + { + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->entityid); + VARSTRUCT_ENCODE_TYPE(float, Buffer, emu->distance); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->level); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->NPC); + VARSTRUCT_ENCODE_STRING(Buffer, emu->name); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->GroupMember); + } + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); + } + + ENCODE(OP_Trader) + { + if ((*p)->size == sizeof(ClickTrader_Struct)) + { + ENCODE_LENGTH_EXACT(ClickTrader_Struct); + SETUP_DIRECT_ENCODE(ClickTrader_Struct, structs::ClickTrader_Struct); + + eq->Code = emu->Code; + // Live actually has 200 items now, but 80 is the most our internal struct supports + for (uint32 i = 0; i < 200; i++) + { + strncpy(eq->items[i].SerialNumber, "0000000000000000", sizeof(eq->items[i].SerialNumber)); + eq->items[i].Unknown18 = 0; + if (i < 80) { + eq->ItemCost[i] = emu->ItemCost[i]; + } + else { + eq->ItemCost[i] = 0; + } + } + + FINISH_ENCODE(); + } + else if ((*p)->size == sizeof(Trader_ShowItems_Struct)) + { + ENCODE_LENGTH_EXACT(Trader_ShowItems_Struct); + SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct); + + eq->Code = emu->Code; + strncpy(eq->SerialNumber, "0000000000000000", sizeof(eq->SerialNumber)); + eq->TraderID = emu->TraderID; + eq->Stacksize = 0; + eq->Price = 0; + + FINISH_ENCODE(); + } + else if ((*p)->size == sizeof(TraderStatus_Struct)) + { + ENCODE_LENGTH_EXACT(TraderStatus_Struct); + SETUP_DIRECT_ENCODE(TraderStatus_Struct, structs::TraderStatus_Struct); + + eq->Code = emu->Code; + + FINISH_ENCODE(); + } + else if ((*p)->size == sizeof(TraderBuy_Struct)) + { + ENCODE_FORWARD(OP_TraderBuy); + } + } + + ENCODE(OP_TraderBuy) + { + ENCODE_LENGTH_EXACT(TraderBuy_Struct); + SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct); + + OUT(Action); + OUT(Price); + OUT(TraderID); + memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName)); + OUT(ItemID); + OUT(Quantity); + OUT(AlreadySold); + + FINISH_ENCODE(); + } + + ENCODE(OP_TributeInfo) + { + ENCODE_LENGTH_ATLEAST(TributeAbility_Struct); + SETUP_VAR_ENCODE(TributeAbility_Struct); + ALLOC_VAR_ENCODE(structs::TributeAbility_Struct, sizeof(structs::TributeAbility_Struct) + strlen(emu->name) + 1); + + OUT(tribute_id); + OUT(tier_count); + + for (uint32 i = 0; i < MAX_TRIBUTE_TIERS; ++i) + { + eq->tiers[i].level = emu->tiers[i].level; + eq->tiers[i].tribute_item_id = emu->tiers[i].tribute_item_id; + eq->tiers[i].cost = emu->tiers[i].cost; + } + + eq->unknown128 = 0; + + strcpy(eq->name, emu->name); + + FINISH_ENCODE(); + } + + ENCODE(OP_TributeItem) + { + ENCODE_LENGTH_EXACT(TributeItem_Struct); + SETUP_DIRECT_ENCODE(TributeItem_Struct, structs::TributeItem_Struct); + + eq->slot = ServerToRoF2Slot(emu->slot); + OUT(quantity); + OUT(tribute_master_id); + OUT(tribute_points); + + FINISH_ENCODE(); + } + + ENCODE(OP_VetRewardsAvaliable) + { + EQApplicationPacket *inapp = *p; + unsigned char * __emu_buffer = inapp->pBuffer; + + uint32 count = ((*p)->Size() / sizeof(InternalVeteranReward)); + *p = nullptr; + + EQApplicationPacket *outapp_create = new EQApplicationPacket(OP_VetRewardsAvaliable, (sizeof(structs::VeteranReward)*count)); + uchar *old_data = __emu_buffer; + uchar *data = outapp_create->pBuffer; + for (unsigned int i = 0; i < count; ++i) + { + structs::VeteranReward *vr = (structs::VeteranReward*)data; + InternalVeteranReward *ivr = (InternalVeteranReward*)old_data; + + vr->claim_count = ivr->claim_count; + vr->claim_id = ivr->claim_id; + vr->number_available = ivr->number_available; + for (int x = 0; x < 8; ++x) + { + vr->items[x].item_id = ivr->items[x].item_id; + strncpy(vr->items[x].item_name, ivr->items[x].item_name, sizeof(vr->items[x].item_name)); + vr->items[x].charges = ivr->items[x].charges; + } + + old_data += sizeof(InternalVeteranReward); + data += sizeof(structs::VeteranReward); + } + + dest->FastQueuePacket(&outapp_create); + delete inapp; + } + + ENCODE(OP_WearChange) + { + ENCODE_LENGTH_EXACT(WearChange_Struct); + SETUP_DIRECT_ENCODE(WearChange_Struct, structs::WearChange_Struct); + + OUT(spawn_id); + OUT(material); + OUT(unknown06); + OUT(elite_material); + OUT(hero_forge_model); + OUT(unknown18); + OUT(color.color); + OUT(wear_slot_id); + + FINISH_ENCODE(); + } + + ENCODE(OP_WhoAllResponse) + { + EQApplicationPacket *in = *p; + *p = nullptr; + + char *InBuffer = (char *)in->pBuffer; + + WhoAllReturnStruct *wars = (WhoAllReturnStruct*)InBuffer; + + int Count = wars->playercount; + + EQApplicationPacket *outapp = new EQApplicationPacket(OP_WhoAllResponse, in->size + (Count * 4)); + + char *OutBuffer = (char *)outapp->pBuffer; + + // The struct fields were moved around a bit, so adjust values before copying + wars->unknown44[0] = Count; + wars->unknown52 = 0; + + memcpy(OutBuffer, InBuffer, sizeof(WhoAllReturnStruct)); + + OutBuffer += sizeof(WhoAllReturnStruct); + InBuffer += sizeof(WhoAllReturnStruct); + + for (int i = 0; i < Count; ++i) + { + uint32 x; + + x = VARSTRUCT_DECODE_TYPE(uint32, InBuffer); + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, x); + + InBuffer += 4; + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0xffffffff); + + char Name[64]; + + VARSTRUCT_DECODE_STRING(Name, InBuffer); // Char Name + VARSTRUCT_ENCODE_STRING(OutBuffer, Name); + + x = VARSTRUCT_DECODE_TYPE(uint32, InBuffer); + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, x); + + VARSTRUCT_DECODE_STRING(Name, InBuffer); // Guild Name + VARSTRUCT_ENCODE_STRING(OutBuffer, Name); + + for (int j = 0; j < 7; ++j) + { + x = VARSTRUCT_DECODE_TYPE(uint32, InBuffer); + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, x); + } + + VARSTRUCT_DECODE_STRING(Name, InBuffer); // Account + VARSTRUCT_ENCODE_STRING(OutBuffer, Name); + + x = VARSTRUCT_DECODE_TYPE(uint32, InBuffer); + VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, x); + } + + //_hex(NET__ERROR, outapp->pBuffer, outapp->size); + dest->FastQueuePacket(&outapp); + delete in; + } + + ENCODE(OP_ZoneChange) + { + ENCODE_LENGTH_EXACT(ZoneChange_Struct); + SETUP_DIRECT_ENCODE(ZoneChange_Struct, structs::ZoneChange_Struct); + + memcpy(eq->char_name, emu->char_name, sizeof(emu->char_name)); + OUT(zoneID); + OUT(instanceID); + OUT(y); + OUT(x); + OUT(z) + OUT(zone_reason); + OUT(success); + + FINISH_ENCODE(); + } + + ENCODE(OP_ZoneEntry) { ENCODE_FORWARD(OP_ZoneSpawns); } + + ENCODE(OP_ZonePlayerToBind) + { + ENCODE_LENGTH_ATLEAST(ZonePlayerToBind_Struct); + + ZonePlayerToBind_Struct *zps = (ZonePlayerToBind_Struct*)(*p)->pBuffer; + + std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); + + unsigned char *buffer1 = new unsigned char[sizeof(structs::ZonePlayerToBindHeader_Struct) + strlen(zps->zone_name)]; + structs::ZonePlayerToBindHeader_Struct *zph = (structs::ZonePlayerToBindHeader_Struct*)buffer1; + unsigned char *buffer2 = new unsigned char[sizeof(structs::ZonePlayerToBindFooter_Struct)]; + structs::ZonePlayerToBindFooter_Struct *zpf = (structs::ZonePlayerToBindFooter_Struct*)buffer2; + + zph->x = zps->x; + zph->y = zps->y; + zph->z = zps->z; + zph->heading = zps->heading; + zph->bind_zone_id = 0; + zph->bind_instance_id = zps->bind_instance_id; + strncpy(zph->zone_name, zps->zone_name, sizeof(zph->zone_name)); + + zpf->unknown021 = 1; + zpf->unknown022 = 0; + zpf->unknown023 = 0; + zpf->unknown024 = 0; + + ss.write((const char*)buffer1, (sizeof(structs::ZonePlayerToBindHeader_Struct) + strlen(zps->zone_name))); + ss.write((const char*)buffer2, sizeof(structs::ZonePlayerToBindFooter_Struct)); + + delete[] buffer1; + delete[] buffer2; + delete[](*p)->pBuffer; + + (*p)->pBuffer = new unsigned char[ss.str().size()]; + (*p)->size = ss.str().size(); + + memcpy((*p)->pBuffer, ss.str().c_str(), ss.str().size()); + dest->FastQueuePacket(&(*p)); + } + + ENCODE(OP_ZoneServerInfo) + { + SETUP_DIRECT_ENCODE(ZoneServerInfo_Struct, ZoneServerInfo_Struct); + + OUT_str(ip); + OUT(port); + + FINISH_ENCODE(); + } + + ENCODE(OP_ZoneSpawns) + { + //consume the packet + EQApplicationPacket *in = *p; + *p = nullptr; + + //store away the emu struct + unsigned char *__emu_buffer = in->pBuffer; + Spawn_Struct *emu = (Spawn_Struct *)__emu_buffer; + + //determine and verify length + int entrycount = in->size / sizeof(Spawn_Struct); + if (entrycount == 0 || (in->size % sizeof(Spawn_Struct)) != 0) { + _log(NET__STRUCTS, "Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Spawn_Struct)); + delete in; + return; + } + + //_log(NET__STRUCTS, "Spawn name is [%s]", emu->name); + + emu = (Spawn_Struct *)__emu_buffer; + + //_log(NET__STRUCTS, "Spawn packet size is %i, entries = %i", in->size, entrycount); + + char *Buffer = (char *)in->pBuffer, *BufferStart; + + int r; + int k; + for (r = 0; r < entrycount; r++, emu++) { + + int PacketSize = 206; + + PacketSize += strlen(emu->name); + PacketSize += strlen(emu->lastName); + + emu->title[0] = 0; + emu->suffix[0] = 0; + + if (strlen(emu->title)) + PacketSize += strlen(emu->title) + 1; + + if (strlen(emu->suffix)) + PacketSize += strlen(emu->suffix) + 1; + + bool ShowName = 1; + if (emu->bodytype >= 66) + { + emu->race = 127; + emu->bodytype = 11; + emu->gender = 0; + ShowName = 0; + } + + float SpawnSize = emu->size; + if (!((emu->NPC == 0) || (emu->race <= 12) || (emu->race == 128) || (emu->race == 130) || (emu->race == 330) || (emu->race == 522))) + { + PacketSize += 60; + + if (emu->size == 0) + { + emu->size = 6; + SpawnSize = 6; + } + } + else + PacketSize += 216; + + if (SpawnSize == 0) + { + SpawnSize = 3; + } + + EQApplicationPacket *outapp = new EQApplicationPacket(OP_ZoneEntry, PacketSize); + Buffer = (char *)outapp->pBuffer; + BufferStart = Buffer; + VARSTRUCT_ENCODE_STRING(Buffer, emu->name); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->spawnId); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->level); + VARSTRUCT_ENCODE_TYPE(float, Buffer, SpawnSize - 0.7); // Eye Height? + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->NPC); + + structs::Spawn_Struct_Bitfields *Bitfields = (structs::Spawn_Struct_Bitfields*)Buffer; + + Bitfields->gender = emu->gender; + Bitfields->ispet = emu->is_pet; + Bitfields->afk = emu->afk; + Bitfields->anon = emu->anon; + Bitfields->gm = emu->gm; + Bitfields->sneak = 0; + Bitfields->lfg = emu->lfg; + Bitfields->invis = emu->invis; + Bitfields->linkdead = 0; + Bitfields->showhelm = emu->showhelm; + Bitfields->trader = 0; + Bitfields->targetable = 1; + Bitfields->targetable_with_hotkey = (emu->IsMercenary ? 0 : 1); + Bitfields->showname = ShowName; + + // Not currently found + // Bitfields->statue = 0; + // Bitfields->buyer = 0; + + Buffer += sizeof(structs::Spawn_Struct_Bitfields); + + uint8 OtherData = 0; + + if (strlen(emu->title)) + OtherData = OtherData | 16; + + if (strlen(emu->suffix)) + OtherData = OtherData | 32; + + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, OtherData); + + VARSTRUCT_ENCODE_TYPE(float, Buffer, -1); // unknown3 + VARSTRUCT_ENCODE_TYPE(float, Buffer, 0); // unknown4 + + // Setting this next field to zero will cause a crash. Looking at ShowEQ, if it is zero, the bodytype field is not + // present. Will sort that out later. + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 1); // This is a properties count field + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->bodytype); + + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->curHp); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->haircolor); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->beardcolor); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->eyecolor1); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->eyecolor2); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->hairstyle); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->beard); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->drakkin_heritage); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->drakkin_tattoo); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->drakkin_details); + + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->equip_chest2); // unknown8 + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown9 + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown10 + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->helm); // unknown11 + + VARSTRUCT_ENCODE_TYPE(float, Buffer, emu->size); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->face); + VARSTRUCT_ENCODE_TYPE(float, Buffer, emu->walkspeed); + VARSTRUCT_ENCODE_TYPE(float, Buffer, emu->runspeed); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->race); + + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // ShowEQ calls this 'Holding' + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->deity); + if (emu->NPC) + { + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xFFFFFFFF); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0x00000000); + } + else + { + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->guildID); + + /* Translate older ranks to new values */ + switch (emu->guildrank) { + case 0: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 5); break; } // GUILD_MEMBER 0 + case 1: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 3); break; } // GUILD_OFFICER 1 + case 2: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 1); break; } // GUILD_LEADER 2 + default: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->guildrank); break; } // + } + } + + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->class_); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // pvp + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->StandState); // standstate + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->light); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->flymode); + + //VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 100); // LiveUnknown1 12/06/14 (possibly mana percent?) + //VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 10); // LiveUnknown2 12/06/14 + //VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // LiveUnknown3 12/06/14 + + VARSTRUCT_ENCODE_STRING(Buffer, emu->lastName); + + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // aatitle ?? + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->NPC ? 0 : 1); // unknown - Must be 1 for guild name to be shown abover players head. + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown + + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petOwnerId); + + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown13 + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown14 - Stance 64 = normal 4 = aggressive 40 = stun/mezzed + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown15 + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown16 + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown17 + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // unknown18 + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // unknown19 + + if ((emu->NPC == 0) || (emu->race <= 12) || (emu->race == 128) || (emu->race == 130) || (emu->race == 330) || (emu->race == 522)) + { + for (k = 0; k < 9; ++k) + { + { + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->colors[k].color); + } + } + + structs::EquipStruct *Equipment = (structs::EquipStruct *)Buffer; + + for (k = 0; k < 9; k++) { + Equipment[k].equip0 = emu->equipment[k]; + Equipment[k].equip1 = 0; + Equipment[k].equip2 = 0; + Equipment[k].equip3 = 0; + Equipment[k].itemId = 0; + } + + Buffer += (sizeof(structs::EquipStruct) * 9); + } + else + { + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); + + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialPrimary]); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); + + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialSecondary]); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); + } + + structs::Spawn_Struct_Position *Position = (structs::Spawn_Struct_Position*)Buffer; + + Position->y = emu->y; + Position->deltaZ = emu->deltaZ; + Position->deltaX = emu->deltaX; + Position->x = emu->x; + Position->heading = emu->heading; + Position->deltaHeading = emu->deltaHeading; + Position->z = emu->z; + Position->animation = emu->animation; + Position->deltaY = emu->deltaY; + + Buffer += sizeof(structs::Spawn_Struct_Position); + + if (strlen(emu->title)) + { + VARSTRUCT_ENCODE_STRING(Buffer, emu->title); + } + + if (strlen(emu->suffix)) + { + VARSTRUCT_ENCODE_STRING(Buffer, emu->suffix); + } + + Buffer += 8; + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->IsMercenary); + VARSTRUCT_ENCODE_STRING(Buffer, "0000000000000000"); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); + // 29 zero bytes follow + Buffer += 29; + if (Buffer != (BufferStart + PacketSize)) + { + _log(NET__ERROR, "SPAWN ENCODE LOGIC PROBLEM: Buffer pointer is now %i from end", Buffer - (BufferStart + PacketSize)); + } + //_log(NET__ERROR, "Sending zone spawn for %s packet is %i bytes", emu->name, outapp->size); + //_hex(NET__ERROR, outapp->pBuffer, outapp->size); + dest->FastQueuePacket(&outapp, ack_req); + } + + delete in; + } + +// DECODE methods + DECODE(OP_AdventureMerchantSell) + { + DECODE_LENGTH_EXACT(structs::Adventure_Sell_Struct); + SETUP_DIRECT_DECODE(Adventure_Sell_Struct, structs::Adventure_Sell_Struct); + + IN(npcid); + emu->slot = RoF2ToServerMainInvSlot(eq->slot); + IN(charges); + IN(sell_price); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_AltCurrencySell) + { + DECODE_LENGTH_EXACT(structs::AltCurrencySellItem_Struct); + SETUP_DIRECT_DECODE(AltCurrencySellItem_Struct, structs::AltCurrencySellItem_Struct); + + IN(merchant_entity_id); + emu->slot_id = RoF2ToServerSlot(eq->slot_id); + IN(charges); + IN(cost); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_AltCurrencySellSelection) + { + DECODE_LENGTH_EXACT(structs::AltCurrencySelectItem_Struct); + SETUP_DIRECT_DECODE(AltCurrencySelectItem_Struct, structs::AltCurrencySelectItem_Struct); + + IN(merchant_entity_id); + emu->slot_id = RoF2ToServerSlot(eq->slot_id); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_ApplyPoison) + { + DECODE_LENGTH_EXACT(structs::ApplyPoison_Struct); + SETUP_DIRECT_DECODE(ApplyPoison_Struct, structs::ApplyPoison_Struct); + + emu->inventorySlot = RoF2ToServerMainInvSlot(eq->inventorySlot); + IN(success); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_AugmentInfo) + { + DECODE_LENGTH_EXACT(structs::AugmentInfo_Struct); + SETUP_DIRECT_DECODE(AugmentInfo_Struct, structs::AugmentInfo_Struct); + + IN(itemid); + IN(window); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_AugmentItem) + { + DECODE_LENGTH_EXACT(structs::AugmentItem_Struct); + SETUP_DIRECT_DECODE(AugmentItem_Struct, structs::AugmentItem_Struct); + + emu->container_slot = RoF2ToServerSlot(eq->container_slot); + emu->augment_slot = RoF2ToServerSlot(eq->augment_slot); + emu->container_index = eq->container_index; + emu->augment_index = eq->augment_index; + emu->dest_inst_id = eq->dest_inst_id; + emu->augment_action = eq->augment_action; + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_BazaarSearch) + { + char *Buffer = (char *)__packet->pBuffer; + + uint8 SubAction = VARSTRUCT_DECODE_TYPE(uint8, Buffer); + + if ((SubAction != BazaarInspectItem) || (__packet->size != sizeof(structs::NewBazaarInspect_Struct))) + return; + + SETUP_DIRECT_DECODE(NewBazaarInspect_Struct, structs::NewBazaarInspect_Struct); + MEMSET_IN(structs::NewBazaarInspect_Struct); + + IN(Beginning.Action); + memcpy(emu->Name, eq->Name, sizeof(emu->Name)); + IN(SerialNumber); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_BlockedBuffs) + { + DECODE_LENGTH_EXACT(structs::BlockedBuffs_Struct); + SETUP_DIRECT_DECODE(BlockedBuffs_Struct, structs::BlockedBuffs_Struct); + + for (uint32 i = 0; i < BLOCKED_BUFF_COUNT; ++i) + emu->SpellID[i] = eq->SpellID[i]; + + IN(Count); + IN(Pet); + IN(Initialise); + IN(Flags); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_Buff) + { + DECODE_LENGTH_EXACT(structs::SpellBuffFade_Struct_Live); + SETUP_DIRECT_DECODE(SpellBuffFade_Struct, structs::SpellBuffFade_Struct_Live); + + IN(entityid); + //IN(slot); + IN(level); + IN(effect); + IN(spellid); + IN(duration); + IN(slotid); + IN(bufffade); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_BuffRemoveRequest) + { + // This is to cater for the fact that short buff box buffs start at 30 as opposed to 25 in prior clients. + // + DECODE_LENGTH_EXACT(structs::BuffRemoveRequest_Struct); + SETUP_DIRECT_DECODE(BuffRemoveRequest_Struct, structs::BuffRemoveRequest_Struct); + + emu->SlotID = (eq->SlotID < 42) ? eq->SlotID : (eq->SlotID - 17); + + IN(EntityID); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_CastSpell) + { + DECODE_LENGTH_EXACT(structs::CastSpell_Struct); + SETUP_DIRECT_DECODE(CastSpell_Struct, structs::CastSpell_Struct); + + if (eq->slot == 13) + emu->slot = 10; + else + IN(slot); + + IN(spell_id); + emu->inventoryslot = RoF2ToServerSlot(eq->inventoryslot); + //IN(inventoryslot); + IN(target_id); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_ChannelMessage) + { + unsigned char *__eq_buffer = __packet->pBuffer; + + char *InBuffer = (char *)__eq_buffer; + + char Sender[64]; + char Target[64]; + + VARSTRUCT_DECODE_STRING(Sender, InBuffer); + VARSTRUCT_DECODE_STRING(Target, InBuffer); + + InBuffer += 4; + + uint32 Language = VARSTRUCT_DECODE_TYPE(uint32, InBuffer); + uint32 Channel = VARSTRUCT_DECODE_TYPE(uint32, InBuffer); + + InBuffer += 5; + + uint32 Skill = VARSTRUCT_DECODE_TYPE(uint32, InBuffer); + + __packet->size = sizeof(ChannelMessage_Struct)+strlen(InBuffer) + 1; + __packet->pBuffer = new unsigned char[__packet->size]; + ChannelMessage_Struct *emu = (ChannelMessage_Struct *)__packet->pBuffer; + + strn0cpy(emu->targetname, Target, sizeof(emu->targetname)); + strn0cpy(emu->sender, Target, sizeof(emu->sender)); + emu->language = Language; + emu->chan_num = Channel; + emu->skill_in_language = Skill; + strcpy(emu->message, InBuffer); + + delete[] __eq_buffer; + } + + DECODE(OP_CharacterCreate) + { + DECODE_LENGTH_EXACT(structs::CharCreate_Struct); + SETUP_DIRECT_DECODE(CharCreate_Struct, structs::CharCreate_Struct); + + IN(gender); + IN(race); + IN(class_); + IN(deity); + IN(start_zone); + IN(haircolor); + IN(beard); + IN(beardcolor); + IN(hairstyle); + IN(face); + IN(eyecolor1); + IN(eyecolor2); + IN(drakkin_heritage); + IN(drakkin_tattoo); + IN(drakkin_details); + IN(STR); + IN(STA); + IN(AGI); + IN(DEX); + IN(WIS); + IN(INT); + IN(CHA); + IN(tutorial); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_ClientUpdate) + { + // for some odd reason, there is an extra byte on the end of this on occasion.. + DECODE_LENGTH_ATLEAST(structs::PlayerPositionUpdateClient_Struct); + SETUP_DIRECT_DECODE(PlayerPositionUpdateClient_Struct, structs::PlayerPositionUpdateClient_Struct); + + IN(spawn_id); + IN(sequence); + IN(x_pos); + IN(y_pos); + IN(z_pos); + IN(heading); + IN(delta_x); + IN(delta_y); + IN(delta_z); + IN(delta_heading); + IN(animation); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_Consider) + { + DECODE_LENGTH_EXACT(structs::Consider_Struct); + SETUP_DIRECT_DECODE(Consider_Struct, structs::Consider_Struct); + + IN(playerid); + IN(targetid); + IN(faction); + IN(level); + //emu->cur_hp = 1; + //emu->max_hp = 2; + //emu->pvpcon = 0; + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_ConsiderCorpse) { DECODE_FORWARD(OP_Consider); } + + DECODE(OP_Consume) + { + DECODE_LENGTH_EXACT(structs::Consume_Struct); + SETUP_DIRECT_DECODE(Consume_Struct, structs::Consume_Struct); + + emu->slot = RoF2ToServerSlot(eq->slot); + IN(auto_consumed); + IN(type); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_Damage) + { + DECODE_LENGTH_EXACT(structs::CombatDamage_Struct); + SETUP_DIRECT_DECODE(CombatDamage_Struct, structs::CombatDamage_Struct); + + IN(target); + IN(source); + IN(type); + IN(spellid); + IN(damage); + emu->sequence = eq->sequence; + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_DeleteItem) + { + DECODE_LENGTH_EXACT(structs::DeleteItem_Struct); + SETUP_DIRECT_DECODE(DeleteItem_Struct, structs::DeleteItem_Struct); + + emu->from_slot = RoF2ToServerSlot(eq->from_slot); + emu->to_slot = RoF2ToServerSlot(eq->to_slot); + IN(number_in_stack); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_EnvDamage) + { + DECODE_LENGTH_EXACT(structs::EnvDamage2_Struct); + SETUP_DIRECT_DECODE(EnvDamage2_Struct, structs::EnvDamage2_Struct); + + IN(id); + IN(damage); + IN(dmgtype); + emu->constant = 0xFFFF; + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_FaceChange) + { + DECODE_LENGTH_EXACT(structs::FaceChange_Struct); + SETUP_DIRECT_DECODE(FaceChange_Struct, structs::FaceChange_Struct); + + IN(haircolor); + IN(beardcolor); + IN(eyecolor1); + IN(eyecolor2); + IN(hairstyle); + IN(beard); + IN(face); + IN(drakkin_heritage); + IN(drakkin_tattoo); + IN(drakkin_details); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_FindPersonRequest) + { + DECODE_LENGTH_EXACT(structs::FindPersonRequest_Struct); + SETUP_DIRECT_DECODE(FindPersonRequest_Struct, structs::FindPersonRequest_Struct); + + IN(npc_id); + IN(client_pos.x); + IN(client_pos.y); + IN(client_pos.z); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_GMLastName) + { + DECODE_LENGTH_EXACT(structs::GMLastName_Struct); + SETUP_DIRECT_DECODE(GMLastName_Struct, structs::GMLastName_Struct); + + memcpy(emu->name, eq->name, sizeof(emu->name)); + memcpy(emu->gmname, eq->gmname, sizeof(emu->gmname)); + memcpy(emu->lastname, eq->lastname, sizeof(emu->lastname)); + for (int i = 0; i<4; i++) + { + emu->unknown[i] = eq->unknown[i]; + } + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_GroupCancelInvite) + { + DECODE_LENGTH_EXACT(structs::GroupCancel_Struct); + SETUP_DIRECT_DECODE(GroupCancel_Struct, structs::GroupCancel_Struct); + + memcpy(emu->name1, eq->name1, sizeof(emu->name1)); + memcpy(emu->name2, eq->name2, sizeof(emu->name2)); + IN(toggle); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_GroupDisband) + { + //EQApplicationPacket *in = __packet; + //_log(NET__ERROR, "Received incoming OP_Disband"); + //_hex(NET__ERROR, in->pBuffer, in->size); + DECODE_LENGTH_EXACT(structs::GroupGeneric_Struct); + SETUP_DIRECT_DECODE(GroupGeneric_Struct, structs::GroupGeneric_Struct); + + memcpy(emu->name1, eq->name1, sizeof(emu->name1)); + memcpy(emu->name2, eq->name2, sizeof(emu->name2)); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_GroupFollow) + { + //EQApplicationPacket *in = __packet; + //_log(NET__ERROR, "Received incoming OP_GroupFollow"); + //_hex(NET__ERROR, in->pBuffer, in->size); + DECODE_LENGTH_EXACT(structs::GroupFollow_Struct); + SETUP_DIRECT_DECODE(GroupGeneric_Struct, structs::GroupFollow_Struct); + + memcpy(emu->name1, eq->name1, sizeof(emu->name1)); + memcpy(emu->name2, eq->name2, sizeof(emu->name2)); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_GroupFollow2) + { + //EQApplicationPacket *in = __packet; + //_log(NET__ERROR, "Received incoming OP_GroupFollow2"); + //_hex(NET__ERROR, in->pBuffer, in->size); + DECODE_LENGTH_EXACT(structs::GroupFollow_Struct); + SETUP_DIRECT_DECODE(GroupGeneric_Struct, structs::GroupFollow_Struct); + + memcpy(emu->name1, eq->name1, sizeof(emu->name1)); + memcpy(emu->name2, eq->name2, sizeof(emu->name2)); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_GroupInvite) + { + //EQApplicationPacket *in = __packet; + //_log(NET__ERROR, "Received incoming OP_GroupInvite"); + //_hex(NET__ERROR, in->pBuffer, in->size); + DECODE_LENGTH_EXACT(structs::GroupInvite_Struct); + SETUP_DIRECT_DECODE(GroupGeneric_Struct, structs::GroupInvite_Struct); + + memcpy(emu->name1, eq->invitee_name, sizeof(emu->name1)); + memcpy(emu->name2, eq->inviter_name, sizeof(emu->name2)); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_GroupInvite2) + { + //_log(NET__ERROR, "Received incoming OP_GroupInvite2. Forwarding"); + DECODE_FORWARD(OP_GroupInvite); + } + + DECODE(OP_GuildDemote) + { + DECODE_LENGTH_EXACT(structs::GuildDemoteStruct); + SETUP_DIRECT_DECODE(GuildDemoteStruct, structs::GuildDemoteStruct); + + strn0cpy(emu->target, eq->target, sizeof(emu->target)); + strn0cpy(emu->name, eq->name, sizeof(emu->name)); + // IN(rank); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_GuildRemove) + { + DECODE_LENGTH_EXACT(structs::GuildCommand_Struct); + SETUP_DIRECT_DECODE(GuildCommand_Struct, structs::GuildCommand_Struct); + + strn0cpy(emu->othername, eq->othername, sizeof(emu->othername)); + strn0cpy(emu->myname, eq->myname, sizeof(emu->myname)); + IN(guildeqid); + IN(officer); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_GuildStatus) + { + DECODE_LENGTH_EXACT(structs::GuildStatus_Struct); + SETUP_DIRECT_DECODE(GuildStatus_Struct, structs::GuildStatus_Struct); + + memcpy(emu->Name, eq->Name, sizeof(emu->Name)); + + FINISH_DIRECT_DECODE(); + } + + /*DECODE(OP_InspectAnswer) + { + DECODE_LENGTH_EXACT(structs::InspectResponse_Struct); + SETUP_DIRECT_DECODE(InspectResponse_Struct, structs::InspectResponse_Struct); + + IN(TargetID); + IN(playerid); + + int r; + for (r = 0; r < 21; r++) { + strn0cpy(emu->itemnames[r], eq->itemnames[r], sizeof(emu->itemnames[r])); + } + // Swap last 2 slots for Arrow and Power Source + strn0cpy(emu->itemnames[22], eq->itemnames[21], sizeof(emu->itemnames[22])); + strn0cpy(emu->itemnames[21], eq->unknown_zero, sizeof(emu->itemnames[21])); + strn0cpy(emu->unknown_zero, eq->unknown_zero, sizeof(emu->unknown_zero)); + + int k; + for (k = 0; k < 21; k++) { + IN(itemicons[k]); + } + // Swap last 2 slots for Arrow and Power Source + emu->itemicons[22] = eq->itemicons[21]; + emu->itemicons[21] = eq->unknown_zero2; + emu->unknown_zero2 = eq->unknown_zero2; + strn0cpy(emu->text, eq->text, sizeof(emu->text)); + //emu->unknown1772 = 0; + + FINISH_DIRECT_DECODE(); + }*/ + + DECODE(OP_InspectRequest) + { + DECODE_LENGTH_EXACT(structs::Inspect_Struct); + SETUP_DIRECT_DECODE(Inspect_Struct, structs::Inspect_Struct); + + IN(TargetID); + IN(PlayerID); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_ItemLinkClick) + { + DECODE_LENGTH_EXACT(structs::ItemViewRequest_Struct); + SETUP_DIRECT_DECODE(ItemViewRequest_Struct, structs::ItemViewRequest_Struct); + MEMSET_IN(ItemViewRequest_Struct); + + IN(item_id); + int r; + for (r = 0; r < 5; r++) { + IN(augments[r]); + } + // Max Augs is now 6, but no code to support that many yet + IN(link_hash); + IN(icon); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_ItemVerifyRequest) + { + DECODE_LENGTH_EXACT(structs::ItemVerifyRequest_Struct); + SETUP_DIRECT_DECODE(ItemVerifyRequest_Struct, structs::ItemVerifyRequest_Struct); + + emu->slot = RoF2ToServerSlot(eq->slot); + IN(target); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_LoadSpellSet) + { + DECODE_LENGTH_EXACT(structs::LoadSpellSet_Struct); + SETUP_DIRECT_DECODE(LoadSpellSet_Struct, structs::LoadSpellSet_Struct); + + for (unsigned int i = 0; i < MAX_PP_MEMSPELL; ++i) + { + if (eq->spell[i] == 0) + emu->spell[i] = 0xFFFFFFFF; + else + emu->spell[i] = eq->spell[i]; + } + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_LootItem) + { + DECODE_LENGTH_EXACT(structs::LootingItem_Struct); + SETUP_DIRECT_DECODE(LootingItem_Struct, structs::LootingItem_Struct); + + IN(lootee); + IN(looter); + emu->slot_id = RoF2ToServerCorpseSlot(eq->slot_id); + IN(auto_loot); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_MoveItem) + { + DECODE_LENGTH_EXACT(structs::MoveItem_Struct); + SETUP_DIRECT_DECODE(MoveItem_Struct, structs::MoveItem_Struct); + + //_log(NET__ERROR, "Moved item from %u to %u", eq->from_slot.MainSlot, eq->to_slot.MainSlot); + _log(NET__ERROR, "MoveItem SlotType from %i to %i, MainSlot from %i to %i, SubSlot from %i to %i, AugSlot from %i to %i, Unknown01 from %i to %i, Number %u", eq->from_slot.SlotType, eq->to_slot.SlotType, eq->from_slot.MainSlot, eq->to_slot.MainSlot, eq->from_slot.SubSlot, eq->to_slot.SubSlot, eq->from_slot.AugSlot, eq->to_slot.AugSlot, eq->from_slot.Unknown01, eq->to_slot.Unknown01, eq->number_in_stack); + emu->from_slot = RoF2ToServerSlot(eq->from_slot); + emu->to_slot = RoF2ToServerSlot(eq->to_slot); + IN(number_in_stack); + + _hex(NET__ERROR, eq, sizeof(structs::MoveItem_Struct)); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_PetCommands) + { + DECODE_LENGTH_EXACT(structs::PetCommand_Struct); + SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct); + + switch (eq->command) + { + case 0x00: + emu->command = 0x04; // Health + break; + case 0x01: + emu->command = 0x10; // Leader + break; + case 0x02: + emu->command = 0x07; // Attack + break; + case 0x04: + emu->command = 0x08; // Follow + break; + case 0x05: + emu->command = 0x05; // Guard + break; + case 0x06: + emu->command = 0x09; // Sit. Needs work. This appears to be a toggle between Sit/Stand now. + break; + case 0x0c: + emu->command = 0x0b; // Taunt + break; + case 0x0f: + emu->command = 0x0c; // Hold + break; + case 0x10: + emu->command = 0x1b; // Hold on + break; + case 0x11: + emu->command = 0x1c; // Hold off + break; + case 0x1c: + emu->command = 0x01; // Back + break; + case 0x1d: + emu->command = 0x02; // Leave/Go Away + break; + default: + emu->command = eq->command; + } + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_RaidInvite) + { + DECODE_LENGTH_ATLEAST(structs::RaidGeneral_Struct); + + // This is a switch on the RaidGeneral action + switch (*(uint32 *)__packet->pBuffer) { + case 35: { // raidMOTD + // we don't have a nice macro for this + structs::RaidMOTD_Struct *__eq_buffer = (structs::RaidMOTD_Struct *)__packet->pBuffer; + __eq_buffer->motd[1023] = '\0'; + size_t motd_size = strlen(__eq_buffer->motd) + 1; + __packet->size = sizeof(RaidMOTD_Struct) + motd_size; + __packet->pBuffer = new unsigned char[__packet->size]; + RaidMOTD_Struct *emu = (RaidMOTD_Struct *)__packet->pBuffer; + structs::RaidMOTD_Struct *eq = (structs::RaidMOTD_Struct *)__eq_buffer; + strn0cpy(emu->general.player_name, eq->general.player_name, 64); + strn0cpy(emu->motd, eq->motd, motd_size); + IN(general.action); + IN(general.parameter); + FINISH_DIRECT_DECODE(); + break; + } + case 36: { // raidPlayerNote unhandled + break; + } + default: { + DECODE_LENGTH_EXACT(structs::RaidGeneral_Struct); + SETUP_DIRECT_DECODE(RaidGeneral_Struct, structs::RaidGeneral_Struct); + strn0cpy(emu->leader_name, eq->leader_name, 64); + strn0cpy(emu->player_name, eq->player_name, 64); + IN(action); + IN(parameter); + FINISH_DIRECT_DECODE(); + break; + } + } + } + + DECODE(OP_ReadBook) + { + DECODE_LENGTH_EXACT(structs::BookRequest_Struct); + SETUP_DIRECT_DECODE(BookRequest_Struct, structs::BookRequest_Struct); + + IN(type); + IN(invslot); + emu->window = (uint8)eq->window; + strn0cpy(emu->txtfile, eq->txtfile, sizeof(emu->txtfile)); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_RecipeAutoCombine) + { + DECODE_LENGTH_EXACT(structs::RecipeAutoCombine_Struct); + SETUP_DIRECT_DECODE(RecipeAutoCombine_Struct, structs::RecipeAutoCombine_Struct); + + IN(object_type); + IN(some_id); + emu->unknown1 = RoF2ToServerSlot(eq->container_slot); + IN(recipe_id); + IN(reply_code); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_RemoveBlockedBuffs) { DECODE_FORWARD(OP_BlockedBuffs); } + + DECODE(OP_RezzAnswer) + { + DECODE_LENGTH_EXACT(structs::Resurrect_Struct); + SETUP_DIRECT_DECODE(Resurrect_Struct, structs::Resurrect_Struct); + + IN(zone_id); + IN(instance_id); + IN(y); + IN(x); + IN(z); + memcpy(emu->your_name, eq->your_name, sizeof(emu->your_name)); + memcpy(emu->rezzer_name, eq->rezzer_name, sizeof(emu->rezzer_name)); + IN(spellid); + memcpy(emu->corpse_name, eq->corpse_name, sizeof(emu->corpse_name)); + IN(action); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_Save) + { + DECODE_LENGTH_EXACT(structs::Save_Struct); + SETUP_DIRECT_DECODE(Save_Struct, structs::Save_Struct); + + memcpy(emu->unknown00, eq->unknown00, sizeof(emu->unknown00)); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_SetServerFilter) + { + DECODE_LENGTH_EXACT(structs::SetServerFilter_Struct); + SETUP_DIRECT_DECODE(SetServerFilter_Struct, structs::SetServerFilter_Struct); + + int r; + for (r = 0; r < 29; r++) { + // Size 40 in RoF2 + IN(filters[r]); + } + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_ShopPlayerBuy) + { + DECODE_LENGTH_EXACT(structs::Merchant_Sell_Struct); + SETUP_DIRECT_DECODE(Merchant_Sell_Struct, structs::Merchant_Sell_Struct); + + IN(npcid); + IN(playerid); + IN(itemslot); + IN(quantity); + IN(price); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_ShopPlayerSell) + { + DECODE_LENGTH_EXACT(structs::Merchant_Purchase_Struct); + SETUP_DIRECT_DECODE(Merchant_Purchase_Struct, structs::Merchant_Purchase_Struct); + + IN(npcid); + emu->itemslot = RoF2ToServerMainInvSlot(eq->itemslot); + //IN(itemslot); + IN(quantity); + IN(price); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_ShopRequest) + { + DECODE_LENGTH_EXACT(structs::Merchant_Click_Struct); + SETUP_DIRECT_DECODE(Merchant_Click_Struct, structs::Merchant_Click_Struct); + + IN(npcid); + IN(playerid); + IN(command); + IN(rate); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_Trader) + { + uint32 psize = __packet->size; + if (psize == sizeof(structs::ClickTrader_Struct)) + { + DECODE_LENGTH_EXACT(structs::ClickTrader_Struct); + SETUP_DIRECT_DECODE(ClickTrader_Struct, structs::ClickTrader_Struct); + MEMSET_IN(ClickTrader_Struct); + + emu->Code = eq->Code; + // Live actually has 200 items now, but 80 is the most our internal struct supports + for (uint32 i = 0; i < 80; i++) + { + emu->SerialNumber[i] = 0; // eq->SerialNumber[i]; + emu->ItemCost[i] = eq->ItemCost[i]; + } + + FINISH_DIRECT_DECODE(); + } + else if (psize == sizeof(structs::Trader_ShowItems_Struct)) + { + DECODE_LENGTH_EXACT(structs::Trader_ShowItems_Struct); + SETUP_DIRECT_DECODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct); + MEMSET_IN(Trader_ShowItems_Struct); + + emu->Code = eq->Code; + emu->TraderID = eq->TraderID; + + FINISH_DIRECT_DECODE(); + } + else if (psize == sizeof(structs::TraderStatus_Struct)) + { + DECODE_LENGTH_EXACT(structs::TraderStatus_Struct); + SETUP_DIRECT_DECODE(TraderStatus_Struct, structs::TraderStatus_Struct); + MEMSET_IN(TraderStatus_Struct); + + emu->Code = eq->Code; + + FINISH_DIRECT_DECODE(); + } + } + + DECODE(OP_TraderBuy) + { + DECODE_LENGTH_EXACT(structs::TraderBuy_Struct); + SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct); + MEMSET_IN(TraderBuy_Struct); + + IN(Action); + IN(Price); + IN(TraderID); + memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName)); + IN(ItemID); + IN(Quantity); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_TradeSkillCombine) + { + DECODE_LENGTH_EXACT(structs::NewCombine_Struct); + SETUP_DIRECT_DECODE(NewCombine_Struct, structs::NewCombine_Struct); + + int16 slot_id = RoF2ToServerSlot(eq->container_slot); + if (slot_id == 4000) { + slot_id = legacy::SLOT_TRADESKILL; // 1000 + } + emu->container_slot = slot_id; + emu->guildtribute_slot = RoF2ToServerSlot(eq->guildtribute_slot); // this should only return INVALID_INDEX until implemented -U + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_TributeItem) + { + DECODE_LENGTH_EXACT(structs::TributeItem_Struct); + SETUP_DIRECT_DECODE(TributeItem_Struct, structs::TributeItem_Struct); + + emu->slot = RoF2ToServerSlot(eq->slot); + IN(quantity); + IN(tribute_master_id); + IN(tribute_points); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_WhoAllRequest) + { + DECODE_LENGTH_EXACT(structs::Who_All_Struct); + SETUP_DIRECT_DECODE(Who_All_Struct, structs::Who_All_Struct); + + memcpy(emu->whom, eq->whom, sizeof(emu->whom)); + IN(wrace); + IN(wclass); + IN(lvllow); + IN(lvlhigh); + IN(gmlookup); + IN(guildid); + IN(type); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_ZoneChange) + { + DECODE_LENGTH_EXACT(structs::ZoneChange_Struct); + SETUP_DIRECT_DECODE(ZoneChange_Struct, structs::ZoneChange_Struct); + + memcpy(emu->char_name, eq->char_name, sizeof(emu->char_name)); + IN(zoneID); + IN(instanceID); + IN(y); + IN(x); + IN(z) + IN(zone_reason); + IN(success); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_ZoneEntry) + { + DECODE_LENGTH_EXACT(structs::ClientZoneEntry_Struct); + SETUP_DIRECT_DECODE(ClientZoneEntry_Struct, structs::ClientZoneEntry_Struct); + + memcpy(emu->char_name, eq->char_name, sizeof(emu->char_name)); + + FINISH_DIRECT_DECODE(); + } + +// file scope helper methods + uint32 NextItemInstSerialNumber = 1; + uint32 MaxInstances = 2000000000; + + static inline int32 GetNextItemInstSerialNumber() + { + if (NextItemInstSerialNumber >= MaxInstances) + NextItemInstSerialNumber = 1; + else + NextItemInstSerialNumber++; + + return NextItemInstSerialNumber; + } + + char* SerializeItem(const ItemInst *inst, int16 slot_id_in, uint32 *length, uint8 depth) + { + int ornamentationAugtype = RuleI(Character, OrnamentationAugmentType); + uint8 null_term = 0; + bool stackable = inst->IsStackable(); + uint32 merchant_slot = inst->GetMerchantSlot(); + uint32 charges = inst->GetCharges(); + if (!stackable && charges > 254) + charges = 0xFFFFFFFF; + + std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); + + const Item_Struct *item = inst->GetUnscaledItem(); + //_log(NET__ERROR, "Serialize called for: %s", item->Name); + + RoF2::structs::ItemSerializationHeader hdr; + + //sprintf(hdr.unknown000, "06e0002Y1W00"); + + snprintf(hdr.unknown000, sizeof(hdr.unknown000), "%012d", item->ID); + + hdr.stacksize = stackable ? charges : 1; + hdr.unknown004 = 0; + + structs::ItemSlotStruct slot_id = ServerToRoF2Slot(slot_id_in); + + hdr.slot_type = (merchant_slot == 0) ? slot_id.SlotType : 9; // 9 is merchant 20 is reclaim items? + hdr.main_slot = (merchant_slot == 0) ? slot_id.MainSlot : merchant_slot; + hdr.sub_slot = (merchant_slot == 0) ? slot_id.SubSlot : 0xffff; + hdr.unknown013 = (merchant_slot == 0) ? slot_id.AugSlot : 0xffff; + //hdr.unknown013 = 0xffff; + hdr.price = inst->GetPrice(); + hdr.merchant_slot = (merchant_slot == 0) ? 1 : inst->GetMerchantCount(); + //hdr.merchant_slot = (merchant_slot == 0) ? 1 : 0xffffffff; + hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0; + hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot; + hdr.unknown028 = 0; + hdr.last_cast_time = ((item->RecastDelay > 1) ? 1212693140 : 0); + hdr.charges = (stackable ? (item->MaxCharges ? 1 : 0) : charges); + hdr.inst_nodrop = inst->IsInstNoDrop() ? 1 : 0; + hdr.unknown044 = 0; + hdr.unknown048 = 0; + hdr.unknown052 = 0; + hdr.isEvolving = item->EvolvingLevel > 0 ? 1 : 0; + ss.write((const char*)&hdr, sizeof(RoF2::structs::ItemSerializationHeader)); + + if (item->EvolvingLevel > 0) { + RoF2::structs::EvolvingItem evotop; + evotop.unknown001 = 0; + evotop.unknown002 = 0; + evotop.unknown003 = 0; + evotop.unknown004 = 0; + evotop.evoLevel = item->EvolvingLevel; + evotop.progress = 95.512; + evotop.Activated = 1; + evotop.evomaxlevel = 7; + ss.write((const char*)&evotop, sizeof(RoF2::structs::EvolvingItem)); + } + //ORNAMENT IDFILE / ICON + uint16 ornaIcon = 0; + if (inst->GetOrnamentationAug(ornamentationAugtype)) { + const Item_Struct *aug_weap = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem(); + //Mainhand + ss.write(aug_weap->IDFile, strlen(aug_weap->IDFile)); + ss.write((const char*)&null_term, sizeof(uint8)); + //Offhand + ss.write(aug_weap->IDFile, strlen(aug_weap->IDFile)); + ss.write((const char*)&null_term, sizeof(uint8)); + //Icon + ornaIcon = aug_weap->Icon; + } + else if (inst->GetOrnamentationIDFile() && inst->GetOrnamentationIcon()) { + char tmp[30]; memset(tmp, 0x0, 30); sprintf(tmp, "IT%d", inst->GetOrnamentationIDFile()); + //Mainhand + ss.write(tmp, strlen(tmp)); + ss.write((const char*)&null_term, sizeof(uint8)); + //Offhand + ss.write(tmp, strlen(tmp)); + ss.write((const char*)&null_term, sizeof(uint8)); + ornaIcon = inst->GetOrnamentationIcon(); + } + else { + ss.write((const char*)&null_term, sizeof(uint8)); //no mh + ss.write((const char*)&null_term, sizeof(uint8));//no of + } + + RoF2::structs::ItemSerializationHeaderFinish hdrf; + hdrf.ornamentIcon = ornaIcon; + hdrf.unknown061 = 0; + hdrf.unknown062 = 0; + hdrf.unknowna1 = 0xffffffff; + hdrf.unknowna2 = 0; + hdrf.unknown063 = 0; + hdrf.unknowna3 = 0; + hdrf.unknowna4 = 0xffffffff; + hdrf.unknowna5 = 0; + hdrf.ItemClass = item->ItemClass; + ss.write((const char*)&hdrf, sizeof(RoF2::structs::ItemSerializationHeaderFinish)); + + if (strlen(item->Name) > 0) + { + ss.write(item->Name, strlen(item->Name)); + ss.write((const char*)&null_term, sizeof(uint8)); + } + else + { + ss.write((const char*)&null_term, sizeof(uint8)); + } + + if (strlen(item->Lore) > 0) + { + ss.write(item->Lore, strlen(item->Lore)); + ss.write((const char*)&null_term, sizeof(uint8)); + } + else + { + ss.write((const char*)&null_term, sizeof(uint8)); + } + + if (strlen(item->IDFile) > 0) + { + ss.write(item->IDFile, strlen(item->IDFile)); + ss.write((const char*)&null_term, sizeof(uint8)); + } + else + { + ss.write((const char*)&null_term, sizeof(uint8)); + } + + ss.write((const char*)&null_term, sizeof(uint8)); + //_log(NET__ERROR, "ItemBody struct is %i bytes", sizeof(RoF2::structs::ItemBodyStruct)); + RoF2::structs::ItemBodyStruct ibs; + memset(&ibs, 0, sizeof(RoF2::structs::ItemBodyStruct)); + + ibs.id = item->ID; + ibs.weight = item->Weight; + ibs.norent = item->NoRent; + ibs.nodrop = item->NoDrop; + ibs.attune = item->Attuneable; + ibs.size = item->Size; + ibs.slots = SwapBits21and22(item->Slots); + ibs.price = item->Price; + ibs.icon = item->Icon; + ibs.unknown1 = 1; + ibs.unknown2 = 1; + ibs.BenefitFlag = item->BenefitFlag; + ibs.tradeskills = item->Tradeskills; + ibs.CR = item->CR; + ibs.DR = item->DR; + ibs.PR = item->PR; + ibs.MR = item->MR; + ibs.FR = item->FR; + ibs.SVCorruption = item->SVCorruption; + ibs.AStr = item->AStr; + ibs.ASta = item->ASta; + ibs.AAgi = item->AAgi; + ibs.ADex = item->ADex; + ibs.ACha = item->ACha; + ibs.AInt = item->AInt; + ibs.AWis = item->AWis; + + ibs.HP = item->HP; + ibs.Mana = item->Mana; + ibs.Endur = item->Endur; + ibs.AC = item->AC; + ibs.regen = item->Regen; + ibs.mana_regen = item->ManaRegen; + ibs.end_regen = item->EnduranceRegen; + ibs.Classes = item->Classes; + ibs.Races = item->Races; + ibs.Deity = item->Deity; + ibs.SkillModValue = item->SkillModValue; + ibs.SkillModMax = 0xffffffff; + ibs.SkillModType = (int8)(item->SkillModType); + ibs.SkillModExtra = 0; + ibs.BaneDmgRace = item->BaneDmgRace; + ibs.BaneDmgBody = item->BaneDmgBody; + ibs.BaneDmgRaceAmt = item->BaneDmgRaceAmt; + ibs.BaneDmgAmt = item->BaneDmgAmt; + ibs.Magic = item->Magic; + ibs.CastTime_ = item->CastTime_; + ibs.ReqLevel = item->ReqLevel; + if (item->ReqLevel > 100) + ibs.ReqLevel = 100; + ibs.RecLevel = item->RecLevel; + if (item->RecLevel > 100) + ibs.RecLevel = 100; + ibs.RecSkill = item->RecSkill; + ibs.BardType = item->BardType; + ibs.BardValue = item->BardValue; + ibs.Light = item->Light; + ibs.Delay = item->Delay; + ibs.ElemDmgType = item->ElemDmgType; + ibs.ElemDmgAmt = item->ElemDmgAmt; + ibs.Range = item->Range; + ibs.Damage = item->Damage; + ibs.Color = item->Color; + ibs.Prestige = 0; + ibs.ItemType = item->ItemType; + ibs.Material = item->Material; + ibs.unknown7 = 0; + ibs.EliteMaterial = item->EliteMaterial; + ibs.unknown_RoF23 = 0; + ibs.unknown_RoF24 = 0; + ibs.SellRate = item->SellRate; + ibs.CombatEffects = item->CombatEffects; + ibs.Shielding = item->Shielding; + ibs.StunResist = item->StunResist; + ibs.StrikeThrough = item->StrikeThrough; + ibs.ExtraDmgSkill = item->ExtraDmgSkill; + ibs.ExtraDmgAmt = item->ExtraDmgAmt; + ibs.SpellShield = item->SpellShield; + ibs.Avoidance = item->Avoidance; + ibs.Accuracy = item->Accuracy; + ibs.CharmFileID = item->CharmFileID; + ibs.FactionAmt1 = item->FactionAmt1; + ibs.FactionMod1 = item->FactionMod1; + ibs.FactionAmt2 = item->FactionAmt2; + ibs.FactionMod2 = item->FactionMod2; + ibs.FactionAmt3 = item->FactionAmt3; + ibs.FactionMod3 = item->FactionMod3; + ibs.FactionAmt4 = item->FactionAmt4; + ibs.FactionMod4 = item->FactionMod4; + + ss.write((const char*)&ibs, sizeof(RoF2::structs::ItemBodyStruct)); + + //charm text + if (strlen(item->CharmFile) > 0) + { + ss.write((const char*)item->CharmFile, strlen(item->CharmFile)); + ss.write((const char*)&null_term, sizeof(uint8)); + } + else + { + ss.write((const char*)&null_term, sizeof(uint8)); + } + + //_log(NET__ERROR, "ItemBody secondary struct is %i bytes", sizeof(RoF2::structs::ItemSecondaryBodyStruct)); + RoF2::structs::ItemSecondaryBodyStruct isbs; + memset(&isbs, 0, sizeof(RoF2::structs::ItemSecondaryBodyStruct)); + + isbs.augtype = item->AugType; + isbs.augdistiller = 65535; + isbs.augrestrict = item->AugRestrict; + + for (int x = AUG_BEGIN; x < EmuConstants::ITEM_COMMON_SIZE; ++x) + { + isbs.augslots[x].type = item->AugSlotType[x]; + isbs.augslots[x].visible = item->AugSlotVisible[x]; + isbs.augslots[x].unknown = item->AugSlotUnk2[x]; + } + + // Increased to 6 max aug slots + isbs.augslots[5].type = 0; + isbs.augslots[5].visible = 1; + isbs.augslots[5].unknown = 0; + + isbs.ldonpoint_type = item->PointType; + isbs.ldontheme = item->LDoNTheme; + isbs.ldonprice = item->LDoNPrice; + isbs.ldonsellbackrate = item->LDoNSellBackRate; + isbs.ldonsold = item->LDoNSold; + + isbs.bagtype = item->BagType; + isbs.bagslots = item->BagSlots; + isbs.bagsize = item->BagSize; + isbs.wreduction = item->BagWR; + + isbs.book = item->Book; + isbs.booktype = item->BookType; + + ss.write((const char*)&isbs, sizeof(RoF2::structs::ItemSecondaryBodyStruct)); + + if (strlen(item->Filename) > 0) + { + ss.write((const char*)item->Filename, strlen(item->Filename)); + ss.write((const char*)&null_term, sizeof(uint8)); + } + else + { + ss.write((const char*)&null_term, sizeof(uint8)); + } + + //_log(NET__ERROR, "ItemBody tertiary struct is %i bytes", sizeof(RoF2::structs::ItemTertiaryBodyStruct)); + RoF2::structs::ItemTertiaryBodyStruct itbs; + memset(&itbs, 0, sizeof(RoF2::structs::ItemTertiaryBodyStruct)); + + itbs.loregroup = item->LoreGroup; + itbs.artifact = item->ArtifactFlag; + itbs.summonedflag = item->SummonedFlag; + itbs.favor = item->Favor; + itbs.fvnodrop = item->FVNoDrop; + itbs.dotshield = item->DotShielding; + itbs.atk = item->Attack; + itbs.haste = item->Haste; + itbs.damage_shield = item->DamageShield; + itbs.guildfavor = item->GuildFavor; + itbs.augdistil = item->AugDistiller; + itbs.unknown3 = 0xffffffff; + itbs.unknown4 = 0; + itbs.no_pet = item->NoPet; + itbs.unknown5 = 0; + + itbs.potion_belt_enabled = item->PotionBelt; + itbs.potion_belt_slots = item->PotionBeltSlots; + itbs.stacksize = stackable ? item->StackSize : 0; + itbs.no_transfer = item->NoTransfer; + itbs.expendablearrow = item->ExpendableArrow; + + itbs.unknown8 = 0; + itbs.unknown9 = 0; + itbs.unknown10 = 0; + itbs.unknown11 = 0; + itbs.unknown12 = 0; + itbs.unknown13 = 0; + itbs.unknown14 = 0; + + ss.write((const char*)&itbs, sizeof(RoF2::structs::ItemTertiaryBodyStruct)); + + // Effect Structures Broken down to allow variable length strings for effect names + int32 effect_unknown = 0; + + //_log(NET__ERROR, "ItemBody Click effect struct is %i bytes", sizeof(RoF2::structs::ClickEffectStruct)); + RoF2::structs::ClickEffectStruct ices; + memset(&ices, 0, sizeof(RoF2::structs::ClickEffectStruct)); + + ices.effect = item->Click.Effect; + ices.level2 = item->Click.Level2; + ices.type = item->Click.Type; + ices.level = item->Click.Level; + ices.max_charges = item->MaxCharges; + ices.cast_time = item->CastTime; + ices.recast = item->RecastDelay; + ices.recast_type = item->RecastType; + + ss.write((const char*)&ices, sizeof(RoF2::structs::ClickEffectStruct)); + + if (strlen(item->ClickName) > 0) + { + ss.write((const char*)item->ClickName, strlen(item->ClickName)); + ss.write((const char*)&null_term, sizeof(uint8)); + } + else + { + ss.write((const char*)&null_term, sizeof(uint8)); + } + + ss.write((const char*)&effect_unknown, sizeof(int32)); // clickunk7 + + //_log(NET__ERROR, "ItemBody proc effect struct is %i bytes", sizeof(RoF2::structs::ProcEffectStruct)); + RoF2::structs::ProcEffectStruct ipes; + memset(&ipes, 0, sizeof(RoF2::structs::ProcEffectStruct)); + + ipes.effect = item->Proc.Effect; + ipes.level2 = item->Proc.Level2; + ipes.type = item->Proc.Type; + ipes.level = item->Proc.Level; + ipes.procrate = item->ProcRate; + + ss.write((const char*)&ipes, sizeof(RoF2::structs::ProcEffectStruct)); + + if (strlen(item->ProcName) > 0) + { + ss.write((const char*)item->ProcName, strlen(item->ProcName)); + ss.write((const char*)&null_term, sizeof(uint8)); + } + else + { + ss.write((const char*)&null_term, sizeof(uint8)); + } + + ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown5 + + //_log(NET__ERROR, "ItemBody worn effect struct is %i bytes", sizeof(RoF2::structs::WornEffectStruct)); + RoF2::structs::WornEffectStruct iwes; + memset(&iwes, 0, sizeof(RoF2::structs::WornEffectStruct)); + + iwes.effect = item->Worn.Effect; + iwes.level2 = item->Worn.Level2; + iwes.type = item->Worn.Type; + iwes.level = item->Worn.Level; + + ss.write((const char*)&iwes, sizeof(RoF2::structs::WornEffectStruct)); + + if (strlen(item->WornName) > 0) + { + ss.write((const char*)item->WornName, strlen(item->WornName)); + ss.write((const char*)&null_term, sizeof(uint8)); + } + else + { + ss.write((const char*)&null_term, sizeof(uint8)); + } + + ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + + RoF2::structs::WornEffectStruct ifes; + memset(&ifes, 0, sizeof(RoF2::structs::WornEffectStruct)); + + ifes.effect = item->Focus.Effect; + ifes.level2 = item->Focus.Level2; + ifes.type = item->Focus.Type; + ifes.level = item->Focus.Level; + + ss.write((const char*)&ifes, sizeof(RoF2::structs::WornEffectStruct)); + + if (strlen(item->FocusName) > 0) + { + ss.write((const char*)item->FocusName, strlen(item->FocusName)); + ss.write((const char*)&null_term, sizeof(uint8)); + } + else + { + ss.write((const char*)&null_term, sizeof(uint8)); + } + + ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + + RoF2::structs::WornEffectStruct ises; + memset(&ises, 0, sizeof(RoF2::structs::WornEffectStruct)); + + ises.effect = item->Scroll.Effect; + ises.level2 = item->Scroll.Level2; + ises.type = item->Scroll.Type; + ises.level = item->Scroll.Level; + + ss.write((const char*)&ises, sizeof(RoF2::structs::WornEffectStruct)); + + if (strlen(item->ScrollName) > 0) + { + ss.write((const char*)item->ScrollName, strlen(item->ScrollName)); + ss.write((const char*)&null_term, sizeof(uint8)); + } + else + { + ss.write((const char*)&null_term, sizeof(uint8)); + } + + ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + + // Bard Effect? + RoF2::structs::WornEffectStruct ibes; + memset(&ibes, 0, sizeof(RoF2::structs::WornEffectStruct)); + + ibes.effect = 0xffffffff; + ibes.level2 = 0; + ibes.type = 0; + ibes.level = 0; + //ibes.unknown6 = 0xffffffff; + + ss.write((const char*)&ibes, sizeof(RoF2::structs::WornEffectStruct)); + + /* + if(strlen(item->BardName) > 0) + { + ss.write((const char*)item->BardName, strlen(item->BardName)); + ss.write((const char*)&null_term, sizeof(uint8)); + } + else */ + ss.write((const char*)&null_term, sizeof(uint8)); + + ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + // End of Effects + + //_log(NET__ERROR, "ItemBody Quaternary effect struct is %i bytes", sizeof(RoF2::structs::ItemQuaternaryBodyStruct)); + RoF2::structs::ItemQuaternaryBodyStruct iqbs; + memset(&iqbs, 0, sizeof(RoF2::structs::ItemQuaternaryBodyStruct)); + + iqbs.scriptfileid = item->ScriptFileID; + iqbs.quest_item = item->QuestItemFlag; + iqbs.Power = 0; + iqbs.Purity = item->Purity; + iqbs.unknown16 = 0; + iqbs.BackstabDmg = item->BackstabDmg; + iqbs.DSMitigation = item->DSMitigation; + iqbs.HeroicStr = item->HeroicStr; + iqbs.HeroicInt = item->HeroicInt; + iqbs.HeroicWis = item->HeroicWis; + iqbs.HeroicAgi = item->HeroicAgi; + iqbs.HeroicDex = item->HeroicDex; + iqbs.HeroicSta = item->HeroicSta; + iqbs.HeroicCha = item->HeroicCha; + iqbs.HeroicMR = item->HeroicMR; + iqbs.HeroicFR = item->HeroicFR; + iqbs.HeroicCR = item->HeroicCR; + iqbs.HeroicDR = item->HeroicDR; + iqbs.HeroicPR = item->HeroicPR; + iqbs.HeroicSVCorrup = item->HeroicSVCorrup; + iqbs.HealAmt = item->HealAmt; + iqbs.SpellDmg = item->SpellDmg; + iqbs.clairvoyance = item->Clairvoyance; + iqbs.unknown28 = 0; + + + // Begin RoF2 Test + iqbs.unknown_TEST1 = 0; + // End RoF2 Test + + iqbs.unknown30 = 0; + iqbs.unknown39 = 1; + + iqbs.subitem_count = 0; + + char *SubSerializations[10]; // + + uint32 SubLengths[10]; + + for (int x = SUB_BEGIN; x < EmuConstants::ITEM_CONTAINER_SIZE; ++x) { + + SubSerializations[x] = nullptr; + + const ItemInst* subitem = ((const ItemInst*)inst)->GetItem(x); + + if (subitem) { + + int SubSlotNumber; + + iqbs.subitem_count++; + + if (slot_id_in >= EmuConstants::GENERAL_BEGIN && slot_id_in <= EmuConstants::GENERAL_END) // (< 30) - no cursor? + //SubSlotNumber = (((slot_id_in + 3) * 10) + x + 1); + SubSlotNumber = (((slot_id_in + 3) * EmuConstants::ITEM_CONTAINER_SIZE) + x + 1); + else if (slot_id_in >= EmuConstants::BANK_BEGIN && slot_id_in <= EmuConstants::BANK_END) + //SubSlotNumber = (((slot_id_in - 2000) * 10) + 2030 + x + 1); + SubSlotNumber = (((slot_id_in - EmuConstants::BANK_BEGIN) * EmuConstants::ITEM_CONTAINER_SIZE) + EmuConstants::BANK_BAGS_BEGIN + x); + else if (slot_id_in >= EmuConstants::SHARED_BANK_BEGIN && slot_id_in <= EmuConstants::SHARED_BANK_END) + //SubSlotNumber = (((slot_id_in - 2500) * 10) + 2530 + x + 1); + SubSlotNumber = (((slot_id_in - EmuConstants::SHARED_BANK_BEGIN) * EmuConstants::ITEM_CONTAINER_SIZE) + EmuConstants::SHARED_BANK_BAGS_BEGIN + x); + else + SubSlotNumber = slot_id_in; // ??????? + + /* + // TEST CODE: + SubSlotNumber = Inventory::CalcSlotID(slot_id_in, x); + */ + + SubSerializations[x] = SerializeItem(subitem, SubSlotNumber, &SubLengths[x], depth + 1); + } + } + + ss.write((const char*)&iqbs, sizeof(RoF2::structs::ItemQuaternaryBodyStruct)); + + for (int x = SUB_BEGIN; x < EmuConstants::ITEM_CONTAINER_SIZE; ++x) { + + if (SubSerializations[x]) { + + ss.write((const char*)&x, sizeof(uint32)); + + ss.write(SubSerializations[x], SubLengths[x]); + + safe_delete_array(SubSerializations[x]); + } + } + + char* item_serial = new char[ss.tellp()]; + memset(item_serial, 0, ss.tellp()); + memcpy(item_serial, ss.str().c_str(), ss.tellp()); + + *length = ss.tellp(); + return item_serial; + } + + static inline structs::ItemSlotStruct ServerToRoF2Slot(uint32 ServerSlot) + { + structs::ItemSlotStruct RoF2Slot; + RoF2Slot.SlotType = INVALID_INDEX; + RoF2Slot.Unknown02 = NOT_USED; + RoF2Slot.MainSlot = INVALID_INDEX; + RoF2Slot.SubSlot = INVALID_INDEX; + RoF2Slot.AugSlot = INVALID_INDEX; + RoF2Slot.Unknown01 = NOT_USED; + + uint32 TempSlot = 0; + + if (ServerSlot < 56 || ServerSlot == MainPowerSource) { // Main Inventory and Cursor + RoF2Slot.SlotType = maps::MapPossessions; + RoF2Slot.MainSlot = ServerSlot; + + if (ServerSlot == MainPowerSource) + RoF2Slot.MainSlot = slots::MainPowerSource; + + else if (ServerSlot >= MainCursor) // Cursor and Extended Corpse Inventory + RoF2Slot.MainSlot += 3; + + else if (ServerSlot >= MainAmmo) // (> 20) + RoF2Slot.MainSlot += 1; + } + + /*else if (ServerSlot < 51) { // Cursor Buffer + RoF2Slot.SlotType = maps::MapLimbo; + RoF2Slot.MainSlot = ServerSlot - 31; + }*/ + + else if (ServerSlot >= EmuConstants::GENERAL_BAGS_BEGIN && ServerSlot <= EmuConstants::CURSOR_BAG_END) { // (> 250 && < 341) + RoF2Slot.SlotType = maps::MapPossessions; + TempSlot = ServerSlot - 1; + RoF2Slot.MainSlot = int(TempSlot / EmuConstants::ITEM_CONTAINER_SIZE) - 2; + RoF2Slot.SubSlot = TempSlot - ((RoF2Slot.MainSlot + 2) * EmuConstants::ITEM_CONTAINER_SIZE); + + if (RoF2Slot.MainSlot >= slots::MainGeneral9) // (> 30) + RoF2Slot.MainSlot = slots::MainCursor; + } + + else if (ServerSlot >= EmuConstants::TRIBUTE_BEGIN && ServerSlot <= EmuConstants::TRIBUTE_END) { // Tribute + RoF2Slot.SlotType = maps::MapTribute; + RoF2Slot.MainSlot = ServerSlot - EmuConstants::TRIBUTE_BEGIN; + } + + else if (ServerSlot >= EmuConstants::BANK_BEGIN && ServerSlot <= EmuConstants::BANK_BAGS_END) { + RoF2Slot.SlotType = maps::MapBank; + TempSlot = ServerSlot - EmuConstants::BANK_BEGIN; + RoF2Slot.MainSlot = TempSlot; + + if (TempSlot > 30) { // (> 30) + RoF2Slot.MainSlot = int(TempSlot / EmuConstants::ITEM_CONTAINER_SIZE) - 3; + RoF2Slot.SubSlot = TempSlot - ((RoF2Slot.MainSlot + 3) * EmuConstants::ITEM_CONTAINER_SIZE); + } + } + + else if (ServerSlot >= EmuConstants::SHARED_BANK_BEGIN && ServerSlot <= EmuConstants::SHARED_BANK_BAGS_END) { + RoF2Slot.SlotType = maps::MapSharedBank; + TempSlot = ServerSlot - EmuConstants::SHARED_BANK_BEGIN; + RoF2Slot.MainSlot = TempSlot; + + if (TempSlot > 30) { // (> 30) + RoF2Slot.MainSlot = int(TempSlot / EmuConstants::ITEM_CONTAINER_SIZE) - 3; + RoF2Slot.SubSlot = TempSlot - ((RoF2Slot.MainSlot + 3) * EmuConstants::ITEM_CONTAINER_SIZE); + } + } + + else if (ServerSlot >= EmuConstants::TRADE_BEGIN && ServerSlot <= EmuConstants::TRADE_BAGS_END) { + RoF2Slot.SlotType = maps::MapTrade; + TempSlot = ServerSlot - EmuConstants::TRADE_BEGIN; + RoF2Slot.MainSlot = TempSlot; + + if (TempSlot > 30) { + RoF2Slot.MainSlot = int(TempSlot / EmuConstants::ITEM_CONTAINER_SIZE) - 3; + RoF2Slot.SubSlot = TempSlot - ((RoF2Slot.MainSlot + 3) * EmuConstants::ITEM_CONTAINER_SIZE); + } + + /* + // OLD CODE: + if (TempSlot > 99) { + if (TempSlot > 100) + RoF2Slot.MainSlot = int((TempSlot - 100) / 10); + + else + RoF2Slot.MainSlot = 0; + + RoF2Slot.SubSlot = TempSlot - (100 + RoF2Slot.MainSlot); + } + */ + } + + else if (ServerSlot >= EmuConstants::WORLD_BEGIN && ServerSlot <= EmuConstants::WORLD_END) { + RoF2Slot.SlotType = maps::MapWorld; + TempSlot = ServerSlot - EmuConstants::WORLD_BEGIN; + RoF2Slot.MainSlot = TempSlot; + } + + _log(NET__ERROR, "Convert Server Slot %i to RoF2 Slots: Type %i, Unk2 %i, Main %i, Sub %i, Aug %i, Unk1 %i", ServerSlot, RoF2Slot.SlotType, RoF2Slot.Unknown02, RoF2Slot.MainSlot, RoF2Slot.SubSlot, RoF2Slot.AugSlot, RoF2Slot.Unknown01); + + return RoF2Slot; + } + + static inline structs::MainInvItemSlotStruct ServerToRoF2MainInvSlot(uint32 ServerSlot) + { + structs::MainInvItemSlotStruct RoF2Slot; + RoF2Slot.MainSlot = INVALID_INDEX; + RoF2Slot.SubSlot = INVALID_INDEX; + RoF2Slot.AugSlot = INVALID_INDEX; + RoF2Slot.Unknown01 = NOT_USED; + + uint32 TempSlot = 0; + + if (ServerSlot < 56 || ServerSlot == MainPowerSource) { // (< 52) + RoF2Slot.MainSlot = ServerSlot; + + if (ServerSlot == MainPowerSource) + RoF2Slot.MainSlot = slots::MainPowerSource; + + else if (ServerSlot >= MainCursor) // Cursor and Extended Corpse Inventory + RoF2Slot.MainSlot += 3; + + else if (ServerSlot >= MainAmmo) // Ammo and Personl Inventory + RoF2Slot.MainSlot += 1; + + /*else if (ServerSlot >= MainCursor) { // Cursor + RoF2Slot.MainSlot = slots::MainCursor; + + if (ServerSlot > 30) + RoF2Slot.SubSlot = (ServerSlot + 3) - 33; + }*/ + } + + else if (ServerSlot >= EmuConstants::GENERAL_BAGS_BEGIN && ServerSlot <= EmuConstants::CURSOR_BAG_END) { + TempSlot = ServerSlot - 1; + RoF2Slot.MainSlot = int(TempSlot / EmuConstants::ITEM_CONTAINER_SIZE) - 2; + RoF2Slot.SubSlot = TempSlot - ((RoF2Slot.MainSlot + 2) * EmuConstants::ITEM_CONTAINER_SIZE); + } + + _log(NET__ERROR, "Convert Server Slot %i to RoF2 Slots: Main %i, Sub %i, Aug %i, Unk1 %i", ServerSlot, RoF2Slot.MainSlot, RoF2Slot.SubSlot, RoF2Slot.AugSlot, RoF2Slot.Unknown01); + + return RoF2Slot; + } + + static inline uint32 ServerToRoF2CorpseSlot(uint32 ServerCorpse) + { + //uint32 RoF2Corpse; + return (ServerCorpse + 1); + } + + static inline uint32 RoF2ToServerSlot(structs::ItemSlotStruct RoF2Slot) + { + uint32 ServerSlot = INVALID_INDEX; + uint32 TempSlot = 0; + + if (RoF2Slot.SlotType == maps::MapPossessions && RoF2Slot.MainSlot < 57) { // Worn/Personal Inventory and Cursor (< 51) + if (RoF2Slot.MainSlot == slots::MainPowerSource) + TempSlot = MainPowerSource; + + else if (RoF2Slot.MainSlot >= slots::MainCursor) // Cursor and Extended Corpse Inventory + TempSlot = RoF2Slot.MainSlot - 3; + + /*else if (RoF2Slot.MainSlot == slots::MainGeneral9 || RoF2Slot.MainSlot == slots::MainGeneral10) { // 9th and 10th RoF2 inventory/corpse slots + // Need to figure out what to do when we get these + + // The slot range of 0 - client_max is cross-utilized between player inventory and corpse inventory. + // In the case of RoF2, player inventory is addressed as 0 - 33 and corpse inventory is addressed as 23 - 56. + // We 'could' assign the two new inventory slots as 9997 and 9998, and then work around their bag + // slot assignments, but doing so may disrupt our ability to utilize the corpse looting range properly. + + // For now, it's probably best to leave as-is and let this work itself out in the inventory rework. + }*/ + + else if (RoF2Slot.MainSlot >= slots::MainAmmo) // Ammo and Main Inventory + TempSlot = RoF2Slot.MainSlot - 1; + + else // Worn Slots + TempSlot = RoF2Slot.MainSlot; + + if (RoF2Slot.SubSlot >= SUB_BEGIN) // Bag Slots + TempSlot = ((TempSlot + 3) * EmuConstants::ITEM_CONTAINER_SIZE) + RoF2Slot.SubSlot + 1; + + ServerSlot = TempSlot; + } + + else if (RoF2Slot.SlotType == maps::MapBank) { + TempSlot = EmuConstants::BANK_BEGIN; + + if (RoF2Slot.SubSlot >= SUB_BEGIN) + TempSlot += ((RoF2Slot.MainSlot + 3) * EmuConstants::ITEM_CONTAINER_SIZE) + RoF2Slot.SubSlot + 1; + + else + TempSlot += RoF2Slot.MainSlot; + + ServerSlot = TempSlot; + } + + else if (RoF2Slot.SlotType == maps::MapSharedBank) { + TempSlot = EmuConstants::SHARED_BANK_BEGIN; + + if (RoF2Slot.SubSlot >= SUB_BEGIN) + TempSlot += ((RoF2Slot.MainSlot + 3) * EmuConstants::ITEM_CONTAINER_SIZE) + RoF2Slot.SubSlot + 1; + + else + TempSlot += RoF2Slot.MainSlot; + + ServerSlot = TempSlot; + } + + else if (RoF2Slot.SlotType == maps::MapTrade) { + TempSlot = EmuConstants::TRADE_BEGIN; + + if (RoF2Slot.SubSlot >= SUB_BEGIN) + TempSlot += ((RoF2Slot.MainSlot + 3) * EmuConstants::ITEM_CONTAINER_SIZE) + RoF2Slot.SubSlot + 1; + // OLD CODE: + //TempSlot += 100 + (RoF2Slot.MainSlot * EmuConstants::ITEM_CONTAINER_SIZE) + RoF2Slot.SubSlot; + + else + TempSlot += RoF2Slot.MainSlot; + + ServerSlot = TempSlot; + } + + else if (RoF2Slot.SlotType == maps::MapWorld) { + TempSlot = EmuConstants::WORLD_BEGIN; + + if (RoF2Slot.MainSlot >= SUB_BEGIN) + TempSlot += RoF2Slot.MainSlot; + + ServerSlot = TempSlot; + } + + /*else if (RoF2Slot.SlotType == maps::MapLimbo) { // Cursor Buffer + TempSlot = 31; + + if (RoF2Slot.MainSlot >= 0) + TempSlot += RoF2Slot.MainSlot; + + ServerSlot = TempSlot; + }*/ + + else if (RoF2Slot.SlotType == maps::MapGuildTribute) { + ServerSlot = INVALID_INDEX; + } + + _log(NET__ERROR, "Convert RoF2 Slots: Type %i, Unk2 %i, Main %i, Sub %i, Aug %i, Unk1 %i to Server Slot %i", RoF2Slot.SlotType, RoF2Slot.Unknown02, RoF2Slot.MainSlot, RoF2Slot.SubSlot, RoF2Slot.AugSlot, RoF2Slot.Unknown01, ServerSlot); + + return ServerSlot; + } + + static inline uint32 RoF2ToServerMainInvSlot(structs::MainInvItemSlotStruct RoF2Slot) + { + uint32 ServerSlot = INVALID_INDEX; + uint32 TempSlot = 0; + + if (RoF2Slot.MainSlot < 57) { // Worn/Personal Inventory and Cursor (< 33) + if (RoF2Slot.MainSlot == slots::MainPowerSource) + TempSlot = MainPowerSource; + + else if (RoF2Slot.MainSlot >= slots::MainCursor) // Cursor and Extended Corpse Inventory + TempSlot = RoF2Slot.MainSlot - 3; + + /*else if (RoF2Slot.MainSlot == slots::MainGeneral9 || RoF2Slot.MainSlot == slots::MainGeneral10) { // 9th and 10th RoF2 inventory slots + // Need to figure out what to do when we get these + + // Same as above + }*/ + + else if (RoF2Slot.MainSlot >= slots::MainAmmo) // Main Inventory and Ammo Slots + TempSlot = RoF2Slot.MainSlot - 1; + + else + TempSlot = RoF2Slot.MainSlot; + + if (RoF2Slot.SubSlot >= SUB_BEGIN) // Bag Slots + TempSlot = ((TempSlot + 3) * EmuConstants::ITEM_CONTAINER_SIZE) + RoF2Slot.SubSlot + 1; + + ServerSlot = TempSlot; + } + + _log(NET__ERROR, "Convert RoF2 Slots: Main %i, Sub %i, Aug %i, Unk1 %i to Server Slot %i", RoF2Slot.MainSlot, RoF2Slot.SubSlot, RoF2Slot.AugSlot, RoF2Slot.Unknown01, ServerSlot); + + return ServerSlot; + } + + static inline uint32 RoF2ToServerCorpseSlot(uint32 RoF2Corpse) + { + //uint32 ServerCorpse; + return (RoF2Corpse - 1); + } +} +// end namespace RoF2 diff --git a/common/patches/rof2.h b/common/patches/rof2.h new file mode 100644 index 000000000..b39849048 --- /dev/null +++ b/common/patches/rof2.h @@ -0,0 +1,37 @@ +#ifndef RoF2_H_ +#define RoF2_H_ + +#include "../struct_strategy.h" + +class EQStreamIdentifier; + +namespace RoF2 { + + //these are the only public member of this namespace. + extern void Register(EQStreamIdentifier &into); + extern void Reload(); + + + + //you should not directly access anything below.. + //I just dont feel like making a seperate header for it. + + class Strategy : public StructStrategy { + public: + Strategy(); + + protected: + + virtual std::string Describe() const; + virtual const EQClientVersion ClientVersion() const; + + //magic macro to declare our opcode processors + #include "ss_declare.h" + #include "rof2_ops.h" + }; + +}; + + + +#endif /*RoF2_H_*/ diff --git a/common/patches/rof2_constants.h b/common/patches/rof2_constants.h new file mode 100644 index 000000000..596ffa7e7 --- /dev/null +++ b/common/patches/rof2_constants.h @@ -0,0 +1,217 @@ +/* +EQEMu: Everquest Server Emulator + +Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY except by those people which sell it, which +are required to give you total support for your newly bought product; +without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef RoF2_CONSTANTS_H_ +#define RoF2_CONSTANTS_H_ + +#include "../types.h" + +namespace RoF2 { + namespace maps { + typedef enum : int16 { + MapPossessions = 0, + MapBank, + MapSharedBank, + MapTrade, + MapWorld, + MapLimbo, + MapTribute, + MapTrophyTribute, + MapGuildTribute, + MapMerchant, + MapDeleted, + MapCorpse, + MapBazaar, + MapInspect, + MapRealEstate, + MapViewMODPC, + MapViewMODBank, + MapViewMODSharedBank, + MapViewMODLimbo, + MapAltStorage, + MapArchived, + MapMail, + MapGuildTrophyTribute, + MapKrono, + MapOther, + _MapCount + } InventoryMaps; + } + + namespace slots { + typedef enum : int16 { + MainCharm = 0, + MainEar1, + MainHead, + MainFace, + MainEar2, + MainNeck, + MainShoulders, + MainArms, + MainBack, + MainWrist1, + MainWrist2, + MainRange, + MainHands, + MainPrimary, + MainSecondary, + MainFinger1, + MainFinger2, + MainChest, + MainLegs, + MainFeet, + MainWaist, + MainPowerSource, + MainAmmo, + MainGeneral1, + MainGeneral2, + MainGeneral3, + MainGeneral4, + MainGeneral5, + MainGeneral6, + MainGeneral7, + MainGeneral8, + MainGeneral9, + MainGeneral10, + MainCursor, + _MainCount, + _MainEquipmentBegin = MainCharm, + _MainEquipmentEnd = MainAmmo, + _MainEquipmentCount = (_MainEquipmentEnd - _MainEquipmentBegin + 1), + _MainGeneralBegin = MainGeneral1, + _MainGeneralEnd = MainGeneral10, + _MainGeneralCount = (_MainGeneralEnd - _MainGeneralBegin + 1) + } EquipmentSlots; + } + + namespace consts { + static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount; + static const uint16 MAP_BANK_SIZE = 24; + static const uint16 MAP_SHARED_BANK_SIZE = 2; + static const uint16 MAP_TRADE_SIZE = 8; + static const uint16 MAP_WORLD_SIZE = 10; + static const uint16 MAP_LIMBO_SIZE = 36; + static const uint16 MAP_TRIBUTE_SIZE = 0; //? + static const uint16 MAP_TROPHY_TRIBUTE_SIZE = 0; + static const uint16 MAP_GUILD_TRIBUTE_SIZE = 0; + static const uint16 MAP_MERCHANT_SIZE = 0; + static const uint16 MAP_DELETED_SIZE = 0; + static const uint16 MAP_CORPSE_SIZE = slots::_MainCount; + static const uint16 MAP_BAZAAR_SIZE = 200; + static const uint16 MAP_INSPECT_SIZE = slots::_MainEquipmentCount; + static const uint16 MAP_REAL_ESTATE_SIZE = 0; + static const uint16 MAP_VIEW_MOD_PC_SIZE = MAP_POSSESSIONS_SIZE; + static const uint16 MAP_VIEW_MOD_BANK_SIZE = MAP_BANK_SIZE; + static const uint16 MAP_VIEW_MOD_SHARED_BANK_SIZE = MAP_SHARED_BANK_SIZE; + static const uint16 MAP_VIEW_MOD_LIMBO_SIZE = MAP_LIMBO_SIZE; + static const uint16 MAP_ALT_STORAGE_SIZE = 0; + static const uint16 MAP_ARCHIVED_SIZE = 0; + static const uint16 MAP_MAIL_SIZE = 0; + static const uint16 MAP_GUILD_TROPHY_TRIBUTE_SIZE = 0; + static const uint16 MAP_KRONO_SIZE = NOT_USED; + static const uint16 MAP_OTHER_SIZE = 0; + + // most of these definitions will go away with the structure-based system..this maintains compatibility for now + // (bag slots and main slots beyond Possessions are assigned for compatibility with current server coding) + static const int16 EQUIPMENT_BEGIN = slots::MainCharm; + static const int16 EQUIPMENT_END = slots::MainAmmo; + static const uint16 EQUIPMENT_SIZE = slots::_MainEquipmentCount; + + static const int16 GENERAL_BEGIN = slots::MainGeneral1; + static const int16 GENERAL_END = slots::MainGeneral10; + static const uint16 GENERAL_SIZE = slots::_MainGeneralCount; + static const int16 GENERAL_BAGS_BEGIN = 251; + static const int16 GENERAL_BAGS_END_OFFSET = 99; + static const int16 GENERAL_BAGS_END = GENERAL_BAGS_BEGIN + GENERAL_BAGS_END_OFFSET; + + static const int16 CURSOR = slots::MainCursor; + static const int16 CURSOR_BAG_BEGIN = 351; + static const int16 CURSOR_BAG_END_OFFSET = 9; + static const int16 CURSOR_BAG_END = CURSOR_BAG_BEGIN + CURSOR_BAG_END_OFFSET; + + static const int16 BANK_BEGIN = 2000; + static const int16 BANK_END = 2023; + static const int16 BANK_BAGS_BEGIN = 2031; + static const int16 BANK_BAGS_END_OFFSET = 239; + static const int16 BANK_BAGS_END = BANK_BAGS_BEGIN + BANK_BAGS_END_OFFSET; + + static const int16 SHARED_BANK_BEGIN = 2500; + static const int16 SHARED_BANK_END = 2501; + static const int16 SHARED_BANK_BAGS_BEGIN = 2531; + static const int16 SHARED_BANK_BAGS_END_OFFSET = 19; + static const int16 SHARED_BANK_BAGS_END = SHARED_BANK_BAGS_BEGIN + SHARED_BANK_BAGS_END_OFFSET; + + static const int16 TRADE_BEGIN = 3000; + static const int16 TRADE_END = 3007; + static const int16 TRADE_NPC_END = 3003; + static const int16 TRADE_BAGS_BEGIN = 3031; + static const int16 TRADE_BAGS_END_OFFSET = 79; + static const int16 TRADE_BAGS_END = TRADE_BAGS_BEGIN + TRADE_BAGS_END_OFFSET; + + static const int16 WORLD_BEGIN = 4000; + static const int16 WORLD_END = 4009; + + static const int16 TRIBUTE_BEGIN = 400; + static const int16 TRIBUTE_END = 404; + + static const int16 CORPSE_BEGIN = slots::MainGeneral1; + static const int16 CORPSE_END = slots::MainGeneral1 + slots::MainCursor; + + static const uint16 ITEM_COMMON_SIZE = 6; + static const uint16 ITEM_CONTAINER_SIZE = 255; // 255; (server max will be 255..unsure what actual client is - test) + + static const uint32 BANDOLIERS_COUNT = 20; // count = number of bandolier instances + static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance + static const uint32 POTION_BELT_SIZE = 5; + } + + namespace limits { + static const bool ALLOWS_EMPTY_BAG_IN_BAG = true; + static const bool ALLOWS_CLICK_CAST_FROM_BAG = true; + static const bool COIN_HAS_WEIGHT = false; + } + +}; //end namespace RoF2 + +#endif /*RoF2_CONSTANTS_H_*/ + +/* +RoF2 Notes: + ** Structure-based inventory ** +ok Possessions: ( 0, { 0 .. 33 }, -1, -1 ) (Corpse: { 23 .. 56 } [Offset 23]) +ok [Equipment: ( 0, { 0 .. 22 }, -1, -1 )] +ok [General: ( 0, { 23 .. 32 }, -1, -1 )] +ok [Cursor: ( 0, 33, -1, -1 )] + General Bags: ( 0, { 23 .. 32 }, { 0 .. (maxsize - 1) }, -1 ) + Cursor Bags: ( 0, 33, { 0 .. (maxsize - 1) }, -1 ) + + Bank: ( 1, { 0 .. 23 }, -1, -1 ) + Bank Bags: ( 1, { 0 .. 23 }, { 0 .. (maxsize - 1)}, -1 ) + + Shared Bank: ( 2, { 0 .. 1 }, -1, -1 ) + Shared Bank Bags: ( 2, { 0 .. 1 }, { 0 .. (maxsize - 1) }, -1 ) + + Trade: ( 3, { 0 .. 8 }, -1, -1 ) + (Trade Bags: 3031 - 3110 -- server values) + + World: ( 4, { 0 .. 10 }, -1, -1 ) + +*/ diff --git a/common/patches/rof2_itemfields.h b/common/patches/rof2_itemfields.h new file mode 100644 index 000000000..ccba333b5 --- /dev/null +++ b/common/patches/rof2_itemfields.h @@ -0,0 +1,439 @@ +/* + + +These fields must be in the order of how they are serialized! + + + +*/ +#define NEW_TRY +#ifdef NEW_TRY +//* 000 */ I(ItemClass) // Leave this one off on purpose +/* 001 */ S(Name) +/* 002 */ S(Lore) +//* 003 */ C("")//lorefile - Newly Added - Field is Null +/* 004 */ S(IDFile) +/* 005 */ I(ID) +/* 006 */ I(Weight) +/* 007 */ I(NoRent) +/* 008 */ I(NoDrop) +/* 009 */ I(Size) +/* 010 */ I(Slots) +/* 011 */ I(Price) +/* 012 */ I(Icon) +/* 013 */ C("0")//UNK013 +/* 014 */ C("0")//UNK014 +/* 015 */ I(BenefitFlag) +/* 016 */ I(Tradeskills) +/* 017 */ I(CR) +/* 018 */ I(DR) +/* 019 */ I(PR) +/* 020 */ I(MR) +/* 021 */ I(FR) +/* 022 */ C("0")//svcorruption - Newly Added +/* 023 */ I(AStr) +/* 024 */ I(ASta) +/* 025 */ I(AAgi) +/* 026 */ I(ADex) +/* 027 */ I(ACha) +/* 028 */ I(AInt) +/* 029 */ I(AWis) +/* 030 */ I(HP) +/* 031 */ I(Mana) +/* 032 */ I(Endur) //endur - Relocated +/* 033 */ I(AC) +/* 034 */ I(Classes)//classes - Relocated +/* 035 */ I(Races)//races - Relocated +/* 036 */ I(Deity) +/* 037 */ I(SkillModValue) +/* 038 */ C("0")//UNK038 - Default is 0 +/* 039 */ I(SkillModType) +/* 040 */ I(BaneDmgRace) +/* 041 */ I(BaneDmgBody)//banedmgbody - Relocated +/* 042 */ I(BaneDmgRaceAmt)//banedmgraceamt - Relocated +/* 043 */ I(BaneDmgAmt)//banedmgamt - Relocated +/* 044 */ I(Magic) +/* 045 */ I(CastTime_) +/* 046 */ I(ReqLevel) +/* 047 */ I(RecLevel)//reclevel - Relocated +/* 048 */ I(RecSkill)//recskill - Relocated +/* 049 */ I(BardType) +/* 050 */ I(BardValue) +/* 051 */ I(Light) +/* 052 */ I(Delay) +/* 053 */ I(ElemDmgType) +/* 054 */ I(ElemDmgAmt) +/* 055 */ I(Range) +/* 056 */ I(Damage) +/* 057 */ I(Color) +/* 058 */ I(ItemType) +/* 059 */ I(Material) +/* 060 */ C("0")//UNK060 - Default is 0 +/* 061 */ C("0")//UNK061 - Default is 0 +/* 062 */ F(SellRate) +/* 063 */ I(CombatEffects) +/* 064 */ I(Shielding) +/* 065 */ I(StunResist) +/* 066 */ I(StrikeThrough) +/* 067 */ I(ExtraDmgSkill) +/* 068 */ I(ExtraDmgAmt) +/* 069 */ I(SpellShield) +/* 070 */ I(Avoidance) +/* 071 */ I(Accuracy) +/* 072 */ I(CharmFileID) +/* 073 */ I(FactionMod1)//Swapped these so Faction Amt comes after each Faction Mod +/* 074 */ I(FactionAmt1)//Swapped these so Faction Amt comes after each Faction Mod +/* 075 */ I(FactionMod2)//Swapped these so Faction Amt comes after each Faction Mod +/* 076 */ I(FactionAmt2)//Swapped these so Faction Amt comes after each Faction Mod +/* 077 */ I(FactionMod3)//Swapped these so Faction Amt comes after each Faction Mod +/* 078 */ I(FactionAmt3)//Swapped these so Faction Amt comes after each Faction Mod +/* 079 */ I(FactionMod4)//Swapped these so Faction Amt comes after each Faction Mod +/* 080 */ I(FactionAmt4)//Swapped these so Faction Amt comes after each Faction Mod +/* 081 */ S(CharmFile) +/* 082 */ I(AugType) +/* 083 */ I(AugRestrict)//augrestrict - Relocated +/* 084 */ I(AugDistiller)//augdistiller - Relocated +/* 085 */ I(AugSlotType[0]) +/* 086 */ I(AugSlotVisible[0])//augslot1visible - Default 1 +/* 087 */ C("0")//augslot1unk2 - Newly Added - Default 0 +/* 088 */ I(AugSlotType[1]) +/* 089 */ I(AugSlotVisible[1]) +/* 090 */ C("0")//augslot2unk2 - Newly Added +/* 091 */ I(AugSlotType[2]) +/* 092 */ I(AugSlotVisible[2]) +/* 093 */ C("0")//augslot3unk2 - Newly Added +/* 094 */ I(AugSlotType[3]) +/* 095 */ I(AugSlotVisible[3]) +/* 096 */ C("0")//augslot4unk2 - Newly Added +/* 097 */ I(AugSlotType[4]) +/* 098 */ I(AugSlotVisible[4]) +/* 099 */ C("0")//augslot5unk2 - Newly Added +/* 100 */ I(PointType)//pointtype - Relocated +/* 101 */ I(LDoNTheme) +/* 102 */ I(LDoNPrice) +/* 103 */ C("70")//UNK098 - Newly Added - Default 70, but some are set to 0 +/* 104 */ I(LDoNSold) +/* 105 */ I(BagType) +/* 106 */ I(BagSlots) +/* 107 */ I(BagSize) +/* 108 */ I(BagWR) +/* 109 */ I(Book) +/* 110 */ I(BookType) +/* 111 */ S(Filename) +/* 112 */ I(LoreGroup) +/* 113 */ I(ArtifactFlag) +/* 114 */ C("0")//I(PendingLoreFlag)?//UNK109 - Default 0, but a few are 1 +/* 115 */ I(Favor) +/* 116 */ I(GuildFavor)//guildfavor - Relocated +/* 117 */ I(FVNoDrop) +/* 118 */ I(DotShielding) +/* 119 */ I(Attack) +/* 120 */ I(Regen) +/* 121 */ I(ManaRegen) +/* 122 */ I(EnduranceRegen) +/* 123 */ I(Haste) +/* 124 */ I(DamageShield) +/* 125 */ C("-1") //UNK120 - Default is -1 +/* 126 */ C("0") //UNK121 - Default is 0 +/* 127 */ I(Attuneable) +/* 128 */ I(NoPet) +/* 129 */ C("0") //UNK124 - Default 0, but a few are 1 +/* 130 */ I(PotionBelt) +/* 131 */ C("0") //potionbeltslots - Default 0, but a few are 1 +/* 132 */ I(StackSize) +/* 133 */ I(NoTransfer) +/* 134 */ I(Stackable)//UNK129 - Default is 0, but some are much higher +/* 135 */ I(QuestItemFlag)//questitemflag - Default is 0 (off), flag on = 1 +/* 136 */ C("0")//UNK131 - Default is 0, but there is an item set to 1 +/* 137 */ C("0")//UNK132 - Default is 0? 0000000000000000000? +/* 138 */ I(Click.Effect) +/* 139 */ I(Click.Type) +/* 140 */ I(Click.Level2) +/* 141 */ I(Click.Level) +/* 142 */ I(MaxCharges)//maxcharges - Relocated +/* 143 */ I(CastTime_)//casttime - Relocated - Note Duplicate Entries for CastTime_ and none for CastTime +/* 144 */ I(RecastDelay)//recastdelay - Relocated +/* 145 */ I(RecastType)//recasttype - Relocated +/* 146 */ C("0")//clickunk5 - Newly Added - Default is 0 +/* 147 */ C("")//clickname - Newly Added - Default is Null +/* 148 */ C("-1")//clickunk7 - Newly Added - Default is -1, but some set to 0 and some much higher +/* 149 */ I(Proc.Effect) +/* 150 */ I(Proc.Type) +/* 151 */ I(Proc.Level2) +/* 152 */ I(Proc.Level) +/* 153 */ C("0")//procunk1 - Newly Added - Default is 0, but some set to -1 and 1 +/* 154 */ C("0")//procunk2 - Newly Added - Default is 0 +/* 155 */ C("0")//procunk3 - Newly Added - Default is 0 +/* 156 */ C("0")//procunk4 - Newly Added - Default is 0 +/* 157 */ I(ProcRate)//procrate - Relocated +/* 158 */ C("")//procname - Newly Added - Default is Null +/* 159 */ C("-1")//procunk7 - Newly Added - Default is -1, but some set to 0 +/* 160 */ I(Worn.Effect) +/* 161 */ I(Worn.Type) +/* 162 */ I(Worn.Level2) +/* 163 */ I(Worn.Level) +/* 164 */ C("0")//wornunk1 - Newly Added - Default is 0 +/* 165 */ C("0")//wornunk2 - Newly Added - Default is 0 +/* 166 */ C("0")//wornunk3 - Newly Added - Default is 0 +/* 167 */ C("0")//wornunk4 - Newly Added - Default is 0 +/* 168 */ C("0")//wornunk5 - Newly Added - Default is 0 +/* 169 */ C("")//wornname - Newly Added - Default is Null +/* 170 */ C("-1")//wornunk7 - Newly Added - Default is -1, but some set to 0 +/* 171 */ I(Focus.Effect) +/* 172 */ I(Focus.Type) +/* 173 */ I(Focus.Level2) +/* 174 */ I(Focus.Level) +/* 175 */ C("0")//focusunk1 - Newly Added - Default is 0 +/* 176 */ C("0")//focusunk2 - Newly Added - Default is 0 +/* 177 */ C("0")//focusunk3 - Newly Added - Default is 0 +/* 178 */ C("0")//focusunk4 - Newly Added - Default is 0 +/* 179 */ C("0")//focusunk5 - Newly Added - Default is 0 +/* 180 */ C("")//focusname - Newly Added - Default is Null +/* 181 */ C("-1")//focusunk7 - Newly Added - Default is -1, but some set to 0 +/* 182 */ I(Scroll.Effect) +/* 183 */ I(Scroll.Type) +/* 184 */ I(Scroll.Level2) +/* 185 */ I(Scroll.Level) +/* 186 */ C("0")//scrollunk1 - Renumber this*** +/* 187 */ C("0")//scrollunk2 - Newly Added - Default is 0 +/* 188 */ C("0")//scrollunk3 - Newly Added - Default is 0 +/* 189 */ C("0")//scrollunk4 - Newly Added - Default is 0 +/* 190 */ C("0")//scrollunk5 - Newly Added - Default is 0 +/* 191 */ C("")//scrollname - Newly Added - Default is Null +/* 192 */ C("-1")//scrollunk7 - Newly Added - Default is -1, but some set to 0 +/* 193 */ C("0")//UNK193 - Default is 0 +/* 194 */ C("0")//purity - Newly Added - Default is 0, but some go up to 75 +/* 195 */ C("0")//dsmitigation - Newly Added - Default is 0, but some are up to 2 +/* 196 */ C("0")//heroic_str - Newly Added - Default is 0 +/* 197 */ C("0")//heroic_int - Newly Added - Default is 0 +/* 198 */ C("0")//heroic_wis - Newly Added - Default is 0 +/* 199 */ C("0")//heroic_agi - Newly Added - Default is 0 +/* 200 */ C("0")//heroic_dex - Newly Added - Default is 0 +/* 201 */ C("0")//heroic_sta - Newly Added - Default is 0 +/* 202 */ C("0")//heroic_cha - Newly Added - Default is 0 +/* 203 */ C("0")//HeroicSvPoison - Newly Added - Default is 0 +/* 204 */ C("0")//HeroicSvMagic - Newly Added - Default is 0 +/* 205 */ C("0")//HeroicSvFire - Newly Added - Default is 0 +/* 206 */ C("0")//HeroicSvDisease - Newly Added - Default is 0 +/* 207 */ C("0")//HeroicSvCold - Newly Added - Default is 0 +/* 208 */ C("0")//HeroicSvCorruption - Newly Added - Default is 0 +/* 209 */ C("0")//healamt - Newly Added - Default is 0, but some are up to 9 +/* 210 */ C("0")//spelldmg - Newly Added - Default is 0, but some are up to 9 +/* 211 */ C("0")//clairvoyance - Newly Added - Default is 0, but some are up to 10 +/* 212 */ C("0")//backstabdmg - Newly Added - Default is 0, but some are up to 65 +//* 213 */ C("0")//evolvinglevel - Newly Added - Default is 0, but some are up to 7 +//* 214 */ C("0")//MaxPower - Newly Added +//* 215 */ C("0")//Power - Newly Added + +//This doesn't appear to be used /* 102 */ S(verified)//verified +//This doesn't appear to be used /* 102 */ S(serialized)//created +//Unsure where this goes right now (or if it is even used) /* 108 */ I(SummonedFlag) + +#else +/* 000 */ //I(ItemClass) Leave this one off on purpose +/* 001 */ S(Name) +/* 002 */ S(Lore) +/* 003 */ C("") //LoreFile? +/* 003 */ S(IDFile) +/* 004 */ I(ID) +/* 005 */ I(Weight) +/* 006 */ I(NoRent) +/* 007 */ I(NoDrop) +/* 008 */ I(Size) +/* 009 */ I(Slots) +/* 010 */ I(Price) +/* 011 */ I(Icon) +/* 013 */ C("0") +/* 014 */ C("0") +/* 014 */ I(BenefitFlag) +/* 015 */ I(Tradeskills) +/* 016 */ I(CR) +/* 017 */ I(DR) +/* 018 */ I(PR) +/* 019 */ I(MR) +/* 020 */ I(FR) + C("0") //svcorruption +/* 021 */ I(AStr) +/* 022 */ I(ASta) +/* 023 */ I(AAgi) +/* 024 */ I(ADex) +/* 025 */ I(ACha) +/* 026 */ I(AInt) +/* 027 */ I(AWis) +/* 028 */ I(HP) +/* 029 */ I(Mana) + I(Endur) +/* 030 */ I(AC) +/* 052 */ I(Classes) +/* 053 */ I(Races) +/* 031 */ I(Deity) +/* 032 */ I(SkillModValue) +/* 033 */ C("0") +/* 034 */ I(SkillModType) +/* 035 */ I(BaneDmgRace) +/* 037 */ I(BaneDmgBody) +/* 036 */ I(BaneDmgRaceAmt) +/* 036 */ I(BaneDmgAmt) +/* 038 */ I(Magic) +/* 039 */ I(CastTime_) +/* 040 */ I(ReqLevel) +/* 045 */ I(RecLevel) +/* 046 */ I(RecSkill) +/* 041 */ I(BardType) +/* 042 */ I(BardValue) +/* 043 */ I(Light) +/* 044 */ I(Delay) +/* 047 */ I(ElemDmgType) +/* 048 */ I(ElemDmgAmt) +/* 049 */ I(Range) +/* 050 */ I(Damage) +/* 051 */ I(Color) +/* 056 */ I(ItemType) +/* 057 */ I(Material) +/* 060 */ C("0") +/* 061 */ C("0") +/* 058 */ F(SellRate) +/* 063 */ I(CombatEffects) +/* 064 */ I(Shielding) +/* 065 */ I(StunResist) +/* 059 */ //C("0") +/* 061 */ //C("0") +/* 066 */ I(StrikeThrough) +/* 067 */ I(ExtraDmgSkill) +/* 068 */ I(ExtraDmgAmt) +/* 069 */ I(SpellShield) +/* 070 */ I(Avoidance) +/* 071 */ I(Accuracy) +/* 072 */ I(CharmFileID) +/* 073 */ I(FactionMod1) +/* 077 */ I(FactionAmt1) +/* 074 */ I(FactionMod2) +/* 078 */ I(FactionAmt2) +/* 075 */ I(FactionMod3) +/* 079 */ I(FactionAmt3) +/* 076 */ I(FactionMod4) +/* 080 */ I(FactionAmt4) +/* 081 */ S(CharmFile) +/* 082 */ I(AugType) +/* 082 */ I(AugRestrict) +/* 082 */ I(AugDistiller) +/* 083 */ I(AugSlotType[0]) +/* 084 */ I(AugSlotVisible[0]) +/* 084 */ I(AugSlotUnk2[0]) +/* 085 */ I(AugSlotType[1]) +/* 086 */ I(AugSlotVisible[1]) +/* 086 */ I(AugSlotUnk2[1]) +/* 087 */ I(AugSlotType[2]) +/* 088 */ I(AugSlotVisible[2]) +/* 088 */ I(AugSlotUnk2[2]) +/* 089 */ I(AugSlotType[3]) +/* 090 */ I(AugSlotVisible[3]) +/* 090 */ I(AugSlotUnk2[3]) +/* 091 */ I(AugSlotType[4]) +/* 092 */ I(AugSlotVisible[4]) +/* 092 */ I(AugSlotUnk2[4]) +/* 093 */ I(PointType) +/* 093 */ I(LDoNTheme) +/* 094 */ I(LDoNPrice) +/* 094 */ C("0") +/* 095 */ I(LDoNSold) +/* 096 */ I(BagType) +/* 097 */ I(BagSlots) +/* 098 */ I(BagSize) +/* 099 */ I(BagWR) +/* 100 */ I(Book) +/* 101 */ I(BookType) +/* 102 */ S(Filename) +/* 105 */ I(LoreGroup) +/* 106 */ //I(PendingLoreFlag) +/* 107 */ I(ArtifactFlag) +/* 094 */ C("0") +/* 108 */ //I(SummonedFlag) +/* 109 */ I(Favor) +/* 121 */ I(GuildFavor) +/* 110 */ I(FVNoDrop) +/* 112 */ I(DotShielding) +/* 113 */ I(Attack) +/* 114 */ I(Regen) +/* 115 */ I(ManaRegen) +/* 116 */ I(EnduranceRegen) +/* 117 */ I(Haste) +/* 118 */ I(DamageShield) +/* 120 */ C("0") +/* 121 */ C("0") +/* 125 */ I(Attuneable) +/* 126 */ I(NoPet) +/* 124 */ C("0") +/* 129 */ I(PotionBelt) +/* 130 */ I(PotionBeltSlots) +/* 131 */ I(StackSize) +/* 132 */ I(NoTransfer) +/* 129 */ C("0") +/* 132 */ I(QuestItemFlag) +/* 131 */ C("0") +/* 132 */ C("00000000000000000000000000000000000000") +/* 134 */ I(Click.Effect) +/* 135 */ I(Click.Type) +/* 136 */ I(Click.Level2) +/* 137 */ I(Click.Level) +/* 055 */ I(MaxCharges) +/* 060 */ I(CastTime) +/* 119 */ I(RecastDelay) +/* 120 */ I(RecastType) +/* 138 */ C("0") //clickunk5 (prolly ProcRate) +/* 138 */ C("") //clickunk6 +/* 138 */ C("-1") //clickunk7 +/* 139 */ I(Proc.Effect) +/* 140 */ I(Proc.Type) +/* 141 */ I(Proc.Level2) +/* 142 */ I(Proc.Level) +/* 143 */ C("0") //procunk1 (prolly MaxCharges) +/* 143 */ C("0") //procunk2 (prolly CastTime) +/* 143 */ C("0") //procunk3 (prolly RecastDelay) +/* 143 */ C("0") //procunk4 (prolly RecastType) +/* 062 */ I(ProcRate) +/* 143 */ C("") //procunk6 +/* 143 */ C("-1") //procunk7 +/* 144 */ I(Worn.Effect) +/* 145 */ I(Worn.Type) +/* 146 */ I(Worn.Level2) +/* 147 */ I(Worn.Level) +/* 143 */ C("0") //wornunk1 (prolly MaxCharges) +/* 143 */ C("0") //wornunk2 (prolly CastTime) +/* 143 */ C("0") //wornunk3 (prolly RecastDelay) +/* 143 */ C("0") //wornunk4 (prolly RecastType) +/* 143 */ C("0") //wornunk5 (prolly ProcRate) +/* 143 */ C("") //wornunk6 +/* 143 */ C("-1") //wornunk7 +/* 149 */ I(Focus.Effect) +/* 150 */ I(Focus.Type) +/* 151 */ I(Focus.Level2) +/* 152 */ I(Focus.Level) +/* 143 */ C("0") //focusunk1 (prolly MaxCharges) +/* 143 */ C("0") //focusunk2 (prolly CastTime) +/* 143 */ C("0") //focusunk3 (prolly RecastDelay) +/* 143 */ C("0") //focusunk4 (prolly RecastType) +/* 143 */ C("0") //focusunk5 (prolly ProcRate) +/* 143 */ C("") //focusunk6 +/* 143 */ C("-1") //focusunk7 +/* 154 */ I(Scroll.Effect) +/* 155 */ I(Scroll.Type) +/* 156 */ I(Scroll.Level2) +/* 157 */ I(Scroll.Level) +/* 143 */ C("0") //scrollunk1 (prolly MaxCharges) +/* 143 */ C("0") //scrollunk2 (prolly CastTime) +/* 143 */ C("0") //scrollunk3 (prolly RecastDelay) +/* 143 */ C("0") //scrollunk4 (prolly RecastType) +/* 143 */ C("0") //scrollunk5 (prolly ProcRate) +/* 143 */ C("") //scrollunk6 +/* 143 */ C("-1") //scrollunk7 +/* 193 */ C("0") //Power Source Capacity +/* 194 */ C("0") //purity + +#endif + +#undef I +#undef C +#undef S +#undef F + diff --git a/common/patches/rof2_ops.h b/common/patches/rof2_ops.h new file mode 100644 index 000000000..fbdd20575 --- /dev/null +++ b/common/patches/rof2_ops.h @@ -0,0 +1,173 @@ +// out-going packets that require an ENCODE translation: +// Begin RoF2 Encodes + +// incoming packets that require a DECODE translation: +// Begin RoF2 Decodes + + +// End RoF2 Encodes/Decodes + +// These require Encodes/Decodes for RoF, so they do for RoF2 as well +// Begin RoF Encodes +E(OP_Action) +E(OP_AdventureMerchantSell) +E(OP_AltCurrency) +E(OP_AltCurrencySell) +E(OP_Animation) +E(OP_ApplyPoison) +E(OP_AugmentInfo) +E(OP_Barter) +E(OP_BazaarSearch) +E(OP_BeginCast) +E(OP_BlockedBuffs) +E(OP_Buff) +E(OP_BuffCreate) +E(OP_CancelTrade) +E(OP_CastSpell) +E(OP_ChannelMessage) +E(OP_CharInventory) +E(OP_ClickObjectAction) +E(OP_ClientUpdate) +E(OP_Consider) +E(OP_Damage) +E(OP_DeleteCharge) +E(OP_DeleteItem) +E(OP_DeleteSpawn) +E(OP_DisciplineUpdate) +E(OP_DzCompass) +E(OP_DzExpeditionEndsWarning) +E(OP_DzExpeditionInfo) +E(OP_DzExpeditionList) +E(OP_DzJoinExpeditionConfirm) +E(OP_DzLeaderStatus) +E(OP_DzMemberList) +E(OP_ExpansionInfo) +E(OP_GMLastName) +E(OP_GMTrainSkillConfirm) +E(OP_GroundSpawn) +E(OP_GroupCancelInvite) +E(OP_GroupFollow) +E(OP_GroupFollow2) +E(OP_GroupInvite) +E(OP_GroupUpdate) +E(OP_GuildMemberList) +E(OP_GuildMemberUpdate) +E(OP_GuildsList) +E(OP_HPUpdate) +E(OP_Illusion) +E(OP_InspectBuffs) +E(OP_InspectRequest) +E(OP_InterruptCast) +E(OP_ItemLinkResponse) +E(OP_ItemPacket) +E(OP_ItemVerifyReply) +E(OP_LeadershipExpUpdate) +E(OP_LogServer) +E(OP_LootItem) +E(OP_ManaChange) +E(OP_MercenaryDataResponse) +E(OP_MercenaryDataUpdate) +E(OP_MoveItem) +E(OP_NewSpawn) +E(OP_NewZone) +E(OP_OnLevelMessage) +//E(OP_OpenNewTasksWindow) +E(OP_PetBuffWindow) +E(OP_PlayerProfile) +E(OP_RaidJoin) +E(OP_RaidUpdate) +E(OP_ReadBook) +E(OP_RecipeAutoCombine) +E(OP_RemoveBlockedBuffs) +E(OP_RequestClientZoneChange) +E(OP_RespondAA) +E(OP_RezzRequest) +E(OP_SendAATable) +E(OP_SendCharInfo) +E(OP_SendMembership) +E(OP_SendZonepoints) +E(OP_SetGuildRank) +E(OP_ShopPlayerBuy) +E(OP_ShopPlayerSell) +E(OP_ShopRequest) +E(OP_SkillUpdate) +E(OP_SomeItemPacketMaybe) +E(OP_SpawnAppearance) +E(OP_SpawnDoor) +E(OP_Stun) +E(OP_TargetBuffs) +E(OP_TaskDescription) +E(OP_TaskHistoryReply) +E(OP_Track) +E(OP_Trader) +E(OP_TraderBuy) +E(OP_TributeInfo) +E(OP_TributeItem) +E(OP_VetRewardsAvaliable) +E(OP_WearChange) +E(OP_WhoAllResponse) +E(OP_ZoneChange) +E(OP_ZoneEntry) +E(OP_ZonePlayerToBind) +E(OP_ZoneServerInfo) +E(OP_ZoneSpawns) +// Begin RoF Decodes +D(OP_AdventureMerchantSell) +D(OP_AltCurrencySell) +D(OP_AltCurrencySellSelection) +D(OP_ApplyPoison) +D(OP_AugmentInfo) +D(OP_AugmentItem) +D(OP_BazaarSearch) +D(OP_BlockedBuffs) +D(OP_Buff) +D(OP_BuffRemoveRequest) +D(OP_CastSpell) +D(OP_ChannelMessage) +D(OP_CharacterCreate) +D(OP_ClientUpdate) +D(OP_Consider) +D(OP_ConsiderCorpse) +D(OP_Consume) +D(OP_Damage) +D(OP_DeleteItem) +D(OP_EnvDamage) +D(OP_FaceChange) +D(OP_FindPersonRequest) +D(OP_GMLastName) +D(OP_GroupCancelInvite) +D(OP_GroupDisband) +D(OP_GroupFollow) +D(OP_GroupFollow2) +D(OP_GroupInvite) +D(OP_GroupInvite2) +D(OP_GuildDemote) +D(OP_GuildRemove) +D(OP_GuildStatus) +D(OP_InspectRequest) +D(OP_ItemLinkClick) +D(OP_ItemVerifyRequest) +D(OP_LoadSpellSet) +D(OP_LootItem) +D(OP_MoveItem) +D(OP_PetCommands) +D(OP_RaidInvite) +D(OP_ReadBook) +D(OP_RecipeAutoCombine) +D(OP_RemoveBlockedBuffs) +D(OP_RezzAnswer) +D(OP_Save) +D(OP_SetServerFilter) +D(OP_ShopPlayerBuy) +D(OP_ShopPlayerSell) +D(OP_ShopRequest) +D(OP_Trader) +D(OP_TraderBuy) +D(OP_TradeSkillCombine) +D(OP_TributeItem) +D(OP_WhoAllRequest) +D(OP_ZoneChange) +D(OP_ZoneEntry) +// End RoF Encodes/Decodes +#undef E +#undef D diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h new file mode 100644 index 000000000..4bc9a9bb3 --- /dev/null +++ b/common/patches/rof2_structs.h @@ -0,0 +1,4922 @@ +#ifndef RoF2_STRUCTS_H_ +#define RoF2_STRUCTS_H_ + +namespace RoF2 { + namespace structs { + +/* +** Compiler override to ensure +** byte aligned structures +*/ +#pragma pack(1) + +struct LoginInfo_Struct { +/*000*/ char login_info[64]; +/*064*/ uint8 unknown064[124]; +/*188*/ uint8 zoning; // 01 if zoning, 00 if not +/*189*/ uint8 unknown189[275]; +/*488*/ +}; + +struct EnterWorld_Struct { +/*000*/ char name[64]; +/*064*/ uint32 tutorial; // 01 on "Enter Tutorial", 00 if not +/*068*/ uint32 return_home; // 01 on "Return Home", 00 if not +}; + +//New For SoF +struct WorldObjectsSent_Struct { +}; + +// New for RoF2 - Size: 12 +struct ItemSlotStruct { +/*000*/ int16 SlotType; // Worn and Normal inventory = 0, Bank = 1, Shared Bank = 2, Delete Item = -1 +/*002*/ int16 Unknown02; +/*004*/ int16 MainSlot; +/*006*/ int16 SubSlot; +/*008*/ int16 AugSlot; // Guessing - Seen 0xffff +/*010*/ int16 Unknown01; // Normally 0 - Seen 13262 when deleting an item, but didn't match item ID +/*012*/ +}; + +// New for RoF2 - Used for Merchant_Purchase_Struct +// Can't sellfrom other than main inventory so Slot Type is not needed. +struct MainInvItemSlotStruct { +/*000*/ int16 MainSlot; +/*002*/ int16 SubSlot; +/*004*/ int16 AugSlot; +/*006*/ int16 Unknown01; +/*008*/ +}; + +/* Name Approval Struct */ +/* Len: */ +/* Opcode: 0x8B20*/ +struct NameApproval +{ + char name[64]; + uint32 race; + uint32 class_; + uint32 deity; +}; + +/* +** Entity identification struct +** Size: 4 bytes +** OPCodes: OP_DeleteSpawn, OP_Assist +*/ +struct EntityId_Struct +{ +/*00*/ uint32 entity_id; +/*04*/ +}; + +struct Duel_Struct +{ + uint32 duel_initiator; + uint32 duel_target; +}; + +struct DuelResponse_Struct +{ + uint32 target_id; + uint32 entity_id; + uint32 unknown; +}; + +//Adventure stuff,not a net one,just one for our use +static const uint32 ADVENTURE_COLLECT = 0; +static const uint32 ADVENTURE_MASSKILL = 1; +static const uint32 ADVENTURE_NAMED = 2; +static const uint32 ADVENTURE_RESCUE = 3; + +static const uint32 BUFF_COUNT = 42; // was 25 +static const uint32 BLOCKED_BUFF_COUNT = 30; // was 20 + +static const uint32 MAX_PLAYER_TRIBUTES = 5; +static const uint32 MAX_TRIBUTE_TIERS = 10; +static const uint32 TRIBUTE_NONE = 0xFFFFFFFF; + +static const uint32 MAX_PLAYER_BANDOLIER = 20; +static const uint32 MAX_PLAYER_BANDOLIER_ITEMS = 4; + +static const uint32 MAX_POTIONS_IN_BELT = 5; + +static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16; +static const uint32 MAX_RAID_LEADERSHIP_AA_ARRAY = 16; +static const uint32 MAX_LEADERSHIP_AA_ARRAY = (MAX_GROUP_LEADERSHIP_AA_ARRAY+MAX_RAID_LEADERSHIP_AA_ARRAY); + +static const uint32 MAX_NUMBER_GUILDS = 1500; + +// Used primarily in the Player Profile: +static const uint32 MAX_PP_LANGUAGE = 32; // was 25 +static const uint32 MAX_PP_SPELLBOOK = 720; // was 480 +static const uint32 MAX_PP_MEMSPELL = 16; // was 12 +static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE; // 100 - actual skills buffer size +static const uint32 MAX_PP_AA_ARRAY = 300; +static const uint32 MAX_PP_DISCIPLINES = 200; // was 100 +static const uint32 MAX_GROUP_MEMBERS = 6; +static const uint32 MAX_RECAST_TYPES = 20; + +struct AdventureInfo { + uint32 QuestID; + uint32 NPCID; + bool in_use; + uint32 status; + bool ShowCompass; + uint32 Objetive;// can be item to collect,mobs to kill,boss to kill and someone to rescue. + uint32 ObjetiveValue;// number of items,or number of needed mob kills. + char text[512]; + uint8 type; + uint32 minutes; + uint32 points; + float x; + float y; + uint32 zoneid; + uint32 zonedungeonid; +}; +/////////////////////////////////////////////////////////////////////////////// + + +/* +** Color_Struct +** Size: 4 bytes +** Used for convenience +** Merth: Gave struct a name so gcc 2.96 would compile +** +*/ +struct Color_Struct +{ + union + { + struct + { + uint8 blue; + uint8 green; + uint8 red; + uint8 use_tint; // if there's a tint this is FF + } rgb; + uint32 color; + }; +}; + +struct CharSelectEquip { + //totally guessed; + uint32 equip0; + uint32 equip1; + uint32 equip2; + uint32 itemid; + uint32 equip3; + Color_Struct color; +}; + +struct CharacterSelectEntry_Struct { +/*0000*/ char name[1]; // Name null terminated +/*0000*/ uint8 class_; +/*0000*/ uint32 race; +/*0000*/ uint8 level; +/*0000*/ uint8 class_2; +/*0000*/ uint32 race2; +/*0000*/ uint16 zone; +/*0000*/ uint16 instance; +/*0000*/ uint8 gender; +/*0000*/ uint8 face; +/*0000*/ CharSelectEquip equip[9]; +/*0000*/ uint8 u15; // Seen FF +/*0000*/ uint8 u19; // Seen FF +/*0000*/ uint32 drakkin_tattoo; +/*0000*/ uint32 drakkin_details; +/*0000*/ uint32 deity; +/*0000*/ uint32 primary; +/*0000*/ uint32 secondary; +/*0000*/ uint8 haircolor; +/*0000*/ uint8 beardcolor; +/*0000*/ uint8 eyecolor1; +/*0000*/ uint8 eyecolor2; +/*0000*/ uint8 hairstyle; +/*0000*/ uint8 beard; +/*0000*/ uint8 char_enabled; +/*0000*/ uint8 tutorial; // Seen 1 for new char or 0 for existing +/*0000*/ uint32 drakkin_heritage; +/*0000*/ uint8 unknown1; // Seen 0 +/*0000*/ uint8 gohome; // Seen 0 for new char and 1 for existing +/*0000*/ uint32 LastLogin; +/*0000*/ uint8 unknown2; // Seen 0 +}; + +/* +** Character Selection Struct +** +*/ +struct CharacterSelect_Struct { +/*000*/ uint32 char_count; //number of chars in this packet +/*004*/ CharacterSelectEntry_Struct entries[0]; +}; + +struct Membership_Entry_Struct +{ +/*000*/ uint32 purchase_id; // Seen 1, then increments 90287 to 90300 +/*004*/ uint32 bitwise_entry; // Seen 16 to 65536 - Skips 4096 +/*008*/ +}; + +struct Membership_Setting_Struct +{ +/*000*/ uint32 setting_index; // 0, 1, or 2 +/*004*/ uint32 setting_id; // 0 to 21 +/*008*/ int32 setting_value; // All can be 0, 1, or -1 +/*012*/ +}; + +struct Membership_Details_Struct +{ +/*0000*/ uint32 membership_setting_count; // Seen 66 +/*0016*/ Membership_Setting_Struct settings[66]; +/*0012*/ uint32 race_entry_count; // Seen 15 +/*1044*/ Membership_Entry_Struct membership_races[15]; +/*0012*/ uint32 class_entry_count; // Seen 15 +/*1044*/ Membership_Entry_Struct membership_classes[15]; +/*1044*/ uint32 exit_url_length; // Length of the exit_url string (0 for none) +/*1048*/ //char exit_url[42]; // Upgrade to Silver or Gold Membership URL +/*1048*/ uint32 exit_url_length2; // Length of the exit_url2 string (0 for none) +/*0000*/ //char exit_url2[49]; // Upgrade to Gold Membership URL +}; + +struct Membership_Struct +{ +/*000*/ uint32 membership; // Seen 2 on Gold Account +/*004*/ uint32 races; // Seen ff ff 01 00 +/*008*/ uint32 classes; // Seen ff ff 01 01 +/*012*/ uint32 entrysize; // Seen 22 +/*016*/ int32 entries[22]; // Most -1, 1, and 0 for Gold Status +/*104*/ +}; + + +/* +* Visible equiptment. +* Size: 20 Octets +*/ +struct EquipStruct { +/*00*/ uint32 equip0; +/*04*/ uint32 equip1; +/*08*/ uint32 equip2; +/*12*/ uint32 itemId; +/*16*/ uint32 equip3; // Same as equip0? +/*20*/ +}; + + +/* +** Generic Spawn Struct +** Length: 897 Octets +** Used in: +** spawnZoneStruct +** dbSpawnStruct +** petStruct +** newSpawnStruct +*/ +/* +showeq -> eqemu +sed -e 's/_t//g' -e 's/seto_0xFF/set_to_0xFF/g' +*/ + +struct Spawn_Struct_Bitfields +{ +/*00*/ unsigned gender:2; // Gender (0=male, 1=female, 2=monster) +/*02*/ unsigned ispet:1; // Guessed based on observing live spawns +/*03*/ unsigned afk:1; // 0=no, 1=afk +/*04*/ unsigned anon:2; // 0=normal, 1=anon, 2=roleplay +/*06*/ unsigned gm:1; +/*06*/ unsigned sneak:1; +/*08*/ unsigned lfg:1; +/*09*/ unsigned unknown09:1; +/*10*/ unsigned invis:1; // May have invis & sneak the wrong way around ... not sure how to tell which is which +/*11*/ unsigned invis1:1; // GM Invis? Can only be seen with #gm on - same for the below +/*12*/ unsigned invis2:1; // This one also make the NPC/PC invis +/*13*/ unsigned invis3:1; // This one also make the NPC/PC invis +/*14*/ unsigned invis4:1; // This one also make the NPC/PC invis +/*15*/ unsigned invis6:1; // This one also make the NPC/PC invis +/*16*/ unsigned invis7:1; // This one also make the NPC/PC invis +/*17*/ unsigned invis8:1; // This one also make the NPC/PC invis +/*18*/ unsigned invis9:1; // This one also make the NPC/PC invis +/*19*/ unsigned invis10:1; // This one also make the NPC/PC invis +/*20*/ unsigned invis11:1; // This one also make the NPC/PC invis +/*21*/ unsigned invis12:1; // This one also make the NPC/PC invis +/*22*/ unsigned linkdead:1; // 1 Toggles LD on or off after name. Correct for RoF2 +/*23*/ unsigned showhelm:1; +/*24*/ unsigned unknown24:1; // Prefixes name with ! +/*25*/ unsigned trader:1; +/*26*/ unsigned unknown26:1; +/*27*/ unsigned targetable:1; +/*28*/ unsigned targetable_with_hotkey:1; +/*29*/ unsigned showname:1; +/*30*/ unsigned unknown30:1; +/*30*/ unsigned untargetable:1; // Untargetable with mouse + /* + // Unknown in RoF2 + unsigned betabuffed:1; + unsigned buyer:1; + unsigned buyer:1; + */ +}; + +/* +struct Spawn_Struct_Position +{ + signed padding0000:12; + signed y:19; + signed padding0001:1; + + signed deltaX:13; // change in x + signed deltaHeading:10;// change in heading + signed padding0008:9; + + signed deltaY:13; + signed z:19; + + signed x:19; + signed animation:10; // animation + signed padding0016:3; + + signed heading:12; + signed deltaZ:13; // change in z + signed padding0020:7; +}; +*/ + +struct Spawn_Struct_Position +{ + signed padding0000:12; + signed y:19; + signed padding0001:1; + + signed deltaZ:13; // change in z + signed deltaX:13; // change in x + signed padding0008:6; + + signed x:19; + signed heading:12; + signed padding0016:1; + + signed deltaHeading:10;// change in heading + signed z:19; + signed padding0020:3; + + signed animation:10; // animation + signed deltaY:13; + signed padding0023:9; +}; + +struct Spawn_Struct +{ +// Note this struct is not used as such, it is here for reference. As the struct is variable sized, the packets +// are constructed in Live.cpp +// +/*0000*/ char name[1]; //name[64]; +/*0000*/ //uint8 nullterm1; // hack to null terminate name +/*0064*/ uint32 spawnId; +/*0068*/ uint8 level; +/*0069*/ float unknown1; +/*0073*/ uint8 NPC; // 0=player,1=npc,2=pc corpse,3=npc corpse + Spawn_Struct_Bitfields Bitfields; +/*0000*/ uint8 otherData; // & 4 - has title, & 8 - has suffix, & 1 - it's a chest or untargetable +/*0000*/ float unknown3; // seen -1 +/*0000*/ float unknown4; +/*0000*/ float size; +/*0000*/ uint8 face; +/*0000*/ float walkspeed; +/*0000*/ float runspeed; +/*0000*/ uint32 race; +/*0000*/ uint8 showname; // for body types - was charProperties +/*0000*/ uint32 bodytype; +/*0000*/ //uint32 bodytype2; // this is only present if charProperties==2 + // are there more than two possible properties? +/*0000*/ uint8 curHp; +/*0000*/ uint8 haircolor; +/*0000*/ uint8 beardcolor; +/*0000*/ uint8 eyecolor1; +/*0000*/ uint8 eyecolor2; +/*0000*/ uint8 hairstyle; +/*0000*/ uint8 beard; +/*0000*/ uint32 drakkin_heritage; +/*0000*/ uint32 drakkin_tattoo; +/*0000*/ uint32 drakkin_details; +/*0000*/ uint8 statue; // was holding +/*0000*/ uint32 deity; +/*0000*/ uint32 guildID; +/*0000*/ uint32 guildrank; // 0=member, 1=officer, 2=leader, -1=not guilded +/*0000*/ uint8 class_; +/*0000*/ uint8 pvp; // 0 = normal name color, 2 = PVP name color +/*0000*/ uint8 StandState; // stand state - 0x64 for normal animation +/*0000*/ uint8 light; +/*0000*/ uint8 flymode; +/*0000*/ uint8 equip_chest2; +/*0000*/ uint8 unknown9; +/*0000*/ uint8 unknown10; +/*0000*/ uint8 helm; +/*0000*/ char lastName[1]; +/*0000*/ //uint8 lastNameNull; //hack! +/*0000*/ uint32 aatitle; // 0=none, 1=general, 2=archtype, 3=class was AARank +/*0000*/ uint8 unknown12; +/*0000*/ uint32 petOwnerId; +/*0000*/ uint8 unknown13; +/*0000*/ uint32 unknown14; // Stance 64 = normal 4 = aggressive 40 = stun/mezzed +/*0000*/ uint32 unknown15; +/*0000*/ uint32 unknown16; +/*0000*/ uint32 unknown17; +/*0000*/ //uint8 unknownRoF23; +/*0000*/ uint32 unknown18; +/*0000*/ uint32 unknown19; + Spawn_Struct_Position Position; +/*0000*/ union + { + struct + { + /*0000*/ Color_Struct color_helmet; // Color of helmet item + /*0000*/ Color_Struct color_chest; // Color of chest item + /*0000*/ Color_Struct color_arms; // Color of arms item + /*0000*/ Color_Struct color_bracers; // Color of bracers item + /*0000*/ Color_Struct color_hands; // Color of hands item + /*0000*/ Color_Struct color_legs; // Color of legs item + /*0000*/ Color_Struct color_feet; // Color of feet item + /*0000*/ Color_Struct color_primary; // Color of primary item + /*0000*/ Color_Struct color_secondary; // Color of secondary item + } equipment_colors; + /*0000*/ Color_Struct colors[9]; // Array elements correspond to struct equipment_colors above + }; + +// skip these bytes if not a valid player race +/*0000*/ union + { + struct + { + /*0000*/ EquipStruct equip_helmet; // Equiptment: Helmet visual + /*0000*/ EquipStruct equip_chest; // Equiptment: Chest visual + /*0000*/ EquipStruct equip_arms; // Equiptment: Arms visual + /*0000*/ EquipStruct equip_bracers; // Equiptment: Wrist visual + /*0000*/ EquipStruct equip_hands; // Equiptment: Hands visual + /*0000*/ EquipStruct equip_legs; // Equiptment: Legs visual + /*0000*/ EquipStruct equip_feet; // Equiptment: Boots visual + /*0000*/ EquipStruct equip_primary; // Equiptment: Main visual + /*0000*/ EquipStruct equip_secondary; // Equiptment: Off visual + } equip; + /*0000*/ EquipStruct equipment[9]; + }; + +/*0000*/ //char title[0]; // only read if(hasTitleOrSuffix & 4) +/*0000*/ //char suffix[0]; // only read if(hasTitleOrSuffix & 8) + char unknown20[8]; + uint8 IsMercenary; // If NPC == 1 and this == 1, then the NPC name is Orange. +/*0000*/ char unknown21[55]; +}; + + +/* +** Generic Spawn Struct +** Fields from old struct not yet found: +** uint8 traptype; // 65 is disarmable trap, 66 and 67 are invis triggers/traps +** uint8 is_pet; // 0=no, 1=yes +** uint8 afk; // 0=no, 1=afk +** uint8 is_npc; // 0=no, 1=yes +** uint8 max_hp; // (name prolly wrong)takes on the value 100 for players, 100 or 110 for NPCs and 120 for PC corpses... +** uint8 guildrank; // 0=normal, 1=officer, 2=leader +** uint8 eyecolor2; //not sure, may be face +** uint8 aaitle; // 0=none, 1=general, 2=archtype, 3=class +*/ + +/* +** New Spawn +** Length: 176 Bytes +** OpCode: 4921 +*/ +struct NewSpawn_Struct +{ + struct Spawn_Struct spawn; // Spawn Information +}; + + +/* +** Client Zone Entry struct +** Length: 68 Octets +** OpCode: ZoneEntryCode (when direction == client) +*/ +struct ClientZoneEntry_Struct { +/*00*/ uint32 unknown00; // ***Placeholder +/*04*/ char char_name[64]; // Player firstname [32] +/*68*/ uint32 unknown68; +/*72*/ uint32 unknown72; +}; + + +/* +** Server Zone Entry Struct +** Length: 452 Bytes +** OPCodes: OP_ServerZoneEntry +** +*/ +struct ServerZoneEntry_Struct //Adjusted from SEQ Everquest.h Struct +{ + struct NewSpawn_Struct player; +}; + + +//New Zone Struct - Size: 948 +struct NewZone_Struct { +/*0000*/ char char_name[64]; // Character Name +/*0064*/ char zone_short_name[32]; // Zone Short Name +/*0096*/ char unknown0096[96]; +/*0192*/ char zone_long_name[278]; // Zone Long Name +/*0470*/ uint8 ztype; // Zone type (usually FF) +/*0471*/ uint8 fog_red[4]; // Zone fog (red) +/*0475*/ uint8 fog_green[4]; // Zone fog (green) +/*0479*/ uint8 fog_blue[4]; // Zone fog (blue) +/*0483*/ uint8 unknown323; +/*0484*/ float fog_minclip[4]; +/*0500*/ float fog_maxclip[4]; +/*0516*/ float gravity; +/*0520*/ uint8 time_type; +/*0521*/ uint8 rain_chance[4]; +/*0525*/ uint8 rain_duration[4]; +/*0529*/ uint8 snow_chance[4]; +/*0533*/ uint8 snow_duration[4]; +/*0537*/ uint8 unknown537[33]; +/*0570*/ uint8 sky; // Sky Type +/*0571*/ uint8 unknown571[13]; // ***Placeholder +/*0584*/ float zone_exp_multiplier; // Experience Multiplier +/*0588*/ float safe_y; // Zone Safe Y +/*0592*/ float safe_x; // Zone Safe X +/*0596*/ float safe_z; // Zone Safe Z +/*0600*/ float min_z; // Guessed - NEW - Seen 0 +/*0604*/ float max_z; // Guessed +/*0608*/ float underworld; // Underworld, min z (Not Sure?) +/*0612*/ float minclip; // Minimum View Distance +/*0616*/ float maxclip; // Maximum View DIstance +/*0620*/ uint8 unknown620[84]; // ***Placeholder +/*0704*/ char zone_short_name2[96]; //zone file name? excludes instance number which can be in previous version. +/*0800*/ int32 unknown800; //seen -1 +/*0804*/ char unknown804[40]; // +/*0844*/ int32 unknown844; //seen 600 +/*0848*/ int32 unknown848; +/*0852*/ uint16 zone_id; +/*0854*/ uint16 zone_instance; +/*0856*/ char unknown856[20]; +/*0876*/ uint32 SuspendBuffs; +/*0880*/ uint32 unknown880; // Seen 50 +/*0884*/ uint32 unknown884; // Seen 10 +/*0888*/ uint8 unknown888; // Seen 1 +/*0889*/ uint8 unknown889; // Seen 0 (POK) or 1 (rujj) +/*0890*/ uint8 unknown890; // Seen 1 +/*0891*/ uint8 unknown891; // Seen 0 +/*0892*/ uint8 unknown892; // Seen 0 +/*0893*/ uint8 unknown893; // Seen 0 - 00 +/*0894*/ uint8 fall_damage; // 0 = Fall Damage on, 1 = Fall Damage off +/*0895*/ uint8 unknown895; // Seen 0 - 00 +/*0896*/ uint32 unknown896; // Seen 180 +/*0900*/ uint32 unknown900; // Seen 180 +/*0904*/ uint32 unknown904; // Seen 180 +/*0908*/ uint32 unknown908; // Seen 2 +/*0912*/ uint32 unknown912; // Seen 2 +/*0916*/ float FogDensity; // Most zones have this set to 0.33 Blightfire had 0.16 +/*0920*/ uint32 unknown920; // Seen 0 +/*0924*/ uint32 unknown924; // Seen 0 +/*0928*/ uint32 unknown928; // Seen 0 +/*0932*/ int32 unknown932; // Seen -1 +/*0936*/ int32 unknown936; // Seen -1 +/*0940*/ uint32 unknown940; // Seen 0 +/*0944*/ float unknown944; // Seen 1.0 +/*0948*/ +}; + + +/* +** Memorize Spell Struct +** Length: 16 Bytes +** +*/ +struct MemorizeSpell_Struct { +uint32 slot; // Spot in the spell book/memorized slot +uint32 spell_id; // Spell id (200 or c8 is minor healing, etc) +uint32 scribing; // 1 if memorizing a spell, set to 0 if scribing to book, 2 if un-memming +uint32 unknown12; +}; + +/* +** Make Charmed Pet +** Length: 12 Bytes +** +*/ +struct Charm_Struct { +/*00*/ uint32 owner_id; +/*04*/ uint32 pet_id; +/*08*/ uint32 command; // 1: make pet, 0: release pet +/*12*/ +}; + +struct InterruptCast_Struct +{ + uint32 spawnid; + uint32 messageid; + //char message[0]; +}; + +struct DeleteSpell_Struct +{ +/*000*/int16 spell_slot; +/*002*/uint8 unknowndss002[2]; +/*004*/uint8 success; +/*005*/uint8 unknowndss006[3]; +/*008*/ +}; + +struct ManaChange_Struct +{ + uint32 new_mana; // New Mana AMount + uint32 stamina; + uint32 spell_id; + uint32 unknown12; + uint32 unknown16; +}; + +struct SwapSpell_Struct +{ + uint32 from_slot; + uint32 to_slot; +}; + +struct BeginCast_Struct +{ +/*000*/ uint32 spell_id; +/*004*/ uint16 caster_id; +/*006*/ uint32 cast_time; // in miliseconds +/*010*/ +}; + +struct CastSpell_Struct +{ +/*00*/ uint32 slot; +/*04*/ uint32 spell_id; +/*08*/ ItemSlotStruct inventoryslot; // slot for clicky item, Seen unknown of 131 = normal cast +/*20*/ uint32 target_id; +/*24*/ uint32 cs_unknown[5]; +/*44*/ +}; + +/* +** SpawnAppearance_Struct +** Changes client appearance for all other clients in zone +** Size: 8 bytes +** Used in: OP_SpawnAppearance +** +*/ +struct SpawnAppearance_Struct +{ +/*0000*/ uint16 spawn_id; // ID of the spawn +/*0002*/ uint16 type; // Values associated with the type +/*0004*/ uint32 parameter; // Type of data sent +/*0008*/ +}; + +struct SpellBuff_Struct +{ +/*000*/ uint8 slotid; // badly named... seems to be 2 for a real buff, 0 otherwise +/*001*/ float unknown004; // Seen 1 for no buff +/*005*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages +/*009*/ uint32 unknown016; +/*013*/ uint8 bard_modifier; +/*014*/ uint32 duration; +/*018*/ uint8 level; +/*019*/ uint32 spellid; +/*023*/ uint32 counters; +/*027*/ uint8 unknown0028[53]; +/*080*/ +}; + +struct SpellBuff_Struct_Old +{ +/*000*/ uint8 slotid; // badly named... seems to be 2 for a real buff, 0 otherwise +/*001*/ uint8 level; +/*002*/ uint8 bard_modifier; +/*003*/ uint8 effect; // not real +/*004*/ float unknown004; // Seen 1 for no buff +/*008*/ uint32 spellid; +/*012*/ uint32 duration; +/*016*/ uint32 unknown016; +/*020*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages +/*024*/ uint32 counters; +/*028*/ uint8 unknown0028[60]; +/*088*/ +}; + +// Not functional yet, but this is what the packet looks like on Live +struct SpellBuffFade_Struct_Live { +/*000*/ uint32 entityid; // Player id who cast the buff +/*004*/ uint8 unknown004; +/*005*/ uint8 level; +/*006*/ uint8 effect; +/*007*/ uint8 unknown007; +/*008*/ float unknown008; +/*012*/ uint32 spellid; +/*016*/ uint32 duration; +/*020*/ uint32 playerId; // Global player ID? +/*024*/ uint32 num_hits; +/*028*/ uint8 unknown0028[64]; +/*092*/ uint32 slotid; +/*096*/ uint32 bufffade; +/*100*/ +}; + +struct SpellBuffFade_Struct { +/*000*/ uint32 entityid; +/*004*/ uint8 slot; +/*005*/ uint8 level; +/*006*/ uint8 effect; +/*007*/ uint8 unknown7; +/*008*/ uint32 spellid; +/*012*/ uint32 duration; +/*016*/ uint32 num_hits; +/*020*/ uint32 unknown020; // Global player ID? +/*024*/ uint32 playerId; // Player id who cast the buff +/*028*/ uint32 slotid; +/*032*/ uint32 bufffade; +/*036*/ +}; + +struct BuffRemoveRequest_Struct +{ +/*00*/ uint32 SlotID; +/*04*/ uint32 EntityID; +/*08*/ +}; + +#if 0 +// not in use +struct BuffIconEntry_Struct { +/*000*/ uint32 buff_slot; +/*004*/ uint32 spell_id; +/*008*/ uint32 tics_remaining; +/*012*/ uint32 num_hits; +// char name[0]; caster name is also here sometimes +// uint8 unknownend; 1 when single, 0 when all opposite of all_buffs? +}; + +// not in use +struct BuffIcon_Struct { +/*000*/ uint32 entity_id; +/*004*/ uint32 unknown004; +/*008*/ uint8 all_buffs; // 1 when updating all buffs, 0 when doing one +/*009*/ uint16 count; +/*011*/ BuffIconEntry_Struct entires[0]; +}; +#endif + +struct GMTrainee_Struct +{ + /*000*/ uint32 npcid; + /*004*/ uint32 playerid; + /*008*/ uint32 skills[PACKET_SKILL_ARRAY_SIZE]; + /*408*/ uint8 unknown408[40]; + /*448*/ +}; + +struct GMTrainEnd_Struct +{ + /*000*/ uint32 npcid; + /*004*/ uint32 playerid; + /*008*/ +}; + +struct GMSkillChange_Struct { +/*000*/ uint16 npcid; +/*002*/ uint8 unknown1[2]; // something like PC_ID, but not really. stays the same thru the session though +/*002*/ uint16 skillbank; // 0 if normal skills, 1 if languages +/*002*/ uint8 unknown2[2]; +/*008*/ uint16 skill_id; +/*010*/ uint8 unknown3[2]; +/*012*/ +}; + +struct GMTrainSkillConfirm_Struct { // SoF+ only +/*000*/ uint32 SkillID; +/*004*/ uint32 Cost; +/*008*/ uint8 NewSkill; // Set to 1 for 'You have learned the basics' message. +/*009*/ char TrainerName[64]; +/*073*/ uint8 Unknown073[3]; +/*076*/ +}; + +struct ConsentResponse_Struct { + char grantname[64]; + char ownername[64]; + uint8 permission; + char zonename[64]; +}; + +/* +** Name Generator Struct +** Length: 72 bytes +** OpCode: 0x0290 +*/ +struct NameGeneration_Struct +{ +/*0000*/ uint32 race; +/*0004*/ uint32 gender; +/*0008*/ char name[64]; +/*0072*/ +}; + +/* +** Character Creation struct +** Length: 96 Bytes +*/ +struct CharCreate_Struct +{ +/*0000*/ uint32 gender; +/*0004*/ uint32 race; +/*0008*/ uint32 class_; +/*0012*/ uint32 deity; +/*0016*/ uint32 start_zone; +/*0020*/ uint32 haircolor; +/*0024*/ uint32 beard; +/*0028*/ uint32 beardcolor; +/*0032*/ uint32 hairstyle; +/*0036*/ uint32 face; +/*0040*/ uint32 eyecolor1; +/*0044*/ uint32 eyecolor2; +/*0048*/ uint32 drakkin_heritage; +/*0052*/ uint32 drakkin_tattoo; +/*0056*/ uint32 drakkin_details; +/*0060*/ uint32 STR; +/*0064*/ uint32 STA; +/*0068*/ uint32 AGI; +/*0073*/ uint32 DEX; +/*0076*/ uint32 WIS; +/*0080*/ uint32 INT; +/*0084*/ uint32 CHA; +/*0088*/ uint32 tutorial; +/*0092*/ uint32 unknown0092; +/*0096*/ +}; + +/* +** Character Creation struct +** Length: 0 Bytes +** OpCode: 0x +*/ +struct CharCreate_Struct_Temp //Size is now 0 +{ +}; + +/* + *Used in PlayerProfile + */ +struct AA_Array +{ + uint32 AA; + uint32 value; + uint32 unknown08; // Looks like AA_Array is now 12 bytes in Live +}; + +struct Disciplines_Struct { + uint32 values[MAX_PP_DISCIPLINES]; +}; + + + +struct Tribute_Struct { + uint32 tribute; + uint32 tier; +}; + +struct BandolierItem_Struct { + char item_name[1]; // Variable Length + uint32 item_id; + uint32 icon; +}; + +//len = 72 +struct BandolierItem_Struct_Old { + uint32 item_id; + uint32 icon; + char item_name[64]; +}; + +//len = 320 +enum { //bandolier item positions + bandolierMainHand = 0, + bandolierOffHand, + bandolierRange, + bandolierAmmo +}; +struct Bandolier_Struct { + char name[1]; // Variable Length + BandolierItem_Struct items[MAX_PLAYER_BANDOLIER_ITEMS]; +}; + +struct Bandolier_Struct_Old { + char name[32]; + BandolierItem_Struct items[MAX_PLAYER_BANDOLIER_ITEMS]; +}; + +struct PotionBelt_Struct { + BandolierItem_Struct items[MAX_POTIONS_IN_BELT]; +}; + +struct GroupLeadershipAA_Struct { + union { + struct { + uint32 groupAAMarkNPC; + uint32 groupAANPCHealth; + uint32 groupAADelegateMainAssist; + uint32 groupAADelegateMarkNPC; + uint32 groupAA4; + uint32 groupAA5; + uint32 groupAAInspectBuffs; + uint32 groupAA7; + uint32 groupAASpellAwareness; + uint32 groupAAOffenseEnhancement; + uint32 groupAAManaEnhancement; + uint32 groupAAHealthEnhancement; + uint32 groupAAHealthRegeneration; + uint32 groupAAFindPathToPC; + uint32 groupAAHealthOfTargetsTarget; + uint32 groupAA15; + }; + uint32 ranks[MAX_GROUP_LEADERSHIP_AA_ARRAY]; + }; +}; + +struct RaidLeadershipAA_Struct { + union { + struct { + uint32 raidAAMarkNPC; + uint32 raidAANPCHealth; + uint32 raidAADelegateMainAssist; + uint32 raidAADelegateMarkNPC; + uint32 raidAA4; + uint32 raidAA5; + uint32 raidAA6; + uint32 raidAASpellAwareness; + uint32 raidAAOffenseEnhancement; + uint32 raidAAManaEnhancement; + uint32 raidAAHealthEnhancement; + uint32 raidAAHealthRegeneration; + uint32 raidAAFindPathToPC; + uint32 raidAAHealthOfTargetsTarget; + uint32 raidAA14; + uint32 raidAA15; + }; + uint32 ranks[MAX_RAID_LEADERSHIP_AA_ARRAY]; + }; +}; + +struct LeadershipAA_Struct { + union { + struct { + GroupLeadershipAA_Struct group; + RaidLeadershipAA_Struct raid; + }; + uint32 ranks[MAX_LEADERSHIP_AA_ARRAY]; + }; +}; + + /** +* A bind point. +* Size: 20 Octets +*/ +struct BindStruct { + /*000*/ uint32 zoneId; + /*004*/ float x; + /*008*/ float y; + /*012*/ float z; + /*016*/ float heading; + /*020*/ +}; + + +// Player Profile - Variable Length as of Oct 12 2012 patch +struct PlayerProfile_Struct +{ +/*00000*/ uint32 checksum; // +/*00004*/ uint32 checksum_size; // Value = ( Packet Size - 9 ) +/*00008*/ uint8 checksum_byte; // +/*00009*/ uint8 unknown_rof1[3]; // +/*00012*/ uint32 unknown_rof2; // +/*00016*/ uint8 gender; // Player Gender - 0 Male, 1 Female +/*00017*/ uint32 race; // Player race +/*00021*/ uint8 class_; // Player class +/*00022*/ uint8 level; // Level of player +/*00023*/ uint8 level1; // Level of player (again?) +/*00024*/ uint32 bind_count; // Seen 5 +/*00028*/ BindStruct binds[5]; // Bind points (primary is first) 5 fields = 100 bytes +/*00128*/ uint32 deity; // deity +/*00132*/ uint32 unknown_rof3; // Maybe Drakkin Heritage? +/*00136*/ uint32 unknown4_count; // Seen 10 +/*00140*/ uint32 unknown_rof4[10]; // Seen all 0s +/*00180*/ uint32 equip_count; // Seen 22 +union +{ + struct + { + /*00184*/ EquipStruct equip_helmet; // Equiptment: Helmet visual + /*00204*/ EquipStruct equip_chest; // Equiptment: Chest visual + /*00224*/ EquipStruct equip_arms; // Equiptment: Arms visual + /*00244*/ EquipStruct equip_bracers; // Equiptment: Wrist visual + /*00264*/ EquipStruct equip_hands; // Equiptment: Hands visual + /*00284*/ EquipStruct equip_legs; // Equiptment: Legs visual + /*00304*/ EquipStruct equip_feet; // Equiptment: Boots visual + /*00324*/ EquipStruct equip_primary; // Equiptment: Main visual + /*00344*/ EquipStruct equip_secondary; // Equiptment: Off visual + // Below slots are just guesses, but all 0s anyway... + /*00364*/ EquipStruct equip_charm; // Equiptment: Non-visual + /*00384*/ EquipStruct equip_ear1; // Equiptment: Non-visual + /*00404*/ EquipStruct equip_ear2; // Equiptment: Non-visual + /*00424*/ EquipStruct equip_face; // Equiptment: Non-visual + /*00444*/ EquipStruct equip_neck; // Equiptment: Non-visual + /*00464*/ EquipStruct equip_shoulder; // Equiptment: Non-visual + /*00484*/ EquipStruct equip_bracer2; // Equiptment: Non-visual + /*00504*/ EquipStruct equip_range; // Equiptment: Non-visual + /*00524*/ EquipStruct equip_ring1; // Equiptment: Non-visual + /*00544*/ EquipStruct equip_ring2; // Equiptment: Non-visual + /*00564*/ EquipStruct equip_waist; // Equiptment: Non-visual + /*00584*/ EquipStruct equip_powersource; // Equiptment: Non-visual + /*00604*/ EquipStruct equip_ammo; // Equiptment: Non-visual + } equip; + /*00184*/ EquipStruct equipment[22]; +}; +/*00624*/ uint32 equip2_count; // Seen 9 +/*00628*/ EquipStruct equipment2[9]; // Appears to be Visible slots, but all 0s +/*00808*/ uint32 tint_count; // Seen 9 +/*00812*/ Color_Struct item_tint[9]; // RR GG BB 00 +/*00848*/ uint32 tint_count2; // Seen 9 +/*00852*/ Color_Struct item_tint2[9]; // RR GG BB 00 +/*00888*/ uint8 haircolor; // Player hair color +/*00889*/ uint8 beardcolor; // Player beard color +/*00890*/ uint32 unknown_rof5; // +/*00894*/ uint8 eyecolor1; // Player left eye color +/*00895*/ uint8 eyecolor2; // Player right eye color +/*00896*/ uint8 hairstyle; // Player hair style +/*00897*/ uint8 beard; // Player beard type +/*00898*/ uint8 face; // Player face +/*00899*/ uint32 drakkin_heritage; // +/*00903*/ uint32 drakkin_tattoo; // +/*00907*/ uint32 drakkin_details; // +/*00911*/ uint8 unknown_rof6; // +/*00912*/ int8 unknown_rof7; // seen -1 +/*00913*/ uint8 unknown_rof8; // +/*00914*/ uint8 unknown_rof9; // +/*00915*/ uint8 unknown_rof10; // Seen 1 or 0 (on a female?) +/*00916*/ float height; // Seen 7.0 (barb), 5.0 (woodelf), 5.5 (halfelf) +/*00920*/ float unknown_rof11; // Seen 3.0 +/*00924*/ float unknown_rof12; // Seen 2.5 +/*00928*/ float unknown_rof13; // Seen 5.5 +/*00932*/ uint32 primary; // Seen 10528 +/*00936*/ uint32 secondary; // Seen 10006 +/*00940*/ uint32 points; // Unspent Practice points - RELOCATED??? +/*00944*/ uint32 mana; // Current mana +/*00948*/ uint32 cur_hp; // Current HP without +HP equipment +/*00952*/ uint32 STR; // Strength - 6e 00 00 00 - 110 +/*00956*/ uint32 STA; // Stamina - 73 00 00 00 - 115 +/*00960*/ uint32 CHA; // Charisma - 37 00 00 00 - 55 +/*00964*/ uint32 DEX; // Dexterity - 50 00 00 00 - 80 +/*00968*/ uint32 INT; // Intelligence - 3c 00 00 00 - 60 +/*00972*/ uint32 AGI; // Agility - 5f 00 00 00 - 95 +/*00976*/ uint32 WIS; // Wisdom - 46 00 00 00 - 70 +/*00980*/ uint32 unknown_rof14[7]; // Probably base resists? +/*01008*/ uint32 aa_count; // Seen 300 +/*01012*/ AA_Array aa_array[MAX_PP_AA_ARRAY]; // [300] 3600 bytes - AAs 12 bytes each +/*04612*/ uint32 skill_count; // Seen 100 +/*04616*/ uint32 skills[MAX_PP_SKILL]; // [100] 400 bytes - List of skills +/*05016*/ uint32 unknown15_count; // Seen 25 +/*05020*/ uint32 unknown_rof15[25]; // Most are 255 or 0 +/*05120*/ uint32 discipline_count; // Seen 200 +/*05124*/ Disciplines_Struct disciplines; // [200] 800 bytes Known disciplines +/*05924*/ uint32 timestamp_count; // Seen 20 +/*05928*/ uint32 timestamps[20]; // Unknown Unix Timestamps - maybe recast related? +/*06008*/ uint32 recast_count; // Seen 20 +/*06012*/ uint32 recastTimers[MAX_RECAST_TYPES];// [20] 80 bytes - Timers (UNIX Time of last use) +/*06092*/ uint32 timestamp2_count; // Seen 100 +/*06096*/ uint32 timestamps2[100]; // Unknown Unix Timestamps - maybe Skill related? +/*06496*/ uint32 spell_book_count; // Seen 720 +/*06500*/ uint32 spell_book[MAX_PP_SPELLBOOK]; // List of the Spells in spellbook 720 = 90 pages [2880 bytes] +/*09380*/ uint32 mem_spell_count; // Seen 16 +/*09384*/ int32 mem_spells[MAX_PP_MEMSPELL]; // [16] List of spells memorized - First 12 are set or -1 and last 4 are 0s +/*09448*/ uint32 unknown16_count; // Seen 13 +/*09452*/ uint32 unknown_rof16[13]; // Possibly spell or buff related +/*09504*/ uint8 unknown_rof17; // Seen 0 or 8 +/*09505*/ uint32 buff_count; // Seen 42 +/*09509*/ SpellBuff_Struct buffs[BUFF_COUNT]; // [42] 3360 bytes - Buffs currently on the player (42 Max) - (Each Size 80) +/*12869*/ uint32 platinum; // Platinum Pieces on player +/*12873*/ uint32 gold; // Gold Pieces on player +/*12877*/ uint32 silver; // Silver Pieces on player +/*12881*/ uint32 copper; // Copper Pieces on player +/*12885*/ uint32 platinum_cursor; // Platinum Pieces on cursor +/*12889*/ uint32 gold_cursor; // Gold Pieces on cursor +/*12893*/ uint32 silver_cursor; // Silver Pieces on cursor +/*12897*/ uint32 copper_cursor; // Copper Pieces on cursor +/*12901*/ uint32 intoxication; // Alcohol level (in ticks till sober?) - Position Guessed +/*12905*/ uint32 toxicity; // Potion Toxicity (15=too toxic, each potion adds 3) - Position Guessed +/*12909*/ uint32 unknown_rof19; // +/*12913*/ uint32 thirst_level; // Drink (ticks till next drink) - Position Guessed +/*12917*/ uint32 hunger_level; // Food (ticks till next eat) - Position Guessed +/*12921*/ uint32 aapoints_spent; // Number of spent AA points +/*12925*/ uint32 aapoint_count; // Seen 5 - Unsure what this is exactly +/*12929*/ uint32 aapoints_assigned; // Number of Assigned AA points - Seen 206 (total of the 4 fields below) +/*12933*/ uint32 aa_spent_general; // Seen 63 +/*12937*/ uint32 aa_spent_archetype; // Seen 40 +/*12941*/ uint32 aa_spent_class; // Seen 103 +/*12945*/ uint32 aa_spent_special; // Seen 0 +/*12949*/ uint32 aapoints; // Unspent AA points - Seen 1 +/*12953*/ uint16 unknown_rof20; // +/*12955*/ uint32 bandolier_count; // Seen 20 +/*12959*/ Bandolier_Struct bandoliers[MAX_PLAYER_BANDOLIER]; // [20] 740 bytes (Variable Name Sizes) - bandolier contents +/*13699*/ uint32 potionbelt_count; // Seen 5 +/*13703*/ PotionBelt_Struct potionbelt; // [5] 45 bytes potion belt - (Variable Name Sizes) +/*13748*/ int32 unknown_rof21; // Seen -1 +/*13752*/ int32 hp_total; // Guessed - Seen 20 on level 1 new mage +/*13756*/ int32 endurance_total; // Guessed - Seen 20 on level 1 new mage +/*13760*/ int32 mana_total; // Guessed - Only seen on casters so far - Matches above field if caster +/*13764*/ uint32 unknown_rof22[12]; // Same for all seen PPs - 48 bytes: +/* +19 00 00 00 19 00 00 00 19 00 00 00 0f 00 00 00 +0f 00 00 00 0f 00 00 00 0f 00 00 00 1f 85 eb 3e +33 33 33 3f 08 00 00 00 02 00 00 00 01 00 00 00 +*/ +/*13812*/ uint32 unknown_rof23; // Seen 5, 19, and 20 in examples +/*13816*/ uint32 unknown_rof24[4]; // +/*13832*/ uint32 unknown_rof25[2]; // Seen random numbers from 0 to 2165037 +/*13840*/ uint32 unknown_rof26; // Seen 106 +//END SUB-STRUCT used for shrouding. +/*13844*/ uint32 name_str_len; // Seen 64 +/*13848*/ char name[64]; // Name of player - 19960 for Live 1180 difference +/*13912*/ uint32 last_name_str_len; // Seen 32 +/*13916*/ char last_name[32]; // Last name of player +/*13948*/ uint32 birthday; // character birthday +/*13952*/ uint32 account_startdate; // Date the Account was started +/*13956*/ uint32 lastlogin; // character last save time +/*13960*/ uint32 timePlayedMin; // time character played +/*13964*/ uint32 timeentitledonaccount; +/*13968*/ uint32 expansions; // Bitmask for expansions ff 7f 00 00 - SoD +/*13972*/ uint32 language_count; // Seen 32 +/*13976*/ uint8 languages[MAX_PP_LANGUAGE]; // [32] 32 bytes - List of languages +/*14008*/ uint16 zone_id; // see zones.h +/*14010*/ uint16 zoneInstance; // Instance id +/*14012*/ float y; // Players y position (NOT positive about this switch) +/*14016*/ float x; // Players x position +/*14020*/ float z; // Players z position +/*14024*/ float heading; // Players heading +/*14028*/ uint32 air_remaining; // Air supply (seconds) +/*14032*/ int32 unknown_rof28; // Seen -1 +/*14036*/ uint8 unknown_rof29[10]; // +/*14046*/ uint32 unknown_rof30; // Random large number or 0 +/*14050*/ uint32 unknown_rof31; // +/*14054*/ uint32 unknown32_count; // Seen 5 +/*14058*/ uint8 unknown_rof32[29]; // +/*14087*/ uint32 unknown33_count; // Seen 32 for melee/hybrid and 21 for druid, 34 for mage +/*14091*/ uint32 unknown_rof33[64]; // Struct contains 2 ints, so double 32 count (Variable Sized) +// Position Varies after this point - Really starts varying at Bandolier names, but if no names set it starts here +/*00000*/ int32 unknown_rof34; // Seen -1 +/*00000*/ int32 unknown_rof35; // Seen -1 +/*00000*/ uint8 unknown_rof36[18]; // +/*00000*/ uint32 unknown37_count; // Seen 5 +/*00000*/ int32 unknown_rof37[10]; // Alternates -1 and 0 - Struct contains 2 ints +/*00000*/ uint32 unknown38_count; // Seen 10 +/*00000*/ int32 unknown_rof38[20]; // Alternates -1 and 0 - Struct contains 2 ints +/*00000*/ uint8 unknown_rof39[137]; // +/*00000*/ float unknown_rof40; // Seen 1.0 +/*00000*/ uint32 unknown_rof41[9]; // +/*00000*/ uint32 unknown_rof42; // Seen 0 or 1 +/*00000*/ uint32 unknown_string1_count; // Seen 64 +/*00000*/ char unknown_string1[64]; // +/*00000*/ uint8 unknown_rof43[30]; // +/*00000*/ uint32 unknown_string2_count; // Seen 64 +/*00000*/ char unknown_string2[64]; // +/*00000*/ uint32 unknown_string3_count; // Seen 64 +/*00000*/ char unknown_string3[64]; // +/*00000*/ uint32 unknown_rof44; // Seen 0 or 50 +/*00000*/ uint8 unknown_rof45[663]; // +/*00000*/ uint32 char_id; // Guessed based on char creation date and values +/*00000*/ uint8 unknown_rof46; // Seen 0 or 1 +/*00000*/ uint32 unknown_rof47; // Seen 6 +/*00000*/ uint32 unknown_rof48[13]; // Seen all 0s or some mix of ints and float? +/*00000*/ uint32 unknown_rof49; // Seen 64 +/*00000*/ uint8 unknown_rof50[256]; // Seen mostly 0s, but one example had a 2 in the middle +/*00000*/ uint32 unknown_rof51; // Seen 100 or 0 +/*00000*/ uint8 unknown_rof52[82]; // +/*00000*/ uint32 unknown_rof53; // Seen 50 + +/*00000*/ uint8 unknown_rof54[1325]; // Unknown Section + +// Bottom of Struct: +/*00000*/ uint8 groupAutoconsent; // 0=off, 1=on +/*00000*/ uint8 raidAutoconsent; // 0=off, 1=on +/*00000*/ uint8 guildAutoconsent; // 0=off, 1=on +/*00000*/ uint8 unknown_rof55; // Seen 1 +/*00000*/ uint32 level3; // SoF looks at the level here to determine how many leadership AA you can bank. +/*00000*/ uint32 showhelm; // 0=no, 1=yes +/*00000*/ uint32 RestTimer; +/*00000*/ uint8 unknown_rof56; +/*00000*/ uint32 unknown_rof57; // Seen 49 +/*00000*/ uint8 unknown_rof58[1045]; // Seen all 0s + +/* +///////////////////// - Haven't identified the below fields in the PP yet +uint8 pvp; // 1=pvp, 0=not pvp +uint8 anon; // 2=roleplay, 1=anon, 0=not anon +uint8 gm; // 0=no, 1=yes (guessing!) +uint32 guild_id; // guildid +uint8 guildrank; // 0=member, 1=officer, 2=guildleader -1=no guild +uint32 guildbanker; +uint32 available_slots; +uint32 endurance; // Current endurance +uint32 spellSlotRefresh[MAX_PP_MEMSPELL]; // Refresh time (millis) - 4 bytes Each * 16 = 64 bytes +uint32 abilitySlotRefresh; +/////////////////////// + +uint32 platinum_bank; // Platinum Pieces in Bank +uint32 gold_bank; // Gold Pieces in Bank +uint32 silver_bank; // Silver Pieces in Bank +uint32 copper_bank; // Copper Pieces in Bank +uint32 platinum_shared; // Shared platinum pieces + +uint32 autosplit; // 0 = off, 1 = on + +char groupMembers[MAX_GROUP_MEMBERS][64];// 384 all the members in group, including self +char groupLeader[64]; // Leader of the group ? +uint32 entityid; + +uint32 leadAAActive; // 0 = leader AA off, 1 = leader AA on +int32 ldon_points_guk; // Earned GUK points +int32 ldon_points_mir; // Earned MIR points +int32 ldon_points_mmc; // Earned MMC points +int32 ldon_points_ruj; // Earned RUJ points +int32 ldon_points_tak; // Earned TAK points +int32 ldon_points_available;// Available LDON points +float tribute_time_remaining;// Time remaining on tribute (millisecs) +uint32 career_tribute_points;// Total favor points for this char +uint32 tribute_points; // Current tribute points +uint32 tribute_active; // 0 = off, 1=on +Tribute_Struct tributes[MAX_PLAYER_TRIBUTES]; // [40] Current tribute loadout +double group_leadership_exp; // Current group lead exp points +double raid_leadership_exp; // Current raid lead AA exp points +uint32 group_leadership_points; // Unspent group lead AA points +uint32 raid_leadership_points; // Unspent raid lead AA points +LeadershipAA_Struct leader_abilities; // [128]Leader AA ranks 19332 + +uint32 PVPKills; +uint32 PVPDeaths; +uint32 PVPCurrentPoints; +uint32 PVPCareerPoints; +uint32 PVPBestKillStreak; +uint32 PVPWorstDeathStreak; +uint32 PVPCurrentKillStreak; +PVPStatsEntry_Struct PVPLastKill; // size 88 +PVPStatsEntry_Struct PVPLastDeath; // size 88 +uint32 PVPNumberOfKillsInLast24Hours; +PVPStatsEntry_Struct PVPRecentKills[50]; // size 4400 - 88 each +uint32 expAA; // Exp earned in current AA point +uint32 currentRadCrystals; // Current count of radiant crystals +uint32 careerRadCrystals; // Total count of radiant crystals ever +uint32 currentEbonCrystals; // Current count of ebon crystals +uint32 careerEbonCrystals; // Total count of ebon crystals ever +*/ + +}; + +/* +** Client Target Struct +** Length: 2 Bytes +** OpCode: 6221 +*/ +struct ClientTarget_Struct { +/*000*/ uint32 new_target; // Target ID +}; + +/* +** Target Rejection Struct +** Length: 12 Bytes +** OpCode: OP_TargetReject +*/ +struct TargetReject_Struct { +/*00*/ uint8 unknown00[12]; +}; + +struct PetCommand_Struct { +/*00*/ uint32 command; +/*04*/ uint32 unknown04; +/*08*/ uint32 unknown08; +}; + +/* +** Delete Spawn +** Length: 5 Bytes +** OpCode: OP_DeleteSpawn +*/ +struct DeleteSpawn_Struct +{ +/*00*/ uint32 spawn_id; // Spawn ID to delete +/*04*/ uint8 unknown04; // Seen 1 +/*05*/ +}; + +/* +** Channel Message received or sent +** Length: 144 Bytes + Variable Length + 1 +** OpCode: OP_ChannelMessage +** +*/ +struct ChannelMessage_Struct +{ +/*000*/ char targetname[64]; // Tell recipient +/*064*/ char sender[64]; // The senders name (len might be wrong) +/*128*/ uint32 language; // Language +/*132*/ uint32 chan_num; // Channel +/*136*/ uint32 cm_unknown4[2]; // ***Placeholder +/*144*/ uint32 skill_in_language; // The players skill in this language? might be wrong +/*148*/ char message[0]; // Variable length message +}; + +/* +** Special Message +** Length: 4 Bytes + Variable Text Length + 1 +** OpCode: OP_SpecialMesg +** +*/ +/* + Theres something wrong with this... example live packet: +Server->Client: [ Opcode: OP_SpecialMesg (0x0fab) Size: 244 ] + 0: 01 02 00 0A 00 00 00 09 - 05 00 00 42 61 72 73 74 | ...........Barst + 16: 72 65 20 53 6F 6E 67 77 - 65 61 76 65 72 00 7C F9 | re Songweaver.|. + 32: FF FF 84 FF FF FF 03 00 - 00 00 47 72 65 65 74 69 | ..........Greeti + +*/ +struct SpecialMesg_Struct +{ +/*00*/ char header[3]; // 04 04 00 <-- for #emote style msg +/*03*/ uint32 msg_type; // Color of text (see MT_*** below) +/*07*/ uint32 target_spawn_id; // Who is it being said to? +/*11*/ char sayer[1]; // Who is the source of the info - Was 1 +/*12*/ uint8 unknown12[12]; +/*24*/ char message[128]; // What is being said? - was 128 +}; + +/* +** When somebody changes what they're wearing +** or give a pet a weapon (model changes) +** Length: 19 Bytes +*/ +struct WearChange_Struct{ +/*000*/ uint16 spawn_id; +/*002*/ uint32 material; +/*006*/ uint32 unknown06; +/*010*/ uint32 elite_material; // 1 for Drakkin Elite Material +/*014*/ uint32 hero_forge_model; // New to VoA +/*018*/ uint32 unknown18; // New to RoF2 +/*022*/ Color_Struct color; +/*026*/ uint8 wear_slot_id; +/*027*/ +}; + +/* +** Type: Bind Wound Structure +** Length: 8 Bytes +*/ +//Fixed for 7-14-04 patch +struct BindWound_Struct +{ +/*000*/ uint16 to; // TargetID +/*002*/ uint16 unknown2; // ***Placeholder +/*004*/ uint16 type; +/*006*/ uint16 unknown6; +}; + + +/* +** Type: Zone Change Request (before hand) +** Length: 88 bytes +** OpCode: a320 +*/ + +struct ZoneChange_Struct { +/*000*/ char char_name[64]; // Character Name +/*064*/ uint16 zoneID; +/*066*/ uint16 instanceID; +/*068*/ uint32 Unknown068; +/*072*/ uint32 Unknown072; +/*076*/ float y; +/*080*/ float x; +/*084*/ float z; +/*088*/ uint32 zone_reason; //0x0A == death, I think +/*092*/ int32 success; // =0 client->server, =1 server->client, -X=specific error +/*096*/ uint32 Unknown096; // Not sure the extra 4 bytes goes here or earlier in the struct. +/*100*/ +}; + +struct RequestClientZoneChange_Struct { +/*000*/ uint16 zone_id; +/*002*/ uint16 instance_id; +/*004*/ uint32 unknown004; +/*008*/ float y; +/*012*/ float x; +/*016*/ float z; +/*020*/ float heading; +/*024*/ uint32 type; //unknown... values +/*032*/ uint8 unknown032[144]; +/*172*/ uint32 unknown172; +/*176*/ +}; + +struct Animation_Struct { +/*00*/ uint16 spawnid; +/*02*/ uint8 value; +/*03*/ uint8 action; +/*04*/ +}; + +// solar: this is what causes the caster to animate and the target to +// get the particle effects around them when a spell is cast +// also causes a buff icon +struct Action_Struct +{ +/*00*/ uint16 target; // id of target +/*02*/ uint16 source; // id of caster +/*04*/ uint16 level; // level of caster - Seen 0 +/*06*/ uint32 unknown06; +/*10*/ float instrument_mod; +/*14*/ uint32 bard_focus_id; // seen 0 +/*18*/ float knockback_angle; //seems to go from 0-512 then it rolls over again +/*22*/ uint32 unknown22; +/*26*/ uint8 type; +/*27*/ uint32 damage; +/*31*/ uint16 unknown31; +/*33*/ uint32 spell; // spell id being cast +/*37*/ uint8 level2; // level of caster again? Or maybe the castee +/*38*/ uint8 effect_flag; // if this is 4, the effect is valid: or if two are sent at the same time? +/*39*/ +}; + +// Starting with 2/21/2006, OP_Actions seem to come in pairs, duplicating +// themselves, with the second one with slightly more information. Maybe this +// has to do with buff blocking?? +struct ActionAlt_Struct +{ +/*00*/ uint16 target; // id of target +/*02*/ uint16 source; // id of caster +/*04*/ uint16 level; // level of caster - Seen 0 +/*06*/ uint32 unknown06; +/*10*/ float instrument_mod; +/*14*/ uint32 bard_focus_id; // seen 0 +/*18*/ float knockback_angle; //seems to go from 0-512 then it rolls over again +/*22*/ uint32 unknown22; +/*26*/ uint8 type; +/*27*/ uint32 damage; +/*31*/ uint16 unknown31; +/*33*/ uint32 spell; // spell id being cast +/*37*/ uint8 level2; // level of caster again? Or maybe the castee +/*38*/ uint8 effect_flag; // if this is 4, the effect is valid: or if two are sent at the same time? +/*39*/ uint32 unknown39; // New field to Underfoot - Seen 14 +/*43*/ uint8 unknown43; // New field to Underfoot - Seen 0 +/*44*/ uint8 unknown44; // New field to Underfoot - Seen 17 +/*45*/ uint8 unknown45; // New field to Underfoot - Seen 0 +/*46*/ int32 unknown46; // New field to Underfoot - Seen -1 +/*50*/ uint32 unknown50; // New field to Underfoot - Seen 0 +/*54*/ uint16 unknown54; // New field to Underfoot - Seen 0 +/*56*/ +}; + +// solar: this is what prints the You have been struck. and the regular +// melee messages like You try to pierce, etc. It's basically the melee +// and spell damage message +struct CombatDamage_Struct +{ +/* 00 */ uint16 target; +/* 02 */ uint16 source; +/* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells +/* 05 */ uint32 spellid; +/* 09 */ int32 damage; +/* 13 */ float unknown11; // cd cc cc 3d +/* 17 */ float sequence; // see above notes in Action_Struct +/* 21 */ uint8 unknown19[9]; // was [9] +/* 30 */ +}; + + +/* +** Consider Struct +** Length: 20 Bytes +*/ +struct Consider_Struct{ +/*000*/ uint32 playerid; // PlayerID +/*004*/ uint32 targetid; // TargetID +/*008*/ uint32 faction; // Faction +/*012*/ uint32 level; // Level +/*016*/ uint8 pvpcon; // Pvp con flag 0/1 +/*017*/ uint8 unknown017[3]; // +/*020*/ +}; + +/* +** Spawn Death Blow +** Length: 32 Bytes +** OpCode: 0114 +*/ +struct Death_Struct +{ +/*000*/ uint32 spawn_id; +/*004*/ uint32 killer_id; +/*008*/ uint32 corpseid; // was corpseid +/*012*/ uint32 attack_skill; // was type +/*016*/ uint32 spell_id; +/*020*/ uint32 bindzoneid; //bindzoneid? +/*024*/ uint32 damage; +/*028*/ uint32 unknown028; +}; + +struct BecomeCorpse_Struct { + uint32 spawn_id; + float y; + float x; + float z; +}; + +struct ZonePlayerToBind_Struct { +/*000*/ uint16 bind_zone_id; +/*002*/ uint16 bind_instance_id; +/*004*/ float x; +/*008*/ float y; +/*012*/ float z; +/*016*/ float heading; +/*020*/ char zone_name[1]; // Or "Bind Location" +/*000*/ uint8 unknown021; // Seen 1 - Maybe 0 would be to force a rezone and 1 is just respawn +/*000*/ uint32 unknown022; // Seen 32 or 59 +/*000*/ uint32 unknown023; // Seen 0 +/*000*/ uint32 unknown024; // Seen 21 or 43 +}; + +struct ZonePlayerToBindHeader_Struct +{ + /*000*/ uint16 bind_zone_id; + /*002*/ uint16 bind_instance_id; + /*004*/ float x; + /*008*/ float y; + /*012*/ float z; + /*016*/ float heading; + /*020*/ char zone_name[1]; // Or "Bind Location" +}; + +struct ZonePlayerToBindFooter_Struct +{ + /*000*/ uint8 unknown021; // Seen 1 - Maybe 0 would be to force a rezone and 1 is just respawn + /*000*/ uint32 unknown022; // Seen 32 or 59 + /*000*/ uint32 unknown023; // Seen 0 + /*000*/ uint32 unknown024; // Seen 21 or 43 +}; + +typedef struct { +/*000*/ uint32 bind_number; // Number of this bind in the iteration +/*004*/ uint32 bind_zone_id; // ID of the zone for this bind point or resurect point +/*008*/ float x; // X loc for this bind point +/*012*/ float y; // Y loc for this bind point +/*016*/ float z; // Z loc for this bind point +/*020*/ float heading; // Heading for this bind point +/*024*/ char bind_zone_name[1]; // Or "Bind Location" or "Resurrect" +/*000*/ uint8 validity; // 0 = valid choice, 1 = not a valid choice at this time (resurrection) +} RespawnOptions_Struct; + +struct RespawnWindow_Struct { +/*000*/ uint32 unknown000; // Seen 0 +/*004*/ uint32 time_remaining; // Total time before respawn in milliseconds +/*008*/ uint32 unknown008; // Seen 0 +/*012*/ uint32 total_binds; // Total Bind Point Options? - Seen 2 +/*016*/ RespawnOptions_Struct bind_points; +// First bind point is "Bind Location" and the last one is "Ressurect" +}; + + +/* +** Spawn position update - Size: 22 +** Struct sent from server->client to update position of +** another spawn's position update in zone (whether NPC or PC) +** +*/ +struct PlayerPositionUpdateServer_Struct +{ + uint16 spawn_id; + uint16 spawnId2; + signed padding0004:12; + signed y_pos:19; // y coord + unsigned padding:1; + signed delta_z:13; // change in z + signed delta_x:13; // change in x + signed padding0008:6; + signed x_pos:19; // x coord + unsigned heading:12; // heading + signed padding0016:1; + signed delta_heading:10; // change in heading + signed z_pos:19; // z coord + signed padding0020:3; + signed animation:10; // animation + signed delta_y:13; // change in y + signed padding0024:9; +}; + +/* +** Player position update - Size: 40 +** Struct sent from client->server to update +** player position on server +** +*/ +struct PlayerPositionUpdateClient_Struct +{ + uint16 sequence; // increments one each packet - Verified + uint16 spawn_id; // Player's spawn id + uint8 unknown0004[6]; // ***Placeholder + float delta_x; // Change in x + unsigned heading:12; // Directional heading + unsigned padding0040:20; // ***Placeholder + float x_pos; // x coord (2nd loc value) + float delta_z; // Change in z + float z_pos; // z coord (3rd loc value) + float y_pos; // y coord (1st loc value) + unsigned animation:10; // ***Placeholder + unsigned padding0024:22; // animation + float delta_y; // Change in y + signed delta_heading:10; // change in heading + unsigned padding0041:22; // ***Placeholder +}; + +/* +** Spawn HP Update +** Length: 10 Bytes +** OpCode: OP_HPUpdate +*/ +struct SpawnHPUpdate_Struct +{ +/*00*/ int16 spawn_id; +/*02*/ uint32 cur_hp; +/*06*/ int32 max_hp; +/*10*/ +}; + +/* +** SendExpZonein +** Length: 152 Bytes +** OpCode: OP_SendExpZonein +*/ +struct SendExpZonein_Struct +{ +/*0000*/ uint16 spawn_id; // ID of the spawn +/*0002*/ uint16 type; // Values associated with the type +/*0004*/ uint32 parameter; // Type of data sent +/*0008*/ uint32 exp; // Current experience ratio from 0 to 330 +/*0012*/ uint32 expAA; +/*0016*/ uint8 unknown0016[4]; +/*0020*/ char name[64]; +/*0084*/ char last_name[64]; +/*00148*/ uint32 unknown132; +/*00152*/ +}; + +/* +** SendExpZonein +** Length: 0 Bytes +** OpCode: OP_SendExpZonein +*/ +//struct SendExpZonein_Struct {}; + +struct SpawnHPUpdate_Struct2 +{ +/*01*/ int16 spawn_id; +/*00*/ uint8 hp; +}; +/* +** Stamina +** Length: 8 Bytes +** OpCode: 5721 +*/ +struct Stamina_Struct { +/*00*/ uint32 food; // (low more hungry 127-0) +/*02*/ uint32 water; // (low more thirsty 127-0) +}; + +/* +** Level Update +** Length: 12 Bytes +*/ +struct LevelUpdate_Struct +{ +/*00*/ uint32 level; // New level +/*04*/ uint32 level_old; // Old level +/*08*/ uint32 exp; // Current Experience +}; + +/* +** Experience Update +** Length: 14 Bytes +** OpCode: 9921 +*/ +struct ExpUpdate_Struct +{ +/*0000*/ uint32 exp; // Current experience ratio from 0 to 330 +/*0004*/ uint32 aaxp; // @BP ?? +}; + +/* +** Item Packet Struct - Works on a variety of opcodes +** Packet Types: See ItemPacketType enum +** +*/ +enum ItemPacketType +{ + ItemPacketViewLink = 0x00, + ItemPacketTradeView = 0x65, + ItemPacketLoot = 0x66, + ItemPacketTrade = 0x67, + ItemPacketCharInventory = 0x69, + ItemPacketSummonItem = 0x6A, + ItemPacketTributeItem = 0x6C, + ItemPacketMerchant = 0x64, + ItemPacketWorldContainer = 0x6B +}; +struct ItemPacket_Struct +{ +/*00*/ ItemPacketType PacketType; +/*04*/ char SerializedItem[1]; //was 1 +/*xx*/ +}; + +struct BulkItemPacket_Struct +{ +/*00*/ char SerializedItem[0]; +/*xx*/ +}; + +struct Consume_Struct +{ +/*000*/ ItemSlotStruct slot; +/*012*/ uint32 auto_consumed; // 0xffffffff when auto eating e7030000 when right click +/*016*/ uint32 type; // 0x01=Food 0x02=Water +/*020*/ uint32 c_unknown1; // Seen 2 +/*024*/ +}; + +struct ItemNamePacket_Struct { +/*000*/ uint32 item_id; +/*004*/ uint32 unkown004; +/*008*/ char name[64]; +/*072*/ +}; + +// Length: 16 +struct ItemProperties_Struct_Old { + +/*000*/ uint8 unknown01[2]; +/*002*/ uint8 charges; +/*003*/ uint8 unknown02[13]; +/*016*/ +}; + +// Length: 8 +struct ItemProperties_Struct { + +/*000*/ uint8 unknown01[4]; +/*004*/ uint8 charges; +/*005*/ uint8 unknown02[3]; +/*008*/ +}; + +struct DeleteItem_Struct { +/*0000*/ ItemSlotStruct from_slot; +/*0012*/ ItemSlotStruct to_slot; +/*0024*/ uint32 number_in_stack; +/*0028*/ +}; + +struct MoveItem_Struct { +/*0000*/ ItemSlotStruct from_slot; +/*0012*/ ItemSlotStruct to_slot; +/*0024*/ uint32 number_in_stack; +/*0028*/ +}; + +// +// from_slot/to_slot +// -1 - destroy +// 0 - cursor +// 1 - inventory +// 2 - bank +// 3 - trade +// 4 - shared bank +// +// cointype +// 0 - copeer +// 1 - silver +// 2 - gold +// 3 - platinum +// +static const uint32 COINTYPE_PP = 3; +static const uint32 COINTYPE_GP = 2; +static const uint32 COINTYPE_SP = 1; +static const uint32 COINTYPE_CP = 0; + +struct MoveCoin_Struct +{ + int32 from_slot; + int32 to_slot; + int32 cointype1; + int32 cointype2; + int32 amount; +}; +struct TradeCoin_Struct{ + uint32 trader; + uint8 slot; + uint16 unknown5; + uint8 unknown7; + uint32 amount; +}; +struct TradeMoneyUpdate_Struct{ + uint32 trader; + uint32 type; + uint32 amount; +}; +/* +** Surname struct +** Size: 100 bytes +*/ +struct Surname_Struct +{ +/*0000*/ char name[64]; +/*0064*/ uint32 unknown0064; +/*0068*/ char lastname[32]; +/*0100*/ +}; + +struct GuildsListEntry_Struct { + char name[64]; +}; + +struct GuildsList_Struct { + uint8 head[64]; // First on guild list seems to be empty... + GuildsListEntry_Struct Guilds[MAX_NUMBER_GUILDS]; +}; + +struct GuildUpdate_Struct { + uint32 guildID; + GuildsListEntry_Struct entry; +}; + +/* +** Money Loot +** Length: 22 Bytes +** OpCode: 5020 +*/ +struct moneyOnCorpseStruct { +/*0000*/ uint8 response; // 0 = someone else is, 1 = OK, 2 = not at this time +/*0001*/ uint8 unknown1; // = 0x5a +/*0002*/ uint8 unknown2; // = 0x40 +/*0003*/ uint8 unknown3; // = 0 +/*0004*/ uint32 platinum; // Platinum Pieces +/*0008*/ uint32 gold; // Gold Pieces + +/*0012*/ uint32 silver; // Silver Pieces +/*0016*/ uint32 copper; // Copper Pieces +}; + +struct LootingItem_Struct { +/*000*/ uint32 lootee; +/*004*/ uint32 looter; +/*008*/ uint16 slot_id; +/*010*/ uint16 unknown10; +/*012*/ uint32 auto_loot; +/*016*/ uint32 unknown16; +/*020*/ +}; + +struct GuildManageStatus_Struct{ + uint32 guildid; + uint32 oldrank; + uint32 newrank; + char name[64]; +}; +// Guild invite, remove +struct GuildJoin_Struct{ +/*000*/ uint32 guild_id; +/*004*/ uint32 unknown04; +/*008*/ uint32 level; +/*012*/ uint32 class_; +/*016*/ uint32 rank;//0 member, 1 officer, 2 leader +/*020*/ uint32 zoneid; +/*024*/ uint32 unknown24; +/*028*/ char name[64]; +/*092*/ +}; +struct GuildInviteAccept_Struct { + char inviter[64]; + char newmember[64]; + uint32 response; + uint32 guildeqid; +}; +struct GuildManageRemove_Struct { + uint32 guildeqid; + char member[64]; +}; +struct GuildCommand_Struct { +/*000*/ char othername[64]; +/*064*/ char myname[64]; +/*128*/ uint16 guildeqid; +/*130*/ uint8 unknown[2]; // for guildinvite all 0's, for remove 0=0x56, 2=0x02 +/*132*/ uint32 officer; +/*136*/ uint32 unknown136; // New in RoF2 +/*140*/ +}; + +// Opcode OP_GMZoneRequest +// Size = 88 bytes +struct GMZoneRequest_Struct { +/*0000*/ char charname[64]; +/*0064*/ uint32 zone_id; +/*0068*/ float x; +/*0072*/ float y; +/*0076*/ float z; +/*0080*/ char unknown0080[4]; +/*0084*/ uint32 success; // 0 if command failed, 1 if succeeded? +/*0088*/ +// /*072*/ int8 success; // =0 client->server, =1 server->client, -X=specific error +// /*073*/ uint8 unknown0073[3]; // =0 ok, =ffffff error +}; + +struct GMSummon_Struct { +/* 0*/ char charname[64]; +/* 30*/ char gmname[64]; +/* 60*/ uint32 success; +/* 61*/ uint32 zoneID; +/*92*/ int32 y; +/*96*/ int32 x; +/*100*/ int32 z; +/*104*/ uint32 unknown2; // E0 E0 56 00 +}; + +struct GMGoto_Struct { // x,y is swapped as compared to summon and makes sense as own packet +/* 0*/ char charname[64]; + +/* 64*/ char gmname[64]; +/* 128*/ uint32 success; +/* 132*/ uint32 zoneID; + +/*136*/ int32 y; +/*140*/ int32 x; +/*144*/ int32 z; +/*148*/ uint32 unknown2; // E0 E0 56 00 +}; + +struct GMLastName_Struct { +/*000*/ char name[64]; +/*064*/ char gmname[64]; +/*128*/ char lastname[64]; +/*192*/ uint16 unknown[4]; // 0x00, 0x00, 0x01, 0x00 = Update the clients +/*200*/ uint32 unknown200[8]; +/*232*/ +}; + +struct OnLevelMessage_Struct { +/*0000*/ uint32 Title_Count; +/*0000*/ char Title[128]; +/*0000*/ uint32 Text_Count; +/*0000*/ char Text[4096]; +/*0000*/ uint32 ButtonName0_Count; +/*0000*/ char ButtonName0[25]; // If Buttons = 1, these two are the text for the left and right buttons respectively +/*0000*/ uint32 ButtonName1_Count; +/*0000*/ char ButtonName1[25]; +/*0000*/ uint8 Buttons; +/*0000*/ uint8 Unknown4275; // Something to do with audio controls +/*0000*/ uint32 Duration; +/*0000*/ uint32 PopupID; // If none zero, a response packet with 00 00 00 00 is returned on clicking the left button +/*0000*/ uint32 NegativeID; // If none zero, a response packet with 01 00 00 00 is returned on clicking the right button +/*0000*/ uint32 Unknown4288; +/*0000*/ uint8 Unknown4276; +/*0000*/ uint8 Unknown4277; +/*0000*/ +}; + +//Combat Abilities +struct CombatAbility_Struct { + uint32 m_target; //the ID of the target mob + uint32 m_atk; + uint32 m_skill; +}; + +//Instill Doubt +struct Instill_Doubt_Struct { + uint8 i_id; + uint8 ia_unknown; + uint8 ib_unknown; + uint8 ic_unknown; + uint8 i_atk; + + uint8 id_unknown; + uint8 ie_unknown; + uint8 if_unknown; + uint8 i_type; + uint8 ig_unknown; + uint8 ih_unknown; + uint8 ii_unknown; +}; + +struct GiveItem_Struct { + uint16 to_entity; + int16 to_equipSlot; + uint16 from_entity; + int16 from_equipSlot; +}; + +struct RandomReq_Struct { + uint32 low; + uint32 high; +}; + +/* solar: 9/23/03 reply to /random command; struct from Zaphod */ +struct RandomReply_Struct { +/* 00 */ uint32 low; +/* 04 */ uint32 high; +/* 08 */ uint32 result; +/* 12 */ char name[64]; +/* 76 */ +}; + +/* +** LFG_Appearance_Struct +** Packet sent to clients to notify when someone in zone toggles LFG flag +** Size: 8 bytes +** Used in: OP_LFGAppearance +** +*/ +struct LFG_Appearance_Struct +{ +/*0000*/ uint32 spawn_id; // ID of the client +/*0004*/ uint8 lfg; // 1=LFG, 0=Not LFG +/*0005*/ char unknown0005[3]; // +/*0008*/ +}; + + +// EverQuest Time Information: +// 72 minutes per EQ Day +// 3 minutes per EQ Hour +// 6 seconds per EQ Tick (2 minutes EQ Time) +// 3 seconds per EQ Minute + +struct TimeOfDay_Struct { + uint8 hour; + uint8 minute; + uint8 day; + uint8 month; + uint16 year; +/*0006*/ uint16 unknown0016; // Placeholder +/*0008*/ +}; + +// Darvik: shopkeeper structs +struct Merchant_Click_Struct { +/*000*/ uint32 npcid; // Merchant NPC's entity id +/*004*/ uint32 playerid; +/*008*/ uint32 command; // 1=open, 0=cancel/close +/*012*/ float rate; // cost multiplier, dosent work anymore +/*016*/ int32 unknown01; // Seen 3 from Server or -1 from Client +/*020*/ int32 unknown02; // Seen 2592000 from Server or -1 from Client +/*024*/ +}; +/* +Unknowns: +0 is e7 from 01 to // MAYBE SLOT IN PURCHASE +1 is 03 +2 is 00 +3 is 00 +4 is ?? +5 is ?? +6 is 00 from a0 to +7 is 00 from 3f to */ +/* +0 is F6 to 01 +1 is CE CE +4A 4A +00 00 +00 E0 +00 CB +00 90 +00 3F +*/ + +struct Merchant_Sell_Struct { +/*000*/ uint32 npcid; // Merchant NPC's entity id +/*004*/ uint32 playerid; // Player's entity id +/*008*/ uint32 itemslot; // Merchant Slot / Item Instance ID +/*012*/ uint32 unknown12; +/*016*/ uint32 quantity; // Already sold +/*020*/ uint32 unknown20; +/*024*/ uint32 price; +/*028*/ uint32 unknown28; // Normally 0, but seen 84 c5 63 00 as well +/*032*/ +}; + +struct Merchant_Purchase_Struct { +/*000*/ uint32 npcid; // Merchant NPC's entity id +/*004*/ MainInvItemSlotStruct itemslot; +/*012*/ uint32 quantity; +/*016*/ uint32 price; +/*020*/ +}; + +struct Merchant_DelItem_Struct{ +/*000*/ uint32 npcid; // Merchant NPC's entity id +/*004*/ uint32 playerid; // Player's entity id +/*008*/ uint32 itemslot; +}; + +struct AltCurrencyDefinition_Struct { + uint32 id; + uint32 item_id; +}; + +//One packet i didn't include here is the alt currency merchant window. +//it works much like the adventure merchant window +//it is formated like: dbstringid|1|dbstringid|count +//ex for a blank crowns window you would send: +//999999|1|999999|0 +//any items come after in much the same way adventure merchant items do except there is no theme included + +//Server -> Client +//Populates the initial Alternate Currency Window +struct AltCurrencyPopulateEntry_Struct +{ +/*000*/ uint32 currency_number; // corresponds to a dbstr id as well, the string matches what shows up in the "alternate currency" tab. +/*004*/ uint32 unknown00; // always 1 +/*008*/ uint32 currency_number2; // always same as currency number +/*012*/ uint32 item_id; // appears to be the item id +/*016*/ uint32 item_icon; // actual icon +/*020*/ uint32 stack_size; // most are set to 1000, the stack size for the item; should match db i think or there will be problems. +/*024*/ uint8 display; // If set to 0, will not display by default. +/*025*/ +}; + +struct AltCurrencyPopulate_Struct { +/*000*/ uint32 opcode; // 8 for populate +/*004*/ uint32 count; // number of entries +/*008*/ AltCurrencyPopulateEntry_Struct entries[0]; +}; + +//Server -> Client +//Updates the value of a specific Alternate Currency +struct AltCurrencyUpdate_Struct { +/*000*/ uint32 opcode; //7 for update +/*004*/ char name[64]; //name of client (who knows why just do it) +/*068*/ uint32 currency_number; //matches currency_number from populate entry +/*072*/ uint32 unknown072; //always 1 +/*076*/ uint32 amount; //new amount +/*080*/ uint32 unknown080; //seen 0 +/*084*/ uint32 unknown084; //seen 0 +}; + +//Client -> Server +//When an item is selected while the alt currency merchant window is open +struct AltCurrencySelectItem_Struct { +/*000*/ uint32 merchant_entity_id; +/*004*/ //uint32 slot_id; + ItemSlotStruct slot_id; +/*008*/ uint32 unknown008; +/*012*/ uint32 unknown012; +/*016*/ uint32 unknown016; +/*020*/ uint32 unknown020; +/*024*/ uint32 unknown024; +/*028*/ uint32 unknown028; +/*032*/ uint32 unknown032; +/*036*/ uint32 unknown036; +/*040*/ uint32 unknown040; +/*044*/ uint32 unknown044; +/*048*/ uint32 unknown048; +/*052*/ uint32 unknown052; +/*056*/ uint32 unknown056; +/*060*/ uint32 unknown060; +/*064*/ uint32 unknown064; +/*068*/ uint32 unknown068; +/*072*/ uint32 unknown072; +/*076*/ uint32 unknown076; +}; + +//Server -> Client +//As setup it makes it so that item can't be sold to the merchant. +//eg: "I will give you no doubloons for a cloth cap." +//Probably also sends amounts somewhere +struct AltCurrencySelectItemReply_Struct { +/*000*/ uint32 unknown000; +/*004*/ uint8 unknown004; //0xff +/*005*/ uint8 unknown005; //0xff +/*006*/ uint8 unknown006; //0xff +/*007*/ uint8 unknown007; //0xff +/*008*/ char item_name[64]; +/*072*/ uint32 unknown074; +/*076*/ uint32 cost; +/*080*/ uint32 unknown080; +/*084*/ uint32 unknown084; +}; + +//Client -> Server +//Requests purchase of a specific item from the vendor +struct AltCurrencyPurchaseItem_Struct { +/*000*/ uint32 merchant_entity_id; +/*004*/ uint32 item_id; +/*008*/ uint32 unknown008; //1 +}; + +//Client -> Server +//Reclaims / Create currency button pushed. +struct AltCurrencyReclaim_Struct { +/*000*/ uint32 currency_id; +/*004*/ uint32 unknown004; +/*008*/ uint32 count; +/*012*/ uint32 reclaim_flag; //1 = this is reclaim +}; + +struct AltCurrencySellItem_Struct { +/*000*/ uint32 merchant_entity_id; +/*004*/ //uint32 slot_id; + ItemSlotStruct slot_id; +/*008*/ uint32 charges; +/*012*/ uint32 cost; +}; + +struct Adventure_Purchase_Struct { +/*000*/ uint32 some_flag; //set to 1 generally... +/*004*/ uint32 npcid; +/*008*/ uint32 itemid; +/*012*/ uint32 variable; +}; + +struct Adventure_Sell_Struct { +/*000*/ uint32 unknown000; //0x01 - Stack Size/Charges? +/*004*/ uint32 npcid; +/*008*/ MainInvItemSlotStruct slot; +/*016*/ uint32 charges; +/*020*/ uint32 sell_price; +/*024*/ +}; + +struct AdventurePoints_Update_Struct { +/*000*/ uint32 ldon_available_points; // Total available points +/*004*/ uint8 unkown_apu004[20]; +/*024*/ uint32 ldon_guk_points; // Earned Deepest Guk points +/*028*/ uint32 ldon_mirugal_points; // Earned Mirugal' Mebagerie points +/*032*/ uint32 ldon_mistmoore_points; // Earned Mismoore Catacombs Points +/*036*/ uint32 ldon_rujarkian_points; // Earned Rujarkian Hills points +/*040*/ uint32 ldon_takish_points; // Earned Takish points +/*044*/ uint8 unknown_apu042[216]; +}; + + +struct AdventureFinish_Struct{ + uint32 win_lose;//Cofruben: 00 is a lose,01 is win. + uint32 points; +}; +//OP_AdventureRequest +struct AdventureRequest_Struct{ + uint32 risk;//1 normal,2 hard. + uint32 entity_id; +}; +struct AdventureRequestResponse_Struct{ + uint32 unknown000; + char text[2048]; + uint32 timetoenter; + uint32 timeleft; + uint32 risk; + float x; + float y; + float z; + uint32 showcompass; + uint32 unknown2080; +}; + +//this is mostly right but something is off that causes the client to crash sometimes +//I don't really care enough about the feature to work on it anymore though. +struct AdventureLeaderboardEntry_Struct +{ +/*004*/ char name[64]; +/*008*/ uint32 success; +/*012*/ uint32 failure; +/*016*/ +}; + +struct AdventureLeaderboard_Struct +{ +/*000*/ uint32 unknown000; +/*004*/ uint32 unknown004; +/*008*/ uint32 success; +/*012*/ uint32 failure; +/*016*/ uint32 our_rank; +/*020*/ +}; + +/*struct Item_Shop_Struct { + uint16 merchantid; + uint8 itemtype; + Item_Struct item; + uint8 iss_unknown001[6]; +};*/ + +struct Illusion_Struct { // Was size: 336 +/*000*/ uint32 spawnid; +/*004*/ char charname[64]; +/*068*/ uint16 race; +/*070*/ char unknown006[2]; // Weird green name +/*072*/ uint8 gender; +/*073*/ uint8 texture; +/*074*/ uint8 unknown074; +/*075*/ uint8 unknown075; +/*076*/ uint8 helmtexture; +/*077*/ uint8 unknown077; +/*078*/ uint8 unknown078; +/*079*/ uint8 unknown079; +/*080*/ uint32 face; +/*084*/ uint8 hairstyle; // Some Races don't change Hair Style Properly in SoF +/*085*/ uint8 haircolor; +/*086*/ uint8 beard; +/*087*/ uint8 beardcolor; +/*088*/ float size; +/*092*/ uint8 unknown092[148]; +/*240*/ uint32 unknown240; // Removes armor? +/*244*/ uint32 drakkin_heritage; +/*248*/ uint32 drakkin_tattoo; +/*252*/ uint32 drakkin_details; +/*256*/ uint8 unknown256[60]; // This and below are new to RoF2 +/*316*/ int32 unknown316; // Seen -1 +/*320*/ uint8 unknown320[16]; +/*336*/ +}; + +struct ZonePoint_Entry { //32 octets +/*0000*/ uint32 iterator; +/*0004*/ float y; +/*0008*/ float x; +/*0012*/ float z; +/*0016*/ float heading; +/*0020*/ uint16 zoneid; +/*0022*/ uint16 zoneinstance; // LDoN instance +/*0024*/ uint32 unknown024; +/*0028*/ uint32 unknown028; +/*0032*/ +}; + +struct ZonePoints { +/*0000*/ uint32 count; +/*0004*/ struct ZonePoint_Entry zpe[0]; // Always add one extra to the end after all zonepoints +//*0xxx*/ uint8 unknown0xxx[24]; //New from SEQ +}; + +struct SkillUpdate_Struct { +/*00*/ uint32 skillId; +/*04*/ uint32 value; +/*08*/ uint8 unknown08; // Seen 1 +/*09*/ uint8 unknown09; // Seen 80 +/*10*/ uint8 unknown10; // Seen 136 +/*11*/ uint8 unknown11; // Seen 54 +/*12*/ +}; + +struct ZoneUnavail_Struct { + //This actually varies, but... + char zonename[16]; + int16 unknown[4]; +}; + +struct GroupInvite_Struct { +/*0000*/ char invitee_name[64]; +/*0064*/ char inviter_name[64]; +/*0128*/ uint32 unknown0128; +/*0132*/ uint32 unknown0132; +/*0136*/ uint32 unknown0136; +/*0140*/ uint32 unknown0140; +/*0144*/ uint32 unknown0144; +/*0148*/ +}; + +struct GroupGeneric_Struct { +/*0000*/ char name1[64]; +/*0064*/ char name2[64]; +/*0128*/ uint32 unknown0128; +/*0132*/ uint32 unknown0132; +/*0136*/ uint32 unknown0136; +/*0140*/ uint32 unknown0140; +/*0144*/ uint32 unknown0144; +/*0148*/ +}; + +struct GroupCancel_Struct { +/*000*/ char name1[64]; +/*064*/ char name2[64]; +/*128*/ uint8 unknown128[20]; +/*148*/ uint32 toggle; +/*152*/ +}; + +struct GroupUpdate_Struct { +/*0000*/ uint32 action; +/*0004*/ char yourname[64]; +/*0068*/ char membername[5][64]; +/*0388*/ char leadersname[64]; +/*0452*/ +}; + +struct GroupUpdate2_Struct { +/*0000*/ uint32 action; +/*0004*/ char yourname[64]; +/*0068*/ char membername[5][64]; +/*0388*/ char leadersname[64]; +/*0452*/ GroupLeadershipAA_Struct leader_aas; +/*0516*/ uint8 unknown[252]; // Titanium uses [188] here +/*0768*/ +}; + +struct GroupUpdate_Struct_Live { // New for Live +/*0000*/ uint32 groupid; // Guess - Matches unknown0136 from GroupFollow_Struct +/*0004*/ uint32 totalmembers; // Guess +/*0000*/ //uint32 leadersname[0]; // Group Leader Name Null Terminated +/*0008*/ //GroupMembers_Struct groupmembers; +}; + +struct GroupMembers_Struct { // New for Live +/*0000*/ uint32 membernumber; // Guess - number of member in the group (0 to 5?) +/*0000*/ //char membername[0]; // Member Name Null Terminated +/*0000*/ uint8 unknown001[3]; // Seen 0 +/*0000*/ uint32 memberlevel; // Guess +/*0000*/ uint8 unknown002[11]; // Seen 0 +}; + +struct GroupJoin_Struct_Live { // New for Live +/*0000*/ uint32 unknown0000; // Matches unknown0136 from GroupFollow_Struct +/*0004*/ uint32 action; +/*0008*/ uint8 unknown0008[5]; // Seen 0 +/*0013*/ //char membername[0]; // Null Terminated? +/*0000*/ uint8 unknown0013[3]; // Seen 0 +/*0000*/ uint32 unknown0016; // Matches unknown0132 from GroupFollow_Struct +/*0000*/ uint8 unknown0020[11]; // Seen 0 +}; + +struct GroupJoin_Struct { +/*000*/ char unknown000[64]; +/*064*/ char membername[64]; +/*128*/ uint8 unknown128[20]; // Leadership AA ? +/*148*/ +}; + +struct GroupFollow_Struct { // Live Follow Struct +/*0000*/ char name1[64]; // inviter +/*0064*/ char name2[64]; // invitee +/*0128*/ uint32 unknown0128; // Seen 0 +/*0132*/ uint32 unknown0132; // Group ID or member level? +/*0136*/ uint32 unknown0136; // Maybe Voice Chat Channel or Group ID? +/*0140*/ uint32 unknown0140; // Seen 0 +/*0144*/ uint32 unknown0144; // Seen 0 +/*0148*/ uint32 unknown0148; +/*0152*/ +}; + +struct InspectBuffs_Struct { +/*000*/ uint32 spell_id[BUFF_COUNT]; +/*168*/ uint32 tics_remaining[BUFF_COUNT]; +}; + +struct LFG_Struct { +/*000*/ uint32 unknown000; +/*004*/ uint32 value; // 0x00 = off 0x01 = on +/*008*/ uint32 unknown008; +/*012*/ uint32 unknown012; +/*016*/ char name[64]; +}; + +struct FaceChange_Struct { +/*000*/ uint8 haircolor; +/*001*/ uint8 beardcolor; +/*002*/ uint8 eyecolor1; +/*003*/ uint8 eyecolor2; +/*004*/ uint8 hairstyle; +/*005*/ uint8 beard; +/*006*/ uint8 face; +/*007*/ uint8 unknown007; +/*008*/ uint32 drakkin_heritage; +/*012*/ uint32 drakkin_tattoo; +/*016*/ uint32 drakkin_details; +/*020*/ uint32 unknown020; +/*024*/ +}; +//there are only 10 faces for barbs changing woad just +//increase the face value by ten so if there were 8 woad +//designs then there would be 80 barb faces + +/* +** Trade request from one client to another +** Used to initiate a trade +** Size: 8 bytes +** Used in: OP_TradeRequest +*/ +struct TradeRequest_Struct { +/*00*/ uint32 to_mob_id; +/*04*/ uint32 from_mob_id; +/*08*/ +}; + +struct TradeAccept_Struct { +/*00*/ uint32 from_mob_id; +/*04*/ uint32 unknown4; //seems to be garbage +/*08*/ +}; + +/* +** Cancel Trade struct +** Sent when a player cancels a trade +** Size: 8 bytes +** Used In: OP_CancelTrade +** +*/ +struct CancelTrade_Struct { +/*00*/ uint32 fromid; +/*04*/ uint32 action; +/*08*/ +}; + +struct PetitionUpdate_Struct { + uint32 petnumber; // Petition Number + uint32 color; // 0x00 = green, 0x01 = yellow, 0x02 = red + uint32 status; + time_t senttime; // 4 has to be 0x1F + char accountid[32]; + char gmsenttoo[64]; + int32 quetotal; + char charname[64]; +}; + +struct Petition_Struct { + uint32 petnumber; + uint32 urgency; + char accountid[32]; + char lastgm[32]; + uint32 zone; + //char zone[32]; + char charname[64]; + uint32 charlevel; + uint32 charclass; + uint32 charrace; + uint32 unknown; + //time_t senttime; // Time? + uint32 checkouts; + uint32 unavail; + //uint8 unknown5[4]; + time_t senttime; + uint32 unknown2; + char petitiontext[1024]; + char gmtext[1024]; +}; + + +struct Who_All_Struct { // 156 length total +/*000*/ char whom[64]; +/*088*/ uint8 unknown088[64]; +/*064*/ uint32 wrace; // FF FF = no race +/*068*/ uint32 wclass; // FF FF = no class +/*072*/ uint32 lvllow; // FF FF = no numbers +/*076*/ uint32 lvlhigh; // FF FF = no numbers +/*080*/ uint32 gmlookup; // FF FF = not doing /who all gm +/*084*/ uint32 guildid; // Also used for Buyer/Trader/LFG +/*152*/ uint32 type; // 0 = /who 3 = /who all +/*156*/ +}; + +struct Stun_Struct { // 8 bytes total +/*000*/ uint32 duration; // Duration of stun +/*004*/ uint8 unknown004; // seen 0 +/*005*/ uint8 unknown005; // seen 163 +/*006*/ uint8 unknown006; // seen 67 +/*007*/ uint8 unknown007; // seen 0 +/*008*/ +}; + +struct AugmentItem_Struct { +/*00*/ uint32 dest_inst_id; // The unique serial number for the item instance that is being augmented +/*04*/ uint32 container_index; // Seen 0 +/*08*/ ItemSlotStruct container_slot; // Slot of the item being augmented +/*20*/ uint32 augment_index; // Seen 0 +/*24*/ ItemSlotStruct augment_slot; // Slot of the distiller to use (if one applies) +/*36*/ int32 augment_action; // Guessed - 0 = augment, 1 = remove with distiller, 3 = delete aug +/*36*/ //int32 augment_slot; +/*40*/ +}; + +// OP_Emote +struct Emote_Struct { +/*0000*/ uint32 unknown01; +/*0004*/ char message[1024]; // was 1024 +/*1028*/ +}; + +// Inspect +struct Inspect_Struct { + uint32 TargetID; + uint32 PlayerID; +}; + +//OP_InspectAnswer - Size: 1860 +struct InspectResponse_Struct{ +/*000*/ uint32 TargetID; +/*004*/ uint32 playerid; +/*008*/ char itemnames[23][64]; +/*1480*/uint32 itemicons[23]; +/*1572*/char text[288]; // Max number of chars in Inspect Window appears to be 254 +/*1860*/ +}; + +//OP_SetDataRate +struct SetDataRate_Struct { + float newdatarate; +}; + +//OP_SetServerFilter +struct SetServerFilter_Struct { + uint32 filters[35]; //see enum eqFilterType [31] +}; + +//Op_SetServerFilterAck +struct SetServerFilterAck_Struct { + uint8 blank[8]; +}; +struct IncreaseStat_Struct{ + /*0000*/ uint8 unknown0; + /*0001*/ uint8 str; + /*0002*/ uint8 sta; + /*0003*/ uint8 agi; + /*0004*/ uint8 dex; + /*0005*/ uint8 int_; + /*0006*/ uint8 wis; + /*0007*/ uint8 cha; + /*0008*/ uint8 fire; + /*0009*/ uint8 cold; + /*0010*/ uint8 magic; + /*0011*/ uint8 poison; + /*0012*/ uint8 disease; + /*0013*/ char unknown13[116]; + /*0129*/ uint8 str2; + /*0130*/ uint8 sta2; + /*0131*/ uint8 agi2; + /*0132*/ uint8 dex2; + /*0133*/ uint8 int_2; + /*0134*/ uint8 wis2; + /*0135*/ uint8 cha2; + /*0136*/ uint8 fire2; + /*0137*/ uint8 cold2; + /*0138*/ uint8 magic2; + /*0139*/ uint8 poison2; + /*0140*/ uint8 disease2; +}; + +struct GMName_Struct { + char oldname[64]; + char gmname[64]; + char newname[64]; + uint8 badname; + uint8 unknown[3]; +}; + +struct GMDelCorpse_Struct { + char corpsename[64]; + char gmname[64]; + uint8 unknown; +}; + +struct GMKick_Struct { + char name[64]; + char gmname[64]; + uint8 unknown; +}; + + +struct GMKill_Struct { + char name[64]; + char gmname[64]; + uint8 unknown; +}; + + +struct GMEmoteZone_Struct { + char text[512]; +}; + +// The BookText_Struct is not used in SoF and later clients. +// The BookRequest_Struct is used instead for both request and reply. +// +struct BookText_Struct { + uint8 window; // where to display the text (0xFF means new window) + uint8 type; //type: 0=scroll, 1=book, 2=item info.. prolly + char booktext[1]; // Variable Length - was 1 +}; +// This is the request to read a book. +// This is just a "text file" on the server +// or in our case, the 'name' column in our books table. +struct BookRequest_Struct { +/*0000*/ uint32 window; // where to display the text (0xFFFFFFFF means new window). +/*0004*/ uint16 invslot; // Is the slot, but the RoF2 conversion causes it to fail. Turned to 0 since it isnt required anyway. +/*0008*/ uint32 unknown006; // Seen FFFFFFFF +/*0010*/ uint16 unknown008; // seen 0000 +/*0012*/ uint32 type; // 0 = Scroll, 1 = Book, 2 = Item Info. Possibly others +/*0016*/ uint32 unknown0012; +/*0020*/ uint16 unknown0016; +/*0022*/ char txtfile[8194]; +}; + +/* +** Object/Ground Spawn struct +** Used for Forges, Ovens, ground spawns, items dropped to ground, etc +** Size: Variable +** OpCodes: OP_CreateObject +** +*/ +struct Object_Struct { +/*00*/ uint32 object_count; // Iteration count in the object list +/*00*/ char object_name[1]; // Name of object, usually something like IT63_ACTORDEF +/*00*/ uint16 zone_id; // Redudant, but: Zone the object appears in +/*00*/ uint16 zone_instance; // +/*00*/ uint32 drop_id; // Unique object id for zone +/*00*/ uint32 unknown024; // 53 9e f9 7e - same for all objects in the zone? +/*00*/ float heading; // heading +/*00*/ float unknown032[2]; // 00 00 00 00 00 00 00 00 +/*00*/ float size; // Size - default 1 +/*00*/ float z; // z coord +/*00*/ float x; // x coord +/*00*/ float y; // y coord +/*00*/ int32 object_type; // Type of object, not directly translated to OP_OpenObject +}; +// object_type - 01 = generic drop, 02 = armor, 19 = weapon +// 0xff seems to be indicative of the tradeskill/openable items that end up returning the old style item type in the OP_OpenObject + +/* +** Click Object Struct +** Client clicking on zone object (forge, groundspawn, etc) +** Size: 8 bytes +** Last Updated: Oct-17-2003 +** +*/ +struct ClickObject_Struct { +/*00*/ uint32 drop_id; // Appears to use the Object Count field now +/*04*/ uint32 player_id; +/*08*/ +}; + +struct Shielding_Struct { + uint32 target_id; +}; + +/* +** Click Object Acknowledgement Struct +** Response to client clicking on a World Container (ie, forge) +** +*/ +struct ClickObjectAction_Struct { +/*00*/ //uint32 player_id; // Appears to have been removed +/*00*/ uint32 drop_id; // Appears to use the object_count field now +/*04*/ int32 unknown04; // Seen -1 +/*08*/ int32 unknown08; // Seen -1 +/*08*/ //uint32 open; // 1=opening, 0=closing - Removed? +/*12*/ uint32 type; // See object.h, "Object Types" +/*16*/ uint32 unknown16; // +/*20*/ uint32 icon; // Icon to display for tradeskill containers +/*24*/ uint32 unknown24; // +/*28*/ char object_name[64]; // Object name to display +/*92*/ +}; + +/* +** This is different now, mostly unknown +** +*/ +struct CloseContainer_Struct { +/*00*/ uint32 player_id; // Entity Id of player who clicked object +/*04*/ uint32 drop_id; // Zone-specified unique object identifier +/*08*/ uint32 open; // 1=opening, 0=closing +/*12*/ uint32 unknown12[12]; +}; + +/* +** Generic Door Struct +** Length: 52 Octets +** Used in: +** cDoorSpawnsStruct(f721) +** +*/ +struct Door_Struct +{ +/*0000*/ char name[32]; // Filename of Door // Was 10char long before... added the 6 in the next unknown to it: Daeken M. BlackBlade +/*0032*/ float yPos; // y loc +/*0036*/ float xPos; // x loc +/*0040*/ float zPos; // z loc +/*0044*/ float heading; +/*0048*/ uint32 incline; // rotates the whole door +/*0052*/ uint32 size; // 100 is normal, smaller number = smaller model +/*0054*/ uint8 unknown0054[4]; // 00 00 00 00 +/*0060*/ uint8 doorId; // door's id # +/*0061*/ uint8 opentype; +/*0062*/ uint8 state_at_spawn; +/*0063*/ uint8 invert_state; // if this is 1, the door is normally open +/*0064*/ uint32 door_param; // normally ff ff ff ff (-1) +/*0068*/ uint32 unknown0068; // 00 00 00 00 +/*0072*/ uint32 unknown0072; // 00 00 00 00 +/*0076*/ uint8 unknown0076[4]; // New for RoF2 +/*0080*/ uint8 unknown0080; // seen 1 or 0 +/*0081*/ uint8 unknown0081; // seen 1 (always?) +/*0082*/ uint8 unknown0082; // seen 0 (always?) +/*0083*/ uint8 unknown0083; // seen 1 (always?) +/*0084*/ uint8 unknown0084; // seen 0 (always?) +/*0085*/ uint8 unknown0085; // seen 1 or 0 or rarely 2C or 90 or ED or 2D or A1 +/*0086*/ uint8 unknown0086; // seen 0 or rarely FF or FE or 10 or 5A or 82 +/*0087*/ uint8 unknown0087; // seen 0 or rarely 02 or 7C +/*0088*/ uint8 unknown0088[12]; // mostly 0s, the last 3 bytes are something tho +/*0100*/ +}; + +struct DoorSpawns_Struct { + struct Door_Struct doors[0]; +}; + +/* + OP Code: Op_ClickDoor + Size: 16 +*/ +struct ClickDoor_Struct { +/*000*/ uint8 doorid; +/*001*/ uint8 unknown001; // This may be some type of action setting +/*002*/ uint8 unknown002; // This is sometimes set after a lever is closed +/*003*/ uint8 unknown003; // Seen 0 +/*004*/ uint8 picklockskill; +/*005*/ uint8 unknown005[3]; +/*008*/ uint32 item_id; +/*012*/ uint16 player_id; +/*014*/ uint8 unknown014[2]; +/*016*/ +}; + +struct MoveDoor_Struct { + uint8 doorid; + uint8 action; +}; + + +struct BecomeNPC_Struct { + uint32 id; + int32 maxlevel; +}; + +struct Underworld_Struct { + float speed; + float y; + float x; + float z; +}; + +struct Resurrect_Struct +{ +/*000*/ uint32 unknown000; +/*004*/ uint16 zone_id; +/*006*/ uint16 instance_id; +/*008*/ float y; +/*012*/ float x; +/*016*/ float z; +/*020*/ uint32 unknown020; +/*024*/ char your_name[64]; +/*088*/ uint32 unknown088; +/*092*/ char rezzer_name[64]; +/*156*/ uint32 spellid; +/*160*/ char corpse_name[64]; +/*224*/ uint32 action; +/*228*/ uint32 unknown228; +/*232*/ +}; + +struct SetRunMode_Struct { + uint8 mode; //01=run 00=walk + uint8 unknown[3]; +}; + +// EnvDamage is EnvDamage2 without a few bytes at the end. +// Size: 37 bytes +struct EnvDamage2_Struct { +/*0000*/ uint32 id; +/*0004*/ uint16 unknown4; +/*0006*/ uint32 damage; +/*0010*/ float unknown10; // New to Underfoot - Seen 1 +/*0014*/ uint8 unknown14[12]; +/*0026*/ uint8 dmgtype; // FA = Lava; FC = Falling +/*0027*/ uint8 unknown27[4]; +/*0031*/ uint16 unknown31; // New to Underfoot - Seen 66 +/*0033*/ uint16 constant; // Always FFFF +/*0035*/ uint16 unknown35; +/*0037*/ +}; + +//Bazaar Stuff + +enum { + BazaarTrader_StartTraderMode = 1, + BazaarTrader_EndTraderMode = 2, + BazaarTrader_UpdatePrice = 3, + BazaarTrader_EndTransaction = 4, + BazaarSearchResults = 7, + BazaarWelcome = 9, + BazaarBuyItem = 10, + BazaarTrader_ShowItems = 11, + BazaarSearchDone = 12, + BazaarTrader_CustomerBrowsing = 13, + BazaarInspectItem = 18, + BazaarSearchDone2 = 19, + BazaarTrader_StartTraderMode2 = 22 +}; + +enum { + BazaarPriceChange_Fail = 0, + BazaarPriceChange_UpdatePrice = 1, + BazaarPriceChange_RemoveItem = 2, + BazaarPriceChange_AddItem = 3 +}; + +struct BazaarWindowStart_Struct { + uint8 Action; + uint8 Unknown001; + uint16 Unknown002; +}; + + +struct BazaarWelcome_Struct { + BazaarWindowStart_Struct Beginning; + uint32 Traders; + uint32 Items; + uint8 Unknown012[8]; +}; + +struct BazaarSearch_Struct { + BazaarWindowStart_Struct Beginning; + uint32 TraderID; + uint32 Class_; + uint32 Race; + uint32 ItemStat; + uint32 Slot; + uint32 Type; + char Name[64]; + uint32 MinPrice; + uint32 MaxPrice; + uint32 Minlevel; + uint32 MaxLlevel; +}; +struct BazaarInspect_Struct{ + uint32 ItemID; + uint32 Unknown004; + char Name[64]; +}; + +struct NewBazaarInspect_Struct { +/*000*/ BazaarWindowStart_Struct Beginning; +/*004*/ char Name[64]; +/*068*/ uint32 Unknown068; +/*072*/ int32 SerialNumber; +/*076*/ uint32 Unknown076; +/*080*/ uint32 SellerID; +/*084*/ uint32 Unknown084; +}; + +struct BazaarReturnDone_Struct{ + uint32 Type; + uint32 TraderID; + uint32 Unknown008; + uint32 Unknown012; + uint32 Unknown016; +}; + +struct BazaarSearchResults_Struct { +/*000*/ BazaarWindowStart_Struct Beginning; +/*004*/ uint32 SellerID; +/*008*/ char SellerName[64]; +/*072*/ uint32 NumItems; +/*076*/ uint32 ItemID; +/*080*/ uint32 SerialNumber; +/*084*/ uint32 Unknown084; +/*088*/ char ItemName[64]; +/*152*/ uint32 Cost; +/*156*/ uint32 ItemStat; +/*160*/ +}; + +struct ServerSideFilters_Struct { +uint8 clientattackfilters; // 0) No, 1) All (players) but self, 2) All (players) but group +uint8 npcattackfilters; // 0) No, 1) Ignore NPC misses (all), 2) Ignore NPC Misses + Attacks (all but self), 3) Ignores NPC Misses + Attacks (all but group) +uint8 clientcastfilters; // 0) No, 1) Ignore PC Casts (all), 2) Ignore PC Casts (not directed towards self) +uint8 npccastfilters; // 0) No, 1) Ignore NPC Casts (all), 2) Ignore NPC Casts (not directed towards self) +}; + +/* +** Client requesting item statistics +** Size: 52 bytes +** Used In: OP_ItemLinkClick +** Last Updated: 01/03/2012 +** +*/ +struct ItemViewRequest_Struct { +/*000*/ uint32 item_id; +/*004*/ uint32 augments[6]; +/*028*/ uint32 link_hash; +/*032*/ uint32 unknown028; //seems to always be 4 on SoF client +/*036*/ char unknown032[12]; //probably includes loregroup & evolving info. see Client::MakeItemLink() in zone/inventory.cpp:469 +/*048*/ uint16 icon; +/*050*/ char unknown046[2]; +/*052*/ +}; + +/* + * Client to server packet + */ +struct PickPocket_Struct { +// Size 18 + uint32 to; + uint32 from; + uint16 myskill; + uint8 type; // -1 you are being picked, 0 failed , 1 = plat, 2 = gold, 3 = silver, 4 = copper, 5 = item + uint8 unknown1; // 0 for response, unknown for input + uint32 coin; + uint8 lastsix[2]; +}; +/* + * Server to client packet + */ + +struct sPickPocket_Struct { + // Size 28 = coin/fail + uint32 to; + uint32 from; + uint32 myskill; + uint32 type; + uint32 coin; + char itemname[64]; +}; + + +struct LogServer_Struct { +// Op_Code OP_LOGSERVER +/*000*/ uint32 unknown000; +/*004*/ uint8 enable_pvp; +/*005*/ uint8 unknown005; +/*006*/ uint8 unknown006; +/*007*/ uint8 unknown007; +/*008*/ uint8 enable_FV; +/*009*/ uint8 unknown009; +/*010*/ uint8 unknown010; +/*011*/ uint8 unknown011; +/*012*/ uint32 unknown012; // htonl(1) on live +/*016*/ uint32 unknown016; // htonl(1) on live +/*020*/ uint8 unknown020[12]; +/*032*/ uint32 unknown032; +/*036*/ char worldshortname[32]; +/*068*/ uint8 unknown068[181]; +/*249*/ uint8 unknown249[27]; +/*276*/ float unknown276[7]; +/*304*/ uint8 unknown304[256]; +/*560*/ + +/* Currently lost + uint8 enablevoicemacros; + uint8 enablemail; +*/ +}; + +struct ApproveWorld_Struct { +// Size 544 +// Op_Code OP_ApproveWorld + uint8 unknown544[544]; +}; + +struct ClientError_Struct +{ +/*00001*/ char type; +/*00001*/ char unknown0001[69]; +/*00069*/ char character_name[64]; +/*00134*/ char unknown134[192]; +/*00133*/ char message[31994]; +/*32136*/ +}; + +struct MobHealth +{ + /*0000*/ uint8 hp; //health percent + /*0001*/ uint16 id;//mobs id +}; + +struct Track_Struct { + uint16 entityid; + uint16 y; + uint16 x; + uint16 z; +}; + +struct Tracking_Struct { + Track_Struct Entrys[0]; +}; + +// Looks like new tracking structures - Opcode: 0x57a7 +struct Tracking_Struct_New { + uint16 totalcount; // Total Count of mobs within tracking range + Track_Struct Entrys[0]; +}; + +struct Track_Struct_New { + uint16 entityid; // Entity ID + uint16 unknown002; // 00 00 + uint32 unknown004; // + uint8 level; // level of mob + uint8 unknown009; // 01 maybe type of mob? player/npc? + char name[1]; // name of mob +}; + + +/* +** ZoneServerInfo_Struct +** Zone server information +** Size: 130 bytes +** Used In: OP_ZoneServerInfo +** +*/ +struct ZoneServerInfo_Struct +{ +/*0000*/ char ip[128]; +/*0128*/ uint16 port; +}; + +struct WhoAllPlayer{ + uint32 formatstring; + uint32 pidstring; + int32 unknown64; // Seen -1 + char* name; + uint32 rankstring; + char* guild; + uint32 unknown80[2]; + uint32 zonestring; + uint32 zone; + uint32 class_; + uint32 level; + uint32 race; + char* account; + uint32 unknown100; +}; + +struct WhoAllReturnStruct { + uint32 id; + uint32 playerineqstring; + char line[27]; + uint8 unknown35; // 0A + uint32 unknown36; // Seen 208243456 + uint32 playersinzonestring; + uint32 unknown52; // Same as playercount? + uint32 unknown44[2]; // 0s + uint32 unknown56; // Same as playercount? + uint32 playercount; // Player Count in the who list + struct WhoAllPlayer player[0]; +}; + +// The following four structs are the WhoAllPlayer struct above broken down +// for use in World ClientList::SendFriendsWho to accomodate the user of variable +// length strings within the struct above. + +struct WhoAllPlayerPart1 { + uint32 FormatMSGID; + uint32 Unknown04; + uint32 Unknown08; + char Name[1]; +}; + +struct WhoAllPlayerPart2 { + uint32 RankMSGID; + char Guild[1]; +}; + +struct WhoAllPlayerPart3 { + uint32 Unknown80[2]; + uint32 ZoneMSGID; + uint32 Zone; + uint32 Class_; + uint32 Level; + uint32 Race; + char Account[1]; +}; + +struct WhoAllPlayerPart4 { + uint32 Unknown100; +}; + +struct TraderItemSerial_Struct { + char SerialNumber[17]; + uint8 Unknown18; +}; + +struct Trader_Struct { +/*0000*/ uint32 Code; +/*0004*/ TraderItemSerial_Struct items[200]; +/*3604*/ uint32 ItemCost[200]; +/*4404*/ +}; + +struct ClickTrader_Struct { +/*0000*/ uint32 Code; +/*0004*/ TraderItemSerial_Struct items[200]; +/*3604*/ uint32 ItemCost[200]; +/*4404*/ +}; + +struct GetItems_Struct { + uint32 items[200]; +}; + +struct BecomeTrader_Struct { + uint32 id; + uint32 code; +}; + +struct Trader_ShowItems_Struct { +/*000*/ uint32 Code; +/*004*/ char SerialNumber[17]; +/*021*/ uint8 Unknown21; +/*022*/ uint16 TraderID; +/*026*/ uint32 Stacksize; +/*030*/ uint32 Price; +/*032*/ +}; + +struct TraderStatus_Struct { +/*000*/ uint32 Code; +/*004*/ uint32 Uknown04; +/*008*/ uint32 Uknown08; +/*012*/ +}; + +struct TraderBuy_Struct { +/*000*/ uint32 Action; +/*004*/ uint32 Unknown004; +/*008*/ uint32 Price; +/*012*/ uint32 Unknown008; // Probably high order bits of a 64 bit price. +/*016*/ uint32 TraderID; +/*020*/ char ItemName[64]; +/*084*/ uint32 Unknown076; +/*088*/ uint32 ItemID; +/*092*/ uint32 AlreadySold; +/*096*/ uint32 Quantity; +/*100*/ uint32 Unknown092; +/*104*/ +}; + +struct TraderItemUpdate_Struct{ + uint32 unknown0; + uint32 traderid; + uint8 fromslot; + uint8 toslot; //7? + uint16 charges; +}; + +struct MoneyUpdate_Struct{ + int32 platinum; + int32 gold; + int32 silver; + int32 copper; +}; + +//struct MoneyUpdate_Struct +//{ +//*0000*/ uint32 spawn_id; // ***Placeholder +//*0004*/ uint32 cointype; // Coin Type +//*0008*/ uint32 amount; // Amount +//*0012*/ +//}; + + +struct TraderDelItem_Struct{ + uint32 slotid; + uint32 quantity; + uint32 unknown; +}; + +struct TraderClick_Struct{ + uint32 traderid; + uint32 unknown4[2]; + uint32 approval; +}; + +struct FormattedMessage_Struct{ + uint32 unknown0; + uint32 string_id; + uint32 type; + char message[0]; +//*0???*/ uint8 unknown0[8]; // ***Placeholder +}; +struct SimpleMessage_Struct{ + uint32 string_id; + uint32 color; + uint32 unknown8; +}; + +// Size: 52 + strings +// Other than the strings, all of this packet is network byte order (reverse from normal) +struct GuildMemberEntry_Struct { + char name[1]; // variable length + uint32 level; + uint32 banker; // 1=yes, 0=no + uint32 class_; + uint32 rank; + uint32 time_last_on; + uint32 tribute_enable; + uint32 unknown01; // Seen 0 + uint32 total_tribute; // total guild tribute donated, network byte order + uint32 last_tribute; // unix timestamp + uint32 unknown_one; // unknown, set to 1 + char public_note[1]; // variable length. + uint16 zoneinstance; // Seen 0s or -1 in RoF2 + uint16 zone_id; // Seen 0s or -1 in RoF2 + uint32 unknown_one2; // unknown, set to 1 + uint32 unknown04; // Seen 0 +}; + +//just for display purposes, this is not actually used in the message encoding other than for size. +struct GuildMembers_Struct { + char player_name[1]; // variable length. + uint32 guildid; // Was unknown02 - network byte order + uint32 count; // network byte order + GuildMemberEntry_Struct member[0]; +}; + +struct GuildMOTD_Struct{ +/*0000*/ uint32 unknown0; +/*0004*/ char name[64]; +/*0068*/ char setby_name[64]; +/*0132*/ uint32 unknown132; +/*0136*/ char motd[0]; //was 512 +}; + +struct GuildURL_Struct{ +/*0000*/ uint32 unknown0; //index? seen server send 0 w/ the Guild URL, followed by 1 with nothing. +/*0004*/ uint32 unknown4; +/*0008*/ uint32 unknown8; //seen 7 +/*0012*/ char setby_name[64]; +/*0076*/ uint32 unknown132; //seen 0xc7de +/*0136*/ char url[4040]; +}; + +struct GuildStatus_Struct +{ +/*000*/ char Name[64]; +/*064*/ uint8 Unknown064[76]; +}; + +struct GuildMemberUpdate_Struct { +/*00*/ uint32 GuildID; +/*04*/ char MemberName[64]; +/*68*/ uint16 ZoneID; +/*70*/ uint16 InstanceID; //speculated +/*72*/ uint32 LastSeen; //unix timestamp +/*76*/ uint32 Unknown76; +/*80*/ +}; + +struct GuildMemberLevelUpdate_Struct { +/*00*/ uint32 guild_id; +/*04*/ char member_name[64]; +/*68*/ uint32 level; //not sure +}; + +struct GuildUpdate_PublicNote { + uint32 unknown0; + char name[64]; + char target[64]; + char note[100]; //we are cutting this off at 100, actually around 252 +}; + +struct GuildDemoteStruct { +/*000*/ char name[64]; +/*064*/ char target[64]; +/*128*/ uint32 rank; // New in RoF2 +/*132*/ +}; + +struct GuildRemoveStruct { +/*000*/ char target[64]; +/*064*/ char name[64]; +/*128*/ uint32 GuildID; // Was unknown128 +/*132*/ uint32 leaderstatus; +/*136*/ uint32 unknown136; // New in RoF2 +/*140*/ +}; + +struct GuildMakeLeader { + char name[64]; + char target[64]; +}; + +// Server -> Client +// Update a guild members rank and banker status +struct GuildSetRank_Struct +{ +/*00*/ uint32 GuildID; // Was Unknown00 +/*04*/ uint32 Rank; +/*08*/ char MemberName[64]; +/*72*/ uint32 Banker; +/*76*/ uint32 Unknown76; // Seen 1 - Maybe Banker? +/*80*/ +}; + +struct BugStruct{ +/*0000*/ char chartype[64]; +/*0064*/ char name[96]; +/*0160*/ char ui[128]; +/*0288*/ float x; +/*0292*/ float y; +/*0296*/ float z; +/*0300*/ float heading; +/*0304*/ uint32 unknown304; +/*0308*/ uint32 type; +/*0312*/ char unknown312[2144]; +/*2456*/ char bug[1024]; +/*3480*/ char placeholder[2]; +/*3482*/ char system_info[4098]; +}; +struct Make_Pet_Struct { //Simple struct for getting pet info + uint8 level; + uint8 class_; + uint16 race; + uint8 texture; + uint8 pettype; + float size; + uint8 type; + uint32 min_dmg; + uint32 max_dmg; +}; +struct Ground_Spawn{ + float max_x; + float max_y; + float min_x; + float min_y; + float max_z; + float heading; + char name[16]; + uint32 item; + uint32 max_allowed; + uint32 respawntimer; +}; +struct Ground_Spawns { + struct Ground_Spawn spawn[50]; //Assigned max number to allow +}; +struct PetitionBug_Struct{ + uint32 petition_number; + uint32 unknown4; + char accountname[64]; + uint32 zoneid; + char name[64]; + uint32 level; + uint32 class_; + uint32 race; + uint32 unknown152[3]; + uint32 time; + uint32 unknown168; + char text[1028]; +}; + +struct DyeStruct +{ + union + { + struct + { + struct Color_Struct head; + struct Color_Struct chest; + struct Color_Struct arms; + struct Color_Struct wrists; + struct Color_Struct hands; + struct Color_Struct legs; + struct Color_Struct feet; + struct Color_Struct primary; // you can't actually dye this + struct Color_Struct secondary; // or this + } + dyes; + struct Color_Struct dye[9]; + }; +}; + +struct ApproveZone_Struct { + char name[64]; + uint32 zoneid; + uint32 approve; +}; +struct ZoneInSendName_Struct { + uint32 unknown0; + char name[64]; + char name2[64]; + uint32 unknown132; +}; +struct ZoneInSendName_Struct2 { + uint32 unknown0; + char name[64]; + uint32 unknown68[145]; +}; + +struct StartTribute_Struct { + uint32 client_id; + uint32 tribute_master_id; + uint32 response; +}; + +struct TributeLevel_Struct { + uint32 level; //backwards byte order! + uint32 tribute_item_id; //backwards byte order! + uint32 cost; //backwards byte order! +}; + +struct TributeAbility_Struct { +/*000*/ uint32 tribute_id; //backwards byte order! +/*004*/ uint32 tier_count; //backwards byte order! +/*008*/ TributeLevel_Struct tiers[MAX_TRIBUTE_TIERS]; +/*128*/ uint32 unknown128; // New to RoF2 +/*132*/ char name[0]; +}; + +struct GuildTributeAbility_Struct { + uint32 guild_id; + TributeAbility_Struct ability; +}; + +struct SelectTributeReq_Struct { + uint32 client_id; //? maybe action ID? + uint32 tribute_id; + uint32 unknown8; //seen E3 00 00 00 +}; + +struct SelectTributeReply_Struct { + uint32 client_id; //echoed from request. + uint32 tribute_id; + char desc[0]; +}; + +struct TributeInfo_Struct { + uint32 active; //0 == inactive, 1 == active + uint32 tributes[MAX_PLAYER_TRIBUTES]; //-1 == NONE + uint32 tiers[MAX_PLAYER_TRIBUTES]; //all 00's + uint32 tribute_master_id; +}; + +struct TributeItem_Struct +{ +/*00*/ ItemSlotStruct slot; +/*12*/ uint32 quantity; +/*16*/ uint32 tribute_master_id; +/*20*/ int32 tribute_points; +/*24*/ +}; + +struct TributePoint_Struct { + int32 tribute_points; + uint32 unknown04; + int32 career_tribute_points; + uint32 unknown12; +}; + +struct TributeMoney_Struct { + uint32 platinum; + uint32 tribute_master_id; + int32 tribute_points; +}; + + +struct Split_Struct +{ + uint32 platinum; + uint32 gold; + uint32 silver; + uint32 copper; +}; + + +/* +** New Combine Struct +** Client requesting to perform a tradeskill combine +** Size: 24 bytes +** Used In: OP_TradeSkillCombine +** Last Updated: 01-05-2013 +*/ +struct NewCombine_Struct { +/*00*/ ItemSlotStruct container_slot; +/*12*/ ItemSlotStruct guildtribute_slot; // Slot type is 8? (MapGuildTribute = 8 -U) +/*24*/ +}; + + +//client requesting favorite recipies +struct TradeskillFavorites_Struct { + uint32 object_type; + uint32 some_id; + uint32 favorite_recipes[500]; +}; + +//search request +struct RecipesSearch_Struct { + uint32 object_type; //same as in favorites + uint32 some_id; //same as in favorites + uint32 mintrivial; + uint32 maxtrivial; + char query[56]; + uint32 unknown4; //is set to 00 03 00 00 + uint32 unknown5; //is set to 4C DD 12 00 +/*80*/ +}; + +//one sent for each item, from server in reply to favorites or search +struct RecipeReply_Struct { + uint32 object_type; + uint32 some_id; //same as in favorites + uint32 component_count; + uint32 recipe_id; + uint32 trivial; + char recipe_name[64]; +/*84*/ +}; + +//received and sent back as an ACK with different reply_code +struct RecipeAutoCombine_Struct { +/*00*/ uint32 object_type; +/*04*/ uint32 some_id; +/*08*/ ItemSlotStruct container_slot; //echoed in reply - Was uint32 unknown1 +/*20*/ ItemSlotStruct unknown_slot; //echoed in reply +/*32*/ uint32 recipe_id; +/*36*/ uint32 reply_code; +/*40*/ +}; + +struct LevelAppearance_Struct { //Sends a little graphic on level up + uint32 spawn_id; + uint32 parm1; + uint32 value1a; + uint32 value1b; + uint32 parm2; + uint32 value2a; + uint32 value2b; + uint32 parm3; + uint32 value3a; + uint32 value3b; + uint32 parm4; + uint32 value4a; + uint32 value4b; + uint32 parm5; + uint32 value5a; + uint32 value5b; +/*64*/ +}; +struct MerchantList{ + uint32 id; + uint32 slot; + uint32 item; +}; +struct TempMerchantList{ + uint32 npcid; + uint32 slot; + uint32 item; + uint32 charges; //charges/quantity + uint32 origslot; +}; + + +struct FindPerson_Point { + float y; + float x; + float z; +}; + +struct FindPersonRequest_Struct { +/*00*/ uint32 unknown00; +/*04*/ uint32 npc_id; +/*08*/ uint32 unknown08; +/*12*/ uint32 unknown12; +/*16*/ FindPerson_Point client_pos; +/*28*/ uint32 unknown28; +/*32*/ uint32 unknown32; +/*36*/ uint32 unknown36; +}; + +//variable length packet of points +struct FindPersonResult_Struct { + FindPerson_Point dest; + FindPerson_Point path[0]; //last element must be the same as dest +}; + +struct MobRename_Struct { +/*000*/ char old_name[64]; +/*064*/ char old_name_again[64]; //not sure what the difference is +/*128*/ char new_name[64]; +/*192*/ uint32 unknown192; //set to 0 +/*196*/ uint32 unknown196; //set to 1 +/*200*/ +}; + +struct PlayMP3_Struct { + char filename[0]; +}; + +//this is for custom title display in the skill window +struct TitleEntry_Struct { + uint32 skill_id; + uint32 skill_value; + char title[1]; +}; + +struct Titles_Struct { + uint32 title_count; + TitleEntry_Struct titles[0]; +}; + +//this is for title selection by the client +struct TitleListEntry_Struct { + uint32 unknown0; //title ID + char prefix[1]; //variable length, null terminated + char postfix[1]; //variable length, null terminated +}; + +struct TitleList_Struct { + uint32 title_count; + TitleListEntry_Struct titles[0]; //list of title structs + //uint32 unknown_ending; seen 0x7265, 0 +}; + +struct SetTitle_Struct { + uint32 is_suffix; //guessed: 0 = prefix, 1 = suffix + uint32 title_id; +}; + +struct SetTitleReply_Struct { + uint32 is_suffix; //guessed: 0 = prefix, 1 = suffix + char title[32]; + uint32 entity_id; +}; + + +#if 0 +// Old struct not used by Task System implementation but left for reference +struct TaskDescription_Struct { +/*000*/ uint32 activity_count; //not right. +/*004*/ uint32 taskid; +/*008*/ uint8 unk; +/*009*/ uint32 id3; +/*013*/ uint32 unknown13; +/*017*/ char name[1]; //variable length, 0 terminated +/*018*/ uint32 unknown18; +/*022*/ uint32 unknown22; +/*026*/ uint32 unknown26; +/*030*/ char desc[1]; //variable length, 0 terminated +/*031*/ uint32 reward_count; //not sure +/*035*/ uint8 unknown31; +/*036*/ uint32 unknown31; +/*040*/ uint32 unknown35; +/*044*/ uint16 unknown39; +/*046*/ char reward_link[1]; //variable length, 0 terminated +/*047*/ uint32 unknown43; //maybe crystal count? +/*051*/ +}; +#endif + +struct TaskMemberList_Struct { +/*00*/ uint32 gopher_id; +/*04*/ uint32 unknown04; +/*08*/ uint32 member_count; //1 less than the number of members +/*12*/ char list_pointer[0]; +/* list is of the form: + char member_name[1] //null terminated string + uint8 task_leader //boolean flag +*/ +}; + +#if 0 +// Struct not used by Task System implentation but left for reference (current for RoF2) +struct TaskActivity_Struct { +/*000*/ uint32 TaskSequenceNumber; +/*004*/ uint32 unknown2; +/*008*/ uint32 TaskID; +/*012*/ uint32 ActivityID; +/*016*/ uint32 unknown3; +/*020*/ uint32 ActivityType; +/*024*/ uint32 Optional; +/*028*/ uint8 unknown5; +/*032*/ char Text1[1]; // Variable length - Null terminated +/*000*/ uint32 Text2Len; // Lenth of the following string +/*000*/ char Text2[1]; // Variable length - not Null terminated +/*000*/ uint32 GoalCount; +/*000*/ uint32 String1Len; // Lenth of the following string - Seen 2 +/*000*/ char String1[1]; // Numeric String - Seen "-1" - not Null terminated +/*000*/ uint32 String2Len; // Lenth of the following string - Seen 2 +/*000*/ char String2[1]; // Numeric String - Seen "-1" - not Null terminated +/*000*/ char ZoneIDString1[1]; // Numeric String - Seen "398" - Null terminated +/*000*/ uint32 unknown7; // Seen 0 +/*000*/ char Text3[1]; // Variable length - Null terminated +/*000*/ uint32 DoneCount; +/*000*/ uint8 unknown9; // Seen 1 +/*000*/ char ZoneIDString2[1]; // Numeric String - Seen "398" - Null terminated +}; + +struct TaskHistoryEntry_Struct { + uint32 task_id; + char name[1]; + uint32 completed_time; +}; +struct TaskHistory_Struct { + uint32 completed_count; + TaskHistoryEntry_Struct entries[0]; +}; +#endif + +struct AcceptNewTask_Struct { + uint32 unknown00; + uint32 task_id; //set to 0 for 'decline' + uint32 task_master_id; //entity ID +}; + +//was all 0's from client, server replied with same op, all 0's +struct CancelTask_Struct { + uint32 SequenceNumber; + uint32 unknown4; // Only seen 0x00000002 +}; + +#if 0 +// old struct, not used by Task System implementation but left for reference. +struct AvaliableTask_Struct { + uint32 task_index; //no idea, seen 0x1 + uint32 task_master_id; //entity ID + uint32 task_id; + uint32 unknown012; + uint32 activity_count; //not sure, seen 2 + char desc[1]; //variable length, 0 terminated + uint32 reward_platinum;//not sure on these + uint32 reward_gold; + uint32 reward_silver; + uint32 reward_copper; + char some_name[1]; //variable length, 0 terminated + uint8 unknown1; + uint32 unknown2; //0xFFFFFFFF + uint32 unknown3; //0xFFFFFFFF + uint32 unknown4; //seen 0x16 + uint8 unknown5; +}; +#endif + + +// Many of the Task System packets contain variable length strings, as well as variable numbers +// of records, hence splitting them into multiple structs (header, middle, trailer) etc. +// +struct AvailableTaskHeader_Struct { + uint32 TaskCount; + uint32 unknown1; + uint32 TaskGiver; +}; + +struct AvailableTaskData1_Struct { + uint32 TaskID; + uint32 unknown1; + uint32 TimeLimit; + uint32 unknown2; +}; + +struct AvailableTaskData2_Struct { + uint32 unknown1,unknown2,unknown3,unknown4; +}; + +struct AvailableTaskTrailer_Struct { + uint32 ItemCount; + uint32 unknown1, unknown2; + uint32 StartZone; +}; + +struct TaskDescriptionHeader_Struct { + uint32 SequenceNumber; // The order the tasks appear in the journal. 0 for first task, 1 for second, etc. + uint32 TaskID; + uint32 unknown2; + uint32 unknown3; + uint8 unknown4; +}; + +struct TaskDescriptionData1_Struct { + uint32 Duration; + uint32 unknown2; + uint32 StartTime; +}; + +struct TaskDescriptionData2_Struct { + uint32 RewardCount; // ?? + uint32 unknown1; + uint32 unknown2; + uint16 unknown3; + //uint8 unknown4; +}; + +struct TaskDescriptionTrailer_Struct { + //uint16 unknown1; // 0x0012 + uint32 Points; +}; + +struct TaskActivityHeader_Struct { + uint32 TaskSequenceNumber; + uint32 unknown2; // Seen 0x00000002 + uint32 TaskID; + uint32 ActivityID; + uint32 unknown3; + uint32 ActivityType; + uint32 Optional; + uint32 unknown5; +}; + +struct TaskActivityData1_Struct { + uint32 GoalCount; + uint32 unknown1; // 0xffffffff + uint32 unknown2; // 0xffffffff + uint32 ZoneID; // seen 0x36 + uint32 unknown3; +}; + +struct TaskActivityTrailer_Struct { + uint32 DoneCount; + uint32 unknown1; // Seen 1 +}; + +// The Short_Struct is sent for tasks that are hidden and act as a placeholder +struct TaskActivityShort_Struct { + uint32 TaskSequenceNumber; + uint32 unknown2; // Seen 0x00000002 + uint32 TaskID; + uint32 ActivityID; + uint32 unknown3; + uint32 ActivityType; // 0xffffffff for the short packet + uint32 unknown4; +}; + +struct TaskActivityComplete_Struct { + uint32 TaskIndex; + uint32 unknown2; // 0x00000002 + uint32 unknown3; + uint32 ActivityID; + uint32 unknown4; // 0x00000001 + uint32 unknown5; // 0x00000001 +}; + +#if 0 +// This is a dupe of the CancelTask struct +struct TaskComplete_Struct { + uint32 unknown00; // 0x00000000 + uint32 unknown04; // 0x00000002 +}; +#endif + +struct TaskHistoryRequest_Struct { + uint32 TaskIndex; // This is the sequence the task was sent in the Completed Tasks packet. +}; + +struct TaskHistoryReplyHeader_Struct { + uint32 TaskID; + uint32 ActivityCount; +}; + +struct TaskHistoryReplyData1_Struct { + uint32 ActivityType; +}; + +struct TaskHistoryReplyData2_Struct { + uint32 GoalCount; + uint32 unknown04; // 0xffffffff + uint32 unknown08; // 0xffffffff + uint32 ZoneID; + uint32 unknown16; +}; + +struct BankerChange_Struct { +/*00*/ uint32 platinum; +/*04*/ uint32 gold; +/*08*/ uint32 silver; +/*12*/ uint32 copper; +/*16*/ uint32 platinum_bank; +/*20*/ uint32 gold_bank; +/*24*/ uint32 silver_bank; +/*28*/ uint32 copper_bank; +/*32*/ +}; + +struct LeadershipExpUpdate_Struct { +/*00*/ double group_leadership_exp; +/*08*/ uint32 group_leadership_points; +/*12*/ uint32 Unknown12; +/*16*/ double raid_leadership_exp; +/*24*/ uint32 raid_leadership_points; +}; + +struct UpdateLeadershipAA_Struct { +/*00*/ uint32 ability_id; +/*04*/ uint32 new_rank; +/*08*/ uint32 unknown08; +/*12*/ +}; + +/** +* Leadership AA update +* Length: 32 Octets +* OpCode: LeadExpUpdate +*/ +struct leadExpUpdateStruct { + /*0000*/ uint32 unknown0000; // All zeroes? + /*0004*/ uint32 group_leadership_exp; // Group leadership exp value + /*0008*/ uint32 group_leadership_points; // Unspent group points + /*0012*/ uint32 unknown0012; // Type? + /*0016*/ uint32 unknown0016; // All zeroes? + /*0020*/ uint32 raid_leadership_exp; // Raid leadership exp value + /*0024*/ uint32 raid_leadership_points; // Unspent raid points + /*0028*/ uint32 unknown0028; +}; + +struct RaidGeneral_Struct { +/*00*/ uint32 action; +/*04*/ char player_name[64]; +/*68*/ uint32 unknown68; +/*72*/ char leader_name[64]; +/*136*/ uint32 parameter; +}; + +struct RaidAddMember_Struct { +/*000*/ RaidGeneral_Struct raidGen; //param = (group num-1); 0xFFFFFFFF = no group +/*136*/ uint8 _class; +/*137*/ uint8 level; +/*138*/ uint8 isGroupLeader; +/*139*/ uint8 flags[5]; //no idea if these are needed... +}; + +struct RaidMOTD_Struct { +/*000*/ RaidGeneral_Struct general; // leader_name and action only used +/*140*/ char motd[0]; // max size 1024, but reply is variable +}; + +struct RaidLeadershipUpdate_Struct { +/*000*/ uint32 action; +/*004*/ char player_name[64]; +/*068*/ uint32 Unknown068; +/*072*/ char leader_name[64]; +/*136*/ GroupLeadershipAA_Struct group; //unneeded +/*200*/ RaidLeadershipAA_Struct raid; +/*264*/ char Unknown264[128]; +}; + +struct RaidAdd_Struct { +/*000*/ uint32 action; //=0 +/*004*/ char player_name[64]; //should both be the player's name +/*068*/ char leader_name[64]; +/*132*/ uint8 _class; +/*133*/ uint8 level; +/*134*/ uint8 has_group; +/*135*/ uint8 unknown135; //seems to be 0x42 or 0 +}; + +struct RaidCreate_Struct { +/*00*/ uint32 action; //=8 +/*04*/ char leader_name[64]; +/*68*/ uint32 leader_id; +}; + +struct RaidMemberInfo_Struct { +/*00*/ uint8 group_number; +/*01*/ char member_name[1]; //dyanmic length, null terminated '\0' +/*00*/ uint8 unknown00; +/*01*/ uint8 _class; +/*02*/ uint8 level; +/*03*/ uint8 is_raid_leader; +/*04*/ uint8 is_group_leader; +/*05*/ uint8 main_tank; //not sure +/*06*/ uint8 unknown06[5]; //prolly more flags +}; + +struct RaidDetails_Struct { +/*000*/ uint32 action; //=6,20 +/*004*/ char leader_name[64]; +/*068*/ uint32 unknown68[4]; +/*084*/ LeadershipAA_Struct abilities; //ranks in backwards byte order +/*128*/ uint8 unknown128[142]; +/*354*/ uint32 leader_id; +}; + +struct RaidMembers_Struct { +/*000*/ RaidDetails_Struct details; +/*358*/ uint32 member_count; //including leader +/*362*/ RaidMemberInfo_Struct members[1]; +/*...*/ RaidMemberInfo_Struct empty; //seem to have an extra member with a 0 length name on the end +}; + +struct DynamicWall_Struct { +/*00*/ char name[32]; +/*32*/ float y; +/*36*/ float x; +/*40*/ float z; +/*44*/ uint32 something; +/*48*/ uint32 unknown48; //0 +/*52*/ uint32 one_hundred; //0x64 +/*56*/ uint32 unknown56; //0 +/*60*/ uint32 something2; +/*64*/ int32 unknown64; //-1 +/*68*/ uint32 unknown68; //0 +/*72*/ uint32 unknown72; //0 +/*76*/ uint32 unknown76; //0x100 +/*80*/ +}; + +enum { //bandolier actions + BandolierCreate = 0, + BandolierRemove = 1, + BandolierSet = 2 +}; + +struct BandolierCreate_Struct { +/*00*/ uint32 action; //0 for create +/*04*/ uint8 number; +/*05*/ char name[32]; +/*37*/ uint16 unknown37; //seen 0x93FD +/*39*/ uint8 unknown39; //0 +}; + +struct BandolierDelete_Struct { +/*00*/ uint32 action; +/*04*/ uint8 number; +/*05*/ uint8 unknown05[35]; +}; + +struct BandolierSet_Struct { +/*00*/ uint32 action; +/*04*/ uint8 number; +/*05*/ uint8 unknown05[35]; +}; + +struct Arrow_Struct { +/*000*/ float src_y; +/*004*/ float src_x; +/*008*/ float src_z; +/*012*/ uint8 unknown012[12]; +/*024*/ float velocity; //4 is normal, 20 is quite fast +/*028*/ float launch_angle; //0-450ish, not sure the units, 140ish is straight +/*032*/ float tilt; //on the order of 125 +/*036*/ uint8 unknown036[8]; +/*044*/ float arc; +/*048*/ uint32 source_id; +/*052*/ uint32 target_id; //entity ID +/*056*/ uint32 item_id; +/*060*/ uint32 unknown060; +/*064*/ uint32 unknown064; +/*068*/ uint8 unknown068; +/*069*/ uint8 unknown069; +/*070*/ uint8 unknown070; +/*071*/ uint8 item_type; +/*072*/ uint8 skill; +/*073*/ uint8 unknown073[16]; +/*089*/ char model_name[27]; +/*116*/ +}; + +//made a bunch of trivial structs for stuff for opcode finder to use +struct Consent_Struct { + char name[1]; //always at least a null - was 1 +}; + +struct AdventureMerchant_Struct { + uint32 unknown_flag; //seems to be 1 + uint32 entity_id; +}; + +// OP_Save - Size: 484 +struct Save_Struct { +/*000*/ uint8 unknown00[192]; +/*192*/ uint8 unknown0192[176]; +/*368*/ uint8 unknown0368[116]; +/*484*/ +}; + +struct GMToggle_Struct { + uint8 unknown0[64]; + uint32 toggle; +}; + +struct ColoredText_Struct { + uint32 color; + char msg[1]; //was 1 +/*0???*/ uint8 paddingXXX[3]; // always 0's +}; + +struct UseAA_Struct { + uint32 begin; + uint32 ability; + uint32 end; +}; + +struct AA_Ability { +/*00*/ uint32 skill_id; +/*04*/ uint32 base1; +/*08*/ uint32 base2; +/*12*/ uint32 slot; +/*16*/ +}; + +struct SendAA_Struct { +/*0000*/ uint32 id; +/*0004*/ uint8 unknown004; // uint32 unknown004; set to 1. +/*0005*/ int32 hotkey_sid; +/*0009*/ int32 hotkey_sid2; +/*0013*/ uint32 title_sid; +/*0017*/ uint32 desc_sid; +/*0021*/ uint32 class_type; +/*0025*/ uint32 cost; +/*0029*/ uint32 seq; +/*0033*/ uint32 current_level; //1s, MQ2 calls this AARankRequired +/*0037*/ uint32 unknown037; // Introduced during HoT +/*0041*/ uint32 prereq_skill; //is < 0, abs() is category # +/*0045*/ uint32 unknown045; // New Mar 21 2012 - Seen 1 +/*0049*/ uint32 prereq_minpoints; //min points in the prereq +/*0053*/ uint32 type; +/*0057*/ uint32 spellid; +/*0061*/ uint32 unknown057; // Introduced during HoT - Seen 1 - Maybe account status or enable/disable AA? +/*0065*/ uint32 spell_type; +/*0069*/ uint32 spell_refresh; +/*0073*/ uint16 classes; +/*0075*/ uint16 berserker; //seems to be 1 if its a berserker ability +/*0077*/ uint32 max_level; +/*0081*/ uint32 last_id; +/*0085*/ uint32 next_id; +/*0089*/ uint32 cost2; +/*0093*/ uint8 unknown80[7]; +/*0100*/ uint32 aa_expansion; +/*0104*/ uint32 special_category; +/*0108*/ uint32 unknown0096; +/*0112*/ uint32 total_abilities; +/*0116*/ AA_Ability abilities[0]; +}; + +struct AA_List { + SendAA_Struct* aa[0]; +}; + +struct AA_Action { +/*00*/ uint32 action; +/*04*/ uint32 ability; +/*08*/ uint32 unknown08; +/*12*/ uint32 exp_value; +/*16*/ +}; + +struct AA_Skills { //this should be removed and changed to AA_Array +/*00*/ uint32 aa_skill; // Total AAs Spent +/*04*/ uint32 aa_value; +/*08*/ uint32 unknown08; +/*12*/ +}; + +struct AAExpUpdate_Struct { +/*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability +/*04*/ uint32 aapoints_unspent; +/*08*/ uint8 aaxp_percent; //% of exp that goes to AAs +/*09*/ uint8 unknown09[3]; //live doesn't always zero these, so they arnt part of aaxp_percent +/*12*/ +}; + +struct AltAdvStats_Struct { +/*000*/ uint32 experience; +/*004*/ uint16 unspent; +/*006*/ uint16 unknown006; +/*008*/ uint8 percentage; +/*009*/ uint8 unknown009[3]; +/*012*/ +}; + +struct PlayerAA_Struct { // Is this still used? + AA_Skills aa_list[MAX_PP_AA_ARRAY]; +}; + +struct AA_Values { +/*00*/ uint32 aa_skill; +/*04*/ uint32 aa_value; +/*08*/ uint32 unknown08; +/*12*/ +}; + +struct AATable_Struct { +/*00*/ uint32 aa_spent; // Total AAs Spent +/*04*/ uint32 aapoints_assigned; // Number of Assigned AA points - Seen 206 (total of the 4 fields below) +/*08*/ uint32 aa_spent_general; // Seen 63 +/*12*/ uint32 aa_spent_archetype; // Seen 40 +/*16*/ uint32 aa_spent_class; // Seen 103 +/*20*/ uint32 aa_spent_special; // Seen 0 +/*24*/ AA_Values aa_list[MAX_PP_AA_ARRAY]; +}; + +struct Weather_Struct { + uint32 val1; //generall 0x000000FF + uint32 type; //0x31=rain, 0x02=snow(i think), 0 = normal + uint32 mode; +}; + +struct ZoneInUnknown_Struct { + uint32 val1; + uint32 val2; + uint32 val3; +}; + +struct MobHealth_Struct { + uint16 entity_id; + uint8 hp; +}; + +struct AnnoyingZoneUnknown_Struct { + uint32 entity_id; + uint32 value; //always 4 +}; + +struct LoadSpellSet_Struct { + uint8 spell[12]; // 0xFFFFFFFF if no action, slot number if to unmem starting at 0 + uint32 unknown; //Seen 12 - Maybe a gem count? +}; + +struct BlockedBuffs_Struct +{ +/*000*/ int32 SpellID[BLOCKED_BUFF_COUNT]; +/*120*/ uint32 Count; +/*124*/ uint8 Pet; +/*125*/ uint8 Initialise; +/*126*/ uint16 Flags; +}; + +//Size 24 Bytes +struct WorldObfuscator_Struct { +/*000*/ uint32 var1; +/*004*/ uint32 Unknown1; +/*008*/ uint32 Unknown2; +/*012*/ uint32 Unknown3; +/*016*/ uint32 var2; +/*020*/ uint32 Unknown4; +/*024*/ +}; + +struct ExpansionInfo_Struct { +/*000*/ char Unknown000[64]; +/*064*/ uint32 Expansions; +}; + +struct ApplyPoison_Struct { + MainInvItemSlotStruct inventorySlot; + uint32 success; +}; + +struct ItemVerifyRequest_Struct { +/*000*/ ItemSlotStruct slot; +/*012*/ uint32 target; // Target Entity ID +/*016*/ +}; + +struct ItemVerifyReply_Struct { +/*000*/ ItemSlotStruct slot; +/*012*/ uint32 spell; // Spell ID to cast if different than item effect +/*016*/ uint32 target; // Target Entity ID +/*020*/ +}; + + +struct RoF2SlotStruct +{ + uint8 Bank; + uint16 MainSlot; + uint16 SubSlot; +}; + +struct ItemSerializationHeader +{ +/*000*/ char unknown000[13]; // New for HoT. Looks like a string. +/*017*/ uint32 stacksize; +/*021*/ uint32 unknown004; +/*025*/ uint8 slot_type; // 0 = normal, 1 = bank, 2 = shared bank, 9 = merchant, 20 = ? +/*026*/ uint16 main_slot; +/*028*/ uint16 sub_slot; +/*030*/ uint16 unknown013; // 0xffff +/*032*/ uint32 price; +/*036*/ uint32 merchant_slot; //1 if not a merchant item +/*040*/ uint32 scaled_value; //0 +/*044*/ uint32 instance_id; //unique instance id if not merchant item, else is merchant slot +/*048*/ uint32 unknown028; //0 +/*052*/ uint32 last_cast_time; // Unix Time from PP of last cast for this recast type if recast delay > 0 +/*056*/ uint32 charges; //Total Charges an item has (-1 for unlimited) +/*060*/ uint32 inst_nodrop; // 1 if the item is no drop (attuned items) +/*064*/ uint32 unknown044; // 0 +/*068*/ uint32 unknown048; // 0 +/*072*/ uint32 unknown052; // 0 + uint8 isEvolving; +}; + +struct EvolvingItem { + uint8 unknown001; + uint8 unknown002; + uint8 unknown003; + uint8 unknown004; + int32 evoLevel; + double progress; + uint8 Activated; + int32 evomaxlevel; + uint8 unknown005[4]; +}; + +struct ItemSerializationHeaderFinish +{ + uint16 ornamentIcon; +/*081*/ uint8 unknown061; // 0 - Add Evolving Item struct if this isn't set to 0? +/*082*/ uint8 unknown062; // 0 +/*083*/ uint32 unknowna1; // 0xffffffff +/*087*/ uint32 unknowna2; // 0 +/*091*/ uint8 unknown063; // 0 +/*092*/ uint32 unknowna3; // 0 +/*096*/ uint32 unknowna4; // 0xffffffff +/*100*/ uint32 unknowna5; // 0 +/*104*/ uint8 ItemClass; //0, 1, or 2 +/*105*/ +}; + +struct ItemBodyStruct +{ + uint32 id; + int32 weight; // Seen an item on Live with -0.1 weight + uint8 norent; + uint8 nodrop; + uint8 attune; + uint8 size; + uint32 slots; + uint32 price; + uint32 icon; + uint8 unknown1; + uint8 unknown2; + uint32 BenefitFlag; + uint8 tradeskills; + int8 CR; + int8 DR; + int8 PR; + int8 MR; + int8 FR; + int8 SVCorruption; + int8 AStr; + int8 ASta; + int8 AAgi; + int8 ADex; + int8 ACha; + int8 AInt; + int8 AWis; + int32 HP; + int32 Mana; + uint32 Endur; + int32 AC; + int32 regen; + int32 mana_regen; + int32 end_regen; + uint32 Classes; + uint32 Races; + uint32 Deity; + int32 SkillModValue; + int32 SkillModMax; // Max skill point modification + int32 SkillModType; + uint32 SkillModExtra; // Adds a "+value" after the mod percentage + uint32 BaneDmgRace; + uint32 BaneDmgBody; + uint32 BaneDmgRaceAmt; + int32 BaneDmgAmt; + uint8 Magic; + int32 CastTime_; + uint32 ReqLevel; + uint32 RecLevel; + uint32 RecSkill; + uint32 BardType; + int32 BardValue; + uint8 Light; + uint8 Delay; + uint8 ElemDmgType; + uint8 ElemDmgAmt; + uint8 Range; + uint32 Damage; + uint32 Color; + uint32 Prestige; // New to March 21 2012 client + uint8 ItemType; + uint32 Material; + uint32 unknown7; + uint32 EliteMaterial; + uint32 unknown_RoF23; // New to March 21 2012 client + uint32 unknown_RoF24; // New to December 10th 2012 client - NEW + float SellRate; + int32 CombatEffects; + int32 Shielding; + int32 StunResist; + int32 StrikeThrough; + int32 ExtraDmgSkill; + int32 ExtraDmgAmt; + int32 SpellShield; + int32 Avoidance; + int32 Accuracy; + uint32 CharmFileID; + uint32 FactionMod1; + int32 FactionAmt1; + uint32 FactionMod2; + int32 FactionAmt2; + uint32 FactionMod3; + int32 FactionAmt3; + uint32 FactionMod4; + int32 FactionAmt4; +}; + +struct AugSlotStruct +{ + uint32 type; + uint8 visible; + uint8 unknown; +}; + +struct ItemSecondaryBodyStruct +{ + uint32 augtype; + // swapped augrestrict and augdistiller positions + // (this swap does show the proper augment restrictions in Item Information window now) + // unsure what the purpose of augdistiller is at this time -U 3/17/2014 + uint32 augdistiller; // New to December 10th 2012 client - NEW + uint32 augrestrict; + AugSlotStruct augslots[6]; + + uint32 ldonpoint_type; + uint32 ldontheme; + uint32 ldonprice; + uint32 ldonsellbackrate; + uint32 ldonsold; + + uint8 bagtype; + uint8 bagslots; + uint8 bagsize; + uint8 wreduction; + + uint8 book; + uint8 booktype; + //int32 filename; filename is either 0xffffffff/0x00000000 or the null term string ex: CREWizardNote\0 +}; + +struct ItemTertiaryBodyStruct +{ + int32 loregroup; + uint8 artifact; + uint8 summonedflag; + uint32 favor; + uint8 fvnodrop; + int32 dotshield; + int32 atk; + int32 haste; + int32 damage_shield; + uint32 guildfavor; + uint32 augdistil; + int32 unknown3; // 0xffffffff + uint32 unknown4; + uint8 no_pet; + uint8 unknown5; + + uint8 potion_belt_enabled; + uint32 potion_belt_slots; + + uint32 stacksize; + uint8 no_transfer; + uint16 expendablearrow; + + uint32 unknown8; + uint32 unknown9; + uint32 unknown10; + uint32 unknown11; + uint8 unknown12; + uint8 unknown13; + uint8 unknown14; +}; + +struct ClickEffectStruct +{ + int32 effect; + uint8 level2; + uint32 type; + uint8 level; + int32 max_charges; + int32 cast_time; + uint32 recast; + int32 recast_type; + uint32 clickunk5; + //uint8 effect_string; + //int32 clickunk7; +}; + +struct ProcEffectStruct +{ + uint32 effect; + uint8 level2; + uint32 type; + uint8 level; + uint32 unknown1; // poison? + uint32 unknown2; + uint32 unknown3; + uint32 unknown4; + uint32 procrate; + //uint8 effect_string; + //uint32 unknown5; +}; + +struct WornEffectStruct //worn, focus and scroll effect +{ + uint32 effect; + uint8 level2; + uint32 type; + uint8 level; + uint32 unknown1; + uint32 unknown2; + uint32 unknown3; + uint32 unknown4; + uint32 unknown5; + //uint8 effect_string; + //uint32 unknown6; +}; + +struct ItemQuaternaryBodyStruct +{ + uint32 scriptfileid; + uint8 quest_item; + uint32 Power; // Enables "Power" percentage field used by Power Sources + uint32 Purity; + uint8 unknown16; // RoF2 + uint32 BackstabDmg; + uint32 DSMitigation; + int32 HeroicStr; + int32 HeroicInt; + int32 HeroicWis; + int32 HeroicAgi; + int32 HeroicDex; + int32 HeroicSta; + int32 HeroicCha; + int32 HeroicMR; + int32 HeroicFR; + int32 HeroicCR; + int32 HeroicDR; + int32 HeroicPR; + int32 HeroicSVCorrup; + int32 HealAmt; + int32 SpellDmg; + int32 clairvoyance; + uint8 unknown18; //Power Source Capacity or evolve filename? + uint32 evolve_string; // Some String, but being evolution related is just a guess + uint8 unknown19; + uint32 unknown20; // Bard Stuff? + //uint32 unknown21; + uint8 unknown22; + uint32 unknown23; + uint32 unknown24; + uint32 unknown25; + float unknown26; + float unknown27; + uint32 unknown_RoF26; // 0 New to March 21 2012 client + uint32 unknown28; // 0xffffffff + uint16 unknown29; + uint32 unknown30; // 0xffffffff + uint16 unknown31; + uint32 unknown32; + float unknown33; + uint32 unknown34; + uint32 unknown35; + uint32 unknown36; + uint32 unknown37; + uint32 unknown_RoF27; + uint32 unknown_RoF28; + + // Begin RoF2 Test + uint8 unknown_TEST1; + // End RoF2 Test + + uint8 unknown38; // 0 + uint8 unknown39; // 1 + uint32 subitem_count; +}; + +struct AugmentInfo_Struct +{ +/*000*/ uint32 itemid; // id of the solvent needed +/*004*/ uint32 window; // window to display the information in +/*008*/ char augment_info[64]; // total packet length 76, all the rest were always 00 +/*072*/ uint32 unknown072; +}; + +struct VeteranRewardItem +{ +/*000*/ uint32 item_id; +/*004*/ uint32 charges; +/*008*/ char item_name[64]; +}; + +struct VeteranReward +{ +/*000*/ uint32 claim_id; +/*004*/ uint32 number_available; +/*008*/ uint32 claim_count; +/*012*/ VeteranRewardItem items[8]; +}; + +struct ExpeditionEntryHeader_Struct +{ +/*000*/ uint32 unknown000; +/*000*/ uint32 number_of_entries; +}; + +struct ExpeditionJoinPrompt_Struct +{ +/*000*/ uint32 clientid; +/*004*/ uint32 unknown004; +/*008*/ char player_name[64]; +/*072*/ char expedition_name[64]; +}; + +struct ExpeditionExpireWarning +{ +/*000*/ uint32 clientid; +/*004*/ uint32 unknown004; +/*008*/ uint32 minutes_remaining; +}; + +struct ExpeditionInfo_Struct +{ +/*000*/ uint32 clientid; +/*004*/ uint32 unknown004; +/*008*/ uint32 unknown008; +/*012*/ uint32 max_players; +/*016*/ char expedition_name[128]; +/*142*/ char leader_name[64]; +}; + +struct ExpeditionCompassEntry_Struct +{ +/*000*/ float unknown000; //seen *((uint32*)) = 1584791871 +/*004*/ uint32 enabled; //guess +/*008*/ uint32 unknown008; //seen 1019 +/*012*/ float y; +/*016*/ float x; +/*020*/ float z; +}; + +struct ExpeditionCompass_Struct +{ +/*000*/ uint32 clientid; +/*004*/ uint32 count; +/*008*/ ExpeditionCompassEntry_Struct entries[0]; +}; + +struct MaxCharacters_Struct +{ +/*000*/ uint32 max_chars; // Seen 4 on Silver Account (4 chars max) +/*004*/ uint32 unknown004; // Seen 0 +/*008*/ uint32 unknown008; // Seen 0 +}; + +// Used by MercenaryListEntry_Struct +struct MercenaryStance_Struct { +/*0000*/ uint32 StanceIndex; // Index of this stance (sometimes reverse reverse order - 3, 2, 1, 0 for 4 stances etc) +/*0004*/ uint32 Stance; // From dbstr_us.txt - 1^24^Passive^0, 2^24^Balanced^0, etc +}; +// Used by MercenaryMerchantList_Struct +struct MercenaryListEntry_Struct { +/*0000*/ uint32 MercID; // ID unique to each type of mercenary (probably a DB id) +/*0004*/ uint32 MercType; // From dbstr_us.txt - Apprentice (330000100), Journeyman (330000200), Master (330000300) +/*0008*/ uint32 MercSubType; // From dbstr_us.txt - 330020105^23^Race: Guktan
Type: Healer
Confidence: High
Proficiency: Apprentice, Tier V... +/*0012*/ uint32 PurchaseCost; // Purchase Cost (in gold) +/*0016*/ uint32 UpkeepCost; // Upkeep Cost (in gold) +/*0020*/ uint32 Status; // Required Account Status (Free = 0, Silver = 1, Gold = 2) at merchants - Seen 0 (suspended) or 1 (unsuspended) on hired mercs ? +/*0024*/ uint32 AltCurrencyCost; // Alternate Currency Purchase Cost? (all seen costs show N/A Bayle Mark) - Seen 0 +/*0028*/ uint32 AltCurrencyUpkeep; // Alternate Currency Upkeep Cost? (all seen costs show 1 Bayle Mark) - Seen 1 +/*0032*/ uint32 AltCurrencyType; // Alternate Currency Type? - 19^17^Bayle Mark^0 - Seen 19 +/*0036*/ uint8 MercUnk01; // Unknown (always see 0) +/*0037*/ int32 TimeLeft; // Unknown (always see -1 at merchant) - Seen 900000 (15 minutes in ms for newly hired merc) +/*0041*/ uint32 MerchantSlot; // Merchant Slot? Increments, but not always by 1 - May be for Merc Window Options (Seen 5, 36, 1 for active mercs)? +/*0045*/ uint32 MercUnk02; // Unknown (normally see 1, but sometimes 2 or 0) +/*0049*/ uint32 StanceCount; // Iterations of MercenaryStance_Struct - Normally 2 to 4 seen +/*0053*/ int32 MercUnk03; // Unknown (always 0 at merchant) - Seen on active merc: 93 a4 03 77, b8 ed 2f 26, 88 d5 8b c3, and 93 a4 ad 77 +/*0057*/ uint8 MercUnk04; // Seen 1 +/*0058*/ char MercName[1]; // Null Terminated Mercenary Name (00 at merchants) +/*0000*/ MercenaryStance_Struct Stances[1]; // Count Varies - From dbstr_us.txt - 1^24^Passive^0, 2^24^Balanced^0, etc +}; + +// Sent by the server when browsing the Mercenary Merchant +struct MercenaryMerchantList_Struct { +/*0000*/ uint32 MercTypeCount; // Number of Merc Types to follow +/*0004*/ uint32 MercTypes[1]; // Count varies, but hard set to 3 max for now - From dbstr_us.txt - Apprentice (330000100), Journeyman (330000200), Master (330000300) +/*0016*/ uint32 MercCount; // Number of MercenaryInfo_Struct to follow +/*0020*/ MercenaryListEntry_Struct Mercs[0]; // Data for individual mercenaries in the Merchant List +}; + +// OP_MercenaryDataRequest +// Right clicking merchant - shop request +struct MercenaryMerchantShopRequest_Struct { +/*0000*/ uint32 MercMerchantID; // Entity ID of the Mercenary Merchant +/*0004*/ +}; + +// Used by MercenaryDataUpdate_Struct +struct MercenaryData_Struct { +/*0000*/ uint32 MercID; // ID unique to each type of mercenary (probably a DB id) - (if 1, do not send MercenaryData_Struct - No merc hired) +/*0004*/ uint32 MercType; // From dbstr_us.txt - Apprentice (330000100), Journeyman (330000200), Master (330000300) +/*0008*/ uint32 MercSubType; // From dbstr_us.txt - 330020105^23^Race: Guktan
Type: Healer
Confidence: High
Proficiency: Apprentice, Tier V... +/*0012*/ uint32 PurchaseCost; // Purchase Cost (in gold) +/*0016*/ uint32 UpkeepCost; // Upkeep Cost (in gold) +/*0020*/ uint32 Status; // Required Account Status (Free = 0, Silver = 1, Gold = 2) at merchants - Seen 0 (suspended) or 1 (unsuspended) on hired mercs ? +/*0024*/ uint32 AltCurrencyCost; // Alternate Currency Purchase Cost? (all seen costs show N/A Bayle Mark) - Seen 0 +/*0028*/ uint32 AltCurrencyUpkeep; // Alternate Currency Upkeep Cost? (all seen costs show 1 Bayle Mark) - Seen 1 +/*0032*/ uint32 AltCurrencyType; // Alternate Currency Type? - 19^17^Bayle Mark^0 - Seen 19 +/*0036*/ uint8 MercUnk01; // Unknown (always see 0) +/*0037*/ int32 TimeLeft; // Unknown (always see -1 at merchant) - Seen 900000 (15 minutes in ms for newly hired merc) +/*0041*/ uint32 MerchantSlot; // Merchant Slot? Increments, but not always by 1 - May be for Merc Window Options (Seen 5, 36, 1 for active mercs)? +/*0045*/ uint32 MercUnk02; // Unknown (normally see 1, but sometimes 2 or 0) +/*0049*/ uint32 StanceCount; // Iterations of MercenaryStance_Struct - Normally 2 to 4 seen +/*0053*/ int32 MercUnk03; // Unknown (always 0 at merchant) - Seen on active merc: 93 a4 03 77, b8 ed 2f 26, 88 d5 8b c3, and 93 a4 ad 77 +/*0057*/ uint8 MercUnk04; // Seen 1 +/*0058*/ char MercName[1]; // Null Terminated Mercenary Name (00 at merchants) +/*0000*/ MercenaryStance_Struct Stances[1]; // Count Varies, but hard set to 2 for now - From dbstr_us.txt - 1^24^Passive^0, 2^24^Balanced^0, etc (1 to 9 as of April 2012) +/*0000*/ uint32 MercUnk05; // Seen 1 - Extra Merc Data field that differs from MercenaryListEntry_Struct +// MercUnk05 may be a field that is at the end of the packet only, even if multiple mercs are listed (haven't seen examples of multiple mercs owned at once) +}; + +// Should be named OP_MercenaryDataResponse, but the current opcode using that name should be renamed first +// Size varies if mercenary is hired or if browsing Mercenary Merchant +// This may also be the response for Client->Server 0x0327 (size 0) packet On Live as of April 2 2012 +struct MercenaryDataUpdate_Struct { +/*0000*/ int32 MercStatus; // Seen 0 with merc and -1 with no merc hired +/*0004*/ uint32 MercCount; // Seen 1 with 1 merc hired and 0 with no merc hired +/*0008*/ MercenaryData_Struct MercData[0]; // Data for individual mercenaries in the Merchant List +}; + +// Size 12 and sent on Zone-In if no mercenary is currently hired and when merc is dismissed +// (Same packet as MercAssign_Struct?) +struct NoMercenaryHired_Struct { +/*0000*/ int32 MercStatus; // Seen -1 with no merc hired +/*0004*/ uint32 MercCount; // Seen 0 with no merc hired +/*0008*/ uint32 MercID; // Seen 1 when no merc is hired - ID unique to each type of mercenary +/*0012*/ +}; + +// OP_MercenaryAssign (Same packet as NoMercenaryHired_Struct?) +// Not actually Merc related - This is actually a weapon equp packet +struct MercenaryAssign_Struct { +/*0000*/ uint32 MercEntityID; // Seen 0 (no merc spawned) or 615843841 and 22779137 +/*0004*/ uint32 MercUnk01; // +/*0008*/ uint32 MercUnk02; // +/*0012*/ +}; + +// OP_MercenaryTimer +// Sent on Zone-In, or after Dismissing, Suspending, or Unsuspending Mercs +struct MercenaryStatus_Struct { +/*0000*/ uint32 MercEntityID; // Seen 0 (no merc spawned) or 615843841 and 22779137 +/*0004*/ uint32 UpdateInterval; // Seen 900000 - Matches from 0x6537 packet (15 minutes in ms?) +/*0008*/ uint32 MercUnk01; // Seen 180000 - 3 minutes in milleseconds? Maybe next update interval? +/*0012*/ uint32 MercState; // Seen 5 (normal) or 1 (suspended) +/*0016*/ uint32 SuspendedTime; // Seen 0 (not suspended) or c9 c2 64 4f (suspended on Sat Mar 17 11:58:49 2012) - Unix Timestamp +/*0020*/ +}; + +// Sent from the client when using the Mercenary Window +struct MercenaryCommand_Struct { +/*0000*/ uint32 MercCommand; // Seen 0 (zone in with no merc or suspended), 1 (dismiss merc), 5 (normal state), 36 (zone in with merc) +/*0004*/ int32 Option; // Seen -1 (zone in with no merc), 0 (setting to passive stance), 1 (normal or setting to balanced stance) +/*0008*/ +}; + +// Requesting to suspend or unsuspend merc +struct SuspendMercenary_Struct { +/*0000*/ uint8 SuspendMerc; // Seen 30 (48) for suspending or unsuspending +/*0001*/ +}; + +// Response to suspend merc with timestamp +struct SuspendMercenaryResponse_Struct { +/*0000*/ uint32 SuspendTime; // Unix Timestamp - Seen a9 11 78 4f +/*0004*/ +}; + +// Sent by client when requesting to view Mercenary info or Hire a Mercenary +struct MercenaryMerchantRequest_Struct { +/*0000*/ uint32 MercID; // Seen 399 and 400 for merc ID +/*0004*/ uint32 MercUnk01; // Seen 1 +/*0008*/ uint32 MercMerchantID; // Entity ID for Mercenary Merchant +/*0012*/ uint32 MercUnk02; // Seen 65302016 (00 6e e4 03) - (probably actually individual uint8 fields), but seen as DWORD in Seeds client. +/*0016*/ +}; + +// Sent by Server in response to requesting to view Mercenary info or Hire a Mercenary +struct MercenaryMerchantResponse_Struct { +/*0000*/ uint32 ResponseType; +/*0004*/ +}; + + }; //end namespace structs +}; //end namespace RoF2 + +#endif /*RoF2_STRUCTS_H_*/ diff --git a/common/random.h b/common/random.h new file mode 100644 index 000000000..ef2b3ef73 --- /dev/null +++ b/common/random.h @@ -0,0 +1,84 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __random_h__ +#define __random_h__ + +#include +#include + +/* This uses mt19937 seeded with the std::random_device + * The idea is to have this be included as a member of another class + * so mocking out for testing is easier + * If you need to reseed random.Reseed() + * Eventually this should be derived from an abstract base class + */ + +namespace EQEmu { + class Random { + public: + // AKA old MakeRandomInt + const int Int(int low, int high) + { + if (low > high) + std::swap(low, high); + return std::uniform_int_distribution(low, high)(m_gen); // [low, high] + } + + // AKA old MakeRandomFloat + const double Real(double low, double high) + { + if (low > high) + std::swap(low, high); + return std::uniform_real_distribution(low, high)(m_gen); // [low, high) + } + + // example Roll(50) would have a 50% success rate + // Roll(100) 100%, etc + // valid values 0-100 (well, higher works too but ...) + const bool Roll(const int required) + { + return Int(0, 99) < required; + } + + // valid values 0.0 - 1.0 + const bool Roll(const double required) + { + return Real(0.0, 1.0) <= required; + } + + void Reseed() + { + // We could do the seed_seq thing here too if we need better seeding + // but that is mostly overkill for us, so just seed once + std::random_device rd; + m_gen.seed(rd()); + } + + Random() + { + Reseed(); + } + + private: + std::mt19937 m_gen; + }; +} + +#endif /* !__random_h__ */ + diff --git a/loginserver/client.cpp b/loginserver/client.cpp index 9883c059d..bc0a86fa8 100644 --- a/loginserver/client.cpp +++ b/loginserver/client.cpp @@ -389,7 +389,7 @@ void Client::GenerateKey() '6', '7', '8', '9' }; - key.append((const char*)&key_selection[MakeRandomInt(0, 35)], 1); + key.append((const char*)&key_selection[random.Int(0, 35)], 1); count++; } } diff --git a/loginserver/client.h b/loginserver/client.h index 3248aefb5..c1b44dc6f 100644 --- a/loginserver/client.h +++ b/loginserver/client.h @@ -22,6 +22,7 @@ #include "../common/opcodemgr.h" #include "../common/eq_stream_type.h" #include "../common/eq_stream_factory.h" +#include "../common/random.h" #ifndef WIN32 #include "eq_crypto_api.h" #endif @@ -129,6 +130,8 @@ public: * Gets the connection for this client. */ EQStream *GetConnection() { return connection; } + + EQEmu::Random random; private: EQStream *connection; ClientVersion version; diff --git a/utils/patches/patch_RoF.conf b/utils/patches/patch_RoF.conf index 027eac161..05a3a4a76 100644 --- a/utils/patches/patch_RoF.conf +++ b/utils/patches/patch_RoF.conf @@ -94,6 +94,8 @@ OP_ClearBlockedBuffs=0x5d3c OP_WorldObjectsSent=0x7fa8 OP_SendExpZonein=0x25ab OP_SendAATable=0x7791 +OP_ClearAA=0x422e +OP_ClearLeadershipAbilities=0xb978 OP_RespondAA=0x379d OP_UpdateAA=0x504f OP_SendAAStats=0x3d1c @@ -367,7 +369,7 @@ OP_DzLeaderStatus=0x4021 OP_DzExpeditionEndsWarning=0x32eb OP_DzMemberList=0x348f OP_DzCompass=0x0e01 # Was 0x4f09 -OP_DzChooseZone=0x0000 # Maybe 0x29d6 +OP_DzChooseZone=0x6e5e # Maybe 0x29d6 # New Opcodes OP_SpawnPositionUpdate=0x0000 # Actually OP_MobUpdate ? diff --git a/utils/patches/patch_RoF2.conf b/utils/patches/patch_RoF2.conf new file mode 100644 index 000000000..d2ed7f651 --- /dev/null +++ b/utils/patches/patch_RoF2.conf @@ -0,0 +1,662 @@ +# ShowEQ Import Notes: +# ZERO THE FILE first +# perl -pi -e 's/0x[0-9a-fA-F]{4}/0x0000/g' opcodes.conf +# Unknown Mapping: +# OP_Action2 -> OP_Damage +# OP_EnvDamage -> OP_Damage ---> might have been a one time mistake +# Name Differences: +# OP_CancelInvite -> OP_GroupCancelInvite +# OP_GMFind -> OP_FindPersonRequest +# OP_CommonMessage -> OP_ChannelMessage + +OP_Unknown=0x0000 +OP_ExploreUnknown=0x0000 # used for unknown explorer + +# world packets +# Required to reach Char Select: +OP_SendLoginInfo=0x7a09 +OP_ApproveWorld=0x7499 +OP_LogServer=0x7ceb +OP_SendCharInfo=0x00d2 +OP_ExpansionInfo=0x590d +OP_GuildsList=0x507a +OP_EnterWorld=0x578f +OP_PostEnterWorld=0x6259 +OP_World_Client_CRC1=0x12cc +OP_World_Client_CRC2=0x0f13 +OP_SendSpellChecksum=0x0000 +OP_SendSkillCapsChecksum=0x0000 + +# Character Select Related: +OP_SendMaxCharacters=0x5475 +OP_SendMembership=0x7acc +OP_SendMembershipDetails=0x057b +OP_CharacterCreateRequest=0x6773 +OP_CharacterCreate=0x6bbf +OP_DeleteCharacter=0x1808 +OP_RandomNameGenerator=0x5954 +OP_ApproveName=0x56a2 +OP_MOTD=0x0c22 +OP_SetChatServer=0x1bc5 +OP_SetChatServer2=0x7eec +OP_ZoneServerInfo=0x4c44 +OP_WorldComplete=0x4493 +OP_WorldUnknown001=0x2301 +OP_FloatListThing=0x46c6 + +# Reasons for Disconnect: +OP_ZoneUnavail=0x4cb4 +OP_WorldClientReady=0x23c1 +OP_CharacterStillInZone=0x0000 +OP_WorldChecksumFailure=0x0000 +OP_WorldLoginFailed=0x0000 +OP_WorldLogout=0x0000 +OP_WorldLevelTooHigh=0x0000 +OP_CharInacessable=0x0000 +OP_UserCompInfo=0x0000 +OP_SendExeChecksum=0x0000 +OP_SendBaseDataChecksum=0x0000 + +# Zone in opcodes +OP_AckPacket=0x471d +OP_ZoneEntry=0x5089 +OP_ReqNewZone=0x7887 +OP_NewZone=0x1795 +OP_ZoneSpawns=0x5237 +OP_PlayerProfile=0x6506 +OP_TimeOfDay=0x5070 +OP_LevelUpdate=0x1eec +OP_Stamina=0x2a79 +OP_RequestClientZoneChange=0x3fcf +OP_ZoneChange=0x2d18 +OP_LockoutTimerInfo=0x0000 +OP_ZoneServerReady=0x0000 +OP_ZoneInUnknown=0x0000 +OP_LogoutReply=0x0000 +OP_PreLogoutReply=0x0000 + +# Required to fully log in +OP_SpawnAppearance=0x0971 +OP_ChangeSize=0x4707 +OP_TributeUpdate=0x5961 +OP_TributeTimer=0x073d +OP_SendTributes=0x729b +OP_SendGuildTributes=0x1877 +OP_TributeInfo=0x4254 +OP_Weather=0x661e +OP_ReqClientSpawn=0x35fa +OP_SpawnDoor=0x7291 +OP_GroundSpawn=0x6fca +OP_SendZonepoints=0x69a4 +OP_BlockedBuffs=0x3033 +OP_RemoveBlockedBuffs=0x0de7 +OP_ClearBlockedBuffs=0x34cb +OP_WorldObjectsSent=0x5ae2 +OP_SendExpZonein=0x5f8e +OP_SendAATable=0x66b5 +OP_ClearAA=0x0f50 +OP_ClearLeadershipAbilities=0x6da5 +OP_RespondAA=0x7a27 +OP_UpdateAA=0x66f0 +OP_SendAAStats=0x43c8 +OP_AAExpUpdate=0x7d14 +OP_ExpUpdate=0x20ed +OP_HPUpdate=0x2828 +OP_ManaChange=0x5467 +OP_TGB=0x0876 +OP_SpecialMesg=0x0083 +OP_GuildMemberList=0x12a6 +OP_GuildMOTD=0x3e13 +OP_CharInventory=0x5ca6 +OP_WearChange=0x7994 +OP_ClientUpdate=0x7dfc +OP_ClientReady=0x345d +OP_SetServerFilter=0x444d + +# Guild Opcodes - Disabled until crashes are resolved in RoF +OP_GetGuildMOTD=0x36e0 +OP_GetGuildMOTDReply=0x4f1f +OP_GuildMemberUpdate=0x69b9 +OP_GuildInvite=0x7099 +OP_GuildRemove=0x1444 +OP_GuildPeace=0x67e3 +OP_SetGuildMOTD=0x0b0b +OP_GuildList=0x6279 +OP_GuildWar=0x1ffb +OP_GuildLeader=0x7e09 +OP_GuildDelete=0x3708 +OP_GuildInviteAccept=0x7053 +OP_GuildDemote=0x2d4e +OP_GuildPromote=0x0000 +OP_GuildPublicNote=0x5053 +OP_GuildManageBanker=0x748f +OP_GuildBank=0x5134 +OP_SetGuildRank=0x0b9c +OP_GuildUpdateURLAndChannel=0x2958 +OP_GuildStatus=0x7326 +OP_GuildCreate=0x76d9 +OP_GuildMemberLevelUpdate=0x0000 # Unused? +OP_ZoneGuildList=0x0000 # Unused? +OP_GetGuildsList=0x0000 # Unused? +OP_LFGuild=0x0000 +OP_GuildManageRemove=0x0000 +OP_GuildManageAdd=0x0000 +OP_GuildManageStatus=0x0000 + +# GM/Guide Opcodes +OP_GMServers=0x08c1 +OP_GMBecomeNPC=0x3ae1 +OP_GMZoneRequest=0x62ac +OP_GMZoneRequest2=0x7e1a +OP_GMGoto=0x7d8e +OP_GMSearchCorpse=0x357c +OP_GMHideMe=0x79c5 +OP_GMDelCorpse=0x607e +OP_GMApproval=0x6db5 +OP_GMToggle=0x2097 +OP_GMSummon=0x486f +OP_GMEmoteZone=0x1cfd +OP_GMEmoteWorld=0x458e +OP_GMFind=0x4a8f +OP_GMKick=0x26a7 +OP_GMKill=0x51d3 +OP_GMNameChange=0x035f +OP_GMLastName=0x46ce + +# Misc Opcodes +OP_InspectRequest=0x57bc +OP_InspectAnswer=0x71ac +OP_InspectMessageUpdate=0x4d25 +OP_BeginCast=0x318f +OP_ColoredText=0x43af +OP_ConsentResponse=0x384a +OP_MemorizeSpell=0x217c +OP_SwapSpell=0x0efa +OP_CastSpell=0x1287 +OP_Consider=0x742b +OP_FormattedMessage=0x1024 +OP_SimpleMessage=0x213f +OP_Buff=0x659c +OP_Illusion=0x312a +OP_MoneyOnCorpse=0x5f44 +OP_RandomReply=0x106b +OP_DenyResponse=0x2382 +OP_SkillUpdate=0x04c +OP_GMTrainSkillConfirm=0x4b64 +OP_RandomReq=0x7b10 +OP_Death=0x6517 +OP_GMTraining=0x1966 +OP_GMEndTraining=0x4d6b +OP_GMTrainSkill=0x2a85 +OP_Animation=0x7177 +OP_Begging=0x6703 +OP_Consent=0x1fd1 +OP_ConsentDeny=0x7a45 +OP_AutoFire=0x241e +OP_PetCommands=0x0159 +OP_DeleteSpell=0x52e5 +OP_Surname=0x0423 +OP_ClearSurname=0x3fb0 +OP_FaceChange=0x5578 +OP_SenseHeading=0x260a +OP_Action=0x744c +OP_ConsiderCorpse=0x5204 +OP_HideCorpse=0x49e1 +OP_CorpseDrag=0x0904 +OP_CorpseDrop=0x7037 +OP_Bug=0x73f4 +OP_Feedback=0x5602 +OP_Report=0x1414 +OP_Damage=0x6f15 +OP_ChannelMessage=0x2b2d +OP_Assist=0x4478 +OP_AssistGroup=0x27f8 +OP_MoveCoin=0x0bcf +OP_ZonePlayerToBind=0x0ecb +OP_KeyRing=0x6857 +OP_WhoAllRequest=0x674b +OP_WhoAllResponse=0x578c +OP_FriendsWho=0x3956 +OP_ConfirmDelete=0x43a3 +OP_Logout=0x4ac6 +OP_Rewind=0x1745 +OP_TargetCommand=0x58e2 +OP_Hide=0x67fe +OP_Jump=0x31f4 +OP_Camp=0x28ec +OP_Emote=0x373b +OP_SetRunMode=0x009f +OP_BankerChange=0x791e +OP_TargetMouse=0x075d +OP_MobHealth=0x37b1 +OP_InitialMobHealth=0x0000 # Unused? +OP_TargetHoTT=0x0272 +OP_XTargetResponse=0x672f +OP_XTargetRequest=0x45be +OP_XTargetAutoAddHaters=0x792c +OP_TargetBuffs=0x4f4b +OP_BuffCreate=0x3377 +OP_BuffRemoveRequest=0x64f2 +OP_DeleteSpawn=0x7280 +OP_AutoAttack=0x109d +OP_AutoAttack2=0x3526 +OP_Consume=0x4b70 +OP_MoveItem=0x32ee +OP_DeleteItem=0x18ad +OP_DeleteCharge=0x01b8 +OP_ItemPacket=0x368e +OP_ItemLinkResponse=0x70c0 +OP_ItemLinkClick=0x4cef +OP_ItemPreview=0x6b5c +OP_NewSpawn=0x6097 +OP_Track=0x17e5 +OP_TrackTarget=0x0029 +OP_TrackUnknown=0x4577 +OP_ClickDoor=0x3a8f +OP_MoveDoor=0x08e8 +OP_RemoveAllDoors=0x700c +OP_EnvDamage=0x51fd +OP_BoardBoat=0x4211 +OP_Forage=0x5306 +OP_LeaveBoat=0x7617 +OP_ControlBoat=0x0ae7 +OP_SafeFallSuccess=0x2219 +OP_RezzComplete=0x760d +OP_RezzRequest=0x3c21 +OP_RezzAnswer=0x701c +OP_Shielding=0x48c1 +OP_RequestDuel=0x3af1 +OP_MobRename=0x2c57 +OP_AugmentItem=0x661b +OP_WeaponEquip1=0x34a7 +OP_WeaponEquip2=0x559a +OP_WeaponUnequip2=0x2d25 +OP_ApplyPoison=0x31e6 +OP_Save=0x4a39 +OP_TestBuff=0x7cb8 +OP_CustomTitles=0x100e +OP_Split=0x3a54 +OP_YellForHelp=0x4e56 +OP_LoadSpellSet=0x261d +OP_Bandolier=0x7677 +OP_PotionBelt=0x1a3e +OP_DuelResponse=0x6a46 +OP_DuelResponse2=0x68d3 +OP_SaveOnZoneReq=0x600d +OP_ReadBook=0x72df +OP_Dye=0x23b9 +OP_InterruptCast=0x048c +OP_AAAction=0x424e +OP_LeadershipExpToggle=0x6c55 +OP_LeadershipExpUpdate=0x2797 +OP_PurchaseLeadershipAA=0x0026 +OP_UpdateLeadershipAA=0x026 +OP_MarkNPC=0x5a58 +OP_MarkRaidNPC=0x74bd #unimplemented +OP_ClearNPCMarks=0x2003 +OP_ClearRaidNPCMarks=0x20d3 #unimplemented +OP_DelegateAbility=0x76b8 +OP_SetGroupTarget=0x2814 +OP_Charm=0x5d92 +OP_Stun=0x36a4 +OP_SendFindableNPCs=0x4613 +OP_FindPersonRequest=0x5cea +OP_FindPersonReply=0x7e58 +OP_Sound=0x1a30 +OP_PetBuffWindow=0x5882 +OP_LevelAppearance=0x3bc9 +OP_Translocate=0x6580 +OP_Sacrifice=0x1821 +OP_PopupResponse=0x08a6 +OP_OnLevelMessage=0x575b +OP_AugmentInfo=0x0afb +OP_Petition=0x1901 +OP_SomeItemPacketMaybe=0x747c +OP_PVPStats=0x4b15 +OP_PVPLeaderBoardRequest=0x04aa +OP_PVPLeaderBoardReply=0x071f +OP_PVPLeaderBoardDetailsRequest=0x3707 +OP_PVPLeaderBoardDetailsReply=0x25b7 +OP_RestState=0x000f +OP_RespawnWindow=0x28bc +OP_LDoNButton=0x5327 +OP_SetStartCity=0x6326 +OP_VoiceMacroIn=0x17fd +OP_VoiceMacroOut=0x409a +OP_ItemViewUnknown=0x465b +OP_VetRewardsAvaliable=0x590e +OP_VetClaimRequest=0x1126 +OP_VetClaimReply=0x16d4 +OP_DisciplineUpdate=0x759e +OP_DisciplineTimer=0x6989 +OP_BecomeCorpse=0x0000 # Unused? +OP_Action2=0x0000 # Unused? +OP_MobUpdate=0x2c84 +OP_NPCMoveUpdate=0x5892 +OP_CameraEffect=0x127f +OP_SpellEffect=0x5936 +OP_RemoveNimbusEffect=0x7b1e +OP_AltCurrency=0x6b6d +OP_AltCurrencyMerchantRequest=0x5409 +OP_AltCurrencyMerchantReply=0x27a2 +OP_AltCurrencyPurchase=0x3788 +OP_AltCurrencySell=0x40b6 +OP_AltCurrencySellSelection=0x532a +OP_AltCurrencyReclaim=0x0339 +OP_CrystalCountUpdate=0x467f +OP_CrystalCreate=0x7aee +OP_CrystalReclaim=0x2439 +OP_Untargetable=0x053c +OP_IncreaseStats=0x70a3 +OP_Weblink=0x6f4b +OP_OpenContainer=0x0000 +OP_Marquee=0x502e +OP_ItemRecastDelay=0x15a9 +#OP_OpenInventory=0x0000 # Likely does not exist in RoF -U + +OP_DzQuit=0x205f +OP_DzListTimers=0x0398 +OP_DzAddPlayer=0x59ca +OP_DzRemovePlayer=0x4701 +OP_DzSwapPlayer=0x1abc +OP_DzMakeLeader=0x405b +OP_DzPlayerList=0x543d +OP_DzJoinExpeditionConfirm=0x14c6 +OP_DzJoinExpeditionReply=0x7f4b +OP_DzExpeditionInfo=0x4f7e +OP_DzExpeditionList=0x9119 +OP_DzMemberStatus=0xb2e3 +OP_DzLeaderStatus=0x32f0 +OP_DzExpeditionEndsWarning=0x7e94 +OP_DzMemberList=0x3de9 +OP_DzCompass=0x3e0e +OP_DzChooseZone=0x0b7d + +# New Opcodes +OP_SpawnPositionUpdate=0x0000 # Actually OP_MobUpdate ? +OP_ManaUpdate=0x3791 +OP_EnduranceUpdate=0x5f42 +OP_MobManaUpdate=0x2404 +OP_MobEnduranceUpdate=0x1c81 + +# Mercenary Opcodes +OP_MercenaryDataUpdateRequest=0x7b89 +OP_MercenaryDataUpdate=0x61a4 +OP_MercenaryDataRequest=0x11c1 +OP_MercenaryDataResponse=0x72ce +OP_MercenaryHire=0x7169 +OP_MercenaryDismiss=0x6e83 +OP_MercenaryTimerRequest=0x31e4 +OP_MercenaryTimer=0x0763 +OP_MercenaryUnknown1=0x5d26 +OP_MercenaryCommand=0x27f2 +OP_MercenarySuspendRequest=0x4407 +OP_MercenarySuspendResponse=0x6f03 +OP_MercenaryUnsuspendResponse=0x27a0 + +# Looting +OP_LootRequest=0x0adf +OP_EndLootRequest=0x30f7 +OP_LootItem=0x4dc9 +OP_LootComplete=0x55c4 + +# bazaar trader stuff: +OP_BazaarSearch=0x39d6 +OP_TraderDelItem=0x0000 +OP_BecomeTrader=0x61b3 +OP_TraderShop=0x31df +OP_Trader=0x4ef5 +OP_TraderBuy=0x0000 +OP_Barter=0x243a +OP_ShopItem=0x0000 +OP_BazaarInspect=0x0000 +OP_Bazaar=0x0000 +OP_TraderItemUpdate=0x0000 + +# pc/npc trading +OP_TradeRequest=0x77b5 +OP_TradeAcceptClick=0x69e2 +OP_TradeRequestAck=0x14bf +OP_TradeCoins=0x4206 +OP_FinishTrade=0x3993 +OP_CancelTrade=0x354c +OP_TradeMoneyUpdate=0x68c2 +OP_MoneyUpdate=0x640c +OP_TradeBusy=0x5505 + +# Sent after canceling trade or after closing tradeskill object +OP_FinishWindow=0x7349 +OP_FinishWindow2=0x40ef + +# Sent on Live for what seems to be item existance verification +# Ex. Before Right Click Effect happens from items +OP_ItemVerifyRequest=0x189c +OP_ItemVerifyReply=0x097b + +# merchant stuff +OP_ShopPlayerSell=0x0000 +OP_ShopRequest=0x4fed +OP_ShopEnd=0x30a8 +OP_ShopEndConfirm=0x3196 +OP_ShopPlayerBuy=0x0ddd +OP_ShopDelItem=0x724f + +# tradeskill stuff: +OP_ClickObject=0x4aa1 +OP_ClickObjectAction=0x0c1e +OP_ClearObject=0x7a11 +OP_RecipeDetails=0x40d7 +OP_RecipesFavorite=0x71b1 +OP_RecipesSearch=0x1db6 +OP_RecipeReply=0x6e02 +OP_RecipeAutoCombine=0x6261 +OP_TradeSkillCombine=0x579a + +# Tribute Packets: +OP_OpenGuildTributeMaster=0x378d +OP_OpenTributeMaster=0x7666 +OP_SelectTribute=0x79fc +OP_TributeItem=0x4f3e +OP_TributeMoney=0x58fb +OP_TributeToggle=0x241d +OP_TributePointUpdate=0x5300 +OP_TributeNPC=0x0000 +OP_GuildTributeInfo=0x0000 +OP_OpenTributeReply=0x0000 +OP_GuildTributeStatus=0x0000 + +# Adventure packets: +OP_LeaveAdventure=0x5d18 +OP_AdventureFinish=0x400f +OP_AdventureInfoRequest=0x3cb0 +OP_AdventureInfo=0x4c54 +OP_AdventureRequest=0x2c6c +OP_AdventureDetails=0x5648 +OP_AdventureData=0x7171 +OP_AdventureUpdate=0x1b01 +OP_AdventureMerchantRequest=0x6922 +OP_AdventureMerchantResponse=0x3e47 +OP_AdventureMerchantPurchase=0x5b72 +OP_AdventureMerchantSell=0x2f9b +OP_AdventurePointsUpdate=0x65c3 +OP_AdventureStatsRequest=0x5a62 +OP_AdventureStatsReply=0x2370 +OP_AdventureLeaderboardRequest=0x7093 +OP_AdventureLeaderboardReply=0x7f79 + +# Group Opcodes +OP_GroupDisband=0x4c10 +OP_GroupInvite=0x6110 +OP_GroupFollow=0x1649 +OP_GroupUpdate=0x3abb +OP_GroupUpdateB=0x6194 +OP_GroupCancelInvite=0x0000 +OP_GroupAcknowledge=0x7323 +OP_GroupDelete=0x0f6c +OP_CancelInvite=0x2a50 +OP_GroupFollow2=0x2060 +OP_GroupInvite2=0x32c2 +OP_GroupDisbandYou=0x1ae5 +OP_GroupDisbandOther=0x74da +OP_GroupLeaderChange=0x21b4 +OP_GroupRoles=0x70e2 +OP_GroupMakeLeader=0x4229 +OP_DoGroupLeadershipAbility=0x1fb5 +OP_GroupLeadershipAAUpdate=0x02cf +OP_GroupMentor=0x3342 +OP_InspectBuffs=0x486c + +# LFG/LFP Opcodes +OP_LFGCommand=0x6060 +OP_LFGGetMatchesRequest=0x0340 +OP_LFGGetMatchesResponse=0x5048 +OP_LFPGetMatchesRequest=0x4d7d +OP_LFPGetMatchesResponse=0x22c6 +OP_LFPCommand=0x49a9 +OP_LFGAppearance=0x0000 +OP_LFGResponse=0x0000 + +# Raid Opcodes +OP_RaidInvite=0x55ac +OP_RaidUpdate=0x3973 +OP_RaidJoin=0x0000 + +# Button-push commands +OP_Taunt=0x2703 +OP_CombatAbility=0x3eba +OP_SenseTraps=0x02af +OP_PickPocket=0x39e8 +OP_DisarmTraps=0x78bf +OP_Disarm=0x5ec8 +OP_Sneak=0x5d55 +OP_Fishing=0x1e2a +OP_InstillDoubt=0x640e +OP_FeignDeath=0x52fa +OP_Mend=0x0ecf +OP_Bind_Wound=0x0386 +OP_LDoNOpen=0x3d5c + +# Task packets +OP_TaskDescription=0x3714 +OP_TaskActivity=0x08d3 +OP_CompletedTasks=0x4eba +OP_TaskActivityComplete=0x5e19 +OP_AcceptNewTask=0x0a23 +OP_CancelTask=0x39f0 +OP_TaskMemberList=0x5727 +OP_OpenNewTasksWindow=0x48a2 +OP_AvaliableTask=0x36e8 +OP_TaskHistoryRequest=0x5f1c +OP_TaskHistoryReply=0x3d05 +OP_DeclineAllTasks=0x0000 + +# Title opcodes +OP_NewTitlesAvailable=0x0d32 +OP_RequestTitles=0x6344 +OP_SendTitleList=0x2d08 +OP_SetTitle=0x6527 +OP_SetTitleReply=0x4c21 + +# mail opcodes +OP_Command=0x0000 +OP_MailboxHeader=0x0000 +OP_MailHeader=0x0000 +OP_MailBody=0x0000 +OP_NewMail=0x0000 +OP_SentConfirm=0x0000 + +########### Below this point should not be needed ########### + +# This section are all unknown in Titanium +OP_ForceFindPerson=0x0000 +OP_LocInfo=0x0000 +OP_ReloadUI=0x0000 +OP_ItemName=0x0000 +OP_ItemLinkText=0x0000 +OP_MultiLineMsg=0x0000 +OP_MendHPUpdate=0x0000 +OP_TargetReject=0x0000 +OP_SafePoint=0x0000 +OP_ApproveZone=0x0000 +OP_ZoneComplete=0x0000 +OP_ClientError=0x0000 +OP_DumpName=0x0000 +OP_Heartbeat=0x0000 +OP_CrashDump=0x0000 +OP_LoginComplete=0x0000 + +# discovered opcodes not yet used: +OP_PickLockSuccess=0x0000 +OP_PlayMP3=0x5770 +OP_ReclaimCrystals=0x0000 +OP_DynamicWall=0x0000 +OP_OpenDiscordMerchant=0x0000 +OP_DiscordMerchantInventory=0x0000 +OP_GiveMoney=0x0000 +OP_RequestKnowledgeBase=0x0000 +OP_KnowledgeBase=0x0000 +OP_SlashAdventure=0x0000 # /adventure +OP_BecomePVPPrompt=0x0000 +OP_MoveLogRequest=0x0000 # gone I think +OP_MoveLogDisregard=0x0000 # gone I think + +# named unknowns, to make looking for real unknown easier +OP_AnnoyingZoneUnknown=0x0000 +OP_Some6ByteHPUpdate=0x0000 seems to happen when you target group members +OP_QueryResponseThing=0x0000 + + +# realityincarnate: these are just here to stop annoying several thousand byte packet dumps +#OP_LoginUnknown1=0x46d3 # OP_SendSpellChecksum +#OP_LoginUnknown2=0x040b # OP_SendSkillCapsChecksum + +# Petition Opcodes +OP_PetitionSearch=0x0000 search term for petition +OP_PetitionSearchResults=0x0000 (list of?) matches from search +OP_PetitionSearchText=0x0000 text results of search + +OP_PetitionUpdate=0x0000 +OP_PetitionCheckout=0x0000 +OP_PetitionCheckIn=0x0000 +OP_PetitionQue=0x0000 +OP_PetitionUnCheckout=0x0000 +OP_PetitionDelete=0x0000 +OP_DeletePetition=0x0000 +OP_PetitionResolve=0x0000 +OP_PDeletePetition=0x0000 +OP_PetitionBug=0x0000 +OP_PetitionRefresh=0x0000 +OP_PetitionCheckout2=0x0000 +OP_PetitionViewPetition=0x0000 + +# Login opcodes +OP_SessionReady=0x0000 +OP_Login=0x0000 +OP_ServerListRequest=0x0000 +OP_PlayEverquestRequest=0x0000 +OP_PlayEverquestResponse=0x0000 +OP_ChatMessage=0x0000 +OP_LoginAccepted=0x0000 +OP_ServerListResponse=0x0000 +OP_Poll=0x0000 +OP_EnterChat=0x0000 +OP_PollResponse=0x0000 + +# raw opcodes +OP_RAWSessionRequest=0x0000 +OP_RAWSessionResponse=0x0000 +OP_RAWCombined=0x0000 +OP_RAWSessionDisconnect=0x0000 +OP_RAWKeepAlive=0x0000 +OP_RAWSessionStatRequest=0x0000 +OP_RAWSessionStatResponse=0x0000 +OP_RAWPacket=0x0000 +OP_RAWFragment=0x0000 +OP_RAWOutOfOrderAck=0x0000 +OP_RAWAck=0x0000 +OP_RAWAppCombined=0x0000 +OP_RAWOutOfSession=0x0000 + +# we need to document the differences between these packets to make identifying them easier +OP_Some3ByteHPUpdate=0x0000 # initial HP update for mobs +OP_InitialHPUpdate=0x0000 diff --git a/utils/patches/patch_SoD.conf b/utils/patches/patch_SoD.conf index 338ee82e7..a5dee668c 100644 --- a/utils/patches/patch_SoD.conf +++ b/utils/patches/patch_SoD.conf @@ -158,7 +158,7 @@ OP_GMApproval=0x72fa # C OP_GMToggle=0x7566 # C OP_GMSummon=0x596d # C OP_GMEmoteZone=0x3e7c # C -OP_GMEmoteWorld=0x3e7c # C +OP_GMEmoteWorld=0x5298 # C OP_GMFind=0x6e27 # C OP_GMKick=0x799c # C OP_GMKill=0x6685 # C @@ -369,7 +369,7 @@ OP_DzExpeditionEndsWarning=0x1879 OP_DzExpeditionList=0x3657 OP_DzMemberList=0x74e4 OP_DzCompass=0x35d3 -OP_DzChooseZone=0xd8a +OP_DzChooseZone=0x0d8a #0x1d99 was grouped with these too but I don't really know it's purpose. # New Opcodes @@ -531,7 +531,8 @@ OP_Shroud=0x6d1f OP_ShroudRemove=0x17f6 OP_ShroudUnknown1=0x169a OP_ShroudUnknown2=0x4292 -OP_ShroudClearAA=0x3bef +OP_ClearAA=0x3bef +OP_ClearLeadershipAbilities=0x6e58 OP_ShroudSelectionWindow=0x4d79 OP_ShroudRequestStats=0x28ce OP_ShroudRespondStats=0x33f2 @@ -580,7 +581,6 @@ OP_MultiLineMsg=0x0000 # OP_MendHPUpdate=0x0000 # OP_TargetReject=0x0000 # OP_SafePoint=0x0000 # -OP_IncreaseStats=0x0000 # OP_ApproveZone=0x0000 # OP_ZoneComplete=0x0000 # OP_ClientError=0x0000 # diff --git a/utils/patches/patch_SoF.conf b/utils/patches/patch_SoF.conf index fc0c716e1..80aee8bdc 100644 --- a/utils/patches/patch_SoF.conf +++ b/utils/patches/patch_SoF.conf @@ -85,6 +85,8 @@ OP_TaskActivity=0x2E60 #SEQ 12/04/08 OP_CompletedTasks=0x75AC #Derision 2009 OP_Weather=0x70A5 #SEQ 12/04/08 OP_SendAATable=0x6F05 #Trevius 12/20/08 +OP_ClearAA=0x71b9 +OP_ClearLeadershipAbilities=0x74e5 OP_UpdateAA=0x45D2 #Trevius 12/20/08 OP_RespondAA=0x4426 #Trevius 12/20/08 OP_ReqClientSpawn=0x014C #SEQ 12/04/08 @@ -331,6 +333,7 @@ OP_InspectMessageUpdate=0x67e9 # C OP_OpenInventory=0x66c8 OP_OpenContainer=0x10e3 OP_Marquee=0x2f75 +OP_Untargetable=0x3e36 #expedition OP_DzQuit=0x20d6 @@ -530,7 +533,7 @@ OP_MultiLineMsg=0x0000 # OP_MendHPUpdate=0x0000 # OP_TargetReject=0x0000 # OP_SafePoint=0x0000 # -OP_IncreaseStats=0x0000 # +OP_IncreaseStats=0x5ecb # OP_ApproveZone=0x0000 # OP_ZoneComplete=0x0000 # OP_ClientError=0x0000 # @@ -544,9 +547,11 @@ OP_PickLockSuccess=0x0000 # OP_VetRewardsAvaliable=0x044b # OP_VetClaimRequest=0x7503 OP_VetClaimReply=0x01e1 -OP_PlayMP3=0x0000 # +OP_PlayMP3=0x0d1c # OP_ReclaimCrystals=0x0000 # OP_CrystalCountUpdate=0x64C1 # +OP_CrystalCreate=0x65e2 +OP_CrystalReclaim=0x0730 OP_DynamicWall=0x0000 # OP_OpenDiscordMerchant=0x0000 # OP_DiscordMerchantInventory=0x0000 # diff --git a/utils/patches/patch_Underfoot.conf b/utils/patches/patch_Underfoot.conf index 56838da65..09c6a8252 100644 --- a/utils/patches/patch_Underfoot.conf +++ b/utils/patches/patch_Underfoot.conf @@ -88,6 +88,8 @@ OP_TaskActivity=0x31f3 # C OP_CompletedTasks=0x687f # C OP_Weather=0x4658 # V OP_SendAATable=0x6ef9 # V +OP_ClearAA=0x2cd4 +OP_ClearLeadershipAbilities=0x7b77 OP_UpdateAA=0x7bf6 # V OP_RespondAA=0x1fbd # C 0x2bad OP_ReqClientSpawn=0x69cd # V @@ -315,7 +317,7 @@ OP_OnLevelMessage=0x24cb # C OP_AugmentInfo=0x31b1 # C OP_Petition=0x31d1 # C OP_SomeItemPacketMaybe=0x2c27 # C -OP_PVPStats=0x0000 # +OP_PVPStats=0x5272 # OP_PVPLeaderBoardRequest=0x4973 # C OP_PVPLeaderBoardReply=0x3842 # C OP_PVPLeaderBoardDetailsRequest=0x6c75 # C @@ -373,7 +375,17 @@ OP_DzExpeditionEndsWarning=0x6ac2 OP_DzExpeditionList=0x70d8 OP_DzMemberList=0x15c4 OP_DzCompass=0x01cb -OP_DzChooseZone=0x0000 +OP_DzChooseZone=0x65e1 + +#shroud +OP_ShroudSelectionWindow=0x72ad +OP_ShroudRequestStats=0x488b +OP_ShroudRespondStats=0x1910 +OP_ShroudSelect=0x45d7 +OP_ShroudSelectCancel=0x666d +OP_ShroudProgress=0x6016 # This clears current progress and sets +OP_ShroudProgress2=0x66b4 # This just sets progress +OP_Shroud=0x1643 # New Opcodes OP_SpawnPositionUpdate=0x4656 # C diff --git a/utils/scripts/opcode_scripts/.gitignore b/utils/scripts/opcode_scripts/.gitignore new file mode 100644 index 000000000..0227fe923 --- /dev/null +++ b/utils/scripts/opcode_scripts/.gitignore @@ -0,0 +1,3 @@ +# Input and Output txt and conf files +*.txt +*.conf diff --git a/utils/scripts/opcode_scripts/conf_to_oplist.pl b/utils/scripts/opcode_scripts/conf_to_oplist.pl new file mode 100644 index 000000000..f79de1093 --- /dev/null +++ b/utils/scripts/opcode_scripts/conf_to_oplist.pl @@ -0,0 +1,66 @@ +#!/usr/bin/perl + +# File Name: conf_to_oplist.pl +# Converts a Patch File into the Opcode List with Opcode Names for the Spreadsheet. + +# Directions to use this script: +# 1. Paste the contents of the current patch file in the patch_OLD.conf file. +# 2. Run this script using "perl conf_to_oplist.pl" +# 3. This updates the opcodelist.txt with the values from the Patch File. + + +$stopmessage = "Failed to open file"; +open OpcodeFile, "<", "opcodelist.txt" or die $stopmessage; +open PatchFile, "<", "patch_OLD.conf" or die $stopmessage; + +my @OpcodeList = ; +my @PatchFile = ; +my %PatchHash = (); + +foreach $line (@PatchFile) +{ + @equalssplit = split(/=/, $line); + $ArraySize = @equalssplit; + if ($ArraySize > 1) + { + @OpcodeArray = split(//, $equalssplit[1]); + $CurOpcode = $OpcodeArray[0].$OpcodeArray[1].$OpcodeArray[2].$OpcodeArray[3].$OpcodeArray[4].$OpcodeArray[5]; + $CurOpcode = lc($CurOpcode); + # Opcode Name => Opcode + $PatchHash{ $CurOpcode } = $equalssplit[0]; + } +} + +close(OpcodeFile); +close(PatchFile); + +# Clear out file contents +open OpcodeResultFile, ">", "opcodelist.txt" or die $stopmessage; +print OpcodeResultFile ""; +close(OpcodeResultFile); + +open OpcodeResultFile, ">>", "opcodelist.txt" or die $stopmessage; + +while( my ($k, $v) = each %$PatchFile ) +{ + #print OpcodeResultFile "key: $k, value: $v.\n"; +} + + +$TabSpace = " "; # Tab +foreach $line (@OpcodeList) +{ + @LineSplit = split(//, $line); + $CurOpcode = $LineSplit[0].$LineSplit[1].$LineSplit[2].$LineSplit[3].$LineSplit[4].$LineSplit[5]; + $CurOpcode = lc($CurOpcode); + $OpcodeName = ""; # Tab + if ($PatchHash{$CurOpcode}) + { + $NameKey = $PatchHash{$CurOpcode}; + $OpcodeName = $NameKey; + } + $CurLine = $CurOpcode.$TabSpace.$OpcodeName."\n"; + print OpcodeResultFile $CurLine; +} + +close(OpcodeResultFile); diff --git a/utils/scripts/opcode_scripts/opcodelist.txt b/utils/scripts/opcode_scripts/opcodelist.txt new file mode 100644 index 000000000..8a4ebf87d --- /dev/null +++ b/utils/scripts/opcode_scripts/opcodelist.txt @@ -0,0 +1,1671 @@ +RoF2 Built May 10 2013 23:30:08 +0x04d6 +0x5efd +0x0cc1 +0x2c3d +0x7b25 +0x4f44 +0x7592 +0x2b1c +0x1fd1 OP_Consent +0x15a5 +0x3c7e +0x6262 +0x471d OP_AckPacket +0x64a8 +0x7c06 +0x2c5e +0x24ab +0x19b5 +0x72fa +0x0770 +0x4cef OP_ItemLinkClick +0x08c1 OP_GMServers +0x318f OP_BeginCast +0x5ec8 OP_Disarm +0x6ae3 +0x2b2d OP_ChannelMessage +0x1cb1 +0x5070 OP_TimeOfDay +0x7dfc OP_ClientUpdate +0x35ea +0x3b9a +0x148d +0x345d OP_ClientReady +0x5ae2 OP_WorldObjectsSent +0x03a4 +0x69e2 OP_TradeAcceptClick +0x354c OP_CancelTrade +0x3993 OP_FinishTrade +0x165b +0x2b95 +0x6fe2 +0x42fd +0x25d7 +0x7436 +0x4206 OP_TradeCoins +0x14bf OP_TradeRequestAck +0x7349 OP_FinishWindow +0x71fd +0x0b9c OP_SetGuildRank +0x0f7d +0x1bd3 +0x5053 OP_GuildPublicNote +0x01f9 +0x2c84 OP_MobUpdate +0x279d +0x5a94 +0x579a OP_TradeSkillCombine +0x56b1 +0x0f25 +0x3c14 +0x0c16 +0x4a8f OP_GMFind +0x2ad6 +0x0160 +0x7852 +0x41bf +0x40dd +0x3ec6 +0x6af4 +0x6d9d +0x2538 +0x0017 +0x017 +0x691a +0x0520 +0x200f +0x65ab +0x674b OP_WhoAllRequest +0x6a02 +0x0e48 +0x12a6 OP_GuildMemberList +0x0eae +0x2921 +0x7056 +0x507a +0x6279 OP_GuildList +0x5a26 +0x5b51 +0x0bad +0x59ad +0x2264 +0x004c +0x04c OP_SkillUpdate +0x0ddd OP_ShopPlayerBuy +0x4101 +0x5f03 +0x3de3 +0x1901 OP_Petition +0x791b +0x3a5d +0x7013 +0x47f1 +0x6506 OP_PlayerProfile +0x30a8 OP_ShopEnd +0x724f OP_ShopDelItem +0x5829 +0x1ce1 +0x47d6 +0x07cf +0x40c9 +0x38d4 +0x7eb9 +0x1e2c +0x3ae1 OP_GMBecomeNPC +0x4849 +0x376b +0x1e2a OP_Fishing +0x1eec OP_LevelUpdate +0x4958 +0x20ed OP_ExpUpdate +0x3ed4 +0x701c OP_RezzAnswer +0x640e OP_InstillDoubt +0x0ecf OP_Mend +0x09d3 +0x70a3 OP_IncreaseStats +0x178e +0x27e8 +0x61f8 +0x4322 +0x3f84 +0x40ef OP_FinishWindow2 +0x166c +0x106b OP_RandomReply +0x5bfd +0x11c8 +0x1753 +0x009f OP_SetRunMode +0x09f +0x4ae6 +0x3dbf +0x0399 +0x5c89 +0x012c +0x381c +0x4b36 +0x36d5 +0x5f21 +0x56f7 +0x46b1 +0x357c OP_GMSearchCorpse +0x2422 +0x084e +0x67e3 OP_GuildPeace +0x0f83 +0x4577 OP_TrackUnknown +0x5d55 OP_Sneak +0x67fe OP_Hide +0x12e5 +0x2c7a +0x600d OP_SaveOnZoneReq +0x16ce +0x46ce OP_GMLastName +0x1ffb OP_GuildWar +0x6718 +0x2f3e +0x7e09 OP_GuildLeader +0x5ce4 +0x5bcc +0x551d +0x6dbc +0x2219 OP_SafeFallSuccess +0x2686 +0x2022 +0x1c53 +0x33a2 +0x3541 +0x582e +0x3cba +0x190c +0x5067 +0x46d2 +0x49cf +0x1b0c + +0x31e6 OP_ApplyPoison +0x4211 OP_BoardBoat +0x7617 OP_LeaveBoat +0x4466 +0x1287 OP_CastSpell +0x5467 OP_ManaChange +0x43af OP_ColoredText +0x6a0d +0x217c OP_MemorizeSpell +0x260a OP_SenseHeading +0x5886 +0x7e8c +0x1a37 +0x0b6f +0x62ca +0x34a4 +0x6c83 +0x5d10 +0x21a0 +0x3537 +0x2acd +0x7c6d +0x6618 +0x6c65 + + +0x32c2 OP_GroupInvite2 +0x2a50 OP_CancelInvite +0x2060 OP_GroupFollow2 +0x31f4 OP_Jump +0x4420 +0x1256 +0x4d38 +0x50f5 + +0x79c5 OP_GMHideMe +0x2fab +0x57a5 +0x32a4 +0x590d OP_ExpansionInfo +0x6f15 OP_Damage +0x42ea +0x3091 +0x6b5a +0x3234 +0x30b4 +0x51fd OP_EnvDamage +0x15f4 +0x1808 OP_DeleteCharacter +0x1795 OP_NewZone +0x7887 OP_ReqNewZone +0x2414 +0x2eb3 +0x3db3 +0x4008 + +0x373b OP_Emote +0x7280 OP_DeleteSpawn +0x4bc2 +0x15bb +0x4fed OP_ShopRequest +0x0c2f +0x4aa1 OP_ClickObject +0x6fca OP_GroundSpawn +0x1045 +0x2a9e +0x2523 +0x6213 +0x4a39 OP_Save +0x0797 +0x35fa OP_ReqClientSpawn +0x5f8e OP_SendExpZonein +0x4c10 OP_GroupDisband +0x747c OP_SomeItemPacketMaybe +0x744c OP_Action +0x00d2 OP_SendCharInfo +0x0d2 +0x11d4 +0x6bbf OP_CharacterCreate +0x6517 OP_Death +0x19f6 +0x360f +0x1951 +0x51d3 OP_GMKill +0x26a7 OP_GMKick +0x7d8e OP_GMGoto +0x475e +0x5253 +0x3c79 +0x5065 +0x0337 +0x2ded +0x777b +0x4434 +0x0e90 +0x57da +0x150e +0x1ba8 +0x70eb +0x0adf OP_LootRequest +0x30f7 OP_EndLootRequest +0x5f44 OP_MoneyOnCorpse +0x3d54 +0x482d +0x58b2 +0x7361 +0x604f +0x3d87 +0x6909 +0x4f73 +0x0a0f +0x56a2 OP_ApproveName +0x69e6 +0x3a8f OP_ClickDoor +0x08e8 OP_MoveDoor +0x7dd1 +0x5c66 +0x312a OP_Illusion +0x2807 +0x4fe2 +0x2f2e +0x5824 +0x6661 +0x4742 +0x4d02 +0x2105 +0x19e9 +0x2268 +0x7994 OP_WearChange +0x0386 OP_Bind_Wound +0x5306 OP_Forage +0x0971 OP_SpawnAppearance +0x7099 OP_GuildInvite +0x7053 OP_GuildInviteAccept +0x1444 OP_GuildRemove +0x3708 OP_GuildDelete +0x7b22 +0x610f +0x324a +0x2889 +0x6f2a +0x2998 +0x700c OP_RemoveAllDoors +0x1966 OP_GMTraining +0x4d6b OP_GMEndTraining +0x6e8d +0x2b41 +0x4dc9 OP_LootItem +0x7177 OP_Animation +0x650e +0x2d18 OP_ZoneChange +0x707b +0x0803 +0x3fc3 +0x7326 OP_GuildStatus +0x0804 +0x3f86 +0x6d20 +0x04a3 +0x4714 +0x6703 OP_Begging +0x0ae7 OP_ControlBoat +0x27d7 +0x3c21 OP_RezzRequest +0x6f22 +0x32ee OP_MoveItem +0x0bcf OP_MoveCoin +0x2452 +0x0186 +0x0522 +0x3a54 OP_Split +0x659c OP_Buff +0x225b + +0x12cc OP_World_Client_CRC1 +0x661e OP_Weather +0x742b OP_Consider +0x102e +0x0f13 OP_World_Client_CRC2 +0x6944 +0x2703 OP_Taunt +0x5602 OP_Feedback +0x68c2 OP_TradeMoneyUpdate +0x07f7 +0x3fe7 +0x43a0 +0x314c +0x4b70 OP_Consume +0x2a79 OP_Stamina +0x402e +0x750e +0x0927 +0x36a4 OP_Stun +0x2b03 +0x68d3 OP_DuelResponse2 +0x6a46 OP_DuelResponse +0x5237 OP_ZoneSpawns +0x3eba OP_CombatAbility +0x109d OP_AutoAttack +0x075d OP_TargetMouse +0x05d2 +0x2a85 OP_GMTrainSkill +0x43a3 OP_ConfirmDelete +0x6c57 +0x3906 +0x55c4 OP_LootComplete +0x3196 OP_ShopEndConfirm +0x18ad OP_DeleteItem +0x01b8 OP_DeleteCharge +0x01d7 +0x4d28 +0x4fd9 +0x02c6 +0x3e30 +0x3fcf OP_RequestClientZoneChange +0x4e0e +0x1dee +0x62ac OP_GMZoneRequest +0x4ac6 OP_Logout +0x3526 OP_AutoAttack2 +0x7ceb OP_LogServer +0x0423 OP_Surname +0x3956 OP_FriendsWho +0x45dc +0x35e0 +0x173e +0x4853 +0x393b +0x0efa OP_SwapSpell +0x3588 +0x26e9 +0x4e56 OP_YellForHelp +0x2551 +0x38c8 +0x7499 OP_ApproveWorld +0x603a +0x7b10 OP_RandomReq +0x208f +0x607e OP_GMDelCorpse +0x1821 OP_Sacrifice +0x30d6 +0x760d OP_RezzComplete +0x4dd5 +0x0fe8 +0x6e5c +0x2228 +0x21bc +0x78c3 +0x3e57 +0x69d0 +0x1e3a +0x1a30 OP_Sound +0x61a0 +0x048c OP_InterruptCast +0x6e80 +0x3d29 +0x5d92 OP_Charm +0x0159 OP_PetCommands +0x486e +0x579e +0x49b3 +0x6db5 OP_GMApproval +0x4759 +0x0c22 OP_MOTD +0x2097 OP_GMToggle +0x72f7 +0x640c OP_MoneyUpdate +0x51e5 +0x1802 +0x5de1 +0x2e0c +0x58e2 OP_TargetCommand +0x444d OP_SetServerFilter +0x4478 OP_Assist +0x2a21 +0x7e59 +0x0b0b OP_SetGuildMOTD +0x3e13 OP_GuildMOTD +0x7a11 OP_ClearObject +0x6580 OP_Translocate +0x28ec OP_Camp +0x61b3 OP_BecomeTrader +0x31af +0x0876 OP_TGB +0x4ee1 +0x7e92 +0x7d14 OP_AAExpUpdate + +0x5578 OP_FaceChange +0x1a80 +0x42ff +0x7c2d +0x2c57 OP_MobRename +0x6dab +0x4568 +0x7776 +0x5029 +0x696c +0x23b9 OP_Dye +0x5204 OP_ConsiderCorpse +0x213f OP_SimpleMessage +0x1024 OP_FormattedMessage +0x2ce5 +0x5cc9 +0x3358 +0x52e5 OP_DeleteSpell +0x48c1 OP_Shielding +0x6f14 +0x1414 OP_Report +0x0e1c +0x1219 +0x6857 OP_KeyRing +0x55ac OP_RaidInvite +0x3973 OP_RaidUpdate +0x56fe +0x7f2d +0x31df OP_TraderShop +0x4ef5 OP_Trader +0x735d +0x019b +0x5930 +0x2d73 +0x39d6 OP_BazaarSearch +0x6a96 +0x424e OP_AAAction +0x7a27 OP_RespondAA +0x5eca +0x70c6 +0x0dd4 +0x4598 +0x19b6 +0x728a +0x5232 +0x77bd + +0x70c0 OP_ItemLinkResponse +0x633c +0x63eb +0x4765 +0x6290 +0x1db6 OP_RecipesSearch +0x6e02 OP_RecipeReply +0x40d7 OP_RecipeDetails +0x6261 OP_RecipeAutoCombine +0x4015 OP_SetGroupLeadershipAbilities +0x6eae OP_SetRaidLeadershipAbilities +0x1fb5 OP_DoGroupLeadershipAbility +0x5a58 OP_MarkNPC +0x74bd OP_MarkRaidNPC +0x6c55 OP_LeadershipExpToggle +0x0026 OP_PurchaseLeadershipAA +0x026 OP_UpdateLeadershipAA +0x2814 OP_SetGroupTarget +0x4c9d OP_SetRaidTarget +0x76b8 OP_DelegateAbility +0x2b33 OP_DelegateRaidAbility +0x4786 OP_SenseNPCData +0x0eb4 OP_DelegateFailed +0x486c OP_InspectBuffs +0x0272 OP_TargetHoTT +0x2003 OP_ClearNPCMarks +0x20d3 OP_ClearRaidNPCMarks +0x1c89 +0x4ee2 +0x2797 OP_LeadershipExpUpdate +0x6da5 OP_ClearLeadershipAbilities +0x0ca6 +0x7717 +0x509d +0x6bee +0x0b04 +0x6097 OP_NewSpawn +0x758c +0x2b10 +0x4d09 +0x0083 OP_SpecialMesg +0x3714 OP_TaskDescription +0x08d3 OP_TaskActivity +0x39f0 OP_CancelTask +0x5f7a +0x006a OP_ItemScriptAdjustment +0x7465 +0x31c0 +0x14ba +0x25e0 +0x62a0 +0x407a +0x7c88 +0x51b8 +0x578c OP_WhoAllResponse +0x1197 +0x2dd3 +0x333a +0x2925 +0x37b1 OP_MobHealth +0x7314 +0x2404 OP_MobManaUpdate +0x5f5e +0x1c81 OP_MobEnduranceUpdate +0x4a78 +0x37a2 +0x5565 +0x2d09 +0x3141 +0x695e +0x0029 OP_TrackTarget +0x029 +0x1612 +0x3e69 +0x5c59 +0x7e1a OP_GMZoneRequest2 +0x24d9 +0x5089 OP_ZoneEntry +0x61db +0x542f +0x2006 +0x52fa OP_FeignDeath +0x39e8 OP_PickPocket +0x7c2e +0x2cdd +0x5e3a +0x4214 +0x2828 OP_HPUpdate +0x14b8 +0x3791 OP_ManaUpdate +0x0698 +0x5f42 OP_EnduranceUpdate +0x7eb5 +0x73f4 OP_Bug +0x69a4 OP_SendZonepoints +0x57bc OP_InspectRequest +0x71ac OP_InspectAnswer +0x4229 OP_GroupMakeLeader +0x54f7 +0x322b +0x3264 +0x202c +0x29ae +0x7a09 OP_SendLoginInfo +0x5206 +0x7fd2 +0x6259 OP_PostEnterWorld +0x0f70 +0x00d1 +0x0d1 +0x1eac +0x1b54 +0x5e23 +0x7910 +0x152e +0x7555 +0x05ce +0x1649 OP_GroupFollow +0x6110 OP_GroupInvite +0x0641 +0x578f OP_EnterWorld +0x6cb8 +0x6ef5 +0x4c44 OP_ZoneServerInfo +0x4cb4 OP_ZoneUnavail +0x74fb +0xbe6b +0x5ac7 +0x6281 +0x1bc5 OP_SetChatServer +0x48c8 +0x677b +0x6820 +0x2623 +0x69b9 OP_GuildMemberUpdate +0x2dcb +0x5e04 +0x1d3c +0x6060 OP_LFGCommand +0x0340 OP_LFGGetMatchesRequest +0x49a9 OP_LFPCommand +0x4d7d OP_LFPGetMatchesRequest +0x5048 OP_LFGGetMatchesResponse +0x22c6 OP_LFPGetMatchesResponse +0x499e +0x2d4e OP_GuildDemote +0x2009 +0x3b26 +0x69d4 +0x40b1 +0x587d +0x3747 +0x7a66 +0x2f03 +0x01ed +0x36e0 OP_GetGuildMOTD +0x4f1f OP_GetGuildMOTDReply +0x6087 +0x5f92 +0x439a +0x4334 +0x13c2 +0x7cb8 OP_TestBuff +0x17e5 OP_Track +0x5265 +0x1440 +0x7a4b +0x0648 +0x2529 +0x486f OP_GMSummon +0x458e OP_GMEmoteWorld +0x2549 +0x1cfd OP_GMEmoteZone +0x5ca6 OP_CharInventory +0x2710 +0x7291 OP_SpawnDoor +0x7afc +0x1f65 +0x3ddd +0x85fc +0x72df OP_ReadBook +0x3af1 OP_RequestDuel +0x52f7 +0x77b5 OP_TradeRequest +0x70f2 +0x207d +0x384a OP_ConsentResponse +0x5505 OP_TradeBusy +0x0c1e OP_ClickObjectAction +0x51eb +0x466b +0x41a3 +0x0682 +0x1242 +0x261d OP_LoadSpellSet +0x32a6 +0x2c6c OP_AdventureRequest +0x39e5 +0x5648 OP_AdventureDetails +0x5327 OP_LDoNButton +0x4524 +0x5954 OP_RandomNameGenerator +0x327d +0x2945 +0x33d7 +0x2651 +0x3b86 +0x0c6c +0x24d4 +0x4441 +0x4e42 +0x50d8 +0x1afb +0x6bd4 +0x3cb0 OP_AdventureInfoRequest +0x4c54 OP_AdventureInfo +0x7171 OP_AdventureData +0x35e8 +0x7d49 +0x1848 +0x2599 +0x0dab +0x6493 +0x34f2 +0x7d40 +0x0e00 +0x1cf3 +0x71f4 +0x5d18 OP_LeaveAdventure +0x4e25 +0x50c2 +0x400f OP_AdventureFinish +0x6368 +0x6192 +0x3aa4 +0x502e OP_Marquee +0x1b01 OP_AdventureUpdate +0x0f24 +0x1015 +0x23a6 +0x5a74 +0x037a +0x7a45 OP_ConsentDeny +0x71bc +0x2382 OP_DenyResponse +0x02a0 +0x1126 OP_VetClaimRequest +0x0668 +0x16d4 OP_VetClaimReply +0x5cea OP_FindPersonRequest +0x0cc3 +0x7e58 OP_FindPersonReply +0x9be3 OP_PickLock +0x0438 +0x3d5c OP_LDoNOpen +0x15e7 +0x368e OP_ItemPacket +0x7331 +0x4936 +0x2c4e +0x78bf OP_DisarmTraps +0x02af OP_SenseTraps +0x65c3 OP_AdventurePointsUpdate +0x0dcb +0x661b OP_AugmentItem +0x5f68 +0x5278 +0x6b53 +0x5dd1 +0x559a OP_WeaponEquip2 +0x2d25 OP_WeaponUnequip2 +0x23c1 OP_WorldClientReady +0x5a62 OP_AdventureStatsRequest +0x7093 OP_AdventureLeaderboardRequest +0x2370 OP_AdventureStatsReply +0x7f79 OP_AdventureLeaderboardReply +0x4eb3 +0x3377 OP_BuffCreate +0x5882 OP_PetBuffWindow +0x4f4b OP_TargetBuffs +0x5961 OP_TributeUpdate +0x4f3e OP_TributeItem +0x5300 OP_TributePointUpdate +0x729b OP_SendTributes +0x4254 OP_TributeInfo +0x79fc OP_SelectTribute +0x073d OP_TributeTimer +0x08bf +0x7697 +0x4b65 +0x51ae +0x51a9 +0x7666 OP_OpenTributeMaster +0x4290 +0x759e OP_DisciplineUpdate +0x01c6 +0x6989 OP_DisciplineTimer +0x58fb OP_TributeMoney +0x7422 +0x0d25 +0x4de1 +0x46d0 +0x4f50 +0x2ddc +0x7441 +0x6a12 +0x29a8 +0x3f7f +0x150b +0x11e3 +0x1ad3 + +0x59ca OP_DzAddPlayer +0x4701 OP_DzRemovePlayer +0x1abc OP_DzSwapPlayer +0x405b OP_DzMakeLeader +0x543d OP_DzPlayerList +0x14c6 OP_DzJoinExpeditionConfirm +0x7f4b OP_DzJoinExpeditionReply +0x1950 +0x64b5 +0x0398 OP_DzListTimers +0x7b68 +0x4f7e OP_DzExpeditionInfo +0x9119 OP_DzExpeditionList +0x205f OP_DzQuit +0xb2e3 OP_DzMemberStatus +0x32f0 OP_DzLeaderStatus +0x3de9 OP_DzMemberList +0x5ae4 +0x4d6e OP_OnLevelMessage +0x4fd0 +0x575b +0x7e94 OP_DzExpeditionEndsWarning +0x5189 +0x383c +0x791e OP_BankerChange +0x5c74 +0x71b1 OP_RecipesFavorite +0x20ab +0x025f +0x214a +0x08a6 OP_PopupResponse +0x15a9 OP_ItemRecastDelay +0x3707 OP_PVPLeaderBoardDetailsRequest +0x04aa OP_PVPLeaderBoardRequest +0x25b7 OP_PVPLeaderBoardDetailsReply +0x071f OP_PVPLeaderBoardReply +0x2dee +0x4e62 +0x0c91 +0x18d3 +0x6f4b OP_Weblink +0x4b15 OP_PVPStats +0x6755 +0x5c32 +0x5770 OP_PlayMP3 +0x7425 +0x5eed +0x574e +0x11b4 +0x4ed6 +0x0d9f +0x7d23 +0x3fb0 OP_ClearSurname +0xc693 +0x7b1e OP_RemoveNimbusEffect +0x20ae +0x0727 +0x3771 +0x7fe0 +0x4d5e +0x1877 OP_SendGuildTributes +0x649f +0x5f3f +0x5bcb +0x43d2 +0x49ea +0x378d OP_OpenGuildTributeMaster +0x7f8e +0x02bc +0x7dd2 +0x7c1d +0x7a41 +0x7db5 +0x7eec OP_SetChatServer2 +0x0904 OP_CorpseDrag +0x7037 OP_CorpseDrop +0x5e19 OP_TaskActivityComplete +0x4e32 +0x241d OP_TributeToggle +0x756a +0x7745 +0x039d +0x0f50 OP_ClearAA +0x66b5 OP_SendAATable +0x0afb OP_AugmentInfo +0x10f6 +0x1013 + +0x6344 OP_RequestTitles +0x2d08 OP_SendTitleList +0x3719 +0x7a48 +0x0a23 OP_AcceptNewTask +0x705b +0x3bc9 OP_LevelAppearance +0x60ef +0x1619 +0x17fd OP_VoiceMacroIn +0x409a OP_VoiceMacroOut +0x4493 OP_WorldComplete +0x6527 OP_SetTitle +0x4c21 OP_SetTitleReply +0x127f OP_CameraEffect +0x0d32 OP_NewTitlesAvailable +0x34a7 OP_WeaponEquip1 +0x34cd +0x5936 OP_SpellEffect +0x241e OP_AutoFire +0x66f0 OP_UpdateAA +0x100e OP_CustomTitles +0x6b65 +0x12f5 +0x7677 OP_Bandolier +0x688f +0x7adf +0x0ed4 +0x243a OP_Barter +0x1a6a +0x5623 +0x43c8 OP_SendAAStats +0x655e +0x1a3e OP_PotionBelt +0x6326 OP_SetStartCity +0x7485 +0x5416 +0x3282 +0x3752 +0x425b +0x27c8 +0x2b19 +0x70ce +0x3165 +0x786b +0x0f26 +0x3500 +0x3d04 +0x5134 OP_GuildBank +0x0521 +0x7850 +0x108b +0x5671 +0x6d2b +0x732f +0x748f OP_GuildManageBanker +0x6858 +0x5e74 +0x3f35 +0x35e9 +0x2056 +0x6922 OP_AdventureMerchantRequest +0x5b72 OP_AdventureMerchantPurchase +0x2f9b OP_AdventureMerchantSell +0x3e47 OP_AdventureMerchantResponse +0x0b7d OP_DzChooseZone +0x2818 +0x35bd +0x51df +0x1ff7 +0x3926 +0x6265 +0x4ab0 +0x5e6c +0x1350 +0x6288 +0x7348 +0x48a2 OP_OpenNewTasksWindow +0x3010 +0x45db +0x36e8 OP_AvaliableTask +0x4865 +0x322e +0x7582 +0x5727 OP_TaskMemberList +0x6646 +0x37f2 +0x3444 +0x5ffc +0x5cb5 +0x0119 +0x35b5 +0x6cc6 +0x4926 +0x1b1d +0x7299 +0x0bf1 +0x08b4 +0x7f7a +0x3dab +0x1e7d +0x610a +0x04c8 +0x4811 +0x609e +0x65f0 +0x467f OP_CrystalCountUpdate +0x7aee OP_CrystalCreate +0x2439 OP_CrystalReclaim +0x39c1 +0x555e +0x7c9c +0x2c94 +0x2fc2 +0x2067 +0x059e +0x7f74 +0x68b2 +0x6f2b +0x01d6 +0x5182 +0x1da2 +0x5147 +0x51f8 +0x11f3 +0x0d07 +0x272f +0x413f +0x5968 +0x3e0e OP_DzCompass +0x282a +0x035f OP_GMNameChange +0x4013 +0x0e2f +0x099e +0x4eba OP_CompletedTasks +0x5f1c OP_TaskHistoryRequest +0x3d05 OP_TaskHistoryReply +0x2b8e +0x66d6 +0x0143 +0x6a5d +0x6e61 +0x2b0f +0x46c6 OP_FloatListThing +0x3a8d +0x15e5 +0x7d89 +0x4085 +0x1507 +0x5d93 +0x1669 OP_ResetAA +0x4664 +0x312d +0x2215 +0x1745 OP_Rewind +0x0cf1 +0x6567 +0x4405 +0x72d8 +0xaaba +0x27f8 OP_AssistGroup +0x7cfb +0x1a32 +0x14fd +0x77bb +0x36d1 +0x6193 +0x184c +0x3c47 +0x4e0b +0x7c15 +0x2ec3 OP_ShroudSelectionWindow +0x2b37 OP_ShroudRequestStats +0x6c04 OP_ShroudRespondStats +0x1cd0 OP_ShroudSelect +0x79da OP_ShroudSelectCancel +0x7806 +0x541d OP_ShroudProgress +0x3823 OP_ShroudProgress2 +0x6562 OP_Shroud +0x4b25 +0x2507 +0x3acc +0x006e +0x06e +0x0728 +0x66cd +0x3c54 +0x2e8d +0x4eea +0x5a67 +0x3d20 +0x649c +0x21a6 +0x28bc OP_RespawnWindow +0x0ecb OP_ZonePlayerToBind +0x08d8 +0x7b71 +0x1115 +0x18cb +0x34f4 +0x5f08 +0x5bd2 +0x5052 +0x5e69 +0x2ccc +0x655c +0x6773 OP_CharacterCreateRequest +0x590e OP_VetRewardsAvaliable +0x6b0b +0x555a +0x7786 +0x67e8 OP_ShroudRemove +0x6381 +0x5628 +0xb52f +0x6084 +0x2958 OP_GuildUpdateURLAndChannel +0x2301 OP_WorldUnknown001 +0x610b +0x6f8b +0x4d25 OP_InspectMessageUpdate +0x3033 OP_BlockedBuffs +0x0de7 OP_RemoveBlockedBuffs +0x30e5 +0x618c +0x58e6 +0x1456 OP_ShroudUnknown1 +0x053c OP_Untargetable +0x71da +0x333f +0x49bc +0x64f2 OP_BuffRemoveRequest +0x6b3d +0x34cb OP_ClearBlockedBuffs +0x5646 +0x7d13 +0x15e0 +0x5710 +0x172b +0x1888 +0x2956 +0x6a68 +0x7631 +0x298e +0x003c +0x03c +0x0b0f +0x5a72 +0x0767 +0x2f1a +0x6c7a +0x1660 +0x344f +0x028b +0x6eea +0x7707 +0x3fb2 +0x289e +0x3342 OP_GroupMentor +0x5892 OP_NPCMoveUpdate +0x189c OP_ItemVerifyRequest +0x097b OP_ItemVerifyReply +0x2115 +0x6411 +0x6471 +0x134a +0x1304 +0x5a79 OP_ShieldGroup +0x2dde +0x7d50 +0x1d47 +0x10ec +0x000f OP_RestState +0x00f +0x0f +0x465b OP_ItemViewUnknown +0x2289 +0x023b +0x4223 +0x7261 +0x2af9 +0x19aa +0x66dd +0x4b64 OP_GMTrainSkillConfirm +0x319e +0x1af3 +0x449c +0x8582 +0x4b8d #OP_LoginUnknown1 +0x298d #OP_LoginUnknown2 +0x06c8 +0x4f93 +0x412d +0x001f +0x01f +0x60f6 +0x1a9e +0x798e +0x17b7 +0x3042 +0x61bd +0x1f6e +0x65a6 +0x740d +0x48da +0x20d9 +0x5258 +0x1b5d +0x49f4 +0x7aa9 +0xb350 +0x6e2a +0x5d4e +0x6e4d +0x4ffc +0x1d15 +0x6f23 +0x2296 +0x765b +0x2e01 +0x26dd +0x72d3 +0x6981 +0x3b30 +0x14ac +0x0d92 +0x0001 +0x001 +0x01 +0x09bb +0x9e18 +0x0d9d +0x7f2b +0x3651 +0x645d +0x3af2 +0x4377 +0x39c9 +0x4924 +0x1e50 +0x4683 +0x0276 +0x6dec +0x56c9 +0x3ee6 +0x7121 +0x62ab +0x5d88 +0x05f0 +0x6b6d OP_AltCurrency +0x61cb +0x0165 +0x74ec OP_MercenaryAssign +0x5409 OP_AltCurrencyMerchantRequest +0x3788 OP_AltCurrencyPurchase +0x40b6 OP_AltCurrencySell +0x27a2 OP_AltCurrencyMerchantReply +0x532a OP_AltCurrencySellSelection +0x3899 +0x7567 +0x4820 +0x0339 OP_AltCurrencyReclaim +0x0c12 +0x074d +0x47ba +0x55c8 +0x4c89 +0x18b7 +0x2950 +0x44cb +0x4477 +0x6146 +0x40cf +0x2405 +0x49e2 +0x2aff +0x0bfa +0x26c0 +0x7d39 +0x259f +0x086b +0x6dc1 +0x6f80 +0x042e +0x2ad4 +0x317b +0x73ac +0x18d7 +0x5b8b +0x5c83 +0x1f51 +0x62f7 +0x1c46 +0x2a44 +0x3e7a +0x4374 +0x3b23 +0x1df4 +0x3ed8 +0x4b50 +0x36eb +0x65c7 +0x5620 +0x587e +0x3897 +0x7e62 +0x67ae +0x74f4 +0x4613 OP_SendFindableNPCs +0x2a92 +0x6d6e +0x2c01 +0x1243 +0x133e +0x67fc + +0x49e1 OP_HideCorpse +0x0e44 +0x239a +0x1a0a +0x398f +0x1ff4 +0x88a1 +0x74da OP_GroupDisbandOther +0x21b4 OP_GroupLeaderChange +0x62b7 +0x4ced +0x3abb OP_GroupUpdate +0x0f6c OP_GroupDelete +0x0cbc +0x6194 OP_GroupUpdateB +0x7fe6 +0x04d0 +0x7323 OP_GroupAcknowledge +0x1ae5 OP_GroupDisbandYou +0x4d9f +0x70e2 OP_GroupRoles +0x6875 +0x6298 +0x02cf OP_GroupLeadershipAAUpdate +0x22b8 OP_MercenarySuspend2 +0x7bff +0x5512 +0x2b57 +0x1380 +0x2bcb +0x7b89 OP_MercenaryDataUpdateRequest +0x61a4 OP_MercenaryDataUpdate +0x11c1 OP_MercenaryDataRequest +0x72ce OP_MercenaryDataResponse +0x7169 OP_MercenaryHire +0x6e83 OP_MercenaryDismiss +0x31e4 OP_MercenaryTimerRequest +0x0763 OP_MercenaryTimer +0x78f6 +0x1b37 +0x27f2 OP_MercenaryCommand +0x5df8 +0x4333 +0x69ca +0x6e9f +0x4407 OP_MercenarySuspendRequest +0x6f03 OP_MercenarySuspendResponse +0x27a0 OP_MercenaryUnsuspendResponse +0x5f88 +0x2749 +0x038f +0x0e52 +0x20b9 +0x5d26 OP_MercenaryUnknown1 +0x69e7 +0x66b9 +0x0b72 +0x7e6f +0x29ec +0x6248 +0x702b +0x2b4f +0x6e6d +0x1e9f +0x5bd5 +0x4b7f +0x1490 +0x075e +0x4263 +0x1eba +0x4a74 +0x0a37 +0x3289 +0x3171 +0x0114 +0x5148 +0x76c3 +0x09bf +0x356f +0x77a7 +0x479a +0x209f +0x54e6 +0x6c3e +0xee80 +0x40e5 +0x76d9 OP_GuildCreate +0x1dc8 +0x794a +0x35c5 +0x137d +0x004a +0x04a +0x29b4 +0x18f1 +0x17fc +0x4707 OP_ChangeSize +0x3e15 +0x7248 +0x57c6 +0x7679 +0x6c8b +0x14c3 +0x3a02 +0x7900 +0x5688 +0x3a58 +0x75dd +0x39e1 +0x47cb +0x171e +0xdab0 +0x618f +0x27b1 +0x3d0c +0x0d2a +0x8c30 +0x2b42 +0x17f8 +0x1665 +0x059d +0x72c9 +0x675d +0x28e0 +0x61df +0x3ef8 +0x4d59 +0x3763 +0x672f OP_XTargetResponse +0x45be OP_XTargetRequest +0x792c OP_XTargetAutoAddHaters +0x66bf +0x66df +0x2aa7 +0x76c6 +0x6032 +0x3e00 +0x0c13 +0x0a59 +0x393a +0x45ed +0x507f +0x68ba +0x5a63 +0x6fd0 +0x63fd +0x4f09 +0x485d +0x3968 +0x69e1 +0x3d94 +0x0351 +0x5f0a +0x36be +0x59f9 +0x7075 +0x6ee6 +0x2691 +0x3c8b +0x01df +0x218c +0x233b +0x2cf7 +0x1097 +0x1baf +0x6f35 +0x1228 +0x1cef +0x7d28 +0x087f +0x1967 +0x6917 +0x613d +0x37d9 +0x58c7 +0x21ec +0x3424 +0x2036 +0x7ad1 +0x01c3 +0x626e +0x711a +0x5b41 +0x21ba +0x2933 +0x050c +0x51e3 +0x64a3 +0x3146 +0x2aa6 +0x16df +0x2698 +0x21ea +0x796c +0x7bb1 +0x6af6 +0x499a +0x3c44 +0x3cbc +0x6561 +0x12f7 +0x6292 +0x3de0 +0x1409 +0x4604 +0x0ca1 +0x754e +0x4f2b +0x6995 +0x3745 +0x789b +0xcadf +0x4abe +0x6014 +0x7fff +0x6228 +0x10e0 +0x7452 +0x6d9f +0x7f80 +0xb07f +0x6b5c OP_ItemPreview +0x02b4 +0x3bd3 +0x3036 +0x5c3f +0x433d +0x78e2 +0x543f +0x58b4 +0x2563 +0x1820 +0x40be +0x62d6 +0x0d68 +0x6d10 +0x3a32 +0x2fed +0x1303 +0x49df +0x3e24 +0x2b35 +0x0910 +0x3849 +0x6873 +0x15e2 +0x2d85 +0x39bb +0x42e9 +0x6860 +0x15a8 +0x52b5 +0x3311 +0x58df +0x2a7f +0x6573 +0x7a4d +0x7497 +0x1fcc +0x7c23 +0x2d28 +0x5dab +0x005a +0x05a +0x4506 +0x046d +0x36db +0x5a40 +0x4cd9 +0x63d7 +0x48d4 +0x035d +0x11f5 +0x7b84 +0x4f05 +0x7369 +0x7b32 +0x4fe6 +0x6cd0 +0x6770 +0x5c24 +0x063a +0x0d93 +0x4c2a +0x2235 +0x7b95 +0x6a1f +0x46f0 +0x2de2 +0xadd7 +0x2cc6 +0x7db7 +0x7588 +0x4957 +0x6a98 + +0x057b OP_SendMembershipDetails +0x7acc OP_SendMembership +0x431f +0x42c4 +0x05a8 +0x5475 OP_SendMaxCharacters +0x4ad2 +0x03d9 +0x771e +0x2a34 +0x7273 +0x1c9e +0x5f17 +0x37a9 +0x6530 +0x3157 +0x1f5e +0x2bc8 +0x593a +0x1643 +0x16bc +0x1781 +0x53d3 +0x5369 +0x25b3 +0x2fa0 +0x73a9 +0x1595 +0x6b6f +0x65f2 +0x3562 +0x309d +0x4efa +0x1da9 +0x6678 +0x16e8 \ No newline at end of file diff --git a/utils/scripts/opcode_scripts/oplist_to_conf.pl b/utils/scripts/opcode_scripts/oplist_to_conf.pl new file mode 100644 index 000000000..0a3088dd6 --- /dev/null +++ b/utils/scripts/opcode_scripts/oplist_to_conf.pl @@ -0,0 +1,89 @@ +#!/usr/bin/perl + +# File Name: oplist_to_conf.pl +# Converts the Opcode List with Opcode Names from the Spreadsheet into a Patch File. + +# Directions to use this script: +# 1. Copy the opcodes and opcode names columns from the opcode spreadsheet +# for the columns you want to create a new .conf file from into the file. +# 2. Remove the header row entries in the text file. +# 3. Find/Replace all Tabs " " with 2 spaces " " and save the file. +# 4. Paste the contents of the current patch file in the patch_OLD.conf file. +# 5. Run this script using "perl oplist_to_conf.pl" +# 6. This creates a new .conf file named patch_NEW.conf +# 7. Rename patch_NEW.conf to the desired name and you are all done + + +$stopmessage = "Failed to open file"; +# Open the text file that contains the opcode and opcode name rows for a single client from the opcode list spreadsheet +open OpcodeFile, "<", "opcodelist.txt" or die $stopmessage; +# Open the .conf file to copy from +open PatchFile, "<", "patch_OLD.conf" or die $stopmessage; + +# Read these files into arrays for looping and close the files +my @OpcodeList = ; +my @PatchFile = ; +close(OpcodeFile); +close(PatchFile); + +# Open the new/destination .conf file and clear out file contents +open OpcodeResultFile, ">", "patch_NEW.conf" or die $stopmessage; +print OpcodeResultFile ""; +# Close out the newly cleared .conf file +close(OpcodeResultFile); + +# Open the new/destination .conf file again for appending +open OpcodeResultFile, ">>", "patch_NEW.conf" or die $stopmessage; + +my %PatchHash = (); + +foreach $line (@OpcodeList) +{ + @equalssplit = split(/ /, $line); + $ArraySize = @equalssplit; + if ($ArraySize > 1) + { + my $CurOpcode = ""; + my $CurOpcodeName = ""; + @OpcodeArray = split(//, $equalssplit[0]); + if ($equalssplit[1] =~ /^OP_(.*)/i) + { + $CurOpcodeName = "OP_".$1; + } + foreach $Letter (@OpcodeArray) + { + if ($Letter =~ /[A-Za-z0-9]/) + { + $CurOpcode .= $Letter; + } + } + if ($CurOpcode && $CurOpcodeName) + { + $CurOpcode = lc($CurOpcode); + $PatchHash{ $CurOpcodeName } = $CurOpcode; + #print $CurOpcodeName."=". $CurOpcode."\n"; + } + } +} + +$TabSpace = " "; # Tab +foreach $line (@PatchFile) +{ + $CurLine = $line; + if ($line =~ /^OP_([^\=]+)=([^\s]+)(.*)/i) + { + $NewOpcode = "0x0000"; + $OpcodeName = "OP_".$1; + + if ($PatchHash{$OpcodeName}) + { + $NewOpcode = $PatchHash{$OpcodeName}; + } + + $CurLine = $OpcodeName."=".$NewOpcode.$3."\n"; + } + print OpcodeResultFile $CurLine; +} + + +close(OpcodeResultFile); diff --git a/utils/scripts/opcode_scripts/patch_NEW.conf b/utils/scripts/opcode_scripts/patch_NEW.conf new file mode 100644 index 000000000..29bc320d9 --- /dev/null +++ b/utils/scripts/opcode_scripts/patch_NEW.conf @@ -0,0 +1,660 @@ +# ShowEQ Import Notes: +# ZERO THE FILE first +# perl -pi -e 's/0x[0-9a-fA-F]{4}/0x0000/g' opcodes.conf +# Unknown Mapping: +# OP_Action2 -> OP_Damage +# OP_EnvDamage -> OP_Damage ---> might have been a one time mistake +# Name Differences: +# OP_CancelInvite -> OP_GroupCancelInvite +# OP_GMFind -> OP_FindPersonRequest +# OP_CommonMessage -> OP_ChannelMessage + +OP_Unknown=0x0000 +OP_ExploreUnknown=0x0000 # used for unknown explorer + +# world packets +# Required to reach Char Select: +OP_SendLoginInfo=0x7a09 +OP_ApproveWorld=0x7499 +OP_LogServer=0x7ceb +OP_SendCharInfo=0x00d2 +OP_ExpansionInfo=0x590d +OP_GuildsList=0x0000 +OP_EnterWorld=0x578f +OP_PostEnterWorld=0x6259 +OP_World_Client_CRC1=0x12cc +OP_World_Client_CRC2=0x0f13 +OP_SendSpellChecksum=0x0000 +OP_SendSkillCapsChecksum=0x0000 + +# Character Select Related: +OP_SendMaxCharacters=0x5475 +OP_SendMembership=0x7acc +OP_SendMembershipDetails=0x057b +OP_CharacterCreateRequest=0x6773 +OP_CharacterCreate=0x6bbf +OP_DeleteCharacter=0x1808 +OP_RandomNameGenerator=0x5954 +OP_ApproveName=0x56a2 +OP_MOTD=0x0c22 +OP_SetChatServer=0x1bc5 +OP_SetChatServer2=0x7eec +OP_ZoneServerInfo=0x4c44 +OP_WorldComplete=0x4493 +OP_WorldUnknown001=0x2301 +OP_FloatListThing=0x46c6 + +# Reasons for Disconnect: +OP_ZoneUnavail=0x4cb4 +OP_WorldClientReady=0x23c1 +OP_CharacterStillInZone=0x0000 +OP_WorldChecksumFailure=0x0000 +OP_WorldLoginFailed=0x0000 +OP_WorldLogout=0x0000 +OP_WorldLevelTooHigh=0x0000 +OP_CharInacessable=0x0000 +OP_UserCompInfo=0x0000 +OP_SendExeChecksum=0x0000 +OP_SendBaseDataChecksum=0x0000 + +# Zone in opcodes +OP_AckPacket=0x471d +OP_ZoneEntry=0x5089 +OP_ReqNewZone=0x7887 +OP_NewZone=0x1795 +OP_ZoneSpawns=0x5237 +OP_PlayerProfile=0x6506 +OP_TimeOfDay=0x5070 +OP_LevelUpdate=0x1eec +OP_Stamina=0x2a79 +OP_RequestClientZoneChange=0x3fcf +OP_ZoneChange=0x2d18 +OP_LockoutTimerInfo=0x0000 +OP_ZoneServerReady=0x0000 +OP_ZoneInUnknown=0x0000 +OP_LogoutReply=0x0000 +OP_PreLogoutReply=0x0000 + +# Required to fully log in +OP_SpawnAppearance=0x0971 +OP_ChangeSize=0x4707 +OP_TributeUpdate=0x5961 +OP_TributeTimer=0x073d +OP_SendTributes=0x729b +OP_SendGuildTributes=0x1877 +OP_TributeInfo=0x4254 +OP_Weather=0x661e +OP_ReqClientSpawn=0x35fa +OP_SpawnDoor=0x7291 +OP_GroundSpawn=0x6fca +OP_SendZonepoints=0x69a4 +OP_BlockedBuffs=0x3033 +OP_RemoveBlockedBuffs=0x0de7 +OP_ClearBlockedBuffs=0x34cb +OP_WorldObjectsSent=0x5ae2 +OP_SendExpZonein=0x5f8e +OP_SendAATable=0x66b5 +OP_RespondAA=0x7a27 +OP_UpdateAA=0x66f0 +OP_SendAAStats=0x43c8 +OP_AAExpUpdate=0x7d14 +OP_ExpUpdate=0x20ed +OP_HPUpdate=0x2828 +OP_ManaChange=0x5467 +OP_TGB=0x0876 +OP_SpecialMesg=0x0083 +OP_GuildMemberList=0x12a6 +OP_GuildMOTD=0x3e13 +OP_CharInventory=0x5ca6 +OP_WearChange=0x7994 +OP_ClientUpdate=0x7dfc +OP_ClientReady=0x345d +OP_SetServerFilter=0x444d + +# Guild Opcodes - Disabled until crashes are resolved in RoF +OP_GetGuildMOTD=0x36e0 +OP_GetGuildMOTDReply=0x4f1f +OP_GuildMemberUpdate=0x69b9 +OP_GuildInvite=0x7099 +OP_GuildRemove=0x1444 +OP_GuildPeace=0x67e3 +OP_SetGuildMOTD=0x0b0b +OP_GuildList=0x6279 +OP_GuildWar=0x1ffb +OP_GuildLeader=0x7e09 +OP_GuildDelete=0x3708 +OP_GuildInviteAccept=0x7053 +OP_GuildDemote=0x2d4e +OP_GuildPromote=0x0000 +OP_GuildPublicNote=0x5053 +OP_GuildManageBanker=0x748f +OP_GuildBank=0x5134 +OP_SetGuildRank=0x0b9c +OP_GuildUpdateURLAndChannel=0x2958 +OP_GuildStatus=0x7326 +OP_GuildCreate=0x76d9 +OP_GuildMemberLevelUpdate=0x0000 # Unused? +OP_ZoneGuildList=0x0000 # Unused? +OP_GetGuildsList=0x0000 # Unused? +OP_LFGuild=0x0000 +OP_GuildManageRemove=0x0000 +OP_GuildManageAdd=0x0000 +OP_GuildManageStatus=0x0000 + +# GM/Guide Opcodes +OP_GMServers=0x08c1 +OP_GMBecomeNPC=0x3ae1 +OP_GMZoneRequest=0x62ac +OP_GMZoneRequest2=0x7e1a +OP_GMGoto=0x7d8e +OP_GMSearchCorpse=0x357c +OP_GMHideMe=0x79c5 +OP_GMDelCorpse=0x607e +OP_GMApproval=0x6db5 +OP_GMToggle=0x2097 +OP_GMSummon=0x486f +OP_GMEmoteZone=0x1cfd +OP_GMEmoteWorld=0x458e +OP_GMFind=0x4a8f +OP_GMKick=0x26a7 +OP_GMKill=0x51d3 +OP_GMNameChange=0x035f +OP_GMLastName=0x46ce + +# Misc Opcodes +OP_InspectRequest=0x57bc +OP_InspectAnswer=0x71ac +OP_InspectMessageUpdate=0x4d25 +OP_BeginCast=0x318f +OP_ColoredText=0x43af +OP_ConsentResponse=0x384a +OP_MemorizeSpell=0x217c +OP_SwapSpell=0x0efa +OP_CastSpell=0x1287 +OP_Consider=0x742b +OP_FormattedMessage=0x1024 +OP_SimpleMessage=0x213f +OP_Buff=0x659c +OP_Illusion=0x312a +OP_MoneyOnCorpse=0x5f44 +OP_RandomReply=0x106b +OP_DenyResponse=0x2382 +OP_SkillUpdate=0x04c +OP_GMTrainSkillConfirm=0x4b64 +OP_RandomReq=0x7b10 +OP_Death=0x6517 +OP_GMTraining=0x1966 +OP_GMEndTraining=0x4d6b +OP_GMTrainSkill=0x2a85 +OP_Animation=0x7177 +OP_Begging=0x6703 +OP_Consent=0x1fd1 +OP_ConsentDeny=0x7a45 +OP_AutoFire=0x241e +OP_PetCommands=0x0159 +OP_DeleteSpell=0x52e5 +OP_Surname=0x0423 +OP_ClearSurname=0x3fb0 +OP_FaceChange=0x5578 +OP_SenseHeading=0x260a +OP_Action=0x744c +OP_ConsiderCorpse=0x5204 +OP_HideCorpse=0x49e1 +OP_CorpseDrag=0x0904 +OP_CorpseDrop=0x7037 +OP_Bug=0x73f4 +OP_Feedback=0x5602 +OP_Report=0x1414 +OP_Damage=0x6f15 +OP_ChannelMessage=0x2b2d +OP_Assist=0x4478 +OP_AssistGroup=0x27f8 +OP_MoveCoin=0x0bcf +OP_ZonePlayerToBind=0x0ecb +OP_KeyRing=0x6857 +OP_WhoAllRequest=0x674b +OP_WhoAllResponse=0x578c +OP_FriendsWho=0x3956 +OP_ConfirmDelete=0x43a3 +OP_Logout=0x4ac6 +OP_Rewind=0x1745 +OP_TargetCommand=0x58e2 +OP_Hide=0x67fe +OP_Jump=0x31f4 +OP_Camp=0x28ec +OP_Emote=0x373b +OP_SetRunMode=0x009f +OP_BankerChange=0x791e +OP_TargetMouse=0x075d +OP_MobHealth=0x37b1 +OP_InitialMobHealth=0x0000 # Unused? +OP_TargetHoTT=0x0272 +OP_XTargetResponse=0x672f +OP_XTargetRequest=0x45be +OP_XTargetAutoAddHaters=0x792c +OP_TargetBuffs=0x4f4b +OP_BuffCreate=0x3377 +OP_BuffRemoveRequest=0x64f2 +OP_DeleteSpawn=0x7280 +OP_AutoAttack=0x109d +OP_AutoAttack2=0x3526 +OP_Consume=0x4b70 +OP_MoveItem=0x32ee +OP_DeleteItem=0x18ad +OP_DeleteCharge=0x01b8 +OP_ItemPacket=0x368e +OP_ItemLinkResponse=0x70c0 +OP_ItemLinkClick=0x4cef +OP_ItemPreview=0x6b5c +OP_NewSpawn=0x6097 +OP_Track=0x17e5 +OP_TrackTarget=0x0029 +OP_TrackUnknown=0x4577 +OP_ClickDoor=0x3a8f +OP_MoveDoor=0x08e8 +OP_RemoveAllDoors=0x700c +OP_EnvDamage=0x51fd +OP_BoardBoat=0x4211 +OP_Forage=0x5306 +OP_LeaveBoat=0x7617 +OP_ControlBoat=0x0ae7 +OP_SafeFallSuccess=0x2219 +OP_RezzComplete=0x760d +OP_RezzRequest=0x3c21 +OP_RezzAnswer=0x701c +OP_Shielding=0x48c1 +OP_RequestDuel=0x3af1 +OP_MobRename=0x2c57 +OP_AugmentItem=0x661b +OP_WeaponEquip1=0x34a7 +OP_WeaponEquip2=0x559a +OP_WeaponUnequip2=0x2d25 +OP_ApplyPoison=0x31e6 +OP_Save=0x4a39 +OP_TestBuff=0x7cb8 +OP_CustomTitles=0x100e +OP_Split=0x3a54 +OP_YellForHelp=0x4e56 +OP_LoadSpellSet=0x261d +OP_Bandolier=0x7677 +OP_PotionBelt=0x1a3e +OP_DuelResponse=0x6a46 +OP_DuelResponse2=0x68d3 +OP_SaveOnZoneReq=0x600d +OP_ReadBook=0x72df +OP_Dye=0x23b9 +OP_InterruptCast=0x048c +OP_AAAction=0x424e +OP_LeadershipExpToggle=0x6c55 +OP_LeadershipExpUpdate=0x2797 +OP_PurchaseLeadershipAA=0x0026 +OP_UpdateLeadershipAA=0x026 +OP_MarkNPC=0x5a58 +OP_MarkRaidNPC=0x74bd #unimplemented +OP_ClearNPCMarks=0x2003 +OP_ClearRaidNPCMarks=0x20d3 #unimplemented +OP_DelegateAbility=0x76b8 +OP_SetGroupTarget=0x2814 +OP_Charm=0x5d92 +OP_Stun=0x36a4 +OP_SendFindableNPCs=0x4613 +OP_FindPersonRequest=0x5cea +OP_FindPersonReply=0x7e58 +OP_Sound=0x1a30 +OP_PetBuffWindow=0x5882 +OP_LevelAppearance=0x3bc9 +OP_Translocate=0x6580 +OP_Sacrifice=0x1821 +OP_PopupResponse=0x08a6 +OP_OnLevelMessage=0x4d6e +OP_AugmentInfo=0x0afb +OP_Petition=0x1901 +OP_SomeItemPacketMaybe=0x747c +OP_PVPStats=0x4b15 +OP_PVPLeaderBoardRequest=0x04aa +OP_PVPLeaderBoardReply=0x071f +OP_PVPLeaderBoardDetailsRequest=0x3707 +OP_PVPLeaderBoardDetailsReply=0x25b7 +OP_RestState=0x000f +OP_RespawnWindow=0x28bc +OP_LDoNButton=0x5327 +OP_SetStartCity=0x6326 +OP_VoiceMacroIn=0x17fd +OP_VoiceMacroOut=0x409a +OP_ItemViewUnknown=0x465b +OP_VetRewardsAvaliable=0x590e +OP_VetClaimRequest=0x1126 +OP_VetClaimReply=0x16d4 +OP_DisciplineUpdate=0x759e +OP_DisciplineTimer=0x6989 +OP_BecomeCorpse=0x0000 # Unused? +OP_Action2=0x0000 # Unused? +OP_MobUpdate=0x2c84 +OP_NPCMoveUpdate=0x5892 +OP_CameraEffect=0x127f +OP_SpellEffect=0x5936 +OP_RemoveNimbusEffect=0x7b1e +OP_AltCurrency=0x6b6d +OP_AltCurrencyMerchantRequest=0x5409 +OP_AltCurrencyMerchantReply=0x27a2 +OP_AltCurrencyPurchase=0x3788 +OP_AltCurrencySell=0x40b6 +OP_AltCurrencySellSelection=0x532a +OP_AltCurrencyReclaim=0x0339 +OP_CrystalCountUpdate=0x467f +OP_CrystalCreate=0x7aee +OP_CrystalReclaim=0x2439 +OP_Untargetable=0x053c +OP_IncreaseStats=0x70a3 +OP_Weblink=0x6f4b +OP_OpenContainer=0x0000 +OP_Marquee=0x502e +OP_ItemRecastDelay=0x15a9 +#OP_OpenInventory=0x0000 # Likely does not exist in RoF -U + +OP_DzQuit=0x205f +OP_DzListTimers=0x0398 +OP_DzAddPlayer=0x59ca +OP_DzRemovePlayer=0x4701 +OP_DzSwapPlayer=0x1abc +OP_DzMakeLeader=0x405b +OP_DzPlayerList=0x543d +OP_DzJoinExpeditionConfirm=0x14c6 +OP_DzJoinExpeditionReply=0x7f4b +OP_DzExpeditionInfo=0x4f7e +OP_DzExpeditionList=0x9119 +OP_DzMemberStatus=0xb2e3 +OP_DzLeaderStatus=0x32f0 +OP_DzExpeditionEndsWarning=0x7e94 +OP_DzMemberList=0x3de9 +OP_DzCompass=0x3e0e +OP_DzChooseZone=0x0b7d + +# New Opcodes +OP_SpawnPositionUpdate=0x0000 # Actually OP_MobUpdate ? +OP_ManaUpdate=0x3791 +OP_EnduranceUpdate=0x5f42 +OP_MobManaUpdate=0x2404 +OP_MobEnduranceUpdate=0x1c81 + +# Mercenary Opcodes +OP_MercenaryDataUpdateRequest=0x7b89 +OP_MercenaryDataUpdate=0x61a4 +OP_MercenaryDataRequest=0x11c1 +OP_MercenaryDataResponse=0x72ce +OP_MercenaryHire=0x7169 +OP_MercenaryDismiss=0x6e83 +OP_MercenaryTimerRequest=0x31e4 +OP_MercenaryTimer=0x0763 +OP_MercenaryUnknown1=0x5d26 +OP_MercenaryCommand=0x27f2 +OP_MercenarySuspendRequest=0x4407 +OP_MercenarySuspendResponse=0x6f03 +OP_MercenaryUnsuspendResponse=0x27a0 + +# Looting +OP_LootRequest=0x0adf +OP_EndLootRequest=0x30f7 +OP_LootItem=0x4dc9 +OP_LootComplete=0x55c4 + +# bazaar trader stuff: +OP_BazaarSearch=0x39d6 +OP_TraderDelItem=0x0000 +OP_BecomeTrader=0x61b3 +OP_TraderShop=0x31df +OP_Trader=0x4ef5 +OP_TraderBuy=0x0000 +OP_Barter=0x243a +OP_ShopItem=0x0000 +OP_BazaarInspect=0x0000 +OP_Bazaar=0x0000 +OP_TraderItemUpdate=0x0000 + +# pc/npc trading +OP_TradeRequest=0x77b5 +OP_TradeAcceptClick=0x69e2 +OP_TradeRequestAck=0x14bf +OP_TradeCoins=0x4206 +OP_FinishTrade=0x3993 +OP_CancelTrade=0x354c +OP_TradeMoneyUpdate=0x68c2 +OP_MoneyUpdate=0x640c +OP_TradeBusy=0x5505 + +# Sent after canceling trade or after closing tradeskill object +OP_FinishWindow=0x7349 +OP_FinishWindow2=0x40ef + +# Sent on Live for what seems to be item existance verification +# Ex. Before Right Click Effect happens from items +OP_ItemVerifyRequest=0x189c +OP_ItemVerifyReply=0x097b + +# merchant stuff +OP_ShopPlayerSell=0x0000 +OP_ShopRequest=0x4fed +OP_ShopEnd=0x30a8 +OP_ShopEndConfirm=0x3196 +OP_ShopPlayerBuy=0x0ddd +OP_ShopDelItem=0x724f + +# tradeskill stuff: +OP_ClickObject=0x4aa1 +OP_ClickObjectAction=0x0c1e +OP_ClearObject=0x7a11 +OP_RecipeDetails=0x40d7 +OP_RecipesFavorite=0x71b1 +OP_RecipesSearch=0x1db6 +OP_RecipeReply=0x6e02 +OP_RecipeAutoCombine=0x6261 +OP_TradeSkillCombine=0x579a + +# Tribute Packets: +OP_OpenGuildTributeMaster=0x378d +OP_OpenTributeMaster=0x7666 +OP_SelectTribute=0x79fc +OP_TributeItem=0x4f3e +OP_TributeMoney=0x58fb +OP_TributeToggle=0x241d +OP_TributePointUpdate=0x5300 +OP_TributeNPC=0x0000 +OP_GuildTributeInfo=0x0000 +OP_OpenTributeReply=0x0000 +OP_GuildTributeStatus=0x0000 + +# Adventure packets: +OP_LeaveAdventure=0x5d18 +OP_AdventureFinish=0x400f +OP_AdventureInfoRequest=0x3cb0 +OP_AdventureInfo=0x4c54 +OP_AdventureRequest=0x2c6c +OP_AdventureDetails=0x5648 +OP_AdventureData=0x7171 +OP_AdventureUpdate=0x1b01 +OP_AdventureMerchantRequest=0x6922 +OP_AdventureMerchantResponse=0x3e47 +OP_AdventureMerchantPurchase=0x5b72 +OP_AdventureMerchantSell=0x2f9b +OP_AdventurePointsUpdate=0x65c3 +OP_AdventureStatsRequest=0x5a62 +OP_AdventureStatsReply=0x2370 +OP_AdventureLeaderboardRequest=0x7093 +OP_AdventureLeaderboardReply=0x7f79 + +# Group Opcodes +OP_GroupDisband=0x4c10 +OP_GroupInvite=0x6110 +OP_GroupFollow=0x1649 +OP_GroupUpdate=0x3abb +OP_GroupUpdateB=0x6194 +OP_GroupCancelInvite=0x0000 +OP_GroupAcknowledge=0x7323 +OP_GroupDelete=0x0f6c +OP_CancelInvite=0x2a50 +OP_GroupFollow2=0x2060 +OP_GroupInvite2=0x32c2 +OP_GroupDisbandYou=0x1ae5 +OP_GroupDisbandOther=0x74da +OP_GroupLeaderChange=0x21b4 +OP_GroupRoles=0x70e2 +OP_GroupMakeLeader=0x4229 +OP_DoGroupLeadershipAbility=0x1fb5 +OP_GroupLeadershipAAUpdate=0x02cf +OP_GroupMentor=0x3342 +OP_InspectBuffs=0x486c + +# LFG/LFP Opcodes +OP_LFGCommand=0x6060 +OP_LFGGetMatchesRequest=0x0340 +OP_LFGGetMatchesResponse=0x5048 +OP_LFPGetMatchesRequest=0x4d7d +OP_LFPGetMatchesResponse=0x22c6 +OP_LFPCommand=0x49a9 +OP_LFGAppearance=0x0000 +OP_LFGResponse=0x0000 + +# Raid Opcodes +OP_RaidInvite=0x55ac +OP_RaidUpdate=0x3973 +OP_RaidJoin=0x0000 + +# Button-push commands +OP_Taunt=0x2703 +OP_CombatAbility=0x3eba +OP_SenseTraps=0x02af +OP_PickPocket=0x39e8 +OP_DisarmTraps=0x78bf +OP_Disarm=0x5ec8 +OP_Sneak=0x5d55 +OP_Fishing=0x1e2a +OP_InstillDoubt=0x640e +OP_FeignDeath=0x52fa +OP_Mend=0x0ecf +OP_Bind_Wound=0x0386 +OP_LDoNOpen=0x3d5c + +# Task packets +OP_TaskDescription=0x3714 +OP_TaskActivity=0x08d3 +OP_CompletedTasks=0x4eba +OP_TaskActivityComplete=0x5e19 +OP_AcceptNewTask=0x0a23 +OP_CancelTask=0x39f0 +OP_TaskMemberList=0x5727 +OP_OpenNewTasksWindow=0x48a2 +OP_AvaliableTask=0x36e8 +OP_TaskHistoryRequest=0x5f1c +OP_TaskHistoryReply=0x3d05 +OP_DeclineAllTasks=0x0000 + +# Title opcodes +OP_NewTitlesAvailable=0x0d32 +OP_RequestTitles=0x6344 +OP_SendTitleList=0x2d08 +OP_SetTitle=0x6527 +OP_SetTitleReply=0x4c21 + +# mail opcodes +OP_Command=0x0000 +OP_MailboxHeader=0x0000 +OP_MailHeader=0x0000 +OP_MailBody=0x0000 +OP_NewMail=0x0000 +OP_SentConfirm=0x0000 + +########### Below this point should not be needed ########### + +# This section are all unknown in Titanium +OP_ForceFindPerson=0x0000 +OP_LocInfo=0x0000 +OP_ReloadUI=0x0000 +OP_ItemName=0x0000 +OP_ItemLinkText=0x0000 +OP_MultiLineMsg=0x0000 +OP_MendHPUpdate=0x0000 +OP_TargetReject=0x0000 +OP_SafePoint=0x0000 +OP_ApproveZone=0x0000 +OP_ZoneComplete=0x0000 +OP_ClientError=0x0000 +OP_DumpName=0x0000 +OP_Heartbeat=0x0000 +OP_CrashDump=0x0000 +OP_LoginComplete=0x0000 + +# discovered opcodes not yet used: +OP_PickLockSuccess=0x0000 +OP_PlayMP3=0x5770 +OP_ReclaimCrystals=0x0000 +OP_DynamicWall=0x0000 +OP_OpenDiscordMerchant=0x0000 +OP_DiscordMerchantInventory=0x0000 +OP_GiveMoney=0x0000 +OP_RequestKnowledgeBase=0x0000 +OP_KnowledgeBase=0x0000 +OP_SlashAdventure=0x0000 # /adventure +OP_BecomePVPPrompt=0x0000 +OP_MoveLogRequest=0x0000 # gone I think +OP_MoveLogDisregard=0x0000 # gone I think + +# named unknowns, to make looking for real unknown easier +OP_AnnoyingZoneUnknown=0x0000 +OP_Some6ByteHPUpdate=0x0000 seems to happen when you target group members +OP_QueryResponseThing=0x0000 + + +# realityincarnate: these are just here to stop annoying several thousand byte packet dumps +#OP_LoginUnknown1=0x46d3 # OP_SendSpellChecksum +#OP_LoginUnknown2=0x040b # OP_SendSkillCapsChecksum + +# Petition Opcodes +OP_PetitionSearch=0x0000 search term for petition +OP_PetitionSearchResults=0x0000 (list of?) matches from search +OP_PetitionSearchText=0x0000 text results of search + +OP_PetitionUpdate=0x0000 +OP_PetitionCheckout=0x0000 +OP_PetitionCheckIn=0x0000 +OP_PetitionQue=0x0000 +OP_PetitionUnCheckout=0x0000 +OP_PetitionDelete=0x0000 +OP_DeletePetition=0x0000 +OP_PetitionResolve=0x0000 +OP_PDeletePetition=0x0000 +OP_PetitionBug=0x0000 +OP_PetitionRefresh=0x0000 +OP_PetitionCheckout2=0x0000 +OP_PetitionViewPetition=0x0000 + +# Login opcodes +OP_SessionReady=0x0000 +OP_Login=0x0000 +OP_ServerListRequest=0x0000 +OP_PlayEverquestRequest=0x0000 +OP_PlayEverquestResponse=0x0000 +OP_ChatMessage=0x0000 +OP_LoginAccepted=0x0000 +OP_ServerListResponse=0x0000 +OP_Poll=0x0000 +OP_EnterChat=0x0000 +OP_PollResponse=0x0000 + +# raw opcodes +OP_RAWSessionRequest=0x0000 +OP_RAWSessionResponse=0x0000 +OP_RAWCombined=0x0000 +OP_RAWSessionDisconnect=0x0000 +OP_RAWKeepAlive=0x0000 +OP_RAWSessionStatRequest=0x0000 +OP_RAWSessionStatResponse=0x0000 +OP_RAWPacket=0x0000 +OP_RAWFragment=0x0000 +OP_RAWOutOfOrderAck=0x0000 +OP_RAWAck=0x0000 +OP_RAWAppCombined=0x0000 +OP_RAWOutOfSession=0x0000 + +# we need to document the differences between these packets to make identifying them easier +OP_Some3ByteHPUpdate=0x0000 # initial HP update for mobs +OP_InitialHPUpdate=0x0000 diff --git a/utils/scripts/opcode_scripts/patch_OLD.conf b/utils/scripts/opcode_scripts/patch_OLD.conf new file mode 100644 index 000000000..589c47468 --- /dev/null +++ b/utils/scripts/opcode_scripts/patch_OLD.conf @@ -0,0 +1,660 @@ +# ShowEQ Import Notes: +# ZERO THE FILE first +# perl -pi -e 's/0x[0-9a-fA-F]{4}/0x0000/g' opcodes.conf +# Unknown Mapping: +# OP_Action2 -> OP_Damage +# OP_EnvDamage -> OP_Damage ---> might have been a one time mistake +# Name Differences: +# OP_CancelInvite -> OP_GroupCancelInvite +# OP_GMFind -> OP_FindPersonRequest +# OP_CommonMessage -> OP_ChannelMessage + +OP_Unknown=0x0000 +OP_ExploreUnknown=0x0000 # used for unknown explorer + +# world packets +# Required to reach Char Select: +OP_SendLoginInfo=0x7a09 +OP_ApproveWorld=0x7499 +OP_LogServer=0x7ceb +OP_SendCharInfo=0x00d2 +OP_ExpansionInfo=0x590d +OP_GuildsList=0x0000 +OP_EnterWorld=0x578f +OP_PostEnterWorld=0x6259 +OP_World_Client_CRC1=0x12cc +OP_World_Client_CRC2=0x0f13 +OP_SendSpellChecksum=0x0000 +OP_SendSkillCapsChecksum=0x0000 + +# Character Select Related: +OP_SendMaxCharacters=0x5475 +OP_SendMembership=0x7acc +OP_SendMembershipDetails=0x057b +OP_CharacterCreateRequest=0x6773 +OP_CharacterCreate=0x6bbf +OP_DeleteCharacter=0x1808 +OP_RandomNameGenerator=0x5954 +OP_ApproveName=0x56a2 +OP_MOTD=0x0c22 +OP_SetChatServer=0x1bc5 +OP_SetChatServer2=0x7eec +OP_ZoneServerInfo=0x4c44 +OP_WorldComplete=0x4493 +OP_WorldUnknown001=0x2301 +OP_FloatListThing=0x46c6 + +# Reasons for Disconnect: +OP_ZoneUnavail=0x4cb4 +OP_WorldClientReady=0x23c1 +OP_CharacterStillInZone=0x0000 +OP_WorldChecksumFailure=0x0000 +OP_WorldLoginFailed=0x0000 +OP_WorldLogout=0x0000 +OP_WorldLevelTooHigh=0x0000 +OP_CharInacessable=0x0000 +OP_UserCompInfo=0x0000 +OP_SendExeChecksum=0x0000 +OP_SendBaseDataChecksum=0x0000 + +# Zone in opcodes +OP_AckPacket=0x471d +OP_ZoneEntry=0x5089 +OP_ReqNewZone=0x7887 +OP_NewZone=0x1795 +OP_ZoneSpawns=0x5237 +OP_PlayerProfile=0x6506 +OP_TimeOfDay=0x5070 +OP_LevelUpdate=0x1eec +OP_Stamina=0x2a79 +OP_RequestClientZoneChange=0x3fcf +OP_ZoneChange=0x2d18 +OP_LockoutTimerInfo=0x0000 +OP_ZoneServerReady=0x0000 +OP_ZoneInUnknown=0x0000 +OP_LogoutReply=0x0000 +OP_PreLogoutReply=0x0000 + +# Required to fully log in +OP_SpawnAppearance=0x0971 +OP_ChangeSize=0x4707 +OP_TributeUpdate=0x5961 +OP_TributeTimer=0x073d +OP_SendTributes=0x729b +OP_SendGuildTributes=0x1877 +OP_TributeInfo=0x4254 +OP_Weather=0x661e +OP_ReqClientSpawn=0x35fa +OP_SpawnDoor=0x7291 +OP_GroundSpawn=0x6fca +OP_SendZonepoints=0x69a4 +OP_BlockedBuffs=0x3033 +OP_RemoveBlockedBuffs=0x0de7 +OP_ClearBlockedBuffs=0x34cb +OP_WorldObjectsSent=0x5ae2 +OP_SendExpZonein=0x5f8e +OP_SendAATable=0x66b5 +OP_RespondAA=0x7a27 +OP_UpdateAA=0x66f0 +OP_SendAAStats=0x43c8 +OP_AAExpUpdate=0x7d14 +OP_ExpUpdate=0x20ed +OP_HPUpdate=0x2828 +OP_ManaChange=0x43af +OP_TGB=0x0876 +OP_SpecialMesg=0x0083 +OP_GuildMemberList=0x12a6 +OP_GuildMOTD=0x3e13 +OP_CharInventory=0x5ca6 +OP_WearChange=0x7994 +OP_ClientUpdate=0x7dfc +OP_ClientReady=0x345d +OP_SetServerFilter=0x444d + +# Guild Opcodes - Disabled until crashes are resolved in RoF +OP_GetGuildMOTD=0x36e0 +OP_GetGuildMOTDReply=0x4f1f +OP_GuildMemberUpdate=0x69b9 +OP_GuildInvite=0x7099 +OP_GuildRemove=0x1444 +OP_GuildPeace=0x67e3 +OP_SetGuildMOTD=0x0b0b +OP_GuildList=0x507a +OP_GuildWar=0x1ffb +OP_GuildLeader=0x7e09 +OP_GuildDelete=0x3708 +OP_GuildInviteAccept=0x7053 +OP_GuildDemote=0x2d4e +OP_GuildPromote=0x0000 +OP_GuildPublicNote=0x5053 +OP_GuildManageBanker=0x748f +OP_GuildBank=0x5134 +OP_SetGuildRank=0x0b9c +OP_GuildUpdateURLAndChannel=0x2958 +OP_GuildStatus=0x7326 +OP_GuildCreate=0x1dc8 +OP_GuildMemberLevelUpdate=0x0000 # Unused? +OP_ZoneGuildList=0x0000 # Unused? +OP_GetGuildsList=0x0000 # Unused? +OP_LFGuild=0x0000 +OP_GuildManageRemove=0x0000 +OP_GuildManageAdd=0x0000 +OP_GuildManageStatus=0x0000 + +# GM/Guide Opcodes +OP_GMServers=0x08c1 +OP_GMBecomeNPC=0x3ae1 +OP_GMZoneRequest=0x62ac +OP_GMZoneRequest2=0x7e1a +OP_GMGoto=0x7d8e +OP_GMSearchCorpse=0x357c +OP_GMHideMe=0x79c5 +OP_GMDelCorpse=0x607e +OP_GMApproval=0x6db5 +OP_GMToggle=0x2097 +OP_GMSummon=0x486f +OP_GMEmoteZone=0x1cfd +OP_GMEmoteWorld=0x458e +OP_GMFind=0x4a8f +OP_GMKick=0x26a7 +OP_GMKill=0x51d3 +OP_GMNameChange=0x035f +OP_GMLastName=0x46ce + +# Misc Opcodes +OP_InspectRequest=0x57bc +OP_InspectAnswer=0x71ac +OP_InspectMessageUpdate=0x4d25 +OP_BeginCast=0x318f +OP_ColoredText=0x0000 +OP_ConsentResponse=0x384a +OP_MemorizeSpell=0x217c +OP_SwapSpell=0x0efa +OP_CastSpell=0x1287 +OP_Consider=0x742b +OP_FormattedMessage=0x1024 +OP_SimpleMessage=0x213f +OP_Buff=0x659c +OP_Illusion=0x312a +OP_MoneyOnCorpse=0x5f44 +OP_RandomReply=0x106b +OP_DenyResponse=0x2382 +OP_SkillUpdate=0x004c +OP_GMTrainSkillConfirm=0x66dd +OP_RandomReq=0x7b10 +OP_Death=0x6517 +OP_GMTraining=0x1966 +OP_GMEndTraining=0x4d6b +OP_GMTrainSkill=0x2a85 +OP_Animation=0x7177 +OP_Begging=0x6703 +OP_Consent=0x1fd1 +OP_ConsentDeny=0x7a45 +OP_AutoFire=0x241e +OP_PetCommands=0x0159 +OP_DeleteSpell=0x52e5 +OP_Surname=0x0423 +OP_ClearSurname=0x7d23 +OP_FaceChange=0x5578 +OP_SenseHeading=0x260a +OP_Action=0x744c +OP_ConsiderCorpse=0x5204 +OP_HideCorpse=0x49e1 +OP_CorpseDrag=0x0904 +OP_CorpseDrop=0x7037 +OP_Bug=0x73f4 +OP_Feedback=0x5602 +OP_Report=0x1414 +OP_Damage=0x6f15 +OP_ChannelMessage=0x2b2d +OP_Assist=0x4478 +OP_AssistGroup=0x27f8 +OP_MoveCoin=0x0bcf +OP_ZonePlayerToBind=0x0ecb +OP_KeyRing=0x6857 +OP_WhoAllRequest=0x65ab +OP_WhoAllResponse=0x7c88 +OP_FriendsWho=0x3956 +OP_ConfirmDelete=0x43a3 +OP_Logout=0x4ac6 +OP_Rewind=0x1745 +OP_TargetCommand=0x58e2 +OP_Hide=0x67fe +OP_Jump=0x2060 +OP_Camp=0x28ec +OP_Emote=0x373b +OP_SetRunMode=0x009f +OP_BankerChange=0x383c +OP_TargetMouse=0x075d +OP_MobHealth=0x37b1 +OP_InitialMobHealth=0x0000 # Unused? +OP_TargetHoTT=0x0272 +OP_XTargetResponse=0x672f +OP_XTargetRequest=0x45be +OP_XTargetAutoAddHaters=0x792c +OP_TargetBuffs=0x4f4b +OP_BuffCreate=0x3377 +OP_BuffRemoveRequest=0x64f2 +OP_DeleteSpawn=0x7280 +OP_AutoAttack=0x109d +OP_AutoAttack2=0x3526 +OP_Consume=0x4b70 +OP_MoveItem=0x32ee +OP_DeleteItem=0x18ad +OP_DeleteCharge=0x01b8 +OP_ItemPacket=0x368e +OP_ItemLinkResponse=0x633c +OP_ItemLinkClick=0x4cef +OP_ItemPreview=0x6b5c +OP_NewSpawn=0x6097 +OP_Track=0x17e5 +OP_TrackTarget=0x0029 +OP_TrackUnknown=0x4577 +OP_ClickDoor=0x3a8f +OP_MoveDoor=0x08e8 +OP_RemoveAllDoors=0x700c +OP_EnvDamage=0x51fd +OP_BoardBoat=0x4211 +OP_Forage=0x5306 +OP_LeaveBoat=0x7617 +OP_ControlBoat=0x0ae7 +OP_SafeFallSuccess=0x2219 +OP_RezzComplete=0x760d +OP_RezzRequest=0x3c21 +OP_RezzAnswer=0x701c +OP_Shielding=0x48c1 +OP_RequestDuel=0x3af1 +OP_MobRename=0x2c57 +OP_AugmentItem=0x661b +OP_WeaponEquip1=0x34a7 +OP_WeaponEquip2=0x559a +OP_WeaponUnequip2=0x2d25 +OP_ApplyPoison=0x31e6 +OP_Save=0x4a39 +OP_TestBuff=0x7cb8 +OP_CustomTitles=0x100e +OP_Split=0x3a54 +OP_YellForHelp=0x4e56 +OP_LoadSpellSet=0x261d +OP_Bandolier=0x7677 +OP_PotionBelt=0x1a3e +OP_DuelResponse=0x6a46 +OP_DuelResponse2=0x68d3 +OP_SaveOnZoneReq=0x600d +OP_ReadBook=0x72df +OP_Dye=0x23b9 +OP_InterruptCast=0x048c +OP_AAAction=0x424e +OP_LeadershipExpToggle=0x6c55 +OP_LeadershipExpUpdate=0x2797 +OP_PurchaseLeadershipAA=0x0026 +OP_UpdateLeadershipAA=0x026 +OP_MarkNPC=0x5a58 +OP_MarkRaidNPC=0x74bd #unimplemented +OP_ClearNPCMarks=0x2003 +OP_ClearRaidNPCMarks=0x20d3 #unimplemented +OP_DelegateAbility=0x76b8 +OP_SetGroupTarget=0x2814 +OP_Charm=0x5d92 +OP_Stun=0x36a4 +OP_SendFindableNPCs=0x3897 +OP_FindPersonRequest=0x5cea +OP_FindPersonReply=0x7e58 +OP_Sound=0x1a30 +OP_PetBuffWindow=0x5882 +OP_LevelAppearance=0x3bc9 +OP_Translocate=0x6580 +OP_Sacrifice=0x1821 +OP_PopupResponse=0x214a +OP_OnLevelMessage=0x4fd0 +OP_AugmentInfo=0x0afb +OP_Petition=0x5f03 +OP_SomeItemPacketMaybe=0x747c +OP_PVPStats=0x6f4b +OP_PVPLeaderBoardRequest=0x3707 +OP_PVPLeaderBoardReply=0x25b7 +OP_PVPLeaderBoardDetailsRequest=0x15a9 +OP_PVPLeaderBoardDetailsReply=0x04aa +OP_RestState=0x00f +OP_RespawnWindow=0x28bc +OP_LDoNButton=0x5327 +OP_SetStartCity=0x6326 +OP_VoiceMacroIn=0x17fd +OP_VoiceMacroOut=0x409a +OP_ItemViewUnknown=0x2289 +OP_VetRewardsAvaliable=0x590e +OP_VetClaimRequest=0x1126 +OP_VetClaimReply=0x16d4 +OP_DisciplineUpdate=0x759e +OP_DisciplineTimer=0x6989 +OP_BecomeCorpse=0x0000 # Unused? +OP_Action2=0x0000 # Unused? +OP_MobUpdate=0x2c84 +OP_NPCMoveUpdate=0x189c +OP_CameraEffect=0x127f +OP_SpellEffect=0x5936 +OP_RemoveNimbusEffect=0xc693 +OP_AltCurrency=0x7121 +OP_AltCurrencyMerchantRequest=0x6b6d +OP_AltCurrencyMerchantReply=0x74ec +OP_AltCurrencyPurchase=0x61cb +OP_AltCurrencySell=0x0165 +OP_AltCurrencySellSelection=0x5409 +OP_AltCurrencyReclaim=0x532a +OP_CrystalCountUpdate=0x467f +OP_CrystalCreate=0x7aee +OP_CrystalReclaim=0x2439 +OP_Untargetable=0x053c +OP_IncreaseStats=0x70a3 +OP_Weblink=0x18d3 +OP_OpenContainer=0x0000 +OP_Marquee=0x0000 +OP_ItemRecastDelay=0x08a6 +#OP_OpenInventory=0x0000 # Likely does not exist in RoF -U + +OP_DzQuit=0xb2e3 +OP_DzListTimers=0x7b68 +OP_DzAddPlayer=0x4701 +OP_DzRemovePlayer=0x1abc +OP_DzSwapPlayer=0x405b +OP_DzMakeLeader=0x543d +OP_DzPlayerList=0x14c6 +OP_DzJoinExpeditionConfirm=0x7f4b +OP_DzJoinExpeditionReply=0x1950 +OP_DzExpeditionInfo=0x9119 +OP_DzExpeditionList=0x205f +OP_DzMemberStatus=0x32f0 +OP_DzLeaderStatus=0x3de9 +OP_DzExpeditionEndsWarning=0x5189 +OP_DzMemberList=0x5ae4 +OP_DzCompass=0x3e0e +OP_DzChooseZone=0x0000 + +# New Opcodes +OP_SpawnPositionUpdate=0x0000 # Actually OP_MobUpdate ? +OP_ManaUpdate=0x3791 +OP_EnduranceUpdate=0x5f42 +OP_MobManaUpdate=0x2404 +OP_MobEnduranceUpdate=0x1c81 + +# Mercenary Opcodes +OP_MercenaryDataUpdateRequest=0x7b89 +OP_MercenaryDataUpdate=0x61a4 +OP_MercenaryDataRequest=0x11c1 +OP_MercenaryDataResponse=0x72ce +OP_MercenaryHire=0x7169 +OP_MercenaryDismiss=0x6e83 +OP_MercenaryTimerRequest=0x31e4 +OP_MercenaryTimer=0x0763 +OP_MercenaryUnknown1=0x5d26 +OP_MercenaryCommand=0x27f2 +OP_MercenarySuspendRequest=0x4407 +OP_MercenarySuspendResponse=0x6f03 +OP_MercenaryUnsuspendResponse=0x27a0 + +# Looting +OP_LootRequest=0x0adf +OP_EndLootRequest=0x30f7 +OP_LootItem=0x4dc9 +OP_LootComplete=0x55c4 + +# bazaar trader stuff: +OP_BazaarSearch=0x39d6 +OP_TraderDelItem=0x0000 +OP_BecomeTrader=0x61b3 +OP_TraderShop=0x31df +OP_Trader=0x4ef5 +OP_TraderBuy=0x0000 +OP_Barter=0x243a +OP_ShopItem=0x0000 +OP_BazaarInspect=0x0000 +OP_Bazaar=0x0000 +OP_TraderItemUpdate=0x0000 + +# pc/npc trading +OP_TradeRequest=0x77b5 +OP_TradeAcceptClick=0x69e2 +OP_TradeRequestAck=0x14bf +OP_TradeCoins=0x4206 +OP_FinishTrade=0x3993 +OP_CancelTrade=0x354c +OP_TradeMoneyUpdate=0x68c2 +OP_MoneyUpdate=0x640c +OP_TradeBusy=0x5505 + +# Sent after canceling trade or after closing tradeskill object +OP_FinishWindow=0x7349 +OP_FinishWindow2=0x40ef + +# Sent on Live for what seems to be item existance verification +# Ex. Before Right Click Effect happens from items +OP_ItemVerifyRequest=0x097b +OP_ItemVerifyReply=0x2115 + +# merchant stuff +OP_ShopPlayerSell=0x1901 +OP_ShopRequest=0x4fed +OP_ShopEnd=0x30a8 +OP_ShopEndConfirm=0x3196 +OP_ShopPlayerBuy=0x04c +OP_ShopDelItem=0x724f + +# tradeskill stuff: +OP_ClickObject=0x4aa1 +OP_ClickObjectAction=0x0c1e +OP_ClearObject=0x7a11 +OP_RecipeDetails=0x40d7 +OP_RecipesFavorite=0x5c74 +OP_RecipesSearch=0x1db6 +OP_RecipeReply=0x6e02 +OP_RecipeAutoCombine=0x6261 +OP_TradeSkillCombine=0x579a + +# Tribute Packets: +OP_OpenGuildTributeMaster=0x378d +OP_OpenTributeMaster=0x7666 +OP_SelectTribute=0x79fc +OP_TributeItem=0x4f3e +OP_TributeMoney=0x58fb +OP_TributeToggle=0x241d +OP_TributePointUpdate=0x5300 +OP_TributeNPC=0x0000 +OP_GuildTributeInfo=0x0000 +OP_OpenTributeReply=0x0000 +OP_GuildTributeStatus=0x0000 + +# Adventure packets: +OP_LeaveAdventure=0x5d18 +OP_AdventureFinish=0x400f +OP_AdventureInfoRequest=0x3cb0 +OP_AdventureInfo=0x4c54 +OP_AdventureRequest=0x2c6c +OP_AdventureDetails=0x5648 +OP_AdventureData=0x7171 +OP_AdventureUpdate=0x1b01 +OP_AdventureMerchantRequest=0x6922 +OP_AdventureMerchantResponse=0x3e47 +OP_AdventureMerchantPurchase=0x5b72 +OP_AdventureMerchantSell=0x2f9b +OP_AdventurePointsUpdate=0x65c3 +OP_AdventureStatsRequest=0x5a62 +OP_AdventureStatsReply=0x2370 +OP_AdventureLeaderboardRequest=0x7093 +OP_AdventureLeaderboardReply=0x7f79 + +# Group Opcodes +OP_GroupDisband=0x4c10 +OP_GroupInvite=0x1649 +OP_GroupFollow=0x05ce +OP_GroupUpdate=0x3abb +OP_GroupUpdateB=0x6194 +OP_GroupCancelInvite=0x0000 +OP_GroupAcknowledge=0x7323 +OP_GroupDelete=0x0f6c +OP_CancelInvite=0x32c2 +OP_GroupFollow2=0x2a50 +OP_GroupInvite2=0x6c65 +OP_GroupDisbandYou=0x1ae5 +OP_GroupDisbandOther=0x74da +OP_GroupLeaderChange=0x21b4 +OP_GroupRoles=0x70e2 +OP_GroupMakeLeader=0x4229 +OP_DoGroupLeadershipAbility=0x1fb5 +OP_GroupLeadershipAAUpdate=0x02cf +OP_GroupMentor=0x5892 +OP_InspectBuffs=0x486c + +# LFG/LFP Opcodes +OP_LFGCommand=0x6060 +OP_LFGGetMatchesRequest=0x0340 +OP_LFGGetMatchesResponse=0x5048 +OP_LFPGetMatchesRequest=0x4d7d +OP_LFPGetMatchesResponse=0x22c6 +OP_LFPCommand=0x49a9 +OP_LFGAppearance=0x0000 +OP_LFGResponse=0x0000 + +# Raid Opcodes +OP_RaidInvite=0x55ac +OP_RaidUpdate=0x3973 +OP_RaidJoin=0x0000 + +# Button-push commands +OP_Taunt=0x2703 +OP_CombatAbility=0x3eba +OP_SenseTraps=0x02af +OP_PickPocket=0x39e8 +OP_DisarmTraps=0x78bf +OP_Disarm=0x5ec8 +OP_Sneak=0x5d55 +OP_Fishing=0x1e2a +OP_InstillDoubt=0x640e +OP_FeignDeath=0x52fa +OP_Mend=0x0ecf +OP_Bind_Wound=0x0386 +OP_LDoNOpen=0x3d5c + +# Task packets +OP_TaskDescription=0x083 +OP_TaskActivity=0x3714 +OP_CompletedTasks=0x4eba +OP_TaskActivityComplete=0x5e19 +OP_AcceptNewTask=0x0a23 +OP_CancelTask=0x08d3 +OP_TaskMemberList=0x5727 +OP_OpenNewTasksWindow=0x48a2 +OP_AvaliableTask=0x36e8 +OP_TaskHistoryRequest=0x5f1c +OP_TaskHistoryReply=0x3d05 +OP_DeclineAllTasks=0x0000 + +# Title opcodes +OP_NewTitlesAvailable=0x0d32 +OP_RequestTitles=0x6344 +OP_SendTitleList=0x2d08 +OP_SetTitle=0x6527 +OP_SetTitleReply=0x4c21 + +# mail opcodes +OP_Command=0x0000 +OP_MailboxHeader=0x0000 +OP_MailHeader=0x0000 +OP_MailBody=0x0000 +OP_NewMail=0x0000 +OP_SentConfirm=0x0000 + +########### Below this point should not be needed ########### + +# This section are all unknown in Titanium +OP_ForceFindPerson=0x0000 +OP_LocInfo=0x0000 +OP_ReloadUI=0x0000 +OP_ItemName=0x0000 +OP_ItemLinkText=0x0000 +OP_MultiLineMsg=0x0000 +OP_MendHPUpdate=0x0000 +OP_TargetReject=0x0000 +OP_SafePoint=0x0000 +OP_ApproveZone=0x0000 +OP_ZoneComplete=0x0000 +OP_ClientError=0x0000 +OP_DumpName=0x0000 +OP_Heartbeat=0x0000 +OP_CrashDump=0x0000 +OP_LoginComplete=0x0000 + +# discovered opcodes not yet used: +OP_PickLockSuccess=0x0000 +OP_PlayMP3=0x0000 +OP_ReclaimCrystals=0x0000 +OP_DynamicWall=0x0000 +OP_OpenDiscordMerchant=0x0000 +OP_DiscordMerchantInventory=0x0000 +OP_GiveMoney=0x0000 +OP_RequestKnowledgeBase=0x0000 +OP_KnowledgeBase=0x0000 +OP_SlashAdventure=0x0000 # /adventure +OP_BecomePVPPrompt=0x0000 +OP_MoveLogRequest=0x0000 # gone I think +OP_MoveLogDisregard=0x0000 # gone I think + +# named unknowns, to make looking for real unknown easier +OP_AnnoyingZoneUnknown=0x0000 +OP_Some6ByteHPUpdate=0x0000 seems to happen when you target group members +OP_QueryResponseThing=0x0000 + + +# realityincarnate: these are just here to stop annoying several thousand byte packet dumps +#OP_LoginUnknown1=0x46d3 # OP_SendSpellChecksum +#OP_LoginUnknown2=0x040b # OP_SendSkillCapsChecksum + +# Petition Opcodes +OP_PetitionSearch=0x0000 search term for petition +OP_PetitionSearchResults=0x0000 (list of?) matches from search +OP_PetitionSearchText=0x0000 text results of search + +OP_PetitionUpdate=0x0000 +OP_PetitionCheckout=0x0000 +OP_PetitionCheckIn=0x0000 +OP_PetitionQue=0x0000 +OP_PetitionUnCheckout=0x0000 +OP_PetitionDelete=0x0000 +OP_DeletePetition=0x0000 +OP_PetitionResolve=0x0000 +OP_PDeletePetition=0x0000 +OP_PetitionBug=0x0000 +OP_PetitionRefresh=0x0000 +OP_PetitionCheckout2=0x0000 +OP_PetitionViewPetition=0x0000 + +# Login opcodes +OP_SessionReady=0x0000 +OP_Login=0x0000 +OP_ServerListRequest=0x0000 +OP_PlayEverquestRequest=0x0000 +OP_PlayEverquestResponse=0x0000 +OP_ChatMessage=0x0000 +OP_LoginAccepted=0x0000 +OP_ServerListResponse=0x0000 +OP_Poll=0x0000 +OP_EnterChat=0x0000 +OP_PollResponse=0x0000 + +# raw opcodes +OP_RAWSessionRequest=0x0000 +OP_RAWSessionResponse=0x0000 +OP_RAWCombined=0x0000 +OP_RAWSessionDisconnect=0x0000 +OP_RAWKeepAlive=0x0000 +OP_RAWSessionStatRequest=0x0000 +OP_RAWSessionStatResponse=0x0000 +OP_RAWPacket=0x0000 +OP_RAWFragment=0x0000 +OP_RAWOutOfOrderAck=0x0000 +OP_RAWAck=0x0000 +OP_RAWAppCombined=0x0000 +OP_RAWOutOfSession=0x0000 + +# we need to document the differences between these packets to make identifying them easier +OP_Some3ByteHPUpdate=0x0000 # initial HP update for mobs +OP_InitialHPUpdate=0x0000 \ No newline at end of file diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 8291465a4..2af5e6e90 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -312,7 +312,7 @@ 9056|2014_11_08_RaidMembers.sql|SHOW COLUMNS FROM `raid_members` LIKE 'groupid'|missing|unsigned 9057|2014_11_13_spells_new_updates.sql|SHOW COLUMNS FROM `spells_new` LIKE 'disallow_sit'|empty| 9058|2014_11_26_InventoryTableUpdate.sql|SHOW COLUMNS FROM `inventory` LIKE 'ornamenticon'|empty| -9059|2014_11_30_mercs_table_update.sql|SHOW COLUMNS FROM `mercs` LIKE 'MercSize'|empty| +9059|2014_12_01_mercs_table_update.sql|SHOW COLUMNS FROM `mercs` LIKE 'MercSize'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not @@ -331,4 +331,4 @@ # not_empty = If the query is not empty # 4 = Text to match # -# \ No newline at end of file +# diff --git a/world/adventure.cpp b/world/adventure.cpp index 80b1dcaca..b6db3d6d0 100644 --- a/world/adventure.cpp +++ b/world/adventure.cpp @@ -4,6 +4,7 @@ #include "../common/rulesys.h" #include "../common/misc_functions.h" #include "../common/string_util.h" +#include "../common/random.h" #include "adventure.h" #include "adventure_manager.h" #include "worlddb.h" @@ -14,6 +15,7 @@ extern ZSList zoneserver_list; extern ClientList client_list; extern AdventureManager adventure_manager; +extern EQEmu::Random emu_random; Adventure::Adventure(AdventureTemplate *t) { @@ -392,8 +394,8 @@ void Adventure::MoveCorpsesToGraveyard() for (auto iter = dbid_list.begin(); iter != dbid_list.end(); ++iter) { - float x = GetTemplate()->graveyard_x + MakeRandomFloat(-GetTemplate()->graveyard_radius, GetTemplate()->graveyard_radius); - float y = GetTemplate()->graveyard_y + MakeRandomFloat(-GetTemplate()->graveyard_radius, GetTemplate()->graveyard_radius); + float x = GetTemplate()->graveyard_x + emu_random.Real(-GetTemplate()->graveyard_radius, GetTemplate()->graveyard_radius); + float y = GetTemplate()->graveyard_y + emu_random.Real(-GetTemplate()->graveyard_radius, GetTemplate()->graveyard_radius); float z = GetTemplate()->graveyard_z; query = StringFormat("UPDATE character_corpses " diff --git a/world/adventure_manager.cpp b/world/adventure_manager.cpp index aeee8e3c5..47ea42c51 100644 --- a/world/adventure_manager.cpp +++ b/world/adventure_manager.cpp @@ -3,6 +3,7 @@ #include "../common/string_util.h" #include "../common/servertalk.h" #include "../common/rulesys.h" +#include "../common/random.h" #include "adventure.h" #include "adventure_manager.h" #include "worlddb.h" @@ -14,6 +15,7 @@ extern ZSList zoneserver_list; extern ClientList client_list; +extern EQEmu::Random emu_random; AdventureManager::AdventureManager() { @@ -325,7 +327,7 @@ void AdventureManager::CalculateAdventureRequestReply(const char *data) if(eligible_adventures.size() > 0) { ea_iter = eligible_adventures.begin(); - int c_index = MakeRandomInt(0, (eligible_adventures.size()-1)); + int c_index = emu_random.Int(0, (eligible_adventures.size()-1)); for(int i = 0; i < c_index; ++i) { ++ea_iter; diff --git a/world/client.cpp b/world/client.cpp index f3f1a78c8..e37015e19 100644 --- a/world/client.cpp +++ b/world/client.cpp @@ -15,6 +15,7 @@ #include "../common/extprofile.h" #include "../common/string_util.h" #include "../common/clientversions.h" +#include "../common/random.h" #include "client.h" #include "worlddb.h" @@ -61,6 +62,7 @@ std::vector character_create_race_class_combos; extern ZSList zoneserver_list; extern LoginServerList loginserverlist; extern ClientList client_list; +extern EQEmu::Random emu_random; extern uint32 numclients; extern volatile bool RunLoops; @@ -221,7 +223,7 @@ void Client::SendMembership() { mc->entries[1] = 0xffffffff; // Max Level Restriction mc->entries[2] = 0xffffffff; // Max Char Slots per Account (not used by client?) mc->entries[3] = 0xffffffff; // 1 for Silver - mc->entries[4] = 8; // Main Inventory Size (0xffffffff on Live for Gold, but limitting to 8 until 10 is supported) + mc->entries[4] = 8; // Main Inventory Size (0xffffffff on Live for Gold, but limiting to 8 until 10 is supported) mc->entries[5] = 0xffffffff; // Max Platinum per level mc->entries[6] = 1; // 0 for Silver mc->entries[7] = 1; // 0 for Silver @@ -519,7 +521,7 @@ bool Client::HandleGenerateRandomNamePacket(const EQApplicationPacket *app) { char cons[48]="bcdfghjklmnpqrstvwxzybcdgklmnprstvwbcdgkpstrkd"; char rndname[17]="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; char paircons[33]="ngrkndstshthphsktrdrbrgrfrclcr"; - int rndnum=MakeRandomInt(0, 75),n=1; + int rndnum=emu_random.Int(0, 75),n=1; bool dlc=false; bool vwl=false; bool dbl=false; @@ -540,18 +542,18 @@ bool Client::HandleGenerateRandomNamePacket(const EQApplicationPacket *app) { rndname[0]=vowels[rndnum]; vwl=true; } - int namlen=MakeRandomInt(5, 10); + int namlen=emu_random.Int(5, 10); for (int i=n;i46) { // pick a cons pair if (i>namlen-3) // last 2 chars in name? { // name can only end in cons pair "rk" "st" "sh" "th" "ph" "sk" "nd" or "ng" - rndnum=MakeRandomInt(0, 7)*2; + rndnum=emu_random.Int(0, 7)*2; } else { // pick any from the set @@ -569,12 +571,12 @@ bool Client::HandleGenerateRandomNamePacket(const EQApplicationPacket *app) { } else { // select a vowel - rndname[i]=vowels[MakeRandomInt(0, 16)]; + rndname[i]=vowels[emu_random.Int(0, 16)]; } vwl=!vwl; if (!dbl && !dlc) { // one chance at double letters in name - if (!MakeRandomInt(0, i+9)) // chances decrease towards end of name + if (!emu_random.Int(0, i+9)) // chances decrease towards end of name { rndname[i+1]=rndname[i]; dbl=true; @@ -831,7 +833,7 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { QueuePacket(outapp); safe_delete(outapp); - int MailKey = MakeRandomInt(1, INT_MAX); + int MailKey = emu_random.Int(1, INT_MAX); database.SetMailKey(charid, GetIP(), MailKey); @@ -1242,8 +1244,8 @@ void Client::ZoneUnavail() { bool Client::GenPassKey(char* key) { char* passKey=nullptr; - *passKey += ((char)('A'+((int)MakeRandomInt(0, 25)))); - *passKey += ((char)('A'+((int)MakeRandomInt(0, 25)))); + *passKey += ((char)('A'+((int)emu_random.Int(0, 25)))); + *passKey += ((char)('A'+((int)emu_random.Int(0, 25)))); memcpy(key, passKey, strlen(passKey)); return true; } diff --git a/world/net.cpp b/world/net.cpp index da8936bbd..64819a2fd 100644 --- a/world/net.cpp +++ b/world/net.cpp @@ -69,6 +69,7 @@ #include "../common/emu_tcp_server.h" #include "../common/patches/patches.h" +#include "../common/random.h" #include "zoneserver.h" #include "console.h" #include "login_server.h" @@ -100,6 +101,7 @@ QueryServConnection QSLink; WebInterfaceConnection WILink; LauncherList launcher_list; AdventureManager adventure_manager; +EQEmu::Random emu_random; volatile bool RunLoops = true; uint32 numclients = 0; uint32 numzones = 0; diff --git a/world/zonelist.cpp b/world/zonelist.cpp index c97010aa8..c6c1043f5 100644 --- a/world/zonelist.cpp +++ b/world/zonelist.cpp @@ -24,10 +24,12 @@ #include "world_config.h" #include "../common/servertalk.h" #include "../common/string_util.h" +#include "../common/random.h" extern uint32 numzones; extern bool holdzones; extern ConsoleList console_list; +extern EQEmu::Random emu_random; void CatchSignal(int sig_num); ZSList::ZSList() @@ -565,7 +567,7 @@ void ZSList::RebootZone(const char* ip1,uint16 port,const char* ip2, uint32 skip safe_delete(tmp); return; } - uint32 z = MakeRandomInt(0, y-1); + uint32 z = emu_random.Int(0, y-1); ServerPacket* pack = new ServerPacket(ServerOP_ZoneReboot, sizeof(ServerZoneReboot_Struct)); ServerZoneReboot_Struct* s = (ServerZoneReboot_Struct*) pack->pBuffer; diff --git a/zone/aa.cpp b/zone/aa.cpp index a8c6ff3d0..9cb6cf43f 100644 --- a/zone/aa.cpp +++ b/zone/aa.cpp @@ -988,13 +988,20 @@ void Client::BuyAA(AA_Action* action) } uint32 real_cost; + uint8 req_level; std::map::iterator RequiredLevel = AARequiredLevelAndCost.find(action->ability); if(RequiredLevel != AARequiredLevelAndCost.end()) { real_cost = RequiredLevel->second.Cost; + req_level = RequiredLevel->second.Level; } - else + else { real_cost = aa2->cost + (aa2->cost_inc * cur_level); + req_level = aa2->class_type + (aa2->level_inc * cur_level); + } + + if (req_level > GetLevel()) + return; //Cheater trying to Buy AA... if (m_pp.aapoints >= real_cost && cur_level < aa2->max_level) { SetAA(aa2->id, cur_level + 1); @@ -1471,21 +1478,22 @@ bool ZoneDatabase::LoadAAEffects2() { return true; } + void Client::ResetAA(){ - RefundAA(); + RefundAA(); uint32 i; - for(i=0;iAA = 0; aa[i]->value = 0; m_pp.aa_array[MAX_PP_AA_ARRAY].AA = 0; - m_pp.aa_array[MAX_PP_AA_ARRAY].value = 0; + m_pp.aa_array[MAX_PP_AA_ARRAY].value = 0; } std::map::iterator itr; - for(itr=aa_points.begin();itr!=aa_points.end();++itr) + for(itr = aa_points.begin(); itr != aa_points.end(); ++itr) aa_points[itr->first] = 0; - for(int i = 0; i < _maxLeaderAA; ++i) + for(int i = 0; i < _maxLeaderAA; ++i) m_pp.leader_abilities.ranks[i] = 0; m_pp.group_leadership_points = 0; @@ -1494,10 +1502,23 @@ void Client::ResetAA(){ m_pp.raid_leadership_exp = 0; database.DeleteCharacterAAs(this->CharacterID()); - SaveAA(); + SaveAA(); + SendClearAA(); + SendAAList(); SendAATable(); + SendAAStats(); database.DeleteCharacterLeadershipAAs(this->CharacterID()); - Kick(); + // undefined for these clients + if (GetClientVersionBit() & BIT_TitaniumAndEarlier) + Kick(); +} + +void Client::SendClearAA() +{ + EQApplicationPacket *outapp = new EQApplicationPacket(OP_ClearLeadershipAbilities, 0); + FastQueuePacket(&outapp); + outapp = new EQApplicationPacket(OP_ClearAA, 0); + FastQueuePacket(&outapp); } int Client::GroupLeadershipAAHealthEnhancement() diff --git a/zone/aggro.cpp b/zone/aggro.cpp index 8f5da2eaa..dc9aa50ec 100644 --- a/zone/aggro.cpp +++ b/zone/aggro.cpp @@ -15,18 +15,22 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #include "../common/debug.h" -#include -#include -#include "masterentity.h" #include "../common/faction.h" -#include "map.h" -#include "../common/spdat.h" -#include "../common/skills.h" -#include "../common/misc_functions.h" #include "../common/rulesys.h" -#include "string_ids.h" -#include +#include "../common/spdat.h" + +#include "client.h" +#include "corpse.h" +#include "entity.h" +#include "mob.h" + +#ifdef BOTS +#include "bot.h" +#endif + +#include "map.h" extern Zone* zone; //#define LOSDEBUG 6 @@ -329,7 +333,7 @@ bool Mob::CheckWillAggro(Mob *mob) { || ( fv == FACTION_THREATENLY - && MakeRandomInt(0,99) < THREATENLY_ARRGO_CHANCE - heroicCHA_mod + && zone->random.Roll(THREATENLY_ARRGO_CHANCE - heroicCHA_mod) ) ) ) @@ -1254,7 +1258,7 @@ bool Mob::PassCharismaCheck(Mob* caster, Mob* spellTarget, uint16 spell_id) { return true; //1: The mob has a default 25% chance of being allowed a resistance check against the charm. - if (MakeRandomInt(0, 99) > RuleI(Spells, CharmBreakCheckChance)) + if (zone->random.Int(0, 99) > RuleI(Spells, CharmBreakCheckChance)) return true; if (RuleB(Spells, CharismaCharmDuration)) @@ -1273,7 +1277,7 @@ bool Mob::PassCharismaCheck(Mob* caster, Mob* spellTarget, uint16 spell_id) { //3: At maxed ability, Total Domination has a 50% chance of preventing the charm break that otherwise would have occurred. int16 TotalDominationBonus = caster->aabonuses.CharmBreakChance + caster->spellbonuses.CharmBreakChance + caster->itembonuses.CharmBreakChance; - if (MakeRandomInt(0, 99) < TotalDominationBonus) + if (zone->random.Int(0, 99) < TotalDominationBonus) return true; } diff --git a/zone/attack.cpp b/zone/attack.cpp index 01513fa0d..253b85c31 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -340,7 +340,7 @@ bool Mob::CheckHitChance(Mob* other, SkillUseTypes skillinuse, int Hand, int16 c // Did we hit? // - float tohit_roll = MakeRandomFloat(0, 100); + float tohit_roll = zone->random.Real(0, 100); mlog(COMBAT__TOHIT, "Final hit chance: %.2f%%. Hit roll %.2f", chancetohit, tohit_roll); @@ -416,7 +416,7 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte) //Live AA - HightenedAwareness int BlockBehindChance = aabonuses.BlockBehind + spellbonuses.BlockBehind + itembonuses.BlockBehind; - if (BlockBehindChance && (BlockBehindChance > MakeRandomInt(1, 100))){ + if (BlockBehindChance && zone->random.Roll(BlockBehindChance)) { bBlockFromRear = true; if (spellbonuses.BlockBehind || itembonuses.BlockBehind) @@ -509,7 +509,7 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte) } if(damage > 0){ - roll = MakeRandomFloat(0,100); + roll = zone->random.Real(0,100); if(roll <= RollTable[0]){ damage = -3; } @@ -675,7 +675,7 @@ void Mob::MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttac if (acfail>100) acfail=100; } - if (acfail<=0 || MakeRandomInt(0, 100)>acfail) { + if (acfail<=0 || zone->random.Int(0, 100)>acfail) { float acreduction=1; int acrandom=300; if (database.GetVariable("ACreduction", tmp, 9)) @@ -694,7 +694,7 @@ void Mob::MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttac damage -= (int32) (GetAC() * acreduction/100.0f); } if (acrandom>0) { - damage -= (myac * MakeRandomInt(0, acrandom) / 10000); + damage -= (myac * zone->random.Int(0, acrandom) / 10000); } if (damage<1) damage=1; mlog(COMBAT__DAMAGE, "AC Damage Reduction: fail chance %d%%. Failed. Reduction %.3f%%, random %d. Resulting damage %d.", acfail, acreduction, acrandom, damage); @@ -722,8 +722,8 @@ int32 Mob::GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating) { float d = 10.0; - float mit_roll = MakeRandomFloat(0, mit_rating); - float atk_roll = MakeRandomFloat(0, atk_rating); + float mit_roll = zone->random.Real(0, mit_rating); + float atk_roll = zone->random.Real(0, atk_rating); if (atk_roll > mit_roll) { float a_diff = atk_roll - mit_roll; @@ -772,8 +772,8 @@ int32 Client::GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit, dmg_bonus -= dmg_bonus * (itembonuses.MeleeMitigation / 100.0); dmg_interval -= dmg_interval * spellMeleeMit; - float mit_roll = MakeRandomFloat(0, mit_rating); - float atk_roll = MakeRandomFloat(0, atk_rating); + float mit_roll = zone->random.Real(0, mit_rating); + float atk_roll = zone->random.Real(0, atk_rating); if (atk_roll > mit_roll) { float a_diff = atk_roll - mit_roll; @@ -1273,7 +1273,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b if(RuleB(Combat, UseIntervalAC)) damage = max_hit; else - damage = MakeRandomInt(min_hit, max_hit); + damage = zone->random.Int(min_hit, max_hit); damage = mod_client_damage(damage, skillinuse, Hand, weapon, other); @@ -1297,9 +1297,9 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b } else { //we hit, try to avoid it other->AvoidDamage(this, damage); other->MeleeMitigation(this, damage, min_hit, opts); - if(damage > 0) + if(damage > 0) CommonOutgoingHitSuccess(other, damage, skillinuse); - + mlog(COMBAT__DAMAGE, "Final damage after all reductions: %d", damage); } @@ -1315,7 +1315,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b OffhandRiposteFail *= -1; //Live uses a negative value for this. if (OffhandRiposteFail && - (OffhandRiposteFail > 99 || (MakeRandomInt(0, 100) < OffhandRiposteFail))) { + (OffhandRiposteFail > 99 || zone->random.Roll(OffhandRiposteFail))) { damage = 0; // Counts as a miss slippery_attack = true; } else @@ -1331,7 +1331,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b if (((damage < 0) || slippery_attack) && !bRiposte && !IsStrikethrough) { // Hack to still allow Strikethrough chance w/ Slippery Attacks AA int32 bonusStrikeThrough = itembonuses.StrikeThrough + spellbonuses.StrikeThrough + aabonuses.StrikeThrough; - if(bonusStrikeThrough && (MakeRandomInt(0, 100) < bonusStrikeThrough)) { + if(bonusStrikeThrough && zone->random.Roll(bonusStrikeThrough)) { Message_StringID(MT_StrikeThrough, STRIKETHROUGH_STRING); // You strike through your opponents defenses! Attack(other, Hand, false, true); // Strikethrough only gives another attempted hit return false; @@ -1844,7 +1844,7 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool if(RuleB(Combat, UseIntervalAC)) damage = (max_dmg+eleBane); else - damage = MakeRandomInt((min_dmg+eleBane),(max_dmg+eleBane)); + damage = zone->random.Int((min_dmg+eleBane),(max_dmg+eleBane)); //check if we're hitting above our max or below it. @@ -3451,17 +3451,16 @@ bool Client::CheckDoubleAttack(bool tripleAttack) { chance *= float(100.0f+triple_bonus)/100.0f; //Apply modifiers. } - if((MakeRandomFloat(0, 1) < chance)) + if(zone->random.Roll(chance)) return true; return false; } bool Client::CheckDoubleRangedAttack() { - int32 chance = spellbonuses.DoubleRangedAttack + itembonuses.DoubleRangedAttack + aabonuses.DoubleRangedAttack; - if(chance && (MakeRandomInt(0, 100) < chance)) + if(chance && zone->random.Roll(chance)) return true; return false; @@ -3478,7 +3477,7 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons mlog(COMBAT__DAMAGE, "Avoiding %d damage due to invulnerability.", damage); damage = -5; } - + if( spell_id != SPELL_UNKNOWN || attacker == nullptr ) avoidable = false; @@ -3645,7 +3644,7 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons } } - if (stun_chance && MakeRandomInt(0, 99) < stun_chance) { + if (stun_chance && zone->random.Roll(stun_chance)) { // Passed stun, try to resist now int stun_resist = itembonuses.StunResist + spellbonuses.StunResist; int frontal_stun_resist = itembonuses.FrontalStunResist + spellbonuses.FrontalStunResist; @@ -3658,18 +3657,18 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons // frontal stun check for ogres/bonuses if (((GetBaseRace() == OGRE && IsClient()) || - (frontal_stun_resist && MakeRandomInt(0, 99) < frontal_stun_resist)) && + (frontal_stun_resist && zone->random.Roll(frontal_stun_resist))) && !attacker->BehindMob(this, attacker->GetX(), attacker->GetY())) { mlog(COMBAT__HITS, "Frontal stun resisted. %d chance.", frontal_stun_resist); } else { // Normal stun resist check. - if (stun_resist && MakeRandomInt(0, 99) < stun_resist) { + if (stun_resist && zone->random.Roll(stun_resist)) { if (IsClient()) Message_StringID(MT_Stun, SHAKE_OFF_STUN); mlog(COMBAT__HITS, "Stun Resisted. %d chance.", stun_resist); } else { mlog(COMBAT__HITS, "Stunned. %d resist chance.", stun_resist); - Stun(MakeRandomInt(0, 2) * 1000); // 0-2 seconds + Stun(zone->random.Int(0, 2) * 1000); // 0-2 seconds } } } else { @@ -3950,7 +3949,7 @@ void Mob::TryDefensiveProc(const ItemInst* weapon, Mob *on, uint16 hand) { for (int i = 0; i < MAX_PROCS; i++) { if (IsValidSpell(DefensiveProcs[i].spellID)) { float chance = ProcChance * (static_cast(DefensiveProcs[i].chance)/100.0f); - if ((MakeRandomFloat(0, 1) <= chance)) { + if (zone->random.Roll(chance)) { ExecWeaponProc(nullptr, DefensiveProcs[i].spellID, on); CheckNumHitsRemaining(NUMHIT_DefensiveSpellProcs,0,DefensiveProcs[i].base_spellID); } @@ -4012,7 +4011,7 @@ void Mob::TryWeaponProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on if (weapon->Proc.Type == ET_CombatProc) { float WPC = ProcChance * (100.0f + // Proc chance for this weapon static_cast(weapon->ProcRate)) / 100.0f; - if (MakeRandomFloat(0, 1) <= WPC) { // 255 dex = 0.084 chance of proc. No idea what this number should be really. + if (zone->random.Roll(WPC)) { // 255 dex = 0.084 chance of proc. No idea what this number should be really. if (weapon->Proc.Level > ourlevel) { mlog(COMBAT__PROCS, "Tried to proc (%s), but our level (%d) is lower than required (%d)", @@ -4050,7 +4049,7 @@ void Mob::TryWeaponProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on if (aug->Proc.Type == ET_CombatProc) { float APC = ProcChance * (100.0f + // Proc chance for this aug static_cast(aug->ProcRate)) / 100.0f; - if (MakeRandomFloat(0, 1) <= APC) { + if (zone->random.Roll(APC)) { if (aug->Proc.Level > ourlevel) { if (IsPet()) { Mob *own = GetOwner(); @@ -4103,7 +4102,7 @@ void Mob::TrySpellProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on, if (!rangedattk) { // Perma procs (AAs) if (PermaProcs[i].spellID != SPELL_UNKNOWN) { - if (MakeRandomInt(0, 99) < PermaProcs[i].chance) { // TODO: Do these get spell bonus? + if (zone->random.Roll(PermaProcs[i].chance)) { // TODO: Do these get spell bonus? mlog(COMBAT__PROCS, "Permanent proc %d procing spell %d (%d percent chance)", i, PermaProcs[i].spellID, PermaProcs[i].chance); @@ -4118,7 +4117,7 @@ void Mob::TrySpellProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on, // Spell procs (buffs) if (SpellProcs[i].spellID != SPELL_UNKNOWN) { float chance = ProcChance * (static_cast(SpellProcs[i].chance) / 100.0f); - if (MakeRandomFloat(0, 1) <= chance) { + if (zone->random.Roll(chance)) { mlog(COMBAT__PROCS, "Spell proc %d procing spell %d (%.2f percent chance)", i, SpellProcs[i].spellID, chance); @@ -4134,7 +4133,7 @@ void Mob::TrySpellProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on, // ranged spell procs (buffs) if (RangedProcs[i].spellID != SPELL_UNKNOWN) { float chance = ProcChance * (static_cast(RangedProcs[i].chance) / 100.0f); - if (MakeRandomFloat(0, 1) <= chance) { + if (zone->random.Roll(chance)) { mlog(COMBAT__PROCS, "Ranged proc %d procing spell %d (%.2f percent chance)", i, RangedProcs[i].spellID, chance); @@ -4202,7 +4201,7 @@ void Mob::TryPetCriticalHit(Mob *defender, uint16 skill, int32 &damage) critChance /= 100; - if(MakeRandomFloat(0, 1) < critChance) + if(zone->random.Roll(critChance)) { critMod += GetCritDmgMob(skill) * 2; // To account for base crit mod being 200 not 100 damage = (damage * critMod) / 100; @@ -4241,7 +4240,7 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack int32 SlayRateBonus = aabonuses.SlayUndead[0] + itembonuses.SlayUndead[0] + spellbonuses.SlayUndead[0]; if (SlayRateBonus) { float slayChance = static_cast(SlayRateBonus) / 10000.0f; - if (MakeRandomFloat(0, 1) < slayChance) { + if (zone->random.Roll(slayChance)) { int32 SlayDmgBonus = aabonuses.SlayUndead[1] + itembonuses.SlayUndead[1] + spellbonuses.SlayUndead[1]; damage = (damage * SlayDmgBonus * 2.25) / 100; if (GetGender() == 1) // female @@ -4312,12 +4311,12 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack critChance /= 100; - if(MakeRandomFloat(0, 1) < critChance) + if(zone->random.Roll(critChance)) { uint32 critMod = 200; bool crip_success = false; int32 CripplingBlowChance = GetCrippBlowChance(); - + //Crippling Blow Chance: The percent value of the effect is applied //to the your Chance to Critical. (ie You have 10% chance to critical and you //have a 200% Chance to Critical Blow effect, therefore you have a 20% Chance to Critical Blow. @@ -4325,7 +4324,7 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack if (!IsBerserk() && !IsBerskerSPA) critChance *= float(CripplingBlowChance)/100.0f; - if ((IsBerserk() || IsBerskerSPA) || MakeRandomFloat(0, 1) < critChance) { + if ((IsBerserk() || IsBerskerSPA) || zone->random.Roll(critChance)) { critMod = 400; crip_success = true; } @@ -4335,7 +4334,7 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack damage = damage * critMod / 100; bool deadlySuccess = false; - if (deadlyChance && MakeRandomFloat(0, 1) < static_cast(deadlyChance) / 100.0f) { + if (deadlyChance && zone->random.Roll(static_cast(deadlyChance) / 100.0f)) { if (BehindMob(defender, GetX(), GetY())) { damage *= deadlyMod; deadlySuccess = true; @@ -4371,7 +4370,7 @@ bool Mob::TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse) if (defender && !defender->IsClient() && defender->GetHPRatio() < 10){ uint32 FB_Dmg = aabonuses.FinishingBlow[1] + spellbonuses.FinishingBlow[1] + itembonuses.FinishingBlow[1]; - + uint32 FB_Level = 0; FB_Level = aabonuses.FinishingBlowLvl[0]; if (FB_Level < spellbonuses.FinishingBlowLvl[0]) @@ -4382,7 +4381,7 @@ bool Mob::TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse) //Proc Chance value of 500 = 5% uint32 ProcChance = (aabonuses.FinishingBlow[0] + spellbonuses.FinishingBlow[0] + spellbonuses.FinishingBlow[0])/10; - if(FB_Level && FB_Dmg && (defender->GetLevel() <= FB_Level) && (ProcChance >= MakeRandomInt(0, 1000))){ + if(FB_Level && FB_Dmg && (defender->GetLevel() <= FB_Level) && (ProcChance >= zone->random.Int(0, 1000))){ entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, FINISHING_BLOW, GetName()); DoSpecialAttackDamage(defender, skillinuse, FB_Dmg, 1, -1, 10, false, false); return true; @@ -4409,7 +4408,7 @@ void Mob::DoRiposte(Mob* defender) { defender->itembonuses.DoubleRiposte; //Live AA - Double Riposte - if(DoubleRipChance && (DoubleRipChance >= MakeRandomInt(0, 100))) { + if(DoubleRipChance && zone->random.Roll(DoubleRipChance)) { mlog(COMBAT__ATTACKS, "Preforming a double riposed (%d percent chance)", DoubleRipChance); defender->Attack(this, MainPrimary, true); if (HasDied()) return; @@ -4420,7 +4419,7 @@ void Mob::DoRiposte(Mob* defender) { DoubleRipChance = defender->aabonuses.GiveDoubleRiposte[1]; - if(DoubleRipChance && (DoubleRipChance >= MakeRandomInt(0, 100))) { + if(DoubleRipChance && zone->random.Roll(DoubleRipChance)) { mlog(COMBAT__ATTACKS, "Preforming a return SPECIAL ATTACK (%d percent chance)", DoubleRipChance); if (defender->GetClass() == MONK) @@ -4523,7 +4522,7 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui uint16 proc_spell_id = 0; float ProcMod = 0; float chance = 0; - + if (IsDefensive) chance = on->GetSkillProcChances(ReuseTime, hand); else @@ -4532,16 +4531,14 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui if (spellbonuses.LimitToSkill[skill]){ for(int e = 0; e < MAX_SKILL_PROCS; e++){ - - if (CanProc && + if (CanProc && (!Success && spellbonuses.SkillProc[e] && IsValidSpell(spellbonuses.SkillProc[e])) || (Success && spellbonuses.SkillProcSuccess[e] && IsValidSpell(spellbonuses.SkillProcSuccess[e]))) { base_spell_id = spellbonuses.SkillProc[e]; base_spell_id = 0; ProcMod = 0; - + for (int i = 0; i < EFFECT_COUNT; i++) { - if (spells[base_spell_id].effectid[i] == SE_SkillProc) { proc_spell_id = spells[base_spell_id].base[i]; ProcMod = static_cast(spells[base_spell_id].base2[i]); @@ -4551,7 +4548,7 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui if (CanProc && spells[base_spell_id].base[i] == skill && IsValidSpell(proc_spell_id)) { float final_chance = chance * (ProcMod / 100.0f); - if (MakeRandomFloat(0, 1) <= final_chance) { + if (zone->random.Roll(final_chance)) { ExecWeaponProc(nullptr, proc_spell_id, on); CheckNumHitsRemaining(NUMHIT_OffensiveSpellProcs,0, base_spell_id); CanProc = false; @@ -4571,8 +4568,7 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui if (itembonuses.LimitToSkill[skill]){ CanProc = true; for(int e = 0; e < MAX_SKILL_PROCS; e++){ - - if (CanProc && + if (CanProc && (!Success && itembonuses.SkillProc[e] && IsValidSpell(itembonuses.SkillProc[e])) || (Success && itembonuses.SkillProcSuccess[e] && IsValidSpell(itembonuses.SkillProcSuccess[e]))) { base_spell_id = itembonuses.SkillProc[e]; @@ -4580,7 +4576,6 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui ProcMod = 0; for (int i = 0; i < EFFECT_COUNT; i++) { - if (spells[base_spell_id].effectid[i] == SE_SkillProc) { proc_spell_id = spells[base_spell_id].base[i]; ProcMod = static_cast(spells[base_spell_id].base2[i]); @@ -4590,7 +4585,7 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui if (CanProc && spells[base_spell_id].base[i] == skill && IsValidSpell(proc_spell_id)) { float final_chance = chance * (ProcMod / 100.0f); - if (MakeRandomFloat(0, 1) <= final_chance) { + if (zone->random.Roll(final_chance)) { ExecWeaponProc(nullptr, proc_spell_id, on); CanProc = false; break; @@ -4615,8 +4610,7 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui uint32 slot = 0; for(int e = 0; e < MAX_SKILL_PROCS; e++){ - - if (CanProc && + if (CanProc && (!Success && aabonuses.SkillProc[e]) || (Success && aabonuses.SkillProcSuccess[e])){ int aaid = aabonuses.SkillProc[e]; @@ -4643,7 +4637,7 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui if (CanProc && base1 == skill && IsValidSpell(proc_spell_id)) { float final_chance = chance * (ProcMod / 100.0f); - if (MakeRandomFloat(0, 1) <= final_chance) { + if (zone->random.Roll(final_chance)) { ExecWeaponProc(nullptr, proc_spell_id, on); CanProc = false; break; @@ -4664,62 +4658,58 @@ float Mob::GetSkillProcChances(uint16 ReuseTime, uint16 hand) { uint32 weapon_speed; float ProcChance = 0; - + if (!ReuseTime && hand) { - weapon_speed = GetWeaponSpeedbyHand(hand); - ProcChance = static_cast(weapon_speed) * (RuleR(Combat, AvgProcsPerMinute) / 60000.0f); - if (hand != MainPrimary) ProcChance /= 2; } - else + else ProcChance = static_cast(ReuseTime) * (RuleR(Combat, AvgProcsPerMinute) / 60000.0f); return ProcChance; } bool Mob::TryRootFadeByDamage(int buffslot, Mob* attacker) { - - /*Dev Quote 2010: http://forums.station.sony.com/eq/posts/list.m?topic_id=161443 - The Viscid Roots AA does the following: Reduces the chance for root to break by X percent. - There is no distinction of any kind between the caster inflicted damage, or anyone - else's damage. There is also no distinction between Direct and DOT damage in the root code. - - /* General Mechanics - - Check buffslot to make sure damage from a root does not cancel the root - - If multiple roots on target, always and only checks first root slot and if broken only removes that slots root. - - Only roots on determental spells can be broken by damage. + + /*Dev Quote 2010: http://forums.station.sony.com/eq/posts/list.m?topic_id=161443 + The Viscid Roots AA does the following: Reduces the chance for root to break by X percent. + There is no distinction of any kind between the caster inflicted damage, or anyone + else's damage. There is also no distinction between Direct and DOT damage in the root code. + + General Mechanics + - Check buffslot to make sure damage from a root does not cancel the root + - If multiple roots on target, always and only checks first root slot and if broken only removes that slots root. + - Only roots on determental spells can be broken by damage. - Root break chance values obtained from live parses. - */ - + */ + if (!attacker || !spellbonuses.Root[0] || spellbonuses.Root[1] < 0) - return false; - - if (IsDetrimentalSpell(spellbonuses.Root[1]) && spellbonuses.Root[1] != buffslot){ - - int BreakChance = RuleI(Spells, RootBreakFromSpells); - - BreakChance -= BreakChance*buffs[spellbonuses.Root[1]].RootBreakChance/100; + return false; + + if (IsDetrimentalSpell(spellbonuses.Root[1]) && spellbonuses.Root[1] != buffslot){ + int BreakChance = RuleI(Spells, RootBreakFromSpells); + + BreakChance -= BreakChance*buffs[spellbonuses.Root[1]].RootBreakChance/100; int level_diff = attacker->GetLevel() - GetLevel(); //Use baseline if level difference <= 1 (ie. If target is (1) level less than you, or equal or greater level) if (level_diff == 2) BreakChance = (BreakChance * 80) /100; //Decrease by 20%; - + else if (level_diff >= 3 && level_diff <= 20) BreakChance = (BreakChance * 60) /100; //Decrease by 40%; else if (level_diff > 21) BreakChance = (BreakChance * 20) /100; //Decrease by 80%; - - if (BreakChance < 1) - BreakChance = 1; - if (MakeRandomInt(0, 99) < BreakChance) { + if (BreakChance < 1) + BreakChance = 1; + + if (zone->random.Roll(BreakChance)) { if (!TryFadeEffect(spellbonuses.Root[1])) { BuffFadeBySlot(spellbonuses.Root[1]); @@ -4740,7 +4730,7 @@ int32 Mob::RuneAbsorb(int32 damage, uint16 type) for(uint32 slot = 0; slot < buff_max; slot++) { if(slot == spellbonuses.MeleeRune[1] && spellbonuses.MeleeRune[0] && buffs[slot].melee_rune && IsValidSpell(buffs[slot].spellid)){ int melee_rune_left = buffs[slot].melee_rune; - + if(melee_rune_left > damage) { melee_rune_left -= damage; diff --git a/zone/bot.cpp b/zone/bot.cpp index 496ddc7ae..9ae33318a 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -775,49 +775,49 @@ void Bot::GenerateAppearance() { // Randomize facial appearance int iFace = 0; if(this->GetRace() == 2) { // Barbarian w/Tatoo - iFace = MakeRandomInt(0, 79); + iFace = zone->random.Int(0, 79); } else { - iFace = MakeRandomInt(0, 7); + iFace = zone->random.Int(0, 7); } int iHair = 0; int iBeard = 0; int iBeardColor = 1; if(this->GetRace() == 522) { - iHair = MakeRandomInt(0, 8); - iBeard = MakeRandomInt(0, 11); - iBeardColor = MakeRandomInt(0, 3); + iHair = zone->random.Int(0, 8); + iBeard = zone->random.Int(0, 11); + iBeardColor = zone->random.Int(0, 3); } else if(this->GetGender()) { - iHair = MakeRandomInt(0, 2); + iHair = zone->random.Int(0, 2); if(this->GetRace() == 8) { // Dwarven Females can have a beard - if(MakeRandomInt(1, 100) < 50) { + if(zone->random.Int(1, 100) < 50) { iFace += 10; } } } else { - iHair = MakeRandomInt(0, 3); - iBeard = MakeRandomInt(0, 5); - iBeardColor = MakeRandomInt(0, 19); + iHair = zone->random.Int(0, 3); + iBeard = zone->random.Int(0, 5); + iBeardColor = zone->random.Int(0, 19); } int iHairColor = 0; if(this->GetRace() == 522) { - iHairColor = MakeRandomInt(0, 3); + iHairColor = zone->random.Int(0, 3); } else { - iHairColor = MakeRandomInt(0, 19); + iHairColor = zone->random.Int(0, 19); } - uint8 iEyeColor1 = (uint8)MakeRandomInt(0, 9); + uint8 iEyeColor1 = (uint8)zone->random.Int(0, 9); uint8 iEyeColor2 = 0; if(this->GetRace() == 522) { - iEyeColor1 = iEyeColor2 = (uint8)MakeRandomInt(0, 11); + iEyeColor1 = iEyeColor2 = (uint8)zone->random.Int(0, 11); } - else if(MakeRandomInt(1, 100) > 96) { - iEyeColor2 = MakeRandomInt(0, 9); + else if(zone->random.Int(1, 100) > 96) { + iEyeColor2 = zone->random.Int(0, 9); } else { iEyeColor2 = iEyeColor1; @@ -827,9 +827,9 @@ void Bot::GenerateAppearance() { int iTattoo = 0; int iDetails = 0; if(this->GetRace() == 522) { - iHeritage = MakeRandomInt(0, 6); - iTattoo = MakeRandomInt(0, 7); - iDetails = MakeRandomInt(0, 7); + iHeritage = zone->random.Int(0, 6); + iTattoo = zone->random.Int(0, 7); + iDetails = zone->random.Int(0, 7); } this->luclinface = iFace; @@ -3098,7 +3098,7 @@ bool Bot::CheckBotDoubleAttack(bool tripleAttack) { chance *= float(100.0f+triple_bonus)/100.0f; //Apply modifiers. } - if((MakeRandomFloat(0, 1) < chance)) + if((zone->random.Real(0, 1) < chance)) return true; return false; @@ -3148,7 +3148,7 @@ void Bot::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes if(RuleB(Combat, UseIntervalAC)) damage = max_hit; else - damage = MakeRandomInt(min_hit, max_hit); + damage = zone->random.Int(min_hit, max_hit); if(!other->CheckHitChance(this, skillinuse, Hand, chance_mod)) { damage = 0; @@ -3203,7 +3203,7 @@ void Bot::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes if (damage > 0) CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess); - if((skillinuse == SkillDragonPunch) && GetAA(aaDragonPunch) && MakeRandomInt(0, 99) < 25){ + if((skillinuse == SkillDragonPunch) && GetAA(aaDragonPunch) && zone->random.Int(0, 99) < 25){ SpellFinished(904, other, 10, 0, -1, spells[904].ResistDiff); other->Stun(100); } @@ -3483,7 +3483,7 @@ void Bot::AI_Process() { meleeDistance = meleeDistance * .30; } else { - meleeDistance *= (float)MakeRandomFloat(.50, .85); + meleeDistance *= (float)zone->random.Real(.50, .85); } bool atArcheryRange = IsArcheryRange(GetTarget()); @@ -3616,7 +3616,7 @@ void Bot::AI_Process() { if (GetTarget() && flurrychance) { - if(MakeRandomInt(0, 100) < flurrychance) + if(zone->random.Int(0, 100) < flurrychance) { Message_StringID(MT_NPCFlurry, YOU_FLURRY); Attack(GetTarget(), MainPrimary, false); @@ -3633,7 +3633,7 @@ void Bot::AI_Process() { wpn->GetItem()->ItemType == ItemType2HBlunt || wpn->GetItem()->ItemType == ItemType2HPiercing ) { - if(MakeRandomInt(0, 100) < ExtraAttackChanceBonus) + if(zone->random.Int(0, 100) < ExtraAttackChanceBonus) { Attack(GetTarget(), MainPrimary, false); } @@ -3678,7 +3678,7 @@ void Bot::AI_Process() { int32 DWBonus = spellbonuses.DualWieldChance + itembonuses.DualWieldChance; DualWieldProbability += DualWieldProbability*float(DWBonus)/ 100.0f; - float random = MakeRandomFloat(0, 1); + float random = zone->random.Real(0, 1); if (random < DualWieldProbability){ // Max 78% of DW @@ -3912,7 +3912,7 @@ void Bot::PetAIProcess() { if (botPet->GetTarget()) // Do we still have a target? { // We're a pet so we re able to dual attack - int32 RandRoll = MakeRandomInt(0, 99); + int32 RandRoll = zone->random.Int(0, 99); if (botPet->CanThisClassDoubleAttack() && (RandRoll < (botPet->GetLevel() + NPCDualAttackModifier))) { if(botPet->Attack(botPet->GetTarget(), MainPrimary)) @@ -3945,7 +3945,7 @@ void Bot::PetAIProcess() { //aa_chance += botPet->GetOwner()->GetAA(aaCompanionsAlacrity) * 3; - if (MakeRandomInt(1, 100) < aa_chance) + if (zone->random.Int(1, 100) < aa_chance) Flurry(nullptr); } @@ -3955,12 +3955,12 @@ void Bot::PetAIProcess() { if(botPet->GetOwner()->GetLevel() >= 24) { float DualWieldProbability = (botPet->GetSkill(SkillDualWield) + botPet->GetLevel()) / 400.0f; - DualWieldProbability -= MakeRandomFloat(0, 1); + DualWieldProbability -= zone->random.Real(0, 1); if(DualWieldProbability < 0){ botPet->Attack(botPet->GetTarget(), MainSecondary); if (botPet->CanThisClassDoubleAttack()) { - int32 RandRoll = MakeRandomInt(0, 99); + int32 RandRoll = zone->random.Int(0, 99); if (RandRoll < (botPet->GetLevel() + 20)) { botPet->Attack(botPet->GetTarget(), MainSecondary); @@ -6213,7 +6213,7 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b if(RuleB(Combat, UseIntervalAC)) damage = max_hit; else - damage = MakeRandomInt(min_hit, max_hit); + damage = zone->random.Int(min_hit, max_hit); mlog(COMBAT__DAMAGE, "Damage calculated to %d (min %d, max %d, str %d, skill %d, DMG %d, lv %d)", damage, min_hit, max_hit, GetSTR(), GetSkill(skillinuse), weapon_damage, GetLevel()); @@ -6258,7 +6258,7 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b OffhandRiposteFail *= -1; //Live uses a negative value for this. if (OffhandRiposteFail && - (OffhandRiposteFail > 99 || (MakeRandomInt(0, 100) < OffhandRiposteFail))) { + (OffhandRiposteFail > 99 || (zone->random.Int(0, 100) < OffhandRiposteFail))) { damage = 0; // Counts as a miss slippery_attack = true; } else @@ -6274,7 +6274,7 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b if (((damage < 0) || slippery_attack) && !FromRiposte && !IsStrikethrough) { // Hack to still allow Strikethrough chance w/ Slippery Attacks AA int32 bonusStrikeThrough = itembonuses.StrikeThrough + spellbonuses.StrikeThrough + aabonuses.StrikeThrough; - if(bonusStrikeThrough && (MakeRandomInt(0, 100) < bonusStrikeThrough)) { + if(bonusStrikeThrough && (zone->random.Int(0, 100) < bonusStrikeThrough)) { Message_StringID(MT_StrikeThrough, STRIKETHROUGH_STRING); // You strike through your opponents defenses! Attack(other, Hand, false, true); // Strikethrough only gives another attempted hit return false; @@ -6623,7 +6623,7 @@ int32 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id) { if(type == focusTriggerOnCast) { - if(MakeRandomInt(0, 100) <= base1){ + if(zone->random.Int(0, 100) <= base1){ value = base2; } @@ -6646,7 +6646,7 @@ int32 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id) { if(type == focusBlockNextSpell) { - if(MakeRandomInt(1, 100) <= base1) + if(zone->random.Int(1, 100) <= base1) value = 1; } break; @@ -6670,7 +6670,7 @@ int32 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id) int32 cast_time = GetActSpellCasttime(spell_id, spells[spell_id].cast_time); GetSympatheticProcChances(ProcBonus, ProcChance, cast_time, ProcRateMod); - if(MakeRandomFloat(0, 1) <= ProcChance) + if(zone->random.Real(0, 1) <= ProcChance) value = focus_id; else @@ -7147,7 +7147,7 @@ int32 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel value = focus_spell.base[i]; } else { - value = MakeRandomInt(focus_spell.base[i], focus_spell.base2[i]); + value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); } } break; @@ -7165,7 +7165,7 @@ int32 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel value = focus_spell.base[i]; } else { - value = MakeRandomInt(focus_spell.base[i], focus_spell.base2[i]); + value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); } } break; @@ -7183,7 +7183,7 @@ int32 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel value = focus_spell.base[i]; } else { - value = MakeRandomInt(focus_spell.base[i], focus_spell.base2[i]); + value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); } } break; @@ -7273,7 +7273,7 @@ int32 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel { if(bottype == BotfocusTriggerOnCast) - if(MakeRandomInt(0, 100) <= focus_spell.base[i]) + if(zone->random.Int(0, 100) <= focus_spell.base[i]) value = focus_spell.base2[i]; else @@ -7293,7 +7293,7 @@ int32 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel { if(bottype == BotfocusBlockNextSpell) { - if(MakeRandomInt(1, 100) <= focus_spell.base[i]) + if(zone->random.Int(1, 100) <= focus_spell.base[i]) value = 1; } break; @@ -7313,7 +7313,7 @@ int32 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel float ProcChance = GetSympatheticProcChances(spell_id, focus_spell.base[i]); - if(MakeRandomFloat(0, 1) <= ProcChance) + if(zone->random.Real(0, 1) <= ProcChance) value = focus_id; else @@ -7503,7 +7503,7 @@ bool Bot::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte) //Live AA - HightenedAwareness int BlockBehindChance = aabonuses.BlockBehind + spellbonuses.BlockBehind + itembonuses.BlockBehind; - if (BlockBehindChance && (BlockBehindChance > MakeRandomInt(1, 100))){ + if (BlockBehindChance && (BlockBehindChance > zone->random.Int(1, 100))){ bBlockFromRear = true; if (spellbonuses.BlockBehind || itembonuses.BlockBehind) @@ -7595,7 +7595,7 @@ bool Bot::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte) if(damage > 0) { - roll = MakeRandomFloat(0,100); + roll = zone->random.Real(0,100); if(roll <= RollTable[0]){ damage = -3; } @@ -7662,7 +7662,7 @@ bool Bot::TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse) uint32 damage = aabonuses.FinishingBlow[1]; uint16 levelreq = aabonuses.FinishingBlowLvl[0]; - if(defender->GetLevel() <= levelreq && (chance >= MakeRandomInt(0, 1000))){ + if(defender->GetLevel() <= levelreq && (chance >= zone->random.Int(0, 1000))){ mlog(COMBAT__ATTACKS, "Landed a finishing blow: levelreq at %d, other level %d", levelreq , defender->GetLevel()); entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, FINISHING_BLOW, GetName()); defender->Damage(this, damage, SPELL_UNKNOWN, skillinuse); @@ -7690,7 +7690,7 @@ void Bot::DoRiposte(Mob* defender) { defender->GetSpellBonuses().GiveDoubleRiposte[0] + defender->GetItemBonuses().GiveDoubleRiposte[0]; - if(DoubleRipChance && (DoubleRipChance >= MakeRandomInt(0, 100))) { + if(DoubleRipChance && (DoubleRipChance >= zone->random.Int(0, 100))) { mlog(COMBAT__ATTACKS, "Preforming a double riposte (%d percent chance)", DoubleRipChance); defender->Attack(this, MainPrimary, true); @@ -7700,7 +7700,7 @@ void Bot::DoRiposte(Mob* defender) { //Coded narrowly: Limit to one per client. Limit AA only. [1 = Skill Attack Chance, 2 = Skill] DoubleRipChance = defender->GetAABonuses().GiveDoubleRiposte[1]; - if(DoubleRipChance && (DoubleRipChance >= MakeRandomInt(0, 100))) { + if(DoubleRipChance && (DoubleRipChance >= zone->random.Int(0, 100))) { if (defender->GetClass() == MONK) defender->MonkSpecialAttack(this, defender->GetAABonuses().GiveDoubleRiposte[2]); else if (defender->IsBot()) @@ -7766,7 +7766,7 @@ void Bot::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int kb_chance = 25; kb_chance += kb_chance*(100-aabonuses.SpecialAttackKBProc[0])/100; - if (MakeRandomInt(0, 99) < kb_chance) + if (zone->random.Int(0, 99) < kb_chance) SpellFinished(904, who, 10, 0, -1, spells[904].ResistDiff); //who->Stun(100); Kayen: This effect does not stun on live, it only moves the NPC. } @@ -7807,7 +7807,7 @@ void Bot::TryBackstab(Mob *other, int ReuseTime) { //Live AA - Seized Opportunity int FrontalBSChance = itembonuses.FrontalBackstabChance + spellbonuses.FrontalBackstabChance + aabonuses.FrontalBackstabChance; - if (FrontalBSChance && (FrontalBSChance > MakeRandomInt(0, 100))) + if (FrontalBSChance && (FrontalBSChance > zone->random.Int(0, 100))) bCanFrontalBS = true; } @@ -7821,7 +7821,7 @@ void Bot::TryBackstab(Mob *other, int ReuseTime) { !other->CastToNPC()->IsEngaged() && // not aggro other->GetHP()<=32000 && other->IsNPC() - && MakeRandomFloat(0, 99) < chance // chance + && zone->random.Real(0, 99) < chance // chance ) { entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, ASSASSINATES, GetName()); RogueAssassinate(other); @@ -7832,12 +7832,12 @@ void Bot::TryBackstab(Mob *other, int ReuseTime) { float DoubleAttackProbability = (GetSkill(SkillDoubleAttack) + GetLevel()) / 500.0f; // 62.4 max // Check for double attack with main hand assuming maxed DA Skill (MS) - if(MakeRandomFloat(0, 1) < DoubleAttackProbability) // Max 62.4 % chance of DA + if(zone->random.Real(0, 1) < DoubleAttackProbability) // Max 62.4 % chance of DA { if(other->GetHP() > 0) RogueBackstab(other,false,ReuseTime); - if (tripleChance && other->GetHP() > 0 && tripleChance > MakeRandomInt(0, 100)) + if (tripleChance && other->GetHP() > 0 && tripleChance > zone->random.Int(0, 100)) RogueBackstab(other,false,ReuseTime); } } @@ -7851,11 +7851,11 @@ void Bot::TryBackstab(Mob *other, int ReuseTime) { if (level > 54) { float DoubleAttackProbability = (GetSkill(SkillDoubleAttack) + GetLevel()) / 500.0f; // 62.4 max // Check for double attack with main hand assuming maxed DA Skill (MS) - if(MakeRandomFloat(0, 1) < DoubleAttackProbability) // Max 62.4 % chance of DA + if(zone->random.Real(0, 1) < DoubleAttackProbability) // Max 62.4 % chance of DA if(other->GetHP() > 0) RogueBackstab(other,true, ReuseTime); - if (tripleChance && other->GetHP() > 0 && tripleChance > MakeRandomInt(0, 100)) + if (tripleChance && other->GetHP() > 0 && tripleChance > zone->random.Int(0, 100)) RogueBackstab(other,false,ReuseTime); } } @@ -7929,7 +7929,7 @@ void Bot::RogueBackstab(Mob* other, bool min_damage, int ReuseTime) if(RuleB(Combat, UseIntervalAC)) ndamage = max_hit; else - ndamage = MakeRandomInt(min_hit, max_hit); + ndamage = zone->random.Int(min_hit, max_hit); } } @@ -8036,7 +8036,7 @@ void Bot::DoClassAttacks(Mob *target, bool IsRiposte) { canBash = true; } - if(!canBash || MakeRandomInt(0, 100) > 25) { //tested on live, warrior mobs both kick and bash, kick about 75% of the time, casting doesn't seem to make a difference. + if(!canBash || zone->random.Int(0, 100) > 25) { //tested on live, warrior mobs both kick and bash, kick about 75% of the time, casting doesn't seem to make a difference. skill_to_use = SkillKick; } else { @@ -8117,7 +8117,7 @@ void Bot::DoClassAttacks(Mob *target, bool IsRiposte) { if(RuleB(Combat, UseIntervalAC)) dmg = GetBashDamage(); else - dmg = MakeRandomInt(1, GetBashDamage()); + dmg = zone->random.Int(1, GetBashDamage()); } } @@ -8164,7 +8164,7 @@ void Bot::DoClassAttacks(Mob *target, bool IsRiposte) { //Live parses show around 55% Triple 35% Double 10% Single, you will always get first hit. while(AtkRounds > 0) { - if (GetTarget() && (AtkRounds == 1 || MakeRandomInt(0,100) < 75)){ + if (GetTarget() && (AtkRounds == 1 || zone->random.Int(0,100) < 75)){ DoSpecialAttackDamage(GetTarget(), SkillFrenzy, max_dmg, min_dmg, max_dmg , reuse, true); } AtkRounds--; @@ -8192,7 +8192,7 @@ void Bot::DoClassAttacks(Mob *target, bool IsRiposte) { if(RuleB(Combat, UseIntervalAC)) dmg = GetKickDamage(); else - dmg = MakeRandomInt(1, GetKickDamage()); + dmg = zone->random.Int(1, GetKickDamage()); } } @@ -8215,18 +8215,18 @@ void Bot::DoClassAttacks(Mob *target, bool IsRiposte) { //Live AA - Technique of Master Wu uint32 bDoubleSpecialAttack = itembonuses.DoubleSpecialAttack + spellbonuses.DoubleSpecialAttack + aabonuses.DoubleSpecialAttack; - if( bDoubleSpecialAttack && (bDoubleSpecialAttack >= 100 || bDoubleSpecialAttack > MakeRandomInt(0,100))) { + if( bDoubleSpecialAttack && (bDoubleSpecialAttack >= 100 || bDoubleSpecialAttack > zone->random.Int(0,100))) { int MonkSPA [5] = { SkillFlyingKick, SkillDragonPunch, SkillEagleStrike, SkillTigerClaw, SkillRoundKick }; - MonkSpecialAttack(target, MonkSPA[MakeRandomInt(0,4)]); + MonkSpecialAttack(target, MonkSPA[zone->random.Int(0,4)]); int TripleChance = 25; if (bDoubleSpecialAttack > 100) TripleChance += TripleChance*(100-bDoubleSpecialAttack)/100; - if(TripleChance > MakeRandomInt(0,100)) { - MonkSpecialAttack(target, MonkSPA[MakeRandomInt(0,4)]); + if(TripleChance > zone->random.Int(0,100)) { + MonkSpecialAttack(target, MonkSPA[zone->random.Int(0,4)]); } } @@ -8259,7 +8259,7 @@ bool Bot::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) { // WildcardX: These chance formula's below are arbitrary. If someone has a better formula that is more // consistent with live, feel free to update these. float AttackerChance = 0.20f + ((float)(rangerLevel - 51) * 0.005f); - float DefenderChance = (float)MakeRandomFloat(0.00f, 1.00f); + float DefenderChance = (float)zone->random.Real(0.00f, 1.00f); if(AttackerChance > DefenderChance) { mlog(COMBAT__ATTACKS, "Landed a headshot: Attacker chance was %f and Defender chance was %f.", AttackerChance, DefenderChance); // WildcardX: At the time I wrote this, there wasnt a string id for something like HEADSHOT_BLOW @@ -8734,14 +8734,14 @@ int32 Bot::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { if (spell_id == SPELL_IMP_HARM_TOUCH && (GetAA(aaSpellCastingFury) > 0) && (GetAA(aaUnholyTouch) > 0)) chance = 100; - if (MakeRandomInt(1,100) <= chance){ + if (zone->random.Int(1,100) <= chance){ Critical = true; ratio += itembonuses.SpellCritDmgIncrease + spellbonuses.SpellCritDmgIncrease + aabonuses.SpellCritDmgIncrease; ratio += itembonuses.SpellCritDmgIncNoStack + spellbonuses.SpellCritDmgIncNoStack + aabonuses.SpellCritDmgIncNoStack; } - else if (GetClass() == WIZARD && (GetLevel() >= RuleI(Spells, WizCritLevel)) && (MakeRandomInt(1,100) <= RuleI(Spells, WizCritChance))) { - ratio = MakeRandomInt(1,100); //Wizard innate critical chance is calculated seperately from spell effect and is not a set ratio. + else if (GetClass() == WIZARD && (GetLevel() >= RuleI(Spells, WizCritLevel)) && (zone->random.Int(1,100) <= RuleI(Spells, WizCritChance))) { + ratio = zone->random.Int(1,100); //Wizard innate critical chance is calculated seperately from spell effect and is not a set ratio. Critical = true; } @@ -8820,7 +8820,7 @@ int32 Bot::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { if (spellbonuses.CriticalHealDecay) chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay); - if(chance && (MakeRandomInt(0,99) < chance)) { + if(chance && (zone->random.Int(0,99) < chance)) { Critical = true; modifier = 2; //At present time no critical heal amount modifier SPA exists. } @@ -8851,7 +8851,7 @@ int32 Bot::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { if (spellbonuses.CriticalRegenDecay) chance += GetDecayEffectValue(spell_id, SE_CriticalRegenDecay); - if(chance && (MakeRandomInt(0,99) < chance)) + if(chance && (zone->random.Int(0,99) < chance)) return (value * 2); } @@ -8950,7 +8950,7 @@ int32 Bot::GetActSpellCost(uint16 spell_id, int32 cost) { // Formula = Unknown exact, based off a random percent chance up to mana cost(after focuses) of the cast spell if(this->itembonuses.Clairvoyance && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) { - int32 mana_back = this->itembonuses.Clairvoyance * MakeRandomInt(1, 100) / 100; + int32 mana_back = this->itembonuses.Clairvoyance * zone->random.Int(1, 100) / 100; // Doesnt generate mana, so best case is a free spell if(mana_back > cost) mana_back = cost; @@ -8963,7 +8963,7 @@ int32 Bot::GetActSpellCost(uint16 spell_id, int32 cost) { // WildcardX float PercentManaReduction = 0; float SpecializeSkill = GetSpecializeSkillValue(spell_id); - int SuccessChance = MakeRandomInt(0, 100); + int SuccessChance = zone->random.Int(0, 100); float bonus = 1.0; switch(GetAA(aaSpellCastingMastery)) @@ -9015,7 +9015,7 @@ int32 Bot::GetActSpellCost(uint16 spell_id, int32 cost) { if(focus_redux > 0) { - PercentManaReduction += MakeRandomFloat(1, (double)focus_redux); + PercentManaReduction += zone->random.Real(1, (double)focus_redux); } cost -= (cost * (PercentManaReduction / 100)); @@ -15580,7 +15580,7 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl return false; if (iChance < 100) { - uint8 tmp = MakeRandomInt(1, 100); + uint8 tmp = zone->random.Int(1, 100); if (tmp > iChance) return false; } diff --git a/zone/botspellsai.cpp b/zone/botspellsai.cpp index 4917ed953..a5be7341e 100644 --- a/zone/botspellsai.cpp +++ b/zone/botspellsai.cpp @@ -13,7 +13,7 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) { return false; if (iChance < 100) { - if (MakeRandomInt(0, 100) > iChance){ + if (zone->random.Int(0, 100) > iChance){ return false; } } @@ -485,7 +485,7 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) { if(botClass == PALADIN) stunChance = 50; - if(!tar->GetSpecialAbility(UNSTUNABLE) && !tar->IsStunned() && (MakeRandomInt(1, 100) <= stunChance)) { + if(!tar->GetSpecialAbility(UNSTUNABLE) && !tar->IsStunned() && (zone->random.Int(1, 100) <= stunChance)) { botSpell = GetBestBotSpellForStunByTargetType(this, ST_Target); } } @@ -1843,7 +1843,7 @@ std::string Bot::GetBotMagicianPetType(Bot* botCaster) { result = std::string("SumEarth"); else if(botCaster->GetLevel() < 30) { // Under level 30 - int counter = MakeRandomInt(0, 3); + int counter = zone->random.Int(0, 3); switch(counter) { case 0: @@ -1865,7 +1865,7 @@ std::string Bot::GetBotMagicianPetType(Bot* botCaster) { } else { // Over level 30 - int counter = MakeRandomInt(0, 4); + int counter = zone->random.Int(0, 4); switch(counter) { case 0: diff --git a/zone/client.cpp b/zone/client.cpp index e4f2c823a..f67328ae9 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -2328,7 +2328,7 @@ bool Client::CheckIncreaseSkill(SkillUseTypes skillid, Mob *against_who, int cha if(Chance < 1) Chance = 1; // Make it always possible - if(MakeRandomFloat(0, 99) < Chance) + if(zone->random.Real(0, 99) < Chance) { SetSkill(skillid, GetRawSkill(skillid) + 1); _log(SKILLS__GAIN, "Skill %d at value %d successfully gain with %.4f%%chance (mod %d)", skillid, skillval, Chance, chancemodi); @@ -2356,7 +2356,7 @@ void Client::CheckLanguageSkillIncrease(uint8 langid, uint8 TeacherSkill) { int32 Chance = 5 + ((TeacherSkill - LangSkill)/10); // greater chance to learn if teacher's skill is much higher than yours Chance = (Chance * RuleI(Character, SkillUpModifier)/100); - if(MakeRandomFloat(0,100) < Chance) { // if they make the roll + if(zone->random.Real(0,100) < Chance) { // if they make the roll IncreaseLanguageSkill(langid); // increase the language skill by 1 _log(SKILLS__GAIN, "Language %d at value %d successfully gain with %.4f%%chance", langid, LangSkill, Chance); } @@ -4904,7 +4904,7 @@ int Client::LDoNChest_SkillCheck(NPC *target, int skill) chance = 100.0f - base_difficulty; } - float d100 = (float)MakeRandomFloat(0, 100); + float d100 = (float)zone->random.Real(0, 100); if(d100 <= chance) return 1; @@ -7608,9 +7608,9 @@ void Client::GarbleMessage(char *message, uint8 variance) const char alpha_list[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; // only change alpha characters for now for (size_t i = 0; i < strlen(message); i++) { - uint8 chance = (uint8)MakeRandomInt(0, 115); // variation just over worst possible scrambling + uint8 chance = (uint8)zone->random.Int(0, 115); // variation just over worst possible scrambling if (isalpha(message[i]) && (chance <= variance)) { - uint8 rand_char = (uint8)MakeRandomInt(0,51); // choose a random character from the alpha list + uint8 rand_char = (uint8)zone->random.Int(0,51); // choose a random character from the alpha list message[i] = alpha_list[rand_char]; } } @@ -7728,7 +7728,7 @@ void Client::SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, ui // If our result is truncated, then double a mob's value every once and a while to equal what they would have got else { - if (MakeRandomInt(0, 100) < faction_mod) + if (zone->random.Int(0, 100) < faction_mod) npc_value[i] *= 2; } } @@ -7821,11 +7821,11 @@ void Client::MerchantRejectMessage(Mob *merchant, int primaryfaction) } // If no primary faction or biggest influence is your faction hit if (primaryfaction <= 0 || lowestvalue == tmpFactionValue) { - merchant->Say_StringID(MakeRandomInt(WONT_SELL_DEEDS1, WONT_SELL_DEEDS6)); + merchant->Say_StringID(zone->random.Int(WONT_SELL_DEEDS1, WONT_SELL_DEEDS6)); } else if (lowestvalue == fmod.race_mod) { // race biggest // Non-standard race (ex. illusioned to wolf) if (GetRace() > PLAYER_RACE_COUNT) { - messageid = MakeRandomInt(1, 3); // these aren't sequential StringIDs :( + messageid = zone->random.Int(1, 3); // these aren't sequential StringIDs :( switch (messageid) { case 1: messageid = WONT_SELL_NONSTDRACE1; @@ -7842,7 +7842,7 @@ void Client::MerchantRejectMessage(Mob *merchant, int primaryfaction) } merchant->Say_StringID(messageid); } else { // normal player races - messageid = MakeRandomInt(1, 4); + messageid = zone->random.Int(1, 4); switch (messageid) { case 1: messageid = WONT_SELL_RACE1; @@ -7863,7 +7863,7 @@ void Client::MerchantRejectMessage(Mob *merchant, int primaryfaction) merchant->Say_StringID(messageid, itoa(GetRace())); } } else if (lowestvalue == fmod.class_mod) { - merchant->Say_StringID(MakeRandomInt(WONT_SELL_CLASS1, WONT_SELL_CLASS5), itoa(GetClass())); + merchant->Say_StringID(zone->random.Int(WONT_SELL_CLASS1, WONT_SELL_CLASS5), itoa(GetClass())); } return; } @@ -7966,7 +7966,7 @@ void Client::TryItemTick(int slot) if(zone->tick_items.count(iid) > 0) { - if( GetLevel() >= zone->tick_items[iid].level && MakeRandomInt(0, 100) >= (100 - zone->tick_items[iid].chance) && (zone->tick_items[iid].bagslot || slot <= EmuConstants::EQUIPMENT_END) ) + if( GetLevel() >= zone->tick_items[iid].level && zone->random.Int(0, 100) >= (100 - zone->tick_items[iid].chance) && (zone->tick_items[iid].bagslot || slot <= EmuConstants::EQUIPMENT_END) ) { ItemInst* e_inst = (ItemInst*)inst; parse->EventItem(EVENT_ITEM_TICK, this, e_inst, nullptr, "", slot); @@ -7985,7 +7985,7 @@ void Client::TryItemTick(int slot) if(zone->tick_items.count(iid) > 0) { - if( GetLevel() >= zone->tick_items[iid].level && MakeRandomInt(0, 100) >= (100 - zone->tick_items[iid].chance) ) + if( GetLevel() >= zone->tick_items[iid].level && zone->random.Int(0, 100) >= (100 - zone->tick_items[iid].chance) ) { ItemInst* e_inst = (ItemInst*)a_inst; parse->EventItem(EVENT_ITEM_TICK, this, e_inst, nullptr, "", slot); diff --git a/zone/client.h b/zone/client.h index 4c69917fd..a63f37b2f 100644 --- a/zone/client.h +++ b/zone/client.h @@ -755,6 +755,7 @@ public: //AA Methods void SendAAList(); void ResetAA(); + void SendClearAA(); void SendAA(uint32 id, int seq=1); void SendPreviousAA(uint32 id, int seq=1); void BuyAA(AA_Action* action); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 8d9d22650..4caaf5641 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -2956,7 +2956,7 @@ void Client::Handle_OP_ApplyPoison(const EQApplicationPacket *app) if ((PrimaryWeapon && PrimaryWeapon->GetItem()->ItemType == ItemType1HPiercing) || (SecondaryWeapon && SecondaryWeapon->GetItem()->ItemType == ItemType1HPiercing)) { float SuccessChance = (GetSkill(SkillApplyPoison) + GetLevel()) / 400.0f; - double ChanceRoll = MakeRandomFloat(0, 1); + double ChanceRoll = zone->random.Real(0, 1); CheckIncreaseSkill(SkillApplyPoison, nullptr, 10); @@ -3660,14 +3660,14 @@ void Client::Handle_OP_Begging(const EQApplicationPacket *app) return; } - int RandomChance = MakeRandomInt(0, 100); + int RandomChance = zone->random.Int(0, 100); int ChanceToAttack = 0; if (GetLevel() > GetTarget()->GetLevel()) - ChanceToAttack = MakeRandomInt(0, 15); + ChanceToAttack = zone->random.Int(0, 15); else - ChanceToAttack = MakeRandomInt(((this->GetTarget()->GetLevel() - this->GetLevel()) * 10) - 5, ((this->GetTarget()->GetLevel() - this->GetLevel()) * 10)); + ChanceToAttack = zone->random.Int(((this->GetTarget()->GetLevel() - this->GetLevel()) * 10) - 5, ((this->GetTarget()->GetLevel() - this->GetLevel()) * 10)); if (ChanceToAttack < 0) ChanceToAttack = -ChanceToAttack; @@ -3686,7 +3686,7 @@ void Client::Handle_OP_Begging(const EQApplicationPacket *app) if (RandomChance < ChanceToBeg) { - brs->Amount = MakeRandomInt(1, 10); + brs->Amount = zone->random.Int(1, 10); // This needs some work to determine how much money they can beg, based on skill level etc. if (CurrentSkill < 50) { @@ -4581,7 +4581,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) delta_heading = ppu->delta_heading; if(IsTracking() && ((x_pos!=ppu->x_pos) || (y_pos!=ppu->y_pos))){ - if(MakeRandomFloat(0, 100) < 70)//should be good + if(zone->random.Real(0, 100) < 70)//should be good CheckIncreaseSkill(SkillTracking, nullptr, -20); } @@ -5283,16 +5283,16 @@ void Client::Handle_OP_DisarmTraps(const EQApplicationPacket *app) if (trap && trap->detected) { int uskill = GetSkill(SkillDisarmTraps); - if ((MakeRandomInt(0, 49) + uskill) >= (MakeRandomInt(0, 49) + trap->skill)) + if ((zone->random.Int(0, 49) + uskill) >= (zone->random.Int(0, 49) + trap->skill)) { Message(MT_Skills, "You disarm a trap."); trap->disarmed = true; trap->chkarea_timer.Disable(); - trap->respawn_timer.Start((trap->respawn_time + MakeRandomInt(0, trap->respawn_var)) * 1000); + trap->respawn_timer.Start((trap->respawn_time + zone->random.Int(0, trap->respawn_var)) * 1000); } else { - if (MakeRandomInt(0, 99) < 25){ + if (zone->random.Int(0, 99) < 25){ Message(MT_Skills, "You set off the trap while trying to disarm it!"); trap->Trigger(this); } @@ -5653,7 +5653,7 @@ void Client::Handle_OP_FeignDeath(const EQApplicationPacket *app) secfeign = 0; uint16 totalfeign = primfeign + secfeign; - if (MakeRandomFloat(0, 160) > totalfeign) { + if (zone->random.Real(0, 160) > totalfeign) { SetFeigned(false); entity_list.MessageClose_StringID(this, false, 200, 10, STRING_FEIGNFAILED, GetName()); } @@ -7917,7 +7917,7 @@ void Client::Handle_OP_Hide(const EQApplicationPacket *app) p_timers.Start(pTimerHide, reuse - 1); float hidechance = ((GetSkill(SkillHide) / 250.0f) + .25) * 100; - float random = MakeRandomFloat(0, 100); + float random = zone->random.Real(0, 100); CheckIncreaseSkill(SkillHide, nullptr, 5); if (random < hidechance) { EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); @@ -7941,7 +7941,7 @@ void Client::Handle_OP_Hide(const EQApplicationPacket *app) Mob *evadetar = GetTarget(); if (!auto_attack && (evadetar && evadetar->CheckAggro(this) && evadetar->IsNPC())) { - if (MakeRandomInt(0, 260) < (int)GetSkill(SkillHide)) { + if (zone->random.Int(0, 260) < (int)GetSkill(SkillHide)) { msg->string_id = EVADE_SUCCESS; RogueEvade(evadetar); } @@ -9324,11 +9324,11 @@ void Client::Handle_OP_Mend(const EQApplicationPacket *app) int mendhp = GetMaxHP() / 4; int currenthp = GetHP(); - if (MakeRandomInt(0, 199) < (int)GetSkill(SkillMend)) { + if (zone->random.Int(0, 199) < (int)GetSkill(SkillMend)) { int criticalchance = spellbonuses.CriticalMend + itembonuses.CriticalMend + aabonuses.CriticalMend; - if (MakeRandomInt(0, 99) < criticalchance){ + if (zone->random.Int(0, 99) < criticalchance){ mendhp *= 2; Message_StringID(4, MEND_CRITICAL); } @@ -9343,7 +9343,7 @@ void Client::Handle_OP_Mend(const EQApplicationPacket *app) 0 skill - 25% chance to worsen 20 skill - 23% chance to worsen 50 skill - 16% chance to worsen */ - if ((GetSkill(SkillMend) <= 75) && (MakeRandomInt(GetSkill(SkillMend), 100) < 75) && (MakeRandomInt(1, 3) == 1)) + if ((GetSkill(SkillMend) <= 75) && (zone->random.Int(GetSkill(SkillMend), 100) < 75) && (zone->random.Int(1, 3) == 1)) { SetHP(currenthp > mendhp ? (GetHP() - mendhp) : 1); SendHPUpdate(); @@ -10648,37 +10648,28 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) case RaidCommandInviteIntoExisting: case RaidCommandInvite: { Client *i = entity_list.GetClientByName(ri->player_name); - if (i){ - Group *g = i->GetGroup(); - if (g){ - if (g->IsLeader(i) == false) - Message(13, "You can only invite an ungrouped player or group leader to join your raid."); - else{ - //This sends an "invite" to the client in question. - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); - RaidGeneral_Struct *rg = (RaidGeneral_Struct*)outapp->pBuffer; - strn0cpy(rg->leader_name, ri->leader_name, 64); - strn0cpy(rg->player_name, ri->player_name, 64); - - rg->parameter = 0; - rg->action = 20; - i->QueuePacket(outapp); - safe_delete(outapp); - } - } - else{ - //This sends an "invite" to the client in question. - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); - RaidGeneral_Struct *rg = (RaidGeneral_Struct*)outapp->pBuffer; - strn0cpy(rg->leader_name, ri->leader_name, 64); - strn0cpy(rg->player_name, ri->player_name, 64); - - rg->parameter = 0; - rg->action = 20; - i->QueuePacket(outapp); - safe_delete(outapp); - } + if (!i) + break; + Group *g = i->GetGroup(); + // These two messages should be generated by the client I think, just do this for now + if (i->HasRaid()) { + Message(13, "%s is already in a raid.", i->GetName()); + break; } + if (g && !g->IsLeader(i)) { + Message(13, "You can only invite an ungrouped player or group leader to join your raid."); + break; + } + //This sends an "invite" to the client in question. + EQApplicationPacket* outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); + RaidGeneral_Struct *rg = (RaidGeneral_Struct*)outapp->pBuffer; + strn0cpy(rg->leader_name, ri->leader_name, 64); + strn0cpy(rg->player_name, ri->player_name, 64); + + rg->parameter = 0; + rg->action = 20; + i->QueuePacket(outapp); + safe_delete(outapp); break; } case RaidCommandAcceptInvite: { @@ -11244,7 +11235,7 @@ void Client::Handle_OP_RandomReq(const EQApplicationPacket *app) randLow = 0; randHigh = 100; } - randResult = MakeRandomInt(randLow, randHigh); + randResult = zone->random.Int(randLow, randHigh); EQApplicationPacket* outapp = new EQApplicationPacket(OP_RandomReply, sizeof(RandomReply_Struct)); RandomReply_Struct* rr = (RandomReply_Struct*)outapp->pBuffer; @@ -11734,7 +11725,7 @@ void Client::Handle_OP_SenseTraps(const EQApplicationPacket *app) if (trap && trap->skill > 0) { int uskill = GetSkill(SkillSenseTraps); - if ((MakeRandomInt(0, 99) + uskill) >= (MakeRandomInt(0, 99) + trap->skill*0.75)) + if ((zone->random.Int(0, 99) + uskill) >= (zone->random.Int(0, 99) + trap->skill*0.75)) { float xdif = trap->x - GetX(); float ydif = trap->y - GetY(); @@ -12477,7 +12468,7 @@ void Client::Handle_OP_ShopRequest(const EQApplicationPacket *app) // 1199 I don't have time for that now. etc if (!tmp->CastToNPC()->IsMerchantOpen()) { - tmp->Say_StringID(MakeRandomInt(1199, 1202)); + tmp->Say_StringID(zone->random.Int(1199, 1202)); action = 0; } @@ -12532,7 +12523,7 @@ void Client::Handle_OP_Sneak(const EQApplicationPacket *app) CheckIncreaseSkill(SkillSneak, nullptr, 5); } float hidechance = ((GetSkill(SkillSneak) / 300.0f) + .25) * 100; - float random = MakeRandomFloat(0, 99); + float random = zone->random.Real(0, 99); if (!was && random < hidechance) { sneaking = true; } diff --git a/zone/client_process.cpp b/zone/client_process.cpp index c2e3ae1f3..0b99b1c2a 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -436,7 +436,7 @@ bool Client::Process() { if (auto_attack_target && flurrychance) { - if(MakeRandomInt(0, 99) < flurrychance) + if(zone->random.Int(0, 99) < flurrychance) { Message_StringID(MT_NPCFlurry, YOU_FLURRY); Attack(auto_attack_target, MainPrimary, false); @@ -453,7 +453,7 @@ bool Client::Process() { wpn->GetItem()->ItemType == ItemType2HBlunt || wpn->GetItem()->ItemType == ItemType2HPiercing ) { - if(MakeRandomInt(0, 99) < ExtraAttackChanceBonus) + if(zone->random.Int(0, 99) < ExtraAttackChanceBonus) { Attack(auto_attack_target, MainPrimary, false); } @@ -498,7 +498,7 @@ bool Client::Process() { int16 DWBonus = spellbonuses.DualWieldChance + itembonuses.DualWieldChance; DualWieldProbability += DualWieldProbability*float(DWBonus)/ 100.0f; - float random = MakeRandomFloat(0, 1); + float random = zone->random.Real(0, 1); CheckIncreaseSkill(SkillDualWield, auto_attack_target, -10); if (random < DualWieldProbability){ // Max 78% of DW if(CheckAAEffect(aaEffectRampage)) { @@ -1003,7 +1003,7 @@ void Client::BulkSendMerchantInventory(int merchant_id, int npcid) { if (fac != 0 && GetModCharacterFactionLevel(fac) < ml.faction_required) continue; - handychance = MakeRandomInt(0, merlist.size() + tmp_merlist.size() - 1); + handychance = zone->random.Int(0, merlist.size() + tmp_merlist.size() - 1); item = database.GetItem(ml.item); if (item) { @@ -1079,7 +1079,7 @@ void Client::BulkSendMerchantInventory(int merchant_id, int npcid) { zone->tmpmerchanttable[npcid] = tmp_merlist; if (merch != nullptr && handyitem) { char handy_id[8] = { 0 }; - int greeting = MakeRandomInt(0, 4); + int greeting = zone->random.Int(0, 4); int greet_id = 0; switch (greeting) { case 1: @@ -1640,7 +1640,7 @@ void Client::OPGMTraining(const EQApplicationPacket *app) // welcome message if (pTrainer && pTrainer->IsNPC()) { - pTrainer->Say_StringID(MakeRandomInt(1204, 1207), GetCleanName()); + pTrainer->Say_StringID(zone->random.Int(1204, 1207), GetCleanName()); } } @@ -1667,7 +1667,7 @@ void Client::OPGMEndTraining(const EQApplicationPacket *app) // goodbye message if (pTrainer->IsNPC()) { - pTrainer->Say_StringID(MakeRandomInt(1208, 1211), GetCleanName()); + pTrainer->Say_StringID(zone->random.Int(1208, 1211), GetCleanName()); } } diff --git a/zone/effects.cpp b/zone/effects.cpp index 0bface8b7..5c542d16d 100644 --- a/zone/effects.cpp +++ b/zone/effects.cpp @@ -55,30 +55,25 @@ int32 NPC::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { else value -= target->GetFcDamageAmtIncoming(this, spell_id)/spells[spell_id].buffduration; } - - value += dmg*GetSpellFocusDMG()/100; + + value += dmg*GetSpellFocusDMG()/100; if (AI_HasSpellsEffects()){ int16 chance = 0; int ratio = 0; if (spells[spell_id].buffduration == 0) { - chance += spellbonuses.CriticalSpellChance + spellbonuses.FrenziedDevastation; - - if (chance && MakeRandomInt(1,100) <= chance){ - + + if (chance && zone->random.Roll(chance)) { ratio += spellbonuses.SpellCritDmgIncrease + spellbonuses.SpellCritDmgIncNoStack; value += (value*ratio)/100; entity_list.MessageClose_StringID(this, true, 100, MT_SpellCrits, OTHER_CRIT_BLAST, GetCleanName(), itoa(-value)); } } else { - chance += spellbonuses.CriticalDoTChance; - - if (chance && MakeRandomInt(1,100) <= chance){ - + if (chance && zone->random.Roll(chance)) { ratio += spellbonuses.DotCritDmgIncrease; value += (value*ratio)/100; } @@ -119,14 +114,14 @@ int32 Client::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { if (spell_id == SPELL_IMP_HARM_TOUCH && (GetAA(aaSpellCastingFury) > 0) && (GetAA(aaUnholyTouch) > 0)) chance = 100; - if (MakeRandomInt(1,100) <= chance){ + if (zone->random.Roll(chance)) { Critical = true; ratio += itembonuses.SpellCritDmgIncrease + spellbonuses.SpellCritDmgIncrease + aabonuses.SpellCritDmgIncrease; ratio += itembonuses.SpellCritDmgIncNoStack + spellbonuses.SpellCritDmgIncNoStack + aabonuses.SpellCritDmgIncNoStack; } - else if (GetClass() == WIZARD && (GetLevel() >= RuleI(Spells, WizCritLevel)) && (MakeRandomInt(1,100) <= RuleI(Spells, WizCritChance))) { - ratio += MakeRandomInt(20,70); //Wizard innate critical chance is calculated seperately from spell effect and is not a set ratio. (20-70 is parse confirmed) + else if (GetClass() == WIZARD && (GetLevel() >= RuleI(Spells, WizCritLevel)) && (zone->random.Roll(RuleI(Spells, WizCritChance)))) { + ratio += zone->random.Int(20,70); //Wizard innate critical chance is calculated seperately from spell effect and is not a set ratio. (20-70 is parse confirmed) Critical = true; } @@ -193,22 +188,16 @@ int32 Client::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) { if (spellbonuses.CriticalDotDecay) chance += GetDecayEffectValue(spell_id, SE_CriticalDotDecay); - + value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100); - if (chance > 0 && (MakeRandomInt(1, 100) <= chance)) { - + if (chance > 0 && (zone->random.Roll(chance))) { int32 ratio = 200; ratio += itembonuses.DotCritDmgIncrease + spellbonuses.DotCritDmgIncrease + aabonuses.DotCritDmgIncrease; - - value = value_BaseEffect*ratio/100; - - value += int(value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100)*ratio/100; - + value = value_BaseEffect*ratio/100; + value += int(value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100)*ratio/100; value += int(value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100; - - value += int(value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100; - + value += int(value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100; extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) + int(GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100) + GetFocusEffect(focusFcDamageAmt, spell_id); @@ -216,7 +205,7 @@ int32 Client::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) { if (extra_dmg) { int duration = CalcBuffDuration(this, this, spell_id); if (duration > 0) - extra_dmg /= duration; + extra_dmg /= duration; } value -= extra_dmg; @@ -224,25 +213,20 @@ int32 Client::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) { return value; } - value = value_BaseEffect; - - value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100; - - value += value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100; - - value += value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100; - - extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) + + value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100; + value += value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100; + value += value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100; + extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) + GetFocusEffect(focusFcDamageAmtCrit, spell_id) + - GetFocusEffect(focusFcDamageAmt, spell_id); + GetFocusEffect(focusFcDamageAmt, spell_id); if (extra_dmg) { int duration = CalcBuffDuration(this, this, spell_id); if (duration > 0) - extra_dmg /= duration; - } - + extra_dmg /= duration; + } + value -= extra_dmg; return value; @@ -275,28 +259,26 @@ int32 NPC::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { //Scale all NPC spell healing via SetSpellFocusHeal(value) - value += value*GetSpellFocusHeal()/100; + value += value*GetSpellFocusHeal()/100; if (target) { - value += target->GetFocusIncoming(focusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id); + value += target->GetFocusIncoming(focusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id); value += value*target->GetHealRate(spell_id, this)/100; } //Allow for critical heal chance if NPC is loading spell effect bonuses. if (AI_HasSpellsEffects()){ - if(spells[spell_id].buffduration < 1) { - - if(spellbonuses.CriticalHealChance && (MakeRandomInt(0,99) < spellbonuses.CriticalHealChance)) { - value = value*2; + if(spellbonuses.CriticalHealChance && (zone->random.Roll(spellbonuses.CriticalHealChance))) { + value = value*2; entity_list.MessageClose_StringID(this, true, 100, MT_SpellCrits, OTHER_CRIT_HEAL, GetCleanName(), itoa(value)); } } - else if(spellbonuses.CriticalHealOverTime && (MakeRandomInt(0,99) < spellbonuses.CriticalHealOverTime)) { - value = value*2; + else if(spellbonuses.CriticalHealOverTime && (zone->random.Roll(spellbonuses.CriticalHealOverTime))) { + value = value*2; } } - + return value; } @@ -326,7 +308,7 @@ int32 Client::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { if (spellbonuses.CriticalHealDecay) chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay); - if(chance && (MakeRandomInt(0,99) < chance)) { + if(chance && (zone->random.Roll(chance))) { Critical = true; modifier = 2; //At present time no critical heal amount modifier SPA exists. } @@ -360,7 +342,7 @@ int32 Client::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { if (spellbonuses.CriticalRegenDecay) chance += GetDecayEffectValue(spell_id, SE_CriticalRegenDecay); - if(chance && (MakeRandomInt(0,99) < chance)) + if(chance && zone->random.Roll(chance)) return (value * 2); } @@ -374,12 +356,12 @@ int32 Client::GetActSpellCost(uint16 spell_id, int32 cost) int16 FrenziedDevastation = itembonuses.FrenziedDevastation + spellbonuses.FrenziedDevastation + aabonuses.FrenziedDevastation; if (FrenziedDevastation && IsPureNukeSpell(spell_id)) - cost *= 2; - + cost *= 2; + // Formula = Unknown exact, based off a random percent chance up to mana cost(after focuses) of the cast spell if(this->itembonuses.Clairvoyance && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) { - int16 mana_back = this->itembonuses.Clairvoyance * MakeRandomInt(1, 100) / 100; + int16 mana_back = this->itembonuses.Clairvoyance * zone->random.Int(1, 100) / 100; // Doesnt generate mana, so best case is a free spell if(mana_back > cost) mana_back = cost; @@ -392,7 +374,7 @@ int32 Client::GetActSpellCost(uint16 spell_id, int32 cost) // WildcardX float PercentManaReduction = 0; float SpecializeSkill = GetSpecializeSkillValue(spell_id); - int SuccessChance = MakeRandomInt(0, 100); + int SuccessChance = zone->random.Int(0, 100); float bonus = 1.0; switch(GetAA(aaSpellCastingMastery)) @@ -444,7 +426,7 @@ int32 Client::GetActSpellCost(uint16 spell_id, int32 cost) if(focus_redux > 0) { - PercentManaReduction += MakeRandomFloat(1, (double)focus_redux); + PercentManaReduction += zone->random.Real(1, (double)focus_redux); } cost -= (cost * (PercentManaReduction / 100)); diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index 0e8b10a8e..62fa1dd70 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -1521,7 +1521,7 @@ XS(XS__ChooseRandom) if (items < 1) Perl_croak(aTHX_ "Usage: ChooseRandom(... list ...)"); - int index = MakeRandomInt(0, items-1); + int index = zone->random.Int(0, items-1); SV *tmp = ST(0); ST(0) = ST(index); diff --git a/zone/entity.cpp b/zone/entity.cpp index bf6095a7c..f3263bea9 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -631,7 +631,7 @@ void EntityList::AddCorpse(Corpse *corpse, uint32 in_id) void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue) { npc->SetID(GetFreeID()); - npc->SetMerchantProbability((uint8) MakeRandomInt(0, 99)); + npc->SetMerchantProbability((uint8) zone->random.Int(0, 99)); parse->EventNPC(EVENT_SPAWN, npc, nullptr, "", 0); /* Web Interface: NPC Spawn (Pop) */ @@ -1587,7 +1587,7 @@ Client *EntityList::GetRandomClient(float x, float y, float z, float Distance, C if (ClientsInRange.empty()) return nullptr; - return ClientsInRange[MakeRandomInt(0, ClientsInRange.size() - 1)]; + return ClientsInRange[zone->random.Int(0, ClientsInRange.size() - 1)]; } Corpse *EntityList::GetCorpseByOwner(Client *client) @@ -2918,7 +2918,7 @@ void EntityList::ClearFeignAggro(Mob *targ) it->second->RemoveFromHateList(targ); if (targ->IsClient()) { - if (it->second->GetLevel() >= 35 && MakeRandomInt(1, 100) <= 60) + if (it->second->GetLevel() >= 35 && zone->random.Roll(60)) it->second->AddFeignMemory(targ->CastToClient()); else targ->CastToClient()->RemoveXTarget(it->second, false); @@ -4533,7 +4533,7 @@ void EntityList::AddLootToNPCS(uint32 item_id, uint32 count) selection.push_back(j); while (selection.size() > 0 && count > 0) { - int k = MakeRandomInt(0, selection.size() - 1); + int k = zone->random.Int(0, selection.size() - 1); counts[selection[k]]++; count--; selection.erase(selection.begin() + k); @@ -4715,6 +4715,6 @@ Mob *EntityList::GetTargetForVirus(Mob *spreader, int range) if(TargetsInRange.size() == 0) return nullptr; - return TargetsInRange[MakeRandomInt(0, TargetsInRange.size() - 1)]; + return TargetsInRange[zone->random.Int(0, TargetsInRange.size() - 1)]; } diff --git a/zone/fearpath.cpp b/zone/fearpath.cpp index 47fc53a96..25d514cfe 100644 --- a/zone/fearpath.cpp +++ b/zone/fearpath.cpp @@ -186,8 +186,8 @@ void Mob::CalculateNewFearpoint() { int ran = 250 - (loop*2); loop++; - ranx = GetX()+MakeRandomInt(0, ran-1)-MakeRandomInt(0, ran-1); - rany = GetY()+MakeRandomInt(0, ran-1)-MakeRandomInt(0, ran-1); + ranx = GetX()+zone->random.Int(0, ran-1)-zone->random.Int(0, ran-1); + rany = GetY()+zone->random.Int(0, ran-1)-zone->random.Int(0, ran-1); ranz = FindGroundZ(ranx,rany); if (ranz == -999999) continue; diff --git a/zone/forage.cpp b/zone/forage.cpp index cbb6550db..7e2f7d457 100644 --- a/zone/forage.cpp +++ b/zone/forage.cpp @@ -83,7 +83,7 @@ uint32 ZoneDatabase::GetZoneForage(uint32 ZoneID, uint8 skill) { ret = 0; - uint32 rindex = MakeRandomInt(1, chancepool); + uint32 rindex = zone->random.Int(1, chancepool); for(int i = 0; i < index; i++) { if(rindex <= chance[i]) { @@ -136,7 +136,7 @@ uint32 ZoneDatabase::GetZoneFishing(uint32 ZoneID, uint8 skill, uint32 &npc_id, if (index <= 0) return 0; - uint32 random = MakeRandomInt(1, chancepool); + uint32 random = zone->random.Int(1, chancepool); for (int i = 0; i < index; i++) { if (random > chance[i]) @@ -258,18 +258,18 @@ void Client::GoFish() fishing_skill = 100+((fishing_skill-100)/2); } - if (MakeRandomInt(0,175) < fishing_skill) { + if (zone->random.Int(0,175) < fishing_skill) { uint32 food_id = 0; //25% chance to fish an item. - if (MakeRandomInt(0, 399) <= fishing_skill ) { + if (zone->random.Int(0, 399) <= fishing_skill ) { uint32 npc_id = 0; uint8 npc_chance = 0; food_id = database.GetZoneFishing(m_pp.zone_id, fishing_skill, npc_id, npc_chance); //check for add NPC if(npc_chance > 0 && npc_id) { - if(npc_chance < MakeRandomInt(0, 99)) { + if(npc_chance < zone->random.Int(0, 99)) { const NPCType* tmp = database.GetNPCType(npc_id); if(tmp != nullptr) { NPC* npc = new NPC(tmp, nullptr, GetX()+3, GetY(), GetZ(), GetHeading(), FlyMode3); @@ -289,7 +289,7 @@ void Client::GoFish() DeleteItemInInventory(bslot, 1, true); //do we need client update? if(food_id == 0) { - int index = MakeRandomInt(0, MAX_COMMON_FISH_IDS-1); + int index = zone->random.Int(0, MAX_COMMON_FISH_IDS-1); food_id = common_fish_ids[index]; } @@ -324,11 +324,11 @@ void Client::GoFish() else { //chance to use bait when you dont catch anything... - if (MakeRandomInt(0, 4) == 1) { + if (zone->random.Int(0, 4) == 1) { DeleteItemInInventory(bslot, 1, true); //do we need client update? Message_StringID(MT_Skills, FISHING_LOST_BAIT); //You lost your bait! } else { - if (MakeRandomInt(0, 15) == 1) //give about a 1 in 15 chance to spill your beer. we could make this a rule, but it doesn't really seem worth it + if (zone->random.Int(0, 15) == 1) //give about a 1 in 15 chance to spill your beer. we could make this a rule, but it doesn't really seem worth it //TODO: check for & consume an alcoholic beverage from inventory when this triggers, and set it as a rule that's disabled by default Message_StringID(MT_Skills, FISHING_SPILL_BEER); //You spill your beer while bringing in your line. else @@ -341,7 +341,7 @@ void Client::GoFish() //chance to break fishing pole... //this is potentially exploitable in that they can fish //and then swap out items in primary slot... too lazy to fix right now - if (MakeRandomInt(0, 49) == 1) { + if (zone->random.Int(0, 49) == 1) { Message_StringID(MT_Skills, FISHING_POLE_BROKE); //Your fishing pole broke! DeleteItemInInventory(MainPrimary, 0, true); } @@ -370,18 +370,18 @@ void Client::ForageItem(bool guarantee) { }; // these may need to be fine tuned, I am just guessing here - if (guarantee || MakeRandomInt(0,199) < skill_level) { + if (guarantee || zone->random.Int(0,199) < skill_level) { uint32 foragedfood = 0; uint32 stringid = FORAGE_NOEAT; - if (MakeRandomInt(0,99) <= 25) { + if (zone->random.Roll(25)) { foragedfood = database.GetZoneForage(m_pp.zone_id, skill_level); } //not an else in case theres no DB food if(foragedfood == 0) { uint8 index = 0; - index = MakeRandomInt(0, MAX_COMMON_FOOD_IDS-1); + index = zone->random.Int(0, MAX_COMMON_FOOD_IDS-1); foragedfood = common_food_ids[index]; } @@ -438,7 +438,7 @@ void Client::ForageItem(bool guarantee) { } int ChanceSecondForage = aabonuses.ForageAdditionalItems + itembonuses.ForageAdditionalItems + spellbonuses.ForageAdditionalItems; - if(!guarantee && MakeRandomInt(0,99) < ChanceSecondForage) { + if(!guarantee && zone->random.Roll(ChanceSecondForage)) { Message_StringID(MT_Skills, FORAGE_MASTERY); ForageItem(true); } diff --git a/zone/hate_list.cpp b/zone/hate_list.cpp index 4c4290232..2e64f092f 100644 --- a/zone/hate_list.cpp +++ b/zone/hate_list.cpp @@ -485,10 +485,10 @@ Mob *HateList::GetRandom() } auto iterator = list.begin(); - int random = MakeRandomInt(0, count - 1); + int random = zone->random.Int(0, count - 1); for (int i = 0; i < random; i++) ++iterator; - + return (*iterator)->ent; } diff --git a/zone/inventory.cpp b/zone/inventory.cpp index 6b7a0b297..bb9802e1c 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -1032,7 +1032,25 @@ bool Client::MakeItemLink(char* &ret_link, const ItemInst *inst) { uint8 evolvedlevel = 0; int hash = 0; //int hash = GetItemLinkHash(inst); //eventually this will work (currently crashes zone), but for now we'll skip the extra overhead - if (GetClientVersion() >= EQClientRoF) + if (GetClientVersion() >= EQClientRoF2) + { + MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%01X" "%1X" "%04X" "%1X" "%05X" "%08X", + 0, + item->ID, + inst->GetAugmentItemID(0), + inst->GetAugmentItemID(1), + inst->GetAugmentItemID(2), + inst->GetAugmentItemID(3), + inst->GetAugmentItemID(4), + inst->GetAugmentItemID(5), + evolving, + loregroup, + evolvedlevel, + 0, + hash + ); + } + else if (GetClientVersion() >= EQClientRoF) { MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X", 0, diff --git a/zone/loottables.cpp b/zone/loottables.cpp index 121dad8c5..c5fda890e 100644 --- a/zone/loottables.cpp +++ b/zone/loottables.cpp @@ -49,15 +49,15 @@ void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* ite if (lts->mincash == lts->maxcash) cash = lts->mincash; else - cash = MakeRandomInt(lts->mincash, lts->maxcash); + cash = zone->random.Int(lts->mincash, lts->maxcash); if (cash != 0) { if (lts->avgcoin != 0) { //this is some crazy ass stuff... and makes very little sense... dont use it, k? uint32 mincoin = (uint32) (lts->avgcoin * 0.75 + 1); uint32 maxcoin = (uint32) (lts->avgcoin * 1.25 + 1); - *copper = MakeRandomInt(mincoin, maxcoin); - *silver = MakeRandomInt(mincoin, maxcoin); - *gold = MakeRandomInt(mincoin, maxcoin); + *copper = zone->random.Int(mincoin, maxcoin); + *silver = zone->random.Int(mincoin, maxcoin); + *gold = zone->random.Int(mincoin, maxcoin); if(*copper > cash) { *copper = cash; } cash -= *copper; if(*silver>(cash/10)) { *silver = (cash/10); } @@ -92,7 +92,7 @@ void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* ite float drop_chance = 0.0f; if(ltchance > 0.0 && ltchance < 100.0) { - drop_chance = MakeRandomFloat(0.0, 100.0); + drop_chance = zone->random.Real(0.0, 100.0); } if (ltchance != 0.0 && (ltchance == 100.0 || drop_chance < ltchance)) { @@ -118,7 +118,7 @@ void ZoneDatabase::AddLootDropToNPC(NPC* npc,uint32 lootdrop_id, ItemList* iteml uint8 limit = 0; // Start at a random point in itemlist. - uint32 item = MakeRandomInt(0, lds->NumEntries-1); + uint32 item = zone->random.Int(0, lds->NumEntries-1); // Main loop. for (uint32 i=0; iNumEntries;) { @@ -137,7 +137,7 @@ void ZoneDatabase::AddLootDropToNPC(NPC* npc,uint32 lootdrop_id, ItemList* iteml float drop_chance = 0.0; if(thischance != 100.0) - drop_chance = MakeRandomFloat(0.0, 100.0); + drop_chance = zone->random.Real(0.0, 100.0); #if EQDEBUG>=11 LogFile->write(EQEMuLog::Debug, "Drop chance for npc: %s, this chance:%f, drop roll:%f", npc->GetName(), thischance, drop_chance); @@ -282,7 +282,7 @@ void NPC::AddLootDrop(const Item_Struct *item2, ItemList* itemlist, int16 charge eslot = MaterialPrimary; } else if (foundslot == MainSecondary - && (GetOwner() != nullptr || (GetLevel() >= 13 && MakeRandomInt(0,99) < NPC_DW_CHANCE) || (item2->Damage==0)) && + && (GetOwner() != nullptr || (GetLevel() >= 13 && zone->random.Roll(NPC_DW_CHANCE)) || (item2->Damage==0)) && (item2->ItemType == ItemType1HSlash || item2->ItemType == ItemType1HBlunt || item2->ItemType == ItemTypeShield || item2->ItemType == ItemType1HPiercing)) { diff --git a/zone/merc.cpp b/zone/merc.cpp index c94616eab..437790588 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -1457,7 +1457,7 @@ void Merc::AI_Process() { meleeDistance = meleeDistance * .30; } else { - meleeDistance *= (float)MakeRandomFloat(.50, .85); + meleeDistance *= (float)zone->random.Real(.50, .85); } if(IsMercCaster() && GetLevel() > 12) { if(IsMercCasterCombatRange(GetTarget())) @@ -1558,7 +1558,7 @@ void Merc::AI_Process() { if (GetTarget() && flurrychance) { - if(MakeRandomInt(0, 100) < flurrychance) + if(zone->random.Roll(flurrychance)) { Message_StringID(MT_NPCFlurry, YOU_FLURRY); Attack(GetTarget(), MainPrimary, false); @@ -1569,7 +1569,7 @@ void Merc::AI_Process() { int16 ExtraAttackChanceBonus = spellbonuses.ExtraAttackChance + itembonuses.ExtraAttackChance + aabonuses.ExtraAttackChance; if (GetTarget() && ExtraAttackChanceBonus) { - if(MakeRandomInt(0, 100) < ExtraAttackChanceBonus) + if(zone->random.Roll(ExtraAttackChanceBonus)) { Attack(GetTarget(), MainPrimary, false); } @@ -1603,10 +1603,8 @@ void Merc::AI_Process() { int16 DWBonus = spellbonuses.DualWieldChance + itembonuses.DualWieldChance; DualWieldProbability += DualWieldProbability*float(DWBonus)/ 100.0f; - float random = MakeRandomFloat(0, 1); - // Max 78% of DW - if (random < DualWieldProbability) + if (zone->random.Roll(DualWieldProbability)) { Attack(GetTarget(), MainSecondary); // Single attack with offhand @@ -1868,7 +1866,7 @@ bool EntityList::Merc_AICheckCloseBeneficialSpells(Merc* caster, uint8 iChance, return false; if (iChance < 100) { - int8 tmp = MakeRandomInt(1, 100); + int8 tmp = zone->random.Int(1, 100); if (tmp > iChance) return false; } @@ -1964,7 +1962,7 @@ bool Merc::AICastSpell(int8 iChance, int32 iSpellTypes) { return false; if (iChance < 100) { - if (MakeRandomInt(0, 100) > iChance){ + if (zone->random.Int(0, 100) > iChance){ return false; } } @@ -2249,14 +2247,14 @@ bool Merc::AICastSpell(int8 iChance, int32 iSpellTypes) { if(selectedMercSpell.spellid == 0 && !tar->GetSpecialAbility(UNSTUNABLE) && !tar->IsStunned()) { uint8 stunChance = 15; - if(MakeRandomInt(1, 100) <= stunChance) { + if(zone->random.Roll(stunChance)) { selectedMercSpell = GetBestMercSpellForStun(this); } } if(selectedMercSpell.spellid == 0) { uint8 lureChance = 25; - if(MakeRandomInt(1, 100) <= lureChance) { + if(zone->random.Roll(lureChance)) { selectedMercSpell = GetBestMercSpellForNukeByTargetResists(this, tar); } } @@ -2676,14 +2674,14 @@ int32 Merc::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { int32 ratio = RuleI(Spells, BaseCritRatio); //Critical modifier is applied from spell effects only. Keep at 100 for live like criticals. - if (MakeRandomInt(1,100) <= chance){ + if (zone->random.Roll(chance)) { Critical = true; ratio += itembonuses.SpellCritDmgIncrease + spellbonuses.SpellCritDmgIncrease + aabonuses.SpellCritDmgIncrease; ratio += itembonuses.SpellCritDmgIncNoStack + spellbonuses.SpellCritDmgIncNoStack + aabonuses.SpellCritDmgIncNoStack; } - else if (GetClass() == CASTERDPS && (GetLevel() >= RuleI(Spells, WizCritLevel)) && (MakeRandomInt(1,100) <= RuleI(Spells, WizCritChance))) { - ratio = MakeRandomInt(1,100); //Wizard innate critical chance is calculated seperately from spell effect and is not a set ratio. + else if (GetClass() == CASTERDPS && (GetLevel() >= RuleI(Spells, WizCritLevel)) && (zone->random.Roll(RuleI(Spells, WizCritChance)))) { + ratio = zone->random.Int(1,100); //Wizard innate critical chance is calculated seperately from spell effect and is not a set ratio. Critical = true; } @@ -2767,7 +2765,7 @@ int32 Merc::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { if (spellbonuses.CriticalHealDecay) chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay); - if(chance && (MakeRandomInt(0,99) < chance)) { + if(chance && zone->random.Roll(chance)) { Critical = true; modifier = 2; //At present time no critical heal amount modifier SPA exists. } @@ -2798,7 +2796,7 @@ int32 Merc::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { if (spellbonuses.CriticalRegenDecay) chance += GetDecayEffectValue(spell_id, SE_CriticalRegenDecay); - if(chance && (MakeRandomInt(0,99) < chance)) + if(chance && zone->random.Roll(chance)) return (value * 2); } @@ -2810,7 +2808,7 @@ int32 Merc::GetActSpellCost(uint16 spell_id, int32 cost) // Formula = Unknown exact, based off a random percent chance up to mana cost(after focuses) of the cast spell if(this->itembonuses.Clairvoyance && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) { - int16 mana_back = this->itembonuses.Clairvoyance * MakeRandomInt(1, 100) / 100; + int16 mana_back = this->itembonuses.Clairvoyance * zone->random.Int(1, 100) / 100; // Doesnt generate mana, so best case is a free spell if(mana_back > cost) mana_back = cost; @@ -2827,7 +2825,7 @@ int32 Merc::GetActSpellCost(uint16 spell_id, int32 cost) if(focus_redux > 0) { - PercentManaReduction += MakeRandomFloat(1, (double)focus_redux); + PercentManaReduction += zone->random.Real(1, (double)focus_redux); } cost -= (cost * (PercentManaReduction / 100)); @@ -3759,17 +3757,17 @@ MercSpell Merc::GetBestMercSpellForAENuke(Merc* caster, Mob* tar) { } //check of we even want to cast an AE nuke - if(MakeRandomInt(1, 100) <= initialCastChance) { + if(zone->random.Roll(initialCastChance)) { result = GetBestMercSpellForAERainNuke(caster, tar); //check if we have a spell & allow for other AE nuke types - if(result.spellid == 0 && MakeRandomInt(1, 100) <= castChanceFalloff) { + if(result.spellid == 0 && zone->random.Roll(castChanceFalloff)) { result = GetBestMercSpellForPBAENuke(caster, tar); //check if we have a spell & allow for other AE nuke types - if(result.spellid == 0 && MakeRandomInt(1, 100) <= castChanceFalloff) { + if(result.spellid == 0 && zone->random.Roll(castChanceFalloff)) { result = GetBestMercSpellForTargetedAENuke(caster, tar); } @@ -3813,7 +3811,7 @@ MercSpell Merc::GetBestMercSpellForTargetedAENuke(Merc* caster, Mob* tar) { && !IsPBAENukeSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { uint8 numTargets = 0; if(CheckAENuke(caster, tar, mercSpellListItr->spellid, numTargets)) { - if(numTargets >= numTargetsCheck && MakeRandomInt(1, 100) <= castChance) { + if(numTargets >= numTargetsCheck && zone->random.Roll(castChance)) { result.spellid = mercSpellListItr->spellid; result.stance = mercSpellListItr->stance; result.type = mercSpellListItr->type; @@ -3863,7 +3861,7 @@ MercSpell Merc::GetBestMercSpellForPBAENuke(Merc* caster, Mob* tar) { if(IsPBAENukeSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { uint8 numTargets = 0; if(CheckAENuke(caster, caster, mercSpellListItr->spellid, numTargets)) { - if(numTargets >= numTargetsCheck && MakeRandomInt(1, 100) <= castChance) { + if(numTargets >= numTargetsCheck && zone->random.Roll(castChance)) { result.spellid = mercSpellListItr->spellid; result.stance = mercSpellListItr->stance; result.type = mercSpellListItr->type; @@ -3910,7 +3908,7 @@ MercSpell Merc::GetBestMercSpellForAERainNuke(Merc* caster, Mob* tar) { for(std::list::iterator mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order - if(IsAERainNukeSpell(mercSpellListItr->spellid) && MakeRandomInt(1, 100) <= castChance && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { + if(IsAERainNukeSpell(mercSpellListItr->spellid) && zone->random.Roll(castChance) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { uint8 numTargets = 0; if(CheckAENuke(caster, tar, mercSpellListItr->spellid, numTargets)) { if(numTargets >= numTargetsCheck) { @@ -3949,7 +3947,7 @@ MercSpell Merc::GetBestMercSpellForNuke(Merc* caster) { for(std::list::iterator mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order if(IsPureNukeSpell(mercSpellListItr->spellid) && !IsAENukeSpell(mercSpellListItr->spellid) - && MakeRandomInt(1, 100) <= castChance && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { + && zone->random.Roll(castChance) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { result.spellid = mercSpellListItr->spellid; result.stance = mercSpellListItr->stance; result.type = mercSpellListItr->type; @@ -4381,7 +4379,7 @@ bool Merc::CheckConfidence() { ConfidenceLossChance = 25 - ( 5 * (GetTierID() - 1)); } - if(MakeRandomInt(0 ,100) < ConfidenceLossChance) { + if(zone->random.Roll(ConfidenceLossChance)) { result = false; } @@ -4527,7 +4525,7 @@ void Merc::DoClassAttacks(Mob *target) { break; case TANK:{ if(level >= RuleI(Combat, NPCBashKickLevel)){ - if(MakeRandomInt(0, 100) > 25) //tested on live, warrior mobs both kick and bash, kick about 75% of the time, casting doesn't seem to make a difference. + if(zone->random.Int(0, 100) > 25) //tested on live, warrior mobs both kick and bash, kick about 75% of the time, casting doesn't seem to make a difference. { DoAnim(animKick); int32 dmg = 0; @@ -4540,7 +4538,7 @@ void Merc::DoClassAttacks(Mob *target) { if(RuleB(Combat, UseIntervalAC)) dmg = GetKickDamage(); else - dmg = MakeRandomInt(1, GetKickDamage()); + dmg = zone->random.Int(1, GetKickDamage()); } } @@ -4562,7 +4560,7 @@ void Merc::DoClassAttacks(Mob *target) { if(RuleB(Combat, UseIntervalAC)) dmg = GetBashDamage(); else - dmg = MakeRandomInt(1, GetBashDamage()); + dmg = zone->random.Int(1, GetBashDamage()); } } @@ -4690,7 +4688,7 @@ const char* Merc::GetRandomName(){ bool valid = false; while(!valid) { - int rndnum=MakeRandomInt(0, 75),n=1; + int rndnum=zone->random.Int(0, 75),n=1; bool dlc=false; bool vwl=false; bool dbl=false; @@ -4711,18 +4709,18 @@ const char* Merc::GetRandomName(){ rndname[0]=vowels[rndnum]; vwl=true; } - int namlen=MakeRandomInt(5, 10); + int namlen=zone->random.Int(5, 10); for (int i=n;irandom.Int(0, 62); if (rndnum>46) { // pick a cons pair if (i>namlen-3) // last 2 chars in name? { // name can only end in cons pair "rk" "st" "sh" "th" "ph" "sk" "nd" or "ng" - rndnum=MakeRandomInt(0, 7)*2; + rndnum=zone->random.Int(0, 7)*2; } else { // pick any from the set @@ -4740,12 +4738,12 @@ const char* Merc::GetRandomName(){ } else { // select a vowel - rndname[i]=vowels[MakeRandomInt(0, 16)]; + rndname[i]=vowels[zone->random.Int(0, 16)]; } vwl=!vwl; if (!dbl && !dlc) { // one chance at double letters in name - if (!MakeRandomInt(0, i+9)) // chances decrease towards end of name + if (!zone->random.Int(0, i+9)) // chances decrease towards end of name { rndname[i+1]=rndname[i]; dbl=true; @@ -6317,4 +6315,4 @@ uint32 Merc::CalcUpkeepCost(uint32 templateID , uint8 level, uint8 currency_type } return cost; -} \ No newline at end of file +} diff --git a/zone/mob.cpp b/zone/mob.cpp index f651ef714..ee5f143b1 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -1602,157 +1602,157 @@ bool Mob::RandomizeFeatures(bool send_illusion, bool set_variables) uint32 DrakkinDetails = 0xFFFFFFFF; // Set some common feature settings - EyeColor1 = MakeRandomInt(0, 9); - EyeColor2 = MakeRandomInt(0, 9); - LuclinFace = MakeRandomInt(0, 7); + EyeColor1 = zone->random.Int(0, 9); + EyeColor2 = zone->random.Int(0, 9); + LuclinFace = zone->random.Int(0, 7); // Adjust all settings based on the min and max for each feature of each race and gender switch (GetRace()) { case 1: // Human - HairColor = MakeRandomInt(0, 19); + HairColor = zone->random.Int(0, 19); if (Gender == 0) { BeardColor = HairColor; - HairStyle = MakeRandomInt(0, 3); - Beard = MakeRandomInt(0, 5); + HairStyle = zone->random.Int(0, 3); + Beard = zone->random.Int(0, 5); } if (Gender == 1) { - HairStyle = MakeRandomInt(0, 2); + HairStyle = zone->random.Int(0, 2); } break; case 2: // Barbarian - HairColor = MakeRandomInt(0, 19); - LuclinFace = MakeRandomInt(0, 87); + HairColor = zone->random.Int(0, 19); + LuclinFace = zone->random.Int(0, 87); if (Gender == 0) { BeardColor = HairColor; - HairStyle = MakeRandomInt(0, 3); - Beard = MakeRandomInt(0, 5); + HairStyle = zone->random.Int(0, 3); + Beard = zone->random.Int(0, 5); } if (Gender == 1) { - HairStyle = MakeRandomInt(0, 2); + HairStyle = zone->random.Int(0, 2); } break; case 3: // Erudite if (Gender == 0) { - BeardColor = MakeRandomInt(0, 19); - Beard = MakeRandomInt(0, 5); - LuclinFace = MakeRandomInt(0, 57); + BeardColor = zone->random.Int(0, 19); + Beard = zone->random.Int(0, 5); + LuclinFace = zone->random.Int(0, 57); } if (Gender == 1) { - LuclinFace = MakeRandomInt(0, 87); + LuclinFace = zone->random.Int(0, 87); } break; case 4: // WoodElf - HairColor = MakeRandomInt(0, 19); + HairColor = zone->random.Int(0, 19); if (Gender == 0) { - HairStyle = MakeRandomInt(0, 3); + HairStyle = zone->random.Int(0, 3); } if (Gender == 1) { - HairStyle = MakeRandomInt(0, 2); + HairStyle = zone->random.Int(0, 2); } break; case 5: // HighElf - HairColor = MakeRandomInt(0, 14); + HairColor = zone->random.Int(0, 14); if (Gender == 0) { - HairStyle = MakeRandomInt(0, 3); - LuclinFace = MakeRandomInt(0, 37); + HairStyle = zone->random.Int(0, 3); + LuclinFace = zone->random.Int(0, 37); BeardColor = HairColor; } if (Gender == 1) { - HairStyle = MakeRandomInt(0, 2); + HairStyle = zone->random.Int(0, 2); } break; case 6: // DarkElf - HairColor = MakeRandomInt(13, 18); + HairColor = zone->random.Int(13, 18); if (Gender == 0) { - HairStyle = MakeRandomInt(0, 3); - LuclinFace = MakeRandomInt(0, 37); + HairStyle = zone->random.Int(0, 3); + LuclinFace = zone->random.Int(0, 37); BeardColor = HairColor; } if (Gender == 1) { - HairStyle = MakeRandomInt(0, 2); + HairStyle = zone->random.Int(0, 2); } break; case 7: // HalfElf - HairColor = MakeRandomInt(0, 19); + HairColor = zone->random.Int(0, 19); if (Gender == 0) { - HairStyle = MakeRandomInt(0, 3); - LuclinFace = MakeRandomInt(0, 37); + HairStyle = zone->random.Int(0, 3); + LuclinFace = zone->random.Int(0, 37); BeardColor = HairColor; } if (Gender == 1) { - HairStyle = MakeRandomInt(0, 2); + HairStyle = zone->random.Int(0, 2); } break; case 8: // Dwarf - HairColor = MakeRandomInt(0, 19); + HairColor = zone->random.Int(0, 19); BeardColor = HairColor; if (Gender == 0) { - HairStyle = MakeRandomInt(0, 3); - Beard = MakeRandomInt(0, 5); + HairStyle = zone->random.Int(0, 3); + Beard = zone->random.Int(0, 5); } if (Gender == 1) { - HairStyle = MakeRandomInt(0, 2); - LuclinFace = MakeRandomInt(0, 17); + HairStyle = zone->random.Int(0, 2); + LuclinFace = zone->random.Int(0, 17); } break; case 9: // Troll - EyeColor1 = MakeRandomInt(0, 10); - EyeColor2 = MakeRandomInt(0, 10); + EyeColor1 = zone->random.Int(0, 10); + EyeColor2 = zone->random.Int(0, 10); if (Gender == 1) { - HairStyle = MakeRandomInt(0, 3); - HairColor = MakeRandomInt(0, 23); + HairStyle = zone->random.Int(0, 3); + HairColor = zone->random.Int(0, 23); } break; case 10: // Ogre if (Gender == 1) { - HairStyle = MakeRandomInt(0, 3); - HairColor = MakeRandomInt(0, 23); + HairStyle = zone->random.Int(0, 3); + HairColor = zone->random.Int(0, 23); } break; case 11: // Halfling - HairColor = MakeRandomInt(0, 19); + HairColor = zone->random.Int(0, 19); if (Gender == 0) { BeardColor = HairColor; - HairStyle = MakeRandomInt(0, 3); - Beard = MakeRandomInt(0, 5); + HairStyle = zone->random.Int(0, 3); + Beard = zone->random.Int(0, 5); } if (Gender == 1) { - HairStyle = MakeRandomInt(0, 2); + HairStyle = zone->random.Int(0, 2); } break; case 12: // Gnome - HairColor = MakeRandomInt(0, 24); + HairColor = zone->random.Int(0, 24); if (Gender == 0) { BeardColor = HairColor; - HairStyle = MakeRandomInt(0, 3); - Beard = MakeRandomInt(0, 5); + HairStyle = zone->random.Int(0, 3); + Beard = zone->random.Int(0, 5); } if (Gender == 1) { - HairStyle = MakeRandomInt(0, 2); + HairStyle = zone->random.Int(0, 2); } break; case 128: // Iksar case 130: // VahShir break; case 330: // Froglok - LuclinFace = MakeRandomInt(0, 9); + LuclinFace = zone->random.Int(0, 9); case 522: // Drakkin - HairColor = MakeRandomInt(0, 3); + HairColor = zone->random.Int(0, 3); BeardColor = HairColor; - EyeColor1 = MakeRandomInt(0, 11); - EyeColor2 = MakeRandomInt(0, 11); - LuclinFace = MakeRandomInt(0, 6); - DrakkinHeritage = MakeRandomInt(0, 6); - DrakkinTattoo = MakeRandomInt(0, 7); - DrakkinDetails = MakeRandomInt(0, 7); + EyeColor1 = zone->random.Int(0, 11); + EyeColor2 = zone->random.Int(0, 11); + LuclinFace = zone->random.Int(0, 6); + DrakkinHeritage = zone->random.Int(0, 6); + DrakkinTattoo = zone->random.Int(0, 7); + DrakkinDetails = zone->random.Int(0, 7); if (Gender == 0) { - Beard = MakeRandomInt(0, 12); - HairStyle = MakeRandomInt(0, 8); + Beard = zone->random.Int(0, 12); + HairStyle = zone->random.Int(0, 8); } if (Gender == 1) { - Beard = MakeRandomInt(0, 3); - HairStyle = MakeRandomInt(0, 7); + Beard = zone->random.Int(0, 3); + HairStyle = zone->random.Int(0, 7); } break; default: @@ -2591,7 +2591,7 @@ uint32 Mob::RandomTimer(int min,int max) { int r = 14000; if(min != 0 && max != 0 && min < max) { - r = MakeRandomInt(min, max); + r = zone->random.Int(min, max); } return r; } @@ -2988,7 +2988,7 @@ void Mob::ExecWeaponProc(const ItemInst *inst, uint16 spell_id, Mob *on) { if(IsClient()) twinproc_chance = CastToClient()->GetFocusEffect(focusTwincast, spell_id); - if(twinproc_chance && (MakeRandomInt(0,99) < twinproc_chance)) + if(twinproc_chance && zone->random.Roll(twinproc_chance)) twinproc = true; if (IsBeneficialSpell(spell_id)) { @@ -3317,7 +3317,7 @@ bool Mob::TrySpellTrigger(Mob *target, uint32 spell_id, int effect) { if(!target || !IsValidSpell(spell_id)) return false; - + int spell_trig = 0; // Count all the percentage chances to trigger for all effects for(int i = 0; i < EFFECT_COUNT; i++) @@ -3333,7 +3333,7 @@ bool Mob::TrySpellTrigger(Mob *target, uint32 spell_id, int effect) { if (spells[spell_id].effectid[i] == SE_SpellTrigger) { - if(MakeRandomInt(0, trig_chance) <= spells[spell_id].base[i]) + if(zone->random.Int(0, trig_chance) <= spells[spell_id].base[i]) { // If we trigger an effect then its over. if (IsValidSpell(spells[spell_id].base2[i])){ @@ -3353,7 +3353,7 @@ bool Mob::TrySpellTrigger(Mob *target, uint32 spell_id, int effect) // if the chances don't add to 100, then each effect gets a chance to fire, chance for no trigger as well. else { - if(MakeRandomInt(0, 100) <= spells[spell_id].base[effect]) + if(zone->random.Int(0, 100) <= spells[spell_id].base[effect]) { if (IsValidSpell(spells[spell_id].base2[effect])){ SpellFinished(spells[spell_id].base2[effect], target, 10, 0, -1, spells[spells[spell_id].base2[effect]].ResistDiff); @@ -3458,7 +3458,7 @@ void Mob::TryTwincast(Mob *caster, Mob *target, uint32 spell_id) if (focus > 0) { - if(MakeRandomInt(0, 100) <= focus) + if(zone->random.Roll(focus)) { Message(MT_Spells,"You twincast %s!",spells[spell_id].name); SpellFinished(spell_id, target, 10, 0, -1, spells[spell_id].ResistDiff); @@ -3477,7 +3477,7 @@ void Mob::TryTwincast(Mob *caster, Mob *target, uint32 spell_id) int32 focus = CalcFocusEffect(focusTwincast, buffs[i].spellid, spell_id); if(focus > 0) { - if(MakeRandomInt(0, 100) <= focus) + if(zone->random.Roll(focus)) { SpellFinished(spell_id, target, 10, 0, -1, spells[spell_id].ResistDiff); } @@ -4258,7 +4258,7 @@ void Mob::TrySpellOnKill(uint8 level, uint16 spell_id) { if (IsValidSpell(spells[spell_id].base2[i]) && spells[spell_id].max[i] <= level) { - if(MakeRandomInt(0,99) < spells[spell_id].base[i]) + if(zone->random.Roll(spells[spell_id].base[i])) SpellFinished(spells[spell_id].base2[i], this, 10, 0, -1, spells[spells[spell_id].base2[i]].ResistDiff); } } @@ -4273,17 +4273,17 @@ void Mob::TrySpellOnKill(uint8 level, uint16 spell_id) for(int i = 0; i < MAX_SPELL_TRIGGER*3; i+=3) { if(aabonuses.SpellOnKill[i] && IsValidSpell(aabonuses.SpellOnKill[i]) && (level >= aabonuses.SpellOnKill[i + 2])) { - if(MakeRandomInt(0, 99) < static_cast(aabonuses.SpellOnKill[i + 1])) + if(zone->random.Roll(static_cast(aabonuses.SpellOnKill[i + 1]))) SpellFinished(aabonuses.SpellOnKill[i], this, 10, 0, -1, spells[aabonuses.SpellOnKill[i]].ResistDiff); } if(itembonuses.SpellOnKill[i] && IsValidSpell(itembonuses.SpellOnKill[i]) && (level >= itembonuses.SpellOnKill[i + 2])){ - if(MakeRandomInt(0, 99) < static_cast(itembonuses.SpellOnKill[i + 1])) + if(zone->random.Roll(static_cast(itembonuses.SpellOnKill[i + 1]))) SpellFinished(itembonuses.SpellOnKill[i], this, 10, 0, -1, spells[aabonuses.SpellOnKill[i]].ResistDiff); } if(spellbonuses.SpellOnKill[i] && IsValidSpell(spellbonuses.SpellOnKill[i]) && (level >= spellbonuses.SpellOnKill[i + 2])) { - if(MakeRandomInt(0, 99) < static_cast(spellbonuses.SpellOnKill[i + 1])) + if(zone->random.Roll(static_cast(spellbonuses.SpellOnKill[i + 1]))) SpellFinished(spellbonuses.SpellOnKill[i], this, 10, 0, -1, spells[aabonuses.SpellOnKill[i]].ResistDiff); } @@ -4300,19 +4300,19 @@ bool Mob::TrySpellOnDeath() for(int i = 0; i < MAX_SPELL_TRIGGER*2; i+=2) { if(IsClient() && aabonuses.SpellOnDeath[i] && IsValidSpell(aabonuses.SpellOnDeath[i])) { - if(MakeRandomInt(0, 99) < static_cast(aabonuses.SpellOnDeath[i + 1])) { + if(zone->random.Roll(static_cast(aabonuses.SpellOnDeath[i + 1]))) { SpellFinished(aabonuses.SpellOnDeath[i], this, 10, 0, -1, spells[aabonuses.SpellOnDeath[i]].ResistDiff); } } if(itembonuses.SpellOnDeath[i] && IsValidSpell(itembonuses.SpellOnDeath[i])) { - if(MakeRandomInt(0, 99) < static_cast(itembonuses.SpellOnDeath[i + 1])) { + if(zone->random.Roll(static_cast(itembonuses.SpellOnDeath[i + 1]))) { SpellFinished(itembonuses.SpellOnDeath[i], this, 10, 0, -1, spells[itembonuses.SpellOnDeath[i]].ResistDiff); } } if(spellbonuses.SpellOnDeath[i] && IsValidSpell(spellbonuses.SpellOnDeath[i])) { - if(MakeRandomInt(0, 99) < static_cast(spellbonuses.SpellOnDeath[i + 1])) { + if(zone->random.Roll(static_cast(spellbonuses.SpellOnDeath[i + 1]))) { SpellFinished(spellbonuses.SpellOnDeath[i], this, 10, 0, -1, spells[spellbonuses.SpellOnDeath[i]].ResistDiff); } } @@ -4475,7 +4475,7 @@ bool Mob::TryReflectSpell(uint32 spell_id) int chance = itembonuses.reflect_chance + spellbonuses.reflect_chance + aabonuses.reflect_chance; - if(chance && MakeRandomInt(0, 99) < chance) + if(chance && zone->random.Roll(chance)) return true; return false; diff --git a/zone/mob.h b/zone/mob.h index 18f61281f..6135c6571 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -737,6 +737,7 @@ public: void ProjectileAttack(); inline bool HasProjectileAttack() const { return ActiveProjectileATK; } inline void SetProjectileAttack(bool value) { ActiveProjectileATK = value; } + float GetRangeDistTargetSizeMod(Mob* other); bool CanDoSpecialAttack(Mob *other); bool Flurry(ExtraAttackOptions *opts); bool Rampage(ExtraAttackOptions *opts); diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 1f6eb47b8..657d5045c 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -59,7 +59,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) { return false; if (iChance < 100) { - if (MakeRandomInt(0, 100) >= iChance) + if (zone->random.Int(0, 100) >= iChance) return false; } @@ -96,7 +96,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) { dist2 <= spells[AIspells[i].spellid].range*spells[AIspells[i].spellid].range ) && (mana_cost <= GetMana() || GetMana() == GetMaxMana()) - && (AIspells[i].time_cancast + (MakeRandomInt(0, 4) * 1000)) <= Timer::GetCurrentTime() //break up the spelling casting over a period of time. + && (AIspells[i].time_cancast + (zone->random.Int(0, 4) * 1000)) <= Timer::GetCurrentTime() //break up the spelling casting over a period of time. ) { #if MobAI_DEBUG_Spells >= 21 @@ -128,7 +128,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) { } case SpellType_Root: { Mob *rootee = GetHateRandom(); - if (rootee && !rootee->IsRooted() && MakeRandomInt(0, 99) < 50 + if (rootee && !rootee->IsRooted() && zone->random.Roll(50) && rootee->DontRootMeBefore() < Timer::GetCurrentTime() && rootee->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0 ) { @@ -167,7 +167,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) { } case SpellType_InCombatBuff: { - if(MakeRandomInt(0, 99) < 50) + if(zone->random.Roll(50)) { AIDoSpellCast(i, tar, mana_cost); return true; @@ -186,7 +186,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) { case SpellType_Slow: case SpellType_Debuff: { Mob * debuffee = GetHateRandom(); - if (debuffee && manaR >= 10 && MakeRandomInt(0, 99 < 70) && + if (debuffee && manaR >= 10 && zone->random.Roll(70) && debuffee->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0) { if (!checked_los) { if (!CheckLosFN(debuffee)) @@ -200,7 +200,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) { } case SpellType_Nuke: { if ( - manaR >= 10 && MakeRandomInt(0, 99) < 70 + manaR >= 10 && zone->random.Roll(70) && tar->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0 ) { if(!checked_los) { @@ -214,7 +214,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) { break; } case SpellType_Dispel: { - if(MakeRandomInt(0, 99) < 15) + if(zone->random.Roll(15)) { if(!checked_los) { if(!CheckLosFN(tar)) @@ -230,7 +230,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) { break; } case SpellType_Mez: { - if(MakeRandomInt(0, 99) < 20) + if(zone->random.Roll(20)) { Mob * mezTar = nullptr; mezTar = entity_list.GetTargetForMez(this); @@ -246,7 +246,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) { case SpellType_Charm: { - if(!IsPet() && MakeRandomInt(0, 99) < 20) + if(!IsPet() && zone->random.Roll(20)) { Mob * chrmTar = GetHateRandom(); if(chrmTar && chrmTar->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0) @@ -260,7 +260,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) { case SpellType_Pet: { //keep mobs from recasting pets when they have them. - if (!IsPet() && !GetPetID() && MakeRandomInt(0, 99) < 25) { + if (!IsPet() && !GetPetID() && zone->random.Roll(25)) { AIDoSpellCast(i, tar, mana_cost); return true; } @@ -268,7 +268,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) { } case SpellType_Lifetap: { if (GetHPRatio() <= 95 - && MakeRandomInt(0, 99) < 50 + && zone->random.Roll(50) && tar->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0 ) { if(!checked_los) { @@ -284,7 +284,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) { case SpellType_Snare: { if ( !tar->IsRooted() - && MakeRandomInt(0, 99) < 50 + && zone->random.Roll(50) && tar->DontSnareMeBefore() < Timer::GetCurrentTime() && tar->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0 ) { @@ -302,7 +302,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) { } case SpellType_DOT: { if ( - MakeRandomInt(0, 99) < 60 + zone->random.Roll(60) && tar->DontDotMeBefore() < Timer::GetCurrentTime() && tar->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0 ) { @@ -371,7 +371,7 @@ bool EntityList::AICheckCloseBeneficialSpells(NPC* caster, uint8 iChance, float return false; if (iChance < 100) { - uint8 tmp = MakeRandomInt(0, 99); + uint8 tmp = zone->random.Int(0, 99); if (tmp >= iChance) return false; } @@ -689,7 +689,7 @@ void Client::AI_SpellCast() } else { - uint32 idx = MakeRandomInt(0, (valid_spells.size()-1)); + uint32 idx = zone->random.Int(0, (valid_spells.size()-1)); spell_to_cast = valid_spells[idx]; slot_to_use = slots[idx]; } @@ -877,7 +877,7 @@ void Client::AI_Process() if (flurrychance) { - if(MakeRandomInt(0, 100) < flurrychance) + if(zone->random.Roll(flurrychance)) { Message_StringID(MT_NPCFlurry, YOU_FLURRY); Attack(GetTarget(), MainPrimary, false); @@ -894,7 +894,7 @@ void Client::AI_Process() wpn->GetItem()->ItemType == ItemType2HBlunt || wpn->GetItem()->ItemType == ItemType2HPiercing ) { - if(MakeRandomInt(0, 100) < ExtraAttackChanceBonus) + if(zone->random.Roll(ExtraAttackChanceBonus)) { Attack(GetTarget(), MainPrimary, false); } @@ -933,7 +933,7 @@ void Client::AI_Process() int16 DWBonus = spellbonuses.DualWieldChance + itembonuses.DualWieldChance; DualWieldProbability += DualWieldProbability*float(DWBonus)/ 100.0f; - if(MakeRandomFloat(0.0, 1.0) < DualWieldProbability) + if(zone->random.Roll(DualWieldProbability)) { Attack(GetTarget(), MainSecondary); if(CheckDoubleAttack()) @@ -1193,7 +1193,7 @@ void Mob::AI_Process() { //we use this random value in three comparisons with different //thresholds, and if its truely random, then this should work //out reasonably and will save us compute resources. - int32 RandRoll = MakeRandomInt(0, 99); + int32 RandRoll = zone->random.Int(0, 99); if ((CanThisClassDoubleAttack() || GetSpecialAbility(SPECATK_TRIPLE) || GetSpecialAbility(SPECATK_QUAD)) //check double attack, this is NOT the same rules that clients use... @@ -1217,7 +1217,7 @@ void Mob::AI_Process() { int flurry_chance = GetSpecialAbilityParam(SPECATK_FLURRY, 0); flurry_chance = flurry_chance > 0 ? flurry_chance : RuleI(Combat, NPCFlurryChance); - if (MakeRandomInt(0, 99) < flurry_chance) { + if (zone->random.Roll(flurry_chance)) { ExtraAttackOptions opts; int cur = GetSpecialAbilityParam(SPECATK_FLURRY, 2); if (cur > 0) @@ -1259,7 +1259,7 @@ void Mob::AI_Process() { int16 flurry_chance = owner->aabonuses.PetFlurry + owner->spellbonuses.PetFlurry + owner->itembonuses.PetFlurry; - if (flurry_chance && (MakeRandomInt(0, 99) < flurry_chance)) + if (flurry_chance && zone->random.Roll(flurry_chance)) Flurry(nullptr); } } @@ -1268,7 +1268,7 @@ void Mob::AI_Process() { { int rampage_chance = GetSpecialAbilityParam(SPECATK_RAMPAGE, 0); rampage_chance = rampage_chance > 0 ? rampage_chance : 20; - if(MakeRandomInt(0, 99) < rampage_chance) { + if(zone->random.Roll(rampage_chance)) { ExtraAttackOptions opts; int cur = GetSpecialAbilityParam(SPECATK_RAMPAGE, 2); if(cur > 0) { @@ -1307,7 +1307,7 @@ void Mob::AI_Process() { { int rampage_chance = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 0); rampage_chance = rampage_chance > 0 ? rampage_chance : 20; - if(MakeRandomInt(0, 99) < rampage_chance) { + if(zone->random.Roll(rampage_chance)) { ExtraAttackOptions opts; int cur = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 2); if(cur > 0) { @@ -1351,13 +1351,12 @@ void Mob::AI_Process() { //can only dual wield without a weapon if your a monk if(GetSpecialAbility(SPECATK_INNATE_DW) || (GetEquipment(MaterialSecondary) != 0 && GetLevel() > 29) || myclass == MONK || myclass == MONKGM) { float DualWieldProbability = (GetSkill(SkillDualWield) + GetLevel()) / 400.0f; - if(MakeRandomFloat(0.0, 1.0) < DualWieldProbability) + if(zone->random.Roll(DualWieldProbability)) { Attack(target, MainSecondary); if (CanThisClassDoubleAttack()) { - int32 RandRoll = MakeRandomInt(0, 99); - if (RandRoll < (GetLevel() + 20)) + if (zone->random.Roll(GetLevel() + 20)) { Attack(target, MainSecondary); } @@ -1621,12 +1620,12 @@ void NPC::AI_DoMovement() { ) { float movedist = roambox_distance*roambox_distance; - float movex = MakeRandomFloat(0, movedist); + float movex = zone->random.Real(0, movedist); float movey = movedist - movex; movex = sqrtf(movex); movey = sqrtf(movey); - movex *= MakeRandomInt(0, 1) ? 1 : -1; - movey *= MakeRandomInt(0, 1) ? 1 : -1; + movex *= zone->random.Int(0, 1) ? 1 : -1; + movey *= zone->random.Int(0, 1) ? 1 : -1; roambox_movingto_x = GetX() + movex; roambox_movingto_y = GetY() + movey; //Try to calculate new coord using distance. @@ -1637,9 +1636,9 @@ void NPC::AI_DoMovement() { //New coord is still invalid, ignore distance and just pick a new random coord. //If we're here we may have a roambox where one side is shorter than the specified distance. Commons, Wkarana, etc. if (roambox_movingto_x > roambox_max_x || roambox_movingto_x < roambox_min_x) - roambox_movingto_x = MakeRandomFloat(roambox_min_x+1,roambox_max_x-1); + roambox_movingto_x = zone->random.Real(roambox_min_x+1,roambox_max_x-1); if (roambox_movingto_y > roambox_max_y || roambox_movingto_y < roambox_min_y) - roambox_movingto_y = MakeRandomFloat(roambox_min_y+1,roambox_max_y-1); + roambox_movingto_y = zone->random.Real(roambox_min_y+1,roambox_max_y-1); } mlog(AI__WAYPOINTS, "Roam Box: d=%.3f (%.3f->%.3f,%.3f->%.3f): Go To (%.3f,%.3f)", @@ -1890,7 +1889,7 @@ void Mob::AI_Event_NoLongerEngaged() { if (minLastFightingDelayMoving == maxLastFightingDelayMoving) pLastFightingDelayMoving += minLastFightingDelayMoving; else - pLastFightingDelayMoving += MakeRandomInt(minLastFightingDelayMoving, maxLastFightingDelayMoving); + pLastFightingDelayMoving += zone->random.Int(minLastFightingDelayMoving, maxLastFightingDelayMoving); // So mobs don't keep running as a ghost until AIwalking_timer fires // if they were moving prior to losing all hate if(IsMoving()){ diff --git a/zone/npc.cpp b/zone/npc.cpp index 17ab9ed48..034be8f75 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -293,7 +293,7 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, float x, float y, float z, float if(trap_list.size() > 0) { std::list::iterator trap_list_iter = trap_list.begin(); - std::advance(trap_list_iter, MakeRandomInt(0, trap_list.size() - 1)); + std::advance(trap_list_iter, zone->random.Int(0, trap_list.size() - 1)); LDoNTrapTemplate* tt = (*trap_list_iter); if(tt) { @@ -550,10 +550,10 @@ void NPC::AddCash(uint16 in_copper, uint16 in_silver, uint16 in_gold, uint16 in_ } void NPC::AddCash() { - copper = MakeRandomInt(1, 100); - silver = MakeRandomInt(1, 50); - gold = MakeRandomInt(1, 10); - platinum = MakeRandomInt(1, 5); + copper = zone->random.Int(1, 100); + silver = zone->random.Int(1, 50); + gold = zone->random.Int(1, 10); + platinum = zone->random.Int(1, 5); } void NPC::RemoveCash() { @@ -1372,7 +1372,7 @@ void NPC::PickPocket(Client* thief) { return; } - if(MakeRandomInt(0, 100) > 95){ + if(zone->random.Roll(5)) { AddToHateList(thief, 50); Say("Stop thief!"); thief->Message(13, "You are noticed trying to steal!"); @@ -1401,7 +1401,7 @@ void NPC::PickPocket(Client* thief) { memset(charges,0,50); //Determine wheter to steal money or an item. bool no_coin = ((money[0] + money[1] + money[2] + money[3]) == 0); - bool steal_item = (MakeRandomInt(0, 99) < 50 || no_coin); + bool steal_item = (zone->random.Roll(50) || no_coin); if (steal_item) { ItemList::iterator cur,end; @@ -1431,7 +1431,7 @@ void NPC::PickPocket(Client* thief) { } if (x > 0) { - int random = MakeRandomInt(0, x-1); + int random = zone->random.Int(0, x-1); inst = database.CreateItem(steal_items[random], charges[random]); if (inst) { @@ -1466,7 +1466,7 @@ void NPC::PickPocket(Client* thief) { } if (!steal_item) //Steal money { - uint32 amt = MakeRandomInt(1, (steal_skill/25)+1); + uint32 amt = zone->random.Int(1, (steal_skill/25)+1); int steal_type = 0; if (!money[0]) { @@ -1481,7 +1481,7 @@ void NPC::PickPocket(Client* thief) { } } - if (MakeRandomInt(0, 100) <= stealchance) + if (zone->random.Roll(stealchance)) { switch (steal_type) { @@ -1962,7 +1962,7 @@ void NPC::ModifyNPCStat(const char *identifier, const char *newValue) void NPC::LevelScale() { - uint8 random_level = (MakeRandomInt(level, maxlevel)); + uint8 random_level = (zone->random.Int(level, maxlevel)); float scaling = (((random_level / (float)level) - 1) * (scalerate / 100.0f)); @@ -2449,4 +2449,4 @@ void NPC::DepopSwarmPets() } } } -} \ No newline at end of file +} diff --git a/zone/object.cpp b/zone/object.cpp index 0201434c0..b1acc53c9 100644 --- a/zone/object.cpp +++ b/zone/object.cpp @@ -441,8 +441,8 @@ void Object::RandomSpawn(bool send_packet) { if(!m_ground_spawn) return; - m_data.x = MakeRandomFloat(m_min_x, m_max_x); - m_data.y = MakeRandomFloat(m_min_y, m_max_y); + m_data.x = zone->random.Real(m_min_x, m_max_x); + m_data.y = zone->random.Real(m_min_y, m_max_y); respawn_timer.Disable(); if(send_packet) { diff --git a/zone/pathing.cpp b/zone/pathing.cpp index c860913fe..3bf02115e 100644 --- a/zone/pathing.cpp +++ b/zone/pathing.cpp @@ -1344,7 +1344,7 @@ PathNode* PathManager::FindPathNodeByCoordinates(float x, float y, float z) int PathManager::GetRandomPathNode() { - return MakeRandomInt(0, Head.PathNodeCount - 1); + return zone->random.Int(0, Head.PathNodeCount - 1); } diff --git a/zone/pets.cpp b/zone/pets.cpp index cf9ecab8c..052a44bea 100644 --- a/zone/pets.cpp +++ b/zone/pets.cpp @@ -109,7 +109,7 @@ const char *GetRandPetName() "Zibann","Zibarer","Zibartik","Zibekn","Zibn","Zibobn","Zobaner","Zobann", "Zobarn","Zober","Zobn","Zonanab","Zonaner","Zonann","Zonantik","Zonarer", "Zonartik","Zonobn","Zonobtik","Zontik","Ztik" }; - int r = MakeRandomInt(0, (sizeof(petnames)/sizeof(const char *))-1); + int r = zone->random.Int(0, (sizeof(petnames)/sizeof(const char *))-1); printf("Pet being created: %s\n",petnames[r]); // DO NOT COMMENT THIS OUT! return petnames[r]; } diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 2ce1dbc37..38f40142d 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -2658,14 +2658,16 @@ const char* QuestManager::saylink(char* Phrase, bool silent, const char* LinkNam char linktext[250]; if (initiator) { - if (initiator->GetClientVersion() >= EQClientRoF) - sprintf(linktext,"%c%06X%s%s%c",0x12,sayid,"0000000000000000000000000000000000000000000000000",LinkName,0x12); + if (initiator->GetClientVersion() >= EQClientRoF2) + sprintf(linktext, "%c%06X%s%s%c", 0x12, sayid, "00000000000000000000000000000000000000000000000000", LinkName, 0x12); + else if (initiator->GetClientVersion() >= EQClientRoF) + sprintf(linktext, "%c%06X%s%s%c", 0x12, sayid, "0000000000000000000000000000000000000000000000000", LinkName, 0x12); else if (initiator->GetClientVersion() >= EQClientSoF) - sprintf(linktext,"%c%06X%s%s%c",0x12,sayid,"00000000000000000000000000000000000000000000",LinkName,0x12); + sprintf(linktext, "%c%06X%s%s%c", 0x12, sayid, "00000000000000000000000000000000000000000000", LinkName, 0x12); else - sprintf(linktext,"%c%06X%s%s%c",0x12,sayid,"000000000000000000000000000000000000000",LinkName,0x12); - } else { // If no initiator, create an RoF saylink, since older clients handle RoF ones better than RoF handles older ones. - sprintf(linktext,"%c%06X%s%s%c",0x12,sayid,"0000000000000000000000000000000000000000000000000",LinkName,0x12); + sprintf(linktext, "%c%06X%s%s%c", 0x12, sayid, "000000000000000000000000000000000000000", LinkName, 0x12); + } else { // If no initiator, create an RoF2 saylink, since older clients handle RoF2 ones better than RoF2 handles older ones. + sprintf(linktext, "%c%06X%s%s%c", 0x12, sayid, "00000000000000000000000000000000000000000000000000", LinkName, 0x12); } strcpy(Phrase,linktext); diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index 8d8562157..bf7192107 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -109,7 +109,7 @@ uint32 Spawn2::resetTimer() if (variance_ != 0) { int var_over_2 = (variance_ * 1000) / 2; - rspawn = MakeRandomInt(rspawn - var_over_2, rspawn + var_over_2); + rspawn = zone->random.Int(rspawn - var_over_2, rspawn + var_over_2); //put a lower bound on it, not a lot of difference below 100, so set that as the bound. if(rspawn < 100) @@ -126,7 +126,7 @@ uint32 Spawn2::despawnTimer(uint32 despawn_timer) if (variance_ != 0) { int var_over_2 = (variance_ * 1000) / 2; - dspawn = MakeRandomInt(dspawn - var_over_2, dspawn + var_over_2); + dspawn = zone->random.Int(dspawn - var_over_2, dspawn + var_over_2); //put a lower bound on it, not a lot of difference below 100, so set that as the bound. if(dspawn < 100) diff --git a/zone/spawngroup.cpp b/zone/spawngroup.cpp index 81d6c5d51..6943d9349 100644 --- a/zone/spawngroup.cpp +++ b/zone/spawngroup.cpp @@ -25,8 +25,10 @@ #include "zonedb.h" #include "../common/misc_functions.h" #include "../common/string_util.h" +#include "zone.h" extern EntityList entity_list; +extern Zone* zone; SpawnEntry::SpawnEntry( uint32 in_NPCType, int in_chance, uint8 in_npc_spawn_limit ) { NPCType = in_NPCType; @@ -77,7 +79,7 @@ uint32 SpawnGroup::GetNPCType() { int32 roll = 0; - roll = MakeRandomInt(0, totalchance-1); + roll = zone->random.Int(0, totalchance-1); cur = possible.begin(); end = possible.end(); diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index 671968350..928353149 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -138,9 +138,9 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, who->MeleeMitigation(this, max_damage, min_damage); - if(max_damage > 0) + if(max_damage > 0) CommonOutgoingHitSuccess(who, max_damage, skill); - + } who->AddToHateList(this, hate, 0, false); @@ -155,17 +155,17 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int kb_chance = 25; kb_chance += kb_chance*(100-aabonuses.SpecialAttackKBProc[0])/100; - if (MakeRandomInt(0, 99) < kb_chance) + if (zone->random.Roll(kb_chance)) SpellFinished(904, who, 10, 0, -1, spells[904].ResistDiff); //who->Stun(100); Kayen: This effect does not stun on live, it only moves the NPC. } if (HasSkillProcs()) TrySkillProc(who, skill, ReuseTime*1000); - + if (max_damage > 0 && HasSkillProcSuccess()) TrySkillProc(who, skill, ReuseTime*1000, true); - + if(max_damage == -3 && !who->HasDied()) DoRiposte(who); } @@ -256,7 +256,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) { if(RuleB(Combat, UseIntervalAC)) ht = dmg = GetBashDamage(); else - ht = dmg = MakeRandomInt(1, GetBashDamage()); + ht = dmg = zone->random.Int(1, GetBashDamage()); } } @@ -295,8 +295,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) { //Live parses show around 55% Triple 35% Double 10% Single, you will always get first hit. while(AtkRounds > 0) { - - if (GetTarget() && (AtkRounds == 1 || MakeRandomInt(0,100) < 75)){ + if (GetTarget() && (AtkRounds == 1 || zone->random.Roll(75))) { DoSpecialAttackDamage(GetTarget(), SkillFrenzy, max_dmg, min_dmg, max_dmg , ReuseTime, true); } AtkRounds--; @@ -333,7 +332,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) { if(RuleB(Combat, UseIntervalAC)) ht = dmg = GetKickDamage(); else - ht = dmg = MakeRandomInt(1, GetKickDamage()); + ht = dmg = zone->random.Int(1, GetKickDamage()); } } @@ -348,18 +347,18 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) { //Live AA - Technique of Master Wu int wuchance = itembonuses.DoubleSpecialAttack + spellbonuses.DoubleSpecialAttack + aabonuses.DoubleSpecialAttack; if (wuchance) { - if (wuchance >= 100 || wuchance > MakeRandomInt(0, 99)) { + if (wuchance >= 100 || zone->random.Roll(wuchance)) { int MonkSPA [5] = { SkillFlyingKick, SkillDragonPunch, SkillEagleStrike, SkillTigerClaw, SkillRoundKick }; int extra = 1; // always 1/4 of the double attack chance, 25% at rank 5 (100/4) - if (wuchance / 4 > MakeRandomInt(0, 99)) + if (zone->random.Roll(wuchance / 4)) extra++; // They didn't add a string ID for this. std::string msg = StringFormat("The spirit of Master Wu fills you! You gain %d additional attack(s).", extra); // live uses 400 here -- not sure if it's the best for all clients though SendColoredText(400, msg); while (extra) { - MonkSpecialAttack(GetTarget(), MonkSPA[MakeRandomInt(0, 4)]); + MonkSpecialAttack(GetTarget(), MonkSPA[zone->random.Int(0, 4)]); extra--; } } @@ -484,7 +483,7 @@ int Mob::MonkSpecialAttack(Mob* other, uint8 unchecked_type) if(RuleB(Combat, UseIntervalAC)) ht = ndamage = max_dmg; else - ht = ndamage = MakeRandomInt(min_dmg, max_dmg); + ht = ndamage = zone->random.Int(min_dmg, max_dmg); } else{ ht = max_dmg; @@ -525,15 +524,14 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) { //Live AA - Seized Opportunity int FrontalBSChance = itembonuses.FrontalBackstabChance + spellbonuses.FrontalBackstabChance + aabonuses.FrontalBackstabChance; - if (FrontalBSChance && (FrontalBSChance > MakeRandomInt(0, 100))) + if (FrontalBSChance && zone->random.Roll(FrontalBSChance)) bCanFrontalBS = true; } - - if (bIsBehind || bCanFrontalBS){ // Player is behind other OR can do Frontal Backstab - if (bCanFrontalBS) + if (bIsBehind || bCanFrontalBS){ // Player is behind other OR can do Frontal Backstab + if (bCanFrontalBS) CastToClient()->Message(0,"Your fierce attack is executed with such grace, your target did not see it coming!"); - + RogueBackstab(other,false,ReuseTime); if (level > 54) { if(IsClient() && CastToClient()->CheckDoubleAttack(false)) @@ -541,14 +539,14 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) { if(other->GetHP() > 0) RogueBackstab(other,false,ReuseTime); - if (tripleChance && other->GetHP() > 0 && tripleChance > MakeRandomInt(0, 100)) + if (tripleChance && other->GetHP() > 0 && zone->random.Roll(tripleChance)) RogueBackstab(other,false,ReuseTime); } } - + if(IsClient()) CastToClient()->CheckIncreaseSkill(SkillBackstab, other, 10); - + } //Live AA - Chaotic Backstab else if(aabonuses.FrontalBackstabMinDmg || itembonuses.FrontalBackstabMinDmg || spellbonuses.FrontalBackstabMinDmg) { @@ -562,7 +560,7 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) { if(other->GetHP() > 0) RogueBackstab(other,true, ReuseTime); - if (tripleChance && other->GetHP() > 0 && tripleChance > MakeRandomInt(0, 100)) + if (tripleChance && other->GetHP() > 0 && zone->random.Roll(tripleChance)) RogueBackstab(other,false,ReuseTime); } @@ -641,7 +639,7 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime) if(RuleB(Combat, UseIntervalAC)) ndamage = max_hit; else - ndamage = MakeRandomInt(min_hit, max_hit); + ndamage = zone->random.Int(min_hit, max_hit); } } } @@ -678,7 +676,8 @@ void Mob::RogueAssassinate(Mob* other) void Client::RangedAttack(Mob* other, bool CanDoubleAttack) { //conditions to use an attack checked before we are called - + if (!other) + return; //make sure the attack and ranged timers are up //if the ranged timer is disabled, then they have no ranged weapon and shouldent be attacking anyhow if(!CanDoubleAttack && ((attack_timer.Enabled() && !attack_timer.Check(false)) || (ranged_timer.Enabled() && !ranged_timer.Check()))) { @@ -718,7 +717,7 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) { return; } - mlog(COMBAT__RANGED, "Shooting %s with bow %s (%d) and arrow %s (%d)", GetTarget()->GetName(), RangeItem->Name, RangeItem->ID, AmmoItem->Name, AmmoItem->ID); + mlog(COMBAT__RANGED, "Shooting %s with bow %s (%d) and arrow %s (%d)", other->GetName(), RangeItem->Name, RangeItem->ID, AmmoItem->Name, AmmoItem->ID); //look for ammo in inventory if we only have 1 left... if(Ammo->GetCharges() == 1) { @@ -765,19 +764,21 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) { } } - float range = RangeItem->Range + AmmoItem->Range + 5.0f; //Fudge it a little, client will let you hit something at 0 0 0 when you are at 205 0 0 + float range = RangeItem->Range + AmmoItem->Range + GetRangeDistTargetSizeMod(GetTarget()); mlog(COMBAT__RANGED, "Calculated bow range to be %.1f", range); range *= range; - if(DistNoRootNoZ(*GetTarget()) > range) { - mlog(COMBAT__RANGED, "Ranged attack out of range... client should catch this. (%f > %f).\n", DistNoRootNoZ(*GetTarget()), range); - //target is out of range, client does a message + float dist = DistNoRoot(*other); + if(dist > range) { + mlog(COMBAT__RANGED, "Ranged attack out of range... client should catch this. (%f > %f).\n", dist, range); + Message_StringID(13,TARGET_OUT_OF_RANGE);//Client enforces range and sends the message, this is a backup just incase. return; } - else if(DistNoRootNoZ(*GetTarget()) < (RuleI(Combat, MinRangedAttackDist)*RuleI(Combat, MinRangedAttackDist))){ + else if(dist < (RuleI(Combat, MinRangedAttackDist)*RuleI(Combat, MinRangedAttackDist))){ + Message_StringID(15,RANGED_TOO_CLOSE);//Client enforces range and sends the message, this is a backup just incase. return; } - if(!IsAttackAllowed(GetTarget()) || + if(!IsAttackAllowed(other) || IsCasting() || IsSitting() || (DivineAura() && !GetGM()) || @@ -789,12 +790,12 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) { } //Shoots projectile and/or applies the archery damage - DoArcheryAttackDmg(GetTarget(), RangeWeapon, Ammo,0,0,0,0,0,0, AmmoItem, ammo_slot); + DoArcheryAttackDmg(other, RangeWeapon, Ammo,0,0,0,0,0,0, AmmoItem, ammo_slot); //EndlessQuiver AA base1 = 100% Chance to avoid consumption arrow. int ChanceAvoidConsume = aabonuses.ConsumeProjectile + itembonuses.ConsumeProjectile + spellbonuses.ConsumeProjectile; - if (!ChanceAvoidConsume || (ChanceAvoidConsume < 100 && MakeRandomInt(0,99) > ChanceAvoidConsume)){ + if (!ChanceAvoidConsume || (ChanceAvoidConsume < 100 && zone->random.Int(0,99) > ChanceAvoidConsume)){ DeleteItemInInventory(ammo_slot, 1, true); mlog(COMBAT__RANGED, "Consumed one arrow from slot %d", ammo_slot); } else { @@ -829,6 +830,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite this function is then run again to do the damage portion */ bool LaunchProjectile = false; + bool ProjectileImpact = false; bool ProjectileMiss = false; if (RuleB(Combat, ProjectileDmgOnImpact)){ @@ -845,6 +847,8 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite if (!RangeWeapon && !Ammo && range_id && ammo_id){ + ProjectileImpact = true; + if (weapon_damage == 0) ProjectileMiss = true; //This indicates that MISS was originally calculated. @@ -866,7 +870,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite else if (AmmoItem) SendItemAnimation(other, AmmoItem, SkillArchery); - if (ProjectileMiss || !other->CheckHitChance(this, SkillArchery, MainPrimary, chance_mod)) { + if (ProjectileMiss || (!ProjectileImpact && !other->CheckHitChance(this, SkillArchery, MainPrimary, chance_mod))) { mlog(COMBAT__RANGED, "Ranged attack missed %s.", other->GetName()); if (LaunchProjectile){ @@ -921,11 +925,10 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite bool dobonus = false; if(GetClass() == RANGER && GetLevel() > 50){ - int bonuschance = RuleI(Combat, ArcheryBonusChance); bonuschance = mod_archery_bonus_chance(bonuschance, RangeWeapon); - if( !RuleB(Combat, UseArcheryBonusRoll) || (MakeRandomInt(1, 100) < bonuschance)){ + if( !RuleB(Combat, UseArcheryBonusRoll) || zone->random.Roll(bonuschance)){ if(RuleB(Combat, ArcheryBonusRequiresStationary)){ if(other->IsNPC() && !other->IsMoving() && !other->IsRooted()) dobonus = true; @@ -950,7 +953,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite if(RuleB(Combat, UseIntervalAC)) TotalDmg = MaxDmg; else - TotalDmg = MakeRandomInt(1, MaxDmg); + TotalDmg = zone->random.Int(1, MaxDmg); int minDmg = 1; if(GetLevel() > 25){ @@ -1125,6 +1128,45 @@ void Mob::ProjectileAttack() SetProjectileAttack(false); } +float Mob::GetRangeDistTargetSizeMod(Mob* other) +{ + /* + Range is enforced client side, therefore these numbers do not need to be 100% accurate just close enough to + prevent any exploitation. The range mod changes in some situations depending on if size is from spawn or from SendIllusionPacket changes. + At present time only calculate from spawn (it is no consistent what happens to the calc when changing it after spawn). + */ + if (!other) + return 0.0f; + + float tsize = other->GetSize(); + + if (GetSize() > tsize) + tsize = GetSize(); + + float mod = 0.0f; + /*These are correct numbers if mob size is changed via #size (Don't know why it matters but it does) + if (tsize < 7) + mod = 16.0f; + else if (tsize >=7 && tsize <= 20) + mod = 16.0f + (0.6f * (tsize - 6.0f)); + else if (tsize >=20 && tsize <= 60) + mod = 25.0f + (1.25f * (tsize - 20.0f)); + else + mod = 75.0f; + */ + + if (tsize < 10) + mod = 18.0f; + else if (tsize >=10 && tsize < 15) + mod = 20.0f + (4.0f * (tsize - 10.0f)); + else if (tsize >=15 && tsize <= 20) + mod = 42.0f + (5.8f * (tsize - 15.0f)); + else + mod = 75.0f; + + return (mod + 2.0f); //Add 2.0f as buffer to prevent any chance of failures, client enforce range check regardless. +} + void NPC::RangedAttack(Mob* other) { @@ -1194,9 +1236,9 @@ void NPC::RangedAttack(Mob* other) if(ammo) SendItemAnimation(other, ammo, SkillArchery); - else + else ProjectileAnimation(other, 0,false,0,0,0,0,GetAmmoIDfile(),skillinuse); - + FaceTarget(other); if (!other->CheckHitChance(this, skillinuse, MainRange, GetSpecialAbilityParam(SPECATK_RANGED_ATK, 2))) @@ -1212,17 +1254,17 @@ void NPC::RangedAttack(Mob* other) if(WDmg > 0 || ADmg > 0) { mlog(COMBAT__RANGED, "Ranged attack hit %s.", other->GetName()); - + int32 MaxDmg = max_dmg * RuleR(Combat, ArcheryNPCMultiplier); // should add a field to npc_types int32 MinDmg = min_dmg * RuleR(Combat, ArcheryNPCMultiplier); if(RuleB(Combat, UseIntervalAC)) TotalDmg = MaxDmg; else - TotalDmg = MakeRandomInt(MinDmg, MaxDmg); + TotalDmg = zone->random.Int(MinDmg, MaxDmg); TotalDmg += TotalDmg * GetSpecialAbilityParam(SPECATK_RANGED_ATK, 3) / 100; //Damage modifier - + other->AvoidDamage(this, TotalDmg, false); other->MeleeMitigation(this, TotalDmg, MinDmg); if (TotalDmg > 0) @@ -1263,7 +1305,7 @@ uint16 Mob::GetThrownDamage(int16 wDmg, int32& TotalDmg, int& minDmg) { if(RuleB(Combat, UseIntervalAC)) TotalDmg = MaxDmg; else - TotalDmg = MakeRandomInt(1, MaxDmg); + TotalDmg = zone->random.Int(1, MaxDmg); minDmg = 1; if(GetLevel() > 25){ @@ -1282,7 +1324,8 @@ uint16 Mob::GetThrownDamage(int16 wDmg, int32& TotalDmg, int& minDmg) { void Client::ThrowingAttack(Mob* other, bool CanDoubleAttack) { //old was 51 //conditions to use an attack checked before we are called - + if (!other) + return; //make sure the attack and ranged timers are up //if the ranged timer is disabled, then they have no ranged weapon and shouldent be attacking anyhow if((!CanDoubleAttack && (attack_timer.Enabled() && !attack_timer.Check(false)) || (ranged_timer.Enabled() && !ranged_timer.Check()))) { @@ -1308,7 +1351,7 @@ void Client::ThrowingAttack(Mob* other, bool CanDoubleAttack) { //old was 51 return; } - mlog(COMBAT__RANGED, "Throwing %s (%d) at %s", item->Name, item->ID, GetTarget()->GetName()); + mlog(COMBAT__RANGED, "Throwing %s (%d) at %s", item->Name, item->ID, other->GetName()); if(RangeWeapon->GetCharges() == 1) { //first check ammo @@ -1330,19 +1373,20 @@ void Client::ThrowingAttack(Mob* other, bool CanDoubleAttack) { //old was 51 } } - int range = item->Range +50/*Fudge it a little, client will let you hit something at 0 0 0 when you are at 205 0 0*/; + float range = item->Range + GetRangeDistTargetSizeMod(other); mlog(COMBAT__RANGED, "Calculated bow range to be %.1f", range); range *= range; - if(DistNoRootNoZ(*GetTarget()) > range) { - mlog(COMBAT__RANGED, "Throwing attack out of range... client should catch this. (%f > %f).\n", DistNoRootNoZ(*GetTarget()), range); - //target is out of range, client does a message + float dist = DistNoRoot(*other); + if(dist > range) { + mlog(COMBAT__RANGED, "Throwing attack out of range... client should catch this. (%f > %f).\n", dist, range); + Message_StringID(13,TARGET_OUT_OF_RANGE);//Client enforces range and sends the message, this is a backup just incase. return; } - else if(DistNoRootNoZ(*GetTarget()) < (RuleI(Combat, MinRangedAttackDist)*RuleI(Combat, MinRangedAttackDist))){ - return; + else if(dist < (RuleI(Combat, MinRangedAttackDist)*RuleI(Combat, MinRangedAttackDist))){ + Message_StringID(15,RANGED_TOO_CLOSE);//Client enforces range and sends the message, this is a backup just incase. } - if(!IsAttackAllowed(GetTarget()) || + if(!IsAttackAllowed(other) || IsCasting() || IsSitting() || (DivineAura() && !GetGM()) || @@ -1353,7 +1397,7 @@ void Client::ThrowingAttack(Mob* other, bool CanDoubleAttack) { //old was 51 return; } - DoThrowingAttackDmg(GetTarget(), RangeWeapon, item); + DoThrowingAttackDmg(other, RangeWeapon, item); //consume ammo DeleteItemInInventory(ammo_slot, 1, true); @@ -1383,6 +1427,7 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite this function is then run again to do the damage portion */ bool LaunchProjectile = false; + bool ProjectileImpact = false; bool ProjectileMiss = false; if (RuleB(Combat, ProjectileDmgOnImpact)){ @@ -1392,6 +1437,8 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite else{ if (!RangeWeapon && range_id){ + ProjectileImpact = true; + if (weapon_damage == 0) ProjectileMiss = true; //This indicates that MISS was originally calculated. @@ -1409,7 +1456,7 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite else if (AmmoItem) SendItemAnimation(other, AmmoItem, SkillThrowing); - if (ProjectileMiss || !other->CheckHitChance(this, SkillThrowing, MainPrimary, chance_mod)){ + if (ProjectileMiss || (!ProjectileImpact && !other->CheckHitChance(this, SkillThrowing, MainPrimary, chance_mod))){ mlog(COMBAT__RANGED, "Ranged attack missed %s.", other->GetName()); if (LaunchProjectile){ TryProjectileAttack(other, AmmoItem, SkillThrowing, 0, RangeWeapon, nullptr, AmmoSlot, speed); @@ -1681,7 +1728,7 @@ void NPC::DoClassAttacks(Mob *target) { } case WARRIOR: case WARRIORGM:{ if(level >= RuleI(Combat, NPCBashKickLevel)){ - if(MakeRandomInt(0, 100) > 25){ //tested on live, warrior mobs both kick and bash, kick about 75% of the time, casting doesn't seem to make a difference. + if(zone->random.Roll(75)) { //tested on live, warrior mobs both kick and bash, kick about 75% of the time, casting doesn't seem to make a difference. DoAnim(animKick); int32 dmg = 0; @@ -1693,7 +1740,7 @@ void NPC::DoClassAttacks(Mob *target) { if(RuleB(Combat, UseIntervalAC)) dmg = GetKickDamage(); else - dmg = MakeRandomInt(1, GetKickDamage()); + dmg = zone->random.Int(1, GetKickDamage()); } } @@ -1714,7 +1761,7 @@ void NPC::DoClassAttacks(Mob *target) { if(RuleB(Combat, UseIntervalAC)) dmg = GetBashDamage(); else - dmg = MakeRandomInt(1, GetBashDamage()); + dmg = zone->random.Int(1, GetBashDamage()); } } @@ -1741,8 +1788,8 @@ void NPC::DoClassAttacks(Mob *target) { reuse = FrenzyReuseTime * 1000; - while(AtkRounds > 0) { - if (GetTarget() && (AtkRounds == 1 || MakeRandomInt(0,100) < 75)){ + while(AtkRounds > 0) { + if (GetTarget() && (AtkRounds == 1 || zone->random.Roll(75))) { DoSpecialAttackDamage(GetTarget(), SkillFrenzy, max_dmg, min_dmg, -1 , reuse, true); } AtkRounds--; @@ -1767,7 +1814,7 @@ void NPC::DoClassAttacks(Mob *target) { if(RuleB(Combat, UseIntervalAC)) dmg = GetKickDamage(); else - dmg = MakeRandomInt(1, GetKickDamage()); + dmg = zone->random.Int(1, GetKickDamage()); } } @@ -1792,7 +1839,7 @@ void NPC::DoClassAttacks(Mob *target) { if(RuleB(Combat, UseIntervalAC)) dmg = GetBashDamage(); else - dmg = MakeRandomInt(1, GetBashDamage()); + dmg = zone->random.Int(1, GetBashDamage()); } } @@ -1901,7 +1948,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte) if(RuleB(Combat, UseIntervalAC)) dmg = GetBashDamage(); else - dmg = MakeRandomInt(1, GetBashDamage()); + dmg = zone->random.Int(1, GetBashDamage()); } } @@ -1938,7 +1985,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte) //Live parses show around 55% Triple 35% Double 10% Single, you will always get first hit. while(AtkRounds > 0) { - if (GetTarget() && (AtkRounds == 1 || MakeRandomInt(0,100) < 75)){ + if (GetTarget() && (AtkRounds == 1 || zone->random.Roll(75))) { DoSpecialAttackDamage(GetTarget(), SkillFrenzy, max_dmg, min_dmg, max_dmg , ReuseTime, true); } AtkRounds--; @@ -1965,7 +2012,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte) if(RuleB(Combat, UseIntervalAC)) dmg = GetKickDamage(); else - dmg = MakeRandomInt(1, GetKickDamage()); + dmg = zone->random.Int(1, GetKickDamage()); } } @@ -1985,17 +2032,17 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte) //Live AA - Technique of Master Wu int wuchance = itembonuses.DoubleSpecialAttack + spellbonuses.DoubleSpecialAttack + aabonuses.DoubleSpecialAttack; if (wuchance) { - if (wuchance >= 100 || wuchance > MakeRandomInt(0, 99)) { + if (wuchance >= 100 || zone->random.Roll(wuchance)) { int MonkSPA [5] = { SkillFlyingKick, SkillDragonPunch, SkillEagleStrike, SkillTigerClaw, SkillRoundKick }; int extra = 1; - if (wuchance / 4 > MakeRandomInt(0, 99)) + if (zone->random.Roll(wuchance / 4)) extra++; // They didn't add a string ID for this. std::string msg = StringFormat("The spirit of Master Wu fills you! You gain %d additional attack(s).", extra); // live uses 400 here -- not sure if it's the best for all clients though SendColoredText(400, msg); while (extra) { - MonkSpecialAttack(ca_target, MonkSPA[MakeRandomInt(0, 4)]); + MonkSpecialAttack(ca_target, MonkSPA[zone->random.Int(0, 4)]); extra--; } } @@ -2047,7 +2094,7 @@ void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) { int32 newhate = 0; float tauntchance = 50.0f; - + if(always_succeed) tauntchance = 101.0f; @@ -2079,7 +2126,7 @@ void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) { tauntchance /= 100.0f; - if (tauntchance > MakeRandomFloat(0, 1)) { + if (tauntchance > zone->random.Real(0, 1)) { if (hate_top && hate_top != this){ newhate = (who->GetNPCHate(hate_top) - who->GetNPCHate(this)) + 1; who->CastToNPC()->AddToHateList(this, newhate); @@ -2101,7 +2148,7 @@ void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) { if (HasSkillProcs()) TrySkillProc(who, SkillTaunt, TauntReuseTime*1000); - + if (Success && HasSkillProcSuccess()) TrySkillProc(who, SkillTaunt, TauntReuseTime*1000, true); } @@ -2135,7 +2182,7 @@ void Mob::InstillDoubt(Mob *who) { //target's counters value -= target->GetLevel()*4 + who->GetWIS()/4; - if (MakeRandomInt(0,99) < value) { + if (zone->random.Roll(value)) { //temporary hack... //cast fear on them... should prolly be a different spell //and should be un-resistable. @@ -2144,7 +2191,7 @@ void Mob::InstillDoubt(Mob *who) { } else { Message_StringID(4,NOT_SCARING); //Idea from WR: - /* if (target->IsNPC() && MakeRandomInt(0,99) < 10 ) { + /* if (target->IsNPC() && zone->random.Int(0,99) < 10 ) { entity_list.MessageClose(target, false, 50, MT_NPCRampage, "%s lashes out in anger!",target->GetName()); //should we actually do this? and the range is completely made up, unconfirmed entity_list.AEAttack(target, 50); @@ -2152,12 +2199,12 @@ void Mob::InstillDoubt(Mob *who) { } } -uint32 Mob::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) { +uint32 Mob::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) { //Only works on YOUR target. - if(defender && (defender->GetBodyType() == BT_Humanoid) && !defender->IsClient() + if(defender && (defender->GetBodyType() == BT_Humanoid) && !defender->IsClient() && (skillInUse == SkillArchery) && (GetTarget() == defender)) { - - uint32 HeadShot_Dmg = aabonuses.HeadShot[1] + spellbonuses.HeadShot[1] + itembonuses.HeadShot[1]; + + uint32 HeadShot_Dmg = aabonuses.HeadShot[1] + spellbonuses.HeadShot[1] + itembonuses.HeadShot[1]; uint8 HeadShot_Level = 0; //Get Highest Headshot Level HeadShot_Level = aabonuses.HSLevel; if (HeadShot_Level < spellbonuses.HSLevel) @@ -2165,9 +2212,9 @@ uint32 Mob::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) { else if (HeadShot_Level < itembonuses.HSLevel) HeadShot_Level = itembonuses.HSLevel; - if(HeadShot_Dmg && HeadShot_Level && (defender->GetLevel() <= HeadShot_Level)){ + if(HeadShot_Dmg && HeadShot_Level && (defender->GetLevel() <= HeadShot_Level)){ float ProcChance = GetSpecialProcChances(MainRange); - if(ProcChance > MakeRandomFloat(0,1)) + if(zone->random.Roll(ProcChance)) return HeadShot_Dmg; } } @@ -2196,7 +2243,7 @@ float Mob::GetSpecialProcChances(uint16 hand) } else { /*PRE 2014 CHANGE Dev Quote - "Elidroth SOE:Proc chance is a function of your base hardcapped Dexterity / 35 + Heroic Dexterity / 25.” Kayen: Most reports suggest a ~ 6% chance to Headshot which consistent with above.*/ - + ProcChance = (static_cast(mydex/35) + static_cast(itembonuses.HeroicDEX / 25))/100.0f; } @@ -2207,9 +2254,9 @@ uint32 Mob::TryAssassinate(Mob* defender, SkillUseTypes skillInUse, uint16 Reuse if(defender && (defender->GetBodyType() == BT_Humanoid) && !defender->IsClient() && (skillInUse == SkillBackstab || skillInUse == SkillThrowing)) { - + uint32 Assassinate_Dmg = aabonuses.Assassinate[1] + spellbonuses.Assassinate[1] + itembonuses.Assassinate[1]; - + uint8 Assassinate_Level = 0; //Get Highest Headshot Level Assassinate_Level = aabonuses.AssassinateLevel; if (Assassinate_Level < spellbonuses.AssassinateLevel) @@ -2227,13 +2274,13 @@ uint32 Mob::TryAssassinate(Mob* defender, SkillUseTypes skillInUse, uint16 Reuse if(Assassinate_Dmg && Assassinate_Level && (defender->GetLevel() <= Assassinate_Level)){ float ProcChance = 0.0f; - + if (skillInUse == SkillThrowing) ProcChance = GetSpecialProcChances(MainRange); else ProcChance = GetAssassinateProcChances(ReuseTime); - if(ProcChance > MakeRandomFloat(0,1)) + if(zone->random.Roll(ProcChance)) return Assassinate_Dmg; } } @@ -2253,7 +2300,7 @@ float Mob::GetAssassinateProcChances(uint16 ReuseTime) if (RuleB(Combat, AdjustSpecialProcPerMinute)) { ProcChance = (static_cast(ReuseTime*1000) * - RuleR(Combat, AvgSpecialProcsPerMinute) / 60000.0f); + RuleR(Combat, AvgSpecialProcsPerMinute) / 60000.0f); ProcBonus += (10 + (static_cast(mydex/10) + static_cast(itembonuses.HeroicDEX /10)))/100.0f; ProcChance += ProcChance * ProcBonus / 100.0f; @@ -2315,7 +2362,7 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes } } - ApplySpecialAttackMod(skillinuse, max_hit, min_hit); + ApplySpecialAttackMod(skillinuse, max_hit, min_hit); min_hit += min_hit * GetMeleeMinDamageMod_SE(skillinuse) / 100; if(max_hit < min_hit) @@ -2324,8 +2371,8 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes if(RuleB(Combat, UseIntervalAC)) damage = max_hit; else - damage = MakeRandomInt(min_hit, max_hit); - + damage = zone->random.Int(min_hit, max_hit); + if(!other->CheckHitChance(this, skillinuse, Hand, chance_mod)) { damage = 0; } else { @@ -2363,7 +2410,7 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes int kb_chance = 25; kb_chance += kb_chance*(100-aabonuses.SpecialAttackKBProc[0])/100; - if (MakeRandomInt(0, 99) < kb_chance) + if (zone->random.Roll(kb_chance)) SpellFinished(904, other, 10, 0, -1, spells[904].ResistDiff); } diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index d3ef1145d..59526fbbc 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -455,7 +455,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if(IsClient()) { - if(MakeRandomInt(0, 99) < RuleI(Spells, SuccorFailChance)) { //2% Fail chance by default + if(zone->random.Roll(RuleI(Spells, SuccorFailChance))) { //2% Fail chance by default if(IsClient()) { CastToClient()->Message_StringID(MT_SpellFailure,SUCCOR_FAIL); @@ -710,9 +710,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if (IsClient()) stun_resist += aabonuses.StunResist; - if (stun_resist <= 0 || MakeRandomInt(0,99) >= stun_resist) { + if (stun_resist <= 0 || zone->random.Int(0,99) >= stun_resist) { mlog(COMBAT__HITS, "Stunned. We had %d percent resist chance.", stun_resist); - + if (caster->IsClient()) effect_value += effect_value*caster->CastToClient()->GetFocusEffect(focusFcStunTimeMod, spell_id)/100; @@ -1033,8 +1033,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) #endif if(!spellbonuses.AntiGate){ - if(MakeRandomInt(0, 99) < effect_value) - Gate(); + if(zone->random.Roll(effect_value)) + Gate(); else caster->Message_StringID(MT_SpellFailure,GATE_FAIL); } @@ -1475,16 +1475,16 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) #endif int wipechance = spells[spell_id].base[i]; int bonus = 0; - + if (caster){ - bonus = caster->spellbonuses.IncreaseChanceMemwipe + - caster->itembonuses.IncreaseChanceMemwipe + + bonus = caster->spellbonuses.IncreaseChanceMemwipe + + caster->itembonuses.IncreaseChanceMemwipe + caster->aabonuses.IncreaseChanceMemwipe; } wipechance += wipechance*bonus/100; - - if(MakeRandomInt(0, 99) < wipechance) + + if(zone->random.Roll(wipechance)) { if(IsAIControlled()) { @@ -1597,7 +1597,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if(IsClient()) { - if (MakeRandomInt(0, 99) > spells[spell_id].base[i]) { + if (zone->random.Int(0, 99) > spells[spell_id].base[i]) { CastToClient()->SetFeigned(false); entity_list.MessageClose_StringID(this, false, 200, 10, STRING_FEIGNFAILED, GetName()); } @@ -2187,7 +2187,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) #ifdef SPELL_EFFECT_SPAM snprintf(effect_desc, _EDLEN, "Fading Memories"); #endif - if(MakeRandomInt(0, 99) < spells[spell_id].base[i] ) { + if(zone->random.Roll(spells[spell_id].base[i])) { if(caster && caster->IsClient()) caster->CastToClient()->Escape(); @@ -2711,11 +2711,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) } }else{ int32 newhate = GetHateAmount(caster) + effect_value; - if (newhate < 1) + if (newhate < 1) SetHate(caster,1); - else + else SetHate(caster,newhate); - } + } } break; } @@ -2724,9 +2724,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if (buffslot >= 0) break; - if(!spells[spell_id].uninterruptable && IsCasting() && MakeRandomInt(0, 100) <= spells[spell_id].base[i]) + if(!spells[spell_id].uninterruptable && IsCasting() && zone->random.Roll(spells[spell_id].base[i])) InterruptSpell(); - + break; } @@ -2742,17 +2742,16 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) Message(10, "The power of your next illusion spell will flow to your grouped target in your place."); break; } - + case SE_ApplyEffect: { if (caster && IsValidSpell(spells[spell_id].base2[i])){ - - if(MakeRandomInt(0, 100) <= spells[spell_id].base[i]) + if(zone->random.Roll(spells[spell_id].base[i])) caster->SpellFinished(spells[spell_id].base2[i], this, 10, 0, -1, spells[spells[spell_id].base2[i]].ResistDiff); } break; } - + case SE_SpellTrigger: { if (!SE_SpellTrigger_HasCast) { @@ -3209,7 +3208,7 @@ snare has both of them negative, yet their range should work the same: break; } case 123: // added 2/6/04 - result = MakeRandomInt(ubase, abs(max)); + result = zone->random.Int(ubase, abs(max)); break; case 124: // check sign @@ -3573,16 +3572,16 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste int wipechance = spells[spell_id].base[i]; int bonus = 0; - + if (caster){ - bonus = caster->spellbonuses.IncreaseChanceMemwipe + - caster->itembonuses.IncreaseChanceMemwipe + + bonus = caster->spellbonuses.IncreaseChanceMemwipe + + caster->itembonuses.IncreaseChanceMemwipe + caster->aabonuses.IncreaseChanceMemwipe; } - + wipechance += wipechance*bonus/100; - - if(MakeRandomInt(0, 99) < wipechance) + + if(zone->random.Roll(wipechance)) { if(IsAIControlled()) { @@ -3602,16 +3601,14 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste } case SE_Root: { - /* Root formula derived from extensive personal live parses - Kayen ROOT has a 70% chance to do a resist check to break. */ - if (MakeRandomInt(0, 99) < RuleI(Spells, RootBreakCheckChance)){ - + if (zone->random.Roll(RuleI(Spells, RootBreakCheckChance))) { float resist_check = ResistSpell(spells[spell_id].resisttype, spell_id, caster, 0,0,0,0,true); - if(resist_check == 100) + if(resist_check == 100) break; else if(!TryFadeEffect(slot)) @@ -3623,11 +3620,10 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste case SE_Fear: { - if (MakeRandomInt(0, 99) < RuleI(Spells, FearBreakCheckChance)){ - + if (zone->random.Roll(RuleI(Spells, FearBreakCheckChance))) { float resist_check = ResistSpell(spells[spell_id].resisttype, spell_id, caster); - if(resist_check == 100) + if(resist_check == 100) break; else if(!TryFadeEffect(slot)) @@ -3664,7 +3660,7 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste break_chance -= (2 * (((double)GetSkill(SkillDivination) + ((double)GetLevel() * 3.0)) / 650.0)); } - if(MakeRandomFloat(0.0, 100.0) < break_chance) + if(zone->random.Real(0.0, 100.0) < break_chance) { BuffModifyDurationBySpellID(spell_id, 3); } @@ -3684,7 +3680,7 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste { if(IsCasting()) { - if(MakeRandomInt(0, 100) <= spells[spell_id].base[i]) + if(zone->random.Roll(spells[spell_id].base[i])) { InterruptSpell(); } @@ -4582,11 +4578,9 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) case SE_TriggerOnCast: if(type == focusTriggerOnCast){ - if(MakeRandomInt(0, 100) <= base1){ + if(zone->random.Roll(base1)) { value = base2; - } - - else{ + } else { value = 0; LimitFailure = true; } @@ -4600,7 +4594,7 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) case SE_BlockNextSpellFocus: if(type == focusBlockNextSpell){ - if(MakeRandomInt(1, 100) <= base1) + if(zone->random.Roll(base1)) value = 1; } break; @@ -4955,7 +4949,7 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo value = focus_spell.base[i]; } else { - value = MakeRandomInt(focus_spell.base[i], focus_spell.base2[i]); + value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); } } break; @@ -4974,7 +4968,7 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo value = focus_spell.base[i]; } else { - value = MakeRandomInt(focus_spell.base[i], focus_spell.base2[i]); + value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); } } break; @@ -4993,7 +4987,7 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo value = focus_spell.base[i]; } else { - value = MakeRandomInt(focus_spell.base[i], focus_spell.base2[i]); + value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); } } break; @@ -5062,7 +5056,7 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo case SE_TriggerOnCast: if(type == focusTriggerOnCast){ - if(MakeRandomInt(1, 100) <= focus_spell.base[i]) + if(zone->random.Roll(focus_spell.base[i])) value = focus_spell.base2[i]; else value = 0; @@ -5071,7 +5065,7 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo case SE_BlockNextSpellFocus: if(type == focusBlockNextSpell){ - if(MakeRandomInt(1, 100) <= focus_spell.base[i]) + if(zone->random.Roll(focus_spell.base[i])) value = 1; } break; @@ -5219,12 +5213,9 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) { if (TempItem && TempItem->Focus.Effect > 0 && IsValidSpell(TempItem->Focus.Effect)) { proc_spellid = CalcFocusEffect(type, TempItem->Focus.Effect, spell_id); - if (IsValidSpell(proc_spellid)){ - ProcChance = GetSympatheticProcChances(spell_id, spells[TempItem->Focus.Effect].base[0], TempItem->ProcRate); - - if(MakeRandomFloat(0, 1) <= ProcChance) + if(zone->random.Roll(ProcChance)) SympatheticProcList.push_back(proc_spellid); } } @@ -5240,14 +5231,10 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) { { const Item_Struct* TempItemAug = aug->GetItem(); if (TempItemAug && TempItemAug->Focus.Effect > 0 && IsValidSpell(TempItemAug->Focus.Effect)) { - proc_spellid = CalcFocusEffect(type, TempItemAug->Focus.Effect, spell_id); - if (IsValidSpell(proc_spellid)){ - ProcChance = GetSympatheticProcChances(spell_id, spells[TempItemAug->Focus.Effect].base[0], TempItemAug->ProcRate); - - if(MakeRandomFloat(0, 1) <= ProcChance) + if(zone->random.Roll(ProcChance)) SympatheticProcList.push_back(proc_spellid); } } @@ -5275,8 +5262,7 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) { if (IsValidSpell(proc_spellid)){ ProcChance = GetSympatheticProcChances(spell_id, spells[focusspellid].base[0]); - - if(MakeRandomFloat(0, 1) <= ProcChance) + if(zone->random.Roll(ProcChance)) SympatheticProcList.push_back(proc_spellid); } } @@ -5302,10 +5288,8 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) { proc_spellid = CalcAAFocus(type, aa_AA, spell_id); if (IsValidSpell(proc_spellid)){ - ProcChance = GetSympatheticProcChances(spell_id, GetAABase1(aa_AA, 1)); - - if(MakeRandomFloat(0, 1) <= ProcChance) + if(zone->random.Roll(ProcChance)) SympatheticProcList.push_back(proc_spellid); } } @@ -5313,7 +5297,7 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) { if (SympatheticProcList.size() > 0) { - uint8 random = MakeRandomInt(0, SympatheticProcList.size()-1); + uint8 random = zone->random.Int(0, SympatheticProcList.size()-1); int FinalSympatheticProc = SympatheticProcList[random]; SympatheticProcList.clear(); return FinalSympatheticProc; @@ -5672,7 +5656,7 @@ bool Mob::TryDivineSave() */ int32 SuccessChance = aabonuses.DivineSaveChance[0] + itembonuses.DivineSaveChance[0] + spellbonuses.DivineSaveChance[0]; - if (SuccessChance && MakeRandomInt(0, 100) <= SuccessChance) + if (SuccessChance && zone->random.Roll(SuccessChance)) { SetHP(1); @@ -5731,7 +5715,7 @@ bool Mob::TryDeathSave() { if (SuccessChance > 95) SuccessChance = 95; - if(SuccessChance >= MakeRandomInt(0, 100)) { + if(zone->random.Roll(SuccessChance)) { if(spellbonuses.DeathSave[0] == 2) HealAmt = RuleI(Spells, DivineInterventionHeal); //8000HP is how much LIVE Divine Intervention max heals @@ -5762,7 +5746,7 @@ bool Mob::TryDeathSave() { if (SuccessChance > 95) SuccessChance = 95; - if(SuccessChance >= MakeRandomInt(0, 100)) { + if(zone->random.Roll(SuccessChance)) { if(spellbonuses.DeathSave[0] == 2) HealAmt = RuleI(Spells, DivineInterventionHeal); @@ -6064,7 +6048,7 @@ bool Mob::TryDispel(uint8 caster_level, uint8 buff_level, int level_modifier){ else if (dispel_chance < 10) dispel_chance = 10; - if (MakeRandomInt(0,99) < dispel_chance) + if (zone->random.Roll(dispel_chance)) return true; else return false; diff --git a/zone/spells.cpp b/zone/spells.cpp index 3bdc3557e..b051dfdca 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -178,7 +178,7 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, if(IsClient()){ int chance = CastToClient()->GetFocusEffect(focusFcMute, spell_id); - if (MakeRandomInt(0,99) < chance){ + if (zone->random.Roll(chance)) { Message_StringID(13, SILENCED_STRING); if(IsClient()) CastToClient()->SendSpellBarEnable(spell_id); @@ -697,7 +697,7 @@ bool Client::CheckFizzle(uint16 spell_id) specialize = specialize * 1.3; break; } - if(((specialize/6.0f) + 15.0f) < MakeRandomFloat(0, 100)) { + if(((specialize/6.0f) + 15.0f) < zone->random.Real(0, 100)) { specialize *= SPECIALIZE_FIZZLE / 200.0f; } else { specialize = 0.0f; @@ -739,7 +739,7 @@ bool Client::CheckFizzle(uint16 spell_id) } */ - float fizzle_roll = MakeRandomFloat(0, 100); + float fizzle_roll = zone->random.Real(0, 100); mlog(SPELLS__CASTING, "Check Fizzle %s spell %d fizzlechance: %0.2f%% diff: %0.2f roll: %0.2f", GetName(), spell_id, fizzlechance, diff, fizzle_roll); @@ -1028,7 +1028,7 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, mlog(SPELLS__CASTING, "Checking Interruption: spell x: %f spell y: %f cur x: %f cur y: %f channelchance %f channeling skill %d\n", GetSpellX(), GetSpellY(), GetX(), GetY(), channelchance, GetSkill(SkillChanneling)); - if(!spells[spell_id].uninterruptable && MakeRandomFloat(0, 100) > channelchance) { + if(!spells[spell_id].uninterruptable && zone->random.Real(0, 100) > channelchance) { mlog(SPELLS__CASTING_ERR, "Casting of %d canceled: interrupted.", spell_id); InterruptSpell(); return; @@ -1044,7 +1044,7 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, // first check for component reduction if(IsClient()) { int reg_focus = CastToClient()->GetFocusEffect(focusReagentCost,spell_id); - if(MakeRandomInt(1, 100) <= reg_focus) { + if(zone->random.Roll(reg_focus)) { mlog(SPELLS__CASTING, "Spell %d: Reagent focus item prevented reagent consumption (%d chance)", spell_id, reg_focus); } else { if(reg_focus > 0) @@ -4204,7 +4204,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use { IsFear = true; int fear_resist_bonuses = CalcFearResistChance(); - if(MakeRandomInt(0, 99) < fear_resist_bonuses) + if(zone->random.Roll(fear_resist_bonuses)) { mlog(SPELLS__RESISTS, "Resisted spell in fear resistance, had %d chance to resist", fear_resist_bonuses); return 0; @@ -4215,14 +4215,14 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use //Check for Spell Effect specific resistance chances (ie AA Mental Fortitude) int se_resist_bonuses = GetSpellEffectResistChance(spell_id); - if(se_resist_bonuses && (MakeRandomInt(0, 99) < se_resist_bonuses)) + if(se_resist_bonuses && zone->random.Roll(se_resist_bonuses)) { return 0; } // Check for Chance to Resist Spell bonuses (ie Sanctification Discipline) int resist_bonuses = CalcResistChanceBonus(); - if(resist_bonuses && (MakeRandomInt(0, 99) < resist_bonuses)) + if(resist_bonuses && zone->random.Roll(resist_bonuses)) { mlog(SPELLS__RESISTS, "Resisted spell in sanctification, had %d chance to resist", resist_bonuses); return 0; @@ -4448,7 +4448,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use } //Finally our roll - int roll = MakeRandomInt(0, 200); + int roll = zone->random.Int(0, 200); if(roll > resist_chance) { return 100; @@ -4665,7 +4665,7 @@ void Mob::Stun(int duration) if(IsValidSpell(casting_spell_id) && !spells[casting_spell_id].uninterruptable) { int persistent_casting = spellbonuses.PersistantCasting + itembonuses.PersistantCasting + aabonuses.PersistantCasting; - if(MakeRandomInt(0,99) > persistent_casting) + if(zone->random.Int(0,99) > persistent_casting) InterruptSpell(); } @@ -5548,4 +5548,4 @@ void Mob::ConeDirectional(uint16 spell_id, int16 resist_adjust) ++iter; } -} \ No newline at end of file +} diff --git a/zone/string_ids.h b/zone/string_ids.h index e1e1bc7b3..ef758dba6 100644 --- a/zone/string_ids.h +++ b/zone/string_ids.h @@ -396,7 +396,8 @@ #define SONG_ENDS_OTHER 12688 //%1's song ends. #define SONG_ENDS_ABRUPTLY_OTHER 12689 //%1's song ends abruptly. #define DIVINE_AURA_NO_ATK 12695 //You can't attack while invulnerable! -#define TRY_ATTACKING_SOMEONE 12696 //Try attacking someone other than yourself, it's more productive. +#define TRY_ATTACKING_SOMEONE 12696 //Try attacking someone other than yourself, it's more productive +#define RANGED_TOO_CLOSE 12698 //Your target is too close to use a ranged weapon! #define BACKSTAB_WEAPON 12874 //You need a piercing weapon as your primary weapon in order to backstab #define MORE_SKILLED_THAN_I 12931 //%1 tells you, 'You are more skilled than I! What could I possibly teach you?' #define SURNAME_EXISTS 12939 //You already have a surname. Operation failed. diff --git a/zone/tradeskills.cpp b/zone/tradeskills.cpp index fd9f5a632..58774f4b1 100644 --- a/zone/tradeskills.cpp +++ b/zone/tradeskills.cpp @@ -923,7 +923,7 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) { _log(TRADESKILLS__TRACE, "...Current skill: %d , Trivial: %d , Success chance: %f percent", user_skill , spec->trivial , chance); _log(TRADESKILLS__TRACE, "...Bonusstat: %d , INT: %d , WIS: %d , DEX: %d , STR: %d", bonusstat , GetINT() , GetWIS() , GetDEX() , GetSTR()); - float res = MakeRandomFloat(0, 99); + float res = zone->random.Real(0, 99); int aa_chance = 0; //AA modifiers @@ -1057,7 +1057,7 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) { chance = mod_tradeskill_chance(chance, spec); - if (((spec->tradeskill==75) || GetGM() || (chance > res)) || MakeRandomInt(0, 99) < aa_chance){ + if (((spec->tradeskill==75) || GetGM() || (chance > res)) || zone->random.Roll(aa_chance)) { success_modifier = 1; if(over_trivial < 0) @@ -1127,7 +1127,7 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) { uint8 sc = 0; while(itr != spec->salvage.end()) { for(sc = 0; sc < itr->second; sc++) - if(MakeRandomInt(0,99) < SalvageChance) + if(zone->random.Roll(SalvageChance)) SummonItem(itr->first, 1); ++itr; } @@ -1153,7 +1153,7 @@ void Client::CheckIncreaseTradeskill(int16 bonusstat, int16 stat_modifier, float //In stage2 the only thing that matters is your current unmodified skill. //If you want to customize here you probbably need to implement your own //formula instead of tweaking the below one. - if (chance_stage1 > MakeRandomFloat(0, 99)) { + if (chance_stage1 > zone->random.Real(0, 99)) { if (current_raw_skill < 15) { //Always succeed chance_stage2 = 100; @@ -1168,7 +1168,7 @@ void Client::CheckIncreaseTradeskill(int16 bonusstat, int16 stat_modifier, float chance_stage2 = mod_tradeskill_skillup(chance_stage2); - if (chance_stage2 > MakeRandomFloat(0, 99)) { + if (chance_stage2 > zone->random.Real(0, 99)) { //Only if stage1 and stage2 succeeded you get a skillup. SetSkill(tradeskill, current_raw_skill + 1); diff --git a/zone/trap.cpp b/zone/trap.cpp index 44c177118..7d412d7cb 100644 --- a/zone/trap.cpp +++ b/zone/trap.cpp @@ -144,7 +144,7 @@ void Trap::Trigger(Mob* trigger) { if ((tmp = database.GetNPCType(effectvalue))) { - NPC* new_npc = new NPC(tmp, 0, x-5+MakeRandomInt(0, 10), y-5+MakeRandomInt(0, 10), z-5+MakeRandomInt(0, 10), MakeRandomInt(0, 249), FlyMode3); + NPC* new_npc = new NPC(tmp, 0, x-5+zone->random.Int(0, 10), y-5+zone->random.Int(0, 10), z-5+zone->random.Int(0, 10), zone->random.Int(0, 249), FlyMode3); new_npc->AddLootTable(); entity_list.AddNPC(new_npc); new_npc->AddToHateList(trigger,1); @@ -165,7 +165,7 @@ void Trap::Trigger(Mob* trigger) { if ((tmp = database.GetNPCType(effectvalue))) { - NPC* new_npc = new NPC(tmp, 0, x-2+MakeRandomInt(0, 5), y-2+MakeRandomInt(0, 5), z-2+MakeRandomInt(0, 5), MakeRandomInt(0, 249), FlyMode3); + NPC* new_npc = new NPC(tmp, 0, x-2+zone->random.Int(0, 5), y-2+zone->random.Int(0, 5), z-2+zone->random.Int(0, 5), zone->random.Int(0, 249), FlyMode3); new_npc->AddLootTable(); entity_list.AddNPC(new_npc); new_npc->AddToHateList(trigger,1); @@ -185,10 +185,10 @@ void Trap::Trigger(Mob* trigger) { EQApplicationPacket* outapp = new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct)); CombatDamage_Struct* a = (CombatDamage_Struct*)outapp->pBuffer; - int dmg = MakeRandomInt(effectvalue, effectvalue2); + int dmg = zone->random.Int(effectvalue, effectvalue2); trigger->SetHP(trigger->GetHP() - dmg); a->damage = dmg; - a->sequence = MakeRandomInt(0, 1234567); + a->sequence = zone->random.Int(0, 1234567); a->source = GetHiddenTrigger()!=nullptr ? GetHiddenTrigger()->GetID() : trigger->GetID(); a->spellid = 0; a->target = trigger->GetID(); @@ -197,7 +197,7 @@ void Trap::Trigger(Mob* trigger) safe_delete(outapp); } } - respawn_timer.Start((respawn_time + MakeRandomInt(0, respawn_var)) * 1000); + respawn_timer.Start((respawn_time + zone->random.Int(0, respawn_var)) * 1000); chkarea_timer.Disable(); disarmed = true; } @@ -250,7 +250,7 @@ Mob* EntityList::GetTrapTrigger(Trap* trap) { if ((xdiff*xdiff + ydiff*ydiff) <= maxdist && zdiff < trap->maxzdiff) { - if (MakeRandomInt(0,100) < trap->chance) + if (zone->random.Roll(trap->chance)) return(cur); else savemob = cur; diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index 908f0f946..410e76f3f 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -270,7 +270,7 @@ void NPC::CalculateNewWaypoint() if(closest.size() != 0) { iter = closest.begin(); - std::advance(iter, MakeRandomInt(0, closest.size() - 1)); + std::advance(iter, zone->random.Int(0, closest.size() - 1)); cur_wp = (*iter).index; } @@ -278,7 +278,7 @@ void NPC::CalculateNewWaypoint() } case 2: //random { - cur_wp = MakeRandomInt(0, Waypoints.size() - 1); + cur_wp = zone->random.Int(0, Waypoints.size() - 1); if(cur_wp == old_wp) { if(cur_wp == (Waypoints.size() - 1)) @@ -339,7 +339,7 @@ void NPC::CalculateNewWaypoint() if(closest.size() != 0) { iter = closest.begin(); - std::advance(iter, MakeRandomInt(0, closest.size() - 1)); + std::advance(iter, zone->random.Int(0, closest.size() - 1)); cur_wp = (*iter).index; } break; @@ -412,13 +412,13 @@ void NPC::SetWaypointPause() switch (pausetype) { case 0: //Random Half - AIwalking_timer->Start((cur_wp_pause - MakeRandomInt(0, cur_wp_pause-1)/2)*1000); + AIwalking_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); break; case 2: //Random Full - AIwalking_timer->Start(MakeRandomInt(0, cur_wp_pause-1)*1000); + AIwalking_timer->Start(zone->random.Int(0, cur_wp_pause-1)*1000); break; } } diff --git a/zone/zone.cpp b/zone/zone.cpp index 2d5f6e8e6..4453422a8 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -1302,13 +1302,13 @@ void Zone::ChangeWeather() return; } - int chance = MakeRandomInt(0, 3); + int chance = zone->random.Int(0, 3); uint8 rainchance = zone->newzone_data.rain_chance[chance]; uint8 rainduration = zone->newzone_data.rain_duration[chance]; uint8 snowchance = zone->newzone_data.snow_chance[chance]; uint8 snowduration = zone->newzone_data.snow_duration[chance]; uint32 weathertimer = 0; - uint16 tmpweather = MakeRandomInt(0, 100); + uint16 tmpweather = zone->random.Int(0, 100); uint8 duration = 0; uint8 tmpOldWeather = zone->zone_weather; bool changed = false; @@ -1317,7 +1317,7 @@ void Zone::ChangeWeather() { if(rainchance > 0 || snowchance > 0) { - uint8 intensity = MakeRandomInt(1, 10); + uint8 intensity = zone->random.Int(1, 10); if((rainchance > snowchance) || (rainchance == snowchance)) { //It's gunna rain! diff --git a/zone/zone.h b/zone/zone.h index 2d74c9f17..40c3a8d11 100644 --- a/zone/zone.h +++ b/zone/zone.h @@ -22,6 +22,7 @@ #include "../common/linked_list.h" #include "../common/rulesys.h" #include "../common/types.h" +#include "../common/random.h" #include "qglobals.h" #include "spawn2.h" #include "spawngroup.h" @@ -253,6 +254,9 @@ public: void UpdateHotzone(); std::unordered_map tick_items; + // random object that provides random values for the zone + EQEmu::Random random; + //MODDING HOOKS void mod_init(); void mod_repop(); @@ -310,7 +314,7 @@ private: Timer* Instance_Warning_timer; LinkedList client_auth_list; QGlobalCache *qGlobals; - + Timer hotzone_timer; };