diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 18f8791f..784d4db6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -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 diff --git a/LICENSE b/LICENSE index 4ea46065..5c296ab7 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright 2020 Johannes Loher, Gesina Schwalbe, Oliver Rümpelein +Copyright 2020 Johannes Loher, Gesina Schwalbe, Oliver Rümpelein, Siegfried Krug Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/gulpfile.js b/gulpfile.js index dc62e8b7..1cf31998 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -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; diff --git a/package-lock.json b/package-lock.json index efb9982b..c6f8a114 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/package.json b/package.json index 9ebc7bd8..06841a62 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/spec/support/localization/localization.spec.ts b/spec/support/localization/localization.spec.ts new file mode 100644 index 00000000..b289819c --- /dev/null +++ b/spec/support/localization/localization.spec.ts @@ -0,0 +1,15 @@ +import "jasmine"; +import * as fs from "fs-extra"; +import * as path from "path"; + +describe("English and german localization files", () => { + const localizationPath = "./src/lang/"; + const en: Record = fs.readJSONSync(path.join(localizationPath, "en.json")); + const de: Record = fs.readJSONSync(path.join(localizationPath, "de.json")); + + it("should have the same keys.", () => { + const deKeys = Object.keys(de); + const enKeys = Object.keys(en); + expect(deKeys).toEqual(enKeys); + }); +}); diff --git a/src/lang/de.json b/src/lang/de.json new file mode 100644 index 00000000..5c675015 --- /dev/null +++ b/src/lang/de.json @@ -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": " " +} diff --git a/src/lang/en.json b/src/lang/en.json index 4e90df36..0d4674b1 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -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", diff --git a/src/module/actor/actor-sheet.ts b/src/module/actor/actor-sheet.ts index 51eb9e65..ca14fd0d 100644 --- a/src/module/actor/actor-sheet.ts +++ b/src/module/actor/actor-sheet.ts @@ -30,9 +30,9 @@ export class DS4ActorSheet extends ActorSheet { max: number; } +interface DS4Spell extends DS4ItemBase, DS4ItemEquipable { + spellType: "spellcasting" | "targetedSpellcasting"; + bonus: string; + spellCategory: + | "healing" + | "fire" + | "ice" + | "light" + | "darkness" + | "mindAffecting" + | "electricity" + | "none" + | "unset"; + maxDistance: UnitData; + effectRadius: UnitData; + duration: UnitData; + cooldownDuration: UnitData; + scrollPrice: number; +} + interface DS4Shield extends DS4ItemBase, DS4ItemPhysical, DS4ItemEquipable, DS4ItemProtective {} interface DS4Trinket extends DS4ItemBase, DS4ItemPhysical, DS4ItemEquipable {} interface DS4Equipment extends DS4ItemBase, DS4ItemPhysical {} @@ -62,3 +83,10 @@ interface DS4ItemEquipable { interface DS4ItemProtective { armorValue: number; } + +interface UnitData { + value: string; + unit: UnitType; +} +type TemporalUnit = "rounds" | "minutes" | "hours" | "days" | "custom"; +type DistanceUnit = "meter" | "kilometer" | "custom"; diff --git a/src/scss/components/_description.scss b/src/scss/components/_description.scss index cc4c1322..767fb516 100644 --- a/src/scss/components/_description.scss +++ b/src/scss/components/_description.scss @@ -9,12 +9,13 @@ .side-property { margin: 2px 0; display: grid; - grid-template-columns: minmax(30%, auto) auto; + grid-template-columns: 40% auto; justify-content: left; label { line-height: $default-input-height; font-weight: bold; + padding-right: 3pt; } input, @@ -30,6 +31,17 @@ height: 100%; margin: 0px; } + + .unit-data-pair { + display: flex; + flex-direction: row; + select { + width: 4em; + } + input { + max-width: 7em; + } + } } } diff --git a/src/system.json b/src/system.json index a64a1a8c..6c742c7a 100644 --- a/src/system.json +++ b/src/system.json @@ -6,7 +6,7 @@ "minimumCoreVersion": "0.7.9", "compatibleCoreVersion": "0.7.9", "templateVersion": 2, - "author": "Johannes Loher, Gesina Schwalbe, Oliver Rümpelein", + "author": "Johannes Loher, Gesina Schwalbe, Oliver Rümpelein, Siegfried Krug", "esmodules": ["module/ds4.js"], "styles": ["ds4.css"], "scripts": [], @@ -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" } diff --git a/src/template.json b/src/template.json index eee8acee..0d723909 100644 --- a/src/template.json +++ b/src/template.json @@ -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 } } } diff --git a/src/templates/actor/actor-sheet.hbs b/src/templates/actor/actor-sheet.hbs index 8e3e5f54..6763e440 100644 --- a/src/templates/actor/actor-sheet.hbs +++ b/src/templates/actor/actor-sheet.hbs @@ -58,26 +58,30 @@ {{!-- Sheet Tab Navigation --}} {{!-- Sheet Body --}}
- {{!-- Biography Tab --}} -
- {{editor content=data.biography target="data.biography" button=true owner=owner editable=editable}} -
+ {{!-- Items Tab --}} + {{> systems/ds4/templates/actor/partials/items-overview.hbs}} - {{! 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 --}} +
+ {{editor content=data.biography target="data.biography" button=true owner=owner editable=editable}} +
\ No newline at end of file diff --git a/src/templates/actor/partials/items-overview.hbs b/src/templates/actor/partials/items-overview.hbs index 676a9bfc..4dbd269b 100644 --- a/src/templates/actor/partials/items-overview.hbs +++ b/src/templates/actor/partials/items-overview.hbs @@ -37,7 +37,7 @@
  • {{!-- equipped --}} {{#if (ne dataType 'equipment')}} -
    E
    +
    {{localize 'DS4.ItemEquippedAbbr'}}
    {{/if}} {{!-- image --}}
    @@ -48,7 +48,7 @@ {{!-- item type specifics --}} {{> @partial-block }} {{!-- description --}} -
    {{localize 'DS4.HeadingDescription'}}
    +
    {{localize 'DS4.Description'}}
    {{!-- add button --}} {{> systems/ds4/templates/actor/partials/overview-add-button.hbs dataType=dataType }}
  • @@ -78,10 +78,10 @@ {{!-- amount --}} + data-property="data.quantity" title="{{localize 'DS4.Quantity'}}" /> {{!-- name --}} + data-property="name" title="{{localize 'DS4.ItemName'}}" /> {{!-- item type specifics --}} {{> @partial-block}} {{!-- description --}} diff --git a/src/templates/actor/partials/spells-overview.hbs b/src/templates/actor/partials/spells-overview.hbs new file mode 100644 index 00000000..5338955c --- /dev/null +++ b/src/templates/actor/partials/spells-overview.hbs @@ -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"}} +
    + {{unitDatum.value}}{{lookup config.temporalUnitsAbbr unitDatum.unit}} +
    +{{/inline}} + +{{#*inline "distanceUnit"}} +
    + {{unitDatum.value}}{{lookup config.distanceUnitsAbbr unitDatum.unit}} +
    +{{/inline}} + + +{{!-- ======================================================================== --}} + + +
    +
      +
    1. + {{!-- equipped --}} +
      {{localize 'DS4.ItemEquippedAbbr'}}
      + {{!-- image --}} +
      + {{!-- name --}} +
      {{localize 'DS4.ItemName'}}
      + {{!-- spell type --}} +
      {{localize 'DS4.SpellTypeAbbr'}}
      + {{!-- spell bonus --}} +
      {{localize 'DS4.SpellBonusAbbr'}}
      + {{!-- max. distance --}} +
      + {{!-- duration --}} +
      + {{!-- cooldown duration --}} +
      + {{!-- description --}} + {{!--
      {{localize 'DS4.Description'}}
      --}} + {{!-- add button --}} + {{> systems/ds4/templates/actor/partials/overview-add-button.hbs dataType='spell' }} +
    2. + {{#each itemsByType.spell as |item id|}} +
    3. + + {{!-- image --}} +
      + +
      + {{!-- name --}} + + {{!-- spell type --}} +
      + +
      + {{!-- spell bonus --}} + + {{!-- max. distance --}} + {{> distanceUnit localizationString='DS4.SpellMaxDistance' unitDatum=item.data.data.maxDistance config=../config}} + {{!-- duration --}} + {{> temporalUnit localizationString='DS4.SpellDuration' unitDatum=item.data.data.duration config=../config}} + {{!-- cooldown duration --}} + {{> temporalUnit localizationString='DS4.SpellCooldownDuration' unitDatum=item.data.data.cooldownDuration config=../config}} + {{!-- description --}} + {{!--
      {{{item.data.data.description}}}
      --}} + {{!-- control buttons --}} + {{> systems/ds4/templates/actor/partials/overview-control-buttons.hbs }} +
    4. + {{/each}} +
    +
    \ No newline at end of file diff --git a/src/templates/actor/partials/talents-overview.hbs b/src/templates/actor/partials/talents-overview.hbs index f4a06005..8ef93113 100644 --- a/src/templates/actor/partials/talents-overview.hbs +++ b/src/templates/actor/partials/talents-overview.hbs @@ -1,8 +1,6 @@ {{!-- ======================================================================== --}} {{!-- INLINE PARTIAL DEFINITIONS --}} {{!-- ======================================================================== --}} -{{!-- TODO: remove duplicate add and delete button definition --}} - {{!-- @@ -110,7 +108,7 @@ {{!-- name --}}
    {{localize 'DS4.ItemName'}}
    {{!-- description --}} -
    {{localize 'DS4.HeadingDescription'}}
    +
    {{localize 'DS4.Description'}}
    {{!-- add button --}} {{> systems/ds4/templates/actor/partials/overview-add-button.hbs dataType=dataType }} @@ -132,7 +130,7 @@ {{!-- rank info --}}
    {{localize 'DS4.TalentRank'}}
    {{!-- description --}} -
    {{localize 'DS4.HeadingDescription'}}
    +
    {{localize 'DS4.Description'}}
    {{!-- add button --}} {{> systems/ds4/templates/actor/partials/overview-add-button.hbs dataType='talent' }} diff --git a/src/templates/item/alphabet-sheet.hbs b/src/templates/item/alphabet-sheet.hbs index cfd63f9e..5aabb9aa 100644 --- a/src/templates/item/alphabet-sheet.hbs +++ b/src/templates/item/alphabet-sheet.hbs @@ -3,6 +3,6 @@ {{/systems/ds4/templates/item/partials/sheet-header.hbs}} {{!-- Common Item body --}} - {{> systems/ds4/templates/item/partials/body.hbs}} + {{#> systems/ds4/templates/item/partials/body.hbs}}{{/systems/ds4/templates/item/partials/body.hbs}} \ No newline at end of file diff --git a/src/templates/item/armor-sheet.hbs b/src/templates/item/armor-sheet.hbs index 1a2a14bf..5fd59feb 100644 --- a/src/templates/item/armor-sheet.hbs +++ b/src/templates/item/armor-sheet.hbs @@ -12,7 +12,7 @@
    - + -
    -
    - - -
    + + +
    + + +
    + \ No newline at end of file diff --git a/src/templates/item/racialAbility-sheet.hbs b/src/templates/item/racialAbility-sheet.hbs index 40771481..e69b5fc5 100644 --- a/src/templates/item/racialAbility-sheet.hbs +++ b/src/templates/item/racialAbility-sheet.hbs @@ -3,6 +3,6 @@ {{/systems/ds4/templates/item/partials/sheet-header.hbs}} {{!-- Common Item body --}} - {{> systems/ds4/templates/item/partials/body.hbs}} + {{#> systems/ds4/templates/item/partials/body.hbs}}{{/systems/ds4/templates/item/partials/body.hbs}} diff --git a/src/templates/item/shield-sheet.hbs b/src/templates/item/shield-sheet.hbs index 1c1092c3..4ef9c9f9 100644 --- a/src/templates/item/shield-sheet.hbs +++ b/src/templates/item/shield-sheet.hbs @@ -10,5 +10,5 @@ {{/systems/ds4/templates/item/partials/sheet-header.hbs}} {{!-- Common Item body --}} - {{> systems/ds4/templates/item/partials/body.hbs}} + {{#> systems/ds4/templates/item/partials/body.hbs}}{{/systems/ds4/templates/item/partials/body.hbs}} \ No newline at end of file diff --git a/src/templates/item/spell-sheet.hbs b/src/templates/item/spell-sheet.hbs new file mode 100644 index 00000000..5f2c7a28 --- /dev/null +++ b/src/templates/item/spell-sheet.hbs @@ -0,0 +1,72 @@ +{{!-- ======================================================================== --}} +{{!-- INLINE PARTIAL DEFINITIONS --}} +{{!-- ======================================================================== --}} + + +{{#*inline "unitDatum" }} +
    + +
    + + +
    +
    +{{/inline}} + + +{{!-- ======================================================================== --}} + + +
    + {{#> systems/ds4/templates/item/partials/sheet-header.hbs}} +
    +
    + + +
    +
    + + +
    +
    + {{/systems/ds4/templates/item/partials/sheet-header.hbs}} + + {{!-- Common Item body --}} + {{#> systems/ds4/templates/item/partials/body.hbs}} +
    + + +
    + {{> unitDatum data=data property='maxDistance' localizeString='DS4.SpellMaxDistance' unitType='distance' }} + {{> unitDatum data=data property='effectRadius' localizeString='DS4.SpellEffectRadius' unitType='distance' }} + {{> unitDatum data=data property='duration' localizeString='DS4.SpellDuration' unitType='temporal' }} + {{> unitDatum data=data property='cooldownDuration' localizeString='DS4.SpellCooldownDuration' unitType='temporal' }} +
    + + +
    + {{/systems/ds4/templates/item/partials/body.hbs}} + +
    diff --git a/src/templates/item/talent-sheet.hbs b/src/templates/item/talent-sheet.hbs index 1611beea..22257d81 100644 --- a/src/templates/item/talent-sheet.hbs +++ b/src/templates/item/talent-sheet.hbs @@ -27,6 +27,6 @@ {{/systems/ds4/templates/item/partials/sheet-header.hbs}} {{!-- Common Item body --}} - {{> systems/ds4/templates/item/partials/body.hbs}} + {{#> systems/ds4/templates/item/partials/body.hbs}}{{/systems/ds4/templates/item/partials/body.hbs}} diff --git a/src/templates/item/trinket-sheet.hbs b/src/templates/item/trinket-sheet.hbs index 3fa5d4a9..bbd66400 100644 --- a/src/templates/item/trinket-sheet.hbs +++ b/src/templates/item/trinket-sheet.hbs @@ -3,5 +3,5 @@ {{/systems/ds4/templates/item/partials/sheet-header.hbs}} {{!-- Common Item body --}} - {{> systems/ds4/templates/item/partials/body.hbs}} + {{#> systems/ds4/templates/item/partials/body.hbs}}{{/systems/ds4/templates/item/partials/body.hbs}} \ No newline at end of file diff --git a/src/templates/item/weapon-sheet.hbs b/src/templates/item/weapon-sheet.hbs index 69145376..b92bf97f 100644 --- a/src/templates/item/weapon-sheet.hbs +++ b/src/templates/item/weapon-sheet.hbs @@ -25,5 +25,5 @@ {{/systems/ds4/templates/item/partials/sheet-header.hbs}} {{!-- Common Item body --}} - {{> systems/ds4/templates/item/partials/body.hbs}} + {{#> systems/ds4/templates/item/partials/body.hbs}}{{/systems/ds4/templates/item/partials/body.hbs}} \ No newline at end of file