diff --git a/LICENSE b/LICENSE index 4ea46065..5c296ab7 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright 2020 Johannes Loher, Gesina Schwalbe, Oliver Rümpelein +Copyright 2020 Johannes Loher, Gesina Schwalbe, Oliver Rümpelein, Siegfried Krug Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/package-lock.json b/package-lock.json index ff2912b2..447b66d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,9 +44,9 @@ } }, "@eslint/eslintrc": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz", - "integrity": "sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz", + "integrity": "sha512-1JTKgrOKAHVivSvOYw+sJOunkBjUOvjqWk1DPja7ZFhIS2mX/4EgTT8M7eTK9jrKhL/FvXXEbQwIs3pg1xp3dg==", "dev": true, "requires": { "ajv": "^6.12.4", @@ -56,7 +56,7 @@ "ignore": "^4.0.6", "import-fresh": "^3.2.1", "js-yaml": "^3.13.1", - "lodash": "^4.17.19", + "lodash": "^4.17.20", "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" }, @@ -110,6 +110,15 @@ "fastq": "^1.6.0" } }, + "@types/fs-extra": { + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.6.tgz", + "integrity": "sha512-ecNRHw4clCkowNOBJH1e77nvbPxHYnWIXMv1IAoG/9+MYGkgoyr3Ppxr7XYFNL41V422EDhyV4/4SSK8L2mlig==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/jasmine": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.6.2.tgz", @@ -131,6 +140,12 @@ "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", "dev": true }, + "@types/node": { + "version": "14.14.20", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.20.tgz", + "integrity": "sha512-Y93R97Ouif9JEOWPIUyU+eyIdyRqQR0I8Ez1dzku4hDx34NWh4HbtIc3WNzwB1Y9ULvNGeu5B8h8bVL5cAk4/A==", + "dev": true + }, "@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", @@ -144,9 +159,9 @@ "dev": true }, "@types/socket.io-client": { - "version": "1.4.34", - "resolved": "https://registry.npmjs.org/@types/socket.io-client/-/socket.io-client-1.4.34.tgz", - "integrity": "sha512-Lzia5OTQFJZJ5R4HsEEldywiiqT9+W2rDbyHJiiTGqOcju89sCsQ8aUXDljY6Ls33wKZZGC0bfMhr/VpOyjtXg==", + "version": "1.4.35", + "resolved": "https://registry.npmjs.org/@types/socket.io-client/-/socket.io-client-1.4.35.tgz", + "integrity": "sha512-MI8YmxFS+jMkIziycT5ickBWK1sZwDwy16mgH/j99Mcom6zRG/NimNGQ3vJV0uX5G6g/hEw0FG3w3b3sT5OUGw==", "dev": true }, "@types/tinymce": { @@ -159,15 +174,16 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.11.1.tgz", - "integrity": "sha512-fABclAX2QIEDmTMk6Yd7Muv1CzFLwWM4505nETzRHpP3br6jfahD9UUJkhnJ/g2m7lwfz8IlswcwGGPGiq9exw==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.14.0.tgz", + "integrity": "sha512-IJ5e2W7uFNfg4qh9eHkHRUCbgZ8VKtGwD07kannJvM5t/GU8P8+24NX8gi3Hf5jST5oWPY8kyV1s/WtfiZ4+Ww==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "4.11.1", - "@typescript-eslint/scope-manager": "4.11.1", + "@typescript-eslint/experimental-utils": "4.14.0", + "@typescript-eslint/scope-manager": "4.14.0", "debug": "^4.1.1", "functional-red-black-tree": "^1.0.1", + "lodash": "^4.17.15", "regexpp": "^3.0.0", "semver": "^7.3.2", "tsutils": "^3.17.1" @@ -215,28 +231,28 @@ } }, "@typescript-eslint/experimental-utils": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.11.1.tgz", - "integrity": "sha512-mAlWowT4A6h0TC9F+J5pdbEhjNiEMO+kqPKQ4sc3fVieKL71dEqfkKgtcFVSX3cjSBwYwhImaQ/mXQF0oaI38g==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.14.0.tgz", + "integrity": "sha512-6i6eAoiPlXMKRbXzvoQD5Yn9L7k9ezzGRvzC/x1V3650rUk3c3AOjQyGYyF9BDxQQDK2ElmKOZRD0CbtdkMzQQ==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.11.1", - "@typescript-eslint/types": "4.11.1", - "@typescript-eslint/typescript-estree": "4.11.1", + "@typescript-eslint/scope-manager": "4.14.0", + "@typescript-eslint/types": "4.14.0", + "@typescript-eslint/typescript-estree": "4.14.0", "eslint-scope": "^5.0.0", "eslint-utils": "^2.0.0" } }, "@typescript-eslint/parser": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.11.1.tgz", - "integrity": "sha512-BJ3jwPQu1jeynJ5BrjLuGfK/UJu6uwHxJ/di7sanqmUmxzmyIcd3vz58PMR7wpi8k3iWq2Q11KMYgZbUpRoIPw==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.14.0.tgz", + "integrity": "sha512-sUDeuCjBU+ZF3Lzw0hphTyScmDDJ5QVkyE21pRoBo8iDl7WBtVFS+WDN3blY1CH3SBt7EmYCw6wfmJjF0l/uYg==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "4.11.1", - "@typescript-eslint/types": "4.11.1", - "@typescript-eslint/typescript-estree": "4.11.1", + "@typescript-eslint/scope-manager": "4.14.0", + "@typescript-eslint/types": "4.14.0", + "@typescript-eslint/typescript-estree": "4.14.0", "debug": "^4.1.1" }, "dependencies": { @@ -258,29 +274,29 @@ } }, "@typescript-eslint/scope-manager": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.11.1.tgz", - "integrity": "sha512-Al2P394dx+kXCl61fhrrZ1FTI7qsRDIUiVSuN6rTwss6lUn8uVO2+nnF4AvO0ug8vMsy3ShkbxLu/uWZdTtJMQ==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.14.0.tgz", + "integrity": "sha512-/J+LlRMdbPh4RdL4hfP1eCwHN5bAhFAGOTsvE6SxsrM/47XQiPSgF5MDgLyp/i9kbZV9Lx80DW0OpPkzL+uf8Q==", "dev": true, "requires": { - "@typescript-eslint/types": "4.11.1", - "@typescript-eslint/visitor-keys": "4.11.1" + "@typescript-eslint/types": "4.14.0", + "@typescript-eslint/visitor-keys": "4.14.0" } }, "@typescript-eslint/types": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.11.1.tgz", - "integrity": "sha512-5kvd38wZpqGY4yP/6W3qhYX6Hz0NwUbijVsX2rxczpY6OXaMxh0+5E5uLJKVFwaBM7PJe1wnMym85NfKYIh6CA==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.14.0.tgz", + "integrity": "sha512-VsQE4VvpldHrTFuVPY1ZnHn/Txw6cZGjL48e+iBxTi2ksa9DmebKjAeFmTVAYoSkTk7gjA7UqJ7pIsyifTsI4A==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.11.1.tgz", - "integrity": "sha512-tC7MKZIMRTYxQhrVAFoJq/DlRwv1bnqA4/S2r3+HuHibqvbrPcyf858lNzU7bFmy4mLeIHFYr34ar/1KumwyRw==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.14.0.tgz", + "integrity": "sha512-wRjZ5qLao+bvS2F7pX4qi2oLcOONIB+ru8RGBieDptq/SudYwshveORwCVU4/yMAd4GK7Fsf8Uq1tjV838erag==", "dev": true, "requires": { - "@typescript-eslint/types": "4.11.1", - "@typescript-eslint/visitor-keys": "4.11.1", + "@typescript-eslint/types": "4.14.0", + "@typescript-eslint/visitor-keys": "4.14.0", "debug": "^4.1.1", "globby": "^11.0.1", "is-glob": "^4.0.1", @@ -331,12 +347,12 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.11.1.tgz", - "integrity": "sha512-IrlBhD9bm4bdYcS8xpWarazkKXlE7iYb1HzRuyBP114mIaj5DJPo11Us1HgH60dTt41TCZXMaTCAW+OILIYPOg==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.14.0.tgz", + "integrity": "sha512-MeHHzUyRI50DuiPgV9+LxcM52FCJFYjJiWHtXlbyC27b80mfOwKeiKI+MHOTEpcpfmoPFm/vvQS88bYIx6PZTA==", "dev": true, "requires": { - "@typescript-eslint/types": "4.11.1", + "@typescript-eslint/types": "4.14.0", "eslint-visitor-keys": "^2.0.0" } }, @@ -555,9 +571,9 @@ "dev": true }, "archiver": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.1.0.tgz", - "integrity": "sha512-iKuQUP1nuKzBC2PFlGet5twENzCfyODmvkxwDV0cEFXavwcLrIW5ssTuHi9dyTPvpWr6Faweo2eQaQiLIwyXTA==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.2.0.tgz", + "integrity": "sha512-QEAKlgQuAtUxKeZB9w5/ggKXh21bZS+dzzuQ0RPBC20qtDCbTyzqmisoeJP46MP39fg4B4IcyvR+yeyEBdblsQ==", "dev": true, "requires": { "archiver-utils": "^2.1.0", @@ -1954,13 +1970,13 @@ "dev": true }, "eslint": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.17.0.tgz", - "integrity": "sha512-zJk08MiBgwuGoxes5sSQhOtibZ75pz0J35XTRlZOk9xMffhpA9BTbQZxoXZzOl5zMbleShbGwtw+1kGferfFwQ==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.18.0.tgz", + "integrity": "sha512-fbgTiE8BfUJZuBeq2Yi7J3RB3WGUQ9PNuNbmgi6jt9Iv8qrkxfy19Ds3OpL1Pm7zg3BtTVhvcUZbIRQ0wmSjAQ==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@eslint/eslintrc": "^0.2.2", + "@eslint/eslintrc": "^0.3.0", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -1984,7 +2000,7 @@ "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", - "lodash": "^4.17.19", + "lodash": "^4.17.20", "minimatch": "^3.0.4", "natural-compare": "^1.4.0", "optionator": "^0.9.1", @@ -2096,9 +2112,9 @@ "dev": true }, "eslint-plugin-prettier": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.0.tgz", - "integrity": "sha512-tMTwO8iUWlSRZIwS9k7/E4vrTsfvsrcM5p1eftyuqWH25nKsz/o6/54I7jwQ/3zobISyC7wMy9ZsFwgTxOcOpQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz", + "integrity": "sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ==", "dev": true, "requires": { "prettier-linter-helpers": "^1.0.0" @@ -2437,9 +2453,9 @@ "dev": true }, "fast-glob": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", - "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", + "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -2584,12 +2600,12 @@ } }, "find-versions": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz", - "integrity": "sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-4.0.0.tgz", + "integrity": "sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ==", "dev": true, "requires": { - "semver-regex": "^2.0.0" + "semver-regex": "^3.1.2" } }, "findup-sync": { @@ -2702,7 +2718,7 @@ } }, "foundry-pc-types": { - "version": "git+https://git.f3l.de/dungeonslayers/foundry-pc-types.git#f84074f63d1aeeb9229e441e8c3ccaa9cba64142", + "version": "git+https://git.f3l.de/dungeonslayers/foundry-pc-types.git#5fcca4e4327b558d5eeeb962f05470c994a394be", "from": "git+https://git.f3l.de/dungeonslayers/foundry-pc-types.git#f3l-fixes", "dev": true, "requires": { @@ -2970,9 +2986,9 @@ } }, "globby": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", - "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz", + "integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==", "dev": true, "requires": { "array-union": "^2.1.0", @@ -3378,18 +3394,18 @@ "dev": true }, "husky": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.6.tgz", - "integrity": "sha512-o6UjVI8xtlWRL5395iWq9LKDyp/9TE7XMOTvIpEVzW638UcGxTmV5cfel6fsk/jbZSTlvfGVJf2svFtybcIZag==", + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.8.tgz", + "integrity": "sha512-LCqqsB0PzJQ/AlCgfrfzRe3e3+NvmefAdKQhRYpxS4u6clblBoDdzzvHi8fmxKRzvMxPY/1WZWzomPZww0Anow==", "dev": true, "requires": { "chalk": "^4.0.0", "ci-info": "^2.0.0", "compare-versions": "^3.6.0", "cosmiconfig": "^7.0.0", - "find-versions": "^3.2.0", + "find-versions": "^4.0.0", "opencollective-postinstall": "^2.0.2", - "pkg-dir": "^4.2.0", + "pkg-dir": "^5.0.0", "please-upgrade-node": "^3.2.0", "slash": "^3.0.0", "which-pm-runs": "^1.0.0" @@ -5155,40 +5171,49 @@ } }, "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", + "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", "dev": true, "requires": { - "find-up": "^4.0.0" + "find-up": "^5.0.0" }, "dependencies": { "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "requires": { - "locate-path": "^5.0.0", + "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "requires": { - "p-locate": "^4.1.0" + "p-locate": "^5.0.0" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" } }, "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "requires": { - "p-limit": "^2.2.0" + "p-limit": "^3.0.2" } }, "path-exists": { @@ -5648,9 +5673,9 @@ "dev": true }, "sass": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.32.0.tgz", - "integrity": "sha512-fhyqEbMIycQA4blrz/C0pYhv2o4x2y6FYYAH0CshBw3DXh5D5wyERgxw0ptdau1orc/GhNrhF7DFN2etyOCEng==", + "version": "1.32.4", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.32.4.tgz", + "integrity": "sha512-N0BT0PI/t3+gD8jKa83zJJUb7ssfQnRRfqN+GIErokW6U4guBpfYl8qYB+OFLEho+QvnV5ZH1R9qhUC/Z2Ch9w==", "dev": true, "requires": { "chokidar": ">=2.0.0 <4.0.0" @@ -5834,9 +5859,9 @@ } }, "semver-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz", - "integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.2.tgz", + "integrity": "sha512-bXWyL6EAKOJa81XG1OZ/Yyuq+oT0b2YLlxx7c+mrdYPaPbnj6WgVULXhinMIeZGufuUBu/eVRqXEhiv4imfwxA==", "dev": true }, "set-blocking": { @@ -6391,9 +6416,9 @@ } }, "table": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/table/-/table-6.0.6.tgz", - "integrity": "sha512-OInCtPmDNieVBkVFi6C8RwU2S2H0h8mF3e3TQK4nreaUNCpooQUkI+A/KuEkm5FawfhWIfNqG+qfelVVR+V00g==", + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/table/-/table-6.0.7.tgz", + "integrity": "sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g==", "dev": true, "requires": { "ajv": "^7.0.2", @@ -6472,9 +6497,9 @@ } }, "tar-stream": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.4.tgz", - "integrity": "sha512-o3pS2zlG4gxr67GmFYBLlq+dM8gyRGUOvsrHclSkvtVtQbjV0s/+ZE8OpICbaj8clrX3tjeHngYGP7rweaBnuw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, "requires": { "bl": "^4.0.3", @@ -6642,9 +6667,9 @@ "dev": true }, "tsutils": { - "version": "3.17.1", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", - "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "version": "3.19.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.19.1.tgz", + "integrity": "sha512-GEdoBf5XI324lu7ycad7s6laADfnAqCw6wLGI+knxvw9vsIYBaJfYdmeCEG3FMMUiSm3OGgNb+m6utsWf5h9Vw==", "dev": true, "requires": { "tslib": "^1.8.1" @@ -7235,6 +7260,12 @@ "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", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + }, "zip-stream": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.0.4.tgz", diff --git a/package.json b/package.json index 99a5f5d8..b6d11272 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,10 @@ { "name": "Oliver Rümpelein", "email": "foundryvtt@pheerai.de" + }, + { + "name": "Siegfried Krug", + "email": "foundryvtt@asdil1991.de" } ], "scripts": { @@ -40,14 +44,15 @@ "format": "prettier --write 'src/**/*.(ts|json|scss)'" }, "devDependencies": { + "@types/fs-extra": "^9.0.6", "@types/jasmine": "^3.6.2", - "@typescript-eslint/eslint-plugin": "^4.11.1", - "@typescript-eslint/parser": "^4.11.1", - "archiver": "^5.1.0", + "@typescript-eslint/eslint-plugin": "^4.14.0", + "@typescript-eslint/parser": "^4.14.0", + "archiver": "^5.2.0", "chalk": "^4.1.0", - "eslint": "^7.17.0", + "eslint": "^7.18.0", "eslint-config-prettier": "^7.1.0", - "eslint-plugin-prettier": "^3.3.0", + "eslint-plugin-prettier": "^3.3.1", "foundry-pc-types": "git+https://git.f3l.de/dungeonslayers/foundry-pc-types.git#f3l-fixes", "fs-extra": "^9.0.1", "gulp": "^4.0.2", @@ -55,13 +60,13 @@ "gulp-less": "^4.0.1", "gulp-sass": "^4.1.0", "gulp-typescript": "^6.0.0-alpha.1", - "husky": "^4.3.6", + "husky": "^4.3.8", "jasmine": "^3.6.3", "jasmine-xml-reporter": "^1.2.1", "json-stringify-pretty-compact": "^2.0.0", "lint-staged": "^10.5.3", "prettier": "^2.2.1", - "sass": "^1.32.0", + "sass": "^1.32.4", "ts-node": "^9.1.1", "typescript": "^4.1.3", "yargs": "^16.2.0" diff --git a/spec/support/ds4rolls/executor.spec.ts b/spec/support/ds4rolls/executor.spec.ts index 705241a9..58997a98 100644 --- a/spec/support/ds4rolls/executor.spec.ts +++ b/spec/support/ds4rolls/executor.spec.ts @@ -65,37 +65,37 @@ describe("DS4 Rolls with one die and slaying dice, followup throw.", () => { describe("DS4 Rolls with one die and crit roll modifications.", () => { it("Should do a crit success on `1`.", () => { - expect(rollCheckSingleDie(4, { maxCritSuccess: 2, minCritFail: 19 }, [1])).toEqual( + expect(rollCheckSingleDie(4, { maxCritSuccess: 2, minCritFailure: 19 }, [1])).toEqual( new RollResult(4, RollResultStatus.CRITICAL_SUCCESS, [1]), ); }); it("Should do a crit success on `maxCritSucc`.", () => { - expect(rollCheckSingleDie(4, { maxCritSuccess: 2, minCritFail: 19 }, [2])).toEqual( + expect(rollCheckSingleDie(4, { maxCritSuccess: 2, minCritFailure: 19 }, [2])).toEqual( new RollResult(4, RollResultStatus.CRITICAL_SUCCESS, [2]), ); }); it("Should do a success on lower edge case `3`.", () => { - expect(rollCheckSingleDie(4, { maxCritSuccess: 2, minCritFail: 19 }, [3])).toEqual( + expect(rollCheckSingleDie(4, { maxCritSuccess: 2, minCritFailure: 19 }, [3])).toEqual( new RollResult(3, RollResultStatus.SUCCESS, [3]), ); }); it("Should do a success on upper edge case `18`.", () => { - expect(rollCheckSingleDie(4, { maxCritSuccess: 2, minCritFail: 19 }, [18])).toEqual( + expect(rollCheckSingleDie(4, { maxCritSuccess: 2, minCritFailure: 19 }, [18])).toEqual( new RollResult(0, RollResultStatus.FAILURE, [18]), ); }); - it("Should do a crit fail on `minCritFail`.", () => { - expect(rollCheckSingleDie(4, { maxCritSuccess: 2, minCritFail: 19 }, [19])).toEqual( + it("Should do a crit fail on `minCritFailure`.", () => { + expect(rollCheckSingleDie(4, { maxCritSuccess: 2, minCritFailure: 19 }, [19])).toEqual( new RollResult(0, RollResultStatus.CRITICAL_FAILURE, [19]), ); }); it("Should do a crit fail on `20`", () => { - expect(rollCheckSingleDie(4, { maxCritSuccess: 2, minCritFail: 19 }, [20])).toEqual( + expect(rollCheckSingleDie(4, { maxCritSuccess: 2, minCritFailure: 19 }, [20])).toEqual( new RollResult(0, RollResultStatus.CRITICAL_FAILURE, [20]), ); }); @@ -171,37 +171,37 @@ describe("DS4 Rolls with multiple dice and no modifiers.", () => { describe("DS4 Rolls with multiple dice and min/max modifiers.", () => { it("Should do a crit fail on `19` for first roll.", () => { - expect(rollCheckMultipleDice(48, { maxCritSuccess: 2, minCritFail: 19 }, [19, 15, 6])).toEqual( + expect(rollCheckMultipleDice(48, { maxCritSuccess: 2, minCritFailure: 19 }, [19, 15, 6])).toEqual( new RollResult(0, RollResultStatus.CRITICAL_FAILURE, [19, 15, 6]), ); }); it("Should succeed with all rolls crit successes (1 and 2).", () => { - expect(rollCheckMultipleDice(48, { maxCritSuccess: 2, minCritFail: 19 }, [2, 1, 2])).toEqual( + expect(rollCheckMultipleDice(48, { maxCritSuccess: 2, minCritFailure: 19 }, [2, 1, 2])).toEqual( new RollResult(48, RollResultStatus.CRITICAL_SUCCESS, [2, 1, 2]), ); }); it("Should succeed with the last roll not being sufficient.", () => { - expect(rollCheckMultipleDice(48, { maxCritSuccess: 2, minCritFail: 19 }, [15, 15, 15])).toEqual( + expect(rollCheckMultipleDice(48, { maxCritSuccess: 2, minCritFailure: 19 }, [15, 15, 15])).toEqual( new RollResult(30, RollResultStatus.SUCCESS, [15, 15, 15]), ); }); it("Should succeed with the last roll a crit success `2`.", () => { - expect(rollCheckMultipleDice(48, { maxCritSuccess: 2, minCritFail: 19 }, [15, 15, 2])).toEqual( + expect(rollCheckMultipleDice(48, { maxCritSuccess: 2, minCritFailure: 19 }, [15, 15, 2])).toEqual( new RollResult(38, RollResultStatus.SUCCESS, [15, 15, 2]), ); }); it("Should succeed with the last roll being `20` and one crit success '2'.", () => { - expect(rollCheckMultipleDice(48, { maxCritSuccess: 2, minCritFail: 19 }, [15, 2, 20])).toEqual( + expect(rollCheckMultipleDice(48, { maxCritSuccess: 2, minCritFailure: 19 }, [15, 2, 20])).toEqual( new RollResult(43, RollResultStatus.SUCCESS, [15, 2, 20]), ); }); it("Should succeed with the last roll being `19` and one crit success '2'.", () => { - expect(rollCheckMultipleDice(48, { maxCritSuccess: 2, minCritFail: 19 }, [15, 2, 19])).toEqual( + expect(rollCheckMultipleDice(48, { maxCritSuccess: 2, minCritFailure: 19 }, [15, 2, 19])).toEqual( new RollResult(42, RollResultStatus.SUCCESS, [15, 2, 19]), ); }); @@ -209,7 +209,7 @@ describe("DS4 Rolls with multiple dice and min/max modifiers.", () => { describe("DS4 Rolls with multiple dice and fail modifiers.", () => { it("Should do a crit fail on `19` for first roll.", () => { - expect(rollCheckMultipleDice(48, { minCritFail: 19 }, [19, 15, 6])).toEqual( + expect(rollCheckMultipleDice(48, { minCritFailure: 19 }, [19, 15, 6])).toEqual( new RollResult(0, RollResultStatus.CRITICAL_FAILURE, [19, 15, 6]), ); }); diff --git a/spec/support/localization/localization.spec.ts b/spec/support/localization/localization.spec.ts new file mode 100644 index 00000000..b289819c --- /dev/null +++ b/spec/support/localization/localization.spec.ts @@ -0,0 +1,15 @@ +import "jasmine"; +import * as fs from "fs-extra"; +import * as path from "path"; + +describe("English and german localization files", () => { + const localizationPath = "./src/lang/"; + const en: Record = fs.readJSONSync(path.join(localizationPath, "en.json")); + const de: Record = fs.readJSONSync(path.join(localizationPath, "de.json")); + + it("should have the same keys.", () => { + const deKeys = Object.keys(de); + const enKeys = Object.keys(en); + expect(deKeys).toEqual(enKeys); + }); +}); diff --git a/src/lang/de.json b/src/lang/de.json index 581c8fbb..59146324 100644 --- a/src/lang/de.json +++ b/src/lang/de.json @@ -1,12 +1,17 @@ { "DS4.UserInteractionAddItem": "Neu", + "DS4.UserInteractionEditItem": "Bearbeiten", + "DS4.UserInteractionDeleteItem": "Löschen", "DS4.NotOwned": "Nicht besessen", - "DS4.HeadingDescription": "Beschreibung", + "DS4.HeadingBiography": "Biografie", "DS4.HeadingDetails": "Details", "DS4.HeadingEffects": "Effekte", "DS4.HeadingInventory": "Inventar", "DS4.HeadingProfile": "Profil", - "DS4.HeadingTalents": "Talente & Fähigkeiten", + "DS4.HeadingTalentsAbilities": "Talente & Fähigkeiten", + "DS4.HeadingSpells": "Zaubersprüche", + "DS4.HeadingDescription": "Beschreibung", + "DS4.HeadingSpecialCreatureAbilites": "Besondere Fähigkeiten", "DS4.AttackType": "Angriffs Typ", "DS4.AttackTypeAbbr": "AT", "DS4.WeaponBonus": "Waffen Bonus", @@ -16,11 +21,13 @@ "DS4.AttackTypeMelee": "Schlagen", "DS4.AttackTypeRanged": "Schießen", "DS4.AttackTypeMeleeRanged": "Schlagen + Schießen", + "DS4.Description": "Beschreibung", "DS4.Quantity": "Menge", "DS4.PriceGold": "Preis (Gold)", "DS4.StorageLocation": "Wo gelagert", "DS4.ItemEquipped": "Ausgerüstet", - "DS4.ItemOwner": "Eigentümer", + "DS4.ItemEquippedAbbr": "A", + "DS4.ItemOwner": "Besitzer", "DS4.ItemAvailability": "Verfügbarkeit", "DS4.ItemAvailabilityHamlet": "Dorf", "DS4.ItemAvailabilityVilage": "Kleinstadt", @@ -36,6 +43,8 @@ "DS4.ItemTypeArmorPlural": "Panzerungen", "DS4.ItemTypeShield": "Schild", "DS4.ItemTypeShieldPlural": "Schilde", + "DS4.ItemTypeSpell": "Zauberspruch", + "DS4.ItemTypeSpellPlural": "Zaubersprüche", "DS4.ItemTypeTrinket": "Schmuckstück", "DS4.ItemTypeTrinketPlural": "Schmuckstücke", "DS4.ItemTypeEquipment": "Ausrüstung", @@ -48,6 +57,8 @@ "DS4.ItemTypeLanguagePlural": "Sprachen", "DS4.ItemTypeAlphabet": "Schriftzeichen", "DS4.ItemTypeAlphabetPlural": "Schriftzeichen", + "DS4.ItemTypeSpecialCreatureAbility": "Besondere Kreaturenfähigkeit", + "DS4.ItemTypeSpecialCreatureAbilityPlural": "Besondere Kreaturenfähigkeiten", "DS4.ArmorType": "Panzerungstyp", "DS4.ArmorTypeAbbr": "PAT", "DS4.ArmorMaterialType": "Material Typ", @@ -72,6 +83,29 @@ "DS4.ArmorMaterialTypeChainAbbr": "Ketten", "DS4.ArmorMaterialTypePlate": "Platten", "DS4.ArmorMaterialTypePlateAbbr": "Platten", + "DS4.SpellType": "Zauberspruchtyp", + "DS4.SpellTypeAbbr": "T", + "DS4.SpellTypeSpellcasting": "Zaubern", + "DS4.SpellTypeTargetedSpellcasting": "Zielzaubern", + "DS4.SpellCategory": "Kategorie", + "DS4.SpellCategoryHealing": "Heilung", + "DS4.SpellCategoryFire": "Feuer", + "DS4.SpellCategoryIce": "Eis", + "DS4.SpellCategoryLight": "Licht", + "DS4.SpellCategoryDarkness": "Schatten", + "DS4.SpellCategoryMindAffecting": "Geistensbeeinflussend", + "DS4.SpellCategoryElectricity": "Elektrizität", + "DS4.SpellCategoryNone": "Keine", + "DS4.SpellCategoryUnset": "Nicht gesetzt", + "DS4.SpellBonus": "Zauberbonus", + "DS4.SpellBonusAbbr": "ZB", + "DS4.SpellMaxDistance": "Reichweite", + "DS4.SpellEffectRadius": "Effektradius", + "DS4.SpellDuration": "Wirkdauer", + "DS4.SpellCooldownDuration": "Abklingzeit", + "DS4.SpellScrollPriceGold": "Schriftrollenpreis (Gold)", + "DS4.ActorTypeCharacter": "Charakter", + "DS4.ActorTypeCreature": "Kreatur", "DS4.AttributeBody": "Körper", "DS4.AttributeMobility": "Agilität", "DS4.AttributeMind": "Geist", @@ -89,35 +123,83 @@ "DS4.CombatValuesRangedAttack": "Schießen", "DS4.CombatValuesSpellcasting": "Zaubern", "DS4.CombatValuesTargetedSpellcasting": "Zielzaubern", - "DS4.BaseInfoRace": "Volk", - "DS4.BaseInfoClass": "Klasse", - "DS4.BaseInfoHeroClass": "Helden Klasse", - "DS4.BaseInfoCulture": "Kultur", - "DS4.ProgressionLevel": "Stufe", - "DS4.ProgressionExperiencePoints": "Erfahrungspunkte", - "DS4.ProgressionTalentPoints": "Talentpunkte", - "DS4.ProgressionProgressPoints": "Lernpunkte", + "DS4.CharacterBaseInfoRace": "Volk", + "DS4.CharacterBaseInfoClass": "Klasse", + "DS4.CharacterBaseInfoHeroClass": "Helden Klasse", + "DS4.CharacterBaseInfoCulture": "Kultur", + "DS4.CharacterProgressionLevel": "Stufe", + "DS4.CharacterProgressionExperiencePoints": "Erfahrungspunkte", + "DS4.CharacterProgressionTalentPoints": "Talentpunkte", + "DS4.CharacterProgressionProgressPoints": "Lernpunkte", "DS4.TalentRank": "Rang", "DS4.TalentRankBase": "Erworbener Rang", "DS4.TalentRankMax": "Maximaler Rang", "DS4.TalentRankMod": "Zusätzlicher Rang", "DS4.TalentRankTotal": "Gesamter Rang", - "DS4.LanguageLanguages": "Sprachen", - "DS4.LanguageAlphabets": "Schriftzeichen", - "DS4.ProfileGender": "Geschlecht", - "DS4.ProfileBirthday": "Geburtstag", - "DS4.ProfileBirthplace": "Geburtsort", - "DS4.ProfileAge": "Alter", - "DS4.ProfileHeight": "Größe", - "DS4.ProfilHairColor": "Haarfarbe", - "DS4.ProfileWeight": "Gewicht", - "DS4.ProfileEyeColor": "Augenfarbe", - "DS4.ProfileSpecialCharacteristics": "Besondere Eigenschaften", - "DS4.CurrencyGold": "Gold", - "DS4.CurrencySilver": "Silber", - "DS4.CurrencyCopper": "Kupfer", - "DS4.Currency": "Währung", + "DS4.CharacterLanguageLanguages": "Sprachen", + "DS4.CharacterLanguageAlphabets": "Schriftzeichen", + "DS4.SpecialCreatureAbilityExperiencePoints": "Erfahrungspunkte", + "DS4.CharacterProfileBiography": "Biographie", + "DS4.CharacterProfileGender": "Geschlecht", + "DS4.CharacterProfileBirthday": "Geburtstag", + "DS4.CharacterProfileBirthplace": "Geburtsort", + "DS4.CharacterProfileAge": "Alter", + "DS4.CharacterProfileHeight": "Größe", + "DS4.CharacterProfileHairColor": "Haarfarbe", + "DS4.CharacterProfileWeight": "Gewicht", + "DS4.CharacterProfileEyeColor": "Augenfarbe", + "DS4.CharacterProfileSpecialCharacteristics": "Besondere Eigenschaften", + "DS4.CharacterCurrencyGold": "Gold", + "DS4.CharacterCurrencySilver": "Silber", + "DS4.CharacterCurrencyCopper": "Kupfer", + "DS4.CharacterCurrency": "Währung", + "DS4.CreatureTypeAnimal": "Tier", + "DS4.CreatureTypeConstruct": "Konstrukt", + "DS4.CreatureTypeHumanoid": "Humanoid", + "DS4.CreatureTypeMagicalEntity": "Magisches Wesen", + "DS4.CreatureTypePlantBeing": "Pflanzenwesen", + "DS4.CreatureTypeUndead": "Untot", + "DS4.CreatureSizeCategoryTiny": "Winzig", + "DS4.CreatureSizeCategorySmall": "Klein", + "DS4.CreatureSizeCategoryNormal": "Normal", + "DS4.CreatureSizeCategoryLarge": "Groß", + "DS4.CreatureSizeCategoryHuge": "Riesig", + "DS4.CreatureSizeCategoryColossal": "Gewaltig", + "DS4.CreatureBaseInfoLoot": "Beute", + "DS4.CreatureBaseInfoFoeFactor": "Gegnerhärte", + "DS4.CreatureBaseInfoCreatureType": "Kreaturengruppe", + "DS4.CreatureBaseInfoSizeCategory": "Größenkategorie", + "DS4.CreatureBaseInfoExperiencePoints": "Erfahrungspunkte", + "DS4.CreatureBaseInfoDescription": "Beschreibung", "DS4.WarningManageActiveEffectOnOwnedItem": "Das Verwalten von aktiven Effekten innerhalb eines besessen Items wird derzeit nicht unterstützt und wird in einem nachfolgenden Update hinzugefügt.", + "DS4.WarningActorCannotOwnItem": "Der Aktor '{actorName}' vom Typ '{actorType}' kann das Item '{itemName}' vom Typ '{itemType}' nicht besitzen.", "DS4.ErrorDiceCritOverlap": "Es gibt eine Überlappung zwischen Patzern und Immersiegen.", - "DS4.ErrorExplodingRecursionLimitExceeded": "Die maximale Rekursionstiefe für slayende Würfelwürfe wurde überschritten." + "DS4.ErrorExplodingRecursionLimitExceeded": "Die maximale Rekursionstiefe für slayende Würfelwürfe wurde überschritten.", + "DS4.UnitRounds": "Runden", + "DS4.UnitRoundsAbbr": "Rnd", + "DS4.UnitMinutes": "Minuten", + "DS4.UnitMinutesAbbr": "min", + "DS4.UnitHours": "Stunden", + "DS4.UnitHoursAbbr": "h", + "DS4.UnitDays": "Tage", + "DS4.UnitDaysAbbr": "d", + "DS4.UnitMeters": "Meter", + "DS4.UnitMetersAbbr": "m", + "DS4.UnitKilometers": "Kilometer", + "DS4.UnitKilometersAbbr": "km", + "DS4.UnitCustom": "individuell", + "DS4.UnitCustomAbbr": " ", + "DS4.RollDialogDefaultTitle": "Proben-Optionen", + "DS4.RollDialogOkButton": "Ok", + "DS4.RollDialogCancelButton": "Abbrechen", + "DS4.ErrorUnexpectedHtmlType": "Typfehler: Erwartet wurde {exType}, tatsächlich erhalten wurde {realType}", + "DS4.RollDialogTargetLabel": "Probenwert", + "DS4.RollDialogModifierLabel": "SL-Modifikator", + "DS4.RollDialogCoupLabel": "Immersieg bis", + "DS4.RollDialogFumbleLabel": "Patzer ab", + "DS4.RollDialogVisibilityLabel": "Sichtbarkeit", + "DS4.ChatVisibilityRoll": "Alle", + "DS4.ChatVisibilityGmRoll": "Selbst & SL", + "DS4.ChatVisibilityBlindRoll": "Nur SL", + "DS4.ChatVisibilitySelfRoll": "Nur selbst" } diff --git a/src/lang/en.json b/src/lang/en.json index ef1d3eab..c28b165f 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -1,12 +1,17 @@ { "DS4.UserInteractionAddItem": "Add item", + "DS4.UserInteractionEditItem": "Edit item", + "DS4.UserInteractionDeleteItem": "Delete item", "DS4.NotOwned": "No owner", - "DS4.HeadingDescription": "Description", + "DS4.HeadingBiography": "Biography", "DS4.HeadingDetails": "Details", "DS4.HeadingEffects": "Effects", "DS4.HeadingInventory": "Inventory", "DS4.HeadingProfile": "Profile", - "DS4.HeadingTalents": "Talents & Abilities", + "DS4.HeadingTalentsAbilities": "Talents & Abilities", + "DS4.HeadingSpells": "Spells", + "DS4.HeadingDescription": "Description", + "DS4.HeadingSpecialCreatureAbilites": "Special Abilites", "DS4.AttackType": "Attack Type", "DS4.AttackTypeAbbr": "AT", "DS4.WeaponBonus": "Weapon Bonus", @@ -16,10 +21,12 @@ "DS4.AttackTypeMelee": "Melee", "DS4.AttackTypeRanged": "Ranged", "DS4.AttackTypeMeleeRanged": "Melee / Ranged", + "DS4.Description": "Description", "DS4.Quantity": "Quantity", "DS4.PriceGold": "Price (Gold)", "DS4.StorageLocation": "Stored at", "DS4.ItemEquipped": "Equipped", + "DS4.ItemEquippedAbbr": "E", "DS4.ItemOwner": "Owner", "DS4.ItemAvailability": "Availability", "DS4.ItemAvailabilityHamlet": "Hamlet", @@ -36,6 +43,8 @@ "DS4.ItemTypeArmorPlural": "Armor", "DS4.ItemTypeShield": "Shield", "DS4.ItemTypeShieldPlural": "Shields", + "DS4.ItemTypeSpell": "Spell", + "DS4.ItemTypeSpellPlural": "Spells", "DS4.ItemTypeTrinket": "Trinket", "DS4.ItemTypeTrinketPlural": "Trinkets", "DS4.ItemTypeEquipment": "Equipment", @@ -48,6 +57,8 @@ "DS4.ItemTypeLanguagePlural": "Languages", "DS4.ItemTypeAlphabet": "Alphabet", "DS4.ItemTypeAlphabetPlural": "Alphabets", + "DS4.ItemTypeSpecialCreatureAbility": "Special Creature Ability", + "DS4.ItemTypeSpecialCreatureAbilityPlural": "Special Creature Abilities", "DS4.ArmorType": "Armor Type", "DS4.ArmorTypeAbbr": "AT", "DS4.ArmorMaterialType": "Material Type", @@ -72,6 +83,29 @@ "DS4.ArmorMaterialTypeChainAbbr": "Chain", "DS4.ArmorMaterialTypePlate": "Plate", "DS4.ArmorMaterialTypePlateAbbr": "Plate", + "DS4.SpellType": "Spell Type", + "DS4.SpellTypeAbbr": "T", + "DS4.SpellTypeSpellcasting": "Spellcasting", + "DS4.SpellTypeTargetedSpellcasting": "Targeted Spellcasting", + "DS4.SpellCategory": "Category", + "DS4.SpellCategoryHealing": "Healing", + "DS4.SpellCategoryFire": "Fire", + "DS4.SpellCategoryIce": "Ice", + "DS4.SpellCategoryLight": "Light", + "DS4.SpellCategoryDarkness": "Darkness", + "DS4.SpellCategoryMindAffecting": "Mind Affecting", + "DS4.SpellCategoryElectricity": "Electricity", + "DS4.SpellCategoryNone": "None", + "DS4.SpellCategoryUnset": "Unset", + "DS4.SpellBonus": "Spell Bonus", + "DS4.SpellBonusAbbr": "SB", + "DS4.SpellMaxDistance": "Range", + "DS4.SpellEffectRadius": "Radius", + "DS4.SpellDuration": "Duration", + "DS4.SpellCooldownDuration": "Cooldown", + "DS4.SpellScrollPriceGold": "Scroll Price (Gold)", + "DS4.ActorTypeCharacter": "Character", + "DS4.ActorTypeCreature": "Creature", "DS4.AttributeBody": "Body", "DS4.AttributeMobility": "Mobility", "DS4.AttributeMind": "Mind", @@ -89,35 +123,83 @@ "DS4.CombatValuesRangedAttack": "Ranged Attack", "DS4.CombatValuesSpellcasting": "Spellcasting", "DS4.CombatValuesTargetedSpellcasting": "Targeted Spellcasting", - "DS4.BaseInfoRace": "Race", - "DS4.BaseInfoClass": "Class", - "DS4.BaseInfoHeroClass": "Hero Class", - "DS4.BaseInfoCulture": "Culture", - "DS4.ProgressionLevel": "Level", - "DS4.ProgressionExperiencePoints": "Experience Points", - "DS4.ProgressionTalentPoints": "Talent Points", - "DS4.ProgressionProgressPoints": "Progress Points", + "DS4.CharacterBaseInfoRace": "Race", + "DS4.CharacterBaseInfoClass": "Class", + "DS4.CharacterBaseInfoHeroClass": "Hero Class", + "DS4.CharacterBaseInfoCulture": "Culture", + "DS4.CharacterProgressionLevel": "Level", + "DS4.CharacterProgressionExperiencePoints": "Experience Points", + "DS4.CharacterProgressionTalentPoints": "Talent Points", + "DS4.CharacterProgressionProgressPoints": "Progress Points", "DS4.TalentRank": "Rank", "DS4.TalentRankBase": "Acquired Ranks", "DS4.TalentRankMax": "Maximum Ranks", "DS4.TalentRankMod": "Additional Ranks", "DS4.TalentRankTotal": "Total Ranks", - "DS4.LanguageLanguages": "Languages", - "DS4.LanguageAlphabets": "Alphabets", - "DS4.ProfileGender": "Gender", - "DS4.ProfileBirthday": "Birthday", - "DS4.ProfileBirthplace": "Birthplace", - "DS4.ProfileAge": "Age", - "DS4.ProfileHeight": "Height", - "DS4.ProfilHairColor": "Hair Color", - "DS4.ProfileWeight": "Weight", - "DS4.ProfileEyeColor": "Eye Color", - "DS4.ProfileSpecialCharacteristics": "Special Characteristics", - "DS4.CurrencyGold": "Gold", - "DS4.CurrencySilver": "Silver", - "DS4.CurrencyCopper": "Copper", - "DS4.Currency": "Currency", + "DS4.CharacterLanguageLanguages": "Languages", + "DS4.CharacterLanguageAlphabets": "Alphabets", + "DS4.SpecialCreatureAbilityExperiencePoints": "Experience Points", + "DS4.CharacterProfileBiography": "Biography", + "DS4.CharacterProfileGender": "Gender", + "DS4.CharacterProfileBirthday": "Birthday", + "DS4.CharacterProfileBirthplace": "Birthplace", + "DS4.CharacterProfileAge": "Age", + "DS4.CharacterProfileHeight": "Height", + "DS4.CharacterProfileHairColor": "Hair Color", + "DS4.CharacterProfileWeight": "Weight", + "DS4.CharacterProfileEyeColor": "Eye Color", + "DS4.CharacterProfileSpecialCharacteristics": "Special Characteristics", + "DS4.CharacterCurrencyGold": "Gold", + "DS4.CharacterCurrencySilver": "Silver", + "DS4.CharacterCurrencyCopper": "Copper", + "DS4.CharacterCurrency": "Currency", + "DS4.CreatureTypeAnimal": "Animal", + "DS4.CreatureTypeConstruct": "Construct", + "DS4.CreatureTypeHumanoid": "Humanoid", + "DS4.CreatureTypeMagicalEntity": "Magical Entity", + "DS4.CreatureTypePlantBeing": "Plant Being", + "DS4.CreatureTypeUndead": "Undead", + "DS4.CreatureSizeCategoryTiny": "Tiny", + "DS4.CreatureSizeCategorySmall": "Small", + "DS4.CreatureSizeCategoryNormal": "Normal", + "DS4.CreatureSizeCategoryLarge": "Large", + "DS4.CreatureSizeCategoryHuge": "Huge", + "DS4.CreatureSizeCategoryColossal": "Colossal", + "DS4.CreatureBaseInfoLoot": "Loot", + "DS4.CreatureBaseInfoFoeFactor": "Foe Factor", + "DS4.CreatureBaseInfoCreatureType": "Creature Type", + "DS4.CreatureBaseInfoSizeCategory": "Size Category", + "DS4.CreatureBaseInfoExperiencePoints": "Experience Points", + "DS4.CreatureBaseInfoDescription": "Description", "DS4.WarningManageActiveEffectOnOwnedItem": "Managing Active Effects within an Owned Item is not currently supported and will be added in a subsequent update.", + "DS4.WarningActorCannotOwnItem": "The actor '{actorName}' of type '{actorType}' cannot own the item '{itemName}' of type '{itemType}'.", "DS4.ErrorDiceCritOverlap": "There's an overlap between Fumbles and Coups", - "DS4.ErrorExplodingRecursionLimitExceeded": "Maximum recursion depth for exploding dice roll exceeded" + "DS4.ErrorExplodingRecursionLimitExceeded": "Maximum recursion depth for exploding dice roll exceeded", + "DS4.UnitRounds": "Rounds", + "DS4.UnitRoundsAbbr": "rnd", + "DS4.UnitMinutes": "Minutes", + "DS4.UnitMinutesAbbr": "min", + "DS4.UnitHours": "Hours", + "DS4.UnitHoursAbbr": "h", + "DS4.UnitDays": "Days", + "DS4.UnitDaysAbbr": "d", + "DS4.UnitMeters": "Meters", + "DS4.UnitMetersAbbr": "m", + "DS4.UnitKilometers": "Kilometers", + "DS4.UnitKilometersAbbr": "km", + "DS4.UnitCustom": "Custom Unit", + "DS4.UnitCustomAbbr": " ", + "DS4.RollDialogDefaultTitle": "Roll Options", + "DS4.RollDialogOkButton": "Ok", + "DS4.RollDialogCancelButton": "Cancel", + "DS4.ErrorUnexpectedHtmlType": "Type Error: Expected {exType}, got {realType}", + "DS4.RollDialogTargetLabel": "Check Target Number", + "DS4.RollDialogModifierLabel": "Game Master Modifier", + "DS4.RollDialogCoupLabel": "Coup to", + "DS4.RollDialogFumbleLabel": "Fumble from", + "DS4.RollDialogVisibilityLabel": "Visibility", + "DS4.ChatVisibilityRoll": "All", + "DS4.ChatVisibilityGmRoll": "Self & GM", + "DS4.ChatVisibilityBlindRoll": "GM only", + "DS4.ChatVisibilitySelfRoll": "Self only" } diff --git a/src/module/actor/actor-data.ts b/src/module/actor/actor-data.ts index 97d12f1b..dba57d9f 100644 --- a/src/module/actor/actor-data.ts +++ b/src/module/actor/actor-data.ts @@ -1,39 +1,19 @@ -export interface DS4ActorDataType { +import { ModifiableData, ResourceData, UsableResource } from "../common/common-data"; + +export type DS4ActorDataType = DS4ActorDataCharacter | DS4ActorDataCreature; + +interface DS4ActorDataBase { attributes: DS4ActorDataAttributes; traits: DS4ActorDataTraits; combatValues: DS4ActorDataCombatValues; - baseInfo: DS4ActorDataBaseInfo; - progression: DS4ActorDataProgression; - language: DS4ActorDataLanguage; - profile: DS4ActorDataProfile; - currency: DS4ActorDataCurrency; } interface DS4ActorDataAttributes { - body: BodyAttribute; + body: ModifiableData; mobility: ModifiableData; mind: ModifiableData; } -export interface ModifiableData { - base: T; - mod: T; - total?: T; -} - -interface UsableResource { - total: T; - used: T; -} - -interface ResourceData extends ModifiableData { - value: T; - max?: T; -} - -// Blueprint in case we need more detailed differentiation -type BodyAttribute = ModifiableData; - interface DS4ActorDataTraits { strength: ModifiableData; constitution: ModifiableData; @@ -54,26 +34,35 @@ interface DS4ActorDataCombatValues { targetedSpellcasting: ModifiableData; } -interface DS4ActorDataBaseInfo { +interface DS4ActorDataCharacter extends DS4ActorDataBase { + baseInfo: DS4ActorDataCharacterBaseInfo; + progression: DS4ActorDataCharacterProgression; + language: DS4ActorDataCharacterLanguage; + profile: DS4ActorDataCharacterProfile; + currency: DS4ActorDataCharacterCurrency; +} + +interface DS4ActorDataCharacterBaseInfo { race: string; class: string; heroClass: string; culture: string; } -interface DS4ActorDataProgression { +interface DS4ActorDataCharacterProgression { level: number; experiencePoints: number; talentPoints: UsableResource; progressPoints: UsableResource; } -interface DS4ActorDataLanguage { +interface DS4ActorDataCharacterLanguage { languages: string; alphabets: string; } -interface DS4ActorDataProfile { +interface DS4ActorDataCharacterProfile { + biography: string; gender: string; birthday: string; birthplace: string; @@ -85,8 +74,25 @@ interface DS4ActorDataProfile { specialCharacteristics: string; } -interface DS4ActorDataCurrency { +interface DS4ActorDataCharacterCurrency { gold: number; silver: number; copper: number; } + +interface DS4ActorDataCreature extends DS4ActorDataBase { + baseInfo: DS4ActorDataCreatureBaseInfo; +} + +type CreatureType = "animal" | "construct" | "humanoid" | "magicalEntity" | "plantBeing" | "undead"; + +type SizeCategory = "tiny" | "small" | "normal" | "large" | "huge" | "colossal"; + +interface DS4ActorDataCreatureBaseInfo { + loot: string; + foeFactor: number; + creatureType: CreatureType; + sizeCategory: SizeCategory; + experiencePoints: number; + description: string; +} diff --git a/src/module/actor/actor.ts b/src/module/actor/actor.ts index 7f2f8209..df3ad6d7 100644 --- a/src/module/actor/actor.ts +++ b/src/module/actor/actor.ts @@ -1,6 +1,7 @@ +import { ModifiableData } from "../common/common-data"; import { DS4Item } from "../item/item"; -import { DS4ItemDataType } from "../item/item-data"; -import { DS4ActorDataType, ModifiableData } from "./actor-data"; +import { DS4ItemDataType, ItemType } from "../item/item-data"; +import { DS4ActorDataType } from "./actor-data"; export class DS4Actor extends Actor { /** @override */ @@ -21,4 +22,37 @@ export class DS4Actor extends Actor combatValues.hitPoints.max = combatValues.hitPoints.total; } + + /** + * The list of item types that can be owned by this actor. + */ + get ownableItemTypes(): Array { + switch (this.data.type) { + case "character": + return [ + "weapon", + "armor", + "shield", + "trinket", + "equipment", + "spell", + "talent", + "racialAbility", + "language", + "alphabet", + ]; + case "creature": + return ["weapon", "armor", "shield", "trinket", "equipment", "spell", "specialCreatureAbility"]; + default: + return []; + } + } + + /** + * Checks whether or not the given item type can be owned by the actor. + * @param itemType the item type to check + */ + canOwnItemType(itemType: ItemType): boolean { + return this.ownableItemTypes.includes(itemType); + } } diff --git a/src/module/actor/actor-sheet.ts b/src/module/actor/sheets/actor-sheet.ts similarity index 84% rename from src/module/actor/actor-sheet.ts rename to src/module/actor/sheets/actor-sheet.ts index 978b7c6c..26f6bd8b 100644 --- a/src/module/actor/actor-sheet.ts +++ b/src/module/actor/sheets/actor-sheet.ts @@ -1,12 +1,30 @@ -import { DS4ItemDataType } from "../item/item-data"; -import { DS4Actor } from "./actor"; -import { DS4ActorDataType } from "./actor-data"; +import { DS4Item } from "../../item/item"; +import { DS4ItemDataType, ItemType } from "../../item/item-data"; +import { DS4Actor } from "../actor"; +import { DS4ActorDataType } from "../actor-data"; /** * Extend the basic ActorSheet with some very simple modifications * @extends {ActorSheet} */ export class DS4ActorSheet extends ActorSheet { + /** @override */ + static get defaultOptions(): FormApplicationOptions { + return mergeObject(super.defaultOptions, { + classes: ["ds4", "sheet", "actor"], + width: 745, + height: 600, + }); + } + + /** @override */ + get template(): string { + const path = "systems/ds4/templates/actor"; + return `${path}/${this.actor.data.type}-sheet.hbs`; + } + + /* -------------------------------------------- */ + /** * This method returns the data for the template of the actor sheet. * It explicitly adds the items of the object sorted by type in the @@ -21,21 +39,9 @@ export class DS4ActorSheet extends ActorSheet { + const data = JSON.parse(event.dataTransfer?.getData("text/plain")) as { type?: string }; + if (data.type === "Item") { + const item = await Item.fromDropData(data as Parameters[0]); + if (item && !this.actor.canOwnItemType(item.data.type as ItemType)) { + ui.notifications.warn( + game.i18n.format("DS4.WarningActorCannotOwnItem", { + actorName: this.actor.name, + actorType: this.actor.data.type, + itemName: item.name, + itemType: item.data.type, + }), + ); + return false; + } + } + return super._onDrop(event); + } } diff --git a/src/module/actor/sheets/character-sheet.ts b/src/module/actor/sheets/character-sheet.ts new file mode 100644 index 00000000..a7f9d15e --- /dev/null +++ b/src/module/actor/sheets/character-sheet.ts @@ -0,0 +1,11 @@ +import { DS4ActorSheet } from "./actor-sheet"; + +export class DS4CharacterActorSheet extends DS4ActorSheet { + /** @override */ + static get defaultOptions(): FormApplicationOptions { + return mergeObject(super.defaultOptions, { + classes: ["ds4", "sheet", "actor", "character"], + tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "inventory" }], + }); + } +} diff --git a/src/module/actor/sheets/creature-sheet.ts b/src/module/actor/sheets/creature-sheet.ts new file mode 100644 index 00000000..8c86848f --- /dev/null +++ b/src/module/actor/sheets/creature-sheet.ts @@ -0,0 +1,11 @@ +import { DS4ActorSheet } from "./actor-sheet"; + +export class DS4CreatureActorSheet extends DS4ActorSheet { + /** @override */ + static get defaultOptions(): FormApplicationOptions { + return mergeObject(super.defaultOptions, { + classes: ["ds4", "sheet", "actor", "creature"], + tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "inventory" }], + }); + } +} diff --git a/src/module/common/common-data.ts b/src/module/common/common-data.ts new file mode 100644 index 00000000..41bfc3c4 --- /dev/null +++ b/src/module/common/common-data.ts @@ -0,0 +1,15 @@ +export interface ModifiableData { + base: T; + mod: T; + total?: T; +} + +export interface ResourceData extends ModifiableData { + value: T; + max?: T; +} + +export interface UsableResource { + total: T; + used: T; +} diff --git a/src/module/config.ts b/src/module/config.ts index 9cab1d5f..106a791f 100644 --- a/src/module/config.ts +++ b/src/module/config.ts @@ -26,6 +26,14 @@ export const DS4 = { ranged: "systems/ds4/assets/official/DS4-RAT.png", }, + /** + * Define the file paths to icon images + */ + spellTypesIcons: { + spellcasting: "systems/ds4/assets/official/DS4-SPC.png", + targetedSpellcasting: "systems/ds4/assets/official/DS4-TSC.png", + }, + /** * Define the set of item availabilties */ @@ -46,12 +54,14 @@ export const DS4 = { weapon: "DS4.ItemTypeWeapon", armor: "DS4.ItemTypeArmor", shield: "DS4.ItemTypeShield", + spell: "DS4.ItemTypeSpell", trinket: "DS4.ItemTypeTrinket", equipment: "DS4.ItemTypeEquipment", talent: "DS4.ItemTypeTalent", racialAbility: "DS4.ItemTypeRacialAbility", language: "DS4.ItemTypeLanguage", alphabet: "DS4.ItemTypeAlphabet", + specialCreatureAbility: "DS4.ItemTypeSpecialCreatureAbility", }, /** @@ -96,8 +106,33 @@ export const DS4 = { plate: "DS4.ArmorMaterialTypePlateAbbr", }, + spellTypes: { + spellcasting: "DS4.SpellTypeSpellcasting", + targetedSpellcasting: "DS4.SpellTypeTargetedSpellcasting", + }, + + spellCategories: { + healing: "DS4.SpellCategoryHealing", + fire: "DS4.SpellCategoryFire", + ice: "DS4.SpellCategoryIce", + light: "DS4.SpellCategoryLight", + darkness: "DS4.SpellCategoryDarkness", + mindAffecting: "DS4.SpellCategoryMindAffecting", + electricity: "DS4.SpellCategoryElectricity", + none: "DS4.SpellCategoryNone", + unset: "DS4.SpellCategoryUnset", + }, + /** - * Define the set of attributes a character has + * Define the set of actor types + */ + actorTypes: { + character: "DS4.ActorTypeCharacter", + creature: "DS4.ActorTypeCreature", + }, + + /** + * Define the set of attributes an actor has */ attributes: { body: "DS4.AttributeBody", @@ -106,7 +141,7 @@ export const DS4 = { }, /** - * Define the set of traits a character has + * Define the set of traits an actor has */ traits: { strength: "DS4.TraitStrength", @@ -118,7 +153,7 @@ export const DS4 = { }, /** - * Define the set of combat values a character has + * Define the set of combat values an actor has */ combatValues: { hitPoints: "DS4.CombatValuesHitPoints", @@ -134,50 +169,52 @@ export const DS4 = { /** * Define the base info of a character */ - baseInfo: { - race: "DS4.BaseInfoRace", - class: "DS4.BaseInfoClass", - heroClass: "DS4.BaseInfoHeroClass", - culture: "DS4.BaseInfoCulture", + characterBaseInfo: { + race: "DS4.CharacterBaseInfoRace", + class: "DS4.CharacterBaseInfoClass", + heroClass: "DS4.CharacterBaseInfoHeroClass", + culture: "DS4.CharacterBaseInfoCulture", }, /** * Define the progression info of a character */ - progression: { - level: "DS4.ProgressionLevel", - experiencePoints: "DS4.ProgressionExperiencePoints", - talentPoints: "DS4.ProgressionTalentPoints", - progressPoints: "DS4.ProgressionProgressPoints", + characterProgression: { + level: "DS4.CharacterProgressionLevel", + experiencePoints: "DS4.CharacterProgressionExperiencePoints", + talentPoints: "DS4.CharacterProgressionTalentPoints", + progressPoints: "DS4.CharacterProgressionProgressPoints", }, /** * Define the language info of a character */ - language: { - languages: "DS4.LanguageLanguages", - alphabets: "DS4.LanguageAlphabets", + characterLanguage: { + languages: "DS4.CharacterLanguageLanguages", + alphabets: "DS4.CharacterLanguageAlphabets", }, /** * Define the profile info of a character */ - profile: { - gender: "DS4.ProfileGender", - birthday: "DS4.ProfileBirthday", - birthplace: "DS4.ProfileBirthplace", - age: "DS4.ProfileAge", - height: "DS4.ProfileHeight", - hairColor: "DS4.ProfilHairColor", - weight: "DS4.ProfileWeight", - eyeColor: "DS4.ProfileEyeColor", - specialCharacteristics: "DS4.ProfileSpecialCharacteristics", + characterProfile: { + biography: "DS4.CharacterProfileBiography", + gender: "DS4.CharacterProfileGender", + birthday: "DS4.CharacterProfileBirthday", + birthplace: "DS4.CharacterProfileBirthplace", + age: "DS4.CharacterProfileAge", + height: "DS4.CharacterProfileHeight", + hairColor: "DS4.CharacterProfileHairColor", + weight: "DS4.CharacterProfileWeight", + eyeColor: "DS4.CharacterProfileEyeColor", + specialCharacteristics: "DS4.CharacterProfileSpecialCharacteristics", }, /** - * Define the profile info types for hanndlebars of a character + * Define the profile info types for handlebars of a character */ - profileDTypes: { + characterProfileDTypes: { + biography: "String", gender: "String", birthday: "String", birthplace: "String", @@ -192,9 +229,94 @@ export const DS4 = { /** * Define currency elements of a character */ - currency: { - gold: "DS4.CurrencyGold", - silver: "DS4.CurrencySilver", - copper: "DS4.CurrencyCopper", + characterCurrency: { + gold: "DS4.CharacterCurrencyGold", + silver: "DS4.CharacterCurrencySilver", + copper: "DS4.CharacterCurrencyCopper", + }, + + /** + * Define the different creature types a creature can be + */ + creatureTypes: { + animal: "DS4.CreatureTypeAnimal", + construct: "DS4.CreatureTypeConstruct", + humanoid: "DS4.CreatureTypeHumanoid", + magicalEntity: "DS4.CreatureTypeMagicalEntity", + plantBeing: "DS4.CreatureTypePlantBeing", + undead: "DS4.CreatureTypeUndead", + }, + + /** + * Define the different size categories creatures fall into + */ + creatureSizeCategories: { + tiny: "DS4.CreatureSizeCategoryTiny", + small: "DS4.CreatureSizeCategorySmall", + normal: "DS4.CreatureSizeCategoryNormal", + large: "DS4.CreatureSizeCategoryLarge", + huge: "DS4.CreatureSizeCategoryHuge", + colossal: "DS4.CreatureSizeCategoryColossal", + }, + + /** + * Define the base info of a creature + */ + creatureBaseInfo: { + loot: "DS4.CreatureBaseInfoLoot", + foeFactor: "DS4.CreatureBaseInfoFoeFactor", + creatureType: "DS4.CreatureBaseInfoCreatureType", + sizeCategory: "DS4.CreatureBaseInfoSizeCategory", + experiencePoints: "DS4.CreatureBaseInfoExperiencePoints", + description: "DS4.CreatureBaseInfoDescription", + }, + + /** + * Define translations for available distance units + */ + distanceUnits: { + meter: "DS4.UnitMeters", + kilometer: "DS4.UnitKilometers", + custom: "DS4.UnitCustom", + }, + /** + * Define abbreviations for available distance units + */ + distanceUnitsAbbr: { + meter: "DS4.UnitMetersAbbr", + kilometer: "DS4.UnitKilometersAbbr", + custom: "DS4.UnitCustomAbbr", + }, + + /** + * Define translations for available distance units + */ + temporalUnits: { + rounds: "DS4.UnitRounds", + minutes: "DS4.UnitMinutes", + hours: "DS4.UnitHours", + days: "DS4.UnitDays", + custom: "DS4.UnitCustom", + }, + + /** + * Define abbreviations for available units + */ + temporalUnitsAbbr: { + rounds: "DS4.UnitRoundsAbbr", + minutes: "DS4.UnitMinutesAbbr", + hours: "DS4.UnitHoursAbbr", + days: "DS4.UnitDaysAbbr", + custom: "DS4.UnitCustomAbbr", + }, + + /** + * Define localization strings for Chat Visibility + */ + chatVisibilities: { + roll: "DS4.ChatVisibilityRoll", + gmroll: "DS4.ChatVisibilityGmRoll", + blindroll: "DS4.ChatVisibilityBlindRoll", + selfroll: "DS4.ChatVisibilitySelfRoll", }, }; diff --git a/src/module/ds4.ts b/src/module/ds4.ts index 29a71aa3..1351b96c 100644 --- a/src/module/ds4.ts +++ b/src/module/ds4.ts @@ -1,10 +1,12 @@ // Import Modules import { DS4Actor } from "./actor/actor"; -import { DS4ActorSheet } from "./actor/actor-sheet"; import { DS4Item } from "./item/item"; import { DS4ItemSheet } from "./item/item-sheet"; import { DS4 } from "./config"; import { DS4Check } from "./rolls/check"; +import { DS4CharacterActorSheet } from "./actor/sheets/character-sheet"; +import { DS4CreatureActorSheet } from "./actor/sheets/creature-sheet"; +import { createCheckRoll } from "./rolls/check-factory"; Hooks.once("init", async function () { console.log(`DS4 | Initializing the DS4 Game System\n${DS4.ASCII}`); @@ -13,6 +15,7 @@ Hooks.once("init", async function () { DS4Actor, DS4Item, DS4, + createCheckRoll, }; // Record configuration @@ -22,6 +25,10 @@ Hooks.once("init", async function () { CONFIG.Actor.entityClass = DS4Actor as typeof Actor; CONFIG.Item.entityClass = DS4Item as typeof Item; + // Define localized type labels + CONFIG.Actor.typeLabels = DS4.actorTypes; + CONFIG.Item.typeLabels = DS4.itemTypes; + // Configure Dice CONFIG.Dice.types = [Die, DS4Check]; CONFIG.Dice.terms = { @@ -32,7 +39,8 @@ Hooks.once("init", async function () { // Register sheet application classes Actors.unregisterSheet("core", ActorSheet); - Actors.registerSheet("ds4", DS4ActorSheet, { makeDefault: true }); + Actors.registerSheet("ds4", DS4CharacterActorSheet, { types: ["character"], makeDefault: true }); + Actors.registerSheet("ds4", DS4CreatureActorSheet, { types: ["creature"], makeDefault: true }); Items.unregisterSheet("core", ItemSheet); Items.registerSheet("ds4", DS4ItemSheet, { makeDefault: true }); @@ -47,13 +55,15 @@ async function registerHandlebarsPartials() { "systems/ds4/templates/item/partials/effects.hbs", "systems/ds4/templates/item/partials/body.hbs", "systems/ds4/templates/actor/partials/items-overview.hbs", - "systems/ds4/templates/actor/partials/talents-overview.hbs", + "systems/ds4/templates/actor/partials/talents-abilities-overview.hbs", + "systems/ds4/templates/actor/partials/spells-overview.hbs", "systems/ds4/templates/actor/partials/overview-add-button.hbs", "systems/ds4/templates/actor/partials/overview-control-buttons.hbs", "systems/ds4/templates/actor/partials/attributes-traits.hbs", "systems/ds4/templates/actor/partials/combat-values.hbs", "systems/ds4/templates/actor/partials/profile.hbs", "systems/ds4/templates/actor/partials/character-progression.hbs", + "systems/ds4/templates/actor/partials/special-creature-abilites-overview.hbs", ]; return loadTemplates(templatePaths); } @@ -76,18 +86,28 @@ Hooks.once("setup", function () { "armorMaterialTypes", "armorMaterialTypesAbbr", "armorMaterialTypes", + "spellTypes", + "spellCategories", "attributes", "traits", "combatValues", - "baseInfo", - "progression", - "language", - "profile", - "currency", + "characterBaseInfo", + "characterProgression", + "characterLanguage", + "characterProfile", + "characterCurrency", + "creatureTypes", + "creatureSizeCategories", + "creatureBaseInfo", + "temporalUnits", + "temporalUnitsAbbr", + "distanceUnits", + "distanceUnitsAbbr", + "chatVisibilities", ]; // Exclude some from sorting where the default order matters - const noSort = ["attributes", "traits", "combatValues"]; + const noSort = ["attributes", "traits", "combatValues", "creatureSizeCategories"]; // Localize and sort CONFIG objects for (const o of toLocalize) { diff --git a/src/module/item/item-data.ts b/src/module/item/item-data.ts index 23105eb6..64ee17f2 100644 --- a/src/module/item/item-data.ts +++ b/src/module/item/item-data.ts @@ -1,15 +1,20 @@ -import { ModifiableData } from "../actor/actor-data"; +import { ModifiableData } from "../common/common-data"; +import { DS4 } from "../config"; + +export type ItemType = keyof typeof DS4.itemTypes; export type DS4ItemDataType = | DS4Weapon | DS4Armor | DS4Shield + | DS4Spell | DS4Trinket | DS4Equipment | DS4Talent | DS4RacialAbility | DS4Language - | DS4Alphabet; + | DS4Alphabet + | DS4SpecialCreatureAbility; // types @@ -32,12 +37,35 @@ interface DS4TalentRank extends ModifiableData { max: number; } +interface DS4Spell extends DS4ItemBase, DS4ItemEquipable { + spellType: "spellcasting" | "targetedSpellcasting"; + bonus: string; + spellCategory: + | "healing" + | "fire" + | "ice" + | "light" + | "darkness" + | "mindAffecting" + | "electricity" + | "none" + | "unset"; + maxDistance: UnitData; + effectRadius: UnitData; + duration: UnitData; + cooldownDuration: UnitData; + scrollPrice: number; +} + interface DS4Shield extends DS4ItemBase, DS4ItemPhysical, DS4ItemEquipable, DS4ItemProtective {} interface DS4Trinket extends DS4ItemBase, DS4ItemPhysical, DS4ItemEquipable {} interface DS4Equipment extends DS4ItemBase, DS4ItemPhysical {} type DS4RacialAbility = DS4ItemBase; type DS4Language = DS4ItemBase; type DS4Alphabet = DS4ItemBase; +interface DS4SpecialCreatureAbility extends DS4ItemBase { + experiencePoints: number; +} // templates @@ -62,3 +90,10 @@ interface DS4ItemEquipable { interface DS4ItemProtective { armorValue: number; } + +interface UnitData { + value: string; + unit: UnitType; +} +type TemporalUnit = "rounds" | "minutes" | "hours" | "days" | "custom"; +type DistanceUnit = "meter" | "kilometer" | "custom"; diff --git a/src/module/rolls/check-factory.ts b/src/module/rolls/check-factory.ts new file mode 100644 index 00000000..066202d6 --- /dev/null +++ b/src/module/rolls/check-factory.ts @@ -0,0 +1,237 @@ +import { DS4 } from "../config"; + +/** + * Provides default values for all arguments the `CheckFactory` expects. + */ +class DefaultCheckOptions implements DS4CheckFactoryOptions { + maxCritSuccess = 1; + minCritFailure = 20; + useSlayingDice = false; + rollMode: DS4RollMode = "roll"; + + mergeWith(other: Partial): DS4CheckFactoryOptions { + return { ...this, ...other } as DS4CheckFactoryOptions; + } +} + +/** + * Singleton reference for default value extraction. + */ +const defaultCheckOptions = new DefaultCheckOptions(); + +/** + * Most basic class responsible for generating the chat formula and passing it to the chat as roll. + */ +class CheckFactory { + constructor( + private checkTargetValue: number, + private gmModifier: number, + passedOptions: Partial = {}, + ) { + this.checkOptions = new DefaultCheckOptions().mergeWith(passedOptions); + } + + private checkOptions: DS4CheckFactoryOptions; + + async execute(): Promise { + const rollCls: typeof Roll = CONFIG.Dice.rolls[0]; + + const formula = [ + "ds", + this.createTargetValueTerm(), + this.createCritTerm(), + this.createSlayingDiceTerm(), + ].filterJoin(""); + const roll = new rollCls(formula); + + const rollModeTemplate = this.checkOptions.rollMode; + console.log(rollModeTemplate); + return roll.toMessage({}, { rollMode: rollModeTemplate, create: true }); + } + + // Term generators + createTargetValueTerm(): string | null { + if (this.checkTargetValue !== null) { + return "v" + (this.checkTargetValue + this.gmModifier); + } else { + return null; + } + } + + createCritTerm(): string | null { + const minCritRequired = this.checkOptions.minCritFailure !== defaultCheckOptions.minCritFailure; + const maxCritRequired = this.checkOptions.maxCritSuccess !== defaultCheckOptions.maxCritSuccess; + + if (minCritRequired || maxCritRequired) { + return "c" + (this.checkOptions.maxCritSuccess ?? "") + "," + (this.checkOptions.minCritFailure ?? ""); + } else { + return null; + } + } + + createSlayingDiceTerm(): string | null { + return this.checkOptions.useSlayingDice ? "x" : null; + } +} + +/** + * Asks the user for all unknown/necessary information and passes them on to perform a roll. + * @param targetValue {number} The Check Target Number ("CTN") + * @param options {Partial} Options changing the behaviour of the roll and message. + */ +export async function createCheckRoll( + targetValue: number, + options: Partial = {}, +): Promise { + // Ask for additional required data; + const gmModifierData = await askGmModifier(targetValue, options); + + const newOptions: Partial = { + maxCritSuccess: gmModifierData.maxCritSuccess ?? options.maxCritSuccess ?? undefined, + minCritFailure: gmModifierData.minCritFailure ?? options.minCritFailure ?? undefined, + useSlayingDice: gmModifierData.useSlayingDice ?? options.useSlayingDice ?? undefined, + rollMode: gmModifierData.rollMode ?? options.rollMode ?? undefined, + }; + + // Create Factory + const cf = new CheckFactory(gmModifierData.checkTargetValue, gmModifierData.gmModifier, newOptions); + + // Possibly additional processing + + // Execute roll + await cf.execute(); +} + +/** + * Responsible for rendering the modal interface asking for the modifier specified by GM and (currently) additional data. + * + * @notes + * At the moment, this asks for more data than it will do after some iterations. + * + * @returns {Promise} The data given by the user. + */ +async function askGmModifier( + targetValue: number, + options: Partial = {}, + { template, title }: { template?: string; title?: string } = {}, +): Promise { + // Render model interface and return value + const usedTemplate = template ?? "systems/ds4/templates/roll/roll-options.hbs"; + const usedTitle = title ?? game.i18n.localize("DS4.RollDialogDefaultTitle"); + const templateData = { + cssClass: "roll-option", + title: usedTitle, + checkTargetValue: targetValue, + maxCritSuccess: options.maxCritSuccess ?? defaultCheckOptions.maxCritSuccess, + minCritFailure: options.minCritFailure ?? defaultCheckOptions.minCritFailure, + rollModes: rollModes, + config: DS4, + }; + const renderedHtml = await renderTemplate(usedTemplate, templateData); + + const dialogPromise = new Promise((resolve) => { + new Dialog( + { + title: usedTitle, + close: () => { + // Don't do anything + }, + content: renderedHtml, + buttons: { + ok: { + label: game.i18n.localize("DS4.RollDialogOkButton"), + callback: (html: HTMLElement | JQuery) => { + if (!("jquery" in html)) { + throw new Error( + game.i18n.format("DS4.ErrorUnexpectedHtmlType", { + exType: "JQuery", + realType: "HTMLElement", + }), + ); + } else { + const innerForm = html[0].querySelector("form"); + resolve(innerForm); + } + }, + }, + cancel: { + label: game.i18n.localize("DS4.RollDialogCancelButton"), + callback: () => { + // Don't do anything + }, + }, + }, + default: "ok", + }, + {}, + ).render(true); + }); + const dialogForm = await dialogPromise; + return parseDialogFormData(dialogForm, targetValue); +} + +/** + * Extracts Dialog data from the returned DOM element. + * @param formData {HTMLFormElement} The filed dialog + * @param targetValue {number} The previously known target value (slated for removal once data automation is available) + */ +function parseDialogFormData(formData: HTMLFormElement, targetValue: number): IntermediateGmModifierData { + return { + checkTargetValue: parseInt(formData["ctv"]?.value) ?? targetValue, + gmModifier: parseInt(formData["gmmod"]?.value) ?? 0, + maxCritSuccess: parseInt(formData["maxcoup"]?.value) ?? defaultCheckOptions.maxCritSuccess, + minCritFailure: parseInt(formData["minfumble"]?.value) ?? defaultCheckOptions.minCritFailure, + useSlayingDice: false, + rollMode: formData["visibility"]?.value ?? defaultCheckOptions.rollMode, + }; +} + +/** + * Contains data that needs retrieval from an interactive Dialog. + */ +interface GmModifierData { + gmModifier: number; + rollMode: DS4RollMode; +} + +/** + * Contains *CURRENTLY* necessary Data for drafting a roll. + * + * @deprecated + * Quite a lot of this information is requested due to a lack of automation: + * - maxCritSuccess + * - minCritFailure + * - useSlayingDice + * - checkTargetValue + * + * They will and should be removed once effects and data retrieval is in place. + * If a "raw" roll dialog is necessary, create another pre-porcessing Dialog + * class asking for the required information. + * This interface should then be replaced with the `GmModifierData`. + */ +interface IntermediateGmModifierData extends GmModifierData { + checkTargetValue: number; + gmModifier: number; + maxCritSuccess: number; + minCritFailure: number; + // TODO: In final version from system settings + useSlayingDice: boolean; + rollMode: DS4RollMode; +} + +/** + * The minimum behavioural options that need to be passed to the factory. + */ +export interface DS4CheckFactoryOptions { + maxCritSuccess: number; + minCritFailure: number; + useSlayingDice: boolean; + rollMode: DS4RollMode; +} + +/** + * Defines all possible roll modes, both for iterating and typing. + */ +const rollModes = ["roll", "gmroll", "blindroll", "selfroll"] as const; +type DS4RollModeTuple = typeof rollModes; +export type DS4RollMode = DS4RollModeTuple[number]; diff --git a/src/module/rolls/check.ts b/src/module/rolls/check.ts index 5886813c..38773fb3 100644 --- a/src/module/rolls/check.ts +++ b/src/module/rolls/check.ts @@ -86,7 +86,7 @@ export class DS4Check extends DiceTerm { } else { return ds4roll(targetValueToUse, { maxCritSuccess: this.maxCritSuccess, - minCritFail: this.minCritFailure, + minCritFailure: this.minCritFailure, slayingDiceRepetition: slayingDiceRepetition, useSlayingDice: slayingDiceRepetition, }); @@ -132,7 +132,6 @@ export class DS4Check extends DiceTerm { static readonly DEFAULT_TARGET_VALUE = 10; static readonly DEFAULT_MAX_CRIT_SUCCESS = 1; static readonly DEFAULT_MIN_CRIT_FAILURE = 20; - // TODO: add to Type declarations static DENOMINATION = "s"; static MODIFIERS = { x: "explode", diff --git a/src/module/rolls/roll-data.ts b/src/module/rolls/roll-data.ts index 964034c9..78329e44 100644 --- a/src/module/rolls/roll-data.ts +++ b/src/module/rolls/roll-data.ts @@ -1,13 +1,13 @@ export interface RollOptions { maxCritSuccess: number; - minCritFail: number; + minCritFailure: number; useSlayingDice: boolean; slayingDiceRepetition: boolean; } export class DefaultRollOptions implements RollOptions { public maxCritSuccess = 1; - public minCritFail = 20; + public minCritFailure = 20; public useSlayingDice = false; public slayingDiceRepetition = false; diff --git a/src/module/rolls/roll-executor.ts b/src/module/rolls/roll-executor.ts index 72e6b2c4..c7e187b1 100644 --- a/src/module/rolls/roll-executor.ts +++ b/src/module/rolls/roll-executor.ts @@ -48,7 +48,7 @@ export function rollCheckSingleDie( if (rolledDie <= usedOptions.maxCritSuccess) { return new RollResult(checkTargetValue, RollResultStatus.CRITICAL_SUCCESS, usedDice, true); - } else if (rolledDie >= usedOptions.minCritFail && !isSlayingDiceRepetition(usedOptions)) { + } else if (rolledDie >= usedOptions.minCritFailure && !isSlayingDiceRepetition(usedOptions)) { return new RollResult(0, RollResultStatus.CRITICAL_FAILURE, usedDice, true); } else { if (rolledDie <= checkTargetValue) { @@ -90,7 +90,7 @@ export function rollCheckMultipleDice( const slayingDiceRepetition = isSlayingDiceRepetition(usedOptions); // Slaying Dice require a different handling. - if (firstResult >= usedOptions.minCritFail && !slayingDiceRepetition) { + if (firstResult >= usedOptions.minCritFailure && !slayingDiceRepetition) { return new RollResult(0, RollResultStatus.CRITICAL_FAILURE, usedDice, true); } diff --git a/src/scss/components/_description.scss b/src/scss/components/_description.scss index cc4c1322..767fb516 100644 --- a/src/scss/components/_description.scss +++ b/src/scss/components/_description.scss @@ -9,12 +9,13 @@ .side-property { margin: 2px 0; display: grid; - grid-template-columns: minmax(30%, auto) auto; + grid-template-columns: 40% auto; justify-content: left; label { line-height: $default-input-height; font-weight: bold; + padding-right: 3pt; } input, @@ -30,6 +31,17 @@ height: 100%; margin: 0px; } + + .unit-data-pair { + display: flex; + flex-direction: row; + select { + width: 4em; + } + input { + max-width: 7em; + } + } } } diff --git a/src/system.json b/src/system.json index f576d87d..6c742c7a 100644 --- a/src/system.json +++ b/src/system.json @@ -6,7 +6,7 @@ "minimumCoreVersion": "0.7.9", "compatibleCoreVersion": "0.7.9", "templateVersion": 2, - "author": "Johannes Loher, Gesina Schwalbe, Oliver Rümpelein", + "author": "Johannes Loher, Gesina Schwalbe, Oliver Rümpelein, Siegfried Krug", "esmodules": ["module/ds4.js"], "styles": ["ds4.css"], "scripts": [], @@ -29,5 +29,6 @@ "url": "https://git.f3l.de/dungeonslayers/ds4", "manifest": "https://git.f3l.de/dungeonslayers/ds4/-/raw/latest/src/system.json?inline=false", "download": "https://git.f3l.de/dungeonslayers/ds4/-/jobs/artifacts/0.1.0/download?job=build", - "license": "MIT" + "license": "MIT", + "initiative": "@combatValues.initiative.total" } diff --git a/src/template.json b/src/template.json index 293d54b9..726d0a56 100644 --- a/src/template.json +++ b/src/template.json @@ -1,84 +1,98 @@ { "Actor": { - "types": ["character"], - "templates": {}, + "types": ["character", "creature"], + "templates": { + "base": { + "attributes": { + "body": { + "base": 0, + "mod": 0 + }, + "mobility": { + "base": 0, + "mod": 0 + }, + "mind": { + "base": 0, + "mod": 0 + } + }, + "traits": { + "strength": { + "base": 0, + "mod": 0 + }, + "constitution": { + "base": 0, + "mod": 0 + }, + "agility": { + "base": 0, + "mod": 0 + }, + "dexterity": { + "base": 0, + "mod": 0 + }, + "intellect": { + "base": 0, + "mod": 0 + }, + "aura": { + "base": 0, + "mod": 0 + } + }, + "combatValues": { + "hitPoints": { + "base": 0, + "mod": 0, + "value": 0 + }, + "defense": { + "base": 0, + "mod": 0 + }, + "initiative": { + "base": 0, + "mod": 0 + }, + "movement": { + "base": 0, + "mod": 0 + }, + "meleeAttack": { + "base": 0, + "mod": 0 + }, + "rangedAttack": { + "base": 0, + "mod": 0 + }, + "spellcasting": { + "base": 0, + "mod": 0 + }, + "targetedSpellcasting": { + "base": 0, + "mod": 0 + } + } + } + }, + "creature": { + "templates": ["base"], + "baseInfo": { + "loot": "", + "foeFactor": 1, + "creatureType": "humanoid", + "sizeCategory": "normal", + "experiencePoints": 0, + "description": "" + } + }, "character": { - "templates": [], - "attributes": { - "body": { - "base": 0, - "mod": 0 - }, - "mobility": { - "base": 0, - "mod": 0 - }, - "mind": { - "base": 0, - "mod": 0 - } - }, - "traits": { - "strength": { - "base": 0, - "mod": 0 - }, - "constitution": { - "base": 0, - "mod": 0 - }, - "agility": { - "base": 0, - "mod": 0 - }, - "dexterity": { - "base": 0, - "mod": 0 - }, - "intellect": { - "base": 0, - "mod": 0 - }, - "aura": { - "base": 0, - "mod": 0 - } - }, - "combatValues": { - "hitPoints": { - "base": 0, - "mod": 0, - "value": 0 - }, - "defense": { - "base": 0, - "mod": 0 - }, - "initiative": { - "base": 0, - "mod": 0 - }, - "movement": { - "base": 0, - "mod": 0 - }, - "meleeAttack": { - "base": 0, - "mod": 0 - }, - "rangedAttack": { - "base": 0, - "mod": 0 - }, - "spellcasting": { - "base": 0, - "mod": 0 - }, - "targetedSpellcasting": { - "base": 0, - "mod": 0 - } - }, + "templates": ["base"], "baseInfo": { "race": "", "class": "", @@ -98,6 +112,7 @@ } }, "profile": { + "biography": "", "gender": "", "birthday": "", "birthplace": "", @@ -120,12 +135,14 @@ "weapon", "armor", "shield", + "spell", "trinket", "equipment", "talent", "racialAbility", "language", - "alphabet" + "alphabet", + "specialCreatureAbility" ], "templates": { "base": { @@ -180,6 +197,33 @@ }, "alphabet": { "templates": ["base"] + }, + "spell": { + "templates": ["base", "equipable"], + "spellType": "spellcasting", + "bonus": "", + "spellCategory": "unset", + "maxDistance": { + "value": "", + "unit": "meter" + }, + "effectRadius": { + "value": "", + "unit": "meter" + }, + "duration": { + "value": "", + "unit": "custom" + }, + "cooldownDuration": { + "value": "", + "unit": "custom" + }, + "scrollPrice": 0 + }, + "specialCreatureAbility": { + "templates": ["base"], + "experiencePoints": 0 } } } diff --git a/src/templates/actor/actor-sheet.hbs b/src/templates/actor/character-sheet.hbs similarity index 74% rename from src/templates/actor/actor-sheet.hbs rename to src/templates/actor/character-sheet.hbs index 8e3e5f54..5c0b4358 100644 --- a/src/templates/actor/actor-sheet.hbs +++ b/src/templates/actor/character-sheet.hbs @@ -8,17 +8,19 @@
- +
- +
+ for="data.progression.progressPoints.used">{{config.characterProgression.progressPoints}}
+ for="data.progression.talentPoints.used">{{config.characterProgression.talentPoints}}
- +
+ for="data.baseInfo.heroClass">{{config.characterBaseInfo.heroClass}}
@@ -58,26 +61,31 @@ {{!-- Sheet Tab Navigation --}} {{!-- Sheet Body --}}
- {{!-- Biography Tab --}} -
- {{editor content=data.biography target="data.biography" button=true owner=owner editable=editable}} -
+ {{!-- Items Tab --}} + {{> systems/ds4/templates/actor/partials/items-overview.hbs}} + + {{!-- Spells Tab --}} + {{> systems/ds4/templates/actor/partials/spells-overview.hbs}} + + {{!-- Talents Tab --}} + {{> systems/ds4/templates/actor/partials/talents-abilities-overview.hbs}} {{! Profile Tab --}} {{> systems/ds4/templates/actor/partials/profile.hbs}} - {{!-- Talents Tab --}} - {{> systems/ds4/templates/actor/partials/talents-overview.hbs}} - - {{!-- Items Tab --}} - {{> systems/ds4/templates/actor/partials/items-overview.hbs}} + {{!-- Biography Tab --}} +
+ {{editor content=data.profile.biography target="data.profile.biography" button=true owner=owner + editable=editable}} +
- \ No newline at end of file + diff --git a/src/templates/actor/creature-sheet.hbs b/src/templates/actor/creature-sheet.hbs new file mode 100644 index 00000000..2ebf5977 --- /dev/null +++ b/src/templates/actor/creature-sheet.hbs @@ -0,0 +1,78 @@ +
+ {{!-- Sheet Header --}} +
+ +
+

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ {{> systems/ds4/templates/actor/partials/attributes-traits.hbs}} + {{> systems/ds4/templates/actor/partials/combat-values.hbs}} +
+
+ + {{!-- Sheet Tab Navigation --}} + + + {{!-- Sheet Body --}} +
+ {{!-- Items Tab --}} + {{> systems/ds4/templates/actor/partials/items-overview.hbs}} + + {{!-- Special Creature Abilities Tab --}} + {{> systems/ds4/templates/actor/partials/special-creature-abilites-overview.hbs}} + + {{!-- Spells Tab --}} + {{> systems/ds4/templates/actor/partials/spells-overview.hbs}} + + {{!-- Description Tab --}} +
+ {{editor content=data.baseInfo.description target="data.baseInfo.description" button=true owner=owner + editable=editable}} +
+
+
\ No newline at end of file diff --git a/src/templates/actor/partials/character-progression.hbs b/src/templates/actor/partials/character-progression.hbs index f22376f0..8990656c 100644 --- a/src/templates/actor/partials/character-progression.hbs +++ b/src/templates/actor/partials/character-progression.hbs @@ -1,13 +1,13 @@
-

+

+ for="data.progression.experiencePoints">{{config.characterProgression.experiencePoints}}

diff --git a/src/templates/actor/partials/items-overview.hbs b/src/templates/actor/partials/items-overview.hbs index 7fbd5108..a941e6bb 100644 --- a/src/templates/actor/partials/items-overview.hbs +++ b/src/templates/actor/partials/items-overview.hbs @@ -1,5 +1,4 @@ -{{!-- TODO: For items list: only show header, if list is not empty --}} - +{{!-- TODO: Refactor to avoid code duplication with special-creature-abilites-overview and talents-overview --}} {{!-- ======================================================================== --}} {{!-- INLINE PARTIAL DEFINITIONS --}} @@ -15,9 +14,9 @@ --}} {{#*inline "ifHasItemOfType"}} {{#if (and (ne itemsArray undefined) (gt itemsArray.length 0))}} - {{> @partial-block}} +{{> @partial-block}} {{else}} - {{> systems/ds4/templates/actor/partials/overview-add-button.hbs dataType=dataType }} +{{> systems/ds4/templates/actor/partials/overview-add-button.hbs dataType=dataType }} {{/if}} {{/inline}} @@ -34,24 +33,24 @@ !-- @param partial-block: hand over custom children of the flexbox in the partial block. --}} {{#*inline "itemListHeader" }} -
  • - {{!-- equipped --}} - {{#if (ne dataType 'equipment')}} -
    E
    - {{/if}} - {{!-- image --}} -
    - {{!-- amount --}} -
    #
    - {{!-- name --}} -
    {{localize 'DS4.ItemName'}}
    - {{!-- item type specifics --}} - {{> @partial-block }} - {{!-- description --}} -
    {{localize 'DS4.HeadingDescription'}}
    - {{!-- add button --}} - {{> systems/ds4/templates/actor/partials/overview-add-button.hbs dataType=dataType }} -
  • +
  • + {{!-- equipped --}} + {{#if (ne dataType 'equipment')}} +
    {{localize 'DS4.ItemEquippedAbbr'}}
    + {{/if}} + {{!-- image --}} +
    + {{!-- amount --}} +
    #
    + {{!-- name --}} +
    {{localize 'DS4.ItemName'}}
    + {{!-- item type specifics --}} + {{> @partial-block }} + {{!-- description --}} +
    {{localize 'DS4.Description'}}
    + {{!-- add button --}} + {{> systems/ds4/templates/actor/partials/overview-add-button.hbs dataType=dataType }} +
  • {{/inline}} {{!-- @@ -59,36 +58,36 @@ !-- It is a flexbox with a child for each item value of interest. !-- An equipped checkbox is rendered if item.data.data.equipped is defined. !-- The partial assumes a variable item to be given in the context. -!-- If the partial is called with a partial block, the partial block +!-- If the partial is called with a partial block, the partial block !-- content is inserted before the description. !-- @param item: hand over the item to the partial as hash parameter !-- @param partial-block: hand over custom children of the flexbox in the partial block. --}} {{#*inline "itemListEntry"}} -
  • - {{!-- equipped --}} - {{#if (ne item.data.data.equipped undefined)}} - - {{/if}} - {{!-- image --}} -
    - -
    - {{!-- amount --}} - - {{!-- name --}} - - {{!-- item type specifics --}} - {{> @partial-block}} - {{!-- description --}} -
    {{{item.data.data.description}}}
    - {{!-- control buttons --}} - {{> systems/ds4/templates/actor/partials/overview-control-buttons.hbs }} -
  • +
  • + {{!-- equipped --}} + {{#if (ne item.data.data.equipped undefined)}} + + {{/if}} + {{!-- image --}} +
    + +
    + {{!-- amount --}} + + {{!-- name --}} + + {{!-- item type specifics --}} + {{> @partial-block}} + {{!-- description --}} +
    {{{item.data.data.description}}}
    + {{!-- control buttons --}} + {{> systems/ds4/templates/actor/partials/overview-control-buttons.hbs }} +
  • {{/inline}} @@ -98,15 +97,18 @@
    {{!-- Money--}} -

    {{localize 'DS4.Currency'}}

    +

    {{localize 'DS4.CharacterCurrency'}}

      -
    1. - - - - - - +
    2. + + + + + +
    @@ -116,23 +118,23 @@ {{#> ifHasItemOfType itemsArray=itemsByType.weapon dataType='weapon' }}
      {{#> itemListHeader dataType='weapon'}} -
      {{localize 'DS4.AttackTypeAbbr'}}
      -
      - {{localize 'DS4.WeaponBonusAbbr'}} -
      -
      - {{localize 'DS4.OpponentDefenseAbbr'}} -
      +
      {{localize 'DS4.AttackTypeAbbr'}}
      +
      + {{localize 'DS4.WeaponBonusAbbr'}} +
      +
      + {{localize 'DS4.OpponentDefenseAbbr'}} +
      {{/itemListHeader}} {{#each itemsByType.weapon as |item id|}} - {{#> itemListEntry item=item}} -
      - -
      -
      {{ item.data.data.weaponBonus}}
      -
      {{ item.data.data.opponentDefense}}
      - {{/itemListEntry}} + {{#> itemListEntry item=item}} +
      + +
      +
      {{ item.data.data.weaponBonus}}
      +
      {{ item.data.data.opponentDefense}}
      + {{/itemListEntry}} {{/each}}
    {{!-- {{else}} @@ -144,22 +146,22 @@ {{#> ifHasItemOfType itemsArray=itemsByType.armor dataType='armor' }}
      {{#> itemListHeader dataType='armor'}} -
      {{localize 'DS4.ArmorMaterialTypeAbbr'}}
      -
      {{localize 'DS4.ArmorTypeAbbr'}}
      -
      - {{localize 'DS4.ArmorValueAbbr'}} -
      +
      {{localize 'DS4.ArmorMaterialTypeAbbr'}}
      +
      {{localize 'DS4.ArmorTypeAbbr'}}
      +
      + {{localize 'DS4.ArmorValueAbbr'}} +
      {{/itemListHeader}} {{#each itemsByType.armor as |item id|}} - {{#> itemListEntry item=item }} -
      - {{lookup ../../config.armorMaterialTypesAbbr item.data.data.armorMaterialType}} -
      -
      - {{lookup ../../config.armorTypesAbbr item.data.data.armorType}} -
      -
      {{ item.data.data.armorValue}}
      - {{/itemListEntry}} + {{#> itemListEntry item=item }} +
      + {{lookup ../../config.armorMaterialTypesAbbr item.data.data.armorMaterialType}} +
      +
      + {{lookup ../../config.armorTypesAbbr item.data.data.armorType}} +
      +
      {{ item.data.data.armorValue}}
      + {{/itemListEntry}} {{/each}}
    {{/ifHasItemOfType}} @@ -170,14 +172,14 @@ {{#> ifHasItemOfType itemsArray=itemsByType.shield dataType='shield' }}
      {{#> itemListHeader dataType='shield' }} -
      - {{localize 'DS4.ArmorValueAbbr'}} -
      +
      + {{localize 'DS4.ArmorValueAbbr'}} +
      {{/itemListHeader}} {{#each itemsByType.shield as |item id|}} - {{#> itemListEntry item=item }} -
      {{item.data.data.armorValue}}
      {{!-- SPECIFIC --}} - {{/itemListEntry}} + {{#> itemListEntry item=item }} +
      {{item.data.data.armorValue}}
      {{!-- SPECIFIC --}} + {{/itemListEntry}} {{/each}}
    {{/ifHasItemOfType}} @@ -187,13 +189,13 @@ {{#> ifHasItemOfType itemsArray=itemsByType.trinket dataType='trinket' }}
      {{#> itemListHeader dataType='trinket'}} -
      {{localize 'DS4.StorageLocation'}}
      +
      {{localize 'DS4.StorageLocation'}}
      {{/itemListHeader}} {{#each itemsByType.trinket as |item id|}} - {{#> itemListEntry item=item }} - - {{/itemListEntry}} + {{#> itemListEntry item=item }} + + {{/itemListEntry}} {{/each}}
    {{/ifHasItemOfType}} @@ -203,13 +205,13 @@ {{#> ifHasItemOfType itemsArray=itemsByType.equipment dataType='equipment' }}
      {{#> itemListHeader dataType='equipment'}} -
      {{localize 'DS4.StorageLocation'}}
      +
      {{localize 'DS4.StorageLocation'}}
      {{/itemListHeader}} {{#each itemsByType.equipment as |item id|}} - {{#> itemListEntry item=item }} - - {{/itemListEntry}} + {{#> itemListEntry item=item }} + + {{/itemListEntry}} {{/each}}
    {{/ifHasItemOfType}} diff --git a/src/templates/actor/partials/profile.hbs b/src/templates/actor/partials/profile.hbs index b0034128..be95eeb5 100644 --- a/src/templates/actor/partials/profile.hbs +++ b/src/templates/actor/partials/profile.hbs @@ -1,13 +1,15 @@
    {{#each data.profile as |profile-data-value profile-data-key|}} + {{#if (ne profile-data-key 'biography')}}
    + data-dtype="{{lookup ../config/characterProfileDTypes profile-data-key}}" />
    + {{/if}} {{/each}}
    -
    \ No newline at end of file +
    diff --git a/src/templates/actor/partials/special-creature-abilites-overview.hbs b/src/templates/actor/partials/special-creature-abilites-overview.hbs new file mode 100644 index 00000000..28637149 --- /dev/null +++ b/src/templates/actor/partials/special-creature-abilites-overview.hbs @@ -0,0 +1,61 @@ +{{!-- TODO: Refactor to avoid code duplication with items-overview and talents-overview --}} + +{{!-- ======================================================================== --}} +{{!-- INLINE PARTIAL DEFINITIONS --}} +{{!-- ======================================================================== --}} + +{{!-- +!-- Render a list row for a base item from a given item. +!-- Base item means it just has an image, a description, and a name (and effects). +!-- It is a flexbox with a child for each item value of interest. +!-- The partial assumes a variable item to be given in the context. +!-- +!-- @param item: hand over the item to the partial as hash parameter +--}} +{{#*inline "baseItemListEntry"}} +
  • + {{!-- image --}} +
    + +
    + {{!-- name --}} + + {{!-- description --}} +
    {{{item.data.data.description}}}
    + {{!-- control buttons --}} + {{> systems/ds4/templates/actor/partials/overview-control-buttons.hbs }} +
  • +{{/inline}} + +{{!-- +!-- Render a list header for a base item list entries from a given item. +!-- The partial assumes a variable dataType to be given in the context. +!-- +!-- @param dataType: the string item type for the list +--}} +{{#*inline "baseItemListHeader"}} +
  • + {{!-- image --}} +
    + {{!-- name --}} +
    {{localize 'DS4.ItemName'}}
    + {{!-- description --}} +
    {{localize 'DS4.Description'}}
    + {{!-- add button --}} + {{> systems/ds4/templates/actor/partials/overview-add-button.hbs dataType=dataType }} +
  • +{{/inline}} + + +{{!-- ======================================================================== --}} + + +
    +
      + {{> baseItemListHeader dataType='specialCreatureAbility' }} + {{#each itemsByType.specialCreatureAbility as |item id|}} + {{> baseItemListEntry item=item}} + {{/each}} +
    +
    \ No newline at end of file diff --git a/src/templates/actor/partials/spells-overview.hbs b/src/templates/actor/partials/spells-overview.hbs new file mode 100644 index 00000000..8bcd33e3 --- /dev/null +++ b/src/templates/actor/partials/spells-overview.hbs @@ -0,0 +1,93 @@ +{{!-- ======================================================================== --}} +{{!-- INLINE PARTIAL DEFINITIONS --}} +{{!-- ======================================================================== --}} + +{{!-- +!-- Base template to display a value with unit. +!-- @param unitDatum: the object to display; must have a value and a unit attribute +!-- @param localizationString +!-- @param unitNames: mapping of allowed unitDatum.unit values to localized unit name +!-- @param unitAbbrs: mapping of allowed unitDatum.unit values to unit abbreviation +--}} +{{#*inline "unit"}} +
    + {{#if unitDatum.value }} + {{unitDatum.value}}{{lookup unitAbbrs unitDatum.unit}} + {{else}}-{{/if}} +
    +{{/inline}} +{{!-- +!-- Two templates based on the "unit" template for displaying values with unit. +!-- Both accept a `config` object holding the unitNames and unitAbbr instead of +!-- directly handing over the latter two. +--}} +{{#*inline "temporalUnit"}} +{{> unit unitNames=config.temporalUnits unitAbbrs=config.temporalUnitsAbbr unitDatum=unitDatum localizationString=localizationString}} +{{/inline}} + +{{#*inline "distanceUnit"}} +{{> unit unitNames=config.distanceUnits unitAbbrs=config.distanceUnitsAbbr unitDatum=unitDatum localizationString=localizationString}} +{{/inline}} + + +{{!-- ======================================================================== --}} + + +
    +
      +
    1. + {{!-- equipped --}} +
      {{localize 'DS4.ItemEquippedAbbr'}}
      + {{!-- image --}} +
      + {{!-- name --}} +
      {{localize 'DS4.ItemName'}}
      + {{!-- spell type --}} +
      {{localize 'DS4.SpellTypeAbbr'}}
      + {{!-- spell bonus --}} +
      {{localize 'DS4.SpellBonusAbbr'}}
      + {{!-- max. distance --}} +
      + {{!-- duration --}} +
      + {{!-- cooldown duration --}} +
      + {{!-- description --}} + {{!--
      {{localize 'DS4.Description'}}
      --}} + {{!-- add button --}} + {{> systems/ds4/templates/actor/partials/overview-add-button.hbs dataType='spell' }} +
    2. + {{#each itemsByType.spell as |item id|}} +
    3. + + {{!-- image --}} +
      + +
      + {{!-- name --}} + + {{!-- spell type --}} +
      + +
      + {{!-- spell bonus --}} + + {{!-- max. distance --}} + {{> distanceUnit localizationString='DS4.SpellMaxDistance' unitDatum=item.data.data.maxDistance config=../config}} + {{!-- duration --}} + {{> temporalUnit localizationString='DS4.SpellDuration' unitDatum=item.data.data.duration config=../config}} + {{!-- cooldown duration --}} + {{> temporalUnit localizationString='DS4.SpellCooldownDuration' unitDatum=item.data.data.cooldownDuration config=../config}} + {{!-- description --}} + {{!--
      {{{item.data.data.description}}}
      --}} + {{!-- control buttons --}} + {{> systems/ds4/templates/actor/partials/overview-control-buttons.hbs }} +
    4. + {{/each}} +
    +
    \ No newline at end of file diff --git a/src/templates/actor/partials/talents-overview.hbs b/src/templates/actor/partials/talents-abilities-overview.hbs similarity index 95% rename from src/templates/actor/partials/talents-overview.hbs rename to src/templates/actor/partials/talents-abilities-overview.hbs index f4a06005..e40b2aa7 100644 --- a/src/templates/actor/partials/talents-overview.hbs +++ b/src/templates/actor/partials/talents-abilities-overview.hbs @@ -1,8 +1,8 @@ +{{!-- TODO: Refactor to avoid code duplication with creature-special-abilities-overview and talents-overview --}} + {{!-- ======================================================================== --}} {{!-- INLINE PARTIAL DEFINITIONS --}} {{!-- ======================================================================== --}} -{{!-- TODO: remove duplicate add and delete button definition --}} - {{!-- @@ -110,7 +110,7 @@ {{!-- name --}}
    {{localize 'DS4.ItemName'}}
    {{!-- description --}} -
    {{localize 'DS4.HeadingDescription'}}
    +
    {{localize 'DS4.Description'}}
    {{!-- add button --}} {{> systems/ds4/templates/actor/partials/overview-add-button.hbs dataType=dataType }} @@ -120,7 +120,7 @@ {{!-- ======================================================================== --}} -
    +

    {{localize 'DS4.ItemTypeTalentPlural'}}

    {{#> ifHasItemOfType itemsArray=itemsByType.talent dataType='talent' }}
      @@ -132,7 +132,7 @@ {{!-- rank info --}}
      {{localize 'DS4.TalentRank'}}
      {{!-- description --}} -
      {{localize 'DS4.HeadingDescription'}}
      +
      {{localize 'DS4.Description'}}
      {{!-- add button --}} {{> systems/ds4/templates/actor/partials/overview-add-button.hbs dataType='talent' }} diff --git a/src/templates/item/alphabet-sheet.hbs b/src/templates/item/alphabet-sheet.hbs index cfd63f9e..5aabb9aa 100644 --- a/src/templates/item/alphabet-sheet.hbs +++ b/src/templates/item/alphabet-sheet.hbs @@ -3,6 +3,6 @@ {{/systems/ds4/templates/item/partials/sheet-header.hbs}} {{!-- Common Item body --}} - {{> systems/ds4/templates/item/partials/body.hbs}} + {{#> systems/ds4/templates/item/partials/body.hbs}}{{/systems/ds4/templates/item/partials/body.hbs}} \ No newline at end of file diff --git a/src/templates/item/armor-sheet.hbs b/src/templates/item/armor-sheet.hbs index 1a2a14bf..5fd59feb 100644 --- a/src/templates/item/armor-sheet.hbs +++ b/src/templates/item/armor-sheet.hbs @@ -12,7 +12,7 @@
    - + -
    -
    - - -
    + +
    +
    + + +
    +
    \ No newline at end of file diff --git a/src/templates/item/racialAbility-sheet.hbs b/src/templates/item/racialAbility-sheet.hbs index 40771481..e69b5fc5 100644 --- a/src/templates/item/racialAbility-sheet.hbs +++ b/src/templates/item/racialAbility-sheet.hbs @@ -3,6 +3,6 @@ {{/systems/ds4/templates/item/partials/sheet-header.hbs}} {{!-- Common Item body --}} - {{> systems/ds4/templates/item/partials/body.hbs}} + {{#> systems/ds4/templates/item/partials/body.hbs}}{{/systems/ds4/templates/item/partials/body.hbs}} diff --git a/src/templates/item/shield-sheet.hbs b/src/templates/item/shield-sheet.hbs index 1c1092c3..4ef9c9f9 100644 --- a/src/templates/item/shield-sheet.hbs +++ b/src/templates/item/shield-sheet.hbs @@ -10,5 +10,5 @@ {{/systems/ds4/templates/item/partials/sheet-header.hbs}} {{!-- Common Item body --}} - {{> systems/ds4/templates/item/partials/body.hbs}} + {{#> systems/ds4/templates/item/partials/body.hbs}}{{/systems/ds4/templates/item/partials/body.hbs}} \ No newline at end of file diff --git a/src/templates/item/specialCreatureAbility-sheet.hbs b/src/templates/item/specialCreatureAbility-sheet.hbs new file mode 100644 index 00000000..086ba9a5 --- /dev/null +++ b/src/templates/item/specialCreatureAbility-sheet.hbs @@ -0,0 +1,15 @@ +
    + {{#> systems/ds4/templates/item/partials/sheet-header.hbs}} +
    +
    + + +
    +
    + {{/systems/ds4/templates/item/partials/sheet-header.hbs}} + + {{!-- Common Item body --}} + {{#> systems/ds4/templates/item/partials/body.hbs}}{{/systems/ds4/templates/item/partials/body.hbs}} + +
    \ No newline at end of file diff --git a/src/templates/item/spell-sheet.hbs b/src/templates/item/spell-sheet.hbs new file mode 100644 index 00000000..5f2c7a28 --- /dev/null +++ b/src/templates/item/spell-sheet.hbs @@ -0,0 +1,72 @@ +{{!-- ======================================================================== --}} +{{!-- INLINE PARTIAL DEFINITIONS --}} +{{!-- ======================================================================== --}} + + +{{#*inline "unitDatum" }} +
    + +
    + + +
    +
    +{{/inline}} + + +{{!-- ======================================================================== --}} + + +
    + {{#> systems/ds4/templates/item/partials/sheet-header.hbs}} +
    +
    + + +
    +
    + + +
    +
    + {{/systems/ds4/templates/item/partials/sheet-header.hbs}} + + {{!-- Common Item body --}} + {{#> systems/ds4/templates/item/partials/body.hbs}} +
    + + +
    + {{> unitDatum data=data property='maxDistance' localizeString='DS4.SpellMaxDistance' unitType='distance' }} + {{> unitDatum data=data property='effectRadius' localizeString='DS4.SpellEffectRadius' unitType='distance' }} + {{> unitDatum data=data property='duration' localizeString='DS4.SpellDuration' unitType='temporal' }} + {{> unitDatum data=data property='cooldownDuration' localizeString='DS4.SpellCooldownDuration' unitType='temporal' }} +
    + + +
    + {{/systems/ds4/templates/item/partials/body.hbs}} + +
    diff --git a/src/templates/item/talent-sheet.hbs b/src/templates/item/talent-sheet.hbs index 1611beea..22257d81 100644 --- a/src/templates/item/talent-sheet.hbs +++ b/src/templates/item/talent-sheet.hbs @@ -27,6 +27,6 @@ {{/systems/ds4/templates/item/partials/sheet-header.hbs}} {{!-- Common Item body --}} - {{> systems/ds4/templates/item/partials/body.hbs}} + {{#> systems/ds4/templates/item/partials/body.hbs}}{{/systems/ds4/templates/item/partials/body.hbs}} diff --git a/src/templates/item/trinket-sheet.hbs b/src/templates/item/trinket-sheet.hbs index 3fa5d4a9..bbd66400 100644 --- a/src/templates/item/trinket-sheet.hbs +++ b/src/templates/item/trinket-sheet.hbs @@ -3,5 +3,5 @@ {{/systems/ds4/templates/item/partials/sheet-header.hbs}} {{!-- Common Item body --}} - {{> systems/ds4/templates/item/partials/body.hbs}} + {{#> systems/ds4/templates/item/partials/body.hbs}}{{/systems/ds4/templates/item/partials/body.hbs}} \ No newline at end of file diff --git a/src/templates/item/weapon-sheet.hbs b/src/templates/item/weapon-sheet.hbs index 69145376..b92bf97f 100644 --- a/src/templates/item/weapon-sheet.hbs +++ b/src/templates/item/weapon-sheet.hbs @@ -25,5 +25,5 @@ {{/systems/ds4/templates/item/partials/sheet-header.hbs}} {{!-- Common Item body --}} - {{> systems/ds4/templates/item/partials/body.hbs}} + {{#> systems/ds4/templates/item/partials/body.hbs}}{{/systems/ds4/templates/item/partials/body.hbs}} \ No newline at end of file diff --git a/src/templates/roll/roll-options.hbs b/src/templates/roll/roll-options.hbs new file mode 100644 index 00000000..8c3e7dc3 --- /dev/null +++ b/src/templates/roll/roll-options.hbs @@ -0,0 +1,16 @@ +
    + + + + + + + + + + +