157 lines
6.8 KiB
C#
157 lines
6.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using EscapeRoomEngine.Engine.Runtime.Modules.Description;
|
|
using EscapeRoomEngine.Engine.Runtime.Modules.State;
|
|
using EscapeRoomEngine.Engine.Runtime.Requirements;
|
|
using EscapeRoomEngine.Engine.Runtime.Utilities;
|
|
using UnityEngine;
|
|
using Logger = EscapeRoomEngine.Engine.Runtime.Utilities.Logger;
|
|
using LogType = EscapeRoomEngine.Engine.Runtime.Utilities.LogType;
|
|
using Object = UnityEngine.Object;
|
|
|
|
namespace EscapeRoomEngine.Engine.Runtime.Modules
|
|
{
|
|
/// <summary>
|
|
/// The main representation of a module. Contains references to the module description, state and handles its placement.
|
|
/// </summary>
|
|
public class Module
|
|
{
|
|
public readonly List<Module> relatedModules = new();
|
|
|
|
public ModuleState State { get; private set; }
|
|
internal Vector2Int Size => srPlacement.size;
|
|
internal Orientation Orientation => srPlacement.orientation;
|
|
/// <summary>
|
|
/// Get the space relative (<i>SR</i>) position of this module.
|
|
/// </summary>
|
|
internal Vector3Int SrPosition => srPlacement.position;
|
|
/// <summary>
|
|
/// Get the room relative (<i>RR</i>) position of this module.
|
|
/// </summary>
|
|
internal Vector3Int RrPosition => space?.ToRoomRelative(SrPosition) ?? SrPosition;
|
|
|
|
internal readonly ModuleDescription description;
|
|
|
|
/// <summary>
|
|
/// The space relative (<i>SR</i>) placement of this module.
|
|
/// </summary>
|
|
public Placement srPlacement;
|
|
|
|
protected readonly Space space;
|
|
|
|
internal Module(Space space, ModuleDescription description)
|
|
{
|
|
this.space = space;
|
|
this.description = description;
|
|
srPlacement.size = description.modulePrefab.size;
|
|
}
|
|
|
|
internal bool IsType(ModuleType type)
|
|
{
|
|
return description.types.Contains(type);
|
|
}
|
|
|
|
internal bool CheckRequirements()
|
|
{
|
|
return PreconditionRequirement.CheckPreconditions(this, space) &&
|
|
PlacementRequirement.TryPlacing(this, space);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Place this module with a position relative to the room.
|
|
/// </summary>
|
|
/// <param name="rrPosition">The room relative (<i>RR</i>) position of this module. Must be inside the space dimensions.</param>
|
|
/// <param name="orientation">The orientation of this module.</param>
|
|
/// <exception cref="EngineException">If the position is not inside the space dimensions.</exception>
|
|
internal void PlaceRoomRelative(Vector3Int rrPosition, Orientation orientation) =>
|
|
Place(new Placement
|
|
{
|
|
position = space.ToSpaceRelative(rrPosition),
|
|
size = srPlacement.size,
|
|
orientation = orientation
|
|
});
|
|
|
|
/// <summary>
|
|
/// Place this module with a position relative to the space it is in.
|
|
/// </summary>
|
|
/// <param name="placement">The space relative (<i>SR</i>) placement of this module. Must be inside the space dimensions.</param>
|
|
/// <exception cref="EngineException">If the position is not inside the space dimensions.</exception>
|
|
internal void Place(Placement placement) {
|
|
if (space != null && !placement.position.IsInsideRelative(space.rrPlacement))
|
|
{
|
|
throw new EngineException($"Trying to place {this} at {placement.position} which is outside space dimensions {space.rrPlacement}.");
|
|
}
|
|
|
|
srPlacement = placement;
|
|
|
|
Logger.Log($"{this} has been placed at {placement.ToStringShort()} (SR)", LogType.ModulePlacement);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert a position relative to this module to one relative to its space.
|
|
/// <example>The module relative position <c>(0, 0, 1)</c> should always be in front of the module, wherever it faces.</example>
|
|
/// </summary>
|
|
/// <param name="mrPosition">The module relative (<i>MR</i>) position that should be converted to a space relative (<i>SR</i>) position.</param>
|
|
internal Vector3Int ToSpaceRelative(Vector3Int mrPosition)
|
|
{
|
|
// ReSharper disable once ArrangeRedundantParentheses
|
|
return srPlacement.position + (Orientation switch
|
|
{
|
|
Orientation.North => mrPosition,
|
|
Orientation.East => new Vector3Int(mrPosition.z, 0, -mrPosition.x),
|
|
Orientation.South => -mrPosition,
|
|
Orientation.West => new Vector3Int(-mrPosition.z, 0, mrPosition.x),
|
|
_ => throw new ArgumentOutOfRangeException()
|
|
});
|
|
}
|
|
|
|
internal virtual void InstantiateModule(Transform parent)
|
|
{
|
|
Logger.Log($"Instantiating {this}", LogType.ModuleInstantiation);
|
|
|
|
State = Object.Instantiate(description.modulePrefab, parent, false);
|
|
State.transform.localPosition = new Vector3(SrPosition.x + .5f, SrPosition.y, SrPosition.z + .5f);
|
|
State.transform.Rotate(Vector3.up, Orientation.Angle());
|
|
State.name = ToString();
|
|
State.SetModule(this);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a module of the correct type given a module description.
|
|
///
|
|
/// <example>If the module description shows "Puzzle" as a type, this will try to create a puzzle module.</example>
|
|
/// </summary>
|
|
/// <param name="space">The space to create the module for.</param>
|
|
/// <param name="description">The module description to create the module from.</param>
|
|
/// <returns>A <see cref="PuzzleModule"/> or <see cref="DoorModule"/>.</returns>
|
|
/// <exception cref="WrongTypeException">If there is no module type fitting the description.</exception>
|
|
internal static Module CreateModuleByType(Space space, ModuleDescription description)
|
|
{
|
|
if (description.HasType(ModuleType.Puzzle) &&
|
|
description is PuzzleModuleDescription puzzleModuleDescription)
|
|
{
|
|
return new PuzzleModule(space, puzzleModuleDescription);
|
|
}
|
|
|
|
if((description.HasType(ModuleType.DoorEntrance) || description.HasType(ModuleType.DoorExit)) &&
|
|
description is DoorModuleDescription doorModuleDescription)
|
|
{
|
|
return new DoorModule(space, doorModuleDescription);
|
|
}
|
|
|
|
if (description.HasType(ModuleType.Generic))
|
|
{
|
|
return new Module(space, description);
|
|
}
|
|
|
|
throw new WrongTypeException("There is no module type fitting this description.");
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return $"Module ({string.Join(", ", description.types.ToList().ConvertAll(type => type.ToString()))})";
|
|
}
|
|
}
|
|
}
|