mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-31 00:46:46 +00:00
Added initial duration to buff tracking and corrected buff removal
This commit is contained in:
@@ -48,6 +48,7 @@ public:
|
|||||||
virtual std::unique_ptr<EQApplicationPacket> RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove,
|
virtual std::unique_ptr<EQApplicationPacket> RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove,
|
||||||
bool buff_timers_suspended, const std::vector<uint32_t>& slots) const = 0;
|
bool buff_timers_suspended, const std::vector<uint32_t>& slots) const = 0;
|
||||||
virtual void SetRefreshType(std::unique_ptr<EQApplicationPacket>& packet, Mob* source, Client* target) const = 0;
|
virtual void SetRefreshType(std::unique_ptr<EQApplicationPacket>& packet, Mob* source, Client* target) const = 0;
|
||||||
|
virtual bool NeedsWearMessage() const = 0;
|
||||||
|
|
||||||
uint32_t ServerToPatchBuffSlot(uint32_t slot) const;
|
uint32_t ServerToPatchBuffSlot(uint32_t slot) const;
|
||||||
|
|
||||||
|
|||||||
@@ -4056,6 +4056,8 @@ std::unique_ptr<EQApplicationPacket> BuffComponent::RefreshBuffs(EmuOpcode opcod
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BuffComponent::NeedsWearMessage() const { return true; }
|
||||||
|
|
||||||
void BuffComponent::SetRefreshType(std::unique_ptr<EQApplicationPacket>& packet, Mob* source, Client* target) const {}
|
void BuffComponent::SetRefreshType(std::unique_ptr<EQApplicationPacket>& packet, Mob* source, Client* target) const {}
|
||||||
|
|
||||||
} /*Titanium*/
|
} /*Titanium*/
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ public:
|
|||||||
bool fade) const override;
|
bool fade) const override;
|
||||||
std::unique_ptr<EQApplicationPacket> RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove,
|
std::unique_ptr<EQApplicationPacket> RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove,
|
||||||
bool buff_timers_suspended, const std::vector<uint32_t>& slots) const override;
|
bool buff_timers_suspended, const std::vector<uint32_t>& slots) const override;
|
||||||
|
bool NeedsWearMessage() const override;
|
||||||
void SetRefreshType(std::unique_ptr<EQApplicationPacket>& packet, Mob* source, Client* target) const override;
|
void SetRefreshType(std::unique_ptr<EQApplicationPacket>& packet, Mob* source, Client* target) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+32
-18
@@ -3537,6 +3537,20 @@ namespace TOB
|
|||||||
emu->Initialise = init;
|
emu->Initialise = init;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DECODE(OP_BuffRemoveRequest)
|
||||||
|
{
|
||||||
|
// This is to cater for the fact that short buff box buffs start at 30 as opposed to 25 in prior clients.
|
||||||
|
//
|
||||||
|
DECODE_LENGTH_EXACT(BuffRemoveRequest_Struct);
|
||||||
|
SETUP_DIRECT_DECODE(BuffRemoveRequest_Struct, BuffRemoveRequest_Struct);
|
||||||
|
|
||||||
|
emu->SlotID = TOBToServerBuffSlot(eq->SlotID);
|
||||||
|
|
||||||
|
IN(EntityID);
|
||||||
|
|
||||||
|
FINISH_DIRECT_DECODE();
|
||||||
|
}
|
||||||
|
|
||||||
DECODE(OP_CastSpell)
|
DECODE(OP_CastSpell)
|
||||||
{
|
{
|
||||||
DECODE_LENGTH_EXACT(structs::CastSpell_Struct);
|
DECODE_LENGTH_EXACT(structs::CastSpell_Struct);
|
||||||
@@ -5632,24 +5646,22 @@ std::unique_ptr<EQApplicationPacket> BuffComponent::BuffDefinition(Mob* mob, con
|
|||||||
affect->affect.slots[affect_slot].value = 0; // this is always 0
|
affect->affect.slots[affect_slot].value = 0; // this is always 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fade) {
|
// affect info
|
||||||
// affect info
|
affect->affect.caster_id.Id = buff.casterid;
|
||||||
affect->affect.caster_id.Id = buff.casterid;
|
affect->affect.caster_id.WorldId = RuleI(World, Id);
|
||||||
affect->affect.caster_id.WorldId = RuleI(World, Id);
|
affect->affect.caster_id.Reserved = 0;
|
||||||
affect->affect.caster_id.Reserved = 0;
|
affect->affect.flags = 0;
|
||||||
affect->affect.flags = 0;
|
affect->affect.spell_id = buff.spellid;
|
||||||
affect->affect.spell_id = buff.spellid;
|
affect->affect.duration = buff.ticsremaining;
|
||||||
affect->affect.duration = buff.ticsremaining;
|
affect->affect.initial_duration = buff.initialduration;
|
||||||
affect->affect.initial_duration = buff.ticsremaining; // TODO: this isn't correct, it's the total duration
|
affect->affect.hit_count = buff.hit_number;
|
||||||
affect->affect.hit_count = buff.hit_number;
|
affect->affect.viral_timer = 0;
|
||||||
affect->affect.viral_timer = 0;
|
affect->affect.modifier = static_cast<float>(buff.instrument_mod) / 10.f;
|
||||||
affect->affect.modifier = static_cast<float>(buff.instrument_mod) / 10.f;
|
affect->affect.y = static_cast<float>(buff.caston_y);
|
||||||
affect->affect.y = static_cast<float>(buff.caston_y);
|
affect->affect.x = static_cast<float>(buff.caston_x);
|
||||||
affect->affect.x = static_cast<float>(buff.caston_x);
|
affect->affect.z = static_cast<float>(buff.caston_z);
|
||||||
affect->affect.z = static_cast<float>(buff.caston_z);
|
affect->affect.type = 2;
|
||||||
affect->affect.type = 2;
|
affect->affect.level = buff.casterlevel > 0 ? buff.casterlevel : mob->GetLevel();
|
||||||
affect->affect.level = buff.casterlevel > 0 ? buff.casterlevel : mob->GetLevel();
|
|
||||||
}
|
|
||||||
|
|
||||||
//no idea if these are right; eqlib doesn't seem to know either
|
//no idea if these are right; eqlib doesn't seem to know either
|
||||||
if (buff.dot_rune > 0)
|
if (buff.dot_rune > 0)
|
||||||
@@ -5710,6 +5722,8 @@ std::unique_ptr<EQApplicationPacket> BuffComponent::RefreshBuffs(EmuOpcode opcod
|
|||||||
return std::make_unique<EQApplicationPacket>(opcode, std::move(buffer));
|
return std::make_unique<EQApplicationPacket>(opcode, std::move(buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BuffComponent::NeedsWearMessage() const { return false; }
|
||||||
|
|
||||||
// 0 = self buff window, 1 = self target window, 2 = pet buff or target window, 4 = group, 5 = PC, 7 = NPC
|
// 0 = self buff window, 1 = self target window, 2 = pet buff or target window, 4 = group, 5 = PC, 7 = NPC
|
||||||
void BuffComponent::SetRefreshType(std::unique_ptr<EQApplicationPacket>& packet, Mob* source, Client* target) const
|
void BuffComponent::SetRefreshType(std::unique_ptr<EQApplicationPacket>& packet, Mob* source, Client* target) const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ public:
|
|||||||
BuffDefinition(Mob* mob, const Buffs_Struct& buff, uint32_t slot, bool fade) const override;
|
BuffDefinition(Mob* mob, const Buffs_Struct& buff, uint32_t slot, bool fade) const override;
|
||||||
std::unique_ptr<EQApplicationPacket> RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove,
|
std::unique_ptr<EQApplicationPacket> RefreshBuffs(EmuOpcode opcode, Mob* mob, bool remove,
|
||||||
bool buff_timers_suspended, const std::vector<uint32_t>& slots) const override;
|
bool buff_timers_suspended, const std::vector<uint32_t>& slots) const override;
|
||||||
|
bool NeedsWearMessage() const override;
|
||||||
void SetRefreshType(std::unique_ptr<EQApplicationPacket>& packet, Mob* source, Client* target) const override;
|
void SetRefreshType(std::unique_ptr<EQApplicationPacket>& packet, Mob* source, Client* target) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ D(OP_ApproveName)
|
|||||||
D(OP_AugmentInfo)
|
D(OP_AugmentInfo)
|
||||||
D(OP_AugmentItem)
|
D(OP_AugmentItem)
|
||||||
D(OP_BlockedBuffs)
|
D(OP_BlockedBuffs)
|
||||||
|
D(OP_BuffRemoveRequest)
|
||||||
D(OP_CastSpell)
|
D(OP_CastSpell)
|
||||||
D(OP_ChannelMessage)
|
D(OP_ChannelMessage)
|
||||||
D(OP_CharacterCreate)
|
D(OP_CharacterCreate)
|
||||||
|
|||||||
+1
-1
@@ -69,7 +69,7 @@ Below is a status list for the 450 opcodes we currently use on the server for th
|
|||||||
| `OP_BoardBoat` | 🟡 Unverified | | |
|
| `OP_BoardBoat` | 🟡 Unverified | | |
|
||||||
| `OP_BookButton` | 🟡 Unverified | | |
|
| `OP_BookButton` | 🟡 Unverified | | |
|
||||||
| `OP_BuffDefinition` | 🟢 Verified | | |
|
| `OP_BuffDefinition` | 🟢 Verified | | |
|
||||||
| `OP_BuffRemoveRequest` | 🟡 Unverified | | |
|
| `OP_BuffRemoveRequest` | 🟢 Verified | | |
|
||||||
| `OP_Bug` | 🟡 Unverified | | |
|
| `OP_Bug` | 🟡 Unverified | | |
|
||||||
| `OP_BuyerItems` | 🔴 Not-Set | | |
|
| `OP_BuyerItems` | 🔴 Not-Set | | |
|
||||||
| `OP_CameraEffect` | 🟡 Unverified | | |
|
| `OP_CameraEffect` | 🟡 Unverified | | |
|
||||||
|
|||||||
@@ -113,8 +113,13 @@ void ClientPatch::SendSingleBuffChange(Mob* sender, const Buffs_Struct& buff, in
|
|||||||
// first, send to self if self is client, which takes the definition and the refresh
|
// first, send to self if self is client, which takes the definition and the refresh
|
||||||
if (sender->IsClient()) {
|
if (sender->IsClient()) {
|
||||||
Client* c = sender->CastToClient();
|
Client* c = sender->CastToClient();
|
||||||
FastQueuePacket(c, &IBuff::BuffDefinition, GetClientComponent<IBuff>(c), sender, buff, slot, remove);
|
IBuff* component = GetClientComponent<IBuff>(c);
|
||||||
FastQueuePacket(c, &IBuff::RefreshBuffs, GetClientComponent<IBuff>(c), OP_RefreshBuffs, sender, remove, suspended, slots);
|
FastQueuePacket(c, &IBuff::BuffDefinition, component, sender, buff, slot, remove);
|
||||||
|
FastQueuePacket(c, &IBuff::RefreshBuffs, component, OP_RefreshBuffs, sender, remove, suspended, slots);
|
||||||
|
|
||||||
|
// the client doesn't automatically do this for some reason pre-TOB
|
||||||
|
if (remove && component->NeedsWearMessage())
|
||||||
|
c->SendColoredText(Chat::Spells, spells[buff.spellid].spell_fades);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the rest of the buff packets do not take the definition, only the refresh
|
// the rest of the buff packets do not take the definition, only the refresh
|
||||||
@@ -131,8 +136,4 @@ void ClientPatch::SendSingleBuffChange(Mob* sender, const Buffs_Struct& buff, in
|
|||||||
|
|
||||||
QueueClientsByTarget(sender, ackreq, ShouldSendTargetBuffs, mutate)(
|
QueueClientsByTarget(sender, ackreq, ShouldSendTargetBuffs, mutate)(
|
||||||
&IBuff::RefreshBuffs, GetClientComponent<IBuff>, OP_RefreshTargetBuffs, sender, remove, suspended, slots);
|
&IBuff::RefreshBuffs, GetClientComponent<IBuff>, OP_RefreshTargetBuffs, sender, remove, suspended, slots);
|
||||||
|
|
||||||
// the client doesn't automatically do this for some reason, only send it to the sender (TOB doesn't actually need this, but it doesn't double show the message)
|
|
||||||
if (remove && sender->IsClient())
|
|
||||||
sender->CastToClient()->SendColoredText(Chat::Spells, spells[buff.spellid].spell_fades);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ void FastQueuePacket(Client* c, Fun fun, Obj* obj, Args&&... args)
|
|||||||
if (app) {
|
if (app) {
|
||||||
// FastQueuePacket specifically takes lifetime management of packet, so release here
|
// FastQueuePacket specifically takes lifetime management of packet, so release here
|
||||||
EQApplicationPacket* packet = app.release();
|
EQApplicationPacket* packet = app.release();
|
||||||
|
LogNetcode("S->C FastQueuePacket {}", DumpPacketToString(packet));
|
||||||
c->FastQueuePacket(&packet);
|
c->FastQueuePacket(&packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -228,6 +228,7 @@ struct Buffs_Struct {
|
|||||||
uint32 casterid; // Maybe change this to a pointer sometime, but gotta make sure it's 0'd when it no longer points to anything
|
uint32 casterid; // Maybe change this to a pointer sometime, but gotta make sure it's 0'd when it no longer points to anything
|
||||||
char caster_name[64];
|
char caster_name[64];
|
||||||
int32 ticsremaining;
|
int32 ticsremaining;
|
||||||
|
int32 initialduration;
|
||||||
uint32 counters;
|
uint32 counters;
|
||||||
uint32 hit_number; //the number of physical hits this buff can take before it fades away, lots of druid armor spells take advantage of this mixed with powerful effects
|
uint32 hit_number; //the number of physical hits this buff can take before it fades away, lots of druid armor spells take advantage of this mixed with powerful effects
|
||||||
uint32 melee_rune;
|
uint32 melee_rune;
|
||||||
|
|||||||
@@ -4243,9 +4243,6 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
|
|||||||
if(!IsValidSpell(buffs[slot].spellid))
|
if(!IsValidSpell(buffs[slot].spellid))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (IsClient() && !CastToClient()->IsDead())
|
|
||||||
ClientPatch::SendSingleBuffChange(this, buffs[slot], slot);
|
|
||||||
|
|
||||||
LogSpells("Fading buff [{}] from slot [{}]", buffs[slot].spellid, slot);
|
LogSpells("Fading buff [{}] from slot [{}]", buffs[slot].spellid, slot);
|
||||||
|
|
||||||
const auto has_fade_event = parse->SpellHasQuestSub(buffs[slot].spellid, EVENT_SPELL_FADE);
|
const auto has_fade_event = parse->SpellHasQuestSub(buffs[slot].spellid, EVENT_SPELL_FADE);
|
||||||
@@ -4650,8 +4647,12 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
|
|||||||
if (spells[buffs[slot].spellid].nimbus_effect > 0)
|
if (spells[buffs[slot].spellid].nimbus_effect > 0)
|
||||||
RemoveNimbusEffect(spells[buffs[slot].spellid].nimbus_effect);
|
RemoveNimbusEffect(spells[buffs[slot].spellid].nimbus_effect);
|
||||||
|
|
||||||
buffs[slot].spellid = SPELL_UNKNOWN;
|
// the client expects remaining duration to be 0 in the single packet change
|
||||||
|
buffs[slot].ticsremaining = 0;
|
||||||
ClientPatch::SendSingleBuffChange(this, buffs[slot], slot, true);
|
ClientPatch::SendSingleBuffChange(this, buffs[slot], slot, true);
|
||||||
|
|
||||||
|
// don't set the spell to unknown until after the server has sent the single remove packets
|
||||||
|
buffs[slot].spellid = SPELL_UNKNOWN;
|
||||||
ClientPatch::SendFullBuffRefresh(this);
|
ClientPatch::SendFullBuffRefresh(this);
|
||||||
|
|
||||||
// we will eventually call CalcBonuses() even if we skip it right here, so should correct itself if we still have them
|
// we will eventually call CalcBonuses() even if we skip it right here, so should correct itself if we still have them
|
||||||
|
|||||||
@@ -3720,6 +3720,7 @@ int Mob::AddBuff(Mob *caster, int32 spell_id, int duration, int32 level_override
|
|||||||
memset(buffs[emptyslot].caster_name, 0, 64);
|
memset(buffs[emptyslot].caster_name, 0, 64);
|
||||||
buffs[emptyslot].casterid = caster ? caster->GetID() : 0;
|
buffs[emptyslot].casterid = caster ? caster->GetID() : 0;
|
||||||
buffs[emptyslot].ticsremaining = duration;
|
buffs[emptyslot].ticsremaining = duration;
|
||||||
|
buffs[emptyslot].initialduration = duration;
|
||||||
buffs[emptyslot].counters = CalculateCounters(spell_id);
|
buffs[emptyslot].counters = CalculateCounters(spell_id);
|
||||||
buffs[emptyslot].hit_number = spells[spell_id].hit_number;
|
buffs[emptyslot].hit_number = spells[spell_id].hit_number;
|
||||||
buffs[emptyslot].client = caster ? caster->IsClient() : 0;
|
buffs[emptyslot].client = caster ? caster->IsClient() : 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user