mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-22 16:28:28 +00:00
Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 743fd45b17 | |||
| 0ada77f340 | |||
| 9c8107ce96 | |||
| 4581059e78 | |||
| dceec36fad | |||
| 3035e906fe | |||
| 0e0162edc0 | |||
| af06fb703c | |||
| c5d089de68 | |||
| b8ee811ac6 | |||
| 08cdd8234d | |||
| 3bb7f94713 | |||
| ec5a9d0bd4 | |||
| 2da6d3f37c | |||
| 6a7baf8f1c | |||
| a8e3ab41e1 | |||
| fe4146050f | |||
| 36ea946255 | |||
| f29d87aced | |||
| 767f04731b | |||
| 8e7964b835 | |||
| a9333fb51b | |||
| 27ad857ee5 | |||
| 5549daedb1 | |||
| b5cc8dfab1 | |||
| 865f619e21 | |||
| a4785d30e0 | |||
| a54711817d | |||
| 139575661d | |||
| 8dd24f4a70 | |||
| 517d9419a7 | |||
| a789b22fc7 | |||
| 6e1fe45090 | |||
| 492d848f6a | |||
| ce5e216be9 | |||
| 48e0847f21 | |||
| 7f42add39b | |||
| 49161a618f | |||
| aac7bbf48a | |||
| 2c4d82f1b9 | |||
| dea5031d83 | |||
| 30c9c6317f | |||
| c7eea72997 | |||
| 28e6ef29d4 | |||
| a6f4438c0d | |||
| e5a111d8d8 | |||
| abbaf6f9a1 | |||
| ccdc9f2e43 | |||
| a9effc7bac | |||
| a2b3b36cf1 | |||
| 75ddf8dfc3 | |||
| a3802ff257 | |||
| ca23b8612e | |||
| 485ae4809d | |||
| 452407ed67 | |||
| aa1c481f65 | |||
| 780dcdab5a | |||
| 16ec08e71c | |||
| 0024073cee | |||
| 37b8428c48 |
@@ -3,8 +3,9 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
- tob_patch
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
name: Linux
|
||||
@@ -25,17 +26,6 @@ jobs:
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential ninja-build ccache uuid-dev
|
||||
|
||||
- name: Restore vcpkg Cache
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
build/vcpkg_installed
|
||||
submodules/vcpkg/downloads
|
||||
key: ${{ runner.os }}-vcpkg-${{ hashFiles('vcpkg.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-vcpkg-${{ hashFiles('vcpkg.json') }}-
|
||||
${{ runner.os }}-vcpkg-
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake -S . -B build -G Ninja \
|
||||
@@ -58,9 +48,6 @@ jobs:
|
||||
windows:
|
||||
name: Windows
|
||||
runs-on: windows-latest
|
||||
env:
|
||||
VCPKG_DOWNLOADS: ${{ github.workspace }}\submodules\vcpkg\downloads
|
||||
VCPKG_BINARY_SOURCES: 'clear;files,${{ github.workspace }}\vcpkg_archives,readwrite'
|
||||
steps:
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@v5
|
||||
@@ -69,22 +56,12 @@ jobs:
|
||||
|
||||
- name: Enable long paths
|
||||
run: git config --global core.longpaths true
|
||||
|
||||
|
||||
- name: Setup MSVC environment
|
||||
uses: TheMrMilchmann/setup-msvc-dev@v4
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
arch: x64
|
||||
|
||||
- name: Restore vcpkg Cache
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
${{ env.VCPKG_DOWNLOADS }}
|
||||
${{ github.workspace }}/vcpkg_archives
|
||||
key: ${{ runner.os }}-vcpkg-${{ hashFiles('vcpkg.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-vcpkg-
|
||||
|
||||
- name: Configure
|
||||
shell: pwsh
|
||||
run: |
|
||||
|
||||
+2
-2
@@ -42,7 +42,7 @@ option(EQEMU_BUILD_PCH "Build with precompiled headers (Windows)" ON)
|
||||
|
||||
if(MSVC)
|
||||
add_compile_options(/bigobj)
|
||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS NOMINMAX WIN32_LEAN_AND_MEAN CRASH_LOGGING)
|
||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS NOMINMAX WIN32_LEAN_AND_MEAN CRASH_LOGGING _HAS_AUTO_PTR_ETC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
|
||||
|
||||
option(EQEMU_DISABLE_MSVC_WARNINGS "Disable MSVC compile warnings." OFF)
|
||||
@@ -71,7 +71,7 @@ if(UNIX)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package(Boost REQUIRED COMPONENTS dynamic_bitset foreach tuple)
|
||||
find_package(Boost REQUIRED COMPONENTS dynamic_bitset foreach tuple CONFIG REQUIRED)
|
||||
find_package(cereal CONFIG REQUIRED)
|
||||
find_package(fmt CONFIG REQUIRED)
|
||||
find_package(glm CONFIG REQUIRED)
|
||||
|
||||
+13
-3
@@ -6,7 +6,6 @@ set(common_sources
|
||||
bodytypes.cpp
|
||||
classes.cpp
|
||||
cli/eqemu_command_handler.cpp
|
||||
compiler_macros.h
|
||||
compression.cpp
|
||||
content/world_content_service.cpp
|
||||
crash.cpp
|
||||
@@ -87,6 +86,7 @@ set(common_sources
|
||||
packet_dump_file.cpp
|
||||
packet_dump.cpp
|
||||
packet_functions.cpp
|
||||
patches/client_version.cpp
|
||||
patches/patches.cpp
|
||||
patches/rof_limits.cpp
|
||||
patches/rof.cpp
|
||||
@@ -98,6 +98,8 @@ set(common_sources
|
||||
patches/sof.cpp
|
||||
patches/titanium_limits.cpp
|
||||
patches/titanium.cpp
|
||||
patches/tob.cpp
|
||||
patches/tob_limits.cpp
|
||||
patches/uf_limits.cpp
|
||||
patches/uf.cpp
|
||||
path_manager.cpp
|
||||
@@ -134,6 +136,7 @@ set(common_sources
|
||||
util/directory.cpp
|
||||
util/uuid.cpp
|
||||
zone_store.cpp
|
||||
links.cpp
|
||||
)
|
||||
|
||||
set(repositories
|
||||
@@ -653,6 +656,8 @@ set(common_headers
|
||||
packet_dump_file.h
|
||||
packet_dump.h
|
||||
packet_functions.h
|
||||
patches/IMessage.h
|
||||
patches/client_version.h
|
||||
patches/patches.h
|
||||
patches/rof_limits.h
|
||||
patches/rof_ops.h
|
||||
@@ -669,7 +674,7 @@ set(common_headers
|
||||
patches/sof_limits.h
|
||||
patches/sof_ops.h
|
||||
patches/sof_structs.h
|
||||
patches/sof.h
|
||||
patches/sof.h
|
||||
patches/ss_declare.h
|
||||
patches/ss_define.h
|
||||
patches/ss_register.h
|
||||
@@ -677,6 +682,10 @@ set(common_headers
|
||||
patches/titanium_ops.h
|
||||
patches/titanium_structs.h
|
||||
patches/titanium.h
|
||||
patches/tob.h
|
||||
patches/tob_limits.h
|
||||
patches/tob_ops.h
|
||||
patches/tob_structs.h
|
||||
patches/uf_limits.h
|
||||
patches/uf_ops.h
|
||||
patches/uf_structs.h
|
||||
@@ -728,7 +737,8 @@ set(common_headers
|
||||
util/memory_stream.h
|
||||
util/uuid.h
|
||||
version.h
|
||||
zone_store.h
|
||||
zone_store.h
|
||||
links.h
|
||||
)
|
||||
|
||||
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" PREFIX "Source Files" FILES ${common_sources})
|
||||
|
||||
@@ -62,6 +62,7 @@ public:
|
||||
void WriteUInt8(uint8 value) { *(uint8 *)(pBuffer + _wpos) = value; _wpos += sizeof(uint8); }
|
||||
void WriteUInt32(uint32 value) { *(uint32 *)(pBuffer + _wpos) = value; _wpos += sizeof(uint32); }
|
||||
void WriteUInt64(uint64 value) { *(uint64 *)(pBuffer + _wpos) = value; _wpos += sizeof(uint64); }
|
||||
void WriteSInt16(int32 value) { *(int16*)(pBuffer + _wpos) = value; _wpos += sizeof(int16); }
|
||||
void WriteUInt16(uint32 value) { *(uint16 *)(pBuffer + _wpos) = value; _wpos += sizeof(uint16); }
|
||||
void WriteSInt32(int32 value) { *(int32 *)(pBuffer + _wpos) = value; _wpos += sizeof(int32); }
|
||||
void WriteFloat(float value) { *(float *)(pBuffer + _wpos) = value; _wpos += sizeof(float); }
|
||||
|
||||
@@ -71,6 +71,9 @@ namespace Class {
|
||||
constexpr uint8 FellowshipMaster = 69;
|
||||
constexpr uint8 AlternateCurrencyMerchant = 70;
|
||||
constexpr uint8 MercenaryLiaison = 71;
|
||||
constexpr uint8 RealEstateMerchant = 72;
|
||||
constexpr uint8 LoyaltyMerchant = 73;
|
||||
constexpr uint8 TributeMaster2 = 74;
|
||||
|
||||
constexpr uint8 PLAYER_CLASS_COUNT = 16;
|
||||
constexpr uint16 ALL_CLASSES_BITMASK = 65535;
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define PUSH_DISABLE_DEPRECATED_WARNINGS() __pragma(warning(push)) \
|
||||
__pragma(warning(disable:4996))
|
||||
#define POP_DISABLE_DEPRECATED_WARNINGS() __pragma(warning(pop))
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#define PUSH_DISABLE_DEPRECATED_WARNINGS() _Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
|
||||
#define POP_DISABLE_DEPRECATED_WARNINGS() _Pragma("GCC diagnostic pop")
|
||||
#else
|
||||
#define PUSH_DISABLE_DEPRECATED_WARNINGS()
|
||||
#define POP_DISABLE_DEPRECATED_WARNINGS()
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#define UNREACHABLE() __assume(0)
|
||||
#else
|
||||
#define UNREACHABLE() __builtin_unreachable()
|
||||
#endif
|
||||
@@ -99,6 +99,24 @@ uint32 CRC32::GenerateNoFlip(const uint8* buf, uint32 bufsize) {
|
||||
return Update(buf, bufsize);
|
||||
}
|
||||
|
||||
unsigned long CRC32::GetEQChecksum(uchar* in_data, uint32 in_length, uint32 start_at)
|
||||
{
|
||||
unsigned long data;
|
||||
unsigned long check = 0xffffffff;
|
||||
|
||||
for (uint32 i = start_at; i < in_length; i++)
|
||||
{
|
||||
data = in_data[i];
|
||||
data = data ^ (check);
|
||||
data = data & 0x000000ff;
|
||||
check = check >> 8;
|
||||
data = CRC32Table[data];
|
||||
check = check ^ data;
|
||||
}
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
void CRC32::SetEQChecksum(uchar* in_data, uint32 in_length, uint32 start_at)
|
||||
{
|
||||
unsigned long data;
|
||||
|
||||
@@ -25,6 +25,7 @@ public:
|
||||
static uint32 Generate(const uint8* buf, uint32 bufsize);
|
||||
static uint32 GenerateNoFlip(const uint8* buf, uint32 bufsize); // Same as Generate(), but without the ~
|
||||
static void SetEQChecksum(uchar* in_data, uint32 in_length, uint32 start_at=4);
|
||||
static unsigned long GetEQChecksum(uchar* in_data, uint32 in_length, uint32 start_at = 4);
|
||||
|
||||
// Multiple buffer CRC32
|
||||
static uint32 Update(const uint8* buf, uint32 bufsize, uint32 crc32 = 0xFFFFFFFF);
|
||||
|
||||
+2
-2
@@ -18,8 +18,6 @@
|
||||
// system use
|
||||
N(OP_ExploreUnknown),
|
||||
// start (please add new opcodes in descending order and re-order any name changes where applicable)
|
||||
N(OP_0x0193),
|
||||
N(OP_0x0347),
|
||||
N(OP_AAAction),
|
||||
N(OP_AAExpUpdate),
|
||||
N(OP_AcceptNewTask),
|
||||
@@ -381,6 +379,7 @@ N(OP_MercenaryTimer),
|
||||
N(OP_MercenaryTimerRequest),
|
||||
N(OP_MercenaryUnknown1),
|
||||
N(OP_MercenaryUnsuspendResponse),
|
||||
N(OP_MerchantBulkItems),
|
||||
N(OP_MobEnduranceUpdate),
|
||||
N(OP_MobHealth),
|
||||
N(OP_MobManaUpdate),
|
||||
@@ -399,6 +398,7 @@ N(OP_MultiLineMsg),
|
||||
N(OP_NewSpawn),
|
||||
N(OP_NewTitlesAvailable),
|
||||
N(OP_NewZone),
|
||||
N(OP_NPCMoveUpdate),
|
||||
N(OP_OnLevelMessage),
|
||||
N(OP_OpenContainer),
|
||||
N(OP_OpenDiscordMerchant),
|
||||
|
||||
@@ -54,6 +54,8 @@ const char* EQ::versions::ClientVersionName(ClientVersion client_version)
|
||||
return "RoF";
|
||||
case ClientVersion::RoF2:
|
||||
return "RoF2";
|
||||
case ClientVersion::TOB:
|
||||
return "TOB";
|
||||
default:
|
||||
return "Invalid Version";
|
||||
};
|
||||
@@ -74,6 +76,8 @@ uint32 EQ::versions::ConvertClientVersionToClientVersionBit(ClientVersion client
|
||||
return bitRoF;
|
||||
case ClientVersion::RoF2:
|
||||
return bitRoF2;
|
||||
case ClientVersion::TOB:
|
||||
return bitTOB;
|
||||
default:
|
||||
return bitUnknown;
|
||||
}
|
||||
@@ -94,6 +98,8 @@ EQ::versions::ClientVersion EQ::versions::ConvertClientVersionBitToClientVersion
|
||||
return ClientVersion::RoF;
|
||||
case ((uint32)1 << (static_cast<unsigned int>(ClientVersion::RoF2) - 1)) :
|
||||
return ClientVersion::RoF2;
|
||||
case ((uint32)1 << (static_cast<unsigned int>(ClientVersion::TOB) - 1)) :
|
||||
return ClientVersion::TOB;
|
||||
default:
|
||||
return ClientVersion::Unknown;
|
||||
}
|
||||
@@ -182,6 +188,8 @@ const char* EQ::versions::MobVersionName(MobVersion mob_version)
|
||||
return "RoF";
|
||||
case MobVersion::RoF2:
|
||||
return "RoF2";
|
||||
case MobVersion::TOB:
|
||||
return "TOB";
|
||||
case MobVersion::NPC:
|
||||
return "NPC";
|
||||
case MobVersion::NPCMerchant:
|
||||
@@ -210,6 +218,8 @@ const char* EQ::versions::MobVersionName(MobVersion mob_version)
|
||||
return "Offline RoF";
|
||||
case MobVersion::OfflineRoF2:
|
||||
return "Offline RoF2";
|
||||
case MobVersion::OfflineTOB:
|
||||
return "Offline TOB";
|
||||
default:
|
||||
return "Invalid Version";
|
||||
};
|
||||
@@ -233,6 +243,8 @@ EQ::versions::ClientVersion EQ::versions::ConvertMobVersionToClientVersion(MobVe
|
||||
return ClientVersion::RoF;
|
||||
case MobVersion::RoF2:
|
||||
return ClientVersion::RoF2;
|
||||
case MobVersion::TOB:
|
||||
return ClientVersion::TOB;
|
||||
default:
|
||||
return ClientVersion::Unknown;
|
||||
}
|
||||
@@ -256,6 +268,8 @@ EQ::versions::MobVersion EQ::versions::ConvertClientVersionToMobVersion(ClientVe
|
||||
return MobVersion::RoF;
|
||||
case ClientVersion::RoF2:
|
||||
return MobVersion::RoF2;
|
||||
case ClientVersion::TOB:
|
||||
return MobVersion::TOB;
|
||||
default:
|
||||
return MobVersion::Unknown;
|
||||
}
|
||||
@@ -276,6 +290,8 @@ EQ::versions::MobVersion EQ::versions::ConvertPCMobVersionToOfflinePCMobVersion(
|
||||
return MobVersion::OfflineRoF;
|
||||
case MobVersion::RoF2:
|
||||
return MobVersion::OfflineRoF2;
|
||||
case MobVersion::TOB:
|
||||
return MobVersion::OfflineTOB;
|
||||
default:
|
||||
return MobVersion::Unknown;
|
||||
}
|
||||
@@ -296,6 +312,8 @@ EQ::versions::MobVersion EQ::versions::ConvertOfflinePCMobVersionToPCMobVersion(
|
||||
return MobVersion::RoF;
|
||||
case MobVersion::OfflineRoF2:
|
||||
return MobVersion::RoF2;
|
||||
case MobVersion::OfflineTOB:
|
||||
return MobVersion::TOB;
|
||||
default:
|
||||
return MobVersion::Unknown;
|
||||
}
|
||||
@@ -316,6 +334,8 @@ EQ::versions::ClientVersion EQ::versions::ConvertOfflinePCMobVersionToClientVers
|
||||
return ClientVersion::RoF;
|
||||
case MobVersion::OfflineRoF2:
|
||||
return ClientVersion::RoF2;
|
||||
case MobVersion::OfflineTOB:
|
||||
return ClientVersion::TOB;
|
||||
default:
|
||||
return ClientVersion::Unknown;
|
||||
}
|
||||
@@ -336,6 +356,8 @@ EQ::versions::MobVersion EQ::versions::ConvertClientVersionToOfflinePCMobVersion
|
||||
return MobVersion::OfflineRoF;
|
||||
case ClientVersion::RoF2:
|
||||
return MobVersion::OfflineRoF2;
|
||||
case ClientVersion::TOB:
|
||||
return MobVersion::OfflineTOB;
|
||||
default:
|
||||
return MobVersion::Unknown;
|
||||
}
|
||||
@@ -386,6 +408,28 @@ const char* EQ::expansions::ExpansionName(Expansion expansion)
|
||||
return "Rain of Fear";
|
||||
case Expansion::CotF:
|
||||
return "Call of the Forsaken";
|
||||
case Expansion::TDS:
|
||||
return "The Darkened Sea";
|
||||
case Expansion::TBM:
|
||||
return "The Broken Mirror";
|
||||
case Expansion::EoK:
|
||||
return "Empires of Kunark";
|
||||
case Expansion::RoS:
|
||||
return "Ring of Scale";
|
||||
case Expansion::TBL:
|
||||
return "The Burning Lands";
|
||||
case Expansion::ToV:
|
||||
return "Torment of Velious";
|
||||
case Expansion::CoV:
|
||||
return "Claws of Veeshan";
|
||||
case Expansion::ToL:
|
||||
return "Terror of Luclin";
|
||||
case Expansion::NoS:
|
||||
return "Night of Shadows";
|
||||
case Expansion::LS:
|
||||
return "Laurion's Song";
|
||||
case Expansion::TOB:
|
||||
return "The Outer Brood";
|
||||
default:
|
||||
return "Invalid Expansion";
|
||||
}
|
||||
@@ -439,6 +483,29 @@ uint32 EQ::expansions::ConvertExpansionToExpansionBit(Expansion expansion)
|
||||
return bitRoF;
|
||||
case Expansion::CotF:
|
||||
return bitCotF;
|
||||
case Expansion::TDS:
|
||||
return bitTDS;
|
||||
case Expansion::TBM:
|
||||
return bitTBM;
|
||||
case Expansion::EoK:
|
||||
return bitEoK;
|
||||
case Expansion::RoS:
|
||||
return bitRoS;
|
||||
case Expansion::TBL:
|
||||
return bitTBL;
|
||||
case Expansion::ToV:
|
||||
return bitToV;
|
||||
case Expansion::CoV:
|
||||
return bitCoV;
|
||||
case Expansion::ToL:
|
||||
return bitToL;
|
||||
case Expansion::NoS:
|
||||
return bitNoS;
|
||||
case Expansion::LS:
|
||||
return bitLS;
|
||||
case Expansion::TOB:
|
||||
return bitTOB;
|
||||
|
||||
default:
|
||||
return bitEverQuest;
|
||||
}
|
||||
@@ -487,6 +554,28 @@ EQ::expansions::Expansion EQ::expansions::ConvertExpansionBitToExpansion(uint32
|
||||
return Expansion::RoF;
|
||||
case bitCotF:
|
||||
return Expansion::CotF;
|
||||
case bitTDS:
|
||||
return Expansion::TDS;
|
||||
case bitTBM:
|
||||
return Expansion::TBM;
|
||||
case bitEoK:
|
||||
return Expansion::EoK;
|
||||
case bitRoS:
|
||||
return Expansion::RoS;
|
||||
case bitTBL:
|
||||
return Expansion::TBL;
|
||||
case bitToV:
|
||||
return Expansion::ToV;
|
||||
case bitCoV:
|
||||
return Expansion::CoV;
|
||||
case bitToL:
|
||||
return Expansion::ToL;
|
||||
case bitNoS:
|
||||
return Expansion::NoS;
|
||||
case bitLS:
|
||||
return Expansion::LS;
|
||||
case bitTOB:
|
||||
return Expansion::TOB;
|
||||
default:
|
||||
return Expansion::EverQuest;
|
||||
}
|
||||
@@ -535,6 +624,28 @@ uint32 EQ::expansions::ConvertExpansionToExpansionsMask(Expansion expansion)
|
||||
return maskRoF;
|
||||
case Expansion::CotF:
|
||||
return maskCotF;
|
||||
case Expansion::TDS:
|
||||
return maskTDS;
|
||||
case Expansion::TBM:
|
||||
return maskTBM;
|
||||
case Expansion::EoK:
|
||||
return maskEoK;
|
||||
case Expansion::RoS:
|
||||
return maskRoS;
|
||||
case Expansion::TBL:
|
||||
return maskTBL;
|
||||
case Expansion::ToV:
|
||||
return maskToV;
|
||||
case Expansion::CoV:
|
||||
return maskCoV;
|
||||
case Expansion::ToL:
|
||||
return maskToL;
|
||||
case Expansion::NoS:
|
||||
return maskNoS;
|
||||
case Expansion::LS:
|
||||
return maskLS;
|
||||
case Expansion::TOB:
|
||||
return maskTOB;
|
||||
default:
|
||||
return maskEverQuest;
|
||||
}
|
||||
|
||||
+49
-10
@@ -32,7 +32,8 @@ namespace EQ
|
||||
SoD, // Build: 'Dec 19 2008 15:22:49'
|
||||
UF, // Build: 'Jun 8 2010 16:44:32'
|
||||
RoF, // Build: 'Dec 10 2012 17:35:44'
|
||||
RoF2 // Build: 'May 10 2013 23:30:08'
|
||||
RoF2, // Build: 'May 10 2013 23:30:08'
|
||||
TOB // Build: 'Sep 11 2025 11:54:10'
|
||||
};
|
||||
|
||||
enum ClientVersionBitmask : uint32 {
|
||||
@@ -44,6 +45,7 @@ namespace EQ
|
||||
bitUF = 0x00000010,
|
||||
bitRoF = 0x00000020,
|
||||
bitRoF2 = 0x00000040,
|
||||
bitTOB = 0x00000080,
|
||||
maskUnknown = 0x00000000,
|
||||
maskTitaniumAndEarlier = 0x00000003,
|
||||
maskSoFAndEarlier = 0x00000007,
|
||||
@@ -55,11 +57,12 @@ namespace EQ
|
||||
maskUFAndLater = 0xFFFFFFF0,
|
||||
maskRoFAndLater = 0xFFFFFFE0,
|
||||
maskRoF2AndLater = 0xFFFFFFC0,
|
||||
maskTOBAndLater = 0xFFFFFF80,
|
||||
maskAllClients = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
const ClientVersion LastClientVersion = ClientVersion::RoF2;
|
||||
const size_t ClientVersionCount = (static_cast<size_t>(LastClientVersion) + 1);
|
||||
inline constexpr ClientVersion LastClientVersion = ClientVersion::TOB;
|
||||
inline constexpr size_t ClientVersionCount = (static_cast<size_t>(LastClientVersion) + 1);
|
||||
|
||||
bool IsValidClientVersion(ClientVersion client_version);
|
||||
ClientVersion ValidateClientVersion(ClientVersion client_version);
|
||||
@@ -76,6 +79,7 @@ namespace EQ
|
||||
UF,
|
||||
RoF,
|
||||
RoF2,
|
||||
TOB,
|
||||
NPC,
|
||||
NPCMerchant,
|
||||
Merc,
|
||||
@@ -89,13 +93,14 @@ namespace EQ
|
||||
OfflineSoD,
|
||||
OfflineUF,
|
||||
OfflineRoF,
|
||||
OfflineRoF2
|
||||
OfflineRoF2,
|
||||
OfflineTOB
|
||||
};
|
||||
|
||||
const MobVersion LastMobVersion = MobVersion::OfflineRoF2;
|
||||
const MobVersion LastPCMobVersion = MobVersion::RoF2;
|
||||
const MobVersion LastMobVersion = MobVersion::OfflineTOB;
|
||||
const MobVersion LastPCMobVersion = MobVersion::TOB;
|
||||
const MobVersion LastNonPCMobVersion = MobVersion::BotPet;
|
||||
const MobVersion LastOfflinePCMobVersion = MobVersion::OfflineRoF2;
|
||||
const MobVersion LastOfflinePCMobVersion = MobVersion::OfflineTOB;
|
||||
const size_t MobVersionCount = (static_cast<size_t>(LastMobVersion) + 1);
|
||||
|
||||
bool IsValidMobVersion(MobVersion mob_version);
|
||||
@@ -127,7 +132,8 @@ namespace EQ
|
||||
ucsSoDCombined = 'D',
|
||||
ucsUFCombined = 'E',
|
||||
ucsRoFCombined = 'F',
|
||||
ucsRoF2Combined = 'G'
|
||||
ucsRoF2Combined = 'G',
|
||||
ucsTOBCombined = 'H'
|
||||
};
|
||||
|
||||
} /*versions*/
|
||||
@@ -154,7 +160,18 @@ namespace EQ
|
||||
HoT,
|
||||
VoA,
|
||||
RoF,
|
||||
CotF
|
||||
CotF,
|
||||
TDS,
|
||||
TBM,
|
||||
EoK,
|
||||
RoS,
|
||||
TBL,
|
||||
ToV,
|
||||
CoV,
|
||||
ToL,
|
||||
NoS,
|
||||
LS,
|
||||
TOB
|
||||
};
|
||||
|
||||
enum ExpansionBitmask : uint32 {
|
||||
@@ -179,6 +196,17 @@ namespace EQ
|
||||
bitVoA = 0x00020000,
|
||||
bitRoF = 0x00040000,
|
||||
bitCotF = 0x00080000,
|
||||
bitTDS = 0x00100000,
|
||||
bitTBM = 0x00200000,
|
||||
bitEoK = 0x00400000,
|
||||
bitRoS = 0x00800000,
|
||||
bitTBL = 0x01000000,
|
||||
bitToV = 0x02000000,
|
||||
bitCoV = 0x04000000,
|
||||
bitToL = 0x08000000,
|
||||
bitNoS = 0x10000000,
|
||||
bitLS = 0x20000000,
|
||||
bitTOB = 0x40000000,
|
||||
maskEverQuest = 0x00000000,
|
||||
maskRoK = 0x00000001,
|
||||
maskSoV = 0x00000003,
|
||||
@@ -199,7 +227,18 @@ namespace EQ
|
||||
maskHoT = 0x0001FFFF,
|
||||
maskVoA = 0x0003FFFF,
|
||||
maskRoF = 0x0007FFFF,
|
||||
maskCotF = 0x000FFFFF
|
||||
maskCotF = 0x000FFFFF,
|
||||
maskTDS = 0x001FFFFF,
|
||||
maskTBM = 0x003FFFFF,
|
||||
maskEoK = 0x007FFFFF,
|
||||
maskRoS = 0x00FFFFFF,
|
||||
maskTBL = 0x01FFFFFF,
|
||||
maskToV = 0x03FFFFFF,
|
||||
maskCoV = 0x07FFFFFF,
|
||||
maskToL = 0x0FFFFFFF,
|
||||
maskNoS = 0x1FFFFFFF,
|
||||
maskLS = 0x3FFFFFFF,
|
||||
maskTOB = 0x7FFFFFFF,
|
||||
};
|
||||
|
||||
const char* ExpansionName(Expansion expansion);
|
||||
|
||||
@@ -759,6 +759,46 @@ typedef enum {
|
||||
FilterStrikethrough = 26, //0=show, 1=hide // RoF2 Confirmed
|
||||
FilterStuns = 27, //0=show, 1=hide // RoF2 Confirmed
|
||||
FilterBardSongsOnPets = 28, //0=show, 1=hide // RoF2 Confirmed
|
||||
FilterSwarmPetDeath = 29,
|
||||
FilterFellowshipChat = 30,
|
||||
FilterMercenaryMessages = 31,
|
||||
FilterSpam = 32,
|
||||
FilterAchievements = 33,
|
||||
FilterPvPMessages = 34,
|
||||
FilterSpellNameInCast = 35,
|
||||
FilterRandomMine = 36,
|
||||
FilterRandomGroupRaid = 37,
|
||||
FilterRandomOthers = 38,
|
||||
FilterEnvironmentalDamage = 39,
|
||||
FilterMessages = 40,
|
||||
FilterOverwriteDetrimental = 41,
|
||||
FilterOverwriteBeneficial = 42,
|
||||
FilterCantUseCommand = 43,
|
||||
FilterCombatAbilityReuse = 44,
|
||||
FilterAAAbilityReuse = 45,
|
||||
FilterProcBeginCasting = 46,
|
||||
FilterDestroyedItems = 47,
|
||||
FilterYourAuras = 48,
|
||||
FilterOtherAuras = 49,
|
||||
FilterYourHeals = 50,
|
||||
FilterOtherHeals = 51,
|
||||
FilterYourDoTs = 52,
|
||||
FilterOtherDoTs = 53,
|
||||
FilterOtherDirectDamage = 54,
|
||||
FilterSpellEmotes = 55,
|
||||
FilterFactionMessages = 56,
|
||||
FilterTauntMessages = 57,
|
||||
FilterYourDisciplines = 58,
|
||||
FilterOtherDisplines = 59,
|
||||
FilterAchievementsOthers = 60,
|
||||
FilterRaidVictory = 61,
|
||||
FilterOtherDirectDamageCrits = 62,
|
||||
FilterDoTYoursCritical = 63,
|
||||
FilterDoTOthersCritical = 64,
|
||||
FilterDoTDamageTaken = 65,
|
||||
FilterHealsReceived = 66,
|
||||
FilterHealsYoursCritical = 67,
|
||||
FilterHealsOthersCritical = 68,
|
||||
_FilterCount
|
||||
} eqFilterType;
|
||||
|
||||
|
||||
@@ -110,6 +110,15 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
|
||||
RoF2::constants::CHARACTER_CREATION_LIMIT,
|
||||
RoF2::constants::SAY_LINK_BODY_SIZE,
|
||||
RoF2::constants::MAX_BAZAAR_TRADERS
|
||||
),
|
||||
/*[ClientVersion::TOB] =*/
|
||||
EQ::constants::LookupEntry(
|
||||
TOB::constants::EXPANSION,
|
||||
TOB::constants::EXPANSION_BIT,
|
||||
TOB::constants::EXPANSIONS_MASK,
|
||||
TOB::constants::CHARACTER_CREATION_LIMIT,
|
||||
TOB::constants::SAY_LINK_BODY_SIZE,
|
||||
TOB::constants::MAX_BAZAAR_TRADERS
|
||||
)
|
||||
};
|
||||
|
||||
@@ -376,6 +385,34 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
|
||||
RoF2::inventory::ConcatenateInvTypeLimbo,
|
||||
RoF2::inventory::AllowOverLevelEquipment
|
||||
),
|
||||
/*[MobVersion::TOB] =*/
|
||||
//TOBTodo: These need to be set to the latest values not just use RoF2
|
||||
EQ::inventory::LookupEntry(
|
||||
EQ::inventory::LookupEntry::InventoryTypeSize_Struct(
|
||||
EQ::invtype::POSSESSIONS_SIZE, RoF2::invtype::BANK_SIZE, RoF2::invtype::SHARED_BANK_SIZE,
|
||||
RoF2::invtype::TRADE_SIZE, RoF2::invtype::WORLD_SIZE, RoF2::invtype::LIMBO_SIZE,
|
||||
RoF2::invtype::TRIBUTE_SIZE, RoF2::invtype::TROPHY_TRIBUTE_SIZE, RoF2::invtype::GUILD_TRIBUTE_SIZE,
|
||||
RoF2::invtype::MERCHANT_SIZE, RoF2::invtype::DELETED_SIZE, RoF2::invtype::CORPSE_SIZE,
|
||||
RoF2::invtype::BAZAAR_SIZE, RoF2::invtype::INSPECT_SIZE, RoF2::invtype::REAL_ESTATE_SIZE,
|
||||
RoF2::invtype::VIEW_MOD_PC_SIZE, RoF2::invtype::VIEW_MOD_BANK_SIZE, RoF2::invtype::VIEW_MOD_SHARED_BANK_SIZE,
|
||||
RoF2::invtype::VIEW_MOD_LIMBO_SIZE, RoF2::invtype::ALT_STORAGE_SIZE, RoF2::invtype::ARCHIVED_SIZE,
|
||||
RoF2::invtype::MAIL_SIZE, RoF2::invtype::GUILD_TROPHY_TRIBUTE_SIZE, RoF2::invtype::KRONO_SIZE,
|
||||
RoF2::invtype::GUILD_BANK_MAIN_SIZE, RoF2::invtype::GUILD_BANK_DEPOSIT_SIZE, RoF2::invtype::OTHER_SIZE
|
||||
),
|
||||
|
||||
RoF2::invslot::EQUIPMENT_BITMASK,
|
||||
RoF2::invslot::GENERAL_BITMASK,
|
||||
RoF2::invslot::CURSOR_BITMASK,
|
||||
RoF2::invslot::POSSESSIONS_BITMASK,
|
||||
RoF2::invslot::CORPSE_BITMASK,
|
||||
RoF2::invbag::SLOT_COUNT,
|
||||
RoF2::invaug::SOCKET_COUNT,
|
||||
|
||||
RoF2::inventory::AllowEmptyBagInBag,
|
||||
RoF2::inventory::AllowClickCastFromBag,
|
||||
RoF2::inventory::ConcatenateInvTypeLimbo,
|
||||
RoF2::inventory::AllowOverLevelEquipment
|
||||
),
|
||||
/*[MobVersion::NPC] =*/
|
||||
EQ::inventory::LookupEntry(
|
||||
EQ::inventory::LookupEntry::InventoryTypeSize_Struct(
|
||||
@@ -748,6 +785,35 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
|
||||
RoF2::INULL,
|
||||
RoF2::invbag::SLOT_COUNT,
|
||||
RoF2::invaug::SOCKET_COUNT,
|
||||
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
),
|
||||
/*[MobVersion::OfflineTOB] =*/
|
||||
//TOBTodo: Need to use their own values instead of RoF2
|
||||
EQ::inventory::LookupEntry(
|
||||
EQ::inventory::LookupEntry::InventoryTypeSize_Struct(
|
||||
RoF2::INULL, RoF2::INULL, RoF2::INULL,
|
||||
RoF2::invtype::TRADE_SIZE, RoF2::INULL, RoF2::INULL,
|
||||
RoF2::INULL, RoF2::INULL, RoF2::INULL,
|
||||
RoF2::invtype::MERCHANT_SIZE, RoF2::INULL, RoF2::INULL,
|
||||
RoF2::invtype::BAZAAR_SIZE, RoF2::invtype::INSPECT_SIZE, RoF2::INULL,
|
||||
RoF2::invtype::VIEW_MOD_PC_SIZE, RoF2::invtype::VIEW_MOD_BANK_SIZE, RoF2::invtype::VIEW_MOD_SHARED_BANK_SIZE,
|
||||
RoF2::invtype::VIEW_MOD_LIMBO_SIZE, RoF2::INULL, RoF2::INULL,
|
||||
RoF2::INULL, RoF2::INULL, RoF2::INULL,
|
||||
RoF2::INULL, RoF2::INULL, RoF2::INULL
|
||||
),
|
||||
|
||||
RoF2::INULL,
|
||||
RoF2::INULL,
|
||||
RoF2::INULL,
|
||||
RoF2::INULL,
|
||||
RoF2::INULL,
|
||||
RoF2::invbag::SLOT_COUNT,
|
||||
RoF2::invaug::SOCKET_COUNT,
|
||||
|
||||
|
||||
false,
|
||||
false,
|
||||
@@ -1000,6 +1066,11 @@ static const EQ::behavior::LookupEntry behavior_static_lookup_entries[EQ::versio
|
||||
EQ::behavior::LookupEntry(
|
||||
RoF2::behavior::CoinHasWeight
|
||||
),
|
||||
/*[MobVersion::TOB] =*/
|
||||
//TOBTodo: We need this value set properly
|
||||
EQ::behavior::LookupEntry(
|
||||
RoF2::behavior::CoinHasWeight
|
||||
),
|
||||
/*[MobVersion::NPC] =*/
|
||||
EQ::behavior::LookupEntry(
|
||||
EQ::behavior::CoinHasWeight
|
||||
@@ -1053,6 +1124,11 @@ static const EQ::behavior::LookupEntry behavior_static_lookup_entries[EQ::versio
|
||||
RoF::behavior::CoinHasWeight
|
||||
),
|
||||
/*[MobVersion::OfflineRoF2] =*/
|
||||
EQ::behavior::LookupEntry(
|
||||
RoF2::behavior::CoinHasWeight
|
||||
),
|
||||
/*[MobVersion::OfflineTOB] =*/
|
||||
//TOBTodo: We need this value set properly
|
||||
EQ::behavior::LookupEntry(
|
||||
RoF2::behavior::CoinHasWeight
|
||||
)
|
||||
@@ -1208,6 +1284,19 @@ static const EQ::spells::LookupEntry spells_static_lookup_entries[EQ::versions::
|
||||
RoF2::spells::NPC_BUFFS,
|
||||
RoF2::spells::PET_BUFFS,
|
||||
RoF2::spells::MERC_BUFFS
|
||||
),
|
||||
/*[ClientVersion::TOB] =*/
|
||||
EQ::spells::LookupEntry(
|
||||
TOB::spells::SPELL_ID_MAX,
|
||||
TOB::spells::SPELLBOOK_SIZE,
|
||||
UF::spells::SPELL_GEM_COUNT, // client translators are setup to allow the max value a client supports..however, the top 4 indices are not valid in this case
|
||||
TOB::spells::LONG_BUFFS,
|
||||
TOB::spells::SHORT_BUFFS,
|
||||
TOB::spells::DISC_BUFFS,
|
||||
TOB::spells::TOTAL_BUFFS,
|
||||
TOB::spells::NPC_BUFFS,
|
||||
TOB::spells::PET_BUFFS,
|
||||
TOB::spells::MERC_BUFFS
|
||||
)
|
||||
};
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "common/patches/rof2_limits.h"
|
||||
#include "common/patches/sod_limits.h"
|
||||
#include "common/patches/sof_limits.h"
|
||||
#include "common/patches/tob_limits.h"
|
||||
#include "common/patches/titanium_limits.h"
|
||||
#include "common/patches/uf_limits.h"
|
||||
#include "common/types.h"
|
||||
|
||||
@@ -47,6 +47,13 @@ static const uint32 ADVANCED_LORE_LENGTH = 8192;
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
|
||||
struct EqGuid
|
||||
{
|
||||
uint32_t Id;
|
||||
uint16_t WorldId;
|
||||
uint16_t Reserved;
|
||||
};
|
||||
|
||||
struct LoginInfo {
|
||||
/*000*/ char login_info[64];
|
||||
/*064*/ uint8 unknown064[124];
|
||||
@@ -326,6 +333,7 @@ union
|
||||
bool buyer;
|
||||
bool untargetable;
|
||||
uint32 npc_tint_id;
|
||||
EqGuid CharacterGuid;
|
||||
};
|
||||
|
||||
struct PlayerState_Struct {
|
||||
|
||||
@@ -271,7 +271,11 @@ static size_t const stackLimit_g = JSONCPP_DEPRECATED_STACK_LIMIT; // see readVa
|
||||
|
||||
namespace Json {
|
||||
|
||||
#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
|
||||
typedef std::unique_ptr<CharReader> CharReaderPtr;
|
||||
#else
|
||||
typedef std::auto_ptr<CharReader> CharReaderPtr;
|
||||
#endif
|
||||
|
||||
// Implementation of class Features
|
||||
// ////////////////////////////////
|
||||
@@ -4149,7 +4153,11 @@ Value& Path::make(Value& root) const {
|
||||
|
||||
namespace Json {
|
||||
|
||||
#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
|
||||
typedef std::unique_ptr<StreamWriter> StreamWriterPtr;
|
||||
#else
|
||||
typedef std::auto_ptr<StreamWriter> StreamWriterPtr;
|
||||
#endif
|
||||
|
||||
static bool containsControlCharacter(const char* str) {
|
||||
while (*str) {
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// Created by dannu on 4/18/2026.
|
||||
//
|
||||
|
||||
#include "links.h"
|
||||
|
||||
#include "spdat.h"
|
||||
|
||||
void Links::FormatItemLink(char* Buffer, size_t BufferSize, const EQ::ItemInstance* item)
|
||||
{
|
||||
// TODO: Reverse 0x14064B220 to get definition of this function
|
||||
}
|
||||
|
||||
void Links::FormatSpellLink(char* Buffer, size_t BufferSize, uint32_t SpellID,
|
||||
const char* spellNameOverride)
|
||||
{
|
||||
snprintf(Buffer, BufferSize, "%c%d3^%d^0^'%s%c", ITEM_TAG_CHAR, ETAG_SPELL, SpellID,
|
||||
spellNameOverride && spellNameOverride[0] ? spellNameOverride : GetSpellName(SpellID), ITEM_TAG_CHAR);
|
||||
}
|
||||
|
||||
void Links::FormatDialogLink(char* Buffer, size_t BufferSize, std::string_view keyword, std::string_view text)
|
||||
{
|
||||
if (text.empty()) {
|
||||
snprintf(Buffer, BufferSize, "%c%d%.*s%c", ITEM_TAG_CHAR, ETAG_DIALOG_RESPONSE,
|
||||
static_cast<int>(keyword.length()), keyword.data(), ITEM_TAG_CHAR);
|
||||
} else {
|
||||
snprintf(Buffer, BufferSize, "%c%d%.*s:%.*s%c", ITEM_TAG_CHAR, ETAG_DIALOG_RESPONSE,
|
||||
static_cast<int>(keyword.length()), keyword.data(),
|
||||
static_cast<int>(text.length()), text.data(), ITEM_TAG_CHAR);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// Created by dannu on 4/18/2026.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include "item_instance.h"
|
||||
|
||||
namespace EQ { class ItemInstance; }
|
||||
|
||||
namespace Links
|
||||
{
|
||||
// Max Link Size in bytes
|
||||
constexpr size_t MAX_LINK_SIZE = 512;
|
||||
|
||||
// Universal link tag character
|
||||
constexpr char ITEM_TAG_CHAR = '\x12';
|
||||
|
||||
// Enumeration of different types of item tags
|
||||
enum ETagCodes
|
||||
{
|
||||
ETAG_ITEM = 0,
|
||||
ETAG_PLAYER,
|
||||
ETAG_SPAM,
|
||||
ETAG_ACHIEVEMENT,
|
||||
ETAG_DIALOG_RESPONSE,
|
||||
ETAG_COMMAND,
|
||||
ETAG_SPELL,
|
||||
ETAG_FACTION,
|
||||
ETAG_COMMAND2,
|
||||
ETAG_UNKNOWN9,
|
||||
|
||||
ETAG_COUNT,
|
||||
ETAG_FIRST = ETAG_ITEM,
|
||||
ETAG_LAST = ETAG_UNKNOWN9,
|
||||
|
||||
ETAG_INVALID = -1,
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Link Formatting -- Pulled from MQ code
|
||||
|
||||
// Create an achievement link for the given achievement.
|
||||
// TODO: implement this when achievements are added, leave the signature here for reference. Code in eqlib's ItemLinks.cpp
|
||||
// void FormatAchievementLink(char* Buffer, size_t BufferSize, const Achievement* achievement,
|
||||
// std::string_view playerName);
|
||||
|
||||
// Create an item link from the given item.
|
||||
void FormatItemLink(char* Buffer, size_t BufferSize, const EQ::ItemInstance* item);
|
||||
|
||||
// Create a spell link for the given spell, with optional spell name override. Spells on items often have
|
||||
// spell name overrides that changes the display name of the spell.
|
||||
void FormatSpellLink(char* Buffer, size_t BufferSize, uint32_t SpellID,
|
||||
const char* spellNameOverride = nullptr);
|
||||
|
||||
// Format text into a clickable dialog link. The keyword is the text that will be displayed in the chat window,
|
||||
// and the text is the text that will be sent to the server when the link is clicked. If no text is provided,
|
||||
// then the keyword will be used as the text.
|
||||
void FormatDialogLink(char* Buffer, size_t BufferSize, std::string_view keyword,
|
||||
std::string_view text = {});
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/* EQEmu: EQEmulator
|
||||
|
||||
Copyright (C) 2001-2026 EQEmu Development Team
|
||||
|
||||
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; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "client_version.h"
|
||||
|
||||
// Migration path: replace string_ids.h usage with ID enum values one call site at a time.
|
||||
|
||||
class Client;
|
||||
class Mob;
|
||||
class EQApplicationPacket;
|
||||
|
||||
namespace Message {
|
||||
|
||||
template<typename... Args>
|
||||
concept AllConstChar = (std::is_convertible_v<Args, const char*> && ...);
|
||||
|
||||
class IMessage
|
||||
{
|
||||
public:
|
||||
IMessage() = default;
|
||||
virtual ~IMessage() = default;
|
||||
|
||||
// these two are the basic string message packets
|
||||
virtual std::unique_ptr<EQApplicationPacket> Simple(uint32_t color, uint32_t id) const = 0;
|
||||
virtual std::unique_ptr<EQApplicationPacket> Formatted(uint32_t color, uint32_t id,
|
||||
const std::array<const char*, 9>& args) const = 0;
|
||||
|
||||
// These aren't technically messages, but they use the same format and are similar enough to include here
|
||||
virtual std::unique_ptr<EQApplicationPacket> InterruptSpell(uint32_t message, uint32_t spawn_id,
|
||||
const char* spell_link) const = 0;
|
||||
virtual std::unique_ptr<EQApplicationPacket> InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id,
|
||||
const char* name, const char* spell_link) const = 0;
|
||||
};
|
||||
|
||||
} // namespace Message
|
||||
@@ -0,0 +1,86 @@
|
||||
/* EQEmu: EQEmulator
|
||||
|
||||
Copyright (C) 2001-2026 EQEmu Development Team
|
||||
|
||||
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; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "client_version.h"
|
||||
|
||||
#include "common/patches/titanium.h"
|
||||
#include "common/patches/sof.h"
|
||||
#include "common/patches/sod.h"
|
||||
#include "common/patches/uf.h"
|
||||
#include "common/patches/rof.h"
|
||||
#include "common/patches/rof2.h"
|
||||
#include "common/patches/tob.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
using Version = EQ::versions::ClientVersion;
|
||||
|
||||
struct ClientComponents
|
||||
{
|
||||
explicit ClientComponents(Version version) : version(version)
|
||||
{
|
||||
switch (version) {
|
||||
case Version::TOB:
|
||||
messageComponent = std::make_unique<Message::TOB>();
|
||||
break;
|
||||
case Version::RoF2:
|
||||
messageComponent = std::make_unique<Message::RoF2>();
|
||||
break;
|
||||
case Version::RoF:
|
||||
messageComponent = std::make_unique<Message::RoF>();
|
||||
break;
|
||||
case Version::UF:
|
||||
messageComponent = std::make_unique<Message::UF>();
|
||||
break;
|
||||
case Version::SoD:
|
||||
messageComponent = std::make_unique<Message::SoD>();
|
||||
break;
|
||||
case Version::SoF:
|
||||
messageComponent = std::make_unique<Message::SoF>();
|
||||
break;
|
||||
case Version::Titanium:
|
||||
messageComponent = std::make_unique<Message::Titanium>();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const Version version;
|
||||
std::unique_ptr<Message::IMessage> messageComponent;
|
||||
};
|
||||
|
||||
// this array must be in the same order as the Version enum because it converts Version to index directly
|
||||
static const std::array<ClientComponents, EQ::versions::ClientVersionCount> s_patches = {
|
||||
{
|
||||
ClientComponents(Version::Unknown), // empty
|
||||
ClientComponents(Version::Client62), // empty
|
||||
ClientComponents(Version::Titanium),
|
||||
ClientComponents(Version::SoF),
|
||||
ClientComponents(Version::SoD),
|
||||
ClientComponents(Version::UF),
|
||||
ClientComponents(Version::RoF),
|
||||
ClientComponents(Version::RoF2),
|
||||
ClientComponents(Version::TOB),
|
||||
}
|
||||
};
|
||||
|
||||
const std::unique_ptr<Message::IMessage>& GetMessageComponent(Version version)
|
||||
{
|
||||
return s_patches.at(static_cast<uint32_t>(version)).messageComponent;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// Created by dannu on 4/21/2026.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/emu_versions.h"
|
||||
#include <memory>
|
||||
|
||||
namespace Message { class IMessage; }
|
||||
|
||||
// store all static functions for the different patches here, this can return nullptr for unsupported patches
|
||||
const std::unique_ptr<Message::IMessage>& GetMessageComponent(EQ::versions::ClientVersion version);
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "common/patches/rof2.h"
|
||||
#include "common/patches/sod.h"
|
||||
#include "common/patches/sof.h"
|
||||
#include "common/patches/tob.h"
|
||||
#include "common/patches/titanium.h"
|
||||
#include "common/patches/uf.h"
|
||||
|
||||
@@ -33,6 +34,7 @@ void RegisterAllPatches(EQStreamIdentifier &into)
|
||||
UF::Register(into);
|
||||
RoF::Register(into);
|
||||
RoF2::Register(into);
|
||||
TOB::Register(into);
|
||||
}
|
||||
|
||||
void ReloadAllPatches()
|
||||
@@ -43,4 +45,5 @@ void ReloadAllPatches()
|
||||
UF::Reload();
|
||||
RoF::Reload();
|
||||
RoF2::Reload();
|
||||
TOB::Reload();
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "uf.h"
|
||||
#include "common/struct_strategy.h"
|
||||
|
||||
class EQStreamIdentifier;
|
||||
@@ -48,3 +49,14 @@ namespace RoF
|
||||
};
|
||||
|
||||
} /*RoF*/
|
||||
|
||||
namespace Message {
|
||||
|
||||
class RoF : public UF
|
||||
{
|
||||
public:
|
||||
RoF() = default;
|
||||
~RoF() override = default;
|
||||
};
|
||||
|
||||
} // namespace Message
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "rof.h"
|
||||
#include "common/struct_strategy.h"
|
||||
|
||||
class EQStreamIdentifier;
|
||||
@@ -48,3 +49,14 @@ namespace RoF2
|
||||
};
|
||||
|
||||
}; /*RoF2*/
|
||||
|
||||
namespace Message {
|
||||
|
||||
class RoF2 : public RoF
|
||||
{
|
||||
public:
|
||||
RoF2() = default;
|
||||
~RoF2() override = default;
|
||||
};
|
||||
|
||||
} // namespace Message
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "sof.h"
|
||||
#include "common/struct_strategy.h"
|
||||
|
||||
class EQStreamIdentifier;
|
||||
@@ -48,3 +49,14 @@ namespace SoD
|
||||
};
|
||||
|
||||
} /*SoD*/
|
||||
|
||||
namespace Message {
|
||||
|
||||
class SoD : public SoF
|
||||
{
|
||||
public:
|
||||
SoD() = default;
|
||||
~SoD() override = default;
|
||||
};
|
||||
|
||||
} // namespace Message
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "titanium.h"
|
||||
#include "common/struct_strategy.h"
|
||||
|
||||
class EQStreamIdentifier;
|
||||
@@ -48,3 +49,14 @@ namespace SoF
|
||||
};
|
||||
|
||||
} /*SoF*/
|
||||
|
||||
namespace Message {
|
||||
|
||||
class SoF : public Titanium
|
||||
{
|
||||
public:
|
||||
SoF() = default;
|
||||
~SoF() override = default;
|
||||
};
|
||||
|
||||
} // namespace Message
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "common/raid.h"
|
||||
#include "common/rulesys.h"
|
||||
#include "common/strings.h"
|
||||
#include "zone/string_ids.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
@@ -3919,3 +3920,98 @@ namespace Titanium
|
||||
return index; // as long as we guard against bad slots server side, we should be fine
|
||||
}
|
||||
} /*Titanium*/
|
||||
|
||||
namespace Message {
|
||||
std::unique_ptr<EQApplicationPacket> Titanium::Simple(uint32_t color, uint32_t id) const
|
||||
{
|
||||
uint32_t string_id = ResolveID(id);
|
||||
if (string_id > 0) {
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(OP_SimpleMessage, sizeof(SimpleMessage_Struct));
|
||||
auto* sms = reinterpret_cast<SimpleMessage_Struct*>(outapp->pBuffer);
|
||||
sms->string_id = string_id;
|
||||
sms->color = color;
|
||||
sms->unknown8 = 0;
|
||||
|
||||
return outapp;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<EQApplicationPacket> Titanium::Formatted(
|
||||
uint32_t color, uint32_t id, const std::array<const char*, 9>& args) const
|
||||
{
|
||||
uint32_t string_id = ResolveID(id);
|
||||
if (string_id > 0) {
|
||||
std::array<const char*, 9> resolved_args = args;
|
||||
ResolveArguments(id, resolved_args);
|
||||
if (!resolved_args[0])
|
||||
return Simple(color, id);
|
||||
|
||||
SerializeBuffer buf(20);
|
||||
buf.WriteUInt32(0);
|
||||
buf.WriteUInt32(string_id);
|
||||
buf.WriteUInt32(color);
|
||||
|
||||
for (const auto* a : resolved_args) {
|
||||
if (a != nullptr)
|
||||
buf.WriteString(a);
|
||||
}
|
||||
|
||||
buf.WriteUInt8(0);
|
||||
|
||||
return std::make_unique<EQApplicationPacket>(OP_FormattedMessage, std::move(buf));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<EQApplicationPacket> Titanium::InterruptSpell(uint32_t message, uint32_t spawn_id,
|
||||
const char* spell_link) const
|
||||
{
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(OP_InterruptCast, sizeof(InterruptCast_Struct));
|
||||
auto ic = reinterpret_cast<InterruptCast_Struct*>(outapp->pBuffer);
|
||||
ic->messageid = ResolveID(message);
|
||||
ic->spawnid = spawn_id;
|
||||
outapp->priority = 5;
|
||||
|
||||
return outapp;
|
||||
}
|
||||
|
||||
std::unique_ptr<EQApplicationPacket> Titanium::InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id,
|
||||
const char* name,
|
||||
const char* spell_link) const
|
||||
{
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(OP_InterruptCast, sizeof(InterruptCast_Struct) + strlen(name) + 1);
|
||||
auto ic = reinterpret_cast<InterruptCast_Struct*>(outapp->pBuffer);
|
||||
ic->messageid = ResolveID(message);
|
||||
ic->spawnid = spawn_id;
|
||||
fmt::format_to_n(ic->message, strlen(name) + 1, "{}\0", name);
|
||||
return outapp;
|
||||
}
|
||||
|
||||
// A value of 0 means that the string isn't mapped in this client, valid string ids start at 1
|
||||
uint32_t Titanium::ResolveID(uint32_t id) const
|
||||
{
|
||||
// passthrough — string IDs are defined at the base client level;
|
||||
// override in patches where IDs need remapping
|
||||
return id;
|
||||
}
|
||||
|
||||
void Titanium::ResolveArguments(uint32_t id, std::array<const char*, 9>& args) const
|
||||
{
|
||||
switch (id) {
|
||||
case SPELL_FIZZLE:
|
||||
case MISS_NOTE:
|
||||
args[0] = nullptr; // drop spell link
|
||||
break;
|
||||
case SPELL_FIZZLE_OTHER:
|
||||
case MISSED_NOTE_OTHER:
|
||||
args[1] = nullptr; // drop spell link
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Message
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "IMessage.h"
|
||||
#include "common/struct_strategy.h"
|
||||
|
||||
class EQStreamIdentifier;
|
||||
@@ -48,3 +49,30 @@ namespace Titanium
|
||||
};
|
||||
|
||||
} /*Titanium*/
|
||||
|
||||
// out-going message packets
|
||||
namespace Message {
|
||||
|
||||
class Titanium : public IMessage
|
||||
{
|
||||
public:
|
||||
Titanium() = default;
|
||||
~Titanium() override = default;
|
||||
|
||||
std::unique_ptr<EQApplicationPacket> Simple(uint32_t color, uint32_t id) const override;
|
||||
std::unique_ptr<EQApplicationPacket> Formatted(uint32_t color, uint32_t id,
|
||||
const std::array<const char*, 9>& args) const override;
|
||||
|
||||
std::unique_ptr<EQApplicationPacket> InterruptSpell(uint32_t message, uint32_t spawn_id,
|
||||
const char* spell_link) const override;
|
||||
std::unique_ptr<EQApplicationPacket> InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id,
|
||||
const char* name,
|
||||
const char* spell_link) const override;
|
||||
|
||||
protected:
|
||||
[[nodiscard]] virtual uint32_t ResolveID(uint32_t id) const;
|
||||
virtual void ResolveArguments(uint32_t id, std::array<const char*, 9>& args) const;
|
||||
};
|
||||
|
||||
} // namespace Message
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#include "rof2.h"
|
||||
#include "../struct_strategy.h"
|
||||
|
||||
class EQStreamIdentifier;
|
||||
|
||||
namespace TOB
|
||||
{
|
||||
|
||||
//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 EQ::versions::ClientVersion ClientVersion() const;
|
||||
|
||||
//magic macro to declare our opcode processors
|
||||
#include "ss_declare.h"
|
||||
#include "tob_ops.h"
|
||||
|
||||
};
|
||||
|
||||
}; /*TOB*/
|
||||
|
||||
namespace Message {
|
||||
|
||||
class TOB : public RoF2
|
||||
{
|
||||
public:
|
||||
TOB() {}
|
||||
~TOB() override {}
|
||||
|
||||
std::unique_ptr<EQApplicationPacket> Formatted(uint32_t color, uint32_t id,
|
||||
const std::array<const char*, 9>& args) const override;
|
||||
|
||||
std::unique_ptr<EQApplicationPacket> InterruptSpell(uint32_t message, uint32_t spawn_id,
|
||||
const char* spell_link) const override;
|
||||
std::unique_ptr<EQApplicationPacket> InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id,
|
||||
const char* name, const char* spell_link) const override;
|
||||
|
||||
protected:
|
||||
[[nodiscard]] uint32_t ResolveID(uint32_t id) const override;
|
||||
void ResolveArguments(uint32_t id, std::array<const char*, 9>& args) const override;
|
||||
};
|
||||
|
||||
} // namespace Message
|
||||
@@ -0,0 +1,265 @@
|
||||
#include "tob_limits.h"
|
||||
|
||||
#include "../strings.h"
|
||||
|
||||
|
||||
int16 TOB::invtype::GetInvTypeSize(int16 inv_type)
|
||||
{
|
||||
switch (inv_type) {
|
||||
case invtype::typePossessions:
|
||||
return invtype::POSSESSIONS_SIZE;
|
||||
case invtype::typeBank:
|
||||
return invtype::BANK_SIZE;
|
||||
case invtype::typeSharedBank:
|
||||
return invtype::SHARED_BANK_SIZE;
|
||||
case invtype::typeTrade:
|
||||
return invtype::TRADE_SIZE;
|
||||
case invtype::typeWorld:
|
||||
return invtype::WORLD_SIZE;
|
||||
case invtype::typeLimbo:
|
||||
return invtype::LIMBO_SIZE;
|
||||
case invtype::typeTribute:
|
||||
return invtype::TRIBUTE_SIZE;
|
||||
case invtype::typeTrophyTribute:
|
||||
return invtype::TROPHY_TRIBUTE_SIZE;
|
||||
case invtype::typeGuildTribute:
|
||||
return invtype::GUILD_TRIBUTE_SIZE;
|
||||
case invtype::typeMerchant:
|
||||
return invtype::MERCHANT_SIZE;
|
||||
case invtype::typeDeleted:
|
||||
return invtype::DELETED_SIZE;
|
||||
case invtype::typeCorpse:
|
||||
return invtype::CORPSE_SIZE;
|
||||
case invtype::typeBazaar:
|
||||
return invtype::BAZAAR_SIZE;
|
||||
case invtype::typeInspect:
|
||||
return invtype::INSPECT_SIZE;
|
||||
case invtype::typeRealEstate:
|
||||
return invtype::REAL_ESTATE_SIZE;
|
||||
case invtype::typeViewMODPC:
|
||||
return invtype::VIEW_MOD_PC_SIZE;
|
||||
case invtype::typeViewMODBank:
|
||||
return invtype::VIEW_MOD_BANK_SIZE;
|
||||
case invtype::typeViewMODSharedBank:
|
||||
return invtype::VIEW_MOD_SHARED_BANK_SIZE;
|
||||
case invtype::typeViewMODLimbo:
|
||||
return invtype::VIEW_MOD_LIMBO_SIZE;
|
||||
case invtype::typeAltStorage:
|
||||
return invtype::ALT_STORAGE_SIZE;
|
||||
case invtype::typeArchived:
|
||||
return invtype::ARCHIVED_SIZE;
|
||||
case invtype::typeMail:
|
||||
return invtype::MAIL_SIZE;
|
||||
case invtype::typeGuildTrophyTribute:
|
||||
return invtype::GUILD_TROPHY_TRIBUTE_SIZE;
|
||||
case invtype::typeKrono:
|
||||
return invtype::KRONO_SIZE;
|
||||
case invtype::typeOther:
|
||||
return invtype::OTHER_SIZE;
|
||||
default:
|
||||
return INULL;
|
||||
}
|
||||
}
|
||||
|
||||
const char* TOB::invtype::GetInvTypeName(int16 inv_type)
|
||||
{
|
||||
switch (inv_type) {
|
||||
case invtype::TYPE_INVALID:
|
||||
return "Invalid Type";
|
||||
case invtype::typePossessions:
|
||||
return "Possessions";
|
||||
case invtype::typeBank:
|
||||
return "Bank";
|
||||
case invtype::typeSharedBank:
|
||||
return "Shared Bank";
|
||||
case invtype::typeTrade:
|
||||
return "Trade";
|
||||
case invtype::typeWorld:
|
||||
return "World";
|
||||
case invtype::typeLimbo:
|
||||
return "Limbo";
|
||||
case invtype::typeTribute:
|
||||
return "Tribute";
|
||||
case invtype::typeTrophyTribute:
|
||||
return "Trophy Tribute";
|
||||
case invtype::typeGuildTribute:
|
||||
return "Guild Tribute";
|
||||
case invtype::typeMerchant:
|
||||
return "Merchant";
|
||||
case invtype::typeDeleted:
|
||||
return "Deleted";
|
||||
case invtype::typeCorpse:
|
||||
return "Corpse";
|
||||
case invtype::typeBazaar:
|
||||
return "Bazaar";
|
||||
case invtype::typeInspect:
|
||||
return "Inspect";
|
||||
case invtype::typeRealEstate:
|
||||
return "Real Estate";
|
||||
case invtype::typeViewMODPC:
|
||||
return "View MOD PC";
|
||||
case invtype::typeViewMODBank:
|
||||
return "View MOD Bank";
|
||||
case invtype::typeViewMODSharedBank:
|
||||
return "View MOD Shared Bank";
|
||||
case invtype::typeViewMODLimbo:
|
||||
return "View MOD Limbo";
|
||||
case invtype::typeAltStorage:
|
||||
return "Alt Storage";
|
||||
case invtype::typeArchived:
|
||||
return "Archived";
|
||||
case invtype::typeMail:
|
||||
return "Mail";
|
||||
case invtype::typeGuildTrophyTribute:
|
||||
return "Guild Trophy Tribute";
|
||||
case invtype::typeKrono:
|
||||
return "Krono";
|
||||
case invtype::typeOther:
|
||||
return "Other";
|
||||
default:
|
||||
return "Unknown Type";
|
||||
}
|
||||
}
|
||||
|
||||
bool TOB::invtype::IsInvTypePersistent(int16 inv_type)
|
||||
{
|
||||
switch (inv_type) {
|
||||
case invtype::typePossessions:
|
||||
case invtype::typeBank:
|
||||
case invtype::typeSharedBank:
|
||||
case invtype::typeTrade:
|
||||
case invtype::typeWorld:
|
||||
case invtype::typeLimbo:
|
||||
case invtype::typeTribute:
|
||||
case invtype::typeTrophyTribute:
|
||||
case invtype::typeGuildTribute:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const char* TOB::invslot::GetInvPossessionsSlotName(int16 inv_slot)
|
||||
{
|
||||
switch (inv_slot) {
|
||||
case invslot::SLOT_INVALID:
|
||||
return "Invalid Slot";
|
||||
case invslot::slotCharm:
|
||||
return "Charm";
|
||||
case invslot::slotEar1:
|
||||
return "Ear 1";
|
||||
case invslot::slotHead:
|
||||
return "Head";
|
||||
case invslot::slotFace:
|
||||
return "Face";
|
||||
case invslot::slotEar2:
|
||||
return "Ear 2";
|
||||
case invslot::slotNeck:
|
||||
return "Neck";
|
||||
case invslot::slotShoulders:
|
||||
return "Shoulders";
|
||||
case invslot::slotArms:
|
||||
return "Arms";
|
||||
case invslot::slotBack:
|
||||
return "Back";
|
||||
case invslot::slotWrist1:
|
||||
return "Wrist 1";
|
||||
case invslot::slotWrist2:
|
||||
return "Wrist 2";
|
||||
case invslot::slotRange:
|
||||
return "Range";
|
||||
case invslot::slotHands:
|
||||
return "Hands";
|
||||
case invslot::slotPrimary:
|
||||
return "Primary";
|
||||
case invslot::slotSecondary:
|
||||
return "Secondary";
|
||||
case invslot::slotFinger1:
|
||||
return "Finger 1";
|
||||
case invslot::slotFinger2:
|
||||
return "Finger 2";
|
||||
case invslot::slotChest:
|
||||
return "Chest";
|
||||
case invslot::slotLegs:
|
||||
return "Legs";
|
||||
case invslot::slotFeet:
|
||||
return "Feet";
|
||||
case invslot::slotWaist:
|
||||
return "Waist";
|
||||
case invslot::slotPowerSource:
|
||||
return "Power Source";
|
||||
case invslot::slotAmmo:
|
||||
return "Ammo";
|
||||
case invslot::slotGeneral1:
|
||||
return "General 1";
|
||||
case invslot::slotGeneral2:
|
||||
return "General 2";
|
||||
case invslot::slotGeneral3:
|
||||
return "General 3";
|
||||
case invslot::slotGeneral4:
|
||||
return "General 4";
|
||||
case invslot::slotGeneral5:
|
||||
return "General 5";
|
||||
case invslot::slotGeneral6:
|
||||
return "General 6";
|
||||
case invslot::slotGeneral7:
|
||||
return "General 7";
|
||||
case invslot::slotGeneral8:
|
||||
return "General 8";
|
||||
case invslot::slotGeneral9:
|
||||
return "General 9";
|
||||
case invslot::slotGeneral10:
|
||||
return "General 10";
|
||||
case invslot::slotCursor:
|
||||
return "Cursor";
|
||||
default:
|
||||
return "Unknown Slot";
|
||||
}
|
||||
}
|
||||
|
||||
const char* TOB::invslot::GetInvSlotName(int16 inv_type, int16 inv_slot)
|
||||
{
|
||||
if (inv_type == invtype::typePossessions)
|
||||
return invslot::GetInvPossessionsSlotName(inv_slot);
|
||||
|
||||
int16 type_size = invtype::GetInvTypeSize(inv_type);
|
||||
|
||||
if (!type_size || inv_slot == invslot::SLOT_INVALID)
|
||||
return "Invalid Slot";
|
||||
|
||||
if ((inv_slot + 1) >= type_size)
|
||||
return "Unknown Slot";
|
||||
|
||||
static std::string ret_str;
|
||||
ret_str = StringFormat("Slot %i", (inv_slot + 1));
|
||||
|
||||
return ret_str.c_str();
|
||||
}
|
||||
|
||||
const char* TOB::invbag::GetInvBagIndexName(int16 bag_index)
|
||||
{
|
||||
if (bag_index == invbag::SLOT_INVALID)
|
||||
return "Invalid Bag";
|
||||
|
||||
if (bag_index >= invbag::SLOT_COUNT)
|
||||
return "Unknown Bag";
|
||||
|
||||
static std::string ret_str;
|
||||
ret_str = StringFormat("Bag %i", (bag_index + 1));
|
||||
|
||||
return ret_str.c_str();
|
||||
}
|
||||
|
||||
const char* TOB::invaug::GetInvAugIndexName(int16 aug_index)
|
||||
{
|
||||
if (aug_index == invaug::SOCKET_INVALID)
|
||||
return "Invalid Augment";
|
||||
|
||||
if (aug_index >= invaug::SOCKET_COUNT)
|
||||
return "Unknown Augment";
|
||||
|
||||
static std::string ret_str;
|
||||
ret_str = StringFormat("Augment %i", (aug_index + 1));
|
||||
|
||||
return ret_str.c_str();
|
||||
}
|
||||
@@ -0,0 +1,337 @@
|
||||
#ifndef COMMON_LAURION_LIMITS_H
|
||||
#define COMMON_LAURION_LIMITS_H
|
||||
|
||||
#include "../types.h"
|
||||
#include "../emu_versions.h"
|
||||
#include "../skills.h"
|
||||
|
||||
namespace TOB
|
||||
{
|
||||
const int16 IINVALID = -1;
|
||||
const int16 INULL = 0;
|
||||
|
||||
namespace inventory {
|
||||
inline EQ::versions::ClientVersion GetInventoryRef() { return EQ::versions::ClientVersion::TOB; }
|
||||
|
||||
const bool ConcatenateInvTypeLimbo = false;
|
||||
|
||||
const bool AllowOverLevelEquipment = true;
|
||||
|
||||
const bool AllowEmptyBagInBag = true;
|
||||
const bool AllowClickCastFromBag = true;
|
||||
|
||||
} /*inventory*/
|
||||
|
||||
namespace invtype {
|
||||
inline EQ::versions::ClientVersion GetInvTypeRef() { return EQ::versions::ClientVersion::TOB; }
|
||||
|
||||
namespace enum_ {
|
||||
enum InventoryTypes : int16 {
|
||||
typePossessions = INULL,
|
||||
typeBank,
|
||||
typeSharedBank,
|
||||
typeTrade,
|
||||
typeWorld,
|
||||
typeLimbo,
|
||||
typeTribute,
|
||||
typeTrophyTribute,
|
||||
typeGuildTribute,
|
||||
typeMerchant,
|
||||
typeDeleted,
|
||||
typeCorpse,
|
||||
typeBazaar,
|
||||
typeInspect,
|
||||
typeRealEstate,
|
||||
typeViewMODPC,
|
||||
typeViewMODBank,
|
||||
typeViewMODSharedBank,
|
||||
typeViewMODLimbo,
|
||||
typeAltStorage,
|
||||
typeArchived,
|
||||
typeMail,
|
||||
typeGuildTrophyTribute,
|
||||
typeKrono,
|
||||
typeOther,
|
||||
typeMercenaryItems,
|
||||
typeViewModMercenaryItems,
|
||||
typeMountKeyRingItems,
|
||||
typeViewModMountKeyRingItems,
|
||||
typeIllusionKeyRingItems,
|
||||
typeViewModIllusionKeyRingItems,
|
||||
typeFamiliarKeyRingItems,
|
||||
typeViewModFamiliarKeyRingItems,
|
||||
typeHeroForgeKeyRingItems,
|
||||
typeViewModHeroForgeKeyRingItems,
|
||||
typeTeleportationKeyRingItems,
|
||||
typeViewModTeleportationKeyRingItems,
|
||||
typeOverflow,
|
||||
typeDragonHoard,
|
||||
typeTradeskillDepot,
|
||||
typeGuildTradeskillDepot
|
||||
};
|
||||
|
||||
} // namespace enum_
|
||||
using namespace enum_;
|
||||
|
||||
const int16 POSSESSIONS_SIZE = 34;
|
||||
const int16 BANK_SIZE = 24;
|
||||
const int16 SHARED_BANK_SIZE = 2;
|
||||
const int16 TRADE_SIZE = 8;
|
||||
const int16 WORLD_SIZE = 10;
|
||||
const int16 LIMBO_SIZE = 36;
|
||||
const int16 TRIBUTE_SIZE = 5;
|
||||
const int16 TROPHY_TRIBUTE_SIZE = 0;//unknown
|
||||
const int16 GUILD_TRIBUTE_SIZE = 2;//unverified
|
||||
const int16 MERCHANT_SIZE = 200;
|
||||
const int16 DELETED_SIZE = 0;//unknown - "Recovery Tab"
|
||||
const int16 CORPSE_SIZE = POSSESSIONS_SIZE;
|
||||
const int16 BAZAAR_SIZE = 200;
|
||||
const int16 INSPECT_SIZE = 23;
|
||||
const int16 REAL_ESTATE_SIZE = 0;//unknown
|
||||
const int16 VIEW_MOD_PC_SIZE = POSSESSIONS_SIZE;
|
||||
const int16 VIEW_MOD_BANK_SIZE = BANK_SIZE;
|
||||
const int16 VIEW_MOD_SHARED_BANK_SIZE = SHARED_BANK_SIZE;
|
||||
const int16 VIEW_MOD_LIMBO_SIZE = LIMBO_SIZE;
|
||||
const int16 ALT_STORAGE_SIZE = 0;//unknown - "Shroud Bank"
|
||||
const int16 ARCHIVED_SIZE = 0;//unknown
|
||||
const int16 MAIL_SIZE = 0;//unknown
|
||||
const int16 GUILD_TROPHY_TRIBUTE_SIZE = 0;//unknown
|
||||
const int16 KRONO_SIZE = 0;//unknown
|
||||
const int16 OTHER_SIZE = 0;//unknown
|
||||
|
||||
const int16 TRADE_NPC_SIZE = 4; // defined by implication
|
||||
|
||||
const int16 TYPE_INVALID = IINVALID;
|
||||
const int16 TYPE_BEGIN = typePossessions;
|
||||
const int16 TYPE_END = typeOther;
|
||||
const int16 TYPE_COUNT = (TYPE_END - TYPE_BEGIN) + 1;
|
||||
|
||||
int16 GetInvTypeSize(int16 inv_type);
|
||||
const char* GetInvTypeName(int16 inv_type);
|
||||
|
||||
bool IsInvTypePersistent(int16 inv_type);
|
||||
|
||||
} /*invtype*/
|
||||
|
||||
namespace invslot {
|
||||
inline EQ::versions::ClientVersion GetInvSlotRef() { return EQ::versions::ClientVersion::TOB; }
|
||||
|
||||
namespace enum_ {
|
||||
enum InventorySlots : int16 {
|
||||
slotCharm = INULL,
|
||||
slotEar1,
|
||||
slotHead,
|
||||
slotFace,
|
||||
slotEar2,
|
||||
slotNeck,
|
||||
slotShoulders,
|
||||
slotArms,
|
||||
slotBack,
|
||||
slotWrist1,
|
||||
slotWrist2,
|
||||
slotRange,
|
||||
slotHands,
|
||||
slotPrimary,
|
||||
slotSecondary,
|
||||
slotFinger1,
|
||||
slotFinger2,
|
||||
slotChest,
|
||||
slotLegs,
|
||||
slotFeet,
|
||||
slotWaist,
|
||||
slotPowerSource,
|
||||
slotAmmo,
|
||||
slotGeneral1,
|
||||
slotGeneral2,
|
||||
slotGeneral3,
|
||||
slotGeneral4,
|
||||
slotGeneral5,
|
||||
slotGeneral6,
|
||||
slotGeneral7,
|
||||
slotGeneral8,
|
||||
slotGeneral9,
|
||||
slotGeneral10,
|
||||
slotGeneral11,
|
||||
slotGeneral12,
|
||||
slotCursor
|
||||
};
|
||||
|
||||
constexpr int16 format_as(InventorySlots slot) { return static_cast<int16>(slot); }
|
||||
} // namespace enum_
|
||||
using namespace enum_;
|
||||
|
||||
const int16 SLOT_INVALID = IINVALID;
|
||||
const int16 SLOT_BEGIN = INULL;
|
||||
|
||||
const int16 POSSESSIONS_BEGIN = slotCharm;
|
||||
const int16 POSSESSIONS_END = slotCursor;
|
||||
const int16 POSSESSIONS_COUNT = (POSSESSIONS_END - POSSESSIONS_BEGIN) + 1;
|
||||
|
||||
const int16 EQUIPMENT_BEGIN = slotCharm;
|
||||
const int16 EQUIPMENT_END = slotAmmo;
|
||||
const int16 EQUIPMENT_COUNT = (EQUIPMENT_END - EQUIPMENT_BEGIN) + 1;
|
||||
|
||||
//We support more if enabled but for now lets leave it at the 10 slots
|
||||
const int16 GENERAL_BEGIN = slotGeneral1;
|
||||
const int16 GENERAL_END = slotGeneral10;
|
||||
const int16 GENERAL_COUNT = (GENERAL_END - GENERAL_BEGIN) + 1;
|
||||
|
||||
const int16 BONUS_BEGIN = invslot::slotCharm;
|
||||
const int16 BONUS_STAT_END = invslot::slotPowerSource;
|
||||
const int16 BONUS_SKILL_END = invslot::slotAmmo;
|
||||
|
||||
const int16 CORPSE_BEGIN = invslot::slotGeneral1;
|
||||
const int16 CORPSE_END = invslot::slotGeneral1 + invslot::slotCursor;
|
||||
|
||||
const uint64 EQUIPMENT_BITMASK = 0x00000000007FFFFF;
|
||||
const uint64 GENERAL_BITMASK = 0x00000007FF800000;
|
||||
const uint64 CURSOR_BITMASK = 0x0000000800000000;
|
||||
const uint64 POSSESSIONS_BITMASK = (EQUIPMENT_BITMASK | GENERAL_BITMASK | CURSOR_BITMASK); // based on 36-slot count (TOB+)
|
||||
const uint64 CORPSE_BITMASK = (GENERAL_BITMASK | CURSOR_BITMASK | (EQUIPMENT_BITMASK << 36)); // based on 36-slot count (TOB+)
|
||||
|
||||
|
||||
const char* GetInvPossessionsSlotName(int16 inv_slot);
|
||||
const char* GetInvSlotName(int16 inv_type, int16 inv_slot);
|
||||
|
||||
} /*invslot*/
|
||||
|
||||
namespace invbag {
|
||||
inline EQ::versions::ClientVersion GetInvBagRef() { return EQ::versions::ClientVersion::TOB; }
|
||||
|
||||
const int16 SLOT_INVALID = IINVALID;
|
||||
const int16 SLOT_BEGIN = INULL;
|
||||
const int16 SLOT_END = 199;
|
||||
const int16 SLOT_COUNT = 200; // server Size will be 200..unsure what actual client is (test)
|
||||
|
||||
const char* GetInvBagIndexName(int16 bag_index);
|
||||
|
||||
} /*invbag*/
|
||||
|
||||
namespace invaug {
|
||||
inline EQ::versions::ClientVersion GetInvAugRef() { return EQ::versions::ClientVersion::TOB; }
|
||||
|
||||
const int16 SOCKET_INVALID = IINVALID;
|
||||
const int16 SOCKET_BEGIN = INULL;
|
||||
const int16 SOCKET_END = 5;
|
||||
const int16 SOCKET_COUNT = 6;
|
||||
|
||||
const char* GetInvAugIndexName(int16 aug_index);
|
||||
|
||||
} /*invaug*/
|
||||
|
||||
namespace item {
|
||||
inline EQ::versions::ClientVersion GetItemRef() { return EQ::versions::ClientVersion::TOB; }
|
||||
|
||||
//enum Unknown : int { // looks like item class..but, RoF has it too - nothing in UF-
|
||||
// Unknown1 = 0,
|
||||
// Unknown2 = 1,
|
||||
// Unknown3 = 2,
|
||||
// Unknown4 = 5 // krono?
|
||||
//};
|
||||
|
||||
enum ItemPacketType : int {
|
||||
ItemPacketMerchant = 0x64,
|
||||
ItemPacketTradeView = 0x65,
|
||||
ItemPacketLoot = 0x66,
|
||||
ItemPacketTrade = 0x67,
|
||||
//looks like they added something at 0x68 that didn't exist before and shifted everything after it up by 1
|
||||
ItemPacketUnknown068 = 0x68, //Not sure but it seems to deal with the cursor somehow.
|
||||
ItemPacketCharInventory = 0x6A, //Rof 0x69 -> Larion 0x6a (requires translation)
|
||||
ItemPacketLimbo = 0x6B, //0x6A -> 0x6B
|
||||
ItemPacketWorldContainer = 0x6C,
|
||||
ItemPacketTributeItem = 0x6D,
|
||||
ItemPacketGuildTribute = 0x6E,
|
||||
ItemPacketCharmUpdate = 0x6f,
|
||||
ItemPacketRecovery = 0x72,
|
||||
ItemPacketParcel = 0x74,
|
||||
ItemPacketUnknown075 = 0x75, //Not sure but uses a lot of the same logic as the trade and char inventory types
|
||||
ItemPacketOverflow = 0x76,
|
||||
ItemPacketDragonHoard = 0x77,
|
||||
ItemPacketTradeskill = 0x78,
|
||||
ItemPacketTradeskillDepot = 0x79,
|
||||
ItemPacketInvalid = 0xFF
|
||||
};
|
||||
|
||||
} /*item*/
|
||||
|
||||
namespace profile {
|
||||
inline EQ::versions::ClientVersion GetProfileRef() { return EQ::versions::ClientVersion::TOB; }
|
||||
|
||||
const int16 BANDOLIERS_SIZE = 20; // number of bandolier instances
|
||||
const int16 BANDOLIER_ITEM_COUNT = 4; // number of equipment slots in bandolier instance
|
||||
|
||||
const int16 POTION_BELT_SIZE = 5;
|
||||
|
||||
const int16 SKILL_ARRAY_SIZE = 100;
|
||||
|
||||
} /*profile*/
|
||||
|
||||
namespace constants {
|
||||
inline EQ::versions::ClientVersion GetConstantsRef() { return EQ::versions::ClientVersion::TOB; }
|
||||
|
||||
const EQ::expansions::Expansion EXPANSION = EQ::expansions::Expansion::LS;
|
||||
const uint32 EXPANSION_BIT = EQ::expansions::bitLS;
|
||||
const uint32 EXPANSIONS_MASK = EQ::expansions::maskLS;
|
||||
|
||||
const size_t CHARACTER_CREATION_LIMIT = 12;
|
||||
|
||||
const size_t SAY_LINK_BODY_SIZE = 56;
|
||||
const uint32 MAX_GUILD_ID = 50000;
|
||||
const uint32 MAX_BAZAAR_TRADERS = 600;
|
||||
|
||||
} /*constants*/
|
||||
|
||||
namespace behavior {
|
||||
inline EQ::versions::ClientVersion GetBehaviorRef() { return EQ::versions::ClientVersion::TOB; }
|
||||
|
||||
const bool CoinHasWeight = false;
|
||||
|
||||
} /*behavior*/
|
||||
|
||||
namespace skills {
|
||||
inline EQ::versions::ClientVersion GetSkillsRef() { return EQ::versions::ClientVersion::TOB; }
|
||||
|
||||
const size_t LastUsableSkill = EQ::skills::Skill2HPiercing;
|
||||
|
||||
} /*skills*/
|
||||
|
||||
namespace spells {
|
||||
inline EQ::versions::ClientVersion GetSkillsRef() { return EQ::versions::ClientVersion::TOB; }
|
||||
|
||||
enum class CastingSlot : uint32 {
|
||||
Gem1 = 0,
|
||||
Gem2 = 1,
|
||||
Gem3 = 2,
|
||||
Gem4 = 3,
|
||||
Gem5 = 4,
|
||||
Gem6 = 5,
|
||||
Gem7 = 6,
|
||||
Gem8 = 7,
|
||||
Gem9 = 8,
|
||||
Gem10 = 9,
|
||||
Gem11 = 10,
|
||||
Gem12 = 11,
|
||||
MaxGems = 18, // fallacy..only 12 slot are useable...
|
||||
Item = 12,
|
||||
Discipline = 13,
|
||||
AltAbility = 0xFF
|
||||
};
|
||||
|
||||
const int SPELL_ID_MAX = 71999;
|
||||
const int SPELLBOOK_SIZE = 1120;
|
||||
const int SPELL_GEM_COUNT = static_cast<uint32>(CastingSlot::MaxGems);
|
||||
const int SPELL_GEM_RECAST_TIMER = 15;
|
||||
|
||||
const int LONG_BUFFS = 42;
|
||||
const int SHORT_BUFFS = 30;
|
||||
const int DISC_BUFFS = 1;
|
||||
const int TOTAL_BUFFS = LONG_BUFFS + SHORT_BUFFS + DISC_BUFFS;
|
||||
const int NPC_BUFFS = 400;
|
||||
const int PET_BUFFS = NPC_BUFFS;
|
||||
const int MERC_BUFFS = LONG_BUFFS;
|
||||
|
||||
} /*spells*/
|
||||
|
||||
}; /* TOB */
|
||||
|
||||
#endif /*COMMON_LAURION_LIMITS_H*/
|
||||
@@ -0,0 +1,100 @@
|
||||
//list of packets we need to encode on the way out:
|
||||
E(OP_AAExpUpdate)
|
||||
E(OP_Action)
|
||||
E(OP_Animation)
|
||||
E(OP_ApplyPoison)
|
||||
E(OP_AugmentInfo)
|
||||
E(OP_BeginCast)
|
||||
E(OP_BlockedBuffs)
|
||||
E(OP_Buff)
|
||||
E(OP_BuffCreate)
|
||||
E(OP_CancelTrade)
|
||||
E(OP_CastSpell)
|
||||
E(OP_ChannelMessage)
|
||||
E(OP_CharacterCreateRequest)
|
||||
E(OP_CharInventory)
|
||||
E(OP_ClickObjectAction)
|
||||
E(OP_ClientUpdate)
|
||||
E(OP_Consider)
|
||||
E(OP_Damage)
|
||||
E(OP_Death)
|
||||
E(OP_DeleteCharge)
|
||||
E(OP_DeleteItem)
|
||||
E(OP_DeleteSpawn)
|
||||
E(OP_DisciplineUpdate)
|
||||
E(OP_ExpansionInfo)
|
||||
E(OP_ExpUpdate)
|
||||
E(OP_GMTraining)
|
||||
E(OP_GMTrainSkillConfirm)
|
||||
E(OP_GroundSpawn)
|
||||
E(OP_HPUpdate)
|
||||
E(OP_Illusion)
|
||||
E(OP_ItemPacket)
|
||||
E(OP_LogServer)
|
||||
E(OP_ManaChange)
|
||||
E(OP_MemorizeSpell)
|
||||
E(OP_MobHealth)
|
||||
E(OP_MoneyOnCorpse)
|
||||
E(OP_MoveItem)
|
||||
E(OP_NewSpawn)
|
||||
E(OP_NewZone)
|
||||
E(OP_OnLevelMessage)
|
||||
E(OP_PlayerProfile)
|
||||
E(OP_RemoveBlockedBuffs)
|
||||
E(OP_RespondAA)
|
||||
E(OP_RequestClientZoneChange)
|
||||
E(OP_RecipeAutoCombine)
|
||||
E(OP_SendAATable)
|
||||
E(OP_SendCharInfo)
|
||||
E(OP_SendMaxCharacters)
|
||||
E(OP_SendMembership)
|
||||
E(OP_SendMembershipDetails)
|
||||
E(OP_SendZonepoints)
|
||||
E(OP_ShopPlayerBuy)
|
||||
E(OP_ShopPlayerSell)
|
||||
E(OP_ShopRequest)
|
||||
E(OP_SkillUpdate)
|
||||
E(OP_SpecialMesg)
|
||||
E(OP_SpawnAppearance)
|
||||
E(OP_SpawnDoor)
|
||||
E(OP_Stun)
|
||||
E(OP_WearChange)
|
||||
E(OP_ZoneChange)
|
||||
E(OP_ZoneEntry)
|
||||
E(OP_ZonePlayerToBind)
|
||||
E(OP_ZoneSpawns)
|
||||
|
||||
//list of packets we need to decode on the way in:
|
||||
D(OP_Animation)
|
||||
D(OP_ApplyPoison)
|
||||
D(OP_ApproveName)
|
||||
D(OP_AugmentInfo)
|
||||
D(OP_AugmentItem)
|
||||
D(OP_BlockedBuffs)
|
||||
D(OP_CastSpell)
|
||||
D(OP_ChannelMessage)
|
||||
D(OP_CharacterCreate)
|
||||
D(OP_ClientUpdate)
|
||||
D(OP_ClickDoor)
|
||||
D(OP_Consider)
|
||||
D(OP_ConsiderCorpse)
|
||||
D(OP_DeleteItem)
|
||||
D(OP_EnterWorld)
|
||||
D(OP_GMTraining)
|
||||
D(OP_GroupDisband)
|
||||
D(OP_GroupInvite)
|
||||
D(OP_GroupInvite2)
|
||||
D(OP_MemorizeSpell)
|
||||
D(OP_MoveItem)
|
||||
D(OP_RemoveBlockedBuffs)
|
||||
D(OP_SetServerFilter)
|
||||
D(OP_ShopPlayerBuy)
|
||||
D(OP_ShopPlayerSell)
|
||||
D(OP_ShopRequest)
|
||||
D(OP_SpawnAppearance)
|
||||
D(OP_TradeSkillCombine)
|
||||
D(OP_WearChange)
|
||||
D(OP_ZoneEntry)
|
||||
D(OP_ZoneChange)
|
||||
#undef E
|
||||
#undef D
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "sod.h"
|
||||
#include "common/struct_strategy.h"
|
||||
|
||||
class EQStreamIdentifier;
|
||||
@@ -48,3 +49,14 @@ namespace UF
|
||||
};
|
||||
|
||||
}; /*UF*/
|
||||
|
||||
namespace Message {
|
||||
|
||||
class UF : public SoD
|
||||
{
|
||||
public:
|
||||
UF() = default;
|
||||
~UF() override = default;
|
||||
};
|
||||
|
||||
} // namespace Message
|
||||
|
||||
+2
-1
@@ -350,11 +350,12 @@ RULE_STRING(World, MOTD, "", "Server MOTD sent on login, change from empty to ha
|
||||
RULE_STRING(World, Rules, "", "Server Rules, change from empty to have this be used instead of variables table 'rules' value, lines are pipe (|) separated, example: A|B|C")
|
||||
RULE_BOOL(World, EnableAutoLogin, false, "Enables or disables auto login of characters, allowing people to log characters in directly from loginserver to ingame")
|
||||
RULE_BOOL(World, EnablePVPRegions, true, "Enables or disables PVP Regions automatically setting your PVP flag")
|
||||
RULE_STRING(World, SupportedClients, "RoF2", "Comma-delimited list of clients to restrict to. Supported values are Titanium | SoF | SoD | UF | RoF | RoF2. Example: Titanium,RoF2")
|
||||
RULE_STRING(World, SupportedClients, "RoF2,TOB", "Comma-delimited list of clients to restrict to. Supported values are Titanium | SoF | SoD | UF | RoF | RoF2 | TOB. Example: Titanium,RoF2,TOB")
|
||||
RULE_STRING(World, CustomFilesKey, "", "Enable if the server requires custom files and sends a key to validate. Empty string to disable. Example: eqcustom_v1")
|
||||
RULE_STRING(World, CustomFilesUrl, "github.com/knervous/eqnexus/releases", "URL to display at character select if client is missing custom files")
|
||||
RULE_INT(World, CustomFilesAdminLevel, 20, "Admin level at which custom file key is not required when CustomFilesKey is specified")
|
||||
RULE_BOOL(World, RealTimeCalculateGuilds, false, "(Temp feature flag) If true, guilds will be calculated in real time instead of at zone boot. This is a performance hit but allows for more dynamic guilds.")
|
||||
RULE_INT(World, Id, 100, "Used by later clients to create GUIDs, expected to be Unique to the world but ultimately not that important")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Zone)
|
||||
|
||||
+109
-50
@@ -380,59 +380,118 @@ std::string Strings::NumberToWords(unsigned long long int n)
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string Strings::Money(uint64 platinum, uint64 gold, uint64 silver, uint64 copper, bool commify) {
|
||||
uint64 values[] = { platinum, gold, silver, copper };
|
||||
const char* names[] = { " platinum", " gold", " silver", " copper" };
|
||||
|
||||
std::vector<std::string> parts;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (values[i] > 0) {
|
||||
std::string s = std::to_string(values[i]);
|
||||
parts.push_back((commify ? Strings::Commify(s) : s) + names[i]);
|
||||
}
|
||||
std::string Strings::Money(uint64 platinum, uint64 gold, uint64 silver, uint64 copper)
|
||||
{
|
||||
std::string money_string = "Unknown";
|
||||
if (copper && silver && gold && platinum) { // CSGP
|
||||
money_string = fmt::format(
|
||||
"{} platinum, {} gold, {} silver, and {} copper",
|
||||
Strings::Commify(std::to_string(platinum)),
|
||||
Strings::Commify(std::to_string(gold)),
|
||||
Strings::Commify(std::to_string(silver)),
|
||||
Strings::Commify(std::to_string(copper))
|
||||
);
|
||||
}
|
||||
|
||||
if (parts.empty()) return "0 copper";
|
||||
if (parts.size() == 1) return parts[0];
|
||||
|
||||
std::string result;
|
||||
for (size_t i = 0; i < parts.size(); ++i) {
|
||||
result += parts[i];
|
||||
if (i < parts.size() - 2) {
|
||||
result += ", ";
|
||||
}
|
||||
else if (i == parts.size() - 2) {
|
||||
// Oxford comma logic: ", and " for 3+ items, " and " for 2
|
||||
result += (parts.size() > 2) ? ", and " : " and ";
|
||||
}
|
||||
else if (copper && silver && !gold && platinum) { // CSP
|
||||
money_string = fmt::format(
|
||||
"{} platinum, {} silver, and {} copper",
|
||||
Strings::Commify(std::to_string(platinum)),
|
||||
Strings::Commify(std::to_string(silver)),
|
||||
Strings::Commify(std::to_string(copper))
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
else if (copper && silver && gold && !platinum) { // CSG
|
||||
money_string = fmt::format(
|
||||
"{} gold, {} silver, and {} copper",
|
||||
Strings::Commify(std::to_string(gold)),
|
||||
Strings::Commify(std::to_string(silver)),
|
||||
Strings::Commify(std::to_string(copper))
|
||||
);
|
||||
}
|
||||
else if (copper && !silver && !gold && platinum) { // CP
|
||||
money_string = fmt::format(
|
||||
"{} platinum and {} copper",
|
||||
Strings::Commify(std::to_string(platinum)),
|
||||
Strings::Commify(std::to_string(copper))
|
||||
);
|
||||
}
|
||||
else if (copper && silver && !gold && !platinum) { // CS
|
||||
money_string = fmt::format(
|
||||
"{} silver and {} copper",
|
||||
Strings::Commify(std::to_string(silver)),
|
||||
Strings::Commify(std::to_string(copper))
|
||||
);
|
||||
}
|
||||
else if (!copper && silver && gold && platinum) { // SGP
|
||||
money_string = fmt::format(
|
||||
"{} platinum, {} gold, and {} silver",
|
||||
Strings::Commify(std::to_string(platinum)),
|
||||
Strings::Commify(std::to_string(gold)),
|
||||
Strings::Commify(std::to_string(silver))
|
||||
);
|
||||
}
|
||||
else if (!copper && silver && !gold && platinum) { // SP
|
||||
money_string = fmt::format(
|
||||
"{} platinum and {} silver",
|
||||
Strings::Commify(std::to_string(platinum)),
|
||||
Strings::Commify(std::to_string(silver))
|
||||
);
|
||||
}
|
||||
else if (!copper && silver && gold && !platinum) { // SG
|
||||
money_string = fmt::format(
|
||||
"{} gold and {} silver",
|
||||
Strings::Commify(std::to_string(gold)),
|
||||
Strings::Commify(std::to_string(silver))
|
||||
);
|
||||
}
|
||||
else if (copper && !silver && gold && platinum) { // CGP
|
||||
money_string = fmt::format(
|
||||
"{} platinum, {} gold, and {} copper",
|
||||
Strings::Commify(std::to_string(platinum)),
|
||||
Strings::Commify(std::to_string(gold)),
|
||||
Strings::Commify(std::to_string(copper))
|
||||
);
|
||||
}
|
||||
else if (copper && !silver && gold && !platinum) { // CG
|
||||
money_string = fmt::format(
|
||||
"{} gold and {} copper",
|
||||
Strings::Commify(std::to_string(gold)),
|
||||
Strings::Commify(std::to_string(copper))
|
||||
);
|
||||
}
|
||||
else if (!copper && !silver && gold && platinum) { // GP
|
||||
money_string = fmt::format(
|
||||
"{} platinum and {} gold",
|
||||
Strings::Commify(std::to_string(platinum)),
|
||||
Strings::Commify(std::to_string(gold))
|
||||
);
|
||||
}
|
||||
else if (!copper && !silver && !gold && platinum) { // P
|
||||
money_string = fmt::format(
|
||||
"{} platinum",
|
||||
Strings::Commify(std::to_string(platinum))
|
||||
);
|
||||
}
|
||||
else if (!copper && !silver && gold && !platinum) { // G
|
||||
money_string = fmt::format(
|
||||
"{} gold",
|
||||
Strings::Commify(std::to_string(gold))
|
||||
);
|
||||
}
|
||||
else if (!copper && silver && !gold && !platinum) { // S
|
||||
money_string = fmt::format(
|
||||
"{} silver",
|
||||
Strings::Commify(std::to_string(silver))
|
||||
);
|
||||
}
|
||||
else if (copper && !silver && !gold && !platinum) { // C
|
||||
money_string = fmt::format(
|
||||
"{} copper",
|
||||
Strings::Commify(std::to_string(copper))
|
||||
);
|
||||
}
|
||||
return money_string;
|
||||
}
|
||||
|
||||
std::string Strings::MoneyShort(uint64 copper, bool commify) {
|
||||
// Matches merchant format
|
||||
uint64 values[] = {
|
||||
copper / 1000,
|
||||
(copper / 100) % 10,
|
||||
(copper / 10) % 10,
|
||||
copper % 10
|
||||
};
|
||||
const char* names[] = { " platinum", " gold", " silver", " copper" };
|
||||
|
||||
std::string result;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (values[i] > 0) {
|
||||
if (!result.empty()) result += " ";
|
||||
|
||||
std::string s = std::to_string(values[i]);
|
||||
result += (commify ? Strings::Commify(s) : s) + names[i];
|
||||
}
|
||||
}
|
||||
|
||||
return result.empty() ? "0 copper" : result;
|
||||
}
|
||||
|
||||
std::string Strings::SecondsToTime(int duration, bool is_milliseconds)
|
||||
{
|
||||
if (duration <= 0) {
|
||||
|
||||
+1
-2
@@ -62,8 +62,7 @@ public:
|
||||
static std::string Join(const std::vector<std::string> &ar, const std::string &delim);
|
||||
static std::string Join(const std::vector<uint32_t> &ar, const std::string &delim);
|
||||
static std::string MillisecondsToTime(int duration);
|
||||
static std::string Money(uint64 platinum, uint64 gold = 0, uint64 silver = 0, uint64 copper = 0, bool commify = true);
|
||||
static std::string MoneyShort(uint64 copper = 0, bool commify = true); // Matches merchant format when commify is false
|
||||
static std::string Money(uint64 platinum, uint64 gold = 0, uint64 silver = 0, uint64 copper = 0);
|
||||
static std::string NumberToWords(unsigned long long int n);
|
||||
static std::string Repeat(std::string s, int n);
|
||||
static std::string Replace(std::string subject, const std::string &search, const std::string &replace);
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace luabind { namespace detail
|
||||
if (luabind::move_back_reference(L, ptr))
|
||||
return;
|
||||
|
||||
make_instance(L, std::unique_ptr<T>(ptr));
|
||||
make_instance(L, std::auto_ptr<T>(ptr));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -335,7 +335,7 @@ namespace luabind
|
||||
template <class T>
|
||||
struct default_pointer<null_type, T>
|
||||
{
|
||||
typedef std::unique_ptr<T> type;
|
||||
typedef std::auto_ptr<T> type;
|
||||
};
|
||||
|
||||
template <class Class, class Pointer, class Signature, class Policies>
|
||||
|
||||
@@ -46,7 +46,7 @@ struct construct_aux<0, T, Pointer, Signature>
|
||||
object_rep* self = touserdata<object_rep>(self_);
|
||||
class_rep* cls = self->crep();
|
||||
|
||||
std::unique_ptr<T> instance(new T);
|
||||
std::auto_ptr<T> instance(new T);
|
||||
inject_backref(self_.interpreter(), instance.get(), instance.get());
|
||||
|
||||
void* naked_ptr = instance.get();
|
||||
@@ -55,7 +55,7 @@ struct construct_aux<0, T, Pointer, Signature>
|
||||
void* storage = self->allocate(sizeof(holder_type));
|
||||
|
||||
self->set_instance(new (storage) holder_type(
|
||||
std::move(ptr), registered_class<T>::id, naked_ptr, cls));
|
||||
ptr, registered_class<T>::id, naked_ptr, cls));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -92,7 +92,7 @@ struct construct_aux<N, T, Pointer, Signature>
|
||||
object_rep* self = touserdata<object_rep>(self_);
|
||||
class_rep* cls = self->crep();
|
||||
|
||||
std::unique_ptr<T> instance(new T(BOOST_PP_ENUM_PARAMS(N,_)));
|
||||
std::auto_ptr<T> instance(new T(BOOST_PP_ENUM_PARAMS(N,_)));
|
||||
inject_backref(self_.interpreter(), instance.get(), instance.get());
|
||||
|
||||
void* naked_ptr = instance.get();
|
||||
@@ -101,7 +101,7 @@ struct construct_aux<N, T, Pointer, Signature>
|
||||
void* storage = self->allocate(sizeof(holder_type));
|
||||
|
||||
self->set_instance(new (storage) holder_type(
|
||||
std::move(ptr), registered_class<T>::id, naked_ptr, cls));
|
||||
ptr, registered_class<T>::id, naked_ptr, cls));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace has_get_pointer_
|
||||
T* get_pointer(T const volatile*);
|
||||
|
||||
template<class T>
|
||||
T* get_pointer(std::unique_ptr<T> const&);
|
||||
T* get_pointer(std::auto_ptr<T> const&);
|
||||
|
||||
# endif
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ inline mpl::true_ check_const_pointer(void const*)
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void release_ownership(std::unique_ptr<T>& p)
|
||||
void release_ownership(std::auto_ptr<T>& p)
|
||||
{
|
||||
p.release();
|
||||
}
|
||||
@@ -83,7 +83,7 @@ public:
|
||||
P p, class_id dynamic_id, void* dynamic_ptr, class_rep* cls
|
||||
)
|
||||
: instance_holder(cls, check_const_pointer(false ? get_pointer(p) : 0))
|
||||
, p(std::move(p))
|
||||
, p(p)
|
||||
, weak(0)
|
||||
, dynamic_id(dynamic_id)
|
||||
, dynamic_ptr(dynamic_ptr)
|
||||
|
||||
@@ -88,7 +88,7 @@ void make_instance(lua_State* L, P p)
|
||||
|
||||
try
|
||||
{
|
||||
new (storage) holder_type(std::move(p), dynamic.first, dynamic.second, cls);
|
||||
new (storage) holder_type(p, dynamic.first, dynamic.second, cls);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
@@ -169,7 +169,7 @@ namespace luabind { namespace detail
|
||||
{
|
||||
if (get_pointer(x))
|
||||
{
|
||||
make_instance(L, std::move(x));
|
||||
make_instance(L, x);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -180,8 +180,8 @@ namespace luabind { namespace detail
|
||||
template <class T>
|
||||
void make_pointee_instance(lua_State* L, T& x, mpl::false_, mpl::true_)
|
||||
{
|
||||
std::unique_ptr<T> ptr(new T(x));
|
||||
make_instance(L, std::move(ptr));
|
||||
std::auto_ptr<T> ptr(new T(x));
|
||||
make_instance(L, ptr);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace detail
|
||||
template <class F, class Policies>
|
||||
scope def(char const* name, F f, Policies const& policies)
|
||||
{
|
||||
return scope(std::unique_ptr<detail::registration>(
|
||||
return scope(std::auto_ptr<detail::registration>(
|
||||
new detail::function_registration<F, Policies>(name, f, policies)));
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace luabind {
|
||||
struct LUABIND_API scope
|
||||
{
|
||||
scope();
|
||||
explicit scope(std::unique_ptr<detail::registration> reg);
|
||||
explicit scope(std::auto_ptr<detail::registration> reg);
|
||||
scope(scope const& other_);
|
||||
~scope();
|
||||
|
||||
|
||||
@@ -235,7 +235,7 @@ namespace luabind { namespace detail {
|
||||
// -- interface ---------------------------------------------------------
|
||||
|
||||
class_base::class_base(char const* name)
|
||||
: scope(std::unique_ptr<registration>(
|
||||
: scope(std::auto_ptr<registration>(
|
||||
m_registration = new class_registration(name))
|
||||
)
|
||||
{
|
||||
@@ -258,14 +258,14 @@ namespace luabind { namespace detail {
|
||||
|
||||
void class_base::add_member(registration* member)
|
||||
{
|
||||
std::unique_ptr<registration> ptr(member);
|
||||
m_registration->m_members.operator,(scope(std::move(ptr)));
|
||||
std::auto_ptr<registration> ptr(member);
|
||||
m_registration->m_members.operator,(scope(ptr));
|
||||
}
|
||||
|
||||
void class_base::add_default_member(registration* member)
|
||||
{
|
||||
std::unique_ptr<registration> ptr(member);
|
||||
m_registration->m_default_members.operator,(scope(std::move(ptr)));
|
||||
std::auto_ptr<registration> ptr(member);
|
||||
m_registration->m_default_members.operator,(scope(ptr));
|
||||
}
|
||||
|
||||
const char* class_base::name() const
|
||||
|
||||
@@ -49,8 +49,7 @@ namespace luabind { namespace detail {
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
scope::scope(std::unique_ptr<detail::registration> reg)
|
||||
scope::scope(std::auto_ptr<detail::registration> reg)
|
||||
: m_chain(reg.release())
|
||||
{
|
||||
}
|
||||
@@ -194,7 +193,7 @@ namespace luabind {
|
||||
};
|
||||
|
||||
namespace_::namespace_(char const* name)
|
||||
: scope(std::unique_ptr<detail::registration>(
|
||||
: scope(std::auto_ptr<detail::registration>(
|
||||
m_registration = new registration_(name)))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -37,13 +37,3 @@ target_include_directories(loginserver PRIVATE ..)
|
||||
|
||||
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||
set_property(TARGET loginserver PROPERTY FOLDER executables/servers)
|
||||
|
||||
# vcpkg doesn't copy legacy.dll automatically because it is loaded at runtime, not via the import table.
|
||||
if(WIN32 AND DEFINED VCPKG_INSTALLED_DIR AND DEFINED VCPKG_TARGET_TRIPLET)
|
||||
add_custom_command(TARGET loginserver POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"$<IF:$<CONFIG:Debug>,${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug/bin/legacy.dll,${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/bin/legacy.dll>"
|
||||
"$<TARGET_FILE_DIR:loginserver>/legacy.dll"
|
||||
VERBATIM
|
||||
)
|
||||
endif()
|
||||
|
||||
+41
-47
@@ -88,6 +88,9 @@ bool Client::Process()
|
||||
SendPlayToWorld((const char *) app->pBuffer);
|
||||
break;
|
||||
}
|
||||
case OP_SystemFingerprint: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delete app;
|
||||
@@ -104,16 +107,19 @@ void Client::HandleSessionReady(const char *data, unsigned int size)
|
||||
return;
|
||||
}
|
||||
|
||||
if (size < sizeof(unsigned int)) {
|
||||
if (size < sizeof(int32)) {
|
||||
LogError("Session ready was too small");
|
||||
return;
|
||||
}
|
||||
|
||||
//existing sequence id
|
||||
int32 sequence_in = *(int32*)data;
|
||||
|
||||
m_client_status = cs_waiting_for_login;
|
||||
|
||||
auto *outapp = new EQApplicationPacket(OP_ChatMessage, sizeof(LoginHandShakeReply));
|
||||
auto buf = reinterpret_cast<LoginHandShakeReply *>(outapp->pBuffer);
|
||||
buf->base_header.sequence = 0x02;
|
||||
buf->base_header.sequence = sequence_in;
|
||||
buf->base_reply.success = true;
|
||||
buf->base_reply.error_str_id = 0x65; // 101 "No Error"
|
||||
|
||||
@@ -296,20 +302,13 @@ void Client::SendPlayResponse(EQApplicationPacket *outapp)
|
||||
|
||||
void Client::GenerateRandomLoginKey()
|
||||
{
|
||||
m_key.clear();
|
||||
int count = 0;
|
||||
while (count < 10) {
|
||||
static const char key_selection[] =
|
||||
{
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||
'Y', 'Z', '0', '1', '2', '3', '4', '5',
|
||||
'6', '7', '8', '9'
|
||||
};
|
||||
static constexpr std::string_view key_selection = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
|
||||
constexpr size_t key_length = 10;
|
||||
|
||||
m_key.append((const char *) &key_selection[m_random.Int(0, 35)], 1);
|
||||
count++;
|
||||
m_key.clear();
|
||||
m_key.reserve(key_length);
|
||||
for (size_t i = 0; i < key_length; ++i) {
|
||||
m_key += key_selection[m_random.Int(0, key_selection.size() - 1)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,16 +357,17 @@ void Client::SendFailedLogin()
|
||||
|
||||
// unencrypted
|
||||
LoginBaseMessage h{};
|
||||
h.sequence = m_login_base_message.sequence; // login (3)
|
||||
h.sequence = m_login_base_message.sequence;
|
||||
h.encrypt_type = m_login_base_message.encrypt_type;
|
||||
h.unk3 = m_login_base_message.unk3;
|
||||
|
||||
// encrypted
|
||||
PlayerLoginReply r{};
|
||||
r.base_reply.success = false;
|
||||
r.base_reply.error_str_id = 105; // Error - The username and/or password were not valid
|
||||
PlayerLoginReply r = m_client_version == cv_tob ? PlayerLoginReply(PlayerLoginReplyTOB{}) : PlayerLoginReply(PlayerLoginReplyOld{});
|
||||
r.set_error_code(LS::ErrStr::ERROR_INVALID_CREDS);
|
||||
// We don't care what key we send, just that it exists and is 10 characters so that we do not shift
|
||||
r.set_key("InvalidKey");
|
||||
|
||||
char encrypted_buffer[80] = {0};
|
||||
auto rc = eqcrypt_block((const char *) &r, sizeof(r), encrypted_buffer, 1);
|
||||
char encrypted_buffer[80] = { 0 };
|
||||
auto rc = eqcrypt_block(r.data(), r.size(), encrypted_buffer, 1);
|
||||
if (rc == nullptr) {
|
||||
LogDebug("Failed to encrypt eqcrypt block for failed login");
|
||||
}
|
||||
@@ -378,6 +378,7 @@ void Client::SendFailedLogin()
|
||||
outapp.WriteData(&encrypted_buffer, sizeof(encrypted_buffer));
|
||||
|
||||
m_connection->QueuePacket(&outapp);
|
||||
|
||||
m_client_status = cs_failed_to_login;
|
||||
}
|
||||
|
||||
@@ -465,40 +466,33 @@ void Client::DoSuccessfulLogin(LoginAccountsRepository::LoginAccounts &a)
|
||||
|
||||
// unencrypted
|
||||
LoginBaseMessage h{};
|
||||
h.sequence = m_login_base_message.sequence;
|
||||
h.compressed = false;
|
||||
h.sequence = m_login_base_message.sequence;
|
||||
h.compressed = false;
|
||||
h.encrypt_type = m_login_base_message.encrypt_type;
|
||||
h.unk3 = m_login_base_message.unk3;
|
||||
h.unk3 = m_login_base_message.unk3;
|
||||
|
||||
// not serializing any of the variable length strings so just use struct directly
|
||||
PlayerLoginReply r{};
|
||||
r.base_reply.success = true;
|
||||
r.base_reply.error_str_id = 101; // No Error
|
||||
r.unk1 = 0;
|
||||
r.unk2 = 0;
|
||||
r.lsid = a.id;
|
||||
r.failed_attempts = 0;
|
||||
r.show_player_count = server.options.IsShowPlayerCountEnabled();
|
||||
r.offer_min_days = 99;
|
||||
r.offer_min_views = -1;
|
||||
r.offer_cooldown_minutes = 0;
|
||||
r.web_offer_number = 0;
|
||||
r.web_offer_min_days = 99;
|
||||
r.web_offer_min_views = -1;
|
||||
r.web_offer_cooldown_minutes = 0;
|
||||
memcpy(r.key, m_key.c_str(), m_key.size());
|
||||
PlayerLoginReply r = m_client_version == cv_tob ? PlayerLoginReply(PlayerLoginReplyTOB{}) : PlayerLoginReply(PlayerLoginReplyOld{});
|
||||
|
||||
SendExpansionPacketData(r);
|
||||
r.set_success(true);
|
||||
r.set_error_code(LS::ErrStr::ERROR_NONE);
|
||||
r.set_lsid(a.id);
|
||||
r.set_show_player_count(server.options.IsShowPlayerCountEnabled());
|
||||
r.set_key(m_key);
|
||||
|
||||
char encrypted_buffer[80] = {0};
|
||||
if (m_client_version != cv_tob) {
|
||||
SendExpansionPacketData(r.old());
|
||||
}
|
||||
|
||||
auto rc = eqcrypt_block((const char *) &r, sizeof(r), encrypted_buffer, 1);
|
||||
char encrypted_buffer[80] = { 0 };
|
||||
|
||||
auto rc = eqcrypt_block(r.data(), r.size(), encrypted_buffer, 1);
|
||||
if (rc == nullptr) {
|
||||
LogDebug("Failed to encrypt eqcrypt block");
|
||||
}
|
||||
|
||||
constexpr int outsize = sizeof(LoginBaseMessage) + sizeof(encrypted_buffer);
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(OP_LoginAccepted, outsize);
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(OP_LoginAccepted, outsize);
|
||||
outapp->WriteData(&h, sizeof(h));
|
||||
outapp->WriteData(&encrypted_buffer, sizeof(encrypted_buffer));
|
||||
|
||||
@@ -507,7 +501,7 @@ void Client::DoSuccessfulLogin(LoginAccountsRepository::LoginAccounts &a)
|
||||
m_client_status = cs_logged_in;
|
||||
}
|
||||
|
||||
void Client::SendExpansionPacketData(PlayerLoginReply &plrs)
|
||||
void Client::SendExpansionPacketData(PlayerLoginReplyOld &plrs)
|
||||
{
|
||||
SerializeBuffer buf;
|
||||
//from eqlsstr_us.txt id of each expansion, excluding 'Everquest'
|
||||
@@ -534,7 +528,7 @@ void Client::SendExpansionPacketData(PlayerLoginReply &plrs)
|
||||
|
||||
//generate expansion data
|
||||
for (int i = 0; i < 19; i++) {
|
||||
buf.WriteInt32(i); //sequenctial number
|
||||
buf.WriteInt32(i); //sequential number
|
||||
buf.WriteInt32((expansion & (1 << i)) == (1 << i) ? 0x01 : 0x00); //1 own 0 not own
|
||||
buf.WriteInt8(0x00);
|
||||
buf.WriteInt32(ExpansionLookup[i]); //from eqlsstr_us.txt
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
// Titanium uses the encrypted data block to contact the expansion (You own xxx:) and the max expansions (of yyy)
|
||||
// Rof uses a separate data packet specifically for the expansion data
|
||||
// Live, as of July 2021 uses a similar but slightly different seperate data packet
|
||||
void SendExpansionPacketData(PlayerLoginReply &plrs);
|
||||
void SendExpansionPacketData(PlayerLoginReplyOld &plrs);
|
||||
void SendPlayToWorld(const char *data);
|
||||
void SendServerListPacket(uint32 seq);
|
||||
void SendPlayResponse(EQApplicationPacket *outapp);
|
||||
|
||||
@@ -74,7 +74,7 @@ void CheckSoDOpcodeFile(const std::string &path)
|
||||
}
|
||||
}
|
||||
|
||||
void CheckLarionOpcodeFile(const std::string &path)
|
||||
void CheckTOBOpcodeFile(const std::string &path)
|
||||
{
|
||||
if (File::Exists(path)) {
|
||||
return;
|
||||
@@ -87,15 +87,15 @@ void CheckLarionOpcodeFile(const std::string &path)
|
||||
fprintf(f, "OP_Login=0x0002\n");
|
||||
fprintf(f, "OP_ServerListRequest=0x0004\n");
|
||||
fprintf(f, "OP_PlayEverquestRequest=0x000d\n");
|
||||
fprintf(f, "OP_PlayEverquestResponse=0x0022\n");
|
||||
fprintf(f, "OP_ChatMessage=0x0017\n");
|
||||
fprintf(f, "OP_LoginAccepted=0x0018\n");
|
||||
fprintf(f, "OP_ServerListResponse=0x0019\n");
|
||||
fprintf(f, "OP_Poll=0x0029\n");
|
||||
fprintf(f, "OP_PlayEverquestResponse=0x0023\n");
|
||||
fprintf(f, "OP_ChatMessage=0x0018\n");
|
||||
fprintf(f, "OP_LoginAccepted=0x0019\n");
|
||||
fprintf(f, "OP_ServerListResponse=0x001a\n");
|
||||
fprintf(f, "OP_Poll=0x002a\n");
|
||||
fprintf(f, "OP_EnterChat=0x000f\n");
|
||||
fprintf(f, "OP_PollResponse=0x0011\n");
|
||||
fprintf(f, "OP_SystemFingerprint=0x0016\n");
|
||||
fprintf(f, "OP_ExpansionList=0x0030\n");
|
||||
fprintf(f, "OP_ExpansionList=0x0031\n");
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
@@ -177,40 +177,40 @@ ClientManager::ClientManager()
|
||||
}
|
||||
);
|
||||
|
||||
int larion_port = server.config.GetVariableInt("client_configuration", "larion_port", 15900);
|
||||
int tob_port = server.config.GetVariableInt("client_configuration", "tob_port", 15900);
|
||||
|
||||
EQStreamManagerInterfaceOptions larion_opts(larion_port, false, false);
|
||||
EQStreamManagerInterfaceOptions tob_opts(tob_port, false, false);
|
||||
|
||||
m_larion_stream = new EQ::Net::EQStreamManager(larion_opts);
|
||||
m_larion_ops = new RegularOpcodeManager;
|
||||
m_tob_stream = new EQ::Net::EQStreamManager(tob_opts);
|
||||
m_tob_ops = new RegularOpcodeManager;
|
||||
|
||||
opcodes_path = fmt::format(
|
||||
"{}/{}",
|
||||
PathManager::Instance()->GetOpcodePath(),
|
||||
"login_opcodes_larion.conf"
|
||||
"login_opcodes_tob.conf"
|
||||
);
|
||||
|
||||
CheckLarionOpcodeFile(opcodes_path);
|
||||
CheckTOBOpcodeFile(opcodes_path);
|
||||
|
||||
if (!m_larion_ops->LoadOpcodes(opcodes_path.c_str())) {
|
||||
if (!m_tob_ops->LoadOpcodes(opcodes_path.c_str())) {
|
||||
LogError(
|
||||
"ClientManager fatal error: couldn't load opcodes for Larion file [{}]",
|
||||
server.config.GetVariableString("client_configuration", "larion_opcodes", "login_opcodes.conf")
|
||||
"ClientManager fatal error: couldn't load opcodes for TOB file [{}]",
|
||||
server.config.GetVariableString("client_configuration", "tob_opcodes", "login_opcodes.conf")
|
||||
);
|
||||
|
||||
run_server = false;
|
||||
}
|
||||
|
||||
m_larion_stream->OnNewConnection(
|
||||
m_tob_stream->OnNewConnection(
|
||||
[this](std::shared_ptr<EQ::Net::EQStream> stream) {
|
||||
LogInfo(
|
||||
"New Larion client connection from [{}:{}]",
|
||||
"New TOB client connection from [{}:{}]",
|
||||
long2ip(stream->GetRemoteIP()),
|
||||
stream->GetRemotePort()
|
||||
);
|
||||
|
||||
stream->SetOpcodeManager(&m_larion_ops);
|
||||
Client *c = new Client(stream, cv_larion);
|
||||
stream->SetOpcodeManager(&m_tob_ops);
|
||||
Client *c = new Client(stream, cv_tob);
|
||||
m_clients.push_back(c);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -37,6 +37,6 @@ private:
|
||||
EQ::Net::EQStreamManager *m_titanium_stream;
|
||||
OpcodeManager *m_sod_ops;
|
||||
EQ::Net::EQStreamManager *m_sod_stream;
|
||||
OpcodeManager *m_larion_ops;
|
||||
EQ::Net::EQStreamManager *m_larion_stream;
|
||||
OpcodeManager *m_tob_ops;
|
||||
EQ::Net::EQStreamManager *m_tob_stream;
|
||||
};
|
||||
|
||||
+28
-114
@@ -16,12 +16,11 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "encryption.h"
|
||||
#include "common/compiler_macros.h"
|
||||
|
||||
#ifdef EQEMU_USE_OPENSSL
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/provider.h>
|
||||
#include <openssl/des.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/md5.h>
|
||||
#endif
|
||||
#ifdef EQEMU_USE_MBEDTLS
|
||||
#include <mbedtls/des.h>
|
||||
@@ -33,8 +32,6 @@
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#ifdef ENABLE_SECURITY
|
||||
|
||||
#include <sodium.h>
|
||||
@@ -130,104 +127,21 @@ const char *eqcrypt_block(const char *buffer_in, size_t buffer_in_sz, char *buff
|
||||
#endif
|
||||
|
||||
#ifdef EQEMU_USE_OPENSSL
|
||||
// Decrypt requires block-aligned input; encrypt zero-pads a trailing
|
||||
// partial block to match the legacy DES_ncbc_encrypt semantics the
|
||||
// game protocol expects.
|
||||
DES_key_schedule k;
|
||||
DES_cblock v;
|
||||
|
||||
memset(&k, 0, sizeof(DES_key_schedule));
|
||||
memset(&v, 0, sizeof(DES_cblock));
|
||||
|
||||
if (!enc && buffer_in_sz && buffer_in_sz % 8 != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned char key[8] = {0};
|
||||
unsigned char iv[8] = {0};
|
||||
|
||||
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
|
||||
if (!ctx) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool result = EVP_CipherInit_ex2(ctx, EVP_des_cbc(), key, iv, enc, nullptr) == 1;
|
||||
if (result) {
|
||||
EVP_CIPHER_CTX_set_padding(ctx, 0);
|
||||
|
||||
const unsigned char* src = reinterpret_cast<const unsigned char*>(buffer_in);
|
||||
size_t src_len = buffer_in_sz;
|
||||
std::unique_ptr<unsigned char[]> padded;
|
||||
|
||||
if (enc && buffer_in_sz % 8 != 0) {
|
||||
src_len = ((buffer_in_sz / 8) + 1) * 8;
|
||||
padded.reset(new unsigned char[src_len]());
|
||||
memcpy(padded.get(), buffer_in, buffer_in_sz);
|
||||
src = padded.get();
|
||||
}
|
||||
|
||||
int outl = 0;
|
||||
int final_len = 0;
|
||||
result = EVP_CipherUpdate(ctx, reinterpret_cast<unsigned char*>(buffer_out), &outl, src, static_cast<int>(src_len)) == 1
|
||||
&& EVP_CipherFinal_ex(ctx, reinterpret_cast<unsigned char*>(buffer_out) + outl, &final_len) == 1;
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
if (!result) {
|
||||
return nullptr;
|
||||
}
|
||||
DES_ncbc_encrypt((const unsigned char*)buffer_in, (unsigned char*)buffer_out, (long)buffer_in_sz, &k, &v, enc);
|
||||
#endif
|
||||
return buffer_out;
|
||||
}
|
||||
|
||||
#ifdef EQEMU_USE_OPENSSL
|
||||
static OSSL_PROVIDER *s_legacy_provider = nullptr;
|
||||
static OSSL_PROVIDER *s_default_provider = nullptr;
|
||||
#endif
|
||||
|
||||
bool eqcrypt_init()
|
||||
{
|
||||
#ifdef EQEMU_USE_OPENSSL
|
||||
#ifdef _WIN32
|
||||
// Set OpenSSL default provider search path to the executable directory.
|
||||
char* exe_path = nullptr;
|
||||
if (_get_pgmptr(&exe_path) == 0 && exe_path != nullptr && *exe_path != '\0') {
|
||||
std::string exe_dir{exe_path};
|
||||
if (auto sep = exe_dir.find_last_of("\\/"); sep != std::string::npos) {
|
||||
exe_dir.resize(sep);
|
||||
OSSL_PROVIDER_set_default_search_path(nullptr, exe_dir.c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!s_default_provider) {
|
||||
s_default_provider = OSSL_PROVIDER_load(nullptr, "default");
|
||||
}
|
||||
if (!s_legacy_provider) {
|
||||
s_legacy_provider = OSSL_PROVIDER_load(nullptr, "legacy");
|
||||
}
|
||||
|
||||
if (!s_default_provider || !s_legacy_provider) {
|
||||
char buf[256];
|
||||
while (auto err = ERR_get_error()) {
|
||||
ERR_error_string_n(err, buf, sizeof(buf));
|
||||
LogError("OpenSSL provider load failure: {}", buf);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void eqcrypt_shutdown()
|
||||
{
|
||||
#ifdef EQEMU_USE_OPENSSL
|
||||
if (s_legacy_provider) {
|
||||
OSSL_PROVIDER_unload(s_legacy_provider);
|
||||
s_legacy_provider = nullptr;
|
||||
}
|
||||
if (s_default_provider) {
|
||||
OSSL_PROVIDER_unload(s_default_provider);
|
||||
s_default_provider = nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string eqcrypt_md5(const std::string &msg)
|
||||
{
|
||||
std::string ret;
|
||||
@@ -250,12 +164,12 @@ std::string eqcrypt_md5(const std::string &msg)
|
||||
unsigned char md5_digest[16];
|
||||
char tmp[4];
|
||||
|
||||
if (EVP_Digest(msg.data(), msg.length(), md5_digest, nullptr, EVP_md5(), nullptr) == 1) {
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
sprintf(&tmp[0], "%02x", md5_digest[i]);
|
||||
ret.push_back(tmp[0]);
|
||||
ret.push_back(tmp[1]);
|
||||
}
|
||||
MD5((const unsigned char*)msg.c_str(), msg.length(), md5_digest);
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
sprintf(&tmp[0], "%02x", md5_digest[i]);
|
||||
ret.push_back(tmp[0]);
|
||||
ret.push_back(tmp[1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -284,12 +198,12 @@ std::string eqcrypt_sha1(const std::string &msg)
|
||||
unsigned char sha_digest[20];
|
||||
char tmp[4];
|
||||
|
||||
if (EVP_Digest(msg.data(), msg.length(), sha_digest, nullptr, EVP_sha1(), nullptr) == 1) {
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
sprintf(&tmp[0], "%02x", sha_digest[i]);
|
||||
ret.push_back(tmp[0]);
|
||||
ret.push_back(tmp[1]);
|
||||
}
|
||||
SHA1((const unsigned char*)msg.c_str(), msg.length(), sha_digest);
|
||||
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
sprintf(&tmp[0], "%02x", sha_digest[i]);
|
||||
ret.push_back(tmp[0]);
|
||||
ret.push_back(tmp[1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -318,12 +232,12 @@ std::string eqcrypt_sha512(const std::string &msg)
|
||||
unsigned char sha_digest[64];
|
||||
char tmp[4];
|
||||
|
||||
if (EVP_Digest(msg.data(), msg.length(), sha_digest, nullptr, EVP_sha512(), nullptr) == 1) {
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
sprintf(&tmp[0], "%02x", sha_digest[i]);
|
||||
ret.push_back(tmp[0]);
|
||||
ret.push_back(tmp[1]);
|
||||
}
|
||||
SHA512((const unsigned char*)msg.c_str(), msg.length(), sha_digest);
|
||||
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
sprintf(&tmp[0], "%02x", sha_digest[i]);
|
||||
ret.push_back(tmp[0]);
|
||||
ret.push_back(tmp[1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -48,20 +48,10 @@ namespace CryptoHash {
|
||||
}
|
||||
|
||||
std::string GetEncryptionByModeId(uint32 mode);
|
||||
|
||||
// DES-CBC with an all-zero key and IV (EQ login protocol obfuscation, not security).
|
||||
// On encrypt, a trailing partial block is zero-padded to the next 8-byte boundary, so
|
||||
// buffer_out must be at least ((buffer_in_sz + 7) / 8) * 8 bytes. On decrypt, buffer_in_sz
|
||||
// must already be a multiple of 8 or the call returns nullptr.
|
||||
const char *eqcrypt_block(const char *buffer_in, size_t buffer_in_sz, char *buffer_out, bool enc);
|
||||
std::string eqcrypt_hash(const std::string &username, const std::string &password, int mode);
|
||||
bool eqcrypt_verify_hash(const std::string &username, const std::string &password, const std::string &pwhash, int mode);
|
||||
|
||||
// OpenSSL 3.0 moved DES behind the "legacy" provider; these load/unload it
|
||||
// for the lifetime of the process. No-op when built against mbedtls.
|
||||
bool eqcrypt_init();
|
||||
void eqcrypt_shutdown();
|
||||
|
||||
struct EncryptionResult {
|
||||
std::string password;
|
||||
int mode = 0;
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "common/types.h"
|
||||
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
@@ -45,7 +46,7 @@ struct LoginHandShakeReply {
|
||||
};
|
||||
|
||||
// variable length, can use directly if not serializing strings
|
||||
struct PlayerLoginReply {
|
||||
struct PlayerLoginReplyOld {
|
||||
// base header excluded to make struct data easier to encrypt
|
||||
//LoginBaseMessage base_header;
|
||||
LoginBaseReplyMessage base_reply;
|
||||
@@ -61,10 +62,90 @@ struct PlayerLoginReply {
|
||||
int32_t offer_cooldown_minutes; // guess (default: 0)
|
||||
int32_t web_offer_number; // web order view number, 0 nothing (default: 0)
|
||||
int32_t web_offer_min_days; // number of days to show offer (based on first offer time in client eqls ini) (default: 99)
|
||||
int32_t web_offer_min_views; // mininum views, -1 for no minimum, 0 for never shows (based on client eqls ini) (default: -1)
|
||||
int32_t web_offer_min_views; // minimum views, -1 for no minimum, 0 for never shows (based on client eqls ini) (default: -1)
|
||||
int32_t web_offer_cooldown_minutes; // minimum minutes between offers (based on last offer time in client eqls ini) (default: 0)
|
||||
char username[1]; // variable length, if not empty client attempts to re-login to server select when quitting from char select and sends this in a struct
|
||||
char unknown[1]; // variable length, password unlikely? client doesn't send this on re-login from char select
|
||||
|
||||
void set_success(bool v) { base_reply.success = v; }
|
||||
void set_error_code(int32_t v) { base_reply.error_str_id = v; }
|
||||
void set_lsid(int32_t v) { lsid = v; }
|
||||
void set_show_player_count(bool v) { show_player_count = v; }
|
||||
void set_hardcoded_success_values() {
|
||||
offer_min_days = 99;
|
||||
offer_min_views = -1;
|
||||
web_offer_min_days = 99;
|
||||
web_offer_min_views = -1;
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(PlayerLoginReplyOld) == 58, "PlayerLoginReplyOld struct size does not match expected size");
|
||||
static_assert(std::is_trivially_copyable_v<PlayerLoginReplyOld>);
|
||||
static_assert(std::is_standard_layout_v<PlayerLoginReplyOld>);
|
||||
|
||||
struct PlayerLoginReplyTOB {
|
||||
LoginBaseReplyMessage base_reply;
|
||||
|
||||
int8_t unk1 = 0;
|
||||
int8_t unk2 = 0;
|
||||
int32_t lsid = -1;
|
||||
char key[11] = {};
|
||||
int32_t failed_attempts = 0;
|
||||
int32_t display_error_str_id = 0;
|
||||
int32_t unk3 = 0;
|
||||
bool show_player_count = false;
|
||||
char username[1] = {};
|
||||
char unk4[1] = {};
|
||||
|
||||
void set_success(bool v) { base_reply.success = v; }
|
||||
void set_error_code(int32_t v) { display_error_str_id = v; base_reply.error_str_id = v; }
|
||||
void set_lsid(int32_t v) { lsid = v; }
|
||||
void set_show_player_count(bool v) { show_player_count = v; }
|
||||
void set_hardcoded_success_values() {}
|
||||
};
|
||||
static_assert(sizeof(PlayerLoginReplyTOB) == 38, "PlayerLoginReplyTOB struct size does not match expected size");
|
||||
static_assert(std::is_trivially_copyable_v<PlayerLoginReplyTOB>);
|
||||
static_assert(std::is_standard_layout_v<PlayerLoginReplyTOB>);
|
||||
|
||||
class PlayerLoginReply {
|
||||
std::variant<PlayerLoginReplyOld, PlayerLoginReplyTOB> v_;
|
||||
static_assert(sizeof(PlayerLoginReplyOld::key) == sizeof(PlayerLoginReplyTOB::key), "Old and TOB key buffers must match in size due to code assumptions");
|
||||
public:
|
||||
PlayerLoginReply(PlayerLoginReplyOld s) : v_(s) {}
|
||||
PlayerLoginReply(PlayerLoginReplyTOB s) : v_(s) {}
|
||||
|
||||
void set_success(bool val) {
|
||||
std::visit([val](auto& s) { s.set_success(val); }, v_);
|
||||
}
|
||||
void set_error_code(int32_t val) {
|
||||
std::visit([val](auto& s) { s.set_error_code(val); }, v_);
|
||||
}
|
||||
void set_lsid(int32_t val) {
|
||||
std::visit([val](auto& s) { s.set_lsid(val); }, v_);
|
||||
}
|
||||
void set_show_player_count(bool val) {
|
||||
std::visit([val](auto& s) { s.set_show_player_count(val); }, v_);
|
||||
}
|
||||
void set_key(std::string_view s) {
|
||||
std::visit([&](auto& st) {
|
||||
const size_t n = s.copy(st.key, sizeof(st.key) - 1);
|
||||
st.key[n] = '\0';
|
||||
}, v_);
|
||||
}
|
||||
template<size_t N>
|
||||
void set_key(const char (&s)[N]) {
|
||||
static_assert(N != (sizeof(PlayerLoginReplyTOB::key) - 1), "Key literal does not match reply struct's key buffer (without null terminator)");
|
||||
set_key(std::string_view{s, N - 1});
|
||||
}
|
||||
|
||||
PlayerLoginReplyOld& old() { return std::get<PlayerLoginReplyOld>(v_); }
|
||||
const PlayerLoginReplyOld& old() const { return std::get<PlayerLoginReplyOld>(v_); }
|
||||
|
||||
char* data() noexcept {
|
||||
return std::visit([](auto& s) { return reinterpret_cast<char*>(&s); }, v_);
|
||||
}
|
||||
size_t size() const noexcept {
|
||||
return std::visit([](auto const& s) { return sizeof(s); }, v_);
|
||||
}
|
||||
};
|
||||
|
||||
// variable length, for reference
|
||||
@@ -100,12 +181,18 @@ struct PlayEverquestResponse {
|
||||
uint32 server_number;
|
||||
};
|
||||
|
||||
//for reference
|
||||
struct SystemFingerprint {
|
||||
LoginBaseMessage base_header;
|
||||
char fingerprint[1];
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
enum LSClientVersion {
|
||||
cv_titanium,
|
||||
cv_sod,
|
||||
cv_larion
|
||||
cv_tob
|
||||
};
|
||||
|
||||
enum LSClientStatus {
|
||||
@@ -174,11 +261,14 @@ namespace LS {
|
||||
namespace ErrStr {
|
||||
constexpr static int ERROR_NONE = 101; // No Error
|
||||
constexpr static int ERROR_UNKNOWN = 102; // Error - Unknown Error Occurred
|
||||
constexpr static int ERROR_INVALID_CREDS = 105; // Error - Invalid Account Name or Password
|
||||
constexpr static int ERROR_ACTIVE_CHARACTER = 111; // Error 1018: You currently have an active character on that EverQuest Server, please allow a minute for synchronization and try again.
|
||||
constexpr static int ERROR_PASSWORD_RESET = 112; // Require password reset
|
||||
constexpr static int ERROR_SERVER_UNAVAILABLE = 326; // That server is currently unavailable. Please check the EverQuest webpage for current server status and try again later.
|
||||
constexpr static int ERROR_ACCOUNT_SUSPENDED = 337; // This account is currently suspended. Please contact customer service for more information.
|
||||
constexpr static int ERROR_ACCOUNT_BANNED = 338; // This account is currently banned. Please contact customer service for more information.
|
||||
constexpr static int ERROR_WORLD_MAX_CAPACITY = 339; // The world server is currently at maximum capacity and not allowing further logins until the number of players online decreases. Please try again later.
|
||||
constexpr static int ERROR_REQUIRE_2FA = 342; // This account requires two-factor authentication.
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+6
-6
@@ -3,12 +3,12 @@ OP_SessionReady=0x0001
|
||||
OP_Login=0x0002
|
||||
OP_ServerListRequest=0x0004
|
||||
OP_PlayEverquestRequest=0x000d
|
||||
OP_PlayEverquestResponse=0x0022
|
||||
OP_ChatMessage=0x0017
|
||||
OP_LoginAccepted=0x0018
|
||||
OP_ServerListResponse=0x0019
|
||||
OP_Poll=0x0029
|
||||
OP_PlayEverquestResponse=0x0023
|
||||
OP_ChatMessage=0x0018
|
||||
OP_LoginAccepted=0x0019
|
||||
OP_ServerListResponse=0x001a
|
||||
OP_Poll=0x002a
|
||||
OP_EnterChat=0x000f
|
||||
OP_PollResponse=0x0011
|
||||
OP_SystemFingerprint=0x0016
|
||||
OP_ExpansionList=0x0030
|
||||
OP_ExpansionList=0x0031
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "common/platform.h"
|
||||
#include "common/timer.h"
|
||||
#include "common/types.h"
|
||||
#include "loginserver/encryption.h"
|
||||
#include "loginserver/login_server.h"
|
||||
#include "loginserver/loginserver_command_handler.h"
|
||||
#include "loginserver/loginserver_webserver.h"
|
||||
@@ -159,12 +158,12 @@ void start_web_server()
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
RegisterExecutablePlatform(ExePlatformLogin);
|
||||
EQEmuLogSys::Instance()->LoadLogSettingsDefaults();
|
||||
set_exception_handler();
|
||||
|
||||
if (!eqcrypt_init()) {
|
||||
LogError("Failed to initialize crypto providers");
|
||||
return 1;
|
||||
LogInfo("Logging System Init");
|
||||
|
||||
if (argc == 1) {
|
||||
EQEmuLogSys::Instance()->LoadLogSettingsDefaults();
|
||||
}
|
||||
|
||||
PathManager::Instance()->Init();
|
||||
@@ -281,7 +280,5 @@ int main(int argc, char **argv)
|
||||
LogInfo("Server Manager Shutdown");
|
||||
delete server.server_manager;
|
||||
|
||||
eqcrypt_shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -706,19 +706,17 @@ bool WorldServer::ValidateWorldServerAdminLogin(
|
||||
|
||||
void WorldServer::SerializeForClientServerList(SerializeBuffer &out, bool use_local_ip, LSClientVersion version) const
|
||||
{
|
||||
// see LoginClientServerData_Struct
|
||||
if (use_local_ip) {
|
||||
out.WriteString(GetLocalIP());
|
||||
}
|
||||
else {
|
||||
out.WriteString(m_remote_ip_address);
|
||||
}
|
||||
if (version == cv_tob) {
|
||||
if (use_local_ip) {
|
||||
out.WriteString(GetLocalIP());
|
||||
}
|
||||
else {
|
||||
out.WriteString(m_remote_ip_address);
|
||||
}
|
||||
|
||||
if (version == cv_larion) {
|
||||
out.WriteUInt32(9000);
|
||||
}
|
||||
out.WriteInt32(9000); // port, not currently settable in eqemu but needed for compat
|
||||
|
||||
switch (GetServerListID()) {
|
||||
switch (GetServerListID()) {
|
||||
case LS::ServerType::Legends:
|
||||
out.WriteInt32(LS::ServerTypeFlags::Legends);
|
||||
break;
|
||||
@@ -728,35 +726,74 @@ void WorldServer::SerializeForClientServerList(SerializeBuffer &out, bool use_lo
|
||||
default:
|
||||
out.WriteInt32(LS::ServerTypeFlags::Standard);
|
||||
break;
|
||||
}
|
||||
if (version == cv_larion) {
|
||||
auto server_id = m_server_id;
|
||||
//if this is 0, the client will not show the server in the list
|
||||
out.WriteUInt32(1);
|
||||
out.WriteUInt32(server_id);
|
||||
}
|
||||
else {
|
||||
}
|
||||
|
||||
out.WriteInt32(289); //unsure what this is yet
|
||||
out.WriteUInt32(m_server_id);
|
||||
}
|
||||
|
||||
out.WriteString(m_server_long_name);
|
||||
out.WriteString("us"); // country code
|
||||
out.WriteString("en"); // language code
|
||||
out.WriteString(m_server_long_name);
|
||||
out.WriteString("US"); // country code
|
||||
out.WriteString("EN"); // language code
|
||||
out.WriteString("Standard");
|
||||
out.WriteString("This server has no description set currently.");
|
||||
|
||||
// 0 = Up, 1 = Down, 2 = Up, 3 = down, 4 = locked, 5 = locked(down)
|
||||
if (GetStatus() < 0) {
|
||||
if (GetZonesBooted() == 0) {
|
||||
out.WriteInt32(LS::ServerStatusFlags::Down);
|
||||
if (GetStatus() < 0) {
|
||||
if (GetZonesBooted() == 0) {
|
||||
out.WriteInt32(LS::ServerStatusFlags::Down);
|
||||
}
|
||||
else {
|
||||
out.WriteInt32(LS::ServerStatusFlags::Locked);
|
||||
}
|
||||
}
|
||||
else {
|
||||
out.WriteInt32(LS::ServerStatusFlags::Locked);
|
||||
out.WriteInt32(LS::ServerStatusFlags::Up);
|
||||
}
|
||||
|
||||
out.WriteUInt32(GetPlayersOnline());
|
||||
out.WriteInt32(31); //expansions
|
||||
out.WriteInt32(0); //truebox
|
||||
}
|
||||
else {
|
||||
out.WriteInt32(LS::ServerStatusFlags::Up);
|
||||
}
|
||||
// see LoginClientServerData_Struct
|
||||
if (use_local_ip) {
|
||||
out.WriteString(GetLocalIP());
|
||||
}
|
||||
else {
|
||||
out.WriteString(m_remote_ip_address);
|
||||
}
|
||||
|
||||
switch (GetServerListID()) {
|
||||
case LS::ServerType::Legends:
|
||||
out.WriteInt32(LS::ServerTypeFlags::Legends);
|
||||
break;
|
||||
case LS::ServerType::Preferred:
|
||||
out.WriteInt32(LS::ServerTypeFlags::Preferred);
|
||||
break;
|
||||
default:
|
||||
out.WriteInt32(LS::ServerTypeFlags::Standard);
|
||||
break;
|
||||
}
|
||||
|
||||
out.WriteUInt32(GetPlayersOnline());
|
||||
out.WriteUInt32(m_server_id);
|
||||
out.WriteString(m_server_long_name);
|
||||
out.WriteString("us"); // country code
|
||||
out.WriteString("en"); // language code
|
||||
|
||||
// 0 = Up, 1 = Down, 2 = Up, 3 = down, 4 = locked, 5 = locked(down)
|
||||
if (GetStatus() < 0) {
|
||||
if (GetZonesBooted() == 0) {
|
||||
out.WriteInt32(LS::ServerStatusFlags::Down);
|
||||
}
|
||||
else {
|
||||
out.WriteInt32(LS::ServerStatusFlags::Locked);
|
||||
}
|
||||
}
|
||||
else {
|
||||
out.WriteInt32(LS::ServerStatusFlags::Up);
|
||||
}
|
||||
|
||||
out.WriteUInt32(GetPlayersOnline());
|
||||
}
|
||||
}
|
||||
|
||||
void WorldServer::FormatWorldServerName(char *name, int8 server_list_type)
|
||||
|
||||
+636
@@ -0,0 +1,636 @@
|
||||
### Status
|
||||
Below is a status list for the 450 opcodes we currently use on the server for the TOB client. Currently uses 3 status levels (let me know if we should do more):
|
||||
- 🔴 Not-Set (Opcode not set in the patch file)
|
||||
- 🟡 Unverified (Opcode set but structure hasn't been verified as completely working)
|
||||
- 🟢 Verified (Opcode set and structure is working)
|
||||
|
||||
### World/Zone Opcode Implementation Status
|
||||
|
||||
| Opcode | Status | Notes | Working On |
|
||||
|:----------------------------------|:--------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------|
|
||||
| `OP_AAAction` | 🟡 Unverified | | |
|
||||
| `OP_AAExpUpdate` | 🟢 Verified | | |
|
||||
| `OP_AcceptNewTask` | 🔴 Not-Set | | |
|
||||
| `OP_AckPacket` | 🟢 Verified | | |
|
||||
| `OP_Action` | 🟡 Unverified | | |
|
||||
| `OP_Action2` | 🔴 Not-Set | | |
|
||||
| `OP_AddNimbusEffect` | 🟡 Unverified | | |
|
||||
| `OP_AdventureData` | 🔴 Not-Set | | |
|
||||
| `OP_AdventureDetails` | 🔴 Not-Set | | |
|
||||
| `OP_AdventureFinish` | 🔴 Not-Set | | |
|
||||
| `OP_AdventureInfo` | 🔴 Not-Set | | |
|
||||
| `OP_AdventureInfoRequest` | 🔴 Not-Set | | |
|
||||
| `OP_AdventureLeaderboardReply` | 🔴 Not-Set | | |
|
||||
| `OP_AdventureLeaderboardRequest` | 🔴 Not-Set | | |
|
||||
| `OP_AdventureMerchantPurchase` | 🔴 Not-Set | | |
|
||||
| `OP_AdventureMerchantRequest` | 🔴 Not-Set | | |
|
||||
| `OP_AdventureMerchantResponse` | 🔴 Not-Set | | |
|
||||
| `OP_AdventureMerchantSell` | 🔴 Not-Set | | |
|
||||
| `OP_AdventurePointsUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_AdventureRequest` | 🔴 Not-Set | | |
|
||||
| `OP_AdventureStatsReply` | 🔴 Not-Set | | |
|
||||
| `OP_AdventureStatsRequest` | 🔴 Not-Set | | |
|
||||
| `OP_AdventureUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_AggroMeterLockTarget` | 🔴 Not-Set | | |
|
||||
| `OP_AggroMeterTargetInfo` | 🔴 Not-Set | | |
|
||||
| `OP_AggroMeterUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_AltCurrency` | 🔴 Not-Set | | |
|
||||
| `OP_AltCurrencyMerchantReply` | 🔴 Not-Set | | |
|
||||
| `OP_AltCurrencyMerchantRequest` | 🔴 Not-Set | | |
|
||||
| `OP_AltCurrencyPurchase` | 🔴 Not-Set | | |
|
||||
| `OP_AltCurrencyReclaim` | 🔴 Not-Set | | |
|
||||
| `OP_AltCurrencySell` | 🔴 Not-Set | | |
|
||||
| `OP_AltCurrencySellSelection` | 🔴 Not-Set | | |
|
||||
| `OP_Animation` | 🟡 Unverified | | |
|
||||
| `OP_AnnoyingZoneUnknown` | 🔴 Not-Set | | |
|
||||
| `OP_ApplyPoison` | 🟡 Unverified | | |
|
||||
| `OP_ApproveName` | 🟡 Unverified | This takes multiple parameters from the client, and it can take multiple integer values from the server | |
|
||||
| `OP_ApproveWorld` | 🔴 Not-Set | | |
|
||||
| `OP_ApproveZone` | 🔴 Not-Set | | |
|
||||
| `OP_Assist` | 🟡 Unverified | | |
|
||||
| `OP_AssistGroup` | 🟡 Unverified | | |
|
||||
| `OP_AugmentInfo` | 🟡 Unverified | | |
|
||||
| `OP_AugmentItem` | 🟡 Unverified | | |
|
||||
| `OP_AutoAttack` | 🟡 Unverified | | |
|
||||
| `OP_AutoAttack2` | 🟡 Unverified | | |
|
||||
| `OP_AutoFire` | 🟡 Unverified | | |
|
||||
| `OP_Bandolier` | 🔴 Not-Set | | |
|
||||
| `OP_BankerChange` | 🟡 Unverified | | |
|
||||
| `OP_Barter` | 🔴 Not-Set | | |
|
||||
| `OP_Bazaar` | 🔴 Not-Set | | |
|
||||
| `OP_BazaarInspect` | 🔴 Not-Set | | |
|
||||
| `OP_BazaarSearch` | 🔴 Not-Set | | |
|
||||
| `OP_BecomeCorpse` | 🔴 Not-Set | | |
|
||||
| `OP_BecomeTrader` | 🔴 Not-Set | | |
|
||||
| `OP_Begging` | 🟡 Unverified | | |
|
||||
| `OP_BeginCast` | 🟢 Verified | | |
|
||||
| `OP_Bind_Wound` | 🟡 Unverified | | |
|
||||
| `OP_BlockedBuffs` | 🟢 Verified | | |
|
||||
| `OP_BoardBoat` | 🟡 Unverified | | |
|
||||
| `OP_BookButton` | 🟡 Unverified | | |
|
||||
| `OP_Buff` | 🟡 Unverified | | |
|
||||
| `OP_BuffCreate` | 🟡 Unverified | | |
|
||||
| `OP_BuffRemoveRequest` | 🟡 Unverified | | |
|
||||
| `OP_Bug` | 🟡 Unverified | | |
|
||||
| `OP_BuyerItems` | 🔴 Not-Set | | |
|
||||
| `OP_CameraEffect` | 🟡 Unverified | | |
|
||||
| `OP_Camp` | 🟡 Unverified | | |
|
||||
| `OP_CancelSneakHide` | 🟡 Unverified | | |
|
||||
| `OP_CancelTask` | 🔴 Not-Set | | |
|
||||
| `OP_CancelTrade` | 🟡 Unverified | | |
|
||||
| `OP_CashReward` | 🟡 Unverified | | |
|
||||
| `OP_CastSpell` | 🟢 Verified | | |
|
||||
| `OP_ChangeSize` | 🟢 Verified | | |
|
||||
| `OP_ChannelMessage` | 🟢 Verified | | |
|
||||
| `OP_ChangePetName` | 🔴 Not-Set | | |
|
||||
| `OP_CharacterCreate` | 🟢 Verified | Sends heroic type, can be used for something? | |
|
||||
| `OP_CharacterCreateRequest` | 🟢 Verified | | |
|
||||
| `OP_CharInventory` | 🟢 Verified | | |
|
||||
| `OP_Charm` | 🟡 Unverified | | |
|
||||
| `OP_ChatMessage` | 🔴 Not-Set | | |
|
||||
| `OP_ClearAA` | 🟢 Verified | | |
|
||||
| `OP_ClearBlockedBuffs` | 🟢 Verified | | |
|
||||
| `OP_ClearLeadershipAbilities` | 🔴 Not-Set | | |
|
||||
| `OP_ClearNPCMarks` | 🔴 Not-Set | | |
|
||||
| `OP_ClearObject` | 🟡 Unverified | | |
|
||||
| `OP_ClearSurname` | 🔴 Not-Set | | |
|
||||
| `OP_ClickDoor` | 🟡 Unverified | | |
|
||||
| `OP_ClickObject` | 🟡 Unverified | | |
|
||||
| `OP_ClickObjectAction` | 🟡 Unverified | | |
|
||||
| `OP_ClientError` | 🔴 Not-Set | | |
|
||||
| `OP_ClientReady` | 🟢 Verified | | |
|
||||
| `OP_ClientTimeStamp` | 🔴 Not-Set | | |
|
||||
| `OP_ClientUpdate` | 🟢 Verified | | |
|
||||
| `OP_CloseContainer` | 🔴 Not-Set | | |
|
||||
| `OP_CloseTributeMaster` | 🔴 Not-Set | | |
|
||||
| `OP_ColoredText` | 🟢 Verified | | |
|
||||
| `OP_CombatAbility` | 🟡 Unverified | | |
|
||||
| `OP_Command` | 🔴 Not-Set | | |
|
||||
| `OP_CompletedTasks` | 🔴 Not-Set | | |
|
||||
| `OP_ConfirmDelete` | 🟡 Unverified | | |
|
||||
| `OP_Consent` | 🟡 Unverified | | |
|
||||
| `OP_ConsentDeny` | 🟡 Unverified | | |
|
||||
| `OP_ConsentResponse` | 🟢 Verified | | |
|
||||
| `OP_Consider` | 🟢 Verified | | |
|
||||
| `OP_ConsiderCorpse` | 🟡 Unverified | | |
|
||||
| `OP_Consume` | 🟡 Unverified | | |
|
||||
| `OP_ControlBoat` | 🟡 Unverified | | |
|
||||
| `OP_CorpseDrag` | 🟡 Unverified | | |
|
||||
| `OP_CorpseDrop` | 🟡 Unverified | | |
|
||||
| `OP_CrashDump` | 🔴 Not-Set | | |
|
||||
| `OP_CrystalCountUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_CrystalCreate` | 🔴 Not-Set | | |
|
||||
| `OP_CrystalReclaim` | 🔴 Not-Set | | |
|
||||
| `OP_CustomTitles` | 🔴 Not-Set | | |
|
||||
| `OP_Damage` | 🟡 Unverified | | |
|
||||
| `OP_Death` | 🟡 Unverified | | |
|
||||
| `OP_DelegateAbility` | 🔴 Not-Set | | |
|
||||
| `OP_DeleteCharacter` | 🟢 Verified | | |
|
||||
| `OP_DeleteCharge` | 🟡 Unverified | | |
|
||||
| `OP_DeleteItem` | 🟡 Unverified | | |
|
||||
| `OP_DeletePetition` | 🔴 Not-Set | | |
|
||||
| `OP_DeleteSpawn` | 🟡 Unverified | | |
|
||||
| `OP_DeleteSpell` | 🟡 Unverified | | |
|
||||
| `OP_DenyResponse` | 🟡 Unverified | | |
|
||||
| `OP_Disarm` | 🟡 Unverified | | |
|
||||
| `OP_DisarmTraps` | 🟡 Unverified | | |
|
||||
| `OP_DisciplineTimer` | 🟡 Unverified | | |
|
||||
| `OP_DisciplineUpdate` | 🟡 Unverified | | |
|
||||
| `OP_DiscordMerchantInventory` | 🔴 Not-Set | | |
|
||||
| `OP_DoGroupLeadershipAbility` | 🔴 Not-Set | | |
|
||||
| `OP_DuelDecline` | 🔴 Not-Set | | |
|
||||
| `OP_DuelAccept` | 🔴 Not-Set | | |
|
||||
| `OP_DumpName` | 🔴 Not-Set | | |
|
||||
| `OP_Dye` | 🔴 Not-Set | | |
|
||||
| `OP_DynamicWall` | 🔴 Not-Set | | |
|
||||
| `OP_DzAddPlayer` | 🔴 Not-Set | | |
|
||||
| `OP_DzChooseZone` | 🔴 Not-Set | | |
|
||||
| `OP_DzChooseZoneReply` | 🔴 Not-Set | | |
|
||||
| `OP_DzCompass` | 🔴 Not-Set | | |
|
||||
| `OP_DzExpeditionEndsWarning` | 🔴 Not-Set | | |
|
||||
| `OP_DzExpeditionInfo` | 🔴 Not-Set | | |
|
||||
| `OP_DzExpeditionInvite` | 🔴 Not-Set | | |
|
||||
| `OP_DzExpeditionInviteResponse` | 🔴 Not-Set | | |
|
||||
| `OP_DzExpeditionLockoutTimers` | 🔴 Not-Set | | |
|
||||
| `OP_DzListTimers` | 🔴 Not-Set | | |
|
||||
| `OP_DzMakeLeader` | 🔴 Not-Set | | |
|
||||
| `OP_DzMemberList` | 🔴 Not-Set | | |
|
||||
| `OP_DzMemberListName` | 🔴 Not-Set | | |
|
||||
| `OP_DzMemberListStatus` | 🔴 Not-Set | | |
|
||||
| `OP_DzPlayerList` | 🔴 Not-Set | | |
|
||||
| `OP_DzQuit` | 🔴 Not-Set | | |
|
||||
| `OP_DzRemovePlayer` | 🔴 Not-Set | | |
|
||||
| `OP_DzSetLeaderName` | 🔴 Not-Set | | |
|
||||
| `OP_DzSwapPlayer` | 🔴 Not-Set | | |
|
||||
| `OP_Emote` | 🔴 Not-Set | | |
|
||||
| `OP_EndLootRequest` | 🟡 Unverified | | |
|
||||
| `OP_EnduranceUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_EnterChat` | 🔴 Not-Set | | |
|
||||
| `OP_EnterWorld` | 🟢 Verified | | |
|
||||
| `OP_EnvDamage` | 🟡 Unverified | | |
|
||||
| `OP_EvolveItem` | 🔴 Not-Set | | |
|
||||
| `OP_ExpansionInfo` | 🟢 Verified | Updated from u32 to u64 and works now | |
|
||||
| `OP_ExpUpdate` | 🟢 Verified | | |
|
||||
| `OP_FaceChange` | 🔴 Not-Set | | |
|
||||
| `OP_Feedback` | 🔴 Not-Set | | |
|
||||
| `OP_FeignDeath` | 🟡 Unverified | | |
|
||||
| `OP_FellowshipUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_FindPersonReply` | 🔴 Not-Set | | |
|
||||
| `OP_FindPersonRequest` | 🔴 Not-Set | | |
|
||||
| `OP_FinishTrade` | 🟡 Unverified | | |
|
||||
| `OP_FinishWindow` | 🟡 Unverified | | |
|
||||
| `OP_FinishWindow2` | 🟡 Unverified | | |
|
||||
| `OP_Fishing` | 🟡 Unverified | | |
|
||||
| `OP_Fling` | 🟡 Unverified | | |
|
||||
| `OP_FloatListThing` | 🟢 Verified | Movement History. Sent from client, but emu doesn't use it so setting it as verified. Reference is 0x1402FFAD0 | |
|
||||
| `OP_Forage` | 🟡 Unverified | | |
|
||||
| `OP_ForceFindPerson` | 🔴 Not-Set | | |
|
||||
| `OP_FormattedMessage` | 🟢 Verified | Some major work to do here -- the client now expects a spell link in the packet, will need to refactor the client work to decouple the stream from the internal representation | |
|
||||
| `OP_FriendsWho` | 🟡 Unverified | | |
|
||||
| `OP_GetGuildMOTD` | 🔴 Not-Set | | |
|
||||
| `OP_GetGuildMOTDReply` | 🔴 Not-Set | | |
|
||||
| `OP_GetGuildsList` | 🔴 Not-Set | | |
|
||||
| `OP_GiveMoney` | 🔴 Not-Set | | |
|
||||
| `OP_GMApproval` | 🔴 Not-Set | | |
|
||||
| `OP_GMBecomeNPC` | 🔴 Not-Set | | |
|
||||
| `OP_GMDelCorpse` | 🔴 Not-Set | | |
|
||||
| `OP_GMEmoteZone` | 🔴 Not-Set | | |
|
||||
| `OP_GMEndTraining` | 🟡 Unverified | | |
|
||||
| `OP_GMEndTrainingResponse` | 🔴 Not-Set | | |
|
||||
| `OP_GMFind` | 🔴 Not-Set | | |
|
||||
| `OP_GMGoto` | 🔴 Not-Set | | |
|
||||
| `OP_GMHideMe` | 🔴 Not-Set | | |
|
||||
| `OP_GMKick` | 🔴 Not-Set | | |
|
||||
| `OP_GMKill` | 🔴 Not-Set | | |
|
||||
| `OP_GMLastName` | 🔴 Not-Set | | |
|
||||
| `OP_GMNameChange` | 🔴 Not-Set | | |
|
||||
| `OP_GMSearchCorpse` | 🔴 Not-Set | | |
|
||||
| `OP_GMServers` | 🔴 Not-Set | | |
|
||||
| `OP_GMSummon` | 🔴 Not-Set | | |
|
||||
| `OP_GMToggle` | 🔴 Not-Set | | |
|
||||
| `OP_GMTraining` | 🟡 Unverified | | |
|
||||
| `OP_GMTrainSkill` | 🟡 Unverified | | |
|
||||
| `OP_GMTrainSkillConfirm` | 🟡 Unverified | | |
|
||||
| `OP_GMZoneRequest` | 🔴 Not-Set | | |
|
||||
| `OP_GMZoneRequest2` | 🔴 Not-Set | | |
|
||||
| `OP_GroundSpawn` | 🟢 Verified | | |
|
||||
| `OP_GroupAcknowledge` | 🔴 Not-Set | | |
|
||||
| `OP_GroupCancelInvite` | 🔴 Not-Set | | |
|
||||
| `OP_GroupDelete` | 🔴 Not-Set | | |
|
||||
| `OP_GroupDisband` | 🟡 Unverified | | |
|
||||
| `OP_GroupDisbandOther` | 🔴 Not-Set | | |
|
||||
| `OP_GroupDisbandYou` | 🔴 Not-Set | | |
|
||||
| `OP_GroupFollow` | 🔴 Not-Set | | |
|
||||
| `OP_GroupFollow2` | 🔴 Not-Set | | |
|
||||
| `OP_GroupInvite` | 🟡 Unverified | | |
|
||||
| `OP_GroupInvite2` | 🔴 Not-Set | | |
|
||||
| `OP_GroupLeaderChange` | 🔴 Not-Set | | |
|
||||
| `OP_GroupLeadershipAAUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_GroupMakeLeader` | 🔴 Not-Set | | |
|
||||
| `OP_GroupMentor` | 🔴 Not-Set | | |
|
||||
| `OP_GroupRoles` | 🔴 Not-Set | | |
|
||||
| `OP_GroupUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_GroupUpdateB` | 🔴 Not-Set | | |
|
||||
| `OP_GroupUpdateLeaderAA` | 🔴 Not-Set | | |
|
||||
| `OP_GuildBank` | 🔴 Not-Set | | |
|
||||
| `OP_GuildBankItemList` | 🔴 Not-Set | | |
|
||||
| `OP_GuildCreate` | 🔴 Not-Set | | |
|
||||
| `OP_GuildDelete` | 🔴 Not-Set | | |
|
||||
| `OP_GuildDeleteGuild` | 🔴 Not-Set | | |
|
||||
| `OP_GuildDemote` | 🔴 Not-Set | | |
|
||||
| `OP_GuildInvite` | 🔴 Not-Set | | |
|
||||
| `OP_GuildInviteAccept` | 🔴 Not-Set | | |
|
||||
| `OP_GuildLeader` | 🔴 Not-Set | | |
|
||||
| `OP_GuildManageAdd` | 🔴 Not-Set | | |
|
||||
| `OP_GuildManageBanker` | 🔴 Not-Set | | |
|
||||
| `OP_GuildManageRemove` | 🔴 Not-Set | | |
|
||||
| `OP_GuildManageStatus` | 🔴 Not-Set | | |
|
||||
| `OP_GuildMemberLevelUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_GuildMemberList` | 🔴 Not-Set | | |
|
||||
| `OP_GuildMemberUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_GuildMemberLevel` | 🔴 Not-Set | | |
|
||||
| `OP_GuildMemberRankAltBanker` | 🔴 Not-Set | | |
|
||||
| `OP_GuildMemberPublicNote` | 🔴 Not-Set | | |
|
||||
| `OP_GuildMemberAdd` | 🔴 Not-Set | | |
|
||||
| `OP_GuildMemberRename` | 🔴 Not-Set | | |
|
||||
| `OP_GuildMemberDelete` | 🔴 Not-Set | | |
|
||||
| `OP_GuildMemberDetails` | 🔴 Not-Set | | |
|
||||
| `OP_GuildRenameGuild` | 🔴 Not-Set | | |
|
||||
| `OP_GuildMOTD` | 🔴 Not-Set | | |
|
||||
| `OP_GuildPeace` | 🔴 Not-Set | | |
|
||||
| `OP_GuildPromote` | 🔴 Not-Set | | |
|
||||
| `OP_GuildPublicNote` | 🔴 Not-Set | | |
|
||||
| `OP_GuildRemove` | 🔴 Not-Set | | |
|
||||
| `OP_GuildSelectTribute` | 🔴 Not-Set | | |
|
||||
| `OP_GuildModifyBenefits` | 🔴 Not-Set | | |
|
||||
| `OP_GuildTributeToggleReq` | 🔴 Not-Set | | |
|
||||
| `OP_GuildTributeToggleReply` | 🔴 Not-Set | | |
|
||||
| `OP_GuildOptInOut` | 🔴 Not-Set | | |
|
||||
| `OP_GuildSaveActiveTributes` | 🔴 Not-Set | | |
|
||||
| `OP_GuildSendActiveTributes` | 🔴 Not-Set | | |
|
||||
| `OP_GuildTributeFavorAndTimer` | 🔴 Not-Set | | |
|
||||
| `OP_GuildsList` | 🔴 Not-Set | | |
|
||||
| `OP_GuildStatus` | 🔴 Not-Set | | |
|
||||
| `OP_GuildTributeInfo` | 🔴 Not-Set | | |
|
||||
| `OP_GuildUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_GuildTributeDonateItem` | 🔴 Not-Set | | |
|
||||
| `OP_GuildTributeDonatePlat` | 🔴 Not-Set | | |
|
||||
| `OP_GuildWar` | 🔴 Not-Set | | |
|
||||
| `OP_Heartbeat` | 🔴 Not-Set | | |
|
||||
| `OP_Hide` | 🟡 Unverified | | |
|
||||
| `OP_HideCorpse` | 🟡 Unverified | | |
|
||||
| `OP_HPUpdate` | 🟢 Verified | | |
|
||||
| `OP_Illusion` | 🟡 Unverified | | |
|
||||
| `OP_IncreaseStats` | 🟡 Unverified | | |
|
||||
| `OP_InitialHPUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_InitialMobHealth` | 🔴 Not-Set | | |
|
||||
| `OP_InspectAnswer` | 🔴 Not-Set | | |
|
||||
| `OP_InspectBuffs` | 🔴 Not-Set | | |
|
||||
| `OP_InspectMessageUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_InspectRequest` | 🔴 Not-Set | | |
|
||||
| `OP_InstillDoubt` | 🟡 Unverified | | |
|
||||
| `OP_InterruptCast` | 🟢 Verified | Some major work to do here -- the client now expects a spell link in the packet, will need to refactor the client work to decouple the stream from the internal representation | |
|
||||
| `OP_InvokeChangePetName` | 🔴 Not-Set | | |
|
||||
| `OP_InvokeChangePetNameImmediate` | 🔴 Not-Set | | |
|
||||
| `OP_InvokeNameChangeImmediate` | 🔴 Not-Set | | |
|
||||
| `OP_InvokeNameChangeLazy` | 🔴 Not-Set | | |
|
||||
| `OP_ItemLinkClick` | 🔴 Not-Set | | |
|
||||
| `OP_ItemLinkResponse` | 🔴 Not-Set | | |
|
||||
| `OP_ItemLinkText` | 🔴 Not-Set | | |
|
||||
| `OP_ItemName` | 🔴 Not-Set | | |
|
||||
| `OP_ItemPacket` | 🟡 Unverified | | |
|
||||
| `OP_ItemPreview` | 🔴 Not-Set | | |
|
||||
| `OP_ItemPreviewRequest` | 🔴 Not-Set | | |
|
||||
| `OP_ItemRecastDelay` | 🟡 Unverified | | |
|
||||
| `OP_ItemVerifyReply` | 🟡 Unverified | | |
|
||||
| `OP_ItemVerifyRequest` | 🟡 Unverified | | |
|
||||
| `OP_ItemViewUnknown` | 🔴 Not-Set | | |
|
||||
| `OP_Jump` | 🟡 Unverified | | |
|
||||
| `OP_KeyRing` | 🔴 Not-Set | | |
|
||||
| `OP_KickPlayers` | 🟡 Unverified | | |
|
||||
| `OP_KnowledgeBase` | 🔴 Not-Set | | |
|
||||
| `OP_LDoNButton` | 🔴 Not-Set | | |
|
||||
| `OP_LDoNDisarmTraps` | 🔴 Not-Set | | |
|
||||
| `OP_LDoNInspect` | 🔴 Not-Set | | |
|
||||
| `OP_LDoNOpen` | 🟡 Unverified | | |
|
||||
| `OP_LDoNPickLock` | 🟡 Unverified | | |
|
||||
| `OP_LDoNSenseTraps` | 🟡 Unverified | | |
|
||||
| `OP_LeadershipExpToggle` | 🔴 Not-Set | | |
|
||||
| `OP_LeadershipExpUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_LeaveAdventure` | 🔴 Not-Set | | |
|
||||
| `OP_LeaveBoat` | 🟡 Unverified | | |
|
||||
| `OP_LevelAppearance` | 🟡 Unverified | | |
|
||||
| `OP_LevelUpdate` | 🟢 Verified | | |
|
||||
| `OP_LFGAppearance` | 🔴 Not-Set | | |
|
||||
| `OP_LFGCommand` | 🔴 Not-Set | | |
|
||||
| `OP_LFGGetMatchesRequest` | 🔴 Not-Set | | |
|
||||
| `OP_LFGGetMatchesResponse` | 🔴 Not-Set | | |
|
||||
| `OP_LFGResponse` | 🔴 Not-Set | | |
|
||||
| `OP_LFGuild` | 🔴 Not-Set | | |
|
||||
| `OP_LFPCommand` | 🔴 Not-Set | | |
|
||||
| `OP_LFPGetMatchesRequest` | 🔴 Not-Set | | |
|
||||
| `OP_LFPGetMatchesResponse` | 🔴 Not-Set | | |
|
||||
| `OP_LinkedReuse` | 🟢 Verified | | |
|
||||
| `OP_LoadSpellSet` | 🔴 Not-Set | | |
|
||||
| `OP_LocInfo` | 🔴 Not-Set | | |
|
||||
| `OP_LockoutTimerInfo` | 🔴 Not-Set | | |
|
||||
| `OP_Login` | 🔴 Not-Set | | |
|
||||
| `OP_LoginAccepted` | 🔴 Not-Set | | |
|
||||
| `OP_LoginComplete` | 🔴 Not-Set | | |
|
||||
| `OP_LoginExpansionPacketData` | 🔴 Not-Set | | |
|
||||
| `OP_LoginUnknown1` | 🔴 Not-Set | | |
|
||||
| `OP_LoginUnknown2` | 🔴 Not-Set | | |
|
||||
| `OP_Logout` | 🟡 Unverified | | |
|
||||
| `OP_LogoutReply` | 🔴 Not-Set | | |
|
||||
| `OP_LogServer` | 🟢 Verified | Mostly unused values | |
|
||||
| `OP_LootComplete` | 🟡 Unverified | | |
|
||||
| `OP_LootItem` | 🟡 Unverified | | |
|
||||
| `OP_LootRequest` | 🟡 Unverified | | |
|
||||
| `OP_ManaChange` | 🟢 Verified | | |
|
||||
| `OP_ManaUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_MarkNPC` | 🔴 Not-Set | | |
|
||||
| `OP_MarkRaidNPC` | 🔴 Not-Set | | |
|
||||
| `OP_Marquee` | 🟡 Unverified | | |
|
||||
| `OP_MemorizeSpell` | 🟢 Verified | | |
|
||||
| `OP_Mend` | 🟡 Unverified | | |
|
||||
| `OP_MendHPUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_MercenaryAssign` | 🔴 Not-Set | | |
|
||||
| `OP_MercenaryCommand` | 🔴 Not-Set | | |
|
||||
| `OP_MercenaryDataRequest` | 🔴 Not-Set | | |
|
||||
| `OP_MercenaryDataResponse` | 🔴 Not-Set | | |
|
||||
| `OP_MercenaryDataUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_MercenaryDataUpdateRequest` | 🔴 Not-Set | | |
|
||||
| `OP_MercenaryDismiss` | 🔴 Not-Set | | |
|
||||
| `OP_MercenaryHire` | 🔴 Not-Set | | |
|
||||
| `OP_MercenarySuspendRequest` | 🔴 Not-Set | | |
|
||||
| `OP_MercenarySuspendResponse` | 🔴 Not-Set | | |
|
||||
| `OP_MercenaryTimer` | 🔴 Not-Set | | |
|
||||
| `OP_MercenaryTimerRequest` | 🔴 Not-Set | | |
|
||||
| `OP_MercenaryUnknown1` | 🔴 Not-Set | | |
|
||||
| `OP_MercenaryUnsuspendResponse` | 🔴 Not-Set | | |
|
||||
| `OP_MerchantBulkItems` | 🔴 Not-Set | | |
|
||||
| `OP_MobEnduranceUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_MobHealth` | 🟡 Unverified | | |
|
||||
| `OP_MobManaUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_MobRename` | 🔴 Not-Set | | |
|
||||
| `OP_MobUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_MoneyOnCorpse` | 🟡 Unverified | | |
|
||||
| `OP_MoneyUpdate` | 🟡 Unverified | | |
|
||||
| `OP_MOTD` | 🟢 Verified | | |
|
||||
| `OP_MoveCoin` | 🟡 Unverified | | |
|
||||
| `OP_MoveDoor` | 🟡 Unverified | | |
|
||||
| `OP_MoveItem` | 🟢 Verified | | |
|
||||
| `OP_MoveMultipleItems` | 🟡 Unverified | | |
|
||||
| `OP_MoveLogDisregard` | 🔴 Not-Set | | |
|
||||
| `OP_MoveLogRequest` | 🔴 Not-Set | | |
|
||||
| `OP_MultiLineMsg` | 🔴 Not-Set | | |
|
||||
| `OP_NewSpawn` | 🟢 Verified | Deprecated in the client, already handled in emu | |
|
||||
| `OP_NewTitlesAvailable` | 🔴 Not-Set | | |
|
||||
| `OP_NewZone` | 🟢 Verified | | |
|
||||
| `OP_NPCMoveUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_OnLevelMessage` | 🟡 Unverified | | |
|
||||
| `OP_OpenContainer` | 🟡 Unverified | | |
|
||||
| `OP_OpenDiscordMerchant` | 🔴 Not-Set | | |
|
||||
| `OP_OpenGuildTributeMaster` | 🔴 Not-Set | | |
|
||||
| `OP_OpenInventory` | 🔴 Not-Set | | |
|
||||
| `OP_OpenTributeMaster` | 🔴 Not-Set | | |
|
||||
| `OP_PDeletePetition` | 🔴 Not-Set | | |
|
||||
| `OP_PetBuffWindow` | 🔴 Not-Set | | |
|
||||
| `OP_PetCommands` | 🔴 Not-Set | | |
|
||||
| `OP_PetCommandState` | 🔴 Not-Set | | |
|
||||
| `OP_PetHoTT` | 🔴 Not-Set | | |
|
||||
| `OP_Petition` | 🔴 Not-Set | | |
|
||||
| `OP_PetitionBug` | 🔴 Not-Set | | |
|
||||
| `OP_PetitionCheckIn` | 🔴 Not-Set | | |
|
||||
| `OP_PetitionCheckout` | 🔴 Not-Set | | |
|
||||
| `OP_PetitionCheckout2` | 🔴 Not-Set | | |
|
||||
| `OP_PetitionDelete` | 🔴 Not-Set | | |
|
||||
| `OP_PetitionQue` | 🔴 Not-Set | | |
|
||||
| `OP_PetitionRefresh` | 🔴 Not-Set | | |
|
||||
| `OP_PetitionResolve` | 🔴 Not-Set | | |
|
||||
| `OP_PetitionSearch` | 🔴 Not-Set | | |
|
||||
| `OP_PetitionSearchResults` | 🔴 Not-Set | | |
|
||||
| `OP_PetitionSearchText` | 🔴 Not-Set | | |
|
||||
| `OP_PetitionUnCheckout` | 🔴 Not-Set | | |
|
||||
| `OP_PetitionUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_PickPocket` | 🟡 Unverified | | |
|
||||
| `OP_PickZone` | 🔴 Not-Set | | |
|
||||
| `OP_PickZoneWindow` | 🔴 Not-Set | | |
|
||||
| `OP_PlayerProfile` | 🟢 Verified | | |
|
||||
| `OP_PlayerStateAdd` | 🟡 Unverified | | |
|
||||
| `OP_PlayerStateRemove` | 🟡 Unverified | | |
|
||||
| `OP_PlayEverquestRequest` | 🔴 Not-Set | | |
|
||||
| `OP_PlayEverquestResponse` | 🔴 Not-Set | | |
|
||||
| `OP_PlayMP3` | 🟡 Unverified | | |
|
||||
| `OP_Poll` | 🔴 Not-Set | | |
|
||||
| `OP_PollResponse` | 🔴 Not-Set | | |
|
||||
| `OP_PopupResponse` | 🟡 Unverified | | |
|
||||
| `OP_PostEnterWorld` | 🟢 Verified | | |
|
||||
| `OP_PotionBelt` | 🔴 Not-Set | | |
|
||||
| `OP_PreLogoutReply` | 🔴 Not-Set | | |
|
||||
| `OP_PurchaseLeadershipAA` | 🔴 Not-Set | | |
|
||||
| `OP_PVPLeaderBoardDetailsReply` | 🔴 Not-Set | | |
|
||||
| `OP_PVPLeaderBoardDetailsRequest` | 🔴 Not-Set | | |
|
||||
| `OP_PVPLeaderBoardReply` | 🔴 Not-Set | | |
|
||||
| `OP_PVPLeaderBoardRequest` | 🔴 Not-Set | | |
|
||||
| `OP_PVPStats` | 🔴 Not-Set | | |
|
||||
| `OP_QueryResponseThing` | 🔴 Not-Set | | |
|
||||
| `OP_QueryUCSServerStatus` | 🟢 Verified | | |
|
||||
| `OP_RaidDelegateAbility` | 🔴 Not-Set | | |
|
||||
| `OP_RaidClearNPCMarks` | 🔴 Not-Set | | |
|
||||
| `OP_RaidInvite` | 🔴 Not-Set | | |
|
||||
| `OP_RaidJoin` | 🔴 Not-Set | | |
|
||||
| `OP_RaidUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_RandomNameGenerator` | 🟢 Verified | The client no longer sends this packet (random name generation is done entirely in the client). The client will still accept this packet to set name (emu doesn't do this, but it's always been supported) | |
|
||||
| `OP_RandomReply` | 🟡 Unverified | | |
|
||||
| `OP_RandomReq` | 🟡 Unverified | | |
|
||||
| `OP_ReadBook` | 🟡 Unverified | | |
|
||||
| `OP_RecipeAutoCombine` | 🟡 Unverified | | |
|
||||
| `OP_RecipeDetails` | 🟡 Unverified | | |
|
||||
| `OP_RecipeReply` | 🟡 Unverified | | |
|
||||
| `OP_RecipesFavorite` | 🟡 Unverified | | |
|
||||
| `OP_RecipesSearch` | 🟡 Unverified | | |
|
||||
| `OP_ReclaimCrystals` | 🔴 Not-Set | | |
|
||||
| `OP_ReloadUI` | 🔴 Not-Set | | |
|
||||
| `OP_RemoveAllDoors` | 🟡 Unverified | | |
|
||||
| `OP_RemoveBlockedBuffs` | 🟢 Verified | | |
|
||||
| `OP_RemoveNimbusEffect` | 🟡 Unverified | | |
|
||||
| `OP_RemoveTrap` | 🔴 Not-Set | | |
|
||||
| `OP_Report` | 🟡 Unverified | | |
|
||||
| `OP_ReqClientSpawn` | 🟢 Verified | | |
|
||||
| `OP_ReqNewZone` | 🟢 Verified | Client does not send this (in LS or TOB), but it does receive it. emu does not send it | |
|
||||
| `OP_RequestClientZoneChange` | 🟢 Verified | parity with RoF2, there's a string that gets passed to teleport at the end that's not known | |
|
||||
| `OP_RequestDuel` | 🔴 Not-Set | | |
|
||||
| `OP_RequestGuildTributes` | 🔴 Not-Set | | |
|
||||
| `OP_RequestKnowledgeBase` | 🔴 Not-Set | | |
|
||||
| `OP_RequestTitles` | 🔴 Not-Set | | |
|
||||
| `OP_RespawnWindow` | 🟡 Unverified | | |
|
||||
| `OP_RespondAA` | 🟢 Verified | | |
|
||||
| `OP_RestState` | 🟡 Unverified | | |
|
||||
| `OP_Rewind` | 🟡 Unverified | | |
|
||||
| `OP_RezzAnswer` | 🔴 Not-Set | | |
|
||||
| `OP_RezzComplete` | 🔴 Not-Set | | |
|
||||
| `OP_RezzRequest` | 🔴 Not-Set | | |
|
||||
| `OP_Sacrifice` | 🟡 Unverified | | |
|
||||
| `OP_SafeFallSuccess` | 🟡 Unverified | | |
|
||||
| `OP_SafePoint` | 🔴 Not-Set | | |
|
||||
| `OP_Save` | 🟡 Unverified | | |
|
||||
| `OP_SaveOnZoneReq` | 🟡 Unverified | | |
|
||||
| `OP_SelectTribute` | 🔴 Not-Set | | |
|
||||
| `OP_SendAAStats` | 🟡 Unverified | | |
|
||||
| `OP_SendAATable` | 🟢 Verified | | |
|
||||
| `OP_SendCharInfo` | 🟢 Verified | | |
|
||||
| `OP_SendExpZonein` | 🟢 Verified | | |
|
||||
| `OP_SendFindableNPCs` | 🔴 Not-Set | | |
|
||||
| `OP_SendGuildTributes` | 🔴 Not-Set | | |
|
||||
| `OP_SendLoginInfo` | 🟢 Verified | | |
|
||||
| `OP_SendMaxCharacters` | 🟢 Verified | | |
|
||||
| `OP_SendMembership` | 🟢 Verified | | |
|
||||
| `OP_SendMembershipDetails` | 🟢 Verified | The struct is correct, will need reversing for actual option keys/values | |
|
||||
| `OP_SendSystemStats` | 🔴 Not-Set | | |
|
||||
| `OP_SendTitleList` | 🔴 Not-Set | | |
|
||||
| `OP_SendTributes` | 🔴 Not-Set | | |
|
||||
| `OP_SendZonepoints` | 🟢 Verified | | |
|
||||
| `OP_SenseHeading` | 🟡 Unverified | | |
|
||||
| `OP_SenseTraps` | 🟡 Unverified | | |
|
||||
| `OP_ServerListRequest` | 🔴 Not-Set | | |
|
||||
| `OP_ServerListResponse` | 🔴 Not-Set | | |
|
||||
| `OP_SessionReady` | 🔴 Not-Set | | |
|
||||
| `OP_SetChatServer` | 🔴 Not-Set | | |
|
||||
| `OP_SetChatServer2` | 🟢 Verified | | |
|
||||
| `OP_SetFace` | 🔴 Not-Set | | |
|
||||
| `OP_SetGroupTarget` | 🔴 Not-Set | | |
|
||||
| `OP_SetGuildMOTD` | 🔴 Not-Set | | |
|
||||
| `OP_SetGuildRank` | 🔴 Not-Set | | |
|
||||
| `OP_SetRunMode` | 🟡 Unverified | | |
|
||||
| `OP_SetServerFilter` | 🟢 Verified | | |
|
||||
| `OP_SetStartCity` | 🔴 Not-Set | | |
|
||||
| `OP_SetTitle` | 🔴 Not-Set | | |
|
||||
| `OP_SetTitleReply` | 🔴 Not-Set | | |
|
||||
| `OP_SharedTaskMemberList` | 🔴 Not-Set | | |
|
||||
| `OP_SharedTaskAddPlayer` | 🔴 Not-Set | | |
|
||||
| `OP_SharedTaskRemovePlayer` | 🔴 Not-Set | | |
|
||||
| `OP_SharedTaskMakeLeader` | 🔴 Not-Set | | |
|
||||
| `OP_SharedTaskMemberInvite` | 🔴 Not-Set | | |
|
||||
| `OP_SharedTaskInvite` | 🔴 Not-Set | | |
|
||||
| `OP_SharedTaskInviteResponse` | 🔴 Not-Set | | |
|
||||
| `OP_SharedTaskAcceptNew` | 🔴 Not-Set | | |
|
||||
| `OP_SharedTaskMemberChange` | 🔴 Not-Set | | |
|
||||
| `OP_SharedTaskPlayerList` | 🔴 Not-Set | | |
|
||||
| `OP_SharedTaskSelectWindow` | 🔴 Not-Set | | |
|
||||
| `OP_SharedTaskQuit` | 🔴 Not-Set | | |
|
||||
| `OP_TaskTimers` | 🔴 Not-Set | | |
|
||||
| `OP_Shielding` | 🔴 Not-Set | | |
|
||||
| `OP_ShopDelItem` | 🟡 Unverified | | |
|
||||
| `OP_ShopEnd` | 🟡 Unverified | | |
|
||||
| `OP_ShopEndConfirm` | 🟡 Unverified | | |
|
||||
| `OP_ShopItem` | 🔴 Not-Set | | |
|
||||
| `OP_ShopPlayerBuy` | 🟡 Unverified | | |
|
||||
| `OP_ShopPlayerSell` | 🟡 Unverified | | |
|
||||
| `OP_ShopSendParcel` | 🟡 Unverified | | |
|
||||
| `OP_ShopDeleteParcel` | 🟡 Unverified | | |
|
||||
| `OP_ShopRespondParcel` | 🔴 Not-Set | | |
|
||||
| `OP_ShopRetrieveParcel` | 🟡 Unverified | | |
|
||||
| `OP_ShopParcelIcon` | 🟡 Unverified | | |
|
||||
| `OP_ShopRequest` | 🟡 Unverified | | |
|
||||
| `OP_SimpleMessage` | 🟢 Verified | | |
|
||||
| `OP_SkillUpdate` | 🟡 Unverified | | |
|
||||
| `OP_Sneak` | 🟡 Unverified | | |
|
||||
| `OP_Some3ByteHPUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_Some6ByteHPUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_SomeItemPacketMaybe` | 🔴 Not-Set | | |
|
||||
| `OP_Sound` | 🟡 Unverified | | |
|
||||
| `OP_SpawnAppearance` | 🟢 Verified | | |
|
||||
| `OP_SpawnDoor` | 🟢 Verified | | |
|
||||
| `OP_SpawnPositionUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_SpecialMesg` | 🟢 Verified | | |
|
||||
| `OP_SpellEffect` | 🟡 Unverified | | |
|
||||
| `OP_Split` | 🟡 Unverified | | |
|
||||
| `OP_Stamina` | 🟢 Verified | These values are 0-32k instead of 0-127 | |
|
||||
| `OP_Stun` | 🟡 Unverified | | |
|
||||
| `OP_Surname` | 🔴 Not-Set | | |
|
||||
| `OP_SwapSpell` | 🟢 Verified | | |
|
||||
| `OP_SystemFingerprint` | 🔴 Not-Set | | |
|
||||
| `OP_TargetBuffs` | 🔴 Not-Set | | |
|
||||
| `OP_TargetCommand` | 🟡 Unverified | | |
|
||||
| `OP_TargetHoTT` | 🔴 Not-Set | | |
|
||||
| `OP_TargetMouse` | 🟡 Unverified | | |
|
||||
| `OP_TargetReject` | 🔴 Not-Set | | |
|
||||
| `OP_TaskActivity` | 🔴 Not-Set | | |
|
||||
| `OP_TaskActivityComplete` | 🔴 Not-Set | | |
|
||||
| `OP_TaskDescription` | 🔴 Not-Set | | |
|
||||
| `OP_TaskHistoryReply` | 🔴 Not-Set | | |
|
||||
| `OP_TaskHistoryRequest` | 🔴 Not-Set | | |
|
||||
| `OP_TaskRequestTimer` | 🔴 Not-Set | | |
|
||||
| `OP_TaskSelectWindow` | 🔴 Not-Set | | |
|
||||
| `OP_Taunt` | 🟡 Unverified | | |
|
||||
| `OP_TestBuff` | 🔴 Not-Set | | |
|
||||
| `OP_TGB` | 🔴 Not-Set | | |
|
||||
| `OP_TimeOfDay` | 🟢 Verified | | |
|
||||
| `OP_Track` | 🟡 Unverified | | |
|
||||
| `OP_TrackTarget` | 🟡 Unverified | | |
|
||||
| `OP_TrackUnknown` | 🟡 Unverified | | |
|
||||
| `OP_TradeAcceptClick` | 🟡 Unverified | | |
|
||||
| `OP_TradeBusy` | 🟡 Unverified | | |
|
||||
| `OP_TradeCoins` | 🟡 Unverified | | |
|
||||
| `OP_TradeMoneyUpdate` | 🟡 Unverified | | |
|
||||
| `OP_Trader` | 🔴 Not-Set | | |
|
||||
| `OP_TraderBulkSend` | 🔴 Not-Set | | |
|
||||
| `OP_TraderBuy` | 🔴 Not-Set | | |
|
||||
| `OP_TraderDelItem` | 🔴 Not-Set | | |
|
||||
| `OP_TradeRequest` | 🟡 Unverified | | |
|
||||
| `OP_TradeRequestAck` | 🟡 Unverified | | |
|
||||
| `OP_TraderItemUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_TraderShop` | 🔴 Not-Set | | |
|
||||
| `OP_TradeSkillCombine` | 🟡 Unverified | | |
|
||||
| `OP_TradeSkillRecipeInspect` | 🔴 Not-Set | | |
|
||||
| `OP_Translocate` | 🟡 Unverified | | |
|
||||
| `OP_TributeInfo` | 🔴 Not-Set | | |
|
||||
| `OP_TributeItem` | 🔴 Not-Set | | |
|
||||
| `OP_TributeMoney` | 🔴 Not-Set | | |
|
||||
| `OP_TributeNPC` | 🔴 Not-Set | | |
|
||||
| `OP_TributePointUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_TributeTimer` | 🔴 Not-Set | | |
|
||||
| `OP_TributeToggle` | 🔴 Not-Set | | |
|
||||
| `OP_TributeUpdate` | 🔴 Not-Set | | |
|
||||
| `OP_Untargetable` | 🟡 Unverified | | |
|
||||
| `OP_UpdateAA` | 🟢 Verified | | |
|
||||
| `OP_UpdateAura` | 🔴 Not-Set | | |
|
||||
| `OP_UpdateLeadershipAA` | 🔴 Not-Set | | |
|
||||
| `OP_VetClaimReply` | 🔴 Not-Set | | |
|
||||
| `OP_VetClaimRequest` | 🔴 Not-Set | | |
|
||||
| `OP_VetRewardsAvaliable` | 🔴 Not-Set | | |
|
||||
| `OP_VoiceMacroIn` | 🟡 Unverified | | |
|
||||
| `OP_VoiceMacroOut` | 🟡 Unverified | | |
|
||||
| `OP_WeaponEquip1` | 🔴 Not-Set | | |
|
||||
| `OP_WearChange` | 🟢 Verified | | |
|
||||
| `OP_Weather` | 🟢 Verified | | |
|
||||
| `OP_Weblink` | 🟡 Unverified | | |
|
||||
| `OP_WhoAllRequest` | 🟡 Unverified | | |
|
||||
| `OP_WhoAllResponse` | 🟡 Unverified | | |
|
||||
| `OP_World_Client_CRC1` | 🟢 Verified | | |
|
||||
| `OP_World_Client_CRC2` | 🟢 Verified | | |
|
||||
| `OP_World_Client_CRC3` | 🟢 Verified | | |
|
||||
| `OP_WorldClientReady` | 🟢 Verified | | |
|
||||
| `OP_WorldComplete` | 🟢 Verified | | |
|
||||
| `OP_WorldLogout` | 🔴 Not-Set | | |
|
||||
| `OP_WorldObjectsSent` | 🟢 Verified | | |
|
||||
| `OP_WorldUnknown001` | 🟢 Verified | SetServerTime. emu doesn't currently send it so setting it to verified, but the reference is 0x140292550 | |
|
||||
| `OP_XTargetAutoAddHaters` | 🔴 Not-Set | | |
|
||||
| `OP_XTargetOpen` | 🔴 Not-Set | | |
|
||||
| `OP_XTargetOpenResponse` | 🔴 Not-Set | | |
|
||||
| `OP_XTargetRequest` | 🔴 Not-Set | | |
|
||||
| `OP_XTargetResponse` | 🔴 Not-Set | | |
|
||||
| `OP_YellForHelp` | 🟡 Unverified | | |
|
||||
| `OP_ZoneChange` | 🟢 Verified | | |
|
||||
| `OP_ZoneComplete` | 🔴 Not-Set | | |
|
||||
| `OP_ZoneEntry` | 🟢 Verified | unknown fields in C->S struct are various CRCs, emu doesn't use them | |
|
||||
| `OP_ZoneGuildList` | 🔴 Not-Set | | |
|
||||
| `OP_ZoneInUnknown` | 🔴 Not-Set | | |
|
||||
| `OP_ZonePlayerToBind` | 🟡 Unverified | | |
|
||||
| `OP_ZoneServerInfo` | 🟢 Verified | | |
|
||||
| `OP_ZoneServerReady` | 🔴 Not-Set | | |
|
||||
| `OP_ZoneSpawns` | 🟢 Verified | This is deprecated in the client (and emu never sends it directly) | |
|
||||
| `OP_ZoneUnavail` | 🟢 Verified | The client discards all content of this packet | |
|
||||
| `OP_ResetAA` | 🟡 Unverified | | |
|
||||
| `OP_UnderWorld` | 🟡 Unverified | | |
|
||||
@@ -0,0 +1 @@
|
||||
This is a bunch of ImHex patterns for viewing various Outer Brood packets
|
||||
@@ -0,0 +1,23 @@
|
||||
struct BaseResponse
|
||||
{
|
||||
u8 success;
|
||||
u32 error_str_id;
|
||||
char error_str[];
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
BaseResponse base;
|
||||
s8 unk1; //I think this is just padding
|
||||
s8 unk2; //I think this is just padding
|
||||
u32 lsid;
|
||||
char key[];
|
||||
s32 failed_attempts;
|
||||
u8 show_player_count;
|
||||
s32 unk3; // 0
|
||||
s32 unk4; // 0
|
||||
char username[];
|
||||
char password[]; //I'm not sure this is correct, it feels like this might be some internal refresh token
|
||||
char paddingEnd[2];
|
||||
};
|
||||
|
||||
Packet p @ 0x00;
|
||||
@@ -0,0 +1,19 @@
|
||||
// 0x01
|
||||
|
||||
struct LoginBase
|
||||
{
|
||||
u32 sequence_id;
|
||||
u8 compressed;
|
||||
u8 encrypt_type;
|
||||
u32 unknown08;
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
LoginBase base;
|
||||
u8 success;
|
||||
s32 error_str_id;
|
||||
char error_msg[];
|
||||
char other_msg[];
|
||||
};
|
||||
|
||||
Packet packet @0x00;
|
||||
@@ -0,0 +1,22 @@
|
||||
// 0x31
|
||||
|
||||
struct Expansion
|
||||
{
|
||||
u32 index;
|
||||
u8 owned;
|
||||
s32 expansion_name_string_id;
|
||||
s32 order_string_id;
|
||||
s32 unknown_string_id;
|
||||
u32 unknown17;
|
||||
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
u32 unknown00;
|
||||
u32 unknown04;
|
||||
u16 unknown08;
|
||||
u32 expansion_count;
|
||||
Expansion expansions[expansion_count];
|
||||
};
|
||||
|
||||
Packet packet @0x00;
|
||||
@@ -0,0 +1,18 @@
|
||||
// 0x02
|
||||
|
||||
#include <std/mem.pat>
|
||||
|
||||
struct LoginBase
|
||||
{
|
||||
u32 sequence_id;
|
||||
u8 compressed;
|
||||
u8 encrypt_type;
|
||||
u32 unknown08;
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
LoginBase base;
|
||||
u8 payload[std::mem::size() - $];
|
||||
};
|
||||
|
||||
Packet packet @0x00;
|
||||
@@ -0,0 +1,18 @@
|
||||
// 0x19
|
||||
|
||||
#include <std/mem.pat>
|
||||
|
||||
struct LoginBase
|
||||
{
|
||||
u32 sequence_id;
|
||||
u8 compressed;
|
||||
u8 encrypt_type;
|
||||
u32 unknown08;
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
LoginBase base;
|
||||
u8 payload[std::mem::size() - $];
|
||||
};
|
||||
|
||||
Packet packet @0x00;
|
||||
@@ -0,0 +1,20 @@
|
||||
// 0xd
|
||||
|
||||
struct LoginBase
|
||||
{
|
||||
u32 sequence_id;
|
||||
u8 compressed;
|
||||
u8 encrypt_type;
|
||||
u32 unknown08;
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
LoginBase base;
|
||||
u32 server_id;
|
||||
char fingerprint[];
|
||||
u32 unknown1;
|
||||
u8 unknown2;
|
||||
u32 unknown3;
|
||||
};
|
||||
|
||||
Packet packet @0x00;
|
||||
@@ -0,0 +1,19 @@
|
||||
// 0x23
|
||||
|
||||
struct LoginBase
|
||||
{
|
||||
u32 sequence_id;
|
||||
u8 compressed;
|
||||
u8 encrypt_type;
|
||||
u32 unknown08;
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
LoginBase base;
|
||||
u8 success;
|
||||
u32 login_server_string_id;
|
||||
char login_server_string;
|
||||
|
||||
};
|
||||
|
||||
Packet packet @0x00;
|
||||
@@ -0,0 +1,15 @@
|
||||
// 0x04
|
||||
|
||||
struct LoginBase
|
||||
{
|
||||
u32 sequence_id;
|
||||
u8 compressed;
|
||||
u8 encrypt_type;
|
||||
u32 unknown08;
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
LoginBase base;
|
||||
};
|
||||
|
||||
Packet packet @0x00;
|
||||
@@ -0,0 +1,44 @@
|
||||
// 0x1a
|
||||
// work in progress
|
||||
|
||||
struct LoginBase
|
||||
{
|
||||
u32 sequence_id;
|
||||
u8 compressed;
|
||||
u8 encrypt_type;
|
||||
u32 unknown08;
|
||||
};
|
||||
|
||||
struct Realm
|
||||
{
|
||||
char address[];
|
||||
u32 port;
|
||||
u32 server_category;
|
||||
//not sure yet, seen 289 on a lot of classic servers
|
||||
//41 fangbreaker, teek, oakwynd, tormax
|
||||
//31 yelniak
|
||||
//33 vaniki, mischief
|
||||
u32 status_code;
|
||||
u32 server_id;
|
||||
char name[];
|
||||
char language[];
|
||||
char region[];
|
||||
char server_type_desc[];
|
||||
char server_desc[];
|
||||
u32 server_flags;
|
||||
u32 players_online;
|
||||
u32 expansion; //I think
|
||||
u32 truebox_max_clients;
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
LoginBase base;
|
||||
|
||||
u8 success;
|
||||
u32 login_server_string_id;
|
||||
char login_server_string[];
|
||||
u32 realm_count;
|
||||
Realm realms[realm_count];
|
||||
};
|
||||
|
||||
Packet packet @0x00;
|
||||
@@ -0,0 +1,16 @@
|
||||
// 0x01
|
||||
|
||||
struct LoginBase
|
||||
{
|
||||
u32 sequence_id;
|
||||
u8 compressed;
|
||||
u8 encrypt_type;
|
||||
u32 unknown08;
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
LoginBase base;
|
||||
u16 unknown0a;
|
||||
};
|
||||
|
||||
Packet packet @0x00;
|
||||
@@ -0,0 +1,10 @@
|
||||
// 0x16
|
||||
|
||||
struct Packet {
|
||||
u32 sequence_id;
|
||||
u32 unknown04;
|
||||
u16 unknown08;
|
||||
char fingerprint_data[];
|
||||
};
|
||||
|
||||
Packet packet @0x00;
|
||||
@@ -0,0 +1,17 @@
|
||||
// 0x03
|
||||
// I'm not sure what this packet is, it sends right after play everquest response it sent client->server
|
||||
|
||||
struct LoginBase
|
||||
{
|
||||
u32 sequence_id;
|
||||
u8 compressed;
|
||||
u8 encrypt_type;
|
||||
u32 unknown08;
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
LoginBase base;
|
||||
|
||||
};
|
||||
|
||||
Packet packet @0x00;
|
||||
@@ -0,0 +1,27 @@
|
||||
import argparse
|
||||
from Crypto.Cipher import DES
|
||||
|
||||
def decrypt_hex_string(hex_data):
|
||||
raw_hex = "".join(hex_data).replace(" ", "")
|
||||
|
||||
try:
|
||||
encrypted_bytes = bytes.fromhex(raw_hex)
|
||||
except ValueError:
|
||||
return "Error: Input is not valid hexadecimal."
|
||||
|
||||
key = b'\x00' * 8
|
||||
iv = b'\x00' * 8
|
||||
|
||||
cipher = DES.new(key, DES.MODE_CBC, iv)
|
||||
decrypted_bytes = cipher.decrypt(encrypted_bytes)
|
||||
|
||||
return decrypted_bytes
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Decrypt EQ Default Encryption.")
|
||||
parser.add_argument("data", nargs="+", help="The data hex string to decrypt")
|
||||
args = parser.parse_args()
|
||||
result = decrypt_hex_string(args.data)
|
||||
|
||||
print("--- Decrypted Data ---")
|
||||
print(f"Data: {result.hex(' ').upper()}")
|
||||
@@ -0,0 +1,26 @@
|
||||
struct CharacterCreateAllocation
|
||||
{
|
||||
u32 index;
|
||||
u32 base_stats[7];
|
||||
u32 default_allocations[7];
|
||||
};
|
||||
|
||||
struct RaceClassCombo
|
||||
{
|
||||
u64 expansion_req;
|
||||
u32 race;
|
||||
u32 class;
|
||||
u32 deity;
|
||||
u32 allocation_index;
|
||||
u32 zone;
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
u8 padding1;
|
||||
u32 allocation_count;
|
||||
CharacterCreateAllocation allocations[allocation_count];
|
||||
u32 race_class_combo_count;
|
||||
RaceClassCombo race_class_combos[race_class_combo_count];
|
||||
};
|
||||
|
||||
Packet p @ 0x00;
|
||||
@@ -0,0 +1,26 @@
|
||||
struct MembershipEntry
|
||||
{
|
||||
u32 purchase_id;
|
||||
u32 bitwise_entry;
|
||||
};
|
||||
|
||||
struct MembershipSetting
|
||||
{
|
||||
s8 setting_index;
|
||||
s32 setting_id; // 0 to 23 actually seen but the OP_Membership packet has up to 32
|
||||
s32 setting_value;
|
||||
};
|
||||
|
||||
struct Membership
|
||||
{
|
||||
u32 membership_setting_count;
|
||||
MembershipSetting membership_settings[membership_setting_count];
|
||||
u32 race_entry_count;
|
||||
MembershipEntry membership_races[race_entry_count];
|
||||
u32 class_entry_count;
|
||||
MembershipEntry membership_classes[class_entry_count];
|
||||
u32 exit_url_length;
|
||||
char exit_url[exit_url_length];
|
||||
};
|
||||
|
||||
Membership m @ 0x00;
|
||||
@@ -0,0 +1,434 @@
|
||||
struct Bind {
|
||||
u32 zoneid;
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float heading;
|
||||
};
|
||||
|
||||
struct ArmorProperty
|
||||
{
|
||||
s32 type;
|
||||
s32 variation;
|
||||
s32 material;
|
||||
s32 newArmorId;
|
||||
s32 newArmorType;
|
||||
};
|
||||
|
||||
struct AA
|
||||
{
|
||||
s32 index;
|
||||
s32 points_spent;
|
||||
s32 charges_spent;
|
||||
};
|
||||
|
||||
struct EQGuid
|
||||
{
|
||||
u32 entity_id;
|
||||
u32 realm_id;
|
||||
};
|
||||
|
||||
struct SlotData
|
||||
{
|
||||
s32 slot_id;
|
||||
s64 value;
|
||||
};
|
||||
|
||||
struct EQAffect
|
||||
{
|
||||
float modifier;
|
||||
EQGuid caster_id;
|
||||
u32 duration;
|
||||
u32 max_duration;
|
||||
u8 level;
|
||||
s32 spell_id;
|
||||
s32 hitcount;
|
||||
u32 flags;
|
||||
u32 viral_timer;
|
||||
u8 type;
|
||||
SlotData slots[6];
|
||||
};
|
||||
|
||||
struct Coin
|
||||
{
|
||||
u32 platinum;
|
||||
u32 gold;
|
||||
u32 silver;
|
||||
u32 copper;
|
||||
};
|
||||
|
||||
struct BandolierItemInfo {
|
||||
char name[];
|
||||
s32 item_id;
|
||||
s32 icon;
|
||||
};
|
||||
|
||||
struct BandolierSet
|
||||
{
|
||||
char name[];
|
||||
BandolierItemInfo items[4];
|
||||
};
|
||||
|
||||
struct ItemIndex
|
||||
{
|
||||
s16 slot1;
|
||||
s16 slot2;
|
||||
s16 slot3;
|
||||
};
|
||||
|
||||
struct Claim
|
||||
{
|
||||
s32 feature_id;
|
||||
s32 count;
|
||||
};
|
||||
|
||||
struct Tribute {
|
||||
u32 BenefitTimer;
|
||||
s32 unknown1;
|
||||
s32 current_favor;
|
||||
s32 unknown2;
|
||||
s32 all_time_favor;
|
||||
s32 unknown3; //some of these are probably the bools on the pcclient;
|
||||
u16 unknown4;
|
||||
};
|
||||
|
||||
struct TributeBenefit
|
||||
{
|
||||
s32 benefit_id;
|
||||
s32 benefit_tier;
|
||||
};
|
||||
|
||||
struct RaidData
|
||||
{
|
||||
u32 main_assist1;
|
||||
u32 main_assist2;
|
||||
u32 main_assist3;
|
||||
char main_assist_name1[];
|
||||
char main_assist_name2[];
|
||||
char main_assist_name3[];
|
||||
u32 main_marker1;
|
||||
u32 main_marker2;
|
||||
u32 main_marker3;
|
||||
u32 master_looter;
|
||||
};
|
||||
|
||||
struct LdonData
|
||||
{
|
||||
u32 count;
|
||||
u32 ldon_categories[count];
|
||||
u32 ldon_points_available;
|
||||
};
|
||||
|
||||
struct PvPData
|
||||
{
|
||||
u32 kills;
|
||||
u32 deaths;
|
||||
u32 current_points;
|
||||
u32 career_points;
|
||||
u32 best_kill_streak;
|
||||
u32 worst_death_streak;
|
||||
u32 current_kill_streak;
|
||||
};
|
||||
|
||||
struct PvPKill
|
||||
{
|
||||
char name[];
|
||||
u32 level;
|
||||
u32 unknown1; //not sure
|
||||
u32 unknown2; //not sure
|
||||
u32 race;
|
||||
u32 class;
|
||||
u32 zone;
|
||||
u32 time;
|
||||
u32 points;
|
||||
};
|
||||
|
||||
struct PvPDeath
|
||||
{
|
||||
char name[];
|
||||
u32 level;
|
||||
u32 race;
|
||||
u32 class;
|
||||
u32 zone;
|
||||
u32 time;
|
||||
u32 points;
|
||||
};
|
||||
|
||||
struct AltCurrency
|
||||
{
|
||||
u32 alt_currency_str_length;
|
||||
u32 unknown1;
|
||||
char alt_currency_string[alt_currency_str_length];
|
||||
};
|
||||
|
||||
struct AchivementSubComponentData
|
||||
{
|
||||
s32 achievement_id;
|
||||
s32 component_id;
|
||||
s32 requirement_id;
|
||||
s32 requirement_type;
|
||||
s32 count;
|
||||
};
|
||||
|
||||
struct AlchemyBonusSkillData
|
||||
{
|
||||
s32 skill_id;
|
||||
s32 bonus;
|
||||
};
|
||||
|
||||
struct PersonaItemSlot
|
||||
{
|
||||
u32 item_id;
|
||||
u32 slot_id;
|
||||
};
|
||||
|
||||
struct PersonaEquipment
|
||||
{
|
||||
PersonaItemSlot item;
|
||||
u32 augment_count;
|
||||
PersonaItemSlot augments[augment_count];
|
||||
};
|
||||
|
||||
struct PersonaEquipmentSet
|
||||
{
|
||||
u32 class_id;
|
||||
u32 equipment_count;
|
||||
PersonaEquipment equipment[equipment_count];
|
||||
};
|
||||
|
||||
struct PcProfile
|
||||
{
|
||||
u32 profile_type;
|
||||
u32 profile_id;
|
||||
u32 shroud_template_id;
|
||||
u8 gender;
|
||||
u32 race;
|
||||
u32 class;
|
||||
u8 level;
|
||||
u8 level1;
|
||||
u32 bind_count;
|
||||
Bind binds[bind_count];
|
||||
u32 deity;
|
||||
u32 intoxication;
|
||||
u32 property_count;
|
||||
u32 properties[property_count];
|
||||
u32 armor_prop_count;
|
||||
ArmorProperty armor_props[armor_prop_count];
|
||||
u32 base_armor_prop_count;
|
||||
ArmorProperty base_armor_props[base_armor_prop_count];
|
||||
u32 body_tint_count;
|
||||
u32 body_tints[body_tint_count];
|
||||
u32 equip_tint_count;
|
||||
u32 equip_tints[equip_tint_count];
|
||||
u8 hair_color;
|
||||
u8 facial_hair_color;
|
||||
u32 npc_tint_index;
|
||||
u8 eye_color1;
|
||||
u8 eye_color2;
|
||||
u8 hair_style;
|
||||
u8 facial_hair;
|
||||
u8 face;
|
||||
u8 old_face;
|
||||
u32 heritage;
|
||||
u32 tattoo;
|
||||
u32 details;
|
||||
u8 texture_type;
|
||||
u8 material;
|
||||
u8 variation;
|
||||
float height;
|
||||
float width;
|
||||
float length;
|
||||
float view_height;
|
||||
u32 primary;
|
||||
u32 secondary;
|
||||
u32 practices;
|
||||
u32 base_mana;
|
||||
u32 base_hp;
|
||||
u32 base_str;
|
||||
u32 base_sta;
|
||||
u32 base_cha;
|
||||
u32 base_dex;
|
||||
u32 base_int;
|
||||
u32 base_agi;
|
||||
u32 base_wis;
|
||||
u32 base_heroic_str;
|
||||
u32 base_heroic_sta;
|
||||
u32 base_heroic_cha;
|
||||
u32 base_heroic_dex;
|
||||
u32 base_heroic_int;
|
||||
u32 base_heroic_agi;
|
||||
u32 base_heroic_wis;
|
||||
u32 aa_count;
|
||||
AA aas[aa_count];
|
||||
u32 skill_count;
|
||||
s32 skills[skill_count];
|
||||
u32 innate_skill_count;
|
||||
s32 innate_skills[innate_skill_count];
|
||||
u32 combat_ability_count;
|
||||
s32 combat_abilities[combat_ability_count];
|
||||
u32 combat_ability_timer_count;
|
||||
s32 combat_ability_timers[combat_ability_timer_count];
|
||||
u32 unk_ability_count;
|
||||
u32 linked_spell_timer_count;
|
||||
s32 linked_spell_timers[linked_spell_timer_count];
|
||||
u32 item_recast_timer_count;
|
||||
s32 item_recast_timers[item_recast_timer_count];
|
||||
u32 spell_book_slot_count;
|
||||
s32 spell_book_slots[spell_book_slot_count];
|
||||
u32 spell_gem_count;
|
||||
s32 spell_gems[spell_gem_count];
|
||||
u32 spell_recast_timer_count;
|
||||
s32 spell_recast_timers[spell_recast_timer_count];
|
||||
u8 max_allowed_spell_slots;
|
||||
u32 buff_count;
|
||||
EQAffect buffs[buff_count];
|
||||
Coin coin;
|
||||
Coin cursor_coin;
|
||||
u32 disc_timer;
|
||||
u32 mend_timer;
|
||||
u32 forage_timer;
|
||||
u32 thirst;
|
||||
u32 hunger;
|
||||
u32 aa_spent;
|
||||
u32 aa_window_count;
|
||||
u32 aa_window_stats[aa_window_count];
|
||||
u32 aa_points_unspent;
|
||||
u8 sneak;
|
||||
u8 hide;
|
||||
u32 bandolier_count;
|
||||
BandolierSet bandolier_sets[bandolier_count];
|
||||
u32 invslot_bitmask;
|
||||
u32 basedata_hp;
|
||||
u32 basedata_mana;
|
||||
u32 basedata_endur;
|
||||
u32 basedata_mr;
|
||||
u32 basedata_fr;
|
||||
u32 basedata_cr;
|
||||
u32 basedata_pr;
|
||||
u32 basedata_dr;
|
||||
u32 basedata_corrupt;
|
||||
u32 basedata_phr;
|
||||
float basedata_walkspeed;
|
||||
float basedata_runspeed;
|
||||
u32 basedata_hpregen;
|
||||
u32 basedata_manaregen;
|
||||
u32 basedata_mountmanaregen;
|
||||
u32 basedata_endurregen;
|
||||
u32 basedata_ac;
|
||||
u32 basedata_atk;
|
||||
u32 basedata_dmg;
|
||||
u32 basedata_delay;
|
||||
u32 endurance;
|
||||
u32 heroic_type;
|
||||
ItemIndex keyring_item_index[5];
|
||||
u64 exp;
|
||||
u64 aa_exp; //this is a guess, used to be 32 upped to 64
|
||||
u16 unknown1;
|
||||
EQGuid character_id;
|
||||
u32 name_length;
|
||||
char name[name_length];
|
||||
u32 last_name_length;
|
||||
char last_name[last_name_length];
|
||||
u32 creation_time;
|
||||
u32 account_creation_time;
|
||||
u32 last_played_time;
|
||||
u32 played_minutes;
|
||||
u32 entitled_days;
|
||||
u32 expansion_flags;
|
||||
u32 unknown2; //new field from laurion to obrood
|
||||
u32 language_count;
|
||||
u8 languages[language_count];
|
||||
u32 current_zone;
|
||||
float current_x;
|
||||
float current_y;
|
||||
float current_z;
|
||||
float current_heading;
|
||||
u8 animation;
|
||||
u8 pvp;
|
||||
u8 anon;
|
||||
u8 gm;
|
||||
u64 guild_id;
|
||||
u8 guild_show_sprite;
|
||||
u8 status;
|
||||
Coin coin2;
|
||||
Coin bank2;
|
||||
u32 bank_shared_plat;
|
||||
u32 claim_count;
|
||||
Claim claims[claim_count];
|
||||
Tribute tribute;
|
||||
u32 tribute_benefit_count;
|
||||
TributeBenefit tribute_benefits[tribute_benefit_count];
|
||||
u32 trophy_tribute_benefit_count;
|
||||
TributeBenefit trophy_tribute_benefit[trophy_tribute_benefit_count];
|
||||
u8 tasks[137]; //honestly not sure what this is, was just a guess
|
||||
u32 good_points_available;
|
||||
u32 good_points_earned;
|
||||
u32 bad_points_available;
|
||||
u32 bad_points_earned;
|
||||
u32 momentum_balance;
|
||||
u32 loyalty_reward_balance;
|
||||
u32 parcel_status;
|
||||
u32 vehicle_name_length;
|
||||
char vehicle_name[vehicle_name_length];
|
||||
u8 super_pkill;
|
||||
u8 unclone;
|
||||
u8 dead;
|
||||
u32 ld_timer;
|
||||
u32 spell_interrupt_count;
|
||||
u8 autosplit;
|
||||
u8 tells_off;
|
||||
u8 gm_invis;
|
||||
u32 kill_me;
|
||||
u8 cheater_ld_flag;
|
||||
u8 norent;
|
||||
u8 corpse;
|
||||
u8 client_gm_flag_set;
|
||||
u32 mentor_pct;
|
||||
RaidData raid;
|
||||
u32 unique_player_id;
|
||||
LdonData ldon_data;
|
||||
u32 air_supply;
|
||||
PvPData pvp_data;
|
||||
PvPKill last_kill;
|
||||
PvPDeath last_death;
|
||||
u32 kills_in_past_24_hours;
|
||||
u32 kill_list_count;
|
||||
PvPKill kill_list[kill_list_count];
|
||||
u32 pvp_infamy_level;
|
||||
u32 pvp_vitality;
|
||||
u32 cursor_krono;
|
||||
u32 krono;
|
||||
u8 autoconsent_group;
|
||||
u8 autoconsent_raid;
|
||||
u8 autoconsent_guild;
|
||||
u8 autoconsent_fellowship;
|
||||
u8 private_for_eq_players;
|
||||
u32 main_level;
|
||||
u8 show_helm;
|
||||
u32 downtime;
|
||||
AltCurrency alt_currency;
|
||||
u32 completed_event_subcomponent_count;
|
||||
AchivementSubComponentData completed_event_subcomponents[completed_event_subcomponent_count];
|
||||
u32 inprogress_event_subcomponent_count;
|
||||
AchivementSubComponentData inprogress_event_subcomponents[inprogress_event_subcomponent_count];
|
||||
u64 merc_aa_exp;
|
||||
u32 merc_aa_points;
|
||||
u32 merc_aa_spent;
|
||||
u32 starting_city_zone_id;
|
||||
u8 use_advanced_looting;
|
||||
u8 is_master_loot_candidate;
|
||||
u32 alchemy_bonus_list_count;
|
||||
AlchemyBonusSkillData alchemy_bonus_list[alchemy_bonus_list_count];
|
||||
u32 persona_count;
|
||||
PersonaEquipmentSet persona_equipment_set[persona_count];
|
||||
u8 term;
|
||||
};
|
||||
|
||||
struct Packet
|
||||
{
|
||||
u32 crc;
|
||||
u32 length;
|
||||
PcProfile profile;
|
||||
};
|
||||
|
||||
Packet p @ 0x00;
|
||||
@@ -0,0 +1,28 @@
|
||||
def patch_template(template_path, opcodes_path, output_path):
|
||||
try:
|
||||
with open(opcodes_path, 'r') as f:
|
||||
opcodes = [line.strip() for line in f if line.strip()]
|
||||
|
||||
with open(template_path, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
for index, value in enumerate(opcodes):
|
||||
placeholder = f"{{{{{index}}}}}"
|
||||
content = content.replace(placeholder, value)
|
||||
|
||||
with open(output_path, 'w') as f:
|
||||
f.write(content)
|
||||
|
||||
print(f"Successfully transformed: {output_path}")
|
||||
|
||||
except FileNotFoundError as e:
|
||||
print(f"Error: File Not Found - {e}")
|
||||
except Exception as e:
|
||||
print(f"Error: Exception - {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
patch_template(
|
||||
template_path='opcode.template',
|
||||
opcodes_path='opcodes.csv',
|
||||
output_path='patch_TOB.conf'
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,699 @@
|
||||
# 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=0x722a
|
||||
OP_ApproveWorld=0x0000
|
||||
OP_LogServer=0x2cae
|
||||
OP_SendCharInfo=0x5d1a
|
||||
OP_ExpansionInfo=0x393a
|
||||
OP_EnterWorld=0x7fb8
|
||||
OP_PostEnterWorld=0x1945 # unused
|
||||
OP_World_Client_CRC1=0x777f # This is OP_SendExeChecksum
|
||||
OP_World_Client_CRC2=0x0492 # This is OP_SendBaseDataChecksum
|
||||
OP_World_Client_CRC3=0x0690 # This is OP_SendSkillCapsChecksum
|
||||
OP_SendSpellChecksum=0x0000 # There is no spell checksum in TOB
|
||||
OP_SendSkillCapsChecksum=0x0690
|
||||
|
||||
# Character Select Related:
|
||||
OP_SendMaxCharacters=0x25eb
|
||||
OP_SendMembership=0x5789
|
||||
OP_SendMembershipDetails=0x2373
|
||||
OP_CharacterCreateRequest=0x6b67
|
||||
OP_CharacterCreate=0x1859
|
||||
OP_DeleteCharacter=0x71ca
|
||||
OP_RandomNameGenerator=0x7f4a # TOB client no longer sends this, and the S->C packet isn't used by emu
|
||||
OP_ApproveName=0x5306
|
||||
OP_MOTD=0x1eef
|
||||
OP_SetChatServer=0x0000
|
||||
OP_SetChatServer2=0x34c1
|
||||
OP_ZoneServerInfo=0x2323
|
||||
OP_WorldComplete=0x1223
|
||||
OP_WorldUnknown001=0x7723 # SetServerTime, S->C
|
||||
OP_FloatListThing=0x504f # Movement History, C->S
|
||||
|
||||
# Reasons for Disconnect:
|
||||
OP_ZoneUnavail=0x29a6
|
||||
OP_WorldClientReady=0x538f
|
||||
OP_CharacterStillInZone=0x0000
|
||||
OP_WorldChecksumFailure=0x0000
|
||||
OP_WorldLoginFailed=0x0000
|
||||
OP_WorldLogout=0x0000
|
||||
OP_WorldLevelTooHigh=0x0000
|
||||
OP_CharInacessable=0x0000
|
||||
OP_UserCompInfo=0x0000
|
||||
OP_SendExeChecksum=0x777f
|
||||
OP_SendBaseDataChecksum=0x0492
|
||||
|
||||
# Zone in opcodes
|
||||
OP_AckPacket=0x776d
|
||||
OP_ZoneEntry=0x713d
|
||||
OP_ReqNewZone=0x1ccc
|
||||
OP_NewZone=0x5ec0
|
||||
OP_ZoneSpawns=0x6cd9
|
||||
OP_PlayerProfile=0x08bf
|
||||
OP_TimeOfDay=0x5503
|
||||
OP_LevelUpdate=0x54bf
|
||||
OP_Stamina=0x3b01
|
||||
OP_RequestClientZoneChange=0x7a59
|
||||
OP_ZoneChange=0x4816
|
||||
OP_LockoutTimerInfo=0x0000
|
||||
OP_ZoneServerReady=0x0000
|
||||
OP_ZoneInUnknown=0x0000
|
||||
OP_LogoutReply=0x0000
|
||||
OP_PreLogoutReply=0x0000
|
||||
|
||||
# Required to fully log in
|
||||
OP_SpawnAppearance=0x513a
|
||||
OP_ChangeSize=0x1ed0
|
||||
OP_Weather=0x1e6d
|
||||
OP_ReqClientSpawn=0x6a27
|
||||
OP_SpawnDoor=0x532b
|
||||
OP_GroundSpawn=0x14c7
|
||||
OP_SendZonepoints=0x21a2
|
||||
OP_BlockedBuffs=0x0f6f
|
||||
OP_RemoveBlockedBuffs=0x4471
|
||||
OP_ClearBlockedBuffs=0x27ce
|
||||
OP_WorldObjectsSent=0x4f32
|
||||
OP_SendExpZonein=0x7267
|
||||
OP_SendAATable=0x22bd
|
||||
OP_ClearAA=0x6093
|
||||
OP_ClearLeadershipAbilities=0x0000 #removed; leadership abilities are baked in and always on
|
||||
OP_RespondAA=0x4449
|
||||
OP_UpdateAA=0x1655
|
||||
OP_SendAAStats=0x7416 # Removed in TOB
|
||||
OP_AAExpUpdate=0x04c3 #need to look into whether this has changed; exp did
|
||||
OP_ExpUpdate=0x0e55
|
||||
OP_HPUpdate=0x2723
|
||||
OP_ManaChange=0x08f6
|
||||
OP_TGB=0x0000 #removed; tgb is baked in and always on
|
||||
OP_SpecialMesg=0x08bd
|
||||
OP_CharInventory=0x15b4
|
||||
OP_WearChange=0x5897
|
||||
OP_ClientUpdate=0x1615
|
||||
OP_ClientReady=0x666f
|
||||
OP_SetServerFilter=0x5a35
|
||||
|
||||
# Guild Opcodes
|
||||
OP_GuildsList=0x0000
|
||||
OP_GuildMemberList=0x0000
|
||||
OP_GuildMOTD=0x0000
|
||||
OP_GetGuildMOTD=0x0000
|
||||
OP_GetGuildMOTDReply=0x0000
|
||||
OP_GuildMemberUpdate=0x0000
|
||||
OP_GuildInvite=0x0000
|
||||
OP_GuildRemove=0x0000
|
||||
OP_GuildPeace=0x0000
|
||||
OP_SetGuildMOTD=0x0000
|
||||
OP_GuildWar=0x0000
|
||||
OP_GuildLeader=0x0000
|
||||
OP_GuildDelete=0x0000
|
||||
OP_GuildInviteAccept=0x0000
|
||||
OP_GuildDemote=0x0000
|
||||
OP_GuildPromote=0x0000
|
||||
OP_GuildPublicNote=0x0000
|
||||
OP_GuildManageBanker=0x0000
|
||||
OP_GuildBank=0x0000
|
||||
OP_GuildBankItemList=0x0000
|
||||
OP_SetGuildRank=0x0000
|
||||
OP_GuildUpdate=0x0000
|
||||
OP_GuildStatus=0x0000
|
||||
OP_GuildCreate=0x0000
|
||||
OP_GuildOpenGuildWindow=0x0000
|
||||
OP_GuildMemberLevel=0x0000
|
||||
OP_GuildMemberRankAltBanker=0x0000
|
||||
OP_GuildMemberPublicNote=0x0000
|
||||
OP_GuildMemberAdd=0x0000
|
||||
OP_GuildMemberRename=0x0000
|
||||
OP_GuildMemberDelete=0x0000
|
||||
OP_GuildMemberDetails=0x0000
|
||||
OP_GuildRenameGuild=0x0000
|
||||
OP_LFGuild=0x0000
|
||||
OP_GuildDeleteGuild=0x0000
|
||||
|
||||
# GM/Guide Opcodes
|
||||
OP_GMServers=0x0000
|
||||
OP_GMBecomeNPC=0x0000
|
||||
OP_GMZoneRequest=0x0000
|
||||
OP_GMZoneRequest2=0x0000
|
||||
OP_GMGoto=0x0000
|
||||
OP_GMSearchCorpse=0x0000
|
||||
OP_GMHideMe=0x0000
|
||||
OP_GMDelCorpse=0x0000
|
||||
OP_GMApproval=0x0000
|
||||
OP_GMToggle=0x0000
|
||||
OP_GMSummon=0x0000
|
||||
OP_GMEmoteZone=0x0000
|
||||
OP_GMEmoteWorld=0x0000
|
||||
OP_GMFind=0x0000
|
||||
OP_GMKick=0x0000
|
||||
OP_GMKill=0x0000
|
||||
OP_GMNameChange=0x0000
|
||||
OP_GMLastName=0x0000
|
||||
|
||||
# Misc Opcodes
|
||||
OP_QueryUCSServerStatus=0x7093
|
||||
OP_InspectRequest=0x0000
|
||||
OP_InspectAnswer=0x0000
|
||||
OP_InspectMessageUpdate=0x0000
|
||||
OP_BeginCast=0x34b1
|
||||
OP_ColoredText=0x1743
|
||||
OP_ConsentResponse=0x74b3
|
||||
OP_MemorizeSpell=0x6af0
|
||||
OP_LinkedReuse=0x5683
|
||||
OP_SwapSpell=0x32cc
|
||||
OP_CastSpell=0x1d63
|
||||
OP_Consider=0x4568
|
||||
OP_FormattedMessage=0x29b4
|
||||
OP_SimpleMessage=0x5b2d
|
||||
OP_Buff=0x2427
|
||||
OP_Illusion=0x7fb0
|
||||
OP_MoneyOnCorpse=0x6f63
|
||||
OP_RandomReply=0x1234
|
||||
OP_DenyResponse=0x339b
|
||||
OP_SkillUpdate=0x0149
|
||||
OP_GMTrainSkillConfirm=0x3365
|
||||
OP_RandomReq=0x0313
|
||||
OP_Death=0x1e90
|
||||
OP_GMTraining=0x3d75
|
||||
OP_GMEndTraining=0x1bf2
|
||||
OP_GMTrainSkill=0x1525
|
||||
OP_Animation=0x3807
|
||||
OP_Begging=0x217b
|
||||
OP_Consent=0x6c66
|
||||
OP_ConsentDeny=0x5343
|
||||
OP_AutoFire=0x2583
|
||||
OP_PetCommands=0x0000
|
||||
OP_PetCommandState=0x0000
|
||||
OP_PetHoTT=0x0000
|
||||
OP_DeleteSpell=0x5d53
|
||||
OP_Surname=0x0000
|
||||
OP_ClearSurname=0x0000
|
||||
OP_FaceChange=0x0000
|
||||
OP_SetFace=0x0000
|
||||
OP_SenseHeading=0x2ff2
|
||||
OP_Action=0x7d28
|
||||
OP_ConsiderCorpse=0x2f98
|
||||
OP_HideCorpse=0x2623
|
||||
OP_CorpseDrag=0x7200
|
||||
OP_CorpseDrop=0x2a53
|
||||
OP_Bug=0x2846
|
||||
OP_Feedback=0x0000
|
||||
OP_Report=0x6b73
|
||||
OP_Damage=0x5b42
|
||||
OP_ChannelMessage=0x7622
|
||||
OP_Assist=0x51a0
|
||||
OP_AssistGroup=0x4879
|
||||
OP_MoveCoin=0x1987
|
||||
OP_ZonePlayerToBind=0x1860
|
||||
OP_KeyRing=0x0000
|
||||
OP_WhoAllRequest=0x3328
|
||||
OP_WhoAllResponse=0x4dfd
|
||||
OP_FriendsWho=0x3547
|
||||
OP_ConfirmDelete=0x14a8 # This is sent fromt the client after a movement update (with just spawn ID as the content)
|
||||
OP_Logout=0x46f8
|
||||
OP_Rewind=0x898a
|
||||
OP_TargetCommand=0x46bf
|
||||
OP_Hide=0x4f10
|
||||
OP_Jump=0x2b69
|
||||
OP_Camp=0x4fe0
|
||||
OP_Emote=0x0000
|
||||
OP_SetRunMode=0x3b78
|
||||
OP_BankerChange=0x0fa6
|
||||
OP_TargetMouse=0x7f48
|
||||
OP_MobHealth=0x445e
|
||||
OP_InitialMobHealth=0x0000 # Unused?
|
||||
OP_TargetHoTT=0x0000
|
||||
OP_TargetBuffs=0x0000
|
||||
OP_XTargetResponse=0x0000
|
||||
OP_XTargetRequest=0x0000
|
||||
OP_XTargetAutoAddHaters=0x0000
|
||||
OP_XTargetOpen=0x0000
|
||||
OP_XTargetOpenResponse=0x0000
|
||||
OP_BuffCreate=0x754c
|
||||
OP_BuffRemoveRequest=0x0c06
|
||||
OP_DeleteSpawn=0x33fa
|
||||
OP_AutoAttack=0x3ced
|
||||
OP_AutoAttack2=0x1824
|
||||
OP_Consume=0x2d2d
|
||||
OP_MoveItem=0x121c
|
||||
OP_MoveMultipleItems=0x6bf7
|
||||
OP_DeleteItem=0x29e6
|
||||
OP_DeleteCharge=0x4bef
|
||||
OP_ItemPacket=0x0fb6
|
||||
OP_ItemLinkResponse=0x0000
|
||||
OP_ItemLinkClick=0x0000
|
||||
OP_ItemPreview=0x0000
|
||||
OP_NewSpawn=0x053d
|
||||
OP_Track=0x24c2
|
||||
OP_TrackTarget=0x0941
|
||||
OP_TrackUnknown=0x0f55
|
||||
OP_ClickDoor=0x1678
|
||||
OP_MoveDoor=0x6e1d
|
||||
OP_RemoveAllDoors=0x01df
|
||||
OP_EnvDamage=0x2dbe
|
||||
OP_BoardBoat=0x0c52
|
||||
OP_LeaveBoat=0x6097
|
||||
OP_ControlBoat=0x79ad
|
||||
OP_Forage=0x5b12
|
||||
OP_SafeFallSuccess=0x6341
|
||||
OP_RezzComplete=0x0000
|
||||
OP_RezzRequest=0x0000
|
||||
OP_RezzAnswer=0x0000
|
||||
OP_Shielding=0x0000
|
||||
OP_RequestDuel=0x0000
|
||||
OP_MobRename=0x0000
|
||||
OP_AugmentItem=0x322a
|
||||
OP_WeaponEquip1=0x0000
|
||||
OP_PlayerStateAdd=0x0e05
|
||||
OP_PlayerStateRemove=0x0ec0
|
||||
OP_ApplyPoison=0x7216
|
||||
OP_Save=0x667f
|
||||
OP_TestBuff=0x0000
|
||||
OP_CustomTitles=0x0000
|
||||
OP_Split=0x3ea6
|
||||
OP_YellForHelp=0x1330
|
||||
OP_LoadSpellSet=0x0000
|
||||
OP_Bandolier=0x0000
|
||||
OP_PotionBelt=0x0000
|
||||
OP_DuelDecline=0x0000
|
||||
OP_DuelAccept=0x0000
|
||||
OP_SaveOnZoneReq=0x16e3
|
||||
OP_ReadBook=0x165a
|
||||
OP_Dye=0x0000
|
||||
OP_InterruptCast=0x5313
|
||||
OP_AAAction=0x48fb
|
||||
OP_LeadershipExpToggle=0x0000 #removed, these act as if all purchased now
|
||||
OP_LeadershipExpUpdate=0x0000 #removed, these act as if all purchased now
|
||||
OP_PurchaseLeadershipAA=0x0000 #removed, these act as if all purchased now
|
||||
OP_UpdateLeadershipAA=0x0000 #removed, these act as if all purchased now
|
||||
OP_MarkNPC=0x0000
|
||||
OP_ClearNPCMarks=0x0000
|
||||
OP_DelegateAbility=0x0000
|
||||
OP_SetGroupTarget=0x0000
|
||||
OP_Charm=0x2509
|
||||
OP_Stun=0x7f1d
|
||||
OP_SendFindableNPCs=0x0000
|
||||
OP_FindPersonRequest=0x0000
|
||||
OP_FindPersonReply=0x0000
|
||||
OP_Sound=0x5949
|
||||
OP_CashReward=0x3237
|
||||
OP_PetBuffWindow=0x0000
|
||||
OP_LevelAppearance=0x5eb5
|
||||
OP_Translocate=0x0611
|
||||
OP_Sacrifice=0x4b76
|
||||
OP_PopupResponse=0x4032
|
||||
OP_OnLevelMessage=0x552e
|
||||
OP_AugmentInfo=0x19eb
|
||||
OP_Petition=0x0000
|
||||
OP_SomeItemPacketMaybe=0x0000
|
||||
OP_PVPStats=0x0000
|
||||
OP_PVPLeaderBoardRequest=0x0000
|
||||
OP_PVPLeaderBoardReply=0x0000
|
||||
OP_PVPLeaderBoardDetailsRequest=0x0000
|
||||
OP_PVPLeaderBoardDetailsReply=0x0000
|
||||
OP_RestState=0x1930
|
||||
OP_RespawnWindow=0x5c
|
||||
OP_LDoNButton=0x0000
|
||||
OP_SetStartCity=0x0000
|
||||
OP_VoiceMacroIn=0x2963
|
||||
OP_VoiceMacroOut=0x028d
|
||||
OP_ItemViewUnknown=0x0000
|
||||
OP_VetRewardsAvaliable=0x0000
|
||||
OP_VetClaimRequest=0x0000
|
||||
OP_VetClaimReply=0x0000
|
||||
OP_DisciplineUpdate=0x0a2f
|
||||
OP_DisciplineTimer=0x2782
|
||||
OP_BecomeCorpse=0x0000 # Unused?
|
||||
OP_Action2=0x0000 # Unused?
|
||||
OP_MobUpdate=0x0000
|
||||
OP_NPCMoveUpdate=0x0000
|
||||
OP_CameraEffect=0x3352
|
||||
OP_SpellEffect=0x7ea2
|
||||
OP_AddNimbusEffect=0x54b1
|
||||
OP_RemoveNimbusEffect=0x4e88
|
||||
OP_AltCurrency=0x0000
|
||||
OP_AltCurrencyMerchantRequest=0x0000
|
||||
OP_AltCurrencyMerchantReply=0x0000
|
||||
OP_AltCurrencyPurchase=0x0000
|
||||
OP_AltCurrencySell=0x0000
|
||||
OP_AltCurrencySellSelection=0x0000
|
||||
OP_AltCurrencyReclaim=0x0000
|
||||
OP_CrystalCountUpdate=0x0000
|
||||
OP_CrystalCreate=0x0000
|
||||
OP_CrystalReclaim=0x0000
|
||||
OP_Untargetable=0x6205
|
||||
OP_IncreaseStats=0x1312
|
||||
OP_Weblink=0x41f7
|
||||
OP_OpenContainer=0x1e8a
|
||||
OP_Marquee=0x257c
|
||||
OP_ItemRecastDelay=0x0fe4
|
||||
#OP_OpenInventory=0x0000 # Likely does not exist in RoF -U
|
||||
OP_ResetAA=0x3126
|
||||
OP_Fling=0x1101
|
||||
OP_CancelSneakHide=0x14b0
|
||||
OP_AggroMeterLockTarget=0x0000
|
||||
OP_AggroMeterTargetInfo=0x0000
|
||||
OP_AggroMeterUpdate=0x0000
|
||||
OP_UnderWorld=0x156c # clients sends up when they detect an underworld issue, might be useful for cheat detection
|
||||
OP_KickPlayers=0x1257
|
||||
OP_BookButton=0x4e78
|
||||
|
||||
# Expeditions
|
||||
OP_DzQuit=0x0000
|
||||
OP_DzListTimers=0x0000
|
||||
OP_DzAddPlayer=0x0000
|
||||
OP_DzRemovePlayer=0x0000
|
||||
OP_DzSwapPlayer=0x0000
|
||||
OP_DzMakeLeader=0x0000
|
||||
OP_DzPlayerList=0x0000
|
||||
OP_DzExpeditionInvite=0x0000
|
||||
OP_DzExpeditionInviteResponse=0x0000
|
||||
OP_DzExpeditionInfo=0x0000
|
||||
OP_DzExpeditionLockoutTimers=0x0000
|
||||
OP_DzMemberList=0x0000
|
||||
OP_DzMemberListName=0x0000
|
||||
OP_DzMemberListStatus=0x0000
|
||||
OP_DzSetLeaderName=0x0000
|
||||
OP_DzExpeditionEndsWarning=0x0000
|
||||
OP_DzCompass=0x0000
|
||||
OP_DzChooseZone=0x0000
|
||||
OP_DzChooseZoneReply=0x0000
|
||||
|
||||
# New Opcodes
|
||||
OP_SpawnPositionUpdate=0x0000 # Actually OP_MobUpdate ?
|
||||
OP_ManaUpdate=0x0000
|
||||
OP_EnduranceUpdate=0x0000
|
||||
OP_MobManaUpdate=0x0000
|
||||
OP_MobEnduranceUpdate=0x0000
|
||||
|
||||
# Mercenary Opcodes
|
||||
OP_MercenaryDataUpdateRequest=0x0000
|
||||
OP_MercenaryDataUpdate=0x0000
|
||||
OP_MercenaryDataRequest=0x0000
|
||||
OP_MercenaryDataResponse=0x0000
|
||||
OP_MercenaryHire=0x0000
|
||||
OP_MercenaryDismiss=0x0000
|
||||
OP_MercenaryTimerRequest=0x0000
|
||||
OP_MercenaryTimer=0x0000
|
||||
OP_MercenaryUnknown1=0x0000
|
||||
OP_MercenaryCommand=0x0000
|
||||
OP_MercenarySuspendRequest=0x0000
|
||||
OP_MercenarySuspendResponse=0x0000
|
||||
OP_MercenaryUnsuspendResponse=0x0000
|
||||
|
||||
# Looting
|
||||
OP_LootRequest=0x2239
|
||||
OP_EndLootRequest=0x173c
|
||||
OP_LootItem=0x5241
|
||||
OP_LootComplete=0x5470
|
||||
|
||||
# bazaar trader stuff:
|
||||
OP_BazaarSearch=0x0000
|
||||
OP_TraderDelItem=0x0000
|
||||
OP_BecomeTrader=0x0000
|
||||
OP_TraderShop=0x0000
|
||||
OP_TraderBulkSend=0x0000
|
||||
OP_Trader=0x0000
|
||||
OP_Barter=0x0000
|
||||
OP_BuyerItems=0x0000
|
||||
OP_TraderBuy=0x0000
|
||||
OP_ShopItem=0x0000
|
||||
OP_BazaarInspect=0x0000
|
||||
OP_Bazaar=0x0000
|
||||
OP_TraderItemUpdate=0x0000
|
||||
|
||||
# pc/npc trading
|
||||
OP_TradeRequest=0x1f5d
|
||||
OP_TradeAcceptClick=0x1d90
|
||||
OP_TradeRequestAck=0x2737
|
||||
OP_TradeCoins=0x63d8
|
||||
OP_FinishTrade=0x0875
|
||||
OP_CancelTrade=0x5fb5
|
||||
OP_TradeMoneyUpdate=0x544d
|
||||
OP_MoneyUpdate=0x578a
|
||||
OP_TradeBusy=0x43b8
|
||||
|
||||
# Sent after canceling trade or after closing tradeskill object
|
||||
OP_FinishWindow=0x1935
|
||||
OP_FinishWindow2=0x5458
|
||||
|
||||
# Sent on Live for what seems to be item existance verification
|
||||
# Ex. Before Right Click Effect happens from items
|
||||
OP_ItemVerifyRequest=0x4d8e
|
||||
OP_ItemVerifyReply=0x0bce
|
||||
|
||||
OP_ItemAdvancedLoreText=0x0000
|
||||
|
||||
# merchant stuff
|
||||
OP_ShopPlayerSell=0x5d8e
|
||||
OP_ShopRequest=0x25d0
|
||||
OP_ShopEnd=0x3e98
|
||||
OP_ShopEndConfirm=0x493d
|
||||
OP_ShopPlayerBuy=0x0696
|
||||
OP_ShopDelItem=0x0672
|
||||
OP_ShopSendParcel=0x3d05
|
||||
OP_ShopDeleteParcel=0x109b
|
||||
OP_ShopRetrieveParcel=0x5d5b
|
||||
OP_ShopParcelIcon=0x1936
|
||||
|
||||
# tradeskill stuff:
|
||||
OP_ClickObject=0x6693
|
||||
OP_ClickObjectAction=0x3dbe
|
||||
OP_ClearObject=0x3df2
|
||||
OP_RecipeDetails=0x400f
|
||||
OP_RecipesFavorite=0x2d6b
|
||||
OP_RecipesSearch=0x1a3a
|
||||
OP_RecipeReply=0x3e33
|
||||
OP_RecipeAutoCombine=0x5257
|
||||
OP_TradeSkillCombine=0x40af
|
||||
|
||||
# Tribute Packets:
|
||||
OP_TributeUpdate=0x0000
|
||||
OP_TributeTimer=0x0000
|
||||
OP_SendTributes=0x0000
|
||||
OP_RequestGuildTributes=0x0000
|
||||
OP_TributeInfo=0x0000
|
||||
OP_OpenTributeMaster=0x0000
|
||||
OP_SelectTribute=0x0000
|
||||
OP_TributeItem=0x0000
|
||||
OP_TributeMoney=0x0000
|
||||
OP_TributeToggle=0x0000
|
||||
OP_TributePointUpdate=0x0000
|
||||
OP_TributeNPC=0x0000
|
||||
OP_GuildTributeInfo=0x0000
|
||||
OP_OpenTributeReply=0x0000
|
||||
OP_GuildTributeStatus=0x0000
|
||||
OP_GuildSaveActiveTributes=0x0000
|
||||
OP_GuildSendActiveTributes=0x0000
|
||||
OP_GuildTributeToggleReq=0x0000
|
||||
OP_GuildTributeToggleReply=0x0000
|
||||
OP_GuildTributeFavorAndTimer=0x0000
|
||||
OP_GuildTributeDonateItem=0x0000
|
||||
OP_GuildTributeDonatePlat=0x0000
|
||||
OP_GuildSelectTribute=0x0000
|
||||
OP_GuildModifyBenefits=0x0000
|
||||
OP_GuildOptInOut=0x0000
|
||||
OP_SendGuildTributes=0x0000
|
||||
OP_OpenGuildTributeMaster=0x0000
|
||||
|
||||
# Adventure packets:
|
||||
OP_LeaveAdventure=0x0000
|
||||
OP_AdventureFinish=0x0000
|
||||
OP_AdventureInfoRequest=0x0000
|
||||
OP_AdventureInfo=0x0000
|
||||
OP_AdventureRequest=0x0000
|
||||
OP_AdventureDetails=0x0000
|
||||
OP_AdventureData=0x0000
|
||||
OP_AdventureUpdate=0x0000
|
||||
OP_AdventureMerchantRequest=0x0000
|
||||
OP_AdventureMerchantResponse=0x0000
|
||||
OP_AdventureMerchantPurchase=0x0000
|
||||
OP_AdventureMerchantSell=0x0000
|
||||
OP_AdventurePointsUpdate=0x0000
|
||||
OP_AdventureStatsRequest=0x0000
|
||||
OP_AdventureStatsReply=0x0000
|
||||
OP_AdventureLeaderboardRequest=0x0000
|
||||
OP_AdventureLeaderboardReply=0x0000
|
||||
|
||||
# Group Opcodes
|
||||
OP_GroupDisband=0x0573
|
||||
OP_GroupInvite=0x7e79
|
||||
OP_GroupFollow=0x0000
|
||||
OP_GroupUpdate=0x0000
|
||||
OP_GroupUpdateB=0x0000
|
||||
OP_GroupCancelInvite=0x0000
|
||||
OP_GroupAcknowledge=0x0000
|
||||
OP_GroupDelete=0x0000
|
||||
OP_CancelInvite=0x0000
|
||||
OP_GroupFollow2=0x0000
|
||||
OP_GroupInvite2=0x43b1
|
||||
OP_GroupDisbandYou=0x0000
|
||||
OP_GroupDisbandOther=0x0000
|
||||
OP_GroupLeaderChange=0x0000
|
||||
OP_GroupRoles=0x0000
|
||||
OP_GroupMakeLeader=0x0000
|
||||
OP_DoGroupLeadershipAbility=0x0000
|
||||
OP_GroupLeadershipAAUpdate=0x0000 # removed these act as if you have always purchased them
|
||||
OP_GroupMentor=0x0000
|
||||
OP_InspectBuffs=0x0000
|
||||
|
||||
# LFG/LFP Opcodes
|
||||
OP_LFGCommand=0x0000
|
||||
OP_LFGGetMatchesRequest=0x0000
|
||||
OP_LFGGetMatchesResponse=0x0000
|
||||
OP_LFPGetMatchesRequest=0x0000
|
||||
OP_LFPGetMatchesResponse=0x0000
|
||||
OP_LFPCommand=0x0000
|
||||
OP_LFGAppearance=0x0000
|
||||
OP_LFGResponse=0x0000
|
||||
|
||||
# Raid Opcodes
|
||||
OP_RaidInvite=0x0000
|
||||
OP_RaidUpdate=0x0000
|
||||
OP_RaidJoin=0x0000
|
||||
OP_RaidDelegateAbility=0x0000
|
||||
OP_MarkRaidNPC=0x0000
|
||||
OP_RaidClearNPCMarks=0x0000
|
||||
|
||||
# Button-push commands
|
||||
OP_Taunt=0x6ad9
|
||||
OP_CombatAbility=0x50e2
|
||||
OP_SenseTraps=0x235e
|
||||
OP_PickPocket=0x2c63
|
||||
OP_DisarmTraps=0x7362
|
||||
OP_Disarm=0x5a91
|
||||
OP_Sneak=0x7f05
|
||||
OP_Fishing=0x3cdb
|
||||
OP_InstillDoubt=0x3cdb
|
||||
OP_FeignDeath=0x3d9f
|
||||
OP_Mend=0x3bac
|
||||
OP_Bind_Wound=0x580f
|
||||
OP_LDoNOpen=0x7a62
|
||||
OP_LDoNPickLock=0x36ea
|
||||
OP_LDoNInspect=0x256a
|
||||
|
||||
# Task packets
|
||||
OP_TaskDescription=0x0000
|
||||
OP_TaskActivity=0x0000
|
||||
OP_CompletedTasks=0x0000
|
||||
OP_TaskActivityComplete=0x0000
|
||||
OP_AcceptNewTask=0x0000
|
||||
OP_CancelTask=0x0000
|
||||
OP_AvaliableTask=0x0000
|
||||
OP_TaskHistoryRequest=0x0000
|
||||
OP_TaskHistoryReply=0x0000
|
||||
OP_DeclineAllTasks=0x0000
|
||||
OP_TaskRequestTimer=0x0000
|
||||
OP_TaskSelectWindow=0x0000
|
||||
|
||||
# Shared Tasks
|
||||
OP_SharedTaskMemberList=0x0000 #
|
||||
OP_SharedTaskRemovePlayer=0x0000 # /taskremoveplayer
|
||||
OP_SharedTaskAddPlayer=0x0000 # /taskaddplayer
|
||||
OP_SharedTaskMakeLeader=0x0000 # /taskmakeleader
|
||||
OP_SharedTaskInvite=0x0000 # Dialog window
|
||||
OP_SharedTaskInviteResponse=0x0000 # Dialog window response
|
||||
OP_SharedTaskAcceptNew=0x0000 #
|
||||
OP_SharedTaskMemberChange=0x0000 #
|
||||
OP_TaskTimers=0x0000 # /tasktimers
|
||||
OP_SharedTaskQuit=0x0000 # /taskquit
|
||||
OP_SharedTaskSelectWindow=0x0000
|
||||
OP_SharedTaskPlayerList=0x0000 # /taskplayerlist
|
||||
|
||||
# Title opcodes
|
||||
OP_NewTitlesAvailable=0x0000
|
||||
OP_RequestTitles=0x0000
|
||||
OP_SendTitleList=0x0000
|
||||
OP_SetTitle=0x0000
|
||||
OP_SetTitleReply=0x0000
|
||||
|
||||
# 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=0x2e09
|
||||
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=0x0000 # OP_SendSpellChecksum
|
||||
#OP_LoginUnknown2=0x0000 # 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
|
||||
|
||||
#aura related
|
||||
OP_UpdateAura=0x0000
|
||||
OP_RemoveTrap=0x0000
|
||||
|
||||
OP_SystemFingerprint=0x52ef
|
||||
+4
-2
@@ -1223,8 +1223,10 @@ bool Client::Process() {
|
||||
}
|
||||
|
||||
if(connect.Check()){
|
||||
SendGuildList();// Send OPCode: OP_GuildsList
|
||||
SendApproveWorld();
|
||||
if (!(m_ClientVersionBit & EQ::versions::maskTOBAndLater)) {
|
||||
SendGuildList();// Send OPCode: OP_GuildsList
|
||||
SendApproveWorld();
|
||||
}
|
||||
connect.Disable();
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ set(zone_sources
|
||||
client_mods.cpp
|
||||
client_packet.cpp
|
||||
client_process.cpp
|
||||
client_version.cpp
|
||||
combat_record.cpp
|
||||
corpse.cpp
|
||||
dialogue_window.cpp
|
||||
@@ -130,6 +131,7 @@ set(zone_headers
|
||||
cheat_manager.h
|
||||
client.h
|
||||
client_packet.h
|
||||
client_version.h
|
||||
combat_record.h
|
||||
command.h
|
||||
common.h
|
||||
@@ -673,6 +675,8 @@ set_property(TARGET gm_commands_zone PROPERTY FOLDER libraries)
|
||||
|
||||
add_executable(zone ${zone_sources} ${zone_headers})
|
||||
|
||||
target_include_directories(zone PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
install(TARGETS zone RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
|
||||
if(EQEMU_BUILD_PCH)
|
||||
|
||||
+2
-2
@@ -5922,13 +5922,13 @@ bool Bot::CastSpell(
|
||||
|
||||
if (DivineAura()) {
|
||||
LogSpellsDetail("Spell casting canceled: cannot cast while Divine Aura is in effect");
|
||||
InterruptSpell(SPELL_FIZZLE, 0x121, false);
|
||||
InterruptSpell(SPELL_FIZZLE, Chat::SpellFailure, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (slot < EQ::spells::CastingSlot::MaxGems && !CheckFizzle(spell_id)) {
|
||||
int fizzle_msg = IsBardSong(spell_id) ? MISS_NOTE : SPELL_FIZZLE;
|
||||
InterruptSpell(fizzle_msg, 0x121, spell_id);
|
||||
InterruptSpell(fizzle_msg, Chat::SpellFailure, spell_id);
|
||||
|
||||
uint32 use_mana = ((spells[spell_id].mana) / 4);
|
||||
LogSpellsDetail("Spell casting canceled: fizzled. [{}] mana has been consumed", use_mana);
|
||||
|
||||
@@ -775,7 +775,7 @@ void helper_send_usage_required_bots(Client *bot_owner, uint16 spell_type)
|
||||
bot_owner->Message(Chat::Green, "%s", description.c_str());
|
||||
}
|
||||
|
||||
void SendSpellTypeWindow(Client* c, const Seperator* sep, bool short_names) {
|
||||
void SendSpellTypeWindow(Client* c, const Seperator* sep) {
|
||||
std::string arg0 = sep->arg[0];
|
||||
std::string arg1 = sep->arg[1];
|
||||
|
||||
@@ -828,7 +828,7 @@ void SendSpellTypeWindow(Client* c, const Seperator* sep, bool short_names) {
|
||||
std::string popup_text = DialogueWindow::TableRow(
|
||||
DialogueWindow::TableCell(DialogueWindow::ColorMessage(goldenrod, spell_type_field))
|
||||
+
|
||||
DialogueWindow::TableCell((!short_names ? DialogueWindow::ColorMessage(goldenrod, id_field) : DialogueWindow::ColorMessage(goldenrod, shortname_field)))
|
||||
DialogueWindow::TableCell((!arg0.compare("^spelltypeids") ? DialogueWindow::ColorMessage(goldenrod, id_field) : DialogueWindow::ColorMessage(goldenrod, shortname_field)))
|
||||
);
|
||||
|
||||
popup_text += DialogueWindow::TableRow(
|
||||
@@ -845,7 +845,7 @@ void SendSpellTypeWindow(Client* c, const Seperator* sep, bool short_names) {
|
||||
popup_text += DialogueWindow::TableRow(
|
||||
DialogueWindow::TableCell(DialogueWindow::ColorMessage(forest_green, Bot::GetSpellTypeNameByID(i)))
|
||||
+
|
||||
DialogueWindow::TableCell((!short_names ? DialogueWindow::ColorMessage(slate_blue, std::to_string(i)) : DialogueWindow::ColorMessage(slate_blue, Bot::GetSpellTypeShortNameByID(i))))
|
||||
DialogueWindow::TableCell((!arg0.compare("^spelltypeids") ? DialogueWindow::ColorMessage(slate_blue, std::to_string(i)) : DialogueWindow::ColorMessage(slate_blue, Bot::GetSpellTypeShortNameByID(i))))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1182,4 +1182,4 @@ bool helper_is_help_or_usage(const char* arg);
|
||||
bool helper_no_available_bots(Client *bot_owner, Bot *my_bot = nullptr);
|
||||
void helper_send_available_subcommands(Client *bot_owner, const char* command_simile, std::vector<const char*> subcommand_list);
|
||||
void helper_send_usage_required_bots(Client *bot_owner, uint16 spell_type);
|
||||
void SendSpellTypeWindow(Client* c, const Seperator* sep, bool short_names = false);
|
||||
void SendSpellTypeWindow(Client* c, const Seperator* sep);
|
||||
|
||||
@@ -24,5 +24,5 @@ void bot_command_spelltype_ids(Client* c, const Seperator* sep)
|
||||
|
||||
void bot_command_spelltype_names(Client* c, const Seperator* sep)
|
||||
{
|
||||
SendSpellTypeWindow(c, sep, true);
|
||||
SendSpellTypeWindow(c, sep);
|
||||
}
|
||||
|
||||
+91
-112
@@ -46,6 +46,7 @@
|
||||
#include "common/zone_store.h"
|
||||
#include "zone/bot_command.h"
|
||||
#include "zone/cheat_manager.h"
|
||||
#include "zone/client_version.h"
|
||||
#include "zone/command.h"
|
||||
#include "zone/dialogue_window.h"
|
||||
#include "zone/dynamic_zone.h"
|
||||
@@ -1205,7 +1206,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
|
||||
LogDebug("Client::ChannelMessageReceived() Channel:[{}] message:[{}]", chan_num, message);
|
||||
|
||||
if (RuleB(Chat, AlwaysCaptureCommandText)) {
|
||||
if (message[0] == COMMAND_CHAR) {
|
||||
if (message[0] == COMMAND_CHAR || message[0] == COMMAND_CHAR_NON_HASH) {
|
||||
if (command_dispatch(this, message, false) == -2) {
|
||||
if (parse->PlayerHasQuestSub(EVENT_COMMAND)) {
|
||||
int i = parse->EventPlayer(EVENT_COMMAND, this, message, 0);
|
||||
@@ -1538,7 +1539,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
|
||||
}
|
||||
}
|
||||
|
||||
if (message[0] == COMMAND_CHAR) {
|
||||
if (message[0] == COMMAND_CHAR || message[0] == COMMAND_CHAR_NON_HASH) {
|
||||
if (command_dispatch(this, message, false) == -2) {
|
||||
if (parse->PlayerHasQuestSub(EVENT_COMMAND)) {
|
||||
int i = parse->EventPlayer(EVENT_COMMAND, this, message, 0);
|
||||
@@ -1792,7 +1793,7 @@ void Client::Message(uint32 type, const char* message, ...) {
|
||||
}
|
||||
|
||||
void Client::FilteredMessage(Mob *sender, uint32 type, eqFilterType filter, const char* message, ...) {
|
||||
if (!FilteredMessageCheck(sender, filter))
|
||||
if (!ShouldGetPacket(sender, filter))
|
||||
return;
|
||||
|
||||
va_list argptr;
|
||||
@@ -3808,18 +3809,12 @@ void Client::MessageString(uint32 type, uint32 string_id, uint32 distance)
|
||||
return;
|
||||
if (GetFilter(FilterSpellCrits) == FilterHide && type == Chat::SpellCrit)
|
||||
return;
|
||||
auto outapp = new EQApplicationPacket(OP_SimpleMessage, 12);
|
||||
SimpleMessage_Struct* sms = (SimpleMessage_Struct*)outapp->pBuffer;
|
||||
sms->color=type;
|
||||
sms->string_id=string_id;
|
||||
|
||||
sms->unknown8=0;
|
||||
|
||||
if(distance>0)
|
||||
entity_list.QueueCloseClients(this,outapp,false,distance);
|
||||
if (distance > 0)
|
||||
Message::CloseMessageString(this, false, static_cast<float>(distance))(
|
||||
type, string_id);
|
||||
else
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
Message::MessageString(this, type, string_id);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -3829,9 +3824,9 @@ void Client::MessageString(uint32 type, uint32 string_id, uint32 distance)
|
||||
// This hack sucks but it's gonna work for now.
|
||||
//
|
||||
void Client::MessageString(uint32 type, uint32 string_id, const char* message1,
|
||||
const char* message2,const char* message3,const char* message4,
|
||||
const char* message5,const char* message6,const char* message7,
|
||||
const char* message8,const char* message9, uint32 distance)
|
||||
const char* message2, const char* message3, const char* message4,
|
||||
const char* message5, const char* message6, const char* message7,
|
||||
const char* message8, const char* message9, uint32 distance)
|
||||
{
|
||||
if (GetFilter(FilterSpellDamage) == FilterHide && type == Chat::NonMelee)
|
||||
return;
|
||||
@@ -3847,34 +3842,12 @@ void Client::MessageString(uint32 type, uint32 string_id, const char* message1,
|
||||
if (type == Chat::Emote)
|
||||
type = 4;
|
||||
|
||||
if (!message1) {
|
||||
MessageString(type, string_id); // use the simple message instead
|
||||
return;
|
||||
}
|
||||
|
||||
const char *message_arg[] = {
|
||||
message1, message2, message3, message4, message5,
|
||||
message6, message7, message8, message9
|
||||
};
|
||||
|
||||
SerializeBuffer buf(20);
|
||||
buf.WriteInt32(0); // unknown
|
||||
buf.WriteInt32(string_id);
|
||||
buf.WriteInt32(type);
|
||||
for (auto &m : message_arg) {
|
||||
if (m == nullptr)
|
||||
break;
|
||||
buf.WriteString(m);
|
||||
}
|
||||
|
||||
buf.WriteInt8(0); // prevent oob in packet translation, maybe clean that up sometime
|
||||
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(OP_FormattedMessage, std::move(buf));
|
||||
|
||||
if (distance > 0)
|
||||
entity_list.QueueCloseClients(this, outapp.get(), false, distance);
|
||||
Message::CloseMessageString(this, false, static_cast<float>(distance))(type, string_id, message1,
|
||||
message2, message3, message4, message5, message6, message7, message8, message9);
|
||||
else
|
||||
QueuePacket(outapp.get());
|
||||
Message::MessageString(this, type, string_id, message1, message2, message3, message4, message5,
|
||||
message6, message7, message8, message9);
|
||||
}
|
||||
|
||||
void Client::MessageString(const CZClientMessageString_Struct* msg)
|
||||
@@ -3898,60 +3871,49 @@ void Client::MessageString(const CZClientMessageString_Struct* msg)
|
||||
}
|
||||
}
|
||||
|
||||
// helper function, returns true if we should see the message
|
||||
bool Client::FilteredMessageCheck(Mob *sender, eqFilterType filter)
|
||||
// helper function, returns true if the client should get the packet based on the filter and sender
|
||||
bool Client::ShouldGetPacket(Mob *sender, eqFilterType filter)
|
||||
{
|
||||
eqFilterMode mode = GetFilter(filter);
|
||||
// easy ones first
|
||||
if (mode == FilterShow) {
|
||||
return true;
|
||||
} else if (mode == FilterHide) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sender != this && mode == FilterShowSelfOnly) {
|
||||
// easy ones first
|
||||
if (mode == FilterShow)
|
||||
return true;
|
||||
|
||||
if (mode == FilterHide)
|
||||
return false;
|
||||
} else if (sender) {
|
||||
if (mode == FilterShowGroupOnly) {
|
||||
auto g = GetGroup();
|
||||
auto r = GetRaid();
|
||||
if (g) {
|
||||
if (g->IsGroupMember(sender)) {
|
||||
return true;
|
||||
}
|
||||
} else if (r && sender->IsClient()) {
|
||||
auto rgid1 = r->GetGroup(this);
|
||||
auto rgid2 = r->GetGroup(sender->CastToClient());
|
||||
if (rgid1 != RAID_GROUPLESS && rgid1 == rgid2) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sender != this && mode == FilterShowSelfOnly)
|
||||
return false;
|
||||
|
||||
if (sender != nullptr && mode == FilterShowGroupOnly) {
|
||||
if (sender == this)
|
||||
return true;
|
||||
|
||||
Group* g = GetGroup();
|
||||
if (g && g->IsGroupMember(sender))
|
||||
return true;
|
||||
|
||||
Raid* r = GetRaid();
|
||||
if (r && sender->IsClient()) {
|
||||
uint32 rgid1 = r->GetGroup(this);
|
||||
uint32 rgid2 = r->GetGroup(sender->CastToClient());
|
||||
if (rgid1 != RAID_GROUPLESS && rgid1 == rgid2)
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// we passed our checks
|
||||
// fallback case (send by default)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Client::FilteredMessageString(Mob *sender, uint32 type,
|
||||
eqFilterType filter, uint32 string_id)
|
||||
{
|
||||
if (!FilteredMessageCheck(sender, filter))
|
||||
return;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_SimpleMessage, 12);
|
||||
SimpleMessage_Struct *sms = (SimpleMessage_Struct *)outapp->pBuffer;
|
||||
sms->color = type;
|
||||
sms->string_id = string_id;
|
||||
|
||||
sms->unknown8 = 0;
|
||||
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
return;
|
||||
if (ShouldGetPacket(sender, filter))
|
||||
MessageString(type, string_id);
|
||||
}
|
||||
|
||||
void Client::FilteredMessageString(Mob *sender, uint32 type, eqFilterType filter, uint32 string_id,
|
||||
@@ -3959,37 +3921,16 @@ void Client::FilteredMessageString(Mob *sender, uint32 type, eqFilterType filter
|
||||
const char *message4, const char *message5, const char *message6,
|
||||
const char *message7, const char *message8, const char *message9)
|
||||
{
|
||||
if (!FilteredMessageCheck(sender, filter))
|
||||
return;
|
||||
|
||||
if (type == Chat::Emote)
|
||||
type = 4;
|
||||
|
||||
if (!message1) {
|
||||
FilteredMessageString(sender, type, filter, string_id); // use the simple message instead
|
||||
return;
|
||||
} else if (ShouldGetPacket(sender, filter)) {
|
||||
if (type == Chat::Emote)
|
||||
type = 4;
|
||||
|
||||
MessageString(
|
||||
type, string_id, message1, message2, message3, message4,
|
||||
message5, message6, message7, message8, message9);
|
||||
}
|
||||
|
||||
const char *message_arg[] = {
|
||||
message1, message2, message3, message4, message5,
|
||||
message6, message7, message8, message9
|
||||
};
|
||||
|
||||
SerializeBuffer buf(20);
|
||||
buf.WriteInt32(0); // unknown
|
||||
buf.WriteInt32(string_id);
|
||||
buf.WriteInt32(type);
|
||||
for (auto &m : message_arg) {
|
||||
if (m == nullptr)
|
||||
break;
|
||||
buf.WriteString(m);
|
||||
}
|
||||
|
||||
buf.WriteInt8(0); // prevent oob in packet translation, maybe clean that up sometime
|
||||
|
||||
auto outapp = std::make_unique<EQApplicationPacket>(OP_FormattedMessage, std::move(buf));
|
||||
|
||||
QueuePacket(outapp.get());
|
||||
}
|
||||
|
||||
void Client::Tell_StringID(uint32 string_id, const char *who, const char *message)
|
||||
@@ -8133,7 +8074,7 @@ void Client::GarbleMessage(char *message, uint8 variance)
|
||||
int delimiter_count = 0;
|
||||
|
||||
// Don't garble # commands
|
||||
if (message[0] == COMMAND_CHAR || message[0] == BOT_COMMAND_CHAR) {
|
||||
if (message[0] == COMMAND_CHAR || message[0] == COMMAND_CHAR_NON_HASH || message[0] == BOT_COMMAND_CHAR) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -9208,6 +9149,44 @@ void Client::SendHPUpdateMarquee(){
|
||||
SendMarqueeMessage(Chat::Yellow, 510, 0, 3000, 3000, health_update_notification);
|
||||
}
|
||||
|
||||
void Client::SendMembership() {
|
||||
if (m_ClientVersion >= EQ::versions::ClientVersion::TOB) {
|
||||
auto outapp = new EQApplicationPacket(OP_SendMembership, sizeof(Membership_Struct));
|
||||
Membership_Struct* mc = (Membership_Struct*)outapp->pBuffer;
|
||||
|
||||
mc->membership = 2; //Hardcode to gold for now. We don't use anything else.
|
||||
mc->races = 0x1ffff; // Available Races (4110 for silver)
|
||||
mc->classes = 0x1ffff; // Available Classes (4614 for silver) - Was 0x101ffff
|
||||
mc->entrysize = 21; // Number of membership setting entries below
|
||||
mc->entries[0] = 0xffffffff; // Max AA Restriction
|
||||
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] = 0xffffffff; // 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
|
||||
mc->entries[8] = 1; // 1 for Silver
|
||||
mc->entries[9] = 0xffffffff; // Unknown - Maybe Loyalty Points every 12 hours? 60 per week for Silver
|
||||
mc->entries[10] = 1; // 1 for Silver
|
||||
mc->entries[11] = 0xffffffff; // Shared Bank Slots
|
||||
mc->entries[12] = 0xffffffff; // Unknown - Maybe Max Active Tasks?
|
||||
mc->entries[13] = 1; // 1 for Silver
|
||||
mc->entries[14] = 1; // 0 for Silver
|
||||
mc->entries[15] = 1; // 0 for Silver
|
||||
mc->entries[16] = 1; // 1 for Silver
|
||||
mc->entries[17] = 1; // 0 for Silver
|
||||
mc->entries[18] = 1; // 0 for Silver
|
||||
mc->entries[19] = 0xffffffff; // 0 for Silver
|
||||
mc->entries[20] = 0xffffffff; // 0 for Silver
|
||||
mc->exit_url_length = 0;
|
||||
//mc->exit_url = 0; // Used on Live: "http://www.everquest.com/free-to-play/exit-silver"
|
||||
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
}
|
||||
|
||||
uint32 Client::GetMoney(uint8 type, uint8 subtype) {
|
||||
uint32 value = 0;
|
||||
|
||||
|
||||
+6
-4
@@ -343,10 +343,10 @@ public:
|
||||
void DyeArmor(EQ::TintProfile* dye);
|
||||
void DyeArmorBySlot(uint8 slot, uint8 red, uint8 green, uint8 blue, uint8 use_tint = 0x00);
|
||||
uint8 SlotConvert(uint8 slot,bool bracer=false);
|
||||
void MessageString(uint32 type, uint32 string_id, uint32 distance = 0);
|
||||
void MessageString(uint32 type, uint32 string_id, const char* message,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0, uint32 distance = 0);
|
||||
void MessageString(uint32 type, uint32 string_id, uint32 distance = 0) override;
|
||||
void MessageString(uint32 type, uint32 string_id, const char* message,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0, uint32 distance = 0) override;
|
||||
void MessageString(const CZClientMessageString_Struct* msg);
|
||||
bool FilteredMessageCheck(Mob *sender, eqFilterType filter);
|
||||
bool ShouldGetPacket(Mob *sender, eqFilterType filter);
|
||||
void FilteredMessageString(Mob *sender, uint32 type, eqFilterType filter, uint32 string_id);
|
||||
void FilteredMessageString(Mob *sender, uint32 type, eqFilterType filter,
|
||||
uint32 string_id, const char *message1, const char *message2 = nullptr,
|
||||
@@ -1550,7 +1550,8 @@ public:
|
||||
|
||||
inline const EQ::versions::ClientVersion ClientVersion() const { return m_ClientVersion; }
|
||||
inline const uint32 ClientVersionBit() const { return m_ClientVersionBit; }
|
||||
inline void SetClientVersion(EQ::versions::ClientVersion client_version) { m_ClientVersion = client_version; }
|
||||
void SetClientVersion(EQ::versions::ClientVersion client_version);
|
||||
EQ::versions::ClientVersion GetClientVersion() const;
|
||||
|
||||
/** Adventure Stuff **/
|
||||
void SendAdventureError(const char *error);
|
||||
@@ -1856,6 +1857,7 @@ public:
|
||||
void ResetHPUpdateTimer() { hpupdate_timer.Start(); }
|
||||
|
||||
void SendHPUpdateMarquee();
|
||||
void SendMembership();
|
||||
|
||||
void CheckRegionTypeChanges();
|
||||
|
||||
|
||||
+58
-93
@@ -105,7 +105,6 @@ void MapOpcodes()
|
||||
ConnectingOpcodes[OP_ZoneEntry] = &Client::Handle_Connect_OP_ZoneEntry;
|
||||
|
||||
// connected opcode handler assignments:
|
||||
ConnectedOpcodes[OP_0x0193] = &Client::Handle_0x0193;
|
||||
ConnectedOpcodes[OP_AAAction] = &Client::Handle_OP_AAAction;
|
||||
ConnectedOpcodes[OP_AcceptNewTask] = &Client::Handle_OP_AcceptNewTask;
|
||||
ConnectedOpcodes[OP_AdventureInfoRequest] = &Client::Handle_OP_AdventureInfoRequest;
|
||||
@@ -1240,9 +1239,6 @@ void Client::Handle_Connect_OP_WorldObjectsSent(const EQApplicationPacket *app)
|
||||
|
||||
void Client::Handle_Connect_OP_ZoneComplete(const EQApplicationPacket *app)
|
||||
{
|
||||
auto outapp = new EQApplicationPacket(OP_0x0347, 0);
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1705,10 +1701,8 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
if ((m_pp.RestTimer > RuleI(Character, RestRegenTimeToActivate)) && (m_pp.RestTimer > RuleI(Character, RestRegenRaidTimeToActivate)))
|
||||
m_pp.RestTimer = 0;
|
||||
|
||||
/* This checksum should disappear once dynamic structs are in... each struct strategy will do it */ // looks to be in place now
|
||||
//CRC32::SetEQChecksum((unsigned char*)&m_pp, sizeof(PlayerProfile_Struct) - sizeof(m_pp.m_player_profile_version) - 4);
|
||||
// m_pp.checksum = 0; // All server out-bound player profile packets are now translated - no need to waste cycles calculating this...
|
||||
|
||||
SendMembership();
|
||||
|
||||
outapp = new EQApplicationPacket(OP_PlayerProfile, sizeof(PlayerProfile_Struct));
|
||||
|
||||
/* The entityid field in the Player Profile is used by the Client in relation to Group Leadership AA */
|
||||
@@ -1882,16 +1876,6 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
// connected opcode handlers
|
||||
void Client::Handle_0x0193(const EQApplicationPacket *app)
|
||||
{
|
||||
// Not sure what this opcode does. It started being sent when OP_ClientUpdate was
|
||||
// changed to pump OP_ClientUpdate back out instead of OP_MobUpdate
|
||||
// 2 bytes: 00 00
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::Handle_OP_AAAction(const EQApplicationPacket *app)
|
||||
{
|
||||
LogAA("Received OP_AAAction");
|
||||
@@ -4277,21 +4261,30 @@ void Client::Handle_OP_Camp(const EQApplicationPacket *app)
|
||||
|
||||
if (IsLFP())
|
||||
worldserver.StopLFP(CharacterID());
|
||||
|
||||
if (GetGM())
|
||||
{
|
||||
if (RuleB(Character, EnableHackedFastCampForGM))
|
||||
{
|
||||
camp_timer.Start(100, true);
|
||||
}
|
||||
else {
|
||||
OnDisconnect(true);
|
||||
|
||||
if (ClientVersion() >= EQ::versions::ClientVersion::TOB) {
|
||||
if (!GetGM()) {
|
||||
camp_timer.Start(29000, true);
|
||||
}
|
||||
|
||||
return;
|
||||
auto outapp = new EQApplicationPacket(OP_Camp, 1);
|
||||
FastQueuePacket(&outapp);
|
||||
}
|
||||
else {
|
||||
if (GetGM())
|
||||
{
|
||||
if (RuleB(Character, EnableHackedFastCampForGM))
|
||||
{
|
||||
camp_timer.Start(100, true);
|
||||
}
|
||||
else {
|
||||
OnDisconnect(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
camp_timer.Start(29000, true);
|
||||
camp_timer.Start(29000, true);
|
||||
}
|
||||
|
||||
if (RuleB(Bots, Enabled)) {
|
||||
bot_camp_timer.Start((RuleI(Bots, CampTimer) * 1000), true);
|
||||
@@ -8919,31 +8912,20 @@ void Client::Handle_OP_Hide(const EQApplicationPacket *app)
|
||||
tmHidden = Timer::GetCurrentTime();
|
||||
}
|
||||
if (GetClass() == Class::Rogue) {
|
||||
auto outapp = new EQApplicationPacket(OP_SimpleMessage, sizeof(SimpleMessage_Struct));
|
||||
SimpleMessage_Struct *msg = (SimpleMessage_Struct *)outapp->pBuffer;
|
||||
msg->color = 0x010E;
|
||||
Mob *evadetar = GetTarget();
|
||||
if (!auto_attack && (evadetar && evadetar->CheckAggro(this)
|
||||
&& evadetar->IsNPC())) {
|
||||
uint32 string_id = HIDE_FAIL;
|
||||
Mob* evadetar = GetTarget();
|
||||
|
||||
if (!auto_attack && evadetar && evadetar->CheckAggro(this) && evadetar->IsNPC()) {
|
||||
if (zone->random.Int(0, 260) < (int)GetSkill(EQ::skills::SkillHide)) {
|
||||
msg->string_id = EVADE_SUCCESS;
|
||||
string_id = EVADE_SUCCESS;
|
||||
RogueEvade(evadetar);
|
||||
}
|
||||
else {
|
||||
msg->string_id = EVADE_FAIL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (hidden) {
|
||||
msg->string_id = HIDE_SUCCESS;
|
||||
}
|
||||
else {
|
||||
msg->string_id = HIDE_FAIL;
|
||||
}
|
||||
}
|
||||
FastQueuePacket(&outapp);
|
||||
} else
|
||||
string_id = EVADE_FAIL;
|
||||
} else if (hidden)
|
||||
string_id = HIDE_SUCCESS;
|
||||
|
||||
MessageString(Chat::Skills, string_id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::Handle_OP_HideCorpse(const EQApplicationPacket *app)
|
||||
@@ -10332,10 +10314,10 @@ void Client::Handle_OP_ManaChange(const EQApplicationPacket *app)
|
||||
if (app->size == 0) {
|
||||
// i think thats the sign to stop the songs
|
||||
if (IsBardSong(casting_spell_id) || HasActiveSong()) {
|
||||
InterruptSpell(SONG_ENDS, 0x121); //Live doesn't send song end message anymore (~Kayen 1/26/22)
|
||||
InterruptSpell(SONG_ENDS, Chat::SpellFailure); //Live doesn't send song end message anymore (~Kayen 1/26/22)
|
||||
}
|
||||
else {
|
||||
InterruptSpell(INTERRUPT_SPELL, 0x121);
|
||||
InterruptSpell(INTERRUPT_SPELL, Chat::SpellFailure);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -12346,6 +12328,9 @@ void Client::Handle_OP_QueryUCSServerStatus(const EQApplicationPacket *app)
|
||||
case EQ::versions::ClientVersion::RoF2:
|
||||
ConnectionType = EQ::versions::ucsRoF2Combined;
|
||||
break;
|
||||
case EQ::versions::ClientVersion::TOB:
|
||||
ConnectionType = EQ::versions::ucsTOBCombined;
|
||||
break;
|
||||
default:
|
||||
ConnectionType = EQ::versions::ucsUnknown;
|
||||
break;
|
||||
@@ -14378,8 +14363,9 @@ void Client::Handle_OP_ShopPlayerSell(const EQApplicationPacket *app)
|
||||
sizeof(Merchant_Purchase_Struct), app->size);
|
||||
return;
|
||||
}
|
||||
|
||||
RDTSC_Timer t1(true);
|
||||
Merchant_Purchase_Struct* mp = (Merchant_Purchase_Struct*)app->pBuffer;
|
||||
|
||||
Mob* vendor = entity_list.GetMob(mp->npcid);
|
||||
|
||||
if (vendor == 0 || !vendor->IsNPC() || vendor->GetClass() != Class::Merchant)
|
||||
@@ -14389,51 +14375,35 @@ void Client::Handle_OP_ShopPlayerSell(const EQApplicationPacket *app)
|
||||
if (DistanceSquared(m_Position, vendor->GetPosition()) > USE_NPC_RANGE2)
|
||||
return;
|
||||
|
||||
uint32 price = 0;
|
||||
uint32 itemid = GetItemIDAt(mp->itemslot);
|
||||
if (itemid == 0)
|
||||
return;
|
||||
|
||||
const EQ::ItemData* item = database.GetItem(itemid);
|
||||
EQ::ItemInstance* inst = GetInv().GetItem(mp->itemslot);
|
||||
if (!item || !inst) {
|
||||
Message(Chat::Red, "You seem to have misplaced that item..");
|
||||
Message(Chat::Red, "You seemed to have misplaced that item..");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!item->NoDrop) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mp->quantity > 1) {
|
||||
if (mp->quantity > 1)
|
||||
{
|
||||
if ((inst->GetCharges() < 0) || (mp->quantity > (uint32)inst->GetCharges()))
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for veto from script
|
||||
if (parse->PlayerHasQuestSub(EVENT_MERCHANT_PRESELL)) {
|
||||
std::string export_string = fmt::format("{} {} {}", mp->itemslot, itemid, inst->GetItemType());
|
||||
std::vector<std::any> extra_pointers = { vendor, inst };
|
||||
|
||||
int result = parse->EventPlayer(EVENT_MERCHANT_PRESELL, this, export_string, 0, &extra_pointers);
|
||||
// CANCEL: If a script returns -1 for this event, the sale wil be cancelled. Sends a dummy packet sent to satisfy the client
|
||||
if (result == -1) {
|
||||
auto outapp = new EQApplicationPacket(OP_ShopPlayerSell, sizeof(Merchant_Purchase_Struct));
|
||||
Merchant_Purchase_Struct* mco = (Merchant_Purchase_Struct*)outapp->pBuffer;
|
||||
mco->npcid = vendor->GetID();
|
||||
mco->itemslot = -1; // Critical or the client will remove the item visually
|
||||
mco->quantity = 0;
|
||||
mco->price = 0;
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
}
|
||||
if (!item->NoDrop) {
|
||||
//Message(Chat::Red,"%s tells you, 'LOL NOPE'", vendor->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 cost_quantity = inst->IsCharged() ? 1 : mp->quantity;
|
||||
uint32 price = 0;
|
||||
uint32 cost_quantity = mp->quantity;
|
||||
if (inst->IsCharged())
|
||||
uint32 cost_quantity = 1;
|
||||
|
||||
uint32 i;
|
||||
|
||||
if (RuleB(Merchant, UsePriceMod)) {
|
||||
for (uint32 i = 1; i <= cost_quantity; i++) {
|
||||
for (i = 1; i <= cost_quantity; i++) {
|
||||
price = (uint32)(item->Price * i) * Client::CalcPriceMod(vendor, true);
|
||||
|
||||
// Don't use SellCostMod if using UseClassicPriceMod
|
||||
@@ -14451,7 +14421,7 @@ void Client::Handle_OP_ShopPlayerSell(const EQApplicationPacket *app)
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (uint32 i = 1; i <= cost_quantity; i++) {
|
||||
for (i = 1; i <= cost_quantity; i++) {
|
||||
price = (uint32)((item->Price * i)*(RuleR(Merchant, BuyCostMod)) + 0.5); // need to round up, because client does it automatically when displaying price
|
||||
if (price > 4000000000) {
|
||||
cost_quantity = i;
|
||||
@@ -14463,7 +14433,6 @@ void Client::Handle_OP_ShopPlayerSell(const EQApplicationPacket *app)
|
||||
|
||||
AddMoneyToPP(price);
|
||||
|
||||
// Update merchant stock and refresh client
|
||||
if (inst->IsStackable() || inst->IsCharged())
|
||||
{
|
||||
unsigned int i_quan = inst->GetCharges();
|
||||
@@ -14577,8 +14546,6 @@ void Client::Handle_OP_ShopPlayerSell(const EQApplicationPacket *app)
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
SendMoneyUpdate();
|
||||
|
||||
RDTSC_Timer t1(true);
|
||||
t1.start();
|
||||
Save(1);
|
||||
t1.stop();
|
||||
@@ -14686,7 +14653,10 @@ void Client::Handle_OP_ShopRequest(const EQApplicationPacket *app)
|
||||
mco->rate = 1 / buy_cost_mod;
|
||||
}
|
||||
|
||||
outapp->priority = 6;
|
||||
if (m_ClientVersion >= EQ::versions::ClientVersion::TOB) {
|
||||
mco->player_id = GetID();
|
||||
}
|
||||
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
@@ -14697,11 +14667,6 @@ void Client::Handle_OP_ShopRequest(const EQApplicationPacket *app)
|
||||
if ((tabs_to_display & Parcel) == Parcel) {
|
||||
SendBulkParcels();
|
||||
}
|
||||
|
||||
if (parse->PlayerHasQuestSub(EVENT_MERCHANT_OPEN)) {
|
||||
std::vector<std::any> extra_pointers = { tmp };
|
||||
parse->EventPlayer(EVENT_MERCHANT_OPEN, this, "", 0, &extra_pointers);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
@@ -38,8 +38,6 @@
|
||||
void Handle_Connect_OP_ZoneComplete(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app);
|
||||
/* Connected opcode handlers*/
|
||||
void Handle_0x0193(const EQApplicationPacket *app);
|
||||
void Handle_0x01e7(const EQApplicationPacket *app);
|
||||
void Handle_OP_AAAction(const EQApplicationPacket *app);
|
||||
void Handle_OP_AcceptNewTask(const EQApplicationPacket *app);
|
||||
void Handle_OP_AdventureInfoRequest(const EQApplicationPacket *app);
|
||||
|
||||
@@ -229,11 +229,11 @@ bool Client::Process() {
|
||||
}
|
||||
|
||||
if (song_target == nullptr) {
|
||||
InterruptSpell(SONG_ENDS_ABRUPTLY, 0x121, bardsong);
|
||||
InterruptSpell(SONG_ENDS_ABRUPTLY, Chat::SpellFailure, bardsong);
|
||||
}
|
||||
else {
|
||||
if (!ApplyBardPulse(bardsong, song_target, bardsong_slot)) {
|
||||
InterruptSpell(SONG_ENDS_ABRUPTLY, 0x121, bardsong);
|
||||
InterruptSpell(SONG_ENDS_ABRUPTLY, Chat::SpellFailure, bardsong);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/* EQEmu: EQEmulator
|
||||
|
||||
Copyright (C) 2001-2026 EQEmu Development Team
|
||||
|
||||
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; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "client_version.h"
|
||||
|
||||
using Version = EQ::versions::ClientVersion;
|
||||
|
||||
void Client::SetClientVersion(Version client_version)
|
||||
{
|
||||
m_ClientVersion = client_version;
|
||||
m_ClientVersionBit = EQ::versions::ConvertClientVersionToClientVersionBit(client_version);
|
||||
}
|
||||
|
||||
Version Client::GetClientVersion() const { return m_ClientVersion; }
|
||||
@@ -0,0 +1,150 @@
|
||||
//
|
||||
// Created by dannu on 4/21/2026.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "common/emu_versions.h"
|
||||
#include "common/patches/client_version.h"
|
||||
#include "common/patches/IMessage.h"
|
||||
|
||||
#include "zone/client.h"
|
||||
#include "zone/mob.h"
|
||||
|
||||
// store all _generic_ static functions for the different patches here
|
||||
namespace ClientPatch {
|
||||
|
||||
using ClientList = std::unordered_map<uint16, Client*>;
|
||||
template<typename Obj> using ComponentGetter = std::function<Obj*(const Client*)>;
|
||||
|
||||
template <typename Fun, typename Obj, typename... Args>
|
||||
requires std::is_member_function_pointer_v<Fun>
|
||||
static void QueuePacket(Client* c, Fun fun, Obj* obj, Args&&... args)
|
||||
{
|
||||
if (obj != nullptr) {
|
||||
std::unique_ptr<EQApplicationPacket> app = std::invoke(fun, obj, std::forward<Args>(args)...);
|
||||
if (app)
|
||||
c->QueuePacket(app.get());
|
||||
}
|
||||
}
|
||||
|
||||
// packet generator queue functions
|
||||
static auto QueueClients(Mob* sender, bool ignore_sender = false, bool ackreq = true)
|
||||
{
|
||||
return [=]<typename Fun, typename Obj, typename... Args>(Fun fun, const ComponentGetter<Obj>& component, Args&&... args)
|
||||
requires std::is_member_function_pointer_v<Fun>
|
||||
{
|
||||
std::array<std::unique_ptr<EQApplicationPacket>, EQ::versions::ClientVersionCount> build_packets;
|
||||
std::unordered_map<uint16, Client*> client_list = entity_list.GetClientList();
|
||||
|
||||
for (auto [_, ent] : client_list) {
|
||||
if (!ignore_sender || ent != sender) {
|
||||
auto& packet = build_packets.at(static_cast<uint32_t>(ent->ClientVersion()));
|
||||
if (!packet)
|
||||
if (auto comp = component(ent); comp != nullptr)
|
||||
packet = std::invoke(fun, comp, std::forward<Args>(args)...);
|
||||
|
||||
if (packet)
|
||||
ent->QueuePacket(packet.get(), ackreq, Client::CLIENT_CONNECTED);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static auto QueueCloseClients(
|
||||
Mob* sender, bool ignore_sender = false, float distance = 200,
|
||||
Mob* skipped_mob = nullptr, bool is_ack_required = true,
|
||||
eqFilterType filter = FilterNone)
|
||||
{
|
||||
if (distance <= 0) distance = static_cast<float>(zone->GetClientUpdateRange());
|
||||
|
||||
return [=]<typename Fun, typename Obj, typename... Args>(Fun fun, const ComponentGetter<Obj>& component, Args&&... args)
|
||||
requires std::is_member_function_pointer_v<Fun>
|
||||
{
|
||||
if (sender == nullptr) {
|
||||
QueueClients(sender, ignore_sender, is_ack_required)(fun, component, std::forward<Args>(args)...);
|
||||
} else {
|
||||
float distance_squared = distance * distance;
|
||||
std::array<std::unique_ptr<EQApplicationPacket>, EQ::versions::ClientVersionCount> build_packets;
|
||||
|
||||
for (auto& [_, mob] : sender->GetCloseMobList(distance)) {
|
||||
if (mob && mob->IsClient()) {
|
||||
Client* client = mob->CastToClient();
|
||||
if ((!ignore_sender || client != sender)
|
||||
&& client != skipped_mob
|
||||
&& DistanceSquared(client->GetPosition(), sender->GetPosition()) < distance_squared
|
||||
&& client->Connected()
|
||||
&& client->ShouldGetPacket(sender, filter))
|
||||
{
|
||||
auto& packet = build_packets.at(static_cast<uint32_t>(client->ClientVersion()));
|
||||
if (!packet)
|
||||
if (auto comp = component(client); comp != nullptr)
|
||||
packet = std::invoke(fun, comp, std::forward<Args>(args)...);
|
||||
|
||||
if (packet)
|
||||
client->QueuePacket(packet.get(), is_ack_required, Client::CLIENT_CONNECTED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace ClientPatch
|
||||
|
||||
// Helpers for the Message interface to send message packets
|
||||
namespace Message {
|
||||
|
||||
// this can return nullptr when the component doesn't exist for the version
|
||||
static std::function GetComponent = [](const Client* c) -> IMessage* {
|
||||
return GetMessageComponent(c->GetClientVersion()).get();
|
||||
};
|
||||
|
||||
// Helper functions to wrap the packet construction in sends
|
||||
template <AllConstChar... Args>
|
||||
requires (sizeof...(Args) <= 9)
|
||||
void MessageString(Client* c, uint32_t type, uint32_t id, Args&&... args)
|
||||
{
|
||||
if constexpr (sizeof...(Args) == 0) {
|
||||
ClientPatch::QueuePacket(c, &IMessage::Simple, GetComponent(c), type, id);
|
||||
} else {
|
||||
std::array<const char*, 9> a = {args...};
|
||||
ClientPatch::QueuePacket(c, &IMessage::Formatted, GetComponent(c), type, id, a);
|
||||
}
|
||||
}
|
||||
|
||||
static auto CloseMessageString(
|
||||
Mob* sender, bool ignore_sender = false, float distance = 200.f,
|
||||
Mob* skipped_mob = nullptr, bool is_ack_required = true,
|
||||
eqFilterType filter = FilterNone)
|
||||
{
|
||||
return [=]<AllConstChar... Args>(uint32_t type, uint32_t id, Args&&... args)
|
||||
requires (sizeof...(Args) <= 9)
|
||||
{
|
||||
auto queue_close_clients = ClientPatch::QueueCloseClients(sender, ignore_sender, distance, skipped_mob,
|
||||
is_ack_required, filter);
|
||||
|
||||
if constexpr (sizeof...(Args) == 0) {
|
||||
return queue_close_clients(&IMessage::Simple, GetComponent, type, id);
|
||||
} else {
|
||||
std::array<const char*, 9> a = {args...};
|
||||
return queue_close_clients(&IMessage::Formatted, GetComponent, type, id, a);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
inline void InterruptSpell(Client* c, uint32_t message, uint32_t spawn_id, const char* spell_link)
|
||||
{
|
||||
ClientPatch::QueuePacket(c, &IMessage::InterruptSpell, GetComponent(c), message, spawn_id, spell_link);
|
||||
}
|
||||
|
||||
inline void InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, const char* name,
|
||||
const char* spell_link)
|
||||
{
|
||||
ClientPatch::QueueCloseClients(sender, true, RuleI(Range, SongMessages), nullptr, true,
|
||||
sender->IsClient() ? FilterPCSpells : FilterNPCSpells)(
|
||||
&IMessage::InterruptSpellOther, GetComponent, sender, message, spawn_id, name, spell_link);
|
||||
}
|
||||
|
||||
} // namespace Message
|
||||
@@ -25,6 +25,7 @@ class Client;
|
||||
class Seperator;
|
||||
|
||||
#define COMMAND_CHAR '#'
|
||||
#define COMMAND_CHAR_NON_HASH '$'
|
||||
|
||||
typedef void (*CmdFuncPtr)(Client *, const Seperator *);
|
||||
|
||||
|
||||
+22
-57
@@ -17,13 +17,11 @@
|
||||
*/
|
||||
#ifdef EMBPERL
|
||||
|
||||
#include "zone/embparser.h"
|
||||
|
||||
#include "common/compiler_macros.h"
|
||||
#include "common/features.h"
|
||||
#include "common/misc_functions.h"
|
||||
#include "common/seperator.h"
|
||||
#include "common/strings.h"
|
||||
#include "zone/embparser.h"
|
||||
#include "zone/masterentity.h"
|
||||
#include "zone/qglobals.h"
|
||||
#include "zone/questmgr.h"
|
||||
@@ -163,10 +161,8 @@ const char* QuestEventSubroutines[_LargestEventID] = {
|
||||
"EVENT_LANGUAGE_SKILL_UP",
|
||||
"EVENT_ALT_CURRENCY_MERCHANT_BUY",
|
||||
"EVENT_ALT_CURRENCY_MERCHANT_SELL",
|
||||
"EVENT_MERCHANT_OPEN",
|
||||
"EVENT_MERCHANT_BUY",
|
||||
"EVENT_MERCHANT_SELL",
|
||||
"EVENT_MERCHANT_PRESELL",
|
||||
"EVENT_INSPECT",
|
||||
"EVENT_TASK_BEFORE_UPDATE",
|
||||
"EVENT_AA_BUY",
|
||||
@@ -402,8 +398,6 @@ int PerlembParser::EventCommon(
|
||||
zone
|
||||
);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PerlembParser::EventNPC(
|
||||
@@ -1217,33 +1211,31 @@ QuestType PerlembParser::GetQuestTypes(
|
||||
event_id == EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE
|
||||
) {
|
||||
return is_global ? QuestType::SpellGlobal : QuestType::Spell;
|
||||
}
|
||||
|
||||
if (npc_mob) {
|
||||
if (!inst) {
|
||||
if (npc_mob->IsBot()) {
|
||||
return is_global ? QuestType::BotGlobal : QuestType::Bot;
|
||||
} else if (npc_mob->IsMerc()) {
|
||||
return is_global ? QuestType::MercGlobal : QuestType::Merc;
|
||||
} else if (npc_mob->IsNPC()) {
|
||||
return is_global ? QuestType::NPCGlobal : QuestType::NPC;
|
||||
} else {
|
||||
if (npc_mob) {
|
||||
if (!inst) {
|
||||
if (npc_mob->IsBot()) {
|
||||
return is_global ? QuestType::BotGlobal : QuestType::Bot;
|
||||
} else if (npc_mob->IsMerc()) {
|
||||
return is_global ? QuestType::MercGlobal : QuestType::Merc;
|
||||
} else if (npc_mob->IsNPC()) {
|
||||
return is_global ? QuestType::NPCGlobal : QuestType::NPC;
|
||||
}
|
||||
} else {
|
||||
return is_global ? QuestType::ItemGlobal : QuestType::Item;
|
||||
}
|
||||
} else {
|
||||
return is_global ? QuestType::ItemGlobal : QuestType::Item;
|
||||
}
|
||||
} else if (mob) {
|
||||
if (!inst) {
|
||||
if (mob->IsClient()) {
|
||||
return is_global ? QuestType::PlayerGlobal : QuestType::Player;
|
||||
} else if (!npc_mob && mob) {
|
||||
if (!inst) {
|
||||
if (mob->IsClient()) {
|
||||
return is_global ? QuestType::PlayerGlobal : QuestType::Player;
|
||||
}
|
||||
} else {
|
||||
return is_global ? QuestType::ItemGlobal : QuestType::Item;
|
||||
}
|
||||
} else {
|
||||
return is_global ? QuestType::ItemGlobal : QuestType::Item;
|
||||
} else if (zone) {
|
||||
return is_global ? QuestType::ZoneGlobal : QuestType::Zone;
|
||||
}
|
||||
} else if (zone) {
|
||||
return is_global ? QuestType::ZoneGlobal : QuestType::Zone;
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
std::string PerlembParser::GetQuestPackageName(
|
||||
@@ -2291,33 +2283,6 @@ void PerlembParser::ExportEventVariables(
|
||||
break;
|
||||
}
|
||||
|
||||
case EVENT_MERCHANT_OPEN: {
|
||||
if (!extra_pointers || extra_pointers->size() < 1) break;
|
||||
|
||||
auto mob_ptr = std::any_cast<Mob*>(extra_pointers->at(0));
|
||||
if (!mob_ptr) break;
|
||||
|
||||
ExportVar(package_name.c_str(), "other", "Mob", mob_ptr);
|
||||
break;
|
||||
}
|
||||
|
||||
case EVENT_MERCHANT_PRESELL: {
|
||||
Seperator sep(data);
|
||||
ExportVar(package_name.c_str(), "slot_id", sep.arg[0]);
|
||||
ExportVar(package_name.c_str(), "item_id", sep.arg[1]);
|
||||
ExportVar(package_name.c_str(), "item_type", sep.arg[2]);
|
||||
|
||||
if (!extra_pointers || extra_pointers->size() < 2) break;
|
||||
|
||||
auto mob_ptr = std::any_cast<Mob*>(extra_pointers->at(0));
|
||||
auto inst_ptr = std::any_cast<EQ::ItemInstance*>(extra_pointers->at(1));
|
||||
if (!mob_ptr || !inst_ptr) break;
|
||||
|
||||
ExportVar(package_name.c_str(), "other", "Mob", mob_ptr);
|
||||
ExportVar(package_name.c_str(), "item", "ItemInstance", inst_ptr);
|
||||
break;
|
||||
}
|
||||
|
||||
case EVENT_AA_BUY: {
|
||||
Seperator sep(data);
|
||||
ExportVar(package_name.c_str(), "aa_cost", sep.arg[0]);
|
||||
|
||||
@@ -116,10 +116,8 @@ enum QuestEventID {
|
||||
EVENT_LANGUAGE_SKILL_UP,
|
||||
EVENT_ALT_CURRENCY_MERCHANT_BUY,
|
||||
EVENT_ALT_CURRENCY_MERCHANT_SELL,
|
||||
EVENT_MERCHANT_OPEN,
|
||||
EVENT_MERCHANT_BUY,
|
||||
EVENT_MERCHANT_SELL,
|
||||
EVENT_MERCHANT_PRESELL,
|
||||
EVENT_INSPECT,
|
||||
EVENT_TASK_BEFORE_UPDATE,
|
||||
EVENT_AA_BUY,
|
||||
|
||||
@@ -6968,10 +6968,8 @@ luabind::scope lua_register_events() {
|
||||
luabind::value("language_skill_up", static_cast<int>(EVENT_LANGUAGE_SKILL_UP)),
|
||||
luabind::value("alt_currency_merchant_buy", static_cast<int>(EVENT_ALT_CURRENCY_MERCHANT_BUY)),
|
||||
luabind::value("alt_currency_merchant_sell", static_cast<int>(EVENT_ALT_CURRENCY_MERCHANT_SELL)),
|
||||
luabind::value("merchant_open", static_cast<int>(EVENT_MERCHANT_OPEN)),
|
||||
luabind::value("merchant_buy", static_cast<int>(EVENT_MERCHANT_BUY)),
|
||||
luabind::value("merchant_sell", static_cast<int>(EVENT_MERCHANT_SELL)),
|
||||
luabind::value("merchant_presell", static_cast<int>(EVENT_MERCHANT_PRESELL)),
|
||||
luabind::value("inspect", static_cast<int>(EVENT_INSPECT)),
|
||||
luabind::value("task_before_update", static_cast<int>(EVENT_TASK_BEFORE_UPDATE)),
|
||||
luabind::value("aa_buy", static_cast<int>(EVENT_AA_BUY)),
|
||||
|
||||
@@ -158,11 +158,6 @@ uint32 Lua_ItemInst::GetItemScriptID() {
|
||||
return self->GetItemScriptID();
|
||||
}
|
||||
|
||||
uint8 Lua_ItemInst::GetItemType() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetItemType();
|
||||
}
|
||||
|
||||
int Lua_ItemInst::GetCharges() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetCharges();
|
||||
@@ -502,7 +497,6 @@ luabind::scope lua_register_iteminst() {
|
||||
.def("GetItemID", (uint32(Lua_ItemInst::*)(int))&Lua_ItemInst::GetItemID)
|
||||
.def("GetItemLink", (std::string(Lua_ItemInst::*)(void))&Lua_ItemInst::GetItemLink)
|
||||
.def("GetItemScriptID", (uint32(Lua_ItemInst::*)(void))&Lua_ItemInst::GetItemScriptID)
|
||||
.def("GetItemType", (uint8(Lua_ItemInst::*)(void)) & Lua_ItemInst::GetItemType)
|
||||
.def("GetMaxEvolveLvl", (int(Lua_ItemInst::*)(void))&Lua_ItemInst::GetMaxEvolveLvl)
|
||||
.def("GetName", (std::string(Lua_ItemInst::*)(void))&Lua_ItemInst::GetName)
|
||||
.def("GetSerialNumber", (int(Lua_ItemInst::*)(void))&Lua_ItemInst::GetSerialNumber)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user