UnityTowerDefense/Assets/_Project/Scripts/Gameplay/Draft/DraftOption.cs

69 lines
3.2 KiB
C#

// Assets/_Project/Scripts/Gameplay/Draft/DraftOption.cs
using UnityEngine;
namespace TD.Gameplay.Draft
{
/// <summary>
/// Base class for one authored draft choice. The draft system offers a player a
/// weighted-random selection of these between waves; the player picks one and the
/// server applies its effect.
/// </summary>
/// <remarks>
/// <para><b>One asset per choice.</b> Concrete subclasses (e.g.
/// <see cref="NewTowerDraftOption"/>) carry the payload and implement
/// <see cref="ServerApply"/>. New choice types (systemic upgrade, builder ability,
/// relic quest, enemy debuff) are added as new subclasses — the draft spine
/// (<see cref="DraftService"/>, <see cref="PlayerDraft"/>, HUD) is type-agnostic.</para>
///
/// <para><b>Identity.</b> Options live in <see cref="DraftPool"/> and are referenced
/// over the network by their pool index (<c>DraftOptionId</c>) — the same
/// stable-within-a-match index pattern used by the tower catalog.</para>
///
/// <para><b>Server-only logic.</b> <see cref="IsValidFor"/> and
/// <see cref="ServerApply"/> run on the server and operate on the target player's
/// per-player components (deck, gold, etc.). The ScriptableObject holds no per-player
/// state, so a single asset is shared across all players and matches.</para>
/// </remarks>
public abstract class DraftOption : ScriptableObject
{
[Header("Presentation")]
[Tooltip("Name shown on the draft card.")]
public string DisplayName;
[Tooltip("Short description shown on the draft card.")]
[TextArea(2, 4)]
public string Description;
[Tooltip("OPTIONAL override for the draft card icon. Leave empty to inherit the icon of " +
"the item this option grants (its tower / spell); assign one only when you want " +
"to override that inherited icon.")]
public Sprite Icon;
/// <summary>
/// The icon actually shown on the draft card. Returns the explicit <see cref="Icon"/>
/// override when one is assigned; otherwise subclasses fall back to the icon of the item
/// they grant (tower, spell). The base class has no referenced item, so it just returns
/// <see cref="Icon"/> (which may be null).
/// </summary>
public virtual Sprite ResolveIcon() => Icon;
[Header("Generation")]
[Tooltip("Relative draw weight. Higher = offered more often. Rarer rewards use " +
"lower weights. Must be > 0.")]
[Min(0.0001f)]
public float Weight = 1f;
/// <summary>
/// Server-only: can this option validly be OFFERED to the given player right now?
/// Lets the generator skip options that would be a no-op (e.g. a tower the player
/// already owns). Default true; override when an option has prerequisites.
/// </summary>
public virtual bool IsValidFor(ulong clientId) => true;
/// <summary>
/// Server-only: apply this option's effect to the given player. Returns false if
/// it could not be applied (caller treats as a no-op and logs).
/// </summary>
public abstract bool ServerApply(ulong clientId);
}
}