diff --git a/MudEngine/Commands/CommandEditRealm.cs b/MudEngine/Commands/CommandEditRealm.cs index 3356337..79d4d55 100644 --- a/MudEngine/Commands/CommandEditRealm.cs +++ b/MudEngine/Commands/CommandEditRealm.cs @@ -38,7 +38,7 @@ namespace MudEngine.Commands if ((player.Role == SecurityRoles.Admin) || (player.Role == SecurityRoles.GM)) { //Get the admin-entered realm filename - String filename = command.Substring("EditRealm".Length).Trim().ToLower() + ".Realm"; + String filename = command.Substring("EditRealm".Length).Trim() + ".Realm"; //Raise the scope of the player reference to class level instead of method level. this.player = player; @@ -251,6 +251,7 @@ namespace MudEngine.Commands /// private void ParseDescriptionSelection(Int32 value) { + String input = ""; switch (value) { //Simple Description @@ -259,9 +260,18 @@ namespace MudEngine.Commands player.Send("Enter a simple description for this Realm."); player.Send("Simple Descriptions are single line only."); player.Send("To create a blank description, you may simply press ENTER."); + player.Send("To cancel editing this description, you may type 'Exit'"); + if (!String.IsNullOrEmpty(realm.Description)) + player.Send("Current Description: " + realm.Description); + player.Send("Entry: ", false); //Read in the admins new simple description - realm.Description = player.ReadInput(); + input = player.ReadInput(); + + if (input.ToLower() == "exit") + return; + else + realm.Description = input; //Save the game world. player.ActiveGame.Save(); @@ -302,7 +312,7 @@ namespace MudEngine.Commands //Print the current line to the user and read their new description for that line. player.Send(line.ToString() + ": ", false); - String input = player.ReadInput(); + input = player.ReadInput(); //Check what content the admin entered. //If he/she typed 'exit' then we need to exit the editor. @@ -340,7 +350,7 @@ namespace MudEngine.Commands //Let the admin know that the line number specified does not exist. else { - player.Send("Line Editing canceled. The Realm does not contain that many lines."); + player.Send("Line Editing canceled. The Realm does not contain that many Description lines."); } } } @@ -527,18 +537,39 @@ namespace MudEngine.Commands case 1: //Feel player.Send("Enter the new default FEEL description for this Realm."); player.Send("If you wish to clear the current description, just press ENTER to save a blank description."); + + if (!String.IsNullOrEmpty(realm.Feel)) + { + player.Send("Current Value: ", false); + player.Send(realm.Feel); + } + player.Send("Enter Value: ", false); realm.Feel = player.ReadInput(); break; case 2: //Listen player.Send("Enter the new default LISTEN description for this Realm."); player.Send("If you wish to clear the current description, just press ENTER to save a blank description."); + + if (!String.IsNullOrEmpty(realm.Listen)) + { + player.Send("Current Value: ", false); + player.Send(realm.Listen); + } + player.Send("Enter value: ", false); realm.Listen = player.ReadInput(); break; case 3: //Smell player.Send("Enter the new default SMELL description for this Realm."); player.Send("If you wish to clear the current description, just press ENTER to save a blank description."); + + if (!String.IsNullOrEmpty(realm.Smell)) + { + player.Send("Current Value: ", false); + player.Send(realm.Smell); + } + player.Send("Enter value: ", false); realm.Smell = player.ReadInput(); break; @@ -560,6 +591,9 @@ namespace MudEngine.Commands else { realm.IsInitialRealm = true; + if (player.ActiveGame.InitialRealm != null) + player.ActiveGame.InitialRealm.IsInitialRealm = false; + player.ActiveGame.InitialRealm = realm; } break; @@ -615,15 +649,26 @@ namespace MudEngine.Commands //Next, we need to loop through every Zone and Door within this Realm //and update their Realm names to match the new one - foreach (Zone z in realm.ZoneCollection) + foreach (Realm r in player.ActiveGame.World.RealmCollection) { - if (z.Realm == oldName) - z.Realm = realm.Filename; - - foreach (Room r in z.RoomCollection) + foreach (Zone z in realm.ZoneCollection) { - if (r.Realm == oldName) - r.Realm = realm.Filename; + if (z.Realm == oldName) + z.Realm = realm.Filename; + + foreach (Room rm in z.RoomCollection) + { + if (rm.Realm == oldName) + rm.Realm = realm.Filename; + + foreach (Door d in rm.Doorways) + { + if (d.ArrivalRoom.Realm == oldName) + d.ArrivalRoom.Realm = realm.Filename; + if (d.DepartureRoom.Realm == oldName) + d.DepartureRoom.Realm = realm.Filename; + } + } } } } diff --git a/MudEngine/Commands/CommandEditRoom.cs b/MudEngine/Commands/CommandEditRoom.cs new file mode 100644 index 0000000..92f97b4 --- /dev/null +++ b/MudEngine/Commands/CommandEditRoom.cs @@ -0,0 +1,720 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.IO; +using System.Text; + +using MudEngine.FileSystem; +using MudEngine.GameObjects; +using MudEngine.GameObjects.Characters; +using MudEngine.GameManagement; +using MudEngine.Commands; +using MudEngine.GameObjects.Environment; + +namespace MudEngine.Commands +{ + public class CommandEditRoom : IGameCommand + { + public Boolean Override { get; set; } + + public String Name { get; set; } + public List Help { get; set; } + + private Room room; + BaseCharacter player; + + public CommandEditRoom() + { + Help = new List(); + + Help.Add("Use the Edit command to edit existing objects properties."); + Help.Add("Usage: EditRoom Realm>Room>Room"); + Help.Add("Example: EditRoom MyRealmName>MyRoom>MyRoom"); + } + + public void Execute(String command, BaseCharacter player) + { + if ((player.Role == SecurityRoles.Admin) || (player.Role == SecurityRoles.GM)) + { + //Get the admin-entered room filename + String[] tokens = command.Substring("EditRoom".Length).Trim().Split('>'); + + if (tokens.Length == 0) + { + player.Send("Room Editing canceled. No Room name was supplied."); + return; + } + else if (tokens.Length <= 2) + { + player.Send("Room Editing canceled. You must use the Rooms fully qualified path."); + IGameCommand gc = CommandEngine.GetCommand("CommandHelp"); + gc.Execute("Help EditRoom", player); + return; + } + + String filename = tokens[2]; //Room filename is the 3rd index in the array. + + //Raise the scope of the player reference to class level instead of method level. + this.player = player; + + //We have a filename, retrieve the Room the admin wants to edit. + if ((player.ActiveGame.World.GetRealm(tokens[0]) == null) || (player.ActiveGame.World.GetRealm(tokens[0]).GetZone(tokens[1])[0] == null)) + { + player.Send("Room editing canceled. Rooms owning Realm or Zone does not exists."); + return; + } + + if (player.ActiveGame.World.GetRealm(tokens[0]).GetZone(tokens[1])[0].GetRoom(filename).Count == 0) + { + player.Send("Room Editing canceled. The supplied Room does not exist."); + return; + } + room = player.ActiveGame.World.GetRealm(tokens[0]).GetZone(tokens[1])[0].GetRoom(filename)[0]; + + //If no Room was retrieved (due to it not existing), let the admin know + //that the Room filename was not valid. + if (room == null) + { + player.Send("Room Editing canceled. The supplied Room name is not valid."); + return; + } + //Otherwise, the Room does exist and was retrieved. + //Lets build our Editing menu's and allow for Room Editing. + else + { + //Construct the main editing menu. + BuildMenuMain(); + + //Find out what menu option the admin wants to use. + Int32 value = 0; + //Attempt to convert the String entered by the admin into a numeric value + try + { + value = Convert.ToInt32(player.ReadInput()); + } + //If a non-numeric value is supplied, the conversion failed. This is us catching that failure. + catch + { + player.Send("Room Editing canceled. The supplied value was not numeric!"); + return; + } + + //Parse the menu option that the admin supplied. + ParseMenuSelection(value); + //let the admin know that we have now exited the editor. + player.Send("Editing completed."); + } + } + } + + /// + /// Constructs the Main Editing menu for admins to look it. + /// + private void BuildMenuMain() + { + player.FlushConsole(); + player.Send(Path.GetFileNameWithoutExtension(room.Filename)); + player.Send("Select from the available options below:"); + player.Send("1: Descriptions"); + player.Send("2: Names"); + player.Send("3: Senses"); + player.Send("4: Initial Room"); + player.Send("5: Settings"); + player.Send("6: Doorways"); + player.Send("9: Exit"); + player.Send("Enter numeric selection: ", false); + } + + /// + /// Constructs the Descriptions Editing menu for admins to look at. + /// + private void BuildMenuDescriptions() + { + player.FlushConsole(); + player.Send(Path.GetFileNameWithoutExtension(room.Filename)); + player.Send("Select from the available options below:"); + player.Send("1: Simple Description"); + player.Send("2: Detailed Descriptions"); + player.Send("9: Exit"); + player.Send("Enter a numeric selection: ", false); + } + + /// + /// Constructs the Name Editing menu for admins to look at. + /// + private void BuildMenuNames() + { + player.FlushConsole(); + player.Send(Path.GetFileNameWithoutExtension(room.Filename)); + player.Send("When you assign a Room Name, the Filename is overwrote with your RoomName as a filename."); + player.Send("Example: RoomName of 'ExampleRoom' would automatically set a Filename of 'ExampleRoom.Room'"); + player.Send(""); + + player.Send("If you wish to have multiple Rooms with the same visible name, you will need to specify a different Filename for each Room."); + player.Send("Filenames are what you use when accessing objects as a Admin. Typically without the file extension."); + player.Send("Example: A Room with a Visible name of \"My Test Room\" can have a filename of \"Test.Room\". You would access this object as a Admin by specifying a object name of \"Test\""); + player.Send("Select from the available options below:"); + player.Send(""); + + player.Send("1: Room Visibile Name"); + player.Send("2: Room Filename"); + player.Send("9: Exit"); + player.Send("Enter numeric selection: ", false); + } + + private void BuildMenuSenses() + { + player.FlushConsole(); + player.Send(Path.GetFileName(room.Filename)); + player.Send("Senses are what allow the players to get a better understanding of the environment around them."); + player.Send("Choose what sense you would like to edit, make your adjustments and press 'ENTER' to save the changes."); + player.Send("Senses defined for Rooms will override any senses defined for it's parent Zone or Realm."); + player.Send("Select from the available options below:"); + player.Send("1: Feel Sense"); + player.Send("2: Listen Sense"); + player.Send("3: Smell Sense"); + player.Send("9: Exit"); + } + + private void BuildMenuInitial() + { + player.FlushConsole(); + player.Send(room.Name); + player.Send("Initial Room Settings."); + player.Send("The Initial Room setting determins if the Room will be the starting location for all newly created players or not."); + if (room.IsInitialRoom) + { + player.Send("If you disable this Room from being the Initial Room, new players will not have a starting location assigned to them."); + player.Send("You will need to enable Initial Room on another Room in order for new players to have a starting location."); + player.Send("Select from the available options below:"); + player.Send("1: Disable Initial Room"); + } + else + { + player.Send("If you enable Initial Room, then new players will start at this location from now on."); + player.Send("Select from the available options below:"); + player.Send("1: Enable Initial Room"); + } + player.Send("9: Exit"); + player.Send("Enter numeric selection: ", false); + } + + /// + /// This method parses the Admin input based off the main editing menu + /// and sends the admin to what-ever sub-menu method we need to. + /// + /// + private void ParseMenuSelection(Int32 value) + { + Int32 entry = 0; + + switch (value) + { + case 1: //Descriptions + //build the menu and parse their menu selections. + BuildMenuDescriptions(); + try + { + entry = Convert.ToInt32(player.ReadInput()); + } + catch + { + player.Send("Room Editing canceled. The supplied value was not numeric!"); + return; + } + + ParseDescriptionSelection(entry); + break; + case 2: //Names + //build the menu and parse their menu selections. + BuildMenuNames(); + try + { + entry = Convert.ToInt32(player.ReadInput()); + } + catch + { + player.Send("Room Editing canceled. The supplied value was not numeric!"); + return; + } + + ParseNameSelection(entry); + break; + case 3://Senses + break; + case 4: //Initial Realm + //build the menu and parse their menu selections + BuildMenuInitial(); + try + { + entry = Convert.ToInt32(player.ReadInput()); + } + catch + { + player.Send("Room Editing canceled. The supplied value was not numeric!"); + return; + } + + ParseInitialSelection(entry); + break; + case 5: //Settings + break; + case 6: //Doorways + break; + case 9: + break; + default: + break; + } + } + + /// + /// This method parses the admins menu selection from the Description menu + /// and adjusts the Rooms descriptions as specified by the admin + /// + /// + private void ParseDescriptionSelection(Int32 value) + { + String input = ""; + + switch (value) + { + //Simple Description + case 1: + player.FlushConsole(); + player.Send("Enter a simple description for this Room."); + player.Send("Simple Descriptions are single line only."); + player.Send("To create a blank description, you may simply press ENTER."); + player.Send("To cancel editing this description, you may type 'Exit'"); + if (!String.IsNullOrEmpty(room.Description)) + player.Send("Current Description: " + room.Description); + + player.Send("Entry: ", false); + //Read in the admins new simple description + input = player.ReadInput(); + + if (input.ToLower() == "exit") + return; + else + room.Description = input; + + //Save the game world. + player.ActiveGame.Save(); + player.Send("New Simple Description saved."); + break; + case 2://Detailed Description + Boolean isEditing = true; + Int32 line = 1; + + //Loop until the admin is finished entering his/her multi-line description. + while (isEditing) + { + player.FlushConsole(); + line = 1; //reset our line to the first line, so we can re-print the content to the admin. + + //print some help info to the admin + player.Send("Enter a Detailed Description for this Room."); + player.Send("Detailed Descriptions are multi-lined descriptions."); + player.Send("When you are finished entering a line, press ENTER to save it and move onto the next line."); + player.Send("When you are finished, you may type 'Exit' to save your changes and quit the Description editor."); + player.Send("To clear all detailed description lines, you may type 'Clear All'"); + player.Send("To clear a single Detailed Description line, you may type 'Clear x', where x = line number to clear."); + player.Send("Example: 'Clear 2'"); + player.Send("This will clear all contents from line number two in the detailed description."); + player.Send("If you make a mistake and need to edit a previously entered line, type 'Edit x' where x = line number you wish to edit."); + player.Send("An example would be 'Edit 3' which would allow you to change line #3."); + player.Send(""); + player.Send("Detailed Description:"); + + //Loop through each description currently within the collection + //This will include lines created within this loop as well. + foreach (String desc in room.DetailedDescription) + { + player.Send(line.ToString() + ": " + desc); + line++; + } + + //Print the current line to the user and read their new description for that line. + player.Send(line.ToString() + ": ", false); + input = player.ReadInput(); + + //Check what content the admin entered. + //If he/she typed 'exit' then we need to exit the editor. + if (input.ToLower() == "exit") + isEditing = false; + //If he/she typed 'edit' then we need to edit a supplied line number. + else if (input.ToLower().StartsWith("edit")) + { + //Retrieve the line number from the users input. + String editLine = input.Substring("edit".Length).Trim(); + + //If no line number was provided, cancel. + if (String.IsNullOrEmpty(editLine)) + { + player.Send("Line editing canceled. You need to supply a line number."); + } + //Line number was provided, so lets skip to the specified line number + //and replace the contents of that line with whatever the admin enters now. + else + { + //convert the users specified line number from string to integer. + line = Convert.ToInt32(editLine); + + //Make sure the line number specified isn't greater than the number + //of lines we currently have. + if (room.DetailedDescription.Count >= line) + { + //Get the new description for this line... + player.Send("New Description: ", false); + input = player.ReadInput(); + //-1 correction due to collection index starting at 0 and not 1. + //replace the existing description with the new one. + room.DetailedDescription[line - 1] = input; + } + //Let the admin know that the line number specified does not exist. + else + { + player.Send("Line Editing canceled. The Room does not contain that many Description lines."); + } + } + } + //If he/she typed 'clear' then we need to check if the admin wants to clear + //every single line of description or just a single line. + else if (input.ToLower().StartsWith("clear")) + { + //Find out what additional content is included with the clear input. + String clear = input.ToLower().Substring("clear".Length).Trim(); + + //if no additional values supplied with the clear command, we cancel. + if (String.IsNullOrEmpty(clear)) + { + player.Send("Line Clearing canceled. You need to supply a line number or specify 'All' to clear all lines."); + } + //Admin specified to clear 'all' lines of the descrpition. + else if (clear == "all") + { + //Wipe out every line of description. + room.DetailedDescription.Clear(); + } + //Admin specified a single line. Find the admins specified line number for clearing. + else + { + //Convert the specified line number to a integer + Int32 i = Convert.ToInt32(clear); + + //make sure the line number provided does in-fact exist. + if (room.DetailedDescription.Count >= i) + //Remove the specified line number for the descriptions collection. + room.DetailedDescription.Remove(room.DetailedDescription[i - 1]); + //Line provided is larger than the number of lines available to check. Cancel. + else + player.Send("Line Clearing canceled. The Room does not contain that many description lines."); + } + } + //No special tokens provided, so we assume this line is a description. + //Add the contents to the realm's detailed description collection. + else + { + room.DetailedDescription.Add(input); + } + } + + //Loop is finished, so lets save the game world. + player.ActiveGame.Save(); + player.Send("Detailed Description saved."); + break; + case 9: + break; + } + } + + /// + /// This method parses the values supplied by the admin from the Name editing menu. + /// Allows for editing visible names and filenames + /// + /// + private void ParseNameSelection(Int32 value) + { + switch (value) + { + case 1: //Visible Name + player.FlushConsole(); + player.Send("Enter a new Visible name for this Room."); + player.Send("Enter Value: ", false); + + //Get the new name for this Room + String newName = player.ReadInput(); + + //Ensure the new name is not blank. + if (String.IsNullOrEmpty(newName)) + { + player.Send("Room Name Editing canceled. No name supplied."); + } + //We have a valid name, so lets try assigning it to the Room + else + { + //Check to see if the supplied name already exists by checking for a existing Room + //that has a matching filename. + if (player.ActiveGame.World.GetRealm(room.Realm).GetZone(room.Zone)[0].GetRoom(newName + ".room").Count == 0) + { + //No matching Room was found, so we can go ahead and make the change. + //Store the new name within this Room + String oldName = room.Filename; + room.Name = newName; + + //Update all of the objects that are within the Room to have the + //new name assigned to them. + UpdateRoomObjects(oldName); + + //TODO: Any Items/NPC's etc within this Room will need to be updated as well. + } + else + { + player.Send("Room Name Editing canceled. " + newName + " already exists within the Zone."); + player.Send("If you want to keep the provided Visible Name for this Room, you must create a unique Filename."); + player.Send("Would you like to assign a unique Filename now?"); + player.Send("1: Yes"); + player.Send("2: No"); + try + { + Int32 i = Convert.ToInt32(player.ReadInput()); + + switch (i) + { + case 1: + player.FlushConsole(); + player.Send("The default filename for this Room (using the new Visible Name) is currently:"); + player.Send(newName + ".Room"); + player.Send("Please supply a different filename:"); + player.Send("Enter Value: ", false); + + String filename = player.ReadInput(); + + if (String.IsNullOrEmpty(filename)) + { + player.Send("Room Name Editing Canceled. No filename supplied."); + } + else + { + if (player.ActiveGame.World.GetRealm(room.Realm).GetZone(filename)[0].GetRoom(filename)[0] != null) + { + player.Send("Room Name Editing Canceled. A Room with this filename already exists!"); + } + else + { + String oldName = room.Filename; + room.Name = newName; + room.Filename = filename; + + UpdateRoomObjects(oldName); + } + } + break; + case 2: + player.Send("Room Name Editing Canceled. A Room with this filename already exists!"); + break; + } + } + catch + { + player.Send("Room Name Editing canceled. The supplied value was not numeric."); + } + } + } + player.ActiveGame.Save(); + break; + case 2: //Room Filename + player.FlushConsole(); + player.Send("Enter a new Filenamename for this Room."); + player.Send("Enter Value: ", false); + + String fname = player.ReadInput(); + + if (String.IsNullOrEmpty(fname)) + { + player.Send("Room Name Editing canceled. No name supplied."); + } + else if (player.ActiveGame.World.GetRealm(room.Realm).GetZone(room.Zone)[0].GetRoom(fname).Count != 0) + { + player.Send("Room Name Editing canceled. A Room with this filename already exists!"); + } + else + { + String oldName = ""; + oldName = room.Filename; + room.Filename = fname; + UpdateRoomObjects(oldName); + player.ActiveGame.Save(); + } + break; + case 9: //Exit + return; + } + } + + private void ParseSensesSelection(Int32 value) + { + player.FlushConsole(); + + switch (value) + { + case 1: //Feel + player.Send("Enter the new default FEEL description for this Room."); + player.Send("If you wish to clear the current description, just press ENTER to save a blank description."); + + if (!String.IsNullOrEmpty(room.Feel)) + { + player.Send("Current Value: ", false); + player.Send(room.Feel); + } + + player.Send("Enter Value: ", false); + room.Feel = player.ReadInput(); + break; + case 2: //Listen + player.Send("Enter the new default LISTEN description for this Room."); + player.Send("If you wish to clear the current description, just press ENTER to save a blank description."); + + if (!String.IsNullOrEmpty(room.Listen)) + { + player.Send("Current Value: ", false); + player.Send(room.Listen); + } + + player.Send("Enter value: ", false); + room.Listen = player.ReadInput(); + break; + case 3: //Smell + player.Send("Enter the new default SMELL description for this Room."); + player.Send("If you wish to clear the current description, just press ENTER to save a blank description."); + + if (!String.IsNullOrEmpty(room.Smell)) + { + player.Send("Current Value: ", false); + player.Send(room.Smell); + } + + player.Send("Enter value: ", false); + room.Smell = player.ReadInput(); + break; + case 9: //Exit + return; + } + } + + private void ParseInitialSelection(Int32 value) + { + switch (value) + { + case 1: //Enable/Disable Initial Realm + if (player.ActiveGame.InitialRealm == null) + { + player.Send("Room Initial editing canceled. You must have a Initial Realm defined before setting a Initial Room."); + return; + } + + if (player.ActiveGame.InitialRealm.InitialZone == null) + { + player.Send("Room Initial editing canceled. You must have a Initial Zone before setting a Initial Room."); + return; + } + + if ((player.ActiveGame.InitialRealm.Filename == room.Realm) && (player.ActiveGame.InitialRealm.InitialZone.Filename == room.Zone)) + { + if (room.IsInitialRoom) + { + room.IsInitialRoom = false; + player.ActiveGame.InitialRealm.InitialZone.InitialRoom = null; + } + else + { + room.IsInitialRoom = true; + player.ActiveGame.InitialRealm.InitialZone.InitialRoom = room; + } + } + else + { + player.Send("Room Initial editing canceled. You cannot define this Room as initial if it's parent Zone or Realm is not set as Initial."); + } + break; + case 9: //Exit + return; + } + + player.ActiveGame.Save(); + } + + /// + /// This method is used when the Rooms name or filename has changed. + /// It updates all objects that refer to this Rooms filename/roomname + /// + /// + private void UpdateRoomObjects(String oldName) + { + //Check if this Room is the initial Room. If so then we need to update the + //current Game so that when it launches, it checks the new Room and not the old + //one. + if ((room.IsInitialRoom) && (player.ActiveGame.InitialRealm.InitialZone.Filename == room.Zone)) + { + player.ActiveGame.InitialRealm.InitialZone.InitialRoom = room; + } + + //Loop through each player currently logged in and see if they are currently + //within the selected Room. If they are then we need to change their current + //Room to the new one. + foreach (BaseCharacter p in player.ActiveGame.GetPlayerCollection()) + { + if (p.Name.StartsWith("Base")) + continue; + + if (p.CurrentRoom.Filename == oldName) + { + p.CurrentRoom = room; + p.Save(player.ActiveGame.DataPaths.Players); + } + } + + //Loop through every player on file to see if any are currently within + //the selected Realm. If they are, we need to edit their files so that they + //log-in next time into the correct Realm. Otherwise Admins will need to manually + //edit the files and move the players. + //This is done after scanning logged in players, as logged in players will of had + //their location already updated and files saved, preventing any need for us to + //modify their files again. + foreach (String file in Directory.GetFiles(player.ActiveGame.DataPaths.Players)) + { + BaseCharacter ch = new BaseCharacter(player.ActiveGame); + ch.Load(file); + if (ch.CurrentRoom.Filename == oldName) + { + ch.CurrentRoom = room; + ch.Save(player.ActiveGame.DataPaths.Players); + } + } + + //Next, we need to loop through every Room within this Room + //and update their Rooms names to match the new one + foreach(Realm r in player.ActiveGame.World.RealmCollection) + { + foreach (Zone z in r.ZoneCollection) + { + if (z.InitialRoom.Filename == oldName) + { + z.InitialRoom = room; + } + + foreach (Room rm in z.RoomCollection) + { + foreach (Door d in rm.Doorways) + { + if (d.ArrivalRoom.Filename == oldName) + d.ArrivalRoom = room; + if (d.DepartureRoom.Filename == oldName) + d.DepartureRoom = room; + } + } + } + } + } + } +} diff --git a/MudEngine/Commands/CommandEditZone.cs b/MudEngine/Commands/CommandEditZone.cs new file mode 100644 index 0000000..45af473 --- /dev/null +++ b/MudEngine/Commands/CommandEditZone.cs @@ -0,0 +1,698 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.IO; +using System.Text; + +using MudEngine.FileSystem; +using MudEngine.GameObjects; +using MudEngine.GameObjects.Characters; +using MudEngine.GameManagement; +using MudEngine.Commands; +using MudEngine.GameObjects.Environment; + +namespace MudEngine.Commands +{ + public class CommandEditZone : IGameCommand + { + public Boolean Override { get; set; } + + public String Name { get; set; } + public List Help { get; set; } + + private Zone zone; + BaseCharacter player; + + public CommandEditZone() + { + Help = new List(); + + Help.Add("Use the Edit command to edit existing objects properties."); + Help.Add("Usage: EditZone Realm>Zone"); + Help.Add("Example: EditZone MyRealmName>MyZone"); + } + + public void Execute(String command, BaseCharacter player) + { + if ((player.Role == SecurityRoles.Admin) || (player.Role == SecurityRoles.GM)) + { + //Get the admin-entered zone filename + String[] tokens = command.Substring("EditZone".Length).Trim().Split('>'); + + + if (tokens.Length == 0) + { + player.Send("Zone Editing canceled. No Zone name was supplied."); + return; + } + else if (tokens.Length == 1) + { + player.Send("Zone Editing canceled. Realm name supplied, but no Zone name."); + return; + } + + String filename = tokens[1]; + + //Raise the scope of the player reference to class level instead of method level. + this.player = player; + + //We have a filename, retrieve the Zone the admin wants to edit. + if ((player.ActiveGame.World.GetRealm(tokens[0]) == null) && (player.ActiveGame.World.GetRealm(tokens[0]).GetZone(filename).Count == 0)) + { + player.Send("Zone editing canceled. Zones owning Realm or the Zone itself does not exists."); + return; + } + + zone = player.ActiveGame.World.GetRealm(tokens[0]).GetZone(filename)[0]; + + //If no Zone was retrieved (due to it not existing), let the admin know + //that the Zone filename was not valid. + if (zone == null) + { + player.Send("Zone Editing canceled. The supplied Zone name is not valid."); + return; + } + //Otherwise, the Zone does exist and was retrieved. + //Lets build our Editing menu's and allow for Zone Editing. + else + { + //Construct the main editing menu. + BuildMenuMain(); + + //Find out what menu option the admin wants to use. + Int32 value = 0; + //Attempt to convert the String entered by the admin into a numeric value + try + { + value = Convert.ToInt32(player.ReadInput()); + } + //If a non-numeric value is supplied, the conversion failed. This is us catching that failure. + catch + { + player.Send("Zone Editing canceled. The supplied value was not numeric!"); + return; + } + + //Parse the menu option that the admin supplied. + ParseMenuSelection(value); + //let the admin know that we have now exited the editor. + player.Send("Editing completed."); + } + } + } + + /// + /// Constructs the Main Editing menu for admins to look it. + /// + private void BuildMenuMain() + { + player.FlushConsole(); + player.Send(Path.GetFileNameWithoutExtension(zone.Filename)); + player.Send("Select from the available options below:"); + player.Send("1: Descriptions"); + player.Send("2: Names"); + player.Send("3: Senses"); + player.Send("4: Initial Zone"); + player.Send("5: Settings"); + player.Send("9: Exit"); + player.Send("Enter numeric selection: ", false); + } + + /// + /// Constructs the Descriptions Editing menu for admins to look at. + /// + private void BuildMenuDescriptions() + { + player.FlushConsole(); + player.Send(Path.GetFileNameWithoutExtension(zone.Filename)); + player.Send("Select from the available options below:"); + player.Send("1: Simple Description"); + player.Send("2: Detailed Descriptions"); + player.Send("9: Exit"); + player.Send("Enter a numeric selection: ", false); + } + + /// + /// Constructs the Name Editing menu for admins to look at. + /// + private void BuildMenuNames() + { + player.FlushConsole(); + player.Send(Path.GetFileNameWithoutExtension(zone.Filename)); + player.Send("When you assign a Zone Name, the Filename is overwrote with your ZoneName as a filename."); + player.Send("Example: ZoneName of 'ExampleZone' would automatically set a Filename of 'ExampleZone.Zone'"); + player.Send(""); + + player.Send("If you wish to have multiple Zones with the same visible name, you will need to specify a different Filename for each Zone."); + player.Send("Filenames are what you use when accessing objects as a Admin. Typically without the file extension."); + player.Send("Example: A Zone with a Visible name of \"My Test Zone\" can have a filename of \"Test.Zone\". You would access this object as a Admin by specifying a object name of \"Test\""); + player.Send("Select from the available options below:"); + player.Send(""); + + player.Send("1: Zone Visibile Name"); + player.Send("2: Zone Filename"); + player.Send("9: Exit"); + player.Send("Enter numeric selection: ", false); + } + + private void BuildMenuSenses() + { + player.FlushConsole(); + player.Send(Path.GetFileName(zone.Filename)); + player.Send("Senses are what allow the players to get a better understanding of the environment around them."); + player.Send("Choose what sense you would like to edit, make your adjustments and press 'ENTER' to save the changes."); + player.Send("Senses defined for Zones will be applied as the default for every Room created within a Zone."); + player.Send("Select from the available options below:"); + player.Send("1: Feel Sense"); + player.Send("2: Listen Sense"); + player.Send("3: Smell Sense"); + player.Send("9: Exit"); + } + + private void BuildMenuInitial() + { + player.FlushConsole(); + player.Send(zone.Name); + player.Send("Initial Zone Settings."); + player.Send("The Initial Zone setting determins if the Zone will be the starting location for all newly created players or not."); + if (zone.IsInitialZone) + { + player.Send("If you disable this Zone from being the Initial Zone, new players will not have a starting location assigned to them."); + player.Send("You will need to enable Initial Zone on another Zone in order for new players to have a starting location."); + player.Send("Select from the available options below:"); + player.Send("1: Disable Initial Zone"); + } + else + { + player.Send("If you enable Initial Zone, then new players will start at this location from now on."); + player.Send("Select from the available options below:"); + player.Send("1: Enable Initial Zone"); + } + player.Send("9: Exit"); + player.Send("Enter numeric selection: ", false); + } + + /// + /// This method parses the Admin input based off the main editing menu + /// and sends the admin to what-ever sub-menu method we need to. + /// + /// + private void ParseMenuSelection(Int32 value) + { + Int32 entry = 0; + + switch (value) + { + case 1: //Descriptions + //build the menu and parse their menu selections. + BuildMenuDescriptions(); + try + { + entry = Convert.ToInt32(player.ReadInput()); + } + catch + { + player.Send("Zone Editing canceled. The supplied value was not numeric!"); + return; + } + + ParseDescriptionSelection(entry); + break; + case 2: //Names + //build the menu and parse their menu selections. + BuildMenuNames(); + try + { + entry = Convert.ToInt32(player.ReadInput()); + } + catch + { + player.Send("Zone Editing canceled. The supplied value was not numeric!"); + return; + } + + ParseNameSelection(entry); + break; + case 3://Senses + break; + case 4: //Initial Realm + //build the menu and parse their menu selections + BuildMenuInitial(); + try + { + entry = Convert.ToInt32(player.ReadInput()); + } + catch + { + player.Send("Zone Editing canceled. The supplied value was not numeric!"); + return; + } + + ParseInitialSelection(entry); + break; + case 5: //Settings + break; + case 9: + break; + default: + break; + } + } + + /// + /// This method parses the admins menu selection from the Description menu + /// and adjusts the Zones descriptions as specified by the admin + /// + /// + private void ParseDescriptionSelection(Int32 value) + { + String input = ""; + + switch (value) + { + //Simple Description + case 1: + player.FlushConsole(); + player.Send("Enter a simple description for this Zone."); + player.Send("Simple Descriptions are single line only."); + player.Send("To create a blank description, you may simply press ENTER."); + player.Send("To cancel editing this description, you may type 'Exit'"); + if (!String.IsNullOrEmpty(zone.Description)) + player.Send("Current Description: " + zone.Description); + + player.Send("Entry: ", false); + //Read in the admins new simple description + input = player.ReadInput(); + + if (input.ToLower() == "exit") + return; + else + zone.Description = input; + //Save the game world. + player.ActiveGame.Save(); + player.Send("New Simple Description saved."); + break; + case 2://Detailed Description + Boolean isEditing = true; + Int32 line = 1; + + //Loop until the admin is finished entering his/her multi-line description. + while (isEditing) + { + player.FlushConsole(); + line = 1; //reset our line to the first line, so we can re-print the content to the admin. + + //print some help info to the admin + player.Send("Enter a Detailed Description for this Zone."); + player.Send("Detailed Descriptions are multi-lined descriptions."); + player.Send("When you are finished entering a line, press ENTER to save it and move onto the next line."); + player.Send("When you are finished, you may type 'Exit' to save your changes and quit the Description editor."); + player.Send("To clear all detailed description lines, you may type 'Clear All'"); + player.Send("To clear a single Detailed Description line, you may type 'Clear x', where x = line number to clear."); + player.Send("Example: 'Clear 2'"); + player.Send("This will clear all contents from line number two in the detailed description."); + player.Send("If you make a mistake and need to edit a previously entered line, type 'Edit x' where x = line number you wish to edit."); + player.Send("An example would be 'Edit 3' which would allow you to change line #3."); + player.Send(""); + player.Send("Detailed Description:"); + + //Loop through each description currently within the collection + //This will include lines created within this loop as well. + foreach (String desc in zone.DetailedDescription) + { + player.Send(line.ToString() + ": " + desc); + line++; + } + + //Print the current line to the user and read their new description for that line. + player.Send(line.ToString() + ": ", false); + input = player.ReadInput(); + + //Check what content the admin entered. + //If he/she typed 'exit' then we need to exit the editor. + if (input.ToLower() == "exit") + isEditing = false; + //If he/she typed 'edit' then we need to edit a supplied line number. + else if (input.ToLower().StartsWith("edit")) + { + //Retrieve the line number from the users input. + String editLine = input.Substring("edit".Length).Trim(); + + //If no line number was provided, cancel. + if (String.IsNullOrEmpty(editLine)) + { + player.Send("Line editing canceled. You need to supply a line number."); + } + //Line number was provided, so lets skip to the specified line number + //and replace the contents of that line with whatever the admin enters now. + else + { + //convert the users specified line number from string to integer. + line = Convert.ToInt32(editLine); + + //Make sure the line number specified isn't greater than the number + //of lines we currently have. + if (zone.DetailedDescription.Count >= line) + { + //Get the new description for this line... + player.Send("New Description: ", false); + input = player.ReadInput(); + //-1 correction due to collection index starting at 0 and not 1. + //replace the existing description with the new one. + zone.DetailedDescription[line - 1] = input; + } + //Let the admin know that the line number specified does not exist. + else + { + player.Send("Line Editing canceled. The Zone does not contain that many Description lines."); + } + } + } + //If he/she typed 'clear' then we need to check if the admin wants to clear + //every single line of description or just a single line. + else if (input.ToLower().StartsWith("clear")) + { + //Find out what additional content is included with the clear input. + String clear = input.ToLower().Substring("clear".Length).Trim(); + + //if no additional values supplied with the clear command, we cancel. + if (String.IsNullOrEmpty(clear)) + { + player.Send("Line Clearing canceled. You need to supply a line number or specify 'All' to clear all lines."); + } + //Admin specified to clear 'all' lines of the descrpition. + else if (clear == "all") + { + //Wipe out every line of description. + zone.DetailedDescription.Clear(); + } + //Admin specified a single line. Find the admins specified line number for clearing. + else + { + //Convert the specified line number to a integer + Int32 i = Convert.ToInt32(clear); + + //make sure the line number provided does in-fact exist. + if (zone.DetailedDescription.Count >= i) + //Remove the specified line number for the descriptions collection. + zone.DetailedDescription.Remove(zone.DetailedDescription[i - 1]); + //Line provided is larger than the number of lines available to check. Cancel. + else + player.Send("Line Clearing canceled. The Zone does not contain that many description lines."); + } + } + //No special tokens provided, so we assume this line is a description. + //Add the contents to the Zone's detailed description collection. + else + { + zone.DetailedDescription.Add(input); + } + } + + //Loop is finished, so lets save the game world. + player.ActiveGame.Save(); + player.Send("Detailed Description saved."); + break; + case 9: + break; + } + } + + /// + /// This method parses the values supplied by the admin from the Name editing menu. + /// Allows for editing visible names and filenames + /// + /// + private void ParseNameSelection(Int32 value) + { + switch (value) + { + case 1: //Visible Name + player.FlushConsole(); + player.Send("Enter a new Visible name for this Zone."); + player.Send("Enter Value: ", false); + + //Get the new name for this Zone + String newName = player.ReadInput(); + + //Ensure the new name is not blank. + if (String.IsNullOrEmpty(newName)) + { + player.Send("Zone Name Editing canceled. No name supplied."); + } + //We have a valid name, so lets try assigning it to the Zone + else + { + //Check to see if the supplied name already exists by checking for a existing Zone + //that has a matching filename. + if (player.ActiveGame.World.GetRealm(zone.Realm).GetZone(newName + ".zone").Count == 0) + { + //No matching Zone was found, so we can go ahead and make the change. + //Store the new name within this Zone + String oldName = zone.Filename; + zone.Name = newName; + + //Update all of the objects that are within the Zone to have the + //new name assigned to them. + UpdateZoneObjects(oldName); + + //TODO: Any Items/NPC's etc within this Zone will need to be updated as well. + } + else + { + player.Send("Zone Name Editing canceled. " + newName + " already exists within the Realm."); + player.Send("If you want to keep the provided Visible Name for this Zone, you must create a unique Filename."); + player.Send("Would you like to assign a unique Filename now?"); + player.Send("1: Yes"); + player.Send("2: No"); + try + { + Int32 i = Convert.ToInt32(player.ReadInput()); + + switch (i) + { + case 1: + player.FlushConsole(); + player.Send("The default filename for this Zone (using the new Visible Name) is currently:"); + player.Send(newName + ".Zone"); + player.Send("Please supply a different filename:"); + player.Send("Enter Value: ", false); + + String filename = player.ReadInput(); + + if (String.IsNullOrEmpty(filename)) + { + player.Send("Zone Name Editing Canceled. No filename supplied."); + } + else + { + if (player.ActiveGame.World.GetRealm(zone.Realm).GetZone(filename).Count != 0) + { + player.Send("Zone Name Editing Canceled. A Zone with this filename already exists!"); + } + else + { + String oldName = zone.Filename; + zone.Name = newName; + zone.Filename = filename; + + UpdateZoneObjects(oldName); + } + } + break; + case 2: + player.Send("Zone Name Editing Canceled. A Zone with this filename already exists!"); + break; + } + } + catch + { + player.Send("Zone Name Editing canceled. The supplied value was not numeric."); + } + } + } + player.ActiveGame.Save(); + break; + case 2: //Zone Filename + player.FlushConsole(); + player.Send("Enter a new Filenamename for this Zone."); + player.Send("Enter Value: ", false); + + String fname = player.ReadInput(); + + if (String.IsNullOrEmpty(fname)) + { + player.Send("Zone Name Editing canceled. No name supplied."); + } + else if (player.ActiveGame.World.GetRealm(zone.Realm).GetZone(fname) != null) + { + player.Send("Zone Name Editing canceled. A Zone with this filename already exists!"); + } + else + { + String oldName = ""; + oldName = zone.Filename; + zone.Filename = fname; + UpdateZoneObjects(oldName); + player.ActiveGame.Save(); + } + break; + case 9: //Exit + return; + } + } + + private void ParseSensesSelection(Int32 value) + { + player.FlushConsole(); + + switch (value) + { + case 1: //Feel + player.Send("Enter the new default FEEL description for this Zone."); + player.Send("If you wish to clear the current description, just press ENTER to save a blank description."); + + if (!String.IsNullOrEmpty(zone.Feel)) + { + player.Send("Current Value: ", false); + player.Send(zone.Feel); + } + + player.Send("Enter Value: ", false); + zone.Feel = player.ReadInput(); + break; + case 2: //Listen + player.Send("Enter the new default LISTEN description for this Zone."); + player.Send("If you wish to clear the current description, just press ENTER to save a blank description."); + + if (!String.IsNullOrEmpty(zone.Listen)) + { + player.Send("Current Value: ", false); + player.Send(zone.Listen); + } + + player.Send("Enter value: ", false); + zone.Listen = player.ReadInput(); + break; + case 3: //Smell + player.Send("Enter the new default SMELL description for this Zone."); + player.Send("If you wish to clear the current description, just press ENTER to save a blank description."); + + if (!String.IsNullOrEmpty(zone.Smell)) + { + player.Send("Current Value: ", false); + player.Send(zone.Smell); + } + + player.Send("Enter value: ", false); + zone.Smell = player.ReadInput(); + break; + case 9: //Exit + return; + } + } + + private void ParseInitialSelection(Int32 value) + { + switch (value) + { + case 1: //Enable/Disable Initial Realm + if (player.ActiveGame.InitialRealm == null) + { + player.Send("Zone Initial Realm editing canceled. You must have a Initial Realm defined before setting a Initial Zone."); + return; + } + + if (zone.IsInitialZone) + { + zone.IsInitialZone = false; + player.ActiveGame.InitialRealm.InitialZone = null; + } + else + { + zone.IsInitialZone = true; + player.ActiveGame.InitialRealm.InitialZone = zone; + } + + break; + case 9: //Exit + return; + } + + player.ActiveGame.Save(); + } + + private void UpdateZoneObjects(String oldName) + { + //Check if this Zone is the initial Zone. If so then we need to update the + //current Game so that when it launches, it checks the new Zone and not the old + //one. + if ((zone.IsInitialZone) && (player.ActiveGame.InitialRealm.Filename == zone.Realm)) + { + player.ActiveGame.InitialRealm.InitialZone = zone; + } + else + { + player.Send("Error: Unable to set this Zone as the initial Zone due to the parent Realm not being a Initial Realm."); + } + + //Loop through each player currently logged in and see if they are currently + //within the selected Zone. If they are then we need to change their current + //Zone to the new one. + foreach (BaseCharacter p in player.ActiveGame.GetPlayerCollection()) + { + if (p.Name.StartsWith("Base")) + continue; + + if (p.CurrentRoom.Zone == oldName) + { + p.CurrentRoom.Zone = zone.Filename; + p.Save(player.ActiveGame.DataPaths.Players); + } + } + + //Loop through every player on file to see if any are currently within + //the selected Realm. If they are, we need to edit their files so that they + //log-in next time into the correct Realm. Otherwise Admins will need to manually + //edit the files and move the players. + //This is done after scanning logged in players, as logged in players will of had + //their location already updated and files saved, preventing any need for us to + //modify their files again. + foreach (String file in Directory.GetFiles(player.ActiveGame.DataPaths.Players)) + { + BaseCharacter ch = new BaseCharacter(player.ActiveGame); + ch.Load(file); + if (ch.CurrentRoom.Zone == oldName) + { + ch.CurrentRoom.Zone = zone.Filename; + ch.Save(player.ActiveGame.DataPaths.Players); + } + } + + //Next, we need to loop through every Room within this Zone + //and update their Zones names to match the new one + foreach (Realm realm in player.ActiveGame.World.RealmCollection) + { + if (realm.InitialZone.Filename == oldName) + realm.InitialZone = zone; + + foreach (Zone z in realm.ZoneCollection) + { + foreach (Room r in zone.RoomCollection) + { + if (r.Zone == oldName) + r.Zone = zone.Filename; + + foreach (Door d in r.Doorways) + { + if (d.ArrivalRoom.Zone == oldName) + d.ArrivalRoom.Zone = zone.Filename; + if (d.DepartureRoom.Zone == oldName) + d.DepartureRoom.Zone = zone.Filename; + } + } + } + } + } + } +} diff --git a/MudEngine/Commands/CommandLogin.cs b/MudEngine/Commands/CommandLogin.cs index 74b198a..1b4eb31 100644 --- a/MudEngine/Commands/CommandLogin.cs +++ b/MudEngine/Commands/CommandLogin.cs @@ -149,6 +149,12 @@ namespace MudEngine.Commands //Now that we have no duplicate connections, load the real player. //no need to re-varify password as we have already done this above. player.Load(savedFile); + + //If this is a single player game then we need to assign the player to the game collection. + //Multiplayer games have this handled by the server automatically. + if (!player.ActiveGame.IsMultiplayer) + player.ActiveGame.GetPlayerCollection()[0] = player; + player.Send("Welcome back " + player.Name + "!"); } else diff --git a/MudEngine/GameManagement/GameWorld.cs b/MudEngine/GameManagement/GameWorld.cs index 1ea3fac..63f1fe0 100644 --- a/MudEngine/GameManagement/GameWorld.cs +++ b/MudEngine/GameManagement/GameWorld.cs @@ -190,6 +190,9 @@ namespace MudEngine.GameManagement /// public Realm GetRealm(String filename) { + if (!filename.ToLower().EndsWith(".realm")) + filename += ".realm"; + foreach (Realm r in RealmCollection) { if (r.Filename.ToLower() == filename.ToLower()) diff --git a/MudEngine/GameObjects/Environment/Realm.cs b/MudEngine/GameObjects/Environment/Realm.cs index 86d9ceb..493ccb1 100644 --- a/MudEngine/GameObjects/Environment/Realm.cs +++ b/MudEngine/GameObjects/Environment/Realm.cs @@ -28,7 +28,7 @@ namespace MudEngine.GameObjects.Environment /// /// The Initial Starting Zone for this Realm. /// - public Zone InitialZone { get; private set; } + public Zone InitialZone { get; set; } public Realm(GameManagement.Game game) : base(game) { @@ -82,6 +82,9 @@ namespace MudEngine.GameObjects.Environment List zones = new List(); + if (!filename.ToLower().EndsWith(".zone")) + filename += ".zone"; + foreach (Zone zone in ZoneCollection) { if (zone.Filename.ToLower() == filename.ToLower()) diff --git a/MudEngine/GameObjects/Environment/Zone.cs b/MudEngine/GameObjects/Environment/Zone.cs index d150cd9..b83312d 100644 --- a/MudEngine/GameObjects/Environment/Zone.cs +++ b/MudEngine/GameObjects/Environment/Zone.cs @@ -75,7 +75,7 @@ namespace MudEngine.GameObjects.Environment /// Gets the initial Room for this Zone. /// [Category("Environment Information")] - public Room InitialRoom { get; private set; } + public Room InitialRoom { get; set; } public Zone(GameManagement.Game game) : base(game) @@ -175,6 +175,8 @@ namespace MudEngine.GameObjects.Environment { List rooms = new List(); + if (!filename.ToLower().EndsWith(".room")) + filename += ".Room"; foreach (Room r in RoomCollection) { diff --git a/MudEngine/MudEngine.csproj b/MudEngine/MudEngine.csproj index f37cf81..03e0e11 100644 --- a/MudEngine/MudEngine.csproj +++ b/MudEngine/MudEngine.csproj @@ -54,6 +54,8 @@ + + diff --git a/MudGame/MudGame.csproj b/MudGame/MudGame.csproj index 9781045..93866d5 100644 --- a/MudGame/MudGame.csproj +++ b/MudGame/MudGame.csproj @@ -45,43 +45,46 @@ - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + + PreserveNewest + + PreserveNewest PreserveNewest - + PreserveNewest diff --git a/MudGame/Scripts/CommandCreate.cs b/MudGame/Scripts/AdminCommands/CommandCreate.cs similarity index 100% rename from MudGame/Scripts/CommandCreate.cs rename to MudGame/Scripts/AdminCommands/CommandCreate.cs diff --git a/MudGame/Scripts/CommandCreateRoom.cs b/MudGame/Scripts/AdminCommands/CommandCreateRoom.cs similarity index 83% rename from MudGame/Scripts/CommandCreateRoom.cs rename to MudGame/Scripts/AdminCommands/CommandCreateRoom.cs index 0feb6fa..20b2cc4 100644 --- a/MudGame/Scripts/CommandCreateRoom.cs +++ b/MudGame/Scripts/AdminCommands/CommandCreateRoom.cs @@ -45,6 +45,14 @@ class CommandCreateRoom : IGameCommand return; } + + if ((String.IsNullOrEmpty(player.CurrentRoom.Realm)) || (String.IsNullOrEmpty(player.CurrentRoom.Zone))) + { + player.Send("You are not currently within a pre-existing Zone."); + player.Send("Use the Teleport command to teleport yourself into a valid Zone before using the CreateRoom command."); + return; + } + Room r = new Room(player.ActiveGame); r.Realm = player.CurrentRoom.Realm; r.Zone = player.CurrentRoom.Zone; diff --git a/MudGame/Scripts/CommandLinkRoom.cs b/MudGame/Scripts/AdminCommands/CommandLinkRoom.cs similarity index 100% rename from MudGame/Scripts/CommandLinkRoom.cs rename to MudGame/Scripts/AdminCommands/CommandLinkRoom.cs diff --git a/MudGame/Scripts/CommandList.cs b/MudGame/Scripts/AdminCommands/CommandList.cs similarity index 100% rename from MudGame/Scripts/CommandList.cs rename to MudGame/Scripts/AdminCommands/CommandList.cs diff --git a/MudGame/Scripts/AdminCommands/CommandTeleport.cs b/MudGame/Scripts/AdminCommands/CommandTeleport.cs new file mode 100644 index 0000000..6421d31 --- /dev/null +++ b/MudGame/Scripts/AdminCommands/CommandTeleport.cs @@ -0,0 +1,101 @@ +/// +/// The List command is used to list filenames of a specified object type. +/// +public class CommandTeleport : IGameCommand +{ + /// + /// Used by the Command Engine to allow for overriding any other commands that contain the same name. + /// TODO: Does Overriding Commands still work? This is part of some old code I wrote several years back and might be broke. + /// + public Boolean Override { get; set; } + + /// + /// The name of the command. + /// If Override is set to true, this command will override any other command that contains the same name. + /// + public String Name { get; set; } + + /// + /// A collection of strings that contains helpfull information for this Command. + /// When the user enteres 'Help Exit' the game will print the content of this collection. + /// This is treated like a virtual book, each entry in the collection is printed as a new line. + /// + public List Help { get; set; } + + public CommandTeleport() + { + Help = new List(); + Help.Add("The Teleport command will teleport a player to a specified Room, regardless of where they are at."); + Help.Add("Usage: Teleport playername FullyQualifiedRoomPath"); + Help.Add("Example: Teleport Billy MyRealm>MyZone>MyRoom"); + } + + public void Execute(String command, BaseCharacter player) + { + command = command.Substring("teleport".Length).Trim(); + String[] data = command.ToLower().Split(' '); + + //Admin || GM only item listings. + if ((player.Role == SecurityRoles.Admin) || (player.Role == SecurityRoles.GM)) + { + if (data.Length == 0) + { + player.Send("Invalid operation. You must supply a username along with a fully qualified path name for the user to be teleported to."); + return; + } + else if (data.Length == 1) + { + player.Send("Invalid operation. You must supply a fully qualified path name for the user to be teleported."); + return; + } + else + { + foreach (BaseCharacter p in player.ActiveGame.GetPlayerCollection()) + { + if (p.Name.ToLower() == data[0].ToLower()) + { + String[] values = data[1].Split('>'); + + if (values.Length != 3) + { + player.Send("Invalid Operation. You must supply a fully qualified path name for the user to be teleported."); + return; + } + else + { + Realm r = player.ActiveGame.World.GetRealm(values[0]); + if (r == null) + { + player.Send("Invalid Operation. Supplied Realm does not exist."); + return; + } + + Zone z = r.GetZone(values[1])[0]; + if (z == null) + { + player.Send("Invalid operation. Supplied Zone does not exist."); + return; + } + + Room rm = z.GetRoom(values[2])[0]; + if (rm == null) + { + player.Send("Invalid operation. Supplied Room does not exist."); + return; + } + + p.CurrentRoom = rm; + + //Tell the teleported player that they have been moved. + p.Send("You have been teleported by some higher power."); + IGameCommand gc = CommandEngine.GetCommand("CommandLook"); + gc.Execute("Look", p); + + player.Send("Teleporting completed."); + } + } + } + } + } + } +} \ No newline at end of file diff --git a/MudGame/Scripts/EarthGame.cs b/MudGame/Scripts/EarthGame.cs index 325321a..db60268 100644 --- a/MudGame/Scripts/EarthGame.cs +++ b/MudGame/Scripts/EarthGame.cs @@ -39,7 +39,7 @@ public class EarthGame : Game //Create a new instance of our California realm script, we must pass a reference to our EarthGame //to the script so that it may add the Realm to our Game world. That is done by using the 'this' keyword. - Cali = new WorldCalifornia(this); + //Cali = new WorldCalifornia(this); //Calling the create method within the california script. //Cali.Create(); diff --git a/MudGame/Scripts/CommandClear.cs b/MudGame/Scripts/PlayerCommands/CommandClear.cs similarity index 100% rename from MudGame/Scripts/CommandClear.cs rename to MudGame/Scripts/PlayerCommands/CommandClear.cs diff --git a/MudGame/Scripts/CommandExit.cs b/MudGame/Scripts/PlayerCommands/CommandExit.cs similarity index 100% rename from MudGame/Scripts/CommandExit.cs rename to MudGame/Scripts/PlayerCommands/CommandExit.cs diff --git a/MudGame/Scripts/CommandGetTime.cs b/MudGame/Scripts/PlayerCommands/CommandGetTime.cs similarity index 100% rename from MudGame/Scripts/CommandGetTime.cs rename to MudGame/Scripts/PlayerCommands/CommandGetTime.cs diff --git a/MudGame/Scripts/CommandHelp.cs b/MudGame/Scripts/PlayerCommands/CommandHelp.cs similarity index 100% rename from MudGame/Scripts/CommandHelp.cs rename to MudGame/Scripts/PlayerCommands/CommandHelp.cs diff --git a/MudGame/Scripts/CommandLook.cs b/MudGame/Scripts/PlayerCommands/CommandLook.cs similarity index 100% rename from MudGame/Scripts/CommandLook.cs rename to MudGame/Scripts/PlayerCommands/CommandLook.cs diff --git a/MudGame/Scripts/CommandSave.cs b/MudGame/Scripts/PlayerCommands/CommandSave.cs similarity index 100% rename from MudGame/Scripts/CommandSave.cs rename to MudGame/Scripts/PlayerCommands/CommandSave.cs diff --git a/MudGame/Scripts/CommandSay.cs b/MudGame/Scripts/PlayerCommands/CommandSay.cs similarity index 100% rename from MudGame/Scripts/CommandSay.cs rename to MudGame/Scripts/PlayerCommands/CommandSay.cs diff --git a/MudGame/Scripts/CommandWalk.cs b/MudGame/Scripts/PlayerCommands/CommandWalk.cs similarity index 100% rename from MudGame/Scripts/CommandWalk.cs rename to MudGame/Scripts/PlayerCommands/CommandWalk.cs