using System; using System.Collections.Generic; using System.Linq; using Escape_Room_Engine.Engine.Scripts.Utilities; using UnityEngine; using Logger = Escape_Room_Engine.Engine.Scripts.Utilities.Logger; using LogType = Escape_Room_Engine.Engine.Scripts.Utilities.LogType; using Object = UnityEngine.Object; namespace Escape_Room_Engine.Engine.Scripts.Modules { public enum Orientation { North = 0, East = 90, South = 180, West = 270 } public class Module { public static HashSet EveryOrientation => new(new[] { Orientation.North, Orientation.East, Orientation.South, Orientation.West }); /// /// Get the space relative (SR) position of this module. /// internal Vector2Int SrPosition => srDimensions.Position; /// /// Get the room relative (RR) position of this module. /// internal Vector2Int RrPosition => space.ToRoomRelative(SrPosition); internal ModuleState State { get; private set; } internal readonly ModuleDescription description; internal Orientation orientation; /// /// The space relative (SR) dimensions of this module. /// protected Dimensions srDimensions; protected GameObject moduleObject; protected readonly Space space; private GameObject _orientationObject; internal Module(Space space, ModuleDescription description) { this.space = space; this.description = description; } internal bool IsType(ModuleType type) { return description.types.Contains(type); } /// /// Place this module with a position relative to the room. /// /// The room relative (RR) position of this module. Must be inside the space dimensions. /// If the position is not inside the space dimensions. internal void PlaceRoomRelative(Vector2Int rrPosition) => Place(space.ToSpaceRelative(rrPosition)); /// /// Place this module with a position relative to the space it is in. /// /// The space relative (SR) position of this module. Must be inside the space dimensions. /// If the position is not inside the space dimensions. internal void Place(Vector2Int srPosition) { if (space != null && !srPosition.IsInsideRelative(space.rrDimensions)) { throw new Exception($"Trying to place {this} at {srPosition}, which is outside space dimensions {space.rrDimensions}."); } srDimensions.Position = srPosition; Logger.Log($"{this} has been placed at {srPosition} (SR)", LogType.ModulePlacement); } /// /// Convert a position relative to this module to one relative to its space. /// The module relative position (0, 1) should always be in front of the module, wherever it faces. /// /// The module relative (MR) position that should be converted to a space relative (SR) position. /// internal Vector2Int ToSpaceRelative(Vector2Int mrPosition) { return srDimensions.Position + orientation switch { Orientation.North => mrPosition, Orientation.East => new Vector2Int(mrPosition.y, -mrPosition.x), Orientation.South => -mrPosition, Orientation.West => new Vector2Int(-mrPosition.y, mrPosition.x), _ => throw new ArgumentOutOfRangeException() }; } internal virtual void InstantiateModule(Transform parent) { moduleObject = new GameObject(ToString()); moduleObject.transform.SetParent(parent, false); moduleObject.transform.localPosition = new Vector3(srDimensions.x + .5f, 0, srDimensions.z + .5f); AddStateComponent(); _orientationObject = new GameObject("Orientation"); _orientationObject.transform.SetParent(moduleObject.transform, false); _orientationObject.transform.Rotate(Vector3.up, (float)orientation); Object.Instantiate(description.modulePrefab, _orientationObject.transform, false); } protected virtual void AddStateComponent() { State = moduleObject.AddComponent(); State.SetModule(this); } public override string ToString() { return $"Module ({string.Join(", ", description.types.ToList().ConvertAll(type => type.ToString()))})"; } } }