diff --git a/package-lock.json b/package-lock.json index 92b9d132..1599d4cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "izowave", - "version": "1.17.1", + "version": "1.17.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "izowave", - "version": "1.17.1", + "version": "1.17.3", "license": "GNU", "dependencies": { "events": "3.3.0", @@ -14,7 +14,7 @@ "heap": "0.2.7", "idb": "7.1.1", "phaser": "3.60.0", - "phaser-react-ui": "1.14.3", + "phaser-react-ui": "1.14.5", "phaser3-rex-plugins": "1.60.6", "react": "18.2.0", "react-dom": "18.2.0", @@ -22,14 +22,14 @@ "uuid": "9.0.1" }, "devDependencies": { - "@types/heap": "0.2.32", - "@types/jest": "29.5.5", - "@types/node": "20.8.2", + "@types/heap": "0.2.33", + "@types/jest": "29.5.7", + "@types/node": "20.8.10", "@types/react": "18.2.25", "@types/react-dom": "18.2.10", "@types/styled-components": "5.1.29", - "@types/uuid": "9.0.4", - "@vitejs/plugin-react": "4.1.0", + "@types/uuid": "9.0.6", + "@vitejs/plugin-react": "4.1.1", "alias-reuse": "2.0.0", "eslint": "8.51.0", "eslint-config-neki": "1.3.0", @@ -90,25 +90,25 @@ } }, "node_modules/@babel/core": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz", - "integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz", + "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.9", - "@babel/helper-compilation-targets": "^7.22.9", - "@babel/helper-module-transforms": "^7.22.9", - "@babel/helpers": "^7.22.6", - "@babel/parser": "^7.22.7", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.8", - "@babel/types": "^7.22.5", - "convert-source-map": "^1.7.0", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.0", + "@babel/helpers": "^7.23.2", + "@babel/parser": "^7.23.0", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.0", + "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", + "json5": "^2.2.3", "semver": "^6.3.1" }, "engines": { @@ -276,13 +276,13 @@ } }, "node_modules/@babel/helpers": { - "version": "7.23.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.1.tgz", - "integrity": "sha512-chNpneuK18yW5Oxsr+t553UZzzAs3aZnFm4bxhebsNTeshrC95yA7l5yl7GBAG+JG1rF0F7zzD2EixK9mWSDoA==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz", + "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==", "dev": true, "dependencies": { "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.0", + "@babel/traverse": "^7.23.2", "@babel/types": "^7.23.0" }, "engines": { @@ -548,9 +548,9 @@ } }, "node_modules/@babel/traverse": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.0.tgz", - "integrity": "sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", "dev": true, "dependencies": { "@babel/code-frame": "^7.22.13", @@ -1751,12 +1751,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/@jest/transform/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, "node_modules/@jest/transform/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2000,9 +1994,9 @@ } }, "node_modules/@types/babel__core": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.2.tgz", - "integrity": "sha512-pNpr1T1xLUc2l3xJKuPtsEky3ybxN3m4fJkknfIpTCTfIZCDW57oAg+EfCgIIp2rvCe0Wn++/FfodDS4YXxBwA==", + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.3.tgz", + "integrity": "sha512-54fjTSeSHwfan8AyHWrKbfBWiEUrNTZsUwPTDSNaaP1QDQIZbeNUg3a59E9D+375MzUw/x1vx2/0F5LBz+AeYA==", "dev": true, "dependencies": { "@babel/parser": "^7.20.7", @@ -2050,9 +2044,9 @@ } }, "node_modules/@types/heap": { - "version": "0.2.32", - "resolved": "https://registry.npmjs.org/@types/heap/-/heap-0.2.32.tgz", - "integrity": "sha512-GeKFLHmmYx6RIhSMFSXDj7UUVETilQv/JELLiqCYq1ntH0UBVA4a3AIJz2bsUNvLHIDTo2V0QA0CQ4UtfTmrNg==", + "version": "0.2.33", + "resolved": "https://registry.npmjs.org/@types/heap/-/heap-0.2.33.tgz", + "integrity": "sha512-BYVVtgDmRkBIciM2+Uf0RvOdFFdLkO4xRKwRBoFzXIoOpNZcUR+euvr1OYmLR6UXvgg0ZoB3qvlUi6CWspbZag==", "dev": true }, "node_modules/@types/hoist-non-react-statics": { @@ -2090,9 +2084,9 @@ } }, "node_modules/@types/jest": { - "version": "29.5.5", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.5.tgz", - "integrity": "sha512-ebylz2hnsWR9mYvmBFbXJXr+33UPc4+ZdxyDXh5w0FlPBTfCVN3wPL+kuOiQt3xvrK419v7XWeAs+AeOksafXg==", + "version": "29.5.7", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.7.tgz", + "integrity": "sha512-HLyetab6KVPSiF+7pFcUyMeLsx25LDNDemw9mGsJBkai/oouwrjTycocSDYopMEwFhN2Y4s9oPyOCZNofgSt2g==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -2125,10 +2119,13 @@ "peer": true }, "node_modules/@types/node": { - "version": "20.8.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz", - "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==", - "dev": true + "version": "20.8.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.10.tgz", + "integrity": "sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@types/prop-types": { "version": "15.7.5", @@ -2198,9 +2195,9 @@ "dev": true }, "node_modules/@types/uuid": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.4.tgz", - "integrity": "sha512-zAuJWQflfx6dYJM62vna+Sn5aeSWhh3OB+wfUEACNcqUSc0AGc5JKl+ycL1vrH7frGTXhJchYjE1Hak8L819dA==", + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.6.tgz", + "integrity": "sha512-BT2Krtx4xaO6iwzwMFUYvWBWkV2pr37zD68Vmp1CDV196MzczBRxuEpD6Pr395HAgebC/co7hOphs53r8V7jew==", "dev": true }, "node_modules/@types/yargs": { @@ -2523,15 +2520,15 @@ } }, "node_modules/@vitejs/plugin-react": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.1.0.tgz", - "integrity": "sha512-rM0SqazU9iqPUraQ2JlIvReeaxOoRj6n+PzB1C0cBzIbd8qP336nC39/R9yPi3wVcah7E7j/kdU1uCUqMEU4OQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.1.1.tgz", + "integrity": "sha512-Jie2HERK+uh27e+ORXXwEP5h0Y2lS9T2PRGbfebiHGlwzDO0dEnd2aNtOR/qjBlPb1YgxwAONeblL1xqLikLag==", "dev": true, "dependencies": { - "@babel/core": "^7.22.20", + "@babel/core": "^7.23.2", "@babel/plugin-transform-react-jsx-self": "^7.22.5", "@babel/plugin-transform-react-jsx-source": "^7.22.5", - "@types/babel__core": "^7.20.2", + "@types/babel__core": "^7.20.3", "react-refresh": "^0.14.0" }, "engines": { @@ -2541,42 +2538,6 @@ "vite": "^4.2.0" } }, - "node_modules/@vitejs/plugin-react/node_modules/@babel/core": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.0.tgz", - "integrity": "sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-module-transforms": "^7.23.0", - "@babel/helpers": "^7.23.0", - "@babel/parser": "^7.23.0", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.0", - "@babel/types": "^7.23.0", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@vitejs/plugin-react/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, "node_modules/abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", @@ -3343,9 +3304,9 @@ "peer": true }, "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, "node_modules/core-util-is": { @@ -8175,9 +8136,9 @@ } }, "node_modules/phaser-react-ui": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/phaser-react-ui/-/phaser-react-ui-1.14.3.tgz", - "integrity": "sha512-oATH1RUMdpUwvVziZse5UuByeAHlrFj/gFDbgvaPy4RzcoMN06hjCnzEH33nDXbPqD5oMDgm4dJ/CI8jvUcQJw==" + "version": "1.14.5", + "resolved": "https://registry.npmjs.org/phaser-react-ui/-/phaser-react-ui-1.14.5.tgz", + "integrity": "sha512-k0cbf/OPS89HXOzQ+Wq5DWHkotwNI8QSjC7meGW9eb1RBD5EbmQ6q1RSQvx26PsPa/El0jSBNkkjCoVKhZWZ0w==" }, "node_modules/phaser3-rex-plugins": { "version": "1.60.6", @@ -9449,6 +9410,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "node_modules/universalify": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", @@ -9539,12 +9506,6 @@ "node": ">=10.12.0" } }, - "node_modules/v8-to-istanbul/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, "node_modules/vite": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", @@ -10227,25 +10188,25 @@ "dev": true }, "@babel/core": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz", - "integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz", + "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==", "dev": true, "requires": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.9", - "@babel/helper-compilation-targets": "^7.22.9", - "@babel/helper-module-transforms": "^7.22.9", - "@babel/helpers": "^7.22.6", - "@babel/parser": "^7.22.7", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.8", - "@babel/types": "^7.22.5", - "convert-source-map": "^1.7.0", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.0", + "@babel/helpers": "^7.23.2", + "@babel/parser": "^7.23.0", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.0", + "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", + "json5": "^2.2.3", "semver": "^6.3.1" } }, @@ -10364,13 +10325,13 @@ "dev": true }, "@babel/helpers": { - "version": "7.23.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.1.tgz", - "integrity": "sha512-chNpneuK18yW5Oxsr+t553UZzzAs3aZnFm4bxhebsNTeshrC95yA7l5yl7GBAG+JG1rF0F7zzD2EixK9mWSDoA==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz", + "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==", "dev": true, "requires": { "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.0", + "@babel/traverse": "^7.23.2", "@babel/types": "^7.23.0" } }, @@ -10555,9 +10516,9 @@ } }, "@babel/traverse": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.0.tgz", - "integrity": "sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", "dev": true, "requires": { "@babel/code-frame": "^7.22.13", @@ -11352,12 +11313,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -11556,9 +11511,9 @@ "dev": true }, "@types/babel__core": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.2.tgz", - "integrity": "sha512-pNpr1T1xLUc2l3xJKuPtsEky3ybxN3m4fJkknfIpTCTfIZCDW57oAg+EfCgIIp2rvCe0Wn++/FfodDS4YXxBwA==", + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.3.tgz", + "integrity": "sha512-54fjTSeSHwfan8AyHWrKbfBWiEUrNTZsUwPTDSNaaP1QDQIZbeNUg3a59E9D+375MzUw/x1vx2/0F5LBz+AeYA==", "dev": true, "requires": { "@babel/parser": "^7.20.7", @@ -11606,9 +11561,9 @@ } }, "@types/heap": { - "version": "0.2.32", - "resolved": "https://registry.npmjs.org/@types/heap/-/heap-0.2.32.tgz", - "integrity": "sha512-GeKFLHmmYx6RIhSMFSXDj7UUVETilQv/JELLiqCYq1ntH0UBVA4a3AIJz2bsUNvLHIDTo2V0QA0CQ4UtfTmrNg==", + "version": "0.2.33", + "resolved": "https://registry.npmjs.org/@types/heap/-/heap-0.2.33.tgz", + "integrity": "sha512-BYVVtgDmRkBIciM2+Uf0RvOdFFdLkO4xRKwRBoFzXIoOpNZcUR+euvr1OYmLR6UXvgg0ZoB3qvlUi6CWspbZag==", "dev": true }, "@types/hoist-non-react-statics": { @@ -11646,9 +11601,9 @@ } }, "@types/jest": { - "version": "29.5.5", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.5.tgz", - "integrity": "sha512-ebylz2hnsWR9mYvmBFbXJXr+33UPc4+ZdxyDXh5w0FlPBTfCVN3wPL+kuOiQt3xvrK419v7XWeAs+AeOksafXg==", + "version": "29.5.7", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.7.tgz", + "integrity": "sha512-HLyetab6KVPSiF+7pFcUyMeLsx25LDNDemw9mGsJBkai/oouwrjTycocSDYopMEwFhN2Y4s9oPyOCZNofgSt2g==", "dev": true, "requires": { "expect": "^29.0.0", @@ -11681,10 +11636,13 @@ "peer": true }, "@types/node": { - "version": "20.8.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz", - "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==", - "dev": true + "version": "20.8.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.10.tgz", + "integrity": "sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w==", + "dev": true, + "requires": { + "undici-types": "~5.26.4" + } }, "@types/prop-types": { "version": "15.7.5", @@ -11754,9 +11712,9 @@ "dev": true }, "@types/uuid": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.4.tgz", - "integrity": "sha512-zAuJWQflfx6dYJM62vna+Sn5aeSWhh3OB+wfUEACNcqUSc0AGc5JKl+ycL1vrH7frGTXhJchYjE1Hak8L819dA==", + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.6.tgz", + "integrity": "sha512-BT2Krtx4xaO6iwzwMFUYvWBWkV2pr37zD68Vmp1CDV196MzczBRxuEpD6Pr395HAgebC/co7hOphs53r8V7jew==", "dev": true }, "@types/yargs": { @@ -11969,47 +11927,16 @@ } }, "@vitejs/plugin-react": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.1.0.tgz", - "integrity": "sha512-rM0SqazU9iqPUraQ2JlIvReeaxOoRj6n+PzB1C0cBzIbd8qP336nC39/R9yPi3wVcah7E7j/kdU1uCUqMEU4OQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.1.1.tgz", + "integrity": "sha512-Jie2HERK+uh27e+ORXXwEP5h0Y2lS9T2PRGbfebiHGlwzDO0dEnd2aNtOR/qjBlPb1YgxwAONeblL1xqLikLag==", "dev": true, "requires": { - "@babel/core": "^7.22.20", + "@babel/core": "^7.23.2", "@babel/plugin-transform-react-jsx-self": "^7.22.5", "@babel/plugin-transform-react-jsx-source": "^7.22.5", - "@types/babel__core": "^7.20.2", + "@types/babel__core": "^7.20.3", "react-refresh": "^0.14.0" - }, - "dependencies": { - "@babel/core": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.0.tgz", - "integrity": "sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ==", - "dev": true, - "requires": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-module-transforms": "^7.23.0", - "@babel/helpers": "^7.23.0", - "@babel/parser": "^7.23.0", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.0", - "@babel/types": "^7.23.0", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - } - }, - "convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - } } }, "abab": { @@ -12577,9 +12504,9 @@ "peer": true }, "convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, "core-util-is": { @@ -16184,9 +16111,9 @@ } }, "phaser-react-ui": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/phaser-react-ui/-/phaser-react-ui-1.14.3.tgz", - "integrity": "sha512-oATH1RUMdpUwvVziZse5UuByeAHlrFj/gFDbgvaPy4RzcoMN06hjCnzEH33nDXbPqD5oMDgm4dJ/CI8jvUcQJw==" + "version": "1.14.5", + "resolved": "https://registry.npmjs.org/phaser-react-ui/-/phaser-react-ui-1.14.5.tgz", + "integrity": "sha512-k0cbf/OPS89HXOzQ+Wq5DWHkotwNI8QSjC7meGW9eb1RBD5EbmQ6q1RSQvx26PsPa/El0jSBNkkjCoVKhZWZ0w==" }, "phaser3-rex-plugins": { "version": "1.60.6", @@ -17127,6 +17054,12 @@ "which-boxed-primitive": "^1.0.2" } }, + "undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "universalify": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", @@ -17182,14 +17115,6 @@ "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", "convert-source-map": "^2.0.0" - }, - "dependencies": { - "convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - } } }, "vite": { diff --git a/package.json b/package.json index 265b27bd..9e4b49b4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "izowave", "description": "Isometric game. Build and defense in open world", - "version": "1.17.1", + "version": "1.17.3", "keywords": [ "game", "isometric", @@ -27,14 +27,14 @@ "lint": "eslint \"./**/*.{js,ts,tsx}\" --ignore-path .gitignore --fix" }, "devDependencies": { - "@types/heap": "0.2.32", - "@types/jest": "29.5.5", - "@types/node": "20.8.2", + "@types/heap": "0.2.33", + "@types/jest": "29.5.7", + "@types/node": "20.8.10", "@types/react": "18.2.25", "@types/react-dom": "18.2.10", "@types/styled-components": "5.1.29", - "@types/uuid": "9.0.4", - "@vitejs/plugin-react": "4.1.0", + "@types/uuid": "9.0.6", + "@vitejs/plugin-react": "4.1.1", "alias-reuse": "2.0.0", "eslint": "8.51.0", "eslint-config-neki": "1.3.0", @@ -55,7 +55,7 @@ "heap": "0.2.7", "idb": "7.1.1", "phaser": "3.60.0", - "phaser-react-ui": "1.14.3", + "phaser-react-ui": "1.14.5", "phaser3-rex-plugins": "1.60.6", "react": "18.2.0", "react-dom": "18.2.0", diff --git a/src/game/scenes/world/effects/particles-manager.ts b/src/game/scenes/world/effects/particles-manager.ts new file mode 100644 index 00000000..329fbc35 --- /dev/null +++ b/src/game/scenes/world/effects/particles-manager.ts @@ -0,0 +1,301 @@ +import { ENEMY_SIZE_PARAMS, ENEMY_TEXTURE_SIZE } from '~const/world/entities/enemy'; +import { Environment } from '~lib/environment'; +import { GameFlag, GameSettings } from '~type/game'; +import { IWorld } from '~type/world'; +import { IParticlesParent, ParticlesTexture } from '~type/world/effects'; +import { IParticlesManager } from '~type/world/effects/particles-manager'; +import { IBuilding } from '~type/world/entities/building'; +import { INPC } from '~type/world/entities/npc'; +import { EnemyTexture, IEnemy } from '~type/world/entities/npc/enemy'; +import { IPlayer } from '~type/world/entities/player'; +import { ISprite } from '~type/world/entities/sprite'; +import { PositionAtWorld } from '~type/world/level'; + +import { Particles } from './particles'; + +export class ParticlesManager implements IParticlesManager { + private scene: IWorld; + + constructor(scene: IWorld) { + this.scene = scene; + } + + public createDustEffect(parent: IPlayer) { + if (!this.isEffectsEnabled()) { + return null; + } + + return new Particles(parent, { + key: 'dust', + texture: ParticlesTexture.BIT, + dynamic: true, + params: { + followOffset: { + x: 0, + y: -parent.gamut * parent.scaleY * 0.5, + }, + lifespan: { min: 150, max: 300 }, + scale: 0.6, + speed: 10, + frequency: 150, + alpha: { start: 1.0, end: 0.0 }, + emitting: false, + }, + }); + } + + public createBloodEffect(parent: ISprite) { + if ( + !parent.active + || !Environment.GetFlag(GameFlag.BLOOD) + || !this.isEffectsEnabled() + || ParticlesManager.IsExist(parent, 'blood') + ) { + return null; + } + + const scale = Math.min(2.0, parent.displayWidth / 22); + + return new Particles(parent, { + key: 'blood', + texture: ParticlesTexture.BIT_SOFT, + dynamic: true, + params: { + duration: 250, + followOffset: parent.getBodyOffset(), + lifespan: { min: 100, max: 250 }, + scale: { start: scale, end: scale * 0.25 }, + speed: 60, + maxAliveParticles: 6, + tint: 0xdd1e1e, + }, + }); + } + + public createFrozeEffect(parent: INPC) { + if ( + !parent.active + || !this.isEffectsEnabled() + || ParticlesManager.IsExist(parent, 'froze') + ) { + return null; + } + + const lifespan = Math.min(400, parent.displayWidth * 8); + + return new Particles(parent, { + key: 'froze', + texture: ParticlesTexture.BIT_SOFT, + dynamic: true, + params: { + duration: lifespan, + followOffset: parent.getBodyOffset(), + color: [0xffffff, 0x8cf9ff, 0x00f2ff], + colorEase: 'quad.out', + lifespan: { min: lifespan / 2, max: lifespan }, + scale: { start: 1.0, end: 0.5 }, + speed: 80, + }, + }); + } + + public createFireEffect(parent: IEnemy) { + if ( + !parent.active + || !this.isEffectsEnabled() + || ParticlesManager.IsExist(parent, 'fire') + ) { + return null; + } + + const lifespan = parent.displayWidth * 6; + const scale = Math.min(2.0, parent.displayWidth / 22); + + return new Particles(parent, { + key: 'fire', + texture: ParticlesTexture.BIT_SOFT, + dynamic: true, + params: { + duration: lifespan, + followOffset: parent.getBodyOffset(), + color: [0xfacc22, 0xf89800, 0xf83600, 0x9f0404], + colorEase: 'quad.out', + lifespan: { min: lifespan / 2, max: lifespan }, + scale: { start: scale, end: scale * 0.2 }, + alpha: { start: 1.0, end: 0.0 }, + speed: 80, + }, + }); + } + + public createLongFireEffect(parent: IEnemy, params: { duration: number }) { + if (!parent.active || !this.isEffectsEnabled()) { + return null; + } + + const lifespan = parent.displayWidth * 25; + + return new Particles(parent, { + key: 'long-fire', + texture: ParticlesTexture.BIT_SOFT, + dynamic: true, + params: { + followOffset: parent.getBodyOffset(), + duration: params.duration, + color: [0xfacc22, 0xf89800, 0xf83600, 0x9f0404], + colorEase: 'quad.out', + lifespan: { min: lifespan / 2, max: lifespan }, + alpha: { start: 1.0, end: 0.0 }, + angle: { min: -100, max: -80 }, + scale: { + start: parent.displayWidth / 20, + end: 1.0, + ease: 'sine.out', + }, + speed: 40, + advance: 10, + }, + }); + } + + public createLazerEffect(parent: IEnemy) { + if ( + !parent.active + || !this.isEffectsEnabled() + || ParticlesManager.IsExist(parent, 'lazer') + ) { + return null; + } + + const lifespan = parent.displayWidth * 5; + const scale = Math.min(2.25, parent.displayWidth / 18); + + return new Particles(parent, { + key: 'lazer', + texture: ParticlesTexture.BIT_SOFT, + dynamic: true, + params: { + duration: lifespan, + followOffset: parent.getBodyOffset(), + lifespan: { min: lifespan / 2, max: lifespan }, + scale: { start: scale, end: scale * 0.2 }, + alpha: { start: 1.0, end: 0.0 }, + speed: 80, + tint: 0xb136ff, + }, + }); + } + + public createGlowEffect(parent: IParticlesParent, params: { speed: number; color: number }) { + if (!parent.active || !this.isEffectsEnabled()) { + return null; + } + + return new Particles(parent, { + key: 'glow', + texture: ParticlesTexture.GLOW, + dynamic: true, + params: { + scale: 0.2 * parent.scale, + alpha: { start: 1.0, end: 0.0 }, + lifespan: 20000 / params.speed, + frequency: 10000 / params.speed, + tint: params.color, + blendMode: 'ADD', + }, + }); + } + + public createSpawnEffect(parent: IEnemy) { + if (!this.isEffectsEnabled()) { + return null; + } + + // Native body.center isn't working at current state + const size = ENEMY_SIZE_PARAMS[ENEMY_TEXTURE_SIZE[parent.texture.key as EnemyTexture]]; + const position: PositionAtWorld = { + x: parent.x, + y: parent.y - size.height / 2, + }; + const duration = Math.min(700, parent.displayHeight * 17); + const scale = parent.displayWidth / 16; + + return new Particles(parent, { + key: 'spawn', + texture: ParticlesTexture.BIT_SOFT, + position, + params: { + duration, + lifespan: { min: duration / 2, max: duration }, + scale: { start: scale, end: scale / 2 }, + alpha: { start: 1.0, end: 0.0 }, + speed: 40, + quantity: 1, + tint: 0x000000, + }, + }); + } + + public createHealEffect(parent: ISprite, params: { duration: number }) { + if ( + !this.isEffectsEnabled() + || ParticlesManager.IsExist(parent, 'heal') + ) { + return null; + } + + return new Particles(parent, { + key: 'heal', + texture: ParticlesTexture.PLUS, + dynamic: true, + params: { + followOffset: { + x: 0, + y: -parent.displayHeight, + }, + duration: params.duration, + lifespan: params.duration, + alpha: { start: 1.0, end: 0.0 }, + angle: { + min: -110, + max: -70, + }, + scale: { + start: 1.0, + end: 0.5, + }, + speed: 20, + maxAliveParticles: 1, + }, + }); + } + + public createGenerationEffect(parent: IBuilding) { + if (!this.isEffectsEnabled()) { + return null; + } + + return new Particles(parent, { + key: 'generate', + texture: ParticlesTexture.BIT, + position: parent.getTopFace(), + params: { + duration: 300, + lifespan: { min: 100, max: 200 }, + scale: { start: 1.0, end: 0.5 }, + alpha: { start: 1.0, end: 0.0 }, + speed: 60, + maxAliveParticles: 8, + tint: 0x2dffb2, + }, + }); + } + + private isEffectsEnabled() { + return this.scene.game.isSettingEnabled(GameSettings.EFFECTS); + } + + static IsExist(parent: IParticlesParent, key: string) { + return Boolean(parent.effects?.[key]); + } +} diff --git a/src/game/scenes/world/effects/particles.ts b/src/game/scenes/world/effects/particles.ts index 6968e0a7..6be6c41f 100644 --- a/src/game/scenes/world/effects/particles.ts +++ b/src/game/scenes/world/effects/particles.ts @@ -1,5 +1,3 @@ -import { v4 as uuidv4 } from 'uuid'; - import { WORLD_DEPTH_EFFECT } from '~const/world'; import { Assets } from '~lib/assets'; import { IWorld } from '~type/world'; @@ -24,21 +22,17 @@ export class Particles implements IParticles { constructor( parent: IParticlesParent, { - key, position, texture, params, dynamic, replay = false, + key, position, texture, params, dynamic, }: ParticlesData, ) { this.scene = parent.scene; this.parent = parent; - this.key = key ?? uuidv4(); + this.key = key; if (!this.parent.effects) { this.parent.effects = {}; } else if (this.parent.effects[this.key]) { - if (replay) { - this.parent.effects[this.key].destroy(); - } else { - return; - } + this.parent.effects[this.key].destroy(); } this.parent.effects[this.key] = this; diff --git a/src/game/scenes/world/entities/building/variants/generator.ts b/src/game/scenes/world/entities/building/variants/generator.ts index 034834eb..c76fcc29 100644 --- a/src/game/scenes/world/entities/building/variants/generator.ts +++ b/src/game/scenes/world/entities/building/variants/generator.ts @@ -1,12 +1,9 @@ import { DIFFICULTY } from '~const/world/difficulty'; import { Building } from '~entity/building'; import { Tutorial } from '~lib/tutorial'; -import { Particles } from '~scene/world/effects'; -import { GameSettings } from '~type/game'; import { LangPhrase } from '~type/lang'; import { TutorialStep } from '~type/tutorial'; import { IWorld } from '~type/world'; -import { ParticlesTexture } from '~type/world/effects'; import { BuildingTexture, BuildingVariant, @@ -73,22 +70,6 @@ export class BuildingGenerator extends Building { private generateResource() { this.scene.player.giveResources(1); - - if (this.scene.game.isSettingEnabled(GameSettings.EFFECTS)) { - new Particles(this, { - key: 'generate', - texture: ParticlesTexture.BIT, - position: this.getTopFace(), - params: { - duration: 300, - lifespan: { min: 100, max: 200 }, - scale: { start: 1.0, end: 0.5 }, - alpha: { start: 1.0, end: 0.0 }, - speed: 60, - maxAliveParticles: 8, - tint: 0x2dffb2, - }, - }); - } + this.scene.particles.createGenerationEffect(this); } } diff --git a/src/game/scenes/world/entities/npc/npc.ts b/src/game/scenes/world/entities/npc/npc.ts index 4bfee732..427da55b 100644 --- a/src/game/scenes/world/entities/npc/npc.ts +++ b/src/game/scenes/world/entities/npc/npc.ts @@ -6,11 +6,8 @@ import { NPC_PATH_FIND_RATE } from '~const/world/entities/npc'; import { LEVEL_MAP_PERSPECTIVE } from '~const/world/level'; import { Sprite } from '~entity/sprite'; import { isPositionsEqual, getIsometricAngle, getIsometricDistance } from '~lib/dimension'; -import { Particles } from '~scene/world/effects'; import { Level } from '~scene/world/level'; -import { GameSettings } from '~type/game'; import { IWorld } from '~type/world'; -import { ParticlesTexture } from '~type/world/effects'; import { EntityType } from '~type/world/entities'; import { INPC, NPCData } from '~type/world/entities/npc'; import { PositionAtWorld } from '~type/world/level'; @@ -87,37 +84,18 @@ export class NPC extends Sprite implements INPC { public freeze(duration: number, effects: boolean = false) { this.freezeTimestamp = this.scene.getTime() + duration; - if (!effects) { - return; - } - - if (this.freezeEffectTimer) { - this.freezeEffectTimer.elapsed = 0; - } else { - this.setTint(0x00f2ff); - this.freezeEffectTimer = this.scene.time.delayedCall(duration, () => { - this.clearTint(); - this.freezeEffectTimer = null; - }); - } + if (effects) { + this.scene.particles.createFrozeEffect(this); - if (this.scene.game.isSettingEnabled(GameSettings.EFFECTS)) { - const lifespan = Math.min(400, this.displayWidth * 8); - - new Particles(this, { - key: 'freeze', - texture: ParticlesTexture.BIT_SOFT, - dynamic: true, - params: { - duration: lifespan, - followOffset: this.getBodyOffset(), - color: [0xffffff, 0x8cf9ff, 0x00f2ff], - colorEase: 'quad.out', - lifespan: { min: lifespan / 2, max: lifespan }, - scale: { start: 1.0, end: 0.5 }, - speed: 80, - }, - }); + if (this.freezeEffectTimer) { + this.freezeEffectTimer.elapsed = 0; + } else { + this.setTint(0x00f2ff); + this.freezeEffectTimer = this.scene.time.delayedCall(duration, () => { + this.clearTint(); + this.freezeEffectTimer = null; + }); + } } } diff --git a/src/game/scenes/world/entities/npc/variants/enemy/enemy.ts b/src/game/scenes/world/entities/npc/variants/enemy/enemy.ts index ce4f58f1..244be48d 100644 --- a/src/game/scenes/world/entities/npc/variants/enemy/enemy.ts +++ b/src/game/scenes/world/entities/npc/variants/enemy/enemy.ts @@ -10,17 +10,17 @@ import { NPC } from '~entity/npc'; import { Assets } from '~lib/assets'; import { Environment } from '~lib/environment'; import { progressionLinear, progressionQuadratic } from '~lib/progression'; -import { Effect, Particles } from '~scene/world/effects'; +import { Effect } from '~scene/world/effects'; import { GameFlag, GameSettings } from '~type/game'; import { InterfaceFont } from '~type/interface'; import { IWorld } from '~type/world'; -import { EffectTexture, ParticlesTexture } from '~type/world/effects'; +import { EffectTexture } from '~type/world/effects'; import { EntityType } from '~type/world/entities'; import { IEnemyTarget, EnemyData, EnemyTexture, IEnemy, EnemyAudio, } from '~type/world/entities/npc/enemy'; import { PlayerEvents, PlayerSuperskill } from '~type/world/entities/player'; -import { PositionAtWorld, TileType } from '~type/world/level'; +import { TileType } from '~type/world/level'; Assets.RegisterAudio(EnemyAudio); Assets.RegisterSprites(EnemyTexture, (texture) => ( @@ -250,37 +250,6 @@ export class Enemy extends NPC implements IEnemy { }); } - private addFireEffect(duration: number) { - if (!this.scene.game.isSettingEnabled(GameSettings.EFFECTS)) { - return; - } - - const lifespan = this.displayWidth * 25; - - new Particles(this, { - key: 'fire', - texture: ParticlesTexture.BIT_SOFT, - dynamic: true, - replay: true, - params: { - followOffset: this.getBodyOffset(), - duration, - color: [0xfacc22, 0xf89800, 0xf83600, 0x9f0404], - colorEase: 'quad.out', - lifespan: { min: lifespan / 2, max: lifespan }, - alpha: { start: 1.0, end: 0.0 }, - angle: { min: -100, max: -80 }, - scale: { - start: this.displayWidth / 20, - end: 1.0, - ease: 'sine.out', - }, - speed: 40, - advance: 10, - }, - }); - } - private addBloodEffect() { if ( !this.currentBiome?.solid @@ -320,31 +289,7 @@ export class Enemy extends NPC implements IEnemy { }); }, 0); - if (this.scene.game.isSettingEnabled(GameSettings.EFFECTS)) { - // Native body.center isn't working at current state - const size = ENEMY_SIZE_PARAMS[ENEMY_TEXTURE_SIZE[this.texture.key as EnemyTexture]]; - const position: PositionAtWorld = { - x: this.x, - y: this.y - size.height / 2, - }; - const duration = Math.min(700, this.displayHeight * 17); - const scale = this.displayWidth / 16; - - new Particles(this, { - key: 'spawn', - texture: ParticlesTexture.BIT_SOFT, - position, - params: { - duration, - lifespan: { min: duration / 2, max: duration }, - scale: { start: scale, end: scale / 2 }, - alpha: { start: 1.0, end: 0.0 }, - speed: 40, - quantity: 1, - tint: 0x000000, - }, - }); - } + this.scene.particles.createSpawnEffect(this); } private handlePlayerSuperskill() { @@ -370,7 +315,7 @@ export class Enemy extends NPC implements IEnemy { retardationLevel: DIFFICULTY.ENEMY_HEALTH_GROWTH_RETARDATION_LEVEL, }) * DIFFICULTY.SUPERSKILL_FIRE_FORCE; - this.addFireEffect(duration); + this.scene.particles.createLongFireEffect(this, { duration }); this.addOngoingDamage(damage, duration); break; } diff --git a/src/game/scenes/world/entities/npc/variants/enemy/variants/telepath.ts b/src/game/scenes/world/entities/npc/variants/enemy/variants/telepath.ts index 657b1515..8994d709 100644 --- a/src/game/scenes/world/entities/npc/variants/enemy/variants/telepath.ts +++ b/src/game/scenes/world/entities/npc/variants/enemy/variants/telepath.ts @@ -3,10 +3,7 @@ import { } from '~const/world/entities/enemy'; import { LEVEL_MAP_PERSPECTIVE } from '~const/world/level'; import { getIsometricDistance } from '~lib/dimension'; -import { Particles } from '~scene/world/effects'; -import { GameSettings } from '~type/game'; import { IWorld } from '~type/world'; -import { ParticlesTexture } from '~type/world/effects'; import { EntityType } from '~type/world/entities'; import { EnemyVariantData, EnemyTexture, IEnemy } from '~type/world/entities/npc/enemy'; @@ -89,32 +86,9 @@ export class EnemyTelepath extends Enemy { enemy.live.addHealth(healthAmount); - if (this.scene.game.isSettingEnabled(GameSettings.EFFECTS)) { - new Particles(enemy, { - key: 'regeneration', - texture: ParticlesTexture.PLUS, - dynamic: true, - params: { - followOffset: { - x: 0, - y: -enemy.displayHeight, - }, - duration: ENEMY_REGENERATION_EFFECT_DURATION, - lifespan: ENEMY_REGENERATION_EFFECT_DURATION, - alpha: { start: 1.0, end: 0.0 }, - angle: { - min: -110, - max: -70, - }, - scale: { - start: 1.0, - end: 0.5, - }, - speed: 20, - maxAliveParticles: 1, - }, - }); - } + this.scene.particles.createHealEffect(enemy, { + duration: ENEMY_REGENERATION_EFFECT_DURATION, + }); }); } } diff --git a/src/game/scenes/world/entities/player.ts b/src/game/scenes/world/entities/player.ts index c4b0c38c..34cd745c 100644 --- a/src/game/scenes/world/entities/player.ts +++ b/src/game/scenes/world/entities/player.ts @@ -13,16 +13,14 @@ import { Crystal } from '~entity/crystal'; import { Sprite } from '~entity/sprite'; import { Assets } from '~lib/assets'; import { getClosestByIsometricDistance, isPositionsEqual } from '~lib/dimension'; -import { Environment } from '~lib/environment'; import { progressionLinear, progressionQuadratic } from '~lib/progression'; import { Tutorial } from '~lib/tutorial'; import { eachEntries } from '~lib/utils'; -import { Particles } from '~scene/world/effects'; import { Level } from '~scene/world/level'; -import { GameEvents, GameFlag, GameSettings } from '~type/game'; +import { GameEvents, GameSettings } from '~type/game'; import { TutorialStep } from '~type/tutorial'; import { IWorld, WorldEvents, WorldMode } from '~type/world'; -import { IParticles, ParticlesTexture } from '~type/world/effects'; +import { IParticles } from '~type/world/effects'; import { EntityType } from '~type/world/entities'; import { BuildingVariant } from '~type/world/entities/building'; import { ICrystal } from '~type/world/entities/crystal'; @@ -483,25 +481,7 @@ export class Player extends Sprite implements IPlayer { this.scene.game.sound.play(audio); } - if ( - this.scene.game.isSettingEnabled(GameSettings.EFFECTS) - && Environment.GetFlag(GameFlag.BLOOD) - ) { - new Particles(this, { - key: 'blood', - texture: ParticlesTexture.BIT_SOFT, - dynamic: true, - params: { - duration: 200, - followOffset: this.getBodyOffset(), - lifespan: { min: 100, max: 250 }, - scale: { start: 1.0, end: 0.25 }, - speed: 60, - maxAliveParticles: 6, - tint: 0xdd1e1e, - }, - }); - } + this.scene.particles.createBloodEffect(this); super.onDamage(amount); } @@ -695,30 +675,11 @@ export class Player extends Sprite implements IPlayer { } private addDustEffect() { - if ( - this.dustEffect - || !this.scene.game.isSettingEnabled(GameSettings.EFFECTS) - ) { + if (this.dustEffect) { return; } - this.dustEffect = new Particles(this, { - key: 'dust', - texture: ParticlesTexture.BIT, - dynamic: true, - params: { - followOffset: { - x: 0, - y: -this.gamut * this.scaleY * 0.5, - }, - lifespan: { min: 150, max: 300 }, - scale: 0.6, - speed: 10, - frequency: 150, - alpha: { start: 1.0, end: 0.0 }, - emitting: false, - }, - }); + this.dustEffect = this.scene.particles.createDustEffect(this); } private removeDustEffect() { diff --git a/src/game/scenes/world/entities/shot/ball/ball.ts b/src/game/scenes/world/entities/shot/ball/ball.ts index 1047bdd7..d35cc73a 100644 --- a/src/game/scenes/world/entities/shot/ball/ball.ts +++ b/src/game/scenes/world/entities/shot/ball/ball.ts @@ -3,10 +3,8 @@ import Phaser from 'phaser'; import { Analytics } from '~lib/analytics'; import { Assets } from '~lib/assets'; import { getIsometricDistance } from '~lib/dimension'; -import { Particles } from '~scene/world/effects'; -import { GameSettings } from '~type/game'; import { IWorld } from '~type/world'; -import { ParticlesTexture } from '~type/world/effects'; +import { IParticles } from '~type/world/effects'; import { EntityType } from '~type/world/entities'; import { IEnemy } from '~type/world/entities/npc/enemy'; import { @@ -30,7 +28,7 @@ export class ShotBall extends Phaser.Physics.Arcade.Image implements IShotBall { private audio: ShotBallAudio; - private effect: Nullable = null; + private effect: Nullable = null; private startPosition: Nullable = null; @@ -118,19 +116,10 @@ export class ShotBall extends Phaser.Physics.Arcade.Image implements IShotBall { this.setActive(true); this.setVisible(true); - if (this.glow && this.scene.game.isSettingEnabled(GameSettings.EFFECTS)) { - this.effect = new Particles(this, { - key: 'glow', - texture: ParticlesTexture.GLOW, - dynamic: true, - params: { - scale: 0.2 * this.scale, - alpha: { start: 1.0, end: 0.0 }, - lifespan: 20000 / this.params.speed, - frequency: 10000 / this.params.speed, - tint: this.color, - blendMode: 'ADD', - }, + if (this.glow) { + this.effect = this.scene.particles.createGlowEffect(this, { + speed: this.params.speed, + color: this.color, }); } diff --git a/src/game/scenes/world/entities/shot/ball/variants/fire.ts b/src/game/scenes/world/entities/shot/ball/variants/fire.ts index 0310da25..4bff6e2e 100644 --- a/src/game/scenes/world/entities/shot/ball/variants/fire.ts +++ b/src/game/scenes/world/entities/shot/ball/variants/fire.ts @@ -1,9 +1,6 @@ import { SHOT_BALL_DAMAGE_SPREAD_FACTOR, SHOT_BALL_DAMAGE_SPREAD_MAX_DISTANCE } from '~const/world/entities/shot'; import { getIsometricDistance } from '~lib/dimension'; -import { Particles } from '~scene/world/effects'; -import { GameSettings } from '~type/game'; import { IWorld } from '~type/world'; -import { ParticlesTexture } from '~type/world/effects'; import { EntityType } from '~type/world/entities'; import { IEnemy } from '~type/world/entities/npc/enemy'; import { ShotBallAudio, ShotData, ShotParams } from '~type/world/entities/shot'; @@ -23,26 +20,7 @@ export class ShotBallFire extends ShotBall { public hit(target: IEnemy) { super.hit(target); - if (this.scene.game.isSettingEnabled(GameSettings.EFFECTS)) { - const lifespan = target.displayWidth * 5; - const scale = Math.min(2.0, target.displayWidth / 22); - - new Particles(target, { - key: 'fire-mini', - texture: ParticlesTexture.BIT_SOFT, - dynamic: true, - params: { - duration: lifespan, - followOffset: target.getBodyOffset(), - color: [0xfacc22, 0xf89800, 0xf83600, 0x9f0404], - colorEase: 'quad.out', - lifespan: { min: lifespan / 2, max: lifespan }, - scale: { start: scale, end: scale * 0.2 }, - alpha: { start: 1.0, end: 0.0 }, - speed: 80, - }, - }); - } + this.scene.particles.createFireEffect(target); if (this.params.damage) { this.spreadDamage(target, this.params.damage * SHOT_BALL_DAMAGE_SPREAD_FACTOR); diff --git a/src/game/scenes/world/entities/shot/ball/variants/simple.ts b/src/game/scenes/world/entities/shot/ball/variants/simple.ts index e19a5846..cd795c5d 100644 --- a/src/game/scenes/world/entities/shot/ball/variants/simple.ts +++ b/src/game/scenes/world/entities/shot/ball/variants/simple.ts @@ -1,8 +1,4 @@ -import { Environment } from '~lib/environment'; -import { Particles } from '~scene/world/effects'; -import { GameSettings, GameFlag } from '~type/game'; import { IWorld } from '~type/world'; -import { ParticlesTexture } from '~type/world/effects'; import { IEnemy } from '~type/world/entities/npc/enemy'; import { ShotBallAudio, ShotData, ShotParams } from '~type/world/entities/shot'; @@ -20,27 +16,7 @@ export class ShotBallSimple extends ShotBall { public hit(target: IEnemy) { super.hit(target); - if ( - this.scene.game.isSettingEnabled(GameSettings.EFFECTS) - && Environment.GetFlag(GameFlag.BLOOD) - ) { - const scale = Math.min(2.0, target.displayWidth / 22); - - new Particles(target, { - key: 'blood', - texture: ParticlesTexture.BIT_SOFT, - dynamic: true, - params: { - duration: 200, - followOffset: target.getBodyOffset(), - lifespan: { min: 100, max: 250 }, - scale: { start: scale, end: scale * 0.25 }, - speed: 60, - maxAliveParticles: 6, - tint: 0xdd1e1e, - }, - }); - } + this.scene.particles.createBloodEffect(target); if (this.params.damage) { target.live.damage(this.params.damage); diff --git a/src/game/scenes/world/entities/shot/lazer.ts b/src/game/scenes/world/entities/shot/lazer.ts index f26be6df..d74995b9 100644 --- a/src/game/scenes/world/entities/shot/lazer.ts +++ b/src/game/scenes/world/entities/shot/lazer.ts @@ -104,25 +104,7 @@ export class ShotLazer extends Phaser.GameObjects.Line implements IShotLazer { return; } - if (this.scene.game.isSettingEnabled(GameSettings.EFFECTS)) { - const lifespan = this.target.displayWidth * 5; - const scale = Math.min(2.25, this.target.displayWidth / 18); - - new Particles(this.target, { - key: 'lazer', - texture: ParticlesTexture.BIT_SOFT, - dynamic: true, - params: { - duration: lifespan, - followOffset: this.target.getBodyOffset(), - lifespan: { min: lifespan / 2, max: lifespan }, - scale: { start: scale, end: scale * 0.2 }, - alpha: { start: 1.0, end: 0.0 }, - speed: 80, - tint: 0xb136ff, - }, - }); - } + this.scene.particles.createLazerEffect(this.target); const momentDamage = this.params.damage / SHOT_LAZER_REPEAT; diff --git a/src/game/scenes/world/world.ts b/src/game/scenes/world/world.ts index a93f4c61..15f37838 100644 --- a/src/game/scenes/world/world.ts +++ b/src/game/scenes/world/world.ts @@ -14,6 +14,7 @@ import { progressionLinear } from '~lib/progression'; import { hashString } from '~lib/utils'; import { Builder } from '~scene/world/builder'; import { Camera } from '~scene/world/camera'; +import { ParticlesManager } from '~scene/world/effects/particles-manager'; import { WorldUI } from '~scene/world/interface'; import { Level } from '~scene/world/level'; import { Spawner } from '~scene/world/spawner'; @@ -25,6 +26,7 @@ import { } from '~type/world'; import { IBuilder } from '~type/world/builder'; import { ICamera } from '~type/world/camera'; +import { IParticlesManager } from '~type/world/effects/particles-manager'; import { EntityType } from '~type/world/entities'; import { BuildingVariant, IBuilding } from '~type/world/entities/building'; import { ICrystal } from '~type/world/entities/crystal'; @@ -78,6 +80,12 @@ export class World extends Scene implements IWorld { private set spawner(v) { this._spawner = v; } + private _particles: IParticlesManager; + + public get particles() { return this._particles; } + + private set particles(v) { this._particles = v; } + private _camera: ICamera; public get camera() { return this._camera; } @@ -109,6 +117,7 @@ export class World extends Scene implements IWorld { this.input.setPollAlways(); this.level = new Level(this, data); + this.particles = new ParticlesManager(this); this.camera = new Camera(this); this.spawner = new Spawner(this); diff --git a/src/types/world/effects/particles-manager.ts b/src/types/world/effects/particles-manager.ts new file mode 100644 index 00000000..afe6ffe5 --- /dev/null +++ b/src/types/world/effects/particles-manager.ts @@ -0,0 +1,19 @@ +import { IParticles, IParticlesParent } from '~type/world/effects/particles'; +import { IBuilding } from '~type/world/entities/building'; +import { INPC } from '~type/world/entities/npc'; +import { IEnemy } from '~type/world/entities/npc/enemy'; +import { IPlayer } from '~type/world/entities/player'; +import { ISprite } from '~type/world/entities/sprite'; + +export interface IParticlesManager { + createBloodEffect(parent: ISprite): Nullable + createFireEffect(parent: IEnemy): Nullable + createLongFireEffect(parent: IEnemy, params: { duration: number }): Nullable + createLazerEffect(parent: IEnemy): Nullable + createGlowEffect(parent: IParticlesParent, params: { speed: number; color: number }): Nullable + createFrozeEffect(parent: INPC): Nullable + createDustEffect(parent: IPlayer): Nullable + createGenerationEffect(parent: IBuilding): Nullable + createSpawnEffect(parent: IEnemy): Nullable + createHealEffect(parent: ISprite, params: { duration: number }): Nullable +} diff --git a/src/types/world/effects/particles.ts b/src/types/world/effects/particles.ts index 3cc64589..8ff45a54 100644 --- a/src/types/world/effects/particles.ts +++ b/src/types/world/effects/particles.ts @@ -37,10 +37,9 @@ export enum ParticlesTexture { } export type ParticlesData = { - key?: string + key: string position?: PositionAtWorld texture: ParticlesTexture dynamic?: boolean - replay?: boolean params: Phaser.Types.GameObjects.Particles.ParticleEmitterConfig }; diff --git a/src/types/world/world.ts b/src/types/world/world.ts index d4e8d8c0..c28ff317 100644 --- a/src/types/world/world.ts +++ b/src/types/world/world.ts @@ -5,6 +5,7 @@ import { IScene } from '~type/scene'; import { StorageSavePayload } from '~type/storage'; import { IBuilder } from '~type/world/builder'; import { ICamera } from '~type/world/camera'; +import { IParticlesManager } from '~type/world/effects/particles-manager'; import { EntityType } from '~type/world/entities'; import { BuildingSavePayload } from '~type/world/entities/building'; import { CrystalSavePayload } from '~type/world/entities/crystal'; @@ -36,6 +37,11 @@ export interface IWorld extends IScene { */ readonly spawner: ISpawner + /** + * Particles manager. + */ + readonly particles: IParticlesManager + /** * Level. */