Compare commits

..

23 Commits

Author SHA1 Message Date
175d7c6199 Added overlay on portrait screens to force switching to landscape
(Needs better styling/design)
2025-01-22 22:36:08 +01:00
41005735f9 Added version to dexie base class 2025-01-22 20:34:16 +01:00
78f1c6e6a0 Added font to loading text 2025-01-22 00:36:00 +01:00
2d48f83802 Load tiles before showing map editor UI 2025-01-22 00:31:14 +01:00
7dccb73698 TS improvement 2025-01-21 23:38:42 +01:00
7171112881 Moved effects.vue into map folder 2025-01-21 23:33:56 +01:00
9a601b7e2e Wait for map load before loading effects
Both command and mapSettings effects work again
2025-01-21 19:59:40 +01:00
5c68b02fff Removed redundant const 2025-01-19 00:06:36 +01:00
b86d9dd4ce Half working effects
Command triggered effects still brokey
2025-01-19 00:03:08 +01:00
93baa10acf Improvements 2025-01-14 02:39:41 +01:00
419cf319be TS fix 2025-01-14 02:17:35 +01:00
1cd7f28402 Removed debugging code 2025-01-13 15:02:53 +01:00
0657dbcb1b Tiny improvements 2025-01-13 14:51:28 +01:00
5cf7423a5c PlacedMapObjects.vue refactor for map 2025-01-13 11:40:41 +01:00
4d88917526 Loading placed map objects works again 2025-01-13 11:02:04 +01:00
8f07cf5093 Map editor tiles are now fully loaded from cache 2025-01-13 10:52:40 +01:00
367d536c52 more shit 2025-01-12 22:11:33 +01:00
3f8c911e9d Clean up 2025-01-12 20:54:59 +01:00
689e443b3d . 2025-01-12 03:24:31 +01:00
4fead371d7 sprite shit 2025-01-11 21:48:08 +01:00
b9bcfc719f Merge remote-tracking branch 'origin/feature/cache' 2025-01-10 23:23:00 +01:00
2b84bfcad2 #305 - Made all list types full height 2025-01-07 21:00:26 +01:00
f829cfb883 #309 - Removed mobile hidden styling from inner ui box 2025-01-07 20:20:52 +01:00
48 changed files with 425 additions and 404 deletions

290
package-lock.json generated
View File

@ -62,9 +62,9 @@
} }
}, },
"node_modules/@asamuzakjp/css-color": { "node_modules/@asamuzakjp/css-color": {
"version": "2.8.2", "version": "2.8.3",
"resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-2.8.2.tgz", "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-2.8.3.tgz",
"integrity": "sha512-RtWv9jFN2/bLExuZgFFZ0I3pWWeezAHGgrmjqGGWclATl1aDe3yhCUaI0Ilkp6OCk9zX7+FjvDasEX8Q9Rxc5w==", "integrity": "sha512-GIc76d9UI1hCvOATjZPyHFmE5qhRccp3/zGfMPapK3jBi+yocEzp6BBB0UnfRYP9NP4FANqUZYb0hnfs3TM3hw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -72,7 +72,7 @@
"@csstools/css-color-parser": "^3.0.7", "@csstools/css-color-parser": "^3.0.7",
"@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-parser-algorithms": "^3.0.4",
"@csstools/css-tokenizer": "^3.0.3", "@csstools/css-tokenizer": "^3.0.3",
"lru-cache": "^11.0.2" "lru-cache": "^10.4.3"
} }
}, },
"node_modules/@babel/code-frame": { "node_modules/@babel/code-frame": {
@ -91,14 +91,14 @@
} }
}, },
"node_modules/@babel/generator": { "node_modules/@babel/generator": {
"version": "7.26.3", "version": "7.26.5",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.3.tgz", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.5.tgz",
"integrity": "sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==", "integrity": "sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/parser": "^7.26.3", "@babel/parser": "^7.26.5",
"@babel/types": "^7.26.3", "@babel/types": "^7.26.5",
"@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25", "@jridgewell/trace-mapping": "^0.3.25",
"jsesc": "^3.0.2" "jsesc": "^3.0.2"
@ -126,12 +126,12 @@
} }
}, },
"node_modules/@babel/parser": { "node_modules/@babel/parser": {
"version": "7.26.3", "version": "7.26.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.5.tgz",
"integrity": "sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==", "integrity": "sha512-SRJ4jYmXRqV1/Xc+TIVG84WjHBXKlxO9sHQnA2Pf12QQEAp1LOh6kDzNHXcUnbH1QI0FDoPPVOt+vyUDucxpaw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/types": "^7.26.3" "@babel/types": "^7.26.5"
}, },
"bin": { "bin": {
"parser": "bin/babel-parser.js" "parser": "bin/babel-parser.js"
@ -169,17 +169,17 @@
} }
}, },
"node_modules/@babel/traverse": { "node_modules/@babel/traverse": {
"version": "7.26.4", "version": "7.26.5",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.4.tgz", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.5.tgz",
"integrity": "sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==", "integrity": "sha512-rkOSPOw+AXbgtwUga3U4u8RpoK9FEFWBNAlTpcnkLFjL5CT+oyHNuUUC/xx6XefEJ16r38r8Bc/lfp6rYuHeJQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.26.2", "@babel/code-frame": "^7.26.2",
"@babel/generator": "^7.26.3", "@babel/generator": "^7.26.5",
"@babel/parser": "^7.26.3", "@babel/parser": "^7.26.5",
"@babel/template": "^7.25.9", "@babel/template": "^7.25.9",
"@babel/types": "^7.26.3", "@babel/types": "^7.26.5",
"debug": "^4.3.1", "debug": "^4.3.1",
"globals": "^11.1.0" "globals": "^11.1.0"
}, },
@ -188,9 +188,9 @@
} }
}, },
"node_modules/@babel/types": { "node_modules/@babel/types": {
"version": "7.26.3", "version": "7.26.5",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.5.tgz",
"integrity": "sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==", "integrity": "sha512-L6mZmwFDK6Cjh1nRCLXpa6no13ZIioJDz7mdkzHv399pThrTa/k0nUlNaenOeh2kWu/iaOQYElEpKPUswUa9Vg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-string-parser": "^7.25.9", "@babel/helper-string-parser": "^7.25.9",
@ -872,9 +872,9 @@
"license": "BSD-3-Clause" "license": "BSD-3-Clause"
}, },
"node_modules/@ianvs/prettier-plugin-sort-imports": { "node_modules/@ianvs/prettier-plugin-sort-imports": {
"version": "4.4.0", "version": "4.4.1",
"resolved": "https://registry.npmjs.org/@ianvs/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.4.0.tgz", "resolved": "https://registry.npmjs.org/@ianvs/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.4.1.tgz",
"integrity": "sha512-f4/e+/ANGk3tHuwRW0uh2YuBR50I4h1ZjGQ+5uD8sWfinHTivQsnieR5cz24t8M6Vx4rYvZ5v/IEKZhYpzQm9Q==", "integrity": "sha512-F0/Hrcfpy8WuxlQyAWJTEren/uxKhYonOGY4OyWmwRdeTvkh9mMSCxowZLjNkhwi/2ipqCgtXwwOk7tW0mWXkA==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
@ -1373,9 +1373,9 @@
} }
}, },
"node_modules/@rollup/rollup-android-arm-eabi": { "node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.30.1", "version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.31.0.tgz",
"integrity": "sha512-pSWY+EVt3rJ9fQ3IqlrEUtXh3cGqGtPDH1FQlNZehO2yYxCHEX1SPsz1M//NXwYfbTlcKr9WObLnJX9FsS9K1Q==", "integrity": "sha512-9NrR4033uCbUBRgvLcBrJofa2KY9DzxL2UKZ1/4xA/mnTNyhZCWBuD8X3tPm1n4KxcgaraOYgrFKSgwjASfmlA==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -1387,9 +1387,9 @@
] ]
}, },
"node_modules/@rollup/rollup-android-arm64": { "node_modules/@rollup/rollup-android-arm64": {
"version": "4.30.1", "version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.31.0.tgz",
"integrity": "sha512-/NA2qXxE3D/BRjOJM8wQblmArQq1YoBVJjrjoTSBS09jgUisq7bqxNHJ8kjCHeV21W/9WDGwJEWSN0KQ2mtD/w==", "integrity": "sha512-iBbODqT86YBFHajxxF8ebj2hwKm1k8PTBQSojSt3d1FFt1gN+xf4CowE47iN0vOSdnd+5ierMHBbu/rHc7nq5g==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -1401,9 +1401,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-arm64": { "node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.30.1", "version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.31.0.tgz",
"integrity": "sha512-r7FQIXD7gB0WJ5mokTUgUWPl0eYIH0wnxqeSAhuIwvnnpjdVB8cRRClyKLQr7lgzjctkbp5KmswWszlwYln03Q==", "integrity": "sha512-WHIZfXgVBX30SWuTMhlHPXTyN20AXrLH4TEeH/D0Bolvx9PjgZnn4H677PlSGvU6MKNsjCQJYczkpvBbrBnG6g==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -1415,9 +1415,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-x64": { "node_modules/@rollup/rollup-darwin-x64": {
"version": "4.30.1", "version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.31.0.tgz",
"integrity": "sha512-x78BavIwSH6sqfP2xeI1hd1GpHL8J4W2BXcVM/5KYKoAD3nNsfitQhvWSw+TFtQTLZ9OmlF+FEInEHyubut2OA==", "integrity": "sha512-hrWL7uQacTEF8gdrQAqcDy9xllQ0w0zuL1wk1HV8wKGSGbKPVjVUv/DEwT2+Asabf8Dh/As+IvfdU+H8hhzrQQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -1429,9 +1429,9 @@
] ]
}, },
"node_modules/@rollup/rollup-freebsd-arm64": { "node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.30.1", "version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.31.0.tgz",
"integrity": "sha512-HYTlUAjbO1z8ywxsDFWADfTRfTIIy/oUlfIDmlHYmjUP2QRDTzBuWXc9O4CXM+bo9qfiCclmHk1x4ogBjOUpUQ==", "integrity": "sha512-S2oCsZ4hJviG1QjPY1h6sVJLBI6ekBeAEssYKad1soRFv3SocsQCzX6cwnk6fID6UQQACTjeIMB+hyYrFacRew==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -1443,9 +1443,9 @@
] ]
}, },
"node_modules/@rollup/rollup-freebsd-x64": { "node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.30.1", "version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.31.0.tgz",
"integrity": "sha512-1MEdGqogQLccphhX5myCJqeGNYTNcmTyaic9S7CG3JhwuIByJ7J05vGbZxsizQthP1xpVx7kd3o31eOogfEirw==", "integrity": "sha512-pCANqpynRS4Jirn4IKZH4tnm2+2CqCNLKD7gAdEjzdLGbH1iO0zouHz4mxqg0uEMpO030ejJ0aA6e1PJo2xrPA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -1457,9 +1457,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-gnueabihf": { "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.30.1", "version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.31.0.tgz",
"integrity": "sha512-PaMRNBSqCx7K3Wc9QZkFx5+CX27WFpAMxJNiYGAXfmMIKC7jstlr32UhTgK6T07OtqR+wYlWm9IxzennjnvdJg==", "integrity": "sha512-0O8ViX+QcBd3ZmGlcFTnYXZKGbFu09EhgD27tgTdGnkcYXLat4KIsBBQeKLR2xZDCXdIBAlWLkiXE1+rJpCxFw==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -1471,9 +1471,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-musleabihf": { "node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.30.1", "version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.31.0.tgz",
"integrity": "sha512-B8Rcyj9AV7ZlEFqvB5BubG5iO6ANDsRKlhIxySXcF1axXYUyqwBok+XZPgIYGBgs7LDXfWfifxhw0Ik57T0Yug==", "integrity": "sha512-w5IzG0wTVv7B0/SwDnMYmbr2uERQp999q8FMkKG1I+j8hpPX2BYFjWe69xbhbP6J9h2gId/7ogesl9hwblFwwg==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -1485,9 +1485,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-gnu": { "node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.30.1", "version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.31.0.tgz",
"integrity": "sha512-hqVyueGxAj3cBKrAI4aFHLV+h0Lv5VgWZs9CUGqr1z0fZtlADVV1YPOij6AhcK5An33EXaxnDLmJdQikcn5NEw==", "integrity": "sha512-JyFFshbN5xwy6fulZ8B/8qOqENRmDdEkcIMF0Zz+RsfamEW+Zabl5jAb0IozP/8UKnJ7g2FtZZPEUIAlUSX8cA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -1499,9 +1499,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-musl": { "node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.30.1", "version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.31.0.tgz",
"integrity": "sha512-i4Ab2vnvS1AE1PyOIGp2kXni69gU2DAUVt6FSXeIqUCPIR3ZlheMW3oP2JkukDfu3PsexYRbOiJrY+yVNSk9oA==", "integrity": "sha512-kpQXQ0UPFeMPmPYksiBL9WS/BDiQEjRGMfklVIsA0Sng347H8W2iexch+IEwaR7OVSKtr2ZFxggt11zVIlZ25g==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -1513,9 +1513,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-loongarch64-gnu": { "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
"version": "4.30.1", "version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.31.0.tgz",
"integrity": "sha512-fARcF5g296snX0oLGkVxPmysetwUk2zmHcca+e9ObOovBR++9ZPOhqFUM61UUZ2EYpXVPN1redgqVoBB34nTpQ==", "integrity": "sha512-pMlxLjt60iQTzt9iBb3jZphFIl55a70wexvo8p+vVFK+7ifTRookdoXX3bOsRdmfD+OKnMozKO6XM4zR0sHRrQ==",
"cpu": [ "cpu": [
"loong64" "loong64"
], ],
@ -1527,9 +1527,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": { "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.30.1", "version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.31.0.tgz",
"integrity": "sha512-GLrZraoO3wVT4uFXh67ElpwQY0DIygxdv0BNW9Hkm3X34wu+BkqrDrkcsIapAY+N2ATEbvak0XQ9gxZtCIA5Rw==", "integrity": "sha512-D7TXT7I/uKEuWiRkEFbed1UUYZwcJDU4vZQdPTcepK7ecPhzKOYk4Er2YR4uHKme4qDeIh6N3XrLfpuM7vzRWQ==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@ -1541,9 +1541,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-riscv64-gnu": { "node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.30.1", "version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.31.0.tgz",
"integrity": "sha512-0WKLaAUUHKBtll0wvOmh6yh3S0wSU9+yas923JIChfxOaaBarmb/lBKPF0w/+jTVozFnOXJeRGZ8NvOxvk/jcw==", "integrity": "sha512-wal2Tc8O5lMBtoePLBYRKj2CImUCJ4UNGJlLwspx7QApYny7K1cUYlzQ/4IGQBLmm+y0RS7dwc3TDO/pmcneTw==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@ -1555,9 +1555,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-s390x-gnu": { "node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.30.1", "version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.31.0.tgz",
"integrity": "sha512-GWFs97Ruxo5Bt+cvVTQkOJ6TIx0xJDD/bMAOXWJg8TCSTEK8RnFeOeiFTxKniTc4vMIaWvCplMAFBt9miGxgkA==", "integrity": "sha512-O1o5EUI0+RRMkK9wiTVpk2tyzXdXefHtRTIjBbmFREmNMy7pFeYXCFGbhKFwISA3UOExlo5GGUuuj3oMKdK6JQ==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@ -1569,9 +1569,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-gnu": { "node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.30.1", "version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.31.0.tgz",
"integrity": "sha512-UtgGb7QGgXDIO+tqqJ5oZRGHsDLO8SlpE4MhqpY9Llpzi5rJMvrK6ZGhsRCST2abZdBqIBeXW6WPD5fGK5SDwg==", "integrity": "sha512-zSoHl356vKnNxwOWnLd60ixHNPRBglxpv2g7q0Cd3Pmr561gf0HiAcUBRL3S1vPqRC17Zo2CX/9cPkqTIiai1g==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -1583,9 +1583,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-musl": { "node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.30.1", "version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.31.0.tgz",
"integrity": "sha512-V9U8Ey2UqmQsBT+xTOeMzPzwDzyXmnAoO4edZhL7INkwQcaW1Ckv3WJX3qrrp/VHaDkEWIBWhRwP47r8cdrOow==", "integrity": "sha512-ypB/HMtcSGhKUQNiFwqgdclWNRrAYDH8iMYH4etw/ZlGwiTVxBz2tDrGRrPlfZu6QjXwtd+C3Zib5pFqID97ZA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -1597,9 +1597,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-arm64-msvc": { "node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.30.1", "version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.31.0.tgz",
"integrity": "sha512-WabtHWiPaFF47W3PkHnjbmWawnX/aE57K47ZDT1BXTS5GgrBUEpvOzq0FI0V/UYzQJgdb8XlhVNH8/fwV8xDjw==", "integrity": "sha512-JuhN2xdI/m8Hr+aVO3vspO7OQfUFO6bKLIRTAy0U15vmWjnZDLrEgCZ2s6+scAYaQVpYSh9tZtRijApw9IXyMw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -1611,9 +1611,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-ia32-msvc": { "node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.30.1", "version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.31.0.tgz",
"integrity": "sha512-pxHAU+Zv39hLUTdQQHUVHf4P+0C47y/ZloorHpzs2SXMRqeAWmGghzAhfOlzFHHwjvgokdFAhC4V+6kC1lRRfw==", "integrity": "sha512-U1xZZXYkvdf5MIWmftU8wrM5PPXzyaY1nGCI4KI4BFfoZxHamsIe+BtnPLIvvPykvQWlVbqUXdLa4aJUuilwLQ==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@ -1625,9 +1625,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-x64-msvc": { "node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.30.1", "version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.30.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.31.0.tgz",
"integrity": "sha512-D6qjsXGcvhTjv0kI4fU8tUuBDF/Ueee4SVX79VfNDXZa64TfCW1Slkb6Z7O1p7vflqZjcmOVdZlqf8gvJxc6og==", "integrity": "sha512-ul8rnCsUumNln5YWwz0ted2ZHFhzhRRnkpBZ+YRuHoRAlUji9KChpOUOndY7uykrPEPXVbHLlsdo6v5yXo/TXw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -1684,9 +1684,9 @@
} }
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "20.17.12", "version": "20.17.14",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.12.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.14.tgz",
"integrity": "sha512-vo/wmBgMIiEA23A/knMfn/cf37VnuF52nZh5ZoW0GWt4e4sxNquibrMRJ7UQsA06+MBx9r/H1jsI9grYjQCQlw==", "integrity": "sha512-w6qdYetNL5KRBiSClK/KWai+2IMEJuAj+EujKCumalFOwXtvOXaEan9AuwcRID2IcOIAWSIfR495hBtgKlx2zg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -2678,9 +2678,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001692", "version": "1.0.30001695",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001692.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001695.tgz",
"integrity": "sha512-A95VKan0kdtrsnMubMKxEKUKImOPSuCpYgxSQBo036P5YYgVIcOYJEgt/txJWqObiRQeISNCfef9nvlQ0vbV7A==", "integrity": "sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@ -2997,9 +2997,9 @@
} }
}, },
"node_modules/dexie": { "node_modules/dexie": {
"version": "4.0.10", "version": "4.0.11",
"resolved": "https://registry.npmjs.org/dexie/-/dexie-4.0.10.tgz", "resolved": "https://registry.npmjs.org/dexie/-/dexie-4.0.11.tgz",
"integrity": "sha512-eM2RzuR3i+M046r2Q0Optl3pS31qTWf8aFuA7H9wnsHTwl8EPvroVLwvQene/6paAs39Tbk6fWZcn2aZaHkc/w==", "integrity": "sha512-SOKO002EqlvBYYKQSew3iymBoN2EQ4BDw/3yprjh7kAfFzjBYkaMNa/pZvcA7HSWlcKSQb9XhPe3wKyQ0x4A8A==",
"license": "Apache-2.0" "license": "Apache-2.0"
}, },
"node_modules/didyoumean": { "node_modules/didyoumean": {
@ -3085,9 +3085,9 @@
} }
}, },
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.5.80", "version": "1.5.84",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.80.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.84.tgz",
"integrity": "sha512-LTrKpW0AqIuHwmlVNV+cjFYTnXtM9K37OGhpe0ZI10ScPSxqVSryZHIY3WnCS5NSYbBODRTZyhRMS2h5FAEqAw==", "integrity": "sha512-I+DQ8xgafao9Ha6y0qjHHvpZ9OfyA1qKlkHkjywxzniORU2awxyz7f/iVJcULmrF2yrM3nHQf+iDjJtbbexd/g==",
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
@ -3310,9 +3310,9 @@
} }
}, },
"node_modules/eslint-plugin-prettier": { "node_modules/eslint-plugin-prettier": {
"version": "5.2.1", "version": "5.2.3",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.3.tgz",
"integrity": "sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==", "integrity": "sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -4480,14 +4480,11 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/lru-cache": { "node_modules/lru-cache": {
"version": "11.0.2", "version": "10.4.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.2.tgz", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
"integrity": "sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
"dev": true, "dev": true,
"license": "ISC", "license": "ISC"
"engines": {
"node": "20 || >=22"
}
}, },
"node_modules/magic-string": { "node_modules/magic-string": {
"version": "0.30.17", "version": "0.30.17",
@ -5009,13 +5006,6 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/path-scurry/node_modules/lru-cache": {
"version": "10.4.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
"dev": true,
"license": "ISC"
},
"node_modules/path-type": { "node_modules/path-type": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
@ -5131,9 +5121,9 @@
} }
}, },
"node_modules/pinia": { "node_modules/pinia": {
"version": "2.3.0", "version": "2.3.1",
"resolved": "https://registry.npmjs.org/pinia/-/pinia-2.3.0.tgz", "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.3.1.tgz",
"integrity": "sha512-ohZj3jla0LL0OH5PlLTDMzqKiVw2XARmC1XYLdLWIPBMdhDW/123ZWr4zVAhtJm+aoSkFa13pYXskAvAscIkhQ==", "integrity": "sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vue/devtools-api": "^6.6.3", "@vue/devtools-api": "^6.6.3",
@ -5163,9 +5153,9 @@
} }
}, },
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.4.49", "version": "8.5.1",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz",
"integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", "integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@ -5182,7 +5172,7 @@
], ],
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"nanoid": "^3.3.7", "nanoid": "^3.3.8",
"picocolors": "^1.1.1", "picocolors": "^1.1.1",
"source-map-js": "^1.2.1" "source-map-js": "^1.2.1"
}, },
@ -5439,13 +5429,13 @@
} }
}, },
"node_modules/readdirp": { "node_modules/readdirp": {
"version": "4.0.2", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.1.tgz",
"integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", "integrity": "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 14.16.0" "node": ">= 14.18.0"
}, },
"funding": { "funding": {
"type": "individual", "type": "individual",
@ -5572,9 +5562,9 @@
} }
}, },
"node_modules/rollup": { "node_modules/rollup": {
"version": "4.30.1", "version": "4.31.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.30.1.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.31.0.tgz",
"integrity": "sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w==", "integrity": "sha512-9cCE8P4rZLx9+PjoyqHLs31V9a9Vpvfo4qNcs6JCiGWYhw2gijSetFbH6SSy1whnkgcefnUwr8sad7tgqsGvnw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -5588,25 +5578,25 @@
"npm": ">=8.0.0" "npm": ">=8.0.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.30.1", "@rollup/rollup-android-arm-eabi": "4.31.0",
"@rollup/rollup-android-arm64": "4.30.1", "@rollup/rollup-android-arm64": "4.31.0",
"@rollup/rollup-darwin-arm64": "4.30.1", "@rollup/rollup-darwin-arm64": "4.31.0",
"@rollup/rollup-darwin-x64": "4.30.1", "@rollup/rollup-darwin-x64": "4.31.0",
"@rollup/rollup-freebsd-arm64": "4.30.1", "@rollup/rollup-freebsd-arm64": "4.31.0",
"@rollup/rollup-freebsd-x64": "4.30.1", "@rollup/rollup-freebsd-x64": "4.31.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.30.1", "@rollup/rollup-linux-arm-gnueabihf": "4.31.0",
"@rollup/rollup-linux-arm-musleabihf": "4.30.1", "@rollup/rollup-linux-arm-musleabihf": "4.31.0",
"@rollup/rollup-linux-arm64-gnu": "4.30.1", "@rollup/rollup-linux-arm64-gnu": "4.31.0",
"@rollup/rollup-linux-arm64-musl": "4.30.1", "@rollup/rollup-linux-arm64-musl": "4.31.0",
"@rollup/rollup-linux-loongarch64-gnu": "4.30.1", "@rollup/rollup-linux-loongarch64-gnu": "4.31.0",
"@rollup/rollup-linux-powerpc64le-gnu": "4.30.1", "@rollup/rollup-linux-powerpc64le-gnu": "4.31.0",
"@rollup/rollup-linux-riscv64-gnu": "4.30.1", "@rollup/rollup-linux-riscv64-gnu": "4.31.0",
"@rollup/rollup-linux-s390x-gnu": "4.30.1", "@rollup/rollup-linux-s390x-gnu": "4.31.0",
"@rollup/rollup-linux-x64-gnu": "4.30.1", "@rollup/rollup-linux-x64-gnu": "4.31.0",
"@rollup/rollup-linux-x64-musl": "4.30.1", "@rollup/rollup-linux-x64-musl": "4.31.0",
"@rollup/rollup-win32-arm64-msvc": "4.30.1", "@rollup/rollup-win32-arm64-msvc": "4.31.0",
"@rollup/rollup-win32-ia32-msvc": "4.30.1", "@rollup/rollup-win32-ia32-msvc": "4.31.0",
"@rollup/rollup-win32-x64-msvc": "4.30.1", "@rollup/rollup-win32-x64-msvc": "4.31.0",
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },
@ -5649,9 +5639,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/sass": { "node_modules/sass": {
"version": "1.83.1", "version": "1.83.4",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.83.1.tgz", "resolved": "https://registry.npmjs.org/sass/-/sass-1.83.4.tgz",
"integrity": "sha512-EVJbDaEs4Rr3F0glJzFSOvtg2/oy2V/YrGFPqPY24UqcLDWcI9ZY5sN+qyO3c/QCZwzgfirvhXvINiJCE/OLcA==", "integrity": "sha512-B1bozCeNQiOgDcLd33e2Cs2U60wZwjUUXzh900ZyQF5qUasvMdDZYbQ566LJu7cqR+sAHlAfO6RMkaID5s6qpA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -6398,9 +6388,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "5.4.11", "version": "5.4.14",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.14.tgz",
"integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", "integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {

View File

@ -18,7 +18,7 @@ import Debug from '@/components/utilities/Debug.vue'
import Notifications from '@/components/utilities/Notifications.vue' import Notifications from '@/components/utilities/Notifications.vue'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useMapEditorStore } from '@/stores/mapEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import { computed, onMounted, onUnmounted, watch } from 'vue' import { computed, watch } from 'vue'
const gameStore = useGameStore() const gameStore = useGameStore()
const mapEditorStore = useMapEditorStore() const mapEditorStore = useMapEditorStore()
@ -57,7 +57,9 @@ addEventListener('keydown', (event) => {
if (gameStore.character?.role !== 'gm') return // Only allow toggling the gm panel if the character is a gm if (gameStore.character?.role !== 'gm') return // Only allow toggling the gm panel if the character is a gm
// Check if no input is active or focus is on an input // Check if no input is active or focus is on an input
if (event.repeat || event.isComposing || event.defaultPrevented || document.activeElement?.tagName.toUpperCase() === 'INPUT' || document.activeElement?.tagName.toUpperCase() === 'TEXTAREA') return if (event.repeat || event.isComposing || event.defaultPrevented || document.activeElement?.tagName.toUpperCase() === 'INPUT' || document.activeElement?.tagName.toUpperCase() === 'TEXTAREA') {
return
}
if (event.key === 'G') { if (event.key === 'G') {
gameStore.toggleGmPanel() gameStore.toggleGmPanel()

View File

@ -31,6 +31,12 @@ body {
@apply outline-offset-2; @apply outline-offset-2;
@apply rounded-sm; @apply rounded-sm;
} }
@media only screen and (orientation:portrait) and (max-width: 768px) {
.portrait-mode-notice {
@apply block;
}
}
} }
h1, h1,

View File

@ -2,16 +2,13 @@
<ChatBubble :mapCharacter="props.mapCharacter" :currentX="currentPositionX" :currentY="currentPositionY" /> <ChatBubble :mapCharacter="props.mapCharacter" :currentX="currentPositionX" :currentY="currentPositionY" />
<Healthbar :mapCharacter="props.mapCharacter" :currentX="currentPositionX" :currentY="currentPositionY" /> <Healthbar :mapCharacter="props.mapCharacter" :currentX="currentPositionX" :currentY="currentPositionY" />
<Container ref="charContainer" :depth="isometricDepth" :x="currentPositionX" :y="currentPositionY"> <Container ref="charContainer" :depth="isometricDepth" :x="currentPositionX" :y="currentPositionY">
<!-- <CharacterHair :mapCharacter="props.mapCharacter" :currentX="currentX" :currentY="currentY" />-->
<!-- <CharacterChest :mapCharacter="props.mapCharacter" :currentX="currentX" :currentY="currentY" />-->
<Sprite ref="charSprite" :origin-y="1" :flipX="isFlippedX" /> <Sprite ref="charSprite" :origin-y="1" :flipX="isFlippedX" />
</Container> </Container>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import config from '@/application/config' import config from '@/application/config'
import { type MapCharacter, type Sprite as SpriteT } from '@/application/types' import { type MapCharacter } from '@/application/types'
import CharacterHair from '@/components/game/character/partials/CharacterHair.vue'
import ChatBubble from '@/components/game/character/partials/ChatBubble.vue' import ChatBubble from '@/components/game/character/partials/ChatBubble.vue'
import Healthbar from '@/components/game/character/partials/Healthbar.vue' import Healthbar from '@/components/game/character/partials/Healthbar.vue'
import { loadSpriteTextures } from '@/composables/gameComposable' import { loadSpriteTextures } from '@/composables/gameComposable'
@ -22,8 +19,6 @@ import { useMapStore } from '@/stores/mapStore'
import { Container, refObj, Sprite, useScene } from 'phavuer' import { Container, refObj, Sprite, useScene } from 'phavuer'
import { computed, onMounted, onUnmounted, ref, watch } from 'vue' import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
// import CharacterChest from '@/components/game/character/partials/CharacterChest.vue'
enum Direction { enum Direction {
POSITIVE, POSITIVE,
NEGATIVE, NEGATIVE,
@ -151,21 +146,19 @@ watch(
} }
) )
const characterTypeStorage = new CharacterTypeStorage() onMounted(async () => {
characterTypeStorage.getSpriteId(props.mapCharacter.character.characterType!).then((spriteId) => { const characterTypeStorage = new CharacterTypeStorage()
console.log(spriteId)
charSpriteId.value = spriteId const spriteId = await characterTypeStorage.getSpriteId(props.mapCharacter.character.characterType!)
loadSpriteTextures(scene, spriteId) if (!spriteId) return
.then(() => {
charSprite.value!.setTexture(charTexture.value) charSpriteId.value = spriteId
charSprite.value!.setFlipX(isFlippedX.value)
}) await loadSpriteTextures(scene, spriteId)
.catch((error) => {
console.error('Error loading texture:', error) charSprite.value!.setTexture(charTexture.value)
}) charSprite.value!.setFlipX(isFlippedX.value)
})
onMounted(() => {
charContainer.value!.setName(props.mapCharacter.character!.name) charContainer.value!.setName(props.mapCharacter.character!.name)
if (props.mapCharacter.character.id === gameStore.character!.id) { if (props.mapCharacter.character.id === gameStore.character!.id) {

View File

@ -30,10 +30,10 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import CharacterScreen from '@/components/gui/partials/CharacterScreen.vue' import CharacterScreen from '@/components/game/gui/partials/CharacterScreen.vue'
import Equipment from '@/components/gui/partials/Equipment.vue' import Equipment from '@/components/game/gui/partials/Equipment.vue'
import Inventory from '@/components/gui/partials/Inventory.vue' import Inventory from '@/components/game/gui/partials/Inventory.vue'
import Settings from '@/components/gui/partials/Settings.vue' import Settings from '@/components/game/gui/partials/Settings.vue'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { ref } from 'vue' import { ref } from 'vue'

View File

@ -33,7 +33,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import CharacterSettings from '@/components/gui/partials/settings/CharacterSettings.vue' import CharacterSettings from '@/components/game/gui/partials/settings/CharacterSettings.vue'
import { ref } from 'vue' import { ref } from 'vue'
let settingCategory = ref('character') let settingCategory = ref('character')

View File

@ -3,7 +3,8 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { WeatherState } from '@/application/types' import type { Map, WeatherState } from '@/application/types'
import { MapStorage } from '@/storage/storages'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useMapStore } from '@/stores/mapStore' import { useMapStore } from '@/stores/mapStore'
import { Scene } from 'phavuer' import { Scene } from 'phavuer'
@ -20,8 +21,10 @@ const LIGHT_CONFIG = {
// Stores and refs // Stores and refs
const gameStore = useGameStore() const gameStore = useGameStore()
const mapStore = useMapStore() const mapStore = useMapStore()
const mapStorage = new MapStorage()
const sceneRef = ref<Phaser.Scene | null>(null) const sceneRef = ref<Phaser.Scene | null>(null)
const mapEffectsReady = ref(false) const mapEffectsReady = ref(false)
const mapObject = ref<Map | null>(null)
// Effect objects // Effect objects
const effects = { const effects = {
@ -50,6 +53,24 @@ const createScene = (scene: Phaser.Scene) => {
setupSocketListeners() setupSocketListeners()
} }
const loadMap = async () => {
if (!mapStore.mapId) return
mapObject.value = await mapStorage.get(mapStore.mapId)
}
// Watch for mapId changes and load map when it's available
watch(
() => mapStore.mapId,
async (newMapId) => {
if (newMapId) {
mapEffectsReady.value = false
await loadMap()
updateScene()
}
},
{ immediate: true }
)
const initializeEffects = (scene: Phaser.Scene) => { const initializeEffects = (scene: Phaser.Scene) => {
// Light // Light
effects.light.value = scene.add.graphics().setDepth(1000) effects.light.value = scene.add.graphics().setDepth(1000)
@ -80,7 +101,7 @@ const initializeEffects = (scene: Phaser.Scene) => {
// Effect updates // Effect updates
const updateScene = () => { const updateScene = () => {
const timeBasedLight = calculateLightStrength(gameStore.world.date) const timeBasedLight = calculateLightStrength(gameStore.world.date)
const mapEffects = mapStore.map?.mapEffects?.reduce( const mapEffects = mapObject.value?.mapEffects?.reduce(
(acc, curr) => ({ (acc, curr) => ({
...acc, ...acc,
[curr.effect]: curr.strength [curr.effect]: curr.strength
@ -90,7 +111,7 @@ const updateScene = () => {
// Only update effects once mapEffects are loaded // Only update effects once mapEffects are loaded
if (!mapEffectsReady.value) { if (!mapEffectsReady.value) {
if (mapEffects && Object.keys(mapEffects).length) { if (mapObject.value) {
mapEffectsReady.value = true mapEffectsReady.value = true
} else { } else {
return return
@ -105,7 +126,6 @@ const updateScene = () => {
rain: weatherState.value.isRainEnabled ? weatherState.value.rainPercentage : 0, rain: weatherState.value.isRainEnabled ? weatherState.value.rainPercentage : 0,
fog: weatherState.value.isFogEnabled ? weatherState.value.fogDensity * 100 : 0 fog: weatherState.value.isFogEnabled ? weatherState.value.fogDensity * 100 : 0
} }
applyEffects(finalEffects) applyEffects(finalEffects)
} }
@ -161,7 +181,7 @@ const handleResize = () => {
// Lifecycle // Lifecycle
watch( watch(
() => mapStore.map, () => mapObject.value,
() => { () => {
mapEffectsReady.value = false mapEffectsReady.value = false
updateScene() updateScene()

View File

@ -1,14 +1,14 @@
<template> <template>
<MapTiles :key="mapStore.mapId" @tileMap:create="tileMap = $event" /> <MapTiles :key="mapStore.mapId" @tileMap:create="tileMap = $event" />
<!-- <MapObjects v-if="tileMap" :tilemap="tileMap as Phaser.Tilemaps.Tilemap" />--> <PlacedMapObjects v-if="tileMap" :key="mapStore.mapId" :tilemap="tileMap" />
<Characters v-if="tileMap" :tilemap="tileMap as Phaser.Tilemaps.Tilemap" /> <Characters v-if="tileMap && mapStore.characters" :tilemap="tileMap" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { MapCharacter, mapLoadData, UUID } from '@/application/types' import type { MapCharacter, mapLoadData, UUID } from '@/application/types'
import Characters from '@/components/game/map/Characters.vue' import Characters from '@/components/game/map/Characters.vue'
import MapTiles from '@/components/game/map/MapTiles.vue' import MapTiles from '@/components/game/map/MapTiles.vue'
import MapObjects from '@/components/game/map/PlacedMapObjects.vue' import PlacedMapObjects from '@/components/game/map/PlacedMapObjects.vue'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useMapStore } from '@/stores/mapStore' import { useMapStore } from '@/stores/mapStore'
import { onUnmounted, shallowRef } from 'vue' import { onUnmounted, shallowRef } from 'vue'
@ -18,14 +18,6 @@ const mapStore = useMapStore()
const tileMap = shallowRef<Phaser.Tilemaps.Tilemap>() const tileMap = shallowRef<Phaser.Tilemaps.Tilemap>()
onUnmounted(() => {
mapStore.reset()
gameStore.connection?.off('map:character:teleport')
gameStore.connection?.off('map:character:join')
gameStore.connection?.off('map:character:leave')
gameStore.connection?.off('map:character:move')
})
// Event listeners // Event listeners
gameStore.connection?.on('map:character:teleport', async (data: mapLoadData) => { gameStore.connection?.on('map:character:teleport', async (data: mapLoadData) => {
mapStore.setMapId(data.mapId) mapStore.setMapId(data.mapId)
@ -43,4 +35,12 @@ gameStore.connection?.on('map:character:leave', (characterId: UUID) => {
gameStore.connection?.on('map:character:move', (data: { characterId: UUID; positionX: number; positionY: number; rotation: number; isMoving: boolean }) => { gameStore.connection?.on('map:character:move', (data: { characterId: UUID; positionX: number; positionY: number; rotation: number; isMoving: boolean }) => {
mapStore.updateCharacterPosition(data) mapStore.updateCharacterPosition(data)
}) })
onUnmounted(() => {
mapStore.reset()
gameStore.connection?.off('map:character:teleport')
gameStore.connection?.off('map:character:join')
gameStore.connection?.off('map:character:leave')
gameStore.connection?.off('map:character:move')
})
</script> </script>

View File

@ -11,7 +11,7 @@ import { FlattenMapArray, loadMapTilesIntoScene, setLayerTiles } from '@/composa
import { MapStorage } from '@/storage/storages' import { MapStorage } from '@/storage/storages'
import { useMapStore } from '@/stores/mapStore' import { useMapStore } from '@/stores/mapStore'
import { useScene } from 'phavuer' import { useScene } from 'phavuer'
import { onBeforeUnmount, onMounted, shallowRef } from 'vue' import { onBeforeUnmount, shallowRef } from 'vue'
import Tileset = Phaser.Tilemaps.Tileset import Tileset = Phaser.Tilemaps.Tileset
@ -41,7 +41,7 @@ function createTileMap(mapData: any) {
function createTileLayer(currentTileMap: Phaser.Tilemaps.Tilemap, mapData: any) { function createTileLayer(currentTileMap: Phaser.Tilemaps.Tilemap, mapData: any) {
const tilesArray = unduplicateArray(FlattenMapArray(mapData?.tiles ?? [])) const tilesArray = unduplicateArray(FlattenMapArray(mapData?.tiles ?? []))
const tilesetImages = tilesArray.map((tile: any, index: number) => { const tilesetImages = tilesArray.map((tile: string, index: number) => {
return currentTileMap.addTilesetImage(tile, tile, config.tile_size.width, config.tile_size.height, 1, 2, index + 1, { x: 0, y: -config.tile_size.height }) return currentTileMap.addTilesetImage(tile, tile, config.tile_size.width, config.tile_size.height, 1, 2, index + 1, { x: 0, y: -config.tile_size.height })
}) })
@ -55,16 +55,14 @@ function createTileLayer(currentTileMap: Phaser.Tilemaps.Tilemap, mapData: any)
return layer return layer
} }
onMounted(() => { loadMapTilesIntoScene(mapStore.mapId as UUID, scene)
loadMapTilesIntoScene(mapStore.mapId as UUID, scene) .then(() => mapStorage.get(mapStore.mapId))
.then(() => mapStorage.get(mapStore.mapId)) .then((mapData) => {
.then((mapData) => { tileMap.value = createTileMap(mapData)
tileMap.value = createTileMap(mapData) tileLayer.value = createTileLayer(tileMap.value, mapData)
tileLayer.value = createTileLayer(tileMap.value, mapData) setLayerTiles(tileMap.value, tileLayer.value, mapData?.tiles)
setLayerTiles(tileMap.value, tileLayer.value, mapData?.tiles) })
}) .catch((error) => console.error('Failed to initialize map:', error))
.catch((error) => console.error('Failed to initialize map:', error))
})
onBeforeUnmount(() => { onBeforeUnmount(() => {
if (!tileMap.value) return if (!tileMap.value) return

View File

@ -1,14 +1,28 @@
<template> <template>
<PlacedMapObject v-for="placedMapObject in mapStore.map?.placedMapObjects" :tilemap="tilemap" :placedMapObject /> <PlacedMapObject v-for="placedMapObject in items" :tilemap="tilemap" :placedMapObject />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { PlacedMapObject as PlacedMapObjectT } from '@/application/types'
import PlacedMapObject from '@/components/game/map/partials/PlacedMapObject.vue' import PlacedMapObject from '@/components/game/map/partials/PlacedMapObject.vue'
import { MapStorage } from '@/storage/storages'
import { useMapStore } from '@/stores/mapStore' import { useMapStore } from '@/stores/mapStore'
import { onMounted, ref } from 'vue'
const mapStore = useMapStore()
defineProps<{ defineProps<{
tilemap: Phaser.Tilemaps.Tilemap tilemap: Phaser.Tilemaps.Tilemap
}>() }>()
const mapStore = useMapStore()
const mapStorage = new MapStorage()
const items = ref<PlacedMapObjectT[]>([])
onMounted(async () => {
if (!mapStore.mapId) return
const map = await mapStorage.get(mapStore.mapId)
if (!map) return
items.value = map.placedMapObjects
})
</script> </script>

View File

@ -1,5 +1,5 @@
<template> <template>
<Image v-if="gameStore.isAssetLoaded(props.placedMapObject.mapObject)" v-bind="imageProps" /> <Image v-if="gameStore.isTextureLoaded(props.placedMapObject.mapObject.id)" v-bind="imageProps" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -8,7 +8,7 @@ import { loadTexture } from '@/composables/gameComposable'
import { calculateIsometricDepth, tileToWorldX, tileToWorldY } from '@/composables/mapComposable' import { calculateIsometricDepth, tileToWorldX, tileToWorldY } from '@/composables/mapComposable'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { Image, useScene } from 'phavuer' import { Image, useScene } from 'phavuer'
import { computed } from 'vue' import { computed, onMounted } from 'vue'
const props = defineProps<{ const props = defineProps<{
tilemap: Phaser.Tilemaps.Tilemap tilemap: Phaser.Tilemaps.Tilemap
@ -38,4 +38,6 @@ loadTexture(scene, {
} as TextureData).catch((error) => { } as TextureData).catch((error) => {
console.error('Error loading texture:', error) console.error('Error loading texture:', error)
}) })
onMounted(async () => {})
</script> </script>

View File

@ -9,7 +9,7 @@
</button> </button>
</label> </label>
</div> </div>
<div v-bind="containerProps" class="overflow-y-auto relative p-2.5 rounded-md default-border bg-gray" @scroll="onScroll"> <div v-bind="containerProps" class="flex-1 overflow-y-auto relative p-2.5 rounded-md default-border bg-gray" @scroll="onScroll">
<div v-bind="wrapperProps" ref="elementToScroll" class="flex flex-col gap-2.5"> <div v-bind="wrapperProps" ref="elementToScroll" class="flex flex-col gap-2.5">
<a <a
v-for="{ data: characterHair } in list" v-for="{ data: characterHair } in list"
@ -93,7 +93,6 @@ function toTop() {
onMounted(() => { onMounted(() => {
gameStore.connection?.emit('gm:characterHair:list', {}, (response: CharacterHair[]) => { gameStore.connection?.emit('gm:characterHair:list', {}, (response: CharacterHair[]) => {
console.log(response)
assetManagerStore.setCharacterHairList(response) assetManagerStore.setCharacterHairList(response)
}) })
}) })

View File

@ -9,7 +9,7 @@
</button> </button>
</label> </label>
</div> </div>
<div v-bind="containerProps" class="overflow-y-auto relative p-2.5 rounded-md default-border bg-gray" @scroll="onScroll"> <div v-bind="containerProps" class="flex-1 overflow-y-auto relative p-2.5 rounded-md default-border bg-gray" @scroll="onScroll">
<div v-bind="wrapperProps" ref="elementToScroll" class="flex flex-col gap-2.5"> <div v-bind="wrapperProps" ref="elementToScroll" class="flex flex-col gap-2.5">
<a <a
v-for="{ data: characterType } in list" v-for="{ data: characterType } in list"
@ -93,7 +93,6 @@ function toTop() {
onMounted(() => { onMounted(() => {
gameStore.connection?.emit('gm:characterType:list', {}, (response: CharacterType[]) => { gameStore.connection?.emit('gm:characterType:list', {}, (response: CharacterType[]) => {
console.log(response)
assetManagerStore.setCharacterTypeList(response) assetManagerStore.setCharacterTypeList(response)
}) })
}) })

View File

@ -9,7 +9,7 @@
</button> </button>
</label> </label>
</div> </div>
<div v-bind="containerProps" class="overflow-y-auto relative p-2.5 rounded-md default-border bg-gray" @scroll="onScroll"> <div v-bind="containerProps" class="flex-1 overflow-y-auto relative p-2.5 rounded-md default-border bg-gray" @scroll="onScroll">
<div v-bind="wrapperProps" ref="elementToScroll" class="flex flex-col gap-2.5"> <div v-bind="wrapperProps" ref="elementToScroll" class="flex flex-col gap-2.5">
<a v-for="{ data: item } in list" :key="item.id" class="relative p-2.5 cursor-pointer block rounded hover:bg-cyan group" :class="{ 'bg-cyan': assetManagerStore.selectedItem?.id === item.id }" @click="assetManagerStore.setSelectedItem(item as Item)"> <a v-for="{ data: item } in list" :key="item.id" class="relative p-2.5 cursor-pointer block rounded hover:bg-cyan group" :class="{ 'bg-cyan': assetManagerStore.selectedItem?.id === item.id }" @click="assetManagerStore.setSelectedItem(item as Item)">
<div class="flex items-center gap-2.5"> <div class="flex items-center gap-2.5">

View File

@ -8,7 +8,7 @@
</svg> </svg>
</label> </label>
</div> </div>
<div v-bind="containerProps" class="overflow-y-auto relative p-2.5 rounded-md default-border bg-gray" @scroll="onScroll"> <div v-bind="containerProps" class="flex-1 overflow-y-auto relative p-2.5 rounded-md default-border bg-gray" @scroll="onScroll">
<div v-bind="wrapperProps" ref="elementToScroll" class="flex flex-col gap-2.5"> <div v-bind="wrapperProps" ref="elementToScroll" class="flex flex-col gap-2.5">
<a v-for="{ data: mapObject } in list" :key="mapObject.id" class="relative p-2.5 cursor-pointer block rounded hover:bg-cyan group" :class="{ 'bg-cyan': assetManagerStore.selectedMapObject?.id === mapObject.id }" @click="assetManagerStore.setSelectedMapObject(mapObject as MapObject)"> <a v-for="{ data: mapObject } in list" :key="mapObject.id" class="relative p-2.5 cursor-pointer block rounded hover:bg-cyan group" :class="{ 'bg-cyan': assetManagerStore.selectedMapObject?.id === mapObject.id }" @click="assetManagerStore.setSelectedMapObject(mapObject as MapObject)">
<div class="flex items-center gap-2.5"> <div class="flex items-center gap-2.5">

View File

@ -7,7 +7,7 @@
</svg> </svg>
</button> </button>
</div> </div>
<div v-bind="containerProps" class="overflow-y-auto relative p-2.5 rounded-md default-border bg-gray" @scroll="onScroll"> <div v-bind="containerProps" class="flex-1 overflow-y-auto relative p-2.5 rounded-md default-border bg-gray" @scroll="onScroll">
<div v-bind="wrapperProps" ref="elementToScroll" class="flex flex-col gap-2.5"> <div v-bind="wrapperProps" ref="elementToScroll" class="flex flex-col gap-2.5">
<a v-for="{ data: sprite } in list" :key="sprite.id" class="relative p-2.5 cursor-pointer block rounded hover:bg-cyan group" :class="{ 'bg-cyan': assetManagerStore.selectedSprite?.id === sprite.id }" @click="assetManagerStore.setSelectedSprite(sprite as Sprite)"> <a v-for="{ data: sprite } in list" :key="sprite.id" class="relative p-2.5 cursor-pointer block rounded hover:bg-cyan group" :class="{ 'bg-cyan': assetManagerStore.selectedSprite?.id === sprite.id }" @click="assetManagerStore.setSelectedSprite(sprite as Sprite)">
<div class="flex items-center gap-2.5"> <div class="flex items-center gap-2.5">

View File

@ -8,7 +8,7 @@
</svg> </svg>
</label> </label>
</div> </div>
<div v-bind="containerProps" class="overflow-y-auto relative p-2.5 rounded-md default-border bg-gray" @scroll="onScroll"> <div v-bind="containerProps" class="flex-1 overflow-y-auto relative p-2.5 rounded-md default-border bg-gray" @scroll="onScroll">
<div v-bind="wrapperProps" ref="elementToScroll" class="flex flex-col gap-2.5"> <div v-bind="wrapperProps" ref="elementToScroll" class="flex flex-col gap-2.5">
<a v-for="{ data: tile } in list" :key="tile.id" class="relative p-2.5 cursor-pointer block rounded hover:bg-cyan group" :class="{ 'bg-cyan': assetManagerStore.selectedTile?.id === tile.id }" @click="assetManagerStore.setSelectedTile(tile)"> <a v-for="{ data: tile } in list" :key="tile.id" class="relative p-2.5 cursor-pointer block rounded hover:bg-cyan group" :class="{ 'bg-cyan': assetManagerStore.selectedTile?.id === tile.id }" @click="assetManagerStore.setSelectedTile(tile)">
<div class="flex items-center gap-2.5"> <div class="flex items-center gap-2.5">

View File

@ -1,6 +1,6 @@
<template> <template>
<MapTiles @tileMap:create="tileMap = $event" /> <MapTiles @tileMap:create="tileMap = $event" />
<MapObjects v-if="tileMap" :tilemap="tileMap as Phaser.Tilemaps.Tilemap" /> <PlacedMapObjects v-if="tileMap" :tilemap="tileMap as Phaser.Tilemaps.Tilemap" />
<MapEventTiles v-if="tileMap" :tilemap="tileMap as Phaser.Tilemaps.Tilemap" /> <MapEventTiles v-if="tileMap" :tilemap="tileMap as Phaser.Tilemaps.Tilemap" />
<Toolbar @save="save" @clear="clear" /> <Toolbar @save="save" @clear="clear" />
@ -17,17 +17,16 @@
import { type Map } from '@/application/types' import { type Map } from '@/application/types'
import MapEventTiles from '@/components/gameMaster/mapEditor/mapPartials/MapEventTiles.vue' import MapEventTiles from '@/components/gameMaster/mapEditor/mapPartials/MapEventTiles.vue'
import MapTiles from '@/components/gameMaster/mapEditor/mapPartials/MapTiles.vue' import MapTiles from '@/components/gameMaster/mapEditor/mapPartials/MapTiles.vue'
import MapObjects from '@/components/gameMaster/mapEditor/mapPartials/PlacedMapObjects.vue' import PlacedMapObjects from '@/components/gameMaster/mapEditor/mapPartials/PlacedMapObjects.vue'
import MapList from '@/components/gameMaster/mapEditor/partials/MapList.vue' import MapList from '@/components/gameMaster/mapEditor/partials/MapList.vue'
import ObjectList from '@/components/gameMaster/mapEditor/partials/MapObjectList.vue' import ObjectList from '@/components/gameMaster/mapEditor/partials/MapObjectList.vue'
import MapSettings from '@/components/gameMaster/mapEditor/partials/MapSettings.vue' import MapSettings from '@/components/gameMaster/mapEditor/partials/MapSettings.vue'
import TeleportModal from '@/components/gameMaster/mapEditor/partials/TeleportModal.vue' import TeleportModal from '@/components/gameMaster/mapEditor/partials/TeleportModal.vue'
import TileList from '@/components/gameMaster/mapEditor/partials/TileList.vue' import TileList from '@/components/gameMaster/mapEditor/partials/TileList.vue'
// Components
import Toolbar from '@/components/gameMaster/mapEditor/partials/Toolbar.vue' import Toolbar from '@/components/gameMaster/mapEditor/partials/Toolbar.vue'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useMapEditorStore } from '@/stores/mapEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import { onUnmounted, ref, shallowRef } from 'vue' import { onUnmounted, shallowRef } from 'vue'
const gameStore = useGameStore() const gameStore = useGameStore()
const mapEditorStore = useMapEditorStore() const mapEditorStore = useMapEditorStore()
@ -58,8 +57,6 @@ function save() {
placedMapObjects: mapEditorStore.map.placedMapObjects?.map(({ id, mapObject, depth, isRotated, positionX, positionY }) => ({ id, mapObject, depth, isRotated, positionX, positionY })) ?? [] placedMapObjects: mapEditorStore.map.placedMapObjects?.map(({ id, mapObject, depth, isRotated, positionX, positionY }) => ({ id, mapObject, depth, isRotated, positionX, positionY })) ?? []
} }
console.log(data.mapEventTiles)
if (mapEditorStore.isSettingsModalShown) { if (mapEditorStore.isSettingsModalShown) {
mapEditorStore.toggleSettingsModal() mapEditorStore.toggleSettingsModal()
} }

View File

@ -1,30 +1,27 @@
<template> <template>
<Controls :layer="tileLayer" :depth="0" /> <Controls v-if="tileLayer" :layer="tileLayer" :depth="0" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import config from '@/application/config' import config from '@/application/config'
import type { TextureData } from '@/application/types'
import Controls from '@/components/utilities/Controls.vue' import Controls from '@/components/utilities/Controls.vue'
import { createTileArray, getTile, placeTile, setLayerTiles } from '@/composables/mapComposable' import { createTileArray, getTile, loadAllTilesIntoScene, placeTile, setLayerTiles } from '@/composables/mapComposable'
import { useGameStore } from '@/stores/gameStore' import { TileStorage } from '@/storage/storages'
import { useMapEditorStore } from '@/stores/mapEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import { useScene } from 'phavuer' import { useScene } from 'phavuer'
import { onMounted, onUnmounted, watch } from 'vue' import { onBeforeMount, onMounted, onUnmounted, shallowRef, watch } from 'vue'
import Tileset = Phaser.Tilemaps.Tileset
const emit = defineEmits(['tileMap:create']) const emit = defineEmits(['tileMap:create'])
const scene = useScene() const scene = useScene()
const gameStore = useGameStore()
const mapEditorStore = useMapEditorStore() const mapEditorStore = useMapEditorStore()
const tileMap = createTileMap() const tileStorage = new TileStorage()
const tileLayer = createTileLayer()
const tileMap = shallowRef<Phaser.Tilemaps.Tilemap>()
const tileLayer = shallowRef<Phaser.Tilemaps.TilemapLayer>()
/**
* A Tilemap is a container for Tilemap data.
* This isn't a display object, rather, it holds data about the map and allows you to add tilesets and tilemap layers to it.
* A map can have one or more tilemap layers, which are the display objects that actually render the tiles.
*/
function createTileMap() { function createTileMap() {
const mapData = new Phaser.Tilemaps.MapData({ const mapData = new Phaser.Tilemaps.MapData({
width: mapEditorStore.map?.width, width: mapEditorStore.map?.width,
@ -37,31 +34,30 @@ function createTileMap() {
const newTileMap = new Phaser.Tilemaps.Tilemap(scene, mapData) const newTileMap = new Phaser.Tilemaps.Tilemap(scene, mapData)
emit('tileMap:create', newTileMap) emit('tileMap:create', newTileMap)
return newTileMap return newTileMap
} }
/** async function createTileLayer(currentTileMap: Phaser.Tilemaps.Tilemap) {
* A Tileset is a combination of a single image containing the tiles and a container for data about each tile. const tiles = await tileStorage.getAll()
*/ const tilesetImages = []
function createTileLayer() {
const tilesArray = gameStore.getLoadedAssetsByGroup('tiles')
const tilesetImages = Array.from(tilesArray).map((tile: TextureData, index: number) => { for (const tile of tiles) {
return tileMap.addTilesetImage(tile.key, tile.key, config.tile_size.width, config.tile_size.height, 1, 2, index + 1, { x: 0, y: -config.tile_size.height }) tilesetImages.push(currentTileMap.addTilesetImage(tile.id, tile.id, config.tile_size.width, config.tile_size.height, 1, 2, tilesetImages.length + 1, { x: 0, y: -config.tile_size.height }))
}) as any }
// Add blank tile // Add blank tile
tilesetImages.push(tileMap.addTilesetImage('blank_tile', 'blank_tile', config.tile_size.width, config.tile_size.height, 1, 2, 0, { x: 0, y: -config.tile_size.height })) tilesetImages.push(currentTileMap.addTilesetImage('blank_tile', 'blank_tile', config.tile_size.width, config.tile_size.height, 1, 2, 0, { x: 0, y: -config.tile_size.height }))
const layer = tileMap.createBlankLayer('tiles', tilesetImages, 0, config.tile_size.height) as Phaser.Tilemaps.TilemapLayer
const layer = currentTileMap.createBlankLayer('tiles', tilesetImages as Tileset[], 0, config.tile_size.height) as Phaser.Tilemaps.TilemapLayer
layer.setDepth(0) layer.setDepth(0)
layer.setCullPadding(2, 2) layer.setCullPadding(2, 2)
return layer return layer
} }
function pencil(pointer: Phaser.Input.Pointer) { function pencil(pointer: Phaser.Input.Pointer) {
if (!tileMap.value || !tileLayer.value) return
// Check if map is set // Check if map is set
if (!mapEditorStore.map) return if (!mapEditorStore.map) return
@ -81,17 +77,19 @@ function pencil(pointer: Phaser.Input.Pointer) {
if (pointer.event.shiftKey) return if (pointer.event.shiftKey) return
// Check if there is a tile // Check if there is a tile
const tile = getTile(tileLayer, pointer.worldX, pointer.worldY) const tile = getTile(tileLayer.value, pointer.worldX, pointer.worldY)
if (!tile) return if (!tile) return
// Place tile // Place tile
placeTile(tileMap, tileLayer, tile.x, tile.y, mapEditorStore.selectedTile) placeTile(tileMap.value, tileLayer.value, tile.x, tile.y, mapEditorStore.selectedTile)
// Adjust mapEditorStore.map.tiles // Adjust mapEditorStore.map.tiles
mapEditorStore.map.tiles[tile.y][tile.x] = mapEditorStore.selectedTile mapEditorStore.map.tiles[tile.y][tile.x] = mapEditorStore.selectedTile
} }
function eraser(pointer: Phaser.Input.Pointer) { function eraser(pointer: Phaser.Input.Pointer) {
if (!tileMap.value || !tileLayer.value) return
// Check if map is set // Check if map is set
if (!mapEditorStore.map) return if (!mapEditorStore.map) return
@ -111,17 +109,19 @@ function eraser(pointer: Phaser.Input.Pointer) {
if (pointer.event.altKey) return if (pointer.event.altKey) return
// Check if there is a tile // Check if there is a tile
const tile = getTile(tileLayer, pointer.worldX, pointer.worldY) const tile = getTile(tileLayer.value, pointer.worldX, pointer.worldY)
if (!tile) return if (!tile) return
// Place tile // Place tile
placeTile(tileMap, tileLayer, tile.x, tile.y, 'blank_tile') placeTile(tileMap.value, tileLayer.value, tile.x, tile.y, 'blank_tile')
// Adjust mapEditorStore.map.tiles // Adjust mapEditorStore.map.tiles
mapEditorStore.map.tiles[tile.y][tile.x] = 'blank_tile' mapEditorStore.map.tiles[tile.y][tile.x] = 'blank_tile'
} }
function paint(pointer: Phaser.Input.Pointer) { function paint(pointer: Phaser.Input.Pointer) {
if (!tileMap.value || !tileLayer.value) return
// Check if map is set // Check if map is set
if (!mapEditorStore.map) return if (!mapEditorStore.map) return
@ -141,14 +141,16 @@ function paint(pointer: Phaser.Input.Pointer) {
if (pointer.event.altKey) return if (pointer.event.altKey) return
// Set new tileArray with selected tile // Set new tileArray with selected tile
setLayerTiles(tileMap, tileLayer, createTileArray(tileMap.width, tileMap.height, mapEditorStore.selectedTile)) setLayerTiles(tileMap.value, tileLayer.value, createTileArray(tileMap.value.width, tileMap.value.height, mapEditorStore.selectedTile))
// Adjust mapEditorStore.map.tiles // Adjust mapEditorStore.map.tiles
mapEditorStore.map.tiles = createTileArray(tileMap.width, tileMap.height, mapEditorStore.selectedTile) mapEditorStore.map.tiles = createTileArray(tileMap.value.width, tileMap.value.height, mapEditorStore.selectedTile)
} }
// When alt is pressed, and the pointer is down, select the tile that the pointer is over // When alt is pressed, and the pointer is down, select the tile that the pointer is over
function tilePicker(pointer: Phaser.Input.Pointer) { function tilePicker(pointer: Phaser.Input.Pointer) {
if (!tileMap.value || !tileLayer.value) return
// Check if map is set // Check if map is set
if (!mapEditorStore.map) return if (!mapEditorStore.map) return
@ -168,7 +170,7 @@ function tilePicker(pointer: Phaser.Input.Pointer) {
if (!pointer.event.altKey) return if (!pointer.event.altKey) return
// Check if there is a tile // Check if there is a tile
const tile = getTile(tileLayer, pointer.worldX, pointer.worldY) const tile = getTile(tileLayer.value, pointer.worldX, pointer.worldY)
if (!tile) return if (!tile) return
// Select the tile // Select the tile
@ -178,19 +180,20 @@ function tilePicker(pointer: Phaser.Input.Pointer) {
watch( watch(
() => mapEditorStore.shouldClearTiles, () => mapEditorStore.shouldClearTiles,
(shouldClear) => { (shouldClear) => {
if (shouldClear && mapEditorStore.map) { if (shouldClear && mapEditorStore.map && tileMap.value && tileLayer.value) {
const blankTiles = createTileArray(tileMap.width, tileMap.height, 'blank_tile') const blankTiles = createTileArray(tileMap.value.width, tileMap.value.height, 'blank_tile')
setLayerTiles(tileMap, tileLayer, blankTiles) setLayerTiles(tileMap.value, tileLayer.value, blankTiles)
mapEditorStore.map.tiles = blankTiles mapEditorStore.map.tiles = blankTiles
mapEditorStore.resetClearTilesFlag() mapEditorStore.resetClearTilesFlag()
} }
} }
) )
onMounted(() => { onMounted(async () => {
if (!mapEditorStore.map?.tiles) { if (!mapEditorStore.map?.tiles) return
return
} tileMap.value = createTileMap()
tileLayer.value = await createTileLayer(tileMap.value)
// First fill the entire map with blank tiles using current map dimensions // First fill the entire map with blank tiles using current map dimensions
const blankTiles = createTileArray(mapEditorStore.map.width, mapEditorStore.map.height, 'blank_tile') const blankTiles = createTileArray(mapEditorStore.map.width, mapEditorStore.map.height, 'blank_tile')
@ -199,14 +202,13 @@ onMounted(() => {
const mapTiles = mapEditorStore.map.tiles const mapTiles = mapEditorStore.map.tiles
for (let y = 0; y < mapEditorStore.map.height; y++) { for (let y = 0; y < mapEditorStore.map.height; y++) {
for (let x = 0; x < mapEditorStore.map.width; x++) { for (let x = 0; x < mapEditorStore.map.width; x++) {
// Only copy if the source tiles array has this position
if (mapTiles[y] && mapTiles[y][x] !== undefined) { if (mapTiles[y] && mapTiles[y][x] !== undefined) {
blankTiles[y][x] = mapTiles[y][x] blankTiles[y][x] = mapTiles[y][x]
} }
} }
} }
setLayerTiles(tileMap, tileLayer, blankTiles) setLayerTiles(tileMap.value, tileLayer.value, blankTiles)
scene.input.on(Phaser.Input.Events.POINTER_MOVE, pencil) scene.input.on(Phaser.Input.Events.POINTER_MOVE, pencil)
scene.input.on(Phaser.Input.Events.POINTER_MOVE, eraser) scene.input.on(Phaser.Input.Events.POINTER_MOVE, eraser)
@ -220,8 +222,10 @@ onUnmounted(() => {
scene.input.off(Phaser.Input.Events.POINTER_DOWN, paint) scene.input.off(Phaser.Input.Events.POINTER_DOWN, paint)
scene.input.off(Phaser.Input.Events.POINTER_DOWN, tilePicker) scene.input.off(Phaser.Input.Events.POINTER_DOWN, tilePicker)
tileMap.destroyLayer('tiles') if (tileMap.value) {
tileMap.removeAllLayers() tileMap.value.destroyLayer('tiles')
tileMap.destroy() tileMap.value.removeAllLayers()
tileMap.value.destroy()
}
}) })
</script> </script>

View File

@ -1,5 +1,5 @@
<template> <template>
<Image v-if="gameStore.getLoadedAsset(props.placedMapObject.mapObject.id)" v-bind="imageProps" /> <Image v-if="gameStore.isTextureLoaded(props.placedMapObject.mapObject.id)" v-bind="imageProps" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">

View File

@ -4,7 +4,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { MapObject, PlacedMapObject as PlacedMapObjectT } from '@/application/types' import type { PlacedMapObject as PlacedMapObjectT } from '@/application/types'
import { uuidv4 } from '@/application/utilities' import { uuidv4 } from '@/application/utilities'
import PlacedMapObject from '@/components/gameMaster/mapEditor/mapPartials/PlacedMapObject.vue' import PlacedMapObject from '@/components/gameMaster/mapEditor/mapPartials/PlacedMapObject.vue'
import SelectedPlacedMapObjectComponent from '@/components/gameMaster/mapEditor/partials/SelectedPlacedMapObject.vue' import SelectedPlacedMapObjectComponent from '@/components/gameMaster/mapEditor/partials/SelectedPlacedMapObject.vue'

View File

@ -46,7 +46,7 @@
</Modal> </Modal>
</template> </template>
<script setup> <script setup lang="ts">
import Modal from '@/components/utilities/Modal.vue' import Modal from '@/components/utilities/Modal.vue'
import { useMapEditorStore } from '@/stores/mapEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import { ref, watch } from 'vue' import { ref, watch } from 'vue'

View File

@ -17,8 +17,6 @@ const props = defineProps<{
placedMapObject: PlacedMapObject placedMapObject: PlacedMapObject
}>() }>()
console.log(props.placedMapObject)
const emit = defineEmits(['move', 'rotate', 'delete']) const emit = defineEmits(['move', 'rotate', 'delete'])
const handleMove = () => { const handleMove = () => {

View File

@ -1,5 +1,8 @@
<template> <template>
<div class="relative max-lg:h-dvh flex flex-row-reverse"> <div class="relative max-lg:h-dvh flex flex-row-reverse">
<div class="portrait-mode-notice hidden absolute h-[calc(100%_-_80px)] w-[calc(100%_-_80px)] left-0 top-0 bg-gray z-50 p-10 text-center">
<span class="text-lg">Noxious is not compatible with portrait mode on smaller screens. Please switch to landscape mode to play.</span>
</div>
<div class="lg:bg-gradient-to-l bg-gradient-to-b from-gray-900 to-transparent w-full lg:w-1/2 h-[65dvh] lg:h-dvh absolute left-0 max-lg:bottom-0 lg:top-0 z-10"></div> <div class="lg:bg-gradient-to-l bg-gradient-to-b from-gray-900 to-transparent w-full lg:w-1/2 h-[65dvh] lg:h-dvh absolute left-0 max-lg:bottom-0 lg:top-0 z-10"></div>
<div class="bg-[url('/assets/login/login-bg.png')] opacity-20 w-full lg:w-1/2 h-[65dvh] lg:h-dvh absolute left-0 max-lg:bottom-0 lg:top-0 bg-no-repeat bg-cover bg-center grayscale"></div> <div class="bg-[url('/assets/login/login-bg.png')] opacity-20 w-full lg:w-1/2 h-[65dvh] lg:h-dvh absolute left-0 max-lg:bottom-0 lg:top-0 bg-no-repeat bg-cover bg-center grayscale"></div>
<div class="bg-gray-900 z-20 w-full lg:w-1/2 h-[35dvh] lg:h-dvh relative"></div> <div class="bg-gray-900 z-20 w-full lg:w-1/2 h-[35dvh] lg:h-dvh relative"></div>

View File

@ -1,5 +1,8 @@
<template> <template>
<div class="flex justify-center items-center h-dvh relative"> <div class="flex justify-center items-center h-dvh relative">
<div class="portrait-mode-notice hidden absolute h-[calc(100%_-_80px)] w-[calc(100%_-_80px)] left-0 top-0 bg-gray z-50 p-10 text-center">
<span class="text-lg">Noxious is not compatible with portrait mode on smaller screens. Please switch to landscape mode to play.</span>
</div>
<Game :config="gameConfig" @create="createGame"> <Game :config="gameConfig" @create="createGame">
<Scene name="main" @preload="preloadScene" @create="createScene"> <Scene name="main" @preload="preloadScene" @create="createScene">
<Menu /> <Menu />
@ -20,18 +23,16 @@
<script setup lang="ts"> <script setup lang="ts">
import config from '@/application/config' import config from '@/application/config'
import 'phaser' import 'phaser'
import Effects from '@/components/Effects.vue' import CharacterProfile from '@/components/game/gui/CharacterProfile.vue'
import Chat from '@/components/game/gui/Chat.vue'
import Clock from '@/components/game/gui/Clock.vue'
import ExpBar from '@/components/game/gui/ExpBar.vue'
import Hotkeys from '@/components/game/gui/Hotkeys.vue'
import Hud from '@/components/game/gui/Hud.vue'
import Menu from '@/components/game/gui/Menu.vue'
import Effects from '@/components/game/map/Effects.vue'
import Map from '@/components/game/map/Map.vue' import Map from '@/components/game/map/Map.vue'
import CharacterProfile from '@/components/gui/CharacterProfile.vue'
import Chat from '@/components/gui/Chat.vue'
// import Minimap from '@/components/gui/Minimap.vue'
import Clock from '@/components/gui/Clock.vue'
import ExpBar from '@/components/gui/ExpBar.vue'
import Hotkeys from '@/components/gui/Hotkeys.vue'
import Hud from '@/components/gui/Hud.vue'
import Menu from '@/components/gui/Menu.vue'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import AwaitLoaderPlugin from 'phaser3-rex-plugins/plugins/awaitloader-plugin'
import { Game, Scene } from 'phavuer' import { Game, Scene } from 'phavuer'
import { onBeforeUnmount } from 'vue' import { onBeforeUnmount } from 'vue'
@ -42,22 +43,11 @@ const gameConfig = {
width: window.innerWidth, width: window.innerWidth,
height: window.innerHeight, height: window.innerHeight,
type: Phaser.AUTO, // AUTO, CANVAS, WEBGL, HEADLESS type: Phaser.AUTO, // AUTO, CANVAS, WEBGL, HEADLESS
resolution: 5, resolution: 5
plugins: {
global: [
{
key: 'rexAwaitLoader',
plugin: AwaitLoaderPlugin,
start: true
}
]
}
} }
const createGame = (game: Phaser.Game) => { const createGame = (game: Phaser.Game) => {
/** // Resize the game when the window is resized
* Resize the game when the window is resized
*/
addEventListener('resize', () => { addEventListener('resize', () => {
game.scale.resize(window.innerWidth, window.innerHeight) game.scale.resize(window.innerWidth, window.innerHeight)
}) })
@ -73,9 +63,7 @@ const createGame = (game: Phaser.Game) => {
} }
function preloadScene(scene: Phaser.Scene) { function preloadScene(scene: Phaser.Scene) {
/** // Load the base assets into the Phaser scene
* Load the base assets into the Phaser scene
*/
scene.load.image('blank_tile', '/assets/map/blank_tile.png') scene.load.image('blank_tile', '/assets/map/blank_tile.png')
scene.load.image('waypoint', '/assets/waypoint.png') scene.load.image('waypoint', '/assets/waypoint.png')
} }

View File

@ -9,7 +9,7 @@
<!-- <img src="/assets/tlogo.png" class="mb-10 w-52" alt="Noxious logo" />--> <!-- <img src="/assets/tlogo.png" class="mb-10 w-52" alt="Noxious logo" />-->
<div class="relative"> <div class="relative">
<img src="/assets/ui-elements/login-ui-box-outer.svg" class="absolute w-full h-full" alt="UI box outer" /> <img src="/assets/ui-elements/login-ui-box-outer.svg" class="absolute w-full h-full" alt="UI box outer" />
<img src="/assets/ui-elements/login-ui-box-inner.svg" class="absolute left-2 top-2 w-[calc(100%_-_16px)] h-[calc(100%_-_16px)] max-lg:hidden" alt="UI box inner" /> <img src="/assets/ui-elements/login-ui-box-inner.svg" class="absolute left-2 top-2 w-[calc(100%_-_16px)] h-[calc(100%_-_16px)]" alt="UI box inner" />
<!-- Login Form --> <!-- Login Form -->
<LoginForm v-if="currentForm === 'login' && !doesUrlHaveToken" @openResetPasswordModal="() => (isPasswordResetFormShown = true)" @switchToRegister="currentForm = 'register'" /> <LoginForm v-if="currentForm === 'login' && !doesUrlHaveToken" @openResetPasswordModal="() => (isPasswordResetFormShown = true)" @switchToRegister="currentForm = 'register'" />

View File

@ -2,7 +2,8 @@
<div class="flex justify-center items-center h-dvh relative"> <div class="flex justify-center items-center h-dvh relative">
<Game :config="gameConfig" @create="createGame"> <Game :config="gameConfig" @create="createGame">
<Scene name="main" @preload="preloadScene" @create="createScene"> <Scene name="main" @preload="preloadScene" @create="createScene">
<MapEditor :key="JSON.stringify(`${mapEditorStore.map?.id}_${mapEditorStore.map?.createdAt}_${mapEditorStore.map?.updatedAt ?? ''}`)" /> <MapEditor :key="JSON.stringify(`${mapEditorStore.map?.id}_${mapEditorStore.map?.createdAt}_${mapEditorStore.map?.updatedAt}`)" v-if="isLoaded" />
<div v-else class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-white text-3xl font-ui">Loading...</div>
</Scene> </Scene>
</Game> </Game>
</div> </div>
@ -11,38 +12,28 @@
<script setup lang="ts"> <script setup lang="ts">
import config from '@/application/config' import config from '@/application/config'
import 'phaser' import 'phaser'
import type { TextureData } from '@/application/types'
import MapEditor from '@/components/gameMaster/mapEditor/MapEditor.vue' import MapEditor from '@/components/gameMaster/mapEditor/MapEditor.vue'
import { loadTexture } from '@/composables/gameComposable' import { loadAllTilesIntoScene } from '@/composables/mapComposable'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useMapEditorStore } from '@/stores/mapEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import AwaitLoaderPlugin from 'phaser3-rex-plugins/plugins/awaitloader-plugin'
import { Game, Scene } from 'phavuer' import { Game, Scene } from 'phavuer'
import { ref } from 'vue'
const gameStore = useGameStore() const gameStore = useGameStore()
const mapEditorStore = useMapEditorStore() const mapEditorStore = useMapEditorStore()
const isLoaded = ref(false)
const gameConfig = { const gameConfig = {
name: config.name, name: config.name,
width: window.innerWidth, width: window.innerWidth,
height: window.innerHeight, height: window.innerHeight,
type: Phaser.AUTO, // AUTO, CANVAS, WEBGL, HEADLESS type: Phaser.AUTO, // AUTO, CANVAS, WEBGL, HEADLESS
resolution: 5, resolution: 5
plugins: {
global: [
{
key: 'rexAwaitLoader',
plugin: AwaitLoaderPlugin,
start: true
}
]
}
} }
const createGame = (game: Phaser.Game) => { const createGame = (game: Phaser.Game) => {
/** // Resize the game when the window is resized
* Resize the game when the window is resized
*/
addEventListener('resize', () => { addEventListener('resize', () => {
game.scale.resize(window.innerWidth, window.innerHeight) game.scale.resize(window.innerWidth, window.innerHeight)
}) })
@ -58,27 +49,19 @@ const createGame = (game: Phaser.Game) => {
} }
const preloadScene = async (scene: Phaser.Scene) => { const preloadScene = async (scene: Phaser.Scene) => {
/** // Load the base assets into the Phaser scene
* Load the base assets into the Phaser scene
*/
scene.load.image('BLOCK', '/assets/map/bt_tile.png') scene.load.image('BLOCK', '/assets/map/bt_tile.png')
scene.load.image('TELEPORT', '/assets/map/tp_tile.png') scene.load.image('TELEPORT', '/assets/map/tp_tile.png')
scene.load.image('blank_tile', '/assets/map/blank_tile.png') scene.load.image('blank_tile', '/assets/map/blank_tile.png')
scene.load.image('waypoint', '/assets/waypoint.png') scene.load.image('waypoint', '/assets/waypoint.png')
/** await loadAllTilesIntoScene(scene)
* Because Phaser can't load tiles after the scene with map in it is created,
* we need to load and cache all the tiles first.
* Then load them into the scene.
*/
scene.load.rexAwait(async function (successCallback: any) {
const tiles: { data: TextureData[] } = await fetch(config.server_endpoint + '/assets/list_tiles').then((response) => response.json())
for await (const tile of tiles?.data ?? []) { await new Promise<void>((resolve) => {
await loadTexture(scene, tile) scene.load.on(Phaser.Loader.Events.COMPLETE, () => {
} resolve()
})
successCallback() isLoaded.value = true
}) })
} }

View File

@ -1,34 +0,0 @@
export function createSceneLoader(scene: Phaser.Scene) {
const width = scene.cameras.main.width
const height = scene.cameras.main.height
const progressBox = scene.add.graphics()
const progressBar = scene.add.graphics()
progressBox.fillStyle(0x222222, 0.8)
progressBox.fillRect(width / 2 - 180, height / 2, 320, 50)
const loadingText = scene.make.text({
x: width / 2,
y: height / 2 - 50,
text: 'Loading...',
style: {
font: '20px monospace',
// @ts-ignore
fill: '#ffffff'
}
})
loadingText.setOrigin(0.5, 0.5)
scene.load.on(Phaser.Loader.Events.PROGRESS, function (value: any) {
progressBar.clear()
progressBar.fillStyle(0x368f8b, 1)
progressBar.fillRect(width / 2 - 180 + 10, height / 2 + 10, 300 * value, 30)
})
scene.load.on(Phaser.Loader.Events.COMPLETE, function () {
progressBar.destroy()
progressBox.destroy()
loadingText.destroy()
return true
})
}

View File

@ -26,7 +26,6 @@ export async function loadTexture(scene: Phaser.Scene, textureData: TextureData)
// If asset is not found, download it // If asset is not found, download it
if (!texture) { if (!texture) {
console.log('Downloading texture:', textureData.key)
await textureStorage.download(textureData) await textureStorage.download(textureData)
texture = await textureStorage.get(textureData.key) texture = await textureStorage.get(textureData.key)
} }
@ -58,20 +57,18 @@ export async function loadTexture(scene: Phaser.Scene, textureData: TextureData)
} }
export async function loadSpriteTextures(scene: Phaser.Scene, sprite_id: string) { export async function loadSpriteTextures(scene: Phaser.Scene, sprite_id: string) {
if (!sprite_id) return if (!sprite_id) return false
console.log(sprite_id)
// @TODO: Fix this // @TODO: Fix this
const spriteStorage = new SpriteStorage() const spriteStorage = new SpriteStorage()
const sprite = await spriteStorage.get(sprite_id) const sprite = await spriteStorage.get(sprite_id)
if (!sprite) { if (!sprite) {
console.error('Failed to load sprite:', sprite_id) console.error('Failed to load sprite:', sprite_id)
return return false
} }
for await (const sprite_action of sprite.spriteActions) { for await (const sprite_action of sprite.spriteActions) {
console.log('Loading sprite action:', sprite.id + '-' + sprite_action.action)
const key = sprite.id + '-' + sprite_action.action const key = sprite.id + '-' + sprite_action.action
await loadTexture(scene, { await loadTexture(scene, {
key, key,
@ -102,5 +99,5 @@ export async function loadSpriteTextures(scene: Phaser.Scene, sprite_id: string)
repeat: -1 repeat: -1
}) })
} }
return Promise.resolve(true) return true
} }

View File

@ -2,22 +2,22 @@ import config from '@/application/config'
import type { HttpResponse, TextureData, UUID } from '@/application/types' import type { HttpResponse, TextureData, UUID } from '@/application/types'
import { unduplicateArray } from '@/application/utilities' import { unduplicateArray } from '@/application/utilities'
import { loadTexture } from '@/composables/gameComposable' import { loadTexture } from '@/composables/gameComposable'
import { MapStorage } from '@/storage/storages' import { MapStorage, TileStorage } from '@/storage/storages'
import Tilemap = Phaser.Tilemaps.Tilemap import Tilemap = Phaser.Tilemaps.Tilemap
import TilemapLayer = Phaser.Tilemaps.TilemapLayer import TilemapLayer = Phaser.Tilemaps.TilemapLayer
import Tileset = Phaser.Tilemaps.Tileset import Tileset = Phaser.Tilemaps.Tileset
import Tile = Phaser.Tilemaps.Tile import Tile = Phaser.Tilemaps.Tile
export function getTile(layer: TilemapLayer | Tilemap, positionX: number, positionY: number): Tile | undefined { export function getTile(layer: TilemapLayer | Tilemap, positionX: number, positionY: number): Tile | null {
const tile = layer.getTileAtWorldXY(positionX, positionY) const tile = layer?.getTileAtWorldXY(positionX, positionY)
if (!tile) return undefined if (!tile) return null
return tile return tile
} }
export function tileToWorldXY(layer: TilemapLayer | Tilemap, positionX: number, positionY: number) { export function tileToWorldXY(layer: TilemapLayer | Tilemap, positionX: number, positionY: number) {
const worldPoint = layer.tileToWorldXY(positionX, positionY) const worldPoint = layer.tileToWorldXY(positionX, positionY)
if (!worldPoint) return { positionX: 0, positionY: 0 } if (!worldPoint) return { worldPositionX: 0, worldPositionY: 0 }
const worldPositionX = worldPoint.x + config.tile_size.height const worldPositionX = worldPoint.x + config.tile_size.height
const worldPositionY = worldPoint.y const worldPositionY = worldPoint.y
@ -88,19 +88,54 @@ export function FlattenMapArray(tiles: string[][]) {
} }
export async function loadMapTilesIntoScene(map_id: UUID, scene: Phaser.Scene) { export async function loadMapTilesIntoScene(map_id: UUID, scene: Phaser.Scene) {
const tileStorage = new TileStorage()
const mapStorage = new MapStorage() const mapStorage = new MapStorage()
const map = await mapStorage.get(map_id) const map = await mapStorage.get(map_id)
if (!map) return if (!map) return
const tileArray = unduplicateArray(FlattenMapArray(map.tiles)) const tileArray = unduplicateArray(FlattenMapArray(map.tiles))
const tiles = await tileStorage.getByIds(tileArray)
// Load each tile into the scene // Load each tile into the scene
for (const tile of tileArray) { for (const tile of tiles) {
const textureData = { const textureData = {
key: tile, key: tile.id,
data: '/textures/tiles/' + tile + '.png', data: '/textures/tiles/' + tile.id + '.png',
group: 'tiles', group: 'tiles',
updatedAt: map.updatedAt // @TODO: Fix this updatedAt: tile.updatedAt
} as TextureData
await loadTexture(scene, textureData)
}
}
export async function loadTilesIntoScene(tileIds: string[], scene: Phaser.Scene) {
const tileStorage = new TileStorage()
const tiles = await tileStorage.getByIds(tileIds)
// Load each tile into the scene
for (const tile of tiles) {
const textureData = {
key: tile.id,
data: '/textures/tiles/' + tile.id + '.png',
group: 'tiles',
updatedAt: tile.updatedAt
} as TextureData
await loadTexture(scene, textureData)
}
}
export async function loadAllTilesIntoScene(scene: Phaser.Scene) {
const tileStorage = new TileStorage()
const tiles = await tileStorage.getAll()
// Load each tile into the scene
for (const tile of tiles) {
const textureData = {
key: tile.id,
data: '/textures/tiles/' + tile.id + '.png',
group: 'tiles',
updatedAt: tile.updatedAt
} as TextureData } as TextureData
await loadTexture(scene, textureData) await loadTexture(scene, textureData)
} }

View File

@ -2,41 +2,57 @@ import config from '@/application/config'
import { getTile, tileToWorldXY } from '@/composables/mapComposable' import { getTile, tileToWorldXY } from '@/composables/mapComposable'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useMapEditorStore } from '@/stores/mapEditorStore' import { useMapEditorStore } from '@/stores/mapEditorStore'
import { computed, type Ref } from 'vue' import { computed, ref, type Ref } from 'vue'
export function useMapEditorPointerHandlers(scene: Phaser.Scene, layer: Phaser.Tilemaps.TilemapLayer, waypoint: Ref<{ visible: boolean; x: number; y: number }>, camera: Phaser.Cameras.Scene2D.Camera) { export function useMapEditorPointerHandlers(scene: Phaser.Scene, layer: Phaser.Tilemaps.TilemapLayer, waypoint: Ref<{ visible: boolean; x: number; y: number }>, camera: Phaser.Cameras.Scene2D.Camera) {
const gameStore = useGameStore() const gameStore = useGameStore()
const mapEditorStore = useMapEditorStore() const mapEditorStore = useMapEditorStore()
const isMoveTool = computed(() => mapEditorStore.tool === 'move') const isMoveTool = computed(() => mapEditorStore.tool === 'move')
const pointerStartPosition = ref({ x: 0, y: 0 })
const dragThreshold = 5 // pixels
function updateWaypoint(pointer: Phaser.Input.Pointer) { function updateWaypoint(worldX: number, worldY: number) {
const { x: px, y: py } = camera.getWorldPoint(pointer.x, pointer.y) const pointerTile = getTile(layer, worldX, worldY)
const pointerTile = getTile(layer, px, py) if (!pointerTile) {
if (pointerTile) {
const worldPoint = tileToWorldXY(layer, pointerTile.x, pointerTile.y)
if (!worldPoint.positionX || !worldPoint.positionY) return
waypoint.value = {
visible: true,
x: worldPoint.positionX,
y: worldPoint.positionY + config.tile_size.height + 15
}
} else {
waypoint.value.visible = false waypoint.value.visible = false
return
}
const worldPoint = tileToWorldXY(layer, pointerTile.x, pointerTile.y)
if (!worldPoint.worldPositionX || !worldPoint.worldPositionX) return
waypoint.value = {
visible: true,
x: worldPoint.worldPositionX,
y: worldPoint.worldPositionY + config.tile_size.height + 15
}
}
function handlePointerDown(pointer: Phaser.Input.Pointer) {
pointerStartPosition.value = { x: pointer.x, y: pointer.y }
if (isMoveTool.value || pointer.event.shiftKey) {
gameStore.setPlayerDraggingCamera(true)
} }
} }
function dragMap(pointer: Phaser.Input.Pointer) { function dragMap(pointer: Phaser.Input.Pointer) {
if (!gameStore.game.isPlayerDraggingCamera) return if (!gameStore.game.isPlayerDraggingCamera) return
camera.setScroll(camera.scrollX - (pointer.x - pointer.prevPosition.x) / camera.zoom, scrollY - (pointer.y - pointer.prevPosition.y) / camera.zoom)
const distance = Phaser.Math.Distance.Between(pointerStartPosition.value.x, pointerStartPosition.value.y, pointer.x, pointer.y)
if (distance <= dragThreshold) return
camera.setScroll(camera.scrollX - (pointer.x - pointer.prevPosition.x) / camera.zoom, camera.scrollY - (pointer.y - pointer.prevPosition.y) / camera.zoom)
} }
function handlePointerMove(pointer: Phaser.Input.Pointer) { function handlePointerMove(pointer: Phaser.Input.Pointer) {
if (isMoveTool.value || pointer.event.shiftKey) { if (isMoveTool.value || pointer.event.shiftKey) {
dragMap(pointer) dragMap(pointer)
} }
updateWaypoint(pointer) updateWaypoint(pointer.worldX, pointer.worldY)
}
function handlePointerUp(pointer: Phaser.Input.Pointer) {
gameStore.setPlayerDraggingCamera(false)
} }
function handleZoom(pointer: Phaser.Input.Pointer) { function handleZoom(pointer: Phaser.Input.Pointer) {
@ -50,12 +66,16 @@ export function useMapEditorPointerHandlers(scene: Phaser.Scene, layer: Phaser.T
} }
const setupPointerHandlers = () => { const setupPointerHandlers = () => {
scene.input.on(Phaser.Input.Events.POINTER_DOWN, handlePointerDown)
scene.input.on(Phaser.Input.Events.POINTER_MOVE, handlePointerMove) scene.input.on(Phaser.Input.Events.POINTER_MOVE, handlePointerMove)
scene.input.on(Phaser.Input.Events.POINTER_UP, handlePointerUp)
scene.input.on(Phaser.Input.Events.POINTER_WHEEL, handleZoom) scene.input.on(Phaser.Input.Events.POINTER_WHEEL, handleZoom)
} }
const cleanupPointerHandlers = () => { const cleanupPointerHandlers = () => {
scene.input.off(Phaser.Input.Events.POINTER_DOWN, handlePointerDown)
scene.input.off(Phaser.Input.Events.POINTER_MOVE, handlePointerMove) scene.input.off(Phaser.Input.Events.POINTER_MOVE, handlePointerMove)
scene.input.off(Phaser.Input.Events.POINTER_UP, handlePointerUp)
scene.input.off(Phaser.Input.Events.POINTER_WHEEL, handleZoom) scene.input.off(Phaser.Input.Events.POINTER_WHEEL, handleZoom)
} }

View File

@ -4,10 +4,10 @@ export class BaseStorage<T extends { id: string }> {
protected dexie: Dexie protected dexie: Dexie
protected tableName: string protected tableName: string
constructor(tableName: string, schema: string) { constructor(tableName: string, schema: string, version = 1) {
this.tableName = tableName this.tableName = tableName
this.dexie = new Dexie(tableName) this.dexie = new Dexie(tableName)
this.dexie.version(1).stores({ this.dexie.version(version).stores({
[tableName]: schema [tableName]: schema
}) })
} }
@ -33,6 +33,16 @@ export class BaseStorage<T extends { id: string }> {
} }
} }
async getByIds(ids: string[]): Promise<T[]> {
try {
const items = await this.dexie.table(this.tableName).bulkGet(ids)
return items.filter((item) => item !== null)
} catch (error) {
console.error(`Failed to retrieve ${this.tableName} by ids:`, error)
return []
}
}
async getAll(): Promise<T[]> { async getAll(): Promise<T[]> {
try { try {
return await this.dexie.table(this.tableName).toArray() return await this.dexie.table(this.tableName).toArray()

View File

@ -34,10 +34,7 @@ export const useGameStore = defineStore('game', {
} }
}, },
getters: { getters: {
getLoadedAssets: (state) => { isTextureLoaded: (state) => {
return state.game.loadedTextures
},
isAssetLoaded: (state) => {
return (key: string) => { return (key: string) => {
return state.game.loadedTextures.includes(key) return state.game.loadedTextures.includes(key)
} }