mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-24 18:22:29 +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,6 +3,7 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- tob_patch
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
|
||||
+1
-1
@@ -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
-2
@@ -86,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
|
||||
@@ -97,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
|
||||
@@ -133,6 +136,7 @@ set(common_sources
|
||||
util/directory.cpp
|
||||
util/uuid.cpp
|
||||
zone_store.cpp
|
||||
links.cpp
|
||||
)
|
||||
|
||||
set(repositories
|
||||
@@ -652,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
|
||||
@@ -668,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
|
||||
@@ -676,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
|
||||
@@ -727,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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
+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;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
+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();
|
||||
|
||||
|
||||
+42
-54
@@ -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;
|
||||
@@ -14668,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);
|
||||
|
||||
|
||||
@@ -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 *);
|
||||
|
||||
|
||||
@@ -693,8 +693,6 @@ luabind::scope lua_register_packet_opcodes() {
|
||||
luabind::value("ShopEndConfirm", static_cast<int>(OP_ShopEndConfirm)),
|
||||
luabind::value("AdventureMerchantRequest", static_cast<int>(OP_AdventureMerchantRequest)),
|
||||
luabind::value("Sound", static_cast<int>(OP_Sound)),
|
||||
luabind::value("0x0193", static_cast<int>(OP_0x0193)),
|
||||
luabind::value("0x0347", static_cast<int>(OP_0x0347)),
|
||||
luabind::value("WorldComplete", static_cast<int>(OP_WorldComplete)),
|
||||
luabind::value("MobRename", static_cast<int>(OP_MobRename)),
|
||||
luabind::value("TaskDescription", static_cast<int>(OP_TaskDescription)),
|
||||
|
||||
@@ -1284,6 +1284,14 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
strcpy(ns->spawn.name, name);
|
||||
if(IsClient()) {
|
||||
strn0cpy(ns->spawn.lastName, lastname, sizeof(ns->spawn.lastName));
|
||||
ns->spawn.CharacterGuid.Id = CastToClient()->CharacterID();
|
||||
ns->spawn.CharacterGuid.WorldId = RuleI(World, Id);
|
||||
ns->spawn.CharacterGuid.Reserved = 0;
|
||||
}
|
||||
else {
|
||||
ns->spawn.CharacterGuid.Id = 0;
|
||||
ns->spawn.CharacterGuid.WorldId = 0;
|
||||
ns->spawn.CharacterGuid.Reserved = 0;
|
||||
}
|
||||
|
||||
ns->spawn.heading = FloatToEQ12(m_Position.w);
|
||||
|
||||
+26
-43
@@ -82,6 +82,7 @@
|
||||
#include "common/strings.h"
|
||||
#include "zone/bot.h"
|
||||
#include "zone/client.h"
|
||||
#include "zone/client_version.h"
|
||||
#include "zone/fastmath.h"
|
||||
#include "zone/lua_parser.h"
|
||||
#include "zone/mob_movement_manager.h"
|
||||
@@ -94,6 +95,8 @@
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
#include "common/links.h"
|
||||
|
||||
extern Zone *zone;
|
||||
extern volatile bool is_zone_loaded;
|
||||
extern WorldServer worldserver;
|
||||
@@ -319,6 +322,10 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
|
||||
// note that CheckFizzle itself doesn't let NPCs fizzle,
|
||||
// but this code allows for it.
|
||||
if (slot < CastingSlot::MaxGems && !CheckFizzle(spell_id)) {
|
||||
/*
|
||||
MessageFormat: You miss a note, bringing your song to a close! (TOB: You miss a note, bringing your %1 to a close!)
|
||||
MessageFormat: Your spell fizzles! (TOB: Your %1 spell fizzles!)
|
||||
*/
|
||||
int fizzle_msg = IsBardSong(spell_id) ? MISS_NOTE : SPELL_FIZZLE;
|
||||
|
||||
uint32 use_mana = ((spells[spell_id].mana) / 4);
|
||||
@@ -328,29 +335,21 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
|
||||
Mob::SetMana(GetMana() - use_mana); // We send StopCasting which will update mana
|
||||
StopCasting();
|
||||
|
||||
MessageString(Chat::SpellFailure, fizzle_msg);
|
||||
char spell_link[Links::MAX_LINK_SIZE];
|
||||
Links::FormatSpellLink(spell_link, Links::MAX_LINK_SIZE, spell_id);
|
||||
|
||||
if (IsClient())
|
||||
Message::MessageString(CastToClient(), Chat::SpellFailure, fizzle_msg, spell_link);
|
||||
|
||||
/**
|
||||
* Song Failure message
|
||||
*/
|
||||
entity_list.FilteredMessageCloseString(
|
||||
this,
|
||||
true,
|
||||
RuleI(Range, SpellMessages),
|
||||
Chat::SpellFailure,
|
||||
(IsClient() ? FilterPCSpells : FilterNPCSpells),
|
||||
(fizzle_msg == MISS_NOTE ? MISSED_NOTE_OTHER : SPELL_FIZZLE_OTHER),
|
||||
0,
|
||||
/*
|
||||
MessageFormat: You miss a note, bringing your song to a close! (if missed note)
|
||||
MessageFormat: A missed note brings %1's song to a close!
|
||||
MessageFormat: %1's spell fizzles!
|
||||
*/
|
||||
GetName()
|
||||
);
|
||||
Message::CloseMessageString(this, true, RuleI(Range, SpellMessages),
|
||||
nullptr, true, IsClient() ? FilterPCSpells : FilterNPCSpells)(
|
||||
Chat::SpellFailure, fizzle_msg == MISS_NOTE ? MISSED_NOTE_OTHER : SPELL_FIZZLE_OTHER, GetName(), spell_link);
|
||||
|
||||
TryTriggerOnCastRequirement();
|
||||
return(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
SaveSpellLoc();
|
||||
@@ -1241,7 +1240,6 @@ void Mob::InterruptSpell(uint16 spellid)
|
||||
// color not used right now
|
||||
void Mob::InterruptSpell(uint16 message, uint16 color, uint16 spellid)
|
||||
{
|
||||
EQApplicationPacket *outapp = nullptr;
|
||||
uint16 message_other;
|
||||
bool bard_song_mode = false; //has the bard song gone to auto repeat mode
|
||||
|
||||
@@ -1303,14 +1301,9 @@ void Mob::InterruptSpell(uint16 message, uint16 color, uint16 spellid)
|
||||
if (IsClient() && message != SONG_ENDS)
|
||||
{
|
||||
// the interrupt message
|
||||
outapp = new EQApplicationPacket(OP_InterruptCast, sizeof(InterruptCast_Struct));
|
||||
InterruptCast_Struct* ic = (InterruptCast_Struct*) outapp->pBuffer;
|
||||
ic->messageid = message;
|
||||
ic->spawnid = GetID();
|
||||
outapp->priority = 5;
|
||||
CastToClient()->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
char spell_link[Links::MAX_LINK_SIZE];
|
||||
Links::FormatSpellLink(spell_link, Links::MAX_LINK_SIZE, spellid);
|
||||
Message::InterruptSpell(CastToClient(), message, GetID(), spell_link);
|
||||
SendSpellBarEnable(spellid);
|
||||
}
|
||||
|
||||
@@ -1336,14 +1329,9 @@ void Mob::InterruptSpell(uint16 message, uint16 color, uint16 spellid)
|
||||
}
|
||||
|
||||
// this is the actual message, it works the same as a formatted message
|
||||
outapp = new EQApplicationPacket(OP_InterruptCast, sizeof(InterruptCast_Struct) + strlen(GetCleanName()) + 1);
|
||||
InterruptCast_Struct* ic = (InterruptCast_Struct*) outapp->pBuffer;
|
||||
ic->messageid = message_other;
|
||||
ic->spawnid = GetID();
|
||||
strcpy(ic->message, GetCleanName());
|
||||
entity_list.QueueCloseClients(this, outapp, true, RuleI(Range, SongMessages), 0, true, IsClient() ? FilterPCSpells : FilterNPCSpells);
|
||||
safe_delete(outapp);
|
||||
|
||||
char spell_link[Links::MAX_LINK_SIZE];
|
||||
Links::FormatSpellLink(spell_link, Links::MAX_LINK_SIZE, spellid);
|
||||
Message::InterruptSpellOther(this, message_other, GetID(), GetCleanName(), spell_link);
|
||||
}
|
||||
|
||||
// this is like interrupt, just it doesn't spam interrupt packets to everyone
|
||||
@@ -7279,16 +7267,11 @@ void Mob::DoBardCastingFromItemClick(bool is_casting_bard_song, uint32 cast_time
|
||||
Known bug: When a bard uses an augment with a clicky that has a cast time, the cast won't display. This issue only affects bards.
|
||||
*/
|
||||
if (is_casting_bard_song) {
|
||||
//For spells with cast times. Cancel song cast, stop pusling and start item cast.
|
||||
//For spells with cast times. Cancel song cast, stop pulsing and start item cast.
|
||||
if (cast_time != 0) {
|
||||
EQApplicationPacket *outapp = nullptr;
|
||||
outapp = new EQApplicationPacket(OP_InterruptCast, sizeof(InterruptCast_Struct));
|
||||
InterruptCast_Struct* ic = (InterruptCast_Struct*)outapp->pBuffer;
|
||||
ic->messageid = SONG_ENDS;
|
||||
ic->spawnid = GetID();
|
||||
outapp->priority = 5;
|
||||
CastToClient()->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
char spell_link[Links::MAX_LINK_SIZE];
|
||||
Links::FormatSpellLink(spell_link, Links::MAX_LINK_SIZE, spell_id);
|
||||
Message::InterruptSpell(CastToClient(), SONG_ENDS, GetID(), spell_link);
|
||||
|
||||
ZeroCastingVars();
|
||||
ZeroBardPulseVars();
|
||||
|
||||
+58
-58
@@ -41,8 +41,8 @@
|
||||
#define DOORS_INSUFFICIENT_SKILL 132 //You are not sufficiently skilled to pick this lock.
|
||||
#define DOORS_GM 133 //You opened the locked door with your magic GM key.
|
||||
#define ITEMS_INSUFFICIENT_LEVEL 136 //You are not sufficient level to use this item.
|
||||
#define GAIN_XP 138 //You gain experience!!
|
||||
#define GAIN_GROUPXP 139 //You gain party experience!!
|
||||
#define GAIN_XP 138 //You gain experience!! // TODO: TOB added experience value - You gain experience!%1
|
||||
#define GAIN_GROUPXP 139 //You gain party experience!! // TODO: TOB added experience value - You gain party experience!%1
|
||||
#define BOW_DOUBLE_DAMAGE 143 //Your bow shot did double dmg.
|
||||
#define YOU_ARE_BEING_BANDAGED 147 //Someone is bandaging you.
|
||||
#define FORAGE_GRUBS 150 //You have scrounged up some fishing grubs.
|
||||
@@ -69,7 +69,7 @@
|
||||
#define SPELL_FIZZLE 173 //Your spell fizzles!
|
||||
#define MUST_EQUIP_ITEM 179 //You cannot use this item unless it is equipped.
|
||||
#define MISS_NOTE 180 //You miss a note, bringing your song to a close!
|
||||
#define CANNOT_USE_ITEM 181 //Your race, class, or deity cannot use this item.
|
||||
#define CANNOT_USE_ITEM 181 //Your race, class, or deity cannot use this item. // TODO: TOB moved this: 6611 Your class, deity, and/or race may not equip %1.
|
||||
#define ITEM_OUT_OF_CHARGES 182 //Item is out of charges.
|
||||
#define ALREADY_ON_A_MOUNT 189 //You are already on a mount.
|
||||
#define TARGET_NO_MANA 191 //Your target has no mana to affect
|
||||
@@ -106,7 +106,7 @@
|
||||
#define NO_PET 255 //You do not have a pet.
|
||||
#define GATE_FAIL 260 //Your gate is too unstable, and collapses.
|
||||
#define CORPSE_CANT_SENSE 262 //You cannot sense any corpses for this PC in this zone.
|
||||
#define SPELL_NO_HOLD 263 //Your spell did not take hold.
|
||||
#define SPELL_NO_HOLD 263 //Your spell did not take hold. // TODO: This one is complex. There are 4 replacement strings, all taking arguments 9164, 9209, 9210, 9211
|
||||
#define CANNOT_CHARM 267 //This NPC cannot be charmed.
|
||||
#define SPELL_NO_EFFECT 268 //Your target looks unaffected.
|
||||
#define NO_INSTRUMENT_SKILL 269 //Stick to singing until you learn to play this instrument.
|
||||
@@ -123,9 +123,9 @@
|
||||
#define DISARMED_TRAP 305 //You have disarmed the trap.
|
||||
#define LDON_SENSE_TRAP1 306 //You do not Sense any traps.
|
||||
#define TRADESKILL_NOCOMBINE 334 //You cannot combine these items in this container type!
|
||||
#define TRADESKILL_FAILED 336 //You lacked the skills to fashion the items together.
|
||||
#define TRADESKILL_FAILED 336 //You lacked the skills to fashion the items together. // TODO: TOB - 336 You lacked the skills to fashion %1.
|
||||
#define TRADESKILL_TRIVIAL 338 //You can no longer advance your skill from making this item.
|
||||
#define TRADESKILL_SUCCEED 339 //You have fashioned the items together to create something new!
|
||||
#define TRADESKILL_SUCCEED 339 //You have fashioned the items together to create something new! // TODO: TOB - 339 You have %2fashioned the items together to create something new: %1.
|
||||
#define EVADE_SUCCESS 343 //You have momentarily ducked away from the main combat.
|
||||
#define EVADE_FAIL 344 //Your attempts at ducking clear of combat fail.
|
||||
#define HIDE_FAIL 345 //You failed to hide yourself.
|
||||
@@ -136,11 +136,11 @@
|
||||
#define MEND_SUCCESS 350 //You mend your wounds and heal some damage.
|
||||
#define MEND_WORSEN 351 //You have worsened your wounds!
|
||||
#define MEND_FAIL 352 //You have failed to mend your wounds.
|
||||
#define LDON_SENSE_TRAP2 367 //You have not detected any traps.
|
||||
#define TRAP_TOO_FAR 368 //You are too far away from that trap to affect it.
|
||||
#define FAIL_DISARM_DETECTED_TRAP 370 //You fail to disarm the detected trap.
|
||||
#define LDON_SENSE_TRAP2 367 //You have not detected any traps. // TODO: TOB - unk
|
||||
#define TRAP_TOO_FAR 368 //You are too far away from that trap to affect it. // TODO: TOB - unk
|
||||
#define FAIL_DISARM_DETECTED_TRAP 370 //You fail to disarm the detected trap. // TODO: TOB - unk
|
||||
#define LOOT_LORE_ERROR 371 //You cannot loot this Lore Item. You already have one.
|
||||
#define PICK_LORE 379 //You cannot pick up a lore item you already possess.
|
||||
#define PICK_LORE 379 //You cannot pick up a lore item you already possess. // TODO: TOB - 379 You cannot pick up %1 because it is a lore item you already possess.
|
||||
#define POISON_TOO_HIGH 382 //This poison is too high level for you to apply.
|
||||
#define TAUNT_TOO_FAR 386 //You are too far away from your target to taunt.
|
||||
#define CORPSE_TOO_FAR 389 //The corpse is too far away to summon.
|
||||
@@ -154,17 +154,17 @@
|
||||
#define SONG_NEEDS_WIND 406 //You need to play a wind instrument for this song
|
||||
#define SONG_NEEDS_STRINGS 407 //You need to play a stringed instrument for this song
|
||||
#define SONG_NEEDS_BRASS 408 //You need to play a brass instrument for this song
|
||||
#define AA_GAIN_ABILITY 410 //You have gained the ability "%T1" at a cost of %2 ability %T3.
|
||||
#define AA_IMPROVE 411 //You have improved %T1 %2 at a cost of %3 ability %T4.
|
||||
#define TAUNT_SUCCESS 412 //You taunt %1 to ignore others and attack you!
|
||||
#define AA_GAIN_ABILITY 410 //You have gained the ability "%T1" at a cost of %2 ability %T3. // TODO: TOB - You have gained the ability "%B1(1)" at a cost of %2 ability %T3.
|
||||
#define AA_IMPROVE 411 //You have improved %T1 %2 at a cost of %3 ability %T4. // TODO: TOB - You have improved %B1(1) %2 at a cost of %3 ability %T4.
|
||||
#define TAUNT_SUCCESS 412 //You taunt %1 to ignore others and attack you! // TODO: TOB - unk
|
||||
#define AA_REUSE_MSG 413 //You can use the ability %B1(1) again in %2 hour(s) %3 minute(s) %4 seconds.
|
||||
#define AA_REUSE_MSG2 414 //You can use the ability %B1(1) again in %2 minute(s) %3 seconds.
|
||||
#define YOU_HEALED 419 //%1 has healed you for %2 points of damage.
|
||||
#define YOU_HEALED 419 //%1 has healed you for %2 points of damage. // TODO: TOB - 12998 %1 healed you for %2 hit points by %3.
|
||||
#define BEGINS_TO_GLOW 422 //Your %1 begins to glow.
|
||||
#define ALREADY_INVIS 423 //%1 tries to cast an invisibility spell on you, but you are already invisible.
|
||||
#define YOU_ARE_PROTECTED 424 //%1 tries to cast a spell on you, but you are protected.
|
||||
#define TARGET_RESISTED 425 //Your target resisted the %1 spell.
|
||||
#define YOU_RESIST 426 //You resist the %1 spell!
|
||||
#define TARGET_RESISTED 425 //Your target resisted the %1 spell. // TODO: TOB - 425 %1 resisted your %2!
|
||||
#define YOU_RESIST 426 //You resist the %1 spell! // TODO: TOB - 426 You resist %1!
|
||||
#define YOU_CRIT_HEAL 427 //You perform an exceptional heal! (%1)
|
||||
#define YOU_CRIT_BLAST 428 //You deliver a critical blast! (%1)
|
||||
#define SUMMONING_CORPSE 429 //Summoning your corpse.
|
||||
@@ -176,15 +176,15 @@
|
||||
#define PET_TAUNTING 438 //Taunting attacker, Master.
|
||||
#define INTERRUPT_SPELL 439 //Your spell is interrupted.
|
||||
#define LOSE_LEVEL 442 //You LOST a level! You are now level %1!
|
||||
#define GAIN_ABILITY_POINT 446 //You have gained an ability point! You now have %1 ability point%2.
|
||||
#define GAIN_ABILITY_POINT 446 //You have gained an ability point! You now have %1 ability point%2. // TODO: TOB - 446 You have gained an ability point! You now have %1 ability points. (Actual system moved to 8019-8021 and can handle multiples)
|
||||
#define GAIN_LEVEL 447 //You have gained a level! Welcome to level %1!
|
||||
#define LANG_SKILL_IMPROVED 449 //Your language skills have improved.
|
||||
#define OTHER_LOOTED_MESSAGE 466 //--%1 has looted a %2--
|
||||
#define LOOTED_MESSAGE 467 //--You have looted a %1--
|
||||
#define FACTION_WORST 469 //Your faction standing with %1 could not possibly get any worse.
|
||||
#define FACTION_WORSE 470 //Your faction standing with %1 got worse.
|
||||
#define FACTION_BEST 471 //Your faction standing with %1 could not possibly get any better.
|
||||
#define FACTION_BETTER 472 //Your faction standing with %1 got better.
|
||||
#define OTHER_LOOTED_MESSAGE 466 //--%1 has looted a %2-- // TODO: TOB - 466 --%1 has looted %2 %3 from %4.--
|
||||
#define LOOTED_MESSAGE 467 //--You have looted a %1-- // TODO: TOB - 467 --You have looted %1 %2 from %3.--
|
||||
#define FACTION_WORST 469 //Your faction standing with %1 could not possibly get any worse. // TODO: TOB - 469 Your faction standing with %B1(45) could not possibly get any worse.
|
||||
#define FACTION_WORSE 470 //Your faction standing with %1 got worse. // TODO: TOB - 14261 Your faction standing with %B1(45) has been adjusted by %2.
|
||||
#define FACTION_BEST 471 //Your faction standing with %1 could not possibly get any better. // TODO: TOB - 471 Your faction standing with %B1(45) could not possibly get any better.
|
||||
#define FACTION_BETTER 472 //Your faction standing with %1 got better. // TODO: TOB - 14261 Your faction standing with %B1(45) has been adjusted by %2.
|
||||
#define PET_REPORT_HP 488 //I have %1 percent of my hit points left.
|
||||
#define PET_NO_TAUNT 489 //No longer taunting attackers, Master.
|
||||
#define PET_DO_TAUNT 490 //Taunting attackers as normal, Master.
|
||||
@@ -241,7 +241,7 @@
|
||||
#define NPC_RAMPAGE 1044 //%1 goes on a RAMPAGE!
|
||||
#define NPC_FLURRY 1045 //%1 executes a FLURRY of attacks on %2!
|
||||
#define DISCIPLINE_FEARLESS 1076 //%1 becomes fearless.
|
||||
#define DUEL_FINISHED 1088 //dont know text
|
||||
#define DUEL_FINISHED 1088 //%1 has defeated %2 in a duel to the death!
|
||||
#define EATING_MESSAGE 1091 //Chomp, chomp, chomp... %1 takes a bite from a %2.
|
||||
#define DRINKING_MESSAGE 1093 //Glug, glug, glug... %1 takes a drink from a %2.
|
||||
#define SUCCESSFUL_TAUNT 1095 //I'll teach you to interfere with me %3.
|
||||
@@ -285,8 +285,8 @@
|
||||
#define MERCHANT_CLOSED_TWO 1200 //Can't you see I'm doing something here?
|
||||
#define MERCHANT_CLOSED_THREE 1201 //I am not open for business right now.
|
||||
#define AA_POINTS 1215 //points
|
||||
#define SPELL_FIZZLE_OTHER 1218 //%1's spell fizzles!
|
||||
#define MISSED_NOTE_OTHER 1219 //A missed note brings %1's song to a close!
|
||||
#define SPELL_FIZZLE_OTHER 1218 //%1's spell fizzles! // TODO: TOB - 1218 %1's %2 spell fizzles!
|
||||
#define MISSED_NOTE_OTHER 1219 //A missed note brings %1's song to a close! // TODO: TOB - 1219 A missed note brings %1's %2 to a close!
|
||||
#define SPELL_LEVEL_REQ 1226 //This spell only works on people who are level %1 and under.
|
||||
#define CORPSE_DECAY_NOW 1227 //This corpse is waiting to expire.
|
||||
#define CORPSE_ITEM_LOST 1228 //Your items will no longer stay with you when you respawn on death. You will now need to return to your corpse for your items.
|
||||
@@ -327,27 +327,27 @@
|
||||
#define SENSE_CORPSE_DIRECTION 1563 //You sense a corpse in this direction.
|
||||
#define DUPE_LORE_MERCHANT 1573 //%1 tells you, 'You already have the lore item, %2, on your person, on your shroud, in the bank, in a real estate, or as an augment in another item. You cannot have more than one of a particular lore item at a time.'
|
||||
#define QUEUED_TELL 2458 //[queued]
|
||||
#define QUEUE_TELL_FULL 2459 //[zoing and queue is full]
|
||||
#define QUEUE_TELL_FULL 2459 //[zoning and queue is full]
|
||||
#define TRADER_BUSY_TWO 3192 //Sorry, that action cannot be performed while trading.
|
||||
#define SUSPEND_MINION_UNSUSPEND 3267 //%1 tells you, 'I live again...'
|
||||
#define SUSPEND_MINION_SUSPEND 3268 //%1 tells you, 'By your command, master.'
|
||||
#define ONLY_SUMMONED_PETS 3269 //3269 This effect only works with summoned pets.
|
||||
#define ONLY_SUMMONED_PETS 3269 //This effect only works with summoned pets.
|
||||
#define SUSPEND_MINION_FIGHTING 3270 //Your pet must be at peace, first.
|
||||
#define SHIELD_TARGET_NPC 3278 //You must first target a living Player Character.
|
||||
#define ALREADY_SHIELDED 3279 //Either you or your target is already being shielded.
|
||||
#define ALREADY_SHIELDING 3280 //Either you or your target is already shielding another.
|
||||
#define START_SHIELDING 3281 //%1 begins to use %2 as a living shield!
|
||||
#define END_SHIELDING 3282 //%1 ceases protecting %2.
|
||||
#define OVER_AA_CAP 3374 //Warning: You are currently over the earned Advancement point limit of %1. Please spend some of your stored AA points. The NEXT time you zone all of your AA points over %2 will be deleted. You MUST spend the extra points now.
|
||||
#define OVER_AA_CAP 3374 //Warning: You are currently over the earned Advancement point limit of %1. Please spend some of your stored AA points. The NEXT time you zone all of your AA points over %2 will be deleted. You MUST spend the extra points now. // TODO: TOB - 3374 You are currently over the earned Advancement point limit of %1. You must spend some of your ability points before you can earn more.
|
||||
#define TRADESKILL_MISSING_ITEM 3455 //You are missing a %1.
|
||||
#define TRADESKILL_MISSING_COMPONENTS 3456 //Sorry, but you don't have everything you need for this recipe in your general inventory.
|
||||
#define TRADESKILL_LEARN_RECIPE 3457 //You have learned the recipe %1!
|
||||
#define TASK_UPDATED 3471 //Your task '%1' has been updated.
|
||||
#define YOU_ASSIGNED_TASK 3472 //You have been assigned the task '%1'.
|
||||
#define DZ_YOU_BELONG 3500 //You cannot create this expedition since you already belong to another.
|
||||
#define DZ_REPLAY_YOU 3501 //You cannot create this expedition for another %1d:%2h:%3m since you have recently played here.
|
||||
#define DZ_PLAYER_COUNT 3503 //You do not meet the player count requirement. You have %1 players. You must have at least %2 and no more than %3.
|
||||
#define DZ_REPLAY_OTHER 3504 //%1 cannot be added to this expedition for another %2D:%3H:%4M since they have recently played in this area.
|
||||
#define DZ_REPLAY_YOU 3501 //You cannot create this expedition for another %1d:%2h:%3m since you have recently played here. // TODO: TOB - 3501 You cannot create this expedition for another %1d:%2h:%3m:%4s since you have recently played here.
|
||||
#define DZ_PLAYER_COUNT 3503 //You do not meet the player count requirement. You have %1 players. You must have at least %2 and no more than %3. // TODO: TOB - 3503 You do not meet the player count requirement. You have %1 players. You must have at least %2.
|
||||
#define DZ_REPLAY_OTHER 3504 //%1 cannot be added to this expedition for another %2D:%3H:%4M since they have recently played in this area. // TODO: TOB - 3504 %1 cannot be added to this expedition for another %2d:%3h:%4m:%5s since they have recently played in this area.
|
||||
#define DZ_AVAILABLE 3507 //%1 is now available to you.
|
||||
#define DZADD_INVITE 3508 //Sending an invitation to: %1.
|
||||
#define DZ_PREVENT_ENTERING 3510 //A strange magical presence prevents you from entering. It's too dangerous to enter at the moment.
|
||||
@@ -358,7 +358,7 @@
|
||||
#define DZ_REMOVED 3516 //%1 has been removed from %2.
|
||||
#define DZSWAP_INVITE 3517 //Sending an invitation to: %1. They must accept in order to swap party members.
|
||||
#define DZ_LEADER_OFFLINE 3518 //%1 is not currently online. You can only transfer leadership to an online member of the expedition you are in.
|
||||
#define DZ_TIMER 3519 //You have %1d:%2h:%3m remaining until you may enter %4.
|
||||
#define DZ_TIMER 3519 //You have %1d:%2h:%3m remaining until you may enter %4. // TODO: TOB - 3519 You have %1d:%2h:%3m:%4s remaining until you may enter %5.
|
||||
#define DZ_LEADER_NAME 3520 //%1 has been made the leader for this expedition.
|
||||
#define DZ_LEADER_YOU 3521 //You have been made the leader of this expedition.
|
||||
#define DZ_INVITE_ACCEPTED 3522 //%1 has accepted your offer to join your expedition.
|
||||
@@ -371,8 +371,8 @@
|
||||
#define DZ_MINUTES_REMAIN 3551 //You only have %1 minutes remaining before this expedition comes to an end.
|
||||
#define DZ_LEADER 3552 //Expedition Leader: %1
|
||||
#define DZ_MEMBERS 3553 //Expedition Members: %1
|
||||
#define DZ_EVENT_TIMER 3561 //%1 cannot be added to this expedition since they have recently experienced %2. They must wait another %3D:%4H:%5M until they can experience it again. They may be added to the expedition later, once %2 has been completed.
|
||||
#define LOOT_NOT_ALLOWED 3562 //You are not allowed to loot the item: %1.
|
||||
#define DZ_EVENT_TIMER 3561 //%1 cannot be added to this expedition since they have recently experienced %2. They must wait another %3D:%4H:%5M until they can experience it again. They may be added to the expedition later, once %2 has been completed. // TODO: TOB - 3561 %1 cannot be added to this expedition since they have recently experienced %2. They must wait another %3d:%4h:%5m:%6s until they can experience it again. They may be added to the expedition later, once %2 has been completed.
|
||||
#define LOOT_NOT_ALLOWED 3562 //You are not allowed to loot the item: %1. // TODO: TOB - 8337 & 8338 (has a reason now)
|
||||
#define DZ_UNABLE_RETRIEVE_LEADER 3583 //Unable to retrieve dynamic zone leader to check permissions.
|
||||
#define DZADD_NOT_ALLOWING 3585 //The expedition is not allowing players to be added.
|
||||
#define DZADD_NOT_ONLINE 3586 //%1 is not currently online. A player needs to be online to be added to a Dynamic Zone
|
||||
@@ -380,8 +380,8 @@
|
||||
#define DZADD_ALREADY_PART 3588 //You can not add %1 since they are already part of this zone.
|
||||
#define DZADD_LEAVE_ZONE 3589 //You can not add %1 since they first need to leave the zone before being allowed back in.
|
||||
#define DZADD_ALREADY_OTHER 3590 //%1 can not be added to this dynamic zone since they are already assigned to another dynamic zone.
|
||||
#define DZADD_REPLAY_TIMER 3591 //%1 can not be added to this dynamic zone for another %2D:%3H:%4M since they have recently played this zone.
|
||||
#define DZADD_EVENT_TIMER 3592 //%1 can not be added to this dynamic zone since they have recently experienced %2. They must wait for another %3D:%4H:%5M, or until event %2 has occurred.
|
||||
#define DZADD_REPLAY_TIMER 3591 //%1 can not be added to this dynamic zone for another %2D:%3H:%4M since they have recently played this zone. // TODO: TOB - 3591 %1 can not be added to this dynamic zone for another %2d:%3h:%4m:%5s since they have recently played this zone.
|
||||
#define DZADD_EVENT_TIMER 3592 //%1 can not be added to this dynamic zone since they have recently experienced %2. They must wait for another %3D:%4H:%5M, or until event %2 has occurred. // TODO: TOB - 3592 %1 can not be added to this dynamic zone since they have recently experienced %2. They must wait for another %3d:%4h:%5m:%6s, or until event %2 has occurred.
|
||||
#define DZADD_PENDING 3593 //%1 currently has an outstanding invitation to join this Dynamic Zone.
|
||||
#define DZADD_PENDING_OTHER 3594 //%1 currently has an outstanding invitation to join another Dynamic Zone. Players may only have one invitation outstanding.
|
||||
#define DZSWAP_CANNOT_REMOVE 3595 //%1 can not be removed from this dynamic zone since they are not assigned to it.
|
||||
@@ -405,9 +405,9 @@
|
||||
#define PETITION_NO_DELETE 5053 //You do not have a petition in the queue.
|
||||
#define PETITION_DELETED 5054 //Your petition was successfully deleted.
|
||||
#define ALREADY_IN_RAID 5060 //%1 is already in a raid.
|
||||
#define ALREADY_IN_YOUR_RAID 5077 //%1 is already in your raid.
|
||||
#define ALREADY_IN_YOUR_RAID 5077 //%1 is already in your raid. // TODO: TOB - 5077 That person is already in your raid.
|
||||
#define NOT_IN_YOUR_RAID 5082 //%1 is not in your raid.
|
||||
#define GAIN_RAIDEXP 5085 //You gained raid experience!
|
||||
#define GAIN_RAIDEXP 5085 //You gained raid experience! // TODO: TOB - 5085 You gained raid experience!%1
|
||||
#define ALREADY_IN_GRP_RAID 5088 //% 1 rejects your invite because they are in a raid and you are not in theirs, or they are a raid group leader
|
||||
#define DUNGEON_SEALED 5141 //The gateway to the dungeon is sealed off to you. Perhaps you would be able to enter if you needed to adventure there.
|
||||
#define ADVENTURE_COMPLETE 5147 //You received %1 points for successfully completing the adventure.
|
||||
@@ -423,8 +423,8 @@
|
||||
#define MELEE_SILENCE 5806 //You *CANNOT* use this melee ability, you are suffering from amnesia!
|
||||
#define DISCIPLINE_REUSE_MSG 5807 //You can use the ability %1 again in %2 hour(s) %3 minute(s) %4 seconds.
|
||||
#define DISCIPLINE_REUSE_MSG2 5808 //You can use the ability %1 again in %2 minute(s) %3 seconds.
|
||||
#define FAILED_TAUNT 5811 //You have failed to taunt your target.
|
||||
#define PHYSICAL_RESIST_FAIL 5817 //Your target avoided your %1 ability.
|
||||
#define FAILED_TAUNT 5811 //You have failed to taunt your target. // TODO: TOB - 5811 You have failed to taunt %1.
|
||||
#define PHYSICAL_RESIST_FAIL 5817 //Your target avoided your %1 ability. // TODO: TOB - 5817 %1 avoided your %2!
|
||||
#define AA_NO_TARGET 5825 //You must first select a target for this ability!
|
||||
#define YOU_RECEIVE 5941 //You receive %1.
|
||||
#define NO_TASK_OFFERS 6009 //Sorry %3, I don't have anything for someone with your abilities.
|
||||
@@ -447,7 +447,7 @@
|
||||
#define TRANSFORM_COMPLETE 6327 //You have successfully transformed your %1.
|
||||
#define DETRANSFORM_FAILED 6341 //%1 has no transformation that can be removed.
|
||||
#define GUILD_PERMISSION_FAILED 6418 //You do not have permission to change access options.
|
||||
#define PARCEL_DELIVERY_ARRIVED 6465 //You have received a new parcel delivery!
|
||||
#define PARCEL_DELIVERY_ARRIVED 6465 //You have received a new parcel delivery! // TODO: TOB - 6465 You have received a new parcel delivery %1!
|
||||
#define PARCEL_DELIVERY 6466 //%1 tells you, 'I will deliver the %2 to %3 as soon as possible!'
|
||||
#define PARCEL_UNKNOWN_NAME 6467 //%1 tells you, 'Unfortunately, I don't know anyone by the name of %2. Here is your %3 back.''
|
||||
#define PARCEL_DELIVERED 6471 //%1 hands you the %2 that was sent from %3.
|
||||
@@ -474,7 +474,7 @@
|
||||
#define LDON_CERTAIN_TRAP 7557 //You are certain that %1 is trapped.
|
||||
#define LDON_CERTAIN_NOT_TRAP 7558 //You are certain that %1 is not trapped.
|
||||
#define LDON_CANT_DETERMINE_TRAP 7559 //You are unable to determine if %1 is trapped.
|
||||
#define LDON_PICKLOCK_SUCCESS 7560 //You have successfully picked %1!
|
||||
#define LDON_PICKLOCK_SUCCESS 7560 //You have successfully picked %1! // TODO: TOB - 7560 You have successfully picked %1%2!
|
||||
#define LDON_PICKLOCK_FAILURE 7561 //You have failed to pick %1.
|
||||
#define LDON_STILL_LOCKED 7562 //You cannot open %1, it is locked.
|
||||
#define LDON_BASH_CHEST 7563 //%1 try to %2 %3, but do no damage.
|
||||
@@ -497,7 +497,7 @@
|
||||
#define NOT_DELEGATED_MARKER 8794 //You have not been delegated Raid Mark
|
||||
#define GAIN_GROUP_LEADERSHIP_EXP 8788 //
|
||||
#define GAIN_RAID_LEADERSHIP_EXP 8789 //
|
||||
#define BUFF_MINUTES_REMAINING 8799 //%1 (%2 minutes remaining)
|
||||
#define BUFF_MINUTES_REMAINING 8799 //%1 (%2 minutes remaining) // TODO: TOB - 8799 --You sense %1%2 on %3 has %4.--
|
||||
#define RAID_NO_LONGER_MARKED 8801 //%1 is no longer marked
|
||||
#define YOU_HAVE_BEEN_GIVEN 8994 //You have been given: %1
|
||||
#define NO_MORE_TRAPS 9002 //You have already placed your maximum number of traps.
|
||||
@@ -508,13 +508,13 @@
|
||||
#define SPELL_OPPOSITE_EFFECT 9032 //Your spell may have had the opposite effect of what you desired.
|
||||
#define HAS_BEEN_AWAKENED 9037 //%1 has been awakened by %2.
|
||||
#define YOU_HEAL 9068 //You have healed %1 for %2 points of damage.
|
||||
#define YOUR_HIT_DOT 9072 //%1 has taken %2 damage from your %3.
|
||||
#define HIT_NON_MELEE 9073 //%1 hit %2 for %3 points of non-melee damage.
|
||||
#define YOUR_HIT_DOT 9072 //%1 has taken %2 damage from your %3. // TODO: TOB - 9072 %1 has taken %2 damage from your %3.%4
|
||||
#define HIT_NON_MELEE 9073 //%1 hit %2 for %3 points of non-melee damage. // TODO: TOB - 9073 %1 hit %2 for %3 points of %4 damage by %5.%6
|
||||
#define GLOWS_BLUE 9074 //Your %1 glows blue.
|
||||
#define GLOWS_RED 9075 //Your %1 glows red.
|
||||
#define SHAKE_OFF_STUN 9077 //You shake off the stun effect!
|
||||
#define STRIKETHROUGH_STRING 9078 //You strike through your opponent's defenses!
|
||||
#define SPELL_REFLECT 9082 //%1's spell has been reflected by %2.
|
||||
#define SPELL_REFLECT 9082 //%1's spell has been reflected by %2. // TODO: TOB - 9082 %1's %2 spell has been reflected by %3.
|
||||
#define NO_MORE_AURAS 9160 //You do not have sufficient focus to maintain that ability.
|
||||
#define NEW_SPELLS_AVAIL 9149 //You have new spells available to you. Check the merchants near your guild master.
|
||||
#define FD_CAST_ON_NO_BREAK 9174 //The strength of your will allows you to resume feigning death.
|
||||
@@ -527,17 +527,17 @@
|
||||
#define NO_CAST_OUT_OF_COMBAT 9191 //You can not cast this spell while out of combat.
|
||||
#define NO_ABILITY_IN_COMBAT 9192 //You can not use this ability while in combat.
|
||||
#define NO_ABILITY_OUT_OF_COMBAT 9194 //You can not use this ability while out of combat.
|
||||
#define GAIN_GROUPXP_BONUS 9298 //You gain party experience (with a bonus)!
|
||||
#define GAIN_GROUPXP_PENALTY 9301 //You gain party experience (with a penalty)!
|
||||
#define GAIN_RAIDXP_BONUS 9302 //You gained raid experience (with a bonus)!
|
||||
#define GAIN_RAIDXP_PENALTY 9303 //You gained raid experience (with a penalty)!
|
||||
#define GAIN_GROUPXP_BONUS 9298 //You gain party experience (with a bonus)! // TODO: TOB - 9298 You gain party experience (with a bonus)!%1
|
||||
#define GAIN_GROUPXP_PENALTY 9301 //You gain party experience (with a penalty)! // TODO: TOB - 9301 You gain party experience (with a penalty)!%1
|
||||
#define GAIN_RAIDXP_BONUS 9302 //You gained raid experience (with a bonus)! // TODO: TOB - 9302 You gained raid experience (with a bonus)!%1
|
||||
#define GAIN_RAIDXP_PENALTY 9303 //You gained raid experience (with a penalty)! // TODO: TOB - 9303 You gained raid experience (with a penalty)!%1
|
||||
#define LESSER_SPELL_VERSION 11004 //%1 is a lesser version of %2 and cannot be scribed
|
||||
#define AE_RAMPAGE 11015 //%1 goes on a WILD RAMPAGE!
|
||||
#define GROUP_IS_FULL 12000 //You cannot join that group, it is full.
|
||||
#define FACE_ACCEPTED 12028 //Facial features accepted.
|
||||
#define TRACKING_BEGIN 12040 //You begin tracking %1.
|
||||
#define SPELL_LEVEL_TO_LOW 12048 //You will have to achieve level %1 before you can scribe the %2.
|
||||
#define YOU_RECEIVE_AS_SPLIT 12071 //You receive %1 as your split.
|
||||
#define YOU_RECEIVE_AS_SPLIT 12071 //You receive %1 as your split. // TODO: TOB - 12072 You receive %1 from the corpse%2.
|
||||
#define ATTACKFAILED 12158 //%1 try to %2 %3, but %4!
|
||||
#define HIT_STRING 12183 //hit
|
||||
#define CRUSH_STRING 12191 //crush
|
||||
@@ -554,7 +554,7 @@
|
||||
#define TARGET_PLAYER_FOR_GUILD_STATUS 12260
|
||||
#define TARGET_ALREADY_IN_GROUP 12265 //% 1 is already in another group.
|
||||
#define GROUP_INVITEE_NOT_FOUND 12268 //You must target a player or use /invite <name> to invite someone to your group.
|
||||
#define GROUP_INVITEE_SELF 12270 //12270 You cannot invite yourself.
|
||||
#define GROUP_INVITEE_SELF 12270 //You cannot invite yourself.
|
||||
#define ALREADY_IN_PARTY 12272 //That person is already in your party.
|
||||
#define TALKING_TO_SELF 12323 //Talking to yourself again?
|
||||
#define SPLIT_NO_GROUP 12328 //You are not in a group! Keep it all.
|
||||
@@ -593,7 +593,7 @@
|
||||
#define RANGED_TOO_CLOSE 12698 //Your target is too close to use a ranged weapon!
|
||||
#define BACKSTAB_WEAPON 12874 //You need a piercing weapon as your primary weapon in order to backstab
|
||||
#define DISARMED 12889 //You have been disarmed!
|
||||
#define DISARM_SUCCESS 12890 //You disarmed %1!
|
||||
#define DISARM_SUCCESS 12890 //You disarmed %1! // TODO: TOB - 12890 You %2disarmed %1!
|
||||
#define DISARM_FAILED 12891 //Your attempt to disarm failed.
|
||||
#define MORE_SKILLED_THAN_I 12931 //%1 tells you, 'You are more skilled than I! What could I possibly teach you?'
|
||||
#define SURNAME_EXISTS 12939 //You already have a surname. Operation failed.
|
||||
@@ -602,7 +602,7 @@
|
||||
#define REPORT_ONCE 12945 //You may only submit a report once per time that you zone. Thank you.
|
||||
#define NOW_INVISIBLE 12950 //%1 is now Invisible.
|
||||
#define NOW_VISIBLE 12951 //%1 is now Visible.
|
||||
#define YOU_TAKE_DOT 12954 //You have taken %1 damage from %2 by %3
|
||||
#define YOU_TAKE_DOT 12954 //You have taken %1 damage from %2 by %3 // TODO: TOB - 12954 You have taken %1 damage from %2 by %3.%4
|
||||
#define GUILD_NOT_MEMBER2 12966 //You are not in a guild.
|
||||
#define HOT_HEAL_SELF 12976 //You have been healed for %1 hit points by your %2.
|
||||
#define HOT_HEAL_OTHER 12997 //You have healed %1 for %2 hit points with your %3.
|
||||
@@ -612,7 +612,7 @@
|
||||
#define TOGGLE_ON 13172 //Asking server to turn ON your incoming tells.
|
||||
#define TOGGLE_OFF 13173 //Asking server to turn OFF all incoming tells for you.
|
||||
#define DUEL_INPROGRESS 13251 //You have already accepted a duel with someone else cowardly dog.
|
||||
#define OTHER_HIT_DOT 13327 //%1 has taken %2 damage from %3 by %4.
|
||||
#define GAIN_XP_BONUS 14541 //You gain experience (with a bonus)!
|
||||
#define GAIN_XP_PENALTY 14542 //You gain experience (with a penalty)!
|
||||
#define OTHER_HIT_DOT 13327 //%1 has taken %2 damage from %3 by %4. // TODO: TOB - 13327 %1 has taken %2 damage from %3 by %4.%5
|
||||
#define GAIN_XP_BONUS 14541 //You gain experience (with a bonus)! // TODO: TOB - 14541 You gain experience (with a bonus)!%1
|
||||
#define GAIN_XP_PENALTY 14542 //You gain experience (with a penalty)! // TODO: TOB - 14542 You gain experience (with a penalty)!%1
|
||||
#define GENERIC_MISS 15041 //%1 missed %2
|
||||
|
||||
Reference in New Issue
Block a user