mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-04-21 15:03:37 +02:00
Compare commits
28 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3cbc18f42b | ||
|
|
f850cbda76 | ||
|
|
f2ec5ef458 | ||
|
|
c683bc4352 | ||
|
|
fa04c9920f | ||
|
|
03110377e1 | ||
|
|
1fea8438ba | ||
|
|
4944722139 | ||
|
|
4b92001f97 | ||
|
|
2fde61a1d5 | ||
|
|
d9b322406d | ||
|
|
16c07d23bb | ||
|
|
91aff8b10d | ||
|
|
7e9385bc39 | ||
|
|
aa8771bf0d | ||
|
|
7d5cdeb09d | ||
|
|
8808e4646d | ||
|
|
a77d2088a0 | ||
|
|
c6335980ba | ||
|
|
1176328f62 | ||
| a62d28cd96 | |||
|
|
8d8dea81fe | ||
|
|
fb07938e54 | ||
|
|
c337338c8b | ||
|
|
f900011510 | ||
|
|
56a6613a73 | ||
|
|
e003db3ec1 | ||
|
|
66c90d69e3 |
96 changed files with 1878 additions and 753 deletions
|
|
@ -1,3 +1,5 @@
|
|||
[*]
|
||||
indent_size = 4
|
||||
indent_style = spaces
|
||||
[*.yml]
|
||||
indent_size = 2
|
||||
|
|
|
|||
42
.github/workflows/ci.yml
vendored
Normal file
42
.github/workflows/ci.yml
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
name: Project CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [24.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Cache NPM Deps
|
||||
id: cache-npm
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: node_modules/
|
||||
key: npm-${{ hashFiles('package-lock.json') }}
|
||||
|
||||
- name: Install NPM Deps
|
||||
if: ${{ steps.cache-npm.outputs.cache-hit != 'true' }}
|
||||
run: npm ci
|
||||
|
||||
- name: Lint
|
||||
run: npm run lint
|
||||
|
|
@ -1,78 +1,9 @@
|
|||
# Contributing to Foundryborne
|
||||
# Contributing to Daggerheart
|
||||
|
||||
Welcome! This is a community-driven project to bring [Daggerheart](https://www.daggerheart.com/) to [FoundryVTT](https://foundryvtt.com/) as a full system. We're excited to have you here and appreciate your interest in contributing.
|
||||
Thank you for your interest in contributing to the Foundryborne project!
|
||||
|
||||
---
|
||||
To ensure that all contributions align with our project goals and architectural standards, we ask that you **do not submit outside contributions without first receiving feedback from the development team.**
|
||||
|
||||
## 🤝 How to Contribute
|
||||
If you have an idea or a fix you'd like to contribute, please start a discussion or open an issue first. We'd love to hear from you and collaborate on the best way to move forward!
|
||||
|
||||
We welcome contributions of all kinds:
|
||||
|
||||
- Bug reports
|
||||
- Feature suggestions
|
||||
- Code contributions
|
||||
- UI/UX mockups
|
||||
- Documentation improvements
|
||||
- Questions and discussions
|
||||
|
||||
Please be respectful and collaborative — we’re all here to build something great together.
|
||||
|
||||
### Community Translations
|
||||
|
||||
Please note that we are not accepting community translations in the main project. Instead, community translations should be published as a module.
|
||||
|
||||
---
|
||||
|
||||
## 🧭 General Guidelines
|
||||
|
||||
- **Use GitHub Issues** to report bugs or propose features
|
||||
- **Start a Discussion** for larger ideas or questions
|
||||
- **Open a Pull Request** once you've confirmed your work aligns with project direction
|
||||
- **Keep things modular and maintainable** — if you're not sure how to structure something, ask!
|
||||
- **Orient your code on existing examples**, and feel free to suggest a standard if it makes things clearer
|
||||
|
||||
---
|
||||
|
||||
## 🗂️ Project Structure
|
||||
|
||||
Please try to follow the general logic of the existing code when submitting PRs.
|
||||
|
||||
We encourage contributors to leave comments or open Discussions when proposing structural or organizational changes.
|
||||
|
||||
---
|
||||
|
||||
## 🧾 Issue & PR Best Practices
|
||||
|
||||
**For Issues:**
|
||||
|
||||
- Use clear, descriptive titles
|
||||
- Provide a concise explanation of the problem or idea
|
||||
- Include reproduction steps or example scenarios if it's a bug
|
||||
- Add screenshots or logs if helpful
|
||||
|
||||
**For Pull Requests:**
|
||||
|
||||
- Use a clear title summarizing the change
|
||||
- Provide a brief description of what your code does and why
|
||||
- Link to any related Issues
|
||||
- Keep PRs focused — smaller is better
|
||||
|
||||
---
|
||||
|
||||
## 🔖 Labels and Boards
|
||||
|
||||
We use GitHub labels to help organize contributions. If your issue or PR relates to a specific category, feel free to tag it. There is also a GitHub Project Board to help track active work and priorities.
|
||||
|
||||
---
|
||||
|
||||
## 📣 Communication
|
||||
|
||||
Discussions are currently happening on GitHub — in Issues, PRs, and [GitHub Discussions](https://github.com/Foundryborne/daggerheart/discussions). You're welcome to use any of these, though we may consolidate to one in the future.
|
||||
|
||||
---
|
||||
|
||||
## 🤗 Thank You!
|
||||
|
||||
Whether you're fixing a typo or designing entire mechanics — every contribution matters. Thank you for helping bring _Daggerheart_ to life in FoundryVTT through **Foundryborne**!
|
||||
|
||||
🐸🛠️
|
||||
Thank you for your understanding and support.
|
||||
|
|
|
|||
|
|
@ -355,6 +355,8 @@ Hooks.on(CONFIG.DH.HOOKS.hooksConfig.groupRollStart, async data => {
|
|||
});
|
||||
|
||||
const updateActorsRangeDependentEffects = async token => {
|
||||
if (!token) return;
|
||||
|
||||
const rangeMeasurement = game.settings.get(
|
||||
CONFIG.DH.id,
|
||||
CONFIG.DH.SETTINGS.gameSettings.variantRules
|
||||
|
|
|
|||
14
eslint.config.mjs
Normal file
14
eslint.config.mjs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import globals from 'globals';
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import prettier from 'eslint-plugin-prettier';
|
||||
|
||||
export default defineConfig([
|
||||
{ files: ['**/*.{js,mjs,cjs}'], languageOptions: { globals: globals.browser } },
|
||||
{ plugins: { prettier } },
|
||||
{
|
||||
files: ['**/*.{js,mjs,cjs}'],
|
||||
rules: {
|
||||
'prettier/prettier': 'error'
|
||||
}
|
||||
}
|
||||
]);
|
||||
39
lang/en.json
39
lang/en.json
|
|
@ -74,9 +74,7 @@
|
|||
"name": "Summon",
|
||||
"tooltip": "Create tokens in the scene.",
|
||||
"error": "You do not have permission to summon tokens or there is no active scene.",
|
||||
"invalidDrop": "You can only drop Actor entities to summon.",
|
||||
"chatMessageTitle": "Test2",
|
||||
"chatMessageHeaderTitle": "Summoning"
|
||||
"invalidDrop": "You can only drop Actor entities to summon."
|
||||
},
|
||||
"transform": {
|
||||
"name": "Transform",
|
||||
|
|
@ -115,7 +113,9 @@
|
|||
"deleteTriggerTitle": "Delete Trigger",
|
||||
"deleteTriggerContent": "Are you sure you want to delete the {trigger} trigger?",
|
||||
"advantageState": "Advantage State",
|
||||
"damageOnSave": "Damage on Save"
|
||||
"damageOnSave": "Damage on Save",
|
||||
"useDefaultItemValues": "Use default Item values",
|
||||
"itemDamageIsUsed": "Item Damage Is Used"
|
||||
},
|
||||
"RollField": {
|
||||
"diceRolling": {
|
||||
|
|
@ -130,7 +130,7 @@
|
|||
"attackModifier": "Attack Modifier",
|
||||
"attackName": "Attack Name",
|
||||
"criticalThreshold": "Critical Threshold",
|
||||
"includeBase": { "label": "Include Item Damage" },
|
||||
"includeBase": { "label": "Use Item Damage" },
|
||||
"groupAttack": { "label": "Group Attack" },
|
||||
"multiplier": "Multiplier",
|
||||
"saveHint": "Set a default Trait to enable Reaction Roll. It can be changed later in Reaction Roll Dialog.",
|
||||
|
|
@ -215,6 +215,9 @@
|
|||
"headerTitle": "Adversary Reaction Roll"
|
||||
}
|
||||
},
|
||||
"Base": {
|
||||
"CannotAddType": "Cannot add {itemType} items to {actorType} actors."
|
||||
},
|
||||
"Character": {
|
||||
"advantageSources": {
|
||||
"label": "Advantage Sources",
|
||||
|
|
@ -238,6 +241,8 @@
|
|||
},
|
||||
"defaultHopeDice": "Default Hope Dice",
|
||||
"defaultFearDice": "Default Fear Dice",
|
||||
"defaultAdvantageDice": "Default Advantage Dice",
|
||||
"defaultDisadvantageDice": "Default Disadvantage Dice",
|
||||
"disadvantageSources": {
|
||||
"label": "Disadvantage Sources",
|
||||
"hint": "Add single words or short text as reminders and hints of what a character has disadvantage on."
|
||||
|
|
@ -2016,6 +2021,10 @@
|
|||
"hint": "Multiply any damage dealt to you by this number"
|
||||
}
|
||||
},
|
||||
"Battlepoints": {
|
||||
"full": "Battlepoints",
|
||||
"short": "BP"
|
||||
},
|
||||
"Bonuses": {
|
||||
"rest": {
|
||||
"downtimeAction": "Downtime Action",
|
||||
|
|
@ -2431,6 +2440,7 @@
|
|||
"next": "Next",
|
||||
"none": "None",
|
||||
"noTarget": "No current target",
|
||||
"optionalThing": "Optional {thing}",
|
||||
"partner": "Partner",
|
||||
"player": {
|
||||
"single": "Player",
|
||||
|
|
@ -2457,6 +2467,7 @@
|
|||
"rollDamage": "Roll Damage",
|
||||
"rollWith": "{roll} Roll",
|
||||
"save": "Save",
|
||||
"saveSettings": "Save Settings",
|
||||
"scalable": "Scalable",
|
||||
"scars": "Scars",
|
||||
"situationalBonus": "Situational Bonus",
|
||||
|
|
@ -2611,8 +2622,14 @@
|
|||
},
|
||||
"Weapon": {
|
||||
"weaponType": "Weapon Type",
|
||||
"primaryWeapon": "Primary Weapon",
|
||||
"secondaryWeapon": "Secondary Weapon"
|
||||
"primaryWeapon": {
|
||||
"full": "Primary Weapon",
|
||||
"short": "Primary"
|
||||
},
|
||||
"secondaryWeapon": {
|
||||
"full": "Secondary Weapon",
|
||||
"short": "Secondary"
|
||||
}
|
||||
}
|
||||
},
|
||||
"MACROS": {
|
||||
|
|
@ -2866,6 +2883,10 @@
|
|||
}
|
||||
},
|
||||
"Keybindings": {
|
||||
"partySheet": {
|
||||
"name": "Toggle Party Sheet",
|
||||
"hint": "Open or close the active party's sheet"
|
||||
},
|
||||
"spotlight": {
|
||||
"name": "Spotlight Combatant",
|
||||
"hint": "Move the spotlight to a hovered or selected token that's present in an active encounter"
|
||||
|
|
@ -3067,6 +3088,7 @@
|
|||
},
|
||||
"ItemBrowser": {
|
||||
"title": "Daggerheart Compendium Browser",
|
||||
"windowTitle": "Compendium Browser",
|
||||
"hint": "Select a Folder in sidebar to start browsing through the compendium",
|
||||
"browserSettings": "Browser Settings",
|
||||
"columnName": "Name",
|
||||
|
|
@ -3199,6 +3221,8 @@
|
|||
"companion": "Level {level} - {partner}",
|
||||
"companionNoPartner": "No Partner",
|
||||
"duplicateToNewTier": "Duplicate to New Tier",
|
||||
"activateParty": "Make Active Party",
|
||||
"partyIsActive": "Active",
|
||||
"createAdversary": "Create Adversary",
|
||||
"pickTierTitle": "Pick a new tier for this adversary"
|
||||
},
|
||||
|
|
@ -3211,6 +3235,7 @@
|
|||
"Tooltip": {
|
||||
"disableEffect": "Disable Effect",
|
||||
"enableEffect": "Enable Effect",
|
||||
"edit": "Edit",
|
||||
"openItemWorld": "Open Item World",
|
||||
"openActorWorld": "Open Actor World",
|
||||
"sendToChat": "Send to Chat",
|
||||
|
|
|
|||
|
|
@ -11,7 +11,10 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
|||
this.character = character;
|
||||
|
||||
this.setup = {
|
||||
traits: this.character.system.traits,
|
||||
traits: Object.keys(this.character.system.traits).reduce((acc, key) => {
|
||||
acc[key] = { value: null };
|
||||
return acc;
|
||||
}, {}),
|
||||
ancestryName: {
|
||||
primary: '',
|
||||
secondary: ''
|
||||
|
|
@ -377,8 +380,10 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
|||
];
|
||||
return Object.values(this.setup.traits).reduce((acc, x) => {
|
||||
const index = traitCompareArray.indexOf(x.value);
|
||||
if (index === -1) return acc;
|
||||
|
||||
traitCompareArray.splice(index, 1);
|
||||
acc += index !== -1;
|
||||
acc += 1;
|
||||
return acc;
|
||||
}, 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,6 +123,10 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
context.advantage = this.config.roll?.advantage;
|
||||
context.disadvantage = this.config.roll?.disadvantage;
|
||||
context.diceOptions = CONFIG.DH.GENERAL.diceTypes;
|
||||
context.dieFaces = CONFIG.DH.GENERAL.dieFaces.reduce((acc, face) => {
|
||||
acc[face] = `d${face}`;
|
||||
return acc;
|
||||
}, {});
|
||||
context.isLite = this.config.roll?.lite;
|
||||
context.extraFormula = this.config.extraFormula;
|
||||
context.formula = this.roll.constructFormula(this.config);
|
||||
|
|
@ -152,9 +156,7 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
}
|
||||
if (this.config.uses) this.config.uses = foundry.utils.mergeObject(this.config.uses, rest.uses);
|
||||
if (rest.roll?.dice) {
|
||||
Object.entries(rest.roll.dice).forEach(([key, value]) => {
|
||||
this.roll[key] = value;
|
||||
});
|
||||
this.roll = foundry.utils.mergeObject(this.roll, rest.roll.dice);
|
||||
}
|
||||
if (rest.hasOwnProperty('trait')) {
|
||||
this.config.roll.trait = rest.trait;
|
||||
|
|
@ -173,6 +175,15 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
this.disadvantage = advantage === -1;
|
||||
|
||||
this.config.roll.advantage = this.config.roll.advantage === advantage ? 0 : advantage;
|
||||
|
||||
if (this.config.roll.advantage === 1 && this.config.data.rules.roll.defaultAdvantageDice) {
|
||||
const faces = Number.parseInt(this.config.data.rules.roll.defaultAdvantageDice);
|
||||
this.roll.advantageFaces = Number.isNaN(faces) ? this.roll.advantageFaces : faces;
|
||||
} else if (this.config.roll.advantage === -1 && this.config.data.rules.roll.defaultDisadvantageDice) {
|
||||
const faces = Number.parseInt(this.config.data.rules.roll.defaultDisadvantageDice);
|
||||
this.roll.advantageFaces = Number.isNaN(faces) ? this.roll.advantageFaces : faces;
|
||||
}
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -259,8 +259,9 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
|
|||
const resetValue = increasing
|
||||
? 0
|
||||
: feature.system.resource.max
|
||||
? Roll.replaceFormulaData(feature.system.resource.max, this.actor)
|
||||
? new Roll(Roll.replaceFormulaData(feature.system.resource.max, this.actor)).evaluateSync().total
|
||||
: 0;
|
||||
|
||||
await feature.update({ 'system.resource.value': resetValue });
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,13 +38,15 @@ export default class ItemTransferDialog extends HandlebarsApplicationMixin(Appli
|
|||
originActor ??= item?.actor;
|
||||
const homebrewKey = CONFIG.DH.SETTINGS.gameSettings.Homebrew;
|
||||
const currencySetting = game.settings.get(CONFIG.DH.id, homebrewKey).currency?.[currency] ?? null;
|
||||
const max = item?.system.quantity ?? originActor.system.gold[currency] ?? 0;
|
||||
|
||||
return {
|
||||
originActor,
|
||||
targetActor,
|
||||
itemImage: item?.img,
|
||||
currencyIcon: currencySetting?.icon,
|
||||
max: item?.system.quantity ?? originActor.system.gold[currency] ?? 0,
|
||||
max,
|
||||
initial: targetActor.system.metadata.quantifiable?.includes(item.type) ? max : 1,
|
||||
title: item?.name ?? currencySetting?.label
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App
|
|||
type: 'button',
|
||||
action: 'reset',
|
||||
icon: 'fa-solid fa-arrow-rotate-left',
|
||||
label: game.i18n.localize('ACTIONS.Reset')
|
||||
label: game.i18n.localize('SETTINGS.UI.ACTIONS.Reset')
|
||||
},
|
||||
{ type: 'submit', icon: 'fa-solid fa-floppy-disk', label: game.i18n.localize('EDITOR.Save') }
|
||||
];
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
static DEFAULT_OPTIONS = {
|
||||
classes: ['character'],
|
||||
position: { width: 850, height: 800 },
|
||||
/* Foundry adds disabled to all buttons and inputs if editPermission is missing. This is not desired. */
|
||||
editPermission: CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER,
|
||||
actions: {
|
||||
toggleVault: CharacterSheet.#toggleVault,
|
||||
rollAttribute: CharacterSheet.#rollAttribute,
|
||||
|
|
@ -68,7 +66,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
}
|
||||
},
|
||||
{
|
||||
handler: CharacterSheet.#getEquipamentContextOptions,
|
||||
handler: CharacterSheet.#getEquipmentContextOptions,
|
||||
selector: '[data-item-uuid][data-type="armor"], [data-item-uuid][data-type="weapon"]',
|
||||
options: {
|
||||
parentClassHooks: false,
|
||||
|
|
@ -170,6 +168,16 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
return applicationOptions;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
_toggleDisabled(disabled) {
|
||||
// Overriden to only disable text inputs by default.
|
||||
// Everything else is done by checking @root.editable in the sheet
|
||||
const form = this.form;
|
||||
for (const input of form.querySelectorAll('input:not([type=search]), .editor.prosemirror')) {
|
||||
input.disabled = disabled;
|
||||
}
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
async _onRender(context, options) {
|
||||
await super._onRender(context, options);
|
||||
|
|
@ -315,11 +323,11 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
/**@type {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} */
|
||||
const options = [
|
||||
{
|
||||
name: 'toLoadout',
|
||||
label: 'toLoadout',
|
||||
icon: 'fa-solid fa-arrow-up',
|
||||
condition: target => {
|
||||
visible: target => {
|
||||
const doc = getDocFromElementSync(target);
|
||||
return doc && doc.system.inVault;
|
||||
return doc?.isOwner && doc.system.inVault;
|
||||
},
|
||||
callback: async target => {
|
||||
const doc = await getDocFromElement(target);
|
||||
|
|
@ -329,11 +337,11 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
}
|
||||
},
|
||||
{
|
||||
name: 'recall',
|
||||
label: 'recall',
|
||||
icon: 'fa-solid fa-bolt-lightning',
|
||||
condition: target => {
|
||||
visible: target => {
|
||||
const doc = getDocFromElementSync(target);
|
||||
return doc && doc.system.inVault;
|
||||
return doc?.isOwner && doc.system.inVault;
|
||||
},
|
||||
callback: async (target, event) => {
|
||||
const doc = await getDocFromElement(target);
|
||||
|
|
@ -368,17 +376,17 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
}
|
||||
},
|
||||
{
|
||||
name: 'toVault',
|
||||
label: 'toVault',
|
||||
icon: 'fa-solid fa-arrow-down',
|
||||
condition: target => {
|
||||
visible: target => {
|
||||
const doc = getDocFromElementSync(target);
|
||||
return doc && !doc.system.inVault;
|
||||
return doc?.isOwner && !doc.system.inVault;
|
||||
},
|
||||
callback: async target => (await getDocFromElement(target)).update({ 'system.inVault': true })
|
||||
}
|
||||
].map(option => ({
|
||||
...option,
|
||||
name: `DAGGERHEART.APPLICATIONS.ContextMenu.${option.name}`,
|
||||
label: `DAGGERHEART.APPLICATIONS.ContextMenu.${option.label}`,
|
||||
icon: `<i class="${option.icon}"></i>`
|
||||
}));
|
||||
|
||||
|
|
@ -391,29 +399,29 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
* @this {CharacterSheet}
|
||||
* @protected
|
||||
*/
|
||||
static #getEquipamentContextOptions() {
|
||||
static #getEquipmentContextOptions() {
|
||||
const options = [
|
||||
{
|
||||
name: 'equip',
|
||||
label: 'equip',
|
||||
icon: 'fa-solid fa-hands',
|
||||
condition: target => {
|
||||
visible: target => {
|
||||
const doc = getDocFromElementSync(target);
|
||||
return doc && !doc.system.equipped;
|
||||
return doc.isOwner && doc && !doc.system.equipped;
|
||||
},
|
||||
callback: (target, event) => CharacterSheet.#toggleEquipItem.call(this, event, target)
|
||||
},
|
||||
{
|
||||
name: 'unequip',
|
||||
label: 'unequip',
|
||||
icon: 'fa-solid fa-hands',
|
||||
condition: target => {
|
||||
visible: target => {
|
||||
const doc = getDocFromElementSync(target);
|
||||
return doc && doc.system.equipped;
|
||||
return doc.isOwner && doc && doc.system.equipped;
|
||||
},
|
||||
callback: (target, event) => CharacterSheet.#toggleEquipItem.call(this, event, target)
|
||||
}
|
||||
].map(option => ({
|
||||
...option,
|
||||
name: `DAGGERHEART.APPLICATIONS.ContextMenu.${option.name}`,
|
||||
label: `DAGGERHEART.APPLICATIONS.ContextMenu.${option.label}`,
|
||||
icon: `<i class="${option.icon}"></i>`
|
||||
}));
|
||||
|
||||
|
|
|
|||
|
|
@ -418,18 +418,18 @@ export default function DHApplicationMixin(Base) {
|
|||
/**@type {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} */
|
||||
const options = [
|
||||
{
|
||||
name: 'disableEffect',
|
||||
label: 'disableEffect',
|
||||
icon: 'fa-solid fa-lightbulb',
|
||||
condition: element => {
|
||||
visible: element => {
|
||||
const target = element.closest('[data-item-uuid]');
|
||||
return !target.dataset.disabled && target.dataset.itemType !== 'beastform';
|
||||
},
|
||||
callback: async target => (await getDocFromElement(target)).update({ disabled: true })
|
||||
},
|
||||
{
|
||||
name: 'enableEffect',
|
||||
label: 'enableEffect',
|
||||
icon: 'fa-regular fa-lightbulb',
|
||||
condition: element => {
|
||||
visible: element => {
|
||||
const target = element.closest('[data-item-uuid]');
|
||||
return target.dataset.disabled && target.dataset.itemType !== 'beastform';
|
||||
},
|
||||
|
|
@ -437,7 +437,7 @@ export default function DHApplicationMixin(Base) {
|
|||
}
|
||||
].map(option => ({
|
||||
...option,
|
||||
name: `DAGGERHEART.APPLICATIONS.ContextMenu.${option.name}`,
|
||||
label: `DAGGERHEART.APPLICATIONS.ContextMenu.${option.label}`,
|
||||
icon: `<i class="${option.icon}"></i>`
|
||||
}));
|
||||
|
||||
|
|
@ -468,14 +468,14 @@ export default function DHApplicationMixin(Base) {
|
|||
_getContextMenuCommonOptions({ usable = false, toChat = false, deletable = true }) {
|
||||
const options = [
|
||||
{
|
||||
name: 'CONTROLS.CommonEdit',
|
||||
label: 'CONTROLS.CommonEdit',
|
||||
icon: 'fa-solid fa-pen-to-square',
|
||||
condition: target => {
|
||||
visible: target => {
|
||||
const { dataset } = target.closest('[data-item-uuid]');
|
||||
const doc = getDocFromElementSync(target);
|
||||
return (
|
||||
(!dataset.noCompendiumEdit && !doc) ||
|
||||
(doc && (!doc?.hasOwnProperty('systemPath') || doc?.inCollection))
|
||||
(doc?.isOwner && (!doc?.hasOwnProperty('systemPath') || doc?.inCollection))
|
||||
);
|
||||
},
|
||||
callback: async target => (await getDocFromElement(target)).sheet.render({ force: true })
|
||||
|
|
@ -484,14 +484,14 @@ export default function DHApplicationMixin(Base) {
|
|||
|
||||
if (usable) {
|
||||
options.unshift({
|
||||
name: 'DAGGERHEART.GENERAL.damage',
|
||||
label: 'DAGGERHEART.GENERAL.damage',
|
||||
icon: 'fa-solid fa-explosion',
|
||||
condition: target => {
|
||||
visible: target => {
|
||||
const doc = getDocFromElementSync(target);
|
||||
return (
|
||||
const hasDamage =
|
||||
!foundry.utils.isEmpty(doc?.system?.attack?.damage.parts) ||
|
||||
!foundry.utils.isEmpty(doc?.damage?.parts)
|
||||
);
|
||||
!foundry.utils.isEmpty(doc?.damage?.parts);
|
||||
return doc?.isOwner && hasDamage;
|
||||
},
|
||||
callback: async (target, event) => {
|
||||
const doc = await getDocFromElement(target),
|
||||
|
|
@ -507,11 +507,11 @@ export default function DHApplicationMixin(Base) {
|
|||
});
|
||||
|
||||
options.unshift({
|
||||
name: 'DAGGERHEART.APPLICATIONS.ContextMenu.useItem',
|
||||
label: 'DAGGERHEART.APPLICATIONS.ContextMenu.useItem',
|
||||
icon: 'fa-solid fa-burst',
|
||||
condition: target => {
|
||||
visible: target => {
|
||||
const doc = getDocFromElementSync(target);
|
||||
return doc && !(doc.type === 'domainCard' && doc.system.inVault);
|
||||
return doc?.isOwner && !(doc.type === 'domainCard' && doc.system.inVault);
|
||||
},
|
||||
callback: async (target, event) => (await getDocFromElement(target)).use(event)
|
||||
});
|
||||
|
|
@ -519,18 +519,19 @@ export default function DHApplicationMixin(Base) {
|
|||
|
||||
if (toChat)
|
||||
options.push({
|
||||
name: 'DAGGERHEART.APPLICATIONS.ContextMenu.sendToChat',
|
||||
label: 'DAGGERHEART.APPLICATIONS.ContextMenu.sendToChat',
|
||||
icon: 'fa-solid fa-message',
|
||||
callback: async target => (await getDocFromElement(target)).toChat(this.document.uuid)
|
||||
});
|
||||
|
||||
if (deletable)
|
||||
options.push({
|
||||
name: 'CONTROLS.CommonDelete',
|
||||
label: 'CONTROLS.CommonDelete',
|
||||
icon: 'fa-solid fa-trash',
|
||||
condition: element => {
|
||||
visible: element => {
|
||||
const target = element.closest('[data-item-uuid]');
|
||||
return target.dataset.itemType !== 'beastform';
|
||||
const doc = getDocFromElementSync(target);
|
||||
return doc?.isOwner && target.dataset.itemType !== 'beastform';
|
||||
},
|
||||
callback: async (target, event) => {
|
||||
const doc = await getDocFromElement(target);
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) {
|
|||
.hideAttribution;
|
||||
|
||||
// Prepare inventory data
|
||||
if (['party', 'character'].includes(this.document.type)) {
|
||||
if (this.document.system.metadata.hasInventory) {
|
||||
context.inventory = {
|
||||
currencies: {},
|
||||
weapons: this.document.itemTypes.weapon.sort((a, b) => a.sort - b.sort),
|
||||
|
|
@ -283,11 +283,7 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) {
|
|||
async _onDropItem(event, item) {
|
||||
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event);
|
||||
const originActor = item.actor;
|
||||
if (
|
||||
item.actor?.uuid === this.document.uuid ||
|
||||
!originActor ||
|
||||
!['character', 'party'].includes(this.document.type)
|
||||
) {
|
||||
if (!originActor || originActor.uuid === this.document.uuid || !this.document.system.metadata.hasInventory) {
|
||||
return super._onDropItem(event, item);
|
||||
}
|
||||
|
||||
|
|
@ -302,45 +298,77 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) {
|
|||
);
|
||||
}
|
||||
|
||||
if (item.system.metadata.isQuantifiable) {
|
||||
const actorItem = originActor.items.get(data.originId);
|
||||
const quantityTransfered = await game.system.api.applications.dialogs.ItemTransferDialog.configure({
|
||||
// Perform the actual transfer, showing a dialog when doing it
|
||||
const availableQuantity = Math.max(1, item.system.quantity);
|
||||
const actorItem = originActor.items.get(data.originId) ?? item;
|
||||
if (availableQuantity > 1) {
|
||||
const quantityTransferred = await game.system.api.applications.dialogs.ItemTransferDialog.configure({
|
||||
item,
|
||||
targetActor: this.document
|
||||
});
|
||||
|
||||
if (quantityTransfered) {
|
||||
const existingItem = this.document.items.find(x => itemIsIdentical(x, item));
|
||||
if (existingItem) {
|
||||
await existingItem.update({
|
||||
'system.quantity': existingItem.system.quantity + quantityTransfered
|
||||
});
|
||||
return this.#transferItem(actorItem, quantityTransferred);
|
||||
} else {
|
||||
const createData = item.toObject();
|
||||
await this.document.createEmbeddedDocuments('Item', [
|
||||
{
|
||||
...createData,
|
||||
system: {
|
||||
...createData.system,
|
||||
quantity: quantityTransfered
|
||||
return this.#transferItem(actorItem, availableQuantity);
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
if (quantityTransfered === actorItem.system.quantity) {
|
||||
await originActor.deleteEmbeddedDocuments('Item', [data.originId]);
|
||||
/**
|
||||
* Helper to perform the actual transfer of an item to this actor, including stack/unstack logic based on target quantifiability.
|
||||
* Make sure item is the actor item before calling this method or there will be issues
|
||||
*/
|
||||
async #transferItem(item, quantity) {
|
||||
const originActor = item.actor;
|
||||
const targetActor = this.document;
|
||||
const allowStacking = targetActor.system.metadata.quantifiable?.includes(item.type);
|
||||
|
||||
const batch = [];
|
||||
|
||||
// First add/update the item to the target actor
|
||||
const existing = allowStacking ? targetActor.items.find(x => itemIsIdentical(x, item)) : null;
|
||||
if (existing) {
|
||||
batch.push({
|
||||
action: 'update',
|
||||
documentName: 'Item',
|
||||
parent: targetActor,
|
||||
updates: [{ '_id': existing.id, 'system.quantity': existing.system.quantity + quantity }]
|
||||
});
|
||||
} else {
|
||||
await actorItem.update({
|
||||
'system.quantity': actorItem.system.quantity - quantityTransfered
|
||||
const itemsToCreate = [];
|
||||
if (allowStacking) {
|
||||
itemsToCreate.push(foundry.utils.mergeObject(item.toObject(true), { system: { quantity } }));
|
||||
} else {
|
||||
const createData = new Array(Math.max(1, quantity))
|
||||
.fill(0)
|
||||
.map(() => foundry.utils.mergeObject(item.toObject(), { system: { quantity: 1 } }));
|
||||
itemsToCreate.push(...createData);
|
||||
}
|
||||
batch.push({
|
||||
action: 'create',
|
||||
documentName: 'Item',
|
||||
parent: targetActor,
|
||||
data: itemsToCreate
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the item from the original actor (by either deleting it, or updating its quantity)
|
||||
if (quantity >= item.system.quantity) {
|
||||
batch.push({
|
||||
action: 'delete',
|
||||
documentName: 'Item',
|
||||
parent: originActor,
|
||||
ids: [item.id]
|
||||
});
|
||||
} else {
|
||||
await this.document.createEmbeddedDocuments('Item', [item.toObject()]);
|
||||
await originActor.deleteEmbeddedDocuments('Item', [data.originId]);
|
||||
}
|
||||
batch.push({
|
||||
action: 'update',
|
||||
documentName: 'Item',
|
||||
parent: originActor,
|
||||
updates: [{ '_id': item.id, 'system.quantity': item.system.quantity - quantity }]
|
||||
});
|
||||
}
|
||||
|
||||
return foundry.documents.modifyBatch(batch);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -31,11 +31,12 @@ export default class AncestrySheet extends DHHeritageSheet {
|
|||
if (data.type === 'ActiveEffect') return super._onDrop(event);
|
||||
|
||||
const target = event.target.closest('fieldset.drop-section');
|
||||
if (target) {
|
||||
const typeField =
|
||||
this.document.system[target.dataset.type === 'primary' ? 'primaryFeature' : 'secondaryFeature'];
|
||||
|
||||
if (!typeField) {
|
||||
super._onDrop(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,10 +46,11 @@ export default class DhActorDirectory extends foundry.applications.sidebar.tabs.
|
|||
|
||||
_getEntryContextOptions() {
|
||||
const options = super._getEntryContextOptions();
|
||||
options.push({
|
||||
name: 'DAGGERHEART.UI.Sidebar.actorDirectory.duplicateToNewTier',
|
||||
options.push(
|
||||
{
|
||||
label: 'DAGGERHEART.UI.Sidebar.actorDirectory.duplicateToNewTier',
|
||||
icon: `<i class="fa-solid fa-arrow-trend-up" inert></i>`,
|
||||
condition: li => {
|
||||
visible: li => {
|
||||
const actor = game.actors.get(li.dataset.entryId);
|
||||
return actor?.type === 'adversary' && actor.system.type !== 'social';
|
||||
},
|
||||
|
|
@ -89,7 +90,23 @@ export default class DhActorDirectory extends foundry.applications.sidebar.tabs.
|
|||
ui.notifications.info(`Tier ${tier} ${actor.name} created`);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
{
|
||||
label: 'DAGGERHEART.UI.Sidebar.actorDirectory.activateParty',
|
||||
icon: `<i class="fa-regular fa-square"></i>`,
|
||||
visible: li => {
|
||||
const actor = game.actors.get(li.dataset.entryId);
|
||||
return actor && actor.type === 'party' && !actor.system.active;
|
||||
},
|
||||
callback: async li => {
|
||||
const actor = game.actors.get(li.dataset.entryId);
|
||||
if (!actor) throw new Error('Unexpected missing actor');
|
||||
|
||||
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.ActiveParty, actor.id);
|
||||
ui.actors.render();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,23 +103,10 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
|||
_getEntryContextOptions() {
|
||||
return [
|
||||
...super._getEntryContextOptions(),
|
||||
// {
|
||||
// name: 'Reroll',
|
||||
// icon: '<i class="fa-solid fa-dice"></i>',
|
||||
// condition: li => {
|
||||
// const message = game.messages.get(li.dataset.messageId);
|
||||
|
||||
// return (game.user.isGM || message.isAuthor) && message.rolls.length > 0;
|
||||
// },
|
||||
// callback: li => {
|
||||
// const message = game.messages.get(li.dataset.messageId);
|
||||
// new game.system.api.applications.dialogs.RerollDialog(message).render({ force: true });
|
||||
// }
|
||||
// },
|
||||
{
|
||||
name: game.i18n.localize('DAGGERHEART.UI.ChatLog.rerollDamage'),
|
||||
label: 'DAGGERHEART.UI.ChatLog.rerollDamage',
|
||||
icon: '<i class="fa-solid fa-dice"></i>',
|
||||
condition: li => {
|
||||
visible: li => {
|
||||
const message = game.messages.get(li.dataset.messageId);
|
||||
const hasRolledDamage = message.system.hasDamage
|
||||
? Object.keys(message.system.damage).length > 0
|
||||
|
|
|
|||
|
|
@ -84,15 +84,15 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C
|
|||
_getCombatContextOptions() {
|
||||
return [
|
||||
{
|
||||
name: 'COMBAT.ClearMovementHistories',
|
||||
label: 'COMBAT.ClearMovementHistories',
|
||||
icon: '<i class="fa-solid fa-shoe-prints"></i>',
|
||||
condition: () => game.user.isGM && this.viewed?.combatants.size > 0,
|
||||
visible: () => game.user.isGM && this.viewed?.combatants.size > 0,
|
||||
callback: () => this.viewed.clearMovementHistories()
|
||||
},
|
||||
{
|
||||
name: 'COMBAT.Delete',
|
||||
label: 'COMBAT.Delete',
|
||||
icon: '<i class="fa-solid fa-trash"></i>',
|
||||
condition: () => game.user.isGM && !!this.viewed,
|
||||
visible: () => game.user.isGM && !!this.viewed,
|
||||
callback: () => this.viewed.endCombat()
|
||||
}
|
||||
];
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
|||
tag: 'div',
|
||||
window: {
|
||||
frame: true,
|
||||
title: 'Compendium Browser',
|
||||
title: 'DAGGERHEART.UI.ItemBrowser.windowTitle',
|
||||
icon: 'fa-solid fa-book-atlas',
|
||||
positioned: true,
|
||||
resizable: true
|
||||
|
|
@ -583,7 +583,9 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
|||
const { itemUuid } = event.target.closest('[data-item-uuid]').dataset,
|
||||
item = await foundry.utils.fromUuid(itemUuid),
|
||||
dragData = item.toDragData();
|
||||
|
||||
event.dataTransfer.setData('text/plain', JSON.stringify(dragData));
|
||||
event.dataTransfer.setDragImage(event.target.querySelector('img'), 0, 0);
|
||||
}
|
||||
|
||||
_canDragStart() {
|
||||
|
|
|
|||
|
|
@ -74,12 +74,18 @@ export const typeConfig = {
|
|||
columns: [
|
||||
{
|
||||
key: 'type',
|
||||
label: 'DAGGERHEART.GENERAL.type'
|
||||
label: 'DAGGERHEART.GENERAL.type',
|
||||
format: type => (type ? `TYPES.Item.${type}` : '-')
|
||||
},
|
||||
{
|
||||
key: 'system.secondary',
|
||||
label: 'DAGGERHEART.UI.ItemBrowser.subtype',
|
||||
format: isSecondary => (isSecondary ? 'secondary' : isSecondary === false ? 'primary' : '-')
|
||||
format: isSecondary =>
|
||||
isSecondary
|
||||
? 'DAGGERHEART.ITEMS.Weapon.secondaryWeapon.short'
|
||||
: isSecondary === false
|
||||
? 'DAGGERHEART.ITEMS.Weapon.primaryWeapon.short'
|
||||
: '-'
|
||||
},
|
||||
{
|
||||
key: 'system.tier',
|
||||
|
|
@ -99,8 +105,8 @@ export const typeConfig = {
|
|||
key: 'system.secondary',
|
||||
label: 'DAGGERHEART.UI.ItemBrowser.subtype',
|
||||
choices: [
|
||||
{ value: false, label: 'DAGGERHEART.ITEMS.Weapon.primaryWeapon' },
|
||||
{ value: true, label: 'DAGGERHEART.ITEMS.Weapon.secondaryWeapon' }
|
||||
{ value: false, label: 'DAGGERHEART.ITEMS.Weapon.primaryWeapon.full' },
|
||||
{ value: true, label: 'DAGGERHEART.ITEMS.Weapon.secondaryWeapon.full' }
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -258,11 +264,13 @@ export const typeConfig = {
|
|||
columns: [
|
||||
{
|
||||
key: 'system.type',
|
||||
label: 'DAGGERHEART.GENERAL.type'
|
||||
label: 'DAGGERHEART.GENERAL.type',
|
||||
format: type => (type ? `DAGGERHEART.CONFIG.DomainCardTypes.${type}` : '-')
|
||||
},
|
||||
{
|
||||
key: 'system.domain',
|
||||
label: 'DAGGERHEART.GENERAL.Domain.single'
|
||||
label: 'DAGGERHEART.GENERAL.Domain.single',
|
||||
format: domain => (domain ? CONFIG.DH.DOMAIN.allDomains()[domain].label : '-')
|
||||
},
|
||||
{
|
||||
key: 'system.level',
|
||||
|
|
@ -374,7 +382,7 @@ export const typeConfig = {
|
|||
columns: [
|
||||
{
|
||||
key: 'system.linkedClass',
|
||||
label: 'Class',
|
||||
label: 'TYPES.Item.class',
|
||||
format: linkedClass => linkedClass?.name ?? 'DAGGERHEART.UI.ItemBrowser.missing'
|
||||
},
|
||||
{
|
||||
|
|
@ -386,7 +394,7 @@ export const typeConfig = {
|
|||
filters: [
|
||||
{
|
||||
key: 'system.linkedClass.uuid',
|
||||
label: 'Class',
|
||||
label: 'TYPES.Item.class',
|
||||
choices: items => {
|
||||
const list = items
|
||||
.filter(item => item.system.linkedClass)
|
||||
|
|
@ -410,7 +418,8 @@ export const typeConfig = {
|
|||
},
|
||||
{
|
||||
key: 'system.mainTrait',
|
||||
label: 'DAGGERHEART.GENERAL.Trait.single'
|
||||
label: 'DAGGERHEART.GENERAL.Trait.single',
|
||||
format: trait => (trait ? `DAGGERHEART.CONFIG.Traits.${trait}.name` : '-')
|
||||
}
|
||||
],
|
||||
filters: [
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
export const keybindings = {
|
||||
spotlight: 'DHSpotlight'
|
||||
spotlight: 'DHSpotlight',
|
||||
partySheet: 'DHPartySheet'
|
||||
};
|
||||
|
||||
export const menu = {
|
||||
|
|
@ -40,7 +41,8 @@ export const gameSettings = {
|
|||
LastMigrationVersion: 'LastMigrationVersion',
|
||||
SpotlightRequestQueue: 'SpotlightRequestQueue',
|
||||
CompendiumBrowserSettings: 'CompendiumBrowserSettings',
|
||||
SpotlightTracker: 'SpotlightTracker'
|
||||
SpotlightTracker: 'SpotlightTracker',
|
||||
ActiveParty: 'ActiveParty'
|
||||
};
|
||||
|
||||
export const actionAutomationChoices = {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ export default class DHAttackAction extends DHDamageAction {
|
|||
if (!!this.item?.system?.attack) {
|
||||
if (this.damage.includeBase) {
|
||||
const baseDamage = this.getParentDamage();
|
||||
this.damage.parts.unshift(new DHDamageData(baseDamage));
|
||||
this.damage.parts.hitPoints = new DHDamageData(baseDamage);
|
||||
}
|
||||
if (this.roll.useDefault) {
|
||||
this.roll.trait = this.item.system.attack.roll.trait;
|
||||
|
|
@ -51,7 +51,7 @@ export default class DHAttackAction extends DHDamageAction {
|
|||
async use(event, options) {
|
||||
const result = await super.use(event, options);
|
||||
|
||||
if (result.message?.system.action.roll?.type === 'attack') {
|
||||
if (result?.message?.system.action.roll?.type === 'attack') {
|
||||
const { updateCountdowns } = game.system.api.applications.ui.DhCountdowns;
|
||||
await updateCountdowns(CONFIG.DH.GENERAL.countdownProgressionTypes.characterAttack.id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,6 +110,11 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
return this._id;
|
||||
}
|
||||
|
||||
/** Returns true if the current user is the owner of the containing item */
|
||||
get isOwner() {
|
||||
return this.item?.isOwner ?? true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return Item the action is attached too.
|
||||
*/
|
||||
|
|
@ -143,6 +148,12 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
: null;
|
||||
}
|
||||
|
||||
/** Returns true if the action is usable */
|
||||
get usable() {
|
||||
const actor = this.actor;
|
||||
return this.isOwner && actor?.type === 'character';
|
||||
}
|
||||
|
||||
static getRollType(parent) {
|
||||
return 'trait';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ export default class DhpAdversary extends DhCreature {
|
|||
}
|
||||
|
||||
isItemValid(source) {
|
||||
return source.type === 'feature';
|
||||
return super.isItemValid(source) || source.type === 'feature';
|
||||
}
|
||||
|
||||
async _preUpdate(changes, options, user) {
|
||||
|
|
|
|||
|
|
@ -107,7 +107,8 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel {
|
|||
hasResistances: true,
|
||||
hasAttribution: false,
|
||||
hasLimitedView: true,
|
||||
usesSize: false
|
||||
usesSize: false,
|
||||
hasInventory: false
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -168,6 +169,11 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
isItemValid(source) {
|
||||
const inventoryTypes = ['weapon', 'armor', 'consumable', 'loot'];
|
||||
return this.metadata.hasInventory && inventoryTypes.includes(source.type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a data object used to evaluate any dice rolls associated with this Item Type
|
||||
* @param {object} [options] - Options which modify the getRollData method.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
|
|||
import DhLevelData from '../levelData.mjs';
|
||||
import { commonActorRules } from './base.mjs';
|
||||
import DhCreature from './creature.mjs';
|
||||
import { attributeField, stressDamageReductionRule, bonusField } from '../fields/actorField.mjs';
|
||||
import { attributeField, stressDamageReductionRule, bonusField, GoldField } from '../fields/actorField.mjs';
|
||||
import { ActionField } from '../fields/actionField.mjs';
|
||||
import DHCharacterSettings from '../../applications/sheets-configs/character-settings.mjs';
|
||||
import { getArmorSources } from '../../helpers/utils.mjs';
|
||||
|
|
@ -18,7 +18,9 @@ export default class DhCharacter extends DhCreature {
|
|||
label: 'TYPES.Actor.character',
|
||||
type: 'character',
|
||||
settingSheet: DHCharacterSettings,
|
||||
isNPC: false
|
||||
isNPC: false,
|
||||
hasInventory: true,
|
||||
quantifiable: ['loot', 'consumable']
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -62,12 +64,7 @@ export default class DhCharacter extends DhCreature {
|
|||
core: new fields.BooleanField({ initial: false })
|
||||
})
|
||||
),
|
||||
gold: new fields.SchemaField({
|
||||
coins: new fields.NumberField({ initial: 0, integer: true }),
|
||||
handfuls: new fields.NumberField({ initial: 1, integer: true }),
|
||||
bags: new fields.NumberField({ initial: 0, integer: true }),
|
||||
chests: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
gold: new GoldField(),
|
||||
scars: new fields.NumberField({ initial: 0, integer: true, label: 'DAGGERHEART.GENERAL.scars' }),
|
||||
biography: new fields.SchemaField({
|
||||
background: new fields.HTMLField(),
|
||||
|
|
@ -289,6 +286,22 @@ export default class DhCharacter extends DhCreature {
|
|||
guaranteedCritical: new fields.BooleanField({
|
||||
label: 'DAGGERHEART.ACTORS.Character.roll.guaranteedCritical.label',
|
||||
hint: 'DAGGERHEART.ACTORS.Character.roll.guaranteedCritical.hint'
|
||||
}),
|
||||
defaultAdvantageDice: new fields.NumberField({
|
||||
nullable: true,
|
||||
required: true,
|
||||
integer: true,
|
||||
choices: CONFIG.DH.GENERAL.dieFaces,
|
||||
initial: null,
|
||||
label: 'DAGGERHEART.ACTORS.Character.defaultAdvantageDice'
|
||||
}),
|
||||
defaultDisadvantageDice: new fields.NumberField({
|
||||
nullable: true,
|
||||
required: true,
|
||||
integer: true,
|
||||
choices: CONFIG.DH.GENERAL.dieFaces,
|
||||
initial: null,
|
||||
label: 'DAGGERHEART.ACTORS.Character.defaultDisadvantageDice'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -434,6 +447,11 @@ export default class DhCharacter extends DhCreature {
|
|||
return attack;
|
||||
}
|
||||
|
||||
/* All items are valid on characters */
|
||||
isItemValid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
isItemAvailable(item) {
|
||||
if (!super.isItemAvailable(this)) return false;
|
||||
|
|
|
|||
|
|
@ -61,6 +61,24 @@ export default class DhCompanion extends DhCreature {
|
|||
initial: false,
|
||||
label: 'DAGGERHEART.GENERAL.Rules.conditionImmunities.vulnerable'
|
||||
})
|
||||
}),
|
||||
roll: new fields.SchemaField({
|
||||
defaultAdvantageDice: new fields.NumberField({
|
||||
nullable: true,
|
||||
required: true,
|
||||
integer: true,
|
||||
choices: CONFIG.DH.GENERAL.dieFaces,
|
||||
initial: null,
|
||||
label: 'DAGGERHEART.ACTORS.Character.defaultAdvantageDice'
|
||||
}),
|
||||
defaultDisadvantageDice: new fields.NumberField({
|
||||
nullable: true,
|
||||
required: true,
|
||||
integer: true,
|
||||
choices: CONFIG.DH.GENERAL.dieFaces,
|
||||
initial: null,
|
||||
label: 'DAGGERHEART.ACTORS.Character.defaultDisadvantageDice'
|
||||
})
|
||||
})
|
||||
}),
|
||||
attack: new ActionField({
|
||||
|
|
@ -118,10 +136,6 @@ export default class DhCompanion extends DhCreature {
|
|||
return this.levelupChoicesLeft > 0;
|
||||
}
|
||||
|
||||
isItemValid() {
|
||||
return false;
|
||||
}
|
||||
|
||||
prepareBaseData() {
|
||||
super.prepareBaseData();
|
||||
this.attack.roll.bonus = this.partner?.system?.spellcastModifier ?? 0;
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ export default class DhEnvironment extends BaseDataActor {
|
|||
}
|
||||
|
||||
isItemValid(source) {
|
||||
return source.type === 'feature';
|
||||
return super.isItemValid(source) || source.type === 'feature';
|
||||
}
|
||||
|
||||
_onUpdate(changes, options, userId) {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,17 @@ import BaseDataActor from './base.mjs';
|
|||
import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs';
|
||||
import TagTeamData from '../tagTeamData.mjs';
|
||||
import GroupRollData from '../groupRollData.mjs';
|
||||
import { GoldField } from '../fields/actorField.mjs';
|
||||
|
||||
export default class DhParty extends BaseDataActor {
|
||||
/** @inheritdoc */
|
||||
static get metadata() {
|
||||
return foundry.utils.mergeObject(super.metadata, {
|
||||
hasInventory: true,
|
||||
quantifiable: ['weapon', 'armor', 'loot', 'consumable']
|
||||
});
|
||||
}
|
||||
|
||||
/**@inheritdoc */
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
|
|
@ -11,17 +20,16 @@ export default class DhParty extends BaseDataActor {
|
|||
...super.defineSchema(),
|
||||
partyMembers: new ForeignDocumentUUIDArrayField({ type: 'Actor' }, { prune: true }),
|
||||
notes: new fields.HTMLField(),
|
||||
gold: new fields.SchemaField({
|
||||
coins: new fields.NumberField({ initial: 0, integer: true }),
|
||||
handfuls: new fields.NumberField({ initial: 1, integer: true }),
|
||||
bags: new fields.NumberField({ initial: 0, integer: true }),
|
||||
chests: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
gold: new GoldField(),
|
||||
tagTeam: new fields.EmbeddedDataField(TagTeamData),
|
||||
groupRoll: new fields.EmbeddedDataField(GroupRollData)
|
||||
};
|
||||
}
|
||||
|
||||
get active() {
|
||||
return game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.ActiveParty) === this.parent.id;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**@inheritdoc */
|
||||
|
|
@ -29,10 +37,6 @@ export default class DhParty extends BaseDataActor {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
isItemValid(source) {
|
||||
return ['weapon', 'armor', 'consumable', 'loot'].includes(source.type);
|
||||
}
|
||||
|
||||
prepareBaseData() {
|
||||
super.prepareBaseData();
|
||||
|
||||
|
|
@ -44,6 +48,16 @@ export default class DhParty extends BaseDataActor {
|
|||
}
|
||||
}
|
||||
|
||||
_onCreate(data, options, userId) {
|
||||
super._onCreate(data, options, userId);
|
||||
|
||||
if (game.user.isActiveGM && !game.actors.party) {
|
||||
game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.ActiveParty, this.parent.id).then(_ => {
|
||||
ui.actors.render();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_onDelete(options, userId) {
|
||||
super._onDelete(options, userId);
|
||||
|
||||
|
|
@ -51,5 +65,11 @@ export default class DhParty extends BaseDataActor {
|
|||
for (const member of this.partyMembers) {
|
||||
member?.parties?.delete(this.parent);
|
||||
}
|
||||
|
||||
// If this *was* the active party, delete it. We can't use game.actors.party as this actor was already deleted
|
||||
const isWorldActor = !this.parent?.parent && !this.parent.compendium;
|
||||
const activePartyId = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.ActiveParty);
|
||||
if (isWorldActor && this.id === activePartyId)
|
||||
game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.ActiveParty, null);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { itemAbleRollParse } from '../../../helpers/utils.mjs';
|
||||
import FormulaField from '../formulaField.mjs';
|
||||
|
||||
const fields = foundry.data.fields;
|
||||
|
|
@ -36,13 +37,10 @@ export default class DHSummonField extends fields.ArrayField {
|
|||
const rolls = [];
|
||||
const summonData = [];
|
||||
for (const summon of this.summon) {
|
||||
let count = summon.count;
|
||||
const roll = new Roll(summon.count);
|
||||
if (!roll.isDeterministic) {
|
||||
const roll = new Roll(itemAbleRollParse(summon.count, this.actor, this.item));
|
||||
await roll.evaluate();
|
||||
if (game.modules.get('dice-so-nice')?.active) rolls.push(roll);
|
||||
count = roll.total;
|
||||
}
|
||||
const count = roll.total;
|
||||
if (!roll.isDeterministic && game.modules.get('dice-so-nice')?.active) rolls.push(roll);
|
||||
|
||||
const actor = await DHSummonField.getWorldActor(await foundry.utils.fromUuid(summon.actorUUID));
|
||||
/* Extending summon data in memory so it's available in actionField.toChat. Think it's harmless, but ugly. Could maybe find a better way. */
|
||||
|
|
|
|||
|
|
@ -103,4 +103,15 @@ class ResourcesField extends fields.TypedObjectField {
|
|||
}
|
||||
}
|
||||
|
||||
export { attributeField, ResourcesField, stressDamageReductionRule, bonusField };
|
||||
class GoldField extends fields.SchemaField {
|
||||
constructor() {
|
||||
super({
|
||||
coins: new fields.NumberField({ initial: 0, integer: true }),
|
||||
handfuls: new fields.NumberField({ initial: 1, integer: true }),
|
||||
bags: new fields.NumberField({ initial: 0, integer: true }),
|
||||
chests: new fields.NumberField({ initial: 0, integer: true })
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export { attributeField, ResourcesField, GoldField, stressDamageReductionRule, bonusField };
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
* @property {string} label - A localizable label used on application.
|
||||
* @property {string} type - The system type that this data model represents.
|
||||
* @property {boolean} hasDescription - Indicates whether items of this type have description field
|
||||
* @property {boolean} isQuantifiable - Indicates whether items of this type have quantity field
|
||||
* @property {boolean} isInventoryItem- Indicates whether items of this type is a Inventory Item
|
||||
*/
|
||||
|
||||
|
|
@ -24,7 +23,6 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
|||
type: 'base',
|
||||
hasDescription: false,
|
||||
hasResource: false,
|
||||
isQuantifiable: false,
|
||||
isInventoryItem: false,
|
||||
hasActions: false,
|
||||
hasAttribution: true
|
||||
|
|
@ -83,7 +81,7 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
|||
);
|
||||
}
|
||||
|
||||
if (this.metadata.isQuantifiable)
|
||||
if (this.metadata.isInventoryItem)
|
||||
schema.quantity = new fields.NumberField({ integer: true, initial: 1, min: 0, required: true });
|
||||
|
||||
if (this.metadata.hasActions) schema.actions = new ActionsField();
|
||||
|
|
@ -110,6 +108,8 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
|||
}
|
||||
|
||||
get actionsList() {
|
||||
// No actions on non-characters
|
||||
if (this.actor && this.actor.type !== 'character') return [];
|
||||
return this.actions;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ export default class DHConsumable extends BaseDataItem {
|
|||
label: 'TYPES.Item.consumable',
|
||||
type: 'consumable',
|
||||
hasDescription: true,
|
||||
isQuantifiable: true,
|
||||
isInventoryItem: true,
|
||||
hasActions: true
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ export default class DHLoot extends BaseDataItem {
|
|||
label: 'TYPES.Item.loot',
|
||||
type: 'loot',
|
||||
hasDescription: true,
|
||||
isQuantifiable: true,
|
||||
isInventoryItem: true,
|
||||
hasActions: true
|
||||
});
|
||||
|
|
|
|||
|
|
@ -99,7 +99,9 @@ export default class DHWeapon extends AttachableItem {
|
|||
/* -------------------------------------------- */
|
||||
|
||||
get actionsList() {
|
||||
return [this.attack, ...this.actions];
|
||||
// No actions on non-characters
|
||||
if (this.actor && this.actor.type !== 'character') return [];
|
||||
return [this.attack, ...super.actionsList];
|
||||
}
|
||||
|
||||
get customActions() {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import D20Roll from './d20Roll.mjs';
|
|||
import { parseRallyDice, setDiceSoNiceForDualityRoll } from '../helpers/utils.mjs';
|
||||
|
||||
export default class DualityRoll extends D20Roll {
|
||||
_advantageFaces = 6;
|
||||
_advantageNumber = 1;
|
||||
_rallyIndex;
|
||||
|
||||
|
|
@ -11,6 +10,11 @@ export default class DualityRoll extends D20Roll {
|
|||
super(formula, data, options);
|
||||
this.rallyChoices = this.setRallyChoices();
|
||||
this.guaranteedCritical = options.guaranteedCritical;
|
||||
|
||||
const advantageFaces = data.rules?.roll?.defaultAdvantageDice
|
||||
? Number.parseInt(data.rules.roll.defaultAdvantageDice)
|
||||
: 6;
|
||||
this.advantageFaces = Number.isNaN(advantageFaces) ? 6 : advantageFaces;
|
||||
}
|
||||
|
||||
static messageType = 'dualityRoll';
|
||||
|
|
@ -51,14 +55,6 @@ export default class DualityRoll extends D20Roll {
|
|||
return this.dice[2] instanceof game.system.api.dice.diceTypes.DisadvantageDie ? this.dice[2] : null;
|
||||
}
|
||||
|
||||
get advantageFaces() {
|
||||
return this._advantageFaces;
|
||||
}
|
||||
|
||||
set advantageFaces(faces) {
|
||||
this._advantageFaces = this.getFaces(faces);
|
||||
}
|
||||
|
||||
get advantageNumber() {
|
||||
return this._advantageNumber;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -200,7 +200,6 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect {
|
|||
static effectSafeEval(expression) {
|
||||
let result;
|
||||
try {
|
||||
// eslint-disable-next-line no-new-func
|
||||
const evl = new Function('sandbox', `with (sandbox) { return ${expression}}`);
|
||||
result = evl(Roll.MATH_PROXY);
|
||||
} catch (err) {
|
||||
|
|
|
|||
|
|
@ -113,11 +113,13 @@ export default class DhpActor extends Actor {
|
|||
_onUpdate(changes, options, userId) {
|
||||
super._onUpdate(changes, options, userId);
|
||||
for (const party of this.parties) {
|
||||
party.render();
|
||||
party.render({ parts: ['partyMembers'] });
|
||||
}
|
||||
}
|
||||
|
||||
async _preDelete() {
|
||||
async _preDelete(options, user) {
|
||||
if ((await super._preDelete(options, user)) === false) return false;
|
||||
|
||||
if (this.prototypeToken.actorLink) {
|
||||
game.system.registeredTriggers.unregisterItemTriggers(this.items);
|
||||
} else {
|
||||
|
|
@ -130,7 +132,7 @@ export default class DhpActor extends Actor {
|
|||
_onDelete(options, userId) {
|
||||
super._onDelete(options, userId);
|
||||
for (const party of this.parties) {
|
||||
party.render();
|
||||
party.render({ parts: ['partyMembers'] });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -600,6 +602,7 @@ export default class DhpActor extends Actor {
|
|||
rollData.system = this.system.getRollData();
|
||||
rollData.prof = this.system.proficiency ?? 1;
|
||||
rollData.cast = this.system.spellcastModifier ?? 1;
|
||||
|
||||
return rollData;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,11 @@
|
|||
export default class DhActorCollection extends foundry.documents.collections.Actors {
|
||||
/** @returns the active party */
|
||||
get party() {
|
||||
const id = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.ActiveParty);
|
||||
const actor = game.actors.get(id);
|
||||
return actor?.type === 'party' ? actor : null;
|
||||
}
|
||||
|
||||
/** Ensure companions are initialized after all other subtypes. */
|
||||
_initialize() {
|
||||
super._initialize();
|
||||
|
|
|
|||
|
|
@ -31,8 +31,13 @@ export default class DHItem extends foundry.documents.Item {
|
|||
static async createDocuments(sources, operation) {
|
||||
// Ensure that items being created are valid to the actor its being added to
|
||||
const actor = operation.parent;
|
||||
sources = actor?.system?.isItemValid ? sources.filter(s => actor.system.isItemValid(s)) : sources;
|
||||
return super.createDocuments(sources, operation);
|
||||
const filtered = actor ? sources.filter(s => actor.system.isItemValid(s)) : sources;
|
||||
if (actor && filtered.length === 0 && sources.length > 0) {
|
||||
const itemType = _loc(`TYPES.Item.${sources[0].type}`);
|
||||
const actorType = _loc(`TYPES.Actor.${actor.type}`);
|
||||
ui.notifications.error('DAGGERHEART.ACTORS.Base.CannotAddType', { format: { itemType, actorType } });
|
||||
}
|
||||
return super.createDocuments(filtered, operation);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
|
@ -71,6 +76,13 @@ export default class DHItem extends foundry.documents.Item {
|
|||
return this.system.metadata.isInventoryItem ?? false;
|
||||
}
|
||||
|
||||
/** Returns true if the item can be used */
|
||||
get usable() {
|
||||
const actor = this.actor;
|
||||
const actionsList = this.system.actionsList;
|
||||
return this.isOwner && actor?.type === 'character' && (actionsList?.size || actionsList?.length);
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
static async createDialog(data = {}, createOptions = {}, options = {}) {
|
||||
const { folders, types, template, context = {}, ...dialogOptions } = options;
|
||||
|
|
|
|||
|
|
@ -189,7 +189,13 @@ export const getDeleteKeys = (property, innerProperty, innerPropertyDefaultValue
|
|||
|
||||
// Fix on Foundry native formula replacement for DH
|
||||
const nativeReplaceFormulaData = Roll.replaceFormulaData;
|
||||
Roll.replaceFormulaData = function (formula, data = {}, { missing, warn = false } = {}) {
|
||||
Roll.replaceFormulaData = function (formula, baseData = {}, { missing, warn = false } = {}) {
|
||||
/* Inserting global data */
|
||||
const data = {
|
||||
...baseData,
|
||||
partySize: game.actors?.party?.system.partyMembers.length ?? 0
|
||||
};
|
||||
|
||||
const terms = Object.keys(CONFIG.DH.GENERAL.multiplierTypes).map(type => {
|
||||
return { term: type, default: 1 };
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ export const preloadHandlebarsTemplates = async function () {
|
|||
'templates/generic/tab-navigation.hbs',
|
||||
'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs',
|
||||
'systems/daggerheart/templates/sheets/global/partials/action-item.hbs',
|
||||
'systems/daggerheart/templates/sheets/global/partials/gold.hbs',
|
||||
'systems/daggerheart/templates/sheets/global/partials/domain-card-item.hbs',
|
||||
'systems/daggerheart/templates/sheets/global/partials/item-resource.hbs',
|
||||
'systems/daggerheart/templates/sheets/global/partials/resource-section/resource-section.hbs',
|
||||
|
|
|
|||
|
|
@ -52,6 +52,27 @@ export const registerKeyBindings = () => {
|
|||
reservedModifiers: [],
|
||||
precedence: CONST.KEYBINDING_PRECEDENCE.NORMAL
|
||||
});
|
||||
|
||||
game.keybindings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.keybindings.partySheet, {
|
||||
name: _loc('DAGGERHEART.SETTINGS.Keybindings.partySheet.name'),
|
||||
hint: _loc('DAGGERHEART.SETTINGS.Keybindings.partySheet.hint'),
|
||||
editable: [{ key: 'KeyP' }],
|
||||
onDown: () => {
|
||||
const controlled = canvas.ready ? canvas.tokens.controlled : [];
|
||||
const selectedParty = controlled.find(c => c.actor?.type === 'party')?.actor;
|
||||
const party = selectedParty ?? game.actors.party;
|
||||
if (!party) return;
|
||||
|
||||
const sheet = party.sheet;
|
||||
if (!sheet.rendered) {
|
||||
sheet.render(true);
|
||||
} else if (sheet.minimized) {
|
||||
sheet.maximize();
|
||||
} else {
|
||||
sheet.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const registerMenuSettings = () => {
|
||||
|
|
@ -189,4 +210,11 @@ const registerNonConfigSettings = () => {
|
|||
config: false,
|
||||
type: SpotlightTracker
|
||||
});
|
||||
|
||||
game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.ActiveParty, {
|
||||
scope: 'world',
|
||||
config: false,
|
||||
type: String,
|
||||
default: null
|
||||
});
|
||||
};
|
||||
|
|
|
|||
872
package-lock.json
generated
872
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -17,13 +17,18 @@
|
|||
"pullYMLtoLDB": "node ./tools/pullYMLtoLDB.mjs",
|
||||
"pullYMLtoLDBBuild": "node ./tools/pullYMLtoLDB.mjs --build",
|
||||
"createSymlink": "node ./tools/create-symlink.mjs",
|
||||
"setup:dev": "node ./tools/dev-setup.mjs"
|
||||
"setup:dev": "node ./tools/dev-setup.mjs",
|
||||
"lint": "eslint",
|
||||
"lint:fix": "eslint --fix"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@foundryvtt/foundryvtt-cli": "^1.0.2",
|
||||
"@rollup/plugin-commonjs": "^25.0.7",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"concurrently": "^8.2.2",
|
||||
"eslint": "^10.2.1",
|
||||
"eslint-plugin-prettier": "^5.5.5",
|
||||
"globals": "^17.5.0",
|
||||
"husky": "^9.1.5",
|
||||
"lint-staged": "^15.2.10",
|
||||
"postcss": "^8.4.32",
|
||||
|
|
|
|||
|
|
@ -174,12 +174,9 @@
|
|||
"src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg",
|
||||
"anchorX": 0.5,
|
||||
"anchorY": 0.5,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"fit": "contain",
|
||||
"scaleX": 1,
|
||||
"scaleY": 1,
|
||||
"rotation": 0,
|
||||
"tint": "#ffffff",
|
||||
"alphaThreshold": 0.75
|
||||
},
|
||||
|
|
@ -230,7 +227,7 @@
|
|||
"saturation": 0,
|
||||
"contrast": 0
|
||||
},
|
||||
"detectionModes": [],
|
||||
"detectionModes": {},
|
||||
"occludable": {
|
||||
"radius": 0
|
||||
},
|
||||
|
|
@ -256,7 +253,8 @@
|
|||
"flags": {},
|
||||
"randomImg": false,
|
||||
"appendNumber": false,
|
||||
"prependAdjective": false
|
||||
"prependAdjective": false,
|
||||
"depth": 1
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
|
|
@ -496,34 +494,42 @@
|
|||
"description": "<p><strong>Spend a Fear</strong> to summon a number of @UUID[Compendium.daggerheart.adversaries.Actor.OsLG2BjaEdTZUJU9]{Fallen Shock Troops} equal to twice the number of PCs. The Shock Troops appear at Far range.</p>",
|
||||
"resource": null,
|
||||
"actions": {
|
||||
"hGMzqw00JTlYfHYy": {
|
||||
"type": "effect",
|
||||
"_id": "hGMzqw00JTlYfHYy",
|
||||
"SrU7qbh8LcOgfozT": {
|
||||
"type": "summon",
|
||||
"_id": "SrU7qbh8LcOgfozT",
|
||||
"systemPath": "actions",
|
||||
"baseAction": false,
|
||||
"description": "",
|
||||
"chatDisplay": true,
|
||||
"originItem": {
|
||||
"type": "itemCollection"
|
||||
},
|
||||
"actionType": "action",
|
||||
"triggers": [],
|
||||
"cost": [
|
||||
{
|
||||
"scalable": false,
|
||||
"key": "fear",
|
||||
"value": 1,
|
||||
"step": null
|
||||
"itemId": null,
|
||||
"step": null,
|
||||
"consumeOnSuccess": false
|
||||
}
|
||||
],
|
||||
"uses": {
|
||||
"value": null,
|
||||
"max": "",
|
||||
"recovery": null
|
||||
},
|
||||
"effects": [],
|
||||
"target": {
|
||||
"type": "self",
|
||||
"amount": null
|
||||
"recovery": null,
|
||||
"consumeOnSuccess": false
|
||||
},
|
||||
"summon": [
|
||||
{
|
||||
"actorUUID": "Compendium.daggerheart.adversaries.Actor.OsLG2BjaEdTZUJU9",
|
||||
"count": "@partySize*2"
|
||||
}
|
||||
],
|
||||
"name": "Spend Fear",
|
||||
"img": "icons/magic/death/undead-skeleton-worn-blue.webp",
|
||||
"range": ""
|
||||
"range": "far"
|
||||
}
|
||||
},
|
||||
"originItemType": null,
|
||||
|
|
|
|||
|
|
@ -68,31 +68,33 @@
|
|||
"type": "withinRange",
|
||||
"target": "hostile",
|
||||
"range": "melee"
|
||||
}
|
||||
},
|
||||
"changes": [
|
||||
{
|
||||
"key": "system.resistance.physical.resistance",
|
||||
"mode": 5,
|
||||
"value": "1",
|
||||
"priority": null
|
||||
"type": "override",
|
||||
"value": 1,
|
||||
"priority": null,
|
||||
"phase": "initial"
|
||||
},
|
||||
{
|
||||
"key": "system.disadvantageSources",
|
||||
"mode": 2,
|
||||
"value": "Retract",
|
||||
"priority": null
|
||||
"type": "add",
|
||||
"value": "Action rolls",
|
||||
"priority": null,
|
||||
"phase": "initial"
|
||||
}
|
||||
],
|
||||
"duration": {
|
||||
"type": ""
|
||||
}
|
||||
},
|
||||
"disabled": true,
|
||||
"duration": {
|
||||
"startTime": null,
|
||||
"combat": null,
|
||||
"seconds": null,
|
||||
"rounds": null,
|
||||
"turns": null,
|
||||
"startRound": null,
|
||||
"startTurn": null
|
||||
"value": null,
|
||||
"units": "seconds",
|
||||
"expiry": null,
|
||||
"expired": false
|
||||
},
|
||||
"description": "<p>While in your shell, you have resistance to physical damage, you have disadvantage on action rolls, and you can’t move.</p>",
|
||||
"tint": "#ffffff",
|
||||
|
|
@ -102,6 +104,16 @@
|
|||
"_stats": {
|
||||
"compendiumSource": null
|
||||
},
|
||||
"start": {
|
||||
"time": 0,
|
||||
"combat": null,
|
||||
"combatant": null,
|
||||
"initiative": null,
|
||||
"round": null,
|
||||
"turn": null
|
||||
},
|
||||
"showIcon": 1,
|
||||
"folder": null,
|
||||
"_key": "!items.effects!UFR67BUOhNGLFyg9.3V4FPoyjJUnFP9WS"
|
||||
}
|
||||
],
|
||||
|
|
|
|||
|
|
@ -29,39 +29,28 @@
|
|||
"type": "withinRange",
|
||||
"target": "hostile",
|
||||
"range": "melee"
|
||||
}
|
||||
},
|
||||
"changes": [
|
||||
{
|
||||
"key": "system.advantageSources",
|
||||
"mode": 2,
|
||||
"value": "In an area with low light or heavy shadow: hide, investigate, or perceive",
|
||||
"priority": null
|
||||
},
|
||||
{
|
||||
"key": "system.advantageSources",
|
||||
"mode": 2,
|
||||
"value": "",
|
||||
"priority": null
|
||||
},
|
||||
{
|
||||
"key": "",
|
||||
"mode": 2,
|
||||
"value": "",
|
||||
"priority": null
|
||||
"type": "add",
|
||||
"value": "Rolls to hide, investigate, or perceive details in low light",
|
||||
"priority": null,
|
||||
"phase": "initial"
|
||||
}
|
||||
],
|
||||
"duration": {
|
||||
"type": ""
|
||||
}
|
||||
},
|
||||
"disabled": false,
|
||||
"duration": {
|
||||
"startTime": null,
|
||||
"combat": null,
|
||||
"seconds": null,
|
||||
"rounds": null,
|
||||
"turns": null,
|
||||
"startRound": null,
|
||||
"startTurn": null
|
||||
"value": null,
|
||||
"units": "seconds",
|
||||
"expiry": null,
|
||||
"expired": false
|
||||
},
|
||||
"description": "",
|
||||
"description": "<p>When you’re in an area with low light or heavy shadow, you have advantage on rolls to hide, investigate, or perceive details within that area.</p>",
|
||||
"origin": null,
|
||||
"tint": "#ffffff",
|
||||
"transfer": true,
|
||||
|
|
@ -71,6 +60,16 @@
|
|||
"_stats": {
|
||||
"compendiumSource": null
|
||||
},
|
||||
"start": {
|
||||
"time": 0,
|
||||
"combat": null,
|
||||
"combatant": null,
|
||||
"initiative": null,
|
||||
"round": null,
|
||||
"turn": null
|
||||
},
|
||||
"showIcon": 1,
|
||||
"folder": null,
|
||||
"_key": "!items.effects!aMla3xQuCHEwORGD.pCp32u7UwqxCI4WW"
|
||||
}
|
||||
],
|
||||
|
|
|
|||
|
|
@ -132,27 +132,29 @@
|
|||
"type": "withinRange",
|
||||
"target": "hostile",
|
||||
"range": "melee"
|
||||
}
|
||||
},
|
||||
"changes": [
|
||||
{
|
||||
"key": "system.advantageSources",
|
||||
"mode": 2,
|
||||
"value": "1",
|
||||
"priority": null
|
||||
"type": "add",
|
||||
"value": "On Attacks",
|
||||
"priority": null,
|
||||
"phase": "initial"
|
||||
}
|
||||
],
|
||||
"duration": {
|
||||
"type": "temporary",
|
||||
"description": "<p>Until you or an ally rolls a failure with Fear.</p>"
|
||||
}
|
||||
},
|
||||
"disabled": false,
|
||||
"duration": {
|
||||
"startTime": null,
|
||||
"combat": null,
|
||||
"seconds": null,
|
||||
"rounds": null,
|
||||
"turns": null,
|
||||
"startRound": null,
|
||||
"startTurn": null
|
||||
"value": null,
|
||||
"units": "seconds",
|
||||
"expiry": null,
|
||||
"expired": false
|
||||
},
|
||||
"description": "",
|
||||
"description": "<p>You gain advantage on attack rolls until you or an ally rolls a failure with Fear.</p>",
|
||||
"tint": "#ffffff",
|
||||
"statuses": [],
|
||||
"sort": 0,
|
||||
|
|
@ -160,6 +162,16 @@
|
|||
"_stats": {
|
||||
"compendiumSource": null
|
||||
},
|
||||
"start": {
|
||||
"time": 0,
|
||||
"combat": null,
|
||||
"combatant": null,
|
||||
"initiative": null,
|
||||
"round": null,
|
||||
"turn": null
|
||||
},
|
||||
"showIcon": 1,
|
||||
"folder": null,
|
||||
"_key": "!items.effects!Ef1JsUG50LIoKx2F.s7ma4TNgAvt0ZgEW"
|
||||
}
|
||||
],
|
||||
|
|
|
|||
|
|
@ -52,12 +52,9 @@
|
|||
"src": "systems/daggerheart/assets/icons/documents/actors/forest.svg",
|
||||
"anchorX": 0.5,
|
||||
"anchorY": 0.5,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"fit": "contain",
|
||||
"scaleX": 1,
|
||||
"scaleY": 1,
|
||||
"rotation": 0,
|
||||
"tint": "#ffffff",
|
||||
"alphaThreshold": 0.75
|
||||
},
|
||||
|
|
@ -108,7 +105,7 @@
|
|||
"saturation": 0,
|
||||
"contrast": 0
|
||||
},
|
||||
"detectionModes": [],
|
||||
"detectionModes": {},
|
||||
"occludable": {
|
||||
"radius": 0
|
||||
},
|
||||
|
|
@ -134,7 +131,8 @@
|
|||
"flags": {},
|
||||
"randomImg": false,
|
||||
"appendNumber": false,
|
||||
"prependAdjective": false
|
||||
"prependAdjective": false,
|
||||
"depth": 1
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
|
|
@ -323,7 +321,42 @@
|
|||
"system": {
|
||||
"description": "<p>A @UUID[Compendium.daggerheart.adversaries.Actor.8yUj2Mzvnifhxegm]{Young Dryad}, two @UUID[Compendium.daggerheart.adversaries.Actor.VtFBt9XBE0WrGGxP]{Sylvan Soldiers}, and a number of @UUID[Compendium.daggerheart.adversaries.Actor.G62k4oSkhkoXEs2D]{Minor Treants} equal to the number of PCs appear to confront the party for their intrusion.</p><section id=\"secret-01hkXuVJc5Kei4QW\" class=\"secret\"><p><em>What are the grove guardians concealing? What threat to the forest could the PCs confront to appease the Dryad?</em></p></section>",
|
||||
"resource": null,
|
||||
"actions": {},
|
||||
"actions": {
|
||||
"TPm6rpKA4mbili82": {
|
||||
"type": "summon",
|
||||
"_id": "TPm6rpKA4mbili82",
|
||||
"systemPath": "actions",
|
||||
"baseAction": false,
|
||||
"description": "",
|
||||
"chatDisplay": true,
|
||||
"originItem": {
|
||||
"type": "itemCollection"
|
||||
},
|
||||
"actionType": "action",
|
||||
"triggers": [],
|
||||
"cost": [],
|
||||
"uses": {
|
||||
"value": null,
|
||||
"max": null,
|
||||
"recovery": null,
|
||||
"consumeOnSuccess": false
|
||||
},
|
||||
"summon": [
|
||||
{
|
||||
"actorUUID": "Compendium.daggerheart.adversaries.Actor.8yUj2Mzvnifhxegm",
|
||||
"count": "1"
|
||||
},
|
||||
{
|
||||
"actorUUID": "Compendium.daggerheart.adversaries.Actor.VtFBt9XBE0WrGGxP",
|
||||
"count": "2"
|
||||
},
|
||||
{
|
||||
"actorUUID": "Compendium.daggerheart.adversaries.Actor.G62k4oSkhkoXEs2D",
|
||||
"count": "@partySize"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"originItemType": null,
|
||||
"originId": null,
|
||||
"featureForm": "action"
|
||||
|
|
|
|||
|
|
@ -175,6 +175,11 @@
|
|||
opacity: 0.2;
|
||||
}
|
||||
|
||||
&.no-horizontal-padding {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
|
@ -250,6 +255,11 @@
|
|||
height: 65px;
|
||||
background: url(../assets/svg/trait-shield.svg) no-repeat;
|
||||
background-size: 100%;
|
||||
padding-top: 3px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
row-gap: 3px;
|
||||
|
||||
div {
|
||||
filter: drop-shadow(0 0 3px black);
|
||||
|
|
@ -278,6 +288,15 @@
|
|||
flex-direction: column;
|
||||
gap: 5px;
|
||||
|
||||
&.separated {
|
||||
border-bottom: 2px solid;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
padding: 0 0.75rem;
|
||||
}
|
||||
|
||||
.experience-inner-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -27,10 +27,11 @@
|
|||
height: 65px;
|
||||
background: url(../assets/svg/trait-shield.svg) no-repeat;
|
||||
background-size: 100%;
|
||||
padding-top: 4px;
|
||||
padding-top: 3px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
row-gap: 3px;
|
||||
|
||||
span {
|
||||
font-size: var(--font-size-10);
|
||||
|
|
|
|||
|
|
@ -37,6 +37,59 @@
|
|||
color: light-dark(@chat-blue-bg, @beige-50);
|
||||
}
|
||||
|
||||
.tab.inventory {
|
||||
.search-section {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
.search-bar {
|
||||
position: relative;
|
||||
color: light-dark(@dark-blue-50, @beige-50);
|
||||
width: 100%;
|
||||
padding-top: 5px;
|
||||
|
||||
input {
|
||||
border-radius: 50px;
|
||||
background: light-dark(@dark-blue-10, @golden-10);
|
||||
border: none;
|
||||
outline: 2px solid transparent;
|
||||
transition: all 0.3s ease;
|
||||
padding: 0 20px;
|
||||
|
||||
&:hover {
|
||||
outline: 2px solid light-dark(@dark, @golden);
|
||||
}
|
||||
|
||||
&::-webkit-search-cancel-button {
|
||||
-webkit-appearance: none;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
align-content: center;
|
||||
height: 32px;
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
font-size: 16px;
|
||||
z-index: 1;
|
||||
color: light-dark(@dark-blue-50, @beige-50);
|
||||
}
|
||||
}
|
||||
|
||||
.gold-section {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
gap: 10px;
|
||||
padding: 10px 10px 0;
|
||||
|
||||
.input {
|
||||
color: light-dark(@dark, @beige);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.limited {
|
||||
&.character,
|
||||
&.adversary,
|
||||
|
|
|
|||
|
|
@ -3,47 +3,6 @@
|
|||
|
||||
.application.sheet.daggerheart.actor.dh-style.character {
|
||||
.tab.inventory {
|
||||
.search-section {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
|
||||
.search-bar {
|
||||
position: relative;
|
||||
color: light-dark(@dark-blue-50, @beige-50);
|
||||
width: 100%;
|
||||
padding-top: 5px;
|
||||
|
||||
input {
|
||||
border-radius: 50px;
|
||||
background: light-dark(@dark-blue-10, @golden-10);
|
||||
border: none;
|
||||
outline: 2px solid transparent;
|
||||
transition: all 0.3s ease;
|
||||
padding: 0 20px;
|
||||
|
||||
&:hover {
|
||||
outline: 2px solid light-dark(@dark, @golden);
|
||||
}
|
||||
|
||||
&::-webkit-search-cancel-button {
|
||||
-webkit-appearance: none;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
align-content: center;
|
||||
height: 32px;
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
font-size: var(--font-size-16);
|
||||
z-index: 1;
|
||||
color: light-dark(@dark-blue-50, @beige-50);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.items-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
@ -55,16 +14,5 @@
|
|||
scrollbar-width: thin;
|
||||
scrollbar-color: light-dark(@dark-blue, @golden) transparent;
|
||||
}
|
||||
|
||||
.currency-section {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
gap: 10px;
|
||||
padding: 10px 10px 0;
|
||||
|
||||
.input {
|
||||
color: light-dark(@dark, @beige);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,21 +11,6 @@
|
|||
padding-bottom: 0;
|
||||
overflow-x: auto;
|
||||
|
||||
&.viewMode {
|
||||
button:not(.btn-toggle-view),
|
||||
input:not(.search),
|
||||
.controls,
|
||||
.character-sidebar-sheet,
|
||||
.img-portait,
|
||||
.name-row,
|
||||
.hope-section,
|
||||
.downtime-section,
|
||||
.character-traits,
|
||||
.card-list {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.character-sidebar-sheet {
|
||||
grid-row: 1 / span 2;
|
||||
grid-column: 1;
|
||||
|
|
|
|||
|
|
@ -316,9 +316,9 @@
|
|||
border-radius: 3px;
|
||||
background: light-dark(@dark-blue, @golden);
|
||||
clip-path: none;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
border: 1px solid transparent;
|
||||
transition: all 0.3s ease;
|
||||
|
|
|
|||
|
|
@ -3,51 +3,6 @@
|
|||
|
||||
.application.sheet.daggerheart.actor.dh-style.party {
|
||||
.tab.inventory {
|
||||
.search-section {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
|
||||
.search-bar {
|
||||
position: relative;
|
||||
color: light-dark(@dark-blue-50, @beige-50);
|
||||
width: 100%;
|
||||
padding-top: 5px;
|
||||
|
||||
input {
|
||||
border-radius: 50px;
|
||||
background: light-dark(@dark-blue-10, @golden-10);
|
||||
border: none;
|
||||
outline: 2px solid transparent;
|
||||
transition: all 0.3s ease;
|
||||
padding: 0 20px;
|
||||
|
||||
&:hover {
|
||||
outline: 2px solid light-dark(@dark, @golden);
|
||||
}
|
||||
|
||||
&:placeholder {
|
||||
color: light-dark(@dark-blue-50, @beige-50);
|
||||
}
|
||||
|
||||
&::-webkit-search-cancel-button {
|
||||
-webkit-appearance: none;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
align-content: center;
|
||||
height: 32px;
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
font-size: 16px;
|
||||
z-index: 1;
|
||||
color: light-dark(@dark-blue-50, @beige-50);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.items-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
@ -59,16 +14,5 @@
|
|||
scrollbar-width: thin;
|
||||
scrollbar-color: light-dark(@dark-blue, @golden) transparent;
|
||||
}
|
||||
|
||||
.currency-section {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
gap: 10px;
|
||||
padding: 10px 10px 0;
|
||||
|
||||
.input {
|
||||
color: light-dark(@dark, @beige);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@ body.game:is(.performance-low, .noblur) {
|
|||
|
||||
.actor-img-frame {
|
||||
grid-area: img;
|
||||
width: 7.5rem;
|
||||
height: 7.5rem;
|
||||
width: 7.375rem;
|
||||
height: 7.375rem;
|
||||
position: relative;
|
||||
|
||||
.actor-img {
|
||||
|
|
@ -71,6 +71,7 @@ body.game:is(.performance-low, .noblur) {
|
|||
height: 1.75rem;
|
||||
background: url('../assets/svg/trait-shield.svg') no-repeat;
|
||||
background-size: 100%;
|
||||
color: var(--color-light-1);
|
||||
font-size: var(--font-size-14);
|
||||
font-weight: 700;
|
||||
display: flex;
|
||||
|
|
@ -87,7 +88,7 @@ body.game:is(.performance-low, .noblur) {
|
|||
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
background-color: light-dark(transparent, @dark-blue);
|
||||
background-color: light-dark(var(--color-light-1), @dark-blue);
|
||||
color: light-dark(@dark-blue, @golden);
|
||||
padding: 4px 6px;
|
||||
border: 1px solid light-dark(@dark-blue, @golden);
|
||||
|
|
@ -125,7 +126,7 @@ body.game:is(.performance-low, .noblur) {
|
|||
width: 100%;
|
||||
z-index: 1;
|
||||
font-size: var(--font-size-20);
|
||||
color: light-dark(@beige, @golden);
|
||||
color: light-dark(@dark-blue, @golden);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
</div>
|
||||
|
||||
{{!-- Handlebars uses Symbol.Iterator to produce index|key. This isn't compatible with our parts object, so we instead use applyTo, which is the same value --}}
|
||||
{{#each source.parts as |dmg|}}
|
||||
{{#each source.parts as |dmg key|}}
|
||||
<div class="nest-inputs">
|
||||
<fieldset{{#if dmg.base}} disabled{{/if}} class="one-column{{#if ../path}} no-style{{/if}}">
|
||||
<legend class="with-icon">
|
||||
|
|
@ -31,6 +31,7 @@
|
|||
{{/unless}}
|
||||
</legend>
|
||||
|
||||
{{#unless (and @root.source.damage.includeBase (eq key 'hitPoints'))}}
|
||||
{{#if (and (not @root.isNPC) @root.hasRoll (not dmg.base))}}
|
||||
{{formField ../fields.resultBased value=dmg.resultBased name=(concat "damage.parts." dmg.applyTo ".resultBased") localize=true classes="checkbox"}}
|
||||
{{/if}}
|
||||
|
|
@ -65,6 +66,9 @@
|
|||
</fieldset>
|
||||
{{/if}}
|
||||
<input type="hidden" name="{{concat ../path "damage.parts." dmg.applyTo ".base"}}" value="{{dmg.base}}">
|
||||
{{else}}
|
||||
<span class="hint">{{localize "DAGGERHEART.ACTIONS.Config.itemDamageIsUsed"}}</span>
|
||||
{{/unless}}
|
||||
</fieldset>
|
||||
</div>
|
||||
{{/each}}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<fieldset class="one-column{{#if source.useDefault}} child-disabled{{/if}}">
|
||||
<legend>
|
||||
Roll
|
||||
{{#if @root.hasBaseDamage}}{{formInput fields.useDefault name="roll.useDefault" value=source.useDefault dataset=(object tooltip="Use default Item values" tooltipDirection="UP")}}{{/if}}
|
||||
{{localize "DAGGERHEART.GENERAL.roll"}}
|
||||
{{#if @root.hasBaseDamage}}{{formInput fields.useDefault name="roll.useDefault" value=source.useDefault dataset=(object tooltip=(localize "DAGGERHEART.ACTIONS.Config.useDefaultItemValues") tooltipDirection="UP")}}{{/if}}
|
||||
</legend>
|
||||
|
||||
{{formField fields.type label="DAGGERHEART.GENERAL.type" name="roll.type" value=source.type localize=true choices=@root.getRollTypeOptions localize=true}}
|
||||
|
|
|
|||
|
|
@ -4,18 +4,26 @@
|
|||
data-group='{{tabs.experience.group}}'
|
||||
>
|
||||
<div class="main-selections-container">
|
||||
<fieldset class="section-container">
|
||||
<fieldset class="section-container no-horizontal-padding">
|
||||
<legend>{{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.initialExperiences"}} {{experience.nrSelected}}/{{experience.nrTotal}}</legend>
|
||||
<div class="experiences-inner-container">
|
||||
{{#each experience.values as |experience id|}}
|
||||
<div class="experience-container">
|
||||
<div class="experience-container {{#unless @last}}separated{{/unless}}">
|
||||
<div class="form-group">
|
||||
<label>{{localize "DAGGERHEART.GENERAL.label"}}</label>
|
||||
<div class="experience-inner-container">
|
||||
<input class="experience-description" type="text" name="{{concat "experiences." id ".name" }}" value="{{experience.name}}" placeholder="{{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.newExperience"}}" />
|
||||
<span class="experience-value">{{numberFormat this.value sign=true}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>{{localize "DAGGERHEART.GENERAL.optionalThing" thing=(localize "DAGGERHEART.GENERAL.description")}}</label>
|
||||
<div class="form-fields">
|
||||
<textarea name="{{concat "experiences." id ".description"}}">{{experience.description}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</fieldset>
|
||||
|
|
|
|||
|
|
@ -28,6 +28,6 @@
|
|||
</div>
|
||||
</fieldset>
|
||||
|
||||
<button type="button" data-action="finishSelection">{{localize "ACTIONS.Reset"}}</button>
|
||||
<button type="button" data-action="finishSelection">{{localize "SETTINGS.UI.ACTIONS.Reset"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
<footer>
|
||||
<button data-action="finish">{{localize "Save Settings"}}</button>
|
||||
<button data-action="finish">{{localize "DAGGERHEART.GENERAL.saveSettings"}}</button>
|
||||
</footer>
|
||||
|
|
@ -157,8 +157,8 @@
|
|||
<option value="{{add this 1}}" {{#if (eq @root.roll.advantageNumber (add this 1))}} selected{{/if}}>{{add this 1}}</option>
|
||||
{{/times}}
|
||||
</select>
|
||||
<select name="roll.dice.advantageFaces"{{#unless advantage}} disabled{{/unless}}>
|
||||
{{selectOptions diceOptions selected=(concat 'd' @root.roll.advantageFaces)}}
|
||||
<select name="roll.dice.advantageFaces"{{#unless advantage}} disabled{{/unless}} data-dtype="Number">
|
||||
{{selectOptions dieFaces selected=@root.roll.advantageFaces}}
|
||||
</select>
|
||||
</div>
|
||||
{{#if abilities}}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
<div class="form-group">
|
||||
<label>{{localize "DAGGERHEART.GENERAL.quantity"}}</label>
|
||||
<div class="form-fields">
|
||||
<range-picker step="1" min="1" max="{{max}}" name="quantity" value="{{max}}"></range-picker>
|
||||
<range-picker step="1" min="1" max="{{max}}" name="quantity" value="{{initial}}"></range-picker>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<footer class="form-footer">
|
||||
<button data-action="reset">
|
||||
<i class="fa-solid fa-arrow-rotate-left"></i>
|
||||
<span>{{localize "ACTIONS.Reset"}}</span>
|
||||
<span>{{localize "SETTINGS.UI.ACTIONS.Reset"}}</span>
|
||||
</button>
|
||||
<button data-action="save" >
|
||||
<i class="fa-solid fa-floppy-disk"></i>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
<div class="settings-items">
|
||||
{{#each move.actions as |action|}}
|
||||
{{> "systems/daggerheart/templates/settings/components/settings-item-line.hbs" id=action.id }}
|
||||
{{> "systems/daggerheart/templates/settings/components/settings-item-line.hbs" id=action.id type="action" }}
|
||||
{{/each}}
|
||||
</div>
|
||||
</fieldset>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<footer class="form-footer">
|
||||
<button type="button" data-action="reset">
|
||||
<i class="fa-solid fa-arrow-rotate-left"></i>
|
||||
<span>{{localize "ACTIONS.Reset"}}</span>
|
||||
<span>{{localize "SETTINGS.UI.ACTIONS.Reset"}}</span>
|
||||
</button>
|
||||
<button type="button" data-action="save" >
|
||||
<i class="fa-solid fa-floppy-disk"></i>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<footer class="form-footer">
|
||||
<button data-action="reset">
|
||||
<i class="fa-solid fa-arrow-rotate-left"></i>
|
||||
<span>{{localize "ACTIONS.Reset"}}</span>
|
||||
<span>{{localize "SETTINGS.UI.ACTIONS.Reset"}}</span>
|
||||
</button>
|
||||
<button data-action="save" >
|
||||
<i class="fa-solid fa-floppy-disk"></i>
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
<footer class="form-footer">
|
||||
<button data-action="reset">
|
||||
<i class="fa-solid fa-arrow-rotate-left"></i>
|
||||
<span>{{localize "ACTIONS.ResetReset"}}</span>
|
||||
<span>{{localize "SETTINGS.UI.ACTIONS.ResetReset"}}</span>
|
||||
</button>
|
||||
<button data-action="save" >
|
||||
<i class="fa-solid fa-floppy-disk"></i>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
{{formGroup systemFields.duration.fields.type value=source.system.duration.type localize=true }}
|
||||
|
||||
<div class="form-group slim duration-description">
|
||||
<div class="form-group slim duration-description {{#if (eq source.system.duration.type 'temporary')}}visible{{/if}}">
|
||||
<div class="form-fields">
|
||||
{{formInput systemFields.duration.fields.description value=source.system.duration.description localize=true }}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
type='effect'
|
||||
isGlassy=true
|
||||
collection=effects.actives
|
||||
canCreate=true
|
||||
canCreate=@root.editable
|
||||
hideResources=true
|
||||
}}
|
||||
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
type='effect'
|
||||
isGlassy=true
|
||||
collection=effects.inactives
|
||||
canCreate=true
|
||||
canCreate=@root.editable
|
||||
hideResources=true
|
||||
}}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
type='feature'
|
||||
collection=@root.features
|
||||
hideContextMenu=true
|
||||
canCreate=true
|
||||
showActions=true
|
||||
canCreate=@root.editable
|
||||
showActions=@root.editable
|
||||
}}
|
||||
</div>
|
||||
</section>
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
type='effect'
|
||||
isGlassy=true
|
||||
collection=effects.actives
|
||||
canCreate=true
|
||||
canCreate=@root.editable
|
||||
hideResources=true
|
||||
}}
|
||||
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
type='effect'
|
||||
isGlassy=true
|
||||
collection=effects.inactives
|
||||
canCreate=true
|
||||
canCreate=@root.editable
|
||||
hideResources=true
|
||||
disabled=true
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
type='feature'
|
||||
actorType='character'
|
||||
collection=category.values
|
||||
canCreate=true
|
||||
showActions=true
|
||||
canCreate=@root.editable
|
||||
showActions=@root.editable
|
||||
}}
|
||||
{{else if category.values}}
|
||||
{{> 'daggerheart.inventory-items'
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
actorType='character'
|
||||
collection=category.values
|
||||
canCreate=false
|
||||
showActions=true
|
||||
showActions=@root.editable
|
||||
}}
|
||||
|
||||
{{/if}}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<h1 class="actor-name input" contenteditable="plaintext-only" data-property="name" placeholder="{{localize "DAGGERHEART.GENERAL.actorName"}}">{{source.name}}</h1>
|
||||
<div class='level-div'>
|
||||
<h3 class='label'>
|
||||
{{#if @root.editable}}
|
||||
{{#if document.system.needsCharacterSetup}}
|
||||
<button
|
||||
type="button"
|
||||
|
|
@ -21,6 +22,7 @@
|
|||
<i class="fa-solid fa-angles-up"></i>
|
||||
</button>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{#unless document.system.needsCharacterSetup}}
|
||||
{{localize 'DAGGERHEART.GENERAL.level'}}
|
||||
<input type="text" data-dtype="Number" class="level-value" value={{#if document.system.needsCharacterSetup}}0{{else}}{{document.system.levelData.level.changed}}{{/if}} {{#if document.system.needsCharacterSetup}}disabled{{/if}} />
|
||||
|
|
@ -110,12 +112,14 @@
|
|||
<i class="fa-solid fa-fw fa-users"></i>
|
||||
</button>
|
||||
{{/if}}
|
||||
{{#if @root.editable}}
|
||||
<button type="button" data-action="useDowntime" data-type="shortRest" data-tooltip="DAGGERHEART.APPLICATIONS.Downtime.shortRest.title">
|
||||
<i class="fa-solid fa-fw fa-utensils"></i>
|
||||
</button>
|
||||
<button type="button" data-action="useDowntime" data-type="longRest" data-tooltip="DAGGERHEART.APPLICATIONS.Downtime.longRest.title">
|
||||
<i class="fa-solid fa-fw fa-bed"></i>
|
||||
</button>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -13,18 +13,7 @@
|
|||
</div>
|
||||
|
||||
{{#if this.inventory.hasCurrency}}
|
||||
<div class="currency-section">
|
||||
{{#each this.inventory.currencies as |currency key|}}
|
||||
{{#if currency.enabled}}
|
||||
<div class="input currency" data-currency="{{key}}">
|
||||
<span class="drag-handle">
|
||||
<i class="{{currency.icon}}" inert></i> {{localize currency.label}}
|
||||
</span>
|
||||
<input type="text" name="{{currency.field.fieldPath}}" data-allow-delta value="{{currency.value}}" data-dtype="Number" min="0" step="1" />
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
</div>
|
||||
{{> "systems/daggerheart/templates/sheets/global/partials/gold.hbs" currencies=inventory.currencies}}
|
||||
{{/if}}
|
||||
|
||||
<div class="items-section">
|
||||
|
|
@ -33,7 +22,7 @@
|
|||
type='weapon'
|
||||
collection=@root.inventory.weapons
|
||||
isGlassy=true
|
||||
canCreate=true
|
||||
canCreate=@root.editable
|
||||
hideResources=true
|
||||
}}
|
||||
{{> 'daggerheart.inventory-items'
|
||||
|
|
@ -41,7 +30,7 @@
|
|||
type='armor'
|
||||
collection=@root.inventory.armor
|
||||
isGlassy=true
|
||||
canCreate=true
|
||||
canCreate=@root.editable
|
||||
hideResources=true
|
||||
}}
|
||||
{{> 'daggerheart.inventory-items'
|
||||
|
|
@ -49,15 +38,17 @@
|
|||
type='consumable'
|
||||
collection=@root.inventory.consumables
|
||||
isGlassy=true
|
||||
canCreate=true
|
||||
canCreate=@root.editable
|
||||
isQuantifiable=true
|
||||
}}
|
||||
{{> 'daggerheart.inventory-items'
|
||||
title='TYPES.Item.loot'
|
||||
type='loot'
|
||||
collection=@root.inventory.loot
|
||||
isGlassy=true
|
||||
canCreate=true
|
||||
showActions=true
|
||||
canCreate=@root.editable
|
||||
showActions=@root.editable
|
||||
isQuantifiable=true
|
||||
}}
|
||||
</div>
|
||||
</section>
|
||||
|
|
@ -27,7 +27,7 @@
|
|||
isGlassy=true
|
||||
cardView=cardView
|
||||
collection=document.system.domainCards.loadout
|
||||
canCreate=true
|
||||
canCreate=@root.editable
|
||||
}}
|
||||
{{> 'daggerheart.inventory-items'
|
||||
title='DAGGERHEART.GENERAL.Tabs.vault'
|
||||
|
|
@ -35,7 +35,7 @@
|
|||
isGlassy=true
|
||||
cardView=cardView
|
||||
collection=document.system.domainCards.vault
|
||||
canCreate=true
|
||||
canCreate=@root.editable
|
||||
inVault=true
|
||||
}}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -45,11 +45,11 @@
|
|||
</a>
|
||||
{{/times}}
|
||||
</div>
|
||||
<a class="slot-label" data-action="toggleArmorMangement">
|
||||
<a class="slot-label" data-action="toggleArmorMangement" {{disabled (not @root.editable)}}>
|
||||
<span class="label">{{localize "DAGGERHEART.GENERAL.armorSlots"}}</span>
|
||||
<div class="slot-value-container">
|
||||
<span class="value">{{document.system.armorScore.value}} / {{document.system.armorScore.max}}</span>
|
||||
<i class="fa-solid fa-gear"></i>
|
||||
{{#if @root.editable}}<i class="fa-solid fa-gear" inert></i>{{/if}}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
|
@ -64,9 +64,9 @@
|
|||
value='{{document.system.armorScore.value}}'
|
||||
max='{{document.system.armorScore.max}}'
|
||||
></progress>
|
||||
<a class="status-label" data-action="toggleArmorMangement">
|
||||
<a class="status-label" data-action="toggleArmorMangement" {{disabled (not @root.editable)}}>
|
||||
<h4>{{localize "DAGGERHEART.GENERAL.armorSlots"}}</h4>
|
||||
<i class="fa-solid fa-gear"></i>
|
||||
{{#if @root.editable}}<i class="fa-solid fa-gear" inert></i>{{/if}}
|
||||
</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
type='effect'
|
||||
isGlassy=true
|
||||
collection=effects.actives
|
||||
canCreate=true
|
||||
canCreate=@root.editable
|
||||
hideResources=true
|
||||
}}
|
||||
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
type='effect'
|
||||
isGlassy=true
|
||||
collection=effects.inactives
|
||||
canCreate=true
|
||||
canCreate=@root.editable
|
||||
hideResources=true
|
||||
}}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
type='feature'
|
||||
collection=@root.features
|
||||
hideContextMenu=true
|
||||
canCreate=true
|
||||
showActions=true
|
||||
canCreate=@root.editable
|
||||
showActions=@root.editable
|
||||
}}
|
||||
</div>
|
||||
</section>
|
||||
|
|
@ -16,18 +16,7 @@
|
|||
</div>
|
||||
|
||||
{{#if inventory.hasCurrency}}
|
||||
<div class="currency-section">
|
||||
{{#each this.inventory.currencies as |currency key|}}
|
||||
{{#if currency.enabled}}
|
||||
<div class="input currency" data-currency="{{key}}">
|
||||
<span class="drag-handle">
|
||||
<i class="{{currency.icon}}" inert></i> {{localize currency.label}}
|
||||
</span>
|
||||
<input type="text" name="{{currency.field.fieldPath}}" data-allow-delta value="{{currency.value}}" data-dtype="Number" min="0" step="1" />
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
</div>
|
||||
{{> "systems/daggerheart/templates/sheets/global/partials/gold.hbs" currencies=inventory.currencies}}
|
||||
{{/if}}
|
||||
|
||||
<div class="items-section">
|
||||
|
|
@ -37,9 +26,10 @@
|
|||
actorType='party'
|
||||
collection=@root.inventory.weapons
|
||||
isGlassy=true
|
||||
canCreate=true
|
||||
canCreate=@root.editable
|
||||
hideResources=true
|
||||
hideContextMenu=true
|
||||
isQuantifiable=true
|
||||
}}
|
||||
{{> 'daggerheart.inventory-items'
|
||||
title='TYPES.Item.armor'
|
||||
|
|
@ -47,9 +37,10 @@
|
|||
actorType='party'
|
||||
collection=@root.inventory.armor
|
||||
isGlassy=true
|
||||
canCreate=true
|
||||
canCreate=@root.editable
|
||||
hideResources=true
|
||||
hideContextMenu=true
|
||||
isQuantifiable=true
|
||||
}}
|
||||
{{> 'daggerheart.inventory-items'
|
||||
title='TYPES.Item.consumable'
|
||||
|
|
@ -57,8 +48,9 @@
|
|||
actorType='party'
|
||||
collection=@root.inventory.consumables
|
||||
isGlassy=true
|
||||
canCreate=true
|
||||
canCreate=@root.editable
|
||||
hideContextMenu=true
|
||||
isQuantifiable=true
|
||||
}}
|
||||
{{> 'daggerheart.inventory-items'
|
||||
title='TYPES.Item.loot'
|
||||
|
|
@ -66,8 +58,9 @@
|
|||
actorType='party'
|
||||
collection=@root.inventory.loot
|
||||
isGlassy=true
|
||||
canCreate=true
|
||||
canCreate=@root.editable
|
||||
hideContextMenu=true
|
||||
isQuantifiable=true
|
||||
}}
|
||||
</div>
|
||||
</section>
|
||||
12
templates/sheets/global/partials/gold.hbs
Normal file
12
templates/sheets/global/partials/gold.hbs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<div class="gold-section">
|
||||
{{#each currencies as |currency key|}}
|
||||
{{#if currency.enabled}}
|
||||
<div class="input currency" data-currency="{{key}}">
|
||||
<span class="drag-handle">
|
||||
<i class="{{currency.icon}}" inert></i> {{localize currency.label}}
|
||||
</span>
|
||||
<input type="text" name="{{currency.field.fieldPath}}" data-allow-delta value="{{currency.value}}" data-dtype="Number" min="0" step="1" />
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
</div>
|
||||
|
|
@ -52,12 +52,11 @@ Parameters:
|
|||
{{else}}
|
||||
<ul class="items-list">
|
||||
{{#each collection as |item|}}
|
||||
|
||||
{{> 'daggerheart.inventory-item'
|
||||
item=item
|
||||
type=../type
|
||||
disabledEffect=../disabledEffect
|
||||
actorType=../actorType
|
||||
actorType=(ifThen ../actorType ../actorType @root.document.type)
|
||||
hideControls=../hideControls
|
||||
hideContextMenu=../hideContextMenu
|
||||
isActor=../isActor
|
||||
|
|
@ -66,6 +65,7 @@ Parameters:
|
|||
showLabels=../showLabels
|
||||
isAction=../isAction
|
||||
hideResources=../hideResources
|
||||
isQuantifiable=../isQuantifiable
|
||||
showActions=../showActions
|
||||
}}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,11 +25,11 @@ Parameters:
|
|||
>
|
||||
<div class="inventory-item-header {{#if hideContextMenu}}padded{{/if}}" {{#unless noExtensible}}data-action="toggleExtended" {{/unless}}>
|
||||
{{!-- Image --}}
|
||||
<div class="img-portait" data-action='{{ifThen (or (hasProperty item "use") (eq type "attack")) "useItem" (ifThen
|
||||
<div class="img-portait" data-action='{{ifThen item.usable "useItem" (ifThen
|
||||
(hasProperty item "toChat" ) "toChat" "editDoc" ) }}' {{#unless hideTooltip}} {{#if (eq type 'attack' )}}
|
||||
data-tooltip="#attack#{{item.actor.uuid}}" {{else}} data-tooltip="#item#{{item.uuid}}" {{/if}} {{/unless}} draggable="true">
|
||||
<img src="{{item.img}}" class="item-img {{#if isActor}}actor-img{{/if}}" />
|
||||
{{#if (or item.system.actionsList.size item.system.actionsList.length item.actionType)}}
|
||||
{{#if item.usable}}
|
||||
{{#if @root.isNPC}}
|
||||
<img class="roll-img d20" src="systems/daggerheart/assets/icons/dice/default/d20.svg" alt="d20">
|
||||
{{else}}
|
||||
|
|
@ -63,7 +63,7 @@ Parameters:
|
|||
{{#if (and (not hideResources) (not (eq item.system.resource.type 'diceValue')))}}
|
||||
{{> "systems/daggerheart/templates/sheets/global/partials/item-resource.hbs"}}
|
||||
{{/if}}
|
||||
{{#if (and (not hideResources) (gte item.system.quantity 0))}}
|
||||
{{#if (or isQuantifiable (or (eq item.system.quantity 0) (gt item.system.quantity 1)))}}
|
||||
<div class="item-resource">
|
||||
<input type="number" id="{{item.uuid}}-quantity" class="inventory-item-quantity" value="{{item.system.quantity}}" min="0" />
|
||||
</div>
|
||||
|
|
@ -72,62 +72,59 @@ Parameters:
|
|||
{{!-- Controls --}}
|
||||
{{#unless hideControls}}
|
||||
<div class="controls">
|
||||
{{#if isActor}}
|
||||
<a data-action="editDoc" data-tooltip="DAGGERHEART.UI.Tooltip.openActorWorld">
|
||||
<i class="fa-solid fa-globe"></i>
|
||||
</a>
|
||||
{{#if (eq type 'adversary')}}
|
||||
<a data-action='deleteAdversary' data-category="{{categoryAdversary}}" data-tooltip="CONTROLS.CommonDelete">
|
||||
<i class='fas fa-trash'></i>
|
||||
</a>
|
||||
{{/if}}
|
||||
{{#if (eq type 'character')}}
|
||||
<a data-action='deletePartyMember' data-tooltip="CONTROLS.CommonDelete">
|
||||
<i class='fas fa-trash'></i>
|
||||
</a>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
{{#unless (eq actorType 'party')}}
|
||||
{{#if (eq type 'weapon')}}
|
||||
{{!-- Toggle/Equip buttons --}}
|
||||
{{#if @root.editable}}
|
||||
{{#if (and (eq actorType 'character') (eq type 'weapon'))}}
|
||||
<a class="{{#unless item.system.equipped}}unequipped{{/unless}}" data-action="toggleEquipItem"
|
||||
data-tooltip="DAGGERHEART.UI.Tooltip.{{ifThen item.system.equipped 'unequip' 'equip' }}">
|
||||
<i class="fa-solid fa-hands"></i>
|
||||
</a>
|
||||
{{else if (eq type 'armor')}}
|
||||
<a class="{{#unless item.system.equipped}}unequipped{{/unless}}" data-action="toggleEquipItem"
|
||||
data-tooltip="DAGGERHEART.UI.Tooltip.{{ifThen item.system.equipped 'unequip' 'equip' }}">
|
||||
<i class="fa-solid fa-fw fa-shield"></i>
|
||||
<i class="fa-solid fa-hands" inert></i>
|
||||
</a>
|
||||
{{/if}}
|
||||
{{#if (eq type 'domainCard')}}
|
||||
{{#if (and (eq actorType 'character') (eq type 'armor'))}}
|
||||
<a class="{{#unless item.system.equipped}}unequipped{{/unless}}" data-action="toggleEquipItem"
|
||||
data-tooltip="DAGGERHEART.UI.Tooltip.{{ifThen item.system.equipped 'unequip' 'equip' }}">
|
||||
<i class="fa-solid fa-fw fa-shield" inert></i>
|
||||
</a>
|
||||
{{/if}}
|
||||
{{#if (and (eq type 'domainCard'))}}
|
||||
<a data-action="toggleVault"
|
||||
data-tooltip="DAGGERHEART.UI.Tooltip.{{ifThen item.system.inVault 'sendToLoadout' 'sendToVault' }}">
|
||||
<i class="fa-solid {{ifThen item.system.inVault 'fa-arrow-up' 'fa-arrow-down'}}"></i>
|
||||
<i class="fa-solid {{ifThen item.system.inVault 'fa-arrow-up' 'fa-arrow-down'}}" inert></i>
|
||||
</a>
|
||||
{{else if (and (eq type 'effect') (not (eq item.type 'beastform')))}}
|
||||
{{/if}}
|
||||
{{#if (and (and (eq type 'effect') (not (eq item.type 'beastform'))))}}
|
||||
<a data-action="toggleEffect"
|
||||
data-tooltip="DAGGERHEART.UI.Tooltip.{{ifThen item.disabled 'enableEffect' 'disableEffect' }}">
|
||||
<i class="{{ifThen item.disabled 'fa-solid fa-toggle-off' 'fa-solid fa-toggle-on'}}"></i>
|
||||
<i class="{{ifThen item.disabled 'fa-solid fa-toggle-off' 'fa-solid fa-toggle-on'}}" inert></i>
|
||||
</a>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{!-- Send to Chat --}}
|
||||
{{#if (hasProperty item "toChat")}}
|
||||
<a data-action="toChat" data-tooltip="DAGGERHEART.UI.Tooltip.sendToChat">
|
||||
<i class="fa-regular fa-fw fa-message"></i>
|
||||
<i class="fa-regular fa-fw fa-message" inert></i>
|
||||
</a>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<a data-action="editDoc" data-tooltip="DAGGERHEART.UI.Tooltip.openActorWorld">
|
||||
<i class="fa-solid fa-globe"></i>
|
||||
</a>
|
||||
<a data-action="deleteItem" data-tooltip="DAGGERHEART.UI.Tooltip.deleteItem">
|
||||
<i class="fa-solid fa-trash"></i>
|
||||
</a>
|
||||
{{/unless}}
|
||||
{{#unless hideContextMenu}}
|
||||
|
||||
{{!-- Document management buttons or context menu --}}
|
||||
{{#if (and (not isActor) (not hideContextMenu))}}
|
||||
<a data-action="triggerContextMenu" data-tooltip="DAGGERHEART.UI.Tooltip.moreOptions">
|
||||
<i class="fa-solid fa-fw fa-ellipsis-vertical"></i>
|
||||
<i class="fa-solid fa-fw fa-ellipsis-vertical" inert></i>
|
||||
</a>
|
||||
{{/unless}}
|
||||
{{else if @root.editable}}
|
||||
<a data-action="editDoc" data-tooltip="DAGGERHEART.UI.Tooltip.edit">
|
||||
<i class="fa-solid fa-edit" inert></i>
|
||||
</a>
|
||||
{{#if (not isActor)}}
|
||||
<a data-action="deleteItem" data-tooltip="DAGGERHEART.UI.Tooltip.deleteItem">
|
||||
<i class="fa-solid fa-trash" inert></i>
|
||||
</a>
|
||||
{{else if (eq type 'adversary')}}
|
||||
<a data-action='deleteAdversary' data-category="{{categoryAdversary}}" data-tooltip="CONTROLS.CommonDelete">
|
||||
<i class="fas fa-trash" inert></i>
|
||||
</a>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/unless}}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@
|
|||
</a>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
{{#if @root.editable}}
|
||||
{{#if (eq type 'weapon')}}
|
||||
<a class="{{#unless item.system.equipped}}unequipped{{/unless}}" data-action="toggleEquipItem"
|
||||
data-tooltip="DAGGERHEART.UI.Tooltip.{{ifThen item.system.equipped 'unequip' 'equip' }}">
|
||||
|
|
@ -69,6 +70,7 @@
|
|||
<i class="fa-solid fa-fw {{ifThen item.disabled 'fa-toggle-off' 'fa-toggle-on'}}"></i>
|
||||
</a>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{#if (hasProperty item "toChat")}}
|
||||
<a data-action="toChat" data-tooltip="DAGGERHEART.UI.Tooltip.sendToChat">
|
||||
<i class="fa-regular fa-fw fa-message"></i>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,6 @@
|
|||
title='DAGGERHEART.GENERAL.Action.plural'
|
||||
collection=document.system.actions
|
||||
type='action'
|
||||
canCreate=true
|
||||
canCreate=@root.editable
|
||||
}}
|
||||
</section>
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
type='effect'
|
||||
isGlassy=true
|
||||
collection=effects.actives
|
||||
canCreate=true
|
||||
canCreate=@root.editable
|
||||
hideResources=true
|
||||
}}
|
||||
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
disabledEffect=true
|
||||
isGlassy=true
|
||||
collection=effects.inactives
|
||||
canCreate=true
|
||||
canCreate=@root.editable
|
||||
hideResources=true
|
||||
}}
|
||||
</section>
|
||||
|
|
@ -5,9 +5,9 @@
|
|||
<h1 class='item-name'><input type='text' name='name' value='{{source.name}}' /></h1>
|
||||
<div class='item-description'>
|
||||
{{#if source.system.secondary}}
|
||||
<h3>{{localize "DAGGERHEART.ITEMS.Weapon.secondaryWeapon"}}</h3>
|
||||
<h3>{{localize "DAGGERHEART.ITEMS.Weapon.secondaryWeapon.full"}}</h3>
|
||||
{{else}}
|
||||
<h3>{{localize "DAGGERHEART.ITEMS.Weapon.primaryWeapon"}}</h3>
|
||||
<h3>{{localize "DAGGERHEART.ITEMS.Weapon.primaryWeapon.full"}}</h3>
|
||||
{{/if}}
|
||||
<h3>
|
||||
{{localize (concat 'DAGGERHEART.CONFIG.Traits.' source.system.attack.roll.trait '.short')}}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<legend>{{localize tabs.settings.label}}</legend>
|
||||
<span>{{localize "DAGGERHEART.GENERAL.Tiers.singular"}}</span>
|
||||
{{formInput systemFields.tier value=source.system.tier}}
|
||||
<span>{{localize "DAGGERHEART.ITEMS.Weapon.secondaryWeapon"}}</span>
|
||||
<span>{{localize "DAGGERHEART.ITEMS.Weapon.secondaryWeapon.full"}}</span>
|
||||
{{formInput systemFields.secondary value=source.system.secondary}}
|
||||
<span>{{localize "DAGGERHEART.GENERAL.Trait.single"}}</span>
|
||||
{{formInput systemFields.attack.fields.roll.fields.trait value=document.system.attack.roll.trait name="system.attack.roll.trait" label="DAGGERHEART.GENERAL.Trait.single" localize=true}}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@
|
|||
{{else}}
|
||||
<span class="entry-subtitle">{{localize "DAGGERHEART.UI.Sidebar.actorDirectory.companionNoPartner"}}</span>
|
||||
{{/if}}
|
||||
{{else if (eq type "party")}}
|
||||
{{#if system.active}}
|
||||
<span class="entry-subtitle">{{localize "DAGGERHEART.UI.Sidebar.actorDirectory.partyIsActive"}}</span>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</a>
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@
|
|||
{{#each category as |grouping index|}}
|
||||
<div class="battlepoint-grouping-container">
|
||||
{{#if grouping.nr}}
|
||||
<label>{{key}} BP: {{concat (localize grouping.description) ' ' '('grouping.nr 'x)'}}</label>
|
||||
<label>{{key}} {{localize "DAGGERHEART.GENERAL.Battlepoints.short"}} - {{concat (localize grouping.description) ' ' '('grouping.nr 'x)'}}</label>
|
||||
{{else}}
|
||||
<label class="unselected-grouping">{{key}} BP - {{localize grouping.description}}</label>
|
||||
<label class="unselected-grouping">{{key}} {{localize "DAGGERHEART.GENERAL.Battlepoints.short"}} - {{localize grouping.description}}</label>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/each}}
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
{{else}}
|
||||
<input type="checkbox" data-combat-id="{{@root.combatId}}" data-category="{{toggle.categoryKey}}" data-grouping="{{toggle.toggleKey}}" {{checked toggle.checked}} />
|
||||
{{/if}}
|
||||
<label class="unselected-grouping">{{toggle.categoryKey}} BP: {{localize toggle.description}}</label>
|
||||
<label class="unselected-grouping">{{toggle.categoryKey}} {{localize "DAGGERHEART.GENERAL.Battlepoints.short"}}: {{localize toggle.description}}</label>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<h2 class="tooltip-title">{{item.name}}</h2>
|
||||
<div class="tags">
|
||||
<div class="tag">
|
||||
<span>{{#if item.system.secondary}}{{localize "DAGGERHEART.ITEMS.Weapon.secondaryWeapon"}}{{else}}{{localize "DAGGERHEART.ITEMS.Weapon.primaryWeapon"}}{{/if}}</span>
|
||||
<span>{{#if item.system.secondary}}{{localize "DAGGERHEART.ITEMS.Weapon.secondaryWeapon.full"}}{{else}}{{localize "DAGGERHEART.ITEMS.Weapon.primaryWeapon.full"}}{{/if}}</span>
|
||||
</div>
|
||||
<div class="tag">
|
||||
{{#with (lookup config.GENERAL.burden item.system.burden) as | burden |}}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import { compilePack } from '@foundryvtt/foundryvtt-cli';
|
||||
import readline from 'node:readline/promises';
|
||||
import { promises as fs } from 'fs';
|
||||
import systemJSON from "../system.json" with { type: "json" };
|
||||
import systemJSON from '../system.json' with { type: 'json' };
|
||||
|
||||
const MODULE_ID = process.cwd();
|
||||
|
||||
const answer = await (async () => {
|
||||
if (process.argv.includes("--build")) return "overwrite";
|
||||
if (process.argv.includes('--build')) return 'overwrite';
|
||||
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
|
|
@ -42,8 +42,8 @@ async function pullToLDB() {
|
|||
function transformEntry(entry) {
|
||||
const stats = {
|
||||
coreVersion: systemJSON.compatibility.minimum,
|
||||
systemId: "daggerheart",
|
||||
systemVersion: systemJSON.version,
|
||||
systemId: 'daggerheart',
|
||||
systemVersion: systemJSON.version
|
||||
};
|
||||
|
||||
entry._stats = { ...stats };
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ for (const pack of packs) {
|
|||
await extractPack(`${MODULE_ID}/${pack}`, `${MODULE_ID}/src/${pack}`, {
|
||||
yaml,
|
||||
transformName,
|
||||
transformEntry,
|
||||
transformEntry
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
|
@ -45,12 +45,12 @@ function transformEntry(entry) {
|
|||
|
||||
delete entry._stats;
|
||||
for (const effect of entry.effects ?? []) {
|
||||
effect._stats = prune(effect._stats)
|
||||
effect._stats = prune(effect._stats);
|
||||
}
|
||||
for (const item of entry.items ?? []) {
|
||||
item._stats = prune(item._stats);
|
||||
for (const effect of item.effects ?? []) {
|
||||
effect._stats = prune(effect._stats)
|
||||
effect._stats = prune(effect._stats);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue