MainHud/AchievementManager.cs

Static AchievementManager for the HUD. Checks various game conditions (streaks, damage taken, chosen weapon, prestige, jackpot, hp states) and unlocks corresponding achievements via Sandbox.Services.Achievements, returning a list of strings to display (with an ASCII banner when any unlocked).

NetworkingFile Access
using Keyboard_Warriors_.Models;
using Keyboard_Warriors_.Systems;
using System;
using System.Collections.Generic;
using System.Linq; // 🚀 Required to use .Any() to check the list!

namespace Keyboard_Warriors_.Managers
{
	public static class AchievementManager
	{
		public static List<string> CheckAchievements( bool tookDamage, int winStreak, int lossStreak, Weapon chosenWeapon, Player player, Player ai, ref bool hitJackpot, int round = 0 )
		{
			List<string> unlocked = new List<string>();

			// Grab the active GameManager instance out of the scene to read prestige values
			var manager = Sandbox.Game.ActiveScene.Get<GameManager>();

			// 1. Steel Defense
			if ( manager != null && !manager.HasPlayerTakenAnyDamage )
			{
				if ( !Sandbox.Services.Achievements.All.Any( a => a.Name == "steel_defense" && a.IsUnlocked ) )
				{
					Sandbox.Services.Achievements.Unlock( "steel_defense" );
					unlocked.Add( "\n🏆 ACHIEVEMENT UNLOCKED: 'Steel Defense'" );
					unlocked.Add( "\"This must be the Battle of Trenton. Zero damage taken!\"" );
				}
			}

			// 2. Prisoner Streak
			if ( winStreak == 5 )
			{
				if ( !Sandbox.Services.Achievements.All.Any( a => a.Name == "prisoner_streak" && a.IsUnlocked ) )
				{
					Sandbox.Services.Achievements.Unlock( "prisoner_streak" );
					unlocked.Add( "\n🏆 ACHIEVEMENT UNLOCKED: 'Prisoner Streak'" );
					unlocked.Add( "\"5 wins in a row? Prisoners could do better!\"" );
				}
			}

			// 3. HAL's Worst Nightmare
			if ( winStreak == 10 )
			{
				if ( !Sandbox.Services.Achievements.All.Any( a => a.Name == "hals_nightmare" && a.IsUnlocked ) )
				{
					Sandbox.Services.Achievements.Unlock( "hals_nightmare" );
					unlocked.Add( "\n🏆 ACHIEVEMENT UNLOCKED: 'HAL's Worst Nightmare'" );
					unlocked.Add( "\"10 straight wins? AI's are starting to recognize fear!\"" );
				}
			}

			// 4. New Assassin
			if ( chosenWeapon?.name == "Dagger" && winStreak == 5 )
			{
				if ( !Sandbox.Services.Achievements.All.Any( a => a.Name == "new_assassin" && a.IsUnlocked ) )
				{
					Sandbox.Services.Achievements.Unlock( "new_assassin" );
					unlocked.Add( "\n🏆 ACHIEVEMENT UNLOCKED: 'New Assassin'" );
					unlocked.Add( "\"5 wins with a dagger.. Okay Altair!\"" );
				}
			}

			// 5. Final Breath
			if ( player.hp <= 0 && ai.hp <= 0 )
			{
				if ( !Sandbox.Services.Achievements.All.Any( a => a.Name == "final_breath" && a.IsUnlocked ) )
				{
					Sandbox.Services.Achievements.Unlock( "final_breath" );
					unlocked.Add( "\n🏆 ACHIEVEMENT UNLOCKED: 'Final Breath'" );
					unlocked.Add( "\"At 0 hp, you let one last strike or events caused the AI down with you. A tie in glory!\"" );
				}
			}

			// 6. Scratch of the Gods
			if ( hitJackpot )
			{
				if ( !Sandbox.Services.Achievements.All.Any( a => a.Name == "scratch_of_gods" && a.IsUnlocked ) )
				{
					Sandbox.Services.Achievements.Unlock( "scratch_of_gods" );
					unlocked.Add( "\n🏆 ACHIEVEMENT UNLOCKED: 'Scratch of the Gods'" );
					unlocked.Add( "\"You hit the jackpot during battle, the points are yours!\"" );
				}
				hitJackpot = false;
			}

			// 7. Loss Streak 5
			if ( lossStreak == 5 )
			{
				if ( !Sandbox.Services.Achievements.All.Any( a => a.Name == "turn_off_on" && a.IsUnlocked ) )
				{
					Sandbox.Services.Achievements.Unlock( "turn_off_on" );
					unlocked.Add( "\n🏆 ACHIEVEMENT UNLOCKED: 'Try Turning It Off and On Again'" );
					unlocked.Add( "\"AI: 5 losses in a row... Is all well up there?\"" );
				}
			}

			// 8. Loss Streak 10
			if ( lossStreak == 10 )
			{
				if ( !Sandbox.Services.Achievements.All.Any( a => a.Name == "laughing_at_you" && a.IsUnlocked ) )
				{
					Sandbox.Services.Achievements.Unlock( "laughing_at_you" );
					unlocked.Add( "\n🏆 ACHIEVEMENT UNLOCKED: 'Your Computer's Laughing At You!'" );
					unlocked.Add( "\"AI: *Electronic Laughter Intensifies*\"" );
					GameManager.AddLog( "AI: \"Statistically, you are becoming quite a funny data point.\"" );
				}
			}

			// 👑 9. NEW MILESTONE: QA KeyboardWarrior! 👑
			// Triggers automatically the absolute millisecond they achieve Prestige level 1!
			if ( manager != null && manager.CurrentPrestige >= 1 )
			{
				if ( !Sandbox.Services.Achievements.All.Any( a => a.Name == "qa_keyboard_warrior" && a.IsUnlocked ) )
				{
					Sandbox.Services.Achievements.Unlock( "qa_keyboard_warrior" );
					unlocked.Add( "\n🏆 ACHIEVEMENT UNLOCKED: 'QA KeyboardWarrior!'" );
					unlocked.Add( "\"You broke out of the baseline matrix compilation lane. Welcome to Prestige 1!\"" );
				}
			}

			// 10. Prestige 10
			if ( manager != null && manager.CurrentPrestige == 10 )
			{
				if ( !Sandbox.Services.Achievements.All.Any( a => a.Name == "ten_prestige" && a.IsUnlocked ) )
				{
					Sandbox.Services.Achievements.Unlock( "ten_prestige" );
					unlocked.Add( "\n🏆 ACHIEVEMENT UNLOCKED: 'Keyboard Warrior Special Ops'" );
					unlocked.Add( "\"Prestige 10? AI is starting to watch its back!\"" );
				}
			}

			// 👑 RE-ORDERED SYSTEM: If anything unlocked, construct the ASCII banner first 
			// so it prints gracefully over the top of the description lines in your scroll panels!
			if ( unlocked.Count > 0 )
			{
				List<string> finishedLayoutList = new List<string>();

				string bannerLines = @"
   _   _____  _   _ _____ _____ _   _ _____ ______  _____ _   _ _____   _   _ _   _  _     _____ _____  _   __ _____ _____ _
 / _ \/  __ \| | | |_   _|  ___| | | |  ___|  \/  ||  ___| \ | |_   _| | | | | \ | || |   |  _  /  __ \| | / /|  ___|  _  \ |
/ /_\ \ /  \/| |_| | | | | |__ | | | | |__ | .  . || |__ |  \| | | |   | | | |  \| || |   | | | | /  \/| |/ / | |__ | | | | |
|  _  | |    |  _  | | | |  __|| | | |  __|| |\/| ||  __|| . ` | | |   | | | | . ` || |   | | | | |    |    \ |  __|| | | | |
| | | | \__/\| | | |_| |_| |___\ \_/ / |___| |  | || |___| |\  | | |   | |_| | |\  || |___\ \_/ / \__/\| |\  \| |___| |/ /|_|
\_| |_/\____/\_| |_/\___/\____/ \___/\____/\_|  |_/\____/\_| \_/ \_/    \___/\_| \_/\_____/\___/ \____/\_| \_/\____/|___/ (_)
";

				// 1. Pack the grand banner elements at the top
				foreach ( var line in bannerLines.Split( '\n' ) )
				{
					if ( !string.IsNullOrWhiteSpace( line ) || line.Length > 2 )
					{
						finishedLayoutList.Add( line );
					}
				}

				// 2. Append the descriptive unlock text strings right below it
				finishedLayoutList.AddRange( unlocked );

				return finishedLayoutList;
			}

			return unlocked;
		}
	}
}