Compare commits

..

No commits in common. "04befd2e4efd220e5dc040360f32aeef6f35a9c7" and "d414b464b5d3c51096f54d1a1dc7d04e827eae2d" have entirely different histories.

43 changed files with 264 additions and 360 deletions

View file

@ -80,7 +80,6 @@ CONFIG.ux.ContextMenu = applications.ux.DHContextMenu;
CONFIG.ux.TooltipManager = documents.DhTooltipManager;
CONFIG.ux.TemplateManager = new TemplateManager();
CONFIG.ux.TokenManager = new TokenManager();
CONFIG.debug.triggers = false;
Hooks.once('init', () => {
game.system.api = {
@ -92,7 +91,7 @@ Hooks.once('init', () => {
fields
};
game.system.registeredTriggers = new game.system.api.data.RegisteredTriggers();
game.system.registeredTriggers = new RegisteredTriggers();
const { DocumentSheetConfig } = foundry.applications.apps;
DocumentSheetConfig.unregisterSheet(TokenDocument, 'core', foundry.applications.sheets.TokenConfig);
@ -423,12 +422,49 @@ Hooks.on('refreshToken', (_, options) => {
Hooks.on('renderCompendiumDirectory', (app, html) => applications.ui.ItemBrowser.injectSidebarButton(html));
Hooks.on('renderDocumentDirectory', (app, html) => applications.ui.ItemBrowser.injectSidebarButton(html));
/* Non actor-linked Actors should unregister the triggers of their tokens if a scene's token layer is torn down */
Hooks.on('canvasTearDown', canvas => {
game.system.registeredTriggers.unregisterSceneTriggers(canvas.scene);
});
class RegisteredTriggers extends Map {
constructor() {
super();
}
/* Non actor-linked Actors should register the triggers of their tokens on a readied scene */
Hooks.on('canvasReady', canas => {
game.system.registeredTriggers.registerSceneTriggers(canvas.scene);
});
async registerTriggers(trigger, actor, triggeringActorType, uuid, commands) {
const existingTrigger = this.get(trigger);
if (!existingTrigger) this.set(trigger, new Map());
this.get(trigger).set(uuid, { actor, triggeringActorType, commands });
}
async runTrigger(trigger, currentActor, ...args) {
const updates = [];
const triggerSettings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).triggers;
if (!triggerSettings.enabled) return updates;
const dualityTrigger = this.get(trigger);
if (dualityTrigger) {
for (let { actor, triggeringActorType, commands } of dualityTrigger.values()) {
const triggerData = CONFIG.DH.TRIGGER.triggers[trigger];
if (triggerData.usesActor && triggeringActorType !== 'any') {
if (triggeringActorType === 'self' && currentActor?.uuid !== actor) continue;
else if (triggeringActorType === 'other' && currentActor?.uuid === actor) continue;
}
for (let command of commands) {
try {
const result = await command(...args);
if (result?.updates?.length) updates.push(...result.updates);
} catch (_) {
const triggerName = game.i18n.localize(triggerData.label);
ui.notifications.error(
game.i18n.format('DAGGERHEART.CONFIG.Triggers.triggerError', {
trigger: triggerName,
actor: currentActor?.name
})
);
}
}
}
}
return updates;
}
}

View file

@ -615,8 +615,7 @@
"rerollDice": "Reroll Dice"
},
"RiskItAllDialog": {
"title": "Character: {name} - Risk It All - Clear Stress and/or Hit Points",
"subtitle": "Clear {hope} Stress and/or Hit Points",
"title": "Risk It All - Clear Stress and Hope",
"submit": "Submit"
},
"TagTeamSelect": {
@ -2091,7 +2090,6 @@
"tier4": "tier 4",
"domains": "Domains",
"downtime": "Downtime",
"itemFeatures": "Item Features",
"roll": "Roll",
"rules": "Rules",
"partyMembers": "Party Members",
@ -2731,9 +2729,6 @@
"rerollDamage": "Reroll Damage",
"assignTagRoll": "Assign as Tag Roll"
},
"ConsoleLogs": {
"triggerRun": "DH TRIGGER | Item '{item}' on actor '{actor}' ran a '{trigger}' trigger."
},
"Countdowns": {
"title": "Countdowns",
"toggleIconMode": "Toggle Icon Only",

View file

@ -123,7 +123,7 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
context.formula = this.roll.constructFormula(this.config);
if (this.actor?.system?.traits) context.abilities = this.getTraitModifiers();
context.showReaction = !this.config.roll?.type || context.rollType === 'DualityRoll';
context.showReaction = !this.config.roll?.type && context.rollType === 'DualityRoll';
context.reactionOverride = this.reactionOverride;
}

View file

@ -9,7 +9,7 @@ export default class RiskItAllDialog extends HandlebarsApplicationMixin(Applicat
}
get title() {
return game.i18n.format('DAGGERHEART.APPLICATIONS.RiskItAllDialog.title', { name: this.actor.name });
return game.i18n.format('DAGGERHEART.APPLICATIONS.RiskItAllDialog.title', { actor: this.actor.name });
}
static DEFAULT_OPTIONS = {
@ -31,39 +31,12 @@ export default class RiskItAllDialog extends HandlebarsApplicationMixin(Applicat
async _prepareContext(_options) {
const context = await super._prepareContext(_options);
context.RiskItAllDialog = this.RiskItAllDialog;
context.title = game.i18n.format('DAGGERHEART.APPLICATIONS.RiskItAllDialog.subtitle', { hope: this.config.hope });
context.currentHitPointsLabel = "Current Marked Hit Points: " + this.actor.system.resources.hitPoints.value;
context.currentStressLabel = "Current Marked Stress: " + this.actor.system.resources.stress.value;
context.newHitPoints = this.actor.system.resources.hitPoints.value;
context.newStress = this.actor.system.resources.stress.value;
context.title = game.i18n.localize('DAGGERHEART.APPLICATIONS.RiskItAllDialog.submit');
return context;
}
static checkForValidChoice() {
/*
TODO:
return (this.config.hope == (this.actor.system.resources.hitPoints.value - newHitPointValue) + (this.actor.system.resources.stress.value - newStressValue));
*/
return true;
}
static async submit() {
this.close();
// TODO: Update actor with changes.
await this.actor.update({
system: {
resources: {
hitPoints: {
value: 0 // TODO put editted value here
},
stress: {
value: 0 // TODO put editted value here
}
}
}
});
}
}

View file

@ -712,7 +712,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
headerTitle: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', {
ability: abilityLabel
}),
effects: await game.system.api.data.actions.actionsTypes.base.getEffects(this.document),
effects: Array.from(await this.document.allApplicableEffects()),
roll: {
trait: button.dataset.attribute,
type: 'trait'

View file

@ -505,10 +505,7 @@ export default function DHApplicationMixin(Base) {
const doc = await getDocFromElement(target),
action = doc?.system?.attack ?? doc;
const config = action.prepareConfig(event);
config.effects = await game.system.api.data.actions.actionsTypes.base.getEffects(
this.document,
doc
);
config.effects = Array.from(await this.document.allApplicableEffects());
config.hasRoll = false;
return action && action.workflow.get('damage').execute(config, null, true);
}

View file

@ -25,7 +25,7 @@ export default class DaggerheartMenu extends HandlebarsApplicationMixin(Abstract
/** @override */
static DEFAULT_OPTIONS = {
classes: ['dh-style', 'directory'],
classes: ['dh-style'],
window: {
title: 'SIDEBAR.TabSettings'
},

View file

@ -96,19 +96,6 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
super.close(options);
}
/** Ensure the chat theme inherits the interface theme */
_replaceHTML(result, content, options) {
const themedElement = result.log?.querySelector(".chat-log");
themedElement?.classList.remove("themed", "theme-light", "theme-dark");
super._replaceHTML(result, content, options);
}
/** Remove chat log theme from notifications area */
async _onFirstRender(result, content) {
await super._onFirstRender(result, content);
document.querySelector("#chat-notifications .chat-log")?.classList.remove("themed", "theme-light", "theme-dark")
}
async onRollSimple(event, message) {
const buttonType = event.target.dataset.type ?? 'damage',
total = message.rolls.reduce((a, c) => a + Roll.fromJSON(c).total, 0),

View file

@ -1,7 +1,6 @@
export { default as DhCombat } from './combat.mjs';
export { default as DhCombatant } from './combatant.mjs';
export { default as DhTagTeamRoll } from './tagTeamRoll.mjs';
export { default as RegisteredTriggers } from './registeredTriggers.mjs';
export * as countdowns from './countdowns.mjs';
export * as actions from './action/_module.mjs';

View file

@ -198,7 +198,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
let config = this.prepareConfig(event);
if (!config) return;
config.effects = await game.system.api.data.actions.actionsTypes.base.getEffects(this.actor, this.item);
await this.addEffects(config);
if (Hooks.call(`${CONFIG.DH.id}.preUseAction`, this, config) === false) return;
@ -266,26 +266,14 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
return config;
}
/**
* Get the all potentially applicable effects on the actor
* @param {DHActor} actor The actor performing the action
* @param {DHItem|DhActor} effectParent The parent of the effect
* @returns {DhActiveEffect[]}
*/
static async getEffects(actor, effectParent) {
if (!actor) return [];
/** */
async addEffects(config) {
let effects = [];
if (this.actor) {
effects = Array.from(await this.actor.allApplicableEffects());
}
return Array.from(await actor.allApplicableEffects()).filter(effect => {
/* Effects on weapons only ever apply for the weapon itself */
if (effect.parent.type === 'weapon') {
/* Unless they're secondary - then they apply only to other primary weapons */
if (effect.parent.system.secondary) {
if (effectParent?.type !== 'weapon' || effectParent?.system.secondary) return false;
} else if (effectParent?.id !== effect.parent.id) return false;
}
return !effect.isSuppressed;
});
config.effects = effects;
}
/**

View file

@ -164,7 +164,26 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
prepareBaseData() {
super.prepareBaseData();
game.system.registeredTriggers.registerItemTriggers(this.parent);
for (const action of this.actions ?? []) {
if (!action.actor) continue;
const actionsToRegister = [];
for (let i = 0; i < action.triggers.length; i++) {
const trigger = action.triggers[i];
const { args } = CONFIG.DH.TRIGGER.triggers[trigger.trigger];
const fn = new foundry.utils.AsyncFunction(...args, `{${trigger.command}\n}`);
actionsToRegister.push(fn.bind(action));
if (i === action.triggers.length - 1)
game.system.registeredTriggers.registerTriggers(
trigger.trigger,
action.actor?.uuid,
trigger.triggeringActorType,
this.parent.uuid,
actionsToRegister
);
}
}
}
async _preCreate(data, options, user) {
@ -227,28 +246,6 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
const armorData = getScrollTextData(this.parent.parent.system.resources, changed.system.marks, 'armor');
options.scrollingTextData = [armorData];
}
if (changed.system?.actions) {
const triggersToRemove = Object.keys(changed.system.actions).reduce((acc, key) => {
if (!changed.system.actions[key]) {
const strippedKey = key.replace('-=', '');
acc.push(...this.actions.get(strippedKey).triggers.map(x => x.trigger));
}
return acc;
}, []);
game.system.registeredTriggers.unregisterTriggers(triggersToRemove, this.parent.uuid);
if (!(this.parent.parent.token instanceof game.system.api.documents.DhToken)) {
for (const token of this.parent.parent.getActiveTokens()) {
game.system.registeredTriggers.unregisterTriggers(
triggersToRemove,
`${token.document.uuid}.${this.parent.uuid}`
);
}
}
}
}
_onUpdate(changed, options, userId) {

View file

@ -1,154 +0,0 @@
export default class RegisteredTriggers extends Map {
constructor() {
super();
}
registerTriggers(triggers, actor, uuid) {
for (const triggerKey of Object.keys(CONFIG.DH.TRIGGER.triggers)) {
const match = triggers[triggerKey];
const existingTrigger = this.get(triggerKey);
if (!match) {
if (existingTrigger?.get(uuid)) this.get(triggerKey).delete(uuid);
} else {
const { trigger, triggeringActorType, commands } = match;
if (!existingTrigger) this.set(trigger, new Map());
this.get(trigger).set(uuid, { actor, triggeringActorType, commands });
}
}
}
registerItemTriggers(item, registerOverride) {
for (const action of item.system.actions ?? []) {
if (!action.actor) continue;
/* Non actor-linked should only prep synthetic actors so they're not registering triggers unless they're on the canvas */
if (
!registerOverride &&
!action.actor.prototypeToken.actorLink &&
(!(action.actor.parent instanceof game.system.api.documents.DhToken) || !action.actor.parent?.uuid)
)
continue;
const triggers = {};
for (const trigger of action.triggers) {
const { args } = CONFIG.DH.TRIGGER.triggers[trigger.trigger];
const fn = new foundry.utils.AsyncFunction(...args, `{${trigger.command}\n}`);
if (!triggers[trigger.trigger])
triggers[trigger.trigger] = {
trigger: trigger.trigger,
triggeringActorType: trigger.triggeringActorType,
commands: []
};
triggers[trigger.trigger].commands.push(fn.bind(action));
}
this.registerTriggers(triggers, action.actor?.uuid, item.uuid);
}
}
unregisterTriggers(triggerKeys, uuid) {
for (const triggerKey of triggerKeys) {
const existingTrigger = this.get(triggerKey);
if (!existingTrigger) return;
existingTrigger.delete(uuid);
}
}
unregisterItemTriggers(items) {
for (const item of items) {
if (!item.system.actions.size) continue;
const triggers = (item.system.actions ?? []).reduce((acc, action) => {
acc.push(...action.triggers.map(x => x.trigger));
return acc;
}, []);
this.unregisterTriggers(triggers, item.uuid);
}
}
unregisterSceneTriggers(scene) {
for (const triggerKey of Object.keys(CONFIG.DH.TRIGGER.triggers)) {
const existingTrigger = this.get(triggerKey);
if (!existingTrigger) continue;
const filtered = new Map();
for (const [uuid, data] of existingTrigger.entries()) {
if (!uuid.startsWith(scene.uuid)) filtered.set(uuid, data);
}
this.set(triggerKey, filtered);
}
}
registerSceneTriggers(scene) {
/* TODO: Finish sceneEnvironment registration and unreg */
// const systemData = new game.system.api.data.scenes.DHScene(scene.flags.daggerheart);
// for (const environment of systemData.sceneEnvironments) {
// for (const feature of environment.system.features) {
// if(feature) this.registerItemTriggers(feature, true);
// }
// }
for (const actor of scene.tokens.filter(x => x.actor).map(x => x.actor)) {
if (actor.prototypeToken.actorLink) continue;
for (const item of actor.items) {
this.registerItemTriggers(item);
}
}
}
async runTrigger(trigger, currentActor, ...args) {
const updates = [];
const triggerSettings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).triggers;
if (!triggerSettings.enabled) return updates;
const dualityTrigger = this.get(trigger);
if (dualityTrigger) {
const tokenBoundActors = ['adversary', 'environment'];
const triggerActors = ['character', ...tokenBoundActors];
for (let [itemUuid, { actor: actorUuid, triggeringActorType, commands }] of dualityTrigger.entries()) {
const actor = await foundry.utils.fromUuid(actorUuid);
if (!actor || !triggerActors.includes(actor.type)) continue;
if (tokenBoundActors.includes(actor.type) && !actor.getActiveTokens().length) continue;
const triggerData = CONFIG.DH.TRIGGER.triggers[trigger];
if (triggerData.usesActor && triggeringActorType !== 'any') {
if (triggeringActorType === 'self' && currentActor?.uuid !== actorUuid) continue;
else if (triggeringActorType === 'other' && currentActor?.uuid === actorUuid) continue;
}
for (const command of commands) {
try {
if (CONFIG.debug.triggers) {
const item = await foundry.utils.fromUuid(itemUuid);
console.log(
game.i18n.format('DAGGERHEART.UI.ConsoleLogs.triggerRun', {
actor: actor.name ?? '<Missing Actor>',
item: item?.name ?? '<Missing Item>',
trigger: game.i18n.localize(triggerData.label)
})
);
}
const result = await command(...args);
if (result?.updates?.length) updates.push(...result.updates);
} catch (_) {
const triggerName = game.i18n.localize(triggerData.label);
ui.notifications.error(
game.i18n.format('DAGGERHEART.CONFIG.Triggers.triggerError', {
trigger: triggerName,
actor: currentActor?.name
})
);
}
}
}
}
return updates;
}
}

View file

@ -104,16 +104,6 @@ export default class DhpActor extends Actor {
}
}
async _preDelete() {
if (this.prototypeToken.actorLink) {
game.system.registeredTriggers.unregisterItemTriggers(this.items);
} else {
for (const token of this.getActiveTokens()) {
game.system.registeredTriggers.unregisterItemTriggers(token.actor.items);
}
}
}
_onDelete(options, userId) {
super._onDelete(options, userId);
for (const party of this.parties) {

View file

@ -167,9 +167,7 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
const config = foundry.utils.deepClone(this.system);
config.event = event;
if (this.system.action) {
const actor = await foundry.utils.fromUuid(config.source.actor);
const item = actor?.items.get(config.source.item) ?? null;
config.effects = await game.system.api.data.actions.actionsTypes.base.getEffects(actor, item);
await this.system.action.addEffects(config);
await this.system.action.workflow.get('damage')?.execute(config, this._id, true);
}
@ -203,16 +201,7 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
return ui.notifications.info(game.i18n.localize('DAGGERHEART.UI.Notifications.noTargetsSelectedOrPerm'));
this.consumeOnSuccess();
if (this.system.action) this.system.action.workflow.get('applyDamage')?.execute(config, targets, true);
else {
for (const target of targets) {
const actor = await foundry.utils.fromUuid(target.actorId);
if (!actor) continue;
if (this.system.hasHealing) actor.takeHealing(this.system.damage);
else actor.takeDamage(this.system.damage);
}
}
this.system.action?.workflow.get('applyDamage')?.execute(config, targets, true);
}
async onRollSave(event) {

View file

@ -208,23 +208,4 @@ export default class DHItem extends foundry.documents.Item {
cls.create(msg);
}
deleteTriggers() {
const actions = Array.from(this.system.actions ?? []);
if (!actions.length) return;
const triggerKeys = actions.flatMap(action => action.triggers.map(x => x.trigger));
game.system.registeredTriggers.unregisterTriggers(triggerKeys, this.uuid);
if (!(this.actor.parent instanceof game.system.api.documents.DhToken)) {
for (const token of this.actor.getActiveTokens()) {
game.system.registeredTriggers.unregisterTriggers(triggerKeys, `${token.document.uuid}.${this.uuid}`);
}
}
}
async _preDelete() {
this.deleteTriggers();
}
}

View file

@ -536,10 +536,4 @@ export default class DHToken extends CONFIG.Token.documentClass {
};
}
//#endregion
async _preDelete() {
if (this.actor && !this.actor.prototypeToken?.actorLink) {
game.system.registeredTriggers.unregisterItemTriggers(this.actor.items);
}
}
}

View file

@ -113,7 +113,18 @@
"name": "Powerful",
"description": "On a successful attack, roll an additional damage die and discard the lowest result.",
"img": "icons/magic/control/buff-flight-wings-runes-red-yellow.webp",
"changes": [],
"changes": [
{
"key": "system.bonuses.damage.primaryWeapon.extraDice",
"mode": 2,
"value": "1"
},
{
"key": "system.rules.weapon.dropLowestDamageDice",
"mode": 5,
"value": "1"
}
],
"_id": "sGVVxSM68Fmr1sSM",
"type": "base",
"system": {},

View file

@ -118,6 +118,16 @@
"key": "system.evasion",
"mode": 2,
"value": "-1"
},
{
"key": "system.bonuses.damage.primaryWeapon.extraDice",
"mode": 2,
"value": "1"
},
{
"key": "system.rules.weapon.dropLowestDamageDice",
"mode": 5,
"value": "1"
}
],
"_id": "E0PjC15OP55vIype",

View file

@ -113,7 +113,18 @@
"name": "Powerful",
"description": "On a successful attack, roll an additional damage die and discard the lowest result.",
"img": "icons/magic/control/buff-flight-wings-runes-red-yellow.webp",
"changes": [],
"changes": [
{
"key": "system.bonuses.damage.primaryWeapon.extraDice",
"mode": 2,
"value": "1"
},
{
"key": "system.rules.weapon.dropLowestDamageDice",
"mode": 5,
"value": "1"
}
],
"_id": "DCie5eR1dZH2Qvln",
"type": "base",
"system": {},

View file

@ -113,7 +113,18 @@
"name": "Powerful",
"description": "On a successful attack, roll an additional damage die and discard the lowest result.",
"img": "icons/magic/control/buff-flight-wings-runes-red-yellow.webp",
"changes": [],
"changes": [
{
"key": "system.bonuses.damage.primaryWeapon.extraDice",
"mode": 2,
"value": "1"
},
{
"key": "system.rules.weapon.dropLowestDamageDice",
"mode": 5,
"value": "1"
}
],
"_id": "sZ1XotFlGdkPPDG4",
"type": "base",
"system": {},

View file

@ -113,7 +113,18 @@
"name": "Powerful",
"description": "On a successful attack, roll an additional damage die and discard the lowest result.",
"img": "icons/magic/control/buff-flight-wings-runes-red-yellow.webp",
"changes": [],
"changes": [
{
"key": "system.bonuses.damage.primaryWeapon.extraDice",
"mode": 2,
"value": "1"
},
{
"key": "system.rules.weapon.dropLowestDamageDice",
"mode": 5,
"value": "1"
}
],
"_id": "T831j6kZiMnpMNmv",
"type": "base",
"system": {},

View file

@ -113,7 +113,18 @@
"name": "Powerful",
"description": "On a successful attack, roll an additional damage die and discard the lowest result.",
"img": "icons/magic/control/buff-flight-wings-runes-red-yellow.webp",
"changes": [],
"changes": [
{
"key": "system.bonuses.damage.primaryWeapon.extraDice",
"mode": 2,
"value": "1"
},
{
"key": "system.rules.weapon.dropLowestDamageDice",
"mode": 5,
"value": "1"
}
],
"_id": "ir4iKLIQ4CH1Qckn",
"type": "base",
"system": {},

View file

@ -113,7 +113,18 @@
"name": "Powerful",
"description": "On a successful attack, roll an additional damage die and discard the lowest result.",
"img": "icons/magic/control/buff-flight-wings-runes-red-yellow.webp",
"changes": [],
"changes": [
{
"key": "system.bonuses.damage.primaryWeapon.extraDice",
"mode": 2,
"value": "1"
},
{
"key": "system.rules.weapon.dropLowestDamageDice",
"mode": 5,
"value": "1"
}
],
"_id": "K4VgrDjVj1U1m9Ie",
"type": "base",
"system": {},

View file

@ -113,7 +113,18 @@
"name": "Powerful",
"description": "On a successful attack, roll an additional damage die and discard the lowest result.",
"img": "icons/magic/control/buff-flight-wings-runes-red-yellow.webp",
"changes": [],
"changes": [
{
"key": "system.bonuses.damage.primaryWeapon.extraDice",
"mode": 2,
"value": "1"
},
{
"key": "system.rules.weapon.dropLowestDamageDice",
"mode": 5,
"value": "1"
}
],
"_id": "904orawScurM9GjG",
"type": "base",
"system": {},

View file

@ -118,6 +118,16 @@
"key": "system.evasion",
"mode": 2,
"value": "-1"
},
{
"key": "system.bonuses.damage.primaryWeapon.extraDice",
"mode": 2,
"value": "1"
},
{
"key": "system.rules.weapon.dropLowestDamageDice",
"mode": 5,
"value": "1"
}
],
"_id": "cffkpiwGpEGhjiUC",

View file

@ -113,7 +113,18 @@
"name": "Powerful",
"description": "On a successful attack, roll an additional damage die and discard the lowest result.",
"img": "icons/magic/control/buff-flight-wings-runes-red-yellow.webp",
"changes": [],
"changes": [
{
"key": "system.bonuses.damage.primaryWeapon.extraDice",
"mode": 2,
"value": "1"
},
{
"key": "system.rules.weapon.dropLowestDamageDice",
"mode": 5,
"value": "1"
}
],
"_id": "hnayB09P25ZW3gVY",
"type": "base",
"system": {},

View file

@ -118,6 +118,16 @@
"key": "system.evasion",
"mode": 2,
"value": "-1"
},
{
"key": "system.bonuses.damage.primaryWeapon.extraDice",
"mode": 2,
"value": "1"
},
{
"key": "system.rules.weapon.dropLowestDamageDice",
"mode": 5,
"value": "1"
}
],
"_id": "2nl35v8sPAudiOIb",

View file

@ -113,7 +113,18 @@
"name": "Powerful",
"description": "On a successful attack, roll an additional damage die and discard the lowest result.",
"img": "icons/magic/control/buff-flight-wings-runes-red-yellow.webp",
"changes": [],
"changes": [
{
"key": "system.bonuses.damage.primaryWeapon.extraDice",
"mode": 2,
"value": "1"
},
{
"key": "system.rules.weapon.dropLowestDamageDice",
"mode": 5,
"value": "1"
}
],
"_id": "OV1Ly7vX4owBUgLQ",
"type": "base",
"system": {},

View file

@ -118,6 +118,16 @@
"key": "system.evasion",
"mode": 2,
"value": "-1"
},
{
"key": "system.bonuses.damage.primaryWeapon.extraDice",
"mode": 2,
"value": "1"
},
{
"key": "system.rules.weapon.dropLowestDamageDice",
"mode": 5,
"value": "1"
}
],
"_id": "oRCiXSElN5xufUfn",

View file

@ -113,7 +113,18 @@
"name": "Powerful",
"description": "On a successful attack, roll an additional damage die and discard the lowest result.",
"img": "icons/magic/control/buff-flight-wings-runes-red-yellow.webp",
"changes": [],
"changes": [
{
"key": "system.bonuses.damage.primaryWeapon.extraDice",
"mode": 2,
"value": "1"
},
{
"key": "system.rules.weapon.dropLowestDamageDice",
"mode": 5,
"value": "1"
}
],
"_id": "2J6vzNUel78JFypp",
"type": "base",
"system": {},

View file

@ -2,18 +2,20 @@
@import '../utils/fonts.less';
@import '../utils/mixin.less';
.daggerheart.chat-sidebar.theme-light,
#interface.theme-light {
.chat-log .chat-message {
background-image: url('../assets/parchments/dh-parchment-light.png');
.theme-light {
.daggerheart.chat-sidebar .chat-log,
#chat-notifications .chat-log {
.chat-message {
background-image: url('../assets/parchments/dh-parchment-light.png');
.message-header .message-header-metadata .message-metadata,
.message-header .message-header-main .message-sub-header-container {
color: @dark;
}
.message-header .message-header-metadata .message-metadata,
.message-header .message-header-main .message-sub-header-container {
color: @dark;
}
.message-header .message-header-main .message-sub-header-container h4 {
color: @dark-blue;
.message-header .message-header-main .message-sub-header-container h4 {
color: @dark-blue;
}
}
}
}

View file

@ -2,7 +2,6 @@
@import '../../utils/fonts.less';
@import '../../utils/spacing.less';
.daggerheart.chat-sidebar.theme-light,
#interface.theme-light {
.daggerheart.chat.domain-card {
.domain-card-move .domain-card-header {

View file

@ -2,7 +2,6 @@
@import '../../utils/fonts.less';
@import '../../utils/spacing.less';
.daggerheart.chat-sidebar.theme-light,
#interface.theme-light {
.daggerheart.chat.action {
.action-move .action-section {

View file

@ -2,9 +2,9 @@
@import '../../utils/fonts.less';
@import '../../utils/spacing.less';
.daggerheart.chat-sidebar.theme-light,
#interface.theme-light {
.chat-log {
.daggerheart.chat-sidebar .chat-log,
#chat-notifications .chat-log {
--text-color: @dark-blue;
--bg-color: @dark-blue-40;

View file

@ -1,6 +1,5 @@
@import '../../utils/colors.less';
.daggerheart.chat-sidebar.theme-light,
#interface.theme-light {
.daggerheart.chat.damage-summary .token-target-container {
&:hover {

View file

@ -2,7 +2,6 @@
@import '../../utils/fonts.less';
@import '../../utils/spacing.less';
.daggerheart.chat-sidebar.theme-light,
#interface.theme-light {
.daggerheart.chat.downtime {
.downtime-moves-list .downtime-move {

View file

@ -1,6 +1,5 @@
@import '../../utils/colors.less';
.daggerheart.chat-sidebar.theme-light,
#interface.theme-light {
.daggerheart.chat.effect-summary {
.effect-header,

View file

@ -125,9 +125,9 @@
.group-roll-trait {
padding: 2px 8px;
border: 1px solid light-dark(@dark-blue, white);
border: 1px solid light-dark(white, white);
border-radius: 6px;
color: light-dark(@dark-blue, white);
color: light-dark(white, white);
background: light-dark(@beige-80, @beige-80);
}
}

View file

@ -1,7 +1,6 @@
@import '../../utils/colors.less';
@import '../../utils/fonts.less';
.daggerheart.chat-sidebar.theme-light,
#interface.theme-light {
.chat-message:not(.duality) .message-content {
color: @dark;

View file

@ -5,8 +5,6 @@
display: flex;
flex-direction: column;
gap: 8px;
overflow: auto;
height: 100%;
}
h2 {

View file

@ -2,7 +2,7 @@
"id": "daggerheart",
"title": "Daggerheart",
"description": "An unofficial implementation of the Daggerheart system",
"version": "1.5.2",
"version": "1.5.0",
"compatibility": {
"minimum": "13.346",
"verified": "13.351",

View file

@ -2,23 +2,8 @@
<header class="dialog-header">
<h1>{{title}}</h1>
</header>
<div>
<span>Remaining points to use here.</span>
</div>
<div class="risk-it-all-container">
<div class="two-columns even">
<span>{{currentHitPointsLabel}}</span>
<div>
<span>New Hit Points Value</span>
<input type="text" data-dtype="Number" name="newHitPoints" value="{{newHitPoints}}" />
</div>
<span>{{currentStressLabel}}</span>
<div>
<span>New Stress Value</span>
<input type="text" data-dtype="Number" name="newStress" value="{{newStress}}" />
</div>
</div>
<span>TODO magic here</span>
</div>
<footer class="flexrow">
<button data-action="close">

View file

@ -31,7 +31,10 @@
{{formGroup systemFields.resources.fields.stress.fields.max value=document._source.system.resources.stress.max localize=true}}
{{formGroup systemFields.resources.fields.hope.fields.value value=document._source.system.resources.hope.value localize=true}}
{{formGroup systemFields.resources.fields.hope.fields.max value=document._source.system.resources.hope.max localize=true}}
{{formGroup systemFields.scars value=document._source.system.scars localize=true}}
<span></span>
{{formGroup systemFields.proficiency value=document._source.system.proficiency localize=true}}
<span data-tooltip-text="{{localize "DAGGERHEART.UI.Tooltip.maxEvasionClassBound"}}">