Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp
- index f81063b..32f30d1 100644
- --- a/src/game/GameObject.cpp
- +++ b/src/game/GameObject.cpp
- @@ -61,7 +61,6 @@ GameObject::GameObject() : WorldObject(),
- m_captureTicks = (float)CAPTURE_SLIDER_NEUTRAL;
- m_captureState = CAPTURE_STATE_NEUTRAL;
- m_ownerFaction = TEAM_NONE;
- - m_progressFaction = TEAM_NONE;
- m_cooldownTime = 0;
- m_packedRotation = 0;
- @@ -209,44 +208,7 @@ void GameObject::Update(uint32 update_diff, uint32 diff)
- {
- if (m_captureTime < diff)
- {
- - GameObjectInfo const* info = this->GetGOInfo();
- - if (!info)
- - return;
- -
- - float radius = info->capturePoint.radius;
- - if (!radius)
- - return;
- -
- - // search for players in radius
- - std::list<Player*> pointPlayers;
- -
- - MaNGOS::AnyPlayerInObjectRangeCheck u_check(this, radius);
- - MaNGOS::PlayerListSearcher<MaNGOS::AnyPlayerInObjectRangeCheck> checker(pointPlayers, u_check);
- - Cell::VisitWorldObjects(this, checker, radius);
- -
- - // refill the player sets at every tick
- - m_capturePlayers[BG_TEAM_ALLIANCE].clear();
- - m_capturePlayers[BG_TEAM_HORDE].clear();
- -
- - for (std::list<Player*>::iterator itr = pointPlayers.begin(); itr != pointPlayers.end(); ++itr)
- - {
- - if (!(*itr)->IsWorldPvPActive()) // TODO: Should stealthed/invisible/flying players also get quest objective complete if team member wins tower?
- - continue;
- -
- - if (((Player*)(*itr))->GetTeam() == ALLIANCE)
- - m_capturePlayers[BG_TEAM_ALLIANCE].insert((*itr));
- - else if (((Player*)(*itr))->GetTeam() == HORDE)
- - m_capturePlayers[BG_TEAM_HORDE].insert((*itr));
- - }
- -
- - // return if there are not enough players capturing the point
- - if (m_capturePlayers[BG_TEAM_ALLIANCE].size() - m_capturePlayers[BG_TEAM_HORDE].size() == 0)
- - return;
- -
- - // if conditions are ok, then use the button
- - // further checks and calculations will be done in the use function
- - Use((*(pointPlayers.begin()))); // TODO: We actually now dont need player pointer in the Use() function of capture points
- -
- + ProcessCapturePoint();
- m_captureTime = 1000;
- }
- else
- @@ -1627,204 +1589,6 @@ void GameObject::Use(Unit* user)
- }
- break;
- }
- - case GAMEOBJECT_TYPE_CAPTURE_POINT: // 29
- - {
- - // Code here is not even halfway complete, and only added for further development.
- - // Computer may very well blow up after stealing your bank accounts and wreck your car.
- - // Use() object at own risk.
- -
- - // the main ideea is that every use increases or decreases a counter
- - // the slider can be updated by ticks
- - // then we can check for the transition events (when counter = a value, trigger a certain event)
- -
- - // Can we expect that only player object are able to trigger a capture point or
- - // ToDo- research: could dummy creatures be involved?
- -
- - //if (user->GetTypeId() != TYPEID_PLAYER)
- - // return;
- -
- - GameObjectInfo const* info = GetGOInfo();
- - if (!info)
- - return;
- -
- - // if the capture point is locked return
- - if (sWorldPvPMgr.GetCapturePointLockState(GetEntry()))
- - return;
- -
- - // calculate the number of players which are actually capturing the point
- - uint32 rangePlayers;
- - if (m_capturePlayers[BG_TEAM_ALLIANCE].size() > m_capturePlayers[BG_TEAM_HORDE].size())
- - {
- - m_progressFaction = ALLIANCE;
- - rangePlayers = m_capturePlayers[BG_TEAM_ALLIANCE].size() - m_capturePlayers[BG_TEAM_HORDE].size();
- - }
- - else
- - {
- - m_progressFaction = HORDE;
- - rangePlayers = m_capturePlayers[BG_TEAM_HORDE].size() - m_capturePlayers[BG_TEAM_ALLIANCE].size();
- - }
- -
- - uint32 maxSuperiority = info->capturePoint.maxSuperiority;
- - uint32 neutralPercent = info->capturePoint.neutralPercent;
- - uint32 oldTicks = m_captureTicks;
- -
- - // cap speed
- - if (rangePlayers > maxSuperiority)
- - rangePlayers = maxSuperiority;
- -
- - // time to capture from 0% to 100% is minTime for maxSuperiority amount of players and maxTime for minSuperiority amount of players
- - float diffTicks = 200.0f /
- - (float)((maxSuperiority - rangePlayers) * (info->capturePoint.maxTime - info->capturePoint.minTime) /
- - (float)(maxSuperiority - info->capturePoint.minSuperiority) + info->capturePoint.minTime);
- -
- - if (m_progressFaction == ALLIANCE)
- - {
- - m_captureTicks += diffTicks;
- - if (m_captureTicks > CAPTURE_SLIDER_ALLIANCE)
- - m_captureTicks = CAPTURE_SLIDER_ALLIANCE;
- - }
- - else
- - {
- - m_captureTicks -= diffTicks;
- - if (m_captureTicks < CAPTURE_SLIDER_HORDE)
- - m_captureTicks = CAPTURE_SLIDER_HORDE;
- - }
- -
- - // send world state if integer of capture ticks change
- - if (m_captureTicks != (float)oldTicks)
- - for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team)
- - for (PlayerSet::iterator itr = m_capturePlayers[team].begin(); itr != m_capturePlayers[team].end(); ++itr)
- - {
- - (*itr)->SendUpdateWorldState(info->capturePoint.worldState1, 1);
- - (*itr)->SendUpdateWorldState(info->capturePoint.worldState2, (uint32)m_captureTicks);
- - (*itr)->SendUpdateWorldState(info->capturePoint.worldState3, neutralPercent);
- - }
- -
- - // store the ticks value
- - sWorldPvPMgr.SetCapturePointSlider(GetEntry(), m_captureTicks);
- -
- - // ID1 vs ID2 are possibly related to team. The world states should probably
- - // control which event to be used. For this to work, we need a far better system for
- - // sWorldStateMgr (system to store and keep track of states) so that we at all times
- - // know the state of every part of the world.
- -
- - // Call every event, which is obviously wrong, but can help in further development. For
- - // the time being script side can process events and determine which one to use. It
- - // require of course that some object call go->Use()
- - // win event can happen when a faction captures the tower with the slider at max range
- -
- - uint32 eventId = 0;
- -
- - // win event alliance
- - // alliance wins tower with max points
- - if ((uint32)m_captureTicks == CAPTURE_SLIDER_ALLIANCE && m_captureState == CAPTURE_STATE_PROGRESS)
- - {
- - if (info->capturePoint.winEventID1)
- - eventId = info->capturePoint.winEventID1;
- -
- - m_captureState = CAPTURE_STATE_WIN;
- - }
- - // win event horde
- - // horde wins a tower with max points
- - else if ((uint32)m_captureTicks == CAPTURE_SLIDER_HORDE && m_captureState == CAPTURE_STATE_PROGRESS)
- - {
- - if (info->capturePoint.winEventID2)
- - eventId = info->capturePoint.winEventID2;
- -
- - m_captureState = CAPTURE_STATE_WIN;
- - }
- -
- - // contest event can happen when a player succeeds in attacking a tower which belongs to the opposite faction; owner doesn't change
- -
- - // contest event alliance
- - // horde attack tower which is in progress or is won by alliance
- - else if (m_ownerFaction == ALLIANCE && m_progressFaction == HORDE && m_captureState != CAPTURE_STATE_CONTEST && (m_captureState == CAPTURE_STATE_PROGRESS || m_captureState == CAPTURE_STATE_WIN))
- - {
- - if (info->capturePoint.contestedEventID1)
- - eventId = info->capturePoint.contestedEventID1;
- -
- - m_captureState = CAPTURE_STATE_CONTEST;
- - }
- - // contest event horde
- - // alliance attack tower which is in progress or is won by horde
- - else if (m_ownerFaction == HORDE && m_progressFaction == ALLIANCE && m_captureState != CAPTURE_STATE_CONTEST && (m_captureState == CAPTURE_STATE_PROGRESS || m_captureState == CAPTURE_STATE_WIN))
- - {
- - if (info->capturePoint.contestedEventID2)
- - eventId = info->capturePoint.contestedEventID2;
- -
- - m_captureState = CAPTURE_STATE_CONTEST;
- - }
- -
- - // the progress event can be achieved when a faction passes on its color on the slider or retakes the tower from a contested state
- -
- - // progress event alliance
- - // alliance takes the tower from neutral to alliance OR alliance takes the tower from contested to allaince
- - else if ((uint32)m_captureTicks == CAPTURE_SLIDER_NEUTRAL + neutralPercent * 0.5f + 1 && ((m_captureState == CAPTURE_STATE_NEUTRAL && m_progressFaction == ALLIANCE) || (m_captureState == CAPTURE_STATE_CONTEST && m_progressFaction == ALLIANCE)))
- - {
- - if (info->capturePoint.progressEventID1)
- - eventId = info->capturePoint.progressEventID1;
- -
- - // handle objective complete
- - if (m_captureState != CAPTURE_STATE_CONTEST)
- - sWorldPvPMgr.HandleObjectiveComplete(m_capturePlayers[BG_TEAM_ALLIANCE], info->capturePoint.progressEventID1);
- -
- - // set capture state to alliance
- - m_captureState = CAPTURE_STATE_PROGRESS;
- - m_ownerFaction = ALLIANCE;
- - }
- - // progress event horde
- - // horde takes the tower from neutral to horde OR horde takes the tower from contested to horde
- - else if ((uint32)m_captureTicks == CAPTURE_SLIDER_NEUTRAL - neutralPercent * 0.5f - 1 && ((m_captureState == CAPTURE_STATE_NEUTRAL && m_progressFaction == HORDE) || (m_captureState == CAPTURE_STATE_CONTEST && m_progressFaction == HORDE)))
- - {
- - if (info->capturePoint.progressEventID2)
- - eventId = info->capturePoint.progressEventID2;
- -
- - // handle objective complete
- - if (m_captureState != CAPTURE_STATE_CONTEST)
- - sWorldPvPMgr.HandleObjectiveComplete(m_capturePlayers[BG_TEAM_HORDE], info->capturePoint.progressEventID2);
- -
- - // set capture state to horde
- - m_captureState = CAPTURE_STATE_PROGRESS;
- - m_ownerFaction = HORDE;
- - }
- -
- - // neutral event can happen when one faction takes the tower from the opposite faction and makes it neutral
- -
- - // neutral event alliance
- - // horde takes the tower from alliance to neutral
- - else if ((uint32)m_captureTicks == CAPTURE_SLIDER_NEUTRAL + neutralPercent * 0.5f && m_captureState == CAPTURE_STATE_CONTEST && m_progressFaction == HORDE)
- - {
- - if (info->capturePoint.neutralEventID1)
- - eventId = info->capturePoint.neutralEventID1;
- -
- - m_captureState = CAPTURE_STATE_NEUTRAL;
- - m_ownerFaction = TEAM_NONE;
- - }
- - // neutral event horde
- - // alliance takes the tower from horde to neutral
- - else if ((uint32)m_captureTicks == CAPTURE_SLIDER_NEUTRAL - neutralPercent * 0.5f && m_captureState == CAPTURE_STATE_CONTEST && m_progressFaction == ALLIANCE)
- - {
- - if (info->capturePoint.neutralEventID2)
- - eventId = info->capturePoint.neutralEventID2;
- -
- - m_captureState = CAPTURE_STATE_NEUTRAL;
- - m_ownerFaction = TEAM_NONE;
- - }
- -
- - if (eventId)
- - {
- - // send zone script
- - if (m_zoneScript)
- - m_zoneScript->ProcessEvent(this, eventId, m_progressFaction);
- - // if zone script fails send to ScriptMgr
- - // TODO: WHY?
- - //else if (!sScriptMgr.OnProcessEvent(eventId, user, this, true))
- - // GetMap()->ScriptsStart(sEventScripts, eventId, user, this);
- - }
- -
- - // Some has spell, need to process those further.
- - return;
- - }
- case GAMEOBJECT_TYPE_BARBER_CHAIR: // 32
- {
- GameObjectInfo const* info = GetGOInfo();
- @@ -1869,6 +1633,219 @@ void GameObject::Use(Unit* user)
- spell->prepare(&targets);
- }
- +void GameObject::ProcessCapturePoint()
- +{
- + GameObjectInfo const* info = this->GetGOInfo();
- + if (!info)
- + return;
- +
- + float radius = info->capturePoint.radius;
- + if (!radius)
- + return;
- +
- + // search for players in radius
- + std::list<Player*> pointPlayers;
- +
- + MaNGOS::AnyPlayerInObjectRangeCheck u_check(this, radius);
- + MaNGOS::PlayerListSearcher<MaNGOS::AnyPlayerInObjectRangeCheck> checker(pointPlayers, u_check);
- + Cell::VisitWorldObjects(this, checker, radius);
- +
- + PlayersSet m_capturePlayers[BG_TEAMS_COUNT]; // player sets for each faction // TODO: Use generic enum
- + for (std::list<Player*>::iterator itr = pointPlayers.begin(); itr != pointPlayers.end(); ++itr)
- + {
- + if (!(*itr)->IsWorldPvPActive()) // TODO: Should stealthed/invisible/flying players also get quest objective complete if team member wins tower?
- + continue;
- +
- + if (((Player*)(*itr))->GetTeam() == ALLIANCE)
- + m_capturePlayers[BG_TEAM_ALLIANCE].insert((*itr));
- + else if (((Player*)(*itr))->GetTeam() == HORDE)
- + m_capturePlayers[BG_TEAM_HORDE].insert((*itr));
- + }
- +
- + // return if there are not enough players capturing the point
- + if (m_capturePlayers[BG_TEAM_ALLIANCE].size() - m_capturePlayers[BG_TEAM_HORDE].size() == 0)
- + return;
- +
- + // if the capture point is locked return
- + if (sWorldPvPMgr.GetCapturePointLockState(GetEntry()))
- + return;
- +
- + uint32 rangePlayers;
- + uint32 progressFaction; // faction which has the most players in range of a capture point
- +
- + // calculate the number of players which are actually capturing the point
- + if (m_capturePlayers[BG_TEAM_ALLIANCE].size() > m_capturePlayers[BG_TEAM_HORDE].size())
- + {
- + progressFaction = ALLIANCE;
- + rangePlayers = m_capturePlayers[BG_TEAM_ALLIANCE].size() - m_capturePlayers[BG_TEAM_HORDE].size();
- + }
- + else
- + {
- + progressFaction = HORDE;
- + rangePlayers = m_capturePlayers[BG_TEAM_HORDE].size() - m_capturePlayers[BG_TEAM_ALLIANCE].size();
- + }
- +
- + uint32 maxSuperiority = info->capturePoint.maxSuperiority;
- + uint32 neutralPercent = info->capturePoint.neutralPercent;
- + uint32 oldTicks = m_captureTicks;
- +
- + // cap speed
- + if (rangePlayers > maxSuperiority)
- + rangePlayers = maxSuperiority;
- +
- + // time to capture from 0% to 100% is minTime for maxSuperiority amount of players and maxTime for minSuperiority amount of players
- + float diffTicks = 200.0f /
- + (float)((maxSuperiority - rangePlayers) * (info->capturePoint.maxTime - info->capturePoint.minTime) /
- + (float)(maxSuperiority - info->capturePoint.minSuperiority) + info->capturePoint.minTime);
- +
- + if (progressFaction == ALLIANCE)
- + {
- + m_captureTicks += diffTicks;
- + if (m_captureTicks > CAPTURE_SLIDER_ALLIANCE)
- + m_captureTicks = CAPTURE_SLIDER_ALLIANCE;
- + }
- + else
- + {
- + m_captureTicks -= diffTicks;
- + if (m_captureTicks < CAPTURE_SLIDER_HORDE)
- + m_captureTicks = CAPTURE_SLIDER_HORDE;
- + }
- +
- + // send world state if integer of capture ticks change
- + if (m_captureTicks != (float)oldTicks)
- + for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team)
- + for (PlayerSet::iterator itr = m_capturePlayers[team].begin(); itr != m_capturePlayers[team].end(); ++itr)
- + {
- + (*itr)->SendUpdateWorldState(info->capturePoint.worldState1, 1);
- + (*itr)->SendUpdateWorldState(info->capturePoint.worldState2, (uint32)m_captureTicks);
- + (*itr)->SendUpdateWorldState(info->capturePoint.worldState3, neutralPercent);
- + }
- +
- + // store the ticks value
- + sWorldPvPMgr.SetCapturePointSlider(GetEntry(), m_captureTicks);
- +
- + // ID1 vs ID2 are possibly related to team. The world states should probably
- + // control which event to be used. For this to work, we need a far better system for
- + // sWorldStateMgr (system to store and keep track of states) so that we at all times
- + // know the state of every part of the world.
- +
- + // Call every event, which is obviously wrong, but can help in further development. For
- + // the time being script side can process events and determine which one to use. It
- + // require of course that some object call go->Use()
- + // win event can happen when a faction captures the tower with the slider at max range
- +
- + uint32 eventId = 0;
- +
- + // win event alliance
- + // alliance wins tower with max points
- + if ((uint32)m_captureTicks == CAPTURE_SLIDER_ALLIANCE && m_captureState == CAPTURE_STATE_PROGRESS)
- + {
- + if (info->capturePoint.winEventID1)
- + eventId = info->capturePoint.winEventID1;
- +
- + m_captureState = CAPTURE_STATE_WIN;
- + }
- + // win event horde
- + // horde wins a tower with max points
- + else if ((uint32)m_captureTicks == CAPTURE_SLIDER_HORDE && m_captureState == CAPTURE_STATE_PROGRESS)
- + {
- + if (info->capturePoint.winEventID2)
- + eventId = info->capturePoint.winEventID2;
- +
- + m_captureState = CAPTURE_STATE_WIN;
- + }
- +
- + // contest event can happen when a player succeeds in attacking a tower which belongs to the opposite faction; owner doesn't change
- +
- + // contest event alliance
- + // horde attack tower which is in progress or is won by alliance
- + else if (m_ownerFaction == ALLIANCE && progressFaction == HORDE && m_captureState != CAPTURE_STATE_CONTEST && (m_captureState == CAPTURE_STATE_PROGRESS || m_captureState == CAPTURE_STATE_WIN))
- + {
- + if (info->capturePoint.contestedEventID1)
- + eventId = info->capturePoint.contestedEventID1;
- +
- + m_captureState = CAPTURE_STATE_CONTEST;
- + }
- + // contest event horde
- + // alliance attack tower which is in progress or is won by horde
- + else if (m_ownerFaction == HORDE && progressFaction == ALLIANCE && m_captureState != CAPTURE_STATE_CONTEST && (m_captureState == CAPTURE_STATE_PROGRESS || m_captureState == CAPTURE_STATE_WIN))
- + {
- + if (info->capturePoint.contestedEventID2)
- + eventId = info->capturePoint.contestedEventID2;
- +
- + m_captureState = CAPTURE_STATE_CONTEST;
- + }
- +
- + // the progress event can be achieved when a faction passes on its color on the slider or retakes the tower from a contested state
- +
- + // progress event alliance
- + // alliance takes the tower from neutral to alliance OR alliance takes the tower from contested to allaince
- + else if ((uint32)m_captureTicks == CAPTURE_SLIDER_NEUTRAL + neutralPercent * 0.5f + 1 && ((m_captureState == CAPTURE_STATE_NEUTRAL && progressFaction == ALLIANCE) || (m_captureState == CAPTURE_STATE_CONTEST && progressFaction == ALLIANCE)))
- + {
- + if (info->capturePoint.progressEventID1)
- + eventId = info->capturePoint.progressEventID1;
- +
- + // handle objective complete
- + if (m_captureState != CAPTURE_STATE_CONTEST)
- + sWorldPvPMgr.HandleObjectiveComplete(m_capturePlayers[BG_TEAM_ALLIANCE], info->capturePoint.progressEventID1);
- +
- + // set capture state to alliance
- + m_captureState = CAPTURE_STATE_PROGRESS;
- + m_ownerFaction = ALLIANCE;
- + }
- + // progress event horde
- + // horde takes the tower from neutral to horde OR horde takes the tower from contested to horde
- + else if ((uint32)m_captureTicks == CAPTURE_SLIDER_NEUTRAL - neutralPercent * 0.5f - 1 && ((m_captureState == CAPTURE_STATE_NEUTRAL && progressFaction == HORDE) || (m_captureState == CAPTURE_STATE_CONTEST && progressFaction == HORDE)))
- + {
- + if (info->capturePoint.progressEventID2)
- + eventId = info->capturePoint.progressEventID2;
- +
- + // handle objective complete
- + if (m_captureState != CAPTURE_STATE_CONTEST)
- + sWorldPvPMgr.HandleObjectiveComplete(m_capturePlayers[BG_TEAM_HORDE], info->capturePoint.progressEventID2);
- +
- + // set capture state to horde
- + m_captureState = CAPTURE_STATE_PROGRESS;
- + m_ownerFaction = HORDE;
- + }
- +
- + // neutral event can happen when one faction takes the tower from the opposite faction and makes it neutral
- +
- + // neutral event alliance
- + // horde takes the tower from alliance to neutral
- + else if ((uint32)m_captureTicks == CAPTURE_SLIDER_NEUTRAL + neutralPercent * 0.5f && m_captureState == CAPTURE_STATE_CONTEST && progressFaction == HORDE)
- + {
- + if (info->capturePoint.neutralEventID1)
- + eventId = info->capturePoint.neutralEventID1;
- +
- + m_captureState = CAPTURE_STATE_NEUTRAL;
- + m_ownerFaction = TEAM_NONE;
- + }
- + // neutral event horde
- + // alliance takes the tower from horde to neutral
- + else if ((uint32)m_captureTicks == CAPTURE_SLIDER_NEUTRAL - neutralPercent * 0.5f && m_captureState == CAPTURE_STATE_CONTEST && progressFaction == ALLIANCE)
- + {
- + if (info->capturePoint.neutralEventID2)
- + eventId = info->capturePoint.neutralEventID2;
- +
- + m_captureState = CAPTURE_STATE_NEUTRAL;
- + m_ownerFaction = TEAM_NONE;
- + }
- +
- + if (eventId)
- + {
- + // send zone script
- + if (m_zoneScript)
- + m_zoneScript->ProcessEvent(this, eventId, progressFaction);
- + // if zone script fails send to ScriptMgr
- + // TODO: WHY?
- + //else if (!sScriptMgr.OnProcessEvent(eventId, user, this, true))
- + // GetMap()->ScriptsStart(sEventScripts, eventId, user, this);
- + }
- +
- + // Some has spell, need to process those further.
- +}
- +
- // overwrite WorldObject function for proper name localization
- const char* GameObject::GetNameForLocaleIdx(int32 loc_idx) const
- {
- diff --git a/src/game/GameObject.h b/src/game/GameObject.h
- index 0ba2d2f..8cfc27f 100644
- --- a/src/game/GameObject.h
- +++ b/src/game/GameObject.h
- @@ -715,6 +715,7 @@ class MANGOS_DLL_SPEC GameObject : public WorldObject
- float GetObjectBoundingRadius() const; // overwrite WorldObject version
- void Use(Unit* user);
- + void ProcessCapturePoint();
- LootState getLootState() const { return m_lootState; }
- void SetLootState(LootState s) { m_lootState = s; }
- @@ -765,7 +766,6 @@ class MANGOS_DLL_SPEC GameObject : public WorldObject
- uint32 m_captureTime;
- float m_captureTicks;
- CapturePointState m_captureState;
- - uint32 m_progressFaction; // faction which has the most players in range of a capture point
- uint32 m_ownerFaction; // faction which has conquered the capture point
- uint32 m_spellId;
- time_t m_respawnTime; // (secs) time of next respawn (or despawn if GO have owner()),
- @@ -778,8 +778,6 @@ class MANGOS_DLL_SPEC GameObject : public WorldObject
- typedef std::set<ObjectGuid> GuidsSet;
- typedef std::set<Player*> PlayersSet;
- - PlayersSet m_capturePlayers[BG_TEAMS_COUNT]; // player sets for each faction // TODO: Use generic enum
- -
- GuidsSet m_SkillupSet; // players that already have skill-up at GO use
- uint32 m_useTimes; // amount uses/charges triggered
Add Comment
Please, Sign In to add comment