aboutsummaryrefslogtreecommitdiff
path: root/V3/Data
diff options
context:
space:
mode:
Diffstat (limited to 'V3/Data')
-rw-r--r--V3/Data/DebugMode.cs21
-rw-r--r--V3/Data/GameState.cs64
-rw-r--r--V3/Data/IGameStateManager.cs20
-rw-r--r--V3/Data/IOptionsManager.cs18
-rw-r--r--V3/Data/IPathManager.cs30
-rw-r--r--V3/Data/ISaveGame.cs25
-rw-r--r--V3/Data/ISaveGameManager.cs25
-rw-r--r--V3/Data/Internal/GameStateManager.cs81
-rw-r--r--V3/Data/Internal/OptionsManager.cs65
-rw-r--r--V3/Data/Internal/PathManager.cs51
-rw-r--r--V3/Data/Internal/SaveGame.cs65
-rw-r--r--V3/Data/Internal/SaveGameManager.cs88
-rw-r--r--V3/Data/Options.cs105
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;
+ }
+ }
+}