diff --git a/css/mosh.css b/css/mosh.css index 6ded4ea..1daeaa9 100644 --- a/css/mosh.css +++ b/css/mosh.css @@ -5654,4 +5654,590 @@ p { margin-bottom: 8px !important; } +/* ========================================================================== + STREAMLINED NPC (CREATURE) SHEET DASHBOARD STYLES + ========================================================================== */ + +.mosh.npc-sheet { + background: #080808 !important; + color: #e0e0e0 !important; + font-family: "Barlow Condensed", "Montserrat", sans-serif !important; +} + +.mosh.npc-sheet .window-content { + background: #080808 !important; + color: #e0e0e0 !important; + padding: 12px !important; + overflow-y: auto !important; +} + +/* NPC Header Styles */ +.mosh .npc-header-container { + background: rgba(10, 10, 10, 0.9); + border: 1px solid rgba(0, 255, 100, 0.15); + border-radius: 6px; + padding: 12px; + margin-bottom: 12px; + box-shadow: 0 0 10px rgba(0, 255, 100, 0.05); +} + +.mosh .npc-name-input { + font-family: "Montserrat", "Arial Black", sans-serif; + font-size: 1.8rem; + font-weight: 900; + color: #ffffff; + background: transparent; + border: none; + border-bottom: 2px solid rgba(0, 255, 100, 0.2); + width: 100%; + text-transform: uppercase; + letter-spacing: 1px; + padding-bottom: 4px; + margin-bottom: 8px; + transition: all 0.2s ease; +} + +.mosh .npc-name-input:focus { + border-bottom-color: #00ff66; + box-shadow: 0 4px 10px rgba(0, 255, 100, 0.1); + outline: none; +} + +.mosh .npc-meta-row { + display: flex; + gap: 15px; +} + +.mosh .npc-meta-item { + flex: 1; + display: flex; + flex-direction: column; +} + +.mosh .npc-meta-item label { + font-size: 0.75rem; + font-weight: bold; + text-transform: uppercase; + color: #00ff66; + margin-bottom: 2px; + letter-spacing: 0.5px; +} + +.mosh .npc-meta-item input { + background: rgba(0, 0, 0, 0.4); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 4px; + color: #fff; + padding: 4px 8px; + font-size: 0.9rem; + transition: border-color 0.15s ease; +} + +.mosh .npc-meta-item input:focus { + border-color: #00ff66; + outline: none; +} + +/* Dashboard Layout */ +.mosh .npc-sheet-dashboard { + display: grid; + grid-template-columns: 1.1fr 0.9fr; + gap: 15px; + align-items: start; +} + +.mosh .npc-column-left, +.mosh .npc-column-right { + display: flex; + flex-direction: column; + gap: 12px; +} + +/* Vitals Cards */ +.mosh .npc-vitals-block { + display: flex; + gap: 12px; +} + +.mosh .npc-vital-card { + flex: 1; + background: rgba(0, 0, 0, 0.5); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 5px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.8); +} + +.mosh .npc-vital-card.health { + border-color: rgba(0, 229, 255, 0.2); +} + +.mosh .npc-vital-card.wounds { + border-color: rgba(255, 50, 50, 0.2); +} + +.mosh .npc-vital-label { + font-size: 0.8rem; + font-weight: bold; + text-transform: uppercase; + color: #aaa; + margin-bottom: 6px; + letter-spacing: 0.5px; +} + +.mosh .npc-vital-card.health .npc-vital-label { + color: #00e5ff; + text-shadow: 0 0 5px rgba(0, 229, 255, 0.2); +} + +.mosh .npc-vital-card.wounds .npc-vital-label { + color: #ff3232; + text-shadow: 0 0 5px rgba(255, 50, 50, 0.2); +} + +.mosh .npc-vital-inputs { + display: flex; + align-items: center; + justify-content: center; + gap: 6px; +} + +.mosh .npc-vital-inputs input { + background: transparent; + border: none; + color: #fff; + font-size: 1.4rem; + font-weight: bold; + width: 45px; + text-align: center; +} + +.mosh .npc-vital-inputs input:focus { + outline: none; + background: rgba(255, 255, 255, 0.05); + border-radius: 3px; +} + +.mosh .npc-vital-inputs .divider { + color: #666; + font-size: 1.2rem; + font-weight: light; +} + +/* Glowing Action Buttons */ +.mosh .npc-action-buttons { + display: flex; + gap: 12px; +} + +.mosh .npc-action-btn { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + padding: 12px; + font-family: "Barlow Condensed", sans-serif; + font-size: 1.05rem; + font-weight: 800; + border-radius: 5px; + cursor: pointer; + color: white; + border: 1px solid transparent; + text-transform: uppercase; + letter-spacing: 0.5px; + transition: all 0.2s ease; +} + +.mosh .npc-wound-roll { + background: linear-gradient(135deg, #440a0a 0%, #7e1212 100%) !important; + border-color: #9c1d1d !important; + box-shadow: 0 0 10px rgba(126, 18, 18, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.1) !important; +} + +.mosh .npc-wound-roll:hover { + background: linear-gradient(135deg, #580d0d 0%, #9e1717 100%) !important; + box-shadow: 0 0 16px rgba(220, 20, 20, 0.75), inset 0 1px 0 rgba(255, 255, 255, 0.2) !important; + transform: translateY(-1px); +} + +.mosh .npc-panic-roll { + background: linear-gradient(135deg, #0a361c 0%, #155e32 100%) !important; + border-color: #1c8747 !important; + box-shadow: 0 0 10px rgba(21, 94, 50, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.1) !important; +} + +.mosh .npc-panic-roll:hover { + background: linear-gradient(135deg, #0e4c27 0%, #1c7e43 100%) !important; + box-shadow: 0 0 16px rgba(30, 215, 96, 0.75), inset 0 1px 0 rgba(255, 255, 255, 0.2) !important; + transform: translateY(-1px); +} + +/* Sections Block */ +.mosh .npc-section-block { + background: rgba(12, 12, 12, 0.75); + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 6px; + padding: 12px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5); +} + +.mosh .npc-section-header { + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: 1px solid rgba(0, 255, 100, 0.2); + padding-bottom: 6px; + margin-bottom: 10px; + color: #00ff66; + font-family: "Barlow Condensed", sans-serif; + font-size: 1.15rem; + font-weight: 800; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.mosh .npc-add-btn { + font-size: 0.8rem !important; + color: #00ff66 !important; + cursor: pointer; + transition: all 0.15s ease; + font-family: "Barlow Condensed", sans-serif; + font-weight: bold; +} + +.mosh .npc-add-btn:hover { + color: #ffffff !important; + text-shadow: 0 0 8px #00ff66; +} + +/* Attributes Grid */ +.mosh .npc-stats-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 10px; +} + +.mosh .npc-stat-box { + background: rgba(0, 0, 0, 0.4); + border: 1px solid rgba(255, 255, 255, 0.06); + border-radius: 4px; + padding: 8px 4px; + display: flex; + flex-direction: column; + align-items: center; + transition: all 0.2s ease; +} + +.mosh .npc-stat-box:hover { + border-color: rgba(0, 255, 100, 0.25); + box-shadow: 0 0 10px rgba(0, 255, 100, 0.12); + background: rgba(0, 0, 0, 0.6); +} + +.mosh .npc-stat-label { + font-size: 0.75rem; + font-weight: bold; + letter-spacing: 0.5px; + color: #888; + margin-bottom: 4px; + text-align: center; +} + +.mosh .npc-stat-label.clickable { + cursor: pointer; +} + +.mosh .npc-stat-label.clickable:hover { + color: #00ff66; + text-shadow: 0 0 6px rgba(0, 255, 100, 0.6); +} + +.mosh .npc-stat-box input { + background: transparent; + border: none; + color: #ffffff; + font-size: 1.2rem; + font-weight: 800; + text-align: center; + width: 100%; +} + +.mosh .npc-stat-box input:focus { + outline: none; + background: rgba(255, 255, 255, 0.04); + border-radius: 3px; +} + +/* Skills List */ +.mosh .npc-skills-list { + display: flex; + flex-direction: column; + gap: 6px; +} + +.mosh .npc-skill-item { + display: flex; + align-items: center; + background: rgba(0, 0, 0, 0.3); + border: 1px solid rgba(255, 255, 255, 0.04); + border-left: 3px solid #00ff66; + border-radius: 0 4px 4px 0; + padding: 6px 10px; + justify-content: space-between; + transition: all 0.15s ease; +} + +.mosh .npc-skill-item:hover { + background: rgba(0, 255, 100, 0.04); + border-color: rgba(0, 255, 100, 0.15); +} + +.mosh .npc-skill-item .skill-name { + font-weight: 700; + color: #eee; + flex-grow: 1; +} + +.mosh .npc-skill-item .skill-name.clickable { + cursor: pointer; +} + +.mosh .npc-skill-item .skill-name.clickable:hover { + color: #00ff66; + text-shadow: 0 0 6px rgba(0, 255, 100, 0.4); +} + +.mosh .npc-skill-item .skill-bonus { + color: #00ff66; + font-weight: 800; + margin-right: 12px; +} + +.mosh .npc-skill-item .skill-controls, +.mosh .npc-weapon-item .weapon-controls, +.mosh .npc-ability-item .ability-controls { + display: flex; + gap: 8px; +} + +.mosh .npc-skill-item .skill-controls a, +.mosh .npc-weapon-item .weapon-controls a, +.mosh .npc-ability-item .ability-controls a { + color: #555 !important; + font-size: 0.8rem; + transition: color 0.15s ease; +} + +.mosh .npc-skill-item .skill-controls a:hover, +.mosh .npc-weapon-item .weapon-controls a:hover, +.mosh .npc-ability-item .ability-controls a:hover { + color: #fff !important; +} + +/* Profile Wrapper */ +.mosh .npc-profile-wrapper { + background: rgba(0, 0, 0, 0.4); + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 6px; + padding: 6px; + display: flex; + justify-content: center; + align-items: center; + height: 160px; + overflow: hidden; + box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.8); +} + +.mosh .npc-profile-img { + max-height: 100%; + max-width: 100%; + object-fit: cover; + border-radius: 4px; + border: 1px solid rgba(255, 255, 255, 0.1) !important; + cursor: pointer; + transition: all 0.2s ease; +} + +.mosh .npc-profile-img:hover { + border-color: #00ff66 !important; + box-shadow: 0 0 10px rgba(0, 255, 100, 0.25); +} + +/* Weapons List */ +.mosh .npc-weapons-list { + display: flex; + flex-direction: column; + gap: 6px; +} + +.mosh .npc-weapon-item { + background: rgba(0, 0, 0, 0.3); + border: 1px solid rgba(255, 255, 255, 0.04); + border-left: 3px solid #ff3232; + border-radius: 0 4px 4px 0; + padding: 6px 10px; + transition: all 0.15s ease; +} + +.mosh .npc-weapon-item:hover { + background: rgba(255, 50, 50, 0.04); + border-color: rgba(255, 50, 50, 0.15); +} + +.mosh .npc-weapon-item .weapon-main { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; +} + +.mosh .npc-weapon-item .weapon-name { + font-weight: 700; + color: #eee; + flex-grow: 1; +} + +.mosh .npc-weapon-item .weapon-name.clickable { + cursor: pointer; +} + +.mosh .npc-weapon-item .weapon-name.clickable:hover { + color: #ff3232; + text-shadow: 0 0 6px rgba(255, 50, 50, 0.4); +} + +.mosh .npc-weapon-item .weapon-damage { + color: #ff3232; + font-weight: 800; + margin-right: 12px; +} + +.mosh .npc-weapon-item .weapon-damage.clickable { + cursor: pointer; +} + +.mosh .npc-weapon-item .weapon-damage.clickable:hover { + text-shadow: 0 0 6px rgba(255, 50, 50, 0.5); +} + +.mosh .npc-weapon-item .weapon-ammo-count { + font-size: 0.75rem; + color: #aaa; + background: rgba(255, 255, 255, 0.06); + padding: 2px 6px; + border-radius: 3px; + margin-right: 12px; + border: 1px solid rgba(255, 255, 255, 0.05); +} + +.mosh .npc-weapon-item .weapon-ammo-count.clickable { + cursor: pointer; +} + +.mosh .npc-weapon-item .weapon-ammo-count.clickable:hover { + color: #fff; + border-color: rgba(255, 255, 255, 0.2); + background: rgba(255, 255, 255, 0.12); +} + +/* Protection values */ +.mosh .npc-armor-grid { + display: flex; + gap: 12px; +} + +.mosh .npc-armor-field { + flex: 1; + display: flex; + flex-direction: column; +} + +.mosh .npc-armor-field label { + font-size: 0.75rem; + font-weight: bold; + text-transform: uppercase; + color: #888; + margin-bottom: 4px; + letter-spacing: 0.5px; +} + +.mosh .npc-armor-field input { + background: rgba(0, 0, 0, 0.4); + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 4px; + color: #fff; + padding: 6px; + font-size: 1rem; + font-weight: 800; + text-align: center; + transition: all 0.15s ease; +} + +.mosh .npc-armor-field input:focus { + border-color: #00ff66; + outline: none; + background: rgba(0, 0, 0, 0.6); +} + +/* Ebon Capabilities */ +.mosh .npc-abilities-list { + display: flex; + flex-direction: column; + gap: 6px; +} + +.mosh .npc-ability-item { + background: rgba(0, 0, 0, 0.3); + border: 1px solid rgba(255, 255, 255, 0.04); + border-left: 3px solid #00e5ff; + border-radius: 0 4px 4px 0; + padding: 6px 10px; +} + +.mosh .npc-ability-item .ability-main { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; +} + +.mosh .npc-ability-item .ability-name { + font-weight: 700; + color: #00e5ff; + flex-grow: 1; + text-shadow: 0 0 4px rgba(0, 229, 255, 0.1); +} + +.mosh .npc-ability-item .ability-name.clickable { + cursor: pointer; +} + +.mosh .npc-ability-item .ability-name.clickable:hover { + color: #ffffff; + text-shadow: 0 0 8px #00e5ff; +} + +.mosh .npc-ability-item .ability-description { + font-size: 0.8rem; + color: #bbb; + margin-top: 4px; + padding-top: 4px; + border-top: 1px solid rgba(255, 255, 255, 0.04); + line-height: 1.3; +} + +/* Helper empty text */ +.mosh .npc-empty-text { + font-size: 0.8rem; + color: #555; + font-style: italic; + text-align: center; + padding: 8px; +} + + diff --git a/module/actor/npc-sheet.js b/module/actor/npc-sheet.js new file mode 100644 index 0000000..7962a95 --- /dev/null +++ b/module/actor/npc-sheet.js @@ -0,0 +1,57 @@ +import { MothershipCreatureSheet } from "./creature-sheet.js"; + +/** + * Extend MothershipCreatureSheet for the streamlined NPC (creature) actor sheet. + * Displays a single-page, tab-free dashboard with core stats and equipment. + * @extends {MothershipCreatureSheet} + */ +export class MothershipNpcSheet extends MothershipCreatureSheet { + + /** @override */ + static get defaultOptions() { + const options = { + classes: ["mosh", "sheet", "actor", "creature", "npc-sheet"], + template: "systems/sla-mothership/templates/actor/npc-sheet.html", + width: 720, + height: 680, + tabs: [], // Disable tabs + submitOnChange: true + }; + + return foundry.utils.mergeObject(super.defaultOptions, options); + } + + /** @override */ + async getData() { + const data = await super.getData(); + + // Limit the displayed skills to a maximum of 5 + if (data.skills) { + data.skills = data.skills.slice(0, 5); + } + + // Flag to show/hide the "Add Skill" button based on 5-skill constraint + data.showAddSkill = (!data.skills || data.skills.length < 5); + + return data; + } + + /** @override */ + activateListeners(html) { + super.activateListeners(html); + + if (!this.options.editable) return; + + // Custom Wound Roll Button Click + html.find('.npc-wound-roll').click(async ev => { + ev.preventDefault(); + await this.actor.chooseSlaWoundTable(); + }); + + // Custom Panic Roll Button Click + html.find('.npc-panic-roll').click(async ev => { + ev.preventDefault(); + await this.actor.rollTable("panicCheck", null, null, null, null, null, null); + }); + } +} diff --git a/module/mosh.js b/module/mosh.js index 79086f0..25ff940 100644 --- a/module/mosh.js +++ b/module/mosh.js @@ -2,6 +2,7 @@ import { MothershipActor } from "./actor/actor.js"; import { MothershipActorSheet, MothershipActorSheetDossier } from "./actor/actor-sheet.js"; import { MothershipCreatureSheet } from "./actor/creature-sheet.js"; +import { MothershipNpcSheet } from "./actor/npc-sheet.js"; import { MothershipShipSheet } from "./actor/ship-sheet.js"; import { MothershipShipSheetSBT } from "./actor/ship-sheet-sbt.js"; @@ -81,7 +82,8 @@ Hooks.once('init', async function () { foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet); foundry.documents.collections.Actors.registerSheet("sla-mothership", MothershipActorSheet, {types: ['character'], makeDefault: true}); foundry.documents.collections.Actors.registerSheet("sla-mothership", MothershipActorSheetDossier, {types: ['character'], makeDefault: false, label: "SLA Dossier"}); - foundry.documents.collections.Actors.registerSheet("sla-mothership", MothershipCreatureSheet, {types: ['creature'], makeDefault: false}); + foundry.documents.collections.Actors.registerSheet("sla-mothership", MothershipNpcSheet, {types: ['creature'], makeDefault: true, label: "SLA Streamlined NPC Sheet"}); + foundry.documents.collections.Actors.registerSheet("sla-mothership", MothershipCreatureSheet, {types: ['creature'], makeDefault: false, label: "SLA Standard Creature Sheet"}); foundry.documents.collections.Actors.registerSheet("sla-mothership", MothershipShipSheetSBT, {types: ['ship'], makeDefault: true}); foundry.documents.collections.Actors.registerSheet("sla-mothership", MothershipShipSheet, {types: ['ship'], makeDefault: false}); foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet); diff --git a/system.json b/system.json index c775e5a..f915de6 100644 --- a/system.json +++ b/system.json @@ -2,7 +2,7 @@ "id": "sla-mothership", "title": "SLA Mothership", "description": "An SLA Industries conversion built on the unofficial Mothership system for Foundry VTT, preserving Mothership's core mechanics while adding SLA flux, Ebb, BPN, and equipment support.", - "version": "0.6.11", + "version": "0.6.12", "esmodules": [ "module/mosh.js" ], diff --git a/templates/actor/npc-sheet.html b/templates/actor/npc-sheet.html new file mode 100644 index 0000000..dc41553 --- /dev/null +++ b/templates/actor/npc-sheet.html @@ -0,0 +1,209 @@ +