diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml deleted file mode 100644 index ded26ec..0000000 --- a/.github/workflows/pages.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Update Deployment - -on: - push: - branches: - - "main" - -jobs: - publish: - permissions: - contents: write - runs-on: ubuntu-latest - steps: - - name: Check out - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v2 - with: - node-version: '20' - - - name: Install dependencies - run: cd client && npm install - - - name: Remove .gitignore - run: rm -rf client/.gitignore - - - name: Generate your content - run: npm run build:client - - - name: Publish current workdir (which contains generated content) to GitHub Pages - uses: rayluo/github-pages-overwriter@v1.3 - - with: - source-directory: client - target-branch: gh-pages diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..2fc24f2 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,54 @@ +# File: .github/workflows/publish.yml +name: publish-to-github-pages +on: + push: + branches: + - main + - next-app + + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout 🛎️ + uses: actions/checkout@v4 + + - name: Setup Node.js ⚙️ - Cache dependencies ⚡ - Install dependencies 🔧 + uses: ./.github/workflows/setup-node + + - name: Setup Pages ⚙️ + uses: actions/configure-pages@v4 + with: + static_site_generator: next + + - name: Build with Next.js 🏗️ + run: npx next build + + - name: Upload artifact 📡 + uses: actions/upload-pages-artifact@v3 + with: + path: ./game/out + + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + + runs-on: ubuntu-latest + needs: build + + steps: + - name: Publish to GitHub Pages 🚀 + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/setup-node/action.yml b/.github/workflows/setup-node/action.yml new file mode 100644 index 0000000..5eeaa85 --- /dev/null +++ b/.github/workflows/setup-node/action.yml @@ -0,0 +1,21 @@ +name: setup-node +description: "Setup Node.js ⚙️ - Cache dependencies ⚡ - Install dependencies 🔧" +runs: + using: "composite" + steps: + - name: Setup Node.js ⚙️ + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Cache dependencies ⚡ + id: cache_dependencies + uses: actions/cache@v3 + with: + path: game/node_modules + key: node-modules-${{ hashFiles('game/package-lock.json') }} + + - name: Install dependencies 🔧 + shell: bash + if: steps.cache_dependencies.outputs.cache-hit != 'true' + run: cd game && npm i diff --git a/.gitignore b/.gitignore index a159644..809d1b3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ **/*.sqlite **/*.env node_modules/ +*.wasm diff --git a/client/.gitignore b/client/.gitignore deleted file mode 100644 index e54b9fc..0000000 --- a/client/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.vscode -npm-debug*.* -node_modules -build/ diff --git a/client/README.md b/client/README.md deleted file mode 100644 index ebed8d9..0000000 --- a/client/README.md +++ /dev/null @@ -1,40 +0,0 @@ - -This is an attempt to recreate the classic arcade game, Asteroids. - -[You can give it a try here](https://jphamilton.github.io/asteroids/) - -## Controls - -* Tap, click, press any key to START -* Rotate: Left/Right arrow keys or A and D, pan left/right to rotate on mobile -* Thrust: Up arrow or W, pan up to thrust on mobile -* Fire: CTRL, tap -* Hyperspace: Space bar, pinch out for hyperspace -* Debug Mode: Z (during game only). Primarily shows collision related information. -* Monitor Burn Effect: toggle on/off with B -* God Mode: G - -## Screenshots - -![Sceenshot 1](https://raw.githubusercontent.com/jphamilton/asteroids/master/assets/1.png) -![Sceenshot 2](https://raw.githubusercontent.com/jphamilton/asteroids/master/assets/2.png) -![Sceenshot 3](https://raw.githubusercontent.com/jphamilton/asteroids/master/assets/3.png) - -## About - -This is my "re-imagining" of the classic arcade game, Asteroids. I tried to stay true to the spirit of the original as much as possible, while adding a more modern "game feel" -(e.g. camera shake, kick back, bigger explosions, faster movement, etc). While the original was designed to encourage you to part with your quarters, this version is designed for you to -blow lots of stuff up. It's a little more forgiving, too. Your ship has a little shielding that can protect you from damage for a bit and you can fire more bullets. - -Like the arcade upright, the game will cycle between the highscore screen and 'attraction mode' every 15 seconds. Attraction mode will continue to play itself out until a new game is started. -After a game is completed, attraction mode will continue, using the state of the last game. High scores are tracked and saved in local storage. - -Collision detection occurs in 3 stages. First, a quadtree is used to determine potential collision candidates. Second, candidates are checked using Axis-Aligned Bounding Boxes (AABB). -Finally, if the ship is involved, a point in polygon routine (credit Lascha Lagidse http://alienryderflex.com/polygon/) is used to determine if an actual collision has taken place. -Using point in poly for all collisions didn't "feel right". Bullet collisions (from the ship) also the Cohen-Sutherland line clipping algorithm - the result being that rocks in between 2 bullets -will be destroyed. This vastly speeds up the game and gives the player the illusion that they are actually better than they are :) Basically, everything in the game is favored to the player. -This entire process is visualized in debug mode (hit F1 during game to view). - -I only used two libraries for the game: [howler.js](https://howlerjs.com/) for sound and [hammer.js](http://hammerjs.github.io/) for touch support. I have to say, both of the libraries are amazing. -I can't believe how quickly I was able to put them to use. As for the rest of the game, it was important for me to do all the dirty work myself. I had almost zero exposure to the HTML 5 canvas before -starting this project. diff --git a/client/assets/1.png b/client/assets/1.png deleted file mode 100644 index 5242488..0000000 Binary files a/client/assets/1.png and /dev/null differ diff --git a/client/assets/2.png b/client/assets/2.png deleted file mode 100644 index 44bd046..0000000 Binary files a/client/assets/2.png and /dev/null differ diff --git a/client/assets/3.png b/client/assets/3.png deleted file mode 100644 index f803497..0000000 Binary files a/client/assets/3.png and /dev/null differ diff --git a/client/assets/Hyperspace.otf b/client/assets/Hyperspace.otf deleted file mode 100644 index ab0878a..0000000 Binary files a/client/assets/Hyperspace.otf and /dev/null differ diff --git a/client/assets/explode1.wav b/client/assets/explode1.wav deleted file mode 100644 index 1f9716c..0000000 Binary files a/client/assets/explode1.wav and /dev/null differ diff --git a/client/assets/explode2.wav b/client/assets/explode2.wav deleted file mode 100644 index e54f129..0000000 Binary files a/client/assets/explode2.wav and /dev/null differ diff --git a/client/assets/explode3.wav b/client/assets/explode3.wav deleted file mode 100644 index 98188a5..0000000 Binary files a/client/assets/explode3.wav and /dev/null differ diff --git a/client/assets/fire.wav b/client/assets/fire.wav deleted file mode 100644 index 49d3000..0000000 Binary files a/client/assets/fire.wav and /dev/null differ diff --git a/client/assets/getpowerup.wav b/client/assets/getpowerup.wav deleted file mode 100644 index ca683b4..0000000 Binary files a/client/assets/getpowerup.wav and /dev/null differ diff --git a/client/assets/life.wav b/client/assets/life.wav deleted file mode 100644 index 56eae06..0000000 Binary files a/client/assets/life.wav and /dev/null differ diff --git a/client/assets/lsaucer.wav b/client/assets/lsaucer.wav deleted file mode 100644 index ae56662..0000000 Binary files a/client/assets/lsaucer.wav and /dev/null differ diff --git a/client/assets/powerup.wav b/client/assets/powerup.wav deleted file mode 100644 index 0037caa..0000000 Binary files a/client/assets/powerup.wav and /dev/null differ diff --git a/client/assets/sfire.wav b/client/assets/sfire.wav deleted file mode 100644 index 1702f11..0000000 Binary files a/client/assets/sfire.wav and /dev/null differ diff --git a/client/assets/ssaucer.wav b/client/assets/ssaucer.wav deleted file mode 100644 index 4f5fd56..0000000 Binary files a/client/assets/ssaucer.wav and /dev/null differ diff --git a/client/assets/thrust.wav b/client/assets/thrust.wav deleted file mode 100644 index f92e40c..0000000 Binary files a/client/assets/thrust.wav and /dev/null differ diff --git a/client/assets/thumphi.wav b/client/assets/thumphi.wav deleted file mode 100644 index 041bf4a..0000000 Binary files a/client/assets/thumphi.wav and /dev/null differ diff --git a/client/assets/thumplo.wav b/client/assets/thumplo.wav deleted file mode 100644 index 524bc9e..0000000 Binary files a/client/assets/thumplo.wav and /dev/null differ diff --git a/client/comets.d.ts b/client/comets.d.ts deleted file mode 100644 index 1cd0d40..0000000 --- a/client/comets.d.ts +++ /dev/null @@ -1,28 +0,0 @@ -import {Screen} from './game/screen'; - -interface IGameState { - update: (step: number, inputs?: VirtualInput) => void; - render: (screen: Screen, dt?: number) => void; -} - -type VirtualInput = { [key: string]: boolean }; - -interface Point { - x: number, - y: number -} - -interface Rect extends Point { - width: number; - height: number; -} - -interface IQuadtree { - nodes: IQuadtree[]; - objects: Rect[]; - width2: number; - height2: number; - xmid: number; - ymid: number; -} - diff --git a/client/game/achievement.ts b/client/game/achievement.ts deleted file mode 100644 index 6fee2e6..0000000 --- a/client/game/achievement.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { HEIGHT, WIDTH } from "./constants"; -import { Object2D } from "./object2d"; -import { Screen } from "./screen"; - -export class Achievement extends Object2D { - life: number = 1; // in seconds - fontSize: number; - - heightText: number = HEIGHT / 4; - heightScore: number = HEIGHT / 6; - - constructor(private text: string, score: number) { - super(WIDTH / 2, HEIGHT / 2); - this.score = score; - //this.velocity = new Vector(0, -1); - } - - update(dt: number) { - this.life -= dt; - this.fontSize -= 1; - - if (this.life <= 0) { - this.destroy(); - } - } - - render(screen: Screen) { - this.fontSize = screen.font.xlarge * 2; - - screen.draw.text3(this.text, this.fontSize, (width) => { - return { - x: screen.width2 - width / 2, - y: this.heightText, - }; - }); - - screen.draw.text3(`+${this.score}`, this.fontSize, (width) => { - return { - x: screen.width2 - width / 2, - y: this.heightScore, - }; - }); - } - - destroy() { - this.life = 0; - this.trigger("expired"); - } -} diff --git a/client/game/alien.ts b/client/game/alien.ts deleted file mode 100644 index 98fc939..0000000 --- a/client/game/alien.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { Bullet } from "./bullet"; -import { HEIGHT, OBJECT_SCALE, WIDTH } from "./constants"; -import { Object2D } from "./object2d"; -import { Screen } from "./screen"; -import { Ship } from "./ship"; -import { random } from "./util"; -import { Vector } from "./vector"; - -const BIG_ALIEN_BULLET_SPEED: number = 600 * OBJECT_SCALE; -const SMALL_ALIEN_BULLET_SPEED: number = 800 * OBJECT_SCALE; -const BIG_ALIEN_SPEED: number = 225 * OBJECT_SCALE; -const SMALL_ALIEN_SPEED: number = 250 * OBJECT_SCALE; - -export abstract class Alien extends Object2D { - moveTimer: number = 0; - moveTime: number = 1; - bulletTimer: number = 0; - bulletTime: number = 0.7; - - abstract fire(): void; - abstract destroy(): void; - - constructor(speed) { - super(0, 0); - - this.velocity.y = 0; - - this.origin.y = random(100, HEIGHT - 100); - - if (this.origin.y % 2 === 0) { - this.origin.x = 40; - this.velocity.x = speed; - } else { - this.origin.x = WIDTH - 40; - this.velocity.x = -speed; - } - - this.points = [ - { x: 0.5, y: -2 }, - { x: 1, y: -1 }, - { x: 2.5, y: 0 }, - { x: 1, y: 1 }, - { x: -1, y: 1 }, - { x: -2.5, y: 0 }, - { x: -1, y: -1 }, - { x: -0.5, y: -2 }, - ]; - } - - update(dt: number) { - this.move(dt); - - if (this.origin.x >= WIDTH - 5 || this.origin.x <= 5) { - this.trigger("expired"); - return; - } - - // direction changes - this.moveTimer += dt; - - if (this.moveTimer >= 1 && this.velocity.y !== 0) { - this.velocity.y = 0; - this.moveTimer = 0; - } - - if (this.moveTimer >= this.moveTime) { - let move = random(1, 20) % 2 === 0; - - if (move) { - this.velocity.y = - this.origin.x % 2 === 0 ? this.velocity.x : -this.velocity.x; - } - - this.moveTimer = 0; - } - - // firing - this.bulletTimer += dt; - - if (this.bulletTimer >= this.bulletTime) { - this.fire(); - this.bulletTimer = 0; - } - } - - render(screen: Screen) { - this.draw(screen); - } - - draw(screen: Screen) { - super.draw(screen); - screen.draw.vectorShape( - [this.points[1], this.points[6]], - this.origin.x, - this.origin.y - ); - screen.draw.vectorShape( - [this.points[2], this.points[5]], - this.origin.x, - this.origin.y - ); - } -} - -// Mr. Bill -export class BigAlien extends Alien { - constructor() { - super(BIG_ALIEN_SPEED); - this.score = 200; - this.scale(7); - } - - fire() { - const v = Vector.fromAngle(random(1, 360), BIG_ALIEN_BULLET_SPEED); - const bullet = new Bullet(this.origin, v); - this.trigger("fire", bullet); - } - - destroy() { - this.trigger("expired"); - } -} - -// Sluggo -export class SmallAlien extends Alien { - //score: number = 1000; - bulletTime: number = 1; - - constructor(private ship: Ship) { - super(SMALL_ALIEN_SPEED); - this.score = 1000; - this.scale(4); - } - - fire() { - let bullet; - - if (this.ship) { - // target ship - const v = Vector.fromXY( - this.ship.origin, - this.origin, - SMALL_ALIEN_BULLET_SPEED - ); - bullet = new Bullet(this.origin, v, 2); - } else { - // random fire - const v = Vector.fromAngle(random(1, 360), SMALL_ALIEN_BULLET_SPEED); - bullet = new Bullet(this.origin, v, 2); - } - - this.trigger("fire", bullet); - } - - destroy() { - this.ship = null; - this.trigger("expired"); - } -} diff --git a/client/game/attractMode.ts b/client/game/attractMode.ts deleted file mode 100644 index 695b5bf..0000000 --- a/client/game/attractMode.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { IGameState } from "../comets"; -import { fetchMruInfo, startGame } from "../rpc/api"; -import { addToStore, getFromStore, StorageKey } from "../rpc/storage"; -import { DemoMode } from "./demoMode"; -import { EventSource } from "./events"; -import { HighScoreMode } from "./highScoreMode"; -import { Key } from "./keys"; -import { Screen } from "./screen"; -import { Sound } from "./sounds"; -import { World } from "./world"; - -const ATTRACT_TIME = 15; - -// combines DemoMode and HighscoreMode to attract people to part with their quarters -export class AttractMode extends EventSource implements IGameState { - private currentMode: IGameState; - private modes: IGameState[]; - private isStarting = false; - - constructor(world: World, lastScore: number) { - super(); - - this.modes = [ - new HighScoreMode(lastScore), - new DemoMode(world || new World()), - ]; - - this.currentMode = this.modes[0]; - - Sound.stop(); - Sound.off(); - } - - update(step: number) { - this.currentMode.update(step); - - if (Key.isEnterPressed()) { - if (!this.isStarting) { - this.isStarting = true; - startGame() - .then((res) => { - console.log("Game started", res.logs[0].value); - addToStore(StorageKey.GAME_ID, res.logs[0].value); - this.isStarting = false; - this.trigger("done"); - }) - .catch((e) => { - console.error("Error starting game", e.message); - }) - .finally(() => { - this.isStarting = false; - // clears the keys to prevent the game from starting again - Key.clear(); - }); - } - } - } - - render(screen: Screen, dt?: number) { - this.currentMode.render(screen, dt); - } -} diff --git a/client/game/bullet.ts b/client/game/bullet.ts deleted file mode 100644 index 486ad3c..0000000 --- a/client/game/bullet.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Point } from "../comets"; -import { OBJECT_SCALE } from "./constants"; -import { Object2D } from "./object2d"; -import { Screen } from "./screen"; -import { Vector } from "./vector"; - -export class Bullet extends Object2D { - frame: number = 0; - - constructor(origin: Vector, v: Vector, private life: number = 1.25) { - super(origin.x, origin.y); - this.velocity = v; - } - - render(screen: Screen) { - this.draw(screen); - } - - update(dt: number) { - this.frame++; - this.move(dt); - this.life -= dt; - - if (this.life <= 0) { - this.destroy(); - } - } - - draw(screen: Screen) { - let size = this.frame <= 1 ? 8 * OBJECT_SCALE : 4 * OBJECT_SCALE; - screen.draw.rect( - this.origin.x - 2, - this.origin.y - 2, - size, - size, - `rgba(255,0,255,.5)` - ); - screen.draw.rect( - this.origin.x - 1, - this.origin.y - 1, - size, - size, - `rgba(0,255,255,.5)` - ); - screen.draw.rect(this.origin.x, this.origin.y, size, size); - } - - destroy() { - this.trigger("expired"); - } - - get vertices(): Point[] { - return [this.origin]; - } -} diff --git a/client/game/collisions.ts b/client/game/collisions.ts deleted file mode 100644 index d379725..0000000 --- a/client/game/collisions.ts +++ /dev/null @@ -1,183 +0,0 @@ -import { WIDTH, HEIGHT } from "./constants"; -import { Quadtree } from "./quadtree"; -import { Object2D } from "./object2d"; -import { lineclip } from "./lineclip"; -import { Point } from "../comets"; - -export type CollisionCallback = ( - a: TSource, - b: TTarget -) => void; -export type BulletCollisionCallback = ( - a: TSource, - b: TSource, - c: TTarget -) => void; - -export class Collisions { - tree: Quadtree; - - constructor() { - this.tree = new Quadtree({ - x: 0, - y: 0, - width: WIDTH, - height: HEIGHT, - }); - } - - // special case for ship bullets - bulletCheck( - bullets: TSource[], - targets: TTarget[], - cb: CollisionCallback, - dcb?: BulletCollisionCallback - ) { - if (!bullets || !bullets.length || !targets || !targets.length) { - return; - } - - let candidates: TTarget[] = []; - let results = []; - - this.tree.clear(); - - targets.forEach((target) => { - this.tree.insert(target); - }); - - // check bullet here - for (let i = 0; i < bullets.length; i++) { - const bullet1 = bullets[i]; - - candidates.length = 0; - candidates.push(...(this.tree.retrieve(bullet1) as any)); - - candidates.forEach((candidate) => { - if (candidate.collided(bullet1)) { - cb(bullet1, candidate); - return; // bail - } else if (dcb) { - dcb(bullet1, bullet1, candidate); - } - - // line clip - if (i < bullets.length - 1) { - const bullet2 = bullets[i + 1]; - const bbox = [ - candidate.x, - candidate.y, - candidate.x + candidate.width, - candidate.y + candidate.height, - ]; - - results.length = 0; - - lineclip( - [ - [bullet1.origin.x, bullet1.origin.y], - [bullet2.origin.x, bullet2.origin.y], - ], - bbox, - results - ); - - if (results.length) { - if (dcb) { - dcb(bullet1, bullet2, candidate); - } - - cb(bullet1, candidate); - } - } - }); - } - } - - check( - sources: TSource[], - targets: TTarget[], - deep: boolean, - cb: CollisionCallback, - dcb?: CollisionCallback - ) { - if (!sources || !sources.length || !targets || !targets.length) { - return; - } - - this.tree.clear(); - - targets.forEach((target) => { - this.tree.insert(target); - }); - - sources.forEach((source) => { - const candidates: any[] = this.tree.retrieve(source); - - candidates.forEach((candidate) => { - // AABB first - if (candidate.collided(source)) { - if (deep) { - if ( - this.pointsInPolygon( - source, - candidate || this.pointsInPolygon(candidate, source) - ) - ) { - cb(source, candidate); - } - } else { - cb(source, candidate); - } - } else if (dcb) { - dcb(source, candidate); - } - }); - }); - } - - private pointsInPolygon(source: Object2D, candidate: Object2D): boolean { - let vert1 = - source.vertices.length > candidate.vertices.length - ? source.vertices - : candidate.vertices; - let vert2 = - source.vertices.length <= candidate.vertices.length - ? source.vertices - : candidate.vertices; - - for (let i = 0, l = vert2.length; i < l; i++) { - if (this.pointInPoly(vert1, vert2[i])) { - return true; - } - } - - return false; - } - - // credit: Lascha Lagidse http://alienryderflex.com/polygon/ - private pointInPoly(v: Point[], t: Point) { - let polyCorners = v.length - 1; - let i, - j = polyCorners - 1; - let polyX = v.map((p) => p.x); - let polyY = v.map((p) => p.y); - let x = t.x; - let y = t.y; - let oddNodes = 0; - - for (i = 0; i < polyCorners; i++) { - if ( - ((polyY[i] < y && polyY[j] >= y) || (polyY[j] < y && polyY[i] >= y)) && - (polyX[i] <= x || polyX[j] <= x) - ) { - oddNodes ^= (polyX[i] + - ((y - polyY[i]) / (polyY[j] - polyY[i])) * (polyX[j] - polyX[i]) < - x) as any; - } - j = i; - } - - return oddNodes; - } -} diff --git a/client/game/comets.ts b/client/game/comets.ts deleted file mode 100644 index 84470be..0000000 --- a/client/game/comets.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { IGameState } from "../comets"; -import { fetchLeaderboard, fetchMruInfo } from "../rpc/api"; -import { getFromStore, removeFromStore, StorageKey } from "../rpc/storage"; -import { getWalletClient } from "../rpc/wallet"; -import { AttractMode } from "./attractMode"; -import { GameMode } from "./gameMode"; -import { Key } from "./keys"; -import { loop } from "./loop"; -import { Screen } from "./screen"; -import { Sound } from "./sounds"; -import { TickRecorder } from "./tickRecorder"; -import { World } from "./world"; - -export class Comets { - private lastScore = 0; - private attractMode: AttractMode; - private gameMode: GameMode; - private currentMode: IGameState; - private tickRecorder: TickRecorder; - private screen: Screen; - private isSendingTicks = false; - - constructor() { - this.init(); - } - - init() { - this.attractMode = new AttractMode(new World(), this.lastScore); - this.screen = new Screen(); - this.currentMode = this.attractMode; - this.tickRecorder = new TickRecorder(); - - const setGameMode = (gameId: string) => { - this.tickRecorder.reset(); - this.gameMode = new GameMode(new World(), { - tickRecorder: this.tickRecorder, - gameId, - }); - - this.currentMode = this.gameMode; - - this.gameMode.on("done", (source, world) => { - Sound.off(); - // Send ticks in the form of an action to MRU - // And wait for C1 to confirm score - this.lastScore = world.score; - if (!this.isSendingTicks) { - this.isSendingTicks = true; - this.tickRecorder - .sendTicks(this.lastScore) - .then(() => { - console.log("Sent ticks"); - }) - .catch((e) => { - console.error("Error sending ticks", e.message); - }) - .finally(() => { - removeFromStore(StorageKey.GAME_ID); - this.isSendingTicks = false; - console.log("Game over"); - this.init(); - // Reload page - window.location.reload(); - }); - } - // restart in attract mode - }); - }; - - this.attractMode.on("done", () => { - console.log("Start Game"); - setGameMode(getFromStore(StorageKey.GAME_ID)); - }); - } - - update(dt) { - const gameInputs = this.tickRecorder.collectInputs(); - this.currentMode.update(dt, gameInputs); - } - - render(dt) { - this.currentMode.render(this.screen, dt); - Key.update(); - } -} - -const game = new Comets(); - -// setup things -(async () => { - await Promise.all([fetchMruInfo(), fetchLeaderboard()]); - await getWalletClient(); - setTimeout(() => { - loop(game); - }, 1000); -})(); diff --git a/client/game/constants.ts b/client/game/constants.ts deleted file mode 100644 index f7b39dc..0000000 --- a/client/game/constants.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Rect } from "../comets"; - -export const WIDTH = 960; -export const HEIGHT = 720; -export const OBJECT_SCALE = 0.75; -export const OFF_RECT = 120 * OBJECT_SCALE; -export const SHIP_RECT: Rect = { - x: WIDTH / 2 - OFF_RECT, - y: HEIGHT / 2 - OFF_RECT, - width: OFF_RECT * 2, - height: OFF_RECT * 2, -}; diff --git a/client/game/demoMode.ts b/client/game/demoMode.ts deleted file mode 100644 index 3d21918..0000000 --- a/client/game/demoMode.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { Screen } from "./screen"; -import { Collisions } from "./collisions"; -import { World } from "./world"; -import { IGameState, VirtualInput } from "../comets"; - -export class DemoMode implements IGameState { - showPushStart: boolean = true; - pushStartTimer: number = 0; - - constructor(private world: World) { - this.init(); - } - - init() { - if (!this.world.started) { - this.world.startLevel(); - } - } - - update(dt, inputs?: VirtualInput) { - this.checkCollisions(); - - this.world.updateAlienTimer(dt); - - if ( - !this.world.rocks.length && - !this.world.scenery.length && - !this.world.alien - ) { - this.world.startLevel(); - } - - this.updatePushStartTimer(dt); - - this.world.update(dt, inputs); - } - - updatePushStartTimer(dt: number) { - this.pushStartTimer += dt; - - if (this.pushStartTimer >= 0.4) { - this.pushStartTimer = 0; - this.showPushStart = !this.showPushStart; - } - } - - checkCollisions() { - const { alien, rocks, alienBullets } = this.world; - const check = !!alien || !!alienBullets.length; - - if (!check) { - return; - } - - const collisions = new Collisions(); - - collisions.check([alien], rocks, false, (alien, rock) => { - this.world.shake(); - this.world.alienDestroyed(); - this.world.rockDestroyed(rock); - }); - - collisions.check(alienBullets, rocks, false, (bullet, rock) => { - this.world.shake(); - this.world.rockDestroyed(rock); - }); - } - - render(screen: Screen, delta?: number) { - this.drawBackground(screen); - this.drawPushStart(screen); - this.world.render(screen, delta); - } - - private drawBackground(screen: Screen) { - screen.draw.background(); - screen.draw.scorePlayer1(this.world.score); - screen.draw.oneCoinOnePlay(); - // screen.draw.highscore(this.world.highscore); - screen.draw.stackr(); - screen.draw.gameTitle(); - } - - private drawPushStart(screen: Screen) { - if (this.showPushStart) { - screen.draw.pushStart(); - } - } -} diff --git a/client/game/draw.ts b/client/game/draw.ts deleted file mode 100644 index fdf2203..0000000 --- a/client/game/draw.ts +++ /dev/null @@ -1,458 +0,0 @@ -import { IQuadtree, Point, Rect } from "../comets"; -import Global from "./global"; -import { Screen } from "./screen"; -import { Ship } from "./ship"; -import { random } from "./util"; - -const VectorLine = "rgba(255,255,255,.8)"; -const TextColor = "rgba(255,255,255,.8)"; -const Y_START = 20; -const DefaultLineWidth = 2; - -export function magenta(opacity: number = 1) { - return `rgba(255,0,255, ${opacity})`; -} - -export function cyan(opacity: number = 1) { - return `rgba(0,255,255, ${opacity})`; -} - -export function white(opacity: number = 1) { - return `rgba(255,255,255, ${opacity})`; -} - -export const BACKGROUND_COLOR = "#000000"; - -const magenta5 = magenta(0.5); -const cyan5 = cyan(0.5); - -export class Draw { - screen: Screen; - - constructor(private ctx: CanvasRenderingContext2D, screen: Screen) { - this.screen = screen; - } - - line( - x1: number, - y1: number, - x2: number, - y2: number, - color: string = VectorLine, - width: number = DefaultLineWidth - ) { - const { ctx } = this; - ctx.beginPath(); - ctx.lineWidth = width; - ctx.moveTo(x1, y1); - ctx.strokeStyle = color; - ctx.lineTo(x2, y2); - ctx.stroke(); - ctx.closePath(); - } - - vectorline( - x1: number, - y1: number, - x2: number, - y2: number, - color: string = VectorLine, - width: number = DefaultLineWidth - ) { - const { ctx } = this; - const old = ctx.strokeStyle; - - if (Global.burn) { - this.line(x1 - 2, y1, x2 - 2, y2, magenta5); - this.line(x1 - 1, y1 - 2, x2 - 1, y2 - 1, cyan5); - } - - this.line(x1, y1, x2, y2, color); - - ctx.strokeStyle = old; - } - - shape( - points: Point[], - x: number, - y: number, - color: string = VectorLine, - closed: boolean = true - ) { - let p1, p2; - let l = points.length - 1; - let i = 0; - - this.ctx.save(); - - for (let i = 0; i < l; i++) { - this.line( - x + points[i].x, - y + points[i].y, - x + points[i + 1].x, - y + points[i + 1].y, - color - ); - } - - if (closed) { - this.line( - x + points[l].x, - y + points[l].y, - x + points[0].x, - y + points[0].y, - color - ); - } - - this.ctx.restore(); - } - - vectorShape( - points: Point[], - x: number, - y: number, - color: string = VectorLine, - closed: boolean = true - ) { - let p1, p2; - let l = points.length - 1; - let i = 0; - - this.ctx.save(); - - for (let i = 0; i < l; i++) { - this.vectorline( - x + points[i].x, - y + points[i].y, - x + points[i + 1].x, - y + points[i + 1].y, - color - ); - } - - if (closed) { - this.vectorline( - x + points[l].x, - y + points[l].y, - x + points[0].x, - y + points[0].y, - color - ); - } - - this.ctx.restore(); - } - - rect( - x: number, - y: number, - width: number, - height: number, - color: string = VectorLine - ) { - const { ctx } = this; - ctx.beginPath(); - ctx.fillStyle = color; - ctx.fillRect(x, y, width, height); - ctx.stroke(); - ctx.closePath(); - } - - point(p: Point, fillStyle: string = VectorLine) { - this.rect( - p.x, - p.y, - this.screen.pointSize, - this.screen.pointSize, - fillStyle - ); - } - - background(color: string = BACKGROUND_COLOR) { - const { ctx } = this; - ctx.fillStyle = color; - ctx.fillRect(0, 0, this.screen.width, this.screen.height); - } - - scanlines() { - if (!Global.burn) { - return; - } - - const { ctx } = this; - const step = random(2, 5); - - for (let i = 0; i < this.screen.height - step; i += step) { - ctx.beginPath(); - - ctx.lineWidth = 1; - ctx.moveTo(0, i); - ctx.strokeStyle = "#001111"; - ctx.lineTo(this.screen.width, i); - ctx.stroke(); - - ctx.moveTo(0, i + 1); - ctx.strokeStyle = "rgba(255,0,255,.5)"; - ctx.lineTo(this.screen.width, i + 1); - ctx.stroke(); - - ctx.moveTo(0, i + 2); - ctx.strokeStyle = "rgba(0,255,255,.3)"; - ctx.lineTo(this.screen.width, i + 2); - ctx.stroke(); - - ctx.closePath(); - } - } - - bounds(rect: Rect, color: string = VectorLine) { - const { ctx } = this; - - if (!rect) { - return; - } - - ctx.save(); - ctx.beginPath(); - ctx.strokeStyle = color; - ctx.lineWidth = 2; - ctx.moveTo(rect.x, rect.y); - ctx.lineTo(rect.x + rect.width, rect.y); - ctx.lineTo(rect.x + rect.width, rect.y + rect.height); - ctx.lineTo(rect.x, rect.y + rect.height); - ctx.lineTo(rect.x, rect.y); - ctx.stroke(); - ctx.closePath(); - ctx.restore(); - } - - text( - text: string, - x: number, - y: number, - size: number, - color: string = TextColor - ) { - const { ctx } = this; - - ctx.save(); - ctx.font = `${size}pt hyperspace`; - ctx.textBaseline = "middle"; - ctx.lineWidth = 1; - - if (Global.burn) { - ctx.strokeStyle = magenta5; - ctx.strokeText(text, x - 2, y - 2); - - ctx.strokeStyle = cyan5; - ctx.strokeText(text, x - 1, y - 1); - } - - ctx.strokeStyle = color; - ctx.strokeText(text, x, y); - - ctx.restore(); - } - - text2(text: string, size: number, cb: (width: number) => Point) { - const { ctx } = this; - - ctx.save(); - ctx.font = `${size}pt hyperspace`; - ctx.textBaseline = "middle"; - ctx.lineWidth = 1; - - const width = ctx.measureText(text).width; - const point = cb(width); - - if (Global.burn) { - ctx.strokeStyle = magenta(0.5); - ctx.strokeText(text, point.x - 2, point.y - 2); - - ctx.strokeStyle = cyan(0.5); - ctx.strokeText(text, point.x - 1, point.y - 1); - } - - ctx.strokeStyle = TextColor; - ctx.strokeText(text, point.x, point.y); - ctx.restore(); - } - - text3(text: string, size: number, cb: (width: number) => Point) { - const { ctx } = this; - - ctx.save(); - ctx.font = `${size}pt hyperspace`; - ctx.textBaseline = "middle"; - - const width = ctx.measureText(text).width; - const point = cb(width); - - if (Global.burn) { - ctx.fillStyle = magenta(0.5); - ctx.fillText(text, point.x - 2, point.y - 2); - - ctx.fillStyle = cyan(0.5); - ctx.fillText(text, point.x - 1, point.y - 1); - } - - ctx.fillStyle = TextColor; - ctx.fillText(text, point.x, point.y); - - ctx.restore(); - } - - scorePlayer1(score) { - const X_START = 100; - let text = score.toString(); - while (text.length < 2) { - text = "0" + text; - } - this.text(text, X_START, Y_START, this.screen.font.medium); - } - - highscore(score: number) { - let text = score.toString(); - - while (text.length < 2) { - text = "0" + text; - } - - this.text2(text, this.screen.font.small, (width) => { - return { - x: this.screen.width2 - width / 2, - y: Y_START, - }; - }); - } - - gameTitle() { - this.text2("Comets", this.screen.font.small, (width) => { - return { - x: this.screen.width2 - width / 2, - y: Y_START, - }; - }); - } - - oneCoinOnePlay() { - this.text2("1 coin 1 play", this.screen.font.medium, (width) => { - return { - x: this.screen.width2 - width / 2, - y: (this.screen.height / 8) * 7, - }; - }); - } - - pushStart() { - this.screen.draw.text3("Press Enter", this.screen.font.xlarge, (width) => { - return { - x: this.screen.width2 - width / 2, - y: this.screen.height / 8, - }; - }); - } - - player1() { - this.screen.draw.text3("player 1", this.screen.font.xlarge, (width) => { - return { - x: this.screen.width2 - width / 2, - y: screen.height / 4.5, - }; - }); - } - - gameOver() { - this.screen.draw.text3("game over", this.screen.font.xlarge, (width) => { - return { - x: this.screen.width2 - width / 2, - y: screen.height / 4.5, - }; - }); - } - - stackr() { - this.text2("Powered by Stackr Labs", this.screen.font.small, (width) => { - return { - x: this.screen.width2 - width / 2, - y: this.screen.height - this.screen.font.small, - }; - }); - } - - drawExtraLives(lives: number) { - lives = Math.min(lives, 10); - const life = new Ship(0, 0); - const loc = (life.x + life.width) * 2.3; - - const y = Y_START + this.screen.font.medium + 10; - - for (let i = 0; i < lives; i++) { - life.origin.x = 80 + i * loc; - life.origin.y = y; - life.render(this.screen); - } - } - - circle(x: number, y: number, radius: number, color: string = VectorLine) { - const { ctx } = this; - - ctx.setLineDash([1, 10]); - - if (Global.burn) { - ctx.beginPath(); - ctx.arc(x - 2, y - 2, radius, 0, 2 * Math.PI, false); - ctx.strokeStyle = magenta(0.2); - ctx.stroke(); - ctx.closePath(); - - ctx.beginPath(); - ctx.arc(x - 1, y - 1, radius, 0, 2 * Math.PI, false); - ctx.strokeStyle = cyan(0.2); - ctx.stroke(); - ctx.closePath(); - } - - ctx.beginPath(); - ctx.arc(x, y, radius, 0, 2 * Math.PI, false); - ctx.strokeStyle = color; - ctx.stroke(); - ctx.closePath(); - - ctx.setLineDash([]); - } - - quadtree(tree: IQuadtree) { - const { ctx } = this; - - ctx.save(); - - const drawNode = (node: IQuadtree) => { - const x = node.xmid - node.width2; - const y = node.ymid - node.height2; - - this.bounds( - { - x, - y, - width: node.width2 * 2, - height: node.height2 * 2, - }, - "#00FF00" - ); - }; - - const drawTree = (child: IQuadtree) => { - child.nodes.forEach((node) => { - drawTree(node); - }); - - drawNode(child); - }; - - drawTree(tree); - - ctx.restore(); - } -} diff --git a/client/game/events.ts b/client/game/events.ts deleted file mode 100644 index ab1a874..0000000 --- a/client/game/events.ts +++ /dev/null @@ -1,21 +0,0 @@ -export class EventSource { - - protected handlers: { [event: string]: ((...args: any[])=> void)[]} = {}; - - on(event: string, handler: (...args: any[]) => void) { - if (!this.handlers[event]) { - this.handlers[event] = []; - } - this.handlers[event].push(handler); - } - - off(event: string, handler: (...args: any[]) => void) { - this.handlers[event] = this.handlers[event].filter(x => x !== handler); - } - - trigger(event: string, ...args: any[] ) { - const handlers = this.handlers[event] || []; - handlers.forEach(x => x(this, ...args)); - } - -} \ No newline at end of file diff --git a/client/game/explosion.ts b/client/game/explosion.ts deleted file mode 100644 index 33f4a4a..0000000 --- a/client/game/explosion.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { OBJECT_SCALE } from "./constants"; -import { EventSource } from "./events"; -import { Screen } from "./screen"; -import { random } from "./util"; -import { Vector } from "./vector"; - -const VELOCITY = 300 * OBJECT_SCALE; - -// general, garden variety explosion -export class Explosion extends EventSource { - life: number = 1; - points: { x: number; y: number; vx: number; vy: number; alpha: number }[] = - []; - - constructor( - private x: number, - private y: number, - private size: number = 100 - ) { - super(); - - for (let i = 0; i < 15; i++) { - const v = Vector.fromAngle(random(1, 360), random(0, 1) * VELOCITY); - this.points.push({ x: x, y: y, vx: v.x, vy: v.y, alpha: random(0, 1) }); - } - } - - update(dt: number) { - this.points.forEach((point) => { - point.x += point.vx * dt; - point.y += point.vy * dt; - point.alpha -= 0.002; - }); - - this.life -= dt; - - if (this.life <= 0.1) { - this.trigger("expired"); - } - } - - render(screen: Screen, dt?: number) { - this.points.forEach((p) => { - if (random(1, 10) % 2 === 0) { - screen.draw.rect(p.x, p.y, 2, 2, `rgba(255,255,255,${p.alpha})`); - } - }); - } -} diff --git a/client/game/flash.ts b/client/game/flash.ts deleted file mode 100644 index 5801232..0000000 --- a/client/game/flash.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Screen } from './screen'; -import { EventSource } from './events'; -import { IGameState } from '../comets'; - -export class Flash extends EventSource implements IGameState { - - constructor(private frames: number) { - super(); - } - - render(screen: Screen) { - this.draw(screen); - } - - update(dt: number) { - this.frames--; - if (this.frames <= 0) { - this.trigger('expired'); - } - } - - draw(screen: Screen) { - screen.draw.background('#ffffff'); - screen.draw.scanlines(); - } - -} \ No newline at end of file diff --git a/client/game/gameMode.ts b/client/game/gameMode.ts deleted file mode 100644 index 01e3a78..0000000 --- a/client/game/gameMode.ts +++ /dev/null @@ -1,383 +0,0 @@ -import { IGameState, Rect, VirtualInput } from "../comets"; -import { Collisions } from "./collisions"; -import { HEIGHT, WIDTH } from "./constants"; -import { EventSource } from "./events"; -import Global from "./global"; -import { Object2D } from "./object2d"; -import { Screen } from "./screen"; -import { Sound } from "./sounds"; -import { Thumper } from "./thump"; -import { updateSeed } from "./util"; -import { World } from "./world"; - -export const ACTIONS = [ - "isThrust", - "wasRotateLeft", - "isRotateLeft", - "wasRotateRight", - "isRotateRight", - "isFire", - "wasHyperspace", -]; - -const WAIT_TIME = 5; -type Options = { - gameId?: string; - tickRecorder?: { - recordInputs: (ticks) => void; - }; -}; -export class GameMode extends EventSource implements IGameState { - bounds: Object2D[] = []; - thumper: Thumper; - - private lastCollisions: Collisions; - options: Options; - - constructor(private world: World, options?: Options) { - super(); - this.options = { - tickRecorder: { - recordInputs: () => {}, - }, - gameId: options?.gameId, - }; - - if (options?.tickRecorder) { - this.options.tickRecorder = options.tickRecorder; - } - updateSeed(this.options.gameId); - } - - init() { - Sound.on(); - this.world.addShip(WIDTH / 2, HEIGHT / 2); - this.world.startLevel(); - this.thumper = new Thumper(); - } - - deserializeAndUpdate(dt: number, input: string) { - const vi = input.split("").reduce((acc, action, index) => { - acc[ACTIONS[index]] = action === "1"; - return acc; - }, {}); - - this.update(dt, vi); - } - - update(dt: number, inputs?: VirtualInput) { - this.options.tickRecorder.recordInputs(inputs); - this.world.levelTimer += dt; - - if (this.thumper && this.world.ship) { - this.thumper.update(dt); - } - - if (this.world.gameOver) { - this.world.gameOverTimer += dt; - - if (this.world.gameOverTimer >= WAIT_TIME) { - this.trigger("done", this.world); - } - } - - if (!this.world.started) { - if (this.world.levelTimer >= 2) { - this.init(); - this.world.started = true; - } - return; - } - - // collisions - this.lastCollisions = this.checkCollisions(dt); - - // alien? - this.world.updateAlienTimer(dt); - - if (!this.world.gameOver) { - // place ship after crash - if (this.world.shouldTryToPlaceShip()) { - this.world.tryPlaceShip(dt); - } - - // check for next level - if (this.world.shouldCheckForNextLevel()) { - this.world.startLevel(); - this.thumper.reset(); - } - } - - // game over - if (!this.world.lives) { - this.world.gameOver = true; - } - - // update all objects - this.world.update(dt, inputs); - } - - render(screen: Screen, delta: number) { - if (Global.paused) { - return; - } - - this.renderStatic(screen); - - this.world.render(screen, delta); - } - - private renderStatic(screen: Screen) { - screen.draw.background(); - screen.draw.gameTitle(); - screen.draw.stackr(); - screen.draw.scorePlayer1(this.world.score); - screen.draw.drawExtraLives(this.world.lives); - - // remaining shields - if (this.world.ship) { - screen.draw.vectorline(40, 80, 140, 80, `rgba(255,255,255,.4)`); - screen.draw.vectorline( - 40, - 80, - 40 + this.world.ship.shield * 100, - 80, - `rgba(255,255,255,.6)` - ); - } - - // player 1 - if (!this.world.started) { - screen.draw.player1(); - } - - if (this.world.gameOver) { - screen.draw.gameOver(); - } - - // debug stuff - if (Global.debug) { - this.renderDebug(screen); - } - - if (Global.god) { - screen.draw.text2("god", screen.font.small, (width) => { - return { x: screen.width - width - 10, y: screen.height - 80 }; - }); - } - } - - private renderDebug(screen: Screen) { - screen.draw.text2("debug mode", screen.font.small, (width) => { - return { x: screen.width - width - 10, y: screen.height - 40 }; - }); - - if (this.bounds) { - this.bounds.forEach((r) => { - screen.draw.bounds(r, "#fc058d"); - }); - } - - if (!this.world.ship && this.world.lives) { - let rect: Rect = screen.shipRect; - screen.draw.bounds(rect, "#00ff00"); - } - - if (this.world.ship) { - screen.draw.text( - this.world.ship.angle.toString(), - this.world.ship.origin.x + 20, - this.world.ship.origin.y + 20, - 10 - ); - screen.draw.text( - this.world.ship.velocity.x.toString(), - this.world.ship.origin.x + 20, - this.world.ship.origin.y + 40, - 10 - ); - screen.draw.text( - this.world.ship.velocity.y.toString(), - this.world.ship.origin.x + 20, - this.world.ship.origin.y + 60, - 10 - ); - } - - const date = new Date(null); - date.setSeconds(this.world.levelTimer); - - screen.draw.text2( - date.toISOString().substr(11, 8), - screen.font.small, - (width) => { - return { x: 10, y: screen.height - 40 }; - } - ); - - if (this.lastCollisions) { - screen.draw.quadtree(this.lastCollisions.tree); - } - } - - private checkCollisions(dt: number) { - const { ship, rocks, shipBullets, alien, alienBullets, shockwaves } = - this.world; - - if (!this.world.shouldCheckCollisions()) { - return; - } - - this.bounds.length = 0; - - const collisions = new Collisions(); - - collisions.bulletCheck( - shipBullets, - rocks, - (bullet, rock) => { - this.world.shake(); - this.world.addScore(rock, "rock"); - this.world.rockDestroyed(rock); - bullet.destroy(); - }, - (bullet1, bullet2, rock) => { - if (Global.debug) { - this.bounds.push(rock); - } - } - ); - - collisions.bulletCheck( - shipBullets, - [alien], - (bullet, alien) => { - this.world.shake(); - this.world.addScore(alien, "alien"); - this.world.alienDestroyed(); - bullet.destroy(); - }, - (bullet1, bullet2, alien) => { - if (Global.debug) { - this.bounds.push(alien); - } - } - ); - - // shockwaves can break rocks - let cowboys = []; - shockwaves - .filter((x) => x.rocks.length) - .forEach((y) => cowboys.push(...y.rocks)); - - if (cowboys.length) { - let indians = this.world.rocks.filter((x) => cowboys.indexOf(x) < 0); - collisions.check(cowboys, indians, false, (cowboy, indian) => { - this.world.addScore(cowboy, "cowboy"); - this.world.addScore(indian, "indian"); - this.world.rockDestroyed(cowboy); - this.world.rockDestroyed(indian); - }); - } - - if (!Global.god) { - collisions.check( - [ship], - rocks, - true, - (ship, rock) => { - this.world.shake(); - this.world.addScore(rock, "rock in collision"); - this.world.rockDestroyed(rock); - - ship.shield -= 0.25; - - if (ship.shield <= 0) { - this.world.shipDestroyed(); - } - }, - (ship, rock) => { - if (Global.debug) { - this.bounds.push(rock); - } - } - ); - - collisions.check( - [ship], - [alien], - true, - (ship, alien) => { - this.world.shake(); - this.world.addScore(alien, "alien in collision"); - this.world.alienDestroyed(); - - ship.shield -= 0.5; - - if (ship.shield <= 0) { - this.world.shipDestroyed(); - } - }, - (ship, alien) => { - if (Global.debug) { - this.bounds.push(alien); - } - } - ); - - collisions.check( - alienBullets, - [ship], - true, - (bullet, ship) => { - this.world.shake(); - ship.shield -= 1; - - if (ship.shield <= 0) { - this.world.shipDestroyed(); - } - - bullet.destroy(); - }, - (bullet, ship) => { - if (Global.debug) { - this.bounds.push(ship); - } - } - ); - } - - collisions.check( - [alien], - rocks, - false, - (alien, rock) => { - this.world.shake(); - this.world.alienDestroyed(); - this.world.rockDestroyed(rock); - }, - (alien, rock) => { - if (Global.debug) { - this.bounds.push(rock); - } - } - ); - - collisions.check( - alienBullets, - rocks, - false, - (bullet, rock) => { - this.world.shake(); - this.world.rockDestroyed(rock); - }, - (bullet, rock) => { - if (Global.debug) { - this.bounds.push(rock); - } - } - ); - - return collisions; - } -} diff --git a/client/game/global.ts b/client/game/global.ts deleted file mode 100644 index 3f079af..0000000 --- a/client/game/global.ts +++ /dev/null @@ -1,10 +0,0 @@ -// yeah, yeah - -class Global { - debug: boolean = false; - paused: boolean = false; - god: boolean = false; - burn: boolean = true; // monitor burn effect -} - -export default new Global(); \ No newline at end of file diff --git a/client/game/highScoreMode.ts b/client/game/highScoreMode.ts deleted file mode 100644 index 1168a4e..0000000 --- a/client/game/highScoreMode.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { IGameState } from "../comets"; -import { Highscores } from "./highscores"; -import { Screen } from "./screen"; -import { isAddress } from "viem"; - -const formatAddress = (address: string) => { - if (isAddress(address)) { - return `${address.slice(0, 6)}...${address.slice(-4)}`; - } - // Is an ENS name then - return address.padEnd(14, " "); -}; - -export class HighScoreMode implements IGameState { - blink: number = 0; - showPushStart: boolean = true; - - constructor(private score) {} - - update(dt) { - this.blink += dt; - - if (this.blink >= 0.4) { - this.blink = 0; - this.showPushStart = !this.showPushStart; - } - } - - render(screen: Screen, delta: number) { - this.drawBackground(screen); - this.drawPushStart(screen); - this.drawHighScores(screen); - } - - private drawBackground(screen: Screen) { - screen.draw.background(); - screen.draw.stackr(); - screen.draw.scorePlayer1(this.score); - screen.draw.oneCoinOnePlay(); - screen.draw.gameTitle(); - } - - private drawHighScores(screen: Screen) { - const screenX = screen.width / 2; - const startY = - Math.ceil(screen.height / 4.5) + (screen.font.xlarge + screen.font.small); - const spacing = screen.font.medium + screen.font.small; - - screen.draw.text2("Leaderboard", screen.font.large, (width) => { - return { - x: screenX - width / 2, - y: screen.height / 4.5, - }; - }); - - if (Highscores.scores.length === 0) { - screen.draw.text2("not enough data", screen.font.medium, (width) => { - return { - x: screenX - width / 2, - y: startY, - }; - }); - return; - } - - for (let i = 0; i < Highscores.scores.length; i++) { - const y = startY + i * spacing; - const text = `${this.pad(i + 1, " ", 2)}.${this.pad( - formatAddress(Highscores.scores[i].address), - " ", - 13 - )} ${this.pad("", " ", 2)} ${this.pad( - Highscores.scores[i].score, - " ", - 8 - )}`; - - screen.draw.text2(text, screen.font.large, (width) => { - return { - x: screenX - width / 2, - y: y, - }; - }); - } - } - - private drawPushStart(screen: Screen) { - if (this.showPushStart) { - screen.draw.pushStart(); - } - } - - private pad(text: any, char: string, count: number) { - text = text.toString(); - while (text.length < count) { - text = char + text; - } - return text; - } -} diff --git a/client/game/highscores.ts b/client/game/highscores.ts deleted file mode 100644 index 23c5503..0000000 --- a/client/game/highscores.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { fetchLeaderboard } from "../rpc/api"; -import { getFromStore, StorageKey } from "../rpc/storage"; - -class Highscores { - constructor() {} - - get scores(): { score: number; address: string }[] { - const data = getFromStore(StorageKey.LEADERBOARD); - return data ? data : []; - } - - get top() { - return this.scores[0]; - } - - qualifies(score: number) { - const less = highscores.scores.filter((x) => x.score < score); - return !!less.length; - } -} - -const highscores = new Highscores(); - -export { highscores as Highscores }; diff --git a/client/game/keys.ts b/client/game/keys.ts deleted file mode 100644 index ed1fb18..0000000 --- a/client/game/keys.ts +++ /dev/null @@ -1,174 +0,0 @@ -import * as Hammer from "hammerjs"; - -type KeyPressMap = { [key: number]: boolean }; - -export const Keys = { - HYPERSPACE: 17, - ROTATE_LEFT: 37, - ROTATE_LEFT_A: 65, - ROTATE_RIGHT: 39, - ROTATE_RIGHT_D: 68, - THRUST: 38, - THRUST_W: 87, - FIRE: 32, - // DEBUG: 90, - // PAUSE: 80, - // GOD: 71, - // MONITOR_BURN: 66, -}; - -export class _Key { - keys: KeyPressMap = {}; - prev: KeyPressMap = {}; - touched: boolean = false; - mc: any; - - constructor() { - window.onkeydown = (e) => { - this.keys[e.keyCode] = true; - }; - - window.onkeyup = (e) => { - this.keys[e.keyCode] = false; - }; - - const stage = document.getElementById("game"); - this.mc = new Hammer.Manager(stage); - - const pan = new Hammer.Pan(); - const tap = new Hammer.Tap(); - const pinch = new Hammer.Pinch({ - enable: true, - }); - - this.mc.add(pan); - this.mc.add(tap, { - interval: 50, - }); - this.mc.add(pinch); - - this.mc.on("panup", (e) => { - this.thrust(true); - }); - - this.mc.on("panleft", (e) => { - this.rotateLeft(true); - }); - - this.mc.on("panright", (e) => { - this.rotateRight(true); - }); - - this.mc.on("panend", (e) => { - this.thrust(false); - this.rotateLeft(false); - this.rotateRight(false); - }); - - this.mc.on("tap", (e) => { - this.fire(true); - this.touched = true; - }); - - this.mc.on("pinchout", (e) => { - this.hyperspace(true); - }); - - this.mc.on("pinchend", (e) => { - this.hyperspace(false); - }); - } - - update() { - Object.keys(this.keys).forEach((key) => { - this.prev[key] = this.keys[key]; - }); - - if (this.touched) { - this.fire(false); - } - - this.touched = !this.touched; - } - - clear() { - this.keys = {}; - this.prev = {}; - } - - isPressed(key: number) { - return this.prev[key] === false && this.keys[key] === true; - } - - wasPressed(key: number) { - return this.prev[key] && !this.keys[key]; - } - - isDown(key: number) { - return this.keys[key]; - } - - isEnterPressed() { - return this.keys[13]; - } - - isRotateLeft() { - return this.keys[Keys.ROTATE_LEFT] || this.keys[Keys.ROTATE_LEFT_A]; - } - - isRotateRight() { - return this.keys[Keys.ROTATE_RIGHT] || this.keys[Keys.ROTATE_RIGHT_D]; - } - - isThrust() { - return this.keys[Keys.THRUST] || this.keys[Keys.THRUST_W]; - } - - isFire() { - return this.keys[Keys.FIRE]; - } - - isHyperspace() { - return this.keys[Keys.HYPERSPACE]; - } - - wasRotateLeft() { - return ( - this.isPressed(Keys.ROTATE_LEFT) || this.isPressed(Keys.ROTATE_LEFT_A) - ); - } - - wasRotateRight() { - return ( - this.isPressed(Keys.ROTATE_RIGHT) || this.isPressed(Keys.ROTATE_RIGHT_D) - ); - } - - wasHyperspace() { - return this.isPressed(Keys.HYPERSPACE); - } - - private rotateLeft = (active: boolean) => { - this.keys[Keys.ROTATE_LEFT] = active; - this.keys[Keys.ROTATE_LEFT_A] = active; - }; - - private rotateRight = (active: boolean) => { - this.keys[Keys.ROTATE_RIGHT] = active; - this.keys[Keys.ROTATE_RIGHT_D] = active; - }; - - private thrust = (active: boolean) => { - this.keys[Keys.THRUST] = active; - }; - - private fire = (active: boolean) => { - this.keys[Keys.FIRE] = active; - }; - - private hyperspace = (active: boolean) => { - this.keys[Keys.HYPERSPACE] = active; - }; -} - -export const Key = new _Key(); diff --git a/client/game/lineclip.ts b/client/game/lineclip.ts deleted file mode 100644 index 69275e9..0000000 --- a/client/game/lineclip.ts +++ /dev/null @@ -1,119 +0,0 @@ - -// https://github.com/mapbox/lineclip - -// intersect a segment against one of the 4 lines that make up the bbox - -function intersect(a, b, edge, bbox) { - return edge & 8 ? [a[0] + (b[0] - a[0]) * (bbox[3] - a[1]) / (b[1] - a[1]), bbox[3]] : // top - edge & 4 ? [a[0] + (b[0] - a[0]) * (bbox[1] - a[1]) / (b[1] - a[1]), bbox[1]] : // bottom - edge & 2 ? [bbox[2], a[1] + (b[1] - a[1]) * (bbox[2] - a[0]) / (b[0] - a[0])] : // right - edge & 1 ? [bbox[0], a[1] + (b[1] - a[1]) * (bbox[0] - a[0]) / (b[0] - a[0])] : // left - null; -} - -// bit code reflects the point position relative to the bbox: - -// left mid right -// top 1001 1000 1010 -// mid 0001 0000 0010 -// bottom 0101 0100 0110 - -function bitCode(p, bbox) { - var code = 0; - - if (p[0] < bbox[0]) code |= 1; // left - else if (p[0] > bbox[2]) code |= 2; // right - - if (p[1] < bbox[1]) code |= 4; // bottom - else if (p[1] > bbox[3]) code |= 8; // top - - return code; -} - -// Cohen-Sutherland line clipping algorithm, adapted to efficiently -// handle polylines rather than just segments - -export function lineclip(points, bbox, result) { - - var len = points.length, - codeA = bitCode(points[0], bbox), - part = [], - i, a, b, codeB, lastCode; - - if (!result) result = []; - - for (i = 1; i < len; i++) { - a = points[i - 1]; - b = points[i]; - codeB = lastCode = bitCode(b, bbox); - - while (true) { - - if (!(codeA | codeB)) { // accept - part.push(a); - - if (codeB !== lastCode) { // segment went outside - part.push(b); - - if (i < len - 1) { // start a new line - result.push(part); - part = []; - } - } else if (i === len - 1) { - part.push(b); - } - break; - - } else if (codeA & codeB) { // trivial reject - break; - - } else if (codeA) { // a outside, intersect with clip edge - a = intersect(a, b, codeA, bbox); - codeA = bitCode(a, bbox); - - } else { // b outside - b = intersect(a, b, codeB, bbox); - codeB = bitCode(b, bbox); - } - } - - codeA = lastCode; - } - - if (part.length) result.push(part); - - return result; -} - -// Sutherland-Hodgeman polygon clipping algorithm -export function polygonclip(points, bbox) { - - var result, edge, prev, prevInside, i, p, inside; - - // clip against each side of the clip rectangle - for (edge = 1; edge <= 8; edge *= 2) { - result = []; - prev = points[points.length - 1]; - prevInside = !(bitCode(prev, bbox) & edge); - - for (i = 0; i < points.length; i++) { - p = points[i]; - inside = !(bitCode(p, bbox) & edge); - - // if segment goes through the clip window, add an intersection - if (inside !== prevInside) result.push(intersect(prev, p, edge, bbox)); - - if (inside) result.push(p); // add a point if it's inside - - prev = p; - prevInside = inside; - } - - points = result; - - if (!points.length) break; - } - - return result; -} - diff --git a/client/game/loop.ts b/client/game/loop.ts deleted file mode 100644 index 4da58c4..0000000 --- a/client/game/loop.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Comets } from "./comets"; - -const timestamp = () => { - return window.performance?.now - ? window.performance.now() - : new Date().getTime(); -}; - -let now: number; -let delta = 0; -let last = timestamp(); - -const DT = 1 / 60; -const ONE_SECOND = 1000; - -const init = (state: Comets) => { - const frame = () => { - now = timestamp(); - delta += Math.min(1, (now - last) / ONE_SECOND); - - while (delta > DT) { - // Every time we update world state, we also update the Input Tracker - state.update(DT); - delta -= DT; - } - - state.render(delta); - - last = now; - - requestAnimationFrame(frame); - }; - - frame(); -}; - -export const loop = (state: Comets) => { - init(state); -}; diff --git a/client/game/lut.ts b/client/game/lut.ts deleted file mode 100644 index 8fea0b8..0000000 --- a/client/game/lut.ts +++ /dev/null @@ -1,20 +0,0 @@ - -/* lookup tables */ - -const RAD = {}; -const COS = {}; -const SIN = {}; -const r = Math.PI / 180; - -for(let i = 0; i <= 360; i++) { - RAD[i] = i * r; - COS[i] = Math.cos(RAD[i]); - SIN[i] = Math.sin(RAD[i]); - - RAD[-i] = -i * r; - COS[-i] = Math.cos(RAD[-i]); - SIN[-i] = Math.sin(RAD[-i]); -} - -export { RAD, COS, SIN } - diff --git a/client/game/object2d.ts b/client/game/object2d.ts deleted file mode 100644 index 9951516..0000000 --- a/client/game/object2d.ts +++ /dev/null @@ -1,179 +0,0 @@ -import { IGameState, Point, Rect } from "../comets"; -import { HEIGHT, OBJECT_SCALE, WIDTH } from "./constants"; -import { EventSource } from "./events"; -import { COS, SIN } from "./lut"; -import { Screen } from "./screen"; -import { Vector } from "./vector"; - -export abstract class Object2D extends EventSource implements Rect, IGameState { - angle: number = 360; - velocity: Vector = new Vector(0, 0); - origin: Vector; - - private _xmin: number = 0; - private _xmax: number = 0; - private _ymin: number = 0; - private _ymax: number = 0; - private _width: number = 0; - private _height: number = 0; - private _points: Point[]; - protected _score: number = 0; - - abstract update(dt?: number): void; - abstract render(screen: Screen, dt?: number): void; - - get score(): number { - return this._score; - } - - set score(value: number) { - this._score = value; - } - - constructor(x: number, y: number) { - super(); - this.origin = new Vector(x, y); - } - - set points(points: Point[]) { - points.forEach((p) => { - p.x *= OBJECT_SCALE; - p.y *= OBJECT_SCALE; - }); - this._points = points; - this.calcBounds(); - } - - get points(): Point[] { - return this._points; - } - - private calcBounds() { - this._points.forEach((p) => { - if (p.x < this._xmin) this._xmin = p.x; - if (p.x > this._xmax) this._xmax = p.x; - if (p.y < this._ymin) this._ymin = p.y; - if (p.y > this._ymax) this._ymax = p.y; - }); - this._width = this._xmax - this._xmin; - this._height = this._ymax - this._ymin; - } - - rotate(angle: number) { - this.angle += angle; - - if (this.angle < 1) { - this.angle += 360; - } - - if (this.angle > 360) { - this.angle -= 360; - } - - const c = COS[angle]; - const s = SIN[angle]; - - this.points.forEach((p) => { - const newX = c * p.x - s * p.y; - const newY = s * p.x + c * p.y; - p.x = newX; - p.y = newY; - }); - - this.calcBounds(); - } - - move(dt?: number) { - dt = dt ? dt : 1; - - this.origin.x += this.velocity.x * dt; - this.origin.y += this.velocity.y * dt; - - if (this.origin.x > WIDTH) { - this.origin.x -= WIDTH; - } - - if (this.origin.x < 0) { - this.origin.x += WIDTH; - } - - if (this.origin.y > HEIGHT) { - this.origin.y -= HEIGHT; - } - - if (this.origin.y < 0) { - this.origin.y += HEIGHT; - } - } - - scale(factor: number) { - this.points.forEach((point) => { - point.x *= factor; - point.y *= factor; - }); - this.calcBounds(); - } - - draw(screen: Screen, closed: boolean = true, color = "rgba(255,255,255,.8)") { - screen.draw.vectorShape( - this.points, - this.origin.x, - this.origin.y, - color, - closed - ); - } - - get x(): number { - return this.origin.x + this._xmin; - } - - set x(x: number) { - this.origin.x = x; - } - - get y(): number { - return this.origin.y + this._ymin; - } - - set y(y: number) { - this.origin.y = y; - } - - get width(): number { - return this._width; - } - - get height(): number { - return this._height; - } - - get vertices(): Point[] { - return this.points.map((p) => { - return { - x: this.origin.x + p.x, - y: this.origin.y + p.y, - }; - }); - } - - collided(rect2: Rect) { - if ( - rect2 && - this.x < rect2.x + rect2.width && - this.x + this.width > rect2.x && - this.y < rect2.y + rect2.height && - this.height + this.y > rect2.y - ) { - return true; - } - return false; - } - - destroy() { - for (let event in this.handlers) { - this.handlers[event] = null; - } - this.handlers = {}; - } -} diff --git a/client/game/quadtree.ts b/client/game/quadtree.ts deleted file mode 100644 index 95ffab8..0000000 --- a/client/game/quadtree.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { Rect, IQuadtree } from '../comets'; - -export class Quadtree implements IQuadtree { - - nodes: Quadtree[]; - objects: Rect[]; - width2: number; - height2: number; - xmid: number; - ymid: number; - - constructor(public bounds: Rect, private maxObjects: number = 1, private maxLevels: number = 4, private level = 0) { - this.objects = []; - this.nodes = []; - this.width2 = this.bounds.width / 2; - this.height2 = this.bounds.height / 2; - this.xmid = this.bounds.x + this.width2; - this.ymid = this.bounds.y + this.height2; - } - - insert(rect: Rect) { - if (!rect) { - return; - } - - let i = 0; - let indices: number[]; - - if (this.nodes.length) { - indices = this.getIndex(rect); - - if (indices.length) { - indices.forEach(i => { - this.nodes[i].insert(rect); - }); - return; - } - } - - this.objects.push(rect); - - if (this.objects.length > this.maxObjects && this.level < this.maxLevels) { - if (!this.nodes.length) { - this.split(); - } - - while (i < this.objects.length) { - indices = this.getIndex(this.objects[i]); - - if (indices.length) { - let object = this.objects.splice(i, 1)[0]; - indices.forEach(n => { - this.nodes[n].insert(object); - }); - } else { - i = i + 1; - } - } - } - } - - retrieve(rect: Rect) { - if (!rect) { - return []; - } - - let indices = this.getIndex(rect); - let result = this.objects; - - if (this.nodes.length) { - if (indices.length) { - indices.forEach(i => { - result = result.concat(this.nodes[i].retrieve(rect)); - }); - } else { - for (let i = 0; i < this.nodes.length; i++) { - result = result.concat(this.nodes[i].retrieve(rect)); - } - } - } - - return result.filter((x, n, a) => a.indexOf(x) === n); - }; - - clear() { - this.objects = []; - - for (let i = 0; i < this.nodes.length; i++) { - if (this.nodes[i]) { - this.nodes[i].clear(); - } - } - - this.nodes = []; - }; - - private getIndex(rect: Rect): number[] { - if (!rect) { - return []; - } - - const results = []; - const { xmid, ymid } = this; - const top = (rect.y <= ymid); - const bottom = (rect.y > ymid); - - if (rect.x <= xmid) { - if (top) { - results.push(1); - let zero = false; - - if (rect.x + rect.width > xmid) { - results.push(0); - zero = true; - } - - if (rect.y + rect.height > ymid) { - results.push(2); - if (zero) { - results.push(3); - } - } - } else if (bottom) { - results.push(2); - - if (rect.x + rect.width > xmid) { - results.push(3); - } - } - - } else if (rect.x > xmid) { - if (top) { - results.push(0); - if (rect.y + rect.height > ymid) { - results.push(3); - } - } else { - results.push(3) - } - } - - return results; - }; - - private split() { - const width = Math.round(this.width2); - const height = Math.round(this.height2); - const x = Math.round(this.bounds.x); - const y = Math.round(this.bounds.y); - - const create = (x, y) => { - const bounds: Rect = { - x: x, - y: y, - width: width, - height: height - }; - return new Quadtree(bounds, this.maxObjects, this.maxLevels, this.level + 1); - }; - - // top right, top left, bottom left, bottom right - this.nodes = [create(x + width, y), create(x, y), create(x, y + height), create(x + width, y + height)]; - }; -} \ No newline at end of file diff --git a/client/game/rocks.ts b/client/game/rocks.ts deleted file mode 100644 index 777d4e3..0000000 --- a/client/game/rocks.ts +++ /dev/null @@ -1,223 +0,0 @@ -import { HEIGHT, OBJECT_SCALE, WIDTH } from "./constants"; -import { Object2D } from "./object2d"; -import { Screen } from "./screen"; -import { largeExplosion, mediumExplosion, smallExplosion } from "./sounds"; -import { random, randomFloat } from "./util"; -import { Vector } from "./vector"; - -export enum RockSize { - Small = 5, - Medium = 10, - Large = 20, -} - -export class Rock extends Object2D { - rot: number; - rotTimer: number = 0; - size: RockSize; - timeToRot: number; - - private rock1 = [ - [0.5, -2], - [2, -1], - [2, -0.7], - [1.2, 0], - [2, 1], - [1, 2], - [0.5, 1.5], - [-1, 2], - [-2, 0.7], - [-2, -1], - [-0.5, -1], - [-1, -2], - ]; - - private rock2 = [ - [0, -1.5], - [1, -2], - [2, -1], - [1, -0.5], - [2, 0.5], - [1, 2], - [-0.5, 1.5], - [-1, 2], - [-2, 1], - [-1.5, 0], - [-2, -1], - [-1, -2], - ]; - - private rock3 = [ - [0, -1], - [1, -2], - [2, -1], - [1.5, 0], - [2, 1], - [1, 2], - [-1, 2], - [-2, 1], - [-2, -1], - [-1, -2], - ]; - - private rocks = [this.rock1, this.rock2, this.rock3]; - - constructor( - x: number, - y: number, - v: Vector, - size: RockSize, - speed: number = 1 - ) { - super(x, y); - - const velocity = speed * OBJECT_SCALE; - - this.velocity.x = v.x * velocity; - this.velocity.y = v.y * velocity; - - const type = random(0, 2); - const def = this.rocks[type]; - - this.points = def.map((p) => { - return { - x: p[0] * size, - y: p[1] * size, - }; - }); - - this.size = size; - this.rotate(random(1, 90)); - this.rot = random(0.01, 1) % 2 === 0 ? 1 : -1; - this.timeToRot = random(1, 5); - } - - update(dt: number) { - this.rotTimer += 1; - this.move(dt); - - if (this.rotTimer === this.timeToRot) { - this.rotate(this.rot); - this.rotTimer = 0; - } - } - - render(screen: Screen) { - this.draw(screen); - } - - get direction() { - const radians = Math.atan2(this.velocity.y, this.velocity.x); - let degrees = radians * (180 / Math.PI); - degrees = degrees > 0.0 ? degrees : 360 + degrees; - return Math.floor(degrees); - } - - split(): Rock[] { - let sound; - - switch (this.size) { - case RockSize.Large: - sound = largeExplosion; - break; - - case RockSize.Medium: - sound = mediumExplosion; - break; - - case RockSize.Small: - sound = smallExplosion; - break; - } - - const rate = randomFloat(0.7, 1); - // sound.rate(rate); - sound.play(); - - if (this.size > RockSize.Small) { - let angle1 = random(this.direction, this.direction + 80); - let angle2 = random(this.direction - 80, this.direction); - - if (angle1 < 0) { - angle1 += 360; - } - - if (angle1 > 360) { - angle1 -= 360; - } - - if (angle2 < 0) { - angle2 += 360; - } - - if (angle2 > 360) { - angle2 -= 360; - } - - const size = - this.size === RockSize.Large ? RockSize.Medium : RockSize.Small; - const v1 = Vector.fromAngle(angle1); - const v2 = Vector.fromAngle(angle2); - const speed1 = - size === RockSize.Medium ? random(150, 250) : random(250, 350); - const speed2 = - size === RockSize.Medium ? random(150, 250) : random(250, 350); - const rock1 = new Rock(this.origin.x, this.origin.y, v1, size, speed1); - const rock2 = new Rock(this.origin.x, this.origin.y, v2, size, speed2); - - return [rock1, rock2]; - } - - return []; - } - - get score(): number { - if (this.size === RockSize.Large) { - return 20; - } - - if (this.size === RockSize.Medium) { - return 50; - } - - return 100; - } -} - -export function createRocks(level: number): Rock[] { - const rocks = []; - const count = Math.min(level + 20, 30); - const speed = 150; - const offset = 20; - - for (let i = 0; i < count; i++) { - const zone = random(1, 4); - const v = Vector.fromAngle(random(1, 360)); - let x: number; - let y: number; - - switch (zone) { - case 1: - x = random(offset, WIDTH - offset); - y = random(offset, offset * 2); - break; - case 2: - x = random(WIDTH - offset * 2, WIDTH - offset); - y = random(HEIGHT - offset, HEIGHT - offset); - break; - case 3: - x = random(offset, WIDTH - offset); - y = random(HEIGHT - offset, HEIGHT - offset); - break; - default: - x = random(offset, offset * 2); - y = random(HEIGHT - offset, HEIGHT - offset); - break; - } - - const rock = new Rock(x, y, v, RockSize.Large, speed); - rocks.push(rock); - } - - return rocks; -} diff --git a/client/game/scoreMarker.ts b/client/game/scoreMarker.ts deleted file mode 100644 index 5ca73cd..0000000 --- a/client/game/scoreMarker.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Screen } from './screen'; -import { white } from './draw'; -import { Object2D } from './object2d'; - -export class ScoreMarker extends Object2D { - - life: number = 1; // in seconds - - constructor(obj: Object2D, private text: string) { - super(obj.origin.x, obj.origin.y); - this.velocity = obj.velocity; - } - - render(screen: Screen) { - screen.draw.text(this.text, this.origin.x, this.origin.y, this.life * 50, white(this.life)); - } - - update(dt: number) { - this.move(dt); - - this.life -= dt; - - if (this.life <= 0) { - this.destroy(); - } - } - - destroy() { - this.life = 0; - this.trigger('expired'); - } -} \ No newline at end of file diff --git a/client/game/screen.ts b/client/game/screen.ts deleted file mode 100644 index 86af105..0000000 --- a/client/game/screen.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { Rect } from "../comets"; -import { HEIGHT, OBJECT_SCALE, SHIP_RECT, WIDTH } from "./constants"; -import { Draw } from "./draw"; -import { random } from "./util"; - -export class Screen implements Rect { - canvas: HTMLCanvasElement; - ctx: CanvasRenderingContext2D; - x: number = 0; - y: number = 0; - width: number; - height: number; - draw: Draw; - width2: number; - height2: number; - - private _fontXL: number; - private _fontL: number; - private _fontM: number; - private _fontS: number; - private _objectScale: number; - private _shipRect: Rect; - private _pointSize: number; - - constructor() { - this.canvas = document.getElementById("canvas") as HTMLCanvasElement; - this.ctx = this.canvas.getContext("2d"); - this.draw = new Draw(this.ctx, this); - this.init(); - - window.addEventListener("resize", () => { - console.log("resizing"); - this.init(); - }); - } - - init() { - this.canvas.width = WIDTH; - this.canvas.height = HEIGHT; - this.width = this.canvas.width; - this.height = this.canvas.height; - this.width2 = this.width / 2; - this.height2 = this.height / 2; - - this._fontXL = 48; - this._fontL = 24; - this._fontM = 18; - this._fontS = 10; - this._objectScale = OBJECT_SCALE; - - this._pointSize = 4 * this._objectScale; - - this._shipRect = SHIP_RECT; - } - - get font() { - let self = this; - return { - get xlarge() { - return self._fontXL; - }, - get large() { - return self._fontL; - }, - get medium() { - return self._fontM; - }, - get small() { - return self._fontS; - }, - }; - } - - get objectScale() { - return this._objectScale; - } - - get pointSize() { - return this._pointSize; - } - - get shipRect() { - return this._shipRect; - } - - preShake() { - this.ctx.save(); - var dx = random(0, 1) * 10; - var dy = random(0, 1) * 10; - this.ctx.translate(dx, dy); - } - - postShake() { - this.ctx.restore(); - } -} diff --git a/client/game/ship.ts b/client/game/ship.ts deleted file mode 100644 index 4b2dc3f..0000000 --- a/client/game/ship.ts +++ /dev/null @@ -1,221 +0,0 @@ -import { Screen } from "./screen"; -import { WIDTH, HEIGHT, OBJECT_SCALE } from "./constants"; -import { VirtualInput } from "../comets"; -import { Object2D } from "./object2d"; -import { Vector } from "./vector"; -import { Bullet } from "./bullet"; -import { fire, thrust } from "./sounds"; -import { random } from "./util"; - -const ACCELERATION: number = 0.1; -const BULLET_SPEED: number = 1000 * OBJECT_SCALE; -const BULLET_TIME: number = 0.1; -const FRICTION: number = 0.005; -const ROTATION: number = 5; -const MAX_ACCELERATION: number = 1100 * OBJECT_SCALE; -const MAX_BULLETS: number = 10; -const VELOCITY = 150 * OBJECT_SCALE; - -class Flame extends Object2D { - constructor(x: number, y: number) { - super(x, y); - - this.points = [ - { x: 5, y: 8 }, - { x: 0, y: 20 }, - { x: -5, y: 8 }, - ]; - } - - update() {} - - render(screen: Screen) { - this.draw(screen, false); - } -} - -export class Ship extends Object2D { - private moving: boolean = false; - private bulletCount: number = 0; - private bulletTimer: number = 0; - private flame: Flame; - public shield: number = 1; - public trails = []; - - constructor(x: number, y: number) { - super(x, y); - this.flame = new Flame(x, y); - this.points = [ - { x: 0, y: -15 }, - { x: 10, y: 10 }, - { x: 5, y: 5 }, - { x: -5, y: 5 }, - { x: -10, y: 10 }, - ]; - - this.angle = 270; - } - - render(screen: Screen) { - this.draw(screen); - - if (this.moving && random(1, 10) % 2 === 0) { - this.flame.draw(screen, false); - } - - if (this.trails.length) { - this.trails.forEach((trail) => { - if (trail.alpha > 0) { - screen.draw.shape( - trail.points, - trail.x, - trail.y, - `rgba(255,0,255,${trail.alpha})`, - true - ); - screen.draw.shape( - trail.points, - trail.x - 1, - trail.y - 1, - `rgba(0,255,255,${trail.alpha})`, - true - ); - trail.alpha -= 0.1; - } - }); - } - } - - update(dt: number, inputs?: VirtualInput) { - this.move(dt); - this.flame.move(dt); - - if (inputs.isThrust) { - this.moving = true; - this.thrust(); - } else { - this.moving = false; - } - - if (inputs.wasRotateLeft) { - this.rotate(-1); - } - - if (inputs.isRotateLeft) { - this.rotate(-ROTATION); - } - - if (inputs.wasRotateRight) { - this.rotate(1); - } - - if (inputs.isRotateRight) { - this.rotate(ROTATION); - } - - if (inputs.isFire) { - this.fire(); - } - - if (inputs.wasHyperspace) { - this.hyperspace(); - } - - if (this.bulletTimer >= 0) { - this.bulletTimer -= dt; - } - - if ( - this.moving && - (Math.abs(this.velocity.x) > 200 || Math.abs(this.velocity.y) > 200) - ) { - this.trails.push({ - points: [...this.points], - x: this.origin.x, - y: this.origin.y, - alpha: 0.5, - }); - } else { - this.trails.length = 0; - } - - // slow down ship over time - if (!this.moving) { - this.velocity.friction(FRICTION); - this.flame.velocity = this.velocity; - } - } - - rotate(n: number) { - super.rotate(n); - this.flame.rotate(n); - } - - private thrust() { - const v = Vector.fromAngle(this.angle, VELOCITY * ACCELERATION); - - if (this.velocity.magnitude < MAX_ACCELERATION) { - this.velocity.add(v); - this.flame.velocity = this.velocity; - } - - thrust.play(); - } - - private fire() { - if (this.bulletTimer <= 0 && this.bulletCount < MAX_BULLETS) { - fire.play(); - - this.bulletTimer = BULLET_TIME; - this.bulletCount++; - - const velocity = Vector.fromAngle(this.angle); - const bullet = new Bullet(this.origin, velocity, 1); - - bullet.on("expired", () => { - this.bulletCount--; - }); - - // move bullet to nose of ship - const bv = bullet.velocity.copy(); - bv.scale(20, 20); - bullet.origin.add(bv); - - // adjust for speed of ship if bullets and ship are moving in same general direction - let speed = 0; - const dot = this.velocity.dot(bullet.velocity); - - if (dot > 0) { - speed = this.velocity.magnitude; - } - - speed = Math.max(BULLET_SPEED, speed + BULLET_SPEED); - - bullet.velocity.scale(speed, speed); - - // kick back - let kba = (this.angle + 180) % 360; - let kbv = Vector.fromAngle(kba, 5); - - this.origin.add(kbv); - this.flame.origin.add(kbv); - - this.trigger("fire", bullet); - } - } - - hyperspace() { - let x = random(40, WIDTH - 40); - let y = random(40, HEIGHT - 40); - - this.velocity = new Vector(0, 0); - this.flame.velocity = this.velocity; - - this.x = this.flame.x = x; - this.y = this.flame.y = y; - } - - destroy() { - this.trigger("expired"); - } -} diff --git a/client/game/shockwave.ts b/client/game/shockwave.ts deleted file mode 100644 index 4cd6193..0000000 --- a/client/game/shockwave.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { EventSource } from './events'; -import { Key } from './keys'; -import { Screen } from './screen'; -import { Object2D } from './object2d'; -import { Rock } from './rocks'; -import { Vector } from './vector'; -import { random } from './util'; - -export class Shockwave extends Object2D { - - life: number = 1; - frame: number = 0; - radius: number = 1; - rocks: Rock[] = []; - - constructor(x: number, y: number, public velocity: Vector, public size: number, public multiplier: number = 1) { - super(x, y); - - } - - update(dt: number) { - this.frame++; - this.radius = this.size * (this.frame / 10); - this.life -= dt; - - this.origin.x += this.velocity.x * dt; - this.origin.y += this.velocity.y * dt; - - if (this.life <= .1) { - this.rocks.length = 0; - this.trigger('expired'); - } - } - - render(screen: Screen, dt?: number) { - if (this.frame === 1) { - const radius = (this.size * (random(25,55))) / 10; - const { ctx } = screen; - ctx.beginPath(); - ctx.arc(this.origin.x, this.origin.y, radius, 0, 2 * Math.PI, false); - ctx.fillStyle = `rgba(255, 255, 255, ${random(.2, .5)})`; - ctx.fill(); - ctx.stroke(); - ctx.closePath(); - screen.draw.scanlines(); - } - - screen.draw.circle(this.origin.x, this.origin.y, this.radius, `rgba(128,128,128,${.3 - (this.frame / 100)})`); - } - - get x(): number { - return this.origin.x - this.radius; - } - - get y(): number { - return this.origin.y - this.radius; - } - - get width(): number { - return this.radius * 2; - } - - get height(): number { - return this.radius * 2; - } - - -} \ No newline at end of file diff --git a/client/game/slowMoTimer.ts b/client/game/slowMoTimer.ts deleted file mode 100644 index 2121de8..0000000 --- a/client/game/slowMoTimer.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { EventSource } from "./events"; - -export class SlowMoTimer extends EventSource { - constructor(private time: number, private factor: number) { - super(); - } - - public adjust(dt: number): number { - const result = dt / this.factor; - this.time -= result; - - if (this.time <= 0) { - this.trigger("expired"); - } - - return result; - } -} diff --git a/client/game/sounds.ts b/client/game/sounds.ts deleted file mode 100644 index 23ba757..0000000 --- a/client/game/sounds.ts +++ /dev/null @@ -1,139 +0,0 @@ -declare var require; - -const VOLUME = 0.5; - -let soundOn: boolean = true; - -export const all = []; - -function createSound(options) { - let count = 0; - - let sound = { - play: () => {}, - stop: () => {}, - volume: () => {}, - on: (s, f) => {}, - off: () => {}, - _origVolume: 0, - }; - - try { - if (window) { - const { Howl } = require("howler"); - sound = new Howl(options); - } - } catch (e) {} - - sound.on("end", () => { - if (options.max) { - count--; - } - }); - - const play = sound.play.bind(sound); - const canPlay = options.max ? count < options.max && soundOn : soundOn; - - sound.play = () => { - if (soundOn) { - if (options.max) { - if (count < options.max) { - play(); - count++; - } - } else { - play(); - } - } - }; - - sound._origVolume = options.volume; - - all.push(sound); - return sound; -} - -export const fire = createSound({ - src: ['./assets/fire.wav'], - volume: .2 -}); - -export const thrust = createSound({ - src: ['./assets/thrust.wav'], - volume: 0.3 -}); - -export const alienFire = createSound({ - src: ['./assets/sfire.wav'], - volume: VOLUME -}); - -export const largeExplosion = createSound({ - src: ['./assets/explode1.wav'], - volume: VOLUME, - max: 2 -}); - -export const mediumExplosion = createSound({ - src: ['./assets/explode2.wav'], - volume: VOLUME, - max: 2 -}); - -export const smallExplosion = createSound({ - src: ['./assets/explode3.wav'], - volume: VOLUME, - max: 2 -}); - -export const largeAlien = createSound({ - src: ['./assets/lsaucer.wav'], - volume: VOLUME, - loop: true -}); - -export const smallAlien = createSound({ - src: ['./assets/ssaucer.wav'], - volume: VOLUME, - loop: true -}); - -export const thumpLo = createSound({ - src: ['./assets/thumplo.wav'], - volume: .3 -}); - -export const thumpHi = createSound({ - src: ['./assets/thumphi.wav'], - volume: .3 -}); - -export const extraLife = createSound({ - src: ['./assets/life.wav'], - volume: .5 -}); - -export const powerup = createSound({ - src: ['./assets/powerup.wav'], - volume: .5 -}); - -export const getPowerup = createSound({ - src: ['./assets/getpowerup.wav'], - volume: .5 -}); - -export const Sound = { - on: () => { - soundOn = true; - all.forEach(sound => sound.volume(sound._origVolume)); - }, - off: () => { - soundOn = false; - // do not "stop" sound, just set volume to 0. - all.forEach(sound => sound.volume(0)); - }, - stop: () => { - all.forEach(sound => sound.stop()); - } -} \ No newline at end of file diff --git a/client/game/thump.ts b/client/game/thump.ts deleted file mode 100644 index 5e9f0c2..0000000 --- a/client/game/thump.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { thumpLo, thumpHi } from './sounds'; - -const MIN = .15; -const MAX_VOL = 1; - -export class Thumper { - thumpBeatTimer: number; - thumpBeat: number; - thumpTimer: number; - thumpTime: number; - lo: boolean = true; - max: boolean; - - constructor() { - this.reset(); - } - - reset() { - this.thumpBeatTimer = 0; - this.thumpBeat = 1; - this.thumpTimer = 0; - this.thumpTime = 10; - this.max = false; - } - - update(dt: number) { - this.thumpTimer += dt; - this.thumpBeatTimer += dt; - this.thumpBeat -= .0002; - - if (this.thumpBeat <= MIN) { - this.thumpBeat = MIN; - } - - if (this.thumpBeatTimer >= this.thumpBeat) { - if (this.lo) { - thumpLo.play(); - } else { - thumpHi.play(); - } - - this.lo = !this.lo; - this.thumpBeatTimer = 0; - } - - } -} diff --git a/client/game/tickRecorder.ts b/client/game/tickRecorder.ts deleted file mode 100644 index f8f4554..0000000 --- a/client/game/tickRecorder.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { endGame } from "../rpc/api"; -import { VirtualInput } from "../comets"; -import { Key } from "./keys"; -import { getFromStore, StorageKey } from "../rpc/storage"; -import { ACTIONS } from "./gameMode"; - -export class TickRecorder { - public ticks: VirtualInput[] = []; - - serializedTicks(): string { - return this.ticks - .map((input) => { - return ACTIONS.map((action) => (input[action] ? "1" : "0")); - }) - .map((tick) => parseInt(tick.join(""), 2)) - .join(","); - } - - public collectInputs(): VirtualInput { - const inputMap: VirtualInput = {}; - if (Key.isThrust()) { - inputMap["isThrust"] = true; - } - - if (Key.wasRotateLeft()) { - inputMap["wasRotateLeft"] = true; - } - - if (Key.isRotateLeft()) { - inputMap["isRotateLeft"] = true; - } - - if (Key.wasRotateRight()) { - inputMap["wasRotateRight"] = true; - } - - if (Key.isRotateRight()) { - inputMap["isRotateRight"] = true; - } - - if (Key.isFire()) { - inputMap["isFire"] = true; - } - - if (Key.wasHyperspace()) { - inputMap["wasHyperspace"] = true; - } - - return inputMap; - } - - public recordInputs(inputs: VirtualInput) { - this.ticks.push(inputs); - } - - public reset() { - this.ticks = []; - } - - async sendTicks(score: number) { - console.log( - `Sending ${this.ticks.length} ticks and score ${score} to MRU...` - ); - const payload = { - gameId: getFromStore(StorageKey.GAME_ID), - timestamp: Date.now(), - score, - gameInputs: this.serializedTicks(), - }; - - await endGame(payload); - } -} diff --git a/client/game/util.ts b/client/game/util.ts deleted file mode 100644 index 1da1bb1..0000000 --- a/client/game/util.ts +++ /dev/null @@ -1,15 +0,0 @@ -// default seed -let SEED = 0.8; - -export function updateSeed(gameId: string) { - const num = parseInt(gameId.slice(0, 8), 16); - SEED = num / Math.pow(10, String(num).length); -} - -export function random(start: number, end: number): number { - return Math.floor(SEED * (end - start + 1)) + start; -} - -export function randomFloat(start: number, end: number): number { - return SEED * (end - start) + start; -} diff --git a/client/game/utils/timers.ts b/client/game/utils/timers.ts deleted file mode 100644 index 4a5bcc3..0000000 --- a/client/game/utils/timers.ts +++ /dev/null @@ -1,66 +0,0 @@ -interface TimerOptions { - seconds: number; - delay?: number; - repeat?: boolean; -} - -export class Timer { - - private repeat: boolean; - private time: number = 0; - private delay: number; - private delayTime: number = 0; - private seconds: number; - private triggered: boolean; - private cb: () => void; - - constructor(options: TimerOptions) { - this.seconds = options.seconds; - this.repeat = options.repeat !== undefined ? options.repeat : true; - this.delay = options.delay !== undefined ? options.delay : 0; - } - - update(dt: number) { - if (this.triggered) { - return; - } - - if (this.delay && this.delayTime < this.delay) { - this.delayTime += dt; - if (this.delayTime > this.delay) { - this.cb(); - } - return; - } - - this.time += dt; - - if (this.time >= this.seconds) { - this.time = 0; - this.cb(); - - if (!this.repeat) { - this.triggered = true; - } - } - } - - on(cb: () => void) { - this.cb = cb; - } -} - -export class Timers { - private timers: Timer[] = []; - - add(options: TimerOptions, cb: () => void) { - const timer = new Timer(options); - timer.on(cb); - this.timers.push(timer); - } - - update(dt: number) { - this.timers.forEach(timer => timer.update(dt)); - } -} - diff --git a/client/game/vector.ts b/client/game/vector.ts deleted file mode 100644 index 6bbc635..0000000 --- a/client/game/vector.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { Point } from '../comets'; - -const VECTOR = {}; -const PI2 = 2 * Math.PI; - -for(let i = 0; i <= 360; i++) { - const t = PI2 * (i / 360); - - VECTOR[i] = { - x: Math.cos(t), - y: Math.sin(t) - } -} - -export class Vector { - - x: number; - y: number; - - constructor(x: number, y: number) { - this.x = x; - this.y = y; - } - - static fromAngle(angleInDegrees: number, velocity: number = 1): Vector { - const x = VECTOR[angleInDegrees].x * velocity; - const y = VECTOR[angleInDegrees].y * velocity; - return new Vector(x, y); - } - - static fromXY(p1: Point, p2: Point, velocity: number = 1): Vector { - let x = p1.x - p2.x; - let y = p1.y - p2.y; - const hyp = Math.sqrt(x * x + y * y); - x /= hyp; - y /= hyp; - return new Vector(x * velocity, y * velocity); - } - - add(v: Vector) { - this.x += v.x; - this.y += v.y; - } - - copy() { - return new Vector(this.x, this.y); - } - - dot(v: Vector) { - return (this.x * v.x) + (this.y * v.y); - } - - friction(amount: number) { - this.x -= this.x * amount; - this.y -= this.y * amount; - } - - scale(xscale: number, yscale: number) { - this.x *= xscale; - this.y *= yscale; - } - - get magnitude() { - return Math.sqrt((this.x * this.x) + (this.y * this.y)); - } - -} \ No newline at end of file diff --git a/client/game/world.ts b/client/game/world.ts deleted file mode 100644 index fca1d62..0000000 --- a/client/game/world.ts +++ /dev/null @@ -1,401 +0,0 @@ -import { IGameState, Rect, VirtualInput } from "../comets"; -import { Alien, BigAlien, SmallAlien } from "./alien"; -import { Bullet } from "./bullet"; -import { HEIGHT, SHIP_RECT, WIDTH } from "./constants"; -import { Explosion } from "./explosion"; -import { Flash } from "./flash"; -import { Object2D } from "./object2d"; -import { Rock, createRocks } from "./rocks"; -import { ScoreMarker } from "./scoreMarker"; -import { Screen } from "./screen"; -import { Ship } from "./ship"; -import { Shockwave } from "./shockwave"; -import { SlowMoTimer } from "./slowMoTimer"; -import { - alienFire, - extraLife, - getPowerup, - largeAlien, - largeExplosion, - smallAlien, -} from "./sounds"; -import { random } from "./util"; - -const EXTRA_LIFE = 100_000; -const SHAKE_TIME = 0.5; - -let explosionCount = 0; -let maxExplosionCount = 0; -let maxExplosionThreshold = 10; -let explosionScores: number[] = []; - -const NUM_OF_LIVES = 1; -export class World { - level = 1; - extraLifeScore = 0; - score = 0; - lives = NUM_OF_LIVES; - - ship: Ship; - shipBullets: Bullet[] = []; - alien: Alien; - alienBullets: Bullet[] = []; - shockwaves: Shockwave[] = []; - rocks: Rock[] = []; - - // things with no collision detection - markers, explosions, flash, etc. - scenery: IGameState[] = []; - - shipTimer: number = 0; - alienTimer: number = 0; - levelTimer: number = 0; - gameOverTimer: number = 0; - shakeTimer: number = 0; - powerupTimer: number = 0; - dramaticPauseTimer: number = 0; - slowMoTimer: SlowMoTimer = null; - - gameOver: boolean = false; - started: boolean = false; - - constructor() {} - - get objects(): any { - return [ - this.ship, - this.alien, - ...this.shipBullets, - ...this.alienBullets, - ...this.rocks, - ...this.shockwaves, - ...this.scenery, - ]; - } - - update(dt: number, inputs: VirtualInput) { - if (this.slowMoTimer) { - dt = this.slowMoTimer.adjust(dt); - } - - if (this.dramaticPauseTimer > 0) { - this.dramaticPauseTimer--; - return; - } - - // shaky cam - if (this.shakeTimer > 0) { - this.shakeTimer -= dt; - } - - this.objects.forEach((obj) => { - if (obj) { - obj.update(dt, inputs); - } - }); - } - - render(screen: Screen, dt?: number) { - if (this.slowMoTimer) { - dt = this.slowMoTimer.adjust(dt); - } - - if (this.shakeTimer > 0) { - screen.preShake(); - } - - this.objects.forEach((obj) => { - if (obj) { - obj.render(screen, dt); - } - }); - - if (this.shakeTimer > 0) { - screen.postShake(); - } - } - - startLevel() { - this.level++; - this.levelTimer = 0; - this.powerupTimer = 0; - - if (!this.alienTimer) { - this.alienTimer = random(10, 15); - } - - this.scenery.length = 0; - this.shipBullets.forEach((bullet) => bullet.destroy()); - - this.addRocks(); - } - - private addRocks() { - this.rocks = createRocks(this.level); - } - - addShip(x: number, y: number) { - this.ship = new Ship(x, y); - - this.ship.on("fire", (ship, bullet) => { - bullet.on("expired", () => { - this.shipBullets = this.shipBullets.filter((x) => x !== bullet); - }); - - this.shipBullets.push(bullet); - }); - - this.ship.on("expired", () => { - this.lives--; - this.ship = null; - this.shipBullets.length = 0; - }); - } - - createExplosion( - obj: Object2D, - size: number = 100, - multiplier: number = 1 - ): { explosion: Explosion; shockwave: Shockwave } { - if (!obj) { - return; - } - - const explosion = new Explosion(obj.origin.x, obj.origin.y, size); - explosionCount++; - - explosionScores.push(obj.score); - - if (explosionScores.length > maxExplosionThreshold) { - explosionScores.pop(); - } - - if (explosionCount > maxExplosionCount) { - maxExplosionCount = explosionCount; - - // TODO: this was exploding the game - // if (maxExplosionCount > maxExplosionThreshold) { - // explosionCount = 0; - // console.log("MAX DAMAGE ACHEIVEMENT"); - - // this.setSlowMo(0.25, 4); - - // let bonus = 0; - // explosionScores.forEach((v) => (bonus += v)); - // bonus *= 5; - - // const achievement = new Achievement(`MASSIVE DAMAGE`, bonus); - // this.addScenery(achievement); - // this.addScore(achievement, "achievement"); - - // //const marker = new ScoreMarker(obj, `+${bonus}`); - // //this.addScenery(marker); - - // // Track score of each explosion and display total points with achievement - - // maxExplosionThreshold += 10; - // } - } - - explosion.on("expired", () => { - explosionCount--; - }); - - this.addScenery(explosion); - - const shockwave = new Shockwave( - obj.origin.x, - obj.origin.y, - obj.velocity, - size, - multiplier - ); - - shockwave.on("expired", () => { - this.shockwaves = this.shockwaves.filter((x) => x !== shockwave); - }); - - this.shockwaves.push(shockwave); - - return { - explosion, - shockwave, - }; - } - - setSlowMo(time: number, factor: number) { - if (!this.slowMoTimer) { - this.slowMoTimer = new SlowMoTimer(time, factor); - this.slowMoTimer.on("expired", () => (this.slowMoTimer = null)); - } - } - - shipDestroyed() { - if (this.ship) { - largeExplosion.play(); - this.createExplosion(this.ship); - this.addFlash(5); - this.ship.destroy(); - this.setSlowMo(0.25, 8); - } - } - - alienDestroyed() { - if (this.alien) { - this.addFlash(5); - this.createExplosion(this.alien); - this.alien.destroy(); - } - } - - addFlash(frames: number) { - const flash = new Flash(frames); - this.addScenery(flash); - } - - addScenery(obj: any) { - obj.on("expired", () => { - this.scenery = this.scenery.filter((x) => x !== obj); - }); - - this.scenery.push(obj); - } - - rockDestroyed(rock: Rock, multiplier: number = 1) { - let boom = this.createExplosion(rock, rock.size * 5, multiplier); - let debris = rock.split(); - - this.rocks = this.rocks.filter((x) => x !== rock); - this.rocks.push(...debris); - - this.shockwaves.forEach((shockwave) => { - shockwave.rocks = shockwave.rocks.filter((x) => x !== rock); - }); - - boom.shockwave.rocks = debris; - - rock = null; - } - - addAlien() { - const lvl = Math.min(this.level, 14); - let little = false; - let alienSound = largeAlien; - - if (this.score >= 40000) { - little = true; - } else { - switch (lvl) { - case 7: - little = this.levelTimer > 60 && random(1, 3) === 2; - break; - case 8: - little = this.levelTimer > 30 && random(1, 10) % 2 === 0; - break; - default: - little = random(1, 10) <= lvl + 2; - break; - } - } - - if (little) { - alienSound = smallAlien; - this.alien = new SmallAlien(this.ship); - } else { - this.alien = new BigAlien(); - } - - alienSound.play(); - - this.alien.on("expired", () => { - alienFire.stop(); - alienSound.stop(); - largeExplosion.play(); - this.alien = null; - this.alienBullets.forEach((b) => b.destroy()); - this.alienBullets.length = 0; - }); - - this.alien.on("fire", (alien, bullet: Bullet) => { - alienFire.play(); - - bullet.on("expired", () => { - this.alienBullets = this.alienBullets.filter((x) => x !== bullet); - }); - - this.alienBullets.push(bullet); - }); - } - - // TODO: remove second argument - addScore(obj: Object2D, name: string) { - // console.log(obj.score, name); - this.score += obj.score; - this.extraLifeScore += obj.score; - - if (this.extraLifeScore >= EXTRA_LIFE) { - this.lives++; - this.extraLifeScore -= EXTRA_LIFE; - extraLife.play(); - } - - this.addScenery(new ScoreMarker(obj, `${obj.score}`)); - } - - addPowerup() { - getPowerup.play(); - } - - shake() { - if (this.shakeTimer <= 0.0) { - this.shakeTimer = SHAKE_TIME; - } - } - - tryPlaceShip(dt) { - this.shipTimer += dt; - - if (this.shipTimer <= 2) { - return; - } - - let rect: Rect = SHIP_RECT; - - let collided = false; - - this.rocks.forEach((rock) => { - collided = collided || rock.collided(rect); - }); - - if (this.alien) { - collided = collided || this.alien.collided(rect); - } - - if (!collided) { - this.shipTimer = 0; - this.addShip(WIDTH / 2, HEIGHT / 2); - } - } - - updateAlienTimer(dt: number) { - if (!this.alien) { - this.alienTimer -= dt; - - if (this.alienTimer <= 0) { - this.addAlien(); - this.alienTimer = random(10, 15); - } - } - } - - shouldTryToPlaceShip(): boolean { - return !!this.shipTimer || (!this.ship && !!this.lives); - } - - shouldCheckForNextLevel(): boolean { - return !this.rocks.length && !!this.lives; - } - - shouldCheckCollisions(): boolean { - return !!this.ship || !!this.shipBullets.length; - } -} diff --git a/client/index.html b/client/index.html deleted file mode 100644 index b1d7c87..0000000 --- a/client/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - Comets - - - - - - -
- -
- - - diff --git a/client/package-lock.json b/client/package-lock.json deleted file mode 100644 index ca7fcb8..0000000 --- a/client/package-lock.json +++ /dev/null @@ -1,1790 +0,0 @@ -{ - "name": "comets", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "comets", - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "hammerjs": "^2.0.8", - "howler": "^2.2.4", - "viem": "^2.18.6" - }, - "devDependencies": { - "@types/hammerjs": "^2.0.41", - "file-loader": "^6.2.0", - "ts-loader": "9.4.2", - "typescript": "^5.0.0", - "webpack": "^5.76.0", - "webpack-cli": "^5.0.1" - } - }, - "node_modules/@adraffy/ens-normalize": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz", - "integrity": "sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==" - }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", - "dev": true, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", - "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@noble/curves": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.0.tgz", - "integrity": "sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg==", - "dependencies": { - "@noble/hashes": "1.4.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/base": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.7.tgz", - "integrity": "sha512-PPNYBslrLNNUQ/Yad37MHYsNQtK67EhWb6WtSvNLLPo7SdVZgkUjD6Dg+5On7zNwmskf8OX7I7Nx5oN+MIWE0g==", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip32": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", - "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", - "dependencies": { - "@noble/curves": "~1.4.0", - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip39": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", - "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", - "dependencies": { - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@types/eslint": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.0.tgz", - "integrity": "sha512-gi6WQJ7cHRgZxtkQEoyHMppPjq9Kxo5Tjn2prSKDSmZrCz8TZ3jSRCeTJm+WoM+oB0WG37bRqLzaaU3q7JypGg==", - "dev": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dev": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true - }, - "node_modules/@types/hammerjs": { - "version": "2.0.45", - "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.45.tgz", - "integrity": "sha512-qkcUlZmX6c4J8q45taBKTL3p+LbITgyx7qhlPYOdOHZB7B31K0mXbP5YA7i7SgDeEGuI9MnumiKPEMrxg8j3KQ==", - "dev": true - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, - "node_modules/@types/node": { - "version": "22.0.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.0.0.tgz", - "integrity": "sha512-VT7KSYudcPOzP5Q0wfbowyNLaVR8QWUdw+088uFWwfvpY6uCWaXpqV6ieLAu9WBcnTa7H4Z5RLK8I5t2FuOcqw==", - "dev": true, - "dependencies": { - "undici-types": "~6.11.1" - } - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", - "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", - "dev": true, - "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", - "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", - "dev": true, - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", - "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.12.1" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", - "dev": true, - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", - "dev": true, - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", - "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-opt": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1", - "@webassemblyjs/wast-printer": "1.12.1" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", - "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", - "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", - "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", - "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webpack-cli/configtest": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", - "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", - "dev": true, - "engines": { - "node": ">=14.15.0" - }, - "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" - } - }, - "node_modules/@webpack-cli/info": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", - "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", - "dev": true, - "engines": { - "node": ">=14.15.0" - }, - "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" - } - }, - "node_modules/@webpack-cli/serve": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", - "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", - "dev": true, - "engines": { - "node": ">=14.15.0" - }, - "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" - }, - "peerDependenciesMeta": { - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "node_modules/abitype": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.0.5.tgz", - "integrity": "sha512-YzDhti7cjlfaBhHutMaboYB21Ha3rXR9QTkNJFzYC4kC8YclaiwPBBBJY8ejFdu2wnJeZCVZSMlQJ7fi8S6hsw==", - "funding": { - "url": "https://github.com/sponsors/wevm" - }, - "peerDependencies": { - "typescript": ">=5.0.4", - "zod": "^3 >=3.22.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - }, - "zod": { - "optional": true - } - } - }, - "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-import-attributes": { - "version": "1.9.5", - "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", - "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", - "dev": true, - "peerDependencies": { - "acorn": "^8" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.23.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", - "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001640", - "electron-to-chromium": "^1.4.820", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.1.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001644", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001644.tgz", - "integrity": "sha512-YGvlOZB4QhZuiis+ETS0VXR+MExbFf4fZYYeMTEE0aTQd/RdIjkTyZjLrbYVKnHzppDvnOhritRVv+i7Go6mHw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chrome-trace-event": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", - "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", - "dev": true, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.3.tgz", - "integrity": "sha512-QNdYSS5i8D9axWp/6XIezRObRHqaav/ur9z1VzCDUCH1XIFOr9WQk5xmgunhsTpjjgDy3oLxO/WMOVZlpUQrlA==", - "dev": true - }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", - "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/envinfo": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", - "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", - "dev": true, - "bin": { - "envinfo": "dist/cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/es-module-lexer": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", - "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", - "dev": true - }, - "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fastest-levenshtein": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "dev": true, - "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/file-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", - "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", - "dev": true, - "dependencies": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/hammerjs": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", - "integrity": "sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/howler": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/howler/-/howler-2.2.4.tgz", - "integrity": "sha512-iARIBPgcQrwtEr+tALF+rapJ8qSc+Set2GJQl7xT1MQzWaVkFebdJhR3alVlSiUf5U7nAANKuj3aWpwerocD5w==" - }, - "node_modules/import-local": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", - "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/interpret": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", - "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", - "dev": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/is-core-module": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", - "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", - "dev": true, - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isows": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.4.tgz", - "integrity": "sha512-hEzjY+x9u9hPmBom9IIAqdJCwNLax+xrPb51vEPpERoFlIxgmZcHzsT5jKG06nvInKOBGvReAVz80Umed5CczQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wagmi-dev" - } - ], - "peerDependencies": { - "ws": "*" - } - }, - "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "dev": true, - "engines": { - "node": ">=6.11.5" - } - }, - "node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", - "dev": true, - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/rechoir": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", - "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", - "dev": true, - "dependencies": { - "resolve": "^1.20.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/terser": { - "version": "5.31.3", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.3.tgz", - "integrity": "sha512-pAfYn3NIZLyZpa83ZKigvj6Rn9c/vd5KfYGX7cN1mnzqgDcxWvrU5ZtAfIKhEXz9nRecw4z3LXkjaq96/qZqAA==", - "dev": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.10", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", - "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.20", - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.26.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-loader": { - "version": "9.4.2", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.2.tgz", - "integrity": "sha512-OmlC4WVmFv5I0PpaxYb+qGeGOdm5giHU7HwDDUjw59emP2UYMHy9fFSDcYgSNoH8sXcj4hGCSEhlDZ9ULeDraA==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "enhanced-resolve": "^5.0.0", - "micromatch": "^4.0.0", - "semver": "^7.3.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "typescript": "*", - "webpack": "^5.0.0" - } - }, - "node_modules/typescript": { - "version": "5.5.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", - "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", - "devOptional": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "6.11.1", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.11.1.tgz", - "integrity": "sha512-mIDEX2ek50x0OlRgxryxsenE5XaQD4on5U2inY7RApK3SOJpofyw7uW2AyfMKkhAxXIceo2DeWGVGwyvng1GNQ==", - "dev": true - }, - "node_modules/update-browserslist-db": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/viem": { - "version": "2.18.6", - "resolved": "https://registry.npmjs.org/viem/-/viem-2.18.6.tgz", - "integrity": "sha512-KughUodIEjzkC+KfQ4+259yRXYfo0VLkZQ7NVC3RGfCMMOiVWaOxHjmcaY0FnZzKX3pwrlMyTAZbwH9tVAN/Yw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "dependencies": { - "@adraffy/ens-normalize": "1.10.0", - "@noble/curves": "1.4.0", - "@noble/hashes": "1.4.0", - "@scure/bip32": "1.4.0", - "@scure/bip39": "1.3.0", - "abitype": "1.0.5", - "isows": "1.0.4", - "webauthn-p256": "0.0.5", - "ws": "8.17.1" - }, - "peerDependencies": { - "typescript": ">=5.0.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/watchpack": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", - "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", - "dev": true, - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webauthn-p256": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/webauthn-p256/-/webauthn-p256-0.0.5.tgz", - "integrity": "sha512-drMGNWKdaixZNobeORVIqq7k5DsRC9FnG201K2QjeOoQLmtSDaSsVZdkg6n5jUALJKcAG++zBPJXmv6hy0nWFg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "dependencies": { - "@noble/curves": "^1.4.0", - "@noble/hashes": "^1.4.0" - } - }, - "node_modules/webpack": { - "version": "5.93.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.93.0.tgz", - "integrity": "sha512-Y0m5oEY1LRuwly578VqluorkXbvXKh7U3rLoQCEO04M97ScRr44afGVkI0FQFsXzysk5OgFAxjZAb9rsGQVihA==", - "dev": true, - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.5", - "@webassemblyjs/ast": "^1.12.1", - "@webassemblyjs/wasm-edit": "^1.12.1", - "@webassemblyjs/wasm-parser": "^1.12.1", - "acorn": "^8.7.1", - "acorn-import-attributes": "^1.9.5", - "browserslist": "^4.21.10", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.0", - "es-module-lexer": "^1.2.1", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.10", - "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-cli": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", - "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", - "dev": true, - "dependencies": { - "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^2.1.1", - "@webpack-cli/info": "^2.0.2", - "@webpack-cli/serve": "^2.0.5", - "colorette": "^2.0.14", - "commander": "^10.0.1", - "cross-spawn": "^7.0.3", - "envinfo": "^7.7.3", - "fastest-levenshtein": "^1.0.12", - "import-local": "^3.0.2", - "interpret": "^3.1.1", - "rechoir": "^0.8.0", - "webpack-merge": "^5.7.3" - }, - "bin": { - "webpack-cli": "bin/cli.js" - }, - "engines": { - "node": ">=14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "5.x.x" - }, - "peerDependenciesMeta": { - "@webpack-cli/generators": { - "optional": true - }, - "webpack-bundle-analyzer": { - "optional": true - }, - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/webpack-cli/node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", - "dev": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/webpack-merge": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", - "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", - "dev": true, - "dependencies": { - "clone-deep": "^4.0.1", - "flat": "^5.0.2", - "wildcard": "^2.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wildcard": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", - "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", - "dev": true - }, - "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - } - } -} diff --git a/client/package.json b/client/package.json deleted file mode 100644 index e623e66..0000000 --- a/client/package.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "comets", - "version": "1.0.0", - "description": "Comets", - "keywords": [ - "Asteroids", - "Game", - "Atari", - "JavaScript", - "TypeScript" - ], - "main": "comets.js", - "scripts": { - "build": "webpack --config webpack.config.js", - "test": "echo \"Error: no test specified\" && exit 1", - "watch": "set NODE_ENV=dev&&webpack --watch" - }, - "author": "J.P. Hamilton", - "license": "MIT", - "devDependencies": { - "@types/hammerjs": "^2.0.41", - "file-loader": "^6.2.0", - "ts-loader": "9.4.2", - "typescript": "^5.0.0", - "webpack": "^5.76.0", - "webpack-cli": "^5.0.1" - }, - "dependencies": { - "hammerjs": "^2.0.8", - "howler": "^2.2.4", - "viem": "^2.18.6" - } -} diff --git a/client/rpc/api.ts b/client/rpc/api.ts deleted file mode 100644 index 2a72cb0..0000000 --- a/client/rpc/api.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { getAddress } from "viem"; -import { addToStore, getFromStore, StorageKey } from "./storage"; -import { getWalletClient } from "./wallet"; - -const API_URL = "https://api.comets.stf.xyz"; - -const fetchMruInfo = async () => { - const response = await fetch(`${API_URL}/info`); - const res = await response.json(); - addToStore(StorageKey.MRU_INFO, res); -}; - -const fetchLeaderboard = async () => { - const response = await fetch(`${API_URL}/leaderboard`); - const res = await response.json(); - addToStore(StorageKey.LEADERBOARD, res); -}; - -const submitAction = async (transition: string, inputs: any) => { - const walletClient = await getWalletClient(); - const mruInfo = getFromStore(StorageKey.MRU_INFO); - const { domain, schemas } = mruInfo; - const msgSender = getAddress(walletClient.account.address); - - let signature; - try { - signature = await walletClient.signTypedData({ - domain, - primaryType: schemas[transition].primaryType, - types: schemas[transition].types, - message: inputs, - account: msgSender, - }); - } catch (e) { - console.error("Error signing message", e); - return; - } - - const response = await fetch(`${API_URL}/${transition}`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - inputs, - signature, - msgSender, - }), - }); - - return response.json(); -}; - -const endGame = async (inputs: any) => { - await submitAction("endGame", inputs); -}; - -const startGame = async () => { - const inputs = { timestamp: Date.now() }; - const res = await submitAction("startGame", inputs); - return res; -}; - -export { endGame, fetchLeaderboard, fetchMruInfo, startGame }; - diff --git a/client/rpc/storage.ts b/client/rpc/storage.ts deleted file mode 100644 index 572dd52..0000000 --- a/client/rpc/storage.ts +++ /dev/null @@ -1,17 +0,0 @@ -export enum StorageKey { - MRU_INFO = "mru_info", - GAME_ID = "game_id", - LEADERBOARD = "leaderboard", -} - -export const addToStore = (key: StorageKey, value: any) => { - localStorage.setItem(key, JSON.stringify(value)); -}; - -export const removeFromStore = (key: StorageKey) => { - localStorage.removeItem(key); -}; - -export const getFromStore = (key: StorageKey) => { - return JSON.parse(localStorage.getItem(key) || "null"); -}; diff --git a/client/rpc/wallet.ts b/client/rpc/wallet.ts deleted file mode 100644 index 3bcdf24..0000000 --- a/client/rpc/wallet.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { createWalletClient, custom, WalletClient } from "viem"; -import { sepolia } from "viem/chains"; -import { getFromStore, StorageKey } from "./storage"; - -let walletClient: any; - -const addChainIfMissing = async (walletClient: WalletClient) => { - const mruInfo = getFromStore(StorageKey.MRU_INFO); - const { domain, rpcUrls } = mruInfo; - - const currentChainId = await walletClient.getChainId(); - const domainChainId = domain.chainId; - const chain = { - ...sepolia, - name: "Stackr Devnet", - rpcUrls: { - default: { - http: rpcUrls, - }, - }, - id: domainChainId, - }; - if (currentChainId !== chain.id) { - try { - await walletClient.switchChain({ id: chain.id }); - } catch (e) { - console.log(e); - await walletClient.addChain({ - chain, - }); - } - } -}; - -export const getWalletClient = async (): Promise => { - const eth = (window as any).ethereum; - if (eth == null) { - console.log("Wallet injector not installed; using read-only defaults"); - } else { - if (walletClient) { - return walletClient; - } - - const [account] = await eth.request({ - method: "eth_requestAccounts", - }); - - walletClient = createWalletClient({ - account, - transport: custom(eth), - }); - - await addChainIfMissing(walletClient); - - console.log(`Connected to wallet ${account}`); - return walletClient; - } -}; diff --git a/client/style.css b/client/style.css deleted file mode 100644 index 6a1023f..0000000 --- a/client/style.css +++ /dev/null @@ -1,19 +0,0 @@ -@font-face { - font-family: "hyperspace"; - src: url("assets/Hyperspace.otf"); -} - -body { - font-family: hyperspace; - width: 100vw; - height: 100vh; - margin: 0; - display: flex; - justify-content: center; - align-items: center; - background-color: #525252; -} - -canvas { - vertical-align: middle; -} diff --git a/client/tsconfig.json b/client/tsconfig.json deleted file mode 100644 index fd1f7ee..0000000 --- a/client/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "compilerOptions": { - "target": "es5", - "module": "commonjs", - "removeComments": true, - "sourceMap": true - }, - "include": [ - "game/*.ts", - "rpc/*.ts" - ] -} \ No newline at end of file diff --git a/client/webpack.config.js b/client/webpack.config.js deleted file mode 100644 index 1a557b2..0000000 --- a/client/webpack.config.js +++ /dev/null @@ -1,45 +0,0 @@ -var path = require("path"); -var webpack = require("webpack"); -var isProd = process.env.NODE_ENV !== "dev"; - -function getPlugins() { - var plugins = [ - new webpack.optimize.ModuleConcatenationPlugin(), - new webpack.DefinePlugin({ - "process.env": { - NODE_ENV: process.env.NODE_ENV, - }, - }), - ]; - - return plugins; -} - -const config = { - mode: process.env.NODE_ENV !== "dev" ? "production" : "development", - entry: "./game/comets.ts", - optimization: { - minimize: false, - }, - output: { - path: path.resolve(__dirname, "build"), - filename: "comets.js", - publicPath: "/build/", - }, - resolve: { - extensions: [".webpack.js", ".web.js", ".ts", ".js"], - }, - plugins: getPlugins(), - module: { - rules: [ - { test: /\.ts$/, loader: "ts-loader" }, - { test: /\.wav/, loader: "file-loader" }, - ], - }, -}; - -if (isProd) { - config.optimization.minimize = true; -} - -module.exports = config; diff --git a/package.json b/package.json index adce466..235da9f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "comets", "scripts": { - "build:client": "cd client && npm run build", + "build:client": "cd game && npm run build", "watch:client": "cd client && npm run watch", "start:server": "cd rollup && bun run index.ts" } diff --git a/rollup/genesis-state.json b/rollup/genesis-state.json index cd0a654..b988164 100644 --- a/rollup/genesis-state.json +++ b/rollup/genesis-state.json @@ -3,78 +3,8 @@ "games": [ { "id": "0x6d220b2af3ddf405e228e83def838dfec21b8e03834723c9687eab26efc5460c", - "score": 12300, - "player": "0xea5eE3665C8E4289842FaC79DFB3FA0d129fc735" - }, - { - "id": "0x76d0dbabfe810803768256d2936d42151d0c2aa8689896348626c25d697fb7db", - "score": 19000, - "player": "0xea5eE3665C8E4289842FaC79DFB3FA0d129fc735" - }, - { - "id": "0x7cc5fa142ca6cc3b5015a7469ac52b9140e57887f60866d39930111756a55e87", - "score": 0, - "player": "0xc607B0B98ceC1FB6e6d3c72039bEbd76924aE4a4" - }, - { - "id": "0x9723281952ec249412c6105cebb2376528a9c06023439ee163fe608ed4acba09", - "score": 12700, - "player": "0xc607B0B98ceC1FB6e6d3c72039bEbd76924aE4a4" - }, - { - "id": "0x5bd5ad703723427cfb29ed588bb70b6bf70f32474c7e833637190a6585baeeb9", - "score": 0, - "player": "0xc607B0B98ceC1FB6e6d3c72039bEbd76924aE4a4" - }, - { - "id": "0xac898b60757cd2f465ff978c2e0fd41e63a5f4fc977eef67f3f65bbb61619b45", - "score": 0, - "player": "0xc607B0B98ceC1FB6e6d3c72039bEbd76924aE4a4" - }, - { - "id": "0x1ff2d75adf4be95c4bd827127c30924d945e8a354209b04de2217a73d15e417d", - "score": 76940, - "player": "0xc607B0B98ceC1FB6e6d3c72039bEbd76924aE4a4" - }, - { - "id": "0xb3e989fef8ee7aaaebf399d788694759366724c40874fa046fbd8f707e82c697", - "score": 41130, - "player": "0xc607B0B98ceC1FB6e6d3c72039bEbd76924aE4a4" - }, - { - "id": "0x357550192b1fbf93b963ff8c6a71cf522d279dd370a4c026e4aaef5dc51b668e", "score": 0, - "player": "0xc607B0B98ceC1FB6e6d3c72039bEbd76924aE4a4" - }, - { - "id": "0xf2564ceb6327915a13709289af8c4d5b5c7104cee2c72494b732068d8839964e", - "score": 41980, - "player": "0x5CDe9727B12E3FD211a9Ec961E2e2f5767CA81B3" - }, - { - "id": "0x05efd499ec1720ed126b09322f575a54fa02535b0de22f7d8719b0a2de781488", - "score": 23800, - "player": "0xC2FdE45f9E0a77005493930f72819Fcf70210464" - }, - { - "id": "0xfb7ed74217e7955100c3154598caf03ce6da7c8441e278027f1679b9d5749bc5", - "score": 19400, - "player": "0x372e2D6f74eFA2C5A4C72DAC4A31da09E8505995" - }, - { - "id": "0x9cb51304cfdac6805aa3740c5bdcf1e5c027d1fce990fb93989305e18cd9817d", - "score": 14400, - "player": "0x372e2D6f74eFA2C5A4C72DAC4A31da09E8505995" - }, - { - "id": "0x72c75565034b1aa146b45f0e2f46e4c53707b94766596ccb5a5aade4315e3a94", - "score": 7240, - "player": "0x372e2D6f74eFA2C5A4C72DAC4A31da09E8505995" - }, - { - "id": "0xd679cbb4f8b671f7ad90f9ee7f936934095e36a33a39719e4bd732196b71bfe1", - "score": 4840, - "player": "0x372e2D6f74eFA2C5A4C72DAC4A31da09E8505995" + "player": "0xea5eE3665C8E4289842FaC79DFB3FA0d129fc735" } ] } diff --git a/rollup/stackr/transitions.ts b/rollup/stackr/transitions.ts index 87be457..47dbd01 100644 --- a/rollup/stackr/transitions.ts +++ b/rollup/stackr/transitions.ts @@ -1,7 +1,7 @@ import { REQUIRE, STF, Transitions } from "@stackr/sdk/machine"; import { hashMessage } from "ethers"; -import { ACTIONS, GameMode } from "../../client/game/gameMode"; -import { World } from "../../client/game/world"; +import { ACTIONS, GameMode } from "../../game/src/core/gameMode"; +import { World } from "../../game/src/core/world"; import { AppState } from "./machine"; export type StartGameInput = { diff --git a/rollup/tsconfig.json b/rollup/tsconfig.json index 72f21c4..7033897 100644 --- a/rollup/tsconfig.json +++ b/rollup/tsconfig.json @@ -26,6 +26,7 @@ "deployment.json", "stackr.config.ts", "genesis-state.json", - "stackr/*.ts" + "stackr/*.ts", + "*.ts" ] }