Merge master

This commit is contained in:
Oliver Rümpelein 2021-01-13 18:32:47 +01:00
commit 7ada67b7c3
32 changed files with 662 additions and 158 deletions

View file

@ -5,6 +5,7 @@ stages:
- test
- build
- deploy
- release
cache: &global_cache
key:
@ -66,3 +67,46 @@ deploy:
only:
- master
resource_group: production
.release-template: &release-template
stage: release
before_script:
- apt update
- apt install --yes jq
- REPOSITORY_URL=$(echo "${CI_REPOSITORY_URL}" | sed -e "s|gitlab-ci-token:.*@|${RELEASE_TOKEN}:${RELEASE_TOKEN_SECRET}@|g")
- git remote set-url origin $REPOSITORY_URL
- git config user.name $GITLAB_USER_LOGIN
- git config user.email $GITLAB_USER_EMAIL
- git branch -D ci-processing || true
- git checkout -b ci-processing
cache:
<<: *global_cache
script: |
npm run updateManifest -- --update=${RELEASE_TYPE}
RELEASE_VERSION=$(jq -r '.version' < package.json)
git add package.json package-lock.json src/system.json
git --no-pager diff
git commit -m "release version ${RELEASE_VERSION}"
git tag -f latest
git tag -f ${RELEASE_VERSION}
git push origin ci-processing:${CI_BUILD_REF_NAME}
git push origin latest -f
git push origin ${RELEASE_VERSION}
only:
- master
when: manual
release-patch:
variables:
RELEASE_TYPE: patch
<<: *release-template
release-minor:
variables:
RELEASE_TYPE: minor
<<: *release-template
release-major:
variables:
RELEASE_TYPE: major
<<: *release-template

View file

@ -1,4 +1,4 @@
Copyright 2020 Johannes Loher, Gesina Schwalbe, Oliver Rümpelein
Copyright 2020 Johannes Loher, Gesina Schwalbe, Oliver Rümpelein, Siegfried Krug
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

View file

@ -2,14 +2,11 @@ const gulp = require("gulp");
const fs = require("fs-extra");
const path = require("path");
const chalk = require("chalk");
const archiver = require("archiver");
const stringify = require("json-stringify-pretty-compact");
const typescript = require("typescript");
const ts = require("gulp-typescript");
const less = require("gulp-less");
const sass = require("gulp-sass");
const git = require("gulp-git");
const argv = require("yargs").argv;
@ -127,13 +124,6 @@ function buildTS() {
return gulp.src("src/**/*.ts").pipe(tsConfig()).pipe(gulp.dest("dist"));
}
/**
* Build Less
*/
function buildLess() {
return gulp.src("src/*.less").pipe(less()).pipe(gulp.dest("dist"));
}
/**
* Build SASS
*/
@ -163,7 +153,6 @@ async function copyFiles() {
*/
function buildWatch() {
gulp.watch("src/**/*.ts", { ignoreInitial: false }, buildTS);
gulp.watch("src/**/*.less", { ignoreInitial: false }, buildLess);
gulp.watch("src/**/*.scss", { ignoreInitial: false }, buildSASS);
gulp.watch(["src/fonts", "src/lang", "src/templates", "src/*.json"], { ignoreInitial: false }, copyFiles);
}
@ -194,8 +183,8 @@ async function clean() {
);
}
// If the project uses Less or SASS
if (fs.existsSync(path.join("src", `${name}.less`)) || fs.existsSync(path.join("src", `${name}.scss`))) {
// If the project uses SASS
if (fs.existsSync(path.join("src", `${name}.scss`))) {
files.push("fonts", `${name}.css`);
}
@ -268,69 +257,15 @@ async function linkUserData() {
/* PACKAGE */
/*********************/
/**
* Package build
*/
async function packageBuild() {
const manifest = getManifest();
return new Promise((resolve, reject) => {
try {
// Remove the package dir without doing anything else
if (argv.clean || argv.c) {
console.log(chalk.yellow("Removing all packaged files"));
fs.removeSync("package");
return;
}
// Ensure there is a directory to hold all the packaged versions
fs.ensureDirSync("package");
// Initialize the zip file
const zipName = `${manifest.file.name}-v${manifest.file.version}.zip`;
const zipFile = fs.createWriteStream(path.join("package", zipName));
const zip = archiver("zip", { zlib: { level: 9 } });
zipFile.on("close", () => {
console.log(chalk.green(zip.pointer() + " total bytes"));
console.log(chalk.green(`Zip file ${zipName} has been written`));
return resolve();
});
zip.on("error", (err) => {
throw err;
});
zip.pipe(zipFile);
// Add the directory with the final code
zip.directory("dist/", manifest.file.name);
zip.finalize();
} catch (err) {
return reject(err);
}
});
}
/*********************/
/* PACKAGE */
/*********************/
/**
* Update version and URLs in the manifest JSON
*/
function updateManifest(cb) {
const packageJson = fs.readJSONSync("package.json");
const config = getConfig(),
manifest = getManifest(),
rawURL = config.rawURL,
repoURL = config.repository,
manifestRoot = manifest.root;
const packageLockJson = fs.readJSONSync("package-lock.json");
const manifest = getManifest();
if (!config) cb(Error(chalk.red("foundryconfig.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")));
try {
const version = argv.update || argv.u;
@ -372,22 +307,22 @@ function updateManifest(cb) {
console.log(`Updating version number to '${targetVersion}'`);
packageJson.version = targetVersion;
packageLockJson.version = targetVersion;
manifest.file.version = targetVersion;
/* Update URLs */
/* Update URL */
const result = `https://git.f3l.de/dungeonslayers/ds4/-/jobs/artifacts/${targetVersion}/download?job=build`;
const result = `${rawURL}/v${manifest.file.version}/package/${manifest.file.name}-v${manifest.file.version}.zip`;
manifest.file.url = repoURL;
manifest.file.manifest = `${rawURL}/master/${manifestRoot}/${manifest.name}`;
manifest.file.download = result;
const prettyProjectJson = stringify(manifest.file, {
maxLength: 35,
indent: "\t",
});
const prettyProjectJson =
stringify(manifest.file, {
maxLength: 40,
indent: 4,
}) + "\n";
fs.writeJSONSync("package.json", packageJson, { spaces: "\t" });
fs.writeJSONSync("package.json", packageJson, { spaces: 4 });
fs.writeJSONSync("package-lock.json", packageLockJson, { spaces: 4 });
fs.writeFileSync(path.join(manifest.root, manifest.name), prettyProjectJson, "utf8");
return cb();
@ -396,34 +331,10 @@ function updateManifest(cb) {
}
}
function gitAdd() {
return gulp.src("package").pipe(git.add({ args: "--no-all" }));
}
function gitCommit() {
return gulp.src("./*").pipe(
git.commit(`v${getManifest().file.version}`, {
args: "-a",
disableAppendPaths: true,
}),
);
}
function gitTag() {
const manifest = getManifest();
return git.tag(`v${manifest.file.version}`, `Updated to ${manifest.file.version}`, (err) => {
if (err) throw err;
});
}
const execGit = gulp.series(gitAdd, gitCommit, gitTag);
const execBuild = gulp.parallel(buildTS, buildLess, buildSASS, copyFiles);
const execBuild = gulp.parallel(buildTS, buildSASS, copyFiles);
exports.build = gulp.series(clean, execBuild);
exports.watch = buildWatch;
exports.clean = clean;
exports.link = linkUserData;
exports.package = packageBuild;
exports.update = updateManifest;
exports.publish = gulp.series(clean, updateManifest, execBuild, packageBuild, execGit);
exports.updateManifest = updateManifest;

15
package-lock.json generated
View file

@ -110,6 +110,15 @@
"fastq": "^1.6.0"
}
},
"@types/fs-extra": {
"version": "9.0.6",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.6.tgz",
"integrity": "sha512-ecNRHw4clCkowNOBJH1e77nvbPxHYnWIXMv1IAoG/9+MYGkgoyr3Ppxr7XYFNL41V422EDhyV4/4SSK8L2mlig==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/jasmine": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.6.2.tgz",
@ -131,6 +140,12 @@
"integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==",
"dev": true
},
"@types/node": {
"version": "14.14.20",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.20.tgz",
"integrity": "sha512-Y93R97Ouif9JEOWPIUyU+eyIdyRqQR0I8Ez1dzku4hDx34NWh4HbtIc3WNzwB1Y9ULvNGeu5B8h8bVL5cAk4/A==",
"dev": true
},
"@types/parse-json": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",

View file

@ -24,15 +24,19 @@
{
"name": "Oliver Rümpelein",
"email": "foundryvtt@pheerai.de"
},
{
"name": "Siegfried Krug",
"email": "foundryvtt@asdil1991.de"
}
],
"scripts": {
"package": "gulp package",
"build": "gulp build",
"build:watch": "gulp watch",
"link": "gulp link",
"clean": "gulp clean && gulp link --clean",
"update": "npm install --save-dev git+https://git.f3l.de/dungeonslayers/foundry-pc-types.git#f3l-fixes",
"updateManifest": "gulp updateManifest",
"lint": "eslint 'src/**/*.ts' --cache",
"lint:fix": "eslint 'src/**/*.ts' --cache --fix",
"test": "ts-node ./node_modules/jasmine/bin/jasmine",
@ -40,6 +44,7 @@
"format": "prettier --write 'src/**/*.(ts|json|scss)'"
},
"devDependencies": {
"@types/fs-extra": "^9.0.6",
"@types/jasmine": "^3.6.2",
"@typescript-eslint/eslint-plugin": "^4.11.1",
"@typescript-eslint/parser": "^4.11.1",

View file

@ -0,0 +1,15 @@
import "jasmine";
import * as fs from "fs-extra";
import * as path from "path";
describe("English and german localization files", () => {
const localizationPath = "./src/lang/";
const en: Record<string, unknown> = fs.readJSONSync(path.join(localizationPath, "en.json"));
const de: Record<string, unknown> = fs.readJSONSync(path.join(localizationPath, "de.json"));
it("should have the same keys.", () => {
const deKeys = Object.keys(de);
const enKeys = Object.keys(en);
expect(deKeys).toEqual(enKeys);
});
});

161
src/lang/de.json Normal file
View file

@ -0,0 +1,161 @@
{
"DS4.UserInteractionAddItem": "Neu",
"DS4.UserInteractionEditItem": "Bearbeiten",
"DS4.UserInteractionDeleteItem": "Löschen",
"DS4.NotOwned": "Nicht besessen",
"DS4.HeadingBiography": "Biografie",
"DS4.HeadingDetails": "Details",
"DS4.HeadingEffects": "Effekte",
"DS4.HeadingInventory": "Inventar",
"DS4.HeadingProfile": "Profil",
"DS4.HeadingTalents": "Talente & Fähigkeiten",
"DS4.HeadingSpells": "Zaubersprüche",
"DS4.AttackType": "Angriffs Typ",
"DS4.AttackTypeAbbr": "AT",
"DS4.WeaponBonus": "Waffen Bonus",
"DS4.WeaponBonusAbbr": "WB",
"DS4.OpponentDefense": "Gegner Abwehr",
"DS4.OpponentDefenseAbbr": "GA",
"DS4.AttackTypeMelee": "Schlagen",
"DS4.AttackTypeRanged": "Schießen",
"DS4.AttackTypeMeleeRanged": "Schlagen + Schießen",
"DS4.Description": "Beschreibung",
"DS4.Quantity": "Menge",
"DS4.PriceGold": "Preis (Gold)",
"DS4.StorageLocation": "Wo gelagert",
"DS4.ItemEquipped": "Ausgerüstet",
"DS4.ItemEquippedAbbr": "A",
"DS4.ItemOwner": "Besitzer",
"DS4.ItemAvailability": "Verfügbarkeit",
"DS4.ItemAvailabilityHamlet": "Dorf",
"DS4.ItemAvailabilityVilage": "Kleinstadt",
"DS4.ItemAvailabilityCity": "Großstadt",
"DS4.ItemAvailabilityElves": "Elfen",
"DS4.ItemAvailabilityDwarves": "Zwerge",
"DS4.ItemAvailabilityUnset": "nicht gesetzt",
"DS4.ItemAvailabilityNowhere": "nirgendwo",
"DS4.ItemName": "Name",
"DS4.ItemTypeWeapon": "Waffe",
"DS4.ItemTypeWeaponPlural": "Waffen",
"DS4.ItemTypeArmor": "Panzerung",
"DS4.ItemTypeArmorPlural": "Panzerungen",
"DS4.ItemTypeShield": "Schild",
"DS4.ItemTypeShieldPlural": "Schilde",
"DS4.ItemTypeSpell": "Zauberspruch",
"DS4.ItemTypeSpellPlural": "Zaubersprüche",
"DS4.ItemTypeTrinket": "Schmuckstück",
"DS4.ItemTypeTrinketPlural": "Schmuckstücke",
"DS4.ItemTypeEquipment": "Ausrüstung",
"DS4.ItemTypeEquipmentPlural": "Ausrüstung",
"DS4.ItemTypeTalent": "Talent",
"DS4.ItemTypeTalentPlural": "Talente",
"DS4.ItemTypeRacialAbility": "Volksfähigkeit",
"DS4.ItemTypeRacialAbilityPlural": "Volksfähigkeiten",
"DS4.ItemTypeLanguage": "Sprache",
"DS4.ItemTypeLanguagePlural": "Sprachen",
"DS4.ItemTypeAlphabet": "Schriftzeichen",
"DS4.ItemTypeAlphabetPlural": "Schriftzeichen",
"DS4.ArmorType": "Panzerungstyp",
"DS4.ArmorTypeAbbr": "PAT",
"DS4.ArmorMaterialType": "Material Typ",
"DS4.ArmorMaterialTypeAbbr": "Mat.",
"DS4.ArmorValue": "Panzerungs Wert",
"DS4.ArmorValueAbbr": "PA",
"DS4.ArmorTypeBody": "Körper",
"DS4.ArmorTypeBodyAbbr": "Körper",
"DS4.ArmorTypeHelmet": "Helm",
"DS4.ArmorTypeHelmetAbbr": "Helm",
"DS4.ArmorTypeVambrace": "Armschienen",
"DS4.ArmorTypeVambraceAbbr": "Arm",
"DS4.ArmorTypeGreaves": "Beinschienen",
"DS4.ArmorTypeGreavesAbbr": "Bein",
"DS4.ArmorTypeVambraceGreaves": "Armschienen + Beinschienen",
"DS4.ArmorTypeVambraceGreavesAbbr": "A+B",
"DS4.ArmorMaterialTypeCloth": "Stoff",
"DS4.ArmorMaterialTypeClothAbbr": "Stoff",
"DS4.ArmorMaterialTypeLeather": "Leder",
"DS4.ArmorMaterialTypeLeatherAbbr": "Leder",
"DS4.ArmorMaterialTypeChain": "Ketten",
"DS4.ArmorMaterialTypeChainAbbr": "Ketten",
"DS4.ArmorMaterialTypePlate": "Platten",
"DS4.ArmorMaterialTypePlateAbbr": "Platten",
"DS4.SpellType": "Zauberspruchtyp",
"DS4.SpellTypeAbbr": "T",
"DS4.SpellTypeSpellcasting": "Zaubern",
"DS4.SpellTypeTargetedSpellcasting": "Zielzaubern",
"DS4.SpellCategory": "Kategorie",
"DS4.SpellCategoryHealing": "Heilung",
"DS4.SpellCategoryFire": "Feuer",
"DS4.SpellCategoryIce": "Eis",
"DS4.SpellCategoryLight": "Licht",
"DS4.SpellCategoryDarkness": "Schatten",
"DS4.SpellCategoryMindAffecting": "Geistensbeeinflussend",
"DS4.SpellCategoryElectricity": "Elektrizität",
"DS4.SpellCategoryNone": "Keine",
"DS4.SpellCategoryUnset": "Nicht gesetzt",
"DS4.SpellBonus": "Zauberbonus",
"DS4.SpellBonusAbbr": "ZB",
"DS4.SpellMaxDistance": "Reichweite",
"DS4.SpellEffectRadius": "Effektradius",
"DS4.SpellDuration": "Wirkdauer",
"DS4.SpellCooldownDuration": "Abklingzeit",
"DS4.SpellScrollPriceGold": "Schriftrollenpreis (Gold)",
"DS4.AttributeBody": "Körper",
"DS4.AttributeMobility": "Agilität",
"DS4.AttributeMind": "Geist",
"DS4.TraitStrength": "Stärke",
"DS4.TraitConstitution": "Härte",
"DS4.TraitAgility": "Bewegung",
"DS4.TraitDexterity": "Geschick",
"DS4.TraitIntellect": "Verstand",
"DS4.TraitAura": "Aura",
"DS4.CombatValuesHitPoints": "Lebenskraft",
"DS4.CombatValuesDefense": "Abwehr",
"DS4.CombatValuesInitiative": "Initiative",
"DS4.CombatValuesMovement": "Laufen",
"DS4.CombatValuesMeleeAttack": "Schlagen",
"DS4.CombatValuesRangedAttack": "Schießen",
"DS4.CombatValuesSpellcasting": "Zaubern",
"DS4.CombatValuesTargetedSpellcasting": "Zielzaubern",
"DS4.BaseInfoRace": "Volk",
"DS4.BaseInfoClass": "Klasse",
"DS4.BaseInfoHeroClass": "Helden Klasse",
"DS4.BaseInfoCulture": "Kultur",
"DS4.ProgressionLevel": "Stufe",
"DS4.ProgressionExperiencePoints": "Erfahrungspunkte",
"DS4.ProgressionTalentPoints": "Talentpunkte",
"DS4.ProgressionProgressPoints": "Lernpunkte",
"DS4.TalentRank": "Rang",
"DS4.TalentRankBase": "Erworbener Rang",
"DS4.TalentRankMax": "Maximaler Rang",
"DS4.TalentRankMod": "Zusätzlicher Rang",
"DS4.TalentRankTotal": "Gesamter Rang",
"DS4.LanguageLanguages": "Sprachen",
"DS4.LanguageAlphabets": "Schriftzeichen",
"DS4.ProfileGender": "Geschlecht",
"DS4.ProfileBirthday": "Geburtstag",
"DS4.ProfileBirthplace": "Geburtsort",
"DS4.ProfileAge": "Alter",
"DS4.ProfileHeight": "Größe",
"DS4.ProfilHairColor": "Haarfarbe",
"DS4.ProfileWeight": "Gewicht",
"DS4.ProfileEyeColor": "Augenfarbe",
"DS4.ProfileSpecialCharacteristics": "Besondere Eigenschaften",
"DS4.WarningManageActiveEffectOnOwnedItem": "Das Verwalten von aktiven Effekten innerhalb eines besessen Items wird derzeit nicht unterstützt und wird in einem nachfolgenden Update hinzugefügt.",
"DS4.ErrorDiceCritOverlap": "Es gibt eine Überlappung zwischen Patzern und Immersiegen.",
"DS4.ErrorExplodingRecursionLimitExceeded": "Die maximale Rekursionstiefe für slayende Würfelwürfe wurde überschritten.",
"DS4.UnitRounds": "Runden",
"DS4.UnitRoundsAbbr": "Rnd",
"DS4.UnitMinutes": "Minuten",
"DS4.UnitMinutesAbbr": "min",
"DS4.UnitHours": "Stunden",
"DS4.UnitHoursAbbr": "h",
"DS4.UnitDays": "Tage",
"DS4.UnitDaysAbbr": "d",
"DS4.UnitMeters": "Meter",
"DS4.UnitMetersAbbr": "m",
"DS4.UnitKilometers": "Kilometer",
"DS4.UnitKilometersAbbr": "km",
"DS4.UnitCustom": "individuell",
"DS4.UnitCustomAbbr": " "
}

View file

@ -1,12 +1,15 @@
{
"DS4.UserInteractionAddItem": "Add item",
"DS4.UserInteractionEditItem": "Edit item",
"DS4.UserInteractionDeleteItem": "Delete item",
"DS4.NotOwned": "No owner",
"DS4.HeadingDescription": "Description",
"DS4.HeadingBiography": "Biography",
"DS4.HeadingDetails": "Details",
"DS4.HeadingEffects": "Effects",
"DS4.HeadingInventory": "Inventory",
"DS4.HeadingProfile": "Profile",
"DS4.HeadingTalents": "Talents & Abilities",
"DS4.HeadingSpells": "Spells",
"DS4.AttackType": "Attack Type",
"DS4.AttackTypeAbbr": "AT",
"DS4.WeaponBonus": "Weapon Bonus",
@ -16,10 +19,12 @@
"DS4.AttackTypeMelee": "Melee",
"DS4.AttackTypeRanged": "Ranged",
"DS4.AttackTypeMeleeRanged": "Melee / Ranged",
"DS4.Description": "Description",
"DS4.Quantity": "Quantity",
"DS4.PriceGold": "Price (Gold)",
"DS4.StorageLocation": "Stored at",
"DS4.ItemEquipped": "Equipped",
"DS4.ItemEquippedAbbr": "E",
"DS4.ItemOwner": "Owner",
"DS4.ItemAvailability": "Availability",
"DS4.ItemAvailabilityHamlet": "Hamlet",
@ -36,6 +41,8 @@
"DS4.ItemTypeArmorPlural": "Armor",
"DS4.ItemTypeShield": "Shield",
"DS4.ItemTypeShieldPlural": "Shields",
"DS4.ItemTypeSpell": "Spell",
"DS4.ItemTypeSpellPlural": "Spells",
"DS4.ItemTypeTrinket": "Trinket",
"DS4.ItemTypeTrinketPlural": "Trinkets",
"DS4.ItemTypeEquipment": "Equipment",
@ -72,6 +79,27 @@
"DS4.ArmorMaterialTypeChainAbbr": "Chain",
"DS4.ArmorMaterialTypePlate": "Plate",
"DS4.ArmorMaterialTypePlateAbbr": "Plate",
"DS4.SpellType": "Spell Type",
"DS4.SpellTypeAbbr": "T",
"DS4.SpellTypeSpellcasting": "Spellcasting",
"DS4.SpellTypeTargetedSpellcasting": "Targeted Spellcasting",
"DS4.SpellCategory": "Category",
"DS4.SpellCategoryHealing": "Healing",
"DS4.SpellCategoryFire": "Fire",
"DS4.SpellCategoryIce": "Ice",
"DS4.SpellCategoryLight": "Light",
"DS4.SpellCategoryDarkness": "Darkness",
"DS4.SpellCategoryMindAffecting": "Mind Affecting",
"DS4.SpellCategoryElectricity": "Electricity",
"DS4.SpellCategoryNone": "None",
"DS4.SpellCategoryUnset": "Unset",
"DS4.SpellBonus": "Spell Bonus",
"DS4.SpellBonusAbbr": "SB",
"DS4.SpellMaxDistance": "Range",
"DS4.SpellEffectRadius": "Radius",
"DS4.SpellDuration": "Duration",
"DS4.SpellCooldownDuration": "Cooldown",
"DS4.SpellScrollPriceGold": "Scroll Price (Gold)",
"DS4.AttributeBody": "Body",
"DS4.AttributeMobility": "Mobility",
"DS4.AttributeMind": "Mind",
@ -115,6 +143,20 @@
"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.",
"DS4.ErrorDiceCritOverlap": "There's an overlap between Fumbles and Coups",
"DS4.UnitRounds": "Rounds",
"DS4.UnitRoundsAbbr": "rnd",
"DS4.UnitMinutes": "Minutes",
"DS4.UnitMinutesAbbr": "min",
"DS4.UnitHours": "Hours",
"DS4.UnitHoursAbbr": "h",
"DS4.UnitDays": "Days",
"DS4.UnitDaysAbbr": "d",
"DS4.UnitMeters": "Meters",
"DS4.UnitMetersAbbr": "m",
"DS4.UnitKilometers": "Kilometers",
"DS4.UnitKilometersAbbr": "km",
"DS4.UnitCustom": "Custom Unit",
"DS4.UnitCustomAbbr": " ",
"DS4.ErrorExplodingRecursionLimitExceeded": "Maximum recursion depth for exploding dice roll exceeded",
"DS4.RollDialogDefaultTitle": "Roll Options",
"DS4.RollDialogOkButton": "Ok",

View file

@ -30,9 +30,9 @@ export class DS4ActorSheet extends ActorSheet<DS4ActorDataType, DS4Actor, DS4Ite
return mergeObject(super.defaultOptions, {
classes: ["ds4", "sheet", "actor"],
template: "systems/ds4/templates/actor/actor-sheet.hbs",
width: 725,
width: 745,
height: 600,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description" }],
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "inventory" }],
});
}

View file

@ -26,6 +26,14 @@ export const DS4 = {
ranged: "systems/ds4/assets/official/DS4-RAT.png",
},
/**
* Define the file paths to icon images
*/
spellTypesIcons: {
spellcasting: "systems/ds4/assets/official/DS4-SPC.png",
targetedSpellcasting: "systems/ds4/assets/official/DS4-TSC.png",
},
/**
* Define the set of item availabilties
*/
@ -46,6 +54,7 @@ export const DS4 = {
weapon: "DS4.ItemTypeWeapon",
armor: "DS4.ItemTypeArmor",
shield: "DS4.ItemTypeShield",
spell: "DS4.ItemTypeSpell",
trinket: "DS4.ItemTypeTrinket",
equipment: "DS4.ItemTypeEquipment",
talent: "DS4.ItemTypeTalent",
@ -96,6 +105,23 @@ export const DS4 = {
plate: "DS4.ArmorMaterialTypePlateAbbr",
},
spellTypes: {
spellcasting: "DS4.SpellTypeSpellcasting",
targetedSpellcasting: "DS4.SpellTypeTargetedSpellcasting",
},
spellCategories: {
healing: "DS4.SpellCategoryHealing",
fire: "DS4.SpellCategoryFire",
ice: "DS4.SpellCategoryIce",
light: "DS4.SpellCategoryLight",
darkness: "DS4.SpellCategoryDarkness",
mindAffecting: "DS4.SpellCategoryMindAffecting",
electricity: "DS4.SpellCategoryElectricity",
none: "DS4.SpellCategoryNone",
unset: "DS4.SpellCategoryUnset",
},
/**
* Define the set of attributes a character has
*/
@ -189,6 +215,45 @@ export const DS4 = {
specialCharacteristics: "String",
},
/**
* Define translations for available distance units
*/
distanceUnits: {
meter: "DS4.UnitMeters",
kilometer: "DS4.UnitKilometers",
custom: "DS4.UnitCustom",
},
/**
* Define abbreviations for available distance units
*/
distanceUnitsAbbr: {
meter: "DS4.UnitMetersAbbr",
kilometer: "DS4.UnitKilometersAbbr",
custom: "DS4.UnitCustomAbbr",
},
/**
* Define translations for available distance units
*/
temporalUnits: {
rounds: "DS4.UnitRounds",
minutes: "DS4.UnitMinutes",
hours: "DS4.UnitHours",
days: "DS4.UnitDays",
custom: "DS4.UnitCustom",
},
/**
* Define abbreviations for available units
*/
temporalUnitsAbbr: {
rounds: "DS4.UnitRoundsAbbr",
minutes: "DS4.UnitMinutesAbbr",
hours: "DS4.UnitHoursAbbr",
days: "DS4.UnitDaysAbbr",
custom: "DS4.UnitCustomAbbr",
},
/**
* Define localization strings for Chat Visibility
*/

View file

@ -50,6 +50,7 @@ async function registerHandlebarsPartials() {
"systems/ds4/templates/item/partials/body.hbs",
"systems/ds4/templates/actor/partials/items-overview.hbs",
"systems/ds4/templates/actor/partials/talents-overview.hbs",
"systems/ds4/templates/actor/partials/spells-overview.hbs",
"systems/ds4/templates/actor/partials/overview-add-button.hbs",
"systems/ds4/templates/actor/partials/overview-control-buttons.hbs",
"systems/ds4/templates/actor/partials/attributes-traits.hbs",
@ -78,6 +79,8 @@ Hooks.once("setup", function () {
"armorMaterialTypes",
"armorMaterialTypesAbbr",
"armorMaterialTypes",
"spellTypes",
"spellCategories",
"attributes",
"traits",
"combatValues",
@ -85,6 +88,10 @@ Hooks.once("setup", function () {
"progression",
"language",
"profile",
"temporalUnits",
"temporalUnitsAbbr",
"distanceUnits",
"distanceUnitsAbbr",
"chatVisibilities",
];

View file

@ -4,6 +4,7 @@ export type DS4ItemDataType =
| DS4Weapon
| DS4Armor
| DS4Shield
| DS4Spell
| DS4Trinket
| DS4Equipment
| DS4Talent
@ -32,6 +33,26 @@ interface DS4TalentRank extends ModifiableData<number> {
max: number;
}
interface DS4Spell extends DS4ItemBase, DS4ItemEquipable {
spellType: "spellcasting" | "targetedSpellcasting";
bonus: string;
spellCategory:
| "healing"
| "fire"
| "ice"
| "light"
| "darkness"
| "mindAffecting"
| "electricity"
| "none"
| "unset";
maxDistance: UnitData<DistanceUnit>;
effectRadius: UnitData<DistanceUnit>;
duration: UnitData<TemporalUnit>;
cooldownDuration: UnitData<TemporalUnit>;
scrollPrice: number;
}
interface DS4Shield extends DS4ItemBase, DS4ItemPhysical, DS4ItemEquipable, DS4ItemProtective {}
interface DS4Trinket extends DS4ItemBase, DS4ItemPhysical, DS4ItemEquipable {}
interface DS4Equipment extends DS4ItemBase, DS4ItemPhysical {}
@ -62,3 +83,10 @@ interface DS4ItemEquipable {
interface DS4ItemProtective {
armorValue: number;
}
interface UnitData<UnitType> {
value: string;
unit: UnitType;
}
type TemporalUnit = "rounds" | "minutes" | "hours" | "days" | "custom";
type DistanceUnit = "meter" | "kilometer" | "custom";

View file

@ -9,12 +9,13 @@
.side-property {
margin: 2px 0;
display: grid;
grid-template-columns: minmax(30%, auto) auto;
grid-template-columns: 40% auto;
justify-content: left;
label {
line-height: $default-input-height;
font-weight: bold;
padding-right: 3pt;
}
input,
@ -30,6 +31,17 @@
height: 100%;
margin: 0px;
}
.unit-data-pair {
display: flex;
flex-direction: row;
select {
width: 4em;
}
input {
max-width: 7em;
}
}
}
}

View file

@ -6,7 +6,7 @@
"minimumCoreVersion": "0.7.9",
"compatibleCoreVersion": "0.7.9",
"templateVersion": 2,
"author": "Johannes Loher, Gesina Schwalbe, Oliver Rümpelein",
"author": "Johannes Loher, Gesina Schwalbe, Oliver Rümpelein, Siegfried Krug",
"esmodules": ["module/ds4.js"],
"styles": ["ds4.css"],
"scripts": [],
@ -16,13 +16,19 @@
"lang": "en",
"name": "English",
"path": "lang/en.json"
},
{
"lang": "de",
"name": "Deutsch",
"path": "lang/de.json"
}
],
"gridDistance": 1,
"gridUnits": "m",
"primaryTokenAttribute": "combatValues.hitPoints",
"url": "https://git.f3l.de/dungeonslayers/ds4",
"manifest": "https://git.f3l.de/dungeonslayers/ds4/-/raw/master/src/system.json?inline=false",
"manifest": "https://git.f3l.de/dungeonslayers/ds4/-/raw/latest/src/system.json?inline=false",
"download": "https://git.f3l.de/dungeonslayers/ds4/-/jobs/artifacts/0.1.0/download?job=build",
"license": "MIT"
"license": "MIT",
"initiative": "@combatValues.initiative.total"
}

View file

@ -115,6 +115,7 @@
"weapon",
"armor",
"shield",
"spell",
"trinket",
"equipment",
"talent",
@ -175,6 +176,29 @@
},
"alphabet": {
"templates": ["base"]
},
"spell": {
"templates": ["base", "equipable"],
"spellType": "spellcasting",
"bonus": "",
"spellCategory": "unset",
"maxDistance": {
"value": "",
"unit": "meter"
},
"effectRadius": {
"value": "",
"unit": "meter"
},
"duration": {
"value": "",
"unit": "custom"
},
"cooldownDuration": {
"value": "",
"unit": "custom"
},
"scrollPrice": 0
}
}
}

View file

@ -58,26 +58,30 @@
{{!-- Sheet Tab Navigation --}}
<nav class="sheet-tabs tabs" data-group="primary">
<a class="item" data-tab="description">{{localize 'DS4.HeadingDescription'}}</a>
<a class="item" data-tab="inventory">{{localize 'DS4.HeadingInventory'}}</a>
<a class="item" data-tab="spells">{{localize 'DS4.HeadingSpells'}}</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>
<a class="item" data-tab="biography">{{localize 'DS4.HeadingBiography'}}</a>
</nav>
{{!-- Sheet Body --}}
<section class="sheet-body">
{{!-- Biography Tab --}}
<div class="tab biography" data-group="primary" data-tab="description">
{{editor content=data.biography target="data.biography" button=true owner=owner editable=editable}}
</div>
{{!-- Items Tab --}}
{{> systems/ds4/templates/actor/partials/items-overview.hbs}}
{{! Profile Tab --}}
{{> systems/ds4/templates/actor/partials/profile.hbs}}
{{!-- Spells Tab --}}
{{> systems/ds4/templates/actor/partials/spells-overview.hbs}}
{{!-- Talents Tab --}}
{{> systems/ds4/templates/actor/partials/talents-overview.hbs}}
{{!-- Items Tab --}}
{{> systems/ds4/templates/actor/partials/items-overview.hbs}}
{{! Profile Tab --}}
{{> systems/ds4/templates/actor/partials/profile.hbs}}
{{!-- Biography Tab --}}
<div class="tab biography" data-group="primary" data-tab="biography">
{{editor content=data.biography target="data.biography" button=true owner=owner editable=editable}}
</div>
</section>
</form>

View file

@ -37,7 +37,7 @@
<li class="item flexrow item-header">
{{!-- equipped --}}
{{#if (ne dataType 'equipment')}}
<div class="flex05" title="{{localize 'DS4.ItemEquipped'}}">E</div>
<div class="flex05" title="{{localize 'DS4.ItemEquipped'}}">{{localize 'DS4.ItemEquippedAbbr'}}</div>
{{/if}}
{{!-- image --}}
<div class="flex05 item-image"></div>
@ -48,7 +48,7 @@
{{!-- item type specifics --}}
{{> @partial-block }}
{{!-- description --}}
<div class="flex4">{{localize 'DS4.HeadingDescription'}}</div>
<div class="flex4">{{localize 'DS4.Description'}}</div>
{{!-- add button --}}
{{> systems/ds4/templates/actor/partials/overview-add-button.hbs dataType=dataType }}
</li>
@ -78,10 +78,10 @@
</div>
{{!-- amount --}}
<input class="flex05 item-num-val item-change" type="number" min="0" step="1" value="{{item.data.data.quantity}}" data-dtype="Number"
data-property="data.quantity" title="{{localize 'DS4.Quantity'}}">
data-property="data.quantity" title="{{localize 'DS4.Quantity'}}" />
{{!-- name --}}
<input class="flex3 item-name item-change" type="text" value="{{item.name}}" data-dtype="String"
data-property="name" title="{{localize 'DS4.ItemName'}}">
data-property="name" title="{{localize 'DS4.ItemName'}}" />
{{!-- item type specifics --}}
{{> @partial-block}}
{{!-- description --}}

View file

@ -0,0 +1,86 @@
{{!-- ======================================================================== --}}
{{!-- INLINE PARTIAL DEFINITIONS --}}
{{!-- ======================================================================== --}}
{{!--
!-- Two templates for displaying values with unit.
!-- @param unitDatum: the object to display; must have a value and a unit attribute
!-- @param localizationString
!-- @param config: the config object
--}}
{{#*inline "temporalUnit"}}
<div class="unit-data-pair item-num-val"
title="{{localize localizationString}} [{{lookup config.temporalUnits unitDatum.unit}}]" >
{{unitDatum.value}}{{lookup config.temporalUnitsAbbr unitDatum.unit}}
</div>
{{/inline}}
{{#*inline "distanceUnit"}}
<div class="unit-data-pair item-num-val"
title="{{localize localizationString}} [{{lookup config.distanceUnits unitDatum.unit}}]" >
{{unitDatum.value}}{{lookup config.distanceUnitsAbbr unitDatum.unit}}
</div>
{{/inline}}
{{!-- ======================================================================== --}}
<div class="tab items" data-group="primary" data-tab="spells">
<ol class="items-list">
<li class="item flexrow item-header">
{{!-- equipped --}}
<div class="flex05 item-image" title="{{localize 'DS4.ItemEquipped'}}">{{localize 'DS4.ItemEquippedAbbr'}}</div>
{{!-- image --}}
<div class="flex05 item-image"></div>
{{!-- name --}}
<div class="flex2 item-name">{{localize 'DS4.ItemName'}}</div>
{{!-- spell type --}}
<div class="item-image" title="{{localize 'DS4.SpellType'}}">{{localize 'DS4.SpellTypeAbbr'}}</div>
{{!-- spell bonus --}}
<div class="item-num-val" title="{{localize 'DS4.SpellBonus'}}">{{localize 'DS4.SpellBonusAbbr'}}</div>
{{!-- max. distance --}}
<div class="item-num-val" title="{{localize 'DS4.SpellMaxDistance'}}"><i class="fas fa-ruler"></i></div>
{{!-- duration --}}
<div class="item-num-val" title="{{localize 'DS4.SpellDuration'}}"><i class="far fa-clock"></i></div>
{{!-- cooldown duration --}}
<div class="item-num-val" title="{{localize 'DS4.SpellCooldownDuration'}}"><i class="fas fa-hourglass-half"></i></div>
{{!-- description --}}
{{!-- <div class="flex3">{{localize 'DS4.Description'}}</div> --}}
{{!-- add button --}}
{{> systems/ds4/templates/actor/partials/overview-add-button.hbs dataType='spell' }}
</li>
{{#each itemsByType.spell as |item id|}}
<li class="item flexrow" data-item-id="{{item._id}}">
<input class="flex05 item-image item-change" type="checkbox" {{checked item.data.data.equipped}} data-dtype="Boolean"
data-property="data.equipped" title="{{localize 'DS4.ItemEquipped'}}">
{{!-- 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'}}" />
{{!-- spell type --}}
<div class="flex05 item-image">
<img src="{{lookup ../config.spellTypesIcons item.data.data.spellType}}"
title="{{lookup ../config.spellTypes item.data.data.spellType}}" width="24" height="24" />
</div>
{{!-- spell bonus --}}
<input class="item-num-val item-change" type="text" data-dtype="String"
data-property="data.bonus" value="{{item.data.data.bonus}}" title="{{localize 'DS4.SpellBonus'}}" />
{{!-- max. distance --}}
{{> distanceUnit localizationString='DS4.SpellMaxDistance' unitDatum=item.data.data.maxDistance config=../config}}
{{!-- duration --}}
{{> temporalUnit localizationString='DS4.SpellDuration' unitDatum=item.data.data.duration config=../config}}
{{!-- cooldown duration --}}
{{> temporalUnit localizationString='DS4.SpellCooldownDuration' unitDatum=item.data.data.cooldownDuration config=../config}}
{{!-- description --}}
{{!-- <div class="flex3 item-description">{{{item.data.data.description}}}</div> --}}
{{!-- control buttons --}}
{{> systems/ds4/templates/actor/partials/overview-control-buttons.hbs }}
</li>
{{/each}}
</ol>
</div>

View file

@ -1,8 +1,6 @@
{{!-- ======================================================================== --}}
{{!-- INLINE PARTIAL DEFINITIONS --}}
{{!-- ======================================================================== --}}
{{!-- TODO: remove duplicate add and delete button definition --}}
{{!--
@ -110,7 +108,7 @@
{{!-- name --}}
<div class="flex1 item-name">{{localize 'DS4.ItemName'}}</div>
{{!-- description --}}
<div class="flex3">{{localize 'DS4.HeadingDescription'}}</div>
<div class="flex3">{{localize 'DS4.Description'}}</div>
{{!-- add button --}}
{{> systems/ds4/templates/actor/partials/overview-add-button.hbs dataType=dataType }}
</li>
@ -132,7 +130,7 @@
{{!-- rank info --}}
<div class="flex3">{{localize 'DS4.TalentRank'}}</div>
{{!-- description --}}
<div class="flex4">{{localize 'DS4.HeadingDescription'}}</div>
<div class="flex4">{{localize 'DS4.Description'}}</div>
{{!-- add button --}}
{{> systems/ds4/templates/actor/partials/overview-add-button.hbs dataType='talent' }}
</li>

View file

@ -3,6 +3,6 @@
{{/systems/ds4/templates/item/partials/sheet-header.hbs}}
{{!-- Common Item body --}}
{{> systems/ds4/templates/item/partials/body.hbs}}
{{#> systems/ds4/templates/item/partials/body.hbs}}{{/systems/ds4/templates/item/partials/body.hbs}}
</form>

View file

@ -12,7 +12,7 @@
</select>
</div>
<div class="basic-property">
<label>{{localize "DS4.ArmorMaterialType"}}</label>
<label for="data.armorMaterialType">{{localize "DS4.ArmorMaterialType"}}</label>
<select name="data.armorMaterialType" data-type="String">
{{#select data.armorMaterialType}}
{{#each config.armorMaterialTypes as |value key|}}
@ -30,5 +30,5 @@
{{/systems/ds4/templates/item/partials/sheet-header.hbs}}
{{!-- Common Item body --}}
{{> systems/ds4/templates/item/partials/body.hbs}}
{{#> systems/ds4/templates/item/partials/body.hbs}}{{/systems/ds4/templates/item/partials/body.hbs}}
</form>

View file

@ -3,5 +3,5 @@
{{/systems/ds4/templates/item/partials/sheet-header.hbs}}
{{!-- Common Item body --}}
{{> systems/ds4/templates/item/partials/body.hbs}}
{{#> systems/ds4/templates/item/partials/body.hbs}}{{/systems/ds4/templates/item/partials/body.hbs}}
</form>

View file

@ -3,6 +3,6 @@
{{/systems/ds4/templates/item/partials/sheet-header.hbs}}
{{!-- Common Item body --}}
{{> systems/ds4/templates/item/partials/body.hbs}}
{{#> systems/ds4/templates/item/partials/body.hbs}}{{/systems/ds4/templates/item/partials/body.hbs}}
</form>

View file

@ -2,7 +2,7 @@
{{!-- Sheet Tab Navigation --}}
<nav class="sheet-tabs tabs" data-group="primary">
<a class="item" data-tab="description">{{localize "DS4.HeadingDescription"}}</a>
<a class="item" data-tab="description">{{localize "DS4.Description"}}</a>
<a class="item" data-tab="effects">{{localize "DS4.HeadingEffects"}}</a>
{{#if isPhysical}}
<a class="item" data-tab="details">{{localize "DS4.HeadingDetails"}}</a>
@ -13,7 +13,9 @@
<section class="sheet-body">
{{!-- Description Tab --}}
{{> systems/ds4/templates/item/partials/description.hbs}}
{{#> systems/ds4/templates/item/partials/description.hbs}}
{{> @partial-block}}
{{/systems/ds4/templates/item/partials/description.hbs}}
{{!-- Effects Tab --}}
{{> systems/ds4/templates/item/partials/effects.hbs}}

View file

@ -1,3 +1,8 @@
{{!--
Render a description tab.
Additional elements of the side-properties div can be handed over via the @partial-block.
--}}
<div class="tab flexrow" data-group="primary" data-tab="description">
<div class="side-properties">
{{#if isOwned}}
@ -24,8 +29,9 @@
{{else}}
<span>{{localize "DS4.NotOwned"}}</span>
{{/if}}
{{> @partial-block}}
</div>
<div class="description" title="{{localize 'DS4.HeadingDescription'}}">
<div class="description" title="{{localize 'DS4.Description'}}">
{{editor content=data.description target="data.description" button=true owner=owner editable=editable}}
</div>
</div>

View file

@ -3,18 +3,19 @@
{{!-- As you add new fields, add them in here! --}}
<div class="side-properties">
<div class="side-property">
<label for="data.price">{{localize "DS4.PriceGold"}}</label>
<input type="number" min="0" data-dtype="Number" name="data.price" value="{{data.price}}" />
</div>
<div class="side-property">
<label for="data.availability">{{localize "DS4.ItemAvailability"}}</label>
<select name="data.availability" data-type="String">
{{#select data.availability}}
{{#each config.itemAvailabilities as |value key|}}
<option value="{{key}}">{{value}}</option>
{{/each}}
{{/select}}
</select>
</div>
<label for="data.price">{{localize "DS4.PriceGold"}}</label>
<input type="number" min="0" max="99999" step="0.01" data-dtype="Number"
name="data.price" value="{{data.price}}" />
</div>
<div class="side-property">
<label for="data.availability">{{localize "DS4.ItemAvailability"}}</label>
<select name="data.availability" data-type="String">
{{#select data.availability}}
{{#each config.itemAvailabilities as |value key|}}
<option value="{{key}}">{{value}}</option>
{{/each}}
{{/select}}
</select>
</div>
</div>
</div>

View file

@ -3,6 +3,6 @@
{{/systems/ds4/templates/item/partials/sheet-header.hbs}}
{{!-- Common Item body --}}
{{> systems/ds4/templates/item/partials/body.hbs}}
{{#> systems/ds4/templates/item/partials/body.hbs}}{{/systems/ds4/templates/item/partials/body.hbs}}
</form>

View file

@ -10,5 +10,5 @@
{{/systems/ds4/templates/item/partials/sheet-header.hbs}}
{{!-- Common Item body --}}
{{> systems/ds4/templates/item/partials/body.hbs}}
{{#> systems/ds4/templates/item/partials/body.hbs}}{{/systems/ds4/templates/item/partials/body.hbs}}
</form>

View file

@ -0,0 +1,72 @@
{{!-- ======================================================================== --}}
{{!-- INLINE PARTIAL DEFINITIONS --}}
{{!-- ======================================================================== --}}
{{#*inline "unitDatum" }}
<div class="side-property">
<label>{{localize localizeString}}</label>
<div class="unit-data-pair">
<input class="item-num-val" type="text" data-dtype="String"
name="data.{{property}}.value" value="{{lookup (lookup data property) 'value'}}" />
<select name="data.{{property}}.unit" data-type="String">
{{#select (lookup (lookup data property) 'unit')}}
{{#if (eq unitType 'temporal')}}
{{#each (lookup config 'temporalUnitsAbbr') as |value key|}}<option value="{{key}}">{{value}}</option>{{/each}}
{{else}}
{{#each (lookup config 'distanceUnitsAbbr') as |value key|}}<option value="{{key}}">{{value}}</option>{{/each}}
{{/if}}
{{/select}}
</select>
</div>
</div>
{{/inline}}
{{!-- ======================================================================== --}}
<form class="{{cssClass}}" autocomplete="off">
{{#> systems/ds4/templates/item/partials/sheet-header.hbs}}
<div class="grid grid-4col basic-properties">
<div class="basic-property">
<label for="data.spellType">{{localize "DS4.SpellType"}}</label>
<select name="data.spellType" data-type="String">
{{#select data.spellType}}
{{#each config.spellTypes as |value key|}}
<option value="{{key}}">{{value}}</option>
{{/each}}
{{/select}}
</select>
</div>
<div class="basic-property">
<label for="data.bonus">{{localize "DS4.SpellBonus"}}</label>
<input type="text" name="data.bonus" value="{{data.bonus}}" data-dtype="String" />
</div>
</div>
{{/systems/ds4/templates/item/partials/sheet-header.hbs}}
{{!-- Common Item body --}}
{{#> systems/ds4/templates/item/partials/body.hbs}}
<div class="side-property">
<label for="data.spellCategory">{{localize "DS4.SpellCategory"}}</label>
<select name="data.spellCategory" data-type="String">
{{#select data.spellCategory}}
{{#each config.spellCategories as |value key|}}
<option value="{{key}}">{{value}}</option>
{{/each}}
{{/select}}
</select>
</div>
{{> unitDatum data=data property='maxDistance' localizeString='DS4.SpellMaxDistance' unitType='distance' }}
{{> unitDatum data=data property='effectRadius' localizeString='DS4.SpellEffectRadius' unitType='distance' }}
{{> unitDatum data=data property='duration' localizeString='DS4.SpellDuration' unitType='temporal' }}
{{> unitDatum data=data property='cooldownDuration' localizeString='DS4.SpellCooldownDuration' unitType='temporal' }}
<div class="side-property">
<label for="data.scrollPrice">{{localize "DS4.SpellScrollPriceGold"}}</label>
<input type="number" min="0" max="9999" step="0.01" data-dtype="Number"
name="data.scrollPrice" value="{{data.scrollPrice}}" />
</div>
{{/systems/ds4/templates/item/partials/body.hbs}}
</form>

View file

@ -27,6 +27,6 @@
{{/systems/ds4/templates/item/partials/sheet-header.hbs}}
{{!-- Common Item body --}}
{{> systems/ds4/templates/item/partials/body.hbs}}
{{#> systems/ds4/templates/item/partials/body.hbs}}{{/systems/ds4/templates/item/partials/body.hbs}}
</form>

View file

@ -3,5 +3,5 @@
{{/systems/ds4/templates/item/partials/sheet-header.hbs}}
{{!-- Common Item body --}}
{{> systems/ds4/templates/item/partials/body.hbs}}
{{#> systems/ds4/templates/item/partials/body.hbs}}{{/systems/ds4/templates/item/partials/body.hbs}}
</form>

View file

@ -25,5 +25,5 @@
{{/systems/ds4/templates/item/partials/sheet-header.hbs}}
{{!-- Common Item body --}}
{{> systems/ds4/templates/item/partials/body.hbs}}
{{#> systems/ds4/templates/item/partials/body.hbs}}{{/systems/ds4/templates/item/partials/body.hbs}}
</form>