// Assets/_Project/Scripts/Gameplay/GoldConfig.cs
using System;
using UnityEngine;
using UnityEngine.Serialization;
namespace TD.Gameplay
{
///
/// Gold rules for one encounter slot, addressed by position in the run rather than by
/// which wave happens to occupy it.
///
///
/// Position, not identity. Under the 2.0 run structure the waves filling each slot are
/// drawn at random from a phase pool, so "the gold for wave 3" means the run's third
/// encounter, whatever spawns in it. Payouts are a property of how far the players have
/// progressed — not of which enemy they happened to draw.
///
[Serializable]
public class EncounterGoldEntry
{
[Tooltip("Gold awarded to the killing player per enemy slain during this encounter. " +
"Applies uniformly to every enemy type.")]
public int GoldPerEnemy = 10;
[Tooltip("Flat bonus gold awarded to every active player when this encounter 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 encounter without any " +
"enemy from their own zone escaping their leak volume. Stacks on top of " +
"CompletionBonus.")]
public int NoLeaksBonus = 50;
///
/// Guaranteed gold for a player who clears this encounter: the two bonuses, with no
/// kill income counted.
///
///
/// Kill income can't be known here — the wave occupying this slot is drawn at runtime, so
/// its enemy count varies per run.
/// supplies an estimate for the inspector's projected totals.
///
public int GuaranteedBonusGold => CompletionBonus + NoLeaksBonus;
///
/// Projected best-case earnings for one player this encounter, given an assumed enemy
/// count. Editor tuning aid only — nothing at runtime reads it.
///
public int ProjectedTotal(int assumedEnemyCount)
=> GoldPerEnemy * Mathf.Max(0, assumedEnemyCount) + GuaranteedBonusGold;
}
///
/// Single source of truth for every gold-related tunable in the game.
///
///
/// Wiring. Assign one GoldConfig asset to WaveManager.goldConfig in the Match
/// scene. WaveManager seeds per-player starting gold from , reads
/// for kill rewards, and awards the completion
/// and no-leak bonuses as each encounter clears.
///
/// No per-enemy-type bounties. Every enemy killed in a given encounter grants the
/// same reward regardless of . With enemy types now drawn at
/// random per phase, per-type bounties would make income depend on the luck of the draw
/// rather than on progression.
///
[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("Gold rules per encounter, in run order. Element 0 = the run's first encounter. " +
"Encounters are counted continuously — cycles do NOT restart the count — so one " +
"phase of 5 waves × 3 cycles + a boss needs 16 entries. Missing entries pay " +
"zero for that encounter.")]
[FormerlySerializedAs("Waves")]
public EncounterGoldEntry[] Encounters;
[Header("Editor preview")]
[Tooltip("Assumed enemies per encounter, used ONLY to project totals in this inspector. " +
"Nothing at runtime reads it — the real count comes from whichever wave the run " +
"draws into each slot.")]
[Min(0)]
public int PreviewEnemiesPerEncounter = 40;
///
/// Returns the gold rules for the given 1-based encounter number
/// (RunState.GlobalEncounterNumber), or null if out of range.
///
///
/// Keyed by run position, not by wave slot within a cycle. The same five waves come
/// round three times per phase, so a slot-keyed table would pay the same on cycle 3 as on
/// cycle 1 while the enemies grew steadily stronger from the buffs voted onto them. A
/// run-long counter lets payouts climb with the difficulty.
///
public EncounterGoldEntry GetEncounterEntry(int encounterNumber)
{
if (Encounters == null) return null;
int index = encounterNumber - 1;
if (index < 0 || index >= Encounters.Length) return null;
return Encounters[index];
}
/// Number of authored encounter entries.
public int EncounterCount => Encounters?.Length ?? 0;
///
/// Editor tuning aid: cumulative projected earnings for one player from the run's first
/// encounter through inclusive, assuming
/// kills each time and no leaks.
///
public int ProjectedCumulativeThrough(int encounterNumber)
{
if (Encounters == null) return StartingGold;
int total = StartingGold;
int last = Mathf.Min(encounterNumber, Encounters.Length);
for (int i = 0; i < last; i++)
{
if (Encounters[i] == null) continue;
total += Encounters[i].ProjectedTotal(PreviewEnemiesPerEncounter);
}
return total;
}
}
}