@the-inclusionist/engine 6.36.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +107 -0
- package/app/css/style.css +622 -0
- package/app/public/vendor/fonts/andika-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/andika-400.woff2 +0 -0
- package/app/public/vendor/fonts/andika-700-ext.woff2 +0 -0
- package/app/public/vendor/fonts/andika-700.woff2 +0 -0
- package/app/public/vendor/fonts/atkinson-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/atkinson-400.woff2 +0 -0
- package/app/public/vendor/fonts/atkinson-700-ext.woff2 +0 -0
- package/app/public/vendor/fonts/atkinson-700.woff2 +0 -0
- package/app/public/vendor/fonts/atkinson-mono-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/atkinson-mono-400.woff2 +0 -0
- package/app/public/vendor/fonts/comicneue-400.woff2 +0 -0
- package/app/public/vendor/fonts/comicneue-700.woff2 +0 -0
- package/app/public/vendor/fonts/greatvibes-400.woff2 +0 -0
- package/app/public/vendor/fonts/inter-400.woff2 +0 -0
- package/app/public/vendor/fonts/inter-700.woff2 +0 -0
- package/app/public/vendor/fonts/lato-400.woff2 +0 -0
- package/app/public/vendor/fonts/lato-700.woff2 +0 -0
- package/app/public/vendor/fonts/lexend-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/lexend-400.woff2 +0 -0
- package/app/public/vendor/fonts/lexend-700-ext.woff2 +0 -0
- package/app/public/vendor/fonts/lexend-700.woff2 +0 -0
- package/app/public/vendor/fonts/literata-400.woff2 +0 -0
- package/app/public/vendor/fonts/literata-700.woff2 +0 -0
- package/app/public/vendor/fonts/newsreader-400.woff2 +0 -0
- package/app/public/vendor/fonts/newsreader-700.woff2 +0 -0
- package/app/public/vendor/fonts/opensans-400.woff2 +0 -0
- package/app/public/vendor/fonts/opensans-700.woff2 +0 -0
- package/app/public/vendor/fonts/pinyon-400.woff2 +0 -0
- package/app/public/vendor/fonts/quattro-400.woff2 +0 -0
- package/app/public/vendor/fonts/quattro-700.woff2 +0 -0
- package/app/public/vendor/fonts/sourcesans-400.woff2 +0 -0
- package/app/public/vendor/fonts/sourcesans-700.woff2 +0 -0
- package/app/public/vendor/fonts/sourceserif-400.woff2 +0 -0
- package/app/public/vendor/fonts/sourceserif-700.woff2 +0 -0
- package/app/public/vendor/fonts/ufcook-700.woff2 +0 -0
- package/app/public/vendor/fonts/ufmag-400.woff2 +0 -0
- package/app/public/vendor/fonts.css +88 -0
- package/dist-pkg/boot/create-game.d.ts +159 -0
- package/dist-pkg/boot/create-game.js +266 -0
- package/dist-pkg/core/a11y-sr.d.ts +4 -0
- package/dist-pkg/core/a11y-sr.js +20 -0
- package/dist-pkg/core/actions.d.ts +100 -0
- package/dist-pkg/core/actions.js +149 -0
- package/dist-pkg/core/anel.d.ts +17 -0
- package/dist-pkg/core/anel.js +31 -0
- package/dist-pkg/core/collision.d.ts +21 -0
- package/dist-pkg/core/collision.js +62 -0
- package/dist-pkg/core/constants.d.ts +84 -0
- package/dist-pkg/core/constants.js +64 -0
- package/dist-pkg/core/contract.d.ts +227 -0
- package/dist-pkg/core/contract.js +184 -0
- package/dist-pkg/core/dom-query.d.ts +9 -0
- package/dist-pkg/core/dom-query.js +25 -0
- package/dist-pkg/core/entity.d.ts +150 -0
- package/dist-pkg/core/entity.js +38 -0
- package/dist-pkg/core/escape-html.d.ts +16 -0
- package/dist-pkg/core/escape-html.js +32 -0
- package/dist-pkg/core/i18n.d.ts +71 -0
- package/dist-pkg/core/i18n.js +236 -0
- package/dist-pkg/core/layers.d.ts +39 -0
- package/dist-pkg/core/layers.js +71 -0
- package/dist-pkg/core/letter-grid.d.ts +55 -0
- package/dist-pkg/core/letter-grid.js +116 -0
- package/dist-pkg/core/loop.d.ts +17 -0
- package/dist-pkg/core/loop.js +36 -0
- package/dist-pkg/core/password.d.ts +34 -0
- package/dist-pkg/core/password.js +205 -0
- package/dist-pkg/core/rng.d.ts +20 -0
- package/dist-pkg/core/rng.js +61 -0
- package/dist-pkg/core/rotulo-acessivel.d.ts +17 -0
- package/dist-pkg/core/rotulo-acessivel.js +41 -0
- package/dist-pkg/core/run-state.d.ts +115 -0
- package/dist-pkg/core/run-state.js +40 -0
- package/dist-pkg/core/scenes.d.ts +68 -0
- package/dist-pkg/core/scenes.js +64 -0
- package/dist-pkg/core/screens.d.ts +16 -0
- package/dist-pkg/core/screens.js +28 -0
- package/dist-pkg/core/state.d.ts +138 -0
- package/dist-pkg/core/state.js +290 -0
- package/dist-pkg/core/tiles.d.ts +12 -0
- package/dist-pkg/core/tiles.js +61 -0
- package/dist-pkg/core/world.d.ts +4 -0
- package/dist-pkg/core/world.js +58 -0
- package/dist-pkg/educational/activities-registry.d.ts +47 -0
- package/dist-pkg/educational/activities-registry.js +95 -0
- package/dist-pkg/i18n/en.d.ts +3 -0
- package/dist-pkg/i18n/en.js +560 -0
- package/dist-pkg/i18n/es.d.ts +3 -0
- package/dist-pkg/i18n/es.js +558 -0
- package/dist-pkg/i18n/pt.d.ts +3 -0
- package/dist-pkg/i18n/pt.js +618 -0
- package/dist-pkg/input/default-bindings.d.ts +24 -0
- package/dist-pkg/input/default-bindings.js +122 -0
- package/dist-pkg/input/devices.d.ts +15 -0
- package/dist-pkg/input/devices.js +31 -0
- package/dist-pkg/input/edges.d.ts +58 -0
- package/dist-pkg/input/edges.js +49 -0
- package/dist-pkg/input/gamepad.d.ts +203 -0
- package/dist-pkg/input/gamepad.js +531 -0
- package/dist-pkg/input/keyboard-runtime.d.ts +61 -0
- package/dist-pkg/input/keyboard-runtime.js +83 -0
- package/dist-pkg/input/keyboard.d.ts +45 -0
- package/dist-pkg/input/keyboard.js +80 -0
- package/dist-pkg/input/keydown.d.ts +270 -0
- package/dist-pkg/input/keydown.js +381 -0
- package/dist-pkg/input/latch.d.ts +30 -0
- package/dist-pkg/input/latch.js +63 -0
- package/dist-pkg/input/pointer-space.d.ts +40 -0
- package/dist-pkg/input/pointer-space.js +51 -0
- package/dist-pkg/input/state.d.ts +11 -0
- package/dist-pkg/input/state.js +12 -0
- package/dist-pkg/input/touch-bindings.d.ts +210 -0
- package/dist-pkg/input/touch-bindings.js +365 -0
- package/dist-pkg/input/touch.d.ts +173 -0
- package/dist-pkg/input/touch.js +314 -0
- package/dist-pkg/input/transports.d.ts +90 -0
- package/dist-pkg/input/transports.js +96 -0
- package/dist-pkg/input/vocabulary-migration.d.ts +58 -0
- package/dist-pkg/input/vocabulary-migration.js +125 -0
- package/dist-pkg/platform/audio-ambient.d.ts +27 -0
- package/dist-pkg/platform/audio-ambient.js +89 -0
- package/dist-pkg/platform/audio-earcons.d.ts +24 -0
- package/dist-pkg/platform/audio-earcons.js +62 -0
- package/dist-pkg/platform/audio-jingles.d.ts +17 -0
- package/dist-pkg/platform/audio-jingles.js +54 -0
- package/dist-pkg/platform/audio-mixer.d.ts +14 -0
- package/dist-pkg/platform/audio-mixer.js +62 -0
- package/dist-pkg/platform/audio-nav.d.ts +51 -0
- package/dist-pkg/platform/audio-nav.js +99 -0
- package/dist-pkg/platform/audio-sonar.d.ts +71 -0
- package/dist-pkg/platform/audio-sonar.js +173 -0
- package/dist-pkg/platform/audio.d.ts +32 -0
- package/dist-pkg/platform/audio.js +191 -0
- package/dist-pkg/platform/interruptible-speech.d.ts +19 -0
- package/dist-pkg/platform/interruptible-speech.js +79 -0
- package/dist-pkg/platform/speech.d.ts +2 -0
- package/dist-pkg/platform/speech.js +35 -0
- package/dist-pkg/platform/storage.d.ts +87 -0
- package/dist-pkg/platform/storage.js +148 -0
- package/dist-pkg/platform/tts.d.ts +33 -0
- package/dist-pkg/platform/tts.js +142 -0
- package/dist-pkg/render/camera.d.ts +58 -0
- package/dist-pkg/render/camera.js +105 -0
- package/dist-pkg/render/canvas.d.ts +13 -0
- package/dist-pkg/render/canvas.js +26 -0
- package/dist-pkg/render/cenario-data.d.ts +127 -0
- package/dist-pkg/render/cenario-data.js +145 -0
- package/dist-pkg/render/city-tex.d.ts +63 -0
- package/dist-pkg/render/city-tex.js +228 -0
- package/dist-pkg/render/city-tiles.d.ts +11 -0
- package/dist-pkg/render/city-tiles.js +140 -0
- package/dist-pkg/render/crt.d.ts +19 -0
- package/dist-pkg/render/crt.js +92 -0
- package/dist-pkg/render/cvd-matrices.d.ts +35 -0
- package/dist-pkg/render/cvd-matrices.js +91 -0
- package/dist-pkg/render/draw.d.ts +149 -0
- package/dist-pkg/render/draw.js +221 -0
- package/dist-pkg/render/fx.d.ts +63 -0
- package/dist-pkg/render/fx.js +123 -0
- package/dist-pkg/render/hc-role-data.d.ts +14 -0
- package/dist-pkg/render/hc-role-data.js +24 -0
- package/dist-pkg/render/high-contrast.d.ts +109 -0
- package/dist-pkg/render/high-contrast.js +254 -0
- package/dist-pkg/render/lq-filter.d.ts +37 -0
- package/dist-pkg/render/lq-filter.js +94 -0
- package/dist-pkg/render/minimap.d.ts +11 -0
- package/dist-pkg/render/minimap.js +94 -0
- package/dist-pkg/render/parallax.d.ts +85 -0
- package/dist-pkg/render/parallax.js +158 -0
- package/dist-pkg/render/player-anim.d.ts +71 -0
- package/dist-pkg/render/player-anim.js +152 -0
- package/dist-pkg/render/port.d.ts +143 -0
- package/dist-pkg/render/port.js +29 -0
- package/dist-pkg/render/recycling-tex.d.ts +48 -0
- package/dist-pkg/render/recycling-tex.js +164 -0
- package/dist-pkg/render/scene-city.d.ts +77 -0
- package/dist-pkg/render/scene-city.js +181 -0
- package/dist-pkg/render/scene-parallax.d.ts +72 -0
- package/dist-pkg/render/scene-parallax.js +426 -0
- package/dist-pkg/render/scene-sky.d.ts +126 -0
- package/dist-pkg/render/scene-sky.js +295 -0
- package/dist-pkg/render/screen-pipeline.d.ts +134 -0
- package/dist-pkg/render/screen-pipeline.js +177 -0
- package/dist-pkg/render/set-cenario.d.ts +54 -0
- package/dist-pkg/render/set-cenario.js +103 -0
- package/dist-pkg/render/sprite-fx.d.ts +3 -0
- package/dist-pkg/render/sprite-fx.js +40 -0
- package/dist-pkg/render/textures.d.ts +75 -0
- package/dist-pkg/render/textures.js +240 -0
- package/dist-pkg/render/title-scene.d.ts +46 -0
- package/dist-pkg/render/title-scene.js +75 -0
- package/dist-pkg/render/viewports.d.ts +52 -0
- package/dist-pkg/render/viewports.js +185 -0
- package/dist-pkg/render/viz-axes.d.ts +98 -0
- package/dist-pkg/render/viz-axes.js +184 -0
- package/dist-pkg/render/viz-modes.d.ts +61 -0
- package/dist-pkg/render/viz-modes.js +74 -0
- package/dist-pkg/render/viz-setters.d.ts +130 -0
- package/dist-pkg/render/viz-setters.js +244 -0
- package/dist-pkg/render/weather.d.ts +96 -0
- package/dist-pkg/render/weather.js +171 -0
- package/dist-pkg/render/wheelchair-sprites.d.ts +24 -0
- package/dist-pkg/render/wheelchair-sprites.js +63 -0
- package/dist-pkg/render/world-tex.d.ts +18 -0
- package/dist-pkg/render/world-tex.js +87 -0
- package/dist-pkg/ui/activities-menu.d.ts +258 -0
- package/dist-pkg/ui/activities-menu.js +648 -0
- package/dist-pkg/ui/caa-sets.d.ts +39 -0
- package/dist-pkg/ui/caa-sets.js +65 -0
- package/dist-pkg/ui/changed-mark.d.ts +15 -0
- package/dist-pkg/ui/changed-mark.js +96 -0
- package/dist-pkg/ui/debug-panel.d.ts +67 -0
- package/dist-pkg/ui/debug-panel.js +173 -0
- package/dist-pkg/ui/dom.d.ts +24 -0
- package/dist-pkg/ui/dom.js +47 -0
- package/dist-pkg/ui/focus-trap.d.ts +71 -0
- package/dist-pkg/ui/focus-trap.js +99 -0
- package/dist-pkg/ui/fonts.d.ts +41 -0
- package/dist-pkg/ui/fonts.js +59 -0
- package/dist-pkg/ui/hud.d.ts +137 -0
- package/dist-pkg/ui/hud.js +229 -0
- package/dist-pkg/ui/item-announcement.d.ts +19 -0
- package/dist-pkg/ui/item-announcement.js +36 -0
- package/dist-pkg/ui/layout.d.ts +6 -0
- package/dist-pkg/ui/layout.js +54 -0
- package/dist-pkg/ui/loop-crash.d.ts +19 -0
- package/dist-pkg/ui/loop-crash.js +60 -0
- package/dist-pkg/ui/map-hub.d.ts +56 -0
- package/dist-pkg/ui/map-hub.js +138 -0
- package/dist-pkg/ui/menu-nav.d.ts +141 -0
- package/dist-pkg/ui/menu-nav.js +390 -0
- package/dist-pkg/ui/pause-icons.d.ts +327 -0
- package/dist-pkg/ui/pause-icons.js +620 -0
- package/dist-pkg/ui/reach-notice.d.ts +34 -0
- package/dist-pkg/ui/reach-notice.js +71 -0
- package/dist-pkg/ui/settings-audio.d.ts +139 -0
- package/dist-pkg/ui/settings-audio.js +544 -0
- package/dist-pkg/ui/settings-caa.d.ts +45 -0
- package/dist-pkg/ui/settings-caa.js +137 -0
- package/dist-pkg/ui/settings-controls.d.ts +100 -0
- package/dist-pkg/ui/settings-controls.js +152 -0
- package/dist-pkg/ui/settings-empathy.d.ts +62 -0
- package/dist-pkg/ui/settings-empathy.js +137 -0
- package/dist-pkg/ui/settings-motion.d.ts +95 -0
- package/dist-pkg/ui/settings-motion.js +282 -0
- package/dist-pkg/ui/settings-motor.d.ts +77 -0
- package/dist-pkg/ui/settings-motor.js +215 -0
- package/dist-pkg/ui/settings-panel.d.ts +76 -0
- package/dist-pkg/ui/settings-panel.js +187 -0
- package/dist-pkg/ui/settings-typo.d.ts +74 -0
- package/dist-pkg/ui/settings-typo.js +150 -0
- package/dist-pkg/ui/settings-visual.d.ts +111 -0
- package/dist-pkg/ui/settings-visual.js +252 -0
- package/dist-pkg/ui/shell.d.ts +239 -0
- package/dist-pkg/ui/shell.js +430 -0
- package/dist-pkg/ui/title.d.ts +36 -0
- package/dist-pkg/ui/title.js +60 -0
- package/dist-pkg/ui/vlibras.d.ts +11 -0
- package/dist-pkg/ui/vlibras.js +87 -0
- package/dist-pkg/ui/webcam.d.ts +7 -0
- package/dist-pkg/ui/webcam.js +88 -0
- package/docs/CREDITS.md +64 -0
- package/docs/LICENSES.md +132 -0
- package/package.json +115 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
import type { PixelPainter } from './canvas.js';
|
|
3
|
+
export type Material = 'papel' | 'plastico' | 'metal' | 'vidro';
|
|
4
|
+
export type Lixeira = 'azul' | 'vermelha' | 'amarela' | 'verde';
|
|
5
|
+
/** Latinha de alumínio 6×9 — corpo prateado, tampa e base mais escuras, brilho de uma coluna. */
|
|
6
|
+
export declare const paintLatinha: PixelPainter;
|
|
7
|
+
/** Garrafa PET 6×11 — gargalo estreito, tampa, corpo translúcido esverdeado. */
|
|
8
|
+
export declare const paintGarrafaPet: PixelPainter;
|
|
9
|
+
/** Pote de vidro 8×9 — boca larga, tampa metálica, corpo azulado transparente. */
|
|
10
|
+
export declare const paintPoteDeVidro: PixelPainter;
|
|
11
|
+
/** Caixa de papelão 10×9 — papelão liso, aba superior e fita no meio. */
|
|
12
|
+
export declare const paintCaixaDePapelao: PixelPainter;
|
|
13
|
+
/** Catálogo dos objetos: tamanho do canvas + pintor. As chaves são os `Material` de `game/recycling`. */
|
|
14
|
+
export declare const LIXO_ART: Readonly<Record<Material, {
|
|
15
|
+
w: number;
|
|
16
|
+
h: number;
|
|
17
|
+
paint: PixelPainter;
|
|
18
|
+
}>>;
|
|
19
|
+
export declare const LIXEIRA_W = 12, LIXEIRA_H = 15;
|
|
20
|
+
/** A cor de cada lixeira, na CONAMA 275/2001. Corpo e um tom escuro para tampa, aro e sombra. */
|
|
21
|
+
export declare const COR_DA_LIXEIRA: Readonly<Record<Lixeira, {
|
|
22
|
+
corpo: string;
|
|
23
|
+
escuro: string;
|
|
24
|
+
}>>;
|
|
25
|
+
/**
|
|
26
|
+
* Uma lixeira 12×15 — corpo levemente cônico, tampa saliente, alça e o símbolo da reciclagem em três traços.
|
|
27
|
+
*
|
|
28
|
+
* ⚠️ O SÍMBOLO É CLARO SOBRE O CORPO, e não uma quinta cor: em alto contraste e nos filtros de daltonismo, o que
|
|
29
|
+
* distingue as quatro lixeiras é a cor do corpo, e um símbolo colorido competiria com ela. Claro sobre escuro
|
|
30
|
+
* sobrevive a qualquer um dos dezesseis modos de visão.
|
|
31
|
+
*/
|
|
32
|
+
export declare const paintLixeira: (cor: Lixeira) => PixelPainter;
|
|
33
|
+
export declare const PLACA_W = 20, PLACA_H = 28;
|
|
34
|
+
/**
|
|
35
|
+
* A placa 20×28: disco vermelho vazado, a pessoa jogando lixo em preto, a barra da proibição e o poste.
|
|
36
|
+
*
|
|
37
|
+
* Ela é o rosto de uma regra que o jogo NÃO pune (ver `game/recycling`): quem carrega lixo simplesmente não
|
|
38
|
+
* passa daqui. A placa existe para que a criança saiba POR QUE não passou — sem ela, a barreira seria um bug
|
|
39
|
+
* aos olhos de quem joga.
|
|
40
|
+
*/
|
|
41
|
+
export declare const paintPlaca: PixelPainter;
|
|
42
|
+
export interface RecyclingTextures {
|
|
43
|
+
lixo: Record<Material, unknown>;
|
|
44
|
+
lixeira: Record<Lixeira, unknown>;
|
|
45
|
+
placa: unknown;
|
|
46
|
+
}
|
|
47
|
+
/** Assa tudo uma vez. Chamada pela raiz de composição no boot — nunca no import (ver o cabeçalho). */
|
|
48
|
+
export declare function createRecyclingTextures(): RecyclingTextures;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// render/recycling-tex — a ARTE PROCEDURAL do lixo reciclável e das quatro lixeiras.
|
|
3
|
+
//
|
|
4
|
+
// Mesma técnica de `render/city-tex` (retângulos carimbados por `pixelCanvas`), e por isso mesmo um módulo à
|
|
5
|
+
// parte e não um bloco lá dentro: `city-tex` é a arte DA RUA — bichos, pedestres, carros —, e o seu cabeçalho
|
|
6
|
+
// diz com todas as letras que "props é decoração de QUALQUER cenário" e fica fora. Lixo e lixeira aparecem em
|
|
7
|
+
// qualquer tema, então seguem a regra que aquele arquivo escreveu para si.
|
|
8
|
+
//
|
|
9
|
+
// SEM I/O NO IMPORT, pelo mesmo motivo que lá: `makeCanvas` toca `document`, e um módulo de `render/` é
|
|
10
|
+
// importado pelo project `node` do Vitest. Não há constante pronta aqui — há `createRecyclingTextures()`, que a
|
|
11
|
+
// raiz de composição chama uma vez no boot.
|
|
12
|
+
//
|
|
13
|
+
// ========================= POR QUE PROCEDURAL, E NÃO PNG =========================
|
|
14
|
+
// O pilar diz "arte = dados: nenhum PNG embutido no jogo" (ADR-0010/0018). Quatro objetos e quatro lixeiras em
|
|
15
|
+
// PNG seriam oito arquivos a versionar, precachear e recolorir à mão em cada modo de visão. Como retângulos,
|
|
16
|
+
// eles são LIDOS pelo alto contraste e pelos filtros de daltonismo como o resto do mundo, sem exceção e sem
|
|
17
|
+
// arquivo `_hc` paralelo — que é a dívida que o atlas de sprites do personagem ainda carrega.
|
|
18
|
+
//
|
|
19
|
+
// ========================= AS CORES SÃO CONTEÚDO =========================
|
|
20
|
+
// As lixeiras seguem a Resolução CONAMA 275/2001, que é o padrão da rua brasileira: AZUL papel, VERMELHA
|
|
21
|
+
// plástico, AMARELA metal, VERDE vidro. A criança que aprende a cor aqui reconhece a de fora — trocar uma por
|
|
22
|
+
// gosto ensina errado. O gate compara este arquivo com `game/recycling`, que é quem decide o acerto, para que
|
|
23
|
+
// as duas listas não possam divergir em silêncio.
|
|
24
|
+
import { pixelTexture } from './canvas.js';
|
|
25
|
+
/* ===================== os quatro objetos ===================== */
|
|
26
|
+
// Miúdos de propósito: ficam no chão, ao lado de moedas, num mundo de 320×180. Grandes demais viram obstáculo
|
|
27
|
+
// visual; pequenos demais somem para quem tem baixa visão — a faixa útil aqui é 6 a 11 px de largura.
|
|
28
|
+
/** Latinha de alumínio 6×9 — corpo prateado, tampa e base mais escuras, brilho de uma coluna. */
|
|
29
|
+
export const paintLatinha = (px) => {
|
|
30
|
+
px(1, 1, 4, 7, '#b9c2cc'); // corpo
|
|
31
|
+
px(1, 0, 4, 1, '#8b949e'); // tampa
|
|
32
|
+
px(1, 8, 4, 1, '#8b949e'); // base
|
|
33
|
+
px(2, 2, 1, 5, '#e6ecf2'); // brilho
|
|
34
|
+
px(0, 2, 1, 5, '#8b949e'); // sombra do lado
|
|
35
|
+
};
|
|
36
|
+
/** Garrafa PET 6×11 — gargalo estreito, tampa, corpo translúcido esverdeado. */
|
|
37
|
+
export const paintGarrafaPet = (px) => {
|
|
38
|
+
px(2, 0, 2, 1, '#2f6fd0'); // tampa azul
|
|
39
|
+
px(2, 1, 2, 2, '#bfe6d8'); // gargalo
|
|
40
|
+
px(1, 3, 4, 7, '#a8dcc9'); // corpo
|
|
41
|
+
px(2, 4, 1, 5, '#dcf3ea'); // brilho
|
|
42
|
+
px(1, 10, 4, 1, '#7fbfa8'); // base
|
|
43
|
+
};
|
|
44
|
+
/** Pote de vidro 8×9 — boca larga, tampa metálica, corpo azulado transparente. */
|
|
45
|
+
export const paintPoteDeVidro = (px) => {
|
|
46
|
+
px(1, 0, 6, 1, '#8b949e'); // tampa
|
|
47
|
+
px(1, 1, 6, 1, '#6f7883'); // aro
|
|
48
|
+
px(1, 2, 6, 6, '#a9cfe0'); // corpo
|
|
49
|
+
px(2, 3, 1, 4, '#e2f2f8'); // brilho
|
|
50
|
+
px(1, 8, 6, 1, '#7fa8ba'); // base
|
|
51
|
+
};
|
|
52
|
+
/** Caixa de papelão 10×9 — papelão liso, aba superior e fita no meio. */
|
|
53
|
+
export const paintCaixaDePapelao = (px) => {
|
|
54
|
+
px(0, 1, 10, 8, '#c39a63'); // corpo
|
|
55
|
+
px(0, 0, 10, 1, '#a37f4f'); // aba de cima
|
|
56
|
+
px(4, 0, 2, 9, '#d9bb90'); // fita vertical
|
|
57
|
+
px(0, 4, 10, 1, '#a37f4f'); // vinco
|
|
58
|
+
};
|
|
59
|
+
/** Catálogo dos objetos: tamanho do canvas + pintor. As chaves são os `Material` de `game/recycling`. */
|
|
60
|
+
export const LIXO_ART = Object.freeze({
|
|
61
|
+
metal: { w: 6, h: 9, paint: paintLatinha },
|
|
62
|
+
plastico: { w: 6, h: 11, paint: paintGarrafaPet },
|
|
63
|
+
vidro: { w: 8, h: 9, paint: paintPoteDeVidro },
|
|
64
|
+
papel: { w: 10, h: 9, paint: paintCaixaDePapelao },
|
|
65
|
+
});
|
|
66
|
+
/* ===================== as quatro lixeiras ===================== */
|
|
67
|
+
export const LIXEIRA_W = 12, LIXEIRA_H = 15;
|
|
68
|
+
/** A cor de cada lixeira, na CONAMA 275/2001. Corpo e um tom escuro para tampa, aro e sombra. */
|
|
69
|
+
export const COR_DA_LIXEIRA = Object.freeze({
|
|
70
|
+
azul: { corpo: '#2f6fd0', escuro: '#1e4a8c' },
|
|
71
|
+
vermelha: { corpo: '#c8372d', escuro: '#8d251e' },
|
|
72
|
+
amarela: { corpo: '#e0b423', escuro: '#a07d13' },
|
|
73
|
+
verde: { corpo: '#2f9e52', escuro: '#1d6b36' },
|
|
74
|
+
});
|
|
75
|
+
/**
|
|
76
|
+
* Uma lixeira 12×15 — corpo levemente cônico, tampa saliente, alça e o símbolo da reciclagem em três traços.
|
|
77
|
+
*
|
|
78
|
+
* ⚠️ O SÍMBOLO É CLARO SOBRE O CORPO, e não uma quinta cor: em alto contraste e nos filtros de daltonismo, o que
|
|
79
|
+
* distingue as quatro lixeiras é a cor do corpo, e um símbolo colorido competiria com ela. Claro sobre escuro
|
|
80
|
+
* sobrevive a qualquer um dos dezesseis modos de visão.
|
|
81
|
+
*/
|
|
82
|
+
export const paintLixeira = (cor) => (px) => {
|
|
83
|
+
const { corpo, escuro } = COR_DA_LIXEIRA[cor];
|
|
84
|
+
px(1, 3, 10, 11, corpo); // corpo
|
|
85
|
+
px(0, 1, 12, 2, escuro); // tampa
|
|
86
|
+
px(5, 0, 2, 1, escuro); // alça
|
|
87
|
+
px(1, 14, 10, 1, escuro); // base
|
|
88
|
+
px(2, 4, 1, 9, escuro); // vinco esquerdo
|
|
89
|
+
px(9, 4, 1, 9, escuro); // vinco direito
|
|
90
|
+
px(4, 6, 4, 1, '#f2f5f7'); // símbolo: traço de cima
|
|
91
|
+
px(4, 8, 4, 1, '#f2f5f7'); // símbolo: traço do meio
|
|
92
|
+
px(4, 10, 4, 1, '#f2f5f7'); // símbolo: traço de baixo
|
|
93
|
+
};
|
|
94
|
+
/* ===================== a placa de proibido jogar lixo =====================
|
|
95
|
+
*
|
|
96
|
+
* ⚠️ SEGUNDA VERSÃO, e a primeira era pequena demais para dizer o que dizia. Tinha 11×16 e resolvia o disco
|
|
97
|
+
* de proibição com quatro retângulos — na tela virava um quadradinho vermelho com um risco branco, que a
|
|
98
|
+
* criança lê como "algum objeto", não como "aqui não". O Dev mandou a referência da placa de verdade (o
|
|
99
|
+
* pictograma da pessoa jogando lixo dentro do círculo cortado) e pediu: "a placa deveria ser grande, com o
|
|
100
|
+
* símbolo identificável da pessoa jogando coisas e o sinal de proibido."
|
|
101
|
+
*
|
|
102
|
+
* Agora são 20×28: prancha de 20×20 e poste de 8. O círculo vem de TABELA DE LINHAS, como a roda do carro —
|
|
103
|
+
* é o mesmo problema, e pela mesma razão: numa arte de retângulos, o que o olho já sabe que é redondo
|
|
104
|
+
* denuncia o desenho inteiro se sair quadrado.
|
|
105
|
+
*
|
|
106
|
+
* ⚠️ E A LEITURA É EM TRÊS CAMADAS, na ordem em que a criança precisa delas: a prancha clara separa a placa
|
|
107
|
+
* do fundo; o pictograma PRETO sobre claro é o contraste mais alto que existe e sobrevive aos dezesseis
|
|
108
|
+
* modos de visão; a barra vermelha vem por último, por cima de tudo, porque é ela que transforma "uma pessoa
|
|
109
|
+
* jogando lixo" em "não jogue lixo". Trocar essa ordem inverte o sentido do desenho. */
|
|
110
|
+
export const PLACA_W = 20, PLACA_H = 28;
|
|
111
|
+
/** Disco Ø18: `[recuo, largura]` por linha. Mesma técnica da roda do carro. */
|
|
112
|
+
const DISCO = [
|
|
113
|
+
[6, 6], [4, 10], [3, 12], [2, 14], [1, 16], [1, 16], [0, 18], [0, 18], [0, 18],
|
|
114
|
+
[0, 18], [0, 18], [0, 18], [1, 16], [1, 16], [2, 14], [3, 12], [4, 10], [6, 6],
|
|
115
|
+
];
|
|
116
|
+
/** Miolo Ø14, no mesmo formato — abre o vazio claro dentro do aro vermelho. */
|
|
117
|
+
const MIOLO = [
|
|
118
|
+
[5, 4], [3, 8], [2, 10], [1, 12], [1, 12], [0, 14], [0, 14],
|
|
119
|
+
[0, 14], [0, 14], [1, 12], [1, 12], [2, 10], [3, 8], [5, 4],
|
|
120
|
+
];
|
|
121
|
+
const VERMELHO = '#d42a1e', CLARO = '#f2f5f7', PRETO = '#1a1d24', POSTE = '#6f7883';
|
|
122
|
+
/**
|
|
123
|
+
* A placa 20×28: disco vermelho vazado, a pessoa jogando lixo em preto, a barra da proibição e o poste.
|
|
124
|
+
*
|
|
125
|
+
* Ela é o rosto de uma regra que o jogo NÃO pune (ver `game/recycling`): quem carrega lixo simplesmente não
|
|
126
|
+
* passa daqui. A placa existe para que a criança saiba POR QUE não passou — sem ela, a barreira seria um bug
|
|
127
|
+
* aos olhos de quem joga.
|
|
128
|
+
*/
|
|
129
|
+
export const paintPlaca = (px) => {
|
|
130
|
+
px(1, 0, 18, 20, CLARO); // prancha
|
|
131
|
+
px(0, 0, 20, 1, PRETO);
|
|
132
|
+
px(0, 19, 20, 1, PRETO); // moldura: topo e base
|
|
133
|
+
px(0, 1, 1, 18, PRETO);
|
|
134
|
+
px(19, 1, 1, 18, PRETO); // moldura: laterais
|
|
135
|
+
DISCO.forEach(([dx, w], i) => px(1 + dx, 1 + i, w, 1, VERMELHO));
|
|
136
|
+
MIOLO.forEach(([dx, w], i) => px(3 + dx, 3 + i, w, 1, CLARO));
|
|
137
|
+
// O pictograma, dentro do miolo (x 3..16, y 3..16): cabeça, tronco, braço estendido e as pernas.
|
|
138
|
+
px(7, 5, 3, 3, PRETO); // cabeça
|
|
139
|
+
px(7, 8, 3, 5, PRETO); // tronco
|
|
140
|
+
px(10, 9, 3, 1, PRETO); // braço que joga
|
|
141
|
+
px(7, 13, 1, 3, PRETO);
|
|
142
|
+
px(9, 13, 1, 3, PRETO); // pernas
|
|
143
|
+
px(13, 11, 1, 1, PRETO);
|
|
144
|
+
px(14, 13, 1, 1, PRETO);
|
|
145
|
+
px(12, 14, 1, 1, PRETO); // o lixo caindo
|
|
146
|
+
// A barra da proibição POR ÚLTIMO: é ela que faz o desenho dizer "não".
|
|
147
|
+
for (let k = 0; k < 12; k++)
|
|
148
|
+
px(4 + k, 4 + k, 3, 2, VERMELHO);
|
|
149
|
+
px(9, 20, 2, 7, POSTE);
|
|
150
|
+
px(7, 27, 6, 1, POSTE); // poste e pé
|
|
151
|
+
};
|
|
152
|
+
/** Assa tudo uma vez. Chamada pela raiz de composição no boot — nunca no import (ver o cabeçalho). */
|
|
153
|
+
export function createRecyclingTextures() {
|
|
154
|
+
const lixo = {};
|
|
155
|
+
for (const m of Object.keys(LIXO_ART)) {
|
|
156
|
+
const a = LIXO_ART[m];
|
|
157
|
+
lixo[m] = pixelTexture(a.w, a.h, a.paint);
|
|
158
|
+
}
|
|
159
|
+
const lixeira = {};
|
|
160
|
+
for (const c of Object.keys(COR_DA_LIXEIRA)) {
|
|
161
|
+
lixeira[c] = pixelTexture(LIXEIRA_W, LIXEIRA_H, paintLixeira(c));
|
|
162
|
+
}
|
|
163
|
+
return { lixo, lixeira, placa: pixelTexture(PLACA_W, PLACA_H, paintPlaca) };
|
|
164
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
import type { Desenho, Visivel } from './port.js';
|
|
3
|
+
type Gfx = Desenho & Visivel;
|
|
4
|
+
type VisibleLayer = Visivel;
|
|
5
|
+
interface DarkRegion {
|
|
6
|
+
set: Set<string>;
|
|
7
|
+
}
|
|
8
|
+
interface Pl {
|
|
9
|
+
x: number;
|
|
10
|
+
y: number;
|
|
11
|
+
quit?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface SceneCityCtx {
|
|
14
|
+
cityDecoG: Gfx;
|
|
15
|
+
abandonG: Gfx;
|
|
16
|
+
lavaFxG: Gfx;
|
|
17
|
+
waterFxG: Gfx;
|
|
18
|
+
skyLayer: VisibleLayer;
|
|
19
|
+
darkRegions: DarkRegion[];
|
|
20
|
+
solidAt: (x: number, y: number) => boolean;
|
|
21
|
+
tileAt: (x: number, y: number) => number;
|
|
22
|
+
lifeSurfaceAt: (tx: number) => number;
|
|
23
|
+
WORLD_W: number;
|
|
24
|
+
WORLD_H: number;
|
|
25
|
+
TILE: number;
|
|
26
|
+
WORLD_PX_W: number;
|
|
27
|
+
WORLD_PX_H: number;
|
|
28
|
+
LOGICAL_W: number;
|
|
29
|
+
LOGICAL_H: number;
|
|
30
|
+
BOX: {
|
|
31
|
+
h: number;
|
|
32
|
+
};
|
|
33
|
+
DIRECT_CFG: Record<string, unknown>;
|
|
34
|
+
getCenario: () => string;
|
|
35
|
+
getVizMode: () => string;
|
|
36
|
+
getPlayers: () => Pl[];
|
|
37
|
+
getFxClock: () => number;
|
|
38
|
+
getRm: () => {
|
|
39
|
+
decor?: boolean;
|
|
40
|
+
};
|
|
41
|
+
onCenarioChange?: (city: boolean) => void;
|
|
42
|
+
}
|
|
43
|
+
export interface SceneCity {
|
|
44
|
+
buildCityDeco: () => void;
|
|
45
|
+
applyCenarioVida: () => void;
|
|
46
|
+
stepTileFx: () => void;
|
|
47
|
+
}
|
|
48
|
+
/** Coluna com poste de luz na fachada (a cada 11 tiles). */
|
|
49
|
+
export declare function isStreetlampColumn(tx: number): boolean;
|
|
50
|
+
/** Coluna com letreiro na fachada (a cada 9 tiles, exige parede 3 tiles acima — checado pelo chamador). */
|
|
51
|
+
export declare function isSignageColumn(tx: number): boolean;
|
|
52
|
+
export declare const SIGNAGE_COLORS: readonly [3656096, 16747610, 6598911, 16765503];
|
|
53
|
+
/** Cor do letreiro daquela coluna (4 variações, cíclicas por tx). */
|
|
54
|
+
export declare function signageColor(tx: number): number;
|
|
55
|
+
/** Tipo de decoração da célula abandonada (entulho/viga/pichação/vazio) — hash determinístico em tx,ty. */
|
|
56
|
+
export declare function abandonedDecorKind(tx: number, ty: number): number;
|
|
57
|
+
export declare const GRAFFITI_COLORS: readonly [13193174, 5232250, 14076239];
|
|
58
|
+
/** Cor da pichação daquela coluna (3 variações, cíclicas por tx). */
|
|
59
|
+
export declare function graffitiColor(tx: number): number;
|
|
60
|
+
/** Deriva horizontal (0..3) dos tracinhos de lava — avança 1 tile a cada 8 ticks do fxClock. */
|
|
61
|
+
export declare function lavaStreakOffset(fxClock: number, worldX: number): number;
|
|
62
|
+
/** Hash determinístico por coluna, usado p/ escolher o "leito" da água (coral/algas/vazio). */
|
|
63
|
+
export declare function waterBedHash(tx: number): number;
|
|
64
|
+
/** Tipo de leito da coluna: 0=coral, 1=algas, 2=vazio. */
|
|
65
|
+
export declare function waterBedKind(tx: number): number;
|
|
66
|
+
export declare const CORAL_COLORS: readonly [15234107, 15909198, 9187129];
|
|
67
|
+
/** Cor do coral daquela coluna (3 variações, derivadas do mesmo hash do leito). */
|
|
68
|
+
export declare function coralColor(tx: number): number;
|
|
69
|
+
/** Hash determinístico por célula, usado p/ decidir se há peixe nadando ali (água aberta). */
|
|
70
|
+
export declare function fishHash(tx: number, ty: number): number;
|
|
71
|
+
/** ~1/7 das células de água aberta recebe um peixe. */
|
|
72
|
+
export declare function fishSpawnsAt(tx: number, ty: number): boolean;
|
|
73
|
+
export declare const FISH_COLORS: readonly [15026253, 3829413, 4763754];
|
|
74
|
+
/** Cor do peixe daquela célula (3 variações, derivadas do hash de peixe). */
|
|
75
|
+
export declare function fishColor(tx: number, ty: number): number;
|
|
76
|
+
export declare function initSceneCity(ctx: SceneCityCtx): SceneCity;
|
|
77
|
+
export {};
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// render/scene-city — city scenario decoration: sidewalk/streetlamp/signage facade band, water-tank walls,
|
|
3
|
+
// abandoned-interior clutter (darkRegions, drawn under the darkness layer), and the live water/lava tile fx
|
|
4
|
+
// (waves/coral/algae/fish, lava streaks). Extracted from game.js. The layers (cityDecoG/abandonG/lavaFxG/
|
|
5
|
+
// waterFxG/skyLayer) are CREATED in game.js — z-order stays soldered there — and INJECTED here; we move only
|
|
6
|
+
// the LOGIC. Formulas copied verbatim. `applyCenarioVida` is the thin scenario-toggle orchestrator: it flips
|
|
7
|
+
// only this module's own layers and calls an injected hook so the coordinator can wire game/life and
|
|
8
|
+
// game/traffic's own scenario reactions (see the module boundary note in the extraction report).
|
|
9
|
+
// ---- Seleção de tile/decoração por posição (lógica pura, determinística — hash em tx/ty, sem PIXI) ----
|
|
10
|
+
/** Coluna com poste de luz na fachada (a cada 11 tiles). */
|
|
11
|
+
export function isStreetlampColumn(tx) { return tx % 11 === 4; }
|
|
12
|
+
/** Coluna com letreiro na fachada (a cada 9 tiles, exige parede 3 tiles acima — checado pelo chamador). */
|
|
13
|
+
export function isSignageColumn(tx) { return tx % 9 === 2; }
|
|
14
|
+
export const SIGNAGE_COLORS = [0x37c9a0, 0xff8c5a, 0x64b0ff, 0xffd23f];
|
|
15
|
+
/** Cor do letreiro daquela coluna (4 variações, cíclicas por tx). */
|
|
16
|
+
export function signageColor(tx) { return SIGNAGE_COLORS[tx % 4]; }
|
|
17
|
+
/** Tipo de decoração da célula abandonada (entulho/viga/pichação/vazio) — hash determinístico em tx,ty. */
|
|
18
|
+
export function abandonedDecorKind(tx, ty) { return (tx * 13 + ty * 7) % 10; }
|
|
19
|
+
export const GRAFFITI_COLORS = [0xc94fd6, 0x4fd67a, 0xd6c94f];
|
|
20
|
+
/** Cor da pichação daquela coluna (3 variações, cíclicas por tx). */
|
|
21
|
+
export function graffitiColor(tx) { return GRAFFITI_COLORS[tx % 3]; }
|
|
22
|
+
/** Deriva horizontal (0..3) dos tracinhos de lava — avança 1 tile a cada 8 ticks do fxClock. */
|
|
23
|
+
export function lavaStreakOffset(fxClock, worldX) { return (Math.floor(fxClock / 8) + worldX) % 4; }
|
|
24
|
+
/** Hash determinístico por coluna, usado p/ escolher o "leito" da água (coral/algas/vazio). */
|
|
25
|
+
export function waterBedHash(tx) { return (tx * 2654435761) >>> 0; }
|
|
26
|
+
/** Tipo de leito da coluna: 0=coral, 1=algas, 2=vazio. */
|
|
27
|
+
export function waterBedKind(tx) { return waterBedHash(tx) % 3; }
|
|
28
|
+
export const CORAL_COLORS = [0xe8743b, 0xf2c14e, 0x8c2f39];
|
|
29
|
+
/** Cor do coral daquela coluna (3 variações, derivadas do mesmo hash do leito). */
|
|
30
|
+
export function coralColor(tx) { return CORAL_COLORS[(waterBedHash(tx) >>> 3) % 3]; }
|
|
31
|
+
/** Hash determinístico por célula, usado p/ decidir se há peixe nadando ali (água aberta). */
|
|
32
|
+
export function fishHash(tx, ty) { return (tx * 40503 + ty * 12289) >>> 0; }
|
|
33
|
+
/** ~1/7 das células de água aberta recebe um peixe. */
|
|
34
|
+
export function fishSpawnsAt(tx, ty) { return fishHash(tx, ty) % 7 === 0; }
|
|
35
|
+
export const FISH_COLORS = [0xe5484d, 0x3a6ea5, 0x48b06a];
|
|
36
|
+
/** Cor do peixe daquela célula (3 variações, derivadas do hash de peixe). */
|
|
37
|
+
export function fishColor(tx, ty) { return FISH_COLORS[fishHash(tx, ty) % 3]; }
|
|
38
|
+
export function initSceneCity(ctx) {
|
|
39
|
+
// buildCityDeco v3: desenhado UMA vez (mapa é estático) — calçada+postes+letreiros na fachada mais baixa,
|
|
40
|
+
// paredes/linha d'água da caixa d'água (bounding box dos tiles de água, tipo 3), e entulho/viga/pichação
|
|
41
|
+
// sob a escuridão das áreas secretas (abandonG, camada abaixo de darkLayer no game.js).
|
|
42
|
+
function buildCityDeco() {
|
|
43
|
+
const g = ctx.cityDecoG;
|
|
44
|
+
g.clear();
|
|
45
|
+
const a = ctx.abandonG;
|
|
46
|
+
a.clear();
|
|
47
|
+
const TILE = ctx.TILE;
|
|
48
|
+
// ---- FACHADA (banda mais baixa, por onde o personagem anda): calçada + postes + letreiros.
|
|
49
|
+
// Placas de PARE ficam na rua da frente (game/traffic), junto dos carros.
|
|
50
|
+
const BASE_TY = ctx.WORLD_H - 9;
|
|
51
|
+
for (let tx = 1; tx < ctx.WORLD_W - 1; tx++) {
|
|
52
|
+
const ty = ctx.lifeSurfaceAt(tx);
|
|
53
|
+
if (ty < BASE_TY)
|
|
54
|
+
continue;
|
|
55
|
+
const X = tx * TILE, y = ty * TILE;
|
|
56
|
+
g.beginFill(0x9aa0ad, 0.9).drawRect(X, y, TILE, 2).endFill(); // calçada clara
|
|
57
|
+
g.beginFill(0x565e70, 1).drawRect(X, y + 2, TILE, 1).endFill(); // meio-fio
|
|
58
|
+
if (isStreetlampColumn(tx)) {
|
|
59
|
+
g.beginFill(0x3a4152).drawRect(X + 7, y - 30, 2, 30).endFill();
|
|
60
|
+
g.beginFill(0x3a4152).drawRect(X + 7, y - 30, 8, 2).endFill(); // poste + braço
|
|
61
|
+
g.beginFill(0xffe9a8, 1).drawRect(X + 13, y - 29, 3, 3).endFill();
|
|
62
|
+
g.beginFill(0xffe9a8, 0.18).drawRect(X + 9, y - 31, 11, 8).endFill(); // lâmpada + halo FIXO (sem piscar)
|
|
63
|
+
}
|
|
64
|
+
if (isSignageColumn(tx) && ctx.solidAt(tx, ty - 3)) {
|
|
65
|
+
const c = signageColor(tx); // letreiro na fachada
|
|
66
|
+
g.beginFill(0x141824).drawRect(X + 2, y - 3.5 * TILE, 12, 6).endFill();
|
|
67
|
+
g.beginFill(c, 1).drawRect(X + 3, y - 3.5 * TILE + 1, 10, 4).endFill();
|
|
68
|
+
g.beginFill(c, 0.15).drawRect(X, y - 3.5 * TILE - 2, 16, 10).endFill(); // brilho estável
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// ---- CAIXA D'ÁGUA: paredes metálicas nas bordas do corpo d'água (tile 3) + linha d'água no topo
|
|
72
|
+
let wx0 = 1e9, wx1 = -1, wy0 = 1e9, wy1 = -1;
|
|
73
|
+
for (let ty = 0; ty < ctx.WORLD_H; ty++)
|
|
74
|
+
for (let tx = 0; tx < ctx.WORLD_W; tx++) {
|
|
75
|
+
if (ctx.tileAt(tx, ty) === 3) {
|
|
76
|
+
wx0 = Math.min(wx0, tx);
|
|
77
|
+
wx1 = Math.max(wx1, tx);
|
|
78
|
+
wy0 = Math.min(wy0, ty);
|
|
79
|
+
wy1 = Math.max(wy1, ty);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (wx1 >= 0) {
|
|
83
|
+
const X0 = wx0 * TILE, X1 = (wx1 + 1) * TILE, Y0 = wy0 * TILE, Y1 = (wy1 + 1) * TILE;
|
|
84
|
+
g.beginFill(0x6a7486, 0.85).drawRect(X0 - 3, Y0 - 6, 3, Y1 - Y0 + 6).drawRect(X1, Y0 - 6, 3, Y1 - Y0 + 6).endFill(); // paredes do tanque
|
|
85
|
+
for (let ry = Y0; ry < Y1; ry += 12) {
|
|
86
|
+
g.beginFill(0x49515f).drawRect(X0 - 3, ry, 3, 2).drawRect(X1, ry, 3, 2).endFill();
|
|
87
|
+
} // rebites
|
|
88
|
+
g.beginFill(0xbfe6ff, 0.5).drawRect(X0, Y0, X1 - X0, 1.5).endFill(); // linha d'água
|
|
89
|
+
}
|
|
90
|
+
// ---- ABANDONADO (darkRegions): entulho, viga e pichação — desenhado sob a escuridão
|
|
91
|
+
for (const reg of ctx.darkRegions) {
|
|
92
|
+
for (const key of reg.set) {
|
|
93
|
+
const [tx, ty] = key.split(',').map(Number);
|
|
94
|
+
const X = tx * TILE, Y = ty * TILE, h = abandonedDecorKind(tx, ty);
|
|
95
|
+
if (ctx.solidAt(tx, ty + 1) && h < 3) {
|
|
96
|
+
a.beginFill(0x555b66).drawRect(X + 2, Y + TILE - 5, 7, 5).endFill();
|
|
97
|
+
a.beginFill(0x434955).drawRect(X + 7, Y + TILE - 3, 6, 3).endFill();
|
|
98
|
+
} // entulho
|
|
99
|
+
else if (h === 4) {
|
|
100
|
+
a.beginFill(0x6b4e2e, 0.9).drawRect(X, Y + 3, TILE, 3).endFill();
|
|
101
|
+
} // viga exposta
|
|
102
|
+
else if (h === 7) {
|
|
103
|
+
const c = graffitiColor(tx);
|
|
104
|
+
a.beginFill(c, 0.55).drawRect(X + 3, Y + 6, 9, 2).drawRect(X + 5, Y + 9, 6, 2).endFill();
|
|
105
|
+
} // pichação
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// applyCenarioVida: orquestrador FINO do troca-de-cenário. Só liga/desliga as camadas que este módulo possui
|
|
110
|
+
// (deco da cidade + o céu procedural da cidade); trânsito (carLayer + cars) e vida (criaturas) são de outros
|
|
111
|
+
// dois módulos e reagem via onCenarioChange — nunca tocados diretamente daqui.
|
|
112
|
+
function applyCenarioVida() {
|
|
113
|
+
const city = ctx.getCenario() === 'cidade';
|
|
114
|
+
ctx.cityDecoG.visible = city;
|
|
115
|
+
ctx.skyLayer.visible = city; // deco/céu da cidade SÓ na Cidade
|
|
116
|
+
ctx.onCenarioChange?.(city);
|
|
117
|
+
}
|
|
118
|
+
// stepTileFx v3: água (ondas de superfície + leito coral/algas + peixes esparsos) e lava (tracinhos claros à
|
|
119
|
+
// deriva) — só perto de cada jogador (câmera), com dedupe por célula entre jogadores em tela dividida.
|
|
120
|
+
function stepTileFx() {
|
|
121
|
+
ctx.lavaFxG.clear();
|
|
122
|
+
ctx.waterFxG.clear();
|
|
123
|
+
if (ctx.DIRECT_CFG[ctx.getVizMode()] || ctx.getRm().decor)
|
|
124
|
+
return; // HC repinta o mundo; viewDecor off na v3 = só a base estática
|
|
125
|
+
const TILE = ctx.TILE, t = ctx.getFxClock(), seen = new Set();
|
|
126
|
+
for (const pl of ctx.getPlayers()) {
|
|
127
|
+
if (pl.quit)
|
|
128
|
+
continue;
|
|
129
|
+
const camX = Math.max(0, Math.min(pl.x - ctx.LOGICAL_W / 2, ctx.WORLD_PX_W - ctx.LOGICAL_W));
|
|
130
|
+
const camY = Math.max(0, Math.min((pl.y - ctx.BOX.h / 2) - ctx.LOGICAL_H / 2, ctx.WORLD_PX_H - ctx.LOGICAL_H));
|
|
131
|
+
const tx0 = Math.max(0, Math.floor(camX / TILE) - 1), tx1 = Math.min(ctx.WORLD_W - 1, Math.floor((camX + ctx.LOGICAL_W) / TILE) + 1);
|
|
132
|
+
const ty0 = Math.max(0, Math.floor(camY / TILE) - 1), ty1 = Math.min(ctx.WORLD_H - 1, Math.floor((camY + ctx.LOGICAL_H) / TILE) + 1);
|
|
133
|
+
for (let ty = ty0; ty <= ty1; ty++)
|
|
134
|
+
for (let tx = tx0; tx <= tx1; tx++) {
|
|
135
|
+
const tt = ctx.tileAt(tx, ty);
|
|
136
|
+
if (tt !== 3 && tt !== 9)
|
|
137
|
+
continue; // só água(3)/lava(9)
|
|
138
|
+
const k = tx + ',' + ty;
|
|
139
|
+
if (seen.has(k))
|
|
140
|
+
continue;
|
|
141
|
+
seen.add(k);
|
|
142
|
+
const X = tx * TILE, Y = ty * TILE;
|
|
143
|
+
if (tt === 9) {
|
|
144
|
+
const off = lavaStreakOffset(t, X); // lava v3: tracinhos claros que derivam
|
|
145
|
+
ctx.lavaFxG.beginFill(0xff7755).drawRect(X + off, Y + 3, 3, 1).drawRect(X + ((off + 6) % TILE), Y + 8, 3, 1).endFill();
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
// ÁGUA v3: ondulação verde sutil que deriva
|
|
149
|
+
ctx.waterFxG.beginFill(0x46a078, 0.12).drawRect(X, Y + 7 + Math.round(2 * Math.sin(tx * 1.3 + t * 0.04)), TILE, 2).endFill();
|
|
150
|
+
if (ctx.tileAt(tx, ty - 1) !== 3) {
|
|
151
|
+
const off = Math.sin(t * 0.05 + X * 0.1) > 0 ? 1 : 0; // linha de superfície SÓ na borda de cima
|
|
152
|
+
ctx.waterFxG.beginFill(0xffffff, 0.35).drawRect(X + off, Y + 1, TILE - off, 1).endFill();
|
|
153
|
+
}
|
|
154
|
+
if (ctx.solidAt(tx, ty + 1)) {
|
|
155
|
+
const kind = waterBedKind(tx); // leito: coral / algas (determinísticos por coluna)
|
|
156
|
+
if (kind === 0) {
|
|
157
|
+
ctx.waterFxG.beginFill(coralColor(tx))
|
|
158
|
+
.drawRect(X + 6, Y + 9, 2, 7).drawRect(X + 4, Y + 10, 2, 4).drawRect(X + 9, Y + 8, 2, 5).drawRect(X + 3, Y + 12, 1, 2).drawRect(X + 11, Y + 11, 1, 2).endFill();
|
|
159
|
+
}
|
|
160
|
+
else if (kind === 1) {
|
|
161
|
+
ctx.waterFxG.beginFill(0x3fae6a);
|
|
162
|
+
const sway = 2 * Math.sin(t * 0.06 + tx); // algas balançando
|
|
163
|
+
for (let a2 = 0; a2 < 9; a2++) {
|
|
164
|
+
ctx.waterFxG.drawRect(X + 7 + Math.round(sway * (a2 / 9)), Y + 15 - a2, 1, 1);
|
|
165
|
+
if (a2 % 2 === 0)
|
|
166
|
+
ctx.waterFxG.drawRect(X + 9 + Math.round(sway * (a2 / 9)), Y + 15 - a2, 1, 1);
|
|
167
|
+
}
|
|
168
|
+
ctx.waterFxG.endFill();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
else if (fishSpawnsAt(tx, ty)) { // água aberta: peixinho esparso nadando (com olho!)
|
|
172
|
+
const fx2 = X + 6 + Math.round(5 * Math.sin(t * 0.04 + tx + ty)), fy2 = Y + 7 + Math.round(2 * Math.sin(t * 0.07 + ty));
|
|
173
|
+
const dir = Math.cos(t * 0.04 + tx + ty) >= 0 ? 1 : -1;
|
|
174
|
+
ctx.waterFxG.beginFill(fishColor(tx, ty)).drawRect(fx2, fy2, 3, 2).drawRect(fx2 - dir, fy2, 1, 2).endFill();
|
|
175
|
+
ctx.waterFxG.beginFill(0xffffff, 1).drawRect(fx2 + (dir > 0 ? 2 : 0), fy2, 1, 1).endFill();
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return { buildCityDeco, applyCenarioVida, stepTileFx };
|
|
181
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
import type { CenarioTema, TemaMorros, TemaPredios, FaixaDePredios } from './cenario-data.js';
|
|
3
|
+
/** Um sol baixo com leque de raios, assado na textura do céu. Ver `pintarSol`. */
|
|
4
|
+
export interface Sol {
|
|
5
|
+
cor: string;
|
|
6
|
+
x: number;
|
|
7
|
+
y: number;
|
|
8
|
+
}
|
|
9
|
+
/** Hill silhouette height at column `x` (v3 drawHillBand: double sine). `near` = the front (taller) band. */
|
|
10
|
+
export declare function hillHeight(x: number, near: boolean): number;
|
|
11
|
+
/** City placeholder backdrop (the 4 v3 themes have their own sky/hills below). */
|
|
12
|
+
export declare function parallaxPlaceholder(i: number): unknown;
|
|
13
|
+
/** Largura da textura do céu. 64 basta para um gradiente (ele é constante em x); um SOL precisa da tela toda. */
|
|
14
|
+
export declare function larguraDoCeu(T: CenarioTema): number;
|
|
15
|
+
/**
|
|
16
|
+
* Onde cada cor do céu cai, em PIXELS de altura. Separado do desenho porque é a parte que se pode AFERIR: o
|
|
17
|
+
* desenho precisa de um canvas, esta conta não, e é ela que decide se o vermelho do pôr do sol vai parar na
|
|
18
|
+
* linha do horizonte ou atrás dos morros.
|
|
19
|
+
*/
|
|
20
|
+
export declare function paradasDoCeu(cores: readonly string[], h?: number): {
|
|
21
|
+
y: number;
|
|
22
|
+
cor: string;
|
|
23
|
+
}[];
|
|
24
|
+
/**
|
|
25
|
+
* Sol baixo e leque de raios, DENTRO da textura do céu (e não numa camada própria).
|
|
26
|
+
*
|
|
27
|
+
* Aqui e não em `render/scene-sky` de propósito: o sol pertence ao FUNDO mais distante, e é na textura do céu
|
|
28
|
+
* que ele herda de graça as duas coisas que o fazem parecer distante — a rolagem de fator 0,10 (ele quase não
|
|
29
|
+
* anda) e o recolor de alto contraste (viz-setters repinta a textura crua; um sol desenhado por fora ficaria
|
|
30
|
+
* de fora do recolor e brilharia em amarelo no modo de contraste, que é exatamente o que a opção existe para
|
|
31
|
+
* eliminar).
|
|
32
|
+
*
|
|
33
|
+
* O leque aponta para CIMA, com abertura de ±35°, e cada raio desbota até zero por um gradiente radial. As
|
|
34
|
+
* duas coisas juntas mantêm o desenho longe das bordas da textura: um raio cortado na borda reapareceria do
|
|
35
|
+
* outro lado a cada repetição do azulejo, e essa emenda é o defeito mais visível que um céu pode ter.
|
|
36
|
+
*/
|
|
37
|
+
export declare function pintarSol(c: CanvasRenderingContext2D, w: number, h: number, sol: Sol): void;
|
|
38
|
+
/** Theme sky: vertical gradient over `T.sky` (evenly spaced stops), plus the theme's sun when it has one. */
|
|
39
|
+
export declare function themeSkyTexture(T: CenarioTema): unknown;
|
|
40
|
+
/** Ruído reprodutível em [0,1) a partir de um inteiro. Substitui `Math.random` onde a arte precisa variar. */
|
|
41
|
+
export declare function hash01(n: number): number;
|
|
42
|
+
/** Desenha UM elemento de silhueta. `topo` é a linha do morro naquele x; tudo cresce para cima a partir dela. */
|
|
43
|
+
type Elemento = (c: CanvasRenderingContext2D, x: number, topo: number, alt: number) => void;
|
|
44
|
+
interface Silhueta {
|
|
45
|
+
el: Elemento;
|
|
46
|
+
passo: number;
|
|
47
|
+
alt: [number, number];
|
|
48
|
+
}
|
|
49
|
+
export declare const SILHUETAS: Readonly<Record<string, {
|
|
50
|
+
far?: Silhueta;
|
|
51
|
+
near?: Silhueta;
|
|
52
|
+
}>>;
|
|
53
|
+
/**
|
|
54
|
+
* Uma camada inteira: a banda do FUNDO (tom claro, mais alta, mais simples) e a da FRENTE por cima.
|
|
55
|
+
*
|
|
56
|
+
* As duas profundidades são o que o original tem e a primeira versão não tinha — sem elas a camada é uma
|
|
57
|
+
* fileira só, e a cidade perde o ar de cidade.
|
|
58
|
+
*
|
|
59
|
+
* Exportada para o teste: o contexto entra por parâmetro, como em `pintarSol`, e um contexto falso que grava
|
|
60
|
+
* os `fillRect` deixa afirmar as propriedades da faixa sem navegador nenhum.
|
|
61
|
+
*/
|
|
62
|
+
export declare function desenharPredios(c: CanvasRenderingContext2D, w: number, h: number, faixa: FaixaDePredios, semente: number): void;
|
|
63
|
+
/**
|
|
64
|
+
* Camada 0 da Cidade: o céu inteiro E os prédios distantes assados nele.
|
|
65
|
+
*
|
|
66
|
+
* É a única camada OPACA das três, e é assim no original — o `c4.png` não tinha transparência nenhuma.
|
|
67
|
+
*/
|
|
68
|
+
export declare function themeCitySkyTexture(T: TemaPredios): unknown;
|
|
69
|
+
/** Camadas 1 e 2 da Cidade: prédios sobre TRANSPARÊNCIA, para o céu da camada 0 aparecer atrás. */
|
|
70
|
+
export declare function themeSkylineTexture(faixa: FaixaDePredios, semente: number): unknown;
|
|
71
|
+
export declare function themeHillsTexture(T: TemaMorros, near: boolean, tema?: string): unknown;
|
|
72
|
+
export {};
|