From bec2cb7016036329d877ce47756b74279290332d Mon Sep 17 00:00:00 2001 From: Histmy Date: Mon, 20 Feb 2023 21:21:55 +0100 Subject: [PATCH] =?UTF-8?q?no,=20=C5=A1achy,=20no?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 375 +++++++++++++++++++++++++++- package.json | 7 +- res/sachy/error.html | 15 ++ res/sachy/index.html | 32 +++ res/sachy/promotion.html | 24 ++ res/sachy/tah.html | 19 ++ src/modules/sachy.ts | 522 +++++++++++++++++++++++++++++++++++++++ src/utils/sachyEtc.ts | 93 +++++++ src/utils/sachyServer.ts | 177 +++++++++++++ 9 files changed, 1253 insertions(+), 11 deletions(-) create mode 100644 res/sachy/error.html create mode 100644 res/sachy/index.html create mode 100644 res/sachy/promotion.html create mode 100644 res/sachy/tah.html create mode 100644 src/modules/sachy.ts create mode 100644 src/utils/sachyEtc.ts create mode 100644 src/utils/sachyServer.ts diff --git a/package-lock.json b/package-lock.json index 0a4948e..bdcbf09 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "denim_3001", - "version": "3001.45.1", + "version": "3001.46.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "denim_3001", - "version": "3001.45.1", + "version": "3001.46.0", "license": "ISC", "dependencies": { "@discordjs/voice": "^0.14.0", @@ -15,13 +15,16 @@ "node-fetch": "^2.6.1", "opusscript": "^0.0.8", "play-dl": "^1.9.6", + "tiny-typed-emitter": "^2.1.0", "tweetnacl": "^1.0.3" }, "devDependencies": { "@types/jest": "^29.2.4", "@types/js-levenshtein": "^1.1.1", "@types/node-fetch": "^2.6.2", - "jest": "^29.3.1" + "jest": "^29.3.1", + "ts-node": "^10.9.1", + "tsconfig-paths": "^4.1.2" } }, "node_modules/@ampproject/remapping": { @@ -608,6 +611,28 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@discordjs/builders": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.4.0.tgz", @@ -1083,6 +1108,30 @@ "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, "node_modules/@types/babel__core": { "version": "7.1.20", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz", @@ -1237,6 +1286,27 @@ "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", "dev": true }, + "node_modules/acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -1289,6 +1359,12 @@ "node": ">= 8" } }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -1620,6 +1696,12 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1684,6 +1766,15 @@ "node": ">=8" } }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/diff-sequences": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.3.1.tgz", @@ -2839,9 +2930,9 @@ "dev": true }, "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "bin": { "json5": "lib/cli.js" @@ -2923,6 +3014,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -2993,6 +3090,15 @@ "node": "*" } }, + "node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -3655,6 +3761,11 @@ "node": ">=8" } }, + "node_modules/tiny-typed-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz", + "integrity": "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==" + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -3708,6 +3819,72 @@ "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.2.tgz", "integrity": "sha512-zvHx3VM83m2WYCE8XL99uaM7mFwYSkjR2OZti98fabHrwkjsCvgwChda5xctein3xGOyaQhtTeDq/1H/GNvF3A==" }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tsconfig-paths": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.1.2.tgz", + "integrity": "sha512-uhxiMgnXQp1IR622dUXI+9Ehnws7i/y6xvpZB9IbUVOPy0muvdvgXeZOn88UcGPiT98Vp3rJPTa8bFoalZ3Qhw==", + "dev": true, + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/tslib": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", @@ -3739,6 +3916,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typescript": { + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/undici": { "version": "5.14.0", "resolved": "https://registry.npmjs.org/undici/-/undici-5.14.0.tgz", @@ -3781,6 +3972,12 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "node_modules/v8-to-istanbul": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", @@ -3937,6 +4134,15 @@ "node": ">=12" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -4393,6 +4599,27 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } + } + }, "@discordjs/builders": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.4.0.tgz", @@ -4768,6 +4995,30 @@ "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, "@types/babel__core": { "version": "7.1.20", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz", @@ -4921,6 +5172,18 @@ "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", "dev": true }, + "acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, "ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -4955,6 +5218,12 @@ "picomatch": "^2.0.4" } }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -5205,6 +5474,12 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -5249,6 +5524,12 @@ "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, "diff-sequences": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.3.1.tgz", @@ -6111,9 +6392,9 @@ "dev": true }, "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true }, "kleur": { @@ -6171,6 +6452,12 @@ "semver": "^6.0.0" } }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -6226,6 +6513,12 @@ "brace-expansion": "^1.1.7" } }, + "minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -6680,6 +6973,11 @@ "minimatch": "^3.0.4" } }, + "tiny-typed-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz", + "integrity": "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==" + }, "tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -6720,6 +7018,46 @@ "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.2.tgz", "integrity": "sha512-zvHx3VM83m2WYCE8XL99uaM7mFwYSkjR2OZti98fabHrwkjsCvgwChda5xctein3xGOyaQhtTeDq/1H/GNvF3A==" }, + "ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + } + }, + "tsconfig-paths": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.1.2.tgz", + "integrity": "sha512-uhxiMgnXQp1IR622dUXI+9Ehnws7i/y6xvpZB9IbUVOPy0muvdvgXeZOn88UcGPiT98Vp3rJPTa8bFoalZ3Qhw==", + "dev": true, + "requires": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true + } + } + }, "tslib": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", @@ -6742,6 +7080,13 @@ "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true }, + "typescript": { + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "dev": true, + "peer": true + }, "undici": { "version": "5.14.0", "resolved": "https://registry.npmjs.org/undici/-/undici-5.14.0.tgz", @@ -6765,6 +7110,12 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "v8-to-istanbul": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", @@ -6882,6 +7233,12 @@ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 8f05391..d902457 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "denim_3001", - "version": "3001.45.1", + "version": "3001.46.0", "description": "Toto je velmi kvalitní bot.", "repository": { "url": "https://github.com/Histmy/Denim-Bot/" @@ -20,12 +20,15 @@ "node-fetch": "^2.6.1", "opusscript": "^0.0.8", "play-dl": "^1.9.6", + "tiny-typed-emitter": "^2.1.0", "tweetnacl": "^1.0.3" }, "devDependencies": { "@types/jest": "^29.2.4", "@types/js-levenshtein": "^1.1.1", "@types/node-fetch": "^2.6.2", - "jest": "^29.3.1" + "jest": "^29.3.1", + "ts-node": "^10.9.1", + "tsconfig-paths": "^4.1.2" } } diff --git a/res/sachy/error.html b/res/sachy/error.html new file mode 100644 index 0000000..23746db --- /dev/null +++ b/res/sachy/error.html @@ -0,0 +1,15 @@ + + + + + + + + Chyba - šach.ml + + + + $error + + + diff --git a/res/sachy/index.html b/res/sachy/index.html new file mode 100644 index 0000000..0877e65 --- /dev/null +++ b/res/sachy/index.html @@ -0,0 +1,32 @@ + + + + + + + + Šach.ml + + + +

Šach.ml

+ +

Vytajte na úvodní stránce DENIM3001 šachů!

+ +

+ + + + + diff --git a/res/sachy/promotion.html b/res/sachy/promotion.html new file mode 100644 index 0000000..e06cff6 --- /dev/null +++ b/res/sachy/promotion.html @@ -0,0 +1,24 @@ + + + + + + + + Proměna + + + +

Gratuluju! Provádíš speciální tah "proměna"!

+ +

Aby ale tento tah mohl být dokončen, vyber, prosím, na co se má tvůj pěšec proměnit:

+ +
+ Královna + Jezdec + Věž + Střelec +
+ + + diff --git a/res/sachy/tah.html b/res/sachy/tah.html new file mode 100644 index 0000000..678da3d --- /dev/null +++ b/res/sachy/tah.html @@ -0,0 +1,19 @@ + + + + + + + + Šach.ml - $title + + + + $content + + + + diff --git a/src/modules/sachy.ts b/src/modules/sachy.ts new file mode 100644 index 0000000..7361dbd --- /dev/null +++ b/src/modules/sachy.ts @@ -0,0 +1,522 @@ +// Jo, šachec, :sjetec: + +import { APIEmbed, Message } from "discord.js"; +import { Modul, SRecord } from "../utils/types"; +import { fokinLookupTable, klikance, pocetKeStrane } from "../utils/sachyEtc"; +import { emiter } from "../utils/sachyServer"; + +const hry: SRecord = {}; +const hraci: SRecord = {}; + +const smery = [-8, 1, 8, -1, -7, 9, 7, -9]; + +const mkPis = (barva: Figurka["barva"], typ: Figurka["typ"]) => ({ barva, typ, netahnuta: true, enPassantovatelna: false }); + +function createGame(kanel: string, bilej: string, cernej: string, mes: Message) { + + const deska: Deska = [...new Array(64)]; + + for (let i = 0; i < 8; i++) { + deska[i + 8] = mkPis("cerna", "pawn"); + deska[i + 48] = mkPis("bila", "pawn"); + } + + deska[0] = mkPis("cerna", "rook"); + deska[7] = mkPis("cerna", "rook"); + deska[56] = mkPis("bila", "rook"); + deska[63] = mkPis("bila", "rook"); + + deska[1] = mkPis("cerna", "knight"); + deska[6] = mkPis("cerna", "knight"); + deska[57] = mkPis("bila", "knight"); + deska[62] = mkPis("bila", "knight"); + + deska[2] = mkPis("cerna", "bishop"); + deska[5] = mkPis("cerna", "bishop"); + deska[58] = mkPis("bila", "bishop"); + deska[61] = mkPis("bila", "bishop"); + + deska[4] = mkPis("cerna", "king"); + deska[60] = mkPis("bila", "king"); + + deska[3] = mkPis("cerna", "queen"); + deska[59] = mkPis("bila", "queen"); + + const hra: Hra = { + bila: bilej, + cerna: cernej, + deska, + hraje: "bila", + tahy: [], + message: mes + }; + + hry[kanel] = hra; + + return hra; +} + +function jeCheck(barva: Hra["hraje"], deska: Deska) { + + let check = false; + const index = deska.findIndex(pis => pis?.typ == "king" && pis.barva == barva); + + // Od tahačů + for (let smer = 0; smer < 8; smer++) { + for (let n = 1; n <= pocetKeStrane[index][smer]; n++) { + + const target = index + smery[smer] * n; + const pisNaTargetu = deska[target]; + + if (pisNaTargetu?.barva != barva && [(smer < 4 ? "rook" : "bishop"), "queen"].includes(pisNaTargetu?.typ || "")) return true; + + if (pisNaTargetu) break; + } + } + + // Od koliků + [[-1, 2], [1, 2], [-2, 1], [2, 1], [-2, -1], [2, -1], [-1, -2], [1, -2]].forEach(smery => { + + const x = smery[0] > 0 ? 1 : 3; + const y = smery[1] > 0 ? 2 : 0; + + // Estli je mimo board + if (pocetKeStrane[index][x] < Math.abs(smery[0]) || pocetKeStrane[index][y] < Math.abs(smery[1])) return; + + const target = index + (8 * smery[1] + smery[0]); + const pis = deska[target]; + + // Estli už tam felí náš + if (pis?.barva == barva) return; + + if (pis?.typ == "knight") check = true; + }); + + // od pawnů + [7, 9].forEach(i => { + let pis = deska[index - i]; + if (pis?.typ == "pawn" && pis.barva != barva) check = true; + }); + + // od králika + for (let smer = 0; smer < 8; smer++) { + if (pocetKeStrane[index][smer] == 0) continue; + + if (deska[index + smery[smer]]?.typ == "king") return true; + } + + return check; +} + +function tahyProJezdiciPisi(index: number, pis: "queen" | "bishop" | "rook", deska: Deska) { + + const tahy: number[] = []; + const barva = deska[index]!.barva; + + const startSmer = pis == "bishop" ? 4 : 0; + const endSmer = pis == "rook" ? 4 : 8; + + for (let smer = startSmer; smer < endSmer; smer++) { + for (let n = 1; n <= pocetKeStrane[index][smer]; n++) { + + const target = index + smery[smer] * n; + const pisNaTargetu = deska[target]; + + if (pisNaTargetu?.barva == barva) break; + + tahy.push(target); + + if (pisNaTargetu && pisNaTargetu.barva != barva) break; + } + } + + return tahy; +} + +function tahyProKoniky(index: number, deska: Deska) { + + const tahy: number[] = []; + const barva = deska[index]!.barva; + + [[-1, 2], [1, 2], [-2, 1], [2, 1], [-2, -1], [2, -1], [-1, -2], [1, -2]].forEach(smery => { + + const x = smery[0] > 0 ? 1 : 3; + const y = smery[1] > 0 ? 2 : 0; + + // Estli je mimo board + if (pocetKeStrane[index][x] < Math.abs(smery[0]) || pocetKeStrane[index][y] < Math.abs(smery[1])) return; + + const target = index + (8 * smery[1] + smery[0]); + const pis = deska[target]; + + // Estli už tam felí náš + if (pis?.barva == barva) return; + + tahy.push(target); + }); + + return tahy; +} + +function tahyProPawny(index: number, deska: Deska) { + + const tahy: number[] = []; + const barva = deska[index]!.barva; + + // Takey + if (index % 8 != 0 && deska[index - 9] && deska[index - 9]!.barva != barva) + tahy.push(index - 9); + + if (index % 8 != 7 && deska[index - 7] && deska[index - 7]!.barva != barva) + tahy.push(index - 7); + + // Blokáda + if (deska[index - 8]) + return tahy; + + tahy.push(index - 8); + + // Double-advance + if (deska[index]?.netahnuta && !deska[index - 16]) + tahy.push(index - 16); + + // en croassant + if (deska[index - 1]?.enPassantovatelna) + tahy.push(index - 9); + + if (deska[index + 1]?.enPassantovatelna) + tahy.push(index - 7); + + return tahy; +} + +function tahyProKrale(index: number, deska: Deska) { + + const tahy: number[] = []; + const barva = deska[index]!.barva; + + for (let smer = 0; smer < 8; smer++) { + const target = index + smery[smer]; + if (pocetKeStrane[index][smer] != 0 && deska[target]?.barva != barva) tahy.push(target); + } + + // Castling + if (jeCheck(barva, deska)) return tahy; + for (let strana = 0; strana < 2; strana++) { + + const offset = (barva == "bila" ? (strana ? 3 : -4) : (strana ? 4 : -3)); + const rook = deska[index + offset]; + + if (deska[index]!.netahnuta && rook?.typ == "rook" && rook.netahnuta) { + let muze = true; + for (let i = (strana > 0 ? 1 : -1); (strana > 0 ? i < offset : i > offset); strana > 0 ? i++ : i--) { + if (deska[index + i]) { + muze = false; + break; + } + + const novaDeska = [...deska]; + novaDeska[index + i] = deska[index]; + novaDeska[index] = undefined; + if (jeCheck(barva, novaDeska)) + muze = false; + } + + if (muze) tahy.push(index + (2 * (offset > 0 ? 1 : -1))); + } + } + + return tahy; +} + +function legalniTahy(index: number, deska: Deska) { + + let tahy: number[]; + const pis = deska[index]!; + + if (pis.typ == "queen" || pis.typ == "bishop" || pis.typ == "rook") + tahy = tahyProJezdiciPisi(index, pis.typ, deska); + + else if (pis.typ == "knight") + tahy = tahyProKoniky(index, deska); + + else if (pis.typ == "pawn") + tahy = tahyProPawny(index, deska); + + else + tahy = tahyProKrale(index, deska); + + + // Otestovat jestli jsou fakt legální + for (let i = 0; i < tahy.length; i++) { + const tah = tahy[i]; + + if (jeCheck(pis.barva, udelejTah(index, tah, deska))) { + tahy.splice(i, 1); + i--; + } + }; + + return tahy; +} + +function udelejTah(z: number, kam: number, deska: Deska, fakt?: true) { + + const mojeDeska = [...deska]; + const pis = mojeDeska[z]!; + + if (fakt) pis.netahnuta = false; + + mojeDeska[kam] = pis; + mojeDeska[z] = undefined; + + // croassant + if (pis.typ == "pawn" && mojeDeska[kam + 8]?.enPassantovatelna) + mojeDeska[kam + 8] = undefined; + + if (fakt) + mojeDeska.forEach(pole => { + if (!pole) return; + + pole.enPassantovatelna = false; + }); + + if (fakt && pis.typ == "pawn" && z - kam == 16) pis.enPassantovatelna = true; + + + // Castling + const rozdil = z - kam; + if (pis.typ == "king" && Math.abs(rozdil) == 2) { + const i = (rozdil > 0 ? 56 : 63); + mojeDeska[(rozdil > 0 ? kam + 1 : kam - 1)] = mojeDeska[i]; + mojeDeska[i] = undefined; + } + + return mojeDeska; +} + +function renderHra(hra: Hra, konec?: true) { + const deska = [...hra.deska]; + const vybranejPis = hra.vybranejPis; + + const embed: APIEmbed = { + fields: [ + { + name: "Sachy sou", + value: "", + inline: true + }, + { + name: "gamesa vole", + value: "", + inline: true + } + ] + }; + + hra.tahy = []; + + if (typeof vybranejPis == "number") hra.tahy = legalniTahy(vybranejPis, deska); + + for (let i = 0; i < 64; i++) { + const figurka = deska[i]; + const klikanec = klikance[i]; + + const prvniDuhy = (i % 8) < 4 ? 0 : 1; + const field = embed.fields![prvniDuhy]; + + const cernyPozadi = (Math.floor(i / 8) + (i % 8)) % 2; + + if (!figurka) { + + field.value += hra.tahy.includes(i) + ? (cernyPozadi ? `[<:h:1066376051422404628>](http://šach.ml/${klikanec})` : `[<:h:1066376343807336488>](http://šach.ml/${klikanec})`) + : (cernyPozadi ? "🟩" : "⬜"); + + } else { + + let klic = (cernyPozadi ? "g" : "w") + (figurka.barva == "bila" ? "w" : "b") + figurka.typ; + if (hra.tahy.includes(i)) klic += "t"; + if (figurka.typ == "king" && figurka.barva == hra.hraje && jeCheck(figurka.barva, deska)) klic += "c"; + const emout = fokinLookupTable[klic]; + const figurkaStr = `<:h:${emout}>`; + + if (!konec && figurka.barva == hra.hraje || hra.tahy.includes(i)) { + field.value += `[${figurkaStr}](http://šach.ml/${klikanec})`; + } else { + field.value += figurkaStr; + } + + } + + if (i % 8 == 3 || i % 8 == 7) field.value += "\n"; + + } + + return embed; + +} + +function konec(mes: Message, hra: Hra, duvod: string) { + mes.edit({ content: `hra zkoncila ${duvod}`, embeds: [renderHra(hra, true)] }); + + delete hraci[hra.bila]; + delete hraci[hra.cerna]; + delete hry[mes.channelId]; +} + +function prekreslitHru(hra: Hra) { + const mes = hra.message; + + // Checkmate + if (jeCheck(hra.hraje, hra.deska)) { + let mat = true; + + hra.deska.forEach((pole, i) => { + if (!pole || pole.barva != hra.hraje) return; + + if (legalniTahy(i, hra.deska).length != 0) mat = false; + }); + + if (mat) + return konec(mes, hra, `${hra.hraje} je zasachmatovana`); + + } + + // Stalemate + let pat = true; + hra.deska.forEach((pole, i) => { + if (!pole || pole.barva != hra.hraje) return; + + if (legalniTahy(i, hra.deska).length != 0) pat = false; + }); + + if (pat) + return konec(mes, hra, `achylova sytuace`); + + mes.edit({ content: "", embeds: [renderHra(hra)] }); +} + +emiter.on("tah", (hrac, policko, respond, promo) => { + const channelId = hraci[hrac]; + if (!channelId) return respond("Však vůbec nehraješ ty magore"); + + const hra = hry[channelId]; + const barva = hra.bila == hrac ? "bila" : "cerna"; + if (hra.hraje != barva) return respond("Teď nehraješ ty ty magore"); + + const index = klikance.findIndex(e => e == policko); + + if (typeof index != "number") return respond("Co to meleš za hovna?"); + + // Kliknul na stejnej pis + if (hra.vybranejPis == index) { + + hra.vybranejPis = undefined; + + prekreslitHru(hra); + return respond(); + } + + // Kliknul nějakej pis + const pis = hra.deska[index]; + if (pis && pis.barva == barva) { + + hra.vybranejPis = index; + + prekreslitHru(hra); + return respond(); + } + + // Táhnul + if (typeof hra.vybranejPis == "number" && hra.tahy.includes(index)) { + + // Promotuje + if (hra.deska[hra.vybranejPis!]?.typ == "pawn" && index < 8) { + if (!promo) return respond("--promote--"); + + const promoNa = promo == "q" ? "queen" : + promo == "r" ? "rook" : + promo == "n" ? "knight" : + promo == "b" ? "bishop" : undefined; + + if (!promoNa) return respond("Co to meleš za hovna?"); + + hra.deska[hra.vybranejPis] = mkPis(barva, promoNa); + } + + hra.deska = udelejTah(hra.vybranejPis, index, hra.deska, true); + + hra.vybranejPis = undefined; + + hra.hraje = barva == "bila" ? "cerna" : "bila"; + + hra.deska = hra.deska.reduce((acc, item) => [item].concat(acc), []); + + prekreslitHru(hra); + return respond(); + } + + respond("cos to tam zandal"); +}); + +const exp: Modul = { + more_komandy: { + + sachy: { + DMUnsafe: true, + run: async mes => { + + if (hry[mes.channelId]) return "nejze tady se us hraej"; + + const druhej = mes.mentions.members?.first()?.id; + if (!druhej) return "no sam asi hrat nebudez vet"; + + for (const player of [mes.author.id, druhej]) { + if (hraci[player]) return "zakaz symultanki"; + }; + + const message = await mes.channel.send("hraj zopiciva"); + + const hra = createGame(mes.channelId, mes.author.id, druhej, message); + hraci[mes.author.id] = mes.channelId; + hraci[druhej] = mes.channelId; + + message.edit({ content: "", embeds: [renderHra(hra)] }); + + } + }, + + jasevzdavam: mes => { + + if (!hraci[mes.author.id]) return "vsak nehrajes magore"; + + const hra = hry[mes.channelId]; + if (!hra) return "tadi nehrajes"; + + konec(hra.message, hra, `${mes.author} je pusi`); + } + + } +}; + +module.exports = exp; + +type Hra = { + bila: string; + cerna: string; + deska: Deska; + hraje: "bila" | "cerna"; + tahy: number[]; + vybranejPis?: number; + message: Message; +}; + +type Deska = (Figurka | undefined)[]; + +type Figurka = { + barva: "bila" | "cerna"; + typ: "pawn" | "rook" | "knight" | "bishop" | "queen" | "king"; + netahnuta: boolean; + enPassantovatelna: boolean; +}; diff --git a/src/utils/sachyEtc.ts b/src/utils/sachyEtc.ts new file mode 100644 index 0000000..8e4c7b2 --- /dev/null +++ b/src/utils/sachyEtc.ts @@ -0,0 +1,93 @@ +import { Message } from "discord.js"; +import { SRecord } from "./types"; + +export const fokinLookupTable: SRecord = { + wwking: "1045048659508727961", + gwking: "1045048657826824243", + wbking: "1039994234553507860", + gbking: "1039994216673185843", + + wwrook: "1039994248273072228", + gwrook: "1039994231395192903", + wbrook: "1039994241100820500", + gbrook: "1039994225380573194", + + wwknight: "1039994245412565012", + gwknight: "1039994228559843328", + wbknight: "1039994236348661820", + gbknight: "1039994219110088726", + + wwbishop: "1039994244158459924", + gwbishop: "1039994226844373023", + wbbishop: "1039994232842240162", + gbbishop: "1039994215217778738", + + wwqueen: "1039990754434625656", + gwqueen: "1039991198309425172", + wbqueen: "1039994239729287230", + gbqueen: "1039994224025817138", + + wwpawn: "1039994246888964106", + gwpawn: "1039994230027858030", + wbpawn: "1039994237887975494", + gbpawn: "1039994222306152498", + + wwrookt: "1066376081478778930", + gwrookt: "1066376061392261121", + wbrookt: "1066376070586179724", + gbrookt: "1066376049732091955", + + wwknightt: "1066376345598316655", + gwknightt: "1066376055646060585", + wbknightt: "1066376065422991470", + gbknightt: "1066376042425622650", + + wwbishopt: "1066376074033897522", + gwbishopt: "1066376054169669672", + wbbishopt: "1066376063862718464", + gbbishopt: "1066371034795753522", + + wwqueent: "1066376348609818624", + gwqueent: "1066376059546775612", + wbqueent: "1066376340770652232", + gbqueent: "1066376047194550402", + + wwpawnt: "1066376078119141456", + gwpawnt: "1066376057009217586", + wbpawnt: "1066376067956363294", + gbpawnt: "1066376044975751268", + + wwkingc: "1068186011311542343", + gwkingc: "1068186006869778533", + wbkingc: "1068186008824320134", + gbkingc: "1068186004386758706" +}; + +export const klikance = [ + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "-", "_" +]; + +export const pocetKeStrane: number[][] = []; + +for (let sloupec = 0; sloupec < 8; sloupec++) { + for (let radek = 0; radek < 8; radek++) { + + const nahoru = radek; + const dolu = 7 - radek; + const vlevo = sloupec; + const vpravo = 7 - sloupec; + + const index = 8 * radek + sloupec; + + pocetKeStrane[index] = [ + nahoru, + vpravo, + dolu, + vlevo, + Math.min(nahoru, vpravo), + Math.min(vpravo, dolu), + Math.min(dolu, vlevo), + Math.min(vlevo, nahoru) + ]; + } +} diff --git a/src/utils/sachyServer.ts b/src/utils/sachyServer.ts new file mode 100644 index 0000000..8373ed7 --- /dev/null +++ b/src/utils/sachyServer.ts @@ -0,0 +1,177 @@ +import { createServer, IncomingMessage, ServerResponse } from "http"; +import { SRecord } from "./types"; +import { join } from "path"; +import { readFileSync } from "fs"; +import fetch from "node-fetch"; +import { TypedEmitter } from "tiny-typed-emitter"; +import { log, rand } from "./utils"; + +const basePath = join(__dirname, "../../res/sachy"); +const sessions: SRecord = {}; + +const indexStranka = readFileSync(`${basePath}/index.html`).toString(); +const tahStranka = readFileSync(`${basePath}/tah.html`).toString(); +const promoStranka = readFileSync(`${basePath}/promotion.html`).toString(); +const chybaStranka = readFileSync(`${basePath}/error.html`).toString(); + +interface Eventy { + tah: (playerId: string, square: string, verify: (err?: string) => void, promotionType?: string) => void; +} + +export const emiter = new TypedEmitter(); + +function parseCookies(cookies?: string) { + const list: SRecord = {}; + if (!cookies) return list; + + cookies.split(`;`).forEach(function (cookie) { + let [name, ...rest] = cookie.split(`=`); + name = name?.trim(); + if (!name) return; + const value = rest.join(`=`).trim(); + if (!value) return; + list[name] = decodeURIComponent(value); + }); + + return list; +} + +function generateId() { + while (true) { + const id = Math.round(Math.random() * 3554597877099506 + 101560562963469).toString(36); + if (!Object.keys(sessions).includes(id)) return id; + } +} + +function startSession(req: IncomingMessage, res: ServerResponse): Session { + + const cookies = parseCookies(req.headers.cookie); + const sessionId = cookies.sachySession; + + // Jestli on něco pošle a my to máme taky, akorát updateneme dýlku uložení + if (sessionId && sessions[sessionId]) { + sessions[sessionId].lastInteractedAt = Date.now(); + + res.setHeader("Set-Cookie", `sachySession=${sessionId}; Max-Age=3600`); + return sessions[sessionId]; + } + + const randomId = generateId(); + sessions[randomId] = { logedIn: false, lastInteractedAt: Date.now() }; + + res.setHeader("Set-Cookie", `sachySession=${randomId}; Max-Age=3600`); + + return sessions[randomId]; +} + +// Session garbage-collection +setInterval(() => { + for (const key in sessions) { + if ((sessions[key].lastInteractedAt + 36e5) > Date.now()) return; + + delete sessions[key]; + } +}, 3e5); + +function redirect(res: ServerResponse, path: string) { + res.statusCode = 302; + res.setHeader("Location", path); + res.end("302 gone"); +} + +function login(session: Session, res: ServerResponse) { + if (session.logedIn) return "uzjsi prihlasenej"; + + redirect(res, "https://discord.com/api/oauth2/authorize?client_id=1064269692165963826&redirect_uri=http%3A%2F%2F%C5%A1ach.ml%2Foauth&response_type=code&scope=identify"); +} + +function logout(session: Session, res: ServerResponse) { + session.logedIn = false; + redirect(res, "/"); +} + +function loginErr(res: ServerResponse) { + res.end(chybaStranka.replaceAll("$error", "Prihlaseni se nezdarilo, zkus to znovu a jestli to nefunguje furt, tak si holt stezuj no")); +} + +async function overeni(url: string, session: Session, res: ServerResponse) { + + const code = (new URL(url, "h:/")).searchParams.get("code"); + const data = await fetch("https://discord.com/api/v10/oauth2/token", { method: "post", body: `client_id=1064269692165963826&client_secret=8HHKODmb1HTLWoJGVyoinSU_9323dEla&grant_type=authorization_code&code=${code}&redirect_uri=http%3A%2F%2F%C5%A1ach.ml%2Foauth`, headers: { "Content-type": "application/x-www-form-urlencoded" } }) + .then(r => r.json()) + .catch(err => log("sachy jednotka:", err)); + + if (!data?.access_token) return loginErr(res); + + const uzivatel = await fetch("https://discord.com/api/v10/users/@me", { headers: { authorization: `Bearer ${data.access_token}` } }) + .then(r => r.json()) + .catch(err => log("sachy dva:", err)); + + if (!uzivatel) return loginErr(res); + + session.logedIn = true; + session.discordId = uzivatel.id; + session.discordName = `${uzivatel.username}#${uzivatel.discriminator}`; + + redirect(res, session.redirect || "/"); +} + +function validateMove(res: ServerResponse, session: Session, url: string) { + + if (!session.logedIn) return redirect(res, `/login?redirect=${url}`); + + const pismenko = url[1]; + const promoNa: string | undefined = url[3]; + + function overeni(err?: string) { + if (err == "--promote--") + return res.end(promoStranka); + + const response = tahStranka.replace("$title", err ? "Neplatej tah" : "Úspšný tah") + .replace("$content", err ?? "Kvalitní tah!") + .replace("$podminka", err ? "0" : "1"); + + res.end(response); + } + + emiter.emit("tah", session.discordId!, pismenko, overeni, promoNa); +} + +const server = createServer((req, res) => { + + const session = startSession(req, res); + // TODO: Natipovaný, protože vscode jebe (možná někdy přestane, v tom případě odebrat pls) + const url: URL = new URL(req.url!, "http://šach.ml"); + + if (url.pathname.length == 2 || url.pathname.length == 4) return validateMove(res, session, req.url!); + + if (req.url?.startsWith("/oauth")) return overeni(req.url, session, res); + + switch (url.pathname) { + case "/": + const response = indexStranka.replace("$logged", session.logedIn ? "1" : "0") + .replace("$jmeno", session.discordName ?? ""); + return res.end(response); + + case "/login": + const path = url.searchParams.get("redirect"); + session.redirect = path || ""; + return login(session, res); + + case "/logout": + return logout(session, res); + + default: + redirect(res, "/"); + } +}); + +server.listen(50236); + +type Session = { + logedIn: boolean; + discordId?: string; + discordName?: string; + lastInteractedAt: number; + redirect?: string; +};