Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf4e98a780 | ||
|
|
3d21b8e466 |
@@ -4483,3 +4483,931 @@ p {
|
||||
background: #1a120c;
|
||||
border: 1px solid #8a5a31;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
SLA PASS 4 — SCL Controls, Session Tracking, Contacts, Rest
|
||||
============================================================ */
|
||||
|
||||
/* SCL fractional control */
|
||||
.sla-scl-control {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.sla-scl-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sla-scl-buttons {
|
||||
display: flex;
|
||||
gap: 3px;
|
||||
}
|
||||
|
||||
.sla-scl-buttons .sla-scl-adjust {
|
||||
flex: 1;
|
||||
padding: 2px 0;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
border: 1px solid rgba(170, 2, 0, 0.4);
|
||||
background: rgba(170, 2, 0, 0.12);
|
||||
color: #cc3333;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.sla-scl-buttons .sla-scl-adjust:hover {
|
||||
background: rgba(170, 2, 0, 0.28);
|
||||
color: #f0f0f0;
|
||||
}
|
||||
|
||||
/* Trauma Response / Session Ability Tracking */
|
||||
.sla-trauma-header-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.sla-session-ability-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.sla-session-ability-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
font-size: 0.75rem;
|
||||
color: #aaa;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.sla-session-ability-label input[type="checkbox"] {
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sla-session-ability-label span {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.sla-new-session {
|
||||
font-size: 0.72rem;
|
||||
padding: 2px 8px;
|
||||
border: 1px solid rgba(170, 2, 0, 0.4);
|
||||
background: rgba(170, 2, 0, 0.12);
|
||||
color: #cc3333;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.sla-new-session:hover {
|
||||
background: rgba(170, 2, 0, 0.28);
|
||||
color: #f0f0f0;
|
||||
}
|
||||
|
||||
/* Rest button — in save-action-strip */
|
||||
.sla-rest-button {
|
||||
/* inherits .sla-sheet-action but add a distinct colour */
|
||||
background: rgba(40, 90, 150, 0.18) !important;
|
||||
border-color: rgba(60, 120, 200, 0.45) !important;
|
||||
color: #7ab8f5 !important;
|
||||
}
|
||||
|
||||
.sla-rest-button:hover {
|
||||
background: rgba(40, 90, 150, 0.36) !important;
|
||||
color: #d8eaff !important;
|
||||
}
|
||||
|
||||
/* Contacts Tab */
|
||||
.sla-contacts-toolbar {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.sla-contacts-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.sla-contact-card {
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-radius: 6px;
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.sla-contact-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.sla-contact-disposition {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.sla-contact-disposition-ally {
|
||||
background: #4eb765;
|
||||
box-shadow: 0 0 6px rgba(78, 183, 101, 0.5);
|
||||
}
|
||||
|
||||
.sla-contact-disposition-neutral {
|
||||
background: #aaa;
|
||||
}
|
||||
|
||||
.sla-contact-disposition-hostile {
|
||||
background: #cc5050;
|
||||
box-shadow: 0 0 6px rgba(204, 80, 80, 0.5);
|
||||
}
|
||||
|
||||
.sla-contact-disposition-unknown {
|
||||
background: #777;
|
||||
border: 1px dashed #aaa;
|
||||
}
|
||||
|
||||
.sla-contact-name {
|
||||
font-weight: 700;
|
||||
font-size: 0.9rem;
|
||||
color: #f0f0f0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.sla-contact-role {
|
||||
font-size: 0.78rem;
|
||||
color: #999;
|
||||
font-style: italic;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.sla-contact-controls {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.sla-contact-controls button {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #888;
|
||||
cursor: pointer;
|
||||
padding: 2px 4px;
|
||||
font-size: 0.8rem;
|
||||
transition: color 0.15s;
|
||||
}
|
||||
|
||||
.sla-contact-controls button:hover {
|
||||
color: #f0f0f0;
|
||||
}
|
||||
|
||||
.sla-contact-controls .sla-contact-delete:hover {
|
||||
color: #cc5050;
|
||||
}
|
||||
|
||||
.sla-contact-notes {
|
||||
margin-top: 6px;
|
||||
font-size: 0.8rem;
|
||||
color: #bbb;
|
||||
line-height: 1.5;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.06);
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
/* LAD + Rest button row in header */
|
||||
.sla-lad-rest-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.sla-header-rest-button {
|
||||
font-size: 0.72rem !important;
|
||||
padding: 2px 9px !important;
|
||||
border-radius: 3px !important;
|
||||
font-weight: 600 !important;
|
||||
cursor: pointer !important;
|
||||
white-space: nowrap !important;
|
||||
line-height: 1.5 !important;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
SLA — Header grid: LAD · Credits · SCL · Height · Weight · Rest
|
||||
============================================================ */
|
||||
|
||||
/* 8-column grid — col 8 holds the Rest button at the far right */
|
||||
.mosh .headergrid {
|
||||
grid-template-columns: 1.1fr 1.3fr 0.85fr 0.85fr 0.85fr 0.85fr 0.85fr 0.9fr !important;
|
||||
}
|
||||
|
||||
/* Row 2: Name (1-4), Class (5-6), Race (7-8) */
|
||||
.mosh .headernamegrid,
|
||||
.mosh .header-field-name {
|
||||
grid-column: 1 / span 4 !important;
|
||||
grid-row: 2;
|
||||
}
|
||||
.mosh .header-field-class {
|
||||
grid-column: 5 / span 2 !important;
|
||||
grid-row: 2;
|
||||
}
|
||||
.mosh .header-field-race {
|
||||
grid-column: 7 / span 2 !important;
|
||||
grid-row: 2;
|
||||
}
|
||||
|
||||
/* Row 3: LAD (1) · Credits (2) · SCL (3) · Height (4) · Weight (5) · Rest (6-8) */
|
||||
.mosh .header-field-lad {
|
||||
grid-column: 1 !important;
|
||||
grid-row: 3;
|
||||
align-self: start;
|
||||
}
|
||||
.mosh .header-field-credits {
|
||||
grid-column: 2 !important;
|
||||
grid-row: 3;
|
||||
}
|
||||
.mosh .header-field-sla-rank {
|
||||
grid-column: 3 !important;
|
||||
grid-row: 3;
|
||||
}
|
||||
.mosh .header-field-height {
|
||||
grid-column: 4 !important;
|
||||
grid-row: 3;
|
||||
}
|
||||
.mosh .header-field-weight {
|
||||
grid-column: 5 !important;
|
||||
grid-row: 3;
|
||||
}
|
||||
.mosh .header-field-rest {
|
||||
grid-column: 6 / span 3 !important;
|
||||
grid-row: 3;
|
||||
align-self: end;
|
||||
}
|
||||
|
||||
/* Rest header pill — blue rounded, matching Wound/Panic shape */
|
||||
.mosh .sla-header-rest-pill {
|
||||
background: linear-gradient(180deg, #3a8fd1, #1a5fa0) !important;
|
||||
color: #e8f4ff !important;
|
||||
border-color: rgba(100, 180, 255, 0.3) !important;
|
||||
min-width: 0 !important;
|
||||
width: 100%;
|
||||
padding: 6px 10px !important;
|
||||
font-size: 0.82rem !important;
|
||||
}
|
||||
.mosh .sla-header-rest-pill:hover {
|
||||
background: linear-gradient(180deg, #4ea8f0, #2472bc) !important;
|
||||
box-shadow: 0 0 12px rgba(60, 140, 255, 0.4) !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
/* Dossier sheet overrides */
|
||||
.mosh.sla-dossier-sheet .header-field-lad {
|
||||
grid-column: 1 !important;
|
||||
}
|
||||
.mosh.sla-dossier-sheet .header-field-credits {
|
||||
grid-column: 2 !important;
|
||||
}
|
||||
.mosh.sla-dossier-sheet .header-field-rest {
|
||||
grid-column: 6 / span 3 !important;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Portrait — static neon blue border (no animation)
|
||||
============================================================ */
|
||||
.mosh .sla-portrait-static {
|
||||
outline: 2px solid #3a9fd6;
|
||||
outline-offset: 2px;
|
||||
box-shadow: 0 0 8px 2px rgba(58, 159, 214, 0.55);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Activity log textarea
|
||||
============================================================ */
|
||||
.sla-activity-log-textarea {
|
||||
font-family: 'Roboto Mono', 'Courier New', monospace !important;
|
||||
font-size: 0.75rem !important;
|
||||
line-height: 1.55 !important;
|
||||
overflow-y: auto !important;
|
||||
resize: vertical !important;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
SLA Industries Pause Screen Animation
|
||||
============================================================ */
|
||||
|
||||
/* Make the pause overlay a centered flex column — only when visible.
|
||||
Do NOT set display here globally: Foundry controls show/hide via
|
||||
its own display:none and we must not override that with !important. */
|
||||
#pause:not([hidden]):not(.hidden) {
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
}
|
||||
|
||||
/* Nuke all of Foundry's default pause children */
|
||||
#pause > *:not(.sla-pause-root) {
|
||||
display: none !important;
|
||||
}
|
||||
#pause figure,
|
||||
#pause h3,
|
||||
#pause img,
|
||||
#pause canvas,
|
||||
#pause figure *,
|
||||
#pause .fas,
|
||||
#pause .fa-cog {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Root container for the injected SVG — full centered column */
|
||||
.sla-pause-root {
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
position: absolute !important;
|
||||
top: 0 !important;
|
||||
left: 0 !important;
|
||||
}
|
||||
|
||||
/* Main SVG — large and prominent */
|
||||
.sla-pause-svg {
|
||||
width: min(360px, 60vw) !important;
|
||||
height: auto !important;
|
||||
overflow: visible !important;
|
||||
}
|
||||
|
||||
/* ── Outer ring: rotates clockwise ── */
|
||||
.sla-ring-outer {
|
||||
transform-origin: 0px 0px;
|
||||
animation: sla-spin-cw 12s linear infinite;
|
||||
}
|
||||
|
||||
/* ── Inner ring: rotates counter-clockwise ── */
|
||||
.sla-ring-inner {
|
||||
transform-origin: 0px 0px;
|
||||
animation: sla-spin-ccw 8s linear infinite;
|
||||
}
|
||||
|
||||
/* ── Scan line: sweeps clockwise like a radar ── */
|
||||
.sla-pause-scan {
|
||||
transform-origin: 0px 0px;
|
||||
animation: sla-spin-cw 4s linear infinite;
|
||||
}
|
||||
|
||||
/* ── Logo pulse ── */
|
||||
.sla-pause-logo-text {
|
||||
animation: sla-logo-pulse 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* ── "STAND BY" blinking ── */
|
||||
.sla-pause-standby {
|
||||
animation: sla-standby-blink 1.8s step-start infinite;
|
||||
}
|
||||
|
||||
/* ─── Keyframes ─────────────────────────────────────────── */
|
||||
|
||||
@keyframes sla-spin-cw {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
@keyframes sla-spin-ccw {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(-360deg); }
|
||||
}
|
||||
|
||||
@keyframes sla-logo-pulse {
|
||||
0%, 100% { fill: #ff2222; filter: drop-shadow(0 0 4px #ff2222); }
|
||||
50% { fill: #ff5555; filter: drop-shadow(0 0 10px #ff4444); }
|
||||
}
|
||||
|
||||
@keyframes sla-standby-blink {
|
||||
0%, 60% { opacity: 1; }
|
||||
61%, 100% { opacity: 0; }
|
||||
}
|
||||
/* ============================================================
|
||||
SLA Industries — Custom UI Icon Set (v2 — scoped selectors)
|
||||
Replaces Foundry's Font Awesome icons via CSS mask-image
|
||||
============================================================ */
|
||||
|
||||
/* ── Sidebar Tabs ─────────────────────────────────────────── */
|
||||
|
||||
/* chat — chat */
|
||||
#sidebar-tabs [data-tab="chat"] i,
|
||||
#sidebar-tabs a[data-tab="chat"] i,
|
||||
nav#sidebar-tabs [data-tab="chat"] i {
|
||||
display: inline-block !important;
|
||||
position: relative !important;
|
||||
width: 1.25em !important;
|
||||
height: 1.25em !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
#sidebar-tabs [data-tab="chat"] i::before,
|
||||
#sidebar-tabs a[data-tab="chat"] i::before,
|
||||
nav#sidebar-tabs [data-tab="chat"] i::before {
|
||||
content: '' !important;
|
||||
position: absolute !important;
|
||||
inset: 0 !important;
|
||||
background-color: currentColor !important;
|
||||
-webkit-mask-image: url('../icons/ui/chat.svg') !important;
|
||||
mask-image: url('../icons/ui/chat.svg') !important;
|
||||
-webkit-mask-size: contain !important;
|
||||
mask-size: contain !important;
|
||||
-webkit-mask-repeat: no-repeat !important;
|
||||
mask-repeat: no-repeat !important;
|
||||
-webkit-mask-position: center !important;
|
||||
mask-position: center !important;
|
||||
}
|
||||
|
||||
/* combat — combat */
|
||||
#sidebar-tabs [data-tab="combat"] i,
|
||||
#sidebar-tabs a[data-tab="combat"] i,
|
||||
nav#sidebar-tabs [data-tab="combat"] i {
|
||||
display: inline-block !important;
|
||||
position: relative !important;
|
||||
width: 1.25em !important;
|
||||
height: 1.25em !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
#sidebar-tabs [data-tab="combat"] i::before,
|
||||
#sidebar-tabs a[data-tab="combat"] i::before,
|
||||
nav#sidebar-tabs [data-tab="combat"] i::before {
|
||||
content: '' !important;
|
||||
position: absolute !important;
|
||||
inset: 0 !important;
|
||||
background-color: currentColor !important;
|
||||
-webkit-mask-image: url('../icons/ui/combat.svg') !important;
|
||||
mask-image: url('../icons/ui/combat.svg') !important;
|
||||
-webkit-mask-size: contain !important;
|
||||
mask-size: contain !important;
|
||||
-webkit-mask-repeat: no-repeat !important;
|
||||
mask-repeat: no-repeat !important;
|
||||
-webkit-mask-position: center !important;
|
||||
mask-position: center !important;
|
||||
}
|
||||
|
||||
/* scenes — scenes */
|
||||
#sidebar-tabs [data-tab="scenes"] i,
|
||||
#sidebar-tabs a[data-tab="scenes"] i,
|
||||
nav#sidebar-tabs [data-tab="scenes"] i {
|
||||
display: inline-block !important;
|
||||
position: relative !important;
|
||||
width: 1.25em !important;
|
||||
height: 1.25em !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
#sidebar-tabs [data-tab="scenes"] i::before,
|
||||
#sidebar-tabs a[data-tab="scenes"] i::before,
|
||||
nav#sidebar-tabs [data-tab="scenes"] i::before {
|
||||
content: '' !important;
|
||||
position: absolute !important;
|
||||
inset: 0 !important;
|
||||
background-color: currentColor !important;
|
||||
-webkit-mask-image: url('../icons/ui/scenes.svg') !important;
|
||||
mask-image: url('../icons/ui/scenes.svg') !important;
|
||||
-webkit-mask-size: contain !important;
|
||||
mask-size: contain !important;
|
||||
-webkit-mask-repeat: no-repeat !important;
|
||||
mask-repeat: no-repeat !important;
|
||||
-webkit-mask-position: center !important;
|
||||
mask-position: center !important;
|
||||
}
|
||||
|
||||
/* actors — actors */
|
||||
#sidebar-tabs [data-tab="actors"] i,
|
||||
#sidebar-tabs a[data-tab="actors"] i,
|
||||
nav#sidebar-tabs [data-tab="actors"] i {
|
||||
display: inline-block !important;
|
||||
position: relative !important;
|
||||
width: 1.25em !important;
|
||||
height: 1.25em !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
#sidebar-tabs [data-tab="actors"] i::before,
|
||||
#sidebar-tabs a[data-tab="actors"] i::before,
|
||||
nav#sidebar-tabs [data-tab="actors"] i::before {
|
||||
content: '' !important;
|
||||
position: absolute !important;
|
||||
inset: 0 !important;
|
||||
background-color: currentColor !important;
|
||||
-webkit-mask-image: url('../icons/ui/actors.svg') !important;
|
||||
mask-image: url('../icons/ui/actors.svg') !important;
|
||||
-webkit-mask-size: contain !important;
|
||||
mask-size: contain !important;
|
||||
-webkit-mask-repeat: no-repeat !important;
|
||||
mask-repeat: no-repeat !important;
|
||||
-webkit-mask-position: center !important;
|
||||
mask-position: center !important;
|
||||
}
|
||||
|
||||
/* items — items */
|
||||
#sidebar-tabs [data-tab="items"] i,
|
||||
#sidebar-tabs a[data-tab="items"] i,
|
||||
nav#sidebar-tabs [data-tab="items"] i {
|
||||
display: inline-block !important;
|
||||
position: relative !important;
|
||||
width: 1.25em !important;
|
||||
height: 1.25em !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
#sidebar-tabs [data-tab="items"] i::before,
|
||||
#sidebar-tabs a[data-tab="items"] i::before,
|
||||
nav#sidebar-tabs [data-tab="items"] i::before {
|
||||
content: '' !important;
|
||||
position: absolute !important;
|
||||
inset: 0 !important;
|
||||
background-color: currentColor !important;
|
||||
-webkit-mask-image: url('../icons/ui/items.svg') !important;
|
||||
mask-image: url('../icons/ui/items.svg') !important;
|
||||
-webkit-mask-size: contain !important;
|
||||
mask-size: contain !important;
|
||||
-webkit-mask-repeat: no-repeat !important;
|
||||
mask-repeat: no-repeat !important;
|
||||
-webkit-mask-position: center !important;
|
||||
mask-position: center !important;
|
||||
}
|
||||
|
||||
/* journal — journal */
|
||||
#sidebar-tabs [data-tab="journal"] i,
|
||||
#sidebar-tabs a[data-tab="journal"] i,
|
||||
nav#sidebar-tabs [data-tab="journal"] i {
|
||||
display: inline-block !important;
|
||||
position: relative !important;
|
||||
width: 1.25em !important;
|
||||
height: 1.25em !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
#sidebar-tabs [data-tab="journal"] i::before,
|
||||
#sidebar-tabs a[data-tab="journal"] i::before,
|
||||
nav#sidebar-tabs [data-tab="journal"] i::before {
|
||||
content: '' !important;
|
||||
position: absolute !important;
|
||||
inset: 0 !important;
|
||||
background-color: currentColor !important;
|
||||
-webkit-mask-image: url('../icons/ui/journal.svg') !important;
|
||||
mask-image: url('../icons/ui/journal.svg') !important;
|
||||
-webkit-mask-size: contain !important;
|
||||
mask-size: contain !important;
|
||||
-webkit-mask-repeat: no-repeat !important;
|
||||
mask-repeat: no-repeat !important;
|
||||
-webkit-mask-position: center !important;
|
||||
mask-position: center !important;
|
||||
}
|
||||
|
||||
/* tables — tables */
|
||||
#sidebar-tabs [data-tab="tables"] i,
|
||||
#sidebar-tabs a[data-tab="tables"] i,
|
||||
nav#sidebar-tabs [data-tab="tables"] i {
|
||||
display: inline-block !important;
|
||||
position: relative !important;
|
||||
width: 1.25em !important;
|
||||
height: 1.25em !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
#sidebar-tabs [data-tab="tables"] i::before,
|
||||
#sidebar-tabs a[data-tab="tables"] i::before,
|
||||
nav#sidebar-tabs [data-tab="tables"] i::before {
|
||||
content: '' !important;
|
||||
position: absolute !important;
|
||||
inset: 0 !important;
|
||||
background-color: currentColor !important;
|
||||
-webkit-mask-image: url('../icons/ui/tables.svg') !important;
|
||||
mask-image: url('../icons/ui/tables.svg') !important;
|
||||
-webkit-mask-size: contain !important;
|
||||
mask-size: contain !important;
|
||||
-webkit-mask-repeat: no-repeat !important;
|
||||
mask-repeat: no-repeat !important;
|
||||
-webkit-mask-position: center !important;
|
||||
mask-position: center !important;
|
||||
}
|
||||
|
||||
/* playlists — playlists */
|
||||
#sidebar-tabs [data-tab="playlists"] i,
|
||||
#sidebar-tabs a[data-tab="playlists"] i,
|
||||
nav#sidebar-tabs [data-tab="playlists"] i {
|
||||
display: inline-block !important;
|
||||
position: relative !important;
|
||||
width: 1.25em !important;
|
||||
height: 1.25em !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
#sidebar-tabs [data-tab="playlists"] i::before,
|
||||
#sidebar-tabs a[data-tab="playlists"] i::before,
|
||||
nav#sidebar-tabs [data-tab="playlists"] i::before {
|
||||
content: '' !important;
|
||||
position: absolute !important;
|
||||
inset: 0 !important;
|
||||
background-color: currentColor !important;
|
||||
-webkit-mask-image: url('../icons/ui/playlists.svg') !important;
|
||||
mask-image: url('../icons/ui/playlists.svg') !important;
|
||||
-webkit-mask-size: contain !important;
|
||||
mask-size: contain !important;
|
||||
-webkit-mask-repeat: no-repeat !important;
|
||||
mask-repeat: no-repeat !important;
|
||||
-webkit-mask-position: center !important;
|
||||
mask-position: center !important;
|
||||
}
|
||||
|
||||
/* compendium — compendium */
|
||||
#sidebar-tabs [data-tab="compendium"] i,
|
||||
#sidebar-tabs a[data-tab="compendium"] i,
|
||||
nav#sidebar-tabs [data-tab="compendium"] i {
|
||||
display: inline-block !important;
|
||||
position: relative !important;
|
||||
width: 1.25em !important;
|
||||
height: 1.25em !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
#sidebar-tabs [data-tab="compendium"] i::before,
|
||||
#sidebar-tabs a[data-tab="compendium"] i::before,
|
||||
nav#sidebar-tabs [data-tab="compendium"] i::before {
|
||||
content: '' !important;
|
||||
position: absolute !important;
|
||||
inset: 0 !important;
|
||||
background-color: currentColor !important;
|
||||
-webkit-mask-image: url('../icons/ui/compendium.svg') !important;
|
||||
mask-image: url('../icons/ui/compendium.svg') !important;
|
||||
-webkit-mask-size: contain !important;
|
||||
mask-size: contain !important;
|
||||
-webkit-mask-repeat: no-repeat !important;
|
||||
mask-repeat: no-repeat !important;
|
||||
-webkit-mask-position: center !important;
|
||||
mask-position: center !important;
|
||||
}
|
||||
|
||||
/* settings — settings */
|
||||
#sidebar-tabs [data-tab="settings"] i,
|
||||
#sidebar-tabs a[data-tab="settings"] i,
|
||||
nav#sidebar-tabs [data-tab="settings"] i {
|
||||
display: inline-block !important;
|
||||
position: relative !important;
|
||||
width: 1.25em !important;
|
||||
height: 1.25em !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
#sidebar-tabs [data-tab="settings"] i::before,
|
||||
#sidebar-tabs a[data-tab="settings"] i::before,
|
||||
nav#sidebar-tabs [data-tab="settings"] i::before {
|
||||
content: '' !important;
|
||||
position: absolute !important;
|
||||
inset: 0 !important;
|
||||
background-color: currentColor !important;
|
||||
-webkit-mask-image: url('../icons/ui/settings.svg') !important;
|
||||
mask-image: url('../icons/ui/settings.svg') !important;
|
||||
-webkit-mask-size: contain !important;
|
||||
mask-size: contain !important;
|
||||
-webkit-mask-repeat: no-repeat !important;
|
||||
mask-repeat: no-repeat !important;
|
||||
-webkit-mask-position: center !important;
|
||||
mask-position: center !important;
|
||||
}
|
||||
|
||||
/* ── Scene Controls (left toolbar) ────────────────────────── */
|
||||
|
||||
/* token — token */
|
||||
#controls [data-control="token"] > i,
|
||||
#controls li[data-control="token"] > i,
|
||||
#controls .scene-control[data-control="token"] > i,
|
||||
ol#controls [data-control="token"] > i {
|
||||
display: inline-block !important;
|
||||
position: relative !important;
|
||||
width: 1.25em !important;
|
||||
height: 1.25em !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
#controls [data-control="token"] > i::before,
|
||||
#controls li[data-control="token"] > i::before,
|
||||
#controls .scene-control[data-control="token"] > i::before,
|
||||
ol#controls [data-control="token"] > i::before {
|
||||
content: '' !important;
|
||||
position: absolute !important;
|
||||
inset: 0 !important;
|
||||
background-color: currentColor !important;
|
||||
-webkit-mask-image: url('../icons/ui/token.svg') !important;
|
||||
mask-image: url('../icons/ui/token.svg') !important;
|
||||
-webkit-mask-size: contain !important;
|
||||
mask-size: contain !important;
|
||||
-webkit-mask-repeat: no-repeat !important;
|
||||
mask-repeat: no-repeat !important;
|
||||
-webkit-mask-position: center !important;
|
||||
mask-position: center !important;
|
||||
}
|
||||
|
||||
/* measure — measure */
|
||||
#controls [data-control="measure"] > i,
|
||||
#controls li[data-control="measure"] > i,
|
||||
#controls .scene-control[data-control="measure"] > i,
|
||||
ol#controls [data-control="measure"] > i {
|
||||
display: inline-block !important;
|
||||
position: relative !important;
|
||||
width: 1.25em !important;
|
||||
height: 1.25em !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
#controls [data-control="measure"] > i::before,
|
||||
#controls li[data-control="measure"] > i::before,
|
||||
#controls .scene-control[data-control="measure"] > i::before,
|
||||
ol#controls [data-control="measure"] > i::before {
|
||||
content: '' !important;
|
||||
position: absolute !important;
|
||||
inset: 0 !important;
|
||||
background-color: currentColor !important;
|
||||
-webkit-mask-image: url('../icons/ui/measure.svg') !important;
|
||||
mask-image: url('../icons/ui/measure.svg') !important;
|
||||
-webkit-mask-size: contain !important;
|
||||
mask-size: contain !important;
|
||||
-webkit-mask-repeat: no-repeat !important;
|
||||
mask-repeat: no-repeat !important;
|
||||
-webkit-mask-position: center !important;
|
||||
mask-position: center !important;
|
||||
}
|
||||
|
||||
/* tiles — tiles */
|
||||
#controls [data-control="tiles"] > i,
|
||||
#controls li[data-control="tiles"] > i,
|
||||
#controls .scene-control[data-control="tiles"] > i,
|
||||
ol#controls [data-control="tiles"] > i {
|
||||
display: inline-block !important;
|
||||
position: relative !important;
|
||||
width: 1.25em !important;
|
||||
height: 1.25em !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
#controls [data-control="tiles"] > i::before,
|
||||
#controls li[data-control="tiles"] > i::before,
|
||||
#controls .scene-control[data-control="tiles"] > i::before,
|
||||
ol#controls [data-control="tiles"] > i::before {
|
||||
content: '' !important;
|
||||
position: absolute !important;
|
||||
inset: 0 !important;
|
||||
background-color: currentColor !important;
|
||||
-webkit-mask-image: url('../icons/ui/tiles.svg') !important;
|
||||
mask-image: url('../icons/ui/tiles.svg') !important;
|
||||
-webkit-mask-size: contain !important;
|
||||
mask-size: contain !important;
|
||||
-webkit-mask-repeat: no-repeat !important;
|
||||
mask-repeat: no-repeat !important;
|
||||
-webkit-mask-position: center !important;
|
||||
mask-position: center !important;
|
||||
}
|
||||
|
||||
/* drawings — drawings */
|
||||
#controls [data-control="drawings"] > i,
|
||||
#controls li[data-control="drawings"] > i,
|
||||
#controls .scene-control[data-control="drawings"] > i,
|
||||
ol#controls [data-control="drawings"] > i {
|
||||
display: inline-block !important;
|
||||
position: relative !important;
|
||||
width: 1.25em !important;
|
||||
height: 1.25em !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
#controls [data-control="drawings"] > i::before,
|
||||
#controls li[data-control="drawings"] > i::before,
|
||||
#controls .scene-control[data-control="drawings"] > i::before,
|
||||
ol#controls [data-control="drawings"] > i::before {
|
||||
content: '' !important;
|
||||
position: absolute !important;
|
||||
inset: 0 !important;
|
||||
background-color: currentColor !important;
|
||||
-webkit-mask-image: url('../icons/ui/drawings.svg') !important;
|
||||
mask-image: url('../icons/ui/drawings.svg') !important;
|
||||
-webkit-mask-size: contain !important;
|
||||
mask-size: contain !important;
|
||||
-webkit-mask-repeat: no-repeat !important;
|
||||
mask-repeat: no-repeat !important;
|
||||
-webkit-mask-position: center !important;
|
||||
mask-position: center !important;
|
||||
}
|
||||
|
||||
/* walls — walls */
|
||||
#controls [data-control="walls"] > i,
|
||||
#controls li[data-control="walls"] > i,
|
||||
#controls .scene-control[data-control="walls"] > i,
|
||||
ol#controls [data-control="walls"] > i {
|
||||
display: inline-block !important;
|
||||
position: relative !important;
|
||||
width: 1.25em !important;
|
||||
height: 1.25em !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
#controls [data-control="walls"] > i::before,
|
||||
#controls li[data-control="walls"] > i::before,
|
||||
#controls .scene-control[data-control="walls"] > i::before,
|
||||
ol#controls [data-control="walls"] > i::before {
|
||||
content: '' !important;
|
||||
position: absolute !important;
|
||||
inset: 0 !important;
|
||||
background-color: currentColor !important;
|
||||
-webkit-mask-image: url('../icons/ui/walls.svg') !important;
|
||||
mask-image: url('../icons/ui/walls.svg') !important;
|
||||
-webkit-mask-size: contain !important;
|
||||
mask-size: contain !important;
|
||||
-webkit-mask-repeat: no-repeat !important;
|
||||
mask-repeat: no-repeat !important;
|
||||
-webkit-mask-position: center !important;
|
||||
mask-position: center !important;
|
||||
}
|
||||
|
||||
/* lighting — lighting */
|
||||
#controls [data-control="lighting"] > i,
|
||||
#controls li[data-control="lighting"] > i,
|
||||
#controls .scene-control[data-control="lighting"] > i,
|
||||
ol#controls [data-control="lighting"] > i {
|
||||
display: inline-block !important;
|
||||
position: relative !important;
|
||||
width: 1.25em !important;
|
||||
height: 1.25em !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
#controls [data-control="lighting"] > i::before,
|
||||
#controls li[data-control="lighting"] > i::before,
|
||||
#controls .scene-control[data-control="lighting"] > i::before,
|
||||
ol#controls [data-control="lighting"] > i::before {
|
||||
content: '' !important;
|
||||
position: absolute !important;
|
||||
inset: 0 !important;
|
||||
background-color: currentColor !important;
|
||||
-webkit-mask-image: url('../icons/ui/lighting.svg') !important;
|
||||
mask-image: url('../icons/ui/lighting.svg') !important;
|
||||
-webkit-mask-size: contain !important;
|
||||
mask-size: contain !important;
|
||||
-webkit-mask-repeat: no-repeat !important;
|
||||
mask-repeat: no-repeat !important;
|
||||
-webkit-mask-position: center !important;
|
||||
mask-position: center !important;
|
||||
}
|
||||
|
||||
/* sounds — sounds */
|
||||
#controls [data-control="sounds"] > i,
|
||||
#controls li[data-control="sounds"] > i,
|
||||
#controls .scene-control[data-control="sounds"] > i,
|
||||
ol#controls [data-control="sounds"] > i {
|
||||
display: inline-block !important;
|
||||
position: relative !important;
|
||||
width: 1.25em !important;
|
||||
height: 1.25em !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
#controls [data-control="sounds"] > i::before,
|
||||
#controls li[data-control="sounds"] > i::before,
|
||||
#controls .scene-control[data-control="sounds"] > i::before,
|
||||
ol#controls [data-control="sounds"] > i::before {
|
||||
content: '' !important;
|
||||
position: absolute !important;
|
||||
inset: 0 !important;
|
||||
background-color: currentColor !important;
|
||||
-webkit-mask-image: url('../icons/ui/sounds.svg') !important;
|
||||
mask-image: url('../icons/ui/sounds.svg') !important;
|
||||
-webkit-mask-size: contain !important;
|
||||
mask-size: contain !important;
|
||||
-webkit-mask-repeat: no-repeat !important;
|
||||
mask-repeat: no-repeat !important;
|
||||
-webkit-mask-position: center !important;
|
||||
mask-position: center !important;
|
||||
}
|
||||
|
||||
/* notes — notes */
|
||||
#controls [data-control="notes"] > i,
|
||||
#controls li[data-control="notes"] > i,
|
||||
#controls .scene-control[data-control="notes"] > i,
|
||||
ol#controls [data-control="notes"] > i {
|
||||
display: inline-block !important;
|
||||
position: relative !important;
|
||||
width: 1.25em !important;
|
||||
height: 1.25em !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
#controls [data-control="notes"] > i::before,
|
||||
#controls li[data-control="notes"] > i::before,
|
||||
#controls .scene-control[data-control="notes"] > i::before,
|
||||
ol#controls [data-control="notes"] > i::before {
|
||||
content: '' !important;
|
||||
position: absolute !important;
|
||||
inset: 0 !important;
|
||||
background-color: currentColor !important;
|
||||
-webkit-mask-image: url('../icons/ui/notes.svg') !important;
|
||||
mask-image: url('../icons/ui/notes.svg') !important;
|
||||
-webkit-mask-size: contain !important;
|
||||
mask-size: contain !important;
|
||||
-webkit-mask-repeat: no-repeat !important;
|
||||
mask-repeat: no-repeat !important;
|
||||
-webkit-mask-position: center !important;
|
||||
mask-position: center !important;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<!-- Badge shape -->
|
||||
<path d="M6,2 H26 L30,6 V30 H2 V6 Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
|
||||
<!-- Notch at top (lanyard hole) -->
|
||||
<rect x="13" y="0" width="6" height="4" rx="1" fill="currentColor"/>
|
||||
<!-- Head -->
|
||||
<circle cx="16" cy="12" r="4" fill="currentColor"/>
|
||||
<!-- Shoulders -->
|
||||
<path d="M8,26 C8,20 24,20 24,26" fill="currentColor"/>
|
||||
<!-- ID stripe at bottom -->
|
||||
<rect x="5" y="26" width="22" height="2" fill="currentColor" opacity="0.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 575 B |
@@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<!-- Hexagonal speech bubble -->
|
||||
<polygon points="4,4 28,4 28,22 20,22 16,28 12,22 4,22" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linejoin="round" fill-rule="evenodd"/>
|
||||
<!-- Signal bars inside -->
|
||||
<rect x="8" y="14" width="3" height="5" fill="currentColor"/>
|
||||
<rect x="13" y="11" width="3" height="8" fill="currentColor"/>
|
||||
<rect x="18" y="8" width="3" height="11" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 489 B |
@@ -0,0 +1,16 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<!-- Outer ring -->
|
||||
<circle cx="16" cy="16" r="13" fill="none" stroke="currentColor" stroke-width="2"/>
|
||||
<!-- Inner ring -->
|
||||
<circle cx="16" cy="16" r="5" fill="none" stroke="currentColor" stroke-width="1.5"/>
|
||||
<!-- Crosshairs -->
|
||||
<line x1="16" y1="3" x2="16" y2="9" stroke="currentColor" stroke-width="2"/>
|
||||
<line x1="16" y1="23" x2="16" y2="29" stroke="currentColor" stroke-width="2"/>
|
||||
<line x1="3" y1="16" x2="9" y2="16" stroke="currentColor" stroke-width="2"/>
|
||||
<line x1="23" y1="16" x2="29" y2="16" stroke="currentColor" stroke-width="2"/>
|
||||
<!-- Corner tick marks -->
|
||||
<line x1="11" y1="5" x2="12.5" y2="5" stroke="currentColor" stroke-width="1.5"/>
|
||||
<line x1="21" y1="5" x2="19.5" y2="5" stroke="currentColor" stroke-width="1.5"/>
|
||||
<!-- Center dot -->
|
||||
<circle cx="16" cy="16" r="2" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 897 B |
@@ -0,0 +1,14 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<!-- Cylinder top ellipse -->
|
||||
<ellipse cx="16" cy="6" rx="12" ry="4" fill="none" stroke="currentColor" stroke-width="2"/>
|
||||
<!-- Cylinder body -->
|
||||
<line x1="4" y1="6" x2="4" y2="24" stroke="currentColor" stroke-width="2"/>
|
||||
<line x1="28" y1="6" x2="28" y2="24" stroke="currentColor" stroke-width="2"/>
|
||||
<!-- Cylinder bottom ellipse -->
|
||||
<ellipse cx="16" cy="24" rx="12" ry="4" fill="currentColor" stroke="currentColor" stroke-width="2"/>
|
||||
<!-- Data bands -->
|
||||
<ellipse cx="16" cy="12" rx="12" ry="4" fill="none" stroke="currentColor" stroke-width="1" stroke-dasharray="3 2"/>
|
||||
<ellipse cx="16" cy="18" rx="12" ry="4" fill="none" stroke="currentColor" stroke-width="1" stroke-dasharray="3 2"/>
|
||||
<!-- Access port -->
|
||||
<rect x="13" y="4" width="6" height="4" rx="1" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 866 B |
@@ -0,0 +1,10 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<!-- Stylus body -->
|
||||
<polygon points="8,4 24,4 28,8 16,30 4,8" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
|
||||
<!-- Stylus grip band -->
|
||||
<line x1="6" y1="10" x2="26" y2="10" stroke="currentColor" stroke-width="1.5"/>
|
||||
<!-- Tip -->
|
||||
<polygon points="16,25 13,29 19,29" fill="currentColor"/>
|
||||
<!-- SLA insignia on stylus face -->
|
||||
<text x="16" y="19" text-anchor="middle" font-family="sans-serif" font-size="7" font-weight="bold" fill="currentColor">SLA</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 567 B |
@@ -0,0 +1,15 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<!-- Main crate -->
|
||||
<rect x="3" y="8" width="26" height="20" fill="none" stroke="currentColor" stroke-width="2" rx="1"/>
|
||||
<!-- Lid -->
|
||||
<rect x="3" y="4" width="26" height="6" fill="currentColor" rx="1"/>
|
||||
<!-- Center clasp -->
|
||||
<rect x="13" y="6" width="6" height="4" rx="1" fill="currentColor" opacity="0.6"/>
|
||||
<!-- Horizontal divider on crate -->
|
||||
<line x1="3" y1="18" x2="29" y2="18" stroke="currentColor" stroke-width="1.5"/>
|
||||
<!-- Corner brackets -->
|
||||
<path d="M3,13 L3,10 L6,10" fill="none" stroke="currentColor" stroke-width="1.5"/>
|
||||
<path d="M29,13 L29,10 L26,10" fill="none" stroke="currentColor" stroke-width="1.5"/>
|
||||
<path d="M3,23 L3,26 L6,26" fill="none" stroke="currentColor" stroke-width="1.5"/>
|
||||
<path d="M29,23 L29,26 L26,26" fill="none" stroke="currentColor" stroke-width="1.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 881 B |
@@ -0,0 +1,13 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<!-- File/tablet body -->
|
||||
<path d="M5,2 H22 L28,8 V30 H5 Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
|
||||
<!-- Folded corner -->
|
||||
<path d="M22,2 L22,8 L28,8" fill="none" stroke="currentColor" stroke-width="1.5"/>
|
||||
<!-- Text lines -->
|
||||
<line x1="9" y1="13" x2="24" y2="13" stroke="currentColor" stroke-width="1.5"/>
|
||||
<line x1="9" y1="17" x2="24" y2="17" stroke="currentColor" stroke-width="1.5"/>
|
||||
<line x1="9" y1="21" x2="20" y2="21" stroke="currentColor" stroke-width="1.5"/>
|
||||
<!-- Classified stamp -->
|
||||
<rect x="7" y="24" width="10" height="4" rx="0.5" fill="none" stroke="currentColor" stroke-width="1.2" transform="rotate(-8 12 26)"/>
|
||||
<line x1="8" y1="26" x2="16" y2="26" stroke="currentColor" stroke-width="1" transform="rotate(-8 12 26)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 859 B |
@@ -0,0 +1,14 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<!-- Emitter housing -->
|
||||
<polygon points="12,6 20,6 22,12 10,12" fill="currentColor" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/>
|
||||
<!-- Lens circle -->
|
||||
<circle cx="16" cy="9" r="3" fill="none" stroke="currentColor" stroke-width="1.5" opacity="0.7"/>
|
||||
<!-- Beam spread (lower trapezoid) -->
|
||||
<polygon points="10,12 22,12 28,28 4,28" fill="currentColor" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/>
|
||||
<!-- Beam rays -->
|
||||
<line x1="16" y1="12" x2="16" y2="28" stroke="currentColor" stroke-width="1" opacity="0.5"/>
|
||||
<line x1="13" y1="12" x2="8" y2="28" stroke="currentColor" stroke-width="1"/>
|
||||
<line x1="19" y1="12" x2="24" y2="28" stroke="currentColor" stroke-width="1"/>
|
||||
<!-- Mounting bracket -->
|
||||
<rect x="14" y="2" width="4" height="5" rx="1" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 894 B |
@@ -0,0 +1,17 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<!-- Ruler body -->
|
||||
<rect x="2" y="12" width="28" height="8" rx="1" fill="none" stroke="currentColor" stroke-width="2"/>
|
||||
<!-- Major tick marks -->
|
||||
<line x1="9" y1="12" x2="9" y2="17" stroke="currentColor" stroke-width="1.5"/>
|
||||
<line x1="16" y1="12" x2="16" y2="20" stroke="currentColor" stroke-width="2"/>
|
||||
<line x1="23" y1="12" x2="23" y2="17" stroke="currentColor" stroke-width="1.5"/>
|
||||
<!-- Minor ticks -->
|
||||
<line x1="5" y1="12" x2="5" y2="15" stroke="currentColor" stroke-width="1"/>
|
||||
<line x1="12" y1="12" x2="12" y2="15" stroke="currentColor" stroke-width="1"/>
|
||||
<line x1="19" y1="12" x2="19" y2="15" stroke="currentColor" stroke-width="1"/>
|
||||
<line x1="26" y1="12" x2="26" y2="15" stroke="currentColor" stroke-width="1"/>
|
||||
<!-- Arrow / range indicator above -->
|
||||
<line x1="4" y1="8" x2="28" y2="8" stroke="currentColor" stroke-width="1.5"/>
|
||||
<polygon points="4,8 8,6 8,10" fill="currentColor"/>
|
||||
<polygon points="28,8 24,6 24,10" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1,11 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<!-- Map pin shape -->
|
||||
<path d="M16,2 C10,2 6,7 6,12 C6,19 16,30 16,30 C16,30 26,19 26,12 C26,7 22,2 16,2 Z" fill="currentColor" stroke="currentColor" stroke-width="2"/>
|
||||
<!-- Inner ring -->
|
||||
<circle cx="16" cy="12" r="5" fill="none" stroke="currentColor" stroke-width="2"/>
|
||||
<!-- Center dot -->
|
||||
<circle cx="16" cy="12" r="2.5" fill="currentColor"/>
|
||||
<!-- Angular bracket decorations -->
|
||||
<path d="M10,5 L8,7" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
||||
<path d="M22,5 L24,7" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 644 B |
@@ -0,0 +1,11 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<!-- Waveform bars -->
|
||||
<rect x="2" y="12" width="3" height="8" rx="1" fill="currentColor"/>
|
||||
<rect x="7" y="7" width="3" height="18" rx="1" fill="currentColor"/>
|
||||
<rect x="12" y="4" width="3" height="24" rx="1" fill="currentColor"/>
|
||||
<rect x="17" y="9" width="3" height="14" rx="1" fill="currentColor"/>
|
||||
<rect x="22" y="6" width="3" height="20" rx="1" fill="currentColor"/>
|
||||
<rect x="27" y="13" width="3" height="6" rx="1" fill="currentColor"/>
|
||||
<!-- Base line -->
|
||||
<line x1="2" y1="29" x2="30" y2="29" stroke="currentColor" stroke-width="1"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 631 B |
@@ -0,0 +1,16 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<!-- Outer border -->
|
||||
<rect x="2" y="2" width="28" height="28" fill="none" stroke="currentColor" stroke-width="2" rx="1"/>
|
||||
<!-- Grid lines -->
|
||||
<line x1="11" y1="2" x2="11" y2="30" stroke="currentColor" stroke-width="1"/>
|
||||
<line x1="21" y1="2" x2="21" y2="30" stroke="currentColor" stroke-width="1"/>
|
||||
<line x1="2" y1="11" x2="30" y2="11" stroke="currentColor" stroke-width="1"/>
|
||||
<line x1="2" y1="21" x2="30" y2="21" stroke="currentColor" stroke-width="1"/>
|
||||
<!-- Sector fills — industrial blocks -->
|
||||
<rect x="3" y="3" width="7" height="7" fill="currentColor"/>
|
||||
<rect x="13" y="13" width="7" height="7" fill="currentColor" opacity="0.6"/>
|
||||
<rect x="22" y="22" width="7" height="7" fill="currentColor"/>
|
||||
<rect x="22" y="3" width="7" height="7" fill="currentColor"/>
|
||||
<!-- Location marker -->
|
||||
<polygon points="16,17 14,21 18,21" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 940 B |
@@ -0,0 +1,16 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<!-- Hex gear outer -->
|
||||
<polygon points="16,2 27,8 27,20 16,26 5,20 5,8" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linejoin="round"/>
|
||||
<!-- Gear teeth on hex edges -->
|
||||
<polygon points="16,1 18,4 14,4" fill="currentColor"/>
|
||||
<polygon points="27.5,7.5 27,11 24.5,9.5" fill="currentColor"/>
|
||||
<polygon points="27.5,20.5 24.5,22.5 27,19" fill="currentColor"/>
|
||||
<polygon points="16,27 14,24 18,24" fill="currentColor"/>
|
||||
<polygon points="4.5,20.5 5,19 7.5,22.5" fill="currentColor"/>
|
||||
<polygon points="4.5,7.5 7.5,9.5 5,11" fill="currentColor"/>
|
||||
<!-- Inner hex cutout -->
|
||||
<polygon points="16,9 21,12 21,18 16,21 11,18 11,12" fill="currentColor"/>
|
||||
<!-- Center circle -->
|
||||
<circle cx="16" cy="15" r="3.5" fill="none" stroke="currentColor" stroke-width="2"/>
|
||||
<circle cx="16" cy="15" r="1.5" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 910 B |
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<!-- Speaker cone -->
|
||||
<polygon points="4,11 12,11 20,5 20,27 12,21 4,21" fill="currentColor" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/>
|
||||
<!-- Sound wave arcs -->
|
||||
<path d="M23,10 C26,12 26,20 23,22" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M25,7 C30,11 30,21 25,25" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" opacity="0.6"/>
|
||||
<!-- Base line -->
|
||||
<rect x="4" y="21" width="8" height="5" rx="0.5" fill="currentColor" opacity="0.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 609 B |
@@ -0,0 +1,15 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<!-- Outer frame -->
|
||||
<rect x="2" y="3" width="28" height="26" fill="none" stroke="currentColor" stroke-width="2" rx="1"/>
|
||||
<!-- Header row -->
|
||||
<rect x="2" y="3" width="28" height="6" fill="currentColor" rx="1"/>
|
||||
<!-- Row dividers -->
|
||||
<line x1="2" y1="15" x2="30" y2="15" stroke="currentColor" stroke-width="1"/>
|
||||
<line x1="2" y1="21" x2="30" y2="21" stroke="currentColor" stroke-width="1"/>
|
||||
<!-- Column dividers -->
|
||||
<line x1="10" y1="9" x2="10" y2="29" stroke="currentColor" stroke-width="1"/>
|
||||
<line x1="21" y1="9" x2="21" y2="29" stroke="currentColor" stroke-width="1"/>
|
||||
<!-- Die symbol in first col -->
|
||||
<rect x="4" y="11" width="4" height="4" rx="0.5" fill="none" stroke="currentColor" stroke-width="1"/>
|
||||
<circle cx="6" cy="13" r="0.8" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 851 B |
@@ -0,0 +1,14 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<!-- 2x2 tile grid with isometric feel -->
|
||||
<!-- Top-left tile -->
|
||||
<rect x="2" y="2" width="13" height="13" rx="1" fill="currentColor" stroke="currentColor" stroke-width="1.5"/>
|
||||
<!-- Top-right tile -->
|
||||
<rect x="17" y="2" width="13" height="13" rx="1" fill="currentColor" opacity="0.5" stroke="currentColor" stroke-width="1.5"/>
|
||||
<!-- Bottom-left tile -->
|
||||
<rect x="2" y="17" width="13" height="13" rx="1" fill="currentColor" opacity="0.5" stroke="currentColor" stroke-width="1.5"/>
|
||||
<!-- Bottom-right tile -->
|
||||
<rect x="17" y="17" width="13" height="13" rx="1" fill="currentColor" stroke="currentColor" stroke-width="1.5"/>
|
||||
<!-- Corner brackets on tiles -->
|
||||
<path d="M4,7 L4,4 L7,4" fill="none" stroke="currentColor" stroke-width="1.2"/>
|
||||
<path d="M19,7 L19,4 L22,4" fill="none" stroke="currentColor" stroke-width="1.2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 907 B |
@@ -0,0 +1,10 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<!-- Hex base -->
|
||||
<polygon points="16,3 28,10 28,22 16,29 4,22 4,10" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
|
||||
<!-- Inner ring -->
|
||||
<polygon points="16,8 23,12 23,20 16,24 9,20 9,12" fill="none" stroke="currentColor" stroke-width="1"/>
|
||||
<!-- Head silhouette -->
|
||||
<circle cx="16" cy="14" r="3.5" fill="currentColor"/>
|
||||
<!-- Shoulders -->
|
||||
<path d="M10,23 C10,19 22,19 22,23" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 509 B |
@@ -0,0 +1,14 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<!-- Main wall line heavy -->
|
||||
<line x1="4" y1="16" x2="28" y2="16" stroke="currentColor" stroke-width="4"/>
|
||||
<!-- Wall battlements (top) -->
|
||||
<rect x="5" y="10" width="4" height="6" fill="currentColor"/>
|
||||
<rect x="13" y="10" width="4" height="6" fill="currentColor"/>
|
||||
<rect x="21" y="10" width="4" height="6" fill="currentColor"/>
|
||||
<!-- Wall base foundation -->
|
||||
<rect x="3" y="20" width="26" height="4" rx="1" fill="currentColor" opacity="0.5"/>
|
||||
<!-- Door gap indicator -->
|
||||
<rect x="14" y="16" width="4" height="4" fill="currentColor" opacity="0"/>
|
||||
<line x1="14" y1="16" x2="14" y2="24" stroke="currentColor" stroke-width="1" stroke-dasharray="2 2" opacity="0.7"/>
|
||||
<line x1="18" y1="16" x2="18" y2="24" stroke="currentColor" stroke-width="1" stroke-dasharray="2 2" opacity="0.7"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 869 B |
@@ -258,6 +258,9 @@ export class MothershipActorSheet extends foundry.appv1.sheets.ActorSheet {
|
||||
superData.sla.fluxNotes ??= { value: "" };
|
||||
superData.sla.ebbNotes ??= { value: "" };
|
||||
superData.sla.speciesRules ??= {};
|
||||
superData.sla.sessionAbilityUsed ??= false;
|
||||
superData.sla.contacts ??= [];
|
||||
superData.sla.activityLog ??= { value: "" };
|
||||
const activeTheme = this.actor.getFlag("sla-mothership", "sheetTheme") || "modern";
|
||||
data.slaSheetTheme = activeTheme;
|
||||
data.data.slaSheetTheme = activeTheme;
|
||||
@@ -292,6 +295,17 @@ export class MothershipActorSheet extends foundry.appv1.sheets.ActorSheet {
|
||||
disadvantage: String(this._slaTraitPickerSelection?.disadvantage ?? "").trim()
|
||||
};
|
||||
data.data.slaPrometheusStatus = this.actor.getSlaPrometheusStatus?.() ?? { enabled: false, inCombat: false, currentRound: 0, roundsUntilPulse: null, pulseThisRound: false };
|
||||
|
||||
// Contacts
|
||||
const rawContacts = Array.isArray(superData.sla.contacts) ? superData.sla.contacts : [];
|
||||
data.data.slaContacts = rawContacts.map((c) => ({
|
||||
id: String(c.id ?? foundry.utils.randomID()),
|
||||
name: String(c.name ?? "Unknown"),
|
||||
role: String(c.role ?? ""),
|
||||
notes: String(c.notes ?? ""),
|
||||
disposition: ["ally", "neutral", "hostile", "unknown"].includes(c.disposition) ? c.disposition : "neutral"
|
||||
}));
|
||||
data.data.slaContactCount = data.data.slaContacts.length;
|
||||
const traitRows = buildSlaTraitRows(data.data.persTraits ?? []);
|
||||
data.data.persTraitsEnhanced = traitRows;
|
||||
data.data.traitCount = traitRows.length;
|
||||
@@ -933,8 +947,123 @@ export class MothershipActorSheet extends foundry.appv1.sheets.ActorSheet {
|
||||
this.render(false);
|
||||
});
|
||||
|
||||
html.find('.sla-panic-button').click(ev => {
|
||||
this.actor.rollTable("panicCheck", null, null, null, null, null, null);
|
||||
// SCL fractional adjustment buttons
|
||||
html.find('.sla-scl-adjust').click(async (ev) => {
|
||||
ev.preventDefault();
|
||||
const delta = parseFloat(ev.currentTarget.dataset.delta ?? 0);
|
||||
if (!delta) return;
|
||||
const current = parseFloat(String(this.actor.system?.sla?.scl?.value ?? "0").replace(",", ".")) || 0;
|
||||
const next = Math.max(0, Math.round((current + delta) * 10) / 10);
|
||||
const formatted = Number.isInteger(next) ? String(next) : next.toFixed(1);
|
||||
await this.actor.update({ "system.sla.scl.value": formatted });
|
||||
this.render(false);
|
||||
});
|
||||
|
||||
// Session ability tracking — checkbox
|
||||
html.find('.sla-session-ability-used').on('change', async (ev) => {
|
||||
ev.stopPropagation();
|
||||
await this.actor.update({ "system.sla.sessionAbilityUsed": ev.currentTarget.checked });
|
||||
});
|
||||
|
||||
// New Session reset button
|
||||
html.find('.sla-new-session').click(async (ev) => {
|
||||
ev.preventDefault();
|
||||
const confirmed = await Dialog.confirm({
|
||||
title: "New Session",
|
||||
content: "<p>Start a new session? This will reset the trauma response session ability for this operative.</p>",
|
||||
defaultYes: true
|
||||
});
|
||||
if (!confirmed) return;
|
||||
await this.actor.update({ "system.sla.sessionAbilityUsed": false });
|
||||
ui.notifications.info(`${this.actor.name}: session ability reset for new session.`);
|
||||
this.render(false);
|
||||
});
|
||||
|
||||
// Rest button — short or long rest dialog
|
||||
html.find('.sla-rest-button').click(async (ev) => {
|
||||
ev.preventDefault();
|
||||
const restType = await new Promise((resolve) => {
|
||||
new Dialog({
|
||||
title: "Take a Rest",
|
||||
content: `
|
||||
<p>What kind of rest is <strong>${this.actor.name}</strong> taking?</p>
|
||||
<p><strong>Short Rest:</strong> Removes non-permanent conditions. No stat recovery.</p>
|
||||
<p><strong>Long Rest:</strong> Removes non-permanent conditions and fully restores Flux (if Ebb user).</p>
|
||||
`,
|
||||
buttons: {
|
||||
short: { icon: '<i class="fas fa-moon"></i>', label: "Short Rest", callback: () => resolve("short") },
|
||||
long: { icon: '<i class="fas fa-bed"></i>', label: "Long Rest", callback: () => resolve("long") },
|
||||
cancel: { icon: '<i class="fas fa-times"></i>', label: "Cancel", callback: () => resolve(null) }
|
||||
},
|
||||
default: "short"
|
||||
}).render(true);
|
||||
});
|
||||
if (!restType) return;
|
||||
|
||||
const updates = {};
|
||||
// Remove temporary conditions (items of type "condition")
|
||||
const conditionIds = this.actor.items
|
||||
.filter((item) => item.type === "condition")
|
||||
.map((item) => item.id);
|
||||
if (conditionIds.length > 0) {
|
||||
await this.actor.deleteEmbeddedDocuments("Item", conditionIds);
|
||||
}
|
||||
|
||||
if (restType === "long") {
|
||||
// Restore Flux to max for Ebb users
|
||||
const isEbb = this.actor.isSlaEbbUser?.() ?? false;
|
||||
if (isEbb) {
|
||||
const fluxMax = Math.max(0, Number(this.actor.system?.sla?.flux?.max ?? 0));
|
||||
updates["system.sla.flux.value"] = fluxMax;
|
||||
await this.actor.updateSlaFluxState?.(fluxMax, { save: true });
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(updates).length > 0) {
|
||||
await this.actor.update(updates);
|
||||
}
|
||||
|
||||
const condMsg = conditionIds.length > 0 ? ` Cleared ${conditionIds.length} condition(s).` : "";
|
||||
const fluxMsg = restType === "long" && (this.actor.isSlaEbbUser?.() ?? false) ? " Flux restored." : "";
|
||||
ui.notifications.info(`${this.actor.name}: ${restType === "long" ? "Long" : "Short"} rest complete.${condMsg}${fluxMsg}`);
|
||||
await this.actor.addSlaActivityLog?.(`${restType === "long" ? "Long" : "Short"} rest.${condMsg}${fluxMsg}`);
|
||||
this.render(false);
|
||||
});
|
||||
|
||||
// Contact add button
|
||||
html.find('.sla-contact-add').click(async (ev) => {
|
||||
ev.preventDefault();
|
||||
await this._slaContactDialog(null);
|
||||
});
|
||||
|
||||
// Contact edit button
|
||||
html.find('.sla-contact-edit').click(async (ev) => {
|
||||
ev.preventDefault();
|
||||
const contactId = String(ev.currentTarget.dataset.contactId ?? "").trim();
|
||||
if (!contactId) return;
|
||||
await this._slaContactDialog(contactId);
|
||||
});
|
||||
|
||||
// Contact delete button
|
||||
html.find('.sla-contact-delete').click(async (ev) => {
|
||||
ev.preventDefault();
|
||||
const contactId = String(ev.currentTarget.dataset.contactId ?? "").trim();
|
||||
if (!contactId) return;
|
||||
const confirmed = await Dialog.confirm({
|
||||
title: "Delete Contact",
|
||||
content: "<p>Remove this contact from the operative's network?</p>",
|
||||
defaultYes: false
|
||||
});
|
||||
if (!confirmed) return;
|
||||
const contacts = Array.isArray(this.actor.system?.sla?.contacts) ? [...this.actor.system.sla.contacts] : [];
|
||||
const updated = contacts.filter((c) => c.id !== contactId);
|
||||
await this.actor.update({ "system.sla.contacts": updated });
|
||||
this.render(false);
|
||||
});
|
||||
|
||||
html.find('.sla-panic-button').click(async ev => {
|
||||
await this.actor.rollTable("panicCheck", null, null, null, null, null, null);
|
||||
await this.actor.addSlaActivityLog?.("Panic check triggered.");
|
||||
});
|
||||
|
||||
html.find('.sla-wound-button').click(ev => {
|
||||
@@ -1210,6 +1339,76 @@ export class MothershipActorSheet extends foundry.appv1.sheets.ActorSheet {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a dialog for adding or editing a contact
|
||||
* @param {string|null} contactId null = add new, string = edit existing
|
||||
*/
|
||||
async _slaContactDialog(contactId) {
|
||||
const contacts = Array.isArray(this.actor.system?.sla?.contacts) ? [...this.actor.system.sla.contacts] : [];
|
||||
const existing = contactId ? contacts.find((c) => c.id === contactId) : null;
|
||||
const isNew = !existing;
|
||||
|
||||
const name = existing?.name ?? "";
|
||||
const role = existing?.role ?? "";
|
||||
const notes = existing?.notes ?? "";
|
||||
const disposition = existing?.disposition ?? "neutral";
|
||||
|
||||
const content = `
|
||||
<div style="display:grid; gap:8px; padding:8px 0;">
|
||||
<div>
|
||||
<label style="font-size:0.8rem; font-weight:600; display:block; margin-bottom:4px;">Name</label>
|
||||
<input type="text" id="sla-contact-name" value="${name}" placeholder="Contact name" style="width:100%;" />
|
||||
</div>
|
||||
<div>
|
||||
<label style="font-size:0.8rem; font-weight:600; display:block; margin-bottom:4px;">Role / Occupation</label>
|
||||
<input type="text" id="sla-contact-role" value="${role}" placeholder="e.g. Fixer, Fence, Squad medic" style="width:100%;" />
|
||||
</div>
|
||||
<div>
|
||||
<label style="font-size:0.8rem; font-weight:600; display:block; margin-bottom:4px;">Disposition</label>
|
||||
<select id="sla-contact-disposition" style="width:100%;">
|
||||
<option value="ally" ${disposition === "ally" ? "selected" : ""}>Ally</option>
|
||||
<option value="neutral" ${disposition === "neutral" ? "selected" : ""}>Neutral</option>
|
||||
<option value="hostile" ${disposition === "hostile" ? "selected" : ""}>Hostile</option>
|
||||
<option value="unknown" ${disposition === "unknown" ? "selected" : ""}>Unknown</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label style="font-size:0.8rem; font-weight:600; display:block; margin-bottom:4px;">Notes</label>
|
||||
<textarea id="sla-contact-notes" rows="3" placeholder="Sector, history, how they know the operative..." style="width:100%;">${notes}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const result = await Dialog.prompt({
|
||||
title: isNew ? "Add Contact" : "Edit Contact",
|
||||
content,
|
||||
label: isNew ? "Add" : "Save",
|
||||
callback: (html) => {
|
||||
const nameVal = String(html.find("#sla-contact-name").val() ?? "").trim();
|
||||
if (!nameVal) return null;
|
||||
return {
|
||||
id: existing?.id ?? foundry.utils.randomID(),
|
||||
name: nameVal,
|
||||
role: String(html.find("#sla-contact-role").val() ?? "").trim(),
|
||||
disposition: String(html.find("#sla-contact-disposition").val() ?? "neutral"),
|
||||
notes: String(html.find("#sla-contact-notes").val() ?? "").trim()
|
||||
};
|
||||
},
|
||||
rejectClose: false
|
||||
});
|
||||
|
||||
if (!result) return;
|
||||
|
||||
let updated;
|
||||
if (isNew) {
|
||||
updated = [...contacts, result];
|
||||
} else {
|
||||
updated = contacts.map((c) => c.id === contactId ? result : c);
|
||||
}
|
||||
await this.actor.update({ "system.sla.contacts": updated });
|
||||
this.render(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend and override the sheet header buttons
|
||||
* @override
|
||||
|
||||
@@ -497,11 +497,44 @@ export class MothershipActor extends Actor {
|
||||
}
|
||||
|
||||
async useSlaDrug(itemId) {
|
||||
return SLADrugSystem.useDrug({ actor: this, itemId });
|
||||
const result = await SLADrugSystem.useDrug({ actor: this, itemId });
|
||||
if (result?.ok !== false) {
|
||||
const item = this.items.get(itemId);
|
||||
if (item) await this.addSlaActivityLog(`Drug used: ${item.name}.`);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async closeSlaDrug(itemId = "", drug = "") {
|
||||
return SLADrugSystem.closeDrug({ actor: this, itemId, drug });
|
||||
const result = await SLADrugSystem.closeDrug({ actor: this, itemId, drug });
|
||||
if (result?.ok !== false) {
|
||||
const drugName = drug || (itemId ? (this.items.get(itemId)?.name ?? "Unknown drug") : "Unknown drug");
|
||||
await this.addSlaActivityLog(`Drug effect ended: ${drugName}.`);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a timestamped line to the operative's activity log.
|
||||
* Keeps newest entries at the top and trims to ~10 KB.
|
||||
*/
|
||||
async addSlaActivityLog(entry) {
|
||||
try {
|
||||
const now = new Date();
|
||||
const ts = now.toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit" });
|
||||
const line = `[${ts}] ${entry}`;
|
||||
const current = String(this.system?.sla?.activityLog?.value ?? "");
|
||||
const combined = current ? `${line}\n${current}` : line;
|
||||
// Trim oldest lines until under 10 KB
|
||||
const MAX = 10240;
|
||||
if (combined.length > MAX) {
|
||||
const lines = combined.split("\n");
|
||||
while (lines.join("\n").length > MAX && lines.length > 1) lines.pop();
|
||||
await this.update({ "system.sla.activityLog.value": lines.join("\n") });
|
||||
} else {
|
||||
await this.update({ "system.sla.activityLog.value": combined });
|
||||
}
|
||||
} catch (_) { /* log failures are non-fatal */ }
|
||||
}
|
||||
|
||||
//central flavor text library for all chat messages
|
||||
@@ -3007,6 +3040,18 @@ export class MothershipActor extends Actor {
|
||||
await this.rollTable("panicCheck", null, null, null, null, null, null);
|
||||
}
|
||||
}
|
||||
// Activity log
|
||||
if (this.type === "character" && specialRoll !== "damage") {
|
||||
try {
|
||||
const rollLabel = skill && skill !== "none" ? skill : (attribute ? String(attribute).charAt(0).toUpperCase() + String(attribute).slice(1) : "Roll");
|
||||
const resultNum = Number(parsedRollResult?.total ?? 0);
|
||||
const outcome = parsedRollResult?.success
|
||||
? (parsedRollResult.critical ? "Critical success" : "Pass")
|
||||
: (parsedRollResult?.critical ? "Critical failure" : "Fail");
|
||||
const critTag = parsedRollResult?.critical ? " ★" : "";
|
||||
await this.addSlaActivityLog(`${rollLabel}: rolled ${resultNum} vs ${rollTarget} — ${outcome}${critTag}`);
|
||||
} catch (_) {}
|
||||
}
|
||||
return [messageData];
|
||||
}
|
||||
|
||||
@@ -5299,6 +5344,8 @@ export class MothershipActor extends Actor {
|
||||
if (shouldPanic) {
|
||||
await this.rollTable("panicCheck", null, null, null, null, null, null);
|
||||
}
|
||||
const saveOutcome = saveResult ? (saveResult.success ? "Pass" : "Fail") : "n/a";
|
||||
await this.addSlaActivityLog(`Flux ${forcePanic ? "Panic forced" : "Save"} — Fear save ${saveOutcome}. Flux ${this.system?.sla?.flux?.value ?? 0}/${this.system?.sla?.flux?.max ?? 0}.${shouldPanic ? " Panic triggered." : ""}`);
|
||||
return { saveResult, state, panicTriggered: shouldPanic };
|
||||
}
|
||||
|
||||
|
||||
@@ -1249,3 +1249,302 @@ export function formatCreditsNumber(num) {
|
||||
return num.toString() + 'cr';
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// SLA Industries Pause Screen Animation
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
function injectSlaPauseAnimation() {
|
||||
const pauseEl = document.querySelector('#pause');
|
||||
if (!pauseEl) return;
|
||||
|
||||
// Don't inject twice
|
||||
if (pauseEl.querySelector('.sla-pause-root')) return;
|
||||
|
||||
// Aggressively hide ALL of Foundry's default pause content
|
||||
// Hide every direct child that isn't our injected element
|
||||
Array.from(pauseEl.children).forEach(child => {
|
||||
child.style.setProperty('display', 'none', 'important');
|
||||
});
|
||||
// Also kill any descendant with animation or image content
|
||||
pauseEl.querySelectorAll('figure, img, svg, h3, p, .fas, .fa-cog, canvas').forEach(el => {
|
||||
el.style.setProperty('display', 'none', 'important');
|
||||
});
|
||||
|
||||
const svgHTML = `
|
||||
<div class="sla-pause-root" aria-label="SLA Industries – Game Paused">
|
||||
<svg
|
||||
class="sla-pause-svg"
|
||||
viewBox="-120 -120 240 260"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
role="img"
|
||||
>
|
||||
<defs>
|
||||
<!-- Red glow filter for the logo and satellites -->
|
||||
<filter id="sla-glow-red" x="-50%" y="-50%" width="200%" height="200%">
|
||||
<feGaussianBlur stdDeviation="3.5" result="blur"/>
|
||||
<feMerge>
|
||||
<feMergeNode in="blur"/>
|
||||
<feMergeNode in="SourceGraphic"/>
|
||||
</feMerge>
|
||||
</filter>
|
||||
<!-- Subtle glow for rings -->
|
||||
<filter id="sla-glow-ring" x="-30%" y="-30%" width="160%" height="160%">
|
||||
<feGaussianBlur stdDeviation="1.5" result="blur"/>
|
||||
<feMerge>
|
||||
<feMergeNode in="blur"/>
|
||||
<feMergeNode in="SourceGraphic"/>
|
||||
</feMerge>
|
||||
</filter>
|
||||
<!-- Radial gradient for background disc -->
|
||||
<radialGradient id="sla-bg-grad" cx="50%" cy="50%" r="50%">
|
||||
<stop offset="0%" stop-color="#1a0000" stop-opacity="0.95"/>
|
||||
<stop offset="100%" stop-color="#000000" stop-opacity="0.0"/>
|
||||
</radialGradient>
|
||||
<!-- Clip for the inner content -->
|
||||
<clipPath id="sla-clip-outer">
|
||||
<circle cx="0" cy="0" r="108"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
|
||||
<!-- Ambient background disc -->
|
||||
<circle cx="0" cy="0" r="108" fill="url(#sla-bg-grad)"/>
|
||||
|
||||
<!-- ── Outer ring (clockwise) ── -->
|
||||
<g class="sla-ring-outer">
|
||||
<!-- Dashed orbit path -->
|
||||
<circle cx="0" cy="0" r="90"
|
||||
fill="none"
|
||||
stroke="#8b1a1a"
|
||||
stroke-width="0.8"
|
||||
stroke-dasharray="6 4"
|
||||
opacity="0.7"
|
||||
filter="url(#sla-glow-ring)"
|
||||
/>
|
||||
<!-- 3 red satellite dots at 0°, 120°, 240° -->
|
||||
<circle cx="0" cy="-90" r="5" fill="#cc2222" filter="url(#sla-glow-red)" class="sla-sat"/>
|
||||
<circle cx="77.9" cy="45" r="5" fill="#cc2222" filter="url(#sla-glow-red)" class="sla-sat"/>
|
||||
<circle cx="-77.9" cy="45" r="5" fill="#cc2222" filter="url(#sla-glow-red)" class="sla-sat"/>
|
||||
<!-- Thin tick marks every 30° on outer ring -->
|
||||
<line x1="0" y1="-86" x2="0" y2="-94" stroke="#8b1a1a" stroke-width="1" transform="rotate(0)"/>
|
||||
<line x1="0" y1="-86" x2="0" y2="-94" stroke="#8b1a1a" stroke-width="1" transform="rotate(30)"/>
|
||||
<line x1="0" y1="-86" x2="0" y2="-94" stroke="#8b1a1a" stroke-width="1" transform="rotate(60)"/>
|
||||
<line x1="0" y1="-86" x2="0" y2="-94" stroke="#8b1a1a" stroke-width="1" transform="rotate(90)"/>
|
||||
<line x1="0" y1="-86" x2="0" y2="-94" stroke="#8b1a1a" stroke-width="1" transform="rotate(120)"/>
|
||||
<line x1="0" y1="-86" x2="0" y2="-94" stroke="#8b1a1a" stroke-width="1" transform="rotate(150)"/>
|
||||
<line x1="0" y1="-86" x2="0" y2="-94" stroke="#8b1a1a" stroke-width="1" transform="rotate(180)"/>
|
||||
<line x1="0" y1="-86" x2="0" y2="-94" stroke="#8b1a1a" stroke-width="1" transform="rotate(210)"/>
|
||||
<line x1="0" y1="-86" x2="0" y2="-94" stroke="#8b1a1a" stroke-width="1" transform="rotate(240)"/>
|
||||
<line x1="0" y1="-86" x2="0" y2="-94" stroke="#8b1a1a" stroke-width="1" transform="rotate(270)"/>
|
||||
<line x1="0" y1="-86" x2="0" y2="-94" stroke="#8b1a1a" stroke-width="1" transform="rotate(300)"/>
|
||||
<line x1="0" y1="-86" x2="0" y2="-94" stroke="#8b1a1a" stroke-width="1" transform="rotate(330)"/>
|
||||
</g>
|
||||
|
||||
<!-- ── Inner ring (counter-clockwise) ── -->
|
||||
<g class="sla-ring-inner">
|
||||
<circle cx="0" cy="0" r="62"
|
||||
fill="none"
|
||||
stroke="#6b1010"
|
||||
stroke-width="0.6"
|
||||
stroke-dasharray="4 6"
|
||||
opacity="0.6"
|
||||
filter="url(#sla-glow-ring)"
|
||||
/>
|
||||
<!-- 3 smaller orange-red dots at 60°, 180°, 300° offset for variety -->
|
||||
<circle cx="53.7" cy="-31" r="3.5" fill="#dd4422" filter="url(#sla-glow-red)" class="sla-sat-inner"/>
|
||||
<circle cx="-53.7" cy="-31" r="3.5" fill="#dd4422" filter="url(#sla-glow-red)" class="sla-sat-inner"/>
|
||||
<circle cx="0" cy="62" r="3.5" fill="#dd4422" filter="url(#sla-glow-red)" class="sla-sat-inner"/>
|
||||
</g>
|
||||
|
||||
<!-- ── Central "SLA" logotype ── -->
|
||||
<g filter="url(#sla-glow-red)">
|
||||
<!-- Hexagonal backing plate -->
|
||||
<polygon
|
||||
points="0,-38 33,-19 33,19 0,38 -33,19 -33,-19"
|
||||
fill="#1a0000"
|
||||
stroke="#cc2222"
|
||||
stroke-width="1.2"
|
||||
opacity="0.9"
|
||||
/>
|
||||
<!-- SLA text -->
|
||||
<text
|
||||
x="0" y="14"
|
||||
text-anchor="middle"
|
||||
font-family="'Oswald', 'Impact', 'Arial Narrow', sans-serif"
|
||||
font-size="38"
|
||||
font-weight="700"
|
||||
letter-spacing="3"
|
||||
fill="#ff2222"
|
||||
class="sla-pause-logo-text"
|
||||
>SLA</text>
|
||||
</g>
|
||||
|
||||
<!-- ── Thin separator lines ── -->
|
||||
<line x1="-70" y1="48" x2="70" y2="48" stroke="#8b1a1a" stroke-width="0.5" opacity="0.7"/>
|
||||
|
||||
<!-- ── "STAND BY" label ── -->
|
||||
<text
|
||||
x="0" y="70"
|
||||
text-anchor="middle"
|
||||
font-family="'Oswald', 'Courier New', monospace"
|
||||
font-size="13"
|
||||
font-weight="400"
|
||||
letter-spacing="5"
|
||||
fill="#cc4444"
|
||||
class="sla-pause-standby"
|
||||
>STAND BY</text>
|
||||
|
||||
<!-- ── "SLA INDUSTRIES" footer text ── -->
|
||||
<text
|
||||
x="0" y="95"
|
||||
text-anchor="middle"
|
||||
font-family="'Oswald', 'Arial Narrow', sans-serif"
|
||||
font-size="7"
|
||||
font-weight="300"
|
||||
letter-spacing="3"
|
||||
fill="#661111"
|
||||
opacity="0.85"
|
||||
>SLA INDUSTRIES</text>
|
||||
|
||||
<!-- ── Scanning line sweep ── -->
|
||||
<line
|
||||
x1="0" y1="-90" x2="0" y2="0"
|
||||
stroke="#ff2222"
|
||||
stroke-width="0.8"
|
||||
opacity="0.18"
|
||||
class="sla-pause-scan"
|
||||
/>
|
||||
</svg>
|
||||
</div>`;
|
||||
|
||||
// Inject directly into the pause element (not into figure, which we hid)
|
||||
pauseEl.insertAdjacentHTML('beforeend', svgHTML);
|
||||
}
|
||||
|
||||
Hooks.once('ready', () => {
|
||||
// Inject if game is already paused on load
|
||||
if (game.paused) injectSlaPauseAnimation();
|
||||
});
|
||||
|
||||
// Use the pauseGame hook exclusively — don't use a MutationObserver
|
||||
// which could fight Foundry's own show/hide logic on the #pause element.
|
||||
Hooks.on('pauseGame', (paused) => {
|
||||
if (paused) {
|
||||
// Two-frame delay — Foundry renders the pause figure asynchronously
|
||||
requestAnimationFrame(() => requestAnimationFrame(() => injectSlaPauseAnimation()));
|
||||
} else {
|
||||
// On unpause: remove our injected content so it can be re-injected cleanly next time
|
||||
const slaRoot = document.querySelector('#pause .sla-pause-root');
|
||||
if (slaRoot) slaRoot.remove();
|
||||
// Restore Foundry's original pause children (they were hidden inline, unhide them)
|
||||
const pauseEl = document.querySelector('#pause');
|
||||
if (pauseEl) {
|
||||
pauseEl.querySelectorAll(':scope > *:not(.sla-pause-root)').forEach(child => {
|
||||
child.style.removeProperty('display');
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// SLA Industries — UI Icon Injection
|
||||
// Replaces Foundry's Font Awesome icons in the sidebar and scene controls
|
||||
// by walking the live DOM and applying inline CSS mask-image styles.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
const SLA_ICON_BASE = "systems/sla-mothership/icons/ui/";
|
||||
|
||||
const SLA_SIDEBAR_ICONS = {
|
||||
chat: "chat",
|
||||
combat: "combat",
|
||||
scenes: "scenes",
|
||||
actors: "actors",
|
||||
items: "items",
|
||||
journal: "journal",
|
||||
tables: "tables",
|
||||
playlists: "playlists",
|
||||
compendium: "compendium",
|
||||
settings: "settings",
|
||||
};
|
||||
|
||||
const SLA_CONTROL_ICONS = {
|
||||
token: "token",
|
||||
measure: "measure",
|
||||
tiles: "tiles",
|
||||
drawings: "drawings",
|
||||
walls: "walls",
|
||||
lighting: "lighting",
|
||||
sounds: "sounds",
|
||||
notes: "notes",
|
||||
};
|
||||
|
||||
function _slaApplyIconMask(el, iconFile) {
|
||||
const url = `${SLA_ICON_BASE}${iconFile}.svg`;
|
||||
// Measure font size BEFORE zeroing it — FA icons scale with font-size
|
||||
const fs = parseFloat(getComputedStyle(el).fontSize) || 18;
|
||||
const sz = Math.round(fs * 1.15) + "px";
|
||||
|
||||
// font-size:0 → collapses the ::before FA glyph to nothing
|
||||
// currentColor → inherits the button's text colour (white/grey/active from Foundry)
|
||||
// mask → cuts that fill into our SVG shape
|
||||
el.style.setProperty("font-size", "0", "important");
|
||||
el.style.setProperty("line-height", "0", "important");
|
||||
el.style.setProperty("width", sz, "important");
|
||||
el.style.setProperty("height", sz, "important");
|
||||
el.style.setProperty("display", "inline-flex", "important");
|
||||
el.style.setProperty("align-items", "center", "important");
|
||||
el.style.setProperty("justify-content", "center", "important");
|
||||
el.style.setProperty("background-color", "currentColor", "important");
|
||||
el.style.setProperty("-webkit-mask", `url('${url}') center/contain no-repeat`, "important");
|
||||
el.style.setProperty("mask", `url('${url}') center/contain no-repeat`, "important");
|
||||
el.setAttribute("data-sla-icon", iconFile);
|
||||
}
|
||||
|
||||
function injectSlaIcons() {
|
||||
let found = 0;
|
||||
|
||||
// ── Sidebar tab icons ─────────────────────────────────────────────────
|
||||
// Foundry v13 confirmed structure:
|
||||
// <button class="ui-control plain icon fa-solid fa-comments" data-tab="chat" ...>
|
||||
// The BUTTON itself is the icon — no child <i> element.
|
||||
document.querySelectorAll(
|
||||
"#sidebar-tabs button[data-tab], #sidebar-tabs [data-tab].icon"
|
||||
).forEach(btn => {
|
||||
const name = btn.dataset.tab;
|
||||
const file = SLA_SIDEBAR_ICONS[name];
|
||||
if (!file || btn.hasAttribute("data-sla-icon")) return;
|
||||
_slaApplyIconMask(btn, file);
|
||||
found++;
|
||||
});
|
||||
|
||||
// ── Scene / layer control icons ───────────────────────────────────────
|
||||
// Foundry v13 scene controls are also buttons — search the whole doc
|
||||
// since we don't yet know the container ID.
|
||||
document.querySelectorAll(
|
||||
"button[data-control], [data-control].icon, [data-control].ui-control"
|
||||
).forEach(btn => {
|
||||
const name = btn.dataset.control;
|
||||
const file = SLA_CONTROL_ICONS[name];
|
||||
if (!file || btn.hasAttribute("data-sla-icon")) return;
|
||||
_slaApplyIconMask(btn, file);
|
||||
found++;
|
||||
});
|
||||
|
||||
if (found > 0) {
|
||||
console.log(`SLA Industries | Applied ${found} custom icons.`);
|
||||
} else {
|
||||
console.warn("SLA Industries | injectSlaIcons: no icons matched — dumping HTML:");
|
||||
console.warn("sidebar:", document.querySelector("#sidebar-tabs")?.outerHTML?.slice(0, 1200));
|
||||
const ctrlDump = document.querySelector("#ui-left, #scene-controls, #controls");
|
||||
console.warn("controls:", ctrlDump?.outerHTML?.slice(0, 1200) ?? "(not found — try: " + [...document.querySelectorAll("[data-control]")].map(e=>e.tagName+'.'+e.className).join(', ') + ")");
|
||||
}
|
||||
}
|
||||
|
||||
// Run once on ready, then re-run whenever Foundry re-renders these components
|
||||
Hooks.once("ready", () => {
|
||||
requestAnimationFrame(() => requestAnimationFrame(() => injectSlaIcons()));
|
||||
});
|
||||
Hooks.on("renderSidebar", () => requestAnimationFrame(() => injectSlaIcons()));
|
||||
Hooks.on("renderSidebarTab", () => requestAnimationFrame(() => injectSlaIcons()));
|
||||
Hooks.on("changeSidebarTab", () => requestAnimationFrame(() => injectSlaIcons()));
|
||||
Hooks.on("renderSceneControls", () => requestAnimationFrame(() => injectSlaIcons()));
|
||||
|
||||
@@ -487,6 +487,23 @@ export class SLADrugSystem {
|
||||
|
||||
await this.resolveExpiredEffects(actor);
|
||||
|
||||
// Drug stacking warning — check if any OTHER drug is already active
|
||||
const allActiveDrugEffects = this.getActorDrugEffects(actor);
|
||||
const otherActiveDrugs = allActiveDrugEffects.filter((effect) => {
|
||||
const flag = this.getDrugEffectFlag(effect);
|
||||
return flag?.stage === "active" && flag?.drugId && flag.drugId !== def.id;
|
||||
});
|
||||
if (otherActiveDrugs.length > 0) {
|
||||
const activeNames = [...new Set(otherActiveDrugs.map((e) => this.getDrugEffectFlag(e)?.drugName ?? e.name))].join(", ");
|
||||
const proceed = await Dialog.confirm({
|
||||
title: "Drug Stacking Warning",
|
||||
content: `<p><strong>${actor.name}</strong> already has active drug effects from: <strong>${activeNames}</strong>.</p>
|
||||
<p>Combining drugs can cause unpredictable or lethal interactions. Do you want to proceed?</p>`,
|
||||
defaultYes: false
|
||||
});
|
||||
if (!proceed) return { ok: false, reason: "stacking-cancelled" };
|
||||
}
|
||||
|
||||
const quantity = Math.max(0, Number(item.system?.quantity ?? 0));
|
||||
if (consume && quantity < 1) {
|
||||
ui.notifications.warn(`${actor.name} has no ${def.name} doses remaining.`);
|
||||
|
||||
@@ -1 +1 @@
|
||||
MANIFEST-000039
|
||||
MANIFEST-000061
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
2026/03/31-15:50:48.583476 17054f000 Recovering log #38
|
||||
2026/03/31-15:50:48.583855 17054f000 Delete type=0 #38
|
||||
2026/03/31-15:50:48.583882 17054f000 Delete type=3 #37
|
||||
2026/04/10-15:21:30.814878 16f8db000 Recovering log #60
|
||||
2026/04/10-15:21:30.815292 16f8db000 Delete type=0 #60
|
||||
2026/04/10-15:21:30.815311 16f8db000 Delete type=3 #59
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
2026/03/29-21:14:27.556257 16ffc3000 Recovering log #34
|
||||
2026/03/29-21:14:27.556633 16ffc3000 Delete type=3 #32
|
||||
2026/03/29-21:14:27.556668 16ffc3000 Delete type=0 #34
|
||||
2026/04/10-15:15:40.939578 17164b000 Recovering log #58
|
||||
2026/04/10-15:15:40.939865 17164b000 Delete type=0 #58
|
||||
2026/04/10-15:15:40.939883 17164b000 Delete type=3 #57
|
||||
|
||||
@@ -1 +1 @@
|
||||
MANIFEST-000039
|
||||
MANIFEST-000061
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
2026/03/31-15:50:48.585617 170d5b000 Recovering log #38
|
||||
2026/03/31-15:50:48.585981 170d5b000 Delete type=0 #38
|
||||
2026/03/31-15:50:48.586009 170d5b000 Delete type=3 #37
|
||||
2026/04/10-15:21:30.816908 16e0b7000 Recovering log #60
|
||||
2026/04/10-15:21:30.817298 16e0b7000 Delete type=0 #60
|
||||
2026/04/10-15:21:30.817326 16e0b7000 Delete type=3 #59
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
2026/03/29-21:14:27.559077 1717e7000 Recovering log #34
|
||||
2026/03/29-21:14:27.559760 1717e7000 Delete type=3 #32
|
||||
2026/03/29-21:14:27.559790 1717e7000 Delete type=0 #34
|
||||
2026/04/10-15:15:40.941390 170e3f000 Recovering log #58
|
||||
2026/04/10-15:15:40.941631 170e3f000 Delete type=0 #58
|
||||
2026/04/10-15:15:40.941649 170e3f000 Delete type=3 #57
|
||||
|
||||
@@ -1 +1 @@
|
||||
MANIFEST-000039
|
||||
MANIFEST-000061
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
2026/03/31-15:50:48.587337 171d73000 Recovering log #38
|
||||
2026/03/31-15:50:48.587684 171d73000 Delete type=0 #38
|
||||
2026/03/31-15:50:48.587707 171d73000 Delete type=3 #37
|
||||
2026/04/10-15:21:30.818908 16f0cf000 Recovering log #60
|
||||
2026/04/10-15:21:30.819298 16f0cf000 Delete type=0 #60
|
||||
2026/04/10-15:21:30.819316 16f0cf000 Delete type=3 #59
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
2026/03/29-21:14:27.561319 170fdb000 Recovering log #34
|
||||
2026/03/29-21:14:27.561677 170fdb000 Delete type=3 #32
|
||||
2026/03/29-21:14:27.561715 170fdb000 Delete type=0 #34
|
||||
2026/04/10-15:15:40.942933 17164b000 Recovering log #58
|
||||
2026/04/10-15:15:40.943347 17164b000 Delete type=0 #58
|
||||
2026/04/10-15:15:40.943366 17164b000 Delete type=3 #57
|
||||
|
||||
@@ -1 +1 @@
|
||||
MANIFEST-000039
|
||||
MANIFEST-000061
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
2026/03/31-15:50:48.589215 17054f000 Recovering log #38
|
||||
2026/03/31-15:50:48.589634 17054f000 Delete type=0 #38
|
||||
2026/03/31-15:50:48.589656 17054f000 Delete type=3 #37
|
||||
2026/04/10-15:21:30.820489 16f0cf000 Recovering log #60
|
||||
2026/04/10-15:21:30.820764 16f0cf000 Delete type=0 #60
|
||||
2026/04/10-15:21:30.820786 16f0cf000 Delete type=3 #59
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
2026/03/29-21:14:27.563010 1707cf000 Recovering log #34
|
||||
2026/03/29-21:14:27.563276 1707cf000 Delete type=3 #32
|
||||
2026/03/29-21:14:27.563303 1707cf000 Delete type=0 #34
|
||||
2026/04/10-15:15:40.944425 171e57000 Recovering log #58
|
||||
2026/04/10-15:15:40.944787 171e57000 Delete type=0 #58
|
||||
2026/04/10-15:15:40.944804 171e57000 Delete type=3 #57
|
||||
|
||||
@@ -1 +1 @@
|
||||
MANIFEST-000039
|
||||
MANIFEST-000061
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
2026/03/31-15:50:48.590832 171567000 Recovering log #38
|
||||
2026/03/31-15:50:48.591262 171567000 Delete type=0 #38
|
||||
2026/03/31-15:50:48.591291 171567000 Delete type=3 #37
|
||||
2026/04/10-15:21:30.821825 16e0b7000 Recovering log #60
|
||||
2026/04/10-15:21:30.822206 16e0b7000 Delete type=0 #60
|
||||
2026/04/10-15:21:30.822238 16e0b7000 Delete type=3 #59
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
2026/03/29-21:14:27.564411 1717e7000 Recovering log #34
|
||||
2026/03/29-21:14:27.564754 1717e7000 Delete type=3 #32
|
||||
2026/03/29-21:14:27.564784 1717e7000 Delete type=0 #34
|
||||
2026/04/10-15:15:40.946179 170e3f000 Recovering log #58
|
||||
2026/04/10-15:15:40.946914 170e3f000 Delete type=0 #58
|
||||
2026/04/10-15:15:40.946937 170e3f000 Delete type=3 #57
|
||||
|
||||
@@ -1 +1 @@
|
||||
MANIFEST-000039
|
||||
MANIFEST-000061
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
2026/03/31-15:50:48.592976 170d5b000 Recovering log #38
|
||||
2026/03/31-15:50:48.593456 170d5b000 Delete type=0 #38
|
||||
2026/03/31-15:50:48.593476 170d5b000 Delete type=3 #37
|
||||
2026/04/10-15:21:30.988603 16f8db000 Recovering log #60
|
||||
2026/04/10-15:21:30.989459 16f8db000 Delete type=0 #60
|
||||
2026/04/10-15:21:30.989517 16f8db000 Delete type=3 #59
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
2026/03/29-21:14:27.565839 1707cf000 Recovering log #34
|
||||
2026/03/29-21:14:27.566214 1707cf000 Delete type=3 #32
|
||||
2026/03/29-21:14:27.566242 1707cf000 Delete type=0 #34
|
||||
2026/04/10-15:15:40.964061 17164b000 Recovering log #58
|
||||
2026/04/10-15:15:40.964631 17164b000 Delete type=0 #58
|
||||
2026/04/10-15:15:40.964657 17164b000 Delete type=3 #57
|
||||
|
||||
@@ -1 +1 @@
|
||||
MANIFEST-000039
|
||||
MANIFEST-000063
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
2026/03/31-15:50:48.594786 171567000 Recovering log #38
|
||||
2026/03/31-15:50:48.595201 171567000 Delete type=0 #38
|
||||
2026/03/31-15:50:48.595227 171567000 Delete type=3 #37
|
||||
2026/04/10-15:21:30.992926 16f8db000 Recovering log #62
|
||||
2026/04/10-15:21:30.993656 16f8db000 Delete type=0 #62
|
||||
2026/04/10-15:21:30.993730 16f8db000 Delete type=3 #61
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
2026/03/29-21:14:27.567335 170fdb000 Recovering log #34
|
||||
2026/03/29-21:14:27.567720 170fdb000 Delete type=3 #32
|
||||
2026/03/29-21:14:27.567753 170fdb000 Delete type=0 #34
|
||||
2026/04/10-15:15:40.966053 17164b000 Recovering log #60
|
||||
2026/04/10-15:15:40.967356 17164b000 Delete type=0 #60
|
||||
2026/04/10-15:15:40.967388 17164b000 Delete type=3 #59
|
||||
|
||||
@@ -1 +1 @@
|
||||
MANIFEST-000039
|
||||
MANIFEST-000061
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
2026/03/31-15:50:48.597410 170d5b000 Recovering log #38
|
||||
2026/03/31-15:50:48.598033 170d5b000 Delete type=0 #38
|
||||
2026/03/31-15:50:48.598068 170d5b000 Delete type=3 #37
|
||||
2026/04/10-15:21:30.995778 16e8c3000 Recovering log #60
|
||||
2026/04/10-15:21:30.996525 16e8c3000 Delete type=0 #60
|
||||
2026/04/10-15:21:30.996566 16e8c3000 Delete type=3 #59
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
2026/03/29-21:14:27.568770 1707cf000 Recovering log #34
|
||||
2026/03/29-21:14:27.569097 1707cf000 Delete type=3 #32
|
||||
2026/03/29-21:14:27.569138 1707cf000 Delete type=0 #34
|
||||
2026/04/10-15:15:40.968762 17164b000 Recovering log #58
|
||||
2026/04/10-15:15:40.968983 17164b000 Delete type=0 #58
|
||||
2026/04/10-15:15:40.969099 17164b000 Delete type=3 #57
|
||||
|
||||
@@ -1 +1 @@
|
||||
MANIFEST-000039
|
||||
MANIFEST-000061
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
2026/03/31-15:50:48.600045 17054f000 Recovering log #38
|
||||
2026/03/31-15:50:48.600385 17054f000 Delete type=0 #38
|
||||
2026/03/31-15:50:48.600414 17054f000 Delete type=3 #37
|
||||
2026/04/10-15:21:30.998700 16e8c3000 Recovering log #60
|
||||
2026/04/10-15:21:30.999246 16e8c3000 Delete type=0 #60
|
||||
2026/04/10-15:21:30.999287 16e8c3000 Delete type=3 #59
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
2026/03/29-21:14:27.570654 170fdb000 Recovering log #34
|
||||
2026/03/29-21:14:27.571032 170fdb000 Delete type=3 #32
|
||||
2026/03/29-21:14:27.571059 170fdb000 Delete type=0 #34
|
||||
2026/04/10-15:15:40.970322 172663000 Recovering log #58
|
||||
2026/04/10-15:15:40.970657 172663000 Delete type=0 #58
|
||||
2026/04/10-15:15:40.970680 172663000 Delete type=3 #57
|
||||
|
||||
@@ -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.0",
|
||||
"version": "0.6.1",
|
||||
"esmodules": [
|
||||
"module/mosh.js"
|
||||
],
|
||||
|
||||
@@ -227,6 +227,11 @@
|
||||
},
|
||||
"morphNotes": {
|
||||
"value": ""
|
||||
},
|
||||
"sessionAbilityUsed": false,
|
||||
"contacts": [],
|
||||
"activityLog": {
|
||||
"value": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
from 1 to 12 and will create that number of columns. --}}
|
||||
|
||||
<div class="header">
|
||||
<img class="profile" src="{{img}}" data-edit="img" title="{{name}}" height="150"
|
||||
<img class="profile sla-portrait-static" src="{{img}}" data-edit="img" title="{{name}}" height="150"
|
||||
width="150" />
|
||||
|
||||
<div class="headergrid">
|
||||
@@ -29,7 +29,7 @@
|
||||
<div class="headerinputtext">L.A.D.</div>
|
||||
<label class="sla-header-checkbox" title="Life After Death">
|
||||
<input type="checkbox" name="system.sla.lad" data-dtype="Boolean" {{checked system.sla.lad}} />
|
||||
<span>Life After Death</span>
|
||||
<span>L.A.D.</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-field header-field-credits">
|
||||
@@ -52,22 +52,26 @@
|
||||
value="{{system.rank.value}}" placeholder="" /></div>
|
||||
</div>
|
||||
|
||||
<div class="header-field header-field-sla-rank header-field-compact">
|
||||
<div class="headerinputtext">SLA Rank</div>
|
||||
<div class="header-field header-field-sla-rank">
|
||||
<div class="headerinputtext">S.C.L</div>
|
||||
<div class="headerinputfield sla-header-input charname"><input name="system.attributes.level.value" class="noborder"
|
||||
type="text" value="{{system.attributes.level.value}}" placeholder="" /></div>
|
||||
</div>
|
||||
|
||||
<div class="header-field header-field-height header-field-compact">
|
||||
<div class="header-field header-field-height">
|
||||
<div class="headerinputtext">Height</div>
|
||||
<div class="headerinputfield sla-header-input charname"><input name="system.sla.height.value" class="noborder" type="text"
|
||||
value="{{system.sla.height.value}}" placeholder="" /></div>
|
||||
</div>
|
||||
<div class="header-field header-field-weight header-field-compact">
|
||||
<div class="header-field header-field-weight">
|
||||
<div class="headerinputtext">Weight</div>
|
||||
<div class="headerinputfield sla-header-input charname"><input name="system.sla.weightText.value" class="noborder" type="text"
|
||||
value="{{system.sla.weightText.value}}" placeholder="" /></div>
|
||||
</div>
|
||||
<div class="header-field header-field-rest">
|
||||
<div class="headerinputtext"> </div>
|
||||
<button type="button" class="sla-sheet-action sla-rest-button sla-header-rest-pill" title="Take a short or long rest">Rest</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -203,7 +207,16 @@
|
||||
{{/if}}
|
||||
<!-- Trauma Response -->
|
||||
<div class="" style="margin-left: 6px; margin-right: 0px; flex: 0; grid-column-start: 1; grid-column-end: 3;">
|
||||
<div class="resource-label sla-stat-heading sla-trauma-heading">{{ localize 'Mosh.TraumaResponse' }}</div>
|
||||
<div class="sla-trauma-header-row">
|
||||
<div class="resource-label sla-stat-heading sla-trauma-heading">{{ localize 'Mosh.TraumaResponse' }}</div>
|
||||
<div class="sla-session-ability-row">
|
||||
<label class="sla-session-ability-label" title="Check when the session trauma ability has been used">
|
||||
<input type="checkbox" class="sla-session-ability-used" {{#if system.sla.sessionAbilityUsed}}checked{{/if}} />
|
||||
<span>Session ability used</span>
|
||||
</label>
|
||||
<button type="button" class="sla-new-session" title="Start a new session — resets session ability">New Session</button>
|
||||
</div>
|
||||
</div>
|
||||
<textarea name="system.other.stressdesc.value" rows="4" class="textarea-input trauma-response-box" type="text"
|
||||
data-target="system.other.stressdesc.value" placeholder="Trauma response">{{system.other.stressdesc.value}}</textarea>
|
||||
</div>
|
||||
@@ -382,6 +395,7 @@
|
||||
<a class="tab-select" data-tab="special-rules">Special Rules</a>
|
||||
{{#if isEbbUser}}<a class="tab-select" data-tab="ebb">Ebb</a>{{/if}}
|
||||
{{#if isVevaphon}}<a class="tab-select" data-tab="morph">Morph</a>{{/if}}
|
||||
<a class="tab-select" data-tab="contacts">Contacts</a>
|
||||
<a class="tab-select" data-tab="description">{{ localize 'Mosh.Bio' }}</a>
|
||||
<a class="tab-select" data-tab="notes">{{ localize 'Mosh.Notes' }}</a>
|
||||
</nav>
|
||||
@@ -389,6 +403,48 @@
|
||||
{{!-- Sheet Body --}}
|
||||
<section class="sheet-body">
|
||||
|
||||
{{!-- Contacts Tab --}}
|
||||
<div class="tab items" data-group="primary" data-tab="contacts">
|
||||
<div class="sla-panel">
|
||||
<div class="sla-banner">
|
||||
<div>
|
||||
<div class="sla-kicker">Operative Network</div>
|
||||
<div class="sla-title">Contacts & Associates</div>
|
||||
</div>
|
||||
<div class="sla-tags">
|
||||
<span class="sla-tag">{{slaContactCount}} contact{{#unless (compare 'int' slaContactCount '===' 1)}}s{{/unless}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sla-contacts-toolbar">
|
||||
<button type="button" class="sla-sheet-action sla-contact-add"><i class="fas fa-plus"></i> Add Contact</button>
|
||||
</div>
|
||||
|
||||
{{#if slaContacts.length}}
|
||||
<div class="sla-contacts-list">
|
||||
{{#each slaContacts as |contact|}}
|
||||
<div class="sla-contact-card" data-contact-id="{{contact.id}}">
|
||||
<div class="sla-contact-header">
|
||||
<div class="sla-contact-disposition sla-contact-disposition-{{contact.disposition}}"></div>
|
||||
<div class="sla-contact-name">{{contact.name}}</div>
|
||||
<div class="sla-contact-role">{{contact.role}}</div>
|
||||
<div class="sla-contact-controls">
|
||||
<button type="button" class="sla-contact-edit" data-contact-id="{{contact.id}}" title="Edit contact"><i class="fas fa-edit"></i></button>
|
||||
<button type="button" class="sla-contact-delete" data-contact-id="{{contact.id}}" title="Delete contact"><i class="fas fa-trash"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
{{#if contact.notes}}
|
||||
<div class="sla-contact-notes">{{contact.notes}}</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="sla-note-pill sla-note-pill-wide">No contacts yet. Add allies, fixers, squad members, and other NPCs the operative knows.</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{!-- Biography Tab --}}
|
||||
<div class="tab biography" data-group="primary" data-tab="description">
|
||||
{{editor enriched.biography target="system.biography" button=true editable=true}}
|
||||
@@ -400,6 +456,11 @@
|
||||
<div class="sla-card-copy">Total spent: {{system.sla.ammoSpendTotal.value}} cR</div>
|
||||
<textarea readonly rows="6" class="textarea-input">{{system.sla.ammoLedger.value}}</textarea>
|
||||
</div>
|
||||
<div class="sla-card sla-activity-log-card" style="margin-bottom: 12px;">
|
||||
<div class="sla-card-label">Operative Activity Log</div>
|
||||
<div class="sla-card-copy">Rolls, rests, drug use, panic — automatically recorded. Newest first.</div>
|
||||
<textarea readonly rows="8" class="textarea-input sla-activity-log-textarea">{{system.sla.activityLog.value}}</textarea>
|
||||
</div>
|
||||
{{editor enriched.notes target="system.notes" button=true editable=true}}
|
||||
</div>
|
||||
<div class="tab items" data-group="primary" data-tab="sla">
|
||||
@@ -478,7 +539,15 @@
|
||||
</div>
|
||||
<div class="resource">
|
||||
<label class="resource-label">SCL</label>
|
||||
<input type="text" name="system.sla.scl.value" value="{{system.sla.scl.value}}" data-dtype="String" />
|
||||
<div class="sla-scl-control">
|
||||
<input type="text" name="system.sla.scl.value" value="{{system.sla.scl.value}}" data-dtype="String" class="sla-scl-input" />
|
||||
<div class="sla-scl-buttons">
|
||||
<button type="button" class="sla-scl-adjust" data-delta="1" title="+1 SCL">+1</button>
|
||||
<button type="button" class="sla-scl-adjust" data-delta="-1" title="-1 SCL">-1</button>
|
||||
<button type="button" class="sla-scl-adjust" data-delta="0.5" title="+0.5 SCL">+½</button>
|
||||
<button type="button" class="sla-scl-adjust" data-delta="-0.5" title="-0.5 SCL">-½</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource">
|
||||
<label class="resource-label">Employer / Squad</label>
|
||||
|
||||