mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 14:41:28 +00:00
Merge branch 'master' of https://github.com/EQEmu/Server
This commit is contained in:
commit
2e55c98e90
@ -1,5 +1,13 @@
|
||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||
-------------------------------------------------------
|
||||
== 01/06/2015 ==
|
||||
Trevius: Changed the pet command #defines to be based on RoF2 list of pet commands and added decodes to Titanium, SoF and SoD.
|
||||
Trevius: (RoF+) The /pet focus on/off and /pet hold on/off commands are now functional.
|
||||
Trevius: Added defines for all remaining pet commands and some support for them as well.
|
||||
|
||||
== 01/05/2015 ==
|
||||
Uleat: Fixed (added translators for) item/text links. Only 'OP_ChannelMessage' and 'OP_SpecialMesg' are currently handled..more text channels will be added as the need arises.
|
||||
|
||||
== 01/03/2015 ==
|
||||
Trevius: (RoF2) /shield (shielding) and /key (key ring) are both now functional after opcode updates.
|
||||
|
||||
|
||||
@ -149,6 +149,8 @@ public:
|
||||
static const uint32 BANDOLIER_SIZE = Titanium::consts::BANDOLIER_SIZE; // size = number of equipment slots in bandolier instance
|
||||
static const uint32 POTION_BELT_SIZE = Titanium::consts::POTION_BELT_SIZE;
|
||||
|
||||
static const size_t TEXT_LINK_BODY_LENGTH = 56;
|
||||
|
||||
// legacy-related functions
|
||||
//static int ServerToPerlSlot(int slot); // encode
|
||||
//static int PerlToServerSlot(int slot); // decode
|
||||
|
||||
@ -5269,6 +5269,23 @@ struct ClientMarqueeMessage_Struct {
|
||||
|
||||
typedef std::list<ServerLootItem_Struct*> ItemList;
|
||||
|
||||
struct TextLinkBody_Struct {
|
||||
// Current server mask: EQClientRoF2
|
||||
uint8 unknown_1; /* %1X */
|
||||
uint32 item_id; /* %05X */
|
||||
uint32 augment_1; /* %05X */
|
||||
uint32 augment_2; /* %05X */
|
||||
uint32 augment_3; /* %05X */
|
||||
uint32 augment_4; /* %05X */
|
||||
uint32 augment_5; /* %05X */
|
||||
uint32 augment_6; /* %05X */
|
||||
uint8 is_evolving; /* %1X */
|
||||
uint32 evolve_group; /* %05X */
|
||||
uint8 evolve_level; /* %02X */
|
||||
uint32 ornament_icon; /* %05X */
|
||||
int hash; /* %08X */
|
||||
};
|
||||
|
||||
// Restore structure packing to default
|
||||
#pragma pack()
|
||||
|
||||
|
||||
@ -33,6 +33,12 @@ namespace RoF
|
||||
static inline uint32 RoFToServerMainInvSlot(structs::MainInvItemSlotStruct RoFSlot);
|
||||
static inline uint32 RoFToServerCorpseSlot(uint32 RoFCorpse);
|
||||
|
||||
// server to client text link converter
|
||||
static inline void ServerToRoFTextLink(std::string& rofTextLink, const std::string& serverTextLink);
|
||||
|
||||
// client to server text link converter
|
||||
static inline void RoFToServerTextLink(std::string& serverTextLink, const std::string& rofTextLink);
|
||||
|
||||
void Register(EQStreamIdentifier &into)
|
||||
{
|
||||
//create our opcode manager if we havent already
|
||||
@ -488,7 +494,13 @@ namespace RoF
|
||||
|
||||
unsigned char *__emu_buffer = in->pBuffer;
|
||||
|
||||
in->size = strlen(emu->sender) + 1 + strlen(emu->targetname) + 1 + strlen(emu->message) + 1 + 36;
|
||||
std::string old_message = emu->message;
|
||||
std::string new_message;
|
||||
ServerToRoFTextLink(new_message, old_message);
|
||||
|
||||
//in->size = strlen(emu->sender) + 1 + strlen(emu->targetname) + 1 + strlen(emu->message) + 1 + 36;
|
||||
in->size = strlen(emu->sender) + strlen(emu->targetname) + new_message.length() + 39;
|
||||
|
||||
in->pBuffer = new unsigned char[in->size];
|
||||
|
||||
char *OutBuffer = (char *)in->pBuffer;
|
||||
@ -501,7 +513,7 @@ namespace RoF
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, 0); // Unknown
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->skill_in_language);
|
||||
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->message);
|
||||
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown
|
||||
@ -3096,6 +3108,44 @@ namespace RoF
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_SpecialMesg)
|
||||
{
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
|
||||
SpecialMesg_Struct *emu = (SpecialMesg_Struct *)in->pBuffer;
|
||||
|
||||
unsigned char *__emu_buffer = in->pBuffer;
|
||||
|
||||
std::string old_message = &emu->message[strlen(emu->sayer)];
|
||||
std::string new_message;
|
||||
ServerToRoFTextLink(new_message, old_message);
|
||||
|
||||
//in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1;
|
||||
in->size = 25 + strlen(emu->sayer) + new_message.length();
|
||||
in->pBuffer = new unsigned char[in->size];
|
||||
|
||||
char *OutBuffer = (char *)in->pBuffer;
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[0]);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[1]);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[2]);
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->msg_type);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->target_spawn_id);
|
||||
|
||||
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer);
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
|
||||
|
||||
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
|
||||
|
||||
delete[] __emu_buffer;
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
}
|
||||
|
||||
ENCODE(OP_Stun)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(Stun_Struct);
|
||||
@ -4041,7 +4091,13 @@ namespace RoF
|
||||
|
||||
uint32 Skill = VARSTRUCT_DECODE_TYPE(uint32, InBuffer);
|
||||
|
||||
__packet->size = sizeof(ChannelMessage_Struct)+strlen(InBuffer) + 1;
|
||||
std::string old_message = InBuffer;
|
||||
std::string new_message;
|
||||
RoFToServerTextLink(new_message, old_message);
|
||||
|
||||
//__packet->size = sizeof(ChannelMessage_Struct)+strlen(InBuffer) + 1;
|
||||
__packet->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1;
|
||||
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
ChannelMessage_Struct *emu = (ChannelMessage_Struct *)__packet->pBuffer;
|
||||
|
||||
@ -4050,7 +4106,7 @@ namespace RoF
|
||||
emu->language = Language;
|
||||
emu->chan_num = Channel;
|
||||
emu->skill_in_language = Skill;
|
||||
strcpy(emu->message, InBuffer);
|
||||
strcpy(emu->message, new_message.c_str());
|
||||
|
||||
delete[] __eq_buffer;
|
||||
}
|
||||
@ -4456,47 +4512,8 @@ namespace RoF
|
||||
DECODE_LENGTH_EXACT(structs::PetCommand_Struct);
|
||||
SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct);
|
||||
|
||||
switch (eq->command)
|
||||
{
|
||||
case 0x00:
|
||||
emu->command = 0x04; // Health
|
||||
break;
|
||||
case 0x01:
|
||||
emu->command = 0x10; // Leader
|
||||
break;
|
||||
case 0x02:
|
||||
emu->command = 0x07; // Attack
|
||||
break;
|
||||
case 0x04:
|
||||
emu->command = 0x08; // Follow
|
||||
break;
|
||||
case 0x05:
|
||||
emu->command = 0x05; // Guard
|
||||
break;
|
||||
case 0x06:
|
||||
emu->command = 0x09; // Sit. Needs work. This appears to be a toggle between Sit/Stand now.
|
||||
break;
|
||||
case 0x0c:
|
||||
emu->command = 0x0b; // Taunt
|
||||
break;
|
||||
case 0x0f:
|
||||
emu->command = 0x0c; // Hold
|
||||
break;
|
||||
case 0x10:
|
||||
emu->command = 0x1b; // Hold on
|
||||
break;
|
||||
case 0x11:
|
||||
emu->command = 0x1c; // Hold off
|
||||
break;
|
||||
case 0x1c:
|
||||
emu->command = 0x01; // Back
|
||||
break;
|
||||
case 0x1d:
|
||||
emu->command = 0x02; // Leave/Go Away
|
||||
break;
|
||||
default:
|
||||
emu->command = eq->command;
|
||||
}
|
||||
IN(command);
|
||||
emu->unknown = eq->unknown04;
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
@ -5627,5 +5644,78 @@ namespace RoF
|
||||
{
|
||||
return (RoFCorpse - 1);
|
||||
}
|
||||
|
||||
static inline void ServerToRoFTextLink(std::string& rofTextLink, const std::string& serverTextLink)
|
||||
{
|
||||
const char delimiter = 0x12;
|
||||
|
||||
if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find(delimiter) == std::string::npos)) {
|
||||
rofTextLink = serverTextLink;
|
||||
return;
|
||||
}
|
||||
|
||||
auto segments = SplitString(serverTextLink, delimiter);
|
||||
|
||||
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
|
||||
if (segment_iter & 1) {
|
||||
std::string new_segment;
|
||||
|
||||
// Idx: 0 1 6 11 16 21 26 31 36 37 41 43 48 (Source)
|
||||
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
|
||||
// RoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (55)
|
||||
// Diff: ^
|
||||
|
||||
new_segment.append(segments[segment_iter].substr(0, 41).c_str());
|
||||
|
||||
if (segments[segment_iter].substr(41, 1) == "0")
|
||||
new_segment.append(segments[segment_iter].substr(42, 1).c_str());
|
||||
else
|
||||
new_segment.append("F");
|
||||
|
||||
new_segment.append(segments[segment_iter].substr(43).c_str());
|
||||
|
||||
rofTextLink.push_back(delimiter);
|
||||
rofTextLink.append(new_segment.c_str());
|
||||
rofTextLink.push_back(delimiter);
|
||||
}
|
||||
else {
|
||||
rofTextLink.append(segments[segment_iter].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void RoFToServerTextLink(std::string& serverTextLink, const std::string& rofTextLink)
|
||||
{
|
||||
const char delimiter = 0x12;
|
||||
|
||||
if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (rofTextLink.find(delimiter) == std::string::npos)) {
|
||||
serverTextLink = rofTextLink;
|
||||
return;
|
||||
}
|
||||
|
||||
auto segments = SplitString(rofTextLink, delimiter);
|
||||
|
||||
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
|
||||
if (segment_iter & 1) {
|
||||
std::string new_segment;
|
||||
|
||||
// Idx: 0 1 6 11 16 21 26 31 36 37 41 42 47 (Source)
|
||||
// RoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (55)
|
||||
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
|
||||
// Diff: ^
|
||||
|
||||
new_segment.append(segments[segment_iter].substr(0, 41).c_str());
|
||||
new_segment.append("0");
|
||||
new_segment.append(segments[segment_iter].substr(41).c_str());
|
||||
|
||||
serverTextLink.push_back(delimiter);
|
||||
serverTextLink.append(new_segment.c_str());
|
||||
serverTextLink.push_back(delimiter);
|
||||
}
|
||||
else {
|
||||
serverTextLink.append(segments[segment_iter].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// end namespace RoF
|
||||
|
||||
@ -33,6 +33,12 @@ namespace RoF2
|
||||
static inline uint32 RoF2ToServerMainInvSlot(structs::MainInvItemSlotStruct RoF2Slot);
|
||||
static inline uint32 RoF2ToServerCorpseSlot(uint32 RoF2Corpse);
|
||||
|
||||
// server to client text link converter
|
||||
static inline void ServerToRoF2TextLink(std::string& rof2TextLink, const std::string& serverTextLink);
|
||||
|
||||
// client to server text link converter
|
||||
static inline void RoF2ToServerTextLink(std::string& serverTextLink, const std::string& rof2TextLink);
|
||||
|
||||
void Register(EQStreamIdentifier &into)
|
||||
{
|
||||
//create our opcode manager if we havent already
|
||||
@ -554,7 +560,13 @@ namespace RoF2
|
||||
|
||||
unsigned char *__emu_buffer = in->pBuffer;
|
||||
|
||||
in->size = strlen(emu->sender) + 1 + strlen(emu->targetname) + 1 + strlen(emu->message) + 1 + 36;
|
||||
std::string old_message = emu->message;
|
||||
std::string new_message;
|
||||
ServerToRoF2TextLink(new_message, old_message);
|
||||
|
||||
//in->size = strlen(emu->sender) + 1 + strlen(emu->targetname) + 1 + strlen(emu->message) + 1 + 36;
|
||||
in->size = strlen(emu->sender) + strlen(emu->targetname) + new_message.length() + 39;
|
||||
|
||||
in->pBuffer = new unsigned char[in->size];
|
||||
|
||||
char *OutBuffer = (char *)in->pBuffer;
|
||||
@ -567,7 +579,7 @@ namespace RoF2
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, 0); // Unknown
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->skill_in_language);
|
||||
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->message);
|
||||
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown
|
||||
@ -3162,6 +3174,44 @@ namespace RoF2
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_SpecialMesg)
|
||||
{
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
|
||||
SpecialMesg_Struct *emu = (SpecialMesg_Struct *)in->pBuffer;
|
||||
|
||||
unsigned char *__emu_buffer = in->pBuffer;
|
||||
|
||||
std::string old_message = &emu->message[strlen(emu->sayer)];
|
||||
std::string new_message;
|
||||
ServerToRoF2TextLink(new_message, old_message);
|
||||
|
||||
//in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1;
|
||||
in->size = 25 + strlen(emu->sayer) + new_message.length();
|
||||
in->pBuffer = new unsigned char[in->size];
|
||||
|
||||
char *OutBuffer = (char *)in->pBuffer;
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[0]);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[1]);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[2]);
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->msg_type);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->target_spawn_id);
|
||||
|
||||
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer);
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
|
||||
|
||||
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
|
||||
|
||||
delete[] __emu_buffer;
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
}
|
||||
|
||||
ENCODE(OP_Stun)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(Stun_Struct);
|
||||
@ -4113,7 +4163,13 @@ namespace RoF2
|
||||
|
||||
uint32 Skill = VARSTRUCT_DECODE_TYPE(uint32, InBuffer);
|
||||
|
||||
__packet->size = sizeof(ChannelMessage_Struct)+strlen(InBuffer) + 1;
|
||||
std::string old_message = InBuffer;
|
||||
std::string new_message;
|
||||
RoF2ToServerTextLink(new_message, old_message);
|
||||
|
||||
//__packet->size = sizeof(ChannelMessage_Struct)+strlen(InBuffer) + 1;
|
||||
__packet->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1;
|
||||
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
ChannelMessage_Struct *emu = (ChannelMessage_Struct *)__packet->pBuffer;
|
||||
|
||||
@ -4122,7 +4178,7 @@ namespace RoF2
|
||||
emu->language = Language;
|
||||
emu->chan_num = Channel;
|
||||
emu->skill_in_language = Skill;
|
||||
strcpy(emu->message, InBuffer);
|
||||
strcpy(emu->message, new_message.c_str());
|
||||
|
||||
delete[] __eq_buffer;
|
||||
}
|
||||
@ -4527,47 +4583,8 @@ namespace RoF2
|
||||
DECODE_LENGTH_EXACT(structs::PetCommand_Struct);
|
||||
SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct);
|
||||
|
||||
switch (eq->command)
|
||||
{
|
||||
case 0x00:
|
||||
emu->command = 0x04; // Health
|
||||
break;
|
||||
case 0x01:
|
||||
emu->command = 0x10; // Leader
|
||||
break;
|
||||
case 0x02:
|
||||
emu->command = 0x07; // Attack
|
||||
break;
|
||||
case 0x04:
|
||||
emu->command = 0x08; // Follow
|
||||
break;
|
||||
case 0x05:
|
||||
emu->command = 0x05; // Guard
|
||||
break;
|
||||
case 0x06:
|
||||
emu->command = 0x09; // Sit. Needs work. This appears to be a toggle between Sit/Stand now.
|
||||
break;
|
||||
case 0x0c:
|
||||
emu->command = 0x0b; // Taunt
|
||||
break;
|
||||
case 0x0f:
|
||||
emu->command = 0x0c; // Hold
|
||||
break;
|
||||
case 0x10:
|
||||
emu->command = 0x1b; // Hold on
|
||||
break;
|
||||
case 0x11:
|
||||
emu->command = 0x1c; // Hold off
|
||||
break;
|
||||
case 0x1c:
|
||||
emu->command = 0x01; // Back
|
||||
break;
|
||||
case 0x1d:
|
||||
emu->command = 0x02; // Leave/Go Away
|
||||
break;
|
||||
default:
|
||||
emu->command = eq->command;
|
||||
}
|
||||
IN(command);
|
||||
emu->unknown = eq->unknown04;
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
@ -5722,5 +5739,69 @@ namespace RoF2
|
||||
{
|
||||
return (RoF2Corpse + EmuConstants::CORPSE_BEGIN - 1);
|
||||
}
|
||||
|
||||
static inline void ServerToRoF2TextLink(std::string& rof2TextLink, const std::string& serverTextLink)
|
||||
{
|
||||
const char delimiter = 0x12;
|
||||
|
||||
if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find(delimiter) == std::string::npos)) {
|
||||
rof2TextLink = serverTextLink;
|
||||
return;
|
||||
}
|
||||
|
||||
auto segments = SplitString(serverTextLink, delimiter);
|
||||
|
||||
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
|
||||
if (segment_iter & 1) {
|
||||
std::string new_segment;
|
||||
|
||||
// Idx: 0 1 6 11 16 21 26 31 36 37 41 43 48 (Source)
|
||||
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
|
||||
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
|
||||
// Diff:
|
||||
|
||||
new_segment.append(segments[segment_iter]);
|
||||
|
||||
rof2TextLink.push_back(delimiter);
|
||||
rof2TextLink.append(new_segment.c_str());
|
||||
rof2TextLink.push_back(delimiter);
|
||||
}
|
||||
else {
|
||||
rof2TextLink.append(segments[segment_iter].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void RoF2ToServerTextLink(std::string& serverTextLink, const std::string& rof2TextLink)
|
||||
{
|
||||
const char delimiter = 0x12;
|
||||
|
||||
if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (rof2TextLink.find(delimiter) == std::string::npos)) {
|
||||
serverTextLink = rof2TextLink;
|
||||
return;
|
||||
}
|
||||
|
||||
auto segments = SplitString(rof2TextLink, delimiter);
|
||||
|
||||
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
|
||||
if (segment_iter & 1) {
|
||||
std::string new_segment;
|
||||
|
||||
// Idx: 0 1 6 11 16 21 26 31 36 37 41 43 48 (Source)
|
||||
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
|
||||
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
|
||||
// Diff:
|
||||
|
||||
new_segment.append(segments[segment_iter]);
|
||||
|
||||
serverTextLink.push_back(delimiter);
|
||||
serverTextLink.append(new_segment.c_str());
|
||||
serverTextLink.push_back(delimiter);
|
||||
}
|
||||
else {
|
||||
serverTextLink.append(segments[segment_iter].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// end namespace RoF2
|
||||
|
||||
@ -181,6 +181,8 @@ namespace RoF2 {
|
||||
static const uint32 BANDOLIERS_COUNT = 20; // count = number of bandolier instances
|
||||
static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance
|
||||
static const uint32 POTION_BELT_SIZE = 5;
|
||||
|
||||
static const size_t TEXT_LINK_BODY_LENGTH = 56;
|
||||
}
|
||||
|
||||
namespace limits {
|
||||
|
||||
@ -95,6 +95,7 @@ E(OP_SkillUpdate)
|
||||
E(OP_SomeItemPacketMaybe)
|
||||
E(OP_SpawnAppearance)
|
||||
E(OP_SpawnDoor)
|
||||
E(OP_SpecialMesg)
|
||||
E(OP_Stun)
|
||||
E(OP_TargetBuffs)
|
||||
E(OP_TaskDescription)
|
||||
|
||||
@ -180,6 +180,8 @@ namespace RoF {
|
||||
static const uint32 BANDOLIERS_COUNT = 20; // count = number of bandolier instances
|
||||
static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance
|
||||
static const uint32 POTION_BELT_SIZE = 5;
|
||||
|
||||
static const size_t TEXT_LINK_BODY_LENGTH = 55;
|
||||
}
|
||||
|
||||
namespace limits {
|
||||
|
||||
@ -84,6 +84,7 @@ E(OP_SkillUpdate)
|
||||
E(OP_SomeItemPacketMaybe)
|
||||
E(OP_SpawnAppearance)
|
||||
E(OP_SpawnDoor)
|
||||
E(OP_SpecialMesg)
|
||||
E(OP_Stun)
|
||||
E(OP_TargetBuffs)
|
||||
E(OP_TaskDescription)
|
||||
|
||||
@ -31,6 +31,12 @@ namespace SoD
|
||||
static inline uint32 SoDToServerSlot(uint32 SoDSlot);
|
||||
static inline uint32 SoDToServerCorpseSlot(uint32 SoDCorpse);
|
||||
|
||||
// server to client text link converter
|
||||
static inline void ServerToSoDTextLink(std::string& sodTextLink, const std::string& serverTextLink);
|
||||
|
||||
// client to server text link converter
|
||||
static inline void SoDToServerTextLink(std::string& serverTextLink, const std::string& sodTextLink);
|
||||
|
||||
void Register(EQStreamIdentifier &into)
|
||||
{
|
||||
//create our opcode manager if we havent already
|
||||
@ -296,6 +302,35 @@ namespace SoD
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_ChannelMessage)
|
||||
{
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
|
||||
ChannelMessage_Struct *emu = (ChannelMessage_Struct *)in->pBuffer;
|
||||
|
||||
unsigned char *__emu_buffer = in->pBuffer;
|
||||
|
||||
std::string old_message = emu->message;
|
||||
std::string new_message;
|
||||
ServerToSoDTextLink(new_message, old_message);
|
||||
|
||||
in->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1;
|
||||
|
||||
in->pBuffer = new unsigned char[in->size];
|
||||
|
||||
char *OutBuffer = (char *)in->pBuffer;
|
||||
|
||||
memcpy(OutBuffer, __emu_buffer, sizeof(ChannelMessage_Struct));
|
||||
|
||||
OutBuffer += sizeof(ChannelMessage_Struct);
|
||||
|
||||
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
|
||||
|
||||
delete[] __emu_buffer;
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
}
|
||||
|
||||
ENCODE(OP_CharInventory)
|
||||
{
|
||||
//consume the packet
|
||||
@ -1963,6 +1998,44 @@ namespace SoD
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_SpecialMesg)
|
||||
{
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
|
||||
SpecialMesg_Struct *emu = (SpecialMesg_Struct *)in->pBuffer;
|
||||
|
||||
unsigned char *__emu_buffer = in->pBuffer;
|
||||
|
||||
std::string old_message = &emu->message[strlen(emu->sayer)];
|
||||
std::string new_message;
|
||||
ServerToSoDTextLink(new_message, old_message);
|
||||
|
||||
//in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1;
|
||||
in->size = 25 + strlen(emu->sayer) + new_message.length();
|
||||
in->pBuffer = new unsigned char[in->size];
|
||||
|
||||
char *OutBuffer = (char *)in->pBuffer;
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[0]);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[1]);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[2]);
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->msg_type);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->target_spawn_id);
|
||||
|
||||
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer);
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
|
||||
|
||||
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
|
||||
|
||||
delete[] __emu_buffer;
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
}
|
||||
|
||||
ENCODE(OP_Stun)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(Stun_Struct);
|
||||
@ -2729,6 +2802,25 @@ namespace SoD
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_ChannelMessage)
|
||||
{
|
||||
unsigned char *__eq_buffer = __packet->pBuffer;
|
||||
|
||||
std::string old_message = (char *)&__eq_buffer[sizeof(ChannelMessage_Struct)];
|
||||
std::string new_message;
|
||||
SoDToServerTextLink(new_message, old_message);
|
||||
|
||||
__packet->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1;
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
|
||||
ChannelMessage_Struct *emu = (ChannelMessage_Struct *)__packet->pBuffer;
|
||||
|
||||
memcpy(emu, __eq_buffer, sizeof(ChannelMessage_Struct));
|
||||
strcpy(emu->message, new_message.c_str());
|
||||
|
||||
delete[] __eq_buffer;
|
||||
}
|
||||
|
||||
DECODE(OP_CharacterCreate)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::CharCreate_Struct);
|
||||
@ -3007,6 +3099,89 @@ namespace SoD
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_PetCommands)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::PetCommand_Struct);
|
||||
SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct);
|
||||
|
||||
switch (eq->command)
|
||||
{
|
||||
case 0x04:
|
||||
emu->command = 0x00; // /pet health
|
||||
break;
|
||||
case 0x10:
|
||||
emu->command = 0x01; // /pet leader
|
||||
break;
|
||||
case 0x07:
|
||||
emu->command = 0x02; // /pet attack or Pet Window
|
||||
break;
|
||||
case 0x03: // Case Guessed
|
||||
emu->command = 0x03; // /pet qattack
|
||||
case 0x08:
|
||||
emu->command = 0x04; // /pet follow or Pet Window
|
||||
break;
|
||||
case 0x05:
|
||||
emu->command = 0x05; // /pet guard or Pet Window
|
||||
break;
|
||||
case 0x09:
|
||||
emu->command = 0x07; // /pet sit or Pet Window
|
||||
break;
|
||||
case 0x0a:
|
||||
emu->command = 0x08; // /pet stand or Pet Window
|
||||
break;
|
||||
case 0x06:
|
||||
emu->command = 0x1e; // /pet guard me
|
||||
break;
|
||||
case 0x0f: // Case Made Up
|
||||
emu->command = 0x09; // /pet stop
|
||||
break;
|
||||
case 0x0b:
|
||||
emu->command = 0x0d; // /pet taunt or Pet Window
|
||||
break;
|
||||
case 0x0e:
|
||||
emu->command = 0x0e; // /pet notaunt or Pet Window
|
||||
break;
|
||||
case 0x0c:
|
||||
emu->command = 0x0f; // /pet hold
|
||||
break;
|
||||
case 0x1b:
|
||||
emu->command = 0x10; // /pet hold on
|
||||
break;
|
||||
case 0x1c:
|
||||
emu->command = 0x11; // /pet hold off
|
||||
break;
|
||||
case 0x11:
|
||||
emu->command = 0x12; // Slumber?
|
||||
break;
|
||||
case 0x12:
|
||||
emu->command = 0x15; // /pet no cast
|
||||
break;
|
||||
case 0x0d: // Case Made Up
|
||||
emu->command = 0x16; // Pet Window No Cast
|
||||
break;
|
||||
case 0x13:
|
||||
emu->command = 0x18; // /pet focus
|
||||
break;
|
||||
case 0x19:
|
||||
emu->command = 0x19; // /pet focus on
|
||||
break;
|
||||
case 0x1a:
|
||||
emu->command = 0x1a; // /pet focus off
|
||||
break;
|
||||
case 0x01:
|
||||
emu->command = 0x1c; // /pet back off
|
||||
break;
|
||||
case 0x02:
|
||||
emu->command = 0x1d; // /pet get lost
|
||||
break;
|
||||
default:
|
||||
emu->command = eq->command;
|
||||
}
|
||||
OUT(unknown);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_RaidInvite)
|
||||
{
|
||||
DECODE_LENGTH_ATLEAST(structs::RaidGeneral_Struct);
|
||||
@ -3683,5 +3858,81 @@ namespace SoD
|
||||
//uint32 ServerCorpse;
|
||||
return (SoDCorpse - 1);
|
||||
}
|
||||
|
||||
static inline void ServerToSoDTextLink(std::string& sodTextLink, const std::string& serverTextLink)
|
||||
{
|
||||
const char delimiter = 0x12;
|
||||
|
||||
if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find(delimiter) == std::string::npos)) {
|
||||
sodTextLink = serverTextLink;
|
||||
return;
|
||||
}
|
||||
|
||||
auto segments = SplitString(serverTextLink, delimiter);
|
||||
|
||||
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
|
||||
if (segment_iter & 1) {
|
||||
std::string new_segment;
|
||||
|
||||
// Idx: 0 1 6 11 16 21 26 31 36 37 41 43 48 (Source)
|
||||
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
|
||||
// SoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (50)
|
||||
// Diff: ^^^^^ ^
|
||||
|
||||
new_segment.append(segments[segment_iter].substr(0, 31).c_str());
|
||||
new_segment.append(segments[segment_iter].substr(36, 5).c_str());
|
||||
|
||||
if (segments[segment_iter].substr(41, 1) == "0")
|
||||
new_segment.append(segments[segment_iter].substr(42, 1).c_str());
|
||||
else
|
||||
new_segment.append("F");
|
||||
|
||||
new_segment.append(segments[segment_iter].substr(43).c_str());
|
||||
|
||||
sodTextLink.push_back(delimiter);
|
||||
sodTextLink.append(new_segment.c_str());
|
||||
sodTextLink.push_back(delimiter);
|
||||
}
|
||||
else {
|
||||
sodTextLink.append(segments[segment_iter].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void SoDToServerTextLink(std::string& serverTextLink, const std::string& sodTextLink)
|
||||
{
|
||||
const char delimiter = 0x12;
|
||||
|
||||
if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (sodTextLink.find(delimiter) == std::string::npos)) {
|
||||
serverTextLink = sodTextLink;
|
||||
return;
|
||||
}
|
||||
|
||||
auto segments = SplitString(sodTextLink, delimiter);
|
||||
|
||||
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
|
||||
if (segment_iter & 1) {
|
||||
std::string new_segment;
|
||||
|
||||
// Idx: 0 1 6 11 16 21 26 31 32 36 37 42 (Source)
|
||||
// SoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (50)
|
||||
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
|
||||
// Diff: ^^^^^ ^
|
||||
|
||||
new_segment.append(segments[segment_iter].substr(0, 31).c_str());
|
||||
new_segment.append("00000");
|
||||
new_segment.append(segments[segment_iter].substr(31, 5).c_str());
|
||||
new_segment.append("0");
|
||||
new_segment.append(segments[segment_iter].substr(36).c_str());
|
||||
|
||||
serverTextLink.push_back(delimiter);
|
||||
serverTextLink.append(new_segment.c_str());
|
||||
serverTextLink.push_back(delimiter);
|
||||
}
|
||||
else {
|
||||
serverTextLink.append(segments[segment_iter].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// end namespace SoD
|
||||
|
||||
@ -177,6 +177,8 @@ namespace SoD {
|
||||
static const uint32 BANDOLIERS_COUNT = 20; // count = number of bandolier instances
|
||||
static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance
|
||||
static const uint32 POTION_BELT_SIZE = 5;
|
||||
|
||||
static const size_t TEXT_LINK_BODY_LENGTH = 50;
|
||||
}
|
||||
|
||||
namespace limits {
|
||||
|
||||
@ -8,6 +8,7 @@ E(OP_Barter)
|
||||
E(OP_BazaarSearch)
|
||||
E(OP_Buff)
|
||||
E(OP_CancelTrade)
|
||||
E(OP_ChannelMessage)
|
||||
E(OP_CharInventory)
|
||||
E(OP_ClientUpdate)
|
||||
E(OP_Consider)
|
||||
@ -57,6 +58,7 @@ E(OP_ShopPlayerBuy)
|
||||
E(OP_ShopPlayerSell)
|
||||
E(OP_SomeItemPacketMaybe)
|
||||
E(OP_SpawnDoor)
|
||||
E(OP_SpecialMesg)
|
||||
E(OP_Stun)
|
||||
E(OP_TargetBuffs)
|
||||
E(OP_Track)
|
||||
@ -81,6 +83,7 @@ D(OP_BazaarSearch)
|
||||
D(OP_Buff)
|
||||
D(OP_Bug)
|
||||
D(OP_CastSpell)
|
||||
D(OP_ChannelMessage)
|
||||
D(OP_CharacterCreate)
|
||||
D(OP_ClientUpdate)
|
||||
D(OP_Consider)
|
||||
@ -101,6 +104,7 @@ D(OP_ItemVerifyRequest)
|
||||
D(OP_LoadSpellSet)
|
||||
D(OP_LootItem)
|
||||
D(OP_MoveItem)
|
||||
D(OP_PetCommands)
|
||||
D(OP_RaidInvite)
|
||||
D(OP_ReadBook)
|
||||
D(OP_Save)
|
||||
|
||||
@ -4409,7 +4409,6 @@ struct MercenaryAssign_Struct {
|
||||
/*0012*/
|
||||
};
|
||||
|
||||
|
||||
}; //end namespace structs
|
||||
}; //end namespace SoD
|
||||
|
||||
|
||||
@ -31,6 +31,12 @@ namespace SoF
|
||||
static inline uint32 SoFToServerSlot(uint32 SoFSlot);
|
||||
static inline uint32 SoFToServerCorpseSlot(uint32 SoFCorpse);
|
||||
|
||||
// server to client text link converter
|
||||
static inline void ServerToSoFTextLink(std::string& sofTextLink, const std::string& serverTextLink);
|
||||
|
||||
// client to server text link converter
|
||||
static inline void SoFToServerTextLink(std::string& serverTextLink, const std::string& sofTextLink);
|
||||
|
||||
void Register(EQStreamIdentifier &into)
|
||||
{
|
||||
//create our opcode manager if we havent already
|
||||
@ -278,6 +284,35 @@ namespace SoF
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_ChannelMessage)
|
||||
{
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
|
||||
ChannelMessage_Struct *emu = (ChannelMessage_Struct *)in->pBuffer;
|
||||
|
||||
unsigned char *__emu_buffer = in->pBuffer;
|
||||
|
||||
std::string old_message = emu->message;
|
||||
std::string new_message;
|
||||
ServerToSoFTextLink(new_message, old_message);
|
||||
|
||||
in->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1;
|
||||
|
||||
in->pBuffer = new unsigned char[in->size];
|
||||
|
||||
char *OutBuffer = (char *)in->pBuffer;
|
||||
|
||||
memcpy(OutBuffer, __emu_buffer, sizeof(ChannelMessage_Struct));
|
||||
|
||||
OutBuffer += sizeof(ChannelMessage_Struct);
|
||||
|
||||
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
|
||||
|
||||
delete[] __emu_buffer;
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
}
|
||||
|
||||
ENCODE(OP_CharInventory)
|
||||
{
|
||||
//consume the packet
|
||||
@ -1609,6 +1644,44 @@ namespace SoF
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_SpecialMesg)
|
||||
{
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
|
||||
SpecialMesg_Struct *emu = (SpecialMesg_Struct *)in->pBuffer;
|
||||
|
||||
unsigned char *__emu_buffer = in->pBuffer;
|
||||
|
||||
std::string old_message = &emu->message[strlen(emu->sayer)];
|
||||
std::string new_message;
|
||||
ServerToSoFTextLink(new_message, old_message);
|
||||
|
||||
//in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1;
|
||||
in->size = 25 + strlen(emu->sayer) + new_message.length();
|
||||
in->pBuffer = new unsigned char[in->size];
|
||||
|
||||
char *OutBuffer = (char *)in->pBuffer;
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[0]);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[1]);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[2]);
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->msg_type);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->target_spawn_id);
|
||||
|
||||
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer);
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
|
||||
|
||||
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
|
||||
|
||||
delete[] __emu_buffer;
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
}
|
||||
|
||||
ENCODE(OP_Stun)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(Stun_Struct);
|
||||
@ -2129,6 +2202,25 @@ namespace SoF
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_ChannelMessage)
|
||||
{
|
||||
unsigned char *__eq_buffer = __packet->pBuffer;
|
||||
|
||||
std::string old_message = (char *)&__eq_buffer[sizeof(ChannelMessage_Struct)];
|
||||
std::string new_message;
|
||||
SoFToServerTextLink(new_message, old_message);
|
||||
|
||||
__packet->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1;
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
|
||||
ChannelMessage_Struct *emu = (ChannelMessage_Struct *)__packet->pBuffer;
|
||||
|
||||
memcpy(emu, __eq_buffer, sizeof(ChannelMessage_Struct));
|
||||
strcpy(emu->message, new_message.c_str());
|
||||
|
||||
delete[] __eq_buffer;
|
||||
}
|
||||
|
||||
DECODE(OP_CharacterCreate)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::CharCreate_Struct);
|
||||
@ -2345,6 +2437,89 @@ namespace SoF
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_PetCommands)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::PetCommand_Struct);
|
||||
SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct);
|
||||
|
||||
switch (eq->command)
|
||||
{
|
||||
case 0x04:
|
||||
emu->command = 0x00; // /pet health
|
||||
break;
|
||||
case 0x10:
|
||||
emu->command = 0x01; // /pet leader
|
||||
break;
|
||||
case 0x07:
|
||||
emu->command = 0x02; // /pet attack or Pet Window
|
||||
break;
|
||||
case 0x03: // Case Guessed
|
||||
emu->command = 0x03; // /pet qattack
|
||||
case 0x08:
|
||||
emu->command = 0x04; // /pet follow or Pet Window
|
||||
break;
|
||||
case 0x05:
|
||||
emu->command = 0x05; // /pet guard or Pet Window
|
||||
break;
|
||||
case 0x09:
|
||||
emu->command = 0x07; // /pet sit or Pet Window
|
||||
break;
|
||||
case 0x0a:
|
||||
emu->command = 0x08; // /pet stand or Pet Window
|
||||
break;
|
||||
case 0x06:
|
||||
emu->command = 0x1e; // /pet guard me
|
||||
break;
|
||||
case 0x0f: // Case Made Up
|
||||
emu->command = 0x09; // Stop?
|
||||
break;
|
||||
case 0x0b:
|
||||
emu->command = 0x0d; // /pet taunt or Pet Window
|
||||
break;
|
||||
case 0x0e:
|
||||
emu->command = 0x0e; // /pet notaunt or Pet Window
|
||||
break;
|
||||
case 0x0c:
|
||||
emu->command = 0x0f; // /pet hold
|
||||
break;
|
||||
case 0x1b:
|
||||
emu->command = 0x10; // /pet hold on
|
||||
break;
|
||||
case 0x1c:
|
||||
emu->command = 0x11; // /pet hold off
|
||||
break;
|
||||
case 0x11:
|
||||
emu->command = 0x12; // Slumber?
|
||||
break;
|
||||
case 0x12:
|
||||
emu->command = 0x15; // /pet no cast
|
||||
break;
|
||||
case 0x0d: // Case Made Up
|
||||
emu->command = 0x16; // Pet Window No Cast
|
||||
break;
|
||||
case 0x13:
|
||||
emu->command = 0x18; // /pet focus
|
||||
break;
|
||||
case 0x19:
|
||||
emu->command = 0x19; // /pet focus on
|
||||
break;
|
||||
case 0x1a:
|
||||
emu->command = 0x1a; // /pet focus off
|
||||
break;
|
||||
case 0x01:
|
||||
emu->command = 0x1c; // /pet back off
|
||||
break;
|
||||
case 0x02:
|
||||
emu->command = 0x1d; // /pet get lost
|
||||
break;
|
||||
default:
|
||||
emu->command = eq->command;
|
||||
}
|
||||
OUT(unknown);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_RaidInvite)
|
||||
{
|
||||
DECODE_LENGTH_ATLEAST(structs::RaidGeneral_Struct);
|
||||
@ -3005,5 +3180,81 @@ namespace SoF
|
||||
//uint32 ServerCorpse;
|
||||
return (SoFCorpse - 1);
|
||||
}
|
||||
|
||||
static inline void ServerToSoFTextLink(std::string& sofTextLink, const std::string& serverTextLink)
|
||||
{
|
||||
const char delimiter = 0x12;
|
||||
|
||||
if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find(delimiter) == std::string::npos)) {
|
||||
sofTextLink = serverTextLink;
|
||||
return;
|
||||
}
|
||||
|
||||
auto segments = SplitString(serverTextLink, delimiter);
|
||||
|
||||
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
|
||||
if (segment_iter & 1) {
|
||||
std::string new_segment;
|
||||
|
||||
// Idx: 0 1 6 11 16 21 26 31 36 37 41 43 48 (Source)
|
||||
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
|
||||
// SoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (50)
|
||||
// Diff: ^^^^^ ^
|
||||
|
||||
new_segment.append(segments[segment_iter].substr(0, 31).c_str());
|
||||
new_segment.append(segments[segment_iter].substr(36, 5).c_str());
|
||||
|
||||
if (segments[segment_iter].substr(41, 1) == "0")
|
||||
new_segment.append(segments[segment_iter].substr(42, 1).c_str());
|
||||
else
|
||||
new_segment.append("F");
|
||||
|
||||
new_segment.append(segments[segment_iter].substr(43).c_str());
|
||||
|
||||
sofTextLink.push_back(delimiter);
|
||||
sofTextLink.append(new_segment.c_str());
|
||||
sofTextLink.push_back(delimiter);
|
||||
}
|
||||
else {
|
||||
sofTextLink.append(segments[segment_iter].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void SoFToServerTextLink(std::string& serverTextLink, const std::string& sofTextLink)
|
||||
{
|
||||
const char delimiter = 0x12;
|
||||
|
||||
if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (sofTextLink.find(delimiter) == std::string::npos)) {
|
||||
serverTextLink = sofTextLink;
|
||||
return;
|
||||
}
|
||||
|
||||
auto segments = SplitString(sofTextLink, delimiter);
|
||||
|
||||
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
|
||||
if (segment_iter & 1) {
|
||||
std::string new_segment;
|
||||
|
||||
// Idx: 0 1 6 11 16 21 26 31 32 36 37 42 (Source)
|
||||
// SoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (50)
|
||||
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
|
||||
// Diff: ^^^^^ ^
|
||||
|
||||
new_segment.append(segments[segment_iter].substr(0, 31).c_str());
|
||||
new_segment.append("00000");
|
||||
new_segment.append(segments[segment_iter].substr(31, 5).c_str());
|
||||
new_segment.append("0");
|
||||
new_segment.append(segments[segment_iter].substr(36).c_str());
|
||||
|
||||
serverTextLink.push_back(delimiter);
|
||||
serverTextLink.append(new_segment.c_str());
|
||||
serverTextLink.push_back(delimiter);
|
||||
}
|
||||
else {
|
||||
serverTextLink.append(segments[segment_iter].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// end namespace SoF
|
||||
|
||||
@ -177,6 +177,8 @@ namespace SoF {
|
||||
static const uint32 BANDOLIERS_COUNT = 20; // count = number of bandolier instances
|
||||
static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance
|
||||
static const uint32 POTION_BELT_SIZE = 5;
|
||||
|
||||
static const size_t TEXT_LINK_BODY_LENGTH = 50;
|
||||
}
|
||||
|
||||
namespace limits {
|
||||
|
||||
@ -8,6 +8,7 @@ E(OP_BazaarSearch)
|
||||
E(OP_BecomeTrader)
|
||||
E(OP_Buff)
|
||||
E(OP_CancelTrade)
|
||||
E(OP_ChannelMessage)
|
||||
E(OP_CharInventory)
|
||||
E(OP_ClientUpdate)
|
||||
E(OP_Consider)
|
||||
@ -50,6 +51,7 @@ E(OP_SendZonepoints)
|
||||
E(OP_ShopPlayerSell)
|
||||
E(OP_SomeItemPacketMaybe)
|
||||
E(OP_SpawnDoor)
|
||||
E(OP_SpecialMesg)
|
||||
E(OP_Stun)
|
||||
E(OP_Track)
|
||||
E(OP_Trader)
|
||||
@ -70,6 +72,7 @@ D(OP_AugmentInfo)
|
||||
D(OP_AugmentItem)
|
||||
D(OP_Buff)
|
||||
D(OP_CastSpell)
|
||||
D(OP_ChannelMessage)
|
||||
D(OP_CharacterCreate)
|
||||
D(OP_ClientUpdate)
|
||||
D(OP_Consider)
|
||||
@ -85,6 +88,7 @@ D(OP_ItemLinkClick)
|
||||
D(OP_ItemVerifyRequest)
|
||||
D(OP_LootItem)
|
||||
D(OP_MoveItem)
|
||||
D(OP_PetCommands)
|
||||
D(OP_RaidInvite)
|
||||
D(OP_ReadBook)
|
||||
D(OP_Save)
|
||||
|
||||
@ -4115,18 +4115,7 @@ struct AltCurrencySellItem_Struct {
|
||||
/*010*/ uint32 cost;
|
||||
};
|
||||
|
||||
|
||||
}; //end namespace structs
|
||||
}; //end namespace SoF
|
||||
|
||||
#endif /*SoF_STRUCTS_H_*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include "../races.h"
|
||||
|
||||
#include "../eq_packet_structs.h"
|
||||
#include "../misc_functions.h"
|
||||
#include "../string_util.h"
|
||||
#include "../item.h"
|
||||
#include "titanium_structs.h"
|
||||
@ -28,6 +29,12 @@ namespace Titanium
|
||||
static inline uint32 TitaniumToServerSlot(int16 TitaniumSlot);
|
||||
static inline uint32 TitaniumToServerCorpseSlot(int16 TitaniumCorpse);
|
||||
|
||||
// server to client text link converter
|
||||
static inline void ServerToTitaniumTextLink(std::string& titaniumTextLink, const std::string& serverTextLink);
|
||||
|
||||
// client to server text link converter
|
||||
static inline void TitaniumToServerTextLink(std::string& serverTextLink, const std::string& titaniumTextLink);
|
||||
|
||||
void Register(EQStreamIdentifier &into)
|
||||
{
|
||||
//create our opcode manager if we havent already
|
||||
@ -220,6 +227,35 @@ namespace Titanium
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_ChannelMessage)
|
||||
{
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
|
||||
ChannelMessage_Struct *emu = (ChannelMessage_Struct *)in->pBuffer;
|
||||
|
||||
unsigned char *__emu_buffer = in->pBuffer;
|
||||
|
||||
std::string old_message = emu->message;
|
||||
std::string new_message;
|
||||
ServerToTitaniumTextLink(new_message, old_message);
|
||||
|
||||
in->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1;
|
||||
|
||||
in->pBuffer = new unsigned char[in->size];
|
||||
|
||||
char *OutBuffer = (char *)in->pBuffer;
|
||||
|
||||
memcpy(OutBuffer, __emu_buffer, sizeof(ChannelMessage_Struct));
|
||||
|
||||
OutBuffer += sizeof(ChannelMessage_Struct);
|
||||
|
||||
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
|
||||
|
||||
delete[] __emu_buffer;
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
}
|
||||
|
||||
ENCODE(OP_CharInventory)
|
||||
{
|
||||
//consume the packet
|
||||
@ -1070,6 +1106,44 @@ namespace Titanium
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_SpecialMesg)
|
||||
{
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
|
||||
SpecialMesg_Struct *emu = (SpecialMesg_Struct *)in->pBuffer;
|
||||
|
||||
unsigned char *__emu_buffer = in->pBuffer;
|
||||
|
||||
std::string old_message = &emu->message[strlen(emu->sayer)];
|
||||
std::string new_message;
|
||||
ServerToTitaniumTextLink(new_message, old_message);
|
||||
|
||||
//in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1;
|
||||
in->size = 25 + strlen(emu->sayer) + new_message.length();
|
||||
in->pBuffer = new unsigned char[in->size];
|
||||
|
||||
char *OutBuffer = (char *)in->pBuffer;
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[0]);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[1]);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[2]);
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->msg_type);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->target_spawn_id);
|
||||
|
||||
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer);
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
|
||||
|
||||
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
|
||||
|
||||
delete[] __emu_buffer;
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
}
|
||||
|
||||
ENCODE(OP_Track)
|
||||
{
|
||||
EQApplicationPacket *in = *p;
|
||||
@ -1371,6 +1445,25 @@ namespace Titanium
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_ChannelMessage)
|
||||
{
|
||||
unsigned char *__eq_buffer = __packet->pBuffer;
|
||||
|
||||
std::string old_message = (char *)&__eq_buffer[sizeof(ChannelMessage_Struct)];
|
||||
std::string new_message;
|
||||
TitaniumToServerTextLink(new_message, old_message);
|
||||
|
||||
__packet->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1;
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
|
||||
ChannelMessage_Struct *emu = (ChannelMessage_Struct *)__packet->pBuffer;
|
||||
|
||||
memcpy(emu, __eq_buffer, sizeof(ChannelMessage_Struct));
|
||||
strcpy(emu->message, new_message.c_str());
|
||||
|
||||
delete[] __eq_buffer;
|
||||
}
|
||||
|
||||
DECODE(OP_CharacterCreate)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::CharCreate_Struct);
|
||||
@ -1538,6 +1631,89 @@ namespace Titanium
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_PetCommands)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::PetCommand_Struct);
|
||||
SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct);
|
||||
|
||||
switch (eq->command)
|
||||
{
|
||||
case 0x04:
|
||||
emu->command = 0x00; // /pet health
|
||||
break;
|
||||
case 0x10:
|
||||
emu->command = 0x01; // /pet leader
|
||||
break;
|
||||
case 0x07:
|
||||
emu->command = 0x02; // /pet attack or Pet Window
|
||||
break;
|
||||
case 0x03: // Case Guessed
|
||||
emu->command = 0x03; // /pet qattack
|
||||
case 0x08:
|
||||
emu->command = 0x04; // /pet follow or Pet Window
|
||||
break;
|
||||
case 0x05:
|
||||
emu->command = 0x05; // /pet guard or Pet Window
|
||||
break;
|
||||
case 0x09:
|
||||
emu->command = 0x07; // /pet sit or Pet Window
|
||||
break;
|
||||
case 0x0a:
|
||||
emu->command = 0x08; // /pet stand or Pet Window
|
||||
break;
|
||||
case 0x06:
|
||||
emu->command = 0x1e; // /pet guard me
|
||||
break;
|
||||
case 0x0f: // Case Made Up
|
||||
emu->command = 0x09; // Stop?
|
||||
break;
|
||||
case 0x0b:
|
||||
emu->command = 0x0d; // /pet taunt or Pet Window
|
||||
break;
|
||||
case 0x0e:
|
||||
emu->command = 0x0e; // /pet notaunt or Pet Window
|
||||
break;
|
||||
case 0x0c:
|
||||
emu->command = 0x0f; // /pet hold
|
||||
break;
|
||||
case 0x1b:
|
||||
emu->command = 0x10; // /pet hold on
|
||||
break;
|
||||
case 0x1c:
|
||||
emu->command = 0x11; // /pet hold off
|
||||
break;
|
||||
case 0x11:
|
||||
emu->command = 0x12; // Slumber?
|
||||
break;
|
||||
case 0x12:
|
||||
emu->command = 0x15; // /pet no cast
|
||||
break;
|
||||
case 0x0d: // Case Made Up
|
||||
emu->command = 0x16; // Pet Window No Cast
|
||||
break;
|
||||
case 0x13:
|
||||
emu->command = 0x18; // /pet focus
|
||||
break;
|
||||
case 0x19:
|
||||
emu->command = 0x19; // /pet focus on
|
||||
break;
|
||||
case 0x1a:
|
||||
emu->command = 0x1a; // /pet focus off
|
||||
break;
|
||||
case 0x01:
|
||||
emu->command = 0x1c; // /pet back off
|
||||
break;
|
||||
case 0x02:
|
||||
emu->command = 0x1d; // /pet get lost
|
||||
break;
|
||||
default:
|
||||
emu->command = eq->command;
|
||||
}
|
||||
OUT(unknown);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_ReadBook)
|
||||
{
|
||||
// no apparent slot translation needed -U
|
||||
@ -1763,5 +1939,83 @@ namespace Titanium
|
||||
//uint32 ServerCorpse;
|
||||
return TitaniumCorpse;
|
||||
}
|
||||
|
||||
static inline void ServerToTitaniumTextLink(std::string& titaniumTextLink, const std::string& serverTextLink)
|
||||
{
|
||||
const char delimiter = 0x12;
|
||||
|
||||
if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find(delimiter) == std::string::npos)) {
|
||||
titaniumTextLink = serverTextLink;
|
||||
return;
|
||||
}
|
||||
|
||||
auto segments = SplitString(serverTextLink, delimiter);
|
||||
|
||||
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
|
||||
if (segment_iter & 1) {
|
||||
std::string new_segment;
|
||||
|
||||
// Idx: 0 1 6 11 16 21 26 31 36 37 41 43 48 (Source)
|
||||
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
|
||||
// 6.2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXXXXX (45)
|
||||
// Diff: ^^^^^ ^ ^^^^^
|
||||
|
||||
new_segment.append(segments[segment_iter].substr(0, 31).c_str());
|
||||
new_segment.append(segments[segment_iter].substr(36, 5).c_str());
|
||||
|
||||
if (segments[segment_iter].substr(41, 1) == "0")
|
||||
new_segment.append(segments[segment_iter].substr(42, 1).c_str());
|
||||
else
|
||||
new_segment.append("F");
|
||||
|
||||
new_segment.append(segments[segment_iter].substr(48).c_str());
|
||||
|
||||
titaniumTextLink.push_back(delimiter);
|
||||
titaniumTextLink.append(new_segment.c_str());
|
||||
titaniumTextLink.push_back(delimiter);
|
||||
}
|
||||
else {
|
||||
titaniumTextLink.append(segments[segment_iter].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void TitaniumToServerTextLink(std::string& serverTextLink, const std::string& titaniumTextLink)
|
||||
{
|
||||
const char delimiter = 0x12;
|
||||
|
||||
if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (titaniumTextLink.find(delimiter) == std::string::npos)) {
|
||||
serverTextLink = titaniumTextLink;
|
||||
return;
|
||||
}
|
||||
|
||||
auto segments = SplitString(titaniumTextLink, delimiter);
|
||||
|
||||
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
|
||||
if (segment_iter & 1) {
|
||||
std::string new_segment;
|
||||
|
||||
// Idx: 0 1 6 11 16 21 26 31 32 36 37 (Source)
|
||||
// 6.2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXXXXX (45)
|
||||
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
|
||||
// Diff: ^^^^^ ^ ^^^^^
|
||||
|
||||
new_segment.append(segments[segment_iter].substr(0, 31).c_str());
|
||||
new_segment.append("00000");
|
||||
new_segment.append(segments[segment_iter].substr(31, 5).c_str());
|
||||
new_segment.append("0");
|
||||
new_segment.append(segments[segment_iter].substr(36, 1).c_str());
|
||||
new_segment.append("00000");
|
||||
new_segment.append(segments[segment_iter].substr(37).c_str());
|
||||
|
||||
serverTextLink.push_back(delimiter);
|
||||
serverTextLink.append(new_segment.c_str());
|
||||
serverTextLink.push_back(delimiter);
|
||||
}
|
||||
else {
|
||||
serverTextLink.append(segments[segment_iter].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// end namespace Titanium
|
||||
|
||||
@ -176,6 +176,8 @@ namespace Titanium {
|
||||
static const uint32 BANDOLIERS_COUNT = 4; // count = number of bandolier instances
|
||||
static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance
|
||||
static const uint32 POTION_BELT_SIZE = 4;
|
||||
|
||||
static const size_t TEXT_LINK_BODY_LENGTH = 45;
|
||||
}
|
||||
|
||||
namespace limits {
|
||||
|
||||
@ -4,6 +4,7 @@ E(OP_AdventureMerchantSell)
|
||||
E(OP_ApplyPoison)
|
||||
E(OP_BazaarSearch)
|
||||
E(OP_BecomeTrader)
|
||||
E(OP_ChannelMessage)
|
||||
E(OP_CharInventory)
|
||||
E(OP_DeleteCharge)
|
||||
E(OP_DeleteItem)
|
||||
@ -35,6 +36,7 @@ E(OP_RespondAA)
|
||||
E(OP_SendCharInfo)
|
||||
E(OP_SendAATable)
|
||||
E(OP_ShopPlayerSell)
|
||||
E(OP_SpecialMesg)
|
||||
E(OP_Track)
|
||||
E(OP_Trader)
|
||||
E(OP_TraderBuy)
|
||||
@ -49,6 +51,7 @@ D(OP_AdventureMerchantSell)
|
||||
D(OP_ApplyPoison)
|
||||
D(OP_AugmentItem)
|
||||
D(OP_CastSpell)
|
||||
D(OP_ChannelMessage)
|
||||
D(OP_CharacterCreate)
|
||||
D(OP_Consume)
|
||||
D(OP_DeleteItem)
|
||||
@ -59,6 +62,7 @@ D(OP_ItemLinkClick)
|
||||
D(OP_LFGuild)
|
||||
D(OP_LootItem)
|
||||
D(OP_MoveItem)
|
||||
D(OP_PetCommands)
|
||||
D(OP_ReadBook)
|
||||
D(OP_SetServerFilter)
|
||||
D(OP_ShopPlayerSell)
|
||||
|
||||
@ -3332,16 +3332,4 @@ struct LFGuild_GuildToggle_Struct
|
||||
}; //end namespace structs
|
||||
}; //end namespace Titanium
|
||||
|
||||
|
||||
|
||||
#endif /*Titanium_STRUCTS_H_*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -31,6 +31,12 @@ namespace Underfoot
|
||||
static inline uint32 UnderfootToServerSlot(uint32 UnderfootSlot);
|
||||
static inline uint32 UnderfootToServerCorpseSlot(uint32 UnderfootCorpse);
|
||||
|
||||
// server to client text link converter
|
||||
static inline void ServerToUnderfootTextLink(std::string& underfootTextLink, const std::string& serverTextLink);
|
||||
|
||||
// client to server text link converter
|
||||
static inline void UnderfootToServerTextLink(std::string& serverTextLink, const std::string& underfootTextLink);
|
||||
|
||||
void Register(EQStreamIdentifier &into)
|
||||
{
|
||||
//create our opcode manager if we havent already
|
||||
@ -432,7 +438,12 @@ namespace Underfoot
|
||||
|
||||
unsigned char *__emu_buffer = in->pBuffer;
|
||||
|
||||
in->size = strlen(emu->sender) + 1 + strlen(emu->targetname) + 1 + strlen(emu->message) + 1 + 36;
|
||||
std::string old_message = emu->message;
|
||||
std::string new_message;
|
||||
ServerToUnderfootTextLink(new_message, old_message);
|
||||
|
||||
//in->size = strlen(emu->sender) + 1 + strlen(emu->targetname) + 1 + strlen(emu->message) + 1 + 36;
|
||||
in->size = strlen(emu->sender) + strlen(emu->targetname) + new_message.length() + 39;
|
||||
|
||||
in->pBuffer = new unsigned char[in->size];
|
||||
|
||||
@ -446,7 +457,7 @@ namespace Underfoot
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, 0); // Unknown
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->skill_in_language);
|
||||
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->message);
|
||||
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown
|
||||
@ -2298,6 +2309,44 @@ namespace Underfoot
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_SpecialMesg)
|
||||
{
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
|
||||
SpecialMesg_Struct *emu = (SpecialMesg_Struct *)in->pBuffer;
|
||||
|
||||
unsigned char *__emu_buffer = in->pBuffer;
|
||||
|
||||
std::string old_message = &emu->message[strlen(emu->sayer)];
|
||||
std::string new_message;
|
||||
ServerToUnderfootTextLink(new_message, old_message);
|
||||
|
||||
//in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1;
|
||||
in->size = 25 + strlen(emu->sayer) + new_message.length();
|
||||
in->pBuffer = new unsigned char[in->size];
|
||||
|
||||
char *OutBuffer = (char *)in->pBuffer;
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[0]);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[1]);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[2]);
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->msg_type);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->target_spawn_id);
|
||||
|
||||
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer);
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0);
|
||||
|
||||
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
|
||||
|
||||
delete[] __emu_buffer;
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
}
|
||||
|
||||
ENCODE(OP_Stun)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(Stun_Struct);
|
||||
@ -3036,7 +3085,13 @@ namespace Underfoot
|
||||
|
||||
uint32 Skill = VARSTRUCT_DECODE_TYPE(uint32, InBuffer);
|
||||
|
||||
__packet->size = sizeof(ChannelMessage_Struct)+strlen(InBuffer) + 1;
|
||||
std::string old_message = InBuffer;
|
||||
std::string new_message;
|
||||
UnderfootToServerTextLink(new_message, old_message);
|
||||
|
||||
//__packet->size = sizeof(ChannelMessage_Struct)+strlen(InBuffer) + 1;
|
||||
__packet->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1;
|
||||
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
ChannelMessage_Struct *emu = (ChannelMessage_Struct *)__packet->pBuffer;
|
||||
|
||||
@ -3045,7 +3100,7 @@ namespace Underfoot
|
||||
emu->language = Language;
|
||||
emu->chan_num = Channel;
|
||||
emu->skill_in_language = Skill;
|
||||
strcpy(emu->message, InBuffer);
|
||||
strcpy(emu->message, new_message.c_str());
|
||||
|
||||
delete[] __eq_buffer;
|
||||
}
|
||||
@ -3364,57 +3419,8 @@ namespace Underfoot
|
||||
DECODE_LENGTH_EXACT(structs::PetCommand_Struct);
|
||||
SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct);
|
||||
|
||||
switch (eq->command)
|
||||
{
|
||||
case 0x00:
|
||||
emu->command = 0x04; // Health
|
||||
break;
|
||||
case 0x01:
|
||||
emu->command = 0x10; // Leader
|
||||
break;
|
||||
case 0x02:
|
||||
emu->command = 0x07; // Attack
|
||||
break;
|
||||
case 0x04:
|
||||
emu->command = 0x08; // Follow
|
||||
break;
|
||||
case 0x05:
|
||||
emu->command = 0x05; // Guard
|
||||
break;
|
||||
case 0x06:
|
||||
emu->command = 0x09; // Sit. Needs work. This appears to be a toggle between Sit/Stand now.
|
||||
break;
|
||||
case 0x0c:
|
||||
emu->command = 0x0b; // Taunt
|
||||
break;
|
||||
case 0x0f:
|
||||
emu->command = 0x0c; // Hold
|
||||
break;
|
||||
case 0x10:
|
||||
emu->command = 0x1b; // Hold on
|
||||
break;
|
||||
case 0x11:
|
||||
emu->command = 0x1c; // Hold off
|
||||
break;
|
||||
case 0x1c:
|
||||
emu->command = 0x01; // Back
|
||||
break;
|
||||
case 0x1d:
|
||||
emu->command = 0x02; // Leave/Go Away
|
||||
break;
|
||||
case 0x15:
|
||||
emu->command = 0x12; // No Cast - /command
|
||||
break;
|
||||
case 0x16:
|
||||
emu->command = 0x12; // No Cast - Pet Window
|
||||
break;
|
||||
case 0x18:
|
||||
emu->command = 0x13; // Focus - Pet Window
|
||||
break;
|
||||
default:
|
||||
emu->command = eq->command;
|
||||
}
|
||||
OUT(unknown);
|
||||
IN(command);
|
||||
IN(unknown);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
@ -4155,5 +4161,81 @@ namespace Underfoot
|
||||
//uint32 ServerCorpse;
|
||||
return (UnderfootCorpse - 1);
|
||||
}
|
||||
|
||||
static inline void ServerToUnderfootTextLink(std::string& underfootTextLink, const std::string& serverTextLink)
|
||||
{
|
||||
const char delimiter = 0x12;
|
||||
|
||||
if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find(delimiter) == std::string::npos)) {
|
||||
underfootTextLink = serverTextLink;
|
||||
return;
|
||||
}
|
||||
|
||||
auto segments = SplitString(serverTextLink, delimiter);
|
||||
|
||||
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
|
||||
if (segment_iter & 1) {
|
||||
std::string new_segment;
|
||||
|
||||
// Idx: 0 1 6 11 16 21 26 31 36 37 41 43 48 (Source)
|
||||
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
|
||||
// SoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (50)
|
||||
// Diff: ^^^^^ ^
|
||||
|
||||
new_segment.append(segments[segment_iter].substr(0, 31).c_str());
|
||||
new_segment.append(segments[segment_iter].substr(36, 5).c_str());
|
||||
|
||||
if (segments[segment_iter].substr(41, 1) == "0")
|
||||
new_segment.append(segments[segment_iter].substr(42, 1).c_str());
|
||||
else
|
||||
new_segment.append("F");
|
||||
|
||||
new_segment.append(segments[segment_iter].substr(43).c_str());
|
||||
|
||||
underfootTextLink.push_back(delimiter);
|
||||
underfootTextLink.append(new_segment.c_str());
|
||||
underfootTextLink.push_back(delimiter);
|
||||
}
|
||||
else {
|
||||
underfootTextLink.append(segments[segment_iter].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void UnderfootToServerTextLink(std::string& serverTextLink, const std::string& underfootTextLink)
|
||||
{
|
||||
const char delimiter = 0x12;
|
||||
|
||||
if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (underfootTextLink.find(delimiter) == std::string::npos)) {
|
||||
serverTextLink = underfootTextLink;
|
||||
return;
|
||||
}
|
||||
|
||||
auto segments = SplitString(underfootTextLink, delimiter);
|
||||
|
||||
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
|
||||
if (segment_iter & 1) {
|
||||
std::string new_segment;
|
||||
|
||||
// Idx: 0 1 6 11 16 21 26 31 32 36 37 42 (Source)
|
||||
// SoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (50)
|
||||
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
|
||||
// Diff: ^^^^^ ^
|
||||
|
||||
new_segment.append(segments[segment_iter].substr(0, 31).c_str());
|
||||
new_segment.append("00000");
|
||||
new_segment.append(segments[segment_iter].substr(31, 5).c_str());
|
||||
new_segment.append("0");
|
||||
new_segment.append(segments[segment_iter].substr(36).c_str());
|
||||
|
||||
serverTextLink.push_back(delimiter);
|
||||
serverTextLink.append(new_segment.c_str());
|
||||
serverTextLink.push_back(delimiter);
|
||||
}
|
||||
else {
|
||||
serverTextLink.append(segments[segment_iter].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// end namespace Underfoot
|
||||
|
||||
@ -177,6 +177,8 @@ namespace Underfoot {
|
||||
static const uint32 BANDOLIERS_COUNT = 20; // count = number of bandolier instances
|
||||
static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance
|
||||
static const uint32 POTION_BELT_SIZE = 5;
|
||||
|
||||
static const size_t TEXT_LINK_BODY_LENGTH = 50;
|
||||
}
|
||||
|
||||
namespace limits {
|
||||
|
||||
@ -65,6 +65,7 @@ E(OP_ShopPlayerSell)
|
||||
E(OP_SomeItemPacketMaybe)
|
||||
E(OP_SpawnAppearance)
|
||||
E(OP_SpawnDoor)
|
||||
E(OP_SpecialMesg)
|
||||
E(OP_Stun)
|
||||
E(OP_TargetBuffs)
|
||||
E(OP_Track)
|
||||
|
||||
@ -11707,7 +11707,6 @@ void Bot::ProcessBotCommands(Client *c, const Seperator *sep) {
|
||||
std::string item_link;
|
||||
Client::TextLink linker;
|
||||
linker.SetLinkType(linker.linkItemInst);
|
||||
linker.SetClientVersion(c->GetClientVersion());
|
||||
|
||||
for(int i = EmuConstants::EQUIPMENT_BEGIN; i <= EmuConstants::EQUIPMENT_END; ++i) {
|
||||
if((i == MainSecondary) && is2Hweapon) {
|
||||
|
||||
289
zone/client.cpp
289
zone/client.cpp
@ -6255,6 +6255,7 @@ void Client::Doppelganger(uint16 spell_id, Mob *target, const char *name_overrid
|
||||
made_npc->DR = GetDR();
|
||||
made_npc->PR = GetPR();
|
||||
made_npc->Corrup = GetCorrup();
|
||||
made_npc->PhR = GetPhR();
|
||||
// looks
|
||||
made_npc->texture = GetEquipmentMaterial(MaterialChest);
|
||||
made_npc->helmtexture = GetEquipmentMaterial(MaterialHead);
|
||||
@ -6352,7 +6353,7 @@ void Client::SendStatsWindow(Client* client, bool use_window)
|
||||
|
||||
// Set Class
|
||||
std::string class_Name = itoa(GetClass());
|
||||
std::string class_List[] = { "WAR", "CLR", "PAL", "RNG", "SK", "DRU", "MNK", "BRD", "ROG", "SHM", "NEC", "WIZ", "MAG", "ENC", "BST", "BER" };
|
||||
std::string class_List[] = { "WAR", "CLR", "PAL", "RNG", "SHD", "DRU", "MNK", "BRD", "ROG", "SHM", "NEC", "WIZ", "MAG", "ENC", "BST", "BER" };
|
||||
|
||||
if(GetClass() < 17 && GetClass() > 0) { class_Name = class_List[GetClass()-1]; }
|
||||
|
||||
@ -6440,7 +6441,7 @@ void Client::SendStatsWindow(Client* client, bool use_window)
|
||||
/*===========================*/
|
||||
std::string regen_row_header = "";
|
||||
std::string regen_row_color = "";
|
||||
std::string base_regen_field = "";
|
||||
std::string base_regen_field = "";
|
||||
std::string base_regen_spacing = "";
|
||||
std::string item_regen_field = "";
|
||||
std::string item_regen_spacing = "";
|
||||
@ -6601,8 +6602,11 @@ void Client::SendStatsWindow(Client* client, bool use_window)
|
||||
}
|
||||
case 6: {
|
||||
a_stat_name = " CHA: ";
|
||||
a_resist_name = "PhR: "; // Not implemented for clients yet
|
||||
a_stat = itoa(GetCHA());
|
||||
h_stat = itoa(GetHeroicCHA());
|
||||
a_resist = itoa(GetPhR());
|
||||
h_resist_field = itoa(GetHeroicPhR());
|
||||
break;
|
||||
}
|
||||
default: { break; }
|
||||
@ -6617,8 +6621,9 @@ void Client::SendStatsWindow(Client* client, bool use_window)
|
||||
for(int h = a_resist.size(); h < max_stat_value_len; h++) { a_resist_spacing += " . "; }
|
||||
|
||||
stat_field += indP + a_stat_name + a_stat_spacing + a_stat + heroic_color + h_stat + "</c>";
|
||||
stat_field += h_stat_spacing + a_resist_name + a_resist_spacing + a_resist + heroic_color + h_resist_field + "</c>";
|
||||
if(stat_row_counter < 6) {
|
||||
stat_field += h_stat_spacing + a_resist_name + a_resist_spacing + a_resist + heroic_color + h_resist_field + "</c><br>";
|
||||
stat_field += "<br>";
|
||||
}
|
||||
}
|
||||
/*##########################################################
|
||||
@ -6827,7 +6832,7 @@ void Client::SendStatsWindow(Client* client, bool use_window)
|
||||
client->Message(0, " Haste: %i / %i (Item: %i + Spell: %i + Over: %i)", GetHaste(), RuleI(Character, HasteCap), itembonuses.haste, spellbonuses.haste + spellbonuses.hastetype2, spellbonuses.hastetype3 + ExtraHaste);
|
||||
client->Message(0, " STR: %i STA: %i DEX: %i AGI: %i INT: %i WIS: %i CHA: %i", GetSTR(), GetSTA(), GetDEX(), GetAGI(), GetINT(), GetWIS(), GetCHA());
|
||||
client->Message(0, " hSTR: %i hSTA: %i hDEX: %i hAGI: %i hINT: %i hWIS: %i hCHA: %i", GetHeroicSTR(), GetHeroicSTA(), GetHeroicDEX(), GetHeroicAGI(), GetHeroicINT(), GetHeroicWIS(), GetHeroicCHA());
|
||||
client->Message(0, " MR: %i PR: %i FR: %i CR: %i DR: %i Corruption: %i", GetMR(), GetPR(), GetFR(), GetCR(), GetDR(), GetCorrup());
|
||||
client->Message(0, " MR: %i PR: %i FR: %i CR: %i DR: %i Corruption: %i PhR: %i", GetMR(), GetPR(), GetFR(), GetCR(), GetDR(), GetCorrup(), GetPhR());
|
||||
client->Message(0, " hMR: %i hPR: %i hFR: %i hCR: %i hDR: %i hCorruption: %i", GetHeroicMR(), GetHeroicPR(), GetHeroicFR(), GetHeroicCR(), GetHeroicDR(), GetHeroicCorrup());
|
||||
client->Message(0, " Shielding: %i Spell Shield: %i DoT Shielding: %i Stun Resist: %i Strikethrough: %i Avoidance: %i Accuracy: %i Combat Effects: %i", GetShielding(), GetSpellShield(), GetDoTShield(), GetStunResist(), GetStrikeThrough(), GetAvoidance(), GetAccuracy(), GetCombatEffects());
|
||||
client->Message(0, " Heal Amt.: %i Spell Dmg.: %i Clairvoyance: %i DS Mitigation: %i", GetHealAmt(), GetSpellDmg(), GetClair(), GetDSMit());
|
||||
@ -8271,71 +8276,27 @@ std::string Client::TextLink::GenerateLink()
|
||||
generate_body();
|
||||
generate_text();
|
||||
|
||||
if (m_LinkBody.length() && m_LinkText.length()) {
|
||||
m_Link.append(StringFormat("%c", 0x12));
|
||||
if ((m_LinkBody.length() == EmuConstants::TEXT_LINK_BODY_LENGTH) && (m_LinkText.length() > 0)) {
|
||||
m_Link.push_back(0x12);
|
||||
m_Link.append(m_LinkBody);
|
||||
m_Link.append(m_LinkText);
|
||||
m_Link.append(StringFormat("%c", 0x12));
|
||||
m_Link.push_back(0x12);
|
||||
}
|
||||
|
||||
if ((m_Link.length() == 0) || (m_Link.length() > 250)) {
|
||||
m_Error = true;
|
||||
m_Link = "<LINKER ERROR>";
|
||||
_log(CHANNELS__ERROR, "TextLink::GenerateLink() failed to generate a useable text link (LinkType: %i, Lengths: {l: %u, b: %u, t: %u})",
|
||||
_log(CHANNELS__ERROR, "TextLink::GenerateLink() failed to generate a useable text link (LinkType: %i, Lengths: {link: %u, body: %u, text: %u})",
|
||||
m_LinkType, m_Link.length(), m_LinkBody.length(), m_LinkText.length());
|
||||
#if EQDEBUG >= 5
|
||||
_log(CHANNELS__ERROR, ">> LinkBody: %s", m_LinkBody.c_str());
|
||||
_log(CHANNELS__ERROR, ">> LinkText: %s", m_LinkText.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
return m_Link;
|
||||
}
|
||||
|
||||
const char* Client::TextLink::GetLink()
|
||||
{
|
||||
if (m_Link.length() == 0)
|
||||
return nullptr;
|
||||
|
||||
return m_Link.c_str();
|
||||
}
|
||||
|
||||
const char* Client::TextLink::GetLinkBody()
|
||||
{
|
||||
if (m_LinkBody.length() == 0)
|
||||
return nullptr;
|
||||
|
||||
return m_LinkBody.c_str();
|
||||
}
|
||||
|
||||
const char* Client::TextLink::GetLinkText()
|
||||
{
|
||||
if (m_LinkText.length() == 0)
|
||||
return nullptr;
|
||||
|
||||
return m_LinkText.c_str();
|
||||
}
|
||||
|
||||
std::string Client::TextLink::GetLinkString()
|
||||
{
|
||||
if (m_Link.length() == 0)
|
||||
return "";
|
||||
|
||||
return m_Link;
|
||||
}
|
||||
|
||||
std::string Client::TextLink::GetLinkBodyString()
|
||||
{
|
||||
if (m_LinkBody.length() == 0)
|
||||
return "";
|
||||
|
||||
return m_LinkBody;
|
||||
}
|
||||
|
||||
std::string Client::TextLink::GetLinkTextString()
|
||||
{
|
||||
if (m_LinkText.length() == 0)
|
||||
return "";
|
||||
|
||||
return m_LinkText;
|
||||
}
|
||||
|
||||
void Client::TextLink::Reset()
|
||||
{
|
||||
m_LinkType = linkBlank;
|
||||
@ -8348,108 +8309,93 @@ void Client::TextLink::Reset()
|
||||
m_Link.clear();
|
||||
m_LinkBody.clear();
|
||||
m_LinkText.clear();
|
||||
m_ClientVersion = EQClientUnknown;
|
||||
m_Error = false;
|
||||
}
|
||||
|
||||
void Client::TextLink::generate_body()
|
||||
{
|
||||
enum { field_0 = 0, field_1, field_2, field_3, field_4, field_5, field_6, field_7, field_8, field_9, field_10, field_11, field_12, field_13 };
|
||||
static const int field_count = 14;
|
||||
static const bool field_use[_EQClientCount][field_count] = {
|
||||
// 6.2: MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%08X"
|
||||
// SoF: MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X"
|
||||
// RoF: MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X"
|
||||
// RoF2: MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%1X" "%04X" "%1X" "%05X" "%08X"
|
||||
/*
|
||||
Current server mask: EQClientRoF2
|
||||
|
||||
RoF2: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%02X" "%05X" "%08X" (56)
|
||||
RoF: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X" (55)
|
||||
SoF: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X" (50)
|
||||
6.2: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%08X" (45)
|
||||
*/
|
||||
|
||||
//(RoF2) %01x %05x %05x %05x %05x %05x %05x %05x %01x %01x %04x %01x %05x %08x
|
||||
{ true, true, true, true, true, true, true, true, true, true, true, true, true, true }, // EQClientUnknown
|
||||
{ true, true, true, true, true, true, true, false, false, true, true, true, false, true }, // EQClient6.2
|
||||
{ true, true, true, true, true, true, true, false, false, true, true, true, false, true }, // EQClientTitanium
|
||||
{ true, true, true, true, true, true, true, false, false, true, true, true, true, true }, // EQClientSoF
|
||||
{ true, true, true, true, true, true, true, false, false, true, true, true, true, true }, // EQClientSoD
|
||||
{ true, true, true, true, true, true, true, false, false, true, true, true, true, true }, // EQClientUnderfoot
|
||||
{ true, true, true, true, true, true, true, true, false, true, true, true, true, true }, // EQClientRoF
|
||||
{ true, true, true, true, true, true, true, true, true, true, true, true, true, true } // EQClientRoF2
|
||||
};
|
||||
|
||||
/*%01X*/ uint8 unknown_0 = NOT_USED;
|
||||
/*%05X*/ uint32 item_id = NOT_USED;
|
||||
/*%05X*/ uint32 augment_0 = NOT_USED;
|
||||
/*%05X*/ uint32 augment_1 = NOT_USED;
|
||||
/*%05X*/ uint32 augment_2 = NOT_USED;
|
||||
/*%05X*/ uint32 augment_3 = NOT_USED;
|
||||
/*%05X*/ uint32 augment_4 = NOT_USED;
|
||||
/*%05X*/ uint32 augment_5 = NOT_USED;
|
||||
/*%01X*/ uint8 unknown_8 = NOT_USED;
|
||||
/*%01X*/ uint8 unknown_9 = NOT_USED;
|
||||
/*%04X*/ uint32 unknown_10 = NOT_USED;
|
||||
/*%01X*/ uint8 unknown_11 = NOT_USED;
|
||||
/*%05X*/ uint32 unknown_12 = NOT_USED;
|
||||
/*%08X*/ int hash = NOT_USED;
|
||||
memset(&m_LinkBodyStruct, 0, sizeof(TextLinkBody_Struct));
|
||||
|
||||
const Item_Struct* item_data = nullptr;
|
||||
|
||||
switch (m_LinkType) {
|
||||
case linkBlank:
|
||||
break;
|
||||
case linkItemData:
|
||||
if (m_ItemData != nullptr) {
|
||||
item_id = m_ItemData->ID;
|
||||
// TODO: add hash call
|
||||
}
|
||||
if (m_ItemData == nullptr) { break; }
|
||||
m_LinkBodyStruct.item_id = m_ItemData->ID;
|
||||
m_LinkBodyStruct.evolve_group = m_ItemData->LoreGroup; // this probably won't work for all items
|
||||
//m_LinkBodyStruct.evolve_level = m_ItemData->EvolvingLevel;
|
||||
// TODO: add hash call
|
||||
break;
|
||||
case linkLootItem:
|
||||
if (m_LootData != nullptr) {
|
||||
const Item_Struct* item_data = database.GetItem(m_LootData->item_id);
|
||||
if (item_data == nullptr) { break; }
|
||||
item_id = item_data->ID;
|
||||
augment_0 = m_LootData->aug_1;
|
||||
augment_1 = m_LootData->aug_2;
|
||||
augment_2 = m_LootData->aug_3;
|
||||
augment_3 = m_LootData->aug_4;
|
||||
augment_4 = m_LootData->aug_5;
|
||||
augment_5 = m_LootData->aug_6;
|
||||
// TODO: add hash call
|
||||
}
|
||||
if (m_LootData == nullptr) { break; }
|
||||
item_data = database.GetItem(m_LootData->item_id);
|
||||
if (item_data == nullptr) { break; }
|
||||
m_LinkBodyStruct.item_id = item_data->ID;
|
||||
m_LinkBodyStruct.augment_1 = m_LootData->aug_1;
|
||||
m_LinkBodyStruct.augment_2 = m_LootData->aug_2;
|
||||
m_LinkBodyStruct.augment_3 = m_LootData->aug_3;
|
||||
m_LinkBodyStruct.augment_4 = m_LootData->aug_4;
|
||||
m_LinkBodyStruct.augment_5 = m_LootData->aug_5;
|
||||
m_LinkBodyStruct.augment_6 = m_LootData->aug_6;
|
||||
m_LinkBodyStruct.evolve_group = item_data->LoreGroup; // see note above
|
||||
//m_LinkBodyStruct.evolve_level = item_data->EvolvingLevel;
|
||||
// TODO: add hash call
|
||||
break;
|
||||
case linkItemInst:
|
||||
if (m_ItemInst != nullptr) {
|
||||
if (m_ItemInst->GetItem() == nullptr) { break; }
|
||||
item_id = m_ItemInst->GetItem()->ID;
|
||||
augment_0 = m_ItemInst->GetAugmentItemID(0);
|
||||
augment_1 = m_ItemInst->GetAugmentItemID(1);
|
||||
augment_2 = m_ItemInst->GetAugmentItemID(2);
|
||||
augment_3 = m_ItemInst->GetAugmentItemID(3);
|
||||
augment_4 = m_ItemInst->GetAugmentItemID(4);
|
||||
augment_5 = m_ItemInst->GetAugmentItemID(5);
|
||||
// TODO: add hash call
|
||||
}
|
||||
if (m_ItemInst == nullptr) { break; }
|
||||
if (m_ItemInst->GetItem() == nullptr) { break; }
|
||||
m_LinkBodyStruct.item_id = m_ItemInst->GetItem()->ID;
|
||||
m_LinkBodyStruct.augment_1 = m_ItemInst->GetAugmentItemID(0);
|
||||
m_LinkBodyStruct.augment_2 = m_ItemInst->GetAugmentItemID(1);
|
||||
m_LinkBodyStruct.augment_3 = m_ItemInst->GetAugmentItemID(2);
|
||||
m_LinkBodyStruct.augment_4 = m_ItemInst->GetAugmentItemID(3);
|
||||
m_LinkBodyStruct.augment_5 = m_ItemInst->GetAugmentItemID(4);
|
||||
m_LinkBodyStruct.augment_6 = m_ItemInst->GetAugmentItemID(5);
|
||||
m_LinkBodyStruct.is_evolving = (m_ItemInst->IsEvolving() ? 1 : 0);
|
||||
m_LinkBodyStruct.evolve_group = m_ItemInst->GetItem()->LoreGroup; // see note above
|
||||
m_LinkBodyStruct.evolve_level = m_ItemInst->GetEvolveLvl();
|
||||
m_LinkBodyStruct.ornament_icon = m_ItemInst->GetOrnamentationIcon();
|
||||
// TODO: add hash call
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_ProxyItemID != NOT_USED) {
|
||||
item_id = m_ProxyItemID;
|
||||
m_LinkBodyStruct.item_id = m_ProxyItemID;
|
||||
}
|
||||
|
||||
if (m_TaskUse) {
|
||||
hash = 0x0000000014505DC2;
|
||||
m_LinkBodyStruct.hash = 0x14505DC2;
|
||||
}
|
||||
|
||||
if (field_use[m_ClientVersion][field_0]) { m_LinkBody.append(StringFormat("%01x", unknown_0)); }
|
||||
if (field_use[m_ClientVersion][field_1]) { m_LinkBody.append(StringFormat("%05x", item_id)); }
|
||||
if (field_use[m_ClientVersion][field_2]) { m_LinkBody.append(StringFormat("%05x", augment_0)); }
|
||||
if (field_use[m_ClientVersion][field_3]) { m_LinkBody.append(StringFormat("%05x", augment_1)); }
|
||||
if (field_use[m_ClientVersion][field_4]) { m_LinkBody.append(StringFormat("%05x", augment_2)); }
|
||||
if (field_use[m_ClientVersion][field_5]) { m_LinkBody.append(StringFormat("%05x", augment_3)); }
|
||||
if (field_use[m_ClientVersion][field_6]) { m_LinkBody.append(StringFormat("%05x", augment_4)); }
|
||||
if (field_use[m_ClientVersion][field_7]) { m_LinkBody.append(StringFormat("%05x", augment_5)); }
|
||||
if (field_use[m_ClientVersion][field_8]) { m_LinkBody.append(StringFormat("%01x", unknown_8)); }
|
||||
if (field_use[m_ClientVersion][field_9]) { m_LinkBody.append(StringFormat("%01x", unknown_9)); }
|
||||
if (field_use[m_ClientVersion][field_10]) { m_LinkBody.append(StringFormat("%04x", unknown_10)); }
|
||||
if (field_use[m_ClientVersion][field_11]) { m_LinkBody.append(StringFormat("%01x", unknown_11)); }
|
||||
if (field_use[m_ClientVersion][field_12]) { m_LinkBody.append(StringFormat("%05x", unknown_12)); }
|
||||
if (field_use[m_ClientVersion][field_13]) { m_LinkBody.append(StringFormat("%08x", hash)); }
|
||||
m_LinkBody = StringFormat(
|
||||
"%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%02X" "%05X" "%08X",
|
||||
(0x0F & m_LinkBodyStruct.unknown_1),
|
||||
(0x000FFFFF & m_LinkBodyStruct.item_id),
|
||||
(0x000FFFFF & m_LinkBodyStruct.augment_1),
|
||||
(0x000FFFFF & m_LinkBodyStruct.augment_2),
|
||||
(0x000FFFFF & m_LinkBodyStruct.augment_3),
|
||||
(0x000FFFFF & m_LinkBodyStruct.augment_4),
|
||||
(0x000FFFFF & m_LinkBodyStruct.augment_5),
|
||||
(0x000FFFFF & m_LinkBodyStruct.augment_6),
|
||||
(0x0F & m_LinkBodyStruct.is_evolving),
|
||||
(0x0000FFFF & m_LinkBodyStruct.evolve_group),
|
||||
(0xFF & m_LinkBodyStruct.evolve_level),
|
||||
(0x000FFFFF & m_LinkBodyStruct.ornament_icon),
|
||||
(0xFFFFFFFF & m_LinkBodyStruct.hash)
|
||||
);
|
||||
}
|
||||
|
||||
void Client::TextLink::generate_text()
|
||||
@ -8459,35 +8405,74 @@ void Client::TextLink::generate_text()
|
||||
return;
|
||||
}
|
||||
|
||||
const Item_Struct* item_data = nullptr;
|
||||
|
||||
switch (m_LinkType) {
|
||||
case linkBlank:
|
||||
break;
|
||||
case linkItemData:
|
||||
if (m_ItemData != nullptr) {
|
||||
m_LinkText = m_ItemData->Name;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
if (m_ItemData == nullptr) { break; }
|
||||
m_LinkText = m_ItemData->Name;
|
||||
return;
|
||||
case linkLootItem:
|
||||
if (m_LootData != nullptr) {
|
||||
const Item_Struct* item_data = database.GetItem(m_LootData->item_id);
|
||||
if (item_data != nullptr) {
|
||||
m_LinkText = item_data->Name;
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
if (m_LootData == nullptr) { break; }
|
||||
item_data = database.GetItem(m_LootData->item_id);
|
||||
if (item_data == nullptr) { break; }
|
||||
m_LinkText = item_data->Name;
|
||||
return;
|
||||
case linkItemInst:
|
||||
if (m_ItemInst != nullptr) {
|
||||
if (m_ItemInst->GetItem() != nullptr) {
|
||||
m_LinkText = m_ItemInst->GetItem()->Name;
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
if (m_ItemInst == nullptr) { break; }
|
||||
if (m_ItemInst->GetItem() == nullptr) { break; }
|
||||
m_LinkText = m_ItemInst->GetItem()->Name;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
m_LinkText = "null";
|
||||
}
|
||||
|
||||
bool Client::TextLink::DegenerateLinkBody(TextLinkBody_Struct& textLinkBodyStruct, const std::string& textLinkBody)
|
||||
{
|
||||
memset(&textLinkBodyStruct, 0, sizeof(TextLinkBody_Struct));
|
||||
if (textLinkBody.length() != EmuConstants::TEXT_LINK_BODY_LENGTH) { return false; }
|
||||
|
||||
textLinkBodyStruct.unknown_1 = (uint8)strtol(textLinkBody.substr(0, 1).c_str(), nullptr, 16);
|
||||
textLinkBodyStruct.item_id = (uint32)strtol(textLinkBody.substr(1, 5).c_str(), nullptr, 16);
|
||||
textLinkBodyStruct.augment_1 = (uint32)strtol(textLinkBody.substr(6, 5).c_str(), nullptr, 16);
|
||||
textLinkBodyStruct.augment_2 = (uint32)strtol(textLinkBody.substr(11, 5).c_str(), nullptr, 16);
|
||||
textLinkBodyStruct.augment_3 = (uint32)strtol(textLinkBody.substr(16, 5).c_str(), nullptr, 16);
|
||||
textLinkBodyStruct.augment_4 = (uint32)strtol(textLinkBody.substr(21, 5).c_str(), nullptr, 16);
|
||||
textLinkBodyStruct.augment_5 = (uint32)strtol(textLinkBody.substr(26, 5).c_str(), nullptr, 16);
|
||||
textLinkBodyStruct.augment_6 = (uint32)strtol(textLinkBody.substr(31, 5).c_str(), nullptr, 16);
|
||||
textLinkBodyStruct.is_evolving = (uint8)strtol(textLinkBody.substr(36, 1).c_str(), nullptr, 16);
|
||||
textLinkBodyStruct.evolve_group = (uint32)strtol(textLinkBody.substr(37, 4).c_str(), nullptr, 16);
|
||||
textLinkBodyStruct.evolve_level = (uint8)strtol(textLinkBody.substr(41, 2).c_str(), nullptr, 16);
|
||||
textLinkBodyStruct.ornament_icon = (uint32)strtol(textLinkBody.substr(43, 5).c_str(), nullptr, 16);
|
||||
textLinkBodyStruct.hash = (int)strtol(textLinkBody.substr(48, 8).c_str(), nullptr, 16);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Client::TextLink::GenerateLinkBody(std::string& textLinkBody, const TextLinkBody_Struct& textLinkBodyStruct)
|
||||
{
|
||||
textLinkBody = StringFormat(
|
||||
"%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%02X" "%05X" "%08X",
|
||||
(0x0F & textLinkBodyStruct.unknown_1),
|
||||
(0x000FFFFF & textLinkBodyStruct.item_id),
|
||||
(0x000FFFFF & textLinkBodyStruct.augment_1),
|
||||
(0x000FFFFF & textLinkBodyStruct.augment_2),
|
||||
(0x000FFFFF & textLinkBodyStruct.augment_3),
|
||||
(0x000FFFFF & textLinkBodyStruct.augment_4),
|
||||
(0x000FFFFF & textLinkBodyStruct.augment_5),
|
||||
(0x000FFFFF & textLinkBodyStruct.augment_6),
|
||||
(0x0F & textLinkBodyStruct.is_evolving),
|
||||
(0x0000FFFF & textLinkBodyStruct.evolve_group),
|
||||
(0xFF & textLinkBodyStruct.evolve_level),
|
||||
(0x000FFFFF & textLinkBodyStruct.ornament_icon),
|
||||
(0xFFFFFFFF & textLinkBodyStruct.hash)
|
||||
);
|
||||
|
||||
if (textLinkBody.length() != EmuConstants::TEXT_LINK_BODY_LENGTH) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -428,6 +428,7 @@ public:
|
||||
inline virtual int32 GetPR() const { return PR; }
|
||||
inline virtual int32 GetCR() const { return CR; }
|
||||
inline virtual int32 GetCorrup() const { return Corrup; }
|
||||
inline virtual int32 GetPhR() const { return PhR; }
|
||||
|
||||
int32 GetMaxStat() const;
|
||||
int32 GetMaxResist() const;
|
||||
@ -452,6 +453,7 @@ public:
|
||||
inline uint8 GetBaseAGI() const { return m_pp.AGI; }
|
||||
inline uint8 GetBaseWIS() const { return m_pp.WIS; }
|
||||
inline uint8 GetBaseCorrup() const { return 15; } // Same for all
|
||||
inline uint8 GetBasePhR() const { return 0; } // Guessing at 0 as base
|
||||
|
||||
inline virtual int32 GetHeroicSTR() const { return itembonuses.HeroicSTR; }
|
||||
inline virtual int32 GetHeroicSTA() const { return itembonuses.HeroicSTA; }
|
||||
@ -466,6 +468,7 @@ public:
|
||||
inline virtual int32 GetHeroicPR() const { return itembonuses.HeroicPR; }
|
||||
inline virtual int32 GetHeroicCR() const { return itembonuses.HeroicCR; }
|
||||
inline virtual int32 GetHeroicCorrup() const { return itembonuses.HeroicCorrup; }
|
||||
inline virtual int32 GetHeroicPhR() const { return 0; } // Heroic PhR not implemented yet
|
||||
// Mod2
|
||||
inline virtual int32 GetShielding() const { return itembonuses.MeleeMitigation; }
|
||||
inline virtual int32 GetSpellShield() const { return itembonuses.SpellShield; }
|
||||
@ -832,20 +835,19 @@ public:
|
||||
void SetProxyItemID(uint32 proxyItemID) { m_ProxyItemID = proxyItemID; } // mainly for saylinks..but, not limited to
|
||||
void SetProxyText(const char* proxyText) { m_ProxyText = proxyText; } // overrides standard text use
|
||||
void SetTaskUse() { m_TaskUse = true; }
|
||||
void SetClientVersion(EQClientVersion clientVersion) { m_ClientVersion = EQLimits::ValidateClientVersion(clientVersion); }
|
||||
|
||||
std::string GenerateLink();
|
||||
bool LinkError() { return m_Error; }
|
||||
|
||||
const char* GetLink(); // contains full format: '/12x' '<LinkBody>' '<LinkText>' '/12x'
|
||||
const char* GetLinkBody(); // contains format: '<LinkBody>'
|
||||
const char* GetLinkText(); // contains format: '<LinkText>'
|
||||
std::string GetLinkString();
|
||||
std::string GetLinkBodyString();
|
||||
std::string GetLinkTextString();
|
||||
std::string GetLink() { return m_Link; } // contains full string format: '/12x' '<LinkBody>' '<LinkText>' '/12x'
|
||||
std::string GetLinkBody() { return m_LinkBody; } // contains string format: '<LinkBody>'
|
||||
std::string GetLinkText() { return m_LinkText; } // contains string format: '<LinkText>'
|
||||
|
||||
void Reset();
|
||||
|
||||
static bool DegenerateLinkBody(TextLinkBody_Struct& textLinkBodyStruct, const std::string& textLinkBody);
|
||||
static bool GenerateLinkBody(std::string& textLinkBody, const TextLinkBody_Struct& textLinkBodyStruct);
|
||||
|
||||
private:
|
||||
void generate_body();
|
||||
void generate_text();
|
||||
@ -857,10 +859,10 @@ public:
|
||||
uint32 m_ProxyItemID;
|
||||
const char* m_ProxyText;
|
||||
bool m_TaskUse;
|
||||
TextLinkBody_Struct m_LinkBodyStruct;
|
||||
std::string m_Link;
|
||||
std::string m_LinkBody;
|
||||
std::string m_LinkText;
|
||||
EQClientVersion m_ClientVersion;
|
||||
bool m_Error;
|
||||
};
|
||||
|
||||
|
||||
@ -9925,12 +9925,14 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
||||
uint32 PetCommand = pet->command;
|
||||
|
||||
// Handle Sit/Stand toggle in UF and later.
|
||||
/*
|
||||
if (GetClientVersion() >= EQClientUnderfoot)
|
||||
{
|
||||
if (PetCommand == PET_SITDOWN)
|
||||
if (mypet->GetPetOrder() == SPO_Sit)
|
||||
PetCommand = PET_STANDUP;
|
||||
}
|
||||
*/
|
||||
|
||||
switch (PetCommand)
|
||||
{
|
||||
@ -9968,6 +9970,31 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PET_QATTACK: {
|
||||
if (mypet->IsFeared())
|
||||
break; //prevent pet from attacking stuff while feared
|
||||
|
||||
if (!GetTarget())
|
||||
break;
|
||||
if (GetTarget()->IsMezzed()) {
|
||||
Message_StringID(10, CANNOT_WAKE, mypet->GetCleanName(), GetTarget()->GetCleanName());
|
||||
break;
|
||||
}
|
||||
|
||||
if (!mypet->IsAttackAllowed(GetTarget())) {
|
||||
mypet->Say_StringID(NOT_LEGAL_TARGET);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 2) || mypet->GetPetType() != petAnimation) {
|
||||
if (GetTarget() != this && mypet->DistNoRootNoZ(*GetTarget()) <= (RuleR(Pets, AttackCommandRange)*RuleR(Pets, AttackCommandRange))) {
|
||||
zone->AddAggroMob();
|
||||
mypet->AddToHateList(GetTarget(), 1);
|
||||
Message_StringID(MT_PetResponse, PET_ATTACKING, mypet->GetCleanName(), GetTarget()->GetCleanName());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PET_BACKOFF: {
|
||||
if (mypet->IsFeared()) break; //keeps pet running while feared
|
||||
|
||||
@ -10036,13 +10063,28 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
||||
break;
|
||||
}
|
||||
case PET_TAUNT: {
|
||||
if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 3) || mypet->GetPetType() != petAnimation) {
|
||||
if (mypet->CastToNPC()->IsTaunting())
|
||||
{
|
||||
Message_StringID(MT_PetResponse, PET_NO_TAUNT);
|
||||
mypet->CastToNPC()->SetTaunting(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
Message_StringID(MT_PetResponse, PET_DO_TAUNT);
|
||||
mypet->CastToNPC()->SetTaunting(true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PET_TAUNT_ON: {
|
||||
if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 3) || mypet->GetPetType() != petAnimation) {
|
||||
Message_StringID(MT_PetResponse, PET_DO_TAUNT);
|
||||
mypet->CastToNPC()->SetTaunting(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PET_NOTAUNT: {
|
||||
case PET_TAUNT_OFF: {
|
||||
if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 3) || mypet->GetPetType() != petAnimation) {
|
||||
Message_StringID(MT_PetResponse, PET_NO_TAUNT);
|
||||
mypet->CastToNPC()->SetTaunting(false);
|
||||
@ -10060,6 +10102,38 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PET_SIT: {
|
||||
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
|
||||
|
||||
if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 3) || mypet->GetPetType() != petAnimation) {
|
||||
if (mypet->GetPetOrder() == SPO_Sit)
|
||||
{
|
||||
mypet->Say_StringID(MT_PetResponse, PET_SIT_STRING);
|
||||
mypet->SetPetOrder(SPO_Follow);
|
||||
mypet->SendAppearancePacket(AT_Anim, ANIM_STAND);
|
||||
}
|
||||
else
|
||||
{
|
||||
mypet->Say_StringID(MT_PetResponse, PET_SIT_STRING);
|
||||
mypet->SetPetOrder(SPO_Sit);
|
||||
mypet->SetRunAnimSpeed(0);
|
||||
if (!mypet->UseBardSpellLogic()) //maybe we can have a bard pet
|
||||
mypet->InterruptSpell(); //No cast 4 u. //i guess the pet should start casting
|
||||
mypet->SendAppearancePacket(AT_Anim, ANIM_SIT);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PET_STANDUP: {
|
||||
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
|
||||
|
||||
if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 3) || mypet->GetPetType() != petAnimation) {
|
||||
mypet->Say_StringID(MT_PetResponse, PET_SIT_STRING);
|
||||
mypet->SetPetOrder(SPO_Follow);
|
||||
mypet->SendAppearancePacket(AT_Anim, ANIM_STAND);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PET_SITDOWN: {
|
||||
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
|
||||
|
||||
@ -10073,17 +10147,21 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PET_STANDUP: {
|
||||
case PET_SLUMBER: {
|
||||
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
|
||||
|
||||
if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 3) || mypet->GetPetType() != petAnimation) {
|
||||
if (mypet->GetPetType() != petAnimation) {
|
||||
// Needs to have an IsSleeping() check added and this case should toggle on/off
|
||||
mypet->Say_StringID(MT_PetResponse, PET_SIT_STRING);
|
||||
mypet->SetPetOrder(SPO_Follow);
|
||||
mypet->SendAppearancePacket(AT_Anim, ANIM_STAND);
|
||||
mypet->SetPetOrder(SPO_Sit);
|
||||
mypet->SetRunAnimSpeed(0);
|
||||
if (!mypet->UseBardSpellLogic()) //maybe we can have a bard pet
|
||||
mypet->InterruptSpell(); //No cast 4 u. //i guess the pet should start casting
|
||||
mypet->SendAppearancePacket(AT_Anim, ANIM_DEATH);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PET_SLUMBER: {
|
||||
case PET_SLUMBER_ON: {
|
||||
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
|
||||
|
||||
if (mypet->GetPetType() != petAnimation) {
|
||||
@ -10096,14 +10174,32 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PET_SLUMBER_OFF: {
|
||||
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
|
||||
|
||||
if (mypet->GetPetType() != petAnimation) {
|
||||
mypet->Say_StringID(MT_PetResponse, PET_SIT_STRING);
|
||||
mypet->SetPetOrder(SPO_Follow);
|
||||
mypet->SetRunAnimSpeed(mypet->GetBaseRunspeed());
|
||||
mypet->SendAppearancePacket(AT_Anim, ANIM_STAND);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PET_HOLD: {
|
||||
if (GetAA(aaPetDiscipline) && mypet->IsNPC()){
|
||||
if (mypet->IsFeared())
|
||||
break; //could be exploited like PET_BACKOFF
|
||||
|
||||
mypet->Say_StringID(MT_PetResponse, PET_ON_HOLD);
|
||||
mypet->WipeHateList();
|
||||
mypet->SetHeld(true);
|
||||
if (mypet->IsHeld())
|
||||
{
|
||||
mypet->SetHeld(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
mypet->Say_StringID(MT_PetResponse, PET_ON_HOLD);
|
||||
mypet->WipeHateList();
|
||||
mypet->SetHeld(true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -10123,7 +10219,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
||||
mypet->SetHeld(false);
|
||||
break;
|
||||
}
|
||||
case PET_NOCAST: {
|
||||
case PET_SPELLHOLD: {
|
||||
if (GetAA(aaAdvancedPetDiscipline) == 2 && mypet->IsNPC()) {
|
||||
if (mypet->IsFeared())
|
||||
break;
|
||||
@ -10138,6 +10234,28 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PET_SPELLHOLD_ON: {
|
||||
if (GetAA(aaAdvancedPetDiscipline) == 2 && mypet->IsNPC()) {
|
||||
if (mypet->IsFeared())
|
||||
break;
|
||||
if (!mypet->IsNoCast()) {
|
||||
Message_StringID(MT_PetResponse, PET_NOT_CASTING);
|
||||
mypet->CastToNPC()->SetNoCast(true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PET_SPELLHOLD_OFF: {
|
||||
if (GetAA(aaAdvancedPetDiscipline) == 2 && mypet->IsNPC()) {
|
||||
if (mypet->IsFeared())
|
||||
break;
|
||||
if (mypet->IsNoCast()) {
|
||||
Message_StringID(MT_PetResponse, PET_CASTING);
|
||||
mypet->CastToNPC()->SetNoCast(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PET_FOCUS: {
|
||||
if (GetAA(aaAdvancedPetDiscipline) >= 1 && mypet->IsNPC()) {
|
||||
if (mypet->IsFeared())
|
||||
|
||||
@ -2621,7 +2621,6 @@ void command_peekinv(Client *c, const Seperator *sep)
|
||||
std::string item_link;
|
||||
Client::TextLink linker;
|
||||
linker.SetLinkType(linker.linkItemInst);
|
||||
linker.SetClientVersion(c->GetClientVersion());
|
||||
|
||||
c->Message(0, "Displaying inventory for %s...", targetClient->GetName());
|
||||
|
||||
@ -5574,7 +5573,6 @@ void command_itemsearch(Client *c, const Seperator *sep)
|
||||
std::string item_link;
|
||||
Client::TextLink linker;
|
||||
linker.SetLinkType(linker.linkItemData);
|
||||
linker.SetClientVersion(c->GetClientVersion());
|
||||
|
||||
if (Seperator::IsNumber(search_criteria)) {
|
||||
item = database.GetItem(atoi(search_criteria));
|
||||
|
||||
@ -1258,23 +1258,16 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) {
|
||||
SetPlayerKillItemID(0);
|
||||
}
|
||||
|
||||
/* Send message with item link to groups and such */
|
||||
Client::TextLink linker;
|
||||
linker.SetLinkType(linker.linkItemInst);
|
||||
linker.SetItemInst(inst);
|
||||
linker.SetClientVersion(client->GetClientVersion());
|
||||
/* Send message with item link to groups and such */
|
||||
Client::TextLink linker;
|
||||
linker.SetLinkType(linker.linkItemInst);
|
||||
linker.SetItemInst(inst);
|
||||
|
||||
auto item_link = linker.GenerateLink();
|
||||
|
||||
client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, item_link.c_str());
|
||||
|
||||
if(!IsPlayerCorpse()) {
|
||||
// When sending to multiple/unknown client types, we set for the highest client..
|
||||
// ..which is processed when 'EQClientUnknown,' or default value, is selected.
|
||||
// This should help with any current issues..or it may create more! O.o
|
||||
linker.SetClientVersion(EQClientUnknown);
|
||||
item_link = linker.GenerateLink();
|
||||
|
||||
if (!IsPlayerCorpse()) {
|
||||
Group *g = client->GetGroup();
|
||||
if(g != nullptr) {
|
||||
g->GroupMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), item_link.c_str());
|
||||
|
||||
@ -576,6 +576,11 @@ int Lua_Mob::GetCorruption() {
|
||||
return self->GetCorrup();
|
||||
}
|
||||
|
||||
int Lua_Mob::GetPhR() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetPhR();
|
||||
}
|
||||
|
||||
int Lua_Mob::GetMaxSTR() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetMaxSTR();
|
||||
@ -1962,6 +1967,7 @@ luabind::scope lua_register_mob() {
|
||||
.def("GetPR", &Lua_Mob::GetPR)
|
||||
.def("GetCR", &Lua_Mob::GetCR)
|
||||
.def("GetCorruption", &Lua_Mob::GetCorruption)
|
||||
.def("GetPhR", &Lua_Mob::GetPhR)
|
||||
.def("GetMaxSTR", &Lua_Mob::GetMaxSTR)
|
||||
.def("GetMaxSTA", &Lua_Mob::GetMaxSTA)
|
||||
.def("GetMaxDEX", &Lua_Mob::GetMaxDEX)
|
||||
|
||||
@ -128,6 +128,7 @@ public:
|
||||
int GetPR();
|
||||
int GetCR();
|
||||
int GetCorruption();
|
||||
int GetPhR();
|
||||
int GetMaxSTR();
|
||||
int GetMaxSTA();
|
||||
int GetMaxDEX();
|
||||
|
||||
@ -1296,7 +1296,7 @@ void Mob::ShowStats(Client* client)
|
||||
client->Message(0, " Mana: %i Max Mana: %i", GetMana(), GetMaxMana());
|
||||
client->Message(0, " Total ATK: %i Worn/Spell ATK (Cap %i): %i", GetATK(), RuleI(Character, ItemATKCap), GetATKBonus());
|
||||
client->Message(0, " STR: %i STA: %i DEX: %i AGI: %i INT: %i WIS: %i CHA: %i", GetSTR(), GetSTA(), GetDEX(), GetAGI(), GetINT(), GetWIS(), GetCHA());
|
||||
client->Message(0, " MR: %i PR: %i FR: %i CR: %i DR: %i Corruption: %i", GetMR(), GetPR(), GetFR(), GetCR(), GetDR(), GetCorrup());
|
||||
client->Message(0, " MR: %i PR: %i FR: %i CR: %i DR: %i Corruption: %i PhR: %i", GetMR(), GetPR(), GetFR(), GetCR(), GetDR(), GetCorrup(), GetPhR());
|
||||
client->Message(0, " Race: %i BaseRace: %i Texture: %i HelmTexture: %i Gender: %i BaseGender: %i", GetRace(), GetBaseRace(), GetTexture(), GetHelmTexture(), GetGender(), GetBaseGender());
|
||||
if (client->Admin() >= 100)
|
||||
client->Message(0, " EntityID: %i PetID: %i OwnerID: %i AIControlled: %i Targetted: %i", GetID(), GetPetID(), GetOwnerID(), IsAIControlled(), targeted);
|
||||
|
||||
@ -371,7 +371,7 @@ public:
|
||||
inline virtual int32 GetPR() const { return PR + itembonuses.PR + spellbonuses.PR; }
|
||||
inline virtual int32 GetCR() const { return CR + itembonuses.CR + spellbonuses.CR; }
|
||||
inline virtual int32 GetCorrup() const { return Corrup + itembonuses.Corrup + spellbonuses.Corrup; }
|
||||
inline virtual int32 GetPhR() const { return PhR; }
|
||||
inline virtual int32 GetPhR() const { return PhR; } // PhR bonuses not implemented yet
|
||||
inline StatBonuses GetItemBonuses() const { return itembonuses; }
|
||||
inline StatBonuses GetSpellBonuses() const { return spellbonuses; }
|
||||
inline StatBonuses GetAABonuses() const { return aabonuses; }
|
||||
|
||||
@ -515,7 +515,6 @@ void NPC::QueryLoot(Client* to)
|
||||
Client::TextLink linker;
|
||||
linker.SetLinkType(linker.linkItemData);
|
||||
linker.SetItemData(item);
|
||||
linker.SetClientVersion(to->GetClientVersion());
|
||||
|
||||
auto item_link = linker.GenerateLink();
|
||||
|
||||
|
||||
@ -266,6 +266,7 @@ public:
|
||||
void SetPetSpellID(uint16 amt) {pet_spell_id = amt;}
|
||||
uint32 GetMaxDamage(uint8 tlevel);
|
||||
void SetTaunting(bool tog) {taunting = tog;}
|
||||
bool IsTaunting() const { return taunting; }
|
||||
void PickPocket(Client* thief);
|
||||
void StartSwarmTimer(uint32 duration) { swarm_timer.Start(duration); }
|
||||
void AddLootDrop(const Item_Struct*dbitem, ItemList* itemlistconst, int16 charges, uint8 minlevel, uint8 maxlevel, bool equipit, bool wearchange = false);
|
||||
|
||||
@ -2933,6 +2933,32 @@ XS(XS_Mob_GetCorruption)
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_GetPhR); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_GetPhR)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Mob::GetPhR(THIS)");
|
||||
{
|
||||
Mob * THIS;
|
||||
int32 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob *, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetPhR();
|
||||
XSprePUSH; PUSHi((IV)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_GetMaxSTR); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_GetMaxSTR)
|
||||
{
|
||||
@ -8462,7 +8488,8 @@ XS(boot_Mob)
|
||||
newXSproto(strcpy(buf, "GetDR"), XS_Mob_GetDR, file, "$");
|
||||
newXSproto(strcpy(buf, "GetPR"), XS_Mob_GetPR, file, "$");
|
||||
newXSproto(strcpy(buf, "GetCR"), XS_Mob_GetCR, file, "$");
|
||||
newXSproto(strcpy(buf, "GetCorruption"), XS_Mob_GetCR, file, "$");
|
||||
newXSproto(strcpy(buf, "GetCorruption"), XS_Mob_GetCorruption, file, "$");
|
||||
newXSproto(strcpy(buf, "GetPhR"), XS_Mob_GetPhR, file, "$");
|
||||
newXSproto(strcpy(buf, "GetMaxSTR"), XS_Mob_GetMaxSTR, file, "$");
|
||||
newXSproto(strcpy(buf, "GetMaxSTA"), XS_Mob_GetMaxSTA, file, "$");
|
||||
newXSproto(strcpy(buf, "GetMaxDEX"), XS_Mob_GetMaxDEX, file, "$");
|
||||
|
||||
51
zone/pets.h
51
zone/pets.h
@ -1,26 +1,37 @@
|
||||
#ifndef PETS_H
|
||||
#define PETS_H
|
||||
|
||||
#define PET_BACKOFF 1
|
||||
#define PET_GETLOST 2
|
||||
#define PET_HEALTHREPORT 4
|
||||
#define PET_GUARDHERE 5
|
||||
#define PET_GUARDME 6
|
||||
#define PET_ATTACK 7
|
||||
#define PET_FOLLOWME 8
|
||||
#define PET_SITDOWN 9
|
||||
#define PET_STANDUP 10
|
||||
#define PET_TAUNT 11
|
||||
#define PET_HOLD 12
|
||||
#define PET_NOTAUNT 14
|
||||
#define PET_LEADER 16
|
||||
#define PET_SLUMBER 17
|
||||
#define PET_NOCAST 18
|
||||
#define PET_FOCUS 19
|
||||
#define PET_FOCUS_ON 25
|
||||
#define PET_FOCUS_OFF 26
|
||||
#define PET_HOLD_ON 27
|
||||
#define PET_HOLD_OFF 28
|
||||
// Defines based on the RoF2 Client
|
||||
#define PET_HEALTHREPORT 0 // 0x00 - /pet health or Pet Window
|
||||
#define PET_LEADER 1 // 0x01 - /pet leader or Pet Window
|
||||
#define PET_ATTACK 2 // 0x02 - /pet attack or Pet Window
|
||||
#define PET_QATTACK 3 // 0x03 - /pet qattack or Pet Window
|
||||
#define PET_FOLLOWME 4 // 0x04 - /pet follow or Pet Window
|
||||
#define PET_GUARDHERE 5 // 0x05 - /pet guard or Pet Window
|
||||
#define PET_SIT 6 // 0x06 - /pet sit or Pet Window
|
||||
#define PET_SITDOWN 7 // 0x07 - /pet sit on
|
||||
#define PET_STANDUP 8 // 0x08 - /pet sit off
|
||||
#define PET_STOP 9 // 0x09 - /pet stop or Pet Window - Not implemented
|
||||
#define PET_STOP_ON 10 // 0x0a - /pet stop on - Not implemented
|
||||
#define PET_STOP_OFF 11 // 0x0b - /pet stop off - Not implemented
|
||||
#define PET_TAUNT 12 // 0x0c - /pet taunt or Pet Window
|
||||
#define PET_TAUNT_ON 13 // 0x0d - /pet taunt on
|
||||
#define PET_TAUNT_OFF 14 // 0x0e - /pet taunt off
|
||||
#define PET_HOLD 15 // 0x0f - /pet hold or Pet Window
|
||||
#define PET_HOLD_ON 16 // 0x10 - /pet hold on
|
||||
#define PET_HOLD_OFF 17 // 0x11 - /pet hold off
|
||||
#define PET_SLUMBER 18 // 0x12 - What activates this? - define guessed
|
||||
#define PET_SLUMBER_ON 19 // 0x13 - What activates this? - define guessed
|
||||
#define PET_SLUMBER_OFF 20 // 0x14 - What activates this? - define guessed
|
||||
#define PET_SPELLHOLD 21 // 0x15 - /pet no cast or /pet spellhold or Pet Window
|
||||
#define PET_SPELLHOLD_ON 22 // 0x16 - /pet spellhold on
|
||||
#define PET_SPELLHOLD_OFF 23 // 0x17 - /pet spellhold off
|
||||
#define PET_FOCUS 24 // 0x18 - /pet focus or Pet Window
|
||||
#define PET_FOCUS_ON 25 // 0x19 - /pet focus on
|
||||
#define PET_FOCUS_OFF 26 // 0x1a - /pet focus off
|
||||
#define PET_BACKOFF 28 // 0x1c - /pet back off
|
||||
#define PET_GETLOST 29 // 0x1d - /pet get lost
|
||||
#define PET_GUARDME 30 // 0x1e - Same as /pet follow, but different message in older clients - define not from client
|
||||
|
||||
class Mob;
|
||||
struct NPCType;
|
||||
|
||||
@ -1234,7 +1234,6 @@ void QuestManager::itemlink(int item_id) {
|
||||
Client::TextLink linker;
|
||||
linker.SetLinkType(linker.linkItemData);
|
||||
linker.SetItemData(item);
|
||||
linker.SetClientVersion(initiator->GetClientVersion());
|
||||
|
||||
auto item_link = linker.GenerateLink();
|
||||
|
||||
@ -2474,8 +2473,6 @@ const char* QuestManager::varlink(char* perltext, int item_id) {
|
||||
Client::TextLink linker;
|
||||
linker.SetLinkType(linker.linkItemData);
|
||||
linker.SetItemData(item);
|
||||
if (initiator)
|
||||
linker.SetClientVersion(initiator->GetClientVersion());
|
||||
|
||||
auto item_link = linker.GenerateLink();
|
||||
strcpy(perltext, item_link.c_str()); // link length is currently ranged from 1 to 250 in TextLink::GenerateLink()
|
||||
@ -2668,8 +2665,6 @@ const char* QuestManager::saylink(char* Phrase, bool silent, const char* LinkNam
|
||||
Client::TextLink linker;
|
||||
linker.SetProxyItemID(sayid);
|
||||
linker.SetProxyText(LinkName);
|
||||
if (initiator)
|
||||
linker.SetClientVersion(initiator->GetClientVersion());
|
||||
|
||||
auto say_link = linker.GenerateLink();
|
||||
strcpy(Phrase, say_link.c_str()); // link length is currently ranged from 1 to 250 in TextLink::GenerateLink()
|
||||
|
||||
@ -274,7 +274,15 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
||||
database.SetHackerFlag(CastToClient()->AccountName(), CastToClient()->GetCleanName(), "Clicking race/class restricted item with an invalid class");
|
||||
}
|
||||
else {
|
||||
Message_StringID(13, CANNOT_USE_ITEM);
|
||||
if (CastToClient()->GetClientVersion() >= EQClientRoF)
|
||||
{
|
||||
// Line 181 in eqstr_us.txt was changed in RoF+
|
||||
Message(15, "Your race, class, or deity cannot use this item.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Message_StringID(13, CANNOT_USE_ITEM);
|
||||
}
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
@ -2779,7 +2779,6 @@ void TaskManager::SendActiveTaskDescription(Client *c, int TaskID, int SequenceN
|
||||
Client::TextLink linker;
|
||||
linker.SetLinkType(linker.linkItemData);
|
||||
linker.SetItemData(reward_item);
|
||||
linker.SetClientVersion(c->GetClientVersion());
|
||||
linker.SetTaskUse();
|
||||
if (strlen(Tasks[TaskID]->Reward) != 0)
|
||||
linker.SetProxyText(Tasks[TaskID]->Reward);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user