diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index 8e5588e5c..a022626e1 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -534,7 +534,7 @@ struct SpellBuffFade_Struct { /*007*/ uint8 unknown7; /*008*/ uint32 spellid; /*012*/ uint32 duration; -/*016*/ uint32 unknown016; +/*016*/ uint32 num_hits; /*020*/ uint32 unknown020; //prolly global player ID /*024*/ uint32 slotid; /*028*/ uint32 bufffade; @@ -4602,11 +4602,13 @@ struct BuffIconEntry_Struct uint32 buff_slot; uint32 spell_id; uint32 tics_remaining; + uint32 num_hits; }; struct BuffIcon_Struct { uint32 entity_id; + uint8 all_buffs; uint16 count; BuffIconEntry_Struct entries[0]; }; diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index d6eb858e3..a107a1246 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -376,6 +376,7 @@ namespace RoF OUT(duration); eq->playerId = 0x7cde; OUT(slotid); + OUT(num_hits); if (emu->bufffade == 1) eq->bufffade = 1; else @@ -414,7 +415,7 @@ namespace RoF __packet->WriteUInt32(emu->entity_id); __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); for (uint16 i = 0; i < emu->count; ++i) @@ -429,10 +430,10 @@ namespace RoF __packet->WriteUInt32(buffslot); __packet->WriteUInt32(emu->entries[i].spell_id); __packet->WriteUInt32(emu->entries[i].tics_remaining); - __packet->WriteUInt32(0); // Unknown + __packet->WriteUInt32(emu->entries[i].num_hits); // Unknown __packet->WriteString(""); } - __packet->WriteUInt8(0); // Unknown + __packet->WriteUInt8(!emu->all_buffs); // Unknown FINISH_ENCODE(); } diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index 0549b4b58..5f1d2aac4 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -712,7 +712,8 @@ struct SpellBuffFade_Struct_Live { /*012*/ uint32 spellid; /*016*/ uint32 duration; /*020*/ uint32 playerId; // Global player ID? -/*024*/ uint8 unknown0028[68]; +/*024*/ uint32 num_hits; +/*028*/ uint8 unknown0028[64]; /*092*/ uint32 slotid; /*096*/ uint32 bufffade; /*100*/ @@ -726,7 +727,7 @@ struct SpellBuffFade_Struct { /*007*/ uint8 unknown7; /*008*/ uint32 spellid; /*012*/ uint32 duration; -/*016*/ uint32 unknown016; +/*016*/ uint32 num_hits; /*020*/ uint32 unknown020; // Global player ID? /*024*/ uint32 playerId; // Player id who cast the buff /*028*/ uint32 slotid; @@ -741,6 +742,27 @@ struct BuffRemoveRequest_Struct /*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 { /*000*/ uint32 npcid; diff --git a/common/patches/underfoot.cpp b/common/patches/underfoot.cpp index 7c1aa940b..6291d3077 100644 --- a/common/patches/underfoot.cpp +++ b/common/patches/underfoot.cpp @@ -330,6 +330,7 @@ namespace Underfoot OUT(duration); 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(num_hits); eq->unknown008 = 1.0f; FINISH_ENCODE(); @@ -348,7 +349,7 @@ namespace Underfoot *((uint32*)ptr) = emu->entity_id; ptr += sizeof(uint32); ptr += sizeof(uint32); - *((uint8*)ptr) = 1; + *((uint8*)ptr) = emu->all_buffs; ptr += sizeof(uchar); *((uint16*)ptr) = emu->count; ptr += sizeof(uint16); @@ -371,7 +372,9 @@ namespace Underfoot ptr += sizeof(uint32); *((uint32*)ptr) = emu->entries[i].tics_remaining; ptr += sizeof(uint32); + *((uint32*)ptr) = emu->entries[i].num_hits; ptr += sizeof(uint32); + *((uint8*)ptr) = !emu->all_buffs; ptr += 1; } diff --git a/common/patches/underfoot_structs.h b/common/patches/underfoot_structs.h index ab263d6c4..89101ca2e 100644 --- a/common/patches/underfoot_structs.h +++ b/common/patches/underfoot_structs.h @@ -564,7 +564,7 @@ struct SpellBuffFade_Struct_Underfoot { /*008*/ float unknown008; /*012*/ uint32 spellid; /*016*/ uint32 duration; -/*020*/ uint32 unknown016; +/*020*/ uint32 num_hits; /*024*/ uint32 playerId; // Global player ID? /*028*/ uint32 unknown020; /*032*/ uint8 unknown0028[48]; @@ -589,6 +589,25 @@ struct SpellBuffFade_Struct { /*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 { /*00*/ uint32 SlotID; diff --git a/zone/client.h b/zone/client.h index 235861396..fe05194bc 100644 --- a/zone/client.h +++ b/zone/client.h @@ -896,7 +896,8 @@ 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(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); bool ClientFinishedLoading() { return (conn_state == ClientConnectFinished); } diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index add06714b..f86f43bf4 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -3395,7 +3395,7 @@ void Mob::BuffProcess() { 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; } } @@ -5559,64 +5559,56 @@ void Mob::CheckNumHitsRemaining(uint8 type, uint32 buff_slot, uint16 spell_id) uint32 buff_max = GetMaxTotalSlots(); //Spell specific procs [Type 7,10,11] - if (IsValidSpell(spell_id)){ - - 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].numhits == 0) { + if (IsValidSpell(spell_id)) { + 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].numhits == 0) { CastOnNumHitFade(buffs[d].spellid); - if(!TryFadeEffect(d)) + if (!TryFadeEffect(d)) 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){ - - if(--buffs[buff_slot].numhits == 0) { + } else if (type == 7) { + if (buff_slot > 0) { + if (--buffs[buff_slot].numhits == 0) { CastOnNumHitFade(buffs[buff_slot].spellid); - if(!TryFadeEffect(buff_slot)) + if (!TryFadeEffect(buff_slot)) BuffFadeBySlot(buff_slot , true); - } + } else if (IsClient()) { // still have numhits and client, update + CastToClient()->SendBuffNumHitPacket(buffs[buff_slot], buff_slot); } - - else { - - for(int d = 0; d < buff_max; d++) { - - if(!m_spellHitsLeft[d]) + } else { + for (int d = 0; d < buff_max; d++) { + if (!m_spellHitsLeft[d]) continue; - if ((IsValidSpell(buffs[d].spellid)) && (m_spellHitsLeft[d] == buffs[d].spellid)) { - if(--buffs[d].numhits == 0) { + if (IsValidSpell(buffs[d].spellid) && m_spellHitsLeft[d] == buffs[d].spellid) { + if (--buffs[d].numhits == 0) { CastOnNumHitFade(buffs[d].spellid); m_spellHitsLeft[d] = 0; - if(!TryFadeEffect(d)) + if (!TryFadeEffect(d)) 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) && (spells[buffs[d].spellid].numhitstype == type)){ - - if(--buffs[d].numhits == 0) { + } else { + 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); - if(!TryFadeEffect(d)){ + if (!TryFadeEffect(d)) BuffFadeBySlot(d, true); - } + } else if (IsClient()) { // still have numhits and client, update + CastToClient()->SendBuffNumHitPacket(buffs[d], d); } - } } } diff --git a/zone/spells.cpp b/zone/spells.cpp index fb3cba454..310bc35bd 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -5164,20 +5164,40 @@ 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(uint16 spell_id, int duration, int inlevel) +void Client::SendBuffDurationPacket(Buffs_Struct &buff) { EQApplicationPacket* outapp; outapp = new EQApplicationPacket(OP_Buff, sizeof(SpellBuffFade_Struct)); SpellBuffFade_Struct* sbf = (SpellBuffFade_Struct*) outapp->pBuffer; sbf->entityid = GetID(); - sbf->slot=2; - sbf->spellid=spell_id; - sbf->slotid=0; - sbf->effect = inlevel > 0 ? inlevel : GetLevel(); - sbf->level = inlevel > 0 ? inlevel : GetLevel(); + sbf->slot = 2; + sbf->spellid = buff.spellid; + sbf->slotid = 0; + sbf->effect = buff.casterlevel > 0 ? buff.casterlevel : GetLevel(); + sbf->level = buff.casterlevel > 0 ? buff.casterlevel : GetLevel(); 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); } @@ -5252,6 +5272,7 @@ EQApplicationPacket *Mob::MakeBuffsPacket(bool for_target) BuffIcon_Struct *buff = (BuffIcon_Struct*)outapp->pBuffer; buff->entity_id = GetID(); buff->count = count; + buff->all_buffs = 1; uint32 index = 0; for(unsigned int i = 0; i < buff_count; ++i) @@ -5261,6 +5282,7 @@ EQApplicationPacket *Mob::MakeBuffsPacket(bool for_target) buff->entries[index].buff_slot = i; buff->entries[index].spell_id = buffs[i].spellid; buff->entries[index].tics_remaining = buffs[i].ticsremaining; + buff->entries[index].num_hits = buffs[i].numhits; ++index; } } @@ -5278,7 +5300,7 @@ void Mob::BuffModifyDurationBySpellID(uint16 spell_id, int32 newDuration) buffs[i].ticsremaining = newDuration; if(IsClient()) { - CastToClient()->SendBuffDurationPacket(buffs[i].spellid, buffs[i].ticsremaining, buffs[i].casterlevel); + CastToClient()->SendBuffDurationPacket(buffs[i]); } } }