Game/Idle/IdleAchievements.cs
using System;
using System.Collections.Generic;
using System.Linq;
/// <summary>
/// The Reactor Log — long-tail goals that hand out Flux and Fragments.
/// These are the "one more session" hooks: each one is visible from the start
/// with a progress bar, so there is always something a few minutes away.
/// </summary>
public class IdleAchievement
{
public string Id { get; set; }
public string Name { get; set; }
public string Icon { get; set; }
public string Desc { get; set; }
public int RewardFlux { get; set; }
public int RewardFrags { get; set; }
/// <summary>Current progress, 0..Target.</summary>
public Func<IdleSave, double> Progress { get; set; }
public double Target { get; set; }
/// <summary>True when the numeric target should be shown compacted (big currency).</summary>
public bool BigNumbers { get; set; }
public bool IsDone( IdleSave s ) => Progress( s ) >= Target;
public float Fraction( IdleSave s )
=> Target <= 0 ? 1f : (float)Math.Clamp( Progress( s ) / Target, 0.0, 1.0 );
}
public static class IdleAchievements
{
public static readonly List<IdleAchievement> All = new()
{
// ── First steps ──
new IdleAchievement { Id = "first_blood", Name = "Ignition", Icon = "🔥",
Desc = "Run 25 detonation cycles.",
Progress = s => s.TotalDetonations, Target = 25, RewardFrags = 5 },
new IdleAchievement { Id = "cores_1k", Name = "Warm Start", Icon = "⚛️",
Desc = "Bank 1,000 Cores in one cycle.",
Progress = s => s.CycleCores, Target = 1_000, BigNumbers = true, RewardFrags = 8 },
new IdleAchievement { Id = "chain_10", Name = "Linked", Icon = "⛓️",
Desc = "Clear 10 chests in a single detonation.",
Progress = s => s.BestChain, Target = 10, RewardFrags = 10 },
// ── Getting going ──
new IdleAchievement { Id = "cores_100k", Name = "Producer", Icon = "🏭",
Desc = "Bank 100K Cores in one cycle.",
Progress = s => s.CycleCores, Target = 100_000, BigNumbers = true, RewardFlux = 2, RewardFrags = 15 },
new IdleAchievement { Id = "chain_25", Name = "Cascade", Icon = "🌊",
Desc = "Clear 25 chests in a single detonation.",
Progress = s => s.BestChain, Target = 25, RewardFlux = 1, RewardFrags = 15 },
new IdleAchievement { Id = "golden_10", Name = "Quick Hands", Icon = "🌟",
Desc = "Catch 10 Golden Chests.",
Progress = s => s.GoldenGrabbed, Target = 10, RewardFrags = 20 },
new IdleAchievement { Id = "blown_5k", Name = "Demolition Crew", Icon = "💣",
Desc = "Destroy 5,000 chests in the reactor.",
Progress = s => s.TotalChestsBlown, Target = 5_000, BigNumbers = true, RewardFrags = 25 },
// ── The prestige wall ──
new IdleAchievement { Id = "meltdown_1", Name = "Critical", Icon = "☢️",
Desc = "Trigger your first Meltdown.",
Progress = s => s.Meltdowns, Target = 1, RewardFlux = 3, RewardFrags = 40 },
new IdleAchievement { Id = "meltdown_5", Name = "Serial Offender", Icon = "🔁",
Desc = "Trigger 5 Meltdowns.",
Progress = s => s.Meltdowns, Target = 5, RewardFlux = 10, RewardFrags = 60 },
new IdleAchievement { Id = "flux_50", Name = "Fluxed", Icon = "🔷",
Desc = "Earn 50 Flux in total.",
Progress = s => s.FluxEarned, Target = 50, RewardFrags = 50 },
// ── Long haul ──
new IdleAchievement { Id = "cps_10k", Name = "Ten Thousand A Second", Icon = "📈",
Desc = "Reach 10K Cores per second.",
Progress = s => s.BestCps, Target = 10_000, BigNumbers = true, RewardFlux = 5, RewardFrags = 50 },
new IdleAchievement { Id = "chain_60", Name = "Board Wipe", Icon = "🧨",
Desc = "Clear 60 chests in a single detonation.",
Progress = s => s.BestChain, Target = 60, RewardFlux = 6, RewardFrags = 60 },
new IdleAchievement { Id = "cores_1b", Name = "Billionaire", Icon = "💎",
Desc = "Bank 1B Cores in one cycle.",
Progress = s => s.CycleCores, Target = 1e9, BigNumbers = true, RewardFlux = 15, RewardFrags = 100 },
new IdleAchievement { Id = "runtime_2h", Name = "Shift Worker", Icon = "🕒",
Desc = "Watch the reactor for 2 hours total.",
Progress = s => s.SecondsRun, Target = 7_200, RewardFrags = 40 },
new IdleAchievement { Id = "runtime_10h", Name = "Reactor Chief", Icon = "🎖️",
Desc = "Watch the reactor for 10 hours total.",
Progress = s => s.SecondsRun, Target = 36_000, RewardFlux = 12, RewardFrags = 120 },
new IdleAchievement { Id = "alltime_1t", Name = "Chain Reaction", Icon = "♾️",
Desc = "Produce 1T Cores across all cycles.",
Progress = s => s.AllTimeCores, Target = 1e12, BigNumbers = true, RewardFlux = 40, RewardFrags = 250 },
};
/// <summary>
/// Marks any newly completed achievement and returns them so the HUD can toast.
/// Rewards are applied by the caller (it owns PlayerSave).
/// </summary>
public static List<IdleAchievement> CollectNewlyCompleted( IdleSave s )
{
List<IdleAchievement> done = null;
foreach ( var a in All )
{
if ( s.HasAchievement( a.Id ) ) continue;
if ( !a.IsDone( s ) ) continue;
s.Achievements.Add( a.Id );
(done ??= new()).Add( a );
}
return done ?? new List<IdleAchievement>();
}
public static int CompletedCount( IdleSave s ) => All.Count( a => s.HasAchievement( a.Id ) );
}