From cc8d12a540a17085f5884ea3638c2948ff849918 Mon Sep 17 00:00:00 2001
From: Nyeogmi <economicsbat@gmail.com>
Date: Sat, 8 Feb 2025 17:56:27 -0800
Subject: [PATCH] Endgame screen with fake numbers

---
 src/endgamemodal.ts | 78 +++++++++++++++++++++++++++++++++++++++++++++
 src/game.ts         | 58 +++++++++++++++++++--------------
 src/gameplay.ts     | 29 +++++++++++++++++
 src/statemanager.ts | 12 ++++---
 src/vnmodal.ts      | 58 ++++++++++++++++++++-------------
 5 files changed, 183 insertions(+), 52 deletions(-)
 create mode 100644 src/endgamemodal.ts
 create mode 100644 src/gameplay.ts

diff --git a/src/endgamemodal.ts b/src/endgamemodal.ts
new file mode 100644
index 0000000..53e7918
--- /dev/null
+++ b/src/endgamemodal.ts
@@ -0,0 +1,78 @@
+import {withCamera} from "./layout.ts";
+import {D} from "./engine/public.ts";
+import {FG_BOLD, FG_TEXT} from "./colors.ts";
+import {AlignX, Point, Rect, Size} from "./engine/datatypes.ts";
+import {DrawPile} from "./drawpile.ts";
+import {addButton} from "./button.ts";
+
+const WIDTH = 384;
+const HEIGHT = 384;
+
+export class EndgameModal {
+  #isShown: boolean;
+  #drawpile: DrawPile;
+
+  constructor() {
+    this.#isShown = false;
+    this.#drawpile = new DrawPile();
+
+    // debug
+  }
+
+  get isShown(): boolean {
+    return this.#isShown;
+  }
+
+  show() {
+    this.#isShown = true;
+  }
+
+  update() {
+    withCamera("FullscreenPopover", () => this.#update())
+  }
+
+  draw() {
+    withCamera("FullscreenPopover", () => this.#draw())
+  }
+
+  #update() {
+    this.#drawpile.clear();
+    addButton(
+      this.#drawpile,
+      "Appoint a Successor",
+      new Rect(
+        new Point(0, HEIGHT - 32), new Size(WIDTH, 32)
+      ),
+      true,
+      () => {
+        alert("beep");
+      }
+    )
+    this.#drawpile.executeOnClick();
+  }
+
+  #draw() {
+    D.drawText("It is time to announce the sentence of fate.", new Point(0, 0), FG_TEXT)
+    D.drawText("You are no longer a fledgling. Your new rank:", new Point(0, 32), FG_TEXT)
+    D.drawText("Progenitor", new Point(WIDTH/2, 64), FG_BOLD, {alignX: AlignX.Center})
+    D.drawText("You have achieved a DOMICILE STATUS of:", new Point(0, 96), FG_TEXT)
+    D.drawText("Guest House", new Point(WIDTH/2, 128), FG_BOLD, {alignX: AlignX.Center})
+    D.drawText("where you live with many friends.", new Point(0, 160), FG_TEXT)
+    D.drawText("You have achieved:", new Point(0, 192), FG_TEXT)
+    D.drawText("48 items purloined\n96 vampiric skills\n50 mortal servants", new Point(WIDTH/2, 224), FG_TEXT, {alignX: AlignX.Center})
+    D.drawText("48                \n96                \n50                ", new Point(WIDTH/2, 224), FG_BOLD, {alignX: AlignX.Center})
+    D.drawText("That feels like a lot!", new Point(0, 288), FG_TEXT)
+    D.drawText("Your reign continues unimpeded from the shadows. It is now time to", new Point(0, 320), FG_TEXT, {forceWidth: WIDTH})
+
+    this.#drawpile.draw();
+  }
+
+  get blocksHud(): boolean {
+    return true;
+  }
+}
+
+let active = new EndgameModal();
+export function getEndgameModal() {
+  return active;
+}
\ No newline at end of file
diff --git a/src/game.ts b/src/game.ts
index 105bf2e..e737064 100644
--- a/src/game.ts
+++ b/src/game.ts
@@ -1,13 +1,13 @@
 import {BG_OUTER} from "./colors.ts";
 import {D, I} from "./engine/public.ts";
 import {IGame, Point, Size} from "./engine/datatypes.ts";
-import {getHuntMode} from "./huntmode.ts";
-import {getPageLocation, Page, withCamera} from "./layout.ts";
-import {getHud} from "./hud.ts";
+import {getPageLocation, Page} from "./layout.ts";
 import {getHotbar, Hotbar} from "./hotbar.ts";
 import {getSkillsModal, SkillsModal} from "./skillsmodal.ts";
 import {getSleepModal, SleepModal} from "./sleepmodal.ts";
-import {getEndgameModal} from "./vnmodal.ts";
+import {getVNModal, VNModal} from "./vnmodal.ts";
+import {Gameplay, getGameplay} from "./gameplay.ts";
+import {getEndgameModal} from "./endgamemodal.ts";
 
 class MenuCamera {
   // measured in whole screens
@@ -33,6 +33,7 @@ class MenuCamera {
 export class Game implements IGame {
   camera: MenuCamera;
   page: Page;
+  #mainThing: Gameplay | VNModal | null;
   #bottomThing: SkillsModal | SleepModal | Hotbar | null;
 
   constructor() {
@@ -42,16 +43,13 @@ export class Game implements IGame {
     });
     this.page = "Gameplay";
 
+    this.#mainThing = null;
     this.#bottomThing = null;
   }
 
   update() {
-    if (I.isKeyPressed("w")) {
-      this.page = "Gameplay"
-    }
-    if (I.isKeyPressed("s")) {
-      this.page = "Thralls"
-    }
+    if (I.isKeyPressed("w")) { this.page = "Gameplay" }
+    if (I.isKeyPressed("s")) { this.page = "Thralls" }
 
     this.camera.target = getPageLocation(this.page);
     D.camera = new Point(
@@ -82,23 +80,22 @@ export class Game implements IGame {
   }
 
   updateGameplay() {
+    this.#chooseMainThing();
     this.#chooseBottomThing();
 
-    withCamera("Gameplay", () => {
-      getHuntMode().update();
-    });
-    withCamera("HUD", () => { getHud().update() })
-    this.#bottomThing?.update();
-    getEndgameModal().update();
+    this.#mainThing?.update();
+
+    if (!this.#mainThing?.blocksHud) {
+      this.#bottomThing?.update();
+    }
   }
 
   drawGameplay() {
-    withCamera("Gameplay", () => {
-      getHuntMode().draw();
-    });
-    withCamera("HUD", () => { getHud().draw() })
-    this.#bottomThing?.draw()
-    getEndgameModal().draw();
+    this.#mainThing?.draw();
+
+    if (!this.#mainThing?.blocksHud) {
+      this.#bottomThing?.draw()
+    }
   }
 
   #chooseBottomThing() {
@@ -126,8 +123,21 @@ export class Game implements IGame {
     this.#bottomThing = getHotbar();
   }
 
-  // withCamera("Hotbar", () => { getHotbar().draw() })
+  #chooseMainThing() {
+    let vnModal = getVNModal();
+    if (vnModal.isShown) {
+      this.#mainThing = vnModal;
+      return;
+    }
+
+    let endgameModal = getEndgameModal();
+    if (endgameModal.isShown) {
+      this.#mainThing = endgameModal;
+      return;
+    }
+
+    this.#mainThing = getGameplay();
+  }
 }
 
-
 export let game = new Game();
\ No newline at end of file
diff --git a/src/gameplay.ts b/src/gameplay.ts
new file mode 100644
index 0000000..15f8f4e
--- /dev/null
+++ b/src/gameplay.ts
@@ -0,0 +1,29 @@
+import {withCamera} from "./layout.ts";
+import {getHuntMode} from "./huntmode.ts";
+import {getHud} from "./hud.ts";
+
+export class Gameplay {
+  update() {
+    withCamera("Gameplay", () => {
+      getHuntMode().update();
+    });
+    withCamera("HUD", () => { getHud().update() })
+  }
+
+  draw() {
+    withCamera("Gameplay", () => {
+      getHuntMode().draw();
+    });
+    withCamera("HUD", () => { getHud().draw() })
+  }
+
+  get blocksHud(): boolean {
+    return false;
+  }
+}
+
+let active = new Gameplay();
+export function getGameplay(): Gameplay {
+  return active;
+}
+
diff --git a/src/statemanager.ts b/src/statemanager.ts
index 9dc597b..15e97af 100644
--- a/src/statemanager.ts
+++ b/src/statemanager.ts
@@ -1,8 +1,9 @@
 import {getPlayerProgress} from "./playerprogress.ts";
 import {getHuntMode} from "./huntmode.ts";
 import {getSleepModal} from "./sleepmodal.ts";
-import {getEndgameModal} from "./vnmodal.ts";
+import {getVNModal} from "./vnmodal.ts";
 import {getScorer} from "./scorer.ts";
+import {getEndgameModal} from "./endgamemodal.ts";
 
 const N_TURNS: number = 9;
 
@@ -18,16 +19,17 @@ export class StateManager {
   }
 
   advance() {
-    this.#turn += 1;
+    getSleepModal().setShown(false);
 
-    if (this.#turn <= N_TURNS) {
+    if (this.#turn + 1 <= N_TURNS) {
+      this.#turn += 1;
       getPlayerProgress().refill();
       getHuntMode().replaceMap();
-      getSleepModal().setShown(false);
     } else {
       // TODO: Play a specific scene
       let ending = getScorer().pickEnding();
-      getEndgameModal().play(ending.scene);
+      getVNModal().play(ending.scene);
+      getEndgameModal().show();
     }
   }
 
diff --git a/src/vnmodal.ts b/src/vnmodal.ts
index ffc4ec9..c217744 100644
--- a/src/vnmodal.ts
+++ b/src/vnmodal.ts
@@ -1,13 +1,13 @@
 import {D, I} from "./engine/public.ts";
-import {AlignX, AlignY, Color, Point} from "./engine/datatypes.ts";
-import {BG_OUTER, FG_BOLD} from "./colors.ts";
+import {AlignX, AlignY, Point} from "./engine/datatypes.ts";
+import {FG_BOLD} from "./colors.ts";
 import {withCamera} from "./layout.ts";
 import {VNScene, VNSceneMessage, VNScenePart} from "./vnscene.ts";
 
 const WIDTH = 384;
 const HEIGHT = 384;
 
-class VNModal {
+export class VNModal {
   #scene: VNScene | null;
   #nextIndex = 0;
   #cathexis: SceneCathexis | null;
@@ -18,6 +18,10 @@ class VNModal {
     this.#cathexis = null;
   }
 
+  get blocksHud(): boolean {
+    return true;
+  }
+
   get isShown(): boolean {
     return this.#scene != null;
   }
@@ -26,37 +30,40 @@ class VNModal {
     this.#scene = scene
     this.#nextIndex = 0;
     this.#cathexis = null;
+
+    this.#fixCathexis();
   }
 
   #fixCathexis() {
-    if (this.#cathexis?.isDone()) {
-      this.#cathexis = null;
-    }
-    if (this.#scene == null) {
-      return;
-    }
-    if (this.#cathexis == null) {
-      let ix = this.#nextIndex
-      if (ix < this.#scene?.length) {
-        this.#cathexis = createCathexis(this.#scene[ix])
-        this.#nextIndex += 1;
-      } else {
-        this.#scene = null;
+    while (true) {
+      if (this.#cathexis?.isDone()) {
+        this.#cathexis = null;
+      }
+      if (this.#cathexis != null) {
+        return;
+      }
+
+      if (this.#scene == null) {
+        return;
+      }
+      if (this.#cathexis == null) {
+        let ix = this.#nextIndex
+        if (ix < this.#scene?.length) {
+          this.#cathexis = createCathexis(this.#scene[ix])
+          this.#nextIndex += 1;
+        } else {
+          this.#scene = null;
+        }
       }
     }
   }
 
   update() {
     this.#fixCathexis()
-    if (!this.isShown) { return }
-
     withCamera("FullscreenPopover", () => this.#update())
   }
 
   draw() {
-    if (!this.isShown) { return }
-
-    D.fillRect(new Point(0, 0), D.size, new Color(BG_OUTER.r, BG_OUTER.g, BG_OUTER.b, 255));
     withCamera("FullscreenPopover", () => this.#draw())
   }
 
@@ -86,10 +93,12 @@ function createCathexis(part: VNScenePart): SceneCathexis {
 class SceneMessageCathexis {
   #message: VNSceneMessage;
   #done: boolean;
+  #gotOneFrame: boolean;
 
   constructor (message: VNSceneMessage) {
     this.#message = message;
     this.#done = false;
+    this.#gotOneFrame = false;
   }
 
   isDone() {
@@ -97,8 +106,11 @@ class SceneMessageCathexis {
   }
 
   update() {
+    let firstFrame = !this.#gotOneFrame;
+    this.#gotOneFrame = true;
+
     // TODO: SFX
-    if (I.isAnythingPressed()) {
+    if (!firstFrame && I.isAnythingPressed()) {
       this.#done = true;
     }
   }
@@ -113,6 +125,6 @@ class SceneMessageCathexis {
 }
 
 let active: VNModal = new VNModal();
-export function getEndgameModal() {
+export function getVNModal() {
   return active;
 }
\ No newline at end of file