feat(Core/PvP): Set 30 sec timer before turn off FFA PvP flag. (#5090)

This commit is contained in:
UltraNix
2021-04-08 13:00:45 +02:00
committed by GitHub
parent 143fad42c7
commit 54e371e0e7
5 changed files with 109 additions and 45 deletions

View File

@@ -1617,6 +1617,7 @@ void Player::Update(uint32 p_time)
time_t now = time(nullptr);
UpdatePvPFlag(now);
UpdateFFAPvPFlag(now);
UpdateContestedPvP(p_time);
@@ -7730,28 +7731,8 @@ void Player::UpdateArea(uint32 newArea)
m_areaUpdateId = newArea;
AreaTableEntry const* area = sAreaTableStore.LookupEntry(newArea);
bool oldFFAPvPArea = pvpInfo.IsInFFAPvPArea;
pvpInfo.IsInFFAPvPArea = area && (area->flags & AREA_FLAG_ARENA);
UpdatePvPState(true);
// xinef: check if we were in ffa arena and we left
if (oldFFAPvPArea && !pvpInfo.IsInFFAPvPArea)
{
// xinef: iterate attackers
AttackerSet toRemove;
AttackerSet const& attackers = getAttackers();
for (AttackerSet::const_iterator itr = attackers.begin(); itr != attackers.end(); ++itr)
if (!(*itr)->IsValidAttackTarget(this))
toRemove.insert(*itr);
for (AttackerSet::const_iterator itr = toRemove.begin(); itr != toRemove.end(); ++itr)
(*itr)->AttackStop();
// xinef: remove our own victim
if (Unit* victim = GetVictim())
if (!IsValidAttackTarget(victim))
AttackStop();
}
UpdateFFAPvPState(false);
UpdateAreaDependentAuras(newArea);
@@ -21158,18 +21139,50 @@ void Player::UpdatePvPFlag(time_t currTime)
{
if (!IsPvP())
return;
if (pvpInfo.EndTimer == 0 || pvpInfo.IsHostile)
return;
if (currTime < (pvpInfo.EndTimer + 300 + 5))
{
if (currTime > (pvpInfo.EndTimer + 4) && !HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_PVP_TIMER))
SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_PVP_TIMER);
return;
}
UpdatePvP(false);
}
void Player::UpdateFFAPvPFlag(time_t currTime)
{
if (!IsFFAPvP() || sWorld->IsFFAPvPRealm() || !pvpInfo.FFAPvPEndTimer || currTime < pvpInfo.FFAPvPEndTimer + 30)
{
return;
}
pvpInfo.FFAPvPEndTimer = time_t(0);
RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
for (ControlSet::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
(*itr)->RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
// xinef: iterate attackers
AttackerSet toRemove;
AttackerSet const& attackers = getAttackers();
for (AttackerSet::const_iterator itr = attackers.begin(); itr != attackers.end(); ++itr)
if (!(*itr)->IsValidAttackTarget(this))
toRemove.insert(*itr);
for (AttackerSet::const_iterator itr = toRemove.begin(); itr != toRemove.end(); ++itr)
(*itr)->AttackStop();
// xinef: remove our own victim
if (Unit* victim = GetVictim())
if (!IsValidAttackTarget(victim))
AttackStop();
}
void Player::UpdateDuelFlag(time_t currTime)
{
if (!duel || duel->startTimer == 0 || currTime < duel->startTimer + 3)
@@ -22747,29 +22760,9 @@ void Player::UpdateHomebindTime(uint32 time)
}
}
void Player::UpdatePvPState(bool onlyFFA)
void Player::UpdatePvPState()
{
// TODO: should we always synchronize UNIT_FIELD_BYTES_2, 1 of controller and controlled?
// no, we shouldn't, those are checked for affecting player by client
if (!pvpInfo.IsInNoPvPArea && !IsGameMaster()
&& (pvpInfo.IsInFFAPvPArea || sWorld->IsFFAPvPRealm()))
{
if (!IsFFAPvP())
{
SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
for (ControlSet::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
(*itr)->SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
}
}
else if (IsFFAPvP())
{
RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
for (ControlSet::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
(*itr)->RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
}
if (onlyFFA)
return;
UpdateFFAPvPState();
if (pvpInfo.IsHostile) // in hostile area
{
@@ -22783,6 +22776,63 @@ void Player::UpdatePvPState(bool onlyFFA)
}
}
void Player::UpdateFFAPvPState(bool reset /*= true*/)
{
// TODO: should we always synchronize UNIT_FIELD_BYTES_2, 1 of controller and controlled?
// no, we shouldn't, those are checked for affecting player by client
if (!pvpInfo.IsInNoPvPArea && !IsGameMaster() && (pvpInfo.IsInFFAPvPArea || sWorld->IsFFAPvPRealm()))
{
if (!IsFFAPvP())
{
SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
for (ControlSet::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
(*itr)->SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
}
if (pvpInfo.IsInFFAPvPArea)
{
pvpInfo.FFAPvPEndTimer = time_t(0);
}
}
else if (IsFFAPvP())
{
if ((pvpInfo.IsInNoPvPArea || IsGameMaster()) || reset || !pvpInfo.EndTimer)
{
pvpInfo.FFAPvPEndTimer = time_t(0);
RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
for (ControlSet::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
(*itr)->RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
// xinef: iterate attackers
AttackerSet toRemove;
AttackerSet const& attackers = getAttackers();
for (AttackerSet::const_iterator itr = attackers.begin(); itr != attackers.end(); ++itr)
if (!(*itr)->IsValidAttackTarget(this))
toRemove.insert(*itr);
for (AttackerSet::const_iterator itr = toRemove.begin(); itr != toRemove.end(); ++itr)
(*itr)->AttackStop();
// xinef: remove our own victim
if (Unit* victim = GetVictim())
if (!IsValidAttackTarget(victim))
AttackStop();
}
else
{
// Not in FFA PvP Area
// Not FFA PvP realm
// Not FFA PvP timer already set
// Being recently in PvP combat
if (!pvpInfo.IsInFFAPvPArea && !sWorld->IsFFAPvPRealm() && !pvpInfo.FFAPvPEndTimer)
{
pvpInfo.FFAPvPEndTimer = sWorld->GetGameTime() + sWorld->getIntConfig(CONFIG_FFA_PVP_TIMER);
}
}
}
}
void Player::UpdatePvP(bool state, bool _override)
{
if (!state || _override)
@@ -22795,6 +22845,7 @@ void Player::UpdatePvP(bool state, bool _override)
pvpInfo.EndTimer = time(nullptr);
SetPvP(state);
}
RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_PVP_TIMER);
}

View File

@@ -309,7 +309,8 @@ struct PvPInfo
bool IsInHostileArea{false}; ///> Marks if player is in an area which forces PvP flag
bool IsInNoPvPArea{false}; ///> Marks if player is in a sanctuary or friendly capital city
bool IsInFFAPvPArea{false}; ///> Marks if player is in an FFAPvP area (such as Gurubashi Arena)
time_t EndTimer{0}; ///> Time when player unflags himself for PvP (flag removed after 5 minutes)
time_t EndTimer{0}; ///> Time when player unflags himself for PvP (flag removed after 5 minutes)
time_t FFAPvPEndTimer{0}; ///> Time when player unflags himself for FFA PvP (flag removed after 30 sec)
};
struct DuelInfo
@@ -1843,7 +1844,8 @@ public:
bool IsActionButtonDataValid(uint8 button, uint32 action, uint8 type);
PvPInfo pvpInfo;
void UpdatePvPState(bool onlyFFA = false);
void UpdatePvPState();
void UpdateFFAPvPState(bool reset = true);
void SetPvP(bool state)
{
Unit::SetPvP(state);
@@ -1864,6 +1866,7 @@ public:
void UpdateAfkReport(time_t currTime);
void UpdatePvPFlag(time_t currTime);
void UpdateFFAPvPFlag(time_t currTime);
void UpdateContestedPvP(uint32 currTime);
void SetContestedPvPTimer(uint32 newTime) {m_contestedPvPTimer = newTime;}
void ResetContestedPvP()

View File

@@ -378,6 +378,7 @@ enum WorldIntConfigs
CONFIG_TOGGLE_XP_COST,
CONFIG_NPC_EVADE_IF_NOT_REACHABLE,
CONFIG_NPC_REGEN_TIME_IF_NOT_REACHABLE_IN_RAID,
CONFIG_FFA_PVP_TIMER,
INT_CONFIG_VALUE_COUNT
};

View File

@@ -1240,6 +1240,8 @@ void World::LoadConfigSettings(bool reload)
m_int_configs[CONFIG_ITEMDELETE_QUALITY] = sConfigMgr->GetOption<int32>("ItemDelete.Quality", 3);
m_int_configs[CONFIG_ITEMDELETE_ITEM_LEVEL] = sConfigMgr->GetOption<int32>("ItemDelete.ItemLevel", 80);
m_int_configs[CONFIG_FFA_PVP_TIMER] = sConfigMgr->GetOption<int32>("FFAPvPTimer", 30);
///- Read the "Data" directory from the config file
std::string dataPath = sConfigMgr->GetOption<std::string>("DataDir", "./");
if (dataPath.empty() || (dataPath.at(dataPath.length() - 1) != '/' && dataPath.at(dataPath.length() - 1) != '\\'))

View File

@@ -3680,6 +3680,13 @@ ICC.Buff.Alliance = 73828
Item.SetItemTradeable = 1
#
# FFAPvPTimer
# Description: Specify time offset when player unset FFAPvP flag when leaving FFAPvP area. (e.g. Gurubashi Arena)
# Default: 30 sec
FFAPvPTimer = 30
#
###################################################################################################