mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-12 11:41:08 +01:00
parent
7faec34597
commit
2aaab73699
11 changed files with 87 additions and 53 deletions
|
|
@ -505,7 +505,8 @@
|
||||||
},
|
},
|
||||||
"CLASS": {
|
"CLASS": {
|
||||||
"Feature": {
|
"Feature": {
|
||||||
"rallyDice": "Bardic Rally Dice"
|
"rallyDice": "Bardic Rally Dice",
|
||||||
|
"short": "Rally"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"CONFIG": {
|
"CONFIG": {
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,6 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
||||||
else if (this.hasSave || this.hasEffect) {
|
else if (this.hasSave || this.hasEffect) {
|
||||||
const roll = new CONFIG.Dice.daggerheart.DHRoll('');
|
const roll = new CONFIG.Dice.daggerheart.DHRoll('');
|
||||||
roll._evaluated = true;
|
roll._evaluated = true;
|
||||||
if(config.hasTarget) config.targetSelection = config.targets.length > 0;
|
|
||||||
await CONFIG.Dice.daggerheart.DHRoll.toMessage(roll, config);
|
await CONFIG.Dice.daggerheart.DHRoll.toMessage(roll, config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -227,15 +226,18 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
||||||
(!successCost && (!c.consumeOnSuccess || config.roll?.success)) ||
|
(!successCost && (!c.consumeOnSuccess || config.roll?.success)) ||
|
||||||
(successCost && c.consumeOnSuccess)
|
(successCost && c.consumeOnSuccess)
|
||||||
)
|
)
|
||||||
.map(c => {
|
.reduce((a, c) => {
|
||||||
const resource = usefulResources[c.key];
|
const resource = usefulResources[c.key];
|
||||||
return {
|
if( resource ) {
|
||||||
key: c.key,
|
a.push({
|
||||||
value: (c.total ?? c.value) * (resource.isReversed ? 1 : -1),
|
key: c.key,
|
||||||
target: resource.target,
|
value: (c.total ?? c.value) * (resource.isReversed ? 1 : -1),
|
||||||
keyIsID: resource.keyIsID
|
target: resource.target,
|
||||||
};
|
keyIsID: resource.keyIsID
|
||||||
});
|
});
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
await (this.actor.system.partner ?? this.actor).modifyResource(resources);
|
await (this.actor.system.partner ?? this.actor).modifyResource(resources);
|
||||||
if (
|
if (
|
||||||
|
|
|
||||||
|
|
@ -49,8 +49,7 @@ export default class DHDamageAction extends DHBaseAction {
|
||||||
...systemData,
|
...systemData,
|
||||||
roll: formulas,
|
roll: formulas,
|
||||||
dialog: {},
|
dialog: {},
|
||||||
data: this.getRollData(),
|
data: this.getRollData()
|
||||||
targetSelection: systemData.targets.length > 0
|
|
||||||
};
|
};
|
||||||
if (this.hasSave) config.onSave = this.save.damageMod;
|
if (this.hasSave) config.onSave = this.save.damageMod;
|
||||||
if (data.system) {
|
if (data.system) {
|
||||||
|
|
|
||||||
|
|
@ -18,14 +18,12 @@ const targetsField = () =>
|
||||||
);
|
);
|
||||||
|
|
||||||
export default class DHActorRoll extends foundry.abstract.TypeDataModel {
|
export default class DHActorRoll extends foundry.abstract.TypeDataModel {
|
||||||
targetHook = null;
|
|
||||||
|
|
||||||
static defineSchema() {
|
static defineSchema() {
|
||||||
return {
|
return {
|
||||||
title: new fields.StringField(),
|
title: new fields.StringField(),
|
||||||
roll: new fields.ObjectField(),
|
roll: new fields.ObjectField(),
|
||||||
targets: targetsField(),
|
targets: targetsField(),
|
||||||
targetSelection: new fields.BooleanField({ initial: false }),
|
|
||||||
hasRoll: new fields.BooleanField({ initial: false }),
|
hasRoll: new fields.BooleanField({ initial: false }),
|
||||||
hasDamage: new fields.BooleanField({ initial: false }),
|
hasDamage: new fields.BooleanField({ initial: false }),
|
||||||
hasHealing: new fields.BooleanField({ initial: false }),
|
hasHealing: new fields.BooleanField({ initial: false }),
|
||||||
|
|
@ -63,42 +61,45 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
get targetMode() {
|
get targetMode() {
|
||||||
return this.targetSelection;
|
return this.parent.targetSelection;
|
||||||
}
|
}
|
||||||
|
|
||||||
set targetMode(mode) {
|
set targetMode(mode) {
|
||||||
this.targetSelection = mode;
|
if(!this.parent.isAuthor) return;
|
||||||
|
this.parent.targetSelection = mode;
|
||||||
this.registerTargetHook();
|
this.registerTargetHook();
|
||||||
this.updateTargets();
|
this.updateTargets();
|
||||||
}
|
}
|
||||||
|
|
||||||
get hitTargets() {
|
get hitTargets() {
|
||||||
return this.currentTargets.filter(t => t.hit || !this.hasRoll || !this.targetSelection);
|
return this.currentTargets.filter(t => t.hit || !this.hasRoll || !this.targetMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateTargets() {
|
async updateTargets() {
|
||||||
if(!ui.chat.collection.get(this.parent.id)) return;
|
if(!ui.chat.collection.get(this.parent.id)) return;
|
||||||
let targets;
|
let targets;
|
||||||
if(this.targetSelection)
|
if(this.targetMode)
|
||||||
targets = this.targets;
|
targets = this.targets;
|
||||||
else
|
else
|
||||||
targets = Array.from(game.user.targets).map(t => game.system.api.fields.ActionFields.TargetField.formatTarget(t));
|
targets = Array.from(game.user.targets).map(t => game.system.api.fields.ActionFields.TargetField.formatTarget(t));
|
||||||
|
|
||||||
this.parent.setFlag(game.system.id, "targets", targets);
|
await this.parent.update({
|
||||||
await this.parent.updateSource({
|
flags: {
|
||||||
system: {
|
[game.system.id]: {
|
||||||
targetSelection: this.targetSelection
|
targets: targets,
|
||||||
|
targetMode: this.targetMode
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
registerTargetHook() {
|
registerTargetHook() {
|
||||||
if(!this.parent.isAuthor) return;
|
if(!this.parent.isAuthor) return;
|
||||||
if(this.targetSelection && this.targetHook !== null) {
|
if(this.targetMode && this.parent.targetHook !== null) {
|
||||||
Hooks.off("targetToken", this.targetHook);
|
Hooks.off("targetToken", this.parent.targetHook);
|
||||||
this.targetHook = null;
|
return this.parent.targetHook = null;
|
||||||
} else if (!this.targetSelection && this.targetHook === null) {
|
} else if (!this.targetMode && this.parent.targetHook === null) {
|
||||||
this.targetHook = Hooks.on('targetToken', foundry.utils.debounce(this.updateTargets.bind(this), 50));
|
return this.parent.targetHook = Hooks.on('targetToken', foundry.utils.debounce(this.updateTargets.bind(this), 50));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,9 +107,8 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
|
||||||
if (this.hasTarget) {
|
if (this.hasTarget) {
|
||||||
this.hasHitTarget = this.targets.filter(t => t.hit === true).length > 0;
|
this.hasHitTarget = this.targets.filter(t => t.hit === true).length > 0;
|
||||||
this.currentTargets = this.getTargetList();
|
this.currentTargets = this.getTargetList();
|
||||||
this. registerTargetHook();
|
|
||||||
|
|
||||||
if(this.targetSelection === true && this.hasRoll) {
|
if(this.targetMode === true && this.hasRoll) {
|
||||||
this.targetShort = this.targets.reduce((a,c) => {
|
this.targetShort = this.targets.reduce((a,c) => {
|
||||||
if(c.hit) a.hit += 1;
|
if(c.hit) a.hit += 1;
|
||||||
else a.miss += 1;
|
else a.miss += 1;
|
||||||
|
|
@ -123,7 +123,7 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
getTargetList() {
|
getTargetList() {
|
||||||
const targets = this.targetSelection && this.parent.isAuthor ? this.targets : (this.parent.getFlag(game.system.id, "targets") ?? this.targets),
|
const targets = this.targetMode && this.parent.isAuthor ? this.targets : (this.parent.getFlag(game.system.id, "targets") ?? this.targets),
|
||||||
reactionRolls = this.parent.getFlag(game.system.id, "reactionRolls");
|
reactionRolls = this.parent.getFlag(game.system.id, "reactionRolls");
|
||||||
|
|
||||||
if(reactionRolls) {
|
if(reactionRolls) {
|
||||||
|
|
@ -137,7 +137,7 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
setPendingSaves() {
|
setPendingSaves() {
|
||||||
this.pendingSaves = this.targetSelection
|
this.pendingSaves = this.targetMode
|
||||||
? this.targets.filter(target => target.hit && target.saved.success === null).length > 0
|
? this.targets.filter(target => target.hit && target.saved.success === null).length > 0
|
||||||
: this.currentTargets.filter(target => target.saved.success === null).length > 0;
|
: this.currentTargets.filter(target => target.saved.success === null).length > 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -229,7 +229,7 @@ export function ActionMixin(Base) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.inCollection
|
return this.inCollection
|
||||||
? foundry.utils.getProperty(result, basePath).get(this.id)
|
? foundry.utils.getProperty(result, basePath)?.get(this.id)
|
||||||
: foundry.utils.getProperty(result, basePath);
|
: foundry.utils.getProperty(result, basePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,6 @@ export default class D20Roll extends DHRoll {
|
||||||
data.type = config.roll?.type;
|
data.type = config.roll?.type;
|
||||||
data.difficulty = config.roll.difficulty;
|
data.difficulty = config.roll.difficulty;
|
||||||
if (config.targets?.length) {
|
if (config.targets?.length) {
|
||||||
config.targetSelection = true;
|
|
||||||
config.targets.forEach(target => {
|
config.targets.forEach(target => {
|
||||||
const difficulty = config.roll.difficulty ?? target.difficulty ?? target.evasion;
|
const difficulty = config.roll.difficulty ?? target.difficulty ?? target.evasion;
|
||||||
target.hit = roll.isCritical || roll.total >= difficulty;
|
target.hit = roll.isCritical || roll.total >= difficulty;
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ export default class DamageRoll extends DHRoll {
|
||||||
const parts = config.roll.map(r => this.postEvaluate(r));
|
const parts = config.roll.map(r => this.postEvaluate(r));
|
||||||
|
|
||||||
config.damage = this.unifyDamageRoll(parts);
|
config.damage = this.unifyDamageRoll(parts);
|
||||||
// config.targetSelection = config.targets?.length
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static postEvaluate(roll, config = {}) {
|
static postEvaluate(roll, config = {}) {
|
||||||
|
|
|
||||||
|
|
@ -644,16 +644,20 @@ export default class DhpActor extends Actor {
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'armor':
|
case 'armor':
|
||||||
updates.armor.resources['system.marks.value'] = Math.max(
|
if(this.system.armor?.system?.marks) {
|
||||||
Math.min(this.system.armor.system.marks.value + r.value, this.system.armorScore),
|
updates.armor.resources['system.marks.value'] = Math.max(
|
||||||
0
|
Math.min(this.system.armor.system.marks.value + r.value, this.system.armorScore),
|
||||||
);
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
updates.actor.resources[`system.resources.${r.key}.value`] = Math.max(
|
if(this.system.resources?.[r.key]) {
|
||||||
Math.min(this.system.resources[r.key].value + r.value, this.system.resources[r.key].max),
|
updates.actor.resources[`system.resources.${r.key}.value`] = Math.max(
|
||||||
0
|
Math.min(this.system.resources[r.key].value + r.value, this.system.resources[r.key].max),
|
||||||
);
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
||||||
|
targetHook = null;
|
||||||
|
targetSelection = null;
|
||||||
|
|
||||||
async renderHTML() {
|
async renderHTML() {
|
||||||
const actor = game.actors.get(this.speaker.actor);
|
const actor = game.actors.get(this.speaker.actor);
|
||||||
const actorData = actor && this.isContentVisible ? actor : {
|
const actorData = actor && this.isContentVisible ? actor : {
|
||||||
|
|
@ -14,6 +17,32 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
prepareData() {
|
||||||
|
if(this.isAuthor && this.targetSelection === null)
|
||||||
|
this.targetSelection = this.system.targets?.length > 0;
|
||||||
|
super.prepareData();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
_onCreate(data, options, userId) {
|
||||||
|
super._onCreate(data, options, userId);
|
||||||
|
if(this.system.registerTargetHook) this.system.registerTargetHook();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
async _preDelete(options, user) {
|
||||||
|
if(this.targetHook !== null) Hooks.off("targetToken", this.targetHook);
|
||||||
|
return super._preDelete(options, user);
|
||||||
|
}
|
||||||
|
|
||||||
enrichChatMessage(html) {
|
enrichChatMessage(html) {
|
||||||
const elements = html.querySelectorAll('[data-perm-id]');
|
const elements = html.querySelectorAll('[data-perm-id]');
|
||||||
elements.forEach(e => {
|
elements.forEach(e => {
|
||||||
|
|
@ -62,7 +91,7 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
getTargetList() {
|
getTargetList() {
|
||||||
const targets = this.system.hitTargets;
|
const targets = this.system.hitTargets ?? [];
|
||||||
return targets.map(target => game.canvas.tokens.documentCollection.find(t => t.actor?.uuid === target.actorId));
|
return targets.map(target => game.canvas.tokens.documentCollection.find(t => t.actor?.uuid === target.actorId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -134,7 +163,7 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
consumeOnSuccess() {
|
consumeOnSuccess() {
|
||||||
if (!this.system.successConsumed && !this.system.targetSelection) {
|
if (!this.system.successConsumed && !this.targetSelection) {
|
||||||
const action = this.system.action;
|
const action = this.system.action;
|
||||||
if (action) action.consume(this.system, true);
|
if (action) action.consume(this.system, true);
|
||||||
}
|
}
|
||||||
|
|
@ -143,12 +172,12 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
||||||
hoverTarget(event) {
|
hoverTarget(event) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
const token = canvas.tokens.get(event.currentTarget.dataset.token);
|
const token = canvas.tokens.get(event.currentTarget.dataset.token);
|
||||||
if (!token?.controlled) token._onHoverIn(event, { hoverOutOthers: true });
|
if (token && !token?.controlled) token._onHoverIn(event, { hoverOutOthers: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
unhoverTarget(event) {
|
unhoverTarget(event) {
|
||||||
const token = canvas.tokens.get(event.currentTarget.dataset.token);
|
const token = canvas.tokens.get(event.currentTarget.dataset.token);
|
||||||
if (!token?.controlled) token._onHoverOut(event);
|
if (token && !token?.controlled) token._onHoverOut(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
clickTarget(event) {
|
clickTarget(event) {
|
||||||
|
|
@ -163,6 +192,7 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
||||||
|
|
||||||
onTargetSelection(event) {
|
onTargetSelection(event) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
this.system.targetMode = Boolean(event.target.dataset.targetHit);
|
if(!event.target.classList.contains("target-selected"))
|
||||||
|
this.system.targetMode = Boolean(event.target.dataset.targetHit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if roll.rally.dice}}
|
{{#if roll.rally.dice}}
|
||||||
<div class="roll-die has-plus">
|
<div class="roll-die has-plus">
|
||||||
<label>{{localize "DAGGERHEART.GENERAL.fear"}}</label>
|
<label>{{localize "DAGGERHEART.CLASS.Feature.short"}}</label>
|
||||||
<div class="dice {{roll.rally.dice}}">{{roll.rally.value}}</div>
|
<div class="dice {{roll.rally.dice}}">{{roll.rally.value}}</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@
|
||||||
<div class="target-selector">
|
<div class="target-selector">
|
||||||
<div class="roll-part-header"><div></div></div>
|
<div class="roll-part-header"><div></div></div>
|
||||||
<div class="target-choice">
|
<div class="target-choice">
|
||||||
<div class="button-target-selection{{#if targetSelection}} target-selected{{/if}}" data-target-hit="true">{{localize "DAGGERHEART.UI.Chat.damageRoll.hitTarget"}}</div>
|
<div class="button-target-selection{{#if targetMode}} target-selected{{/if}}" data-target-hit="true">{{localize "DAGGERHEART.UI.Chat.damageRoll.hitTarget"}}</div>
|
||||||
<div class="button-target-selection{{#unless targetSelection}} target-selected{{/unless}}">{{localize "DAGGERHEART.UI.Chat.damageRoll.currentTarget"}}</div>
|
<div class="button-target-selection{{#unless targetMode}} target-selected{{/unless}}">{{localize "DAGGERHEART.UI.Chat.damageRoll.currentTarget"}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="roll-part-header"><div></div></div>
|
<div class="roll-part-header"><div></div></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
<img class="target-img" src="{{img}}">
|
<img class="target-img" src="{{img}}">
|
||||||
<div class="target-data">
|
<div class="target-data">
|
||||||
<div class="target-name" data-perm-id="{{actorId}}"><span>{{name}}</span></div>
|
<div class="target-name" data-perm-id="{{actorId}}"><span>{{name}}</span></div>
|
||||||
{{#if (and ../targetSelection ../hasRoll)}}
|
{{#if (and ../targetMode ../hasRoll)}}
|
||||||
<div class="target-hit-status {{#if hit}}is-hit{{else}}is-miss{{/if}}">
|
<div class="target-hit-status {{#if hit}}is-hit{{else}}is-miss{{/if}}">
|
||||||
{{#if hit}}
|
{{#if hit}}
|
||||||
{{localize "DAGGERHEART.GENERAL.hit.single"}}
|
{{localize "DAGGERHEART.GENERAL.hit.single"}}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue