// Assets/_Project/Scripts/Gameplay/TowerPlacementSettings.cs using UnityEngine; namespace TD.Gameplay { /// /// Project-wide settings for the tower placement system. One asset shared across all /// tower types — assign it to in the scene. /// /// /// Why not on TowerDefinition? Ghost materials and rejection messages are /// identical for every tower type. Putting them on TowerDefinition would mean 100+ /// assets each holding two redundant material references that must be kept in sync. /// A single shared settings asset is easier to maintain and impossible to accidentally /// de-sync. /// /// Rejection messages. These are the strings shown on screen when the /// server rejects a placement. Kept here so designers can tune the wording without /// touching code. /// [CreateAssetMenu(fileName = "TowerPlacementSettings", menuName = "TD/Tower Placement Settings", order = 3)] public class TowerPlacementSettings : ScriptableObject { // ----- Ghost visuals ----------------------------------------------- [Header("Ghost Materials")] [Tooltip("Material applied to the placement ghost when placement is valid. " + "Should be a transparent/unlit white material so the tower mesh is " + "recognizable but clearly distinct from a placed tower.")] public Material GhostValidMaterial; [Tooltip("Material applied to the placement ghost when placement is invalid. " + "Should be a transparent/unlit red material.")] public Material GhostInvalidMaterial; // ----- Rejection messages ------------------------------------------ [Header("Rejection Messages")] [Tooltip("Shown when the server rejects a placement because tiles belong to " + "another player's zone.")] public string MessageWrongOwner = "You can only place towers in your own zone."; [Tooltip("Shown when the server rejects because one or more tiles are " + "Restricted or Outside the map.")] public string MessageTileNotBuildable = "That location is not buildable."; [Tooltip("Shown when the server rejects because a tile is already occupied " + "by an existing tower.")] public string MessageTileOccupied = "A tower already occupies that location."; [Tooltip("Shown when the server rejects because the player cannot afford " + "the tower.")] public string MessageInsufficientGold = "Not enough gold."; [Tooltip("Shown when the server rejects because the builder is too far away " + "from the requested location.")] public string MessageOutOfRange = "Your builder is too far away."; [Tooltip("Shown when the server rejects because placing the tower would block " + "all valid paths through the player's zone.")] public string MessageBlocksPath = "That placement would block the path."; [Tooltip("Shown for unexpected server-side errors (invalid tower type, etc.). " + "Should rarely appear in normal play.")] public string MessageServerError = "Placement failed. Please try again."; // ----- Helpers ----------------------------------------------------- /// /// Returns the human-readable rejection message for the given reason. /// public string GetRejectionMessage(PlacementRejectionReason reason) { switch (reason) { case PlacementRejectionReason.WrongOwner: return MessageWrongOwner; case PlacementRejectionReason.TileNotBuildable: return MessageTileNotBuildable; case PlacementRejectionReason.TileOccupied: return MessageTileOccupied; case PlacementRejectionReason.InsufficientGold: return MessageInsufficientGold; case PlacementRejectionReason.OutOfRange: return MessageOutOfRange; case PlacementRejectionReason.BlocksPath: return MessageBlocksPath; case PlacementRejectionReason.InvalidTowerType: case PlacementRejectionReason.ServerError: default: return MessageServerError; } } } }