ROLLIN AROUND AT THE SPEED OF *TRANSPORT*

This commit is contained in:
SilicaAndPina 2020-10-20 01:05:32 +13:00
parent f3f59d26eb
commit f72cd3e9cb
13 changed files with 701 additions and 112 deletions

View file

@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Horse_Isle_Server
{
class Action
{
public enum ActivationMethod
{
MANUAL,
SHOVEL,
BINOCULARS,
MAGNIFYING_GLASS,
RAKE
}
public struct AltActivation
{
public ActivationMethod Method;
public int ActivationX;
public int ActivationY;
}
public struct Requirements
{
public bool Track;
public int MaxCompletions;
public int MoneyRequired;
public int[] CompletedRequired;
public int[] NotCompletedRequired;
public int RequiredAward;
}
public struct GameAction
{
public int Id;
public string Notes;
public string AdventurousTitle;
public string Difficulty;
public string Author;
public int[] ActionIdRequired;
AltActivation Activation;
}
}
}

View file

@ -155,6 +155,9 @@ namespace Horse_Isle_Server
case PacketBuilder.PACKET_KEEP_ALIVE:
Server.OnKeepAlive(this, Packet);
break;
case PacketBuilder.PACKET_TRANSPORT:
Server.OnTransportUsed(this, Packet);
break;
default:
Logger.ErrorPrint("Unimplemented Packet: " + BitConverter.ToString(Packet).Replace('-', ' '));
break;

View file

@ -129,6 +129,35 @@ namespace Horse_Isle_Server
Logger.DebugPrint("Registered Word Correction: " + correction.FilteredWord + " to "+correction.ReplacedWord);
}
// Register Transports
int totalTransportPoints = gameData.transport.transport_points.Count;
for (int i = 0; i < totalTransportPoints; i++)
{
Transport.TransportPoint transportPoint = new Transport.TransportPoint();
transportPoint.X = gameData.transport.transport_points[i].x;
transportPoint.Y = gameData.transport.transport_points[i].y;
transportPoint.Locations = gameData.transport.transport_points[i].places.ToObject<int[]>();
Transport.TransportPoints.Add(transportPoint);
Logger.DebugPrint("Registered Transport Point: At X: " + transportPoint.X + " Y: " + transportPoint.Y);
}
int totalTransportPlaces = gameData.transport.transport_places.Count;
for (int i = 0; i < totalTransportPlaces; i++)
{
Transport.TransportLocation transportPlace = new Transport.TransportLocation();
transportPlace.Id = gameData.transport.transport_places[i].id;
transportPlace.Cost = gameData.transport.transport_places[i].cost;
transportPlace.GotoX = gameData.transport.transport_places[i].goto_x;
transportPlace.GotoY = gameData.transport.transport_places[i].goto_y;
transportPlace.Type = gameData.transport.transport_places[i].type;
transportPlace.LocationTitle = gameData.transport.transport_places[i].place_title;
Transport.TransportLocations.Add(transportPlace);
Logger.DebugPrint("Registered Transport Location: "+ transportPlace.LocationTitle+" To Goto X: " + transportPlace.GotoX + " Y: " + transportPlace.GotoY);
}
// New Users
@ -182,6 +211,7 @@ namespace Horse_Isle_Server
Messages.AreaFormat = gameData.messages.meta.area_format;
Messages.Seperator = gameData.messages.meta.seperator;
Messages.TileFormat = gameData.messages.meta.tile_format;
Messages.TransportFormat = gameData.messages.meta.transport_format;
Messages.NothingMessage = gameData.messages.meta.nothing_message;
Messages.ExitThisPlace = gameData.messages.meta.exit_this_place;
Messages.MetaTerminator = gameData.messages.meta.end_of_meta;
@ -195,7 +225,6 @@ namespace Horse_Isle_Server
// Map Data
Map.OverlayTileDepth = gameData.tile_paramaters.overlay_tiles.tile_depth.ToObject<int[]>();
Map.OverlayTilesetPassibility = gameData.tile_paramaters.overlay_tiles.passibility.ToObject<bool[]>();
List<Map.TerrainTile> terrainTiles = new List<Map.TerrainTile>();
int totalTerrainTiles = gameData.tile_paramaters.terrain_tiles.Count;
@ -219,6 +248,11 @@ namespace Horse_Isle_Server
Server.IdleWarning = gameData.messages.disconnect.client_timeout.warn_after;
Server.IdleTimeout = gameData.messages.disconnect.client_timeout.kick_after;
// Swf
Messages.WagonCutscene = gameData.transport.wagon_cutscene;
Messages.BoatCutscene = gameData.transport.boat_cutscene;
Messages.BallonCutscene = gameData.transport.ballon_cutscene;
}
}

View file

@ -95,6 +95,7 @@
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Server.cs" />
<Compile Include="Transport.cs" />
<Compile Include="User.cs" />
<Compile Include="World.cs" />
</ItemGroup>

View file

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Horse_Isle_Server
{
class ItemObject
{
public int IconId;
public int Price;
public string ItemName;
public string ItemDescription;
public string ItemCategory;
}
}

View file

@ -19,7 +19,6 @@ namespace Horse_Isle_Server
public static int[] OverlayTileDepth;
public static TerrainTile[] TerrainTiles;
public static bool[] OverlayTilesetPassibility;
public static Bitmap MapData;

View file

@ -51,6 +51,7 @@ namespace Horse_Isle_Server
public static string TownFormat;
public static string AreaFormat;
public static string LocationFormat;
public static string TransportFormat;
public static string NearbyPlayers;
public static string North;
@ -68,11 +69,31 @@ namespace Horse_Isle_Server
public static string BanMessage;
public static string IdleKickMessageFormat;
// Swf
public static string BoatCutscene;
public static string WagonCutscene;
public static string BallonCutscene;
public static string FormatGlobalChatViolationMessage(Chat.Reason violationReason)
{
return ChatViolationMessageFormat.Replace("%AMOUNT%", RequiredChatViolations.ToString()).Replace("%REASON%", violationReason.Message);
}
// Meta
public static string FormatTransportMessage(string method, string place, int cost, int id, int x, int y)
{
byte[] xy = new byte[4];
xy[0] = (byte)(((x - 4) / 64) + 20);
xy[1] = (byte)(((x - 4) % 64) + 20);
xy[2] = (byte)(((y - 1) / 64) + 20);
xy[3] = (byte)(((y - 1) % 64) + 20);
int iconId = 253;
if(method == "WAGON")
iconId = 254;
return TransportFormat.Replace("%METHOD%", method).Replace("%PLACE%", place).Replace("%COST%", cost.ToString()).Replace("%ID%", id.ToString()).Replace("%ICON%",iconId.ToString()).Replace(" % XY%",Encoding.UTF8.GetString(xy));
}
// For all
public static string FormatGlobalChatMessage(string username, string message)
{

View file

@ -0,0 +1,138 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Horse_Isle_Server
{
class Meta
{
// Meta
private static string buildLocationString(int x, int y)
{
string locationString = "";
if (World.InArea(x, y))
locationString += Messages.AreaFormat.Replace("%AREA%", World.GetArea(x, y).Name);
if (World.InTown(x, y))
locationString += Messages.TownFormat.Replace("%TOWN%", World.GetTown(x, y).Name);
if (World.InIsle(x, y))
locationString += Messages.IsleFormat.Replace("%ISLE%", World.GetIsle(x, y).Name);
if (locationString != "")
locationString = Messages.LocationFormat.Replace("%META%", locationString);
return locationString;
}
private static string buildNearbyString(int x, int y)
{
string playersNearby = "";
User[] nearbyUsers = Server.GetNearbyUsers(x, y, true, true);
if (nearbyUsers.Length > 1)
{
playersNearby += Messages.NearbyPlayers;
playersNearby += Messages.Seperator;
string usersWest = "";
string usersNorth = "";
string usersEast = "";
string usersSouth = "";
foreach (User nearbyUser in nearbyUsers)
{
if (nearbyUser.X < x)
{
usersWest += " " + nearbyUser.Username + " ";
}
else if (nearbyUser.X > x)
{
usersEast += " " + nearbyUser.Username + " ";
}
else if (nearbyUser.Y > y)
{
usersSouth += " " + nearbyUser.Username + " ";
}
else if (nearbyUser.Y < y)
{
usersNorth += " " + nearbyUser.Username + " ";
}
}
if (usersEast != "")
playersNearby += " " + Messages.East + usersEast + Messages.Seperator;
if (usersWest != "")
playersNearby += " " + Messages.West + usersWest + Messages.Seperator;
if (usersSouth != "")
playersNearby += " " + Messages.South + usersSouth + Messages.Seperator;
if (usersNorth != "")
playersNearby += " " + Messages.North + usersNorth + Messages.Seperator;
}
return playersNearby;
}
private static string buildCommonInfo(int x, int y)
{
string message = "";
message += Messages.Seperator + buildNearbyString(x, y);
// Dropped Items
int[] itemIds = World.GetDroppedItems(x, y);
if (itemIds.Length == 0)
message += Messages.NothingMessage;
return message;
}
public static string BuildTransportInfo(Transport.TransportPoint transportPoint)
{
string message = "";
// Build list of locations
foreach(int transportLocationId in transportPoint.Locations)
{
Transport.TransportLocation transportLocation = Transport.GetTransportLocation(transportLocationId);
message += Messages.FormatTransportMessage(transportLocation.Type, transportLocation.LocationTitle, transportLocation.Cost, transportLocation.Id, transportLocation.GotoX, transportLocation.GotoY);
}
return message;
}
public static string BuildSpecialTileInfo(World.SpecialTile specialTile)
{
string message = "";
if (specialTile.Title != null)
message += Messages.TileFormat.Replace("%TILENAME%", specialTile.Title);
else
message += buildLocationString(specialTile.X, specialTile.Y);
if (specialTile.Description != null)
message += Messages.Seperator + specialTile.Description;
if (specialTile.Code == null)
message += buildCommonInfo(specialTile.X, specialTile.Y);
if (specialTile.Code == "TRANSPORT")
{
Transport.TransportPoint point = Transport.GetTransportPoint(specialTile.X, specialTile.Y);
message += Meta.BuildTransportInfo(point)+ "^R1";
}
if (specialTile.ExitX != 0 && specialTile.ExitY != 0)
message += Messages.ExitThisPlace + Messages.MetaTerminator;
return message;
}
public static string BuildMetaInfo(int x, int y)
{
string message = "";
message += buildLocationString(x, y);
message += buildCommonInfo(x, y);
return message;
}
}
}

View file

@ -17,7 +17,8 @@ namespace Horse_Isle_Server
public const byte PACKET_USERINFO = 0x81;
public const byte PACKET_WORLD = 0x7A;
public const byte PACKET_BASE_STATS = 0x7B;
public const byte PACKET_SWF_MODULE = 0x2A;
public const byte PACKET_SWF_CUTSCENE = 0x29;
public const byte PACKET_SWF_MODULE_GENTLE = 0x2A;
public const byte PACKET_PLACE_INFO = 0x1E;
public const byte PACKET_AREA_DEFS = 0x79;
public const byte PACKET_ANNOUNCEMENT = 0x7E;
@ -25,6 +26,7 @@ namespace Horse_Isle_Server
public const byte PACKET_PLAYSOUND = 0x23;
public const byte PACKET_KEEP_ALIVE = 0x7C;
public const byte PACKET_PROFILE = 0x18;
public const byte PACKET_TRANSPORT = 0x29;
public const byte PACKET_KICK = 0x80;
public const byte PACKET_LEAVE = 0x7D;
@ -560,10 +562,10 @@ namespace Horse_Isle_Server
return Packet;
}
public static byte[] CreateSwfModulePacket(string swf)
public static byte[] CreateSwfModulePacket(string swf,byte type)
{
MemoryStream ms = new MemoryStream();
ms.WriteByte(PACKET_SWF_MODULE);
ms.WriteByte(type);
byte[] strBytes = Encoding.UTF8.GetBytes(swf);
ms.Write(strBytes, 0x00, strBytes.Length);
ms.WriteByte(PACKET_TERMINATOR);

View file

@ -299,6 +299,55 @@ namespace Horse_Isle_Server
Update(sender);
}
public static void OnTransportUsed(Client sender, byte[] packet)
{
if (!sender.LoggedIn)
{
Logger.ErrorPrint(sender.RemoteIp + " Sent transport packet when not logged in.");
return;
}
if (packet.Length < 3)
{
Logger.ErrorPrint(sender.RemoteIp + " Sent an invalid transport packet.");
return;
}
string packetStr = Encoding.UTF8.GetString(packet);
string number = packetStr.Substring(1, packetStr.Length - 3);
int transportid;
try
{
transportid = Int32.Parse(number);
}
catch(InvalidOperationException)
{
Logger.ErrorPrint(sender.RemoteIp + " Tried to use a transport with id that is NaN.");
return;
}
Transport.TransportLocation transportLocation = Transport.GetTransportLocation(transportid);
if (sender.LoggedinUser.Money >= transportLocation.Cost)
{
string swfToLoad = Messages.BoatCutscene;
if (transportLocation.Type == "WAGON")
swfToLoad = Messages.WagonCutscene;
if (transportLocation.Type != "ROWBOAT")
{
byte[] swfModulePacket = PacketBuilder.CreateSwfModulePacket(swfToLoad, PacketBuilder.PACKET_SWF_CUTSCENE);
sender.SendPacket(swfModulePacket);
}
Teleport(sender, transportLocation.GotoX, transportLocation.GotoY);
sender.LoggedinUser.Money -= transportLocation.Cost;
}
}
public static void OnChatPacket(Client sender, byte[] packet)
{
if (!sender.LoggedIn)
@ -435,6 +484,8 @@ namespace Horse_Isle_Server
}
public static void OnDisconnect(Client sender)
{
if (sender.LoggedIn)
@ -457,77 +508,6 @@ namespace Horse_Isle_Server
connectedClients.Remove(sender);
}
public static void UpdateArea(Client forClient, bool justArea=false)
{
if (!forClient.LoggedIn)
{
Logger.ErrorPrint(forClient.RemoteIp + "tried to update tile information when not logged in.");
return;
}
string LocationStr = "";
if (!World.InSpecialTile(forClient.LoggedinUser.X, forClient.LoggedinUser.Y))
{
LocationStr = Meta.BuildMetaInfo(forClient.LoggedinUser.X, forClient.LoggedinUser.Y);
}
else
{
World.SpecialTile specialTile = World.GetSpecialTile(forClient.LoggedinUser.X, forClient.LoggedinUser.Y);
if(specialTile.AutoplaySwf != null && specialTile.AutoplaySwf != "" && !justArea)
{
byte[] swfModulePacket = PacketBuilder.CreateSwfModulePacket(specialTile.AutoplaySwf);
forClient.SendPacket(swfModulePacket);
}
if(specialTile.Code != null && !justArea)
if (!ProcessMapCode(forClient, specialTile.Code))
return;
LocationStr = Meta.BuildSpecialTileInfo(specialTile);
}
byte[] AreaMessage = PacketBuilder.CreatePlaceInfo(LocationStr);
forClient.SendPacket(AreaMessage);
}
public static void UpdateWorld(Client forClient)
{
if (!forClient.LoggedIn)
{
Logger.ErrorPrint(forClient.RemoteIp + "tried to update world information when not logged in.");
return;
}
byte[] WorldData = PacketBuilder.CreateWorldData(World.ServerTime.Minutes, World.ServerTime.Days, World.ServerTime.Years, World.GetWeather());
forClient.SendPacket(WorldData);
}
public static void UpdatePlayer(Client forClient)
{
if (!forClient.LoggedIn)
{
Logger.ErrorPrint(forClient.RemoteIp + "tried to update player information when not logged in.");
return;
}
byte[] PlayerData = PacketBuilder.CreatePlayerData(forClient.LoggedinUser.Money, Server.GetNumberOfPlayers(), forClient.LoggedinUser.MailBox.MailCount);
forClient.SendPacket(PlayerData);
}
public static void UpdateUserInfo(User user)
{
byte[] playerInfoBytes = PacketBuilder.CreatePlayerInfoUpdateOrCreate(user.X, user.Y, user.Facing, user.CharacterId, user.Username);
List<User> users = new List<User>();
foreach (Client client in ConnectedClients)
if (client.LoggedIn)
{
if (client.LoggedinUser.Id != user.Id)
client.SendPacket(playerInfoBytes);
}
}
public static User[] GetUsersUsersInIsle(World.Isle isle, bool includeStealth = false, bool includeMuted = false)
{
@ -638,7 +618,81 @@ namespace Horse_Isle_Server
UpdateUserInfo(client.LoggedinUser);
}
public static bool ProcessMapCode(Client forClient, string mapCode)
public static void UpdateWorld(Client forClient)
{
if (!forClient.LoggedIn)
{
Logger.ErrorPrint(forClient.RemoteIp + "tried to update world information when not logged in.");
return;
}
byte[] WorldData = PacketBuilder.CreateWorldData(World.ServerTime.Minutes, World.ServerTime.Days, World.ServerTime.Years, World.GetWeather());
forClient.SendPacket(WorldData);
}
public static void UpdatePlayer(Client forClient)
{
if (!forClient.LoggedIn)
{
Logger.ErrorPrint(forClient.RemoteIp + "tried to update player information when not logged in.");
return;
}
byte[] PlayerData = PacketBuilder.CreatePlayerData(forClient.LoggedinUser.Money, Server.GetNumberOfPlayers(), forClient.LoggedinUser.MailBox.MailCount);
forClient.SendPacket(PlayerData);
}
public static void UpdateUserInfo(User user)
{
byte[] playerInfoBytes = PacketBuilder.CreatePlayerInfoUpdateOrCreate(user.X, user.Y, user.Facing, user.CharacterId, user.Username);
List<User> users = new List<User>();
foreach (Client client in ConnectedClients)
if (client.LoggedIn)
{
if (client.LoggedinUser.Id != user.Id)
client.SendPacket(playerInfoBytes);
}
}
public static void UpdateArea(Client forClient, bool justArea = false)
{
if (!forClient.LoggedIn)
{
Logger.ErrorPrint(forClient.RemoteIp + "tried to update tile information when not logged in.");
return;
}
string LocationStr = "";
if (!World.InSpecialTile(forClient.LoggedinUser.X, forClient.LoggedinUser.Y))
{
LocationStr = Meta.BuildMetaInfo(forClient.LoggedinUser.X, forClient.LoggedinUser.Y);
}
else
{
World.SpecialTile specialTile = World.GetSpecialTile(forClient.LoggedinUser.X, forClient.LoggedinUser.Y);
if (specialTile.AutoplaySwf != null && specialTile.AutoplaySwf != "" && !justArea)
{
byte[] swfModulePacket = PacketBuilder.CreateSwfModulePacket(specialTile.AutoplaySwf,PacketBuilder.PACKET_SWF_MODULE_GENTLE);
forClient.SendPacket(swfModulePacket);
}
if (specialTile.Code != null && !justArea)
if (!ProcessMapCodeWithArg(forClient, specialTile.Code))
return;
LocationStr = Meta.BuildSpecialTileInfo(specialTile);
}
byte[] AreaMessage = PacketBuilder.CreatePlaceInfo(LocationStr);
forClient.SendPacket(AreaMessage);
}
public static bool ProcessMapCodeWithArg(Client forClient, string mapCode)
{
if(mapCode.Contains('-'))
{

View file

@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Horse_Isle_Server
{
class Transport
{
public struct TransportLocation
{
public int Id;
public int Cost;
public int GotoX;
public int GotoY;
public string Type;
public string LocationTitle;
}
public struct TransportPoint
{
public int X;
public int Y;
public int[] Locations;
}
public static List<TransportPoint> TransportPoints = new List<TransportPoint>();
public static List<TransportLocation> TransportLocations = new List<TransportLocation>();
public static TransportPoint GetTransportPoint(int x, int y)
{
foreach(TransportPoint transportPoint in TransportPoints)
{
if (transportPoint.X == x && transportPoint.Y == y)
{
return transportPoint;
}
}
throw new KeyNotFoundException("Cannot find transport port at x:" + x + "y:" + y);
}
public static TransportLocation GetTransportLocation(int id)
{
foreach (TransportLocation transportLocation in TransportLocations)
{
if (transportLocation.Id == id)
{
return transportLocation;
}
}
throw new KeyNotFoundException("Cannot find transport location at Id:" + id);
}
}
}

View file

@ -61,7 +61,8 @@ namespace Horse_Isle_Server
}
set
{
Database.SetPlayerBankMoney(value, Id);
Database.SetPlayerMoney(value, Id);
Server.UpdatePlayer(LoggedinClient);
money = value;
}
}