diff options
author | Thomas Leyh <leyh.thomas@web.de> | 2016-07-24 08:14:18 +0200 |
---|---|---|
committer | Thomas Leyh <leyh.thomas@web.de> | 2016-07-24 08:14:18 +0200 |
commit | ced3d03bdb3ce866d832e03fb212865140905a9a (patch) | |
tree | 2a16c2063a46d3c354ce1585029dda3124f6ad93 /V3/Data | |
parent | 0394dccaf06e1009e591a6ff4d645895574724c1 (diff) | |
download | V3-ced3d03bdb3ce866d832e03fb212865140905a9a.tar.gz V3-ced3d03bdb3ce866d832e03fb212865140905a9a.tar.bz2 |
Diffstat (limited to 'V3/Data')
-rw-r--r-- | V3/Data/DebugMode.cs | 21 | ||||
-rw-r--r-- | V3/Data/GameState.cs | 64 | ||||
-rw-r--r-- | V3/Data/IGameStateManager.cs | 20 | ||||
-rw-r--r-- | V3/Data/IOptionsManager.cs | 18 | ||||
-rw-r--r-- | V3/Data/IPathManager.cs | 30 | ||||
-rw-r--r-- | V3/Data/ISaveGame.cs | 25 | ||||
-rw-r--r-- | V3/Data/ISaveGameManager.cs | 25 | ||||
-rw-r--r-- | V3/Data/Internal/GameStateManager.cs | 81 | ||||
-rw-r--r-- | V3/Data/Internal/OptionsManager.cs | 65 | ||||
-rw-r--r-- | V3/Data/Internal/PathManager.cs | 51 | ||||
-rw-r--r-- | V3/Data/Internal/SaveGame.cs | 65 | ||||
-rw-r--r-- | V3/Data/Internal/SaveGameManager.cs | 88 | ||||
-rw-r--r-- | V3/Data/Options.cs | 105 |
13 files changed, 658 insertions, 0 deletions
diff --git a/V3/Data/DebugMode.cs b/V3/Data/DebugMode.cs new file mode 100644 index 0000000..b93ae7a --- /dev/null +++ b/V3/Data/DebugMode.cs @@ -0,0 +1,21 @@ +namespace V3.Data +{ + /// <summary> + /// A debug level that can be set by the player. + /// </summary> + public enum DebugMode + { + /// <summary> + /// Disable all debug utils. + /// </summary> + Off, + /// <summary> + /// Show the FPS counter. + /// </summary> + Fps, + /// <summary> + /// Show all debug information. + /// </summary> + Full + } +} diff --git a/V3/Data/GameState.cs b/V3/Data/GameState.cs new file mode 100644 index 0000000..b38ec46 --- /dev/null +++ b/V3/Data/GameState.cs @@ -0,0 +1,64 @@ +using Microsoft.Xna.Framework; +using System; +using System.Collections.Generic; +using V3.AI; +using V3.Objects; + +namespace V3.Data +{ + /// <summary> + /// Stores the current state of the game (the data that must be stored in + /// a save game). All members should be public and serializable. + /// </summary> + [Serializable] + public sealed class GameState + { + public List<CreatureData> mCreatures = new List<CreatureData>(); + public List<Rectangle> mFog = new List<Rectangle>(); + public Vector2 mCameraPosition; + public AiState mAiState = AiState.Idle; + } + + public enum CreatureType + { + FemalePeasant, + King, + KingsGuard, + Knight, + MalePeasant, + Meatball, + Necromancer, + Prince, + Skeleton, + SkeletonHorse, + Zombie + } + + public sealed class CreatureData + { + public CreatureType Type { get; set; } + public int Id { get; set; } + public int Life { get; set; } + public int MaxLife { get; set; } + public int Attack { get; set; } + public TimeSpan Recovery { get; set; } + public bool IsUpgraded { get; set; } + public float PositionX { get; set; } + public float PositionY { get; set; } + public MovementDirection MovementDirection { get; set; } + public MovementState MovementState { get; set; } + public MovementData MovementData { get; set; } + public int IsAttackingId { get; set; } + public bool Mounted { get; set; } + public int SkeletonId { get; set; } + // IsAttackingBuilding + } + + public sealed class MovementData + { + public List<Vector2> Path { get; set; } + public int Step { get; set; } + public Vector2 LastMovement { get; set; } + public bool IsMoving { get; set; } + } +} diff --git a/V3/Data/IGameStateManager.cs b/V3/Data/IGameStateManager.cs new file mode 100644 index 0000000..3a7f901 --- /dev/null +++ b/V3/Data/IGameStateManager.cs @@ -0,0 +1,20 @@ +namespace V3.Data +{ + /// <summary> + /// Stores the current game state. + /// </summary> + public interface IGameStateManager + { + /// <summary> + /// Stores the current game state and returns it. + /// </summary> + /// <returns>the current game state</returns> + GameState GetGameState(); + + /// <summary> + /// Restores the given game state. + /// </summary> + /// <param name="gameState">the game state to restore</param> + void LoadGameState(GameState gameState); + } +} diff --git a/V3/Data/IOptionsManager.cs b/V3/Data/IOptionsManager.cs new file mode 100644 index 0000000..6910107 --- /dev/null +++ b/V3/Data/IOptionsManager.cs @@ -0,0 +1,18 @@ +namespace V3.Data +{ + /// <summary> + /// Handles the storing and loading of game options to the hard disk. + /// </summary> + public interface IOptionsManager + { + /// <summary> + /// The current options. + /// </summary> + Options Options { get; } + + /// <summary> + /// Saves the current options to the hard disk. + /// </summary> + void SaveOptions(); + } +} diff --git a/V3/Data/IPathManager.cs b/V3/Data/IPathManager.cs new file mode 100644 index 0000000..5574b35 --- /dev/null +++ b/V3/Data/IPathManager.cs @@ -0,0 +1,30 @@ +namespace V3.Data +{ + /// <summary> + /// Provides access to the default applications path, i. e. the + /// directories where save games, achievements and other persistent data + /// can be stored. + /// </summary> + public interface IPathManager + { + /// <summary> + /// The base directory for persistent application data. + /// </summary> + string AppDirectory { get; } + + /// <summary> + /// The directory for save games. + /// </summary> + string SaveGameDirectory { get; } + + /// <summary> + /// The file to store the options in. + /// </summary> + string OptionsFile { get; } + + /// <summary> + /// Creates the application directories that do not already exist. + /// </summary> + void CreateMissingDirectories(); + } +}
\ No newline at end of file diff --git a/V3/Data/ISaveGame.cs b/V3/Data/ISaveGame.cs new file mode 100644 index 0000000..6f954e1 --- /dev/null +++ b/V3/Data/ISaveGame.cs @@ -0,0 +1,25 @@ +using System; + +namespace V3.Data +{ + /// <summary> + /// Stores a game state with some metadata. + /// </summary> + public interface ISaveGame : IComparable<ISaveGame> + { + /// <summary> + /// The creation time of this save game in local time. + /// </summary> + DateTime Timestamp { get; set; } + + /// <summary> + /// The compability version of this save game. + /// </summary> + int Version { get; set; } + + /// <summary> + /// The data stored in this save game. + /// </summary> + GameState GameState { get; set; } + } +}
\ No newline at end of file diff --git a/V3/Data/ISaveGameManager.cs b/V3/Data/ISaveGameManager.cs new file mode 100644 index 0000000..f4e810f --- /dev/null +++ b/V3/Data/ISaveGameManager.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + +namespace V3.Data +{ + /// <summary> + /// Stores and manages the game state in save games. + /// </summary> + public interface ISaveGameManager + { + /// <summary> + /// Creates and persists a new save game of the given data with the + /// title. + /// </summary> + /// <param name="gameState">the data to store</param> + void CreateSaveGame(GameState gameState); + + /// <summary> + /// Loads all available save games and returns them ordered by the + /// creation date. + /// </summary> + /// <returns>a list of all available save games, orderd by creation + /// data</returns> + List<ISaveGame> GetSaveGames(); + } +}
\ No newline at end of file diff --git a/V3/Data/Internal/GameStateManager.cs b/V3/Data/Internal/GameStateManager.cs new file mode 100644 index 0000000..53ef3de --- /dev/null +++ b/V3/Data/Internal/GameStateManager.cs @@ -0,0 +1,81 @@ +using System.Collections.Generic; +using V3.Camera; +using V3.Map; +using V3.Objects; + +namespace V3.Data.Internal +{ + /// <summary> + /// Default implementation of IGameStateManager. + /// </summary> + // ReSharper disable once ClassNeverInstantiated.Global + internal sealed class GameStateManager : IGameStateManager + { + private readonly CameraManager mCameraManager; + private readonly CreatureFactory mCreatureFactory; + private readonly IMapManager mMapManager; + private readonly IObjectsManager mObjectsManager; + + public GameStateManager(CameraManager cameraManager, CreatureFactory creatureFactory, + IMapManager mapManager, IObjectsManager objectsManager) + { + mCameraManager = cameraManager; + mCreatureFactory = creatureFactory; + mMapManager = mapManager; + mObjectsManager = objectsManager; + } + + /// <summary> + /// Restores the given game state. + /// </summary> + public GameState GetGameState() + { + var gameState = new GameState(); + foreach (var obj in mObjectsManager.CreatureList) + { + gameState.mCreatures.Add(obj.SaveData()); + } + gameState.mCameraPosition = mCameraManager.GetCamera().Location; + return gameState; + } + + /// <summary> + /// Restores the given game state. + /// </summary> + /// <param name="gameState">the game state to restore</param> + public void LoadGameState(GameState gameState) + { + mObjectsManager.Clear(); + mObjectsManager.ImportMapObjects(mMapManager.GetObjects()); + var creatures = new Dictionary<int, ICreature>(); + + // load creatures + foreach (var creatureData in gameState.mCreatures) + { + ICreature creature = mCreatureFactory.CreateCreature(creatureData.Type, creatureData.Id); + if (creature == null) + continue; + creature.LoadData(creatureData); + if (creature is Necromancer) + mObjectsManager.CreatePlayerCharacter((Necromancer) creature); + else if (creature is King) // || creature is Prince + mObjectsManager.CreateBoss(creature); + else + mObjectsManager.CreateCreature(creature); + + creatures.Add(creature.Id, creature); + } + + // fix references + foreach (var creatureData in gameState.mCreatures) + { + if (!creatures.ContainsKey(creatureData.Id)) + continue; + creatures[creatureData.Id].LoadReferences(creatureData, creatures); + } + + if (mCameraManager.GetCamera() is CameraScrolling) + mCameraManager.GetCamera().Location = gameState.mCameraPosition; + } + } +} diff --git a/V3/Data/Internal/OptionsManager.cs b/V3/Data/Internal/OptionsManager.cs new file mode 100644 index 0000000..d581ba5 --- /dev/null +++ b/V3/Data/Internal/OptionsManager.cs @@ -0,0 +1,65 @@ +using System.IO; +using System.Runtime.Serialization; +using System.Xml.Serialization; +using Ninject; + +namespace V3.Data.Internal +{ + /// <summary> + /// Default implementation of IOptionsManager. + /// </summary> + // ReSharper disable once ClassNeverInstantiated.Global + internal sealed class OptionsManager : IOptionsManager, IInitializable + { + /// <summary> + /// The current options. + /// </summary> + public Options Options { get; private set; } + + private readonly IPathManager mPathManager; + private readonly XmlSerializer mSerializer = new XmlSerializer(typeof(Options)); + + /// <summary> + /// Creates a new OptionsManager. + /// </summary> + public OptionsManager(IPathManager pathManager) + { + mPathManager = pathManager; + } + + public void Initialize() + { + Options = LoadOptions(); + } + + /// <summary> + /// Saves the current options to the hard disk. + /// </summary> + public void SaveOptions() + { + var stream = new FileStream(mPathManager.OptionsFile, FileMode.Create, FileAccess.Write); + mSerializer.Serialize(stream, Options); + stream.Close(); + } + + private Options LoadOptions() + { + if (!File.Exists(mPathManager.OptionsFile)) + return new Options(); + var stream = new FileStream(mPathManager.OptionsFile, FileMode.Open, FileAccess.Read); + try + { + return (Options)mSerializer.Deserialize(stream); + } + catch (SerializationException) + { + // ignore so far + } + finally + { + stream.Close(); + } + return new Options(); + } + } +} diff --git a/V3/Data/Internal/PathManager.cs b/V3/Data/Internal/PathManager.cs new file mode 100644 index 0000000..3f4ad9d --- /dev/null +++ b/V3/Data/Internal/PathManager.cs @@ -0,0 +1,51 @@ +using System; +using System.IO; + +namespace V3.Data.Internal { + /// <summary> + /// Default implementation of IPathManager. + /// </summary> + // ReSharper disable once ClassNeverInstantiated.Global + internal sealed class PathManager : IPathManager + { + /// <summary> + /// The base directory for persistent application data. + /// </summary> + public string AppDirectory { get; } + + /// <summary> + /// The file to store the options in. + /// </summary> + public string OptionsFile { get; } + + /// <summary> + /// The directory for save games. + /// </summary> + public string SaveGameDirectory { get; } + + /// <summary> + /// Creates a new path manager and initializes the paths, but does not + /// create the directories if they don’t already exist. + /// </summary> + public PathManager() + { + var localAppDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + AppDirectory = $"{localAppDir}/V3"; + SaveGameDirectory = $"{AppDirectory}/SaveGames"; + OptionsFile = $"{AppDirectory}/Options.xml"; + } + + /// <summary> + /// Creates the application directories that do not already exist. + /// </summary> + public void CreateMissingDirectories() + { + string[] directories = { AppDirectory, SaveGameDirectory }; + foreach (var directory in directories) + { + if (!Directory.Exists(directory)) + Directory.CreateDirectory(directory); + } + } + } +} diff --git a/V3/Data/Internal/SaveGame.cs b/V3/Data/Internal/SaveGame.cs new file mode 100644 index 0000000..9ff3586 --- /dev/null +++ b/V3/Data/Internal/SaveGame.cs @@ -0,0 +1,65 @@ +using System; + +namespace V3.Data.Internal +{ + // TODO: once the game state is getting larger, we have to separate the + // save game metadata from the game state. + + /// <summary> + /// A save game that has a timestamp and a title, and that can store + /// the game state. + /// </summary> + [Serializable] + public sealed class SaveGame : ISaveGame + { + /// <summary> + /// The creation time of this save game in local time. + /// </summary> + public DateTime Timestamp { get; set; } + + /// <summary> + /// The compability version of this save game. + /// </summary> + public int Version { get; set; } + + /// <summary> + /// The data stored in this save game. + /// </summary> + public GameState GameState { get; set; } + + /// <summary> + /// Empty constructor for serialization. + /// </summary> + private SaveGame() + { + } + + /// <summary> + /// Creates a new save game from the given data. + /// </summary> + /// <param name="timestamp">the creation time of the save game</param> + /// <param name="version">the compability version of the save game</param> + /// <param name="gameState">the game state to store in the save game</param> + internal SaveGame(DateTime timestamp, int version, GameState gameState) + { + Timestamp = timestamp; + Version = version; + GameState = gameState; + } + + /// <summary> + /// Compares this save game object to another save game object based + /// on the creation time. + /// </summary> + /// <param name="saveGame">the save game to compare this save game + /// with</param> + /// <returns>a value less than zero if this save game has been saved + /// before the given save game, zero if they have been saved at the + /// same time and a value greater than zero if the given save game has + /// been saved before the given one</returns> + public int CompareTo(ISaveGame saveGame) + { + return Timestamp.CompareTo(saveGame.Timestamp); + } + } +} diff --git a/V3/Data/Internal/SaveGameManager.cs b/V3/Data/Internal/SaveGameManager.cs new file mode 100644 index 0000000..1c52b50 --- /dev/null +++ b/V3/Data/Internal/SaveGameManager.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.Serialization; +using System.Xml.Serialization; + +namespace V3.Data.Internal +{ + /// <summary> + /// Default implementation if ISaveGameManager. + /// </summary> + // ReSharper disable once ClassNeverInstantiated.Global + internal sealed class SaveGameManager : ISaveGameManager + { + private readonly IPathManager mPathManager; + + private const int CurrentVersion = 1; + private readonly XmlSerializer mFormatter = new XmlSerializer(typeof(SaveGame)); + + /// <summary> + /// Creates a new SaveGameManager. The save game directory must already + /// be created. + /// </summary> + public SaveGameManager(IPathManager pathManager) + { + mPathManager = pathManager; + } + + /// <summary> + /// Creates and persists a new save game of the given data with the + /// title. + /// </summary> + /// <param name="gameState">the data to store</param> + public void CreateSaveGame(GameState gameState) + { + var saveGame = new SaveGame(DateTime.Now, CurrentVersion, gameState); + var fileName = GetUniqueFileName(); + var stream = new FileStream(fileName, FileMode.Create, FileAccess.Write); + mFormatter.Serialize(stream, saveGame); + stream.Close(); + } + + /// <summary> + /// Loads all available save games and returns them ordered by the + /// creation date. + /// </summary> + /// <returns>a list of all available save games, orderd by creation + /// data</returns> + public List<ISaveGame> GetSaveGames() + { + var saveGames = new List<ISaveGame>(); + foreach (var file in Directory.GetFiles(mPathManager.SaveGameDirectory)) + { + var stream = new FileStream(file, FileMode.Open, FileAccess.Read); + try + { + var saveGame = (ISaveGame)mFormatter.Deserialize(stream); + if (saveGame.Version == CurrentVersion) + saveGames.Add(saveGame); + } + catch (SerializationException) + { + // ignore so far + } + stream.Close(); + } + saveGames.Sort(); + return saveGames; + } + + private string GetUniqueFileName() + { + var index = 1; + var fileName = GetFileName(index); + while (File.Exists(fileName)) + { + index++; + fileName = GetFileName(index); + } + return fileName; + } + + private string GetFileName(int index) + { + return $"{mPathManager.SaveGameDirectory}/{index:000}.xml"; + } + } +} diff --git a/V3/Data/Options.cs b/V3/Data/Options.cs new file mode 100644 index 0000000..38670dc --- /dev/null +++ b/V3/Data/Options.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Xna.Framework; +using V3.Camera; + +namespace V3.Data +{ + /// <summary> + /// The graphics options. + /// </summary> + [Serializable] + public sealed class Options + { + /// <summary> + /// All available screen resolutions. + /// </summary> + public static List<Point> Resolutions { get; } = new List<Point> + { + new Point(800, 480), + new Point(800, 600), + new Point(1024, 768), + new Point(1280, 800), + new Point(1280, 1024), + new Point(1366, 768), + new Point(1920, 1080) + }; + + /// <summary> + /// All available camera types. + /// </summary> + public static List<CameraType> CameraTypes { get; } = + Enum.GetValues(typeof (CameraType)).Cast<CameraType>().ToList(); + + /// <summary> + /// All available debug modes. + /// </summary> + public static List<DebugMode> DebugModes { get; } = + Enum.GetValues(typeof (DebugMode)).Cast<DebugMode>().ToList(); + + /// <summary> + /// All available volume settings. + /// </summary> + public static List<int> Volumes { get; } = new List<int>() + { + 10, + 20, + 30, + 40, + 50, + 60, + 70, + 80, + 90, + 100 + }; + private static readonly Point sDefaultResolution = Resolutions[0]; + private static readonly bool sDefaultIsFullScreen = false; + private static readonly DebugMode sDefaultDebugMode = DebugMode.Off; + private static readonly CameraType sDefaultCameraType = CameraType.Scrolling; + private static readonly bool sDefaultIsMuted = false; + private static readonly int sDefaultVolume = 100; + + /// <summary> + /// The current screen resolution. + /// </summary> + public Point Resolution { get; set; } = sDefaultResolution; + + /// <summary> + /// True if the game should be run in full screen, otherwise false. + /// </summary> + public bool IsFullScreen { get; set; } = sDefaultIsFullScreen; + + /// <summary> + /// The current debug mode. + /// </summary> + public DebugMode DebugMode { get; set; } = sDefaultDebugMode; + + /// <summary> + /// The current camera type. + /// </summary> + public CameraType CameraType { get; set; } = sDefaultCameraType; + + /// <summary> + /// True if the sound is muted, otherwise false. + /// </summary> + public bool IsMuted { get; set; } = sDefaultIsMuted; + + /// <summary> + /// The volume to use for the sound (if the sound is not muted), range + /// 0 .. 100. + /// </summary> + public int Volume { get; set; } = sDefaultVolume; + + /// <summary> + /// Returns the effective volume with regard to the mute and volume + /// settings. + /// </summary> + /// <returns>the effective volume that should be used for sound</returns> + public float GetEffectiveVolume() + { + return IsMuted ? 0 : ((float) Volume) / 100; + } + } +} |