mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-11 11:15:21 +01:00
Merged with development
This commit is contained in:
commit
f9bfd2184f
65 changed files with 3930 additions and 201 deletions
|
|
@ -335,14 +335,14 @@ const updateActorsRangeDependentEffects = async token => {
|
|||
break;
|
||||
}
|
||||
|
||||
const distanceBetween = canvas.grid.measurePath([
|
||||
userTarget.document.movement.destination,
|
||||
token.movement.destination
|
||||
]).distance;
|
||||
const distance = rangeMeasurement[range];
|
||||
|
||||
// Get required distance and special case 5 feet to test adjacency
|
||||
const required = rangeMeasurement[range];
|
||||
const reverse = type === CONFIG.DH.GENERAL.rangeInclusion.outsideRange.id;
|
||||
if (reverse ? distanceBetween <= distance : distanceBetween > distance) {
|
||||
const inRange =
|
||||
required === 5
|
||||
? userTarget.isAdjacentWith(token.object)
|
||||
: userTarget.distanceTo(token.object) <= required;
|
||||
if (reverse ? inRange : !inRange) {
|
||||
enabledEffect = false;
|
||||
break;
|
||||
}
|
||||
|
|
@ -356,16 +356,15 @@ const updateAllRangeDependentEffects = async () => {
|
|||
const effectsAutomation = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).effects;
|
||||
if (!effectsAutomation.rangeDependent) return;
|
||||
|
||||
// Only consider tokens on the active scene
|
||||
const tokens = game.scenes.find(x => x.active).tokens;
|
||||
const tokens = canvas.scene.tokens;
|
||||
if (game.user.character) {
|
||||
// The character updates their character's token. There can be only one token.
|
||||
const characterToken = tokens.find(x => x.actor === game.user.character);
|
||||
updateActorsRangeDependentEffects(characterToken);
|
||||
} else if (game.user.isGM) {
|
||||
} else if (game.user.isActiveGM) {
|
||||
// The GM is responsible for all other tokens.
|
||||
const playerCharacters = game.users.players.filter(x => x.active).map(x => x.character);
|
||||
for (let token of tokens.filter(x => !playerCharacters.includes(x.actor))) {
|
||||
for (const token of tokens.filter(x => !playerCharacters.includes(x.actor))) {
|
||||
updateActorsRangeDependentEffects(token);
|
||||
}
|
||||
}
|
||||
|
|
@ -373,12 +372,14 @@ const updateAllRangeDependentEffects = async () => {
|
|||
|
||||
const debouncedRangeEffectCall = foundry.utils.debounce(updateAllRangeDependentEffects, 50);
|
||||
|
||||
Hooks.on('targetToken', async (user, token, targeted) => {
|
||||
Hooks.on('targetToken', () => {
|
||||
debouncedRangeEffectCall();
|
||||
});
|
||||
|
||||
Hooks.on('moveToken', async (movedToken, data) => {
|
||||
debouncedRangeEffectCall();
|
||||
Hooks.on('refreshToken', (_, options) => {
|
||||
if (options.refreshPosition) {
|
||||
debouncedRangeEffectCall();
|
||||
}
|
||||
});
|
||||
|
||||
Hooks.on('renderCompendiumDirectory', (app, html) => applications.ui.ItemBrowser.injectSidebarButton(html));
|
||||
|
|
|
|||
|
|
@ -233,6 +233,7 @@
|
|||
"confirmText": "Would you like to level up your companion {name} by {levelChange} levels at this time? (You can do it manually later)"
|
||||
},
|
||||
"viewLevelups": "View Levelups",
|
||||
"viewParty": "View Party",
|
||||
"InvalidOldCharacterImportTitle": "Old Character Import",
|
||||
"InvalidOldCharacterImportText": "Character data exported prior to system version 1.1 will not generate a complete character. Do you wish to continue?",
|
||||
"cancelBeastform": "Cancel Beastform"
|
||||
|
|
@ -333,6 +334,7 @@
|
|||
"equip": "Equip",
|
||||
"sendToChat": "Send To Chat",
|
||||
"toLoadout": "Send to Loadout",
|
||||
"recall": "Recall",
|
||||
"toVault": "Send to Vault",
|
||||
"unequip": "Unequip",
|
||||
"useItem": "Use Item"
|
||||
|
|
@ -1807,7 +1809,9 @@
|
|||
"label": "Long Rest: Bonus Long Rest Moves",
|
||||
"hint": "The number of extra Long Rest Moves the character can take during a Long Rest."
|
||||
}
|
||||
}
|
||||
},
|
||||
"target": "Target",
|
||||
"targetSelf": "Self"
|
||||
},
|
||||
"maxLoadout": {
|
||||
"label": "Max Loadout Cards Bonus"
|
||||
|
|
|
|||
|
|
@ -278,19 +278,26 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat
|
|||
'close',
|
||||
async () => {
|
||||
const selected = app.selected.toObject();
|
||||
const evolved = app.evolved.form ? app.evolved.form.toObject() : null;
|
||||
const data = await game.system.api.data.items.DHBeastform.getWildcardImage(
|
||||
app.configData.data.parent,
|
||||
app.selected
|
||||
evolved ?? app.selected
|
||||
);
|
||||
if (data) {
|
||||
if (!data.selectedImage) selected = null;
|
||||
else {
|
||||
if (data.usesDynamicToken) selected.system.tokenRingImg = data.selectedImage;
|
||||
else selected.system.tokenImg = data.selectedImage;
|
||||
const imageSource = evolved ?? selected;
|
||||
if (imageSource.usesDynamicToken) imageSource.system.tokenRingImg = data.selectedImage;
|
||||
else imageSource.system.tokenImg = data.selectedImage;
|
||||
}
|
||||
}
|
||||
|
||||
resolve({ selected: selected, evolved: app.evolved, hybrid: app.hybrid, item: featureItem });
|
||||
resolve({
|
||||
selected: selected,
|
||||
evolved: { ...app.evolved, form: evolved },
|
||||
hybrid: app.hybrid,
|
||||
item: featureItem
|
||||
});
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
context.roll = this.roll;
|
||||
context.rollType = this.roll?.constructor.name;
|
||||
context.rallyDie = this.roll.rallyChoices;
|
||||
const experiences = this.config.data?.system.experiences || {};
|
||||
const experiences = this.config.data?.system?.experiences || {};
|
||||
context.experiences = Object.keys(experiences).map(id => ({
|
||||
id,
|
||||
...experiences[id]
|
||||
|
|
|
|||
|
|
@ -93,27 +93,29 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
|
|||
}
|
||||
|
||||
getRefreshables() {
|
||||
const actionItems = this.actor.items.filter(x => this.actor.system.isItemAvailable(x)).reduce((acc, x) => {
|
||||
if (x.system.actions) {
|
||||
const recoverable = x.system.actions.reduce((acc, action) => {
|
||||
if (refreshIsAllowed([this.shortrest ? 'shortRest' : 'longRest'], action.uses.recovery)) {
|
||||
acc.push({
|
||||
title: x.name,
|
||||
name: action.name,
|
||||
uuid: action.uuid
|
||||
});
|
||||
const actionItems = this.actor.items
|
||||
.filter(x => this.actor.system.isItemAvailable(x))
|
||||
.reduce((acc, x) => {
|
||||
if (x.system.actions) {
|
||||
const recoverable = x.system.actions.reduce((acc, action) => {
|
||||
if (refreshIsAllowed([this.shortrest ? 'shortRest' : 'longRest'], action.uses.recovery)) {
|
||||
acc.push({
|
||||
title: x.name,
|
||||
name: action.name,
|
||||
uuid: action.uuid
|
||||
});
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
if (recoverable) {
|
||||
acc.push(...recoverable);
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
if (recoverable) {
|
||||
acc.push(...recoverable);
|
||||
}
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
return acc;
|
||||
}, []);
|
||||
const resourceItems = this.actor.items.reduce((acc, x) => {
|
||||
if (
|
||||
x.system.resource &&
|
||||
|
|
@ -181,12 +183,18 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
|
|||
.filter(x => category.moves[x].selected)
|
||||
.flatMap(key => {
|
||||
const move = category.moves[key];
|
||||
const needsTarget = move.actions.filter(x => x.target?.type && x.target.type !== 'self').length > 0;
|
||||
return [...Array(move.selected).keys()].map(_ => ({
|
||||
...move,
|
||||
movePath: `${categoryKey}.moves.${key}`
|
||||
movePath: `${categoryKey}.moves.${key}`,
|
||||
needsTarget: needsTarget
|
||||
}));
|
||||
});
|
||||
});
|
||||
const characters = game.actors
|
||||
.filter(x => x.type === 'character')
|
||||
.filter(x => x.testUserPermission(game.user, 'LIMITED'))
|
||||
.filter(x => x.uuid !== this.actor.uuid);
|
||||
|
||||
const cls = getDocumentClass('ChatMessage');
|
||||
const msg = {
|
||||
|
|
@ -206,7 +214,9 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
|
|||
`DAGGERHEART.APPLICATIONS.Downtime.${this.shortrest ? 'shortRest' : 'longRest'}.title`
|
||||
),
|
||||
actor: { name: this.actor.name, img: this.actor.img },
|
||||
moves: moves
|
||||
moves: moves,
|
||||
characters: characters,
|
||||
selfId: this.actor.uuid
|
||||
}
|
||||
),
|
||||
flags: {
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
cost: this.data.initiator.cost
|
||||
};
|
||||
|
||||
const selectedMember = Object.values(context.members).find(x => x.selected);
|
||||
const selectedMember = Object.values(context.members).find(x => x.selected && x.roll);
|
||||
const selectedIsCritical = selectedMember?.roll?.system?.isCritical;
|
||||
context.selectedData = {
|
||||
result: selectedMember
|
||||
|
|
|
|||
|
|
@ -51,6 +51,19 @@ export default class DHAdversarySettings extends DHBaseActorSettings {
|
|||
}
|
||||
};
|
||||
|
||||
async _prepareContext(options) {
|
||||
const context = await super._prepareContext(options);
|
||||
|
||||
const featureForms = ['passive', 'action', 'reaction'];
|
||||
context.features = context.document.system.features.sort((a, b) =>
|
||||
a.system.featureForm !== b.system.featureForm
|
||||
? featureForms.indexOf(a.system.featureForm) - featureForms.indexOf(b.system.featureForm)
|
||||
: a.sort - b.sort
|
||||
);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
|
|
@ -98,16 +111,16 @@ export default class DHAdversarySettings extends DHBaseActorSettings {
|
|||
|
||||
async _onDrop(event) {
|
||||
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event);
|
||||
|
||||
|
||||
const item = await fromUuid(data.uuid);
|
||||
if (item?.type === 'feature') {
|
||||
if (data.fromInternal && item.parent?.uuid === this.actor.uuid) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const itemData = item.toObject();
|
||||
delete itemData._id;
|
||||
|
||||
|
||||
await this.actor.createEmbeddedDocuments('Item', [itemData]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,19 @@ export default class DHEnvironmentSettings extends DHBaseActorSettings {
|
|||
}
|
||||
};
|
||||
|
||||
async _prepareContext(options) {
|
||||
const context = await super._prepareContext(options);
|
||||
|
||||
const featureForms = ['passive', 'action', 'reaction'];
|
||||
context.features = context.document.system.features.sort((a, b) =>
|
||||
a.system.featureForm !== b.system.featureForm
|
||||
? featureForms.indexOf(a.system.featureForm) - featureForms.indexOf(b.system.featureForm)
|
||||
: a.sort - b.sort
|
||||
);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new category entry to the actor.
|
||||
* @type {ApplicationClickAction}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,12 @@ export default class AdversarySheet extends DHBaseActorSheet {
|
|||
}
|
||||
]
|
||||
},
|
||||
dragDrop: [{ dragSelector: '[data-item-id]', dropSelector: null }]
|
||||
dragDrop: [
|
||||
{
|
||||
dragSelector: '[data-item-id][draggable="true"], [data-item-id] [draggable="true"]',
|
||||
dropSelector: null
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
static PARTS = {
|
||||
|
|
@ -88,6 +93,13 @@ export default class AdversarySheet extends DHBaseActorSheet {
|
|||
context.resources.stress.emptyPips =
|
||||
context.resources.stress.max < maxResource ? maxResource - context.resources.stress.max : 0;
|
||||
|
||||
const featureForms = ['passive', 'action', 'reaction'];
|
||||
context.features = this.document.system.features.sort((a, b) =>
|
||||
a.system.featureForm !== b.system.featureForm
|
||||
? featureForms.indexOf(a.system.featureForm) - featureForms.indexOf(b.system.featureForm)
|
||||
: a.sort - b.sort
|
||||
);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
|
|
@ -164,6 +176,15 @@ export default class AdversarySheet extends DHBaseActorSheet {
|
|||
});
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
async _onDragStart(event) {
|
||||
const inventoryItem = event.currentTarget.closest('.inventory-item');
|
||||
if (inventoryItem) {
|
||||
event.dataTransfer.setDragImage(inventoryItem.querySelector('img'), 60, 0);
|
||||
}
|
||||
super._onDragStart(event);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Application Clicks Actions */
|
||||
/* -------------------------------------------- */
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
handleResourceDice: CharacterSheet.#handleResourceDice,
|
||||
advanceResourceDie: CharacterSheet.#advanceResourceDie,
|
||||
cancelBeastform: CharacterSheet.#cancelBeastform,
|
||||
useDowntime: this.useDowntime
|
||||
useDowntime: this.useDowntime,
|
||||
viewParty: CharacterSheet.#viewParty
|
||||
},
|
||||
window: {
|
||||
resizable: true,
|
||||
|
|
@ -318,6 +319,45 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.loadoutMaxReached'));
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'recall',
|
||||
icon: 'fa-solid fa-bolt-lightning',
|
||||
condition: target => {
|
||||
const doc = getDocFromElementSync(target);
|
||||
return doc && doc.system.inVault;
|
||||
},
|
||||
callback: async (target, event) => {
|
||||
const doc = await getDocFromElement(target);
|
||||
const actorLoadout = doc.actor.system.loadoutSlot;
|
||||
if (!actorLoadout.available) {
|
||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.loadoutMaxReached'));
|
||||
return;
|
||||
}
|
||||
if (doc.system.recallCost == 0) {
|
||||
return doc.update({ 'system.inVault': false });
|
||||
}
|
||||
const type = 'effect';
|
||||
const cls = game.system.api.models.actions.actionsTypes[type];
|
||||
const action = new cls(
|
||||
{
|
||||
...cls.getSourceConfig(doc.system),
|
||||
type: type,
|
||||
chatDisplay: false,
|
||||
cost: [
|
||||
{
|
||||
key: 'stress',
|
||||
value: doc.system.recallCost
|
||||
}
|
||||
]
|
||||
},
|
||||
{ parent: doc.system }
|
||||
);
|
||||
const config = await action.use(event);
|
||||
if (config) {
|
||||
return doc.update({ 'system.inVault': false });
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'toVault',
|
||||
icon: 'fa-solid fa-arrow-down',
|
||||
|
|
@ -858,6 +898,41 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
game.system.api.fields.ActionFields.BeastformField.handleActiveTransformations.call(item);
|
||||
}
|
||||
|
||||
static async #viewParty(_, target) {
|
||||
const parties = this.document.parties;
|
||||
if (parties.size <= 1) {
|
||||
parties.first()?.sheet.render({ force: true });
|
||||
return;
|
||||
}
|
||||
|
||||
const buttons = parties.map(p => {
|
||||
const button = document.createElement('button');
|
||||
button.type = 'button';
|
||||
button.classList.add('plain');
|
||||
const img = document.createElement('img');
|
||||
img.src = p.img;
|
||||
button.append(img);
|
||||
const name = document.createElement('span');
|
||||
name.textContent = p.name;
|
||||
button.append(name);
|
||||
button.addEventListener('click', () => {
|
||||
p.sheet?.render({ force: true });
|
||||
game.tooltip.dismissLockedTooltips();
|
||||
});
|
||||
return button;
|
||||
});
|
||||
|
||||
const html = document.createElement('div');
|
||||
html.classList.add('party-list');
|
||||
html.append(...buttons);
|
||||
|
||||
game.tooltip.dismissLockedTooltips();
|
||||
game.tooltip.activate(target, {
|
||||
html,
|
||||
locked: true
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the downtime application.
|
||||
* @type {ApplicationClickAction}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,12 @@ export default class DhpEnvironment extends DHBaseActorSheet {
|
|||
toggleResourceDice: DhpEnvironment.#toggleResourceDice,
|
||||
handleResourceDice: DhpEnvironment.#handleResourceDice
|
||||
},
|
||||
dragDrop: [{ dragSelector: '.inventory-item', dropSelector: null }]
|
||||
dragDrop: [
|
||||
{
|
||||
dragSelector: '[data-item-id][draggable="true"], [data-item-id] [draggable="true"]',
|
||||
dropSelector: null
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/**@override */
|
||||
|
|
@ -74,6 +79,9 @@ export default class DhpEnvironment extends DHBaseActorSheet {
|
|||
case 'header':
|
||||
await this._prepareHeaderContext(context, options);
|
||||
|
||||
break;
|
||||
case 'features':
|
||||
await this._prepareFeaturesContext(context, options);
|
||||
break;
|
||||
case 'notes':
|
||||
await this._prepareNotesContext(context, options);
|
||||
|
|
@ -110,6 +118,22 @@ export default class DhpEnvironment extends DHBaseActorSheet {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare render context for the features part.
|
||||
* @param {ApplicationRenderContext} context
|
||||
* @param {ApplicationRenderOptions} options
|
||||
* @returns {Promise<void>}
|
||||
* @protected
|
||||
*/
|
||||
async _prepareFeaturesContext(context, _options) {
|
||||
const featureForms = ['passive', 'action', 'reaction'];
|
||||
context.features = this.document.system.features.sort((a, b) =>
|
||||
a.system.featureForm !== b.system.featureForm
|
||||
? featureForms.indexOf(a.system.featureForm) - featureForms.indexOf(b.system.featureForm)
|
||||
: a.sort - b.sort
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare render context for the Header part.
|
||||
* @param {ApplicationRenderContext} context
|
||||
|
|
|
|||
|
|
@ -134,7 +134,9 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
|||
|
||||
async actionUseButton(event, message) {
|
||||
const { moveIndex, actionIndex, movePath } = event.currentTarget.dataset;
|
||||
const parent = await foundry.utils.fromUuid(message.system.actor);
|
||||
const targetUuid = event.currentTarget.closest('.action-use-button-parent').querySelector('select')?.value;
|
||||
const parent = await foundry.utils.fromUuid(targetUuid || message.system.actor);
|
||||
|
||||
const actionType = message.system.moves[moveIndex].actions[actionIndex];
|
||||
const cls = game.system.api.models.actions.actionsTypes[actionType.type];
|
||||
const action = new cls(
|
||||
|
|
@ -146,7 +148,8 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
|||
type: CONFIG.DH.ITEM.originItemType.restMove,
|
||||
itemPath: movePath,
|
||||
actionIndex: actionIndex
|
||||
}
|
||||
},
|
||||
targetUuid: targetUuid
|
||||
},
|
||||
{ parent: parent.system }
|
||||
);
|
||||
|
|
|
|||
|
|
@ -42,6 +42,69 @@ export default class DhTokenPlaceable extends foundry.canvas.placeables.Token {
|
|||
this.renderFlags.set({ refreshEffects: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the distance from this token to another token object.
|
||||
* This value is corrected to handle alternate token sizes and other grid types
|
||||
* according to the diagonal rules.
|
||||
*/
|
||||
distanceTo(target) {
|
||||
if (!canvas.ready) return NaN;
|
||||
if (this === target) return 0;
|
||||
|
||||
const originPoint = this.center;
|
||||
const destinationPoint = target.center;
|
||||
|
||||
// Compute for gridless. This version returns circular edge to edge + grid distance,
|
||||
// so that tokens that are touching return 5.
|
||||
if (canvas.grid.type === CONST.GRID_TYPES.GRIDLESS) {
|
||||
const boundsCorrection = canvas.grid.distance / canvas.grid.size;
|
||||
const originRadius = (this.bounds.width * boundsCorrection) / 2;
|
||||
const targetRadius = (target.bounds.width * boundsCorrection) / 2;
|
||||
const distance = canvas.grid.measurePath([originPoint, destinationPoint]).distance;
|
||||
return distance - originRadius - targetRadius + canvas.grid.distance;
|
||||
}
|
||||
|
||||
// Compute what the closest grid space of each token is, then compute that distance
|
||||
const originEdge = this.#getEdgeBoundary(this.bounds, originPoint, destinationPoint);
|
||||
const targetEdge = this.#getEdgeBoundary(target.bounds, originPoint, destinationPoint);
|
||||
const adjustedOriginPoint = canvas.grid.getTopLeftPoint({
|
||||
x: originEdge.x + Math.sign(originPoint.x - originEdge.x),
|
||||
y: originEdge.y + Math.sign(originPoint.y - originEdge.y)
|
||||
});
|
||||
const adjustDestinationPoint = canvas.grid.getTopLeftPoint({
|
||||
x: targetEdge.x + Math.sign(destinationPoint.x - targetEdge.x),
|
||||
y: targetEdge.y + Math.sign(destinationPoint.y - targetEdge.y)
|
||||
});
|
||||
return canvas.grid.measurePath([adjustedOriginPoint, adjustDestinationPoint]).distance;
|
||||
}
|
||||
|
||||
/** Returns the point at which a line starting at origin and ending at destination intersects the edge of the bounds */
|
||||
#getEdgeBoundary(bounds, originPoint, destinationPoint) {
|
||||
const points = [
|
||||
{ x: bounds.x, y: bounds.y },
|
||||
{ x: bounds.x + bounds.width, y: bounds.y },
|
||||
{ x: bounds.x + bounds.width, y: bounds.y + bounds.height },
|
||||
{ x: bounds.x, y: bounds.y + bounds.height }
|
||||
];
|
||||
const pairsToTest = [
|
||||
[points[0], points[1]],
|
||||
[points[1], points[2]],
|
||||
[points[2], points[3]],
|
||||
[points[3], points[0]]
|
||||
];
|
||||
for (const pair of pairsToTest) {
|
||||
const result = foundry.utils.lineSegmentIntersection(originPoint, destinationPoint, pair[0], pair[1]);
|
||||
if (result) return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Tests if the token is at least adjacent with another, with some leeway for diagonals */
|
||||
isAdjacentWith(token) {
|
||||
return this.distanceTo(token) <= canvas.grid.distance * 1.5;
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
_drawBar(number, bar, data) {
|
||||
const val = Number(data.value);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ export const actionTypes = {
|
|||
attack: {
|
||||
id: 'attack',
|
||||
name: 'DAGGERHEART.ACTIONS.TYPES.attack.name',
|
||||
icon: 'fa-khanda',
|
||||
icon: 'fa-hand-fist',
|
||||
tooltip: 'DAGGERHEART.ACTIONS.TYPES.attack.tooltip'
|
||||
},
|
||||
countdown: {
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ export const defaultRestOptions = {
|
|||
actionType: 'action',
|
||||
chatDisplay: false,
|
||||
target: {
|
||||
type: 'self'
|
||||
type: 'friendly'
|
||||
},
|
||||
damage: {
|
||||
parts: [
|
||||
|
|
@ -298,7 +298,7 @@ export const defaultRestOptions = {
|
|||
actionType: 'action',
|
||||
chatDisplay: false,
|
||||
target: {
|
||||
type: 'self'
|
||||
type: 'friendly'
|
||||
},
|
||||
damage: {
|
||||
parts: [
|
||||
|
|
@ -341,7 +341,7 @@ export const defaultRestOptions = {
|
|||
actionType: 'action',
|
||||
chatDisplay: false,
|
||||
target: {
|
||||
type: 'self'
|
||||
type: 'friendly'
|
||||
},
|
||||
damage: {
|
||||
parts: [
|
||||
|
|
@ -407,7 +407,7 @@ export const defaultRestOptions = {
|
|||
actionType: 'action',
|
||||
chatDisplay: false,
|
||||
target: {
|
||||
type: 'self'
|
||||
type: 'friendly'
|
||||
},
|
||||
damage: {
|
||||
parts: [
|
||||
|
|
|
|||
|
|
@ -435,7 +435,8 @@ export const armorFeatures = {
|
|||
{
|
||||
key: 'system.resistance.magical.reduction',
|
||||
mode: 2,
|
||||
value: '@system.armorScore'
|
||||
value: '@system.armorScore',
|
||||
priority: 21
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -709,7 +710,8 @@ export const weaponFeatures = {
|
|||
{
|
||||
key: 'system.evasion',
|
||||
mode: 2,
|
||||
value: '@system.armorScore'
|
||||
value: '@system.armorScore',
|
||||
priority: 21
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1324,7 +1326,8 @@ export const weaponFeatures = {
|
|||
{
|
||||
key: 'system.bonuses.damage.primaryWeapon.bonus',
|
||||
mode: 2,
|
||||
value: '@system.traits.agility.value'
|
||||
value: '@system.traits.agility.value',
|
||||
priority: 21
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1416,9 +1419,9 @@ export const orderedWeaponFeatures = () => {
|
|||
};
|
||||
|
||||
export const featureForm = {
|
||||
passive: "DAGGERHEART.CONFIG.FeatureForm.passive",
|
||||
action: "DAGGERHEART.CONFIG.FeatureForm.action",
|
||||
reaction: "DAGGERHEART.CONFIG.FeatureForm.reaction"
|
||||
passive: 'DAGGERHEART.CONFIG.FeatureForm.passive',
|
||||
action: 'DAGGERHEART.CONFIG.FeatureForm.action',
|
||||
reaction: 'DAGGERHEART.CONFIG.FeatureForm.reaction'
|
||||
};
|
||||
|
||||
export const featureTypes = {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
initial: 'action',
|
||||
nullable: false,
|
||||
required: true
|
||||
})
|
||||
}),
|
||||
targetUuid: new fields.StringField({ initial: undefined })
|
||||
};
|
||||
|
||||
this.extraSchemas.forEach(s => {
|
||||
|
|
@ -240,7 +241,8 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
selectedRollMode: game.settings.get('core', 'rollMode'),
|
||||
data: this.getRollData(),
|
||||
evaluate: this.hasRoll,
|
||||
resourceUpdates: new ResourceUpdateMap(this.actor)
|
||||
resourceUpdates: new ResourceUpdateMap(this.actor),
|
||||
targetUuid: this.targetUuid
|
||||
};
|
||||
|
||||
DHBaseAction.applyKeybindings(config);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,17 @@
|
|||
/** -- Changes Type Priorities --
|
||||
* - Base Number -
|
||||
* Custom: 0
|
||||
* Multiply: 10
|
||||
* Add: 20
|
||||
* Downgrade: 30
|
||||
* Upgrade: 40
|
||||
* Override: 50
|
||||
*
|
||||
* - Changes Value Priorities -
|
||||
* Standard: +0
|
||||
* "Anything that uses another data model value as its value": +1 - Effects that increase traits have to be calculated first at Base priority. (EX: Raise evasion by half your agility)
|
||||
*/
|
||||
|
||||
export default class BaseEffect extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
|
|
|
|||
|
|
@ -66,12 +66,20 @@ export default class BeastformEffect extends BaseEffect {
|
|||
};
|
||||
|
||||
const updateToken = token => {
|
||||
const { x, y } = game.system.api.documents.DhToken.getSnappedPositionInSquareGrid(
|
||||
token.object.scene.grid,
|
||||
{ x: token.x, y: token.y, elevation: token.elevation },
|
||||
baseUpdate.width,
|
||||
baseUpdate.height
|
||||
);
|
||||
let x = null,
|
||||
y = null;
|
||||
if (token.object?.scene?.grid) {
|
||||
const positionData = game.system.api.documents.DhToken.getSnappedPositionInSquareGrid(
|
||||
token.object.scene.grid,
|
||||
{ x: token.x, y: token.y, elevation: token.elevation },
|
||||
baseUpdate.width,
|
||||
baseUpdate.height
|
||||
);
|
||||
|
||||
x = positionData.x;
|
||||
y = positionData.y;
|
||||
}
|
||||
|
||||
return {
|
||||
...baseUpdate,
|
||||
x,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import DHAdversarySettings from '../../applications/sheets-configs/adversary-settings.mjs';
|
||||
import { ActionField } from '../fields/actionField.mjs';
|
||||
import BaseDataActor from './base.mjs';
|
||||
import BaseDataActor, { commonActorRules } from './base.mjs';
|
||||
import { resourceField, bonusField } from '../fields/actorField.mjs';
|
||||
|
||||
export default class DhpAdversary extends BaseDataActor {
|
||||
|
|
@ -56,25 +56,11 @@ export default class DhpAdversary extends BaseDataActor {
|
|||
})
|
||||
}),
|
||||
resources: new fields.SchemaField({
|
||||
hitPoints: resourceField(
|
||||
0,
|
||||
0,
|
||||
'DAGGERHEART.GENERAL.HitPoints.plural',
|
||||
true
|
||||
),
|
||||
stress: resourceField(
|
||||
0,
|
||||
0,
|
||||
'DAGGERHEART.GENERAL.stress',
|
||||
true
|
||||
)
|
||||
hitPoints: resourceField(0, 0, 'DAGGERHEART.GENERAL.HitPoints.plural', true),
|
||||
stress: resourceField(0, 0, 'DAGGERHEART.GENERAL.stress', true)
|
||||
}),
|
||||
rules: new fields.SchemaField({
|
||||
conditionImmunities: new fields.SchemaField({
|
||||
hidden: new fields.BooleanField({ initial: false }),
|
||||
restrained: new fields.BooleanField({ initial: false }),
|
||||
vulnerable: new fields.BooleanField({ initial: false })
|
||||
})
|
||||
...commonActorRules()
|
||||
}),
|
||||
attack: new ActionField({
|
||||
initial: {
|
||||
|
|
|
|||
|
|
@ -2,21 +2,23 @@ import DHBaseActorSettings from '../../applications/sheets/api/actor-setting.mjs
|
|||
import DHItem from '../../documents/item.mjs';
|
||||
import { getScrollTextData } from '../../helpers/utils.mjs';
|
||||
|
||||
const fields = foundry.data.fields;
|
||||
|
||||
const resistanceField = (resistanceLabel, immunityLabel, reductionLabel) =>
|
||||
new foundry.data.fields.SchemaField({
|
||||
resistance: new foundry.data.fields.BooleanField({
|
||||
new fields.SchemaField({
|
||||
resistance: new fields.BooleanField({
|
||||
initial: false,
|
||||
label: `${resistanceLabel}.label`,
|
||||
hint: `${resistanceLabel}.hint`,
|
||||
isAttributeChoice: true
|
||||
}),
|
||||
immunity: new foundry.data.fields.BooleanField({
|
||||
immunity: new fields.BooleanField({
|
||||
initial: false,
|
||||
label: `${immunityLabel}.label`,
|
||||
hint: `${immunityLabel}.hint`,
|
||||
isAttributeChoice: true
|
||||
}),
|
||||
reduction: new foundry.data.fields.NumberField({
|
||||
reduction: new fields.NumberField({
|
||||
integer: true,
|
||||
initial: 0,
|
||||
label: `${reductionLabel}.label`,
|
||||
|
|
@ -24,6 +26,25 @@ const resistanceField = (resistanceLabel, immunityLabel, reductionLabel) =>
|
|||
})
|
||||
});
|
||||
|
||||
/* Common rules applying to Characters and Adversaries */
|
||||
export const commonActorRules = (extendedData = { damageReduction: {} }) => ({
|
||||
conditionImmunities: new fields.SchemaField({
|
||||
hidden: new fields.BooleanField({ initial: false }),
|
||||
restrained: new fields.BooleanField({ initial: false }),
|
||||
vulnerable: new fields.BooleanField({ initial: false })
|
||||
}),
|
||||
damageReduction: new fields.SchemaField({
|
||||
thresholdImmunities: new fields.SchemaField({
|
||||
minor: new fields.BooleanField({ initial: false })
|
||||
}),
|
||||
reduceSeverity: new fields.SchemaField({
|
||||
magical: new fields.NumberField({ initial: 0, min: 0 }),
|
||||
physical: new fields.NumberField({ initial: 0, min: 0 })
|
||||
}),
|
||||
...extendedData.damageReduction
|
||||
})
|
||||
});
|
||||
|
||||
/**
|
||||
* Describes metadata about the actor data model type
|
||||
* @typedef {Object} ActorDataModelMetadata
|
||||
|
|
@ -54,7 +75,6 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel {
|
|||
|
||||
/** @inheritDoc */
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
const schema = {};
|
||||
|
||||
if (this.metadata.hasAttribution) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { burden } from '../../config/generalConfig.mjs';
|
||||
import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
|
||||
import DhLevelData from '../levelData.mjs';
|
||||
import BaseDataActor from './base.mjs';
|
||||
import BaseDataActor, { commonActorRules } from './base.mjs';
|
||||
import { attributeField, resourceField, stressDamageReductionRule, bonusField } from '../fields/actorField.mjs';
|
||||
import { ActionField } from '../fields/actionField.mjs';
|
||||
import DHCharacterSettings from '../../applications/sheets-configs/character-settings.mjs';
|
||||
|
|
@ -217,44 +217,41 @@ export default class DhCharacter extends BaseDataActor {
|
|||
}),
|
||||
companion: new ForeignDocumentUUIDField({ type: 'Actor', nullable: true, initial: null }),
|
||||
rules: new fields.SchemaField({
|
||||
damageReduction: new fields.SchemaField({
|
||||
maxArmorMarked: new fields.SchemaField({
|
||||
value: new fields.NumberField({
|
||||
required: true,
|
||||
...commonActorRules({
|
||||
damageReduction: {
|
||||
magical: new fields.BooleanField({ initial: false }),
|
||||
physical: new fields.BooleanField({ initial: false }),
|
||||
maxArmorMarked: new fields.SchemaField({
|
||||
value: new fields.NumberField({
|
||||
required: true,
|
||||
integer: true,
|
||||
initial: 1,
|
||||
label: 'DAGGERHEART.GENERAL.Rules.damageReduction.maxArmorMarkedBonus'
|
||||
}),
|
||||
stressExtra: new fields.NumberField({
|
||||
required: true,
|
||||
integer: true,
|
||||
initial: 0,
|
||||
label: 'DAGGERHEART.GENERAL.Rules.damageReduction.maxArmorMarkedStress.label',
|
||||
hint: 'DAGGERHEART.GENERAL.Rules.damageReduction.maxArmorMarkedStress.hint'
|
||||
})
|
||||
}),
|
||||
stressDamageReduction: new fields.SchemaField({
|
||||
severe: stressDamageReductionRule(
|
||||
'DAGGERHEART.GENERAL.Rules.damageReduction.stress.severe'
|
||||
),
|
||||
major: stressDamageReductionRule('DAGGERHEART.GENERAL.Rules.damageReduction.stress.major'),
|
||||
minor: stressDamageReductionRule('DAGGERHEART.GENERAL.Rules.damageReduction.stress.minor'),
|
||||
any: stressDamageReductionRule('DAGGERHEART.GENERAL.Rules.damageReduction.stress.any')
|
||||
}),
|
||||
increasePerArmorMark: new fields.NumberField({
|
||||
integer: true,
|
||||
initial: 1,
|
||||
label: 'DAGGERHEART.GENERAL.Rules.damageReduction.maxArmorMarkedBonus'
|
||||
label: 'DAGGERHEART.GENERAL.Rules.damageReduction.increasePerArmorMark.label',
|
||||
hint: 'DAGGERHEART.GENERAL.Rules.damageReduction.increasePerArmorMark.hint'
|
||||
}),
|
||||
stressExtra: new fields.NumberField({
|
||||
required: true,
|
||||
integer: true,
|
||||
initial: 0,
|
||||
label: 'DAGGERHEART.GENERAL.Rules.damageReduction.maxArmorMarkedStress.label',
|
||||
hint: 'DAGGERHEART.GENERAL.Rules.damageReduction.maxArmorMarkedStress.hint'
|
||||
})
|
||||
}),
|
||||
stressDamageReduction: new fields.SchemaField({
|
||||
severe: stressDamageReductionRule('DAGGERHEART.GENERAL.Rules.damageReduction.stress.severe'),
|
||||
major: stressDamageReductionRule('DAGGERHEART.GENERAL.Rules.damageReduction.stress.major'),
|
||||
minor: stressDamageReductionRule('DAGGERHEART.GENERAL.Rules.damageReduction.stress.minor'),
|
||||
any: stressDamageReductionRule('DAGGERHEART.GENERAL.Rules.damageReduction.stress.any')
|
||||
}),
|
||||
increasePerArmorMark: new fields.NumberField({
|
||||
integer: true,
|
||||
initial: 1,
|
||||
label: 'DAGGERHEART.GENERAL.Rules.damageReduction.increasePerArmorMark.label',
|
||||
hint: 'DAGGERHEART.GENERAL.Rules.damageReduction.increasePerArmorMark.hint'
|
||||
}),
|
||||
magical: new fields.BooleanField({ initial: false }),
|
||||
physical: new fields.BooleanField({ initial: false }),
|
||||
thresholdImmunities: new fields.SchemaField({
|
||||
minor: new fields.BooleanField({ initial: false })
|
||||
}),
|
||||
reduceSeverity: new fields.SchemaField({
|
||||
magical: new fields.NumberField({ initial: 0, min: 0 }),
|
||||
physical: new fields.NumberField({ initial: 0, min: 0 })
|
||||
}),
|
||||
disabledArmor: new fields.BooleanField({ intial: false })
|
||||
disabledArmor: new fields.BooleanField({ intial: false })
|
||||
}
|
||||
}),
|
||||
attack: new fields.SchemaField({
|
||||
damage: new fields.SchemaField({
|
||||
|
|
@ -283,11 +280,6 @@ export default class DhCharacter extends BaseDataActor {
|
|||
})
|
||||
})
|
||||
}),
|
||||
conditionImmunities: new fields.SchemaField({
|
||||
hidden: new fields.BooleanField({ initial: false }),
|
||||
restrained: new fields.BooleanField({ initial: false }),
|
||||
vulnerable: new fields.BooleanField({ initial: false })
|
||||
}),
|
||||
runeWard: new fields.BooleanField({ initial: false }),
|
||||
burden: new fields.SchemaField({
|
||||
ignore: new fields.BooleanField()
|
||||
|
|
@ -453,8 +445,7 @@ export default class DhCharacter extends BaseDataActor {
|
|||
|
||||
if (
|
||||
item.system.identifier === CONFIG.DH.ITEM.featureSubTypes.foundation ||
|
||||
(item.system.identifier === CONFIG.DH.ITEM.featureSubTypes.specialization &&
|
||||
subclassState >= 2) ||
|
||||
(item.system.identifier === CONFIG.DH.ITEM.featureSubTypes.specialization && subclassState >= 2) ||
|
||||
(item.system.identifier === CONFIG.DH.ITEM.featureSubTypes.mastery && subclassState >= 3)
|
||||
) {
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ export default class BeastformField extends fields.SchemaField {
|
|||
* @returns
|
||||
*/
|
||||
static async transform(selectedForm, evolvedData, hybridData) {
|
||||
const formData = evolvedData?.form ? evolvedData.form.toObject() : selectedForm;
|
||||
const formData = evolvedData?.form ?? selectedForm;
|
||||
const beastformEffect = formData.effects.find(x => x.type === 'beastform');
|
||||
if (!beastformEffect) {
|
||||
ui.notifications.error('DAGGERHEART.UI.Notifications.beastformMissingEffect');
|
||||
|
|
|
|||
|
|
@ -25,9 +25,12 @@ export default class TargetField extends fields.SchemaField {
|
|||
config.hasTarget = true;
|
||||
let targets;
|
||||
// If the Action is configured as self-targeted, set targets as the owner. Probably better way than to fallback to getDependentTokens
|
||||
if (this.target?.type === CONFIG.DH.GENERAL.targetTypes.self.id)
|
||||
if (this.target?.type === CONFIG.DH.GENERAL.targetTypes.self.id) {
|
||||
targets = [this.actor.token ?? this.actor.prototypeToken];
|
||||
else {
|
||||
} else if (config.targetUuid) {
|
||||
const actor = fromUuidSync(config.targetUuid);
|
||||
targets = [actor.token ?? actor.prototypeToken];
|
||||
} else {
|
||||
targets = Array.from(game.user.targets);
|
||||
if (this.target.type !== CONFIG.DH.GENERAL.targetTypes.any.id) {
|
||||
targets = targets.filter(target => TargetField.isTargetFriendly(this.actor, target, this.target.type));
|
||||
|
|
|
|||
|
|
@ -273,12 +273,17 @@ export function ActionMixin(Base) {
|
|||
itemOrigin: this.item,
|
||||
description: this.description || (this.item instanceof Item ? this.item.system.description : '')
|
||||
};
|
||||
|
||||
const speaker = cls.getSpeaker();
|
||||
const msg = {
|
||||
type: 'abilityUse',
|
||||
user: game.user.id,
|
||||
actor: { name: this.actor.name, img: this.actor.img },
|
||||
author: this.author,
|
||||
speaker: cls.getSpeaker(),
|
||||
speaker: {
|
||||
speaker,
|
||||
actor: speaker.actor ?? this.actor
|
||||
},
|
||||
title: game.i18n.localize('DAGGERHEART.UI.Chat.action.title'),
|
||||
system: systemData,
|
||||
content: await foundry.applications.handlebars.renderTemplate(
|
||||
|
|
|
|||
|
|
@ -218,12 +218,20 @@ export default class DHBeastform extends BaseDataItem {
|
|||
}
|
||||
};
|
||||
const tokenUpdate = token => {
|
||||
const { x, y } = game.system.api.documents.DhToken.getSnappedPositionInSquareGrid(
|
||||
token.object.scene.grid,
|
||||
{ x: token.x, y: token.y, elevation: token.elevation },
|
||||
width ?? token.width,
|
||||
height ?? token.height
|
||||
);
|
||||
let x = null,
|
||||
y = null;
|
||||
if (token.object?.scene?.grid) {
|
||||
const positionData = game.system.api.documents.DhToken.getSnappedPositionInSquareGrid(
|
||||
token.object.scene.grid,
|
||||
{ x: token.x, y: token.y, elevation: token.elevation },
|
||||
width ?? token.width,
|
||||
height ?? token.height
|
||||
);
|
||||
|
||||
x = positionData.x;
|
||||
y = positionData.y;
|
||||
}
|
||||
|
||||
return {
|
||||
...prototypeTokenUpdate,
|
||||
x,
|
||||
|
|
|
|||
|
|
@ -298,7 +298,7 @@ export default class DualityRoll extends D20Roll {
|
|||
|
||||
if (looseSpotlight && game.combat?.active) {
|
||||
const currentCombatant = game.combat.combatants.get(game.combat.current?.combatantId);
|
||||
if (currentCombatant?.actorId == actor.id) ui.combat.setCombatantSpotlight(currentCombatant.id);
|
||||
if (currentCombatant?.actorId == config.data.id) ui.combat.setCombatantSpotlight(currentCombatant.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { emitAsGM, GMUpdateEvent } from '../systemRegistration/socket.mjs';
|
||||
import { LevelOptionType } from '../data/levelTier.mjs';
|
||||
import DHFeature from '../data/item/feature.mjs';
|
||||
import { createScrollText, damageKeyToNumber } from '../helpers/utils.mjs';
|
||||
import { createScrollText, damageKeyToNumber, getDamageKey } from '../helpers/utils.mjs';
|
||||
import DhCompanionLevelUp from '../applications/levelup/companionLevelup.mjs';
|
||||
import { ResourceUpdateMap } from '../data/action/baseAction.mjs';
|
||||
|
||||
|
|
@ -539,7 +539,11 @@ export default class DhpActor extends Actor {
|
|||
|
||||
/**@inheritdoc */
|
||||
getRollData() {
|
||||
const rollData = super.getRollData().clone();
|
||||
const rollData = foundry.utils.deepClone(super.getRollData());
|
||||
/* system gets repeated infinately which causes issues when trying to use the data for document creation */
|
||||
delete rollData.system;
|
||||
|
||||
rollData.id = this.id;
|
||||
rollData.name = this.name;
|
||||
rollData.system = this.system.getRollData();
|
||||
rollData.prof = this.system.proficiency ?? 1;
|
||||
|
|
@ -627,6 +631,19 @@ export default class DhpActor extends Actor {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (this.type === 'adversary') {
|
||||
const reducedSeverity = hpDamage.damageTypes.reduce((value, curr) => {
|
||||
return Math.max(this.system.rules.damageReduction.reduceSeverity[curr], value);
|
||||
}, 0);
|
||||
hpDamage.value = Math.max(hpDamage.value - reducedSeverity, 0);
|
||||
|
||||
if (
|
||||
hpDamage.value &&
|
||||
this.system.rules.damageReduction.thresholdImmunities[getDamageKey(hpDamage.value)]
|
||||
) {
|
||||
hpDamage.value -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updates.forEach(
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ export const tagifyElement = (element, baseOptions, onChange, tagifyOptions = {}
|
|||
spellcheck='false'
|
||||
tabIndex="${this.settings.a11y.focusableTags ? 0 : -1}"
|
||||
class="${this.settings.classNames.tag} ${tagData.class ? tagData.class : ''}"
|
||||
data-tooltip="${tagData.description || tagData.name}"
|
||||
data-tooltip="${tagData.description ? htmlToText(tagData.description) : tagData.name}"
|
||||
${this.getAttributes(tagData)}>
|
||||
<x class="${this.settings.classNames.tagX}" role='button' aria-label='remove tag'></x>
|
||||
<div>
|
||||
|
|
@ -198,7 +198,7 @@ foundry.dice.terms.Die.prototype.selfCorrecting = function (modifier) {
|
|||
};
|
||||
|
||||
export const getDamageKey = damage => {
|
||||
return ['none', 'minor', 'major', 'severe', 'massive','any'][damage];
|
||||
return ['none', 'minor', 'major', 'severe', 'massive', 'any'][damage];
|
||||
};
|
||||
|
||||
export const getDamageLabel = damage => {
|
||||
|
|
@ -474,3 +474,10 @@ export async function getCritDamageBonus(formula) {
|
|||
const critRoll = new Roll(formula);
|
||||
return critRoll.dice.reduce((acc, dice) => acc + dice.faces * dice.number, 0);
|
||||
}
|
||||
|
||||
export function htmlToText(html) {
|
||||
var tempDivElement = document.createElement('div');
|
||||
tempDivElement.innerHTML = html;
|
||||
|
||||
return tempDivElement.textContent || tempDivElement.innerText || '';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -284,7 +284,7 @@
|
|||
"key": "system.bonuses.roll.attack.bonus",
|
||||
"mode": 2,
|
||||
"value": "ITEM.@system.resource.value",
|
||||
"priority": null
|
||||
"priority": 21
|
||||
}
|
||||
],
|
||||
"disabled": false,
|
||||
|
|
|
|||
|
|
@ -36,13 +36,13 @@
|
|||
"key": "system.damageThresholds.major",
|
||||
"mode": 2,
|
||||
"value": "@prof",
|
||||
"priority": null
|
||||
"priority": 21
|
||||
},
|
||||
{
|
||||
"key": "system.damageThresholds.severe",
|
||||
"mode": 2,
|
||||
"value": "@prof",
|
||||
"priority": null
|
||||
"priority": 21
|
||||
}
|
||||
],
|
||||
"disabled": false,
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@
|
|||
"key": "system.resistance.physical.reduction",
|
||||
"mode": 2,
|
||||
"value": "@system.armorScore",
|
||||
"priority": null
|
||||
"priority": 21
|
||||
}
|
||||
],
|
||||
"disabled": false,
|
||||
|
|
|
|||
|
|
@ -38,13 +38,13 @@
|
|||
"key": "system.bonuses.damage.primaryWeapon.bonus",
|
||||
"mode": 2,
|
||||
"value": "@system.traits.strength.value",
|
||||
"priority": null
|
||||
"priority": 21
|
||||
},
|
||||
{
|
||||
"key": "system.bonuses.damage.secondaryWeapon.bonus",
|
||||
"mode": 2,
|
||||
"value": "@system.traits.strength.value",
|
||||
"priority": null
|
||||
"priority": 21
|
||||
}
|
||||
],
|
||||
"disabled": false,
|
||||
|
|
@ -57,7 +57,7 @@
|
|||
"startRound": null,
|
||||
"startTurn": null
|
||||
},
|
||||
"description": "<p><span style=\"color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.376);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;display:inline !important;float:none\">On a successful attack using a weapon with a </span><span class=\"tooltip-convert\" style=\"box-sizing:border-box;scrollbar-width:thin;scrollbar-color:rgb(93, 20, 43) rgba(0, 0, 0, 0);color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.376);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial\">Melee</span><span style=\"color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.376);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;display:inline !important;float:none\"> range, gain a bonus to your damage roll equal to your </span><span class=\"tooltip-convert\" style=\"box-sizing:border-box;scrollbar-width:thin;scrollbar-color:rgb(93, 20, 43) rgba(0, 0, 0, 0);color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.376);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial\">Strength</span><span style=\"color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.376);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;display:inline !important;float:none\">.</p>",
|
||||
"description": "<p><span style=\"color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.376);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;display:inline !important;float:none\">On a successful attack using a weapon with a </span><span class=\"tooltip-convert\" style=\"box-sizing:border-box;scrollbar-width:thin;scrollbar-color:rgb(93, 20, 43) rgba(0, 0, 0, 0);color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.376);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial\">Melee</span><span style=\"color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.376);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;display:inline !important;float:none\"> range, gain a bonus to your damage roll equal to your </span><span class=\"tooltip-convert\" style=\"box-sizing:border-box;scrollbar-width:thin;scrollbar-color:rgb(93, 20, 43) rgba(0, 0, 0, 0);color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.376);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial\">Strength</span><span style=\"color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.376);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;display:inline !important;float:none\">.</span></p>",
|
||||
"origin": null,
|
||||
"tint": "#ffffff",
|
||||
"transfer": true,
|
||||
|
|
|
|||
|
|
@ -37,13 +37,13 @@
|
|||
"key": "system.bonuses.damage.primaryWeapon.bonus",
|
||||
"mode": 2,
|
||||
"value": "@system.traits.agility.value",
|
||||
"priority": null
|
||||
"priority": 21
|
||||
},
|
||||
{
|
||||
"key": "system.bonuses.damage.secondaryWeapon.bonus",
|
||||
"mode": 2,
|
||||
"value": "@system.traits.agility.value",
|
||||
"priority": null
|
||||
"priority": 21
|
||||
}
|
||||
],
|
||||
"disabled": true,
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@
|
|||
"key": "system.traits.presence.value",
|
||||
"mode": 5,
|
||||
"value": "@cast",
|
||||
"priority": null
|
||||
"priority": 51
|
||||
}
|
||||
],
|
||||
"disabled": false,
|
||||
|
|
|
|||
|
|
@ -113,13 +113,13 @@
|
|||
"key": "system.bonuses.damage.magical.bonus",
|
||||
"mode": 2,
|
||||
"value": "2*@system.traits.strength.value",
|
||||
"priority": null
|
||||
"priority": 21
|
||||
},
|
||||
{
|
||||
"key": "system.bonuses.damage.physical.bonus",
|
||||
"mode": 2,
|
||||
"value": "2*@system.traits.strength.value",
|
||||
"priority": null
|
||||
"priority": 21
|
||||
}
|
||||
],
|
||||
"disabled": false,
|
||||
|
|
@ -162,13 +162,13 @@
|
|||
"key": "system.bonuses.damage.magical.bonus",
|
||||
"mode": 2,
|
||||
"value": "4*@system.traits.strength.value",
|
||||
"priority": null
|
||||
"priority": 21
|
||||
},
|
||||
{
|
||||
"key": "system.bonuses.damage.physical.bonus",
|
||||
"mode": 2,
|
||||
"value": "4*@system.traits.strength.value",
|
||||
"priority": null
|
||||
"priority": 21
|
||||
}
|
||||
],
|
||||
"disabled": false,
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@
|
|||
"key": "system.damageThresholds.severe",
|
||||
"mode": 2,
|
||||
"value": "@system.proficiency",
|
||||
"priority": null
|
||||
"priority": 21
|
||||
}
|
||||
],
|
||||
"disabled": false,
|
||||
|
|
@ -119,7 +119,7 @@
|
|||
"startRound": null,
|
||||
"startTurn": null
|
||||
},
|
||||
"description": "<p><span style=\"color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.376);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;display:inline !important;float:none\">Gain a bonus to your </span><span class=\"tooltip-convert\" style=\"box-sizing:border-box;scrollbar-width:thin;scrollbar-color:rgb(93, 20, 43) rgba(0, 0, 0, 0);color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.376);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial\">Severe </span><span style=\"color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.376);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;display:inline !important;float:none\">threshold equal to your </span><span class=\"tooltip-convert\" style=\"box-sizing:border-box;scrollbar-width:thin;scrollbar-color:rgb(93, 20, 43) rgba(0, 0, 0, 0);color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.376);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial\">Proficiency</span><span style=\"color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.376);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;display:inline !important;float:none\">.</p>",
|
||||
"description": "<p><span style=\"color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.376);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;display:inline !important;float:none\">Gain a bonus to your </span><span class=\"tooltip-convert\" style=\"box-sizing:border-box;scrollbar-width:thin;scrollbar-color:rgb(93, 20, 43) rgba(0, 0, 0, 0);color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.376);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial\">Severe </span><span style=\"color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.376);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;display:inline !important;float:none\">threshold equal to your </span><span class=\"tooltip-convert\" style=\"box-sizing:border-box;scrollbar-width:thin;scrollbar-color:rgb(93, 20, 43) rgba(0, 0, 0, 0);color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.376);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial\">Proficiency</span><span style=\"color:rgb(239, 230, 216);font-family:Montserrat, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:rgba(24, 22, 46, 0.376);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;display:inline !important;float:none\">.</span></p>",
|
||||
"origin": null,
|
||||
"tint": "#ffffff",
|
||||
"transfer": true,
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
"key": "system.evasion",
|
||||
"mode": 2,
|
||||
"value": "ceil(@system.traits.agility.value / 2)",
|
||||
"priority": null
|
||||
"priority": 21
|
||||
}
|
||||
],
|
||||
"disabled": false,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"type": "domainCard",
|
||||
"folder": "OwsbTSWzKq2WJmQN",
|
||||
"system": {
|
||||
"description": "<p class=\"Body-Foundation\">Make a <strong>Spellcast Roll (16)</strong>. Once per long rest on a success, choose a point within Far range and create a visible zone of protection there for all allies within Very Close range of that point. When you do, place a <strong>d6</strong> on this card with the 1 value facing up. When an ally in this zone takes damage, they reduce it by the die’s value. You then increase the die’s value by one. When the die’s value would exceed 6, this effect ends.</p><p><span style=\"color:oklab(0.952331 0.000418991 -0.00125992);font-family:'gg mono', 'Source Code Pro', Consolas, 'Andale Mono WT', 'Andale Mono', 'Lucida Console', 'Lucida Sans Typewriter', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Liberation Mono', 'Nimbus Mono L', Monaco, 'Courier New', Courier, monospace;font-size:13.6px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:left;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:pre-wrap;background-color:oklab(0.57738 0.0140701 -0.208587 / 0.0784314);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;display:inline !important;float:none\">@Template[type:emanation|range:vc]</p>",
|
||||
"description": "<p class=\"Body-Foundation\">Make a <strong>Spellcast Roll (16)</strong>. Once per long rest on a success, choose a point within Far range and create a visible zone of protection there for all allies within Very Close range of that point. When you do, place a <strong>d6</strong> on this card with the 1 value facing up. When an ally in this zone takes damage, they reduce it by the die’s value. You then increase the die’s value by one. When the die’s value would exceed 6, this effect ends.</p><p>@Template[type:emanation|range:vc]</p>",
|
||||
"domain": "splendor",
|
||||
"recallCost": 2,
|
||||
"level": 6,
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
"key": "system.armorScore",
|
||||
"mode": 2,
|
||||
"value": "@system.traits.strength.value",
|
||||
"priority": null
|
||||
"priority": 21
|
||||
}
|
||||
],
|
||||
"disabled": false,
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@
|
|||
{
|
||||
"key": "system.resistance.magical.reduction",
|
||||
"mode": 2,
|
||||
"value": "@system.armorScore"
|
||||
"value": "@system.armorScore",
|
||||
"priority": 21
|
||||
}
|
||||
],
|
||||
"_id": "xGxqTCO8MjNq5Cw6",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"_id": "y4c1jrlHrf0wBWOq",
|
||||
"img": "icons/magic/light/projectiles-star-purple.webp",
|
||||
"system": {
|
||||
"description": "<p>You can use this stardrop to summon a hailstorm of comets that deals 8d20 physical damage to all targets within Very Far range.</p><p>@Template[type:emanation|range:vf]</p>",
|
||||
"description": "<p>You can use this stardrop to summon a hailstorm of comets that deals 8d20 physical damage to all targets within Very Far range.</p>",
|
||||
"quantity": 1,
|
||||
"actions": {
|
||||
"pt5U6hlyx4T7MUOa": {
|
||||
|
|
|
|||
|
|
@ -155,7 +155,8 @@
|
|||
{
|
||||
"key": "system.evasion",
|
||||
"mode": 2,
|
||||
"value": "@system.armorScore"
|
||||
"value": "@system.armorScore",
|
||||
"priority": 21
|
||||
}
|
||||
],
|
||||
"transfer": false,
|
||||
|
|
|
|||
|
|
@ -117,7 +117,8 @@
|
|||
{
|
||||
"key": "system.bonuses.damage.primaryWeapon.bonus",
|
||||
"mode": 2,
|
||||
"value": "@system.traits.agility.value"
|
||||
"value": "@system.traits.agility.value",
|
||||
"priority": 21
|
||||
}
|
||||
],
|
||||
"_id": "jMIrOhpPUncn7dWg",
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
1519
src/packs/rolltables/tables_Consumables_tF04P02yVN1YDVel.json
Normal file
1519
src/packs/rolltables/tables_Consumables_tF04P02yVN1YDVel.json
Normal file
File diff suppressed because it is too large
Load diff
1519
src/packs/rolltables/tables_Loot_S61Shlt2I5CbLRjz.json
Normal file
1519
src/packs/rolltables/tables_Loot_S61Shlt2I5CbLRjz.json
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,319 @@
|
|||
{
|
||||
"name": "Table of Random Objectives",
|
||||
"img": "icons/sundries/documents/document-torn-diagram-tan.webp",
|
||||
"description": "<p>Layering Goals Other than Attrition into Combat</p>",
|
||||
"results": [
|
||||
{
|
||||
"type": "text",
|
||||
"weight": 1,
|
||||
"range": [
|
||||
1,
|
||||
1
|
||||
],
|
||||
"_id": "LDuVbmdvhJiEOe7U",
|
||||
"name": "",
|
||||
"img": "icons/svg/d12-grey.svg",
|
||||
"description": "<p>Acquire (obtain or steal) an important item or items.</p>",
|
||||
"drawn": false,
|
||||
"flags": {},
|
||||
"_stats": {
|
||||
"compendiumSource": null,
|
||||
"duplicateSource": null,
|
||||
"exportSource": null,
|
||||
"coreVersion": "13.351",
|
||||
"systemId": "daggerheart",
|
||||
"systemVersion": "1.4.4",
|
||||
"lastModifiedBy": null
|
||||
},
|
||||
"documentUuid": null,
|
||||
"_key": "!tables.results!I5L1dlgxXTNrCCkL.LDuVbmdvhJiEOe7U"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"weight": 1,
|
||||
"range": [
|
||||
2,
|
||||
2
|
||||
],
|
||||
"_id": "FxYpST4nQUTBp1mN",
|
||||
"name": "",
|
||||
"img": "icons/svg/d12-grey.svg",
|
||||
"description": "<p>Capture one or more of the opponents.</p>",
|
||||
"drawn": false,
|
||||
"flags": {},
|
||||
"_stats": {
|
||||
"compendiumSource": null,
|
||||
"duplicateSource": null,
|
||||
"exportSource": null,
|
||||
"coreVersion": "13.351",
|
||||
"systemId": "daggerheart",
|
||||
"systemVersion": "1.4.4",
|
||||
"lastModifiedBy": null
|
||||
},
|
||||
"documentUuid": null,
|
||||
"_key": "!tables.results!I5L1dlgxXTNrCCkL.FxYpST4nQUTBp1mN"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"weight": 1,
|
||||
"range": [
|
||||
3,
|
||||
3
|
||||
],
|
||||
"_id": "bTkZgxqEr4lNxzeK",
|
||||
"name": "",
|
||||
"img": "icons/svg/d12-grey.svg",
|
||||
"description": "<p>Activate a magical device.</p>",
|
||||
"drawn": false,
|
||||
"flags": {},
|
||||
"_stats": {
|
||||
"compendiumSource": null,
|
||||
"duplicateSource": null,
|
||||
"exportSource": null,
|
||||
"coreVersion": "13.351",
|
||||
"systemId": "daggerheart",
|
||||
"systemVersion": "1.4.4",
|
||||
"lastModifiedBy": null
|
||||
},
|
||||
"documentUuid": null,
|
||||
"_key": "!tables.results!I5L1dlgxXTNrCCkL.bTkZgxqEr4lNxzeK"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"weight": 1,
|
||||
"range": [
|
||||
4,
|
||||
4
|
||||
],
|
||||
"_id": "T39LgOL1cw5AIY59",
|
||||
"name": "",
|
||||
"img": "icons/svg/d12-grey.svg",
|
||||
"description": "<p>Frame a character or tarnish their reputation.</p>",
|
||||
"drawn": false,
|
||||
"flags": {},
|
||||
"_stats": {
|
||||
"compendiumSource": null,
|
||||
"duplicateSource": null,
|
||||
"exportSource": null,
|
||||
"coreVersion": "13.351",
|
||||
"systemId": "daggerheart",
|
||||
"systemVersion": "1.4.4",
|
||||
"lastModifiedBy": null
|
||||
},
|
||||
"documentUuid": null,
|
||||
"_key": "!tables.results!I5L1dlgxXTNrCCkL.T39LgOL1cw5AIY59"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"weight": 1,
|
||||
"range": [
|
||||
5,
|
||||
5
|
||||
],
|
||||
"_id": "MHgv8dlrwA3ZmBKq",
|
||||
"name": "",
|
||||
"img": "icons/svg/d12-grey.svg",
|
||||
"description": "<p>Drive the opponent into a corner or ambush point.</p>",
|
||||
"drawn": false,
|
||||
"flags": {},
|
||||
"_stats": {
|
||||
"compendiumSource": null,
|
||||
"duplicateSource": null,
|
||||
"exportSource": null,
|
||||
"coreVersion": "13.351",
|
||||
"systemId": "daggerheart",
|
||||
"systemVersion": "1.4.4",
|
||||
"lastModifiedBy": null
|
||||
},
|
||||
"documentUuid": null,
|
||||
"_key": "!tables.results!I5L1dlgxXTNrCCkL.MHgv8dlrwA3ZmBKq"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"weight": 1,
|
||||
"range": [
|
||||
6,
|
||||
6
|
||||
],
|
||||
"_id": "4USCNNavzVvBqldn",
|
||||
"name": "",
|
||||
"img": "icons/svg/d12-grey.svg",
|
||||
"description": "<p>Stop a magical ritual, legal ceremony, or time-sensitive spell.</p>",
|
||||
"drawn": false,
|
||||
"flags": {},
|
||||
"_stats": {
|
||||
"compendiumSource": null,
|
||||
"duplicateSource": null,
|
||||
"exportSource": null,
|
||||
"coreVersion": "13.351",
|
||||
"systemId": "daggerheart",
|
||||
"systemVersion": "1.4.4",
|
||||
"lastModifiedBy": null
|
||||
},
|
||||
"documentUuid": null,
|
||||
"_key": "!tables.results!I5L1dlgxXTNrCCkL.4USCNNavzVvBqldn"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"weight": 1,
|
||||
"range": [
|
||||
7,
|
||||
7
|
||||
],
|
||||
"_id": "gwZnWTauHsbb6rsr",
|
||||
"name": "",
|
||||
"img": "icons/svg/d12-grey.svg",
|
||||
"description": "<p>Hold the line—keep the enemy from reaching a specific area or group.</p>",
|
||||
"drawn": false,
|
||||
"flags": {},
|
||||
"_stats": {
|
||||
"compendiumSource": null,
|
||||
"duplicateSource": null,
|
||||
"exportSource": null,
|
||||
"coreVersion": "13.351",
|
||||
"systemId": "daggerheart",
|
||||
"systemVersion": "1.4.4",
|
||||
"lastModifiedBy": null
|
||||
},
|
||||
"documentUuid": null,
|
||||
"_key": "!tables.results!I5L1dlgxXTNrCCkL.gwZnWTauHsbb6rsr"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"weight": 1,
|
||||
"range": [
|
||||
8,
|
||||
8
|
||||
],
|
||||
"_id": "beDIxxPyCCVa8nlE",
|
||||
"name": "",
|
||||
"img": "icons/svg/d12-grey.svg",
|
||||
"description": "<p>Plant evidence or a tracking device on a target.</p>",
|
||||
"drawn": false,
|
||||
"flags": {},
|
||||
"_stats": {
|
||||
"compendiumSource": null,
|
||||
"duplicateSource": null,
|
||||
"exportSource": null,
|
||||
"coreVersion": "13.351",
|
||||
"systemId": "daggerheart",
|
||||
"systemVersion": "1.4.4",
|
||||
"lastModifiedBy": null
|
||||
},
|
||||
"documentUuid": null,
|
||||
"_key": "!tables.results!I5L1dlgxXTNrCCkL.beDIxxPyCCVa8nlE"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"weight": 1,
|
||||
"range": [
|
||||
9,
|
||||
9
|
||||
],
|
||||
"_id": "C70V6prVmZd5VRV8",
|
||||
"name": "",
|
||||
"img": "icons/svg/d12-grey.svg",
|
||||
"description": "<p>Secure a specific location ahead of another group’s arrival.</p>",
|
||||
"drawn": false,
|
||||
"flags": {},
|
||||
"_stats": {
|
||||
"compendiumSource": null,
|
||||
"duplicateSource": null,
|
||||
"exportSource": null,
|
||||
"coreVersion": "13.351",
|
||||
"systemId": "daggerheart",
|
||||
"systemVersion": "1.4.4",
|
||||
"lastModifiedBy": null
|
||||
},
|
||||
"documentUuid": null,
|
||||
"_key": "!tables.results!I5L1dlgxXTNrCCkL.C70V6prVmZd5VRV8"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"weight": 1,
|
||||
"range": [
|
||||
10,
|
||||
10
|
||||
],
|
||||
"_id": "i02rh05CvhHlKJCN",
|
||||
"name": "",
|
||||
"img": "icons/svg/d12-grey.svg",
|
||||
"description": "<p>Harass the opponent to deplete their resources or keep them occupied.</p>",
|
||||
"drawn": false,
|
||||
"flags": {},
|
||||
"_stats": {
|
||||
"compendiumSource": null,
|
||||
"duplicateSource": null,
|
||||
"exportSource": null,
|
||||
"coreVersion": "13.351",
|
||||
"systemId": "daggerheart",
|
||||
"systemVersion": "1.4.4",
|
||||
"lastModifiedBy": null
|
||||
},
|
||||
"documentUuid": null,
|
||||
"_key": "!tables.results!I5L1dlgxXTNrCCkL.i02rh05CvhHlKJCN"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"weight": 1,
|
||||
"range": [
|
||||
11,
|
||||
11
|
||||
],
|
||||
"_id": "AbNgD5GCbWuui9oP",
|
||||
"name": "",
|
||||
"img": "icons/svg/d12-grey.svg",
|
||||
"description": "<p>Destroy a piece of architecture, a statue, a shrine, or a weapon.</p>",
|
||||
"drawn": false,
|
||||
"flags": {},
|
||||
"_stats": {
|
||||
"compendiumSource": null,
|
||||
"duplicateSource": null,
|
||||
"exportSource": null,
|
||||
"coreVersion": "13.351",
|
||||
"systemId": "daggerheart",
|
||||
"systemVersion": "1.4.4",
|
||||
"lastModifiedBy": null
|
||||
},
|
||||
"documentUuid": null,
|
||||
"_key": "!tables.results!I5L1dlgxXTNrCCkL.AbNgD5GCbWuui9oP"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"weight": 1,
|
||||
"range": [
|
||||
12,
|
||||
12
|
||||
],
|
||||
"_id": "TCrdyh3qhl2vtQxO",
|
||||
"name": "",
|
||||
"img": "icons/svg/d12-grey.svg",
|
||||
"description": "<p>Investigate a situation to confirm or deny existing information.</p>",
|
||||
"drawn": false,
|
||||
"flags": {},
|
||||
"_stats": {
|
||||
"compendiumSource": null,
|
||||
"duplicateSource": null,
|
||||
"exportSource": null,
|
||||
"coreVersion": "13.351",
|
||||
"systemId": "daggerheart",
|
||||
"systemVersion": "1.4.4",
|
||||
"lastModifiedBy": null
|
||||
},
|
||||
"documentUuid": null,
|
||||
"_key": "!tables.results!I5L1dlgxXTNrCCkL.TCrdyh3qhl2vtQxO"
|
||||
}
|
||||
],
|
||||
"replacement": true,
|
||||
"displayRoll": true,
|
||||
"folder": null,
|
||||
"ownership": {
|
||||
"default": 0,
|
||||
"Bgvu4A6AMkRFOTGR": 3
|
||||
},
|
||||
"flags": {},
|
||||
"formula": "1d12",
|
||||
"_id": "I5L1dlgxXTNrCCkL",
|
||||
"sort": 400000,
|
||||
"_key": "!tables!I5L1dlgxXTNrCCkL"
|
||||
}
|
||||
|
|
@ -35,7 +35,7 @@
|
|||
"key": "system.evasion",
|
||||
"mode": 2,
|
||||
"value": "@system.proficiency",
|
||||
"priority": null
|
||||
"priority": 21
|
||||
}
|
||||
],
|
||||
"disabled": false,
|
||||
|
|
|
|||
|
|
@ -255,13 +255,13 @@
|
|||
"key": "system.damageThresholds.major",
|
||||
"mode": 2,
|
||||
"value": "@system.proficiency",
|
||||
"priority": null
|
||||
"priority": 21
|
||||
},
|
||||
{
|
||||
"key": "system.damageThresholds.severe",
|
||||
"mode": 2,
|
||||
"value": "@system.proficiency",
|
||||
"priority": null
|
||||
"priority": 21
|
||||
}
|
||||
],
|
||||
"disabled": false,
|
||||
|
|
|
|||
|
|
@ -145,6 +145,11 @@
|
|||
|
||||
button {
|
||||
flex: 1;
|
||||
padding: 0 0.375rem;
|
||||
}
|
||||
|
||||
button[data-action='viewParty'] {
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -99,6 +99,28 @@
|
|||
}
|
||||
}
|
||||
|
||||
.action-use-button-parent {
|
||||
width: 100%;
|
||||
|
||||
.action-use-target {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 4px;
|
||||
width: 100%;
|
||||
padding: 4px 8px 10px 40px;
|
||||
font-size: var(--font-size-12);
|
||||
|
||||
label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
select {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.action-use-button {
|
||||
width: -webkit-fill-available;
|
||||
margin: 0 8px;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ aside[role='tooltip']:has(div.daggerheart.dh-style.tooltip.card-style) {
|
|||
width: 18rem;
|
||||
background-image: url('../assets/parchments/dh-parchment-dark.png');
|
||||
outline: 1px solid light-dark(@dark-80, @beige-80);
|
||||
box-shadow: 0 0 25px rgba(0, 0, 0, 0.80);
|
||||
box-shadow: 0 0 25px rgba(0, 0, 0, 0.8);
|
||||
|
||||
.tooltip-title {
|
||||
font-size: var(--font-size-20);
|
||||
|
|
@ -235,7 +235,6 @@ aside[role='tooltip'].locked-tooltip:has(div.daggerheart.dh-style.tooltip.card-s
|
|||
.theme-light aside[role='tooltip'].locked-tooltip:has(div.daggerheart.dh-style.tooltip) {
|
||||
box-shadow: 0 0 25px @dark-blue-90;
|
||||
outline: 1px solid light-dark(@dark-blue, @golden);
|
||||
|
||||
}
|
||||
|
||||
#tooltip,
|
||||
|
|
@ -344,4 +343,20 @@ aside[role='tooltip'].locked-tooltip:has(div.daggerheart.dh-style.tooltip.card-s
|
|||
margin-bottom: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.party-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
button {
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
img {
|
||||
border: none;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
13
system.json
13
system.json
|
|
@ -2,7 +2,7 @@
|
|||
"id": "daggerheart",
|
||||
"title": "Daggerheart",
|
||||
"description": "An unofficial implementation of the Daggerheart system",
|
||||
"version": "1.4.1",
|
||||
"version": "1.4.5",
|
||||
"compatibility": {
|
||||
"minimum": "13.346",
|
||||
"verified": "13.351",
|
||||
|
|
@ -173,6 +173,15 @@
|
|||
"private": false,
|
||||
"flags": {}
|
||||
},
|
||||
{
|
||||
"name": "rolltables",
|
||||
"label": "Rolltables",
|
||||
"system": "daggerheart",
|
||||
"path": "packs/rolltables.db",
|
||||
"type": "RollTable",
|
||||
"private": false,
|
||||
"flags": {}
|
||||
},
|
||||
{
|
||||
"name": "beastforms",
|
||||
"label": "Beastforms",
|
||||
|
|
@ -188,7 +197,7 @@
|
|||
"name": "Daggerheart SRD",
|
||||
"sorting": "m",
|
||||
"color": "#08718c",
|
||||
"packs": ["adversaries", "environments", "journals"],
|
||||
"packs": ["adversaries", "environments", "journals", "rolltables"],
|
||||
"folders": [
|
||||
{
|
||||
"name": "Character Options",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<section
|
||||
class="tab {{tabs.domains.cssClass}} {{tabs.domains.id}}"
|
||||
class="tab {{tabs.domains.cssClass}} {{tabs.domains.id}} scrollable"
|
||||
data-tab="{{tabs.domains.id}}"
|
||||
data-group="{{tabs.domains.group}}"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<section
|
||||
class="tab {{tabs.downtime.cssClass}} {{tabs.downtime.id}}"
|
||||
class="tab {{tabs.downtime.cssClass}} {{tabs.downtime.id}} scrollable"
|
||||
data-tab="{{tabs.downtime.id}}"
|
||||
data-group="{{tabs.downtime.group}}"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<section
|
||||
class="tab {{tabs.itemFeatures.cssClass}} {{tabs.itemFeatures.id}}"
|
||||
class="tab {{tabs.itemFeatures.cssClass}} {{tabs.itemFeatures.id}} scrollable"
|
||||
data-tab="{{tabs.itemFeatures.id}}"
|
||||
data-group="{{tabs.itemFeatures.group}}"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<section
|
||||
class="tab {{tabs.settings.cssClass}} {{tabs.settings.id}}"
|
||||
class="tab {{tabs.settings.cssClass}} {{tabs.settings.id}} scrollable"
|
||||
data-tab="{{tabs.settings.id}}"
|
||||
data-group="{{tabs.settings.group}}"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<section
|
||||
class="tab {{tabs.types.cssClass}} {{tabs.types.id}}"
|
||||
class="tab {{tabs.types.cssClass}} {{tabs.types.id}} scrollable"
|
||||
data-tab="{{tabs.types.id}}"
|
||||
data-group="{{tabs.types.group}}"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
<fieldset>
|
||||
<legend>{{localize tabs.features.label}}</legend>
|
||||
<ul class="feature-list">
|
||||
{{#each document.system.features as |feature|}}
|
||||
{{#each @root.features as |feature|}}
|
||||
<li class="feature-item" id="{{feature.id}}" draggable="true">
|
||||
<img src="{{feature.img}}" alt="">
|
||||
<div class="label">
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
<fieldset>
|
||||
<legend>{{localize tabs.features.label}}</legend>
|
||||
<ul class="feature-list">
|
||||
{{#each document.system.features as |feature|}}
|
||||
{{#each @root.features as |feature|}}
|
||||
<li class="feature-item" id="{{feature.id}}">
|
||||
<img src="{{feature.img}}" alt="">
|
||||
<div class="label">
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
{{> 'daggerheart.inventory-items'
|
||||
title=tabs.features.label
|
||||
type='feature'
|
||||
collection=document.system.features
|
||||
collection=@root.features
|
||||
hideContextMenu=true
|
||||
canCreate=true
|
||||
showActions=true
|
||||
|
|
|
|||
|
|
@ -87,11 +87,16 @@
|
|||
</div>
|
||||
{{/if}}
|
||||
<div class="downtime-section">
|
||||
<button type="button" data-action="useDowntime" data-type="shortRest" data-tooltip="{{localize "DAGGERHEART.APPLICATIONS.Downtime.shortRest.title"}}">
|
||||
<i class="fa-solid fa-utensils"></i>
|
||||
{{#if document.parties.size}}
|
||||
<button type="button" data-action="viewParty" data-tooltip="DAGGERHEART.ACTORS.Character.viewParty">
|
||||
<i class="fa-solid fa-fw fa-users"></i>
|
||||
</button>
|
||||
{{/if}}
|
||||
<button type="button" data-action="useDowntime" data-type="shortRest" data-tooltip="DAGGERHEART.APPLICATIONS.Downtime.shortRest.title">
|
||||
<i class="fa-solid fa-fw fa-utensils"></i>
|
||||
</button>
|
||||
<button type="button" data-action="useDowntime" data-type="longRest" data-tooltip="{{localize "DAGGERHEART.APPLICATIONS.Downtime.longRest.title"}}">
|
||||
<i class="fa-solid fa-bed"></i>
|
||||
<button type="button" data-action="useDowntime" data-type="longRest" data-tooltip="DAGGERHEART.APPLICATIONS.Downtime.longRest.title">
|
||||
<i class="fa-solid fa-fw fa-bed"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
{{> 'daggerheart.inventory-items'
|
||||
title=tabs.features.label
|
||||
type='feature'
|
||||
collection=document.system.features
|
||||
collection=@root.features
|
||||
hideContextMenu=true
|
||||
canCreate=true
|
||||
showActions=true
|
||||
|
|
|
|||
|
|
@ -15,9 +15,22 @@
|
|||
</div>
|
||||
</details>
|
||||
{{#each move.actions as | action index |}}
|
||||
<button class="action-use-button" data-move-index="{{@../key}}" data-action-index="{{index}}" data-move-path="{{../movePath}}" >
|
||||
<span>{{localize action.name}}</span>
|
||||
</button>
|
||||
<div class="action-use-button-parent">
|
||||
<button class="action-use-button" data-move-index="{{@../key}}" data-action-index="{{index}}" data-move-path="{{../movePath}}" >
|
||||
<span>{{localize action.name}}</span>
|
||||
</button>
|
||||
{{#if move.needsTarget}}
|
||||
<div class="action-use-target">
|
||||
<label>{{localize "DAGGERHEART.GENERAL.Bonuses.rest.target"}}:</label>
|
||||
<select>
|
||||
<option value="{{../../selfId}}">{{localize "DAGGERHEART.GENERAL.Bonuses.rest.targetSelf"}}</option>
|
||||
{{#each ../../characters as | character |}}
|
||||
<option value="{{character.uuid}}">{{character.name}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/each}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue