From af53598fa2d7d63021f54a4a2bd37449f31e97cf Mon Sep 17 00:00:00 2001 From: Meltie2013 Date: Fri, 11 Dec 2020 08:23:09 -0600 Subject: [PATCH] fix(Core/Game): Rest & Inn Improvements (#3780) --- src/server/game/Entities/Object/Object.cpp | 13 +-- src/server/game/Entities/Player/Player.cpp | 92 ++++++++++++--------- src/server/game/Entities/Player/Player.h | 12 +++ src/server/game/Handlers/MiscHandler.cpp | 2 +- src/server/shared/DataStores/DBCStructure.h | 10 --- 5 files changed, 73 insertions(+), 56 deletions(-) diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 9faccd8cc..2a4ca7de4 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -1335,7 +1335,7 @@ bool Position::IsWithinBox(const Position& center, float xradius, float yradius, // is-in-cube check and we have to calculate only one point instead of 4 // 2PI = 360*, keep in mind that ingame orientation is counter-clockwise - double rotation = 2 * M_PI - center.GetOrientation(); + double rotation = 2 * M_PI - GetOrientation(); double sinVal = std::sin(rotation); double cosVal = std::cos(rotation); @@ -1347,13 +1347,14 @@ bool Position::IsWithinBox(const Position& center, float xradius, float yradius, // box edges are parallel to coordiante axis, so we can treat every dimension independently :D float dz = GetPositionZ() - center.GetPositionZ(); - float dx = rotX - center.GetPositionX(); - float dy = rotY - center.GetPositionY(); + float dx = rotX - GetPositionX(); + float dy = rotY - GetPositionY(); if ((std::fabs(dx) > xradius) || - (std::fabs(dy) > yradius) || - (std::fabs(dz) > zradius)) + (std::fabs(dy) > yradius) || + (std::fabs(dz) > zradius)) + { return false; - + } return true; } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index f0eaa0be8..d828db13b 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -82,7 +82,8 @@ #include "LuaEngine.h" #endif -#define ZONE_UPDATE_INTERVAL (2*IN_MILLISECONDS) +// Zone Interval should be 1 second +#define ZONE_UPDATE_INTERVAL (1*IN_MILLISECONDS) #define PLAYER_SKILL_INDEX(x) (PLAYER_SKILL_INFO_1_1 + ((x)*3)) #define PLAYER_SKILL_VALUE_INDEX(x) (PLAYER_SKILL_INDEX(x)+1) @@ -824,6 +825,7 @@ Player::Player(WorldSession* session): Unit(true), m_mover(this) _restTime = 0; _innTriggerId = 0; _restBonus = 0; + _restFlagMask = 0; ////////////////////Rest System///////////////////// m_mailsUpdated = false; @@ -1776,6 +1778,14 @@ void Player::Update(uint32 p_time) { if (p_time >= m_zoneUpdateTimer) { + // On zone update tick check if we are still in an inn if we are supposed to be in one + if (HasRestFlag(REST_FLAG_IN_TAVERN)) + { + AreaTrigger const* atEntry = sObjectMgr->GetAreaTrigger(GetInnTriggerId()); + if (!atEntry || !IsInAreaTriggerRadius(atEntry)) + RemoveRestFlag(REST_FLAG_IN_TAVERN); + } + uint32 newzone, newarea; GetZoneAndAreaId(newzone, newarea, true); m_last_zone_id = newzone; @@ -3023,20 +3033,22 @@ void Player::SetInWater(bool apply) bool Player::IsInAreaTriggerRadius(const AreaTrigger* trigger) const { + static const float delta = 5.0f; + if (!trigger || GetMapId() != trigger->map) return false; - if (trigger->radius > 0.f) + if (trigger->radius > 0) { // if we have radius check it float dist = GetDistance(trigger->x, trigger->y, trigger->z); - if (dist > trigger->radius) + if (dist > trigger->radius + delta) return false; } else { - Position center = {trigger->x, trigger->y, trigger->z, trigger->orientation}; - if (!IsWithinBox(center, trigger->length / 2.f, trigger->width / 2.f, trigger->height / 2.f)) + Position center(trigger->x, trigger->y, trigger->z, trigger->orientation); + if (IsWithinBox(center, trigger->length / 2 + delta, trigger->width / 2 + delta, trigger->height / 2 + delta)) return false; } @@ -7673,27 +7685,7 @@ void Player::UpdateArea(uint32 newArea) UpdateAreaDependentAuras(newArea); pvpInfo.IsInNoPvPArea = false; - if (!area) - { - RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY); - RemoveRestState(); - return; - } - - // Xinef: area should inherit zone flags - AreaTableEntry const* zone = sAreaTableStore.LookupEntry(area->zone); - uint32 areaFlags = area->flags; - bool isSanctuary = area->IsSanctuary(); - bool isInn = area->IsInn(GetTeamId(true)); - if (zone) - { - areaFlags |= zone->flags; - isSanctuary |= zone->IsSanctuary(); - isInn |= zone->IsInn(GetTeamId(true)); - } - - // previously this was in UpdateZone (but after UpdateArea) so nothing will break - if (isSanctuary) // in sanctuary + if (area && area->IsSanctuary()) { SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY); pvpInfo.IsInNoPvPArea = true; @@ -7702,18 +7694,11 @@ void Player::UpdateArea(uint32 newArea) else RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY); - if (isInn) - { - SetRestState(0); - if (sWorld->IsFFAPvPRealm()) - RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); - } - else if (!(areaFlags & AREA_FLAG_CAPITAL)) - { - AreaTrigger const* atEntry = sObjectMgr->GetAreaTrigger(GetInnTriggerId()); - if (!atEntry || !IsInAreaTriggerRadius(atEntry)) - RemoveRestState(); - } + uint32 const areaRestFlag = (GetTeamId(true) == TEAM_ALLIANCE) ? AREA_FLAG_REST_ZONE_ALLIANCE : AREA_FLAG_REST_ZONE_HORDE; + if (area && area->flags & areaRestFlag) + SetRestFlag(REST_FLAG_IN_FACTION_AREA); + else + RemoveRestFlag(REST_FLAG_IN_FACTION_AREA); } uint32 Player::GetZoneId(bool forceRecalc) const @@ -7809,10 +7794,12 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) if (zone->flags & AREA_FLAG_CAPITAL) // Is in a capital city { if (!pvpInfo.IsHostile || zone->IsSanctuary()) - SetRestState(0); + SetRestFlag(REST_FLAG_IN_CITY); pvpInfo.IsInNoPvPArea = true; } + else + RemoveRestFlag(REST_FLAG_IN_CITY); // Recently left a capital city UpdatePvPState(); @@ -27855,3 +27842,30 @@ bool Player::HasHealSpec() } std::unordered_map Player::bgZoneIdToFillWorldStates = {}; + +void Player::SetRestFlag(RestFlag restFlag, uint32 triggerId /*= 0*/) +{ + uint32 oldRestMask = _restFlagMask; + _restFlagMask |= restFlag; + + if (!oldRestMask && _restFlagMask) // only set flag/time on the first rest state + { + _restTime = time(nullptr); + SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING); + } + + if (triggerId) + _innTriggerId = triggerId; +} + +void Player::RemoveRestFlag(RestFlag restFlag) +{ + uint32 oldRestMask = _restFlagMask; + _restFlagMask &= ~restFlag; + + if (oldRestMask && !_restFlagMask) // only remove flag/time on the last rest state remove + { + _restTime = 0; + RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING); + } +} diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 24f8a7f60..837d1a8f8 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -766,6 +766,13 @@ enum ArenaTeamInfoType class InstanceSave; +enum RestFlag +{ + REST_FLAG_IN_TAVERN = 0x1, + REST_FLAG_IN_CITY = 0x2, + REST_FLAG_IN_FACTION_AREA = 0x4, // used with AREA_FLAG_REST_ZONE_* +}; + enum TeleportToOptions { TELE_TO_GM_MODE = 0x01, @@ -1251,6 +1258,10 @@ public: uint32 GetXPRestBonus(uint32 xp); [[nodiscard]] float GetRestBonus() const { return _restBonus; } void SetRestBonus(float rest_bonus_new); + + bool HasRestFlag(RestFlag restFlag) const { return (_restFlagMask & restFlag) != 0; } + void SetRestFlag(RestFlag restFlag, uint32 triggerId = 0); + void RemoveRestFlag(RestFlag restFlag); [[nodiscard]] uint32 GetInnTriggerId() const { return _innTriggerId; } [[nodiscard]] Pet* GetPet() const; @@ -2901,6 +2912,7 @@ protected: time_t _restTime; uint32 _innTriggerId; float _restBonus; + uint32 _restFlagMask; ////////////////////Rest System///////////////////// uint32 m_resetTalentsCost; time_t m_resetTalentsTime; diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 472ae3a50..f5154df99 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -766,7 +766,7 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recv_data) if (sObjectMgr->IsTavernAreaTrigger(triggerId)) { // set resting flag we are in the inn - player->SetRestState(atEntry->entry); + player->SetRestFlag(REST_FLAG_IN_TAVERN, atEntry->entry); if (sWorld->IsFFAPvPRealm()) player->RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); diff --git a/src/server/shared/DataStores/DBCStructure.h b/src/server/shared/DataStores/DBCStructure.h index ca9758e2b..90718c04f 100644 --- a/src/server/shared/DataStores/DBCStructure.h +++ b/src/server/shared/DataStores/DBCStructure.h @@ -522,16 +522,6 @@ struct AreaTableEntry return true; return (flags & AREA_FLAG_SANCTUARY); } - - // Xinef: mark some zones / areas as inns - [[nodiscard]] bool IsInn(TeamId teamId) const - { - if (teamId == TEAM_ALLIANCE) - return flags & AREA_FLAG_REST_ZONE_ALLIANCE; - else if (teamId == TEAM_HORDE) - return flags & AREA_FLAG_REST_ZONE_HORDE; - return false; - } }; #define MAX_GROUP_AREA_IDS 6