add hbs for percentile roll
add skillPath for optimization checks update lang files add market skill feature
This commit is contained in:
+33
-1
@@ -1235,4 +1235,36 @@ body:not(.no-theme) #interface:not(.theme-light) #action-bar .slot.full:hover {
|
||||
|
||||
.target-proficiency-mod {
|
||||
color: #247c14;
|
||||
}
|
||||
}
|
||||
|
||||
.rollback-section {
|
||||
order: 99;
|
||||
display: flex;
|
||||
margin-top: 5px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
> i {
|
||||
margin: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
[data-action="rollback-skill-failure-state"] {
|
||||
align-items: center;
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
min-height: unset;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-left: 5px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
[data-tooltip] {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.strike {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
+4
-1
@@ -271,5 +271,8 @@
|
||||
"DG.ItemWindow.Ritual.ActivationTime": "Activation Time",
|
||||
"DG.ItemWindow.Ritual.ActivationCosts": "Activation Costs",
|
||||
"DG.ItemWindow.Ritual.StudyTime": "Study Time",
|
||||
"DG.ItemWindow.Ritual.LearnedSanityDamage": "Learn SAN Damage"
|
||||
"DG.ItemWindow.Ritual.LearnedSanityDamage": "Learn SAN Damage",
|
||||
|
||||
"DG.Messages.Skillsmark.Marked": "Aquesta habilitat està marcada",
|
||||
"DG.Messages.Skillsmark.Tooltip": "Vegeu la p. 29 del Manual de l'agent"
|
||||
}
|
||||
|
||||
+4
-1
@@ -309,5 +309,8 @@
|
||||
"DG.ItemWindow.Ritual.ActivationTime": "激活耗时",
|
||||
"DG.ItemWindow.Ritual.ActivationCosts": "激活代价",
|
||||
"DG.ItemWindow.Ritual.StudyTime": "学习时长",
|
||||
"DG.ItemWindow.Ritual.LearnedSanityDamage": "学习造成的理智损失"
|
||||
"DG.ItemWindow.Ritual.LearnedSanityDamage": "学习造成的理智损失",
|
||||
|
||||
"DG.Messages.Skillsmark.Marked": "此技能被标记",
|
||||
"DG.Messages.Skillsmark.Tooltip": "参见第 29 页《代理人手册》"
|
||||
}
|
||||
|
||||
+4
-1
@@ -289,5 +289,8 @@
|
||||
"DG.ItemWindow.Ritual.ActivationTime": "Activation Time",
|
||||
"DG.ItemWindow.Ritual.ActivationCosts": "Activation Costs",
|
||||
"DG.ItemWindow.Ritual.StudyTime": "Study Time",
|
||||
"DG.ItemWindow.Ritual.LearnedSanityDamage": "Learn SAN Damage"
|
||||
"DG.ItemWindow.Ritual.LearnedSanityDamage": "Learn SAN Damage",
|
||||
|
||||
"DG.Messages.Skillsmark.Marked": "Diese Fähigkeit ist gekennzeichnet.",
|
||||
"DG.Messages.Skillsmark.Tooltip": "Siehe S. 29 des Agentenhandbuchs"
|
||||
}
|
||||
|
||||
@@ -391,4 +391,7 @@
|
||||
"DG.Settings.hypergeometry.hint": "Always show Hypergeometry item section for players, even if they don't have any items of that type.",
|
||||
"DG.Settings.landscapes.name": "Show Impossible Landscapes Content",
|
||||
"DG.Settings.landscapes.hint": "Show Impossible Landscapes-specific fields from character sheets."
|
||||
|
||||
"DG.Messages.Skillsmark.Marked": "This skill is marked",
|
||||
"DG.Messages.Skillsmark.Tooltip": "See p. 29 Agent's Handbook"
|
||||
}
|
||||
|
||||
+4
-1
@@ -276,5 +276,8 @@
|
||||
"DG.ItemWindow.Ritual.ActivationTime": "Activation Time",
|
||||
"DG.ItemWindow.Ritual.ActivationCosts": "Activation Costs",
|
||||
"DG.ItemWindow.Ritual.StudyTime": "Study Time",
|
||||
"DG.ItemWindow.Ritual.LearnedSanityDamage": "Learn SAN Damage"
|
||||
"DG.ItemWindow.Ritual.LearnedSanityDamage": "Learn SAN Damage",
|
||||
|
||||
"DG.Messages.Skillsmark.Marked": "Esta habilidad está marcada.",
|
||||
"DG.Messages.Skillsmark.Tooltip": "Ver pág. 29 del Manual del Agente."
|
||||
}
|
||||
|
||||
+4
-1
@@ -313,5 +313,8 @@
|
||||
"DG.ItemWindow.Ritual.ActivationTime": "Temp d'Activation",
|
||||
"DG.ItemWindow.Ritual.ActivationCosts": "Coût d'Activation",
|
||||
"DG.ItemWindow.Ritual.StudyTime": "Temps d'étude",
|
||||
"DG.ItemWindow.Ritual.LearnedSanityDamage": "Dégâts SAN Étude"
|
||||
"DG.ItemWindow.Ritual.LearnedSanityDamage": "Dégâts SAN Étude",
|
||||
|
||||
"DG.Messages.Skillsmark.Marked": "Cette compétence est marquée.",
|
||||
"DG.Messages.Skillsmark.Tooltip": "Voir p. 29 du Manuel de l'agent."
|
||||
}
|
||||
|
||||
+4
-1
@@ -352,5 +352,8 @@
|
||||
"DG.Skills.ruby.swim": "すいえい",
|
||||
"DG.Skills.ruby.unarmed_combat": "としゅかくとう",
|
||||
"DG.Skills.ruby.unnatural": "ひしぜん",
|
||||
"DG.Skills.ruby.flight": "ひこう"
|
||||
"DG.Skills.ruby.flight": "ひこう",
|
||||
|
||||
"DG.Messages.Skillsmark.Marked": "このスキルはマークされています",
|
||||
"DG.Messages.Skillsmark.Tooltip": "エージェントハンドブック29ページ参照"
|
||||
}
|
||||
|
||||
+4
-1
@@ -313,5 +313,8 @@
|
||||
"DG.ItemWindow.Ritual.ActivationTime": "Czas Aktywacji",
|
||||
"DG.ItemWindow.Ritual.ActivationCosts": "Koszt Aktywacji",
|
||||
"DG.ItemWindow.Ritual.StudyTime": "Czas Nauki",
|
||||
"DG.ItemWindow.Ritual.LearnedSanityDamage": "Utrata PP po Nauce"
|
||||
"DG.ItemWindow.Ritual.LearnedSanityDamage": "Utrata PP po Nauce",
|
||||
|
||||
"DG.Messages.Skillsmark.Marked": "Ta umiejętność jest oznaczona.",
|
||||
"DG.Messages.Skillsmark.Tooltip": "Zobacz str. 29 Podręcznika Agenta."
|
||||
}
|
||||
|
||||
+4
-1
@@ -311,5 +311,8 @@
|
||||
"DG.ItemWindow.Ritual.ActivationTime": "Tempo de Ativação",
|
||||
"DG.ItemWindow.Ritual.ActivationCosts": "Custos de Ativação",
|
||||
"DG.ItemWindow.Ritual.StudyTime": "Tempo de Estudo",
|
||||
"DG.ItemWindow.Ritual.LearnedSanityDamage": "Dano de SAN ao Aprender"
|
||||
"DG.ItemWindow.Ritual.LearnedSanityDamage": "Dano de SAN ao Aprender",
|
||||
|
||||
"DG.Messages.Skillsmark.Marked": "Esta perícia é marcada",
|
||||
"DG.Messages.Skillsmark.Tooltip": "Veja pág. 29 do Manual do Agente"
|
||||
}
|
||||
|
||||
+4
-1
@@ -311,5 +311,8 @@
|
||||
"DG.ItemWindow.Ritual.ActivationTime": "Aktiveringstid",
|
||||
"DG.ItemWindow.Ritual.ActivationCosts": "Aktiveringskostnader",
|
||||
"DG.ItemWindow.Ritual.StudyTime": "Studietid",
|
||||
"DG.ItemWindow.Ritual.LearnedSanityDamage": "Learn SAN Damage"
|
||||
"DG.ItemWindow.Ritual.LearnedSanityDamage": "Learn SAN Damage",
|
||||
|
||||
"DG.Messages.Skillsmark.Marked": "Denna färdighet är markerad",
|
||||
"DG.Messages.Skillsmark.Tooltip": "Se s. 29 Agenthandbok"
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ import {
|
||||
rollSkillMacro,
|
||||
rollSkillTestAndDamageForOwnedItem,
|
||||
} from "./other/macro-functions.js";
|
||||
import DGUtils from "./other/utility-functions.js";
|
||||
import { handleInlineActions } from "./other/inline.js";
|
||||
|
||||
Hooks.once("init", async () => {
|
||||
game.deltagreen = {
|
||||
@@ -197,3 +199,14 @@ Hooks.on("renderGamePause", function (_, html, options) {
|
||||
html.querySelector("img").classList.remove("fa-spin"); // I don't like the logo spinning personally
|
||||
} catch {}
|
||||
});
|
||||
|
||||
Hooks.on("renderChatLog", async (app, element, context, options) => {
|
||||
element.addEventListener("click", (event) => {
|
||||
let btnWithAction = DGUtils.htmlClosest(event.target, "button[data-action]");
|
||||
let message = DGUtils.htmlClosest(event.target, "li[data-message-id]");
|
||||
|
||||
if (btnWithAction && message && message?.dataset?.messageId) {
|
||||
handleInlineActions(btnWithAction, message?.dataset?.messageId);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
export async function handleInlineActions(btnWithAction, messageId) {
|
||||
let action = btnWithAction.dataset?.action;
|
||||
let message = game.messages.get(messageId);
|
||||
let actor = message?.speakerActor;
|
||||
if (!action || !message || !actor) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (action === 'rollback-skill-failure-state') {
|
||||
let rollbackFlag = foundry.utils.deepClone(message.getFlag("deltagreen", "rollbacks"));
|
||||
await actor.update(foundry.utils.deepClone(rollbackFlag));
|
||||
|
||||
toggleAllSkillFailures(rollbackFlag)
|
||||
|
||||
let label = btnWithAction
|
||||
.closest(".rollback-section")
|
||||
?.querySelector("label");
|
||||
let oldHtml = label.outerHTML;
|
||||
label.classList.toggle('strike');
|
||||
|
||||
message.update({
|
||||
[`flags.deltagreen.rollbacks`]: rollbackFlag,
|
||||
content: message.content
|
||||
.replace(oldHtml, label.outerHTML)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function toggleAllSkillFailures(data) {
|
||||
for (const skill of Object.values(data.system?.skills || {})) {
|
||||
skill.failure = !skill.failure;
|
||||
}
|
||||
for (const skill of Object.values(data.system?.typedSkills || {})) {
|
||||
skill.failure = !skill.failure;
|
||||
}
|
||||
}
|
||||
@@ -33,4 +33,15 @@ export default class DGUtils {
|
||||
static formatStringWithLeadingPlus(number) {
|
||||
return number > 0 ? `+${number}` : number.toString();
|
||||
}
|
||||
|
||||
static htmlClosest(element, selectors) {
|
||||
if (element instanceof Element) {
|
||||
return element.closest(selectors);
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
static getValueByPath(obj, path) {
|
||||
return path.split('.').reduce((acc, key) => acc?.[key], obj);
|
||||
}
|
||||
}
|
||||
|
||||
+94
-84
@@ -77,12 +77,13 @@ export class DGPercentileRoll extends DGRoll {
|
||||
super("1D100", {}, options);
|
||||
|
||||
// Set roll info for Skill, Stat, Typed Skill, and non-custom Weapon Percentile rolls.
|
||||
const { target, localizedKey } = this.getRollInfoFromKey(
|
||||
const { target, localizedKey, skillPath } = this.getRollInfoFromKey(
|
||||
this.key,
|
||||
this.actor.system,
|
||||
);
|
||||
this.target = target;
|
||||
this.localizedKey = localizedKey;
|
||||
this.skillPath = skillPath;
|
||||
|
||||
// Set roll info for other Percentile rolls
|
||||
switch (this.type) {
|
||||
@@ -272,50 +273,7 @@ export class DGPercentileRoll extends DGRoll {
|
||||
this.options.rollMode = "blindroll";
|
||||
}
|
||||
|
||||
let label = `${game.i18n.localize("DG.Roll.Rolling")} <b>${
|
||||
this.localizedKey
|
||||
}</b><br> ${game.i18n.localize("DG.Roll.Target")} ${this.effectiveTarget}%`;
|
||||
// "Inhuman" stat being rolled. See function for details.
|
||||
if (this.isInhuman) {
|
||||
label = `${game.i18n.localize("DG.Roll.Rolling")} <b>${
|
||||
this.localizedKey
|
||||
} [${game.i18n
|
||||
.localize("DG.Roll.Inhuman")
|
||||
.toUpperCase()}]</b> ${game.i18n.localize("DG.Roll.Target")} ${
|
||||
this.effectiveTarget
|
||||
}`;
|
||||
}
|
||||
|
||||
let isExhausted = false;
|
||||
let exhaustedCheckPenalty = -20;
|
||||
|
||||
try {
|
||||
// I suspect (but am not entirely certain) that being tired doesn't make you less lucky)
|
||||
if (this.type !== "luck") {
|
||||
isExhausted = this.actor.system.physical.exhausted;
|
||||
exhaustedCheckPenalty = this.actor.system.physical.exhaustedPenalty;
|
||||
exhaustedCheckPenalty = -1 * Math.abs(exhaustedCheckPenalty);
|
||||
}
|
||||
} catch {
|
||||
isExhausted = false;
|
||||
exhaustedCheckPenalty = -20;
|
||||
}
|
||||
|
||||
if (this.modifier || isExhausted) {
|
||||
label += ` (${this.target}%`;
|
||||
|
||||
if (this.modifier) {
|
||||
label += `${DGUtils.formatStringWithLeadingPlus(this.modifier)}%`;
|
||||
}
|
||||
|
||||
if (isExhausted) {
|
||||
label += `${DGUtils.formatStringWithLeadingPlus(
|
||||
exhaustedCheckPenalty,
|
||||
)}%`;
|
||||
}
|
||||
|
||||
label += `)`;
|
||||
}
|
||||
let label = this.createLabel();
|
||||
|
||||
let resultString = "";
|
||||
let styleOverride = "";
|
||||
@@ -338,31 +296,36 @@ export class DGPercentileRoll extends DGRoll {
|
||||
}
|
||||
}
|
||||
|
||||
let html = "";
|
||||
html += `<div class="dice-roll">`;
|
||||
html += ` <div class="dice-result">`;
|
||||
html += ` <div style="${styleOverride}" class="dice-formula">${resultString}</div>`;
|
||||
html += ` <div class="dice-tooltip">`;
|
||||
html += ` <section class="tooltip-part">`;
|
||||
html += ` <div class="dice">`;
|
||||
html += ` <header class="part-header flexrow">`;
|
||||
html += ` <span class="part-formula">`;
|
||||
html += ` ${this.formula}`;
|
||||
html += ` </span>`;
|
||||
html += ` <span class="part-total">`;
|
||||
html += ` ${this.total}`;
|
||||
html += ` </span>`;
|
||||
html += ` </header>`;
|
||||
html += ` <ol class="dice-rolls">`;
|
||||
html += ` <li class="roll die ${this.formula}">${this.total}</li>`;
|
||||
html += ` </ol>`;
|
||||
html += ` </div>`;
|
||||
html += ` </section>`;
|
||||
html += ` </div>`;
|
||||
html += ` <h4 class="dice-total">${this.total}</h4>`;
|
||||
html += `</div>`;
|
||||
let failureMark = !this.isSuccess && this.skillPath
|
||||
&& !DGUtils.getValueByPath(this.actor, this.skillPath).failure;
|
||||
|
||||
return this.toMessage({ content: html, flavor: label });
|
||||
const html = await renderTemplate(
|
||||
"systems/deltagreen/templates/roll/percentile-roll.hbs",
|
||||
{
|
||||
styleOverride,
|
||||
resultString,
|
||||
formula: this.formula,
|
||||
total: this.total,
|
||||
failureMark
|
||||
});
|
||||
|
||||
//TODO: add setting for it?
|
||||
if (failureMark) {
|
||||
let keyForUpdate = `${this.skillPath}.failure`;
|
||||
|
||||
//TODO: auto-update actor or post icon with manual apply
|
||||
await this.actor.update({
|
||||
[keyForUpdate]: true
|
||||
})
|
||||
|
||||
return this.toMessage({ flags: { deltagreen: {
|
||||
rollbacks: {
|
||||
[keyForUpdate]: false
|
||||
}
|
||||
} }, content: html, flavor: label });
|
||||
} else {
|
||||
return this.toMessage({ content: html, flavor: label });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -382,6 +345,7 @@ export class DGPercentileRoll extends DGRoll {
|
||||
|
||||
let target = null;
|
||||
let localizedKey = null;
|
||||
let skillPath = null;//for optimization failure checks
|
||||
if (statKeys.includes(this.key)) {
|
||||
target = actorData.statistics[this.key].x5;
|
||||
localizedKey = game.i18n.localize(`DG.Attributes.${this.key}`);
|
||||
@@ -390,17 +354,76 @@ export class DGPercentileRoll extends DGRoll {
|
||||
// use calculated target proficiency (effects and etc like aim + 20%)
|
||||
target = actorData.skills[this.key].targetProficiency || actorData.skills[this.key].proficiency;
|
||||
localizedKey = game.i18n.localize(`DG.Skills.${this.key}`);
|
||||
skillPath = `system.skills.${this.key}`;
|
||||
}
|
||||
if (typedSkillKeys.includes(this.key)) {
|
||||
const skill = actorData.typedSkills[this.key];
|
||||
target = skill.proficiency;
|
||||
localizedKey = `${skill.group} (${skill.label})`;
|
||||
skillPath = `system.typedSkills.${this.key}`;
|
||||
}
|
||||
if (this.key === "ritual") {
|
||||
target = actorData.sanity.ritual;
|
||||
localizedKey = game.i18n.localize(`DG.Skills.ritual`);
|
||||
}
|
||||
return { target, localizedKey };
|
||||
return { target, localizedKey, skillPath };
|
||||
}
|
||||
|
||||
/**
|
||||
* Create label based on result of roll
|
||||
*
|
||||
* todo: do we want make isInhuman more similar to base label?
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
createLabel() {
|
||||
let startOfLabel = game.i18n.localize("DG.Roll.Rolling")
|
||||
+ ` <b>${this.localizedKey}`
|
||||
let endOfLabel =`${game.i18n.localize("DG.Roll.Target")} ${this.effectiveTarget}`
|
||||
|
||||
let label = this.isInhuman
|
||||
// "Inhuman" stat being rolled. See function for details.
|
||||
? `${startOfLabel} [${game.i18n.localize("DG.Roll.Inhuman").toUpperCase()}]</b> ${endOfLabel}`
|
||||
: `${startOfLabel}</b><br> ${endOfLabel}%`;
|
||||
|
||||
let {isExhausted, exhaustedCheckPenalty} = this.exhausted
|
||||
|
||||
if (this.modifier || isExhausted) {
|
||||
label += ` (${this.target}%`;
|
||||
|
||||
if (this.modifier) {
|
||||
label += `${DGUtils.formatStringWithLeadingPlus(this.modifier)}%`;
|
||||
}
|
||||
|
||||
if (isExhausted) {
|
||||
label += `${DGUtils.formatStringWithLeadingPlus(
|
||||
exhaustedCheckPenalty,
|
||||
)}%`;
|
||||
}
|
||||
|
||||
label += `)`;
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
get exhausted() {
|
||||
let isExhausted = false;
|
||||
let exhaustedCheckPenalty = -20;
|
||||
|
||||
try {
|
||||
// I suspect (but am not entirely certain) that being tired doesn't make you less lucky)
|
||||
if (this.type !== "luck") {
|
||||
isExhausted = this.actor.system.physical.exhausted;
|
||||
exhaustedCheckPenalty = this.actor.system.physical.exhaustedPenalty;
|
||||
exhaustedCheckPenalty = -1 * Math.abs(exhaustedCheckPenalty);
|
||||
}
|
||||
} catch {
|
||||
isExhausted = false;
|
||||
exhaustedCheckPenalty = -20;
|
||||
}
|
||||
|
||||
return {isExhausted, exhaustedCheckPenalty};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -481,20 +504,7 @@ export class DGPercentileRoll extends DGRoll {
|
||||
get effectiveTarget() {
|
||||
let target = 1;
|
||||
|
||||
let isExhausted = false;
|
||||
let exhaustedCheckPenalty = -20;
|
||||
|
||||
try {
|
||||
// I suspect (but am not entirely certain) that being tired doesn't make you less lucky)
|
||||
if (this.type !== "luck") {
|
||||
isExhausted = this.actor.system.physical.exhausted;
|
||||
exhaustedCheckPenalty = this.actor.system.physical.exhaustedPenalty;
|
||||
exhaustedCheckPenalty = -1 * Math.abs(exhaustedCheckPenalty);
|
||||
}
|
||||
} catch {
|
||||
isExhausted = false;
|
||||
exhaustedCheckPenalty = -20;
|
||||
}
|
||||
let {isExhausted, exhaustedCheckPenalty} = this.exhausted
|
||||
|
||||
if (!this.target || Number.isNaN(this.target)) {
|
||||
return null;
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<div class="dice-roll">
|
||||
<div class="dice-result">
|
||||
<div style="{{styleOverride}}" class="dice-formula">{{resultString}}</div>
|
||||
<div class="dice-tooltip">
|
||||
<section class="tooltip-part">
|
||||
<div class="dice">
|
||||
<header class="part-header flexrow">
|
||||
<span class="part-formula">{{formula}}</span>
|
||||
<span class="part-total">{{total}}</span>
|
||||
</header>
|
||||
<ol class="dice-rolls">
|
||||
<li class="roll die {{formula}}">{{total}}</li>
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<h4 class="dice-total">{{total}}</h4>
|
||||
</div>
|
||||
|
||||
{{#if failureMark}}
|
||||
<div class="rollback-section">
|
||||
<label>{{localize 'DG.Messages.Skillsmark.Marked'}}</label>
|
||||
<i class="fa fa-book" aria-hidden="true" data-tooltip="<p>{{localize 'DG.Messages.Skillsmark.Tooltip'}}</p>"></i>
|
||||
<button type="button" data-action="rollback-skill-failure-state">
|
||||
<i class="fa fa-undo" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
</div>
|
||||
Reference in New Issue
Block a user