diff --git a/tob/opcodes.md b/tob/opcodes.md index 3c6bb5c38..fe7af3407 100644 --- a/tob/opcodes.md +++ b/tob/opcodes.md @@ -68,8 +68,7 @@ Below is a status list for the 450 opcodes we currently use on the server for th | `OP_BlockedBuffs` | 🟢 Verified | | | | `OP_BoardBoat` | 🟡 Unverified | | | | `OP_BookButton` | 🟡 Unverified | | | -| `OP_BuffDefinition` | 🟡 Unverified | | | -| `OP_RefreshBuffs` | 🟡 Unverified | | | +| `OP_BuffDefinition` | 🟢 Verified | | | | `OP_BuffRemoveRequest` | 🟡 Unverified | | | | `OP_Bug` | 🟡 Unverified | | | | `OP_BuyerItems` | 🔴 Not-Set | | | @@ -395,7 +394,6 @@ Below is a status list for the 450 opcodes we currently use on the server for th | `OP_OpenInventory` | 🔴 Not-Set | | | | `OP_OpenTributeMaster` | 🔴 Not-Set | | | | `OP_PDeletePetition` | 🔴 Not-Set | | | -| `OP_RefreshPetBuffs` | 🔴 Not-Set | | | | `OP_PetCommands` | 🔴 Not-Set | | | | `OP_PetCommandState` | 🔴 Not-Set | | | | `OP_PetHoTT` | 🔴 Not-Set | | | @@ -451,6 +449,9 @@ Below is a status list for the 450 opcodes we currently use on the server for th | `OP_RecipesFavorite` | 🟡 Unverified | | | | `OP_RecipesSearch` | 🟡 Unverified | | | | `OP_ReclaimCrystals` | 🔴 Not-Set | | | +| `OP_RefreshBuffs` | 🟢 Verified | | | +| `OP_RefreshPetBuffs` | 🟢 Verified | | | +| `OP_RefreshTargetBuffs` | 🟢 Verified | | | | `OP_ReloadUI` | 🔴 Not-Set | | | | `OP_RemoveAllDoors` | 🟡 Unverified | | | | `OP_RemoveBlockedBuffs` | 🟢 Verified | | | @@ -551,7 +552,6 @@ Below is a status list for the 450 opcodes we currently use on the server for th | `OP_Surname` | 🔴 Not-Set | | | | `OP_SwapSpell` | 🟢 Verified | | | | `OP_SystemFingerprint` | 🔴 Not-Set | | | -| `OP_RefreshTargetBuffs` | 🔴 Not-Set | | | | `OP_TargetCommand` | 🟡 Unverified | | | | `OP_TargetHoTT` | 🔴 Not-Set | | | | `OP_TargetMouse` | 🟡 Unverified | | | diff --git a/zone/client.cpp b/zone/client.cpp index c37923d1e..ad202571a 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -6326,8 +6326,7 @@ void Client::SuspendMinion(int value) if(value >= 1) { CurrentPet->SetPetState(m_suspendedminion.Buffs, m_suspendedminion.Items); - - CurrentPet->SendPetBuffsToClient(); + Buff::SendFullBuffRefresh(CurrentPet); } CurrentPet->CalcBonuses(); diff --git a/zone/client.h b/zone/client.h index 619298925..d36e331b6 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1268,11 +1268,6 @@ public: const std::string GetAutoLoginCharacterName(); bool SetAutoLoginCharacterName(const std::string& character_name); - //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, int slot); - void SendBuffNumHitPacket(Buffs_Struct &buff, int slot); - void ProcessInspectRequest(Client* requestee, Client* requester); bool ClientFinishedLoading() { return (conn_state == ClientConnectFinished); } int FindSpellBookSlotBySpellID(int32 spellid); @@ -1956,7 +1951,6 @@ public: protected: friend class Mob; void CalcEdibleBonuses(StatBonuses* newbon); - void MakeBuffFadePacket(int32 spell_id, int slot_id, bool send_message = true); bool client_data_loaded; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index c20856598..c73dc49b0 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -760,7 +760,7 @@ void Client::CompleteConnect() Mob* pet = GetPet(); if (pet) { pet->SendWearChangeAndLighting(EQ::textures::LastTexture); - pet->SendPetBuffsToClient(); + Buff::SendFullBuffRefresh(pet); } if (GetGroup()) diff --git a/zone/client_version.h b/zone/client_version.h index 28a4af480..130372d03 100644 --- a/zone/client_version.h +++ b/zone/client_version.h @@ -295,6 +295,18 @@ inline void SendSingleBuffChange(Mob* sender, const Buffs_Struct& buff, int slot ClientPatch::QueueClientsByTarget(sender, ackreq, false, ShouldSendTargetBuffs, mutate)( &IBuff::RefreshBuffs, GetComponent, OP_RefreshTargetBuffs, sender, remove, suspended, slots); + + // the client doesn't automatically do this for some reason (RoF2? I think this is in TOB) + // TODO: hook this up to QueueClients, or figure out if there's another missing packet to display the fade text + if (remove && sender->IsClient()) + { + const char *fadetext = spells[buff.spellid].spell_fades; + auto outapp = std::make_unique(OP_ColoredText, sizeof(ColoredText_Struct) + strlen(fadetext)); + ColoredText_Struct *bfm = (ColoredText_Struct *) outapp->pBuffer; + bfm->color = Chat::Spells; + memcpy(bfm->msg, fadetext, strlen(fadetext)); + sender->CastToClient()->QueuePacket(outapp.get()); + } } } // namespace Buff diff --git a/zone/common.h b/zone/common.h index b295a3898..59d20d305 100644 --- a/zone/common.h +++ b/zone/common.h @@ -242,7 +242,7 @@ struct Buffs_Struct { int32 virus_spread_time; //time till next attempted viral spread bool persistant_buff; bool client; //True if the caster is a client - bool UpdateClient; + bool UpdateClient; // This is for legacy client support only. Newer clients take refresh packets for the entire buff list // cereal template diff --git a/zone/mob.h b/zone/mob.h index 3aeffe0f9..606a96109 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -459,7 +459,6 @@ public: int AddBuff(Mob *caster, const int32 spell_id, int duration = 0, int32 level_override = -1, bool disable_buff_overwrite = false); int CanBuffStack(int32 spellid, uint8 caster_level, bool iFailIfOverwrite = false); int CalcBuffDuration(Mob *caster, Mob *target, int32 spell_id, int32 caster_level_override = -1); - void SendPetBuffsToClient(); virtual int GetCurrentBuffSlots() const { return 0; } virtual int GetCurrentSongSlots() const { return 0; } virtual int GetCurrentDiscSlots() const { return 0; } diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index c7718bbad..0d06e1c37 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -821,7 +821,7 @@ bool Mob::SpellEffect(Mob* caster, int32 spell_id, float partial, int level_over ps->command = 1; entity_list.QueueClients(this, app); safe_delete(app); - SendPetBuffsToClient(); + Buff::SendFullBuffRefresh(this); SendAppearancePacket(AppearanceType::Pet, caster->GetID(), true, true); } @@ -3864,19 +3864,15 @@ void Mob::BuffProcess() } } - if(IsClient()) - { - if(buffs[buffs_i].UpdateClient == true) - { - CastToClient()->SendBuffDurationPacket(buffs[buffs_i], buffs_i); - // Hack to get UF to play nicer, RoF seems fine without it - if (CastToClient()->ClientVersion() == EQ::versions::ClientVersion::UF && buffs[buffs_i].hit_number > 0) - CastToClient()->SendBuffNumHitPacket(buffs[buffs_i], buffs_i); - buffs[buffs_i].UpdateClient = false; - } + // this is for older clients. Newer clients will simply discard this packet + if (IsClient() && buffs[buffs_i].UpdateClient == true) { + Buff::SendSingleBuffChange(this, buffs[buffs_i], buffs_i); + buffs[buffs_i].UpdateClient = false; } } } + + Buff::SendFullBuffRefresh(this); } void Mob::DoBuffTic(const Buffs_Struct &buff, int slot, Mob *caster) @@ -4248,7 +4244,7 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) return; if (IsClient() && !CastToClient()->IsDead()) - CastToClient()->MakeBuffFadePacket(buffs[slot].spellid, slot); + Buff::SendSingleBuffChange(this, buffs[slot], slot); LogSpells("Fading buff [{}] from slot [{}]", buffs[slot].spellid, slot); @@ -7014,7 +7010,7 @@ void Mob::CheckNumHitsRemaining(NumHit type, int32 buff_slot, int32 spell_id) if (!TryFadeEffect(d)) BuffFadeBySlot(d, true); } else if (IsClient()) { // still have numhits and client, update - CastToClient()->SendBuffNumHitPacket(buffs[d], d); + Buff::SendSingleBuffChange(this, buffs[d], d); } } } @@ -7029,7 +7025,7 @@ void Mob::CheckNumHitsRemaining(NumHit type, int32 buff_slot, int32 spell_id) if (!TryFadeEffect(buff_slot)) BuffFadeBySlot(buff_slot , true); } else if (IsClient()) { // still have numhits and client, update - CastToClient()->SendBuffNumHitPacket(buffs[buff_slot], buff_slot); + Buff::SendSingleBuffChange(this, buffs[buff_slot], buff_slot); } } } @@ -7047,7 +7043,7 @@ void Mob::CheckNumHitsRemaining(NumHit type, int32 buff_slot, int32 spell_id) if (!TryFadeEffect(d)) BuffFadeBySlot(d, true); } else if (IsClient()) { // still have numhits and client, update - CastToClient()->SendBuffNumHitPacket(buffs[d], d); + Buff::SendSingleBuffChange(this, buffs[d], d); } } } diff --git a/zone/spells.cpp b/zone/spells.cpp index 8edaa7548..3717a90b8 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -2856,7 +2856,7 @@ bool Mob::SpellFinished(int32 spell_id, Mob *spell_target, CastingSlot slot, int if (IsClient() && IsEffectInSpell(spell_id, SpellEffect::BindSight)) { for (int i = 0; i < GetMaxTotalSlots(); i++) { if (buffs[i].spellid == spell_id) { - CastToClient()->SendBuffNumHitPacket(buffs[i], i);//its hack, it works. + Buff::SendSingleBuffChange(this, buffs[i], i);//its hack, it works. } } } @@ -2864,7 +2864,7 @@ bool Mob::SpellFinished(int32 spell_id, Mob *spell_target, CastingSlot slot, int if (IsClient() && spells[spell_id].hit_number) { for (int i = 0; i < GetMaxTotalSlots(); i++) { if (buffs[i].spellid == spell_id && buffs[i].hit_number > 0) { - CastToClient()->SendBuffNumHitPacket(buffs[i], i); + Buff::SendSingleBuffChange(this, buffs[i], i); break; } } @@ -5809,53 +5809,6 @@ void Mob::Mesmerize() StopNavigation(); } -void Client::MakeBuffFadePacket(int32 spell_id, int slot_id, bool send_message) -{ - EQApplicationPacket* outapp = nullptr; - - outapp = new EQApplicationPacket(OP_BuffDefinition, sizeof(SpellBuffPacket_Struct)); - SpellBuffPacket_Struct* sbf = (SpellBuffPacket_Struct*) outapp->pBuffer; - - sbf->entityid = GetID(); - // i dont know why but this works.. for now - 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->buff.spellid = spell_id; - sbf->slotid = slot_id; - sbf->bufffade = 1; -#if EQDEBUG >= 11 - printf("Sending SBF 1 from server:\n"); - DumpPacket(outapp); -#endif - QueuePacket(outapp); - -/* - sbf->effect=0; - sbf->level=0; - sbf->slot=0; -*/ - sbf->buff.spellid = 0xffffffff; -#if EQDEBUG >= 11 - printf("Sending SBF 2 from server:\n"); - DumpPacket(outapp); -#endif - QueuePacket(outapp); - safe_delete(outapp); - - if(send_message) - { - const char *fadetext = spells[spell_id].spell_fades; - outapp = new EQApplicationPacket(OP_ColoredText, sizeof(ColoredText_Struct) + strlen(fadetext)); - ColoredText_Struct *bfm = (ColoredText_Struct *) outapp->pBuffer; - bfm->color = Chat::Spells; - memcpy(bfm->msg, fadetext, strlen(fadetext)); - QueuePacket(outapp); - safe_delete(outapp); - } -} - void Client::MemSpell(int32 spell_id, int slot, bool update_client) { if (slot >= EQ::spells::SPELL_GEM_COUNT || slot < 0) { @@ -6501,99 +6454,6 @@ int Mob::GetCasterLevel(int32 spell_id) { return std::max(1, level); } -//This member function sets the buff duration on the client -//however it does not work if sent quickly after an action packets, which is what one might perfer to do -//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, int slot) -{ - EQApplicationPacket* outapp = nullptr; - outapp = new EQApplicationPacket(OP_BuffDefinition, sizeof(SpellBuffPacket_Struct)); - SpellBuffPacket_Struct* sbf = (SpellBuffPacket_Struct*) outapp->pBuffer; - - sbf->entityid = GetID(); - - sbf->buff.effect_type = 2; - - 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.hit_number; - sbf->buff.y = buff.caston_y; - sbf->buff.x = buff.caston_x; - sbf->buff.z = buff.caston_z; - - sbf->slotid = slot; - sbf->bufffade = 0; - FastQueuePacket(&outapp); -} - -void Client::SendBuffNumHitPacket(Buffs_Struct &buff, int slot) -{ - // UF+ use this packet - if (ClientVersion() < EQ::versions::ClientVersion::UF) - return; - EQApplicationPacket *outapp = nullptr; - outapp = new EQApplicationPacket(OP_RefreshBuffs, 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->tic_timer = tic_timer.GetRemainingTime(); - - 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.hit_number; - strn0cpy(bi->entries[0].caster, buff.caster_name, 64); - bi->name_lengths = strlen(bi->entries[0].caster); - FastQueuePacket(&outapp); -} - -void Mob::SendPetBuffsToClient() -{ - // Don't really need this check, as it should be checked before this method is called, but it doesn't hurt - // too much to check again. - if(!(GetOwner() && GetOwner()->IsClient())) - return; - - int PetBuffCount = 0; - - auto outapp = new EQApplicationPacket(OP_RefreshPetBuffs, sizeof(PetBuff_Struct)); - PetBuff_Struct* pbs=(PetBuff_Struct*)outapp->pBuffer; - memset(outapp->pBuffer,0,outapp->size); - pbs->petid=GetID(); - - int MaxSlots = GetMaxTotalSlots(); - - if(MaxSlots > PET_BUFF_COUNT) - MaxSlots = PET_BUFF_COUNT; - - for(int buffslot = 0; buffslot < MaxSlots; buffslot++) - { - if (IsValidSpell(buffs[buffslot].spellid)) { - pbs->spellid[buffslot] = buffs[buffslot].spellid; - pbs->ticsremaining[buffslot] = buffs[buffslot].ticsremaining; - PetBuffCount++; - } - } - - pbs->buffcount=PetBuffCount; - GetOwner()->CastToClient()->QueuePacket(outapp); - safe_delete(outapp); -} - void Mob::BuffModifyDurationBySpellID(int32 spell_id, int32 newDuration) { int buff_count = GetMaxTotalSlots(); @@ -6602,10 +6462,7 @@ void Mob::BuffModifyDurationBySpellID(int32 spell_id, int32 newDuration) if (buffs[i].spellid == spell_id) { buffs[i].ticsremaining = newDuration; - if(IsClient()) - { - CastToClient()->SendBuffDurationPacket(buffs[i], i); - } + Buff::SendSingleBuffChange(this, buffs[i], i); } } }