Add crew member option with pilot rolls integrated
All checks were successful
Release Creation / build (release) Successful in 48s
All checks were successful
Release Creation / build (release) Successful in 48s
This commit is contained in:
@@ -14,9 +14,100 @@ export default class FTLNomadStarshipSheet extends FTLNomadActorSheet {
|
||||
actions: {
|
||||
createEquipment: FTLNomadStarshipSheet.#onCreateEquipment,
|
||||
createWeapon: FTLNomadStarshipSheet.#onCreateWeapon,
|
||||
removeCrew: FTLNomadStarshipSheet.#onRemoveCrew,
|
||||
viewCrew: FTLNomadStarshipSheet.#onViewCrew,
|
||||
pilotCrew: FTLNomadStarshipSheet.#onPilotCrew,
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a crew member from the starship
|
||||
* @param {Event} event The initiating click event
|
||||
* @param {HTMLElement} target The current target of the event listener
|
||||
*/
|
||||
static async #onRemoveCrew(event, target) {
|
||||
const crewUuid = target.dataset.crewUuid
|
||||
const actor = await fromUuid(crewUuid)
|
||||
|
||||
// Show confirmation dialog
|
||||
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||
window: { title: game.i18n.localize("FTLNOMAD.RemoveCrewTitle") },
|
||||
content: game.i18n.format("FTLNOMAD.RemoveCrewContent", { name: actor?.name || "Unknown" }),
|
||||
rejectClose: false,
|
||||
modal: true
|
||||
})
|
||||
|
||||
if (!confirmed) return
|
||||
|
||||
const currentCrew = this.document.system.crewList || []
|
||||
const updatedCrew = currentCrew.filter(uuid => uuid !== crewUuid)
|
||||
await this.document.update({ "system.crewList": updatedCrew })
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the actor sheet of a crew member
|
||||
* @param {Event} event The initiating click event
|
||||
* @param {HTMLElement} target The current target of the event listener
|
||||
*/
|
||||
static async #onViewCrew(event, target) {
|
||||
const actorUuid = target.closest('.crew-member').dataset.actorUuid
|
||||
const actor = await fromUuid(actorUuid)
|
||||
if (actor) {
|
||||
actor.sheet.render(true)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll a piloting check for a crew member with starship agility bonus
|
||||
* @param {Event} event The initiating click event
|
||||
* @param {HTMLElement} target The current target of the event listener
|
||||
*/
|
||||
static async #onPilotCrew(event, target) {
|
||||
const actorUuid = target.closest('.crew-member').dataset.actorUuid
|
||||
const actor = await fromUuid(actorUuid)
|
||||
|
||||
console.log("Pilot crew - Actor:", actor, "Type:", actor?.type)
|
||||
|
||||
if (!actor) {
|
||||
ui.notifications.warn("Actor not found")
|
||||
return
|
||||
}
|
||||
|
||||
if (actor.type !== "character") {
|
||||
ui.notifications.warn(`This actor is of type "${actor.type}", not "character"`)
|
||||
return
|
||||
}
|
||||
|
||||
// Get starship agility bonus
|
||||
const starshipAgility = this.document.system.agility || 0
|
||||
|
||||
// Get the vehicles skill from the actor
|
||||
const vehiclesSkill = actor.system.skills?.vehicles
|
||||
if (!vehiclesSkill) {
|
||||
ui.notifications.warn(game.i18n.localize("FTLNOMAD.Warning.noVehiclesSkill"))
|
||||
return
|
||||
}
|
||||
|
||||
// Import the Roll class
|
||||
const FTLNomadRoll = (await import("../../documents/roll.mjs")).default
|
||||
|
||||
// Call the roll prompt with the starship agility as a vehicle bonus
|
||||
let roll = await FTLNomadRoll.prompt({
|
||||
rollType: "skill",
|
||||
rollItem: vehiclesSkill,
|
||||
actorId: actor.id,
|
||||
actorName: actor.name,
|
||||
actorImage: actor.img,
|
||||
talents: actor.items.filter(i => i.type === "talent" && i.system.isAdvantage),
|
||||
isEncumbered: actor.system.isEncumbered(),
|
||||
hasTarget: false,
|
||||
vehicleBonus: starshipAgility
|
||||
})
|
||||
if (!roll) return null
|
||||
|
||||
await roll.toMessage({}, { rollMode: roll.options.rollMode })
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
@@ -63,9 +154,35 @@ export default class FTLNomadStarshipSheet extends FTLNomadActorSheet {
|
||||
context.enrichedNotes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.notes, { async: true })
|
||||
context.enrichedModifications = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.modifications, { async: true })
|
||||
|
||||
// Prepare crew members data
|
||||
context.crewMembers = await this.#prepareCrewMembers()
|
||||
|
||||
return context
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare crew members data from stored UUIDs
|
||||
* @returns {Promise<Array>}
|
||||
*/
|
||||
async #prepareCrewMembers() {
|
||||
const crewUuids = this.document.system.crewList || []
|
||||
const crewMembers = []
|
||||
|
||||
for (const uuid of crewUuids) {
|
||||
const actor = await fromUuid(uuid)
|
||||
if (actor) {
|
||||
crewMembers.push({
|
||||
uuid: uuid,
|
||||
id: actor.id,
|
||||
name: actor.name,
|
||||
img: actor.img
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return crewMembers
|
||||
}
|
||||
|
||||
_generateTooltip(type, target) {
|
||||
}
|
||||
|
||||
@@ -128,7 +245,41 @@ export default class FTLNomadStarshipSheet extends FTLNomadActorSheet {
|
||||
case "Item":
|
||||
const item = await fromUuid(data.uuid)
|
||||
return super._onDropItem(item)
|
||||
case "Actor":
|
||||
const actor = await fromUuid(data.uuid)
|
||||
return this.#onDropActor(actor)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle dropping an actor onto the starship sheet to add them to the crew
|
||||
* @param {Actor} actor The actor being dropped
|
||||
*/
|
||||
async #onDropActor(actor) {
|
||||
if (!actor) return
|
||||
|
||||
// Check if actor is of type "character"
|
||||
if (actor.type !== "character") {
|
||||
ui.notifications.info(game.i18n.localize("FTLNOMAD.Warning.onlyCharactersAllowed"))
|
||||
return
|
||||
}
|
||||
// Check if the actor has a linked prototype
|
||||
if (!actor.prototypeToken?.actorLink) {
|
||||
ui.notifications.info(game.i18n.localize("FTLNOMAD.Warning.noLinkedPrototype"))
|
||||
return
|
||||
}
|
||||
|
||||
const currentCrew = this.document.system.crewList || []
|
||||
|
||||
// Check if actor is already in crew
|
||||
if (currentCrew.includes(actor.uuid)) {
|
||||
ui.notifications.warn(game.i18n.localize("FTLNOMAD.Warning.alreadyInCrew"))
|
||||
return
|
||||
}
|
||||
|
||||
// Add actor UUID to crew array
|
||||
const updatedCrew = [...currentCrew, actor.uuid]
|
||||
await this.document.update({ "system.crewList": updatedCrew })
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,9 +14,100 @@ export default class FTLNomadVehicleSheet extends FTLNomadActorSheet {
|
||||
actions: {
|
||||
createEquipment: FTLNomadVehicleSheet.#onCreateEquipment,
|
||||
createWeapon: FTLNomadVehicleSheet.#onCreateWeapon,
|
||||
removeCrew: FTLNomadVehicleSheet.#onRemoveCrew,
|
||||
viewCrew: FTLNomadVehicleSheet.#onViewCrew,
|
||||
pilotCrew: FTLNomadVehicleSheet.#onPilotCrew,
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a crew member from the vehicle
|
||||
* @param {Event} event The initiating click event
|
||||
* @param {HTMLElement} target The current target of the event listener
|
||||
*/
|
||||
static async #onRemoveCrew(event, target) {
|
||||
const crewUuid = target.dataset.crewUuid
|
||||
const actor = await fromUuid(crewUuid)
|
||||
|
||||
// Show confirmation dialog
|
||||
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||
window: { title: game.i18n.localize("FTLNOMAD.RemoveCrewTitle") },
|
||||
content: game.i18n.format("FTLNOMAD.RemoveCrewContent", { name: actor?.name || "Unknown" }),
|
||||
rejectClose: false,
|
||||
modal: true
|
||||
})
|
||||
|
||||
if (!confirmed) return
|
||||
|
||||
const currentCrew = this.document.system.crewList || []
|
||||
const updatedCrew = currentCrew.filter(uuid => uuid !== crewUuid)
|
||||
await this.document.update({ "system.crewList": updatedCrew })
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the actor sheet of a crew member
|
||||
* @param {Event} event The initiating click event
|
||||
* @param {HTMLElement} target The current target of the event listener
|
||||
*/
|
||||
static async #onViewCrew(event, target) {
|
||||
const actorUuid = target.closest('.crew-member').dataset.actorUuid
|
||||
const actor = await fromUuid(actorUuid)
|
||||
if (actor) {
|
||||
actor.sheet.render(true)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll a piloting check for a crew member with vehicle agility bonus
|
||||
* @param {Event} event The initiating click event
|
||||
* @param {HTMLElement} target The current target of the event listener
|
||||
*/
|
||||
static async #onPilotCrew(event, target) {
|
||||
const actorUuid = target.closest('.crew-member').dataset.actorUuid
|
||||
const actor = await fromUuid(actorUuid)
|
||||
|
||||
console.log("Pilot crew - Actor:", actor, "Type:", actor?.type)
|
||||
|
||||
if (!actor) {
|
||||
ui.notifications.warn("Actor not found")
|
||||
return
|
||||
}
|
||||
|
||||
if (actor.type !== "character") {
|
||||
ui.notifications.warn(`This actor is of type "${actor.type}", not "character"`)
|
||||
return
|
||||
}
|
||||
|
||||
// Get vehicle agility bonus
|
||||
const vehicleAgility = this.document.system.agility || 0
|
||||
|
||||
// Get the vehicles skill from the actor
|
||||
const vehiclesSkill = actor.system.skills?.vehicles
|
||||
if (!vehiclesSkill) {
|
||||
ui.notifications.warn(game.i18n.localize("FTLNOMAD.Warning.noVehiclesSkill"))
|
||||
return
|
||||
}
|
||||
|
||||
// Import the Roll class
|
||||
const FTLNomadRoll = (await import("../../documents/roll.mjs")).default
|
||||
|
||||
// Call the roll prompt with the vehicle agility as a vehicle bonus
|
||||
let roll = await FTLNomadRoll.prompt({
|
||||
rollType: "skill",
|
||||
rollItem: vehiclesSkill,
|
||||
actorId: actor.id,
|
||||
actorName: actor.name,
|
||||
actorImage: actor.img,
|
||||
talents: actor.items.filter(i => i.type === "talent" && i.system.isAdvantage),
|
||||
isEncumbered: actor.system.isEncumbered(),
|
||||
hasTarget: false,
|
||||
vehicleBonus: vehicleAgility
|
||||
})
|
||||
if (!roll) return null
|
||||
|
||||
await roll.toMessage({}, { rollMode: roll.options.rollMode })
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
@@ -62,9 +153,35 @@ export default class FTLNomadVehicleSheet extends FTLNomadActorSheet {
|
||||
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true })
|
||||
context.enrichedNotes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.notes, { async: true })
|
||||
|
||||
// Prepare crew members data
|
||||
context.crewMembers = await this.#prepareCrewMembers()
|
||||
|
||||
return context
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare crew members data from stored UUIDs
|
||||
* @returns {Promise<Array>}
|
||||
*/
|
||||
async #prepareCrewMembers() {
|
||||
const crewUuids = this.document.system.crewList || []
|
||||
const crewMembers = []
|
||||
|
||||
for (const uuid of crewUuids) {
|
||||
const actor = await fromUuid(uuid)
|
||||
if (actor) {
|
||||
crewMembers.push({
|
||||
uuid: uuid,
|
||||
id: actor.id,
|
||||
name: actor.name,
|
||||
img: actor.img
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return crewMembers
|
||||
}
|
||||
|
||||
_generateTooltip(type, target) {
|
||||
}
|
||||
|
||||
@@ -128,7 +245,36 @@ export default class FTLNomadVehicleSheet extends FTLNomadActorSheet {
|
||||
case "Item":
|
||||
const item = await fromUuid(data.uuid)
|
||||
return super._onDropItem(item)
|
||||
case "Actor":
|
||||
const actor = await fromUuid(data.uuid)
|
||||
return this.#onDropActor(actor)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle dropping an actor onto the vehicle sheet to add them to the crew
|
||||
* @param {Actor} actor The actor being dropped
|
||||
*/
|
||||
async #onDropActor(actor) {
|
||||
if (!actor) return
|
||||
|
||||
// Check if actor is of type "character"
|
||||
if (actor.type !== "character") {
|
||||
ui.notifications.info(game.i18n.localize("FTLNOMAD.Warning.onlyCharactersAllowed"))
|
||||
return
|
||||
}
|
||||
|
||||
const currentCrew = this.document.system.crewList || []
|
||||
|
||||
// Check if actor is already in crew
|
||||
if (currentCrew.includes(actor.uuid)) {
|
||||
ui.notifications.warn(game.i18n.localize("FTLNOMAD.Warning.alreadyInCrew"))
|
||||
return
|
||||
}
|
||||
|
||||
// Add actor UUID to crew array
|
||||
const updatedCrew = [...currentCrew, actor.uuid]
|
||||
await this.document.update({ "system.crewList": updatedCrew })
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -67,9 +67,12 @@ export default class FTLNomadRoll extends Roll {
|
||||
} else {
|
||||
let mod = options.rollItem?.value || 0
|
||||
fullFormula = `${options.formula} + ${options.skillModifier}D + ${mod} + ${options.rangeModifier}D + ${options.numericModifier}D + ${options.numericModifierSelect}`
|
||||
if (options.vehicleBonus) {
|
||||
fullFormula += ` + ${options.vehicleBonus}`
|
||||
}
|
||||
}
|
||||
// Replace all the "+ -" with "-"
|
||||
fullFormula = fullFormula.replace(/\+\s*\-/g, "- ")
|
||||
fullFormula = fullFormula.replace(/\+\s*-/g, "- ")
|
||||
$('#roll-dialog-full-formula').text(fullFormula)
|
||||
options.fullFormula = fullFormula
|
||||
}
|
||||
@@ -136,10 +139,14 @@ export default class FTLNomadRoll extends Roll {
|
||||
options.numericModifierSelect = 0
|
||||
options.rangeModifier = rangeModifier
|
||||
options.damageModifier = damageModifier
|
||||
options.vehicleBonus = options.vehicleBonus || 0
|
||||
let fullFormula = `${formula} + ${options.rollItem.value}`
|
||||
if (options.isEncumbered) {
|
||||
fullFormula += ` - 1D`
|
||||
}
|
||||
if (options.vehicleBonus) {
|
||||
fullFormula += ` + ${options.vehicleBonus}`
|
||||
}
|
||||
options.fullFormula = fullFormula
|
||||
options.formula = formula
|
||||
|
||||
@@ -164,6 +171,7 @@ export default class FTLNomadRoll extends Roll {
|
||||
hasTarget: options.hasTarget,
|
||||
modifier,
|
||||
numericModifierSelect,
|
||||
vehicleBonus: options.vehicleBonus,
|
||||
}
|
||||
const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-ftl-nomad/templates/roll-dialog.hbs", dialogContext)
|
||||
|
||||
@@ -236,6 +244,7 @@ export default class FTLNomadRoll extends Roll {
|
||||
options.finalModifier = options.numericModifier + options.skillModifier + options.rangeModifier
|
||||
let mod = options.rollItem?.value || 0
|
||||
mod += options.numericModifierSelect
|
||||
mod += options.vehicleBonus || 0
|
||||
|
||||
// Build the dice formula
|
||||
let diceFormula = "2d6"
|
||||
|
||||
@@ -11,7 +11,8 @@ export default class FTLNomadStarship extends foundry.abstract.TypeDataModel {
|
||||
schema.hullType = new fields.StringField({ required: true, initial: "small", choices: SYSTEM.STARSHIP_HULL })
|
||||
schema.endurance = new fields.StringField({ required: true, initial: "" })
|
||||
schema.armor = new fields.StringField({ required: true, initial: "" })
|
||||
schema.crew = new fields.StringField({ required: true, initial: "" })
|
||||
schema.crewList = new fields.ArrayField(new fields.StringField({ required: true }), { initial: [] })
|
||||
schema.crewCapacity = new fields.StringField({ required: true, initial: "" })
|
||||
schema.cargo = new fields.StringField({ required: true, initial: "" })
|
||||
schema.guns = new fields.StringField({ required: true, initial: "1d6" })
|
||||
schema.travelMultiplier = new fields.StringField({ required: true, initial: "" })
|
||||
|
||||
@@ -10,7 +10,8 @@ export default class FTLNomadVehicle extends foundry.abstract.TypeDataModel {
|
||||
schema.agility = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
|
||||
schema.armor = new fields.StringField({ required: true, initial: "" })
|
||||
schema.cargo = new fields.StringField({ required: true, initial: "" })
|
||||
schema.crew = new fields.StringField({ required: true, initial: "" })
|
||||
schema.crewList = new fields.ArrayField(new fields.StringField({ required: true }), { initial: [] })
|
||||
schema.crewCapacity = new fields.StringField({ required: true, initial: "" })
|
||||
schema.force = new fields.NumberField({ ...requiredInteger, initial: 1, min: 1 })
|
||||
schema.range = new fields.StringField({ required: true, initial: "1d6" })
|
||||
schema.speed = new fields.StringField({ required: true, initial: "1d6" })
|
||||
|
||||
Reference in New Issue
Block a user