@origingame/create-game 0.0.0-stage → 0.1.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 +57 -2
- package/archetypes/README.md +99 -0
- package/archetypes/idle/.origin/setup +14 -0
- package/archetypes/idle/LICENSES.md +12 -0
- package/archetypes/idle/README.md +234 -0
- package/archetypes/idle/assets/audio/buy.wav +0 -0
- package/archetypes/idle/assets/audio/milestone.wav +0 -0
- package/archetypes/idle/assets/audio/nova.wav +0 -0
- package/archetypes/idle/assets/audio/orbit.wav +0 -0
- package/archetypes/idle/assets/audio/tap.wav +0 -0
- package/archetypes/idle/assets/audio/ui-close.ogt +9 -0
- package/archetypes/idle/assets/audio/ui-error.ogt +9 -0
- package/archetypes/idle/assets/audio/ui-open.ogt +9 -0
- package/archetypes/idle/assets/audio/ui-press.ogt +9 -0
- package/archetypes/idle/assets/audio/ui-success.ogt +9 -0
- package/archetypes/idle/assets/fonts/NotoSansSC-subset.ttf +0 -0
- package/archetypes/idle/assets/fonts/NotoSansSC-subset.ttf.ogt +10 -0
- package/archetypes/idle/assets/fonts/OFL.txt +93 -0
- package/archetypes/idle/assets/fx/drift.ogt +21 -0
- package/archetypes/idle/assets/fx/milestone.ogt +21 -0
- package/archetypes/idle/assets/fx/nova.ogt +22 -0
- package/archetypes/idle/assets/fx/stars.ogt +20 -0
- package/archetypes/idle/assets/fx/tap.ogt +23 -0
- package/archetypes/idle/assets/looks/idle.ogt +17 -0
- package/archetypes/idle/assets/skins/sparkorb/ChakraPetch-BoldItalic.ttf +0 -0
- package/archetypes/idle/assets/skins/sparkorb/ChakraPetch-BoldItalic.ttf.ogt +9 -0
- package/archetypes/idle/assets/skins/sparkorb/LICENSES.md +19 -0
- package/archetypes/idle/assets/skins/sparkorb/OFL.txt +95 -0
- package/archetypes/idle/assets/skins/sparkorb/Orbitron-Medium.ttf +0 -0
- package/archetypes/idle/assets/skins/sparkorb/Orbitron-Medium.ttf.ogt +9 -0
- package/archetypes/idle/assets/skins/sparkorb/Rajdhani-Bold.ttf +0 -0
- package/archetypes/idle/assets/skins/sparkorb/Rajdhani-Bold.ttf.ogt +9 -0
- package/archetypes/idle/assets/skins/sparkorb/atlas.png +0 -0
- package/archetypes/idle/assets/skins/sparkorb/atlas.png.ogt +7 -0
- package/archetypes/idle/assets/skins/sparkorb/icons.png +0 -0
- package/archetypes/idle/assets/skins/sparkorb/icons.png.ogt +7 -0
- package/archetypes/idle/assets/skins/sparkorb/skin.ogt +113 -0
- package/archetypes/idle/assets/sprites/glow.png +0 -0
- package/archetypes/idle/assets/sprites/glow.png.ogt +8 -0
- package/archetypes/idle/assets/sprites/mote-crystal.png +0 -0
- package/archetypes/idle/assets/sprites/mote-crystal.png.ogt +7 -0
- package/archetypes/idle/assets/sprites/mote-ember.png +0 -0
- package/archetypes/idle/assets/sprites/mote-ember.png.ogt +7 -0
- package/archetypes/idle/assets/sprites/mote-star.png +0 -0
- package/archetypes/idle/assets/sprites/mote-star.png.ogt +7 -0
- package/archetypes/idle/assets/sprites/mote-storm.png +0 -0
- package/archetypes/idle/assets/sprites/mote-storm.png.ogt +7 -0
- package/archetypes/idle/assets/sprites/orb.png +0 -0
- package/archetypes/idle/assets/sprites/orb.png.ogt +7 -0
- package/archetypes/idle/assets/sprites/spark.png +0 -0
- package/archetypes/idle/assets/sprites/spark.png.ogt +7 -0
- package/archetypes/idle/assets/strings/en.ogt +62 -0
- package/archetypes/idle/assets/strings/zh-CN.ogt +62 -0
- package/archetypes/idle/gitattributes +22 -0
- package/archetypes/idle/host.d.ts +46 -0
- package/archetypes/idle/package.json +18 -0
- package/archetypes/idle/project.ogt +14 -0
- package/archetypes/idle/references/metal/card.png +0 -0
- package/archetypes/idle/references/metal/orbit.png +0 -0
- package/archetypes/idle/references/metal/title.png +0 -0
- package/archetypes/idle/src/components.ts +139 -0
- package/archetypes/idle/src/main.ts +247 -0
- package/archetypes/idle/src/numbers.ts +126 -0
- package/archetypes/idle/src/systems.ts +340 -0
- package/archetypes/idle/src/ui.ts +412 -0
- package/archetypes/idle/tests/away.og.ts +42 -0
- package/archetypes/idle/tests/flow.og.ts +57 -0
- package/archetypes/idle/tests/frames.og.ts +33 -0
- package/archetypes/idle/tests/frames.ts +134 -0
- package/archetypes/idle/tests/lib.ts +74 -0
- package/archetypes/idle/tests/milestone.og.ts +32 -0
- package/archetypes/idle/tests/nova.og.ts +52 -0
- package/archetypes/idle/tests/offline.og.ts +60 -0
- package/archetypes/idle/tests/pad.og.ts +55 -0
- package/archetypes/idle/tests/pause.og.ts +68 -0
- package/archetypes/idle/tests/phone.og.ts +50 -0
- package/archetypes/idle/tests/replay.og.ts +28 -0
- package/archetypes/idle/tools/make-assets.py +448 -0
- package/archetypes/idle/tools/oglite.py +285 -0
- package/archetypes/idle/tsconfig.json +17 -0
- package/archetypes/match3/.origin/setup +14 -0
- package/archetypes/match3/LICENSES.md +7 -0
- package/archetypes/match3/README.md +205 -0
- package/archetypes/match3/assets/audio/cascade.wav +0 -0
- package/archetypes/match3/assets/audio/clear.wav +0 -0
- package/archetypes/match3/assets/audio/lost.wav +0 -0
- package/archetypes/match3/assets/audio/refused.wav +0 -0
- package/archetypes/match3/assets/audio/select.wav +0 -0
- package/archetypes/match3/assets/audio/swap.wav +0 -0
- package/archetypes/match3/assets/audio/won.wav +0 -0
- package/archetypes/match3/assets/fonts/OFL.txt +93 -0
- package/archetypes/match3/assets/fonts/ui.ttf +0 -0
- package/archetypes/match3/assets/fonts/ui.ttf.ogt +11 -0
- package/archetypes/match3/assets/scenes/main.ogt +24 -0
- package/archetypes/match3/assets/sprites/backdrop.png +0 -0
- package/archetypes/match3/assets/sprites/board.ogt +21 -0
- package/archetypes/match3/assets/sprites/cells.ogt +7 -0
- package/archetypes/match3/assets/sprites/cells.png +0 -0
- package/archetypes/match3/assets/sprites/cells.png.ogt +7 -0
- package/archetypes/match3/assets/sprites/gems.ogt +75 -0
- package/archetypes/match3/assets/sprites/gems.png +0 -0
- package/archetypes/match3/assets/sprites/panel.png +0 -0
- package/archetypes/match3/assets/sprites/ring.png +0 -0
- package/archetypes/match3/gitattributes +22 -0
- package/archetypes/match3/host.d.ts +46 -0
- package/archetypes/match3/package.json +18 -0
- package/archetypes/match3/project.ogt +18 -0
- package/archetypes/match3/references/metal/cascade.png +0 -0
- package/archetypes/match3/references/metal/clearing.png +0 -0
- package/archetypes/match3/references/metal/dealt.png +0 -0
- package/archetypes/match3/src/art.ts +54 -0
- package/archetypes/match3/src/board.ts +112 -0
- package/archetypes/match3/src/components.ts +95 -0
- package/archetypes/match3/src/layout.ts +25 -0
- package/archetypes/match3/src/main.ts +199 -0
- package/archetypes/match3/src/systems.ts +631 -0
- package/archetypes/match3/tests/drag.og.ts +31 -0
- package/archetypes/match3/tests/endings.og.ts +40 -0
- package/archetypes/match3/tests/frames.og.ts +49 -0
- package/archetypes/match3/tests/frames.ts +134 -0
- package/archetypes/match3/tests/hidpi.og.ts +41 -0
- package/archetypes/match3/tests/lib.ts +64 -0
- package/archetypes/match3/tests/replay.og.ts +28 -0
- package/archetypes/match3/tests/sounds.og.ts +50 -0
- package/archetypes/match3/tests/swap.og.ts +67 -0
- package/archetypes/match3/tools/make-assets.py +404 -0
- package/archetypes/match3/tools/oglite.py +285 -0
- package/archetypes/match3/tsconfig.json +17 -0
- package/archetypes/rhythm/.origin/setup +14 -0
- package/archetypes/rhythm/LICENSES.md +13 -0
- package/archetypes/rhythm/README.md +235 -0
- package/archetypes/rhythm/assets/audio/bass0.wav +0 -0
- package/archetypes/rhythm/assets/audio/bass1.wav +0 -0
- package/archetypes/rhythm/assets/audio/bass2.wav +0 -0
- package/archetypes/rhythm/assets/audio/bass3.wav +0 -0
- package/archetypes/rhythm/assets/audio/chords0.wav +0 -0
- package/archetypes/rhythm/assets/audio/chords1.wav +0 -0
- package/archetypes/rhythm/assets/audio/chords2.wav +0 -0
- package/archetypes/rhythm/assets/audio/chords3.wav +0 -0
- package/archetypes/rhythm/assets/audio/clear.wav +0 -0
- package/archetypes/rhythm/assets/audio/click.wav +0 -0
- package/archetypes/rhythm/assets/audio/drums.wav +0 -0
- package/archetypes/rhythm/assets/audio/fail.wav +0 -0
- package/archetypes/rhythm/assets/audio/leadA.wav +0 -0
- package/archetypes/rhythm/assets/audio/leadB.wav +0 -0
- package/archetypes/rhythm/assets/audio/miss.wav +0 -0
- package/archetypes/rhythm/assets/audio/tap0.wav +0 -0
- package/archetypes/rhythm/assets/audio/tap1.wav +0 -0
- package/archetypes/rhythm/assets/audio/tap2.wav +0 -0
- package/archetypes/rhythm/assets/audio/ui-close.ogt +9 -0
- package/archetypes/rhythm/assets/audio/ui-error.ogt +9 -0
- package/archetypes/rhythm/assets/audio/ui-open.ogt +9 -0
- package/archetypes/rhythm/assets/audio/ui-press.ogt +9 -0
- package/archetypes/rhythm/assets/audio/ui-success.ogt +9 -0
- package/archetypes/rhythm/assets/charts/neon-pulse.ogt +919 -0
- package/archetypes/rhythm/assets/fonts/NotoSansSC-subset.ttf +0 -0
- package/archetypes/rhythm/assets/fonts/NotoSansSC-subset.ttf.ogt +10 -0
- package/archetypes/rhythm/assets/fonts/OFL.txt +93 -0
- package/archetypes/rhythm/assets/fx/hit.ogt +22 -0
- package/archetypes/rhythm/assets/skins/lanebeat/ChakraPetch-Medium.ttf +0 -0
- package/archetypes/rhythm/assets/skins/lanebeat/ChakraPetch-Medium.ttf.ogt +9 -0
- package/archetypes/rhythm/assets/skins/lanebeat/JetBrainsMono-Regular.ttf +0 -0
- package/archetypes/rhythm/assets/skins/lanebeat/JetBrainsMono-Regular.ttf.ogt +9 -0
- package/archetypes/rhythm/assets/skins/lanebeat/LICENSES.md +17 -0
- package/archetypes/rhythm/assets/skins/lanebeat/OFL.txt +95 -0
- package/archetypes/rhythm/assets/skins/lanebeat/Orbitron-Bold.ttf +0 -0
- package/archetypes/rhythm/assets/skins/lanebeat/Orbitron-Bold.ttf.ogt +9 -0
- package/archetypes/rhythm/assets/skins/lanebeat/atlas.png +0 -0
- package/archetypes/rhythm/assets/skins/lanebeat/atlas.png.ogt +7 -0
- package/archetypes/rhythm/assets/skins/lanebeat/icons.png +0 -0
- package/archetypes/rhythm/assets/skins/lanebeat/icons.png.ogt +7 -0
- package/archetypes/rhythm/assets/skins/lanebeat/skin.ogt +110 -0
- package/archetypes/rhythm/assets/sprites/lane.png +0 -0
- package/archetypes/rhythm/assets/sprites/lane.png.ogt +7 -0
- package/archetypes/rhythm/assets/sprites/note.png +0 -0
- package/archetypes/rhythm/assets/sprites/note.png.ogt +7 -0
- package/archetypes/rhythm/assets/sprites/ring.png +0 -0
- package/archetypes/rhythm/assets/sprites/ring.png.ogt +7 -0
- package/archetypes/rhythm/assets/sprites/spark.png +0 -0
- package/archetypes/rhythm/assets/sprites/spark.png.ogt +7 -0
- package/archetypes/rhythm/assets/strings/en.ogt +61 -0
- package/archetypes/rhythm/assets/strings/zh-CN.ogt +61 -0
- package/archetypes/rhythm/gitattributes +22 -0
- package/archetypes/rhythm/host.d.ts +46 -0
- package/archetypes/rhythm/package.json +18 -0
- package/archetypes/rhythm/project.ogt +14 -0
- package/archetypes/rhythm/references/metal/highway.png +0 -0
- package/archetypes/rhythm/references/metal/results.png +0 -0
- package/archetypes/rhythm/references/metal/title.png +0 -0
- package/archetypes/rhythm/src/components.ts +147 -0
- package/archetypes/rhythm/src/main.ts +202 -0
- package/archetypes/rhythm/src/systems.ts +490 -0
- package/archetypes/rhythm/src/ui.ts +421 -0
- package/archetypes/rhythm/tests/band.og.ts +45 -0
- package/archetypes/rhythm/tests/calibrate.og.ts +49 -0
- package/archetypes/rhythm/tests/clear.og.ts +51 -0
- package/archetypes/rhythm/tests/fail.og.ts +40 -0
- package/archetypes/rhythm/tests/flow.og.ts +54 -0
- package/archetypes/rhythm/tests/frames.og.ts +35 -0
- package/archetypes/rhythm/tests/frames.ts +134 -0
- package/archetypes/rhythm/tests/lib.ts +123 -0
- package/archetypes/rhythm/tests/pad.og.ts +41 -0
- package/archetypes/rhythm/tests/pause.og.ts +77 -0
- package/archetypes/rhythm/tests/phone.og.ts +44 -0
- package/archetypes/rhythm/tests/replay.og.ts +27 -0
- package/archetypes/rhythm/tests/timing.og.ts +37 -0
- package/archetypes/rhythm/tools/make-assets.py +383 -0
- package/archetypes/rhythm/tools/oglite.py +285 -0
- package/archetypes/rhythm/tsconfig.json +17 -0
- package/archetypes/roguelike/.origin/setup +14 -0
- package/archetypes/roguelike/LICENSES.md +14 -0
- package/archetypes/roguelike/README.md +256 -0
- package/archetypes/roguelike/assets/ai/foe.ogt +28 -0
- package/archetypes/roguelike/assets/ai/guardian.ogt +26 -0
- package/archetypes/roguelike/assets/audio/bump.wav +0 -0
- package/archetypes/roguelike/assets/audio/drink.wav +0 -0
- package/archetypes/roguelike/assets/audio/fall.wav +0 -0
- package/archetypes/roguelike/assets/audio/hit.wav +0 -0
- package/archetypes/roguelike/assets/audio/hurt.wav +0 -0
- package/archetypes/roguelike/assets/audio/item.wav +0 -0
- package/archetypes/roguelike/assets/audio/kill.wav +0 -0
- package/archetypes/roguelike/assets/audio/pickup.wav +0 -0
- package/archetypes/roguelike/assets/audio/roar.wav +0 -0
- package/archetypes/roguelike/assets/audio/stairs.wav +0 -0
- package/archetypes/roguelike/assets/audio/step.ogt +9 -0
- package/archetypes/roguelike/assets/audio/telegraph.wav +0 -0
- package/archetypes/roguelike/assets/audio/tomb.wav +0 -0
- package/archetypes/roguelike/assets/audio/ui-close.ogt +9 -0
- package/archetypes/roguelike/assets/audio/ui-error.ogt +9 -0
- package/archetypes/roguelike/assets/audio/ui-open.ogt +9 -0
- package/archetypes/roguelike/assets/audio/ui-press.ogt +9 -0
- package/archetypes/roguelike/assets/audio/ui-success.ogt +9 -0
- package/archetypes/roguelike/assets/audio/won.wav +0 -0
- package/archetypes/roguelike/assets/fonts/NotoSansSC-subset.ttf +0 -0
- package/archetypes/roguelike/assets/fonts/NotoSansSC-subset.ttf.ogt +10 -0
- package/archetypes/roguelike/assets/fonts/OFL.txt +93 -0
- package/archetypes/roguelike/assets/maps/dive.ogt +106 -0
- package/archetypes/roguelike/assets/skins/lampdive/DotGothic16-Regular.ttf +0 -0
- package/archetypes/roguelike/assets/skins/lampdive/DotGothic16-Regular.ttf.ogt +9 -0
- package/archetypes/roguelike/assets/skins/lampdive/LICENSES.md +16 -0
- package/archetypes/roguelike/assets/skins/lampdive/OFL.txt +93 -0
- package/archetypes/roguelike/assets/skins/lampdive/atlas.png +0 -0
- package/archetypes/roguelike/assets/skins/lampdive/atlas.png.ogt +7 -0
- package/archetypes/roguelike/assets/skins/lampdive/icons.png +0 -0
- package/archetypes/roguelike/assets/skins/lampdive/icons.png.ogt +7 -0
- package/archetypes/roguelike/assets/skins/lampdive/skin.ogt +115 -0
- package/archetypes/roguelike/assets/sprites/dive.ogt +50 -0
- package/archetypes/roguelike/assets/sprites/dive.png +0 -0
- package/archetypes/roguelike/assets/sprites/dive.png.ogt +7 -0
- package/archetypes/roguelike/assets/sprites/glow.png +0 -0
- package/archetypes/roguelike/assets/sprites/glow.png.ogt +7 -0
- package/archetypes/roguelike/assets/strings/en.ogt +57 -0
- package/archetypes/roguelike/assets/strings/zh-CN.ogt +57 -0
- package/archetypes/roguelike/assets/tiles/tomb.ogt +31 -0
- package/archetypes/roguelike/assets/tiles/tomb.png +0 -0
- package/archetypes/roguelike/assets/tiles/tomb.png.ogt +7 -0
- package/archetypes/roguelike/gitattributes +22 -0
- package/archetypes/roguelike/host.d.ts +46 -0
- package/archetypes/roguelike/package.json +18 -0
- package/archetypes/roguelike/project.ogt +14 -0
- package/archetypes/roguelike/references/metal/dive.png +0 -0
- package/archetypes/roguelike/references/metal/over.png +0 -0
- package/archetypes/roguelike/references/metal/title.png +0 -0
- package/archetypes/roguelike/src/art.ts +23 -0
- package/archetypes/roguelike/src/components.ts +169 -0
- package/archetypes/roguelike/src/dive.ts +144 -0
- package/archetypes/roguelike/src/foes.ts +174 -0
- package/archetypes/roguelike/src/main.ts +258 -0
- package/archetypes/roguelike/src/systems.ts +620 -0
- package/archetypes/roguelike/src/ui.ts +350 -0
- package/archetypes/roguelike/tests/flow.og.ts +54 -0
- package/archetypes/roguelike/tests/foes.og.ts +45 -0
- package/archetypes/roguelike/tests/frames.og.ts +32 -0
- package/archetypes/roguelike/tests/frames.ts +134 -0
- package/archetypes/roguelike/tests/lib.ts +83 -0
- package/archetypes/roguelike/tests/lose.og.ts +44 -0
- package/archetypes/roguelike/tests/pad.og.ts +54 -0
- package/archetypes/roguelike/tests/pause.og.ts +59 -0
- package/archetypes/roguelike/tests/phone.og.ts +54 -0
- package/archetypes/roguelike/tests/replay.og.ts +24 -0
- package/archetypes/roguelike/tests/win.og.ts +60 -0
- package/archetypes/roguelike/tools/make-assets.py +518 -0
- package/archetypes/roguelike/tools/oglite.py +285 -0
- package/archetypes/roguelike/tsconfig.json +17 -0
- package/archetypes/runner/.origin/setup +14 -0
- package/archetypes/runner/LICENSES.md +10 -0
- package/archetypes/runner/README.md +225 -0
- package/archetypes/runner/assets/audio/coin.wav +0 -0
- package/archetypes/runner/assets/audio/crash.wav +0 -0
- package/archetypes/runner/assets/audio/hold.ogt +9 -0
- package/archetypes/runner/assets/audio/jump.wav +0 -0
- package/archetypes/runner/assets/audio/start.wav +0 -0
- package/archetypes/runner/assets/fonts/OFL.txt +93 -0
- package/archetypes/runner/assets/fonts/ui.ttf +0 -0
- package/archetypes/runner/assets/fonts/ui.ttf.ogt +11 -0
- package/archetypes/runner/assets/maps/far.ogt +25 -0
- package/archetypes/runner/assets/maps/near.ogt +25 -0
- package/archetypes/runner/assets/maps/roofs.ogt +19 -0
- package/archetypes/runner/assets/scenes/main.ogt +35 -0
- package/archetypes/runner/assets/sprites/coin.ogt +11 -0
- package/archetypes/runner/assets/sprites/coin.png +0 -0
- package/archetypes/runner/assets/sprites/coin.png.ogt +7 -0
- package/archetypes/runner/assets/sprites/courier.ogt +32 -0
- package/archetypes/runner/assets/sprites/courier.png +0 -0
- package/archetypes/runner/assets/sprites/courier.png.ogt +7 -0
- package/archetypes/runner/assets/sprites/props.ogt +21 -0
- package/archetypes/runner/assets/sprites/props.png +0 -0
- package/archetypes/runner/assets/sprites/props.png.ogt +7 -0
- package/archetypes/runner/assets/sprites/sky.png +0 -0
- package/archetypes/runner/assets/sprites/sky.png.ogt +7 -0
- package/archetypes/runner/assets/tiles/city.ogt +18 -0
- package/archetypes/runner/assets/tiles/city.png +0 -0
- package/archetypes/runner/assets/tiles/city.png.ogt +7 -0
- package/archetypes/runner/gitattributes +22 -0
- package/archetypes/runner/host.d.ts +46 -0
- package/archetypes/runner/package.json +18 -0
- package/archetypes/runner/project.ogt +18 -0
- package/archetypes/runner/references/metal/frames-coin.png +0 -0
- package/archetypes/runner/references/metal/frames-crash.png +0 -0
- package/archetypes/runner/references/metal/frames-title.png +0 -0
- package/archetypes/runner/src/art.ts +57 -0
- package/archetypes/runner/src/components.ts +94 -0
- package/archetypes/runner/src/main.ts +241 -0
- package/archetypes/runner/src/systems.ts +553 -0
- package/archetypes/runner/tests/coins.og.ts +30 -0
- package/archetypes/runner/tests/flow.og.ts +72 -0
- package/archetypes/runner/tests/frames.og.ts +37 -0
- package/archetypes/runner/tests/frames.ts +134 -0
- package/archetypes/runner/tests/jump.og.ts +44 -0
- package/archetypes/runner/tests/lib.ts +42 -0
- package/archetypes/runner/tests/records.og.ts +43 -0
- package/archetypes/runner/tests/replay.og.ts +36 -0
- package/archetypes/runner/tests/sounds.og.ts +43 -0
- package/archetypes/runner/tests/tune.og.ts +36 -0
- package/archetypes/runner/tools/make-assets.py +603 -0
- package/archetypes/runner/tools/oglite.py +285 -0
- package/archetypes/runner/tsconfig.json +17 -0
- package/archetypes/third-person/.origin/setup +14 -0
- package/archetypes/third-person/LICENSES.md +23 -0
- package/archetypes/third-person/README.md +249 -0
- package/archetypes/third-person/assets/ai/sentinel-east.ogt +69 -0
- package/archetypes/third-person/assets/ai/sentinel-north.ogt +69 -0
- package/archetypes/third-person/assets/ai/sentinel-west.ogt +69 -0
- package/archetypes/third-person/assets/anims/humanoid-clips.glb +0 -0
- package/archetypes/third-person/assets/audio/alarm.wav +0 -0
- package/archetypes/third-person/assets/audio/dawn.wav +0 -0
- package/archetypes/third-person/assets/audio/grab.wav +0 -0
- package/archetypes/third-person/assets/audio/ignite.wav +0 -0
- package/archetypes/third-person/assets/audio/jump.wav +0 -0
- package/archetypes/third-person/assets/audio/night.wav +0 -0
- package/archetypes/third-person/assets/audio/splash.wav +0 -0
- package/archetypes/third-person/assets/audio/step.ogt +9 -0
- package/archetypes/third-person/assets/audio/ui-close.ogt +9 -0
- package/archetypes/third-person/assets/audio/ui-error.ogt +9 -0
- package/archetypes/third-person/assets/audio/ui-open.ogt +9 -0
- package/archetypes/third-person/assets/audio/ui-press.ogt +9 -0
- package/archetypes/third-person/assets/audio/ui-success.ogt +9 -0
- package/archetypes/third-person/assets/audio/vale.wav +0 -0
- package/archetypes/third-person/assets/fonts/NotoSansSC-subset.ttf +0 -0
- package/archetypes/third-person/assets/fonts/NotoSansSC-subset.ttf.ogt +10 -0
- package/archetypes/third-person/assets/fonts/OFL.txt +93 -0
- package/archetypes/third-person/assets/fx/burst.ogt +25 -0
- package/archetypes/third-person/assets/fx/fire.ogt +24 -0
- package/archetypes/third-person/assets/fx/smoke.ogt +24 -0
- package/archetypes/third-person/assets/fx/splash.ogt +24 -0
- package/archetypes/third-person/assets/luts/teal-orange.cube +4917 -0
- package/archetypes/third-person/assets/models/stout.glb +0 -0
- package/archetypes/third-person/assets/models/strider.glb +0 -0
- package/archetypes/third-person/assets/models/strider.glb.ogt +9 -0
- package/archetypes/third-person/assets/nav/vale.ogt +43 -0
- package/archetypes/third-person/assets/rigs/strider.ogt +6 -0
- package/archetypes/third-person/assets/skins/ember/Cinzel-Bold.ttf +0 -0
- package/archetypes/third-person/assets/skins/ember/Cinzel-Bold.ttf.ogt +9 -0
- package/archetypes/third-person/assets/skins/ember/LICENSES.md +13 -0
- package/archetypes/third-person/assets/skins/ember/Newsreader-Medium.ttf +0 -0
- package/archetypes/third-person/assets/skins/ember/Newsreader-Medium.ttf.ogt +9 -0
- package/archetypes/third-person/assets/skins/ember/OFL.txt +94 -0
- package/archetypes/third-person/assets/skins/ember/atlas.png +0 -0
- package/archetypes/third-person/assets/skins/ember/atlas.png.ogt +7 -0
- package/archetypes/third-person/assets/skins/ember/icons.png +0 -0
- package/archetypes/third-person/assets/skins/ember/icons.png.ogt +7 -0
- package/archetypes/third-person/assets/skins/ember/skin.ogt +109 -0
- package/archetypes/third-person/assets/strings/en.ogt +47 -0
- package/archetypes/third-person/assets/strings/zh-CN.ogt +47 -0
- package/archetypes/third-person/assets/terrain/vale-control.png +0 -0
- package/archetypes/third-person/assets/terrain/vale.ogt +42 -0
- package/archetypes/third-person/assets/terrain/vale.png +0 -0
- package/archetypes/third-person/assets/textures/decals.png +0 -0
- package/archetypes/third-person/assets/textures/flame.png +0 -0
- package/archetypes/third-person/assets/textures/smoke.png +0 -0
- package/archetypes/third-person/assets/textures/spark.png +0 -0
- package/archetypes/third-person/assets/textures/terrain-grass.png +0 -0
- package/archetypes/third-person/assets/textures/terrain-path.png +0 -0
- package/archetypes/third-person/assets/textures/terrain-rock.png +0 -0
- package/archetypes/third-person/assets/textures/terrain-sand.png +0 -0
- package/archetypes/third-person/gitattributes +22 -0
- package/archetypes/third-person/host.d.ts +46 -0
- package/archetypes/third-person/package.json +18 -0
- package/archetypes/third-person/project.ogt +14 -0
- package/archetypes/third-person/references/metal/beacon.png +0 -0
- package/archetypes/third-person/references/metal/dawn.png +0 -0
- package/archetypes/third-person/references/metal/title.png +0 -0
- package/archetypes/third-person/references/webgl2/beacon.png +0 -0
- package/archetypes/third-person/src/anim.ts +87 -0
- package/archetypes/third-person/src/beacons.ts +80 -0
- package/archetypes/third-person/src/components.ts +148 -0
- package/archetypes/third-person/src/hero.ts +293 -0
- package/archetypes/third-person/src/main.ts +164 -0
- package/archetypes/third-person/src/sentinels.ts +159 -0
- package/archetypes/third-person/src/sound.ts +66 -0
- package/archetypes/third-person/src/ui.ts +451 -0
- package/archetypes/third-person/src/world.ts +212 -0
- package/archetypes/third-person/tests/flow.og.ts +70 -0
- package/archetypes/third-person/tests/frames.og.ts +35 -0
- package/archetypes/third-person/tests/frames.ts +134 -0
- package/archetypes/third-person/tests/hitstop.og.ts +26 -0
- package/archetypes/third-person/tests/lib.ts +87 -0
- package/archetypes/third-person/tests/lose.og.ts +44 -0
- package/archetypes/third-person/tests/pause.og.ts +64 -0
- package/archetypes/third-person/tests/phone.og.ts +65 -0
- package/archetypes/third-person/tests/replay.og.ts +32 -0
- package/archetypes/third-person/tests/restart.og.ts +28 -0
- package/archetypes/third-person/tests/sentinels.og.ts +48 -0
- package/archetypes/third-person/tests/win.og.ts +62 -0
- package/archetypes/third-person/tools/make-assets.py +353 -0
- package/archetypes/third-person/tools/oglite.py +285 -0
- package/archetypes/third-person/tsconfig.json +17 -0
- package/archetypes/topdown/.origin/setup +14 -0
- package/archetypes/topdown/LICENSES.md +10 -0
- package/archetypes/topdown/README.md +235 -0
- package/archetypes/topdown/assets/ai/slime.ogt +49 -0
- package/archetypes/topdown/assets/audio/coin.wav +0 -0
- package/archetypes/topdown/assets/audio/door.wav +0 -0
- package/archetypes/topdown/assets/audio/hit.wav +0 -0
- package/archetypes/topdown/assets/audio/hurt.wav +0 -0
- package/archetypes/topdown/assets/audio/key.wav +0 -0
- package/archetypes/topdown/assets/audio/step.ogt +9 -0
- package/archetypes/topdown/assets/fonts/OFL.txt +93 -0
- package/archetypes/topdown/assets/fonts/ui.ttf +0 -0
- package/archetypes/topdown/assets/fonts/ui.ttf.ogt +9 -0
- package/archetypes/topdown/assets/maps/tomb.tmj +2183 -0
- package/archetypes/topdown/assets/sprites/hero.ogt +58 -0
- package/archetypes/topdown/assets/sprites/hero.png +0 -0
- package/archetypes/topdown/assets/sprites/hero.png.ogt +7 -0
- package/archetypes/topdown/assets/sprites/items.ogt +15 -0
- package/archetypes/topdown/assets/sprites/items.png +0 -0
- package/archetypes/topdown/assets/sprites/items.png.ogt +7 -0
- package/archetypes/topdown/assets/sprites/slime.ogt +17 -0
- package/archetypes/topdown/assets/sprites/slime.png +0 -0
- package/archetypes/topdown/assets/sprites/slime.png.ogt +7 -0
- package/archetypes/topdown/assets/tiles/dungeon.ogt +65 -0
- package/archetypes/topdown/assets/tiles/dungeon.png +0 -0
- package/archetypes/topdown/assets/tiles/dungeon.png.ogt +7 -0
- package/archetypes/topdown/gitattributes +22 -0
- package/archetypes/topdown/host.d.ts +46 -0
- package/archetypes/topdown/package.json +18 -0
- package/archetypes/topdown/project.ogt +14 -0
- package/archetypes/topdown/references/metal/crit.png +0 -0
- package/archetypes/topdown/references/metal/dash.png +0 -0
- package/archetypes/topdown/references/metal/east.png +0 -0
- package/archetypes/topdown/references/metal/start.png +0 -0
- package/archetypes/topdown/src/art.ts +48 -0
- package/archetypes/topdown/src/components.ts +128 -0
- package/archetypes/topdown/src/main.ts +275 -0
- package/archetypes/topdown/src/systems.ts +503 -0
- package/archetypes/topdown/tests/ai.og.ts +64 -0
- package/archetypes/topdown/tests/combat.og.ts +72 -0
- package/archetypes/topdown/tests/door.og.ts +62 -0
- package/archetypes/topdown/tests/flee.og.ts +49 -0
- package/archetypes/topdown/tests/frames.og.ts +45 -0
- package/archetypes/topdown/tests/frames.ts +134 -0
- package/archetypes/topdown/tests/lib.ts +71 -0
- package/archetypes/topdown/tests/replay.og.ts +40 -0
- package/archetypes/topdown/tests/walk.og.ts +46 -0
- package/archetypes/topdown/tools/make-assets.py +623 -0
- package/archetypes/topdown/tools/oglite.py +285 -0
- package/archetypes/topdown/tsconfig.json +17 -0
- package/archetypes/tower-defense/.origin/setup +14 -0
- package/archetypes/tower-defense/LICENSES.md +15 -0
- package/archetypes/tower-defense/README.md +240 -0
- package/archetypes/tower-defense/assets/ai/plant.ogt +16 -0
- package/archetypes/tower-defense/assets/audio/clear.wav +0 -0
- package/archetypes/tower-defense/assets/audio/frost.wav +0 -0
- package/archetypes/tower-defense/assets/audio/leak.wav +0 -0
- package/archetypes/tower-defense/assets/audio/lost.wav +0 -0
- package/archetypes/tower-defense/assets/audio/night.wav +0 -0
- package/archetypes/tower-defense/assets/audio/plant.wav +0 -0
- package/archetypes/tower-defense/assets/audio/pop.wav +0 -0
- package/archetypes/tower-defense/assets/audio/thorn.wav +0 -0
- package/archetypes/tower-defense/assets/audio/ui-close.ogt +9 -0
- package/archetypes/tower-defense/assets/audio/ui-error.ogt +9 -0
- package/archetypes/tower-defense/assets/audio/ui-open.ogt +9 -0
- package/archetypes/tower-defense/assets/audio/ui-press.ogt +9 -0
- package/archetypes/tower-defense/assets/audio/ui-success.ogt +9 -0
- package/archetypes/tower-defense/assets/audio/wave.wav +0 -0
- package/archetypes/tower-defense/assets/audio/won.wav +0 -0
- package/archetypes/tower-defense/assets/fonts/NotoSansSC-subset.ttf +0 -0
- package/archetypes/tower-defense/assets/fonts/NotoSansSC-subset.ttf.ogt +10 -0
- package/archetypes/tower-defense/assets/fonts/OFL.txt +93 -0
- package/archetypes/tower-defense/assets/fx/fireflies.ogt +21 -0
- package/archetypes/tower-defense/assets/fx/pop.ogt +21 -0
- package/archetypes/tower-defense/assets/maps/garden.ogt +91 -0
- package/archetypes/tower-defense/assets/skins/pathguard/Fredoka-SemiBold.ttf +0 -0
- package/archetypes/tower-defense/assets/skins/pathguard/Fredoka-SemiBold.ttf.ogt +9 -0
- package/archetypes/tower-defense/assets/skins/pathguard/LICENSES.md +13 -0
- package/archetypes/tower-defense/assets/skins/pathguard/LilitaOne-Regular.ttf +0 -0
- package/archetypes/tower-defense/assets/skins/pathguard/LilitaOne-Regular.ttf.ogt +9 -0
- package/archetypes/tower-defense/assets/skins/pathguard/OFL.txt +94 -0
- package/archetypes/tower-defense/assets/skins/pathguard/atlas.png +0 -0
- package/archetypes/tower-defense/assets/skins/pathguard/atlas.png.ogt +7 -0
- package/archetypes/tower-defense/assets/skins/pathguard/icons.png +0 -0
- package/archetypes/tower-defense/assets/skins/pathguard/icons.png.ogt +7 -0
- package/archetypes/tower-defense/assets/skins/pathguard/skin.ogt +111 -0
- package/archetypes/tower-defense/assets/sprites/garden.ogt +66 -0
- package/archetypes/tower-defense/assets/sprites/garden.png +0 -0
- package/archetypes/tower-defense/assets/sprites/garden.png.ogt +7 -0
- package/archetypes/tower-defense/assets/sprites/glow.png +0 -0
- package/archetypes/tower-defense/assets/sprites/glow.png.ogt +7 -0
- package/archetypes/tower-defense/assets/sprites/ring.png +0 -0
- package/archetypes/tower-defense/assets/sprites/ring.png.ogt +7 -0
- package/archetypes/tower-defense/assets/sprites/spark.png +0 -0
- package/archetypes/tower-defense/assets/sprites/spark.png.ogt +7 -0
- package/archetypes/tower-defense/assets/strings/en.ogt +47 -0
- package/archetypes/tower-defense/assets/strings/zh-CN.ogt +47 -0
- package/archetypes/tower-defense/assets/tiles/garden.ogt +10 -0
- package/archetypes/tower-defense/assets/tiles/garden.png +0 -0
- package/archetypes/tower-defense/assets/tiles/garden.png.ogt +7 -0
- package/archetypes/tower-defense/gitattributes +22 -0
- package/archetypes/tower-defense/host.d.ts +46 -0
- package/archetypes/tower-defense/package.json +18 -0
- package/archetypes/tower-defense/project.ogt +14 -0
- package/archetypes/tower-defense/references/metal/end.png +0 -0
- package/archetypes/tower-defense/references/metal/title.png +0 -0
- package/archetypes/tower-defense/references/metal/wave.png +0 -0
- package/archetypes/tower-defense/src/art.ts +24 -0
- package/archetypes/tower-defense/src/components.ts +156 -0
- package/archetypes/tower-defense/src/main.ts +253 -0
- package/archetypes/tower-defense/src/systems.ts +658 -0
- package/archetypes/tower-defense/src/ui.ts +382 -0
- package/archetypes/tower-defense/tests/flow.og.ts +56 -0
- package/archetypes/tower-defense/tests/frames.og.ts +31 -0
- package/archetypes/tower-defense/tests/frames.ts +134 -0
- package/archetypes/tower-defense/tests/lib.ts +81 -0
- package/archetypes/tower-defense/tests/lose.og.ts +40 -0
- package/archetypes/tower-defense/tests/maze.og.ts +53 -0
- package/archetypes/tower-defense/tests/pad.og.ts +41 -0
- package/archetypes/tower-defense/tests/pause.og.ts +59 -0
- package/archetypes/tower-defense/tests/phone.og.ts +49 -0
- package/archetypes/tower-defense/tests/replay.og.ts +28 -0
- package/archetypes/tower-defense/tests/win.og.ts +58 -0
- package/archetypes/tower-defense/tools/make-assets.py +640 -0
- package/archetypes/tower-defense/tools/oglite.py +285 -0
- package/archetypes/tower-defense/tsconfig.json +17 -0
- package/bin/create.ts +496 -0
- package/looks/catalogue.json +1871 -0
- package/package.json +31 -4
- package/template/.origin/setup +14 -0
- package/template/LICENSES.md +23 -0
- package/template/README.md +37 -0
- package/template/assets/ai/guard.ogt +48 -0
- package/template/assets/audio/blip.wav +0 -0
- package/template/assets/audio/click.ogt +9 -0
- package/template/assets/fonts/NotoSansSC-Regular-subset.ttf +0 -0
- package/template/assets/fonts/NotoSansSC-Regular-subset.ttf.ogt +12 -0
- package/template/assets/fonts/OFL.txt +93 -0
- package/template/assets/looks/origin-game.ogt +12 -0
- package/template/assets/models/dropship.glb +0 -0
- package/template/assets/models/walker.glb +0 -0
- package/template/assets/nav/yard.ogt +27 -0
- package/template/assets/scenes/main.ogt +34 -0
- package/template/assets/strings/en.ogt +14 -0
- package/template/assets/textures/stone.png +0 -0
- package/template/assets/textures/stone_n.png +0 -0
- package/template/assets/textures/stone_n.png.ogt +7 -0
- package/template/gitattributes +22 -0
- package/template/package.json +18 -0
- package/template/project.ogt +25 -0
- package/template/src/main.ts +246 -0
- package/template/tests/guard.og.ts +67 -0
- package/template/tests/smoke.og.ts +43 -0
- package/template/tsconfig.json +17 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// The door: without the key the doorway's wall cells block the hero; the
|
|
2
|
+
// key is picked up by walking over it; with it the door opens on approach
|
|
3
|
+
// (og.tilemap.setTile clears the wall terrain's cells, re-tiling their
|
|
4
|
+
// neighbours and dropping their colliders), the key is spent, and the hero
|
|
5
|
+
// walks through into the east room.
|
|
6
|
+
import { playtest } from "@origingame/engine/playtest";
|
|
7
|
+
import { hold, MAP, position, report } from "./lib.ts";
|
|
8
|
+
|
|
9
|
+
interface Camera {
|
|
10
|
+
zoneActive: boolean;
|
|
11
|
+
zoneMin: number[];
|
|
12
|
+
zoneFromActive: boolean;
|
|
13
|
+
zoneFromMax: number[];
|
|
14
|
+
zoneScroll: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default playtest({
|
|
18
|
+
name: "the doorway blocks until the key, then opens and leads into room 2",
|
|
19
|
+
commands: [
|
|
20
|
+
"0.1:slime:35:3",
|
|
21
|
+
"0.2:place:17.5:6",
|
|
22
|
+
hold("KeyD", 0.2, 1.0),
|
|
23
|
+
"1.1:dump_entity:hero:locked.json",
|
|
24
|
+
// The key at (16.5, 2.5).
|
|
25
|
+
"1.2:place:15.2:2.3",
|
|
26
|
+
hold("KeyD", 1.2, 1.6),
|
|
27
|
+
"1.7:dump_entity:hero:key.json",
|
|
28
|
+
"1.8:place:17.5:6",
|
|
29
|
+
hold("KeyD", 1.8, 3.2),
|
|
30
|
+
// The camera across the doorway: og.Camera's zone fields every 0.05 s.
|
|
31
|
+
Array.from({ length: 25 }, (_, i) => `${(2 + 0.05 * i).toFixed(2)}:get:og.Camera:cam-${String(i).padStart(2, "0")}.json`).join(";"),
|
|
32
|
+
"3.3:dump_entity:hero:through.json",
|
|
33
|
+
"3.3:screenshot:door.png",
|
|
34
|
+
"3.4:quit",
|
|
35
|
+
]
|
|
36
|
+
.flatMap((s) => s.split(";"))
|
|
37
|
+
// Steps run in time order (a stable sort keeps the order within a time).
|
|
38
|
+
.sort((a, b) => parseFloat(a) - parseFloat(b))
|
|
39
|
+
.join(";"),
|
|
40
|
+
check(run, t) {
|
|
41
|
+
t.equal(run.warnings.join("; "), "", "the script ran without warnings");
|
|
42
|
+
const locked = report(run, "locked.json");
|
|
43
|
+
t.equal(locked.doorOpen, false, "the door stays shut without the key");
|
|
44
|
+
t.ok(locked.doorWall >= 0, `the doorway's cell draws the wall terrain's auto-tiled tile (${locked.doorWall})`);
|
|
45
|
+
t.near(position(run, "locked.json").x, 19 - 0.3, 0.03, "the doorway's wall stops the hero");
|
|
46
|
+
t.equal(locked.room, 1, "still in room 1");
|
|
47
|
+
t.equal(report(run, "key.json").hasKey, true, "walking over the key picks it up");
|
|
48
|
+
const through = report(run, "through.json");
|
|
49
|
+
t.equal(through.doorOpen, true, "the key opened the door");
|
|
50
|
+
t.equal(through.hasKey, false, "the key was spent");
|
|
51
|
+
t.equal(through.doorWall, -1, "the doorway's wall terrain cell is cleared: no tile");
|
|
52
|
+
t.ok(position(run, "through.json").x > MAP.split + 1, `the hero walked through (x ${position(run, "through.json").x.toFixed(2)})`);
|
|
53
|
+
t.equal(through.room, 2, "the hero is in room 2");
|
|
54
|
+
// Crossing into room 2 scrolls the view across over the zone's scrollTime, then settles in room 2's zone.
|
|
55
|
+
const cams = Array.from({ length: 25 }, (_, i) => run.json<{ value: Camera }>(`cam-${String(i).padStart(2, "0")}.json`).value);
|
|
56
|
+
const mid = cams.filter((c) => c.zoneFromActive && c.zoneScroll > 0 && c.zoneScroll < 1);
|
|
57
|
+
t.ok(mid.length >= 3, `the view scrolls between the rooms for several samples (${mid.length})`);
|
|
58
|
+
t.ok(mid.every((c) => c.zoneFromMax[0] <= MAP.split + 0.01 && c.zoneMin[0] >= MAP.split - 0.01), "from room 1's zone into room 2's");
|
|
59
|
+
const last = cams[cams.length - 1]!;
|
|
60
|
+
t.ok(last.zoneActive && !last.zoneFromActive && last.zoneScroll === 1 && last.zoneMin[0] >= MAP.split - 0.01, "and settles in room 2's zone");
|
|
61
|
+
},
|
|
62
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// The slime's senses and its fear (assets/ai/slime.ogt, og.Perception):
|
|
2
|
+
// the pillar in the west room hides the hero 4.5 m away (sight rays stop at
|
|
3
|
+
// the map's wall colliders), stepping out from behind it shows the hero,
|
|
4
|
+
// and a slime under 30 hp keeps away instead of chasing.
|
|
5
|
+
import { playtest } from "@origingame/engine/playtest";
|
|
6
|
+
import { position } from "./lib.ts";
|
|
7
|
+
|
|
8
|
+
interface AiDump {
|
|
9
|
+
path: string;
|
|
10
|
+
sees: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default playtest({
|
|
14
|
+
name: "the pillar hides the hero from the slime, and a hurt slime flees",
|
|
15
|
+
commands: [
|
|
16
|
+
// Behind the pillar (cells 6–7, rows 7–8): the slime east of it, the hero west.
|
|
17
|
+
"0.1:slime:9.5:8",
|
|
18
|
+
"0.1:place:5:8",
|
|
19
|
+
"0.3:dump_ai:slime:hidden.json",
|
|
20
|
+
// The hero steps out below the pillar.
|
|
21
|
+
"0.4:slime:9.5:8",
|
|
22
|
+
"0.4:place:7:5",
|
|
23
|
+
"0.6:dump_ai:slime:visible.json",
|
|
24
|
+
// Hurt: the slime keeps away from a hero 2 m off.
|
|
25
|
+
"1.0:set:slime.Slime.hp=20",
|
|
26
|
+
"1.0:slime:13.5:5",
|
|
27
|
+
"1.0:place:11.5:5",
|
|
28
|
+
"1.3:dump_ai:slime:fear.json",
|
|
29
|
+
"2.2:dump_entity:slime:fled.json",
|
|
30
|
+
"2.2:dump_entity:hero:hero.json",
|
|
31
|
+
"2.3:quit",
|
|
32
|
+
].join(";"),
|
|
33
|
+
check(run, t) {
|
|
34
|
+
t.equal(run.warnings.join("; "), "", "the script ran without warnings");
|
|
35
|
+
const hidden = run.json<AiDump>("hidden.json");
|
|
36
|
+
t.equal(hidden.sees, false, "behind the pillar the hero is hidden, 4.5 m away (inside the slime's 5 m sight)");
|
|
37
|
+
t.ok(hidden.path.includes("patrol"), `so the slime patrols on (${hidden.path})`);
|
|
38
|
+
const visible = run.json<AiDump>("visible.json");
|
|
39
|
+
t.equal(visible.sees, true, "below the pillar the slime sees the hero");
|
|
40
|
+
t.ok(visible.path.includes("chase"), `and chases (${visible.path})`);
|
|
41
|
+
|
|
42
|
+
const fear = run.json<AiDump>("fear.json");
|
|
43
|
+
t.ok(fear.path.includes("flee"), `under 30 hp it flees (${fear.path})`);
|
|
44
|
+
const s = position(run, "fled.json");
|
|
45
|
+
const h = position(run, "hero.json");
|
|
46
|
+
const d = Math.hypot(s.x - h.x, s.y - h.y);
|
|
47
|
+
t.ok(d > 3.5, `and keeps away from the hero (${d.toFixed(2)} m, from 2)`);
|
|
48
|
+
},
|
|
49
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Four frames at 1280×720 compared with references/<tier>/: the west room at
|
|
2
|
+
// rest (tiles, torches over the wall face, shadows, HUD), the crit's freeze
|
|
3
|
+
// frame (white squashed slime, the crit number, the shaken camera), a dash
|
|
4
|
+
// (the hero's afterimages) and the east room through the opened doorway
|
|
5
|
+
// (the re-tiled wall, the camera zone of room 2).
|
|
6
|
+
// `OG_FX_CAPTURE=1 og test .` records this tier's references.
|
|
7
|
+
import { playtest } from "@origingame/engine/playtest";
|
|
8
|
+
import { checkFrames } from "./frames.ts";
|
|
9
|
+
import { press } from "./lib.ts";
|
|
10
|
+
|
|
11
|
+
const setup = (t: number) => `${t}:place:12.3:6.5;${t}:slime:13.4:6.5;${t}:face:right`;
|
|
12
|
+
const FILES = ["start.png", "crit.png", "dash.png", "east.png"];
|
|
13
|
+
|
|
14
|
+
export default playtest({
|
|
15
|
+
name: "the rooms, a crit's freeze frame and a dash match their reference frames",
|
|
16
|
+
size: "1280x720",
|
|
17
|
+
commands: [
|
|
18
|
+
"0.5:screenshot:start.png",
|
|
19
|
+
setup(0.6),
|
|
20
|
+
press("Space", 0.65),
|
|
21
|
+
setup(1.3),
|
|
22
|
+
press("Space", 1.35),
|
|
23
|
+
setup(2.0),
|
|
24
|
+
press("Space", 2.05),
|
|
25
|
+
// The third hit lands on tick 129 and holds seven ticks.
|
|
26
|
+
"2.185:screenshot:crit.png",
|
|
27
|
+
"2.6:place:5:3",
|
|
28
|
+
"2.6:key_down:KeyD",
|
|
29
|
+
press("ShiftLeft", 2.7),
|
|
30
|
+
"2.8:screenshot:dash.png",
|
|
31
|
+
"2.9:key_up:KeyD",
|
|
32
|
+
"3.0:give:door",
|
|
33
|
+
"3.0:place:23:6",
|
|
34
|
+
"3.6:screenshot:east.png",
|
|
35
|
+
"3.7:quit",
|
|
36
|
+
].join(";"),
|
|
37
|
+
check(run, t) {
|
|
38
|
+
t.equal(run.warnings.join("; "), "", "the script ran without warnings");
|
|
39
|
+
t.ok(run.quit, "the script reached quit");
|
|
40
|
+
t.frame(FILES, () => {
|
|
41
|
+
for (const f of FILES) t.equal(run.png(f).width, 1280, `${f} is 1280 wide`);
|
|
42
|
+
});
|
|
43
|
+
checkFrames(run, t, FILES, "");
|
|
44
|
+
},
|
|
45
|
+
});
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// The reference-frame check: decode the PNGs a run wrote and compare them
|
|
2
|
+
// with references/<tier>/ under og-tests' tolerance (a channel off by more
|
|
3
|
+
// than 32/255 is an outlier; fail above 0.5 % outliers or an RGB RMSE above
|
|
4
|
+
// 0.01). A tier without its own references compares with `metal` and says
|
|
5
|
+
// so. `OG_FX_CAPTURE=1 og test .` records this tier's references instead.
|
|
6
|
+
// (Copied from templates/fx-showcase/tests/frames.ts so the archetype stands alone.)
|
|
7
|
+
|
|
8
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
9
|
+
import { dirname, join, resolve } from "node:path";
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
11
|
+
import { inflateSync } from "node:zlib";
|
|
12
|
+
import type { PlaytestChecks, PlaytestRun } from "@origingame/engine/playtest";
|
|
13
|
+
|
|
14
|
+
export interface Image {
|
|
15
|
+
width: number;
|
|
16
|
+
height: number;
|
|
17
|
+
/** RGBA8 rows. */
|
|
18
|
+
rgba: Uint8Array;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** An 8-bit RGB or RGBA, non-interlaced PNG, unfiltered. */
|
|
22
|
+
export function decodePng(bytes: Uint8Array): Image {
|
|
23
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
24
|
+
let at = 8;
|
|
25
|
+
let width = 0;
|
|
26
|
+
let height = 0;
|
|
27
|
+
let channels = 4;
|
|
28
|
+
const idat: Uint8Array[] = [];
|
|
29
|
+
while (at < bytes.length) {
|
|
30
|
+
const len = view.getUint32(at);
|
|
31
|
+
const type = String.fromCharCode(...bytes.subarray(at + 4, at + 8));
|
|
32
|
+
const data = bytes.subarray(at + 8, at + 8 + len);
|
|
33
|
+
if (type === "IHDR") {
|
|
34
|
+
width = view.getUint32(at + 8);
|
|
35
|
+
height = view.getUint32(at + 12);
|
|
36
|
+
const depth = data[8]!;
|
|
37
|
+
const color = data[9]!;
|
|
38
|
+
if (depth !== 8 || (color !== 6 && color !== 2) || data[12] !== 0) throw new Error(`unsupported PNG (depth ${depth}, colour ${color}, interlace ${data[12]})`);
|
|
39
|
+
channels = color === 6 ? 4 : 3;
|
|
40
|
+
} else if (type === "IDAT") idat.push(data);
|
|
41
|
+
else if (type === "IEND") break;
|
|
42
|
+
at += 12 + len;
|
|
43
|
+
}
|
|
44
|
+
const raw = inflateSync(Buffer.concat(idat));
|
|
45
|
+
const stride = width * channels;
|
|
46
|
+
const out = new Uint8Array(width * height * 4);
|
|
47
|
+
const prev = new Uint8Array(stride);
|
|
48
|
+
const cur = new Uint8Array(stride);
|
|
49
|
+
for (let y = 0; y < height; y++) {
|
|
50
|
+
const filter = raw[y * (stride + 1)]!;
|
|
51
|
+
const line = raw.subarray(y * (stride + 1) + 1, (y + 1) * (stride + 1));
|
|
52
|
+
for (let i = 0; i < stride; i++) {
|
|
53
|
+
const a = i >= channels ? cur[i - channels]! : 0;
|
|
54
|
+
const b = prev[i]!;
|
|
55
|
+
const c = i >= channels ? prev[i - channels]! : 0;
|
|
56
|
+
let v = line[i]!;
|
|
57
|
+
if (filter === 1) v += a;
|
|
58
|
+
else if (filter === 2) v += b;
|
|
59
|
+
else if (filter === 3) v += (a + b) >> 1;
|
|
60
|
+
else if (filter === 4) {
|
|
61
|
+
const p = a + b - c;
|
|
62
|
+
const pa = Math.abs(p - a), pb = Math.abs(p - b), pc = Math.abs(p - c);
|
|
63
|
+
v += pa <= pb && pa <= pc ? a : pb <= pc ? b : c;
|
|
64
|
+
}
|
|
65
|
+
cur[i] = v & 255;
|
|
66
|
+
}
|
|
67
|
+
for (let x = 0; x < width; x++) {
|
|
68
|
+
for (let k = 0; k < 4; k++) out[(y * width + x) * 4 + k] = k < channels ? cur[x * channels + k]! : 255;
|
|
69
|
+
}
|
|
70
|
+
prev.set(cur);
|
|
71
|
+
}
|
|
72
|
+
return { width, height, rgba: out };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** og-tests' rule: outlier fraction and RGB RMSE between two equal-size frames. */
|
|
76
|
+
export function difference(a: Image, b: Image): { outliers: number; rmse: number } {
|
|
77
|
+
if (a.width !== b.width || a.height !== b.height) return { outliers: 1, rmse: 1 };
|
|
78
|
+
let outliers = 0;
|
|
79
|
+
let sum = 0;
|
|
80
|
+
const n = a.width * a.height;
|
|
81
|
+
for (let p = 0; p < n; p++) {
|
|
82
|
+
let out = false;
|
|
83
|
+
for (let k = 0; k < 3; k++) {
|
|
84
|
+
const d = Math.abs(a.rgba[p * 4 + k]! - b.rgba[p * 4 + k]!);
|
|
85
|
+
if (d > 32) out = true;
|
|
86
|
+
const f = d / 255;
|
|
87
|
+
sum += f * f;
|
|
88
|
+
}
|
|
89
|
+
if (out) outliers++;
|
|
90
|
+
}
|
|
91
|
+
return { outliers: outliers / n, rmse: Math.sqrt(sum / (n * 3)) };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** The playtest's output directory (the bundled playtest runs from it). */
|
|
95
|
+
export function outDir(): string {
|
|
96
|
+
return dirname(fileURLToPath(import.meta.url));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** The project's references/, from its og-out/test/<name>/. */
|
|
100
|
+
export function referencesDir(): string {
|
|
101
|
+
return resolve(outDir(), "..", "..", "..", "references");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Compares each screenshot with its reference (`<prefix><file>`), or records it. */
|
|
105
|
+
export function checkFrames(run: PlaytestRun, t: PlaytestChecks, files: readonly string[], prefix: string): void {
|
|
106
|
+
// Read only where there is a renderer: without one (tier `none`) each frame is
|
|
107
|
+
// reported "no renderer, frame unchecked" and every other check still runs.
|
|
108
|
+
t.frame(files, () => {
|
|
109
|
+
const refs = referencesDir();
|
|
110
|
+
t.ok(existsSync(refs) || process.env.OG_FX_CAPTURE !== undefined, `the references directory exists at ${refs}`);
|
|
111
|
+
const own = join(refs, run.tier);
|
|
112
|
+
const capture = process.env.OG_FX_CAPTURE !== undefined;
|
|
113
|
+
for (const f of files) {
|
|
114
|
+
const actual = join(outDir(), f);
|
|
115
|
+
// Each file on its own: this tier's reference where it has one, metal's otherwise.
|
|
116
|
+
const mine = join(own, prefix + f);
|
|
117
|
+
const ref = capture || existsSync(mine) ? mine : join(refs, "metal", prefix + f);
|
|
118
|
+
if (ref !== mine) process.stdout.write(` note: no ${run.tier} reference for ${prefix}${f}; comparing with metal\n`);
|
|
119
|
+
if (capture) {
|
|
120
|
+
mkdirSync(own, { recursive: true });
|
|
121
|
+
copyFileSync(actual, ref);
|
|
122
|
+
t.ok(true, `recorded ${ref}`);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (!existsSync(ref)) {
|
|
126
|
+
t.ok(false, `${ref} is missing: record it with OG_FX_CAPTURE=1 og test .`);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const d = difference(decodePng(readFileSync(actual)), decodePng(readFileSync(ref)));
|
|
130
|
+
process.stdout.write(` ${f}: ${(d.outliers * 100).toFixed(3)} % outliers, RMSE ${d.rmse.toFixed(5)} against ${ref}\n`);
|
|
131
|
+
t.ok(d.outliers <= 0.005 && d.rmse <= 0.01, `${f} matches ${prefix}${f}: ${(d.outliers * 100).toFixed(3)} % outliers (≤ 0.5 %), RMSE ${d.rmse.toFixed(5)} (≤ 0.01)`);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Shared readers for Tomb Room's playtests: `dump_entity:<name>:<file>`
|
|
2
|
+
// writes an entity's components; the hero's Report carries the run's facts
|
|
3
|
+
// (src/components.ts says why).
|
|
4
|
+
import type { PlaytestRun } from "@origingame/engine/playtest";
|
|
5
|
+
|
|
6
|
+
export interface Report {
|
|
7
|
+
room: number;
|
|
8
|
+
hp: number;
|
|
9
|
+
coins: number;
|
|
10
|
+
hasKey: boolean;
|
|
11
|
+
doorOpen: boolean;
|
|
12
|
+
enemyHp: number;
|
|
13
|
+
hits: number;
|
|
14
|
+
swings: number;
|
|
15
|
+
steps: number;
|
|
16
|
+
hurts: number;
|
|
17
|
+
facing: number;
|
|
18
|
+
doorWall: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface EntityDump {
|
|
22
|
+
components: Record<string, Record<string, unknown>>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** One component of a dumped entity. */
|
|
26
|
+
export function component<T>(run: PlaytestRun, file: string, name: string): T {
|
|
27
|
+
const dump = run.json<EntityDump>(file);
|
|
28
|
+
const c = dump.components[name];
|
|
29
|
+
if (!c) throw new Error(`${file} has no ${name}: ${Object.keys(dump.components).join(", ")}`);
|
|
30
|
+
return c as unknown as T;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** The hero's Report from a `dump_entity:hero` file. */
|
|
34
|
+
export function report(run: PlaytestRun, file: string): Report {
|
|
35
|
+
return component<Report>(run, file, "Report");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** A dumped entity's position. */
|
|
39
|
+
export function position(run: PlaytestRun, file: string): { x: number; y: number } {
|
|
40
|
+
const p = component<{ position: [number, number, number] }>(run, file, "og.Transform").position;
|
|
41
|
+
return { x: p[0], y: p[1] };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** A dumped entity's scale. */
|
|
45
|
+
export function scale(run: PlaytestRun, file: string): { x: number; y: number } {
|
|
46
|
+
const s = component<{ scale: [number, number, number] }>(run, file, "og.Transform").scale;
|
|
47
|
+
return { x: s[0], y: s[1] };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Facing.* of src/components.ts. */
|
|
51
|
+
export const DOWN = 0;
|
|
52
|
+
export const UP = 1;
|
|
53
|
+
export const LEFT = 2;
|
|
54
|
+
export const RIGHT = 3;
|
|
55
|
+
|
|
56
|
+
/** A key held from t0 to t1 seconds. */
|
|
57
|
+
export const hold = (key: string, t0: number, t1: number) => `${t0}:key_down:${key};${t1}:key_up:${key}`;
|
|
58
|
+
|
|
59
|
+
/** A press (down, up two ticks later): Space swings, ShiftLeft dashes. */
|
|
60
|
+
export const press = (key: string, t: number) => hold(key, t, Number((t + 0.034).toFixed(3)));
|
|
61
|
+
|
|
62
|
+
/** Where the map puts things (world units: the map's bottom-left corner is the origin, y up). */
|
|
63
|
+
export const MAP = {
|
|
64
|
+
spawn: { x: 4.5, y: 5.5 },
|
|
65
|
+
slime: { x: 13.5, y: 6.5 },
|
|
66
|
+
key: { x: 16.5, y: 2.5 },
|
|
67
|
+
/** The doorway: cells 19–20, rows 5–6, so x 19..21, y 5..7. */
|
|
68
|
+
door: { x: 20, y: 6 },
|
|
69
|
+
/** The east room starts here. */
|
|
70
|
+
split: 20,
|
|
71
|
+
} as const;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Determinism: a whole visit (walking past the pillar, four swings of which
|
|
2
|
+
// two land with their hit stops, a coin, the key, the door, the east room,
|
|
3
|
+
// a dash) replayed in two fresh processes ends on the same world hash.
|
|
4
|
+
import { playtest } from "@origingame/engine/playtest";
|
|
5
|
+
import { hold, press, report } from "./lib.ts";
|
|
6
|
+
|
|
7
|
+
export default playtest({
|
|
8
|
+
name: "a whole visit replays to the same hash",
|
|
9
|
+
runs: 2,
|
|
10
|
+
commands: [
|
|
11
|
+
"0.2:key_down:KeyD",
|
|
12
|
+
"0.9:key_down:KeyW",
|
|
13
|
+
"1.3:key_up:KeyW",
|
|
14
|
+
"1.6:key_up:KeyD",
|
|
15
|
+
press("Space", 1.7),
|
|
16
|
+
press("Space", 2.2),
|
|
17
|
+
press("Space", 2.7),
|
|
18
|
+
press("Space", 3.2),
|
|
19
|
+
"3.5:key_down:KeyS",
|
|
20
|
+
"4.0:key_down:KeyD",
|
|
21
|
+
"4.5:key_up:KeyS",
|
|
22
|
+
"5.0:key_up:KeyD",
|
|
23
|
+
"5.1:place:15.2:2.3",
|
|
24
|
+
hold("KeyD", 5.1, 5.5),
|
|
25
|
+
"5.6:place:17.5:6",
|
|
26
|
+
"5.6:key_down:KeyD",
|
|
27
|
+
press("ShiftLeft", 6.8),
|
|
28
|
+
"7.4:key_up:KeyD",
|
|
29
|
+
"7.5:dump_entity:hero:end.json",
|
|
30
|
+
"7.6:quit",
|
|
31
|
+
].join(";"),
|
|
32
|
+
check(run, t) {
|
|
33
|
+
t.equal(run.warnings.join("; "), "", "the script ran without warnings");
|
|
34
|
+
t.equal(run.hashes.length, 2, "two runs");
|
|
35
|
+
t.equal(run.hashes[1], run.hashes[0], `both runs end on hash ${run.hashes[0]}`);
|
|
36
|
+
const end = report(run, "end.json");
|
|
37
|
+
t.equal(end.doorOpen, true, "the visit opened the door");
|
|
38
|
+
t.equal(end.room, 2, "and ended in room 2");
|
|
39
|
+
},
|
|
40
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Walking: the keys move the hero at Tuning.speed, the walk clip's "step"
|
|
2
|
+
// events count footsteps, the facing follows the keys (left is the side row
|
|
3
|
+
// flipped), and the wall terrain's colliders stop the body.
|
|
4
|
+
//
|
|
5
|
+
// The slime waits in the east room, out of sight, so nothing interrupts.
|
|
6
|
+
import { playtest } from "@origingame/engine/playtest";
|
|
7
|
+
import { LEFT, MAP, RIGHT, UP, component, hold, position, report } from "./lib.ts";
|
|
8
|
+
|
|
9
|
+
export default playtest({
|
|
10
|
+
name: "the hero walks at its speed, steps on the walk frames and stops at walls",
|
|
11
|
+
commands: [
|
|
12
|
+
"0.1:slime:35:3",
|
|
13
|
+
// Right for one second from the spawn: 4.5 m at 4.5 m/s.
|
|
14
|
+
hold("KeyD", 0.2, 1.2),
|
|
15
|
+
"1.3:dump_entity:hero:right.json",
|
|
16
|
+
// Up into the top wall (row 0 covers y 11..12; the body's box reaches 0.35 above the feet).
|
|
17
|
+
hold("KeyW", 1.4, 3.0),
|
|
18
|
+
"3.1:dump_entity:hero:up.json",
|
|
19
|
+
// Left along the wall to the west wall (column 0 covers x 0..1; the box is 0.6 wide).
|
|
20
|
+
"3.2:key_down:ArrowLeft",
|
|
21
|
+
"3.6:dump_entity:hero:walking-left.json",
|
|
22
|
+
"3.6:screenshot:walk.png",
|
|
23
|
+
"5.4:key_up:ArrowLeft",
|
|
24
|
+
"5.5:dump_entity:hero:left.json",
|
|
25
|
+
"5.6:quit",
|
|
26
|
+
].join(";"),
|
|
27
|
+
check(run, t) {
|
|
28
|
+
t.equal(run.warnings.join("; "), "", "the script ran without warnings");
|
|
29
|
+
const right = position(run, "right.json");
|
|
30
|
+
t.near(right.x, MAP.spawn.x + 4.5, 0.1, `one second of D walks 4.5 m (x ${right.x.toFixed(3)})`);
|
|
31
|
+
t.near(right.y, MAP.spawn.y, 0.001, "walking right keeps y");
|
|
32
|
+
const r = report(run, "right.json");
|
|
33
|
+
t.equal(r.facing, RIGHT, "the hero faces right");
|
|
34
|
+
t.ok(r.steps >= 3 && r.steps <= 5, `the walk clip's step events fired twice a cycle (${r.steps} steps in 1 s at 8 fps)`);
|
|
35
|
+
const up = position(run, "up.json");
|
|
36
|
+
t.near(up.y, 11 - 0.35, 0.03, `the top wall stops the body (feet at y ${up.y.toFixed(3)}, box top at 11)`);
|
|
37
|
+
t.near(up.x, right.x, 0.01, "walking up keeps x");
|
|
38
|
+
t.equal(report(run, "up.json").facing, UP, "the hero faces up");
|
|
39
|
+
t.equal(component<{ clip: number }>(run, "walking-left.json", "og.Flipbook").clip, 5, "walking left plays walk_side (clip 5)");
|
|
40
|
+
t.equal(component<{ flipX: boolean }>(run, "walking-left.json", "og.Sprite").flipX, true, "facing left flips the side row");
|
|
41
|
+
const left = position(run, "left.json");
|
|
42
|
+
t.near(left.x, 1 + 0.3, 0.03, `the west wall stops the body (x ${left.x.toFixed(3)})`);
|
|
43
|
+
t.equal(report(run, "left.json").facing, LEFT, "the hero faces left");
|
|
44
|
+
t.equal(component<{ clip: number }>(run, "left.json", "og.Flipbook").clip, 2, "standing still shows idle_side (clip 2)");
|
|
45
|
+
},
|
|
46
|
+
});
|