98 lines
4.1 KiB
C#
98 lines
4.1 KiB
C#
using UnityEngine;
|
|
using Ashwild.Inventory;
|
|
|
|
namespace Ashwild.Building
|
|
{
|
|
/// <summary>
|
|
/// What a buildable is allowed to rest on. This is the one placement rule that genuinely differs
|
|
/// per structure — a foundation sits on terrain, a wall or a ceiling only makes sense attached to
|
|
/// something — so it is authored here rather than configured globally on BuildManager (which keeps
|
|
/// owning the project-wide layer masks: what blocks a build does not vary per build).
|
|
///
|
|
/// <see cref="GroundOrSnap"/> is deliberately the zero value: Unity deserializes a missing field to
|
|
/// 0, so buildables authored before this rule existed keep their old, permissive behaviour instead
|
|
/// of silently becoming unplaceable.
|
|
/// </summary>
|
|
public enum PlacementSupport
|
|
{
|
|
/// <summary>Free placement anywhere the aim lands, or connected to a socket. Foundations, floors.</summary>
|
|
GroundOrSnap,
|
|
|
|
/// <summary>Only valid while connected to a matching socket. Walls, ceilings, roofs.</summary>
|
|
SnapOnly
|
|
}
|
|
|
|
/// <summary>
|
|
/// Authoring data for one buildable structure shown in the construction menu (a wall, a
|
|
/// floor, a door, ...). Mirrors the ScriptableObject-for-data / MonoBehaviour-for-logic
|
|
/// split: it carries only what the menu card and the placement ghost need, no behaviour.
|
|
/// The final networked spawn will map this to an id later, the same way ItemData does.
|
|
/// </summary>
|
|
[CreateAssetMenu(fileName = "NewBuildable", menuName = "Building/Buildable Data")]
|
|
public class BuildableData : ScriptableObject
|
|
{
|
|
#region Serialized Fields
|
|
|
|
[Header("Identity")]
|
|
[Tooltip("Name shown on the menu card.")]
|
|
[SerializeField] private string displayName;
|
|
|
|
[Tooltip("Icon shown on the menu card.")]
|
|
[SerializeField] private Sprite icon;
|
|
|
|
[TextArea]
|
|
[SerializeField] private string description;
|
|
|
|
[Header("Prefabs")]
|
|
[Tooltip("Semi-transparent preview spawned in the world while positioning the structure.")]
|
|
[SerializeField] private GameObject ghostPrefab;
|
|
|
|
[Tooltip("The real structure spawned once the placement is confirmed.")]
|
|
[SerializeField] private GameObject builtPrefab;
|
|
|
|
[Header("Cost")]
|
|
[Tooltip("Resources consumed from the builder's inventory on each placement. Leave empty for a free build.")]
|
|
[SerializeField] private BuildCost[] cost;
|
|
|
|
[Header("Placement")]
|
|
[Tooltip("Where this structure may be committed. Walls, ceilings and roofs should be Snap Only so they cannot be dropped in mid-air; foundations and floors stay Ground Or Snap.")]
|
|
[SerializeField] private PlacementSupport support = PlacementSupport.GroundOrSnap;
|
|
|
|
[Header("Health")]
|
|
[Tooltip("Hit points the placed structure starts with. Damage subtracts from this (server-authoritative in BuildRegistry); at 0 the build is destroyed. A manual demolition refunds the cost in proportion to the health left.")]
|
|
[SerializeField] private float maxHealth = 100f;
|
|
|
|
#endregion
|
|
|
|
#region Public API
|
|
|
|
public string DisplayName => displayName;
|
|
public Sprite Icon => icon;
|
|
public string Description => description;
|
|
public GameObject GhostPrefab => ghostPrefab;
|
|
public GameObject BuiltPrefab => builtPrefab;
|
|
public BuildCost[] Cost => cost;
|
|
public float MaxHealth => maxHealth;
|
|
public PlacementSupport Support => support;
|
|
|
|
/// <summary>
|
|
/// Whether the given inventory holds enough of every cost line to place this structure once.
|
|
/// A null inventory or an empty cost list counts as affordable (free build).
|
|
/// </summary>
|
|
public bool CanAfford(PlayerInventory inventory)
|
|
{
|
|
if (cost == null || cost.Length == 0) return true;
|
|
if (inventory == null) return false;
|
|
|
|
for (int i = 0; i < cost.Length; i++)
|
|
{
|
|
if (cost[i].item == null) continue;
|
|
if (!inventory.HasItem(cost[i].item, cost[i].quantity)) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|