prechody
This commit is contained in:
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<PageTitle>NULL DEPTH</PageTitle>
|
<PageTitle>NULL DEPTH</PageTitle>
|
||||||
|
|
||||||
<main class="game-shell @(_isTransitioning ? "transitioning" : "") @(_systemFlash ? "system-alert" : "")" tabindex="0" @ref="_shell" @onkeydown="HandleKey">
|
<main class="game-shell @(_isTransitioning ? $"transitioning dir-{_moveDirection}" : "") @(_systemFlash ? "system-alert" : "")" tabindex="0" @ref="_shell" @onkeydown="HandleKey">
|
||||||
@if (!_ready)
|
@if (!_ready)
|
||||||
{
|
{
|
||||||
<section class="loading-screen">
|
<section class="loading-screen">
|
||||||
@@ -438,6 +438,9 @@
|
|||||||
}
|
}
|
||||||
<div class="system-flash" aria-hidden="true"></div>
|
<div class="system-flash" aria-hidden="true"></div>
|
||||||
<div class="screen-fade" aria-hidden="true"></div>
|
<div class="screen-fade" aria-hidden="true"></div>
|
||||||
|
<div class="screen-glitch @(_crtSync ? "active" : "")" aria-hidden="true"></div>
|
||||||
|
<div class="screen-reboot @(_rebootFlash ? "active" : "")" aria-hidden="true"></div>
|
||||||
|
<div class="screen-death-flash @(_deathFlash ? "active" : "")" aria-hidden="true"></div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
@@ -457,6 +460,10 @@
|
|||||||
private bool _scanMode;
|
private bool _scanMode;
|
||||||
private bool _isFullscreen;
|
private bool _isFullscreen;
|
||||||
private bool _isTransitioning;
|
private bool _isTransitioning;
|
||||||
|
private string _moveDirection = "north";
|
||||||
|
private bool _crtSync;
|
||||||
|
private bool _rebootFlash;
|
||||||
|
private bool _deathFlash;
|
||||||
private bool _systemFlash;
|
private bool _systemFlash;
|
||||||
private bool _savePulse;
|
private bool _savePulse;
|
||||||
private int _savePulseVersion;
|
private int _savePulseVersion;
|
||||||
@@ -529,6 +536,7 @@
|
|||||||
await Game.NewGameAsync();
|
await Game.NewGameAsync();
|
||||||
_screen = Screen.Briefing;
|
_screen = Screen.Briefing;
|
||||||
_notice = null;
|
_notice = null;
|
||||||
|
_ = TriggerCrtSyncAsync();
|
||||||
await Audio.PlayAmbientAsync("assets/audio/amb_facility.mp3");
|
await Audio.PlayAmbientAsync("assets/audio/amb_facility.mp3");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,6 +548,7 @@
|
|||||||
_scanMode = false;
|
_scanMode = false;
|
||||||
_ending = Game.State.CompletedEnding;
|
_ending = Game.State.CompletedEnding;
|
||||||
_screen = _ending is null ? Screen.Game : Screen.Ending;
|
_screen = _ending is null ? Screen.Game : Screen.Ending;
|
||||||
|
_ = TriggerCrtSyncAsync();
|
||||||
await Audio.PlayAmbientAsync(Game.CurrentRoom.Ambient);
|
await Audio.PlayAmbientAsync(Game.CurrentRoom.Ambient);
|
||||||
await Audio.SetHeartbeatBpmAsync(Game.CurrentBpm);
|
await Audio.SetHeartbeatBpmAsync(Game.CurrentBpm);
|
||||||
}
|
}
|
||||||
@@ -547,6 +556,7 @@
|
|||||||
private async Task BeginPlay()
|
private async Task BeginPlay()
|
||||||
{
|
{
|
||||||
_screen = Screen.Game;
|
_screen = Screen.Game;
|
||||||
|
_ = TriggerCrtSyncAsync();
|
||||||
await Audio.PlayAmbientAsync(Game.CurrentRoom.Ambient);
|
await Audio.PlayAmbientAsync(Game.CurrentRoom.Ambient);
|
||||||
await Audio.SetHeartbeatBpmAsync(Game.CurrentBpm);
|
await Audio.SetHeartbeatBpmAsync(Game.CurrentBpm);
|
||||||
}
|
}
|
||||||
@@ -556,6 +566,7 @@
|
|||||||
if (_isTransitioning) return;
|
if (_isTransitioning) return;
|
||||||
if (!Game.CurrentRoom.Exits.TryGetValue(direction, out var exit)) return;
|
if (!Game.CurrentRoom.Exits.TryGetValue(direction, out var exit)) return;
|
||||||
if (!Game.HasAll(exit.RequiresFlags)) { _notice = Game.T(exit.LockedMessageKey ?? "game.exit.locked"); return; }
|
if (!Game.HasAll(exit.RequiresFlags)) { _notice = Game.T(exit.LockedMessageKey ?? "game.exit.locked"); return; }
|
||||||
|
_moveDirection = direction;
|
||||||
_isTransitioning = true;
|
_isTransitioning = true;
|
||||||
await Audio.PlaySfxAsync("assets/audio/sfx_door_heavy.mp3");
|
await Audio.PlaySfxAsync("assets/audio/sfx_door_heavy.mp3");
|
||||||
await Task.Delay(150);
|
await Task.Delay(150);
|
||||||
@@ -654,7 +665,7 @@
|
|||||||
_interaction = null;
|
_interaction = null;
|
||||||
if (choice.Sound?.Contains("alarm") == true || choice.Sound?.Contains("disturbance") == true)
|
if (choice.Sound?.Contains("alarm") == true || choice.Sound?.Contains("disturbance") == true)
|
||||||
_ = TriggerSystemFlashAsync();
|
_ = TriggerSystemFlashAsync();
|
||||||
if (choice.Death) { await Audio.SetHeartbeatBpmAsync(0); _screen = Screen.Death; return; }
|
if (choice.Death) { await Audio.SetHeartbeatBpmAsync(0); _ = TriggerDeathFlashAsync(); _screen = Screen.Death; return; }
|
||||||
if (!string.IsNullOrWhiteSpace(choice.Ending)) { await Audio.SetHeartbeatBpmAsync(0); _ending = choice.Ending; _screen = Screen.Ending; return; }
|
if (!string.IsNullOrWhiteSpace(choice.Ending)) { await Audio.SetHeartbeatBpmAsync(0); _ending = choice.Ending; _screen = Screen.Ending; return; }
|
||||||
await Audio.SetHeartbeatBpmAsync(Game.CurrentBpm);
|
await Audio.SetHeartbeatBpmAsync(Game.CurrentBpm);
|
||||||
await Task.Delay(180);
|
await Task.Delay(180);
|
||||||
@@ -686,6 +697,7 @@
|
|||||||
await Game.RestoreCheckpointAsync();
|
await Game.RestoreCheckpointAsync();
|
||||||
_screen = Screen.Game;
|
_screen = Screen.Game;
|
||||||
_notice = Game.T("death.restored");
|
_notice = Game.T("death.restored");
|
||||||
|
_ = TriggerRebootAsync();
|
||||||
await Audio.PlayAmbientAsync(Game.CurrentRoom.Ambient);
|
await Audio.PlayAmbientAsync(Game.CurrentRoom.Ambient);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -786,6 +798,33 @@
|
|||||||
await InvokeAsync(StateHasChanged);
|
await InvokeAsync(StateHasChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task TriggerCrtSyncAsync()
|
||||||
|
{
|
||||||
|
_crtSync = true;
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
await Task.Delay(220);
|
||||||
|
_crtSync = false;
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task TriggerRebootAsync()
|
||||||
|
{
|
||||||
|
_rebootFlash = true;
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
await Task.Delay(480);
|
||||||
|
_rebootFlash = false;
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task TriggerDeathFlashAsync()
|
||||||
|
{
|
||||||
|
_deathFlash = true;
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
await Task.Delay(750);
|
||||||
|
_deathFlash = false;
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
|
||||||
private string MenuClass(int index) => _menuIndex == index ? "selected" : "";
|
private string MenuClass(int index) => _menuIndex == index ? "selected" : "";
|
||||||
|
|
||||||
private async Task HandleKey(KeyboardEventArgs args)
|
private async Task HandleKey(KeyboardEventArgs args)
|
||||||
|
|||||||
@@ -11,9 +11,23 @@ button:disabled { opacity:.28; cursor:not-allowed; background:transparent; color
|
|||||||
kbd, .eyebrow, .subtitle, .top-hud, .command-bar, .terminal-copy, small { font-family:'IBM Plex Mono',Consolas,monospace; }
|
kbd, .eyebrow, .subtitle, .top-hud, .command-bar, .terminal-copy, small { font-family:'IBM Plex Mono',Consolas,monospace; }
|
||||||
kbd { color:var(--cyan); background:none; padding:0; }
|
kbd { color:var(--cyan); background:none; padding:0; }
|
||||||
.game-shell { position:relative; width:100%; height:100%; outline:none; background:#020507; }
|
.game-shell { position:relative; width:100%; height:100%; outline:none; background:#020507; }
|
||||||
.screen-fade, .system-flash { position:absolute; inset:0; z-index:50; pointer-events:none; opacity:0; }
|
.screen-fade, .system-flash, .screen-glitch, .screen-reboot, .screen-death-flash { position:absolute; inset:0; z-index:50; pointer-events:none; opacity:0; }
|
||||||
.screen-fade { background:#010304; transition:opacity .15s ease; }
|
.screen-fade { background:#010304; transition:opacity .15s ease; }
|
||||||
.game-shell.transitioning .screen-fade { opacity:1; transition-duration:.22s; }
|
.game-shell.transitioning .screen-fade { opacity:1; transition-duration:.18s; }
|
||||||
|
.game-shell.transitioning.dir-north .parallax-bg { transform:translate3d(calc(var(--mouse-px, 0) * -14px), calc(var(--mouse-py, 0) * -14px - 18px), 0) scale(1.08); }
|
||||||
|
.game-shell.transitioning.dir-south .parallax-bg { transform:translate3d(calc(var(--mouse-px, 0) * -14px), calc(var(--mouse-py, 0) * -14px + 18px), 0) scale(0.98); }
|
||||||
|
.game-shell.transitioning.dir-west .parallax-bg { transform:translate3d(calc(var(--mouse-px, 0) * -14px - 22px), calc(var(--mouse-py, 0) * -14px), 0) scale(1.04); }
|
||||||
|
.game-shell.transitioning.dir-east .parallax-bg { transform:translate3d(calc(var(--mouse-px, 0) * -14px + 22px), calc(var(--mouse-py, 0) * -14px), 0) scale(1.04); }
|
||||||
|
|
||||||
|
.screen-glitch.active { opacity:1; animation:crt-glitch .22s ease-out both; }
|
||||||
|
@keyframes crt-glitch { 0% { opacity:0; transform:scale(1.02); filter:brightness(2.2) contrast(1.6); } 25% { opacity:1; transform:scale(0.99) skewX(1deg); } 65% { opacity:0.7; transform:scale(1.01) skewX(-0.5deg); } 100% { opacity:0; transform:scale(1); } }
|
||||||
|
|
||||||
|
.screen-reboot.active { opacity:1; animation:reboot-flash .5s ease-out both; }
|
||||||
|
@keyframes reboot-flash { 0% { opacity:1; } 100% { opacity:0; } }
|
||||||
|
|
||||||
|
.screen-death-flash.active { opacity:1; animation:death-flash .75s ease-out both; }
|
||||||
|
@keyframes death-flash { 0% { opacity:1; } 40% { opacity:0.9; } 100% { opacity:0; } }
|
||||||
|
|
||||||
.system-flash { z-index:40; background:radial-gradient(circle at 50% 45%,rgba(255,74,80,.35),rgba(125,0,8,.12) 42%,transparent 72%); }
|
.system-flash { z-index:40; background:radial-gradient(circle at 50% 45%,rgba(255,74,80,.35),rgba(125,0,8,.12) 42%,transparent 72%); }
|
||||||
.game-shell.system-alert .system-flash { animation:system-flash .65s steps(2,end); }
|
.game-shell.system-alert .system-flash { animation:system-flash .65s steps(2,end); }
|
||||||
@keyframes system-flash { 0%,100% { opacity:0; } 15%,45% { opacity:1; } 30%,65% { opacity:.18; } }
|
@keyframes system-flash { 0%,100% { opacity:0; } 15%,45% { opacity:1; } 30%,65% { opacity:.18; } }
|
||||||
@@ -67,8 +81,12 @@ kbd { color:var(--cyan); background:none; padding:0; }
|
|||||||
.movement-pad { position:absolute; right:2rem; bottom:6.2rem; display:grid; grid-template:repeat(3,2.7rem)/repeat(3,2.7rem); gap:.25rem; z-index:10; }
|
.movement-pad { position:absolute; right:2rem; bottom:6.2rem; display:grid; grid-template:repeat(3,2.7rem)/repeat(3,2.7rem); gap:.25rem; z-index:10; }
|
||||||
.movement-pad button { padding:0; font-size:1.2rem; background:rgba(2,8,11,.78); }.movement-pad .north { grid-area:1/2; }.movement-pad .west { grid-area:2/1; }.movement-pad .position { grid-area:2/2; display:grid; place-items:center; color:var(--muted); font:.58rem 'IBM Plex Mono'; }.movement-pad .east { grid-area:2/3; }.movement-pad .south { grid-area:3/2; }
|
.movement-pad button { padding:0; font-size:1.2rem; background:rgba(2,8,11,.78); }.movement-pad .north { grid-area:1/2; }.movement-pad .west { grid-area:2/1; }.movement-pad .position { grid-area:2/2; display:grid; place-items:center; color:var(--muted); font:.58rem 'IBM Plex Mono'; }.movement-pad .east { grid-area:2/3; }.movement-pad .south { grid-area:3/2; }
|
||||||
.command-bar { position:absolute; left:0; right:0; bottom:0; display:flex; justify-content:center; gap:.5rem; padding:.8rem; background:rgba(1,6,8,.91); border-top:1px solid rgba(158,239,255,.16); z-index:15; }.command-bar button { border:0; font-size:.66rem; }
|
.command-bar { position:absolute; left:0; right:0; bottom:0; display:flex; justify-content:center; gap:.5rem; padding:.8rem; background:rgba(1,6,8,.91); border-top:1px solid rgba(158,239,255,.16); z-index:15; }.command-bar button { border:0; font-size:.66rem; }
|
||||||
.modal-layer { position:absolute; inset:0; z-index:30; display:grid; place-items:center; padding:2rem; background:rgba(0,3,5,.75); backdrop-filter:blur(8px); }
|
.modal-layer { position:absolute; inset:0; z-index:30; display:grid; place-items:center; padding:2rem; background:rgba(0,3,5,.8); backdrop-filter:blur(12px); animation:modal-backdrop-in .18s ease-out both; }
|
||||||
.interaction-modal, .overlay-card { width:min(44rem,92vw); max-height:86vh; overflow:auto; padding:2rem; }.terminal-copy { white-space:pre-line; color:#bfe6ea; line-height:1.75; }
|
@keyframes modal-backdrop-in { from { opacity:0; } to { opacity:1; } }
|
||||||
|
|
||||||
|
.interaction-modal, .overlay-card, .breaker-switchboard { width:min(44rem,92vw); max-height:86vh; overflow:auto; padding:2rem; animation:modal-card-in .2s cubic-bezier(0.16, 1, 0.3, 1) both; }
|
||||||
|
@keyframes modal-card-in { from { opacity:0; transform:scale(0.96) translateY(8px); } to { opacity:1; transform:scale(1) translateY(0); } }
|
||||||
|
.terminal-copy { white-space:pre-line; color:#bfe6ea; line-height:1.75; }
|
||||||
.terminal-copy strong { color:var(--cyan); }
|
.terminal-copy strong { color:var(--cyan); }
|
||||||
.close-button { position:absolute; top:.65rem; right:.65rem; border:0; font-size:1.3rem; padding:.35rem .6rem; }
|
.close-button { position:absolute; top:.65rem; right:.65rem; border:0; font-size:1.3rem; padding:.35rem .6rem; }
|
||||||
.choice-list { display:flex; flex-direction:column; gap:.6rem; margin-top:1.5rem; }.choice-list button { text-align:left; line-height:1.4; padding:.8rem 1rem; }
|
.choice-list { display:flex; flex-direction:column; gap:.6rem; margin-top:1.5rem; }.choice-list button { text-align:left; line-height:1.4; padding:.8rem 1rem; }
|
||||||
|
|||||||
Reference in New Issue
Block a user