@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,285 @@
|
|
|
1
|
+
"""A tiny, standard-library-only sprite kit for Origin Engine archetypes.
|
|
2
|
+
|
|
3
|
+
It draws antialiased vector shapes into RGBA images (4x4 supersampling),
|
|
4
|
+
writes PNGs, packs sprites into one glTF binary (.glb) of unit quads, one
|
|
5
|
+
mesh and one emissive, alpha-masked material per sprite, and writes 16-bit
|
|
6
|
+
WAV sounds. Everything is a pure function of its inputs, so the assets it
|
|
7
|
+
makes are byte-for-byte reproducible.
|
|
8
|
+
|
|
9
|
+
A sprite quad lies in the xy plane facing +z, 1 x 1 units, centred on the
|
|
10
|
+
origin, with uv (0,0) at the image's top left. Its material is black base
|
|
11
|
+
colour (alpha from the image, for the mask), roughness 1, and the image as
|
|
12
|
+
the emissive texture: with no light, no environment and tone mapping off,
|
|
13
|
+
the frame shows the image's colours exactly.
|
|
14
|
+
"""
|
|
15
|
+
import json, math, struct, wave, zlib
|
|
16
|
+
|
|
17
|
+
SS = 4 # supersamples per axis
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def hex_rgb(h):
|
|
21
|
+
h = h.lstrip("#")
|
|
22
|
+
return tuple(int(h[i:i + 2], 16) for i in (0, 2, 4))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Canvas:
|
|
26
|
+
"""An RGBA canvas; shapes are painted in order with coverage antialiasing.
|
|
27
|
+
Coordinates are in pixels, origin top left, y down."""
|
|
28
|
+
|
|
29
|
+
def __init__(self, w, h):
|
|
30
|
+
self.w, self.h = w, h
|
|
31
|
+
self.px = [[0.0, 0.0, 0.0, 0.0] for _ in range(w * h)] # premultiplied
|
|
32
|
+
|
|
33
|
+
def _paint(self, inside, bbox, colour, alpha=1.0):
|
|
34
|
+
r, g, b = (c / 255.0 for c in hex_rgb(colour))
|
|
35
|
+
x0, y0, x1, y1 = bbox
|
|
36
|
+
x0 = max(0, int(math.floor(x0))); y0 = max(0, int(math.floor(y0)))
|
|
37
|
+
x1 = min(self.w, int(math.ceil(x1))); y1 = min(self.h, int(math.ceil(y1)))
|
|
38
|
+
n = SS * SS
|
|
39
|
+
for y in range(y0, y1):
|
|
40
|
+
for x in range(x0, x1):
|
|
41
|
+
hits = 0
|
|
42
|
+
for sy in range(SS):
|
|
43
|
+
py = y + (sy + 0.5) / SS
|
|
44
|
+
for sx in range(SS):
|
|
45
|
+
if inside(x + (sx + 0.5) / SS, py):
|
|
46
|
+
hits += 1
|
|
47
|
+
if hits == 0:
|
|
48
|
+
continue
|
|
49
|
+
a = alpha * hits / n
|
|
50
|
+
p = self.px[y * self.w + x]
|
|
51
|
+
p[0] = r * a + p[0] * (1 - a)
|
|
52
|
+
p[1] = g * a + p[1] * (1 - a)
|
|
53
|
+
p[2] = b * a + p[2] * (1 - a)
|
|
54
|
+
p[3] = a + p[3] * (1 - a)
|
|
55
|
+
|
|
56
|
+
def rect(self, x, y, w, h, colour, radius=0.0, alpha=1.0):
|
|
57
|
+
rad = min(radius, w / 2, h / 2)
|
|
58
|
+
|
|
59
|
+
def inside(px, py):
|
|
60
|
+
if px < x or px > x + w or py < y or py > y + h:
|
|
61
|
+
return False
|
|
62
|
+
if rad <= 0:
|
|
63
|
+
return True
|
|
64
|
+
cx = min(max(px, x + rad), x + w - rad)
|
|
65
|
+
cy = min(max(py, y + rad), y + h - rad)
|
|
66
|
+
return (px - cx) ** 2 + (py - cy) ** 2 <= rad * rad
|
|
67
|
+
|
|
68
|
+
self._paint(inside, (x, y, x + w, y + h), colour, alpha)
|
|
69
|
+
|
|
70
|
+
def circle(self, cx, cy, r, colour, alpha=1.0):
|
|
71
|
+
self.ellipse(cx, cy, r, r, colour, alpha)
|
|
72
|
+
|
|
73
|
+
def ellipse(self, cx, cy, rx, ry, colour, alpha=1.0):
|
|
74
|
+
def inside(px, py):
|
|
75
|
+
return ((px - cx) / rx) ** 2 + ((py - cy) / ry) ** 2 <= 1.0
|
|
76
|
+
|
|
77
|
+
self._paint(inside, (cx - rx, cy - ry, cx + rx, cy + ry), colour, alpha)
|
|
78
|
+
|
|
79
|
+
def ring(self, cx, cy, r, width, colour, alpha=1.0):
|
|
80
|
+
def inside(px, py):
|
|
81
|
+
d = math.hypot(px - cx, py - cy)
|
|
82
|
+
return r - width <= d <= r
|
|
83
|
+
|
|
84
|
+
self._paint(inside, (cx - r, cy - r, cx + r, cy + r), colour, alpha)
|
|
85
|
+
|
|
86
|
+
def poly(self, pts, colour, alpha=1.0):
|
|
87
|
+
xs = [p[0] for p in pts]; ys = [p[1] for p in pts]
|
|
88
|
+
|
|
89
|
+
def inside(px, py):
|
|
90
|
+
c = False
|
|
91
|
+
j = len(pts) - 1
|
|
92
|
+
for i in range(len(pts)):
|
|
93
|
+
xi, yi = pts[i]; xj, yj = pts[j]
|
|
94
|
+
if (yi > py) != (yj > py) and px < (xj - xi) * (py - yi) / (yj - yi) + xi:
|
|
95
|
+
c = not c
|
|
96
|
+
j = i
|
|
97
|
+
return c
|
|
98
|
+
|
|
99
|
+
self._paint(inside, (min(xs), min(ys), max(xs), max(ys)), colour, alpha)
|
|
100
|
+
|
|
101
|
+
def line(self, x0, y0, x1, y1, width, colour, alpha=1.0):
|
|
102
|
+
dx, dy = x1 - x0, y1 - y0
|
|
103
|
+
ln = math.hypot(dx, dy) or 1.0
|
|
104
|
+
nx, ny = -dy / ln * width / 2, dx / ln * width / 2
|
|
105
|
+
self.poly([(x0 + nx, y0 + ny), (x1 + nx, y1 + ny), (x1 - nx, y1 - ny), (x0 - nx, y0 - ny)], colour, alpha)
|
|
106
|
+
self.circle(x0, y0, width / 2, colour, alpha)
|
|
107
|
+
self.circle(x1, y1, width / 2, colour, alpha)
|
|
108
|
+
|
|
109
|
+
def rgba(self):
|
|
110
|
+
"""Straight-alpha RGBA8 rows. Transparent pixels take the colour of
|
|
111
|
+
the nearest painted pixel (a few dilation passes), so filtering and
|
|
112
|
+
mips never pull a dark fringe into the edge."""
|
|
113
|
+
w, h = self.w, self.h
|
|
114
|
+
col = [None] * (w * h)
|
|
115
|
+
for i, p in enumerate(self.px):
|
|
116
|
+
if p[3] > 0:
|
|
117
|
+
col[i] = (p[0] / p[3], p[1] / p[3], p[2] / p[3])
|
|
118
|
+
for _ in range(8):
|
|
119
|
+
nxt = list(col)
|
|
120
|
+
changed = False
|
|
121
|
+
for y in range(h):
|
|
122
|
+
for x in range(w):
|
|
123
|
+
i = y * w + x
|
|
124
|
+
if col[i] is not None:
|
|
125
|
+
continue
|
|
126
|
+
for dx, dy in ((1, 0), (-1, 0), (0, 1), (0, -1)):
|
|
127
|
+
xx, yy = x + dx, y + dy
|
|
128
|
+
if 0 <= xx < w and 0 <= yy < h and col[yy * w + xx] is not None:
|
|
129
|
+
nxt[i] = col[yy * w + xx]
|
|
130
|
+
changed = True
|
|
131
|
+
break
|
|
132
|
+
col = nxt
|
|
133
|
+
if not changed:
|
|
134
|
+
break
|
|
135
|
+
rows = []
|
|
136
|
+
for y in range(h):
|
|
137
|
+
row = bytearray()
|
|
138
|
+
for x in range(w):
|
|
139
|
+
i = y * w + x
|
|
140
|
+
c = col[i] or (0.0, 0.0, 0.0)
|
|
141
|
+
a = self.px[i][3]
|
|
142
|
+
row += bytes([round(min(1, max(0, c[0])) * 255), round(min(1, max(0, c[1])) * 255),
|
|
143
|
+
round(min(1, max(0, c[2])) * 255), round(min(1, max(0, a)) * 255)])
|
|
144
|
+
rows.append(bytes(row))
|
|
145
|
+
return rows
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def png_bytes(w, h, rows):
|
|
149
|
+
raw = b"".join(b"\x00" + r for r in rows)
|
|
150
|
+
|
|
151
|
+
def chunk(t, d):
|
|
152
|
+
return struct.pack(">I", len(d)) + t + d + struct.pack(">I", zlib.crc32(t + d) & 0xFFFFFFFF)
|
|
153
|
+
|
|
154
|
+
return (b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", struct.pack(">IIBBBBB", w, h, 8, 6, 0, 0, 0))
|
|
155
|
+
+ chunk(b"IDAT", zlib.compress(raw, 9)) + chunk(b"IEND", b""))
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def write_glb(path, sprites):
|
|
159
|
+
"""sprites: list of (name, png bytes, masked). One quad mesh per sprite,
|
|
160
|
+
in list order: GltfInfo.geometries[i] and materials[i] are sprite i."""
|
|
161
|
+
bin_ = bytearray()
|
|
162
|
+
|
|
163
|
+
def add(data, align=4):
|
|
164
|
+
while len(bin_) % align:
|
|
165
|
+
bin_.append(0)
|
|
166
|
+
off = len(bin_)
|
|
167
|
+
bin_.extend(data)
|
|
168
|
+
return off, len(data)
|
|
169
|
+
|
|
170
|
+
pos = struct.pack("<12f", -0.5, -0.5, 0, 0.5, -0.5, 0, 0.5, 0.5, 0, -0.5, 0.5, 0)
|
|
171
|
+
nrm = struct.pack("<12f", *([0, 0, 1] * 4))
|
|
172
|
+
uv = struct.pack("<8f", 0, 1, 1, 1, 1, 0, 0, 0)
|
|
173
|
+
idx = struct.pack("<6H", 0, 1, 2, 0, 2, 3)
|
|
174
|
+
views, accessors = [], []
|
|
175
|
+
for data, target in ((pos, 34962), (nrm, 34962), (uv, 34962), (idx, 34963)):
|
|
176
|
+
o, n = add(data)
|
|
177
|
+
views.append({"buffer": 0, "byteOffset": o, "byteLength": n, "target": target})
|
|
178
|
+
accessors = [
|
|
179
|
+
{"bufferView": 0, "componentType": 5126, "count": 4, "type": "VEC3", "min": [-0.5, -0.5, 0], "max": [0.5, 0.5, 0]},
|
|
180
|
+
{"bufferView": 1, "componentType": 5126, "count": 4, "type": "VEC3"},
|
|
181
|
+
{"bufferView": 2, "componentType": 5126, "count": 4, "type": "VEC2"},
|
|
182
|
+
{"bufferView": 3, "componentType": 5123, "count": 6, "type": "SCALAR"},
|
|
183
|
+
]
|
|
184
|
+
images, textures, materials, meshes, nodes = [], [], [], [], []
|
|
185
|
+
for i, (name, data, masked) in enumerate(sprites):
|
|
186
|
+
o, n = add(data)
|
|
187
|
+
views.append({"buffer": 0, "byteOffset": o, "byteLength": n})
|
|
188
|
+
images.append({"bufferView": len(views) - 1, "mimeType": "image/png", "name": name})
|
|
189
|
+
textures.append({"source": i, "sampler": 0})
|
|
190
|
+
m = {
|
|
191
|
+
"name": name,
|
|
192
|
+
"pbrMetallicRoughness": {"baseColorFactor": [0, 0, 0, 1], "baseColorTexture": {"index": i},
|
|
193
|
+
"metallicFactor": 0, "roughnessFactor": 1},
|
|
194
|
+
"emissiveTexture": {"index": i},
|
|
195
|
+
"emissiveFactor": [1, 1, 1],
|
|
196
|
+
}
|
|
197
|
+
if masked:
|
|
198
|
+
m["alphaMode"] = "MASK"
|
|
199
|
+
m["alphaCutoff"] = 0.5
|
|
200
|
+
materials.append(m)
|
|
201
|
+
meshes.append({"name": name, "primitives": [{"attributes": {"POSITION": 0, "NORMAL": 1, "TEXCOORD_0": 2},
|
|
202
|
+
"indices": 3, "material": i}]})
|
|
203
|
+
nodes.append({"name": name, "mesh": i, "translation": [i * 1.2, 0, 0]})
|
|
204
|
+
while len(bin_) % 4:
|
|
205
|
+
bin_.append(0)
|
|
206
|
+
doc = {
|
|
207
|
+
"asset": {"version": "2.0", "generator": "oglite.py"},
|
|
208
|
+
"scene": 0, "scenes": [{"nodes": list(range(len(nodes)))}], "nodes": nodes, "meshes": meshes,
|
|
209
|
+
"materials": materials, "textures": textures, "images": images,
|
|
210
|
+
"samplers": [{"magFilter": 9729, "minFilter": 9987, "wrapS": 33071, "wrapT": 33071}],
|
|
211
|
+
"accessors": accessors, "bufferViews": views, "buffers": [{"byteLength": len(bin_)}],
|
|
212
|
+
}
|
|
213
|
+
js = json.dumps(doc, separators=(",", ":")).encode()
|
|
214
|
+
while len(js) % 4:
|
|
215
|
+
js += b" "
|
|
216
|
+
out = struct.pack("<III", 0x46546C67, 2, 12 + 8 + len(js) + 8 + len(bin_))
|
|
217
|
+
out += struct.pack("<II", len(js), 0x4E4F534A) + js + struct.pack("<II", len(bin_), 0x004E4942) + bytes(bin_)
|
|
218
|
+
with open(path, "wb") as f:
|
|
219
|
+
f.write(out)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def write_wav(path, samples, rate=22050):
|
|
223
|
+
"""samples: floats in [-1, 1], mono."""
|
|
224
|
+
with wave.open(path, "wb") as w:
|
|
225
|
+
w.setnchannels(1)
|
|
226
|
+
w.setsampwidth(2)
|
|
227
|
+
w.setframerate(rate)
|
|
228
|
+
w.writeframes(b"".join(struct.pack("<h", int(max(-1, min(1, s)) * 32000)) for s in samples))
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def tone(seconds, f0, f1=None, rate=22050, shape="sine", attack=0.005, decay=None, gain=0.6):
|
|
232
|
+
"""A sweep from f0 to f1 Hz with a short attack and an exponential decay."""
|
|
233
|
+
f1 = f0 if f1 is None else f1
|
|
234
|
+
n = int(seconds * rate)
|
|
235
|
+
out, phase = [], 0.0
|
|
236
|
+
decay = decay or seconds / 4
|
|
237
|
+
for i in range(n):
|
|
238
|
+
t = i / rate
|
|
239
|
+
f = f0 + (f1 - f0) * (i / max(1, n - 1))
|
|
240
|
+
phase += 2 * math.pi * f / rate
|
|
241
|
+
if shape == "square":
|
|
242
|
+
s = 1.0 if math.sin(phase) >= 0 else -1.0
|
|
243
|
+
s *= 0.5
|
|
244
|
+
elif shape == "tri":
|
|
245
|
+
s = 2 / math.pi * math.asin(math.sin(phase))
|
|
246
|
+
else:
|
|
247
|
+
s = math.sin(phase)
|
|
248
|
+
env = min(1.0, t / attack) * math.exp(-t / decay)
|
|
249
|
+
out.append(s * env * gain)
|
|
250
|
+
return out
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def noise(seconds, rate=22050, decay=0.08, gain=0.5, seed=1):
|
|
254
|
+
x = seed & 0xFFFFFFFF
|
|
255
|
+
out = []
|
|
256
|
+
for i in range(int(seconds * rate)):
|
|
257
|
+
x ^= (x << 13) & 0xFFFFFFFF; x ^= x >> 17; x ^= (x << 5) & 0xFFFFFFFF
|
|
258
|
+
out.append(((x / 0xFFFFFFFF) * 2 - 1) * math.exp(-(i / rate) / decay) * gain)
|
|
259
|
+
return out
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def mix(*parts):
|
|
263
|
+
n = max(len(p) for p in parts)
|
|
264
|
+
return [sum(p[i] for p in parts if i < len(p)) for i in range(n)]
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def concat(*parts):
|
|
268
|
+
out = []
|
|
269
|
+
for p in parts:
|
|
270
|
+
out.extend(p)
|
|
271
|
+
return out
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def subset_font(src, dst, text):
|
|
275
|
+
"""Subset a TTF to Latin-1 plus `text` (needs fontTools)."""
|
|
276
|
+
from fontTools import subset
|
|
277
|
+
opts = subset.Options()
|
|
278
|
+
opts.name_IDs = ["*"]
|
|
279
|
+
opts.notdef_outline = True
|
|
280
|
+
opts.layout_features = []
|
|
281
|
+
font = subset.load_font(src, opts)
|
|
282
|
+
s = subset.Subsetter(opts)
|
|
283
|
+
s.populate(text="".join(chr(c) for c in range(0x20, 0x7F)) + "".join(chr(c) for c in range(0xA0, 0x100)) + text)
|
|
284
|
+
s.subset(font)
|
|
285
|
+
subset.save_font(font, dst, opts)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "Bundler",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"types": [],
|
|
8
|
+
"strict": true,
|
|
9
|
+
"exactOptionalPropertyTypes": true,
|
|
10
|
+
"noFallthroughCasesInSwitch": true,
|
|
11
|
+
"isolatedModules": true,
|
|
12
|
+
"verbatimModuleSyntax": true,
|
|
13
|
+
"allowImportingTsExtensions": true,
|
|
14
|
+
"noEmit": true
|
|
15
|
+
},
|
|
16
|
+
"include": ["src/**/*.ts", "tests/**/*.ts", "host.d.ts"]
|
|
17
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Prepares this Game's cloud sandbox snapshot: Origin runs it once per
|
|
3
|
+
# snapshot build, in the checkout, without a terminal, for at most 20 minutes,
|
|
4
|
+
# and saves the result for new sandboxes of the Game. Keep it idempotent; it
|
|
5
|
+
# never receives credentials. Only ignored output is kept: node_modules/ and
|
|
6
|
+
# cooked/ (og cook is incremental, so a new sandbox starts cooked).
|
|
7
|
+
set -eu
|
|
8
|
+
if [ -f bun.lock ]; then bun install --frozen-lockfile; else bun install; fi
|
|
9
|
+
og="${ORIGIN_OG_BIN:-og}"
|
|
10
|
+
if ! command -v "$og" >/dev/null 2>&1; then
|
|
11
|
+
echo "no og on this executor class; the first og run cooks instead"
|
|
12
|
+
exit 0
|
|
13
|
+
fi
|
|
14
|
+
"$og" cook .
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Asset licences
|
|
2
|
+
|
|
3
|
+
| File | Licence | Origin |
|
|
4
|
+
|---|---|---|
|
|
5
|
+
| `assets/tiles/garden.png`, `assets/tiles/*.ogt` | CC0 1.0 | self-made: the night garden's tileset (grass, hedge, stone, gate, doorstep, pads, flowers) drawn with antialiased shapes by `tools/make-assets.py` (standard library only, deterministic), with its tileset and import settings |
|
|
6
|
+
| `assets/maps/garden.ogt` | CC0 1.0 | self-made: the 9 × 13 field, same script |
|
|
7
|
+
| `assets/sprites/*.png`, `assets/sprites/*.ogt` | CC0 1.0 | self-made: the visitors, plants, lantern, shots and cursor sheet, the range ring, the spark and the glow, same script |
|
|
8
|
+
| `assets/fx/*.ogt` | CC0 1.0 | self-made: the pop and fireflies emitters, same script |
|
|
9
|
+
| `assets/ai/plant.ogt` | CC0 1.0 | self-made: the plants' behaviour |
|
|
10
|
+
| `assets/audio/*.wav` | CC0 1.0 | self-made: synthesised tones, noise and the night music loop, same script |
|
|
11
|
+
| `assets/audio/*.ogt` | CC0 1.0 | `og sfx` presets (click, select, back, error, levelup) that `og cook` synthesises, written by the same script |
|
|
12
|
+
| `assets/strings/*.ogt` | CC0 1.0 | self-made: the English and Chinese string tables |
|
|
13
|
+
| `assets/fonts/NotoSansSC-subset.ttf` | SIL Open Font License 1.1 (`assets/fonts/OFL.txt`) | Noto Sans SC Regular, subset to Latin-1 and the characters of `assets/strings/zh-CN.ogt` by the same script from the project template's `assets/fonts/NotoSansSC-Regular-subset.ttf` |
|
|
14
|
+
| `assets/skins/pathguard/*` | CC0 1.0 art, SIL OFL 1.1 fonts | the engine's cartoon style pack (`templates/ui-kit/assets/skins/cartoon`, `assets/skins/pathguard/LICENSES.md`) with this game's palette |
|
|
15
|
+
| `references/*/*.png` | CC0 1.0 | frames of this game recorded by `tests/frames.og.ts` |
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# Path Guard — the tower-defense archetype (2D)
|
|
2
|
+
|
|
3
|
+
A night garden. Visitors (beetles, moths, snails) come through the gate in
|
|
4
|
+
the hedge and walk to the lantern on the doorstep; you set plants on the
|
|
5
|
+
lawn to turn them away. Thorns shoot, frost lilies slow, hedges only block,
|
|
6
|
+
and every plant re-routes the visitors, who always take the shortest way
|
|
7
|
+
round what stands on the lawn. Five waves; the lantern's light is gone
|
|
8
|
+
after ten visitors get through.
|
|
9
|
+
|
|
10
|
+
小径守卫:夜里的花园,甲虫、飞蛾和蜗牛从树篱的门进来,走向门口台阶上的灯笼。在草地上种植物把它们劝走:荆棘射击,霜百合减速,树篱只挡路;每种下一株,来客都会绕开它重新找最短的路。五波来客,有十个走到门口,灯就灭了。
|
|
11
|
+
|
|
12
|
+
This is a complete Origin Engine project: `og run .` plays it headless,
|
|
13
|
+
`og build .` makes the play page, `og test .` runs its playtests and
|
|
14
|
+
`og polish .` scores them. It rebuilds the platform's retired Discover
|
|
15
|
+
prototype *Bloomguard* (花园守夜人) on the engine: its night garden, its
|
|
16
|
+
three plant roles (one shoots, one supports, one walls) and its lesson that
|
|
17
|
+
a kill's time must scale with the walk's, but as a mazing defence on a
|
|
18
|
+
flow field rather than lanes, and none of its code or art.
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
og cook . # assets/ into cooked/ (og run and og build cook too)
|
|
22
|
+
og run . --headless --commands "0.3:begin;0.5:plant:thorn:3:4;0.5:plant:hedge:4:4;6:screenshot:wave.png;6.1:quit"
|
|
23
|
+
og test . # tests/*.og.ts through og run --headless --commands
|
|
24
|
+
og polish . # the playtests scored against og-taste and og-feel
|
|
25
|
+
og build . --publish # dist/: the play page as it ships
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## What it demonstrates, and the skills it exercises
|
|
29
|
+
|
|
30
|
+
- **Crowds on a flow field** (og-ai §1, §2): one `og.nav.flowField` over a
|
|
31
|
+
grid made from the map's colliding layer (`og.nav.gridFromTilemap`)
|
|
32
|
+
serves every visitor; each `og.NavAgent` follows it to the doorstep with
|
|
33
|
+
`faceMovement` turning the sprite. A plant is `og.nav.setCost(…, 0)` on
|
|
34
|
+
its cell and the field rebuilds; a plant that would close the path for
|
|
35
|
+
the gate or any visitor on the lawn is found with `og.nav.findPath` and
|
|
36
|
+
refused before it costs anything.
|
|
37
|
+
- **Targeting as data** (og-ai §3, §4): a shooting plant is an `og.AiAgent`
|
|
38
|
+
running `assets/ai/plant.ogt` (set, reloaded, sees a visitor → the
|
|
39
|
+
game's `fire` command) with an `og.Perception` of its range all round;
|
|
40
|
+
the visitors are `og.Perceivable`. Damage, frost and the shot stay in the
|
|
41
|
+
game (`fire` in `src/systems.ts`).
|
|
42
|
+
- **Towers on a tilemap** (og-game §8): `assets/maps/garden.ogt` is a
|
|
43
|
+
hand-written tilemap whose `walls` layer collides; the `pads` layer starts
|
|
44
|
+
empty and `og.tilemap.setTile` writes the plant's pad on its cell, so the
|
|
45
|
+
map itself remembers what grows where.
|
|
46
|
+
- **Waves and an economy**: five waves of visitors in data (`WAVES`), a
|
|
47
|
+
break between them that an early call (N, Y, or the Next wave button)
|
|
48
|
+
turns into coins, bounties, a wave bonus, prices in `Tuning`.
|
|
49
|
+
- **Shots on tweens** (og-feel §6): a shot is a pooled sprite on an
|
|
50
|
+
`og.tween.sequence` whose `tag` names the target's pool slot and the
|
|
51
|
+
plant's kind; the hit lands on the tick `og.TweenCompleted` reports it.
|
|
52
|
+
- **Feel** (og-feel §3–§7): a pop is a coin count (`og.render.floatingText`),
|
|
53
|
+
a burst of petals (`og.ParticleSystem` with `startTick`), a pitch-varied
|
|
54
|
+
sound and a light hit stop at most every 10 ticks; a visitor at the
|
|
55
|
+
doorstep is a red number, a 6-tick hit stop, trauma and a kick, the
|
|
56
|
+
lantern flashing red and squashing. Plants pop up when set and squash
|
|
57
|
+
when they shoot.
|
|
58
|
+
- **Screens on og.ui with a skin** (og-ui §2–§6, og-taste §1–§7): the
|
|
59
|
+
engine's cartoon pack recoloured as `assets/skins/pathguard` (cream
|
|
60
|
+
panels on the night lawn, the lantern's orange as the one accent); the
|
|
61
|
+
title (`og.ui.mainMenu`), the HUD as capsules in the corners with
|
|
62
|
+
counting numbers (`og.ui.counter`), the plant tray (right on a wide
|
|
63
|
+
screen, along the bottom on a phone), `og.ui.pauseMenu`, a settings
|
|
64
|
+
dialog and the end card built from widgets (stars landing with
|
|
65
|
+
`og.ui.burst`, the score counting up), an iris between screens (a fade
|
|
66
|
+
with reduced motion), a refused plant shaking the purse with the error
|
|
67
|
+
sound (`og.ui.shake`).
|
|
68
|
+
- **Sound** (og-audio §1–§5): a voice per event, the UI's sounds from
|
|
69
|
+
`og sfx` presets, a night music loop on the music bus ducked under the
|
|
70
|
+
effects (`og.AudioBusFx`).
|
|
71
|
+
- **Languages** (og-i18n §1–§5): every string is a key of
|
|
72
|
+
`assets/strings/en.ogt` and `zh-CN.ogt`; the settings switch with
|
|
73
|
+
`og.i18n.setLocale`; the Chinese font is Noto Sans SC subset to exactly
|
|
74
|
+
the table's characters.
|
|
75
|
+
- **The platform** (og-platform-sdk §1–§4): settings through
|
|
76
|
+
`loadSettings`/`saveSettings`, the best score read on tick 0 and written
|
|
77
|
+
at the revision read, the board and a `round.over` event.
|
|
78
|
+
|
|
79
|
+
`og polish .` (2026-10-19, og and the native addon built release from
|
|
80
|
+
this checkout, load 16–18): taste 99, feel 100, in
|
|
81
|
+
`tests/evidence/P2/archetypes/tower-defense/` of the engine repository.
|
|
82
|
+
The same playtests at load 25–50 scored feel 80–89, frame time's p95
|
|
83
|
+
following the machine's load (`tests/evidence/P2/archetypes/frame-time.md`).
|
|
84
|
+
|
|
85
|
+
## Rules
|
|
86
|
+
|
|
87
|
+
- **Plants.** Pick one on the tray (or 1, 2, 3; the pad's X cycles), then
|
|
88
|
+
tap a lawn cell (or move the cursor with the arrows, WASD or the d-pad
|
|
89
|
+
and press Space, Enter or A). It costs its price at once and stands
|
|
90
|
+
until the round ends.
|
|
91
|
+
|
|
92
|
+
| Plant | Price | Does |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| Thorn | 50 | shoots the nearest visitor within 2.8 m: 14 every 30 ticks |
|
|
95
|
+
| Frost lily | 70 | shoots the nearest within 2.2 m: 5 every 60 ticks, and frosts it to half speed for 2 s |
|
|
96
|
+
| Hedge | 10 | blocks the cell: the maze's wall |
|
|
97
|
+
|
|
98
|
+
- **Refusals.** A cell inside the hedge that is not a stone and holds no
|
|
99
|
+
plant and no visitor takes a plant, if the purse covers it and the gate
|
|
100
|
+
and every visitor can still reach the doorstep. Otherwise nothing is
|
|
101
|
+
spent; a red line says why and the purse shakes.
|
|
102
|
+
- **Visitors.** They walk the flow field to the doorstep. Beetles (34 hp,
|
|
103
|
+
1.3 m/s, 6 coins), moths (22 hp, 2.1 m/s, 5 coins), snails (140 hp,
|
|
104
|
+
0.75 m/s, 20 coins, three lights). Each wave's are 20 % tougher than the
|
|
105
|
+
last's.
|
|
106
|
+
- **Waves.** The first comes 3 s after Play; then a wave comes after the
|
|
107
|
+
last one's visitors are all gone and an 8 s break. Calling it early pays
|
|
108
|
+
2 coins a second saved. A wave cleared pays 20 + 5 × its number.
|
|
109
|
+
- **The end.** Ten lights gone ends the round lost; the fifth wave cleared
|
|
110
|
+
ends it won, with one to three stars by the light left. The score is
|
|
111
|
+
kills × 10 + light × 50 + coins left.
|
|
112
|
+
|
|
113
|
+
Everything is deterministic from the project seed: the clock is the fixed
|
|
114
|
+
tick, og.nav, og.ai, tweens and particles are deterministic and in
|
|
115
|
+
snapshots, and `tests/replay.og.ts` replays a round to the same hash.
|
|
116
|
+
|
|
117
|
+
## How it feels
|
|
118
|
+
|
|
119
|
+
| Moment | What happens | Where |
|
|
120
|
+
|---|---|---|
|
|
121
|
+
| a plant set | it pops up (squash 0.6 × 1.5 over 0.25 s), a wooden thunk on the ui bus | `Plants`, `place` |
|
|
122
|
+
| a refusal | a red line over the cell, the purse shakes with the error sound | `place`, `hud` |
|
|
123
|
+
| a shot | the plant's shooting frame and a 1.15 × 0.85 squash, a pitch-varied pluck or chime | `fire` |
|
|
124
|
+
| a hit | the visitor flashes white for 0.08 s; frost tints it blue and slows its legs | `Visitors` |
|
|
125
|
+
| a pop | `+6` in gold rising, a burst of petals, a pop, a 2-tick hit stop (at most one per 10 ticks) | `pop` |
|
|
126
|
+
| a leak | `-1` in red at the lantern, a 6-tick hit stop, trauma 0.4 and a kick down, the lantern flashes red and squashes, a low bell | `leak` |
|
|
127
|
+
| a wave | `Wave 3` over the gate, a horn; cleared: `Wave cleared +35` and an arpeggio | `startWave`, `Visitors` |
|
|
128
|
+
| the end | an iris to the end card, stars landing one by one with bursts, the score counting up | `endCard` |
|
|
129
|
+
|
|
130
|
+
## State
|
|
131
|
+
|
|
132
|
+
| Type | Kind | What it holds |
|
|
133
|
+
|---|---|---|
|
|
134
|
+
| `Game` | resource | the phase, the light, the purse, the wave clock, the counts (kills, leaks, plants, refusals, shots), the cursor, the score and the best, the cells visitors stand on, sound requests, the grid, field and map handles |
|
|
135
|
+
| `Tuning` | resource | the knobs below |
|
|
136
|
+
| `Prefs` | resource | the volumes, the language, reduced motion, the settings request |
|
|
137
|
+
| `Bed` | one row per lawn cell | whether a plant stands there, its kind, its reload, its shots |
|
|
138
|
+
| `Visitor` | the 24 pooled visitors | slot, kind, health, speed, frost, the pop |
|
|
139
|
+
| `Shot` | the 24 pooled shots | the tween carrying it |
|
|
140
|
+
| `Cursor` | the cursor | its moves |
|
|
141
|
+
| `Sfx` | one row per sound | its `Sound.*` bit, its plays |
|
|
142
|
+
|
|
143
|
+
## Systems (in tick order)
|
|
144
|
+
|
|
145
|
+
| System | Job |
|
|
146
|
+
|---|---|
|
|
147
|
+
| `Control` | the cursor, the tray keys, placements by key, pad and tap, the next wave, pause; draws the cursor and the range |
|
|
148
|
+
| `Plants` | switches on the rows of cells planted this tick (the pads tile names the plant), reloads, sight from `Tuning`, the shooting clip back to the sway; clears the rows for a new round |
|
|
149
|
+
| `Visitors` | the wave clock and the gate, shots landing (`og.TweenCompleted`), frost, health bars, pops, leaks, the cells visitors stand on, the end of a wave and of the round |
|
|
150
|
+
| `Ui` | the screens, the camera framed for the surface, the buses, the platform's answers |
|
|
151
|
+
| `Voices` | plays each requested sound once |
|
|
152
|
+
|
|
153
|
+
og.ai runs before them (the plants' decisions, whose `fire` commands run
|
|
154
|
+
before the next tick) and og.nav after them (walking the visitors).
|
|
155
|
+
|
|
156
|
+
## Tunables (`Tuning`)
|
|
157
|
+
|
|
158
|
+
| Field | Default | What it changes |
|
|
159
|
+
|---|---|---|
|
|
160
|
+
| `startGold`, `startLives` | 150, 10 | the purse and the light at Play |
|
|
161
|
+
| `waveBreak`, `spawnGap` | 8 s, 1 s | the break between waves, the gap between visitors |
|
|
162
|
+
| `hpGrowth` | 0.2 | how much tougher each wave's visitors are |
|
|
163
|
+
| `thornCost`, `thornDamage`, `thornReload`, `thornRange` | 50, 14, 30 ticks, 2.8 m | the thorn |
|
|
164
|
+
| `frostCost`, `frostDamage`, `frostReload`, `frostRange`, `frostSlow`, `frostTicks` | 70, 5, 60 ticks, 2.2 m, 0.5, 120 ticks | the frost lily |
|
|
165
|
+
| `hedgeCost` | 10 | the hedge |
|
|
166
|
+
| `shotSpeed` | 11 m/s | how fast shots fly (so how far they lead their targets) |
|
|
167
|
+
| `killStop`, `leakStop`, `leakShake` | 2, 6 ticks, 0.4 | the weight of a pop and of a leak |
|
|
168
|
+
|
|
169
|
+
The visitors' numbers are `KINDS` and the waves `WAVES` in `src/systems.ts`.
|
|
170
|
+
|
|
171
|
+
## What a Maker changes first
|
|
172
|
+
|
|
173
|
+
1. **The waves**: `WAVES` (one letter per visitor: b, m, s) and `KINDS`.
|
|
174
|
+
2. **The plants**: their numbers in `Tuning`; a fourth plant is a clip in
|
|
175
|
+
`tools/make-assets.py`, a pad tile, a `PLANTS` entry and a case in
|
|
176
|
+
`fire`.
|
|
177
|
+
3. **The field**: `MAP` in `tools/make-assets.py` (H hedge, R stone, G the
|
|
178
|
+
gate, D the doorstep), then `python3 tools/make-assets.py && og cook .`.
|
|
179
|
+
4. **The look**: `assets/skins/pathguard/skin.ogt`'s palette and the art
|
|
180
|
+
in `tools/make-assets.py`.
|
|
181
|
+
5. **Words**: `assets/strings/*.ogt`; a new Chinese string needs the
|
|
182
|
+
script run again to subset the font.
|
|
183
|
+
|
|
184
|
+
## Commands (for scripts and agents)
|
|
185
|
+
|
|
186
|
+
| Action | Does |
|
|
187
|
+
|---|---|
|
|
188
|
+
| `begin` | starts a round, as Play does |
|
|
189
|
+
| `plant:<thorn\|frost\|hedge>:<x>:<y>` | sets a plant on a map cell (column, row from the top) as a placement does, refusals included |
|
|
190
|
+
| `gold:<n>` | sets the purse |
|
|
191
|
+
| `wave:<n>` | skips to the break before wave n |
|
|
192
|
+
| `lose`, `win` | puts the lantern out; ends the round won |
|
|
193
|
+
| `viewport:<desktop\|phone>` | lays the UI out for a phone in portrait (390 × 844 at 3×) |
|
|
194
|
+
| `language:<en\|zh-CN>` | switches the language |
|
|
195
|
+
| `fire:<plant>` | the plants' behaviour command (og.ai sends it) |
|
|
196
|
+
| core actions | `touch_move_to:play`, `Plant#1/Pick`, `Next`, `Pause`, `Retry`, `Menu`; keys `1`–`3`, arrows, `Space`, `N`, `Escape`; `gamepad:a` … |
|
|
197
|
+
|
|
198
|
+
`facts` (the probe's `state()`) reports the phase, the wave, the light
|
|
199
|
+
(`lives`), the purse, `kills`, `leaks`, `placed`, `refused` and why, `shots`,
|
|
200
|
+
the visitors walking, the selected plant, the cursor, the score and the
|
|
201
|
+
best, and the language. The playtests read the same values from the `Game`
|
|
202
|
+
resource with `get:Game`.
|
|
203
|
+
|
|
204
|
+
## Playtests (`og test .`)
|
|
205
|
+
|
|
206
|
+
| File | Proves |
|
|
207
|
+
|---|---|
|
|
208
|
+
| `tests/flow.og.ts` | Play by tap; a hedge picked on the tray and tapped onto the lawn; two thorns set by keys; the first wave walks the field at a beetle's pace, is shot and pays its bounties |
|
|
209
|
+
| `tests/maze.og.ts` | a row of hedges leaves one gap and the first visitor crosses through it only; a hedge closing the gap, a stone, a taken cell and an empty purse are refused and cost nothing |
|
|
210
|
+
| `tests/lose.og.ts` | unguarded, visitors reach the doorstep, the light runs out, the end card, Play again starts round two with the light back |
|
|
211
|
+
| `tests/win.og.ts` | a stand holds the last wave called early with N; the win, the score, the best written at the revision read, the board, the telemetry, Title |
|
|
212
|
+
| `tests/pause.og.ts` | Escape holds the garden (time scale 0); settings switch to 简体中文 and move the music; Done saves through og.platform; Resume |
|
|
213
|
+
| `tests/pad.og.ts` | a gamepad alone starts, moves, plants, picks, calls, pauses and resumes |
|
|
214
|
+
| `tests/phone.og.ts` | 390 × 844 at 3×: the tray along the bottom with touch-sized buttons inside the safe area, the pause button below the notch |
|
|
215
|
+
| `tests/frames.og.ts` | the title, a wave in a small maze and the end card match `references/<tier>/` (`OG_FX_CAPTURE=1 og test .` records them) |
|
|
216
|
+
| `tests/replay.og.ts` | a round with taps, keys, shots, frost and pops, run twice, ends on one hash |
|
|
217
|
+
|
|
218
|
+
Each one fails when the behaviour it names is broken (one was broken on
|
|
219
|
+
purpose and restored: `tests/evidence/P2/archetypes/break-and-restore.md`
|
|
220
|
+
in the engine repository).
|
|
221
|
+
|
|
222
|
+
## Assets
|
|
223
|
+
|
|
224
|
+
`tools/make-assets.py` regenerates every asset byte for byte (two runs
|
|
225
|
+
give the same bytes): the tileset, the map, the sprite sheet, the glow and
|
|
226
|
+
particle textures and emitters, the sounds and the music, the `og sfx`
|
|
227
|
+
preset files of the UI's sounds, and the font subset. `LICENSES.md` lists
|
|
228
|
+
them; the skin's are in `assets/skins/pathguard/LICENSES.md`.
|
|
229
|
+
|
|
230
|
+
## Known limits (engine gaps, not design)
|
|
231
|
+
|
|
232
|
+
- og.ui's `settingsScreen` and `resultsScreen` carried English labels of
|
|
233
|
+
their own ("Master", "Done", "Best", "New best") when this game was
|
|
234
|
+
written, so it builds its settings dialog and its end card from widgets to
|
|
235
|
+
keep every string in its tables (both now take a field for each of their
|
|
236
|
+
words: og-i18n §2).
|
|
237
|
+
- A system may only `world.get`/`world.set` the components its query
|
|
238
|
+
declares, and declaring one narrows the query, so a placement is written
|
|
239
|
+
to the map's pads layer and the `Plants` system, which owns the plant
|
|
240
|
+
rows, switches the row on in the same tick.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type behaviour
|
|
2
|
+
version 1
|
|
3
|
+
---
|
|
4
|
+
# A shooting plant's mind (og.ai): when it is set, reloaded and sees a
|
|
5
|
+
# visitor (og.Perception: the nearest within its range), it raises the
|
|
6
|
+
# game's `fire` command with its own handle. Damage, frost and the shot are
|
|
7
|
+
# the game's (src/systems.ts `fire`); the reload is the plant's Bed.cool.
|
|
8
|
+
name "plant"
|
|
9
|
+
tree {
|
|
10
|
+
sequence shoot {
|
|
11
|
+
check Bed.planted
|
|
12
|
+
check Bed.cool atMost 0
|
|
13
|
+
check sees
|
|
14
|
+
command fire
|
|
15
|
+
}
|
|
16
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|