import { onManageActiveEffect, prepareActiveEffectCategories } from "../system/effects.mjs"; import { VermineActorSheet } from "./actor-sheet.mjs"; import { TotemPicker } from "../system/applications.mjs"; /** * Extend the basic ActorSheet for NPC type * @extends {VermineActorSheet} */ export class VermineNpcSheet extends VermineActorSheet { /** @override */ static get defaultOptions() { return foundry.utils.mergeObject(super.defaultOptions, { classes: ["vermine2047", "sheet", "actor", "npc"], template: "systems/vermine2047/templates/actor/actor-sheet.hbs", width: 600, height: 700, tabs: [ { navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "characteristics" } ] }); } /** @override */ get template() { return `systems/vermine2047/templates/actor/actor-${this.actor.type}-sheet.hbs`; } /* -------------------------------------------- */ /** @override */ getData() { // Retrieve the data structure from the base sheet. const context = super.getData(); // Use a safe clone of the actor data for further operations. const actorData = this.actor.toObject(false); // Add the actor's data to context.data for easier access, as well as flags. context.system = actorData.system; context.flags = actorData.flags; context.config = CONFIG.VERMINE; // Prepare items for all actor types this._prepareItems(context); // Prepare NPC-specific data if (actorData.type === 'npc') { this._prepareNpcData(context); } // Add roll data for TinyMCE editors context.rollData = this.actor.getRollData(); // Prepare active effects context.effects = prepareActiveEffectCategories(this.actor.effects); return context; } /** * Prepare NPC specific data */ _prepareNpcData(context) { // Calculate derived values from threat, experience, and role const threat = CONFIG.VERMINE.npcThreatLevels[context.system.threat.value]; const experience = CONFIG.VERMINE.npcExperienceLevels[context.system.experience.value]; const role = CONFIG.VERMINE.npcRoleLevels[context.system.role.value]; // Add calculated values to context for easier access context.threatData = threat; context.experienceData = experience; context.roleData = role; // Set wound thresholds based on threat level if (threat) { context.system.minorWound.threshold = threat.minorWound || context.system.minorWound.threshold; context.system.majorWound.threshold = threat.majorWound || context.system.majorWound.threshold; context.system.deadlyWound.threshold = threat.deadlyWound || context.system.deadlyWound.threshold; // Set max wounds context.system.minorWound.max = threat.minorWound || context.system.minorWound.max; context.system.majorWound.max = threat.majorWound || context.system.majorWound.max; context.system.deadlyWound.max = threat.deadlyWound || context.system.deadlyWound.max; } // Set reserve max values based on role if (role) { context.system.attributes.effort.max = role.pools || context.system.attributes.effort.max; context.system.attributes.self_control.max = role.reaction_bonus || context.system.attributes.self_control.max; } // Prepare abilities with labels for (let [k, v] of Object.entries(context.system.abilities)) { v.label = game.i18n.localize(CONFIG.VERMINE.abilities[k]) ?? k; } // Prepare skills with localized names for (let [k, v] of Object.entries(context.system.skills)) { const skillKey = `VERMINE.skill.${k}`; v.name = game.i18n.localize(skillKey); if (v.name === skillKey) { // Fallback to key if no translation v.name = k.charAt(0).toUpperCase() + k.slice(1); } } // Prepare skill categories for (let [k, v] of Object.entries(context.system.skill_categories)) { if (k !== 'preferred') { v.label = game.i18n.localize(v.label) ?? k; } } } /** * Organize and classify Items for NPC sheets. * * @param {Object} context - The context to prepare. */ _prepareItems(context) { context.gear = this.actor.itemTypes['item']; context.weapons = this.actor.itemTypes['weapon']; context.defenses = this.actor.itemTypes['defense']; context.vehicles = this.actor.itemTypes['vehicle']; context.abilities = this.actor.itemTypes['ability']; context.specialties = this.actor.itemTypes['specialty']; context.backgrounds = this.actor.itemTypes['background']; context.traumas = this.actor.itemTypes['trauma']; context.evolutions = this.actor.itemTypes['evolution']; } /* -------------------------------------------- */ /** @override */ activateListeners(html) { super.activateListeners(html); // Choose Totem html.find('.chooseTotem').click(this._onTotemButton.bind(this)); } /** * Handle totem pick * @param {Event} event - The originating click event * @private */ _onTotemButton(event) { event.preventDefault(); const el = event.currentTarget; const totemPicker = new TotemPicker(el, this.actor); totemPicker.render(true); } }