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 @@
+
+
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"]
}