using System; using System.Collections.Generic; using Mango.Players; using Mango.Rooms.Mapping; using Mango.Rooms.Avatar; using Mango.Communication.Packets.Outgoing.Room.Session; using Mango.Communication.Packets.Outgoing.Navigator; using Mango.Communication.Packets.Outgoing.Handshake; using Mango.Communication.Packets.Outgoing.Room.Engine; using Mango.Communication.Packets.Outgoing.Room.Action; using Mango.Communication.Packets.Outgoing.Room.Chat; using Mango.Communication.Packets.Outgoing; using Mango.Rooms.Mapping.PathFinding; using Mango.Chat.Emotions; using Mango.Items; using Mango.Communication.Packets.Incoming.Room.Engine; namespace Mango.Rooms { class RoomAvatar : RoomAvatarData { /// /// Reference to the current room this avatar is in (null if none) /// private volatile RoomInstance _currentRoom = null; /// /// Links data for username, figure, motto etc. /// private readonly IAvatarData _data; /// /// Authentication Checking /// private bool _authOk = false; /// /// Initialize new instance of the RoomAvatar linked to the player. /// /// Player. public RoomAvatar(Player Player) { if (Player == null) throw new NullReferenceException("Player cannot be null."); base._player = Player; this._data = Player; base._type = RoomAvatarType.Player; } /// /// Returns the AvatarData (mainly used for packets only) /// public IAvatarData Data { get { return this._data; } } public Player Player { get { if (this.Type != RoomAvatarType.Player) { throw new InvalidOperationException("Avatar is not linked to a Player."); } return this._player; } } public RoomInstance CurrentRoom { get { return this._currentRoom; } set { this._currentRoom = value; } } public RoomAvatarType Type { get { return this._type; } set { this._type = value; } } public Vector3D Position { get { return this._position; } set { this._position = value; } } public int HeadRotation { get { return this._headRotation; } set { this._headRotation = value; } } public int BodyRotation { get { return this._bodyRotation; } set { this._bodyRotation = value; } } public Dictionary Statusses { get { return this._statusses; } //set { this._statusses = value; } } public List Path { get { return this._path; } set { this._path = value; } } public List PathToSet { get { return this._pathToSet; } set { this._pathToSet = value; } } public Vector2D PositionToSet { get { return this._positionToSet; } set { this._positionToSet = value; } } public Vector2D Target { get { return this._target; } set { this._target = value; } } public bool UpdateNeeded { get { return this._updateNeeded; } set { this._updateNeeded = value; } } public int MoveToAndInteract { get { return this._moveToAndInteract; } set { this._moveToAndInteract = value; } } public int MoveToAndInteractData { get { return this._moveToAndInteract; } set { this._moveToAndInteractData = value; } } public bool FastWalking { get { return this._fastWalking; } set { this._fastWalking = value; } } public bool IsTeleporting { get { return this._isTeleporting; } set { this._isTeleporting = value; } } public int TeleporterTargetId { get { return this._teleporterTargetId; } set { this._teleporterTargetId = value; } } public int DanceId { get { return this._danceId; } set { this._danceId = value; } } public int CarryItemId { get { return this._carryItemId; } set { this._carryItemId = value; } } public int CarryItemTimer { get { return this._carryItemTimer; } set { this._carryItemTimer = value; } } public int EffectId { get { return this._effectId; } set { this._effectId = value; } } public bool EffectByItem { get { return this._effectByItem; } set { this._effectByItem = value; } } public int UserSetEffectId { get { return this._userSetEffectId; } set { this._userSetEffectId = value; } } public bool LeavingRoom { get { return this._leavingRoom; } set { this._leavingRoom = value; } } public bool ForcedLeave { get { return this._forcedLeave; } set { this._forcedLeave = value; } } public int LeaveStepsTaken { get { return this._leaveStepsTaken; } set { this._leaveStepsTaken = value; } } public bool Overriding { get { return this._overriding; } set { this._overriding = value; } } public bool WalkingDisabled { get { return this._walkingDisabled; } set { this._walkingDisabled = value; } } public int IdleTime { get { return this._idleTime; } set { this._idleTime = value; } } public bool Sleeping { get { return this._sleeping; } set { this._sleeping = value; } } public int ChatMessagesSent { get { return this._chatMessagesSent; } set { this._chatMessagesSent = value; } } public int ChatSpamTicks { get { return this._chatSpamTicks; } set { this._chatSpamTicks = value; } } public bool ForceSit { get { return this._forceSit; } set { this._forceSit = value; } } public int ApplySignId { get { return this._applySignId; } set { this._applySignId = value; } } public int SignApplyTicks { get { return this._signApplyTicks; } set { this._signApplyTicks = value; } } public bool InRoom { get { return (this.CurrentRoom != null); } } public int CurrentRoomId { get { return (this.CurrentRoom != null ? this.CurrentRoom.Id : 0); } } public Vector2D SquareInFront { get { if (!InRoom) { throw new InvalidOperationException("Invalid call to method, item is not in a room."); } Vector2D posNow = new Vector2D(this.Position.X, this.Position.Y); if (this.BodyRotation == 0) { posNow.Y--; } else if (this.BodyRotation == 2) { posNow.X++; } else if (this.BodyRotation == 4) { posNow.Y++; } else if (this.BodyRotation == 6) { posNow.X--; } return posNow; } } public Vector2D SquareBehind { get { if (!InRoom) { throw new InvalidOperationException("Invalid call to method, item is not in a room."); } Vector2D posNow = new Vector2D(this.Position.X, this.Position.Y); if (this.BodyRotation == 0) { posNow.Y++; } else if (this.BodyRotation == 2) { posNow.X--; } else if (this.BodyRotation == 4) { posNow.Y--; } else if (this.BodyRotation == 6) { posNow.X++; } return posNow; } } public bool HasStatus(string Key) { return this.Statusses.ContainsKey(Key); } public void RemoveStatus(string Key) { this.Statusses.Remove(Key); } public void SetStatus(string Key, string Value = "") { if (this.Statusses.ContainsKey(Key)) { this.Statusses[Key] = Value; } else { this.Statusses.Add(Key, Value); } } public bool IsMoving { get { return (this.Path.Count > 0); } } public bool AuthOK { get { return this._authOk; } set { this._authOk = value; } } /// /// Attempts to load the requested room. /// /// RoomId to load. /// Password input if required. /// Ignore any form of authing for rooms. public void PrepareRoom(int roomId, string password = "", bool ignoreAuth = false) { if (this.InRoom) { ExitRoom(false); } if (this.CurrentRoom != null) { Player.GetSession().SendPacket(new CloseConnectionComposer()); throw new InvalidOperationException("CurrentRoom still has a reference to a room."); } RoomInstance instance = null; if (!Mango.GetServer().GetRoomManager().TryLoadRoom(roomId, out instance)) { Player.GetSession().SendPacket(new CloseConnectionComposer()); return; } this.CurrentRoom = instance; if (instance.Model == null) { Player.GetSession().SendPacket(new CloseConnectionComposer()); return; // model is missing.. } // check if room max users is reached if (instance.UsersNow >= instance.MaxUsers && !Player.GetPermissions().HasRight("room_enter_full")) { Player.GetSession().SendPacket(new CantConnectComposer(1)); Player.GetSession().SendPacket(new CloseConnectionComposer()); return; } // check if user is banned from room if (instance.GetBans().IsBanned(Player.GetAvatar())) { Player.GetSession().SendPacket(new CantConnectComposer(4)); Player.GetSession().SendPacket(new CloseConnectionComposer()); return; } this.AuthOK = (ignoreAuth || instance.OwnerId == Player.Id || Player.GetPermissions().HasRight("room_enter_locked")); if (instance.Type == RoomType.FLAT) { Player.GetSession().SendPacket(new OpenConnectionComposer()); } if (!this.AuthOK) { if (instance.Access == RoomAccess.Password_Protected) { if (instance.Password != password) { Player.GetSession().SendPacket(new GenericErrorComposer(-100002)); Player.GetSession().SendPacket(new CloseConnectionComposer()); return; } } else if (instance.Access == RoomAccess.Locked) { if (instance.UsersNow > 0) { Player.GetSession().SendPacket(new DoorbellComposer(null)); instance.GetAvatars().BroadcastPacket(new DoorbellComposer(Player), true); return; } else { Player.GetSession().SendPacket(new FlatAccessDeniedComposer()); Player.GetSession().SendPacket(new CloseConnectionComposer()); //ExitRoom(); return; } } } this.AuthOK = true; if (!EnterRoom()) { Player.GetSession().SendPacket(new CloseConnectionComposer()); } } /// /// Finalizes the enter room stage. /// /// If entering was successful or not. public bool EnterRoom() { if (!this.AuthOK) { return false; } // URL? Player.GetSession().SendPacket(new RoomReadyComposer(CurrentRoom, CurrentRoom.Model)); if (CurrentRoom.Type == RoomType.FLAT) { Dictionary decorations = new Dictionary(CurrentRoom.Decorations); // concurrent shit foreach (KeyValuePair kvp in decorations) { Player.GetSession().SendPacket(new RoomPropertyComposer(kvp.Key, kvp.Value)); } Player.GetSession().SendPacket(new RoomRatingComposer(CurrentRoom.Score)); // need to handle room ratings // -1 = (not yet rated room) //Player.GetSession().SendPacket(new RoomEventComposer(CurrentRoom.Event)); } return true; } public void ExitRoom(bool SendKick = true) { if (!this.InRoom) { throw new InvalidOperationException("RoomAvatar is not in room."); } this.CurrentRoom.GetAvatars().RemoveAvatarFromRoom(this); this.ResetToDefaults(); this.CurrentRoom = null; if (SendKick) { Player.GetSession().SendPacket(new CloseConnectionComposer()); } this.Player.GetMessenger().SetUpdateNeeded(false); } public void Reset() // reset any values back to defaults { base.ResetToDefaults(); } public void LeaveRoom(bool Forced = false) { if (!this.InRoom) { throw new InvalidOperationException("RoomAvatar is not in room."); } MoveTo(new Vector2D(this.GetCurrentRoom().Model.DoorX, this.GetCurrentRoom().Model.DoorY)); this.LeavingRoom = true; this.ForcedLeave = Forced; } public void BlockWalking() { this.Path.Clear(); this.WalkingDisabled = true; } public void UnblockWalking() { this.WalkingDisabled = false; } public void MoveToAndInteractItem(Item Item, int RequestData, Vector2D MoveToPosition = null) { this.MoveToAndInteract = Item.Id; this.MoveToAndInteractData = RequestData; MoveTo(MoveToPosition == null ? Item.SquareInFront : MoveToPosition); } public void MoveTo(Vector2D Target, bool IgnoreCanInitiate = false, bool IgnoreRedirections = false, bool Overriding = false) { if (!this.InRoom) throw new InvalidOperationException("RoomAvatar is not in room."); UnIdle(); if (!this.GetCurrentRoom().GetMapping().IsValidPosition(Target)) { return; } if (!MangoStaticSettings.WalkUpToFurniOnClick) { if (this.GetCurrentRoom().GetMapping().IsTargetBlocked(Target)) { return; } } this.Overriding = Overriding; if (this.Overriding) { IgnoreCanInitiate = true; } if (!IgnoreRedirections) { Vector2D rt = this.GetCurrentRoom().GetMapping().GetRedirectedTarget(Target); Target.X = rt.X; Target.Y = rt.Y; } if ((Target.X == this.Position.X && Target.Y == this.Position.Y) || this.ForcedLeave || ((!IgnoreCanInitiate && !GetCurrentRoom().GetMapping().CanInitiateMoveToPosition(Target))) || (this.WalkingDisabled && !Overriding)) { return; } /*this.MoveToAndInteract = 0; this.MoveToAndInteractData = 0;*/ if (this.PositionToSet != null) { this.Position.X = this.PositionToSet.X; this.Position.Y = this.PositionToSet.Y; this.Position.Z = this.CurrentRoom.GetMapping().GetUserStepHeight(new Vector2D(this.PositionToSet.X, this.PositionToSet.Y)); this.PositionToSet = null; } this.ForceSit = false; this.Target = Target; this.PathToSet = PathFinder.FindPath(this.CurrentRoom.GetMapping(), this.Position.ToVector2D(), Target); } public void IncreaseIdleTime(bool IsOwner, bool Instant = false) { if (!this.InRoom) throw new InvalidOperationException("RoomAvatar is not in room."); if (Instant) { this.IdleTime = 600; } else { this.IdleTime++; } if (!this.Sleeping && this.IdleTime >= 600) { this.GetCurrentRoom().GetAvatars().BroadcastPacket(new SleepComposer(this, true)); this.Sleeping = true; } else if (!this.LeavingRoom && this.IdleTime >= 1800) { if (MangoStaticSettings.RoomOwnerNoAFKKick && !IsOwner) { return; } LeaveRoom(); return; } } /// /// Increases the CarryItem Timer. /// public void IncreaseCarryItemTimer() { if (this.CarryItemTimer > 0) { this.CarryItemTimer--; if (this.CarryItemTimer == 0) { CarryItem(0); } } } /// /// Handles the chat ticks to prevent chat spam. /// public void HandleChatSpamTicks() { if (this.ChatSpamTicks >= 0) { this.ChatSpamTicks--; if (this.ChatSpamTicks == -1) { this.ChatMessagesSent = 0; } } } /// /// Increases the AntiSpam Ticks as the user is typing. /// public void IncreaseAntiSpam() { if (!this.InRoom) { throw new InvalidOperationException("RoomAvatar is not in room."); } this.ChatMessagesSent++; if (this.ChatSpamTicks == -1) { this.ChatSpamTicks = 16; // divide it by 2 to get the real 'seconds' } else if (this.ChatMessagesSent >= 5) { this.Player.Mute(MangoStaticSettings.RoomFloodMuteTimeInSec); this.Player.GetSession().SendPacket(new FloodControlComposer(MangoStaticSettings.RoomFloodMuteTimeInSec)); } } public void UnIdle() { if (!this.InRoom) { throw new InvalidOperationException("RoomAvatar is not in room."); } this.IdleTime = 0; if (this.Sleeping) { this.GetCurrentRoom().GetAvatars().BroadcastPacket(new SleepComposer(this, false)); this.Sleeping = false; } } public void ApplySign(int SignId) { if (!this.InRoom) { throw new InvalidOperationException("RoomAvatar is not in room."); } UnIdle(); this._signApplyTicks = 0; this._applySignId = SignId; } public void Wave(int Action) { if (!this.InRoom) { throw new InvalidOperationException("RoomAvatar is not in room."); } if (this.DanceId > 0) // you stop dancing when you wave { this.DanceId = 0; } UnIdle(); this.GetCurrentRoom().GetAvatars().BroadcastPacket(new WaveComposer(this, Action)); if (Action == 5) { //this.GetCurrentRoom().GetAvatars().BroadcastPacket(new SleepComposer(this, true)); this.IncreaseIdleTime(false, true); } } public void Dance(int DanceId, bool Broadcast = true) { if (!this.InRoom) { throw new InvalidOperationException("RoomAvatar is not in room."); } if (this.DanceId == DanceId) { return; } UnIdle(); this.DanceId = DanceId; if (Broadcast) { this.GetCurrentRoom().GetAvatars().BroadcastPacket(new DanceComposer(this, DanceId)); } } public void CarryItem(int ItemId, bool Broadcast = true) { if (!this.InRoom) { throw new InvalidOperationException("RoomAvatar is not in room."); } UnIdle(); this.CarryItemId = ItemId; if (ItemId > 0) { this.CarryItemTimer = 90; } if (Broadcast) { this.GetCurrentRoom().GetAvatars().BroadcastPacket(new CarryObjectComposer(this, ItemId)); } } public void ApplyEffect(int EffectId, bool Brodcast = true, bool ByItem = false) { UnIdle(); if ((!ByItem && this._effectByItem) || EffectId == this._effectId) { return; } this._effectId = EffectId; this._effectByItem = (ByItem && EffectId > 0); if (Brodcast) { if (!this.InRoom) { throw new InvalidOperationException("Cannot broadcast when Avatar is not in a room."); } this.CurrentRoom.GetAvatars().BroadcastPacket(new AvatarEffectComposer(this, EffectId)); } } public void Chat(string Message, int Colour, bool OverrideRoomMute = false) { if (!this.InRoom) throw new InvalidOperationException("RoomAvatar is not in room."); if (this.Player.Muted) { return; } if (this.LeavingRoom && this.ForcedLeave) { return; } UnIdle(); if (Mango.GetServer().GetChatManager().GetCommands().Parse(Player.GetSession(), Message)) { return; } IncreaseAntiSpam(); this.GetCurrentRoom().GetAvatars().BroadcastPacket(new ChatComposer(this.Player, Message, Mango.GetServer().GetChatManager().GetEmotions().GetEmotionsForText(Message), Colour)); } public void Shout(string Message, int Colour, bool OverrideRoomMute = false) { if (!this.InRoom) throw new InvalidOperationException("RoomAvatar is not in room."); if (this.Player.Muted) { return; } if (this.LeavingRoom && this.ForcedLeave) { return; } UnIdle(); IncreaseAntiSpam(); this.GetCurrentRoom().GetAvatars().BroadcastPacket(new ShoutComposer(this.Player, Message, Mango.GetServer().GetChatManager().GetEmotions().GetEmotionsForText(Message), Colour)); } public void Whisper(string Message, string Username, int Colour, bool OverrideRoomMute = false) { if (!this.InRoom) throw new InvalidOperationException("RoomAvatar is not in room."); Player InteractingPlayer = null; if (!Mango.GetServer().GetPlayerManager().TryGet(Username, out InteractingPlayer)) { return; } if (this.Player.Muted) { return; } if (this.LeavingRoom && this.ForcedLeave) { return; } UnIdle(); IncreaseAntiSpam(); this.Player.GetSession().SendPacket(new WhisperComposer(this.Player, Message, 0, Colour)); InteractingPlayer.GetSession().SendPacket(new WhisperComposer(this.Player, Message, 0, Colour)); } public RoomInstance GetCurrentRoom() { return this.CurrentRoom; } } }