/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
#include "PhaseShift.h"
#include "Containers.h"
bool PhaseShift::AddPhase(uint32 phaseId, PhaseFlags flags, std::vector const* areaConditions, int32 references /*= 1*/)
{
auto insertResult = Phases.emplace(phaseId, flags, nullptr);
ModifyPhasesReferences(insertResult.first, references);
if (areaConditions)
insertResult.first->AreaConditions = areaConditions;
return insertResult.second;
}
PhaseShift::EraseResult PhaseShift::RemovePhase(uint32 phaseId)
{
auto itr = Phases.find(PhaseRef(phaseId, PhaseFlags::None, nullptr));
if (itr != Phases.end())
{
ModifyPhasesReferences(itr, -1);
if (!itr->References)
return { Phases.erase(itr), true };
return { itr, false };
}
return { Phases.end(), false };
}
bool PhaseShift::AddVisibleMapId(uint32 visibleMapId, TerrainSwapInfo const* visibleMapInfo, int32 references /*= 1*/)
{
auto insertResult = VisibleMapIds.emplace(visibleMapId, VisibleMapIdRef{ 0, visibleMapInfo });
insertResult.first->second.References += references;
return insertResult.second;
}
PhaseShift::EraseResult PhaseShift::RemoveVisibleMapId(uint32 visibleMapId)
{
auto itr = VisibleMapIds.find(visibleMapId);
if (itr != VisibleMapIds.end())
{
if (!--itr->second.References)
return { VisibleMapIds.erase(itr), true };
return { itr, false };
}
return { VisibleMapIds.end(), false };
}
bool PhaseShift::AddUiMapPhaseId(uint32 uiMapPhaseId, int32 references /*= 1*/)
{
auto insertResult = UiMapPhaseIds.emplace(uiMapPhaseId, UiMapPhaseIdRef{ 0 });
insertResult.first->second.References += references;
return insertResult.second;
}
PhaseShift::EraseResult PhaseShift::RemoveUiMapPhaseId(uint32 uiMapPhaseId)
{
auto itr = UiMapPhaseIds.find(uiMapPhaseId);
if (itr != UiMapPhaseIds.end())
{
if (!--itr->second.References)
return { UiMapPhaseIds.erase(itr), true };
return { itr, false };
}
return { UiMapPhaseIds.end(), false };
}
void PhaseShift::Clear()
{
ClearPhases();
PersonalGuid.Clear();
VisibleMapIds.clear();
UiMapPhaseIds.clear();
}
void PhaseShift::ClearPhases()
{
Flags &= EnumClassFlag(PhaseShiftFlags::AlwaysVisible) | PhaseShiftFlags::Inverse;
Phases.clear();
NonCosmeticReferences = 0;
CosmeticReferences = 0;
DefaultReferences = 0;
UpdateUnphasedFlag();
}
bool PhaseShift::CanSee(PhaseShift const& other) const
{
if (Flags.HasFlag(PhaseShiftFlags::Unphased) && other.Flags.HasFlag(PhaseShiftFlags::Unphased))
return true;
if (Flags.HasFlag(PhaseShiftFlags::AlwaysVisible) || other.Flags.HasFlag(PhaseShiftFlags::AlwaysVisible))
return true;
if (Flags.HasFlag(PhaseShiftFlags::Inverse) && other.Flags.HasFlag(PhaseShiftFlags::Inverse))
return true;
PhaseFlags excludePhasesWithFlag = PhaseFlags::None;
if (Flags.HasFlag(PhaseShiftFlags::NoCosmetic) && other.Flags.HasFlag(PhaseShiftFlags::NoCosmetic))
excludePhasesWithFlag = PhaseFlags::Cosmetic;
if (!Flags.HasFlag(PhaseShiftFlags::Inverse) && !other.Flags.HasFlag(PhaseShiftFlags::Inverse))
{
ObjectGuid ownerGuid = PersonalGuid;
ObjectGuid otherPersonalGuid = other.PersonalGuid;
return Trinity::Containers::Intersects(Phases.begin(), Phases.end(), other.Phases.begin(), other.Phases.end(),
[&ownerGuid, &otherPersonalGuid, excludePhasesWithFlag](PhaseRef const& myPhase, PhaseRef const& /*otherPhase*/)
{
return !myPhase.Flags.HasFlag(excludePhasesWithFlag) && (!myPhase.Flags.HasFlag(PhaseFlags::Personal) || ownerGuid == otherPersonalGuid);
});
}
auto checkInversePhaseShift = [excludePhasesWithFlag](PhaseShift const& phaseShift, PhaseShift const& excludedPhaseShift)
{
if (phaseShift.Flags.HasFlag(PhaseShiftFlags::Unphased) && !excludedPhaseShift.Flags.HasFlag(PhaseShiftFlags::InverseUnphased))
return true;
for (auto itr = phaseShift.Phases.begin(); itr != phaseShift.Phases.end(); ++itr)
{
if (itr->Flags.HasFlag(excludePhasesWithFlag))
continue;
auto itr2 = std::find(excludedPhaseShift.Phases.begin(), excludedPhaseShift.Phases.end(), *itr);
if (itr2 == excludedPhaseShift.Phases.end() || itr2->Flags.HasFlag(excludePhasesWithFlag))
return true;
}
return false;
};
if (other.Flags.HasFlag(PhaseShiftFlags::Inverse))
return checkInversePhaseShift(*this, other);
return checkInversePhaseShift(other, *this);
}
void PhaseShift::ModifyPhasesReferences(PhaseContainer::iterator itr, int32 references)
{
itr->References += references;
if (!IsDbPhaseShift)
{
if (itr->Flags.HasFlag(PhaseFlags::Cosmetic))
CosmeticReferences += references;
else if (itr->Id != DEFAULT_PHASE)
NonCosmeticReferences += references;
else
DefaultReferences += references;
if (CosmeticReferences)
Flags |= PhaseShiftFlags::NoCosmetic;
else
Flags &= ~EnumClassFlag(PhaseShiftFlags::NoCosmetic);
UpdateUnphasedFlag();
}
}
void PhaseShift::UpdateUnphasedFlag()
{
EnumClassFlag unphasedFlag = !Flags.HasFlag(PhaseShiftFlags::Inverse) ? PhaseShiftFlags::Unphased : PhaseShiftFlags::InverseUnphased;
Flags &= ~EnumClassFlag(!Flags.HasFlag(PhaseShiftFlags::Inverse) ? PhaseShiftFlags::InverseUnphased : PhaseShiftFlags::Unphased);
if (NonCosmeticReferences && !DefaultReferences)
Flags &= ~unphasedFlag;
else
Flags |= unphasedFlag;
}