Merged with main

This commit is contained in:
WBHarry 2025-07-15 15:40:32 +02:00
commit ce4a08d318
27 changed files with 414 additions and 170 deletions

View file

@ -686,11 +686,11 @@
}
},
"RollTypes": {
"ability": {
"name": "Ability"
"trait": {
"name": "Trait"
},
"weapon": {
"name": "Weapon"
"attack": {
"name": "Attack"
},
"spellcast": {
"name": "SpellCast"
@ -1015,8 +1015,8 @@
"allDamage": "All Damage",
"physicalDamage": "Physical Damage",
"magicalDamage": "Magical Damage",
"primaryDamageBonus": "Primary Weapon Damage",
"primaryDamageDice": "Primary Weapon Extra Damage Dice"
"primaryWeapon": "Primary Weapon Damage",
"secondaryWeapon": "Secondary Weapon Damage"
},
"DamageResistance": {
"none": "None",
@ -1093,10 +1093,18 @@
"single": "Experience",
"plural": "Experiences"
},
"Healing": {
"healingAmount": "Healing Amount"
},
"Neutral": {
"full": "None",
"short": "no"
},
"Range": {
"other": "Range Increase: Other",
"spell": "Range Increase: Spell",
"weapon": "Range Increase: Weapon"
},
"RefreshType": {
"session": "Session",
"shortrest": "Short Rest",
@ -1109,9 +1117,11 @@
"Roll": {
"attack": "Attack Roll",
"primaryWeaponAttack": "Primary Weapon Attack Roll",
"secondaryWeaponAttack": "Secondary Weapon Attack Roll",
"spellcast": "Spellcast Roll",
"trait": "Trait Roll",
"action": "Action Roll",
"hopeOrFear": "Hope Or Fear Roll"
"reaction": "Reaction Roll"
},
"Rules": {
"damageReduction": {
@ -1186,6 +1196,7 @@
},
"armorScore": "Armor Score",
"activeEffects": "Active Effects",
"armorSlots": "Armor Slots",
"attack": "Attack",
"basics": "Basics",
"bonus": "Bonus",

View file

@ -103,6 +103,11 @@ export default class CharacterSheet extends DHBaseActorSheet {
htmlElement.querySelectorAll('.inventory-item-quantity').forEach(element => {
element.addEventListener('change', this.updateItemQuantity.bind(this));
});
// Add listener for armor marks input
htmlElement.querySelectorAll('.armor-marks-input').forEach(element => {
element.addEventListener('change', this.updateArmorMarks.bind(this));
});
}
/** @inheritDoc */
@ -515,6 +520,16 @@ export default class CharacterSheet extends DHBaseActorSheet {
this.render();
}
async updateArmorMarks(event) {
const armor = this.document.system.armor;
if (!armor) return;
const maxMarks = this.document.system.armorScore;
const value = Math.min(Math.max(Number(event.currentTarget.value), 0), maxMarks);
await armor.update({ 'system.marks.value': value });
this.render();
}
/* -------------------------------------------- */
/* Application Clicks Actions */
/* -------------------------------------------- */

View file

@ -14,8 +14,6 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
}
addChatListeners = async (app, html, data) => {
super.addChatListeners(app, html, data);
html.querySelectorAll('.duality-action-damage').forEach(element =>
element.addEventListener('click', event => this.onRollDamage(event, data.message))
);

View file

@ -388,17 +388,17 @@ export const countdownTypes = {
}
};
export const rollTypes = {
weapon: {
id: 'weapon',
label: 'DAGGERHEART.CONFIG.RollTypes.weapon.name'
attack: {
id: 'attack',
label: 'DAGGERHEART.CONFIG.RollTypes.attack.name'
},
spellcast: {
id: 'spellcast',
label: 'DAGGERHEART.CONFIG.RollTypes.spellcast.name'
},
ability: {
id: 'ability',
label: 'DAGGERHEART.CONFIG.RollTypes.ability.name'
trait: {
id: 'trait',
label: 'DAGGERHEART.CONFIG.RollTypes.trait.name'
},
diceSet: {
id: 'diceSet',

View file

@ -5,7 +5,7 @@ export default class DHAttackAction extends DHDamageAction {
static extraSchemas = [...super.extraSchemas, ...['roll', 'save']];
static getRollType(parent) {
return parent.type === 'weapon' ? 'weapon' : 'spellcast';
return parent.type === 'weapon' ? 'attack' : 'spellcast';
}
get chatTemplate() {
@ -21,7 +21,7 @@ export default class DHAttackAction extends DHDamageAction {
}
if (this.roll.useDefault) {
this.roll.trait = this.item.system.attack.roll.trait;
this.roll.type = 'weapon';
this.roll.type = 'attack';
}
}
}
@ -37,4 +37,8 @@ export default class DHAttackAction extends DHDamageAction {
base: true
};
}
// get modifiers() {
// return [];
// }
}

View file

@ -150,7 +150,7 @@ export default class DHBaseAction extends foundry.abstract.DataModel {
}
static getRollType(parent) {
return 'ability';
return 'trait';
}
static getSourceConfig(parent) {
@ -308,7 +308,7 @@ export default class DHBaseAction extends foundry.abstract.DataModel {
prepareRoll() {
const roll = {
modifiers: [],
modifiers: this.modifiers,
trait: this.roll?.trait,
label: 'Attack',
type: this.actionType,
@ -362,6 +362,13 @@ export default class DHBaseAction extends foundry.abstract.DataModel {
get hasRoll() {
return !!this.roll?.type || !!this.roll?.bonus;
}
get modifiers() {
if (!this.actor) return [];
const modifiers = [];
/** Placeholder for specific bonuses **/
return modifiers;
}
/* ROLL */
/* SAVE */

View file

@ -28,6 +28,7 @@ export default class DHDamageAction extends DHBaseAction {
hasSave: this.hasSave,
isCritical: data.system?.roll?.isCritical ?? false,
source: data.system?.source,
data: this.getRollData(),
damageTypes,
event
};
@ -39,4 +40,8 @@ export default class DHDamageAction extends DHBaseAction {
roll = CONFIG.Dice.daggerheart.DamageRoll.build(config);
}
// get modifiers() {
// return [];
// }
}

View file

@ -39,4 +39,8 @@ export default class DHHealingAction extends DHBaseAction {
get chatTemplate() {
return 'systems/daggerheart/templates/ui/chat/healing-roll.hbs';
}
get modifiers() {
return [];
}
}

View file

@ -1,13 +1,7 @@
import DHAdversarySettings from '../../applications/sheets-configs/adversary-settings.mjs';
import ActionField from '../fields/actionField.mjs';
import BaseDataActor from './base.mjs';
const resourceField = label =>
new foundry.data.fields.SchemaField({
value: new foundry.data.fields.NumberField({ initial: 0, integer: true, label }),
max: new foundry.data.fields.NumberField({ initial: 0, integer: true }),
isReversed: new foundry.data.fields.BooleanField({ initial: true })
});
import { resourceField, bonusField } from '../fields/actorField.mjs';
export default class DhpAdversary extends BaseDataActor {
static LOCALIZATION_PREFIXES = ['DAGGERHEART.ACTORS.Adversary'];
@ -58,8 +52,8 @@ export default class DhpAdversary extends BaseDataActor {
})
}),
resources: new fields.SchemaField({
hitPoints: resourceField('DAGGERHEART.GENERAL.hitPoints'),
stress: resourceField('DAGGERHEART.GENERAL.stress')
hitPoints: resourceField(0, 'DAGGERHEART.GENERAL.hitPoints', true),
stress: resourceField(0, 'DAGGERHEART.GENERAL.stress', true)
}),
attack: new ActionField({
initial: {
@ -74,7 +68,7 @@ export default class DhpAdversary extends BaseDataActor {
amount: 1
},
roll: {
type: 'weapon'
type: 'attack'
},
damage: {
parts: [
@ -95,17 +89,14 @@ export default class DhpAdversary extends BaseDataActor {
})
),
bonuses: new fields.SchemaField({
difficulty: new fields.SchemaField({
all: new fields.NumberField({
integer: true,
initial: 0,
label: 'DAGGERHEART.GENERAL.Difficulty.all'
}),
reaction: new fields.NumberField({
integer: true,
initial: 0,
label: 'DAGGERHEART.GENERAL.Difficulty.reaction'
})
roll: new fields.SchemaField({
attack: bonusField('DAGGERHEART.GENERAL.Roll.attack'),
action: bonusField('DAGGERHEART.GENERAL.Roll.action'),
reaction: bonusField('DAGGERHEART.GENERAL.Roll.reaction')
}),
damage: new fields.SchemaField({
physical: bonusField('DAGGERHEART.GENERAL.Damage.physicalDamage'),
magical: bonusField('DAGGERHEART.GENERAL.Damage.magicalDamage')
})
})
};

View file

@ -2,29 +2,7 @@ import { burden } from '../../config/generalConfig.mjs';
import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
import DhLevelData from '../levelData.mjs';
import BaseDataActor from './base.mjs';
const attributeField = label =>
new foundry.data.fields.SchemaField({
value: new foundry.data.fields.NumberField({ initial: 0, integer: true, label: label }),
tierMarked: new foundry.data.fields.BooleanField({ initial: false })
});
const resourceField = (max, label, reverse = false) =>
new foundry.data.fields.SchemaField({
value: new foundry.data.fields.NumberField({ initial: 0, integer: true, label: label }),
max: new foundry.data.fields.NumberField({ initial: max, integer: true }),
isReversed: new foundry.data.fields.BooleanField({ initial: reverse })
});
const stressDamageReductionRule = localizationPath =>
new foundry.data.fields.SchemaField({
enabled: new foundry.data.fields.BooleanField({ required: true, initial: false }),
cost: new foundry.data.fields.NumberField({
integer: true,
label: `${localizationPath}.label`,
hint: `${localizationPath}.hint`
})
});
import { attributeField, resourceField, stressDamageReductionRule, bonusField } from '../fields/actorField.mjs';
export default class DhCharacter extends BaseDataActor {
static LOCALIZATION_PREFIXES = ['DAGGERHEART.ACTORS.Character'];
@ -112,59 +90,36 @@ export default class DhCharacter extends BaseDataActor {
levelData: new fields.EmbeddedDataField(DhLevelData),
bonuses: new fields.SchemaField({
roll: new fields.SchemaField({
attack: new fields.NumberField({
integer: true,
initial: 0,
label: 'DAGGERHEART.GENERAL.Roll.attack'
}),
primaryWeapon: new fields.SchemaField({
attack: new fields.NumberField({
integer: true,
initial: 0,
label: 'DAGGERHEART.GENERAL.Roll.primaryWeaponAttack'
})
}),
spellcast: new fields.NumberField({
integer: true,
initial: 0,
label: 'DAGGERHEART.GENERAL.Roll.spellcast'
}),
action: new fields.NumberField({
integer: true,
initial: 0,
label: 'DAGGERHEART.GENERAL.Roll.action'
}),
hopeOrFear: new fields.NumberField({
integer: true,
initial: 0,
label: 'DAGGERHEART.GENERAL.Roll.hopeOrFear'
})
attack: bonusField('DAGGERHEART.GENERAL.Roll.attack'),
spellcast: bonusField('DAGGERHEART.GENERAL.Roll.spellcast'),
trait: bonusField('DAGGERHEART.GENERAL.Roll.trait'),
action: bonusField('DAGGERHEART.GENERAL.Roll.action'),
reaction: bonusField('DAGGERHEART.GENERAL.Roll.reaction'),
primaryWeapon: bonusField('DAGGERHEART.GENERAL.Roll.primaryWeaponAttack'),
secondaryWeapon: bonusField('DAGGERHEART.GENERAL.Roll.secondaryWeaponAttack')
}),
damage: new fields.SchemaField({
all: new fields.NumberField({
physical: bonusField('DAGGERHEART.GENERAL.Damage.physicalDamage'),
magical: bonusField('DAGGERHEART.GENERAL.Damage.magicalDamage'),
primaryWeapon: bonusField('DAGGERHEART.GENERAL.Damage.primaryWeapon'),
secondaryWeapon: bonusField('DAGGERHEART.GENERAL.Damage.primaryWeapon')
}),
healing: bonusField('DAGGERHEART.GENERAL.Healing.healingAmount'),
range: new fields.SchemaField({
weapon: new fields.NumberField({
integer: true,
initial: 0,
label: 'DAGGERHEART.GENERAL.Damage.allDamage'
label: 'DAGGERHEART.GENERAL.Range.weapon'
}),
physical: new fields.NumberField({
spell: new fields.NumberField({
integer: true,
initial: 0,
label: 'DAGGERHEART.GENERAL.Damage.physicalDamage'
label: 'DAGGERHEART.GENERAL.Range.spell'
}),
magic: new fields.NumberField({
other: new fields.NumberField({
integer: true,
initial: 0,
label: 'DAGGERHEART.GENERAL.Damage.magicalDamage'
}),
primaryWeapon: new fields.SchemaField({
bonus: new fields.NumberField({
integer: true,
label: 'DAGGERHEART.GENERAL.Damage.primaryDamageBonus'
}),
extraDice: new fields.NumberField({
integer: true,
label: 'DAGGERHEART.GENERAL.Damage.primaryDamageDice'
})
label: 'DAGGERHEART.GENERAL.Range.other'
})
})
}),
@ -246,6 +201,11 @@ export default class DhCharacter extends BaseDataActor {
return !this.class.value || !this.class.subclass;
}
get spellcastModifier() {
const subClasses = this.parent.items.filter(x => x.type === 'subclass') ?? [];
return Math.max(subClasses?.map(sc => this.traits[sc.system.spellcastingTrait]?.value));
}
get spellcastingModifiers() {
return {
main: this.class.subclass?.system?.spellcastingTrait,
@ -388,6 +348,8 @@ export default class DhCharacter extends BaseDataActor {
}
prepareBaseData() {
this.evasion = this.class.value?.system?.evasion ?? 0;
const currentLevel = this.levelData.level.current;
const currentTier =
currentLevel === 1

View file

@ -4,6 +4,7 @@ import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
import ActionField from '../fields/actionField.mjs';
import { adjustDice, adjustRange } from '../../helpers/utils.mjs';
import DHCompanionSettings from '../../applications/sheets-configs/companion-settings.mjs';
import { resourceField, bonusField } from '../fields/actorField.mjs';
export default class DhCompanion extends BaseDataActor {
static LOCALIZATION_PREFIXES = ['DAGGERHEART.ACTORS.Companion'];
@ -23,20 +24,9 @@ export default class DhCompanion extends BaseDataActor {
...super.defineSchema(),
partner: new ForeignDocumentUUIDField({ type: 'Actor' }),
resources: new fields.SchemaField({
stress: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true }),
max: new fields.NumberField({ initial: 3, integer: true }),
isReversed: new foundry.data.fields.BooleanField({ initial: true })
}),
stress: resourceField(3, 'DAGGERHEART.GENERAL.stress', true),
hope: new fields.NumberField({ initial: 0, integer: true, label: 'DAGGERHEART.GENERAL.hope' })
}),
evasion: new fields.NumberField({
required: true,
min: 1,
initial: 10,
integer: true,
label: 'DAGGERHEART.GENERAL.evasion'
}),
experiences: new fields.TypedObjectField(
new fields.SchemaField({
name: new fields.StringField({}),
@ -62,7 +52,7 @@ export default class DhCompanion extends BaseDataActor {
amount: 1
},
roll: {
type: 'weapon',
type: 'attack',
bonus: 0,
trait: 'instinct'
},
@ -80,7 +70,13 @@ export default class DhCompanion extends BaseDataActor {
}
}),
actions: new fields.ArrayField(new ActionField()),
levelData: new fields.EmbeddedDataField(DhLevelData)
levelData: new fields.EmbeddedDataField(DhLevelData),
bonuses: new fields.SchemaField({
damage: new fields.SchemaField({
physical: bonusField('DAGGERHEART.GENERAL.Damage.physicalDamage'),
magical: bonusField('DAGGERHEART.GENERAL.Damage.magicalDamage')
})
})
};
}
@ -95,7 +91,7 @@ export default class DhCompanion extends BaseDataActor {
}
prepareBaseData() {
const partnerSpellcastingModifier = this.partner?.system?.spellcastingModifiers?.main;
const partnerSpellcastingModifier = this.partner?.system?.spellcastModifier;
const spellcastingModifier = this.partner?.system?.traits?.[partnerSpellcastingModifier]?.value;
this.attack.roll.bonus = spellcastingModifier ?? 0; // Needs to expand on which modifier it is that should be used because of multiclassing;

View file

@ -0,0 +1,32 @@
const fields = foundry.data.fields;
const attributeField = label =>
new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true, label }),
tierMarked: new fields.BooleanField({ initial: false })
});
const resourceField = (max = 0, label, reverse = false) =>
new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true, label }),
max: new fields.NumberField({ initial: max, integer: true }),
isReversed: new fields.BooleanField({ initial: reverse })
});
const stressDamageReductionRule = localizationPath =>
new fields.SchemaField({
enabled: new fields.BooleanField({ required: true, initial: false }),
cost: new fields.NumberField({
integer: true,
label: `${localizationPath}.label`,
hint: `${localizationPath}.hint`
})
});
const bonusField = label =>
new fields.SchemaField({
bonus: new fields.NumberField({ integer: true, initial: 0, label }),
dice: new fields.ArrayField(new fields.StringField())
});
export { attributeField, resourceField, stressDamageReductionRule, bonusField };

View file

@ -50,7 +50,7 @@ export default class DHWeapon extends AttachableItem {
},
roll: {
trait: 'agility',
type: 'weapon'
type: 'attack'
},
damage: {
parts: [

View file

@ -74,7 +74,6 @@ export default class D20Roll extends DHRoll {
}
constructFormula(config) {
// this.terms = [];
this.createBaseDice();
this.configureModifiers();
this.resetFormula();
@ -91,7 +90,10 @@ export default class D20Roll extends DHRoll {
configureModifiers() {
this.applyAdvantage();
this.applyBaseBonus();
this.baseTerms = foundry.utils.deepClone(this.terms);
this.options.roll.modifiers = this.applyBaseBonus();
this.options.experiences?.forEach(m => {
if (this.options.data.experiences?.[m])
@ -101,12 +103,7 @@ export default class D20Roll extends DHRoll {
});
});
this.options.roll.modifiers?.forEach(m => {
this.terms.push(...this.formatModifier(m.value));
});
this.baseTerms = foundry.utils.deepClone(this.terms);
this.addModifiers();
if (this.options.extraFormula) {
this.terms.push(
new foundry.dice.terms.OperatorTerm({ operator: '+' }),
@ -125,13 +122,20 @@ export default class D20Roll extends DHRoll {
}
applyBaseBonus() {
this.options.roll.modifiers = [];
if (!this.options.roll.bonus) return;
this.options.roll.modifiers.push({
label: 'Bonus to Hit',
value: this.options.roll.bonus
// value: Roll.replaceFormulaData('@attackBonus', this.data)
});
const modifiers = [];
if (this.options.roll.bonus)
modifiers.push({
label: 'Bonus to Hit',
value: this.options.roll.bonus
});
modifiers.push(...this.getBonus(`roll.${this.options.type}`, `${this.options.type.capitalize()} Bonus`));
modifiers.push(
...this.getBonus(`roll.${this.options.roll.type}`, `${this.options.roll.type.capitalize()} Bonus`)
);
return modifiers;
}
static async buildEvaluate(roll, config = {}, message = {}) {

View file

@ -24,8 +24,26 @@ export default class DamageRoll extends DHRoll {
}
}
applyBaseBonus() {
const modifiers = [],
type = this.options.messageType ?? 'damage';
modifiers.push(...this.getBonus(`${type}`, `${type.capitalize()} Bonus`));
this.options.damageTypes?.forEach(t => {
modifiers.push(...this.getBonus(`${type}.${t}`, `${t.capitalize()} ${type.capitalize()} Bonus`));
});
const weapons = ['primaryWeapon', 'secondaryWeapon'];
weapons.forEach(w => {
if (this.options.source.item && this.options.source.item === this.data[w]?.id)
modifiers.push(...this.getBonus(`${type}.${w}`, 'Weapon Bonus'));
});
return modifiers;
}
constructFormula(config) {
super.constructFormula(config);
if (config.isCritical) {
const tmpRoll = new Roll(this._formula)._evaluateSync({ maximize: true }),
criticalBonus = tmpRoll.total - this.constructor.calculateTotalModifiers(tmpRoll);

View file

@ -4,6 +4,7 @@ export default class DHRoll extends Roll {
baseTerms = [];
constructor(formula, data, options) {
super(formula, data, options);
if (!this.data || !Object.keys(this.data).length) this.data = options.data;
}
static messageType = 'adversaryRoll';
@ -99,11 +100,44 @@ export default class DHRoll extends Roll {
}
formatModifier(modifier) {
const numTerm = modifier < 0 ? '-' : '+';
return [
new foundry.dice.terms.OperatorTerm({ operator: numTerm }),
new foundry.dice.terms.NumericTerm({ number: Math.abs(modifier) })
];
if (Array.isArray(modifier)) {
return [
new foundry.dice.terms.OperatorTerm({ operator: '+' }),
...this.constructor.parse(modifier.join(' + '), this.options.data)
];
} else {
const numTerm = modifier < 0 ? '-' : '+';
return [
new foundry.dice.terms.OperatorTerm({ operator: numTerm }),
new foundry.dice.terms.NumericTerm({ number: Math.abs(modifier) })
];
}
}
applyBaseBonus() {
return [];
}
addModifiers() {
this.options.roll.modifiers?.forEach(m => {
this.terms.push(...this.formatModifier(m.value));
});
}
getBonus(path, label) {
const bonus = foundry.utils.getProperty(this.data.bonuses, path),
modifiers = [];
if (bonus?.bonus)
modifiers.push({
label: label,
value: bonus?.bonus
});
if (bonus?.dice?.length)
modifiers.push({
label: label,
value: bonus?.dice
});
return modifiers;
}
getFaces(faces) {
@ -113,6 +147,9 @@ export default class DHRoll extends Roll {
constructFormula(config) {
this.terms = Roll.parse(this.options.roll.formula, config.data);
this.options.roll.modifiers = this.applyBaseBonus();
this.addModifiers();
if (this.options.extraFormula) {
this.terms.push(
new foundry.dice.terms.OperatorTerm({ operator: '+' }),

View file

@ -119,12 +119,21 @@ export default class DualityRoll extends D20Roll {
}
applyBaseBonus() {
this.options.roll.modifiers = [];
if (!this.options.roll.trait) return;
this.options.roll.modifiers.push({
label: `DAGGERHEART.CONFIG.Traits.${this.options.roll.trait}.name`,
value: Roll.replaceFormulaData(`@traits.${this.options.roll.trait}.value`, this.data)
const modifiers = super.applyBaseBonus();
if (this.options.roll.trait && this.data.traits[this.options.roll.trait])
modifiers.unshift({
label: `DAGGERHEART.CONFIG.Traits.${this.options.roll.trait}.name`,
value: this.data.traits[this.options.roll.trait].value
});
const weapons = ['primaryWeapon', 'secondaryWeapon'];
weapons.forEach(w => {
if (this.options.source.item && this.options.source.item === this.data[w]?.id)
modifiers.push(...this.getBonus(`roll.${w}`, 'Weapon Bonus'));
});
return modifiers;
}
static postEvaluate(roll, config = {}) {

View file

@ -371,7 +371,7 @@ export default class DhpActor extends Actor {
getRollData() {
const rollData = super.getRollData();
rollData.prof = this.system.proficiency ?? 1;
rollData.cast = this.system.spellcast ?? 1;
rollData.cast = this.system.spellcastModifier ?? 1;
return rollData;
}

View file

@ -39,8 +39,9 @@ export default class RegisterHandlebarsHelpers {
}
static damageSymbols(damageParts) {
const symbols = new Set();
damageParts.forEach(part => symbols.add(...CONFIG.DH.GENERAL.damageTypes[part.type].icon));
const symbols = [...new Set(damageParts.reduce((a, c) => a.concat([...c.type]), []))].map(
p => CONFIG.DH.GENERAL.damageTypes[p].icon
);
return new Handlebars.SafeString(Array.from(symbols).map(symbol => `<i class="fa-solid ${symbol}"></i>`));
}

View file

@ -306,7 +306,7 @@ export const itemAbleRollParse = (value, actor, item) => {
const isItemTarget = value.toLowerCase().startsWith('item.');
const slicedValue = isItemTarget ? value.slice(5) : value;
try {
return Roll.safeEval(Roll.replaceFormulaData(slicedValue, isItemTarget ? item : actor));
return Roll.replaceFormulaData(slicedValue, isItemTarget ? item : actor);
} catch (_) {
return '';
}

View file

@ -215,7 +215,9 @@
justify-content: center;
.status-number {
justify-items: center;
display: flex;
align-items: center;
flex-direction: column;
.status-value {
position: relative;

View file

@ -174,8 +174,115 @@
gap: 5px;
justify-content: center;
.status-bar.armor-slots {
display: flex;
justify-content: center;
position: relative;
width: 95px;
height: 30px;
.status-label {
padding: 2px 10px;
position: relative;
top: 30px;
height: 22px;
width: 95px;
border-radius: 3px;
background: light-dark(@dark-blue, @golden);
h4 {
font-weight: bold;
text-align: center;
line-height: 18px;
color: light-dark(@beige, @dark-blue);
font-size: 12px;
}
}
.status-value {
position: absolute;
display: flex;
padding: 0 6px;
font-size: 1.2rem;
align-items: center;
width: 80px;
height: 30px;
justify-content: center;
text-align: center;
z-index: 2;
color: light-dark(@dark-blue, @beige);
border: 1px solid light-dark(@dark-blue, @golden);
border-bottom: none;
border-radius: 6px 6px 0 0;
input[type='number'] {
background: transparent;
font-size: 1.2rem;
width: 30px;
height: 20px;
text-align: center;
border: none;
outline: 2px solid transparent;
color: light-dark(@dark-blue, @beige);
&.bar-input {
padding: 0;
color: light-dark(@dark-blue, @beige);
backdrop-filter: none;
background: transparent;
transition: all 0.3s ease;
&:hover,
&:focus {
background: @semi-transparent-dark-blue;
backdrop-filter: blur(9.5px);
}
}
}
.bar-label {
width: 30px;
}
}
.progress-bar {
position: absolute;
appearance: none;
width: 80px;
height: 30px;
border: 1px solid light-dark(@dark-blue, @golden);
border-radius: 6px;
z-index: 1;
background: light-dark(transparent, @dark-blue);
border-bottom: none;
border-radius: 6px 6px 0 0;
&::-webkit-progress-bar {
border: none;
background: light-dark(transparent, @dark-blue);
}
&::-webkit-progress-value {
background: @gradient-stress;
}
&.stress-color::-webkit-progress-value {
background: @gradient-stress;
}
&::-moz-progress-bar {
background: @gradient-stress;
}
&.stress-color::-moz-progress-bar {
background: @gradient-stress;
}
}
}
.status-number {
justify-items: center;
display: flex;
align-items: center;
flex-direction: column;
&.armor-slots {
width: 95px;
}
.status-value {
position: relative;
@ -192,9 +299,33 @@
background: light-dark(transparent, @dark-blue);
z-index: 2;
&.armor-slots {
width: 80px;
height: 30px;
input[type='number'] {
background: transparent;
font-size: 1.2rem;
width: 30px;
height: 20px;
text-align: center;
border: none;
outline: 2px solid transparent;
color: light-dark(@dark-blue, @beige);
&.bar-input {
padding: 0;
color: light-dark(@dark-blue, @beige);
backdrop-filter: none;
background: transparent;
transition: all 0.3s ease;
&:hover,
&:focus {
background: @semi-transparent-dark-blue;
backdrop-filter: blur(9.5px);
}
}
}
.bar-label {
width: 30px;
}
}

View file

@ -92,7 +92,6 @@
position: relative;
width: 100px;
height: 40px;
justify-items: center;
.status-label {
position: relative;

View file

@ -60,7 +60,9 @@
}
.status-number {
justify-items: center;
display: flex;
align-items: center;
flex-direction: column;
.status-value {
position: relative;

View file

@ -44,12 +44,14 @@
display: flex;
gap: 2px;
margin-bottom: 4px;
flex-wrap: wrap;
.duality-modifier {
padding: 2px;
border-radius: 6px;
border: 1px solid;
background: var(--color-dark-6);
font-size: 12px;
white-space: nowrap;
}
}
.dice-flavor {

View file

@ -5,8 +5,8 @@
<ul class="actions-list">
{{#each actions}}
<li class="action-item">
<input type="radio" name="actionId" value="{{_id}}" {{#if (eq @index 0)}}checked{{/if}}>
<span class="label">{{ name }}</span>
<input type="radio" id="action-{{_id}}" name="actionId" value="{{_id}}" {{#if (eq @index 0)}}checked{{/if}}>
<label class="label" for="action-{{_id}}">{{ name }}</label>
</li>
{{/each}}
</ul>

View file

@ -48,18 +48,32 @@
</div>
</div>
<div class="status-number">
<div class='status-value armor-slots'>
{{#if document.system.armor.system.marks}}
<p>{{document.system.armor.system.marks.value}}/{{document.system.armorScore}}</p>
{{else}}
{{#if document.system.armor.system.marks}}
<div class="status-bar armor-slots">
<div class='status-value'>
<p><input class="bar-input armor-marks-input" value="{{document.system.armor.system.marks.value}}" type="number"></p>
<p>/</p>
<p class="bar-label">{{document.system.armorScore}}</p>
</div>
<progress
class='progress-bar stress-color'
value='{{document.system.armor.system.marks.value}}'
max='{{document.system.armorScore}}'
></progress>
<div class="status-label">
<h4>{{localize "DAGGERHEART.GENERAL.armorSlots"}}</h4>
</div>
</div>
{{else}}
<div class="status-number armor-slots">
<div class='status-value'>
<p>-</p>
{{/if}}
</div>
<div class="status-label">
<h4>{{localize "DAGGERHEART.GENERAL.armorSlots"}}</h4>
</div>
</div>
<div class="status-label">
<h4>Armor Slots</h4>
</div>
</div>
{{/if}}
<div class="status-number">
<div class='status-value'>