From 27b09d454691854992d1a81a22b32c91f72844cd Mon Sep 17 00:00:00 2001 From: LeRatierBretonnien Date: Sun, 9 Nov 2025 22:12:00 +0100 Subject: [PATCH] Add crew member option with pilot rolls integrated --- css/fvtt-ftl-nomad.css | 118 ++++++++++++++ lang/en.json | 24 ++- module/applications/sheets/starship-sheet.mjs | 151 ++++++++++++++++++ module/applications/sheets/vehicle-sheet.mjs | 146 +++++++++++++++++ module/documents/roll.mjs | 11 +- module/models/starship.mjs | 3 +- module/models/vehicle.mjs | 3 +- .../{000090.ldb => 000119.ldb} | Bin .../{000109.log => 000122.log} | 0 packs/ftl-nomad-items/CURRENT | 2 +- packs/ftl-nomad-items/LOG | 14 +- packs/ftl-nomad-items/LOG.old | 18 ++- packs/ftl-nomad-items/MANIFEST-000107 | Bin 173 -> 0 bytes packs/ftl-nomad-items/MANIFEST-000120 | Bin 0 -> 173 bytes .../lost/000113.log} | 0 .../{000068.ldb => 000097.ldb} | Bin packs/ftl-nomad-vehicles/000100.log | 0 packs/ftl-nomad-vehicles/CURRENT | 2 +- packs/ftl-nomad-vehicles/LOG | 14 +- packs/ftl-nomad-vehicles/LOG.old | 18 ++- packs/ftl-nomad-vehicles/MANIFEST-000085 | Bin 174 -> 0 bytes packs/ftl-nomad-vehicles/MANIFEST-000098 | Bin 0 -> 174 bytes packs/ftl-nomad-vehicles/lost/000091.log | 0 styles/starship.less | 62 +++++++ styles/vehicle.less | 62 +++++++ templates/roll-dialog.hbs | 6 + templates/starship-equipment.hbs | 70 +++----- templates/starship-main.hbs | 4 +- templates/vehicle-equipment.hbs | 39 +++++ templates/vehicle-main.hbs | 5 +- 30 files changed, 687 insertions(+), 85 deletions(-) rename packs/ftl-nomad-items/{000090.ldb => 000119.ldb} (100%) rename packs/ftl-nomad-items/{000109.log => 000122.log} (100%) delete mode 100644 packs/ftl-nomad-items/MANIFEST-000107 create mode 100644 packs/ftl-nomad-items/MANIFEST-000120 rename packs/{ftl-nomad-vehicles/000087.log => ftl-nomad-items/lost/000113.log} (100%) rename packs/ftl-nomad-vehicles/{000068.ldb => 000097.ldb} (100%) create mode 100644 packs/ftl-nomad-vehicles/000100.log delete mode 100644 packs/ftl-nomad-vehicles/MANIFEST-000085 create mode 100644 packs/ftl-nomad-vehicles/MANIFEST-000098 create mode 100644 packs/ftl-nomad-vehicles/lost/000091.log diff --git a/css/fvtt-ftl-nomad.css b/css/fvtt-ftl-nomad.css index a6f7c89..cce7be7 100644 --- a/css/fvtt-ftl-nomad.css +++ b/css/fvtt-ftl-nomad.css @@ -1155,6 +1155,65 @@ i.fvtt-ftl-nomad { font-size: calc(var(--font-size-standard) * 1.4); padding-left: 5px; } +.fvtt-ftl-nomad .tab.vehicle-equipment .main-div .crew .crew-list { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 8px; + padding: 4px; +} +.fvtt-ftl-nomad .tab.vehicle-equipment .main-div .crew .crew-member { + display: flex; + align-items: center; + gap: 4px; + padding: 4px; + border: 1px solid var(--color-border-dark); + border-radius: 4px; + background: var(--color-light-2); +} +.fvtt-ftl-nomad .tab.vehicle-equipment .main-div .crew .crew-member .crew-img { + width: 32px; + height: 32px; + border-radius: 50%; + border: 1px solid var(--color-border-dark); + cursor: pointer; +} +.fvtt-ftl-nomad .tab.vehicle-equipment .main-div .crew .crew-member .crew-img:hover { + opacity: 0.8; + box-shadow: 0 0 4px var(--color-shadow-primary); +} +.fvtt-ftl-nomad .tab.vehicle-equipment .main-div .crew .crew-member .crew-name { + flex: 1; + font-size: var(--font-size-small); + cursor: pointer; +} +.fvtt-ftl-nomad .tab.vehicle-equipment .main-div .crew .crew-member .crew-name:hover { + color: var(--color-text-dark-highlight); + text-shadow: 0 0 4px var(--color-shadow-primary); +} +.fvtt-ftl-nomad .tab.vehicle-equipment .main-div .crew .crew-member .controls { + display: flex; + gap: 4px; + min-width: 3rem; +} +.fvtt-ftl-nomad .tab.vehicle-equipment .main-div .crew .crew-member .controls a { + color: var(--color-text-dark-primary); +} +.fvtt-ftl-nomad .tab.vehicle-equipment .main-div .crew .crew-member .controls a:hover { + color: var(--color-text-dark-highlight); +} +.fvtt-ftl-nomad .tab.vehicle-equipment .main-div .crew .crew-member .controls .pilot-button { + color: var(--color-text-light-primary); +} +.fvtt-ftl-nomad .tab.vehicle-equipment .main-div .crew .crew-member .controls .pilot-button:hover { + color: var(--color-text-light-highlight); +} +.fvtt-ftl-nomad .tab.vehicle-equipment .main-div .crew .crew-empty { + grid-column: 1 / -1; + text-align: center; + padding: 8px; + font-style: italic; + color: var(--color-text-dark-secondary); +} .fvtt-ftl-nomad .tab.vehicle-equipment .main-div .weapons { display: grid; grid-template-columns: repeat(2, 1fr); @@ -1845,6 +1904,65 @@ i.fvtt-ftl-nomad { font-size: calc(var(--font-size-standard) * 1.4); padding-left: 5px; } +.fvtt-ftl-nomad .tab.starship-equipment .crew .crew-list { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 8px; + padding: 4px; +} +.fvtt-ftl-nomad .tab.starship-equipment .crew .crew-member { + display: flex; + align-items: center; + gap: 4px; + padding: 4px; + border: 1px solid var(--color-border-dark); + border-radius: 4px; + background: var(--color-light-2); +} +.fvtt-ftl-nomad .tab.starship-equipment .crew .crew-member .crew-img { + width: 32px; + height: 32px; + border-radius: 50%; + border: 1px solid var(--color-border-dark); + cursor: pointer; +} +.fvtt-ftl-nomad .tab.starship-equipment .crew .crew-member .crew-img:hover { + opacity: 0.8; + box-shadow: 0 0 4px var(--color-shadow-primary); +} +.fvtt-ftl-nomad .tab.starship-equipment .crew .crew-member .crew-name { + flex: 1; + font-size: var(--font-size-small); + cursor: pointer; +} +.fvtt-ftl-nomad .tab.starship-equipment .crew .crew-member .crew-name:hover { + color: var(--color-text-dark-highlight); + text-shadow: 0 0 4px var(--color-shadow-primary); +} +.fvtt-ftl-nomad .tab.starship-equipment .crew .crew-member .controls { + display: flex; + gap: 4px; + min-width: 3rem; +} +.fvtt-ftl-nomad .tab.starship-equipment .crew .crew-member .controls a { + color: var(--color-text-dark-primary); +} +.fvtt-ftl-nomad .tab.starship-equipment .crew .crew-member .controls a:hover { + color: var(--color-text-dark-highlight); +} +.fvtt-ftl-nomad .tab.starship-equipment .crew .crew-member .controls .pilot-button { + color: var(--color-text-light-primary); +} +.fvtt-ftl-nomad .tab.starship-equipment .crew .crew-member .controls .pilot-button:hover { + color: var(--color-text-light-highlight); +} +.fvtt-ftl-nomad .tab.starship-equipment .crew .crew-empty { + grid-column: 1 / -1; + text-align: center; + padding: 8px; + font-style: italic; + color: var(--color-text-dark-secondary); +} .fvtt-ftl-nomad .tab.starship-equipment .weapons { display: grid; grid-template-columns: repeat(2, 1fr); diff --git a/lang/en.json b/lang/en.json index 4af3c41..e6c3fee 100644 --- a/lang/en.json +++ b/lang/en.json @@ -524,7 +524,10 @@ "titleWeapon": "Weapon Roll", "total": "Total", "totalScore": "Total Score", - "weapons": "Weapons" + "weapons": "Weapons", + "crew": "Crew", + "noCrew": "No crew members assigned", + "vehicleBonus": "Vehicle/Starship Agility Bonus" }, "Language": { "FIELDS": { @@ -633,6 +636,9 @@ "crew": { "label": "Crew" }, + "crewCapacity": { + "label": "Crew Capacity" + }, "description": { "label": "Description" }, @@ -712,6 +718,9 @@ "crew": { "label": "Crew" }, + "crewCapacity": { + "label": "Crew Capacity" + }, "description": { "label": "Description" }, @@ -723,7 +732,18 @@ } } }, - "Warning": {}, + "Warning": { + "alreadyInCrew": "This actor is already a crew member", + "notACharacter": "Only characters can pilot vehicles", + "noVehiclesSkill": "This character does not have the vehicles skill", + "onlyCharactersAllowed": "Only characters can be added as crew members", + "noLinkedPrototype": "This character must be linked to his token to be added as crew member" + }, + "RemoveCrew": "Remove from crew", + "RemoveCrewTitle": "Remove crew member?", + "RemoveCrewContent": "Are you sure you want to remove {name} from the crew?", + "PilotVehicle": "Pilot vehicle (with vehicle agility bonus)", + "PilotStarship": "Pilot starship (with starship agility bonus)", "Weapon": { "FIELDS": { "cost": { diff --git a/module/applications/sheets/starship-sheet.mjs b/module/applications/sheets/starship-sheet.mjs index bffa2ef..232785a 100644 --- a/module/applications/sheets/starship-sheet.mjs +++ b/module/applications/sheets/starship-sheet.mjs @@ -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} + */ + 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 }) + } + } diff --git a/module/applications/sheets/vehicle-sheet.mjs b/module/applications/sheets/vehicle-sheet.mjs index 905dbab..724abe5 100644 --- a/module/applications/sheets/vehicle-sheet.mjs +++ b/module/applications/sheets/vehicle-sheet.mjs @@ -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} + */ + 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 }) + } + } diff --git a/module/documents/roll.mjs b/module/documents/roll.mjs index f9f8f4d..5ef6f38 100644 --- a/module/documents/roll.mjs +++ b/module/documents/roll.mjs @@ -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" diff --git a/module/models/starship.mjs b/module/models/starship.mjs index 724f54b..4c5be4b 100644 --- a/module/models/starship.mjs +++ b/module/models/starship.mjs @@ -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: "" }) diff --git a/module/models/vehicle.mjs b/module/models/vehicle.mjs index fa1e34a..f25b3bd 100644 --- a/module/models/vehicle.mjs +++ b/module/models/vehicle.mjs @@ -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" }) diff --git a/packs/ftl-nomad-items/000090.ldb b/packs/ftl-nomad-items/000119.ldb similarity index 100% rename from packs/ftl-nomad-items/000090.ldb rename to packs/ftl-nomad-items/000119.ldb diff --git a/packs/ftl-nomad-items/000109.log b/packs/ftl-nomad-items/000122.log similarity index 100% rename from packs/ftl-nomad-items/000109.log rename to packs/ftl-nomad-items/000122.log diff --git a/packs/ftl-nomad-items/CURRENT b/packs/ftl-nomad-items/CURRENT index aecd689..30eb131 100644 --- a/packs/ftl-nomad-items/CURRENT +++ b/packs/ftl-nomad-items/CURRENT @@ -1 +1 @@ -MANIFEST-000107 +MANIFEST-000120 diff --git a/packs/ftl-nomad-items/LOG b/packs/ftl-nomad-items/LOG index 04c00d5..f231dbb 100644 --- a/packs/ftl-nomad-items/LOG +++ b/packs/ftl-nomad-items/LOG @@ -1,7 +1,7 @@ -2025/10/27-20:06:28.536125 7f2a23fff6c0 Recovering log #105 -2025/10/27-20:06:28.547660 7f2a23fff6c0 Delete type=3 #103 -2025/10/27-20:06:28.547796 7f2a23fff6c0 Delete type=0 #105 -2025/10/27-20:07:11.806730 7f2a213ff6c0 Level-0 table #110: started -2025/10/27-20:07:11.806798 7f2a213ff6c0 Level-0 table #110: 0 bytes OK -2025/10/27-20:07:11.813240 7f2a213ff6c0 Delete type=0 #108 -2025/10/27-20:07:11.813543 7f2a213ff6c0 Manual compaction at level-0 from '!folders!AuBtSOj1mJmh88qx' @ 72057594037927935 : 1 .. '!items!zv9dwgL3p7ThQn7j' @ 0 : 0; will stop at (end) +2025/11/09-22:04:33.775487 7f0921ffb6c0 Recovering log #117 +2025/11/09-22:04:33.868329 7f0921ffb6c0 Delete type=3 #115 +2025/11/09-22:04:33.868406 7f0921ffb6c0 Delete type=0 #117 +2025/11/09-22:11:34.495817 7f0920bff6c0 Level-0 table #123: started +2025/11/09-22:11:34.495875 7f0920bff6c0 Level-0 table #123: 0 bytes OK +2025/11/09-22:11:34.530303 7f0920bff6c0 Delete type=0 #121 +2025/11/09-22:11:34.530590 7f0920bff6c0 Manual compaction at level-0 from '!folders!AuBtSOj1mJmh88qx' @ 72057594037927935 : 1 .. '!items!zv9dwgL3p7ThQn7j' @ 0 : 0; will stop at (end) diff --git a/packs/ftl-nomad-items/LOG.old b/packs/ftl-nomad-items/LOG.old index 50bdba9..26ebee8 100644 --- a/packs/ftl-nomad-items/LOG.old +++ b/packs/ftl-nomad-items/LOG.old @@ -1,7 +1,11 @@ -2025/10/27-20:03:18.716726 7f2a22ffd6c0 Recovering log #101 -2025/10/27-20:03:18.728612 7f2a22ffd6c0 Delete type=3 #99 -2025/10/27-20:03:18.728755 7f2a22ffd6c0 Delete type=0 #101 -2025/10/27-20:06:09.635606 7f2a213ff6c0 Level-0 table #106: started -2025/10/27-20:06:09.635675 7f2a213ff6c0 Level-0 table #106: 0 bytes OK -2025/10/27-20:06:09.644064 7f2a213ff6c0 Delete type=0 #104 -2025/10/27-20:06:09.658912 7f2a213ff6c0 Manual compaction at level-0 from '!folders!AuBtSOj1mJmh88qx' @ 72057594037927935 : 1 .. '!items!zv9dwgL3p7ThQn7j' @ 0 : 0; will stop at (end) +2025/11/09-19:53:34.147030 7f09217fa6c0 Delete type=3 #1 +2025/11/09-22:04:27.202802 7f0920bff6c0 Level-0 table #118: started +2025/11/09-22:04:27.202844 7f0920bff6c0 Level-0 table #118: 0 bytes OK +2025/11/09-22:04:27.240256 7f0920bff6c0 Delete type=0 #116 +2025/11/09-22:04:27.339388 7f0920bff6c0 Manual compaction at level-0 from '!folders!AuBtSOj1mJmh88qx' @ 72057594037927935 : 1 .. '!items!zv9dwgL3p7ThQn7j' @ 0 : 0; will stop at '!items!zv9dwgL3p7ThQn7j' @ 385 : 1 +2025/11/09-22:04:27.339402 7f0920bff6c0 Compacting 1@0 + 0@1 files +2025/11/09-22:04:27.363062 7f0920bff6c0 Generated table #119@0: 316 keys, 126470 bytes +2025/11/09-22:04:27.363092 7f0920bff6c0 Compacted 1@0 + 0@1 files => 126470 bytes +2025/11/09-22:04:27.437323 7f0920bff6c0 compacted to: files[ 0 1 0 0 0 0 0 ] +2025/11/09-22:04:27.437448 7f0920bff6c0 Delete type=2 #90 +2025/11/09-22:04:27.535013 7f0920bff6c0 Manual compaction at level-0 from '!items!zv9dwgL3p7ThQn7j' @ 385 : 1 .. '!items!zv9dwgL3p7ThQn7j' @ 0 : 0; will stop at (end) diff --git a/packs/ftl-nomad-items/MANIFEST-000107 b/packs/ftl-nomad-items/MANIFEST-000107 deleted file mode 100644 index 595f11d3189d29ccd344aaed5bab2e9c9358c6a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 173 zcmZ>5xZTypz{n_-lUkOVlai$8R9TW*o>`pgoS$2eSd>_jU&P8Fub5eqnp><`mG5fe z8B&>+W1OF2mJ#W~c#(+#1lSp)+U~F`DyHS{}sl?3}|8RmNBW>{DhRxr+H z1gnFaQ)Zb`p6+8@U>=eYm}j2F*a(rY^IjRv$-u~z!^yy$%kq%*McKP$Abu{8pAX~% E0CZO}mjD0& diff --git a/packs/ftl-nomad-items/MANIFEST-000120 b/packs/ftl-nomad-items/MANIFEST-000120 new file mode 100644 index 0000000000000000000000000000000000000000..690fcafc6ee6bac34dad3fb52d228d87f53f2294 GIT binary patch literal 173 zcmb2l(OcKXz{n_-lUkOVlai$8R9TW*o>`pgoS$2eSd>_jU&P8Fub5eqnp><`Rc4t| zp6+8@U>=eYm}j2F*vQBL0_=?CZFkre71Q!_Qc{bG6&*{RN`n2f40FA5Gb}6$D;Q@( k)Dbdgrt|ifoD7Uim7EOBRV)u#X9c$MgZNcIehrWh0O 62826 bytes +2025/11/09-22:04:27.339052 7f0920bff6c0 compacted to: files[ 0 1 0 0 0 0 0 ] +2025/11/09-22:04:27.339182 7f0920bff6c0 Delete type=2 #68 +2025/11/09-22:04:27.437605 7f0920bff6c0 Manual compaction at level-0 from '!folders!vRnrOJqSMlxbSgyX' @ 92 : 1 .. '!folders!vRnrOJqSMlxbSgyX' @ 0 : 0; will stop at (end) diff --git a/packs/ftl-nomad-vehicles/MANIFEST-000085 b/packs/ftl-nomad-vehicles/MANIFEST-000085 deleted file mode 100644 index 3647a2d3384aa08d4a0f939d212144932625ec22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 174 zcmd;oxb|l!10$nUPHI_dPD+xVQ)NkNd1i5{bAE0?Vo_pAei18!qGDQpPD*M~v7$$Q zl3Qs>PM(LEM?i>cS_oq-0~oL~y1aVDte}{f4AfApXy6uT7Lgc~X=LJ`U*u_I$e0CD zhA^lsD6h!ht1#F%ry?mhy)uF^2BIQr>Zu`pgoS$2eSd>_jU&P9wsF;?Ylag9gtXLM5 zSLE+i80?!8NnFC00!)giLYKUD<~!=12q&Y8n^|TMI;7g8kzX#7kL^PGG;-P i5jJRTzRWxh21cf2P6p-_mWmlXA`d~_6d*T^r2+szlrXCR literal 0 HcmV?d00001 diff --git a/packs/ftl-nomad-vehicles/lost/000091.log b/packs/ftl-nomad-vehicles/lost/000091.log new file mode 100644 index 0000000..e69de29 diff --git a/styles/starship.less b/styles/starship.less index e607ef0..3f46893 100644 --- a/styles/starship.less +++ b/styles/starship.less @@ -214,6 +214,68 @@ padding-left: 5px; } } + .crew { + .crew-list { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 8px; + padding: 4px; + } + .crew-member { + display: flex; + align-items: center; + gap: 4px; + padding: 4px; + border: 1px solid var(--color-border-dark); + border-radius: 4px; + background: var(--color-light-2); + .crew-img { + width: 32px; + height: 32px; + border-radius: 50%; + border: 1px solid var(--color-border-dark); + cursor: pointer; + &:hover { + opacity: 0.8; + box-shadow: 0 0 4px var(--color-shadow-primary); + } + } + .crew-name { + flex: 1; + font-size: var(--font-size-small); + cursor: pointer; + &:hover { + color: var(--color-text-dark-highlight); + text-shadow: 0 0 4px var(--color-shadow-primary); + } + } + .controls { + display: flex; + gap: 4px; + min-width: 3rem; + a { + color: var(--color-text-dark-primary); + &:hover { + color: var(--color-text-dark-highlight); + } + } + .pilot-button { + color: var(--color-text-light-primary); + &:hover { + color: var(--color-text-light-highlight); + } + } + } + } + .crew-empty { + grid-column: 1 / -1; + text-align: center; + padding: 8px; + font-style: italic; + color: var(--color-text-dark-secondary); + } + } + .weapons { display: grid; grid-template-columns: repeat(2, 1fr); diff --git a/styles/vehicle.less b/styles/vehicle.less index 797ff7d..c40a904 100644 --- a/styles/vehicle.less +++ b/styles/vehicle.less @@ -173,6 +173,68 @@ padding-left: 5px; } } + .crew { + .crew-list { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 8px; + padding: 4px; + } + .crew-member { + display: flex; + align-items: center; + gap: 4px; + padding: 4px; + border: 1px solid var(--color-border-dark); + border-radius: 4px; + background: var(--color-light-2); + .crew-img { + width: 32px; + height: 32px; + border-radius: 50%; + border: 1px solid var(--color-border-dark); + cursor: pointer; + &:hover { + opacity: 0.8; + box-shadow: 0 0 4px var(--color-shadow-primary); + } + } + .crew-name { + flex: 1; + font-size: var(--font-size-small); + cursor: pointer; + &:hover { + color: var(--color-text-dark-highlight); + text-shadow: 0 0 4px var(--color-shadow-primary); + } + } + .controls { + display: flex; + gap: 4px; + min-width: 3rem; + a { + color: var(--color-text-dark-primary); + &:hover { + color: var(--color-text-dark-highlight); + } + } + .pilot-button { + color: var(--color-text-light-primary); + &:hover { + color: var(--color-text-light-highlight); + } + } + } + } + .crew-empty { + grid-column: 1 / -1; + text-align: center; + padding: 8px; + font-style: italic; + color: var(--color-text-dark-secondary); + } + } + .weapons { display: grid; grid-template-columns: repeat(2, 1fr); diff --git a/templates/roll-dialog.hbs b/templates/roll-dialog.hbs index 1a5d960..17a5e4e 100644 --- a/templates/roll-dialog.hbs +++ b/templates/roll-dialog.hbs @@ -44,6 +44,12 @@ + {{#if vehicleBonus}} +
+ + +{{vehicleBonus}} +
+ {{/if}} {{/if}} {{#if (eq rollType "weapon")}} diff --git a/templates/starship-equipment.hbs b/templates/starship-equipment.hbs index 18b2070..445854a 100644 --- a/templates/starship-equipment.hbs +++ b/templates/starship-equipment.hbs @@ -4,63 +4,43 @@ data-group="{{tab.group}}" >
- - +
{{localize "FTLNOMAD.Label.equipment"}}{{#if isEditMode}} diff --git a/templates/starship-main.hbs b/templates/starship-main.hbs index 3ea64d8..5d3dbb8 100644 --- a/templates/starship-main.hbs +++ b/templates/starship-main.hbs @@ -96,8 +96,8 @@ {{localize "FTLNOMAD.Label.cargo"}}
{{formField - systemFields.crew - value=system.crew + systemFields.crewCapacity + value=system.crewCapacity localize=true disabled=isPlayMode }} diff --git a/templates/vehicle-equipment.hbs b/templates/vehicle-equipment.hbs index 3a0a482..d7d0f7c 100644 --- a/templates/vehicle-equipment.hbs +++ b/templates/vehicle-equipment.hbs @@ -4,6 +4,45 @@ data-group="{{tab.group}}" >
+ +
+ {{localize "FTLNOMAD.Label.crew"}} + ({{crewMembers.length}}{{#if + system.crewCapacity + }}/{{system.crewCapacity}}{{/if}}) +
+ {{#each crewMembers as |member|}} +
+ +
{{member.name}}
+
+ + +
+
+ {{else}} +
{{localize "FTLNOMAD.Label.noCrew"}}
+ {{/each}} +
+
+
{{localize "FTLNOMAD.Label.weapons"}}{{#if isEditMode}} {{localize "FTLNOMAD.Label.cargo"}}
{{formField - systemFields.crew - value=system.crew + systemFields.crewCapacity + value=system.crewCapacity localize=true disabled=isPlayMode }} @@ -100,7 +100,6 @@ }}
-