mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-04-21 15:03:37 +02:00
[Feature] Active Party (#1803)
This commit is contained in:
parent
8808e4646d
commit
7d5cdeb09d
12 changed files with 179 additions and 71 deletions
|
|
@ -236,6 +236,8 @@
|
||||||
},
|
},
|
||||||
"defaultHopeDice": "Default Hope Dice",
|
"defaultHopeDice": "Default Hope Dice",
|
||||||
"defaultFearDice": "Default Fear Dice",
|
"defaultFearDice": "Default Fear Dice",
|
||||||
|
"defaultAdvantageDice": "Default Advantage Dice",
|
||||||
|
"defaultDisadvantageDice": "Default Disadvantage Dice",
|
||||||
"disadvantageSources": {
|
"disadvantageSources": {
|
||||||
"label": "Disadvantage Sources",
|
"label": "Disadvantage Sources",
|
||||||
"hint": "Add single words or short text as reminders and hints of what a character has disadvantage on."
|
"hint": "Add single words or short text as reminders and hints of what a character has disadvantage on."
|
||||||
|
|
@ -3210,6 +3212,8 @@
|
||||||
"companion": "Level {level} - {partner}",
|
"companion": "Level {level} - {partner}",
|
||||||
"companionNoPartner": "No Partner",
|
"companionNoPartner": "No Partner",
|
||||||
"duplicateToNewTier": "Duplicate to New Tier",
|
"duplicateToNewTier": "Duplicate to New Tier",
|
||||||
|
"activateParty": "Make Active Party",
|
||||||
|
"partyIsActive": "Active",
|
||||||
"createAdversary": "Create Adversary",
|
"createAdversary": "Create Adversary",
|
||||||
"pickTierTitle": "Pick a new tier for this adversary"
|
"pickTierTitle": "Pick a new tier for this adversary"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,8 @@ export default class DhActorDirectory extends foundry.applications.sidebar.tabs.
|
||||||
|
|
||||||
_getEntryContextOptions() {
|
_getEntryContextOptions() {
|
||||||
const options = super._getEntryContextOptions();
|
const options = super._getEntryContextOptions();
|
||||||
options.push({
|
options.push(
|
||||||
|
{
|
||||||
name: 'DAGGERHEART.UI.Sidebar.actorDirectory.duplicateToNewTier',
|
name: 'DAGGERHEART.UI.Sidebar.actorDirectory.duplicateToNewTier',
|
||||||
icon: `<i class="fa-solid fa-arrow-trend-up" inert></i>`,
|
icon: `<i class="fa-solid fa-arrow-trend-up" inert></i>`,
|
||||||
condition: li => {
|
condition: li => {
|
||||||
|
|
@ -89,7 +90,23 @@ export default class DhActorDirectory extends foundry.applications.sidebar.tabs.
|
||||||
ui.notifications.info(`Tier ${tier} ${actor.name} created`);
|
ui.notifications.info(`Tier ${tier} ${actor.name} created`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
{
|
||||||
|
name: 'DAGGERHEART.UI.Sidebar.actorDirectory.activateParty',
|
||||||
|
icon: `<i class="fa-regular fa-square"></i>`,
|
||||||
|
condition: li => {
|
||||||
|
const actor = game.actors.get(li.dataset.entryId);
|
||||||
|
return actor && actor.type === 'party' && !actor.system.active;
|
||||||
|
},
|
||||||
|
callback: async li => {
|
||||||
|
const actor = game.actors.get(li.dataset.entryId);
|
||||||
|
if (!actor) throw new Error('Unexpected missing actor');
|
||||||
|
|
||||||
|
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.ActiveParty, actor.id);
|
||||||
|
ui.actors.render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,8 @@ export const gameSettings = {
|
||||||
LastMigrationVersion: 'LastMigrationVersion',
|
LastMigrationVersion: 'LastMigrationVersion',
|
||||||
SpotlightRequestQueue: 'SpotlightRequestQueue',
|
SpotlightRequestQueue: 'SpotlightRequestQueue',
|
||||||
CompendiumBrowserSettings: 'CompendiumBrowserSettings',
|
CompendiumBrowserSettings: 'CompendiumBrowserSettings',
|
||||||
SpotlightTracker: 'SpotlightTracker'
|
SpotlightTracker: 'SpotlightTracker',
|
||||||
|
ActiveParty: 'ActiveParty',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const actionAutomationChoices = {
|
export const actionAutomationChoices = {
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,10 @@ export default class DhParty extends BaseDataActor {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get active() {
|
||||||
|
return game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.ActiveParty) === this.parent.id;
|
||||||
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/**@inheritdoc */
|
/**@inheritdoc */
|
||||||
|
|
@ -40,6 +44,16 @@ export default class DhParty extends BaseDataActor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onCreate(data, options, userId) {
|
||||||
|
super._onCreate(data, options, userId);
|
||||||
|
|
||||||
|
if (game.user.isActiveGM && !game.actors.party) {
|
||||||
|
game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.ActiveParty, this.parent.id).then(_ => {
|
||||||
|
ui.actors.render();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_onDelete(options, userId) {
|
_onDelete(options, userId) {
|
||||||
super._onDelete(options, userId);
|
super._onDelete(options, userId);
|
||||||
|
|
||||||
|
|
@ -47,5 +61,11 @@ export default class DhParty extends BaseDataActor {
|
||||||
for (const member of this.partyMembers) {
|
for (const member of this.partyMembers) {
|
||||||
member?.parties?.delete(this.parent);
|
member?.parties?.delete(this.parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this *was* the active party, delete it. We can't use game.actors.party as this actor was already deleted
|
||||||
|
const isWorldActor = !this.parent?.parent && !this.parent.compendium;
|
||||||
|
const activePartyId = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.ActiveParty);
|
||||||
|
if (isWorldActor && this.id === activePartyId)
|
||||||
|
game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.ActiveParty, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { itemAbleRollParse } from '../../../helpers/utils.mjs';
|
||||||
import FormulaField from '../formulaField.mjs';
|
import FormulaField from '../formulaField.mjs';
|
||||||
|
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
|
|
@ -36,13 +37,12 @@ export default class DHSummonField extends fields.ArrayField {
|
||||||
const rolls = [];
|
const rolls = [];
|
||||||
const summonData = [];
|
const summonData = [];
|
||||||
for (const summon of this.summon) {
|
for (const summon of this.summon) {
|
||||||
let count = summon.count;
|
const roll = new Roll(itemAbleRollParse(summon.count, this.actor, this.item));
|
||||||
const roll = new Roll(summon.count);
|
|
||||||
if (!roll.isDeterministic) {
|
|
||||||
await roll.evaluate();
|
await roll.evaluate();
|
||||||
if (game.modules.get('dice-so-nice')?.active) rolls.push(roll);
|
const count = roll.total;
|
||||||
count = roll.total;
|
if (!roll.isDeterministic && game.modules.get('dice-so-nice')?.active)
|
||||||
}
|
rolls.push(roll);
|
||||||
|
|
||||||
|
|
||||||
const actor = await DHSummonField.getWorldActor(await foundry.utils.fromUuid(summon.actorUUID));
|
const actor = await DHSummonField.getWorldActor(await foundry.utils.fromUuid(summon.actorUUID));
|
||||||
/* Extending summon data in memory so it's available in actionField.toChat. Think it's harmless, but ugly. Could maybe find a better way. */
|
/* Extending summon data in memory so it's available in actionField.toChat. Think it's harmless, but ugly. Could maybe find a better way. */
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,9 @@ export default class DhpActor extends Actor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async _preDelete() {
|
async _preDelete(options, user) {
|
||||||
|
if ((await super._preDelete(options, user)) === false) return false;
|
||||||
|
|
||||||
if (this.prototypeToken.actorLink) {
|
if (this.prototypeToken.actorLink) {
|
||||||
game.system.registeredTriggers.unregisterItemTriggers(this.items);
|
game.system.registeredTriggers.unregisterItemTriggers(this.items);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -600,6 +602,7 @@ export default class DhpActor extends Actor {
|
||||||
rollData.system = this.system.getRollData();
|
rollData.system = this.system.getRollData();
|
||||||
rollData.prof = this.system.proficiency ?? 1;
|
rollData.prof = this.system.proficiency ?? 1;
|
||||||
rollData.cast = this.system.spellcastModifier ?? 1;
|
rollData.cast = this.system.spellcastModifier ?? 1;
|
||||||
|
|
||||||
return rollData;
|
return rollData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,11 @@
|
||||||
export default class DhActorCollection extends foundry.documents.collections.Actors {
|
export default class DhActorCollection extends foundry.documents.collections.Actors {
|
||||||
|
/** @returns the active party */
|
||||||
|
get party() {
|
||||||
|
const id = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.ActiveParty);
|
||||||
|
const actor = game.actors.get(id);
|
||||||
|
return actor?.type === "party" ? actor : null;
|
||||||
|
}
|
||||||
|
|
||||||
/** Ensure companions are initialized after all other subtypes. */
|
/** Ensure companions are initialized after all other subtypes. */
|
||||||
_initialize() {
|
_initialize() {
|
||||||
super._initialize();
|
super._initialize();
|
||||||
|
|
|
||||||
|
|
@ -189,7 +189,13 @@ export const getDeleteKeys = (property, innerProperty, innerPropertyDefaultValue
|
||||||
|
|
||||||
// Fix on Foundry native formula replacement for DH
|
// Fix on Foundry native formula replacement for DH
|
||||||
const nativeReplaceFormulaData = Roll.replaceFormulaData;
|
const nativeReplaceFormulaData = Roll.replaceFormulaData;
|
||||||
Roll.replaceFormulaData = function (formula, data = {}, { missing, warn = false } = {}) {
|
Roll.replaceFormulaData = function (formula, baseData = {}, { missing, warn = false } = {}) {
|
||||||
|
/* Inserting global data */
|
||||||
|
const data = {
|
||||||
|
...baseData,
|
||||||
|
partySize: game.actors?.party?.system.partyMembers.length ?? 0
|
||||||
|
};
|
||||||
|
|
||||||
const terms = Object.keys(CONFIG.DH.GENERAL.multiplierTypes).map(type => {
|
const terms = Object.keys(CONFIG.DH.GENERAL.multiplierTypes).map(type => {
|
||||||
return { term: type, default: 1 };
|
return { term: type, default: 1 };
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -189,4 +189,11 @@ const registerNonConfigSettings = () => {
|
||||||
config: false,
|
config: false,
|
||||||
type: SpotlightTracker
|
type: SpotlightTracker
|
||||||
});
|
});
|
||||||
|
|
||||||
|
game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.ActiveParty, {
|
||||||
|
scope: 'world',
|
||||||
|
config: false,
|
||||||
|
type: String,
|
||||||
|
default: null,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -174,12 +174,9 @@
|
||||||
"src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg",
|
"src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg",
|
||||||
"anchorX": 0.5,
|
"anchorX": 0.5,
|
||||||
"anchorY": 0.5,
|
"anchorY": 0.5,
|
||||||
"offsetX": 0,
|
|
||||||
"offsetY": 0,
|
|
||||||
"fit": "contain",
|
"fit": "contain",
|
||||||
"scaleX": 1,
|
"scaleX": 1,
|
||||||
"scaleY": 1,
|
"scaleY": 1,
|
||||||
"rotation": 0,
|
|
||||||
"tint": "#ffffff",
|
"tint": "#ffffff",
|
||||||
"alphaThreshold": 0.75
|
"alphaThreshold": 0.75
|
||||||
},
|
},
|
||||||
|
|
@ -230,7 +227,7 @@
|
||||||
"saturation": 0,
|
"saturation": 0,
|
||||||
"contrast": 0
|
"contrast": 0
|
||||||
},
|
},
|
||||||
"detectionModes": [],
|
"detectionModes": {},
|
||||||
"occludable": {
|
"occludable": {
|
||||||
"radius": 0
|
"radius": 0
|
||||||
},
|
},
|
||||||
|
|
@ -256,7 +253,8 @@
|
||||||
"flags": {},
|
"flags": {},
|
||||||
"randomImg": false,
|
"randomImg": false,
|
||||||
"appendNumber": false,
|
"appendNumber": false,
|
||||||
"prependAdjective": false
|
"prependAdjective": false,
|
||||||
|
"depth": 1
|
||||||
},
|
},
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
|
|
@ -496,34 +494,42 @@
|
||||||
"description": "<p><strong>Spend a Fear</strong> to summon a number of @UUID[Compendium.daggerheart.adversaries.Actor.OsLG2BjaEdTZUJU9]{Fallen Shock Troops} equal to twice the number of PCs. The Shock Troops appear at Far range.</p>",
|
"description": "<p><strong>Spend a Fear</strong> to summon a number of @UUID[Compendium.daggerheart.adversaries.Actor.OsLG2BjaEdTZUJU9]{Fallen Shock Troops} equal to twice the number of PCs. The Shock Troops appear at Far range.</p>",
|
||||||
"resource": null,
|
"resource": null,
|
||||||
"actions": {
|
"actions": {
|
||||||
"hGMzqw00JTlYfHYy": {
|
"SrU7qbh8LcOgfozT": {
|
||||||
"type": "effect",
|
"type": "summon",
|
||||||
"_id": "hGMzqw00JTlYfHYy",
|
"_id": "SrU7qbh8LcOgfozT",
|
||||||
"systemPath": "actions",
|
"systemPath": "actions",
|
||||||
|
"baseAction": false,
|
||||||
"description": "",
|
"description": "",
|
||||||
"chatDisplay": true,
|
"chatDisplay": true,
|
||||||
|
"originItem": {
|
||||||
|
"type": "itemCollection"
|
||||||
|
},
|
||||||
"actionType": "action",
|
"actionType": "action",
|
||||||
|
"triggers": [],
|
||||||
"cost": [
|
"cost": [
|
||||||
{
|
{
|
||||||
"scalable": false,
|
"scalable": false,
|
||||||
"key": "fear",
|
"key": "fear",
|
||||||
"value": 1,
|
"value": 1,
|
||||||
"step": null
|
"itemId": null,
|
||||||
|
"step": null,
|
||||||
|
"consumeOnSuccess": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"uses": {
|
"uses": {
|
||||||
"value": null,
|
"value": null,
|
||||||
"max": "",
|
"max": "",
|
||||||
"recovery": null
|
"recovery": null,
|
||||||
},
|
"consumeOnSuccess": false
|
||||||
"effects": [],
|
|
||||||
"target": {
|
|
||||||
"type": "self",
|
|
||||||
"amount": null
|
|
||||||
},
|
},
|
||||||
|
"summon": [
|
||||||
|
{
|
||||||
|
"actorUUID": "Compendium.daggerheart.adversaries.Actor.OsLG2BjaEdTZUJU9",
|
||||||
|
"count": "@partySize*2"
|
||||||
|
}
|
||||||
|
],
|
||||||
"name": "Spend Fear",
|
"name": "Spend Fear",
|
||||||
"img": "icons/magic/death/undead-skeleton-worn-blue.webp",
|
"range": "far"
|
||||||
"range": ""
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"originItemType": null,
|
"originItemType": null,
|
||||||
|
|
|
||||||
|
|
@ -52,12 +52,9 @@
|
||||||
"src": "systems/daggerheart/assets/icons/documents/actors/forest.svg",
|
"src": "systems/daggerheart/assets/icons/documents/actors/forest.svg",
|
||||||
"anchorX": 0.5,
|
"anchorX": 0.5,
|
||||||
"anchorY": 0.5,
|
"anchorY": 0.5,
|
||||||
"offsetX": 0,
|
|
||||||
"offsetY": 0,
|
|
||||||
"fit": "contain",
|
"fit": "contain",
|
||||||
"scaleX": 1,
|
"scaleX": 1,
|
||||||
"scaleY": 1,
|
"scaleY": 1,
|
||||||
"rotation": 0,
|
|
||||||
"tint": "#ffffff",
|
"tint": "#ffffff",
|
||||||
"alphaThreshold": 0.75
|
"alphaThreshold": 0.75
|
||||||
},
|
},
|
||||||
|
|
@ -108,7 +105,7 @@
|
||||||
"saturation": 0,
|
"saturation": 0,
|
||||||
"contrast": 0
|
"contrast": 0
|
||||||
},
|
},
|
||||||
"detectionModes": [],
|
"detectionModes": {},
|
||||||
"occludable": {
|
"occludable": {
|
||||||
"radius": 0
|
"radius": 0
|
||||||
},
|
},
|
||||||
|
|
@ -134,7 +131,8 @@
|
||||||
"flags": {},
|
"flags": {},
|
||||||
"randomImg": false,
|
"randomImg": false,
|
||||||
"appendNumber": false,
|
"appendNumber": false,
|
||||||
"prependAdjective": false
|
"prependAdjective": false,
|
||||||
|
"depth": 1
|
||||||
},
|
},
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
|
|
@ -323,7 +321,42 @@
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>A @UUID[Compendium.daggerheart.adversaries.Actor.8yUj2Mzvnifhxegm]{Young Dryad}, two @UUID[Compendium.daggerheart.adversaries.Actor.VtFBt9XBE0WrGGxP]{Sylvan Soldiers}, and a number of @UUID[Compendium.daggerheart.adversaries.Actor.G62k4oSkhkoXEs2D]{Minor Treants} equal to the number of PCs appear to confront the party for their intrusion.</p><section id=\"secret-01hkXuVJc5Kei4QW\" class=\"secret\"><p><em>What are the grove guardians concealing? What threat to the forest could the PCs confront to appease the Dryad?</em></p></section>",
|
"description": "<p>A @UUID[Compendium.daggerheart.adversaries.Actor.8yUj2Mzvnifhxegm]{Young Dryad}, two @UUID[Compendium.daggerheart.adversaries.Actor.VtFBt9XBE0WrGGxP]{Sylvan Soldiers}, and a number of @UUID[Compendium.daggerheart.adversaries.Actor.G62k4oSkhkoXEs2D]{Minor Treants} equal to the number of PCs appear to confront the party for their intrusion.</p><section id=\"secret-01hkXuVJc5Kei4QW\" class=\"secret\"><p><em>What are the grove guardians concealing? What threat to the forest could the PCs confront to appease the Dryad?</em></p></section>",
|
||||||
"resource": null,
|
"resource": null,
|
||||||
"actions": {},
|
"actions": {
|
||||||
|
"TPm6rpKA4mbili82": {
|
||||||
|
"type": "summon",
|
||||||
|
"_id": "TPm6rpKA4mbili82",
|
||||||
|
"systemPath": "actions",
|
||||||
|
"baseAction": false,
|
||||||
|
"description": "",
|
||||||
|
"chatDisplay": true,
|
||||||
|
"originItem": {
|
||||||
|
"type": "itemCollection"
|
||||||
|
},
|
||||||
|
"actionType": "action",
|
||||||
|
"triggers": [],
|
||||||
|
"cost": [],
|
||||||
|
"uses": {
|
||||||
|
"value": null,
|
||||||
|
"max": null,
|
||||||
|
"recovery": null,
|
||||||
|
"consumeOnSuccess": false
|
||||||
|
},
|
||||||
|
"summon": [
|
||||||
|
{
|
||||||
|
"actorUUID": "Compendium.daggerheart.adversaries.Actor.8yUj2Mzvnifhxegm",
|
||||||
|
"count": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"actorUUID": "Compendium.daggerheart.adversaries.Actor.VtFBt9XBE0WrGGxP",
|
||||||
|
"count": "2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"actorUUID": "Compendium.daggerheart.adversaries.Actor.G62k4oSkhkoXEs2D",
|
||||||
|
"count": "@partySize"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"originItemType": null,
|
"originItemType": null,
|
||||||
"originId": null,
|
"originId": null,
|
||||||
"featureForm": "action"
|
"featureForm": "action"
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,10 @@
|
||||||
{{else}}
|
{{else}}
|
||||||
<span class="entry-subtitle">{{localize "DAGGERHEART.UI.Sidebar.actorDirectory.companionNoPartner"}}</span>
|
<span class="entry-subtitle">{{localize "DAGGERHEART.UI.Sidebar.actorDirectory.companionNoPartner"}}</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
{{else if (eq type "party")}}
|
||||||
|
{{#if system.active}}
|
||||||
|
<span class="entry-subtitle">{{localize "DAGGERHEART.UI.Sidebar.actorDirectory.partyIsActive"}}</span>
|
||||||
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue