Compare commits
3 Commits
1b5da3e144
...
cab77645b7
| Author | SHA1 | Date | |
|---|---|---|---|
| cab77645b7 | |||
| 0689fae792 | |||
| 6fda4b9246 |
@@ -860,6 +860,72 @@ section.npc .cde-neon-tabs .item.active {
|
|||||||
.cde-aptitudes-table .cde-spec-cell {
|
.cde-aptitudes-table .cde-spec-cell {
|
||||||
flex: 1 1 0;
|
flex: 1 1 0;
|
||||||
}
|
}
|
||||||
|
.cde-aptitudes-table .cde-roll-cell {
|
||||||
|
width: 28px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.cde-aptitudes-table .cde-roll-cell .cde-roll-trigger {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
color: #7d94b8;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: color 0.15s, background 0.15s;
|
||||||
|
}
|
||||||
|
.cde-aptitudes-table .cde-roll-cell .cde-roll-trigger:hover {
|
||||||
|
color: #cc44ff;
|
||||||
|
background: rgba(204, 68, 255, 0.12);
|
||||||
|
}
|
||||||
|
.cde-empty-list {
|
||||||
|
color: #7d94b8;
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 11px;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
.cde-supernatural-list .cde-supernatural-item {
|
||||||
|
background: rgba(16, 22, 34, 0.6);
|
||||||
|
border: 1px solid #1a2436;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
padding: 6px;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
.cde-supernatural-list .cde-supernatural-header {
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.cde-supernatural-list .cde-supernatural-header img {
|
||||||
|
border-radius: 4px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.cde-supernatural-list .cde-supernatural-info {
|
||||||
|
flex: 1 1 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.cde-supernatural-list .cde-supernatural-info .cde-supernatural-name {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.cde-supernatural-list .cde-supernatural-desc {
|
||||||
|
font-size: 10px;
|
||||||
|
color: #7d94b8;
|
||||||
|
margin-top: 4px;
|
||||||
|
padding-left: 36px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
.cde-supernatural-list .cde-supernatural-desc p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
.cde-npc-tracks {
|
.cde-npc-tracks {
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
}
|
}
|
||||||
@@ -915,6 +981,546 @@ section.npc .cde-neon-tabs .item.active {
|
|||||||
.cde-npc-tracks .cde-track-note input {
|
.cde-npc-tracks .cde-track-note input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
.cde-chat-app-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 6px 8px 4px;
|
||||||
|
border-top: 1px solid #1a2436;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
.cde-chat-app-buttons .cde-chat-btn {
|
||||||
|
flex: 1 1 0;
|
||||||
|
pointer-events: auto;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 5px 8px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-family: "Orbitron", "Averia", sans-serif;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.06em;
|
||||||
|
background: #101622;
|
||||||
|
border: 1px solid #1a2436;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: #7d94b8;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
.cde-chat-app-buttons .cde-chat-btn i {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.cde-chat-app-buttons .cde-chat-btn:hover {
|
||||||
|
background: rgba(74, 158, 255, 0.1);
|
||||||
|
border-color: #4a9eff;
|
||||||
|
color: #4a9eff;
|
||||||
|
box-shadow: 0 0 8px rgba(74, 158, 255, 0.3);
|
||||||
|
}
|
||||||
|
.cde-chat-app-buttons .cde-chat-btn--tinji:hover {
|
||||||
|
background: rgba(255, 61, 90, 0.1);
|
||||||
|
border-color: #ff3d5a;
|
||||||
|
color: #ff3d5a;
|
||||||
|
box-shadow: 0 0 8px rgba(255, 61, 90, 0.3);
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-loksyu-app-body {
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-loksyu-elements {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-card {
|
||||||
|
flex: 0 0 calc(33.333% - 6px);
|
||||||
|
min-width: 140px;
|
||||||
|
max-width: 160px;
|
||||||
|
background: rgba(16, 22, 34, 0.8);
|
||||||
|
border: 1px solid #1a2436;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 10px 8px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-card--wood:hover {
|
||||||
|
border-color: #4a9e3f;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-card--wood .cde-lok-input:focus {
|
||||||
|
border-bottom-color: #4a9e3f;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-card--fire:hover {
|
||||||
|
border-color: #ff3d5a;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-card--fire .cde-lok-input:focus {
|
||||||
|
border-bottom-color: #ff3d5a;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-card--earth:hover {
|
||||||
|
border-color: #c88a3a;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-card--earth .cde-lok-input:focus {
|
||||||
|
border-bottom-color: #c88a3a;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-card--metal:hover {
|
||||||
|
border-color: #7d94b8;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-card--metal .cde-lok-input:focus {
|
||||||
|
border-bottom-color: #7d94b8;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-card--water:hover {
|
||||||
|
border-color: #4a9eff;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-card--water .cde-lok-input:focus {
|
||||||
|
border-bottom-color: #4a9eff;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-header img.cde-lok-icon {
|
||||||
|
border-radius: 4px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-titles {
|
||||||
|
flex: 1 1 0;
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-titles .cde-lok-name {
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
color: #e2e8f4;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-titles .cde-lok-qual {
|
||||||
|
font-size: 9px;
|
||||||
|
color: #7d94b8;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-reset {
|
||||||
|
color: #7d94b8;
|
||||||
|
font-size: 11px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-reset:hover {
|
||||||
|
color: #e2e8f4;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-values {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-polarity {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-polarity .cde-lok-pol-label {
|
||||||
|
font-size: 9px;
|
||||||
|
color: #7d94b8;
|
||||||
|
width: 30px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-polarity--yang .cde-lok-pol-label {
|
||||||
|
color: #e2e8f4;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-input {
|
||||||
|
flex: 1 1 0;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
border-bottom: 1px solid #1a2436;
|
||||||
|
color: #e2e8f4;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 700;
|
||||||
|
text-align: center;
|
||||||
|
padding: 2px 0;
|
||||||
|
transition: border-bottom-color 0.2s;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-input:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-input[disabled] {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-loksyu-visual-row {
|
||||||
|
text-align: center;
|
||||||
|
margin: 6px 0;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-loksyu-visual-row .cde-lok-visual {
|
||||||
|
max-width: 120px;
|
||||||
|
max-height: 160px;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding-top: 6px;
|
||||||
|
border-top: 1px solid #1a2436;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-reset-all {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 5px 14px;
|
||||||
|
font-size: 11px;
|
||||||
|
background: rgba(255, 61, 90, 0.12);
|
||||||
|
border: 1px solid rgba(255, 61, 90, 0.3);
|
||||||
|
border-radius: 4px;
|
||||||
|
color: #7d94b8;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
.cde-loksyu-standalone .cde-lok-reset-all:hover {
|
||||||
|
background: rgba(255, 61, 90, 0.2);
|
||||||
|
border-color: #ff3d5a;
|
||||||
|
color: #e2e8f4;
|
||||||
|
}
|
||||||
|
.cde-tinji-standalone .cde-tinji-app-body {
|
||||||
|
padding: 16px 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
.cde-tinji-standalone .cde-tinji-display {
|
||||||
|
flex: 1 1 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.cde-tinji-standalone .cde-tinji-chinese-large {
|
||||||
|
font-size: 40px;
|
||||||
|
color: #ff3d5a;
|
||||||
|
text-shadow: 0 0 20px rgba(255, 61, 90, 0.6);
|
||||||
|
line-height: 1;
|
||||||
|
font-family: serif;
|
||||||
|
}
|
||||||
|
.cde-tinji-standalone .cde-tinji-label {
|
||||||
|
font-size: 11px;
|
||||||
|
font-family: "Orbitron", sans-serif;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.12em;
|
||||||
|
color: #e2e8f4;
|
||||||
|
opacity: 0.75;
|
||||||
|
}
|
||||||
|
.cde-tinji-standalone .cde-tinji-counter {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin: 4px 0;
|
||||||
|
}
|
||||||
|
.cde-tinji-standalone .cde-tinji-step {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
background: #0d1520;
|
||||||
|
border: 1px solid #263853;
|
||||||
|
border-radius: 50%;
|
||||||
|
color: #e2e8f4;
|
||||||
|
font-size: 18px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: all 0.2s;
|
||||||
|
line-height: 1;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.cde-tinji-standalone .cde-tinji-step:hover {
|
||||||
|
background: rgba(255, 61, 90, 0.25);
|
||||||
|
border-color: #ff3d5a;
|
||||||
|
color: #e2e8f4;
|
||||||
|
}
|
||||||
|
.cde-tinji-standalone .cde-tinji-direct {
|
||||||
|
width: 72px;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
border-bottom: 2px solid #ff3d5a;
|
||||||
|
color: #ff3d5a;
|
||||||
|
font-size: 36px;
|
||||||
|
font-weight: 700;
|
||||||
|
text-align: center;
|
||||||
|
text-shadow: 0 0 12px rgba(255, 61, 90, 0.5);
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.cde-tinji-standalone .cde-tinji-direct:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
.cde-tinji-standalone .cde-tinji-direct[disabled] {
|
||||||
|
opacity: 0.7;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.cde-tinji-standalone .cde-tinji-hint {
|
||||||
|
font-size: 10px;
|
||||||
|
color: #7d94b8;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.cde-tinji-standalone .cde-tinji-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
.cde-tinji-standalone .cde-tinji-spend-btn,
|
||||||
|
.cde-tinji-standalone .cde-tinji-reset-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
}
|
||||||
|
.cde-tinji-standalone .cde-tinji-spend-btn {
|
||||||
|
background: rgba(255, 61, 90, 0.25);
|
||||||
|
border: 1px solid #ff3d5a;
|
||||||
|
color: #e2e8f4;
|
||||||
|
}
|
||||||
|
.cde-tinji-standalone .cde-tinji-spend-btn:hover {
|
||||||
|
background: rgba(255, 61, 90, 0.45);
|
||||||
|
border-color: #ff7085;
|
||||||
|
}
|
||||||
|
.cde-tinji-standalone .cde-tinji-spend-btn[disabled] {
|
||||||
|
opacity: 0.55;
|
||||||
|
cursor: not-allowed;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.cde-tinji-standalone .cde-tinji-reset-btn {
|
||||||
|
background: #0d1520;
|
||||||
|
border: 1px solid #263853;
|
||||||
|
color: #e2e8f4;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
.cde-tinji-standalone .cde-tinji-reset-btn:hover {
|
||||||
|
border-color: #e2e8f4;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.cde-tinji-standalone .cde-tinji-visual {
|
||||||
|
width: 90px;
|
||||||
|
height: auto;
|
||||||
|
opacity: 0.85;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.cde-tinji-spend-msg {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 8px 10px;
|
||||||
|
background: rgba(255, 61, 90, 0.18);
|
||||||
|
border: 1px solid rgba(255, 61, 90, 0.35);
|
||||||
|
border-left: 4px solid #ff3d5a;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: #e2e8f4;
|
||||||
|
}
|
||||||
|
.cde-tinji-spend-msg .cde-tinji-icon {
|
||||||
|
font-size: 18px;
|
||||||
|
color: #ff3d5a;
|
||||||
|
text-shadow: 0 0 6px rgba(255, 61, 90, 0.7);
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.cde-tinji-spend-msg i {
|
||||||
|
color: #ff3d5a;
|
||||||
|
font-size: 15px;
|
||||||
|
filter: drop-shadow(0 0 4px rgba(255, 61, 90, 0.6));
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.cde-tinji-spend-msg strong {
|
||||||
|
color: #ff3d5a;
|
||||||
|
font-size: 13px;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
}
|
||||||
|
.cde-tinji-spend-msg .cde-tinji-remain {
|
||||||
|
margin-left: auto;
|
||||||
|
font-size: 11px;
|
||||||
|
color: rgba(226, 232, 244, 0.65);
|
||||||
|
font-style: italic;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.cde-loksyu-draw-msg {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 5px;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 9px 11px;
|
||||||
|
background: linear-gradient(135deg, rgba(0, 212, 212, 0.1) 0%, rgba(16, 22, 34, 0.95) 100%);
|
||||||
|
border: 1px solid rgba(0, 212, 212, 0.4);
|
||||||
|
border-left: 4px solid #00d4d4;
|
||||||
|
border-radius: 5px;
|
||||||
|
color: #e2e8f4;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 212, 212, 0.12);
|
||||||
|
}
|
||||||
|
.cde-loksyu-draw-msg .cde-loksyu-draw-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 5px;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
.cde-loksyu-draw-msg .cde-loksyu-draw-aspect-icon {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
object-fit: contain;
|
||||||
|
filter: drop-shadow(0 0 4px rgba(0, 212, 212, 0.6));
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.cde-loksyu-draw-msg .cde-loksyu-draw-user {
|
||||||
|
font-weight: 700;
|
||||||
|
color: #00d4d4;
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
}
|
||||||
|
.cde-loksyu-draw-msg .cde-loksyu-draw-action {
|
||||||
|
color: rgba(226, 232, 244, 0.65);
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
.cde-loksyu-draw-msg .cde-loksyu-draw-type {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #c9a227;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
text-shadow: 0 0 6px rgba(201, 162, 39, 0.4);
|
||||||
|
}
|
||||||
|
.cde-loksyu-draw-msg .cde-loksyu-draw-from {
|
||||||
|
color: rgba(226, 232, 244, 0.6);
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
.cde-loksyu-draw-msg .cde-loksyu-draw-from em {
|
||||||
|
color: #00d4d4;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.cde-loksyu-draw-msg .cde-loksyu-draw-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: rgba(226, 232, 244, 0.55);
|
||||||
|
padding-top: 4px;
|
||||||
|
border-top: 1px solid rgba(0, 212, 212, 0.2);
|
||||||
|
}
|
||||||
|
.cde-loksyu-draw-msg .cde-loksyu-draw-footer i {
|
||||||
|
color: #00d4d4;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
.cde-loksyu-draw-msg .cde-loksyu-draw-footer .cde-loksyu-remain {
|
||||||
|
color: #00d4d4;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
.cde-roll-actions {
|
||||||
|
margin-top: 10px;
|
||||||
|
padding-top: 8px;
|
||||||
|
border-top: 1px solid rgba(26, 36, 54, 0.6);
|
||||||
|
}
|
||||||
|
.cde-roll-actions .cde-roll-actions-title {
|
||||||
|
font-size: 10px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
color: rgba(226, 232, 244, 0.5);
|
||||||
|
margin-bottom: 6px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
.cde-roll-actions .cde-roll-actions-title i {
|
||||||
|
font-size: 9px;
|
||||||
|
}
|
||||||
|
.cde-roll-actions .cde-roll-actions-btns {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
.cde-roll-actions .cde-roll-action-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-family: "Courier New", Courier, monospace;
|
||||||
|
border-radius: 3px;
|
||||||
|
border: 1px solid rgba(26, 36, 54, 0.8);
|
||||||
|
background: rgba(16, 22, 34, 0.9);
|
||||||
|
color: #e2e8f4;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.15s, border-color 0.15s, box-shadow 0.15s;
|
||||||
|
pointer-events: auto;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
.cde-roll-actions .cde-roll-action-btn:hover:not(:disabled) {
|
||||||
|
border-color: rgba(0, 212, 212, 0.7);
|
||||||
|
background: rgba(0, 212, 212, 0.12);
|
||||||
|
box-shadow: 0 0 6px rgba(0, 212, 212, 0.25);
|
||||||
|
color: #00d4d4;
|
||||||
|
}
|
||||||
|
.cde-roll-actions .cde-roll-action-btn:disabled {
|
||||||
|
opacity: 0.35;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
.cde-roll-actions .cde-roll-action-btn .cde-roll-action-icon {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
object-fit: contain;
|
||||||
|
filter: drop-shadow(0 0 2px rgba(0, 212, 212, 0.4));
|
||||||
|
}
|
||||||
|
.cde-roll-actions .cde-roll-action-btn .cde-roll-action-label {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.cde-roll-actions .cde-roll-action-btn .cde-roll-action-count {
|
||||||
|
background: rgba(26, 36, 54, 0.6);
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: 1px 4px;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 700;
|
||||||
|
min-width: 18px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.cde-roll-actions .cde-roll-action-btn .cde-roll-action-tinji-char {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1;
|
||||||
|
color: #ff3d5a;
|
||||||
|
text-shadow: 0 0 4px rgba(255, 61, 90, 0.6);
|
||||||
|
}
|
||||||
|
.cde-roll-actions .cde-roll-action-btn.cde-roll-action--success:hover:not(:disabled) {
|
||||||
|
border-color: rgba(201, 162, 39, 0.7);
|
||||||
|
background: rgba(201, 162, 39, 0.1);
|
||||||
|
box-shadow: 0 0 6px rgba(201, 162, 39, 0.25);
|
||||||
|
color: #c9a227;
|
||||||
|
}
|
||||||
|
.cde-roll-actions .cde-roll-action-btn.cde-roll-action--faste:hover:not(:disabled) {
|
||||||
|
border-color: rgba(0, 212, 212, 0.7);
|
||||||
|
background: rgba(0, 212, 212, 0.1);
|
||||||
|
box-shadow: 0 0 6px rgba(0, 212, 212, 0.25);
|
||||||
|
color: #00d4d4;
|
||||||
|
}
|
||||||
|
.cde-roll-actions .cde-roll-action-btn.cde-roll-action--tinji:hover:not(:disabled) {
|
||||||
|
border-color: rgba(255, 61, 90, 0.7);
|
||||||
|
background: rgba(255, 61, 90, 0.12);
|
||||||
|
box-shadow: 0 0 6px rgba(255, 61, 90, 0.3);
|
||||||
|
color: #ff3d5a;
|
||||||
|
}
|
||||||
|
.cde-roll-actions .cde-roll-action-btn.cde-roll-action--tinji:hover:not(:disabled) .cde-roll-action-count {
|
||||||
|
background: rgba(255, 61, 90, 0.25);
|
||||||
|
}
|
||||||
.cde-loksyu-grid {
|
.cde-loksyu-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||||
@@ -2783,6 +3389,38 @@ ol.item-list li.item .item-controls a.item-control:hover {
|
|||||||
letter-spacing: 0.1em;
|
letter-spacing: 0.1em;
|
||||||
color: #7d94b8;
|
color: #7d94b8;
|
||||||
}
|
}
|
||||||
|
.cde-roll-result .cde-rr-hero .cde-rr-loksyu-bonus {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 3px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 3px;
|
||||||
|
animation: cde-pulse-in 0.3s ease;
|
||||||
|
}
|
||||||
|
.cde-roll-result .cde-rr-hero .cde-rr-loksyu-bonus.cde-rr-loksyu-bonus--success {
|
||||||
|
background: rgba(201, 162, 39, 0.2);
|
||||||
|
border: 1px solid rgba(201, 162, 39, 0.5);
|
||||||
|
color: #c9a227;
|
||||||
|
text-shadow: 0 0 6px rgba(201, 162, 39, 0.6);
|
||||||
|
}
|
||||||
|
.cde-roll-result .cde-rr-hero .cde-rr-loksyu-bonus.cde-rr-loksyu-bonus--faste {
|
||||||
|
background: rgba(0, 212, 212, 0.15);
|
||||||
|
border: 1px solid rgba(0, 212, 212, 0.4);
|
||||||
|
color: #00d4d4;
|
||||||
|
text-shadow: 0 0 6px rgba(0, 212, 212, 0.5);
|
||||||
|
}
|
||||||
|
@keyframes cde-pulse-in {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.7);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
.cde-roll-result .cde-rr-details {
|
.cde-roll-result .cde-rr-details {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -2806,6 +3444,17 @@ ol.item-list li.item .item-controls a.item-control:hover {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
text-shadow: 0 0 6px currentColor;
|
text-shadow: 0 0 6px currentColor;
|
||||||
}
|
}
|
||||||
|
.cde-roll-result .cde-rr-row .cde-rr-loksyu-bonus {
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 1px 4px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: rgba(0, 212, 212, 0.15);
|
||||||
|
border: 1px solid rgba(0, 212, 212, 0.4);
|
||||||
|
color: #00d4d4;
|
||||||
|
text-shadow: 0 0 4px rgba(0, 212, 212, 0.5);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
.cde-roll-result .cde-rr-row .cde-rr-icon {
|
.cde-roll-result .cde-rr-row .cde-rr-icon {
|
||||||
width: 22px;
|
width: 22px;
|
||||||
height: 22px;
|
height: 22px;
|
||||||
|
|||||||
@@ -891,6 +891,167 @@ section.npc .cde-neon-tabs .item.active { color: @cde-supernatural; borde
|
|||||||
.cde-aptitudes-table {
|
.cde-aptitudes-table {
|
||||||
// Inherits .cde-skills-table styles; just ensure consistent width
|
// Inherits .cde-skills-table styles; just ensure consistent width
|
||||||
.cde-spec-cell { flex: 1 1 0; }
|
.cde-spec-cell { flex: 1 1 0; }
|
||||||
|
|
||||||
|
.cde-roll-cell {
|
||||||
|
width: 28px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.cde-roll-trigger {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
color: @cde-muted;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: color 0.15s, background 0.15s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: @cde-supernatural;
|
||||||
|
background: fade(@cde-supernatural, 12%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty list placeholder
|
||||||
|
.cde-empty-list {
|
||||||
|
color: @cde-muted;
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 11px;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NPC supernatural item cards
|
||||||
|
// ── Supernatural abilities card (NPC) ───────────────────────────────────────
|
||||||
|
|
||||||
|
.cde-super-add-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding: 4px 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-super-add-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-family: "Averia", sans-serif;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
color: @cde-muted;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 4px 10px;
|
||||||
|
border-radius: @cde-radius;
|
||||||
|
border: 1px solid @cde-border;
|
||||||
|
transition: color 0.12s, border-color 0.12s, background 0.12s;
|
||||||
|
|
||||||
|
i { font-size: 10px; }
|
||||||
|
|
||||||
|
&:hover { color: @cde-supernatural; border-color: @cde-supernatural; background: fade(@cde-supernatural, 8%); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-super-card {
|
||||||
|
border: 1px solid @cde-border;
|
||||||
|
border-left: 3px solid @cde-supernatural;
|
||||||
|
border-radius: @cde-radius;
|
||||||
|
background: fade(@cde-surface, 70%);
|
||||||
|
margin-bottom: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: box-shadow 0.15s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 0 8px fade(@cde-supernatural, 20%);
|
||||||
|
|
||||||
|
.cde-super-controls { opacity: 1; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-super-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 8px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-super-img {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
object-fit: contain;
|
||||||
|
border-radius: 4px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-super-info {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 3px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-super-name {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 700;
|
||||||
|
font-family: "Averia", sans-serif;
|
||||||
|
color: @cde-text;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-super-meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-super-controls {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.12s;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
a {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: @cde-muted;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color 0.12s, background 0.12s;
|
||||||
|
|
||||||
|
i { font-size: 11px; }
|
||||||
|
|
||||||
|
&:hover { color: @cde-text; background: fade(@cde-border-hi, 30%); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-super-desc {
|
||||||
|
padding: 6px 12px 8px 46px;
|
||||||
|
border-top: 1px solid fade(@cde-border, 60%);
|
||||||
|
background: fade(@cde-surface, 40%);
|
||||||
|
font-size: 11px;
|
||||||
|
color: @cde-muted;
|
||||||
|
line-height: 1.5;
|
||||||
|
|
||||||
|
p { margin: 0 0 4px; &:last-child { margin-bottom: 0; } }
|
||||||
|
em { color: @cde-text; }
|
||||||
|
strong { color: @cde-supernatural; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-super-empty {
|
||||||
|
padding: 16px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 12px;
|
||||||
|
color: @cde-muted;
|
||||||
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NPC vitality / hei tracker
|
// NPC vitality / hei tracker
|
||||||
@@ -956,6 +1117,586 @@ section.npc .cde-neon-tabs .item.active { color: @cde-supernatural; borde
|
|||||||
// ============================================================
|
// ============================================================
|
||||||
// Loksyu — 5 elemental cards grid
|
// Loksyu — 5 elemental cards grid
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
// ============================================================
|
||||||
|
// Chat buttons — Loksyu / TinJi quick-access
|
||||||
|
// ============================================================
|
||||||
|
.cde-chat-app-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 6px 8px 4px;
|
||||||
|
border-top: 1px solid @cde-border;
|
||||||
|
pointer-events: auto; // sidebar has pointer-events:none — must override
|
||||||
|
|
||||||
|
.cde-chat-btn {
|
||||||
|
flex: 1 1 0;
|
||||||
|
pointer-events: auto;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 5px 8px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-family: "Orbitron", "Averia", sans-serif;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.06em;
|
||||||
|
background: @cde-surface;
|
||||||
|
border: 1px solid @cde-border;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: @cde-muted;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
|
||||||
|
i { font-size: 12px; }
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: fade(@cde-spell, 10%);
|
||||||
|
border-color: @cde-spell;
|
||||||
|
color: @cde-spell;
|
||||||
|
box-shadow: 0 0 8px fade(@cde-spell, 30%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&--tinji:hover {
|
||||||
|
background: fade(@cde-kungfu, 10%);
|
||||||
|
border-color: @cde-kungfu;
|
||||||
|
color: @cde-kungfu;
|
||||||
|
box-shadow: 0 0 8px fade(@cde-kungfu, 30%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Loksyu standalone app
|
||||||
|
// ============================================================
|
||||||
|
.cde-loksyu-standalone {
|
||||||
|
.cde-loksyu-app-body {
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-loksyu-elements {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-lok-card {
|
||||||
|
flex: 0 0 calc(33.333% - 6px);
|
||||||
|
min-width: 140px;
|
||||||
|
max-width: 160px;
|
||||||
|
background: fade(@cde-surface, 80%);
|
||||||
|
border: 1px solid @cde-border;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 10px 8px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
|
||||||
|
&--wood { &:hover { border-color: #4a9e3f; } .cde-lok-input:focus { border-bottom-color: #4a9e3f; } }
|
||||||
|
&--fire { &:hover { border-color: @cde-kungfu; } .cde-lok-input:focus { border-bottom-color: @cde-kungfu; } }
|
||||||
|
&--earth { &:hover { border-color: #c88a3a; } .cde-lok-input:focus { border-bottom-color: #c88a3a; } }
|
||||||
|
&--metal { &:hover { border-color: @cde-muted; } .cde-lok-input:focus { border-bottom-color: @cde-muted; } }
|
||||||
|
&--water { &:hover { border-color: @cde-spell; } .cde-lok-input:focus { border-bottom-color: @cde-spell; } }
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-lok-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
|
||||||
|
img.cde-lok-icon { border-radius: 4px; flex-shrink: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-lok-titles {
|
||||||
|
flex: 1 1 0;
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.cde-lok-name {
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
color: @cde-text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-lok-qual {
|
||||||
|
font-size: 9px;
|
||||||
|
color: @cde-muted;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-lok-reset {
|
||||||
|
color: @cde-muted;
|
||||||
|
font-size: 11px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover { color: @cde-text; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-lok-values {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-lok-polarity {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
.cde-lok-pol-label {
|
||||||
|
font-size: 9px;
|
||||||
|
color: @cde-muted;
|
||||||
|
width: 30px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--yang .cde-lok-pol-label { color: @cde-text; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-lok-input {
|
||||||
|
flex: 1 1 0;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
border-bottom: 1px solid @cde-border;
|
||||||
|
color: @cde-text;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 700;
|
||||||
|
text-align: center;
|
||||||
|
padding: 2px 0;
|
||||||
|
transition: border-bottom-color 0.2s;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&:focus { outline: none; }
|
||||||
|
&[disabled] { opacity: 0.5; cursor: default; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-loksyu-visual-row {
|
||||||
|
text-align: center;
|
||||||
|
margin: 6px 0;
|
||||||
|
|
||||||
|
.cde-lok-visual {
|
||||||
|
max-width: 120px;
|
||||||
|
max-height: 160px;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-lok-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding-top: 6px;
|
||||||
|
border-top: 1px solid @cde-border;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-lok-reset-all {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 5px 14px;
|
||||||
|
font-size: 11px;
|
||||||
|
background: fade(@cde-kungfu, 12%);
|
||||||
|
border: 1px solid fade(@cde-kungfu, 30%);
|
||||||
|
border-radius: 4px;
|
||||||
|
color: @cde-muted;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: fade(@cde-kungfu, 20%);
|
||||||
|
border-color: @cde-kungfu;
|
||||||
|
color: @cde-text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// TinJi standalone app
|
||||||
|
// ============================================================
|
||||||
|
.cde-tinji-standalone {
|
||||||
|
.cde-tinji-app-body {
|
||||||
|
padding: 16px 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-tinji-display {
|
||||||
|
flex: 1 1 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-tinji-chinese-large {
|
||||||
|
font-size: 40px;
|
||||||
|
color: @cde-kungfu;
|
||||||
|
text-shadow: 0 0 20px fade(@cde-kungfu, 60%);
|
||||||
|
line-height: 1;
|
||||||
|
font-family: serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-tinji-label {
|
||||||
|
font-size: 11px;
|
||||||
|
font-family: "Orbitron", sans-serif;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.12em;
|
||||||
|
color: @cde-text;
|
||||||
|
opacity: 0.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-tinji-counter {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin: 4px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-tinji-step {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
background: @cde-surface2;
|
||||||
|
border: 1px solid @cde-border-hi;
|
||||||
|
border-radius: 50%;
|
||||||
|
color: @cde-text;
|
||||||
|
font-size: 18px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: all 0.2s;
|
||||||
|
line-height: 1;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: fade(@cde-kungfu, 25%);
|
||||||
|
border-color: @cde-kungfu;
|
||||||
|
color: @cde-text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-tinji-direct {
|
||||||
|
width: 72px;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
border-bottom: 2px solid @cde-kungfu;
|
||||||
|
color: @cde-kungfu;
|
||||||
|
font-size: 36px;
|
||||||
|
font-weight: 700;
|
||||||
|
text-align: center;
|
||||||
|
text-shadow: 0 0 12px fade(@cde-kungfu, 50%);
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
&:focus { outline: none; }
|
||||||
|
&[disabled] { opacity: 0.7; cursor: default; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-tinji-hint {
|
||||||
|
font-size: 10px;
|
||||||
|
color: @cde-muted;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-tinji-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-tinji-spend-btn,
|
||||||
|
.cde-tinji-reset-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-tinji-spend-btn {
|
||||||
|
background: fade(@cde-kungfu, 25%);
|
||||||
|
border: 1px solid @cde-kungfu;
|
||||||
|
color: @cde-text;
|
||||||
|
|
||||||
|
&:hover { background: fade(@cde-kungfu, 45%); border-color: lighten(@cde-kungfu, 10%); }
|
||||||
|
&[disabled] { opacity: 0.55; cursor: not-allowed; pointer-events: none; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-tinji-reset-btn {
|
||||||
|
background: @cde-surface2;
|
||||||
|
border: 1px solid @cde-border-hi;
|
||||||
|
color: @cde-text;
|
||||||
|
opacity: 0.85;
|
||||||
|
|
||||||
|
&:hover { border-color: @cde-text; opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-tinji-visual {
|
||||||
|
width: 90px;
|
||||||
|
height: auto;
|
||||||
|
opacity: 0.85;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chat Tin Ji spend message
|
||||||
|
.cde-tinji-spend-msg {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 8px 10px;
|
||||||
|
background: fade(@cde-kungfu, 18%);
|
||||||
|
border: 1px solid fade(@cde-kungfu, 35%);
|
||||||
|
border-left: 4px solid @cde-kungfu;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: @cde-text;
|
||||||
|
|
||||||
|
.cde-tinji-icon {
|
||||||
|
font-size: 18px;
|
||||||
|
color: @cde-kungfu;
|
||||||
|
text-shadow: 0 0 6px fade(@cde-kungfu, 70%);
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
color: @cde-kungfu;
|
||||||
|
font-size: 15px;
|
||||||
|
filter: drop-shadow(0 0 4px fade(@cde-kungfu, 60%));
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
color: @cde-kungfu;
|
||||||
|
font-size: 13px;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-tinji-remain {
|
||||||
|
margin-left: auto;
|
||||||
|
font-size: 11px;
|
||||||
|
color: fade(@cde-text, 65%);
|
||||||
|
font-style: italic;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post-roll Loksyu draw message — rich notification card
|
||||||
|
.cde-loksyu-draw-msg {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 5px;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 9px 11px;
|
||||||
|
background: linear-gradient(135deg, fade(@cde-item, 10%) 0%, fade(@cde-surface, 95%) 100%);
|
||||||
|
border: 1px solid fade(@cde-item, 40%);
|
||||||
|
border-left: 4px solid @cde-item;
|
||||||
|
border-radius: 5px;
|
||||||
|
color: @cde-text;
|
||||||
|
box-shadow: 0 2px 8px fade(@cde-item, 12%);
|
||||||
|
|
||||||
|
.cde-loksyu-draw-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 5px;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-loksyu-draw-aspect-icon {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
object-fit: contain;
|
||||||
|
filter: drop-shadow(0 0 4px fade(@cde-item, 60%));
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-loksyu-draw-user {
|
||||||
|
font-weight: 700;
|
||||||
|
color: @cde-item;
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-loksyu-draw-action {
|
||||||
|
color: fade(@cde-text, 65%);
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-loksyu-draw-type {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #c9a227;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
text-shadow: 0 0 6px fade(#c9a227, 40%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-loksyu-draw-from {
|
||||||
|
color: fade(@cde-text, 60%);
|
||||||
|
font-size: 11px;
|
||||||
|
|
||||||
|
em {
|
||||||
|
color: @cde-item;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-loksyu-draw-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: fade(@cde-text, 55%);
|
||||||
|
padding-top: 4px;
|
||||||
|
border-top: 1px solid fade(@cde-item, 20%);
|
||||||
|
|
||||||
|
i {
|
||||||
|
color: @cde-item;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-loksyu-remain {
|
||||||
|
color: @cde-item;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post-roll action buttons section inside a roll-result card
|
||||||
|
.cde-roll-actions {
|
||||||
|
margin-top: 10px;
|
||||||
|
padding-top: 8px;
|
||||||
|
border-top: 1px solid fade(@cde-border, 60%);
|
||||||
|
|
||||||
|
.cde-roll-actions-title {
|
||||||
|
font-size: 10px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
color: fade(@cde-text, 50%);
|
||||||
|
margin-bottom: 6px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
i { font-size: 9px; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-roll-actions-btns {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-roll-action-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-family: "Courier New", Courier, monospace;
|
||||||
|
border-radius: 3px;
|
||||||
|
border: 1px solid fade(@cde-border, 80%);
|
||||||
|
background: fade(@cde-surface, 90%);
|
||||||
|
color: @cde-text;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.15s, border-color 0.15s, box-shadow 0.15s;
|
||||||
|
pointer-events: auto;
|
||||||
|
line-height: 1.4;
|
||||||
|
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
border-color: fade(@cde-item, 70%);
|
||||||
|
background: fade(@cde-item, 12%);
|
||||||
|
box-shadow: 0 0 6px fade(@cde-item, 25%);
|
||||||
|
color: @cde-item;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 0.35;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-roll-action-icon {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
object-fit: contain;
|
||||||
|
filter: drop-shadow(0 0 2px fade(@cde-item, 40%));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-roll-action-label {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-roll-action-count {
|
||||||
|
background: fade(@cde-border, 60%);
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: 1px 4px;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 700;
|
||||||
|
min-width: 18px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-roll-action-tinji-char {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1;
|
||||||
|
color: @cde-kungfu;
|
||||||
|
text-shadow: 0 0 4px fade(@cde-kungfu, 60%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.cde-roll-action--success {
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
border-color: fade(#c9a227, 70%);
|
||||||
|
background: fade(#c9a227, 10%);
|
||||||
|
box-shadow: 0 0 6px fade(#c9a227, 25%);
|
||||||
|
color: #c9a227;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.cde-roll-action--faste {
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
border-color: fade(@cde-item, 70%);
|
||||||
|
background: fade(@cde-item, 10%);
|
||||||
|
box-shadow: 0 0 6px fade(@cde-item, 25%);
|
||||||
|
color: @cde-item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.cde-roll-action--tinji {
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
border-color: fade(@cde-kungfu, 70%);
|
||||||
|
background: fade(@cde-kungfu, 12%);
|
||||||
|
box-shadow: 0 0 6px fade(@cde-kungfu, 30%);
|
||||||
|
color: @cde-kungfu;
|
||||||
|
|
||||||
|
.cde-roll-action-count {
|
||||||
|
background: fade(@cde-kungfu, 25%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.cde-loksyu-grid {
|
.cde-loksyu-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||||
@@ -2793,6 +3534,37 @@ ol.item-list {
|
|||||||
color: @cde-muted;
|
color: @cde-muted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Loksyu bonus badge (shown when dice drawn from Loksyu)
|
||||||
|
.cde-rr-loksyu-bonus {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 3px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 3px;
|
||||||
|
animation: cde-pulse-in 0.3s ease;
|
||||||
|
|
||||||
|
&.cde-rr-loksyu-bonus--success {
|
||||||
|
background: fade(#c9a227, 20%);
|
||||||
|
border: 1px solid fade(#c9a227, 50%);
|
||||||
|
color: #c9a227;
|
||||||
|
text-shadow: 0 0 6px fade(#c9a227, 60%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.cde-rr-loksyu-bonus--faste {
|
||||||
|
background: fade(@cde-item, 15%);
|
||||||
|
border: 1px solid fade(@cde-item, 40%);
|
||||||
|
color: @cde-item;
|
||||||
|
text-shadow: 0 0 6px fade(@cde-item, 50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes cde-pulse-in {
|
||||||
|
from { opacity: 0; transform: scale(0.7); }
|
||||||
|
to { opacity: 1; transform: scale(1); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Detail rows ----
|
// ---- Detail rows ----
|
||||||
@@ -2821,6 +3593,19 @@ ol.item-list {
|
|||||||
text-shadow: 0 0 6px currentColor;
|
text-shadow: 0 0 6px currentColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Inline Loksyu bonus badge in detail rows
|
||||||
|
.cde-rr-loksyu-bonus {
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 1px 4px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: fade(@cde-item, 15%);
|
||||||
|
border: 1px solid fade(@cde-item, 40%);
|
||||||
|
color: @cde-item;
|
||||||
|
text-shadow: 0 0 4px fade(@cde-item, 50%);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.cde-rr-icon {
|
.cde-rr-icon {
|
||||||
width: 22px;
|
width: 22px;
|
||||||
height: 22px;
|
height: 22px;
|
||||||
|
|||||||
732
dist/system.js
vendored
732
dist/system.js
vendored
File diff suppressed because it is too large
Load Diff
8
dist/system.js.map
vendored
8
dist/system.js.map
vendored
File diff suppressed because one or more lines are too long
@@ -18,6 +18,9 @@
|
|||||||
"CDE.DefineTemplate": "Define as Template",
|
"CDE.DefineTemplate": "Define as Template",
|
||||||
"CDE.UnsetTemplate": "Unset Template",
|
"CDE.UnsetTemplate": "Unset Template",
|
||||||
"CDE.NoTemplate": "No Template",
|
"CDE.NoTemplate": "No Template",
|
||||||
|
"CDE.NoSupernaturals": "No supernatural powers",
|
||||||
|
"CDE.NoSpells": "No spells",
|
||||||
|
"CDE.NoKungFu": "No martial arts",
|
||||||
|
|
||||||
"CDE.Quantity": "Quantity",
|
"CDE.Quantity": "Quantity",
|
||||||
"CDE.Weight": "Weight",
|
"CDE.Weight": "Weight",
|
||||||
@@ -239,6 +242,7 @@
|
|||||||
|
|
||||||
"CDE.LoksyuName": "Loksyu Name",
|
"CDE.LoksyuName": "Loksyu Name",
|
||||||
"CDE.Loksyu": "Loksyu",
|
"CDE.Loksyu": "Loksyu",
|
||||||
|
"CDE.LoksyuNotFound": "No Loksyu actor found. The Game Master must create one.",
|
||||||
"CDE.MetalYang": "㊎ Yang Metal (3)",
|
"CDE.MetalYang": "㊎ Yang Metal (3)",
|
||||||
"CDE.MetalYin": "㊎ Yin Metal (8)",
|
"CDE.MetalYin": "㊎ Yin Metal (8)",
|
||||||
"CDE.WaterYang": "㊌ Yang Water (1)",
|
"CDE.WaterYang": "㊌ Yang Water (1)",
|
||||||
@@ -299,6 +303,20 @@
|
|||||||
|
|
||||||
"CDE.TinJiName": "Tin Ji Name",
|
"CDE.TinJiName": "Tin Ji Name",
|
||||||
"CDE.TinJi2": "Tin Ji",
|
"CDE.TinJi2": "Tin Ji",
|
||||||
|
"CDE.TinjiNotFound": "No Tin Ji actor found. The Game Master must create one.",
|
||||||
|
"CDE.TinjiEmpty": "No Tin Ji dice remaining.",
|
||||||
|
"CDE.TinjiSpent": "{name} spends 1 Tin Ji die.",
|
||||||
|
"CDE.PostRollActions": "Draw from Loksyu / Spend Tin Ji",
|
||||||
|
"CDE.LoksyuDrawsA": "draws",
|
||||||
|
"CDE.LoksyuFromAspect": "from",
|
||||||
|
"CDE.LoksyuRemaining": "die/dice remaining",
|
||||||
|
"CDE.LoksyuEmpty": "The Loksyu has no dice remaining for this aspect.",
|
||||||
|
"CDE.TinjiRemaining": "remaining",
|
||||||
|
"CDE.SpendTinji": "Spend a die",
|
||||||
|
"CDE.Reset": "Reset",
|
||||||
|
"CDE.ResetAll": "Reset all",
|
||||||
|
"CDE.Decrement": "Decrease",
|
||||||
|
"CDE.Increment": "Increase",
|
||||||
|
|
||||||
"CDE.UpperCaseSuccesses": "SUCCESSES",
|
"CDE.UpperCaseSuccesses": "SUCCESSES",
|
||||||
"CDE.UpperCaseAuspiciousDice": "AUSPICIOUS-DICE",
|
"CDE.UpperCaseAuspiciousDice": "AUSPICIOUS-DICE",
|
||||||
|
|||||||
@@ -151,6 +151,7 @@
|
|||||||
"CDE.Loksyu": "Loksyu",
|
"CDE.Loksyu": "Loksyu",
|
||||||
"CDE.Loksyu2": "Loksyu :",
|
"CDE.Loksyu2": "Loksyu :",
|
||||||
"CDE.LoksyuName": "Nom du Loksyu",
|
"CDE.LoksyuName": "Nom du Loksyu",
|
||||||
|
"CDE.LoksyuNotFound": "Aucun acteur Loksyu trouvé. Le Maître du Jeu doit en créer un.",
|
||||||
"CDE.MagicPromptName": "Jet de Magie",
|
"CDE.MagicPromptName": "Jet de Magie",
|
||||||
"CDE.Magics": "Magies",
|
"CDE.Magics": "Magies",
|
||||||
"CDE.Manipulation": "Manipulation",
|
"CDE.Manipulation": "Manipulation",
|
||||||
@@ -187,6 +188,9 @@
|
|||||||
"CDE.NextTimeGoToTheSettings": "Tout ceci est paramétrable dans les Préférences",
|
"CDE.NextTimeGoToTheSettings": "Tout ceci est paramétrable dans les Préférences",
|
||||||
"CDE.NgHang": "Ng Hang",
|
"CDE.NgHang": "Ng Hang",
|
||||||
"CDE.NoTemplate": "Aucun Modèle",
|
"CDE.NoTemplate": "Aucun Modèle",
|
||||||
|
"CDE.NoSupernaturals": "Aucun pouvoir surnaturel",
|
||||||
|
"CDE.NoSpells": "Aucun sortilège",
|
||||||
|
"CDE.NoKungFu": "Aucun art martial",
|
||||||
"CDE.Notes": "Notes",
|
"CDE.Notes": "Notes",
|
||||||
"CDE.Noxious": "Dés-Néfastes",
|
"CDE.Noxious": "Dés-Néfastes",
|
||||||
"CDE.Nuisance": "Capacité de Nuisance",
|
"CDE.Nuisance": "Capacité de Nuisance",
|
||||||
@@ -278,6 +282,20 @@
|
|||||||
"CDE.TinJi": "Tin Ji :",
|
"CDE.TinJi": "Tin Ji :",
|
||||||
"CDE.TinJi2": "Tin Ji",
|
"CDE.TinJi2": "Tin Ji",
|
||||||
"CDE.TinJiName": "Nom de la Tin Ji",
|
"CDE.TinJiName": "Nom de la Tin Ji",
|
||||||
|
"CDE.TinjiNotFound": "Aucun acteur Tin Ji trouvé. Le Maître du Jeu doit en créer un.",
|
||||||
|
"CDE.TinjiEmpty": "Il n'y a plus de dés de Tin Ji disponibles.",
|
||||||
|
"CDE.TinjiSpent": "{name} dépense 1 dé de Tin Ji.",
|
||||||
|
"CDE.PostRollActions": "Puiser dans le Loksyu / Dépenser Tin Ji",
|
||||||
|
"CDE.LoksyuDrawsA": "pioche",
|
||||||
|
"CDE.LoksyuFromAspect": "du",
|
||||||
|
"CDE.LoksyuRemaining": "dé(s) restant(s)",
|
||||||
|
"CDE.LoksyuEmpty": "Le Loksyu ne contient plus de dés pour cet aspect.",
|
||||||
|
"CDE.TinjiRemaining": "restant(s)",
|
||||||
|
"CDE.SpendTinji": "Dépenser un dé",
|
||||||
|
"CDE.Reset": "Réinitialiser",
|
||||||
|
"CDE.ResetAll": "Tout réinitialiser",
|
||||||
|
"CDE.Decrement": "Diminuer",
|
||||||
|
"CDE.Increment": "Augmenter",
|
||||||
"CDE.Total": "Total",
|
"CDE.Total": "Total",
|
||||||
"CDE.Total-Present": "Total ● Actuel",
|
"CDE.Total-Present": "Total ● Actuel",
|
||||||
"CDE.Tracking": "Traque",
|
"CDE.Tracking": "Traque",
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
MANIFEST-000062
|
MANIFEST-000078
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
2026/03/27-23:40:07.003627 7f90f7fff6c0 Recovering log #60
|
2026/03/30-15:06:44.332250 7f4bdafee6c0 Recovering log #76
|
||||||
2026/03/27-23:40:07.014585 7f90f7fff6c0 Delete type=3 #58
|
2026/03/30-15:06:44.345027 7f4bdafee6c0 Delete type=3 #74
|
||||||
2026/03/27-23:40:07.014647 7f90f7fff6c0 Delete type=0 #60
|
2026/03/30-15:06:44.345091 7f4bdafee6c0 Delete type=0 #76
|
||||||
2026/03/28-01:06:04.060694 7f90f5ffb6c0 Level-0 table #65: started
|
|
||||||
2026/03/28-01:06:04.060719 7f90f5ffb6c0 Level-0 table #65: 0 bytes OK
|
|
||||||
2026/03/28-01:06:04.067602 7f90f5ffb6c0 Delete type=0 #63
|
|
||||||
2026/03/28-01:06:04.080111 7f90f5ffb6c0 Manual compaction at level-0 from '!journal!ZWBHiWW5QlUeseAX' @ 72057594037927935 : 1 .. '!journal.pages!ZWBHiWW5QlUeseAX.jtQXIqLfyet8Nlte' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/03/27-21:21:30.280454 7f90f67fc6c0 Recovering log #56
|
2026/03/30-14:14:12.690902 7f4bdafee6c0 Recovering log #72
|
||||||
2026/03/27-21:21:30.290347 7f90f67fc6c0 Delete type=3 #54
|
2026/03/30-14:14:12.745563 7f4bdafee6c0 Delete type=3 #70
|
||||||
2026/03/27-21:21:30.290399 7f90f67fc6c0 Delete type=0 #56
|
2026/03/30-14:14:12.745612 7f4bdafee6c0 Delete type=0 #72
|
||||||
2026/03/27-21:21:32.095874 7f90f5ffb6c0 Level-0 table #61: started
|
2026/03/30-15:06:34.607428 7f4bd8fea6c0 Level-0 table #77: started
|
||||||
2026/03/27-21:21:32.095896 7f90f5ffb6c0 Level-0 table #61: 0 bytes OK
|
2026/03/30-15:06:34.607461 7f4bd8fea6c0 Level-0 table #77: 0 bytes OK
|
||||||
2026/03/27-21:21:32.102427 7f90f5ffb6c0 Delete type=0 #59
|
2026/03/30-15:06:34.613785 7f4bd8fea6c0 Delete type=0 #75
|
||||||
2026/03/27-21:21:32.116179 7f90f5ffb6c0 Manual compaction at level-0 from '!journal!ZWBHiWW5QlUeseAX' @ 72057594037927935 : 1 .. '!journal.pages!ZWBHiWW5QlUeseAX.jtQXIqLfyet8Nlte' @ 0 : 0; will stop at (end)
|
2026/03/30-15:06:34.613973 7f4bd8fea6c0 Manual compaction at level-0 from '!journal!ZWBHiWW5QlUeseAX' @ 72057594037927935 : 1 .. '!journal.pages!ZWBHiWW5QlUeseAX.jtQXIqLfyet8Nlte' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000178
|
MANIFEST-000194
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
2026/03/27-23:40:06.991314 7f90f77fe6c0 Recovering log #176
|
2026/03/30-15:06:44.318696 7f4bd97eb6c0 Recovering log #192
|
||||||
2026/03/27-23:40:07.001875 7f90f77fe6c0 Delete type=3 #174
|
2026/03/30-15:06:44.329241 7f4bd97eb6c0 Delete type=3 #190
|
||||||
2026/03/27-23:40:07.001926 7f90f77fe6c0 Delete type=0 #176
|
2026/03/30-15:06:44.329288 7f4bd97eb6c0 Delete type=0 #192
|
||||||
2026/03/28-01:06:04.048472 7f90f5ffb6c0 Level-0 table #181: started
|
|
||||||
2026/03/28-01:06:04.048493 7f90f5ffb6c0 Level-0 table #181: 0 bytes OK
|
|
||||||
2026/03/28-01:06:04.054367 7f90f5ffb6c0 Delete type=0 #179
|
|
||||||
2026/03/28-01:06:04.054479 7f90f5ffb6c0 Manual compaction at level-0 from '!journal!TniC3ok9W0hDYxJS' @ 72057594037927935 : 1 .. '!journal.pages!yZsG9QaBHT3cUfNd.AHcfBcO96nUCELxv' @ 0 : 0; will stop at (end)
|
|
||||||
2026/03/28-01:06:04.054500 7f90f5ffb6c0 Manual compaction at level-1 from '!journal!TniC3ok9W0hDYxJS' @ 72057594037927935 : 1 .. '!journal.pages!yZsG9QaBHT3cUfNd.AHcfBcO96nUCELxv' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2026/03/27-21:21:30.268953 7f90f6ffd6c0 Recovering log #172
|
2026/03/30-14:14:12.605619 7f4bd9fec6c0 Recovering log #188
|
||||||
2026/03/27-21:21:30.278662 7f90f6ffd6c0 Delete type=3 #170
|
2026/03/30-14:14:12.686963 7f4bd9fec6c0 Delete type=3 #186
|
||||||
2026/03/27-21:21:30.278730 7f90f6ffd6c0 Delete type=0 #172
|
2026/03/30-14:14:12.687013 7f4bd9fec6c0 Delete type=0 #188
|
||||||
2026/03/27-21:21:32.067762 7f90f5ffb6c0 Level-0 table #177: started
|
2026/03/30-15:06:34.620345 7f4bd8fea6c0 Level-0 table #193: started
|
||||||
2026/03/27-21:21:32.067784 7f90f5ffb6c0 Level-0 table #177: 0 bytes OK
|
2026/03/30-15:06:34.620377 7f4bd8fea6c0 Level-0 table #193: 0 bytes OK
|
||||||
2026/03/27-21:21:32.074619 7f90f5ffb6c0 Delete type=0 #175
|
2026/03/30-15:06:34.628129 7f4bd8fea6c0 Delete type=0 #191
|
||||||
2026/03/27-21:21:32.089332 7f90f5ffb6c0 Manual compaction at level-0 from '!journal!TniC3ok9W0hDYxJS' @ 72057594037927935 : 1 .. '!journal.pages!yZsG9QaBHT3cUfNd.AHcfBcO96nUCELxv' @ 0 : 0; will stop at (end)
|
2026/03/30-15:06:34.641660 7f4bd8fea6c0 Manual compaction at level-0 from '!journal!TniC3ok9W0hDYxJS' @ 72057594037927935 : 1 .. '!journal.pages!yZsG9QaBHT3cUfNd.AHcfBcO96nUCELxv' @ 0 : 0; will stop at (end)
|
||||||
2026/03/27-21:21:32.089368 7f90f5ffb6c0 Manual compaction at level-1 from '!journal!TniC3ok9W0hDYxJS' @ 72057594037927935 : 1 .. '!journal.pages!yZsG9QaBHT3cUfNd.AHcfBcO96nUCELxv' @ 0 : 0; will stop at (end)
|
2026/03/30-15:06:34.641692 7f4bd8fea6c0 Manual compaction at level-1 from '!journal!TniC3ok9W0hDYxJS' @ 72057594037927935 : 1 .. '!journal.pages!yZsG9QaBHT3cUfNd.AHcfBcO96nUCELxv' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000750
|
MANIFEST-000766
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
2026/03/27-23:40:06.977536 7f90f67fc6c0 Recovering log #748
|
2026/03/30-15:06:44.305642 7f4bda7ed6c0 Recovering log #764
|
||||||
2026/03/27-23:40:06.987624 7f90f67fc6c0 Delete type=3 #746
|
2026/03/30-15:06:44.315212 7f4bda7ed6c0 Delete type=3 #762
|
||||||
2026/03/27-23:40:06.987699 7f90f67fc6c0 Delete type=0 #748
|
2026/03/30-15:06:44.315294 7f4bda7ed6c0 Delete type=0 #764
|
||||||
2026/03/28-01:06:04.041962 7f90f5ffb6c0 Level-0 table #753: started
|
|
||||||
2026/03/28-01:06:04.041998 7f90f5ffb6c0 Level-0 table #753: 0 bytes OK
|
|
||||||
2026/03/28-01:06:04.048371 7f90f5ffb6c0 Delete type=0 #751
|
|
||||||
2026/03/28-01:06:04.054466 7f90f5ffb6c0 Manual compaction at level-0 from '!journal!f6UhPlIUh2O0F36q' @ 72057594037927935 : 1 .. '!journal.pages!f6UhPlIUh2O0F36q.keqszrb6FAI7CVZx' @ 0 : 0; will stop at (end)
|
|
||||||
2026/03/28-01:06:04.054494 7f90f5ffb6c0 Manual compaction at level-1 from '!journal!f6UhPlIUh2O0F36q' @ 72057594037927935 : 1 .. '!journal.pages!f6UhPlIUh2O0F36q.keqszrb6FAI7CVZx' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2026/03/27-21:21:30.255554 7f90f77fe6c0 Recovering log #744
|
2026/03/30-14:14:12.515876 7f4bd97eb6c0 Recovering log #760
|
||||||
2026/03/27-21:21:30.266879 7f90f77fe6c0 Delete type=3 #742
|
2026/03/30-14:14:12.589985 7f4bd97eb6c0 Delete type=3 #758
|
||||||
2026/03/27-21:21:30.266948 7f90f77fe6c0 Delete type=0 #744
|
2026/03/30-14:14:12.590051 7f4bd97eb6c0 Delete type=0 #760
|
||||||
2026/03/27-21:21:32.081193 7f90f5ffb6c0 Level-0 table #749: started
|
2026/03/30-15:06:34.600499 7f4bd8fea6c0 Level-0 table #765: started
|
||||||
2026/03/27-21:21:32.081218 7f90f5ffb6c0 Level-0 table #749: 0 bytes OK
|
2026/03/30-15:06:34.600616 7f4bd8fea6c0 Level-0 table #765: 0 bytes OK
|
||||||
2026/03/27-21:21:32.089124 7f90f5ffb6c0 Delete type=0 #747
|
2026/03/30-15:06:34.607256 7f4bd8fea6c0 Delete type=0 #763
|
||||||
2026/03/27-21:21:32.089363 7f90f5ffb6c0 Manual compaction at level-0 from '!journal!f6UhPlIUh2O0F36q' @ 72057594037927935 : 1 .. '!journal.pages!f6UhPlIUh2O0F36q.keqszrb6FAI7CVZx' @ 0 : 0; will stop at (end)
|
2026/03/30-15:06:34.613958 7f4bd8fea6c0 Manual compaction at level-0 from '!journal!f6UhPlIUh2O0F36q' @ 72057594037927935 : 1 .. '!journal.pages!f6UhPlIUh2O0F36q.keqszrb6FAI7CVZx' @ 0 : 0; will stop at (end)
|
||||||
2026/03/27-21:21:32.089373 7f90f5ffb6c0 Manual compaction at level-1 from '!journal!f6UhPlIUh2O0F36q' @ 72057594037927935 : 1 .. '!journal.pages!f6UhPlIUh2O0F36q.keqszrb6FAI7CVZx' @ 0 : 0; will stop at (end)
|
2026/03/30-15:06:34.614004 7f4bd8fea6c0 Manual compaction at level-1 from '!journal!f6UhPlIUh2O0F36q' @ 72057594037927935 : 1 .. '!journal.pages!f6UhPlIUh2O0F36q.keqszrb6FAI7CVZx' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-004371
|
MANIFEST-004387
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
2026/03/27-23:40:06.951174 7f90f77fe6c0 Recovering log #4369
|
2026/03/30-15:06:44.225449 7f4bd97eb6c0 Recovering log #4385
|
||||||
2026/03/27-23:40:06.961084 7f90f77fe6c0 Delete type=3 #4367
|
2026/03/30-15:06:44.236150 7f4bd97eb6c0 Delete type=3 #4383
|
||||||
2026/03/27-23:40:06.961153 7f90f77fe6c0 Delete type=0 #4369
|
2026/03/30-15:06:44.236230 7f4bd97eb6c0 Delete type=0 #4385
|
||||||
2026/03/28-01:06:04.029376 7f90f5ffb6c0 Level-0 table #4374: started
|
|
||||||
2026/03/28-01:06:04.029452 7f90f5ffb6c0 Level-0 table #4374: 0 bytes OK
|
|
||||||
2026/03/28-01:06:04.035591 7f90f5ffb6c0 Delete type=0 #4372
|
|
||||||
2026/03/28-01:06:04.054447 7f90f5ffb6c0 Manual compaction at level-0 from '!journal!0lxwWrzKsdTBQhH0' @ 72057594037927935 : 1 .. '!journal.pages!wgSyae4GTJDkmBOm.6Ql0lgquUCTrMyTZ' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/03/27-21:21:30.230925 7f90f67fc6c0 Recovering log #4365
|
2026/03/30-14:14:12.387545 7f4bda7ed6c0 Recovering log #4381
|
||||||
2026/03/27-21:21:30.240633 7f90f67fc6c0 Delete type=3 #4363
|
2026/03/30-14:14:12.435510 7f4bda7ed6c0 Delete type=3 #4379
|
||||||
2026/03/27-21:21:30.240686 7f90f67fc6c0 Delete type=0 #4365
|
2026/03/30-14:14:12.435579 7f4bda7ed6c0 Delete type=0 #4381
|
||||||
2026/03/27-21:21:32.060793 7f90f5ffb6c0 Level-0 table #4370: started
|
2026/03/30-15:06:34.685316 7f4bd8fea6c0 Level-0 table #4386: started
|
||||||
2026/03/27-21:21:32.060834 7f90f5ffb6c0 Level-0 table #4370: 0 bytes OK
|
2026/03/30-15:06:34.685354 7f4bd8fea6c0 Level-0 table #4386: 0 bytes OK
|
||||||
2026/03/27-21:21:32.067619 7f90f5ffb6c0 Delete type=0 #4368
|
2026/03/30-15:06:34.691827 7f4bd8fea6c0 Delete type=0 #4384
|
||||||
2026/03/27-21:21:32.089309 7f90f5ffb6c0 Manual compaction at level-0 from '!journal!0lxwWrzKsdTBQhH0' @ 72057594037927935 : 1 .. '!journal.pages!wgSyae4GTJDkmBOm.6Ql0lgquUCTrMyTZ' @ 0 : 0; will stop at (end)
|
2026/03/30-15:06:34.709676 7f4bd8fea6c0 Manual compaction at level-0 from '!journal!0lxwWrzKsdTBQhH0' @ 72057594037927935 : 1 .. '!journal.pages!wgSyae4GTJDkmBOm.6Ql0lgquUCTrMyTZ' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000091
|
MANIFEST-000107
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
2026/03/27-23:40:07.041219 7f90f6ffd6c0 Recovering log #89
|
2026/03/30-15:06:44.375576 7f4bd97eb6c0 Recovering log #105
|
||||||
2026/03/27-23:40:07.052133 7f90f6ffd6c0 Delete type=3 #87
|
2026/03/30-15:06:44.385281 7f4bd97eb6c0 Delete type=3 #103
|
||||||
2026/03/27-23:40:07.052198 7f90f6ffd6c0 Delete type=0 #89
|
2026/03/30-15:06:44.385352 7f4bd97eb6c0 Delete type=0 #105
|
||||||
2026/03/28-01:06:04.074099 7f90f5ffb6c0 Level-0 table #94: started
|
|
||||||
2026/03/28-01:06:04.074129 7f90f5ffb6c0 Level-0 table #94: 0 bytes OK
|
|
||||||
2026/03/28-01:06:04.080023 7f90f5ffb6c0 Delete type=0 #92
|
|
||||||
2026/03/28-01:06:04.080128 7f90f5ffb6c0 Manual compaction at level-0 from '!tables!J9VdvrwkbyKxMAT7' @ 72057594037927935 : 1 .. '!tables.results!jGKjfCyk4ROSy9fU.zRzADzATtijaBdNX' @ 0 : 0; will stop at (end)
|
|
||||||
2026/03/28-01:06:04.080153 7f90f5ffb6c0 Manual compaction at level-1 from '!tables!J9VdvrwkbyKxMAT7' @ 72057594037927935 : 1 .. '!tables.results!jGKjfCyk4ROSy9fU.zRzADzATtijaBdNX' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2026/03/27-21:21:30.316292 7f90f77fe6c0 Recovering log #85
|
2026/03/30-14:14:12.872794 7f4bd9fec6c0 Recovering log #101
|
||||||
2026/03/27-21:21:30.326791 7f90f77fe6c0 Delete type=3 #83
|
2026/03/30-14:14:12.920810 7f4bd9fec6c0 Delete type=3 #99
|
||||||
2026/03/27-21:21:30.326838 7f90f77fe6c0 Delete type=0 #85
|
2026/03/30-14:14:12.920879 7f4bd9fec6c0 Delete type=0 #101
|
||||||
2026/03/27-21:21:32.102543 7f90f5ffb6c0 Level-0 table #90: started
|
2026/03/30-15:06:34.717076 7f4bd8fea6c0 Level-0 table #106: started
|
||||||
2026/03/27-21:21:32.102564 7f90f5ffb6c0 Level-0 table #90: 0 bytes OK
|
2026/03/30-15:06:34.717223 7f4bd8fea6c0 Level-0 table #106: 0 bytes OK
|
||||||
2026/03/27-21:21:32.109807 7f90f5ffb6c0 Delete type=0 #88
|
2026/03/30-15:06:34.723514 7f4bd8fea6c0 Delete type=0 #104
|
||||||
2026/03/27-21:21:32.116185 7f90f5ffb6c0 Manual compaction at level-0 from '!tables!J9VdvrwkbyKxMAT7' @ 72057594037927935 : 1 .. '!tables.results!jGKjfCyk4ROSy9fU.zRzADzATtijaBdNX' @ 0 : 0; will stop at (end)
|
2026/03/30-15:06:34.740972 7f4bd8fea6c0 Manual compaction at level-0 from '!tables!J9VdvrwkbyKxMAT7' @ 72057594037927935 : 1 .. '!tables.results!jGKjfCyk4ROSy9fU.zRzADzATtijaBdNX' @ 0 : 0; will stop at (end)
|
||||||
2026/03/27-21:21:32.123641 7f90f5ffb6c0 Manual compaction at level-1 from '!tables!J9VdvrwkbyKxMAT7' @ 72057594037927935 : 1 .. '!tables.results!jGKjfCyk4ROSy9fU.zRzADzATtijaBdNX' @ 0 : 0; will stop at (end)
|
2026/03/30-15:06:34.741010 7f4bd8fea6c0 Manual compaction at level-1 from '!tables!J9VdvrwkbyKxMAT7' @ 72057594037927935 : 1 .. '!tables.results!jGKjfCyk4ROSy9fU.zRzADzATtijaBdNX' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000072
|
MANIFEST-000088
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
2026/03/27-23:40:07.028975 7f90f7fff6c0 Recovering log #70
|
2026/03/30-15:06:44.362194 7f4bdafee6c0 Recovering log #86
|
||||||
2026/03/27-23:40:07.039557 7f90f7fff6c0 Delete type=3 #68
|
2026/03/30-15:06:44.373140 7f4bdafee6c0 Delete type=3 #84
|
||||||
2026/03/27-23:40:07.039615 7f90f7fff6c0 Delete type=0 #70
|
2026/03/30-15:06:44.373208 7f4bdafee6c0 Delete type=0 #86
|
||||||
2026/03/28-01:06:04.054602 7f90f5ffb6c0 Level-0 table #75: started
|
|
||||||
2026/03/28-01:06:04.054622 7f90f5ffb6c0 Level-0 table #75: 0 bytes OK
|
|
||||||
2026/03/28-01:06:04.060604 7f90f5ffb6c0 Delete type=0 #73
|
|
||||||
2026/03/28-01:06:04.080099 7f90f5ffb6c0 Manual compaction at level-0 from '!macros!apyHJT40enTKFUfX' @ 72057594037927935 : 1 .. '!macros!suexsLbORUfE9ptz' @ 0 : 0; will stop at (end)
|
|
||||||
2026/03/28-01:06:04.080138 7f90f5ffb6c0 Manual compaction at level-1 from '!macros!apyHJT40enTKFUfX' @ 72057594037927935 : 1 .. '!macros!suexsLbORUfE9ptz' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2026/03/27-21:21:30.304400 7f90f67fc6c0 Recovering log #66
|
2026/03/30-14:14:12.812401 7f4bdafee6c0 Recovering log #82
|
||||||
2026/03/27-21:21:30.314598 7f90f67fc6c0 Delete type=3 #64
|
2026/03/30-14:14:12.871063 7f4bdafee6c0 Delete type=3 #80
|
||||||
2026/03/27-21:21:30.314668 7f90f67fc6c0 Delete type=0 #66
|
2026/03/30-14:14:12.871115 7f4bdafee6c0 Delete type=0 #82
|
||||||
2026/03/27-21:21:32.089478 7f90f5ffb6c0 Level-0 table #71: started
|
2026/03/30-15:06:34.592601 7f4bd8fea6c0 Level-0 table #87: started
|
||||||
2026/03/27-21:21:32.089505 7f90f5ffb6c0 Level-0 table #71: 0 bytes OK
|
2026/03/30-15:06:34.592754 7f4bd8fea6c0 Level-0 table #87: 0 bytes OK
|
||||||
2026/03/27-21:21:32.095733 7f90f5ffb6c0 Delete type=0 #69
|
2026/03/30-15:06:34.600381 7f4bd8fea6c0 Delete type=0 #85
|
||||||
2026/03/27-21:21:32.116170 7f90f5ffb6c0 Manual compaction at level-0 from '!macros!apyHJT40enTKFUfX' @ 72057594037927935 : 1 .. '!macros!suexsLbORUfE9ptz' @ 0 : 0; will stop at (end)
|
2026/03/30-15:06:34.613943 7f4bd8fea6c0 Manual compaction at level-0 from '!macros!apyHJT40enTKFUfX' @ 72057594037927935 : 1 .. '!macros!suexsLbORUfE9ptz' @ 0 : 0; will stop at (end)
|
||||||
2026/03/27-21:21:32.123631 7f90f5ffb6c0 Manual compaction at level-1 from '!macros!apyHJT40enTKFUfX' @ 72057594037927935 : 1 .. '!macros!suexsLbORUfE9ptz' @ 0 : 0; will stop at (end)
|
2026/03/30-15:06:34.613995 7f4bd8fea6c0 Manual compaction at level-1 from '!macros!apyHJT40enTKFUfX' @ 72057594037927935 : 1 .. '!macros!suexsLbORUfE9ptz' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000250
|
MANIFEST-000266
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
2026/03/27-23:40:07.017004 7f90f6ffd6c0 Recovering log #248
|
2026/03/30-15:06:44.348172 7f4bda7ed6c0 Recovering log #264
|
||||||
2026/03/27-23:40:07.027187 7f90f6ffd6c0 Delete type=3 #246
|
2026/03/30-15:06:44.358939 7f4bda7ed6c0 Delete type=3 #262
|
||||||
2026/03/27-23:40:07.027254 7f90f6ffd6c0 Delete type=0 #248
|
2026/03/30-15:06:44.358996 7f4bda7ed6c0 Delete type=0 #264
|
||||||
2026/03/28-01:06:04.067738 7f90f5ffb6c0 Level-0 table #253: started
|
|
||||||
2026/03/28-01:06:04.067767 7f90f5ffb6c0 Level-0 table #253: 0 bytes OK
|
|
||||||
2026/03/28-01:06:04.073991 7f90f5ffb6c0 Delete type=0 #251
|
|
||||||
2026/03/28-01:06:04.080120 7f90f5ffb6c0 Manual compaction at level-0 from '!macros!Admg6zBHid4mfbJY' @ 72057594037927935 : 1 .. '!macros!wY3tga12higX7soz' @ 0 : 0; will stop at (end)
|
|
||||||
2026/03/28-01:06:04.080146 7f90f5ffb6c0 Manual compaction at level-1 from '!macros!Admg6zBHid4mfbJY' @ 72057594037927935 : 1 .. '!macros!wY3tga12higX7soz' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2026/03/27-21:21:30.291918 7f90f7fff6c0 Recovering log #244
|
2026/03/30-14:14:12.747731 7f4bda7ed6c0 Recovering log #260
|
||||||
2026/03/27-21:21:30.302711 7f90f7fff6c0 Delete type=3 #242
|
2026/03/30-14:14:12.800943 7f4bda7ed6c0 Delete type=3 #258
|
||||||
2026/03/27-21:21:30.302762 7f90f7fff6c0 Delete type=0 #244
|
2026/03/30-14:14:12.801033 7f4bda7ed6c0 Delete type=0 #260
|
||||||
2026/03/27-21:21:32.109958 7f90f5ffb6c0 Level-0 table #249: started
|
2026/03/30-15:06:34.614167 7f4bd8fea6c0 Level-0 table #265: started
|
||||||
2026/03/27-21:21:32.109983 7f90f5ffb6c0 Level-0 table #249: 0 bytes OK
|
2026/03/30-15:06:34.614201 7f4bd8fea6c0 Level-0 table #265: 0 bytes OK
|
||||||
2026/03/27-21:21:32.116069 7f90f5ffb6c0 Delete type=0 #247
|
2026/03/30-15:06:34.620245 7f4bd8fea6c0 Delete type=0 #263
|
||||||
2026/03/27-21:21:32.116191 7f90f5ffb6c0 Manual compaction at level-0 from '!macros!Admg6zBHid4mfbJY' @ 72057594037927935 : 1 .. '!macros!wY3tga12higX7soz' @ 0 : 0; will stop at (end)
|
2026/03/30-15:06:34.641645 7f4bd8fea6c0 Manual compaction at level-0 from '!macros!Admg6zBHid4mfbJY' @ 72057594037927935 : 1 .. '!macros!wY3tga12higX7soz' @ 0 : 0; will stop at (end)
|
||||||
2026/03/27-21:21:32.116205 7f90f5ffb6c0 Manual compaction at level-1 from '!macros!Admg6zBHid4mfbJY' @ 72057594037927935 : 1 .. '!macros!wY3tga12higX7soz' @ 0 : 0; will stop at (end)
|
2026/03/30-15:06:34.641681 7f4bd8fea6c0 Manual compaction at level-1 from '!macros!Admg6zBHid4mfbJY' @ 72057594037927935 : 1 .. '!macros!wY3tga12higX7soz' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000992
|
MANIFEST-001008
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
2026/03/27-23:40:06.964100 7f90f7fff6c0 Recovering log #990
|
2026/03/30-15:06:44.274432 7f4bdafee6c0 Recovering log #1006
|
||||||
2026/03/27-23:40:06.975062 7f90f7fff6c0 Delete type=3 #988
|
2026/03/30-15:06:44.302845 7f4bdafee6c0 Delete type=3 #1004
|
||||||
2026/03/27-23:40:06.975129 7f90f7fff6c0 Delete type=0 #990
|
2026/03/30-15:06:44.302897 7f4bdafee6c0 Delete type=0 #1006
|
||||||
2026/03/28-01:06:04.035671 7f90f5ffb6c0 Level-0 table #995: started
|
|
||||||
2026/03/28-01:06:04.035691 7f90f5ffb6c0 Level-0 table #995: 0 bytes OK
|
|
||||||
2026/03/28-01:06:04.041795 7f90f5ffb6c0 Delete type=0 #993
|
|
||||||
2026/03/28-01:06:04.054457 7f90f5ffb6c0 Manual compaction at level-0 from '!journal!OgzOugwIXfHtijaY' @ 72057594037927935 : 1 .. '!journal.pages!OgzOugwIXfHtijaY.OOev7kj2KoMOGoMD' @ 0 : 0; will stop at (end)
|
|
||||||
2026/03/28-01:06:04.054505 7f90f5ffb6c0 Manual compaction at level-1 from '!journal!OgzOugwIXfHtijaY' @ 72057594037927935 : 1 .. '!journal.pages!OgzOugwIXfHtijaY.OOev7kj2KoMOGoMD' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2026/03/27-21:21:30.242574 7f90f7fff6c0 Recovering log #986
|
2026/03/30-14:14:12.447332 7f4bdafee6c0 Recovering log #1002
|
||||||
2026/03/27-21:21:30.253063 7f90f7fff6c0 Delete type=3 #984
|
2026/03/30-14:14:12.506248 7f4bdafee6c0 Delete type=3 #1000
|
||||||
2026/03/27-21:21:30.253116 7f90f7fff6c0 Delete type=0 #986
|
2026/03/30-14:14:12.506320 7f4bdafee6c0 Delete type=0 #1002
|
||||||
2026/03/27-21:21:32.074771 7f90f5ffb6c0 Level-0 table #991: started
|
2026/03/30-15:06:34.585439 7f4bd8fea6c0 Level-0 table #1007: started
|
||||||
2026/03/27-21:21:32.074793 7f90f5ffb6c0 Level-0 table #991: 0 bytes OK
|
2026/03/30-15:06:34.585515 7f4bd8fea6c0 Level-0 table #1007: 0 bytes OK
|
||||||
2026/03/27-21:21:32.081032 7f90f5ffb6c0 Delete type=0 #989
|
2026/03/30-15:06:34.592340 7f4bd8fea6c0 Delete type=0 #1005
|
||||||
2026/03/27-21:21:32.089348 7f90f5ffb6c0 Manual compaction at level-0 from '!journal!OgzOugwIXfHtijaY' @ 72057594037927935 : 1 .. '!journal.pages!OgzOugwIXfHtijaY.OOev7kj2KoMOGoMD' @ 0 : 0; will stop at (end)
|
2026/03/30-15:06:34.613927 7f4bd8fea6c0 Manual compaction at level-0 from '!journal!OgzOugwIXfHtijaY' @ 72057594037927935 : 1 .. '!journal.pages!OgzOugwIXfHtijaY.OOev7kj2KoMOGoMD' @ 0 : 0; will stop at (end)
|
||||||
2026/03/27-21:21:32.089398 7f90f5ffb6c0 Manual compaction at level-1 from '!journal!OgzOugwIXfHtijaY' @ 72057594037927935 : 1 .. '!journal.pages!OgzOugwIXfHtijaY.OOev7kj2KoMOGoMD' @ 0 : 0; will stop at (end)
|
2026/03/30-15:06:34.613985 7f4bd8fea6c0 Manual compaction at level-1 from '!journal!OgzOugwIXfHtijaY' @ 72057594037927935 : 1 .. '!journal.pages!OgzOugwIXfHtijaY.OOev7kj2KoMOGoMD' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
@@ -3,8 +3,6 @@ export const SYSTEM_ID = "fvtt-chroniques-de-l-etrange"
|
|||||||
export const ACTOR_TYPES = {
|
export const ACTOR_TYPES = {
|
||||||
character: "character",
|
character: "character",
|
||||||
npc: "npc",
|
npc: "npc",
|
||||||
tinji: "tinji",
|
|
||||||
loksyu: "loksyu",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ITEM_TYPES = {
|
export const ITEM_TYPES = {
|
||||||
@@ -105,4 +103,6 @@ export const TEMPLATE_PARTIALS = [
|
|||||||
"systems/fvtt-chroniques-de-l-etrange/templates/actor/parts/cde-npc-spells.html",
|
"systems/fvtt-chroniques-de-l-etrange/templates/actor/parts/cde-npc-spells.html",
|
||||||
"systems/fvtt-chroniques-de-l-etrange/templates/actor/parts/cde-npc-kungfus.html",
|
"systems/fvtt-chroniques-de-l-etrange/templates/actor/parts/cde-npc-kungfus.html",
|
||||||
"systems/fvtt-chroniques-de-l-etrange/templates/actor/parts/cde-npc-items.html",
|
"systems/fvtt-chroniques-de-l-etrange/templates/actor/parts/cde-npc-items.html",
|
||||||
|
"systems/fvtt-chroniques-de-l-etrange/templates/apps/cde-loksyu-app.html",
|
||||||
|
"systems/fvtt-chroniques-de-l-etrange/templates/apps/cde-tinji-app.html",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,4 +1,2 @@
|
|||||||
export { default as CharacterDataModel } from "./character.js"
|
export { default as CharacterDataModel } from "./character.js"
|
||||||
export { default as NpcDataModel } from "./npc.js"
|
export { default as NpcDataModel } from "./npc.js"
|
||||||
export { default as TinjiDataModel } from "./tinji.js"
|
|
||||||
export { default as LoksyuDataModel } from "./loksyu.js"
|
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
export default class LoksyuDataModel extends foundry.abstract.TypeDataModel {
|
|
||||||
static defineSchema() {
|
|
||||||
const { fields } = foundry.data
|
|
||||||
const numberField = (initial = 0, extra = {}) => new fields.NumberField({ required: true, nullable: false, integer: true, initial, ...extra })
|
|
||||||
const htmlField = (initial = "") => new fields.HTMLField({ required: true, nullable: false, initial, textSearch: true })
|
|
||||||
|
|
||||||
const polarity = () =>
|
|
||||||
new fields.SchemaField({
|
|
||||||
yin: new fields.SchemaField({ value: numberField(0, { min: 0 }) }),
|
|
||||||
yang: new fields.SchemaField({ value: numberField(0, { min: 0 }) }),
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
|
||||||
fire: polarity(),
|
|
||||||
earth: polarity(),
|
|
||||||
metal: polarity(),
|
|
||||||
water: polarity(),
|
|
||||||
wood: polarity(),
|
|
||||||
description: htmlField(""),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
export default class TinjiDataModel extends foundry.abstract.TypeDataModel {
|
|
||||||
static defineSchema() {
|
|
||||||
const { fields } = foundry.data
|
|
||||||
const numberField = (initial = 0, extra = {}) => new fields.NumberField({ required: true, nullable: false, integer: true, initial, ...extra })
|
|
||||||
const htmlField = (initial = "") => new fields.HTMLField({ required: true, nullable: false, initial, textSearch: true })
|
|
||||||
|
|
||||||
return {
|
|
||||||
value: numberField(0, { min: 0 }),
|
|
||||||
description: htmlField(""),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,10 +10,24 @@ export function registerSettings() {
|
|||||||
type: String,
|
type: String,
|
||||||
default: "0.0.0",
|
default: "0.0.0",
|
||||||
})
|
})
|
||||||
|
game.settings.register(SYSTEM_ID, "loksyuData", {
|
||||||
|
name: "Loksyu Data",
|
||||||
|
scope: "world",
|
||||||
|
config: false,
|
||||||
|
type: Object,
|
||||||
|
default: { wood: {yin:0,yang:0}, fire: {yin:0,yang:0}, earth: {yin:0,yang:0}, metal: {yin:0,yang:0}, water: {yin:0,yang:0} },
|
||||||
|
})
|
||||||
|
game.settings.register(SYSTEM_ID, "tinjiData", {
|
||||||
|
name: "TinJi Data",
|
||||||
|
scope: "world",
|
||||||
|
config: false,
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function migrateIfNeeded() {
|
export async function migrateIfNeeded() {
|
||||||
const current = game.system.version ?? MIGRATION_VERSION
|
const current = MIGRATION_VERSION
|
||||||
const stored = game.settings.get(SYSTEM_ID, "migrationVersion") ?? "0.0.0"
|
const stored = game.settings.get(SYSTEM_ID, "migrationVersion") ?? "0.0.0"
|
||||||
if (!foundry.utils.isNewerVersion(current, stored)) return
|
if (!foundry.utils.isNewerVersion(current, stored)) return
|
||||||
|
|
||||||
@@ -31,7 +45,7 @@ async function migrateActors() {
|
|||||||
for (const actor of game.actors.contents) {
|
for (const actor of game.actors.contents) {
|
||||||
const updateData = migrateActorData(actor)
|
const updateData = migrateActorData(actor)
|
||||||
if (Object.keys(updateData).length > 0) {
|
if (Object.keys(updateData).length > 0) {
|
||||||
updates.push(actor.update(updateData, { enforceTypes: false }))
|
updates.push(actor.update(updateData))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await Promise.all(updates)
|
await Promise.all(updates)
|
||||||
@@ -44,7 +58,7 @@ async function migrateCompendiumActors() {
|
|||||||
for (const actor of content) {
|
for (const actor of content) {
|
||||||
const updateData = migrateActorData(actor)
|
const updateData = migrateActorData(actor)
|
||||||
if (Object.keys(updateData).length > 0) {
|
if (Object.keys(updateData).length > 0) {
|
||||||
await actor.update(updateData, { pack: pack.collection, enforceTypes: false })
|
await actor.update(updateData, { pack: pack.collection })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,7 +69,7 @@ async function migrateItems() {
|
|||||||
for (const item of game.items.contents) {
|
for (const item of game.items.contents) {
|
||||||
const updateData = migrateItemData(item)
|
const updateData = migrateItemData(item)
|
||||||
if (Object.keys(updateData).length > 0) {
|
if (Object.keys(updateData).length > 0) {
|
||||||
updates.push(item.update(updateData, { enforceTypes: false }))
|
updates.push(item.update(updateData))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await Promise.all(updates)
|
await Promise.all(updates)
|
||||||
@@ -68,7 +82,7 @@ async function migrateCompendiumItems() {
|
|||||||
for (const item of content) {
|
for (const item of content) {
|
||||||
const updateData = migrateItemData(item)
|
const updateData = migrateItemData(item)
|
||||||
if (Object.keys(updateData).length > 0) {
|
if (Object.keys(updateData).length > 0) {
|
||||||
await item.update(updateData, { pack: pack.collection, enforceTypes: false })
|
await item.update(updateData, { pack: pack.collection })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -119,7 +133,14 @@ function migrateItemData(item) {
|
|||||||
const updateData = {}
|
const updateData = {}
|
||||||
const system = item.system ?? {}
|
const system = item.system ?? {}
|
||||||
|
|
||||||
// Add item-specific migrations here as needed
|
// Normalize legacy French damageAspect values to English keys
|
||||||
|
if (item.type === "weapon") {
|
||||||
|
const ASPECT_FR_TO_EN = { eau: "water", terre: "earth", feu: "fire", bois: "wood" }
|
||||||
|
const normalized = ASPECT_FR_TO_EN[system.damageAspect]
|
||||||
|
if (normalized) {
|
||||||
|
updateData["system.damageAspect"] = normalized
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return updateData
|
return updateData
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ACTOR_TYPES, ITEM_TYPES, MAGICS, SUBTYPES, SYSTEM_ID } from "./config/constants.js"
|
import { ACTOR_TYPES, ITEM_TYPES, MAGICS, SUBTYPES, SYSTEM_ID } from "./config/constants.js"
|
||||||
import { preLocalizeConfig } from "./config/localize.js"
|
import { preLocalizeConfig } from "./config/localize.js"
|
||||||
import { configureRuntime } from "./config/runtime.js"
|
import { configureRuntime } from "./config/runtime.js"
|
||||||
import { CharacterDataModel, LoksyuDataModel, NpcDataModel, TinjiDataModel } from "./data/actors/index.js"
|
import { CharacterDataModel, NpcDataModel } from "./data/actors/index.js"
|
||||||
import { EquipmentDataModel, KungfuDataModel, SpellDataModel, SupernaturalDataModel, WeaponDataModel, ArmorDataModel, SanheiDataModel, IngredientDataModel } from "./data/items/index.js"
|
import { EquipmentDataModel, KungfuDataModel, SpellDataModel, SupernaturalDataModel, WeaponDataModel, ArmorDataModel, SanheiDataModel, IngredientDataModel } from "./data/items/index.js"
|
||||||
import { CDEMessage } from "./documents/chat-message.js"
|
import { CDEMessage } from "./documents/chat-message.js"
|
||||||
import { CDEActor } from "./documents/actor.js"
|
import { CDEActor } from "./documents/actor.js"
|
||||||
@@ -9,9 +9,12 @@ import { CDEItem } from "./documents/item.js"
|
|||||||
import { registerDice } from "./ui/dice.js"
|
import { registerDice } from "./ui/dice.js"
|
||||||
import { registerHandlebarsHelpers } from "./ui/helpers.js"
|
import { registerHandlebarsHelpers } from "./ui/helpers.js"
|
||||||
import { preloadPartials } from "./ui/templates.js"
|
import { preloadPartials } from "./ui/templates.js"
|
||||||
import { CDELoksyuSheet, CDECharacterSheet, CDENpcSheet, CDETinjiSheet } from "./ui/sheets/actors/index.js"
|
import { CDECharacterSheet, CDENpcSheet } from "./ui/sheets/actors/index.js"
|
||||||
import { CDEItemSheet, CDEKungfuSheet, CDESpellSheet, CDESupernaturalSheet, CDEWeaponSheet, CDEArmorSheet, CDESanheiSheet, CDEIngredientSheet } from "./ui/sheets/items/index.js"
|
import { CDEItemSheet, CDEKungfuSheet, CDESpellSheet, CDESupernaturalSheet, CDEWeaponSheet, CDEArmorSheet, CDESanheiSheet, CDEIngredientSheet } from "./ui/sheets/items/index.js"
|
||||||
|
import { CDELoksyuApp } from "./ui/apps/loksyu-app.js"
|
||||||
|
import { CDETinjiApp } from "./ui/apps/tinji-app.js"
|
||||||
import { migrateIfNeeded, registerSettings } from "./migration.js"
|
import { migrateIfNeeded, registerSettings } from "./migration.js"
|
||||||
|
import { injectRollActions, refreshAllRollActions } from "./ui/roll-actions.js"
|
||||||
|
|
||||||
Hooks.once("i18nInit", preLocalizeConfig)
|
Hooks.once("i18nInit", preLocalizeConfig)
|
||||||
|
|
||||||
@@ -22,11 +25,12 @@ Hooks.once("init", async () => {
|
|||||||
|
|
||||||
game.system.CONST = { MAGICS, SUBTYPES }
|
game.system.CONST = { MAGICS, SUBTYPES }
|
||||||
|
|
||||||
|
// Expose standalone apps globally for macros
|
||||||
|
game.cde = { CDELoksyuApp, CDETinjiApp }
|
||||||
|
|
||||||
CONFIG.Actor.dataModels = {
|
CONFIG.Actor.dataModels = {
|
||||||
[ACTOR_TYPES.character]: CharacterDataModel,
|
[ACTOR_TYPES.character]: CharacterDataModel,
|
||||||
[ACTOR_TYPES.npc]: NpcDataModel,
|
[ACTOR_TYPES.npc]: NpcDataModel,
|
||||||
[ACTOR_TYPES.tinji]: TinjiDataModel,
|
|
||||||
[ACTOR_TYPES.loksyu]: LoksyuDataModel,
|
|
||||||
}
|
}
|
||||||
CONFIG.Item.dataModels = {
|
CONFIG.Item.dataModels = {
|
||||||
[ITEM_TYPES.item]: EquipmentDataModel,
|
[ITEM_TYPES.item]: EquipmentDataModel,
|
||||||
@@ -45,8 +49,8 @@ Hooks.once("init", async () => {
|
|||||||
|
|
||||||
configureRuntime()
|
configureRuntime()
|
||||||
|
|
||||||
foundry.applications.apps.DocumentSheetConfig.unregisterSheet(Actor, "core", ActorSheet)
|
foundry.applications.apps.DocumentSheetConfig.unregisterSheet(Actor, "core", foundry.appv1.sheets.ActorSheet)
|
||||||
foundry.applications.apps.DocumentSheetConfig.unregisterSheet(Item, "core", ItemSheet)
|
foundry.applications.apps.DocumentSheetConfig.unregisterSheet(Item, "core", foundry.appv1.sheets.ItemSheet)
|
||||||
|
|
||||||
foundry.applications.apps.DocumentSheetConfig.registerSheet(Actor, SYSTEM_ID, CDECharacterSheet, {
|
foundry.applications.apps.DocumentSheetConfig.registerSheet(Actor, SYSTEM_ID, CDECharacterSheet, {
|
||||||
types: [ACTOR_TYPES.character],
|
types: [ACTOR_TYPES.character],
|
||||||
@@ -58,16 +62,6 @@ Hooks.once("init", async () => {
|
|||||||
makeDefault: true,
|
makeDefault: true,
|
||||||
label: "CDE NPC Sheet (V2)",
|
label: "CDE NPC Sheet (V2)",
|
||||||
})
|
})
|
||||||
foundry.applications.apps.DocumentSheetConfig.registerSheet(Actor, SYSTEM_ID, CDETinjiSheet, {
|
|
||||||
types: [ACTOR_TYPES.tinji],
|
|
||||||
makeDefault: true,
|
|
||||||
label: "CDE Tinji Sheet (V2)",
|
|
||||||
})
|
|
||||||
foundry.applications.apps.DocumentSheetConfig.registerSheet(Actor, SYSTEM_ID, CDELoksyuSheet, {
|
|
||||||
types: [ACTOR_TYPES.loksyu],
|
|
||||||
makeDefault: true,
|
|
||||||
label: "CDE Loksyu Sheet (V2)",
|
|
||||||
})
|
|
||||||
|
|
||||||
foundry.applications.apps.DocumentSheetConfig.registerSheet(Item, SYSTEM_ID, CDEItemSheet, {
|
foundry.applications.apps.DocumentSheetConfig.registerSheet(Item, SYSTEM_ID, CDEItemSheet, {
|
||||||
types: [ITEM_TYPES.item],
|
types: [ITEM_TYPES.item],
|
||||||
@@ -119,12 +113,55 @@ Hooks.once("init", async () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
Hooks.once("ready", async () => {
|
Hooks.once("ready", async () => {
|
||||||
if (!game.modules.get("lib-wrapper")?.active && game.user.isGM) {
|
|
||||||
ui.notifications.error("System fvtt-chroniques-de-l-etrange requires the 'libWrapper' module. Please install and activate it.")
|
|
||||||
}
|
|
||||||
await migrateIfNeeded()
|
await migrateIfNeeded()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/** Add Loksyu + Tin Ji quick-access buttons to the chat panel (FoundryVTT v13) */
|
||||||
|
Hooks.on("renderChatLog", (_app, html) => {
|
||||||
|
const el = html instanceof HTMLElement ? html : (html[0] ?? html)
|
||||||
|
if (!el?.querySelector) return
|
||||||
|
|
||||||
|
// Avoid double-injection on re-renders
|
||||||
|
if (el.querySelector(".cde-chat-app-buttons")) return
|
||||||
|
|
||||||
|
const wrapper = document.createElement("div")
|
||||||
|
wrapper.classList.add("cde-chat-app-buttons")
|
||||||
|
wrapper.innerHTML = `
|
||||||
|
<button type="button" class="cde-chat-btn cde-chat-btn--loksyu">
|
||||||
|
<i class="fas fa-yin-yang"></i> ${game.i18n.localize("CDE.Loksyu")}
|
||||||
|
</button>
|
||||||
|
<button type="button" class="cde-chat-btn cde-chat-btn--tinji">
|
||||||
|
<i class="fas fa-star"></i> ${game.i18n.localize("CDE.TinJi2")}
|
||||||
|
</button>
|
||||||
|
`
|
||||||
|
|
||||||
|
// Use event delegation to avoid being swallowed by Foundry's own handlers
|
||||||
|
wrapper.addEventListener("click", (ev) => {
|
||||||
|
if (ev.target.closest(".cde-chat-btn--loksyu")) CDELoksyuApp.open()
|
||||||
|
if (ev.target.closest(".cde-chat-btn--tinji")) CDETinjiApp.open()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Insert before the chat form — works on v12 and v13
|
||||||
|
const anchor = el.querySelector(".chat-form")
|
||||||
|
?? el.querySelector(".chat-message-form")
|
||||||
|
?? el.querySelector("form")
|
||||||
|
if (anchor) anchor.parentElement.insertBefore(wrapper, anchor)
|
||||||
|
else el.appendChild(wrapper)
|
||||||
|
})
|
||||||
|
|
||||||
|
/** Inject Loksyu / TinJi action buttons into roll-result chat messages */
|
||||||
|
Hooks.on("renderChatMessageHTML", (message, html) => {
|
||||||
|
injectRollActions(message, html)
|
||||||
|
})
|
||||||
|
|
||||||
|
/** Refresh all visible roll-result buttons whenever Loksyu or TinJi settings change */
|
||||||
|
Hooks.on("updateSetting", setting => {
|
||||||
|
if (!setting.key) return
|
||||||
|
if (setting.key.includes("loksyuData") || setting.key.includes("tinjiData")) {
|
||||||
|
refreshAllRollActions()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
function injectCompendiumLink(html) {
|
function injectCompendiumLink(html) {
|
||||||
const header = html[0]?.querySelector?.("h4.divider")
|
const header = html[0]?.querySelector?.("h4.divider")
|
||||||
if (!header) return
|
if (!header) return
|
||||||
@@ -149,7 +186,7 @@ function injectCompendiumLink(html) {
|
|||||||
</section>
|
</section>
|
||||||
`
|
`
|
||||||
section.querySelector("button[data-action='open-cde-link']")?.addEventListener("click", () => {
|
section.querySelector("button[data-action='open-cde-link']")?.addEventListener("click", () => {
|
||||||
window.open("https://antre-monde.com/les-chroniques-de-letrengae/", "_blank")
|
window.open("https://antre-monde.com/les-chroniques-de-letrange/", "_blank")
|
||||||
})
|
})
|
||||||
|
|
||||||
header.parentNode.insertBefore(section, header)
|
header.parentNode.insertBefore(section, header)
|
||||||
|
|||||||
3
src/ui/apps/index.js
Normal file
3
src/ui/apps/index.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export { CDELoksyuApp } from "./loksyu-app.js"
|
||||||
|
export { CDETinjiApp } from "./tinji-app.js"
|
||||||
|
export { getSingletonActor, updateLoksyuFromRoll, updateTinjiFromRoll } from "./singletons.js"
|
||||||
112
src/ui/apps/loksyu-app.js
Normal file
112
src/ui/apps/loksyu-app.js
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
import { getLoksyuData, setLoksyuData } from "./singletons.js"
|
||||||
|
|
||||||
|
const SYSTEM_ID = "fvtt-chroniques-de-l-etrange"
|
||||||
|
|
||||||
|
export class CDELoksyuApp extends foundry.applications.api.HandlebarsApplicationMixin(
|
||||||
|
foundry.applications.api.ApplicationV2
|
||||||
|
) {
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
id: "cde-loksyu-app",
|
||||||
|
tag: "div",
|
||||||
|
window: {
|
||||||
|
title: "CDE.Loksyu",
|
||||||
|
icon: "fas fa-yin-yang",
|
||||||
|
resizable: false,
|
||||||
|
},
|
||||||
|
classes: ["cde-app", "cde-loksyu-standalone"],
|
||||||
|
position: { width: 520, height: "auto" },
|
||||||
|
actions: {
|
||||||
|
resetElement: CDELoksyuApp.#onResetElement,
|
||||||
|
resetAll: CDELoksyuApp.#onResetAll,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
static PARTS = {
|
||||||
|
main: {
|
||||||
|
template: `systems/${SYSTEM_ID}/templates/apps/cde-loksyu-app.html`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {Function|null} bound hook handler */
|
||||||
|
_updateHook = null
|
||||||
|
|
||||||
|
/** Singleton accessor — open or bring to front */
|
||||||
|
static open() {
|
||||||
|
const existing = Array.from(foundry.applications.instances.values()).find(
|
||||||
|
(app) => app instanceof CDELoksyuApp
|
||||||
|
)
|
||||||
|
if (existing) { existing.bringToFront(); return existing }
|
||||||
|
const app = new CDELoksyuApp()
|
||||||
|
app.render(true)
|
||||||
|
return app
|
||||||
|
}
|
||||||
|
|
||||||
|
async _prepareContext() {
|
||||||
|
const sys = getLoksyuData()
|
||||||
|
const ELEMENTS = [
|
||||||
|
{ key: "wood", nameKey: "CDE.Wood", qualKey: "CDE.WoodQualities", img: `systems/${SYSTEM_ID}/images/cde_bois.webp` },
|
||||||
|
{ key: "fire", nameKey: "CDE.Fire", qualKey: "CDE.FireQualities", img: `systems/${SYSTEM_ID}/images/cde_feu.webp` },
|
||||||
|
{ key: "earth", nameKey: "CDE.Earth", qualKey: "CDE.EarthQualities", img: `systems/${SYSTEM_ID}/images/cde_terre.webp` },
|
||||||
|
{ key: "metal", nameKey: "CDE.Metal", qualKey: "CDE.MetalQualities", img: `systems/${SYSTEM_ID}/images/cde_metal.webp` },
|
||||||
|
{ key: "water", nameKey: "CDE.Water", qualKey: "CDE.WaterQualities", img: `systems/${SYSTEM_ID}/images/cde_eau.webp` },
|
||||||
|
]
|
||||||
|
|
||||||
|
return {
|
||||||
|
canEdit: game.user.isGM,
|
||||||
|
elements: ELEMENTS.map((el) => ({
|
||||||
|
...el,
|
||||||
|
yang: sys[el.key]?.yang ?? 0,
|
||||||
|
yin: sys[el.key]?.yin ?? 0,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_onRender(context, options) {
|
||||||
|
super._onRender(context, options)
|
||||||
|
this.#bindInputs()
|
||||||
|
|
||||||
|
this._updateHook = Hooks.on("cde:loksyuUpdated", () => this.render())
|
||||||
|
}
|
||||||
|
|
||||||
|
_onClose(options) {
|
||||||
|
if (this._updateHook !== null) {
|
||||||
|
Hooks.off("cde:loksyuUpdated", this._updateHook)
|
||||||
|
this._updateHook = null
|
||||||
|
}
|
||||||
|
super._onClose(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
#bindInputs() {
|
||||||
|
const inputs = this.element?.querySelectorAll("input[data-field]")
|
||||||
|
if (!inputs?.length) return
|
||||||
|
inputs.forEach((input) => {
|
||||||
|
input.addEventListener("change", async (ev) => {
|
||||||
|
const field = ev.currentTarget.dataset.field
|
||||||
|
const val = parseInt(ev.currentTarget.value, 10)
|
||||||
|
if (!field || isNaN(val)) return
|
||||||
|
// field is like "wood.yin" or "fire.yang"
|
||||||
|
const [aspect, dim] = field.split(".")
|
||||||
|
if (!aspect || !dim) return
|
||||||
|
const data = getLoksyuData()
|
||||||
|
if (!data[aspect]) data[aspect] = { yin: 0, yang: 0 }
|
||||||
|
data[aspect][dim] = Math.max(0, val)
|
||||||
|
await setLoksyuData(data)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #onResetElement(event, target) {
|
||||||
|
const key = target.dataset.element
|
||||||
|
if (!key) return
|
||||||
|
const data = getLoksyuData()
|
||||||
|
data[key] = { yin: 0, yang: 0 }
|
||||||
|
await setLoksyuData(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #onResetAll(_event, _target) {
|
||||||
|
const KEYS = ["wood", "fire", "earth", "metal", "water"]
|
||||||
|
const data = getLoksyuData()
|
||||||
|
for (const k of KEYS) data[k] = { yin: 0, yang: 0 }
|
||||||
|
await setLoksyuData(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
87
src/ui/apps/singletons.js
Normal file
87
src/ui/apps/singletons.js
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
/**
|
||||||
|
* Loksyu / TinJi settings-based helpers.
|
||||||
|
*
|
||||||
|
* Data is stored as world settings instead of singleton Actor documents.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const SYSTEM_ID = "fvtt-chroniques-de-l-etrange"
|
||||||
|
|
||||||
|
/** Wu Xing generating cycle — [successes, auspicious, noxious, loksyu, tinji] */
|
||||||
|
const WU_XING_CYCLE = {
|
||||||
|
wood: ["wood", "fire", "water", "earth", "metal"],
|
||||||
|
fire: ["fire", "earth", "wood", "metal", "water"],
|
||||||
|
earth: ["earth", "metal", "fire", "water", "wood"],
|
||||||
|
metal: ["metal", "water", "earth", "wood", "fire"],
|
||||||
|
water: ["water", "wood", "metal", "fire", "earth"],
|
||||||
|
}
|
||||||
|
|
||||||
|
const ASPECT_FACES = {
|
||||||
|
metal: [3, 8],
|
||||||
|
water: [1, 6],
|
||||||
|
earth: [0, 5],
|
||||||
|
fire: [2, 7],
|
||||||
|
wood: [4, 9],
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Read the current loksyu data object from world settings */
|
||||||
|
export function getLoksyuData() {
|
||||||
|
return game.settings.get(SYSTEM_ID, "loksyuData") ?? {
|
||||||
|
wood: {yin:0,yang:0}, fire: {yin:0,yang:0}, earth: {yin:0,yang:0}, metal: {yin:0,yang:0}, water: {yin:0,yang:0},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Write the loksyu data object to world settings */
|
||||||
|
export async function setLoksyuData(data) {
|
||||||
|
await game.settings.set(SYSTEM_ID, "loksyuData", data)
|
||||||
|
Hooks.callAll("cde:loksyuUpdated", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Read current TinJi value from world settings */
|
||||||
|
export function getTinjiValue() {
|
||||||
|
return game.settings.get(SYSTEM_ID, "tinjiData") ?? 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Write TinJi value to world settings */
|
||||||
|
export async function setTinjiValue(value) {
|
||||||
|
await game.settings.set(SYSTEM_ID, "tinjiData", Math.max(0, value))
|
||||||
|
Hooks.callAll("cde:tinjiUpdated", Math.max(0, value))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After a WuXing roll, add the loksyu faces (yin + yang) of the relevant
|
||||||
|
* aspect to the loksyu settings data.
|
||||||
|
*
|
||||||
|
* @param {string} activeAspect - e.g. "fire"
|
||||||
|
* @param {Object} faces - Die face counts { 0: n, 1: n, …, 9: n }
|
||||||
|
*/
|
||||||
|
export async function updateLoksyuFromRoll(activeAspect, faces) {
|
||||||
|
const cycle = WU_XING_CYCLE[activeAspect]
|
||||||
|
if (!cycle) return
|
||||||
|
|
||||||
|
const lokAspect = cycle[3]
|
||||||
|
const [yinFace, yangFace] = ASPECT_FACES[lokAspect] ?? []
|
||||||
|
if (yinFace === undefined) return
|
||||||
|
|
||||||
|
const yinCount = faces[yinFace] ?? 0
|
||||||
|
const yangCount = faces[yangFace] ?? 0
|
||||||
|
if (yinCount === 0 && yangCount === 0) return
|
||||||
|
|
||||||
|
const data = getLoksyuData()
|
||||||
|
const current = data[lokAspect] ?? { yin: 0, yang: 0 }
|
||||||
|
data[lokAspect] = {
|
||||||
|
yin: (current.yin ?? 0) + yinCount,
|
||||||
|
yang: (current.yang ?? 0) + yangCount,
|
||||||
|
}
|
||||||
|
await setLoksyuData(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After a WuXing roll, add tinji faces to the TinJi settings.
|
||||||
|
*
|
||||||
|
* @param {number} count - Number of tinji faces rolled
|
||||||
|
*/
|
||||||
|
export async function updateTinjiFromRoll(count) {
|
||||||
|
if (!count || count <= 0) return
|
||||||
|
const current = getTinjiValue()
|
||||||
|
await setTinjiValue(current + count)
|
||||||
|
}
|
||||||
106
src/ui/apps/tinji-app.js
Normal file
106
src/ui/apps/tinji-app.js
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
import { getTinjiValue, setTinjiValue } from "./singletons.js"
|
||||||
|
|
||||||
|
const SYSTEM_ID = "fvtt-chroniques-de-l-etrange"
|
||||||
|
|
||||||
|
export class CDETinjiApp extends foundry.applications.api.HandlebarsApplicationMixin(
|
||||||
|
foundry.applications.api.ApplicationV2
|
||||||
|
) {
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
id: "cde-tinji-app",
|
||||||
|
tag: "div",
|
||||||
|
window: {
|
||||||
|
title: "CDE.TinJi2",
|
||||||
|
icon: "fas fa-star",
|
||||||
|
resizable: false,
|
||||||
|
},
|
||||||
|
classes: ["cde-app", "cde-tinji-standalone"],
|
||||||
|
position: { width: 320, height: "auto" },
|
||||||
|
actions: {
|
||||||
|
increment: CDETinjiApp.#onIncrement,
|
||||||
|
decrement: CDETinjiApp.#onDecrement,
|
||||||
|
reset: CDETinjiApp.#onReset,
|
||||||
|
spend: CDETinjiApp.#onSpend,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
static PARTS = {
|
||||||
|
main: {
|
||||||
|
template: `systems/${SYSTEM_ID}/templates/apps/cde-tinji-app.html`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {Function|null} */
|
||||||
|
_updateHook = null
|
||||||
|
|
||||||
|
static open() {
|
||||||
|
const existing = Array.from(foundry.applications.instances.values()).find(
|
||||||
|
(app) => app instanceof CDETinjiApp
|
||||||
|
)
|
||||||
|
if (existing) { existing.bringToFront(); return existing }
|
||||||
|
const app = new CDETinjiApp()
|
||||||
|
app.render(true)
|
||||||
|
return app
|
||||||
|
}
|
||||||
|
|
||||||
|
async _prepareContext() {
|
||||||
|
return {
|
||||||
|
canEdit: game.user.isGM,
|
||||||
|
value: getTinjiValue(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_onRender(context, options) {
|
||||||
|
super._onRender(context, options)
|
||||||
|
this.#bindDirectInput()
|
||||||
|
this._updateHook = Hooks.on("cde:tinjiUpdated", () => this.render())
|
||||||
|
}
|
||||||
|
|
||||||
|
_onClose(options) {
|
||||||
|
if (this._updateHook !== null) {
|
||||||
|
Hooks.off("cde:tinjiUpdated", this._updateHook)
|
||||||
|
this._updateHook = null
|
||||||
|
}
|
||||||
|
super._onClose(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
#bindDirectInput() {
|
||||||
|
const input = this.element?.querySelector("input.cde-tinji-direct")
|
||||||
|
if (!input) return
|
||||||
|
input.addEventListener("change", async (ev) => {
|
||||||
|
const val = parseInt(ev.currentTarget.value, 10)
|
||||||
|
if (!isNaN(val)) await setTinjiValue(val)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #onIncrement() {
|
||||||
|
await setTinjiValue(getTinjiValue() + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #onDecrement() {
|
||||||
|
const current = getTinjiValue()
|
||||||
|
if (current <= 0) return
|
||||||
|
await setTinjiValue(current - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #onReset() {
|
||||||
|
await setTinjiValue(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #onSpend() {
|
||||||
|
const current = getTinjiValue()
|
||||||
|
if (current <= 0) {
|
||||||
|
ui.notifications.warn(game.i18n.localize("CDE.TinjiEmpty"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await setTinjiValue(current - 1)
|
||||||
|
ChatMessage.create({
|
||||||
|
user: game.user.id,
|
||||||
|
content: `<div class="cde-tinji-spend-msg">
|
||||||
|
<i class="fas fa-star"></i>
|
||||||
|
<strong>${game.i18n.localize("CDE.TinJi2")}</strong>
|
||||||
|
${game.i18n.format("CDE.TinjiSpent", { name: game.user.name })}
|
||||||
|
<span class="cde-tinji-remain">(${current - 1} ${game.i18n.localize("CDE.TinjiRemaining")})</span>
|
||||||
|
</div>`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -61,6 +61,11 @@ export function registerHandlebarsHelpers() {
|
|||||||
Handlebars.registerHelper("getElementIcon", function (aspect) {
|
Handlebars.registerHelper("getElementIcon", function (aspect) {
|
||||||
const icons = {
|
const icons = {
|
||||||
metal: "/systems/fvtt-chroniques-de-l-etrange/images/cde_metal.webp",
|
metal: "/systems/fvtt-chroniques-de-l-etrange/images/cde_metal.webp",
|
||||||
|
water: "/systems/fvtt-chroniques-de-l-etrange/images/cde_eau.webp",
|
||||||
|
earth: "/systems/fvtt-chroniques-de-l-etrange/images/cde_terre.webp",
|
||||||
|
fire: "/systems/fvtt-chroniques-de-l-etrange/images/cde_feu.webp",
|
||||||
|
wood: "/systems/fvtt-chroniques-de-l-etrange/images/cde_bois.webp",
|
||||||
|
// legacy French keys
|
||||||
eau: "/systems/fvtt-chroniques-de-l-etrange/images/cde_eau.webp",
|
eau: "/systems/fvtt-chroniques-de-l-etrange/images/cde_eau.webp",
|
||||||
terre: "/systems/fvtt-chroniques-de-l-etrange/images/cde_terre.webp",
|
terre: "/systems/fvtt-chroniques-de-l-etrange/images/cde_terre.webp",
|
||||||
feu: "/systems/fvtt-chroniques-de-l-etrange/images/cde_feu.webp",
|
feu: "/systems/fvtt-chroniques-de-l-etrange/images/cde_feu.webp",
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ function buildNPCOptions(sys) {
|
|||||||
function readInitFields(dialog) {
|
function readInitFields(dialog) {
|
||||||
const root = dialog.element ?? dialog
|
const root = dialog.element ?? dialog
|
||||||
const selectedKey = root.querySelector("select[name='firstaction']")?.value ?? ""
|
const selectedKey = root.querySelector("select[name='firstaction']")?.value ?? ""
|
||||||
const modifier = parseInt(root.querySelector("input[name='modifier']")?.value ?? 0) || 0
|
const modifier = parseInt(root.querySelector("input[name='modifier']")?.value ?? "0", 10) || 0
|
||||||
return { selectedKey, modifier }
|
return { selectedKey, modifier }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
236
src/ui/roll-actions.js
Normal file
236
src/ui/roll-actions.js
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
/**
|
||||||
|
* Post-roll interactive action buttons injected into dice result chat messages.
|
||||||
|
* Allows players to pull dice from the Loksyu (as Successes or dés-fastes)
|
||||||
|
* and allows the GM to spend Tin Ji to intervene.
|
||||||
|
*
|
||||||
|
* After a draw, the originating roll result message is updated in-place
|
||||||
|
* with the new counts, without creating noise.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { getLoksyuData, setLoksyuData, getTinjiValue, setTinjiValue } from "./apps/singletons.js"
|
||||||
|
|
||||||
|
const SYSTEM_ID = "fvtt-chroniques-de-l-etrange"
|
||||||
|
const RESULT_TEMPLATE = "systems/fvtt-chroniques-de-l-etrange/templates/form/cde-dice-result.html"
|
||||||
|
|
||||||
|
const WU_XING_CYCLE = {
|
||||||
|
wood: ["wood", "fire", "water", "earth", "metal"],
|
||||||
|
fire: ["fire", "earth", "wood", "metal", "water"],
|
||||||
|
earth: ["earth", "metal", "fire", "water", "wood"],
|
||||||
|
metal: ["metal", "water", "earth", "wood", "fire"],
|
||||||
|
water: ["water", "wood", "metal", "fire", "earth"],
|
||||||
|
}
|
||||||
|
|
||||||
|
const ASPECT_LABELS = {
|
||||||
|
metal: "CDE.Metal",
|
||||||
|
water: "CDE.Water",
|
||||||
|
earth: "CDE.Earth",
|
||||||
|
fire: "CDE.Fire",
|
||||||
|
wood: "CDE.Wood",
|
||||||
|
}
|
||||||
|
|
||||||
|
const ASPECT_ICONS = {
|
||||||
|
metal: "systems/fvtt-chroniques-de-l-etrange/images/cde_metal.webp",
|
||||||
|
water: "systems/fvtt-chroniques-de-l-etrange/images/cde_eau.webp",
|
||||||
|
earth: "systems/fvtt-chroniques-de-l-etrange/images/cde_terre.webp",
|
||||||
|
fire: "systems/fvtt-chroniques-de-l-etrange/images/cde_feu.webp",
|
||||||
|
wood: "systems/fvtt-chroniques-de-l-etrange/images/cde_bois.webp",
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject or refresh post-roll action buttons in the given chat message HTML element.
|
||||||
|
* Called from renderChatMessageHTML hook.
|
||||||
|
* @param {ChatMessage} message
|
||||||
|
* @param {HTMLElement} html - the chat message HTML element (li.chat-message)
|
||||||
|
*/
|
||||||
|
export function injectRollActions(message, html) {
|
||||||
|
const rollCard = html.querySelector(".cde-roll-result")
|
||||||
|
if (!rollCard) return
|
||||||
|
const aspect = rollCard.dataset.aspect
|
||||||
|
if (!aspect || !WU_XING_CYCLE[aspect]) return
|
||||||
|
refreshRollActions(rollCard, aspect, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-render the action buttons section based on current Loksyu / TinJi state.
|
||||||
|
*/
|
||||||
|
function refreshRollActions(rollCard, aspect, message) {
|
||||||
|
rollCard.querySelector(".cde-roll-actions")?.remove()
|
||||||
|
|
||||||
|
const cycle = WU_XING_CYCLE[aspect]
|
||||||
|
const fasteAspect = cycle[1]
|
||||||
|
|
||||||
|
const loksyu = getLoksyuData()
|
||||||
|
const tinji = getTinjiValue()
|
||||||
|
|
||||||
|
const successAvail = (loksyu[aspect]?.yin ?? 0) + (loksyu[aspect]?.yang ?? 0)
|
||||||
|
const fasteAvail = (loksyu[fasteAspect]?.yin ?? 0) + (loksyu[fasteAspect]?.yang ?? 0)
|
||||||
|
const isGM = game.user.isGM
|
||||||
|
|
||||||
|
const hasSomething = successAvail > 0 || fasteAvail > 0 || (isGM && tinji > 0)
|
||||||
|
if (!hasSomething) return
|
||||||
|
|
||||||
|
const aspLabel = game.i18n.localize(ASPECT_LABELS[aspect])
|
||||||
|
const fasteLabel = game.i18n.localize(ASPECT_LABELS[fasteAspect])
|
||||||
|
|
||||||
|
let btns = ""
|
||||||
|
|
||||||
|
if (successAvail > 0) {
|
||||||
|
btns += `<button class="cde-roll-action-btn cde-roll-action--success" data-action="loksyu-success">
|
||||||
|
<img src="${ASPECT_ICONS[aspect]}" class="cde-roll-action-icon" alt="${aspLabel}"/>
|
||||||
|
<span class="cde-roll-action-label">+1 ${game.i18n.localize("CDE.Successes")}</span>
|
||||||
|
<span class="cde-roll-action-count">${successAvail}</span>
|
||||||
|
</button>`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fasteAvail > 0) {
|
||||||
|
btns += `<button class="cde-roll-action-btn cde-roll-action--faste" data-action="loksyu-faste">
|
||||||
|
<img src="${ASPECT_ICONS[fasteAspect]}" class="cde-roll-action-icon" alt="${fasteLabel}"/>
|
||||||
|
<span class="cde-roll-action-label">+1 ${game.i18n.localize("CDE.AuspiciousDie")}</span>
|
||||||
|
<span class="cde-roll-action-count">${fasteAvail}</span>
|
||||||
|
</button>`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isGM && tinji > 0) {
|
||||||
|
btns += `<button class="cde-roll-action-btn cde-roll-action--tinji" data-action="tinji">
|
||||||
|
<span class="cde-roll-action-tinji-char">天</span>
|
||||||
|
<span class="cde-roll-action-label">${game.i18n.localize("CDE.TinJi2")}</span>
|
||||||
|
<span class="cde-roll-action-count">${tinji}</span>
|
||||||
|
</button>`
|
||||||
|
}
|
||||||
|
|
||||||
|
const wrapper = document.createElement("div")
|
||||||
|
wrapper.className = "cde-roll-actions"
|
||||||
|
wrapper.innerHTML = `
|
||||||
|
<div class="cde-roll-actions-title">
|
||||||
|
<i class="fas fa-yin-yang"></i>
|
||||||
|
${game.i18n.localize("CDE.PostRollActions")}
|
||||||
|
</div>
|
||||||
|
<div class="cde-roll-actions-btns">${btns}</div>
|
||||||
|
`
|
||||||
|
rollCard.appendChild(wrapper)
|
||||||
|
|
||||||
|
wrapper.addEventListener("click", async ev => {
|
||||||
|
const btn = ev.target.closest("[data-action]")
|
||||||
|
if (!btn || btn.disabled) return
|
||||||
|
const action = btn.dataset.action
|
||||||
|
if (action === "loksyu-success") {
|
||||||
|
await _drawFromLoksyu(message, aspect, "success", aspLabel)
|
||||||
|
} else if (action === "loksyu-faste") {
|
||||||
|
await _drawFromLoksyu(message, fasteAspect, "faste", fasteLabel)
|
||||||
|
} else if (action === "tinji") {
|
||||||
|
await _spendTinjiPostRoll()
|
||||||
|
}
|
||||||
|
// Buttons will be re-injected automatically via renderChatMessageHTML
|
||||||
|
// after message.update(). For tinji (no message update), refresh manually.
|
||||||
|
if (action === "tinji") refreshRollActions(rollCard, aspect, message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pull one die from a given Loksyu aspect slot, update Loksyu settings,
|
||||||
|
* and update the originating roll-result message in-place.
|
||||||
|
*
|
||||||
|
* @param {ChatMessage} message - the roll result chat message to update
|
||||||
|
* @param {string} aspect - which Loksyu aspect slot to draw from
|
||||||
|
* @param {"success"|"faste"} type
|
||||||
|
* @param {string} aspectLabel - localised aspect name for the notification
|
||||||
|
*/
|
||||||
|
async function _drawFromLoksyu(message, aspect, type, aspectLabel) {
|
||||||
|
const data = getLoksyuData()
|
||||||
|
const entry = data[aspect] ?? { yin: 0, yang: 0 }
|
||||||
|
const total = entry.yin + entry.yang
|
||||||
|
if (total <= 0) {
|
||||||
|
ui.notifications.warn(game.i18n.localize("CDE.LoksyuEmpty"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove 1 die (prefer yang first)
|
||||||
|
if (entry.yang > 0) entry.yang--
|
||||||
|
else entry.yin--
|
||||||
|
data[aspect] = entry
|
||||||
|
await setLoksyuData(data)
|
||||||
|
|
||||||
|
// Update the roll-result message in-place if it has stored flags
|
||||||
|
const flags = message?.flags?.[SYSTEM_ID]
|
||||||
|
if (flags?.rollResult && message.isOwner) {
|
||||||
|
const updated = foundry.utils.deepClone(flags.rollResult)
|
||||||
|
if (type === "success") {
|
||||||
|
updated.successesdice = (updated.successesdice ?? 0) + 1
|
||||||
|
updated.loksyuBonusSuc = (updated.loksyuBonusSuc ?? 0) + 1
|
||||||
|
// Recalculate weapon damage if applicable
|
||||||
|
if (updated.damageBase) updated.totalDamage = updated.successesdice * updated.damageBase
|
||||||
|
} else {
|
||||||
|
updated.auspiciousdice = (updated.auspiciousdice ?? 0) + 1
|
||||||
|
updated.loksyuBonusFaste = (updated.loksyuBonusFaste ?? 0) + 1
|
||||||
|
}
|
||||||
|
const newHtml = await foundry.applications.handlebars.renderTemplate(RESULT_TEMPLATE, updated)
|
||||||
|
await message.update({
|
||||||
|
content: newHtml,
|
||||||
|
[`flags.${SYSTEM_ID}.rollResult`]: updated,
|
||||||
|
})
|
||||||
|
// renderChatMessageHTML hook fires automatically → buttons re-injected
|
||||||
|
}
|
||||||
|
|
||||||
|
const remain = entry.yin + entry.yang
|
||||||
|
const typeLabel = type === "success"
|
||||||
|
? game.i18n.localize("CDE.Successes")
|
||||||
|
: game.i18n.localize("CDE.AuspiciousDie")
|
||||||
|
|
||||||
|
ChatMessage.create({
|
||||||
|
user: game.user.id,
|
||||||
|
content: `<div class="cde-loksyu-draw-msg">
|
||||||
|
<div class="cde-loksyu-draw-header">
|
||||||
|
<img src="${ASPECT_ICONS[aspect]}" class="cde-loksyu-draw-aspect-icon" alt="${aspectLabel}"/>
|
||||||
|
<span class="cde-loksyu-draw-user">${game.user.name}</span>
|
||||||
|
<span class="cde-loksyu-draw-action">${game.i18n.localize("CDE.LoksyuDrawsA")}</span>
|
||||||
|
<span class="cde-loksyu-draw-type">${typeLabel}</span>
|
||||||
|
<span class="cde-loksyu-draw-from">${game.i18n.localize("CDE.LoksyuFromAspect")} <em>${aspectLabel}</em></span>
|
||||||
|
</div>
|
||||||
|
<div class="cde-loksyu-draw-footer">
|
||||||
|
<i class="fas fa-yin-yang"></i>
|
||||||
|
<span>${game.i18n.localize("CDE.Loksyu")} ${aspectLabel} : </span>
|
||||||
|
<strong class="cde-loksyu-remain">${remain} ${game.i18n.localize("CDE.LoksyuRemaining")}</strong>
|
||||||
|
</div>
|
||||||
|
</div>`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spend 1 Tin Ji point (GM only) and post a notification.
|
||||||
|
*/
|
||||||
|
async function _spendTinjiPostRoll() {
|
||||||
|
if (!game.user.isGM) return
|
||||||
|
const current = getTinjiValue()
|
||||||
|
if (current <= 0) {
|
||||||
|
ui.notifications.warn(game.i18n.localize("CDE.TinjiEmpty"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await setTinjiValue(current - 1)
|
||||||
|
ChatMessage.create({
|
||||||
|
user: game.user.id,
|
||||||
|
content: `<div class="cde-tinji-spend-msg">
|
||||||
|
<span class="cde-tinji-icon">天</span>
|
||||||
|
<span class="cde-tinji-text">
|
||||||
|
<strong>${game.user.name}</strong> ${game.i18n.localize("CDE.TinjiSpent").replace("{name}", game.user.name)}
|
||||||
|
</span>
|
||||||
|
<span class="cde-tinji-remain">(${current - 1} ${game.i18n.localize("CDE.TinjiRemaining")})</span>
|
||||||
|
</div>`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh all visible roll-result buttons when Loksyu or TinJi settings change.
|
||||||
|
* Wired up via Hooks.on("updateSetting", ...) in system.js.
|
||||||
|
*/
|
||||||
|
export function refreshAllRollActions() {
|
||||||
|
document.querySelectorAll(".chat-message .cde-roll-result[data-aspect]").forEach(card => {
|
||||||
|
const aspect = card.dataset.aspect
|
||||||
|
if (!aspect || !WU_XING_CYCLE[aspect]) return
|
||||||
|
// Find the ChatMessage document from the ancestor element's data-message-id
|
||||||
|
const msgEl = card.closest("[data-message-id]")
|
||||||
|
const msgId = msgEl?.dataset?.messageId
|
||||||
|
const message = msgId ? game.messages.get(msgId) : null
|
||||||
|
refreshRollActions(card, aspect, message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
@@ -13,6 +13,9 @@
|
|||||||
* Each category is associated with one of the five aspects in Wu Xing cycle order.
|
* Each category is associated with one of the five aspects in Wu Xing cycle order.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { MAGICS } from "../config/constants.js"
|
||||||
|
import { updateLoksyuFromRoll, updateTinjiFromRoll } from "./apps/singletons.js"
|
||||||
|
|
||||||
const RESULT_TEMPLATE = "systems/fvtt-chroniques-de-l-etrange/templates/form/cde-dice-result.html"
|
const RESULT_TEMPLATE = "systems/fvtt-chroniques-de-l-etrange/templates/form/cde-dice-result.html"
|
||||||
const SKILL_PROMPT_TEMPLATE = "systems/fvtt-chroniques-de-l-etrange/templates/form/cde-skill-dice-prompt.html"
|
const SKILL_PROMPT_TEMPLATE = "systems/fvtt-chroniques-de-l-etrange/templates/form/cde-skill-dice-prompt.html"
|
||||||
const SKILL_SPECIAL_PROMPT_TEMPLATE = "systems/fvtt-chroniques-de-l-etrange/templates/form/cde-skill-special-dice-prompt.html"
|
const SKILL_SPECIAL_PROMPT_TEMPLATE = "systems/fvtt-chroniques-de-l-etrange/templates/form/cde-skill-special-dice-prompt.html"
|
||||||
@@ -247,6 +250,9 @@ async function sendResultMessage(actor, resultData, roll, rollMode) {
|
|||||||
content: html,
|
content: html,
|
||||||
rolls: [roll],
|
rolls: [roll],
|
||||||
rollMode,
|
rollMode,
|
||||||
|
flags: {
|
||||||
|
"fvtt-chroniques-de-l-etrange": { rollResult: { ...resultData } },
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,56 +294,61 @@ export async function rollForActor(actor, rollKey) {
|
|||||||
numberofdice = sys.aspect[skillLibel]?.value ?? 0
|
numberofdice = sys.aspect[skillLibel]?.value ?? 0
|
||||||
title = game.i18n.localize(sys.aspect[skillLibel]?.label ?? "CDE.Roll")
|
title = game.i18n.localize(sys.aspect[skillLibel]?.label ?? "CDE.Roll")
|
||||||
break
|
break
|
||||||
|
case "aptitude":
|
||||||
|
// NPC aptitude roll — flat pool with WuXing prompt
|
||||||
|
numberofdice = sys.aptitudes?.[skillLibel]?.value ?? 0
|
||||||
|
title = game.i18n.localize(`CDE.${skillLibel.charAt(0).toUpperCase() + skillLibel.slice(1)}`)
|
||||||
|
break
|
||||||
case "skill":
|
case "skill":
|
||||||
numberofdice = sys.skills[skillLibel]?.value ?? 0
|
numberofdice = sys.skills?.[skillLibel]?.value ?? 0
|
||||||
title = game.i18n.localize(sys.skills[skillLibel]?.label ?? "CDE.Roll")
|
title = game.i18n.localize(sys.skills?.[skillLibel]?.label ?? "CDE.Roll")
|
||||||
break
|
break
|
||||||
case "special":
|
case "special":
|
||||||
numberofdice = sys.skills[skillLibel]?.value ?? 0
|
numberofdice = sys.skills?.[skillLibel]?.value ?? 0
|
||||||
title = game.i18n.localize(sys.skills[skillLibel]?.label ?? "CDE.Roll")
|
title = game.i18n.localize(sys.skills?.[skillLibel]?.label ?? "CDE.Roll")
|
||||||
title += ` [${game.i18n.localize("CDE.Speciality")}]`
|
title += ` [${game.i18n.localize("CDE.Speciality")}]`
|
||||||
isSpecial = true
|
isSpecial = true
|
||||||
if (!sys.skills[skillLibel]?.specialities) {
|
if (!sys.skills?.[skillLibel]?.specialities) {
|
||||||
ui.notifications.warn(game.i18n.localize("CDE.Error2"))
|
ui.notifications.warn(game.i18n.localize("CDE.Error2"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "resource":
|
case "resource":
|
||||||
numberofdice = sys.resources[skillLibel]?.value ?? 0
|
numberofdice = sys.resources?.[skillLibel]?.value ?? 0
|
||||||
title = game.i18n.localize(sys.resources[skillLibel]?.label ?? "CDE.Roll")
|
title = game.i18n.localize(sys.resources?.[skillLibel]?.label ?? "CDE.Roll")
|
||||||
break
|
break
|
||||||
case "field":
|
case "field":
|
||||||
numberofdice = sys.resources[skillLibel]?.value ?? 0
|
numberofdice = sys.resources?.[skillLibel]?.value ?? 0
|
||||||
title = game.i18n.localize(sys.resources[skillLibel]?.label ?? "CDE.Roll")
|
title = game.i18n.localize(sys.resources?.[skillLibel]?.label ?? "CDE.Roll")
|
||||||
title += ` [${game.i18n.localize("CDE.Field")}]`
|
title += ` [${game.i18n.localize("CDE.Field")}]`
|
||||||
isSpecial = true
|
isSpecial = true
|
||||||
if (!sys.resources[skillLibel]?.specialities) {
|
if (!sys.resources?.[skillLibel]?.specialities) {
|
||||||
ui.notifications.warn(game.i18n.localize("CDE.Error4"))
|
ui.notifications.warn(game.i18n.localize("CDE.Error4"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "magic":
|
case "magic":
|
||||||
numberofdice = sys.magics[skillLibel]?.value ?? 0
|
numberofdice = sys.magics?.[skillLibel]?.value ?? 0
|
||||||
isMagic = true
|
isMagic = true
|
||||||
title = game.i18n.localize(MAGIC_I18N_KEYS[skillLibel] ?? "CDE.Magics")
|
title = game.i18n.localize(MAGIC_I18N_KEYS[skillLibel] ?? "CDE.Magics")
|
||||||
break
|
break
|
||||||
case "magicspecial":
|
case "magicspecial":
|
||||||
numberofdice = sys.magics[skillLibel]?.value ?? 0
|
numberofdice = sys.magics?.[skillLibel]?.value ?? 0
|
||||||
isMagicSpecial = true
|
isMagicSpecial = true
|
||||||
isMagic = true
|
isMagic = true
|
||||||
if (!sys.magics[skillLibel]?.speciality?.[specialLibel]?.check) {
|
if (!sys.magics?.[skillLibel]?.speciality?.[specialLibel]?.check) {
|
||||||
ui.notifications.warn(game.i18n.localize("CDE.Error6"))
|
ui.notifications.warn(game.i18n.localize("CDE.Error6"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
title = `${game.i18n.localize(MAGIC_I18N_KEYS[skillLibel] ?? "CDE.Magics")} [${game.i18n.localize(game.system.CONST?.MAGICS?.[skillLibel]?.speciality?.[specialLibel]?.label ?? "")}]`
|
title = `${game.i18n.localize(MAGIC_I18N_KEYS[skillLibel] ?? "CDE.Magics")} [${game.i18n.localize(MAGICS?.[skillLibel]?.speciality?.[specialLibel]?.label ?? "")}]`
|
||||||
break
|
break
|
||||||
case "itemkungfu": {
|
case "itemkungfu": {
|
||||||
// skillLibel = item._id — look up the kungfu item to find which skill + aspect to use
|
// skillLibel = item._id — look up the kungfu item to find which skill + aspect to use
|
||||||
const kfItem = actor.items.get(skillLibel)
|
const kfItem = actor.items.get(skillLibel)
|
||||||
if (!kfItem) { ui.notifications.warn(game.i18n.localize("CDE.Error0")); return }
|
if (!kfItem) { ui.notifications.warn(game.i18n.localize("CDE.Error0")); return }
|
||||||
const kfSkill = kfItem.system.skill ?? "kungfu"
|
const kfSkill = kfItem.system.skill ?? "kungfu"
|
||||||
numberofdice = sys.skills[kfSkill]?.value ?? 0
|
numberofdice = sys.skills?.[kfSkill]?.value ?? 0
|
||||||
title = `${kfItem.name} [${game.i18n.localize(sys.skills[kfSkill]?.label ?? "CDE.KungFu")}]`
|
title = `${kfItem.name} [${game.i18n.localize(sys.skills?.[kfSkill]?.label ?? "CDE.KungFu")}]`
|
||||||
kfDefaultAspect = ASPECT_NAMES.indexOf(kfItem.system.aspect ?? "metal")
|
kfDefaultAspect = ASPECT_NAMES.indexOf(kfItem.system.aspect ?? "metal")
|
||||||
if (kfDefaultAspect < 0) kfDefaultAspect = 0
|
if (kfDefaultAspect < 0) kfDefaultAspect = 0
|
||||||
break
|
break
|
||||||
@@ -349,7 +360,7 @@ export async function rollForActor(actor, rollKey) {
|
|||||||
|
|
||||||
const wpType = wpItem.system.weaponType ?? "melee"
|
const wpType = wpItem.system.weaponType ?? "melee"
|
||||||
const wpSkill = WEAPON_TYPE_SKILL[wpType] ?? "kungfu"
|
const wpSkill = WEAPON_TYPE_SKILL[wpType] ?? "kungfu"
|
||||||
numberofdice = sys.skills[wpSkill]?.value ?? 0
|
numberofdice = sys.skills?.[wpSkill]?.value ?? 0
|
||||||
|
|
||||||
const wpAspectRaw = wpItem.system.damageAspect ?? "metal"
|
const wpAspectRaw = wpItem.system.damageAspect ?? "metal"
|
||||||
const wpAspectIdx = WEAPON_ASPECT_INDEX[wpAspectRaw] ?? 0
|
const wpAspectIdx = WEAPON_ASPECT_INDEX[wpAspectRaw] ?? 0
|
||||||
@@ -364,7 +375,7 @@ export async function rollForActor(actor, rollKey) {
|
|||||||
|
|
||||||
// Show weapon-specific prompt
|
// Show weapon-specific prompt
|
||||||
const wParams = await showWeaponPrompt({
|
const wParams = await showWeaponPrompt({
|
||||||
title: `${wpItem.name} [${game.i18n.localize(sys.skills[wpSkill]?.label ?? "CDE.WeaponRoll")}]`,
|
title: `${wpItem.name} [${game.i18n.localize(sys.skills?.[wpSkill]?.label ?? "CDE.WeaponRoll")}]`,
|
||||||
numberofdice,
|
numberofdice,
|
||||||
weaponName: wpItem.name,
|
weaponName: wpItem.name,
|
||||||
weaponTypeLabel: WEAPON_TYPE_LABELS[wpType] ?? "CDE.Weapon",
|
weaponTypeLabel: WEAPON_TYPE_LABELS[wpType] ?? "CDE.Weapon",
|
||||||
@@ -384,7 +395,7 @@ export async function rollForActor(actor, rollKey) {
|
|||||||
|
|
||||||
// Resolve final pool from weapon prompt values
|
// Resolve final pool from weapon prompt values
|
||||||
const wpChosenSkill = wParams.weaponskill ?? wpSkill
|
const wpChosenSkill = wParams.weaponskill ?? wpSkill
|
||||||
const wpSkillDice = sys.skills[wpChosenSkill]?.value ?? 0
|
const wpSkillDice = sys.skills?.[wpChosenSkill]?.value ?? 0
|
||||||
const wpAspFinal = Number(wParams.aspect ?? wpAspectIdx)
|
const wpAspFinal = Number(wParams.aspect ?? wpAspectIdx)
|
||||||
const wpAspectDice = sys.aspect[ASPECT_NAMES[wpAspFinal]]?.value ?? 0
|
const wpAspectDice = sys.aspect[ASPECT_NAMES[wpAspFinal]]?.value ?? 0
|
||||||
const wpRangeMalus = RANGE_MALUS[wParams.effectiverange ?? "contact"] ?? 0
|
const wpRangeMalus = RANGE_MALUS[wParams.effectiverange ?? "contact"] ?? 0
|
||||||
@@ -438,6 +449,9 @@ export async function rollForActor(actor, rollKey) {
|
|||||||
if (game.modules.get("dice-so-nice")?.active && wpMsg?.id) {
|
if (game.modules.get("dice-so-nice")?.active && wpMsg?.id) {
|
||||||
await game.dice3d.waitFor3DAnimationByMessageID(wpMsg.id)
|
await game.dice3d.waitFor3DAnimationByMessageID(wpMsg.id)
|
||||||
}
|
}
|
||||||
|
// Auto-update Loksyu/TinJi singletons from weapon roll faces
|
||||||
|
if ((wpResults.loksyudice ?? 0) > 0) await updateLoksyuFromRoll(wpAspectName, wpFaces)
|
||||||
|
if ((wpResults.tinjidice ?? 0) > 0) await updateTinjiFromRoll(wpResults.tinjidice)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -474,7 +488,7 @@ export async function rollForActor(actor, rollKey) {
|
|||||||
let defaultSpecialAspect = 0
|
let defaultSpecialAspect = 0
|
||||||
if (isMagicSpecial && specialLibel) {
|
if (isMagicSpecial && specialLibel) {
|
||||||
// Look up the speciality's element from the MAGICS config constant
|
// Look up the speciality's element from the MAGICS config constant
|
||||||
const specialCfg = game.system.CONST?.MAGICS?.[skillLibel]?.speciality?.[specialLibel]
|
const specialCfg = MAGICS?.[skillLibel]?.speciality?.[specialLibel]
|
||||||
const aspectName = LABELELEMENT_TO_ASPECT[specialCfg?.labelelement]
|
const aspectName = LABELELEMENT_TO_ASPECT[specialCfg?.labelelement]
|
||||||
if (aspectName) {
|
if (aspectName) {
|
||||||
defaultSpecialAspect = ASPECT_NAMES.indexOf(aspectName)
|
defaultSpecialAspect = ASPECT_NAMES.indexOf(aspectName)
|
||||||
@@ -526,7 +540,7 @@ export async function rollForActor(actor, rollKey) {
|
|||||||
rollDifficulty = Math.max(1, Number(params.rolldifficulty ?? 1))
|
rollDifficulty = Math.max(1, Number(params.rolldifficulty ?? 1))
|
||||||
throwMode = Number(params.typeofthrow ?? 0)
|
throwMode = Number(params.typeofthrow ?? 0)
|
||||||
// magic: magic skill + aspect + bonuses + 1 (speciality base) + HEI spent
|
// magic: magic skill + aspect + bonuses + 1 (speciality base) + HEI spent
|
||||||
const aspectDice = sys.aspect[ASPECT_NAMES[aspectIndex]]?.value ?? 0
|
const aspectDice = sys.aspect?.[ASPECT_NAMES[aspectIndex]]?.value ?? 0
|
||||||
const bonusSpec = Number(params.bonusmalusspeciality ?? 0)
|
const bonusSpec = Number(params.bonusmalusspeciality ?? 0)
|
||||||
const heiDice = Number(params.heispend ?? 0)
|
const heiDice = Number(params.heispend ?? 0)
|
||||||
numberofdice = numberofdice + aspectDice + bonusMalus + 1 + bonusSpec + heiDice
|
numberofdice = numberofdice + aspectDice + bonusMalus + 1 + bonusSpec + heiDice
|
||||||
@@ -538,7 +552,7 @@ export async function rollForActor(actor, rollKey) {
|
|||||||
throwMode = Number(params.typeofthrow ?? 0)
|
throwMode = Number(params.typeofthrow ?? 0)
|
||||||
|
|
||||||
const aspectDice = (typeLibel !== "aspect")
|
const aspectDice = (typeLibel !== "aspect")
|
||||||
? (sys.aspect[ASPECT_NAMES[aspectIndex]]?.value ?? 0)
|
? (sys.aspect?.[ASPECT_NAMES[aspectIndex]]?.value ?? 0)
|
||||||
: 0
|
: 0
|
||||||
|
|
||||||
numberofdice = numberofdice + aspectDice + bonusMalus - woundMalus
|
numberofdice = numberofdice + aspectDice + bonusMalus - woundMalus
|
||||||
@@ -618,4 +632,8 @@ export async function rollForActor(actor, rollKey) {
|
|||||||
if (game.modules.get("dice-so-nice")?.active && msg?.id) {
|
if (game.modules.get("dice-so-nice")?.active && msg?.id) {
|
||||||
await game.dice3d.waitFor3DAnimationByMessageID(msg.id)
|
await game.dice3d.waitFor3DAnimationByMessageID(msg.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---- Auto-update Loksyu / TinJi singletons ----
|
||||||
|
if ((results.loksyudice ?? 0) > 0) await updateLoksyuFromRoll(wuXingAspectName, faces)
|
||||||
|
if ((results.tinjidice ?? 0) > 0) await updateTinjiFromRoll(results.tinjidice)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export class CDEBaseActorSheet extends HandlebarsApplicationMixin(foundry.applic
|
|||||||
create: CDEBaseActorSheet.#onItemCreate,
|
create: CDEBaseActorSheet.#onItemCreate,
|
||||||
edit: CDEBaseActorSheet.#onItemEdit,
|
edit: CDEBaseActorSheet.#onItemEdit,
|
||||||
delete: CDEBaseActorSheet.#onItemDelete,
|
delete: CDEBaseActorSheet.#onItemDelete,
|
||||||
|
editImage: CDEBaseActorSheet.#onEditImage,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,4 +78,19 @@ export class CDEBaseActorSheet extends HandlebarsApplicationMixin(foundry.applic
|
|||||||
const item = this.document.items.get(itemId)
|
const item = this.document.items.get(itemId)
|
||||||
if (item) item.delete()
|
if (item) item.delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async #onEditImage(event, target) {
|
||||||
|
const attr = target.dataset.edit
|
||||||
|
const current = foundry.utils.getProperty(this.document, attr)
|
||||||
|
const { img } = this.document.constructor.getDefaultArtwork?.(this.document.toObject()) ?? {}
|
||||||
|
const fp = new FilePicker({
|
||||||
|
current,
|
||||||
|
type: "image",
|
||||||
|
redirectToRoot: img ? [img] : [],
|
||||||
|
callback: (path) => this.document.update({ [attr]: path }),
|
||||||
|
top: this.position.top + 40,
|
||||||
|
left: this.position.left + 10,
|
||||||
|
})
|
||||||
|
return fp.browse()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export class CDECharacterSheet extends CDEBaseActorSheet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_onRender(context, options) {
|
_onRender(context, options) {
|
||||||
super._onRender?.(context, options)
|
super._onRender(context, options)
|
||||||
this.#bindInitiativeControls()
|
this.#bindInitiativeControls()
|
||||||
this.#bindPrefs()
|
this.#bindPrefs()
|
||||||
this.#bindRollButtons()
|
this.#bindRollButtons()
|
||||||
@@ -99,7 +99,7 @@ export class CDECharacterSheet extends CDEBaseActorSheet {
|
|||||||
<form class="flexcol">
|
<form class="flexcol">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>${game.i18n.localize("CDE.ThrowType")}</label>
|
<label>${game.i18n.localize("CDE.ThrowType")}</label>
|
||||||
<select name="choice" value="${current.choice}">
|
<select name="choice">
|
||||||
<option value="0"${current.choice === "0" ? " selected" : ""}>0</option>
|
<option value="0"${current.choice === "0" ? " selected" : ""}>0</option>
|
||||||
<option value="1"${current.choice === "1" ? " selected" : ""}>1</option>
|
<option value="1"${current.choice === "1" ? " selected" : ""}>1</option>
|
||||||
<option value="2"${current.choice === "2" ? " selected" : ""}>2</option>
|
<option value="2"${current.choice === "2" ? " selected" : ""}>2</option>
|
||||||
@@ -111,15 +111,19 @@ export class CDECharacterSheet extends CDEBaseActorSheet {
|
|||||||
<input type="checkbox" name="check" ${current.check ? "checked" : ""}/>
|
<input type="checkbox" name="check" ${current.check ? "checked" : ""}/>
|
||||||
</div>
|
</div>
|
||||||
</form>`
|
</form>`
|
||||||
const prefs = await Dialog.prompt({
|
const prefs = await foundry.applications.api.DialogV2.prompt({
|
||||||
title: game.i18n.localize("CDE.Preferences"),
|
window: { title: game.i18n.localize("CDE.Preferences") },
|
||||||
content: html,
|
content: html,
|
||||||
|
rejectClose: false,
|
||||||
|
ok: {
|
||||||
label: game.i18n.localize("CDE.Validate"),
|
label: game.i18n.localize("CDE.Validate"),
|
||||||
callback: (dlg) => {
|
callback: (_ev, _btn, dialog) => {
|
||||||
const choice = dlg.querySelector("select[name='choice']")?.value ?? "0"
|
const root = dialog.element ?? dialog
|
||||||
const check = dlg.querySelector("input[name='check']")?.checked ?? false
|
const choice = root.querySelector("select[name='choice']")?.value ?? "0"
|
||||||
|
const check = root.querySelector("input[name='check']")?.checked ?? false
|
||||||
return { choice, check }
|
return { choice, check }
|
||||||
},
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
if (prefs) {
|
if (prefs) {
|
||||||
await this.document.update({
|
await this.document.update({
|
||||||
@@ -166,7 +170,7 @@ export class CDECharacterSheet extends CDEBaseActorSheet {
|
|||||||
speaker: ChatMessage.getSpeaker({ actor: this.document }),
|
speaker: ChatMessage.getSpeaker({ actor: this.document }),
|
||||||
content,
|
content,
|
||||||
rolls: [roll],
|
rolls: [roll],
|
||||||
rollMode: "roll",
|
rollMode: game.settings.get("core", "rollMode") ?? "roll",
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,2 @@
|
|||||||
export { CDECharacterSheet } from "./character.js"
|
export { CDECharacterSheet } from "./character.js"
|
||||||
export { CDENpcSheet } from "./npc.js"
|
export { CDENpcSheet } from "./npc.js"
|
||||||
export { CDETinjiSheet } from "./tinji.js"
|
|
||||||
export { CDELoksyuSheet } from "./loksyu.js"
|
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
import { CDEBaseActorSheet } from "./base.js"
|
|
||||||
|
|
||||||
export class CDELoksyuSheet extends CDEBaseActorSheet {
|
|
||||||
static DEFAULT_OPTIONS = {
|
|
||||||
classes: ["loksyu"],
|
|
||||||
}
|
|
||||||
|
|
||||||
static PARTS = {
|
|
||||||
main: { template: "systems/fvtt-chroniques-de-l-etrange/templates/actor/cde-loksyu-sheet.html" },
|
|
||||||
}
|
|
||||||
|
|
||||||
tabGroups = { primary: "loksyu" }
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { rollInitiativeNPC } from "../../initiative.js"
|
import { rollInitiativeNPC } from "../../initiative.js"
|
||||||
|
import { rollForActor } from "../../rolling.js"
|
||||||
import { CDEBaseActorSheet } from "./base.js"
|
import { CDEBaseActorSheet } from "./base.js"
|
||||||
|
|
||||||
export class CDENpcSheet extends CDEBaseActorSheet {
|
export class CDENpcSheet extends CDEBaseActorSheet {
|
||||||
@@ -17,13 +18,28 @@ export class CDENpcSheet extends CDEBaseActorSheet {
|
|||||||
context.supernaturals = context.items.filter((item) => item.type === "supernatural")
|
context.supernaturals = context.items.filter((item) => item.type === "supernatural")
|
||||||
context.spells = context.items.filter((item) => item.type === "spell")
|
context.spells = context.items.filter((item) => item.type === "spell")
|
||||||
context.kungfus = context.items.filter((item) => item.type === "kungfu")
|
context.kungfus = context.items.filter((item) => item.type === "kungfu")
|
||||||
|
context.weapons = context.items.filter((item) => item.type === "weapon")
|
||||||
|
context.armors = context.items.filter((item) => item.type === "armor")
|
||||||
context.equipments = context.items.filter((item) => item.type === "item")
|
context.equipments = context.items.filter((item) => item.type === "item")
|
||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
|
|
||||||
_onRender(context, options) {
|
_onRender(context, options) {
|
||||||
super._onRender?.(context, options)
|
super._onRender(context, options)
|
||||||
this.#bindInitiativeControls()
|
this.#bindInitiativeControls()
|
||||||
|
this.#bindRollButtons()
|
||||||
|
}
|
||||||
|
|
||||||
|
#bindRollButtons() {
|
||||||
|
const cells = this.element?.querySelectorAll(".cde-roll-trigger[data-libel-id]")
|
||||||
|
if (!cells?.length) return
|
||||||
|
cells.forEach((cell) => {
|
||||||
|
cell.addEventListener("click", (event) => {
|
||||||
|
event.preventDefault()
|
||||||
|
const rollKey = cell.dataset.libelId
|
||||||
|
if (rollKey) rollForActor(this.document, rollKey)
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#bindInitiativeControls() {
|
#bindInitiativeControls() {
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
import { CDEBaseActorSheet } from "./base.js"
|
|
||||||
|
|
||||||
export class CDETinjiSheet extends CDEBaseActorSheet {
|
|
||||||
static DEFAULT_OPTIONS = {
|
|
||||||
classes: ["tinji"],
|
|
||||||
}
|
|
||||||
|
|
||||||
static PARTS = {
|
|
||||||
main: { template: "systems/fvtt-chroniques-de-l-etrange/templates/actor/cde-tinji-sheet.html" },
|
|
||||||
}
|
|
||||||
|
|
||||||
tabGroups = { primary: "tinji" }
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,9 @@ export class CDEBaseItemSheet extends HandlebarsApplicationMixin(foundry.applica
|
|||||||
position: { width: 520, height: "auto" },
|
position: { width: 520, height: "auto" },
|
||||||
window: { resizable: true },
|
window: { resizable: true },
|
||||||
form: { submitOnChange: true },
|
form: { submitOnChange: true },
|
||||||
actions: {},
|
actions: {
|
||||||
|
editImage: CDEBaseItemSheet.#onEditImage,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
tabGroups = { primary: "details" }
|
tabGroups = { primary: "details" }
|
||||||
@@ -40,4 +42,19 @@ export class CDEBaseItemSheet extends HandlebarsApplicationMixin(foundry.applica
|
|||||||
this.changeTab(tab, group, { force: true })
|
this.changeTab(tab, group, { force: true })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async #onEditImage(event, target) {
|
||||||
|
const attr = target.dataset.edit
|
||||||
|
const current = foundry.utils.getProperty(this.document, attr)
|
||||||
|
const { img } = this.document.constructor.getDefaultArtwork?.(this.document.toObject()) ?? {}
|
||||||
|
const fp = new FilePicker({
|
||||||
|
current,
|
||||||
|
type: "image",
|
||||||
|
redirectToRoot: img ? [img] : [],
|
||||||
|
callback: (path) => this.document.update({ [attr]: path }),
|
||||||
|
top: this.position.top + 40,
|
||||||
|
left: this.position.left + 10,
|
||||||
|
})
|
||||||
|
return fp.browse()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { TEMPLATE_PARTIALS } from "../config/constants.js"
|
import { TEMPLATE_PARTIALS } from "../config/constants.js"
|
||||||
|
|
||||||
export async function preloadPartials() {
|
export async function preloadPartials() {
|
||||||
return loadTemplates(TEMPLATE_PARTIALS)
|
return foundry.applications.handlebars.loadTemplates(TEMPLATE_PARTIALS)
|
||||||
}
|
}
|
||||||
|
|||||||
10
system.json
10
system.json
@@ -168,16 +168,6 @@
|
|||||||
"htmlFields": [
|
"htmlFields": [
|
||||||
"description"
|
"description"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
"tinji": {
|
|
||||||
"htmlFields": [
|
|
||||||
"description"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"loksyu": {
|
|
||||||
"htmlFields": [
|
|
||||||
"description"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Item": {
|
"Item": {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
{{log 'actor-sheet' this}}
|
{{log 'actor-sheet' this}}
|
||||||
|
|
||||||
<header class="cde-header cde-actor-header">
|
<header class="cde-header cde-actor-header">
|
||||||
<img class="profile-img" src="{{actor.img}}" data-edit="img" title="{{actor.name}}" />
|
<img class="profile-img" src="{{actor.img}}" data-action="editImage" data-edit="img" title="{{actor.name}}" />
|
||||||
<div class="header-fields">
|
<div class="header-fields">
|
||||||
<div class="cde-header-top">
|
<div class="cde-header-top">
|
||||||
<h1 class="charname">
|
<h1 class="charname">
|
||||||
|
|||||||
@@ -1,137 +0,0 @@
|
|||||||
<section class="flexcol cde-sheet cde-actor {{cssClass}}">
|
|
||||||
<header class="cde-header cde-actor-header">
|
|
||||||
<img class="profile-img" src="{{actor.img}}" data-edit="img" title="{{actor.name}}" />
|
|
||||||
<div class="header-fields">
|
|
||||||
<h1 class="charname">
|
|
||||||
<input name="name" type="text" value="{{actor.name}}" placeholder="{{ localize 'CDE.LoksyuName' }}" />
|
|
||||||
</h1>
|
|
||||||
<div class="cde-tag">
|
|
||||||
<span class="cde-pill spell">{{ localize "CDE.UpperCaseLoksyu" }}</span>
|
|
||||||
<span>Chroniques de l'Étrange</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<nav class="sheet-tabs tabs cde-neon-tabs" data-group="primary">
|
|
||||||
<a class="item" data-action="tab" data-group="primary" data-tab="loksyu">{{ localize "CDE.Loksyu" }}</a>
|
|
||||||
<a class="item" data-action="tab" data-group="primary" data-tab="description">{{ localize "CDE.Description" }}</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<section class="sheet-body cde-tab-body">
|
|
||||||
<div class="tab" data-group="primary" data-tab="loksyu">
|
|
||||||
<div class="cde-loksyu-grid">
|
|
||||||
|
|
||||||
<div class="cde-element-card cde-element--wood">
|
|
||||||
<div class="cde-element-header">
|
|
||||||
<img class="cde-element-img" src="systems/fvtt-chroniques-de-l-etrange/images/cde_bois.webp" alt="Bois" />
|
|
||||||
<div class="cde-element-titles">
|
|
||||||
<span class="cde-element-name">{{ localize "CDE.Wood" }}</span>
|
|
||||||
<span class="cde-element-qualities">{{ localize "CDE.WoodQualities" }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="cde-element-values">
|
|
||||||
<div class="cde-element-polarity cde-element-polarity--yang">
|
|
||||||
<span class="cde-polarity-label">○ {{ localize "CDE.Yang" }}</span>
|
|
||||||
<input type="number" min="0" name="system.wood.yang.value" value="{{systemData.wood.yang.value}}" title="{{ localize 'CDE.WoodYang' }}" />
|
|
||||||
</div>
|
|
||||||
<div class="cde-element-polarity cde-element-polarity--yin">
|
|
||||||
<span class="cde-polarity-label">● {{ localize "CDE.Yin" }}</span>
|
|
||||||
<input type="number" min="0" name="system.wood.yin.value" value="{{systemData.wood.yin.value}}" title="{{ localize 'CDE.WoodYin' }}" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="cde-element-card cde-element--fire">
|
|
||||||
<div class="cde-element-header">
|
|
||||||
<img class="cde-element-img" src="systems/fvtt-chroniques-de-l-etrange/images/cde_feu.webp" alt="Feu" />
|
|
||||||
<div class="cde-element-titles">
|
|
||||||
<span class="cde-element-name">{{ localize "CDE.Fire" }}</span>
|
|
||||||
<span class="cde-element-qualities">{{ localize "CDE.FireQualities" }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="cde-element-values">
|
|
||||||
<div class="cde-element-polarity cde-element-polarity--yang">
|
|
||||||
<span class="cde-polarity-label">○ {{ localize "CDE.Yang" }}</span>
|
|
||||||
<input type="number" min="0" name="system.fire.yang.value" value="{{systemData.fire.yang.value}}" title="{{ localize 'CDE.FireYang' }}" />
|
|
||||||
</div>
|
|
||||||
<div class="cde-element-polarity cde-element-polarity--yin">
|
|
||||||
<span class="cde-polarity-label">● {{ localize "CDE.Yin" }}</span>
|
|
||||||
<input type="number" min="0" name="system.fire.yin.value" value="{{systemData.fire.yin.value}}" title="{{ localize 'CDE.FireYin' }}" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="cde-element-card cde-element--earth">
|
|
||||||
<div class="cde-element-header">
|
|
||||||
<img class="cde-element-img" src="systems/fvtt-chroniques-de-l-etrange/images/cde_terre.webp" alt="Terre" />
|
|
||||||
<div class="cde-element-titles">
|
|
||||||
<span class="cde-element-name">{{ localize "CDE.Earth" }}</span>
|
|
||||||
<span class="cde-element-qualities">{{ localize "CDE.EarthQualities" }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="cde-element-values">
|
|
||||||
<div class="cde-element-polarity cde-element-polarity--yang">
|
|
||||||
<span class="cde-polarity-label">○ {{ localize "CDE.Yang" }}</span>
|
|
||||||
<input type="number" min="0" name="system.earth.yang.value" value="{{systemData.earth.yang.value}}" title="{{ localize 'CDE.EarthYang' }}" />
|
|
||||||
</div>
|
|
||||||
<div class="cde-element-polarity cde-element-polarity--yin">
|
|
||||||
<span class="cde-polarity-label">● {{ localize "CDE.Yin" }}</span>
|
|
||||||
<input type="number" min="0" name="system.earth.yin.value" value="{{systemData.earth.yin.value}}" title="{{ localize 'CDE.EarthYin' }}" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="cde-element-card cde-element--metal">
|
|
||||||
<div class="cde-element-header">
|
|
||||||
<img class="cde-element-img" src="systems/fvtt-chroniques-de-l-etrange/images/cde_metal.webp" alt="Métal" />
|
|
||||||
<div class="cde-element-titles">
|
|
||||||
<span class="cde-element-name">{{ localize "CDE.Metal" }}</span>
|
|
||||||
<span class="cde-element-qualities">{{ localize "CDE.MetalQualities" }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="cde-element-values">
|
|
||||||
<div class="cde-element-polarity cde-element-polarity--yang">
|
|
||||||
<span class="cde-polarity-label">○ {{ localize "CDE.Yang" }}</span>
|
|
||||||
<input type="number" min="0" name="system.metal.yang.value" value="{{systemData.metal.yang.value}}" title="{{ localize 'CDE.MetalYang' }}" />
|
|
||||||
</div>
|
|
||||||
<div class="cde-element-polarity cde-element-polarity--yin">
|
|
||||||
<span class="cde-polarity-label">● {{ localize "CDE.Yin" }}</span>
|
|
||||||
<input type="number" min="0" name="system.metal.yin.value" value="{{systemData.metal.yin.value}}" title="{{ localize 'CDE.MetalYin' }}" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="cde-element-card cde-element--water">
|
|
||||||
<div class="cde-element-header">
|
|
||||||
<img class="cde-element-img" src="systems/fvtt-chroniques-de-l-etrange/images/cde_eau.webp" alt="Eau" />
|
|
||||||
<div class="cde-element-titles">
|
|
||||||
<span class="cde-element-name">{{ localize "CDE.Water" }}</span>
|
|
||||||
<span class="cde-element-qualities">{{ localize "CDE.WaterQualities" }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="cde-element-values">
|
|
||||||
<div class="cde-element-polarity cde-element-polarity--yang">
|
|
||||||
<span class="cde-polarity-label">○ {{ localize "CDE.Yang" }}</span>
|
|
||||||
<input type="number" min="0" name="system.water.yang.value" value="{{systemData.water.yang.value}}" title="{{ localize 'CDE.WaterYang' }}" />
|
|
||||||
</div>
|
|
||||||
<div class="cde-element-polarity cde-element-polarity--yin">
|
|
||||||
<span class="cde-polarity-label">● {{ localize "CDE.Yin" }}</span>
|
|
||||||
<input type="number" min="0" name="system.water.yin.value" value="{{systemData.water.yin.value}}" title="{{ localize 'CDE.WaterYin' }}" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="cde-loksyu-visual-row">
|
|
||||||
<img class="loksyu-visual" src="systems/fvtt-chroniques-de-l-etrange/images/loksyu_long.webp" title="Loksyu — Roue des Cinq Éléments" alt="Loksyu" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="tab" data-group="primary" data-tab="description">
|
|
||||||
<div class="cde-card cde-notes-editor">
|
|
||||||
{{formInput systemFields.description enriched=descriptionHTML value=system.description name="system.description" toggled=true}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<section class="flexcol cde-sheet cde-actor {{cssClass}}">
|
<section class="flexcol cde-sheet cde-actor {{cssClass}}">
|
||||||
<header class="cde-header cde-actor-header">
|
<header class="cde-header cde-actor-header">
|
||||||
<img class="profile-img" src="{{actor.img}}" data-edit="img" title="{{actor.name}}" />
|
<img class="profile-img" src="{{actor.img}}" data-action="editImage" data-edit="img" title="{{actor.name}}" />
|
||||||
<div class="header-fields">
|
<div class="header-fields">
|
||||||
<div class="cde-header-top">
|
<div class="cde-header-top">
|
||||||
<h1 class="charname">
|
<h1 class="charname">
|
||||||
@@ -110,6 +110,9 @@
|
|||||||
<td class="cde-spec-cell">
|
<td class="cde-spec-cell">
|
||||||
<input type="text" placeholder="{{ localize 'CDE.Specialities' }}…" name="system.aptitudes.physical.speciality" value="{{systemData.aptitudes.physical.speciality}}" />
|
<input type="text" placeholder="{{ localize 'CDE.Specialities' }}…" name="system.aptitudes.physical.speciality" value="{{systemData.aptitudes.physical.speciality}}" />
|
||||||
</td>
|
</td>
|
||||||
|
<td class="cde-roll-cell">
|
||||||
|
<a class="cde-roll-trigger" data-libel-id="physical-aptitude" title="{{ localize 'CDE.Roll' }}"><i class="fas fa-dice-d10"></i></a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="cde-skill-label"><b>{{ localize "CDE.Martial" }}</b></td>
|
<td class="cde-skill-label"><b>{{ localize "CDE.Martial" }}</b></td>
|
||||||
@@ -119,6 +122,9 @@
|
|||||||
<td class="cde-spec-cell">
|
<td class="cde-spec-cell">
|
||||||
<input type="text" placeholder="{{ localize 'CDE.Specialities' }}…" name="system.aptitudes.martial.speciality" value="{{systemData.aptitudes.martial.speciality}}" />
|
<input type="text" placeholder="{{ localize 'CDE.Specialities' }}…" name="system.aptitudes.martial.speciality" value="{{systemData.aptitudes.martial.speciality}}" />
|
||||||
</td>
|
</td>
|
||||||
|
<td class="cde-roll-cell">
|
||||||
|
<a class="cde-roll-trigger" data-libel-id="martial-aptitude" title="{{ localize 'CDE.Roll' }}"><i class="fas fa-dice-d10"></i></a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="cde-skill-label"><b>{{ localize "CDE.Mental" }}</b></td>
|
<td class="cde-skill-label"><b>{{ localize "CDE.Mental" }}</b></td>
|
||||||
@@ -128,6 +134,9 @@
|
|||||||
<td class="cde-spec-cell">
|
<td class="cde-spec-cell">
|
||||||
<input type="text" placeholder="{{ localize 'CDE.Specialities' }}…" name="system.aptitudes.mental.speciality" value="{{systemData.aptitudes.mental.speciality}}" />
|
<input type="text" placeholder="{{ localize 'CDE.Specialities' }}…" name="system.aptitudes.mental.speciality" value="{{systemData.aptitudes.mental.speciality}}" />
|
||||||
</td>
|
</td>
|
||||||
|
<td class="cde-roll-cell">
|
||||||
|
<a class="cde-roll-trigger" data-libel-id="mental-aptitude" title="{{ localize 'CDE.Roll' }}"><i class="fas fa-dice-d10"></i></a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="cde-skill-label"><b>{{ localize "CDE.Social" }}</b></td>
|
<td class="cde-skill-label"><b>{{ localize "CDE.Social" }}</b></td>
|
||||||
@@ -137,6 +146,9 @@
|
|||||||
<td class="cde-spec-cell">
|
<td class="cde-spec-cell">
|
||||||
<input type="text" placeholder="{{ localize 'CDE.Specialities' }}…" name="system.aptitudes.social.speciality" value="{{systemData.aptitudes.social.speciality}}" />
|
<input type="text" placeholder="{{ localize 'CDE.Specialities' }}…" name="system.aptitudes.social.speciality" value="{{systemData.aptitudes.social.speciality}}" />
|
||||||
</td>
|
</td>
|
||||||
|
<td class="cde-roll-cell">
|
||||||
|
<a class="cde-roll-trigger" data-libel-id="social-aptitude" title="{{ localize 'CDE.Roll' }}"><i class="fas fa-dice-d10"></i></a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="cde-skill-label"><b>{{ localize "CDE.Spiritual" }}</b></td>
|
<td class="cde-skill-label"><b>{{ localize "CDE.Spiritual" }}</b></td>
|
||||||
@@ -146,6 +158,9 @@
|
|||||||
<td class="cde-spec-cell">
|
<td class="cde-spec-cell">
|
||||||
<input type="text" placeholder="{{ localize 'CDE.Specialities' }}…" name="system.aptitudes.spiritual.speciality" value="{{systemData.aptitudes.spiritual.speciality}}" />
|
<input type="text" placeholder="{{ localize 'CDE.Specialities' }}…" name="system.aptitudes.spiritual.speciality" value="{{systemData.aptitudes.spiritual.speciality}}" />
|
||||||
</td>
|
</td>
|
||||||
|
<td class="cde-roll-cell">
|
||||||
|
<a class="cde-roll-trigger" data-libel-id="spiritual-aptitude" title="{{ localize 'CDE.Roll' }}"><i class="fas fa-dice-d10"></i></a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
<section class="flexcol cde-sheet cde-actor {{cssClass}}">
|
|
||||||
<header class="cde-header cde-actor-header">
|
|
||||||
<img class="profile-img" src="{{actor.img}}" data-edit="img" title="{{actor.name}}" />
|
|
||||||
<div class="header-fields">
|
|
||||||
<h1 class="charname">
|
|
||||||
<input name="name" type="text" value="{{actor.name}}" placeholder="{{ localize 'CDE.TinJiName' }}" />
|
|
||||||
</h1>
|
|
||||||
<div class="cde-tag">
|
|
||||||
<span class="cde-pill supernatural">{{ localize "CDE.UpperCaseTinJi" }}</span>
|
|
||||||
<span>Chroniques de l'Étrange</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<nav class="sheet-tabs tabs cde-neon-tabs" data-group="primary">
|
|
||||||
<a class="item" data-action="tab" data-group="primary" data-tab="tinji">{{ localize "CDE.TinJi2" }}</a>
|
|
||||||
<a class="item" data-action="tab" data-group="primary" data-tab="description">{{ localize "CDE.Description" }}</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<section class="sheet-body cde-tab-body">
|
|
||||||
<div class="tab" data-group="primary" data-tab="tinji">
|
|
||||||
<div class="cde-tinji-layout">
|
|
||||||
<div class="cde-tinji-main">
|
|
||||||
<div class="cde-tinji-chinese">天機</div>
|
|
||||||
<div class="cde-tinji-subtitle">{{ localize "CDE.UpperCaseTinJi" }}</div>
|
|
||||||
<div class="cde-tinji-value-wrapper">
|
|
||||||
<input
|
|
||||||
class="cde-tinji-input"
|
|
||||||
type="number"
|
|
||||||
min="0"
|
|
||||||
name="system.value"
|
|
||||||
value="{{systemData.value}}"
|
|
||||||
title="{{ localize 'CDE.TinJi2' }}"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="cde-tinji-hint">{{ localize "CDE.AuspiciousDice" }}</div>
|
|
||||||
</div>
|
|
||||||
<img class="tinji-visual" src="systems/fvtt-chroniques-de-l-etrange/images/tinji.webp" title="Tin Ji — 天機" alt="Tin Ji" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="tab" data-group="primary" data-tab="description">
|
|
||||||
<div class="cde-card cde-notes-editor">
|
|
||||||
{{formInput systemFields.description enriched=descriptionHTML value=system.description name="system.description" toggled=true}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
@@ -1,8 +1,58 @@
|
|||||||
|
{{!-- Weapons --}}
|
||||||
|
{{#if weapons.length}}
|
||||||
|
<p class="cde-item-group-label">{{ localize "CDE.Weapons" }}</p>
|
||||||
|
{{/if}}
|
||||||
<ol class="item-list">
|
<ol class="item-list">
|
||||||
{{#each equipments as |item id|}}
|
{{#each weapons as |item|}}
|
||||||
<li class="item flexrow" data-item-id="{{item._id}}">
|
<li class="item flexrow" data-item-id="{{item._id}}">
|
||||||
<img src="{{item.img}}" title="{{item.name}}" width="24" height="24" />
|
<img src="{{item.img}}" title="{{item.name}}" width="24" height="24" />
|
||||||
<h4 class="item-name">{{item.name}}</h4>
|
<h4 class="item-name">{{item.name}}</h4>
|
||||||
|
<span class="cde-badge weapon">{{ localize "CDE.WeaponType" }}</span>
|
||||||
|
{{#if item.system.damageBase}}<span class="cde-item-stat cde-item-damage">{{item.system.damageBase}}</span>{{/if}}
|
||||||
|
<div class="item-controls">
|
||||||
|
<a class="item-control cde-roll-trigger cde-weapon-roll-btn" title="{{ localize 'CDE.WeaponRoll' }}" data-libel-id="{{item._id}}-itemweapon"><i class="fas fa-dice-d10"></i></a>
|
||||||
|
<a class="item-control" title="{{ localize 'CDE.ItemEdit' }}" data-action="edit"><i class="fas fa-edit"></i></a>
|
||||||
|
<a class="item-control" title="{{ localize 'CDE.ItemDelete' }}" data-action="delete"><i class="fas fa-trash"></i></a>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{{/each}}
|
||||||
|
</ol>
|
||||||
|
<p>
|
||||||
|
<a class="item-control" title="{{ localize 'CDE.WeaponCreate' }}" data-action="create" data-type="weapon"><i class="fas fa-plus"></i> {{ localize "CDE.WeaponCreate" }}</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{{!-- Armors --}}
|
||||||
|
{{#if armors.length}}
|
||||||
|
<p class="cde-item-group-label">{{ localize "CDE.Armors" }}</p>
|
||||||
|
{{/if}}
|
||||||
|
<ol class="item-list">
|
||||||
|
{{#each armors as |item|}}
|
||||||
|
<li class="item flexrow" data-item-id="{{item._id}}">
|
||||||
|
<img src="{{item.img}}" title="{{item.name}}" width="24" height="24" />
|
||||||
|
<h4 class="item-name">{{item.name}}</h4>
|
||||||
|
<span class="cde-badge armor">{{ localize "CDE.ArmorType" }}</span>
|
||||||
|
{{#if item.system.protection}}<span class="cde-item-stat">{{item.system.protection}}</span>{{/if}}
|
||||||
|
<div class="item-controls">
|
||||||
|
<a class="item-control" title="{{ localize 'CDE.ItemEdit' }}" data-action="edit"><i class="fas fa-edit"></i></a>
|
||||||
|
<a class="item-control" title="{{ localize 'CDE.ItemDelete' }}" data-action="delete"><i class="fas fa-trash"></i></a>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{{/each}}
|
||||||
|
</ol>
|
||||||
|
<p>
|
||||||
|
<a class="item-control" title="{{ localize 'CDE.ArmorCreate' }}" data-action="create" data-type="armor"><i class="fas fa-plus"></i> {{ localize "CDE.ArmorCreate" }}</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{{!-- Generic items --}}
|
||||||
|
{{#if equipments.length}}
|
||||||
|
<p class="cde-item-group-label">{{ localize "CDE.Items" }}</p>
|
||||||
|
{{/if}}
|
||||||
|
<ol class="item-list">
|
||||||
|
{{#each equipments as |item|}}
|
||||||
|
<li class="item flexrow" data-item-id="{{item._id}}">
|
||||||
|
<img src="{{item.img}}" title="{{item.name}}" width="24" height="24" />
|
||||||
|
<h4 class="item-name">{{item.name}}</h4>
|
||||||
|
<span class="cde-badge item">{{ localize "CDE.ItemType" }}</span>
|
||||||
<div class="item-controls">
|
<div class="item-controls">
|
||||||
<a class="item-control" title="{{ localize 'CDE.ItemEdit' }}" data-action="edit"><i class="fas fa-edit"></i></a>
|
<a class="item-control" title="{{ localize 'CDE.ItemEdit' }}" data-action="edit"><i class="fas fa-edit"></i></a>
|
||||||
<a class="item-control" title="{{ localize 'CDE.ItemDelete' }}" data-action="delete"><i class="fas fa-trash"></i></a>
|
<a class="item-control" title="{{ localize 'CDE.ItemDelete' }}" data-action="delete"><i class="fas fa-trash"></i></a>
|
||||||
|
|||||||
@@ -1,15 +1,2 @@
|
|||||||
<ol class="item-list">
|
{{!-- NPC Kung-Fu tab — reuse character card design --}}
|
||||||
{{#each kungfus as |item id|}}
|
{{> "systems/fvtt-chroniques-de-l-etrange/templates/actor/parts/cde-character-kungfus.html"}}
|
||||||
<li class="item flexrow" data-item-id="{{item._id}}">
|
|
||||||
<img src="{{item.img}}" title="{{item.name}}" width="24" height="24" />
|
|
||||||
<h4 class="item-name">{{item.name}}</h4>
|
|
||||||
<div class="item-controls">
|
|
||||||
<a class="item-control" title="{{ localize 'CDE.KFEdit' }}" data-action="edit"><i class="fas fa-edit"></i></a>
|
|
||||||
<a class="item-control" title="{{ localize 'CDE.KFDelete' }}" data-action="delete"><i class="fas fa-trash"></i></a>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
{{/each}}
|
|
||||||
</ol>
|
|
||||||
<p>
|
|
||||||
<a class="item-control" title="{{ localize 'CDE.KFCreate' }}" data-action="create" data-type="kungfu"><i class="fas fa-plus"></i> {{ localize "CDE.KFCreate" }}</a>
|
|
||||||
</p>
|
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
|
{{#if spells.length}}
|
||||||
<ol class="item-list">
|
<ol class="item-list">
|
||||||
{{#each spells as |item id|}}
|
{{#each spells as |item|}}
|
||||||
<li class="item flexrow" data-item-id="{{item._id}}">
|
<li class="item flexrow" data-item-id="{{item._id}}">
|
||||||
|
{{#if item.system.aspect}}
|
||||||
|
<img class="cde-spell-aspect-icon" src="{{ getElementIcon item.system.aspect }}" title="{{item.system.aspect}}" width="24" height="24" />
|
||||||
|
{{else}}
|
||||||
<img src="{{item.img}}" title="{{item.name}}" width="24" height="24" />
|
<img src="{{item.img}}" title="{{item.name}}" width="24" height="24" />
|
||||||
|
{{/if}}
|
||||||
<h4 class="item-name">{{item.name}}</h4>
|
<h4 class="item-name">{{item.name}}</h4>
|
||||||
|
{{#if item.system.discipline}}<span class="cde-badge spell">{{item.system.discipline}}</span>{{/if}}
|
||||||
<div class="item-controls">
|
<div class="item-controls">
|
||||||
<a class="item-control" title="{{ localize 'CDE.SpellEdit' }}" data-action="edit"><i class="fas fa-edit"></i></a>
|
<a class="item-control" title="{{ localize 'CDE.SpellEdit' }}" data-action="edit"><i class="fas fa-edit"></i></a>
|
||||||
<a class="item-control" title="{{ localize 'CDE.SpellDelete' }}" data-action="delete"><i class="fas fa-trash"></i></a>
|
<a class="item-control" title="{{ localize 'CDE.SpellDelete' }}" data-action="delete"><i class="fas fa-trash"></i></a>
|
||||||
@@ -10,6 +16,9 @@
|
|||||||
</li>
|
</li>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ol>
|
</ol>
|
||||||
|
{{else}}
|
||||||
|
<p class="cde-empty-list">{{ localize "CDE.NoSpells" }}</p>
|
||||||
|
{{/if}}
|
||||||
<p>
|
<p>
|
||||||
<a class="item-control" title="{{ localize 'CDE.SpellCreate' }}" data-action="create" data-type="spell"><i class="fas fa-plus"></i> {{ localize "CDE.SpellCreate" }}</a>
|
<a class="item-control" title="{{ localize 'CDE.SpellCreate' }}" data-action="create" data-type="spell"><i class="fas fa-plus"></i> {{ localize "CDE.SpellCreate" }}</a>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -1,15 +1,37 @@
|
|||||||
<ol class="item-list">
|
{{!-- ===================== CAPACITÉS SURNATURELLES ===================== --}}
|
||||||
{{#each supernaturals as |item id|}}
|
|
||||||
<li class="item flexrow" data-item-id="{{item._id}}">
|
<div class="cde-super-add-row">
|
||||||
<img src="{{item.img}}" title="{{item.name}}" width="24" height="24" />
|
<a class="cde-super-add-btn" data-action="create" data-type="supernatural" title="{{ localize 'CDE.SupernaturalCreate' }}">
|
||||||
<h4 class="item-name">{{item.name}}</h4>
|
<i class="fas fa-plus"></i> {{ localize "CDE.SupernaturalCreate" }}
|
||||||
<div class="item-controls">
|
</a>
|
||||||
<a class="item-control" title="{{ localize 'CDE.SupernaturalEdit' }}" data-action="edit"><i class="fas fa-edit"></i></a>
|
</div>
|
||||||
<a class="item-control" title="{{ localize 'CDE.SupernaturalDelete' }}" data-action="delete"><i class="fas fa-trash"></i></a>
|
|
||||||
|
{{#if supernaturals.length}}
|
||||||
|
{{#each supernaturals as |item|}}
|
||||||
|
<div class="cde-super-card" data-item-id="{{item._id}}">
|
||||||
|
|
||||||
|
<div class="cde-super-header">
|
||||||
|
<img class="cde-super-img" src="{{item.img}}" alt="{{item.name}}" />
|
||||||
|
<div class="cde-super-info">
|
||||||
|
<span class="cde-super-name">{{item.name}}</span>
|
||||||
|
{{#if item.system.activation}}
|
||||||
|
<span class="cde-super-meta">
|
||||||
|
<span class="cde-act-badge cde-act--{{item.system.activation}}" title="{{ getActivationLabel item.system.activation }}">{{ getActivationLabel item.system.activation }}</span>
|
||||||
|
</span>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
<div class="cde-super-controls">
|
||||||
|
<a data-action="edit" data-item-id="{{item._id}}" title="{{ localize 'CDE.SupernaturalEdit' }}"><i class="fas fa-edit"></i></a>
|
||||||
|
<a data-action="delete" data-item-id="{{item._id}}" title="{{ localize 'CDE.SupernaturalDelete' }}"><i class="fas fa-trash"></i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if item.system.description}}
|
||||||
|
<div class="cde-super-desc">{{{item.system.description}}}</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</li>
|
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ol>
|
{{else}}
|
||||||
<p>
|
<p class="cde-super-empty">{{ localize "CDE.NoSupernaturals" }}</p>
|
||||||
<a class="item-control" title="{{ localize 'CDE.SupernaturalCreate' }}" data-action="create" data-type="supernatural"><i class="fas fa-plus"></i> {{ localize "CDE.SupernaturalCreate" }}</a>
|
{{/if}}
|
||||||
</p>
|
|
||||||
|
|||||||
49
templates/apps/cde-loksyu-app.html
Normal file
49
templates/apps/cde-loksyu-app.html
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{{!-- Loksyu standalone app --}}
|
||||||
|
<div class="cde-loksyu-app-body">
|
||||||
|
|
||||||
|
<div class="cde-loksyu-elements">
|
||||||
|
{{#each elements as |el|}}
|
||||||
|
<div class="cde-lok-card cde-lok-card--{{el.key}}">
|
||||||
|
<div class="cde-lok-header">
|
||||||
|
<img class="cde-lok-icon" src="{{el.img}}" alt="{{localize el.nameKey}}" width="32" height="32" />
|
||||||
|
<div class="cde-lok-titles">
|
||||||
|
<span class="cde-lok-name">{{ localize el.nameKey }}</span>
|
||||||
|
<span class="cde-lok-qual">{{ localize el.qualKey }}</span>
|
||||||
|
</div>
|
||||||
|
<a class="cde-lok-reset" data-action="resetElement" data-element="{{el.key}}" title="{{ localize 'CDE.Reset' }}">
|
||||||
|
<i class="fas fa-rotate-left"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="cde-lok-values">
|
||||||
|
<div class="cde-lok-polarity cde-lok-polarity--yang">
|
||||||
|
<span class="cde-lok-pol-label">○ {{ localize "CDE.Yang" }}</span>
|
||||||
|
<input class="cde-lok-input" type="number" min="0"
|
||||||
|
data-field="{{el.key}}.yang"
|
||||||
|
value="{{el.yang}}"
|
||||||
|
{{#unless ../canEdit}}disabled{{/unless}} />
|
||||||
|
</div>
|
||||||
|
<div class="cde-lok-polarity cde-lok-polarity--yin">
|
||||||
|
<span class="cde-lok-pol-label">● {{ localize "CDE.Yin" }}</span>
|
||||||
|
<input class="cde-lok-input" type="number" min="0"
|
||||||
|
data-field="{{el.key}}.yin"
|
||||||
|
value="{{el.yin}}"
|
||||||
|
{{#unless ../canEdit}}disabled{{/unless}} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cde-loksyu-visual-row">
|
||||||
|
<img class="cde-lok-visual" src="systems/fvtt-chroniques-de-l-etrange/images/loksyu_long.webp" alt="Loksyu" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if canEdit}}
|
||||||
|
<div class="cde-lok-footer">
|
||||||
|
<button class="cde-lok-reset-all" data-action="resetAll">
|
||||||
|
<i class="fas fa-rotate-left"></i> {{ localize "CDE.ResetAll" }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
</div>
|
||||||
35
templates/apps/cde-tinji-app.html
Normal file
35
templates/apps/cde-tinji-app.html
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{{!-- Tin Ji standalone app --}}
|
||||||
|
<div class="cde-tinji-app-body">
|
||||||
|
|
||||||
|
<div class="cde-tinji-display">
|
||||||
|
<div class="cde-tinji-chinese-large">天機</div>
|
||||||
|
<div class="cde-tinji-label">{{ localize "CDE.UpperCaseTinJi" }}</div>
|
||||||
|
|
||||||
|
<div class="cde-tinji-counter">
|
||||||
|
{{#if canEdit}}
|
||||||
|
<button class="cde-tinji-step" data-action="decrement" title="{{ localize 'CDE.Decrement' }}">−</button>
|
||||||
|
{{/if}}
|
||||||
|
<input class="cde-tinji-direct" type="number" min="0" value="{{value}}"
|
||||||
|
{{#unless canEdit}}disabled{{/unless}} />
|
||||||
|
{{#if canEdit}}
|
||||||
|
<button class="cde-tinji-step" data-action="increment" title="{{ localize 'CDE.Increment' }}">+</button>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cde-tinji-hint">{{ localize "CDE.AuspiciousDice" }}</div>
|
||||||
|
|
||||||
|
<div class="cde-tinji-actions">
|
||||||
|
<button class="cde-tinji-spend-btn" data-action="spend" {{#unless value}}disabled{{/unless}}>
|
||||||
|
<i class="fas fa-star"></i> {{ localize "CDE.SpendTinji" }}
|
||||||
|
</button>
|
||||||
|
{{#if canEdit}}
|
||||||
|
<button class="cde-tinji-reset-btn" data-action="reset">
|
||||||
|
<i class="fas fa-rotate-left"></i> {{ localize "CDE.Reset" }}
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<img class="cde-tinji-visual" src="systems/fvtt-chroniques-de-l-etrange/images/tinji.webp" alt="Tin Ji" />
|
||||||
|
|
||||||
|
</div>
|
||||||
@@ -20,6 +20,9 @@
|
|||||||
{{!-- Hero: successes count (+ spell power for magic rolls) --}}
|
{{!-- Hero: successes count (+ spell power for magic rolls) --}}
|
||||||
<div class="cde-rr-hero">
|
<div class="cde-rr-hero">
|
||||||
<span class="cde-rr-hero-count">{{successesdice}}</span>
|
<span class="cde-rr-hero-count">{{successesdice}}</span>
|
||||||
|
{{#if loksyuBonusSuc}}
|
||||||
|
<span class="cde-rr-loksyu-bonus cde-rr-loksyu-bonus--success" title="Loksyu">+{{loksyuBonusSuc}} ☯</span>
|
||||||
|
{{/if}}
|
||||||
<div class="cde-rr-hero-right">
|
<div class="cde-rr-hero-right">
|
||||||
<span class="cde-rr-hero-label">{{ localize "CDE.UpperCaseSuccesses" }}</span>
|
<span class="cde-rr-hero-label">{{ localize "CDE.UpperCaseSuccesses" }}</span>
|
||||||
<span class="cde-rr-hero-dice">{{totalDice}} <span class="cde-rr-hero-dice-label">d10</span></span>
|
<span class="cde-rr-hero-dice">{{totalDice}} <span class="cde-rr-hero-dice-label">d10</span></span>
|
||||||
@@ -37,6 +40,9 @@
|
|||||||
|
|
||||||
<div class="cde-rr-row cde-rr-row--auspicious">
|
<div class="cde-rr-row cde-rr-row--auspicious">
|
||||||
<span class="cde-rr-count">{{auspiciousdice}}</span>
|
<span class="cde-rr-count">{{auspiciousdice}}</span>
|
||||||
|
{{#if loksyuBonusFaste}}
|
||||||
|
<span class="cde-rr-loksyu-bonus cde-rr-loksyu-bonus--faste" title="Loksyu">+{{loksyuBonusFaste}} ☯</span>
|
||||||
|
{{/if}}
|
||||||
<div class="cde-rr-icon"></div>
|
<div class="cde-rr-icon"></div>
|
||||||
<span class="cde-rr-label">{{ localize "CDE.UpperCaseAuspiciousDice" }}</span>
|
<span class="cde-rr-label">{{ localize "CDE.UpperCaseAuspiciousDice" }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<section class="flexcol cde-sheet {{cssClass}}">
|
<section class="flexcol cde-sheet {{cssClass}}">
|
||||||
<header class="cde-neon-header armor">
|
<header class="cde-neon-header armor">
|
||||||
<img class="cde-avatar" src="{{item.img}}" data-edit="img" title="{{item.name}}" />
|
<img class="cde-avatar" src="{{item.img}}" data-action="editImage" data-edit="img" title="{{item.name}}" />
|
||||||
<div class="cde-header-content">
|
<div class="cde-header-content">
|
||||||
<h1 class="cde-item-name">
|
<h1 class="cde-item-name">
|
||||||
<input name="name" type="text" value="{{item.name}}" placeholder="{{ localize 'CDE.Name' }}" />
|
<input name="name" type="text" value="{{item.name}}" placeholder="{{ localize 'CDE.Name' }}" />
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<section class="flexcol cde-sheet {{cssClass}}">
|
<section class="flexcol cde-sheet {{cssClass}}">
|
||||||
<header class="cde-neon-header ingredient">
|
<header class="cde-neon-header ingredient">
|
||||||
<img class="cde-avatar" src="{{item.img}}" data-edit="img" title="{{item.name}}" />
|
<img class="cde-avatar" src="{{item.img}}" data-action="editImage" data-edit="img" title="{{item.name}}" />
|
||||||
<div class="cde-header-content">
|
<div class="cde-header-content">
|
||||||
<h1 class="cde-item-name">
|
<h1 class="cde-item-name">
|
||||||
<input name="name" type="text" value="{{item.name}}" placeholder="{{ localize 'CDE.Name' }}" />
|
<input name="name" type="text" value="{{item.name}}" placeholder="{{ localize 'CDE.Name' }}" />
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<section class="flexcol cde-sheet {{cssClass}}">
|
<section class="flexcol cde-sheet {{cssClass}}">
|
||||||
<header class="cde-neon-header item">
|
<header class="cde-neon-header item">
|
||||||
<img class="cde-avatar" src="{{item.img}}" data-edit="img" title="{{item.name}}" />
|
<img class="cde-avatar" src="{{item.img}}" data-action="editImage" data-edit="img" title="{{item.name}}" />
|
||||||
<div class="cde-header-content">
|
<div class="cde-header-content">
|
||||||
<h1 class="cde-item-name">
|
<h1 class="cde-item-name">
|
||||||
<input name="name" type="text" value="{{item.name}}" placeholder="{{ localize 'CDE.Name' }}" />
|
<input name="name" type="text" value="{{item.name}}" placeholder="{{ localize 'CDE.Name' }}" />
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<section class="flexcol cde-sheet {{cssClass}}">
|
<section class="flexcol cde-sheet {{cssClass}}">
|
||||||
<header class="cde-neon-header kungfu">
|
<header class="cde-neon-header kungfu">
|
||||||
<img class="cde-avatar" src="{{item.img}}" data-edit="img" title="{{item.name}}" />
|
<img class="cde-avatar" src="{{item.img}}" data-action="editImage" data-edit="img" title="{{item.name}}" />
|
||||||
<div class="cde-header-content">
|
<div class="cde-header-content">
|
||||||
<h1 class="cde-item-name">
|
<h1 class="cde-item-name">
|
||||||
<input name="name" type="text" value="{{item.name}}" placeholder="{{ localize 'CDE.Name' }}" />
|
<input name="name" type="text" value="{{item.name}}" placeholder="{{ localize 'CDE.Name' }}" />
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<section class="flexcol cde-sheet {{cssClass}}">
|
<section class="flexcol cde-sheet {{cssClass}}">
|
||||||
<header class="cde-neon-header sanhei">
|
<header class="cde-neon-header sanhei">
|
||||||
<img class="cde-avatar" src="{{item.img}}" data-edit="img" title="{{item.name}}" />
|
<img class="cde-avatar" src="{{item.img}}" data-action="editImage" data-edit="img" title="{{item.name}}" />
|
||||||
<div class="cde-header-content">
|
<div class="cde-header-content">
|
||||||
<h1 class="cde-item-name">
|
<h1 class="cde-item-name">
|
||||||
<input name="name" type="text" value="{{item.name}}" placeholder="{{ localize 'CDE.Name' }}" />
|
<input name="name" type="text" value="{{item.name}}" placeholder="{{ localize 'CDE.Name' }}" />
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<section class="flexcol cde-sheet {{cssClass}}">
|
<section class="flexcol cde-sheet {{cssClass}}">
|
||||||
<header class="cde-neon-header spell">
|
<header class="cde-neon-header spell">
|
||||||
<img class="cde-avatar" src="{{item.img}}" data-edit="img" title="{{item.name}}" />
|
<img class="cde-avatar" src="{{item.img}}" data-action="editImage" data-edit="img" title="{{item.name}}" />
|
||||||
<div class="cde-header-content">
|
<div class="cde-header-content">
|
||||||
<h1 class="cde-item-name">
|
<h1 class="cde-item-name">
|
||||||
<input name="name" type="text" value="{{item.name}}" placeholder="{{ localize 'CDE.Name' }}" />
|
<input name="name" type="text" value="{{item.name}}" placeholder="{{ localize 'CDE.Name' }}" />
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<section class="flexcol cde-sheet {{cssClass}}">
|
<section class="flexcol cde-sheet {{cssClass}}">
|
||||||
<header class="cde-neon-header supernatural">
|
<header class="cde-neon-header supernatural">
|
||||||
<img class="cde-avatar" src="{{item.img}}" data-edit="img" title="{{item.name}}" />
|
<img class="cde-avatar" src="{{item.img}}" data-action="editImage" data-edit="img" title="{{item.name}}" />
|
||||||
<div class="cde-header-content">
|
<div class="cde-header-content">
|
||||||
<h1 class="cde-item-name">
|
<h1 class="cde-item-name">
|
||||||
<input name="name" type="text" value="{{item.name}}" placeholder="{{ localize 'CDE.Name' }}" />
|
<input name="name" type="text" value="{{item.name}}" placeholder="{{ localize 'CDE.Name' }}" />
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<section class="flexcol cde-sheet {{cssClass}}">
|
<section class="flexcol cde-sheet {{cssClass}}">
|
||||||
<header class="cde-neon-header weapon">
|
<header class="cde-neon-header weapon">
|
||||||
<img class="cde-avatar" src="{{item.img}}" data-edit="img" title="{{item.name}}" />
|
<img class="cde-avatar" src="{{item.img}}" data-action="editImage" data-edit="img" title="{{item.name}}" />
|
||||||
<div class="cde-header-content">
|
<div class="cde-header-content">
|
||||||
<h1 class="cde-item-name">
|
<h1 class="cde-item-name">
|
||||||
<input name="name" type="text" value="{{item.name}}" placeholder="{{ localize 'CDE.Name' }}" />
|
<input name="name" type="text" value="{{item.name}}" placeholder="{{ localize 'CDE.Name' }}" />
|
||||||
|
|||||||
Reference in New Issue
Block a user