diff --git a/zone/aura.cpp b/zone/aura.cpp index add3e25d9..326ff8974 100644 --- a/zone/aura.cpp +++ b/zone/aura.cpp @@ -61,6 +61,11 @@ void Aura::ProcessOnAllFriendlies(Mob *owner) Shout("Stub 1"); } +Mob *Aura::GetOwner() +{ + return entity_list.GetMob(m_owner); +} + void Aura::ProcessOnAllGroupMembers(Mob *owner) { auto &mob_list = entity_list.GetMobList(); // read only reference so we can do it all inline @@ -260,12 +265,63 @@ void Aura::ProcessOnGroupMembersPets(Mob *owner) void Aura::ProcessTotem(Mob *owner) { - Shout("Stub 4"); + auto &mob_list = entity_list.GetMobList(); // read only reference so we can do it all inline + std::set delayed_remove; + bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter + + for (auto &e : mob_list) { + auto mob = e.second; + if (mob == this) + continue; + if (owner->IsAttackAllowed(mob)) { // might need more checks ... + bool in_range = DistanceSquared(GetPosition(), mob->GetPosition()) <= distance; + auto it = casted_on.find(mob->GetID()); + if (it != casted_on.end()) { + if (!in_range) + delayed_remove.insert(mob->GetID()); + } else if (in_range) { + casted_on.insert(mob->GetID()); + SpellFinished(spell_id, mob); + } + } + } + + for (auto &e : delayed_remove) { + auto mob = entity_list.GetMob(e); + if (mob != nullptr && is_buff) // some auras cast instant spells so no need to remove + mob->BuffFadeBySpellIDAndCaster(spell_id, GetID()); + casted_on.erase(e); + } + + // so if we have a cast timer and our set isn't empty and timer is disabled we need to enable it + if (cast_timer.GetDuration() > 0 && !cast_timer.Enabled() && !casted_on.empty()) + cast_timer.Start(); + + if (!cast_timer.Enabled() || !cast_timer.Check()) + return; + + for (auto &e : casted_on) { + auto mob = entity_list.GetMob(e); + if (mob != nullptr) + SpellFinished(spell_id, mob); + } } void Aura::ProcessEnterTrap(Mob *owner) { - Shout("Stub 5"); + auto &mob_list = entity_list.GetMobList(); // read only reference so we can do it all inline + + for (auto &e : mob_list) { + auto mob = e.second; + if (mob == this) + continue; + // might need more checks ... + if (owner->IsAttackAllowed(mob) && DistanceSquared(GetPosition(), mob->GetPosition()) <= distance) { + SpellFinished(spell_id, mob); + Depop(); // if we're a buff (ex. NEC) we don't want to strip :P + break; + } + } } void Aura::ProcessExitTrap(Mob *owner) @@ -303,7 +359,14 @@ bool Aura::Process() void Aura::Depop(bool unused) { - // TODO: clean up buffs + if (IsBuffSpell(spell_id)) { + for (auto &e : casted_on) { + auto mob = entity_list.GetMob(e); + if (mob != nullptr) + mob->BuffFadeBySpellIDAndCaster(spell_id, GetID()); + } + } + casted_on.clear(); p_depop = true; } diff --git a/zone/aura.h b/zone/aura.h index cdc01be55..8d467d945 100644 --- a/zone/aura.h +++ b/zone/aura.h @@ -48,6 +48,7 @@ public: bool IsAura() const { return true; } bool Process(); void Depop(bool unused = false); + Mob *GetOwner(); void ProcessOnAllFriendlies(Mob *owner); void ProcessOnAllGroupMembers(Mob *owner);