Use socket to manage loksyu
This commit is contained in:
Vendored
+118
-20
@@ -1561,6 +1561,7 @@ async function rollInitiativeNPC(actor) {
|
||||
}
|
||||
|
||||
// src/ui/apps/singletons.js
|
||||
var SOCKET_CHANNEL = `system.${SYSTEM_ID}`;
|
||||
function getLoksyuData() {
|
||||
return game.settings.get(SYSTEM_ID, "loksyuData") ?? {
|
||||
wood: { yin: 0, yang: 0 },
|
||||
@@ -1570,16 +1571,75 @@ function getLoksyuData() {
|
||||
water: { yin: 0, yang: 0 }
|
||||
};
|
||||
}
|
||||
async function setLoksyuData(data) {
|
||||
async function writeLoksyuData(data) {
|
||||
await game.settings.set(SYSTEM_ID, "loksyuData", 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() {
|
||||
return game.settings.get(SYSTEM_ID, "tinjiData") ?? 0;
|
||||
}
|
||||
async function setTinjiValue(value) {
|
||||
await game.settings.set(SYSTEM_ID, "tinjiData", Math.max(0, value));
|
||||
Hooks.callAll("cde:tinjiUpdated", Math.max(0, value));
|
||||
if (game.user.isGM) return writeTinjiValue(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) {
|
||||
const cycle = WU_XING_CYCLE[activeAspect];
|
||||
@@ -1590,18 +1650,23 @@ async function updateLoksyuFromRoll(activeAspect, faces) {
|
||||
const yinCount = faces[yinFace] ?? 0;
|
||||
const yangCount = faces[yangFace] ?? 0;
|
||||
if (yinCount === 0 && yangCount === 0) return;
|
||||
const data = getLoksyuData();
|
||||
const current = data[lokAspect] ?? { yin: 0, yang: 0 };
|
||||
data[lokAspect] = {
|
||||
yin: (current.yin ?? 0) + yinCount,
|
||||
yang: (current.yang ?? 0) + yangCount
|
||||
};
|
||||
await setLoksyuData(data);
|
||||
if (game.user.isGM) {
|
||||
const data = getLoksyuData();
|
||||
const current = data[lokAspect] ?? { yin: 0, yang: 0 };
|
||||
data[lokAspect] = { yin: (current.yin ?? 0) + yinCount, yang: (current.yang ?? 0) + yangCount };
|
||||
await writeLoksyuData(data);
|
||||
} else {
|
||||
game.socket.emit(SOCKET_CHANNEL, { action: "updateLoksyuFromRoll", activeAspect, faces });
|
||||
}
|
||||
}
|
||||
async function updateTinjiFromRoll(count) {
|
||||
if (!count || count <= 0) return;
|
||||
const current = getTinjiValue();
|
||||
await setTinjiValue(current + count);
|
||||
if (game.user.isGM) {
|
||||
const current = getTinjiValue();
|
||||
await writeTinjiValue(current + count);
|
||||
} else {
|
||||
game.socket.emit(SOCKET_CHANNEL, { action: "updateTinjiFromRoll", delta: count });
|
||||
}
|
||||
}
|
||||
|
||||
// src/ui/rolling.js
|
||||
@@ -2685,6 +2750,8 @@ var CDELoksyuApp = class _CDELoksyuApp extends foundry.applications.api.Handleba
|
||||
};
|
||||
/** @type {Function|null} bound hook handler */
|
||||
_updateHook = null;
|
||||
/** @type {Function|null} updateSetting hook handler (for socket-propagated writes) */
|
||||
_settingHook = null;
|
||||
/** Singleton accessor — open or bring to front */
|
||||
static open() {
|
||||
const existing = Array.from(foundry.applications.instances.values()).find(
|
||||
@@ -2719,13 +2786,24 @@ var CDELoksyuApp = class _CDELoksyuApp extends foundry.applications.api.Handleba
|
||||
_onRender(context, options) {
|
||||
super._onRender(context, options);
|
||||
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) {
|
||||
if (this._updateHook !== null) {
|
||||
Hooks.off("cde:loksyuUpdated", this._updateHook);
|
||||
this._updateHook = null;
|
||||
}
|
||||
if (this._settingHook !== null) {
|
||||
Hooks.off("updateSetting", this._settingHook);
|
||||
this._settingHook = null;
|
||||
}
|
||||
super._onClose(options);
|
||||
}
|
||||
#bindInputs() {
|
||||
@@ -2794,6 +2872,8 @@ var CDETinjiApp = class _CDETinjiApp extends foundry.applications.api.Handlebars
|
||||
};
|
||||
/** @type {Function|null} */
|
||||
_updateHook = null;
|
||||
/** @type {Function|null} */
|
||||
_settingHook = null;
|
||||
static open() {
|
||||
const existing = Array.from(foundry.applications.instances.values()).find(
|
||||
(app2) => app2 instanceof _CDETinjiApp
|
||||
@@ -2815,13 +2895,24 @@ var CDETinjiApp = class _CDETinjiApp extends foundry.applications.api.Handlebars
|
||||
_onRender(context, options) {
|
||||
super._onRender(context, options);
|
||||
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) {
|
||||
if (this._updateHook !== null) {
|
||||
Hooks.off("cde:tinjiUpdated", this._updateHook);
|
||||
this._updateHook = null;
|
||||
}
|
||||
if (this._settingHook !== null) {
|
||||
Hooks.off("updateSetting", this._settingHook);
|
||||
this._settingHook = null;
|
||||
}
|
||||
super._onClose(options);
|
||||
}
|
||||
#bindDirectInput() {
|
||||
@@ -3078,8 +3169,7 @@ function refreshRollActions(rollCard, aspect, message) {
|
||||
const tinji = getTinjiValue();
|
||||
const successAvail = (loksyu[aspect]?.yin ?? 0) + (loksyu[aspect]?.yang ?? 0);
|
||||
const fasteAvail = (loksyu[fasteAspect]?.yin ?? 0) + (loksyu[fasteAspect]?.yang ?? 0);
|
||||
const isGM = game.user.isGM;
|
||||
const hasSomething = successAvail > 0 || fasteAvail > 0 || isGM && tinji > 0;
|
||||
const hasSomething = successAvail > 0 || fasteAvail > 0 || tinji > 0;
|
||||
if (!hasSomething) return;
|
||||
const aspLabel = game.i18n.localize(ASPECT_LABELS[aspect]);
|
||||
const fasteLabel = game.i18n.localize(ASPECT_LABELS[fasteAspect]);
|
||||
@@ -3098,7 +3188,7 @@ function refreshRollActions(rollCard, aspect, message) {
|
||||
<span class="cde-roll-action-count">${fasteAvail}</span>
|
||||
</button>`;
|
||||
}
|
||||
if (isGM && tinji > 0) {
|
||||
if (tinji > 0) {
|
||||
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-label">${game.i18n.localize("CDE.TinJi2")}</span>
|
||||
@@ -3151,7 +3241,11 @@ async function _drawFromLoksyu(message, aspect, type, aspectLabel) {
|
||||
else entry.yin--;
|
||||
}
|
||||
data[aspect] = entry;
|
||||
await setLoksyuData(data);
|
||||
if (game.user.isGM) {
|
||||
await setLoksyuData(data);
|
||||
} else {
|
||||
requestLoksyuDraw(aspect, order);
|
||||
}
|
||||
const flags = message?.flags?.[SYSTEM_ID];
|
||||
if (flags?.rollResult && message.isOwner) {
|
||||
const updated = foundry.utils.deepClone(flags.rollResult);
|
||||
@@ -3190,13 +3284,16 @@ async function _drawFromLoksyu(message, aspect, type, aspectLabel) {
|
||||
});
|
||||
}
|
||||
async function _spendTinjiPostRoll() {
|
||||
if (!game.user.isGM) return;
|
||||
const current = getTinjiValue();
|
||||
if (current <= 0) {
|
||||
ui.notifications.warn(game.i18n.localize("CDE.TinjiEmpty"));
|
||||
return;
|
||||
}
|
||||
await setTinjiValue(current - 1);
|
||||
if (game.user.isGM) {
|
||||
await setTinjiValue(current - 1);
|
||||
} else {
|
||||
requestTinjiSpend();
|
||||
}
|
||||
await ChatMessage.create({
|
||||
user: game.user.id,
|
||||
content: `<div class="cde-tinji-spend-msg">
|
||||
@@ -3354,6 +3451,7 @@ Hooks.once("ready", async () => {
|
||||
await migrateIfNeeded();
|
||||
await loadWelcomeSceneIfNeeded();
|
||||
CDEWheelApp.registerHooks();
|
||||
registerSingletonSocket();
|
||||
if (game.user.isGM) showWelcomeMessage();
|
||||
});
|
||||
Hooks.on("renderChatLog", (_app, html) => {
|
||||
|
||||
Reference in New Issue
Block a user