Compare commits
5 Commits
14.0.7
...
98c319767e
| Author | SHA1 | Date | |
|---|---|---|---|
| 98c319767e | |||
| 50038a13f9 | |||
| 4cb8e26333 | |||
| faf8c4ca92 | |||
| 20b41f2cd4 |
@@ -3209,7 +3209,9 @@ ol.item-list li.item h4.item-name {
|
|||||||
flex: 1 1 0;
|
flex: 1 1 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
color: #e2e8f4;
|
color: #e2e8f4;
|
||||||
|
font-family: "Signika", sans-serif;
|
||||||
}
|
}
|
||||||
ol.item-list li.item .cde-item-stat {
|
ol.item-list li.item .cde-item-stat {
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
@@ -4443,6 +4445,105 @@ ol.item-list li.item .item-controls a.item-control:hover {
|
|||||||
color: #7d94b8;
|
color: #7d94b8;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
/* Duplicate row highlight */
|
||||||
|
.cde-migration-row-duplicate {
|
||||||
|
background: rgba(212, 175, 55, 0.15);
|
||||||
|
}
|
||||||
|
.cde-migration-duplicate-icon {
|
||||||
|
color: #d4af37;
|
||||||
|
margin-right: 4px;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
/* Confirmation bar */
|
||||||
|
.cde-migration-confirm-bar {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
border: 1px solid rgba(212, 175, 55, 0.7);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: rgba(212, 175, 55, 0.1);
|
||||||
|
}
|
||||||
|
.cde-migration-confirm-msg {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #e2e8f4;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
.cde-migration-confirm-msg i {
|
||||||
|
color: #d4af37;
|
||||||
|
}
|
||||||
|
.cde-migration-confirm-duplicates {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #e07070;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
.cde-migration-confirm-duplicates i {
|
||||||
|
color: #e07070;
|
||||||
|
}
|
||||||
|
.cde-migration-confirm-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
.cde-migration-confirm-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 9px 24px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: #4a9eff;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 700;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: filter 0.15s;
|
||||||
|
}
|
||||||
|
.cde-migration-confirm-btn:hover {
|
||||||
|
filter: brightness(1.15);
|
||||||
|
}
|
||||||
|
.cde-migration-cancel-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 9px 24px;
|
||||||
|
border: 1px solid #1a2436;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: none;
|
||||||
|
color: #7d94b8;
|
||||||
|
font-size: 13px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color 0.15s, border-color 0.15s;
|
||||||
|
}
|
||||||
|
.cde-migration-cancel-btn:hover {
|
||||||
|
color: #e04444;
|
||||||
|
border-color: #e04444;
|
||||||
|
}
|
||||||
|
/* Progress section */
|
||||||
|
.cde-migration-progress {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 16px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #e2e8f4;
|
||||||
|
}
|
||||||
|
.cde-migration-progress i {
|
||||||
|
color: #4a9eff;
|
||||||
|
}
|
||||||
|
.cde-migration-progress-count {
|
||||||
|
font-weight: 700;
|
||||||
|
color: #4a9eff;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
.cde-welcome-message {
|
.cde-welcome-message {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
+107
-1
@@ -3264,7 +3264,7 @@ ol.item-list {
|
|||||||
|
|
||||||
img { border: none; border-radius: 3px; flex-shrink: 0; }
|
img { border: none; border-radius: 3px; flex-shrink: 0; }
|
||||||
|
|
||||||
h4.item-name { flex: 1 1 0; margin: 0; font-size: 13px; color: @cde-text; }
|
h4.item-name { flex: 1 1 0; margin: 0; font-size: 13px; font-weight: 600; color: @cde-text; font-family: "Signika", sans-serif; }
|
||||||
|
|
||||||
.cde-item-stat {
|
.cde-item-stat {
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
@@ -4631,6 +4631,112 @@ ol.item-list {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Duplicate row highlight */
|
||||||
|
.cde-migration-row-duplicate {
|
||||||
|
background: fadeout(#d4af37, 85%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-migration-duplicate-icon {
|
||||||
|
color: #d4af37;
|
||||||
|
margin-right: 4px;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Confirmation bar */
|
||||||
|
.cde-migration-confirm-bar {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
border: 1px solid fadeout(#d4af37, 30%);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: fadeout(#d4af37, 90%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-migration-confirm-msg {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
color: @cde-text;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
|
||||||
|
i { color: #d4af37; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-migration-confirm-duplicates {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #e07070;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
|
||||||
|
i { color: #e07070; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-migration-confirm-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-migration-confirm-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 9px 24px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: @cde-spell;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 700;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: filter 0.15s;
|
||||||
|
|
||||||
|
&:hover { filter: brightness(1.15); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-migration-cancel-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 9px 24px;
|
||||||
|
border: 1px solid @cde-border;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: none;
|
||||||
|
color: @cde-muted;
|
||||||
|
font-size: 13px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color 0.15s, border-color 0.15s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #e04444;
|
||||||
|
border-color: #e04444;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Progress section */
|
||||||
|
.cde-migration-progress {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 16px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: @cde-text;
|
||||||
|
|
||||||
|
i { color: @cde-spell; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.cde-migration-progress-count {
|
||||||
|
font-weight: 700;
|
||||||
|
color: @cde-spell;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// Welcome message
|
// Welcome message
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|||||||
Vendored
+263
-29
@@ -311,6 +311,89 @@ function migrateSupernaturalItem(oldItem) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
function migrateWeaponItem(oldItem) {
|
||||||
|
const s = oldItem.system ?? {};
|
||||||
|
return {
|
||||||
|
name: oldItem.name,
|
||||||
|
type: "weapon",
|
||||||
|
img: oldItem.img || DEFAULT_ITEM_IMG,
|
||||||
|
system: {
|
||||||
|
reference: s.reference ?? "",
|
||||||
|
description: s.description ?? "",
|
||||||
|
hasSpeciality: Boolean(s.hasSpeciality),
|
||||||
|
weaponType: s.weaponType || "melee",
|
||||||
|
material: s.material ?? "",
|
||||||
|
damageAspect: elementKey(s.damageAspect ?? ""),
|
||||||
|
damageBase: Number(s.damageBase ?? 0),
|
||||||
|
range: s.range || "contact",
|
||||||
|
obtainLevel: Number(s.obtainLevel ?? 0),
|
||||||
|
obtainDifficulty: Number(s.obtainDifficulty ?? 0),
|
||||||
|
quantity: Number(s.quantity ?? 1),
|
||||||
|
notes: s.notes ?? ""
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function migrateArmorItem(oldItem) {
|
||||||
|
const s = oldItem.system ?? {};
|
||||||
|
return {
|
||||||
|
name: oldItem.name,
|
||||||
|
type: "armor",
|
||||||
|
img: oldItem.img || DEFAULT_ITEM_IMG,
|
||||||
|
system: {
|
||||||
|
reference: s.reference ?? "",
|
||||||
|
description: s.description ?? "",
|
||||||
|
protectionValue: Number(s.protectionValue ?? 0),
|
||||||
|
domain: s.domain ?? "",
|
||||||
|
obtainLevel: Number(s.obtainLevel ?? 0),
|
||||||
|
obtainDifficulty: Number(s.obtainDifficulty ?? 0),
|
||||||
|
quantity: Number(s.quantity ?? 1),
|
||||||
|
notes: s.notes ?? ""
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function migrateSanheiItem(oldItem) {
|
||||||
|
const s = oldItem.system ?? {};
|
||||||
|
const props = s.properties ?? {};
|
||||||
|
const propSchema = (p) => ({
|
||||||
|
name: p?.name ?? "",
|
||||||
|
heiCost: Number(p?.heiCost ?? 0),
|
||||||
|
heiType: heiKey(p?.heiType ?? ""),
|
||||||
|
description: p?.description ?? ""
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
name: oldItem.name,
|
||||||
|
type: "sanhei",
|
||||||
|
img: oldItem.img || DEFAULT_ITEM_IMG,
|
||||||
|
system: {
|
||||||
|
reference: s.reference ?? "",
|
||||||
|
description: s.description ?? "",
|
||||||
|
heiType: heiKey(s.heiType ?? ""),
|
||||||
|
properties: {
|
||||||
|
prop1: propSchema(props.prop1),
|
||||||
|
prop2: propSchema(props.prop2),
|
||||||
|
prop3: propSchema(props.prop3)
|
||||||
|
},
|
||||||
|
notes: s.notes ?? ""
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function migrateIngredientItem(oldItem) {
|
||||||
|
const s = oldItem.system ?? {};
|
||||||
|
return {
|
||||||
|
name: oldItem.name,
|
||||||
|
type: "ingredient",
|
||||||
|
img: oldItem.img || DEFAULT_ITEM_IMG,
|
||||||
|
system: {
|
||||||
|
reference: s.reference ?? "",
|
||||||
|
description: s.description ?? "",
|
||||||
|
school: s.school ?? "all",
|
||||||
|
obtainLevel: Number(s.obtainLevel ?? 0),
|
||||||
|
obtainDifficulty: Number(s.obtainDifficulty ?? 0),
|
||||||
|
quantity: Number(s.quantity ?? 1),
|
||||||
|
notes: s.notes ?? ""
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
function migrateItem(oldItem) {
|
function migrateItem(oldItem) {
|
||||||
switch (oldItem.type) {
|
switch (oldItem.type) {
|
||||||
case "item":
|
case "item":
|
||||||
@@ -321,6 +404,14 @@ function migrateItem(oldItem) {
|
|||||||
return migrateSpellItem(oldItem);
|
return migrateSpellItem(oldItem);
|
||||||
case "supernatural":
|
case "supernatural":
|
||||||
return migrateSupernaturalItem(oldItem);
|
return migrateSupernaturalItem(oldItem);
|
||||||
|
case "weapon":
|
||||||
|
return migrateWeaponItem(oldItem);
|
||||||
|
case "armor":
|
||||||
|
return migrateArmorItem(oldItem);
|
||||||
|
case "sanhei":
|
||||||
|
return migrateSanheiItem(oldItem);
|
||||||
|
case "ingredient":
|
||||||
|
return migrateIngredientItem(oldItem);
|
||||||
default:
|
default:
|
||||||
return migrateEquipmentItem({ ...oldItem, type: "item" });
|
return migrateEquipmentItem({ ...oldItem, type: "item" });
|
||||||
}
|
}
|
||||||
@@ -394,6 +485,7 @@ function migrateCharacter(old) {
|
|||||||
resources,
|
resources,
|
||||||
component,
|
component,
|
||||||
magics,
|
magics,
|
||||||
|
magicOrder: [],
|
||||||
threetreasures,
|
threetreasures,
|
||||||
experience: {
|
experience: {
|
||||||
value: Number(s.experience?.value ?? 0),
|
value: Number(s.experience?.value ?? 0),
|
||||||
@@ -471,10 +563,12 @@ var CDEMigrationApp = class _CDEMigrationApp extends foundry.applications.api.Ha
|
|||||||
icon: "fas fa-file-import",
|
icon: "fas fa-file-import",
|
||||||
resizable: false
|
resizable: false
|
||||||
},
|
},
|
||||||
position: { width: 560, height: "auto" },
|
position: { width: 600, height: "auto" },
|
||||||
actions: {
|
actions: {
|
||||||
clearFiles: _CDEMigrationApp.#clearFiles,
|
clearFiles: _CDEMigrationApp.#clearFiles,
|
||||||
doImport: _CDEMigrationApp.#doImport
|
doImport: _CDEMigrationApp.#doImport,
|
||||||
|
confirmImport: _CDEMigrationApp.#confirmImport,
|
||||||
|
cancelImport: _CDEMigrationApp.#cancelImport
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
static PARTS = {
|
static PARTS = {
|
||||||
@@ -484,13 +578,28 @@ var CDEMigrationApp = class _CDEMigrationApp extends foundry.applications.api.Ha
|
|||||||
#pending = [];
|
#pending = [];
|
||||||
/** @type {string[]} - error messages per file */
|
/** @type {string[]} - error messages per file */
|
||||||
#errors = [];
|
#errors = [];
|
||||||
|
/** @type {"idle"|"confirm"|"importing"} */
|
||||||
|
#importState = "idle";
|
||||||
|
/** @type {number} - actors created so far (during importing) */
|
||||||
|
#progress = 0;
|
||||||
async _prepareContext(options) {
|
async _prepareContext(options) {
|
||||||
|
const enrichDuplicate = (a) => ({
|
||||||
|
...a,
|
||||||
|
_duplicate: game.actors?.getName(a.name) !== null
|
||||||
|
});
|
||||||
|
const pending = this.#pending.map(enrichDuplicate);
|
||||||
|
const duplicateCount = pending.filter((a) => a._duplicate).length;
|
||||||
return {
|
return {
|
||||||
pending: this.#pending,
|
pending,
|
||||||
errors: this.#errors,
|
errors: this.#errors,
|
||||||
hasPending: this.#pending.length > 0,
|
hasPending: this.#pending.length > 0,
|
||||||
hasErrors: this.#errors.length > 0,
|
hasErrors: this.#errors.length > 0,
|
||||||
count: this.#pending.length
|
hasDuplicates: duplicateCount > 0,
|
||||||
|
duplicateCount,
|
||||||
|
count: this.#pending.length,
|
||||||
|
importState: this.#importState,
|
||||||
|
progress: this.#progress,
|
||||||
|
total: this.#pending.length
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/** After render, wire up the file input. */
|
/** After render, wire up the file input. */
|
||||||
@@ -528,37 +637,59 @@ var CDEMigrationApp = class _CDEMigrationApp extends foundry.applications.api.Ha
|
|||||||
const actors = parseLegacyJson(text);
|
const actors = parseLegacyJson(text);
|
||||||
for (const actor of actors) {
|
for (const actor of actors) {
|
||||||
actor._srcFile = file.name;
|
actor._srcFile = file.name;
|
||||||
if (!this.#pending.some((p) => p.name === actor.name)) {
|
if (this.#pending.some((p) => p.name === actor.name)) {
|
||||||
this.#pending.push(actor);
|
this.#errors.push(`\xAB ${actor.name} \xBB ignor\xE9 (nom d\xE9j\xE0 dans la liste d'attente, fichier \xAB ${file.name} \xBB)`);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
this.#pending.push(actor);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.#errors.push(game.i18n.format("CDE.MigrationErrorParse", { file: file.name, error: err.message }));
|
this.#errors.push(game.i18n.format("CDE.MigrationErrorParse", { file: file.name, error: err.message }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.#importState = "idle";
|
||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
static async #clearFiles() {
|
static async #clearFiles() {
|
||||||
this.#pending = [];
|
this.#pending = [];
|
||||||
this.#errors = [];
|
this.#errors = [];
|
||||||
|
this.#importState = "idle";
|
||||||
|
this.#progress = 0;
|
||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
|
/** First click: switch to confirmation state instead of importing immediately. */
|
||||||
static async #doImport() {
|
static async #doImport() {
|
||||||
if (!this.#pending.length) return;
|
if (!this.#pending.length) return;
|
||||||
|
this.#importState = "confirm";
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
/** Second click: actually perform the import. */
|
||||||
|
static async #confirmImport() {
|
||||||
|
if (!this.#pending.length) return;
|
||||||
|
this.#importState = "importing";
|
||||||
|
this.#progress = 0;
|
||||||
|
this.render();
|
||||||
|
const total = this.#pending.length;
|
||||||
const created = [];
|
const created = [];
|
||||||
const failed = [];
|
const failed = [];
|
||||||
for (const data of this.#pending) {
|
for (let i = 0; i < total; i++) {
|
||||||
|
const data = this.#pending[i];
|
||||||
try {
|
try {
|
||||||
const { _srcFile, ...actorData } = data;
|
const { _srcFile, ...actorData } = data;
|
||||||
const actor = await Actor.create(actorData);
|
const actor = await Actor.create(actorData);
|
||||||
created.push(actor.name);
|
created.push(actor.name);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
failed.push(`${data.name}: ${err.message}`);
|
failed.push(`${data.name}: ${err.message}`);
|
||||||
console.error(`CHRONIQUESDELETRANGE | Migration failed for "${data.name}":`, err);
|
console.error(`CHRONIQUESDELETRANGE | Import failed for "${data.name}":`, err);
|
||||||
}
|
}
|
||||||
|
this.#progress = i + 1;
|
||||||
|
const progEl = this.element?.querySelector(".cde-migration-progress-count");
|
||||||
|
if (progEl) progEl.textContent = `${this.#progress}/${total}`;
|
||||||
}
|
}
|
||||||
this.#pending = [];
|
this.#pending = [];
|
||||||
this.#errors = failed;
|
this.#errors = failed;
|
||||||
|
this.#importState = "idle";
|
||||||
|
this.#progress = 0;
|
||||||
this.render();
|
this.render();
|
||||||
if (created.length) {
|
if (created.length) {
|
||||||
ui.notifications.info(
|
ui.notifications.info(
|
||||||
@@ -571,6 +702,10 @@ var CDEMigrationApp = class _CDEMigrationApp extends foundry.applications.api.Ha
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static async #cancelImport() {
|
||||||
|
this.#importState = "idle";
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// src/config/settings.js
|
// src/config/settings.js
|
||||||
@@ -661,6 +796,7 @@ function preLocalizeConfig() {
|
|||||||
magic.aspectlabel = game.i18n.localize(magic.aspectlabel);
|
magic.aspectlabel = game.i18n.localize(magic.aspectlabel);
|
||||||
Object.values(magic.speciality).forEach((spec) => {
|
Object.values(magic.speciality).forEach((spec) => {
|
||||||
spec.label = game.i18n.localize(spec.label);
|
spec.label = game.i18n.localize(spec.label);
|
||||||
|
spec.labelelementkey = spec.labelelement;
|
||||||
spec.labelelement = game.i18n.localize(spec.labelelement);
|
spec.labelelement = game.i18n.localize(spec.labelelement);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1425,6 +1561,7 @@ async function rollInitiativeNPC(actor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// src/ui/apps/singletons.js
|
// src/ui/apps/singletons.js
|
||||||
|
var SOCKET_CHANNEL = `system.${SYSTEM_ID}`;
|
||||||
function getLoksyuData() {
|
function getLoksyuData() {
|
||||||
return game.settings.get(SYSTEM_ID, "loksyuData") ?? {
|
return game.settings.get(SYSTEM_ID, "loksyuData") ?? {
|
||||||
wood: { yin: 0, yang: 0 },
|
wood: { yin: 0, yang: 0 },
|
||||||
@@ -1434,16 +1571,75 @@ function getLoksyuData() {
|
|||||||
water: { yin: 0, yang: 0 }
|
water: { yin: 0, yang: 0 }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
async function setLoksyuData(data) {
|
async function writeLoksyuData(data) {
|
||||||
await game.settings.set(SYSTEM_ID, "loksyuData", data);
|
await game.settings.set(SYSTEM_ID, "loksyuData", data);
|
||||||
Hooks.callAll("cde:loksyuUpdated", data);
|
Hooks.callAll("cde:loksyuUpdated", data);
|
||||||
}
|
}
|
||||||
|
async function writeTinjiValue(value) {
|
||||||
|
value = Math.max(0, value);
|
||||||
|
await game.settings.set(SYSTEM_ID, "tinjiData", value);
|
||||||
|
Hooks.callAll("cde:tinjiUpdated", value);
|
||||||
|
}
|
||||||
|
async function setLoksyuData(data) {
|
||||||
|
if (game.user.isGM) return writeLoksyuData(data);
|
||||||
|
game.socket.emit(SOCKET_CHANNEL, { action: "setLoksyuData", data });
|
||||||
|
}
|
||||||
function getTinjiValue() {
|
function getTinjiValue() {
|
||||||
return game.settings.get(SYSTEM_ID, "tinjiData") ?? 0;
|
return game.settings.get(SYSTEM_ID, "tinjiData") ?? 0;
|
||||||
}
|
}
|
||||||
async function setTinjiValue(value) {
|
async function setTinjiValue(value) {
|
||||||
await game.settings.set(SYSTEM_ID, "tinjiData", Math.max(0, value));
|
if (game.user.isGM) return writeTinjiValue(value);
|
||||||
Hooks.callAll("cde:tinjiUpdated", Math.max(0, value));
|
game.socket.emit(SOCKET_CHANNEL, { action: "setTinjiValue", value });
|
||||||
|
}
|
||||||
|
function requestLoksyuDraw(aspect, order) {
|
||||||
|
game.socket.emit(SOCKET_CHANNEL, { action: "loksyuDraw", aspect, order });
|
||||||
|
}
|
||||||
|
function requestTinjiSpend() {
|
||||||
|
game.socket.emit(SOCKET_CHANNEL, { action: "tinjiSpend" });
|
||||||
|
}
|
||||||
|
function registerSingletonSocket() {
|
||||||
|
game.socket.on(SOCKET_CHANNEL, async (payload) => {
|
||||||
|
if (!game.user.isGM) return;
|
||||||
|
switch (payload.action) {
|
||||||
|
case "setLoksyuData":
|
||||||
|
await writeLoksyuData(payload.data);
|
||||||
|
break;
|
||||||
|
case "setTinjiValue":
|
||||||
|
await writeTinjiValue(payload.value);
|
||||||
|
break;
|
||||||
|
case "updateLoksyuFromRoll":
|
||||||
|
await updateLoksyuFromRoll(payload.activeAspect, payload.faces);
|
||||||
|
break;
|
||||||
|
case "updateTinjiFromRoll":
|
||||||
|
await updateTinjiFromRoll(payload.delta);
|
||||||
|
break;
|
||||||
|
case "loksyuDraw": {
|
||||||
|
const data = getLoksyuData();
|
||||||
|
const entry = data[payload.aspect] ?? { yin: 0, yang: 0 };
|
||||||
|
const order = payload.order ?? "yang-first";
|
||||||
|
if (order === "yin-first") {
|
||||||
|
if (entry.yin > 0) entry.yin--;
|
||||||
|
else entry.yang--;
|
||||||
|
} else if (order === "balanced") {
|
||||||
|
if (entry.yin > entry.yang) entry.yin--;
|
||||||
|
else if (entry.yang > entry.yin) entry.yang--;
|
||||||
|
else if (entry.yang > 0) entry.yang--;
|
||||||
|
else entry.yin--;
|
||||||
|
} else {
|
||||||
|
if (entry.yang > 0) entry.yang--;
|
||||||
|
else entry.yin--;
|
||||||
|
}
|
||||||
|
data[payload.aspect] = entry;
|
||||||
|
await writeLoksyuData(data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "tinjiSpend": {
|
||||||
|
const cur = getTinjiValue();
|
||||||
|
if (cur > 0) await writeTinjiValue(cur - 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
async function updateLoksyuFromRoll(activeAspect, faces) {
|
async function updateLoksyuFromRoll(activeAspect, faces) {
|
||||||
const cycle = WU_XING_CYCLE[activeAspect];
|
const cycle = WU_XING_CYCLE[activeAspect];
|
||||||
@@ -1454,18 +1650,23 @@ async function updateLoksyuFromRoll(activeAspect, faces) {
|
|||||||
const yinCount = faces[yinFace] ?? 0;
|
const yinCount = faces[yinFace] ?? 0;
|
||||||
const yangCount = faces[yangFace] ?? 0;
|
const yangCount = faces[yangFace] ?? 0;
|
||||||
if (yinCount === 0 && yangCount === 0) return;
|
if (yinCount === 0 && yangCount === 0) return;
|
||||||
const data = getLoksyuData();
|
if (game.user.isGM) {
|
||||||
const current = data[lokAspect] ?? { yin: 0, yang: 0 };
|
const data = getLoksyuData();
|
||||||
data[lokAspect] = {
|
const current = data[lokAspect] ?? { yin: 0, yang: 0 };
|
||||||
yin: (current.yin ?? 0) + yinCount,
|
data[lokAspect] = { yin: (current.yin ?? 0) + yinCount, yang: (current.yang ?? 0) + yangCount };
|
||||||
yang: (current.yang ?? 0) + yangCount
|
await writeLoksyuData(data);
|
||||||
};
|
} else {
|
||||||
await setLoksyuData(data);
|
game.socket.emit(SOCKET_CHANNEL, { action: "updateLoksyuFromRoll", activeAspect, faces });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
async function updateTinjiFromRoll(count) {
|
async function updateTinjiFromRoll(count) {
|
||||||
if (!count || count <= 0) return;
|
if (!count || count <= 0) return;
|
||||||
const current = getTinjiValue();
|
if (game.user.isGM) {
|
||||||
await setTinjiValue(current + count);
|
const current = getTinjiValue();
|
||||||
|
await writeTinjiValue(current + count);
|
||||||
|
} else {
|
||||||
|
game.socket.emit(SOCKET_CHANNEL, { action: "updateTinjiFromRoll", delta: count });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// src/ui/rolling.js
|
// src/ui/rolling.js
|
||||||
@@ -1909,7 +2110,7 @@ async function rollForActor(actor, rollKey) {
|
|||||||
if (isMagic) {
|
if (isMagic) {
|
||||||
if (isMagicSpecial && specialLibel) {
|
if (isMagicSpecial && specialLibel) {
|
||||||
const specialCfg = MAGICS?.[skillLibel]?.speciality?.[specialLibel];
|
const specialCfg = MAGICS?.[skillLibel]?.speciality?.[specialLibel];
|
||||||
const elemName = LABELELEMENT_TO_ASPECT[specialCfg?.labelelement];
|
const elemName = LABELELEMENT_TO_ASPECT[specialCfg?.labelelementkey];
|
||||||
if (elemName) spellPowerAspectName = elemName;
|
if (elemName) spellPowerAspectName = elemName;
|
||||||
}
|
}
|
||||||
if (!spellPowerAspectName) spellPowerAspectName = ASPECT_NAMES[aspectIndex];
|
if (!spellPowerAspectName) spellPowerAspectName = ASPECT_NAMES[aspectIndex];
|
||||||
@@ -2549,6 +2750,8 @@ var CDELoksyuApp = class _CDELoksyuApp extends foundry.applications.api.Handleba
|
|||||||
};
|
};
|
||||||
/** @type {Function|null} bound hook handler */
|
/** @type {Function|null} bound hook handler */
|
||||||
_updateHook = null;
|
_updateHook = null;
|
||||||
|
/** @type {Function|null} updateSetting hook handler (for socket-propagated writes) */
|
||||||
|
_settingHook = null;
|
||||||
/** Singleton accessor — open or bring to front */
|
/** Singleton accessor — open or bring to front */
|
||||||
static open() {
|
static open() {
|
||||||
const existing = Array.from(foundry.applications.instances.values()).find(
|
const existing = Array.from(foundry.applications.instances.values()).find(
|
||||||
@@ -2583,13 +2786,24 @@ var CDELoksyuApp = class _CDELoksyuApp extends foundry.applications.api.Handleba
|
|||||||
_onRender(context, options) {
|
_onRender(context, options) {
|
||||||
super._onRender(context, options);
|
super._onRender(context, options);
|
||||||
this.#bindInputs();
|
this.#bindInputs();
|
||||||
this._updateHook = Hooks.on("cde:loksyuUpdated", () => this.render());
|
if (!this._updateHook) {
|
||||||
|
this._updateHook = Hooks.on("cde:loksyuUpdated", () => this.render());
|
||||||
|
}
|
||||||
|
if (!this._settingHook) {
|
||||||
|
this._settingHook = Hooks.on("updateSetting", (setting) => {
|
||||||
|
if (setting.key === `${SYSTEM_ID}.loksyuData`) this.render();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_onClose(options) {
|
_onClose(options) {
|
||||||
if (this._updateHook !== null) {
|
if (this._updateHook !== null) {
|
||||||
Hooks.off("cde:loksyuUpdated", this._updateHook);
|
Hooks.off("cde:loksyuUpdated", this._updateHook);
|
||||||
this._updateHook = null;
|
this._updateHook = null;
|
||||||
}
|
}
|
||||||
|
if (this._settingHook !== null) {
|
||||||
|
Hooks.off("updateSetting", this._settingHook);
|
||||||
|
this._settingHook = null;
|
||||||
|
}
|
||||||
super._onClose(options);
|
super._onClose(options);
|
||||||
}
|
}
|
||||||
#bindInputs() {
|
#bindInputs() {
|
||||||
@@ -2658,6 +2872,8 @@ var CDETinjiApp = class _CDETinjiApp extends foundry.applications.api.Handlebars
|
|||||||
};
|
};
|
||||||
/** @type {Function|null} */
|
/** @type {Function|null} */
|
||||||
_updateHook = null;
|
_updateHook = null;
|
||||||
|
/** @type {Function|null} */
|
||||||
|
_settingHook = null;
|
||||||
static open() {
|
static open() {
|
||||||
const existing = Array.from(foundry.applications.instances.values()).find(
|
const existing = Array.from(foundry.applications.instances.values()).find(
|
||||||
(app2) => app2 instanceof _CDETinjiApp
|
(app2) => app2 instanceof _CDETinjiApp
|
||||||
@@ -2679,13 +2895,24 @@ var CDETinjiApp = class _CDETinjiApp extends foundry.applications.api.Handlebars
|
|||||||
_onRender(context, options) {
|
_onRender(context, options) {
|
||||||
super._onRender(context, options);
|
super._onRender(context, options);
|
||||||
this.#bindDirectInput();
|
this.#bindDirectInput();
|
||||||
this._updateHook = Hooks.on("cde:tinjiUpdated", () => this.render());
|
if (!this._updateHook) {
|
||||||
|
this._updateHook = Hooks.on("cde:tinjiUpdated", () => this.render());
|
||||||
|
}
|
||||||
|
if (!this._settingHook) {
|
||||||
|
this._settingHook = Hooks.on("updateSetting", (setting) => {
|
||||||
|
if (setting.key === `${SYSTEM_ID}.tinjiData`) this.render();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_onClose(options) {
|
_onClose(options) {
|
||||||
if (this._updateHook !== null) {
|
if (this._updateHook !== null) {
|
||||||
Hooks.off("cde:tinjiUpdated", this._updateHook);
|
Hooks.off("cde:tinjiUpdated", this._updateHook);
|
||||||
this._updateHook = null;
|
this._updateHook = null;
|
||||||
}
|
}
|
||||||
|
if (this._settingHook !== null) {
|
||||||
|
Hooks.off("updateSetting", this._settingHook);
|
||||||
|
this._settingHook = null;
|
||||||
|
}
|
||||||
super._onClose(options);
|
super._onClose(options);
|
||||||
}
|
}
|
||||||
#bindDirectInput() {
|
#bindDirectInput() {
|
||||||
@@ -2942,8 +3169,7 @@ function refreshRollActions(rollCard, aspect, message) {
|
|||||||
const tinji = getTinjiValue();
|
const tinji = getTinjiValue();
|
||||||
const successAvail = (loksyu[aspect]?.yin ?? 0) + (loksyu[aspect]?.yang ?? 0);
|
const successAvail = (loksyu[aspect]?.yin ?? 0) + (loksyu[aspect]?.yang ?? 0);
|
||||||
const fasteAvail = (loksyu[fasteAspect]?.yin ?? 0) + (loksyu[fasteAspect]?.yang ?? 0);
|
const fasteAvail = (loksyu[fasteAspect]?.yin ?? 0) + (loksyu[fasteAspect]?.yang ?? 0);
|
||||||
const isGM = game.user.isGM;
|
const hasSomething = successAvail > 0 || fasteAvail > 0 || tinji > 0;
|
||||||
const hasSomething = successAvail > 0 || fasteAvail > 0 || isGM && tinji > 0;
|
|
||||||
if (!hasSomething) return;
|
if (!hasSomething) return;
|
||||||
const aspLabel = game.i18n.localize(ASPECT_LABELS[aspect]);
|
const aspLabel = game.i18n.localize(ASPECT_LABELS[aspect]);
|
||||||
const fasteLabel = game.i18n.localize(ASPECT_LABELS[fasteAspect]);
|
const fasteLabel = game.i18n.localize(ASPECT_LABELS[fasteAspect]);
|
||||||
@@ -2962,7 +3188,7 @@ function refreshRollActions(rollCard, aspect, message) {
|
|||||||
<span class="cde-roll-action-count">${fasteAvail}</span>
|
<span class="cde-roll-action-count">${fasteAvail}</span>
|
||||||
</button>`;
|
</button>`;
|
||||||
}
|
}
|
||||||
if (isGM && tinji > 0) {
|
if (tinji > 0) {
|
||||||
btns += `<button class="cde-roll-action-btn cde-roll-action--tinji" data-action="tinji">
|
btns += `<button class="cde-roll-action-btn cde-roll-action--tinji" data-action="tinji">
|
||||||
<span class="cde-roll-action-tinji-char">\u5929</span>
|
<span class="cde-roll-action-tinji-char">\u5929</span>
|
||||||
<span class="cde-roll-action-label">${game.i18n.localize("CDE.TinJi2")}</span>
|
<span class="cde-roll-action-label">${game.i18n.localize("CDE.TinJi2")}</span>
|
||||||
@@ -3015,7 +3241,11 @@ async function _drawFromLoksyu(message, aspect, type, aspectLabel) {
|
|||||||
else entry.yin--;
|
else entry.yin--;
|
||||||
}
|
}
|
||||||
data[aspect] = entry;
|
data[aspect] = entry;
|
||||||
await setLoksyuData(data);
|
if (game.user.isGM) {
|
||||||
|
await setLoksyuData(data);
|
||||||
|
} else {
|
||||||
|
requestLoksyuDraw(aspect, order);
|
||||||
|
}
|
||||||
const flags = message?.flags?.[SYSTEM_ID];
|
const flags = message?.flags?.[SYSTEM_ID];
|
||||||
if (flags?.rollResult && message.isOwner) {
|
if (flags?.rollResult && message.isOwner) {
|
||||||
const updated = foundry.utils.deepClone(flags.rollResult);
|
const updated = foundry.utils.deepClone(flags.rollResult);
|
||||||
@@ -3054,13 +3284,16 @@ async function _drawFromLoksyu(message, aspect, type, aspectLabel) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
async function _spendTinjiPostRoll() {
|
async function _spendTinjiPostRoll() {
|
||||||
if (!game.user.isGM) return;
|
|
||||||
const current = getTinjiValue();
|
const current = getTinjiValue();
|
||||||
if (current <= 0) {
|
if (current <= 0) {
|
||||||
ui.notifications.warn(game.i18n.localize("CDE.TinjiEmpty"));
|
ui.notifications.warn(game.i18n.localize("CDE.TinjiEmpty"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await setTinjiValue(current - 1);
|
if (game.user.isGM) {
|
||||||
|
await setTinjiValue(current - 1);
|
||||||
|
} else {
|
||||||
|
requestTinjiSpend();
|
||||||
|
}
|
||||||
await ChatMessage.create({
|
await ChatMessage.create({
|
||||||
user: game.user.id,
|
user: game.user.id,
|
||||||
content: `<div class="cde-tinji-spend-msg">
|
content: `<div class="cde-tinji-spend-msg">
|
||||||
@@ -3218,6 +3451,7 @@ Hooks.once("ready", async () => {
|
|||||||
await migrateIfNeeded();
|
await migrateIfNeeded();
|
||||||
await loadWelcomeSceneIfNeeded();
|
await loadWelcomeSceneIfNeeded();
|
||||||
CDEWheelApp.registerHooks();
|
CDEWheelApp.registerHooks();
|
||||||
|
registerSingletonSocket();
|
||||||
if (game.user.isGM) showWelcomeMessage();
|
if (game.user.isGM) showWelcomeMessage();
|
||||||
});
|
});
|
||||||
Hooks.on("renderChatLog", (_app, html) => {
|
Hooks.on("renderChatLog", (_app, html) => {
|
||||||
|
|||||||
Vendored
+2
-2
File diff suppressed because one or more lines are too long
@@ -150,6 +150,11 @@
|
|||||||
"CDE.MigrationPartialError": "{count} personnage(s) n'ont pas pu être importés.",
|
"CDE.MigrationPartialError": "{count} personnage(s) n'ont pas pu être importés.",
|
||||||
"CDE.MigrationErrorNotJson": "Le fichier « {file} » n'est pas un fichier JSON.",
|
"CDE.MigrationErrorNotJson": "Le fichier « {file} » n'est pas un fichier JSON.",
|
||||||
"CDE.MigrationErrorParse": "Erreur lors de la lecture de « {file} » : {error}",
|
"CDE.MigrationErrorParse": "Erreur lors de la lecture de « {file} » : {error}",
|
||||||
|
"CDE.MigrationConfirmAction": "Confirmer l'importation",
|
||||||
|
"CDE.MigrationDuplicate": "Ce nom existe déjà dans le monde",
|
||||||
|
"CDE.MigrationDuplicateCount": "{count} personnage(s) existent déjà dans le monde",
|
||||||
|
"CDE.MigrationImportConfirm": "Vous allez importer {count} personnage(s). Confirmez-vous ?",
|
||||||
|
"CDE.MigrationImporting": "Importation en cours...",
|
||||||
"CDE.InitiativeWheel": "Roue d'Initiative",
|
"CDE.InitiativeWheel": "Roue d'Initiative",
|
||||||
"CDE.InitiativeWheelOpen": "Ouvrir la Roue d'Initiative",
|
"CDE.InitiativeWheelOpen": "Ouvrir la Roue d'Initiative",
|
||||||
"CDE.InitiativeWheelHint": "Roue d'initiative – Les Chroniques de l'Étrange",
|
"CDE.InitiativeWheelHint": "Roue d'initiative – Les Chroniques de l'Étrange",
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
MANIFEST-000040
|
MANIFEST-000052
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/06/10-16:26:13.211312 7f2fceffd6c0 Recovering log #38
|
2026/06/14-22:49:59.100287 7f29d5fed6c0 Recovering log #50
|
||||||
2026/06/10-16:26:13.220902 7f2fceffd6c0 Delete type=3 #36
|
2026/06/14-22:49:59.110340 7f29d5fed6c0 Delete type=3 #48
|
||||||
2026/06/10-16:26:13.220927 7f2fceffd6c0 Delete type=0 #38
|
2026/06/14-22:49:59.110396 7f29d5fed6c0 Delete type=0 #50
|
||||||
2026/06/10-16:29:53.729923 7f2fce7fc6c0 Level-0 table #43: started
|
2026/06/14-22:52:09.917197 7f29d4feb6c0 Level-0 table #55: started
|
||||||
2026/06/10-16:29:53.729930 7f2fce7fc6c0 Level-0 table #43: 0 bytes OK
|
2026/06/14-22:52:09.917225 7f29d4feb6c0 Level-0 table #55: 0 bytes OK
|
||||||
2026/06/10-16:29:53.735552 7f2fce7fc6c0 Delete type=0 #41
|
2026/06/14-22:52:09.923646 7f29d4feb6c0 Delete type=0 #53
|
||||||
2026/06/10-16:29:53.741380 7f2fce7fc6c0 Manual compaction at level-0 from '!items!3aig6MWvZCRoWXPW' @ 72057594037927935 : 1 .. '!items!cXaQG1TBE0jzrbNt' @ 0 : 0; will stop at (end)
|
2026/06/14-22:52:09.923831 7f29d4feb6c0 Manual compaction at level-0 from '!items!3aig6MWvZCRoWXPW' @ 72057594037927935 : 1 .. '!items!cXaQG1TBE0jzrbNt' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/06/10-16:17:31.579029 7f301cbff6c0 Recovering log #34
|
2026/06/14-22:22:39.661219 7f29d6fef6c0 Recovering log #46
|
||||||
2026/06/10-16:17:31.588884 7f301cbff6c0 Delete type=3 #32
|
2026/06/14-22:22:39.671056 7f29d6fef6c0 Delete type=3 #44
|
||||||
2026/06/10-16:17:31.588903 7f301cbff6c0 Delete type=0 #34
|
2026/06/14-22:22:39.671114 7f29d6fef6c0 Delete type=0 #46
|
||||||
2026/06/10-16:19:32.836492 7f2fce7fc6c0 Level-0 table #39: started
|
2026/06/14-22:32:37.952133 7f29d4feb6c0 Level-0 table #51: started
|
||||||
2026/06/10-16:19:32.836504 7f2fce7fc6c0 Level-0 table #39: 0 bytes OK
|
2026/06/14-22:32:37.952163 7f29d4feb6c0 Level-0 table #51: 0 bytes OK
|
||||||
2026/06/10-16:19:32.843139 7f2fce7fc6c0 Delete type=0 #37
|
2026/06/14-22:32:37.958637 7f29d4feb6c0 Delete type=0 #49
|
||||||
2026/06/10-16:19:32.855656 7f2fce7fc6c0 Manual compaction at level-0 from '!items!3aig6MWvZCRoWXPW' @ 72057594037927935 : 1 .. '!items!cXaQG1TBE0jzrbNt' @ 0 : 0; will stop at (end)
|
2026/06/14-22:32:37.965966 7f29d4feb6c0 Manual compaction at level-0 from '!items!3aig6MWvZCRoWXPW' @ 72057594037927935 : 1 .. '!items!cXaQG1TBE0jzrbNt' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000040
|
MANIFEST-000052
|
||||||
|
|||||||
+7
-7
@@ -1,7 +1,7 @@
|
|||||||
2026/06/10-16:26:13.276120 7f301cbff6c0 Recovering log #38
|
2026/06/14-22:49:59.185177 7f29d5fed6c0 Recovering log #50
|
||||||
2026/06/10-16:26:13.285508 7f301cbff6c0 Delete type=3 #36
|
2026/06/14-22:49:59.194849 7f29d5fed6c0 Delete type=3 #48
|
||||||
2026/06/10-16:26:13.285526 7f301cbff6c0 Delete type=0 #38
|
2026/06/14-22:49:59.194912 7f29d5fed6c0 Delete type=0 #50
|
||||||
2026/06/10-16:29:53.772491 7f2fce7fc6c0 Level-0 table #43: started
|
2026/06/14-22:52:09.979071 7f29d4feb6c0 Level-0 table #55: started
|
||||||
2026/06/10-16:29:53.772502 7f2fce7fc6c0 Level-0 table #43: 0 bytes OK
|
2026/06/14-22:52:09.979102 7f29d4feb6c0 Level-0 table #55: 0 bytes OK
|
||||||
2026/06/10-16:29:53.778096 7f2fce7fc6c0 Delete type=0 #41
|
2026/06/14-22:52:09.985673 7f29d4feb6c0 Delete type=0 #53
|
||||||
2026/06/10-16:29:53.791678 7f2fce7fc6c0 Manual compaction at level-0 from '!journal!CDEGuideMain0001' @ 72057594037927935 : 1 .. '!journal.pages!CDEGuideMain0001.wgqIHHVlO9miegn1' @ 0 : 0; will stop at (end)
|
2026/06/14-22:52:10.010878 7f29d4feb6c0 Manual compaction at level-0 from '!journal!CDEGuideMain0001' @ 72057594037927935 : 1 .. '!journal.pages!CDEGuideMain0001.wgqIHHVlO9miegn1' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/06/10-16:17:31.644676 7f2fcf7fe6c0 Recovering log #34
|
2026/06/14-22:22:39.748395 7f29d6fef6c0 Recovering log #46
|
||||||
2026/06/10-16:17:31.653678 7f2fcf7fe6c0 Delete type=3 #32
|
2026/06/14-22:22:39.759263 7f29d6fef6c0 Delete type=3 #44
|
||||||
2026/06/10-16:17:31.653697 7f2fcf7fe6c0 Delete type=0 #34
|
2026/06/14-22:22:39.759326 7f29d6fef6c0 Delete type=0 #46
|
||||||
2026/06/10-16:19:32.867823 7f2fce7fc6c0 Level-0 table #39: started
|
2026/06/14-22:32:38.022572 7f29d4feb6c0 Level-0 table #51: started
|
||||||
2026/06/10-16:19:32.867836 7f2fce7fc6c0 Level-0 table #39: 0 bytes OK
|
2026/06/14-22:32:38.022623 7f29d4feb6c0 Level-0 table #51: 0 bytes OK
|
||||||
2026/06/10-16:19:32.874859 7f2fce7fc6c0 Delete type=0 #37
|
2026/06/14-22:32:38.028952 7f29d4feb6c0 Delete type=0 #49
|
||||||
2026/06/10-16:19:32.874953 7f2fce7fc6c0 Manual compaction at level-0 from '!journal!CDEGuideMain0001' @ 72057594037927935 : 1 .. '!journal.pages!CDEGuideMain0001.wgqIHHVlO9miegn1' @ 0 : 0; will stop at (end)
|
2026/06/14-22:32:38.054477 7f29d4feb6c0 Manual compaction at level-0 from '!journal!CDEGuideMain0001' @ 72057594037927935 : 1 .. '!journal.pages!CDEGuideMain0001.wgqIHHVlO9miegn1' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000040
|
MANIFEST-000052
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/06/10-16:26:13.232087 7f2fcf7fe6c0 Recovering log #38
|
2026/06/14-22:49:59.128336 7f29d5fed6c0 Recovering log #50
|
||||||
2026/06/10-16:26:13.242712 7f2fcf7fe6c0 Delete type=3 #36
|
2026/06/14-22:49:59.138475 7f29d5fed6c0 Delete type=3 #48
|
||||||
2026/06/10-16:26:13.242732 7f2fcf7fe6c0 Delete type=0 #38
|
2026/06/14-22:49:59.138521 7f29d5fed6c0 Delete type=0 #50
|
||||||
2026/06/10-16:29:53.748487 7f2fce7fc6c0 Level-0 table #43: started
|
2026/06/14-22:52:09.937223 7f29d4feb6c0 Level-0 table #55: started
|
||||||
2026/06/10-16:29:53.748497 7f2fce7fc6c0 Level-0 table #43: 0 bytes OK
|
2026/06/14-22:52:09.937263 7f29d4feb6c0 Level-0 table #55: 0 bytes OK
|
||||||
2026/06/10-16:29:53.754350 7f2fce7fc6c0 Delete type=0 #41
|
2026/06/14-22:52:09.944028 7f29d4feb6c0 Delete type=0 #53
|
||||||
2026/06/10-16:29:53.766297 7f2fce7fc6c0 Manual compaction at level-0 from '!items!0NDBw1YB54q3hLH0' @ 72057594037927935 : 1 .. '!items!ykekdZlirabRobEF' @ 0 : 0; will stop at (end)
|
2026/06/14-22:52:09.951911 7f29d4feb6c0 Manual compaction at level-0 from '!items!0NDBw1YB54q3hLH0' @ 72057594037927935 : 1 .. '!items!ykekdZlirabRobEF' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/06/10-16:17:31.600066 7f2fcf7fe6c0 Recovering log #34
|
2026/06/14-22:22:39.688631 7f29d6fef6c0 Recovering log #46
|
||||||
2026/06/10-16:17:31.609869 7f2fcf7fe6c0 Delete type=3 #32
|
2026/06/14-22:22:39.699291 7f29d6fef6c0 Delete type=3 #44
|
||||||
2026/06/10-16:17:31.609890 7f2fcf7fe6c0 Delete type=0 #34
|
2026/06/14-22:22:39.699355 7f29d6fef6c0 Delete type=0 #46
|
||||||
2026/06/10-16:19:32.843204 7f2fce7fc6c0 Level-0 table #39: started
|
2026/06/14-22:32:37.979476 7f29d4feb6c0 Level-0 table #51: started
|
||||||
2026/06/10-16:19:32.843219 7f2fce7fc6c0 Level-0 table #39: 0 bytes OK
|
2026/06/14-22:32:37.979507 7f29d4feb6c0 Level-0 table #51: 0 bytes OK
|
||||||
2026/06/10-16:19:32.849235 7f2fce7fc6c0 Delete type=0 #37
|
2026/06/14-22:32:37.985981 7f29d4feb6c0 Delete type=0 #49
|
||||||
2026/06/10-16:19:32.855663 7f2fce7fc6c0 Manual compaction at level-0 from '!items!0NDBw1YB54q3hLH0' @ 72057594037927935 : 1 .. '!items!ykekdZlirabRobEF' @ 0 : 0; will stop at (end)
|
2026/06/14-22:32:37.994186 7f29d4feb6c0 Manual compaction at level-0 from '!items!0NDBw1YB54q3hLH0' @ 72057594037927935 : 1 .. '!items!ykekdZlirabRobEF' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000040
|
MANIFEST-000052
|
||||||
|
|||||||
+7
-7
@@ -1,7 +1,7 @@
|
|||||||
2026/06/10-16:26:13.243837 7f2fcffff6c0 Recovering log #38
|
2026/06/14-22:49:59.141353 7f29d6fef6c0 Recovering log #50
|
||||||
2026/06/10-16:26:13.253357 7f2fcffff6c0 Delete type=3 #36
|
2026/06/14-22:49:59.151373 7f29d6fef6c0 Delete type=3 #48
|
||||||
2026/06/10-16:26:13.253373 7f2fcffff6c0 Delete type=0 #38
|
2026/06/14-22:49:59.151426 7f29d6fef6c0 Delete type=0 #50
|
||||||
2026/06/10-16:29:53.754405 7f2fce7fc6c0 Level-0 table #43: started
|
2026/06/14-22:52:09.944165 7f29d4feb6c0 Level-0 table #55: started
|
||||||
2026/06/10-16:29:53.754415 7f2fce7fc6c0 Level-0 table #43: 0 bytes OK
|
2026/06/14-22:52:09.944196 7f29d4feb6c0 Level-0 table #55: 0 bytes OK
|
||||||
2026/06/10-16:29:53.760076 7f2fce7fc6c0 Delete type=0 #41
|
2026/06/14-22:52:09.951751 7f29d4feb6c0 Delete type=0 #53
|
||||||
2026/06/10-16:29:53.766302 7f2fce7fc6c0 Manual compaction at level-0 from '!items!HKq5ANSGiBIdcnki' @ 72057594037927935 : 1 .. '!items!HKq5ANSGiBIdcnki' @ 0 : 0; will stop at (end)
|
2026/06/14-22:52:09.952015 7f29d4feb6c0 Manual compaction at level-0 from '!items!HKq5ANSGiBIdcnki' @ 72057594037927935 : 1 .. '!items!HKq5ANSGiBIdcnki' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/06/10-16:17:31.611312 7f2fceffd6c0 Recovering log #34
|
2026/06/14-22:22:39.702477 7f29d5fed6c0 Recovering log #46
|
||||||
2026/06/10-16:17:31.621229 7f2fceffd6c0 Delete type=3 #32
|
2026/06/14-22:22:39.712938 7f29d5fed6c0 Delete type=3 #44
|
||||||
2026/06/10-16:17:31.621250 7f2fceffd6c0 Delete type=0 #34
|
2026/06/14-22:22:39.712993 7f29d5fed6c0 Delete type=0 #46
|
||||||
2026/06/10-16:19:32.849323 7f2fce7fc6c0 Level-0 table #39: started
|
2026/06/14-22:32:37.986092 7f29d4feb6c0 Level-0 table #51: started
|
||||||
2026/06/10-16:19:32.849339 7f2fce7fc6c0 Level-0 table #39: 0 bytes OK
|
2026/06/14-22:32:37.986120 7f29d4feb6c0 Level-0 table #51: 0 bytes OK
|
||||||
2026/06/10-16:19:32.855577 7f2fce7fc6c0 Delete type=0 #37
|
2026/06/14-22:32:37.994045 7f29d4feb6c0 Delete type=0 #49
|
||||||
2026/06/10-16:19:32.874930 7f2fce7fc6c0 Manual compaction at level-0 from '!items!HKq5ANSGiBIdcnki' @ 72057594037927935 : 1 .. '!items!HKq5ANSGiBIdcnki' @ 0 : 0; will stop at (end)
|
2026/06/14-22:32:37.994361 7f29d4feb6c0 Manual compaction at level-0 from '!items!HKq5ANSGiBIdcnki' @ 72057594037927935 : 1 .. '!items!HKq5ANSGiBIdcnki' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000040
|
MANIFEST-000052
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/06/10-16:26:13.102940 7f2fcffff6c0 Recovering log #38
|
2026/06/14-22:49:59.045733 7f29d57ec6c0 Recovering log #50
|
||||||
2026/06/10-16:26:13.157514 7f2fcffff6c0 Delete type=3 #36
|
2026/06/14-22:49:59.056842 7f29d57ec6c0 Delete type=3 #48
|
||||||
2026/06/10-16:26:13.157538 7f2fcffff6c0 Delete type=0 #38
|
2026/06/14-22:49:59.056897 7f29d57ec6c0 Delete type=0 #50
|
||||||
2026/06/10-16:29:53.716605 7f2fce7fc6c0 Level-0 table #43: started
|
2026/06/14-22:52:09.896535 7f29d4feb6c0 Level-0 table #55: started
|
||||||
2026/06/10-16:29:53.716618 7f2fce7fc6c0 Level-0 table #43: 0 bytes OK
|
2026/06/14-22:52:09.896595 7f29d4feb6c0 Level-0 table #55: 0 bytes OK
|
||||||
2026/06/10-16:29:53.723647 7f2fce7fc6c0 Delete type=0 #41
|
2026/06/14-22:52:09.903914 7f29d4feb6c0 Delete type=0 #53
|
||||||
2026/06/10-16:29:53.735595 7f2fce7fc6c0 Manual compaction at level-0 from '!items!2nKXEHLG0fXtSOdy' @ 72057594037927935 : 1 .. '!items!tlIc1bmIAbQeUwj7' @ 0 : 0; will stop at (end)
|
2026/06/14-22:52:09.923752 7f29d4feb6c0 Manual compaction at level-0 from '!items!2nKXEHLG0fXtSOdy' @ 72057594037927935 : 1 .. '!items!tlIc1bmIAbQeUwj7' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/06/10-16:17:31.536886 7f301cbff6c0 Recovering log #34
|
2026/06/14-22:22:39.603745 7f29d67ee6c0 Recovering log #46
|
||||||
2026/06/10-16:17:31.546178 7f301cbff6c0 Delete type=3 #32
|
2026/06/14-22:22:39.614957 7f29d67ee6c0 Delete type=3 #44
|
||||||
2026/06/10-16:17:31.546208 7f301cbff6c0 Delete type=0 #34
|
2026/06/14-22:22:39.615010 7f29d67ee6c0 Delete type=0 #46
|
||||||
2026/06/10-16:19:32.817770 7f2fce7fc6c0 Level-0 table #39: started
|
2026/06/14-22:32:37.939036 7f29d4feb6c0 Level-0 table #51: started
|
||||||
2026/06/10-16:19:32.817789 7f2fce7fc6c0 Level-0 table #39: 0 bytes OK
|
2026/06/14-22:32:37.939102 7f29d4feb6c0 Level-0 table #51: 0 bytes OK
|
||||||
2026/06/10-16:19:32.823980 7f2fce7fc6c0 Delete type=0 #37
|
2026/06/14-22:32:37.945655 7f29d4feb6c0 Delete type=0 #49
|
||||||
2026/06/10-16:19:32.830698 7f2fce7fc6c0 Manual compaction at level-0 from '!items!2nKXEHLG0fXtSOdy' @ 72057594037927935 : 1 .. '!items!tlIc1bmIAbQeUwj7' @ 0 : 0; will stop at (end)
|
2026/06/14-22:32:37.965934 7f29d4feb6c0 Manual compaction at level-0 from '!items!2nKXEHLG0fXtSOdy' @ 72057594037927935 : 1 .. '!items!tlIc1bmIAbQeUwj7' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000040
|
MANIFEST-000052
|
||||||
|
|||||||
+7
-7
@@ -1,7 +1,7 @@
|
|||||||
2026/06/10-16:26:13.254219 7f2fceffd6c0 Recovering log #38
|
2026/06/14-22:49:59.154286 7f29d5fed6c0 Recovering log #50
|
||||||
2026/06/10-16:26:13.263234 7f2fceffd6c0 Delete type=3 #36
|
2026/06/14-22:49:59.165791 7f29d5fed6c0 Delete type=3 #48
|
||||||
2026/06/10-16:26:13.263255 7f2fceffd6c0 Delete type=0 #38
|
2026/06/14-22:49:59.165837 7f29d5fed6c0 Delete type=0 #50
|
||||||
2026/06/10-16:29:53.760191 7f2fce7fc6c0 Level-0 table #43: started
|
2026/06/14-22:52:09.952102 7f29d4feb6c0 Level-0 table #55: started
|
||||||
2026/06/10-16:29:53.760201 7f2fce7fc6c0 Level-0 table #43: 0 bytes OK
|
2026/06/14-22:52:09.952142 7f29d4feb6c0 Level-0 table #55: 0 bytes OK
|
||||||
2026/06/10-16:29:53.766249 7f2fce7fc6c0 Delete type=0 #41
|
2026/06/14-22:52:09.958682 7f29d4feb6c0 Delete type=0 #53
|
||||||
2026/06/10-16:29:53.772486 7f2fce7fc6c0 Manual compaction at level-0 from '!actors!4ZjFZ1HoJV9mJStt' @ 72057594037927935 : 1 .. '!actors!zVpmacwoWEG8YTCQ' @ 0 : 0; will stop at (end)
|
2026/06/14-22:52:09.978831 7f29d4feb6c0 Manual compaction at level-0 from '!actors!4ZjFZ1HoJV9mJStt' @ 72057594037927935 : 1 .. '!actors!zVpmacwoWEG8YTCQ' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/06/10-16:17:31.622266 7f2fcf7fe6c0 Recovering log #34
|
2026/06/14-22:22:39.716564 7f29d6fef6c0 Recovering log #46
|
||||||
2026/06/10-16:17:31.631460 7f2fcf7fe6c0 Delete type=3 #32
|
2026/06/14-22:22:39.726981 7f29d6fef6c0 Delete type=3 #44
|
||||||
2026/06/10-16:17:31.631480 7f2fcf7fe6c0 Delete type=0 #34
|
2026/06/14-22:22:39.727264 7f29d6fef6c0 Delete type=0 #46
|
||||||
2026/06/10-16:19:32.855722 7f2fce7fc6c0 Level-0 table #39: started
|
2026/06/14-22:32:37.994382 7f29d4feb6c0 Level-0 table #51: started
|
||||||
2026/06/10-16:19:32.855734 7f2fce7fc6c0 Level-0 table #39: 0 bytes OK
|
2026/06/14-22:32:37.994411 7f29d4feb6c0 Level-0 table #51: 0 bytes OK
|
||||||
2026/06/10-16:19:32.861808 7f2fce7fc6c0 Delete type=0 #37
|
2026/06/14-22:32:38.000939 7f29d4feb6c0 Delete type=0 #49
|
||||||
2026/06/10-16:19:32.874938 7f2fce7fc6c0 Manual compaction at level-0 from '!actors!4ZjFZ1HoJV9mJStt' @ 72057594037927935 : 1 .. '!actors!zVpmacwoWEG8YTCQ' @ 0 : 0; will stop at (end)
|
2026/06/14-22:32:38.022274 7f29d4feb6c0 Manual compaction at level-0 from '!actors!4ZjFZ1HoJV9mJStt' @ 72057594037927935 : 1 .. '!actors!zVpmacwoWEG8YTCQ' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000018
|
MANIFEST-000030
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2026/06/10-16:26:13.264620 7f2fceffd6c0 Recovering log #16
|
2026/06/14-22:49:59.169462 7f29d5fed6c0 Recovering log #28
|
||||||
2026/06/10-16:26:13.274036 7f2fceffd6c0 Delete type=3 #14
|
2026/06/14-22:49:59.179433 7f29d5fed6c0 Delete type=3 #26
|
||||||
2026/06/10-16:26:13.274051 7f2fceffd6c0 Delete type=0 #16
|
2026/06/14-22:49:59.179471 7f29d5fed6c0 Delete type=0 #28
|
||||||
2026/06/10-16:29:53.766305 7f2fce7fc6c0 Level-0 table #21: started
|
2026/06/14-22:52:09.985789 7f29d4feb6c0 Level-0 table #33: started
|
||||||
2026/06/10-16:29:53.766315 7f2fce7fc6c0 Level-0 table #21: 0 bytes OK
|
2026/06/14-22:52:09.985816 7f29d4feb6c0 Level-0 table #33: 0 bytes OK
|
||||||
2026/06/10-16:29:53.772397 7f2fce7fc6c0 Delete type=0 #19
|
2026/06/14-22:52:09.992966 7f29d4feb6c0 Delete type=0 #31
|
||||||
2026/06/10-16:29:53.791671 7f2fce7fc6c0 Manual compaction at level-0 from '!actors!5OGW1fRUn12aNMMV' @ 72057594037927935 : 1 .. '!actors.items!zSWwOmFiFjN4YxC9.w8LXSYQ1eIygtlKV' @ 0 : 0; will stop at (end)
|
2026/06/14-22:52:10.010894 7f29d4feb6c0 Manual compaction at level-0 from '!actors!5OGW1fRUn12aNMMV' @ 72057594037927935 : 1 .. '!actors.items!zSWwOmFiFjN4YxC9.w8LXSYQ1eIygtlKV' @ 0 : 0; will stop at (end)
|
||||||
2026/06/10-16:29:53.814542 7f2fce7fc6c0 Manual compaction at level-1 from '!actors!5OGW1fRUn12aNMMV' @ 72057594037927935 : 1 .. '!actors.items!zSWwOmFiFjN4YxC9.w8LXSYQ1eIygtlKV' @ 0 : 0; will stop at (end)
|
2026/06/14-22:52:10.011012 7f29d4feb6c0 Manual compaction at level-1 from '!actors!5OGW1fRUn12aNMMV' @ 72057594037927935 : 1 .. '!actors.items!zSWwOmFiFjN4YxC9.w8LXSYQ1eIygtlKV' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2026/06/10-16:17:31.632628 7f2fcf7fe6c0 Recovering log #12
|
2026/06/14-22:22:39.731841 7f29d6fef6c0 Recovering log #24
|
||||||
2026/06/10-16:17:31.642483 7f2fcf7fe6c0 Delete type=3 #10
|
2026/06/14-22:22:39.741957 7f29d6fef6c0 Delete type=3 #22
|
||||||
2026/06/10-16:17:31.642501 7f2fcf7fe6c0 Delete type=0 #12
|
2026/06/14-22:22:39.742028 7f29d6fef6c0 Delete type=0 #24
|
||||||
2026/06/10-16:19:32.861885 7f2fce7fc6c0 Level-0 table #17: started
|
2026/06/14-22:32:38.007843 7f29d4feb6c0 Level-0 table #29: started
|
||||||
2026/06/10-16:19:32.861895 7f2fce7fc6c0 Level-0 table #17: 0 bytes OK
|
2026/06/14-22:32:38.007886 7f29d4feb6c0 Level-0 table #29: 0 bytes OK
|
||||||
2026/06/10-16:19:32.867739 7f2fce7fc6c0 Delete type=0 #15
|
2026/06/14-22:32:38.014714 7f29d4feb6c0 Delete type=0 #27
|
||||||
2026/06/10-16:19:32.874946 7f2fce7fc6c0 Manual compaction at level-0 from '!actors!5OGW1fRUn12aNMMV' @ 72057594037927935 : 1 .. '!actors.items!zSWwOmFiFjN4YxC9.w8LXSYQ1eIygtlKV' @ 0 : 0; will stop at (end)
|
2026/06/14-22:32:38.022308 7f29d4feb6c0 Manual compaction at level-0 from '!actors!5OGW1fRUn12aNMMV' @ 72057594037927935 : 1 .. '!actors.items!zSWwOmFiFjN4YxC9.w8LXSYQ1eIygtlKV' @ 0 : 0; will stop at (end)
|
||||||
2026/06/10-16:19:32.874957 7f2fce7fc6c0 Manual compaction at level-1 from '!actors!5OGW1fRUn12aNMMV' @ 72057594037927935 : 1 .. '!actors.items!zSWwOmFiFjN4YxC9.w8LXSYQ1eIygtlKV' @ 0 : 0; will stop at (end)
|
2026/06/14-22:32:38.022452 7f29d4feb6c0 Manual compaction at level-1 from '!actors!5OGW1fRUn12aNMMV' @ 72057594037927935 : 1 .. '!actors.items!zSWwOmFiFjN4YxC9.w8LXSYQ1eIygtlKV' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000040
|
MANIFEST-000052
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/06/10-16:26:13.222183 7f2fcffff6c0 Recovering log #38
|
2026/06/14-22:49:59.113546 7f29d67ee6c0 Recovering log #50
|
||||||
2026/06/10-16:26:13.231094 7f2fcffff6c0 Delete type=3 #36
|
2026/06/14-22:49:59.125289 7f29d67ee6c0 Delete type=3 #48
|
||||||
2026/06/10-16:26:13.231111 7f2fcffff6c0 Delete type=0 #38
|
2026/06/14-22:49:59.125333 7f29d67ee6c0 Delete type=0 #50
|
||||||
2026/06/10-16:29:53.735658 7f2fce7fc6c0 Level-0 table #43: started
|
2026/06/14-22:52:09.930699 7f29d4feb6c0 Level-0 table #55: started
|
||||||
2026/06/10-16:29:53.735668 7f2fce7fc6c0 Level-0 table #43: 0 bytes OK
|
2026/06/14-22:52:09.930727 7f29d4feb6c0 Level-0 table #55: 0 bytes OK
|
||||||
2026/06/10-16:29:53.741314 7f2fce7fc6c0 Delete type=0 #41
|
2026/06/14-22:52:09.937112 7f29d4feb6c0 Delete type=0 #53
|
||||||
2026/06/10-16:29:53.754398 7f2fce7fc6c0 Manual compaction at level-0 from '!items!DC2kimCi9sWxqhXG' @ 72057594037927935 : 1 .. '!items!qzfAEhmvVxEMzm0k' @ 0 : 0; will stop at (end)
|
2026/06/14-22:52:09.951899 7f29d4feb6c0 Manual compaction at level-0 from '!items!DC2kimCi9sWxqhXG' @ 72057594037927935 : 1 .. '!items!qzfAEhmvVxEMzm0k' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/06/10-16:17:31.589862 7f2fcffff6c0 Recovering log #34
|
2026/06/14-22:22:39.674682 7f29d5fed6c0 Recovering log #46
|
||||||
2026/06/10-16:17:31.599011 7f2fcffff6c0 Delete type=3 #32
|
2026/06/14-22:22:39.685769 7f29d5fed6c0 Delete type=3 #44
|
||||||
2026/06/10-16:17:31.599029 7f2fcffff6c0 Delete type=0 #34
|
2026/06/14-22:22:39.685821 7f29d5fed6c0 Delete type=0 #46
|
||||||
2026/06/10-16:19:32.811842 7f2fce7fc6c0 Level-0 table #39: started
|
2026/06/14-22:32:37.972754 7f29d4feb6c0 Level-0 table #51: started
|
||||||
2026/06/10-16:19:32.811862 7f2fce7fc6c0 Level-0 table #39: 0 bytes OK
|
2026/06/14-22:32:37.972783 7f29d4feb6c0 Level-0 table #51: 0 bytes OK
|
||||||
2026/06/10-16:19:32.817688 7f2fce7fc6c0 Delete type=0 #37
|
2026/06/14-22:32:37.979353 7f29d4feb6c0 Delete type=0 #49
|
||||||
2026/06/10-16:19:32.830692 7f2fce7fc6c0 Manual compaction at level-0 from '!items!DC2kimCi9sWxqhXG' @ 72057594037927935 : 1 .. '!items!qzfAEhmvVxEMzm0k' @ 0 : 0; will stop at (end)
|
2026/06/14-22:32:37.994176 7f29d4feb6c0 Manual compaction at level-0 from '!items!DC2kimCi9sWxqhXG' @ 72057594037927935 : 1 .. '!items!qzfAEhmvVxEMzm0k' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000059
|
MANIFEST-000072
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/06/10-16:26:13.286742 7f2fcf7fe6c0 Recovering log #57
|
2026/06/14-22:49:59.198719 7f29d57ec6c0 Recovering log #69
|
||||||
2026/06/10-16:26:13.296421 7f2fcf7fe6c0 Delete type=3 #55
|
2026/06/14-22:49:59.210387 7f29d57ec6c0 Delete type=3 #67
|
||||||
2026/06/10-16:26:13.296441 7f2fcf7fe6c0 Delete type=0 #57
|
2026/06/14-22:49:59.210425 7f29d57ec6c0 Delete type=0 #69
|
||||||
2026/06/10-16:29:53.778131 7f2fce7fc6c0 Level-0 table #62: started
|
2026/06/14-22:52:09.958777 7f29d4feb6c0 Level-0 table #75: started
|
||||||
2026/06/10-16:29:53.778141 7f2fce7fc6c0 Level-0 table #62: 0 bytes OK
|
2026/06/14-22:52:09.958803 7f29d4feb6c0 Level-0 table #75: 0 bytes OK
|
||||||
2026/06/10-16:29:53.783939 7f2fce7fc6c0 Delete type=0 #60
|
2026/06/14-22:52:09.965059 7f29d4feb6c0 Delete type=0 #73
|
||||||
2026/06/10-16:29:53.791683 7f2fce7fc6c0 Manual compaction at level-0 from '!scenes!2C6gyZpvPxWlsVZi' @ 72057594037927935 : 1 .. '!scenes.levels!olYe9bhuXwRWQ8j7.defaultLevel0000' @ 0 : 0; will stop at (end)
|
2026/06/14-22:52:09.978852 7f29d4feb6c0 Manual compaction at level-0 from '!scenes!2C6gyZpvPxWlsVZi' @ 72057594037927935 : 1 .. '!scenes.levels!olYe9bhuXwRWQ8j7.defaultLevel0000' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
2026/06/10-16:17:31.655147 7f2fceffd6c0 Recovering log #53
|
2026/06/14-22:22:39.763440 7f29d67ee6c0 Recovering log #65
|
||||||
2026/06/10-16:17:31.664989 7f2fceffd6c0 Delete type=3 #51
|
2026/06/14-22:22:39.773982 7f29d67ee6c0 Delete type=3 #63
|
||||||
2026/06/10-16:17:31.665009 7f2fceffd6c0 Delete type=0 #53
|
2026/06/14-22:22:39.774029 7f29d67ee6c0 Delete type=0 #65
|
||||||
2026/06/10-16:19:32.875008 7f2fce7fc6c0 Level-0 table #58: started
|
2026/06/14-22:32:38.029088 7f29d4feb6c0 Level-0 table #70: started
|
||||||
2026/06/10-16:19:32.875020 7f2fce7fc6c0 Level-0 table #58: 0 bytes OK
|
2026/06/14-22:32:38.032823 7f29d4feb6c0 Level-0 table #70: 3169 bytes OK
|
||||||
2026/06/10-16:19:32.880947 7f2fce7fc6c0 Delete type=0 #56
|
2026/06/14-22:32:38.039619 7f29d4feb6c0 Delete type=0 #68
|
||||||
2026/06/10-16:19:32.903220 7f2fce7fc6c0 Manual compaction at level-0 from '!scenes!2C6gyZpvPxWlsVZi' @ 72057594037927935 : 1 .. '!scenes.levels!olYe9bhuXwRWQ8j7.defaultLevel0000' @ 0 : 0; will stop at (end)
|
2026/06/14-22:32:38.054502 7f29d4feb6c0 Manual compaction at level-0 from '!scenes!2C6gyZpvPxWlsVZi' @ 72057594037927935 : 1 .. '!scenes.levels!olYe9bhuXwRWQ8j7.defaultLevel0000' @ 0 : 0; will stop at '!scenes.levels!olYe9bhuXwRWQ8j7.defaultLevel0000' @ 29 : 1
|
||||||
|
2026/06/14-22:32:38.054509 7f29d4feb6c0 Compacting 1@0 + 1@1 files
|
||||||
|
2026/06/14-22:32:38.058254 7f29d4feb6c0 Generated table #71@0: 8 keys, 3169 bytes
|
||||||
|
2026/06/14-22:32:38.058277 7f29d4feb6c0 Compacted 1@0 + 1@1 files => 3169 bytes
|
||||||
|
2026/06/14-22:32:38.064919 7f29d4feb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
||||||
|
2026/06/14-22:32:38.065170 7f29d4feb6c0 Delete type=2 #46
|
||||||
|
2026/06/14-22:32:38.065328 7f29d4feb6c0 Delete type=2 #70
|
||||||
|
2026/06/14-22:32:38.072993 7f29d4feb6c0 Manual compaction at level-0 from '!scenes.levels!olYe9bhuXwRWQ8j7.defaultLevel0000' @ 29 : 1 .. '!scenes.levels!olYe9bhuXwRWQ8j7.defaultLevel0000' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000040
|
MANIFEST-000052
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/06/10-16:26:13.159784 7f2fceffd6c0 Recovering log #38
|
2026/06/14-22:49:59.060460 7f29d5fed6c0 Recovering log #50
|
||||||
2026/06/10-16:26:13.186364 7f2fceffd6c0 Delete type=3 #36
|
2026/06/14-22:49:59.070829 7f29d5fed6c0 Delete type=3 #48
|
||||||
2026/06/10-16:26:13.186391 7f2fceffd6c0 Delete type=0 #38
|
2026/06/14-22:49:59.070872 7f29d5fed6c0 Delete type=0 #50
|
||||||
2026/06/10-16:29:53.741387 7f2fce7fc6c0 Level-0 table #43: started
|
2026/06/14-22:52:09.904026 7f29d4feb6c0 Level-0 table #55: started
|
||||||
2026/06/10-16:29:53.741400 7f2fce7fc6c0 Level-0 table #43: 0 bytes OK
|
2026/06/14-22:52:09.904053 7f29d4feb6c0 Level-0 table #55: 0 bytes OK
|
||||||
2026/06/10-16:29:53.748439 7f2fce7fc6c0 Delete type=0 #41
|
2026/06/14-22:52:09.910627 7f29d4feb6c0 Delete type=0 #53
|
||||||
2026/06/10-16:29:53.760185 7f2fce7fc6c0 Manual compaction at level-0 from '!items!2f51pcvFkcZjaxDk' @ 72057594037927935 : 1 .. '!items!yVN7PZw35iIaBl0H' @ 0 : 0; will stop at (end)
|
2026/06/14-22:52:09.923769 7f29d4feb6c0 Manual compaction at level-0 from '!items!2f51pcvFkcZjaxDk' @ 72057594037927935 : 1 .. '!items!yVN7PZw35iIaBl0H' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/06/10-16:17:31.547590 7f2fcffff6c0 Recovering log #34
|
2026/06/14-22:22:39.618536 7f29d57ec6c0 Recovering log #46
|
||||||
2026/06/10-16:17:31.557499 7f2fcffff6c0 Delete type=3 #32
|
2026/06/14-22:22:39.628785 7f29d57ec6c0 Delete type=3 #44
|
||||||
2026/06/10-16:17:31.557521 7f2fcffff6c0 Delete type=0 #34
|
2026/06/14-22:22:39.628834 7f29d57ec6c0 Delete type=0 #46
|
||||||
2026/06/10-16:19:32.804540 7f2fce7fc6c0 Level-0 table #39: started
|
2026/06/14-22:32:37.966108 7f29d4feb6c0 Level-0 table #51: started
|
||||||
2026/06/10-16:19:32.804579 7f2fce7fc6c0 Level-0 table #39: 0 bytes OK
|
2026/06/14-22:32:37.966141 7f29d4feb6c0 Level-0 table #51: 0 bytes OK
|
||||||
2026/06/10-16:19:32.811731 7f2fce7fc6c0 Delete type=0 #37
|
2026/06/14-22:32:37.972646 7f29d4feb6c0 Delete type=0 #49
|
||||||
2026/06/10-16:19:32.830682 7f2fce7fc6c0 Manual compaction at level-0 from '!items!2f51pcvFkcZjaxDk' @ 72057594037927935 : 1 .. '!items!yVN7PZw35iIaBl0H' @ 0 : 0; will stop at (end)
|
2026/06/14-22:32:37.994161 7f29d4feb6c0 Manual compaction at level-0 from '!items!2f51pcvFkcZjaxDk' @ 72057594037927935 : 1 .. '!items!yVN7PZw35iIaBl0H' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000040
|
MANIFEST-000052
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/06/10-16:26:13.188966 7f2fcf7fe6c0 Recovering log #38
|
2026/06/14-22:49:59.074203 7f29d57ec6c0 Recovering log #50
|
||||||
2026/06/10-16:26:13.198881 7f2fcf7fe6c0 Delete type=3 #36
|
2026/06/14-22:49:59.085196 7f29d57ec6c0 Delete type=3 #48
|
||||||
2026/06/10-16:26:13.198898 7f2fcf7fe6c0 Delete type=0 #38
|
2026/06/14-22:49:59.085240 7f29d57ec6c0 Delete type=0 #50
|
||||||
2026/06/10-16:29:53.710145 7f2fce7fc6c0 Level-0 table #43: started
|
2026/06/14-22:52:09.923913 7f29d4feb6c0 Level-0 table #55: started
|
||||||
2026/06/10-16:29:53.710176 7f2fce7fc6c0 Level-0 table #43: 0 bytes OK
|
2026/06/14-22:52:09.923940 7f29d4feb6c0 Level-0 table #55: 0 bytes OK
|
||||||
2026/06/10-16:29:53.716550 7f2fce7fc6c0 Delete type=0 #41
|
2026/06/14-22:52:09.930579 7f29d4feb6c0 Delete type=0 #53
|
||||||
2026/06/10-16:29:53.735590 7f2fce7fc6c0 Manual compaction at level-0 from '!items!APN91pQL0NBfZsG7' @ 72057594037927935 : 1 .. '!items!xxZKGqDVxAfr140W' @ 0 : 0; will stop at (end)
|
2026/06/14-22:52:09.951882 7f29d4feb6c0 Manual compaction at level-0 from '!items!APN91pQL0NBfZsG7' @ 72057594037927935 : 1 .. '!items!xxZKGqDVxAfr140W' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/06/10-16:17:31.558759 7f2fcf7fe6c0 Recovering log #34
|
2026/06/14-22:22:39.633149 7f29d6fef6c0 Recovering log #46
|
||||||
2026/06/10-16:17:31.567443 7f2fcf7fe6c0 Delete type=3 #32
|
2026/06/14-22:22:39.644445 7f29d6fef6c0 Delete type=3 #44
|
||||||
2026/06/10-16:17:31.567462 7f2fcf7fe6c0 Delete type=0 #34
|
2026/06/14-22:22:39.644504 7f29d6fef6c0 Delete type=0 #46
|
||||||
2026/06/10-16:19:32.830760 7f2fce7fc6c0 Level-0 table #39: started
|
2026/06/14-22:32:37.945805 7f29d4feb6c0 Level-0 table #51: started
|
||||||
2026/06/10-16:19:32.830772 7f2fce7fc6c0 Level-0 table #39: 0 bytes OK
|
2026/06/14-22:32:37.945837 7f29d4feb6c0 Level-0 table #51: 0 bytes OK
|
||||||
2026/06/10-16:19:32.836446 7f2fce7fc6c0 Delete type=0 #37
|
2026/06/14-22:32:37.952016 7f29d4feb6c0 Delete type=0 #49
|
||||||
2026/06/10-16:19:32.855647 7f2fce7fc6c0 Manual compaction at level-0 from '!items!APN91pQL0NBfZsG7' @ 72057594037927935 : 1 .. '!items!xxZKGqDVxAfr140W' @ 0 : 0; will stop at (end)
|
2026/06/14-22:32:37.965952 7f29d4feb6c0 Manual compaction at level-0 from '!items!APN91pQL0NBfZsG7' @ 72057594037927935 : 1 .. '!items!xxZKGqDVxAfr140W' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000040
|
MANIFEST-000052
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/06/10-16:26:13.200233 7f2fcffff6c0 Recovering log #38
|
2026/06/14-22:49:59.087477 7f29d67ee6c0 Recovering log #50
|
||||||
2026/06/10-16:26:13.210096 7f2fcffff6c0 Delete type=3 #36
|
2026/06/14-22:49:59.097614 7f29d67ee6c0 Delete type=3 #48
|
||||||
2026/06/10-16:26:13.210116 7f2fcffff6c0 Delete type=0 #38
|
2026/06/14-22:49:59.097669 7f29d67ee6c0 Delete type=0 #50
|
||||||
2026/06/10-16:29:53.723688 7f2fce7fc6c0 Level-0 table #43: started
|
2026/06/14-22:52:09.910724 7f29d4feb6c0 Level-0 table #55: started
|
||||||
2026/06/10-16:29:53.723697 7f2fce7fc6c0 Level-0 table #43: 0 bytes OK
|
2026/06/14-22:52:09.910751 7f29d4feb6c0 Level-0 table #55: 0 bytes OK
|
||||||
2026/06/10-16:29:53.729865 7f2fce7fc6c0 Delete type=0 #41
|
2026/06/14-22:52:09.917084 7f29d4feb6c0 Delete type=0 #53
|
||||||
2026/06/10-16:29:53.735599 7f2fce7fc6c0 Manual compaction at level-0 from '!items!2IYbyCPF9LJojzsj' @ 72057594037927935 : 1 .. '!items!uOpWyMGK3oiUJ1Sl' @ 0 : 0; will stop at (end)
|
2026/06/14-22:52:09.923779 7f29d4feb6c0 Manual compaction at level-0 from '!items!2IYbyCPF9LJojzsj' @ 72057594037927935 : 1 .. '!items!uOpWyMGK3oiUJ1Sl' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/06/10-16:17:31.568388 7f2fceffd6c0 Recovering log #34
|
2026/06/14-22:22:39.647097 7f29d67ee6c0 Recovering log #46
|
||||||
2026/06/10-16:17:31.577902 7f2fceffd6c0 Delete type=3 #32
|
2026/06/14-22:22:39.657645 7f29d67ee6c0 Delete type=3 #44
|
||||||
2026/06/10-16:17:31.577924 7f2fceffd6c0 Delete type=0 #34
|
2026/06/14-22:22:39.657692 7f29d67ee6c0 Delete type=0 #46
|
||||||
2026/06/10-16:19:32.824041 7f2fce7fc6c0 Level-0 table #39: started
|
2026/06/14-22:32:37.958747 7f29d4feb6c0 Level-0 table #51: started
|
||||||
2026/06/10-16:19:32.824056 7f2fce7fc6c0 Level-0 table #39: 0 bytes OK
|
2026/06/14-22:32:37.958775 7f29d4feb6c0 Level-0 table #51: 0 bytes OK
|
||||||
2026/06/10-16:19:32.830626 7f2fce7fc6c0 Delete type=0 #37
|
2026/06/14-22:32:37.965805 7f29d4feb6c0 Delete type=0 #49
|
||||||
2026/06/10-16:19:32.830702 7f2fce7fc6c0 Manual compaction at level-0 from '!items!2IYbyCPF9LJojzsj' @ 72057594037927935 : 1 .. '!items!uOpWyMGK3oiUJ1Sl' @ 0 : 0; will stop at (end)
|
2026/06/14-22:32:37.966067 7f29d4feb6c0 Manual compaction at level-0 from '!items!2IYbyCPF9LJojzsj' @ 72057594037927935 : 1 .. '!items!uOpWyMGK3oiUJ1Sl' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
@@ -28,6 +28,7 @@ export function preLocalizeConfig() {
|
|||||||
magic.aspectlabel = game.i18n.localize(magic.aspectlabel)
|
magic.aspectlabel = game.i18n.localize(magic.aspectlabel)
|
||||||
Object.values(magic.speciality).forEach((spec) => {
|
Object.values(magic.speciality).forEach((spec) => {
|
||||||
spec.label = game.i18n.localize(spec.label)
|
spec.label = game.i18n.localize(spec.label)
|
||||||
|
spec.labelelementkey = spec.labelelement
|
||||||
spec.labelelement = game.i18n.localize(spec.labelelement)
|
spec.labelelement = game.i18n.localize(spec.labelelement)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -231,12 +231,103 @@ function migrateSupernaturalItem(oldItem) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function migrateWeaponItem(oldItem) {
|
||||||
|
const s = oldItem.system ?? {}
|
||||||
|
return {
|
||||||
|
name: oldItem.name,
|
||||||
|
type: "weapon",
|
||||||
|
img: oldItem.img || DEFAULT_ITEM_IMG,
|
||||||
|
system: {
|
||||||
|
reference: s.reference ?? "",
|
||||||
|
description: s.description ?? "",
|
||||||
|
hasSpeciality: Boolean(s.hasSpeciality),
|
||||||
|
weaponType: s.weaponType || "melee",
|
||||||
|
material: s.material ?? "",
|
||||||
|
damageAspect: elementKey(s.damageAspect ?? ""),
|
||||||
|
damageBase: Number(s.damageBase ?? 0),
|
||||||
|
range: s.range || "contact",
|
||||||
|
obtainLevel: Number(s.obtainLevel ?? 0),
|
||||||
|
obtainDifficulty: Number(s.obtainDifficulty ?? 0),
|
||||||
|
quantity: Number(s.quantity ?? 1),
|
||||||
|
notes: s.notes ?? "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function migrateArmorItem(oldItem) {
|
||||||
|
const s = oldItem.system ?? {}
|
||||||
|
return {
|
||||||
|
name: oldItem.name,
|
||||||
|
type: "armor",
|
||||||
|
img: oldItem.img || DEFAULT_ITEM_IMG,
|
||||||
|
system: {
|
||||||
|
reference: s.reference ?? "",
|
||||||
|
description: s.description ?? "",
|
||||||
|
protectionValue: Number(s.protectionValue ?? 0),
|
||||||
|
domain: s.domain ?? "",
|
||||||
|
obtainLevel: Number(s.obtainLevel ?? 0),
|
||||||
|
obtainDifficulty: Number(s.obtainDifficulty ?? 0),
|
||||||
|
quantity: Number(s.quantity ?? 1),
|
||||||
|
notes: s.notes ?? "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function migrateSanheiItem(oldItem) {
|
||||||
|
const s = oldItem.system ?? {}
|
||||||
|
const props = s.properties ?? {}
|
||||||
|
const propSchema = (p) => ({
|
||||||
|
name: p?.name ?? "",
|
||||||
|
heiCost: Number(p?.heiCost ?? 0),
|
||||||
|
heiType: heiKey(p?.heiType ?? ""),
|
||||||
|
description: p?.description ?? "",
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
name: oldItem.name,
|
||||||
|
type: "sanhei",
|
||||||
|
img: oldItem.img || DEFAULT_ITEM_IMG,
|
||||||
|
system: {
|
||||||
|
reference: s.reference ?? "",
|
||||||
|
description: s.description ?? "",
|
||||||
|
heiType: heiKey(s.heiType ?? ""),
|
||||||
|
properties: {
|
||||||
|
prop1: propSchema(props.prop1),
|
||||||
|
prop2: propSchema(props.prop2),
|
||||||
|
prop3: propSchema(props.prop3),
|
||||||
|
},
|
||||||
|
notes: s.notes ?? "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function migrateIngredientItem(oldItem) {
|
||||||
|
const s = oldItem.system ?? {}
|
||||||
|
return {
|
||||||
|
name: oldItem.name,
|
||||||
|
type: "ingredient",
|
||||||
|
img: oldItem.img || DEFAULT_ITEM_IMG,
|
||||||
|
system: {
|
||||||
|
reference: s.reference ?? "",
|
||||||
|
description: s.description ?? "",
|
||||||
|
school: s.school ?? "all",
|
||||||
|
obtainLevel: Number(s.obtainLevel ?? 0),
|
||||||
|
obtainDifficulty: Number(s.obtainDifficulty ?? 0),
|
||||||
|
quantity: Number(s.quantity ?? 1),
|
||||||
|
notes: s.notes ?? "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function migrateItem(oldItem) {
|
function migrateItem(oldItem) {
|
||||||
switch (oldItem.type) {
|
switch (oldItem.type) {
|
||||||
case "item": return migrateEquipmentItem(oldItem)
|
case "item": return migrateEquipmentItem(oldItem)
|
||||||
case "kungfu": return migrateKungfuItem(oldItem)
|
case "kungfu": return migrateKungfuItem(oldItem)
|
||||||
case "spell": return migrateSpellItem(oldItem)
|
case "spell": return migrateSpellItem(oldItem)
|
||||||
case "supernatural": return migrateSupernaturalItem(oldItem)
|
case "supernatural": return migrateSupernaturalItem(oldItem)
|
||||||
|
case "weapon": return migrateWeaponItem(oldItem)
|
||||||
|
case "armor": return migrateArmorItem(oldItem)
|
||||||
|
case "sanhei": return migrateSanheiItem(oldItem)
|
||||||
|
case "ingredient": return migrateIngredientItem(oldItem)
|
||||||
default:
|
default:
|
||||||
// Unknown item type: keep as generic equipment
|
// Unknown item type: keep as generic equipment
|
||||||
return migrateEquipmentItem({ ...oldItem, type: "item" })
|
return migrateEquipmentItem({ ...oldItem, type: "item" })
|
||||||
@@ -329,6 +420,7 @@ function migrateCharacter(old) {
|
|||||||
resources,
|
resources,
|
||||||
component,
|
component,
|
||||||
magics,
|
magics,
|
||||||
|
magicOrder: [],
|
||||||
threetreasures,
|
threetreasures,
|
||||||
experience: {
|
experience: {
|
||||||
value: Number(s.experience?.value ?? 0),
|
value: Number(s.experience?.value ?? 0),
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import { CDEItemSheet, CDEKungfuSheet, CDESpellSheet, CDESupernaturalSheet, CDEW
|
|||||||
import { CDELoksyuApp } from "./ui/apps/loksyu-app.js"
|
import { CDELoksyuApp } from "./ui/apps/loksyu-app.js"
|
||||||
import { CDETinjiApp } from "./ui/apps/tinji-app.js"
|
import { CDETinjiApp } from "./ui/apps/tinji-app.js"
|
||||||
import { CDEWheelApp } from "./ui/apps/wheel-app.js"
|
import { CDEWheelApp } from "./ui/apps/wheel-app.js"
|
||||||
|
import { registerSingletonSocket } from "./ui/apps/singletons.js"
|
||||||
import { injectRollActions, refreshAllRollActions } from "./ui/roll-actions.js"
|
import { injectRollActions, refreshAllRollActions } from "./ui/roll-actions.js"
|
||||||
import { CDECombat } from "./documents/combat.js"
|
import { CDECombat } from "./documents/combat.js"
|
||||||
import { showWelcomeMessage, injectWelcomeActions } from "./ui/apps/welcome.js"
|
import { showWelcomeMessage, injectWelcomeActions } from "./ui/apps/welcome.js"
|
||||||
@@ -144,6 +145,7 @@ Hooks.once("ready", async () => {
|
|||||||
await migrateIfNeeded()
|
await migrateIfNeeded()
|
||||||
await loadWelcomeSceneIfNeeded()
|
await loadWelcomeSceneIfNeeded()
|
||||||
CDEWheelApp.registerHooks()
|
CDEWheelApp.registerHooks()
|
||||||
|
registerSingletonSocket()
|
||||||
if (game.user.isGM) showWelcomeMessage()
|
if (game.user.isGM) showWelcomeMessage()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ export class CDELoksyuApp extends foundry.applications.api.HandlebarsApplication
|
|||||||
/** @type {Function|null} bound hook handler */
|
/** @type {Function|null} bound hook handler */
|
||||||
_updateHook = null
|
_updateHook = null
|
||||||
|
|
||||||
|
/** @type {Function|null} updateSetting hook handler (for socket-propagated writes) */
|
||||||
|
_settingHook = null
|
||||||
|
|
||||||
/** Singleton accessor — open or bring to front */
|
/** Singleton accessor — open or bring to front */
|
||||||
static open() {
|
static open() {
|
||||||
const existing = Array.from(foundry.applications.instances.values()).find(
|
const existing = Array.from(foundry.applications.instances.values()).find(
|
||||||
@@ -78,7 +81,14 @@ export class CDELoksyuApp extends foundry.applications.api.HandlebarsApplication
|
|||||||
super._onRender(context, options)
|
super._onRender(context, options)
|
||||||
this.#bindInputs()
|
this.#bindInputs()
|
||||||
|
|
||||||
this._updateHook = Hooks.on("cde:loksyuUpdated", () => this.render())
|
if (!this._updateHook) {
|
||||||
|
this._updateHook = Hooks.on("cde:loksyuUpdated", () => this.render())
|
||||||
|
}
|
||||||
|
if (!this._settingHook) {
|
||||||
|
this._settingHook = Hooks.on("updateSetting", (setting) => {
|
||||||
|
if (setting.key === `${SYSTEM_ID}.loksyuData`) this.render()
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onClose(options) {
|
_onClose(options) {
|
||||||
@@ -86,6 +96,10 @@ export class CDELoksyuApp extends foundry.applications.api.HandlebarsApplication
|
|||||||
Hooks.off("cde:loksyuUpdated", this._updateHook)
|
Hooks.off("cde:loksyuUpdated", this._updateHook)
|
||||||
this._updateHook = null
|
this._updateHook = null
|
||||||
}
|
}
|
||||||
|
if (this._settingHook !== null) {
|
||||||
|
Hooks.off("updateSetting", this._settingHook)
|
||||||
|
this._settingHook = null
|
||||||
|
}
|
||||||
super._onClose(options)
|
super._onClose(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,3 @@
|
|||||||
/**
|
|
||||||
* Chroniques de l'Étrange — Système FoundryVTT
|
|
||||||
*
|
|
||||||
* Chroniques de l'Étrange est un jeu de rôle édité par Antre-Monde Éditions.
|
|
||||||
* Ce système FoundryVTT est une implémentation indépendante et n'est pas
|
|
||||||
* affilié à Antre-Monde Éditions,
|
|
||||||
* mais a été réalisé avec l'autorisation d'Antre-Monde Éditions.
|
|
||||||
*
|
|
||||||
* @author LeRatierBretonnien
|
|
||||||
* @copyright 2024–2026 LeRatierBretonnien
|
|
||||||
* @license CC BY-NC-SA 4.0 – https://creativecommons.org/licenses/by-nc-sa/4.0/
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { parseLegacyJson } from "../../migration/migrator.js"
|
import { parseLegacyJson } from "../../migration/migrator.js"
|
||||||
|
|
||||||
const MIGRATION_TEMPLATE = "systems/fvtt-chroniques-de-l-etrange/templates/apps/cde-migration-app.html"
|
const MIGRATION_TEMPLATE = "systems/fvtt-chroniques-de-l-etrange/templates/apps/cde-migration-app.html"
|
||||||
@@ -33,10 +20,12 @@ export class CDEMigrationApp extends foundry.applications.api.HandlebarsApplicat
|
|||||||
icon: "fas fa-file-import",
|
icon: "fas fa-file-import",
|
||||||
resizable: false,
|
resizable: false,
|
||||||
},
|
},
|
||||||
position: { width: 560, height: "auto" },
|
position: { width: 600, height: "auto" },
|
||||||
actions: {
|
actions: {
|
||||||
clearFiles: CDEMigrationApp.#clearFiles,
|
clearFiles: CDEMigrationApp.#clearFiles,
|
||||||
doImport: CDEMigrationApp.#doImport,
|
doImport: CDEMigrationApp.#doImport,
|
||||||
|
confirmImport: CDEMigrationApp.#confirmImport,
|
||||||
|
cancelImport: CDEMigrationApp.#cancelImport,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,13 +39,31 @@ export class CDEMigrationApp extends foundry.applications.api.HandlebarsApplicat
|
|||||||
/** @type {string[]} - error messages per file */
|
/** @type {string[]} - error messages per file */
|
||||||
#errors = []
|
#errors = []
|
||||||
|
|
||||||
|
/** @type {"idle"|"confirm"|"importing"} */
|
||||||
|
#importState = "idle"
|
||||||
|
|
||||||
|
/** @type {number} - actors created so far (during importing) */
|
||||||
|
#progress = 0
|
||||||
|
|
||||||
async _prepareContext(options) {
|
async _prepareContext(options) {
|
||||||
|
// Compute _duplicate live from the world each render, to avoid stale flags
|
||||||
|
const enrichDuplicate = (a) => ({
|
||||||
|
...a,
|
||||||
|
_duplicate: game.actors?.getName(a.name) !== null,
|
||||||
|
})
|
||||||
|
const pending = this.#pending.map(enrichDuplicate)
|
||||||
|
const duplicateCount = pending.filter(a => a._duplicate).length
|
||||||
return {
|
return {
|
||||||
pending: this.#pending,
|
pending,
|
||||||
errors: this.#errors,
|
errors: this.#errors,
|
||||||
hasPending: this.#pending.length > 0,
|
hasPending: this.#pending.length > 0,
|
||||||
hasErrors: this.#errors.length > 0,
|
hasErrors: this.#errors.length > 0,
|
||||||
|
hasDuplicates: duplicateCount > 0,
|
||||||
|
duplicateCount,
|
||||||
count: this.#pending.length,
|
count: this.#pending.length,
|
||||||
|
importState: this.#importState,
|
||||||
|
progress: this.#progress,
|
||||||
|
total: this.#pending.length,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,43 +102,68 @@ export class CDEMigrationApp extends foundry.applications.api.HandlebarsApplicat
|
|||||||
const actors = parseLegacyJson(text)
|
const actors = parseLegacyJson(text)
|
||||||
for (const actor of actors) {
|
for (const actor of actors) {
|
||||||
actor._srcFile = file.name
|
actor._srcFile = file.name
|
||||||
// Avoid duplicates by name
|
// Avoid duplicates-by-name in our pending list
|
||||||
if (!this.#pending.some(p => p.name === actor.name)) {
|
if (this.#pending.some(p => p.name === actor.name)) {
|
||||||
this.#pending.push(actor)
|
this.#errors.push(`« ${actor.name} » ignoré (nom déjà dans la liste d'attente, fichier « ${file.name} »)`)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
this.#pending.push(actor)
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.#errors.push(game.i18n.format("CDE.MigrationErrorParse", { file: file.name, error: err.message }))
|
this.#errors.push(game.i18n.format("CDE.MigrationErrorParse", { file: file.name, error: err.message }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.#importState = "idle"
|
||||||
this.render()
|
this.render()
|
||||||
}
|
}
|
||||||
|
|
||||||
static async #clearFiles() {
|
static async #clearFiles() {
|
||||||
this.#pending = []
|
this.#pending = []
|
||||||
this.#errors = []
|
this.#errors = []
|
||||||
|
this.#importState = "idle"
|
||||||
|
this.#progress = 0
|
||||||
this.render()
|
this.render()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** First click: switch to confirmation state instead of importing immediately. */
|
||||||
static async #doImport() {
|
static async #doImport() {
|
||||||
if (!this.#pending.length) return
|
if (!this.#pending.length) return
|
||||||
|
this.#importState = "confirm"
|
||||||
|
this.render()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Second click: actually perform the import. */
|
||||||
|
static async #confirmImport() {
|
||||||
|
if (!this.#pending.length) return
|
||||||
|
|
||||||
|
this.#importState = "importing"
|
||||||
|
this.#progress = 0
|
||||||
|
this.render()
|
||||||
|
|
||||||
|
const total = this.#pending.length
|
||||||
const created = []
|
const created = []
|
||||||
const failed = []
|
const failed = []
|
||||||
|
|
||||||
for (const data of this.#pending) {
|
for (let i = 0; i < total; i++) {
|
||||||
|
const data = this.#pending[i]
|
||||||
try {
|
try {
|
||||||
const { _srcFile, ...actorData } = data
|
const { _srcFile, ...actorData } = data
|
||||||
const actor = await Actor.create(actorData)
|
const actor = await Actor.create(actorData)
|
||||||
created.push(actor.name)
|
created.push(actor.name)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
failed.push(`${data.name}: ${err.message}`)
|
failed.push(`${data.name}: ${err.message}`)
|
||||||
console.error(`CHRONIQUESDELETRANGE | Migration failed for "${data.name}":`, err)
|
console.error(`CHRONIQUESDELETRANGE | Import failed for "${data.name}":`, err)
|
||||||
}
|
}
|
||||||
|
this.#progress = i + 1
|
||||||
|
// Live-update the progress element in the DOM without full re-render
|
||||||
|
const progEl = this.element?.querySelector(".cde-migration-progress-count")
|
||||||
|
if (progEl) progEl.textContent = `${this.#progress}/${total}`
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#pending = []
|
this.#pending = []
|
||||||
this.#errors = failed
|
this.#errors = failed
|
||||||
|
this.#importState = "idle"
|
||||||
|
this.#progress = 0
|
||||||
this.render()
|
this.render()
|
||||||
|
|
||||||
if (created.length) {
|
if (created.length) {
|
||||||
@@ -145,4 +177,9 @@ export class CDEMigrationApp extends foundry.applications.api.HandlebarsApplicat
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async #cancelImport() {
|
||||||
|
this.#importState = "idle"
|
||||||
|
this.render()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+110
-13
@@ -15,10 +15,14 @@
|
|||||||
* Loksyu / TinJi settings-based helpers.
|
* Loksyu / TinJi settings-based helpers.
|
||||||
*
|
*
|
||||||
* Data is stored as world settings instead of singleton Actor documents.
|
* Data is stored as world settings instead of singleton Actor documents.
|
||||||
|
* Socket-based replication allows non-GM players to update Loksyu and
|
||||||
|
* TinJi — the GM processes the actual writes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { SYSTEM_ID, WU_XING_CYCLE, ASPECT_FACES } from "../../config/constants.js"
|
import { SYSTEM_ID, WU_XING_CYCLE, ASPECT_FACES } from "../../config/constants.js"
|
||||||
|
|
||||||
|
const SOCKET_CHANNEL = `system.${SYSTEM_ID}`
|
||||||
|
|
||||||
/** Read the current loksyu data object from world settings */
|
/** Read the current loksyu data object from world settings */
|
||||||
export function getLoksyuData() {
|
export function getLoksyuData() {
|
||||||
return game.settings.get(SYSTEM_ID, "loksyuData") ?? {
|
return game.settings.get(SYSTEM_ID, "loksyuData") ?? {
|
||||||
@@ -26,27 +30,112 @@ export function getLoksyuData() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Write the loksyu data object to world settings */
|
/** Write the loksyu data object to world settings (GM only). */
|
||||||
export async function setLoksyuData(data) {
|
async function writeLoksyuData(data) {
|
||||||
await game.settings.set(SYSTEM_ID, "loksyuData", data)
|
await game.settings.set(SYSTEM_ID, "loksyuData", data)
|
||||||
Hooks.callAll("cde:loksyuUpdated", data)
|
Hooks.callAll("cde:loksyuUpdated", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Write TinJi value to world settings (GM only). */
|
||||||
|
async function writeTinjiValue(value) {
|
||||||
|
value = Math.max(0, value)
|
||||||
|
await game.settings.set(SYSTEM_ID, "tinjiData", value)
|
||||||
|
Hooks.callAll("cde:tinjiUpdated", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Write the loksyu data object — non-GM emits via socket. */
|
||||||
|
export async function setLoksyuData(data) {
|
||||||
|
if (game.user.isGM) return writeLoksyuData(data)
|
||||||
|
game.socket.emit(SOCKET_CHANNEL, { action: "setLoksyuData", data })
|
||||||
|
}
|
||||||
|
|
||||||
/** Read current TinJi value from world settings */
|
/** Read current TinJi value from world settings */
|
||||||
export function getTinjiValue() {
|
export function getTinjiValue() {
|
||||||
return game.settings.get(SYSTEM_ID, "tinjiData") ?? 0
|
return game.settings.get(SYSTEM_ID, "tinjiData") ?? 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Write TinJi value to world settings */
|
/** Write TinJi value — non-GM emits via socket. */
|
||||||
export async function setTinjiValue(value) {
|
export async function setTinjiValue(value) {
|
||||||
await game.settings.set(SYSTEM_ID, "tinjiData", Math.max(0, value))
|
if (game.user.isGM) return writeTinjiValue(value)
|
||||||
Hooks.callAll("cde:tinjiUpdated", Math.max(0, value))
|
game.socket.emit(SOCKET_CHANNEL, { action: "setTinjiValue", value })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Non-GM: request an atomic Loksyu die draw via socket. The GM reads
|
||||||
|
* current state, decrements, and writes — avoiding stale-read races.
|
||||||
|
*/
|
||||||
|
export function requestLoksyuDraw(aspect, order) {
|
||||||
|
game.socket.emit(SOCKET_CHANNEL, { action: "loksyuDraw", aspect, order })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Non-GM: request an atomic TinJi spend via socket. The GM reads current
|
||||||
|
* value, decrements if > 0, and writes.
|
||||||
|
*/
|
||||||
|
export function requestTinjiSpend() {
|
||||||
|
game.socket.emit(SOCKET_CHANNEL, { action: "tinjiSpend" })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the socket listener that processes Loksyu/TinJi write requests
|
||||||
|
* from non-GM clients. Only the GM actually performs the writes; other
|
||||||
|
* clients ignore the message.
|
||||||
|
*
|
||||||
|
* Must be called after the `ready` hook (when game.socket is available).
|
||||||
|
*/
|
||||||
|
export function registerSingletonSocket() {
|
||||||
|
game.socket.on(SOCKET_CHANNEL, async (payload) => {
|
||||||
|
if (!game.user.isGM) return
|
||||||
|
switch (payload.action) {
|
||||||
|
case "setLoksyuData":
|
||||||
|
await writeLoksyuData(payload.data)
|
||||||
|
break
|
||||||
|
case "setTinjiValue":
|
||||||
|
await writeTinjiValue(payload.value)
|
||||||
|
break
|
||||||
|
case "updateLoksyuFromRoll":
|
||||||
|
await updateLoksyuFromRoll(payload.activeAspect, payload.faces)
|
||||||
|
break
|
||||||
|
case "updateTinjiFromRoll":
|
||||||
|
await updateTinjiFromRoll(payload.delta)
|
||||||
|
break
|
||||||
|
case "loksyuDraw": {
|
||||||
|
const data = getLoksyuData()
|
||||||
|
const entry = data[payload.aspect] ?? { yin: 0, yang: 0 }
|
||||||
|
const order = payload.order ?? "yang-first"
|
||||||
|
if (order === "yin-first") {
|
||||||
|
if (entry.yin > 0) entry.yin--
|
||||||
|
else entry.yang--
|
||||||
|
} else if (order === "balanced") {
|
||||||
|
if (entry.yin > entry.yang) entry.yin--
|
||||||
|
else if (entry.yang > entry.yin) entry.yang--
|
||||||
|
else if (entry.yang > 0) entry.yang--
|
||||||
|
else entry.yin--
|
||||||
|
} else {
|
||||||
|
if (entry.yang > 0) entry.yang--
|
||||||
|
else entry.yin--
|
||||||
|
}
|
||||||
|
data[payload.aspect] = entry
|
||||||
|
await writeLoksyuData(data)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case "tinjiSpend": {
|
||||||
|
const cur = getTinjiValue()
|
||||||
|
if (cur > 0) await writeTinjiValue(cur - 1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* After a WuXing roll, add the loksyu faces (yin + yang) of the relevant
|
* After a WuXing roll, add the loksyu faces (yin + yang) of the relevant
|
||||||
* aspect to the loksyu settings data.
|
* aspect to the loksyu settings data.
|
||||||
*
|
*
|
||||||
|
* Non-GM: emits raw activeAspect+faces via socket so the GM recomputes
|
||||||
|
* from current state — avoids stale-read races when two players roll
|
||||||
|
* simultaneously.
|
||||||
|
*
|
||||||
* @param {string} activeAspect - e.g. "fire"
|
* @param {string} activeAspect - e.g. "fire"
|
||||||
* @param {Object} faces - Die face counts { 0: n, 1: n, …, 9: n }
|
* @param {Object} faces - Die face counts { 0: n, 1: n, …, 9: n }
|
||||||
*/
|
*/
|
||||||
@@ -62,22 +151,30 @@ export async function updateLoksyuFromRoll(activeAspect, faces) {
|
|||||||
const yangCount = faces[yangFace] ?? 0
|
const yangCount = faces[yangFace] ?? 0
|
||||||
if (yinCount === 0 && yangCount === 0) return
|
if (yinCount === 0 && yangCount === 0) return
|
||||||
|
|
||||||
const data = getLoksyuData()
|
if (game.user.isGM) {
|
||||||
const current = data[lokAspect] ?? { yin: 0, yang: 0 }
|
const data = getLoksyuData()
|
||||||
data[lokAspect] = {
|
const current = data[lokAspect] ?? { yin: 0, yang: 0 }
|
||||||
yin: (current.yin ?? 0) + yinCount,
|
data[lokAspect] = { yin: (current.yin ?? 0) + yinCount, yang: (current.yang ?? 0) + yangCount }
|
||||||
yang: (current.yang ?? 0) + yangCount,
|
await writeLoksyuData(data)
|
||||||
|
} else {
|
||||||
|
game.socket.emit(SOCKET_CHANNEL, { action: "updateLoksyuFromRoll", activeAspect, faces })
|
||||||
}
|
}
|
||||||
await setLoksyuData(data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* After a WuXing roll, add tinji faces to the TinJi settings.
|
* After a WuXing roll, add tinji faces to the TinJi settings.
|
||||||
*
|
*
|
||||||
|
* Non-GM: emits delta via socket so the GM adds to the current value
|
||||||
|
* atomically.
|
||||||
|
*
|
||||||
* @param {number} count - Number of tinji faces rolled
|
* @param {number} count - Number of tinji faces rolled
|
||||||
*/
|
*/
|
||||||
export async function updateTinjiFromRoll(count) {
|
export async function updateTinjiFromRoll(count) {
|
||||||
if (!count || count <= 0) return
|
if (!count || count <= 0) return
|
||||||
const current = getTinjiValue()
|
if (game.user.isGM) {
|
||||||
await setTinjiValue(current + count)
|
const current = getTinjiValue()
|
||||||
|
await writeTinjiValue(current + count)
|
||||||
|
} else {
|
||||||
|
game.socket.emit(SOCKET_CHANNEL, { action: "updateTinjiFromRoll", delta: count })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ export class CDETinjiApp extends foundry.applications.api.HandlebarsApplicationM
|
|||||||
/** @type {Function|null} */
|
/** @type {Function|null} */
|
||||||
_updateHook = null
|
_updateHook = null
|
||||||
|
|
||||||
|
/** @type {Function|null} */
|
||||||
|
_settingHook = null
|
||||||
|
|
||||||
static open() {
|
static open() {
|
||||||
const existing = Array.from(foundry.applications.instances.values()).find(
|
const existing = Array.from(foundry.applications.instances.values()).find(
|
||||||
(app) => app instanceof CDETinjiApp
|
(app) => app instanceof CDETinjiApp
|
||||||
@@ -64,7 +67,14 @@ export class CDETinjiApp extends foundry.applications.api.HandlebarsApplicationM
|
|||||||
_onRender(context, options) {
|
_onRender(context, options) {
|
||||||
super._onRender(context, options)
|
super._onRender(context, options)
|
||||||
this.#bindDirectInput()
|
this.#bindDirectInput()
|
||||||
this._updateHook = Hooks.on("cde:tinjiUpdated", () => this.render())
|
if (!this._updateHook) {
|
||||||
|
this._updateHook = Hooks.on("cde:tinjiUpdated", () => this.render())
|
||||||
|
}
|
||||||
|
if (!this._settingHook) {
|
||||||
|
this._settingHook = Hooks.on("updateSetting", (setting) => {
|
||||||
|
if (setting.key === `${SYSTEM_ID}.tinjiData`) this.render()
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onClose(options) {
|
_onClose(options) {
|
||||||
@@ -72,6 +82,10 @@ export class CDETinjiApp extends foundry.applications.api.HandlebarsApplicationM
|
|||||||
Hooks.off("cde:tinjiUpdated", this._updateHook)
|
Hooks.off("cde:tinjiUpdated", this._updateHook)
|
||||||
this._updateHook = null
|
this._updateHook = null
|
||||||
}
|
}
|
||||||
|
if (this._settingHook !== null) {
|
||||||
|
Hooks.off("updateSetting", this._settingHook)
|
||||||
|
this._settingHook = null
|
||||||
|
}
|
||||||
super._onClose(options)
|
super._onClose(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-7
@@ -20,7 +20,7 @@
|
|||||||
* with the new counts, without creating noise.
|
* with the new counts, without creating noise.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getLoksyuData, setLoksyuData, getTinjiValue, setTinjiValue } from "./apps/singletons.js"
|
import { getLoksyuData, setLoksyuData, getTinjiValue, setTinjiValue, requestLoksyuDraw, requestTinjiSpend } from "./apps/singletons.js"
|
||||||
import { SYSTEM_ID, WU_XING_CYCLE, ASPECT_LABELS, ASPECT_ICONS } from "../config/constants.js"
|
import { SYSTEM_ID, WU_XING_CYCLE, ASPECT_LABELS, ASPECT_ICONS } from "../config/constants.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"
|
||||||
@@ -53,9 +53,8 @@ function refreshRollActions(rollCard, aspect, message) {
|
|||||||
|
|
||||||
const successAvail = (loksyu[aspect]?.yin ?? 0) + (loksyu[aspect]?.yang ?? 0)
|
const successAvail = (loksyu[aspect]?.yin ?? 0) + (loksyu[aspect]?.yang ?? 0)
|
||||||
const fasteAvail = (loksyu[fasteAspect]?.yin ?? 0) + (loksyu[fasteAspect]?.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)
|
const hasSomething = successAvail > 0 || fasteAvail > 0 || tinji > 0
|
||||||
if (!hasSomething) return
|
if (!hasSomething) return
|
||||||
|
|
||||||
const aspLabel = game.i18n.localize(ASPECT_LABELS[aspect])
|
const aspLabel = game.i18n.localize(ASPECT_LABELS[aspect])
|
||||||
@@ -79,7 +78,7 @@ function refreshRollActions(rollCard, aspect, message) {
|
|||||||
</button>`
|
</button>`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isGM && tinji > 0) {
|
if (tinji > 0) {
|
||||||
btns += `<button class="cde-roll-action-btn cde-roll-action--tinji" data-action="tinji">
|
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-tinji-char">天</span>
|
||||||
<span class="cde-roll-action-label">${game.i18n.localize("CDE.TinJi2")}</span>
|
<span class="cde-roll-action-label">${game.i18n.localize("CDE.TinJi2")}</span>
|
||||||
@@ -149,7 +148,11 @@ async function _drawFromLoksyu(message, aspect, type, aspectLabel) {
|
|||||||
else entry.yin--
|
else entry.yin--
|
||||||
}
|
}
|
||||||
data[aspect] = entry
|
data[aspect] = entry
|
||||||
await setLoksyuData(data)
|
if (game.user.isGM) {
|
||||||
|
await setLoksyuData(data)
|
||||||
|
} else {
|
||||||
|
requestLoksyuDraw(aspect, order)
|
||||||
|
}
|
||||||
|
|
||||||
// Update the roll-result message in-place if it has stored flags
|
// Update the roll-result message in-place if it has stored flags
|
||||||
const flags = message?.flags?.[SYSTEM_ID]
|
const flags = message?.flags?.[SYSTEM_ID]
|
||||||
@@ -200,13 +203,16 @@ async function _drawFromLoksyu(message, aspect, type, aspectLabel) {
|
|||||||
* Spend 1 Tin Ji point (GM only) and post a notification.
|
* Spend 1 Tin Ji point (GM only) and post a notification.
|
||||||
*/
|
*/
|
||||||
async function _spendTinjiPostRoll() {
|
async function _spendTinjiPostRoll() {
|
||||||
if (!game.user.isGM) return
|
|
||||||
const current = getTinjiValue()
|
const current = getTinjiValue()
|
||||||
if (current <= 0) {
|
if (current <= 0) {
|
||||||
ui.notifications.warn(game.i18n.localize("CDE.TinjiEmpty"))
|
ui.notifications.warn(game.i18n.localize("CDE.TinjiEmpty"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
await setTinjiValue(current - 1)
|
if (game.user.isGM) {
|
||||||
|
await setTinjiValue(current - 1)
|
||||||
|
} else {
|
||||||
|
requestTinjiSpend()
|
||||||
|
}
|
||||||
await ChatMessage.create({
|
await ChatMessage.create({
|
||||||
user: game.user.id,
|
user: game.user.id,
|
||||||
content: `<div class="cde-tinji-spend-msg">
|
content: `<div class="cde-tinji-spend-msg">
|
||||||
|
|||||||
+1
-1
@@ -541,7 +541,7 @@ export async function rollForActor(actor, rollKey) {
|
|||||||
if (isMagic) {
|
if (isMagic) {
|
||||||
if (isMagicSpecial && specialLibel) {
|
if (isMagicSpecial && specialLibel) {
|
||||||
const specialCfg = MAGICS?.[skillLibel]?.speciality?.[specialLibel]
|
const specialCfg = MAGICS?.[skillLibel]?.speciality?.[specialLibel]
|
||||||
const elemName = LABELELEMENT_TO_ASPECT[specialCfg?.labelelement]
|
const elemName = LABELELEMENT_TO_ASPECT[specialCfg?.labelelementkey]
|
||||||
if (elemName) spellPowerAspectName = elemName
|
if (elemName) spellPowerAspectName = elemName
|
||||||
}
|
}
|
||||||
if (!spellPowerAspectName) spellPowerAspectName = ASPECT_NAMES[aspectIndex]
|
if (!spellPowerAspectName) spellPowerAspectName = ASPECT_NAMES[aspectIndex]
|
||||||
|
|||||||
+2
-1
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"id": "fvtt-chroniques-de-l-etrange",
|
"id": "fvtt-chroniques-de-l-etrange",
|
||||||
"version": "13.0.0",
|
"version": "13.0.0",
|
||||||
|
"socket": true,
|
||||||
"title": "Les Chroniques de l'Étrange",
|
"title": "Les Chroniques de l'Étrange",
|
||||||
"url": "https://www.uberwald.me/gitea/uberwald/fvtt-chroniques-de-l-etrange",
|
"url": "https://www.uberwald.me/gitea/uberwald/fvtt-chroniques-de-l-etrange",
|
||||||
"description": "Game system for Les Chroniques de l'Étrange, from Antre-Monde éditions",
|
"description": "Game system for Les Chroniques de l'Étrange, from Antre-Monde éditions",
|
||||||
@@ -245,7 +246,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"compatibility": {
|
"compatibility": {
|
||||||
"minimum": "13",
|
"minimum": "14",
|
||||||
"verified": "14"
|
"verified": "14"
|
||||||
},
|
},
|
||||||
"relationships": {},
|
"relationships": {},
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{! Preview table }}
|
{{! Preview table }}
|
||||||
{{#if hasPending}}
|
{{#if (and hasPending (ne importState "importing"))}}
|
||||||
<div class="cde-migration-preview">
|
<div class="cde-migration-preview">
|
||||||
<div class="cde-migration-preview-header">
|
<div class="cde-migration-preview-header">
|
||||||
<span>{{ localize "CDE.MigrationPreviewTitle" }}</span>
|
<span>{{ localize "CDE.MigrationPreviewTitle" }}</span>
|
||||||
@@ -34,9 +34,12 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{{#each pending}}
|
{{#each pending}}
|
||||||
<tr>
|
<tr class="{{#if _duplicate}}cde-migration-row-duplicate{{/if}}">
|
||||||
<td><img src="{{img}}" class="cde-migration-thumb" alt=""></td>
|
<td><img src="{{img}}" class="cde-migration-thumb" alt=""></td>
|
||||||
<td class="cde-migration-name">{{name}}</td>
|
<td class="cde-migration-name">
|
||||||
|
{{#if _duplicate}}<i class="fa-solid fa-triangle-exclamation cde-migration-duplicate-icon" title="{{ localize 'CDE.MigrationDuplicate' }}"></i>{{/if}}
|
||||||
|
{{name}}
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="cde-migration-type-badge cde-migration-type-{{type}}">
|
<span class="cde-migration-type-badge cde-migration-type-{{type}}">
|
||||||
{{#if (eq type "character")}}
|
{{#if (eq type "character")}}
|
||||||
@@ -55,6 +58,41 @@
|
|||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
{{! Duplicate warning banner (confirmation step) }}
|
||||||
|
{{#if (eq importState "confirm")}}
|
||||||
|
<div class="cde-migration-confirm-bar">
|
||||||
|
<p class="cde-migration-confirm-msg">
|
||||||
|
<i class="fa-solid fa-triangle-exclamation"></i>
|
||||||
|
{{ localize "CDE.MigrationImportConfirm" count=count }}
|
||||||
|
</p>
|
||||||
|
{{#if hasDuplicates}}
|
||||||
|
<p class="cde-migration-confirm-duplicates">
|
||||||
|
<i class="fa-solid fa-triangle-exclamation"></i>
|
||||||
|
{{ localize "CDE.MigrationDuplicateCount" count=duplicateCount }}
|
||||||
|
</p>
|
||||||
|
{{/if}}
|
||||||
|
<div class="cde-migration-confirm-actions">
|
||||||
|
<button type="button" class="cde-migration-confirm-btn" data-action="confirmImport">
|
||||||
|
<i class="fa-solid fa-download"></i>
|
||||||
|
{{ localize "CDE.MigrationConfirmAction" }} ({{count}})
|
||||||
|
</button>
|
||||||
|
<button type="button" class="cde-migration-cancel-btn" data-action="cancelImport">
|
||||||
|
<i class="fa-solid fa-xmark"></i>
|
||||||
|
{{ localize "CDE.Cancel" }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{! Progress (importing state) }}
|
||||||
|
{{#if (eq importState "importing")}}
|
||||||
|
<div class="cde-migration-progress">
|
||||||
|
<i class="fa-solid fa-spinner fa-spin"></i>
|
||||||
|
<span>{{ localize "CDE.MigrationImporting" }}</span>
|
||||||
|
<span class="cde-migration-progress-count">{{progress}}/{{total}}</span>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
{{! Errors }}
|
{{! Errors }}
|
||||||
{{#if hasErrors}}
|
{{#if hasErrors}}
|
||||||
<ul class="cde-migration-errors">
|
<ul class="cde-migration-errors">
|
||||||
@@ -66,12 +104,12 @@
|
|||||||
|
|
||||||
{{! Action bar }}
|
{{! Action bar }}
|
||||||
<div class="cde-migration-actions">
|
<div class="cde-migration-actions">
|
||||||
{{#if hasPending}}
|
{{#if (and hasPending (eq importState "idle"))}}
|
||||||
<button type="button" class="cde-migration-import-btn" data-action="doImport">
|
<button type="button" class="cde-migration-import-btn" data-action="doImport">
|
||||||
<i class="fa-solid fa-download"></i>
|
<i class="fa-solid fa-download"></i>
|
||||||
{{ localize "CDE.MigrationImport" }} ({{count}})
|
{{ localize "CDE.MigrationImport" }} ({{count}})
|
||||||
</button>
|
</button>
|
||||||
{{else}}
|
{{else if (and (not hasPending) (eq importState "idle"))}}
|
||||||
<p class="cde-migration-hint">{{ localize "CDE.MigrationHint" }}</p>
|
<p class="cde-migration-hint">{{ localize "CDE.MigrationHint" }}</p>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user