diff --git a/changelog.txt b/changelog.txt index efa9b257a..7607bcf14 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,10 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 07/25/216 == +mackal: Fix up the SpellBuff struct + - THERE MAYBE BUGS + - there shouldn't though, most of the hackery was from badly named fields causing confusion + == 07/09/2016 == Uleat: Important fix for mob pathing - This should fix failed pathing issues (and high cpu usage for zone.exe) for mobs in affect zones diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index 504f8aed3..3252d07cc 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -488,30 +488,28 @@ struct SpawnAppearance_Struct // this is used inside profile struct SpellBuff_Struct { -/*000*/ uint8 slotid; //badly named... seems to be 2 for a real buff, 0 otherwise -/*001*/ uint8 level; +/*000*/ uint8 effect_type; // 0 = no buff, 2 = buff, 4 = inverse affects of buff +/*001*/ uint8 level; /*002*/ uint8 bard_modifier; -/*003*/ uint8 effect; //not real +/*003*/ uint8 unknown003; // MQ2 used to call this "damage shield" -- don't see client referencing it, so maybe server side DS type tracking? -- OSX client calls this "activated" /*004*/ uint32 spellid; -/*008*/ int32 duration; -/*012*/ uint32 counters; -/*016*/ uint32 player_id; //'global' ID of the caster, for wearoff messages -/*020*/ +/*008*/ int32 duration; +/*012*/ uint32 counters; // single book keeping value (counters, rune/vie) +/*016*/ uint32 player_id; // caster ID, pretty sure just zone ID +// extra stuff for newer packets +/*020*/ uint32 num_hits; +/*024*/ float y; // referenced by SPA 441 +/*028*/ float x; // unsure if all buffs get them +/*032*/ float z; // as valid data +/*036*/ }; -struct SpellBuffFade_Struct { +struct SpellBuffPacket_Struct { /*000*/ uint32 entityid; -/*004*/ uint8 slot; -/*005*/ uint8 level; -/*006*/ uint8 effect; -/*007*/ uint8 unknown7; -/*008*/ uint32 spellid; -/*012*/ int32 duration; -/*016*/ uint32 num_hits; -/*020*/ uint32 unknown020; //prolly global player ID -/*024*/ uint32 slotid; -/*028*/ uint32 bufffade; -/*032*/ +/*004*/ SpellBuff_Struct buff; +/*040*/ uint32 slotid; +/*044*/ uint32 bufffade; +/*048*/ }; // Underfoot & later struct. diff --git a/common/opcode_dispatch.h b/common/opcode_dispatch.h index a88391bce..496dcdea3 100644 --- a/common/opcode_dispatch.h +++ b/common/opcode_dispatch.h @@ -173,7 +173,7 @@ IN(OP_TradeAcceptClick, TradeAccept_Struct); IN(OP_BoardBoat, EntityId_Struct); //not really the struct, just 4 bytes INz(OP_LeaveBoat); //? IN(OP_RandomReq, RandomReq_Struct); -IN(OP_Buff, SpellBuffFade_Struct); +IN(OP_Buff, SpellBuffPacket_Struct); IN(OP_GMHideMe, SpawnAppearance_Struct); IN(OP_GMNameChange, GMName_Struct); IN(OP_GMKill, GMKill_Struct); @@ -415,7 +415,7 @@ OUTv(OP_SendAATable, SendAA_Struct); OUT(OP_AAAction, UseAA_Struct); OUT(OP_Bazaar, BazaarReturnDone_Struct); //alt:OUT(OP_Bazaar, BazaarWelcome_Struct); -OUT(OP_Buff, SpellBuffFade_Struct); +OUT(OP_Buff, SpellBuffPacket_Struct); OUT(OP_ClickObject, ClickObject_Struct); OUT(OP_ClientUpdate, PlayerPositionUpdateServer_Struct); OUT(OP_SpawnPositionUpdate, SpawnPositionUpdate_Struct); diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index 0b45b98e6..4bf8ed63d 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -405,22 +405,31 @@ namespace RoF ENCODE(OP_Buff) { - ENCODE_LENGTH_EXACT(SpellBuffFade_Struct); - SETUP_DIRECT_ENCODE(SpellBuffFade_Struct, structs::SpellBuffFade_Struct_Live); + ENCODE_LENGTH_EXACT(SpellBuffPacket_Struct); + SETUP_DIRECT_ENCODE(SpellBuffPacket_Struct, structs::SpellBuffPacket_Struct); OUT(entityid); - eq->unknown004 = 2; - //eq->level = 80; - //eq->effect = 0; - OUT(level); - OUT(effect); - eq->unknown007 = 0; - eq->unknown008 = 1.0f; - OUT(spellid); - OUT(duration); - eq->playerId = 0x7cde; - OUT(slotid); - OUT(num_hits); + OUT(buff.effect_type); + OUT(buff.level); + // just so we're 100% sure we get a 1.0f ... + eq->buff.bard_modifier = emu->buff.bard_modifier == 10 ? 1.0f : emu->buff.bard_modifier / 10.0f; + OUT(buff.spellid); + OUT(buff.duration); + OUT(buff.player_id); + OUT(buff.num_hits); + OUT(buff.y); + OUT(buff.x); + OUT(buff.z); + uint16 buffslot = emu->slotid; + // Not sure if this is needs amending for RoF yet. + if (buffslot >= 25) + { + buffslot += 17; + } + + // TODO: implement slot_data stuff + eq->slotid = buffslot; + if (emu->bufffade == 1) eq->bufffade = 1; else @@ -432,10 +441,10 @@ namespace RoF { outapp = new EQApplicationPacket(OP_BuffCreate, 29); outapp->WriteUInt32(emu->entityid); - outapp->WriteUInt32(0x0271); // Unk + outapp->WriteUInt32(0); // tic timer outapp->WriteUInt8(0); // Type of OP_BuffCreate packet ? outapp->WriteUInt16(1); // 1 buff in this packet - outapp->WriteUInt32(emu->slotid); + outapp->WriteUInt32(buffslot); outapp->WriteUInt32(0xffffffff); // SpellID (0xffff to remove) outapp->WriteUInt32(0); // Duration outapp->WriteUInt32(0); // ? @@ -2274,31 +2283,32 @@ namespace RoF for (uint32 r = 0; r < BUFF_COUNT; r++) { float instrument_mod = 0.0f; - uint8 slotid = emu->buffs[r].slotid; + uint8 effect_type = emu->buffs[r].effect_type; uint32 player_id = emu->buffs[r].player_id;; if (emu->buffs[r].spellid != 0xFFFF && emu->buffs[r].spellid != 0) { instrument_mod = 1.0f + (emu->buffs[r].bard_modifier - 10) / 10.0f; - slotid = 2; + effect_type = 2; player_id = 0x000717fd; } else { - slotid = 0; + effect_type = 0; } - outapp->WriteUInt8(0); // Had this as slot, but always appears to be 0 on live. + // this is different than the client struct for some reason :P + // missing a few things, shuffled around + outapp->WriteUInt8(0); // this is an unknown outapp->WriteFloat(instrument_mod); outapp->WriteUInt32(player_id); outapp->WriteUInt8(0); outapp->WriteUInt32(emu->buffs[r].counters); - //outapp->WriteUInt8(emu->buffs[r].bard_modifier); outapp->WriteUInt32(emu->buffs[r].duration); outapp->WriteUInt8(emu->buffs[r].level); outapp->WriteUInt32(emu->buffs[r].spellid); - outapp->WriteUInt32(slotid); // Only ever seen 2 + outapp->WriteUInt8(effect_type); // Only ever seen 2 + outapp->WriteUInt32(emu->buffs[r].num_hits); outapp->WriteUInt32(0); - outapp->WriteUInt8(0); outapp->WriteUInt32(emu->buffs[r].counters); // Appears twice ? for (uint32 j = 0; j < 44; ++j) @@ -4290,15 +4300,15 @@ namespace RoF DECODE(OP_Buff) { - DECODE_LENGTH_EXACT(structs::SpellBuffFade_Struct_Live); - SETUP_DIRECT_DECODE(SpellBuffFade_Struct, structs::SpellBuffFade_Struct_Live); + DECODE_LENGTH_EXACT(structs::SpellBuffPacket_Struct); + SETUP_DIRECT_DECODE(SpellBuffPacket_Struct, structs::SpellBuffPacket_Struct); IN(entityid); - //IN(slot); - IN(level); - IN(effect); - IN(spellid); - IN(duration); + IN(buff.effect_type); + IN(buff.level); + IN(buff.unknown003); + IN(buff.spellid); + IN(buff.duration); IN(slotid); IN(bufffade); diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 57f823ce2..41d34a50a 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -474,22 +474,34 @@ namespace RoF2 ENCODE(OP_Buff) { - ENCODE_LENGTH_EXACT(SpellBuffFade_Struct); - SETUP_DIRECT_ENCODE(SpellBuffFade_Struct, structs::SpellBuffFade_Struct_Live); + ENCODE_LENGTH_EXACT(SpellBuffPacket_Struct); + SETUP_DIRECT_ENCODE(SpellBuffPacket_Struct, structs::SpellBuffPacket_Struct); OUT(entityid); - eq->unknown004 = 2; - //eq->level = 80; - //eq->effect = 0; - OUT(level); - OUT(effect); - eq->unknown007 = 0; - eq->unknown008 = 1.0f; - OUT(spellid); - OUT(duration); - eq->playerId = 0x7cde; - OUT(slotid); - OUT(num_hits); + OUT(buff.effect_type); + OUT(buff.level); + // just so we're 100% sure we get a 1.0f ... + eq->buff.bard_modifier = emu->buff.bard_modifier == 10 ? 1.0f : emu->buff.bard_modifier / 10.0f; + OUT(buff.spellid); + OUT(buff.duration); + OUT(buff.player_id); + OUT(buff.num_hits); + OUT(buff.y); + OUT(buff.x); + OUT(buff.z); + uint16 buffslot = emu->slotid; + // Not sure if this is needs amending for RoF2 yet. + if (buffslot >= 25) + { + buffslot += 17; + } + // TODO: We should really just deal with these "server side" + // so we can have clients not limited to other clients. + // This fixes discs, songs were changed to 20 + if (buffslot == 54) + buffslot = 62; + eq->slotid = buffslot; + // TODO: implement slot_data stuff if (emu->bufffade == 1) eq->bufffade = 1; else @@ -501,10 +513,10 @@ namespace RoF2 { outapp = new EQApplicationPacket(OP_BuffCreate, 29); outapp->WriteUInt32(emu->entityid); - outapp->WriteUInt32(0x0271); // Unk + outapp->WriteUInt32(0); // tic timer outapp->WriteUInt8(0); // Type of OP_BuffCreate packet ? outapp->WriteUInt16(1); // 1 buff in this packet - outapp->WriteUInt32(emu->slotid); + outapp->WriteUInt32(buffslot); outapp->WriteUInt32(0xffffffff); // SpellID (0xffff to remove) outapp->WriteUInt32(0); // Duration outapp->WriteUInt32(0); // ? @@ -2358,31 +2370,33 @@ namespace RoF2 for (uint32 r = 0; r < BUFF_COUNT; r++) { float instrument_mod = 0.0f; - uint8 slotid = emu->buffs[r].slotid; + uint8 effect_type = emu->buffs[r].effect_type; uint32 player_id = emu->buffs[r].player_id;; if (emu->buffs[r].spellid != 0xFFFF && emu->buffs[r].spellid != 0) { instrument_mod = 1.0f + (emu->buffs[r].bard_modifier - 10) / 10.0f; - slotid = 2; + effect_type = 2; player_id = 0x000717fd; } else { - slotid = 0; + effect_type = 0; } - outapp->WriteUInt8(0); // Had this as slot, but always appears to be 0 on live. + + // this is different than the client struct for some reason :P + // missing a few things, shuffled around + outapp->WriteUInt8(0); // this is an unknown outapp->WriteFloat(instrument_mod); outapp->WriteUInt32(player_id); outapp->WriteUInt8(0); outapp->WriteUInt32(emu->buffs[r].counters); - //outapp->WriteUInt8(emu->buffs[r].bard_modifier); outapp->WriteUInt32(emu->buffs[r].duration); outapp->WriteUInt8(emu->buffs[r].level); outapp->WriteUInt32(emu->buffs[r].spellid); - outapp->WriteUInt32(slotid); // Only ever seen 2 + outapp->WriteUInt8(effect_type); // Only ever seen 2 + outapp->WriteUInt32(emu->buffs[r].num_hits); outapp->WriteUInt32(0); - outapp->WriteUInt8(0); outapp->WriteUInt32(emu->buffs[r].counters); // Appears twice ? for (uint32 j = 0; j < 44; ++j) @@ -4526,15 +4540,15 @@ namespace RoF2 DECODE(OP_Buff) { - DECODE_LENGTH_EXACT(structs::SpellBuffFade_Struct_Live); - SETUP_DIRECT_DECODE(SpellBuffFade_Struct, structs::SpellBuffFade_Struct_Live); + DECODE_LENGTH_EXACT(structs::SpellBuffPacket_Struct); + SETUP_DIRECT_DECODE(SpellBuffPacket_Struct, structs::SpellBuffPacket_Struct); IN(entityid); - //IN(slot); - IN(level); - IN(effect); - IN(spellid); - IN(duration); + IN(buff.effect_type); + IN(buff.level); + IN(buff.unknown003); + IN(buff.spellid); + IN(buff.duration); IN(slotid); IN(bufffade); diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index 0b638660e..61cbb0d0b 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -719,69 +719,31 @@ struct SpawnAppearance_Struct struct SpellBuff_Struct { -/*000*/ uint8 slotid; // badly named... seems to be 2 for a real buff, 0 otherwise -/*001*/ float unknown004; // Seen 1 for no buff -/*005*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages -/*009*/ uint32 unknown016; -/*013*/ uint8 bard_modifier; -/*014*/ int32 duration; -/*018*/ uint8 level; -/*019*/ uint32 spellid; -/*023*/ uint32 counters; -/*027*/ uint8 unknown0028[53]; -/*080*/ -}; - -struct SpellBuff_Struct_Old -{ -/*000*/ uint8 slotid; // badly named... seems to be 2 for a real buff, 0 otherwise -/*001*/ uint8 level; -/*002*/ uint8 bard_modifier; -/*003*/ uint8 effect; // not real -/*004*/ float unknown004; // Seen 1 for no buff -/*008*/ uint32 spellid; -/*012*/ int32 duration; -/*016*/ uint32 unknown016; -/*020*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages -/*024*/ uint32 counters; -/*028*/ uint8 unknown0028[60]; +/*000*/ uint8 effect_type; // 0 = no buff, 2 = buff, 4 = inverse affects of buff +/*001*/ uint8 level; // Seen 1 for no buff +/*002*/ uint8 unknown002; //pretty sure padding now +/*003*/ uint8 unknown003; // MQ2 used to call this "damage shield" -- don't see client referencing it, so maybe server side DS type tracking? +/*004*/ float bard_modifier; +/*008*/ uint32 spellid; +/*012*/ uint32 duration; +/*016*/ uint32 player_id; // caster ID, pretty sure just zone ID +/*020*/ uint32 num_hits; +/*024*/ float y; // referenced by SPA 441 +/*028*/ float x; // unsure if all buffs get them +/*032*/ float z; // as valid data +/*036*/ uint32 unknown036; +/*040*/ int32 slot_data[12]; // book keeping stuff per slot (counters, rune/vie) /*088*/ }; -// Not functional yet, but this is what the packet looks like on Live -struct SpellBuffFade_Struct_Live { -/*000*/ uint32 entityid; // Player id who cast the buff -/*004*/ uint8 unknown004; -/*005*/ uint8 level; -/*006*/ uint8 effect; -/*007*/ uint8 unknown007; -/*008*/ float unknown008; -/*012*/ uint32 spellid; -/*016*/ int32 duration; -/*020*/ uint32 playerId; // Global player ID? -/*024*/ uint32 num_hits; -/*028*/ uint8 unknown0028[64]; +struct SpellBuffPacket_Struct { +/*000*/ uint32 entityid; // Player id who cast the buff +/*004*/ SpellBuff_Struct buff; /*092*/ uint32 slotid; /*096*/ uint32 bufffade; /*100*/ }; -struct SpellBuffFade_Struct { -/*000*/ uint32 entityid; -/*004*/ uint8 slot; -/*005*/ uint8 level; -/*006*/ uint8 effect; -/*007*/ uint8 unknown7; -/*008*/ uint32 spellid; -/*012*/ int32 duration; -/*016*/ uint32 num_hits; -/*020*/ uint32 unknown020; // Global player ID? -/*024*/ uint32 playerId; // Player id who cast the buff -/*028*/ uint32 slotid; -/*032*/ uint32 bufffade; -/*036*/ -}; - struct BuffRemoveRequest_Struct { /*00*/ uint32 SlotID; diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index 9846b1e9e..9c5aa8ab8 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -708,69 +708,31 @@ struct SpawnAppearance_Struct struct SpellBuff_Struct { -/*000*/ uint8 slotid; // badly named... seems to be 2 for a real buff, 0 otherwise -/*001*/ float unknown004; // Seen 1 for no buff -/*005*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages -/*009*/ uint32 unknown016; -/*013*/ uint8 bard_modifier; -/*014*/ int32 duration; -/*018*/ uint8 level; -/*019*/ uint32 spellid; -/*023*/ uint32 counters; -/*027*/ uint8 unknown0028[53]; -/*080*/ -}; - -struct SpellBuff_Struct_Old -{ -/*000*/ uint8 slotid; // badly named... seems to be 2 for a real buff, 0 otherwise -/*001*/ uint8 level; -/*002*/ uint8 bard_modifier; -/*003*/ uint8 effect; // not real -/*004*/ float unknown004; // Seen 1 for no buff -/*008*/ uint32 spellid; -/*012*/ int32 duration; -/*016*/ uint32 unknown016; -/*020*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages -/*024*/ uint32 counters; -/*028*/ uint8 unknown0028[60]; +/*000*/ uint8 effect_type; // 0 = no buff, 2 = buff, 4 = inverse affects of buff +/*001*/ uint8 level; // Seen 1 for no buff +/*002*/ uint8 unknown002; //pretty sure padding now +/*003*/ uint8 unknown003; // MQ2 used to call this "damage shield" -- don't see client referencing it, so maybe server side DS type tracking? +/*004*/ float bard_modifier; +/*008*/ uint32 spellid; +/*012*/ uint32 duration; +/*016*/ uint32 player_id; // caster ID, pretty sure just zone ID +/*020*/ uint32 num_hits; +/*024*/ float y; // referenced by SPA 441 +/*028*/ float x; // unsure if all buffs get them +/*032*/ float z; // as valid data +/*036*/ uint32 unknown036; +/*040*/ int32 slot_data[12]; // book keeping stuff per slot (counters, rune/vie) /*088*/ }; -// Not functional yet, but this is what the packet looks like on Live -struct SpellBuffFade_Struct_Live { -/*000*/ uint32 entityid; // Player id who cast the buff -/*004*/ uint8 unknown004; -/*005*/ uint8 level; -/*006*/ uint8 effect; -/*007*/ uint8 unknown007; -/*008*/ float unknown008; -/*012*/ uint32 spellid; -/*016*/ int32 duration; -/*020*/ uint32 playerId; // Global player ID? -/*024*/ uint32 num_hits; -/*028*/ uint8 unknown0028[64]; +struct SpellBuffPacket_Struct { +/*000*/ uint32 entityid; // Player id who cast the buff +/*004*/ SpellBuff_Struct buff; /*092*/ uint32 slotid; /*096*/ uint32 bufffade; /*100*/ }; -struct SpellBuffFade_Struct { -/*000*/ uint32 entityid; -/*004*/ uint8 slot; -/*005*/ uint8 level; -/*006*/ uint8 effect; -/*007*/ uint8 unknown7; -/*008*/ uint32 spellid; -/*012*/ int32 duration; -/*016*/ uint32 num_hits; -/*020*/ uint32 unknown020; // Global player ID? -/*024*/ uint32 playerId; // Player id who cast the buff -/*028*/ uint32 slotid; -/*032*/ uint32 bufffade; -/*036*/ -}; - struct BuffRemoveRequest_Struct { /*00*/ uint32 SlotID; diff --git a/common/patches/sod.cpp b/common/patches/sod.cpp index 58997a9a5..c148a02be 100644 --- a/common/patches/sod.cpp +++ b/common/patches/sod.cpp @@ -301,16 +301,17 @@ namespace SoD ENCODE(OP_Buff) { - ENCODE_LENGTH_EXACT(SpellBuffFade_Struct); - SETUP_DIRECT_ENCODE(SpellBuffFade_Struct, structs::SpellBuffFade_Struct); + ENCODE_LENGTH_EXACT(SpellBuffPacket_Struct); + SETUP_DIRECT_ENCODE(SpellBuffPacket_Struct, structs::SpellBuffPacket_Struct); OUT(entityid); - OUT(slot); - OUT(level); - OUT(effect); - //eq->unknown7 = 10; - OUT(spellid); - OUT(duration); + OUT(buff.effect_type); + OUT(buff.level); + OUT(buff.bard_modifier); + OUT(buff.spellid); + OUT(buff.duration); + OUT(buff.counters); + OUT(buff.player_id); OUT(slotid); OUT(bufffade); @@ -1602,10 +1603,10 @@ namespace SoD OUT(thirst_level); OUT(hunger_level); for (r = 0; r < structs::BUFF_COUNT; r++) { - OUT(buffs[r].slotid); + OUT(buffs[r].effect_type); OUT(buffs[r].level); OUT(buffs[r].bard_modifier); - OUT(buffs[r].effect); + OUT(buffs[r].unknown003); OUT(buffs[r].spellid); OUT(buffs[r].duration); OUT(buffs[r].counters); @@ -2907,15 +2908,16 @@ namespace SoD DECODE(OP_Buff) { - DECODE_LENGTH_EXACT(structs::SpellBuffFade_Struct); - SETUP_DIRECT_DECODE(SpellBuffFade_Struct, structs::SpellBuffFade_Struct); + DECODE_LENGTH_EXACT(structs::SpellBuffPacket_Struct); + SETUP_DIRECT_DECODE(SpellBuffPacket_Struct, structs::SpellBuffPacket_Struct); IN(entityid); - IN(slot); - IN(level); - IN(effect); - IN(spellid); - IN(duration); + IN(buff.effect_type); + IN(buff.level); + IN(buff.bard_modifier); + IN(buff.spellid); + IN(buff.duration); + IN(buff.counters) IN(slotid); IN(bufffade); diff --git a/common/patches/sod_structs.h b/common/patches/sod_structs.h index 11331552a..191d048e9 100644 --- a/common/patches/sod_structs.h +++ b/common/patches/sod_structs.h @@ -563,32 +563,22 @@ struct SpawnAppearance_Struct // this is used inside profile struct SpellBuff_Struct { -/*000*/ uint8 slotid; //badly named... seems to be 2 for a real buff, 0 otherwise -/*001*/ uint8 level; -/*002*/ uint8 bard_modifier; -/*003*/ uint8 effect; //not real -/*004*/ uint32 spellid; -/*008*/ int32 duration; -/*012*/ uint32 counters; -/*016*/ uint32 unknown004; //Might need to be swapped with player_id -/*020*/ uint32 player_id; //'global' ID of the caster, for wearoff messages +/*000*/ uint8 effect_type; // 0 = no buff, 2 = buff, 4 = inverse affects of buff +/*001*/ uint8 level; // Seen 1 for no buff +/*002*/ uint8 bard_modifier; +/*003*/ uint8 unknown003; // MQ2 used to call this "damage shield" -- don't see client referencing it, so maybe server side DS type tracking? +/*004*/ uint32 spellid; +/*008*/ uint32 duration; +/*012*/ uint32 counters; +/*016*/ uint32 unknown016; +/*020*/ uint32 player_id; // caster ID, pretty sure just zone ID /*024*/ - - }; -struct SpellBuffFade_Struct { +struct SpellBuffPacket_Struct { /*000*/ uint32 entityid; -/*004*/ uint8 slot; -/*005*/ uint8 level; -/*006*/ uint8 effect; -/*007*/ uint8 unknown7; -/*008*/ uint32 spellid; -/*012*/ int32 duration; -/*016*/ uint32 unknown016; -/*020*/ uint32 unknown020; //prolly global player ID -/*024*/ uint32 playerId; // Player id who cast the buff +/*004*/ SpellBuff_Struct buff; /*028*/ uint32 slotid; /*032*/ uint32 bufffade; /*036*/ diff --git a/common/patches/sof.cpp b/common/patches/sof.cpp index c2402f1e2..7984debd9 100644 --- a/common/patches/sof.cpp +++ b/common/patches/sof.cpp @@ -283,16 +283,17 @@ namespace SoF ENCODE(OP_Buff) { - ENCODE_LENGTH_EXACT(SpellBuffFade_Struct); - SETUP_DIRECT_ENCODE(SpellBuffFade_Struct, structs::SpellBuffFade_Struct); + ENCODE_LENGTH_EXACT(SpellBuffPacket_Struct); + SETUP_DIRECT_ENCODE(SpellBuffPacket_Struct, structs::SpellBuffPacket_Struct); OUT(entityid); - OUT(slot); - OUT(level); - OUT(effect); - //eq->unknown7 = 10; - OUT(spellid); - OUT(duration); + OUT(buff.effect_type); + OUT(buff.level); + OUT(buff.bard_modifier); + OUT(buff.spellid); + OUT(buff.duration); + OUT(buff.counters); + OUT(buff.player_id); OUT(slotid); OUT(bufffade); @@ -1258,10 +1259,10 @@ namespace SoF OUT(thirst_level); OUT(hunger_level); for (r = 0; r < structs::BUFF_COUNT; r++) { - OUT(buffs[r].slotid); + OUT(buffs[r].effect_type); OUT(buffs[r].level); OUT(buffs[r].bard_modifier); - OUT(buffs[r].effect); + OUT(buffs[r].unknown003); OUT(buffs[r].spellid); OUT(buffs[r].duration); OUT(buffs[r].counters); @@ -2343,15 +2344,17 @@ namespace SoF DECODE(OP_Buff) { - DECODE_LENGTH_EXACT(structs::SpellBuffFade_Struct); - SETUP_DIRECT_DECODE(SpellBuffFade_Struct, structs::SpellBuffFade_Struct); + DECODE_LENGTH_EXACT(structs::SpellBuffPacket_Struct); + SETUP_DIRECT_DECODE(SpellBuffPacket_Struct, structs::SpellBuffPacket_Struct); IN(entityid); - IN(slot); - IN(level); - IN(effect); - IN(spellid); - IN(duration); + IN(buff.effect_type); + IN(buff.level); + IN(buff.bard_modifier); + IN(buff.spellid); + IN(buff.duration); + IN(buff.counters); + IN(buff.player_id); IN(slotid); IN(bufffade); diff --git a/common/patches/sof_structs.h b/common/patches/sof_structs.h index 881259e3e..86dc91e14 100644 --- a/common/patches/sof_structs.h +++ b/common/patches/sof_structs.h @@ -542,32 +542,23 @@ struct SpawnAppearance_Struct // this is used inside profile struct SpellBuff_Struct { -/*000*/ uint8 slotid; //badly named... seems to be 2 for a real buff, 0 otherwise -/*001*/ uint8 level; -/*002*/ uint8 bard_modifier; -/*003*/ uint8 effect; //not real -/*004*/ uint32 spellid; -/*008*/ int32 duration; -/*012*/ uint32 counters; -/*016*/ uint32 unknown004; //Might need to be swapped with player_id -/*020*/ uint32 player_id; //'global' ID of the caster, for wearoff messages +/*000*/ uint8 effect_type; // 0 = no buff, 2 = buff, 4 = inverse affects of buff +/*001*/ uint8 level; // Seen 1 for no buff +/*002*/ uint8 bard_modifier; +/*003*/ uint8 unknown003; // MQ2 used to call this "damage shield" -- don't see client referencing it, so maybe server side DS type tracking? +/*004*/ uint32 spellid; +/*008*/ uint32 duration; +/*012*/ uint32 counters; +/*016*/ uint32 unknown016; +/*020*/ uint32 player_id; // caster ID, pretty sure just zone ID + /*024*/ - - }; -struct SpellBuffFade_Struct { +struct SpellBuffPacket_Struct { /*000*/ uint32 entityid; -/*004*/ uint8 slot; -/*005*/ uint8 level; -/*006*/ uint8 effect; -/*007*/ uint8 unknown7; -/*008*/ uint32 spellid; -/*012*/ int32 duration; -/*016*/ uint32 unknown016; -/*020*/ uint32 unknown020; //prolly global player ID -/*024*/ uint32 playerId; // Player id who cast the buff +/*004*/ SpellBuff_Struct buff; /*028*/ uint32 slotid; /*032*/ uint32 bufffade; /*036*/ diff --git a/common/patches/titanium.cpp b/common/patches/titanium.cpp index 849f898f7..919267132 100644 --- a/common/patches/titanium.cpp +++ b/common/patches/titanium.cpp @@ -254,6 +254,25 @@ namespace Titanium FINISH_ENCODE(); } + ENCODE(OP_Buff) + { + ENCODE_LENGTH_EXACT(SpellBuffPacket_Struct); + SETUP_DIRECT_ENCODE(SpellBuffPacket_Struct, structs::SpellBuffPacket_Struct); + + OUT(entityid); + OUT(buff.effect_type); + OUT(buff.level); + OUT(buff.bard_modifier); + OUT(buff.spellid); + OUT(buff.duration); + OUT(buff.counters); + OUT(buff.player_id); + OUT(slotid); + OUT(bufffade); + + FINISH_ENCODE(); + } + ENCODE(OP_ChannelMessage) { EQApplicationPacket *in = *p; @@ -945,10 +964,10 @@ namespace Titanium OUT(thirst_level); OUT(hunger_level); for (r = 0; r < structs::BUFF_COUNT; r++) { - OUT(buffs[r].slotid); + OUT(buffs[r].effect_type); OUT(buffs[r].level); OUT(buffs[r].bard_modifier); - OUT(buffs[r].effect); + OUT(buffs[r].unknown003); OUT(buffs[r].spellid); OUT(buffs[r].duration); OUT(buffs[r].counters); @@ -1688,6 +1707,25 @@ namespace Titanium FINISH_DIRECT_DECODE(); } + DECODE(OP_Buff) + { + DECODE_LENGTH_EXACT(SpellBuffPacket_Struct); + SETUP_DIRECT_DECODE(SpellBuffPacket_Struct, structs::SpellBuffPacket_Struct); + + IN(entityid); + IN(buff.effect_type); + IN(buff.level); + IN(buff.bard_modifier); + IN(buff.spellid); + IN(buff.duration); + IN(buff.counters); + IN(buff.player_id); + IN(slotid); + IN(bufffade); + + FINISH_DIRECT_DECODE(); + } + DECODE(OP_CastSpell) { DECODE_LENGTH_EXACT(structs::CastSpell_Struct); diff --git a/common/patches/titanium_ops.h b/common/patches/titanium_ops.h index be61ea692..f878fbd76 100644 --- a/common/patches/titanium_ops.h +++ b/common/patches/titanium_ops.h @@ -24,6 +24,7 @@ E(OP_AdventureMerchantSell) E(OP_ApplyPoison) E(OP_BazaarSearch) E(OP_BecomeTrader) +E(OP_Buff) E(OP_ChannelMessage) E(OP_CharInventory) E(OP_Damage) @@ -74,6 +75,7 @@ E(OP_ZoneSpawns) D(OP_AdventureMerchantSell) D(OP_ApplyPoison) D(OP_AugmentItem) +D(OP_Buff) D(OP_CastSpell) D(OP_ChannelMessage) D(OP_CharacterCreate) diff --git a/common/patches/titanium_structs.h b/common/patches/titanium_structs.h index 997aecc5d..caa798da0 100644 --- a/common/patches/titanium_structs.h +++ b/common/patches/titanium_structs.h @@ -473,26 +473,19 @@ struct SpawnAppearance_Struct // this is used inside profile struct SpellBuff_Struct { -/*000*/ uint8 slotid; //badly named... seems to be 2 for a real buff, 0 otherwise +/*000*/ uint8 effect_type; // 0 = no buff, 2 = buff, 4 = inverse affects of buff /*001*/ uint8 level; /*002*/ uint8 bard_modifier; -/*003*/ uint8 effect; //not real +/*003*/ uint8 unknown003; // MQ2 used to call this "damage shield" -- don't see client referencing it, so maybe server side DS type tracking? /*004*/ uint32 spellid; /*008*/ int32 duration; -/*012*/ uint32 counters; -/*016*/ uint32 player_id; //'global' ID of the caster, for wearoff messages +/*012*/ uint32 counters; // single book keeping value (counters, rune/vie) +/*016*/ uint32 player_id; // caster ID, pretty sure just zone ID }; -struct SpellBuffFade_Struct { +struct SpellBuffPacket_Struct { /*000*/ uint32 entityid; -/*004*/ uint8 slot; -/*005*/ uint8 level; -/*006*/ uint8 effect; -/*007*/ uint8 unknown7; -/*008*/ uint32 spellid; -/*012*/ int32 duration; -/*016*/ uint32 unknown016; -/*020*/ uint32 unknown020; //prolly global player ID +/*004*/ SpellBuff_Struct buff; /*024*/ uint32 slotid; /*028*/ uint32 bufffade; /*032*/ diff --git a/common/patches/uf.cpp b/common/patches/uf.cpp index d613c8867..a65e9cef0 100644 --- a/common/patches/uf.cpp +++ b/common/patches/uf.cpp @@ -363,20 +363,29 @@ namespace UF ENCODE(OP_Buff) { - ENCODE_LENGTH_EXACT(SpellBuffFade_Struct); - SETUP_DIRECT_ENCODE(SpellBuffFade_Struct, structs::SpellBuffFade_Struct_Underfoot); + ENCODE_LENGTH_EXACT(SpellBuffPacket_Struct); + SETUP_DIRECT_ENCODE(SpellBuffPacket_Struct, structs::SpellBuffPacket_Struct); OUT(entityid); - OUT(slot); - OUT(level); - OUT(effect); - //eq->unknown7 = 10; - OUT(spellid); - OUT(duration); - OUT(slotid); + OUT(buff.effect_type); + OUT(buff.level); + // just so we're 100% sure we get a 1.0f ... + eq->buff.bard_modifier = emu->buff.bard_modifier == 10 ? 1.0f : emu->buff.bard_modifier / 10.0f; + OUT(buff.spellid); + OUT(buff.duration); + OUT(buff.num_hits); + uint16 buffslot = emu->slotid; + if (buffslot >= 25 && buffslot < 37) + { + buffslot += 5; + } + else if (buffslot >= 37) + { + buffslot += 14; + } + // TODO: implement slot_data stuff + eq->slotid = buffslot; 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; FINISH_ENCODE(); } @@ -1862,22 +1871,22 @@ namespace UF { if (emu->buffs[r].spellid != 0xFFFF && emu->buffs[r].spellid != 0) { - eq->buffs[r].unknown004 = 0x3f800000; - eq->buffs[r].slotid = 2; + eq->buffs[r].bard_modifier = 1.0f; + eq->buffs[r].effect_type= 2; eq->buffs[r].player_id = 0x000717fd; } else { - eq->buffs[r].slotid = 0; + eq->buffs[r].effect_type = 0; } - //OUT(buffs[r].slotid); + OUT(buffs[r].effect_type); OUT(buffs[r].level); - //OUT(buffs[r].bard_modifier); - //OUT(buffs[r].effect); + OUT(buffs[r].bard_modifier); + OUT(buffs[r].unknown003); OUT(buffs[r].spellid); OUT(buffs[r].duration); - OUT(buffs[r].counters); - //OUT(buffs[r].player_id); + OUT(buffs[r].num_hits); + OUT(buffs[r].player_id); } for (r = 0; r < MAX_PP_DISCIPLINES; r++) { OUT(disciplines.values[r]); @@ -3216,15 +3225,15 @@ namespace UF DECODE(OP_Buff) { - DECODE_LENGTH_EXACT(structs::SpellBuffFade_Struct_Underfoot); - SETUP_DIRECT_DECODE(SpellBuffFade_Struct, structs::SpellBuffFade_Struct_Underfoot); + DECODE_LENGTH_EXACT(structs::SpellBuffPacket_Struct); + SETUP_DIRECT_DECODE(SpellBuffPacket_Struct, structs::SpellBuffPacket_Struct); IN(entityid); - IN(slot); - IN(level); - IN(effect); - IN(spellid); - IN(duration); + IN(buff.effect_type); + IN(buff.level); + IN(buff.unknown003); + IN(buff.spellid); + IN(buff.duration); IN(slotid); IN(bufffade); diff --git a/common/patches/uf_structs.h b/common/patches/uf_structs.h index f4f78f1c5..932213827 100644 --- a/common/patches/uf_structs.h +++ b/common/patches/uf_structs.h @@ -566,55 +566,28 @@ struct SpawnAppearance_Struct // Size 76 (was 24) struct SpellBuff_Struct { -/*000*/ uint8 slotid; // badly named... seems to be 2 for a real buff, 0 otherwise -/*001*/ uint8 level; -/*002*/ uint8 bard_modifier; -/*003*/ uint8 effect; // not real -/*004*/ uint32 unknown004; // Seen 1 for no buff -/*008*/ uint32 spellid; -/*012*/ int32 duration; -/*016*/ uint32 unknown016; -/*020*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages -/*024*/ uint32 counters; -/*028*/ uint8 unknown0028[48]; -/*076*/ +/*000*/ uint8 effect_type; // 0 = no buff, 2 = buff, 4 = inverse affects of buff +/*001*/ uint8 level; // Seen 1 for no buff +/*002*/ uint8 unknown002; //pretty sure padding now +/*003*/ uint8 unknown003; // MQ2 used to call this "damage shield" -- don't see client referencing it, so maybe server side DS type tracking? +/*004*/ float bard_modifier; +/*008*/ uint32 spellid; +/*012*/ uint32 duration; +/*016*/ uint32 num_hits; +/*020*/ uint32 player_id; // caster ID, pretty sure just zone ID +/*024*/ uint32 unknown036; +/*028*/ int32 slot_data[12]; // book keeping stuff per slot (counters, rune/vie) }; // Not functional yet, but this is what the packet looks like on Underfoot -struct SpellBuffFade_Struct_Underfoot { +struct SpellBuffPacket_Struct { /*000*/ uint32 entityid; // Player id who cast the buff -/*004*/ uint8 slot; -/*005*/ uint8 level; -/*006*/ uint8 effect; -/*007*/ uint8 unknown7; -/*008*/ float unknown008; -/*012*/ uint32 spellid; -/*016*/ int32 duration; -/*020*/ uint32 num_hits; -/*024*/ uint32 playerId; // Global player ID? -/*028*/ uint32 unknown020; -/*032*/ uint8 unknown0028[48]; +/*004*/ SpellBuff_Struct buff; /*080*/ uint32 slotid; /*084*/ uint32 bufffade; /*088*/ }; -struct SpellBuffFade_Struct { -/*000*/ uint32 entityid; -/*004*/ uint8 slot; -/*005*/ uint8 level; -/*006*/ uint8 effect; -/*007*/ uint8 unknown7; -/*008*/ uint32 spellid; -/*012*/ int32 duration; -/*016*/ uint32 unknown016; -/*020*/ uint32 unknown020; // Global player ID? -/*024*/ uint32 playerId; // Player id who cast the buff -/*028*/ uint32 slotid; -/*032*/ uint32 bufffade; -/*036*/ -}; - #if 0 struct BuffIconEntry_Struct { /*000*/ uint32 buff_slot; diff --git a/zone/client.h b/zone/client.h index 9bd22f815..1d30b97ce 100644 --- a/zone/client.h +++ b/zone/client.h @@ -918,7 +918,7 @@ public: //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. - void SendBuffDurationPacket(Buffs_Struct &buff); + void SendBuffDurationPacket(Buffs_Struct &buff, int slot); void SendBuffNumHitPacket(Buffs_Struct &buff, int slot); void ProcessInspectRequest(Client* requestee, Client* requester); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 4bf5b0968..39574274a 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1463,22 +1463,24 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) if (buffs[i].spellid != SPELL_UNKNOWN) { m_pp.buffs[i].spellid = buffs[i].spellid; m_pp.buffs[i].bard_modifier = buffs[i].instrument_mod; - m_pp.buffs[i].slotid = 2; + m_pp.buffs[i].effect_type = 2; m_pp.buffs[i].player_id = 0x2211; m_pp.buffs[i].level = buffs[i].casterlevel; - m_pp.buffs[i].effect = 0; + m_pp.buffs[i].unknown003 = 0; m_pp.buffs[i].duration = buffs[i].ticsremaining; m_pp.buffs[i].counters = buffs[i].counters; + m_pp.buffs[i].num_hits = buffs[i].numhits; } else { m_pp.buffs[i].spellid = SPELLBOOK_UNKNOWN; m_pp.buffs[i].bard_modifier = 10; - m_pp.buffs[i].slotid = 0; + m_pp.buffs[i].effect_type = 0; m_pp.buffs[i].player_id = 0; m_pp.buffs[i].level = 0; - m_pp.buffs[i].effect = 0; + m_pp.buffs[i].unknown003 = 0; m_pp.buffs[i].duration = 0; m_pp.buffs[i].counters = 0; + m_pp.buffs[i].num_hits = 0; } } } @@ -3833,15 +3835,15 @@ void Client::Handle_OP_BoardBoat(const EQApplicationPacket *app) void Client::Handle_OP_Buff(const EQApplicationPacket *app) { - if (app->size != sizeof(SpellBuffFade_Struct)) + if (app->size != sizeof(SpellBuffPacket_Struct)) { - Log.Out(Logs::General, Logs::Error, "Size mismatch in OP_Buff. expected %i got %i", sizeof(SpellBuffFade_Struct), app->size); + Log.Out(Logs::General, Logs::Error, "Size mismatch in OP_Buff. expected %i got %i", sizeof(SpellBuffPacket_Struct), app->size); DumpPacket(app); return; } - SpellBuffFade_Struct* sbf = (SpellBuffFade_Struct*)app->pBuffer; - uint32 spid = sbf->spellid; + SpellBuffPacket_Struct* sbf = (SpellBuffPacket_Struct*)app->pBuffer; + uint32 spid = sbf->buff.spellid; Log.Out(Logs::Detail, Logs::Spells, "Client requested that buff with spell id %d be canceled.", spid); //something about IsDetrimentalSpell() crashes this portion of code.. diff --git a/zone/pets.cpp b/zone/pets.cpp index 28d6bdf91..e527d80ce 100644 --- a/zone/pets.cpp +++ b/zone/pets.cpp @@ -579,10 +579,10 @@ void NPC::GetPetState(SpellBuff_Struct *pet_buffs, uint32 *items, char *name) { for (int i=0; i < GetPetMaxTotalSlots(); i++) { if (buffs[i].spellid != SPELL_UNKNOWN) { pet_buffs[i].spellid = buffs[i].spellid; - pet_buffs[i].slotid = i+1; + pet_buffs[i].effect_type = i+1; pet_buffs[i].duration = buffs[i].ticsremaining; pet_buffs[i].level = buffs[i].casterlevel; - pet_buffs[i].effect = 10; + pet_buffs[i].bard_modifier = 10; pet_buffs[i].counters = buffs[i].counters; pet_buffs[i].bard_modifier = buffs[i].instrument_mod; } @@ -590,7 +590,7 @@ void NPC::GetPetState(SpellBuff_Struct *pet_buffs, uint32 *items, char *name) { pet_buffs[i].spellid = SPELL_UNKNOWN; pet_buffs[i].duration = 0; pet_buffs[i].level = 0; - pet_buffs[i].effect = 0; + pet_buffs[i].bard_modifier = 10; pet_buffs[i].counters = 0; } } @@ -623,10 +623,10 @@ void NPC::SetPetState(SpellBuff_Struct *pet_buffs, uint32 *items) { else { buffs[i].spellid = SPELL_UNKNOWN; pet_buffs[i].spellid = 0xFFFFFFFF; - pet_buffs[i].slotid = 0; + pet_buffs[i].effect_type = 0; pet_buffs[i].level = 0; pet_buffs[i].duration = 0; - pet_buffs[i].effect = 0; + pet_buffs[i].bard_modifier = 0; } } for (int j1=0; j1 < GetPetMaxTotalSlots(); j1++) { @@ -648,10 +648,10 @@ void NPC::SetPetState(SpellBuff_Struct *pet_buffs, uint32 *items) { case SE_Illusion: buffs[j1].spellid = SPELL_UNKNOWN; pet_buffs[j1].spellid = SPELLBOOK_UNKNOWN; - pet_buffs[j1].slotid = 0; + pet_buffs[j1].effect_type = 0; pet_buffs[j1].level = 0; pet_buffs[j1].duration = 0; - pet_buffs[j1].effect = 0; + pet_buffs[j1].bard_modifier = 0; x1 = EFFECT_COUNT; break; // We can't send appearance packets yet, put down at CompleteConnect diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 45225421b..0209ba4df 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -3413,7 +3413,7 @@ void Mob::BuffProcess() { if(buffs[buffs_i].UpdateClient == true) { - CastToClient()->SendBuffDurationPacket(buffs[buffs_i]); + CastToClient()->SendBuffDurationPacket(buffs[buffs_i], buffs_i); // Hack to get UF to play nicer, RoF seems fine without it if (CastToClient()->ClientVersion() == EQEmu::versions::ClientVersion::UF && buffs[buffs_i].numhits > 0) CastToClient()->SendBuffNumHitPacket(buffs[buffs_i], buffs_i); diff --git a/zone/spells.cpp b/zone/spells.cpp index 9e8297e3a..ab6c5d48e 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -4797,17 +4797,17 @@ void Client::MakeBuffFadePacket(uint16 spell_id, int slot_id, bool send_message) { EQApplicationPacket* outapp; - outapp = new EQApplicationPacket(OP_Buff, sizeof(SpellBuffFade_Struct)); - SpellBuffFade_Struct* sbf = (SpellBuffFade_Struct*) outapp->pBuffer; + outapp = new EQApplicationPacket(OP_Buff, sizeof(SpellBuffPacket_Struct)); + SpellBuffPacket_Struct* sbf = (SpellBuffPacket_Struct*) outapp->pBuffer; - sbf->entityid=GetID(); + sbf->entityid = GetID(); // i dont know why but this works.. for now - sbf->slot=2; + sbf->buff.effect_type = 2; // sbf->slot=m_pp.buffs[slot_id].slotid; // sbf->level=m_pp.buffs[slot_id].level; // sbf->effect=m_pp.buffs[slot_id].effect; - sbf->spellid=spell_id; - sbf->slotid=slot_id; + sbf->buff.spellid = spell_id; + sbf->slotid = slot_id; sbf->bufffade = 1; #if EQDEBUG >= 11 printf("Sending SBF 1 from server:\n"); @@ -4820,7 +4820,7 @@ void Client::MakeBuffFadePacket(uint16 spell_id, int slot_id, bool send_message) sbf->level=0; sbf->slot=0; */ - sbf->spellid=0xffffffff; + sbf->buff.spellid = 0xffffffff; #if EQDEBUG >= 11 printf("Sending SBF 2 from server:\n"); DumpPacket(outapp); @@ -4838,7 +4838,6 @@ void Client::MakeBuffFadePacket(uint16 spell_id, int slot_id, bool send_message) QueuePacket(outapp); safe_delete(outapp); } - } void Client::MemSpell(uint16 spell_id, int slot, bool update_client) @@ -5274,99 +5273,36 @@ void Mob::_StopSong() //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 //be used for other things as well -void Client::SendBuffDurationPacket(Buffs_Struct &buff) +void Client::SendBuffDurationPacket(Buffs_Struct &buff, int slot) { EQApplicationPacket* outapp; - outapp = new EQApplicationPacket(OP_Buff, sizeof(SpellBuffFade_Struct)); - SpellBuffFade_Struct* sbf = (SpellBuffFade_Struct*) outapp->pBuffer; - int index; + outapp = new EQApplicationPacket(OP_Buff, sizeof(SpellBuffPacket_Struct)); + SpellBuffPacket_Struct* sbf = (SpellBuffPacket_Struct*) outapp->pBuffer; sbf->entityid = GetID(); - sbf->slot = 2; - sbf->spellid = buff.spellid; - sbf->slotid = 0; - sbf->level = buff.casterlevel > 0 ? buff.casterlevel : GetLevel(); - // We really don't know what to send as sbf->effect. - // The code used to send level (and still does for cases we don't know) - // - // The fixes below address known issues with sending level in this field. - // Typically, when the packet is sent, or when the user - // next does something on the UI that causes an update (like opening a - // pack), the stats updated by the spell in question get corrupted. - // - // The values were determined by trial and error. I could not find a - // pattern or find a field in spells_new that would work. + sbf->buff.effect_type = 2; - sbf->effect=sbf->level; - - if (IsEffectInSpell(buff.spellid, SE_TotalHP)) - { - // If any of the lower 6 bits are set, the GUI changes MAX_HP AGAIN. - // If its set to 0 the effect is cancelled. - // 128 seems to work (ie: change only duration). - sbf->effect = 128; - } - else if (IsEffectInSpell(buff.spellid, SE_CurrentHP)) - { - // This is mostly a problem when we try and update duration on a - // dot or a hp->mana conversion. Zero cancels the effect - // Sending teh actual change again seems to work. - index = GetSpellEffectIndex(buff.spellid, SE_CurrentHP); - sbf->effect = abs(spells[buff.spellid].base[index]); - } - else if (IsEffectInSpell(buff.spellid, SE_SeeInvis)) - { - // 10 seems to not break SeeInvis spells. Level, - // which is what the old client sends breaks the client at at - // least level 9, maybe more. - sbf->effect = 10; - } - else if (IsEffectInSpell(buff.spellid, SE_ArmorClass) || - IsEffectInSpell(buff.spellid, SE_ResistFire) || - IsEffectInSpell(buff.spellid, SE_ResistCold) || - IsEffectInSpell(buff.spellid, SE_ResistPoison) || - IsEffectInSpell(buff.spellid, SE_ResistDisease) || - IsEffectInSpell(buff.spellid, SE_ResistMagic) || - IsEffectInSpell(buff.spellid, SE_STR) || - IsEffectInSpell(buff.spellid, SE_STA) || - IsEffectInSpell(buff.spellid, SE_DEX) || - IsEffectInSpell(buff.spellid, SE_WIS) || - IsEffectInSpell(buff.spellid, SE_INT) || - IsEffectInSpell(buff.spellid, SE_AGI)) - { - // This seems to work. Previosly stats got corrupted when sending - // level. - sbf->effect = 46; - } - else if (IsEffectInSpell(buff.spellid, SE_MovementSpeed)) - { - index = GetSpellEffectIndex(buff.spellid, SE_MovementSpeed); - - // So MovementSpeed spells react to effect values as follows: - // 0- cancels the effect (buff stays up - run speed is normal) - // 1-45 - A formula of change where 1-9 yield about a .1 to .9 - // reduction of the spell effect, 10 yields about the same, and - // 11-45 gets faster very quickly until the effect well exceeds - // any intended max. - // 46 - seems to do nothing - which is what we need. - sbf->effect = 46; - } - else if (IsEffectInSpell(buff.spellid, SE_CHA)) - { - index = GetSpellEffectIndex(buff.spellid, SE_CHA); - sbf->effect = abs(spells[buff.spellid].base[index]); - // Only use this valie if its not a spacer. - if (sbf->effect != 0) - { - // Same as other stats, need this to prevent a double update. - sbf->effect = 46; - } - } + sbf->buff.level = buff.casterlevel > 0 ? buff.casterlevel : GetLevel(); + sbf->buff.bard_modifier = buff.instrument_mod; + sbf->buff.spellid = buff.spellid; + sbf->buff.duration = buff.ticsremaining; + if (buff.dot_rune) + sbf->buff.counters = buff.dot_rune; + else if (buff.magic_rune) + sbf->buff.counters = buff.magic_rune; + else if (buff.melee_rune) + sbf->buff.counters = buff.melee_rune; + else if (buff.counters) + sbf->buff.counters = buff.counters; + sbf->buff.player_id = buff.casterid; + sbf->buff.num_hits = buff.numhits; + sbf->buff.y = buff.caston_y; + sbf->buff.x = buff.caston_x; + sbf->buff.z = buff.caston_z; + sbf->slotid = slot; sbf->bufffade = 0; - sbf->duration = buff.ticsremaining; - sbf->num_hits = buff.numhits; FastQueuePacket(&outapp); } @@ -5496,7 +5432,7 @@ void Mob::BuffModifyDurationBySpellID(uint16 spell_id, int32 newDuration) buffs[i].ticsremaining = newDuration; if(IsClient()) { - CastToClient()->SendBuffDurationPacket(buffs[i]); + CastToClient()->SendBuffDurationPacket(buffs[i], i); } } } diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 1c37d4689..d0c80f37f 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -3305,7 +3305,7 @@ void ZoneDatabase::LoadPetInfo(Client *client) pi->Buffs[slot_id].spellid = spell_id; pi->Buffs[slot_id].level = caster_level; pi->Buffs[slot_id].player_id = caster_id; - pi->Buffs[slot_id].slotid = 2; // Always 2 in buffs struct for real buffs + pi->Buffs[slot_id].effect_type = 2; // Always 2 in buffs struct for real buffs pi->Buffs[slot_id].duration = ticsremaining; pi->Buffs[slot_id].counters = counters;