diff --git a/src/TextLore/Components/Pages/Games/Roguelike/RoguelikePage.razor.cs b/src/TextLore/Components/Pages/Games/Roguelike/RoguelikePage.razor.cs index 4c7d207..346530d 100644 --- a/src/TextLore/Components/Pages/Games/Roguelike/RoguelikePage.razor.cs +++ b/src/TextLore/Components/Pages/Games/Roguelike/RoguelikePage.razor.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Components; +using TextLore.Components.Pages.Games.Roguelike.Builders; using TextLore.Console; using TextLore.Shared.Commands; using TextLore.Shared.Logic; @@ -22,9 +23,11 @@ public partial class RoguelikePage [Parameter] public string Seed { get; set; } = string.Empty; - public async void OnLevelGenerated(Level level) + public void OnLevelGenerated(Level level) { - gameManager = new GameManager(level); + gameManager = new GameManager(level, [typeof(EnemyBuilder)]); + + gameManager.StartGame(); StateHasChanged(); } diff --git a/src/TextLore/Program.cs b/src/TextLore/Program.cs index 2858ada..4fa31d4 100644 --- a/src/TextLore/Program.cs +++ b/src/TextLore/Program.cs @@ -30,14 +30,14 @@ GamesDatabaseContext databaseContext = serviceScope.ServiceProvider.GetRequiredS if (await databaseContext.Database.EnsureCreatedAsync()) { databaseContext.Rooms.AddRange( - new RoomDefinition(1, RoomTag.Start, "roguelike") { Name = "Start Room" }, - new RoomDefinition(1, RoomTag.Unique, "roguelike") { Name = "Unique Room" }, - new RoomDefinition(2, RoomTag.None, "roguelike") { Name = "Normal Room 1" }, - new RoomDefinition(3, RoomTag.None, "roguelike") { Name = "Normal Room 2" }, - new RoomDefinition(4, RoomTag.None, "roguelike") { Name = "Normal Room 3" }, - new RoomDefinition(5, RoomTag.None, "roguelike") { Name = "Normal Room 4" }, - new RoomDefinition(6, RoomTag.None, "roguelike") { Name = "Normal Room 5" }, - new RoomDefinition(1, RoomTag.End, "roguelike") { Name = "End Room" } + new RoomDefinition(1, RoomTag.Start, "roguelike") { Name = "Start Room", Size = new(5, 5) }, + new RoomDefinition(1, RoomTag.Unique, "roguelike") { Name = "Unique Room", Size = new(30, 30) }, + new RoomDefinition(2, RoomTag.None, "roguelike") { Name = "Normal Room 1", Size = new(10, 10) }, + new RoomDefinition(3, RoomTag.None, "roguelike") { Name = "Normal Room 2", Size = new(10, 10) }, + new RoomDefinition(4, RoomTag.None, "roguelike") { Name = "Normal Room 3", Size = new(10, 10) }, + new RoomDefinition(5, RoomTag.None, "roguelike") { Name = "Normal Room 4", Size = new(10, 10) }, + new RoomDefinition(6, RoomTag.None, "roguelike") { Name = "Normal Room 5", Size = new(10, 10) }, + new RoomDefinition(1, RoomTag.End, "roguelike") { Name = "End Room", Size = new(10, 5) } ); _ = await databaseContext.SaveChangesAsync(); diff --git a/src/TextLore/Shared/Logic/GameManager.cs b/src/TextLore/Shared/Logic/GameManager.cs index 2c0b81f..93dda5f 100644 --- a/src/TextLore/Shared/Logic/GameManager.cs +++ b/src/TextLore/Shared/Logic/GameManager.cs @@ -23,22 +23,95 @@ public partial class GameManager scriptEngine.AddHostObject("context", currentScriptContext); } - public void MovePlayer(Direction direction) + public GameManager(Level level, IEnumerable typesToAdd, IEnumerable objectsToAdd) : this(level) { - Position newPosition = PlayState.Player.Position + direction; - if (PlayState.Level.IsPositionInBounds(newPosition)) + foreach (Type type in typesToAdd) { - PlayState.Player.Position = newPosition; + scriptEngine.AddHostType(type.Name, type); + } - SetScript(PlayState.CurrentRoom?.Definition.Script ?? string.Empty); + foreach (object obj in objectsToAdd) + { + scriptEngine.AddHostObject(obj.GetType().Name, obj); } } - public void ExecuteMethod(string method, ConsoleWriter consoleWriter) + public GameManager(Level level, IEnumerable typesToAdd) : this(level) { + foreach (Type type in typesToAdd) + { + scriptEngine.AddHostType(type.Name, type); + } + } + + public GameManager(Level level, IEnumerable objectsToAdd) : this(level) + { + foreach (object obj in objectsToAdd) + { + scriptEngine.AddHostObject(obj.GetType().Name, obj); + } + } + + public virtual void StartGame() + { + SetPlayerPositionInLevel(PlayState.Level.StartRoom.Position); + + Size currentRoomSize = PlayState.CurrentRoom!.Definition.Size; + + SetPlayerPositionInRoom(new(currentRoomSize.Width / 2, currentRoomSize.Height / 2)); + } + + public void MovePlayerInLevel(Direction direction) + { + Position newPosition = PlayState.Player.PositionInLevel + direction; + if (PlayState.Level.IsPositionInBounds(newPosition)) + { + SetPlayerPositionInLevel(newPosition); + } + } + + public void MovePlayerInRoom(Direction direction) + { + Position newPosition = PlayState.Player.PositionInLevel + direction; + if (PlayState.CurrentRoom?.IsPositionInBounds(newPosition) == true) + { + SetPlayerPositionInRoom(newPosition); + } + } + + public virtual void SetPlayerPositionInLevel(Position position) + { + PlayState.Player.PositionInLevel = position; + + SetScript(PlayState.CurrentRoom?.Definition.Script ?? string.Empty); + + _ = ExecuteMethod("onPlayerEnterRoom"); + } + + public virtual void SetPlayerPositionInRoom(Position position) + { + PlayState.Player.PositionInLevel = position; + + _ = ExecuteMethod("onPlayerMove"); + } + + public void Update() + { + _ = ExecuteMethod("onUpdate"); + } + + protected T? ExecuteMethod(string method, ConsoleWriter? consoleWriter = null) where T : class + { + return ExecuteMethod(method, consoleWriter) as T; + } + + protected object? ExecuteMethod(string method, ConsoleWriter? consoleWriter = null) + { + consoleWriter ??= new ConsoleWriter(); + try { - _ = scriptEngine.Invoke(method, consoleWriter); + return scriptEngine.Invoke(method, consoleWriter); } catch (ScriptEngineException ex) { @@ -48,9 +121,11 @@ public partial class GameManager { consoleWriter.WriteLine(ex.Message); } + + return default; } - private void SetScript(string script) + protected void SetScript(string script) { scriptEngine.Execute(script); } diff --git a/src/TextLore/Shared/Logic/PlayState.cs b/src/TextLore/Shared/Logic/PlayState.cs index d70ecd9..8819d86 100644 --- a/src/TextLore/Shared/Logic/PlayState.cs +++ b/src/TextLore/Shared/Logic/PlayState.cs @@ -9,5 +9,5 @@ public class PlayState(Level level, Player player) public Player Player { get; } = player; - public Room? CurrentRoom => Level.GetRoom(Player.Position); + public Room? CurrentRoom => Level.GetRoom(Player.PositionInLevel); } \ No newline at end of file diff --git a/src/TextLore/Shared/Models/Level/Level.cs b/src/TextLore/Shared/Models/Level/Level.cs index af210c2..84ee94f 100644 --- a/src/TextLore/Shared/Models/Level/Level.cs +++ b/src/TextLore/Shared/Models/Level/Level.cs @@ -1,5 +1,4 @@ using TextLore.Shared.Logic; -using TextLore.Shared.Models; namespace TextLore.Shared.Models.Level; @@ -12,6 +11,8 @@ public class Level(Size size, DeterministicRandom seed) public DeterministicRandom Seed => seed; + public Room StartRoom => rooms.Values.First(r => r.Definition.Tag == RoomTag.Start); + public Room? GetRoom(Position point) { return rooms.GetValueOrDefault(point); @@ -64,7 +65,7 @@ public class Level(Size size, DeterministicRandom seed) return rooms.Values.Any(r => r.Definition.Id == definition.Id); } - public void ClearRoom(Position point) + public void RemoveRoom(Position point) { _ = rooms.Remove(point); } diff --git a/src/TextLore/Shared/Models/Level/Room.cs b/src/TextLore/Shared/Models/Level/Room.cs index cb9f54d..bbb5bbf 100644 --- a/src/TextLore/Shared/Models/Level/Room.cs +++ b/src/TextLore/Shared/Models/Level/Room.cs @@ -1,10 +1,51 @@ -using TextLore.Shared.Models; - -namespace TextLore.Shared.Models.Level; +namespace TextLore.Shared.Models.Level; public class Room(Position position, RoomDefinition roomDefinition) { + private readonly Dictionary objects = []; public Position Position => position; public List DoorDirections { get; init; } = [Direction.Up, Direction.Down, Direction.Right, Direction.Left]; public RoomDefinition Definition => roomDefinition; + + public IRoomObject? GetObject(Position point) + { + return objects.GetValueOrDefault(point); + } + + public IReadOnlyDictionary GetRooms() + { + return objects; + } + + public bool AddObject(Position point, IRoomObject roomObject) + { + if (!IsPositionInBounds(point)) + { + return false; + } + + objects[point] = roomObject; + + return true; + } + + public bool IsPositionInBounds(Position point) + { + return point.X >= 0 && point.X < roomDefinition.Size.Width && point.Y >= 0 && point.Y < roomDefinition.Size.Height; + } + + public bool ObjectExists(Position point) + { + return objects.ContainsKey(point); + } + + public void RemoveObject(Position point) + { + _ = objects.Remove(point); + } + + public void ClearObjects() + { + objects.Clear(); + } } \ No newline at end of file diff --git a/src/TextLore/Shared/Models/Level/RoomDefinition.cs b/src/TextLore/Shared/Models/Level/RoomDefinition.cs index ec07df9..24bc71c 100644 --- a/src/TextLore/Shared/Models/Level/RoomDefinition.cs +++ b/src/TextLore/Shared/Models/Level/RoomDefinition.cs @@ -18,5 +18,7 @@ public class RoomDefinition(int id, RoomTag tag, string game) public required string Name { get; set; } + public required Size Size { get; set; } + public string Script { get; set; } = string.Empty; } \ No newline at end of file diff --git a/src/TextLore/Shared/Models/Player/InventoryItem.cs b/src/TextLore/Shared/Models/Player/InventoryItem.cs deleted file mode 100644 index cdb5be0..0000000 --- a/src/TextLore/Shared/Models/Player/InventoryItem.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace TextLore.Shared.Models.Player; - -public class InventoryItem(string name, string description, string tag) -{ - public string Name { get; set; } = name; - - public string Description { get; set; } = description; - - public string Tag { get; set; } = tag; -} \ No newline at end of file diff --git a/src/TextLore/Shared/Models/Player/Player.cs b/src/TextLore/Shared/Models/Player/Player.cs index 4dff1e3..dd11476 100644 --- a/src/TextLore/Shared/Models/Player/Player.cs +++ b/src/TextLore/Shared/Models/Player/Player.cs @@ -4,7 +4,9 @@ public class Player { public int Health { get; set; } = 100; - public List Inventory { get; } = []; + public List Inventory { get; } = []; - public Position Position { get; set; } = new Position(0, 0); + public Position PositionInLevel { get; set; } = new Position(0, 0); + + public Position PositionInRoom { get; set; } = new Position(0, 0); } \ No newline at end of file