pi-extensions 0.1.9

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.
Files changed (135) hide show
  1. package/.ralph/import-cc-codex.md +31 -0
  2. package/.ralph/import-cc-codex.state.json +14 -0
  3. package/.ralph/mario-not-impl.md +69 -0
  4. package/.ralph/mario-not-impl.state.json +14 -0
  5. package/.ralph/mario-not-spec.md +163 -0
  6. package/.ralph/mario-not-spec.state.json +14 -0
  7. package/LICENSE +21 -0
  8. package/README.md +65 -0
  9. package/RELEASING.md +34 -0
  10. package/agent-guidance/CHANGELOG.md +4 -0
  11. package/agent-guidance/README.md +102 -0
  12. package/agent-guidance/agent-guidance.ts +147 -0
  13. package/agent-guidance/package.json +22 -0
  14. package/agent-guidance/setup.sh +75 -0
  15. package/agent-guidance/templates/CLAUDE.md +5 -0
  16. package/agent-guidance/templates/CODEX.md +92 -0
  17. package/agent-guidance/templates/GEMINI.md +5 -0
  18. package/arcade/CHANGELOG.md +4 -0
  19. package/arcade/README.md +85 -0
  20. package/arcade/assets/picman.png +0 -0
  21. package/arcade/assets/ping.png +0 -0
  22. package/arcade/assets/spice-invaders.png +0 -0
  23. package/arcade/assets/tetris.png +0 -0
  24. package/arcade/mario-not/README.md +30 -0
  25. package/arcade/mario-not/boss.js +103 -0
  26. package/arcade/mario-not/camera.js +59 -0
  27. package/arcade/mario-not/collision.js +91 -0
  28. package/arcade/mario-not/colors.js +36 -0
  29. package/arcade/mario-not/constants.js +97 -0
  30. package/arcade/mario-not/core.js +39 -0
  31. package/arcade/mario-not/death.js +77 -0
  32. package/arcade/mario-not/effects.js +84 -0
  33. package/arcade/mario-not/enemies.js +31 -0
  34. package/arcade/mario-not/engine.js +171 -0
  35. package/arcade/mario-not/fireballs.js +98 -0
  36. package/arcade/mario-not/items.js +24 -0
  37. package/arcade/mario-not/levels.js +403 -0
  38. package/arcade/mario-not/logic.js +104 -0
  39. package/arcade/mario-not/mario-not.ts +297 -0
  40. package/arcade/mario-not/player.js +244 -0
  41. package/arcade/mario-not/render.js +257 -0
  42. package/arcade/mario-not/spec.md +548 -0
  43. package/arcade/mario-not/state.js +246 -0
  44. package/arcade/mario-not/tests/e2e.test.js +855 -0
  45. package/arcade/mario-not/tests/engine.test.js +888 -0
  46. package/arcade/mario-not/tests/fixtures/story0-frame.txt +4 -0
  47. package/arcade/mario-not/tests/fixtures/story1-camera.txt +4 -0
  48. package/arcade/mario-not/tests/fixtures/story1-glyphs.txt +4 -0
  49. package/arcade/mario-not/tests/fixtures/story10-item.txt +4 -0
  50. package/arcade/mario-not/tests/fixtures/story11-hazards.txt +4 -0
  51. package/arcade/mario-not/tests/fixtures/story12-used-block.txt +4 -0
  52. package/arcade/mario-not/tests/fixtures/story13-pipes.txt +4 -0
  53. package/arcade/mario-not/tests/fixtures/story14-goal.txt +4 -0
  54. package/arcade/mario-not/tests/fixtures/story15-hud-narrow.txt +2 -0
  55. package/arcade/mario-not/tests/fixtures/story16-unknown-tile.txt +4 -0
  56. package/arcade/mario-not/tests/fixtures/story17-mix.txt +4 -0
  57. package/arcade/mario-not/tests/fixtures/story18-hud-score.txt +2 -0
  58. package/arcade/mario-not/tests/fixtures/story19-cue.txt +4 -0
  59. package/arcade/mario-not/tests/fixtures/story2-enemy.txt +4 -0
  60. package/arcade/mario-not/tests/fixtures/story20-camera-offset.txt +4 -0
  61. package/arcade/mario-not/tests/fixtures/story21-hud-zero.txt +2 -0
  62. package/arcade/mario-not/tests/fixtures/story22-big-viewport.txt +4 -0
  63. package/arcade/mario-not/tests/fixtures/story23-camera-negative.txt +4 -0
  64. package/arcade/mario-not/tests/fixtures/story24-camera-width.txt +4 -0
  65. package/arcade/mario-not/tests/fixtures/story25-camera-positive.txt +4 -0
  66. package/arcade/mario-not/tests/fixtures/story26-hud-lives.txt +2 -0
  67. package/arcade/mario-not/tests/fixtures/story27-hud-coins.txt +2 -0
  68. package/arcade/mario-not/tests/fixtures/story28-item-viewport.txt +4 -0
  69. package/arcade/mario-not/tests/fixtures/story29-enemy-viewport.txt +4 -0
  70. package/arcade/mario-not/tests/fixtures/story3-hud.txt +2 -0
  71. package/arcade/mario-not/tests/fixtures/story30-hud-score.txt +2 -0
  72. package/arcade/mario-not/tests/fixtures/story31-particles-viewport.txt +4 -0
  73. package/arcade/mario-not/tests/fixtures/story32-paused-frame.txt +4 -0
  74. package/arcade/mario-not/tests/fixtures/story4-big.txt +4 -0
  75. package/arcade/mario-not/tests/fixtures/story5-resume-hud.txt +2 -0
  76. package/arcade/mario-not/tests/fixtures/story6-particles.txt +4 -0
  77. package/arcade/mario-not/tests/fixtures/story6-paused.txt +4 -0
  78. package/arcade/mario-not/tests/fixtures/story7-powerup.txt +4 -0
  79. package/arcade/mario-not/tests/fixtures/story8-hud-time.txt +2 -0
  80. package/arcade/mario-not/tests/fixtures/story9-hud-level.txt +2 -0
  81. package/arcade/mario-not/tiles.js +79 -0
  82. package/arcade/mario-not/tsconfig.json +14 -0
  83. package/arcade/mario-not/types.js +225 -0
  84. package/arcade/package.json +26 -0
  85. package/arcade/picman.ts +328 -0
  86. package/arcade/ping.ts +594 -0
  87. package/arcade/spice-invaders.ts +1104 -0
  88. package/arcade/tetris.ts +662 -0
  89. package/code-actions/CHANGELOG.md +4 -0
  90. package/code-actions/README.md +65 -0
  91. package/code-actions/actions.ts +107 -0
  92. package/code-actions/index.ts +148 -0
  93. package/code-actions/package.json +22 -0
  94. package/code-actions/search.ts +79 -0
  95. package/code-actions/snippets.ts +179 -0
  96. package/code-actions/ui.ts +120 -0
  97. package/files-widget/CHANGELOG.md +90 -0
  98. package/files-widget/DESIGN.md +452 -0
  99. package/files-widget/README.md +122 -0
  100. package/files-widget/TODO.md +141 -0
  101. package/files-widget/browser.ts +922 -0
  102. package/files-widget/comment.ts +5 -0
  103. package/files-widget/constants.ts +18 -0
  104. package/files-widget/demo.svg +1 -0
  105. package/files-widget/file-tree.ts +224 -0
  106. package/files-widget/file-viewer.ts +93 -0
  107. package/files-widget/git.ts +107 -0
  108. package/files-widget/index.ts +140 -0
  109. package/files-widget/input-utils.ts +3 -0
  110. package/files-widget/package.json +22 -0
  111. package/files-widget/types.ts +28 -0
  112. package/files-widget/utils.ts +26 -0
  113. package/files-widget/viewer.ts +424 -0
  114. package/import-cc-codex/research/import-chats-from-other-agents.md +135 -0
  115. package/import-cc-codex/spec.md +79 -0
  116. package/package.json +29 -0
  117. package/ralph-wiggum/CHANGELOG.md +7 -0
  118. package/ralph-wiggum/README.md +96 -0
  119. package/ralph-wiggum/SKILL.md +73 -0
  120. package/ralph-wiggum/index.ts +792 -0
  121. package/ralph-wiggum/package.json +25 -0
  122. package/raw-paste/CHANGELOG.md +7 -0
  123. package/raw-paste/README.md +52 -0
  124. package/raw-paste/index.ts +112 -0
  125. package/raw-paste/package.json +22 -0
  126. package/tab-status/CHANGELOG.md +4 -0
  127. package/tab-status/README.md +61 -0
  128. package/tab-status/assets/tab-status.png +0 -0
  129. package/tab-status/package.json +22 -0
  130. package/tab-status/tab-status.ts +179 -0
  131. package/usage-extension/CHANGELOG.md +17 -0
  132. package/usage-extension/README.md +120 -0
  133. package/usage-extension/index.ts +628 -0
  134. package/usage-extension/package.json +22 -0
  135. package/usage-extension/screenshot.png +0 -0
@@ -0,0 +1,403 @@
1
+ // @ts-check
2
+ "use strict";
3
+
4
+ const LEVEL_1_WIDTH = 160;
5
+ const LEVEL_1_HEIGHT = 15;
6
+
7
+ /** @param {number} width @param {number} height @param {string} fill @returns {string[][]} */
8
+ function makeGrid(width, height, fill) {
9
+ return Array.from({ length: height }, () => Array(width).fill(fill));
10
+ }
11
+
12
+ /** @param {string[][]} grid @param {number} x @param {number} y @param {string} tile */
13
+ function setTile(grid, x, y, tile) {
14
+ if (y < 0 || y >= grid.length) return;
15
+ if (x < 0 || x >= grid[0].length) return;
16
+ grid[y][x] = tile;
17
+ }
18
+
19
+ /** @param {string[][]} grid @param {number} y @param {number} x0 @param {number} x1 @param {string} tile */
20
+ function fillRow(grid, y, x0, x1, tile) {
21
+ for (let x = x0; x <= x1; x += 1) {
22
+ setTile(grid, x, y, tile);
23
+ }
24
+ }
25
+
26
+ /** @param {string[][]} grid @param {number} x @param {number} baseY @param {number} height */
27
+ function makeStaircase(grid, x, baseY, height) {
28
+ for (let step = 0; step < height; step++) {
29
+ for (let row = 0; row <= step; row++) {
30
+ setTile(grid, x + step, baseY - row, "B");
31
+ }
32
+ }
33
+ }
34
+
35
+ /** @param {string[][]} grid @param {number} x @param {number} topY @param {number} baseY */
36
+ function makeFlagpole(grid, x, topY, baseY) {
37
+ setTile(grid, x, topY, "G");
38
+ for (let y = topY + 1; y <= baseY; y++) {
39
+ setTile(grid, x, y, "F");
40
+ }
41
+ }
42
+
43
+ /** @param {string[][]} grid @param {number} x @param {number} baseY */
44
+ function makePipe(grid, x, baseY) {
45
+ setTile(grid, x, baseY - 1, "T");
46
+ setTile(grid, x + 1, baseY - 1, "T");
47
+ setTile(grid, x, baseY, "P");
48
+ setTile(grid, x + 1, baseY, "P");
49
+ }
50
+
51
+ /** @returns {string[]} */
52
+ function buildLevel1() {
53
+ const grid = makeGrid(LEVEL_1_WIDTH, LEVEL_1_HEIGHT, " ");
54
+
55
+ // Ground baseline.
56
+ fillRow(grid, 14, 0, LEVEL_1_WIDTH - 1, "#");
57
+
58
+ // Segment 1: flat ground, 3-coin line, low brick step.
59
+ setTile(grid, 6, 10, "o");
60
+ setTile(grid, 7, 10, "o");
61
+ setTile(grid, 8, 10, "o");
62
+ setTile(grid, 20, 13, "B");
63
+ setTile(grid, 21, 13, "B");
64
+ setTile(grid, 22, 12, "B");
65
+
66
+ // Segment 2: 4-tile gap, single goomba, question block.
67
+ setTile(grid, 50, 14, " ");
68
+ setTile(grid, 51, 14, " ");
69
+ setTile(grid, 52, 14, " ");
70
+ setTile(grid, 53, 14, " ");
71
+ setTile(grid, 60, 13, "E");
72
+ setTile(grid, 70, 11, "?");
73
+
74
+ // Segment 3: pipe, two goombas, brick stack.
75
+ makePipe(grid, 90, 14);
76
+ setTile(grid, 100, 13, "E");
77
+ setTile(grid, 106, 13, "E");
78
+ setTile(grid, 110, 13, "B");
79
+ setTile(grid, 110, 12, "B");
80
+ setTile(grid, 112, 13, "B");
81
+
82
+ // Segment 4: 2-tile gap, staircase, goal.
83
+ setTile(grid, 130, 14, " ");
84
+ setTile(grid, 131, 14, " ");
85
+ makeStaircase(grid, 140, 13, 4);
86
+ makeFlagpole(grid, 149, 5, 13);
87
+
88
+ return grid.map((row) => row.join(""));
89
+ }
90
+
91
+ /** @returns {string[]} */
92
+ function buildLevel2() {
93
+ const grid = makeGrid(LEVEL_1_WIDTH, LEVEL_1_HEIGHT, " ");
94
+
95
+ // Ground baseline with more gaps.
96
+ fillRow(grid, 14, 0, 45, "#");
97
+ fillRow(grid, 14, 50, 85, "#");
98
+ fillRow(grid, 14, 90, LEVEL_1_WIDTH - 1, "#");
99
+
100
+ // Segment 1: elevated platform, coins above.
101
+ setTile(grid, 8, 11, "B");
102
+ setTile(grid, 9, 11, "B");
103
+ setTile(grid, 10, 11, "B");
104
+ setTile(grid, 11, 11, "B");
105
+ setTile(grid, 9, 8, "o");
106
+ setTile(grid, 10, 8, "o");
107
+
108
+ // Segment 2: pipe with goomba behind, question block.
109
+ makePipe(grid, 25, 14);
110
+ setTile(grid, 30, 13, "E");
111
+ setTile(grid, 35, 10, "?");
112
+
113
+ // Large gap (50-90 is ground, so 46-49 is gap) - need platforms.
114
+ setTile(grid, 47, 12, "B");
115
+ setTile(grid, 48, 12, "B");
116
+
117
+ // Segment 3: brick staircase up then down.
118
+ setTile(grid, 55, 13, "B");
119
+ setTile(grid, 56, 13, "B");
120
+ setTile(grid, 56, 12, "B");
121
+ setTile(grid, 57, 13, "B");
122
+ setTile(grid, 57, 12, "B");
123
+ setTile(grid, 57, 11, "B");
124
+ setTile(grid, 58, 13, "B");
125
+ setTile(grid, 58, 12, "B");
126
+ setTile(grid, 59, 13, "B");
127
+ // Coins on top
128
+ setTile(grid, 56, 9, "o");
129
+ setTile(grid, 57, 8, "o");
130
+ setTile(grid, 58, 9, "o");
131
+
132
+ // Multiple goombas patrolling.
133
+ setTile(grid, 65, 13, "E");
134
+ setTile(grid, 70, 13, "E");
135
+ setTile(grid, 75, 13, "E");
136
+
137
+ // Another question block.
138
+ setTile(grid, 80, 10, "?");
139
+
140
+ // Gap at 86-89.
141
+ setTile(grid, 86, 14, " ");
142
+ setTile(grid, 87, 14, " ");
143
+ setTile(grid, 88, 14, " ");
144
+ setTile(grid, 89, 14, " ");
145
+
146
+ // Final staircase to flag.
147
+ makeStaircase(grid, 100, 13, 5);
148
+ makeFlagpole(grid, 110, 4, 13);
149
+
150
+ return grid.map((row) => row.join(""));
151
+ }
152
+
153
+ /** @returns {string[]} */
154
+ function buildLevel3() {
155
+ const grid = makeGrid(LEVEL_1_WIDTH, LEVEL_1_HEIGHT, " ");
156
+
157
+ // Sparse ground with many gaps - this is the hard level!
158
+ fillRow(grid, 14, 0, 12, "#");
159
+ fillRow(grid, 14, 18, 30, "#");
160
+ fillRow(grid, 14, 38, 50, "#");
161
+ fillRow(grid, 14, 58, 70, "#");
162
+ fillRow(grid, 14, 80, 95, "#");
163
+ fillRow(grid, 14, 105, 120, "#");
164
+ fillRow(grid, 14, 130, LEVEL_1_WIDTH - 1, "#");
165
+
166
+ // Segment 1: spike pit with floating platforms above
167
+ fillRow(grid, 14, 13, 17, "^"); // spikes in first gap
168
+ setTile(grid, 14, 11, "B"); // floating platform
169
+ setTile(grid, 15, 11, "B");
170
+ setTile(grid, 16, 9, "B"); // higher platform
171
+ setTile(grid, 10, 13, "E"); // goomba before gap
172
+
173
+ // Coins reward for taking upper path
174
+ setTile(grid, 14, 8, "o");
175
+ setTile(grid, 15, 8, "o");
176
+ setTile(grid, 16, 6, "o");
177
+
178
+ // Segment 2: enemy gauntlet
179
+ setTile(grid, 20, 13, "E");
180
+ setTile(grid, 23, 13, "E");
181
+ setTile(grid, 26, 13, "E");
182
+ setTile(grid, 29, 13, "E");
183
+ setTile(grid, 25, 10, "?"); // power-up to help
184
+
185
+ // Gap with water (instant death)
186
+ fillRow(grid, 14, 31, 37, "~");
187
+ setTile(grid, 33, 11, "B"); // small platform in middle
188
+ setTile(grid, 34, 11, "B");
189
+ setTile(grid, 33, 8, "o");
190
+ setTile(grid, 34, 8, "o");
191
+
192
+ // Segment 3: vertical climb with enemies
193
+ setTile(grid, 40, 13, "B");
194
+ setTile(grid, 40, 12, "B");
195
+ setTile(grid, 42, 11, "B");
196
+ setTile(grid, 42, 10, "B");
197
+ setTile(grid, 44, 9, "B");
198
+ setTile(grid, 44, 8, "B");
199
+ setTile(grid, 46, 7, "B");
200
+ setTile(grid, 47, 7, "B");
201
+ // Coins at the top
202
+ setTile(grid, 46, 4, "o");
203
+ setTile(grid, 47, 4, "o");
204
+ setTile(grid, 48, 13, "E");
205
+
206
+ // Spike gap
207
+ fillRow(grid, 14, 51, 57, "^");
208
+ setTile(grid, 53, 10, "B");
209
+ setTile(grid, 54, 10, "B");
210
+ setTile(grid, 55, 10, "B");
211
+
212
+ // Segment 4: pipe maze with goombas
213
+ makePipe(grid, 60, 14);
214
+ setTile(grid, 64, 13, "E");
215
+ makePipe(grid, 66, 14);
216
+ setTile(grid, 68, 13, "E");
217
+ setTile(grid, 63, 10, "?");
218
+
219
+ // Long water gap - need precise jumping
220
+ fillRow(grid, 14, 71, 79, "~");
221
+ setTile(grid, 73, 11, "B");
222
+ setTile(grid, 76, 12, "B");
223
+ setTile(grid, 77, 12, "B");
224
+
225
+ // Segment 5: descending platforms with enemies
226
+ setTile(grid, 82, 10, "B");
227
+ setTile(grid, 83, 10, "B");
228
+ setTile(grid, 84, 10, "E");
229
+ setTile(grid, 86, 11, "B");
230
+ setTile(grid, 87, 11, "B");
231
+ setTile(grid, 89, 12, "B");
232
+ setTile(grid, 90, 12, "B");
233
+ setTile(grid, 91, 13, "E");
234
+ setTile(grid, 93, 13, "E");
235
+
236
+ // Another spike gap
237
+ fillRow(grid, 14, 96, 104, "^");
238
+ setTile(grid, 98, 10, "B");
239
+ setTile(grid, 99, 10, "B");
240
+ setTile(grid, 101, 11, "B");
241
+ setTile(grid, 102, 11, "B");
242
+
243
+ // Segment 6: final gauntlet
244
+ setTile(grid, 107, 13, "E");
245
+ setTile(grid, 110, 13, "E");
246
+ setTile(grid, 113, 13, "E");
247
+ setTile(grid, 116, 13, "E");
248
+ setTile(grid, 112, 10, "?"); // last power-up
249
+
250
+ // Water before final stretch
251
+ fillRow(grid, 14, 121, 129, "~");
252
+ setTile(grid, 123, 11, "B");
253
+ setTile(grid, 124, 11, "B");
254
+ setTile(grid, 126, 10, "B");
255
+ setTile(grid, 127, 10, "B");
256
+
257
+ // Final staircase - extra tall
258
+ makeStaircase(grid, 135, 13, 6);
259
+ makeFlagpole(grid, 146, 3, 13);
260
+
261
+ return grid.map((row) => row.join(""));
262
+ }
263
+
264
+ /** @returns {string[]} */
265
+ function buildLevel4() {
266
+ const grid = makeGrid(LEVEL_1_WIDTH, LEVEL_1_HEIGHT, " ");
267
+
268
+ // This is Bowser's Castle - lava floor, fireballs, and a boss fight!
269
+
270
+ // Lava baseline - deadly floor throughout most of the level
271
+ fillRow(grid, 14, 0, 20, "L");
272
+ fillRow(grid, 14, 25, 60, "L");
273
+ fillRow(grid, 14, 65, 100, "L");
274
+ fillRow(grid, 14, 105, 130, "L");
275
+
276
+ // Safe ground sections
277
+ fillRow(grid, 14, 0, 8, "C"); // Starting platform
278
+ fillRow(grid, 14, 131, LEVEL_1_WIDTH - 1, "C"); // Boss arena
279
+
280
+ // Segment 1: Opening gauntlet with floating platforms over lava
281
+ setTile(grid, 10, 12, "C");
282
+ setTile(grid, 11, 12, "C");
283
+ setTile(grid, 14, 10, "C");
284
+ setTile(grid, 15, 10, "C");
285
+ setTile(grid, 18, 11, "C");
286
+ setTile(grid, 19, 11, "C");
287
+
288
+ // Coins to guide the way
289
+ setTile(grid, 10, 9, "o");
290
+ setTile(grid, 14, 7, "o");
291
+
292
+ // Segment 2: Bridge section with gaps and goombas
293
+ fillRow(grid, 11, 22, 35, "C"); // Bridge
294
+ setTile(grid, 26, 11, " "); // Gap in bridge
295
+ setTile(grid, 27, 11, " ");
296
+ setTile(grid, 30, 10, "E"); // Goomba on bridge
297
+ setTile(grid, 33, 10, "E");
298
+
299
+ // Fireball spawner shooting across the bridge
300
+ setTile(grid, 22, 9, ">");
301
+
302
+ // Segment 3: Vertical climb section
303
+ setTile(grid, 38, 12, "C");
304
+ setTile(grid, 39, 12, "C");
305
+ setTile(grid, 41, 10, "C");
306
+ setTile(grid, 42, 10, "C");
307
+ setTile(grid, 44, 8, "C");
308
+ setTile(grid, 45, 8, "C");
309
+ setTile(grid, 47, 6, "C");
310
+ setTile(grid, 48, 6, "C");
311
+ setTile(grid, 50, 8, "C");
312
+ setTile(grid, 51, 8, "C");
313
+ setTile(grid, 53, 10, "C");
314
+ setTile(grid, 54, 10, "C");
315
+ setTile(grid, 56, 12, "C");
316
+ setTile(grid, 57, 12, "C");
317
+
318
+ // Power-up for the climb
319
+ setTile(grid, 47, 4, "?");
320
+
321
+ // Segment 4: Descending platforms
322
+ fillRow(grid, 10, 60, 64, "C");
323
+
324
+ setTile(grid, 67, 11, "C");
325
+ setTile(grid, 68, 11, "C");
326
+ setTile(grid, 71, 12, "C");
327
+ setTile(grid, 72, 12, "C");
328
+ setTile(grid, 75, 11, "C");
329
+ setTile(grid, 76, 11, "C");
330
+
331
+ // Goombas on the descent
332
+ setTile(grid, 75, 10, "E");
333
+
334
+ // Segment 5: Lava corridor with tight jumps
335
+ setTile(grid, 80, 10, "C");
336
+ setTile(grid, 83, 11, "C");
337
+ setTile(grid, 86, 10, "C");
338
+ setTile(grid, 89, 11, "C");
339
+ setTile(grid, 92, 10, "C");
340
+ setTile(grid, 95, 11, "C");
341
+ setTile(grid, 98, 10, "C");
342
+
343
+ // Fireball shooting through the corridor
344
+ setTile(grid, 84, 9, ">");
345
+
346
+ // Segment 6: Final approach to boss
347
+ fillRow(grid, 12, 102, 110, "C");
348
+ setTile(grid, 105, 11, "E");
349
+ setTile(grid, 108, 11, "E");
350
+
351
+ // Power-up before boss
352
+ setTile(grid, 106, 9, "?");
353
+
354
+ // Bridge to boss arena
355
+ fillRow(grid, 12, 112, 130, "C");
356
+ setTile(grid, 118, 12, " "); // Gap
357
+ setTile(grid, 119, 12, " ");
358
+ setTile(grid, 124, 12, " "); // Gap
359
+ setTile(grid, 125, 12, " ");
360
+
361
+ // Segment 7: Boss Arena
362
+ // Solid floor for boss fight
363
+ fillRow(grid, 13, 131, LEVEL_1_WIDTH - 5, "C");
364
+
365
+ // Walls to contain the fight
366
+ for (let y = 8; y <= 13; y++) {
367
+ setTile(grid, 131, y, "C");
368
+ }
369
+ for (let y = 8; y <= 13; y++) {
370
+ setTile(grid, LEVEL_1_WIDTH - 5, y, "C");
371
+ }
372
+
373
+ // Bowser!
374
+ setTile(grid, 145, 12, "W");
375
+
376
+ // Fireball spawner in arena
377
+ setTile(grid, 150, 10, "<");
378
+
379
+ // Coins as a reward for entering
380
+ setTile(grid, 138, 10, "o");
381
+ setTile(grid, 140, 10, "o");
382
+ setTile(grid, 142, 10, "o");
383
+
384
+ return grid.map((row) => row.join(""));
385
+ }
386
+
387
+ const LEVEL_1_LINES = buildLevel1();
388
+ const LEVEL_2_LINES = buildLevel2();
389
+ const LEVEL_3_LINES = buildLevel3();
390
+ const LEVEL_4_LINES = buildLevel4();
391
+
392
+ /** @type {string[][]} */
393
+ const ALL_LEVELS = [LEVEL_1_LINES, LEVEL_2_LINES, LEVEL_3_LINES, LEVEL_4_LINES];
394
+
395
+ module.exports = {
396
+ LEVEL_1_LINES,
397
+ LEVEL_2_LINES,
398
+ LEVEL_3_LINES,
399
+ LEVEL_4_LINES,
400
+ ALL_LEVELS,
401
+ LEVEL_1_WIDTH,
402
+ LEVEL_1_HEIGHT,
403
+ };
@@ -0,0 +1,104 @@
1
+ // @ts-check
2
+ "use strict";
3
+
4
+ const { updateCamera } = require("./camera.js");
5
+ const { updateParticles, setCue, updateCue } = require("./effects.js");
6
+ const { updateEnemies } = require("./enemies.js");
7
+ const { updateItems } = require("./items.js");
8
+ const { stepDeath } = require("./death.js");
9
+ const { updateFireballSpawners, updateFireballs, checkFireballCollision } = require("./fireballs.js");
10
+ const { updateBoss, resolveBossCollision } = require("./boss.js");
11
+ const {
12
+ applyPlayerDamage,
13
+ checkGoal,
14
+ checkHazard,
15
+ collectCoin,
16
+ collectItems,
17
+ resolveEnemyCollisions,
18
+ stepPlayerMovement,
19
+ } = require("./player.js");
20
+ const { GAME_MODES } = require("./constants.js");
21
+
22
+ /** @typedef {import("./types").GameState} GameState */
23
+ /** @typedef {import("./types").InputState} InputState */
24
+
25
+ /** @param {GameState} state @param {InputState} [input] @returns {GameState} */
26
+ function stepGame(state, input) {
27
+ const dt = state.config.dt;
28
+ if (state.mode === GAME_MODES.dead) {
29
+ return stepDeath(state, dt);
30
+ }
31
+ if (state.mode !== GAME_MODES.playing) {
32
+ state.tick += 1;
33
+ return state;
34
+ }
35
+
36
+ const { prevY, height } = stepPlayerMovement(state, input);
37
+ updateEnemies(state);
38
+ updateItems(state);
39
+ updateFireballSpawners(state);
40
+ updateFireballs(state);
41
+ updateBoss(state);
42
+
43
+ resolveEnemyCollisions(state, prevY);
44
+
45
+ // Check boss collision
46
+ if (state.boss && state.boss.alive) {
47
+ const bossHurt = resolveBossCollision(state, prevY);
48
+ if (bossHurt) {
49
+ applyPlayerDamage(state);
50
+ }
51
+ }
52
+
53
+ // Check fireball collision
54
+ if (checkFireballCollision(state)) {
55
+ applyPlayerDamage(state);
56
+ }
57
+
58
+ collectCoin(state);
59
+ collectItems(state);
60
+
61
+ // Only check goal if no boss or boss is defeated
62
+ if (!state.boss || !state.boss.alive) {
63
+ checkGoal(state, height);
64
+ }
65
+
66
+ if (state.mode === GAME_MODES.playing) {
67
+ // Check hazards
68
+ if (checkHazard(state)) {
69
+ applyPlayerDamage(state);
70
+ } else if (state.player.y >= state.level.height) {
71
+ applyPlayerDamage(state, true);
72
+ }
73
+
74
+ // Update world (only if still playing after hazard check)
75
+ if (state.mode === GAME_MODES.playing) {
76
+ updateCamera(state);
77
+ updateParticles(state, dt);
78
+ updateCue(state, dt);
79
+ state.time = Math.max(0, state.time - dt);
80
+ }
81
+ }
82
+
83
+ state.tick += 1;
84
+ return state;
85
+ }
86
+
87
+ /** @param {GameState} state @param {boolean} paused */
88
+ function setPaused(state, paused) {
89
+ if (state.mode === GAME_MODES.dead || state.mode === GAME_MODES.gameOver || state.mode === GAME_MODES.levelClear) {
90
+ return state;
91
+ }
92
+ state.mode = paused ? GAME_MODES.paused : GAME_MODES.playing;
93
+ if (paused) {
94
+ setCue(state, "PAUSED", 0, true);
95
+ } else if (state.cue && state.cue.persist) {
96
+ state.cue = null;
97
+ }
98
+ return state;
99
+ }
100
+
101
+ module.exports = {
102
+ stepGame,
103
+ setPaused,
104
+ };