Merge git://github.com/EQEmu/Server into Development

This commit is contained in:
KayenEQ 2014-10-05 07:49:20 -04:00
commit ad116af59d
23 changed files with 249 additions and 223 deletions

View File

@ -259,7 +259,10 @@ OPTION(EQEMU_BUILD_CLIENT_FILES "Build Client Import/Export Data Programs." ON)
#C++11 stuff #C++11 stuff
IF(NOT MSVC) IF(NOT MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-reserved-user-defined-literal")
ENDIF()
ENDIF(NOT MSVC) ENDIF(NOT MSVC)
#Various definitions #Various definitions

View File

@ -1,5 +1,9 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50) EQEMu Changelog (Started on Sept 24, 2003 15:50)
------------------------------------------------------- -------------------------------------------------------
== 10/03/2014 ==
Uleat: Fixed Ti(6.2) OP_AugmentInfo translation that I broke (does not currently need and I mis-read a process)
Uleat: Moved client patch OP_LootItem slot translation to external handlers
== 10/02/2014 == == 10/02/2014 ==
Kayen: Exported to PERL $client->SendSpellAnim(targetid, spellid) Kayen: Exported to PERL $client->SendSpellAnim(targetid, spellid)
This function sends the spell graphic of a spell without actually having to cast the spell. This function sends the spell graphic of a spell without actually having to cast the spell.

View File

@ -534,7 +534,7 @@ struct SpellBuffFade_Struct {
/*007*/ uint8 unknown7; /*007*/ uint8 unknown7;
/*008*/ uint32 spellid; /*008*/ uint32 spellid;
/*012*/ uint32 duration; /*012*/ uint32 duration;
/*016*/ uint32 unknown016; /*016*/ uint32 num_hits;
/*020*/ uint32 unknown020; //prolly global player ID /*020*/ uint32 unknown020; //prolly global player ID
/*024*/ uint32 slotid; /*024*/ uint32 slotid;
/*028*/ uint32 bufffade; /*028*/ uint32 bufffade;
@ -4312,9 +4312,9 @@ struct ControlBoat_Struct {
struct AugmentInfo_Struct struct AugmentInfo_Struct
{ {
/*000*/ uint32 itemid; // id of the solvent needed /*000*/ uint32 itemid; // id of the solvent needed
/*004*/ uint8 window; // window to display the information in /*004*/ uint8 window; // window to display the information in
/*005*/ uint8 unknown005[67]; // total packet length 72, all the rest were always 00 /*005*/ uint8 unknown005[67]; // total packet length 72, all the rest were always 00
/*072*/ /*072*/
}; };
@ -4602,11 +4602,13 @@ struct BuffIconEntry_Struct
uint32 buff_slot; uint32 buff_slot;
uint32 spell_id; uint32 spell_id;
uint32 tics_remaining; uint32 tics_remaining;
uint32 num_hits;
}; };
struct BuffIcon_Struct struct BuffIcon_Struct
{ {
uint32 entity_id; uint32 entity_id;
uint8 all_buffs;
uint16 count; uint16 count;
BuffIconEntry_Struct entries[0]; BuffIconEntry_Struct entries[0];
}; };

View File

@ -446,7 +446,7 @@ namespace Client62
OUT(lootee); OUT(lootee);
OUT(looter); OUT(looter);
eq->slot_id = emu->slot_id; eq->slot_id = ServerToClient62CorpseSlot(emu->slot_id);
OUT(auto_loot); OUT(auto_loot);
FINISH_ENCODE(); FINISH_ENCODE();
@ -990,11 +990,6 @@ namespace Client62
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
} }
#if 0
// needs to be tested (and OpCode found)
DECODE(OP_AugmentInfo) { DECODE_FORWARD(OP_ReadBook); }
#endif
DECODE(OP_AugmentItem) DECODE(OP_AugmentItem)
{ {
DECODE_LENGTH_EXACT(structs::AugmentItem_Struct); DECODE_LENGTH_EXACT(structs::AugmentItem_Struct);
@ -1110,7 +1105,7 @@ namespace Client62
IN(lootee); IN(lootee);
IN(looter); IN(looter);
emu->slot_id = eq->slot_id; emu->slot_id = Client62ToServerCorpseSlot(eq->slot_id);
IN(auto_loot); IN(auto_loot);
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
@ -1239,6 +1234,7 @@ namespace Client62
int i; int i;
uint32 sub_length; uint32 sub_length;
// not sure if 6.2 has a recast timer timestamp field..but, something seems amiss between this and Ti's ordering
MakeAnyLenString(&instance, MakeAnyLenString(&instance,
"%i|%i|%i|%i|%i|%i|%i|%i|%i|%i|", "%i|%i|%i|%i|%i|%i|%i|%i|%i|%i|",
stackable ? charges : 1, stackable ? charges : 1,
@ -1322,6 +1318,7 @@ namespace Client62
static inline int16 ServerToClient62CorpseSlot(uint32 ServerCorpse) static inline int16 ServerToClient62CorpseSlot(uint32 ServerCorpse)
{ {
//int16 Client62Corpse; //int16 Client62Corpse;
return ServerCorpse;
} }
static inline uint32 Client62ToServerSlot(int16 Client62Slot) static inline uint32 Client62ToServerSlot(int16 Client62Slot)
@ -1336,6 +1333,7 @@ namespace Client62
static inline uint32 Client62ToServerCorpseSlot(int16 Client62Corpse) static inline uint32 Client62ToServerCorpseSlot(int16 Client62Corpse)
{ {
//uint32 ServerCorpse; //uint32 ServerCorpse;
return Client62Corpse;
} }
} }
// end namespace Client62 // end namespace Client62

View File

@ -34,7 +34,6 @@ E(OP_ZoneSpawns)
// incoming packets that require a DECODE translation: // incoming packets that require a DECODE translation:
D(OP_AdventureMerchantSell) D(OP_AdventureMerchantSell)
D(OP_ApplyPoison) D(OP_ApplyPoison)
//D(OP_AugmentInfo) - needs opcode for conf file update
D(OP_AugmentItem) D(OP_AugmentItem)
D(OP_CastSpell) D(OP_CastSpell)
D(OP_CharacterCreate) D(OP_CharacterCreate)

View File

@ -3099,11 +3099,6 @@ struct GuildMemberUpdate_Struct {
/*72*/ uint32 unknown072; /*72*/ uint32 unknown072;
}; };
}; //end namespace structs }; //end namespace structs
}; //end namespace Client62 }; //end namespace Client62

View File

@ -376,6 +376,7 @@ namespace RoF
OUT(duration); OUT(duration);
eq->playerId = 0x7cde; eq->playerId = 0x7cde;
OUT(slotid); OUT(slotid);
OUT(num_hits);
if (emu->bufffade == 1) if (emu->bufffade == 1)
eq->bufffade = 1; eq->bufffade = 1;
else else
@ -414,7 +415,7 @@ namespace RoF
__packet->WriteUInt32(emu->entity_id); __packet->WriteUInt32(emu->entity_id);
__packet->WriteUInt32(0); // PlayerID ? __packet->WriteUInt32(0); // PlayerID ?
__packet->WriteUInt8(1); // 1 indicates all buffs on the player (0 to add or remove a single buff) __packet->WriteUInt8(emu->all_buffs); // 1 indicates all buffs on the player (0 to add or remove a single buff)
__packet->WriteUInt16(emu->count); __packet->WriteUInt16(emu->count);
for (uint16 i = 0; i < emu->count; ++i) for (uint16 i = 0; i < emu->count; ++i)
@ -429,10 +430,10 @@ namespace RoF
__packet->WriteUInt32(buffslot); __packet->WriteUInt32(buffslot);
__packet->WriteUInt32(emu->entries[i].spell_id); __packet->WriteUInt32(emu->entries[i].spell_id);
__packet->WriteUInt32(emu->entries[i].tics_remaining); __packet->WriteUInt32(emu->entries[i].tics_remaining);
__packet->WriteUInt32(0); // Unknown __packet->WriteUInt32(emu->entries[i].num_hits); // Unknown
__packet->WriteString(""); __packet->WriteString("");
} }
__packet->WriteUInt8(0); // Unknown __packet->WriteUInt8(!emu->all_buffs); // Unknown
FINISH_ENCODE(); FINISH_ENCODE();
} }
@ -1423,7 +1424,7 @@ namespace RoF
OUT(lootee); OUT(lootee);
OUT(looter); OUT(looter);
eq->slot_id = emu->slot_id + 1; eq->slot_id = ServerToRoFCorpseSlot(emu->slot_id);
OUT(auto_loot); OUT(auto_loot);
FINISH_ENCODE(); FINISH_ENCODE();
@ -4405,7 +4406,7 @@ namespace RoF
IN(lootee); IN(lootee);
IN(looter); IN(looter);
emu->slot_id = eq->slot_id - 1; emu->slot_id = RoFToServerCorpseSlot(eq->slot_id);
IN(auto_loot); IN(auto_loot);
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
@ -5406,6 +5407,7 @@ namespace RoF
static inline uint32 ServerToRoFCorpseSlot(uint32 ServerCorpse) static inline uint32 ServerToRoFCorpseSlot(uint32 ServerCorpse)
{ {
//uint32 RoFCorpse; //uint32 RoFCorpse;
return (ServerCorpse + 1);
} }
static inline uint32 RoFToServerSlot(structs::ItemSlotStruct RoFSlot) static inline uint32 RoFToServerSlot(structs::ItemSlotStruct RoFSlot)
@ -5546,6 +5548,7 @@ namespace RoF
static inline uint32 RoFToServerCorpseSlot(uint32 RoFCorpse) static inline uint32 RoFToServerCorpseSlot(uint32 RoFCorpse)
{ {
//uint32 ServerCorpse; //uint32 ServerCorpse;
return (RoFCorpse - 1);
} }
} }
// end namespace RoF // end namespace RoF

View File

@ -712,7 +712,8 @@ struct SpellBuffFade_Struct_Live {
/*012*/ uint32 spellid; /*012*/ uint32 spellid;
/*016*/ uint32 duration; /*016*/ uint32 duration;
/*020*/ uint32 playerId; // Global player ID? /*020*/ uint32 playerId; // Global player ID?
/*024*/ uint8 unknown0028[68]; /*024*/ uint32 num_hits;
/*028*/ uint8 unknown0028[64];
/*092*/ uint32 slotid; /*092*/ uint32 slotid;
/*096*/ uint32 bufffade; /*096*/ uint32 bufffade;
/*100*/ /*100*/
@ -726,7 +727,7 @@ struct SpellBuffFade_Struct {
/*007*/ uint8 unknown7; /*007*/ uint8 unknown7;
/*008*/ uint32 spellid; /*008*/ uint32 spellid;
/*012*/ uint32 duration; /*012*/ uint32 duration;
/*016*/ uint32 unknown016; /*016*/ uint32 num_hits;
/*020*/ uint32 unknown020; // Global player ID? /*020*/ uint32 unknown020; // Global player ID?
/*024*/ uint32 playerId; // Player id who cast the buff /*024*/ uint32 playerId; // Player id who cast the buff
/*028*/ uint32 slotid; /*028*/ uint32 slotid;
@ -741,6 +742,27 @@ struct BuffRemoveRequest_Struct
/*08*/ /*08*/
}; };
#if 0
// not in use
struct BuffIconEntry_Struct {
/*000*/ uint32 buff_slot;
/*004*/ uint32 spell_id;
/*008*/ uint32 tics_remaining;
/*012*/ uint32 num_hits;
// char name[0]; caster name is also here sometimes
// uint8 unknownend; 1 when single, 0 when all opposite of all_buffs?
};
// not in use
struct BuffIcon_Struct {
/*000*/ uint32 entity_id;
/*004*/ uint32 unknown004;
/*008*/ uint8 all_buffs; // 1 when updating all buffs, 0 when doing one
/*009*/ uint16 count;
/*011*/ BuffIconEntry_Struct entires[0];
};
#endif
struct GMTrainee_Struct struct GMTrainee_Struct
{ {
/*000*/ uint32 npcid; /*000*/ uint32 npcid;
@ -4585,9 +4607,9 @@ struct ItemQuaternaryBodyStruct
struct AugmentInfo_Struct struct AugmentInfo_Struct
{ {
/*000*/ uint32 itemid; // id of the solvent needed /*000*/ uint32 itemid; // id of the solvent needed
/*004*/ uint8 window; // window to display the information in /*004*/ uint8 window; // window to display the information in
/*005*/ uint8 unknown005[71]; // total packet length 76, all the rest were always 00 /*005*/ uint8 unknown005[71]; // total packet length 76, all the rest were always 00
/*076*/ /*076*/
}; };

View File

@ -984,7 +984,7 @@ namespace SoD
OUT(lootee); OUT(lootee);
OUT(looter); OUT(looter);
eq->slot_id = emu->slot_id + 1; eq->slot_id = ServerToSoDCorpseSlot(emu->slot_id);
OUT(auto_loot); OUT(auto_loot);
FINISH_ENCODE(); FINISH_ENCODE();
@ -2956,7 +2956,7 @@ namespace SoD
IN(lootee); IN(lootee);
IN(looter); IN(looter);
emu->slot_id = eq->slot_id - 1; emu->slot_id = SoDToServerCorpseSlot(eq->slot_id);
IN(auto_loot); IN(auto_loot);
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
@ -3599,6 +3599,7 @@ namespace SoD
static inline uint32 ServerToSoDCorpseSlot(uint32 ServerCorpse) static inline uint32 ServerToSoDCorpseSlot(uint32 ServerCorpse)
{ {
//uint32 SoDCorpse; //uint32 SoDCorpse;
return (ServerCorpse + 1);
} }
static inline uint32 SoDToServerSlot(uint32 SoDSlot) static inline uint32 SoDToServerSlot(uint32 SoDSlot)
@ -3623,6 +3624,7 @@ namespace SoD
static inline uint32 SoDToServerCorpseSlot(uint32 SoDCorpse) static inline uint32 SoDToServerCorpseSlot(uint32 SoDCorpse)
{ {
//uint32 ServerCorpse; //uint32 ServerCorpse;
return (SoDCorpse - 1);
} }
} }
// end namespace SoD // end namespace SoD

View File

@ -4109,9 +4109,9 @@ struct ItemQuaternaryBodyStruct
struct AugmentInfo_Struct struct AugmentInfo_Struct
{ {
/*000*/ uint32 itemid; // id of the solvent needed /*000*/ uint32 itemid; // id of the solvent needed
/*004*/ uint8 window; // window to display the information in /*004*/ uint8 window; // window to display the information in
/*005*/ uint8 unknown005[71]; // total packet length 76, all the rest were always 00 /*005*/ uint8 unknown005[71]; // total packet length 76, all the rest were always 00
/*076*/ /*076*/
}; };

View File

@ -783,7 +783,7 @@ namespace SoF
OUT(lootee); OUT(lootee);
OUT(looter); OUT(looter);
eq->slot_id = emu->slot_id + 1; eq->slot_id = ServerToSoFCorpseSlot(emu->slot_id);
OUT(auto_loot); OUT(auto_loot);
FINISH_ENCODE(); FINISH_ENCODE();
@ -2294,7 +2294,7 @@ namespace SoF
IN(lootee); IN(lootee);
IN(looter); IN(looter);
emu->slot_id = eq->slot_id - 1; emu->slot_id = SoFToServerCorpseSlot(eq->slot_id);
IN(auto_loot); IN(auto_loot);
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
@ -2920,6 +2920,7 @@ namespace SoF
static inline uint32 ServerToSoFCorpseSlot(uint32 ServerCorpse) static inline uint32 ServerToSoFCorpseSlot(uint32 ServerCorpse)
{ {
//uint32 SoFCorpse; //uint32 SoFCorpse;
return (ServerCorpse + 1);
} }
static inline uint32 SoFToServerSlot(uint32 SoFSlot) static inline uint32 SoFToServerSlot(uint32 SoFSlot)
@ -2945,6 +2946,7 @@ namespace SoF
static inline uint32 SoFToServerCorpseSlot(uint32 SoFCorpse) static inline uint32 SoFToServerCorpseSlot(uint32 SoFCorpse)
{ {
//uint32 ServerCorpse; //uint32 ServerCorpse;
return (SoFCorpse - 1);
} }
} }
// end namespace SoF // end namespace SoF

View File

@ -3963,9 +3963,9 @@ struct ItemQuaternaryBodyStruct
struct AugmentInfo_Struct struct AugmentInfo_Struct
{ {
/*000*/ uint32 itemid; // id of the solvent needed /*000*/ uint32 itemid; // id of the solvent needed
/*004*/ uint8 window; // window to display the information in /*004*/ uint8 window; // window to display the information in
/*005*/ uint8 unknown005[71]; // total packet length 76, all the rest were always 00 /*005*/ uint8 unknown005[71]; // total packet length 76, all the rest were always 00
/*076*/ /*076*/
}; };

View File

@ -654,7 +654,7 @@ namespace Titanium
OUT(lootee); OUT(lootee);
OUT(looter); OUT(looter);
eq->slot_id = emu->slot_id; eq->slot_id = ServerToTitaniumCorpseSlot(emu->slot_id);
OUT(auto_loot); OUT(auto_loot);
FINISH_ENCODE(); FINISH_ENCODE();
@ -1347,9 +1347,6 @@ namespace Titanium
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
} }
// needs to be tested
DECODE(OP_AugmentInfo) { DECODE_FORWARD(OP_ReadBook); }
DECODE(OP_AugmentItem) DECODE(OP_AugmentItem)
{ {
DECODE_LENGTH_EXACT(structs::AugmentItem_Struct); DECODE_LENGTH_EXACT(structs::AugmentItem_Struct);
@ -1520,7 +1517,7 @@ namespace Titanium
IN(lootee); IN(lootee);
IN(looter); IN(looter);
emu->slot_id = eq->slot_id; emu->slot_id = TitaniumToServerCorpseSlot(eq->slot_id);
IN(auto_loot); IN(auto_loot);
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
@ -1678,7 +1675,7 @@ namespace Titanium
0, 0,
//merchant_slot, //instance ID, bullshit for now //merchant_slot, //instance ID, bullshit for now
(merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot, (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot,
0, 0, // item recast timer timestamp field (aka..last_cast_time field in SoF+ clients)
(stackable ? ((inst->GetItem()->ItemType == ItemTypePotion) ? 1 : 0) : charges), (stackable ? ((inst->GetItem()->ItemType == ItemTypePotion) ? 1 : 0) : charges),
inst->IsInstNoDrop() ? 1 : 0, inst->IsInstNoDrop() ? 1 : 0,
0 0
@ -1748,6 +1745,7 @@ namespace Titanium
static inline int16 ServerToTitaniumCorpseSlot(uint32 ServerCorpse) static inline int16 ServerToTitaniumCorpseSlot(uint32 ServerCorpse)
{ {
//int16 TitaniumCorpse; //int16 TitaniumCorpse;
return ServerCorpse;
} }
static inline uint32 TitaniumToServerSlot(int16 TitaniumSlot) static inline uint32 TitaniumToServerSlot(int16 TitaniumSlot)
@ -1762,6 +1760,7 @@ namespace Titanium
static inline uint32 TitaniumToServerCorpseSlot(int16 TitaniumCorpse) static inline uint32 TitaniumToServerCorpseSlot(int16 TitaniumCorpse)
{ {
//uint32 ServerCorpse; //uint32 ServerCorpse;
return TitaniumCorpse;
} }
} }
// end namespace Titanium // end namespace Titanium

View File

@ -47,7 +47,6 @@ E(OP_ZoneSpawns)
// incoming packets that require a DECODE translation: // incoming packets that require a DECODE translation:
D(OP_AdventureMerchantSell) D(OP_AdventureMerchantSell)
D(OP_ApplyPoison) D(OP_ApplyPoison)
D(OP_AugmentInfo)
D(OP_AugmentItem) D(OP_AugmentItem)
D(OP_CastSpell) D(OP_CastSpell)
D(OP_CharacterCreate) D(OP_CharacterCreate)

View File

@ -330,6 +330,7 @@ namespace Underfoot
OUT(duration); OUT(duration);
OUT(slotid); OUT(slotid);
OUT(bufffade); // Live (October 2011) sends a 2 rather than 0 when a buff is created, but it doesn't seem to matter. OUT(bufffade); // Live (October 2011) sends a 2 rather than 0 when a buff is created, but it doesn't seem to matter.
OUT(num_hits);
eq->unknown008 = 1.0f; eq->unknown008 = 1.0f;
FINISH_ENCODE(); FINISH_ENCODE();
@ -348,7 +349,7 @@ namespace Underfoot
*((uint32*)ptr) = emu->entity_id; *((uint32*)ptr) = emu->entity_id;
ptr += sizeof(uint32); ptr += sizeof(uint32);
ptr += sizeof(uint32); ptr += sizeof(uint32);
*((uint8*)ptr) = 1; *((uint8*)ptr) = emu->all_buffs;
ptr += sizeof(uchar); ptr += sizeof(uchar);
*((uint16*)ptr) = emu->count; *((uint16*)ptr) = emu->count;
ptr += sizeof(uint16); ptr += sizeof(uint16);
@ -371,7 +372,9 @@ namespace Underfoot
ptr += sizeof(uint32); ptr += sizeof(uint32);
*((uint32*)ptr) = emu->entries[i].tics_remaining; *((uint32*)ptr) = emu->entries[i].tics_remaining;
ptr += sizeof(uint32); ptr += sizeof(uint32);
*((uint32*)ptr) = emu->entries[i].num_hits;
ptr += sizeof(uint32); ptr += sizeof(uint32);
*((uint8*)ptr) = !emu->all_buffs;
ptr += 1; ptr += 1;
} }
@ -1234,7 +1237,7 @@ namespace Underfoot
OUT(lootee); OUT(lootee);
OUT(looter); OUT(looter);
eq->slot_id = emu->slot_id + 1; eq->slot_id = ServerToUnderFootCorpseSlot(emu->slot_id);
OUT(auto_loot); OUT(auto_loot);
FINISH_ENCODE(); FINISH_ENCODE();
@ -3294,7 +3297,7 @@ namespace Underfoot
IN(lootee); IN(lootee);
IN(looter); IN(looter);
emu->slot_id = eq->slot_id - 1; emu->slot_id = UnderfootToServerCorpseSlot(eq->slot_id);
IN(auto_loot); IN(auto_loot);
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
@ -4021,6 +4024,7 @@ namespace Underfoot
static inline uint32 ServerToUnderFootCorpseSlot(uint32 ServerCorpse) static inline uint32 ServerToUnderFootCorpseSlot(uint32 ServerCorpse)
{ {
//uint32 UnderfootCorpse; //uint32 UnderfootCorpse;
return (ServerCorpse + 1);
} }
static inline uint32 UnderfootToServerSlot(uint32 UnderfootSlot) static inline uint32 UnderfootToServerSlot(uint32 UnderfootSlot)
@ -4046,6 +4050,7 @@ namespace Underfoot
static inline uint32 UnderfootToServerCorpseSlot(uint32 UnderfootCorpse) static inline uint32 UnderfootToServerCorpseSlot(uint32 UnderfootCorpse)
{ {
//uint32 ServerCorpse; //uint32 ServerCorpse;
return (UnderfootCorpse - 1);
} }
} }
// end namespace Underfoot // end namespace Underfoot

View File

@ -564,7 +564,7 @@ struct SpellBuffFade_Struct_Underfoot {
/*008*/ float unknown008; /*008*/ float unknown008;
/*012*/ uint32 spellid; /*012*/ uint32 spellid;
/*016*/ uint32 duration; /*016*/ uint32 duration;
/*020*/ uint32 unknown016; /*020*/ uint32 num_hits;
/*024*/ uint32 playerId; // Global player ID? /*024*/ uint32 playerId; // Global player ID?
/*028*/ uint32 unknown020; /*028*/ uint32 unknown020;
/*032*/ uint8 unknown0028[48]; /*032*/ uint8 unknown0028[48];
@ -589,6 +589,25 @@ struct SpellBuffFade_Struct {
/*036*/ /*036*/
}; };
#if 0
struct BuffIconEntry_Struct {
/*000*/ uint32 buff_slot;
/*004*/ uint32 spell_id;
/*008*/ uint32 tics_remaining;
/*012*/ uint32 num_hits;
// char name[0]; caster name is also here sometimes
// uint8 unknownend; 1 when single, 0 when all opposite of all_buffs?
};
struct BuffIcon_Struct {
/*000*/ uint32 entity_id;
/*004*/ uint32 unknown004;
/*008*/ uint8 all_buffs; // 1 when updating all buffs, 0 when doing one
/*009*/ uint16 count;
/*011*/ BuffIconEntry_Struct entires[0];
};
#endif
struct BuffRemoveRequest_Struct struct BuffRemoveRequest_Struct
{ {
/*00*/ uint32 SlotID; /*00*/ uint32 SlotID;
@ -4160,9 +4179,9 @@ struct ItemQuaternaryBodyStruct
struct AugmentInfo_Struct struct AugmentInfo_Struct
{ {
/*000*/ uint32 itemid; // id of the solvent needed /*000*/ uint32 itemid; // id of the solvent needed
/*004*/ uint8 window; // window to display the information in /*004*/ uint8 window; // window to display the information in
/*005*/ uint8 unknown005[71]; // total packet length 76, all the rest were always 00 /*005*/ uint8 unknown005[71]; // total packet length 76, all the rest were always 00
/*076*/ /*076*/
}; };

View File

@ -615,6 +615,8 @@ OP_RAWOutOfSession=0x0000 #
OP_Some3ByteHPUpdate=0x0000 #initial HP update for mobs OP_Some3ByteHPUpdate=0x0000 #initial HP update for mobs
OP_InitialHPUpdate=0x0000 # OP_InitialHPUpdate=0x0000 #
OP_ItemRecastDelay=0x0ada
# Opcodes from the client that are currently Unknowns: # Opcodes from the client that are currently Unknowns:
# 0x3E85 - Sent when Guild Management window is opened # 0x3E85 - Sent when Guild Management window is opened

View File

@ -1751,19 +1751,15 @@ void ZoneDatabase::FillAAEffects(SendAA_Struct* aa_struct){
if(!aa_struct) if(!aa_struct)
return; return;
std::string query = StringFormat("SELECT effectid, base1, base2, slot from aa_effects where aaid=%i order by slot asc", aa_struct->id); auto it = aa_effects.find(aa_struct->id);
auto results = QueryDatabase(query); if (it != aa_effects.end()) {
if (!results.Success()) { for (int slot = 0; slot < aa_struct->total_abilities; slot++) {
LogFile->write(EQEMuLog::Error, "Error in Client::FillAAEffects query: '%s': %s", query.c_str(), results.ErrorMessage().c_str()); // aa_effects is a map of a map, so the slot reference does not start at 0
return; aa_struct->abilities[slot].skill_id = it->second[slot + 1].skill_id;
} aa_struct->abilities[slot].base1 = it->second[slot + 1].base1;
aa_struct->abilities[slot].base2 = it->second[slot + 1].base2;
int index = 0; aa_struct->abilities[slot].slot = it->second[slot + 1].slot;
for (auto row = results.begin(); row != results.end(); ++row, ++index) { }
aa_struct->abilities[index].skill_id=atoi(row[0]);
aa_struct->abilities[index].base1=atoi(row[1]);
aa_struct->abilities[index].base2=atoi(row[2]);
aa_struct->abilities[index].slot=atoi(row[3]);
} }
} }

View File

@ -39,15 +39,10 @@
extern volatile bool RunLoops; extern volatile bool RunLoops;
#include "../common/features.h" #include "../common/features.h"
#include "masterentity.h"
#include "worldserver.h"
#include "../common/misc.h" #include "../common/misc.h"
#include "zonedb.h"
#include "../common/spdat.h" #include "../common/spdat.h"
#include "net.h"
#include "../common/packet_dump.h" #include "../common/packet_dump.h"
#include "../common/packet_functions.h" #include "../common/packet_functions.h"
#include "petitions.h"
#include "../common/serverinfo.h" #include "../common/serverinfo.h"
#include "../common/zone_numbers.h" #include "../common/zone_numbers.h"
#include "../common/moremath.h" #include "../common/moremath.h"
@ -55,6 +50,12 @@ extern volatile bool RunLoops;
#include "../common/breakdowns.h" #include "../common/breakdowns.h"
#include "../common/rulesys.h" #include "../common/rulesys.h"
#include "../common/string_util.h" #include "../common/string_util.h"
#include "../common/data_verification.h"
#include "net.h"
#include "masterentity.h"
#include "worldserver.h"
#include "zonedb.h"
#include "petitions.h"
#include "forage.h" #include "forage.h"
#include "command.h" #include "command.h"
#include "string_ids.h" #include "string_ids.h"
@ -594,19 +595,8 @@ bool Client::Save(uint8 iCommitNow) {
database.SaveCharacterTribute(this->CharacterID(), &m_pp); database.SaveCharacterTribute(this->CharacterID(), &m_pp);
SaveTaskState(); /* Save Character Task */ SaveTaskState(); /* Save Character Task */
if(m_pp.hunger_level < 0) { m_pp.hunger_level = EQEmu::Clamp(m_pp.hunger_level, 0, 50000);
m_pp.hunger_level = 0; m_pp.thirst_level = EQEmu::Clamp(m_pp.thirst_level, 0, 50000);
}
else if(m_pp.hunger_level > 6000) {
m_pp.hunger_level = 6000;
}
if(m_pp.thirst_level < 0) {
m_pp.thirst_level = 0;
}
else if(m_pp.thirst_level > 6000) {
m_pp.thirst_level = 6000;
}
database.SaveCharacterData(this->CharacterID(), this->AccountID(), &m_pp, &m_epp); /* Save Character Data */ database.SaveCharacterData(this->CharacterID(), this->AccountID(), &m_pp, &m_epp); /* Save Character Data */
return true; return true;

View File

@ -896,7 +896,8 @@ public:
//This is used to later set the buff duration of the spell, in slot to duration. //This is used to later set the buff duration of the spell, in slot to duration.
//Doesn't appear to work directly after the client recieves an action packet. //Doesn't appear to work directly after the client recieves an action packet.
void SendBuffDurationPacket(uint16 spell_id, int duration, int inlevel); void SendBuffDurationPacket(Buffs_Struct &buff);
void SendBuffNumHitPacket(Buffs_Struct &buff, int slot);
void ProcessInspectRequest(Client* requestee, Client* requester); void ProcessInspectRequest(Client* requestee, Client* requester);
bool ClientFinishedLoading() { return (conn_state == ClientConnectFinished); } bool ClientFinishedLoading() { return (conn_state == ClientConnectFinished); }

View File

@ -3395,7 +3395,7 @@ void Mob::BuffProcess()
{ {
if(buffs[buffs_i].UpdateClient == true) if(buffs[buffs_i].UpdateClient == true)
{ {
CastToClient()->SendBuffDurationPacket(buffs[buffs_i].spellid, buffs[buffs_i].ticsremaining, buffs[buffs_i].casterlevel); CastToClient()->SendBuffDurationPacket(buffs[buffs_i]);
buffs[buffs_i].UpdateClient = false; buffs[buffs_i].UpdateClient = false;
} }
} }
@ -5559,64 +5559,56 @@ void Mob::CheckNumHitsRemaining(uint8 type, uint32 buff_slot, uint16 spell_id)
uint32 buff_max = GetMaxTotalSlots(); uint32 buff_max = GetMaxTotalSlots();
//Spell specific procs [Type 7,10,11] //Spell specific procs [Type 7,10,11]
if (IsValidSpell(spell_id)){ if (IsValidSpell(spell_id)) {
for (uint32 d = 0; d < buff_max; d++) {
for(uint32 d = 0; d < buff_max; d++) { if (buffs[d].spellid == spell_id && buffs[d].numhits > 0 &&
spells[buffs[d].spellid].numhitstype == type) {
if((buffs[d].spellid == spell_id) && (buffs[d].numhits > 0) && (spells[buffs[d].spellid].numhitstype == type)){ if (--buffs[d].numhits == 0) {
if(--buffs[d].numhits == 0) {
CastOnNumHitFade(buffs[d].spellid); CastOnNumHitFade(buffs[d].spellid);
if(!TryFadeEffect(d)) if (!TryFadeEffect(d))
BuffFadeBySlot(d, true); BuffFadeBySlot(d, true);
} else if (IsClient()) { // still have numhits and client, update
CastToClient()->SendBuffNumHitPacket(buffs[d], d);
} }
} }
} }
} } else if (type == 7) {
if (buff_slot > 0) {
else if (type == 7){ if (--buffs[buff_slot].numhits == 0) {
if (buff_slot > 0){
if(--buffs[buff_slot].numhits == 0) {
CastOnNumHitFade(buffs[buff_slot].spellid); CastOnNumHitFade(buffs[buff_slot].spellid);
if(!TryFadeEffect(buff_slot)) if (!TryFadeEffect(buff_slot))
BuffFadeBySlot(buff_slot , true); BuffFadeBySlot(buff_slot , true);
} } else if (IsClient()) { // still have numhits and client, update
CastToClient()->SendBuffNumHitPacket(buffs[buff_slot], buff_slot);
} }
} else {
else { for (int d = 0; d < buff_max; d++) {
if (!m_spellHitsLeft[d])
for(int d = 0; d < buff_max; d++) {
if(!m_spellHitsLeft[d])
continue; continue;
if ((IsValidSpell(buffs[d].spellid)) && (m_spellHitsLeft[d] == buffs[d].spellid)) { if (IsValidSpell(buffs[d].spellid) && m_spellHitsLeft[d] == buffs[d].spellid) {
if(--buffs[d].numhits == 0) { if (--buffs[d].numhits == 0) {
CastOnNumHitFade(buffs[d].spellid); CastOnNumHitFade(buffs[d].spellid);
m_spellHitsLeft[d] = 0; m_spellHitsLeft[d] = 0;
if(!TryFadeEffect(d)) if (!TryFadeEffect(d))
BuffFadeBySlot(d, true); BuffFadeBySlot(d, true);
} else if (IsClient()) { // still have numhits and client, update
CastToClient()->SendBuffNumHitPacket(buffs[d], d);
} }
} }
} }
} }
} } else {
for (uint32 d = 0; d < buff_max; d++) {
if (IsValidSpell(buffs[d].spellid) && buffs[d].numhits > 0 &&
else{ spells[buffs[d].spellid].numhitstype == type) {
if (--buffs[d].numhits == 0) {
for(uint32 d = 0; d < buff_max; d++) {
if((IsValidSpell(buffs[d].spellid)) && (buffs[d].numhits > 0) && (spells[buffs[d].spellid].numhitstype == type)){
if(--buffs[d].numhits == 0) {
CastOnNumHitFade(buffs[d].spellid); CastOnNumHitFade(buffs[d].spellid);
if(!TryFadeEffect(d)){ if (!TryFadeEffect(d))
BuffFadeBySlot(d, true); BuffFadeBySlot(d, true);
} } else if (IsClient()) { // still have numhits and client, update
CastToClient()->SendBuffNumHitPacket(buffs[d], d);
} }
} }
} }
} }

View File

@ -484,19 +484,6 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
return false; return false;
} }
// This needs a bit more work for saving timer to PP for zoning etc
if (IsClient() && item_slot != INVALID_INDEX && ((slot == USE_ITEM_SPELL_SLOT) || (slot == POTION_BELT_SPELL_SLOT))) {
ItemInst *itm = CastToClient()->GetInv().GetItem(item_slot);
if (itm && itm->GetItem()->RecastDelay) {
outapp = new EQApplicationPacket(OP_ItemRecastDelay, sizeof(ItemRecastDelay_Struct));
ItemRecastDelay_Struct *ird = (ItemRecastDelay_Struct *)outapp->pBuffer;
ird->recast_delay = itm->GetItem()->RecastDelay;
ird->recast_type = itm->GetItem()->RecastType;
CastToClient()->QueuePacket(outapp);
safe_delete(outapp);
}
}
return(true); return(true);
} }
@ -2228,6 +2215,12 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
ItemInst *itm = CastToClient()->GetInv().GetItem(inventory_slot); ItemInst *itm = CastToClient()->GetInv().GetItem(inventory_slot);
if(itm && itm->GetItem()->RecastDelay > 0){ if(itm && itm->GetItem()->RecastDelay > 0){
CastToClient()->GetPTimers().Start((pTimerItemStart + itm->GetItem()->RecastType), itm->GetItem()->RecastDelay); CastToClient()->GetPTimers().Start((pTimerItemStart + itm->GetItem()->RecastType), itm->GetItem()->RecastDelay);
EQApplicationPacket *outapp = new EQApplicationPacket(OP_ItemRecastDelay, sizeof(ItemRecastDelay_Struct));
ItemRecastDelay_Struct *ird = (ItemRecastDelay_Struct *)outapp->pBuffer;
ird->recast_delay = itm->GetItem()->RecastDelay;
ird->recast_type = itm->GetItem()->RecastType;
CastToClient()->QueuePacket(outapp);
safe_delete(outapp);
} }
} }
@ -5164,20 +5157,40 @@ void Mob::_StopSong()
//Thus I use this in the buff process to update the correct duration once after casting //Thus I use this in the buff process to update the correct duration once after casting
//this allows AAs and focus effects that increase buff duration to work correctly, but could probably //this allows AAs and focus effects that increase buff duration to work correctly, but could probably
//be used for other things as well //be used for other things as well
void Client::SendBuffDurationPacket(uint16 spell_id, int duration, int inlevel) void Client::SendBuffDurationPacket(Buffs_Struct &buff)
{ {
EQApplicationPacket* outapp; EQApplicationPacket* outapp;
outapp = new EQApplicationPacket(OP_Buff, sizeof(SpellBuffFade_Struct)); outapp = new EQApplicationPacket(OP_Buff, sizeof(SpellBuffFade_Struct));
SpellBuffFade_Struct* sbf = (SpellBuffFade_Struct*) outapp->pBuffer; SpellBuffFade_Struct* sbf = (SpellBuffFade_Struct*) outapp->pBuffer;
sbf->entityid = GetID(); sbf->entityid = GetID();
sbf->slot=2; sbf->slot = 2;
sbf->spellid=spell_id; sbf->spellid = buff.spellid;
sbf->slotid=0; sbf->slotid = 0;
sbf->effect = inlevel > 0 ? inlevel : GetLevel(); sbf->effect = buff.casterlevel > 0 ? buff.casterlevel : GetLevel();
sbf->level = inlevel > 0 ? inlevel : GetLevel(); sbf->level = buff.casterlevel > 0 ? buff.casterlevel : GetLevel();
sbf->bufffade = 0; sbf->bufffade = 0;
sbf->duration = duration; sbf->duration = buff.ticsremaining;
sbf->num_hits = buff.numhits;
FastQueuePacket(&outapp);
}
void Client::SendBuffNumHitPacket(Buffs_Struct &buff, int slot)
{
// UF+ use this packet
if (GetClientVersion() < EQClientUnderfoot)
return;
EQApplicationPacket *outapp;
outapp = new EQApplicationPacket(OP_BuffCreate, sizeof(BuffIcon_Struct) + sizeof(BuffIconEntry_Struct));
BuffIcon_Struct *bi = (BuffIcon_Struct *)outapp->pBuffer;
bi->entity_id = GetID();
bi->count = 1;
bi->all_buffs = 0;
bi->entries[0].buff_slot = slot;
bi->entries[0].spell_id = buff.spellid;
bi->entries[0].tics_remaining = buff.ticsremaining;
bi->entries[0].num_hits = buff.numhits;
FastQueuePacket(&outapp); FastQueuePacket(&outapp);
} }
@ -5252,6 +5265,7 @@ EQApplicationPacket *Mob::MakeBuffsPacket(bool for_target)
BuffIcon_Struct *buff = (BuffIcon_Struct*)outapp->pBuffer; BuffIcon_Struct *buff = (BuffIcon_Struct*)outapp->pBuffer;
buff->entity_id = GetID(); buff->entity_id = GetID();
buff->count = count; buff->count = count;
buff->all_buffs = 1;
uint32 index = 0; uint32 index = 0;
for(unsigned int i = 0; i < buff_count; ++i) for(unsigned int i = 0; i < buff_count; ++i)
@ -5261,6 +5275,7 @@ EQApplicationPacket *Mob::MakeBuffsPacket(bool for_target)
buff->entries[index].buff_slot = i; buff->entries[index].buff_slot = i;
buff->entries[index].spell_id = buffs[i].spellid; buff->entries[index].spell_id = buffs[i].spellid;
buff->entries[index].tics_remaining = buffs[i].ticsremaining; buff->entries[index].tics_remaining = buffs[i].ticsremaining;
buff->entries[index].num_hits = buffs[i].numhits;
++index; ++index;
} }
} }
@ -5278,7 +5293,7 @@ void Mob::BuffModifyDurationBySpellID(uint16 spell_id, int32 newDuration)
buffs[i].ticsremaining = newDuration; buffs[i].ticsremaining = newDuration;
if(IsClient()) if(IsClient())
{ {
CastToClient()->SendBuffDurationPacket(buffs[i].spellid, buffs[i].ticsremaining, buffs[i].casterlevel); CastToClient()->SendBuffDurationPacket(buffs[i]);
} }
} }
} }

View File

@ -2895,96 +2895,74 @@ void ZoneDatabase::LoadBuffs(Client *client) {
} }
} }
void ZoneDatabase::SavePetInfo(Client *client) { void ZoneDatabase::SavePetInfo(Client *client)
{
PetInfo *petinfo = nullptr;
PetInfo *petinfo = client->GetPetInfo(0); std::string query = StringFormat("DELETE FROM `character_pet_buffs` WHERE `char_id` = %u", client->CharacterID());
PetInfo *suspended = client->GetPetInfo(1); auto results = database.QueryDatabase(query);
if (!results.Success())
std::string query = StringFormat("DELETE FROM `character_pet_buffs` WHERE `char_id` = %u", client->CharacterID());
auto results = database.QueryDatabase(query);
if(!results.Success())
return; return;
query = StringFormat("DELETE FROM `character_pet_buffs` WHERE `char_id` = %u", client->CharacterID()); query = StringFormat("DELETE FROM `character_pet_inventory` WHERE `char_id` = %u", client->CharacterID());
results = database.QueryDatabase(query); results = database.QueryDatabase(query);
if(!results.Success()) if (!results.Success())
return; return;
query = StringFormat("INSERT INTO `character_pet_info` " for (int pet = 0; pet < 2; pet++) {
"(`char_id`, `pet`, `petname`, `petpower`, `spell_id`, `hp`, `mana`, `size`) " petinfo = client->GetPetInfo(pet);
"VALUES (%u, 0, '%s', %i, %u, %u, %u, %f) " if (!petinfo)
"ON DUPLICATE KEY UPDATE `petname` = '%s', `petpower` = %i, `spell_id` = %u, " continue;
"`hp` = %u, `mana` = %u, `size` = %f",
client->CharacterID(), petinfo->Name, petinfo->petpower, petinfo->SpellID,
petinfo->HP, petinfo->Mana, petinfo->size, petinfo->Name, petinfo->petpower,
petinfo->SpellID, petinfo->HP, petinfo->Mana, petinfo->size);
results = database.QueryDatabase(query);
if(!results.Success())
return;
for(int index = 0; index < RuleI(Spells, MaxTotalSlotsPET); index++) { query = StringFormat("INSERT INTO `character_pet_info` "
if (petinfo->Buffs[index].spellid == SPELL_UNKNOWN || petinfo->Buffs[index].spellid == 0) "(`char_id`, `pet`, `petname`, `petpower`, `spell_id`, `hp`, `mana`, `size`) "
continue; "VALUES (%u, %u, '%s', %i, %u, %u, %u, %f) "
"ON DUPLICATE KEY UPDATE `petname` = '%s', `petpower` = %i, `spell_id` = %u, "
"`hp` = %u, `mana` = %u, `size` = %f",
client->CharacterID(), pet, petinfo->Name, petinfo->petpower, petinfo->SpellID,
petinfo->HP, petinfo->Mana, petinfo->size, // and now the ON DUPLICATE ENTRIES
petinfo->Name, petinfo->petpower, petinfo->SpellID, petinfo->HP, petinfo->Mana, petinfo->size);
results = database.QueryDatabase(query);
if (!results.Success())
return;
query.clear();
query = StringFormat("INSERT INTO `character_pet_buffs` " // pet buffs!
"(`char_id`, `pet`, `slot`, `spell_id`, `caster_level`, " for (int index = 0; index < RuleI(Spells, MaxTotalSlotsPET); index++) {
"`ticsremaining`, `counters`) " if (petinfo->Buffs[index].spellid == SPELL_UNKNOWN || petinfo->Buffs[index].spellid == 0)
"VALUES (%u, 0, %u, %u, %u, %u, %d)", continue;
client->CharacterID(), index, petinfo->Buffs[index].spellid, if (query.length() == 0)
petinfo->Buffs[index].level, petinfo->Buffs[index].duration, query = StringFormat("INSERT INTO `character_pet_buffs` "
petinfo->Buffs[index].counters); "(`char_id`, `pet`, `slot`, `spell_id`, `caster_level`, "
database.QueryDatabase(query); "`ticsremaining`, `counters`) "
} "VALUES (%u, %u, %u, %u, %u, %u, %d)",
client->CharacterID(), pet, index, petinfo->Buffs[index].spellid,
petinfo->Buffs[index].level, petinfo->Buffs[index].duration,
petinfo->Buffs[index].counters);
else
query += StringFormat(", (%u, %u, %u, %u, %u, %u, %d)",
client->CharacterID(), pet, index, petinfo->Buffs[index].spellid,
petinfo->Buffs[index].level, petinfo->Buffs[index].duration,
petinfo->Buffs[index].counters);
}
database.QueryDatabase(query);
query.clear();
for(int index = 0; index < RuleI(Spells, MaxTotalSlotsPET); index++) { // pet inventory!
if (petinfo->Buffs[index].spellid == SPELL_UNKNOWN || petinfo->Buffs[index].spellid == 0) for (int index = EmuConstants::EQUIPMENT_BEGIN; index <= EmuConstants::EQUIPMENT_END; index++) {
continue; if (!petinfo->Items[index])
continue;
query = StringFormat("INSERT INTO `character_pet_buffs` " if (query.length() == 0)
"(`char_id`, `pet`, `slot`, `spell_id`, `caster_level`, " query = StringFormat("INSERT INTO `character_pet_inventory` "
"`ticsremaining`, `counters`) " "(`char_id`, `pet`, `slot`, `item_id`) "
"VALUES (%u, 1, %u, %u, %u, %u, %d)", "VALUES (%u, %u, %u, %u)",
client->CharacterID(), index, suspended->Buffs[index].spellid, client->CharacterID(), pet, index, petinfo->Items[index]);
suspended->Buffs[index].level, suspended->Buffs[index].duration, else
suspended->Buffs[index].counters); query += StringFormat(", (%u, %u, %u, %u)", client->CharacterID(), pet, index, petinfo->Items[index]);
database.QueryDatabase(query); }
database.QueryDatabase(query);
} }
for (int index = EmuConstants::EQUIPMENT_BEGIN; index <= EmuConstants::EQUIPMENT_END; index++) {
if(!petinfo->Items[index])
continue;
query = StringFormat("INSERT INTO `character_pet_inventory` "
"(`char_id`, `pet`, `slot`, `item_id`) "
"VALUES (%u, 0, %u, %u)",
client->CharacterID(), index, petinfo->Items[index]);
database.QueryDatabase(query);
}
query = StringFormat("INSERT INTO `character_pet_info` "
"(`char_id`, `pet`, `petname`, `petpower`, `spell_id`, `hp`, `mana`, `size`) "
"VALUES (%u, 1, '%s', %u, %u, %u, %u, %f) "
"ON DUPLICATE KEY UPDATE "
"`petname`='%s', `petpower`=%i, `spell_id`=%u, `hp`=%u, `mana`=%u, `size`=%f",
client->CharacterID(), suspended->Name, suspended->petpower, suspended->SpellID,
suspended->HP, suspended->Mana, suspended->size, suspended->Name, suspended->petpower,
suspended->SpellID, suspended->HP, suspended->Mana, suspended->size);
results = database.QueryDatabase(query);
if(!results.Success())
return;
for (int index = EmuConstants::EQUIPMENT_BEGIN; index <= EmuConstants::EQUIPMENT_END; index++) {
if(!suspended->Items[index])
continue;
query = StringFormat("INSERT INTO `character_pet_inventory` "
"(`char_id`, `pet`, `slot`, `item_id`) "
"VALUES (%u, 1, %u, %u)",
client->CharacterID(), index, suspended->Items[index]);
database.QueryDatabase(query);
}
} }
void ZoneDatabase::RemoveTempFactions(Client *client) { void ZoneDatabase::RemoveTempFactions(Client *client) {