@the-inclusionist/engine 9.0.0 → 11.0.0
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/README.md +120 -78
- package/app/css/style.css +761 -377
- package/app/public/vendor/fonts/playwrite-cu.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-es-deco.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-es.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-gb-j.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-gb-s.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-pe.woff2 +0 -0
- package/app/public/vendor/fonts/playwrite-pt.woff2 +0 -0
- package/app/public/vendor/fonts-licences/NOTICE.txt +166 -0
- package/app/public/vendor/fonts-licences/OFL-1.1.txt +86 -0
- package/app/public/vendor/fonts.css +36 -84
- package/dist-pkg/boot/create-game.d.ts +499 -219
- package/dist-pkg/boot/create-game.js +3944 -562
- package/dist-pkg/core/a11y-sr.d.ts +25 -3
- package/dist-pkg/core/a11y-sr.js +38 -19
- package/dist-pkg/core/accessible-label.d.ts +17 -0
- package/dist-pkg/core/accessible-label.js +37 -0
- package/dist-pkg/core/accommodation-subjects.d.ts +26 -0
- package/dist-pkg/core/accommodation-subjects.js +32 -0
- package/dist-pkg/core/accommodations.d.ts +125 -0
- package/dist-pkg/core/accommodations.js +195 -0
- package/dist-pkg/core/actions.d.ts +108 -55
- package/dist-pkg/core/actions.js +122 -71
- package/dist-pkg/core/calm-mode.d.ts +31 -0
- package/dist-pkg/core/calm-mode.js +47 -0
- package/dist-pkg/core/camera-cycle.d.ts +15 -0
- package/dist-pkg/core/camera-cycle.js +7 -0
- package/dist-pkg/core/caption-duration.d.ts +15 -0
- package/dist-pkg/core/caption-duration.js +19 -0
- package/dist-pkg/core/cartridge-problems.d.ts +34 -0
- package/dist-pkg/core/cartridge-problems.js +53 -0
- package/dist-pkg/core/constants.d.ts +0 -54
- package/dist-pkg/core/constants.js +9 -76
- package/dist-pkg/core/contract.d.ts +142 -164
- package/dist-pkg/core/contract.js +222 -208
- package/dist-pkg/core/dom-query.d.ts +4 -4
- package/dist-pkg/core/dom-query.js +12 -20
- package/dist-pkg/core/entity.d.ts +62 -77
- package/dist-pkg/core/entity.js +18 -32
- package/dist-pkg/core/escape-html.d.ts +9 -10
- package/dist-pkg/core/escape-html.js +16 -20
- package/dist-pkg/core/flash-threshold.d.ts +17 -0
- package/dist-pkg/core/flash-threshold.js +113 -0
- package/dist-pkg/core/game-speed.d.ts +11 -0
- package/dist-pkg/core/game-speed.js +16 -0
- package/dist-pkg/core/genres.d.ts +20 -0
- package/dist-pkg/core/genres.js +44 -0
- package/dist-pkg/core/i18n.d.ts +71 -60
- package/dist-pkg/core/i18n.js +186 -200
- package/dist-pkg/core/loop.d.ts +17 -6
- package/dist-pkg/core/loop.js +26 -26
- package/dist-pkg/core/pause-icon-catalogue.d.ts +15 -0
- package/dist-pkg/core/pause-icon-catalogue.js +54 -0
- package/dist-pkg/core/ring.d.ts +17 -0
- package/dist-pkg/core/ring.js +29 -0
- package/dist-pkg/core/rng.d.ts +7 -12
- package/dist-pkg/core/rng.js +23 -53
- package/dist-pkg/core/route.d.ts +26 -26
- package/dist-pkg/core/route.js +126 -121
- package/dist-pkg/core/scenes.d.ts +37 -40
- package/dist-pkg/core/scenes.js +41 -43
- package/dist-pkg/core/screens.d.ts +4 -4
- package/dist-pkg/core/screens.js +11 -16
- package/dist-pkg/core/session-clock.d.ts +23 -0
- package/dist-pkg/core/session-clock.js +37 -0
- package/dist-pkg/core/setting-defaults.d.ts +61 -0
- package/dist-pkg/core/setting-defaults.js +66 -0
- package/dist-pkg/core/speech-rate.d.ts +29 -0
- package/dist-pkg/core/speech-rate.js +47 -0
- package/dist-pkg/core/state.d.ts +118 -118
- package/dist-pkg/core/state.js +322 -297
- package/dist-pkg/core/visual-cycles.d.ts +30 -0
- package/dist-pkg/core/visual-cycles.js +52 -0
- package/dist-pkg/core/visual-state.d.ts +13 -0
- package/dist-pkg/core/visual-state.js +6 -0
- package/dist-pkg/educational/activities-registry.d.ts +1 -1
- package/dist-pkg/educational/activities-registry.js +9 -8
- package/dist-pkg/educational/adaptive-engine.d.ts +11 -11
- package/dist-pkg/educational/adaptive-engine.js +17 -17
- package/dist-pkg/educational/segment-bar.d.ts +12 -12
- package/dist-pkg/educational/segment-bar.js +9 -9
- package/dist-pkg/i18n/en.js +324 -223
- package/dist-pkg/i18n/es.js +323 -223
- package/dist-pkg/i18n/pt.js +348 -226
- package/dist-pkg/input/default-bindings.d.ts +37 -38
- package/dist-pkg/input/default-bindings.js +127 -144
- package/dist-pkg/input/devices.d.ts +7 -7
- package/dist-pkg/input/devices.js +17 -16
- package/dist-pkg/input/edges.d.ts +23 -32
- package/dist-pkg/input/edges.js +23 -28
- package/dist-pkg/input/empathy-filter.d.ts +22 -0
- package/dist-pkg/input/empathy-filter.js +34 -0
- package/dist-pkg/input/face-map.d.ts +96 -0
- package/dist-pkg/input/face-map.js +255 -0
- package/dist-pkg/input/face-signals.d.ts +40 -0
- package/dist-pkg/input/face-signals.js +48 -0
- package/dist-pkg/input/gamepad.d.ts +195 -145
- package/dist-pkg/input/gamepad.js +383 -556
- package/dist-pkg/input/gaze-cycle.d.ts +64 -0
- package/dist-pkg/input/gaze-cycle.js +133 -0
- package/dist-pkg/input/gaze-relative.d.ts +68 -0
- package/dist-pkg/input/gaze-relative.js +142 -0
- package/dist-pkg/input/hand-map.d.ts +28 -0
- package/dist-pkg/input/hand-map.js +142 -0
- package/dist-pkg/input/input-cooldown.d.ts +17 -0
- package/dist-pkg/input/input-cooldown.js +39 -0
- package/dist-pkg/input/key-default.d.ts +30 -0
- package/dist-pkg/input/key-default.js +60 -0
- package/dist-pkg/input/keyboard-runtime.d.ts +15 -21
- package/dist-pkg/input/keyboard-runtime.js +23 -27
- package/dist-pkg/input/keyboard.d.ts +68 -63
- package/dist-pkg/input/keyboard.js +83 -105
- package/dist-pkg/input/keydown.d.ts +123 -137
- package/dist-pkg/input/keydown.js +284 -289
- package/dist-pkg/input/latch-edge.d.ts +33 -21
- package/dist-pkg/input/latch-edge.js +34 -35
- package/dist-pkg/input/latch-scope.d.ts +51 -50
- package/dist-pkg/input/latch-scope.js +61 -82
- package/dist-pkg/input/latch-store.d.ts +26 -30
- package/dist-pkg/input/latch-store.js +42 -50
- package/dist-pkg/input/latch-sync.d.ts +29 -29
- package/dist-pkg/input/latch-sync.js +25 -25
- package/dist-pkg/input/latch.d.ts +14 -17
- package/dist-pkg/input/latch.js +29 -37
- package/dist-pkg/input/pad-defaults.d.ts +13 -16
- package/dist-pkg/input/pad-defaults.js +21 -28
- package/dist-pkg/input/pad-reading.d.ts +76 -0
- package/dist-pkg/input/pad-reading.js +169 -0
- package/dist-pkg/input/pad-wizard.d.ts +99 -0
- package/dist-pkg/input/pad-wizard.js +256 -0
- package/dist-pkg/input/pointer-space.d.ts +19 -20
- package/dist-pkg/input/pointer-space.js +27 -32
- package/dist-pkg/input/pointer.d.ts +39 -40
- package/dist-pkg/input/pointer.js +42 -45
- package/dist-pkg/input/state.d.ts +101 -89
- package/dist-pkg/input/state.js +54 -134
- package/dist-pkg/input/switch-scan.d.ts +59 -0
- package/dist-pkg/input/switch-scan.js +67 -0
- package/dist-pkg/input/synthetic-source.d.ts +42 -0
- package/dist-pkg/input/synthetic-source.js +57 -0
- package/dist-pkg/input/touch-bindings.d.ts +127 -116
- package/dist-pkg/input/touch-bindings.js +158 -173
- package/dist-pkg/input/touch.d.ts +147 -72
- package/dist-pkg/input/touch.js +362 -126
- package/dist-pkg/input/transport-in-use.d.ts +107 -0
- package/dist-pkg/input/transport-in-use.js +130 -0
- package/dist-pkg/input/transports.d.ts +90 -117
- package/dist-pkg/input/transports.js +104 -106
- package/dist-pkg/input/virtual-controller.d.ts +82 -0
- package/dist-pkg/input/virtual-controller.js +69 -0
- package/dist-pkg/input/vocabulary-migration.d.ts +50 -49
- package/dist-pkg/input/vocabulary-migration.js +80 -79
- package/dist-pkg/input/voice-map.d.ts +59 -0
- package/dist-pkg/input/voice-map.js +123 -0
- package/dist-pkg/platform/audio-ambient.d.ts +13 -2
- package/dist-pkg/platform/audio-ambient.js +14 -14
- package/dist-pkg/platform/audio-earcons.d.ts +20 -19
- package/dist-pkg/platform/audio-earcons.js +51 -42
- package/dist-pkg/platform/audio-jingles.js +9 -10
- package/dist-pkg/platform/audio-mixer.d.ts +14 -2
- package/dist-pkg/platform/audio-mixer.js +31 -39
- package/dist-pkg/platform/audio-sonar.d.ts +49 -152
- package/dist-pkg/platform/audio-sonar.js +124 -302
- package/dist-pkg/platform/audio.d.ts +62 -19
- package/dist-pkg/platform/audio.js +193 -168
- package/dist-pkg/platform/choose-by-voice.d.ts +70 -0
- package/dist-pkg/platform/choose-by-voice.js +157 -0
- package/dist-pkg/platform/flash-sampler.d.ts +19 -0
- package/dist-pkg/platform/flash-sampler.js +79 -0
- package/dist-pkg/platform/font-library.d.ts +77 -0
- package/dist-pkg/platform/font-library.js +98 -0
- package/dist-pkg/platform/font-library.json +721 -0
- package/dist-pkg/platform/heavy-catalogue.d.ts +77 -0
- package/dist-pkg/platform/heavy-catalogue.js +256 -0
- package/dist-pkg/platform/heavy-mirror.d.ts +20 -0
- package/dist-pkg/platform/heavy-mirror.js +73 -0
- package/dist-pkg/platform/heavy.d.ts +136 -0
- package/dist-pkg/platform/heavy.js +324 -0
- package/dist-pkg/platform/interruptible-speech.d.ts +23 -16
- package/dist-pkg/platform/interruptible-speech.js +77 -54
- package/dist-pkg/platform/kokoro-port.d.ts +27 -0
- package/dist-pkg/platform/kokoro-port.js +50 -0
- package/dist-pkg/platform/kokoro-runtime.d.ts +20 -0
- package/dist-pkg/platform/kokoro-runtime.js +52 -0
- package/dist-pkg/platform/kokoro.d.ts +70 -0
- package/dist-pkg/platform/kokoro.js +133 -0
- package/dist-pkg/platform/listener-scope.d.ts +12 -0
- package/dist-pkg/platform/listener-scope.js +90 -0
- package/dist-pkg/platform/locale-host.d.ts +14 -0
- package/dist-pkg/platform/locale-host.js +45 -0
- package/dist-pkg/platform/microphone.d.ts +51 -0
- package/dist-pkg/platform/microphone.js +118 -0
- package/dist-pkg/platform/onnx-runtime.d.ts +34 -0
- package/dist-pkg/platform/onnx-runtime.js +42 -0
- package/dist-pkg/platform/reading-in-worker.d.ts +64 -0
- package/dist-pkg/platform/reading-in-worker.js +125 -0
- package/dist-pkg/platform/reading-model.d.ts +94 -0
- package/dist-pkg/platform/reading-model.js +272 -0
- package/dist-pkg/platform/reading-runtime.d.ts +24 -0
- package/dist-pkg/platform/reading-runtime.js +164 -0
- package/dist-pkg/platform/reading-worker.d.ts +41 -0
- package/dist-pkg/platform/reading-worker.js +58 -0
- package/dist-pkg/platform/reading.d.ts +80 -0
- package/dist-pkg/platform/reading.js +136 -0
- package/dist-pkg/platform/speech-recognition.d.ts +60 -0
- package/dist-pkg/platform/speech-recognition.js +104 -0
- package/dist-pkg/platform/speech.d.ts +23 -1
- package/dist-pkg/platform/speech.js +29 -18
- package/dist-pkg/platform/storage-keys.d.ts +96 -0
- package/dist-pkg/platform/storage-keys.js +106 -0
- package/dist-pkg/platform/storage.d.ts +46 -111
- package/dist-pkg/platform/storage.js +104 -169
- package/dist-pkg/platform/tts.d.ts +85 -39
- package/dist-pkg/platform/tts.js +447 -127
- package/dist-pkg/platform/vision-loop.d.ts +23 -0
- package/dist-pkg/platform/vision-loop.js +56 -0
- package/dist-pkg/platform/vision.d.ts +132 -0
- package/dist-pkg/platform/vision.js +117 -0
- package/dist-pkg/platform/voice-listener.d.ts +40 -0
- package/dist-pkg/platform/voice-listener.js +88 -0
- package/dist-pkg/platform/voice-plan.d.ts +15 -98
- package/dist-pkg/platform/voice-plan.js +56 -143
- package/dist-pkg/platform/vosk-runtime.d.ts +96 -0
- package/dist-pkg/platform/vosk-runtime.js +151 -0
- package/dist-pkg/platform/vosk-vocabulary.d.ts +6 -0
- package/dist-pkg/platform/vosk-vocabulary.js +178 -0
- package/dist-pkg/render/canvas.d.ts +13 -7
- package/dist-pkg/render/canvas.js +13 -13
- package/dist-pkg/render/crt.d.ts +48 -12
- package/dist-pkg/render/crt.js +78 -80
- package/dist-pkg/render/cvd-matrices.d.ts +22 -18
- package/dist-pkg/render/cvd-matrices.js +37 -38
- package/dist-pkg/render/hc-role-data.d.ts +7 -7
- package/dist-pkg/render/hc-role-data.js +14 -14
- package/dist-pkg/render/high-contrast.d.ts +67 -56
- package/dist-pkg/render/high-contrast.js +226 -217
- package/dist-pkg/render/low-vision-drawing.d.ts +5 -0
- package/dist-pkg/render/low-vision-drawing.js +46 -0
- package/dist-pkg/render/lq-filter.d.ts +32 -20
- package/dist-pkg/render/lq-filter.js +59 -65
- package/dist-pkg/render/port.d.ts +86 -88
- package/dist-pkg/render/port.js +17 -23
- package/dist-pkg/render/screen-pipeline.d.ts +42 -42
- package/dist-pkg/render/screen-pipeline.js +80 -87
- package/dist-pkg/render/sprite-fx.d.ts +2 -1
- package/dist-pkg/render/sprite-fx.js +16 -14
- package/dist-pkg/render/viewports.d.ts +20 -15
- package/dist-pkg/render/viewports.js +83 -114
- package/dist-pkg/render/viz-axes-labels.d.ts +47 -0
- package/dist-pkg/render/viz-axes-labels.js +88 -0
- package/dist-pkg/render/viz-axes.d.ts +89 -86
- package/dist-pkg/render/viz-axes.js +128 -116
- package/dist-pkg/render/viz-modes.d.ts +28 -29
- package/dist-pkg/render/viz-modes.js +40 -45
- package/dist-pkg/render/viz-refusal.d.ts +32 -0
- package/dist-pkg/render/viz-refusal.js +57 -0
- package/dist-pkg/render/viz-setters.d.ts +104 -66
- package/dist-pkg/render/viz-setters.js +182 -191
- package/dist-pkg/ui/aac-sets.d.ts +45 -0
- package/dist-pkg/ui/aac-sets.js +41 -0
- package/dist-pkg/ui/audio-choices.d.ts +68 -0
- package/dist-pkg/ui/audio-choices.js +98 -0
- package/dist-pkg/ui/audio-rows-that-apply.d.ts +12 -0
- package/dist-pkg/ui/audio-rows-that-apply.js +43 -0
- package/dist-pkg/ui/camera-control.d.ts +53 -0
- package/dist-pkg/ui/camera-control.js +48 -0
- package/dist-pkg/ui/changed-mark.d.ts +9 -8
- package/dist-pkg/ui/changed-mark.js +22 -53
- package/dist-pkg/ui/control-choices.d.ts +37 -0
- package/dist-pkg/ui/control-choices.js +84 -0
- package/dist-pkg/ui/debug-panel.d.ts +59 -43
- package/dist-pkg/ui/debug-panel.js +68 -69
- package/dist-pkg/ui/declared-words.d.ts +21 -0
- package/dist-pkg/ui/declared-words.js +66 -0
- package/dist-pkg/ui/dom.d.ts +10 -14
- package/dist-pkg/ui/dom.js +10 -47
- package/dist-pkg/ui/drawing-problems.d.ts +25 -0
- package/dist-pkg/ui/drawing-problems.js +94 -0
- package/dist-pkg/ui/eye-control.d.ts +36 -0
- package/dist-pkg/ui/eye-control.js +178 -0
- package/dist-pkg/ui/face-control.d.ts +25 -0
- package/dist-pkg/ui/face-control.js +183 -0
- package/dist-pkg/ui/focus-trap.d.ts +39 -49
- package/dist-pkg/ui/focus-trap.js +56 -65
- package/dist-pkg/ui/fonts.d.ts +157 -68
- package/dist-pkg/ui/fonts.js +305 -115
- package/dist-pkg/ui/footer-scroll-driver.d.ts +14 -0
- package/dist-pkg/ui/footer-scroll-driver.js +201 -0
- package/dist-pkg/ui/footer-scroll.d.ts +38 -0
- package/dist-pkg/ui/footer-scroll.js +55 -0
- package/dist-pkg/ui/game-options.d.ts +47 -0
- package/dist-pkg/ui/game-options.js +158 -0
- package/dist-pkg/ui/gaze-overlay.d.ts +64 -0
- package/dist-pkg/ui/gaze-overlay.js +165 -0
- package/dist-pkg/ui/hand-control.d.ts +25 -0
- package/dist-pkg/ui/hand-control.js +143 -0
- package/dist-pkg/ui/help-panel.d.ts +87 -0
- package/dist-pkg/ui/help-panel.js +242 -0
- package/dist-pkg/ui/hud-bands.d.ts +62 -0
- package/dist-pkg/ui/hud-bands.js +146 -0
- package/dist-pkg/ui/hud-row.d.ts +34 -0
- package/dist-pkg/ui/hud-row.js +80 -0
- package/dist-pkg/ui/hud.d.ts +73 -73
- package/dist-pkg/ui/hud.js +94 -98
- package/dist-pkg/ui/item-announcement.d.ts +13 -12
- package/dist-pkg/ui/item-announcement.js +25 -26
- package/dist-pkg/ui/layout.d.ts +103 -28
- package/dist-pkg/ui/layout.js +117 -99
- package/dist-pkg/ui/libras-avatar-clip.d.ts +30 -0
- package/dist-pkg/ui/libras-avatar-clip.js +86 -0
- package/dist-pkg/ui/libras-avatar-load.d.ts +52 -0
- package/dist-pkg/ui/libras-avatar-load.js +134 -0
- package/dist-pkg/ui/libras-avatar-plan.d.ts +102 -0
- package/dist-pkg/ui/libras-avatar-plan.js +211 -0
- package/dist-pkg/ui/libras-avatar-player.d.ts +28 -0
- package/dist-pkg/ui/libras-avatar-player.js +226 -0
- package/dist-pkg/ui/libras-avatar-stage.d.ts +37 -0
- package/dist-pkg/ui/libras-avatar-stage.js +208 -0
- package/dist-pkg/ui/libras-glosses.d.ts +28 -0
- package/dist-pkg/ui/libras-glosses.js +161 -0
- package/dist-pkg/ui/locale-flags.d.ts +16 -0
- package/dist-pkg/ui/locale-flags.js +30 -0
- package/dist-pkg/ui/loop-crash.d.ts +17 -17
- package/dist-pkg/ui/loop-crash.js +33 -62
- package/dist-pkg/ui/menu-intent.d.ts +61 -0
- package/dist-pkg/ui/menu-intent.js +88 -0
- package/dist-pkg/ui/menu-items.d.ts +20 -0
- package/dist-pkg/ui/menu-items.js +51 -0
- package/dist-pkg/ui/menu-nav.d.ts +98 -92
- package/dist-pkg/ui/menu-nav.js +398 -286
- package/dist-pkg/ui/mobility-choices.d.ts +26 -0
- package/dist-pkg/ui/mobility-choices.js +41 -0
- package/dist-pkg/ui/motion-choices.d.ts +31 -0
- package/dist-pkg/ui/motion-choices.js +68 -0
- package/dist-pkg/ui/motion-scene.d.ts +24 -19
- package/dist-pkg/ui/motion-scene.js +29 -61
- package/dist-pkg/ui/mount-panel.d.ts +81 -0
- package/dist-pkg/ui/mount-panel.js +61 -0
- package/dist-pkg/ui/panel-shell.d.ts +65 -31
- package/dist-pkg/ui/panel-shell.js +92 -66
- package/dist-pkg/ui/panel-widgets.d.ts +150 -0
- package/dist-pkg/ui/panel-widgets.js +294 -0
- package/dist-pkg/ui/pause-buttons.d.ts +35 -0
- package/dist-pkg/ui/pause-buttons.js +66 -0
- package/dist-pkg/ui/pause-icons.d.ts +261 -347
- package/dist-pkg/ui/pause-icons.js +671 -601
- package/dist-pkg/ui/pause-markup.d.ts +86 -0
- package/dist-pkg/ui/pause-markup.js +125 -0
- package/dist-pkg/ui/reach-notice.d.ts +22 -23
- package/dist-pkg/ui/reach-notice.js +55 -58
- package/dist-pkg/ui/scan-overlay.d.ts +23 -0
- package/dist-pkg/ui/scan-overlay.js +50 -0
- package/dist-pkg/ui/screen-text.d.ts +25 -0
- package/dist-pkg/ui/screen-text.js +152 -0
- package/dist-pkg/ui/session-clock.d.ts +32 -0
- package/dist-pkg/ui/session-clock.js +67 -0
- package/dist-pkg/ui/settings-aac.d.ts +70 -0
- package/dist-pkg/ui/settings-aac.js +208 -0
- package/dist-pkg/ui/settings-audio.d.ts +97 -114
- package/dist-pkg/ui/settings-audio.js +493 -425
- package/dist-pkg/ui/settings-controls.d.ts +53 -96
- package/dist-pkg/ui/settings-controls.js +143 -215
- package/dist-pkg/ui/settings-empathy.d.ts +39 -30
- package/dist-pkg/ui/settings-empathy.js +53 -60
- package/dist-pkg/ui/settings-mobility.d.ts +192 -0
- package/dist-pkg/ui/settings-mobility.js +332 -0
- package/dist-pkg/ui/settings-motion.d.ts +91 -70
- package/dist-pkg/ui/settings-motion.js +287 -198
- package/dist-pkg/ui/settings-panel.d.ts +58 -45
- package/dist-pkg/ui/settings-panel.js +189 -94
- package/dist-pkg/ui/settings-typo.d.ts +29 -78
- package/dist-pkg/ui/settings-typo.js +158 -129
- package/dist-pkg/ui/settings-visual.d.ts +29 -87
- package/dist-pkg/ui/settings-visual.js +240 -193
- package/dist-pkg/ui/shell.d.ts +112 -135
- package/dist-pkg/ui/shell.js +148 -217
- package/dist-pkg/ui/simulation-list.d.ts +27 -0
- package/dist-pkg/ui/simulation-list.js +76 -0
- package/dist-pkg/ui/simulation-over-the-world.d.ts +23 -0
- package/dist-pkg/ui/simulation-over-the-world.js +131 -0
- package/dist-pkg/ui/simulation-refusal.d.ts +5 -31
- package/dist-pkg/ui/simulation-refusal.js +8 -56
- package/dist-pkg/ui/switchable-control.d.ts +11 -0
- package/dist-pkg/ui/switchable-control.js +19 -0
- package/dist-pkg/ui/title.d.ts +3 -12
- package/dist-pkg/ui/title.js +49 -18
- package/dist-pkg/ui/top-band.d.ts +26 -0
- package/dist-pkg/ui/top-band.js +96 -0
- package/dist-pkg/ui/typo-choices.d.ts +71 -0
- package/dist-pkg/ui/typo-choices.js +85 -0
- package/dist-pkg/ui/visual-axes-panel.d.ts +11 -47
- package/dist-pkg/ui/visual-axes-panel.js +12 -94
- package/dist-pkg/ui/visual-choices.d.ts +77 -0
- package/dist-pkg/ui/visual-choices.js +107 -0
- package/dist-pkg/ui/vlibras.d.ts +77 -10
- package/dist-pkg/ui/vlibras.js +130 -81
- package/dist-pkg/ui/voice-control.d.ts +68 -0
- package/dist-pkg/ui/voice-control.js +276 -0
- package/dist-pkg/ui/voice-settings.d.ts +95 -0
- package/dist-pkg/ui/voice-settings.js +352 -0
- package/dist-pkg/ui/where-the-child-is.d.ts +31 -0
- package/dist-pkg/ui/where-the-child-is.js +70 -0
- package/docs/CREDITS.md +300 -44
- package/docs/LICENSES.md +189 -145
- package/package.json +51 -27
- package/scripts/check-cartridge.mjs +78 -0
- package/scripts/game-build.d.mts +25 -0
- package/scripts/game-build.mjs +144 -0
- package/scripts/heavy-into-the-delivery.mjs +388 -0
- package/scripts/libras-avatar.json +680 -0
- package/scripts/libras-avatar.mjs +246 -0
- package/scripts/libras-glosses/gloss.py +95 -0
- package/scripts/libras-glosses/pyproject.toml +32 -0
- package/scripts/libras-glosses/uv.lock +781 -0
- package/scripts/libras-glosses.mjs +351 -0
- package/scripts/licences/Apache-2.0.txt +176 -0
- package/scripts/licences/GPL-3.0.txt +674 -0
- package/scripts/licences/MIT.txt +17 -0
- package/scripts/licences/OFL-1.1.txt +86 -0
- package/scripts/licences/UFL-1.0.txt +96 -0
- package/scripts/licences/fonts.mjs +389 -0
- package/scripts/licences/third-party.mjs +301 -0
- package/scripts/licences/vosk-browser.NOTICE.txt +268 -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/fondamento-400-ext.woff2 +0 -0
- package/app/public/vendor/fonts/fondamento-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/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/opendyslexic-400.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/pressstart-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/ufmag-400.woff2 +0 -0
- package/dist-pkg/core/anel.d.ts +0 -17
- package/dist-pkg/core/anel.js +0 -31
- package/dist-pkg/core/collision.d.ts +0 -21
- package/dist-pkg/core/collision.js +0 -62
- package/dist-pkg/core/layers.d.ts +0 -63
- package/dist-pkg/core/layers.js +0 -95
- package/dist-pkg/core/letter-grid.d.ts +0 -55
- package/dist-pkg/core/letter-grid.js +0 -116
- package/dist-pkg/core/password.d.ts +0 -34
- package/dist-pkg/core/password.js +0 -205
- package/dist-pkg/core/rotulo-acessivel.d.ts +0 -17
- package/dist-pkg/core/rotulo-acessivel.js +0 -41
- package/dist-pkg/core/run-state.d.ts +0 -115
- package/dist-pkg/core/run-state.js +0 -40
- package/dist-pkg/core/tiles.d.ts +0 -12
- package/dist-pkg/core/tiles.js +0 -61
- package/dist-pkg/core/world.d.ts +0 -4
- package/dist-pkg/core/world.js +0 -58
- package/dist-pkg/input/origem-sintetica.d.ts +0 -44
- package/dist-pkg/input/origem-sintetica.js +0 -60
- package/dist-pkg/input/transporte-em-uso.d.ts +0 -101
- package/dist-pkg/input/transporte-em-uso.js +0 -130
- package/dist-pkg/platform/audio-nav.d.ts +0 -51
- package/dist-pkg/platform/audio-nav.js +0 -99
- package/dist-pkg/platform/guide-intensity.d.ts +0 -40
- package/dist-pkg/platform/guide-intensity.js +0 -73
- package/dist-pkg/platform/pesados-catalogo.d.ts +0 -14
- package/dist-pkg/platform/pesados-catalogo.js +0 -177
- package/dist-pkg/platform/pesados.d.ts +0 -31
- package/dist-pkg/platform/pesados.js +0 -75
- package/dist-pkg/platform/vozes-prontas.d.ts +0 -28
- package/dist-pkg/platform/vozes-prontas.js +0 -61
- package/dist-pkg/render/camera.d.ts +0 -58
- package/dist-pkg/render/camera.js +0 -105
- package/dist-pkg/render/cenario-data.d.ts +0 -127
- package/dist-pkg/render/cenario-data.js +0 -145
- package/dist-pkg/render/city-tex.d.ts +0 -63
- package/dist-pkg/render/city-tex.js +0 -228
- package/dist-pkg/render/city-tiles.d.ts +0 -11
- package/dist-pkg/render/city-tiles.js +0 -140
- package/dist-pkg/render/draw.d.ts +0 -149
- package/dist-pkg/render/draw.js +0 -231
- package/dist-pkg/render/fx.d.ts +0 -63
- package/dist-pkg/render/fx.js +0 -123
- package/dist-pkg/render/minimap.d.ts +0 -11
- package/dist-pkg/render/minimap.js +0 -94
- package/dist-pkg/render/parallax.d.ts +0 -85
- package/dist-pkg/render/parallax.js +0 -158
- package/dist-pkg/render/player-anim.d.ts +0 -71
- package/dist-pkg/render/player-anim.js +0 -152
- package/dist-pkg/render/recycling-tex.d.ts +0 -48
- package/dist-pkg/render/recycling-tex.js +0 -164
- package/dist-pkg/render/scene-city.d.ts +0 -77
- package/dist-pkg/render/scene-city.js +0 -181
- package/dist-pkg/render/scene-parallax.d.ts +0 -72
- package/dist-pkg/render/scene-parallax.js +0 -426
- package/dist-pkg/render/scene-sky.d.ts +0 -126
- package/dist-pkg/render/scene-sky.js +0 -295
- package/dist-pkg/render/set-cenario.d.ts +0 -54
- package/dist-pkg/render/set-cenario.js +0 -103
- package/dist-pkg/render/textures.d.ts +0 -75
- package/dist-pkg/render/textures.js +0 -240
- package/dist-pkg/render/title-scene.d.ts +0 -46
- package/dist-pkg/render/title-scene.js +0 -75
- package/dist-pkg/render/weather.d.ts +0 -96
- package/dist-pkg/render/weather.js +0 -171
- package/dist-pkg/render/wheelchair-sprites.d.ts +0 -32
- package/dist-pkg/render/wheelchair-sprites.js +0 -69
- package/dist-pkg/render/world-tex.d.ts +0 -18
- package/dist-pkg/render/world-tex.js +0 -87
- package/dist-pkg/ui/activities-menu.d.ts +0 -258
- package/dist-pkg/ui/activities-menu.js +0 -648
- package/dist-pkg/ui/caa-sets.d.ts +0 -39
- package/dist-pkg/ui/caa-sets.js +0 -65
- package/dist-pkg/ui/latch-refusal.d.ts +0 -32
- package/dist-pkg/ui/latch-refusal.js +0 -60
- package/dist-pkg/ui/map-hub.d.ts +0 -56
- package/dist-pkg/ui/map-hub.js +0 -138
- package/dist-pkg/ui/settings-caa.d.ts +0 -45
- package/dist-pkg/ui/settings-caa.js +0 -137
- package/dist-pkg/ui/settings-motor.d.ts +0 -175
- package/dist-pkg/ui/settings-motor.js +0 -342
- package/dist-pkg/ui/webcam.d.ts +0 -7
- package/dist-pkg/ui/webcam.js +0 -93
|
@@ -2,617 +2,444 @@
|
|
|
2
2
|
// input/gamepad.ts — gamepad READING (stdDirs/padActions/bindActive/padMapFor) + the poll dispatcher
|
|
3
3
|
// (pollPads) + the accessibility MAPPING WIZARD (openPadWiz/openPadWizFor/closePadWiz/padWizTick). Pure
|
|
4
4
|
// button->action logic is separated from the DI runtime (initGamepad(ctx)): the Gamepad API is injected
|
|
5
|
-
// (ctx.getGamepads, so tests feed a fake pad with no browser) and every cross-subsystem call (menu nav,
|
|
6
|
-
// join/respawn,
|
|
5
|
+
// (ctx.getGamepads, so tests feed a fake pad with no browser) and every cross-subsystem call (menu nav, modal,
|
|
6
|
+
// join/respawn, pause, overlays) is injected too — it never reaches `document`/`navigator`.
|
|
7
7
|
// Boundary: this module only READS buttons/axes and maps them to actions; the physical button ARTWORK/labels
|
|
8
|
-
// (PAD_DESIGNS) and the on-screen touch pad are input/devices.ts + input/touch
|
|
9
|
-
import { t } from '../core/i18n.js';
|
|
8
|
+
// (PAD_DESIGNS) and the on-screen touch pad are input/devices.ts + input/touch — not here.
|
|
10
9
|
import { EDGE_BY_ACTION, edgeAllowed } from './edges.js';
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
// ⚠️ E ESQUECER É EXATAMENTE O DEFEITO QUE ISTO CONSERTA (issue #120). Um campo opcional no ctx faria a
|
|
21
|
-
// acomodação existir só nos jogos onde alguém se lembrou dela, que é o argumento M3 do ADR-0077 com outro
|
|
22
|
-
// substantivo. Binding vivo de `core/state`: não há por onde falhar.
|
|
23
|
-
import * as estadoDoJogo from '../core/state.js';
|
|
24
|
-
import * as store from '../platform/storage.js';
|
|
25
|
-
function bindingAt(map, key) {
|
|
26
|
-
const v = map[key];
|
|
27
|
-
return typeof v === 'object' && v !== null ? v : undefined;
|
|
28
|
-
}
|
|
29
|
-
// [axisValue, up, down, left, right] — os 8 passos de um D-pad "POV hat" (eixo alto do DirectInput), repouso ~1.286.
|
|
30
|
-
const HAT_STEPS = [
|
|
31
|
-
[-1, 1, 0, 0, 0], [-0.7143, 1, 0, 0, 1], [-0.4286, 0, 0, 0, 1], [-0.1429, 0, 1, 0, 1],
|
|
32
|
-
[0.1429, 0, 1, 0, 0], [0.4286, 0, 1, 1, 0], [0.7143, 0, 0, 1, 0], [1, 1, 0, 1, 0],
|
|
33
|
-
];
|
|
34
|
-
/** Direções pelas FONTES PADRÃO: stick 0/1 (zona morta PAD_DEAD), D-pad 12-15, e o "hat" nos eixos >=6 (POV do
|
|
35
|
-
* DirectInput). Controles com os dois direcionais mapeados ficam com ambos vivos (dedo no stick não mata o D-pad). */
|
|
36
|
-
export function stdDirs(gp) {
|
|
37
|
-
const b = (i) => !!(gp.buttons[i] && gp.buttons[i].pressed);
|
|
38
|
-
const ax = (i) => gp.axes[i] || 0;
|
|
39
|
-
const d = { left: ax(0) < -PAD_DEAD || b(14), right: ax(0) > PAD_DEAD || b(15), up: ax(1) < -PAD_DEAD || b(12), down: ax(1) > PAD_DEAD || b(13) };
|
|
40
|
-
for (let i = 6; i < gp.axes.length; i++) {
|
|
41
|
-
const v = gp.axes[i];
|
|
42
|
-
if (typeof v !== 'number' || Math.abs(v) > 1.001)
|
|
43
|
-
continue; // fora do repouso do hat
|
|
44
|
-
for (const [hv, u, dn, l, r] of HAT_STEPS) {
|
|
45
|
-
if (Math.abs(v - hv) <= 0.09) {
|
|
46
|
-
if (u)
|
|
47
|
-
d.up = true;
|
|
48
|
-
if (dn)
|
|
49
|
-
d.down = true;
|
|
50
|
-
if (l)
|
|
51
|
-
d.left = true;
|
|
52
|
-
if (r)
|
|
53
|
-
d.right = true;
|
|
54
|
-
break;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
return d;
|
|
59
|
-
}
|
|
60
|
-
/** Está o binding `bd` ativo agora neste gamepad? Digital = pressed; analógico ({ax,s}) = limiar por sinal
|
|
61
|
-
* (metade do curso); hat ({av,v}) = valor exato do passo (±0.13 — os 8 passos distam ~0.286). */
|
|
62
|
-
export function bindActive(gp, bd) {
|
|
63
|
-
if (!bd)
|
|
64
|
-
return false;
|
|
65
|
-
if (bd.b != null)
|
|
66
|
-
return !!(gp.buttons[bd.b] && gp.buttons[bd.b].pressed);
|
|
67
|
-
if (bd.ax != null)
|
|
68
|
-
return ((gp.axes[bd.ax] || 0) * (bd.s ?? 0)) > 0.5;
|
|
69
|
-
if (bd.av != null)
|
|
70
|
-
return Math.abs((gp.axes[bd.av] || 0) - (bd.v ?? 0)) <= 0.13;
|
|
71
|
-
return false;
|
|
72
|
-
}
|
|
73
|
-
/** Ações do frame para este gamepad. `custom` = mapa salvo pelo wizard para este `gp.id` (null/`_skip` = usa o
|
|
74
|
-
* mapa PADRÃO da Gamepad API "standard": 0=pulo · 1=especial · 2/5/7=correr · 3=troca · 9=START). Direções
|
|
75
|
-
* custom caem de volta em stdDirs quando o binding do usuário não está ativo (D-pad/stick continuam vivos). */
|
|
76
|
-
export function padActions(gp, custom, tabela = GAMEPAD_STANDARD) {
|
|
77
|
-
if (custom && !custom._skip) {
|
|
78
|
-
const A = (k) => bindActive(gp, bindingAt(custom, k));
|
|
79
|
-
const sd = stdDirs(gp);
|
|
80
|
-
return {
|
|
81
|
-
left: A('left') || sd.left, right: A('right') || sd.right, up: A('up') || sd.up, down: A('down') || sd.down,
|
|
82
|
-
action2: A('action2'), action1: A('action1'), action4: A('action4'), action3: A('action3'), _start: A('action2') || A('start'), _pause: A('start'),
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
const b = (i) => !!(gp.buttons[i] && gp.buttons[i].pressed);
|
|
86
|
-
const sd = stdDirs(gp);
|
|
87
|
-
// ⚠️ OS ÍNDICES SAEM DA TABELA DECLARADA, e não de literais aqui. Enquanto eram literais, esta linha e
|
|
88
|
-
// `input/default-bindings` DISCORDAVAM e nada notava — a mesma forma de defeito que o gate do toque
|
|
89
|
-
// apanhou: duas tabelas que concordam entre si não provam nada sobre um terceiro que as lê.
|
|
90
|
-
//
|
|
91
|
-
// ⚠️ E A DISCORDÂNCIA ERA REAL: aqui estava `action1: b(2) || b(5) || b(7)`, ou seja X, R1 e R2 todos a
|
|
92
|
-
// correr, enquanto a tabela declara R1 como `rightShoulder` e R2 como `rightTrigger`. O ADR-0086 registrou
|
|
93
|
-
// esta mudança como o asterisco do seu «zero movimento»: nenhum VERBO muda de botão, mas `run` perde dois
|
|
94
|
-
// dos seus três. Quem usava R1 para correr sente — e é o preço de os quatro ombros existirem.
|
|
95
|
-
// 📌 A TABELA CHEGA POR PARÂMETRO desde o ADR-0115: é a fábrica da engine COM o padrão deste jogo por cima,
|
|
96
|
-
// resolvida em `input/pad-defaults`. O padrão da assinatura é o da engine, então quem chamava com dois
|
|
97
|
-
// argumentos continua a ler exactamente o que lia.
|
|
98
|
-
// ⚠️ E ela só decide neste ramo, que é o certo: o ramo de cima é o mapa que a CRIANÇA gravou no assistente,
|
|
99
|
-
// e o padrão de um jogo não se sobrepõe a uma escolha dela.
|
|
100
|
-
const B = tabela;
|
|
101
|
-
const at = (a) => { const i = B[a]; return typeof i === 'number' ? b(i) : false; };
|
|
102
|
-
return {
|
|
103
|
-
left: sd.left, right: sd.right, up: sd.up, down: sd.down,
|
|
104
|
-
action1: at('action1'), action2: at('action2'), action3: at('action3'), action4: at('action4'),
|
|
105
|
-
leftShoulder: at('leftShoulder'), leftTrigger: at('leftTrigger'),
|
|
106
|
-
rightShoulder: at('rightShoulder'), rightTrigger: at('rightTrigger'),
|
|
107
|
-
// ⚠️ `start` COMO POSIÇÃO, e não só como os derivados abaixo. Faltava, e o gate da tabela foi quem
|
|
108
|
-
// o encontrou: quem quisesse saber «o START está apertado?» tinha de ler `_start`, que começa por
|
|
109
|
-
// underscore e quer dizer outra coisa (fecha diálogo, e aceita a ação 2 também).
|
|
110
|
-
start: at('start'), select: at('select'),
|
|
111
|
-
// `_start` e `_pause` são DERIVADOS e não posições: «fecha diálogo» aceita a ação 2 ou o START, «pausa»
|
|
112
|
-
// só o START. Ficam escritos aqui porque descrevem o que a raiz faz com duas posições, não uma terceira.
|
|
113
|
-
_start: at('action2') || at('start'), _pause: at('start'),
|
|
114
|
-
};
|
|
115
|
-
}
|
|
10
|
+
import { createPadWizard, PADWIZ_ORDER as ORDEM_DO_ASSISTENTE } from './pad-wizard.js';
|
|
11
|
+
// 📌 The pad's frame memory, the stored maps and the game's button table arrive through the ctx, built once by the root
|
|
12
|
+
// (ADR-0232 D4): as module state, two roots on one page shared a pad's previous frame and each other's maps.
|
|
13
|
+
// 📌 `oneButton` (the motor empathy's one-button mode, issue #120) arrives through the ctx, as `input/keydown`'s does:
|
|
14
|
+
// the settings store is built by the root and passed in (ADR-0232, issue #207). The field is REQUIRED, which is what the
|
|
15
|
+
// old live import defended — an optional field would make the accommodation exist only where someone remembered it
|
|
16
|
+
// (ADR-0077's M3 argument); a required one does not compile without it.
|
|
17
|
+
// ---------------------------------------------------------------------------------------------
|
|
18
|
+
// Gamepad API surface (minimal, adapter-friendly — mirrors the real Gamepad/GamepadButton shape)
|
|
116
19
|
// ---------------------------------------------------------------------------------------------
|
|
117
|
-
//
|
|
20
|
+
// 🔴 WHAT A PAD IS DOING lives in `input/pad-reading`: it is the PURE half — buttons and axes in, positions out. Here
|
|
21
|
+
// is the wiring, which can only be read with a ctx in hand: the conductor that polls the pads every frame and decides
|
|
22
|
+
// where the reading goes.
|
|
23
|
+
// ⚠️ NO ALIAS: a re-export would keep alive a published path nothing in the engine imports (issue #204), and the
|
|
24
|
+
// migration note is what says where each name went.
|
|
25
|
+
import { padActions, oneButtonAtOnce, } from './pad-reading.js';
|
|
26
|
+
// ---------------------------------------------------------------------------------------------
|
|
27
|
+
// Wizard data (the ORDER of the steps; the WORDS and the demonstration come from the game)
|
|
118
28
|
// ---------------------------------------------------------------------------------------------
|
|
119
29
|
/**
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
* ⚠️ ELA CARREGAVA AS PALAVRAS, EM PORTUGUÊS CRU, DENTRO DA ENGINE: `['action2', 'PULAR']`,
|
|
123
|
-
* `['action1', 'CORRER / INTERAGIR']`. Era o defeito do ADR-0074 na sua forma mais visível — não só
|
|
124
|
-
* vocabulário de plataforma dentro do motor, mas vocabulário de plataforma NUM IDIOMA SÓ, à frente de uma
|
|
125
|
-
* criança, num ficheiro que o pilar 3 obriga a ser localizável.
|
|
30
|
+
* The ORDER in which the wizard asks. ONLY the order — the same list `input/pad-wizard` walks, where it lives apart
|
|
31
|
+
* from any game (issue #182).
|
|
126
32
|
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
33
|
+
* ⚠️ NO WORDS HERE: the word comes from `ctx.actionLabel`, which the game supplies through its preset (ADR-0074 —
|
|
34
|
+
* platformer vocabulary, in one language, inside the engine was the defect this removed). What stays is what really
|
|
35
|
+
* is the engine's: the sequence of the questions — directions first, actions next, system last —, an ergonomic
|
|
36
|
+
* decision of the wizard and not of the game.
|
|
130
37
|
*
|
|
131
|
-
* ⚠️
|
|
132
|
-
*
|
|
133
|
-
*
|
|
38
|
+
* ⚠️ AND AN ACTION THE GAME DOES NOT NAME IS NOT ASKED. `input/pad-wizard` skips it, because a game that does not use
|
|
39
|
+
* the position has nothing to map on it — and asking would produce a mute step or, worse, a step saying `action7` out
|
|
40
|
+
* loud. The exception is the system's two: START and SELECT are always asked, in the engine's words, because no game may
|
|
41
|
+
* name them and no pad may lack them (ADR-0144, erratum of 2026-09-26).
|
|
134
42
|
*/
|
|
43
|
+
export const PADWIZ_ORDER = ORDEM_DO_ASSISTENTE;
|
|
135
44
|
/**
|
|
136
|
-
*
|
|
45
|
+
* WHAT EACH ABSENCE MEANS, AS DATA (ADR-0224). A table and not ten `??` scattered through whoever mounts: the meaning
|
|
46
|
+
* of an absence is a DECISION, and a composition root should hold only wiring — ten decisions in it are ten branches in
|
|
47
|
+
* a function the ratchet already watches (ADR-0221, erratum).
|
|
137
48
|
*
|
|
138
|
-
* ⚠️
|
|
139
|
-
*
|
|
140
|
-
* é acomodação. Os derivados (`_start`, `_pause`) também passam: eles descrevem o que a raiz faz com
|
|
141
|
-
* estas duas posições, não uma terceira.
|
|
49
|
+
* ⚠️ `worldRunning` is not here because its absence has no universal answer: it depends on whoever mounts knowing
|
|
50
|
+
* which menus they have open. It comes in as a parameter, which also makes it the only absence a host can answer.
|
|
142
51
|
*/
|
|
143
|
-
const
|
|
52
|
+
const SILENT_PAD_ANSWERS = Object.freeze({
|
|
53
|
+
navTitle: () => { }, // no title screen to navigate
|
|
54
|
+
attractActive: () => false, // no demonstration running
|
|
55
|
+
stopAttract: () => { }, // so nothing to stop
|
|
56
|
+
hasModal: () => false, // no open challenge: the d-pad belongs to the game
|
|
57
|
+
modalInput: () => { }, // and so nothing to feed
|
|
58
|
+
joinPlayer: () => false, // nobody joins a running game midway
|
|
59
|
+
respawnPlayer: () => { }, // an abandoned screen stays abandoned
|
|
60
|
+
clearWaitingBadge: () => { }, // the waiting badge is the game's HUD; with no game declaring it, it does not exist
|
|
61
|
+
wizardStep: () => { }, // the mapping wizard speaks, with no drawing
|
|
62
|
+
wizardTick: () => { }, // and so nothing animates
|
|
63
|
+
});
|
|
144
64
|
/**
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
* «segurar» que o ADR-0077 dá.
|
|
65
|
+
* The cartridge's answers with every absence already resolved. 📌 A field DECLARED as `undefined` is an absence like any
|
|
66
|
+
* other — spreading the raw object over the table would erase the answer with an `undefined`, which is the silent
|
|
67
|
+
* defect this function exists not to have.
|
|
68
|
+
*/
|
|
69
|
+
export function padGameAnswers(hooks, worldRunningWhenSilent) {
|
|
70
|
+
const declared = {};
|
|
71
|
+
for (const [name, answer] of Object.entries(hooks ?? {}))
|
|
72
|
+
if (answer !== undefined)
|
|
73
|
+
declared[name] = answer;
|
|
74
|
+
return { worldRunning: worldRunningWhenSilent, ...SILENT_PAD_ANSWERS, ...declared };
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* THE SEAT FIELDS, SEEDED BY THE ENGINE (ADR-0224). 📏 Measured: the players a cartridge declares are
|
|
78
|
+
* `{ ctrl, audioSink? }`, and this transport needs to know whose each pad is (`pad`), who is still waiting (`waiting`)
|
|
79
|
+
* and who left the screen (`quit`).
|
|
161
80
|
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
81
|
+
* 🔴 IT SEEDS THE OBJECT ITSELF and returns the SAME list — copying would lose the seat on the next frame, because
|
|
82
|
+
* `takeSeat` writes into this object. That is also why there is no `.map`: the identity is what carries the state.
|
|
83
|
+
* 📌 It only touches whoever does not have the fields yet, so a cartridge that declares them keeps its own.
|
|
165
84
|
*/
|
|
166
|
-
export function
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
const ativas = cortaveis.filter((k) => atual[k] === true);
|
|
175
|
-
if (ativas.length <= 1)
|
|
176
|
-
return atual;
|
|
177
|
-
// A que já valia tem prioridade; sem nenhuma, a primeira do retrato assume.
|
|
178
|
-
const mantida = ativas.find((k) => anterior[k] === true) ?? ativas[0];
|
|
179
|
-
const saida = { ...atual };
|
|
180
|
-
for (const k of ativas)
|
|
181
|
-
if (k !== mantida)
|
|
182
|
-
saida[k] = false;
|
|
183
|
-
return saida;
|
|
85
|
+
export function seatEveryPlayer(list) {
|
|
86
|
+
for (const p of list) {
|
|
87
|
+
const seat = p;
|
|
88
|
+
seat.pad ??= -1;
|
|
89
|
+
seat.waiting ??= false;
|
|
90
|
+
seat.quit ??= false;
|
|
91
|
+
}
|
|
92
|
+
return list;
|
|
184
93
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
// de uma mão —, e um jogo que declarasse `leftShoulder` não tinha por onde a criança o mapear. Cinco das
|
|
194
|
-
// quatorze posições eram inalcançáveis exatamente para quem mais precisa do assistente.
|
|
195
|
-
'leftShoulder', 'leftTrigger', 'rightShoulder', 'rightTrigger',
|
|
196
|
-
// Sistema por último: `start` e `select` costumam ser os botões mais pequenos e mais escondidos, e pedi-los
|
|
197
|
-
// no fim deixa a criança já habituada ao ritmo do assistente quando chega neles.
|
|
198
|
-
'start', 'select',
|
|
199
|
-
];
|
|
200
|
-
/** Demonstração animada de cada ação (frames reais do jogo) mostrada durante o passo correspondente do wizard. */
|
|
201
|
-
export const PADWIZ_ANIM = {
|
|
202
|
-
up: { seq: ['escada/0', 'escada/1'], hold: 9, cls: 'pw-up' },
|
|
203
|
-
down: { seq: ['escada/1', 'escada/0'], hold: 9, cls: 'pw-down' },
|
|
204
|
-
left: { seq: ['andar/0', 'andar/1', 'andar/2', 'andar/3', 'andar/4', 'andar/5', 'andar/6', 'andar/7'], hold: 4, cls: 'pw-left', flip: 1 },
|
|
205
|
-
right: { seq: ['andar/0', 'andar/1', 'andar/2', 'andar/3', 'andar/4', 'andar/5', 'andar/6', 'andar/7'], hold: 4, cls: 'pw-right' },
|
|
206
|
-
action2: { seq: ['pulo/0', 'pulo/0', 'pulo/1', 'pulo/1'], hold: 7, cls: 'pw-jump' },
|
|
207
|
-
action1: { seq: ['correr/0', 'correr/1', 'correr/2', 'correr/3'], hold: 3, cls: 'pw-run' },
|
|
208
|
-
action4: { fx: '👟 🕷️ 🎈 🐇 🦘', cls: 'pw-swap', noimg: 1 },
|
|
209
|
-
action3: { seq: ['idle/0', 'idle/1', 'idle/2', 'idle/3'], hold: 8, fx: '✨', cls: 'pw-especial' },
|
|
210
|
-
start: { fx: 'PAUSA', cls: 'pw-start', noimg: 1 },
|
|
211
|
-
};
|
|
94
|
+
/** The eight positions THIS transport reads: the d-pad and the four actions. The shoulders and triggers a cartridge may
|
|
95
|
+
* declare have no reading on the pad — the list says what is true today. */
|
|
96
|
+
const PAD_POSITIONS = Object.freeze(['left', 'right', 'up', 'down', 'action1', 'action2', 'action3', 'action4']);
|
|
97
|
+
/** Inside a modal the ORDER is the rule — `input/keydown`'s: a pad delivers a snapshot with no order of arrival, and
|
|
98
|
+
* with left and confirm in the same frame it is this list that decides the child moves instead of confirming. */
|
|
99
|
+
const MODAL_BY_POSITION = Object.freeze([
|
|
100
|
+
['left', 'left'], ['right', 'right'], ['up', 'up'], ['down', 'down'], ['action2', 'confirm'], ['action3', 'erase'],
|
|
101
|
+
]);
|
|
212
102
|
export function initGamepad(ctx) {
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
let padWizAutoResume = false; // wizard
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
if (!d)
|
|
246
|
-
return;
|
|
247
|
-
const a = k ? PADWIZ_ANIM[k] : null;
|
|
248
|
-
d.className = a ? a.cls : '';
|
|
249
|
-
padWizAnim = null;
|
|
250
|
-
if (fx)
|
|
251
|
-
fx.textContent = (a && a.fx) || '';
|
|
252
|
-
if (img) {
|
|
253
|
-
img.style.display = a && a.noimg ? 'none' : '';
|
|
254
|
-
img.style.transform = a && a.flip ? 'scaleX(-1)' : '';
|
|
255
|
-
if (a && a.seq) {
|
|
256
|
-
img.src = ctx.spriteBase + a.seq[0] + '.png';
|
|
257
|
-
padWizAnim = { seq: a.seq, hold: a.hold || 6, t: 0 };
|
|
103
|
+
const { t } = ctx;
|
|
104
|
+
const { padCur, padPrevAct, padPrevStart } = ctx.input;
|
|
105
|
+
let padWizAutoResume = false; // the wizard opened by itself mid-game -> resume when it closes
|
|
106
|
+
// the root's one cache of stored maps (input/pad-wizard): a map saved by the engine's own wizard is read here next frame
|
|
107
|
+
const padMapFor = (id) => ctx.padMaps.padMap(id);
|
|
108
|
+
function actionsFor(gp, table) { return padActions(gp, padMapFor(gp.id), table); }
|
|
109
|
+
// the wizard asks; what a position LOOKS like is drawn by the game (note CD), through the two hooks it may answer
|
|
110
|
+
const wizard = createPadWizard({
|
|
111
|
+
maps: ctx.padMaps, t,
|
|
112
|
+
getGamepads: () => ctx.getGamepads(),
|
|
113
|
+
actionLabel: (action) => ctx.actionLabel(action),
|
|
114
|
+
say: (phrase) => { const el = ctx.$('#padwiz-prompt'); if (el)
|
|
115
|
+
el.textContent = phrase; ctx.srSay(phrase); },
|
|
116
|
+
progress: (text) => { const pr = ctx.$('#padwiz-progress'); if (pr)
|
|
117
|
+
pr.textContent = text; },
|
|
118
|
+
srAlert: (phrase) => ctx.srAlert(phrase),
|
|
119
|
+
onStep: (position) => ctx.wizardStep(position),
|
|
120
|
+
onTick: () => ctx.wizardTick(),
|
|
121
|
+
onClose: (gi) => {
|
|
122
|
+
const ov = ctx.$('#padwiz');
|
|
123
|
+
if (ov)
|
|
124
|
+
ov.hidden = true;
|
|
125
|
+
// no phantom edges: the button still HELD from the last step (SELECT) must not open the menus or act on resume
|
|
126
|
+
try {
|
|
127
|
+
const pads = ctx.getGamepads() ?? [];
|
|
128
|
+
const gp = pads[gi];
|
|
129
|
+
if (gp) {
|
|
130
|
+
const c = actionsFor(gp);
|
|
131
|
+
padCur[gi] = c;
|
|
132
|
+
padPrevAct[gi] = c;
|
|
133
|
+
padPrevStart[gi] = c._start;
|
|
134
|
+
}
|
|
258
135
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
if (img)
|
|
270
|
-
img.src = ctx.spriteBase + a.seq[Math.floor(a.t / a.hold) % a.seq.length] + '.png';
|
|
271
|
-
}
|
|
272
|
-
/**
|
|
273
|
-
* Anda até o próximo passo que ESTE jogo usa, ou fecha se não houver mais.
|
|
274
|
-
*
|
|
275
|
-
* ⚠️ UMA FUNÇÃO SÓ, e antes eram duas com regras diferentes: `wizBind` incrementava e fechava no fim,
|
|
276
|
-
* `wizPrompt` saltava as não nomeadas. Depois do último passo nomeado o assistente ficava aberto a
|
|
277
|
-
* apontar para uma posição que o jogo não usa, e só fechava no tique seguinte — uma criança veria o
|
|
278
|
-
* assistente pendurado, sem pergunta nenhuma na tela.
|
|
279
|
-
*/
|
|
280
|
-
function wizAvancar() {
|
|
281
|
-
if (!padWiz)
|
|
282
|
-
return;
|
|
283
|
-
while (padWiz.step < PADWIZ_ORDER.length && !ctx.rotuloDaAcao(PADWIZ_ORDER[padWiz.step]))
|
|
284
|
-
padWiz.step++;
|
|
285
|
-
if (padWiz.step >= PADWIZ_ORDER.length)
|
|
286
|
-
closePadWiz(true);
|
|
287
|
-
}
|
|
288
|
-
function wizPrompt() {
|
|
289
|
-
if (!padWiz)
|
|
290
|
-
return;
|
|
291
|
-
wizAvancar();
|
|
292
|
-
if (!padWiz)
|
|
293
|
-
return; // fechou ao avançar
|
|
294
|
-
const acao = PADWIZ_ORDER[padWiz.step];
|
|
295
|
-
const rotulo = ctx.rotuloDaAcao(acao);
|
|
296
|
-
wizSay(t('pad.wiz.step', { n: padWiz.step + 1, total: PADWIZ_ORDER.length, acao: rotulo }));
|
|
297
|
-
wizDemo(acao); // demonstração animada do que a ação FAZ
|
|
298
|
-
const pr = ctx.$('#padwiz-progress');
|
|
299
|
-
// O travessão da lista vazia fica cru de propósito: é pontuação, não idioma.
|
|
300
|
-
if (pr)
|
|
301
|
-
pr.textContent = t('pad.wiz.mapped', { lista: Object.keys(padWiz.map).join(' · ') || '—' });
|
|
302
|
-
}
|
|
303
|
-
function wizBind(bd) {
|
|
304
|
-
if (!padWiz)
|
|
305
|
-
return;
|
|
306
|
-
padWiz.map[PADWIZ_ORDER[padWiz.step]] = bd;
|
|
307
|
-
padWiz.step++;
|
|
308
|
-
padWiz.release = true; // exige soltar antes do próximo passo (mesmo botão segurado não dobra pro passo seguinte)
|
|
309
|
-
wizAvancar(); // salta o que este jogo não usa, e fecha se o resto da lista for tudo isso
|
|
310
|
-
}
|
|
311
|
-
// ----- wizard: abrir/fechar -----
|
|
136
|
+
catch { /* a pad API that throws here only costs the edge baseline, never the closing */ }
|
|
137
|
+
if (padWizAutoResume) {
|
|
138
|
+
padWizAutoResume = false;
|
|
139
|
+
if (ctx.pauseMenu())
|
|
140
|
+
ctx.resume(0);
|
|
141
|
+
}
|
|
142
|
+
// last: the overlay is hidden and the game resumed, so the focus goes back to what is really in front (ADR-0248)
|
|
143
|
+
ctx.wizardClosed();
|
|
144
|
+
},
|
|
145
|
+
});
|
|
312
146
|
function openPadWiz() {
|
|
313
147
|
const ov = ctx.$('#padwiz');
|
|
314
148
|
if (!ov)
|
|
315
149
|
return;
|
|
316
150
|
ov.hidden = false;
|
|
317
151
|
ctx.frontOverlay(ov);
|
|
318
|
-
|
|
319
|
-
wizSay(t('pad.wiz.pressAny'));
|
|
320
|
-
wizDemo(null);
|
|
321
|
-
const pr = ctx.$('#padwiz-progress');
|
|
322
|
-
if (pr)
|
|
323
|
-
pr.textContent = '';
|
|
324
|
-
padWiz.timer = setInterval(padWizTick, 30);
|
|
152
|
+
wizard.open();
|
|
325
153
|
}
|
|
326
|
-
//
|
|
154
|
+
// The wizard opened BY ITSELF (a DirectInput pad with no map pressed something): we already know which pad it is.
|
|
327
155
|
function openPadWizFor(gp) {
|
|
328
156
|
const ov = ctx.$('#padwiz');
|
|
329
157
|
if (!ov)
|
|
330
158
|
return;
|
|
331
159
|
ov.hidden = false;
|
|
332
160
|
ctx.frontOverlay(ov);
|
|
333
|
-
|
|
334
|
-
wizSay(t('pad.wiz.detected', { id: gp.id }));
|
|
335
|
-
wizDemo(null);
|
|
336
|
-
const pr = ctx.$('#padwiz-progress');
|
|
337
|
-
if (pr)
|
|
338
|
-
pr.textContent = '';
|
|
339
|
-
padWiz.timer = setInterval(padWizTick, 30);
|
|
161
|
+
wizard.openFor(gp);
|
|
340
162
|
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
163
|
+
const closePadWiz = (save) => wizard.close(save);
|
|
164
|
+
const padWizTick = () => wizard.tick();
|
|
165
|
+
const cancelBtn = ctx.$('#padwiz-cancel');
|
|
166
|
+
if (cancelBtn)
|
|
167
|
+
cancelBtn.addEventListener('click', () => closePadWiz(false));
|
|
168
|
+
// ----- poll (called every frame of the loop) -----
|
|
169
|
+
/** This frame's reading for ONE pad: the actions now, the edges against the previous frame, and the seat. */
|
|
170
|
+
function readPad(gp, players) {
|
|
171
|
+
const gi = gp.index;
|
|
172
|
+
const prev = padPrevAct[gi] || {};
|
|
173
|
+
// ⚠️ THE SEAT IS READ BEFORE THE ACTIONS, and the reason is ADR-0115: this game's button table is declared PER SEAT,
|
|
174
|
+
// and it is read inside `actionsFor`. Read after, the actions would be taken before knowing whose pad it is — and a
|
|
175
|
+
// per-seat default would arrive late.
|
|
176
|
+
const owner = players.findIndex((p) => p.pad === gi);
|
|
177
|
+
// ⚠️ AND A PAD NOT YET ASSIGNED (`owner < 0`) READS SEAT 0, not "none": it is producing edges on the title screen,
|
|
178
|
+
// and an empty map there would leave the child with no way to choose their own game.
|
|
179
|
+
// THE MOTOR EMPATHY SIMULATION APPLIED TO THE PAD (issue #120). Without this line, a child with the one-button mode
|
|
180
|
+
// on and a pad in hand WAS NOT in the mode — and nothing anywhere said so.
|
|
181
|
+
const cur = oneButtonAtOnce(prev, actionsFor(gp, ctx.padTable(ctx.getNumPlayers(), owner < 0 ? 0 : owner)), ctx.oneButton());
|
|
182
|
+
const startEdge = cur._start && !padPrevStart[gi];
|
|
183
|
+
padPrevStart[gi] = cur._start;
|
|
184
|
+
const pauseEdge = cur._pause && !prev._pause;
|
|
185
|
+
const selectEdge = !!cur.select && !prev.select;
|
|
186
|
+
const edge = (k) => cur[k] && !prev[k];
|
|
187
|
+
const released = (k) => !!prev[k] && !cur[k];
|
|
188
|
+
padCur[gi] = cur;
|
|
189
|
+
padPrevAct[gi] = cur;
|
|
190
|
+
// 📌 START counts as "yes" ONLY on the title: there it is the button that begins the game, and on the pause card or
|
|
191
|
+
// the bar it is the EXIT (ADR-0044 item 7). One parameter instead of three lists equal but for one term.
|
|
192
|
+
const navKeys = (withStart = false) => ({
|
|
193
|
+
yes: edge('action2') || (withStart && startEdge), no: edge('action3'),
|
|
194
|
+
up: edge('up'), down: edge('down'), left: edge('left'), right: edge('right'),
|
|
195
|
+
});
|
|
196
|
+
return { gp, gi, owner, players, cur, startEdge, pauseEdge, selectEdge, edge, released, navKeys };
|
|
197
|
+
}
|
|
198
|
+
/** Did any of the six menu intents happen this frame? */
|
|
199
|
+
// 📌 The `!!` is what `NavKeys` asks for: its six fields are OPTIONAL, because not every transport produces them all.
|
|
200
|
+
const anyIntent = (k) => !!(k.yes || k.no || k.up || k.down || k.left || k.right);
|
|
201
|
+
/** A non-standard (DirectInput) pad with NO stored map pressed something: pause everything and open the wizard on it. */
|
|
202
|
+
function wizardTookOver(gp) {
|
|
203
|
+
if (gp.mapping === 'standard' || padMapFor(gp.id) || !gp.buttons.some((b) => b && b.pressed))
|
|
204
|
+
return false;
|
|
205
|
+
padWizAutoResume = ctx.worldRunning();
|
|
206
|
+
if (ctx.worldRunning())
|
|
207
|
+
ctx.pause();
|
|
208
|
+
openPadWizFor(gp);
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
/** A win: START/jump close the modal (Play again), and nothing from this pad reaches the game underneath it. */
|
|
212
|
+
function winOverlayTook(f) {
|
|
213
|
+
const winOv = ctx.$('#win-overlay');
|
|
214
|
+
if (!winOv || winOv.hidden)
|
|
215
|
+
return false;
|
|
216
|
+
if (f.startEdge) {
|
|
217
|
+
const b = ctx.$('#btn-again');
|
|
218
|
+
if (b)
|
|
219
|
+
b.click();
|
|
350
220
|
}
|
|
351
|
-
|
|
352
|
-
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
/** The title menu: the pad navigates, and in a multiplayer game only P1 chooses. */
|
|
224
|
+
function steerTitle(f) {
|
|
225
|
+
const k = f.navKeys(true);
|
|
226
|
+
if (!anyIntent(k))
|
|
227
|
+
return;
|
|
228
|
+
if (ctx.getNumPlayers() > 1 && f.owner > 0) {
|
|
229
|
+
ctx.srSay(t('sr.title.waitP1'));
|
|
230
|
+
return;
|
|
231
|
+
} // only P1 chooses
|
|
232
|
+
ctx.navTitle(k); // the title menu, navigable by pad
|
|
233
|
+
}
|
|
234
|
+
/** A menu is open: START resumes, action 4 is pressed, and the d-pad navigates the quick bar, the shared dialog or the seat's own card. */
|
|
235
|
+
function steerPause(f) {
|
|
236
|
+
const pi = f.owner < 0 ? 0 : f.owner;
|
|
237
|
+
if (f.pauseEdge) {
|
|
238
|
+
ctx.resume(pi);
|
|
239
|
+
return;
|
|
240
|
+
} // START resumes — if this seat's START reaches this screen's pause (the root's)
|
|
241
|
+
if (ctx.leadsTheScreen && !ctx.leadsTheScreen(pi))
|
|
242
|
+
return; // another seat of a shared screen steers none of its menus
|
|
243
|
+
// ACTION 4 IS PRESSED, as the keyboard's key rises: no menu intent reads it, and the controller hands it to the menus as the
|
|
244
|
+
// seat's key, which the root answers where it answers the keyboard's — in the quick pause, the menus' second door (ADR-0155
|
|
245
|
+
// erratum «Ambos»). The pad decides nothing about it; one frame, one door, as SELECT.
|
|
246
|
+
if (f.edge('action4')) {
|
|
247
|
+
ctx.press('action4', 'gamepad', pi);
|
|
248
|
+
return;
|
|
353
249
|
}
|
|
354
|
-
const
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
const gp = pads[gi];
|
|
363
|
-
if (gp) {
|
|
364
|
-
const c = actionsFor(gp);
|
|
365
|
-
padCur[gi] = c;
|
|
366
|
-
padPrevAct[gi] = c;
|
|
367
|
-
padPrevStart[gi] = c._start;
|
|
368
|
-
}
|
|
250
|
+
const k = f.navKeys();
|
|
251
|
+
if (!anyIntent(k))
|
|
252
|
+
return;
|
|
253
|
+
// THE QUICK BAR FIRST, in the order `ui/menu-nav` steers a key: the quick pause (ADR-0155 §1) is a menu, so its frames come
|
|
254
|
+
// HERE and never reach `steerGame`'s bar. START was answered above, so the bar's exits here are back, and START by `resume`.
|
|
255
|
+
if (ctx.onBar(pi)) {
|
|
256
|
+
ctx.navBar(pi, k, false);
|
|
257
|
+
return;
|
|
369
258
|
}
|
|
370
|
-
|
|
371
|
-
if (
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
ctx.retomar();
|
|
259
|
+
const dlg = ctx.sharedDialogOpen();
|
|
260
|
+
if (dlg) {
|
|
261
|
+
ctx.navDialog(dlg, k);
|
|
262
|
+
return;
|
|
375
263
|
}
|
|
264
|
+
const menu = ctx.getPauseMenu(pi);
|
|
265
|
+
if (menu && !menu.hidden)
|
|
266
|
+
ctx.navPause(menu, pi, k);
|
|
376
267
|
}
|
|
377
|
-
|
|
378
|
-
function
|
|
379
|
-
if (!
|
|
268
|
+
/** Assignment BY ORDER OF ACTION: any button binds -> the 1st pad to act -> the 1st player without a pad. */
|
|
269
|
+
function takeSeat(f) {
|
|
270
|
+
if (!f.startEdge && !PAD_POSITIONS.some((k) => f.edge(k)))
|
|
380
271
|
return;
|
|
381
|
-
|
|
382
|
-
const
|
|
383
|
-
if (
|
|
384
|
-
|
|
385
|
-
if (gp && gp.buttons.some((b) => b && b.pressed)) {
|
|
386
|
-
padWiz.gi = gp.index;
|
|
387
|
-
padWiz.id = gp.id;
|
|
388
|
-
padWiz.baseWait = true;
|
|
389
|
-
wizSay(t('pad.wiz.releaseAll', { id: gp.id }));
|
|
390
|
-
break;
|
|
391
|
-
}
|
|
392
|
-
}
|
|
272
|
+
const waitI = f.players.findIndex((p) => p && p.waiting);
|
|
273
|
+
const free = waitI >= 0 ? waitI : f.players.findIndex((p) => p && p.pad < 0 && !p.quit);
|
|
274
|
+
if (free < 0) {
|
|
275
|
+
ctx.joinPlayer(f.gi);
|
|
393
276
|
return;
|
|
394
277
|
}
|
|
395
|
-
const
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
278
|
+
const seated = f.players[free];
|
|
279
|
+
seated.pad = f.gi;
|
|
280
|
+
if (seated.waiting) {
|
|
281
|
+
seated.waiting = false;
|
|
282
|
+
ctx.clearWaitingBadge(free);
|
|
283
|
+
}
|
|
284
|
+
ctx.srSay(t('sr.pad.assigned', { n: free + 1 }));
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* THE HALF OF THE SINGLE DOOR THAT PRESSES (ADR-0223): every position that WENT DOWN this frame goes to the virtual
|
|
288
|
+
* controller, stamped `gamepad` with this pad's seat. Returns the ones that reached the GAME — the controller's
|
|
289
|
+
* answer, which is what tells a game press from one a menu took.
|
|
290
|
+
*
|
|
291
|
+
* ⚠️ The EIGHT positions and not the six with an edge: those with an edge are a subset (`EDGE_BY_ACTION`), and up and
|
|
292
|
+
* down always travelled as held keys. All eight reach the cartridge.
|
|
293
|
+
*/
|
|
294
|
+
function pressWhatWentDown(f) {
|
|
295
|
+
const reached = new Set();
|
|
296
|
+
for (const act of PAD_POSITIONS)
|
|
297
|
+
if (f.edge(act) && ctx.press(act, 'gamepad', f.owner))
|
|
298
|
+
reached.add(act);
|
|
299
|
+
return reached;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* THE HALF THAT RELEASES, and it is UNCONDITIONAL on purpose (ADR-0223). A press is only born in the PLAY branch, but
|
|
303
|
+
* the finger leaves the button wherever it likes — a child who opens the pause with jump held would leave the key held
|
|
304
|
+
* forever if the release depended on the branch. The controller ignores the release of a press the game never heard,
|
|
305
|
+
* which is exactly the memory it exists to have.
|
|
306
|
+
*
|
|
307
|
+
* 📌 The pad is the only transport that reads STATE per frame instead of receiving events, so the release never
|
|
308
|
+
* arrives to it: it is computed against the previous frame.
|
|
309
|
+
*/
|
|
310
|
+
function releaseWhatCameUp(f) {
|
|
311
|
+
if (f.owner < 0)
|
|
312
|
+
return; // a pad with no seat never pressed anything
|
|
313
|
+
for (const act of PAD_POSITIONS)
|
|
314
|
+
if (f.released(act))
|
|
315
|
+
ctx.release(act, 'gamepad', f.owner);
|
|
316
|
+
}
|
|
317
|
+
/** The real game: START pauses, the modal eats the d-pad, and the rest becomes an action flag. */
|
|
318
|
+
function playRound(f, p) {
|
|
319
|
+
// START IS PRESSED FOR THIS PAD'S SEAT, as SELECT is: the virtual controller hands it to the engine (`systemPress`), which
|
|
320
|
+
// answers it as that seat's START key — its own quick pause, and START again leaves it (ADR-0155, ADR-0144 §1 and its
|
|
321
|
+
// erratum of 2026-09-26). A seatless `pause()` here froze seat 0's quick pause whoever pressed.
|
|
322
|
+
if (f.pauseEdge) {
|
|
323
|
+
ctx.press('start', 'gamepad', f.owner);
|
|
324
|
+
ctx.setPauseActor(f.owner);
|
|
405
325
|
return;
|
|
406
326
|
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
const
|
|
410
|
-
if (
|
|
411
|
-
|
|
412
|
-
wizPrompt();
|
|
413
|
-
}
|
|
327
|
+
if (ctx.hasModal(f.owner)) { // the pad navigates the player's OWN modal (the others' game goes on)
|
|
328
|
+
// What left this module is the MEANING — the grid's ±1/±3 and the Braille detour, which are the game's decision.
|
|
329
|
+
const hit = MODAL_BY_POSITION.find(([position]) => f.edge(position));
|
|
330
|
+
if (hit)
|
|
331
|
+
ctx.modalInput(f.owner, hit[1]);
|
|
414
332
|
return;
|
|
415
333
|
}
|
|
416
|
-
//
|
|
417
|
-
//
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
if (
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
334
|
+
// The table and the Easy guard come from input/edges.ts, the SAME ones keydown and touch use — three hand-written
|
|
335
|
+
// copies had already drifted once (the touch one forgot `!p.easy`).
|
|
336
|
+
// 🔴 THE SINGLE DOOR FIRST (ADR-0223): the position goes to the virtual controller, which holds the child's key
|
|
337
|
+
// stamped `gamepad` and delivers the command to the cartridge. Only then is an edge raised — and only for a press
|
|
338
|
+
// that REACHED the game, which is the controller's answer.
|
|
339
|
+
const reachedPlay = pressWhatWentDown(f);
|
|
340
|
+
let hasAnyEdge = false;
|
|
341
|
+
for (const [act, flag] of EDGE_BY_ACTION) {
|
|
342
|
+
if (!reachedPlay.has(act))
|
|
343
|
+
continue;
|
|
344
|
+
hasAnyEdge = true;
|
|
345
|
+
if (edgeAllowed(act, p.easy))
|
|
346
|
+
p[flag] = true;
|
|
347
|
+
}
|
|
348
|
+
// 📌 THE PAD'S EDGE, and it counts EVEN WHEN EASY FILTERS IT (ADR-0113 clause 4): the child pressed the button —
|
|
349
|
+
// that the Easy Mode rule does not raise the game's flag does not change the fact that this is the device in use.
|
|
350
|
+
// Reading the same condition as `p[flag]` would leave a child in Easy Mode with the keyboard's latch while playing
|
|
351
|
+
// on the pad.
|
|
352
|
+
// ⚠️ AND IT IS HERE, in the PLAY branch, not the menu ones: `onBar`, the title and the pause are navigation, and the
|
|
353
|
+
// question this feeds — which latch holds NOW — is about playing.
|
|
354
|
+
if (hasAnyEdge)
|
|
355
|
+
ctx.playerEdge(f.owner, 'gamepad');
|
|
356
|
+
}
|
|
357
|
+
/** With the world moving: the quick bar first, then the seat, the abandoned screen, and finally the game. */
|
|
358
|
+
function steerGame(f) {
|
|
359
|
+
// ===================== THE `accessibility` MODE (ADR-0044, item 7) =====================
|
|
360
|
+
// With the game RUNNING, this player's d-pad steers the QUICK BAR and not the character. It comes before everything
|
|
361
|
+
// that is the game's, because while the mode is on nothing else from this pad is the game's.
|
|
362
|
+
//
|
|
363
|
+
// Both exits arrive together: `especial` (action 3) is the project's BACK — the east button: B on Xbox, ◯ on
|
|
364
|
+
// PlayStation, A on Nintendo — and `pauseEdge` is the button that opens the pause, where this was entered. A child
|
|
365
|
+
// who is lost goes back the way they came, one who knows the game tries the usual back; both work.
|
|
366
|
+
// ⚠️ START ALONE, not `startEdge`: that one fires on action 2 too («close a dialog»), and passed here it made the confirm
|
|
367
|
+
// LEAVE the bar instead of pressing the icon under the cursor.
|
|
368
|
+
if (f.owner >= 0 && ctx.onBar(f.owner)) {
|
|
369
|
+
const k = f.navKeys();
|
|
370
|
+
if (f.pauseEdge || anyIntent(k))
|
|
371
|
+
ctx.navBar(f.owner, k, f.pauseEdge);
|
|
431
372
|
return;
|
|
432
373
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
return;
|
|
437
|
-
}
|
|
374
|
+
if (f.owner < 0) {
|
|
375
|
+
takeSeat(f);
|
|
376
|
+
return;
|
|
438
377
|
}
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
if (
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
378
|
+
const p = f.players[f.owner];
|
|
379
|
+
if (p.quit) {
|
|
380
|
+
if (f.startEdge)
|
|
381
|
+
ctx.respawnPlayer(f.owner);
|
|
382
|
+
return;
|
|
383
|
+
} // abandoned screen -> restart ONLY it
|
|
384
|
+
playRound(f, p);
|
|
385
|
+
}
|
|
386
|
+
/** In the demonstration, a pad button ends the demo — and the frame ends here, button or not. */
|
|
387
|
+
function attractTook(pads) {
|
|
388
|
+
if (!ctx.isAttractActive())
|
|
389
|
+
return false;
|
|
390
|
+
if (pads.some((gp) => gp && gp.buttons.some((b) => b && b.pressed)))
|
|
391
|
+
ctx.stopAttract();
|
|
392
|
+
return true;
|
|
393
|
+
}
|
|
394
|
+
/** Did a button go down on this frame — any position, START or SELECT? A button held is one press, not one a frame. */
|
|
395
|
+
const wentDown = (f) => f.startEdge || f.pauseEdge || f.selectEdge || PAD_POSITIONS.some((k) => f.edge(k));
|
|
396
|
+
/** A physical button used -> the on-screen pad goes away (the keyboard's rule): any of the nine positions read. */
|
|
397
|
+
function hideTouchPadIfHeld(f) {
|
|
398
|
+
if (ctx.isTouchMode() && (f.cur._start || PAD_POSITIONS.some((k) => f.cur[k])))
|
|
399
|
+
ctx.hideTouchControls();
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Where this frame goes. The destinations ask for the facts, not a PHASE. The pause wins over a world running beneath
|
|
403
|
+
* it, and the title is derived by exclusion on purpose: in a scene this module does not know (a map, a results
|
|
404
|
+
* screen), the pad should navigate as on the title — the safe behaviour — instead of doing nothing.
|
|
405
|
+
*/
|
|
406
|
+
function steerFrame(f) {
|
|
407
|
+
// SELECT OPENS THE MENUS wherever the keyboard's F does — in play and in the quick pause (ADR-0155) — and it is PRESSED,
|
|
408
|
+
// not decided here: the virtual controller hands the position to the engine, which answers it as F (ADR-0144 §1). An open
|
|
409
|
+
// card or panel refuses it there. A pad nobody has seated yet is seat 0's, as on the pause card below.
|
|
410
|
+
if (f.selectEdge) {
|
|
411
|
+
ctx.press('select', 'gamepad', f.owner < 0 ? 0 : f.owner);
|
|
412
|
+
return;
|
|
445
413
|
}
|
|
414
|
+
if (ctx.pauseMenu())
|
|
415
|
+
steerPause(f);
|
|
416
|
+
else if (ctx.worldRunning())
|
|
417
|
+
steerGame(f);
|
|
418
|
+
else
|
|
419
|
+
steerTitle(f);
|
|
446
420
|
}
|
|
447
|
-
const cancelBtn = ctx.$('#padwiz-cancel');
|
|
448
|
-
if (cancelBtn)
|
|
449
|
-
cancelBtn.addEventListener('click', () => closePadWiz(false));
|
|
450
|
-
// ----- poll (chamado a cada frame do loop) -----
|
|
451
421
|
function pollPads() {
|
|
452
|
-
if (
|
|
453
|
-
return; //
|
|
422
|
+
if (wizard.state())
|
|
423
|
+
return; // during the wizard, the pads talk only to it
|
|
454
424
|
const pads = ctx.getGamepads();
|
|
455
|
-
if (!pads)
|
|
456
|
-
return;
|
|
457
|
-
if (ctx.isAttractActive()) {
|
|
458
|
-
for (const gp of pads) {
|
|
459
|
-
if (gp && gp.buttons.some((b) => b && b.pressed)) {
|
|
460
|
-
ctx.stopAttract();
|
|
461
|
-
return;
|
|
462
|
-
}
|
|
463
|
-
} // botão de pad encerra a demo
|
|
425
|
+
if (!pads || attractTook(pads))
|
|
464
426
|
return;
|
|
465
|
-
}
|
|
466
427
|
for (const gp of pads) {
|
|
467
428
|
if (!gp)
|
|
468
429
|
continue;
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
if (gp.mapping !== 'standard' && !padMapFor(gp.id) && gp.buttons.some((b) => b && b.pressed)) {
|
|
472
|
-
padWizAutoResume = ctx.mundoRodando();
|
|
473
|
-
if (ctx.mundoRodando())
|
|
474
|
-
ctx.pausar();
|
|
475
|
-
openPadWizFor(gp);
|
|
430
|
+
// a non-standard (DirectInput) pad with NO saved map pressed something -> pause everything + the wizard directly
|
|
431
|
+
if (wizardTookOver(gp))
|
|
476
432
|
return;
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
//
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
// arestas na tela do título, e um mapa vazio ali deixaria a criança sem como escolher o próprio jogo.
|
|
487
|
-
// A EMPATIA MOTORA APLICADA AO CONTROLE (issue #120). Sem esta linha, uma criança com o modo de
|
|
488
|
-
// um botão ligado e um pad na mão NÃO ESTAVA no modo — e nada em lado nenhum o dizia.
|
|
489
|
-
const cur = umBotaoPorVez(prev, actionsFor(gp, tabelaDoPad(ctx.getNumPlayers(), owner < 0 ? 0 : owner)), estadoDoJogo.oneButton);
|
|
490
|
-
if (ctx.isTouchMode() && (cur.left || cur.right || cur.up || cur.down || cur.action2 || cur.action1 || cur.action4 || cur.action3 || cur._start)) {
|
|
491
|
-
ctx.hideTouchControls(); // botão físico usado -> some o gamepad virtual (mesma regra do teclado)
|
|
492
|
-
}
|
|
493
|
-
const startEdge = cur._start && !padPrevStart[gi];
|
|
494
|
-
padPrevStart[gi] = cur._start;
|
|
495
|
-
const pauseEdge = cur._pause && !prev._pause;
|
|
496
|
-
const edge = (k) => cur[k] && !prev[k];
|
|
497
|
-
padCur[gi] = cur;
|
|
498
|
-
padPrevAct[gi] = cur;
|
|
499
|
-
const winOv = ctx.$('#win-overlay');
|
|
500
|
-
if (winOv && !winOv.hidden) { // Vitória: START/pulo fecham o modal (Jogar de novo)
|
|
501
|
-
if (startEdge) {
|
|
502
|
-
const b = ctx.$('#btn-again');
|
|
503
|
-
if (b)
|
|
504
|
-
b.click();
|
|
505
|
-
}
|
|
506
|
-
continue;
|
|
507
|
-
}
|
|
508
|
-
// Os três ramos abaixo pediam a FASE; hoje pedem os fatos. O `telaDeTitulo` é derivado por exclusão
|
|
509
|
-
// de propósito: numa cena que este módulo não conheça (um mapa, uma tela de resultados), o controle
|
|
510
|
-
// deve navegar como no título — que é o comportamento seguro — em vez de não fazer nada.
|
|
511
|
-
const rodando = ctx.mundoRodando(), pausado = ctx.menuDePausa();
|
|
512
|
-
if (!rodando && !pausado) {
|
|
513
|
-
const k = { yes: edge('action2') || startEdge, no: edge('action3'), up: edge('up'), down: edge('down'), left: edge('left'), right: edge('right') };
|
|
514
|
-
const any = k.yes || k.no || k.up || k.down || k.left || k.right;
|
|
515
|
-
if (ctx.getNumPlayers() > 1 && owner > 0) {
|
|
516
|
-
if (any)
|
|
517
|
-
ctx.srSay(t('sr.title.waitP1'));
|
|
518
|
-
continue;
|
|
519
|
-
} // só o J1 escolhe
|
|
520
|
-
if (any)
|
|
521
|
-
ctx.navTitle(k); // menu inicial navegável pelo pad
|
|
522
|
-
continue;
|
|
523
|
-
}
|
|
524
|
-
if (pausado) {
|
|
525
|
-
const pi = owner < 0 ? 0 : owner;
|
|
526
|
-
if (pauseEdge) {
|
|
527
|
-
ctx.retomar();
|
|
528
|
-
continue;
|
|
529
|
-
} // START retoma
|
|
530
|
-
const k = { yes: edge('action2'), no: edge('action3'), up: edge('up'), down: edge('down'), left: edge('left'), right: edge('right') };
|
|
531
|
-
if (k.yes || k.no || k.up || k.down || k.left || k.right) {
|
|
532
|
-
const dlg = ctx.sharedDialogOpen();
|
|
533
|
-
if (dlg)
|
|
534
|
-
ctx.navDialog(dlg, k);
|
|
535
|
-
else {
|
|
536
|
-
const menu = ctx.getPauseMenu(pi);
|
|
537
|
-
if (menu && !menu.hidden)
|
|
538
|
-
ctx.navPause(menu, pi, k);
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
continue;
|
|
542
|
-
}
|
|
543
|
-
if (rodando) {
|
|
544
|
-
// ===================== O MODO `accessibility` (ADR-0044, item 7) =====================
|
|
545
|
-
// Com o jogo ANDANDO, o direcional deste jogador dirige a BARRA RÁPIDA e não o personagem. Vem antes
|
|
546
|
-
// de tudo o que é de jogo, porque enquanto o modo está ligado nada mais deste controle é de jogo.
|
|
547
|
-
//
|
|
548
|
-
// As DUAS saídas chegam juntas: `especial` é o VOLTAR do projeto (X no PlayStation, B no Xbox, A no
|
|
549
|
-
// Nintendo) e `startEdge` é o botão que abre a pausa — de onde se entrou aqui. Quem se perde tenta
|
|
550
|
-
// voltar por onde veio, e quem já conhece o jogo tenta o voltar de sempre; as duas dão certo.
|
|
551
|
-
if (owner >= 0 && ctx.naBarraDe(owner)) {
|
|
552
|
-
const k = { yes: edge('action2'), no: edge('action3'), up: edge('up'), down: edge('down'), left: edge('left'), right: edge('right') };
|
|
553
|
-
if (startEdge || k.yes || k.no || k.up || k.down || k.left || k.right)
|
|
554
|
-
ctx.navBar(owner, k, !!startEdge);
|
|
555
|
-
continue;
|
|
556
|
-
}
|
|
557
|
-
if (owner < 0) { // atribuição POR ORDEM DE AÇÃO: qualquer botão associa -> 1º controle a agir -> 1º jogador sem pad
|
|
558
|
-
const anyEdge = edge('action2') || edge('action1') || edge('action4') || edge('action3') || startEdge || edge('left') || edge('right') || edge('up') || edge('down');
|
|
559
|
-
if (anyEdge) {
|
|
560
|
-
const waitI = players.findIndex((p) => p && p.waiting);
|
|
561
|
-
const free = waitI >= 0 ? waitI : players.findIndex((p) => p && p.pad < 0 && !p.quit);
|
|
562
|
-
if (free >= 0) {
|
|
563
|
-
players[free].pad = gi;
|
|
564
|
-
if (players[free].waiting) {
|
|
565
|
-
players[free].waiting = false;
|
|
566
|
-
ctx.clearWaitingBadge(free);
|
|
567
|
-
}
|
|
568
|
-
ctx.srSay(t('sr.pad.assigned', { n: free + 1 }));
|
|
569
|
-
}
|
|
570
|
-
else {
|
|
571
|
-
ctx.joinPlayer(gi);
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
else if (players[owner].quit) {
|
|
576
|
-
if (startEdge)
|
|
577
|
-
ctx.respawnPlayer(owner); // tela abandonada -> recomeça SÓ ela
|
|
578
|
-
}
|
|
579
|
-
else {
|
|
580
|
-
const p = players[owner];
|
|
581
|
-
if (pauseEdge) {
|
|
582
|
-
ctx.pausar();
|
|
583
|
-
ctx.setPauseActor(owner);
|
|
584
|
-
continue;
|
|
585
|
-
} // START pausa (todos pausam; cada tela navega a sua)
|
|
586
|
-
if (ctx.hasModal(owner)) { // o pad navega o modal do PRÓPRIO jogador (o jogo dos outros segue)
|
|
587
|
-
// A ORDEM é a do original: esquerda, direita, cima, baixo, confirmar, apagar. O que saiu foi o
|
|
588
|
-
// SIGNIFICADO — o ±1/±3 da grade e o desvio de Braille, que agora são decisão do jogo.
|
|
589
|
-
const intent = edge('left') ? 'left' : edge('right') ? 'right'
|
|
590
|
-
: edge('up') ? 'up' : edge('down') ? 'down'
|
|
591
|
-
: edge('action2') ? 'confirm' : edge('action3') ? 'erase' : null;
|
|
592
|
-
if (intent)
|
|
593
|
-
ctx.modalInput(owner, intent);
|
|
594
|
-
continue;
|
|
595
|
-
}
|
|
596
|
-
// A tabela e a guarda do Fácil vêm de input/edges.ts, as MESMAS que keydown e touch usam. Antes eram
|
|
597
|
-
// seis `if` à mão aqui, seis lá e seis no toque — e o do toque tinha esquecido o `!p.easy`.
|
|
598
|
-
let algumaAresta = false;
|
|
599
|
-
for (const [act, flag] of EDGE_BY_ACTION) {
|
|
600
|
-
if (edge(act))
|
|
601
|
-
algumaAresta = true;
|
|
602
|
-
if (edgeAllowed(act, p.easy) && edge(act))
|
|
603
|
-
p[flag] = true;
|
|
604
|
-
}
|
|
605
|
-
// 📌 A ARESTA DO CONTROLE, e ela conta MESMO QUANDO O FÁCIL A FILTRA (ADR-0113 cláusula 4): a
|
|
606
|
-
// criança carregou no botão — que a regra do Modo Fácil não levante a bandeira do jogo não muda
|
|
607
|
-
// o facto de o aparelho em uso ser este. Ler a mesma condição do `p[flag]` faria uma criança em
|
|
608
|
-
// Modo Fácil ficar com a alternância do teclado enquanto joga no controle.
|
|
609
|
-
// ⚠️ E É AQUI, no ramo de JOGO, e não nos de menu: `naBarraDe`, o título e a pausa são navegação, e
|
|
610
|
-
// a pergunta que isto alimenta — que alternância vale AGORA — é sobre jogar.
|
|
611
|
-
if (algumaAresta)
|
|
612
|
-
ctx.arestaDoJogador(owner, 'gamepad');
|
|
613
|
-
}
|
|
614
|
-
}
|
|
433
|
+
// ⚠️ `getPlayers()` IS READ HERE, once per pad, and not once before the loop: the seat branch WRITES into the list
|
|
434
|
+
// (`players[free].pad = gi`), and reading it only once would change what the next pad sees.
|
|
435
|
+
const f = readPad(gp, ctx.getPlayers());
|
|
436
|
+
releaseWhatCameUp(f); // before every branch: the finger leaves the button wherever it likes (ADR-0223)
|
|
437
|
+
hideTouchPadIfHeld(f);
|
|
438
|
+
if (wentDown(f) && ctx.takeShown?.())
|
|
439
|
+
continue; // one button only: the button is the switch (ADR-0218 §4)
|
|
440
|
+
if (!winOverlayTook(f))
|
|
441
|
+
steerFrame(f);
|
|
615
442
|
}
|
|
616
443
|
}
|
|
617
|
-
return { pollPads, openPadWiz, openPadWizFor, closePadWiz, padWizTick, padMapFor, getPadWiz: () =>
|
|
444
|
+
return { pollPads, openPadWiz, openPadWizFor, closePadWiz, padWizTick, padMapFor, getPadWiz: () => wizard.state() };
|
|
618
445
|
}
|