@origingame/create-game 0.2.0 → 0.4.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 +2 -2
- package/archetypes/README.md +2 -1
- package/archetypes/arena/.origin/setup +14 -0
- package/archetypes/arena/LICENSES.md +8 -0
- package/archetypes/arena/README.md +67 -0
- package/archetypes/arena/assets/audio/coin.ogt +9 -0
- package/archetypes/arena/assets/audio/dash.ogt +9 -0
- package/archetypes/arena/assets/audio/win.ogt +9 -0
- package/archetypes/arena/assets/fx/coin.ogt +20 -0
- package/archetypes/arena/assets/looks/arena.ogt +10 -0
- package/archetypes/arena/gitattributes +22 -0
- package/archetypes/arena/gitignore +8 -0
- package/archetypes/arena/host.d.ts +46 -0
- package/archetypes/arena/package.json +18 -0
- package/archetypes/arena/project.ogt +14 -0
- package/archetypes/arena/src/game.ts +314 -0
- package/archetypes/arena/src/main.ts +100 -0
- package/archetypes/arena/tests/duel.og.ts +32 -0
- package/archetypes/arena/tests/solo.og.ts +22 -0
- package/archetypes/arena/tsconfig.json +17 -0
- package/archetypes/idle/LICENSES.md +1 -1
- package/archetypes/idle/README.md +5 -5
- package/archetypes/idle/assets/looks/idle.ogt +2 -2
- package/archetypes/idle/assets/{skins → styles}/sparkorb/LICENSES.md +6 -6
- package/archetypes/idle/assets/{skins/sparkorb/skin.ogt → styles/sparkorb/style.ogt} +47 -47
- package/archetypes/idle/package.json +1 -1
- package/archetypes/idle/project.ogt +1 -1
- 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 +1 -1
- package/archetypes/idle/src/main.ts +5 -5
- package/archetypes/idle/src/ui.ts +13 -13
- package/archetypes/idle/tools/make-assets.py +5 -5
- package/archetypes/match3/package.json +1 -1
- package/archetypes/match3/project.ogt +1 -1
- package/archetypes/rhythm/LICENSES.md +1 -1
- package/archetypes/rhythm/README.md +5 -5
- package/archetypes/rhythm/assets/{skins → styles}/lanebeat/LICENSES.md +6 -6
- package/archetypes/rhythm/assets/{skins/lanebeat/skin.ogt → styles/lanebeat/style.ogt} +45 -45
- package/archetypes/rhythm/package.json +1 -1
- package/archetypes/rhythm/project.ogt +1 -1
- package/archetypes/rhythm/references/metal/results.png +0 -0
- package/archetypes/rhythm/references/metal/title.png +0 -0
- package/archetypes/rhythm/src/components.ts +1 -1
- package/archetypes/rhythm/src/main.ts +3 -3
- package/archetypes/rhythm/src/ui.ts +12 -12
- package/archetypes/roguelike/LICENSES.md +1 -1
- package/archetypes/roguelike/README.md +5 -5
- package/archetypes/roguelike/assets/{skins → styles}/lampdive/LICENSES.md +6 -6
- package/archetypes/roguelike/assets/{skins/lampdive/skin.ogt → styles/lampdive/style.ogt} +41 -41
- package/archetypes/roguelike/package.json +1 -1
- package/archetypes/roguelike/project.ogt +1 -1
- package/archetypes/roguelike/references/metal/over.png +0 -0
- package/archetypes/roguelike/references/metal/title.png +0 -0
- package/archetypes/roguelike/src/components.ts +1 -1
- package/archetypes/roguelike/src/main.ts +2 -2
- package/archetypes/roguelike/src/ui.ts +8 -8
- package/archetypes/runner/package.json +1 -1
- package/archetypes/runner/project.ogt +1 -1
- package/archetypes/third-person/LICENSES.md +1 -1
- package/archetypes/third-person/README.md +4 -4
- package/archetypes/third-person/assets/{skins → styles}/ember/LICENSES.md +4 -4
- package/archetypes/third-person/assets/{skins/ember/skin.ogt → styles/ember/style.ogt} +40 -41
- package/archetypes/third-person/package.json +1 -1
- package/archetypes/third-person/project.ogt +1 -1
- 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/components.ts +1 -1
- package/archetypes/third-person/src/main.ts +3 -3
- package/archetypes/third-person/src/sound.ts +1 -1
- package/archetypes/third-person/src/ui.ts +11 -11
- package/archetypes/topdown/package.json +1 -1
- package/archetypes/topdown/project.ogt +1 -1
- package/archetypes/tower-defense/LICENSES.md +1 -1
- package/archetypes/tower-defense/README.md +5 -5
- package/archetypes/tower-defense/assets/{skins → styles}/pathguard/LICENSES.md +4 -4
- package/archetypes/tower-defense/assets/styles/pathguard/atlas.png +0 -0
- package/archetypes/tower-defense/assets/styles/pathguard/style.ogt +111 -0
- package/archetypes/tower-defense/package.json +1 -1
- package/archetypes/tower-defense/project.ogt +1 -1
- 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/components.ts +1 -1
- package/archetypes/tower-defense/src/main.ts +2 -2
- package/archetypes/tower-defense/src/ui.ts +20 -18
- package/bin/create.ts +11 -8
- package/looks/catalogue.json +40 -40
- package/package.json +2 -2
- package/template/README.md +2 -1
- package/template/assets/audio/sting.ogt +10 -0
- package/template/assets/timelines/intro.ogt +101 -0
- package/template/assets/timelines/narration.srt +11 -0
- package/template/host.d.ts +46 -0
- package/template/package.json +1 -1
- package/template/project.ogt +1 -1
- package/template/references/metal/intro-4.png +0 -0
- package/template/references/metal/intro-8.png +0 -0
- package/template/src/main.ts +1 -1
- package/template/tests/frames.ts +134 -0
- package/template/tests/intro.og.ts +65 -0
- package/template/tests/smoke.og.ts +30 -36
- package/template/tsconfig.json +1 -1
- package/template-2d/LICENSES.md +1 -0
- package/template-2d/README.md +6 -2
- package/template-2d/assets/rigs/keeper.ogt +292 -0
- package/template-2d/assets/rigs/keeper.png +0 -0
- package/template-2d/assets/rigs/keeper.png.ogt +7 -0
- package/template-2d/package.json +1 -1
- package/template-2d/project.ogt +1 -1
- package/template-2d/src/main.ts +240 -4
- package/template-2d/tests/keeper.og.ts +178 -0
- package/archetypes/tower-defense/assets/skins/pathguard/atlas.png +0 -0
- package/archetypes/tower-defense/assets/skins/pathguard/skin.ogt +0 -111
- /package/archetypes/idle/assets/{skins → styles}/sparkorb/ChakraPetch-BoldItalic.ttf +0 -0
- /package/archetypes/idle/assets/{skins → styles}/sparkorb/ChakraPetch-BoldItalic.ttf.ogt +0 -0
- /package/archetypes/idle/assets/{skins → styles}/sparkorb/OFL.txt +0 -0
- /package/archetypes/idle/assets/{skins → styles}/sparkorb/Orbitron-Medium.ttf +0 -0
- /package/archetypes/idle/assets/{skins → styles}/sparkorb/Orbitron-Medium.ttf.ogt +0 -0
- /package/archetypes/idle/assets/{skins → styles}/sparkorb/Rajdhani-Bold.ttf +0 -0
- /package/archetypes/idle/assets/{skins → styles}/sparkorb/Rajdhani-Bold.ttf.ogt +0 -0
- /package/archetypes/idle/assets/{skins → styles}/sparkorb/atlas.png +0 -0
- /package/archetypes/idle/assets/{skins → styles}/sparkorb/atlas.png.ogt +0 -0
- /package/archetypes/idle/assets/{skins → styles}/sparkorb/icons.png +0 -0
- /package/archetypes/idle/assets/{skins → styles}/sparkorb/icons.png.ogt +0 -0
- /package/archetypes/rhythm/assets/{skins → styles}/lanebeat/ChakraPetch-Medium.ttf +0 -0
- /package/archetypes/rhythm/assets/{skins → styles}/lanebeat/ChakraPetch-Medium.ttf.ogt +0 -0
- /package/archetypes/rhythm/assets/{skins → styles}/lanebeat/JetBrainsMono-Regular.ttf +0 -0
- /package/archetypes/rhythm/assets/{skins → styles}/lanebeat/JetBrainsMono-Regular.ttf.ogt +0 -0
- /package/archetypes/rhythm/assets/{skins → styles}/lanebeat/OFL.txt +0 -0
- /package/archetypes/rhythm/assets/{skins → styles}/lanebeat/Orbitron-Bold.ttf +0 -0
- /package/archetypes/rhythm/assets/{skins → styles}/lanebeat/Orbitron-Bold.ttf.ogt +0 -0
- /package/archetypes/rhythm/assets/{skins → styles}/lanebeat/atlas.png +0 -0
- /package/archetypes/rhythm/assets/{skins → styles}/lanebeat/atlas.png.ogt +0 -0
- /package/archetypes/rhythm/assets/{skins → styles}/lanebeat/icons.png +0 -0
- /package/archetypes/rhythm/assets/{skins → styles}/lanebeat/icons.png.ogt +0 -0
- /package/archetypes/roguelike/assets/{skins → styles}/lampdive/DotGothic16-Regular.ttf +0 -0
- /package/archetypes/roguelike/assets/{skins → styles}/lampdive/DotGothic16-Regular.ttf.ogt +0 -0
- /package/archetypes/roguelike/assets/{skins → styles}/lampdive/OFL.txt +0 -0
- /package/archetypes/roguelike/assets/{skins → styles}/lampdive/atlas.png +0 -0
- /package/archetypes/roguelike/assets/{skins → styles}/lampdive/atlas.png.ogt +0 -0
- /package/archetypes/roguelike/assets/{skins → styles}/lampdive/icons.png +0 -0
- /package/archetypes/roguelike/assets/{skins → styles}/lampdive/icons.png.ogt +0 -0
- /package/archetypes/third-person/assets/{skins → styles}/ember/Cinzel-Bold.ttf +0 -0
- /package/archetypes/third-person/assets/{skins → styles}/ember/Cinzel-Bold.ttf.ogt +0 -0
- /package/archetypes/third-person/assets/{skins → styles}/ember/Newsreader-Medium.ttf +0 -0
- /package/archetypes/third-person/assets/{skins → styles}/ember/Newsreader-Medium.ttf.ogt +0 -0
- /package/archetypes/third-person/assets/{skins → styles}/ember/OFL.txt +0 -0
- /package/archetypes/third-person/assets/{skins → styles}/ember/atlas.png +0 -0
- /package/archetypes/third-person/assets/{skins → styles}/ember/atlas.png.ogt +0 -0
- /package/archetypes/third-person/assets/{skins → styles}/ember/icons.png +0 -0
- /package/archetypes/third-person/assets/{skins → styles}/ember/icons.png.ogt +0 -0
- /package/archetypes/tower-defense/assets/{skins → styles}/pathguard/Fredoka-SemiBold.ttf +0 -0
- /package/archetypes/tower-defense/assets/{skins → styles}/pathguard/Fredoka-SemiBold.ttf.ogt +0 -0
- /package/archetypes/tower-defense/assets/{skins → styles}/pathguard/LilitaOne-Regular.ttf +0 -0
- /package/archetypes/tower-defense/assets/{skins → styles}/pathguard/LilitaOne-Regular.ttf.ogt +0 -0
- /package/archetypes/tower-defense/assets/{skins → styles}/pathguard/OFL.txt +0 -0
- /package/archetypes/tower-defense/assets/{skins → styles}/pathguard/atlas.png.ogt +0 -0
- /package/archetypes/tower-defense/assets/{skins → styles}/pathguard/icons.png +0 -0
- /package/archetypes/tower-defense/assets/{skins → styles}/pathguard/icons.png.ogt +0 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// The lamp keeper's playtest (og-game §8, 2D skeletons): the rig plays its
|
|
2
|
+
// idle clip (its event counted as breaths) with both legs' IK targets on
|
|
3
|
+
// the ramp and reached; `keeper:7` sends it walking up the ramp with its
|
|
4
|
+
// walk clip, facing the way it goes, one foot planted on the plank while
|
|
5
|
+
// the other swings above it; it arrives, faces the spawn and breathes again
|
|
6
|
+
// with both feet planted, higher. Every tick from the command to the end
|
|
7
|
+
// is dumped: the turns take several ticks, and no foot ever moves further
|
|
8
|
+
// in a tick than the gait's own swing does, setting off and stopping
|
|
9
|
+
// included; the idle clip comes back only once both feet are down.
|
|
10
|
+
import { playtest } from "@origingame/engine/playtest";
|
|
11
|
+
|
|
12
|
+
interface Got<T> {
|
|
13
|
+
value: T;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type Fields = Record<string, number | boolean | string | number[]>;
|
|
17
|
+
|
|
18
|
+
interface EntityDump {
|
|
19
|
+
components: Record<string, Fields>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** The ramp's top at x (src/main.ts's RAMP), plus the ankle's height. */
|
|
23
|
+
const ankleY = (x: number): number => 2 + 0.21256 * (x - 4.5) + 0.12;
|
|
24
|
+
/** The plank's ends and the highest a swinging foot lifts (src/main.ts's RAMP and WALK). */
|
|
25
|
+
const PLANK = { x0: 4.5, x1: 7.6 } as const;
|
|
26
|
+
const LIFT = 0.08;
|
|
27
|
+
/** The rig's clips, in file order. */
|
|
28
|
+
const IDLE = 0;
|
|
29
|
+
const WALK = 1;
|
|
30
|
+
/**
|
|
31
|
+
* The most a foot moves in a 60 Hz tick: the gait's swing at its start,
|
|
32
|
+
* worked out by hand from src/main.ts's WALK and RAMP. Forward twice the
|
|
33
|
+
* walking speed, 1 m/s; up the 0.21256 slope at that, plus the lift's
|
|
34
|
+
* parabola at its steepest, 4 x 0.08 m over the swing's half cycle of
|
|
35
|
+
* 0.4 s (2.5 per second of its parameter), 0.8 m/s: 1.01256 m/s. Together
|
|
36
|
+
* 1.42316 m/s, 0.023719 m a tick.
|
|
37
|
+
*/
|
|
38
|
+
const STRIDE_STEP = 0.023719;
|
|
39
|
+
/** The ticks dumped every tick: from just before `keeper:7` (2.2 s) to the end (5 s). */
|
|
40
|
+
const FIRST = 130;
|
|
41
|
+
const LAST = 300;
|
|
42
|
+
const perTick = Array.from({ length: LAST - FIRST + 1 }, (_, i) => {
|
|
43
|
+
const k = FIRST + i;
|
|
44
|
+
const at = (j: number) => (k / 60 + 0.002 * j).toFixed(4);
|
|
45
|
+
return `${at(1)}:dump_entity:keeper:k${k}.json;${at(2)}:dump_entity:keeper-leg-f:f${k}.json;${at(3)}:dump_entity:keeper-leg-b:b${k}.json`;
|
|
46
|
+
}).join(";");
|
|
47
|
+
|
|
48
|
+
export default playtest({
|
|
49
|
+
name: "The lamp keeper breathes on its ramp with both feet planted, walks up the slope stepping on the plank, and stands planted again",
|
|
50
|
+
commands: [
|
|
51
|
+
"1.0:screenshot:keeper.png;1.01:dump_entity:keeper:keeper.json;1.02:dump_entity:keeper-leg-f:front.json;1.03:dump_entity:keeper-leg-b:back.json",
|
|
52
|
+
"2.1:get:Game:game.json;2.2:keeper:7",
|
|
53
|
+
"2.85:screenshot:walk.png;2.851:dump_entity:keeper:walk.json;2.852:dump_entity:keeper-leg-f:walk-front.json;2.853:dump_entity:keeper-leg-b:walk-back.json",
|
|
54
|
+
"3.15:dump_entity:keeper:walk-later.json;3.151:dump_entity:keeper-leg-f:walk-front-later.json;3.152:dump_entity:keeper-leg-b:walk-back-later.json",
|
|
55
|
+
perTick,
|
|
56
|
+
"5.1:dump_entity:keeper:keeper-up.json;5.11:dump_entity:keeper-leg-f:front-up.json;5.12:dump_entity:keeper-leg-b:back-up.json;5.2:get:Game:game-end.json;5.3:quit",
|
|
57
|
+
]
|
|
58
|
+
.join(";")
|
|
59
|
+
.split(";")
|
|
60
|
+
.sort((a, b) => Number(a.split(":")[0]) - Number(b.split(":")[0]))
|
|
61
|
+
.join(";"),
|
|
62
|
+
check(run, t) {
|
|
63
|
+
t.ok(run.quit, "the script reached quit");
|
|
64
|
+
for (const png of ["keeper.png", "walk.png"]) {
|
|
65
|
+
t.frame(png, () => {
|
|
66
|
+
const frame = run.png(png);
|
|
67
|
+
t.ok(frame.width > 0 && frame.height > 0, `a ${frame.width}x${frame.height} frame was captured`);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
const skeleton = (file: string) => run.json<EntityDump>(file).components["og.Skeleton2D"]!;
|
|
71
|
+
const at = (file: string) => (run.json<EntityDump>(file).components["og.Transform"]!["position"] as number[])[0]!;
|
|
72
|
+
const foot = (file: string) => run.json<EntityDump>(file).components["og.IkTarget2D"]!;
|
|
73
|
+
|
|
74
|
+
// Standing: the idle clip, both feet on the ramp under the keeper.
|
|
75
|
+
const idle = skeleton("keeper.json");
|
|
76
|
+
t.ok(idle["clip"] === IDLE && (idle["time"] as number) > 0.9 && (idle["time"] as number) < 1.1, `the idle clip plays (clip ${idle["clip"]}, time ${idle["time"]})`);
|
|
77
|
+
for (const [file, label, dx, x0] of [["front.json", "front", -0.15, 6], ["back.json", "back", 0.15, 6], ["front-up.json", "front after the walk", -0.15, 7], ["back-up.json", "back after the walk", 0.15, 7]] as const) {
|
|
78
|
+
const ik = foot(file);
|
|
79
|
+
const target = ik["target"] as number[];
|
|
80
|
+
const x = x0 + dx;
|
|
81
|
+
t.ok(Math.abs(target[0]! - x) < 1e-4 && Math.abs(target[1]! - ankleY(x)) < 1e-4, `the ${label} foot's target is on the ramp (${target.join(", ")})`);
|
|
82
|
+
t.ok(ik["reached"] === true, `the ${label} foot reached it (error ${ik["error"]})`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Walking: the walk clip, facing up the ramp, the keeper between where it was and where it goes.
|
|
86
|
+
let planted = 0;
|
|
87
|
+
for (const [keeper, front, back] of [["walk.json", "walk-front.json", "walk-back.json"], ["walk-later.json", "walk-front-later.json", "walk-back-later.json"]] as const) {
|
|
88
|
+
const s = skeleton(keeper);
|
|
89
|
+
const x = at(keeper);
|
|
90
|
+
t.ok(s["clip"] === WALK && s["flipX"] === false, `walking, the keeper plays its walk clip facing right (clip ${s["clip"]}, flipX ${s["flipX"]})`);
|
|
91
|
+
t.ok(x > 6 && x < 7, `walking, it is part of the way along the ramp (x ${x})`);
|
|
92
|
+
for (const [file, label] of [[front, "front"], [back, "back"]] as const) {
|
|
93
|
+
const ik = foot(file);
|
|
94
|
+
const [fx, fy] = ik["target"] as [number, number];
|
|
95
|
+
const lift = fy - ankleY(fx);
|
|
96
|
+
t.ok(fx > PLANK.x0 && fx < PLANK.x1 && lift > -1e-4 && lift <= LIFT + 1e-4, `walking, the ${label} foot is on the plank or above it (x ${fx}, ${lift.toFixed(4)} up)`);
|
|
97
|
+
t.ok(ik["reached"] === true, `walking, the ${label} foot reached its target (error ${ik["error"]})`);
|
|
98
|
+
if (Math.abs(lift) < 1e-4) planted += 1;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
t.ok(planted >= 2, `while it walks a foot stays planted on the plank (${planted} of 4 targets on it)`);
|
|
102
|
+
// The back foot carried the keeper from 2.85 s to 3.15 s (the walk starts after the turn): it did not move.
|
|
103
|
+
const before = foot("walk-back.json")["target"] as number[];
|
|
104
|
+
const later = foot("walk-back-later.json")["target"] as number[];
|
|
105
|
+
t.ok(Math.abs(before[0]! - later[0]!) < 1e-4 && Math.abs(before[1]! - later[1]!) < 1e-4, `the planted foot stays put while the keeper passes over it (${before.join(", ")} then ${later.join(", ")})`);
|
|
106
|
+
|
|
107
|
+
// Arrived: idle again, facing the spawn, at x 7.
|
|
108
|
+
const up = skeleton("keeper-up.json");
|
|
109
|
+
t.ok(up["clip"] === IDLE && up["flipX"] === true && Math.abs(at("keeper-up.json") - 7) < 1e-4, `it arrived at 7 and breathes facing the spawn (clip ${up["clip"]}, x ${at("keeper-up.json")})`);
|
|
110
|
+
|
|
111
|
+
// Tick by tick: the keeper's scale x, facing, clip and place, and each foot's target.
|
|
112
|
+
const ticks = Array.from({ length: LAST - FIRST + 1 }, (_, i) => {
|
|
113
|
+
const k = FIRST + i;
|
|
114
|
+
const keeper = run.json<EntityDump>(`k${k}.json`).components;
|
|
115
|
+
const s = keeper["og.Skeleton2D"]!;
|
|
116
|
+
return {
|
|
117
|
+
k,
|
|
118
|
+
x: (keeper["og.Transform"]!["position"] as number[])[0]!,
|
|
119
|
+
squash: (keeper["og.Transform"]!["scale"] as number[])[0]!,
|
|
120
|
+
flipX: s["flipX"] === true,
|
|
121
|
+
clip: s["clip"] as number,
|
|
122
|
+
feet: [`f${k}.json`, `b${k}.json`].map((f) => foot(f)["target"] as number[]),
|
|
123
|
+
};
|
|
124
|
+
});
|
|
125
|
+
// No foot moves further in a tick than the gait's swing: setting off, walking, stopping and both turns.
|
|
126
|
+
let worst = 0;
|
|
127
|
+
let worstAt = 0;
|
|
128
|
+
for (let i = 1; i < ticks.length; i++) {
|
|
129
|
+
for (const f of [0, 1]) {
|
|
130
|
+
const [a, b] = [ticks[i - 1]!.feet[f]!, ticks[i]!.feet[f]!];
|
|
131
|
+
const d = Math.hypot(b[0]! - a[0]!, b[1]! - a[1]!);
|
|
132
|
+
if (d > worst) [worst, worstAt] = [d, ticks[i]!.k];
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
t.ok(worst <= STRIDE_STEP + 1e-6, `no foot moves more than a gait tick's ${STRIDE_STEP} m in one tick (at most ${worst.toFixed(6)} m, tick ${worstAt})`);
|
|
136
|
+
// The walk itself moves the swinging foot nearly that far, so the bound is the gait's, not a loose one.
|
|
137
|
+
t.ok(worst > STRIDE_STEP * 0.9, `the walk's swing reaches the bound (${worst.toFixed(6)} m)`);
|
|
138
|
+
// Each turn: several ticks of a narrowed rig (never edge-on), standing still, between one facing and the other.
|
|
139
|
+
const turns: { from: number; to: number; ticks: number; still: boolean; steady: boolean }[] = [];
|
|
140
|
+
for (let i = 1; i < ticks.length; i++) {
|
|
141
|
+
if (ticks[i]!.flipX === ticks[i - 1]!.flipX) continue;
|
|
142
|
+
let j = i - 1;
|
|
143
|
+
while (j > 0 && ticks[j]!.squash !== 1) j--;
|
|
144
|
+
const span = ticks.slice(j, i + 1);
|
|
145
|
+
turns.push({
|
|
146
|
+
from: ticks[j]!.k,
|
|
147
|
+
to: ticks[i]!.k,
|
|
148
|
+
ticks: i - j - 1,
|
|
149
|
+
still: span.every((u) => Math.abs(u.x - span[0]!.x) < 1e-6),
|
|
150
|
+
steady: span.every((u, n) => u.squash !== 0 && (n === 0 || Math.abs(u.squash * (u.flipX ? -1 : 1) - span[n - 1]!.squash * (span[n - 1]!.flipX ? -1 : 1)) <= 0.5)),
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
t.ok(turns.length === 2, `the keeper turned twice: setting off and on arrival (${turns.length})`);
|
|
154
|
+
for (const u of turns) {
|
|
155
|
+
t.ok(u.ticks >= 4 && u.still && u.steady, `a turn (ticks ${u.from} to ${u.to}) narrows the rig over ${u.ticks} ticks in place, never edge-on or by half its width at once`);
|
|
156
|
+
}
|
|
157
|
+
// The stop: the idle clip returns only with both feet down on the ramp, where they stand.
|
|
158
|
+
const back = ticks.findIndex((u, i) => i > 0 && u.clip === IDLE && ticks[i - 1]!.clip !== IDLE);
|
|
159
|
+
t.ok(back > 0, `the idle clip came back (tick ${ticks[back]?.k})`);
|
|
160
|
+
if (back > 0) {
|
|
161
|
+
const u = ticks[back]!;
|
|
162
|
+
for (const [f, dx] of [[0, -0.15], [1, 0.15]] as const) {
|
|
163
|
+
const [fx, fy] = u.feet[f]!;
|
|
164
|
+
t.ok(Math.abs(fx! - (u.x + dx)) < 1e-4 && Math.abs(fy! - ankleY(fx!)) < 1e-4, `when idle returns, foot ${f} is down where it stands (${fx}, ${fy})`);
|
|
165
|
+
}
|
|
166
|
+
const arrived = ticks.findIndex((v) => Math.abs(v.x - 7) < 1e-6);
|
|
167
|
+
t.ok(arrived > 0 && back - arrived > 1, `between arriving (tick ${ticks[arrived]?.k}) and breathing (tick ${u.k}) the feet land and the keeper turns`);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// A loop of 2 s from tick 0 to 2.1 s passed its event at 0 and at 2; the walk
|
|
171
|
+
// (2 s at 0.5 m/s, a step every 0.4 s) stepped 5 times, and the idle clip
|
|
172
|
+
// started over on arrival with a breath.
|
|
173
|
+
const game = run.json<Got<{ inhales: number }>>("game.json").value;
|
|
174
|
+
t.ok(game.inhales === 2, `og.Skeleton2DEvent counted two breaths before the walk (${game.inhales})`);
|
|
175
|
+
const end = run.json<Got<{ inhales: number; steps: number }>>("game-end.json").value;
|
|
176
|
+
t.ok(end.steps === 5 && end.inhales === 3, `the walk clip's events counted 5 steps, then a third breath (${end.steps}, ${end.inhales})`);
|
|
177
|
+
},
|
|
178
|
+
});
|
|
Binary file
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
type skin
|
|
2
|
-
version 1
|
|
3
|
-
---
|
|
4
|
-
# Path Guard's skin: the engine's cartoon style pack (templates/ui-kit/tools/make-skins.py; CC0 art, OFL fonts;
|
|
5
|
-
# LICENSES.md) in a night-garden palette: cream panels on the dark lawn, the lantern's orange as the one accent.
|
|
6
|
-
name "pathguard"
|
|
7
|
-
base light
|
|
8
|
-
atlas "skins/pathguard/atlas.png" 384 256
|
|
9
|
-
scale 1
|
|
10
|
-
palette {
|
|
11
|
-
bg "#10231a"
|
|
12
|
-
bgSubtle "#15301f"
|
|
13
|
-
surface "#fff4dc"
|
|
14
|
-
surfaceRaised "#fff4dc"
|
|
15
|
-
surfaceHover "#ffe9bd"
|
|
16
|
-
materialThick "#fff4dcf5"
|
|
17
|
-
materialRegular "#fff4dcee"
|
|
18
|
-
materialThin "#fff4dce0"
|
|
19
|
-
fg "#0f1a14"
|
|
20
|
-
fgMuted "#3a483f"
|
|
21
|
-
fgSubtle "#45534a"
|
|
22
|
-
fgInverse "#fff4dc"
|
|
23
|
-
fill "#ffe08a"
|
|
24
|
-
fillStrong "#ffd466"
|
|
25
|
-
border "#20302a"
|
|
26
|
-
borderStrong "#20302a"
|
|
27
|
-
accent "#b44c0d"
|
|
28
|
-
accentHover "#ab480c"
|
|
29
|
-
accentActive "#a0430b"
|
|
30
|
-
accentFg "#fff4dc"
|
|
31
|
-
accentInk "#a8400a"
|
|
32
|
-
accentSoft "#ff8c3a40"
|
|
33
|
-
focus "#5cb6e8"
|
|
34
|
-
thumb "#ffffff"
|
|
35
|
-
scrim "#07120ccc"
|
|
36
|
-
success "#06681b"
|
|
37
|
-
warn "#7b5102"
|
|
38
|
-
danger "#700b1c"
|
|
39
|
-
info "#2256af"
|
|
40
|
-
shadow "#0b1a1299"
|
|
41
|
-
}
|
|
42
|
-
radius {
|
|
43
|
-
control 12
|
|
44
|
-
field 14
|
|
45
|
-
block 14
|
|
46
|
-
card 18
|
|
47
|
-
panel 28
|
|
48
|
-
sheet 28
|
|
49
|
-
button 9999
|
|
50
|
-
}
|
|
51
|
-
ramp {
|
|
52
|
-
body 15 20
|
|
53
|
-
meta 13 18
|
|
54
|
-
caption 13 18
|
|
55
|
-
lg 19 26
|
|
56
|
-
xl 22 28
|
|
57
|
-
xl2 26 30
|
|
58
|
-
xl3 30 34
|
|
59
|
-
displaySm 32 36
|
|
60
|
-
displayMd 40 44
|
|
61
|
-
displayLg 52 56
|
|
62
|
-
}
|
|
63
|
-
durations {
|
|
64
|
-
instant 110
|
|
65
|
-
fast 160
|
|
66
|
-
base 280
|
|
67
|
-
slow 420
|
|
68
|
-
}
|
|
69
|
-
fonts {
|
|
70
|
-
body "skins/pathguard/Fredoka-SemiBold.ttf"
|
|
71
|
-
display "skins/pathguard/LilitaOne-Regular.ttf"
|
|
72
|
-
numeric "skins/pathguard/LilitaOne-Regular.ttf"
|
|
73
|
-
fallback "fonts/NotoSansSC-subset.ttf"
|
|
74
|
-
}
|
|
75
|
-
icons "skins/pathguard/icons.png" 8 4 {
|
|
76
|
-
names "heart" "star" "coin" "lock" "pause" "gear" "sword" "shield" "potion" "gem" "key" "map" "bolt" "clock" "trophy" "home" "plus" "close" "check" "play" "back" "bag" "bomb" "crown" "flag" "apple" "leaf" "fire" "drop" "skull" "music" "person"
|
|
77
|
-
}
|
|
78
|
-
slice panel 4 4 96 96 30 tint
|
|
79
|
-
slice card 104 4 64 64 20 tint
|
|
80
|
-
slice button 172 4 48 48 20 tint
|
|
81
|
-
slice buttonHover 224 4 48 48 20 tint
|
|
82
|
-
slice buttonPressed 276 4 48 48 20 tint
|
|
83
|
-
slice buttonDisabled 328 4 48 48 20 tint
|
|
84
|
-
slice field 4 104 48 48 16 tint
|
|
85
|
-
slice slot 56 104 48 48 16 tint
|
|
86
|
-
slice tooltip 108 104 32 32 13 tint
|
|
87
|
-
slice capsule 144 104 32 32 15 tint
|
|
88
|
-
slice track 180 104 32 16 7 tint
|
|
89
|
-
slice fill 216 104 32 16 7 tint
|
|
90
|
-
soft 252 104 64 64 24
|
|
91
|
-
divider 4 172 128 24 48 16 accent
|
|
92
|
-
flourish 136 172 64 24 22 10 accent 2
|
|
93
|
-
shadow panel 0 8 0 0 "#0b1a12cc"
|
|
94
|
-
shadow card 0 5 0 0 "#0b1a1299"
|
|
95
|
-
shadow button 0 5 0 0 "#0b1a12cc"
|
|
96
|
-
shadow capsule 0 4 0 0 "#0b1a1299"
|
|
97
|
-
shadow slot 0 3 0 0 "#0b1a1266"
|
|
98
|
-
textShadow display 0 4 0 "#0b1a12"
|
|
99
|
-
# Body text gets a hairline of its own ink to the right: the Chinese fallback
|
|
100
|
-
# (Noto Sans SC Regular) reads at the weight of the Latin face.
|
|
101
|
-
textShadow body 1 0 0 "#20302a"
|
|
102
|
-
press 1.08 0.88 3
|
|
103
|
-
hover -3 1.04
|
|
104
|
-
motion {
|
|
105
|
-
enter pop
|
|
106
|
-
stagger 50
|
|
107
|
-
toast pop
|
|
108
|
-
progress 360
|
|
109
|
-
shake 8
|
|
110
|
-
pop 0.22
|
|
111
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/archetypes/tower-defense/assets/{skins → styles}/pathguard/Fredoka-SemiBold.ttf.ogt
RENAMED
|
File without changes
|
|
File without changes
|
/package/archetypes/tower-defense/assets/{skins → styles}/pathguard/LilitaOne-Regular.ttf.ogt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|