MudEngine:

- Deleted BaseAI as AI will be built into BaseCharacter and enabled/disabled via the already existing IsControlled property.
 - Added BaseStats class which will manage all of the stats used by characters. It was decided this should be a separate class that players can extend off of and change how stats are handled in their games without having to re-write large chunks of player code.
 - Began adding better commenting through-out the project. CommandExit.cs, CommandGetTime.cs have been given much better commenting. These will ultimately be converted to Scripts for developers to modify.
This commit is contained in:
Scionwest_cp 2010-08-22 00:06:20 -07:00
parent ce910a5fd0
commit cc2213a7b3
7 changed files with 354 additions and 81 deletions

View file

@ -1,9 +1,11 @@
using System;
//Microsoft.NET Framework
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
//Mud Designer Game Engine
using MudEngine.FileSystem;
using MudEngine.GameObjects.Characters;
using MudEngine.GameManagement;
@ -12,45 +14,73 @@ using MudEngine.GameObjects.Environment;
namespace MudEngine.Commands
{
/// <summary>
/// The Exit command is used to exit the MUD game.
/// Using this command while connected to a MUD server will perform a disconnect from the server.
/// Using the command while running the game in offline mode will simply shut down the game.
/// </summary>
public class CommandExit : IGameCommand
{
/// <summary>
/// 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.
/// </summary>
public Boolean Override { get; set; }
/// <summary>
/// The name of the command.
/// If Override is set to true, this command will override any other command that contains the same name.
/// </summary>
public String Name { get; set; }
/// <summary>
/// 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.
/// </summary>
public List<String> Help { get; set; }
/// <summary>
/// Constructor for the class.
/// </summary>
public CommandExit()
{
//Instance the help collection and add our help information to it.
//Typically the Help content is placed within the constructor, but this particular help document
//needs to access information from the player, so we will build our Help collection in the Execute command.
Help = new List<string>();
Help.Add("Exits the game cleanly.");
}
/// <summary>
/// Executes the command.
/// This method is called from the Command Engine, it is not recommended that you call this method directly.
/// </summary>
/// <param name="command"></param>
/// <param name="player"></param>
public void Execute(String command, BaseCharacter player)
{
//Check if the game is multiplayer.
//Multiplayer games require disconnecting from the server and letting other players in the same Room know
//that this player has left.
if (player.ActiveGame.IsMultiplayer)
{
//Let other players know that the user walked in.
for (Int32 i = 0; i != player.ActiveGame.GetPlayerCollection().Length; i++)
{
if (player.ActiveGame.GetPlayerCollection()[i].Name == player.Name)
continue;
//Query the Active Games Player collection so that we can build a collection of Players that need to be
//informed of the Player disconnecting from the Server.
var playerQuery =
from p in player.ActiveGame.GetPlayerCollection()
where !p.Name.StartsWith("New") && p.Name != player.Name && p.CurrentWorldLocation == player.CurrentWorldLocation
select p;
String room = player.ActiveGame.GetPlayerCollection()[i].CurrentRoom.Name;
String realm = player.ActiveGame.GetPlayerCollection()[i].CurrentRoom.Realm;
String zone = player.ActiveGame.GetPlayerCollection()[i].CurrentRoom.Zone;
if ((room == player.CurrentRoom.Name) && (realm == player.CurrentRoom.Realm) && (zone == player.CurrentRoom.Zone))
{
player.ActiveGame.GetPlayerCollection()[i].Send(player.Name + " has left.");
}
}
//Inform each player found in our LINQ query that the player has disconnected from the Server.
foreach (BaseCharacter p in playerQuery)
p.Send(player.Name + " has left."); ;
//TODO: If a player is in a Group then s/he needs to be removed upon disconnecting.
player.Disconnect();
}
else
{
//Save the player prior to attempting to shutdown.
//Player saving is handled in the server disconnect code but not in game shutdown.
player.Save(player.ActiveGame.DataPaths.Players);
//Call the game's shutdown method which will save all objects and exit the game gracefully.
player.ActiveGame.Shutdown();
}
}

View file

@ -1,27 +1,59 @@
using System;
//Microsoft.NET Framework
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//Mud Designer Game Engine
using MudEngine.GameObjects.Characters;
using MudEngine.GameManagement;
namespace MudEngine.Commands
{
public class CommandGetTime : MudEngine.GameManagement.IGameCommand
/// <summary>
/// The GetTime command is used to print the current in-game time to the player.
/// This command will print the day, month and year along with hour, minute and seconds.
/// </summary>
public class CommandGetTime : IGameCommand
{
/// <summary>
/// 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.
/// </summary>
public Boolean Override { get; set; }
/// <summary>
/// The name of the command.
/// If Override is set to true, this command will override any other command that contains the same name.
/// </summary>
public String Name { get; set; }
public Boolean Override { get; set; }
/// <summary>
/// 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.
/// </summary>
public List<String> Help { get; set; }
/// <summary>
/// Constructor for the class.
/// </summary>
public CommandGetTime()
{
//Instance the help collection and add our help information to it.
Help = new List<string>();
Help.Add("Gives you the current time and date in the game world.");
}
/// <summary>
/// Executes the Command.
/// This method is called from the Command Engine, it is not recommended that you call this method directly.
/// </summary>
/// <param name="command"></param>
/// <param name="player"></param>
public void Execute(String command, BaseCharacter player)
{
//Send the returned String containing the World Time to the player.
player.Send(player.ActiveGame.WorldTime.GetCurrentWorldTime());
}
}

View file

@ -1,9 +1,11 @@
using System;
//Microsoft.NET Framework
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
//Mud Designer Game Engine
using MudEngine.FileSystem;
using MudEngine.GameManagement;
using MudEngine.GameObjects;
@ -12,29 +14,75 @@ using MudEngine.GameObjects.Environment;
namespace MudEngine.Commands
{
/// <summary>
/// The LinkRoom command is used to Link two previously created Rooms together.
/// Rooms linked together can be traversed by players.
/// This command is used to link Rooms dynamically during run-time by Admins, allowing environments to be created
/// and traversed on-the-fly without the need to modify scripts and re-start the server.
/// </summary>
public class CommandLinkRoom : IGameCommand
{
/// <summary>
/// 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.
/// </summary>
public Boolean Override { get; set; }
/// <summary>
/// The name of the command.
/// If Override is set to true, this command will override any other command that contains the same name.
/// </summary>
public String Name { get; set; }
/// <summary>
/// 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.
/// </summary>
public List<String> Help { get; set; }
/// <summary>
/// Constructor for the class.
/// </summary>
public CommandLinkRoom()
{
//Instance the help collection and add our help information to it.
Help = new List<string>();
Help.Add("Use this to link two previously created Rooms together");
Help.Add("Note that this command is not fully implemented and does not work.");
Help.Add("Use this to link two previously created Rooms together.");
//Incase Admins try to use the command, they will know that it's broken.
//Don't convert this class into a Script until it is fully completed.
Help.Add("NOTE: This command is not fully implemented and does not work.");
}
/// <summary>
/// Executes the command.
/// This method is called from the Command Engine, it is not recommended that you call this method directly.
/// </summary>
/// <param name="command"></param>
/// <param name="player"></param>
public void Execute(String command, BaseCharacter player)
{
//Check if the Player has the correct privileges to Link Rooms together.
//If they are not a Admin or GM then the command will bail.
//This creates the illusion that this command possibly doesn't exist.
if ((player.Role != SecurityRoles.Admin) && (player.Role != SecurityRoles.GM))
{
player.Send("Invalid Command.");
return;
}
//Build the Menu system that will be displayed to Admins.
player.Send("Room linkage tool");
player.Send("Please select an option.");
player.Send("1: Link Room");
player.Send("2: Exit");
//Read the input from the Admin.
string input = player.ReadInput();
Int32 value = 0;
//Attempt to convert their input from a String into a numerical value.
//If they entered a non-numerical value, then the method will exit
try
{
value = Convert.ToInt32(input);
@ -45,122 +93,204 @@ namespace MudEngine.Commands
return;
}
//Ask what Room the Admin wants to use as the Departing Room.
//Departing Rooms will be where the travel direction originates from.
//meaning if the Admin selects West as the traveling direction, then traveling West will exit the
//Departing Room and enter the Arrival Room.
player.Send("");
player.Send("Please select which Realm your departing Room resides within:");
player.Send("");
//Instance a new Realm that we can use to reference an existing Realm so that we can find the
//Rooms within it that the Admin is looking for.
Boolean isValidRealm = false;
Realm realm = new Realm(player.ActiveGame);
//Create a Loop incase the Admin enters an invalid Realm, we can just loop
//back and re-ask the Admin the enter a valid Realm name.
while (!isValidRealm)
{
isValidRealm = true;//Default to true, assume the user entered a valid name.
foreach (Realm r in player.ActiveGame.World.RealmCollection)
{
player.Send(r.Filename + " | ", false);
}
//Now that we are in the loop, set the isValidRealm to true, as we will assume that
//the user will enter a valid Realm name on the first shot. If we can't find a matching
//Realm, then this will get set to false once iterating through Realms is completed.
isValidRealm = true;
//Print each Realm out to the Admin so they may see a complete list to choose from.
//This is the Realm that their first Room will reside within.
//TODO: Currently only linking Rooms within the same Realm/Zone is supported. Need to fix that.
foreach (Realm r in player.ActiveGame.World.RealmCollection)
player.Send(r.Filename + " | ", false);
//As for the Admins selection, we will place the Admins input on the same line
//as the last message sent to the Admin by setting the newLine parameter to false.
player.Send("");
player.Send("Selection: ", false);
//Get the Admins input that should specify what Realm they are wanting.
input = player.ReadInput();
//Check if the Admin entered 'Cancel'. If so, then cancel the Link process.
if (input.ToLower() == "cancel")
{
player.Send("Room Linking aborted.");
return;
}
//Ensure it's a valid name, if not then loop back and try again.
foreach (Realm r in player.ActiveGame.World.RealmCollection)
{
if (r.Filename.ToLower() == input.ToLower())
{
isValidRealm = true;
realm = r;
break;
}
else
{
isValidRealm = false;
}
}
//Query the Active Games world collection, finding Realms that match the filename entered by the Admin
var realmQuery =
from r in player.ActiveGame.World.RealmCollection
where r.Filename.ToLower() == input.ToLower()
select r;
if (!isValidRealm)
//Check if the query contains a Realm.
if (realmQuery.FirstOrDefault() != null)
{
//The query does in-fact contain a valid Realm. Assign it to our realm field for use later.
realm = realmQuery.FirstOrDefault();
//We can set this to true, allowing us to exit out of the loop.
isValidRealm = true;
}
//If the query does not contain a Realm, then we ensure that the loop will continue by forcing
//isValidRealm back to false.
else
{
isValidRealm = false;
//Let the Admin know that they entered an invalid Realm name and that they need to try again.
player.Send("That Realm does not exist! Please try again.");
}
}
//Let the Admin know that they need to now select which Zone the Room they are wanting to link resides within.
player.Send("");
player.Send("Please select which Zone your departing Room resides within:");
player.Send("");
//Instance a new Zone that we can use to reference an existing Zone so that we can find the
//Rooms within it that the Admin is looking for.
Boolean isValidZone = false;
Zone zone = new Zone(player.ActiveGame);
//Create a Loop incase the Admin enters an invalid Zone, we can just loop
//back and re-ask the Admin the enter a valid Zone name.
while (!isValidZone)
{
isValidZone = true;//Default to true, assume the user entered a valid name.
//Now that we are in the loop, set the isValidZone to true, as we will assume that
//the user will enter a valid Zone name on the first shot. If we can't find a matching
//Zone, then this will get set to false once iterating through Zone is completed.
isValidZone = true;
//Print each Zone out to the Admin so they may see a complete list to choose from.
//This is the Zone that their first Room will reside within.
//TODO: Currently only linking Rooms within the same Realm/Zone is supported. Need to fix that.
foreach (Zone z in realm.ZoneCollection)
{
player.Send(z.Filename + " | ", false);
}
//As for the Admins selection, we will place the Admins input on the same line
//as the last message sent to the Admin by setting the newLine parameter to false.
player.Send("");
player.Send("Selection: ", false);
//Get the Admins input that should specify what Zone they are wanting.
input = player.ReadInput();
//Check if the Admin entered 'Cancel'. If so, then cancel the Link process.
if (input.ToLower() == "cancel")
{
player.Send("Room Linking aborted.");
return;
}
//Ensure it's a valid name, if not then loop back and try again.
foreach (Zone z in realm.ZoneCollection)
{
if (z.Filename.ToLower() == input.ToLower())
{
isValidZone = true;
zone = z;
break;
}
else
{
isValidZone = false;
}
}
//Query the stored Realm's Zone collection, finding Zones that match the filename entered by the Admin
var zoneQuery =
from z in realm.ZoneCollection
where z.Filename.ToLower() == input.ToLower()
select z;
if (!isValidZone)
//Check if the query contains a Zone.
if (zoneQuery.FirstOrDefault() != null)
{
//The query does in-fact contain a valid Zone. Assign it to our zone field for use later.
zone = zoneQuery.FirstOrDefault();
//We can set this to true, allowing us to exit out of the loop.
isValidZone = true;
}
//If the query does not contain a Zone, then we ensure that the loop will continue by forcing
//isValidZone back to false.
else
{
isValidZone = false;
//Let the Admin know that they entered an invalid Zone name and that they need to try again.
player.Send("That Zone does not exist! Please try again.");
}
}
//Let the Admin know that they need to now select Room they are wanting to link as the departure Room
player.Send("");
player.Send("Please select which Room that you wish to be the departing Room:");
player.Send("");
//Instance a new Room that we can store a reference to a existing Room.
//We will use this reference to link the departure and arrival Rooms together.
Boolean isValidRoom = false;
Room departingRoom = new Room(player.ActiveGame);
//Create a Loop incase the Admin enters an invalid Room, we can just loop
//back and re-ask the Admin the enter a valid Room name.
while (!isValidRoom)
{
isValidRoom = true;//Default to true, assume the user entered a valid name.
//Now that we are in the loop, set the isValidRoom to true, as we will assume that
//the user will enter a valid Room name on the first shot. If we can't find a matching
//Room, then this will get set to false once iterating through Room is completed.
isValidRoom = true;
//Print each Room out to the Admin so they may see a complete list to choose from.
//This will be their departing Room.
//TODO: Currently only linking Rooms within the same Realm/Zone is supported. Need to fix that.
foreach (Room r in zone.RoomCollection)
{
player.Send(r.Filename + " | ", false);
}
//As for the Admins selection, we will place the Admins input on the same line
//as the last message sent to the Admin by setting the newLine parameter to false.
player.Send("");
player.Send("Selection: ", false);
//Get the Admins input that should specify what Room they are wanting.
input = player.ReadInput();
//Check if the Admin entered 'Cancel'. If so, then cancel the Link process.
if (input.ToLower() == "cancel")
{
player.Send("Room Linking aborted.");
return;
}
//Query the referenced zone's Room collection, finding Rooms that match the filename entered by the Admin
var roomQuery =
from r in zone.RoomCollection
where r.Filename.ToLower() == input.ToLower()
select r;
//Check if the query contains a Room.
if (roomQuery.FirstOrDefault() != null)
{
//The query does in-fact contain a valid Room. Assign it to our departingRoom field for use later.
departingRoom = roomQuery.FirstOrDefault();
//We can set this to true, allowing us to exit out of the loop.
isValidRoom = true;
}
//If the query does not contain a Room, then we ensure that the loop will continue by forcing
//isValidRoom back to false.
else
{
isValidRoom = false;
//Let the Admin know that they entered an invalid Room name and that they need to try again.
player.Send("That Room does not exist! Please try again.");
}
//Ensure it's a valid name, if not then loop back and try again.
foreach (Room r in zone.RoomCollection)
{

View file

@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MudEngine.GameManagement;
namespace MudEngine.GameObjects.Characters
{
public class BaseAI : BaseCharacter
{
public BaseAI(Game game) : base(game)
{
}
}
}

View file

@ -26,10 +26,33 @@
/// </summary>
public Room CurrentRoom { get; set; }
public String CurrentWorldLocation
{
get
{
return CurrentRoom.Realm + "." + CurrentRoom.Zone + "." + CurrentRoom.Filename;
}
}
/// <summary>
/// Gets or Sets if this Character is controlled by the user. If not user controlled then it will be AI controlled.
/// </summary>
public Boolean IsControlled { get; set; }
public Boolean IsControlled
{
get
{
return _IsControlled;
}
set
{
if (value)
{
//TODO: Begin AI initialization
}
_IsControlled = value;
}
}
private Boolean _IsControlled;
/// <summary>
/// Gets if this user has Admin privileges or not.

View file

@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MudEngine.GameObjects.Characters
{
/// <summary>
/// This class is the base class that handles the managing of a Characters stats.
/// It was decided to place stats within their own class, to allow for developers to easily add additional
/// stats or adjust how stats are used within their MUD's without having to modify the Character code themselves.
/// </summary>
public class BaseStats
{
/// <summary>
/// Strength is a measure of muscle, endurance and stamina combined.
/// Strength affects the ability of characters to lift and carry weights, melee attack rolls,
/// damage rolls (for both melee and ranged weapons,) the Jump, Climb, and Swim skills,
/// several combat actions, and general checks involving moving or breaking stubborn objects.
/// </summary>
public Int32 Strength { get; set; }
/// <summary>
/// Dexterity encompasses a number of physical attributes including hand-eye coordination, agility,
/// reflexes, fine motor skills, balance and speed of movement; a high dexterity score indicates
/// superiority in all these attributes. Dexterity affects characters with regard to initiative in combat,
/// ranged attack rolls, Armor Class, Reflex saves, and the Balance, Escape Artist, Hide, Move Silently,
/// Open Lock, Ride, Sleight of Hand, Tumble, and Use Rope skills. It also affects the number of additional
/// attacks of opportunity granted by the Combat Reflexes feat. Dexterity is the ability most influenced by
/// outside influences (such as armor).
/// </summary>
public Int32 Dexterity { get; set; }
/// <summary>
/// Constitution is a term which encompasses the character's physique, toughness, health and resistance to disease and poison.
/// The higher a character's Constitution, the more hit points that character will have.
/// Constitution also is important for Fortitude saves, the Concentration skill, and fatigue-based general checks.
/// Constitution also determines the duration of a barbarian's rage.
/// Unlike the other ability scores, which render the character unconscious or immobile when they hit 0,
/// having 0 Constitution is fatal.
/// </summary>
public Int32 Constitution { get; set; }
/// <summary>
/// Intelligence is similar to IQ, but also includes mnemonic ability, reasoning and learning ability outside
/// those measured by the written word. Intelligence dictates the number of languages a character can learn,
/// and it influences the number of spells a preparation-based arcane spellcaster (like a Wizard) may cast per
/// day, and the effectiveness of said spells. It also affects how many skill points a character gains per level,
/// the Appraise, Craft, Decipher Script, Disable Device, Forgery, Knowledge, Search, and Spellcraft skills,
/// and bardic knowledge checks.
/// </summary>
public Int32 Intelligence { get; set; }
/// <summary>
/// Wisdom is a composite term for the characters enlightenment, judgement, wile, willpower and intuitiveness.
/// Wisdom influences the number of spells a divine spellcaster (like clerics, druids, paladins, and rangers)
/// can cast per day, and the effectiveness of said spells. It also affects Will saving throws, the Heal, Listen,
/// Profession, Sense Motive, Spot, and Survival skills, the effectiveness of the Stunning Fist feat, and a
/// monk's quivering palm attack.
/// </summary>
public Int32 Wisdom { get; set; }
/// <summary>
/// Charisma is the measure of the character's combined physical attractiveness, persuasiveness, and personal magnetism.
/// A generally non-beautiful character can have a very high charisma due to strong measures of the other two aspects of charisma.
/// Charisma influences how many spells spontaneous arcane spellcasters (like sorcerers and bards) can cast per day, and the
/// effectiveness of said spells. It also affects Bluff, Diplomacy, Disguise, Gather Information, Handle Animal,
/// Intimidate, Perform, and Use Magic Device checks, how often and how effectively clerics and paladins can turn
/// undead, the wild empathy of druids and rangers, and a paladin's lay on hands ability.
/// </summary>
public Int32 Charisma { get; set; }
}
}

View file

@ -74,8 +74,8 @@
<Compile Include="GameManagement\SecurityRoles.cs" />
<Compile Include="GameObjects\Bag.cs" />
<Compile Include="GameObjects\BaseObject.cs" />
<Compile Include="GameObjects\Characters\BaseAI.cs" />
<Compile Include="GameObjects\Characters\BaseCharacter.cs" />
<Compile Include="GameObjects\Characters\BaseStats.cs" />
<Compile Include="GameObjects\Environment\Door.cs" />
<Compile Include="GameObjects\Environment\MyRealm.cs" />
<Compile Include="GameObjects\Environment\Realm.cs" />