Merge remote-tracking branch 'origin/master' into 008-chatRollInterface

This commit is contained in:
Oliver Rümpelein 2021-01-08 18:32:36 +01:00
commit c89278992f
43 changed files with 1137 additions and 640 deletions

View file

@ -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/

View 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.

View file

@ -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.

View file

@ -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).

View file

@ -87,7 +87,7 @@ function createTransformer() {
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`);
@ -96,7 +96,7 @@ function createTransformer() {
node.decorators, node.decorators,
node.modifiers, node.modifiers,
node.exportClause, node.exportClause,
newModuleSpecifier newModuleSpecifier,
); );
} }
} }
@ -190,7 +190,7 @@ async function clean() {
`${name}.js`, `${name}.js`,
"module.json", "module.json",
"system.json", "system.json",
"template.json" "template.json",
); );
} }
@ -405,7 +405,7 @@ function gitCommit() {
git.commit(`v${getManifest().file.version}`, { git.commit(`v${getManifest().file.version}`, {
args: "-a", args: "-a",
disableAppendPaths: true, disableAppendPaths: true,
}) }),
); );
} }

View file

@ -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";
} }

View file

@ -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."
} }

View file

@ -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;
}

View file

@ -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;
} }
} }

View file

@ -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",
},
}; };

View file

@ -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

View file

@ -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;
} }

View file

@ -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 = {

View file

@ -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;
}
}
} }

View file

@ -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;
} }
} }
} }

View file

@ -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;
} }
} }

View 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;
}
}
}

View file

@ -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%;
} }

View file

@ -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;

View file

@ -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%;

View file

@ -0,0 +1,3 @@
.talent-ranks-equation {
text-align: center;
}

View file

@ -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;
} }

View file

@ -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 {

View file

@ -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 {

View file

@ -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%);

View file

@ -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;
}
}

View file

@ -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"
} }

View file

@ -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"]
} }
} }
} }

View file

@ -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>
{{> systems/ds4/templates/actor/partials/character-progression.hbs}}
<div class="flexrow basic-properties">
<div class="basic-property">
<label class="basic-property-label" for="data.baseInfo.race">{{config.baseInfo.race}}</label>
<input type="text" name="data.baseInfo.race" value="{{data.baseInfo.race}}" data-dtype="String" />
</div> </div>
<div class="character-values"> <div class="basic-property">
{{!-- The grid classes are defined in scss/global/_grid.scss. To use, use both the "grid" and "grid-Ncol" <label class="basic-property-label" for="data.baseInfo.culture">{{config.baseInfo.culture}}</label>
class where "N" can be any number from 1 to 12 and will create that number of columns. --}} <input type="text" name="data.baseInfo.culture" value="{{data.baseInfo.culture}}"
<div class="base-infos grid grid-3col">
{{!-- "flex-group-center" is also defined in the _grid.scss file and it will add a small amount of
padding, a border, and will center all of its child elements content and text. --}}
<div class="base-info flex-group-center">
<label for="data.baseInfo.race" class="base-info-label">{{config.baseInfo.race}}</label>
<div class="base-info-content flexrow flex-center flex-between">
<input type="text" name="data.baseInfo.race" value="{{data.baseInfo.race}}"
data-dtype="String" /> data-dtype="String" />
</div> </div>
</div> <div class="basic-property flex125">
<div class="base-info flex-group-center"> <label class="basic-property-label"
<div class="grid grid-3col"> for="data.progression.progressPoints.used">{{config.progression.progressPoints}}</label>
<div class="base-info flex-group-center"> <div class="flexrow">
<label for="data.progression.level" <input type="number" name="data.progression.progressPoints.used"
class="base-info-label">{{config.progression.level}}</label> value="{{data.progression.progressPoints.used}}" data-dtype="Number" /><span
<div class="base-info-content flexrow flex-center flex-between"> class="input-divider"> /
<input type="text" name="data.progression.level" value="{{data.progression.level}}" </span><input type="number" name="data.progression.progressPoints.total"
data-dtype="Number" />
</div>
</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" /> value="{{data.progression.progressPoints.total}}" data-dtype="Number" />
</div> </div>
</div> </div>
<div class="base-info flex-group-center"> <div class="basic-property flex125">
<label for="data.progression.talentPoints" <label class="basic-property-label"
class="base-info-label">{{config.progression.talentPoints}}</label> for="data.progression.talentPoints.used">{{config.progression.talentPoints}}</label>
<div class="base-info-content flexrow flex-center flex-between"> <div class="flexrow">
<input type="text" name="data.progression.talentPoints.used" <input type="number" name="data.progression.talentPoints.used"
value="{{data.progression.talentPoints.used}}" data-dtype="Number" /><span> / value="{{data.progression.talentPoints.used}}" data-dtype="Number" /><span
</span><input type="text" name="data.progression.talentPoints.total" class="input-divider"> /
</span><input type="number" name="data.progression.talentPoints.total"
value="{{data.progression.talentPoints.total}}" data-dtype="Number" /> value="{{data.progression.talentPoints.total}}" data-dtype="Number" />
</div> </div>
</div> </div>
<div class="basic-property">
<label class="basic-property-label" for="data.baseInfo.class">{{config.baseInfo.class}}</label>
<input type="text" name="data.baseInfo.class" value="{{data.baseInfo.class}}" data-dtype="String" />
</div> </div>
</div> <div class="basic-property">
<div class="base-info flex-group-center"> <label class="basic-property-label"
<label for="data.baseInfo.class" class="base-info-label">{{config.baseInfo.class}}</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.class" value="{{data.baseInfo.class}}"
data-dtype="String" />
</div>
</div>
<div class="base-info flex-group-center">
<label for="data.baseInfo.racialAbilities"
class="base-info-label">{{config.baseInfo.racialAbilities}}</label>
<div class="base-info-content flexrow flex-center flex-between">
<input type="text" name="data.baseInfo.racialAbilities"
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}}" <input type="text" name="data.baseInfo.heroClass" value="{{data.baseInfo.heroClass}}"
data-dtype="String" /> 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>

View 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>

View file

@ -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>

View 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>

View file

@ -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>

View 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>

View 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>

View file

@ -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>

View file

@ -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>

View file

@ -11,6 +11,7 @@
<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>
{{#if isPhysical}}
<div class="side-property"> <div class="side-property">
<label for="data.quantity">{{localize 'DS4.Quantity'}}</label> <label for="data.quantity">{{localize 'DS4.Quantity'}}</label>
<input type="number" min="0" step="1" data-dtype="Number" name="data.quantity" value="{{data.quantity}}" /> <input type="number" min="0" step="1" data-dtype="Number" name="data.quantity" value="{{data.quantity}}" />
@ -19,11 +20,12 @@
<label for="data.storageLocation">{{localize 'DS4.StorageLocation'}}</label> <label for="data.storageLocation">{{localize 'DS4.StorageLocation'}}</label>
<input type="text" data-dtype="String" name="data.storageLocation" value="{{data.storageLocation}}" /> <input type="text" data-dtype="String" name="data.storageLocation" value="{{data.storageLocation}}" />
</div> </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>

View file

@ -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}}

View 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>

View file

@ -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>

View 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>

View file

@ -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>