diff --git a/src/NullDepth/Game/GameService.cs b/src/NullDepth/Game/GameService.cs index bff10dc..35191c5 100644 --- a/src/NullDepth/Game/GameService.cs +++ b/src/NullDepth/Game/GameService.cs @@ -179,6 +179,7 @@ public sealed class GameService(HttpClient http, IJSRuntime js) if (!HasAll(exit.RequiresFlags)) return T(exit.LockedMessageKey ?? "game.exit.locked"); State.CurrentRoomId = exit.Target; State.VisitedRooms.Add(exit.Target); + await CheckAchievementsAsync(); await SaveAsync(); return ""; } @@ -204,9 +205,47 @@ public sealed class GameService(HttpClient http, IJSRuntime js) } } if (interaction.Checkpoint) SetCheckpoint(); + await CheckAchievementsAsync(); await SaveAsync(); } + public static readonly List AchievementsList = + [ + new() { Id = "ach_descent", TitleKey = "ach.descent.title", DescriptionKey = "ach.descent.desc", Icon = "▼" }, + new() { Id = "ach_cold_blood", TitleKey = "ach.coldBlood.title", DescriptionKey = "ach.coldBlood.desc", Icon = "♥" }, + new() { Id = "ach_electrician", TitleKey = "ach.electrician.title", DescriptionKey = "ach.electrician.desc", Icon = "⚡" }, + new() { Id = "ach_waveform", TitleKey = "ach.waveform.title", DescriptionKey = "ach.waveform.desc", Icon = "〰" }, + new() { Id = "ach_dialogue", TitleKey = "ach.dialogue.title", DescriptionKey = "ach.dialogue.desc", Icon = "◆" }, + new() { Id = "ach_archivist", TitleKey = "ach.archivist.title", DescriptionKey = "ach.archivist.desc", Icon = "📖" }, + new() { Id = "ach_ending_a", TitleKey = "ach.endingA.title", DescriptionKey = "ach.endingA.desc", Icon = "📡" }, + new() { Id = "ach_ending_b", TitleKey = "ach.endingB.title", DescriptionKey = "ach.endingB.desc", Icon = "⏻" }, + new() { Id = "ach_ending_c", TitleKey = "ach.endingC.title", DescriptionKey = "ach.endingC.desc", Icon = "🔒" }, + new() { Id = "ach_survivor", TitleKey = "ach.survivor.title", DescriptionKey = "ach.survivor.desc", Icon = "★" } + ]; + + public async Task UnlockAchievementAsync(string id) + { + if (Profile.UnlockedAchievements.Add(id)) + { + await SaveProfileAsync(); + return true; + } + return false; + } + + public async Task CheckAchievementsAsync() + { + if (State.CurrentRoomId == "loc_08_lower_landing") await UnlockAchievementAsync("ach_descent"); + if (State.Flags.Contains("manual_override_found")) await UnlockAchievementAsync("ach_electrician"); + if (State.Flags.Contains("asked_why") && State.Flags.Contains("asked_staff") && State.Flags.Contains("asked_reconnect")) + await UnlockAchievementAsync("ach_dialogue"); + if (Profile.DiscoveredArchives.Count >= 6) await UnlockAchievementAsync("ach_archivist"); + if (State.CompletedEnding == "release") await UnlockAchievementAsync("ach_ending_a"); + if (State.CompletedEnding == "shutdown") await UnlockAchievementAsync("ach_ending_b"); + if (State.CompletedEnding == "containment") await UnlockAchievementAsync("ach_ending_c"); + if (State.CompletedEnding is not null && CurrentBpm < 100) await UnlockAchievementAsync("ach_cold_blood"); + } + public async Task ApplyChoiceAsync(ChoiceDefinition choice) { Apply(choice.SetFlags, choice.ClearFlags, choice.AddItems); @@ -220,6 +259,7 @@ public sealed class GameService(HttpClient http, IJSRuntime js) } } if (choice.Checkpoint) SetCheckpoint(); + await CheckAchievementsAsync(); await SaveAsync(); } diff --git a/src/NullDepth/Models/GameModels.cs b/src/NullDepth/Models/GameModels.cs index 5d6adfc..a9d8a80 100644 --- a/src/NullDepth/Models/GameModels.cs +++ b/src/NullDepth/Models/GameModels.cs @@ -131,6 +131,15 @@ public sealed class PlayerProfile { public HashSet UnlockedEndings { get; set; } = []; public HashSet DiscoveredArchives { get; set; } = []; + public HashSet UnlockedAchievements { get; set; } = []; +} + +public sealed class AchievementDefinition +{ + public string Id { get; set; } = ""; + public string TitleKey { get; set; } = ""; + public string DescriptionKey { get; set; } = ""; + public string Icon { get; set; } = "★"; } public enum SaveLoadResult diff --git a/src/NullDepth/Pages/Home.razor b/src/NullDepth/Pages/Home.razor index cef0cc3..285f9bb 100644 --- a/src/NullDepth/Pages/Home.razor +++ b/src/NullDepth/Pages/Home.razor @@ -42,7 +42,8 @@ @@ -76,6 +77,23 @@
+ @if (room.Id == "loc_01_exterior_access") + { +
+ } + @if (room.Id is "loc_09_cooling_junction" or "loc_10_cooling_control") + { +
+ } + @if (room.Id == "loc_11_equipment_storage" && !Game.State.Flags.Contains("manual_override_found")) + { +
+ } + @if (room.Id is "loc_14_core_access" or "loc_15_server_core") + { +
+ } + @if (_scanMode) {
@@ -311,8 +329,9 @@

@(selectedItem.DetailedKey is not null ? Game.T(selectedItem.DetailedKey) : Game.T(selectedItem.DescriptionKey))

@if (selectedItem.Id == "diagnostic_scanner") { -
+
+
}
@@ -372,6 +391,71 @@
} + @if (_showWaveformPuzzle) + { + + } + @if (_showCodex) + { + + } @if (_showPause) {