Style fixes
This commit is contained in:
+7
-6
@@ -230,6 +230,7 @@
|
||||
"DG.Mental.AdaptedToHelplessness": "Adapted to Helplessness",
|
||||
"DG.Mental.Motivations": "Motivation",
|
||||
"DG.Mental.Disorders": "Disorder",
|
||||
"DG.Gear.SelectCompendium": "Select Compendium",
|
||||
"DG.Gear.WeaponTypes.Firearms": "Firearms",
|
||||
"DG.Gear.WeaponTypes.Melee": "Melee",
|
||||
"DG.Gear.Weapons": "WEAPONS",
|
||||
@@ -342,8 +343,9 @@
|
||||
"DG.Sheet.BlockHeaders.PersonalInfoCV": "PERSONAL INFORMATION / CV",
|
||||
"DG.Sheet.BlockHeaders.ScenarioInformation": "SCENARIO INFORMATION",
|
||||
"DG.Sheet.BlockHeaders.BondsRelationshipsContacts": "BONDS / RELATIONSHIPS / CONTACTS",
|
||||
"DG.AgentSheet.ProfessionPlaceholder": "PROFESSION (RANK IF APPLICABLE)",
|
||||
"DG.AgentSheet.OpenProfessionToEdit": "Click to edit profession",
|
||||
"DG.AgentSheet.ProfessionPlaceholder": "PROFESSION (RANK)",
|
||||
"DG.AgentSheet.RenameProfession.Title": "Rename Profession",
|
||||
"DG.AgentSheet.RenameProfession.Tooltip": "Click to rename profession",
|
||||
"DG.UnnaturalSheet.HideUntrainedSkillsLabel": "Hide Untrained",
|
||||
"DG.UnnaturalSheet.ShortDescriptionPlaceholder": "Description of creature or creature type",
|
||||
"DG.UnnaturalSheet.ShowUntrainedSkillsLabel": "Show Untrained",
|
||||
@@ -389,14 +391,13 @@
|
||||
"DG.Profession.Dialog.SkillTotalsHint": "Skills in green have been increased by your profession. Hover over a skill to see what it does or consult the Agent's Handbook for the full description.",
|
||||
"DG.Profession.Dialog.SkillsOptionsHeader": "Skills Options ({picks} picks)",
|
||||
"DG.Profession.Dialog.BonusSkillsIntro": "Select skills from the dropdowns to add 20% to their total. A skill may be selected multiple times. Unnatural cannot be selected, nor can any skill be increased above 80% at character creation.",
|
||||
"DG.Profession.Dialog.BonusSkillAlreadyAtCap": "{skill} may not be increased further. Please select a different bonus skill.",
|
||||
"DG.Profession.Dialog.BonusSkillWasteTooHigh": "Bonus increases to {skill} would waste {waste} skill points (at most {maxWaste} may be wasted per skill).",
|
||||
"DG.Profession.Dialog.BonusSkillWasteTooHigh": "{skill} cannot be increased above 80. Select a different bonus skill.",
|
||||
"DG.Profession.Dialog.BondsIntro": "Bonds are the important relationships in your agent's life, such as family, friends, and other loved ones. They can provide a buffer against SAN loss, at the cost of that relationship. Initial relationship score is equal to CHA.",
|
||||
"DG.Profession.Dialog.BondFieldLabel": "Bond{number}",
|
||||
"DG.Profession.Dialog.SelectSkill": "Select a skill…",
|
||||
"DG.Profession.Dialog.SkillTypePlaceholder": "Type or specialization",
|
||||
"DG.Profession.Dialog.Submit": "Submit",
|
||||
"DG.Profession.Dialog.CapWarning": "{skill} is being raised to {attempted} but is capped at 80 during agent creation. This is wasting {waste} skill points.",
|
||||
"DG.Profession.Dialog.CapWarning": "{skill} is being raised to {attempted} but is capped at 80 during agent creation, wasting {waste} skill points.",
|
||||
"DG.Profession.Dialog.DuplicateTypedName": "Duplicate {type} ({name}) detected. Please choose unique names.",
|
||||
"DG.Profession.ChooseOnePlaceholder": "choose one",
|
||||
"DG.Profession.Dialog.ChooseOneNamesHeader": "Name Skill Specializations",
|
||||
@@ -419,7 +420,7 @@
|
||||
"DG.ItemWindow.Profession.SkillsTab": "Skills",
|
||||
"DG.ItemWindow.Profession.Name": "Profession Name",
|
||||
"DG.ItemWindow.Profession.Bonds": "Bonds",
|
||||
"DG.ItemWindow.Profession.BondsTooltip": "Number of bond slots granted when this profession is assigned to an agent (0–5).",
|
||||
"DG.ItemWindow.Profession.BondsTooltip": "Number of bond slots granted when this profession is assigned to an agent (1 – 5).",
|
||||
"DG.ItemWindow.Profession.AutomaticSkills": "Automatic Skills",
|
||||
"DG.ItemWindow.Profession.OptionSkills": "Skill Options",
|
||||
"DG.ItemWindow.Profession.OptionPicks": "Option Picks",
|
||||
|
||||
@@ -462,16 +462,16 @@ class AddProfessionDialogController {
|
||||
* @returns {{
|
||||
* validationMessages: string[],
|
||||
* capWarnings: { warning: string }[],
|
||||
* atCapMessages: string[],
|
||||
* wasteMessages: string[],
|
||||
* }}
|
||||
*/
|
||||
#getDisplayMessages(computed) {
|
||||
const atCapPrefix = "bonusAtCap:";
|
||||
const wastePrefix = "bonusWaste:";
|
||||
const mainErrors = computed.validationErrors.filter(
|
||||
(code) => !code.startsWith(atCapPrefix),
|
||||
(code) => !code.startsWith(wastePrefix),
|
||||
);
|
||||
const atCapErrors = computed.validationErrors.filter((code) =>
|
||||
code.startsWith(atCapPrefix),
|
||||
const wasteErrors = computed.validationErrors.filter((code) =>
|
||||
code.startsWith(wastePrefix),
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -485,7 +485,7 @@ class AddProfessionDialogController {
|
||||
waste: w.waste,
|
||||
}),
|
||||
})),
|
||||
atCapMessages: formatProfessionValidationMessages(atCapErrors, {
|
||||
wasteMessages: formatProfessionValidationMessages(wasteErrors, {
|
||||
optionPicks: this.optionPicks,
|
||||
}),
|
||||
};
|
||||
@@ -496,7 +496,7 @@ class AddProfessionDialogController {
|
||||
* @returns {string}
|
||||
*/
|
||||
#buildMessagesHtml(computed) {
|
||||
const { validationMessages, capWarnings, atCapMessages } =
|
||||
const { validationMessages, capWarnings, wasteMessages } =
|
||||
this.#getDisplayMessages(computed);
|
||||
|
||||
const toErrorHtml = (messages) =>
|
||||
@@ -519,7 +519,9 @@ class AddProfessionDialogController {
|
||||
.join("");
|
||||
|
||||
return (
|
||||
toErrorHtml(validationMessages) + capHtml + toErrorHtml(atCapMessages)
|
||||
toErrorHtml(validationMessages) +
|
||||
capHtml +
|
||||
toErrorHtml(wasteMessages)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import { BASE_TEMPLATE_PATH } from "../config/index.js";
|
||||
import { getDialogContentRoot, showDgDialog } from "./dg-dialog.js";
|
||||
|
||||
const { renderTemplate } = foundry.applications.handlebars;
|
||||
|
||||
/**
|
||||
* @param {Item} professionItem
|
||||
* @returns {Promise<boolean>} True if the name was updated.
|
||||
*/
|
||||
export async function showRenameProfessionDialog(professionItem) {
|
||||
if (professionItem.type !== "profession") return false;
|
||||
|
||||
const content = await renderTemplate(
|
||||
`${BASE_TEMPLATE_PATH}/dialog/rename-profession.html`,
|
||||
{ name: professionItem.name },
|
||||
);
|
||||
|
||||
const result = await showDgDialog({
|
||||
modifier: "rename-profession",
|
||||
content,
|
||||
position: { width: 360 },
|
||||
window: {
|
||||
title: game.i18n.localize("DG.AgentSheet.RenameProfession.Title"),
|
||||
},
|
||||
default: "submit",
|
||||
buttons: [
|
||||
{
|
||||
default: true,
|
||||
action: "submit",
|
||||
label: game.i18n.localize("DG.Profession.Dialog.Submit"),
|
||||
callback: (_event, _button, dialog) => {
|
||||
const name = getDialogContentRoot(dialog)
|
||||
?.querySelector("[name='profession-rename']")
|
||||
?.value?.trim();
|
||||
return name || null;
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
if (!result || result === professionItem.name) return false;
|
||||
|
||||
await professionItem.update({ name: result });
|
||||
return true;
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import { showDgDialog } from "../applications/dg-dialog.js";
|
||||
|
||||
function GetAttacksFromInput(inputText) {
|
||||
const attacks = [];
|
||||
try {
|
||||
@@ -661,14 +663,16 @@ async function GetUserInput() {
|
||||
</div>
|
||||
</form>`;
|
||||
|
||||
new foundry.applications.api.DialogV2({
|
||||
window: { title: "Stat Block Parser" },
|
||||
await showDgDialog({
|
||||
modifier: "stat-parser",
|
||||
content,
|
||||
window: { title: "Stat Block Parser" },
|
||||
buttons: [
|
||||
{
|
||||
label: "PARSE",
|
||||
action: "roll",
|
||||
callback: (event, button, dialog) => {
|
||||
default: true,
|
||||
callback: (_event, _button, dialog) => {
|
||||
const textInput =
|
||||
dialog.element.querySelector("[name=parse-input]")?.value;
|
||||
|
||||
@@ -679,9 +683,9 @@ async function GetUserInput() {
|
||||
},
|
||||
},
|
||||
],
|
||||
}).render(true);
|
||||
});
|
||||
}
|
||||
|
||||
export default async function ParseDeltaGreenStatBlock() {
|
||||
GetUserInput();
|
||||
await GetUserInput();
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ function getBonusTrackBaseValue(trackKey, baseFixed, baseTyped, defaults) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Bonus skill slots that would waste 20+ points or raise a skill already at the creation cap.
|
||||
* Bonus skill slots that would waste 20+ points over the creation cap (skill below 80).
|
||||
*
|
||||
* @param {Record<string, number>} baseFixed
|
||||
* @param {Record<string, { group: string, label: string, value: number }>} baseTyped
|
||||
@@ -191,7 +191,7 @@ export function collectBonusCapValidationErrors(
|
||||
);
|
||||
const final = base + count * BONUS_SKILL_INCREMENT;
|
||||
const waste = Math.max(0, final - SKILL_CAP);
|
||||
if (base >= SKILL_CAP || waste >= MAX_ALLOWED_BONUS_WASTE) {
|
||||
if (base < SKILL_CAP && waste >= MAX_ALLOWED_BONUS_WASTE) {
|
||||
violatingTrackKeys.add(trackKey);
|
||||
}
|
||||
}
|
||||
@@ -212,11 +212,7 @@ export function collectBonusCapValidationErrors(
|
||||
const final = base + count * BONUS_SKILL_INCREMENT;
|
||||
const waste = Math.max(0, final - SKILL_CAP);
|
||||
|
||||
if (base >= SKILL_CAP) {
|
||||
errors.push(`bonusAtCap:${i}|${trackKey}`);
|
||||
} else {
|
||||
errors.push(`bonusWaste:${i}|${waste}|${trackKey}`);
|
||||
}
|
||||
errors.push(`bonusWaste:${i}|${waste}|${trackKey}`);
|
||||
}
|
||||
|
||||
return errors;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BONUS_SKILL_COUNT, MAX_ALLOWED_BONUS_WASTE } from "./constants.js";
|
||||
import { BONUS_SKILL_COUNT } from "./constants.js";
|
||||
import { catalogIdToSkillRef, getBonusTrackLabel } from "./catalog.js";
|
||||
import {
|
||||
getTypedGroupDisplayName,
|
||||
@@ -135,7 +135,7 @@ export function formatProfessionValidationMessages(
|
||||
/** @type {Set<string>} */
|
||||
const typedNameRequiredGroups = new Set();
|
||||
/** @type {string[]} */
|
||||
const bonusAtCapTrackKeys = [];
|
||||
const bonusWasteTrackKeys = [];
|
||||
|
||||
for (const code of errors) {
|
||||
if (code === "optionPicks") {
|
||||
@@ -150,21 +150,9 @@ export function formatProfessionValidationMessages(
|
||||
needsBondRelationship = true;
|
||||
continue;
|
||||
}
|
||||
const bonusAtCap = code.match(/^bonusAtCap:\d+\|(.+)$/);
|
||||
if (bonusAtCap) {
|
||||
bonusAtCapTrackKeys.push(bonusAtCap[1]);
|
||||
continue;
|
||||
}
|
||||
|
||||
const bonusWaste = code.match(/^bonusWaste:\d+\|(\d+)\|(.+)$/);
|
||||
if (bonusWaste) {
|
||||
push(
|
||||
game.i18n.format("DG.Profession.Dialog.BonusSkillWasteTooHigh", {
|
||||
skill: getBonusTrackLabel(bonusWaste[2]),
|
||||
waste: Number(bonusWaste[1]),
|
||||
maxWaste: MAX_ALLOWED_BONUS_WASTE - 1,
|
||||
}),
|
||||
);
|
||||
bonusWasteTrackKeys.push(bonusWaste[2]);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -226,9 +214,9 @@ export function formatProfessionValidationMessages(
|
||||
push(game.i18n.localize("DG.Profession.Dialog.BondRelationshipRequired"));
|
||||
}
|
||||
|
||||
for (const trackKey of bonusAtCapTrackKeys) {
|
||||
for (const trackKey of bonusWasteTrackKeys) {
|
||||
push(
|
||||
game.i18n.format("DG.Profession.Dialog.BonusSkillAlreadyAtCap", {
|
||||
game.i18n.format("DG.Profession.Dialog.BonusSkillWasteTooHigh", {
|
||||
skill: getBonusTrackLabel(trackKey),
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { createDGChatMessage } from "../chat/dg-chat-card.js";
|
||||
import DG from "../config/index.js";
|
||||
import { formatProfessionSkillLabel } from "../profession/index.js";
|
||||
|
||||
/**
|
||||
* @param {"1"|"d3"|"d4"|"d4-1"} baseFormula
|
||||
@@ -68,23 +69,24 @@ export async function createSkillImprovementChatMessage({
|
||||
failedTypedSkills,
|
||||
resultObj,
|
||||
}) {
|
||||
const localizeFailedSkills = (skillsArray) => {
|
||||
const localizeFailedSkills = (skillsArray, kind) => {
|
||||
return skillsArray.map((skill) => {
|
||||
const increment = resultObj[skill.key] ?? 1;
|
||||
const label =
|
||||
skill.label ?? game.i18n.localize(`DG.Skills.${skill.key}`);
|
||||
const groupLabel = skill.group
|
||||
? `${game.i18n.localize(
|
||||
`DG.TypeSkills.${skill.group.replace(/\s+/g, "")}`,
|
||||
)} (${label})`
|
||||
: label;
|
||||
kind === "typed"
|
||||
? formatProfessionSkillLabel({
|
||||
kind: "typed",
|
||||
group: skill.group,
|
||||
label: skill.label,
|
||||
})
|
||||
: formatProfessionSkillLabel({ kind: "fixed", key: skill.key });
|
||||
|
||||
return `${groupLabel}: <b>+${increment}%</b>`;
|
||||
return `${label}: <b>+${increment}%</b>`;
|
||||
});
|
||||
};
|
||||
|
||||
const failedSkillNames = localizeFailedSkills(failedSkills);
|
||||
const failedTypedSkillNames = localizeFailedSkills(failedTypedSkills);
|
||||
const failedSkillNames = localizeFailedSkills(failedSkills, "fixed");
|
||||
const failedTypedSkillNames = localizeFailedSkills(failedTypedSkills, "typed");
|
||||
|
||||
const content = [...failedSkillNames, ...failedTypedSkillNames].join(", ");
|
||||
const label = game.i18n.format(
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
} from "../active-effect/runtime/stimulant-effect.js";
|
||||
import { assignProfessionToAgent } from "../applications/profession-setup-flow.js";
|
||||
import { showDgDialog } from "../applications/dg-dialog.js";
|
||||
import { showRenameProfessionDialog } from "../applications/rename-profession-dialog.js";
|
||||
import { PROFESSION_OPTION_PICKS_KEY } from "../data/item/profession.js";
|
||||
|
||||
const { renderTemplate } = foundry.applications.handlebars;
|
||||
@@ -292,12 +293,13 @@ export default class DGAgentSheet extends AgentSheetBase {
|
||||
* @param {PointerEvent} _event
|
||||
* @param {HTMLElement} target
|
||||
*/
|
||||
static _openProfessionItem(_event, target) {
|
||||
static async _openProfessionItem(_event, target) {
|
||||
const itemId =
|
||||
target.dataset.itemId ??
|
||||
target.closest("[data-item-id]")?.dataset?.itemId;
|
||||
const item = this.actor.items.get(itemId);
|
||||
if (item?.type === "profession") item.sheet.render(true);
|
||||
if (item?.type !== "profession") return;
|
||||
await showRenameProfessionDialog(item);
|
||||
}
|
||||
|
||||
static _clearBondDamage() {
|
||||
@@ -550,6 +552,18 @@ export default class DGAgentSheet extends AgentSheetBase {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Record<string, object>} skillMap
|
||||
* @returns {object[]}
|
||||
*/
|
||||
static _collectFailedSkills(skillMap) {
|
||||
return Object.entries(skillMap)
|
||||
.filter(
|
||||
([, skill]) => skill.failure && !skill.cannotBeImprovedByFailure,
|
||||
)
|
||||
.map(([key, skill]) => ({ ...skill, key }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs through the whole process of improving skills,
|
||||
* i.e., prompting the user, rolling, and creating the chat card.
|
||||
@@ -559,12 +573,8 @@ export default class DGAgentSheet extends AgentSheetBase {
|
||||
static async _processSkillImprovements() {
|
||||
const { skills, typedSkills } = this.actor.system;
|
||||
|
||||
const failedSkills = Object.values(skills).filter(
|
||||
(skill) => skill.failure && !skill.cannotBeImprovedByFailure,
|
||||
);
|
||||
const failedTypedSkills = Object.values(typedSkills).filter(
|
||||
(skill) => skill.failure && !skill.cannotBeImprovedByFailure,
|
||||
);
|
||||
const failedSkills = DGAgentSheet._collectFailedSkills(skills);
|
||||
const failedTypedSkills = DGAgentSheet._collectFailedSkills(typedSkills);
|
||||
|
||||
if (failedSkills.length + failedTypedSkills.length === 0) {
|
||||
ui.notifications.warn("DG.Skills.ApplySkillImprovements.Warning", {
|
||||
@@ -640,14 +650,16 @@ export default class DGAgentSheet extends AgentSheetBase {
|
||||
failedTypedSkills,
|
||||
) {
|
||||
const localizedFailedSkills = failedSkills.map((skill) =>
|
||||
game.i18n.localize(`DG.Skills.${skill.key}`),
|
||||
formatProfessionSkillLabel({ kind: "fixed", key: skill.key }),
|
||||
);
|
||||
|
||||
const localizedFailedTypedSkills = failedTypedSkills.map((skill) => {
|
||||
const groupKey = `DG.TypeSkills.${skill.group.replace(/\s+/g, "")}`;
|
||||
const groupLabel = game.i18n.localize(groupKey);
|
||||
return `${groupLabel} (${skill.label})`;
|
||||
});
|
||||
const localizedFailedTypedSkills = failedTypedSkills.map((skill) =>
|
||||
formatProfessionSkillLabel({
|
||||
kind: "typed",
|
||||
group: skill.group,
|
||||
label: skill.label,
|
||||
}),
|
||||
);
|
||||
|
||||
const failedSkillNames = [
|
||||
...localizedFailedSkills,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { DialogV2 } = foundry.applications.api;
|
||||
import { showDgDialog } from "../../applications/dg-dialog.js";
|
||||
|
||||
/** @param {typeof foundry.applications.api.ApplicationV2} Base */
|
||||
export default function ItemListMixin(Base) {
|
||||
@@ -189,41 +189,43 @@ export default function ItemListMixin(Base) {
|
||||
|
||||
static _browsePack(event, target) {
|
||||
const { packType } = target.dataset;
|
||||
switch (packType) {
|
||||
case "weapon": {
|
||||
new DialogV2({
|
||||
window: { title: "Select Compendium" },
|
||||
buttons: [
|
||||
{
|
||||
action: "firearms",
|
||||
label: game.i18n.localize("DG.Gear.WeaponTypes.Firearms"),
|
||||
icon: '<i class="fas fa-crosshairs"></i>',
|
||||
callback: () =>
|
||||
game.packs
|
||||
.find((k) => k.collection === "deltagreen.firearms")
|
||||
.render(true),
|
||||
},
|
||||
{
|
||||
action: "melee",
|
||||
label: game.i18n.localize("DG.Gear.WeaponTypes.Melee"),
|
||||
icon: '<i class="far fa-hand-rock"></i>',
|
||||
callback: () =>
|
||||
game.packs
|
||||
.find(
|
||||
(k) => k.collection === "deltagreen.hand-to-hand-weapons",
|
||||
)
|
||||
.render(true),
|
||||
},
|
||||
],
|
||||
}).render(true);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
game.packs
|
||||
.find((k) => k.collection === `deltagreen.${packType}`)
|
||||
.render(true);
|
||||
break;
|
||||
if (packType === "weapon") {
|
||||
void this._browseWeaponPack();
|
||||
return;
|
||||
}
|
||||
|
||||
game.packs
|
||||
.find((k) => k.collection === `deltagreen.${packType}`)
|
||||
.render(true);
|
||||
}
|
||||
|
||||
async _browseWeaponPack() {
|
||||
await showDgDialog({
|
||||
modifier: "browse-weapon-pack",
|
||||
window: {
|
||||
title: game.i18n.localize("DG.Gear.SelectCompendium"),
|
||||
},
|
||||
buttons: [
|
||||
{
|
||||
action: "firearms",
|
||||
label: game.i18n.localize("DG.Gear.WeaponTypes.Firearms"),
|
||||
icon: '<i class="fas fa-crosshairs"></i>',
|
||||
callback: () =>
|
||||
game.packs
|
||||
.find((k) => k.collection === "deltagreen.firearms")
|
||||
.render(true),
|
||||
},
|
||||
{
|
||||
action: "melee",
|
||||
label: game.i18n.localize("DG.Gear.WeaponTypes.Melee"),
|
||||
icon: '<i class="far fa-hand-rock"></i>',
|
||||
callback: () =>
|
||||
game.packs
|
||||
.find((k) => k.collection === "deltagreen.hand-to-hand-weapons")
|
||||
.render(true),
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { DialogV2 } = foundry.applications.api;
|
||||
import { showDgDialog } from "../../applications/dg-dialog.js";
|
||||
|
||||
/** @param {typeof foundry.applications.api.ApplicationV2} Base */
|
||||
export default function SpecialTrainingMixin(Base) {
|
||||
@@ -23,7 +23,7 @@ export default function SpecialTrainingMixin(Base) {
|
||||
}
|
||||
break;
|
||||
default:
|
||||
this._showSpecialTrainingDialog(actionType, id);
|
||||
void this._showSpecialTrainingDialog(actionType, id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,8 @@ export default function SpecialTrainingMixin(Base) {
|
||||
`DG.SpecialTraining.Dialog.${action.capitalize()}SpecialTraining`,
|
||||
);
|
||||
|
||||
new DialogV2({
|
||||
await showDgDialog({
|
||||
modifier: "special-training",
|
||||
content,
|
||||
window: {
|
||||
title: game.i18n.localize("DG.SpecialTraining.Dialog.Title"),
|
||||
@@ -106,7 +107,7 @@ export default function SpecialTrainingMixin(Base) {
|
||||
default: true,
|
||||
action: "confirm",
|
||||
label: buttonLabel,
|
||||
callback: (event, button, dialog) => {
|
||||
callback: (_event, _button, dialog) => {
|
||||
const specialTrainingLabel = dialog.element.querySelector(
|
||||
"[name='special-training-label']",
|
||||
)?.value;
|
||||
@@ -127,7 +128,7 @@ export default function SpecialTrainingMixin(Base) {
|
||||
},
|
||||
},
|
||||
],
|
||||
}).render(true);
|
||||
});
|
||||
}
|
||||
|
||||
_createSpecialTraining(label, attribute) {
|
||||
|
||||
@@ -1,4 +1,23 @@
|
||||
const { DialogV2 } = foundry.applications.api;
|
||||
import { showDgDialog } from "../../applications/dg-dialog.js";
|
||||
import { BASE_TEMPLATE_PATH } from "../../config/index.js";
|
||||
import {
|
||||
TYPED_GROUP_I18N,
|
||||
TYPED_SKILL_TEMPLATE_GROUPS,
|
||||
} from "../../profession/constants.js";
|
||||
|
||||
const { renderTemplate } = foundry.applications.handlebars;
|
||||
|
||||
/**
|
||||
* @param {string} [selectedGroup]
|
||||
* @returns {{ value: string, label: string, selected: boolean }[]}
|
||||
*/
|
||||
function buildTypedSkillGroupOptions(selectedGroup) {
|
||||
return TYPED_SKILL_TEMPLATE_GROUPS.map((value) => ({
|
||||
value,
|
||||
label: game.i18n.localize(TYPED_GROUP_I18N[value]),
|
||||
selected: value === selectedGroup,
|
||||
}));
|
||||
}
|
||||
|
||||
/** @param {typeof foundry.applications.api.ApplicationV2} Base */
|
||||
export default function TypedSkillMixin(Base) {
|
||||
@@ -7,10 +26,13 @@ export default function TypedSkillMixin(Base) {
|
||||
const { actionType, typedskill } = target.dataset;
|
||||
switch (actionType) {
|
||||
case "create":
|
||||
this._showNewTypeSkillDialog();
|
||||
void this._showTypedSkillDialog({ mode: "create" });
|
||||
break;
|
||||
case "edit":
|
||||
this._showNewEditTypeSkillDialog(typedskill);
|
||||
void this._showTypedSkillDialog({
|
||||
mode: "edit",
|
||||
targetSkill: typedskill,
|
||||
});
|
||||
break;
|
||||
case "delete":
|
||||
this.actor.update({ [`system.typedSkills.-=${typedskill}`]: null });
|
||||
@@ -20,215 +42,61 @@ export default function TypedSkillMixin(Base) {
|
||||
}
|
||||
}
|
||||
|
||||
_showNewEditTypeSkillDialog(targetSkill) {
|
||||
const { typedSkills } = this.actor.system;
|
||||
const currentLabel = typedSkills[targetSkill].label;
|
||||
const currentGroup = typedSkills[targetSkill].group;
|
||||
/**
|
||||
* @param {{ mode: "create" | "edit", targetSkill?: string }} options
|
||||
*/
|
||||
async _showTypedSkillDialog({ mode, targetSkill }) {
|
||||
const isEdit = mode === "edit";
|
||||
const typedSkills = this.actor.system.typedSkills;
|
||||
const currentLabel = isEdit ? typedSkills[targetSkill].label : "";
|
||||
const currentGroup = isEdit
|
||||
? typedSkills[targetSkill].group
|
||||
: TYPED_SKILL_TEMPLATE_GROUPS[0];
|
||||
|
||||
let htmlContent = `<div>`;
|
||||
htmlContent += ` <label>${
|
||||
game.i18n.translations.DG?.Skills?.SkillGroup ?? "Skill Group"
|
||||
}:</label>`;
|
||||
htmlContent += ` <select name="new-type-skill-group" />`;
|
||||
|
||||
if (currentGroup === game.i18n.translations.DG?.TypeSkills?.Art ?? "Art") {
|
||||
htmlContent += ` <option value="Art" selected>${
|
||||
game.i18n.translations.DG?.TypeSkills?.Art ?? "Art"
|
||||
}</option>`;
|
||||
} else {
|
||||
htmlContent += ` <option value="Art">${
|
||||
game.i18n.translations.DG?.TypeSkills?.Art ?? "Art"
|
||||
}</option>`;
|
||||
}
|
||||
|
||||
if (
|
||||
currentGroup === game.i18n.translations.DG?.TypeSkills?.Craft ??
|
||||
"Craft"
|
||||
) {
|
||||
htmlContent += ` <option value="Craft" selected>${
|
||||
game.i18n.translations.DG?.TypeSkills?.Craft ?? "Craft"
|
||||
}</option>`;
|
||||
} else {
|
||||
htmlContent += ` <option value="Craft">${
|
||||
game.i18n.translations.DG?.TypeSkills?.Craft ?? "Craft"
|
||||
}</option>`;
|
||||
}
|
||||
|
||||
if (
|
||||
currentGroup ===
|
||||
(game.i18n.translations.DG?.TypeSkills?.ForeignLanguage ??
|
||||
"Foreign Language")
|
||||
) {
|
||||
htmlContent += ` <option value="ForeignLanguage" selected>${
|
||||
game.i18n.translations.DG?.TypeSkills?.ForeignLanguage ??
|
||||
"Foreign Language"
|
||||
}</option>`;
|
||||
} else {
|
||||
htmlContent += ` <option value="ForeignLanguage">${
|
||||
game.i18n.translations.DG?.TypeSkills?.ForeignLanguage ??
|
||||
"Foreign Language"
|
||||
}</option>`;
|
||||
}
|
||||
|
||||
if (
|
||||
currentGroup ===
|
||||
(game.i18n.translations.DG?.TypeSkills?.MilitaryScience ??
|
||||
"Military Science")
|
||||
) {
|
||||
htmlContent += ` <option value="MilitaryScience" selected>${
|
||||
game.i18n.translations.DG?.TypeSkills?.MilitaryScience ??
|
||||
"Military Science"
|
||||
}</option>`;
|
||||
} else {
|
||||
htmlContent += ` <option value="MilitaryScience">${
|
||||
game.i18n.translations.DG?.TypeSkills?.MilitaryScience ??
|
||||
"Military Science"
|
||||
}</option>`;
|
||||
}
|
||||
|
||||
if (
|
||||
currentGroup === game.i18n.translations.DG?.TypeSkills?.Pilot ?? "Pilot"
|
||||
) {
|
||||
htmlContent += ` <option value="Pilot" selected>${
|
||||
game.i18n.translations.DG?.TypeSkills?.Pilot ?? "Pilot"
|
||||
}</option>`;
|
||||
} else {
|
||||
htmlContent += ` <option value="Pilot">${
|
||||
game.i18n.translations.DG?.TypeSkills?.Pilot ?? "Pilot"
|
||||
}</option>`;
|
||||
}
|
||||
|
||||
if (
|
||||
currentGroup ===
|
||||
(game.i18n.translations.DG?.TypeSkills?.Science ?? "Science")
|
||||
) {
|
||||
htmlContent += ` <option value="Science" selected>${
|
||||
game.i18n.translations.DG?.TypeSkills?.Science ?? "Science"
|
||||
}</option>`;
|
||||
} else {
|
||||
htmlContent += ` <option value="Science">${
|
||||
game.i18n.translations.DG?.TypeSkills?.Science ?? "Science"
|
||||
}</option>`;
|
||||
}
|
||||
|
||||
if (
|
||||
currentGroup === game.i18n.translations.DG?.TypeSkills?.Other ?? "Other"
|
||||
) {
|
||||
htmlContent += ` <option value="Other" selected>${
|
||||
game.i18n.translations.DG?.TypeSkills?.Other ?? "Other"
|
||||
}</option>`;
|
||||
} else {
|
||||
htmlContent += ` <option value="Other">${
|
||||
game.i18n.translations.DG?.TypeSkills?.Other ?? "Other"
|
||||
}</option>`;
|
||||
}
|
||||
|
||||
htmlContent += ` </select>`;
|
||||
htmlContent += `</div>`;
|
||||
|
||||
htmlContent += `<div>`;
|
||||
htmlContent += ` <label>${
|
||||
game.i18n.translations.DG?.Skills.SkillName ?? "Skill Name"
|
||||
}</label>`;
|
||||
htmlContent += ` <input type="text" name="new-type-skill-label" value="${currentLabel}" />`;
|
||||
htmlContent += `</div>`;
|
||||
|
||||
new DialogV2({
|
||||
content: htmlContent,
|
||||
window: {
|
||||
title:
|
||||
game.i18n.translations.DG?.Skills?.EditTypedOrCustomSkill ??
|
||||
"Edit Typed or Custom Skill",
|
||||
const content = await renderTemplate(
|
||||
`${BASE_TEMPLATE_PATH}/dialog/typed-skill.html`,
|
||||
{
|
||||
groups: buildTypedSkillGroupOptions(currentGroup),
|
||||
label: currentLabel,
|
||||
},
|
||||
);
|
||||
|
||||
const titleKey = isEdit
|
||||
? "DG.Skills.EditTypedOrCustomSkill"
|
||||
: "DG.Skills.AddTypedOrCustomSkill";
|
||||
const buttonKey = isEdit ? "DG.Skills.EditSkill" : "DG.Skills.AddSkill";
|
||||
|
||||
await showDgDialog({
|
||||
modifier: "typed-skill",
|
||||
content,
|
||||
position: { width: 320 },
|
||||
window: { title: game.i18n.localize(titleKey) },
|
||||
default: "submit",
|
||||
buttons: [
|
||||
{
|
||||
default: true,
|
||||
action: "add",
|
||||
label: game.i18n.translations.DG?.Skills?.EditSkill ?? "Edit Skill",
|
||||
callback: (event, button, dialog) => {
|
||||
action: "submit",
|
||||
label: game.i18n.localize(buttonKey),
|
||||
callback: (_event, _button, dialog) => {
|
||||
const newTypeSkillLabel = dialog.element.querySelector(
|
||||
"[name='new-type-skill-label']",
|
||||
)?.value;
|
||||
const newTypeSkillGroup = dialog.element.querySelector(
|
||||
"[name='new-type-skill-group']",
|
||||
)?.value;
|
||||
this._updateTypedSkill(
|
||||
targetSkill,
|
||||
newTypeSkillLabel,
|
||||
newTypeSkillGroup,
|
||||
);
|
||||
if (isEdit) {
|
||||
this._updateTypedSkill(
|
||||
targetSkill,
|
||||
newTypeSkillLabel,
|
||||
newTypeSkillGroup,
|
||||
);
|
||||
} else {
|
||||
this._addNewTypedSkill(newTypeSkillLabel, newTypeSkillGroup);
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
}).render(true);
|
||||
}
|
||||
|
||||
_showNewTypeSkillDialog() {
|
||||
let htmlContent = "";
|
||||
|
||||
htmlContent += `<div>`;
|
||||
htmlContent += ` <label>${
|
||||
game.i18n.translations.DG?.Skills?.SkillGroup ?? "Skill Group"
|
||||
}:</label>`;
|
||||
htmlContent += ` <select name="new-type-skill-group" />`;
|
||||
htmlContent += ` <option value="Art">${
|
||||
game.i18n.translations.DG?.TypeSkills?.Art ?? "Art"
|
||||
}</option>`;
|
||||
htmlContent += ` <option value="Craft">${
|
||||
game.i18n.translations.DG?.TypeSkills?.Craft ?? "Craft"
|
||||
}</option>`;
|
||||
htmlContent += ` <option value="ForeignLanguage">${
|
||||
game.i18n.translations.DG?.TypeSkills?.ForeignLanguage ??
|
||||
"Foreign Language"
|
||||
}</option>`;
|
||||
htmlContent += ` <option value="MilitaryScience">${
|
||||
game.i18n.translations.DG?.TypeSkills?.MilitaryScience ??
|
||||
"Military Science"
|
||||
}</option>`;
|
||||
htmlContent += ` <option value="Pilot">${
|
||||
game.i18n.translations.DG?.TypeSkills?.Pilot ?? "Pilot"
|
||||
}</option>`;
|
||||
htmlContent += ` <option value="Science">${
|
||||
game.i18n.translations.DG?.TypeSkills?.Science ?? "Science"
|
||||
}</option>`;
|
||||
htmlContent += ` <option value="Other">${
|
||||
game.i18n.translations.DG?.TypeSkills?.Other ?? "Other"
|
||||
}</option>`;
|
||||
htmlContent += ` </select>`;
|
||||
htmlContent += `</div>`;
|
||||
|
||||
htmlContent += `<div>`;
|
||||
htmlContent += ` <label>${
|
||||
game.i18n.translations.DG?.Skills.SkillName ?? "Skill Name"
|
||||
}</label>`;
|
||||
htmlContent += ` <input type="text" name="new-type-skill-label" />`;
|
||||
htmlContent += `</div>`;
|
||||
|
||||
new DialogV2({
|
||||
content: htmlContent,
|
||||
window: {
|
||||
title:
|
||||
game.i18n.translations.DG?.Skills?.AddTypedOrCustomSkill ??
|
||||
"Add Typed or Custom Skill",
|
||||
},
|
||||
default: "add",
|
||||
buttons: [
|
||||
{
|
||||
default: true,
|
||||
action: "add",
|
||||
label: game.i18n.translations.DG?.Skills?.AddSkill ?? "Add Skill",
|
||||
callback: (event, button, dialog) => {
|
||||
const newTypeSkillLabel = dialog.element.querySelector(
|
||||
"[name='new-type-skill-label']",
|
||||
)?.value;
|
||||
const newTypeSkillGroup = dialog.element.querySelector(
|
||||
"[name='new-type-skill-group']",
|
||||
)?.value;
|
||||
this._addNewTypedSkill(newTypeSkillLabel, newTypeSkillGroup);
|
||||
},
|
||||
},
|
||||
],
|
||||
}).render(true);
|
||||
});
|
||||
}
|
||||
|
||||
_addNewTypedSkill(newSkillLabel, newSkillGroup) {
|
||||
|
||||
@@ -17,15 +17,26 @@
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.left-bar .profession-subname-link {
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
padding: 1px 2px;
|
||||
line-height: var(--line-height-18, 1.125rem);
|
||||
text-decoration: none;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
/* DG global form inputs use height: unset; restore Foundry sizing in the header. */
|
||||
.left-bar .header-name-fields > input {
|
||||
height: var(--input-height);
|
||||
line-height: var(--input-height);
|
||||
}
|
||||
|
||||
.left-bar .header-name-fields > input + input {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.left-bar .header-name-fields > input.profession-subname-display[readonly] {
|
||||
cursor: pointer;
|
||||
--input-background-color: rgba(0, 0, 0, 0.1);
|
||||
--input-border-color: var(--color-dark-6);
|
||||
--input-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
|
||||
--input-text-color: inherit;
|
||||
|
||||
&:hover {
|
||||
--input-background-color: rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
}
|
||||
|
||||
.stats-wrapper {
|
||||
@@ -244,18 +255,18 @@
|
||||
|
||||
.resources .resource-inner-grid-3col input {
|
||||
box-sizing: border-box;
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
width: 1.75rem;
|
||||
height: 1.75rem;
|
||||
padding: 1px;
|
||||
line-height: calc(1.5rem - 4px);
|
||||
line-height: calc(1.75rem - 4px);
|
||||
}
|
||||
|
||||
.resources .resource-inner-grid-3col .max-resource-value {
|
||||
box-sizing: border-box;
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
min-width: 1.5rem;
|
||||
min-height: 1.5rem;
|
||||
width: 1.7rem;
|
||||
height: 1.75rem;
|
||||
min-width: 1.75rem;
|
||||
min-height: 1.75rem;
|
||||
}
|
||||
|
||||
.breaking-point-inline {
|
||||
@@ -807,8 +818,16 @@
|
||||
|
||||
.tab.motivations .items-list .item-header .acute-episode-col,
|
||||
.tab.motivations .items-list .item .acute-episode-col {
|
||||
flex: 0 0 5.5rem;
|
||||
text-align: center;
|
||||
flex: 0 0 7.75rem;
|
||||
min-width: 7.75rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
|
||||
input[type="checkbox"] {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Equipment tab */
|
||||
|
||||
@@ -93,8 +93,16 @@
|
||||
}
|
||||
|
||||
.deltagreen .motivations .acute-episode-col {
|
||||
flex: 0 0 5.5rem;
|
||||
text-align: center;
|
||||
flex: 0 0 7.75rem;
|
||||
min-width: 7.75rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
|
||||
input[type="checkbox"] {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.deltagreen .motivations li.acute-episode-active {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
{{#if professionItem}}
|
||||
<a class="content-link profession-subname-link fill-remaining-space"
|
||||
data-action="openProfessionItem"
|
||||
data-item-id="{{professionItem.id}}"
|
||||
title="{{localize 'DG.AgentSheet.OpenProfessionToEdit'}}">
|
||||
<i class="fas fa-briefcase"></i> {{professionItem.name}}
|
||||
</a>
|
||||
<input class="fill-remaining-space profession-subname-display"
|
||||
type="text"
|
||||
readonly
|
||||
value="{{professionItem.name}}"
|
||||
data-action="openProfessionItem"
|
||||
data-item-id="{{professionItem.id}}"
|
||||
title="{{localize 'DG.AgentSheet.RenameProfession.Tooltip'}}" />
|
||||
{{else}}
|
||||
<input class="fill-remaining-space profession-input"
|
||||
<input class="fill-remaining-space"
|
||||
name="system.biography.profession"
|
||||
type="text"
|
||||
value="{{actor.system.biography.profession}}"
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
|
||||
<li class="item flexrow item-header">
|
||||
<div class="item-name">{{localize 'DG.Mental.Motivations'}}</div>
|
||||
<div class="item-name acute-episode-col">{{localize 'DG.ItemWindow.Motivations.AcuteEpisode'}}</div>
|
||||
<div class="item-name">{{localize 'DG.Mental.Disorders'}}</div>
|
||||
<div class="item-name acute-episode-col">{{localize 'DG.ItemWindow.Motivations.AcuteEpisode'}}</div>
|
||||
<div class="item-controls">
|
||||
<a class="item-control action-pill"
|
||||
data-action="itemAction"
|
||||
@@ -36,6 +36,10 @@
|
||||
{{item.name}}
|
||||
</span>
|
||||
|
||||
<span class="item-name">
|
||||
{{#if item.system.crossedOut }}{{item.system.disorder}}{{/if}}
|
||||
</span>
|
||||
|
||||
<span class="acute-episode-col">
|
||||
<input type="checkbox"
|
||||
{{checked item.system.acuteEpisode}}
|
||||
@@ -44,10 +48,6 @@
|
||||
title="{{localize 'DG.ItemWindow.Motivations.AcuteEpisodeTooltip'}}" />
|
||||
</span>
|
||||
|
||||
{{#if item.system.crossedOut }}
|
||||
<span class="item-name">{{item.system.disorder}}</span>
|
||||
{{/if}}
|
||||
|
||||
<div class="item-controls">
|
||||
<a class="item-control"
|
||||
data-action="itemAction"
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<div class="dg-dialog dg-dialog--rename-profession">
|
||||
<div class="dg-dialog__field form-group">
|
||||
<label class="dg-dialog__field-label" for="profession-rename">{{localize "DG.ItemWindow.Profession.Name"}}</label>
|
||||
<input id="profession-rename"
|
||||
type="text"
|
||||
name="profession-rename"
|
||||
value="{{name}}"
|
||||
autofocus />
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,3 +1,4 @@
|
||||
<div class="dg-dialog dg-dialog--special-training">
|
||||
<form class="flexcol">
|
||||
<div class="flexrow">
|
||||
<label>
|
||||
@@ -11,4 +12,5 @@
|
||||
</label>
|
||||
{{{selectElement}}}
|
||||
</div>
|
||||
</form>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<div class="dg-dialog dg-dialog--typed-skill">
|
||||
<div class="dg-dialog__field form-group">
|
||||
<label class="dg-dialog__field-label" for="typed-skill-group">{{localize "DG.Skills.SkillGroup"}}</label>
|
||||
<select id="typed-skill-group" name="new-type-skill-group">
|
||||
{{#each groups}}
|
||||
<option value="{{value}}" {{#if selected}}selected{{/if}}>{{label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="dg-dialog__field form-group">
|
||||
<label class="dg-dialog__field-label" for="typed-skill-label">{{localize "DG.Skills.SkillName"}}</label>
|
||||
<input id="typed-skill-label"
|
||||
type="text"
|
||||
name="new-type-skill-label"
|
||||
value="{{label}}" />
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user