using System; using System.Collections.Generic; using System.Linq; using Cirno.Scripts.Components.FSM.Enemy; using Cirno.Scripts.Resources; using Cirno.Scripts.Resources.Roguelite; using Godot; using Godot.Collections; namespace Cirno.Scripts.Controllers; public partial class RogueliteRoom : Node2D { [Export] public RogueliteRoomResource RoomResource { get; set; } public Vector2I GridPosition { get; set; } // Set by dungeon manager [Export] public PackedScene DoorPrefab { get; private set; } [Export] public PackedScene WallPrefab { get; private set; } private static readonly Godot.Collections.Dictionary DirectionMap = new() { { "North", new Vector2I(0, -1) }, { "South", new Vector2I(0, 1) }, { "East", new Vector2I(1, 0) }, { "West", new Vector2I(-1, 0) }, }; private List _doors = []; private List _connections = []; private List _enemies = []; private Array SpawnableEnemies => RoomResource.SpawnableEnemies; public RogueliteRoom Spawn() { SpawnEnemies(); //HandleDoors(connectionChecker); AddDebugLabel(); return this; } private void AddDebugLabel() { for (int i = 0; i < RoomResource.Size.X; i++) { for (int j = 0; j < RoomResource.Size.Y; j++) { var label = new Label(); label.Text = $"{GridPosition + new Vector2I(i, j)}"; label.ZIndex = 11; label.Position = (new Vector2(i, j) * new Vector2(320, 160)) + new Vector2(160, 80); this.AddChild(label); } } } public void HandleDoors(Func connectionChecker) { if (!HasNode("Doors")) return; var doorsNode = GetNode("Doors"); foreach (Node child in doorsNode.GetChildren()) { if (child is not DoorMarker marker) continue; var baseDir = marker.GetWorldDirection(); // WallIndex determines the offset *along* the edge of the room Vector2I offset = marker.Direction switch { RoomDirection.North => new Vector2I(marker.WallIndex, 0), RoomDirection.South => new Vector2I(marker.WallIndex, RoomResource.Size.Y - 1), RoomDirection.East => new Vector2I(RoomResource.Size.X - 1, marker.WallIndex), RoomDirection.West => new Vector2I(0, marker.WallIndex), _ => Vector2I.Zero }; // Combine GridPosition + offset to locate where this door aligns Vector2I doorEdge = GridPosition + offset; Vector2I neighborPos = doorEdge + baseDir; var connection = connectionChecker.Invoke(doorEdge, neighborPos); var connected = connection is not null; if (connected) { var door = this.CreateChildOf(marker, DoorPrefab, marker.GlobalPosition); door.State = DoorState.Closed; _doors.Add(door); if (doorEdge == connection.From) { connection.FromDoor = door; } else if (doorEdge == connection.To) { connection.ToDoor = door; } else { GD.Print($"Door {door} connection was full: {connection.From} {connection.FromDoor} to {connection.To} {connection.ToDoor}"); } // if (connection.FromDoor is null && connection.ToDoor != door) // { // connection.FromDoor = door; // } // else if (connection.ToDoor is null && connection.FromDoor != door) // { // connection.ToDoor = door; // } // else // { // GD.Print($"Door {door} connection was full: {connection.From} {connection.FromDoor} to {connection.To} {connection.ToDoor}"); // } _connections.Add(connection); // var label = new Label(); // label.Text = $"Door Edge: {doorEdge}, {connection}"; // label.ZIndex = 10; // // door.AddChild(label); } else { var wall = this.CreateChild(WallPrefab, marker.GlobalPosition); // var label = new Label(); // label.Text = $"Door Edge: {doorEdge}, Neighbor: {neighborPos}"; // label.ZIndex = 10; // // marker.AddChild(label); } } } private void SpawnEnemies() { if (SpawnableEnemies is null || !SpawnableEnemies.Any()) return; var enemySpawners = this.GetNode("EnemySpawners").GetChildren().Cast(); foreach (var spawner in enemySpawners) { var index = GD.RandRange(0, SpawnableEnemies.Count - 1); var e = SpawnableEnemies[index]; var enemyScene = GD.Load(e.PrefabPath); var spawnedEnemy = spawner.CreateChild(enemyScene); _enemies.Add(spawnedEnemy); spawnedEnemy.Death += SpawnedEnemyOnDeath; } } private void SpawnedEnemyOnDeath(EnemyFSMProxy enemy) { enemy.Death -= SpawnedEnemyOnDeath; _enemies.Remove(enemy); if (_enemies.Count == 0) { OpenDoors(); } } public void OpenDoors() { foreach (var connection in _connections) { connection.FromDoor?.Open(); connection.ToDoor?.Open(); } } public void CloseDoors() { foreach (var connection in _connections) { connection.FromDoor?.Close(); connection.ToDoor?.Close(); } } private void OnRoomEntered(Area2D area) { if (area is not InteractionController player) return; if (_enemies.Count <= 0) { OpenDoors(); } else { CloseDoors(); } } private void OnRoomExited(Area2D area) { if (area is not InteractionController player) return; } }