Release Creation / build (release) Failing after 1m38s
- #getSpecialtyName accédait à this.#el sans garde : fermer le dialogue pendant l'animation du jet levait "Uncaught (in promise)". Chaînage optionnel sur l'élément (le jet se résout quand même et dépense le dé).
545 lines
21 KiB
JavaScript
545 lines
21 KiB
JavaScript
import { VermineUtils } from "../roll.mjs";
|
|
import { VermineExperience } from "../experience.mjs";
|
|
|
|
const { HandlebarsApplicationMixin } = foundry.applications.api;
|
|
|
|
/**
|
|
* Dialogue d'apprentissage (phase d'Expérience).
|
|
* Permet de dépenser des Dés d'Expérience pour tenter de développer une
|
|
* Compétence, une Spécialité, une Caractéristique, une Réserve ou un
|
|
* Dé d'Évolution. La progression est appliquée automatiquement en cas de
|
|
* réussite.
|
|
*/
|
|
export default class LearningDialog extends HandlebarsApplicationMixin(foundry.applications.api.ApplicationV2) {
|
|
|
|
#actor;
|
|
|
|
static DEFAULT_OPTIONS = {
|
|
classes: ["vermine-roll"],
|
|
tag: "form",
|
|
window: {
|
|
icon: "fas fa-graduation-cap",
|
|
resizable: false
|
|
},
|
|
position: {
|
|
width: 560,
|
|
height: 640
|
|
},
|
|
actions: {
|
|
roll: LearningDialog.#onRoll,
|
|
cancel: LearningDialog.#onCancel
|
|
}
|
|
};
|
|
|
|
static PARTS = {
|
|
main: { template: "systems/vermine2047/templates/dialogs/learning-dialog.hbs", scrollable: [""] }
|
|
};
|
|
|
|
static async create({ actorId }) {
|
|
const actor = await game.actors.get(actorId);
|
|
if (!actor) {
|
|
ui.notifications.warn(game.i18n.localize("VERMINE.error_no_actor_selected"));
|
|
return null;
|
|
}
|
|
return new LearningDialog({ actor });
|
|
}
|
|
|
|
constructor(options = {}) {
|
|
super(options);
|
|
this.#actor = options.actor;
|
|
}
|
|
|
|
get title() {
|
|
return game.i18n.localize("VERMINE.open_learning");
|
|
}
|
|
|
|
async _prepareContext() {
|
|
const actor = this.#actor;
|
|
const skills = Object.entries(CONFIG.VERMINE.skills).map(([key, cfg]) => ({
|
|
key,
|
|
name: game.i18n.localize("SKILLS." + key + ".name"),
|
|
category: cfg.category,
|
|
value: actor.system?.skills?.[key]?.value || 0,
|
|
target: Math.min(5, (actor.system?.skills?.[key]?.value || 0) + 1),
|
|
rarity: actor.system?.skills?.[key]?.rarity || 0,
|
|
isDomain: VermineExperience.isPreferredDomain(actor, key)
|
|
}));
|
|
const totem = actor.system?.identity?.totem || "";
|
|
const gameMode = this.#getGameMode();
|
|
const groupLevel = this.#getGroupLevel();
|
|
const totemAbilities = (actor.itemTypes?.ability || [])
|
|
.filter(i =>
|
|
i.system?.type === "character"
|
|
&& !i.system?.learned
|
|
&& i.system?.totem === totem
|
|
&& (i.system?.level?.value || 0) <= gameMode
|
|
&& groupLevel >= (i.system?.level?.value || 0)
|
|
)
|
|
.map(a => ({
|
|
id: a.id,
|
|
name: a.name,
|
|
level: a.system.level.value,
|
|
threshold: a.system.learn.threshold,
|
|
hindrance: a.system.learn.hindrance
|
|
}));
|
|
const backgrounds = (actor.itemTypes?.background || [])
|
|
.filter(i => !i.system?.learned)
|
|
.map(b => ({ id: b.id, name: b.name, asterisk: b.system?.asterisk || false }));
|
|
const human = actor.system?.adaptation?.totems?.human?.value || 0;
|
|
const adapted = actor.system?.adaptation?.totems?.adapted?.value || 0;
|
|
return {
|
|
actor,
|
|
system: actor.system,
|
|
config: CONFIG.VERMINE,
|
|
dice: actor.system?.experience?.dice || 0,
|
|
ageType: actor.system?.identity?.ageType || 2,
|
|
abilities: Object.entries(CONFIG.VERMINE.abilities).map(([key, label]) => ({
|
|
key,
|
|
label: game.i18n.localize(label),
|
|
value: actor.system?.abilities?.[key]?.value || 0
|
|
})),
|
|
reserves: [
|
|
{ key: "self_control", label: game.i18n.localize("VERMINE.self_control"), value: actor.system?.attributes?.self_control?.value || 0, max: actor.system?.attributes?.self_control?.max || 0 },
|
|
{ key: "effort", label: game.i18n.localize("VERMINE.effort"), value: actor.system?.attributes?.effort?.value || 0, max: actor.system?.attributes?.effort?.max || 0 }
|
|
],
|
|
specialties: actor.itemTypes?.specialty || [],
|
|
skills,
|
|
specialtyCount: (actor.itemTypes?.specialty || []).length,
|
|
totem,
|
|
gameMode,
|
|
groupLevel,
|
|
totemAbilities,
|
|
backgrounds,
|
|
reputation: actor.system?.attributes?.reputation?.value ?? 0,
|
|
human,
|
|
adapted,
|
|
canUseAdaptedDie: VermineExperience.canUseAdaptedDie(human, adapted)
|
|
};
|
|
}
|
|
|
|
#getGameMode() {
|
|
return parseInt(game.settings.get("vermine2047", "game-mode") || "1", 10) || 1;
|
|
}
|
|
|
|
#getGroupLevel() {
|
|
const groups = game.actors.filter(a => a.type === "group" && (a.system?.members || []).includes(this.#actor.id));
|
|
return Math.max(0, ...groups.map(g => g.system?.level?.value || 0));
|
|
}
|
|
|
|
#canUseAdaptedDie() {
|
|
const a = this.#actor.system?.adaptation?.totems;
|
|
return VermineExperience.canUseAdaptedDie(a?.human?.value || 0, a?.adapted?.value || 0);
|
|
}
|
|
|
|
#totemCapacityCounts() {
|
|
// Ne comptabilise que les Capacités du Totem courant du personnage
|
|
// (les Capacités liées à un autre Totem ne bloquent pas les limites).
|
|
const totem = this.#actor.system?.identity?.totem;
|
|
const items = (this.#actor.itemTypes?.ability || []).filter(i =>
|
|
i.system?.type === "character" && i.system?.learned && i.system?.totem === totem);
|
|
const byLevel = { 1: 0, 2: 0, 3: 0 };
|
|
for (const i of items) {
|
|
const level = i.system?.level?.value || 0;
|
|
byLevel[level] = (byLevel[level] || 0) + 1;
|
|
}
|
|
return { total: items.length, byLevel };
|
|
}
|
|
|
|
async _onRender() {
|
|
this.element.dataset.actorId = this.#actor.id;
|
|
for (const inp of this.element.querySelectorAll("[data-roll]")) {
|
|
inp.addEventListener("change", () => this.#updateUI());
|
|
}
|
|
this.element.querySelector("#learning-dice")?.addEventListener("input", () => this.#updateUI());
|
|
this.#updateUI();
|
|
}
|
|
|
|
get #el() { return this.element; }
|
|
|
|
#getType() {
|
|
return this.#el.querySelector('input[name="learning-type"]:checked')?.value ?? "skill";
|
|
}
|
|
|
|
#getTargetKey() {
|
|
const type = this.#getType();
|
|
if (type === "characteristic") return this.#el.querySelector("#learning-ability")?.value ?? "";
|
|
if (type === "reserve") return this.#el.querySelector("#learning-reserve")?.value ?? "";
|
|
if (type === "totem") return this.#el.querySelector("#learning-totem")?.value ?? "";
|
|
if (type === "background") return this.#el.querySelector("#learning-background")?.value ?? "";
|
|
return this.#el.querySelector("#learning-target")?.value ?? "";
|
|
}
|
|
|
|
#getReputationDirection() {
|
|
return this.#el.querySelector("#learning-reputation-direction")?.value ?? "reduce";
|
|
}
|
|
|
|
#isAdaptedDieChecked() {
|
|
return Boolean(this.#el.querySelector("#learning-adapted-die")?.checked);
|
|
}
|
|
|
|
#getDiceSpent() {
|
|
return Math.max(1, parseInt(this.#el.querySelector("#learning-dice")?.value, 10) || 1);
|
|
}
|
|
|
|
#getSpecialtyName() {
|
|
// Le dialogue peut avoir été fermé pendant le jet (this.#el null).
|
|
const el = this.#el?.querySelector("#specialty-name");
|
|
return el?.value?.trim() || game.i18n.localize("ITEMS.new_specialty");
|
|
}
|
|
|
|
#compute() {
|
|
const actor = this.#actor;
|
|
const type = this.#getType();
|
|
const key = this.#getTargetKey();
|
|
let label = "";
|
|
let targetLevel = null;
|
|
|
|
if (type === "skill") {
|
|
const current = key ? actor.system?.skills?.[key]?.value || 0 : 0;
|
|
targetLevel = Math.min(5, current + 1);
|
|
const rarity = key ? actor.system?.skills?.[key]?.rarity || 0 : 0;
|
|
label = game.i18n.localize(VermineExperience.skillLevelLabelKey(targetLevel));
|
|
const diff = VermineExperience.skillLearningDifficulty(targetLevel);
|
|
const domain = key ? VermineExperience.isPreferredDomain(actor, key) : false;
|
|
return {
|
|
type,
|
|
key,
|
|
targetLevel,
|
|
difficulty: domain ? Math.max(3, diff - 2) : diff,
|
|
handicap: VermineExperience.skillLearningHandicap(targetLevel, rarity),
|
|
poolModifier: 0,
|
|
label,
|
|
targetLabel: key ? game.i18n.localize("SKILLS." + key + ".name") : ""
|
|
};
|
|
}
|
|
if (type === "specialty") {
|
|
const current = key ? actor.system?.skills?.[key]?.value || 0 : 0;
|
|
const domain = key ? VermineExperience.isPreferredDomain(actor, key) : false;
|
|
label = game.i18n.localize("VERMINE.specialty");
|
|
return {
|
|
type,
|
|
key,
|
|
targetLevel: current,
|
|
difficulty: VermineExperience.specialtyLearningDifficulty(current, domain),
|
|
handicap: VermineExperience.specialtyLearningHandicap(actor.itemTypes?.specialty?.length || 0),
|
|
poolModifier: 0,
|
|
label,
|
|
targetLabel: key ? game.i18n.localize("SKILLS." + key + ".name") : ""
|
|
};
|
|
}
|
|
if (type === "characteristic") {
|
|
const current = key ? actor.system?.abilities?.[key]?.value || 0 : 0;
|
|
label = game.i18n.localize("VERMINE.characteristic");
|
|
return {
|
|
type,
|
|
key,
|
|
targetLevel: current,
|
|
difficulty: VermineExperience.characteristicLearningDifficulty(),
|
|
handicap: current,
|
|
poolModifier: 0,
|
|
label,
|
|
targetLabel: key ? game.i18n.localize(CONFIG.VERMINE.abilities[key]) : ""
|
|
};
|
|
}
|
|
if (type === "reserve") {
|
|
const current = key ? actor.system?.attributes?.[key]?.value || 0 : 0;
|
|
label = game.i18n.localize("VERMINE.reserve");
|
|
return {
|
|
type,
|
|
key,
|
|
targetLevel: current,
|
|
difficulty: VermineExperience.reserveLearningDifficulty(current),
|
|
handicap: VermineExperience.ageHandicap(actor.system?.identity?.ageType || 2),
|
|
poolModifier: 0,
|
|
adaptedDie: false,
|
|
label,
|
|
targetLabel: key ? game.i18n.localize(key === "self_control" ? "VERMINE.self_control" : "VERMINE.effort") : ""
|
|
};
|
|
}
|
|
if (type === "totem") {
|
|
const item = actor.itemTypes?.ability?.find(i => i.id === key);
|
|
const data = item?.system;
|
|
label = game.i18n.localize("VERMINE.learn_totem_ability");
|
|
return {
|
|
type,
|
|
key,
|
|
targetLevel: data?.level?.value || 0,
|
|
difficulty: VermineExperience.totemAbilityLearningDifficulty(data),
|
|
handicap: VermineExperience.totemAbilityLearningHandicap(data),
|
|
poolModifier: 0,
|
|
adaptedDie: false,
|
|
label,
|
|
targetLabel: item?.name || ""
|
|
};
|
|
}
|
|
if (type === "background") {
|
|
const item = actor.itemTypes?.background?.find(i => i.id === key);
|
|
const data = item?.system;
|
|
label = game.i18n.localize("VERMINE.learn_background");
|
|
return {
|
|
type,
|
|
key,
|
|
targetLevel: 0,
|
|
difficulty: VermineExperience.backgroundLearningDifficulty(),
|
|
handicap: VermineExperience.backgroundLearningHandicap(data?.asterisk),
|
|
poolModifier: 0,
|
|
adaptedDie: false,
|
|
label,
|
|
targetLabel: item?.name || ""
|
|
};
|
|
}
|
|
if (type === "reputation") {
|
|
const current = actor.system?.attributes?.reputation?.value ?? 0;
|
|
const direction = this.#getReputationDirection();
|
|
if (direction === "increase") {
|
|
return {
|
|
type,
|
|
key: "increase",
|
|
targetLevel: current,
|
|
difficulty: VermineExperience.reputationIncreaseDifficulty(current),
|
|
handicap: 0,
|
|
poolModifier: 0,
|
|
adaptedDie: false,
|
|
label: game.i18n.localize("VERMINE.learn_reputation"),
|
|
targetLabel: game.i18n.localize("VERMINE.reputation_increase")
|
|
};
|
|
}
|
|
return {
|
|
type,
|
|
key: "reduce",
|
|
targetLevel: Math.max(0, current - 1),
|
|
difficulty: VermineExperience.reputationReduceDifficulty(current),
|
|
handicap: 0,
|
|
poolModifier: 0,
|
|
adaptedDie: false,
|
|
label: game.i18n.localize("VERMINE.learn_reputation"),
|
|
targetLabel: game.i18n.localize("VERMINE.reputation_reduce")
|
|
};
|
|
}
|
|
// evolution
|
|
const human = actor.system?.adaptation?.totems?.human?.value || 0;
|
|
const adapted = actor.system?.adaptation?.totems?.adapted?.value || 0;
|
|
label = game.i18n.localize("VERMINE.evolution_dice");
|
|
return {
|
|
type,
|
|
key,
|
|
targetLevel: actor.system?.experience?.evolution || 0,
|
|
difficulty: VermineExperience.evolutionDifficulty(actor.system?.identity?.ageType || 2),
|
|
handicap: actor.system?.experience?.evolution || 0,
|
|
poolModifier: VermineExperience.evolutionTotemModifier(human, adapted),
|
|
adaptedDie: this.#canUseAdaptedDie() && this.#isAdaptedDieChecked(),
|
|
label,
|
|
targetLabel: ""
|
|
};
|
|
}
|
|
|
|
#updateUI() {
|
|
const type = this.#getType();
|
|
const show = (id, visible) => {
|
|
const el = this.#el.querySelector(id);
|
|
if (el) el.style.display = visible ? "" : "none";
|
|
};
|
|
show("#learning-skill-section", type === "skill" || type === "specialty");
|
|
show("#learning-specialty-section", type === "specialty");
|
|
show("#learning-ability-section", type === "characteristic");
|
|
show("#learning-reserve-section", type === "reserve");
|
|
show("#learning-evolution-section", type === "evolution");
|
|
show("#learning-totem-section", type === "totem");
|
|
show("#learning-background-section", type === "background");
|
|
show("#learning-reputation-section", type === "reputation");
|
|
show("#learning-adapted-die-row", type === "evolution" && this.#canUseAdaptedDie());
|
|
|
|
// Pour une Spécialité, seule une compétence au moins Confirmée (≥2) est valable.
|
|
const skillSelect = this.#el.querySelector("#learning-target");
|
|
if (skillSelect) {
|
|
for (const opt of skillSelect.options) {
|
|
const value = parseInt(opt.dataset.value, 10) || 0;
|
|
opt.hidden = (type === "specialty") ? value < 2 : false;
|
|
}
|
|
}
|
|
|
|
const c = this.#compute();
|
|
const set = (sel, txt) => { const el = this.#el.querySelector(sel); if (el) el.textContent = txt; };
|
|
set("#diff-value", c.difficulty);
|
|
set("#handicap-value", c.handicap);
|
|
set("#required-value", 1 + c.handicap);
|
|
const pool = Math.max(0, this.#getDiceSpent() + c.poolModifier);
|
|
let poolText = `${pool}D${c.poolModifier ? ` (${c.poolModifier >= 0 ? "+" : ""}${c.poolModifier}D)` : ""}`;
|
|
if (c.adaptedDie) poolText += " — " + game.i18n.localize("VERMINE.adapted_die_x2");
|
|
set("#pool-value", poolText);
|
|
if (type === "reputation") {
|
|
const current = this.#actor.system?.attributes?.reputation?.value ?? 0;
|
|
const direction = this.#getReputationDirection();
|
|
set("#reputation-target", direction === "increase"
|
|
? `${current} → ${Math.min(10, current + 1)}+`
|
|
: `${current} → ${Math.max(0, current - 1)}`);
|
|
}
|
|
const poolInput = this.#el.querySelector("#learning-dice");
|
|
if (poolInput) poolInput.max = this.#actor.system?.experience?.dice || 0;
|
|
}
|
|
|
|
static async #onCancel() {
|
|
this.close();
|
|
}
|
|
|
|
static async #onRoll() {
|
|
const actor = this.#actor;
|
|
const ex = actor.system?.experience;
|
|
const dice = ex?.dice || 0;
|
|
const spent = Math.min(this.#getDiceSpent(), dice);
|
|
if (spent < 1) {
|
|
ui.notifications.warn(game.i18n.localize("VERMINE.error_no_experience_dice"));
|
|
return;
|
|
}
|
|
|
|
const c = this.#compute();
|
|
|
|
// Limite : une seule compétence, spécialité, réserve, caractéristique,
|
|
// un seul Dé d'Évolution, Capacité de Totem, Historique ou jet de
|
|
// Réputation par phase.
|
|
if (ex?.learned?.phase === ex?.phase) {
|
|
const flagMap = { skill: "skill", specialty: "specialty", reserve: "reserve", characteristic: "characteristic", evolution: "evolution", totem: "ability", background: "background", reputation: "reputation" };
|
|
if (ex.learned[flagMap[c.type]]) {
|
|
ui.notifications.warn(game.i18n.localize("VERMINE.error_learning_limit"));
|
|
return;
|
|
}
|
|
}
|
|
if (c.type === "skill" && c.targetLevel !== null && (actor.system?.skills?.[c.key]?.value || 0) >= 5) {
|
|
ui.notifications.warn(game.i18n.localize("VERMINE.error_skill_max"));
|
|
return;
|
|
}
|
|
if (c.type === "characteristic" && c.targetLevel !== null && (actor.system?.abilities?.[c.key]?.value || 0) >= 3) {
|
|
ui.notifications.warn(game.i18n.localize("VERMINE.error_characteristic_max"));
|
|
return;
|
|
}
|
|
if (c.type === "specialty" && c.targetLevel !== null && c.targetLevel < 2) {
|
|
ui.notifications.warn(game.i18n.localize("VERMINE.error_specialty_requirement"));
|
|
return;
|
|
}
|
|
if (c.type === "reserve" && c.targetLevel !== null && (actor.system?.attributes?.[c.key]?.max || 0) >= 10) {
|
|
ui.notifications.warn(game.i18n.localize("VERMINE.error_reserve_max"));
|
|
return;
|
|
}
|
|
if (c.type === "totem") {
|
|
const item = actor.itemTypes?.ability?.find(i => i.id === c.key);
|
|
if (!item || item.system?.learned) {
|
|
ui.notifications.warn(game.i18n.localize("VERMINE.no_totem_ability"));
|
|
return;
|
|
}
|
|
const level = item.system?.level?.value || 0;
|
|
if (level > this.#getGameMode()) {
|
|
ui.notifications.warn(game.i18n.localize("VERMINE.error_totem_mode"));
|
|
return;
|
|
}
|
|
if (item.system?.totem !== actor.system?.identity?.totem) {
|
|
ui.notifications.warn(game.i18n.localize("VERMINE.error_totem_totem"));
|
|
return;
|
|
}
|
|
if (this.#getGroupLevel() < level) {
|
|
ui.notifications.warn(game.i18n.localize("VERMINE.error_totem_group_level"));
|
|
return;
|
|
}
|
|
const counts = this.#totemCapacityCounts();
|
|
if (level === 1 && (counts.byLevel[1] || 0) >= 3) {
|
|
ui.notifications.warn(game.i18n.localize("VERMINE.error_totem_limit"));
|
|
return;
|
|
}
|
|
if (level >= 2 && (counts.byLevel[level] || 0) >= 1) {
|
|
ui.notifications.warn(game.i18n.localize("VERMINE.error_totem_limit"));
|
|
return;
|
|
}
|
|
if (counts.total >= 5) {
|
|
ui.notifications.warn(game.i18n.localize("VERMINE.error_totem_limit"));
|
|
return;
|
|
}
|
|
}
|
|
if (c.type === "background") {
|
|
const item = actor.itemTypes?.background?.find(i => i.id === c.key);
|
|
if (!item || item.system?.learned) {
|
|
ui.notifications.warn(game.i18n.localize("VERMINE.no_background"));
|
|
return;
|
|
}
|
|
}
|
|
if (c.type === "reputation") {
|
|
const current = actor.system?.attributes?.reputation?.value ?? 0;
|
|
if (c.key === "reduce" && current <= 0) {
|
|
ui.notifications.warn(game.i18n.localize("VERMINE.error_reputation_min"));
|
|
return;
|
|
}
|
|
if (c.key === "increase" && current >= 10) {
|
|
ui.notifications.warn(game.i18n.localize("VERMINE.error_reputation_max"));
|
|
return;
|
|
}
|
|
}
|
|
if (c.type === "evolution" && c.adaptedDie && !this.#canUseAdaptedDie()) {
|
|
ui.notifications.warn(game.i18n.localize("VERMINE.error_evolution_no_adapted"));
|
|
return;
|
|
}
|
|
|
|
const pool = Math.max(0, spent + c.poolModifier);
|
|
const rollLabel = `${game.i18n.localize("VERMINE.open_learning")} — ${c.label}${c.targetLabel ? " (" + c.targetLabel + ")" : ""}`;
|
|
|
|
const roll = await VermineUtils.roll({
|
|
actor,
|
|
NoD: pool,
|
|
Reroll: 0,
|
|
difficulty: c.difficulty,
|
|
handicap: c.handicap,
|
|
totems: c.adaptedDie ? { adapted: true } : { human: false, adapted: false },
|
|
rollLabel,
|
|
poolBreakdown: { ability: 0, skill: 0, selfControl: 0, specialty: 0, help: 0, tooling: 0, group: 0, total: pool },
|
|
messageFlags: { "vermine-learning": { type: c.type, key: c.key, spent, success: false } }
|
|
});
|
|
|
|
const required = 1 + c.handicap;
|
|
const specialtyName = this.#getSpecialtyName();
|
|
if ((roll._total ?? 0) >= required) {
|
|
await this.#applySuccess(c, specialtyName, roll._total ?? 0);
|
|
}
|
|
// Les Dés d'Expérience sont perdus que le jet soit réussi ou raté.
|
|
await actor.update({ "system.experience.dice": Math.max(0, (actor.system.experience.dice || 0) - spent) });
|
|
this.close();
|
|
}
|
|
|
|
async #applySuccess(c, specialtyName, successes = 0) {
|
|
const actor = this.#actor;
|
|
const updates = {};
|
|
if (c.type === "skill") {
|
|
const current = actor.system.skills[c.key].value || 0;
|
|
updates["system.skills." + c.key + ".value"] = Math.min(5, current + 1);
|
|
updates["system.experience.learned.skill"] = true;
|
|
} else if (c.type === "specialty") {
|
|
await actor.createEmbeddedDocuments("Item", [{ name: specialtyName, type: "specialty", system: { skill: c.key } }]);
|
|
updates["system.experience.learned.specialty"] = true;
|
|
} else if (c.type === "characteristic") {
|
|
const current = actor.system.abilities[c.key].value || 0;
|
|
updates["system.abilities." + c.key + ".value"] = Math.min(3, current + 1);
|
|
updates["system.experience.learned.characteristic"] = true;
|
|
} else if (c.type === "reserve") {
|
|
const bonus = actor.system.experience.reserveBonus?.[c.key] || 0;
|
|
updates["system.experience.reserveBonus." + c.key] = bonus + 1;
|
|
updates["system.experience.learned.reserve"] = true;
|
|
} else if (c.type === "evolution") {
|
|
updates["system.experience.evolution"] = (actor.system.experience.evolution || 0) + 1;
|
|
updates["system.experience.learned.evolution"] = true;
|
|
} else if (c.type === "totem") {
|
|
updates["system.experience.learned.ability"] = true;
|
|
await actor.updateEmbeddedDocuments("Item", [{ _id: c.key, "system.learned": true }]);
|
|
} else if (c.type === "background") {
|
|
updates["system.experience.learned.background"] = true;
|
|
await actor.updateEmbeddedDocuments("Item", [{ _id: c.key, "system.learned": true }]);
|
|
} else if (c.type === "reputation") {
|
|
const current = actor.system?.attributes?.reputation?.value ?? 0;
|
|
if (c.key === "increase") {
|
|
updates["system.attributes.reputation.value"] = Math.min(10, current + successes);
|
|
} else {
|
|
updates["system.attributes.reputation.value"] = Math.max(0, current - 1);
|
|
}
|
|
updates["system.experience.learned.reputation"] = true;
|
|
}
|
|
updates["system.experience.learned.phase"] = actor.system.experience.phase;
|
|
await actor.update(updates);
|
|
ui.notifications.info(game.i18n.localize("VERMINE.learning_success"));
|
|
}
|
|
}
|