mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-12 03:31:07 +01:00
166 - Damage Reduction (#180)
* Temp * Fixed Stress Reductions * Changed from index based to object
This commit is contained in:
parent
e1dd59454c
commit
5dafdaafcd
33 changed files with 1688 additions and 1013 deletions
|
|
@ -16,7 +16,7 @@ import Resources from './module/applications/resources.mjs';
|
|||
import { NarrativeCountdowns, registerCountdownApplicationHooks } from './module/applications/countdowns.mjs';
|
||||
import DHDualityRoll from './module/data/chat-message/dualityRoll.mjs';
|
||||
import { DualityRollColor } from './module/data/settings/Appearance.mjs';
|
||||
import { DHRoll, DualityRoll, D20Roll, DamageRoll, DualityDie } from './module/applications/roll.mjs'
|
||||
import { DHRoll, DualityRoll, D20Roll, DamageRoll, DualityDie } from './module/applications/roll.mjs';
|
||||
import { DhMeasuredTemplate } from './module/placeables/_module.mjs';
|
||||
import { renderDualityButton } from './module/enrichers/DualityRollEnricher.mjs';
|
||||
import { renderMeasuredTemplate } from './module/enrichers/TemplateEnricher.mjs';
|
||||
|
|
|
|||
20
lang/en.json
20
lang/en.json
|
|
@ -207,6 +207,12 @@
|
|||
"Session": "Session",
|
||||
"Shortrest": "Short Rest",
|
||||
"Longrest": "Long Rest"
|
||||
},
|
||||
"Damage": {
|
||||
"Severe": "Severe",
|
||||
"Major": "Major",
|
||||
"Minor": "Minor",
|
||||
"None": "None"
|
||||
}
|
||||
},
|
||||
"ActionType": {
|
||||
|
|
@ -1084,6 +1090,20 @@
|
|||
"Title": "Ownership Selection - {name}",
|
||||
"Default": "Default Ownership"
|
||||
},
|
||||
"DamageReduction": {
|
||||
"Title": "Damage Reduction",
|
||||
"ArmorMarks": "Armor Marks",
|
||||
"UsedMarks": "Used Marks",
|
||||
"Stress": "Stress",
|
||||
"ArmorWithStress": "Spend 1 stress to use an extra mark",
|
||||
"UnncessaryStress": "You don't need to expend stress",
|
||||
"StressReduction": "Reduce By Stress",
|
||||
"Notifications": {
|
||||
"DamageAlreadyNone": "The damage has already been reduced to none",
|
||||
"NoAvailableArmorMarks": "You have no more available armor marks",
|
||||
"DamageIgnore": "{character} did not take damage"
|
||||
}
|
||||
},
|
||||
"Sheets": {
|
||||
"PC": {
|
||||
"Name": "Name",
|
||||
|
|
|
|||
|
|
@ -60,11 +60,12 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) {
|
|||
context.tabs = this._getTabs();
|
||||
context.config = SYSTEM;
|
||||
if (!!this.action.effects) context.effects = this.action.effects.map(e => this.action.item.effects.get(e._id));
|
||||
if (this.action.damage?.hasOwnProperty('includeBase') && this.action.type === 'attack') context.hasBaseDamage = !!this.action.parent.damage;
|
||||
if (this.action.damage?.hasOwnProperty('includeBase') && this.action.type === 'attack')
|
||||
context.hasBaseDamage = !!this.action.parent.damage;
|
||||
context.getRealIndex = this.getRealIndex.bind(this);
|
||||
context.disableOption = this.disableOption.bind(this);
|
||||
context.isNPC = this.action.actor.type !== 'character';
|
||||
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
|
|
@ -76,9 +77,9 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) {
|
|||
disableOption(index, options, choices) {
|
||||
const filtered = foundry.utils.deepClone(options);
|
||||
Object.keys(filtered).forEach(o => {
|
||||
if(choices.find((c, idx) => c.type === o && index !== idx)) delete filtered[o];
|
||||
if (choices.find((c, idx) => c.type === o && index !== idx)) delete filtered[o];
|
||||
});
|
||||
return filtered
|
||||
return filtered;
|
||||
}
|
||||
|
||||
getRealIndex(index) {
|
||||
|
|
@ -99,14 +100,16 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) {
|
|||
data = foundry.utils.expandObject(foundry.utils.mergeObject(this.action.toObject(), submitData)),
|
||||
container = foundry.utils.getProperty(this.action.parent, this.action.systemPath);
|
||||
let newActions;
|
||||
if(Array.isArray(container)) {
|
||||
if (Array.isArray(container)) {
|
||||
newActions = foundry.utils.getProperty(this.action.parent, this.action.systemPath).map(x => x.toObject()); // Find better way
|
||||
if (!newActions.findSplice(x => x._id === data._id, data)) newActions.push(data);
|
||||
} else newActions = data;
|
||||
|
||||
|
||||
const updates = await this.action.parent.parent.update({ [`system.${this.action.systemPath}`]: newActions });
|
||||
if (!updates) return;
|
||||
this.action = Array.isArray(container) ? foundry.utils.getProperty(updates.system, this.action.systemPath)[this.action.index] : foundry.utils.getProperty(updates.system, this.action.systemPath);
|
||||
this.action = Array.isArray(container)
|
||||
? foundry.utils.getProperty(updates.system, this.action.systemPath)[this.action.index]
|
||||
: foundry.utils.getProperty(updates.system, this.action.systemPath);
|
||||
this.render();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ export default class CostSelectionDialog extends HandlebarsApplicationMixin(Appl
|
|||
}
|
||||
|
||||
async _prepareContext(_options) {
|
||||
console.log(this.costs)
|
||||
console.log(this.costs);
|
||||
const updatedCosts = this.action.calcCosts(this.costs),
|
||||
updatedUses = this.action.calcUses(this.uses);
|
||||
return {
|
||||
|
|
@ -56,12 +56,12 @@ export default class CostSelectionDialog extends HandlebarsApplicationMixin(Appl
|
|||
const data = foundry.utils.expandObject(formData.object);
|
||||
this.costs = foundry.utils.mergeObject(this.costs, data.costs);
|
||||
this.uses = foundry.utils.mergeObject(this.uses, data.uses);
|
||||
this.render(true)
|
||||
this.render(true);
|
||||
}
|
||||
|
||||
static sendCost(event) {
|
||||
event.preventDefault();
|
||||
this.resolve({ costs: this.action.getRealCosts(this.costs), uses: this.uses});
|
||||
this.resolve({ costs: this.action.getRealCosts(this.costs), uses: this.uses });
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
202
module/applications/damageReductionDialog.mjs
Normal file
202
module/applications/damageReductionDialog.mjs
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
import { damageKeyToNumber, getDamageLabel } from '../helpers/utils.mjs';
|
||||
|
||||
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
|
||||
|
||||
export default class DamageReductionDialog extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
constructor(resolve, reject, actor, damage) {
|
||||
super({});
|
||||
|
||||
this.resolve = resolve;
|
||||
this.reject = reject;
|
||||
this.actor = actor;
|
||||
this.damage = damage;
|
||||
|
||||
const maxArmorMarks = Math.min(
|
||||
actor.system.armorScore - actor.system.armor.system.marks.value,
|
||||
actor.system.rules.maxArmorMarked.total
|
||||
);
|
||||
|
||||
const armor = [...Array(maxArmorMarks).keys()].reduce((acc, _) => {
|
||||
acc[foundry.utils.randomID()] = { selected: false };
|
||||
return acc;
|
||||
}, {});
|
||||
const stress = [...Array(actor.system.rules.maxArmorMarked.stressExtra ?? 0).keys()].reduce((acc, _) => {
|
||||
acc[foundry.utils.randomID()] = { selected: false };
|
||||
return acc;
|
||||
}, {});
|
||||
this.marks = { armor, stress };
|
||||
|
||||
this.availableStressReductions = Object.keys(actor.system.rules.stressDamageReduction).reduce((acc, key) => {
|
||||
const dr = actor.system.rules.stressDamageReduction[key];
|
||||
if (dr.enabled) {
|
||||
if (acc === null) acc = {};
|
||||
|
||||
const damage = damageKeyToNumber(key);
|
||||
acc[damage] = {
|
||||
cost: dr.cost,
|
||||
selected: false,
|
||||
from: getDamageLabel(damage),
|
||||
to: getDamageLabel(damage - 1)
|
||||
};
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, null);
|
||||
}
|
||||
|
||||
get title() {
|
||||
return game.i18n.localize('DAGGERHEART.DamageReduction.Title');
|
||||
}
|
||||
|
||||
static DEFAULT_OPTIONS = {
|
||||
tag: 'form',
|
||||
classes: ['daggerheart', 'views', 'damage-reduction'],
|
||||
position: {
|
||||
width: 240,
|
||||
height: 'auto'
|
||||
},
|
||||
actions: {
|
||||
setMarks: this.setMarks,
|
||||
useStressReduction: this.useStressReduction,
|
||||
takeDamage: this.takeDamage
|
||||
},
|
||||
form: {
|
||||
handler: this.updateData,
|
||||
submitOnChange: true,
|
||||
closeOnSubmit: false
|
||||
}
|
||||
};
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
damageSelection: {
|
||||
id: 'damageReduction',
|
||||
template: 'systems/daggerheart/templates/views/damageReduction.hbs'
|
||||
}
|
||||
};
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @inheritDoc */
|
||||
get title() {
|
||||
return `Damage Options`;
|
||||
}
|
||||
|
||||
async _prepareContext(_options) {
|
||||
const context = await super._prepareContext(_options);
|
||||
|
||||
const { selectedArmorMarks, selectedStressMarks, stressReductions, currentMarks, currentDamage } =
|
||||
this.getDamageInfo();
|
||||
|
||||
context.armorScore = this.actor.system.armorScore;
|
||||
context.armorMarks = currentMarks;
|
||||
context.basicMarksUsed = selectedArmorMarks.length === this.actor.system.rules.maxArmorMarked.total;
|
||||
|
||||
const stressReductionStress = this.availableStressReductions
|
||||
? stressReductions.reduce((acc, red) => acc + red.cost, 0)
|
||||
: 0;
|
||||
context.stress =
|
||||
selectedStressMarks.length > 0 || this.availableStressReductions
|
||||
? {
|
||||
value:
|
||||
this.actor.system.resources.stress.value + selectedStressMarks.length + stressReductionStress,
|
||||
maxTotal: this.actor.system.resources.stress.maxTotal
|
||||
}
|
||||
: null;
|
||||
|
||||
context.marks = this.marks;
|
||||
context.availableStressReductions = this.availableStressReductions;
|
||||
|
||||
context.damage = getDamageLabel(this.damage);
|
||||
context.reducedDamage = currentDamage !== this.damage ? getDamageLabel(currentDamage) : null;
|
||||
context.currentDamage = context.reducedDamage ?? context.damage;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
static updateData(event, _, formData) {
|
||||
const form = foundry.utils.expandObject(formData.object);
|
||||
this.render(true);
|
||||
}
|
||||
|
||||
getDamageInfo = () => {
|
||||
const selectedArmorMarks = Object.values(this.marks.armor).filter(x => x.selected);
|
||||
const selectedStressMarks = Object.values(this.marks.stress).filter(x => x.selected);
|
||||
const stressReductions = Object.values(this.availableStressReductions).filter(red => red.selected);
|
||||
const currentMarks =
|
||||
this.actor.system.armor.system.marks.value + selectedArmorMarks.length + selectedStressMarks.length;
|
||||
|
||||
const currentDamage =
|
||||
this.damage - selectedArmorMarks.length - selectedStressMarks.length - stressReductions.length;
|
||||
|
||||
return { selectedArmorMarks, selectedStressMarks, stressReductions, currentMarks, currentDamage };
|
||||
};
|
||||
|
||||
static setMarks(_, target) {
|
||||
const currentMark = this.marks[target.dataset.type][target.dataset.key];
|
||||
const { selectedStressMarks, stressReductions, currentMarks, currentDamage } = this.getDamageInfo();
|
||||
if (!currentMark.selected && currentDamage === 0) {
|
||||
ui.notifications.info(game.i18n.localize('DAGGERHEART.DamageReduction.Notifications.DamageAlreadyNone'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!currentMark.selected && currentMarks === this.actor.system.armorScore) {
|
||||
ui.notifications.info(
|
||||
game.i18n.localize('DAGGERHEART.DamageReduction.Notifications.NoAvailableArmorMarks')
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentMark.selected) {
|
||||
const currentDamageLabel = getDamageLabel(currentDamage);
|
||||
for (let reduction of stressReductions) {
|
||||
if (reduction.selected && reduction.to === currentDamageLabel) {
|
||||
reduction.selected = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (target.dataset.type === 'armor' && selectedStressMarks.length > 0) {
|
||||
selectedStressMarks.forEach(mark => (mark.selected = false));
|
||||
}
|
||||
}
|
||||
|
||||
currentMark.selected = !currentMark.selected;
|
||||
this.render();
|
||||
}
|
||||
|
||||
static useStressReduction(_, target) {
|
||||
const damageValue = Number(target.dataset.reduction);
|
||||
const stressReduction = this.availableStressReductions[damageValue];
|
||||
const { currentDamage } = this.getDamageInfo();
|
||||
|
||||
if (stressReduction.selected) {
|
||||
stressReduction.selected = false;
|
||||
this.render();
|
||||
} else {
|
||||
const reducedDamage = currentDamage !== this.damage ? getDamageLabel(currentDamage) : null;
|
||||
const currentDamageLabel = reducedDamage ?? getDamageLabel(this.damage);
|
||||
|
||||
if (stressReduction.from !== currentDamageLabel) return;
|
||||
|
||||
stressReduction.selected = true;
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
||||
static async takeDamage() {
|
||||
const { selectedArmorMarks, selectedStressMarks, stressReductions, currentDamage } = this.getDamageInfo();
|
||||
const armorSpent = selectedArmorMarks.length + selectedStressMarks.length;
|
||||
const stressSpent = selectedStressMarks.length + stressReductions.reduce((acc, red) => acc + red.cost, 0);
|
||||
|
||||
this.resolve({ modifiedDamage: currentDamage, armorSpent, stressSpent });
|
||||
await this.close(true);
|
||||
}
|
||||
|
||||
async close(fromSave) {
|
||||
if (!fromSave) {
|
||||
this.reject();
|
||||
}
|
||||
|
||||
await super.close({});
|
||||
}
|
||||
}
|
||||
|
|
@ -11,61 +11,65 @@ export class DHRoll extends Roll {
|
|||
super(formula, data, options);
|
||||
}
|
||||
|
||||
static async build(config={}, message={}) {
|
||||
static async build(config = {}, message = {}) {
|
||||
const roll = await this.buildConfigure(config, message);
|
||||
if(!roll) return;
|
||||
await this.buildEvaluate(roll, config, message={});
|
||||
await this.buildPost(roll, config, message={});
|
||||
if (!roll) return;
|
||||
await this.buildEvaluate(roll, config, (message = {}));
|
||||
await this.buildPost(roll, config, (message = {}));
|
||||
return roll;
|
||||
}
|
||||
|
||||
static async buildConfigure(config={}, message={}) {
|
||||
config.hooks = [...(config.hooks ?? []), ""];
|
||||
|
||||
static async buildConfigure(config = {}, message = {}) {
|
||||
config.hooks = [...(config.hooks ?? []), ''];
|
||||
config.dialog ??= {};
|
||||
for ( const hook of config.hooks ) {
|
||||
if ( Hooks.call(`${SYSTEM.id}.preRoll${hook.capitalize()}`, config, message) === false ) return null;
|
||||
for (const hook of config.hooks) {
|
||||
if (Hooks.call(`${SYSTEM.id}.preRoll${hook.capitalize()}`, config, message) === false) return null;
|
||||
}
|
||||
|
||||
this.applyKeybindings(config);
|
||||
|
||||
if(config.dialog.configure !== false) {
|
||||
|
||||
// let roll;
|
||||
// if(config.dialog?.configure === false) {
|
||||
// roll = new this('', config.actor, config);
|
||||
// } else {
|
||||
if (config.dialog.configure !== false) {
|
||||
// Open Roll Dialog
|
||||
const DialogClass = config.dialog?.class ?? this.DefaultDialog;
|
||||
config = await DialogClass.configure(config, message);
|
||||
if(!config) return;
|
||||
if (!config) return;
|
||||
}
|
||||
let roll = new this(config.formula, config.data, config);
|
||||
|
||||
for ( const hook of config.hooks ) {
|
||||
if ( Hooks.call(`${SYSTEM.id}.post${hook.capitalize()}RollConfiguration`, roll, config, message) === false ) return [];
|
||||
for (const hook of config.hooks) {
|
||||
if (Hooks.call(`${SYSTEM.id}.post${hook.capitalize()}RollConfiguration`, roll, config, message) === false)
|
||||
return [];
|
||||
}
|
||||
|
||||
return roll;
|
||||
}
|
||||
|
||||
static async buildEvaluate(roll, config={}, message={}) {
|
||||
if(config.evaluate !== false) await roll.evaluate();
|
||||
|
||||
static async buildEvaluate(roll, config = {}, message = {}) {
|
||||
if (config.evaluate !== false) await roll.evaluate();
|
||||
this.postEvaluate(roll, config);
|
||||
}
|
||||
|
||||
static async buildPost(roll, config, message) {
|
||||
for ( const hook of config.hooks ) {
|
||||
if ( Hooks.call(`${SYSTEM.id}.postRoll${hook.capitalize()}`, config, message) === false ) return null;
|
||||
}
|
||||
|
||||
// Create Chat Message
|
||||
if(message.data) {
|
||||
|
||||
static async buildPost(roll, config, message) {
|
||||
for (const hook of config.hooks) {
|
||||
if (Hooks.call(`${SYSTEM.id}.postRoll${hook.capitalize()}`, config, message) === false) return null;
|
||||
}
|
||||
|
||||
// Create Chat Message
|
||||
if (message.data) {
|
||||
} else {
|
||||
const messageData = {};
|
||||
await this.toMessage(roll, config);
|
||||
}
|
||||
}
|
||||
|
||||
static async postEvaluate(roll, config={}) {}
|
||||
static async postEvaluate(roll, config = {}) {}
|
||||
|
||||
static async toMessage(roll, config) {
|
||||
const cls = getDocumentClass("ChatMessage"),
|
||||
const cls = getDocumentClass('ChatMessage'),
|
||||
msg = {
|
||||
type: this.messageType,
|
||||
user: game.user.id,
|
||||
|
|
@ -89,13 +93,13 @@ export class DHRoll extends Roll {
|
|||
// D20Die
|
||||
|
||||
export class DualityDie extends foundry.dice.terms.Die {
|
||||
constructor({ number=1, faces=12, ...args }={}) {
|
||||
constructor({ number = 1, faces = 12, ...args } = {}) {
|
||||
super({ number, faces, ...args });
|
||||
}
|
||||
}
|
||||
|
||||
export class D20Roll extends DHRoll {
|
||||
constructor(formula, data={}, options={}) {
|
||||
constructor(formula, data = {}, options = {}) {
|
||||
super(formula, data, options);
|
||||
this.createBaseDice();
|
||||
this.configureModifiers();
|
||||
|
|
@ -113,21 +117,21 @@ export class D20Roll extends DHRoll {
|
|||
|
||||
// static messageTemplate = 'systems/daggerheart/templates/chat/adversary-roll.hbs';
|
||||
|
||||
static messageTemplate = async (config) => {
|
||||
static messageTemplate = async config => {
|
||||
return 'systems/daggerheart/templates/chat/adversary-roll.hbs';
|
||||
}
|
||||
};
|
||||
|
||||
static CRITICAL_TRESHOLD = 20;
|
||||
|
||||
static DefaultDialog = D20RollDialog;
|
||||
|
||||
get d20() {
|
||||
if ( !(this.terms[0] instanceof foundry.dice.terms.Die) ) this.createBaseDice();
|
||||
if (!(this.terms[0] instanceof foundry.dice.terms.Die)) this.createBaseDice();
|
||||
return this.terms[0];
|
||||
}
|
||||
|
||||
set d20(faces) {
|
||||
if ( !(this.terms[0] instanceof foundry.dice.terms.Die) ) this.createBaseDice();
|
||||
if (!(this.terms[0] instanceof foundry.dice.terms.Die)) this.createBaseDice();
|
||||
this.terms[0].faces = faces;
|
||||
}
|
||||
|
||||
|
|
@ -136,7 +140,7 @@ export class D20Roll extends DHRoll {
|
|||
}
|
||||
|
||||
get isCritical() {
|
||||
if ( !this.d20._evaluated ) return;
|
||||
if (!this.d20._evaluated) return;
|
||||
return this.d20.total >= this.constructor.CRITICAL_TRESHOLD;
|
||||
}
|
||||
|
||||
|
|
@ -154,75 +158,78 @@ export class D20Roll extends DHRoll {
|
|||
advantage: config.event.altKey,
|
||||
disadvantage: config.event.ctrlKey
|
||||
};
|
||||
|
||||
|
||||
// Should the roll configuration dialog be displayed?
|
||||
config.dialog.configure ??= !Object.values(keys).some(k => k);
|
||||
|
||||
// Determine advantage mode
|
||||
const advantage = config.advantage || keys.advantage;
|
||||
const disadvantage = config.disadvantage || keys.disadvantage;
|
||||
if ( advantage && !disadvantage ) config.advantage = this.ADV_MODE.ADVANTAGE;
|
||||
else if ( !advantage && disadvantage ) config.advantage = this.ADV_MODE.DISADVANTAGE;
|
||||
if (advantage && !disadvantage) config.advantage = this.ADV_MODE.ADVANTAGE;
|
||||
else if (!advantage && disadvantage) config.advantage = this.ADV_MODE.DISADVANTAGE;
|
||||
else config.advantage = this.ADV_MODE.NORMAL;
|
||||
}
|
||||
|
||||
createBaseDice() {
|
||||
if ( this.terms[0] instanceof foundry.dice.terms.Die ) return;
|
||||
if (this.terms[0] instanceof foundry.dice.terms.Die) return;
|
||||
this.terms[0] = new foundry.dice.terms.Die({ faces: 20 });
|
||||
}
|
||||
|
||||
applyAdvantage() {
|
||||
this.d20.modifiers.findSplice(m => ["kh", "kl"].includes(m));
|
||||
if ( !this.hasAdvantage && !this.hasAdvantage ) this.number = 1;
|
||||
this.d20.modifiers.findSplice(m => ['kh', 'kl'].includes(m));
|
||||
if (!this.hasAdvantage && !this.hasAdvantage) this.number = 1;
|
||||
else {
|
||||
this.d20.number = 2;
|
||||
this.d20.modifiers.push(this.hasAdvantage ? "kh" : "kl");
|
||||
this.d20.modifiers.push(this.hasAdvantage ? 'kh' : 'kl');
|
||||
}
|
||||
}
|
||||
|
||||
// Trait bonus != Adversary
|
||||
configureModifiers() {
|
||||
|
||||
this.applyAdvantage();
|
||||
|
||||
this.applyBaseBonus();
|
||||
|
||||
this.options.experiences?.forEach(m => {
|
||||
if(this.options.data.experiences?.[m]) this.options.roll.modifiers.push(
|
||||
{
|
||||
if (this.options.data.experiences?.[m])
|
||||
this.options.roll.modifiers.push({
|
||||
label: this.options.data.experiences[m].description,
|
||||
value: this.options.data.experiences[m].total
|
||||
}
|
||||
);
|
||||
})
|
||||
});
|
||||
});
|
||||
this.options.roll.modifiers?.forEach(m => {
|
||||
this.terms.push(...this.formatModifier(m.value));
|
||||
})
|
||||
});
|
||||
|
||||
if(this.options.extraFormula) this.terms.push(new foundry.dice.terms.OperatorTerm({operator: '+'}), ...this.constructor.parse(this.options.extraFormula, this.getRollData()));
|
||||
if (this.options.extraFormula)
|
||||
this.terms.push(
|
||||
new foundry.dice.terms.OperatorTerm({ operator: '+' }),
|
||||
...this.constructor.parse(this.options.extraFormula, this.getRollData())
|
||||
);
|
||||
|
||||
// this.resetFormula();
|
||||
}
|
||||
|
||||
applyBaseBonus() {
|
||||
if(this.options.type === "attack") this.terms.push(...this.formatModifier(this.options.data.attack.roll.bonus));
|
||||
if (this.options.type === 'attack')
|
||||
this.terms.push(...this.formatModifier(this.options.data.attack.roll.bonus));
|
||||
}
|
||||
|
||||
static async postEvaluate(roll, config={}) {
|
||||
static async postEvaluate(roll, config = {}) {
|
||||
if (config.targets?.length) {
|
||||
config.targets.forEach(target => {
|
||||
const difficulty = config.roll.difficulty ?? target.difficulty ?? target.evasion
|
||||
const difficulty = config.roll.difficulty ?? target.difficulty ?? target.evasion;
|
||||
target.hit = roll.total >= difficulty;
|
||||
})
|
||||
} else if(config.roll.difficulty) roll.success = roll.total >= config.roll.difficulty;
|
||||
});
|
||||
} else if (config.roll.difficulty) roll.success = roll.total >= config.roll.difficulty;
|
||||
config.roll.total = roll.total;
|
||||
config.roll.formula = roll.formula;
|
||||
config.roll.advantage = {
|
||||
type: config.advantage,
|
||||
dice: roll.dAdvantage?.denomination,
|
||||
value: roll.dAdvantage?.total
|
||||
}
|
||||
config.roll.modifierTotal = config.roll.modifiers.reduce((a,c) => a + c.value, 0);
|
||||
};
|
||||
config.roll.modifierTotal = config.roll.modifiers.reduce((a, c) => a + c.value, 0);
|
||||
config.roll.dice = [];
|
||||
roll.dice.forEach(d => {
|
||||
config.roll.dice.push({
|
||||
|
|
@ -230,8 +237,8 @@ export class D20Roll extends DHRoll {
|
|||
total: d.total,
|
||||
formula: d.formula,
|
||||
results: d.results
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getRollData() {
|
||||
|
|
@ -240,51 +247,54 @@ export class D20Roll extends DHRoll {
|
|||
|
||||
formatModifier(modifier) {
|
||||
const numTerm = modifier < 0 ? '-' : '+';
|
||||
return [new foundry.dice.terms.OperatorTerm({operator: numTerm}), new foundry.dice.terms.NumericTerm({number: Math.abs(modifier)})];
|
||||
return [
|
||||
new foundry.dice.terms.OperatorTerm({ operator: numTerm }),
|
||||
new foundry.dice.terms.NumericTerm({ number: Math.abs(modifier) })
|
||||
];
|
||||
}
|
||||
|
||||
resetFormula() {
|
||||
return this._formula = this.constructor.getFormula(this.terms);
|
||||
return (this._formula = this.constructor.getFormula(this.terms));
|
||||
}
|
||||
}
|
||||
|
||||
export class DualityRoll extends D20Roll {
|
||||
constructor(formula, data={}, options={}) {
|
||||
constructor(formula, data = {}, options = {}) {
|
||||
super(formula, data, options);
|
||||
}
|
||||
|
||||
static messageType = 'dualityRoll';
|
||||
|
||||
// static messageTemplate = 'systems/daggerheart/templates/chat/duality-roll.hbs';
|
||||
|
||||
static messageTemplate = async (config) => {
|
||||
|
||||
static messageTemplate = async config => {
|
||||
return 'systems/daggerheart/templates/chat/duality-roll.hbs';
|
||||
}
|
||||
};
|
||||
|
||||
static DefaultDialog = D20RollDialog;
|
||||
|
||||
get dHope() {
|
||||
// if ( !(this.terms[0] instanceof foundry.dice.terms.Die) ) return;
|
||||
if ( !(this.dice[0] instanceof CONFIG.Dice.daggerheart.DualityDie) ) this.createBaseDice();
|
||||
if (!(this.dice[0] instanceof CONFIG.Dice.daggerheart.DualityDie)) this.createBaseDice();
|
||||
return this.dice[0];
|
||||
// return this.#hopeDice;
|
||||
}
|
||||
|
||||
set dHope(faces) {
|
||||
if ( !(this.dice[0] instanceof CONFIG.Dice.daggerheart.DualityDie) ) this.createBaseDice();
|
||||
if (!(this.dice[0] instanceof CONFIG.Dice.daggerheart.DualityDie)) this.createBaseDice();
|
||||
this.terms[0].faces = faces;
|
||||
// this.#hopeDice = `d${face}`;
|
||||
}
|
||||
|
||||
get dFear() {
|
||||
// if ( !(this.terms[1] instanceof foundry.dice.terms.Die) ) return;
|
||||
if ( !(this.dice[1] instanceof CONFIG.Dice.daggerheart.DualityDie) ) this.createBaseDice();
|
||||
if (!(this.dice[1] instanceof CONFIG.Dice.daggerheart.DualityDie)) this.createBaseDice();
|
||||
return this.dice[1];
|
||||
// return this.#fearDice;
|
||||
}
|
||||
|
||||
set dFear(faces) {
|
||||
if ( !(this.dice[1] instanceof CONFIG.Dice.daggerheart.DualityDie) ) this.createBaseDice();
|
||||
if (!(this.dice[1] instanceof CONFIG.Dice.daggerheart.DualityDie)) this.createBaseDice();
|
||||
this.dice[1].faces = faces;
|
||||
// this.#fearDice = `d${face}`;
|
||||
}
|
||||
|
|
@ -294,17 +304,17 @@ export class DualityRoll extends D20Roll {
|
|||
}
|
||||
|
||||
get isCritical() {
|
||||
if ( !this.dHope._evaluated || !this.dFear._evaluated ) return;
|
||||
if (!this.dHope._evaluated || !this.dFear._evaluated) return;
|
||||
return this.dHope.total === this.dFear.total;
|
||||
}
|
||||
|
||||
get withHope() {
|
||||
if(!this._evaluated) return;
|
||||
if (!this._evaluated) return;
|
||||
return this.dHope.total > this.dFear.total;
|
||||
}
|
||||
|
||||
get withFear() {
|
||||
if(!this._evaluated) return;
|
||||
if (!this._evaluated) return;
|
||||
return this.dHope.total < this.dFear.total;
|
||||
}
|
||||
|
||||
|
|
@ -312,94 +322,99 @@ export class DualityRoll extends D20Roll {
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
get totalLabel() {
|
||||
const label =
|
||||
this.withHope
|
||||
? 'DAGGERHEART.General.Hope'
|
||||
: this.withFear
|
||||
? 'DAGGERHEART.General.Fear'
|
||||
: 'DAGGERHEART.General.CriticalSuccess';
|
||||
const label = this.withHope
|
||||
? 'DAGGERHEART.General.Hope'
|
||||
: this.withFear
|
||||
? 'DAGGERHEART.General.Fear'
|
||||
: 'DAGGERHEART.General.CriticalSuccess';
|
||||
|
||||
return game.i18n.localize(label);
|
||||
}
|
||||
|
||||
createBaseDice() {
|
||||
if ( this.dice[0] instanceof CONFIG.Dice.daggerheart.DualityDie && this.dice[1] instanceof CONFIG.Dice.daggerheart.DualityDie ) return;
|
||||
if ( !(this.dice[0] instanceof CONFIG.Dice.daggerheart.DualityDie) ) this.terms[0] = new CONFIG.Dice.daggerheart.DualityDie();
|
||||
this.terms[1] = new foundry.dice.terms.OperatorTerm({operator:'+'});
|
||||
if ( !(this.dice[2] instanceof CONFIG.Dice.daggerheart.DualityDie) ) this.terms[2] = new CONFIG.Dice.daggerheart.DualityDie();
|
||||
if (
|
||||
this.dice[0] instanceof CONFIG.Dice.daggerheart.DualityDie &&
|
||||
this.dice[1] instanceof CONFIG.Dice.daggerheart.DualityDie
|
||||
)
|
||||
return;
|
||||
if (!(this.dice[0] instanceof CONFIG.Dice.daggerheart.DualityDie))
|
||||
this.terms[0] = new CONFIG.Dice.daggerheart.DualityDie();
|
||||
this.terms[1] = new foundry.dice.terms.OperatorTerm({ operator: '+' });
|
||||
if (!(this.dice[2] instanceof CONFIG.Dice.daggerheart.DualityDie))
|
||||
this.terms[2] = new CONFIG.Dice.daggerheart.DualityDie();
|
||||
}
|
||||
|
||||
applyAdvantage() {
|
||||
const dieFaces = 6,
|
||||
bardRallyFaces = this.hasBarRally,
|
||||
advDie = new foundry.dice.terms.Die({faces: dieFaces});
|
||||
if(this.hasAdvantage || this.hasDisadvantage || bardRallyFaces) this.terms.push(new foundry.dice.terms.OperatorTerm({operator:'+'}));
|
||||
if(bardRallyFaces) {
|
||||
const rallyDie = new foundry.dice.terms.Die({faces: bardRallyFaces});
|
||||
if(this.hasAdvantage) {
|
||||
this.terms.push(new foundry.dice.terms.PoolTerm({
|
||||
terms: [advDie.formula, rallyDie.formula],
|
||||
modifiers: ["kh"]
|
||||
}))
|
||||
} else if(this.hasDisadvantage){
|
||||
this.terms.push(advDie, new foundry.dice.terms.OperatorTerm({operator:'+'}), rallyDie);
|
||||
advDie = new foundry.dice.terms.Die({ faces: dieFaces });
|
||||
if (this.hasAdvantage || this.hasDisadvantage || bardRallyFaces)
|
||||
this.terms.push(new foundry.dice.terms.OperatorTerm({ operator: '+' }));
|
||||
if (bardRallyFaces) {
|
||||
const rallyDie = new foundry.dice.terms.Die({ faces: bardRallyFaces });
|
||||
if (this.hasAdvantage) {
|
||||
this.terms.push(
|
||||
new foundry.dice.terms.PoolTerm({
|
||||
terms: [advDie.formula, rallyDie.formula],
|
||||
modifiers: ['kh']
|
||||
})
|
||||
);
|
||||
} else if (this.hasDisadvantage) {
|
||||
this.terms.push(advDie, new foundry.dice.terms.OperatorTerm({ operator: '+' }), rallyDie);
|
||||
}
|
||||
} else if(this.hasAdvantage || this.hasDisadvantage) this.terms.push(advDie);
|
||||
} else if (this.hasAdvantage || this.hasDisadvantage) this.terms.push(advDie);
|
||||
}
|
||||
|
||||
applyBaseBonus() {
|
||||
if(!this.options.roll.modifiers) this.options.roll.modifiers = [];
|
||||
if(this.options.roll?.trait) this.options.roll.modifiers.push(
|
||||
{
|
||||
if (!this.options.roll.modifiers) this.options.roll.modifiers = [];
|
||||
if (this.options.roll?.trait)
|
||||
this.options.roll.modifiers.push({
|
||||
label: `DAGGERHEART.Abilities.${this.options.roll.trait}.name`,
|
||||
value: this.options.data.traits[this.options.roll.trait].total
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
static async postEvaluate(roll, config={}) {
|
||||
static async postEvaluate(roll, config = {}) {
|
||||
super.postEvaluate(roll, config);
|
||||
config.roll.hope = {
|
||||
dice: roll.dHope.denomination,
|
||||
value: roll.dHope.total
|
||||
}
|
||||
};
|
||||
config.roll.fear = {
|
||||
dice: roll.dFear.denomination,
|
||||
value: roll.dFear.total
|
||||
}
|
||||
};
|
||||
config.roll.result = {
|
||||
duality: roll.withHope ? 1 : roll.withFear ? -1 : 0,
|
||||
total: roll.dHope.total + roll.dFear.total,
|
||||
label: roll.totalLabel
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class DamageRoll extends DHRoll {
|
||||
constructor(formula, data={}, options={}) {
|
||||
super(formula, data, options)
|
||||
constructor(formula, data = {}, options = {}) {
|
||||
super(formula, data, options);
|
||||
}
|
||||
|
||||
static messageType = 'damageRoll';
|
||||
|
||||
// static messageTemplate = 'systems/daggerheart/templates/chat/damage-roll.hbs';
|
||||
static messageTemplate = async (config) => {
|
||||
static messageTemplate = async config => {
|
||||
return await foundry.applications.handlebars.renderTemplate(
|
||||
config.messageTemplate ?? 'systems/daggerheart/templates/chat/damage-roll.hbs',
|
||||
config
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
static DefaultDialog = DamageDialog;
|
||||
|
||||
static async postEvaluate(roll, config={}) {
|
||||
|
||||
static async postEvaluate(roll, config = {}) {
|
||||
config.roll = {
|
||||
result: roll.total,
|
||||
dice: roll.dice
|
||||
}
|
||||
if(roll.healing) config.roll.type = roll.healing.type
|
||||
};
|
||||
if (roll.healing) config.roll.type = roll.healing.type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
context.tabs = super._getTabs(this.constructor.TABS);
|
||||
context.systemFields.attack.fields = this.document.system.attack.schema.fields;
|
||||
context.isNPC = true;
|
||||
console.log(context)
|
||||
console.log(context);
|
||||
return context;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -372,7 +372,7 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
trait: button.dataset.attribute
|
||||
/* label: abilityLabel,
|
||||
modifier: button.dataset.value */
|
||||
},
|
||||
}
|
||||
/* chatMessage: {
|
||||
template: 'systems/daggerheart/templates/chat/duality-roll.hbs'
|
||||
} */
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ export class DHBaseAction extends foundry.abstract.DataModel {
|
|||
range: new fields.StringField({
|
||||
choices: SYSTEM.GENERAL.range,
|
||||
required: false,
|
||||
blank: true,
|
||||
blank: true
|
||||
// initial: null
|
||||
}),
|
||||
...this.defineExtraSchema()
|
||||
|
|
@ -111,7 +111,8 @@ export class DHBaseAction extends foundry.abstract.DataModel {
|
|||
type: new fields.StringField({
|
||||
choices: SYSTEM.ACTIONS.targetTypes,
|
||||
initial: SYSTEM.ACTIONS.targetTypes.any.id,
|
||||
nullable: true, initial: null
|
||||
nullable: true,
|
||||
initial: null
|
||||
}),
|
||||
amount: new fields.NumberField({ nullable: true, initial: null, integer: true, min: 0 })
|
||||
}),
|
||||
|
|
@ -132,8 +133,8 @@ export class DHBaseAction extends foundry.abstract.DataModel {
|
|||
})
|
||||
},
|
||||
extraSchemas = {};
|
||||
|
||||
this.extraSchemas.forEach(s => extraSchemas[s] = extraFields[s]);
|
||||
|
||||
this.extraSchemas.forEach(s => (extraSchemas[s] = extraFields[s]));
|
||||
return extraSchemas;
|
||||
}
|
||||
|
||||
|
|
@ -172,8 +173,8 @@ export class DHBaseAction extends foundry.abstract.DataModel {
|
|||
trait: parent.system.trait
|
||||
};
|
||||
}
|
||||
if(parent?.type === 'weapon' && !!this.schema.fields.damage) {
|
||||
updateSource['damage'] = {includeBase: true};
|
||||
if (parent?.type === 'weapon' && !!this.schema.fields.damage) {
|
||||
updateSource['damage'] = { includeBase: true };
|
||||
}
|
||||
if (parent?.system?.range) {
|
||||
updateSource['range'] = parent?.system?.range;
|
||||
|
|
@ -187,9 +188,14 @@ export class DHBaseAction extends foundry.abstract.DataModel {
|
|||
...actorData.toObject(),
|
||||
prof: actorData.proficiency?.value ?? 1,
|
||||
cast: actorData.spellcast?.value ?? 1,
|
||||
scale: this.cost.length ? this.cost.reduce((a,c) => {a[c.type] = c.value; return a},{}) : 1,
|
||||
scale: this.cost.length
|
||||
? this.cost.reduce((a, c) => {
|
||||
a[c.type] = c.value;
|
||||
return a;
|
||||
}, {})
|
||||
: 1,
|
||||
roll: {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async use(event, ...args) {
|
||||
|
|
@ -208,26 +214,27 @@ export class DHBaseAction extends foundry.abstract.DataModel {
|
|||
};
|
||||
|
||||
// this.proceedChatDisplay(config);
|
||||
|
||||
|
||||
// Filter selected targets based on Target parameters
|
||||
config.targets = await this.getTarget(config);
|
||||
if(!config.targets) return ui.notifications.warn("Too many targets selected for that actions.");
|
||||
|
||||
if (!config.targets) return ui.notifications.warn('Too many targets selected for that actions.');
|
||||
|
||||
// Filter selected targets based on Range parameters
|
||||
config.range = await this.checkRange(config);
|
||||
if(!config.range.hasRange) return ui.notifications.warn("No Target within range.");
|
||||
if (!config.range.hasRange) return ui.notifications.warn('No Target within range.');
|
||||
|
||||
// Display Uses/Costs Dialog & Check if Actor get enough resources
|
||||
config = {
|
||||
...config,
|
||||
...await this.getCost(config)
|
||||
}
|
||||
if(!this.hasRoll() && (!config.costs.hasCost || !this.hasUses(config.uses))) return ui.notifications.warn("You don't have the resources to use that action.");
|
||||
...(await this.getCost(config))
|
||||
};
|
||||
if (!this.hasRoll() && (!config.costs.hasCost || !this.hasUses(config.uses)))
|
||||
return ui.notifications.warn("You don't have the resources to use that action.");
|
||||
|
||||
// Proceed with Roll
|
||||
config = await this.proceedRoll(config);
|
||||
if(this.roll && !config.roll.result) return;
|
||||
|
||||
if (this.roll && !config.roll.result) return;
|
||||
|
||||
// Update Actor resources based on Action Cost configuration
|
||||
this.spendCost(config.costs.values);
|
||||
this.spendUses(config.uses);
|
||||
|
|
@ -254,7 +261,7 @@ export class DHBaseAction extends foundry.abstract.DataModel {
|
|||
type: this.actionType,
|
||||
difficulty: this.roll?.difficulty
|
||||
}
|
||||
}
|
||||
};
|
||||
// config = await this.actor.diceRoll(config, this);
|
||||
return this.actor.diceRoll(config, this);
|
||||
}
|
||||
|
|
@ -262,20 +269,20 @@ export class DHBaseAction extends foundry.abstract.DataModel {
|
|||
|
||||
/* COST */
|
||||
async getCost(config) {
|
||||
let costs = this.cost?.length ? foundry.utils.deepClone(this.cost) : {values: [], hasCost: true};
|
||||
let costs = this.cost?.length ? foundry.utils.deepClone(this.cost) : { values: [], hasCost: true };
|
||||
let uses = this.getUses();
|
||||
if (!config.event.shiftKey && !this.hasRoll()) {
|
||||
const dialogClosed = new Promise((resolve, _) => {
|
||||
new CostSelectionDialog(costs, uses, this, resolve).render(true);
|
||||
});
|
||||
({costs, uses} = await dialogClosed);
|
||||
({ costs, uses } = await dialogClosed);
|
||||
}
|
||||
return {costs, uses};
|
||||
return { costs, uses };
|
||||
}
|
||||
|
||||
getRealCosts(costs) {
|
||||
const realCosts = costs?.length ? costs.filter(c => c.enabled) : [];
|
||||
return {values: realCosts, hasCost: this.hasCost(realCosts)}
|
||||
return { values: realCosts, hasCost: this.hasCost(realCosts) };
|
||||
}
|
||||
|
||||
calcCosts(costs) {
|
||||
|
|
@ -284,32 +291,32 @@ export class DHBaseAction extends foundry.abstract.DataModel {
|
|||
c.step = c.step ?? 1;
|
||||
c.total = c.value * c.scale * c.step;
|
||||
c.enabled = c.hasOwnProperty('enabled') ? c.enabled : true;
|
||||
return c
|
||||
})
|
||||
return c;
|
||||
});
|
||||
}
|
||||
|
||||
hasCost(costs) {
|
||||
return costs.reduce((a, c) => a && this.actor.system.resources[c.type]?.value >= (c.total ?? c.value), true)
|
||||
return costs.reduce((a, c) => a && this.actor.system.resources[c.type]?.value >= (c.total ?? c.value), true);
|
||||
}
|
||||
|
||||
async spendCost(config) {
|
||||
if(!config.costs?.values?.length) return;
|
||||
if (!config.costs?.values?.length) return;
|
||||
return await this.actor.modifyResource(config.costs.values);
|
||||
}
|
||||
/* COST */
|
||||
|
||||
/* USES */
|
||||
async spendUses(config) {
|
||||
if(!this.uses.max || config.enabled === false) return;
|
||||
if (!this.uses.max || config.enabled === false) return;
|
||||
const newActions = foundry.utils.getProperty(this.item.system, this.systemPath).map(x => x.toObject());
|
||||
newActions[this.index].uses.value++;
|
||||
await this.item.update({ [`system.${this.systemPath}`]: newActions });
|
||||
}
|
||||
|
||||
getUses() {
|
||||
if(!this.uses) return {hasUse: true}
|
||||
if (!this.uses) return { hasUse: true };
|
||||
const uses = foundry.utils.deepClone(this.uses);
|
||||
if(!uses.value) uses.value = 0;
|
||||
if (!uses.value) uses.value = 0;
|
||||
return uses;
|
||||
}
|
||||
|
||||
|
|
@ -325,23 +332,28 @@ export class DHBaseAction extends foundry.abstract.DataModel {
|
|||
}
|
||||
/* USES */
|
||||
|
||||
|
||||
/* TARGET */
|
||||
async getTarget(config) {
|
||||
if(this.target?.type === SYSTEM.ACTIONS.targetTypes.self.id) return this.formatTarget(this.actor.token ?? this.actor.prototypeToken);
|
||||
if (this.target?.type === SYSTEM.ACTIONS.targetTypes.self.id)
|
||||
return this.formatTarget(this.actor.token ?? this.actor.prototypeToken);
|
||||
let targets = Array.from(game.user.targets);
|
||||
// foundry.CONST.TOKEN_DISPOSITIONS.FRIENDLY
|
||||
if(this.target?.type && this.target.type !== SYSTEM.ACTIONS.targetTypes.any.id) {
|
||||
if (this.target?.type && this.target.type !== SYSTEM.ACTIONS.targetTypes.any.id) {
|
||||
targets = targets.filter(t => this.isTargetFriendly(t));
|
||||
if(this.target.amount && targets.length > this.target.amount) return false;
|
||||
if (this.target.amount && targets.length > this.target.amount) return false;
|
||||
}
|
||||
return targets.map(t => this.formatTarget(t));
|
||||
}
|
||||
|
||||
isTargetFriendly(target) {
|
||||
const actorDisposition = this.actor.token ? this.actor.token.disposition : this.actor.prototypeToken.disposition,
|
||||
const actorDisposition = this.actor.token
|
||||
? this.actor.token.disposition
|
||||
: this.actor.prototypeToken.disposition,
|
||||
targetDisposition = target.document.disposition;
|
||||
return (this.target.type === SYSTEM.ACTIONS.targetTypes.friendly.id && actorDisposition === targetDisposition) || (this.target.type === SYSTEM.ACTIONS.targetTypes.hostile.id && (actorDisposition + targetDisposition === 0))
|
||||
return (
|
||||
(this.target.type === SYSTEM.ACTIONS.targetTypes.friendly.id && actorDisposition === targetDisposition) ||
|
||||
(this.target.type === SYSTEM.ACTIONS.targetTypes.hostile.id && actorDisposition + targetDisposition === 0)
|
||||
);
|
||||
}
|
||||
|
||||
formatTarget(actor) {
|
||||
|
|
@ -351,56 +363,57 @@ export class DHBaseAction extends foundry.abstract.DataModel {
|
|||
img: actor.actor.img,
|
||||
difficulty: actor.actor.system.difficulty,
|
||||
evasion: actor.actor.system.evasion?.total
|
||||
}
|
||||
};
|
||||
}
|
||||
/* TARGET */
|
||||
|
||||
|
||||
/* RANGE */
|
||||
async checkRange(config) {
|
||||
if(!this.range || !this.actor) return true;
|
||||
return {values: [], hasRange: true};
|
||||
if (!this.range || !this.actor) return true;
|
||||
return { values: [], hasRange: true };
|
||||
}
|
||||
/* RANGE */
|
||||
|
||||
/* EFFECTS */
|
||||
async applyEffects(event, data, force=false) {
|
||||
if(!this.effects?.length || !data.system.targets.length) return;
|
||||
data.system.targets.forEach(async (token) => {
|
||||
if(!token.hit && !force) return;
|
||||
this.effects.forEach(async (e) => {
|
||||
async applyEffects(event, data, force = false) {
|
||||
if (!this.effects?.length || !data.system.targets.length) return;
|
||||
data.system.targets.forEach(async token => {
|
||||
if (!token.hit && !force) return;
|
||||
this.effects.forEach(async e => {
|
||||
const actor = canvas.tokens.get(token.id)?.actor,
|
||||
effect = this.item.effects.get(e._id);
|
||||
if(!actor || !effect) return;
|
||||
if (!actor || !effect) return;
|
||||
await this.applyEffect(effect, actor);
|
||||
})
|
||||
})
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async applyEffect(effect, actor) {
|
||||
// Enable an existing effect on the target if it originated from this effect
|
||||
const existingEffect = actor.effects.find(e => e.origin === origin.uuid);
|
||||
if ( existingEffect ) {
|
||||
return existingEffect.update(foundry.utils.mergeObject({
|
||||
// Enable an existing effect on the target if it originated from this effect
|
||||
const existingEffect = actor.effects.find(e => e.origin === origin.uuid);
|
||||
if (existingEffect) {
|
||||
return existingEffect.update(
|
||||
foundry.utils.mergeObject({
|
||||
...effect.constructor.getInitialDuration(),
|
||||
disabled: false
|
||||
}));
|
||||
}
|
||||
|
||||
// Otherwise, create a new effect on the target
|
||||
const effectData = foundry.utils.mergeObject({
|
||||
...effect.toObject(),
|
||||
disabled: false,
|
||||
transfer: false,
|
||||
origin: origin.uuid
|
||||
});
|
||||
await ActiveEffect.implementation.create(effectData, { parent: actor });
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Otherwise, create a new effect on the target
|
||||
const effectData = foundry.utils.mergeObject({
|
||||
...effect.toObject(),
|
||||
disabled: false,
|
||||
transfer: false,
|
||||
origin: origin.uuid
|
||||
});
|
||||
await ActiveEffect.implementation.create(effectData, { parent: actor });
|
||||
}
|
||||
/* EFFECTS */
|
||||
|
||||
/* CHAT */
|
||||
async proceedChatDisplay(config) {
|
||||
if(!this.chatDisplay) return;
|
||||
if (!this.chatDisplay) return;
|
||||
}
|
||||
/* CHAT */
|
||||
}
|
||||
|
|
@ -412,14 +425,14 @@ export class DHDamageAction extends DHBaseAction {
|
|||
|
||||
async use(event, ...args) {
|
||||
const config = await super.use(event, args);
|
||||
if(!config || ['error', 'warning'].includes(config.type)) return;
|
||||
if(!this.directDamage) return;
|
||||
if (!config || ['error', 'warning'].includes(config.type)) return;
|
||||
if (!this.directDamage) return;
|
||||
return await this.rollDamage(event, config);
|
||||
}
|
||||
|
||||
async rollDamage(event, data) {
|
||||
let formula = this.damage.parts.map(p => p.getFormula(this.actor)).join(' + ');
|
||||
|
||||
|
||||
if (!formula || formula == '') return;
|
||||
let roll = { formula: formula, total: formula },
|
||||
bonusDamage = [];
|
||||
|
|
@ -427,10 +440,15 @@ export class DHDamageAction extends DHBaseAction {
|
|||
const config = {
|
||||
title: game.i18n.format('DAGGERHEART.Chat.DamageRoll.Title', { damage: this.name }),
|
||||
formula,
|
||||
targets: (data.system?.targets ?? data.targets).map(x => ({ id: x.id, name: x.name, img: x.img, hit: true }))
|
||||
}
|
||||
|
||||
roll = CONFIG.Dice.daggerheart.DamageRoll.build(config)
|
||||
targets: (data.system?.targets ?? data.targets).map(x => ({
|
||||
id: x.id,
|
||||
name: x.name,
|
||||
img: x.img,
|
||||
hit: true
|
||||
}))
|
||||
};
|
||||
|
||||
roll = CONFIG.Dice.daggerheart.DamageRoll.build(config);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -475,24 +493,31 @@ export class DHHealingAction extends DHBaseAction {
|
|||
|
||||
async use(event, ...args) {
|
||||
const config = await super.use(event, args);
|
||||
if(!config || ['error', 'warning'].includes(config.type)) return;
|
||||
if(this.hasRoll()) return;
|
||||
if (!config || ['error', 'warning'].includes(config.type)) return;
|
||||
if (this.hasRoll()) return;
|
||||
return await this.rollHealing(event, config);
|
||||
}
|
||||
|
||||
async rollHealing(event, data) {
|
||||
let formula = this.healing.value.getFormula(this.actor);
|
||||
|
||||
|
||||
if (!formula || formula == '') return;
|
||||
let roll = { formula: formula, total: formula },
|
||||
bonusDamage = [];
|
||||
|
||||
const config = {
|
||||
title: game.i18n.format('DAGGERHEART.Chat.HealingRoll.Title', { healing: game.i18n.localize(SYSTEM.GENERAL.healingTypes[this.healing.type].label) }),
|
||||
title: game.i18n.format('DAGGERHEART.Chat.HealingRoll.Title', {
|
||||
healing: game.i18n.localize(SYSTEM.GENERAL.healingTypes[this.healing.type].label)
|
||||
}),
|
||||
formula,
|
||||
targets: (data.system?.targets ?? data.targets).map(x => ({ id: x.id, name: x.name, img: x.img, hit: true })),
|
||||
targets: (data.system?.targets ?? data.targets).map(x => ({
|
||||
id: x.id,
|
||||
name: x.name,
|
||||
img: x.img,
|
||||
hit: true
|
||||
})),
|
||||
messageTemplate: 'systems/daggerheart/templates/chat/healing-roll.hbs'
|
||||
}
|
||||
};
|
||||
|
||||
roll = CONFIG.Dice.daggerheart.DamageRoll.build(config);
|
||||
}
|
||||
|
|
@ -511,13 +536,12 @@ export class DHSummonAction extends DHBaseAction {
|
|||
}
|
||||
|
||||
async use(event, ...args) {
|
||||
if ( !this.canSummon || !canvas.scene ) return;
|
||||
if (!this.canSummon || !canvas.scene) return;
|
||||
const config = await super.use(event, args);
|
||||
|
||||
}
|
||||
|
||||
get canSummon() {
|
||||
return game.user.can("TOKEN_CREATE");
|
||||
return game.user.can('TOKEN_CREATE');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -526,7 +550,7 @@ export class DHEffectAction extends DHBaseAction {
|
|||
|
||||
async use(event, ...args) {
|
||||
const config = await super.use(event, args);
|
||||
if(['error', 'warning'].includes(config.type)) return;
|
||||
if (['error', 'warning'].includes(config.type)) return;
|
||||
return await this.chatApplyEffects(event, config);
|
||||
}
|
||||
|
||||
|
|
@ -570,7 +594,7 @@ export class DHMacroAction extends DHBaseAction {
|
|||
|
||||
async use(event, ...args) {
|
||||
const config = await super.use(event, args);
|
||||
if(['error', 'warning'].includes(config.type)) return;
|
||||
if (['error', 'warning'].includes(config.type)) return;
|
||||
const fixUUID = !this.documentUUID.includes('Macro.') ? `Macro.${this.documentUUID}` : this.documentUUID,
|
||||
macro = await fromUuid(fixUUID);
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ export class DHActionDiceData extends foundry.abstract.DataModel {
|
|||
initial: 'proficiency',
|
||||
label: 'Multiplier'
|
||||
}),
|
||||
flatMultiplier : new fields.NumberField({ nullable: true, initial: 1, label: 'Flat Multiplier' }),
|
||||
flatMultiplier: new fields.NumberField({ nullable: true, initial: 1, label: 'Flat Multiplier' }),
|
||||
dice: new fields.StringField({ choices: SYSTEM.GENERAL.diceTypes, initial: 'd6', label: 'Formula' }),
|
||||
bonus: new fields.NumberField({ nullable: true, initial: null, label: 'Bonus' }),
|
||||
custom: new fields.SchemaField({
|
||||
|
|
|
|||
|
|
@ -90,9 +90,11 @@ export default class DhpAdversary extends BaseDataActor {
|
|||
type: 'weapon'
|
||||
},
|
||||
damage: {
|
||||
parts: [{
|
||||
multiplier: 'flat'
|
||||
}]
|
||||
parts: [
|
||||
{
|
||||
multiplier: 'flat'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -17,6 +17,12 @@ const resourceField = max =>
|
|||
max: new foundry.data.fields.NumberField({ initial: max, integer: true })
|
||||
});
|
||||
|
||||
const stressDamageReductionRule = () =>
|
||||
new foundry.data.fields.SchemaField({
|
||||
enabled: new foundry.data.fields.BooleanField({ required: true, initial: false }),
|
||||
cost: new foundry.data.fields.NumberField({ integer: true })
|
||||
});
|
||||
|
||||
export default class DhCharacter extends BaseDataActor {
|
||||
static get metadata() {
|
||||
return foundry.utils.mergeObject(super.metadata, {
|
||||
|
|
@ -90,6 +96,18 @@ export default class DhCharacter extends BaseDataActor {
|
|||
attack: new fields.NumberField({ integer: true, initial: 0 }),
|
||||
spellcast: new fields.NumberField({ integer: true, initial: 0 }),
|
||||
armorScore: new fields.NumberField({ integer: true, initial: 0 })
|
||||
}),
|
||||
rules: new fields.SchemaField({
|
||||
maxArmorMarked: new fields.SchemaField({
|
||||
value: new fields.NumberField({ required: true, integer: true, initial: 1 }),
|
||||
bonus: new fields.NumberField({ required: true, integer: true, initial: 0 }),
|
||||
stressExtra: new fields.NumberField({ required: true, integer: true, initial: 0 })
|
||||
}),
|
||||
stressDamageReduction: new fields.SchemaField({
|
||||
severe: stressDamageReductionRule(),
|
||||
major: stressDamageReductionRule(),
|
||||
minor: stressDamageReductionRule()
|
||||
})
|
||||
})
|
||||
};
|
||||
}
|
||||
|
|
@ -239,6 +257,9 @@ export default class DhCharacter extends BaseDataActor {
|
|||
experience.total = experience.value + experience.bonus;
|
||||
}
|
||||
|
||||
this.rules.maxArmorMarked.total = this.rules.maxArmorMarked.value + this.rules.maxArmorMarked.bonus;
|
||||
|
||||
this.armorScore = this.armor ? this.armor.system.baseScore + (this.bonuses.armorScore ?? 0) : 0;
|
||||
this.resources.hitPoints.maxTotal = this.resources.hitPoints.max + this.resources.hitPoints.bonus;
|
||||
this.resources.stress.maxTotal = this.resources.stress.max + this.resources.stress.bonus;
|
||||
this.evasion.total = (this.class?.evasion ?? 0) + this.evasion.bonus;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import DhpActor from "../../documents/actor.mjs";
|
||||
import ActionField from "../fields/actionField.mjs";
|
||||
import DhpActor from '../../documents/actor.mjs';
|
||||
import ActionField from '../fields/actionField.mjs';
|
||||
|
||||
export default class DHAdversaryRoll extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ export default class DHArmor extends BaseDataItem {
|
|||
})
|
||||
),
|
||||
marks: new fields.SchemaField({
|
||||
max: new fields.NumberField({ initial: 6, integer: true }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
baseThresholds: new fields.SchemaField({
|
||||
|
|
|
|||
|
|
@ -1,15 +1,18 @@
|
|||
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
|
||||
|
||||
export default class D20RollDialog extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
constructor(config={}, options={}) {
|
||||
constructor(config = {}, options = {}) {
|
||||
super(options);
|
||||
|
||||
this.config = config;
|
||||
this.config.experiences = [];
|
||||
|
||||
if(config.source?.action) {
|
||||
|
||||
if (config.source?.action) {
|
||||
this.item = config.data.parent.items.get(config.source.item);
|
||||
this.action = config.data.attack?._id == config.source.action ? config.data.attack : this.item.system.actions.find(a => a._id === config.source.action);
|
||||
this.action =
|
||||
config.data.attack?._id == config.source.action
|
||||
? config.data.attack
|
||||
: this.item.system.actions.find(a => a._id === config.source.action);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -47,17 +50,20 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
|
||||
async _prepareContext(_options) {
|
||||
const context = await super._prepareContext(_options);
|
||||
context.experiences = Object.keys(this.config.data.experiences).map(id => ({ id, ...this.config.data.experiences[id] }));
|
||||
context.experiences = Object.keys(this.config.data.experiences).map(id => ({
|
||||
id,
|
||||
...this.config.data.experiences[id]
|
||||
}));
|
||||
context.selectedExperiences = this.config.experiences;
|
||||
context.advantage = this.config.advantage;
|
||||
/* context.diceOptions = this.diceOptions; */
|
||||
context.canRoll = true;
|
||||
if(this.config.costs?.length) {
|
||||
if (this.config.costs?.length) {
|
||||
const updatedCosts = this.action.calcCosts(this.config.costs);
|
||||
context.costs = updatedCosts
|
||||
context.costs = updatedCosts;
|
||||
context.canRoll = this.action.getRealCosts(updatedCosts)?.hasCost;
|
||||
}
|
||||
if(this.config.uses?.max) {
|
||||
if (this.config.uses?.max) {
|
||||
context.uses = this.action.calcUses(this.config.uses);
|
||||
context.canRoll = context.canRoll && this.action.hasUses(context.uses);
|
||||
}
|
||||
|
|
@ -66,8 +72,8 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
|
||||
static updateRollConfiguration(event, _, formData) {
|
||||
const { ...rest } = foundry.utils.expandObject(formData.object);
|
||||
if(this.config.costs) this.config.costs = foundry.utils.mergeObject(this.config.costs, rest.costs);
|
||||
if(this.config.uses) this.config.uses = foundry.utils.mergeObject(this.config.uses, rest.uses);
|
||||
if (this.config.costs) this.config.costs = foundry.utils.mergeObject(this.config.costs, rest.costs);
|
||||
if (this.config.uses) this.config.uses = foundry.utils.mergeObject(this.config.uses, rest.uses);
|
||||
this.render();
|
||||
}
|
||||
|
||||
|
|
@ -87,19 +93,19 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
}
|
||||
|
||||
static async submitRoll() {
|
||||
await this.close({ submitted: true });
|
||||
await this.close({ submitted: true });
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_onClose(options={}) {
|
||||
if ( !options.submitted ) this.config = false;
|
||||
_onClose(options = {}) {
|
||||
if (!options.submitted) this.config = false;
|
||||
}
|
||||
|
||||
static async configure(config={}) {
|
||||
static async configure(config = {}) {
|
||||
return new Promise(resolve => {
|
||||
const app = new this(config);
|
||||
app.addEventListener("close", () => resolve(app.config), { once: true });
|
||||
app.addEventListener('close', () => resolve(app.config), { once: true });
|
||||
app.render({ force: true });
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import RollSelectionDialog from '../applications/rollSelectionDialog.mjs';
|
|||
import { GMUpdateEvent, socketEvent } from '../helpers/socket.mjs';
|
||||
import { setDiceSoNiceForDualityRoll } from '../helpers/utils.mjs';
|
||||
import DHDualityRoll from '../data/chat-message/dualityRoll.mjs';
|
||||
import DamageReductionDialog from '../applications/damageReductionDialog.mjs';
|
||||
|
||||
export default class DhpActor extends Actor {
|
||||
async _preCreate(data, options, user) {
|
||||
|
|
@ -265,9 +266,9 @@ export default class DhpActor extends Actor {
|
|||
* @param {object} [config.costs]
|
||||
*/
|
||||
async diceRoll(config, action) {
|
||||
config.source = {...(config.source ?? {}), actor: this._id};
|
||||
config.data = this.getRollData()
|
||||
const roll = await CONFIG.Dice.daggerheart[this.type === 'character' ? 'DualityRoll' : 'D20Roll'].build(config)
|
||||
config.source = { ...(config.source ?? {}), actor: this._id };
|
||||
config.data = this.getRollData();
|
||||
const roll = await CONFIG.Dice.daggerheart[this.type === 'character' ? 'DualityRoll' : 'D20Roll'].build(config);
|
||||
return config;
|
||||
}
|
||||
|
||||
|
|
@ -361,66 +362,78 @@ export default class DhpActor extends Actor {
|
|||
async takeDamage(damage, type) {
|
||||
const hpDamage =
|
||||
damage >= this.system.damageThresholds.severe
|
||||
? -3
|
||||
? 3
|
||||
: damage >= this.system.damageThresholds.major
|
||||
? -2
|
||||
? 2
|
||||
: damage >= this.system.damageThresholds.minor
|
||||
? -1
|
||||
? 1
|
||||
: 0;
|
||||
await this.modifyResource([{value: hpDamage, type}]);
|
||||
/* const update = {
|
||||
'system.resources.hitPoints.value': Math.min(
|
||||
this.system.resources.hitPoints.value + hpDamage,
|
||||
this.system.resources.hitPoints.max
|
||||
)
|
||||
};
|
||||
|
||||
if (game.user.isGM) {
|
||||
await this.update(update);
|
||||
if (
|
||||
this.type === 'character' &&
|
||||
this.system.armor &&
|
||||
this.system.armor.system.marks.value < this.system.armorScore
|
||||
) {
|
||||
new Promise((resolve, reject) => {
|
||||
new DamageReductionDialog(resolve, reject, this, hpDamage).render(true);
|
||||
})
|
||||
.then(async ({ modifiedDamage, armorSpent, stressSpent }) => {
|
||||
const resources = [
|
||||
{ value: modifiedDamage, type: 'hitPoints' },
|
||||
...(armorSpent ? [{ value: armorSpent, type: 'armorStack' }] : []),
|
||||
...(stressSpent ? [{ value: stressSpent, type: 'stress' }] : [])
|
||||
];
|
||||
await this.modifyResource(resources);
|
||||
})
|
||||
.catch(() => {
|
||||
const cls = getDocumentClass('ChatMessage');
|
||||
const msg = new cls({
|
||||
user: game.user.id,
|
||||
content: game.i18n.format('DAGGERHEART.DamageReduction.Notifications.DamageIgnore', {
|
||||
character: this.name
|
||||
})
|
||||
});
|
||||
cls.create(msg.toObject());
|
||||
});
|
||||
} else {
|
||||
await game.socket.emit(`system.${SYSTEM.id}`, {
|
||||
action: socketEvent.GMUpdate,
|
||||
data: {
|
||||
action: GMUpdateEvent.UpdateDocument,
|
||||
uuid: this.uuid,
|
||||
update: update
|
||||
}
|
||||
});
|
||||
} */
|
||||
await this.modifyResource([{ value: hpDamage, type: 'hitPoints' }]);
|
||||
}
|
||||
}
|
||||
|
||||
async modifyResource(resources) {
|
||||
if(!resources.length) return;
|
||||
let updates = { actor: { target: this, resources: {} }, armor: { target: this.armor, resources: {} } };
|
||||
if (!resources.length) return;
|
||||
let updates = { actor: { target: this, resources: {} }, armor: { target: this.system.armor, resources: {} } };
|
||||
resources.forEach(r => {
|
||||
switch (type) {
|
||||
case 'armorStrack':
|
||||
// resource = 'system.stacks.value';
|
||||
// target = this.armor;
|
||||
// update = Math.min(this.marks.value + value, this.marks.max);
|
||||
updates.armor.resources['system.stacks.value'] = Math.min(this.marks.value + value, this.marks.max);
|
||||
switch (r.type) {
|
||||
case 'armorStack':
|
||||
updates.armor.resources['system.marks.value'] = Math.min(
|
||||
this.system.armor.system.marks.value + r.value,
|
||||
this.system.armorScore
|
||||
);
|
||||
break;
|
||||
default:
|
||||
// resource = `system.resources.${type}`;
|
||||
// target = this;
|
||||
// update = Math.min(this.resources[type].value + value, this.resources[type].max);
|
||||
updates.armor.resources[`system.resources.${type}`] = Math.min(this.resources[type].value + value, this.resources[type].max);
|
||||
updates.actor.resources[`system.resources.${r.type}.value`] = Math.min(
|
||||
this.system.resources[r.type].value + r.value,
|
||||
this.system.resources[r.type].max
|
||||
);
|
||||
break;
|
||||
}
|
||||
})
|
||||
Object.values(updates).forEach(async (u) => {
|
||||
if (game.user.isGM) {
|
||||
await u.target.update(u.resources);
|
||||
} else {
|
||||
await game.socket.emit(`system.${SYSTEM.id}`, {
|
||||
action: socketEvent.GMUpdate,
|
||||
data: {
|
||||
action: GMUpdateEvent.UpdateDocument,
|
||||
uuid: u.target.uuid,
|
||||
update: u.resources
|
||||
}
|
||||
});
|
||||
});
|
||||
Object.values(updates).forEach(async u => {
|
||||
if (Object.keys(u.resources).length > 0) {
|
||||
if (game.user.isGM) {
|
||||
await u.target.update(u.resources);
|
||||
} else {
|
||||
await game.socket.emit(`system.${SYSTEM.id}`, {
|
||||
action: socketEvent.GMUpdate,
|
||||
data: {
|
||||
action: GMUpdateEvent.UpdateDocument,
|
||||
uuid: u.target.uuid,
|
||||
update: u.resources
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -235,3 +235,29 @@ Roll.replaceFormulaData = function (formula, data, { missing, warn = false } = {
|
|||
formula = terms.reduce((a, c) => a.replaceAll(`@${c.term}`, data[c.term] ?? c.default), formula);
|
||||
return nativeReplaceFormulaData(formula, data, { missing, warn });
|
||||
};
|
||||
|
||||
export const getDamageLabel = damage => {
|
||||
switch (damage) {
|
||||
case 3:
|
||||
return game.i18n.localize('DAGGERHEART.General.Damage.Severe');
|
||||
case 2:
|
||||
return game.i18n.localize('DAGGERHEART.General.Damage.Major');
|
||||
case 1:
|
||||
return game.i18n.localize('DAGGERHEART.General.Damage.Minor');
|
||||
case 0:
|
||||
return game.i18n.localize('DAGGERHEART.General.Damage.None');
|
||||
}
|
||||
};
|
||||
|
||||
export const damageKeyToNumber = key => {
|
||||
switch (key) {
|
||||
case 'severe':
|
||||
return 3;
|
||||
case 'major':
|
||||
return 2;
|
||||
case 'minor':
|
||||
return 1;
|
||||
case 'none':
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -66,7 +66,10 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
|||
|
||||
getAction(actor, itemId, actionId) {
|
||||
const item = actor.items.get(itemId),
|
||||
action = actor.system.attack?._id === actionId ? actor.system.attack : item?.system?.actions?.find(a => a._id === actionId);
|
||||
action =
|
||||
actor.system.attack?._id === actionId
|
||||
? actor.system.attack
|
||||
: item?.system?.actions?.find(a => a._id === actionId);
|
||||
return action;
|
||||
}
|
||||
|
||||
|
|
@ -74,9 +77,9 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
|||
event.stopPropagation();
|
||||
const actor = this.getActor(message.system.source.actor);
|
||||
if (!actor || !game.user.isGM) return true;
|
||||
if(message.system.source.item && message.system.source.action) {
|
||||
if (message.system.source.item && message.system.source.action) {
|
||||
const action = this.getAction(actor, message.system.source.item, message.system.source.action);
|
||||
if(!action || !action?.rollDamage) return;
|
||||
if (!action || !action?.rollDamage) return;
|
||||
await action.rollDamage(event, message);
|
||||
}
|
||||
};
|
||||
|
|
@ -85,9 +88,9 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
|||
event.stopPropagation();
|
||||
const actor = this.getActor(message.system.source.actor);
|
||||
if (!actor || !game.user.isGM) return true;
|
||||
if(message.system.source.item && message.system.source.action) {
|
||||
if (message.system.source.item && message.system.source.action) {
|
||||
const action = this.getAction(actor, message.system.source.item, message.system.source.action);
|
||||
if(!action || !action?.rollHealing) return;
|
||||
if (!action || !action?.rollHealing) return;
|
||||
await action.rollHealing(event, message);
|
||||
}
|
||||
};
|
||||
|
|
@ -96,12 +99,12 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
|||
event.stopPropagation();
|
||||
const actor = this.getActor(message.system.source.actor);
|
||||
if (!actor || !game.user.isGM) return true;
|
||||
if(message.system.source.item && message.system.source.action) {
|
||||
if (message.system.source.item && message.system.source.action) {
|
||||
const action = this.getAction(actor, message.system.source.item, message.system.source.action);
|
||||
if(!action || !action?.applyEffects) return;
|
||||
if (!action || !action?.applyEffects) return;
|
||||
await action.applyEffects(event, message);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
hoverTarget = event => {
|
||||
event.stopPropagation();
|
||||
|
|
@ -148,7 +151,7 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
|||
ui.notifications.info(game.i18n.localize('DAGGERHEART.Notification.Info.NoTargetsSelected'));
|
||||
|
||||
for (var target of targets) {
|
||||
await target.actor.modifyResource([{value: healing, type: event.currentTarget.dataset.type}]);
|
||||
await target.actor.modifyResource([{ value: healing, type: event.currentTarget.dataset.type }]);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -3115,6 +3115,125 @@ div.daggerheart.views.multiclass {
|
|||
.daggerheart.views.ownership-selection .ownership-outer-container .ownership-container select {
|
||||
margin: 4px 0;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .window-content {
|
||||
padding: 8px 0;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .damage-reduction-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .damage-reduction-container .section-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .damage-reduction-container .padded {
|
||||
padding: 0 8px;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .damage-reduction-container .armor-title {
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .damage-reduction-container .resources-container {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .damage-reduction-container .resources-container .resource-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .damage-reduction-container .mark-selection {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .damage-reduction-container .mark-selection .mark-selection-inner {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .damage-reduction-container .mark-selection .mark-selection-inner:not(:last-child) {
|
||||
margin-right: 8px;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .damage-reduction-container .mark-selection .mark-selection-inner .mark-container {
|
||||
cursor: pointer;
|
||||
border: 1px solid light-dark(#18162e, #f3c267);
|
||||
border-radius: 6px;
|
||||
height: 26px;
|
||||
padding: 0 1px;
|
||||
font-size: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0.4;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .damage-reduction-container .mark-selection .mark-selection-inner .mark-container.selected {
|
||||
opacity: 1;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .damage-reduction-container .mark-selection .mark-selection-inner .mark-container.inactive {
|
||||
cursor: initial;
|
||||
opacity: 0.2;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .damage-reduction-container .mark-selection .mark-selection-inner .mark-container .fa-shield {
|
||||
position: relative;
|
||||
right: 0.5px;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .damage-reduction-container .stress-reduction-container {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .damage-reduction-container .stress-reduction-container .stress-reduction {
|
||||
border: 1px solid light-dark(#18162e, #f3c267);
|
||||
border-radius: 6px;
|
||||
height: 26px;
|
||||
padding: 0 4px;
|
||||
font-size: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
opacity: 0.4;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .damage-reduction-container .stress-reduction-container .stress-reduction.active {
|
||||
opacity: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .damage-reduction-container .stress-reduction-container .stress-reduction.selected {
|
||||
opacity: 1;
|
||||
background: var(--color-warm-2);
|
||||
color: white;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .damage-reduction-container .stress-reduction-container .stress-reduction .stress-reduction-cost {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .damage-reduction-container .markers-subtitle {
|
||||
margin: -4px 0 0 0;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .damage-reduction-container .markers-subtitle.bold {
|
||||
font-variant: all-small-caps;
|
||||
font-weight: bold;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .damage-reduction-container footer {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .damage-reduction-container footer button {
|
||||
flex: 1;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .damage-reduction-container footer button .damage-value {
|
||||
font-weight: bold;
|
||||
}
|
||||
.daggerheart.views.damage-reduction .damage-reduction-container footer button .damage-value.reduced-value {
|
||||
opacity: 0.4;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
:root {
|
||||
--shadow-text-stroke: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;
|
||||
--fear-animation: background 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease, opacity 0.3s ease;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
@import './characterCreation.less';
|
||||
@import './levelup.less';
|
||||
@import './ownershipSelection.less';
|
||||
@import './damageReduction.less';
|
||||
@import './resources.less';
|
||||
@import './countdown.less';
|
||||
@import './settings.less';
|
||||
|
|
|
|||
145
styles/damageReduction.less
Normal file
145
styles/damageReduction.less
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
.daggerheart.views.damage-reduction {
|
||||
.window-content {
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.damage-reduction-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
|
||||
.section-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.padded {
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.armor-title {
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.resources-container {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
|
||||
.resource-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.mark-selection {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
|
||||
.mark-selection-inner {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.mark-container {
|
||||
cursor: pointer;
|
||||
border: 1px solid light-dark(@dark-blue, @golden);
|
||||
border-radius: 6px;
|
||||
height: 26px;
|
||||
padding: 0 1px;
|
||||
font-size: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0.4;
|
||||
|
||||
&.selected {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.inactive {
|
||||
cursor: initial;
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.fa-shield {
|
||||
position: relative;
|
||||
right: 0.5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.stress-reduction-container {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
|
||||
.stress-reduction {
|
||||
border: 1px solid light-dark(@dark-blue, @golden);
|
||||
border-radius: 6px;
|
||||
height: 26px;
|
||||
padding: 0 4px;
|
||||
font-size: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
opacity: 0.4;
|
||||
|
||||
&.active {
|
||||
opacity: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
opacity: 1;
|
||||
background: var(--color-warm-2);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.stress-reduction-cost {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.markers-subtitle {
|
||||
margin: -4px 0 0 0;
|
||||
|
||||
&.bold {
|
||||
font-variant: all-small-caps;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
footer {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
||||
button {
|
||||
flex: 1;
|
||||
|
||||
.damage-value {
|
||||
font-weight: bold;
|
||||
|
||||
&.reduced-value {
|
||||
opacity: 0.4;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
@import '../utils/colors.less';
|
||||
@import '../utils/fonts.less';
|
||||
|
||||
.application.sheet.daggerheart.actor.dh-style.character {
|
||||
.window-content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
@import '../utils/colors.less';
|
||||
@import '../utils/fonts.less';
|
||||
|
||||
.application.sheet.daggerheart.actor.dh-style.character {
|
||||
.window-content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
@import '../../utils/colors.less';
|
||||
@import '../../utils/fonts.less';
|
||||
|
||||
.application.sheet.daggerheart.actor.dh-style.character {
|
||||
.tab.biography {
|
||||
.items-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
mask-image: linear-gradient(0deg, transparent 0%, black 10%, black 98%, transparent 100%);
|
||||
padding-bottom: 40px;
|
||||
height: 100%;
|
||||
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: light-dark(@dark-blue, @golden) transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
@import '../../utils/colors.less';
|
||||
@import '../../utils/fonts.less';
|
||||
|
||||
.application.sheet.daggerheart.actor.dh-style.character {
|
||||
.tab.biography {
|
||||
.items-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
mask-image: linear-gradient(0deg, transparent 0%, black 10%, black 98%, transparent 100%);
|
||||
padding-bottom: 40px;
|
||||
height: 100%;
|
||||
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: light-dark(@dark-blue, @golden) transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
@import '../../utils/colors.less';
|
||||
@import '../../utils/fonts.less';
|
||||
|
||||
.application.sheet.daggerheart.actor.dh-style.character {
|
||||
.tab.features {
|
||||
.features-sections {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
overflow-y: auto;
|
||||
mask-image: linear-gradient(0deg, transparent 0%, black 5%, black 95%, transparent 100%);
|
||||
padding: 20px 0;
|
||||
padding-top: 10px;
|
||||
height: 95%;
|
||||
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: light-dark(@dark-blue, @golden) transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
@import '../../utils/colors.less';
|
||||
@import '../../utils/fonts.less';
|
||||
|
||||
.application.sheet.daggerheart.actor.dh-style.character {
|
||||
.tab.features {
|
||||
.features-sections {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
overflow-y: auto;
|
||||
mask-image: linear-gradient(0deg, transparent 0%, black 5%, black 95%, transparent 100%);
|
||||
padding: 20px 0;
|
||||
padding-top: 10px;
|
||||
height: 95%;
|
||||
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: light-dark(@dark-blue, @golden) transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,65 +1,65 @@
|
|||
@import '../../utils/colors.less';
|
||||
@import '../../utils/fonts.less';
|
||||
|
||||
.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;
|
||||
font-family: @font-body;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
.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;
|
||||
gap: 10px;
|
||||
overflow-y: auto;
|
||||
mask-image: linear-gradient(0deg, transparent 0%, black 5%, black 95%, transparent 100%);
|
||||
padding: 20px 0;
|
||||
height: 80%;
|
||||
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: light-dark(@dark-blue, @golden) transparent;
|
||||
}
|
||||
|
||||
.currency-section {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@import '../../utils/colors.less';
|
||||
@import '../../utils/fonts.less';
|
||||
|
||||
.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;
|
||||
font-family: @font-body;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
.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;
|
||||
gap: 10px;
|
||||
overflow-y: auto;
|
||||
mask-image: linear-gradient(0deg, transparent 0%, black 5%, black 95%, transparent 100%);
|
||||
padding: 20px 0;
|
||||
height: 80%;
|
||||
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: light-dark(@dark-blue, @golden) transparent;
|
||||
}
|
||||
|
||||
.currency-section {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,101 +1,101 @@
|
|||
@import '../../utils/colors.less';
|
||||
@import '../../utils/fonts.less';
|
||||
|
||||
.application.sheet.daggerheart.actor.dh-style.character {
|
||||
.tab.loadout {
|
||||
.search-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.search-bar {
|
||||
position: relative;
|
||||
color: light-dark(@dark-blue-50, @beige-50);
|
||||
width: 80%;
|
||||
padding-top: 5px;
|
||||
|
||||
input {
|
||||
border-radius: 50px;
|
||||
font-family: @font-body;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
align-content: center;
|
||||
height: 32px;
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
font-size: 16px;
|
||||
z-index: 1;
|
||||
color: light-dark(@dark-blue-50, @beige-50);
|
||||
}
|
||||
}
|
||||
|
||||
.btn-toogle-view {
|
||||
background: light-dark(@dark-blue-10, @dark-blue);
|
||||
border: 1px solid light-dark(@dark-blue, @golden);
|
||||
border-radius: 15px;
|
||||
padding: 0;
|
||||
gap: 0;
|
||||
width: 62px;
|
||||
|
||||
span {
|
||||
margin: 1px;
|
||||
width: 26px;
|
||||
color: light-dark(@dark-blue, @golden);
|
||||
|
||||
&.list-icon {
|
||||
i {
|
||||
margin-left: 3px;
|
||||
}
|
||||
}
|
||||
&.grid-icon {
|
||||
i {
|
||||
margin-right: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
&.list-active {
|
||||
border-radius: 32px 3px 3px 32px;
|
||||
background-color: light-dark(@dark-blue, @golden);
|
||||
color: light-dark(@beige, @dark-blue);
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
&.grid-active {
|
||||
border-radius: 3px 32px 32px 3px;
|
||||
background-color: light-dark(@dark-blue, @golden);
|
||||
color: light-dark(@beige, @dark-blue);
|
||||
padding: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.items-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
mask-image: linear-gradient(0deg, transparent 0%, black 10%, black 98%, transparent 100%);
|
||||
padding: 20px 0;
|
||||
height: 90%;
|
||||
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: light-dark(@dark-blue, @golden) transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
@import '../../utils/colors.less';
|
||||
@import '../../utils/fonts.less';
|
||||
|
||||
.application.sheet.daggerheart.actor.dh-style.character {
|
||||
.tab.loadout {
|
||||
.search-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.search-bar {
|
||||
position: relative;
|
||||
color: light-dark(@dark-blue-50, @beige-50);
|
||||
width: 80%;
|
||||
padding-top: 5px;
|
||||
|
||||
input {
|
||||
border-radius: 50px;
|
||||
font-family: @font-body;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
align-content: center;
|
||||
height: 32px;
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
font-size: 16px;
|
||||
z-index: 1;
|
||||
color: light-dark(@dark-blue-50, @beige-50);
|
||||
}
|
||||
}
|
||||
|
||||
.btn-toogle-view {
|
||||
background: light-dark(@dark-blue-10, @dark-blue);
|
||||
border: 1px solid light-dark(@dark-blue, @golden);
|
||||
border-radius: 15px;
|
||||
padding: 0;
|
||||
gap: 0;
|
||||
width: 62px;
|
||||
|
||||
span {
|
||||
margin: 1px;
|
||||
width: 26px;
|
||||
color: light-dark(@dark-blue, @golden);
|
||||
|
||||
&.list-icon {
|
||||
i {
|
||||
margin-left: 3px;
|
||||
}
|
||||
}
|
||||
&.grid-icon {
|
||||
i {
|
||||
margin-right: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
&.list-active {
|
||||
border-radius: 32px 3px 3px 32px;
|
||||
background-color: light-dark(@dark-blue, @golden);
|
||||
color: light-dark(@beige, @dark-blue);
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
&.grid-active {
|
||||
border-radius: 3px 32px 32px 3px;
|
||||
background-color: light-dark(@dark-blue, @golden);
|
||||
color: light-dark(@beige, @dark-blue);
|
||||
padding: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.items-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
mask-image: linear-gradient(0deg, transparent 0%, black 10%, black 98%, transparent 100%);
|
||||
padding: 20px 0;
|
||||
height: 90%;
|
||||
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: light-dark(@dark-blue, @golden) transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,32 +1,32 @@
|
|||
@import '../../utils/colors.less';
|
||||
@import '../../utils/fonts.less';
|
||||
|
||||
.application.sheet.daggerheart.actor.dh-style.character {
|
||||
.window-content {
|
||||
display: grid;
|
||||
grid-template-columns: 275px 1fr;
|
||||
grid-template-rows: 283px 1fr;
|
||||
gap: 15px 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
.character-sidebar-sheet {
|
||||
grid-row: 1 / span 2;
|
||||
grid-column: 1;
|
||||
}
|
||||
|
||||
.character-header-sheet {
|
||||
grid-row: 1;
|
||||
grid-column: 2;
|
||||
}
|
||||
|
||||
.tab {
|
||||
grid-row: 2;
|
||||
grid-column: 2;
|
||||
}
|
||||
|
||||
.old-sheet {
|
||||
width: 500px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@import '../../utils/colors.less';
|
||||
@import '../../utils/fonts.less';
|
||||
|
||||
.application.sheet.daggerheart.actor.dh-style.character {
|
||||
.window-content {
|
||||
display: grid;
|
||||
grid-template-columns: 275px 1fr;
|
||||
grid-template-rows: 283px 1fr;
|
||||
gap: 15px 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
.character-sidebar-sheet {
|
||||
grid-row: 1 / span 2;
|
||||
grid-column: 1;
|
||||
}
|
||||
|
||||
.character-header-sheet {
|
||||
grid-row: 1;
|
||||
grid-column: 2;
|
||||
}
|
||||
|
||||
.tab {
|
||||
grid-row: 2;
|
||||
grid-column: 2;
|
||||
}
|
||||
|
||||
.old-sheet {
|
||||
width: 500px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,283 +1,283 @@
|
|||
@import '../../utils/colors.less';
|
||||
@import '../../utils/fonts.less';
|
||||
|
||||
.application.sheet.daggerheart.actor.dh-style.character {
|
||||
.character-sidebar-sheet {
|
||||
width: 275px;
|
||||
min-width: 275px;
|
||||
border-right: 1px solid light-dark(@dark-blue, @golden);
|
||||
background-image: url('../assets/parchments/dh-parchment-dark.png');
|
||||
|
||||
.theme-light & {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
img {
|
||||
height: 235px;
|
||||
width: 275px;
|
||||
border-bottom: 1px solid light-dark(@dark-blue, @golden);
|
||||
cursor: pointer;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.info-section {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
top: -20px;
|
||||
gap: 30px;
|
||||
margin-bottom: -10px;
|
||||
|
||||
.resources-section {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
|
||||
.status-bar {
|
||||
position: relative;
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
justify-items: center;
|
||||
|
||||
.status-label {
|
||||
position: relative;
|
||||
top: 40px;
|
||||
height: 22px;
|
||||
width: 79px;
|
||||
clip-path: path('M0 0H79L74 16.5L39 22L4 16.5L0 0Z');
|
||||
background: light-dark(@dark-blue, @golden);
|
||||
|
||||
h4 {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
line-height: 18px;
|
||||
color: light-dark(@beige, @dark-blue);
|
||||
}
|
||||
}
|
||||
.status-value {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
padding: 0 6px;
|
||||
font-size: 1.5rem;
|
||||
align-items: center;
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
z-index: 2;
|
||||
color: @beige;
|
||||
|
||||
input[type='number'] {
|
||||
background: transparent;
|
||||
font-size: 1.5rem;
|
||||
width: 40px;
|
||||
height: 30px;
|
||||
text-align: center;
|
||||
border: none;
|
||||
outline: 2px solid transparent;
|
||||
color: @beige;
|
||||
|
||||
&.bar-input {
|
||||
padding: 0;
|
||||
color: @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: 40px;
|
||||
}
|
||||
}
|
||||
.progress-bar {
|
||||
position: absolute;
|
||||
appearance: none;
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
border: 1px solid light-dark(@dark-blue, @golden);
|
||||
border-radius: 6px;
|
||||
z-index: 1;
|
||||
|
||||
&::-webkit-progress-bar {
|
||||
border: none;
|
||||
background: @dark-blue;
|
||||
border-radius: 6px;
|
||||
}
|
||||
&::-webkit-progress-value {
|
||||
background: @gradient-hp;
|
||||
border-radius: 6px;
|
||||
}
|
||||
&.stress-color::-webkit-progress-value {
|
||||
background: @gradient-stress;
|
||||
border-radius: 6px;
|
||||
}
|
||||
&::-moz-progress-value,
|
||||
&::-moz-progress-bar {
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
&::-moz-progress-bar {
|
||||
background: @gradient-hp;
|
||||
}
|
||||
&.stress-color::-moz-progress-bar {
|
||||
background: @gradient-stress;
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.status-section {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 5px;
|
||||
justify-content: center;
|
||||
|
||||
.status-number {
|
||||
justify-items: center;
|
||||
|
||||
.status-value {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 50px;
|
||||
height: 30px;
|
||||
border: 1px solid light-dark(@dark-blue, @golden);
|
||||
border-bottom: none;
|
||||
border-radius: 6px 6px 0 0;
|
||||
padding: 0 6px;
|
||||
font-size: 1.2rem;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: light-dark(transparent, @dark-blue);
|
||||
z-index: 2;
|
||||
|
||||
&.armor-slots {
|
||||
width: 80px;
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.status-label {
|
||||
padding: 2px 10px;
|
||||
width: 100%;
|
||||
border-radius: 3px;
|
||||
background: light-dark(@dark-blue, @golden);
|
||||
|
||||
h4 {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
line-height: 18px;
|
||||
font-size: 12px;
|
||||
color: light-dark(@beige, @dark-blue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.items-sidebar-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
|
||||
.inventory-item {
|
||||
padding: 0 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.equipment-section {
|
||||
.title {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
align-items: center;
|
||||
|
||||
h3 {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
.items-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.loadout-section {
|
||||
.title {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
align-items: center;
|
||||
|
||||
h3 {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.experience-section {
|
||||
.title {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
align-items: center;
|
||||
|
||||
h3 {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.experience-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
align-items: center;
|
||||
|
||||
.experience-row {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
width: 250px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
input[type='text'] {
|
||||
height: 32px;
|
||||
width: 180px;
|
||||
border: 1px solid transparent;
|
||||
outline: 2px solid transparent;
|
||||
font-size: 14px;
|
||||
font-family: @font-body;
|
||||
transition: all 0.3s ease;
|
||||
color: light-dark(@dark, @beige);
|
||||
|
||||
&:hover {
|
||||
outline: 2px solid light-dark(@dark, @beige);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.experience-value {
|
||||
height: 25px;
|
||||
width: 35px;
|
||||
font-size: 14px;
|
||||
font-family: @font-body;
|
||||
color: light-dark(@dark, @beige);
|
||||
align-content: center;
|
||||
text-align: center;
|
||||
background: url(../assets/svg/experience-shield.svg) no-repeat;
|
||||
|
||||
.theme-light & {
|
||||
background: url('../assets/svg/experience-shield-light.svg') no-repeat;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@import '../../utils/colors.less';
|
||||
@import '../../utils/fonts.less';
|
||||
|
||||
.application.sheet.daggerheart.actor.dh-style.character {
|
||||
.character-sidebar-sheet {
|
||||
width: 275px;
|
||||
min-width: 275px;
|
||||
border-right: 1px solid light-dark(@dark-blue, @golden);
|
||||
background-image: url('../assets/parchments/dh-parchment-dark.png');
|
||||
|
||||
.theme-light & {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
img {
|
||||
height: 235px;
|
||||
width: 275px;
|
||||
border-bottom: 1px solid light-dark(@dark-blue, @golden);
|
||||
cursor: pointer;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.info-section {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
top: -20px;
|
||||
gap: 30px;
|
||||
margin-bottom: -10px;
|
||||
|
||||
.resources-section {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
|
||||
.status-bar {
|
||||
position: relative;
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
justify-items: center;
|
||||
|
||||
.status-label {
|
||||
position: relative;
|
||||
top: 40px;
|
||||
height: 22px;
|
||||
width: 79px;
|
||||
clip-path: path('M0 0H79L74 16.5L39 22L4 16.5L0 0Z');
|
||||
background: light-dark(@dark-blue, @golden);
|
||||
|
||||
h4 {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
line-height: 18px;
|
||||
color: light-dark(@beige, @dark-blue);
|
||||
}
|
||||
}
|
||||
.status-value {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
padding: 0 6px;
|
||||
font-size: 1.5rem;
|
||||
align-items: center;
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
z-index: 2;
|
||||
color: @beige;
|
||||
|
||||
input[type='number'] {
|
||||
background: transparent;
|
||||
font-size: 1.5rem;
|
||||
width: 40px;
|
||||
height: 30px;
|
||||
text-align: center;
|
||||
border: none;
|
||||
outline: 2px solid transparent;
|
||||
color: @beige;
|
||||
|
||||
&.bar-input {
|
||||
padding: 0;
|
||||
color: @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: 40px;
|
||||
}
|
||||
}
|
||||
.progress-bar {
|
||||
position: absolute;
|
||||
appearance: none;
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
border: 1px solid light-dark(@dark-blue, @golden);
|
||||
border-radius: 6px;
|
||||
z-index: 1;
|
||||
|
||||
&::-webkit-progress-bar {
|
||||
border: none;
|
||||
background: @dark-blue;
|
||||
border-radius: 6px;
|
||||
}
|
||||
&::-webkit-progress-value {
|
||||
background: @gradient-hp;
|
||||
border-radius: 6px;
|
||||
}
|
||||
&.stress-color::-webkit-progress-value {
|
||||
background: @gradient-stress;
|
||||
border-radius: 6px;
|
||||
}
|
||||
&::-moz-progress-value,
|
||||
&::-moz-progress-bar {
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
&::-moz-progress-bar {
|
||||
background: @gradient-hp;
|
||||
}
|
||||
&.stress-color::-moz-progress-bar {
|
||||
background: @gradient-stress;
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.status-section {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 5px;
|
||||
justify-content: center;
|
||||
|
||||
.status-number {
|
||||
justify-items: center;
|
||||
|
||||
.status-value {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 50px;
|
||||
height: 30px;
|
||||
border: 1px solid light-dark(@dark-blue, @golden);
|
||||
border-bottom: none;
|
||||
border-radius: 6px 6px 0 0;
|
||||
padding: 0 6px;
|
||||
font-size: 1.2rem;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: light-dark(transparent, @dark-blue);
|
||||
z-index: 2;
|
||||
|
||||
&.armor-slots {
|
||||
width: 80px;
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.status-label {
|
||||
padding: 2px 10px;
|
||||
width: 100%;
|
||||
border-radius: 3px;
|
||||
background: light-dark(@dark-blue, @golden);
|
||||
|
||||
h4 {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
line-height: 18px;
|
||||
font-size: 12px;
|
||||
color: light-dark(@beige, @dark-blue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.items-sidebar-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
|
||||
.inventory-item {
|
||||
padding: 0 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.equipment-section {
|
||||
.title {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
align-items: center;
|
||||
|
||||
h3 {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
.items-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.loadout-section {
|
||||
.title {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
align-items: center;
|
||||
|
||||
h3 {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.experience-section {
|
||||
.title {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
align-items: center;
|
||||
|
||||
h3 {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.experience-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
align-items: center;
|
||||
|
||||
.experience-row {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
width: 250px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
input[type='text'] {
|
||||
height: 32px;
|
||||
width: 180px;
|
||||
border: 1px solid transparent;
|
||||
outline: 2px solid transparent;
|
||||
font-size: 14px;
|
||||
font-family: @font-body;
|
||||
transition: all 0.3s ease;
|
||||
color: light-dark(@dark, @beige);
|
||||
|
||||
&:hover {
|
||||
outline: 2px solid light-dark(@dark, @beige);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.experience-value {
|
||||
height: 25px;
|
||||
width: 35px;
|
||||
font-size: 14px;
|
||||
font-family: @font-body;
|
||||
color: light-dark(@dark, @beige);
|
||||
align-content: center;
|
||||
text-align: center;
|
||||
background: url(../assets/svg/experience-shield.svg) no-repeat;
|
||||
|
||||
.theme-light & {
|
||||
background: url('../assets/svg/experience-shield-light.svg') no-repeat;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
@import '../utils/colors.less';
|
||||
@import '../utils/fonts.less';
|
||||
|
||||
.application.sheet.daggerheart.actor.dh-style.character {
|
||||
.items-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
.card-list {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
@import '../utils/colors.less';
|
||||
@import '../utils/fonts.less';
|
||||
|
||||
.application.sheet.daggerheart.actor.dh-style.character {
|
||||
.items-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
.card-list {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,133 +1,133 @@
|
|||
@import '../utils/colors.less';
|
||||
@import '../utils/fonts.less';
|
||||
|
||||
.application.sheet.daggerheart.actor.dh-style.character {
|
||||
.inventory-item {
|
||||
display: grid;
|
||||
grid-template-columns: 40px 1fr 60px;
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
|
||||
.item-img {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
border-radius: 3px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.item-label {
|
||||
font-family: @font-body;
|
||||
align-self: center;
|
||||
|
||||
.item-name {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.item-tags,
|
||||
.item-labels {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
|
||||
.tag {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 3px 5px;
|
||||
font-size: 12px;
|
||||
|
||||
background: light-dark(@dark-15, @beige-15);
|
||||
border: 1px solid light-dark(@dark, @beige);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.label {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: end;
|
||||
gap: 8px;
|
||||
|
||||
a {
|
||||
text-align: center;
|
||||
|
||||
&.unequipped {
|
||||
opacity: 0.4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.card-item {
|
||||
position: relative;
|
||||
height: 120px;
|
||||
width: 100px;
|
||||
border: 1px solid light-dark(@dark-blue, @golden);
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
.card-label {
|
||||
padding-top: 15px;
|
||||
.controls {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transition: all 0.3s ease;
|
||||
max-height: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-img {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.card-label {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: fit-content;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
background-color: @dark-blue;
|
||||
bottom: 0;
|
||||
mask-image: linear-gradient(180deg, transparent 0%, black 20%);
|
||||
|
||||
.card-name {
|
||||
font-family: @font-body;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
line-height: 15px;
|
||||
|
||||
color: @beige;
|
||||
}
|
||||
|
||||
.controls {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
align-items: center;
|
||||
max-height: 0px;
|
||||
opacity: 0;
|
||||
visibility: collapse;
|
||||
transition: all 0.3s ease;
|
||||
color: @beige;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@import '../utils/colors.less';
|
||||
@import '../utils/fonts.less';
|
||||
|
||||
.application.sheet.daggerheart.actor.dh-style.character {
|
||||
.inventory-item {
|
||||
display: grid;
|
||||
grid-template-columns: 40px 1fr 60px;
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
|
||||
.item-img {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
border-radius: 3px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.item-label {
|
||||
font-family: @font-body;
|
||||
align-self: center;
|
||||
|
||||
.item-name {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.item-tags,
|
||||
.item-labels {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
|
||||
.tag {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 3px 5px;
|
||||
font-size: 12px;
|
||||
|
||||
background: light-dark(@dark-15, @beige-15);
|
||||
border: 1px solid light-dark(@dark, @beige);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.label {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: end;
|
||||
gap: 8px;
|
||||
|
||||
a {
|
||||
text-align: center;
|
||||
|
||||
&.unequipped {
|
||||
opacity: 0.4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.card-item {
|
||||
position: relative;
|
||||
height: 120px;
|
||||
width: 100px;
|
||||
border: 1px solid light-dark(@dark-blue, @golden);
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
.card-label {
|
||||
padding-top: 15px;
|
||||
.controls {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transition: all 0.3s ease;
|
||||
max-height: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-img {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.card-label {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: fit-content;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
background-color: @dark-blue;
|
||||
bottom: 0;
|
||||
mask-image: linear-gradient(180deg, transparent 0%, black 20%);
|
||||
|
||||
.card-name {
|
||||
font-family: @font-body;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
line-height: 15px;
|
||||
|
||||
color: @beige;
|
||||
}
|
||||
|
||||
.controls {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
align-items: center;
|
||||
max-height: 0px;
|
||||
opacity: 0;
|
||||
visibility: collapse;
|
||||
transition: all 0.3s ease;
|
||||
color: @beige;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
@import '../utils/colors.less';
|
||||
@import '../utils/fonts.less';
|
||||
|
||||
.sheet.daggerheart.dh-style {
|
||||
.tab-navigation {
|
||||
margin: 5px 0;
|
||||
height: 40px;
|
||||
|
||||
.feature-tab {
|
||||
border: none;
|
||||
|
||||
a {
|
||||
color: light-dark(@dark-blue, @golden);
|
||||
font-family: @font-body;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@import '../utils/colors.less';
|
||||
@import '../utils/fonts.less';
|
||||
|
||||
.sheet.daggerheart.dh-style {
|
||||
.tab-navigation {
|
||||
margin: 5px 0;
|
||||
height: 40px;
|
||||
|
||||
.feature-tab {
|
||||
border: none;
|
||||
|
||||
a {
|
||||
color: light-dark(@dark-blue, @golden);
|
||||
font-family: @font-body;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
@primary-blue: #1488cc;
|
||||
@secondary-blue: #2b32b2;
|
||||
@golden: #f3c267;
|
||||
@golden-40: #f3c26740;
|
||||
@dark-blue-40: #18162e40;
|
||||
@golden-10: #f3c26710;
|
||||
@dark-blue-10: #18162e10;
|
||||
@dark-blue-50: #18162e50;
|
||||
@dark-blue: #18162e;
|
||||
@deep-black: #0e0d15;
|
||||
@beige: #efe6d8;
|
||||
@beige-15: #efe6d815;
|
||||
@beige-50: #efe6d850;
|
||||
@dark-blue: rgb(24, 22, 46);
|
||||
@semi-transparent-dark-blue: rgba(24, 22, 46, 0.33);
|
||||
@dark: #222;
|
||||
@dark-15: #22222215;
|
||||
@light-black: rgba(0, 0, 0, 0.3);
|
||||
@soft-shadow: rgba(0, 0, 0, 0.05);
|
||||
@gradient-hp: linear-gradient(15deg, rgb(70, 20, 10) 0%, rgb(190, 0, 0) 42%, rgb(252, 176, 69) 100%);
|
||||
@gradient-stress: linear-gradient(15deg, rgb(130, 59, 1) 0%, rgb(252, 142, 69) 65%, rgb(190, 0, 0) 100%);
|
||||
@primary-blue: #1488cc;
|
||||
@secondary-blue: #2b32b2;
|
||||
@golden: #f3c267;
|
||||
@golden-40: #f3c26740;
|
||||
@dark-blue-40: #18162e40;
|
||||
@golden-10: #f3c26710;
|
||||
@dark-blue-10: #18162e10;
|
||||
@dark-blue-50: #18162e50;
|
||||
@dark-blue: #18162e;
|
||||
@deep-black: #0e0d15;
|
||||
@beige: #efe6d8;
|
||||
@beige-15: #efe6d815;
|
||||
@beige-50: #efe6d850;
|
||||
@dark-blue: rgb(24, 22, 46);
|
||||
@semi-transparent-dark-blue: rgba(24, 22, 46, 0.33);
|
||||
@dark: #222;
|
||||
@dark-15: #22222215;
|
||||
@light-black: rgba(0, 0, 0, 0.3);
|
||||
@soft-shadow: rgba(0, 0, 0, 0.05);
|
||||
@gradient-hp: linear-gradient(15deg, rgb(70, 20, 10) 0%, rgb(190, 0, 0) 42%, rgb(252, 176, 69) 100%);
|
||||
@gradient-stress: linear-gradient(15deg, rgb(130, 59, 1) 0%, rgb(252, 142, 69) 65%, rgb(190, 0, 0) 100%);
|
||||
|
|
|
|||
76
templates/views/damageReduction.hbs
Normal file
76
templates/views/damageReduction.hbs
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
<div class="damage-reduction-container">
|
||||
<div class="section-container padded">
|
||||
<div class="resources-container">
|
||||
<div class="resource-container">
|
||||
<h4 class="armor-title">{{localize "DAGGERHEART.DamageReduction.ArmorMarks"}}</h4>
|
||||
<div class="markers-subtitle">{{armorMarks}}/{{armorScore}}</div>
|
||||
</div>
|
||||
{{#if this.stress}}
|
||||
<div class="resource-container">
|
||||
<h4 class="armor-title">{{localize "DAGGERHEART.DamageReduction.Stress"}}</h4>
|
||||
<div class="markers-subtitle">{{this.stress.value}}/{{this.stress.maxTotal}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-container">
|
||||
<h4 class="mark-selection divider">
|
||||
<div class="mark-selection-inner">
|
||||
{{#each marks.armor}}
|
||||
<div
|
||||
class="mark-container {{#if this.selected}}selected{{/if}}"
|
||||
data-action="setMarks" data-key="{{@key}}" data-type="armor"
|
||||
>
|
||||
<i class="fa-solid fa-shield"></i>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
<div class="mark-selection-inner">
|
||||
{{#each marks.stress}}
|
||||
<div
|
||||
class="mark-container {{#if this.selected}}selected{{/if}} {{#if (not @root.basicMarksUsed)}}inactive{{/if}}"
|
||||
{{#if @root.basicMarksUsed}}data-action="setMarks"{{/if}} data-key="{{@key}}" data-type="stress" data-tooltip="{{#if @root.basicMarksUsed}}{{localize "DAGGERHEART.DamageReduction.ArmorWithStress"}}{{else}}{{localize "DAGGERHEART.DamageReduction.UnncessaryStress"}}{{/if}}"
|
||||
>
|
||||
<i class="fa-solid fa-bolt"></i>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</h4>
|
||||
<div class="markers-subtitle bold">{{localize "DAGGERHEART.DamageReduction.UsedMarks"}}</div>
|
||||
</div>
|
||||
|
||||
<div class="resources-container">
|
||||
<div class="resource-container">
|
||||
<h4 class="armor-title">{{localize "DAGGERHEART.DamageReduction.StressReduction"}}</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#each availableStressReductions}}
|
||||
<div class="section-container">
|
||||
<h4 class="stress-reduction-container divider">
|
||||
<div class="stress-reduction {{#if (eq this.from @root.currentDamage)}}active{{/if}} {{#if this.selected}}selected{{/if}}" data-action="useStressReduction" data-reduction="{{@key}}">
|
||||
{{this.from}}
|
||||
<i class="fa-solid fa-arrow-right-long"></i>
|
||||
{{this.to}}
|
||||
<div class="stress-reduction-cost">
|
||||
{{this.cost}}
|
||||
<i class="fa-solid fa-bolt"></i>
|
||||
</div>
|
||||
</div>
|
||||
</h4>
|
||||
</div>
|
||||
{{/each}}
|
||||
|
||||
<footer class="padded">
|
||||
<button type="button" data-action="takeDamage">
|
||||
{{localize "Take"}}
|
||||
<div class="damage-value {{#if this.reducedDamage}}reduced-value{{/if}}">{{this.damage}}</div>
|
||||
{{#if this.reducedDamage}}
|
||||
<i class="fa-solid fa-arrow-right-long"></i>
|
||||
<div class="damage-value">{{this.reducedDamage}}</div>
|
||||
{{/if}}
|
||||
{{localize "Damage"}}
|
||||
</button>
|
||||
</footer>
|
||||
</div>
|
||||
Loading…
Add table
Add a link
Reference in a new issue