@@ -9,7 +9,23 @@ steps:
|
|||||||
commands:
|
commands:
|
||||||
- npm ci
|
- npm ci
|
||||||
- npm run test
|
- npm run test
|
||||||
- npm run build
|
- PUBLIC_GLITCHTIP_RELEASE=$CI_PIPELINE_NUMBER npm run build
|
||||||
|
|
||||||
|
- name: upload-sourcemaps
|
||||||
|
image: rust:1
|
||||||
|
environment:
|
||||||
|
SENTRY_URL:
|
||||||
|
from_secret: glitchtip_url
|
||||||
|
SENTRY_AUTH_TOKEN:
|
||||||
|
from_secret: glitchtip_auth_token
|
||||||
|
SENTRY_ORG:
|
||||||
|
from_secret: glitchtip_org
|
||||||
|
SENTRY_PROJECT:
|
||||||
|
from_secret: glitchtip_project
|
||||||
|
commands:
|
||||||
|
- cargo install --locked --git https://gitlab.com/glitchtip/glitchtip-cli.git
|
||||||
|
- glitchtip-cli sourcemaps inject ./dist
|
||||||
|
- glitchtip-cli sourcemaps upload ./dist --release "$CI_PIPELINE_NUMBER"
|
||||||
|
|
||||||
- name: deploy
|
- name: deploy
|
||||||
image: node:22
|
image: node:22
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ Played at [halfstreet.io](https://halfstreet.io).
|
|||||||
- TypeScript engine — pure (no DOM, `Date`, `Math.random`, or console)
|
- TypeScript engine — pure (no DOM, `Date`, `Math.random`, or console)
|
||||||
- World content authored in markdown (rooms, items, encounters, endings) under `src/world/`
|
- World content authored in markdown (rooms, items, encounters, endings) under `src/world/`
|
||||||
- [Vitest](https://vitest.dev) for tests
|
- [Vitest](https://vitest.dev) for tests
|
||||||
|
- Optional client error reporting via [GlitchTip](https://glitchtip.com) using `PUBLIC_GLITCHTIP_DSN`
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
@@ -22,6 +23,9 @@ npm run dev # local dev server
|
|||||||
npm run build # type-check + production build
|
npm run build # type-check + production build
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To enable GlitchTip in the browser, set `PUBLIC_GLITCHTIP_DSN` in your environment before running or building the site.
|
||||||
|
If you want deploy-aware grouping and readable stack traces, also set `PUBLIC_GLITCHTIP_RELEASE` at build time and upload the generated source maps for that same release.
|
||||||
|
|
||||||
## Layout
|
## Layout
|
||||||
|
|
||||||
- `src/engine/` — parser, dispatcher, encounter logic
|
- `src/engine/` — parser, dispatcher, encounter logic
|
||||||
|
|||||||
@@ -6,4 +6,9 @@ export default defineConfig({
|
|||||||
build: {
|
build: {
|
||||||
inlineStylesheets: 'auto',
|
inlineStylesheets: 'auto',
|
||||||
},
|
},
|
||||||
|
vite: {
|
||||||
|
build: {
|
||||||
|
sourcemap: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"license": "GPL-3.0-or-later",
|
"license": "GPL-3.0-or-later",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@sentry/browser": "^10.52.0",
|
||||||
"astro": "^6.1.9",
|
"astro": "^6.1.9",
|
||||||
"yaml": "^2.8.4",
|
"yaml": "^2.8.4",
|
||||||
"zod": "^4.4.3"
|
"zod": "^4.4.3"
|
||||||
@@ -1766,6 +1767,81 @@
|
|||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/@sentry-internal/browser-utils": {
|
||||||
|
"version": "10.52.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-10.52.0.tgz",
|
||||||
|
"integrity": "sha512-x/yEPZdpH6NGQeoeQnV9tj8reAH8twNttiltGZl2o8Rk7sQeUfe7E8yuYP2XbJ2RqyZK5qRS3COrNyMPzf6KFA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/core": "10.52.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry-internal/feedback": {
|
||||||
|
"version": "10.52.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-10.52.0.tgz",
|
||||||
|
"integrity": "sha512-5kAn1W8ZvCuHtEHXpq6iRkUMdNCilwww+YxaN2yofVrCivAbB3Ha5JJUMqmWOPW0pC27zGYmoJMIDvG+PczUxA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/core": "10.52.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry-internal/replay": {
|
||||||
|
"version": "10.52.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-10.52.0.tgz",
|
||||||
|
"integrity": "sha512-diywyuc/H7VTUR+W5ryVmLF+0X4UP1OskMqb6V8RSAvJHcj2JmIm7uP+Fc6ACTno+b6AUShwT/L4xVXzO6X9Cw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry-internal/browser-utils": "10.52.0",
|
||||||
|
"@sentry/core": "10.52.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry-internal/replay-canvas": {
|
||||||
|
"version": "10.52.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-10.52.0.tgz",
|
||||||
|
"integrity": "sha512-BI5ie4dxPuUJ344CXVSnAxY1xZCbghglPSCIlTOYODpR9so9yo5IZh+Mwspt0oWsUMaxWJiQSNYlbPWi7WDavg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry-internal/replay": "10.52.0",
|
||||||
|
"@sentry/core": "10.52.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/browser": {
|
||||||
|
"version": "10.52.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-10.52.0.tgz",
|
||||||
|
"integrity": "sha512-ijL9jN86oXwXQWbwhPlEb70ODJSEmjxQEQdnZkC4gDWbjswcwvRsVJPYk+1xl2ir2iZixRIHipVxDcLwian35g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry-internal/browser-utils": "10.52.0",
|
||||||
|
"@sentry-internal/feedback": "10.52.0",
|
||||||
|
"@sentry-internal/replay": "10.52.0",
|
||||||
|
"@sentry-internal/replay-canvas": "10.52.0",
|
||||||
|
"@sentry/core": "10.52.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/core": {
|
||||||
|
"version": "10.52.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.52.0.tgz",
|
||||||
|
"integrity": "sha512-VA/kAqLhkMnRWY2RXdBLyTemR9D4m7MVRy/gyapoq9yvllVPx9WXbvKgnMP2LQp7mFgT/oLFvw58aQKaYTGn3A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@shikijs/core": {
|
"node_modules/@shikijs/core": {
|
||||||
"version": "4.0.2",
|
"version": "4.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.0.2.tgz",
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
"test:watch": "vitest"
|
"test:watch": "vitest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@sentry/browser": "^10.52.0",
|
||||||
"astro": "^6.1.9",
|
"astro": "^6.1.9",
|
||||||
"yaml": "^2.8.4",
|
"yaml": "^2.8.4",
|
||||||
"zod": "^4.4.3"
|
"zod": "^4.4.3"
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="1200pt" height="1200pt" version="1.1" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m1065.9 452.47v-64.941h66.352v-304.94h67.766v-62.824h-78.352v54.352h-96v75.531h-105.88v105.18h-118.59v62.824h-60.707v64.941h-57.883v56.469h-76.234v108.71h-59.293v172.94h-53.648v-241.41h-52.941v-92.469h-49.41v-53.648h49.41v-67.059h97.41v-112.23h-67.059v45.176h-94.59v55.059h-48v62.824l-194.82-0.003906v-62.824h-66.352v-100.23h-67.059v112.23h54.352v67.059h51.531v53.648h-66.352v153.18h50.117v63.531h-50.117v127.77h53.648v56.469h166.59v-56.469h60.707v-60h107.29v146.12h-156v276h-17.648v86.824h280.23v-164.47h149.65v49.41h56.469v39.531h-59.293v75.531h139.77v-71.293h59.293v-93.176h45.176v93.176h67.059v71.293h176.47v-83.293h-113.65v-117.88h-62.824v-52.234h-59.293v-67.059h-60v-42.352h-121.41v-41.648h182.12v-67.059h-182.12v-45.176h280.23v-67.059h-230.12v-45.176h230.12v-50.117h-153.88v-48.707h188.47zm-750.35 151.06h-113.65v-63.531h113.65zm106.59 496.94h-40.234v-97.41h40.234z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="1200pt" height="1200pt" version="1.1" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m1200 431.4v-157.8h-77.398v49.199h-750v-49.199h-106.8v49.199h53.398v24.602h53.398v39.602h-54v13.801h-60.602v52.801h-81v60h-61.199v52.801h-57.602v85.199h-57.602v274.8h265.8v-254.4h57.602v-45h67.199v105.6h54v-105.6h43.199v67.801h54v-70.199h43.199v108h54v-64.801h54v-72h114.6v-70.199h237v-49.199h-234v-45.602h390.6zm-502.8-1.8008v96.602h-237v-121.8h237z"/>
|
||||||
|
<path d="m506.4 443.4h147v49.199h-147z"/>
|
||||||
|
<path d="m444.6 732.6h139.8v48.602h-139.8z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 610 B |
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="1200pt" height="1200pt" version="1.1" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m770.13 1200v-116.11h-69.797v-100.67h-67.785v100.67h-72.484v-100.67h-67.785v100.67h-69.797v116.11z"/>
|
||||||
|
<path d="m284.9 903.36h137.58v180.54h-137.58z"/>
|
||||||
|
<path d="m770.13 903.36h137.58v180.54h-137.58z"/>
|
||||||
|
<path d="m667.45 910.74v-132.89h206.04v-176.51h-226.17v176.51h-95.973v-176.51h-226.18v176.51h204.7v132.89z"/>
|
||||||
|
<path d="m915.1 232.21v-116.11h-144.97v-116.11h-340.27v116.11h-144.97v116.11h-116.11v671.14h116.11v-555.04h116.11v-116.11h397.98v116.11h116.11v555.04h116.11v-671.14z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 650 B |
|
After Width: | Height: | Size: 8.4 KiB |
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="1200pt" height="1200pt" version="1.1" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m473.64 170.52h50.52v50.52h-50.52z"/>
|
||||||
|
<path d="m574.68 170.52h50.52v50.52h-50.52z"/>
|
||||||
|
<path d="m473.64 221.04h-50.52v101.04h50.52z"/>
|
||||||
|
<path d="m625.2 322.08h50.641v-101.04h-50.641z"/>
|
||||||
|
<path d="m524.16 473.64h151.68v-50.52h-101.04v-50.52h50.398v-50.523h-151.56v50.523h50.52v50.52h-101.04v50.52z"/>
|
||||||
|
<path d="m524.16 120h50.52v50.52h-50.52z"/>
|
||||||
|
<path d="m574.8 625.2v50.641h50.398v-101.04h-50.398z"/>
|
||||||
|
<path d="m877.92 928.44h-151.56v-454.8h-50.52v50.52h-50.641v50.641h50.641v353.64h-252.72v-353.64h50.52v-50.641h-50.52v-50.52h-50.52v454.8h-151.56v50.52h50.52v50.52h50.52v-50.52h505.32v50.52h50.523z"/>
|
||||||
|
<path d="m524.16 524.16h50.52v50.52h-50.52z"/>
|
||||||
|
<path d="m473.64 574.68h50.52v50.52h-50.52z"/>
|
||||||
|
<path d="m877.92 827.4h-50.523v50.523h101.04v-50.523z"/>
|
||||||
|
<path d="m928.44 928.44v101.04h50.52v-151.56h-50.52z"/>
|
||||||
|
<path d="m726.36 1029.5h-404.28v50.52h505.32v-50.52z"/>
|
||||||
|
<path d="m877.92 1029.5h50.52v50.52h-50.52z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="1200pt" height="1200pt" version="1.1" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m536.04 152.04h63.961v63.961h-63.961z"/>
|
||||||
|
<path d="m792 152.04h63.961v63.961h-63.961z"/>
|
||||||
|
<path d="m663.96 279.96v-63.961h-63.961v128.04h63.961z"/>
|
||||||
|
<path d="m600 408v-63.961h-128.04v63.961z"/>
|
||||||
|
<path d="m855.96 408v-63.961h-127.92v63.961z"/>
|
||||||
|
<path d="m408 408h63.961v63.961h-63.961z"/>
|
||||||
|
<path d="m663.96 408h63.961v63.961h-63.961z"/>
|
||||||
|
<path d="m920.04 279.96v-63.961h-64.078v128.04h64.078z"/>
|
||||||
|
<path d="m152.04 600h127.92v128.04h-127.92v63.961h192v63.961h63.961v64.078h-63.961v63.961h639.96v-63.961h-63.961v-64.078h63.961v-63.961h63.961v-255.96h-895.92zm639.96 192h63.961v-128.04h64.078v128.04h-64.078v63.961h-63.961z"/>
|
||||||
|
<path d="m87.961 663.96v64.078h64.078v-128.04h-64.078z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 848 B |
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="1200pt" height="1200pt" version="1.1" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m684.72 854.16h-282.36v56.398h395.28v-56.398z"/>
|
||||||
|
<path d="m684.72 684.72h-282.36v56.52h395.28v-56.52z"/>
|
||||||
|
<path d="m571.8 515.28h-169.44v56.52h395.28v-56.52z"/>
|
||||||
|
<path d="m684.72 120h-451.8v960h734.16v-734.16h-56.52v-56.398h-56.398v-56.52h-56.52v-56.398l-56.52-0.003907v-56.52zm0 112.92v169.44h225.84v621.12h-621.12v-846.96h395.28z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 502 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="1200pt" height="1200pt" version="1.1" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m1100 274.87v-50.016h-49.969v50.016h-550.08v-50.016h-199.97v50.016h-150v50.016h-49.969v150.05h49.969v100.03h-49.969v100.03h-49.969v100.03l-50.062 0.09375v150.05h49.969v50.016h300v-50.016h-49.969v-200.06h49.969v-50.016h199.97v-50.016h-150v-100.03h49.969v50.016h49.969v-100.03h49.969v150.05h49.969v-150.05h600l0.09375-200.16h-100.03zm-900.05 600.24h-49.969v50.016h-49.969v-50.016h-49.969v-50.016h49.969v-50.016h49.969v50.016h49.969zm450.05-450.19h-49.969v-50.016h49.969zm99.984 0h-49.969v-50.016h49.969zm100.03 0h-49.969v-50.016h49.969zm99.984 0h-49.969v-50.016h49.969zm99.984 0h-49.969v-50.016h49.969zm100.03 0h-49.969v-50.016h49.969z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 803 B |
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="1200pt" height="1200pt" version="1.1" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m862.4 1125v-224.95h-74.953v-75l-374.9-0.046875v75h-74.953v224.95h74.953v75h374.86v-75h74.953zm-374.81-75v-150h224.9v150z"/>
|
||||||
|
<path d="m487.6 0v75h-150v75h74.953v75l-74.953 0.046875v75h149.95v75h-149.95v75h149.95v300h149.95l0.046875-750.05z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 410 B |
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="1200pt" height="1200pt" version="1.1" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m555 120-30 30 30 30-30 30 30 30-30 30 30 30-30 30 30 30-30 30 30 30-30 30 30 30-30 30 30 30-30 30 30 30-30 30 30 30-30 30 30 30-30 30 30 30-30 30-30-30c-9.9375 9.9844-19.969 19.969-29.953 30l30 30-30 30 30 30-30 30 30 30-30 30 30 30-30 30 30 30-30 30 30 30-30 30 30 30c30-30 59.953-60 89.953-90l-30-30 30-30-30-30 30-30-30-30 30-30-30-30 30-30-30-30 30-30 30 30 30-30 30 30c20.016-20.016 39.984-39.984 59.953-60l-30-30 30-30-30-30 30-30-30-30 30-30-30-30 30-30-30-30 30-30-30-30 30-30-30-30 30-30c-20.016-20.016-39.984-39.984-59.953-60l30-30c-20.016-20.016-39.984-39.984-59.953-60l30-30c-60.047-60-120.05-120-180-180l-30 30 30 30-30 30 30 30 30-30 30 30z"/>
|
||||||
|
<path d="m495.05 180 30-30-30-30-30 30 30 30z"/>
|
||||||
|
<path d="m495.05 180-30 30 30 30 30-30-30-30z"/>
|
||||||
|
<path d="m495.05 240-30 30 30 30 30-30-30-30z"/>
|
||||||
|
<path d="m495.05 300c-9.9844 10.031-20.016 20.016-30 30l30 30 30-30-30-30z"/>
|
||||||
|
<path d="m495.05 360c-9.9844 10.031-20.016 20.016-30 30l30 30 30-30-30-30z"/>
|
||||||
|
<path d="m495.05 420-30 30 30 30 30-30-30-30z"/>
|
||||||
|
<path d="m495.05 480c-9.9844 10.031-20.016 20.016-30 30l30 30 30-30-30-30z"/>
|
||||||
|
<path d="m495.05 540c-9.9844 10.031-20.016 20.016-30 30l30 30 30-30-30-30z"/>
|
||||||
|
<path d="m495.05 600-30 30 30 30 30-30-30-30z"/>
|
||||||
|
<path d="m495.05 660-30 30 30 30 30-30-30-30z"/>
|
||||||
|
<path d="m495.05 720c-9.9844 9.9844-20.016 19.969-30 30l30 30 30-30-30-30z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="1200pt" height="1200pt" version="1.1" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m971.44 257.02v-57.141h-285.74v57.188h-57.141v57.188h-57.141v114.33h-57.141v171.47h-57.141v171.47h-57.141v114.33h-57.141v57.188h-57.141v57.188h914.29v-57.188h-57.141v-57.188h-57.141v-57.188h-57.141v-171.47h-57.141v114.33h-57.141v57.188h-57.141v-57.188h-57.141v57.188h-57.141v-57.188h-57.141v-171.47h57.141v-57.188h57.141v57.188h57.141v-114.33h57.141v114.33h57.141v-57.188h57.141v114.33h57.141l0.14062-342.98h-57.141v114.33h-114.28v-57.188h57.141v-57.188h57.141v-57.188h-57.141zm-114.28 171.47h-114.28v-57.188h57.141v-57.188h57.141z"/>
|
||||||
|
<path d="m0 1000.1h57.141v-57.188l-57.141 0.046875v57.188z"/>
|
||||||
|
<path d="m114.28 1000.1h114.28v-57.188h-114.28z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 816 B |
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="1200pt" height="1200pt" version="1.1" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m162.94 9.0469h411.79v65.625h-411.79z"/>
|
||||||
|
<path d="m531.74 254.21h394.45v65.625h-394.45z"/>
|
||||||
|
<path d="m531.74 144.79h394.45v65.625h-394.45z"/>
|
||||||
|
<path d="m162.94 552.84h288.14v70.125h-288.14z"/>
|
||||||
|
<path d="m825.14 552.84h101.06v70.125h-101.06z"/>
|
||||||
|
<path d="m751.22 497.06v-116.16h-219.47v242.11h219.47v-70.172h-71.625v-55.781z"/>
|
||||||
|
<path d="m162.94 679.6h288.14v70.125h-288.14z"/>
|
||||||
|
<path d="m1109.5 240.61v-73.172h-83.719v-92.766h-73.172v92.766h66.375v794.21h-66.375v59.578l-866.63 0.046876v-791.95h76.172v276.05h288.14v-371.11h-288.14v-59.578h-86.719v92.766h-75.422v862.08h85.969v79.219h106.36v82.219h1008.4v-950.34zm-24.141 883.22h-778.36v-24.891h779.11v24.891z"/>
|
||||||
|
<path d="m531.74 679.6h394.45v70.125h-394.45z"/>
|
||||||
|
<path d="m531.74 788.21h394.45v70.125h-394.45z"/>
|
||||||
|
<path d="m531.74 891.52h394.45v70.125h-394.45z"/>
|
||||||
|
<path d="m162.94 805.55h288.14v156.14h-288.14z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="1200pt" height="1200pt" version="1.1" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m524.16 675.84h202.2v-50.641h101.04v-101.04h50.523v-252.6h-50.523v-101.04h-101.04v-50.52h-252.72v50.52h-101.04v101.04h-50.523v252.6h50.523v101.04h101.04v50.641z"/>
|
||||||
|
<path d="m221.04 1029.5v50.52h757.92v-101.04h-50.52v-101.04h-50.52v-101.04h-101.04v-50.52h-353.76v50.52h-101.04v101.04h-50.52v101.04h-50.52z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 475 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="1200pt" height="1200pt" version="1.1" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m1200 202.92h-1200v794.16h1200zm-366 206.06v263.34h52.406v183h-160.64v-183h52.406v-263.34h55.875zm-206.76 0v263.34h52.406v183h-160.64v-183h52.406v-263.34h55.875zm-206.76 0v263.34h52.406v183h-160.64v-183h52.406v-263.34h55.875zm-298.26 0h90.797v263.34h52.406v183h-143.86v-446.34zm956.26 446.34h-145.26v-183h52.406v-263.34h92.906v446.34z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 504 B |
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="1200pt" height="1200pt" version="1.1" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m563.04 489.24v-221.52h73.922v295.32h73.801v-295.32h73.918v-147.72h-369.24v147.72h73.797v295.32h73.801z"/>
|
||||||
|
<path d="m415.44 563.04h73.801v73.801h-73.801z"/>
|
||||||
|
<path d="m710.76 563.04h73.801v73.801h-73.801z"/>
|
||||||
|
<path d="m341.52 636.96h73.801v73.801h-73.801z"/>
|
||||||
|
<path d="m784.56 636.96h73.801v73.801h-73.801z"/>
|
||||||
|
<path d="m267.72 710.76h73.801v73.801h-73.801z"/>
|
||||||
|
<path d="m858.48 710.76h73.801v73.801h-73.801z"/>
|
||||||
|
<path d="m193.8 784.56h73.801v73.801h-73.801z"/>
|
||||||
|
<path d="m784.68 784.68h-73.918v-73.918h-221.52v73.918h-73.797v73.801h-73.922v73.801h516.96v-73.801h-73.801z"/>
|
||||||
|
<path d="m932.28 784.56h73.801v73.801h-73.801z"/>
|
||||||
|
<path d="m193.8 858.48h-73.801v147.72h73.801z"/>
|
||||||
|
<path d="m1006.2 932.28v73.918h73.801v-147.72h-73.801z"/>
|
||||||
|
<path d="m858.48 1006.2h-664.68v73.801h812.4v-73.801z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 960 B |
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="1200pt" height="1200pt" version="1.1" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m969.3 600.06v-92.398h-46.332v-46.199h-45.961v-46.078h-92.27v-46.211h-46.309v-92.277h46.309v-184.57h-46.309v-46.078h-276.84v46.078h-46.309v184.58h46.309v92.277h-46.309v46.211h-92.281v46.078h-45.961v46.199h-46.32v92.398h-45.949v276.86h45.949v92.277h46.32v92.289h45.961v46.199h92.281v46.078h369.46v-46.078h92.27v-46.199h45.961v-92.289h46.332v-92.277h45.961v-276.86l-45.961 0.011719zm-92.293-46.32v46.32h-46.309v46.199h-45.961v46.078h-92.27v46.211h-184.92v-46.211h-92.27v-46.078h-45.961v-46.199h-46.32v-92.398h46.32v-46.199h92.27v-46.078h45.961v-184.58h-45.961v-92.277h45.961l0.003906-46.195h184.92v46.211h45.961v92.277h-45.961v184.58h45.961v46.078h92.27v46.199h46.309z"/>
|
||||||
|
<path d="m646.13 138.54h46.332v46.078h-46.332z"/>
|
||||||
|
<path d="m553.86 184.62v46.188h92.27v-46.188z"/>
|
||||||
|
<path d="m507.53 138.54h46.32v46.078h-46.32z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 986 B |
@@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="1200pt" height="1200pt" version="1.1" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m540 60v-60h-59.953v60z"/>
|
||||||
|
<path d="m719.95 60h-59.953v60h59.953z"/>
|
||||||
|
<path d="m959.9 60h-59.953v60h59.953z"/>
|
||||||
|
<path d="m599.95 120v60h59.953v-60z"/>
|
||||||
|
<path d="m779.9 180v-60h-59.953v60z"/>
|
||||||
|
<path d="m360.1 240v-60h-59.953v60z"/>
|
||||||
|
<path d="m719.95 240v-60h-59.953v60z"/>
|
||||||
|
<path d="m899.86 240h-59.953v60h59.953z"/>
|
||||||
|
<path d="m779.9 300v60h59.953v-60z"/>
|
||||||
|
<path d="m959.9 300h-59.953v60h59.953z"/>
|
||||||
|
<path d="m360.1 360v60h299.9v-60z"/>
|
||||||
|
<path d="m839.9 420h59.953v-60h-59.953z"/>
|
||||||
|
<path d="m300.14 480h59.953v-60h-59.953z"/>
|
||||||
|
<path d="m660 420v60h59.953v-60z"/>
|
||||||
|
<path d="m240.1 540h59.953v-60h-59.953z"/>
|
||||||
|
<path d="m719.95 480v60h59.953v-60z"/>
|
||||||
|
<path d="m180.14 1200h539.81v-60h-479.86v-600h-59.953z"/>
|
||||||
|
<path d="m839.9 1200v-660h-59.953v660z"/>
|
||||||
|
<path d="m1019.9 540h-59.953v60h59.953z"/>
|
||||||
|
<path d="m719.95 780h-179.95v60h179.95z"/>
|
||||||
|
<path d="m899.86 840h59.953v-60h-59.953z"/>
|
||||||
|
<path d="m719.95 900h-299.9v60h299.9z"/>
|
||||||
|
<path d="m300.14 1080h419.81v-60l-419.81-0.046875z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="1200pt" height="1200pt" version="1.1" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m627.24 163.64v-54.562h-109.08v-54.562h54.516v-54.516h218.11v54.562h163.6v54.562h54.516v54.562h54.516v54.562h-54.516v54.562h109.08v54.562h-490.74v-54.562h-54.516v-54.562h109.08v-54.562h-54.516z"/>
|
||||||
|
<path d="m790.82 600v54.562h218.11v-54.562h54.516v-54.562h54.516v-163.64h-436.22v163.64h54.516v54.562zm163.6-109.08v-54.562h109.08v54.562zm-54.562 54.562h54.516v54.562h-54.516zm-109.03-54.562v-54.562h109.08v54.562z"/>
|
||||||
|
<path d="m354.61 1145.5v54.562h-163.55v-54.562h109.08v-54.562h-218.16v-54.562h54.516v-54.562h54.516v-54.562h54.516v-54.562h54.516v-54.562h54.516v-109.12h54.516v-109.12h54.516v-54.562h54.516v-54.562h54.516v-54.562h54.516v109.12h54.516v54.562h54.516v54.562h54.516v54.562h54.516v163.64h-54.516v109.12h-54.516v109.12h-54.516v54.562h-54.516v54.562h-54.516v-163.64h-54.516v54.562h-54.516v54.562h-109.08z"/>
|
||||||
|
<path d="m899.86 763.64h54.516v54.562h-54.516z"/>
|
||||||
|
<path d="m954.42 818.21h54.516v109.12h-54.516z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -1,5 +1,5 @@
|
|||||||
import { describe, it, expect } from 'vitest'
|
import { describe, it, expect } from 'vitest'
|
||||||
import { dispatch, initialStateFor } from './dispatcher'
|
import { dispatch, getLightStatus, initialStateFor } from './dispatcher'
|
||||||
import type { World } from '../world/types'
|
import type { World } from '../world/types'
|
||||||
import type { GameState, ParsedCommand } from './types'
|
import type { GameState, ParsedCommand } from './types'
|
||||||
import { SCHEMA_VERSION } from './types'
|
import { SCHEMA_VERSION } from './types'
|
||||||
@@ -256,6 +256,78 @@ describe('dispatcher — inventory', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('light status', () => {
|
||||||
|
it('shows the meter when carrying a lightable item even before it is lit', () => {
|
||||||
|
const lightWorld: World = {
|
||||||
|
...world,
|
||||||
|
items: {
|
||||||
|
...world.items,
|
||||||
|
torch: {
|
||||||
|
id: 'torch',
|
||||||
|
names: ['torch', 'lamp'],
|
||||||
|
short: 'an oil lamp',
|
||||||
|
long: 'An iron oil lamp, unlit.',
|
||||||
|
initialState: { lit: false },
|
||||||
|
takeable: true,
|
||||||
|
lightable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const state: GameState = {
|
||||||
|
...initialStateFor(lightWorld),
|
||||||
|
inventory: [{ id: 'torch', state: { lit: false } }],
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(getLightStatus(state, lightWorld)).toEqual({
|
||||||
|
itemId: 'torch',
|
||||||
|
lit: false,
|
||||||
|
turnsLeft: 0,
|
||||||
|
maxTurns: 6,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('prefers a lit lightable item over an unlit one in inventory order', () => {
|
||||||
|
const lightWorld: World = {
|
||||||
|
...world,
|
||||||
|
items: {
|
||||||
|
...world.items,
|
||||||
|
torch: {
|
||||||
|
id: 'torch',
|
||||||
|
names: ['torch', 'lamp'],
|
||||||
|
short: 'an oil lamp',
|
||||||
|
long: 'An iron oil lamp, unlit.',
|
||||||
|
initialState: { lit: false },
|
||||||
|
takeable: true,
|
||||||
|
lightable: true,
|
||||||
|
},
|
||||||
|
candlestick: {
|
||||||
|
id: 'candlestick',
|
||||||
|
names: ['candlestick', 'candle'],
|
||||||
|
short: 'a brass candlestick',
|
||||||
|
long: 'A brass candlestick.',
|
||||||
|
initialState: { lit: false },
|
||||||
|
takeable: true,
|
||||||
|
lightable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const state: GameState = {
|
||||||
|
...initialStateFor(lightWorld),
|
||||||
|
inventory: [
|
||||||
|
{ id: 'candlestick', state: { lit: false } },
|
||||||
|
{ id: 'torch', state: { lit: true, burn: 6 } },
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(getLightStatus(state, lightWorld)).toEqual({
|
||||||
|
itemId: 'torch',
|
||||||
|
lit: true,
|
||||||
|
turnsLeft: 6,
|
||||||
|
maxTurns: 6,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('ambiguous → disambiguation flow', () => {
|
describe('ambiguous → disambiguation flow', () => {
|
||||||
function makeAmbiguousWorld(): World {
|
function makeAmbiguousWorld(): World {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -52,19 +52,22 @@ export function initialStateFor(world: World): GameState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getLightStatus(state: GameState, world: World): LightStatus | null {
|
export function getLightStatus(state: GameState, world: World): LightStatus | null {
|
||||||
|
let fallback: LightStatus | null = null
|
||||||
for (const inst of state.inventory) {
|
for (const inst of state.inventory) {
|
||||||
const def = world.items[inst.id]
|
const def = world.items[inst.id]
|
||||||
if (!def?.lightable) continue
|
if (!def?.lightable) continue
|
||||||
if (inst.state['lit'] !== true) continue
|
const lit = inst.state['lit'] === true
|
||||||
const turnsLeft = getLightTurnsLeft(inst)
|
const turnsLeft = lit ? getLightTurnsLeft(inst) : 0
|
||||||
return {
|
const status = {
|
||||||
itemId: inst.id,
|
itemId: inst.id,
|
||||||
lit: true,
|
lit,
|
||||||
turnsLeft,
|
turnsLeft,
|
||||||
maxTurns: LIGHT_TURNS_MAX,
|
maxTurns: LIGHT_TURNS_MAX,
|
||||||
}
|
}
|
||||||
|
if (lit) return status
|
||||||
|
fallback = fallback ?? status
|
||||||
}
|
}
|
||||||
return null
|
return fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
function append(state: GameState, lines: TranscriptLine[]): GameState {
|
function append(state: GameState, lines: TranscriptLine[]): GameState {
|
||||||
|
|||||||
@@ -405,8 +405,15 @@ body {
|
|||||||
width: 30px;
|
width: 30px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
display: block;
|
display: block;
|
||||||
object-fit: contain;
|
color: var(--m-dim);
|
||||||
filter: drop-shadow(0 0 2px currentColor);
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mystery-light-icon svg {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: block;
|
||||||
|
fill: currentColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mystery-light-leds {
|
.mystery-light-leds {
|
||||||
@@ -431,6 +438,12 @@ body {
|
|||||||
box-shadow: 0 0 7px currentColor;
|
box-shadow: 0 0 7px currentColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mystery-light-meter[data-lit='true'] .mystery-light-icon {
|
||||||
|
color: var(--m-fg);
|
||||||
|
opacity: 1;
|
||||||
|
filter: drop-shadow(0 0 2px currentColor) drop-shadow(0 0 6px currentColor);
|
||||||
|
}
|
||||||
|
|
||||||
.mystery-chip {
|
.mystery-chip {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: var(--m-fg);
|
color: var(--m-fg);
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import * as Sentry from '@sentry/browser'
|
||||||
|
|
||||||
|
const dsn = import.meta.env.PUBLIC_GLITCHTIP_DSN as string | undefined
|
||||||
|
const release = import.meta.env.PUBLIC_GLITCHTIP_RELEASE as string | undefined
|
||||||
|
|
||||||
|
export function initGlitchTip(): void {
|
||||||
|
if (!dsn) return
|
||||||
|
|
||||||
|
Sentry.init({
|
||||||
|
dsn,
|
||||||
|
release,
|
||||||
|
environment: import.meta.env.MODE,
|
||||||
|
tracesSampleRate: 0.01,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -7,12 +7,15 @@ import type { GameState, TranscriptLine } from '../engine/types'
|
|||||||
import { TRANSCRIPT_CAP } from '../engine/types'
|
import { TRANSCRIPT_CAP } from '../engine/types'
|
||||||
import { computeChips } from './chips'
|
import { computeChips } from './chips'
|
||||||
import { renderChips } from './chip-render'
|
import { renderChips } from './chip-render'
|
||||||
|
import LIGHT_ICON_SVG from '../assets/noun-candle-6409709.svg?raw'
|
||||||
|
import { initGlitchTip } from './glitchtip'
|
||||||
|
|
||||||
const transcriptEl = document.querySelector<HTMLDivElement>('[data-mystery-transcript]')
|
const transcriptEl = document.querySelector<HTMLDivElement>('[data-mystery-transcript]')
|
||||||
const inputEl = document.querySelector<HTMLInputElement>('[data-mystery-input]')
|
const inputEl = document.querySelector<HTMLInputElement>('[data-mystery-input]')
|
||||||
const inputDisplayEl = document.querySelector<HTMLSpanElement>('[data-mystery-input-display]')
|
const inputDisplayEl = document.querySelector<HTMLSpanElement>('[data-mystery-input-display]')
|
||||||
const lightMeterEl = document.querySelector<HTMLDivElement>('[data-mystery-light-meter]')
|
const lightMeterEl = document.querySelector<HTMLDivElement>('[data-mystery-light-meter]')
|
||||||
const LIGHT_ICON_URL = new URL('../assets/noun-oil-lamp-8301660.svg', import.meta.url).href
|
|
||||||
|
initGlitchTip()
|
||||||
|
|
||||||
const HELP_TEXT = `You arrive at the address, but you do not remember what has happened. The road behind you is gone...
|
const HELP_TEXT = `You arrive at the address, but you do not remember what has happened. The road behind you is gone...
|
||||||
|
|
||||||
@@ -60,11 +63,10 @@ if (!transcriptEl || !inputEl || !inputDisplayEl) {
|
|||||||
lightMeterEl.dataset['lit'] = 'true'
|
lightMeterEl.dataset['lit'] = 'true'
|
||||||
lightMeterEl.dataset['turnsLeft'] = String(status.turnsLeft)
|
lightMeterEl.dataset['turnsLeft'] = String(status.turnsLeft)
|
||||||
|
|
||||||
const icon = document.createElement('img')
|
const icon = document.createElement('div')
|
||||||
icon.className = 'mystery-light-icon'
|
icon.className = 'mystery-light-icon'
|
||||||
icon.src = LIGHT_ICON_URL
|
|
||||||
icon.alt = ''
|
|
||||||
icon.setAttribute('aria-hidden', 'true')
|
icon.setAttribute('aria-hidden', 'true')
|
||||||
|
icon.innerHTML = LIGHT_ICON_SVG
|
||||||
lightMeterEl.appendChild(icon)
|
lightMeterEl.appendChild(icon)
|
||||||
|
|
||||||
const leds = document.createElement('div')
|
const leds = document.createElement('div')
|
||||||
@@ -73,7 +75,11 @@ if (!transcriptEl || !inputEl || !inputDisplayEl) {
|
|||||||
for (let i = 0; i < LIGHT_TURNS_MAX; i++) {
|
for (let i = 0; i < LIGHT_TURNS_MAX; i++) {
|
||||||
const segment = document.createElement('span')
|
const segment = document.createElement('span')
|
||||||
segment.className = 'mystery-light-segment'
|
segment.className = 'mystery-light-segment'
|
||||||
segment.dataset['segmentState'] = i < turnsLeft ? 'lit' : 'dim'
|
const lit = i < turnsLeft
|
||||||
|
segment.dataset['segmentState'] = lit ? 'lit' : 'dim'
|
||||||
|
segment.style.backgroundColor = lit ? 'var(--m-fg)' : 'var(--m-dim)'
|
||||||
|
segment.style.boxShadow = lit ? '0 0 7px var(--m-fg)' : '0 0 0 1px rgba(0, 0, 0, 0.15) inset'
|
||||||
|
segment.style.opacity = lit ? '1' : '0.45'
|
||||||
leds.appendChild(segment)
|
leds.appendChild(segment)
|
||||||
}
|
}
|
||||||
lightMeterEl.appendChild(leds)
|
lightMeterEl.appendChild(leds)
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
- [x] If the user says "use match with letter" they should burn the letter.
|
- [x] If the user says "use match with letter" they should burn the letter.
|
||||||
- [x] There should be a lighter in the smoking room that allows unlimited lighting.
|
- [x] There should be a lighter in the smoking room that allows unlimited lighting.
|
||||||
- [ ] Create a mechanic that asks "Are you sure?" before taking critical actions like attacking or other game-changing mechanics that might affect the final ending.
|
- [ ] Create a mechanic that asks "Are you sure?" before taking critical actions like attacking or other game-changing mechanics that might affect the final ending.
|
||||||
- [ ] Create a new item with a mechanic: whiskey bottle. When the user drinks it they get drunk and are transported to the "drunk rooms" which are a bit of a maze and things get a little topsy-turvy. The player chances to lose an item (returning to its original spot) when they get drunk and wakes up several turns later somewhere else predetermined.
|
|
||||||
- [ ] Add lightened descriptions to darkened rooms. About half the rooms should be too dark to see anything (affects ability to move forward, can't see exits or entounters, except for maybe hints at the encounters, like sounds or shapes in the dark) Add frontmatter property to all rooms: (dark: true/false). Make text in darkened rooms a grey color.
|
- [ ] Add lightened descriptions to darkened rooms. About half the rooms should be too dark to see anything (affects ability to move forward, can't see exits or entounters, except for maybe hints at the encounters, like sounds or shapes in the dark) Add frontmatter property to all rooms: (dark: true/false). Make text in darkened rooms a grey color.
|
||||||
- [ ] Implement a simple "stealth mechanic", where sometimes it's advantageous to have the light out.
|
- [ ] Implement a simple "stealth mechanic", where sometimes it's advantageous to have the light out.
|
||||||
- [ ] Implement a simple (optional?) minimap in the UI? - Maybe tied to an item? Once you get the map the minimap appears? Can we POC it?
|
- [ ] Implement a simple (optional?) minimap in the UI? - Maybe tied to an item? Once you get the map the minimap appears? Can we POC it?
|
||||||
@@ -37,3 +36,10 @@
|
|||||||
- [ ] Implement a carry mechanic. Decide whether we should have a limited carry ability (only able to carry a few things?) or we night need a full inventory system, where items are assigned to pockets or hand carry and we can only hand carry a couple of items?
|
- [ ] Implement a carry mechanic. Decide whether we should have a limited carry ability (only able to carry a few things?) or we night need a full inventory system, where items are assigned to pockets or hand carry and we can only hand carry a couple of items?
|
||||||
- [ ] Implement a "drop" mechanic
|
- [ ] Implement a "drop" mechanic
|
||||||
- [x] We need a light indicator that shows when the light is lit and how much time is left on the light. Use the svg file I dropped in the src/assets folder for the indicator. The indicator should be a 6-segment led that runs in a dotted line underneath the light indicator and burns out right to left. The color of the indicator should be bright when it's lit and dim when it's not. The indicator should be to the right of the tiles and sized appropriately.
|
- [x] We need a light indicator that shows when the light is lit and how much time is left on the light. Use the svg file I dropped in the src/assets folder for the indicator. The indicator should be a 6-segment led that runs in a dotted line underneath the light indicator and burns out right to left. The color of the indicator should be bright when it's lit and dim when it's not. The indicator should be to the right of the tiles and sized appropriately.
|
||||||
|
- [ ] FEATURE: Add an option to disable the chips in the options menu.
|
||||||
|
- [ ] BUG: The new cursor doesn't appear on mobile.
|
||||||
|
- [ ] FEATURE: Add a Safe to somewhere that it makes sense (the bedroom?) We can add a safe-cracking mini-game. The safe contains a single bullet, which can be used with the revolver.
|
||||||
|
- [ ] FEATURE: Add item Revolver, which can be used to kill the thing at the end. It comes with no bullets, so players need to defeat the safe-cracking minjgame. Place the revolver somewhere it takes the player some effort to find.
|
||||||
|
- [ ] Feature: A faceless voice that speaks in a whisper in the chapel, which demands whiskey and dispenses riddles if the player finds a bottle of whiskey (but hasn't drunk it yet). The riddles are randomly chosen from a list of 25 difficult riddles (source them). If the riddle is answered correctly there needs to be some reward and maybe a major plot point is revealed.
|
||||||
|
- [ ] Add item Whiskey bottle, half full of something smoky. In the kitchen. Drinking it gets the player drunk, which causes them to unlock the drunk rooms, which are a series of rooms where they can go many directions, but somehow end up in seemingly back in the same spot. They are essentially a maze of doors and hallways, ladders and levels. There should be boundaries established though, it shouldn't be endless. After 20 or so moves the player passes out and wakes up back in the foyer, with the whiskey bottle returned to the kitchen, somehow still half full. Add a random encounter in the dark rooms, a creaking floorboard helps you find a secret door that opens with a faceless man inside who gives you major plot info. After this encounter you pass out and wake up in the lobby as before.
|
||||||
|
- [ ]
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ The wall beside your shoulder breathes in. The opposite wall answers.
|
|||||||
## wait-resolved
|
## wait-resolved
|
||||||
You stand still.
|
You stand still.
|
||||||
|
|
||||||
The passage narrows, then forgets to. The breathing passes on ahead of you.
|
The passage narrows, then forgets to. The breathing passes on ahead of you, down the wall and out of reach.
|
||||||
|
|
||||||
## wrong-verb
|
## wrong-verb
|
||||||
The walls take a slower breath.
|
The walls take a slower breath.
|
||||||
|
|
||||||
## failed
|
## failed
|
||||||
The boards lean close enough to touch your sleeves. You retreat into the music room.
|
The boards lean close enough to touch your sleeves. You retreat into the music room before they can close around you.
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ The cage is empty. A few pale feathers cling to the wire, though no bird could h
|
|||||||
Somewhere far above you, wings beat once inside a wall.
|
Somewhere far above you, wings beat once inside a wall.
|
||||||
|
|
||||||
## wrong-verb
|
## wrong-verb
|
||||||
The cloth trembles.
|
The cloth trembles, then goes still again.
|
||||||
|
|
||||||
## failed
|
## failed
|
||||||
The rustling grows too close to your ear. You leave the room before you decide to.
|
The rustling grows too close to your ear. You leave the room before you decide to, and the cage is still covered when you look back.
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ The shears close with a sound like teeth.
|
|||||||
The figure falls apart leaf by leaf. Behind it, the glass is only glass.
|
The figure falls apart leaf by leaf. Behind it, the glass is only glass.
|
||||||
|
|
||||||
## wrong-verb
|
## wrong-verb
|
||||||
The vines tighten without moving.
|
The vines tighten without moving. Their silence feels deliberate.
|
||||||
|
|
||||||
## failed
|
## failed
|
||||||
The ivy catches at your wrists. When you pull free, you are back among the cold plates of the dining room.
|
The ivy catches at your wrists. When you pull free, you are back among the cold plates of the dining room, with leaves clinging to your sleeves.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ initialPhase: hanging
|
|||||||
---
|
---
|
||||||
|
|
||||||
## hanging
|
## hanging
|
||||||
One hanging sheet has the weight and outline of a person standing behind it.
|
One hanging sheet has the weight and outline of a person standing behind it. The shape shifts when you look straight at it.
|
||||||
|
|
||||||
## wait-resolved
|
## wait-resolved
|
||||||
You wait.
|
You wait.
|
||||||
@@ -13,7 +13,7 @@ You wait.
|
|||||||
The sheet stirs. Nothing stands behind it. Nothing had stood behind it.
|
The sheet stirs. Nothing stands behind it. Nothing had stood behind it.
|
||||||
|
|
||||||
## wrong-verb
|
## wrong-verb
|
||||||
The shape seems to lean toward you.
|
The shape seems to lean toward you, then settles back into stillness.
|
||||||
|
|
||||||
## failed
|
## failed
|
||||||
You push through the hanging sheets and come out in the servants' passage, breathing hard.
|
You push through the hanging sheets and come out in the servants' passage, breathing hard, with damp cloth brushing your face.
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ You play the waiting note.
|
|||||||
The answer comes at once, nearer than before. A narrow part of the wall settles back into shadow.
|
The answer comes at once, nearer than before. A narrow part of the wall settles back into shadow.
|
||||||
|
|
||||||
## wrong-verb
|
## wrong-verb
|
||||||
The answering note repeats, patient and exact.
|
The answering note repeats, patient and exact. It sounds as if it has not moved at all.
|
||||||
|
|
||||||
## failed
|
## failed
|
||||||
The wrong chord goes through the floorboards. You climb back to the hallway before the echo finishes.
|
The wrong chord goes through the floorboards. You climb back to the hallway before the echo finishes.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ initialPhase: standing-outside
|
|||||||
---
|
---
|
||||||
|
|
||||||
## standing-outside
|
## standing-outside
|
||||||
Rain touches the dining-room window from the wrong side. Someone stands beyond the glass with their head bowed.
|
Rain touches the dining-room window from the wrong side. Someone stands beyond the glass with their head bowed. Their coat is too dark to make out properly.
|
||||||
|
|
||||||
## close-window-guest-resolved
|
## close-window-guest-resolved
|
||||||
You draw the curtains together before you look closely.
|
You draw the curtains together before you look closely.
|
||||||
@@ -13,7 +13,7 @@ You draw the curtains together before you look closely.
|
|||||||
For a moment, cloth and rain hold the same shape. Then there is only the table behind you.
|
For a moment, cloth and rain hold the same shape. Then there is only the table behind you.
|
||||||
|
|
||||||
## wrong-verb
|
## wrong-verb
|
||||||
The figure outside lifts its face a little.
|
The figure outside lifts its face a little, as if disappointed by your hesitation.
|
||||||
|
|
||||||
## failed
|
## failed
|
||||||
The glass shows too much. You find yourself back in the hallway with the taste of rain in your mouth.
|
The glass shows too much. For one instant there is a second dining room beyond it. Then you are back in the hallway with rain in your mouth.
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ initialState:
|
|||||||
lit: false
|
lit: false
|
||||||
---
|
---
|
||||||
|
|
||||||
A brass candlestick, heavy at the base. The candle inside it is burned low but not spent.
|
A brass candlestick, heavy at the base. The candle inside it is burned low but not spent. It holds a little light very steadily, as if it dislikes being noticed.
|
||||||
|
|
||||||
## lit
|
## lit
|
||||||
The wick takes. The flame bends toward the nearest doorway.
|
The wick takes. The flame stands upright for a moment, then bends toward the nearest doorway.
|
||||||
|
|
||||||
## extinguished
|
## extinguished
|
||||||
The candle gutters out. For a moment the smoke leans against your hand.
|
The candle gutters out. For a moment the smoke leans against your hand before it thins.
|
||||||
|
|||||||
@@ -6,4 +6,4 @@ takeable: true
|
|||||||
initialState: {}
|
initialState: {}
|
||||||
---
|
---
|
||||||
|
|
||||||
A sheet still wet from some old washing. It smells of rainwater and closed rooms.
|
A sheet still wet from some old washing. It smells of rainwater and closed rooms. It keeps the cold longer than cloth should.
|
||||||
|
|||||||
@@ -6,4 +6,4 @@ takeable: true
|
|||||||
initialState: {}
|
initialState: {}
|
||||||
---
|
---
|
||||||
|
|
||||||
A tiny key on a black ribbon. It is too small for any door in the house.
|
A tiny key on a black ribbon. It is too small for any door in the house, and yet the ribbon has been tied and retied as if someone meant to keep it safe.
|
||||||
|
|||||||
@@ -6,4 +6,4 @@ takeable: true
|
|||||||
initialState: {}
|
initialState: {}
|
||||||
---
|
---
|
||||||
|
|
||||||
Iron pruning shears with dark soil in the hinge. The handles are cold through your palm.
|
Iron pruning shears with dark soil in the hinge. The handles are cold through your palm. They have been used often enough to remember the shape of branches.
|
||||||
|
|||||||
@@ -7,4 +7,4 @@ lighter: true
|
|||||||
initialState: {}
|
initialState: {}
|
||||||
---
|
---
|
||||||
|
|
||||||
A silver lighter with a worn crest on one side. It opens with a small reluctant click.
|
A silver lighter with a worn crest on one side. It opens with a small reluctant click, then catches as if it had been waiting to be asked.
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
id: whiskey
|
||||||
|
names: ["whiskey", "bottle of whiskey", "bottle"]
|
||||||
|
short: "a bottle of whiskey"
|
||||||
|
takeable: true
|
||||||
|
initialState: {}
|
||||||
|
---
|
||||||
|
|
||||||
|
A bottle of whiskey with a cloudy label and a dark amber level inside. It has the look of something set down in a hurry and never touched again.
|
||||||
@@ -13,7 +13,7 @@ encounter: "[[ivy-figure]]"
|
|||||||
---
|
---
|
||||||
|
|
||||||
## first-visit
|
## first-visit
|
||||||
The conservatory roof has gone blind with moss and old rain. Vines press against the glass from both sides.
|
The conservatory roof has gone blind with moss and old rain. Vines press against the glass from both sides, as if the room were trying to keep something in.
|
||||||
|
|
||||||
Something human-shaped hangs among the ivy. The dining room is south.
|
Something human-shaped hangs among the ivy. The dining room is south.
|
||||||
|
|
||||||
@@ -21,4 +21,4 @@ Something human-shaped hangs among the ivy. The dining room is south.
|
|||||||
The conservatory sweats in the dark.
|
The conservatory sweats in the dark.
|
||||||
|
|
||||||
## examined
|
## examined
|
||||||
The tiled floor is split by roots. The air smells of wet soil and cold iron. A bench has been dragged beneath the blind glass roof.
|
The tiled floor is split by roots. The air smells of wet soil and cold iron. A bench has been dragged beneath the blind glass roof and left at an angle, as if someone stood up too quickly.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ id: dining-room
|
|||||||
title: "[ Dining Room ]"
|
title: "[ Dining Room ]"
|
||||||
exitN: "[[conservatory]]"
|
exitN: "[[conservatory]]"
|
||||||
exitS: null
|
exitS: null
|
||||||
exitE: null
|
exitE: "[[kitchen]]"
|
||||||
exitW: "[[hallway]]"
|
exitW: "[[hallway]]"
|
||||||
exitU: null
|
exitU: null
|
||||||
exitD: null
|
exitD: null
|
||||||
@@ -14,12 +14,12 @@ encounter: "[[window-guest]]"
|
|||||||
---
|
---
|
||||||
|
|
||||||
## first-visit
|
## first-visit
|
||||||
The dining room is laid for supper long after supper ended. Plates dull the long table. One place has not been touched.
|
The dining room is laid for supper long after supper ended. Plates dull the long table. One place at the far end has not been touched.
|
||||||
|
|
||||||
The hallway is west. A greenish light presses through glass to the north.
|
The hallway is west. The kitchen is east. A green light presses through the glass to the north.
|
||||||
|
|
||||||
## revisit
|
## revisit
|
||||||
The dining room holds its place at the table.
|
The dining room holds its place at the table.
|
||||||
|
|
||||||
## examined
|
## examined
|
||||||
The silver has tarnished black at the edges. The untouched plate is clean enough to show a dim shape behind you, though there is no one there.
|
The silver has gone black at the edges. The untouched plate is clean enough to show a shape behind you, though there is no one there when you turn.
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
id: kitchen
|
||||||
|
title: "[ Kitchen ]"
|
||||||
|
exitN: null
|
||||||
|
exitS: null
|
||||||
|
exitE: null
|
||||||
|
exitW: "[[dining-room]]"
|
||||||
|
exitU: null
|
||||||
|
exitD: null
|
||||||
|
items:
|
||||||
|
- "[[whiskey]]"
|
||||||
|
encounter: null
|
||||||
|
safe: true
|
||||||
|
---
|
||||||
|
|
||||||
|
## first-visit
|
||||||
|
Something recently warm. The room smells of fat, onions, and wood smoke that has not yet cleared.
|
||||||
|
|
||||||
|
The dining room is west.
|
||||||
|
|
||||||
|
## revisit
|
||||||
|
The kitchen keeps its heat a little too long.
|
||||||
|
|
||||||
|
## examined
|
||||||
|
Copper pots hang over the stove. A corkscrew lies by the sink. The bottle on the counter catches what little light there is and holds it.
|
||||||
@@ -14,7 +14,7 @@ safe: true
|
|||||||
---
|
---
|
||||||
|
|
||||||
## first-visit
|
## first-visit
|
||||||
Sheets hang unmoving in the still air. They divide the room into narrow aisles. One of them has the shape of a person behind it.
|
Sheets hang unmoving in the still air. They divide the room into narrow aisles. One of them has the shape of a person behind it, or the suggestion of one.
|
||||||
|
|
||||||
The servants' passage is west.
|
The servants' passage is west.
|
||||||
|
|
||||||
@@ -22,4 +22,4 @@ The servants' passage is west.
|
|||||||
The laundry hangs white and silent.
|
The laundry hangs white and silent.
|
||||||
|
|
||||||
## examined
|
## examined
|
||||||
Water darkens the floor beneath the hanging sheets, though none of them drip. An empty basket waits below the line.
|
Water darkens the floor beneath the hanging sheets, though none of them drip. An empty basket waits below the line, tilted as if something climbed out of it.
|
||||||
|
|||||||
@@ -22,4 +22,4 @@ Something answers from elsewhere in the house, too soft to be music. A servants'
|
|||||||
The music room waits on the same note.
|
The music room waits on the same note.
|
||||||
|
|
||||||
## examined
|
## examined
|
||||||
The depressed piano key does not rise when touched. The music stand is empty, but its clips remain open.
|
The depressed piano key does not rise when touched. The music stand is empty, but its clips remain open, as if a page had just been lifted away.
|
||||||
|
|||||||
@@ -14,14 +14,14 @@ safe: true
|
|||||||
---
|
---
|
||||||
|
|
||||||
## first-visit
|
## first-visit
|
||||||
The parlor has been arranged for company. No chair faces another. Each one waits at a slight angle, as if the guests stood suddenly and left the room in silence.
|
The parlor has been set for company that never arrives. The chairs are drawn a little too far apart, as if the people meant to speak and then forgot what they had meant to say.
|
||||||
|
|
||||||
A stopped clock stands against the north wall. A narrow study opens beyond it. The hallway is below.
|
A stopped clock stands against the north wall. The study lies beyond it. The hallway is below.
|
||||||
|
|
||||||
A staircase climbs where the corner of the room should be.
|
A staircase rises where the corner should be.
|
||||||
|
|
||||||
## revisit
|
## revisit
|
||||||
The parlor waits with its empty chairs.
|
The parlor keeps its arrangement.
|
||||||
|
|
||||||
## examined
|
## examined
|
||||||
Dust gathers on the chair arms, but not on the seats. Someone has sat here recently, or the room remembers being occupied. The grandfather clock shows no hour you can name.
|
Dust gathers on the chair arms, not on the seats. Something in the room has been touched often. The grandfather clock shows no hour you can name.
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ encounter: "[[breathing-wall]]"
|
|||||||
---
|
---
|
||||||
|
|
||||||
## first-visit
|
## first-visit
|
||||||
The walls here are unfinished and smell of wet wood. The passage is too narrow for two people to pass.
|
The walls here are unfinished and smell of wet wood. The passage is too narrow for two people to pass, though it feels made for someone else to follow.
|
||||||
|
|
||||||
The music room is south. A laundry lies east.
|
The music room is south. A laundry lies east.
|
||||||
|
|
||||||
@@ -20,4 +20,4 @@ The music room is south. A laundry lies east.
|
|||||||
The servants' passage breathes less loudly now, or you have learned when not to listen.
|
The servants' passage breathes less loudly now, or you have learned when not to listen.
|
||||||
|
|
||||||
## examined
|
## examined
|
||||||
The boards show old finger marks in the grain. They run at shoulder height along both walls, as if someone felt their way through in the dark.
|
The boards show old finger marks in the grain. They run at shoulder height along both walls, as if someone felt their way through in the dark and never touched the floor.
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ encounter: "[[covered-cage]]"
|
|||||||
---
|
---
|
||||||
|
|
||||||
## first-visit
|
## first-visit
|
||||||
The smoking room smells faintly of ash, velvet, and bitter almonds. The chairs are turned toward the cold hearth.
|
The smoking room smells faintly of ash, velvet, and bitter almonds. The chairs are turned toward the cold hearth, though no one has sat here in years.
|
||||||
|
|
||||||
A cloth-covered cage hangs from a stand. The hallway is east.
|
A cloth-covered cage hangs from a stand. The hallway is east.
|
||||||
|
|
||||||
@@ -22,4 +22,4 @@ A cloth-covered cage hangs from a stand. The hallway is east.
|
|||||||
The smoking room keeps its breath.
|
The smoking room keeps its breath.
|
||||||
|
|
||||||
## examined
|
## examined
|
||||||
Cigar ash lies in a clean saucer. The cold hearth reflects the chairs in a narrow black curve.
|
Cigar ash lies in a clean saucer. The cold hearth reflects the chairs in a narrow black curve. Nothing in the room seems to have been allowed to burn all the way down.
|
||||||
|
|||||||