Merge remote-tracking branch 'origin/master' into 008-chatRollInterface
This commit is contained in:
commit
c89278992f
43 changed files with 1137 additions and 640 deletions
|
@ -45,11 +45,12 @@ build:
|
||||||
stage: build
|
stage: build
|
||||||
script:
|
script:
|
||||||
- npm run build
|
- npm run build
|
||||||
|
- mv dist ds4
|
||||||
cache:
|
cache:
|
||||||
<<: *global_cache
|
<<: *global_cache
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- dist
|
- ds4
|
||||||
expire_in: 1 week
|
expire_in: 1 week
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
|
@ -58,7 +59,7 @@ deploy:
|
||||||
dependencies:
|
dependencies:
|
||||||
- build
|
- build
|
||||||
script:
|
script:
|
||||||
- rsync --delete -az ./dist/ rsync://${DEPLOYMENT_USER}@${DEPLOYMENT_SERVER}:${DEPLOYMENT_PATH}
|
- rsync --delete -az ./ds4/ rsync://${DEPLOYMENT_USER}@${DEPLOYMENT_SERVER}:${DEPLOYMENT_PATH}
|
||||||
environment:
|
environment:
|
||||||
name: production
|
name: production
|
||||||
url: https://vtt.f3l.de/
|
url: https://vtt.f3l.de/
|
||||||
|
|
29
.gitlab/issue_templates/Bug Report.md
Normal file
29
.gitlab/issue_templates/Bug Report.md
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
# Description
|
||||||
|
|
||||||
|
Please describe the issue.
|
||||||
|
|
||||||
|
# Steps to Reproduce
|
||||||
|
|
||||||
|
1. ...
|
||||||
|
2. ...
|
||||||
|
3. ...
|
||||||
|
|
||||||
|
# Expected Behavior
|
||||||
|
|
||||||
|
Please describe the expected behavior.
|
||||||
|
|
||||||
|
# Actual Behavior
|
||||||
|
|
||||||
|
Please describe the actual behavior.
|
||||||
|
|
||||||
|
# Additional Details
|
||||||
|
|
||||||
|
These are optional, please add them if it makes sense.
|
||||||
|
|
||||||
|
- ![Screenshot]()
|
||||||
|
- [Logfile]()
|
||||||
|
- ...
|
||||||
|
|
||||||
|
# Possible Solutions
|
||||||
|
|
||||||
|
If you have any suggestions on how to solve the issue, please add them here.
|
|
@ -1,9 +1,13 @@
|
||||||
# Description
|
# Story
|
||||||
|
|
||||||
As a …, I want … so that …
|
As a …, I want … so that …
|
||||||
|
|
||||||
|
# Description
|
||||||
|
|
||||||
|
Please add a more detailed description of the feature here.
|
||||||
|
|
||||||
# Acceptance criteria
|
# Acceptance criteria
|
||||||
|
|
||||||
* Criterion 1
|
1. Criterion 1
|
||||||
* Criterion 2
|
2. Criterion 2
|
||||||
* …
|
3. …
|
||||||
|
|
73
README.md
73
README.md
|
@ -3,50 +3,89 @@
|
||||||
An implementation of the Dungeonslayers 4 game system for [Foundry Virtual
|
An implementation of the Dungeonslayers 4 game system for [Foundry Virtual
|
||||||
Tabletop](http://foundryvtt.com).
|
Tabletop](http://foundryvtt.com).
|
||||||
|
|
||||||
## Prerequisites
|
This system provides character sheet support for Actors and Items and mechanical
|
||||||
|
support for dice and rules necessary to
|
||||||
|
play games of Dungeponslayers 4.
|
||||||
|
|
||||||
In order to build this system, a recent version of `npm` is required.
|
## Installation
|
||||||
|
|
||||||
## Building
|
To install and use the Dungeonslayers 4 system for Foundry Virtual Tabletop,
|
||||||
|
simply paste the following URL into the **Install System** dialog on the Setup
|
||||||
|
menu of the application.
|
||||||
|
|
||||||
To build the system, first install all required dependencies:
|
https://git.f3l.de/dungeonslayers/ds4/-/raw/master/src/system.json?inline=false
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
### Prerequisits
|
||||||
|
|
||||||
|
In order to build this system, recent versions of `node` and `npm` are required.
|
||||||
|
We recommend using the latest lts version of `node`, which is `v14.15.4` at the
|
||||||
|
time of writing. If you use `nvm` to manage your `node` versions, you can simply
|
||||||
|
run
|
||||||
|
```
|
||||||
|
nvm install
|
||||||
|
```
|
||||||
|
|
||||||
|
in the project's root directory.
|
||||||
|
|
||||||
|
You also need to install the the project's dependencies. To do so, run
|
||||||
|
|
||||||
```
|
```
|
||||||
npm install
|
npm install
|
||||||
```
|
```
|
||||||
|
|
||||||
Then build the project by running
|
### Building
|
||||||
|
|
||||||
|
You can build the project by running
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run build
|
npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
If you'd like the built system to be automatically linked to your local Foundry
|
Alternatively, you can run
|
||||||
VTT installation's data folder, add a file called `foundryconfig.json` to the
|
|
||||||
project root with the following contents:
|
```
|
||||||
|
npm run build:watch
|
||||||
|
```
|
||||||
|
|
||||||
|
to watch for changes and automatically build as necessary.
|
||||||
|
|
||||||
|
### Linking the built system to Foundry VTT
|
||||||
|
|
||||||
|
In order to provide a fluent development experience, it is recommended to link
|
||||||
|
the built system to your local Foundry VTT installation's data folder. In order
|
||||||
|
to do so, first add a file called `foundryconfig.json` to the project root with
|
||||||
|
the following content:
|
||||||
|
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
"dataPath": "/<absolute path to your home>/.local/share/FoundryVTT",
|
"dataPath": "<path to your home directory>/.local/share/FoundryVTT"
|
||||||
"repository": "",
|
|
||||||
"rawURL": ""
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
On platforms other than Linux you need to adjust the path accordingly.
|
||||||
|
|
||||||
Then run
|
Then run
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run link
|
npm run link
|
||||||
```
|
```
|
||||||
|
|
||||||
If you want the system to be continuously build upon every saved change, just
|
### Running the tests
|
||||||
run
|
|
||||||
|
You can run the tests with the following command:
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run build:watch
|
npm test
|
||||||
```
|
```
|
||||||
|
|
||||||
# Licensing
|
## Contributing
|
||||||
|
|
||||||
|
Code and content contributions are accepted. Please feel free to submit issues
|
||||||
|
to the issue tracker or submit merge requests for code changes. To create an issue send a mail to [git+dungeonslayers-ds4-155-issue-@git.f3l.de](mailto:git+dungeonslayers-ds4-155-issue-@git.f3l.de).
|
||||||
|
|
||||||
|
## Licensing
|
||||||
|
|
||||||
Dungeonslayers (© Christian Kennig) is licensed under [CC BY-NC-SA 3.0](https://creativecommons.org/licenses/by-nc-sa/3.0/de/deed.en).
|
Dungeonslayers (© Christian Kennig) is licensed under [CC BY-NC-SA 3.0](https://creativecommons.org/licenses/by-nc-sa/3.0/de/deed.en).
|
||||||
|
|
||||||
|
@ -56,5 +95,5 @@ CC BY-NC-SA 3.0. Hence the modified icons are also published under this
|
||||||
license. A copy of this license can be found under
|
license. A copy of this license can be found under
|
||||||
[src/assets/official/LICENSE](src/assets/official/LICENSE).
|
[src/assets/official/LICENSE](src/assets/official/LICENSE).
|
||||||
|
|
||||||
The rest of this project is licensed under the MIT License, a copy of which can
|
The software component of this project is licensed under the MIT License, a copy
|
||||||
be found under [LICENSE](LICENSE).
|
of which can be found under [LICENSE](LICENSE).
|
||||||
|
|
858
gulpfile.js
858
gulpfile.js
|
@ -1,429 +1,429 @@
|
||||||
const gulp = require("gulp");
|
const gulp = require("gulp");
|
||||||
const fs = require("fs-extra");
|
const fs = require("fs-extra");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const chalk = require("chalk");
|
const chalk = require("chalk");
|
||||||
const archiver = require("archiver");
|
const archiver = require("archiver");
|
||||||
const stringify = require("json-stringify-pretty-compact");
|
const stringify = require("json-stringify-pretty-compact");
|
||||||
const typescript = require("typescript");
|
const typescript = require("typescript");
|
||||||
|
|
||||||
const ts = require("gulp-typescript");
|
const ts = require("gulp-typescript");
|
||||||
const less = require("gulp-less");
|
const less = require("gulp-less");
|
||||||
const sass = require("gulp-sass");
|
const sass = require("gulp-sass");
|
||||||
const git = require("gulp-git");
|
const git = require("gulp-git");
|
||||||
|
|
||||||
const argv = require("yargs").argv;
|
const argv = require("yargs").argv;
|
||||||
|
|
||||||
sass.compiler = require("sass");
|
sass.compiler = require("sass");
|
||||||
|
|
||||||
function getConfig() {
|
function getConfig() {
|
||||||
const configPath = path.resolve(process.cwd(), "foundryconfig.json");
|
const configPath = path.resolve(process.cwd(), "foundryconfig.json");
|
||||||
let config;
|
let config;
|
||||||
|
|
||||||
if (fs.existsSync(configPath)) {
|
if (fs.existsSync(configPath)) {
|
||||||
config = fs.readJSONSync(configPath);
|
config = fs.readJSONSync(configPath);
|
||||||
return config;
|
return config;
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getManifest() {
|
function getManifest() {
|
||||||
const json = {};
|
const json = {};
|
||||||
|
|
||||||
if (fs.existsSync("src")) {
|
if (fs.existsSync("src")) {
|
||||||
json.root = "src";
|
json.root = "src";
|
||||||
} else {
|
} else {
|
||||||
json.root = "dist";
|
json.root = "dist";
|
||||||
}
|
}
|
||||||
|
|
||||||
const modulePath = path.join(json.root, "module.json");
|
const modulePath = path.join(json.root, "module.json");
|
||||||
const systemPath = path.join(json.root, "system.json");
|
const systemPath = path.join(json.root, "system.json");
|
||||||
|
|
||||||
if (fs.existsSync(modulePath)) {
|
if (fs.existsSync(modulePath)) {
|
||||||
json.file = fs.readJSONSync(modulePath);
|
json.file = fs.readJSONSync(modulePath);
|
||||||
json.name = "module.json";
|
json.name = "module.json";
|
||||||
} else if (fs.existsSync(systemPath)) {
|
} else if (fs.existsSync(systemPath)) {
|
||||||
json.file = fs.readJSONSync(systemPath);
|
json.file = fs.readJSONSync(systemPath);
|
||||||
json.name = "system.json";
|
json.name = "system.json";
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TypeScript transformers
|
* TypeScript transformers
|
||||||
* @returns {typescript.TransformerFactory<typescript.SourceFile>}
|
* @returns {typescript.TransformerFactory<typescript.SourceFile>}
|
||||||
*/
|
*/
|
||||||
function createTransformer() {
|
function createTransformer() {
|
||||||
/**
|
/**
|
||||||
* @param {typescript.Node} node
|
* @param {typescript.Node} node
|
||||||
*/
|
*/
|
||||||
function shouldMutateModuleSpecifier(node) {
|
function shouldMutateModuleSpecifier(node) {
|
||||||
if (!typescript.isImportDeclaration(node) && !typescript.isExportDeclaration(node)) return false;
|
if (!typescript.isImportDeclaration(node) && !typescript.isExportDeclaration(node)) return false;
|
||||||
if (node.moduleSpecifier === undefined) return false;
|
if (node.moduleSpecifier === undefined) return false;
|
||||||
if (!typescript.isStringLiteral(node.moduleSpecifier)) return false;
|
if (!typescript.isStringLiteral(node.moduleSpecifier)) return false;
|
||||||
if (!node.moduleSpecifier.text.startsWith("./") && !node.moduleSpecifier.text.startsWith("../")) return false;
|
if (!node.moduleSpecifier.text.startsWith("./") && !node.moduleSpecifier.text.startsWith("../")) return false;
|
||||||
if (path.extname(node.moduleSpecifier.text) !== "") return false;
|
if (path.extname(node.moduleSpecifier.text) !== "") return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms import/export declarations to append `.js` extension
|
* Transforms import/export declarations to append `.js` extension
|
||||||
* @param {typescript.TransformationContext} context
|
* @param {typescript.TransformationContext} context
|
||||||
*/
|
*/
|
||||||
function importTransformer(context) {
|
function importTransformer(context) {
|
||||||
return (node) => {
|
return (node) => {
|
||||||
/**
|
/**
|
||||||
* @param {typescript.Node} node
|
* @param {typescript.Node} node
|
||||||
*/
|
*/
|
||||||
function visitor(node) {
|
function visitor(node) {
|
||||||
if (shouldMutateModuleSpecifier(node)) {
|
if (shouldMutateModuleSpecifier(node)) {
|
||||||
if (typescript.isImportDeclaration(node)) {
|
if (typescript.isImportDeclaration(node)) {
|
||||||
const newModuleSpecifier = typescript.createLiteral(`${node.moduleSpecifier.text}.js`);
|
const newModuleSpecifier = typescript.createLiteral(`${node.moduleSpecifier.text}.js`);
|
||||||
return typescript.updateImportDeclaration(
|
return typescript.updateImportDeclaration(
|
||||||
node,
|
node,
|
||||||
node.decorators,
|
node.decorators,
|
||||||
node.modifiers,
|
node.modifiers,
|
||||||
node.importClause,
|
node.importClause,
|
||||||
newModuleSpecifier
|
newModuleSpecifier,
|
||||||
);
|
);
|
||||||
} else if (typescript.isExportDeclaration(node)) {
|
} else if (typescript.isExportDeclaration(node)) {
|
||||||
const newModuleSpecifier = typescript.createLiteral(`${node.moduleSpecifier.text}.js`);
|
const newModuleSpecifier = typescript.createLiteral(`${node.moduleSpecifier.text}.js`);
|
||||||
return typescript.updateExportDeclaration(
|
return typescript.updateExportDeclaration(
|
||||||
node,
|
node,
|
||||||
node.decorators,
|
node.decorators,
|
||||||
node.modifiers,
|
node.modifiers,
|
||||||
node.exportClause,
|
node.exportClause,
|
||||||
newModuleSpecifier
|
newModuleSpecifier,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return typescript.visitEachChild(node, visitor, context);
|
return typescript.visitEachChild(node, visitor, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
return typescript.visitNode(node, visitor);
|
return typescript.visitNode(node, visitor);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return importTransformer;
|
return importTransformer;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tsConfig = ts.createProject("tsconfig.json", {
|
const tsConfig = ts.createProject("tsconfig.json", {
|
||||||
getCustomTransformers: (_program) => ({
|
getCustomTransformers: (_program) => ({
|
||||||
after: [createTransformer()],
|
after: [createTransformer()],
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
/********************/
|
/********************/
|
||||||
/* BUILD */
|
/* BUILD */
|
||||||
/********************/
|
/********************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build TypeScript
|
* Build TypeScript
|
||||||
*/
|
*/
|
||||||
function buildTS() {
|
function buildTS() {
|
||||||
return gulp.src("src/**/*.ts").pipe(tsConfig()).pipe(gulp.dest("dist"));
|
return gulp.src("src/**/*.ts").pipe(tsConfig()).pipe(gulp.dest("dist"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build Less
|
* Build Less
|
||||||
*/
|
*/
|
||||||
function buildLess() {
|
function buildLess() {
|
||||||
return gulp.src("src/*.less").pipe(less()).pipe(gulp.dest("dist"));
|
return gulp.src("src/*.less").pipe(less()).pipe(gulp.dest("dist"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build SASS
|
* Build SASS
|
||||||
*/
|
*/
|
||||||
function buildSASS() {
|
function buildSASS() {
|
||||||
return gulp.src("src/*.scss").pipe(sass().on("error", sass.logError)).pipe(gulp.dest("dist"));
|
return gulp.src("src/*.scss").pipe(sass().on("error", sass.logError)).pipe(gulp.dest("dist"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy static files
|
* Copy static files
|
||||||
*/
|
*/
|
||||||
async function copyFiles() {
|
async function copyFiles() {
|
||||||
const statics = ["lang", "fonts", "assets", "templates", "module.json", "system.json", "template.json"];
|
const statics = ["lang", "fonts", "assets", "templates", "module.json", "system.json", "template.json"];
|
||||||
try {
|
try {
|
||||||
for (const file of statics) {
|
for (const file of statics) {
|
||||||
if (fs.existsSync(path.join("src", file))) {
|
if (fs.existsSync(path.join("src", file))) {
|
||||||
await fs.copy(path.join("src", file), path.join("dist", file));
|
await fs.copy(path.join("src", file), path.join("dist", file));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
Promise.reject(err);
|
Promise.reject(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Watch for changes for each build step
|
* Watch for changes for each build step
|
||||||
*/
|
*/
|
||||||
function buildWatch() {
|
function buildWatch() {
|
||||||
gulp.watch("src/**/*.ts", { ignoreInitial: false }, buildTS);
|
gulp.watch("src/**/*.ts", { ignoreInitial: false }, buildTS);
|
||||||
gulp.watch("src/**/*.less", { ignoreInitial: false }, buildLess);
|
gulp.watch("src/**/*.less", { ignoreInitial: false }, buildLess);
|
||||||
gulp.watch("src/**/*.scss", { ignoreInitial: false }, buildSASS);
|
gulp.watch("src/**/*.scss", { ignoreInitial: false }, buildSASS);
|
||||||
gulp.watch(["src/fonts", "src/lang", "src/templates", "src/*.json"], { ignoreInitial: false }, copyFiles);
|
gulp.watch(["src/fonts", "src/lang", "src/templates", "src/*.json"], { ignoreInitial: false }, copyFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************/
|
/********************/
|
||||||
/* CLEAN */
|
/* CLEAN */
|
||||||
/********************/
|
/********************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove built files from `dist` folder
|
* Remove built files from `dist` folder
|
||||||
* while ignoring source files
|
* while ignoring source files
|
||||||
*/
|
*/
|
||||||
async function clean() {
|
async function clean() {
|
||||||
const name = path.basename(path.resolve("."));
|
const name = path.basename(path.resolve("."));
|
||||||
const files = [];
|
const files = [];
|
||||||
|
|
||||||
// If the project uses TypeScript
|
// If the project uses TypeScript
|
||||||
if (fs.existsSync(path.join("src", `${name}.ts`))) {
|
if (fs.existsSync(path.join("src", `${name}.ts`))) {
|
||||||
files.push(
|
files.push(
|
||||||
"lang",
|
"lang",
|
||||||
"templates",
|
"templates",
|
||||||
"assets",
|
"assets",
|
||||||
"module",
|
"module",
|
||||||
`${name}.js`,
|
`${name}.js`,
|
||||||
"module.json",
|
"module.json",
|
||||||
"system.json",
|
"system.json",
|
||||||
"template.json"
|
"template.json",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the project uses Less or SASS
|
// If the project uses Less or SASS
|
||||||
if (fs.existsSync(path.join("src", `${name}.less`)) || fs.existsSync(path.join("src", `${name}.scss`))) {
|
if (fs.existsSync(path.join("src", `${name}.less`)) || fs.existsSync(path.join("src", `${name}.scss`))) {
|
||||||
files.push("fonts", `${name}.css`);
|
files.push("fonts", `${name}.css`);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(" ", chalk.yellow("Files to clean:"));
|
console.log(" ", chalk.yellow("Files to clean:"));
|
||||||
console.log(" ", chalk.blueBright(files.join("\n ")));
|
console.log(" ", chalk.blueBright(files.join("\n ")));
|
||||||
|
|
||||||
// Attempt to remove the files
|
// Attempt to remove the files
|
||||||
try {
|
try {
|
||||||
for (const filePath of files) {
|
for (const filePath of files) {
|
||||||
await fs.remove(path.join("dist", filePath));
|
await fs.remove(path.join("dist", filePath));
|
||||||
}
|
}
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
Promise.reject(err);
|
Promise.reject(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************/
|
/********************/
|
||||||
/* LINK */
|
/* LINK */
|
||||||
/********************/
|
/********************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Link build to User Data folder
|
* Link build to User Data folder
|
||||||
*/
|
*/
|
||||||
async function linkUserData() {
|
async function linkUserData() {
|
||||||
const name = path.basename(path.resolve("."));
|
const name = path.basename(path.resolve("."));
|
||||||
const config = fs.readJSONSync("foundryconfig.json");
|
const config = fs.readJSONSync("foundryconfig.json");
|
||||||
|
|
||||||
let destDir;
|
let destDir;
|
||||||
try {
|
try {
|
||||||
if (
|
if (
|
||||||
fs.existsSync(path.resolve(".", "dist", "module.json")) ||
|
fs.existsSync(path.resolve(".", "dist", "module.json")) ||
|
||||||
fs.existsSync(path.resolve(".", "src", "module.json"))
|
fs.existsSync(path.resolve(".", "src", "module.json"))
|
||||||
) {
|
) {
|
||||||
destDir = "modules";
|
destDir = "modules";
|
||||||
} else if (
|
} else if (
|
||||||
fs.existsSync(path.resolve(".", "dist", "system.json")) ||
|
fs.existsSync(path.resolve(".", "dist", "system.json")) ||
|
||||||
fs.existsSync(path.resolve(".", "src", "system.json"))
|
fs.existsSync(path.resolve(".", "src", "system.json"))
|
||||||
) {
|
) {
|
||||||
destDir = "systems";
|
destDir = "systems";
|
||||||
} else {
|
} else {
|
||||||
throw Error(`Could not find ${chalk.blueBright("module.json")} or ${chalk.blueBright("system.json")}`);
|
throw Error(`Could not find ${chalk.blueBright("module.json")} or ${chalk.blueBright("system.json")}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
let linkDir;
|
let linkDir;
|
||||||
if (config.dataPath) {
|
if (config.dataPath) {
|
||||||
if (!fs.existsSync(path.join(config.dataPath, "Data")))
|
if (!fs.existsSync(path.join(config.dataPath, "Data")))
|
||||||
throw Error("User Data path invalid, no Data directory found");
|
throw Error("User Data path invalid, no Data directory found");
|
||||||
|
|
||||||
linkDir = path.join(config.dataPath, "Data", destDir, name);
|
linkDir = path.join(config.dataPath, "Data", destDir, name);
|
||||||
} else {
|
} else {
|
||||||
throw Error("No User Data path defined in foundryconfig.json");
|
throw Error("No User Data path defined in foundryconfig.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argv.clean || argv.c) {
|
if (argv.clean || argv.c) {
|
||||||
console.log(chalk.yellow(`Removing build in ${chalk.blueBright(linkDir)}`));
|
console.log(chalk.yellow(`Removing build in ${chalk.blueBright(linkDir)}`));
|
||||||
|
|
||||||
await fs.remove(linkDir);
|
await fs.remove(linkDir);
|
||||||
} else if (!fs.existsSync(linkDir)) {
|
} else if (!fs.existsSync(linkDir)) {
|
||||||
console.log(chalk.green(`Copying build to ${chalk.blueBright(linkDir)}`));
|
console.log(chalk.green(`Copying build to ${chalk.blueBright(linkDir)}`));
|
||||||
await fs.symlink(path.resolve("./dist"), linkDir);
|
await fs.symlink(path.resolve("./dist"), linkDir);
|
||||||
}
|
}
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
Promise.reject(err);
|
Promise.reject(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************/
|
/*********************/
|
||||||
/* PACKAGE */
|
/* PACKAGE */
|
||||||
/*********************/
|
/*********************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Package build
|
* Package build
|
||||||
*/
|
*/
|
||||||
async function packageBuild() {
|
async function packageBuild() {
|
||||||
const manifest = getManifest();
|
const manifest = getManifest();
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
// Remove the package dir without doing anything else
|
// Remove the package dir without doing anything else
|
||||||
if (argv.clean || argv.c) {
|
if (argv.clean || argv.c) {
|
||||||
console.log(chalk.yellow("Removing all packaged files"));
|
console.log(chalk.yellow("Removing all packaged files"));
|
||||||
fs.removeSync("package");
|
fs.removeSync("package");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure there is a directory to hold all the packaged versions
|
// Ensure there is a directory to hold all the packaged versions
|
||||||
fs.ensureDirSync("package");
|
fs.ensureDirSync("package");
|
||||||
|
|
||||||
// Initialize the zip file
|
// Initialize the zip file
|
||||||
const zipName = `${manifest.file.name}-v${manifest.file.version}.zip`;
|
const zipName = `${manifest.file.name}-v${manifest.file.version}.zip`;
|
||||||
const zipFile = fs.createWriteStream(path.join("package", zipName));
|
const zipFile = fs.createWriteStream(path.join("package", zipName));
|
||||||
const zip = archiver("zip", { zlib: { level: 9 } });
|
const zip = archiver("zip", { zlib: { level: 9 } });
|
||||||
|
|
||||||
zipFile.on("close", () => {
|
zipFile.on("close", () => {
|
||||||
console.log(chalk.green(zip.pointer() + " total bytes"));
|
console.log(chalk.green(zip.pointer() + " total bytes"));
|
||||||
console.log(chalk.green(`Zip file ${zipName} has been written`));
|
console.log(chalk.green(`Zip file ${zipName} has been written`));
|
||||||
return resolve();
|
return resolve();
|
||||||
});
|
});
|
||||||
|
|
||||||
zip.on("error", (err) => {
|
zip.on("error", (err) => {
|
||||||
throw err;
|
throw err;
|
||||||
});
|
});
|
||||||
|
|
||||||
zip.pipe(zipFile);
|
zip.pipe(zipFile);
|
||||||
|
|
||||||
// Add the directory with the final code
|
// Add the directory with the final code
|
||||||
zip.directory("dist/", manifest.file.name);
|
zip.directory("dist/", manifest.file.name);
|
||||||
|
|
||||||
zip.finalize();
|
zip.finalize();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return reject(err);
|
return reject(err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************/
|
/*********************/
|
||||||
/* PACKAGE */
|
/* PACKAGE */
|
||||||
/*********************/
|
/*********************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update version and URLs in the manifest JSON
|
* Update version and URLs in the manifest JSON
|
||||||
*/
|
*/
|
||||||
function updateManifest(cb) {
|
function updateManifest(cb) {
|
||||||
const packageJson = fs.readJSONSync("package.json");
|
const packageJson = fs.readJSONSync("package.json");
|
||||||
const config = getConfig(),
|
const config = getConfig(),
|
||||||
manifest = getManifest(),
|
manifest = getManifest(),
|
||||||
rawURL = config.rawURL,
|
rawURL = config.rawURL,
|
||||||
repoURL = config.repository,
|
repoURL = config.repository,
|
||||||
manifestRoot = manifest.root;
|
manifestRoot = manifest.root;
|
||||||
|
|
||||||
if (!config) cb(Error(chalk.red("foundryconfig.json not found")));
|
if (!config) cb(Error(chalk.red("foundryconfig.json not found")));
|
||||||
if (!manifest) cb(Error(chalk.red("Manifest JSON not found")));
|
if (!manifest) cb(Error(chalk.red("Manifest JSON not found")));
|
||||||
if (!rawURL || !repoURL) cb(Error(chalk.red("Repository URLs not configured in foundryconfig.json")));
|
if (!rawURL || !repoURL) cb(Error(chalk.red("Repository URLs not configured in foundryconfig.json")));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const version = argv.update || argv.u;
|
const version = argv.update || argv.u;
|
||||||
|
|
||||||
/* Update version */
|
/* Update version */
|
||||||
|
|
||||||
const versionMatch = /^(\d{1,}).(\d{1,}).(\d{1,})$/;
|
const versionMatch = /^(\d{1,}).(\d{1,}).(\d{1,})$/;
|
||||||
const currentVersion = manifest.file.version;
|
const currentVersion = manifest.file.version;
|
||||||
let targetVersion = "";
|
let targetVersion = "";
|
||||||
|
|
||||||
if (!version) {
|
if (!version) {
|
||||||
cb(Error("Missing version number"));
|
cb(Error("Missing version number"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (versionMatch.test(version)) {
|
if (versionMatch.test(version)) {
|
||||||
targetVersion = version;
|
targetVersion = version;
|
||||||
} else {
|
} else {
|
||||||
targetVersion = currentVersion.replace(versionMatch, (substring, major, minor, patch) => {
|
targetVersion = currentVersion.replace(versionMatch, (substring, major, minor, patch) => {
|
||||||
console.log(substring, Number(major) + 1, Number(minor) + 1, Number(patch) + 1);
|
console.log(substring, Number(major) + 1, Number(minor) + 1, Number(patch) + 1);
|
||||||
if (version === "major") {
|
if (version === "major") {
|
||||||
return `${Number(major) + 1}.0.0`;
|
return `${Number(major) + 1}.0.0`;
|
||||||
} else if (version === "minor") {
|
} else if (version === "minor") {
|
||||||
return `${major}.${Number(minor) + 1}.0`;
|
return `${major}.${Number(minor) + 1}.0`;
|
||||||
} else if (version === "patch") {
|
} else if (version === "patch") {
|
||||||
return `${major}.${minor}.${Number(patch) + 1}`;
|
return `${major}.${minor}.${Number(patch) + 1}`;
|
||||||
} else {
|
} else {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetVersion === "") {
|
if (targetVersion === "") {
|
||||||
return cb(Error(chalk.red("Error: Incorrect version arguments.")));
|
return cb(Error(chalk.red("Error: Incorrect version arguments.")));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetVersion === currentVersion) {
|
if (targetVersion === currentVersion) {
|
||||||
return cb(Error(chalk.red("Error: Target version is identical to current version.")));
|
return cb(Error(chalk.red("Error: Target version is identical to current version.")));
|
||||||
}
|
}
|
||||||
console.log(`Updating version number to '${targetVersion}'`);
|
console.log(`Updating version number to '${targetVersion}'`);
|
||||||
|
|
||||||
packageJson.version = targetVersion;
|
packageJson.version = targetVersion;
|
||||||
manifest.file.version = targetVersion;
|
manifest.file.version = targetVersion;
|
||||||
|
|
||||||
/* Update URLs */
|
/* Update URLs */
|
||||||
|
|
||||||
const result = `${rawURL}/v${manifest.file.version}/package/${manifest.file.name}-v${manifest.file.version}.zip`;
|
const result = `${rawURL}/v${manifest.file.version}/package/${manifest.file.name}-v${manifest.file.version}.zip`;
|
||||||
|
|
||||||
manifest.file.url = repoURL;
|
manifest.file.url = repoURL;
|
||||||
manifest.file.manifest = `${rawURL}/master/${manifestRoot}/${manifest.name}`;
|
manifest.file.manifest = `${rawURL}/master/${manifestRoot}/${manifest.name}`;
|
||||||
manifest.file.download = result;
|
manifest.file.download = result;
|
||||||
|
|
||||||
const prettyProjectJson = stringify(manifest.file, {
|
const prettyProjectJson = stringify(manifest.file, {
|
||||||
maxLength: 35,
|
maxLength: 35,
|
||||||
indent: "\t",
|
indent: "\t",
|
||||||
});
|
});
|
||||||
|
|
||||||
fs.writeJSONSync("package.json", packageJson, { spaces: "\t" });
|
fs.writeJSONSync("package.json", packageJson, { spaces: "\t" });
|
||||||
fs.writeFileSync(path.join(manifest.root, manifest.name), prettyProjectJson, "utf8");
|
fs.writeFileSync(path.join(manifest.root, manifest.name), prettyProjectJson, "utf8");
|
||||||
|
|
||||||
return cb();
|
return cb();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
cb(err);
|
cb(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function gitAdd() {
|
function gitAdd() {
|
||||||
return gulp.src("package").pipe(git.add({ args: "--no-all" }));
|
return gulp.src("package").pipe(git.add({ args: "--no-all" }));
|
||||||
}
|
}
|
||||||
|
|
||||||
function gitCommit() {
|
function gitCommit() {
|
||||||
return gulp.src("./*").pipe(
|
return gulp.src("./*").pipe(
|
||||||
git.commit(`v${getManifest().file.version}`, {
|
git.commit(`v${getManifest().file.version}`, {
|
||||||
args: "-a",
|
args: "-a",
|
||||||
disableAppendPaths: true,
|
disableAppendPaths: true,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function gitTag() {
|
function gitTag() {
|
||||||
const manifest = getManifest();
|
const manifest = getManifest();
|
||||||
return git.tag(`v${manifest.file.version}`, `Updated to ${manifest.file.version}`, (err) => {
|
return git.tag(`v${manifest.file.version}`, `Updated to ${manifest.file.version}`, (err) => {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const execGit = gulp.series(gitAdd, gitCommit, gitTag);
|
const execGit = gulp.series(gitAdd, gitCommit, gitTag);
|
||||||
|
|
||||||
const execBuild = gulp.parallel(buildTS, buildLess, buildSASS, copyFiles);
|
const execBuild = gulp.parallel(buildTS, buildLess, buildSASS, copyFiles);
|
||||||
|
|
||||||
exports.build = gulp.series(clean, execBuild);
|
exports.build = gulp.series(clean, execBuild);
|
||||||
exports.watch = buildWatch;
|
exports.watch = buildWatch;
|
||||||
exports.clean = clean;
|
exports.clean = clean;
|
||||||
exports.link = linkUserData;
|
exports.link = linkUserData;
|
||||||
exports.package = packageBuild;
|
exports.package = packageBuild;
|
||||||
exports.update = updateManifest;
|
exports.update = updateManifest;
|
||||||
exports.publish = gulp.series(clean, updateManifest, execBuild, packageBuild, execGit);
|
exports.publish = gulp.series(clean, updateManifest, execBuild, packageBuild, execGit);
|
||||||
|
|
|
@ -16,8 +16,10 @@
|
||||||
@import "scss/components/basic_property";
|
@import "scss/components/basic_property";
|
||||||
@import "scss/components/tabs";
|
@import "scss/components/tabs";
|
||||||
@import "scss/components/items";
|
@import "scss/components/items";
|
||||||
|
@import "scss/components/talents";
|
||||||
@import "scss/components/description";
|
@import "scss/components/description";
|
||||||
@import "scss/components/character_values";
|
@import "scss/components/character_values";
|
||||||
@import "scss/components/attributes_traits";
|
@import "scss/components/attributes_traits";
|
||||||
@import "scss/components/combat_values";
|
@import "scss/components/combat_values";
|
||||||
|
@import "scss/components/character_progression";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
{
|
{
|
||||||
"DS4.UserInteractionAddItem": "Add item",
|
"DS4.UserInteractionAddItem": "Add item",
|
||||||
"DS4.NotOwned": "No owner",
|
"DS4.NotOwned": "No owner",
|
||||||
"DS4.Description": "Description",
|
"DS4.HeadingDescription": "Description",
|
||||||
"DS4.DescriptionAbbr": "Desc",
|
"DS4.HeadingDetails": "Details",
|
||||||
"DS4.Details": "Details",
|
"DS4.HeadingEffects": "Effects",
|
||||||
"DS4.Effects": "Effects",
|
"DS4.HeadingInventory": "Inventory",
|
||||||
|
"DS4.HeadingProfile": "Profile",
|
||||||
|
"DS4.HeadingTalents": "Talents & Abilities",
|
||||||
"DS4.AttackType": "Attack Type",
|
"DS4.AttackType": "Attack Type",
|
||||||
"DS4.AttackTypeAbbr": "AT",
|
"DS4.AttackTypeAbbr": "AT",
|
||||||
"DS4.WeaponBonus": "Weapon Bonus",
|
"DS4.WeaponBonus": "Weapon Bonus",
|
||||||
|
@ -29,10 +31,19 @@
|
||||||
"DS4.ItemAvailabilityNowhere": "Nowhere",
|
"DS4.ItemAvailabilityNowhere": "Nowhere",
|
||||||
"DS4.ItemName": "Name",
|
"DS4.ItemName": "Name",
|
||||||
"DS4.ItemTypeWeapon": "Weapon",
|
"DS4.ItemTypeWeapon": "Weapon",
|
||||||
|
"DS4.ItemTypeWeaponPlural": "Weapons",
|
||||||
"DS4.ItemTypeArmor": "Armor",
|
"DS4.ItemTypeArmor": "Armor",
|
||||||
|
"DS4.ItemTypeArmorPlural": "Armor",
|
||||||
"DS4.ItemTypeShield": "Shield",
|
"DS4.ItemTypeShield": "Shield",
|
||||||
|
"DS4.ItemTypeShieldPlural": "Shields",
|
||||||
"DS4.ItemTypeTrinket": "Trinket",
|
"DS4.ItemTypeTrinket": "Trinket",
|
||||||
|
"DS4.ItemTypeTrinketPlural": "Trinkets",
|
||||||
"DS4.ItemTypeEquipment": "Equipment",
|
"DS4.ItemTypeEquipment": "Equipment",
|
||||||
|
"DS4.ItemTypeEquipmentPlural": "Equipment",
|
||||||
|
"DS4.ItemTypeTalent": "Talent",
|
||||||
|
"DS4.ItemTypeTalentPlural": "Talents",
|
||||||
|
"DS4.ItemTypeRacialAbility": "Racial Ability",
|
||||||
|
"DS4.ItemTypeRacialAbilityPlural": "Racial Abilities",
|
||||||
"DS4.ArmorType": "Armor Type",
|
"DS4.ArmorType": "Armor Type",
|
||||||
"DS4.ArmorTypeAbbr": "AT",
|
"DS4.ArmorTypeAbbr": "AT",
|
||||||
"DS4.ArmorMaterialType": "Material Type",
|
"DS4.ArmorMaterialType": "Material Type",
|
||||||
|
@ -78,8 +89,26 @@
|
||||||
"DS4.BaseInfoClass": "Class",
|
"DS4.BaseInfoClass": "Class",
|
||||||
"DS4.BaseInfoHeroClass": "Hero Class",
|
"DS4.BaseInfoHeroClass": "Hero Class",
|
||||||
"DS4.BaseInfoRacialAbilities": "Racial Abilites",
|
"DS4.BaseInfoRacialAbilities": "Racial Abilites",
|
||||||
|
"DS4.BaseInfoCulture": "Culture",
|
||||||
"DS4.ProgressionLevel": "Level",
|
"DS4.ProgressionLevel": "Level",
|
||||||
"DS4.ProgressionExperiencePoints": "Experience Points",
|
"DS4.ProgressionExperiencePoints": "Experience Points",
|
||||||
"DS4.ProgressionTalentPoints": "Talent Points",
|
"DS4.ProgressionTalentPoints": "Talent Points",
|
||||||
"DS4.ProgressionProgressPoints": "Progress Points"
|
"DS4.ProgressionProgressPoints": "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.WarningManageActiveEffectOnOwnedItem": "Managing Active Effects within an Owned Item is not currently supported and will be added in a subsequent update."
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ export interface DS4ActorDataType {
|
||||||
combatValues: DS4ActorDataCombatValues;
|
combatValues: DS4ActorDataCombatValues;
|
||||||
baseInfo: DS4ActorDataBaseInfo;
|
baseInfo: DS4ActorDataBaseInfo;
|
||||||
progression: DS4ActorDataProgression;
|
progression: DS4ActorDataProgression;
|
||||||
|
language: DS4ActorDataLanguage;
|
||||||
|
profile: DS4ActorDataProfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DS4ActorDataAttributes {
|
interface DS4ActorDataAttributes {
|
||||||
|
@ -23,8 +25,9 @@ interface UsableResource<T> {
|
||||||
used: T;
|
used: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CurrentData<T> extends ModifiableData<T> {
|
interface ResourceData<T> extends ModifiableData<T> {
|
||||||
current: T;
|
value: T;
|
||||||
|
max?: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blueprint in case we need more detailed differentiation
|
// Blueprint in case we need more detailed differentiation
|
||||||
|
@ -40,7 +43,7 @@ interface DS4ActorDataTraits {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DS4ActorDataCombatValues {
|
interface DS4ActorDataCombatValues {
|
||||||
hitPoints: CurrentData<number>;
|
hitPoints: ResourceData<number>;
|
||||||
defense: ModifiableData<number>;
|
defense: ModifiableData<number>;
|
||||||
initiative: ModifiableData<number>;
|
initiative: ModifiableData<number>;
|
||||||
movement: ModifiableData<number>;
|
movement: ModifiableData<number>;
|
||||||
|
@ -55,6 +58,7 @@ interface DS4ActorDataBaseInfo {
|
||||||
class: string;
|
class: string;
|
||||||
heroClass: string;
|
heroClass: string;
|
||||||
racialAbilities: string;
|
racialAbilities: string;
|
||||||
|
culture: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DS4ActorDataProgression {
|
interface DS4ActorDataProgression {
|
||||||
|
@ -63,3 +67,20 @@ interface DS4ActorDataProgression {
|
||||||
talentPoints: UsableResource<number>;
|
talentPoints: UsableResource<number>;
|
||||||
progressPoints: UsableResource<number>;
|
progressPoints: UsableResource<number>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface DS4ActorDataLanguage {
|
||||||
|
languages: string;
|
||||||
|
alphabets: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DS4ActorDataProfile {
|
||||||
|
gender: string;
|
||||||
|
birthday: string;
|
||||||
|
birthplace: string;
|
||||||
|
age: number;
|
||||||
|
height: number;
|
||||||
|
hairColor: string;
|
||||||
|
weight: number;
|
||||||
|
eyeColor: string;
|
||||||
|
specialCharacteristics: string;
|
||||||
|
}
|
||||||
|
|
|
@ -18,5 +18,7 @@ export class DS4Actor extends Actor<DS4ActorDataType, DS4ItemDataType, DS4Item>
|
||||||
Object.values(combatValues).forEach(
|
Object.values(combatValues).forEach(
|
||||||
(combatValue: ModifiableData<number>) => (combatValue.total = combatValue.base + combatValue.mod),
|
(combatValue: ModifiableData<number>) => (combatValue.total = combatValue.base + combatValue.mod),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
combatValues.hitPoints.max = combatValues.hitPoints.total;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,8 @@ export const DS4 = {
|
||||||
shield: "DS4.ItemTypeShield",
|
shield: "DS4.ItemTypeShield",
|
||||||
trinket: "DS4.ItemTypeTrinket",
|
trinket: "DS4.ItemTypeTrinket",
|
||||||
equipment: "DS4.ItemTypeEquipment",
|
equipment: "DS4.ItemTypeEquipment",
|
||||||
|
talent: "DS4.ItemTypeTalent",
|
||||||
|
racialAbility: "DS4.ItemTypeRacialAbility",
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -135,10 +137,11 @@ export const DS4 = {
|
||||||
class: "DS4.BaseInfoClass",
|
class: "DS4.BaseInfoClass",
|
||||||
heroClass: "DS4.BaseInfoHeroClass",
|
heroClass: "DS4.BaseInfoHeroClass",
|
||||||
racialAbilities: "DS4.BaseInfoRacialAbilities",
|
racialAbilities: "DS4.BaseInfoRacialAbilities",
|
||||||
|
culture: "DS4.BaseInfoCulture",
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Definme the progression info of a character
|
* Define the progression info of a character
|
||||||
*/
|
*/
|
||||||
progression: {
|
progression: {
|
||||||
level: "DS4.ProgressionLevel",
|
level: "DS4.ProgressionLevel",
|
||||||
|
@ -146,4 +149,42 @@ export const DS4 = {
|
||||||
talentPoints: "DS4.ProgressionTalentPoints",
|
talentPoints: "DS4.ProgressionTalentPoints",
|
||||||
progressPoints: "DS4.ProgressionProgressPoints",
|
progressPoints: "DS4.ProgressionProgressPoints",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the language info of a character
|
||||||
|
*/
|
||||||
|
language: {
|
||||||
|
languages: "DS4.LanguageLanguages",
|
||||||
|
alphabets: "DS4.LanguageAlphabets",
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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",
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the profile info types for hanndlebars of a character
|
||||||
|
*/
|
||||||
|
profileDTypes: {
|
||||||
|
gender: "String",
|
||||||
|
birthday: "String",
|
||||||
|
birthplace: "String",
|
||||||
|
age: "Number",
|
||||||
|
height: "Number",
|
||||||
|
hairColor: "String",
|
||||||
|
weight: "Number",
|
||||||
|
eyeColor: "String",
|
||||||
|
specialCharacteristics: "String",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -46,8 +46,13 @@ async function registerHandlebarsPartials() {
|
||||||
"systems/ds4/templates/item/partials/effects.hbs",
|
"systems/ds4/templates/item/partials/effects.hbs",
|
||||||
"systems/ds4/templates/item/partials/body.hbs",
|
"systems/ds4/templates/item/partials/body.hbs",
|
||||||
"systems/ds4/templates/actor/partials/items-overview.hbs",
|
"systems/ds4/templates/actor/partials/items-overview.hbs",
|
||||||
|
"systems/ds4/templates/actor/partials/talents-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/attributes-traits.hbs",
|
||||||
"systems/ds4/templates/actor/partials/combat-values.hbs",
|
"systems/ds4/templates/actor/partials/combat-values.hbs",
|
||||||
|
"systems/ds4/templates/actor/partials/profile.hbs",
|
||||||
|
"systems/ds4/templates/actor/partials/character-progression.hbs",
|
||||||
];
|
];
|
||||||
return loadTemplates(templatePaths);
|
return loadTemplates(templatePaths);
|
||||||
}
|
}
|
||||||
|
@ -75,6 +80,8 @@ Hooks.once("setup", function () {
|
||||||
"combatValues",
|
"combatValues",
|
||||||
"baseInfo",
|
"baseInfo",
|
||||||
"progression",
|
"progression",
|
||||||
|
"language",
|
||||||
|
"profile",
|
||||||
];
|
];
|
||||||
|
|
||||||
// Exclude some from sorting where the default order matters
|
// Exclude some from sorting where the default order matters
|
||||||
|
|
|
@ -1,5 +1,13 @@
|
||||||
// TODO: Actually add a type for data
|
import { ModifiableData } from "../actor/actor-data";
|
||||||
export type DS4ItemDataType = DS4Weapon | DS4Armor | DS4Shield | DS4Trinket | DS4Equipment;
|
|
||||||
|
export type DS4ItemDataType =
|
||||||
|
| DS4Weapon
|
||||||
|
| DS4Armor
|
||||||
|
| DS4Shield
|
||||||
|
| DS4Trinket
|
||||||
|
| DS4Equipment
|
||||||
|
| DS4Talent
|
||||||
|
| DS4RacialAbility;
|
||||||
|
|
||||||
// types
|
// types
|
||||||
|
|
||||||
|
@ -14,9 +22,18 @@ interface DS4Armor extends DS4ItemBase, DS4ItemPhysical, DS4ItemEquipable, DS4It
|
||||||
armorType: "body" | "helmet" | "vambrace" | "greaves" | "vambraceGreaves";
|
armorType: "body" | "helmet" | "vambrace" | "greaves" | "vambraceGreaves";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DS4Talent extends DS4ItemBase {
|
||||||
|
rank: DS4TalentRank;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DS4TalentRank extends ModifiableData<number> {
|
||||||
|
max: number;
|
||||||
|
}
|
||||||
|
|
||||||
interface DS4Shield extends DS4ItemBase, DS4ItemPhysical, DS4ItemEquipable, DS4ItemProtective {}
|
interface DS4Shield extends DS4ItemBase, DS4ItemPhysical, DS4ItemEquipable, DS4ItemProtective {}
|
||||||
interface DS4Trinket extends DS4ItemBase, DS4ItemPhysical, DS4ItemEquipable {}
|
interface DS4Trinket extends DS4ItemBase, DS4ItemPhysical, DS4ItemEquipable {}
|
||||||
interface DS4Equipment extends DS4ItemBase, DS4ItemPhysical {}
|
interface DS4Equipment extends DS4ItemBase, DS4ItemPhysical {}
|
||||||
|
type DS4RacialAbility = DS4ItemBase;
|
||||||
|
|
||||||
// templates
|
// templates
|
||||||
|
|
||||||
|
@ -30,6 +47,10 @@ interface DS4ItemPhysical {
|
||||||
storageLocation: string;
|
storageLocation: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isDS4ItemDataTypePhysical(input: DS4ItemDataType): boolean {
|
||||||
|
return "quantity" in input && "price" in input && "availability" in input && "storageLocation" in input;
|
||||||
|
}
|
||||||
|
|
||||||
interface DS4ItemEquipable {
|
interface DS4ItemEquipable {
|
||||||
equipped: boolean;
|
equipped: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { DS4Item } from "./item";
|
import { DS4Item } from "./item";
|
||||||
import { DS4ItemDataType } from "./item-data";
|
import { DS4ItemDataType, isDS4ItemDataTypePhysical } from "./item-data";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extend the basic ItemSheet with some very simple modifications
|
* Extend the basic ItemSheet with some very simple modifications
|
||||||
|
@ -26,7 +26,13 @@ export class DS4ItemSheet extends ItemSheet<DS4ItemDataType, DS4Item> {
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
getData(): ItemSheetData<DS4ItemDataType, DS4Item> {
|
getData(): ItemSheetData<DS4ItemDataType, DS4Item> {
|
||||||
const data = { ...super.getData(), config: CONFIG.DS4, isOwned: this.item.isOwned, actor: this.item.actor };
|
const data = {
|
||||||
|
...super.getData(),
|
||||||
|
config: CONFIG.DS4,
|
||||||
|
isOwned: this.item.isOwned,
|
||||||
|
actor: this.item.actor,
|
||||||
|
isPhysical: isDS4ItemDataTypePhysical(this.item.data.data),
|
||||||
|
};
|
||||||
console.log(data);
|
console.log(data);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -54,29 +60,38 @@ export class DS4ItemSheet extends ItemSheet<DS4ItemDataType, DS4Item> {
|
||||||
|
|
||||||
if (!this.options.editable) return;
|
if (!this.options.editable) return;
|
||||||
|
|
||||||
html.find(".effect-create").on("click", this._onEffectCreate.bind(this));
|
html.find(".effect-control").on("click", this._onManageActiveEffect.bind(this));
|
||||||
|
|
||||||
html.find(".effect-edit").on("click", (ev) => {
|
|
||||||
const li = $(ev.currentTarget).parents(".effect");
|
|
||||||
console.log(li.data("effectId"));
|
|
||||||
const effect = this.item.effects.get(li.data("effectId"));
|
|
||||||
effect.sheet.render(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
html.find(".effect-delete").on("click", async (ev) => {
|
|
||||||
const li = $(ev.currentTarget).parents(".effect");
|
|
||||||
await this.item.deleteEmbeddedEntity("ActiveEffect", li.data("effectId"));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle creating a new ActiveEffect for the item using initial data defined in the HTML dataset
|
* Handle management of ActiveEffects.
|
||||||
* @param {Event} event The originating click event
|
* @param {Event} event The originating click event
|
||||||
* @private
|
|
||||||
*/
|
*/
|
||||||
private async _onEffectCreate(event: JQuery.ClickEvent): Promise<unknown> {
|
private async _onManageActiveEffect(event: JQuery.ClickEvent): Promise<unknown> {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
|
if (this.item.isOwned) {
|
||||||
|
return ui.notifications.warn(game.i18n.localize("DS4.WarningManageActiveEffectOnOwnedItem"));
|
||||||
|
}
|
||||||
|
const a = event.currentTarget;
|
||||||
|
const li = $(a).parents(".effect");
|
||||||
|
|
||||||
|
switch (a.dataset["action"]) {
|
||||||
|
case "create":
|
||||||
|
return this._createActiveEffect();
|
||||||
|
case "edit":
|
||||||
|
const effect = this.item.effects.get(li.data("effectId"));
|
||||||
|
return effect.sheet.render(true);
|
||||||
|
case "delete": {
|
||||||
|
return this.item.deleteEmbeddedEntity("ActiveEffect", li.data("effectId"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new ActiveEffect for the item using default data.
|
||||||
|
*/
|
||||||
|
private async _createActiveEffect(): Promise<unknown> {
|
||||||
const label = `New Effect`;
|
const label = `New Effect`;
|
||||||
|
|
||||||
const createData = {
|
const createData = {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { DS4Actor } from "../actor/actor";
|
import { DS4Actor } from "../actor/actor";
|
||||||
import { DS4ActorDataType } from "../actor/actor-data";
|
import { DS4ActorDataType } from "../actor/actor-data";
|
||||||
import { DS4ItemDataType } from "./item-data";
|
import { DS4ItemDataType, DS4Talent } from "./item-data";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extend the basic Item with some very simple modifications.
|
* Extend the basic Item with some very simple modifications.
|
||||||
|
@ -12,10 +12,18 @@ export class DS4Item extends Item<DS4ItemDataType, DS4ActorDataType, DS4Actor> {
|
||||||
*/
|
*/
|
||||||
prepareData(): void {
|
prepareData(): void {
|
||||||
super.prepareData();
|
super.prepareData();
|
||||||
|
this.prepareDerivedData();
|
||||||
|
|
||||||
// Get the Item's data
|
// Get the Item's data
|
||||||
// const itemData = this.data;
|
// const itemData = this.data;
|
||||||
// const actorData = this.actor ? this.actor.data : {};
|
// const actorData = this.actor ? this.actor.data : {};
|
||||||
// const data = itemData.data;
|
// const data = itemData.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prepareDerivedData(): void {
|
||||||
|
if (this.type === "talent") {
|
||||||
|
const data = this.data.data as DS4Talent;
|
||||||
|
data.rank.total = data.rank.base + data.rank.mod;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
}
|
}
|
||||||
.attribute-value {
|
.attribute-value {
|
||||||
border: 2px groove $c-border-groove;
|
border: 2px groove $c-border-groove;
|
||||||
line-height: $default-input-height;
|
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding-left: 2px;
|
padding-left: 2px;
|
||||||
|
@ -17,6 +16,7 @@
|
||||||
input,
|
input,
|
||||||
.attribute-value-total {
|
.attribute-value-total {
|
||||||
grid-column: span 2;
|
grid-column: span 2;
|
||||||
|
line-height: $default-input-height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,6 @@
|
||||||
.trait-value {
|
.trait-value {
|
||||||
border: 2px groove $c-border-groove;
|
border: 2px groove $c-border-groove;
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
line-height: $default-input-height;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding-left: 2px;
|
padding-left: 2px;
|
||||||
padding-right: 2px;
|
padding-right: 2px;
|
||||||
|
@ -40,6 +39,7 @@
|
||||||
input,
|
input,
|
||||||
.trait-value-total {
|
.trait-value-total {
|
||||||
grid-column: span 2;
|
grid-column: span 2;
|
||||||
|
line-height: $default-input-height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,25 @@
|
||||||
.basic-properties {
|
.basic-properties {
|
||||||
flex: 0 0 100%;
|
flex: 0 0 100%;
|
||||||
|
gap: 2px;
|
||||||
.basic-property {
|
.basic-property {
|
||||||
.basic-property-label {
|
display: grid;
|
||||||
|
align-content: end;
|
||||||
|
padding-left: 1px;
|
||||||
|
padding-right: 1px;
|
||||||
|
|
||||||
|
& > label {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.basic-property-select {
|
& > select {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.input-divider {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include mark-invalid-or-disabled-input;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
28
src/scss/components/_character_progression.scss
Normal file
28
src/scss/components/_character_progression.scss
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
.progression {
|
||||||
|
.progression-entry {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
padding-right: 3px;
|
||||||
|
h2.progression-label {
|
||||||
|
font-family: $font-heading;
|
||||||
|
display: block;
|
||||||
|
height: 50px;
|
||||||
|
padding: 0px;
|
||||||
|
color: $c-light-grey;
|
||||||
|
border: none;
|
||||||
|
line-height: 50px;
|
||||||
|
margin: $header-top-margin 0;
|
||||||
|
text-align: right;
|
||||||
|
//flex: 0;
|
||||||
|
}
|
||||||
|
input.progression-value {
|
||||||
|
margin-left: 5px;
|
||||||
|
flex: 0 0 40px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,7 @@
|
||||||
.side-property {
|
.side-property {
|
||||||
margin: 2px 0;
|
margin: 2px 0;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 40% auto;
|
grid-template-columns: minmax(30%, auto) auto;
|
||||||
justify-content: left;
|
justify-content: left;
|
||||||
|
|
||||||
label {
|
label {
|
||||||
|
@ -23,6 +23,8 @@
|
||||||
width: calc(100% - 2px);
|
width: calc(100% - 2px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@include mark-invalid-or-disabled-input;
|
||||||
|
|
||||||
input[type="checkbox"] {
|
input[type="checkbox"] {
|
||||||
width: auto;
|
width: auto;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -31,6 +33,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.sheet-body .tab .editor {
|
.sheet-body .tab .editor {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ header.sheet-header {
|
||||||
display: block;
|
display: block;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
flex: 0 0 0;
|
flex: 0 0 auto;
|
||||||
color: $c-light-grey;
|
color: $c-light-grey;
|
||||||
border: none;
|
border: none;
|
||||||
line-height: 50px;
|
line-height: 50px;
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
input {
|
input {
|
||||||
border: 0;
|
border: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="checkbox"] {
|
input[type="checkbox"] {
|
||||||
|
@ -38,6 +39,8 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@include mark-invalid-or-disabled-input;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-name {
|
.item-name {
|
||||||
|
@ -54,9 +57,6 @@
|
||||||
width: 2.5em;
|
width: 2.5em;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
.item-num-val:invalid {
|
|
||||||
background-color: color.mix(lightcoral, $c-light-grey, 25%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-description {
|
.item-description {
|
||||||
font-size: 75%;
|
font-size: 75%;
|
||||||
|
|
3
src/scss/components/_talents.scss
Normal file
3
src/scss/components/_talents.scss
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.talent-ranks-equation {
|
||||||
|
text-align: center;
|
||||||
|
}
|
|
@ -18,6 +18,9 @@
|
||||||
.flex1 {
|
.flex1 {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
.flex125 {
|
||||||
|
flex: 1.25;
|
||||||
|
}
|
||||||
.flex15 {
|
.flex15 {
|
||||||
flex: 1.5;
|
flex: 1.5;
|
||||||
}
|
}
|
||||||
|
@ -51,6 +54,9 @@
|
||||||
.flex1 {
|
.flex1 {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
.flex125 {
|
||||||
|
flex: 1.25;
|
||||||
|
}
|
||||||
.flex15 {
|
.flex15 {
|
||||||
flex: 1.5;
|
flex: 1.5;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid-6col {
|
.grid-6col {
|
||||||
grid-column: span 5 / span 5;
|
grid-column: span 6 / span 6;
|
||||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
grid-template-columns: repeat(6, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid-7col {
|
.grid-7col {
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
.window-app {
|
.window-app {
|
||||||
font-family: $font-primary;
|
font-family: $font-primary;
|
||||||
|
input[type="text"],
|
||||||
|
input[type="number"],
|
||||||
|
input[type="password"],
|
||||||
|
input[type="date"],
|
||||||
|
input[type="time"] {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.rollable {
|
.rollable {
|
||||||
|
|
|
@ -2,3 +2,4 @@ $c-white: #fff;
|
||||||
$c-black: #000;
|
$c-black: #000;
|
||||||
$c-light-grey: #777;
|
$c-light-grey: #777;
|
||||||
$c-border-groove: #eeede0;
|
$c-border-groove: #eeede0;
|
||||||
|
$c-invalid-input: rgba(lightcoral, 50%);
|
||||||
|
|
|
@ -19,3 +19,12 @@
|
||||||
display: grid;
|
display: grid;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin mark-invalid-or-disabled-input {
|
||||||
|
input:invalid {
|
||||||
|
background-color: $c-invalid-input;
|
||||||
|
}
|
||||||
|
input:disabled {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -20,9 +20,9 @@
|
||||||
],
|
],
|
||||||
"gridDistance": 1,
|
"gridDistance": 1,
|
||||||
"gridUnits": "m",
|
"gridUnits": "m",
|
||||||
"primaryTokenAttribute": "combatValues.hitPoints.current",
|
"primaryTokenAttribute": "combatValues.hitPoints",
|
||||||
"url": "https://git.f3l.de/dungeonslayers/ds4",
|
"url": "https://git.f3l.de/dungeonslayers/ds4",
|
||||||
"manifest": "https://git.f3l.de/dungeonslayers/ds4/-/blob/master/src/system.json",
|
"manifest": "https://git.f3l.de/dungeonslayers/ds4/-/raw/master/src/system.json?inline=false",
|
||||||
"download": "https://git.f3l.de/dungeonslayers/ds4/-/archive/master/ds4-master.zip",
|
"download": "https://git.f3l.de/dungeonslayers/ds4/-/jobs/artifacts/0.1.0/download?job=build",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
"hitPoints": {
|
"hitPoints": {
|
||||||
"base": 0,
|
"base": 0,
|
||||||
"mod": 0,
|
"mod": 0,
|
||||||
"current": 0
|
"value": 0
|
||||||
},
|
},
|
||||||
"defense": {
|
"defense": {
|
||||||
"base": 0,
|
"base": 0,
|
||||||
|
@ -83,7 +83,8 @@
|
||||||
"race": "",
|
"race": "",
|
||||||
"class": "",
|
"class": "",
|
||||||
"heroClass": "",
|
"heroClass": "",
|
||||||
"racialAbilities": ""
|
"racialAbilities": "",
|
||||||
|
"culture": ""
|
||||||
},
|
},
|
||||||
"progression": {
|
"progression": {
|
||||||
"level": 0,
|
"level": 0,
|
||||||
|
@ -96,11 +97,26 @@
|
||||||
"total": 0,
|
"total": 0,
|
||||||
"used": 0
|
"used": 0
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"languages": "",
|
||||||
|
"alphabets": ""
|
||||||
|
},
|
||||||
|
"profile": {
|
||||||
|
"gender": "",
|
||||||
|
"birthday": "",
|
||||||
|
"birthplace": "",
|
||||||
|
"age": 0,
|
||||||
|
"height": 0,
|
||||||
|
"hairColor": "",
|
||||||
|
"weight": 0,
|
||||||
|
"eyeColor": "",
|
||||||
|
"specialCharacteristics": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Item": {
|
"Item": {
|
||||||
"types": ["weapon", "armor", "shield", "trinket", "equipment"],
|
"types": ["weapon", "armor", "shield", "trinket", "equipment", "talent", "racialAbility"],
|
||||||
"templates": {
|
"templates": {
|
||||||
"base": {
|
"base": {
|
||||||
"description": ""
|
"description": ""
|
||||||
|
@ -137,6 +153,17 @@
|
||||||
},
|
},
|
||||||
"equipment": {
|
"equipment": {
|
||||||
"templates": ["base", "physical"]
|
"templates": ["base", "physical"]
|
||||||
|
},
|
||||||
|
"talent": {
|
||||||
|
"templates": ["base"],
|
||||||
|
"rank": {
|
||||||
|
"base": 0,
|
||||||
|
"max": 0,
|
||||||
|
"mod": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"racialAbility": {
|
||||||
|
"templates": ["base"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,96 +2,66 @@
|
||||||
{{!-- Sheet Header --}}
|
{{!-- Sheet Header --}}
|
||||||
<header class="sheet-header">
|
<header class="sheet-header">
|
||||||
<img class="profile-img" src="{{actor.img}}" data-edit="img" title="{{actor.name}}" height="100" width="100" />
|
<img class="profile-img" src="{{actor.img}}" data-edit="img" title="{{actor.name}}" height="100" width="100" />
|
||||||
<div class="header-fields">
|
<div class="header-fields flexrow">
|
||||||
<h1 class="charname"><input name="name" type="text" value="{{actor.name}}" placeholder="Name" /></h1>
|
<h1 class="charname"><input name="name" type="text" value="{{actor.name}}" placeholder="Name" /></h1>
|
||||||
</div>
|
{{> systems/ds4/templates/actor/partials/character-progression.hbs}}
|
||||||
<div class="character-values">
|
|
||||||
{{!-- The grid classes are defined in scss/global/_grid.scss. To use, use both the "grid" and "grid-Ncol"
|
<div class="flexrow basic-properties">
|
||||||
class where "N" can be any number from 1 to 12 and will create that number of columns. --}}
|
<div class="basic-property">
|
||||||
<div class="base-infos grid grid-3col">
|
<label class="basic-property-label" for="data.baseInfo.race">{{config.baseInfo.race}}</label>
|
||||||
{{!-- "flex-group-center" is also defined in the _grid.scss file and it will add a small amount of
|
<input type="text" name="data.baseInfo.race" value="{{data.baseInfo.race}}" data-dtype="String" />
|
||||||
padding, a border, and will center all of its child elements content and text. --}}
|
</div>
|
||||||
<div class="base-info flex-group-center">
|
<div class="basic-property">
|
||||||
<label for="data.baseInfo.race" class="base-info-label">{{config.baseInfo.race}}</label>
|
<label class="basic-property-label" for="data.baseInfo.culture">{{config.baseInfo.culture}}</label>
|
||||||
<div class="base-info-content flexrow flex-center flex-between">
|
<input type="text" name="data.baseInfo.culture" value="{{data.baseInfo.culture}}"
|
||||||
<input type="text" name="data.baseInfo.race" value="{{data.baseInfo.race}}"
|
data-dtype="String" />
|
||||||
data-dtype="String" />
|
</div>
|
||||||
|
<div class="basic-property flex125">
|
||||||
|
<label class="basic-property-label"
|
||||||
|
for="data.progression.progressPoints.used">{{config.progression.progressPoints}}</label>
|
||||||
|
<div class="flexrow">
|
||||||
|
<input type="number" name="data.progression.progressPoints.used"
|
||||||
|
value="{{data.progression.progressPoints.used}}" data-dtype="Number" /><span
|
||||||
|
class="input-divider"> /
|
||||||
|
</span><input type="number" name="data.progression.progressPoints.total"
|
||||||
|
value="{{data.progression.progressPoints.total}}" data-dtype="Number" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="base-info flex-group-center">
|
<div class="basic-property flex125">
|
||||||
<div class="grid grid-3col">
|
<label class="basic-property-label"
|
||||||
<div class="base-info flex-group-center">
|
for="data.progression.talentPoints.used">{{config.progression.talentPoints}}</label>
|
||||||
<label for="data.progression.level"
|
<div class="flexrow">
|
||||||
class="base-info-label">{{config.progression.level}}</label>
|
<input type="number" name="data.progression.talentPoints.used"
|
||||||
<div class="base-info-content flexrow flex-center flex-between">
|
value="{{data.progression.talentPoints.used}}" data-dtype="Number" /><span
|
||||||
<input type="text" name="data.progression.level" value="{{data.progression.level}}"
|
class="input-divider"> /
|
||||||
data-dtype="Number" />
|
</span><input type="number" name="data.progression.talentPoints.total"
|
||||||
</div>
|
value="{{data.progression.talentPoints.total}}" data-dtype="Number" />
|
||||||
</div>
|
|
||||||
<div class="base-info flex-group-center">
|
|
||||||
<label for="data.progression.progressPoints"
|
|
||||||
class="base-info-label">{{config.progression.progressPoints}}</label>
|
|
||||||
<div class="base-info-content flexrow flex-center flex-between">
|
|
||||||
<input type="text" name="data.progression.progressPoints.used"
|
|
||||||
value="{{data.progression.progressPoints.used}}" data-dtype="Number" /><span> /
|
|
||||||
</span><input type="text" name="data.progression.progressPoints.total"
|
|
||||||
value="{{data.progression.progressPoints.total}}" data-dtype="Number" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="base-info flex-group-center">
|
|
||||||
<label for="data.progression.talentPoints"
|
|
||||||
class="base-info-label">{{config.progression.talentPoints}}</label>
|
|
||||||
<div class="base-info-content flexrow flex-center flex-between">
|
|
||||||
<input type="text" name="data.progression.talentPoints.used"
|
|
||||||
value="{{data.progression.talentPoints.used}}" data-dtype="Number" /><span> /
|
|
||||||
</span><input type="text" name="data.progression.talentPoints.total"
|
|
||||||
value="{{data.progression.talentPoints.total}}" data-dtype="Number" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="base-info flex-group-center">
|
<div class="basic-property">
|
||||||
<label for="data.baseInfo.class" class="base-info-label">{{config.baseInfo.class}}</label>
|
<label class="basic-property-label" for="data.baseInfo.class">{{config.baseInfo.class}}</label>
|
||||||
<div class="base-info-content flexrow flex-center flex-between">
|
<input type="text" name="data.baseInfo.class" value="{{data.baseInfo.class}}" data-dtype="String" />
|
||||||
<input type="text" name="data.baseInfo.class" value="{{data.baseInfo.class}}"
|
|
||||||
data-dtype="String" />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="base-info flex-group-center">
|
<div class="basic-property">
|
||||||
<label for="data.baseInfo.racialAbilities"
|
<label class="basic-property-label"
|
||||||
class="base-info-label">{{config.baseInfo.racialAbilities}}</label>
|
for="data.baseInfo.heroClass">{{config.baseInfo.heroClass}}</label>
|
||||||
<div class="base-info-content flexrow flex-center flex-between">
|
<input type="text" name="data.baseInfo.heroClass" value="{{data.baseInfo.heroClass}}"
|
||||||
<input type="text" name="data.baseInfo.racialAbilities"
|
data-dtype="String" />
|
||||||
value="{{data.baseInfo.racialAbilities}}" data-dtype="String" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="base-info flex-group-center">
|
|
||||||
<label for="data.progression.experiencePoints"
|
|
||||||
class="base-info-label">{{config.progression.experiencePoints}}</label>
|
|
||||||
<div class="base-info-content flexrow flex-center flex-between">
|
|
||||||
<input type="text" name="data.progression.experiencePoints"
|
|
||||||
value="{{data.progression.experiencePoints}}" data-dtype="Number" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="base-info flex-group-center">
|
|
||||||
<label for="data.baseInfo.heroClass" class="base-info-label">{{config.baseInfo.heroClass}}</label>
|
|
||||||
<div class="base-info-content flexrow flex-center flex-between">
|
|
||||||
<input type="text" name="data.baseInfo.heroClass" value="{{data.baseInfo.heroClass}}"
|
|
||||||
data-dtype="String" />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="character-values">
|
||||||
{{> systems/ds4/templates/actor/partials/attributes-traits.hbs}}
|
{{> systems/ds4/templates/actor/partials/attributes-traits.hbs}}
|
||||||
{{> systems/ds4/templates/actor/partials/combat-values.hbs}}
|
{{> systems/ds4/templates/actor/partials/combat-values.hbs}}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
{{!-- Sheet Tab Navigation --}}
|
{{!-- Sheet Tab Navigation --}}
|
||||||
<nav class="sheet-tabs tabs" data-group="primary">
|
<nav class="sheet-tabs tabs" data-group="primary">
|
||||||
<a class="item" data-tab="description">Description</a>
|
<a class="item" data-tab="description">{{localize 'DS4.HeadingDescription'}}</a>
|
||||||
<a class="item" data-tab="items">Items</a>
|
<a class="item" data-tab="talents">{{localize 'DS4.HeadingTalents'}}</a>
|
||||||
|
<a class="item" data-tab="profile">{{localize "DS4.HeadingProfile"}}</a>
|
||||||
|
<a class="item" data-tab="inventory">{{localize 'DS4.HeadingInventory'}}</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{{!-- Sheet Body --}}
|
{{!-- Sheet Body --}}
|
||||||
|
@ -101,6 +71,12 @@
|
||||||
{{editor content=data.biography target="data.biography" button=true owner=owner editable=editable}}
|
{{editor content=data.biography target="data.biography" button=true owner=owner editable=editable}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{! Profile Tab --}}
|
||||||
|
{{> systems/ds4/templates/actor/partials/profile.hbs}}
|
||||||
|
|
||||||
|
{{!-- Talents Tab --}}
|
||||||
|
{{> systems/ds4/templates/actor/partials/talents-overview.hbs}}
|
||||||
|
|
||||||
{{!-- Items Tab --}}
|
{{!-- Items Tab --}}
|
||||||
{{> systems/ds4/templates/actor/partials/items-overview.hbs}}
|
{{> systems/ds4/templates/actor/partials/items-overview.hbs}}
|
||||||
</section>
|
</section>
|
||||||
|
|
15
src/templates/actor/partials/character-progression.hbs
Normal file
15
src/templates/actor/partials/character-progression.hbs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<div class="progression flexrow">
|
||||||
|
<div class="progression-entry">
|
||||||
|
<h2 class="progression-label"><label for="data.progression.level">{{config.progression.level}}</label>
|
||||||
|
</h2>
|
||||||
|
<input class="progression-value" type="number" name="data.progression.level" value="{{data.progression.level}}"
|
||||||
|
data-dtype="Number" />
|
||||||
|
</div>
|
||||||
|
<div class="progression-entry">
|
||||||
|
<h2 class="progression-label"><label
|
||||||
|
for="data.progression.experiencePoints">{{config.progression.experiencePoints}}</label>
|
||||||
|
</h2>
|
||||||
|
<input class="progression-value" type="number" name="data.progression.experiencePoints"
|
||||||
|
value="{{data.progression.experiencePoints}}" data-dtype="Number" />
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -5,29 +5,6 @@
|
||||||
{{!-- INLINE PARTIAL DEFINITIONS --}}
|
{{!-- INLINE PARTIAL DEFINITIONS --}}
|
||||||
{{!-- ======================================================================== --}}
|
{{!-- ======================================================================== --}}
|
||||||
|
|
||||||
{{!--
|
|
||||||
!-- Render an "add" button for a given data type.
|
|
||||||
!--
|
|
||||||
!-- @param datType: hand over the dataType to the partial as hash parameter
|
|
||||||
--}}
|
|
||||||
{{#*inline "addItemButton"}}
|
|
||||||
<div class="item-controls">
|
|
||||||
<a class="item-control item-create" title="Create item" data-type="{{dataType}}">
|
|
||||||
<i class="fas fa-plus"></i>
|
|
||||||
{{localize 'DS4.UserInteractionAddItem'}}</a>
|
|
||||||
</div>
|
|
||||||
{{/inline}}
|
|
||||||
{{!--
|
|
||||||
!-- Render a group of an "edit" and a "delete" button for the current item.
|
|
||||||
!-- The current item is defined by the data-item-id HTML property of the parent li element.
|
|
||||||
--}}
|
|
||||||
{{#*inline "itemControlButtons"}}
|
|
||||||
<div class="item-controls">
|
|
||||||
<a class="item-control item-edit" title="Edit Item"><i class="fas fa-edit"></i></a>
|
|
||||||
<a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
|
|
||||||
</div>
|
|
||||||
{{/inline}}
|
|
||||||
|
|
||||||
|
|
||||||
{{!--
|
{{!--
|
||||||
!-- Render a header row for a given data type.
|
!-- Render a header row for a given data type.
|
||||||
|
@ -55,9 +32,9 @@
|
||||||
{{!-- item type specifics --}}
|
{{!-- item type specifics --}}
|
||||||
{{> @partial-block }}
|
{{> @partial-block }}
|
||||||
{{!-- description --}}
|
{{!-- description --}}
|
||||||
<div class="flex4">{{localize 'DS4.Description'}}</div>
|
<div class="flex4">{{localize 'DS4.HeadingDescription'}}</div>
|
||||||
{{!-- add button --}}
|
{{!-- add button --}}
|
||||||
{{> addItemButton dataType=dataType }}
|
{{> systems/ds4/templates/actor/partials/overview-add-button.hbs dataType=dataType }}
|
||||||
</li>
|
</li>
|
||||||
{{/inline}}
|
{{/inline}}
|
||||||
|
|
||||||
|
@ -94,7 +71,7 @@
|
||||||
{{!-- description --}}
|
{{!-- description --}}
|
||||||
<div class="flex4 item-description">{{{item.data.data.description}}}</div>
|
<div class="flex4 item-description">{{{item.data.data.description}}}</div>
|
||||||
{{!-- control buttons --}}
|
{{!-- control buttons --}}
|
||||||
{{> itemControlButtons}}
|
{{> systems/ds4/templates/actor/partials/overview-control-buttons.hbs }}
|
||||||
</li>
|
</li>
|
||||||
{{/inline}}
|
{{/inline}}
|
||||||
|
|
||||||
|
@ -102,10 +79,10 @@
|
||||||
{{!-- ======================================================================== --}}
|
{{!-- ======================================================================== --}}
|
||||||
|
|
||||||
|
|
||||||
<div class="tab items" data-group="primary" data-tab="items">
|
<div class="tab inventory" data-group="primary" data-tab="inventory">
|
||||||
|
|
||||||
{{!-- WEAPONS --}}
|
{{!-- WEAPONS --}}
|
||||||
<h4 class="items-list-title">{{localize 'DS4.ItemTypeWeapon'}}</h4>
|
<h4 class="items-list-title">{{localize 'DS4.ItemTypeWeaponPlural'}}</h4>
|
||||||
<ol class="items-list">
|
<ol class="items-list">
|
||||||
{{#> itemListHeader dataType='weapon'}}
|
{{#> itemListHeader dataType='weapon'}}
|
||||||
<div class="flex05 item-image" title="{{localize 'DS4.AttackType'}}">{{localize 'DS4.AttackTypeAbbr'}}</div>
|
<div class="flex05 item-image" title="{{localize 'DS4.AttackType'}}">{{localize 'DS4.AttackTypeAbbr'}}</div>
|
||||||
|
@ -129,7 +106,7 @@
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
{{!-- ARMOR --}}
|
{{!-- ARMOR --}}
|
||||||
<h4 class="items-list-title">{{localize 'DS4.ItemTypeArmor'}}</h4>
|
<h4 class="items-list-title">{{localize 'DS4.ItemTypeArmorPlural'}}</h4>
|
||||||
<ol class="items-list">
|
<ol class="items-list">
|
||||||
{{#> itemListHeader dataType='armor'}}
|
{{#> itemListHeader dataType='armor'}}
|
||||||
<div title="{{localize 'DS4.ArmorMaterialType'}}">{{localize 'DS4.ArmorMaterialTypeAbbr'}}</div>
|
<div title="{{localize 'DS4.ArmorMaterialType'}}">{{localize 'DS4.ArmorMaterialTypeAbbr'}}</div>
|
||||||
|
@ -153,7 +130,7 @@
|
||||||
|
|
||||||
|
|
||||||
{{!-- SHIELD --}}
|
{{!-- SHIELD --}}
|
||||||
<h4 class="items-list-title">{{localize 'DS4.ItemTypeShield'}}</h4> {{!-- SPECIFIC --}}
|
<h4 class="items-list-title">{{localize 'DS4.ItemTypeShieldPlural'}}</h4> {{!-- SPECIFIC --}}
|
||||||
<ol class="items-list">
|
<ol class="items-list">
|
||||||
{{#> itemListHeader dataType='shield' }}
|
{{#> itemListHeader dataType='shield' }}
|
||||||
<div class="flex05 item-num-val" title="{{localize 'DS4.ArmorValue'}}">
|
<div class="flex05 item-num-val" title="{{localize 'DS4.ArmorValue'}}">
|
||||||
|
@ -168,7 +145,7 @@
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
{{!-- TRINKET --}}
|
{{!-- TRINKET --}}
|
||||||
<h4 class="items-list-title">{{localize 'DS4.ItemTypeTrinket'}}</h4>
|
<h4 class="items-list-title">{{localize 'DS4.ItemTypeTrinketPlural'}}</h4>
|
||||||
<ol class="items-list">
|
<ol class="items-list">
|
||||||
{{#> itemListHeader dataType='trinket'}}
|
{{#> itemListHeader dataType='trinket'}}
|
||||||
<div class="flex2">{{localize 'DS4.StorageLocation'}}</div>
|
<div class="flex2">{{localize 'DS4.StorageLocation'}}</div>
|
||||||
|
@ -182,7 +159,7 @@
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
{{!-- EQUIPMENT --}}
|
{{!-- EQUIPMENT --}}
|
||||||
<h4 class="items-list-title">{{localize 'DS4.ItemTypeEquipment'}}</h4>
|
<h4 class="items-list-title">{{localize 'DS4.ItemTypeEquipmentPlural'}}</h4>
|
||||||
<ol class="items-list">
|
<ol class="items-list">
|
||||||
{{#> itemListHeader dataType='equipment'}}
|
{{#> itemListHeader dataType='equipment'}}
|
||||||
<div class="flex2">{{localize 'DS4.StorageLocation'}}</div>
|
<div class="flex2">{{localize 'DS4.StorageLocation'}}</div>
|
||||||
|
|
11
src/templates/actor/partials/overview-add-button.hbs
Normal file
11
src/templates/actor/partials/overview-add-button.hbs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{{!
|
||||||
|
!-- Render an "add" button for adding an item of given data type.
|
||||||
|
!--
|
||||||
|
!-- @param datType: hand over the dataType to the partial as hash parameter
|
||||||
|
}}
|
||||||
|
<div class="item-controls">
|
||||||
|
<a class="item-control item-create" title="Create item" data-type="{{dataType}}">
|
||||||
|
<i class="fas fa-plus"></i>
|
||||||
|
{{localize "DS4.UserInteractionAddItem"}}
|
||||||
|
</a>
|
||||||
|
</div>
|
|
@ -0,0 +1,8 @@
|
||||||
|
{{!--
|
||||||
|
!-- Render a group of an "edit" and a "delete" button for the current item.
|
||||||
|
!-- The current item is defined by the data-item-id HTML property of the parent li element.
|
||||||
|
--}}
|
||||||
|
<div class="item-controls">
|
||||||
|
<a class="item-control item-edit" title="Edit Item"><i class="fas fa-edit"></i></a>
|
||||||
|
<a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
|
||||||
|
</div>
|
13
src/templates/actor/partials/profile.hbs
Normal file
13
src/templates/actor/partials/profile.hbs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<div class="tab profile" data-group="primary" data-tab="profile">
|
||||||
|
<div class="grid grid-2col">
|
||||||
|
{{#each data.profile as |profile-data-value profile-data-key|}}
|
||||||
|
<div class="profile-entry">
|
||||||
|
<label for="data.profile.{{profile-data-key}}">
|
||||||
|
{{lookup ../config.profile profile-data-key}}
|
||||||
|
</label>
|
||||||
|
<input type="text" name="data.profile.{{profile-data-key}}" value="{{profile-data-value}}"
|
||||||
|
data-dtype="{{lookup ../config/profileDTypes profile-data-key}}" />
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</div>
|
123
src/templates/actor/partials/talents-overview.hbs
Normal file
123
src/templates/actor/partials/talents-overview.hbs
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
{{!-- ======================================================================== --}}
|
||||||
|
{{!-- INLINE PARTIAL DEFINITIONS --}}
|
||||||
|
{{!-- ======================================================================== --}}
|
||||||
|
{{!-- TODO: remove duplicate add and delete button definition --}}
|
||||||
|
|
||||||
|
|
||||||
|
{{!--
|
||||||
|
!-- Render an input element for a rank value property of an item.
|
||||||
|
!--
|
||||||
|
!-- @param item: the item
|
||||||
|
!-- @param property: the key of the property in item.data.data (if 'base', the max value is set automatically)
|
||||||
|
!-- @param disabled: if given, is placed plainly into the input as HTML property;
|
||||||
|
!-- meant to be set to "disabled" to disable the input element
|
||||||
|
--}}
|
||||||
|
{{#*inline "talentRankValue"}}
|
||||||
|
<input class="item-num-val item-change" data-dtype="Number" type="number" min="0" step="1" {{#if (eq property 'base' )
|
||||||
|
}}max="{{item.data.data.rank.max}}" {{/if}} {{disabled}} data-property="data.rank.{{property}}"
|
||||||
|
value="{{lookup item.data.data.rank property}}" title="{{localize localizeString}}" />
|
||||||
|
{{/inline}}
|
||||||
|
|
||||||
|
|
||||||
|
{{!--
|
||||||
|
!-- Render a talent list row from a given item.
|
||||||
|
!-- 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
|
||||||
|
!-- @param partial-block: hand over custom children of the flexbox in the partial block.
|
||||||
|
--}}
|
||||||
|
{{#*inline "talentListEntry"}}
|
||||||
|
<li class="item flexrow" data-item-id="{{item._id}}">
|
||||||
|
{{!-- image --}}
|
||||||
|
<div class="flex05 item-image">
|
||||||
|
<img src="{{item.img}}" title="{{item.name}}" width="24" height="24" />
|
||||||
|
</div>
|
||||||
|
{{!-- name --}}
|
||||||
|
<input class="flex2 item-name item-change" type="text" value="{{item.name}}" data-dtype="String"
|
||||||
|
data-property="name" title="{{localize 'DS4.ItemName'}}">
|
||||||
|
<div class="flex3 flexrow talent-ranks-equation">
|
||||||
|
{{!-- acquired rank --}}
|
||||||
|
{{> talentRankValue item=item property='base' localizeString='DS4.TalentRankBase'}}
|
||||||
|
<span> ( of </span>
|
||||||
|
{{!-- maximum acquirable rank --}}
|
||||||
|
{{> talentRankValue item=item property='max' localizeString='DS4.TalentRankMax'}}
|
||||||
|
<span>) + </span>
|
||||||
|
{{!-- additional ranks --}}
|
||||||
|
{{> talentRankValue item=item property='mod' localizeString='DS4.TalentRankMod'}}
|
||||||
|
<span> = </span>
|
||||||
|
{{!-- derived total rank --}}
|
||||||
|
{{> talentRankValue item=item property='total' localizeString='DS4.TalentRankTotal' disabled='disabled'}}
|
||||||
|
</div>
|
||||||
|
{{!-- description --}}
|
||||||
|
<div class="flex4 item-description">{{{item.data.data.description}}}</div>
|
||||||
|
{{!-- control buttons --}}
|
||||||
|
{{> systems/ds4/templates/actor/partials/overview-control-buttons.hbs }}
|
||||||
|
</li>
|
||||||
|
{{/inline}}
|
||||||
|
|
||||||
|
|
||||||
|
{{!--
|
||||||
|
!-- Render a racial ability list row from a given item.
|
||||||
|
!-- 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
|
||||||
|
!-- @param partial-block: hand over custom children of the flexbox in the partial block.
|
||||||
|
--}}
|
||||||
|
{{#*inline "racialAbilityListEntry"}}
|
||||||
|
<li class="item flexrow" data-item-id="{{item._id}}">
|
||||||
|
{{!-- image --}}
|
||||||
|
<div class="flex05 item-image">
|
||||||
|
<img src="{{item.img}}" title="{{item.name}}" width="24" height="24" />
|
||||||
|
</div>
|
||||||
|
{{!-- name --}}
|
||||||
|
<input class="flex1 item-name item-change" type="text" value="{{item.name}}" data-dtype="String"
|
||||||
|
data-property="name" title="{{localize 'DS4.ItemName'}}">
|
||||||
|
{{!-- description --}}
|
||||||
|
<div class="flex3 item-description">{{{item.data.data.description}}}</div>
|
||||||
|
{{!-- control buttons --}}
|
||||||
|
{{> systems/ds4/templates/actor/partials/overview-control-buttons.hbs }}
|
||||||
|
</li>
|
||||||
|
{{/inline}}
|
||||||
|
|
||||||
|
{{!-- ======================================================================== --}}
|
||||||
|
|
||||||
|
|
||||||
|
<div class="tab items" data-group="primary" data-tab="talents">
|
||||||
|
<h4 class="items-list-title">{{localize 'DS4.ItemTypeTalentPlural'}}</h4>
|
||||||
|
<ol class="items-list">
|
||||||
|
<li class="item flexrow item-header">
|
||||||
|
{{!-- image --}}
|
||||||
|
<div class="flex05 item-image"></div>
|
||||||
|
{{!-- name --}}
|
||||||
|
<div class="flex2 item-name">{{localize 'DS4.ItemName'}}</div>
|
||||||
|
{{!-- rank info --}}
|
||||||
|
<div class="flex3">{{localize 'DS4.TalentRank'}}</div>
|
||||||
|
{{!-- description --}}
|
||||||
|
<div class="flex4">{{localize 'DS4.HeadingDescription'}}</div>
|
||||||
|
{{!-- add button --}}
|
||||||
|
{{> systems/ds4/templates/actor/partials/overview-add-button.hbs dataType='talent' }}
|
||||||
|
</li>
|
||||||
|
{{#each itemsByType.talent as |item id|}}
|
||||||
|
{{> talentListEntry item=item}}
|
||||||
|
{{/each}}
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h4 class="items-list-title">{{localize 'DS4.ItemTypeRacialAbilityPlural'}}</h4>
|
||||||
|
<ol class="items-list">
|
||||||
|
<li class="item flexrow item-header">
|
||||||
|
{{!-- image --}}
|
||||||
|
<div class="flex05 item-image"></div>
|
||||||
|
{{!-- name --}}
|
||||||
|
<div class="flex1 item-name">{{localize 'DS4.ItemName'}}</div>
|
||||||
|
{{!-- description --}}
|
||||||
|
<div class="flex3">{{localize 'DS4.HeadingDescription'}}</div>
|
||||||
|
{{!-- add button --}}
|
||||||
|
{{> systems/ds4/templates/actor/partials/overview-add-button.hbs dataType='racialAbility' }}
|
||||||
|
</li>
|
||||||
|
{{#each itemsByType.racialAbility as |item id|}}
|
||||||
|
{{> racialAbilityListEntry item=item}}
|
||||||
|
{{/each}}
|
||||||
|
</ol>
|
||||||
|
</div>
|
|
@ -6,8 +6,8 @@
|
||||||
<h2 class="item-type">{{localize (lookup config.itemTypes item.type)}}</h2>
|
<h2 class="item-type">{{localize (lookup config.itemTypes item.type)}}</h2>
|
||||||
<div class="grid grid-3col basic-properties">
|
<div class="grid grid-3col basic-properties">
|
||||||
<div class="basic-property">
|
<div class="basic-property">
|
||||||
<label class="basic-property-label">{{localize "DS4.ArmorType"}}</label>
|
<label>{{localize "DS4.ArmorType"}}</label>
|
||||||
<select class="basic-property-select" name="data.armorType" data-type="String">
|
<select name="data.armorType" data-type="String">
|
||||||
{{#select data.armorType}}
|
{{#select data.armorType}}
|
||||||
{{#each config.armorTypes as |value key|}}
|
{{#each config.armorTypes as |value key|}}
|
||||||
<option value="{{key}}">{{value}}</option>
|
<option value="{{key}}">{{value}}</option>
|
||||||
|
@ -16,8 +16,8 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="basic-property">
|
<div class="basic-property">
|
||||||
<label class="basic-property-label">{{localize "DS4.ArmorMaterialType"}}</label>
|
<label>{{localize "DS4.ArmorMaterialType"}}</label>
|
||||||
<select class="basic-property-select" name="data.armorMaterialType" data-type="String">
|
<select name="data.armorMaterialType" data-type="String">
|
||||||
{{#select data.armorMaterialType}}
|
{{#select data.armorMaterialType}}
|
||||||
{{#each config.armorMaterialTypes as |value key|}}
|
{{#each config.armorMaterialTypes as |value key|}}
|
||||||
<option value="{{key}}">{{value}}</option>
|
<option value="{{key}}">{{value}}</option>
|
||||||
|
@ -26,8 +26,8 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="basic-property">
|
<div class="basic-property">
|
||||||
<label class="basic-property-label">{{localize "DS4.ArmorValue"}}</label>
|
<label>{{localize "DS4.ArmorValue"}}</label>
|
||||||
<input class="basic-property-input" type="text" name="data.armorValue" value="{{data.armorValue}}"
|
<input type="text" name="data.armorValue" value="{{data.armorValue}}"
|
||||||
placeholder="0" data-dtype="Number" />
|
placeholder="0" data-dtype="Number" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,9 +2,11 @@
|
||||||
|
|
||||||
{{!-- Sheet Tab Navigation --}}
|
{{!-- Sheet Tab Navigation --}}
|
||||||
<nav class="sheet-tabs tabs" data-group="primary">
|
<nav class="sheet-tabs tabs" data-group="primary">
|
||||||
<a class="item" data-tab="description">{{localize "DS4.Description"}}</a>
|
<a class="item" data-tab="description">{{localize "DS4.HeadingDescription"}}</a>
|
||||||
<a class="item" data-tab="effects">{{localize "DS4.Effects"}}</a>
|
<a class="item" data-tab="effects">{{localize "DS4.HeadingEffects"}}</a>
|
||||||
<a class="item" data-tab="details">{{localize "DS4.Details"}}</a>
|
{{#if isPhysical}}
|
||||||
|
<a class="item" data-tab="details">{{localize "DS4.HeadingDetails"}}</a>
|
||||||
|
{{/if}}
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{{!-- Sheet Body --}}
|
{{!-- Sheet Body --}}
|
||||||
|
@ -13,10 +15,12 @@
|
||||||
{{!-- Description Tab --}}
|
{{!-- Description Tab --}}
|
||||||
{{> systems/ds4/templates/item/partials/description.hbs}}
|
{{> systems/ds4/templates/item/partials/description.hbs}}
|
||||||
|
|
||||||
{{!-- Details Tab --}}
|
|
||||||
{{> systems/ds4/templates/item/partials/details.hbs}}
|
|
||||||
|
|
||||||
{{!-- Effects Tab --}}
|
{{!-- Effects Tab --}}
|
||||||
{{> systems/ds4/templates/item/partials/effects.hbs}}
|
{{> systems/ds4/templates/item/partials/effects.hbs}}
|
||||||
|
|
||||||
|
{{#if isPhysical}}
|
||||||
|
{{!-- Details Tab --}}
|
||||||
|
{{> systems/ds4/templates/item/partials/details.hbs}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
</section>
|
</section>
|
|
@ -11,19 +11,21 @@
|
||||||
<a class="entity-link" draggable="true" data-entity="Actor" data-id="{{actor._id}}"><i
|
<a class="entity-link" draggable="true" data-entity="Actor" data-id="{{actor._id}}"><i
|
||||||
class="fas fa-user"></i>{{actor.name}}</a>
|
class="fas fa-user"></i>{{actor.name}}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="side-property">
|
{{#if isPhysical}}
|
||||||
<label for="data.quantity">{{localize 'DS4.Quantity'}}</label>
|
<div class="side-property">
|
||||||
<input type="number" min="0" step="1" data-dtype="Number" name="data.quantity" value="{{data.quantity}}" />
|
<label for="data.quantity">{{localize 'DS4.Quantity'}}</label>
|
||||||
</div>
|
<input type="number" min="0" step="1" data-dtype="Number" name="data.quantity" value="{{data.quantity}}" />
|
||||||
<div class="side-property">
|
</div>
|
||||||
<label for="data.storageLocation">{{localize 'DS4.StorageLocation'}}</label>
|
<div class="side-property">
|
||||||
<input type="text" data-dtype="String" name="data.storageLocation" value="{{data.storageLocation}}" />
|
<label for="data.storageLocation">{{localize 'DS4.StorageLocation'}}</label>
|
||||||
</div>
|
<input type="text" data-dtype="String" name="data.storageLocation" value="{{data.storageLocation}}" />
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{localize "DS4.NotOwned"}}
|
<span>{{localize "DS4.NotOwned"}}</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<div class="description">
|
<div class="description" title="{{localize 'DS4.HeadingDescription'}}">
|
||||||
{{editor content=data.description target="data.description" button=true owner=owner editable=editable}}
|
{{editor content=data.description target="data.description" button=true owner=owner editable=editable}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -5,16 +5,16 @@
|
||||||
<div class="effect-image"></div>
|
<div class="effect-image"></div>
|
||||||
<div class="effect-name">Name</div>
|
<div class="effect-name">Name</div>
|
||||||
<div class="effect-controls">
|
<div class="effect-controls">
|
||||||
<a class="effect-control effect-create" title="Create Effect"><i
|
<a class="effect-control" data-action="create" title="Create Effect"><i class="fas fa-plus"></i> Add
|
||||||
class="fas fa-plus"></i> Add effect</a>
|
effect</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{{#each item.effects as |effect id|}}
|
{{#each item.effects as |effect id|}}
|
||||||
<li class="effect flexrow" data-effect-id="{{effect._id}}">
|
<li class="effect flexrow" data-effect-id="{{effect._id}}">
|
||||||
<h4 class="effect-name">{{effect.label}}</h4>
|
<h4 class="effect-name">{{effect.label}}</h4>
|
||||||
<div class="effect-controls">
|
<div class="effect-controls">
|
||||||
<a class="effect-control effect-edit" title="Edit Effect"><i class="fas fa-edit"></i></a>
|
<a class="effect-control" data-action="edit" title="Edit Effect"><i class="fas fa-edit"></i></a>
|
||||||
<a class="effect-control effect-delete" title="Delete Effect"><i class="fas fa-trash"></i></a>
|
<a class="effect-control" data-action="delete" title="Delete Effect"><i class="fas fa-trash"></i></a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
13
src/templates/item/racialAbility-sheet.hbs
Normal file
13
src/templates/item/racialAbility-sheet.hbs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<form class="{{cssClass}}" autocomplete="off">
|
||||||
|
<header class="sheet-header">
|
||||||
|
<img class="profile-img" src="{{item.img}}" data-edit="img" title="{{item.name}}" />
|
||||||
|
<div class="header-fields flexrow">
|
||||||
|
<h1 class="charname"><input name="name" type="text" value="{{item.name}}" placeholder="Name" /></h1>
|
||||||
|
<h2 class="item-type">{{localize (lookup config.itemTypes item.type)}}</h2>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
{{!-- Common Item body --}}
|
||||||
|
{{> systems/ds4/templates/item/partials/body.hbs}}
|
||||||
|
|
||||||
|
</form>
|
|
@ -6,8 +6,8 @@
|
||||||
<h2 class="item-type">{{localize (lookup config.itemTypes item.type)}}</h2>
|
<h2 class="item-type">{{localize (lookup config.itemTypes item.type)}}</h2>
|
||||||
<div class="grid grid-1col basic-properties">
|
<div class="grid grid-1col basic-properties">
|
||||||
<div class="basic-property">
|
<div class="basic-property">
|
||||||
<label class="basic-property-label">{{localize "DS4.ArmorValue"}}</label>
|
<label>{{localize "DS4.ArmorValue"}}</label>
|
||||||
<input class="basic-property-input" type="text" name="data.armorValue" value="{{data.armorValue}}"
|
<input type="text" name="data.armorValue" value="{{data.armorValue}}"
|
||||||
placeholder="0" data-dtype="Number" />
|
placeholder="0" data-dtype="Number" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
37
src/templates/item/talent-sheet.hbs
Normal file
37
src/templates/item/talent-sheet.hbs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
{{!-- ======================================================================== --}}
|
||||||
|
{{!-- INLINE PARTIAL DEFINITIONS --}}
|
||||||
|
{{!-- ======================================================================== --}}
|
||||||
|
|
||||||
|
|
||||||
|
{{#*inline "talentRankBasicProperty" }}
|
||||||
|
<div class="basic-property">
|
||||||
|
<label for="data.rank.{{property}}">{{localize localizeString}}</label>
|
||||||
|
<input type="number" min="0" step="1" data-dtype="Number" {{disabled}}
|
||||||
|
{{#if (eq property 'base') }}max="{{data.rank.max}}"{{/if}}
|
||||||
|
name="data.rank.{{property}}" value="{{lookup data.rank property}}" />
|
||||||
|
</div>
|
||||||
|
{{/inline}}
|
||||||
|
|
||||||
|
|
||||||
|
{{!-- ======================================================================== --}}
|
||||||
|
|
||||||
|
|
||||||
|
<form class="{{cssClass}}" autocomplete="off">
|
||||||
|
<header class="sheet-header">
|
||||||
|
<img class="profile-img" src="{{item.img}}" data-edit="img" title="{{item.name}}" />
|
||||||
|
<div class="header-fields flexrow">
|
||||||
|
<h1 class="charname"><input name="name" type="text" value="{{item.name}}" placeholder="Name" /></h1>
|
||||||
|
<h2 class="item-type">{{localize (lookup config.itemTypes item.type)}}</h2>
|
||||||
|
<div class="grid grid-4col basic-properties">
|
||||||
|
{{> talentRankBasicProperty data=data property='base' localizeString='DS4.TalentRankBase' }}
|
||||||
|
{{> talentRankBasicProperty data=data property='max' localizeString='DS4.TalentRankMax'}}
|
||||||
|
{{> talentRankBasicProperty data=data property='mod' localizeString='DS4.TalentRankMod'}}
|
||||||
|
{{> talentRankBasicProperty data=data property='total' localizeString='DS4.TalentRankTotal' disabled='disabled'}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
{{!-- Common Item body --}}
|
||||||
|
{{> systems/ds4/templates/item/partials/body.hbs}}
|
||||||
|
|
||||||
|
</form>
|
|
@ -6,8 +6,8 @@
|
||||||
<h2 class="item-type">{{localize (lookup config.itemTypes item.type)}}</h2>
|
<h2 class="item-type">{{localize (lookup config.itemTypes item.type)}}</h2>
|
||||||
<div class="grid grid-3col basic-properties">
|
<div class="grid grid-3col basic-properties">
|
||||||
<div class="basic-property">
|
<div class="basic-property">
|
||||||
<label class="basic-property-label">{{localize "DS4.AttackType"}}</label>
|
<label>{{localize "DS4.AttackType"}}</label>
|
||||||
<select class="basic-property-select" name="data.attackType" data-type="String">
|
<select name="data.attackType" data-type="String">
|
||||||
{{#select data.attackType}}
|
{{#select data.attackType}}
|
||||||
{{#each config.attackTypes as |value key|}}
|
{{#each config.attackTypes as |value key|}}
|
||||||
<option value="{{key}}">{{value}}</option>
|
<option value="{{key}}">{{value}}</option>
|
||||||
|
@ -16,13 +16,13 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="basic-property">
|
<div class="basic-property">
|
||||||
<label class="basic-property-label">{{localize "DS4.WeaponBonus"}}</label>
|
<label>{{localize "DS4.WeaponBonus"}}</label>
|
||||||
<input class="basic-property-input" type="number" name="data.weaponBonus" value="{{data.weaponBonus}}"
|
<input type="number" name="data.weaponBonus" value="{{data.weaponBonus}}"
|
||||||
placeholder="0" data-dtype="Number" />
|
placeholder="0" data-dtype="Number" />
|
||||||
</div>
|
</div>
|
||||||
<div class="basic-property">
|
<div class="basic-property">
|
||||||
<label class="basic-property-label">{{localize "DS4.OpponentDefense"}}</label>
|
<label>{{localize "DS4.OpponentDefense"}}</label>
|
||||||
<input class="basic-property-input" type="number" name="data.opponentDefense"
|
<input type="number" name="data.opponentDefense"
|
||||||
value="{{data.opponentDefense}}" placeholder="0" data-dtype="Number" />
|
value="{{data.opponentDefense}}" placeholder="0" data-dtype="Number" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue