Files
game-forest/src/app/GameOverlays.ts
T

72 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { autorun } from 'mobx';
import type { GameStore } from '../game/GameStore';
import type { Mounted } from './Topbar';
/** Russian plural agreement for "день" (day) after a count. */
function dayWord(n: number): string {
const mod10 = n % 10;
const mod100 = n % 100;
if (mod10 === 1 && mod100 !== 11)
return 'день';
if (mod10 >= 2 && mod10 <= 4 && (mod100 < 12 || mod100 > 14))
return 'дня';
return 'дней';
}
/** Builds the "КРОВАВАЯ ЛУНА!" banner and the death screen, both absolutely positioned over the
* game map (siblings of the Pixi canvas — see App.ts) — the DOM-side replacement for the
* corresponding pieces of GameMap.tsx. Both stay hidden/empty until the store says otherwise, kept
* in sync via a single mobx autorun. */
export function createGameOverlays(store: GameStore, onDeath: () => void): Mounted {
const root = document.createElement('div');
root.className = 'game-overlays';
const banner = document.createElement('div');
banner.className = 'blood-moon-banner';
banner.textContent = 'КРОВАВАЯ ЛУНА!';
banner.hidden = true;
const gameOver = document.createElement('div');
gameOver.className = 'game-over-overlay';
gameOver.hidden = true;
const message = document.createElement('div');
message.className = 'game-over-overlay__message';
const stats = document.createElement('div');
stats.className = 'game-over-overlay__stats';
const distance = document.createElement('div');
const chopped = document.createElement('div');
const caught = document.createElement('div');
const coins = document.createElement('div');
stats.append(distance, chopped, caught, coins);
const menuBtn = document.createElement('button');
menuBtn.type = 'button';
menuBtn.className = 'menu-btn';
// The whole map underneath (including this overlay) has a pointerdown handler that captures the
// pointer and drives character movement — without stopping it here, that handler fires first on
// bubble-up and swallows the tap before it becomes a click (see GameCanvas).
menuBtn.addEventListener('pointerdown', (e) => e.stopPropagation());
menuBtn.addEventListener('click', onDeath);
menuBtn.textContent = 'В меню';
gameOver.append(message, stats, menuBtn);
root.append(banner, gameOver);
const dispose = autorun(() => {
banner.hidden = !store.bloodMoonBannerVisible;
gameOver.hidden = !store.isDead;
if (!store.isDead)
return;
message.textContent = `Вы прожили ${store.day} ${dayWord(store.day)}, но вас поймали кролики`;
distance.textContent = `Пройдено: ${Math.round(store.character.distanceTraveled)} px`;
chopped.textContent = `Срублено: ${store.treesChoppedCount} деревьев, ${store.bushesChoppedCount} кустов`;
caught.textContent = `Поймано кроликов: ${store.rabbitsCaughtCount}`;
coins.textContent = `Заработано монет: ${store.totalCoinsEarned.toFixed(1)}`;
});
return { el: root, dispose };
}