112 lines
5.2 KiB
C#
112 lines
5.2 KiB
C#
// Assets/_Project/Scripts/Gameplay/GoldConfig.cs
|
||
using System;
|
||
using UnityEngine;
|
||
|
||
namespace TD.Gameplay
|
||
{
|
||
/// <summary>
|
||
/// Per-wave gold rules nested under <see cref="GoldConfig"/>. Each entry maps to one
|
||
/// wave by array index in <see cref="GoldConfig.Waves"/>.
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// <b>Pairing with WaveDefinition.</b> The runtime pairing of gold entry to wave is by
|
||
/// array index — entry 0 applies to wave 1, etc. The <see cref="Wave"/> reference here
|
||
/// is OPTIONAL and exists purely so the inspector can compute and display the
|
||
/// <see cref="PreviewTotalGold"/> read-only value (which needs to know the wave's
|
||
/// total enemy count to multiply against <see cref="GoldPerEnemy"/>). Leaving it
|
||
/// unset just hides the kill-reward portion of the preview; runtime is unaffected.
|
||
/// </remarks>
|
||
[Serializable]
|
||
public class WaveGoldEntry
|
||
{
|
||
[Tooltip("Optional reference to the WaveDefinition this entry pairs with. " +
|
||
"Used ONLY for the inspector preview total — runtime pairing is by " +
|
||
"array index in GoldConfig.Waves. Drag the matching WaveDefinition " +
|
||
"here to see the live total computed under this entry.")]
|
||
public WaveDefinition Wave;
|
||
|
||
[Tooltip("Gold awarded to the killing player per enemy slain during this wave. " +
|
||
"Applies uniformly to every enemy type in the wave.")]
|
||
public int GoldPerEnemy = 10;
|
||
|
||
[Tooltip("Flat bonus gold awarded to every active player when this wave is fully " +
|
||
"cleared (all enemies dead or reached the goal).")]
|
||
public int CompletionBonus = 50;
|
||
|
||
[Tooltip("Extra bonus gold awarded to a player who cleared this wave without any " +
|
||
"enemy from their own zone escaping their leak volume. Stacks on top of " +
|
||
"CompletionBonus for the no-leak achievement.")]
|
||
public int NoLeaksBonus = 50;
|
||
|
||
/// <summary>
|
||
/// Read-only preview of the maximum gold a single player could earn in this wave:
|
||
/// <c>GoldPerEnemy × totalEnemyCount + CompletionBonus + NoLeaksBonus</c>.
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// Returns just <c>CompletionBonus + NoLeaksBonus</c> if <see cref="Wave"/> is null
|
||
/// (no enemy count to multiply against). Pure computation — safe at edit time and
|
||
/// at runtime. The custom inspector under <see cref="GoldConfig"/> renders this as
|
||
/// a non-editable label under the entry's fields.
|
||
/// </remarks>
|
||
public int PreviewTotalGold
|
||
{
|
||
get
|
||
{
|
||
int total = CompletionBonus + NoLeaksBonus;
|
||
if (Wave != null && Wave.Entries != null)
|
||
{
|
||
int enemies = 0;
|
||
foreach (var e in Wave.Entries)
|
||
{
|
||
if (e.EnemyType != null && e.Count > 0)
|
||
enemies += e.Count;
|
||
}
|
||
total += GoldPerEnemy * enemies;
|
||
}
|
||
return total;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Single source of truth for every gold-related tunable in the game.
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// <b>Inspector layout.</b> StartingGold is at the top and applies to every player.
|
||
/// The Waves array follows, each element collapsible in the inspector with the
|
||
/// per-wave rules and a read-only preview total computed from the entry's data.
|
||
///
|
||
/// <b>Wiring.</b> Assign one GoldConfig asset to <c>WaveManager.goldConfig</c> in
|
||
/// the Match scene. WaveManager initializes per-player starting gold from
|
||
/// <see cref="StartingGold"/> at match start, uses <see cref="WaveGoldEntry.GoldPerEnemy"/>
|
||
/// to compute kill rewards, and awards <see cref="WaveGoldEntry.CompletionBonus"/> /
|
||
/// <see cref="WaveGoldEntry.NoLeaksBonus"/> when each wave clears.
|
||
///
|
||
/// <b>No per-enemy-type bounties.</b> Every enemy killed in wave N grants the same
|
||
/// <see cref="WaveGoldEntry.GoldPerEnemy"/> regardless of <see cref="EnemyDefinition"/>.
|
||
/// If per-type variation becomes a design need, extend WaveGoldEntry with a per-type
|
||
/// table; the current model intentionally favors simplicity.
|
||
/// </remarks>
|
||
[CreateAssetMenu(fileName = "GoldConfig", menuName = "TD/Gold Config", order = 2)]
|
||
public class GoldConfig : ScriptableObject
|
||
{
|
||
[Tooltip("Gold each player starts the match with. Same for every player.")]
|
||
public int StartingGold = 100;
|
||
|
||
[Tooltip("Per-wave gold rules. Element 0 = Wave 1. Match the order and length of " +
|
||
"WaveManager.waveDefinitions; extra entries are ignored, missing entries " +
|
||
"fall back to zero gold for that wave.")]
|
||
public WaveGoldEntry[] Waves;
|
||
|
||
/// <summary>
|
||
/// Returns the gold entry for the given 1-based wave number, or null if out of range.
|
||
/// </summary>
|
||
public WaveGoldEntry GetWaveEntry(int waveNumber)
|
||
{
|
||
if (Waves == null) return null;
|
||
int index = waveNumber - 1;
|
||
if (index < 0 || index >= Waves.Length) return null;
|
||
return Waves[index];
|
||
}
|
||
}
|
||
}
|