/*
Thor Server Project
Copyright 2008 Joe Hegarty
This file is part of The Thor Server Project.
The Thor Server Project is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
The Thor Server Project 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with The Thor Server Project. If not, see .
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Timers;
using System.Threading;
using ThorServer.Game.Furni;
using ThorServer.Core;
using ThorServer.Utilities;
using ThorServer.Game.Rooms;
using ThorServer.Game.Rooms.Pathfinding;
namespace ThorServer.Game.Rooms.Interactor
{
public partial class RoomInteractor
{
private void HandleUserMovements()
{
Dictionary.Enumerator myEnum = mRoomInstance.Users.GetEnumerator();
while (myEnum.MoveNext())
{
RoomUser user = myEnum.Current.Value;
user.UserLocked = true;
if (user.IsMoving)
{
if (user.Path.Count > 0)
{
WorkBestTile(user);
PathFinderNode nextNode = user.Path[0];
bool specialOcassion = (nextNode.X == user.TargetX && nextNode.Y == user.TargetY && InteractiveTile(nextNode.X, nextNode.Y) && PlayerCheck(nextNode.X, nextNode.Y) == false);
bool isOveride = user.AllowOveride && PlayerCheck(nextNode.X, nextNode.Y) == false;
user.AllowOveride = false;
if (TileCheck(nextNode.X, nextNode.Y, mMatrix) || specialOcassion || isOveride)
{
doPlayerUpdate(user, nextNode);
}
else
{
bool playerBlock = PlayerCheck(nextNode.X, nextNode.Y);
byte tmpByte = 1;
if (playerBlock) { tmpByte = mMatrix[nextNode.X, nextNode.Y]; mMatrix[nextNode.X, nextNode.Y] = 0; }
List route = WorkPath(user.SessionID, user.TargetX, user.TargetY, false);
if (playerBlock) mMatrix[nextNode.X, nextNode.Y] = tmpByte;
if (route != null)
{
if(TileCheck(route[0].X, route[0].Y, mMatrix))
{
user.Path = route;
doPlayerUpdate(user, route[0]);
}
else
{
user.IsMoving = false;
mRoomInstance.AnnounceUserStatus(user.SessionID, true);
}
}
else
{
user.IsMoving = false;
mRoomInstance.AnnounceUserStatus(user.SessionID, true);
}
}
}
else
{
//End of journey!
user.IsMoving = false;
CalculateTileStatusForUser(user.CurrentX, user.CurrentY, user, false);
mRoomInstance.AnnounceUserStatus(user.SessionID, true);
}
}
else
{
mRoomInstance.AnnounceUserStatus(user.SessionID, false);
}
user.UserLocked = false;
}
}
private void WorkBestTile(RoomUser user)
{
if (user.Path.Count > 1)
{
PathFinderNode skipNode = user.Path[1];
if (TilesTouching(user.CurrentX, user.CurrentY, skipNode.X, skipNode.Y))
{
if (TileCheck(skipNode.X, skipNode.Y, mMatrix))
{
int checkX1 = 0;
int checkX2 = 0;
if (skipNode.X > user.CurrentX)
{
checkX1 = -1;
checkX2 = 1;
}
else
{
checkX1 = 1;
checkX2 = -1;
}
if (TileCheck(skipNode.X + checkX1, skipNode.Y, mMatrix) && TileCheck(user.CurrentX + checkX2, user.CurrentY, mMatrix))
{
PathFinderNode nextNode = user.Path[0];
user.Path.Remove(nextNode);
}
}
}
}
}
private void doPlayerUpdate(RoomUser user, PathFinderNode nextNode)
{
user.NextX = nextNode.X;
user.NextY = nextNode.Y;
user.NextZ = mHeightMap[user.NextX, user.NextY];
user.Path.Remove(nextNode);
mPlayerMap[user.CurrentX, user.CurrentY] = false;
mPlayerMap[user.NextX, user.NextY] = true;
int newDirection = SpecialMath.WorkDirection(user.CurrentX, user.CurrentY, user.NextX, user.NextY);
user.HeadDirection = newDirection;
user.BodyDirection = newDirection;
mRoomInstance.AnnounceUserStatus(user.SessionID, true);
user.CurrentX = user.NextX;
user.CurrentY = user.NextY;
user.CurrentZ = user.NextZ;
}
public void RequestMovePlayer(long sessionId, int NewX, int NewY, List route, bool Override)
{
new DoMovePlayerDelegate(DoMovePlayer).BeginInvoke(sessionId, NewX, NewY, route, Override, null, null);
}
private delegate void DoMovePlayerDelegate(long sessionId, int NewX, int NewY, List route, bool Override);
public void DoMovePlayer(long sessionId, int NewX, int NewY, List route, bool Override)
{
NewX = mRedirectMap[NewX, NewY].X;
NewY = mRedirectMap[NewX, NewY].Y;
RoomUser user = mRoomInstance.GetUser(sessionId);
if (!user.UserLocked || Override)
{
if (route == null) route = WorkPath(sessionId, NewX, NewY, Override);
if (route != null)
{
RemoveTileStatus(user, user.CurrentX, user.CurrentY);
user.TargetX = NewX;
user.TargetY = NewY;
user.Path = route;
user.IsMoving = true;
}
}
}
private List WorkPath(long sessionId, int NewX, int NewY, bool Overide)
{
bool specialOccassion = (InteractiveTile(NewX, NewY) && PlayerCheck(NewX, NewY) == false) || Overide;
if (TileCheck(NewX, NewY, mMatrix) == true || specialOccassion)
{
RoomUser user = mRoomInstance.GetUser(sessionId);
byte tmpByte = mMatrix[NewX, NewY];
mMatrix[NewX, NewY] = 1;
List route = CalculatePath(user.CurrentX, user.CurrentY, NewX, NewY, mMatrix);
mMatrix[NewX, NewY] = tmpByte;
return route;
}
return null;
}
private void UpdateChangedUsers(int x, int y)
{
RoomUser user = mRoomInstance.GetUser(x, y);
if (user != null)
{
CalculateTileStatusForUser(x, y, user, false);
}
}
private void CalculateTileStatusForUser(int X, int Y, RoomUser user, bool isRoller)
{
mRoomInstance.RemoveUniqueStatus(user.SessionID, "sit");
mRoomInstance.RemoveUniqueStatus(user.SessionID, "lay");
List objects = GetFurniObjects(X, Y);
if (objects != null)
{
foreach (FurniInfo info in objects)
{
if (info.Flags.NeverBlocked)
{
mPlayerMap[X, Y] = false;
}
if (info.Flags.CanSit)
{
user.HeadDirection = info.PosRotation;
user.BodyDirection = info.PosRotation;
user.CurrentZ = info.PosZ;
if (!user.SpecialStates.ContainsKey("sit"))
{
user.SpecialStates.Add("sit", new RoomUser.RoomUserStatus("sit", false, info.ActionHeight.ToString().Replace(',', '.'), 0, 0, 0, null, true));
}
mRoomInstance.RemoveUniqueStatuses(user.SessionID, "carryd");
}
else if (info.Flags.CanLay)
{
user.CurrentZ = info.PosZ;
user.HeadDirection = info.PosRotation;
user.BodyDirection = info.PosRotation;
if (isRoller) user.CurrentZ = mHeightMap[user.CurrentX, user.CurrentY];
if (!user.SpecialStates.ContainsKey("lay"))
{
user.SpecialStates.Add("lay", new RoomUser.RoomUserStatus("lay", false, info.ActionHeight.ToString().Replace(',', '.'), 0, 0, 0, "", true));
}
mRoomInstance.RemoveUniqueStatuses(user.SessionID, "");
}
else if (info.Flags.PoolChange)
{
user.UserLocked = true;
ClientMessage message = new ClientMessage();
message.Init(96); //A`
mRoomInstance.SendMessage(message, user.SessionID);
message.Init(71); //AG
message.appendString(info.FurniVar);
message.appendString(" ");
message.appendString("close");
mRoomInstance.RoomBroadcast(message);
//Block the curtain position
int tmpX = int.Parse(info.WallLocation.Split(',')[0]);
int tmpY = int.Parse(info.WallLocation.Split(',')[1]);
mPlayerMap[tmpX, tmpY] = true;
}
else if (info.Flags.PoolEnter)
{
if (user.UserInfo.sPoolFigure != "")
{
mRoomInstance.RemoveUniqueStatuses(user.SessionID, "");
int tmpX = int.Parse(info.WallLocation.Split(',')[0]);
int tmpY = int.Parse(info.WallLocation.Split(',')[1]);
user.CurrentX = tmpX;
user.CurrentY = tmpY;
user.CurrentZ = mHeightMap[tmpX, tmpY];
user.IsMoving = false;
if (!user.SpecialStates.ContainsKey("swim"))
{
user.SpecialStates.Add("swim", new RoomUser.RoomUserStatus("swim", true, "", 0, 0, 0, null, true));
}
ClientMessage message = new ClientMessage();
message.Init(71); //AG
message.appendString(info.FurniVar);
message.appendString(" ");
message.appendString("enter");
mRoomInstance.RoomBroadcast(message);
mRoomInstance.AnnounceUserStatus(user.SessionID, true);
}
}
else if (info.Flags.PoolExit)
{
mRoomInstance.RemoveUniqueStatuses(user.SessionID, "");
int tmpX = int.Parse(info.WallLocation.Split(',')[0]);
int tmpY = int.Parse(info.WallLocation.Split(',')[1]);
user.CurrentX = tmpX;
user.CurrentY = tmpY;
user.CurrentZ = mHeightMap[tmpX, tmpY];
user.IsMoving = false;
ClientMessage message = new ClientMessage();
message.Init(71); //AG
message.appendString(info.FurniVar);
message.appendString(" ");
message.appendString("exit");
mRoomInstance.RoomBroadcast(message);
mRoomInstance.AnnounceUserStatus(user.SessionID, true);
}
}
}
else
{
mRoomInstance.RemoveUniqueStatuses(user.SessionID, "carryd,dance,swim");
}
}
public void RemoveTileStatus(RoomUser user, int X, int Y)
{
mRoomInstance.RemoveUniqueStatus(user.SessionID, "sit");
mRoomInstance.RemoveUniqueStatus(user.SessionID, "lay");
List objects = GetFurniObjects(X, Y);
if (objects != null)
{
foreach (FurniInfo info in objects)
{
if (info.Flags.PoolChange)
{
ClientMessage message = new ClientMessage();
message.Init(71); //AG
message.appendString(info.FurniVar);
message.appendString(" ");
message.appendString("open");
mRoomInstance.RoomBroadcast(message);
//Unblock the curtain position
int tmpX = int.Parse(info.WallLocation.Split(',')[0]);
int tmpY = int.Parse(info.WallLocation.Split(',')[1]);
mPlayerMap[tmpX, tmpY] = false;
}
if (info.Flags.CanSit || info.Flags.CanLay)
{
user.CurrentZ = mHeightMap[info.PosX, info.PosY];
}
}
}
}
private List CalculatePath(int StartX, int StartY, int EndX, int EndY, byte[,] Matrix)
{
PathFinder pathFinder = new PathFinder(Matrix);
pathFinder.Heightmap = mHeightMap;
pathFinder.MaxAscend = mRoomInstance.RoomInfo.MaxAscend;
pathFinder.MaxDescend = mRoomInstance.RoomInfo.MaxDescend;
Point Start = new Point(StartX, StartY);
Point End = new Point(EndX, EndY);
List result = pathFinder.FindPath(Start, End);
if (result != null)
{
//This is the current tile, we don't need this
result.Remove(result[0]);
}
return result;
}
}
}