mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-03-07 14:36:13 +01:00
Merged with development
This commit is contained in:
commit
307af5b990
11 changed files with 131 additions and 60 deletions
|
|
@ -2405,6 +2405,14 @@
|
||||||
"hideAttribution": {
|
"hideAttribution": {
|
||||||
"label": "Hide Attribution"
|
"label": "Hide Attribution"
|
||||||
},
|
},
|
||||||
|
"showTokenDistance": {
|
||||||
|
"label": "Show Token Distance on Hover",
|
||||||
|
"choices": {
|
||||||
|
"always": "Always",
|
||||||
|
"encounters": "Encounters",
|
||||||
|
"never": "Never"
|
||||||
|
}
|
||||||
|
},
|
||||||
"expandedTitle": "Auto-expand Descriptions",
|
"expandedTitle": "Auto-expand Descriptions",
|
||||||
"extendCharacterDescriptions": {
|
"extendCharacterDescriptions": {
|
||||||
"label": "Characters"
|
"label": "Characters"
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,8 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
|
||||||
name: game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.newDowntimeMove'),
|
name: game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.newDowntimeMove'),
|
||||||
img: 'icons/magic/life/cross-worn-green.webp',
|
img: 'icons/magic/life/cross-worn-green.webp',
|
||||||
description: '',
|
description: '',
|
||||||
actions: []
|
actions: [],
|
||||||
|
effects: []
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if (['armorFeatures', 'weaponFeatures'].includes(type)) {
|
} else if (['armorFeatures', 'weaponFeatures'].includes(type)) {
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,9 @@ export default class DhMeasuredTemplate extends foundry.canvas.placeables.Measur
|
||||||
|
|
||||||
static getRangeLabels(distanceValue, settings) {
|
static getRangeLabels(distanceValue, settings) {
|
||||||
let result = { distance: distanceValue, units: '' };
|
let result = { distance: distanceValue, units: '' };
|
||||||
const sceneRangeMeasurement = canvas.scene.flags.daggerheart?.rangeMeasurement;
|
if (!settings.enabled) return result;
|
||||||
|
|
||||||
|
const sceneRangeMeasurement = canvas.scene.flags.daggerheart?.rangeMeasurement;
|
||||||
const { disable, custom } = CONFIG.DH.GENERAL.sceneRangeMeasurementSetting;
|
const { disable, custom } = CONFIG.DH.GENERAL.sceneRangeMeasurementSetting;
|
||||||
if (sceneRangeMeasurement?.setting === disable.id) {
|
if (sceneRangeMeasurement?.setting === disable.id) {
|
||||||
result.distance = distanceValue;
|
result.distance = distanceValue;
|
||||||
|
|
@ -27,31 +28,9 @@ export default class DhMeasuredTemplate extends foundry.canvas.placeables.Measur
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const melee = sceneRangeMeasurement?.setting === custom.id ? sceneRangeMeasurement.melee : settings.melee;
|
const ranges = sceneRangeMeasurement?.setting === custom.id ? sceneRangeMeasurement : settings;
|
||||||
const veryClose =
|
const distanceKey = ['melee', 'veryClose', 'close', 'far'].find(r => ranges[r] >= distanceValue);
|
||||||
sceneRangeMeasurement?.setting === custom.id ? sceneRangeMeasurement.veryClose : settings.veryClose;
|
result.distance = game.i18n.localize(`DAGGERHEART.CONFIG.Range.${distanceKey ?? 'veryFar'}.name`);
|
||||||
const close = sceneRangeMeasurement?.setting === custom.id ? sceneRangeMeasurement.close : settings.close;
|
|
||||||
const far = sceneRangeMeasurement?.setting === custom.id ? sceneRangeMeasurement.far : settings.far;
|
|
||||||
if (distanceValue <= melee) {
|
|
||||||
result.distance = game.i18n.localize('DAGGERHEART.CONFIG.Range.melee.name');
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if (distanceValue <= veryClose) {
|
|
||||||
result.distance = game.i18n.localize('DAGGERHEART.CONFIG.Range.veryClose.name');
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if (distanceValue <= close) {
|
|
||||||
result.distance = game.i18n.localize('DAGGERHEART.CONFIG.Range.close.name');
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if (distanceValue <= far) {
|
|
||||||
result.distance = game.i18n.localize('DAGGERHEART.CONFIG.Range.far.name');
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if (distanceValue > far) {
|
|
||||||
result.distance = game.i18n.localize('DAGGERHEART.CONFIG.Range.veryFar.name');
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import DhMeasuredTemplate from './measuredTemplate.mjs';
|
||||||
|
|
||||||
export default class DhTokenPlaceable extends foundry.canvas.placeables.Token {
|
export default class DhTokenPlaceable extends foundry.canvas.placeables.Token {
|
||||||
/** @inheritdoc */
|
/** @inheritdoc */
|
||||||
async _draw(options) {
|
async _draw(options) {
|
||||||
|
|
@ -78,6 +80,60 @@ export default class DhTokenPlaceable extends foundry.canvas.placeables.Token {
|
||||||
return canvas.grid.measurePath([adjustedOriginPoint, adjustDestinationPoint]).distance;
|
return canvas.grid.measurePath([adjustedOriginPoint, adjustDestinationPoint]).distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onHoverIn(event, options) {
|
||||||
|
super._onHoverIn(event, options);
|
||||||
|
|
||||||
|
// Check if the setting is enabled
|
||||||
|
const setting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance).showTokenDistance;
|
||||||
|
if (setting === 'never' || (setting === 'encounters' && !game.combat?.started)) return;
|
||||||
|
|
||||||
|
// Check if this token isn't invisible and is actually being hovered
|
||||||
|
const isTokenValid =
|
||||||
|
this.visible &&
|
||||||
|
this.hover &&
|
||||||
|
!this.isPreview &&
|
||||||
|
!this.document.isSecret &&
|
||||||
|
!this.controlled &&
|
||||||
|
!this.animation;
|
||||||
|
if (!isTokenValid) return;
|
||||||
|
|
||||||
|
// Ensure we have a single controlled token
|
||||||
|
const originToken = canvas.tokens.controlled[0];
|
||||||
|
if (!originToken || canvas.tokens.controlled.length > 1) return;
|
||||||
|
|
||||||
|
// Determine the actual range
|
||||||
|
const ranges = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.variantRules).rangeMeasurement;
|
||||||
|
const distanceNum = originToken.distanceTo(this);
|
||||||
|
const distanceResult = DhMeasuredTemplate.getRangeLabels(distanceNum, ranges);
|
||||||
|
const distanceLabel = `${distanceResult.distance} ${distanceResult.units}`.trim();
|
||||||
|
|
||||||
|
// Create the element
|
||||||
|
const element = document.createElement('div');
|
||||||
|
element.id = 'token-hover-distance';
|
||||||
|
element.classList.add('waypoint-label', 'last');
|
||||||
|
const ruler = document.createElement('i');
|
||||||
|
ruler.classList.add('fa-solid', 'fa-ruler');
|
||||||
|
element.appendChild(ruler);
|
||||||
|
const labelEl = document.createElement('span');
|
||||||
|
labelEl.classList.add('total-measurement');
|
||||||
|
labelEl.textContent = distanceLabel;
|
||||||
|
element.appendChild(labelEl);
|
||||||
|
|
||||||
|
// Position the element and add to the DOM
|
||||||
|
const center = this.getCenterPoint();
|
||||||
|
element.style.setProperty('--transformY', 'calc(-100% - 10px)');
|
||||||
|
element.style.setProperty('--position-y', `${this.y}px`);
|
||||||
|
element.style.setProperty('--position-x', `${center.x}px`);
|
||||||
|
element.style.setProperty('--ui-scale', String(canvas.dimensions.uiScale));
|
||||||
|
document.querySelector('#token-hover-distance')?.remove();
|
||||||
|
document.querySelector('#measurement').appendChild(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onHoverOut(...args) {
|
||||||
|
super._onHoverOut(...args);
|
||||||
|
document.querySelector('#token-hover-distance')?.remove();
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns the point at which a line starting at origin and ending at destination intersects the edge of the bounds */
|
/** Returns the point at which a line starting at origin and ending at destination intersects the edge of the bounds */
|
||||||
#getEdgeBoundary(bounds, originPoint, destinationPoint) {
|
#getEdgeBoundary(bounds, originPoint, destinationPoint) {
|
||||||
const points = [
|
const points = [
|
||||||
|
|
|
||||||
|
|
@ -114,9 +114,24 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
||||||
* Return Item the action is attached too.
|
* Return Item the action is attached too.
|
||||||
*/
|
*/
|
||||||
get item() {
|
get item() {
|
||||||
|
if (!this.parent.parent && this.systemPath)
|
||||||
|
return foundry.utils.getProperty(this.parent, this.systemPath).get(this.id);
|
||||||
|
|
||||||
return this.parent.parent;
|
return this.parent.parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get applyEffects() {
|
||||||
|
if (this.item.systemPath) {
|
||||||
|
const itemEffectIds = this.item.effects.map(x => x._id);
|
||||||
|
const movePathSplit = this.item.systemPath.split('.');
|
||||||
|
movePathSplit.pop();
|
||||||
|
const move = foundry.utils.getProperty(this.parent, movePathSplit.join('.'));
|
||||||
|
return new Collection(itemEffectIds.map(id => [id, move.effects.find(x => x.id === id)]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.item.effects;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the first Actor parent found.
|
* Return the first Actor parent found.
|
||||||
*/
|
*/
|
||||||
|
|
@ -125,7 +140,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
||||||
? this.item
|
? this.item
|
||||||
: this.item?.parent instanceof DhpActor
|
: this.item?.parent instanceof DhpActor
|
||||||
? this.item.parent
|
? this.item.parent
|
||||||
: this.item?.actor;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static getRollType(parent) {
|
static getRollType(parent) {
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ export default class EffectsField extends fields.ArrayField {
|
||||||
});
|
});
|
||||||
|
|
||||||
effects.forEach(async e => {
|
effects.forEach(async e => {
|
||||||
const effect = this.item.effects.get(e._id);
|
const effect = (this.item.applyEffects ?? this.item.effects).get(e._id);
|
||||||
if (!token.actor || !effect) return;
|
if (!token.actor || !effect) return;
|
||||||
await EffectsField.applyEffect(effect, token.actor);
|
await EffectsField.applyEffect(effect, token.actor);
|
||||||
});
|
});
|
||||||
|
|
@ -96,7 +96,7 @@ export default class EffectsField extends fields.ArrayField {
|
||||||
content: await foundry.applications.handlebars.renderTemplate(
|
content: await foundry.applications.handlebars.renderTemplate(
|
||||||
'systems/daggerheart/templates/ui/chat/effectSummary.hbs',
|
'systems/daggerheart/templates/ui/chat/effectSummary.hbs',
|
||||||
{
|
{
|
||||||
effects: this.effects.map(e => this.item.effects.get(e._id)),
|
effects: this.effects.map(e => (this.item.applyEffects ?? this.item.effects).get(e._id)),
|
||||||
targets: messageTargets
|
targets: messageTargets
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -123,7 +123,7 @@ export default class EffectsField extends fields.ArrayField {
|
||||||
|
|
||||||
// Otherwise, create a new effect on the target
|
// Otherwise, create a new effect on the target
|
||||||
const effectData = foundry.utils.mergeObject({
|
const effectData = foundry.utils.mergeObject({
|
||||||
...effect.toObject(),
|
...(effect.toObject?.() ?? effect),
|
||||||
disabled: false,
|
disabled: false,
|
||||||
transfer: false,
|
transfer: false,
|
||||||
origin: effect.uuid
|
origin: effect.uuid
|
||||||
|
|
|
||||||
|
|
@ -159,6 +159,7 @@ export function ActionMixin(Base) {
|
||||||
}
|
}
|
||||||
|
|
||||||
get uuid() {
|
get uuid() {
|
||||||
|
if (!(this.item instanceof game.system.api.documents.DHItem)) return null;
|
||||||
return `${this.item.uuid}.${this.documentName}.${this.id}`;
|
return `${this.item.uuid}.${this.documentName}.${this.id}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,25 @@ export default class DhAppearance extends foundry.abstract.DataModel {
|
||||||
damage: new BooleanField(),
|
damage: new BooleanField(),
|
||||||
target: new BooleanField()
|
target: new BooleanField()
|
||||||
}),
|
}),
|
||||||
|
showTokenDistance: new StringField({
|
||||||
|
required: true,
|
||||||
|
choices: {
|
||||||
|
always: {
|
||||||
|
value: 'always',
|
||||||
|
label: 'DAGGERHEART.SETTINGS.Appearance.FIELDS.showTokenDistance.choices.always'
|
||||||
|
},
|
||||||
|
encounters: {
|
||||||
|
value: 'encounters',
|
||||||
|
label: 'DAGGERHEART.SETTINGS.Appearance.FIELDS.showTokenDistance.choices.encounters'
|
||||||
|
},
|
||||||
|
never: {
|
||||||
|
value: 'never',
|
||||||
|
label: 'DAGGERHEART.SETTINGS.Appearance.FIELDS.showTokenDistance.choices.never'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
nullable: false,
|
||||||
|
initial: 'always'
|
||||||
|
}),
|
||||||
hideAttribution: new BooleanField(),
|
hideAttribution: new BooleanField(),
|
||||||
showGenericStatusEffects: new BooleanField({ initial: true })
|
showGenericStatusEffects: new BooleanField({ initial: true })
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,20 @@ const currencyField = (initial, label, icon) =>
|
||||||
icon: new foundry.data.fields.StringField({ required: true, nullable: false, blank: true, initial: icon })
|
icon: new foundry.data.fields.StringField({ required: true, nullable: false, blank: true, initial: icon })
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const restMoveField = () =>
|
||||||
|
new foundry.data.fields.SchemaField({
|
||||||
|
name: new foundry.data.fields.StringField({ required: true }),
|
||||||
|
icon: new foundry.data.fields.StringField({ required: true }),
|
||||||
|
img: new foundry.data.fields.FilePathField({
|
||||||
|
initial: 'icons/magic/life/cross-worn-green.webp',
|
||||||
|
categories: ['IMAGE'],
|
||||||
|
base64: false
|
||||||
|
}),
|
||||||
|
description: new foundry.data.fields.HTMLField(),
|
||||||
|
actions: new ActionsField(),
|
||||||
|
effects: new foundry.data.fields.ArrayField(new foundry.data.fields.ObjectField())
|
||||||
|
});
|
||||||
|
|
||||||
export default class DhHomebrew extends foundry.abstract.DataModel {
|
export default class DhHomebrew extends foundry.abstract.DataModel {
|
||||||
static defineSchema() {
|
static defineSchema() {
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
|
|
@ -105,37 +119,11 @@ export default class DhHomebrew extends foundry.abstract.DataModel {
|
||||||
restMoves: new fields.SchemaField({
|
restMoves: new fields.SchemaField({
|
||||||
longRest: new fields.SchemaField({
|
longRest: new fields.SchemaField({
|
||||||
nrChoices: new fields.NumberField({ required: true, integer: true, min: 1, initial: 2 }),
|
nrChoices: new fields.NumberField({ required: true, integer: true, min: 1, initial: 2 }),
|
||||||
moves: new fields.TypedObjectField(
|
moves: new fields.TypedObjectField(restMoveField(), { initial: defaultRestOptions.longRest() })
|
||||||
new fields.SchemaField({
|
|
||||||
name: new fields.StringField({ required: true }),
|
|
||||||
icon: new fields.StringField({ required: true }),
|
|
||||||
img: new fields.FilePathField({
|
|
||||||
initial: 'icons/magic/life/cross-worn-green.webp',
|
|
||||||
categories: ['IMAGE'],
|
|
||||||
base64: false
|
|
||||||
}),
|
|
||||||
description: new fields.HTMLField(),
|
|
||||||
actions: new ActionsField()
|
|
||||||
}),
|
|
||||||
{ initial: defaultRestOptions.longRest() }
|
|
||||||
)
|
|
||||||
}),
|
}),
|
||||||
shortRest: new fields.SchemaField({
|
shortRest: new fields.SchemaField({
|
||||||
nrChoices: new fields.NumberField({ required: true, integer: true, min: 1, initial: 2 }),
|
nrChoices: new fields.NumberField({ required: true, integer: true, min: 1, initial: 2 }),
|
||||||
moves: new fields.TypedObjectField(
|
moves: new fields.TypedObjectField(restMoveField(), { initial: defaultRestOptions.shortRest() })
|
||||||
new fields.SchemaField({
|
|
||||||
name: new fields.StringField({ required: true }),
|
|
||||||
icon: new fields.StringField({ required: true }),
|
|
||||||
img: new fields.FilePathField({
|
|
||||||
initial: 'icons/magic/life/cross-worn-green.webp',
|
|
||||||
categories: ['IMAGE'],
|
|
||||||
base64: false
|
|
||||||
}),
|
|
||||||
description: new fields.HTMLField(),
|
|
||||||
actions: new ActionsField()
|
|
||||||
}),
|
|
||||||
{ initial: defaultRestOptions.shortRest() }
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
domains: new fields.TypedObjectField(
|
domains: new fields.TypedObjectField(
|
||||||
|
|
|
||||||
|
|
@ -269,7 +269,7 @@ export default class DHToken extends CONFIG.Token.documentClass {
|
||||||
|
|
||||||
// Hexagon symmetry
|
// Hexagon symmetry
|
||||||
if (columns) {
|
if (columns) {
|
||||||
const rowData = BaseToken.#getHexagonalShape(height, width, shape, false);
|
const rowData = DHToken.#getHexagonalShape(height, width, shape, false);
|
||||||
if (!rowData) return null;
|
if (!rowData) return null;
|
||||||
|
|
||||||
// Transpose the offsets/points of the shape in row orientation
|
// Transpose the offsets/points of the shape in row orientation
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,10 @@
|
||||||
value=setting.showGenericStatusEffects
|
value=setting.showGenericStatusEffects
|
||||||
localize=true}}
|
localize=true}}
|
||||||
{{formGroup
|
{{formGroup
|
||||||
|
fields.showTokenDistance
|
||||||
|
value=setting.showTokenDistance
|
||||||
|
localize=true}}
|
||||||
|
{{formGroup
|
||||||
fields.hideAttribution
|
fields.hideAttribution
|
||||||
value=setting.hideAttribution
|
value=setting.hideAttribution
|
||||||
localize=true}}
|
localize=true}}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue