diff --git a/src/base/Assets.ts b/bsrc/base/Assets.ts similarity index 100% rename from src/base/Assets.ts rename to bsrc/base/Assets.ts diff --git a/src/base/Button.ts b/bsrc/base/Button.ts similarity index 100% rename from src/base/Button.ts rename to bsrc/base/Button.ts diff --git a/src/base/Definitions.ts b/bsrc/base/Definitions.ts similarity index 100% rename from src/base/Definitions.ts rename to bsrc/base/Definitions.ts diff --git a/src/base/Game.ts b/bsrc/base/Game.ts similarity index 100% rename from src/base/Game.ts rename to bsrc/base/Game.ts diff --git a/src/base/GameObject.ts b/bsrc/base/GameObject.ts similarity index 100% rename from src/base/GameObject.ts rename to bsrc/base/GameObject.ts diff --git a/src/base/ScrollingFrame.ts b/bsrc/base/ScrollingFrame.ts similarity index 100% rename from src/base/ScrollingFrame.ts rename to bsrc/base/ScrollingFrame.ts diff --git a/src/components/Creep.ts b/bsrc/components/Creep.ts similarity index 100% rename from src/components/Creep.ts rename to bsrc/components/Creep.ts diff --git a/src/components/Grid.ts b/bsrc/components/Grid.ts similarity index 100% rename from src/components/Grid.ts rename to bsrc/components/Grid.ts diff --git a/src/components/MissionStats.ts b/bsrc/components/MissionStats.ts similarity index 100% rename from src/components/MissionStats.ts rename to bsrc/components/MissionStats.ts diff --git a/src/components/Sidebar.ts b/bsrc/components/Sidebar.ts similarity index 100% rename from src/components/Sidebar.ts rename to bsrc/components/Sidebar.ts diff --git a/src/components/Tower.ts b/bsrc/components/Tower.ts similarity index 100% rename from src/components/Tower.ts rename to bsrc/components/Tower.ts diff --git a/src/components/TowerPicker.ts b/bsrc/components/TowerPicker.ts similarity index 100% rename from src/components/TowerPicker.ts rename to bsrc/components/TowerPicker.ts diff --git a/src/components/WaveManager.ts b/bsrc/components/WaveManager.ts similarity index 100% rename from src/components/WaveManager.ts rename to bsrc/components/WaveManager.ts diff --git a/bsrc/main.ts b/bsrc/main.ts new file mode 100644 index 0000000..5f5c14b --- /dev/null +++ b/bsrc/main.ts @@ -0,0 +1,23 @@ +import * as PIXI from "pixi.js"; +import Game from "./base/Game"; +import Assets from "./base/Assets"; +(async () => { + const app = new PIXI.Application(); + await app.init({ + width: 640, + height: 360, + resizeTo: document.body, + backgroundColor: "white", + sharedTicker: true, + preference: "webgl", + }); + + document.body.appendChild(app.canvas); + await Assets.LoadAssets(); + const game = new Game(app.screen); + app.stage.addChild(game.container); + window.addEventListener("resize", () => { + app.renderer.resize(window.innerWidth, window.innerHeight); + game.setBounds(0, 0, app.screen.width, app.screen.height); + }); +})(); diff --git a/src/scenes/GameScene.ts b/bsrc/scenes/GameScene.ts similarity index 100% rename from src/scenes/GameScene.ts rename to bsrc/scenes/GameScene.ts diff --git a/src/scenes/MainMenu.ts b/bsrc/scenes/MainMenu.ts similarity index 100% rename from src/scenes/MainMenu.ts rename to bsrc/scenes/MainMenu.ts diff --git a/src/scenes/MissionSelectMenu.ts b/bsrc/scenes/MissionSelectMenu.ts similarity index 100% rename from src/scenes/MissionSelectMenu.ts rename to bsrc/scenes/MissionSelectMenu.ts diff --git a/src/scenes/SceneBase.ts b/bsrc/scenes/SceneBase.ts similarity index 100% rename from src/scenes/SceneBase.ts rename to bsrc/scenes/SceneBase.ts diff --git a/src/scenes/SettingsMenu.ts b/bsrc/scenes/SettingsMenu.ts similarity index 100% rename from src/scenes/SettingsMenu.ts rename to bsrc/scenes/SettingsMenu.ts diff --git a/bsrc/typescript.svg b/bsrc/typescript.svg new file mode 100644 index 0000000..d91c910 --- /dev/null +++ b/bsrc/typescript.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/bsrc/vite-env.d.ts b/bsrc/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/bsrc/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/index.html b/index.html index 9add563..9cf28ae 100644 --- a/index.html +++ b/index.html @@ -1,13 +1,13 @@ - - - - - - Bastion App - - - - + + + + + + Bastion App + + + + diff --git a/package-lock.json b/package-lock.json index 44ab693..684dd4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,944 +1,954 @@ { - "name": "bastion", - "version": "0.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "bastion", - "version": "0.0.0", - "dependencies": { - "pixi.js": "^8.4.0" - }, - "devDependencies": { - "typescript": "^5.5.3", - "vite": "^5.4.1" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@pixi/colord": { - "version": "2.9.6", - "resolved": "https://registry.npmjs.org/@pixi/colord/-/colord-2.9.6.tgz", - "integrity": "sha512-nezytU2pw587fQstUu1AsJZDVEynjskwOL+kibwcdxsMBFqPsFFNA7xl0ii/gXuDi6M0xj3mfRJj8pBSc2jCfA==", - "license": "MIT" - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.3.tgz", - "integrity": "sha512-MmKSfaB9GX+zXl6E8z4koOr/xU63AMVleLEa64v7R0QF/ZloMs5vcD1sHgM64GXXS1csaJutG+ddtzcueI/BLg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.3.tgz", - "integrity": "sha512-zrt8ecH07PE3sB4jPOggweBjJMzI1JG5xI2DIsUbkA+7K+Gkjys6eV7i9pOenNSDJH3eOr/jLb/PzqtmdwDq5g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.3.tgz", - "integrity": "sha512-P0UxIOrKNBFTQaXTxOH4RxuEBVCgEA5UTNV6Yz7z9QHnUJ7eLX9reOd/NYMO3+XZO2cco19mXTxDMXxit4R/eQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.3.tgz", - "integrity": "sha512-L1M0vKGO5ASKntqtsFEjTq/fD91vAqnzeaF6sfNAy55aD+Hi2pBI5DKwCO+UNDQHWsDViJLqshxOahXyLSh3EA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.3.tgz", - "integrity": "sha512-btVgIsCjuYFKUjopPoWiDqmoUXQDiW2A4C3Mtmp5vACm7/GnyuprqIDPNczeyR5W8rTXEbkmrJux7cJmD99D2g==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.3.tgz", - "integrity": "sha512-zmjbSphplZlau6ZTkxd3+NMtE4UKVy7U4aVFMmHcgO5CUbw17ZP6QCgyxhzGaU/wFFdTfiojjbLG3/0p9HhAqA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.3.tgz", - "integrity": "sha512-nSZfcZtAnQPRZmUkUQwZq2OjQciR6tEoJaZVFvLHsj0MF6QhNMg0fQ6mUOsiCUpTqxTx0/O6gX0V/nYc7LrgPw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.3.tgz", - "integrity": "sha512-MnvSPGO8KJXIMGlQDYfvYS3IosFN2rKsvxRpPO2l2cum+Z3exiExLwVU+GExL96pn8IP+GdH8Tz70EpBhO0sIQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.3.tgz", - "integrity": "sha512-+W+p/9QNDr2vE2AXU0qIy0qQE75E8RTwTwgqS2G5CRQ11vzq0tbnfBd6brWhS9bCRjAjepJe2fvvkvS3dno+iw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.3.tgz", - "integrity": "sha512-yXH6K6KfqGXaxHrtr+Uoy+JpNlUlI46BKVyonGiaD74ravdnF9BUNC+vV+SIuB96hUMGShhKV693rF9QDfO6nQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.3.tgz", - "integrity": "sha512-R8cwY9wcnApN/KDYWTH4gV/ypvy9yZUHlbJvfaiXSB48JO3KpwSpjOGqO4jnGkLDSk1hgjYkTbTt6Q7uvPf8eg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.3.tgz", - "integrity": "sha512-kZPbX/NOPh0vhS5sI+dR8L1bU2cSO9FgxwM8r7wHzGydzfSjLRCFAT87GR5U9scj2rhzN3JPYVC7NoBbl4FZ0g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.3.tgz", - "integrity": "sha512-S0Yq+xA1VEH66uiMNhijsWAafffydd2X5b77eLHfRmfLsRSpbiAWiRHV6DEpz6aOToPsgid7TI9rGd6zB1rhbg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.3.tgz", - "integrity": "sha512-9isNzeL34yquCPyerog+IMCNxKR8XYmGd0tHSV+OVx0TmE0aJOo9uw4fZfUuk2qxobP5sug6vNdZR6u7Mw7Q+Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.3.tgz", - "integrity": "sha512-nMIdKnfZfzn1Vsk+RuOvl43ONTZXoAPUUxgcU0tXooqg4YrAqzfKzVenqqk2g5efWh46/D28cKFrOzDSW28gTA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.3.tgz", - "integrity": "sha512-fOvu7PCQjAj4eWDEuD8Xz5gpzFqXzGlxHZozHP4b9Jxv9APtdxL6STqztDzMLuRXEc4UpXGGhx029Xgm91QBeA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@types/css-font-loading-module": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/@types/css-font-loading-module/-/css-font-loading-module-0.0.12.tgz", - "integrity": "sha512-x2tZZYkSxXqWvTDgveSynfjq/T2HyiZHXb00j/+gy19yp70PHCizM48XFdjBCWH7eHBD0R5i/pw9yMBP/BH5uA==", - "license": "MIT" - }, - "node_modules/@types/earcut": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@types/earcut/-/earcut-2.1.4.tgz", - "integrity": "sha512-qp3m9PPz4gULB9MhjGID7wpo3gJ4bTGXm7ltNDsmOvsPduTeHp8wSW9YckBj3mljeOh4F0m2z/0JKAALRKbmLQ==", - "license": "MIT" - }, - "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, - "license": "MIT" - }, - "node_modules/@webgpu/types": { - "version": "0.1.45", - "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.45.tgz", - "integrity": "sha512-0TBBF/mhakJoK0qUWCZugBnh23x+VwmYA5RLmtNQwvZt1pQ4P2fzIvQUiSe6jxzkBi4GF8R4BejJjro0ZSoSXQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@xmldom/xmldom": { - "version": "0.8.10", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", - "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/earcut": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", - "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==", - "license": "ISC" - }, - "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" - } - }, - "node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "license": "MIT" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/ismobilejs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ismobilejs/-/ismobilejs-1.1.1.tgz", - "integrity": "sha512-VaFW53yt8QO61k2WJui0dHf4SlL8lxBofUuUmwBo0ljPk0Drz2TiuDW4jo3wDcv41qy/SxrJ+VAzJ/qYqsmzRw==", - "license": "MIT" - }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" + "name": "bastion", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "bastion", + "version": "0.0.0", + "dependencies": { + "pixi-viewport": "^6.0.3", + "pixi.js": "^8.4.0" + }, + "devDependencies": { + "typescript": "^5.5.3", + "vite": "^5.4.1" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@pixi/colord": { + "version": "2.9.6", + "resolved": "https://registry.npmjs.org/@pixi/colord/-/colord-2.9.6.tgz", + "integrity": "sha512-nezytU2pw587fQstUu1AsJZDVEynjskwOL+kibwcdxsMBFqPsFFNA7xl0ii/gXuDi6M0xj3mfRJj8pBSc2jCfA==", + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.3.tgz", + "integrity": "sha512-MmKSfaB9GX+zXl6E8z4koOr/xU63AMVleLEa64v7R0QF/ZloMs5vcD1sHgM64GXXS1csaJutG+ddtzcueI/BLg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.3.tgz", + "integrity": "sha512-zrt8ecH07PE3sB4jPOggweBjJMzI1JG5xI2DIsUbkA+7K+Gkjys6eV7i9pOenNSDJH3eOr/jLb/PzqtmdwDq5g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.3.tgz", + "integrity": "sha512-P0UxIOrKNBFTQaXTxOH4RxuEBVCgEA5UTNV6Yz7z9QHnUJ7eLX9reOd/NYMO3+XZO2cco19mXTxDMXxit4R/eQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.3.tgz", + "integrity": "sha512-L1M0vKGO5ASKntqtsFEjTq/fD91vAqnzeaF6sfNAy55aD+Hi2pBI5DKwCO+UNDQHWsDViJLqshxOahXyLSh3EA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.3.tgz", + "integrity": "sha512-btVgIsCjuYFKUjopPoWiDqmoUXQDiW2A4C3Mtmp5vACm7/GnyuprqIDPNczeyR5W8rTXEbkmrJux7cJmD99D2g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.3.tgz", + "integrity": "sha512-zmjbSphplZlau6ZTkxd3+NMtE4UKVy7U4aVFMmHcgO5CUbw17ZP6QCgyxhzGaU/wFFdTfiojjbLG3/0p9HhAqA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.3.tgz", + "integrity": "sha512-nSZfcZtAnQPRZmUkUQwZq2OjQciR6tEoJaZVFvLHsj0MF6QhNMg0fQ6mUOsiCUpTqxTx0/O6gX0V/nYc7LrgPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.3.tgz", + "integrity": "sha512-MnvSPGO8KJXIMGlQDYfvYS3IosFN2rKsvxRpPO2l2cum+Z3exiExLwVU+GExL96pn8IP+GdH8Tz70EpBhO0sIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.3.tgz", + "integrity": "sha512-+W+p/9QNDr2vE2AXU0qIy0qQE75E8RTwTwgqS2G5CRQ11vzq0tbnfBd6brWhS9bCRjAjepJe2fvvkvS3dno+iw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.3.tgz", + "integrity": "sha512-yXH6K6KfqGXaxHrtr+Uoy+JpNlUlI46BKVyonGiaD74ravdnF9BUNC+vV+SIuB96hUMGShhKV693rF9QDfO6nQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.3.tgz", + "integrity": "sha512-R8cwY9wcnApN/KDYWTH4gV/ypvy9yZUHlbJvfaiXSB48JO3KpwSpjOGqO4jnGkLDSk1hgjYkTbTt6Q7uvPf8eg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.3.tgz", + "integrity": "sha512-kZPbX/NOPh0vhS5sI+dR8L1bU2cSO9FgxwM8r7wHzGydzfSjLRCFAT87GR5U9scj2rhzN3JPYVC7NoBbl4FZ0g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.3.tgz", + "integrity": "sha512-S0Yq+xA1VEH66uiMNhijsWAafffydd2X5b77eLHfRmfLsRSpbiAWiRHV6DEpz6aOToPsgid7TI9rGd6zB1rhbg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.3.tgz", + "integrity": "sha512-9isNzeL34yquCPyerog+IMCNxKR8XYmGd0tHSV+OVx0TmE0aJOo9uw4fZfUuk2qxobP5sug6vNdZR6u7Mw7Q+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.3.tgz", + "integrity": "sha512-nMIdKnfZfzn1Vsk+RuOvl43ONTZXoAPUUxgcU0tXooqg4YrAqzfKzVenqqk2g5efWh46/D28cKFrOzDSW28gTA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.3.tgz", + "integrity": "sha512-fOvu7PCQjAj4eWDEuD8Xz5gpzFqXzGlxHZozHP4b9Jxv9APtdxL6STqztDzMLuRXEc4UpXGGhx029Xgm91QBeA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/css-font-loading-module": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/@types/css-font-loading-module/-/css-font-loading-module-0.0.12.tgz", + "integrity": "sha512-x2tZZYkSxXqWvTDgveSynfjq/T2HyiZHXb00j/+gy19yp70PHCizM48XFdjBCWH7eHBD0R5i/pw9yMBP/BH5uA==", + "license": "MIT" + }, + "node_modules/@types/earcut": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@types/earcut/-/earcut-2.1.4.tgz", + "integrity": "sha512-qp3m9PPz4gULB9MhjGID7wpo3gJ4bTGXm7ltNDsmOvsPduTeHp8wSW9YckBj3mljeOh4F0m2z/0JKAALRKbmLQ==", + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/@webgpu/types": { + "version": "0.1.45", + "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.45.tgz", + "integrity": "sha512-0TBBF/mhakJoK0qUWCZugBnh23x+VwmYA5RLmtNQwvZt1pQ4P2fzIvQUiSe6jxzkBi4GF8R4BejJjro0ZSoSXQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.10", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", + "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/earcut": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", + "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==", + "license": "ISC" + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/ismobilejs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ismobilejs/-/ismobilejs-1.1.1.tgz", + "integrity": "sha512-VaFW53yt8QO61k2WJui0dHf4SlL8lxBofUuUmwBo0ljPk0Drz2TiuDW4jo3wDcv41qy/SxrJ+VAzJ/qYqsmzRw==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/parse-svg-path": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/parse-svg-path/-/parse-svg-path-0.1.2.tgz", + "integrity": "sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "dev": true, + "license": "ISC" + }, + "node_modules/pixi-viewport": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/pixi-viewport/-/pixi-viewport-6.0.3.tgz", + "integrity": "sha512-2+qPJ0/n+8hQYhWvY+795+x9y3MiUrCOWacK0DY53whowWaGdx9iDocy7z1pBwjkZhC52YvrJQuZKK0sdVLtBw==", + "license": "MIT", + "peerDependencies": { + "pixi.js": ">=8" + } + }, + "node_modules/pixi.js": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/pixi.js/-/pixi.js-8.4.0.tgz", + "integrity": "sha512-IM0YDv7G9XATtD/sPgbEi6FoLg82+XSqejzeCWg575vEyuQGs4RrdVFSV/K/i2PeXr/sLxiHRJDOGuotBUlldA==", + "license": "MIT", + "dependencies": { + "@pixi/colord": "^2.9.6", + "@types/css-font-loading-module": "^0.0.12", + "@types/earcut": "^2.1.4", + "@webgpu/types": "^0.1.40", + "@xmldom/xmldom": "^0.8.10", + "earcut": "^2.2.4", + "eventemitter3": "^5.0.1", + "ismobilejs": "^1.1.1", + "parse-svg-path": "^0.1.2" + } + }, + "node_modules/postcss": { + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rollup": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.3.tgz", + "integrity": "sha512-7sqRtBNnEbcBtMeRVc6VRsJMmpI+JU1z9VTvW8D4gXIYQFz0aLcsE6rRkyghZkLfEgUZgVvOG7A5CVz/VW5GIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.21.3", + "@rollup/rollup-android-arm64": "4.21.3", + "@rollup/rollup-darwin-arm64": "4.21.3", + "@rollup/rollup-darwin-x64": "4.21.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.21.3", + "@rollup/rollup-linux-arm-musleabihf": "4.21.3", + "@rollup/rollup-linux-arm64-gnu": "4.21.3", + "@rollup/rollup-linux-arm64-musl": "4.21.3", + "@rollup/rollup-linux-powerpc64le-gnu": "4.21.3", + "@rollup/rollup-linux-riscv64-gnu": "4.21.3", + "@rollup/rollup-linux-s390x-gnu": "4.21.3", + "@rollup/rollup-linux-x64-gnu": "4.21.3", + "@rollup/rollup-linux-x64-musl": "4.21.3", + "@rollup/rollup-win32-arm64-msvc": "4.21.3", + "@rollup/rollup-win32-ia32-msvc": "4.21.3", + "@rollup/rollup-win32-x64-msvc": "4.21.3", + "fsevents": "~2.3.2" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/typescript": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/vite": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.5.tgz", + "integrity": "sha512-pXqR0qtb2bTwLkev4SE3r4abCNioP3GkjvIDLlzziPpXtHgiJIjuKl+1GN6ESOT3wMjG3JTeARopj2SwYaHTOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/parse-svg-path": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/parse-svg-path/-/parse-svg-path-0.1.2.tgz", - "integrity": "sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ==", - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", - "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", - "dev": true, - "license": "ISC" - }, - "node_modules/pixi.js": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/pixi.js/-/pixi.js-8.4.0.tgz", - "integrity": "sha512-IM0YDv7G9XATtD/sPgbEi6FoLg82+XSqejzeCWg575vEyuQGs4RrdVFSV/K/i2PeXr/sLxiHRJDOGuotBUlldA==", - "license": "MIT", - "dependencies": { - "@pixi/colord": "^2.9.6", - "@types/css-font-loading-module": "^0.0.12", - "@types/earcut": "^2.1.4", - "@webgpu/types": "^0.1.40", - "@xmldom/xmldom": "^0.8.10", - "earcut": "^2.2.4", - "eventemitter3": "^5.0.1", - "ismobilejs": "^1.1.1", - "parse-svg-path": "^0.1.2" - } - }, - "node_modules/postcss": { - "version": "8.4.47", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", - "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.1.0", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/rollup": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.3.tgz", - "integrity": "sha512-7sqRtBNnEbcBtMeRVc6VRsJMmpI+JU1z9VTvW8D4gXIYQFz0aLcsE6rRkyghZkLfEgUZgVvOG7A5CVz/VW5GIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.5" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.21.3", - "@rollup/rollup-android-arm64": "4.21.3", - "@rollup/rollup-darwin-arm64": "4.21.3", - "@rollup/rollup-darwin-x64": "4.21.3", - "@rollup/rollup-linux-arm-gnueabihf": "4.21.3", - "@rollup/rollup-linux-arm-musleabihf": "4.21.3", - "@rollup/rollup-linux-arm64-gnu": "4.21.3", - "@rollup/rollup-linux-arm64-musl": "4.21.3", - "@rollup/rollup-linux-powerpc64le-gnu": "4.21.3", - "@rollup/rollup-linux-riscv64-gnu": "4.21.3", - "@rollup/rollup-linux-s390x-gnu": "4.21.3", - "@rollup/rollup-linux-x64-gnu": "4.21.3", - "@rollup/rollup-linux-x64-musl": "4.21.3", - "@rollup/rollup-win32-arm64-msvc": "4.21.3", - "@rollup/rollup-win32-ia32-msvc": "4.21.3", - "@rollup/rollup-win32-x64-msvc": "4.21.3", - "fsevents": "~2.3.2" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/typescript": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", - "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/vite": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.5.tgz", - "integrity": "sha512-pXqR0qtb2bTwLkev4SE3r4abCNioP3GkjvIDLlzziPpXtHgiJIjuKl+1GN6ESOT3wMjG3JTeARopj2SwYaHTOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } } - } } diff --git a/package.json b/package.json index 1ce811b..7693224 100644 --- a/package.json +++ b/package.json @@ -1,18 +1,19 @@ { - "name": "bastion", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "typescript": "^5.5.3", - "vite": "^5.4.1" - }, - "dependencies": { - "pixi.js": "^8.4.0" - } + "name": "bastion", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "devDependencies": { + "typescript": "^5.5.3", + "vite": "^5.4.1" + }, + "dependencies": { + "pixi-viewport": "^6.0.3", + "pixi.js": "^8.4.0" + } } diff --git a/public/Mission011 b/public/Mission011 new file mode 100644 index 0000000..5915250 --- /dev/null +++ b/public/Mission011 @@ -0,0 +1,48 @@ +{ "compressionlevel":-1, + "height":17, + "infinite":false, + "layers":[ + { + "data":[15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 15, 15, 15, 15, 15, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 7, 18, 19, 15, 15, 15, 15, 15, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 17, 18, 19, 15, 15, 15, 15, 15, 17, 18, 6, 32, 32, 32, 32, 32, 32, 32, 32, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 17, 18, 19, 15, 15, 15, 15, 15, 17, 18, 19, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 17, 18, 19, 15, 15, 15, 15, 15, 17, 18, 19, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 3, 4, 4, 4, 4, 4, 4, 4, 4, 21, 18, 19, 15, 15, 15, 15, 15, 17, 18, 19, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 15, 15, 15, 15, 15, 17, 18, 19, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 17, 18, 6, 32, 32, 32, 32, 32, 32, 32, 32, 33, 15, 15, 15, 15, 15, 17, 18, 19, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 17, 18, 19, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 17, 18, 19, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 17, 18, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 21, 18, 19, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 31, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 33, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15], + "height":17, + "id":1, + "name":"Tile Layer 1", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":30, + "x":0, + "y":0 + }], + "nextlayerid":2, + "nextobjectid":1, + "orientation":"orthogonal", + "renderorder":"right-down", + "tiledversion":"1.11.0", + "tileheight":64, + "tilesets":[ + { + "firstgid":1, + "source":"Tileset.tsx" + }], + "tilewidth":64, + "type":"map", + "version":"1.10", + "width":30 +} \ No newline at end of file diff --git a/public/Mission011.tmx b/public/Mission011.tmx new file mode 100644 index 0000000..df76b7d --- /dev/null +++ b/public/Mission011.tmx @@ -0,0 +1,25 @@ + + + + + +15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, +15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, +15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, +4,4,4,4,4,4,4,4,4,4,4,4,4,5,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, +18,18,18,18,18,18,18,18,18,18,18,18,18,19,15,15,15,15,15,3,4,4,4,4,4,4,4,4,4,4, +32,32,32,32,32,32,32,32,32,32,32,7,18,19,15,15,15,15,15,17,18,18,18,18,18,18,18,18,18,18, +15,15,15,15,15,15,15,15,15,15,15,17,18,19,15,15,15,15,15,17,18,6,32,32,32,32,32,32,32,32, +15,15,15,15,15,15,15,15,15,15,15,17,18,19,15,15,15,15,15,17,18,19,15,15,15,15,15,15,15,15, +15,15,15,15,15,15,15,15,15,15,15,17,18,19,15,15,15,15,15,17,18,19,15,15,15,15,15,15,15,15, +15,15,3,4,4,4,4,4,4,4,4,21,18,19,15,15,15,15,15,17,18,19,15,15,15,15,15,15,15,15, +15,15,17,18,18,18,18,18,18,18,18,18,18,19,15,15,15,15,15,17,18,19,15,15,15,15,15,15,15,15, +15,15,17,18,6,32,32,32,32,32,32,32,32,33,15,15,15,15,15,17,18,19,15,15,15,15,15,15,15,15, +15,15,17,18,19,15,15,15,15,15,15,15,15,15,15,15,15,15,15,17,18,19,15,15,15,15,15,15,15,15, +15,15,17,18,20,4,4,4,4,4,4,4,4,4,4,4,4,4,4,21,18,19,15,15,15,15,15,15,15,15, +15,15,17,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,19,15,15,15,15,15,15,15,15, +15,15,31,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,33,15,15,15,15,15,15,15,15, +15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15 + + + diff --git a/public/Tileset.tsx b/public/Tileset.tsx new file mode 100644 index 0000000..7f536c1 --- /dev/null +++ b/public/Tileset.tsx @@ -0,0 +1,4 @@ + + + + diff --git a/public/assets/CreepStats.json b/public/assets/CreepStats.json index 2d76ba3..2953501 100644 --- a/public/assets/CreepStats.json +++ b/public/assets/CreepStats.json @@ -1,7 +1,7 @@ [ { "health": 2, - "speed": 0.0005, + "speed": 0.04, "special": null, "resistance": { "physical": 0, diff --git a/public/assets/Towers.json b/public/assets/Towers.json index 01f0acd..44b34c0 100644 --- a/public/assets/Towers.json +++ b/public/assets/Towers.json @@ -1,12 +1,15 @@ [ { "name": "Basic Tower", + "behaviour": "BasicTowerBehaviour", + "sprite": "basic_tower", + "description": "The building block of society, nothing more basic exists.", "stats": { "damage": 2, - "cooldown": 2, + "cooldown": 120, "gemSlotsAmount": 2, "cost": 100, - "range": 7 + "range": 3 } } ] diff --git a/public/assets/gui/background_01.png b/public/assets/gui/background_01.png new file mode 100755 index 0000000..3fa5d9b Binary files /dev/null and b/public/assets/gui/background_01.png differ diff --git a/public/assets/gui/background_02.png b/public/assets/gui/background_02.png new file mode 100755 index 0000000..223d6c7 Binary files /dev/null and b/public/assets/gui/background_02.png differ diff --git a/public/assets/gui/banner_01.png b/public/assets/gui/banner_01.png new file mode 100755 index 0000000..63258b3 Binary files /dev/null and b/public/assets/gui/banner_01.png differ diff --git a/public/assets/gui/banner_02.png b/public/assets/gui/banner_02.png new file mode 100755 index 0000000..dae9558 Binary files /dev/null and b/public/assets/gui/banner_02.png differ diff --git a/public/assets/gui/button_01.png b/public/assets/gui/button_01.png new file mode 100755 index 0000000..45d7a92 Binary files /dev/null and b/public/assets/gui/button_01.png differ diff --git a/public/assets/gui/frame.png b/public/assets/gui/frame.png deleted file mode 100755 index 2eb8e3b..0000000 Binary files a/public/assets/gui/frame.png and /dev/null differ diff --git a/public/assets/gui/frame_01.png b/public/assets/gui/frame_01.png new file mode 100755 index 0000000..4e8d957 Binary files /dev/null and b/public/assets/gui/frame_01.png differ diff --git a/public/assets/gui/frame_green.png b/public/assets/gui/frame_green.png new file mode 100755 index 0000000..2df7428 Binary files /dev/null and b/public/assets/gui/frame_green.png differ diff --git a/public/assets/gui/frame_red.png b/public/assets/gui/frame_red.png new file mode 100755 index 0000000..69d3a94 Binary files /dev/null and b/public/assets/gui/frame_red.png differ diff --git a/public/assets/gui/frame_violet.png b/public/assets/gui/frame_violet.png new file mode 100755 index 0000000..0adecfb Binary files /dev/null and b/public/assets/gui/frame_violet.png differ diff --git a/public/assets/gui/gems.png b/public/assets/gui/gems.png new file mode 100755 index 0000000..3568b33 Binary files /dev/null and b/public/assets/gui/gems.png differ diff --git a/public/assets/gui/gui_01_button_01.png b/public/assets/gui/gui_01_button_01.png new file mode 100755 index 0000000..5df1548 Binary files /dev/null and b/public/assets/gui/gui_01_button_01.png differ diff --git a/public/assets/gui/gui_01_checkbox_01_bg01.png b/public/assets/gui/gui_01_checkbox_01_bg01.png new file mode 100755 index 0000000..deaf98e Binary files /dev/null and b/public/assets/gui/gui_01_checkbox_01_bg01.png differ diff --git a/public/assets/gui/money.png b/public/assets/gui/money.png new file mode 100755 index 0000000..12c40de Binary files /dev/null and b/public/assets/gui/money.png differ diff --git a/public/assets/gui/shield.png b/public/assets/gui/shield_01.png similarity index 100% rename from public/assets/gui/shield.png rename to public/assets/gui/shield_01.png diff --git a/public/assets/gui/shield_02.png b/public/assets/gui/shield_02.png new file mode 100755 index 0000000..618adb8 Binary files /dev/null and b/public/assets/gui/shield_02.png differ diff --git a/public/assets/gui/w_anvil.png b/public/assets/gui/w_anvil.png new file mode 100755 index 0000000..b641848 Binary files /dev/null and b/public/assets/gui/w_anvil.png differ diff --git a/public/assets/maps/mission_01.png b/public/assets/maps/mission_01.png index f741499..6d14258 100644 Binary files a/public/assets/maps/mission_01.png and b/public/assets/maps/mission_01.png differ diff --git a/public/assets/missions/mission_01.json b/public/assets/missions/mission_01.json index 4c142f7..67f5e30 100644 --- a/public/assets/missions/mission_01.json +++ b/public/assets/missions/mission_01.json @@ -2,58 +2,94 @@ "name": "Mission 1", "description": "This is the first mission", "mapImage": { - "url": "/assets/maps/mission_01.png", - "width": 1200, - "height": 900 + "url": "/assets/maps/mission_01.png" }, "gameMap": { - "rows": 15, - "columns": 20, + "rows": 17, + "columns": 25, "cells": [ - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] ], "paths": [ [ - [8, 0], - [8, 1], - [9, 2], - [10, 2], - [11, 2], - [12, 3], - [12, 4], - [12, 5], - [12, 6], - [12, 7], - [12, 8], - [12, 9], - [11, 10], - [10, 10], - [9, 10], - [8, 11], + [4, 0], + [4, 1], + [4, 2], + [4, 3], + [4, 4], + [4, 5], + [4, 6], + [4, 7], + [4, 8], + [4, 9], + [4, 10], + [4, 11], + [4, 12], + [5, 12], + [6, 12], + [7, 12], [8, 12], - [8, 13], - [7, 14], - [6, 14], - [5, 14], - [4, 14], - [3, 14], - [2, 14], - [1, 14], - [0, 15] + [9, 12], + [10, 12], + [10, 11], + [10, 10], + [10, 9], + [10, 8], + [10, 7], + [10, 6], + [10, 5], + [10, 4], + [10, 3], + [11, 3], + [12, 3], + [13, 3], + [14, 3], + [14, 4], + [14, 5], + [14, 6], + [14, 7], + [14, 8], + [14, 9], + [14, 10], + [14, 11], + [14, 12], + [14, 13], + [14, 14], + [14, 15], + [14, 16], + [14, 17], + [14, 18], + [14, 19], + [14, 20], + [13, 20], + [12, 20], + [11, 20], + [10, 20], + [9, 20], + [8, 20], + [7, 20], + [6, 20], + [5, 20], + [5, 21], + [5, 22], + [5, 23], + [5, 24] ] ] }, diff --git a/public/assets/projectiles/basic_tower.png b/public/assets/projectiles/basic_tower.png new file mode 100644 index 0000000..272ad51 Binary files /dev/null and b/public/assets/projectiles/basic_tower.png differ diff --git a/public/assets/towers/basic_tower.png b/public/assets/towers/basic_tower.png new file mode 100644 index 0000000..6d127c0 Binary files /dev/null and b/public/assets/towers/basic_tower.png differ diff --git a/public/maps.tiled-project b/public/maps.tiled-project new file mode 100644 index 0000000..d0eb592 --- /dev/null +++ b/public/maps.tiled-project @@ -0,0 +1,14 @@ +{ + "automappingRulesFile": "", + "commands": [ + ], + "compatibilityVersion": 1100, + "extensionsPath": "extensions", + "folders": [ + "." + ], + "properties": [ + ], + "propertyTypes": [ + ] +} diff --git a/public/maps.tiled-session b/public/maps.tiled-session new file mode 100644 index 0000000..f9cf226 --- /dev/null +++ b/public/maps.tiled-session @@ -0,0 +1,66 @@ +{ + "Map/SizeTest": { + "height": 4300, + "width": 2 + }, + "activeFile": "Mission011.tmx", + "expandedProjectPaths": [ + "." + ], + "file.lastUsedOpenFilter": "All Files (*)", + "fileStates": { + "": { + "scaleInDock": 0.33 + }, + "#TiledTDThree128": { + "scaleInDock": 0.33, + "scaleInEditor": 1 + }, + "/home/koneko/dumping/tiles/TiledTDThree64.tmx": { + "scale": 0.187625, + "selectedLayer": 0, + "viewCenter": { + "x": 3197.8680879413732, + "y": 3197.8680879413732 + } + }, + "Mission01.tmx": { + "scale": 0.6739062499999999, + "selectedLayer": 0, + "viewCenter": { + "x": 795.3628564804081, + "y": 639.5548342221192 + } + }, + "Mission011.tmx": { + "scale": 0.5, + "selectedLayer": 0, + "viewCenter": { + "x": 1070, + "y": 448 + } + }, + "Tileset.tsx": { + "scaleInDock": 0.5, + "scaleInEditor": 1 + } + }, + "last.externalTilesetPath": "/home/koneko/Programing/js/towerdefense/public", + "map.height": 17, + "map.lastUsedFormat": "tmx", + "map.tileHeight": 64, + "map.tileWidth": 64, + "map.width": 30, + "openFiles": [ + "Tileset.tsx", + "Mission011.tmx" + ], + "project": "maps.tiled-project", + "recentFiles": [ + "Tileset.tsx", + "Mission011.tmx", + "Mission01.tmx", + "/home/koneko/dumping/tiles/TiledTDThree64.tmx" + ], + "tileset.lastUsedFilter": "Tiled tileset files (*.tsx *.xml)" +} diff --git a/public/style.css b/public/style.css index b36f3cc..316c7f7 100644 --- a/public/style.css +++ b/public/style.css @@ -1,10 +1,12 @@ -* { - margin: 0; - padding: 0; -} body, html { - width: 100vw; - height: 100vh; - overflow: hidden; + margin: 0; + padding: 0; + overflow: hidden; /* Prevent scrollbars */ + width: 100%; + height: 100%; + background-color: black; /* Letterbox background color */ +} +canvas { + display: block; } diff --git a/src/classes/Assets.ts b/src/classes/Assets.ts new file mode 100644 index 0000000..0bb3833 --- /dev/null +++ b/src/classes/Assets.ts @@ -0,0 +1,133 @@ +import * as PIXI from 'pixi.js'; +import { CreepStatsDefinition, MissionDefinition, TowerDefinition } from './Definitions'; +import { Globals } from './Bastion'; + +export default class GameAssets { + public static async LoadAssets() { + console.log('Loading Texture Assets'); + const text = new PIXI.Text({ + text: 'Loading textures. This might take a while.', + style: new PIXI.TextStyle({ + fill: 0x333333, + fontSize: 50, + }), + }); + text.x = Globals.app.canvas.width / 2; + text.y = Globals.app.canvas.height / 2; + text.anchor.set(0.5, 0.5); + Globals.app.stage.addChild(text); + GameAssets.Button01Texture = await PIXI.Assets.load({ + src: '/assets/gui/button_01.png', + }); + GameAssets.Button02Texture = await PIXI.Assets.load({ + src: '/assets/gui/button_02.png', + }); + GameAssets.Frame01Texture = await PIXI.Assets.load({ + src: '/assets/gui/frame_01.png', + }); + GameAssets.Frame02Texture = await PIXI.Assets.load({ + src: '/assets/gui/frame_02.png', + }); + GameAssets.FrameBackground = await PIXI.Assets.load({ + src: '/assets/gui/background_01.png', + }); + GameAssets.FrameTowerTab = await PIXI.Assets.load({ + src: '/assets/gui/background_02.png', + }); + GameAssets.VioletBackground = await PIXI.Assets.load({ + src: '/assets/gui/frame_violet.png', + }); + GameAssets.RedBackground = await PIXI.Assets.load({ + src: '/assets/gui/frame_red.png', + }); + GameAssets.GreenBackground = await PIXI.Assets.load({ + src: '/assets/gui/frame_green.png', + }); + GameAssets.HealthTexture = await PIXI.Assets.load({ + src: '/assets/gui/heart.png', + }); + GameAssets.GoldTexture = await PIXI.Assets.load({ + src: '/assets/gui/money.png', + }); + + GameAssets.BasicCreepTexture = await PIXI.Assets.load({ + src: '/assets/creeps/basic.jpg', + }); + + GameAssets.BasicTowerTexture = await PIXI.Assets.load({ + src: '/assets/towers/basic_tower.png', + }); + + GameAssets.BasicProjectileTexture = await PIXI.Assets.load({ + src: '/assets/projectiles/basic_tower.png', + }); + + await this.LoadMissions(); + await this.LoadTowers(); + await this.LoadCreepStats(); + text.destroy(); + } + + public static async LoadCreepStats() { + const res = await fetch('/assets/CreepStats.json'); + const stats = await res.json(); + this.CreepStats = stats; + } + + private static async LoadMissions() { + GameAssets.Missions = [await this.LoadMission('/assets/missions/mission_01.json')]; + } + + private static async LoadTowers() { + const res = await fetch('/assets/Towers.json'); + const towers = await res.json(); + GameAssets.Towers = towers; + towers.forEach(async (tower) => { + let index = this.TowerSprites.length - 1; + if (index == -1) index = 0; + this.TowerSprites[index] = await PIXI.Assets.load({ + src: `/assets/towers/${tower.sprite}.png`, + }); + }); + } + + private static async LoadMission(missionUrl: string) { + const res = await fetch(missionUrl); + const mission = await res.json(); + await this.LoadBackground(mission.mapImage.url); + return mission; + } + + private static async LoadBackground(backgroundUrl: string) { + let index = this.MissionBackgrounds.length - 1; + if (index == -1) index = 0; + this.MissionBackgrounds[index] = await PIXI.Assets.load({ + src: backgroundUrl, + }); + } + + public static BasicCreepTexture: PIXI.Texture; + + public static BasicTowerTexture: PIXI.Texture; + + public static BasicProjectileTexture: PIXI.Texture; + + public static Frame01Texture: PIXI.Texture; + public static Frame02Texture: PIXI.Texture; + public static FrameBackground: PIXI.Texture; + public static FrameTowerTab: PIXI.Texture; + public static VioletBackground: PIXI.Texture; + public static RedBackground: PIXI.Texture; + public static GreenBackground: PIXI.Texture; + public static Button01Texture: PIXI.Texture; + public static Button02Texture: PIXI.Texture; + public static HealthTexture: PIXI.Texture; + public static GoldTexture: PIXI.Texture; + + public static MissionBackgrounds: PIXI.Texture[] = []; + public static TowerSprites: PIXI.Texture[] = []; + public static Missions: MissionDefinition[]; + public static Towers: TowerDefinition[]; + public static CreepStats: CreepStatsDefinition[]; + public static DebuggingEnabled: boolean = false; +} diff --git a/src/classes/Bastion.ts b/src/classes/Bastion.ts new file mode 100644 index 0000000..41c0b5f --- /dev/null +++ b/src/classes/Bastion.ts @@ -0,0 +1,51 @@ +import * as PIXI from 'pixi.js'; +import GameObject from './GameObject'; +import GuiObject from './GuiObject'; +import Scene from '../scenes/Scene'; +import { Grid } from './game/Grid'; +import WaveManager from './game/WaveManager'; +import TowerManager from './game/TowerManager'; +import { GameScene } from '../scenes/Game'; + +export class Globals { + public static app: PIXI.Application; + public static GameMaster: GameMaster; + public static WindowHeight: number; + public static WindowWidth: number; + public static AspectRatio: number = 16 / 9; + public static Grid: Grid; + public static WaveManager: WaveManager; + public static TowerManager: TowerManager; + public static GameScene: GameScene; +} + +export default class GameMaster { + public currentScene: Scene; + private gameScene: GameScene; + private GameObjects: GameObject[] = []; + + constructor() { + Globals.GameMaster = this; + } + + public _CreateGuiObject(object: GuiObject) { + this.currentScene.gui.push(object); + Globals.app.stage.addChild(object.container); + } + + public _RemoveGuiObject(object: GuiObject) { + this.currentScene.gui.splice(this.currentScene.gui.indexOf(object), 1); + Globals.app.stage.removeChild(object.container); + } + + public changeScene(newScene: Scene) { + if (this.currentScene) { + this.currentScene.destroy(); + } + this.GameObjects.forEach((element) => { + element.destroy(); + }); + this.currentScene = newScene; + this.currentScene.init(); + } +} diff --git a/src/classes/Definitions.ts b/src/classes/Definitions.ts new file mode 100644 index 0000000..a1328cf --- /dev/null +++ b/src/classes/Definitions.ts @@ -0,0 +1,85 @@ +export type MissionDefinition = { + name: string; + description: string; + mapImage: MapImageDefinition; + gameMap: GameMapDefinition; + rounds: MissionRoundDefinition[]; +}; + +export type MapImageDefinition = { + url: string; +}; + +export type GameMapDefinition = { + rows: number; + columns: number; + cells: TerrainType[][]; + paths: PathDefinition[]; +}; + +export type MissionRoundDefinition = { + waves: WaveDefinition[]; + offeredGems: GemType[]; +}; + +export type WaveDefinition = { + firstCreepSpawnTick: number; + spawnIntervalTicks: number; + creeps: CreepType[]; +}; + +export type CreepStatsDefinition = { + health: number; + speed: number; + special: Function; + resistance: CreepResistancesDefinition; +}; + +export type CreepResistancesDefinition = { + physical: number; + divine: number; + fire: number; + ice: number; + frostfire: number; +}; + +export type TowerDefinition = { + name: string; + behaviour: string; + sprite: string; + description: string; + stats: TowerStatsDefinition; +}; + +export type TowerStatsDefinition = { + damage: number; + cooldown: number; + gemSlotsAmount: number; + cost: number; + range: number; +}; + +export type PathDefinition = [[row: number, column: number]]; + +export enum CreepType { + Basic = 0, + Fast = 1, +} + +export enum TerrainType { + Restricted = 0, + Buildable = 1, + Path = 9, +} + +export enum GemType { + Fire = 0, + Yeti = 1, + Titalium = 2, + Soulforge = 3, +} + +export enum TowerType { + Shooting = 0, + Circle = 1, +} diff --git a/src/classes/GameObject.ts b/src/classes/GameObject.ts new file mode 100644 index 0000000..6e822e6 --- /dev/null +++ b/src/classes/GameObject.ts @@ -0,0 +1,27 @@ +import * as PIXI from 'pixi.js'; + +export default abstract class GameObject { + public readonly name: string = this.constructor.name; + + protected _container: PIXI.Container = new PIXI.Container(); + + protected bb: PIXI.Rectangle = new PIXI.Rectangle(); + + protected _events: PIXI.EventEmitter = new PIXI.EventEmitter(); + + public destroy() { + this._events.removeAllListeners(); + if (this._container.parent) this._container.parent.removeChild(this._container); + this._container.destroy(); + } + + public get container(): PIXI.Container { + return this._container; + } + + public get events(): PIXI.EventEmitter { + return this._events; + } + + public abstract update(elapsedMS): void; +} diff --git a/src/classes/GuiObject.ts b/src/classes/GuiObject.ts new file mode 100644 index 0000000..ba93d86 --- /dev/null +++ b/src/classes/GuiObject.ts @@ -0,0 +1,50 @@ +import * as PIXI from 'pixi.js'; +import { Globals } from './Bastion'; + +export default abstract class GuiObject { + public readonly name: string = this.constructor.name; + + protected _container: PIXI.Container = new PIXI.Container(); + + protected _events: PIXI.EventEmitter = new PIXI.EventEmitter(); + + protected enabled: boolean = true; + + public destroy() { + this._events.removeAllListeners(); + if (this._container.parent) this._container.parent.removeChild(this._container); + this._container.destroy(); + } + + public get container(): PIXI.Container { + return this._container; + } + + public get events(): PIXI.EventEmitter { + return this._events; + } + + public onClick(e: PIXI.FederatedPointerEvent) { + console.warn(`[${this.name} does not implement GuiObject.onClick()]`); + } + + public onWheel(e: PIXI.FederatedWheelEvent) { + console.warn(`[${this.name} does not implement GuiObject.onWheel()]`); + } + + public setEnabled(enabled: boolean) { + this.enabled = enabled; + } + + constructor(interactive?: boolean) { + Globals.GameMaster._CreateGuiObject(this); + if (!interactive) return; + this._container.interactive = true; + this._container.onwheel = (e) => { + if (this.enabled) this.onWheel(e); + }; + this._container.onclick = (e) => { + if (this.enabled) this.onClick(e); + }; + } +} diff --git a/src/classes/game/Creep.ts b/src/classes/game/Creep.ts new file mode 100644 index 0000000..bbf4269 --- /dev/null +++ b/src/classes/game/Creep.ts @@ -0,0 +1,113 @@ +import GameAssets from '../Assets'; +import Assets from '../Assets'; +import { Globals } from '../Bastion'; +import { CreepStatsDefinition, CreepType, PathDefinition } from '../Definitions'; +import GameObject from '../GameObject'; +import * as PIXI from 'pixi.js'; + +export enum CreepEvents { + Died = 'died', + TakenDamage = 'takenDamage', + Escaped = 'escaped', + Moved = 'moved', +} + +export default class Creep extends GameObject { + public creepType: CreepType; + private sprite: PIXI.Sprite; + private path: PathDefinition; + private stats: CreepStatsDefinition; + private pathIndex: number = 0; + private speed: number; + public health: number; + public maxHealth: number; + public escaped: boolean = false; + public died: boolean = false; + public x: number; + public y: number; + constructor(creepType: CreepType, path: PathDefinition) { + super(); + this.creepType = creepType; + this.stats = structuredClone(Assets.CreepStats[this.creepType]); + this.sprite = new PIXI.Sprite({ + texture: GameAssets.BasicCreepTexture, + }); + this.container.label = 'creep-' + creepType.toString(); + // because wave manager spawns all instantly and i dont want + // it to look like a shit game (they all spawn in top left corner) + // i want to hide minion - mario + this.container.x = -70; + this.container.y = -50; + this.sprite.width = 64; + this.sprite.height = 64; + this.speed = this.stats.speed; + this.health = this.stats.health; + this.maxHealth = this.stats.health; + this.path = path; + this.x = path[0][1] * 64 + 32; // centered + this.y = path[0][0] * 64 + 32; + Globals.Grid.container.addChild(this.container); + this.container.addChild(this.sprite); + } + public update(elapsedMS: number) { + if (this.pathIndex + 1 == this.path.length) { + if (this.escaped) return; + this.events.emit(CreepEvents.Escaped, this); + this.escaped = true; + return; + } + const currentCell = this.path[this.pathIndex]; + const targetCell = this.path[this.pathIndex + 1]; + + const targetX = targetCell[1] * 64 + 32; + const targetY = targetCell[0] * 64 + 32; + const directionX = targetCell[1] - currentCell[1]; + const directionY = targetCell[0] - currentCell[0]; + let deltaX = this.speed * elapsedMS * directionX; + let deltaY = this.speed * elapsedMS * directionY; + let increaseIndex = false; + + if (deltaX > 0 && this.x + deltaX > targetX) { + // limit to center of target cell + deltaX = targetX - this.x; + increaseIndex = true; + } + if (deltaX < 0 && this.x + deltaX < targetX) { + // limit to center of target cell + deltaX = targetX - this.x; + increaseIndex = true; + } + if (deltaY > 0 && this.y + deltaY > targetY) { + // limit to center of target cell + deltaY = targetY - this.y; + increaseIndex = true; + } + if (deltaY < 0 && this.y + deltaY < targetY) { + // limit to center of target cell + deltaY = targetY - this.y; + increaseIndex = true; + } + this.x += deltaX; + this.y += deltaY; + if (increaseIndex) this.pathIndex++; + this.draw(); + } + + public takeDamage(amount: number) { + this.health -= amount; + if (this.health < 0 && !this.died) { + this.died = true; + this.events.emit(CreepEvents.Died, this); + } + } + + public override destroy() { + super.destroy(); + this.container.removeChildren(); + } + protected draw() { + this.sprite.anchor.set(0.5, 0.5); + this.container.x = this.x; + this.container.y = this.y; + } +} diff --git a/src/classes/game/Grid.ts b/src/classes/game/Grid.ts new file mode 100644 index 0000000..0f80765 --- /dev/null +++ b/src/classes/game/Grid.ts @@ -0,0 +1,155 @@ +import * as PIXI from 'pixi.js'; +import GameObject from '../GameObject'; +import { GameMapDefinition, TerrainType } from '../Definitions'; +import GameAssets from '../Assets'; +import { Globals } from '../Bastion'; +import Creep, { CreepEvents } from './Creep'; + +export class Cell extends GameObject { + public type: TerrainType; + public row: number; + public column: number; + public isPath: boolean = false; + private g: PIXI.Graphics; + public clickDetector: PIXI.Graphics; + + constructor(type: TerrainType, row: number, column: number, isPath: boolean) { + super(); + this.type = type; + this.row = row; + this.column = column; + this.isPath = isPath; + this.bb.x = this.column * 64; + this.bb.y = this.row * 64; + this.bb.width = 64; + this.bb.height = 64; + Globals.Grid.container.addChild(this.container); + this.container.x = this.bb.x; + this.container.y = this.bb.y; + + this.clickDetector = new PIXI.Graphics({ + zIndex: 99, + interactive: true, + }); + this.clickDetector.rect(0, 0, this.bb.width, this.bb.height); + this.clickDetector.fill({ color: 0xff0000, alpha: 0 }); + this.container.addChild(this.clickDetector); + this.clickDetector.onclick = (e) => { + Globals.Grid._gridCellClicked(row, column); + }; + + if (!GameAssets.DebuggingEnabled) return; + const text = new PIXI.Text({ + text: `${this.row}|${this.column}`, + style: new PIXI.TextStyle({ + fill: 0xffffff, + dropShadow: true, + fontSize: 16, + }), + }); + this.container.addChild(text); + text.anchor.set(0.5, 0.5); + text.x = this.bb.width / 2; + text.y = this.bb.height / 2; + if (isPath) text.text += 'p'; + } + public gDraw() { + this.g = new PIXI.Graphics({ + zIndex: 5, + }); + this.g.rect(0, 0, this.bb.width, this.bb.height); + switch (this.type) { + case TerrainType.Restricted: + this.g.fill({ color: 0x222222, alpha: 0.5 }); + break; + case TerrainType.Path: + this.g.fill({ color: 0x222222, alpha: 0.5 }); + break; + case TerrainType.Buildable: + this.g.stroke({ color: 0x00ff00, alpha: 0.9 }); + break; + } + this.container.addChild(this.g); + } + public gClear() { + if (this.g != null) { + this.container.removeChild(this.g); + this.g.destroy(); + } + } + public update() {} +} + +export class Grid extends GameObject { + private gameMap: GameMapDefinition; + private cells: Cell[] = []; + public creeps: Creep[] = []; + public gridShown: boolean = false; + + constructor(map: GameMapDefinition, missionIndex) { + super(); + this.gameMap = map; + Globals.Grid = this; + this.bb.x = 0; + this.bb.y = 0; + this.bb.width = 64 * 30; + this.bb.height = 64 * 17; + Globals.app.stage.addChild(this.container); + + let background = new PIXI.Sprite(GameAssets.MissionBackgrounds[missionIndex]); + background.x = 0; + background.y = 0; + background.width = this.bb.width; + background.height = this.bb.height; + + this.container.addChild(background); + + for (let y = 0; y < this.gameMap.columns; y++) { + for (let x = 0; x < this.gameMap.rows; x++) { + let type = this.gameMap.cells[x][y]; + if (!type) type = 1; + const isPath = this.gameMap.paths.some((path) => path.some((p) => p[0] === x && p[1] === y)); + if (isPath) type = TerrainType.Path; + let cell = new Cell(type, x, y, isPath); + this.cells.push(cell); + } + } + } + public toggleGrid() { + this.cells.forEach((cell) => { + if (this.gridShown) { + cell.gClear(); + } else { + cell.gDraw(); + } + }); + this.gridShown = !this.gridShown; + } + public addCreep(creep: Creep) { + console.log('ADD CREEP'); + this.creeps.push(creep); + creep.events.on(CreepEvents.Died, (diedCreep) => { + this.onCreepDiedOrEscaped(diedCreep); + }); + creep.events.on(CreepEvents.Escaped, (escapedCreep) => { + this.onCreepDiedOrEscaped(escapedCreep); + }); + } + private onCreepDiedOrEscaped(creep: Creep) { + this.creeps.splice(this.creeps.indexOf(creep), 1); + creep.destroy(); + } + public update(elapsedMS) { + this.creeps.forEach((creep) => { + creep.update(elapsedMS); + }); + } + public getCellByRowAndCol(row, column) { + return this.cells.filter((item) => item.row == row && item.column == column)[0]; + } + public _gridCellClicked(row, column) { + // function will be assigned by GameScene, but must be predefined here. + this.onGridCellClicked(row, column); + } + public onGridCellClicked(row, column) {} +} diff --git a/src/classes/game/MissionStats.ts b/src/classes/game/MissionStats.ts new file mode 100644 index 0000000..265ba58 --- /dev/null +++ b/src/classes/game/MissionStats.ts @@ -0,0 +1,94 @@ +import Assets from '../Assets'; +import { Globals } from '../Bastion'; +import GameObject from '../GameObject'; +import * as PIXI from 'pixi.js'; + +export default class MissionStats extends GameObject { + private hp: number = 100; + private gold: number = 0; + private goldText: PIXI.Text; + private healthText: PIXI.Text; + + public getHP() { + return this.hp; + } + + public hasEnoughGold(amount) { + return amount <= this.gold; + } + + public setHP(hp: number) { + this.hp = hp; + this.healthText.text = this.hp; + } + + public takeDamage(damage: number) { + this.hp -= damage; + this.healthText.text = this.hp; + } + + public setGold(gold: number) { + this.gold = gold; + this.goldText.text = this.gold; + } + + public earnGold(gold: number) { + this.gold += gold; + this.goldText.text = this.gold; + } + + public spendGold(amount: number) { + this.gold -= amount; + this.goldText.text = this.gold; + } + + constructor(initialHP: number, initialGold: number) { + super(); + this.hp = initialHP; + this.gold = initialGold; + this.container.x = 0; + this.container.y = 20; + Globals.app.stage.addChild(this.container); + this.healthText = new PIXI.Text({ + text: `${this.hp}`, + style: new PIXI.TextStyle({ + fill: 'red', + fontSize: 36, + fontWeight: 'bold', + dropShadow: true, + }), + }); + this.goldText = new PIXI.Text({ + text: `${this.gold}`, + style: new PIXI.TextStyle({ + fill: 'gold', + fontSize: 36, + fontWeight: 'bold', + dropShadow: true, + }), + }); + const healthSprite = new PIXI.Sprite(Assets.HealthTexture); + const goldSprite = new PIXI.Sprite(Assets.GoldTexture); + + this.healthText.x = 200; + this.healthText.y = -15; + healthSprite.x = 160; + healthSprite.width = 36; + healthSprite.height = 32; + healthSprite.y = -10; + + this.goldText.x = 200; + this.goldText.y = 20; + goldSprite.x = 150; + goldSprite.width = 56; + goldSprite.height = 56; + goldSprite.y = 15; + + this.container.addChild(this.healthText); + this.container.addChild(this.goldText); + this.container.addChild(healthSprite); + this.container.addChild(goldSprite); + } + + public update() {} +} diff --git a/src/classes/game/Projectile.ts b/src/classes/game/Projectile.ts new file mode 100644 index 0000000..a0186eb --- /dev/null +++ b/src/classes/game/Projectile.ts @@ -0,0 +1,57 @@ +import * as PIXI from 'pixi.js'; +import GameObject from '../GameObject'; +import { Globals } from '../Bastion'; + +export function calculateAngleToPoint(x, y, targetX, targetY) { + const dx = targetX - x; + const dy = targetY - y; + return Math.atan2(dy, dx); +} + +export default class Projectile extends GameObject { + public sprite: PIXI.Sprite; + public x: number; + public y: number; + public angle: number; + public speed: number; + constructor(x, y, spriteTexture, angle) { + super(); + this.x = x; + this.y = y; + + this.sprite = new PIXI.Sprite({ texture: spriteTexture, scale: 0.5, rotation: angle }); + this.sprite.anchor.set(0.5); + this.container.x = this.x; + this.container.y = this.y; + this.container.addChild(this.sprite); + Globals.app.stage.addChild(this.container); + + this.angle = angle; + + this.speed = 0.9; + } + + public update(elapsedMS) { + if (this.x > 2000 || this.x < 0 || this.y > 2000 || this.y < 0) return this.destroy(); + this.x += Math.cos(this.angle) * this.speed * elapsedMS; + this.y += Math.sin(this.angle) * this.speed * elapsedMS; + + this.container.x = this.x; + this.container.y = this.y; + } + + public onCollide(otherSprite) { + console.log(`Collision detected with`, otherSprite); + } + + public checkCollision(otherSprite) { + const boundsA = this.sprite.getBounds(); + const boundsB = otherSprite.getBounds(); + return ( + boundsA.x < boundsB.x + boundsB.width && + boundsA.x + boundsA.width > boundsB.x && + boundsA.y < boundsB.y + boundsB.height && + boundsA.y + boundsA.height > boundsB.y + ); + } +} diff --git a/src/classes/game/Tower.ts b/src/classes/game/Tower.ts new file mode 100644 index 0000000..de989bd --- /dev/null +++ b/src/classes/game/Tower.ts @@ -0,0 +1,96 @@ +import { Globals } from '../Bastion'; +import * as PIXI from 'pixi.js'; +import GameObject from '../GameObject'; +import { TowerDefinition } from '../Definitions'; +import { Cell } from './Grid'; +import { TowerBehaviours } from './TowerManager'; +import Projectile, { calculateAngleToPoint } from './Projectile'; +import GameAssets from '../Assets'; +import Creep from './Creep'; + +function distance(x1, y1, x2, y2) { + return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); +} + +export type TowerInstance = { + row: number; + column: number; + sprite: PIXI.Sprite; + projectiles: Array; + baseDamage: number; + damage: number; + cooldown: number; + ticksToFireAt: number; + slottedGems: Array; + cost: number; + baseRange: number; + range: number; +}; + +export enum TowerEvents { + TowerPlacedEvent = 'towerPlacedEvent', +} + +export class Tower extends GameObject { + public row: number; + public column: number; + private projectiles: Projectile[] = []; + private behaviour: string; + private definition: TowerDefinition; + private sprite: PIXI.Sprite; + private graphics: PIXI.Graphics = new PIXI.Graphics(); + constructor(row, column, texture, definition, behaviour) { + super(); + this.row = row; + this.column = column; + this.behaviour = behaviour; + this.definition = definition; + let parent: Cell = Globals.Grid.getCellByRowAndCol(row, column); + this.sprite = new PIXI.Sprite({ + texture: texture, + height: 64, + width: 64, + zIndex: 10, + }); + this.container.addChild(this.sprite); + parent.container.addChild(this.container); + parent.clickDetector.onmouseenter = (e) => { + this.graphics.circle(this.column * 64 + 32, this.row * 64 + 32, this.definition.stats.range * 64); + this.graphics.fill({ color: 0xff0000, alpha: 0.5 }); + }; + parent.clickDetector.onmouseleave = (e) => { + this.graphics.clear(); + }; + Globals.app.stage.addChild(this.graphics); + } + public GetCreepsInRange() { + let creeps = Globals.Grid.creeps; + return creeps.filter((creep) => { + const x = creep.x; + const y = creep.y; + const towerX = this.column * 64 + 32; + const towerY = this.row * 64 + 32; + const radius = this.definition.stats.range * 64; + const d = distance(towerX, towerY, x, y); + return d < radius; + }); + } + public Shoot(creep: Creep) { + let x = this.column * 64 + 32; + let y = this.row * 64 + 32; + let angle = calculateAngleToPoint(x, y, creep.x, creep.y); + this.projectiles.push(new Projectile(x, y, GameAssets.BasicProjectileTexture, angle)); + } + public update(elapsedMS: any): void { + this.projectiles.forEach((proj) => { + proj.update(elapsedMS); + }); + if (this.behaviour == TowerBehaviours.BasicTowerBehaviour) { + let creepsInRange = this.GetCreepsInRange(); + if (creepsInRange.length > 0) { + let focus = creepsInRange[0]; + this.Shoot(focus); + } + } + } +} diff --git a/src/classes/game/TowerManager.ts b/src/classes/game/TowerManager.ts new file mode 100644 index 0000000..736e782 --- /dev/null +++ b/src/classes/game/TowerManager.ts @@ -0,0 +1,81 @@ +import * as PIXI from 'pixi.js'; +import { Globals } from '../Bastion'; +import { TerrainType, TowerDefinition } from '../Definitions'; +import GameAssets from '../Assets'; +import GameObject from '../GameObject'; +import { Tower, TowerEvents } from './Tower'; + +export enum TowerBehaviours { + BasicTowerBehaviour = 'BasicTowerBehaviour', +} + +export default class TowerManager { + public isPlacingTower: boolean = false; + public canPlaceTowers: boolean = true; + private selectedTower: TowerDefinition | null = null; + private towers: Tower[] = []; + constructor() { + Globals.TowerManager = this; + } + public ToggleChoosingTowerLocation(towerName: string) { + if (!this.canPlaceTowers) return; + Globals.Grid.toggleGrid(); + if (!this.isPlacingTower) { + GameAssets.Towers.forEach((item) => { + if (item.name == towerName) { + this.selectedTower = item; + } + }); + } else { + this.selectedTower = null; + } + this.isPlacingTower = !this.isPlacingTower; + } + public PlayerClickOnGrid(row, column) { + if (!this.canPlaceTowers) return; + if (this.isPlacingTower) { + if (!this.selectedTower) + throw console.warn('TowerManager.selectedTower is null when trying to place tower.'); + this.PlaceTower(this.selectedTower, row, column, this.selectedTower.behaviour); + } + } + public GetTowerByRowAndCol(row, col) { + // i just want to say that this is really stupid, why do i need to define a type for a local + // variable i will temporarily use? TS is weird + let returnTower: Tower | null = null; + this.towers.forEach((tower) => { + if (tower.row == row && tower.column == col) returnTower = tower; + }); + return returnTower; + } + public PlaceTower(definition: TowerDefinition, row, column, behaviour: string, ignoreCost?) { + let idx = 0; + GameAssets.Towers.forEach((item, index) => { + if (item.sprite == definition.sprite) idx = index; + }); + const sprite = GameAssets.TowerSprites[idx]; + if (!Globals.GameScene.MissionStats.hasEnoughGold(definition.stats.cost) && !ignoreCost) + return console.warn('Does not have enough gold.'); + if ( + !this.GetTowerByRowAndCol(row, column) && + Globals.Grid.getCellByRowAndCol(row, column).type != TerrainType.Path && + Globals.Grid.getCellByRowAndCol(row, column).type != TerrainType.Restricted + ) { + Globals.GameScene.MissionStats.spendGold(definition.stats.cost); + let tower = new Tower(row, column, sprite, definition, behaviour); + this.towers.push(tower); + this.ToggleChoosingTowerLocation('RESET'); + console.log('SHOULDVE PLACED TOWER'); + console.log(this.selectedTower); + this.selectedTower = null; + Globals.GameScene.events.emit(TowerEvents.TowerPlacedEvent, definition.name); + } else { + console.warn('Can not place tower on occupied spot or path. Try again.'); + } + } + public update(elapsedMS) { + this.towers.forEach((twr) => { + twr.update(elapsedMS); + }); + } +} diff --git a/src/classes/game/WaveManager.ts b/src/classes/game/WaveManager.ts new file mode 100644 index 0000000..9076b43 --- /dev/null +++ b/src/classes/game/WaveManager.ts @@ -0,0 +1,74 @@ +import { CreepType, MissionRoundDefinition, PathDefinition } from '../Definitions'; +import * as PIXI from 'pixi.js'; +import Creep, { CreepEvents } from './Creep'; +import { Globals } from '../Bastion'; + +export enum WaveManagerEvents { + CreepSpawned = 'creepSpawned', + Finished = 'finished', +} + +type CreepInstance = { + creep: Creep; + tickToSpawnAt: number; + spawned: boolean; +}; + +export default class WaveManager { + // Doesn't need to extend GameObject since it does not render + private creeps: CreepInstance[] = []; + private rounds: MissionRoundDefinition[]; + private paths: PathDefinition[]; + private ticks: number = 0; + private started: boolean = false; + public finished: boolean = false; + public events = new PIXI.EventEmitter(); + constructor(rounds: MissionRoundDefinition[], paths: PathDefinition[]) { + Globals.WaveManager = this; + this.rounds = rounds; + this.paths = paths; + } + public start(roundIndex) { + this.started = true; + this.ticks = 0; + this.creeps = []; + this.finished = false; + let tickToSpawnAt = 0; + this.rounds[roundIndex].waves.forEach((wave) => { + tickToSpawnAt += wave.firstCreepSpawnTick; + wave.creeps.forEach((creep) => { + const creepObj = new Creep(creep, this.paths[0]); + const creepInstance = { + creep: creepObj, + tickToSpawnAt, + spawned: false, + }; + console.log('CREAWTASEDASD'); + tickToSpawnAt += wave.spawnIntervalTicks; + this.creeps.push(creepInstance); + }); + }); + console.log(this.creeps); + } + public end() { + this.started = false; + } + public update(elapsedMS: number): void { + if (this.started == false) return; + this.ticks += elapsedMS; + this.creeps.forEach((creep) => { + if (!creep.spawned && creep.tickToSpawnAt <= this.ticks) { + creep.spawned = true; + this.events.emit(WaveManagerEvents.CreepSpawned, creep.creep); + console.log('Wave manager creep spawned, ', creep, this.ticks); + if (!this.finished && this.creeps.every((creep) => creep.spawned)) { + this.finished = true; + console.log('wave maanger finisehd'); + this.events.emit(WaveManagerEvents.Finished); + } + } else if (creep.spawned) { + creep.creep.update(elapsedMS); + } + }); + } +} diff --git a/src/classes/gui/Button.ts b/src/classes/gui/Button.ts new file mode 100644 index 0000000..bf2ce64 --- /dev/null +++ b/src/classes/gui/Button.ts @@ -0,0 +1,60 @@ +import * as PIXI from 'pixi.js'; +import GuiObject from '../GuiObject'; +import Assets from '../Assets'; + +export enum ButtonTexture { + Button01 = 0, + Button02 = 1, +} + +export default class Button extends GuiObject { + private caption: string; + private bounds: PIXI.Rectangle; + private buttonTexture: PIXI.Texture; + + private buttonSprite: PIXI.NineSliceSprite; + private buttonText: PIXI.Text; + + setCaption(caption: string) { + this.caption = caption; + this.buttonText.text = caption; + } + + constructor(bounds: PIXI.Rectangle, caption: string, buttonTexture: ButtonTexture, enabled: boolean = true) { + super(true); + if (buttonTexture == ButtonTexture.Button01) this.buttonTexture = Assets.Button01Texture; + if (buttonTexture == ButtonTexture.Button02) this.buttonTexture = Assets.Button02Texture; + this.caption = caption; + this.enabled = enabled; + this.bounds = bounds; + this.container.x = this.bounds.x; + this.container.y = this.bounds.y; + this.container.width = this.bounds.width; + this.container.height = this.bounds.height; + this.buttonSprite = new PIXI.NineSliceSprite({ + texture: this.buttonTexture, + leftWidth: 100, + topHeight: 100, + rightWidth: 100, + bottomHeight: 100, + }); + this.buttonSprite.x = 0; + this.buttonSprite.y = 0; + this.buttonSprite.width = this.bounds.width; + this.buttonSprite.height = this.bounds.height; + this.container.addChild(this.buttonSprite); + this.buttonText = new PIXI.Text({ + text: this.caption, + style: new PIXI.TextStyle({ + fill: 0xffffff, + fontSize: 24, + }), + }); + this.container.addChild(this.buttonText); + this.buttonText.anchor.set(0.5, 0.5); + this.buttonText.x = this.bounds.width / 2; + this.buttonText.y = this.bounds.height / 2; + this.container.x = this.bounds.x; + this.container.y = this.bounds.y; + } +} diff --git a/src/classes/gui/GemTab.ts b/src/classes/gui/GemTab.ts new file mode 100644 index 0000000..7673687 --- /dev/null +++ b/src/classes/gui/GemTab.ts @@ -0,0 +1,31 @@ +import * as PIXI from 'pixi.js'; +import GuiObject from '../GuiObject'; +import GameAssets from '../Assets'; + +export default class GemTab extends GuiObject { + private bounds: PIXI.Rectangle; + private gemTabSprite: PIXI.NineSliceSprite; + + constructor(bounds: PIXI.Rectangle) { + super(false); + this.bounds = bounds; + this.container.x = this.bounds.x; + this.container.y = this.bounds.y; + this.gemTabSprite = new PIXI.NineSliceSprite({ + texture: GameAssets.FrameTowerTab, + leftWidth: 1000, + topHeight: 1000, + rightWidth: 1000, + bottomHeight: 1000, + }); + // this.towerTabSprite = new PIXI.Sprite({ + // texture: GameAssets.FrameBackground, + // }); + this.gemTabSprite.x = 0; + this.gemTabSprite.y = 0; + this.gemTabSprite.width = this.bounds.width; + this.gemTabSprite.height = this.bounds.height; + + this.container.addChild(this.gemTabSprite); + } +} diff --git a/src/classes/gui/Sidebar.ts b/src/classes/gui/Sidebar.ts new file mode 100644 index 0000000..a0a89e6 --- /dev/null +++ b/src/classes/gui/Sidebar.ts @@ -0,0 +1,40 @@ +import * as PIXI from 'pixi.js'; +import GuiObject from '../GuiObject'; +import GameAssets from '../Assets'; +import TowerTab from './TowerTab'; +import GemTab from './GemTab'; + +export default class Sidebar extends GuiObject { + private bounds: PIXI.Rectangle; + private sidebarSprite: PIXI.NineSliceSprite; + private towerTab: TowerTab; + private gemTab: GemTab; + + constructor(bounds: PIXI.Rectangle) { + super(false); + this.bounds = bounds; + this.container.x = this.bounds.x; + this.container.y = this.bounds.y; + this.sidebarSprite = new PIXI.NineSliceSprite({ + texture: GameAssets.Frame01Texture, + leftWidth: 100, + topHeight: 100, + rightWidth: 100, + bottomHeight: 100, + }); + this.sidebarSprite.x = 40; + this.sidebarSprite.y = -40; + this.sidebarSprite.width = this.bounds.width + 40; + this.sidebarSprite.height = this.bounds.height + 80; + + this.container.addChild(this.sidebarSprite); + + const towerTabRect = new PIXI.Rectangle(60, 20, this.bounds.width - 65, 150); + this.towerTab = new TowerTab(towerTabRect); + this.container.addChild(this.towerTab.container); + + const gemTabRect = new PIXI.Rectangle(60, 180, this.bounds.width - 65, this.bounds.height - 280); + this.gemTab = new GemTab(gemTabRect); + this.container.addChild(this.gemTab.container); + } +} diff --git a/src/classes/gui/TowerTab.ts b/src/classes/gui/TowerTab.ts new file mode 100644 index 0000000..8513d79 --- /dev/null +++ b/src/classes/gui/TowerTab.ts @@ -0,0 +1,81 @@ +import * as PIXI from 'pixi.js'; +import GuiObject from '../GuiObject'; +import GameAssets from '../Assets'; +import { Globals } from '../Bastion'; +import { TowerEvents } from '../game/Tower'; + +class TowerButton extends GuiObject { + private frameSprite: PIXI.NineSliceSprite; + private background: PIXI.Sprite; + private towerName: string; + constructor(index: number, row, width, height, parent: PIXI.Container, backgroundTexture, towerName) { + if (index > 3 || row > 2 || index < 0 || row < 0) throw 'Index/row out of bounds for TowerButton.'; + super(true); + this.towerName = towerName; + this.container.x = index * width + 5; + this.container.y = row * height + 5; // 5 is padding, looks better + this.background = new PIXI.Sprite({ + texture: backgroundTexture, + }); + this.background.width = width; + this.background.height = height; + this.container.addChild(this.background); + + this.frameSprite = new PIXI.NineSliceSprite({ + texture: GameAssets.Frame02Texture, + leftWidth: 100, + topHeight: 100, + rightWidth: 100, + bottomHeight: 100, + roundPixels: true, + height: height, + width: width, + }); + this.container.addChild(this.frameSprite); + parent.addChild(this.container); + Globals.GameScene.events.on(TowerEvents.TowerPlacedEvent, (name) => { + this.frameSprite.tint = 0xffffff; // reset the tint after a tower has been placed + }); + this.container.onmouseenter = (e) => { + // add on mouse over info (banner next to sidebar) + }; + + this.container.onmouseleave = (e) => {}; + } + public onClick(e: PIXI.FederatedPointerEvent): void { + if (this.frameSprite.tint == 0x00ff00) this.frameSprite.tint = 0xffffff; + else this.frameSprite.tint = 0x00ff00; + Globals.TowerManager.ToggleChoosingTowerLocation(this.towerName); + } +} + +export default class TowerTab extends GuiObject { + private bounds: PIXI.Rectangle; + private towerTabSprite: PIXI.NineSliceSprite; + private towerList: Array = []; + + constructor(bounds: PIXI.Rectangle) { + super(false); + this.bounds = bounds; + GameAssets.Towers.forEach((twr) => { + let obj = { name: twr.name, description: twr.description, cost: twr.stats.cost }; + this.towerList.push(obj); + }); + this.container.x = this.bounds.x; + this.container.y = this.bounds.y; + this.towerTabSprite = new PIXI.NineSliceSprite({ + texture: GameAssets.FrameTowerTab, + leftWidth: 500, + topHeight: 500, + rightWidth: 500, + bottomHeight: 500, + roundPixels: true, + }); + this.towerTabSprite.width = this.bounds.width; + this.towerTabSprite.height = this.bounds.height; + this.container.addChild(this.towerTabSprite); + + new TowerButton(0, 0, 70, 70, this.container, GameAssets.RedBackground, 'Basic Tower'); + new TowerButton(0, 1, 70, 70, this.container, GameAssets.GreenBackground, 'Basic Tower'); + } +} diff --git a/src/main.ts b/src/main.ts index 5f5c14b..8d069ee 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,23 +1,57 @@ -import * as PIXI from "pixi.js"; -import Game from "./base/Game"; -import Assets from "./base/Assets"; -(async () => { - const app = new PIXI.Application(); - await app.init({ - width: 640, - height: 360, - resizeTo: document.body, - backgroundColor: "white", - sharedTicker: true, - preference: "webgl", - }); +import * as PIXI from 'pixi.js'; +import GameMaster, { Globals } from './classes/Bastion'; +import Assets from './classes/Assets'; +import { MainScene } from './scenes/Main'; +import { GameScene } from './scenes/Game'; - document.body.appendChild(app.canvas); - await Assets.LoadAssets(); - const game = new Game(app.screen); - app.stage.addChild(game.container); - window.addEventListener("resize", () => { - app.renderer.resize(window.innerWidth, window.innerHeight); - game.setBounds(0, 0, app.screen.width, app.screen.height); - }); +(async () => { + const app = new PIXI.Application(); + Globals.app = app; + await app.init({ + width: 1920, // Base width + height: 1080, // Base height + resolution: window.devicePixelRatio || 1, + autoDensity: true, + backgroundColor: 0xffffff, + sharedTicker: true, + }); + document.body.appendChild(app.canvas); + + function resize() { + const windowWidth = window.innerWidth; + const windowHeight = window.innerHeight; + Globals.WindowHeight = windowHeight; + Globals.WindowWidth = windowWidth; + + // Calculate scale factor to maintain aspect ratio + const scaleX = windowWidth / app.screen.width; + const scaleY = windowHeight / app.screen.height; + const scale = Math.min(scaleX, scaleY); // Use the smaller scale to fit + + // Calculate new canvas size + const gameWidth = Math.round(app.screen.width * scale); + const gameHeight = Math.round(app.screen.height * scale); + + // Center the canvas + const marginHorizontal = (windowWidth - gameWidth) / 2; + const marginVertical = (windowHeight - gameHeight) / 2; + + // Apply styles to canvas + app.canvas.style.width = `${gameWidth}px`; + app.canvas.style.height = `${gameHeight}px`; + app.canvas.style.marginLeft = `${marginHorizontal}px`; + app.canvas.style.marginTop = `${marginVertical}px`; + app.canvas.style.marginRight = `0`; // Prevent unnecessary margin + app.canvas.style.marginBottom = `0`; // Prevent unnecessary margin + app.canvas.style.display = 'block'; // Prevent inline-block spacing issues + } + + window.addEventListener('resize', resize); + resize(); + await Assets.LoadAssets(); + new GameMaster(); + globalThis.Globals = Globals; + Globals.GameMaster.changeScene(new MainScene()); + let params = new URLSearchParams(location.href); + if (params.entries().next().value[1] == 'game') Globals.GameMaster.changeScene(new GameScene('Mission 1')); })(); diff --git a/src/scenes/Game.ts b/src/scenes/Game.ts new file mode 100644 index 0000000..0a58e40 --- /dev/null +++ b/src/scenes/Game.ts @@ -0,0 +1,94 @@ +import GameAssets from '../classes/Assets'; +import { Globals } from '../classes/Bastion'; +import { MissionDefinition } from '../classes/Definitions'; +import Creep, { CreepEvents } from '../classes/game/Creep'; +import { Grid } from '../classes/game/Grid'; +import WaveManager, { WaveManagerEvents } from '../classes/game/WaveManager'; +import Sidebar from '../classes/gui/Sidebar'; +import Button, { ButtonTexture } from '../classes/gui/Button'; +import Scene from './Scene'; +import * as PIXI from 'pixi.js'; +import MissionStats from '../classes/game/MissionStats'; +import TowerManager from '../classes/game/TowerManager'; + +enum RoundMode { + Purchase = 0, + Combat = 1, +} + +export class GameScene extends Scene { + public mission: MissionDefinition; + public missionIndex: number; + public MissionStats: MissionStats; + public roundMode: RoundMode; + public ticker: PIXI.Ticker; + public changeRoundButton: Button; + public sidebar: Sidebar; + private currentRound: number = 0; + + constructor(name: string) { + super(); + Globals.GameScene = this; + GameAssets.Missions.forEach((mission, index) => { + if (mission.name == name) { + this.mission = mission; + this.missionIndex = index; + } + }); + } + public init() { + this.ticker = new PIXI.Ticker(); + this.ticker.maxFPS = 60; + this.ticker.minFPS = 30; + this.ticker.add(() => this.update(this.ticker.elapsedMS)); // bruh + this.ticker.start(); + const SidebarRect = new PIXI.Rectangle(64 * 30 - 360, 0, 360, Globals.app.canvas.height); + const changeRoundButtonRect = new PIXI.Rectangle(50, Globals.app.canvas.height - 100, 310, 100); + new Grid(this.mission.gameMap, this.missionIndex); + new TowerManager(); + new WaveManager(this.mission.rounds, this.mission.gameMap.paths); + Globals.Grid.onGridCellClicked = (row, column) => { + if (Globals.TowerManager.isPlacingTower) { + Globals.TowerManager.PlayerClickOnGrid(row, column); + } + }; + Globals.WaveManager.events.on(WaveManagerEvents.CreepSpawned, (creep: Creep) => { + Globals.Grid.addCreep(creep); + creep.events.on(CreepEvents.Escaped, () => { + this.onCreepEscaped(creep); + }); + }); + this.sidebar = new Sidebar(SidebarRect); + this.changeRoundButton = new Button(changeRoundButtonRect, 'Start', ButtonTexture.Button01, true); + this.changeRoundButton.container.removeFromParent(); + this.sidebar.container.addChild(this.changeRoundButton.container); + this.changeRoundButton.onClick = () => { + console.log('clicked'); + this.changeRoundButton.setEnabled(false); + this.changeRoundButton.setCaption('[X]'); + this.setRoundMode(RoundMode.Combat); + }; + + this.MissionStats = new MissionStats(100, 200); + } + public update(elapsedMS) { + Globals.WaveManager.update(elapsedMS); + Globals.Grid.update(elapsedMS); + Globals.TowerManager.update(elapsedMS); + } + + public onCreepEscaped(creep: Creep) { + this.MissionStats.takeDamage(creep.health); + } + + private setRoundMode(roundMode: RoundMode) { + this.roundMode = roundMode; + if (this.roundMode == RoundMode.Combat) { + Globals.WaveManager.start(this.currentRound); + } else { + Globals.WaveManager.end(); + } + } + + public onTowerPlaced() {} +} diff --git a/src/scenes/Main.ts b/src/scenes/Main.ts new file mode 100644 index 0000000..8087807 --- /dev/null +++ b/src/scenes/Main.ts @@ -0,0 +1,28 @@ +import { Globals } from '../classes/Bastion'; +import Button, { ButtonTexture } from '../classes/gui/Button'; +import { MissionPickerScene } from './MissionPicker'; +import Scene from './Scene'; +import * as PIXI from 'pixi.js'; + +export class MainScene extends Scene { + public init() { + const NewGameButton = { + caption: 'New Game', + rect: new PIXI.Rectangle(Globals.WindowWidth / 2 - 300 / 2, Globals.WindowHeight / 2 - 80, 300, 60), + texture: ButtonTexture.Button01, + }; + + const SettingsButton = { + caption: 'Settings', + rect: new PIXI.Rectangle(Globals.WindowWidth / 2 - 300 / 2, Globals.WindowHeight / 2 + 20, 300, 60), + texture: ButtonTexture.Button01, + }; + + const button01 = new Button(NewGameButton.rect, NewGameButton.caption, NewGameButton.texture, true); + button01.onClick = (e) => { + Globals.GameMaster.changeScene(new MissionPickerScene()); + }; + + new Button(SettingsButton.rect, SettingsButton.caption, SettingsButton.texture, true); + } +} diff --git a/src/scenes/MissionPicker.ts b/src/scenes/MissionPicker.ts new file mode 100644 index 0000000..c54b2f4 --- /dev/null +++ b/src/scenes/MissionPicker.ts @@ -0,0 +1,26 @@ +import Assets from '../classes/Assets'; +import { Globals } from '../classes/Bastion'; +import Button, { ButtonTexture } from '../classes/gui/Button'; +import { GameScene } from './Game'; +import Scene from './Scene'; +import * as PIXI from 'pixi.js'; + +export class MissionPickerScene extends Scene { + public init() { + Assets.Missions.forEach((mission, index) => { + const button = new Button( + new PIXI.Rectangle( + Globals.app.canvas.width / 2 - 300 / 2, + Globals.app.canvas.height / 5 + index * 80, + 300, + 60 + ), + mission.name, + ButtonTexture.Button01 + ); + button.onClick = (e) => { + Globals.GameMaster.changeScene(new GameScene(mission.name)); + }; + }); + } +} diff --git a/src/scenes/Scene.ts b/src/scenes/Scene.ts new file mode 100644 index 0000000..0aa3888 --- /dev/null +++ b/src/scenes/Scene.ts @@ -0,0 +1,27 @@ +import GuiObject from '../classes/GuiObject'; +import * as PIXI from 'pixi.js'; + +export default class Scene { + public gui: GuiObject[] = []; + private _events: PIXI.EventEmitter = new PIXI.EventEmitter(); + + public destroy() { + this.gui.forEach((element) => { + element.destroy(); + }); + } + public GetGuiObject(object: GuiObject) { + return this.gui.find((obj) => obj == object); + } + public GetGuiObjectByName(name: string) { + return this.gui.filter((obj) => obj.name == name); + } + + public get events(): PIXI.EventEmitter { + return this._events; + } + + public init() { + // Definitions for scene elements. + } +} diff --git a/tsconfig.json b/tsconfig.json index 5837dc5..cbbd5ac 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,23 +1,23 @@ { - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "skipLibCheck": true, + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "isolatedModules": true, - "moduleDetection": "force", - "noEmit": true, - "noImplicitAny": false, - "esModuleInterop": true, - "strict": false, - "allowJs": true, - "checkJs": false - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "build"] + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "noImplicitAny": false, + "esModuleInterop": true, + "strict": false, + "allowJs": true, + "checkJs": false + }, + "include": ["bsrc/**/*"], + "exclude": ["node_modules", "build"] }